Setting up a timeout

Background: I’m working on the front end software to a film scanner. The software communicates with control hardware inside the scanner via TCP.

In the front end software, I need to run an initialization sequence that does, among other things, the following:

  1. Verify the control hardware is up and running
  2. Run a "MasterInitialize " sequence on the controller and wait for confirmation of completion
  3. Position motors

(there’s more that happens after this)

Step 3 cannot happen until step 2 is complete. MasterInitialize can take quite some time to finish, and we have to wait for a status update from the controller that this command was successfully executed. Part of what it has to do is home some very slow stepper motors, and depending on their position at power-on, this could take up to 30 seconds. Because this will take happen during the application startup while a splash screen is showing, I don’t have a problem with there being a 30 second timeout on step 2, since the machine can’t function without this master initialize command having completed.

My initial thought was to make a simple while loop that runs for 30 seconds, and every 500ms or so, I will check a property that is updated when the controller indicates that MasterIntialize is complete.

Or is there a better way?

I had considered making this event-driven, using a series of computed properties to trigger each step of the sequence as the previous one finishes, but there are situations where we would need to run MasterInitialize without triggering the events that happen after at startup, (not listed above), such as when the hardware has to be reset while the application is running. That would mean having to have two sets of those properties - some that trigger other events, some that don’t.

a loop inside a method will block the ui.
i would use a status enumeration and a timer.
if your hardware send something via tcp you get a direct answer.

I’m not especially concerned about blocking the UI in this case, since nothing can happen until this particular command has completed and it is running in the application startup sequence behind a splash screen. Or are you saying it will also block the incoming TCP message? That would be a problem.

Yes, it will block everything.

As MarkusR said, a Timer would probably be the best option here. It won’t block anything.

Ok, thanks. I’ll look at doing this with a timer then!

The problem with Timer is that the logic can get very complicated. I would probably do this in a Thread subclass.

Edit: to clarify, in a Thread you can do things like this:

MyThread.Start
 // wait for Hardware to get up and running
  while not HardwareReady()
       sleep(5) // check every 5 msec, since the hardware usually comes up quickly
  wend
  
 // let the UI know we've passed this first step
 dim d as new dictionary
 d.value("message") = "Hardware is running"
 AddUserInterfaceUpdate(d)


 // wait for master Initialization, and timeout if it takes more than 90 seconds
  dim t0 as double = microseconds
  while not MasterInitFinished()
       sleep(500) // check every 500 msec, since this step takes a long time

      dim deltaT as double = (microseconds - t0) / 1e6
      if deltaT > 90 then
        d.value("error") = "master Initialization faled after 90 seconds"
        AddUserInterfaceUpdate(d)
        return
      end if
  wend
 d.value("message") = "master Initialization success"
 AddUserInterfaceUpdate(d)

// etc...

If you try to do this all in Timer callbacks, the logic gets a bit hairy - you basically have to use some sort of State Machine.

2 Likes