| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805 |
- /*
- * Sketch for counting impulses in a defined interval
- * e.g. for power meters with an s0 interface that can be
- * connected to an input of an arduino board
- *
- * the sketch uses pin change interrupts which can be anabled
- * for any of the inputs on e.g. an arduino uno or a jeenode
- *
- * the pin change Interrupt handling used here
- * is based on the arduino playground example on PCINT:
- * http://playground.arduino.cc/Main/PcInt
- *
- * Refer to avr-gcc header files, arduino source and atmega datasheet.
- */
- /* Pin to interrupt map:
- * D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
- * D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
- * A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
- */
- /*
- Changes:
- V1.2
- 27.10.16 - use noInterrupts in report()
- - avoid reporting very short timeDiff in case of very slow impulses after a report
- - now reporting is delayed if impulses happened only within in intervalSml
- - reporting is also delayed if less than countMin pulses counted
- - extend command "int" for optional intervalSml and countMin
- 29.10.16 - allow interval Min >= Max or Sml > Min
- which changes behavior to take fixed calculation interval instead of timeDiff between pulses
- -> if intervalMin = intervalMax, counting will allways follow the reporting interval
- 3.11.16 - more noInterrupt blocks when accessing the non byte volatiles in report
- V1.3
- 4.11.16 - check min pulse width and add more output,
- - prefix show output with M
- V1.4
- 10.11.16 - restructure add Cmd
- - change syntax for specifying minPulseLengh
- - res (reset) command
- V1.6
- 13.12.16 - new startup message logic?, newline before first communication?
- 18.12.16 - replace all code containing Strings, new communication syntax and parsing from Jeelink code
- V1.7
- 2.1.17 - change message syntax again, report time as well, first and last impulse are reported relative to start of intervall
- not start of reporting intervall
- V1.8
- 4.1.17 - fixed a missing break in the case statement for pin definition
- 5.1.17 - cleanup debug logging
-
- ToDo / Ideas:
-
- new index scheme to save memory:
- array to map from pcintPin to new index, limit allowed pins.
- unused pcintpins point to -1 and vomment states arduino pin number
- insread of allowedPins array use new function from aPin to pcintPin
- and then look up in new array for index or -1
- */
-
- #include "pins_arduino.h"
- const char versionStr[] PROGMEM = "ArduCounter V1.8";
- const char errorStr[] PROGMEM = "Error: ";
- #define enablePulseLenChecking 1
- #define SERIAL_SPEED 38400
- #define MAX_ARDUINO_PIN 24
- #define MAX_PCINT_PIN 24
- #define MAX_INPUT_NUM 8
- /* arduino pins that are typically ok to use
- * (some are left out because they are used
- * as reset, serial, led or other things on most boards) */
- byte allowedPins[MAX_ARDUINO_PIN] =
- { 0, 0, 0, 3, 4, 5, 6, 7,
- 0, 9, 10, 11, 12, 0,
- 14, 15, 16, 17, 0, 0};
- /* Pin change mask for each chip port */
- volatile uint8_t *port_to_pcmask[] = {
- &PCMSK0,
- &PCMSK1,
- &PCMSK2
- };
- /* last PIN States to detect individual pin changes in ISR */
- volatile static uint8_t PCintLast[3];
- unsigned long intervalMin = 30000; // default 30 sec - report after this time if nothing else delays it
- unsigned long intervalMax = 60000; // default 60 sec - report after this time if it didin't happen before
- unsigned long intervalSml = 2000; // default 2 secs - continue count if timeDiff is less and intervalMax not over
- unsigned int countMin = 1; // continue counting if count is less than this and intervalMax not over
- unsigned long timeNextReport;
- /* index to the following arrays is the internal PCINT pin number, not the arduino
- * pin number because the PCINT pin number corresponds to the physical ports
- * and this saves time for mapping to the arduino numbers
- */
- /* pin change mode (RISING etc.) as parameter for ISR */
- byte PCintMode[MAX_PCINT_PIN];
- /* mode for timing pulse length - derived from PCintMode (RISING etc. */
- byte PulseMode[MAX_PCINT_PIN];
- /* pin number for PCINT number if active - otherwise -1 */
- char PCintActivePin[MAX_PCINT_PIN];
- /* did we get first interrupt yet? */
- volatile boolean initialized[MAX_PCINT_PIN];
-
- /* individual counter for each real pin */
- volatile unsigned long counter[MAX_PCINT_PIN];
- /* count at last report to get difference */
- unsigned long lastCount[MAX_PCINT_PIN];
- #ifdef enablePulseLenChecking
- /* individual reject counter for each real pin */
- volatile unsigned int rejectCounter[MAX_PCINT_PIN];
- unsigned int lastRejCount[MAX_PCINT_PIN];
- /* millis at last interrupt when signal was rising (for filtering with min pulse length) */
- volatile unsigned long lastPulseStart[MAX_PCINT_PIN];
- /* millis at last interrupt when signal was falling (for filtering with min pulse length) */
- volatile unsigned long lastPulseEnd[MAX_PCINT_PIN];
- /* minimal pulse length in millis */
- /* specified instead of rising or falling. isr needs to check change anyway */
- unsigned int pulseWidthMin[MAX_PCINT_PIN];
- /* sum of pulse lengths for average output */
- volatile unsigned long pulseWidthSum[MAX_PCINT_PIN];
- /* start of pulse for measuring length */
- byte pulseWidthStart[MAX_PCINT_PIN];
- #endif
- /* millis at first interrupt for current calculation
- * (is also last interrupt of old interval) */
- volatile unsigned long startTime[MAX_PCINT_PIN];
- /* millis at last interrupt */
- volatile unsigned long lastTime[MAX_PCINT_PIN];
- /* millis at first interrupt in a reporting cycle */
- volatile unsigned long startTimeRepInt[MAX_PCINT_PIN];
- /* millis at last report
- * to find out when maxInterval is over
- * and report has to be done even if
- * no impulses were counted */
- unsigned long lastReport[MAX_PCINT_PIN];
- unsigned int commandData[MAX_INPUT_NUM];
- byte commandDataPointer = 0;
- int digitalPinToPcIntPin(uint8_t aPin) {
- uint8_t pcintPin; // PCINT pin number for the pin to be added (index for most arrays)
- uint8_t port = digitalPinToPort(aPin) - 2; // port that this arduno pin belongs to for enabling interrupts
- if (port == 1) { // now calculate the PCINT pin number that corresponds to the arduino pin number
- pcintPin = aPin - 6; // port 1: PC0-PC5 (A0-A5 or D14-D19) is PCINT 8-13 (PC6 is reset)
- } else { // arduino numbering continues at D14 since PB6/PB7 are used for other things
- pcintPin = port * 8 + (aPin % 8); // port 0: PB0-PB5 (D8-D13) is PCINT 0-5 (PB6/PB7 is crystal)
- } // port 2: PD0-PD7 (D0-D7) is PCINT 16-23
- return pcintPin;
- }
- /* Add a pin to be handled */
- byte AddPinChangeInterrupt(uint8_t aPin) {
- uint8_t pcintPin; // PCINT pin number for the pin to be added (used as index for most arrays)
- volatile uint8_t *pcmask; // pointer to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
-
- uint8_t bit = digitalPinToBitMask(aPin); // bit in PCMSK to enable pin change interrupt for this arduino pin
- uint8_t port = digitalPinToPort(aPin); // port that this arduno pin belongs to for enabling interrupts
- if (port == NOT_A_PORT)
- return 0;
-
- port -= 2;
- pcmask = port_to_pcmask[port]; // point to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
- *pcmask |= bit; // set the pin change interrupt mask through a pointer to PCMSK0 or 1 or 2
- PCICR |= 0x01 << port; // enable the interrupt
- return 1;
- }
- /* Remove a pin to be handled */
- byte RemovePinChangeInterrupt(uint8_t aPin) {
- uint8_t pcintPin;
- volatile uint8_t *pcmask;
- uint8_t bit = digitalPinToBitMask(aPin);
- uint8_t port = digitalPinToPort(aPin);
- if (port == NOT_A_PORT)
- return 0;
- port -= 2;
- pcmask = port_to_pcmask[port];
- *pcmask &= ~bit; // disable the mask.
- if (*pcmask == 0) { // if that's the last one, disable the interrupt.
- PCICR &= ~(0x01 << port);
- }
- return 1;
- }
- void PrintErrorMsg() {
- int len = strlen_P(errorStr);
- char myChar;
- for (unsigned char k = 0; k < len; k++) {
- myChar = pgm_read_byte_near(errorStr + k);
- Serial.print(myChar);
- }
- }
- void printVersion() {
- int len = strlen_P(versionStr);
- char myChar;
- for (unsigned char k = 0; k < len; k++) {
- myChar = pgm_read_byte_near(versionStr + k);
- Serial.print(myChar);
- }
- }
- /*
- common interrupt handler. "port" is the PCINT port number (0-2)
-
- do counting and set start / end time of interval.
- reporting is not triggered from here.
-
- only here counter[] is modified
- lastTime[] is set here and in report
- startTime[] is set in case a pin was not initialized yet and in report
- */
- static void PCint(uint8_t port) {
- uint8_t bit;
- uint8_t curr;
- uint8_t mask;
- uint8_t pcintPin;
- unsigned long now = millis();
- #ifdef enablePulseLenChecking
- unsigned long len, gap;
- #endif
- // get the pin states for the indicated port.
- curr = *portInputRegister(port+2); // current pin states at port
- mask = curr ^ PCintLast[port]; // xor gets bits that are different
- PCintLast[port] = curr; // store new pin state for next interrupt
- if ((mask &= *port_to_pcmask[port]) == 0) // mask is pins that have changed. screen out non pcint pins.
- return; /* no handled pin changed */
- for (uint8_t i=0; i < 8; i++) {
- bit = 0x01 << i; // loop over each pin that changed
- if (bit & mask) { // did this pin change?
- pcintPin = port * 8 + i; // pcint pin numbers follow the bits, only arduino pin nums are special
- // count if mode is CHANGE, or if RISING and bit is high, or if mode is FALLING and bit is low.
- if ((PCintMode[pcintPin] == CHANGE
- || ((PCintMode[pcintPin] == RISING) && (curr & bit))
- || ((PCintMode[pcintPin] == FALLING) && !(curr & bit)))) {
- #ifdef enablePulseLenChecking
- if (pulseWidthMin[pcintPin]) { // check minimal pulse length and gap
- if ( ( (curr & bit) && pulseWidthStart[pcintPin] == RISING)
- || (!(curr & bit) && pulseWidthStart[pcintPin] == FALLING)) { // edge does fit defined start
- lastPulseStart[pcintPin] = now;
- continue;
- } else { // End of defined pulse
- gap = lastPulseStart[pcintPin] - lastPulseEnd[pcintPin];
- len = now - lastPulseStart[pcintPin];
- lastPulseEnd[pcintPin] = now;
- if (len < pulseWidthMin[pcintPin] || gap < pulseWidthMin[pcintPin]) {
- rejectCounter[pcintPin]++; // pulse too short
- continue;
- }
- pulseWidthSum[pcintPin] += len; // for average calculation
- }
- }
- #endif
- lastTime[pcintPin] = now; // remember time of in case pulse will be the last in the interval
- if (!startTimeRepInt[pcintPin]) startTimeRepInt[pcintPin] = now; // time of first impulse in this reporting interval
- if (initialized[pcintPin]) {
- counter[pcintPin]++; // count
- } else {
- startTime[pcintPin] = lastTime[pcintPin]; // if this is the very first impulse on this pin -> start interval now
- initialized[pcintPin] = true; // and start counting the next impulse (so far counter is 0)
- }
- }
- }
- }
- }
- /*
- report count and time for pins that are between min and max interval
-
- lastCount[] is only modified here (count at time of last reporting)
- lastTime[] is modified here and in ISR - disable interrupts in critcal moments to avoid garbage in var
- startTime[] is modified only here (or for very first Interrupt in ISR) -> no problem.
- */
- void report() {
- int aPin;
- unsigned long count, countDiff;
- unsigned long timeDiff, now;
- unsigned long startT, endT;
- unsigned long avgLen;
- now = millis();
- for (int pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++) { // go through all observed pins as PCINT pin number
- aPin = PCintActivePin[pcintPin]; // take saved arduino pin number
- if (aPin < 0) continue; // -1 means pin is not active for reporting
- noInterrupts();
- startT = startTime[pcintPin];
- endT = lastTime[pcintPin];
- count = counter[pcintPin]; // get current counter
- interrupts();
-
- timeDiff = endT - startT; // time between first and last impulse during interval
- countDiff = count - lastCount[pcintPin]; // how many impulses since last report? (works with wrapping)
- if((long)(now - (lastReport[pcintPin] + intervalMax)) >= 0) { // intervalMax is over
- if ((countDiff >= countMin) && (timeDiff > intervalSml) && (intervalMin != intervalMax)) {
- // normal procedure
- lastCount[pcintPin] = count; // remember current count for next interval
- noInterrupts();
- startTime[pcintPin] = endT; // time of last impulse in this interval becomes also time of first impulse in next
- interrupts();
- } else {
- // nothing counted or counts happened during a fraction of intervalMin only
- noInterrupts();
- lastTime[pcintPin] = now; // don't calculate with last impulse, use now instead
- startTime[pcintPin] = now; // start a new interval for next report now
- interrupts();
- lastCount[pcintPin] = count; // remember current count for next interval
- timeDiff = now - startT; // special handling - calculation ends now instead of last impulse
- }
- } else if((long)(now - (lastReport[pcintPin] + intervalMin)) >= 0) { // minInterval has elapsed
- if ((countDiff >= countMin) && (timeDiff > intervalSml)) {
- // normal procedure
- lastCount[pcintPin] = count; // remember current count for next interval
- noInterrupts();
- startTime[pcintPin] = endT; // time of last impulse in this interval becomes also time of first impulse in next
- interrupts();
- } else continue; // not enough counted - wait
- } else continue; // intervalMin not over - wait
- Serial.print(F("R")); // R Report
- Serial.print(aPin);
- Serial.print(F(" C")); // C - Count
- Serial.print(count);
- Serial.print(F(" D")); // D - Count Diff
- Serial.print(countDiff);
- Serial.print(F(" T")); // T - Time
- Serial.print(timeDiff);
- Serial.print(F(" N")); // N - now
- Serial.print((long)now);
-
- #ifdef enablePulseLenChecking
- // rejected count ausgeben
- // evt auch noch average pulse len und gap len
- if (pulseWidthMin[pcintPin]) { // check minimal pulse length and gap
- Serial.print(F(" X")); // X Reject
- Serial.print(rejectCounter[pcintPin] - lastRejCount[pcintPin]);
- noInterrupts();
- lastRejCount[pcintPin] = rejectCounter[pcintPin];
- interrupts();
- }
- #endif
- if (countDiff) {
- Serial.print(F(" F")); // F - first impulse after the one that started the interval
- Serial.print((long)startTimeRepInt[pcintPin] - startT);
- Serial.print(F(" L")); // L - last impulse - marking the end of this interval
- Serial.print((long)endT - startT);
- startTimeRepInt[pcintPin] = 0;
-
- #ifdef enablePulseLenChecking
- if (pulseWidthMin[pcintPin]) {// check minimal pulse length and gap
- noInterrupts();
- avgLen = pulseWidthSum[pcintPin] / countDiff;
- pulseWidthSum[pcintPin] = 0;
- interrupts();
- Serial.print(F(" A"));
- Serial.print(avgLen);
- }
- #endif
- }
- Serial.println();
- lastReport[pcintPin] = now; // remember when we reported
- }
- }
- /* print status for one pin */
- void showPin(byte pcintPin) {
- unsigned long newCount;
- unsigned long countDiff;
- unsigned long timeDiff;
- unsigned long avgLen;
- timeDiff = lastTime[pcintPin] - startTime[pcintPin];
- newCount = counter[pcintPin];
- countDiff = newCount - lastCount[pcintPin];
- if (!timeDiff)
- timeDiff = millis() - startTime[pcintPin];
- Serial.print(F("PCInt pin "));
- Serial.print(pcintPin);
-
- Serial.print(F(", iMode "));
- switch (PCintMode[pcintPin]) {
- case RISING: Serial.print(F("rising")); break;
- case FALLING: Serial.print(F("falling")); break;
- case CHANGE: Serial.print(F("change")); break;
- }
- #ifdef enablePulseLenChecking
- if (pulseWidthMin[pcintPin] > 0) {
- Serial.print(F(", min len "));
- Serial.print(pulseWidthMin[pcintPin]);
- Serial.print(F(" ms"));
- switch (pulseWidthStart[pcintPin]) {
- case RISING: Serial.print(F(" rising")); break;
- case FALLING: Serial.print(F(" falling")); break;
- }
- } else {
- Serial.print(F(", no min len"));
- }
- #endif
- Serial.print(F(", count "));
- Serial.print(newCount);
- Serial.print(F(" (+"));
- Serial.print(countDiff);
- Serial.print(F(") in "));
- Serial.print(timeDiff);
- Serial.print(F(" ms"));
- #ifdef enablePulseLenChecking
- // rejected count ausgeben
- // evt auch noch average pulse len und gap len
- if (pulseWidthMin[pcintPin]) { // check minimal pulse length and gap
- Serial.print(F(" Rej "));
- Serial.print(rejectCounter[pcintPin] - lastRejCount[pcintPin]);
- }
- #endif
- if (countDiff) {
- Serial.println();
- Serial.print(F("M first at "));
- Serial.print((long)startTimeRepInt[pcintPin] - lastReport[pcintPin]);
- Serial.print(F(", last at "));
- Serial.print((long)lastTime[pcintPin] - lastReport[pcintPin]);
- #ifdef enablePulseLenChecking
- noInterrupts();
- avgLen = pulseWidthSum[pcintPin] / countDiff;
- interrupts();
- Serial.print(F(", avg len "));
- Serial.print(avgLen);
- #endif
- }
- }
- /* give status report in between if requested over serial input */
- void showCmd() {
- unsigned long newCount;
- unsigned long countDiff;
- unsigned long timeDiff;
- unsigned long avgLen;
- char myChar;
- Serial.print(F("M Status: "));
- printVersion();
- Serial.println();
- Serial.print(F("M normal interval "));
- Serial.println(intervalMin);
- Serial.print(F("M max interval "));
- Serial.println(intervalMax);
- Serial.print(F("M min interval "));
- Serial.println(intervalSml);
- Serial.print(F("M min count "));
- Serial.println(countMin);
-
- for (byte pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++) {
- int aPin = PCintActivePin[pcintPin];
- if (aPin != -1) {
- timeDiff = lastTime[pcintPin] - startTime[pcintPin];
- newCount = counter[pcintPin];
- countDiff = newCount - lastCount[pcintPin];
- if (!timeDiff)
- timeDiff = millis() - startTime[pcintPin];
- Serial.print(F("M pin "));
- Serial.print(aPin);
- Serial.print(F(" "));
- showPin(pcintPin);
- Serial.println();
- }
- }
- Serial.print(F("M Next report in "));
- Serial.print(timeNextReport - millis());
- Serial.print(F(" Milliseconds"));
- Serial.println();
- }
- /*
- handle add command.
- */
- void addCmd(unsigned int *values, byte size) {
- uint8_t pcintPin; // PCINT pin number for the pin to be added (used as index for most arrays)
- byte mode;
- unsigned int pw;
- unsigned long now = millis();
- //Serial.println(F("M Add called"));
- int aPin = values[0];
- pcintPin = digitalPinToPcIntPin(aPin);
- if (aPin >= MAX_ARDUINO_PIN || aPin < 1
- || allowedPins[aPin] == 0 || pcintPin > MAX_PCINT_PIN) {
- PrintErrorMsg();
- Serial.print(F("Illegal pin specification "));
- Serial.println(aPin);
- return;
- };
-
- switch (values[1]) {
- case 2:
- mode = FALLING;
- pulseWidthStart[pcintPin] = FALLING;
- break;
- case 3:
- mode = RISING;
- pulseWidthStart[pcintPin] = RISING;
- break;
- case 1:
- mode = CHANGE;
- break;
- default:
- PrintErrorMsg();
- Serial.print(F("Illegal pin specification "));
- Serial.println(aPin);
- }
-
- pinMode (aPin, INPUT);
- if (values[2]) {
- digitalWrite (aPin, HIGH); // enable pullup resistor
- }
- #ifdef enablePulseLenChecking
- PulseMode[pcintPin] = mode; // specified mode also defines pulse level in this case
- if (values[3] > 0) {
- pw = values[3];
- mode = CHANGE;
- } else {
- pw = 0;
- }
- #endif
-
- if (!AddPinChangeInterrupt(aPin)) { // add Pin Change Interrupt
- PrintErrorMsg(); Serial.println(F("AddInt"));
- return;
- }
- PCintMode[pcintPin] = mode; // save mode for ISR which uses the pcintPin as index
- #ifdef enablePulseLenChecking
- pulseWidthMin[pcintPin] = pw; // minimal pulse width in millis, 3 if not specified n add cmd
- #endif
-
- if (PCintActivePin[pcintPin] != aPin) { // in case this pin is already active counting
- PCintActivePin[pcintPin] = aPin; // save real arduino pin number and flag this pin as active for reporting
- initialized[pcintPin] = false; // initialize arrays for this pin
- counter[pcintPin] = 0;
- lastCount[pcintPin] = 0;
- startTime[pcintPin] = now;
- lastTime[pcintPin] = now;
- lastReport[pcintPin] = now;
- }
- Serial.print(F("M defined pin "));
- Serial.print(aPin);
- Serial.print(F(" "));
- showPin(pcintPin);
- Serial.println();
- }
- /*
- handle rem command.
- */
- void removeCmd(unsigned int *values, byte size) {
- uint8_t pcintPin; // PCINT pin number for the pin to be added (used as index for most arrays)
- int aPin = values[0];
- pcintPin = digitalPinToPcIntPin(aPin);
- if (aPin >= MAX_ARDUINO_PIN || aPin < 1
- || allowedPins[aPin] == 0 || pcintPin > MAX_PCINT_PIN) {
- PrintErrorMsg();
- Serial.print(F("Illegal pin specification "));
- Serial.println(aPin);
- return;
- };
-
- if (!RemovePinChangeInterrupt(aPin)) {
- PrintErrorMsg(); Serial.println(F("RemInt"));
- return;
- }
-
- PCintActivePin[pcintPin] = -1;
- initialized[pcintPin] = false; // reset for next add
- counter[pcintPin] = 0;
- lastCount[pcintPin] = 0;
- #ifdef enablePulseLenChecking
- pulseWidthMin[pcintPin] = 0;
- lastRejCount[pcintPin] = 0;
- rejectCounter[pcintPin] = 0;
- #endif
- Serial.print(F("M removed "));
- Serial.println(aPin);
- }
- void intervalCmd(unsigned int *values, byte size) {
- if (size < 4) {
- PrintErrorMsg();
- Serial.print(F("size"));
- Serial.println();
- return;
- }
- if (values[0] < 1 || values[0] > 3600) {
- PrintErrorMsg(); Serial.println(values[0]);
- return;
- }
- intervalMin = (long)values[0] * 1000;
- if (millis() + intervalMin < timeNextReport)
- timeNextReport = millis() + intervalMin;
- if (values[1] < 1 || values[1] > 3600) {
- PrintErrorMsg(); Serial.println(values[1]);
- return;
- }
- intervalMax = (long)values[1]* 1000;
-
- if (values[2] > 3600) {
- PrintErrorMsg(); Serial.println(values[2]);
- return;
- }
- if (values[2] > 0) {
- intervalSml = (long)values[2] * 1000;
- }
-
- if (values[3]> 0) {
- countMin = values[3];
- }
- Serial.print(F("M intervals set to "));
- Serial.print(values[0]);
- Serial.print(F(" "));
- Serial.print(values[1]);
- Serial.print(F(" "));
- Serial.print(values[2]);
- Serial.print(F(" "));
- Serial.print(values[3]);
- Serial.println();
- }
- void helloCmd() {
- Serial.println();
- printVersion();
- Serial.println(F("Hello"));
- }
- static void HandleSerialPort(char c) {
- static unsigned int value;
- if (c == ',') {
- if (commandDataPointer + 1 < MAX_INPUT_NUM) {
- commandData[commandDataPointer++] = value;
- value = 0;
- }
- }
- else if ('0' <= c && c <= '9') {
- value = 10 * value + c - '0';
- }
- else if ('a' <= c && c <= 'z') {
- switch (c) {
- case 'a':
- commandData[commandDataPointer] = value;
- addCmd(commandData, ++commandDataPointer);
- commandDataPointer = 0;
- break;
- case 'd':
- commandData[commandDataPointer] = value;
- removeCmd(commandData, ++commandDataPointer);
- commandDataPointer = 0;
- break;
- case 'i':
- commandData[commandDataPointer] = value;
- intervalCmd(commandData, ++commandDataPointer);
- commandDataPointer = 0;
- break;
- case 'r':
- setup();
- commandDataPointer = 0;
- break;
- case 's':
- showCmd();
- commandDataPointer = 0;
- break;
- case 'h':
- helloCmd();
- commandDataPointer = 0;
- break;
- default:
- commandDataPointer = 0;
- //PrintErrorMsg(); Serial.println();
- break;
- }
- value = 0;
- }
- }
- SIGNAL(PCINT0_vect) {
- PCint(0);
- }
- SIGNAL(PCINT1_vect) {
- PCint(1);
- }
- SIGNAL(PCINT2_vect) {
- PCint(2);
- }
- void setup() {
- unsigned long now = millis();
-
- for (int pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++) {
- PCintActivePin[pcintPin] = -1; // set all pins to inactive (-1)
- initialized[pcintPin] = false; // initialize arrays for this pin
- counter[pcintPin] = 0;
- lastCount[pcintPin] = 0;
- startTime[pcintPin] = now;
- lastTime[pcintPin] = now;
- #ifdef enablePulseLenChecking
- lastPulseStart[pcintPin] = now;
- lastPulseEnd[pcintPin] = now;
- pulseWidthMin[pcintPin] = 0;
- rejectCounter[pcintPin] = 0;
- lastRejCount[pcintPin] = 0;
- #endif
- lastReport[pcintPin] = now;
- }
-
- timeNextReport = millis() + intervalMin; // time for first output
- Serial.begin(SERIAL_SPEED); // initialize serial
- delay (500);
- interrupts();
- Serial.println();
- printVersion();
- Serial.println(F("Started"));
- }
- /*
- Main Loop
- checks if report should be called because timeNextReport is reached
- or lastReport for one pin is older than intervalMax
- timeNextReport is only set here (and when interval is changed / at setup)
- */
- void loop() {
- unsigned long now = millis();
-
- if (Serial.available()) {
- HandleSerialPort(Serial.read());
- }
- boolean doReport = false; // check if report nedds to be called
- if((long)(now - timeNextReport) >= 0) // works fine when millis wraps.
- doReport = true; // intervalMin is over
- else
- for (byte pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++)
- if (PCintActivePin[pcintPin] >= 0)
- if((long)(now - (lastReport[pcintPin] + intervalMax)) >= 0)
- doReport = true; // active pin has not been reported for langer than intervalMax
- if (doReport) {
- report();
- timeNextReport = now + intervalMin; // do it again after intervalMin millis
- }
- }
|