|
|
|
|
@ -12,7 +12,7 @@
|
|
|
|
|
* Copyright (C) 2016 Colin Durbridge, G4EML
|
|
|
|
|
* Copyright (C) 2016,2017,2018,2019 Andy Uribe, CA6JAU
|
|
|
|
|
* Copyright (C) 2019 Florian Wolters, DF2ET
|
|
|
|
|
* Copyright (C) 2017-2022 Bryan Biedenkapp, N2PLL
|
|
|
|
|
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
#include "Globals.h"
|
|
|
|
|
@ -25,7 +25,7 @@
|
|
|
|
|
#define concat(a, b, c) a " (build " b " " c ")"
|
|
|
|
|
const char HARDWARE[] = concat(DESCRIPTION, __TIME__, __DATE__);
|
|
|
|
|
|
|
|
|
|
const uint8_t PROTOCOL_VERSION = 3U;
|
|
|
|
|
const uint8_t PROTOCOL_VERSION = 4U;
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Public Class Members
|
|
|
|
|
@ -38,6 +38,7 @@ SerialPort::SerialPort() :
|
|
|
|
|
m_buffer(),
|
|
|
|
|
m_ptr(0U),
|
|
|
|
|
m_len(0U),
|
|
|
|
|
m_dblFrame(false),
|
|
|
|
|
m_debug(false)
|
|
|
|
|
{
|
|
|
|
|
// stub
|
|
|
|
|
@ -60,11 +61,19 @@ void SerialPort::process()
|
|
|
|
|
uint8_t c = readInt(1U);
|
|
|
|
|
|
|
|
|
|
if (m_ptr == 0U) {
|
|
|
|
|
if (c == DVM_FRAME_START) {
|
|
|
|
|
if (c == DVM_SHORT_FRAME_START) {
|
|
|
|
|
// Handle the frame start correctly
|
|
|
|
|
m_buffer[0U] = c;
|
|
|
|
|
m_ptr = 1U;
|
|
|
|
|
m_len = 0U;
|
|
|
|
|
m_dblFrame = false;
|
|
|
|
|
}
|
|
|
|
|
else if (c == DVM_LONG_FRAME_START) {
|
|
|
|
|
// Handle the frame start correctly
|
|
|
|
|
m_buffer[0U] = c;
|
|
|
|
|
m_ptr = 1U;
|
|
|
|
|
m_len = 0U;
|
|
|
|
|
m_dblFrame = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
m_ptr = 0U;
|
|
|
|
|
@ -76,6 +85,11 @@ void SerialPort::process()
|
|
|
|
|
m_len = m_buffer[m_ptr] = c;
|
|
|
|
|
m_ptr = 2U;
|
|
|
|
|
}
|
|
|
|
|
else if (m_ptr == 2U && m_dblFrame) {
|
|
|
|
|
// Handle the frame length
|
|
|
|
|
m_len = m_buffer[m_ptr] = (c + 255U);
|
|
|
|
|
m_ptr = 3U;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Any other bytes are added to the buffer
|
|
|
|
|
m_buffer[m_ptr] = c;
|
|
|
|
|
@ -377,6 +391,7 @@ void SerialPort::process()
|
|
|
|
|
|
|
|
|
|
m_ptr = 0U;
|
|
|
|
|
m_len = 0U;
|
|
|
|
|
m_dblFrame = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -384,6 +399,7 @@ void SerialPort::process()
|
|
|
|
|
if (io.getWatchdog() >= 48000U) {
|
|
|
|
|
m_ptr = 0U;
|
|
|
|
|
m_len = 0U;
|
|
|
|
|
m_dblFrame = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -444,19 +460,22 @@ void SerialPort::writeDMRData(bool slot, const uint8_t* data, uint8_t length)
|
|
|
|
|
if (!m_dmrEnable)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (length + 3U > 40U) {
|
|
|
|
|
m_buffer[2U] = slot ? CMD_DMR_DATA2 : CMD_DMR_DATA1;
|
|
|
|
|
sendNAK(RSN_ILLEGAL_LENGTH);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t reply[40U];
|
|
|
|
|
::memset(reply, 0x00U, 40U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = length + 3U;
|
|
|
|
|
reply[2U] = slot ? CMD_DMR_DATA2 : CMD_DMR_DATA1;
|
|
|
|
|
|
|
|
|
|
uint8_t count = 3U;
|
|
|
|
|
for (uint8_t i = 0U; i < length; i++, count++)
|
|
|
|
|
reply[count] = data[i];
|
|
|
|
|
|
|
|
|
|
reply[1U] = count;
|
|
|
|
|
::memcpy(reply + 3U, data, length);
|
|
|
|
|
|
|
|
|
|
writeInt(1U, reply, count);
|
|
|
|
|
writeInt(1U, reply, length + 3U);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
@ -473,7 +492,7 @@ void SerialPort::writeDMRLost(bool slot)
|
|
|
|
|
|
|
|
|
|
uint8_t reply[3U];
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 3U;
|
|
|
|
|
reply[2U] = slot ? CMD_DMR_LOST2 : CMD_DMR_LOST1;
|
|
|
|
|
|
|
|
|
|
@ -485,7 +504,7 @@ void SerialPort::writeDMRLost(bool slot)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <param name="length"></param>
|
|
|
|
|
void SerialPort::writeP25Data(const uint8_t* data, uint8_t length)
|
|
|
|
|
void SerialPort::writeP25Data(const uint8_t* data, uint16_t length)
|
|
|
|
|
{
|
|
|
|
|
if (m_modemState != STATE_P25 && m_modemState != STATE_IDLE)
|
|
|
|
|
return;
|
|
|
|
|
@ -493,19 +512,32 @@ void SerialPort::writeP25Data(const uint8_t* data, uint8_t length)
|
|
|
|
|
if (!m_p25Enable)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[250U];
|
|
|
|
|
if (length + 4U > 520U) {
|
|
|
|
|
m_buffer[2U] = CMD_P25_DATA;
|
|
|
|
|
sendNAK(RSN_ILLEGAL_LENGTH);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_P25_DATA;
|
|
|
|
|
uint8_t reply[520U];
|
|
|
|
|
::memset(reply, 0x00U, 520U);
|
|
|
|
|
|
|
|
|
|
uint8_t count = 3U;
|
|
|
|
|
for (uint8_t i = 0U; i < length; i++, count++)
|
|
|
|
|
reply[count] = data[i];
|
|
|
|
|
if (length < 252U) {
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = length + 3U;
|
|
|
|
|
reply[2U] = CMD_P25_DATA;
|
|
|
|
|
::memcpy(reply + 3U, data, length);
|
|
|
|
|
|
|
|
|
|
reply[1U] = count;
|
|
|
|
|
writeInt(1U, reply, length + 3U);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
reply[0U] = DVM_LONG_FRAME_START;
|
|
|
|
|
reply[1U] = (length >> 8U) & 0xFFU;
|
|
|
|
|
reply[2U] = (length & 0xFFU);
|
|
|
|
|
reply[3U] = CMD_P25_DATA;
|
|
|
|
|
::memcpy(reply + 4U, data, length);
|
|
|
|
|
|
|
|
|
|
writeInt(1U, reply, count);
|
|
|
|
|
writeInt(1U, reply, length + 4U);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
@ -521,7 +553,7 @@ void SerialPort::writeP25Lost()
|
|
|
|
|
|
|
|
|
|
uint8_t reply[3U];
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 3U;
|
|
|
|
|
reply[2U] = CMD_P25_LOST;
|
|
|
|
|
|
|
|
|
|
@ -541,19 +573,22 @@ void SerialPort::writeNXDNData(const uint8_t* data, uint8_t length)
|
|
|
|
|
if (!m_nxdnEnable)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (length + 3U > 130U) {
|
|
|
|
|
m_buffer[2U] = CMD_NXDN_DATA;
|
|
|
|
|
sendNAK(RSN_ILLEGAL_LENGTH);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = length + 3U;
|
|
|
|
|
reply[2U] = CMD_NXDN_DATA;
|
|
|
|
|
|
|
|
|
|
uint8_t count = 3U;
|
|
|
|
|
for (uint8_t i = 0U; i < length; i++, count++)
|
|
|
|
|
reply[count] = data[i];
|
|
|
|
|
|
|
|
|
|
reply[1U] = count;
|
|
|
|
|
::memcpy(reply + 3U, data, length);
|
|
|
|
|
|
|
|
|
|
writeInt(1U, reply, count);
|
|
|
|
|
writeInt(1U, reply, length + 3U);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
@ -569,7 +604,7 @@ void SerialPort::writeNXDNLost()
|
|
|
|
|
|
|
|
|
|
uint8_t reply[3U];
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 3U;
|
|
|
|
|
reply[2U] = CMD_NXDN_LOST;
|
|
|
|
|
|
|
|
|
|
@ -583,19 +618,22 @@ void SerialPort::writeNXDNLost()
|
|
|
|
|
/// <param name="length"></param>
|
|
|
|
|
void SerialPort::writeCalData(const uint8_t* data, uint8_t length)
|
|
|
|
|
{
|
|
|
|
|
if (length + 3U > 130U) {
|
|
|
|
|
m_buffer[2U] = CMD_CAL_DATA;
|
|
|
|
|
sendNAK(RSN_ILLEGAL_LENGTH);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = length + 3U;
|
|
|
|
|
reply[2U] = CMD_CAL_DATA;
|
|
|
|
|
|
|
|
|
|
uint8_t count = 3U;
|
|
|
|
|
for (uint8_t i = 0U; i < length; i++, count++)
|
|
|
|
|
reply[count] = data[i];
|
|
|
|
|
|
|
|
|
|
reply[1U] = count;
|
|
|
|
|
::memcpy(reply + 3U, data, length);
|
|
|
|
|
|
|
|
|
|
writeInt(1U, reply, count);
|
|
|
|
|
writeInt(1U, reply, length + 3U);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
@ -608,19 +646,22 @@ void SerialPort::writeRSSIData(const uint8_t* data, uint8_t length)
|
|
|
|
|
if (m_modemState != STATE_RSSI_CAL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (length + 3U > 30U) {
|
|
|
|
|
m_buffer[2U] = CMD_RSSI_DATA;
|
|
|
|
|
sendNAK(RSN_ILLEGAL_LENGTH);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t reply[30U];
|
|
|
|
|
::memset(reply, 0x00U, 30U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = length + 3U;
|
|
|
|
|
reply[2U] = CMD_RSSI_DATA;
|
|
|
|
|
|
|
|
|
|
uint8_t count = 3U;
|
|
|
|
|
for (uint8_t i = 0U; i < length; i++, count++)
|
|
|
|
|
reply[count] = data[i];
|
|
|
|
|
|
|
|
|
|
reply[1U] = count;
|
|
|
|
|
::memcpy(reply + 3U, data, length);
|
|
|
|
|
|
|
|
|
|
writeInt(1U, reply, count);
|
|
|
|
|
writeInt(1U, reply, length + 3U);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
@ -633,8 +674,9 @@ void SerialPort::writeDebug(const char* text)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_DEBUG1;
|
|
|
|
|
|
|
|
|
|
@ -658,8 +700,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_DEBUG2;
|
|
|
|
|
|
|
|
|
|
@ -687,8 +730,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1, int16_t n2)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_DEBUG3;
|
|
|
|
|
|
|
|
|
|
@ -720,8 +764,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_DEBUG4;
|
|
|
|
|
|
|
|
|
|
@ -757,8 +802,9 @@ void SerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[130U];
|
|
|
|
|
::memset(reply, 0x00U, 130U);
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_DEBUG5;
|
|
|
|
|
|
|
|
|
|
@ -793,13 +839,19 @@ void SerialPort::writeDump(const uint8_t* data, uint16_t length)
|
|
|
|
|
if (!m_debug)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
uint8_t reply[512U];
|
|
|
|
|
if (length + 4U > 516U) {
|
|
|
|
|
m_buffer[2U] = CMD_DEBUG_DUMP;
|
|
|
|
|
sendNAK(RSN_ILLEGAL_LENGTH);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
uint8_t reply[516U];
|
|
|
|
|
::memset(reply, 0x00U, 516U);
|
|
|
|
|
|
|
|
|
|
if (length > 252U) {
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = (length + 4U) - 255U;
|
|
|
|
|
reply[0U] = DVM_LONG_FRAME_START;
|
|
|
|
|
reply[1U] = (length >> 8U) & 0xFFU;
|
|
|
|
|
reply[2U] = (length & 0xFFU);
|
|
|
|
|
reply[3U] = CMD_DEBUG_DUMP;
|
|
|
|
|
|
|
|
|
|
for (uint8_t i = 0U; i < length; i++)
|
|
|
|
|
@ -808,6 +860,7 @@ void SerialPort::writeDump(const uint8_t* data, uint16_t length)
|
|
|
|
|
writeInt(1U, reply, length + 4U);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = length + 3U;
|
|
|
|
|
reply[2U] = CMD_DEBUG_DUMP;
|
|
|
|
|
|
|
|
|
|
@ -829,7 +882,7 @@ void SerialPort::sendACK()
|
|
|
|
|
{
|
|
|
|
|
uint8_t reply[4U];
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 4U;
|
|
|
|
|
reply[2U] = CMD_ACK;
|
|
|
|
|
reply[3U] = m_buffer[2U];
|
|
|
|
|
@ -845,7 +898,7 @@ void SerialPort::sendNAK(uint8_t err)
|
|
|
|
|
{
|
|
|
|
|
uint8_t reply[5U];
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 5U;
|
|
|
|
|
reply[2U] = CMD_NAK;
|
|
|
|
|
reply[3U] = m_buffer[2U];
|
|
|
|
|
@ -864,7 +917,7 @@ void SerialPort::getStatus()
|
|
|
|
|
uint8_t reply[15U];
|
|
|
|
|
|
|
|
|
|
// send all sorts of interesting internal values
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 12U;
|
|
|
|
|
reply[2U] = CMD_GET_STATUS;
|
|
|
|
|
|
|
|
|
|
@ -930,7 +983,7 @@ void SerialPort::getVersion()
|
|
|
|
|
{
|
|
|
|
|
uint8_t reply[200U];
|
|
|
|
|
|
|
|
|
|
reply[0U] = DVM_FRAME_START;
|
|
|
|
|
reply[0U] = DVM_SHORT_FRAME_START;
|
|
|
|
|
reply[1U] = 0U;
|
|
|
|
|
reply[2U] = CMD_GET_VERSION;
|
|
|
|
|
|
|
|
|
|
|