ax25 iOS works fine

This commit is contained in:
richonguzman 2024-10-30 16:47:46 -03:00
parent 2ca097e0f7
commit e2c4d06a77
6 changed files with 103 additions and 100 deletions

View File

@ -186,21 +186,16 @@ void loop() {
MSG_Utils::processOutputBuffer(); MSG_Utils::processOutputBuffer();
MSG_Utils::clean25SegBuffer(); 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) { if (Config.bluetooth.type == 0 || Config.bluetooth.type == 2) {
BLE_Utils::sendToPhone(packet.text.substring(3));
BLE_Utils::sendToLoRa(); BLE_Utils::sendToLoRa();
} else { } else {
#ifdef HAS_BT_CLASSIC #ifdef HAS_BT_CLASSIC
BLUETOOTH_Utils::sendPacket(packet.text.substring(3));
BLUETOOTH_Utils::sendToLoRa(); BLUETOOTH_Utils::sendToLoRa();
#endif #endif
} }
MSG_Utils::ledNotification(); MSG_Utils::ledNotification();
Utils::checkFlashlight(); Utils::checkFlashlight();
STATION_Utils::checkListenedTrackersByTimeAndDelete(); STATION_Utils::checkListenedTrackersByTimeAndDelete();

View File

@ -4,75 +4,46 @@
namespace AX25_Utils { 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) { int ssid = 0b1111 & ssidChar;
String packet = ""; if (ssid) {
for (int a = 0; a < 6; a ++) { address += '-';
uint16_t shiftedValue = frame[a] >> 1; address += ssid;
if (shiftedValue == 32) { }
a = 10; 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 { } else {
//Serial.print(char(shiftedValue)); ax25Frame += currentChar;
packet += char(shiftedValue);
} }
} }
byte ssid = (frame[6]>>1) & 0x0f; return ax25Frame;
if (String(ssid) != "0") {
packet += "-";
packet += String(ssid);
}
return packet;
} }
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 encapsulateKISS(const String& ax25Frame, uint8_t command) {
String kissFrame = ""; String kissFrame = "";
kissFrame += (char)KissChar::FEND; kissFrame += (char)KissChar::FEND;
@ -119,6 +90,33 @@ namespace AX25_Utils {
return kissAddress; 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 encodeKISS(const String& frame) {
String ax25Frame = ""; String ax25Frame = "";

View File

@ -3,23 +3,12 @@
#include <Arduino.h> #include <Arduino.h>
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 { namespace AX25_Utils {
String decodeFrame(const String& frame); String encodeKISS(const String& frame);
bool decodeAX25(const String& frame, int frameSize, AX25Frame* decodedFrame); String decodeKISS(const String& inputFrame, bool& dataFrame);
String AX25FrameToLoRaPacket(const String& frame);
String encodeKISS(const String& frame);
} }
#endif #endif

View File

@ -2,6 +2,7 @@
#include "configuration.h" #include "configuration.h"
#include "ax25_utils.h" #include "ax25_utils.h"
#include "lora_utils.h" #include "lora_utils.h"
#include "kiss_utils.h"
#include "ble_utils.h" #include "ble_utils.h"
#include "display.h" #include "display.h"
#include "logger.h" #include "logger.h"
@ -30,6 +31,8 @@ extern bool sendBleToLoRa;
extern bool bluetoothConnected; extern bool bluetoothConnected;
extern String BLEToLoRaPacket; extern String BLEToLoRaPacket;
String kissSerialBuffer = "";
class MyServerCallbacks : public NimBLEServerCallbacks { class MyServerCallbacks : public NimBLEServerCallbacks {
void onConnect(NimBLEServer* pServer) { void onConnect(NimBLEServer* pServer) {
@ -46,21 +49,36 @@ class MyServerCallbacks : public NimBLEServerCallbacks {
} }
}; };
class MyCallbacks : public NimBLECharacteristicCallbacks { class MyCallbacks : public NimBLECharacteristicCallbacks {
void onWrite(NimBLECharacteristic *pCharacteristic) { void onWrite(NimBLECharacteristic *pCharacteristic) {
std::string receivedData = pCharacteristic->getValue(); if (Config.bluetooth.type == 0) { // AX25 KISS
String receivedString = ""; std::string receivedData = pCharacteristic->getValue();
for (int i = 0; i < receivedData.length(); i++) { delay(100);
//Serial.print(receivedData[i],HEX); // delete for (int i = 0; i < receivedData.length(); i++) {
//Serial.print(" "); char character = receivedData[i];
receivedString += receivedData[i];
} if (kissSerialBuffer.length() == 0 && character != (char)KissChar::FEND) continue;
if (Config.bluetooth.type == 0) { kissSerialBuffer += receivedData[i];
BLEToLoRaPacket = AX25_Utils::AX25FrameToLoRaPacket(receivedString);
} else if (Config.bluetooth.type == 2) { 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; BLEToLoRaPacket = receivedString;
sendBleToLoRa = true;
} }
sendBleToLoRa = true;
} }
}; };
@ -112,9 +130,7 @@ namespace BLE_Utils {
} }
void sendToLoRa() { void sendToLoRa() {
if (!sendBleToLoRa) { if (!sendBleToLoRa) return;
return;
}
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "BLE Tx", "%s", BLEToLoRaPacket.c_str()); logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "BLE Tx", "%s", BLEToLoRaPacket.c_str());
displayShow("BLE Tx >>", "", BLEToLoRaPacket, 1000); displayShow("BLE Tx >>", "", BLEToLoRaPacket, 1000);
LoRa_Utils::sendNewPacket(BLEToLoRaPacket); LoRa_Utils::sendNewPacket(BLEToLoRaPacket);

View File

@ -9,4 +9,8 @@ namespace KISS_Utils {
return (colonPos != -1) && (greaterThanPos != -1) && (colonPos > greaterThanPos); 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;
}
} }

View File

@ -26,7 +26,8 @@ enum AX25Char {
namespace KISS_Utils { namespace KISS_Utils {
bool validateTNC2Frame(const String& tnc2FormattedFrame); bool validateTNC2Frame(const String& tnc2FormattedFrame);
bool validateKISSFrame(const String& kissFormattedFrame);
} }