diff --git a/src/LoRa_APRS_Tracker.cpp b/src/LoRa_APRS_Tracker.cpp index 8d62fe2..5842f60 100644 --- a/src/LoRa_APRS_Tracker.cpp +++ b/src/LoRa_APRS_Tracker.cpp @@ -186,21 +186,16 @@ void loop() { MSG_Utils::processOutputBuffer(); MSG_Utils::clean25SegBuffer(); - if (Config.bluetooth.type == 0 || Config.bluetooth.type == 2) { // always is sended to Phone - BLE_Utils::sendToPhone(packet.text.substring(3)); // does not check for 25seg buffer - } else { - #ifdef HAS_BT_CLASSIC - BLUETOOTH_Utils::sendPacket(packet.text.substring(3)); - #endif - } - if (Config.bluetooth.type == 0 || Config.bluetooth.type == 2) { + BLE_Utils::sendToPhone(packet.text.substring(3)); BLE_Utils::sendToLoRa(); } else { #ifdef HAS_BT_CLASSIC + BLUETOOTH_Utils::sendPacket(packet.text.substring(3)); BLUETOOTH_Utils::sendToLoRa(); #endif } + MSG_Utils::ledNotification(); Utils::checkFlashlight(); STATION_Utils::checkListenedTrackersByTimeAndDelete(); diff --git a/src/ax25_utils.cpp b/src/ax25_utils.cpp index 840f6be..f027129 100644 --- a/src/ax25_utils.cpp +++ b/src/ax25_utils.cpp @@ -4,75 +4,46 @@ namespace AX25_Utils { - AX25Frame decodedFrame; + String decodeAddressAX25(const String& ax25Address, bool& isLastAddress, bool isRelay) { + String address = ""; + for (int i = 0; i < 6; ++i) { + uint8_t currentCharacter = ax25Address.charAt(i); + currentCharacter >>= 1; + if (currentCharacter != ' ') address += (char)currentCharacter; + } + auto ssidChar = (uint8_t)ax25Address.charAt(6); + bool hasBeenDigipited = ssidChar & HAS_BEEN_DIGIPITED_MASK; + isLastAddress = ssidChar & IS_LAST_ADDRESS_POSITION_MASK; + ssidChar >>= 1; - String decodeFrame(const String& frame) { - String packet = ""; - for (int a = 0; a < 6; a ++) { - uint16_t shiftedValue = frame[a] >> 1; - if (shiftedValue == 32) { - a = 10; + int ssid = 0b1111 & ssidChar; + if (ssid) { + address += '-'; + address += ssid; + } + if (isRelay && hasBeenDigipited) address += '*'; + return address; + } + + String decapsulateKISS(const String& frame) { + String ax25Frame = ""; + for (int i = 2; i < frame.length() - 1; ++i) { + char currentChar = frame.charAt(i); + if (currentChar == (char)KissChar::FESC) { + char nextChar = frame.charAt(i + 1); + if (nextChar == (char)KissChar::TFEND) { + ax25Frame += (char)KissChar::FEND; + } else if (nextChar == (char)KissChar::TFESC) { + ax25Frame += (char)KissChar::FESC; + } + i++; } else { - //Serial.print(char(shiftedValue)); - packet += char(shiftedValue); + ax25Frame += currentChar; } } - byte ssid = (frame[6]>>1) & 0x0f; - if (String(ssid) != "0") { - packet += "-"; - packet += String(ssid); - } - return packet; + return ax25Frame; } - bool decodeAX25(const String& frame, int frameSize, AX25Frame* decodedFrame) { - if ((frameSize < 14) || (frame[0] != KissChar::FEND && frame[1] != KissCmd::Data && frame[frameSize - 1] != KissChar::FEND)) { - return false; - } - int payloadFrameStart = 0; - for (int i = 0; i < frameSize; i++) { // where is CONTROL y PID ? - if (frame[i] == 0x03 && frame[i+1] == 0xf0) { - payloadFrameStart = i+1; - } - } - decodedFrame->tocall = frame.substring(2, 9); // Extract destination address - decodedFrame->sender = frame.substring(9, 16); // Extract source address - if (payloadFrameStart >= 21) { // is there path1? - decodedFrame->path1 = frame.substring(16, 23); - } - if (payloadFrameStart >= 28) { // is there path2? - decodedFrame->path2 = frame.substring(23, 30); - } - decodedFrame->control = frame.substring(payloadFrameStart-1, payloadFrameStart); // Extract control information // 0x03 - decodedFrame->pid = frame.substring(payloadFrameStart, payloadFrameStart + 1); // Extract pid information // 0xF0 - decodedFrame->payload = frame.substring(payloadFrameStart + 1, frameSize - 1); // Extract payload - return true; - } - - String AX25FrameToLoRaPacket(const String& frame) { - //Serial.println(frame); - if (decodeAX25(frame, frame.length(), &decodedFrame)) { - //String packetToLoRa = ""; - String packetToLoRa = decodeFrame(decodedFrame.sender) + ">" + decodeFrame(decodedFrame.tocall); - - if (decodedFrame.path1[0] != 0) { - packetToLoRa += ","; - packetToLoRa += decodeFrame(decodedFrame.path1); - } - if (decodedFrame.path2[0] != 0) { - packetToLoRa += ","; - packetToLoRa += decodeFrame(decodedFrame.path2); - } - packetToLoRa += ":"; - packetToLoRa += decodedFrame.payload; - return packetToLoRa; - } else { - return ""; - } - } - - //************************************** - String encapsulateKISS(const String& ax25Frame, uint8_t command) { String kissFrame = ""; kissFrame += (char)KissChar::FEND; @@ -119,6 +90,33 @@ namespace AX25_Utils { return kissAddress; } + String decodeKISS(const String& inputFrame, bool& dataFrame) { + String frame = ""; + if (KISS_Utils::validateKISSFrame(inputFrame)) { + dataFrame = inputFrame.charAt(1) == KissCmd::Data; + if (dataFrame) { + String ax25Frame = decapsulateKISS(inputFrame); + bool isLastAddress = false; + String dstAddr = decodeAddressAX25(ax25Frame.substring(0, 7), isLastAddress, false); + String srcAddr = decodeAddressAX25(ax25Frame.substring(7, 14), isLastAddress, false); + + frame = srcAddr + ">" + dstAddr; + + int digiInfoIndex = 14; + while (!isLastAddress && digiInfoIndex + 7 < ax25Frame.length()) { + String digiAddr = decodeAddressAX25(ax25Frame.substring(digiInfoIndex, digiInfoIndex + 7), isLastAddress, true); + frame += ',' + digiAddr; + digiInfoIndex += 7; + } + frame += ':'; + frame += ax25Frame.substring(digiInfoIndex + 2); + } else { + frame += inputFrame; + } + } + return frame; + } + String encodeKISS(const String& frame) { String ax25Frame = ""; diff --git a/src/ax25_utils.h b/src/ax25_utils.h index 566571c..0871e6f 100644 --- a/src/ax25_utils.h +++ b/src/ax25_utils.h @@ -3,23 +3,12 @@ #include -struct AX25Frame { // Define AX.25 frame structure - String tocall; // destination - String sender; // source - String path1; // if present - String path2; // if present - String control; - String pid; - String payload; -}; namespace AX25_Utils { - String decodeFrame(const String& frame); - bool decodeAX25(const String& frame, int frameSize, AX25Frame* decodedFrame); - String AX25FrameToLoRaPacket(const String& frame); - - String encodeKISS(const String& frame); + String encodeKISS(const String& frame); + String decodeKISS(const String& inputFrame, bool& dataFrame); + } #endif \ No newline at end of file diff --git a/src/ble_utils.cpp b/src/ble_utils.cpp index a10e9ed..ddc5d64 100644 --- a/src/ble_utils.cpp +++ b/src/ble_utils.cpp @@ -2,6 +2,7 @@ #include "configuration.h" #include "ax25_utils.h" #include "lora_utils.h" +#include "kiss_utils.h" #include "ble_utils.h" #include "display.h" #include "logger.h" @@ -30,6 +31,8 @@ extern bool sendBleToLoRa; extern bool bluetoothConnected; extern String BLEToLoRaPacket; +String kissSerialBuffer = ""; + class MyServerCallbacks : public NimBLEServerCallbacks { void onConnect(NimBLEServer* pServer) { @@ -46,21 +49,36 @@ class MyServerCallbacks : public NimBLEServerCallbacks { } }; + class MyCallbacks : public NimBLECharacteristicCallbacks { void onWrite(NimBLECharacteristic *pCharacteristic) { - std::string receivedData = pCharacteristic->getValue(); - String receivedString = ""; - for (int i = 0; i < receivedData.length(); i++) { - //Serial.print(receivedData[i],HEX); // delete - //Serial.print(" "); - receivedString += receivedData[i]; - } - if (Config.bluetooth.type == 0) { - BLEToLoRaPacket = AX25_Utils::AX25FrameToLoRaPacket(receivedString); - } else if (Config.bluetooth.type == 2) { + if (Config.bluetooth.type == 0) { // AX25 KISS + std::string receivedData = pCharacteristic->getValue(); + delay(100); + for (int i = 0; i < receivedData.length(); i++) { + char character = receivedData[i]; + + if (kissSerialBuffer.length() == 0 && character != (char)KissChar::FEND) continue; + kissSerialBuffer += receivedData[i]; + + if (character == (char)KissChar::FEND && kissSerialBuffer.length() > 3) { + bool isDataFrame = false; + + BLEToLoRaPacket = AX25_Utils::decodeKISS(kissSerialBuffer, isDataFrame); + + if (isDataFrame) { + sendBleToLoRa = true; + kissSerialBuffer = ""; + } + } + } + } else if (Config.bluetooth.type == 2) { // TNC2 + std::string receivedData = pCharacteristic->getValue(); + String receivedString = ""; + for (int i = 0; i < receivedData.length(); i++) receivedString += receivedData[i]; BLEToLoRaPacket = receivedString; + sendBleToLoRa = true; } - sendBleToLoRa = true; } }; @@ -112,9 +130,7 @@ namespace BLE_Utils { } void sendToLoRa() { - if (!sendBleToLoRa) { - return; - } + if (!sendBleToLoRa) return; logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "BLE Tx", "%s", BLEToLoRaPacket.c_str()); displayShow("BLE Tx >>", "", BLEToLoRaPacket, 1000); LoRa_Utils::sendNewPacket(BLEToLoRaPacket); diff --git a/src/kiss_utils.cpp b/src/kiss_utils.cpp index 09cbe5d..23a1679 100644 --- a/src/kiss_utils.cpp +++ b/src/kiss_utils.cpp @@ -9,4 +9,8 @@ namespace KISS_Utils { return (colonPos != -1) && (greaterThanPos != -1) && (colonPos > greaterThanPos); } + bool validateKISSFrame(const String& kissFormattedFrame) { + return kissFormattedFrame.charAt(0) == (char)KissChar::FEND && kissFormattedFrame.charAt(kissFormattedFrame.length() - 1) == (char)KissChar::FEND; + } + } \ No newline at end of file diff --git a/src/kiss_utils.h b/src/kiss_utils.h index 5391b16..9da3347 100644 --- a/src/kiss_utils.h +++ b/src/kiss_utils.h @@ -26,7 +26,8 @@ enum AX25Char { namespace KISS_Utils { - bool validateTNC2Frame(const String& tnc2FormattedFrame); + bool validateTNC2Frame(const String& tnc2FormattedFrame); + bool validateKISSFrame(const String& kissFormattedFrame); }