TNC: recognize and ignore non data frames
This commit is contained in:
parent
c0eb892a7c
commit
6cd887f91a
|
|
@ -7,7 +7,7 @@ String decode_address_ax25(const String &ax25Address, bool &isLast, bool isRelay
|
||||||
|
|
||||||
bool validateKISSFrame(const String &kissFormattedFrame);
|
bool validateKISSFrame(const String &kissFormattedFrame);
|
||||||
|
|
||||||
String decapsulateKISS(const String& frame);
|
String decapsulateKISS(const String &frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* https://ham.zmailer.org/oh2mqk/aprx/PROTOCOLS
|
* https://ham.zmailer.org/oh2mqk/aprx/PROTOCOLS
|
||||||
|
|
@ -33,100 +33,112 @@ String decapsulateKISS(const String& frame);
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String encode_kiss(const String& tnc2FormattedFrame) {
|
String encode_kiss(const String &tnc2FormattedFrame) {
|
||||||
String ax25Frame = "";
|
String ax25Frame = "";
|
||||||
|
|
||||||
if (validateTNC2Frame(tnc2FormattedFrame)){
|
if (validateTNC2Frame(tnc2FormattedFrame)) {
|
||||||
String address = "";
|
String address = "";
|
||||||
bool dst_addres_written = false;
|
bool dst_addres_written = false;
|
||||||
for (int p=0;p<=tnc2FormattedFrame.indexOf(':');p++){
|
for (int p = 0; p <= tnc2FormattedFrame.indexOf(':'); p++) {
|
||||||
char currentChar = tnc2FormattedFrame.charAt(p);
|
char currentChar = tnc2FormattedFrame.charAt(p);
|
||||||
if (currentChar == ':' || currentChar == '>' || currentChar == ','){
|
if (currentChar == ':' || currentChar == '>' || currentChar == ',') {
|
||||||
if (!dst_addres_written && (currentChar == ',' || currentChar == ':')){
|
if (!dst_addres_written && (currentChar == ',' || currentChar == ':')) {
|
||||||
// ax25 frame DST SRC
|
// ax25 frame DST SRC
|
||||||
// tnc2 frame SRC DST
|
// tnc2 frame SRC DST
|
||||||
ax25Frame = encode_address_ax25(address) + ax25Frame;
|
ax25Frame = encode_address_ax25(address) + ax25Frame;
|
||||||
dst_addres_written = true;
|
dst_addres_written = true;
|
||||||
} else {
|
} else {
|
||||||
ax25Frame += encode_address_ax25(address);
|
ax25Frame += encode_address_ax25(address);
|
||||||
}
|
|
||||||
address = "";
|
|
||||||
} else {
|
|
||||||
address += currentChar;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
auto lastAddressChar = (uint8_t)ax25Frame.charAt(ax25Frame.length() - 1);
|
address = "";
|
||||||
ax25Frame.setCharAt(ax25Frame.length() - 1, (char)(lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
|
} else {
|
||||||
ax25Frame += (char)APRS_CONTROL_FIELD;
|
address += currentChar;
|
||||||
ax25Frame += (char)APRS_INFORMATION_FIELD;
|
}
|
||||||
ax25Frame += tnc2FormattedFrame.substring(tnc2FormattedFrame.indexOf(':')+1);
|
|
||||||
}
|
}
|
||||||
|
auto lastAddressChar = (uint8_t) ax25Frame.charAt(ax25Frame.length() - 1);
|
||||||
|
ax25Frame.setCharAt(ax25Frame.length() - 1, (char) (lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
|
||||||
|
ax25Frame += (char) APRS_CONTROL_FIELD;
|
||||||
|
ax25Frame += (char) APRS_INFORMATION_FIELD;
|
||||||
|
ax25Frame += tnc2FormattedFrame.substring(tnc2FormattedFrame.indexOf(':') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);
|
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);
|
||||||
return kissFrame;
|
return kissFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
String encapsulateKISS(const String &ax25Frame, uint8_t TNCCmd) {
|
String encapsulateKISS(const String &ax25Frame, uint8_t TNCCmd) {
|
||||||
String kissFrame = "";
|
String kissFrame = "";
|
||||||
kissFrame += (char)FEND; // start of frame
|
kissFrame += (char) FEND; // start of frame
|
||||||
kissFrame += (char)(0x0f & TNCCmd); // TNC0, cmd
|
kissFrame += (char) (0x0f & TNCCmd); // TNC0, cmd
|
||||||
for (int i = 0; i < ax25Frame.length(); ++i) {
|
for (int i = 0; i < ax25Frame.length(); ++i) {
|
||||||
char currentChar = ax25Frame.charAt(i);
|
char currentChar = ax25Frame.charAt(i);
|
||||||
if (currentChar == (char)FEND){
|
if (currentChar == (char) FEND) {
|
||||||
kissFrame += (char)FESC;
|
kissFrame += (char) FESC;
|
||||||
kissFrame += (char)TFEND;
|
kissFrame += (char) TFEND;
|
||||||
} else if (currentChar == (char)FESC){
|
} else if (currentChar == (char) FESC) {
|
||||||
kissFrame += (char)FESC;
|
kissFrame += (char) FESC;
|
||||||
kissFrame += (char)TFESC;
|
kissFrame += (char) TFESC;
|
||||||
} else {
|
} else {
|
||||||
kissFrame += currentChar;
|
kissFrame += currentChar;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
kissFrame += (char)FEND; // end of frame
|
}
|
||||||
return kissFrame;
|
kissFrame += (char) FEND; // end of frame
|
||||||
|
return kissFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String decapsulateKISS(const String& frame) {
|
String decapsulateKISS(const String &frame) {
|
||||||
String ax25Frame = "";
|
String ax25Frame = "";
|
||||||
for (int i = 2; i < frame.length() - 1; ++i) {
|
for (int i = 2; i < frame.length() - 1; ++i) {
|
||||||
char currentChar = frame.charAt(i);
|
char currentChar = frame.charAt(i);
|
||||||
if (currentChar == (char)FESC){
|
if (currentChar == (char) FESC) {
|
||||||
char nextChar = frame.charAt(i+1);
|
char nextChar = frame.charAt(i + 1);
|
||||||
if (nextChar == (char)TFEND){
|
if (nextChar == (char) TFEND) {
|
||||||
ax25Frame += (char)FEND;
|
ax25Frame += (char) FEND;
|
||||||
} else if (nextChar == (char)TFESC){
|
} else if (nextChar == (char) TFESC) {
|
||||||
ax25Frame += (char)FESC;
|
ax25Frame += (char) FESC;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
ax25Frame += currentChar;
|
ax25Frame += currentChar;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ax25Frame;
|
return ax25Frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
String decode_kiss(const String& kissFormattedFrame) {
|
/**
|
||||||
String TNC2Frame = "";
|
*
|
||||||
|
* @param inputKISSTNCFrame
|
||||||
|
* @param dataFrame
|
||||||
|
* @return Decapsulated TNC2KISS APRS data frame, or raw command data frame
|
||||||
|
*/
|
||||||
|
String decode_kiss(const String &inputKISSTNCFrame, bool &dataFrame) {
|
||||||
|
String TNC2Frame = "";
|
||||||
|
|
||||||
if (validateKISSFrame(kissFormattedFrame)){
|
if (validateKISSFrame(inputKISSTNCFrame)) {
|
||||||
String ax25Frame = decapsulateKISS(kissFormattedFrame);
|
dataFrame = inputKISSTNCFrame.charAt(1) == CMD_DATA;
|
||||||
bool isLast = false;
|
if (dataFrame){
|
||||||
String dst_addr = decode_address_ax25(ax25Frame.substring(0, 7), isLast, false);
|
String ax25Frame = decapsulateKISS(inputKISSTNCFrame);
|
||||||
String src_addr = decode_address_ax25(ax25Frame.substring(7, 14), isLast, false);
|
bool isLast = false;
|
||||||
TNC2Frame = src_addr + ">" + dst_addr;
|
String dst_addr = decode_address_ax25(ax25Frame.substring(0, 7), isLast, false);
|
||||||
int digi_info_index = 14;
|
String src_addr = decode_address_ax25(ax25Frame.substring(7, 14), isLast, false);
|
||||||
while (!isLast && digi_info_index + 7 < ax25Frame.length()){
|
TNC2Frame = src_addr + ">" + dst_addr;
|
||||||
String digi_addr = decode_address_ax25(ax25Frame.substring(digi_info_index, digi_info_index + 7), isLast, true);
|
int digi_info_index = 14;
|
||||||
TNC2Frame += ',' + digi_addr;
|
while (!isLast && digi_info_index + 7 < ax25Frame.length()) {
|
||||||
digi_info_index += 7;
|
String digi_addr = decode_address_ax25(ax25Frame.substring(digi_info_index, digi_info_index + 7), isLast, true);
|
||||||
}
|
TNC2Frame += ',' + digi_addr;
|
||||||
TNC2Frame += ':';
|
digi_info_index += 7;
|
||||||
TNC2Frame += ax25Frame.substring(digi_info_index + 2);
|
}
|
||||||
|
TNC2Frame += ':';
|
||||||
|
TNC2Frame += ax25Frame.substring(digi_info_index + 2);
|
||||||
|
} else {
|
||||||
|
// command frame, currently ignored
|
||||||
|
TNC2Frame += inputKISSTNCFrame;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TNC2Frame;
|
return TNC2Frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -135,32 +147,32 @@ String decode_kiss(const String& kissFormattedFrame) {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String encode_address_ax25(String tnc2Address) {
|
String encode_address_ax25(String tnc2Address) {
|
||||||
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
|
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
|
||||||
|
|
||||||
if (tnc2Address.indexOf('-') == -1){
|
if (tnc2Address.indexOf('-') == -1) {
|
||||||
if (hasBeenDigipited){
|
if (hasBeenDigipited) {
|
||||||
// ex. TCPIP* in tnc2Address
|
// ex. TCPIP* in tnc2Address
|
||||||
// so we skip last char
|
// so we skip last char
|
||||||
tnc2Address = tnc2Address.substring(0, tnc2Address.length()-1);
|
tnc2Address = tnc2Address.substring(0, tnc2Address.length() - 1);
|
||||||
}
|
|
||||||
tnc2Address += "-0";
|
|
||||||
}
|
}
|
||||||
|
tnc2Address += "-0";
|
||||||
|
}
|
||||||
|
|
||||||
int separatorIndex = tnc2Address.indexOf('-');
|
int separatorIndex = tnc2Address.indexOf('-');
|
||||||
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
||||||
// TODO: SSID should not be > 16
|
// TODO: SSID should not be > 16
|
||||||
String kissAddress = "";
|
String kissAddress = "";
|
||||||
for (int i = 0; i < 6; ++i) {
|
for (int i = 0; i < 6; ++i) {
|
||||||
char addressChar;
|
char addressChar;
|
||||||
if (tnc2Address.length() > i && i < separatorIndex){
|
if (tnc2Address.length() > i && i < separatorIndex) {
|
||||||
addressChar = tnc2Address.charAt(i);
|
addressChar = tnc2Address.charAt(i);
|
||||||
} else {
|
} else {
|
||||||
addressChar = ' ';
|
addressChar = ' ';
|
||||||
}
|
|
||||||
kissAddress += (char)(addressChar << 1);
|
|
||||||
}
|
}
|
||||||
kissAddress += (char)((ssid << 1) | 0b01100000 | (hasBeenDigipited ? HAS_BEEN_DIGIPITED_MASK : 0));
|
kissAddress += (char) (addressChar << 1);
|
||||||
return kissAddress;
|
}
|
||||||
|
kissAddress += (char) ((ssid << 1) | 0b01100000 | (hasBeenDigipited ? HAS_BEEN_DIGIPITED_MASK : 0));
|
||||||
|
return kissAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,30 +181,35 @@ String encode_address_ax25(String tnc2Address) {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String decode_address_ax25(const String &ax25Address, bool &isLast, bool isRelay) {
|
String decode_address_ax25(const String &ax25Address, bool &isLast, bool isRelay) {
|
||||||
String TNCAddress = "";
|
String TNCAddress = "";
|
||||||
for (int i = 0; i < 6; ++i) {
|
for (int i = 0; i < 6; ++i) {
|
||||||
uint8_t currentCharacter = ax25Address.charAt(i);
|
uint8_t currentCharacter = ax25Address.charAt(i);
|
||||||
currentCharacter >>= 1;
|
currentCharacter >>= 1;
|
||||||
if (currentCharacter != ' '){
|
if (currentCharacter != ' ') {
|
||||||
TNCAddress += (char)currentCharacter;
|
TNCAddress += (char) currentCharacter;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
auto ssid_char = (uint8_t) ax25Address.charAt(6);
|
}
|
||||||
bool hasBeenDigipited = ssid_char & HAS_BEEN_DIGIPITED_MASK;
|
auto ssid_char = (uint8_t) ax25Address.charAt(6);
|
||||||
isLast = ssid_char & IS_LAST_ADDRESS_POSITION_MASK;
|
bool hasBeenDigipited = ssid_char & HAS_BEEN_DIGIPITED_MASK;
|
||||||
ssid_char >>= 1;
|
isLast = ssid_char & IS_LAST_ADDRESS_POSITION_MASK;
|
||||||
|
ssid_char >>= 1;
|
||||||
|
|
||||||
int ssid = 0b1111 & ssid_char;
|
int ssid = 0b1111 & ssid_char;
|
||||||
if (ssid){
|
if (ssid) {
|
||||||
TNCAddress += '-';
|
TNCAddress += '-';
|
||||||
TNCAddress += ssid;
|
TNCAddress += ssid;
|
||||||
}
|
}
|
||||||
if (isRelay && hasBeenDigipited){
|
if (isRelay && hasBeenDigipited) {
|
||||||
TNCAddress += '*';
|
TNCAddress += '*';
|
||||||
}
|
}
|
||||||
return TNCAddress;
|
return TNCAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateTNC2Frame(const String &tnc2FormattedFrame) { return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1); }
|
bool validateTNC2Frame(const String &tnc2FormattedFrame) {
|
||||||
|
return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1);
|
||||||
|
}
|
||||||
|
|
||||||
bool validateKISSFrame(const String &kissFormattedFrame) { return kissFormattedFrame.charAt(0) == (char)FEND && kissFormattedFrame.charAt(kissFormattedFrame.length() - 1) == (char)FEND; }
|
bool validateKISSFrame(const String &kissFormattedFrame) {
|
||||||
|
return kissFormattedFrame.charAt(0) == (char) FEND &&
|
||||||
|
kissFormattedFrame.charAt(kissFormattedFrame.length() - 1) == (char) FEND;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,6 @@
|
||||||
#define IS_LAST_ADDRESS_POSITION_MASK 0b1
|
#define IS_LAST_ADDRESS_POSITION_MASK 0b1
|
||||||
|
|
||||||
String encode_kiss(const String& tnc2FormattedFrame);
|
String encode_kiss(const String& tnc2FormattedFrame);
|
||||||
String decode_kiss(const String& kissFormattedFrame);
|
String decode_kiss(const String &inputKISSTNCFrame, bool &dataFrame);
|
||||||
|
|
||||||
String encapsulateKISS(const String &ax25Frame, uint8_t TNCCmd);
|
String encapsulateKISS(const String &ax25Frame, uint8_t TNCCmd);
|
||||||
|
|
@ -33,28 +33,31 @@ void handleKISSData(char character, int bufferIndex) {
|
||||||
}
|
}
|
||||||
inTNCData->concat(character);
|
inTNCData->concat(character);
|
||||||
if (character == (char) FEND && inTNCData->length() > 3) {
|
if (character == (char) FEND && inTNCData->length() > 3) {
|
||||||
const String &TNC2DataFrame = decode_kiss(*inTNCData);
|
bool isDataFrame = false;
|
||||||
|
const String &TNC2DataFrame = decode_kiss(*inTNCData, isDataFrame);
|
||||||
|
|
||||||
#ifdef LOCAL_KISS_ECHO
|
if (isDataFrame) {
|
||||||
|
#ifdef LOCAL_KISS_ECHO
|
||||||
Serial.print(inTNCData);
|
Serial.print(inTNCData);
|
||||||
#ifdef ENABLE_BLUETOOTH
|
#ifdef ENABLE_BLUETOOTH
|
||||||
if (SerialBT.hasClient()) {
|
if (SerialBT.hasClient()) {
|
||||||
SerialBT.print(inTNCData);
|
SerialBT.print(inTNCData);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_WIFI
|
#ifdef ENABLE_WIFI
|
||||||
iterateWifiClients([](WiFiClient *client, const String *data){
|
iterateWifiClients([](WiFiClient *client, const String *data){
|
||||||
if (client->connected()){
|
if (client->connected()){
|
||||||
client->print(*data);
|
client->print(*data);
|
||||||
client->flush();
|
client->flush();
|
||||||
}
|
}
|
||||||
}, &inTNCData, clients, MAX_WIFI_CLIENTS);
|
}, &inTNCData, clients, MAX_WIFI_CLIENTS);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
auto *buffer = new String();
|
||||||
auto *buffer = new String();
|
buffer->concat(TNC2DataFrame);
|
||||||
buffer->concat(TNC2DataFrame);
|
if (xQueueSend(tncToSendQueue, &buffer, (1000 / portTICK_PERIOD_MS)) != pdPASS) {
|
||||||
if (xQueueSend(tncToSendQueue, &buffer, (1000 / portTICK_PERIOD_MS)) != pdPASS){
|
delete buffer;
|
||||||
delete buffer;
|
}
|
||||||
}
|
}
|
||||||
inTNCData->clear();
|
inTNCData->clear();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue