TimeMs t = g_schedule[nid];
if (t && t < now)
markNodeDirty(nid);
Which will fail when millis() rolls over (~49 days). I had the same problem, and same pattern, and just recently looked up the right way to do this. The comparison has to calculate a duration:
if (now - started > duration) { expired! }
Both the times have to be unsigned long, then you get modulus arithmetic, and subtraction of times always gives you the duration.
Unfortunately, that means you will have to store 2 values for each schedule: started and duration.
I wonder may we avoid storing two values if declare that the timeout duration can’t be more than a half of the storage domain? For uint32_t it would be 2^31-1. Let me show a simplified example if we used unit8_t instead.
Yes, you could do something like that (though your example code doesn’t look quite right to me: “t < now” is wrong for now==254, t=5). But, as you note, at the cost of limiting the duration. Supposedly, millis() rolls over at about 49 days on the UNO. It seems to vary by processor though.