rasProject_01 / weSweetHome
R. 240
process control / RasPi software by weinert-automation
|
Some system related time and utility functions for Raspberry Pis. More...
#include "sysBasic.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
Data Structures | |
struct | cycTask_t |
Cyclic or event driven task / threads structure. More... | |
struct | cycTaskEventData_t |
Event data for cyclic tasks. More... | |
Functions | |
int | advanceTmTim (struct tm *rTm, char *rTmTxt, uint8_t sec) |
Advance broken down real time by seconds. More... | |
int | char2hexDig (char c) |
Character to hexadecimal. More... | |
int | cycTaskDestroy (cycTask_t *cykTask) |
Destroy a cyclic task / threads structure. More... | |
int | cycTaskEvent (cycTask_t *cycTask, uint8_t noEvents, timespec stamp, cycTaskEventData_t cycTaskEventData) |
Handle and signal events. More... | |
int | cycTaskInit (cycTask_t *cykTask) |
Initialise a cyclic task / threads structure. More... | |
int | cycTaskWaitEvent (cycTask_t *cycTask, uint32_t eventsThreshold, cycTask_t *cycTaskSnap) |
Wait on signalled event. More... | |
int | endCyclist (void) |
The cycles handler arrived. More... | |
char * | formEpocTime (char *target, uint32_t value) |
Format 32 bit unsigned epoch time as ddhh:ssss relative to today. More... | |
char * | formFixed16 (char *target, uint8_t targetLen, uint16_t value, uint8_t dotPos) |
Format 16 bit unsigned fixed point, right aligned. More... | |
char * | formFixed32 (char *target, uint8_t targetLen, uint32_t value, uint8_t dotPos) |
Format 32 bit unsigned fixed point, right aligned. More... | |
char * | formUnsByte (char *target, uint8_t value) |
Format 8 bit unsigned fixed point, right aligned. More... | |
int | genErrWithText (char const *txt) |
Generate error text (errorText) with system error text appended. More... | |
uint8_t | get10inS () |
Get a 10th of second in s reading. More... | |
uint32_t | getAbsS () |
Get the absolute s reading. More... | |
uint32_t | getCykTaskCount (cycTask_t const *const cycTask) |
Get a cycle's/task's current event counter. More... | |
uint16_t | getMSinS () |
Get a ms in s reading. More... | |
void | initStartRTime () |
Initialise start (real) time. More... | |
uint32_t | ioSetClrSelect (uint8_t pin) |
Fetch a clear and set select bit for a GPIO pin. More... | |
int | isValidIp4 (char const *str) |
Check if a string is a valid IPv4 address. More... | |
void | logErrorText (void) |
Log the (last) common error text generated. More... | |
void | logErrText (char const *txt) |
Log an error text on errLog. More... | |
void | logErrWithText (char const *txt) |
Log error text (on errLog) with system error text appended. More... | |
void | logStampedText (char const *txt) |
Log an event or a message on outLog as line with time stamp. More... | |
void | monoTimeResol (timespec *timeRes) |
Absolute time (source) resolution. More... | |
void | onSignalExit (int s) |
On signal exit. More... | |
void | onSignalExit0 (int s) |
On signal exit 0. More... | |
void | onSignalStop (int s) |
On signal stop. More... | |
unsigned int | parse2Long (char *const optArg, long int *parsResult) |
Parse a string of integer numbers. More... | |
int | parsInt (const char *str, const int lower, const int upper, const int def) |
Parse int with checks. More... | |
uint16_t | stopMSwatch () |
Get a (stop-watch) ms reading. More... | |
void | strLappend (char *dest, char const *src, int n) |
Append one char sequence left justified at another one. More... | |
void | strLinto (char *dest, char const *src, size_t n) |
Set one char sequence left justified into another one. More... | |
void | strRinto (char *dest, char const *src, size_t n) |
Set one char sequence right justified into another one. More... | |
int | theCyclistStart (int startMsDelay) |
Start the cycles handler. More... | |
int | theCyclistWaitEnd () |
Wait for the end of the cycles thread. More... | |
timespec | timeAdd (timespec const t1, timespec const t2) |
Add two times as new structure. More... | |
void | timeAddTo (timespec *t1, timespec const t2) |
Add two times overwriting the first operand. More... | |
int | timeCmp (timespec const t1, timespec const t2) |
Compare two times. More... | |
int | timeSleep (unsigned int micros) |
Relative delay for the specified number of ‹¨«s. More... | |
Variables | |
char | actRTmTxt [] |
Actual broken down time (text). More... | |
timespec | allCycStart |
Common absolute / monotonic start time of all cycles. More... | |
char const | bin8digs [256][10] |
"0000_0000" .. "1111_1111" | |
volatile uint8_t | commonRun |
Common boolean run flag for all threads. More... | |
const uint32_t | csBit [] |
single bit set. 1 2 4 8 ... 0x80000000 | |
cycTask_t | cyc100ms |
100ms cycle (data structure) | |
cycTask_t | cyc10ms |
10ms cycle (data structure) | |
cycTask_t | cyc1ms |
1ms cycle (data structure) | |
cycTask_t | cyc1sec |
1s cycle (data structure) | |
cycTask_t | cyc20ms |
20ms cycle (data structure) | |
char const | dec8duns [256][4] |
" 0" .. "255" byte to three char dec | |
char | errorText [182] |
Common error text. More... | |
uint8_t | have100msCyc |
Flag to enable the 100ms cycle. More... | |
uint8_t | have10msCyc |
Flag to enable the 10ms cycle. More... | |
uint8_t | have1msCyc |
Flag to enable the 1ms cycle. More... | |
uint8_t | have1secCyc |
Flag to enable the 1s cycle. More... | |
uint8_t | have20msCyc |
Flag to enable the 20ms cycle. More... | |
long int | parsResult [] |
Long array of length 14. More... | |
volatile int | sigRec |
Storage for the signal (number) requesting exit. More... | |
timespec | startRTime |
Start time (structure, monotonic real time clock). More... | |
char const *const | stmp23 |
The current time as text. More... | |
uint32_t const *const | stmpSec |
The real time epoch seconds. More... | |
int8_t | vcoCorrNs |
external for test/debug only (don't change) | |
Some system related time and utility functions for Raspberry Pis.
Revision history
This file contains some definitions concerning system, time and IO. The IO part will work with the gpio/gpiod library as defined in the library's include file pigpiod_if2.h.
void strLinto | ( | char * | dest, |
char const * | src, | ||
size_t | n | ||
) |
Set one char sequence left justified into another one.
This function copies n characters from src to dest left justified. If the length of src is less than n the remaining length on right in dest will be filled with blanks.
Attention: dest[n-1] must be within the char array provided by dest. This cannot and will not be checked!
Hint: Contrary to strncpy there's no padding with 0. If you want dest to end after the insertion use strLappend().
dest | the pointer to / into the destination sequence where src is to be copied to. If NULL nothing happens. |
src | the sequence to be copied. If NULL or empty fill is used from start |
n | the number of characters to be copied from src. |
void strLappend | ( | char * | dest, |
char const * | src, | ||
int | n | ||
) |
Append one char sequence left justified at another one.
This function copies n characters from src to dest and lets dest then end with 0 (end of string). If n is negativ, -n characters will be copied and dest will end with new line and 0;
Attention: dest[n] respectively dest [-n + 1] must be within the char array provided by dest. This cannot and will not be checked!
dest | the pointer to / into the destination sequence where src is to be copied to. If Null nothing happens. |
src | the sequence to be copied. If Null or empty fill is used from start |
n | the absolute value is the number of characters to be copied from src. If this number exceeds 300 it will be taken as 0. If n is negative a line feed will be appended, too. |
void strRinto | ( | char * | dest, |
char const * | src, | ||
size_t | n | ||
) |
Set one char sequence right justified into another one.
This function copies n characters from src to dest right justified. If the length of src is less than n the remaining length on left in dest will be filled with blanks.
Attention: dest[n-1] must be within the char array provided by dest. This cannot and will not be checked!
Hint to append instead of insert: If this operation shall be at the end of the changed char sequence do
dest[n] = 0;
Then, of course, dest[n] must be within the char array provided by dest.
dest | the pointer to / into the destination sequence where src is to be copied to. If NULL nothing happens. |
src | the sequence to be copied. If NULL or empty fill is used from start |
n | the number of characters to be copied from src. |
char * formFixed16 | ( | char * | target, |
uint8_t | targetLen, | ||
uint16_t | value, | ||
uint8_t | dotPos | ||
) |
Format 16 bit unsigned fixed point, right aligned.
formFixed16(target, 6, 1234, 2), e.g., will yield " 12.34".
formFixed16(target, 6, 4, 2), e.g., will yield " 0.04".
If the value would not fit within targetLen characters leading digits will be truncated.
target | pointer to first of targLen characters changed |
targetLen | field length 2..16; number of characters changed |
value | the fixed point value |
dotPos | where the fixed point is 0..6 < targetLen |
char * formFixed32 | ( | char * | target, |
uint8_t | targetLen, | ||
uint32_t | value, | ||
uint8_t | dotPos | ||
) |
Format 32 bit unsigned fixed point, right aligned.
This function behaves like formFixed16() except for handling 32 bit values. formFixed16() should be preferred, when feasible.
target | pointer to first of targLen characters changed |
targetLen | field length 2..16; number of characters changed |
value | the fixed point value |
dotPos | where the fixed point is 0..6 < targetLen |
char * formEpocTime | ( | char * | target, |
uint32_t | value | ||
) |
Format 32 bit unsigned epoch time as ddhh:ssss relative to today.
The output format ddhh:mm:ss means:
.d: '<<' '<-' ' ' '->' '>>' mean day before yesterday, yesterday, today, tomorrow, day after tomorrow ...
hh:mm:ss is, of course, the time in that day.
For days further in past or future the epoch seconds (ten digits incomprehensible to humans) are output, see formFixed32().
target | pointer to first of 10 characters changed |
value | the fixed point value |
sprintf(target, "%3dd%5ds", relNoDay, secInDay);
char * formUnsByte | ( | char * | target, |
uint8_t | value | ||
) |
Format 8 bit unsigned fixed point, right aligned.
target | pointer to first of targLen characters changed |
value | the unsigned 8 bit value (0..255) |
int isValidIp4 | ( | char const * | str | ) |
Check if a string is a valid IPv4 address.
Syntactically valid IPv4 addresses are: 0.0.0.0 .. 255.255.255.255
str | The string containing the address, only; 0-terminated |
int char2hexDig | ( | char | c | ) |
Character to hexadecimal.
Parameter values '0'..'9' return 0..9. Parameter values 'A'..'F' and 'a'..'f' return 10..15. Other values return -1.
int parsInt | ( | const char * | str, |
const int | lower, | ||
const int | upper, | ||
const int | def | ||
) |
Parse int with checks.
This function expects parameter str to point to a null-terminated string. If not def is returned. If lower > upper def is returned. If the string str contains a decimal integer number n, fulfilling lower <= n <= upper n is returned, or def otherwise.
If the string str starts with [+|-][min|med|max] ignoring case lower respectively ((lower + upper) / 2) respectively upper is returned. A leading sign (+|-) as well as any trailing characters are ignored.
str | 0-terminated string containing a decimal integer number, or one of the keywords described above |
lower | lower limit |
upper | upper limit |
def | default value, to be returned when str is not a pure decimal number one of the keyword starts or when the result violates the limits |
unsigned int parse2Long | ( | char *const | optArg, |
long int * | parsResult | ||
) |
Parse a string of integer numbers.
The string optArg will be tokenised taking any occurrences of the characters " +,;" (blank, plus, comma, semicolon) as border. "Any
occurrences" means two commas ",,", e.g., acting as one separator and not denoting an empty number.
N.b.: The string optArg will be modified (by replacing the first character of the token separators found by zero ('\0').
The number format accepted and parsed is decimal and hexadecimal. Hexadecimal starts with 0x or 0X. Leading zeros have no significance (in C stone age sense of being octal).
optArg | the string to be passed to a number of integer numbers, passed as program parameter, e.g. |
parsResult | pointer to an array of long int, minimal length 14 (!) |
Add two times as new structure.
t1 | summand as time structure (not NULL!, will be left unchanged) |
t2 | the second summand (dto.) |
Add two times overwriting the first operand.
t1 | the time structure to add to (not NULL!, will be modified) |
t2 | the summand (not NULL!, will be left unchanged) |
Compare two times.
t1 | the time structure to compare to t2 (not NULL!) |
t2 | the time structure to compare t1 with (not NULL!) |
void monoTimeResol | ( | timespec * | timeRes | ) |
Absolute time (source) resolution.
This function sets the time structure provided to the absolute time's (ABS_MONOTIME default: CLOCK_MONOTONIC) resolution.
Raspian Jessie on a Raspberry Pi 3 always yielded 1ns, which one may believe or not. We took it as "sufficient for accurate 1ms cycles".
timeRes | the time structure to be used (never NULL!) |
int timeSleep | ( | unsigned int | micros | ) |
Relative delay for the specified number of ‹¨«s.
This is local sleep. It should not be used in combination with absolute times and cyclic threads. It is just an utility for test or very short delays (as a better replacement for spinning).
micros | sleep time in ‹¨«s; allowed 30 .. 63000 |
void initStartRTime | ( | ) |
Initialise start (real) time.
This will be done in theCyclistStart(int). Hence, this function is for "non-cyclic" applications, mainly. Nevertheless it can be called before theCyclistStart(int) and won't be repeated therein.
int advanceTmTim | ( | struct tm * | rTm, |
char * | rTmTxt, | ||
uint8_t | sec | ||
) |
Advance broken down real time by seconds.
This function just advances the broken down (local) time structure rTm and the fitting text rTmTxt by 1 to 40s. All fields not affected by adding to the seconds part, won't be touched.
This function won't care about leap seconds nor handle DST rules. If this is to be kept up to date, it is recommended to refresh it on every hour change (return >=3) by
clock_gettime(CLOCK_REALTIME,..) and localtime_r(..).
Depending on OS, that might be an expensive operation with extra locks.
With wrong parameter values this function does nothing (returns 0).
rTm | pointer to broken down real time |
rTmTxt | date text, length 32, format Fr 2017-10-20 13:55:12.987 UTC+20 NULL is substituted by actRTmTxt |
sec | 1..40 will be added; else: error |
uint32_t ioSetClrSelect | ( | uint8_t | pin | ) |
Fetch a clear and set select bit for a GPIO pin.
For the masks to set or clear GPIO bits each bit 0..31 selects the GPIO pin 0..31 respectively 32..53.
pin | GPIO pin number (only 5 bits relevant here) |
void logErrWithText | ( | char const * | txt | ) |
Log error text (on errLog) with system error text appended.
Gives a (English) clear text translation of the latest system stored error. If txt is not null it will be prepended.
This function appends a linefeed and flushes errLog.
txt | text to be prepended (should nod be longer than 58 characters) |
int genErrWithText | ( | char const * | txt | ) |
Generate error text (errorText) with system error text appended.
Gives a (English) clear text translation of the latest system stored error. If txt is not null it will be prepended.
Date and time will be prepended anyway.
txt | text to be prepended (should nod be longer than 58 characters) |
void logErrorText | ( | void | ) |
Log the (last) common error text generated.
This function outputs the last generated errorText (by genErrWithText() e.g.) to errLog. It appends a linefeed and flushes errLog.
void logErrText | ( | char const * | txt | ) |
Log an error text on errLog.
If txt is not null it will be output to errLog and errLog will be flushed.
txt | text to be output; n.b not LF appended |
void logStampedText | ( | char const * | txt | ) |
Log an event or a message on outLog as line with time stamp.
If txt is not null it will be output to outLog. A time stamp is prepended and a line feed is appended. txt will be shortened to 50 characters if longer.
txt | the text to be output |
void onSignalExit | ( | int | s | ) |
On signal exit.
This function is intended as signal hook; see signal(s, hook). When called, this function calls exit(s) and never returns.
s | the signal forwarded to exit |
void onSignalExit0 | ( | int | s | ) |
On signal exit 0.
This function is intended as signal hook; see signal(s, hook).
When called this function calls exit(0) and never returns.
This may be used as hook for s==SIGIN, to provide a normal return on cntl-C.
s | ignored |
void onSignalStop | ( | int | s | ) |
On signal stop.
This function is a prepared signal hook. When called it sets sigRec by s and clears commonRun.
int cycTaskInit | ( | cycTask_t * | cykTask | ) |
Initialise a cyclic task / threads structure.
This function initialises a cyclic or non cyclic (asynchronous random event driven) task (thread) structure. Common mutex and an own condition are initialised, the event counter (.count) is set to 0.
Note: For the standard cycles provided here, 1ms, 100ms .., this initialisation is done in theCyclistStart() and the destruction (by cycTaskDestroy()) in endCyclist().
cykTask | the task structure to initialise (not NULL!) |
int cycTaskDestroy | ( | cycTask_t * | cykTask | ) |
Destroy a cyclic task / threads structure.
cykTask | the task structure to destroy (not NULL!) |
int cycTaskEvent | ( | cycTask_t * | cycTask, |
uint8_t | noEvents, | ||
timespec | stamp, | ||
cycTaskEventData_t | cycTaskEventData | ||
) |
Handle and signal events.
This is a helper function for the controller / manager to be called when having determined, that one or more events happened.
cycTask | the task structure (not NULL!) |
noEvents | number of events (usually 1); summand to cykTask.count |
stamp | absolute monotonic time of the event; sets sykTask.stamp |
cycTaskEventData | actual cyclic event data |
Wait on signalled event.
This is a helper function for a worker thread. It will return on reaching the signalled event(s) or on ! commonRun. If cykTaskSnap is not NULL cycTask will be assigned to it under mutex lock before returning. This is helpful if cykTask's events are broadcast to multiple handlers.
cycTask | the task structure (not NULL!) |
eventsThreshold | threshold for cykTask.count (update for every round) |
cycTaskSnap | copy of cykTask under mutex lock before returning |
uint32_t getCykTaskCount | ( | cycTask_t const *const | cycTask | ) |
Get a cycle's/task's current event counter.
This is done under (cyclist's) mutex lock.
cycTask | the task structure |
uint16_t stopMSwatch | ( | ) |
Get a (stop-watch) ms reading.
This function provides an 16 bit reading of the cyclist's (64 bit ) milliseconds. It is intended for measuring short (<= 1min) durations.
Hint: This functions thread safety stems from the hope of 16 bit increments being atomic. Even if no problems in this respect were observed on Raspberry Pi 3s, it may be just hope in the end. Thread-safe values are, of course, provided in the cycTaskEventData_t structure. But those are frozen within one cycle task step, and, hence, not usable as stop-watch readings within such step.
uint16_t getMSinS | ( | ) |
Get a ms in s reading.
This function provides the cyclist's ms in sec as 16 bit unsigned reading. It is intended for measuring and testing durations.
Hint: This functions does nothing for thread safety. It hopes 16 bit accesses being atomic. Even if no problems in this respect were observed on Raspberry Pi 3s, it may be just hope in the end. Thread-safe values are, of course, provided in the cycTaskEventData_t structure. But those are frozen within one cycle task step, and, hence, not usable as stop-watch readings within such step.
uint8_t get10inS | ( | ) |
Get a 10th of second in s reading.
This function provides the cyclist's tenth in seconds reading (0..9). It is intended for cyclic tasks with times greater than 100 ms or asynchronous tasks to get a coarse second sub-division.
Hint: Cyclic tasks get this value in their task date valid at start. This function provides an actual value for tasks running longer than 100ms.
uint32_t getAbsS | ( | ) |
Get the absolute s reading.
This function provides a 32 bit monotonic seconds value.
Base of this 32 bit value is the cyclist's 64 bit epoch time in seconds, 0 being 1.1.1970 00:00:00 UTC on almost all Linuxes and C libraries.
This unsigned 32 bit holds until 7. February 2106, which is far longer than the projected lifetime age of this library and of Raspberry Pi3s. (But who knows?) The value may be used for seconds-resolution, absolute (i.e. zone and DST independent) time-stamps and interval calculations (which will be incorrect with leap seconds).
Hint: Cyclic tasks get this value (.realSec) in their task date valid at tick start. Hence, this function is intended for asynchronous tasks or cyclic tasks with periods > 1s.
Since version R.110 we dare to fetch this value without lock, assuming ARMv7 32 bit load and stores being atomic.
int theCyclistStart | ( | int | startMsDelay | ) |
Start the cycles handler.
This function initialises and then runs the predefined cycles cycles (as of Sept. 2020: 1ms, 10ms, 20ms, 100ms and 1s; see have1msCyc) when enabled.
Besides the absolute / monotonic times for the cycles it also initialises real time and timers handling.
Timers and cycles are run in an extra thread made by this function. And to be precise, the cycles are not run here; instead, cyclic events are generated and broadcast.
As the thread started by this function also provides monotonic and civil times and stamps it should be started with the program (i.e. earliest in main()). Preparation time before the cycles should start can be handled by the delay parameter.
As of September 2020 five cycles (see above) are defined and handled. It is strongly recommended not to use more than two of them and implement other cycles with multiple periods by sub-division. That means, e.g., do not enable the 20ms cycle when having the 10ms one.
startMsDelay | number of ms before generating the first cyclic event; allowed range 12 .. 1200; default 1 |
int theCyclistWaitEnd | ( | ) |
Wait for the end of the cycles thread.
This function does so by unconditionally joining the cyclist thread.
int endCyclist | ( | void | ) |
The cycles handler arrived.
This function cleans up after theCyclist. It should be called after theCyclist() ending successfully on commonRun false. The controller thread shall call this function after having joined and cleaned up all of its threads. It may also be put in an exit hook.
|
extern |
Long array of length 14.
Prepared for non thread safe use with parse2Long()
|
extern |
Start time (structure, monotonic real time clock).
By initStartRTime() or by theCyclistStart() actRTime and this startRTime will initially be set. actRTime may be updated on demand, but startRTime should be left unchanged.
|
extern |
Actual broken down time (text).
|-3|- 10 -|1|- 12 -|
The format is: Fr 2017-10-20 13:55:12.987 UTC+20 ................0123456789x123456789v123456789t1234 was Fr 2017-10-20 13:55:12 UTC+20 The length is 32.
|
extern |
The current time as text.
/code The format is: 2017-10-20 13:55:12.987 UTC+20 ................0123456789x123456789v123456789 /endcode The length is 30.
Do NOT change the value provided by this pointer.
|
extern |
The real time epoch seconds.
Do NOT change the value provided by this pointer.
|
extern |
Common error text.
This text is set by genErrWithText() and hence indirectly by (many) other functions optionally generating error texts.
|
extern |
Common boolean run flag for all threads.
When set false, all threads must exit as soon as possible. On any case, a thread has to exit and clean up on next signal. Setting commonRun false implies the end of the application/program and all of its threads as soon as possible.
Initialised as 1 (true) Set 0 by onSignalStop() (or application program)
|
extern |
Storage for the signal (number) requesting exit.
Set by: onSignalStop()
See also: retCode
|
extern |
Common absolute / monotonic start time of all cycles.
May be considered as program's start time when cycles are started early by theCyclist. Normally not to be modified.
|
extern |
Flag to enable the 1ms cycle.
As a rule no more than two oft the cycles offered — cyc1ms, cyc10ms, cyc20ms, cyc100ms, cyc1sec — shall be enabled. This is no restriction as a faster cycle can easily (and often should) implement slower cycles by sub-division.
The default setting is 1ms and 100ms ON and all others OFF.
If other settings are used the flags should be set at the program's early initialisation phase and afterwards left untouched.
default: ON
|
extern |
|
extern |
|
extern |
|
extern |