Merge branch 'M17_AX25_FM' into I2C
This commit is contained in:
commit
0d6387dde2
13 changed files with 164 additions and 158 deletions
8
Conf.cpp
8
Conf.cpp
|
@ -172,6 +172,7 @@ m_nxdnRemoteGateway(false),
|
||||||
m_nxdnTXHang(5U),
|
m_nxdnTXHang(5U),
|
||||||
m_nxdnModeHang(10U),
|
m_nxdnModeHang(10U),
|
||||||
m_m17Enabled(false),
|
m_m17Enabled(false),
|
||||||
|
m_m17ColorCode(1U),
|
||||||
m_m17SelfOnly(false),
|
m_m17SelfOnly(false),
|
||||||
m_m17AllowEncryption(false),
|
m_m17AllowEncryption(false),
|
||||||
m_m17TXHang(5U),
|
m_m17TXHang(5U),
|
||||||
|
@ -740,6 +741,8 @@ bool CConf::read()
|
||||||
} else if (section == SECTION_M17) {
|
} else if (section == SECTION_M17) {
|
||||||
if (::strcmp(key, "Enable") == 0)
|
if (::strcmp(key, "Enable") == 0)
|
||||||
m_m17Enabled = ::atoi(value) == 1;
|
m_m17Enabled = ::atoi(value) == 1;
|
||||||
|
else if (::strcmp(key, "ColorCode") == 0)
|
||||||
|
m_m17ColorCode = (unsigned int)::atoi(value);
|
||||||
else if (::strcmp(key, "SelfOnly") == 0)
|
else if (::strcmp(key, "SelfOnly") == 0)
|
||||||
m_m17SelfOnly = ::atoi(value) == 1;
|
m_m17SelfOnly = ::atoi(value) == 1;
|
||||||
else if (::strcmp(key, "AllowEncryption") == 0)
|
else if (::strcmp(key, "AllowEncryption") == 0)
|
||||||
|
@ -1606,6 +1609,11 @@ bool CConf::getM17Enabled() const
|
||||||
return m_m17Enabled;
|
return m_m17Enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getM17ColorCode() const
|
||||||
|
{
|
||||||
|
return m_m17ColorCode;
|
||||||
|
}
|
||||||
|
|
||||||
bool CConf::getM17SelfOnly() const
|
bool CConf::getM17SelfOnly() const
|
||||||
{
|
{
|
||||||
return m_m17SelfOnly;
|
return m_m17SelfOnly;
|
||||||
|
|
2
Conf.h
2
Conf.h
|
@ -163,6 +163,7 @@ public:
|
||||||
|
|
||||||
// The M17 section
|
// The M17 section
|
||||||
bool getM17Enabled() const;
|
bool getM17Enabled() const;
|
||||||
|
unsigned int getM17ColorCode() const;
|
||||||
bool getM17SelfOnly() const;
|
bool getM17SelfOnly() const;
|
||||||
bool getM17AllowEncryption() const;
|
bool getM17AllowEncryption() const;
|
||||||
unsigned int getM17TXHang() const;
|
unsigned int getM17TXHang() const;
|
||||||
|
@ -470,6 +471,7 @@ private:
|
||||||
unsigned int m_nxdnModeHang;
|
unsigned int m_nxdnModeHang;
|
||||||
|
|
||||||
bool m_m17Enabled;
|
bool m_m17Enabled;
|
||||||
|
unsigned int m_m17ColorCode;
|
||||||
bool m_m17SelfOnly;
|
bool m_m17SelfOnly;
|
||||||
bool m_m17AllowEncryption;
|
bool m_m17AllowEncryption;
|
||||||
unsigned int m_m17TXHang;
|
unsigned int m_m17TXHang;
|
||||||
|
|
225
M17Control.cpp
225
M17Control.cpp
|
@ -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 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])
|
#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_callsign(callsign),
|
||||||
|
m_colorCode(colorCode),
|
||||||
m_selfOnly(selfOnly),
|
m_selfOnly(selfOnly),
|
||||||
m_allowEncryption(allowEncryption),
|
m_allowEncryption(allowEncryption),
|
||||||
m_network(network),
|
m_network(network),
|
||||||
|
@ -78,7 +79,9 @@ m_rfFN(0U),
|
||||||
m_rfErrs(0U),
|
m_rfErrs(0U),
|
||||||
m_rfBits(1U),
|
m_rfBits(1U),
|
||||||
m_rfLICH(),
|
m_rfLICH(),
|
||||||
|
m_rfLICHn(0U),
|
||||||
m_netLICH(),
|
m_netLICH(),
|
||||||
|
m_netLICHn(0U),
|
||||||
m_rssiMapper(rssiMapper),
|
m_rssiMapper(rssiMapper),
|
||||||
m_rssi(0U),
|
m_rssi(0U),
|
||||||
m_maxRSSI(0U),
|
m_maxRSSI(0U),
|
||||||
|
@ -154,7 +157,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
decorrelator(data + 2U, temp);
|
decorrelator(data + 2U, temp);
|
||||||
interleaver(temp, data + 2U);
|
interleaver(temp, data + 2U);
|
||||||
|
|
||||||
if (m_rfState == RS_RF_LISTENING) {
|
if (m_rfState == RS_RF_LISTENING && data[0U] == TAG_HEADER) {
|
||||||
m_rfLICH.reset();
|
m_rfLICH.reset();
|
||||||
|
|
||||||
CM17Convolution conv;
|
CM17Convolution conv;
|
||||||
|
@ -171,13 +174,61 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
m_maxRSSI = m_rssi;
|
m_maxRSSI = m_rssi;
|
||||||
m_aveRSSI = m_rssi;
|
m_aveRSSI = m_rssi;
|
||||||
m_rssiCount = 1U;
|
m_rssiCount = 1U;
|
||||||
m_rfFN = 0U;
|
m_rfLICHn = 0U;
|
||||||
|
m_rfFN = 0U;
|
||||||
|
|
||||||
#if defined(DUMP_M17)
|
#if defined(DUMP_M17)
|
||||||
openFile();
|
openFile();
|
||||||
#endif
|
#endif
|
||||||
m_rfLICH.setLinkSetup(frame);
|
m_rfLICH.setLinkSetup(frame);
|
||||||
|
|
||||||
|
m_rfState = RS_RF_LATE_ENTRY;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m_rfState = RS_RF_LATE_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rfState == RS_RF_LATE_ENTRY && data[0U] == TAG_DATA) {
|
||||||
|
unsigned int frag1, frag2, frag3, frag4;
|
||||||
|
CM17Utils::splitFragmentLICHFEC(data + 2U + M17_SYNC_LENGTH_BYTES, frag1, frag2, frag3, frag4);
|
||||||
|
|
||||||
|
unsigned int lich1 = CGolay24128::decode24128(frag1);
|
||||||
|
unsigned int lich2 = CGolay24128::decode24128(frag2);
|
||||||
|
unsigned int lich3 = CGolay24128::decode24128(frag3);
|
||||||
|
unsigned int lich4 = CGolay24128::decode24128(frag4);
|
||||||
|
|
||||||
|
unsigned int colorCode = (lich4 >> 7) & 0x1FU;
|
||||||
|
if (colorCode != m_colorCode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool lateEntry = false;
|
||||||
|
if (!m_rfLICH.isValid()) {
|
||||||
|
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
|
||||||
|
CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich);
|
||||||
|
|
||||||
|
unsigned int n = (lich4 >> 4) & 0x07U;
|
||||||
|
m_rfLICH.setFragment(lich, n);
|
||||||
|
|
||||||
|
lateEntry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid = m_rfLICH.isValid();
|
||||||
|
if (valid) {
|
||||||
|
m_rfFrames = 0U;
|
||||||
|
m_rfErrs = 0U;
|
||||||
|
m_rfBits = 1U;
|
||||||
|
m_rfTimeoutTimer.start();
|
||||||
|
m_minRSSI = m_rssi;
|
||||||
|
m_maxRSSI = m_rssi;
|
||||||
|
m_aveRSSI = m_rssi;
|
||||||
|
m_rssiCount = 1U;
|
||||||
|
m_rfLICHn = 0U;
|
||||||
|
|
||||||
|
#if defined(DUMP_M17)
|
||||||
|
openFile();
|
||||||
|
#endif
|
||||||
std::string source = m_rfLICH.getSource();
|
std::string source = m_rfLICH.getSource();
|
||||||
std::string dest = m_rfLICH.getDest();
|
std::string dest = m_rfLICH.getDest();
|
||||||
|
|
||||||
|
@ -190,47 +241,36 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_allowEncryption) {
|
|
||||||
bool ret = m_rfLICH.isNONCENull();
|
|
||||||
if (!ret) {
|
|
||||||
LogMessage("M17, invalid access attempt from %s to %s", source.c_str(), dest.c_str());
|
|
||||||
m_rfState = RS_RF_REJECTED;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char dataType = m_rfLICH.getDataType();
|
unsigned char dataType = m_rfLICH.getDataType();
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case 1U:
|
case 1U:
|
||||||
LogMessage("M17, received RF data transmission from %s to %s", source.c_str(), dest.c_str());
|
LogMessage("M17, received RF %s data transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str());
|
||||||
m_rfState = RS_RF_DATA;
|
m_rfState = RS_RF_DATA;
|
||||||
break;
|
break;
|
||||||
case 2U:
|
case 2U:
|
||||||
LogMessage("M17, received RF voice transmission from %s to %s", source.c_str(), dest.c_str());
|
LogMessage("M17, received RF %s voice transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str());
|
||||||
m_rfState = RS_RF_AUDIO;
|
m_rfState = RS_RF_AUDIO;
|
||||||
break;
|
break;
|
||||||
case 3U:
|
case 3U:
|
||||||
LogMessage("M17, received RF voice + data transmission from %s to %s", source.c_str(), dest.c_str());
|
LogMessage("M17, received RF %s voice + data transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str());
|
||||||
m_rfState = RS_RF_AUDIO;
|
m_rfState = RS_RF_AUDIO;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogMessage("M17, received RF unknown transmission from %s to %s", source.c_str(), dest.c_str());
|
LogMessage("M17, received RF %s unknown transmission from %s to %s", lateEntry ? "late entry" : "", source.c_str(), dest.c_str());
|
||||||
m_rfState = RS_RF_DATA;
|
m_rfState = RS_RF_DATA;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_display->writeM17(source.c_str(), dest.c_str(), "R");
|
m_display->writeM17(source.c_str(), dest.c_str(), "R");
|
||||||
|
|
||||||
#if defined(DUMP_M17)
|
|
||||||
writeFile(data + 2U);
|
|
||||||
#endif
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
data[0U] = TAG_DATA;
|
// Create a Link Setup frame
|
||||||
|
data[0U] = TAG_HEADER;
|
||||||
data[1U] = 0x00U;
|
data[1U] = 0x00U;
|
||||||
|
|
||||||
// Generate the sync
|
// Generate the sync
|
||||||
CSync::addM17Sync(data + 2U);
|
CSync::addM17HeaderSync(data + 2U);
|
||||||
|
|
||||||
unsigned char setup[M17_LICH_LENGTH_BYTES];
|
unsigned char setup[M17_LICH_LENGTH_BYTES];
|
||||||
m_rfLICH.getLinkSetup(setup);
|
m_rfLICH.getLinkSetup(setup);
|
||||||
|
|
||||||
|
@ -245,110 +285,11 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
writeQueueRF(data);
|
writeQueueRF(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// Fall through to the next section
|
||||||
} else {
|
|
||||||
m_rfState = RS_RF_LATE_ENTRY;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_rfState == RS_RF_LATE_ENTRY) {
|
if ((m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) && 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);
|
|
||||||
|
|
||||||
bool valid = CM17CRC::checkCRC(frame, M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES);
|
|
||||||
if (valid) {
|
|
||||||
m_rfFN = (frame[0U] << 8) + (frame[1U] << 0);
|
|
||||||
|
|
||||||
unsigned int frag1, frag2, frag3, frag4;
|
|
||||||
CM17Utils::splitFragmentLICHFEC(data + 2U + M17_SYNC_LENGTH_BYTES, frag1, frag2, frag3, frag4);
|
|
||||||
|
|
||||||
unsigned int lich1 = CGolay24128::decode24128(frag1);
|
|
||||||
unsigned int lich2 = CGolay24128::decode24128(frag2);
|
|
||||||
unsigned int lich3 = CGolay24128::decode24128(frag3);
|
|
||||||
unsigned int lich4 = CGolay24128::decode24128(frag4);
|
|
||||||
|
|
||||||
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
|
|
||||||
CM17Utils::combineFragmentLICH(lich1, lich2, lich3, lich4, lich);
|
|
||||||
|
|
||||||
m_rfLICH.setFragment(lich, m_rfFN);
|
|
||||||
|
|
||||||
valid = m_rfLICH.isValid();
|
|
||||||
if (valid) {
|
|
||||||
m_rfFrames = 0U;
|
|
||||||
m_rfErrs = 0U;
|
|
||||||
m_rfBits = 1U;
|
|
||||||
m_rfTimeoutTimer.start();
|
|
||||||
m_minRSSI = m_rssi;
|
|
||||||
m_maxRSSI = m_rssi;
|
|
||||||
m_aveRSSI = m_rssi;
|
|
||||||
m_rssiCount = 1U;
|
|
||||||
|
|
||||||
#if defined(DUMP_M17)
|
|
||||||
openFile();
|
|
||||||
#endif
|
|
||||||
std::string source = m_rfLICH.getSource();
|
|
||||||
std::string dest = m_rfLICH.getDest();
|
|
||||||
|
|
||||||
if (m_selfOnly) {
|
|
||||||
bool ret = checkCallsign(source);
|
|
||||||
if (!ret) {
|
|
||||||
LogMessage("M17, invalid access attempt from %s to %s", source.c_str(), dest.c_str());
|
|
||||||
m_rfState = RS_RF_REJECTED;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char dataType = m_rfLICH.getDataType();
|
|
||||||
switch (dataType) {
|
|
||||||
case 1U:
|
|
||||||
LogMessage("M17, received RF late entry data transmission from %s to %s", source.c_str(), dest.c_str());
|
|
||||||
m_rfState = RS_RF_DATA;
|
|
||||||
break;
|
|
||||||
case 2U:
|
|
||||||
LogMessage("M17, received RF late entry voice transmission from %s to %s", source.c_str(), dest.c_str());
|
|
||||||
m_rfState = RS_RF_AUDIO;
|
|
||||||
break;
|
|
||||||
case 3U:
|
|
||||||
LogMessage("M17, received RF late entry voice + data transmission from %s to %s", source.c_str(), dest.c_str());
|
|
||||||
m_rfState = RS_RF_AUDIO;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogMessage("M17, received RF late entry unknown transmission from %s to %s", source.c_str(), dest.c_str());
|
|
||||||
m_rfState = RS_RF_DATA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_display->writeM17(source.c_str(), dest.c_str(), "R");
|
|
||||||
|
|
||||||
if (m_duplex) {
|
|
||||||
// Create a Link Setup frame
|
|
||||||
data[0U] = TAG_DATA;
|
|
||||||
data[1U] = 0x00U;
|
|
||||||
|
|
||||||
// Generate the sync
|
|
||||||
CSync::addM17Sync(data + 2U);
|
|
||||||
|
|
||||||
unsigned char setup[M17_LICH_LENGTH_BYTES];
|
|
||||||
m_rfLICH.getLinkSetup(setup);
|
|
||||||
|
|
||||||
// Add the convolution FEC
|
|
||||||
CM17Convolution conv;
|
|
||||||
conv.encodeLinkSetup(setup, data + 2U + M17_SYNC_LENGTH_BYTES);
|
|
||||||
|
|
||||||
unsigned char temp[M17_FRAME_LENGTH_BYTES];
|
|
||||||
interleaver(data + 2U, temp);
|
|
||||||
decorrelator(temp, data + 2U);
|
|
||||||
|
|
||||||
writeQueueRF(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall through to the next section
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_rfState == RS_RF_AUDIO || m_rfState == RS_RF_DATA) {
|
|
||||||
#if defined(DUMP_M17)
|
#if defined(DUMP_M17)
|
||||||
writeFile(data + 2U);
|
writeFile(data + 2U);
|
||||||
#endif
|
#endif
|
||||||
|
@ -391,14 +332,18 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
rfData[1U] = 0x00U;
|
rfData[1U] = 0x00U;
|
||||||
|
|
||||||
// Generate the sync
|
// Generate the sync
|
||||||
CSync::addM17Sync(rfData + 2U);
|
CSync::addM17DataSync(rfData + 2U);
|
||||||
|
|
||||||
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
|
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
|
||||||
m_netLICH.getFragment(lich, m_rfFN);
|
m_netLICH.getFragment(lich, m_rfLICHn);
|
||||||
|
|
||||||
unsigned int frag1, frag2, frag3, frag4;
|
unsigned int frag1, frag2, frag3, frag4;
|
||||||
CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4);
|
CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4);
|
||||||
|
|
||||||
|
// Add the Color Code and fragment number
|
||||||
|
frag4 |= (m_rfLICHn & 0x07U) << 4;
|
||||||
|
frag4 |= (m_colorCode & 0x1FU) << 7;
|
||||||
|
|
||||||
// Add Golay to the LICH fragment here
|
// Add Golay to the LICH fragment here
|
||||||
unsigned int lich1 = CGolay24128::encode24128(frag1);
|
unsigned int lich1 = CGolay24128::encode24128(frag1);
|
||||||
unsigned int lich2 = CGolay24128::encode24128(frag2);
|
unsigned int lich2 = CGolay24128::encode24128(frag2);
|
||||||
|
@ -445,6 +390,10 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
|
|
||||||
m_rfFrames++;
|
m_rfFrames++;
|
||||||
|
|
||||||
|
m_rfLICHn++;
|
||||||
|
if (m_rfLICHn >= 6U)
|
||||||
|
m_rfLICHn = 0U;
|
||||||
|
|
||||||
// EOT?
|
// EOT?
|
||||||
if ((m_rfFN & 0x8000U) == 0x8000U) {
|
if ((m_rfFN & 0x8000U) == 0x8000U) {
|
||||||
std::string source = m_rfLICH.getSource();
|
std::string source = m_rfLICH.getSource();
|
||||||
|
@ -460,7 +409,7 @@ bool CM17Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_rfState == RS_RF_REJECTED) {
|
if (m_rfState == RS_RF_REJECTED && data[0U] == TAG_DATA) {
|
||||||
CM17Convolution conv;
|
CM17Convolution conv;
|
||||||
unsigned char frame[M17_FN_LENGTH_BYTES + M17_PAYLOAD_LENGTH_BYTES + M17_CRC_LENGTH_BYTES];
|
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);
|
conv.decodeData(data + 2U + M17_SYNC_LENGTH_BYTES + M17_LICH_FRAGMENT_FEC_LENGTH_BYTES, frame);
|
||||||
|
@ -500,6 +449,8 @@ void CM17Control::writeEndRF()
|
||||||
|
|
||||||
m_rfTimeoutTimer.stop();
|
m_rfTimeoutTimer.stop();
|
||||||
|
|
||||||
|
m_rfLICH.reset();
|
||||||
|
|
||||||
if (m_netState == RS_NET_IDLE) {
|
if (m_netState == RS_NET_IDLE) {
|
||||||
m_display->clearM17();
|
m_display->clearM17();
|
||||||
|
|
||||||
|
@ -520,6 +471,8 @@ void CM17Control::writeEndNet()
|
||||||
m_networkWatchdog.stop();
|
m_networkWatchdog.stop();
|
||||||
m_packetTimer.stop();
|
m_packetTimer.stop();
|
||||||
|
|
||||||
|
m_netLICH.reset();
|
||||||
|
|
||||||
m_display->clearM17();
|
m_display->clearM17();
|
||||||
|
|
||||||
if (m_network != NULL)
|
if (m_network != NULL)
|
||||||
|
@ -579,15 +532,16 @@ void CM17Control::writeNetwork()
|
||||||
m_packetTimer.start();
|
m_packetTimer.start();
|
||||||
m_elapsed.start();
|
m_elapsed.start();
|
||||||
m_netFrames = 0U;
|
m_netFrames = 0U;
|
||||||
|
m_netLICHn = 0U;
|
||||||
|
|
||||||
// Create a dummy start message
|
// Create a dummy start message
|
||||||
unsigned char start[M17_FRAME_LENGTH_BYTES + 2U];
|
unsigned char start[M17_FRAME_LENGTH_BYTES + 2U];
|
||||||
|
|
||||||
start[0U] = TAG_DATA;
|
start[0U] = TAG_HEADER;
|
||||||
start[1U] = 0x00U;
|
start[1U] = 0x00U;
|
||||||
|
|
||||||
// Generate the sync
|
// Generate the sync
|
||||||
CSync::addM17Sync(start + 2U);
|
CSync::addM17HeaderSync(start + 2U);
|
||||||
|
|
||||||
unsigned char setup[M17_LICH_LENGTH_BYTES];
|
unsigned char setup[M17_LICH_LENGTH_BYTES];
|
||||||
m_netLICH.getLinkSetup(setup);
|
m_netLICH.getLinkSetup(setup);
|
||||||
|
@ -609,19 +563,21 @@ void CM17Control::writeNetwork()
|
||||||
data[1U] = 0x00U;
|
data[1U] = 0x00U;
|
||||||
|
|
||||||
// Generate the sync
|
// Generate the sync
|
||||||
CSync::addM17Sync(data + 2U);
|
CSync::addM17DataSync(data + 2U);
|
||||||
|
|
||||||
m_netFrames++;
|
m_netFrames++;
|
||||||
|
|
||||||
// Add the fragment LICH
|
// Add the fragment LICH
|
||||||
uint16_t fn = (netData[28U] << 8) + (netData[29U] << 0);
|
|
||||||
|
|
||||||
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
|
unsigned char lich[M17_LICH_FRAGMENT_LENGTH_BYTES];
|
||||||
m_netLICH.getFragment(lich, fn);
|
m_netLICH.getFragment(lich, m_netLICHn);
|
||||||
|
|
||||||
unsigned int frag1, frag2, frag3, frag4;
|
unsigned int frag1, frag2, frag3, frag4;
|
||||||
CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4);
|
CM17Utils::splitFragmentLICH(lich, frag1, frag2, frag3, frag4);
|
||||||
|
|
||||||
|
// Add the Color Code and fragment number
|
||||||
|
frag4 |= (m_netLICHn & 0x07U) << 4;
|
||||||
|
frag4 |= (m_colorCode & 0x1FU) << 7;
|
||||||
|
|
||||||
// Add Golay to the LICH fragment here
|
// Add Golay to the LICH fragment here
|
||||||
unsigned int lich1 = CGolay24128::encode24128(frag1);
|
unsigned int lich1 = CGolay24128::encode24128(frag1);
|
||||||
unsigned int lich2 = CGolay24128::encode24128(frag2);
|
unsigned int lich2 = CGolay24128::encode24128(frag2);
|
||||||
|
@ -647,7 +603,12 @@ void CM17Control::writeNetwork()
|
||||||
|
|
||||||
writeQueueNet(data);
|
writeQueueNet(data);
|
||||||
|
|
||||||
|
m_netLICHn++;
|
||||||
|
if (m_netLICHn >= 6U)
|
||||||
|
m_netLICHn = 0U;
|
||||||
|
|
||||||
// EOT handling
|
// EOT handling
|
||||||
|
uint16_t fn = (netData[28U] << 8) + (netData[29U] << 0);
|
||||||
if ((fn & 0x8000U) == 0x8000U) {
|
if ((fn & 0x8000U) == 0x8000U) {
|
||||||
std::string source = m_netLICH.getSource();
|
std::string source = m_netLICH.getSource();
|
||||||
std::string dest = m_netLICH.getDest();
|
std::string dest = m_netLICH.getDest();
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
class CM17Control {
|
class CM17Control {
|
||||||
public:
|
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();
|
~CM17Control();
|
||||||
|
|
||||||
bool writeModem(unsigned char* data, unsigned int len);
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
@ -49,6 +49,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_callsign;
|
std::string m_callsign;
|
||||||
|
unsigned int m_colorCode;
|
||||||
bool m_selfOnly;
|
bool m_selfOnly;
|
||||||
bool m_allowEncryption;
|
bool m_allowEncryption;
|
||||||
CM17Network* m_network;
|
CM17Network* m_network;
|
||||||
|
@ -68,7 +69,9 @@ private:
|
||||||
unsigned int m_rfErrs;
|
unsigned int m_rfErrs;
|
||||||
unsigned int m_rfBits;
|
unsigned int m_rfBits;
|
||||||
CM17LICH m_rfLICH;
|
CM17LICH m_rfLICH;
|
||||||
|
unsigned int m_rfLICHn;
|
||||||
CM17LICH m_netLICH;
|
CM17LICH m_netLICH;
|
||||||
|
unsigned int m_netLICHn;
|
||||||
CRSSIInterpolator* m_rssiMapper;
|
CRSSIInterpolator* m_rssiMapper;
|
||||||
unsigned char m_rssi;
|
unsigned char m_rssi;
|
||||||
unsigned char m_maxRSSI;
|
unsigned char m_maxRSSI;
|
||||||
|
|
|
@ -24,14 +24,16 @@ 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_BITS = 384U;
|
||||||
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
|
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_BITS = 16U;
|
||||||
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;
|
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;
|
||||||
|
|
||||||
const unsigned int M17_LICH_LENGTH_BITS = 240U;
|
const unsigned int M17_LICH_LENGTH_BITS = 240U;
|
||||||
const unsigned int M17_LICH_LENGTH_BYTES = M17_LICH_LENGTH_BITS / 8U;
|
const unsigned int M17_LICH_LENGTH_BYTES = M17_LICH_LENGTH_BITS / 8U;
|
||||||
|
|
||||||
const unsigned int M17_LICH_FRAGMENT_LENGTH_BITS = M17_LICH_LENGTH_BITS / 5U;
|
const unsigned int M17_LICH_FRAGMENT_LENGTH_BITS = M17_LICH_LENGTH_BITS / 6U;
|
||||||
const unsigned int M17_LICH_FRAGMENT_LENGTH_BYTES = M17_LICH_FRAGMENT_LENGTH_BITS / 8U;
|
const unsigned int M17_LICH_FRAGMENT_LENGTH_BYTES = M17_LICH_FRAGMENT_LENGTH_BITS / 8U;
|
||||||
|
|
||||||
const unsigned int M17_LICH_FRAGMENT_FEC_LENGTH_BITS = M17_LICH_FRAGMENT_LENGTH_BITS * 2U;
|
const unsigned int M17_LICH_FRAGMENT_FEC_LENGTH_BITS = M17_LICH_FRAGMENT_LENGTH_BITS * 2U;
|
||||||
|
|
|
@ -124,23 +124,19 @@ void CM17LICH::setLinkSetup(const unsigned char* data)
|
||||||
m_valid = CM17CRC::checkCRC(m_lich, M17_LICH_LENGTH_BYTES);
|
m_valid = CM17CRC::checkCRC(m_lich, M17_LICH_LENGTH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CM17LICH::getFragment(unsigned char* data, unsigned short fn) const
|
void CM17LICH::getFragment(unsigned char* data, unsigned int n) const
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
CM17CRC::encodeCRC(m_lich, M17_LICH_LENGTH_BYTES);
|
CM17CRC::encodeCRC(m_lich, M17_LICH_LENGTH_BYTES);
|
||||||
|
|
||||||
unsigned int n = (fn & 0x7FFFU) % 5U;
|
|
||||||
|
|
||||||
::memcpy(data, m_lich + (n * M17_LICH_FRAGMENT_LENGTH_BYTES), M17_LICH_FRAGMENT_LENGTH_BYTES);
|
::memcpy(data, m_lich + (n * M17_LICH_FRAGMENT_LENGTH_BYTES), M17_LICH_FRAGMENT_LENGTH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CM17LICH::setFragment(const unsigned char* data, unsigned short fn)
|
void CM17LICH::setFragment(const unsigned char* data, unsigned int n)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
unsigned int n = (fn & 0x7FFFU) % 5U;
|
|
||||||
|
|
||||||
::memcpy(m_lich + (n * M17_LICH_FRAGMENT_LENGTH_BYTES), data, M17_LICH_FRAGMENT_LENGTH_BYTES);
|
::memcpy(m_lich + (n * M17_LICH_FRAGMENT_LENGTH_BYTES), data, M17_LICH_FRAGMENT_LENGTH_BYTES);
|
||||||
|
|
||||||
m_valid = CM17CRC::checkCRC(m_lich, M17_LICH_LENGTH_BYTES);
|
m_valid = CM17CRC::checkCRC(m_lich, M17_LICH_LENGTH_BYTES);
|
||||||
|
|
|
@ -46,8 +46,8 @@ public:
|
||||||
void getLinkSetup(unsigned char* data) const;
|
void getLinkSetup(unsigned char* data) const;
|
||||||
void setLinkSetup(const unsigned char* data);
|
void setLinkSetup(const unsigned char* data);
|
||||||
|
|
||||||
void getFragment(unsigned char* data, unsigned short fn) const;
|
void getFragment(unsigned char* data, unsigned int n) const;
|
||||||
void setFragment(const unsigned char* data, unsigned short fn);
|
void setFragment(const unsigned char* data, unsigned int n);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned char* m_lich;
|
unsigned char* m_lich;
|
||||||
|
|
|
@ -133,6 +133,7 @@ TXHang=5
|
||||||
|
|
||||||
[M17]
|
[M17]
|
||||||
Enable=1
|
Enable=1
|
||||||
|
ColorCode=3
|
||||||
SelfOnly=0
|
SelfOnly=0
|
||||||
TXHang=5
|
TXHang=5
|
||||||
# ModeHang=10
|
# ModeHang=10
|
||||||
|
|
|
@ -619,18 +619,20 @@ int CMMDVMHost::run()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_m17Enabled) {
|
if (m_m17Enabled) {
|
||||||
bool selfOnly = m_conf.getM17SelfOnly();
|
bool selfOnly = m_conf.getM17SelfOnly();
|
||||||
bool allowEncryption = m_conf.getM17AllowEncryption();
|
unsigned int colorCode = m_conf.getM17ColorCode();
|
||||||
unsigned int txHang = m_conf.getM17TXHang();
|
bool allowEncryption = m_conf.getM17AllowEncryption();
|
||||||
m_m17RFModeHang = m_conf.getM17ModeHang();
|
unsigned int txHang = m_conf.getM17TXHang();
|
||||||
|
m_m17RFModeHang = m_conf.getM17ModeHang();
|
||||||
|
|
||||||
LogInfo("M17 RF Parameters");
|
LogInfo("M17 RF Parameters");
|
||||||
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
|
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
|
||||||
|
LogInfo(" Color Code: %u", colorCode);
|
||||||
LogInfo(" Allow Encryption: %s", allowEncryption ? "yes" : "no");
|
LogInfo(" Allow Encryption: %s", allowEncryption ? "yes" : "no");
|
||||||
LogInfo(" TX Hang: %us", txHang);
|
LogInfo(" TX Hang: %us", txHang);
|
||||||
LogInfo(" Mode Hang: %us", m_m17RFModeHang);
|
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);
|
CTimer pocsagTimer(1000U, 30U);
|
||||||
|
|
|
@ -79,8 +79,9 @@ const unsigned char MMDVM_P25_LOST = 0x32U;
|
||||||
const unsigned char MMDVM_NXDN_DATA = 0x40U;
|
const unsigned char MMDVM_NXDN_DATA = 0x40U;
|
||||||
const unsigned char MMDVM_NXDN_LOST = 0x41U;
|
const unsigned char MMDVM_NXDN_LOST = 0x41U;
|
||||||
|
|
||||||
const unsigned char MMDVM_M17_DATA = 0x45U;
|
const unsigned char MMDVM_M17_HEADER = 0x45U;
|
||||||
const unsigned char MMDVM_M17_LOST = 0x46U;
|
const unsigned char MMDVM_M17_DATA = 0x46U;
|
||||||
|
const unsigned char MMDVM_M17_LOST = 0x47U;
|
||||||
|
|
||||||
const unsigned char MMDVM_POCSAG_DATA = 0x50U;
|
const unsigned char MMDVM_POCSAG_DATA = 0x50U;
|
||||||
|
|
||||||
|
@ -661,6 +662,20 @@ void CSerialModem::clock(unsigned int ms)
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case MMDVM_M17_DATA: {
|
||||||
if (m_trace)
|
if (m_trace)
|
||||||
CUtils::dump(1U, "RX M17 Data", m_buffer, m_length);
|
CUtils::dump(1U, "RX M17 Data", m_buffer, m_length);
|
||||||
|
@ -1017,8 +1032,12 @@ void CSerialModem::clock(unsigned int ms)
|
||||||
m_txM17Data.getData(&len, 1U);
|
m_txM17Data.getData(&len, 1U);
|
||||||
m_txM17Data.getData(m_buffer, len);
|
m_txM17Data.getData(m_buffer, len);
|
||||||
|
|
||||||
if (m_trace)
|
if (m_trace) {
|
||||||
CUtils::dump(1U, "TX M17 Data", m_buffer, len);
|
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);
|
int ret = m_serial->write(m_buffer, len);
|
||||||
if (ret != int(len))
|
if (ret != int(len))
|
||||||
|
@ -1460,14 +1479,18 @@ bool CSerialModem::writeM17Data(const unsigned char* data, unsigned int length)
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
assert(length > 0U);
|
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;
|
return false;
|
||||||
|
|
||||||
unsigned char buffer[130U];
|
unsigned char buffer[130U];
|
||||||
|
|
||||||
buffer[0U] = MMDVM_FRAME_START;
|
buffer[0U] = MMDVM_FRAME_START;
|
||||||
buffer[1U] = length + 2U;
|
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);
|
::memcpy(buffer + 3U, data + 1U, length - 1U);
|
||||||
|
|
||||||
|
|
11
Sync.cpp
11
Sync.cpp
|
@ -85,9 +85,16 @@ void CSync::addNXDNSync(unsigned char* data)
|
||||||
data[i] = (data[i] & ~NXDN_FSW_BYTES_MASK[i]) | NXDN_FSW_BYTES[i];
|
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);
|
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
3
Sync.h
|
@ -33,7 +33,8 @@ public:
|
||||||
|
|
||||||
static void addNXDNSync(unsigned char* data);
|
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:
|
private:
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,6 @@
|
||||||
#if !defined(VERSION_H)
|
#if !defined(VERSION_H)
|
||||||
#define VERSION_H
|
#define VERSION_H
|
||||||
|
|
||||||
const char* VERSION = "20201124";
|
const char* VERSION = "20201126";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue