Table of Timers

Have you ever wished PAC Control had a table of timers? Here’s a simple way to implement just that.

This came up because we had a customer timing a number of “move gate” events, and wanted to see if 12 seconds had elapsed since the “open” or “close” gate command had been issued for a particular each gate.

He just needed one numeric table (64-bit int table in this case) for “time since powerup” for each gate (each an element in that table). Then instead of checking the timer, he’d just get “time since powerup” now, subtract from the previously recorded “start time”, and see if 12 seconds had gone by.

The slightly tricky part is where to get that value to avoid rollover, like you’d have to worry about if you use “Get Seconds Since Midnight” (which rolls over a midnight) or certain parts of the memory map that roll over every 49.7 or 49,710 days.

MMP address F030 0228 returns a 64-bit value that’s milliseconds since powerup which only rolls over every 584,542,046 YEARS. (I’ll refrain from corny jokes here, suffice to say, I don’t think we care what happens in half a BILLION years.)

I’ll attach a chart, but here are the relevant OptoScript snippets:

// "Start" timing for index nIndex in the table
nnTempReadValue = 0;
nResult = ReadNumFromIoUnitMemMap( LocalMemMap, 0xF0300228, nnTempReadValue );

// Sanity check on mem map read
if ( (nnTempReadValue == 0) or (nResult <> 0) ) then
  // something's not right if we get here, need to check IP address on LocalMemMap (should be 127.0.0.1)
  // or firmware version to make sure this area of the mem map is supported (like if you have really old firmware)
  AddMessageToQueue(16, "Something's not right. Check IP address and firmware on local I/O Unit");
else
  nntMillisecondsSincePowerup[nIndex] = nnTempReadValue;
endif

Here’s where we check (in a loop with a delay, of course), how long it’s been since then:

// Read the current time and compare to nIndex in the table of previously recorded values
nnTempReadValue = 0;
nResult = ReadNumFromIoUnitMemMap( LocalMemMap, 0xF0300228, nnTempReadValue );

nnTimeElapsedMS = (nnTempReadValue - nntMillisecondsSincePowerup[nIndex]);

At this point, the customer I mentioned would compare his nnTimeElapsedMS to 12000 (milliseconds) and then do whatever he needed to do if that amount of time had passed.

Easy! Note the 64-bit values since that’s what we’re reading from the memory map (more bits means more days/years before we have to worry about rollover).

Hope that’s helpful.

-OptoMary

TimerTableChart9_0Basic.zip (2.52 KB)

Dear OptoMary

Interesting post, but I wouldn’t park my car in front of your gate control. :rolleyes:

Just to remind any Opto-Newbies out there that time since powerup rollover may occur a little sooner than 584,542,046 YEARS if the unit loses power and resets a couple of times, which does tend to occur more often than your average [I]“Sacred Triple Rebirth of the Sun”[/I]. Our local power company manages to achieve this at least once a month!

Any code that uses start-up timers to control outputs, should contemplate the possibility.

Hi gmitchell,

Excellent point, you get the gold star for mentioning the “edge case.” In particular, the “what if the power goes out?” question is a big one, and something I’d love to get input from those especially experienced in the real world, like you!

BTW, since timers don’t have the option of being persistent, this timing technique could also be helpful in other applications where you just need one (rather than a whole table of timers like we were doing here), but you need to pay attention to power cycles.

Notice I did use persistent variables so their values would persist through a power cycle. (Of course, using a UPS would be a good idea so you don’t have to worry about that as often.) I’d left the “what to do with the elapsed time” value as an exercise to the reader, but let’s talk about that a little more, and perhaps tackle the bigger “what to do in the event of a power loss” question in another thread. (Ben had a clever trick he did leveraging the different options for Initialization: “on strategy run” vs. “on strategy download.”)

Getting back to the timer example, we calculate nnTimeElapsedMS and compare that value to the time interval we care about (12000 milliseconds for the gate example). However, we should also compare that value against 0. In other words, [B]if nnTimeElapsedMS is less than zero we know something is wrong, the power has cycled[/B] since we made note of the MS since powerup when we started to move the gate or whatever.

Now, hopefully during that time the power was out, you had your hardware set up to do something appropriate, not dump all the grain out of the silo or trap your boss’s car behind the gate so he can’t leave.

In the strategy, if nnTimeElapsedMS < 0 then we know there’s been a power cycle, but [B]we don’t know how long it’s been out[/B]. We could add more variables and logic to keep track of total “power on time” for the lifetime of the controller (that might be helpful for other things), or even code to calculate/read time from various places to get a pretty good idea about how long the controller was powered down.

In any case, we’re going to need the “oh no” code/chart to execute, or as Ben called it, the “everybody get out of the pool” logic.What would that look like, exactly? Depends a lot on your application, but there are a few general things you’ll want to think about…

-OptoMary

Maybe a workaround would be to use seconds since midnight? If seconds are an acceptable resolution, that is. I have used this technique successfully to gauge when a reaction is to occur in the future. Just remember to take into account the midnight rollover (86400). Some simple equations should be able to determine how long the period has elapsed. It will survive a power cycle and keep everyone happy! (especially the boss who won’t have grain dumped behind his car!!)

I am actually the customer mentioned. In our situation, the timer table works well because a gate movement is quite a short event (perhaps 20 seconds at the longest). During the movement we are quite regularly checking the map to update the seconds elapsed and a value outside of the expected range triggers an alarm. The code is written such that an event will come to an immediate halt upon power loss anyhow (with no automatic restart of the movement upon powerup) so in Mary’s defence the seconds since elapsed works just fine here.

I could understand if you were timing much longer events that power cycling would be a concern… seconds since midnight is a great idea Nick. We actually debated going that route before Mary came up with this concept (we stayed away from it because of the complications that would come with a rollover).

Anyhow, I was very happy to remove 27 individual timers from my chart and replace them with one table… works pretty slick with a little bit of math! Thanks again Mary!

Nick, your comment reminded me of this picture. Don’t worry, it didn’t happen anywhere near one of our systems!!


I suddenly remembered I got my control systems mixed up and realised that Opto22 doesn’t have one of my favourite commands. I wonder if it could get included in 9.3 before anyone presents it as a “roll your own” subroutine.

Get Seconds Since Sunday
Time/Date Action

Function:

Gets the number of seconds since 00:00 last Sunday.
Typical Use:
In place of timers to determine time between events which may involve more than 24 hours or to time stamp an event with a number rather than a string.
Details:
Value returned is an integer from 0 to 604799

Although contrary to ISO 8601, it is still quite popular in the control world and Tel Aviv!

While we are on the subject, who can name the film that this photo came from? :cool:


Hello McFly…
Nobody calls me chicken…

Hehe classic

Well spotted Nick! I was reminded of the forum post the other day while watching the film again for about the thousandth time. And for any other Opto22 fans out there who grew up with Back to the Future (Maybe the two are synonymous!) and haven’t seen the clip lately, here’s Michael J Fox, in Nov 2011 proving:

a) Time travel really does exist and
b) Parkinson’s is no match for Marty McFly!

//youtu.be/P8Y-PdD1TbA

I’m wondering if we could adapt an OPTOEMU-SNR-DR1 to measure [I] 1.21 gigawatt! :cool:

[/I]Opto22 - OPTOEMU-SNR-DR1 - OBSOLETE Energy monitoring unit with Demand Response capability (Wired+Wireless)

Hello fellow OptoFans & time travelers,

Glad everyone’s sense of humor is in tact. Speaking of rollover, and worrying about cases like the power going off or what happens at midnight, be sure to check out this post on why you should use the new-ish “Get Date & Time” command (rather than getting the date and time separately).

Anyone care to share other “edge cases” that you’ve overlooked or have corrected for related to time (or power, or perhaps analog input values)?

Thanks,
-OptoMary

I think there are a number of ways to avoid problems with restart of timers on powerup.

One would be to time stamp the last time a gate was opened or closed and then simply calculate the time difference at the next gate event. This would not be affected by a controller power loss and restart.

Excellent idea (be sure to use the “Get Date & Time” command I mentioned above to be atomic). Also, don’t want to forget the date to avoid midnight rollover and if you might want to time something longer than a day.

Just a little math required to convert that date/time stamp – you might want to use int64s since an int32 can only go up to: 2147483647, which, if you’re keeping track of milliseconds would be: 2147483.647 seconds or 35791 minutes or 596 hours or 24.8 days.

Watch those “edge cases,” and keep those good ideas coming!

BTW, for those of you using timestamps, have you seen the PAC Control NTP commands like: “Convert NTP Timestamp to Date & Time” and “Synchronize Clock SNTP”? Neat-o!

Hi All,

BTW, you might not need a timer at all if your doing a Turn On <wait a little> Turn Off type function, just use Start On-Pulse, for example. More on that in this post.

Hope that helps!
-OptoMary