From 5509160d03735ed98278f8a2894c0e4dbf74b486 Mon Sep 17 00:00:00 2001 From: Joe Tretter Date: Tue, 12 Dec 2023 18:35:43 -0600 Subject: [PATCH] Change implementation to - Use a switch instead of a button - Replace interrupt with loop read because of crashes (retro analysis: crashes might be due to wrong cabling) --- src/main.cpp | 258 +++++++++++++++++++++++++++------------------------ 1 file changed, 135 insertions(+), 123 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 954bcb7..7e44e1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include #include #include - + // GPIOs #define GPIO_EMERGENCY_LED_SMALL 5 #define GPIO_EMERGENCY_LED_RED 13 @@ -12,127 +12,127 @@ #define GPIO_SYNC_LED 19 #define GPIO_REQUESTED_STATE_LED 2 -#define GPIO_EMERGENCY_BUTTON 16 +#define GPIO_EMERGENCY_SWITCH 16 // Software Parameters #define LOOP_DELAY 1 #define PING_TIMEOUT_NUM_LOOPS 3 -#define EMERGENCY_BUTTON_SCAN_RATE_SECONDS 1 -String macList[2] = {"24:6F:28:B1:EE:74", "24:6F:28:B2:40:8C"}; -String macLocal,macRemote; +String macList[2] = {"24:6F:28:B2:40:8C", "24:6F:28:B1:EE:74"}; +String macLocal, macRemote; uint8_t macRemoteIntArr[6]; -esp_now_peer_info_t peerInfo={}; +esp_now_peer_info_t peerInfo = {}; int64_t lastPingUptimeInSeconds; -volatile int64_t lastButtonPushUptimeInSeconds; volatile boolean isReceiverEmergencyLedOn; volatile boolean isSenderEmergency; TaskHandle_t BigLEDTask; -typedef struct struct_info { +typedef struct struct_info +{ boolean isEmergency; boolean isPing; String macOfSender; } struct_info; struct_info myData; -int64_t getUptimeInSeconds(){ - return esp_timer_get_time()/1000000; +int64_t getUptimeInSeconds() +{ + return esp_timer_get_time() / 1000000; } // Callback when data is sent -void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { +void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) +{ Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } // Callback when data is received -void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) { +void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) +{ struct_info myData; memcpy(&myData, incomingData, sizeof(incomingData)); Serial.print("Bytes received: "); Serial.println(len); - Serial.printf("d:_%d_|",myData.isPing); + Serial.printf("d:_%d_|", myData.isPing); - if (myData.isPing) { - lastPingUptimeInSeconds=getUptimeInSeconds(); - } - - if(myData.isEmergency) { - digitalWrite(GPIO_EMERGENCY_LED_SMALL,HIGH); - isReceiverEmergencyLedOn=true; - } else { - digitalWrite(GPIO_EMERGENCY_LED_SMALL,LOW); - isReceiverEmergencyLedOn=false; + if (myData.isPing) + { + lastPingUptimeInSeconds = getUptimeInSeconds(); } -} -void OnButtonPushed(){ - Serial.println("BUTTON PUSH CALLBACK."); - if((getUptimeInSeconds()-lastButtonPushUptimeInSeconds)>EMERGENCY_BUTTON_SCAN_RATE_SECONDS){ - isSenderEmergency=!isSenderEmergency; - digitalWrite(GPIO_REQUESTED_STATE_LED,isSenderEmergency?HIGH:LOW); - lastButtonPushUptimeInSeconds=getUptimeInSeconds(); - Serial.println("BUTTON PUSH EXEC."); + if (myData.isEmergency) + { + digitalWrite(GPIO_EMERGENCY_LED_SMALL, HIGH); + isReceiverEmergencyLedOn = true; + } + else + { + digitalWrite(GPIO_EMERGENCY_LED_SMALL, LOW); + isReceiverEmergencyLedOn = false; } } // Convert single hex char to integer int char2int(char input) { - if(input >= '0' && input <= '9') + if (input >= '0' && input <= '9') return input - '0'; - if(input >= 'A' && input <= 'F') + if (input >= 'A' && input <= 'F') return input - 'A' + 10; - if(input >= 'a' && input <= 'f') + if (input >= 'a' && input <= 'f') return input - 'a' + 10; throw std::invalid_argument("Invalid input string"); } // This function assumes src to be a zero terminated sanitized string with // an even number of [0-9a-f] characters, and target to be sufficiently large -void hex2bin(const char* src, uint8_t* target) +void hex2bin(const char *src, uint8_t *target) { - while(*src && src[1]) + while (*src && src[1]) { - *(target++) = char2int(*src)*16 + char2int(src[1]); + *(target++) = char2int(*src) * 16 + char2int(src[1]); src += 2; } } // the big LED should flash when we are in emergency state. -void BigLEDTaskCode(void * parameter){ +void BigLEDTaskCode(void *parameter) +{ // Test the channels of the big LED - digitalWrite(GPIO_EMERGENCY_LED_GREEN,LOW); - digitalWrite(GPIO_EMERGENCY_LED_BLUE,LOW); - digitalWrite(GPIO_EMERGENCY_LED_RED,HIGH); + digitalWrite(GPIO_EMERGENCY_LED_GREEN, LOW); + digitalWrite(GPIO_EMERGENCY_LED_BLUE, LOW); + digitalWrite(GPIO_EMERGENCY_LED_RED, HIGH); sleep(1); - digitalWrite(GPIO_EMERGENCY_LED_RED,LOW); - digitalWrite(GPIO_EMERGENCY_LED_GREEN,HIGH); + digitalWrite(GPIO_EMERGENCY_LED_RED, LOW); + digitalWrite(GPIO_EMERGENCY_LED_GREEN, HIGH); sleep(1); - digitalWrite(GPIO_EMERGENCY_LED_GREEN,LOW); - digitalWrite(GPIO_EMERGENCY_LED_BLUE,HIGH); + digitalWrite(GPIO_EMERGENCY_LED_GREEN, LOW); + digitalWrite(GPIO_EMERGENCY_LED_BLUE, HIGH); sleep(1); - digitalWrite(GPIO_EMERGENCY_LED_BLUE,LOW); - + digitalWrite(GPIO_EMERGENCY_LED_BLUE, LOW); + // Blink in emergecy mode. - for(;;){ - if (isReceiverEmergencyLedOn){ - digitalWrite(GPIO_EMERGENCY_LED_BLUE,HIGH); + for (;;) + { + if (isReceiverEmergencyLedOn) + { + digitalWrite(GPIO_EMERGENCY_LED_BLUE, HIGH); delay(100); - digitalWrite(GPIO_EMERGENCY_LED_BLUE,LOW); + digitalWrite(GPIO_EMERGENCY_LED_BLUE, LOW); delay(250); - digitalWrite(GPIO_EMERGENCY_LED_RED,HIGH); + digitalWrite(GPIO_EMERGENCY_LED_RED, HIGH); delay(100); - digitalWrite(GPIO_EMERGENCY_LED_RED,LOW); + digitalWrite(GPIO_EMERGENCY_LED_RED, LOW); delay(500); } } } -void setPowerLEDBrightness(int brightnessValue){ +void setPowerLEDBrightness(int brightnessValue) +{ // setting PWM properties const int freq = 5000; const int ledChannel = 0; @@ -143,43 +143,41 @@ void setPowerLEDBrightness(int brightnessValue){ ledcWrite(ledChannel, brightnessValue); } -void setup(){ +void setup() +{ // GPIO Setup - pinMode(GPIO_POWER_LED,OUTPUT); - pinMode(GPIO_EMERGENCY_LED_RED,OUTPUT); - pinMode(GPIO_EMERGENCY_LED_GREEN,OUTPUT); - pinMode(GPIO_EMERGENCY_LED_BLUE,OUTPUT); + pinMode(GPIO_POWER_LED, OUTPUT); + pinMode(GPIO_EMERGENCY_LED_RED, OUTPUT); + pinMode(GPIO_EMERGENCY_LED_GREEN, OUTPUT); + pinMode(GPIO_EMERGENCY_LED_BLUE, OUTPUT); pinMode(GPIO_EMERGENCY_LED_SMALL, OUTPUT); pinMode(GPIO_REQUESTED_STATE_LED, OUTPUT); - pinMode(GPIO_SYNC_LED,OUTPUT); - pinMode(GPIO_EMERGENCY_BUTTON,INPUT_PULLDOWN); + pinMode(GPIO_SYNC_LED, OUTPUT); + pinMode(GPIO_EMERGENCY_SWITCH, INPUT_PULLDOWN); // Initialize state - digitalWrite(GPIO_POWER_LED,HIGH); //Power LED ON - digitalWrite(GPIO_REQUESTED_STATE_LED,LOW); - digitalWrite(GPIO_EMERGENCY_LED_SMALL,LOW); - digitalWrite(GPIO_SYNC_LED,LOW); + digitalWrite(GPIO_POWER_LED, HIGH); // Power LED ON + digitalWrite(GPIO_REQUESTED_STATE_LED, LOW); + digitalWrite(GPIO_EMERGENCY_LED_SMALL, LOW); + digitalWrite(GPIO_SYNC_LED, LOW); - myData.isPing=1; - myData.macOfSender=""; - isReceiverEmergencyLedOn=false; - myData.isEmergency=false; - isSenderEmergency=false; - lastButtonPushUptimeInSeconds=getUptimeInSeconds(); + myData.isPing = 1; + myData.macOfSender = ""; + isReceiverEmergencyLedOn = false; + myData.isEmergency = false; + isSenderEmergency = false; - // The button triggers an interrupt, attach callback function - attachInterrupt(GPIO_EMERGENCY_BUTTON, OnButtonPushed, RISING); - - sleep(LOOP_DELAY); // give the serial monitor a moment to connect. + sleep(LOOP_DELAY); // give the serial monitor a moment to connect. Serial.begin(115200); WiFi.mode(WIFI_MODE_STA); - macLocal=WiFi.macAddress(); - macRemote=macList[macList[0]==macLocal?1:0]; - Serial.println("Local [" + macLocal + "] -> Remote: [" + macRemote+"]"); + macLocal = WiFi.macAddress(); + macRemote = macList[macList[0] == macLocal ? 1 : 0]; + Serial.println("Local [" + macLocal + "] -> Remote: [" + macRemote + "]"); // Init ESP-NOW - if (esp_now_init() != ESP_OK) { + if (esp_now_init() != ESP_OK) + { Serial.println("Error initializing ESP-NOW"); return; } @@ -187,73 +185,87 @@ void setup(){ // Once ESPNow is successfully Init, we will register for Send CB to // get the status of Trasnmitted packet esp_now_register_send_cb(OnDataSent); - + // Register peer - String macRemoteNoColon=macRemote; - macRemoteNoColon.replace(":",""); + String macRemoteNoColon = macRemote; + macRemoteNoColon.replace(":", ""); char macRemoteNoColonCharArr[13]; - macRemoteNoColon.toCharArray(macRemoteNoColonCharArr,sizeof(macRemoteNoColonCharArr)); - hex2bin(macRemoteNoColonCharArr,macRemoteIntArr); + macRemoteNoColon.toCharArray(macRemoteNoColonCharArr, sizeof(macRemoteNoColonCharArr)); + hex2bin(macRemoteNoColonCharArr, macRemoteIntArr); memcpy(peerInfo.peer_addr, macRemoteIntArr, 6); - peerInfo.channel = 0; + peerInfo.channel = 0; peerInfo.encrypt = false; peerInfo.ifidx = WIFI_IF_STA; - - // Add peer - if (esp_now_add_peer(&peerInfo) != ESP_OK){ + + // Add peer + if (esp_now_add_peer(&peerInfo) != ESP_OK) + { Serial.println("Failed to add peer"); return; - } - + } + // Register for a callback function that will be called when data is received esp_now_register_recv_cb(OnDataRecv); // The BIG LED blinking is running in it's own task - xTaskCreatePinnedToCore(BigLEDTaskCode,"BigLEDHandler",10000,NULL,0,&BigLEDTask,0); + xTaskCreatePinnedToCore(BigLEDTaskCode, "BigLEDHandler", 10000, NULL, 0, &BigLEDTask, 0); } - -void loop(){ + +void loop() +{ // Send message via ESP-NOW sleep(LOOP_DELAY); - boolean isButtonPushed = (HIGH== digitalRead(GPIO_EMERGENCY_BUTTON)); - Serial.println(isButtonPushed?"PUSHED":"RELEASED"); + Serial.println((HIGH == digitalRead(GPIO_EMERGENCY_SWITCH)) ? "EM-SWITCH ON" : "EM-SWITCH OFF"); - // only one device has a button, the origin will tell the recipient to revert back the status. - if (isSenderEmergency) { - myData.macOfSender=macLocal; + // only the sender device has a switch, when the switch is operated (meaning I receive a high state) I know that I am the sender. + isSenderEmergency = (digitalRead(GPIO_EMERGENCY_SWITCH) == HIGH); + if (isSenderEmergency) + { + myData.macOfSender = macLocal; } - if (myData.macOfSender!=macLocal) { - myData.isEmergency=isReceiverEmergencyLedOn; - } else { - myData.isEmergency=isSenderEmergency; + if (myData.macOfSender != macLocal) + { + Serial.println("I am the receiver"); + myData.isEmergency = isReceiverEmergencyLedOn; + } + else + { + Serial.println("I am the sender"); + myData.isEmergency = isSenderEmergency; } - esp_err_t result = esp_now_send(macRemoteIntArr,(uint8_t *) &myData, sizeof(myData)); - - Serial.println(myData.isEmergency?"EMERGENGY ON":"EMERGENCY OFF"); - Serial.println((isSenderEmergency==1)?"SEN EMERG ON":"SEN EMERG OFF"); - + esp_err_t result = esp_now_send(macRemoteIntArr, (uint8_t *)&myData, sizeof(myData)); + + Serial.println(myData.isEmergency ? "EMERGENGY ON" : "EMERGENCY OFF"); + Serial.println((isSenderEmergency == true) ? "SEN EMERG ON" : "SEN EMERG OFF"); + // Control the SYNC-LED, if we didn't receive a ping for too long, the LED is switched off - if ((getUptimeInSeconds()-lastPingUptimeInSeconds) < (LOOP_DELAY*PING_TIMEOUT_NUM_LOOPS)) { - digitalWrite(GPIO_SYNC_LED,HIGH); - } else { - digitalWrite(GPIO_SYNC_LED,LOW); - } + if ((getUptimeInSeconds() - lastPingUptimeInSeconds) < (LOOP_DELAY * PING_TIMEOUT_NUM_LOOPS)) + { + digitalWrite(GPIO_SYNC_LED, HIGH); + } + else + { + digitalWrite(GPIO_SYNC_LED, LOW); + } // To indicate the device hasn't crashed we vary the brightess of the power LED - setPowerLEDBrightness((getUptimeInSeconds()%5*20)+50); + const int numberOfBrightnessLevels = 5; + const int brightnessDifferencePerLevel = 20; + const int minimumBrightness = 50; + setPowerLEDBrightness((getUptimeInSeconds() % numberOfBrightnessLevels * brightnessDifferencePerLevel) + minimumBrightness); - switch (result) { - case ESP_OK: - Serial.println("[" +macLocal+ "] Sent with success"); - break; - case ESP_ERR_ESPNOW_NOT_FOUND: - Serial.println("[" +macLocal+ "] Peer not Avavilable"); - break; - default: - Serial.printf("[%s] Error sending the data [%X]\n",macLocal,result); + switch (result) + { + case ESP_OK: + Serial.println("[" + macLocal + "] Sent with success"); + break; + case ESP_ERR_ESPNOW_NOT_FOUND: + Serial.println("[" + macLocal + "] Peer not Avavilable"); + break; + default: + Serial.printf("[%s] Error sending the data [%X]\n", macLocal, result); } - } \ No newline at end of file