2020-06-12 14:53:21 +00:00
|
|
|
#include "ax25_payload.h"
|
2020-06-12 14:34:23 +00:00
|
|
|
|
|
|
|
namespace AX25 {
|
|
|
|
|
2021-02-02 09:18:46 +00:00
|
|
|
Payload::Payload(const byte *rxPayload, int payloadLength)
|
2020-06-13 22:15:05 +00:00
|
|
|
: rptCallsCount_(0)
|
2020-06-12 14:34:23 +00:00
|
|
|
{
|
2020-06-14 11:52:22 +00:00
|
|
|
isValid_ = fromBinary(rxPayload, payloadLength);
|
2020-06-12 14:34:23 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 07:39:49 +00:00
|
|
|
Payload::Payload(const String &textPayload)
|
2020-06-13 22:15:05 +00:00
|
|
|
: rptCallsCount_(0)
|
|
|
|
{
|
2020-06-19 07:39:49 +00:00
|
|
|
isValid_ = fromString(textPayload);
|
2020-06-13 22:15:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Payload::Dump()
|
|
|
|
{
|
|
|
|
Serial.println();
|
|
|
|
Serial.print("valid: "); Serial.println(isValid_);
|
2020-06-14 11:52:22 +00:00
|
|
|
Serial.println("src: " + srcCall_.ToString());
|
|
|
|
Serial.println("dst: " + dstCall_.ToString());
|
2020-06-13 22:15:05 +00:00
|
|
|
Serial.print("rpt: ");
|
|
|
|
for (int i = 0; i < rptCallsCount_; i++) {
|
2020-06-14 11:52:22 +00:00
|
|
|
Serial.print(rptCalls_[i].ToString() + " ");
|
2020-06-13 22:15:05 +00:00
|
|
|
}
|
|
|
|
Serial.println();
|
|
|
|
Serial.println("info: " + info_);
|
|
|
|
}
|
|
|
|
|
2020-06-14 11:52:22 +00:00
|
|
|
int Payload::ToBinary(byte *txPayload, int bufferLength) const
|
2020-06-13 22:15:05 +00:00
|
|
|
{
|
|
|
|
byte *txPtr = txPayload;
|
|
|
|
byte *txEnd = txPayload + bufferLength;
|
|
|
|
|
|
|
|
// destination address
|
2020-06-14 11:52:22 +00:00
|
|
|
if (!dstCall_.ToBinary(txPtr, CallsignSize)) return 0;
|
2020-06-13 22:15:05 +00:00
|
|
|
txPtr += CallsignSize;
|
|
|
|
if (txPtr >= txEnd) return 0;
|
|
|
|
|
|
|
|
// source address
|
2020-06-14 11:52:22 +00:00
|
|
|
if (!srcCall_.ToBinary(txPtr, CallsignSize)) return 0;
|
2020-06-13 22:15:05 +00:00
|
|
|
txPtr += CallsignSize;
|
|
|
|
if (txPtr >= txEnd) return 0;
|
|
|
|
|
|
|
|
// digipeater addresses
|
|
|
|
for (int i = 0; i < rptCallsCount_; i++) {
|
2020-06-14 11:52:22 +00:00
|
|
|
if (!rptCalls_[i].ToBinary(txPtr, CallsignSize)) return 0;
|
2020-06-13 22:15:05 +00:00
|
|
|
txPtr += CallsignSize;
|
|
|
|
if (txPtr >= txEnd) return 0;
|
|
|
|
}
|
|
|
|
*(txPtr - 1) |= 1;
|
|
|
|
|
|
|
|
// control + protocol id
|
|
|
|
if ((txPtr + 2) >= txEnd) return 0;
|
|
|
|
*(txPtr++) = AX25Ctrl::UI;
|
|
|
|
*(txPtr++) = AX25Pid::NoLayer3;
|
|
|
|
|
|
|
|
// information field
|
|
|
|
for (int i = 0; i < info_.length(); i++) {
|
|
|
|
char c = info_.charAt(i);
|
|
|
|
if (c == '\0') break;
|
|
|
|
*(txPtr++) = c;
|
|
|
|
if (txPtr >= txEnd) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)(txPtr-txPayload);
|
|
|
|
}
|
|
|
|
|
2021-02-02 09:18:46 +00:00
|
|
|
String Payload::ToString(const String &customComment)
|
2020-06-12 14:34:23 +00:00
|
|
|
{
|
2020-06-14 11:52:22 +00:00
|
|
|
String txt = srcCall_.ToString() + String(">") + dstCall_.ToString();
|
2020-06-12 14:34:23 +00:00
|
|
|
|
2020-06-12 15:52:04 +00:00
|
|
|
for (int i = 0; i < rptCallsCount_; i++) {
|
2020-06-14 11:52:22 +00:00
|
|
|
if (rptCalls_[i].IsValid()) {
|
|
|
|
txt += String(",") + rptCalls_[i].ToString();
|
2020-06-12 15:52:04 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-14 11:52:22 +00:00
|
|
|
|
2020-06-12 15:55:55 +00:00
|
|
|
txt += String(":") + info_;
|
2020-06-12 14:34:23 +00:00
|
|
|
|
2020-06-12 15:55:55 +00:00
|
|
|
if (info_.startsWith("=")) {
|
2020-06-12 14:34:23 +00:00
|
|
|
txt += customComment;
|
|
|
|
}
|
2020-06-14 11:52:22 +00:00
|
|
|
|
2020-06-17 10:32:00 +00:00
|
|
|
return txt;
|
2020-06-12 14:34:23 +00:00
|
|
|
}
|
|
|
|
|
2020-06-17 07:42:17 +00:00
|
|
|
bool Payload::Digirepeat(const Callsign &ownCallsign)
|
2020-06-14 11:52:22 +00:00
|
|
|
{
|
2020-06-17 07:42:17 +00:00
|
|
|
for (int i = 0; i < rptCallsCount_; i++) {
|
|
|
|
if (rptCalls_[i].Digirepeat()) {
|
|
|
|
// if trace was digirepeated insert own callsign
|
|
|
|
if (rptCalls_[i].IsTrace()) {
|
|
|
|
InsertRptCallsign(ownCallsign, i);
|
|
|
|
}
|
2020-06-14 11:52:22 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-17 07:42:17 +00:00
|
|
|
bool Payload::InsertRptCallsign(const Callsign &rptCallsign, int index)
|
|
|
|
{
|
|
|
|
if (rptCallsCount_ >= RptMaxCount
|
|
|
|
|| index >= RptMaxCount
|
|
|
|
|| index >= rptCallsCount_) return false;
|
|
|
|
|
|
|
|
for (int i = index; i < rptCallsCount_; i++) {
|
|
|
|
rptCalls_[i + 1] = rptCalls_[i];
|
|
|
|
}
|
|
|
|
rptCalls_[index] = rptCallsign;
|
|
|
|
rptCallsCount_++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-14 11:52:22 +00:00
|
|
|
bool Payload::fromBinary(const byte *rxPayload, int payloadLength)
|
2020-06-12 14:34:23 +00:00
|
|
|
{
|
2020-06-13 22:15:05 +00:00
|
|
|
const byte *rxPtr = rxPayload;
|
|
|
|
const byte *rxEnd = rxPayload + payloadLength;
|
2020-06-14 11:52:22 +00:00
|
|
|
|
|
|
|
if (payloadLength < CallsignSize) return false;
|
|
|
|
|
2020-06-12 15:52:04 +00:00
|
|
|
// destination address
|
2020-06-14 11:52:22 +00:00
|
|
|
dstCall_ = AX25::Callsign(rxPtr, CallsignSize);
|
2020-06-14 14:59:35 +00:00
|
|
|
if (!dstCall_.IsValid()) return false;
|
2020-06-12 14:34:23 +00:00
|
|
|
rxPtr += CallsignSize;
|
2020-06-13 22:15:05 +00:00
|
|
|
if (rxPtr >= rxEnd) return false;
|
2020-06-12 14:34:23 +00:00
|
|
|
|
2020-06-12 15:52:04 +00:00
|
|
|
// source address
|
2020-06-14 11:52:22 +00:00
|
|
|
srcCall_ = AX25::Callsign(rxPtr, CallsignSize);
|
2020-06-14 14:59:35 +00:00
|
|
|
if (!srcCall_.IsValid()) return false;
|
2020-06-12 14:34:23 +00:00
|
|
|
rxPtr += CallsignSize;
|
2020-06-12 15:52:04 +00:00
|
|
|
if (rxPtr >= rxEnd) return false;
|
2020-06-12 14:34:23 +00:00
|
|
|
|
2020-06-12 15:52:04 +00:00
|
|
|
rptCallsCount_ = 0;
|
2020-06-13 22:15:05 +00:00
|
|
|
|
2020-06-12 15:52:04 +00:00
|
|
|
// digipeater addresses
|
2020-06-14 14:59:35 +00:00
|
|
|
for (int i = 0, j = 0; i < RptMaxCount; i++) {
|
2020-06-12 15:52:04 +00:00
|
|
|
if ((rxPayload[(i + 2) * CallsignSize - 1] & 1) == 0) {
|
2020-06-14 14:59:35 +00:00
|
|
|
rptCalls_[j] = AX25::Callsign(rxPtr, CallsignSize);
|
|
|
|
if (rptCalls_[j].IsValid()) {
|
|
|
|
rptCallsCount_++;
|
|
|
|
j++;
|
|
|
|
}
|
2020-06-12 14:34:23 +00:00
|
|
|
rxPtr += CallsignSize;
|
2020-06-12 15:52:04 +00:00
|
|
|
if (rxPtr >= rxEnd) return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
2020-06-12 14:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 15:52:04 +00:00
|
|
|
|
|
|
|
// control + protocol id
|
|
|
|
if ((rxPtr + 2) >= rxEnd) return false;
|
2020-06-12 14:34:23 +00:00
|
|
|
if (*(rxPtr++) != AX25Ctrl::UI) return false;
|
|
|
|
if (*(rxPtr++) != AX25Pid::NoLayer3) return false;
|
2020-06-12 15:52:04 +00:00
|
|
|
|
|
|
|
// information field
|
|
|
|
while (rxPtr < rxEnd) {
|
2020-06-12 15:55:55 +00:00
|
|
|
info_ += String((char)*(rxPtr++));
|
2020-06-12 14:34:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-19 07:39:49 +00:00
|
|
|
bool Payload::fromString(const String &textPayload)
|
2020-06-13 22:15:05 +00:00
|
|
|
{
|
2020-06-19 07:39:49 +00:00
|
|
|
String inputText = textPayload;
|
|
|
|
|
2020-06-13 22:15:05 +00:00
|
|
|
int rptIndex = inputText.indexOf('>');
|
|
|
|
int infoIndex = inputText.indexOf(':');
|
|
|
|
|
|
|
|
// bad format
|
|
|
|
if (rptIndex == -1 || infoIndex == -1) return false;
|
|
|
|
|
|
|
|
info_ = inputText.substring(infoIndex + 1);
|
2020-06-14 14:59:35 +00:00
|
|
|
srcCall_ = AX25::Callsign(inputText.substring(0, rptIndex));
|
|
|
|
if (!srcCall_.IsValid()) return false;
|
2020-06-13 22:15:05 +00:00
|
|
|
String paths = inputText.substring(rptIndex + 1, infoIndex);
|
|
|
|
|
|
|
|
rptCallsCount_ = 0;
|
|
|
|
int index = 0;
|
|
|
|
while (rptCallsCount_ <= RptMaxCount) {
|
|
|
|
int nextIndex = paths.indexOf(',', index);
|
|
|
|
String pathItem = paths.substring(index, nextIndex == -1 ? paths.length() : nextIndex);
|
|
|
|
if (index == 0) {
|
2020-06-14 14:59:35 +00:00
|
|
|
dstCall_ = AX25::Callsign(pathItem);
|
|
|
|
if (!dstCall_.IsValid()) return false;
|
2020-06-13 22:15:05 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-06-14 14:59:35 +00:00
|
|
|
rptCalls_[rptCallsCount_] = AX25::Callsign(pathItem);
|
|
|
|
if (rptCalls_[rptCallsCount_].IsValid()) {
|
|
|
|
rptCallsCount_++;
|
|
|
|
}
|
2020-06-13 22:15:05 +00:00
|
|
|
}
|
|
|
|
if (nextIndex == -1) break;
|
|
|
|
index = nextIndex + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-12 14:34:23 +00:00
|
|
|
} // AX25
|