mirror of
https://github.com/rvdbreemen/OTGW-firmware
synced 2024-11-16 04:33:49 +01:00
275 lines
12 KiB
C
275 lines
12 KiB
C
/*
|
|
***************************************************************************
|
|
** Filename : safeTimers.h
|
|
** Version : 0.3.0
|
|
**
|
|
** Copyright (c) 2020 Willem Aandewiel
|
|
**
|
|
** TERMS OF USE: MIT License. See bottom of file.
|
|
***************************************************************************
|
|
*/
|
|
#ifndef SAFETIMERS_H
|
|
#define SAFETIMERS_H
|
|
|
|
/*
|
|
* safeTimers.h (original name timers.h) is developed by Erik
|
|
*
|
|
* Willem Aandewiel and Robert van den Breemen made some changes due
|
|
* to the "how can I handle the millis() rollover" by Edgar Bonet and added
|
|
* CHANGE_INTERVAL() and RESTART_TIMER() macro's
|
|
*
|
|
* see: https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover
|
|
*
|
|
* DECLARE_TIMER_MIN(timername, interval, <timerType>) // interval in minutes
|
|
* DECLARE_TIMER_SEC(timername, interval, <timerType>) // interval in seconds
|
|
* DECLARE_TIMER_MS(timername, interval, <timerType>) // interval in milliseconds
|
|
* DECLARE_TIMER(timername, interval, <timerType>) // interval in milliseconds
|
|
* Declares three static vars:
|
|
* <timername>_due (uint32_t) for next execution
|
|
* <timername>_interval (uint32_t) for interval in seconds
|
|
* <timername>_type (byte)
|
|
*
|
|
* <timerType> can either be:
|
|
* SKIP_MISSED_TICKS
|
|
* CATCH_UP_MISSED_TICKS
|
|
* SKIP_MISSED_TICKS_WITH_SYNC
|
|
* TIMER_TYPE_4
|
|
*
|
|
* TIME_LEFT_MIN(timerName)
|
|
* returns the time left in minutes
|
|
* TIME_LEFT_SEC(timerName)
|
|
* returns the time left in seconds
|
|
* TIME_LEFT_MS(timerName)
|
|
* returns the time left in milliseconds
|
|
* TIME_LEFT(timerName)
|
|
* returns the time left in milliseconds
|
|
*
|
|
* CHANGE_INTERVAL_MIN(timername, interval, <timerType>)
|
|
* CHANGE_INTERVAL_SEC(timername, interval, <timerType>)
|
|
* CHANGE_INTERVAL_MS(timername, interval, <timerType>)
|
|
* CHANGE_INTERVAL(timername, interval, <timerType>)
|
|
* Changes the static vars declared by DECLARE_TIMER():
|
|
* <timername>_due (uint32_t) for next execution
|
|
* <timername>_interval (uint32_t) for interval
|
|
* <timername>_type (byte)
|
|
*
|
|
* RESTART_TIMER(timername)
|
|
* updates <timername>_due = millis() + <timername>_interval
|
|
*
|
|
* DUE(timername)
|
|
* returns false (0) if interval hasn't elapsed since last DUE-time
|
|
* true (current millis) if it has
|
|
* updates <timername>_due
|
|
*
|
|
* Usage example:
|
|
*
|
|
* DECLARE_TIMER(screenUpdate, 200, SKIP_MISSED_TICKS) // update screen every 200 ms
|
|
* ...
|
|
* loop()
|
|
* {
|
|
* ..
|
|
* if ( DUE(screenUpdate) ) {
|
|
* // update screen code
|
|
* }
|
|
*
|
|
* // to change the screenUpdate interval:
|
|
* CHANGE_INTERVAL(screenUpdate, 500, CATCH_UP_MISSED_TICKS); // change interval to 500 ms
|
|
*
|
|
* // to restart the screenUpdate interval:
|
|
* RESTART_TIMER(screenUpdate); // restart timer so next DUE is in 500ms
|
|
* }
|
|
*
|
|
*/
|
|
|
|
//--- timerType's -----------------------
|
|
#define SKIP_MISSED_TICKS 0
|
|
#define CATCH_UP_MISSED_TICKS 1
|
|
#define SKIP_MISSED_TICKS_WITH_SYNC 2
|
|
#define TIMER_TYPE_4 3
|
|
|
|
|
|
#define DECLARE_TIMER_MIN(timerName, ...) \
|
|
static uint32_t timerName##_interval = (getParam(0, __VA_ARGS__, 0) * 60 * 1000),\
|
|
timerName##_due = millis() \
|
|
+timerName##_interval \
|
|
+random(timerName##_interval / 3); \
|
|
static byte timerName##_type = getParam(1, __VA_ARGS__, 0);
|
|
|
|
#define DECLARE_TIMER_SEC(timerName, ...) \
|
|
static uint32_t timerName##_interval = (getParam(0, __VA_ARGS__, 0) * 1000),\
|
|
timerName##_due = millis() \
|
|
+timerName##_interval \
|
|
+random(timerName##_interval / 3); \
|
|
static byte timerName##_type = getParam(1, __VA_ARGS__, 0);
|
|
|
|
#define DECLARE_TIMER_MS(timerName, ...) \
|
|
static uint32_t timerName##_interval = (getParam(0, __VA_ARGS__, 0)), \
|
|
timerName##_due = millis() \
|
|
+timerName##_interval \
|
|
+random(timerName##_interval / 3); \
|
|
static byte timerName##_type = getParam(1, __VA_ARGS__, 0);
|
|
|
|
#define DECLARE_TIMER DECLARE_TIMER_MS
|
|
|
|
|
|
#define CHANGE_INTERVAL_MIN(timerName, ...) \
|
|
timerName##_interval = (getParam(0, __VA_ARGS__, 0) *60*1000),\
|
|
timerName##_due = millis() \
|
|
+timerName##_interval \
|
|
+random(timerName##_interval / 3); \
|
|
timerName##_type = getParam(1, __VA_ARGS__, 0);
|
|
#define CHANGE_INTERVAL_SEC(timerName, ...) \
|
|
timerName##_interval = (getParam(0, __VA_ARGS__, 0) *1000), \
|
|
timerName##_due = millis() \
|
|
+timerName##_interval \
|
|
+random(timerName##_interval / 3); \
|
|
timerName##_type = getParam(1, __VA_ARGS__, 0);
|
|
#define CHANGE_INTERVAL_MS(timerName, ...) \
|
|
timerName##_interval = (getParam(0, __VA_ARGS__, 0) ), \
|
|
timerName##_due = millis() \
|
|
+timerName##_interval \
|
|
+random(timerName##_interval / 3); \
|
|
timerName##_type = getParam(1, __VA_ARGS__, 0);
|
|
|
|
#define CHANGE_INTERVAL CHANGE_INTERVAL_MS
|
|
|
|
#define TIME_LEFT(timerName) ( __TimeLeft__(timerName##_due) )
|
|
#define TIME_LEFT_MS(timerName) ( (TIME_LEFT(timerName) ) )
|
|
#define TIME_LEFT_MIN(timerName) ( (TIME_LEFT(timerName) ) / (60 * 1000))
|
|
#define TIME_LEFT_SEC(timerName) ( (TIME_LEFT(timerName) ) / 1000 )
|
|
|
|
#define ONCE(timerName) ( __Once__(timerName##_due) )
|
|
#define ONCE_MS(timerName) ( (ONCE(timerName) ) )
|
|
#define ONCE_MIN(timerName) ( (ONCE(timerName) ) / (60 * 1000))
|
|
#define ONCE_SEC(timerName) ( (ONCE(timerName) ) / 1000 )
|
|
|
|
#define TIME_PAST(timerName) ( (timerName##_interval - TIME_LEFT(timerName)) )
|
|
#define TIME_PAST_MS(timerName) ( (TIME_PAST(timerName) ) )
|
|
#define TIME_PAST_SEC(timerName) ( (TIME_PAST(timerName) / 1000) )
|
|
#define TIME_PAST_MIN(timerName) ( (TIME_PAST(timerName) / (60*1000)) )
|
|
|
|
#define RESTART_TIMER(timerName) ( timerName##_due = millis()+timerName##_interval );
|
|
|
|
#define DUE(timerName) ( __Due__(timerName##_due, timerName##_interval, timerName##_type) )
|
|
|
|
uint32_t __Due__(uint32_t &timer_due, uint32_t timer_interval, byte timerType)
|
|
{
|
|
if ((int32_t)(millis() - timer_due) >= 0)
|
|
{
|
|
switch (timerType) {
|
|
case CATCH_UP_MISSED_TICKS:
|
|
timer_due += timer_interval;
|
|
break;
|
|
case SKIP_MISSED_TICKS_WITH_SYNC:
|
|
// this will calculate the next due, and skips passed due events
|
|
// (missing due events)
|
|
// timer_due += (((uint32_t)(( timer_due - millis()) / timer_interval)+1) *timer_interval);
|
|
while ((int32_t)(millis() - timer_due) >= 0)
|
|
{
|
|
timer_due += timer_interval;
|
|
}
|
|
break;
|
|
case TIMER_TYPE_4:
|
|
if ((millis() - timer_due) >= (uint32_t)(timer_interval * 0.05))
|
|
{
|
|
timer_due += timer_interval;
|
|
return 0;
|
|
}
|
|
while ((int32_t)(millis() - timer_due) >= 0)
|
|
{
|
|
timer_due += timer_interval;
|
|
}
|
|
break;
|
|
// SKIP_MISSED_TICKS is default
|
|
default: timer_due = millis() + timer_interval;
|
|
break;
|
|
}
|
|
return timer_due;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} // __Due__()
|
|
|
|
uint32_t __TimeLeft__(uint32_t timer_due)
|
|
{
|
|
uint32_t tmp;
|
|
byte state = 0;
|
|
|
|
// timeline 0-------------------------SIGNED-MAX-------------------------UMAX
|
|
// state=0 0---------------------------T-|---D--------------------------UMAX
|
|
// state=0 0---------------------------d-|---t--------------------------UMAX
|
|
// state=0 0-----------------------------|---------------T-------D------UMAX
|
|
// state=0 0-----------------------------|---------------d--t-----------UMAX
|
|
// state=0 0-------T-D-------------------|------------------------------UMAX
|
|
// state=0 0---------d--t----------------|------------------------------UMAX
|
|
|
|
// state=1 0---T-------------------------|--------------------------D---UMAX
|
|
if ( (timer_due >= INT32_MAX) && (millis() < INT32_MAX) ) state = 1; // millis() rolled-over
|
|
|
|
// state=2 0--------D--------------------|---------------------T--------UMAX
|
|
if ( (timer_due <= INT32_MAX) && (millis() > INT32_MAX) ) state = 2; // _due rolled-over
|
|
|
|
switch(state) {
|
|
case 1: //--- millis() rolled-over
|
|
case 2: //--- _due rolled-over
|
|
if ( (int32_t)((timer_due + UINT32_MAX) - millis()) >= 0 )
|
|
tmp = (timer_due + UINT32_MAX) - millis();
|
|
else tmp = 0;
|
|
break;
|
|
default: if ( (int32_t)(timer_due - millis()) >= 0 )
|
|
tmp = timer_due - millis();
|
|
else tmp = 0;
|
|
}
|
|
|
|
return tmp;
|
|
|
|
} // __TimeLeft__()
|
|
|
|
uint32_t __Once__(uint32_t timer_due)
|
|
{
|
|
//false if timer is not due
|
|
if (__TimeLeft__(timer_due) > 0) return 0;
|
|
else return 1;
|
|
} // __Once__()
|
|
|
|
// process variadic from macro's
|
|
uint32_t getParam(uint32_t i, ...)
|
|
{
|
|
uint32_t parm = 0, p;
|
|
va_list vl;
|
|
va_start(vl,i);
|
|
for (p=0; p<=i; p++)
|
|
{
|
|
parm=va_arg(vl,uint32_t);
|
|
}
|
|
va_end(vl);
|
|
return parm;
|
|
} // getParam()
|
|
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
* persons to whom the Software is furnished to do so, subject to the
|
|
* following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
****************************************************************************
|
|
*/
|