Partial work supporting the latest M17 specification.

This commit is contained in:
Jonathan Naylor 2020-11-26 11:30:16 +00:00
parent 8d31808ae8
commit 67b93d6310
11 changed files with 78 additions and 30 deletions

View file

@ -172,6 +172,7 @@ m_nxdnRemoteGateway(false),
m_nxdnTXHang(5U),
m_nxdnModeHang(10U),
m_m17Enabled(false),
m_m17ColorCode(1U),
m_m17SelfOnly(false),
m_m17AllowEncryption(false),
m_m17TXHang(5U),
@ -739,6 +740,8 @@ bool CConf::read()
} else if (section == SECTION_M17) {
if (::strcmp(key, "Enable") == 0)
m_m17Enabled = ::atoi(value) == 1;
else if (::strcmp(key, "ColorCode") == 0)
m_m17ColorCode = (unsigned int)::atoi(value);
else if (::strcmp(key, "SelfOnly") == 0)
m_m17SelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "AllowEncryption") == 0)
@ -1603,6 +1606,11 @@ bool CConf::getM17Enabled() const
return m_m17Enabled;
}
unsigned int CConf::getM17ColorCode() const
{
return m_m17ColorCode;
}
bool CConf::getM17SelfOnly() const
{
return m_m17SelfOnly;

2
Conf.h
View file

@ -163,6 +163,7 @@ public:
// The M17 section
bool getM17Enabled() const;
unsigned int getM17ColorCode() const;
bool getM17SelfOnly() const;
bool getM17AllowEncryption() const;
unsigned int getM17TXHang() const;
@ -469,6 +470,7 @@ private:
unsigned int m_nxdnModeHang;
bool m_m17Enabled;
unsigned int m_m17ColorCode;
bool m_m17SelfOnly;
bool m_m17AllowEncryption;
unsigned int m_m17TXHang;

View file

@ -57,8 +57,9 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CM17Control::CM17Control(const std::string& callsign, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) :
CM17Control::CM17Control(const std::string& callsign, unsigned int colorCode, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper) :
m_callsign(callsign),
m_colorCode(colorCode),
m_selfOnly(selfOnly),
m_allowEncryption(allowEncryption),
m_network(network),
@ -154,7 +155,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
decorrelator(data + 2U, temp);
interleaver(temp, data + 2U);
if (m_rfState == RS_RF_LISTENING) {
if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_HEADER) {
m_rfLICH.reset();
CM17Convolution conv;
@ -225,11 +226,11 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
writeFile(data + 2U);
#endif
if (m_duplex) {
data[0U] = TAG_DATA;
data[0U] = TAG_HEADER;
data[1U] = 0x00U;
// Generate the sync
CSync::addM17Sync(data + 2U);
CSync::addM17HeaderSync(data + 2U);
unsigned char setup[M17_LICH_LENGTH_BYTES];
m_rfLICH.getLinkSetup(setup);
@ -251,7 +252,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
}
}
if (m_rfState == RS_RF_LATE_ENTRY) {
if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA) {
CM17Convolution conv;
unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES];
conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame);
@ -323,11 +324,11 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
if (m_duplex) {
// Create a Link Setup frame
data[0U] = TAG_DATA;
data[0U] = TAG_HEADER;
data[1U] = 0x00U;
// Generate the sync
CSync::addM17Sync(data + 2U);
CSync::addM17HeaderSync(data + 2U);
unsigned char setup[M17_LICH_LENGTH_BYTES];
m_rfLICH.getLinkSetup(setup);
@ -348,7 +349,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
}
}
if (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) {
if ((m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) && data[0U] == TAG_DATA) {
#if defined(DUMP_M17)
writeFile(data + 2U);
#endif
@ -391,7 +392,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
rfData[1U] = 0x00U;
// Generate the sync
CSync::addM17Sync(rfData + 2U);
CSync::addM17DataSync(rfData + 2U);
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
m_netLICH.getFragment(lich, m_rfFN);
@ -460,7 +461,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
return true;
}
if (m_rfState == RS_RF_REJECTED) {
if (m_rfState == RS_RF_REJECTED && data[0U] == TAG_DATA) {
CM17Convolution conv;
unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES];
conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame);
@ -583,11 +584,11 @@ void CM17Control::writeNetwork()
// Create a dummy start message
unsigned char start[M17_FRAME_LENGTH_BYTES + 2U];
start[0U] = TAG_DATA;
start[0U] = TAG_HEADER;
start[1U] = 0x00U;
// Generate the sync
CSync::addM17Sync(start + 2U);
CSync::addM17HeaderSync(start + 2U);
unsigned char setup[M17_LICH_LENGTH_BYTES];
m_netLICH.getLinkSetup(setup);
@ -609,7 +610,7 @@ void CM17Control::writeNetwork()
data[1U] = 0x00U;
// Generate the sync
CSync::addM17Sync(data + 2U);
CSync::addM17DataSync(data + 2U);
m_netFrames++;

View file

@ -34,7 +34,7 @@
class CM17Control {
public:
CM17Control(const std::string& callsign, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper);
CM17Control(const std::string& callsign, unsigned int colorCode, bool selfOnly, bool allowEncryption, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper);
~CM17Control();
bool writeModem(unsigned char* data, unsigned int len);
@ -49,6 +49,7 @@ public:
private:
std::string m_callsign;
unsigned int m_colorCode;
bool m_selfOnly;
bool m_allowEncryption;
CM17Network* m_network;

View file

@ -24,7 +24,9 @@ const unsigned int M17_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int M17_FRAME_LENGTH_BITS = 384U;
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
const unsigned char M17_SYNC_BYTES[] = {0x32U, 0x43U};
const unsigned char M17_HEADER_SYNC_BYTES[] = {0x5DU, 0xDDU};
const unsigned char M17_DATA_SYNC_BYTES[] = {0xDDU, 0xDDU};
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;

View file

@ -133,6 +133,7 @@ TXHang=5
[M17]
Enable=1
ColorCode=3
SelfOnly=0
TXHang=5
# ModeHang=10

View file

@ -619,18 +619,20 @@ int CMMDVMHost::run()
}
if (m_m17Enabled) {
bool selfOnly = m_conf.getM17SelfOnly();
bool allowEncryption = m_conf.getM17AllowEncryption();
unsigned int txHang = m_conf.getM17TXHang();
m_m17RFModeHang = m_conf.getM17ModeHang();
bool selfOnly = m_conf.getM17SelfOnly();
unsigned int colorCode = m_conf.getM17ColorCode();
bool allowEncryption = m_conf.getM17AllowEncryption();
unsigned int txHang = m_conf.getM17TXHang();
m_m17RFModeHang = m_conf.getM17ModeHang();
LogInfo("M17 RF Parameters");
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" Color Code: %u", colorCode);
LogInfo(" Allow Encryption: %s", allowEncryption ? "yes" : "no");
LogInfo(" TX Hang: %us", txHang);
LogInfo(" Mode Hang: %us", m_m17RFModeHang);
m_m17 = new CM17Control(m_callsign, selfOnly, allowEncryption, m_m17Network, m_display, m_timeout, m_duplex, rssi);
m_m17 = new CM17Control(m_callsign, colorCode, selfOnly, allowEncryption, m_m17Network, m_display, m_timeout, m_duplex, rssi);
}
CTimer pocsagTimer(1000U, 30U);

View file

@ -79,8 +79,9 @@ const unsigned char MMDVM_P25_LOST = 0x32U;
const unsigned char MMDVM_NXDN_DATA = 0x40U;
const unsigned char MMDVM_NXDN_LOST = 0x41U;
const unsigned char MMDVM_M17_DATA = 0x45U;
const unsigned char MMDVM_M17_LOST = 0x46U;
const unsigned char MMDVM_M17_HEADER = 0x45U;
const unsigned char MMDVM_M17_DATA = 0x46U;
const unsigned char MMDVM_M17_LOST = 0x47U;
const unsigned char MMDVM_POCSAG_DATA = 0x50U;
@ -659,6 +660,20 @@ void CSerialModem::clock(unsigned int ms)
}
break;
case MMDVM_M17_HEADER: {
if (m_trace)
CUtils::dump(1U, "RX M17 Header", m_buffer, m_length);
unsigned char data = m_length - 2U;
m_rxM17Data.addData(&data, 1U);
data = TAG_HEADER;
m_rxM17Data.addData(&data, 1U);
m_rxM17Data.addData(m_buffer + 3U, m_length - 3U);
}
break;
case MMDVM_M17_DATA: {
if (m_trace)
CUtils::dump(1U, "RX M17 Data", m_buffer, m_length);
@ -1015,8 +1030,12 @@ void CSerialModem::clock(unsigned int ms)
m_txM17Data.getData(&len, 1U);
m_txM17Data.getData(m_buffer, len);
if (m_trace)
CUtils::dump(1U, "TX M17 Data", m_buffer, len);
if (m_trace) {
if (m_buffer[2U] == MMDVM_M17_HEADER)
CUtils::dump(1U, "TX M17 Header", m_buffer, len);
else
CUtils::dump(1U, "TX M17 Data", m_buffer, len);
}
int ret = m_serial->write(m_buffer, len);
if (ret != int(len))
@ -1471,14 +1490,18 @@ bool CSerialModem::writeM17Data(const unsigned char* data, unsigned int length)
assert(data != NULL);
assert(length > 0U);
if (data[0U] != TAG_DATA && data[0U] != TAG_EOT)
if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA && data[0U] != TAG_EOT)
return false;
unsigned char buffer[130U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = length + 2U;
buffer[2U] = MMDVM_M17_DATA;
if (data[0U] == TAG_HEADER)
buffer[2U] = MMDVM_M17_HEADER;
else
buffer[2U] = MMDVM_M17_DATA;
::memcpy(buffer + 3U, data + 1U, length - 1U);

View file

@ -85,9 +85,16 @@ void CSync::addNXDNSync(unsigned char* data)
data[i] = (data[i] & ~NXDN_FSW_BYTES_MASK[i]) | NXDN_FSW_BYTES[i];
}
void CSync::addM17Sync(unsigned char* data)
void CSync::addM17HeaderSync(unsigned char* data)
{
assert(data != NULL);
::memcpy(data, M17_SYNC_BYTES, M17_SYNC_LENGTH_BYTES);
::memcpy(data, M17_HEADER_SYNC_BYTES, M17_SYNC_LENGTH_BYTES);
}
void CSync::addM17DataSync(unsigned char* data)
{
assert(data != NULL);
::memcpy(data, M17_DATA_SYNC_BYTES, M17_SYNC_LENGTH_BYTES);
}

3
Sync.h
View file

@ -33,7 +33,8 @@ public:
static void addNXDNSync(unsigned char* data);
static void addM17Sync(unsigned char* data);
static void addM17HeaderSync(unsigned char* data);
static void addM17DataSync(unsigned char* data);
private:
};

View file

@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201116";
const char* VERSION = "20201126";
#endif