diff --git a/sw/boitarire_sw/boitarire_sw.ino b/sw/boitarire_sw/boitarire_sw.ino index 1d2b6179551d175a092ab742ce47d279f9105df3..aa456520830ed7b9228d6b6ba0929314bce6e0e5 100644 --- a/sw/boitarire_sw/boitarire_sw.ino +++ b/sw/boitarire_sw/boitarire_sw.ino @@ -1,482 +1,482 @@ -/* - Boitarire software - - Plays a sound through an external MP3 module - when triggered by external sensor : - - inclination switch - - accelerometer module - - touch sensors - Configuration is selected through compilation switches. - Uses an editable playlist allowing any song order, - up to 255 different songs in the playlist, individual - repetition number for eah song. - - created 25 nov 2021 - by Florian Savard - - This example code is in the public domain. - - https://code.electrolab.fr/Flax/boitarire -*/ - -#include - -// Defines - Macros - Constants - -#define SENSOR_INCLINATION -//#define SENSOR_ACCELEROMETER -//#define SENSOR_TOUCH_SENSOR1 -//#define SENSOR_TOUCH_SENSOR2 - - -// Other constants -//Hardwaere constatnts : do not modify >_< ! -#define PIN_SENSOR_POSITION 9 // Position sensor input -#define PIN_TOUCH_SENSOR1 8 // Touch sensor 1 input -#define PIN_TOUCH_SENSOR2 5 // Touch sensor 2 input -#define PIN_GROUND_SWITCH 7 // MP3 module ground switch command output - -//Calibration constants : do adjust :-) -//#define MP3_RESET -// -//#define DEBUG_UART_ACCELEROMETER // Warning : conflict with MP3 player -#define PLAY_BLANK_DELAY 1000 // Blanking when playing a sound (ms): Must be longer than the played sample (recommended : sample duration + 100ms) -#define DELAY_MP3_RESET 100 // Time of ground cut of MP3 module for re-init (ms) : Adjust only if hardware proiblems with new revisions of the mp3 module -#define DEBOUNCE_DELAY 200 // Position sensor input debounce (ms) -#define ACCEL_THRES_GYX 1000 // Detection threshold for X axis acceleration -#define ACCEL_THRES_GYY 1000 // Detection threshold for Y axis acceleration -#define ACCEL_THRES_GYZ 1000 // Detection threshold for Z axis acceleration -#define PLAYLIST_LENGTH 4 // Number of songs in the playlist - -// Typedefs -// Main state machine : start actions -typedef enum -{ - //Initialisation - STM_INIT, - //Wainting for input (capteur) - STM_IDLE, - //When input, play sample - STM_PLAY, - //Waiting after playing sample - STM_BLANK, - //Optional hardware reset of the MP3 module (See calibration constants for activation) - STM_MP3_RESET, -} tStateMachine; - -typedef enum -{ - STM_DEBOUNCE_IDLE_0, - STM_DEBOUNCE_IDLE_1, - STM_DEBOUNCE_DETECT_0, - STM_DEBOUNCE_DETECT_1, - STM_DEBOUNCE_DEBOUNCE_0, - STM_DEBOUNCE_DEBOUNCE_1, -} tStateMachineDebounce; - -typedef struct -{ - uint8_t song_index_u8; // Index of the song in the device /!\ counts from 0 - uint8_t cycles_number_u8; // Number of times the song must be played before switching to the next -} tSongItem; - -// Constant variables - -/* Indifference table for songs cycles - * Contains the indexes of the songs to be played and the number of times each one must be played. - * Contains couples {index of the song in the MP3 device memory, number of times the song must be played}, - * Playlist cycles from first element to last and loops. - * Don't forget to update PLAYLIST_LENGTH define. - */ -const tSongItem cPlaylistIndif_TA[PLAYLIST_LENGTH] = -{ - {0, 2}, - {2, 3}, - {1, 1}, - {3, 2}, -}; - -// Local variables -String inputString = ""; // a String to hold incoming data -bool stringComplete = false; // whether the string is complete - -unsigned long debounce_delay; -int input_position_sensor, input_touch_sensor1, input_touch_sensor2; -unsigned long play_blank_delay, mp3_reset_delay; -unsigned long millis_temp; - -const int MPU=0x68; -int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; -bool accel_detect; - -uint8_t song_cycles_cnt_u8; // Counts the number of times the current song has been played -uint8_t song_playing_current_u8; // Holds the index of the playlist song actually being played - -// State machines states -tStateMachine stmState; -tStateMachineDebounce stmDebounceState; - -// Local function prototypes -void ReadPlayState (void); -void WritePlay (void); -void WritePlaySong (uint16_t index); -uint8_t CrcCalculate (uint8_t *buff, uint8_t size); - -// Setup function -void setup() { - // Initialize serial: - Serial.begin(9600); - // Reserve 200 bytes for the inputString: - inputString.reserve(200); - - // Position sensor input pin - See hardware constants for pin definition - Input pull-up - pinMode(PIN_SENSOR_POSITION, INPUT_PULLUP); - - // Touch sensor 1 input pin - See hardware constants for pin definition - Input no pull - pinMode(PIN_TOUCH_SENSOR1, INPUT); - - // Touch sensor 2 input pin - See hardware constants for pin definition - Input no pull - pinMode(PIN_TOUCH_SENSOR2, INPUT); - - // LED output for visualisation - pinMode(LED_BUILTIN, OUTPUT); - - // MP3 module ground switch command - See hardware constants for pin definition - Output push-pull - pinMode(PIN_GROUND_SWITCH, OUTPUT); - - //Initialise variables, do not define constants value here - play_blank_delay = 0; - mp3_reset_delay = 0; - stmState = STM_INIT; - stmDebounceState = STM_DEBOUNCE_IDLE_0; - debounce_delay = 0; - input_position_sensor = LOW; - input_touch_sensor1 = LOW; - input_touch_sensor2 = LOW; - song_cycles_cnt_u8 = 0; - song_playing_current_u8 = 0; - -#ifdef SENSOR_ACCELEROMETER - // Accelerometer setup - Wire.begin(); - Wire.beginTransmission(MPU); - Wire.write(0x6B); - Wire.write(0); - Wire.endTransmission(true); - - // Set FIFO enable register - /* Wire.beginTransmission(MPU); - Wire.write(0x23); - Wire.write(0x78); - Wire.endTransmission(true);*/ - - // Set filters - Wire.beginTransmission(MPU); - Wire.write(0x1A); - Wire.write(0x06); - Wire.endTransmission(true); -#endif - accel_detect = false; - - // Connect ground for MP3 module - digitalWrite(PIN_GROUND_SWITCH, HIGH); -} - -// Main loop -void loop() { - // print the string when a newline arrives: for debug purposes only - if (stringComplete) { - Serial.println(inputString); - - switch (inputString[0]) - { - case 0x30: - // Play first song in the device - WritePlaySong(1); - break; - case 0x31: - // Play second song in the device - WritePlaySong(2); - break; - default: - break; - } - - // clear the string: - inputString = ""; - stringComplete = false; - } - -#ifdef SENSOR_ACCELEROMETER - // Accelerometer communication - Wire.beginTransmission(MPU); - Wire.write(0x3B); - Wire.endTransmission(false); - Wire.requestFrom(MPU,14,true); - AcX=Wire.read()<<8|Wire.read(); - AcY=Wire.read()<<8|Wire.read(); - AcZ=Wire.read()<<8|Wire.read(); - Tmp=Wire.read()<<8|Wire.read(); - GyX=Wire.read()<<8|Wire.read(); - GyY=Wire.read()<<8|Wire.read(); - GyZ=Wire.read()<<8|Wire.read(); - - if ((GyX > ACCEL_THRES_GYX) || - (GyY > ACCEL_THRES_GYY) || - (GyZ > ACCEL_THRES_GYZ) || - (GyX < ((int16_t)(-1) * ACCEL_THRES_GYX)) || - (GyY < ((int16_t)(-1) * ACCEL_THRES_GYY)) || - (GyZ < ((int16_t)(-1) * ACCEL_THRES_GYZ))) - { - accel_detect = true; - } - else - { - accel_detect = false; - } -#else - accel_detect = false; -#endif - -#ifdef SENSOR_INCLINATION - // Read instantaneous value of position sensor - input_position_sensor = digitalRead(PIN_SENSOR_POSITION); -#else - input_position_sensor = LOW; -#endif - - // Inclination debounce state machine - //----------------------------------- - switch (stmDebounceState) - { - case STM_DEBOUNCE_IDLE_0: - if (input_position_sensor == HIGH) - { - stmDebounceState = STM_DEBOUNCE_DETECT_1; - debounce_delay = millis(); - } - break; - - case STM_DEBOUNCE_IDLE_1: - if (input_position_sensor == LOW) - { - stmDebounceState = STM_DEBOUNCE_DETECT_0; - debounce_delay = millis(); - } - break; - - case STM_DEBOUNCE_DETECT_0: - millis_temp = millis(); - if (input_position_sensor == HIGH) - { - stmDebounceState = STM_DEBOUNCE_IDLE_1; - } - else if ((millis_temp >= debounce_delay) && ((millis_temp - debounce_delay) > DEBOUNCE_DELAY)) - { - stmDebounceState = STM_DEBOUNCE_DEBOUNCE_0; - } - else if (millis_temp < debounce_delay) - { // Overflow protection for uptime of several weeks or more. - debounce_delay = 0; - } - break; - - case STM_DEBOUNCE_DETECT_1: - millis_temp = millis(); - if (input_position_sensor == LOW) - { - stmDebounceState = STM_DEBOUNCE_IDLE_0; - } - else if ((millis_temp >= debounce_delay) && ((millis_temp - debounce_delay) > DEBOUNCE_DELAY)) - { - stmDebounceState = STM_DEBOUNCE_DEBOUNCE_1; - } - else if (millis_temp < debounce_delay) - { // Overflow protection for uptime of several weeks or more. - debounce_delay = 0; - } - break; - - case STM_DEBOUNCE_DEBOUNCE_0: - stmDebounceState = STM_DEBOUNCE_IDLE_0; - digitalWrite(LED_BUILTIN, LOW); // DEBUG - break; - - case STM_DEBOUNCE_DEBOUNCE_1: - stmDebounceState = STM_DEBOUNCE_IDLE_1; - digitalWrite(LED_BUILTIN, HIGH); // DEBUG - break; - - default: - break; - } - -#ifdef SENSOR_TOUCH_SENSOR1 - input_touch_sensor1 = digitalRead(PIN_TOUCH_SENSOR1); -#else - input_touch_sensor1 = LOW; -#endif - -#ifdef SENSOR_TOUCH_SENSOR2 - input_touch_sensor2 = digitalRead(PIN_TOUCH_SENSOR2); -#else - input_touch_sensor2 = LOW; -#endif - - // Main state machine - //------------------- - switch (stmState) - { - //Init is not used, here for future use and coding best practice - case STM_INIT: - stmState = STM_IDLE; - break; - - case STM_IDLE: - if ((stmDebounceState == STM_DEBOUNCE_DEBOUNCE_1) || - (input_touch_sensor1 == HIGH) || - (input_touch_sensor2 == HIGH) || - (accel_detect == true)) - { - stmState = STM_PLAY; - } - break; - - case STM_PLAY: - WritePlaySong(cPlaylistIndif_TA[song_playing_current_u8].song_index_u8 + 1U); // Play the current song - song_cycles_cnt_u8++; // Increment cycles counter - - if (song_cycles_cnt_u8 >= cPlaylistIndif_TA[song_playing_current_u8].cycles_number_u8) - { // Check cycles counter overflow - song_cycles_cnt_u8 = 0; // Reset the cycles counter - song_playing_current_u8++; // Increment the playlist counter - } - - if (song_playing_current_u8 >= PLAYLIST_LENGTH) - { // Check playlist song counter overflow - song_playing_current_u8 = 0; - } - - play_blank_delay = millis(); - stmState = STM_BLANK; - break; - - case STM_BLANK: - millis_temp = millis(); - if ((millis_temp >= play_blank_delay) && ((millis_temp - play_blank_delay) > PLAY_BLANK_DELAY)) - { -#ifdef MP3_RESET - stmState = STM_MP3_RESET; - mp3_reset_delay = millis(); - digitalWrite(PIN_GROUND_SWITCH, LOW); -#else - stmState = STM_IDLE; -#endif - } - else if (millis_temp < play_blank_delay) - { // Overflow protection for uptime of several weeks or more. - play_blank_delay = 0; - } - break; - - case STM_MP3_RESET: - millis_temp = millis(); - if ((millis_temp >= mp3_reset_delay) && ((millis_temp - mp3_reset_delay) > DELAY_MP3_RESET)) - { - stmState = STM_IDLE; - digitalWrite(PIN_GROUND_SWITCH, HIGH); - } - else if (millis_temp < mp3_reset_delay) - { // Overflow protection for uptime of several weeks or more. - mp3_reset_delay = 0; - } - break; - - default: - stmState = STM_INIT; - break; - } - -#ifdef DEBUG_UART_ACCELEROMETER - Serial.print("Accelerometer: "); - Serial.print("X = "); Serial.print(AcX); - Serial.print(" | Y = "); Serial.print(AcY); - Serial.print(" | Z = "); Serial.println(AcZ); - - Serial.print("Gyroscope: "); - Serial.print("X = "); Serial.print(GyX); - Serial.print(" | Y = "); Serial.print(GyY); - Serial.print(" | Z = "); Serial.println(GyZ); - - Serial.print("Temperature: "); Serial.print(Tmp); - Serial.println(" "); -#endif -} - -/* - SerialEvent occurs whenever a new data comes in the hardware serial RX. This - routine is run between each time loop() runs, so using delay inside loop can - delay response. Multiple bytes of data may be available. -*/ -void serialEvent() { - while (Serial.available()) { - // get the new byte: - char inChar = (char)Serial.read(); - // add it to the inputString: - inputString += inChar; - // if the incoming character is a newline, set a flag so the main loop can - // do something about it: - if (inChar == '\n') { - stringComplete = true; - } - } -} - -void ReadPlayState (void) -{ - // Send Play State read request - Serial.write(170); // 0xAA - Serial.write(1); // 0x01 - Serial.write(0); // 0x00 - Serial.write(171); // 0xAB -} - -void WritePlay (void) -{ - // Send Play request - Serial.write(170); // 0xAA - Serial.write(2); // 0x02 - Serial.write(0); // 0x00 - Serial.write(172); // 0xAC -} - -void WritePlaySong (uint16_t index) -{ - uint8_t buffer_u8A[5]; - buffer_u8A[0] = 0xAA; - buffer_u8A[1] = 0x07; - buffer_u8A[2] = 0x02; - buffer_u8A[3] = (uint8_t)((index >> 8U) & (uint16_t)0x00FF); - buffer_u8A[4] = (uint8_t)(index & (uint16_t)0x00FF); - uint8_t crc_u8 = CrcCalculate(buffer_u8A, 5); - // Send Play request - Serial.write((int)buffer_u8A[0]); // 0xAA - Serial.write((int)buffer_u8A[1]); // 0x07 - Serial.write((int)buffer_u8A[2]); // 0x02 - Serial.write((int)buffer_u8A[3]); // Song number high byte - Serial.write((int)buffer_u8A[4]); // Song number low byte - Serial.write((int)crc_u8); // CRC -} - -uint8_t CrcCalculate (uint8_t *buff, uint8_t size) -{ - uint16_t ret_u16 = 0; - uint8_t cnt_u8 = 0; - - for (cnt_u8 = 0; cnt_u8 < size; cnt_u8++) - { - ret_u16 += *(buff + cnt_u8); - } - - return ((uint8_t)(ret_u16 & (uint16_t)0x00FF)); +/* + Boitarire software + + Plays a sound through an external MP3 module + when triggered by external sensor : + - inclination switch + - accelerometer module + - touch sensors + Configuration is selected through compilation switches. + Uses an editable playlist allowing any song order, + up to 255 different songs in the playlist, individual + repetition number for eah song. + + created 25 nov 2021 + by Florian Savard + + This example code is in the public domain. + + https://code.electrolab.fr/Flax/boitarire +*/ + +#include + +// Defines - Macros - Constants + +#define SENSOR_INCLINATION +//#define SENSOR_ACCELEROMETER +//#define SENSOR_TOUCH_SENSOR1 +//#define SENSOR_TOUCH_SENSOR2 + + +// Other constants +//Hardwaere constatnts : do not modify >_< ! +#define PIN_SENSOR_POSITION 9 // Position sensor input +#define PIN_TOUCH_SENSOR1 8 // Touch sensor 1 input +#define PIN_TOUCH_SENSOR2 5 // Touch sensor 2 input +#define PIN_GROUND_SWITCH 7 // MP3 module ground switch command output + +//Calibration constants : do adjust :-) +//#define MP3_RESET +// +//#define DEBUG_UART_ACCELEROMETER // Warning : conflict with MP3 player +#define PLAY_BLANK_DELAY 1000 // Blanking when playing a sound (ms): Must be longer than the played sample (recommended : sample duration + 100ms) +#define DELAY_MP3_RESET 100 // Time of ground cut of MP3 module for re-init (ms) : Adjust only if hardware proiblems with new revisions of the mp3 module +#define DEBOUNCE_DELAY 200 // Position sensor input debounce (ms) +#define ACCEL_THRES_GYX 9999 // Detection threshold for X axis acceleration +#define ACCEL_THRES_GYY 9999 // Detection threshold for Y axis acceleration +#define ACCEL_THRES_GYZ 25000 // Detection threshold for Z axis acceleration +#define PLAYLIST_LENGTH 4 // Number of songs in the playlist + +// Typedefs +// Main state machine : start actions +typedef enum +{ + //Initialisation + STM_INIT, + //Wainting for input (capteur) + STM_IDLE, + //When input, play sample + STM_PLAY, + //Waiting after playing sample + STM_BLANK, + //Optional hardware reset of the MP3 module (See calibration constants for activation) + STM_MP3_RESET, +} tStateMachine; + +typedef enum +{ + STM_DEBOUNCE_IDLE_0, + STM_DEBOUNCE_IDLE_1, + STM_DEBOUNCE_DETECT_0, + STM_DEBOUNCE_DETECT_1, + STM_DEBOUNCE_DEBOUNCE_0, + STM_DEBOUNCE_DEBOUNCE_1, +} tStateMachineDebounce; + +typedef struct +{ + uint8_t song_index_u8; // Index of the song in the device /!\ counts from 0 + uint8_t cycles_number_u8; // Number of times the song must be played before switching to the next +} tSongItem; + +// Constant variables + +/* Indifference table for songs cycles + * Contains the indexes of the songs to be played and the number of times each one must be played. + * Contains couples {index of the song in the MP3 device memory, number of times the song must be played}, + * Playlist cycles from first element to last and loops. + * Don't forget to update PLAYLIST_LENGTH define. + */ +const tSongItem cPlaylistIndif_TA[PLAYLIST_LENGTH] = +{ + {0, 2}, + {2, 3}, + {1, 1}, + {3, 2}, +}; + +// Local variables +String inputString = ""; // a String to hold incoming data +bool stringComplete = false; // whether the string is complete + +unsigned long debounce_delay; +int input_position_sensor, input_touch_sensor1, input_touch_sensor2; +unsigned long play_blank_delay, mp3_reset_delay; +unsigned long millis_temp; + +const int MPU=0x68; +int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; +bool accel_detect; + +uint8_t song_cycles_cnt_u8; // Counts the number of times the current song has been played +uint8_t song_playing_current_u8; // Holds the index of the playlist song actually being played + +// State machines states +tStateMachine stmState; +tStateMachineDebounce stmDebounceState; + +// Local function prototypes +void ReadPlayState (void); +void WritePlay (void); +void WritePlaySong (uint16_t index); +uint8_t CrcCalculate (uint8_t *buff, uint8_t size); + +// Setup function +void setup() { + // Initialize serial: + Serial.begin(9600); + // Reserve 200 bytes for the inputString: + inputString.reserve(200); + + // Position sensor input pin - See hardware constants for pin definition - Input pull-up + pinMode(PIN_SENSOR_POSITION, INPUT_PULLUP); + + // Touch sensor 1 input pin - See hardware constants for pin definition - Input no pull + pinMode(PIN_TOUCH_SENSOR1, INPUT); + + // Touch sensor 2 input pin - See hardware constants for pin definition - Input no pull + pinMode(PIN_TOUCH_SENSOR2, INPUT); + + // LED output for visualisation + pinMode(LED_BUILTIN, OUTPUT); + + // MP3 module ground switch command - See hardware constants for pin definition - Output push-pull + pinMode(PIN_GROUND_SWITCH, OUTPUT); + + //Initialise variables, do not define constants value here + play_blank_delay = 0; + mp3_reset_delay = 0; + stmState = STM_INIT; + stmDebounceState = STM_DEBOUNCE_IDLE_0; + debounce_delay = 0; + input_position_sensor = LOW; + input_touch_sensor1 = LOW; + input_touch_sensor2 = LOW; + song_cycles_cnt_u8 = 0; + song_playing_current_u8 = 0; + +#ifdef SENSOR_ACCELEROMETER + // Accelerometer setup + Wire.begin(); + Wire.beginTransmission(MPU); + Wire.write(0x6B); + Wire.write(0); + Wire.endTransmission(true); + + // Set FIFO enable register + /* Wire.beginTransmission(MPU); + Wire.write(0x23); + Wire.write(0x78); + Wire.endTransmission(true);*/ + + // Set filters + Wire.beginTransmission(MPU); + Wire.write(0x1A); + Wire.write(0x06); + Wire.endTransmission(true); +#endif + accel_detect = false; + + // Connect ground for MP3 module + digitalWrite(PIN_GROUND_SWITCH, HIGH); +} + +// Main loop +void loop() { + // print the string when a newline arrives: for debug purposes only + if (stringComplete) { + Serial.println(inputString); + + switch (inputString[0]) + { + case 0x30: + // Play first song in the device + WritePlaySong(1); + break; + case 0x31: + // Play second song in the device + WritePlaySong(2); + break; + default: + break; + } + + // clear the string: + inputString = ""; + stringComplete = false; + } + +#ifdef SENSOR_ACCELEROMETER + // Accelerometer communication + Wire.beginTransmission(MPU); + Wire.write(0x3B); + Wire.endTransmission(false); + Wire.requestFrom(MPU,14,true); + AcX=Wire.read()<<8|Wire.read(); + AcY=Wire.read()<<8|Wire.read(); + AcZ=Wire.read()<<8|Wire.read(); + Tmp=Wire.read()<<8|Wire.read(); + GyX=Wire.read()<<8|Wire.read(); + GyY=Wire.read()<<8|Wire.read(); + GyZ=Wire.read()<<8|Wire.read(); + + if ((GyX > ACCEL_THRES_GYX) || + (GyY > ACCEL_THRES_GYY) || + (GyZ > ACCEL_THRES_GYZ) || + (GyX < ((int16_t)(-1) * ACCEL_THRES_GYX)) || + (GyY < ((int16_t)(-1) * ACCEL_THRES_GYY)) || + (GyZ < ((int16_t)(-1) * ACCEL_THRES_GYZ))) + { + accel_detect = true; + } + else + { + accel_detect = false; + } +#else + accel_detect = false; +#endif + +#ifdef SENSOR_INCLINATION + // Read instantaneous value of position sensor + input_position_sensor = digitalRead(PIN_SENSOR_POSITION); +#else + input_position_sensor = LOW; +#endif + + // Inclination debounce state machine + //----------------------------------- + switch (stmDebounceState) + { + case STM_DEBOUNCE_IDLE_0: + if (input_position_sensor == HIGH) + { + stmDebounceState = STM_DEBOUNCE_DETECT_1; + debounce_delay = millis(); + } + break; + + case STM_DEBOUNCE_IDLE_1: + if (input_position_sensor == LOW) + { + stmDebounceState = STM_DEBOUNCE_DETECT_0; + debounce_delay = millis(); + } + break; + + case STM_DEBOUNCE_DETECT_0: + millis_temp = millis(); + if (input_position_sensor == HIGH) + { + stmDebounceState = STM_DEBOUNCE_IDLE_1; + } + else if ((millis_temp >= debounce_delay) && ((millis_temp - debounce_delay) > DEBOUNCE_DELAY)) + { + stmDebounceState = STM_DEBOUNCE_DEBOUNCE_0; + } + else if (millis_temp < debounce_delay) + { // Overflow protection for uptime of several weeks or more. + debounce_delay = 0; + } + break; + + case STM_DEBOUNCE_DETECT_1: + millis_temp = millis(); + if (input_position_sensor == LOW) + { + stmDebounceState = STM_DEBOUNCE_IDLE_0; + } + else if ((millis_temp >= debounce_delay) && ((millis_temp - debounce_delay) > DEBOUNCE_DELAY)) + { + stmDebounceState = STM_DEBOUNCE_DEBOUNCE_1; + } + else if (millis_temp < debounce_delay) + { // Overflow protection for uptime of several weeks or more. + debounce_delay = 0; + } + break; + + case STM_DEBOUNCE_DEBOUNCE_0: + stmDebounceState = STM_DEBOUNCE_IDLE_0; + digitalWrite(LED_BUILTIN, LOW); // DEBUG + break; + + case STM_DEBOUNCE_DEBOUNCE_1: + stmDebounceState = STM_DEBOUNCE_IDLE_1; + digitalWrite(LED_BUILTIN, HIGH); // DEBUG + break; + + default: + break; + } + +#ifdef SENSOR_TOUCH_SENSOR1 + input_touch_sensor1 = digitalRead(PIN_TOUCH_SENSOR1); +#else + input_touch_sensor1 = LOW; +#endif + +#ifdef SENSOR_TOUCH_SENSOR2 + input_touch_sensor2 = digitalRead(PIN_TOUCH_SENSOR2); +#else + input_touch_sensor2 = LOW; +#endif + + // Main state machine + //------------------- + switch (stmState) + { + //Init is not used, here for future use and coding best practice + case STM_INIT: + stmState = STM_IDLE; + break; + + case STM_IDLE: + if ((stmDebounceState == STM_DEBOUNCE_DEBOUNCE_1) || + (input_touch_sensor1 == HIGH) || + (input_touch_sensor2 == HIGH) || + (accel_detect == true)) + { + stmState = STM_PLAY; + } + break; + + case STM_PLAY: + WritePlaySong(cPlaylistIndif_TA[song_playing_current_u8].song_index_u8 + 1U); // Play the current song + song_cycles_cnt_u8++; // Increment cycles counter + + if (song_cycles_cnt_u8 >= cPlaylistIndif_TA[song_playing_current_u8].cycles_number_u8) + { // Check cycles counter overflow + song_cycles_cnt_u8 = 0; // Reset the cycles counter + song_playing_current_u8++; // Increment the playlist counter + } + + if (song_playing_current_u8 >= PLAYLIST_LENGTH) + { // Check playlist song counter overflow + song_playing_current_u8 = 0; + } + + play_blank_delay = millis(); + stmState = STM_BLANK; + break; + + case STM_BLANK: + millis_temp = millis(); + if ((millis_temp >= play_blank_delay) && ((millis_temp - play_blank_delay) > PLAY_BLANK_DELAY)) + { +#ifdef MP3_RESET + stmState = STM_MP3_RESET; + mp3_reset_delay = millis(); + digitalWrite(PIN_GROUND_SWITCH, LOW); +#else + stmState = STM_IDLE; +#endif + } + else if (millis_temp < play_blank_delay) + { // Overflow protection for uptime of several weeks or more. + play_blank_delay = 0; + } + break; + + case STM_MP3_RESET: + millis_temp = millis(); + if ((millis_temp >= mp3_reset_delay) && ((millis_temp - mp3_reset_delay) > DELAY_MP3_RESET)) + { + stmState = STM_IDLE; + digitalWrite(PIN_GROUND_SWITCH, HIGH); + } + else if (millis_temp < mp3_reset_delay) + { // Overflow protection for uptime of several weeks or more. + mp3_reset_delay = 0; + } + break; + + default: + stmState = STM_INIT; + break; + } + +#ifdef DEBUG_UART_ACCELEROMETER + Serial.print("Accelerometer: "); + Serial.print("X = "); Serial.print(AcX); + Serial.print(" | Y = "); Serial.print(AcY); + Serial.print(" | Z = "); Serial.println(AcZ); + + Serial.print("Gyroscope: "); + Serial.print("X = "); Serial.print(GyX); + Serial.print(" | Y = "); Serial.print(GyY); + Serial.print(" | Z = "); Serial.println(GyZ); + + Serial.print("Temperature: "); Serial.print(Tmp); + Serial.println(" "); +#endif +} + +/* + SerialEvent occurs whenever a new data comes in the hardware serial RX. This + routine is run between each time loop() runs, so using delay inside loop can + delay response. Multiple bytes of data may be available. +*/ +void serialEvent() { + while (Serial.available()) { + // get the new byte: + char inChar = (char)Serial.read(); + // add it to the inputString: + inputString += inChar; + // if the incoming character is a newline, set a flag so the main loop can + // do something about it: + if (inChar == '\n') { + stringComplete = true; + } + } +} + +void ReadPlayState (void) +{ + // Send Play State read request + Serial.write(170); // 0xAA + Serial.write(1); // 0x01 + Serial.write(0); // 0x00 + Serial.write(171); // 0xAB +} + +void WritePlay (void) +{ + // Send Play request + Serial.write(170); // 0xAA + Serial.write(2); // 0x02 + Serial.write(0); // 0x00 + Serial.write(172); // 0xAC +} + +void WritePlaySong (uint16_t index) +{ + uint8_t buffer_u8A[5]; + buffer_u8A[0] = 0xAA; + buffer_u8A[1] = 0x07; + buffer_u8A[2] = 0x02; + buffer_u8A[3] = (uint8_t)((index >> 8U) & (uint16_t)0x00FF); + buffer_u8A[4] = (uint8_t)(index & (uint16_t)0x00FF); + uint8_t crc_u8 = CrcCalculate(buffer_u8A, 5); + // Send Play request + Serial.write((int)buffer_u8A[0]); // 0xAA + Serial.write((int)buffer_u8A[1]); // 0x07 + Serial.write((int)buffer_u8A[2]); // 0x02 + Serial.write((int)buffer_u8A[3]); // Song number high byte + Serial.write((int)buffer_u8A[4]); // Song number low byte + Serial.write((int)crc_u8); // CRC +} + +uint8_t CrcCalculate (uint8_t *buff, uint8_t size) +{ + uint16_t ret_u16 = 0; + uint8_t cnt_u8 = 0; + + for (cnt_u8 = 0; cnt_u8 < size; cnt_u8++) + { + ret_u16 += *(buff + cnt_u8); + } + + return ((uint8_t)(ret_u16 & (uint16_t)0x00FF)); }