sdrangel/sdrbase/util/ax25.cpp

221 wiersze
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;
}