mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 09:18:54 -05:00
221 lines
6.6 KiB
C++
221 lines
6.6 KiB
C++
///////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2021 Jon Beniston, M7RCE <jon@beniston.com> //
|
|
// //
|
|
// This program is free software; you can redistribute it and/or modify //
|
|
// it under the terms of the GNU General Public License as published by //
|
|
// the Free Software Foundation as version 3 of the License, or //
|
|
// (at your option) any later version. //
|
|
// //
|
|
// This program is distributed in the hope that it will be useful, //
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
// GNU General Public License V3 for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <QDebug>
|
|
|
|
#include "ax25.h"
|
|
|
|
// CRC is assumed to be correct (checked in packetdemodsink)
|
|
bool AX25Packet::decode(QByteArray packet)
|
|
{
|
|
int i, j;
|
|
char destAddress[7];
|
|
unsigned char destSSID;
|
|
char sourceAddress[7];
|
|
unsigned char sourceSSID;
|
|
char repeaterAddress[7];
|
|
unsigned char repeaterSSID;
|
|
unsigned char ssid;
|
|
unsigned char control;
|
|
|
|
// Check for minimum size packet. Addresses, control and CRC
|
|
if (packet.size() < 7+7+1+2)
|
|
return false;
|
|
|
|
// Address - ASCII shifted right one bit
|
|
for (i = 0; i < 6; i++)
|
|
destAddress[i] = (packet[i] >> 1) & 0x7f;
|
|
destAddress[6] = '\0';
|
|
destSSID = packet[6];
|
|
for (i = 0; i < 6; i++)
|
|
sourceAddress[i] = (packet[7+i] >> 1) & 0x7f;
|
|
sourceAddress[6] = '\0';
|
|
sourceSSID = packet[13];
|
|
|
|
// From = source address
|
|
m_from = QString(sourceAddress).trimmed();
|
|
ssid = (sourceSSID >> 1) & 0xf;
|
|
if (ssid != 0)
|
|
m_from = QString("%1-%2").arg(m_from).arg(ssid);
|
|
|
|
// To = destination address
|
|
m_to = QString(destAddress).trimmed();
|
|
ssid = (destSSID >> 1) & 0xf;
|
|
if (ssid != 0)
|
|
m_to = QString("%1-%2").arg(m_to).arg(ssid);
|
|
|
|
// List of repeater addresses for via field
|
|
m_via = QString("");
|
|
i = 13;
|
|
int incomingViaStrIdx = -1;
|
|
while ((packet[i] & 1) == 0)
|
|
{
|
|
i++;
|
|
for (j = 0; j < 6; j++)
|
|
repeaterAddress[j] = (packet[i+j] >> 1) & 0x7f;
|
|
repeaterAddress[j] = '\0';
|
|
i += 6;
|
|
repeaterSSID = packet[i];
|
|
ssid = (repeaterSSID >> 1) & 0xf;
|
|
QString repeater = QString(repeaterAddress).trimmed();
|
|
QString ssidString = (ssid != 0) ? QString("%2-%3").arg(repeater).arg(ssid) : QString(repeater);
|
|
|
|
if (!m_via.isEmpty())
|
|
m_via.append(',');
|
|
m_via.append(ssidString);
|
|
|
|
if (packet[i] & 0x80)
|
|
incomingViaStrIdx = m_via.length();
|
|
}
|
|
if (incomingViaStrIdx >= 0)
|
|
m_via.insert(incomingViaStrIdx, "*");
|
|
|
|
i++;
|
|
// Control can be 1 or 2 bytes - how to know if 2?
|
|
// I, U and S frames
|
|
control = packet[i++];
|
|
if ((control & 1) == 0)
|
|
m_type = QString("I");
|
|
else if ((control & 3) == 3)
|
|
{
|
|
// See figure 4.4 of AX.25 spec
|
|
switch (control & 0xef)
|
|
{
|
|
case 0x6f:
|
|
m_type = QString("SABME");
|
|
break;
|
|
case 0x2f:
|
|
m_type = QString("SABM");
|
|
break;
|
|
case 0x43:
|
|
m_type = QString("DISC");
|
|
break;
|
|
case 0x0f:
|
|
m_type = QString("DM");
|
|
break;
|
|
case 0x63:
|
|
m_type = QString("UA");
|
|
break;
|
|
case 0x87:
|
|
m_type = QString("FR");
|
|
break;
|
|
case 0x03:
|
|
m_type = QString("UI");
|
|
break;
|
|
case 0xaf:
|
|
m_type = QString("XID");
|
|
break;
|
|
case 0xe3:
|
|
m_type = QString("TEST");
|
|
break;
|
|
default:
|
|
m_type = QString("U");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
m_type = QString("S");
|
|
// APRS packets use UI frames, which are a subype of U frames
|
|
// Only I and UI frames have Layer 3 Protocol ID (PID).
|
|
if ((m_type == "I") || (m_type == "UI"))
|
|
m_pid = QString("%1").arg(((unsigned)packet[i++]) & 0xff, 2, 16, QLatin1Char('0'));
|
|
else
|
|
m_pid = QString("");
|
|
int infoStart, infoEnd;
|
|
infoStart = i;
|
|
infoEnd = packet.size()-2-i;
|
|
QByteArray info(packet.mid(infoStart, infoEnd));
|
|
m_data = info;
|
|
m_dataHex = QString(info.toHex());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AX25Packet::ssid(QByteArray& b, int i, int len, uint8_t& ssid)
|
|
{
|
|
if (b[i] == '-')
|
|
{
|
|
if (len > i + 1)
|
|
{
|
|
ssid = b[i+1] - '0';
|
|
if ((len > i + 2) && isdigit(b[i+2])) {
|
|
ssid = (ssid*10) + (b[i+2] - '0');
|
|
}
|
|
if (ssid >= 16)
|
|
{
|
|
// FIXME: APRS-IS seems to support 2 letter SSIDs
|
|
// These can't be sent over RF, as not enough bits in AX.25 packet
|
|
qDebug() << "AX25Packet::ssid: SSID greater than 15 not supported";
|
|
ssid = 0;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qDebug() << "AX25Packet::ssid: SSID number missing";
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
QByteArray AX25Packet::encodeAddress(QString address, uint8_t crrl)
|
|
{
|
|
int len;
|
|
int i;
|
|
QByteArray encodedAddress;
|
|
QByteArray b;
|
|
uint8_t ssid = 0;
|
|
bool hyphenSeen = false;
|
|
|
|
len = address.length();
|
|
b = address.toUtf8();
|
|
ssid = 0;
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if ((i < len) && !hyphenSeen)
|
|
{
|
|
if (b[i] == '-')
|
|
{
|
|
AX25Packet::ssid(b, i, len, ssid);
|
|
hyphenSeen = true;
|
|
encodedAddress.append(' ' << 1);
|
|
}
|
|
else
|
|
{
|
|
encodedAddress.append(b[i] << 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
encodedAddress.append(' ' << 1);
|
|
}
|
|
}
|
|
if (b[i] == '-')
|
|
{
|
|
AX25Packet::ssid(b, i, len, ssid);
|
|
}
|
|
encodedAddress.append(crrl | (ssid << 1));
|
|
|
|
return encodedAddress;
|
|
}
|