SRResources.h

documentation for the following objects:

object library
SRTimertimers; time as an event
SRLEDLED blinker and sequencer
SRButtonsimple momentary switch support
SRCRCCyclical Redundancy Check methods
SRPRNGpseudo-random number generators
SRLoopTallyloop() characterizing code
SRMessagerobust inter-processor messaging scheme

the library source is available from my github repository.

SRTimer

SRTimer is the core component of my fastCode strategy. SRTimer turns changes in time (via the millis() function) into simple repeating timed events. the SRTimer object supports any number of individual timers, each of which can be set to trigger (create an event) from 1..65535 milliseconds or 1..65535 deciseconds (655.35 seconds). set once by setTimer(), timers repeat indefinitely. they can be set to a new value at any time. timers can be reset (begin time interval anew) or triggered immediately.

#include <SRResources.h> SRTimer T; // instantiate the object const int TIMER1 = 0; const int TIMER2 = 1; const int TIMER3 = 2; const int NUMTIMERS = 3; void setup () { ... T.begin (NUMTIMERS); // allocates RAM for timers T.setTimer (TIMER2, 667); // timer 2 fires every 2/3rds of a second T.setTimer (TIMER1, 6000); // timer 1 fires every 6 seconds } void loop () { ... if (T.timer (TIMER2)) Serial.println ("timer 2 fires often"); if (T.timer (TIMER1)) Serial.println ("timer 1 fires not very often") }

RAM for timers is allocated by begin(). this allows determining the number of timers and therefore RAM used at run time.

fires.
void setTimer (int t, unsigned n);causes timer t to trigger an event at millis() plus time_interval mS in the future and every time_interval mS thereafter.
void setDeciTimer (int t, unsigned n);causes timer t to trigger an event at millis() plus time_interval deciseconds (1 decisecond == 100 mS) in the future and every time_interval deciseconds thereafter.
bool timer (t);returns true when timer t
unsigned long getTimer (t);returns the set interval for timer t.
unsigned long untilTimer (t);returns the number of milliseconds until timer t fires.
void trigTimer (t);causes timer t to immediately fire (eg. next call to timer())
void resetTimer (t);causes the countdown for timer t to start from the current time.

timers provide one millisecond resolution when used in an event loop strategy (see the main library page for details). timers fire when millis() reaches or exceeds the set time interval; code within loop() that blocks will defer timer firing for the amount of time blocked.

SRLED

this is a succinct system for visual system status using a single LED. there are two major modes of operation, blink and sequence. as are most of the SR libraries, the heart of the LED system is a state machine that must be invoked within loop() continuously. the state machine has extremely low latency (tens of microseconds).

both "modes" below are actually interoperable; see the method descriptions for details.

BLINK

the blink functions cause the LED to turn on and blink in a proscribed manner; on time, off time, and number of on/off blink cycles specified.

SEQUENCE

the sequence functions create a visual signalling space, where a discernable number of sequential blinks is used to signal status or events. the idea is that an interval is defined, typically one or two seconds and is split into a number of "time slots".

typical usage is to want to indicate various operating states of some remote and/or embedded machine that has no explicit information display. with an interval of 2.5 seconds divided into 8 slots, "normal" is indicated by a blink sequence of 1; in other words, the LED blinks one time in 2.5 seconds, within 1/8th of the interval. different operating states idle, busy, ready, error, waiting, etc) can be indicated by 2, 3, 4, 5, etc sequential blinks. given 8 time slots, three blinks followed by a pause (that is the remaining 5 blink times) is easily seen.

(in detail, each time slot is split between LED on and off times, with OFF being 3/5ths of the time slot and ON the rest.)

#include <SRResources.h> SRLED L; // instantiate void setup () { ... L.begin (13); // blink the built-in LED on pin 13 L.seqSetup (2000, 8); // 2 second loop, carved into 8 time slots L.seq (3); // blink 3 times per sequence } void loop () { ... L.LED(); // runs the LED state machine if (someEvent) L. blink (1000); // long blink If Something Happens }

SRLED conforms to my event loop strategy. the LED state machine takes microseconds to run, the load being effectively zero. the above example blinks the LED 3 times in two seconds. a schematic event (someEvent) in this example will cause the LED to remain on for one second, then return to the blink sequence. the LED() object manages all of the state changes.

void blink (n)causes the LED to blink on for n milliseconds, once.
void blink (n, m)causes the LED to blink on for n milliseconds, m times.
void blink (n, o, m)causes the LED to blink on for n milliseconds, off for o milliseconds, doing so m times.
void seqSetup (t, n)define a blink sequence whose length ist milliseconds, allocated into n time slots.
void seq (n)if a sequence has been defined with seqSetup(), causes the LED to blink on n times during the set interval.
void on()turns the LED on.
void off()turns the LED off.

SRButton

this provides simple access to any two-state digital sensor or electromechanical switch (momentary pushbutton, toggle, etc) attached between an input pin and ground. no pullup resistor is needed. debounce is automatic and built-in.

the most common use of a momentary switch is the initial depression event, and method pressed() provides that; however button() returns the current state of the switch for other uses.

SRButton is initialized by specifying the digital input pin, and optionally, the switch scan rate. if scan rate is not specified then 20 milliseconds is used, which works with nearly any switch.

the following example code will light the Arduino on-board LED for one second each time that a momentary switch attached to pin 8 is initially depressed.

#include <SRResources.h> SRLED L; // the LED SRButton PB; // the switch void setup () { PB.begin (8); // switch attached to pin 8 and ground L.begin (13); // the built-in LED on pin 13 } void loop () { if (PB.pressed()) { // if switch is pressed L.blink (1000); // LED on for one second } }
void begin (n)says that the switch is on pin n.
void begin (n, m)says that the switch is on pin n and to check the switch's physical state every m milliseconds.
bool pressed()returns true when the switch is first depressed, only.
int button()this returns the current state of the switch encoded as an integer. returns are:
 
0released
1just pressed
2just released
1is held depressed
(in fact, pressed() internally returns (button() == 1)).
void polarity (p)specifies switch polarity; use 1 for switch-press-connects-to-ground (default, aka negative logic) or 0 for switch-press-connects-to-5V (positive logic).

SRMessage.h

the SR Message system is a generalized system for sending, receiving, and parsing text-based messages. messages consist of a single command letter (A..Za..z) preceded by a decimal numeric argument in the range 0.65535. messages fit through all channels (Arduino IDE Serial Monitor, USB, radio, EEPROM) and are readable and typeable by humans. messages are extremely compact.

all message handling is done internally to the object, with the actual dispatching of (command-letter, numeric-argument) handled by user code of near trivial simplicity and compactness.

the overall programming model is straightforward. you the programmer need to code the command dispatcher (example below). after instantiation and initialization, the Message object is passed the address of your command dispatcher. thence, within loop(), block/string (radio, EEPROM) or character data (USB, etc) is passed to the object as it arrives. no further action is needed.

whether characters arrive all at once (block/string) or one at a time, the Message state machine decomposes characters into numeric value and command, and when complete, calls the user-code dispatcher to execute it.

since messages are simple digits:letter text strings, they can be generated with anything that can assemble character strings. however the provided message-building methods make this easy, and support Flock and Peep radio addressing as well.

when your program uses text-based commands for both communication (to a desktop Processing or other application, or to another controller via serial or SoftwareSerial, or via radio), the advantages of a uniform interface for all channels becomes more obvious. for example, program configuration storage in EEPROM is simply another destination/source for sending/receiving messages, eg. configuration commands. and it is then when priority levels become useful; you can easily give USB (Arduino IDE Serial Monitor) and EEPROM highest-priority to set global congiguration data (ID strings, whatever) that would be a bad idea to honor when arriving via radio.

instantiate a object with

SRMessage M;

instantiation does not allocate RAM nor resources. initialize the object (allocates RAM and resources) with:

void M.begin();

the message command dispatcher must be added before SRMessage can be used, generally from setup().

you the programmer must write the command dispatcher, but this is quite simple. follows is a perfectly usable example. the idea is that the hard part, the parsing state machine, error handling, etc, is done by the Message object, and the easiest part is done in your code -- storing or using a numeric argument from a command.

here is a typical command dispatcher. the address of this is passed to the Message object via addDispatcher(), below. the function must accept two arguments: a character and an unsigned integer.

void someDispatcher (int c, unsigned nnn) { switch (c) { case 'A': SOMEVARIABLE= nnn; break; // store a value case 'B': someFunction (nnn); break; // pass a value to a function case 'Z': digitalWrite (13, nnn); break; // manipulate a digital pin case -1: Serial.println ("checksum error"); break // (if checksums sent, see below) default: break; // wasn't a message we know after all } }

with the above function somewhere in your source code, you attach it to the Message system with:

addDispatcher (&someDispatcher);

MESSAGE SOURCES

a message source is simply where the serial characters originate from, eg. USB or one of the hardware serial ports in a Mega 2560, or SoftwareSerial, EEPROM, etc. text strings (fixed or variable) are also a source.

generally speaking you want all messages from a given stream (USB serial, or EEPROM, or a fixed string, etc) to each be handled by one SRMessage object and it's associated dispatcher. you might have global configuration data (serial port speed) stored in EEPROM that would be harmful if received from a serial port.

you will generally want to use only one of the following sources in a given SRMessage instantiation. characters arrive asynchronously; they mayy arrive all at once or spaced out in time. intermixing characters from two different serial streams is generally a bad idea. if you need to parse messages from multiple sources each should have it's own SRMessage object.

void rxUSB(); // all Arduino void rxSerial1(); // Mega 2560 only void rxSerial2(); // Mega 2560 only void rxSerial3(); // Mega 2560 only

rxChar is simply a generalization of the character methods above, for none-of-the-abouce character sources.

void rxChar (char c);

rxstring() is most useful for "block" type message strings, such as those stored in EEPROM, or delivered by radio. all characters that comprise the message string are available at once they are best parsed at once:

void rxString (char *p, unsigned len);

CREATING MESSAGES

the following methods build messages in a buffer to be displayed, transmitted, Serial.print()'d to USB, written to EEPROM, etc. message strings are built up message by message, each additional message appended to the string. message strings so produced are normal null-character-terminated C text strings.

messageBegin (char * buffer, unsigned buffSize);

messageBegin() specifies where the message is to be built/stored, and the buffer's maximum length. it is recommended that message strings be brief, which is usually the case anyway. Flock radio packet size is 32 characters maximum.

messageAdd (char c, unsigned nnn);

messageAdd() appends the message payload nnn and command letter c. if nnn is not zero it is ignored (a command letter without payload implies payload 0).

messageChar (char c);

messageChar() appends character c to the message. the most common use for it is to append a space character to increase human readability of the message string (at the expense of RAM to store it all).

MESSAGE-BUILDING EXAMPLES

char buff[32]; // typical use. M.messageBegin (buff, sizeof (buff)); // build messages here (results in "" in buff) M.messageAdd ('A', 1234); // command A, payload 1234 decimal M.messageAdd ('D', 0); // command D, zero payload... M.messageAdd ('Z', 1); Serial.println (buff); // will print out, literally: "1234AD1Z" // adds a space for human readability, otherwise the same as above. M.messageBegin (buff, sizeof (buff)); M.messageAdd ('A', 1234); M.messageChar (' '); M.messageAdd ('D', 0); M.messageChar (' '); M.messageAdd ('Z', 1); M.messageChar (' '); Serial.println (buff); // will print out, literally: "1234A D 1Z"

SRCRC

this is a software implementation of the Dallas/Maxim Semiconductor iButton 8-bit CRC algorithm. more than adequate for most communication needs and computationally light. this was "borrowed from the net", it is not my code, i simply packaged it as an Arduino library.

from http://nongnu.org/avr-libc/user-manual/group__util__crc.html Optimized Dallas (now Maxim) iButton 8-bit CRC calculation. Polynomial: x^8 + x^5 + x^4 + 1 (0x8C) Initial value: 0x0 See http://www.maxim-ic.com/appnotes.cfm/appnote_number/27

instantiate with

SRCRC8 CRC;

and initialize it with

CRC.begin();

the object contains two methods

uint8_t crc8buff (uint8_t * p, unsigned count); uint8_t crc8 (uint8_t crc, uint8_t data);

the first form calculates the polynomial over the specified block of data using an initial seed of 0. the second form accomodates coding your own loop, passing the accumulated crc each time (initially 0).

SRPRNG

object SRPRNG contains three separate Marsaglia XORshift pseudo-random number generators, 8, 16 and 32 bits. these are well-known, high quality pseudorandom sequence generators. all Marsaglia XORshift PRNGs return the same sequence when given the same starting seed, a feature required for certain applications such as radio frequency-hop sequences.

all PRNGs have limitations and these are no exception. the 32-bit version is probably suitable for crypto purposes, but i have not (and will not) check this code. ymmv. please rtfm, or at least skim the wikipedia page. at least the 32-bit version is known to have one severe limitation of importance: it never returns 0, which is serious when the result is used to traverse a table; but taking the result (modulo anything < 2e31) solves that. but even the 32-bit PRNG here is vastly faster than the admittedly high-quality PRNG in the Arduino library.

instantiate with

SRPRNG RNG;

this instantiates the object but doesn't allocate resources for it. do that with

RNG.begin();

begin() also seeds the sequence with the 0'th permutation of the seed. refer to the code if you care what the initial seed value is. if you want to specify another seed, do so with the appropriate method below. do not use 0 as a seed value for any of these methods. the sequence returned by subsequent calls to each PRNG will be the same for a given seed.

RNG.xor32seed (unsigned long s); RNG.xor16seed (uint16_t s); RNG.xor8seed (uint8_t s);

subsequent calls to each PRNG will return the next number in the sequence. xo32 will never return a 0 as noted above. the period of xor8() is 256, so it does return 0 (necessary for table scrambling and such).

long unsigned foo= RNG.xor32 (); uint16_t bar= RNG.xor16 (); uint8_t blatz= RNG.xor8 ();

two additional methods are provided for the 32 and 16 bit versions that constrain the return value to be within bounds, as the stdlib random (min, max) does. this is the only form; the others (zero or one argument) are not available. this makes no sense for the 8-bit version, since a signed char is rather silly most of the time. these follow the "google" convention of min and max. bounds may be signed.

long foo= RNG.random32 (long minimum, long maximum); int RNG.random16 (int minimum, int maximum);

last, and least, notes on the 32-bit version, from the source file:

this code is courtesy WebDrake https://github.com/WebDrake/xorshift/blob/master/xorshift.c see also this dicussion http://www.javamex.com/tutorials/random_numbers/xorshift.shtml#.VNmzLy5gHLU i have added a seed function that multplies the original, example seed with a passed parameter. this allows both ends to begin a predictable sequence. Marsaglia PRNG never returns 0, a serious problem if the return value is traversing a table; but used modulo (N < 32) problem solved.

notes on the 8 and 16 bit versions, from the source file:

low-quality PRNGs are fine for non-crypto stuff like lighting LEDs and "randoming" table traversals etc. added seed functions. found at http://www.arklyffe.com/main/2010/08/29/xorshift-pseudorandom-number-generator/

SRLoopTally

SRLoop measures basic loop() statistics: loop() iterations per second, average loop() execution time, longest loop() execution time.

the strategic goal is to help write code that does not block, that runs through loop() as fast as possible, in order to code to a state-machine, non-blocking, cooperative-tasking model so strongly implied (and desireable) in the Wiring setup()/loop() model.

this is a bit of a crock, admittedly; it's meant to be a lightweight test/performance hack. it makes some simplistic assumptions: the cpu can't execute more than (unsigned) iterations per specified report time. that loop() execution is more or less 1..65535 per second, all of the above entirely reasonable for ATMEGA328, MEGA 2560 and it's ilk.

the first report is often nonsense, as it initializes after the first report.

instantiate with

SRloopTally SRL;

>initialize it and specify the reporting interval, in seconds:

SRL.begin (10); // 10-second report interval

the background state machine is run by calling

unsigned x= SRL.tally();

continuously in loop(). it returns the longest iteration, in microseconds. somewhat useful for exceptionalizing crazy values ("if x > 100 SOMETHING BLOCKED").

at/after the specified report interval, tally() prints out one compact line:

#loop: 7582/s, 131uS avg, 2.13mS max

which indicates 7582 iterations/second, 131 microsecond average loop() execution time, the longest single loop() iteration of 2.13mS. 'longest' is of low resolution because the goal is to identify grossly anomalous loops (eg. encountering some function or code that blocks for an extended period) but the average time will display milliseconds (mS) or microseconds (uS) as appropriate.