Sorry for not having posted before, here's the whole code:
//#define DECODE_DENON // Includes Sharp
//#define DECODE_JVC
//#define DECODE_KASEIKYO
//#define DECODE_PANASONIC // alias for DECODE_KASEIKYO
//#define DECODE_LG
//#define DECODE_NEC // Includes Apple and Onkyo
#define DECODE_SAMSUNG
//#define DECODE_SONY
//#define DECODE_RC5
//#define DECODE_RC6
//#define DECODE_BOSEWAVE
//#define DECODE_LEGO_PF
//#define DECODE_MAGIQUEST
//#define DECODE_WHYNTER
//#define DECODE_FAST
//#define DECODE_DISTANCE_WIDTH // Universal decoder for pulse distance width protocols
//#define DECODE_HASH // special decoder for all protocols
//#define DECODE_BEO // This protocol must always be enabled manually, i.e. it is NOT enabled if no protocol is defined. It prevents decoding of SONY!
//#define DEBUG // Activate this for lots of lovely debug output from the decoders.
//#define RAW_BUFFER_LENGTH 180 // Default is 112 if DECODE_MAGIQUEST is enabled, otherwise 100.
#define DEVICE_ID 412 // device identifier (must be unique in range [000-999])
#define INTERRPIN 2 // interrupt pin connected to proximity sensor
#define SEROUTPIN 3 // serial data pin (output to displays)
#define SERCLKPIN 4 // serial clock pin (output to displays)
#define SERLATPIN 5 // serial latch out pin (output to displays)
#define OUTENAPIN 6 // display output enable (active low, output to displays)
#define NDIGIT 3 // number of display digits
#define BTN_ENTER 104 // IR code for ENTER button
#define BTN_y 7 // IR code for YES button (VOL +)
#define BTN_INFO 31 // IR code for INFO button (show DEVICE_ID)
#define BTN_EVENT 108 // IR code for EVENT BUTTON (simulate event)
#define IDLE_TIME_1 10 // timeout [s] of waiting for IR state
#define IDLE_TIME_2 30 // display idle time [s] on events absence
#define IDLE_TIME_3 3 // maximum period [s] after which the counter per minute variable is flattened to 0 (during Run state)
#define TEXT_DISP_TIME 2 // period [s] of text display (running mode)
#define COUNT_DISP_TIME 10 // period [s] of count display (running mode)
#define PAUSE_TIME 1 // period [s] of pause between text and count
#include <Arduino.h>
#include <EEPROM.h>
#include "PinDefinitionsAndMore.h" // Define macros for input and output pin etc.
#include <IRremote.hpp>
uint8_t machineState = 0; // machine state register
uint8_t irCodesCount = 0; // receiver IR codes counter
uint8_t immediateExit = 0; // routine exit flag
uint16_t irCodes[3] = {0, 0, 0}; // IR codes array
uint32_t time; // for keeping track of timeouts
uint32_t calculatedCrc; // calculated EEPROM CRC checksum during POST
uint32_t storedCrc; // stored EEPROM CRC checksum
uint8_t seconds; // for displaying multiple rows
uint16_t eventsMin = 0; // calculated events (or meters) per minute
uint8_t idleDisplay = 0; // display status flag
uint8_t counterMode; // 'E' for event counter [pcs/min], 'S' for speed meter [m/min]
uint16_t circum; // circumference length [mm] for speed meter mode
char name[6]; // production line name (to be displayed)
char text[NDIGIT]; // text buffer for displaying strings
const char defaultName[6] = "ABCDEF"; //default name of production line (EEPROM restore)
const uint16_t DEF_CIRCUM = 200; // default circumference length [mm] for speed meter mode (EEPROM restore)
const uint32_t DEF_STORED_CRC = 0x807ED417; //default satored CRC of EEPROM (must be recalculated at each byte change!!!)
const uint8_t msgTime = 2; // message time duration [s]
const uint8_t charMap[60] = {
// SEGMENT CHAR
// abcdefg.
0b00000000, // SPACE
0b01100001, // !
0b01000100, // "
0b00000000, // #
0b00000000, // $
0b00000000, // %
0b00000000, // &
0b01000000, // '
0b10011100, // (
0b11110000, // )
0b00000000, // *
0b00000000, // +
0b00000000, // ,
0b00000010, // -
0b00000001, // .
0b01001010, // /
0b11111100, // 0
0b01100000, // 1
0b11011010, // 2
0b11110010, // 3
0b01100110, // 4
0b10110110, // 5
0b10111110, // 6
0b11100000, // 7
0b11111110, // 8
0b11110110, // 9
0b00000000, // :
0b00000000, // ;
0b00000000, // <
0b00010010, // =
0b00000000, // >
0b11001010, // ?
0b00000000, // @
0b11101110, // A
0b00111110, // B
0b00011010, // C
0b01111010, // D
0b10011110, // E
0b10001110, // F
0b10111100, // G
0b01101110, // H
0b00001100, // I
0b01111000, // J
0b01101110, // K
0b00011100, // L
0b11101100, // M
0b00101010, // N
0b11111100, // O
0b11001110, // P
0b11100110, // Q
0b00001010, // R
0b10110110, // S
0b00011110, // T
0b01111100, // U
0b00111000, // V
0b01010100, // W
0b01101110, // X
0b01110110, // Y
0b11011010, // Z
0b11111111 // [ (ALL)
};
volatile uint32_t t1_us=0; // t1 event [microseconds] (note: isr managed variables must be volatile!)
volatile uint32_t t2_us=0; // t2 event [microseconds] (note: isr managed variables must be volatile!)
volatile uint32_t t2_ms=0; // t1 event [milliseconds] (note: isr managed variables must be volatile!)
volatile uint32_t events=0; // events counter (note: isr managed variables must be volatile!)
// __ __
// | | | |
// _____________| |______________| |_________________
// ^ ^
// t1 t2
//
void setup() {
pinMode(SEROUTPIN, OUTPUT); // pin mode definition
pinMode(SERCLKPIN, OUTPUT);
pinMode(SERLATPIN, OUTPUT);
pinMode(OUTENAPIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(INTERRPIN), isr0, FALLING); // interrupt pin to service routine association
Serial.begin(115200);
// Just to know which program is running on my Arduino
Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));
// Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
Serial.print(F("Ready to receive IR signals of protocols: "));
printActiveIRProtocols(&Serial);
Serial.println(F("at pin " STR(IR_RECEIVE_PIN)));
}
void loop() {
Serial.println(machineState);
switch (machineState) {
case 0: // Power On Self Test STATE
immediateExit = 0;
// display test
dispOut("[[[",NDIGIT,OUTENAPIN,255); // light on all display's segments
fadeIn(OUTENAPIN, 1);
fadeOut(OUTENAPIN, 1);
fadeIn(OUTENAPIN, 1);
fadeOut(OUTENAPIN, 1);
// EEPROM test
Serial.print(F("[S0] EEPROM byte length: "));
Serial.println(EEPROM.length());
Serial.print(F("[S0] Calculated CRC32 of EEPROM data: 0x"));
calculatedCrc = eeprom_crc(0, EEPROM.length()-4);
Serial.println(calculatedCrc, HEX);
Serial.print(F("[S0] Stored CRC32 of EEPROM data: 0x"));
EEPROM.get(EEPROM.length()-4, storedCrc);
Serial.println(storedCrc, HEX);
for (uint32_t i = 0; i < EEPROM.length() ; i++) {
if ((i % 64) == 0)
Serial.println();
Serial.print(EEPROM[i], HEX);
Serial.print(" ");
}
Serial.println();
if (storedCrc != calculatedCrc) {
Serial.println(F("[S0] Calculated CRC32 doesn't match stored CRC32 of EEPROM data. Possible data corruption! Set EEPROM to default values? [y]"));
do {
while (!IrReceiver.decode()) {
if ((((millis()/1000)%(msgTime*3))/msgTime)==0) { // prints CRC
dispOut("CRC",NDIGIT,OUTENAPIN,255);
}
if ((((millis()/1000)%(msgTime*3))/msgTime)==1) { // prints ERR
dispOut("ERR",NDIGIT,OUTENAPIN,255);
}
if ((((millis()/1000)%(msgTime*3))/msgTime)==2) { // prints blanks
dispOut(" ",NDIGIT,OUTENAPIN,255);
}
}
if(IrReceiver.decodedIRData.command == BTN_y) {
Serial.println(F("[S0] Setting EEPROM data to default values..."));
EEPROM.update(0,'E'); // default: 'E'vent counter mode;
EEPROM.put(1,DEF_CIRCUM); // default length of circumference for speed meter mode (uint16_t -> 2 bytes)
EEPROM.put(3,defaultName); // default name of production line (6 chars)
for (uint16_t i=9;i<EEPROM.length()-4;i++) {
EEPROM.update(i,0xff); // fill rest of the EEPROM with 0xff
}
EEPROM.put(EEPROM.length()-4,DEF_STORED_CRC); // write last 4 EEPROM bytes with default CRC32 of all EEPROM (warning: must be recalculated for each default byte change)
immediateExit = 1;
}
IrReceiver.resume();
}
while (!immediateExit);
}
counterMode=EEPROM.read(0); // get counter mode from EEPROM
EEPROM.get(1,circum); // get circumference length from EEPROM
EEPROM.get(3,name); // get production line name from EEPROM
Serial.print("[S0] Power On Self Test success, entering RUN STATUS [S1]");
machineState = 1;
break;
case 1: // RUN state
immediateExit = 0;
if ((millis()-t2_ms)>IDLE_TIME_2*1000 && idleDisplay==0) {
fadeOut(OUTENAPIN,1);
Serial.println(F("[S1] No events for a while. Idling display."));
}
if ((millis()-t2_ms)>IDLE_TIME_2*1000) {
idleDisplay=1;
} else {
idleDisplay=0;
}
if((micros()-t2_us)<IDLE_TIME_3*1000000 && t2_us!=t1_us) {
if(counterMode=='E') { // we are counting 'E'vents per minute (pieces per minute)
eventsMin = 60000000/(t2_us-t1_us); // events per minute
}
if(counterMode=='S') { // we are counting 'S'peed (meters per minute)
eventsMin = 60000*circum/(t2_us-t1_us); // meters per minute
}
} else {
eventsMin = 0;
}
if (!idleDisplay) { // display TEXT1 + TEXT2 + PAUSE + COUNT per MIN + PAUSE
if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<PAUSE_TIME) {
dispOut(" ",NDIGIT,OUTENAPIN,255); // light off all display's segments
} else if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<PAUSE_TIME+TEXT_DISP_TIME) {
for(uint8_t i=0;i<3;i++) text[i]=name[i];
dispOut(text,NDIGIT,OUTENAPIN,255);
} else if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<PAUSE_TIME+2*TEXT_DISP_TIME) {
for(uint8_t i=0;i<3;i++) text[i]=name[i+3];
dispOut(text,NDIGIT,OUTENAPIN,255);
} else if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<2*PAUSE_TIME+2*TEXT_DISP_TIME) {
dispOut(" ",NDIGIT,OUTENAPIN,255); // light off all display's segments
} else {
if(eventsMin>99) text[0]=eventsMin/100+'0';
else text[0]=' ';
if(eventsMin>9) text[1]=(eventsMin/10)%10+'0';
else text[1]=' ';
text[2]=eventsMin%10+'0';
dispOut(text,NDIGIT,OUTENAPIN,255);
}
}
if (IrReceiver.decode()) {
Serial.println(IrReceiver.decodedIRData.command); // LINE TO BE REMOVED - ONLY FOR TEST
switch(IrReceiver.decodedIRData.command) {
case BTN_INFO: // INFO button pressed: show DEVICE ID on display
text[0]=DEVICE_ID/100+'0';
text[1]=(DEVICE_ID-100*(text[0]-'0'))/10+'0';
text[2]=DEVICE_ID-100*(text[0]-'0')-10*(text[1]-'0')+'0';
Serial.println(F("[S1] Received INFO command, print DEVICE_ID on display"));
dispOut(text,NDIGIT,OUTENAPIN,255);
fadeOut(OUTENAPIN,1);
break;
case BTN_ENTER: // ENTER button pressed: enter LISTEN status
machineState = 2;
Serial.println(F("[S1] Received ENTER command, entering LISTEN STATUS [S2]"));
time=millis();
irCodesCount = 0;
break;
case BTN_EVENT: // EVENT button pressed: simulate event
Serial.println(F("[S1] Received EVENT command, simulating event."));
t1_us=t2_us;
t2_us=micros();
t2_ms=millis();
events++;
break;
}
IrReceiver.resume(); // Enable receiving of the next value
}
break;
case 2: // Listen Mode STATUS
char text[NDIGIT]="---";
dispOut(text,NDIGIT,OUTENAPIN,255);
while (irCodesCount < 3) {
if ((millis() - time) > 1000 * IDLE_TIME_1) {
machineState = 1;
immediateExit = 1;
Serial.println(F("[S2] Timeout reached, returning to RUN STATUS [S1]"));
fadeOut(OUTENAPIN, 1);
}
if (immediateExit) break;
if (IrReceiver.decode()) {
if (irCodeToDigitPlusOne(IrReceiver.decodedIRData.command)) { // if valid 0-9 keystroke detected
irCodes[irCodesCount] = irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1; // write corresponding array item
Serial.print(F("[S2] Valid keypress received: "));
Serial.println(irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1);
text[irCodesCount]=irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1+'0';
dispOut(text,NDIGIT,OUTENAPIN,255);
irCodesCount++; // increment array pointer
time=millis(); // reset timer for timeout
}
IrReceiver.resume(); // enable IR capture again
}
}
if (immediateExit) break;
if (irCodes[0]*100+irCodes[1]*10+irCodes[2] == DEVICE_ID) {
for(uint8_t i=0; i<5; i++) {
dim(OUTENAPIN,0);
delay(100);
dim(OUTENAPIN,255);
delay(100);
}
Serial.println(F("[S2] ID matches! Entering SETUP STATUS [S3]"));
machineState = 3;
} else {
Serial.println(F("[S2] ID doesn't match. Returning to RUN STATUS [S1]"));
fadeOut(OUTENAPIN,1);
machineState = 1;
}
break;
case 3: // Setup mode STATUS
Serial.println(F("[S3]"));
text[0]="-";
text[2]="-";
EEPROM.get(0,text[1]);
dispOut(text,NDIGIT,OUTENAPIN,255);
break;
}
//if(machineState==3) Serial.println(F("[S3]"));
}
// sketch specific function declarations
uint32_t eeprom_crc(uint16_t firstByte, uint16_t lastByte)
{
const uint32_t crc_table[16] =
{
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t crc = ~0L;
for (uint16_t index = firstByte ; index < lastByte ; ++index)
{
crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4);
crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4);
crc = ~crc;
}
return crc;
}
uint8_t irCodeToDigitPlusOne (uint8_t code) {
switch(code) // formatted to be less 'long'
{
case 4: return(2);
case 5: return(3);
case 6: return(4);
case 8: return(5);
case 9: return(6);
case 10: return(7);
case 12: return(8);
case 13: return(9);
case 14: return(10);
case 17: return(1);
default: return(0);
}
}
void dispOut (char text[], uint8_t n, uint8_t pin, uint8_t dim) {
//analogWrite(pin, 255); // dim to 0%
for(uint8_t i=n; i > 0; i--) {
shiftOut(SEROUTPIN, SERCLKPIN, LSBFIRST, charMap[text[i-1]-32]); // serial send chars
}
digitalWrite(SERLATPIN, HIGH); // latch out
digitalWrite(SERLATPIN, LOW);
analogWrite(pin, 255-dim); // dim to desired value
}
void dim (uint8_t pin, uint8_t dim) {
analogWrite(pin, 255 - dim);
}
void fadeIn (uint8_t pin, uint8_t time) {
for(uint16_t i = 0; i < 256; i++) {
analogWrite(pin, 255 - i);
delay(4*time);
}
}
void fadeOut (uint8_t pin, uint8_t time) {
for(uint16_t i = 0; i < 256; i++) {
analogWrite(pin, i);
delay(4*time);
}
}
// Interrupt service routine: called at each rising edge of signal coming from proximity sensor.
// t1 value takes the t2 value, while t2 value become actual time (both micros() and millis() values).
// Event counter value is increased.
void isr0() {
t1_us=t2_us;
t2_us=micros();
t2_ms=millis();
events++;
}