diff --git a/ESP8266_Transmitter/ESP8266_Transmitter.ino b/ESP8266_Transmitter/ESP8266_Transmitter.ino index a3ac0ab844625ac825ccf40339ac5b127c288530..bddeadc164194b3b9277b39b3126739108ac4394 100644 --- a/ESP8266_Transmitter/ESP8266_Transmitter.ino +++ b/ESP8266_Transmitter/ESP8266_Transmitter.ino @@ -209,7 +209,7 @@ boolean readPMSdata(Stream *s) { memcpy((void *)&data, (void *)buffer_u16, 30); if (sum != data.checksum) { - Serial.println("Checksum failure"); + Serial.print("\n Checksum failure... "); Serial.print("Expected: "); Serial.print(sum); Serial.print(", Got: "); Serial.print(data.checksum); return false; @@ -241,12 +241,12 @@ boolean clearToSend(int listenDuration) { // Listen of listenDuration seconds // If we see a response to our txHello packet, and txHello.okToTransmit is True, we can send our packet -boolean listenTxHelloAccept(int listenDuration) { +boolean listenTxHelloAccept(int listenDuration, int messageID) { int time_now = now() + listenDuration; // Listen until timeout expires + Serial.println("[+] Transmit - \"Hello\" - Listening for ack & clear to send"); while (time_now >= now()) { - Serial.println("Listening for auth"); int packetSize = LoRa.parsePacket(); if (packetSize) { @@ -280,16 +280,24 @@ boolean listenTxHelloAccept(int listenDuration) { StaticJsonDocument<200> doc; deserializeJson(doc, incoming); - const bool okToCopy = doc["okToTransmit"]; + const bool okToTransmit = doc["okTransmit"]; const String authIsForUid = doc["uid"]; + const int authIsForMessageID = doc["messageID"]; + const String gatewayUid = doc["gatewayUid"]; - // Verify txHello.okToTransmit is True & UID Match - return (okToCopy && authIsForUid == getSensorUID()); + // Verify txHello.okToTransmit is True & UID Match & Message IDs Match + if (authIsForUid == getSensorUID()) { Serial.println("[+] Transmit - \"Hello\" - Sensor UID Match!"); } else { Serial.println("[-] Transmit - \"Hello\" - Sensor UID Mis-Match! " + String(authIsForUid) + " vs " + String(getSensorUID())); } + if (authIsForMessageID == messageID) { Serial.println("[+] Transmit - \"Hello\" - Message ID Match!"); } else { Serial.println("[-] Transmit - \"Hello\" - MessageID Mis-Match!"); } + + return (okToTransmit + && authIsForUid == getSensorUID() + && authIsForMessageID == messageID); } - delay(5); + delay(3); } + Serial.println("[-] Transmit - \"Hello\" - Timeout while waiting for Clear to Send\n\n"); return false; // We didn't hear anything, conside this as meaning "Can't Send" } @@ -304,38 +312,103 @@ boolean transmitData(DynamicJsonDocument payload) { // Listen for other communication // Rx - Listen for other messages, if no messages heard then continue -// if (!clearToSend(0.5)) { -// Serial.println("[-] Airways busy, could not send"); -// delay(random(500, 1250)); // Introduce random delay to avoid another collision -// return false; -// } - + if (!clearToSend(0.5)) { + Serial.println("[-] Airways busy, could not send"); + delay(random(500, 1250)); // Introduce random delay to avoid another collision + + // TODO Refactor + while (!clearToSend(0.5)) { + Serial.println("[-] Airways busy, could not send"); + delay(random(500, 1250)); // Introduce random delay to avoid another collision + } + //return false; + } + Serial.println("[+] Transmit - \"Hello\""); // Send short "clear to send?" packet // Tx - "I've got data to send!" + UID // RX - Continue upon recieving "OK" + UID + TX_Auth_ID DynamicJsonDocument txHello(2048); txHello["uid"] = sensorID; txHello["reservationTime"] = reservationTime; // How long do we require reservation of radio? + txHello["messageID"] = msgCount; sendJsonPayloadWithLoRa(txHello); - if (!listenTxHelloAccept(reservationTime * 1.1)) { // Else we have clear to send - return false; // Can't transmit just now - - } else { - Serial.println("OK To Transmit"); + if (!listenTxHelloAccept(reservationTime * 1.5, msgCount)) { // Can't transmit just now + Serial.println("[-] Transmit - \"Hello\" - Can Not Transmit At This Time\n"); + return false; } + Serial.println("[+] Recieved - Clear to Transmit Payload"); // Else we have clear to send // Transmit Payload // Tx - Send payload + UID + TX_Auth_ID // Rx - Listen for Ack/Nack - Serial.println("Sending Payload Now"); + Serial.println("[+] Transmit - Payload"); sendJsonPayloadWithLoRa(payload); // TODO Await Response Ack/Nak + int ackTimeout = 2; // Seconds + int time_now = now() + ackTimeout; + // Listen until timeout expires + Serial.println("[.] Transmit - Payload - Listening for Ack"); + while (time_now >= now()) { + int packetSize = LoRa.parsePacket(); + + if (packetSize) { + String incoming = ""; + char temp; + + while (LoRa.available()) { + // TODO - Tidy this up, ensure we only read in valid JSON + temp = (char)LoRa.read(); + + // Opening { + if (incoming.length() == 0 && temp == '{') { + incoming = "{"; + + // Closing } + } else if (temp == '}') { + incoming.concat("}"); + break; + + // Anything else that's valid + } else if (incoming.length() > 0) { + incoming.concat(temp); + } + } + + // DEBUG +// Serial.print("\nin listedForAck() Recieved: \n"); +// Serial.println(incoming); + + StaticJsonDocument<200> doc; + deserializeJson(doc, incoming); + + const bool ackStatus = doc["ackStatus"]; + const String authIsForUid = doc["uid"]; + const String gatewayUid = doc["gatewayUid"]; + + // Verify txHello.okToTransmit is True & UID Match + if (authIsForUid == getSensorUID()) { + Serial.println("[+] Transmit - Payload - Ack Recieved: " + String(ackStatus) + "\n"); + + if (ackStatus) { return true; } // It all worked :) + + // TODO Retransmit, recover, etc + return false; + } + + // Else UID Mis-Match so we wait for next message + } + + delay(5); + } + + // TODO After Timeout we need to deal with! + Serial.println("[-] Transmit - Payload - Ack Timeout Reached - Assuming Message Was Not Delivered"); // TODO Listen for ack/nak @@ -359,7 +432,7 @@ void setup() { delay(1000); Serial.begin(115200); // Console Debug - Serial.println("[+] Transmitter Node"); + Serial.println("\n\n[+] Transmitter Node"); sensorID = getSensorUID(); @@ -385,7 +458,7 @@ void loop() { pollEventCount++; Serial.println(); - Serial.print(String(pollEventCount) + ") Std Units: "); + Serial.print(String(pollEventCount) + ") "); Serial.print("PM 1.0: "); Serial.print(data.pm10_standard); Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard); Serial.print("\t\tPM 10: "); Serial.print(data.pm100_standard); @@ -408,13 +481,13 @@ void loop() { avgHumidity = humidity / sendAfterPolls; // TODO Transmit Sensor Data - Serial.println("---------------------------------------"); + Serial.println(""); Serial.print("Avg ppm10: "); Serial.print(avgPpm10); Serial.print("\t\tAvg ppm25: "); Serial.print(avgPpm25); Serial.print("\t\tAvg ppm100: "); Serial.print(avgPpm100); Serial.print("\t\tAvg Temp: "); Serial.print(avgTemperature); - Serial.print("\t\tAvg Humidity: "); Serial.println(avgHumidity); - Serial.print("Chip ID: "); Serial.println(sensorID); + Serial.print("\t\tAvg Humidity: "); Serial.print(avgHumidity); + Serial.print("\t\tChip ID: "); Serial.println(sensorID); Serial.println(""); // LORA SEND @@ -443,40 +516,22 @@ void loop() { Serial.println("Packet Sent\n"); } else { - while (!transmitData(doc)){ - Serial.println("[-] Failed to send packet, retrying\n"); - delay(reservationTime + random(250, 1250)); // Introduce random delay to avoid another collision + int maxRetries = 10; // TODO Move to Config + int numRetries = 1; + + while (!transmitData(doc) && numRetries < maxRetries){ + numRetries++; + Serial.println("[-] Failed to send packet, retrying. Attempt " + String(numRetries) + " of " + String(maxRetries) + "\n"); + delay(reservationTime + random(1250, 5250)); // Introduce random delay to avoid another collision } - } - Serial.println("---------------------------------------"); - - // TODO Wait for reply -// int i = 3000; -// int j = 0; -// String incoming = ""; -// -// while (j < i) { -// -// int packetSize = LoRa.parsePacket(); -// if (packetSize) { -// while (LoRa.available()) { -// incoming.concat((char)LoRa.read()); -// } -// -// // TODO Parse response to JSON, check if matches device & message ID -// Serial.print("Inbound!: \n"); -// Serial.print(incoming); -// break; -// } -// -// j+=10; -// delay(10); -// -// // TODO If no response then consider not delivered -// } -// Serial.print("\n"); + if (numRetries >= maxRetries) { + Serial.println("[-] Failed to send packet, max retries reached. Aborting"); + // TODO Don't Clear Counters, record more values then try to retransmit + } + } + // Reset Loop Values ppm10 = 0; ppm25 = 0;