.. _TimeOutLoop: ================= Loop With Timeout ================= Many low level routines require to wait for a specific condition come true: A transmission is finished, a flag is set etc. Most of the time these action do work fine. But sometimes, the check loop does not terminate for some (usually stupid) reason and the program essentially crashed. .. code-block:: forth \ wait for twi finish : twi.wait ( -- ) begin TWCR c@ 80 and until ; To circumvent such unwanted endless loops, a timeout is often a solution. This ensures that the loop will be left, regardless what happens. This recipe is based upon the timer module from the :file:`lib/hardware` directory, that provides a millisecond tick that can be used for timeouts as well. A timeout loop is basically a modified begin that takes a runtime parameter: the maximum allowed time for a particular loop. The loop terminater (again, until, etc) is left unchanged. If the loop terminates properly, the timeout is ignored, otherwise an *exception* is thrown. It is up to the programmer to catch that exception. If it is not catched, the forth interpreter will do it and returns to the command prompt. .. code-block:: forth \ timeout-begin is a potentially endless loop \ that terminates after a predefined timeout \ in the case of a timeout an exception is thrown variable alarmtime : (init-alarm) @tick + alarmtime ! ; : (check-alarm) alarmtime @ expired? if -512 throw then ; : timeout-begin postpone (init-alarm) postpone begin postpone (check-alarm) ; immediate Since the alarm checks are simple, some precautions should be obeyed: * The timer gives a millisecond resolution. * The longest timeout period is 65.535 seconds (slightly more than a minute). * The timeout-loop cannot be nested. If you want to use it in a multitasking environment, change the variable to a user. * Don’t forget to initialize and start the timer. .. code-block:: forth \ testcase. timeout after 100ms : foo 100 timeout-begin noop again ;