diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp
index 1a99c5a..c26a60e 100644
--- a/MMDVMHost.cpp
+++ b/MMDVMHost.cpp
@@ -784,8 +784,7 @@ int CMMDVMHost::run()
if (m_mode == MODE_NXDN) {
m_modem->writeNXDNData(data, len);
m_modeTimer.start();
- }
- else if (m_mode != MODE_LOCKOUT) {
+ } else if (m_mode != MODE_LOCKOUT) {
LogWarning("NXDN data received when in mode %u", m_mode);
}
}
diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj
index 6feb302..5a66b6f 100644
--- a/MMDVMHost.vcxproj
+++ b/MMDVMHost.vcxproj
@@ -195,6 +195,7 @@
+
@@ -269,6 +270,7 @@
+
diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters
index 1d5a94c..ba4a45d 100644
--- a/MMDVMHost.vcxproj.filters
+++ b/MMDVMHost.vcxproj.filters
@@ -239,6 +239,9 @@
Header Files
+
+ Header Files
+
@@ -445,5 +448,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 42ccbfe..b414d09 100644
--- a/Makefile
+++ b/Makefile
@@ -9,9 +9,10 @@ LDFLAGS = -g
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
- Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o P25Audio.o \
- P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
- SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o NXDNLICH.o \
+ NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o \
+ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \
+ YSFNetwork.o YSFPayload.o
all: MMDVMHost
diff --git a/Makefile.Pi b/Makefile.Pi
index 2d4c1a2..8934c4f 100644
--- a/Makefile.Pi
+++ b/Makefile.Pi
@@ -9,9 +9,10 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
- Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o P25Audio.o \
- P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
- SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o NXDNLICH.o \
+ NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o \
+ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o \
+ YSFPayload.o
all: MMDVMHost
diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit
index 5121a6f..25d6aef 100644
--- a/Makefile.Pi.Adafruit
+++ b/Makefile.Pi.Adafruit
@@ -10,8 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
- P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o \
- SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ NXDNLICH.o NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o \
+ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o \
+ YSFPayload.o
all: MMDVMHost
diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780
index 0c5fc11..7d5e7b5 100644
--- a/Makefile.Pi.HD44780
+++ b/Makefile.Pi.HD44780
@@ -10,8 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
- P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o \
- SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ NXDNLICH.o NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o \
+ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o \
+ YSFPayload.o
all: MMDVMHost
diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED
index 36b223c..7ef9f81 100644
--- a/Makefile.Pi.OLED
+++ b/Makefile.Pi.OLED
@@ -10,8 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
- P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o \
- SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ NXDNLICH.o NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o \
+ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o \
+ YSFPayload.o
all: MMDVMHost
diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574
index 3942c66..8bd0b64 100644
--- a/Makefile.Pi.PCF8574
+++ b/Makefile.Pi.PCF8574
@@ -10,8 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
- P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o \
- SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ NXDNLICH.o NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o \
+ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o \
+ YSFPayload.o
all: MMDVMHost
diff --git a/Makefile.Solaris b/Makefile.Solaris
index 1275515..831c097 100644
--- a/Makefile.Solaris
+++ b/Makefile.Solaris
@@ -9,9 +9,10 @@ LDFLAGS = -g
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
- Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o P25Audio.o \
- P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
- SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
+ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
+ NXDNLICH.o NXDNNetwork.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \
+ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \
+ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost
diff --git a/NXDNControl.cpp b/NXDNControl.cpp
index 4865f94..aaebec9 100644
--- a/NXDNControl.cpp
+++ b/NXDNControl.cpp
@@ -51,6 +51,7 @@ m_rfErrs(0U),
m_rfBits(1U),
m_netErrs(0U),
m_netBits(1U),
+m_lastLICH(),
m_netN(0U),
m_rssiMapper(rssiMapper),
m_rssi(0U),
@@ -115,49 +116,74 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len)
m_rssiCount++;
}
+ CUtils::dump(2U, "NXDN, raw data", data, len);
+
scrambler(data + 2U);
- CYSFFICH fich;
- bool valid = fich.decode(data + 2U);
+ CUtils::dump(2U, "NXDN, after descrambling", data, len);
+
+ CNXDNLICH lich;
+ bool valid = lich.decode(data + 2U);
if (valid)
- m_lastFICH = fich;
+ m_lastLICH = lich;
// Stop repeater packets coming through, unless we're acting as a remote gateway
if (m_remoteGateway) {
- unsigned char mr = m_lastFICH.getMR();
- if (mr != YSF_MR_BUSY)
+ unsigned char direction = m_lastLICH.getDirection();
+ if (direction != NXDN_LICH_DIRECTION_INBOUND)
return false;
} else {
- unsigned char mr = m_lastFICH.getMR();
- if (mr == YSF_MR_BUSY)
+ unsigned char direction = m_lastLICH.getDirection();
+ if (direction == NXDN_LICH_DIRECTION_OUTBOUND)
return false;
}
- unsigned char dt = m_lastFICH.getDT();
+ unsigned char usc = m_lastLICH.getFCT();
+ unsigned char option = m_lastLICH.getOption();
bool ret = false;
- switch (dt) {
- case YSF_DT_VOICE_FR_MODE:
- ret = processVWData(valid, data);
- break;
+#ifdef notdef
+ if (usc == NXDN_LICH_USC_SACCH_NS || usc == NXDN_LICH_USC_SACCH_SS) {
+ switch (option) {
+ case NXDN_LICH_STEAL_NONE:
+ ret = processVCHOnly(valid, data);
+ break;
- case YSF_DT_VD_MODE1:
- case YSF_DT_VD_MODE2:
- ret = processDNData(valid, data);
- break;
+ case NXDN_LICH_STEAL_FACCH1_1:
+ ret = processFACCH11(valid, data);
+ break;
- case YSF_DT_DATA_FR_MODE:
- ret = processFRData(valid, data);
- break;
+ case NXDN_LICH_STEAL_FACCH1_2:
+ ret = processFACCH12(valid, data);
+ break;
- default:
- break;
+ case NXDN_LICH_STEAL_FACCH:
+ ret = processFACCH1(valid, data);
+ break;
+
+ default:
+ break;
+ }
+ } else if (usc == NXDN_LICH_USC_UDCH) {
+ switch (option) {
+ case NXDN_LICH_STEAL_NONE:
+ ret = processUDCH(valid, data);
+ break;
+
+ case NXDN_LICH_STEAL_FACCH:
+ ret = processFACCH2(valid, data);
+ break;
+
+ default:
+ break;
+ }
}
-
+#endif
return ret;
}
+#ifdef notdef
bool CNXDNControl::processVWData(bool valid, unsigned char *data)
{
unsigned char fi = m_lastFICH.getFI();
@@ -810,6 +836,8 @@ bool CNXDNControl::processFRData(bool valid, unsigned char *data)
return false;
}
+#endif
+
unsigned int CNXDNControl::readModem(unsigned char* data)
{
assert(data != NULL);
@@ -857,6 +885,8 @@ void CNXDNControl::writeEndNet()
m_network->reset();
}
+#ifdef notdef
+
void CNXDNControl::writeNetwork()
{
unsigned char data[200U];
@@ -986,10 +1016,14 @@ void CNXDNControl::writeNetwork()
}
}
+#endif
+
void CNXDNControl::clock(unsigned int ms)
{
+#ifdef notdef
if (m_network != NULL)
writeNetwork();
+#endif
m_rfTimeoutTimer.clock(ms);
m_netTimeoutTimer.clock(ms);
diff --git a/NXDNControl.h b/NXDNControl.h
index a86b3d4..935110a 100644
--- a/NXDNControl.h
+++ b/NXDNControl.h
@@ -25,7 +25,7 @@
// #include "YSFPayload.h"
#include "RingBuffer.h"
#include "StopWatch.h"
-// #include "YSFFICH.h"
+#include "NXDNLICH.h"
#include "Display.h"
#include "Defines.h"
#include "Timer.h"
@@ -67,6 +67,7 @@ private:
unsigned int m_rfBits;
unsigned int m_netErrs;
unsigned int m_netBits;
+ CNXDNLICH m_lastLICH;
unsigned char m_netN;
CRSSIInterpolator* m_rssiMapper;
unsigned char m_rssi;
@@ -76,9 +77,12 @@ private:
unsigned int m_rssiCount;
FILE* m_fp;
- bool processVWData(bool valid, unsigned char *data);
- bool processDNData(bool valid, unsigned char *data);
- bool processFRData(bool valid, unsigned char *data);
+ bool processVCHOnly(bool valid, unsigned char *data);
+ bool processFACCH11(bool valid, unsigned char *data);
+ bool processFACCH12(bool valid, unsigned char *data);
+ bool processFACCH1(bool valid, unsigned char *data);
+ bool processUDCH(bool valid, unsigned char *data);
+ bool processFACCH2(bool valid, unsigned char *data);
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
diff --git a/NXDNDefines.h b/NXDNDefines.h
index ce39d00..487923b 100644
--- a/NXDNDefines.h
+++ b/NXDNDefines.h
@@ -31,5 +31,24 @@ const unsigned char NXDN_FSW_BYTES[] = {0xCDU, 0xF5U, 0x90U};
const unsigned char NXDN_FSW_BYTES_MASK[] = {0xFFU, 0xFFU, 0xF0U};
const unsigned int NXDN_FSW_BYTES_LENGTH = 3U;
-#endif
+const unsigned int NXDN_LICH_LENGTH_BITS = 16U;
+const unsigned char NXDN_LICH_RFCT_RCCH = 0U;
+const unsigned char NXDN_LICH_RFCT_RTCH = 1U;
+const unsigned char NXDN_LICH_RFCT_RDCH = 2U;
+const unsigned char NXDN_LICH_RFCT_RTCH_C = 3U;
+
+const unsigned char NXDN_LICH_USC_SACCH_NS = 0U;
+const unsigned char NXDN_LICH_USC_UDCH = 1U;
+const unsigned char NXDN_LICH_USC_SACCH_SS = 2U;
+const unsigned char NXDN_LICH_USC_SACCH_SS_IDLE = 3U;
+
+const unsigned char NXDN_LICH_STEAL_NONE = 3U;
+const unsigned char NXDN_LICH_STEAL_FACCH1_2 = 2U;
+const unsigned char NXDN_LICH_STEAL_FACCH1_1 = 1U;
+const unsigned char NXDN_LICH_STEAL_FACCH = 0U;
+
+const unsigned char NXDN_LICH_DIRECTION_INBOUND = 0U;
+const unsigned char NXDN_LICH_DIRECTION_OUTBOUND = 1U;
+
+#endif
diff --git a/NXDNLICH.cpp b/NXDNLICH.cpp
new file mode 100644
index 0000000..9014328
--- /dev/null
+++ b/NXDNLICH.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2018 by Jonathan Naylor G4KLX
+ *
+ * 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; either version 2 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "NXDNDefines.h"
+#include "NXDNLICH.h"
+#include "Log.h"
+
+#include
+#include
+#include
+
+const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
+
+#define WRITE_BIT1(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_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
+
+CNXDNLICH::CNXDNLICH(const CNXDNLICH& lich) :
+m_lich(lich.m_lich)
+{
+}
+
+CNXDNLICH::CNXDNLICH() :
+m_lich(0U)
+{
+}
+
+CNXDNLICH::~CNXDNLICH()
+{
+}
+
+bool CNXDNLICH::decode(const unsigned char* bytes)
+{
+ assert(bytes != NULL);
+
+ unsigned char lich[1U];
+ lich[0U] = 0x00U;
+
+ unsigned int offset = NXDN_FSW_LENGTH_BITS;
+ bool b7 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 7U, b7);
+
+ offset++;
+ bool b6 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 6U, b6);
+
+ offset++;
+ bool b5 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 5U, b5);
+
+ offset++;
+ bool b4 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 4U, b4);
+
+ offset++;
+ bool b3 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 3U, b3);
+
+ offset++;
+ bool b2 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 2U, b2);
+
+ offset++;
+ bool b1 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 1U, b1);
+
+ offset++;
+ bool b0 = READ_BIT1(bytes, offset);
+ WRITE_BIT1(lich, 0U, b0);
+
+ bool parity = b7 ^ b6 ^ b5 ^ b4;
+
+ LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b7 ? 1 : 0, b6 ? 1 : 0, b5 ? 1 : 0, b4 ? 1 : 0, b3 ? 1 : 0, b2 ? 1 : 0, b1 ? 1 : 0, b0 ? 1 : 0, parity ? 1 : 0);
+
+ if (parity != b0)
+ return false;
+
+ m_lich = lich[0U] >> 1;
+
+ return true;
+}
+
+void CNXDNLICH::encode(unsigned char* bytes)
+{
+ assert(bytes != NULL);
+
+ unsigned char lich[1U];
+
+ lich[0U] = m_lich << 1;
+
+ bool b7 = READ_BIT1(lich, 7U);
+ bool b6 = READ_BIT1(lich, 6U);
+ bool b5 = READ_BIT1(lich, 5U);
+ bool b4 = READ_BIT1(lich, 4U);
+ bool b3 = READ_BIT1(lich, 3U);
+ bool b2 = READ_BIT1(lich, 2U);
+ bool b1 = READ_BIT1(lich, 1U);
+ bool b0 = READ_BIT1(lich, 0U);
+
+ bool parity = b7 ^ b6 ^ b5 ^ b4;
+
+ WRITE_BIT1(lich, 0U, parity);
+
+ unsigned int offset = NXDN_FSW_LENGTH_BITS;
+ WRITE_BIT1(bytes, offset, b7);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b6);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b5);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b4);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b3);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b2);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b1);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+ offset++;
+
+ WRITE_BIT1(bytes, offset, b0);
+ offset++;
+ WRITE_BIT1(bytes, offset, true);
+}
+
+unsigned char CNXDNLICH::getRFCT() const
+{
+ return (m_lich >> 5) & 0x03U;
+}
+
+unsigned char CNXDNLICH::getFCT() const
+{
+ return (m_lich >> 3) & 0x03U;
+}
+
+unsigned char CNXDNLICH::getOption() const
+{
+ return (m_lich >> 1) & 0x03U;
+}
+
+unsigned char CNXDNLICH::getDirection() const
+{
+ return m_lich & 0x01U;
+}
+
+void CNXDNLICH::setRFCT(unsigned char rfct)
+{
+ m_lich &= 0x1FU;
+ m_lich |= (rfct << 5) & 0x60U;
+}
+
+void CNXDNLICH::setFCT(unsigned char usc)
+{
+ m_lich &= 0x67U;
+ m_lich |= (usc << 3) & 0x18U;
+}
+
+void CNXDNLICH::setOption(unsigned char option)
+{
+ m_lich &= 0x79U;
+ m_lich |= (option << 1) & 0x06U;
+}
+
+void CNXDNLICH::setDirection(unsigned char direction)
+{
+ m_lich &= 0x7EU;
+ m_lich |= direction & 0x01U;
+}
+
+CNXDNLICH& CNXDNLICH::operator=(const CNXDNLICH& lich)
+{
+ if (&lich != this)
+ m_lich = lich.m_lich;
+
+ return *this;
+}
diff --git a/NXDNLICH.h b/NXDNLICH.h
new file mode 100644
index 0000000..e5ecd2b
--- /dev/null
+++ b/NXDNLICH.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 by Jonathan Naylor G4KLX
+ *
+ * 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; either version 2 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if !defined(NXDNLICH_H)
+#define NXDNLICH_H
+
+class CNXDNLICH {
+public:
+ CNXDNLICH(const CNXDNLICH& fich);
+ CNXDNLICH();
+ ~CNXDNLICH();
+
+ bool decode(const unsigned char* bytes);
+
+ void encode(unsigned char* bytes);
+
+ unsigned char getRFCT() const;
+ unsigned char getFCT() const;
+ unsigned char getOption() const;
+ unsigned char getDirection() const;
+
+ void setRFCT(unsigned char rfct);
+ void setFCT(unsigned char usc);
+ void setOption(unsigned char option);
+ void setDirection(unsigned char direction);
+
+ CNXDNLICH& operator=(const CNXDNLICH& fich);
+
+private:
+ unsigned char m_lich;
+};
+
+#endif