This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
ThiagoTGM's profile picture

Loop counter going nuts

Started by ThiagoTGM, 04 October 2013 - 11:44 PM
ThiagoTGM #1
Posted 05 October 2013 - 01:44 AM
Title: Loop counter going nuts

Hey people! I have a small problem here that needs help.

So, a guy made a program to keep track of 8 redstone energy cells (the amount of energy on them, with openPeripherals), and automatically turn the energy production lines for each of them on or off. With his permission (he asked his subscribers, actually), I got his code and developed it further, adding more functions, like a display monitor, colored bars, override buttons, etc. I made the program to cycle again if a specific number of seconds have passed (the "frequency" variable) or if a button has been touched. At the end of the loop, there is a bit of code made to keep track of how many cycles have passed, and reset the counter once a specific value has been reached. That part is used so the program refreshes the tables containing older energy values after a certain number of cycles. And that data is used on a graph.

Here is the code: http://pastebin.com/A95R2RVL

Now, the problem. As you can probably see, the counter is supposed to count up (or reset) after the program makes a full cycle. The program will finish cycling if either 2 seconds have passed or a touch in the monitor or terminal is detected. The thing runs fine, until the first click. Then, the counter goes completely crazy, and starts doing weird things, like waiting 2 seconds before increasing the counter by 2, therefore the program starts looping faster, in a weird way. A few more clicks, and it gets worse. I tried various things, but the only thing that seemed to work was to put a sleep(1) in the end of the code and reduce frequency by 1. However, this method also creates an input lag that drives me crazy. What I'm looking for is a way to solve this issue while avoiding input lag.

Any help is much necessary and appreciated.
Tanks in advance.
Lyqyd #2
Posted 05 October 2013 - 03:42 PM
Split into new topic.
immibis #3
Posted 05 October 2013 - 03:54 PM
Here is the important bit of code:

 os.startTimer(frequency-0.4)
 repeat
  event, p1, clickx, clicky = os.pullEvent()
  if event == "monitor_touch" then --Detects monitor touch
   buttonPress(clickx,clicky)
  else
   if event == "mouse_click" and p1 == 1 then --Detects term click
    termClick(clickx,clicky)
   end
  end
 until event == "timer" --Wait until refreshing
Also note that buttonPress and termClick queue "timer" events when they're done.

When you don't click, this happens:
  • You call os.startTimer
  • A short time later, you get a "timer" event from that timer
  • You refresh the screen and go back to the first step.
  • Everything is OK.

Consider what happens if you click:
  • You call os.startTimer
  • You get a mouse_click event and queue a timer event.
  • You get a timer event. (the actual timer is still waiting)
  • You refresh the screen.
  • You call os.startTimer again.
  • Now you get the timer event from the first timer, refresh the screen, and call os.startTimer again. The second and third timers are running.
  • Now you get the timer event from the second timer, refresh the screen, and call os.startTimer again. The third and fourth timers are running.
Now you have two timers running at the same time, and you refresh the screen when either one expires. Every time the user clicks again, you get another timer.
ThiagoTGM #4
Posted 05 October 2013 - 11:44 PM
Split into new topic.

Tanks man :)/>

Here is the important bit of code:

os.startTimer(frequency-0.4)
repeat
  event, p1, clickx, clicky = os.pullEvent()
  if event == "monitor_touch" then --Detects monitor touch
   buttonPress(clickx,clicky)
  else
   if event == "mouse_click" and p1 == 1 then --Detects term click
	termClick(clickx,clicky)
   end
  end
until event == "timer" --Wait until refreshing
Also note that buttonPress and termClick queue "timer" events when they're done.

When you don't click, this happens:
  • You call os.startTimer
  • A short time later, you get a "timer" event from that timer
  • You refresh the screen and go back to the first step.
  • Everything is OK.
Consider what happens if you click:
  • You call os.startTimer
  • You get a mouse_click event and queue a timer event.
  • You get a timer event. (the actual timer is still waiting)
  • You refresh the screen.
  • You call os.startTimer again.
  • Now you get the timer event from the first timer, refresh the screen, and call os.startTimer again. The second and third timers are running.
  • Now you get the timer event from the second timer, refresh the screen, and call os.startTimer again. The third and fourth timers are running.
Now you have two timers running at the same time, and you refresh the screen when either one expires. Every time the user clicks again, you get another timer.

Oh, that makes sense. Tanks for pointing it out, Immibis :)/>
It seems that even if I take out the queued timers, the problem would still remain on a smaller scale, since the original timer would remain after the button click. I could make it so that it waits the first timer to clock out (by taking out the queued timers, those were the first way I could think for preventing any other type of event from looping the program, and still loop right after the click), but that would introduce the input lag, tough the lag would vary depending on when the button was clicked.
My new question is, is there a way to stop a timer? That may solve my problem. I guess I can live with the lag if there isn't, it can be very small if I click on the right time. Now that I think about it, this current method might actually be a good thing with the lag, because then it will loop only when the frequency timer is reached, and thus the Variation values and the Legacy graph are more precise. If there is a way to stop the timer, tell me anyway, and then I can look into it and see if the lag-free input is worth the loss of precision. If there isn't, well, not too bad. I might use the lag one one way or another.
Tanks for the help, anyway ;)/>

Edit: Now that I tough of it, doubling both the refresh rate and the refresh cycle reduces the input lag to always less than a second. I hope refreshing the screens every second doesn't start lagging, tough :/
immibis #5
Posted 06 October 2013 - 04:40 AM
You can't stop timers, but you can ignore them.
os.startTimer returns a timer ID, which is also the first parameter in the event it triggers. The timer ID is different for every timer.