Beginnings of DMR data support.

This commit is contained in:
Jonathan Naylor 2016-01-26 18:06:31 +00:00
parent eaae483f96
commit 7bb53cf704
11 changed files with 290 additions and 33 deletions

17
CRC.cpp
View File

@ -19,6 +19,7 @@
#include "CRC.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
@ -72,18 +73,16 @@ unsigned char CCRC::encodeEightBit(const unsigned char *in, unsigned int length)
return crc;
}
bool CCRC::checkCSBK(const unsigned char *in)
bool CCRC::checkCCITT16(const unsigned char *in, unsigned int length)
{
assert(in != NULL);
assert(length > 2U);
unsigned short crc16 = 0U;
// Run through all 12 bits
for (unsigned int a = 0; a < 12U; a++) {
for (unsigned int a = 0; a < (length - 2U); a++) {
unsigned char val = in[a];
// Allow for the CSBK CRC mask
if (a > 9U)
val ^= 0xA5U;
for (unsigned int i = 0U; i < 8U; i++) {
bool c15 = (crc16 >> 15 & 0x01U) == 0x01U;
bool bit = (val >> (7 - i) & 0x01U) == 0x01U;
@ -93,7 +92,9 @@ bool CCRC::checkCSBK(const unsigned char *in)
}
}
return crc16 == 0x1D0FU;
LogMessage("CCITT16, %04X == %02X %02X", crc16, in[length - 2U], in[length - 1U]);
return crc16 == (in[length - 2U] << 8 | in[length - 1U]);
}
unsigned char CCRC::crc8(const unsigned char *in, unsigned int length)

2
CRC.h
View File

@ -25,7 +25,7 @@ public:
static bool checkFiveBit(bool* in, unsigned int tcrc);
static void encodeFiveBit(const bool* in, unsigned int& tcrc);
static bool checkCSBK(const unsigned char* in);
static bool checkCCITT16(const unsigned char* in, unsigned int length);
static unsigned char encodeEightBit(const unsigned char* in, unsigned int length);

View File

@ -39,7 +39,10 @@ m_valid(false)
unsigned char data[12U];
bptc.decode(bytes, data);
m_valid = CCRC::checkCSBK(data);
data[10U] ^= CSBK_CRC_MASK[0U];
data[11U] ^= CSBK_CRC_MASK[1U];
m_valid = CCRC::checkCCITT16(data, 12U);
m_CSBKO = CSBKO(data[0U] & 0x3FU);
m_FID = data[1U];

81
DMRDataHeader.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2012 by Ian Wraith
* Copyright (C) 2015,2016 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 "DMRDataHeader.h"
#include "DMRDefines.h"
#include "CRC.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
CDMRDataHeader::CDMRDataHeader(const unsigned char* data) :
m_bptc(),
m_valid(false),
m_gi(false),
m_srcId(0U),
m_dstId(0U),
m_blocks(0U)
{
assert(data != NULL);
unsigned char header[12U];
m_bptc.decode(data, header);
header[10U] ^= DATA_HEADER_CRC_MASK[0U];
header[11U] ^= DATA_HEADER_CRC_MASK[1U];
m_valid = CCRC::checkCCITT16(header, 12U);
m_gi = (header[0U] & 0x80U) == 0x80U;
m_dstId = data[2U] << 16 | data[3U] << 8 | data[4U];
m_srcId = data[5U] << 16 | data[6U] << 8 | data[7U];
m_blocks = data[8U] & 0x7FU;
}
CDMRDataHeader::~CDMRDataHeader()
{
}
bool CDMRDataHeader::isValid() const
{
return m_valid;
}
bool CDMRDataHeader::getGI() const
{
return m_gi;
}
unsigned int CDMRDataHeader::getSrcId() const
{
return m_srcId;
}
unsigned int CDMRDataHeader::getDstId() const
{
return m_dstId;
}
unsigned int CDMRDataHeader::getBlocks() const
{
return m_blocks;
}

49
DMRDataHeader.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2015,2016 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.
*/
#ifndef DMRDataHeader_H
#define DMRDataHeader_H
#include "BPTC19696.h"
class CDMRDataHeader
{
public:
CDMRDataHeader(const unsigned char* data);
~CDMRDataHeader();
bool isValid() const;
bool getGI() const;
unsigned int getSrcId() const;
unsigned int getDstId() const;
unsigned int getBlocks() const;
private:
CBPTC19696 m_bptc;
bool m_valid;
bool m_gi;
unsigned int m_srcId;
unsigned int m_dstId;
unsigned int m_blocks;
};
#endif

View File

@ -64,6 +64,7 @@ const unsigned char PAYLOAD_RIGHT_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xF
const unsigned char VOICE_LC_HEADER_CRC_MASK[] = {0x96U, 0x96U, 0x96U};
const unsigned char TERMINATOR_WITH_LC_CRC_MASK[] = {0x99U, 0x99U, 0x99U};
const unsigned char DATA_HEADER_CRC_MASK[] = {0xCCU, 0xCCU};
const unsigned char CSBK_CRC_MASK[] = {0xA5U, 0xA5U};
const unsigned int DMR_SLOT_TIME = 60U;
@ -74,8 +75,13 @@ const unsigned char DT_VOICE_PI_HEADER = 0x00U;
const unsigned char DT_VOICE_LC_HEADER = 0x01U;
const unsigned char DT_TERMINATOR_WITH_LC = 0x02U;
const unsigned char DT_CSBK = 0x03U;
const unsigned char DT_MBC_HEADER = 0x04U;
const unsigned char DT_MBC_CONTINUATION = 0x05U;
const unsigned char DT_DATA_HEADER = 0x06U;
const unsigned char DT_RATE_12_DATA = 0x07U;
const unsigned char DT_RATE_34_DATA = 0x08U;
const unsigned char DT_IDLE = 0x09U;
const unsigned char DT_RATE_1_DATA = 0x0AU;
// Dummy values
const unsigned char DT_VOICE_SYNC = 0xF0U;

View File

@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
#include "DMRDataHeader.h"
#include "SlotType.h"
#include "ShortLC.h"
#include "DMRSlot.h"
@ -51,6 +52,7 @@ m_timeoutTimer(1000U, timeout),
m_packetTimer(1000U, 0U, 100U),
m_elapsed(),
m_frames(0U),
m_blocks(0U),
m_lost(0U),
m_fec(),
m_bits(0U),
@ -185,6 +187,20 @@ void CDMRSlot::writeModem(unsigned char *data)
if (m_state == RS_RELAYING_RF_DATA)
return;
CDMRDataHeader dataHeader(data + 2U);
// if (!dataHeader.isValid()) {
// LogMessage("DMR Slot %u: unable to decode the data header", m_slotNo);
// return;
// }
bool gi = dataHeader.getGI();
unsigned int srcId = dataHeader.getSrcId();
unsigned int dstId = dataHeader.getDstId();
m_blocks = dataHeader.getBlocks();
m_lc = new CLC(gi ? FLCO_GROUP : FLCO_USER_USER, srcId, dstId);
// Regenerate the Slot Type
slotType.getData(data + 2U);
@ -206,14 +222,18 @@ void CDMRSlot::writeModem(unsigned char *data)
}
m_state = RS_RELAYING_RF_DATA;
// setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());
// m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());
setShortLC(m_slotNo, m_lc->getDstId(), gi ? FLCO_GROUP : FLCO_USER_USER);
// LogMessage("DMR Slot %u, received RF data header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
LogMessage("DMR Slot %u, received RF data header", m_slotNo);
m_display->writeDMR(m_slotNo, srcId, gi, dstId);
LogMessage("DMR Slot %u, received RF data header from %u to %s%u, %u blocks", m_slotNo, srcId, gi ? "TG ": "", dstId, m_blocks);
} else if (dataType == DT_CSBK) {
CCSBK csbk(data + 2U);
// if (!csbk.isValid()) {
// LogMessage("DMR Slot %u: unable to decode the CSBK", m_slotNo);
// return;
// }
CSBKO csbko = csbk.getCSBKO();
switch (csbko) {
@ -224,6 +244,9 @@ void CDMRSlot::writeModem(unsigned char *data)
case CSBKO_UUANSRSP:
case CSBKO_NACKRSP:
case CSBKO_PRECCSBK: {
// Regenerate the Slot Type
slotType.getData(data + 2U);
// Convert the Data Sync to be from the BS
CDMRSync sync;
sync.addSync(data + 2U, DST_BS_DATA);
@ -244,7 +267,10 @@ void CDMRSlot::writeModem(unsigned char *data)
LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko);
break;
}
} else {
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
if (m_state != RS_RELAYING_RF_DATA)
return;
// Regenerate the Slot Type
slotType.getData(data + 2U);
@ -252,11 +278,21 @@ void CDMRSlot::writeModem(unsigned char *data)
CDMRSync sync;
sync.addSync(data + 2U, DST_BS_DATA);
data[0U] = TAG_DATA;
m_blocks--;
data[0U] = m_blocks == 0U ? TAG_EOT : TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data, dataType);
writeQueue(data);
if (m_blocks == 0U) {
LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo);
writeEndOfTransmission();
}
} else {
// Unhandled data type
LogWarning("DMR Slot %u, unhandled RF data type - 0x%02X", m_slotNo, dataType);
}
} else if (audioSync) {
if (m_state == RS_RELAYING_RF_AUDIO) {
@ -514,6 +550,20 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
if (m_state == RS_RELAYING_NETWORK_DATA)
return;
CDMRDataHeader dataHeader(data + 2U);
// if (!dataHeader.isValid()) {
// LogMessage("DMR Slot %u: unable to decode the data header", m_slotNo);
// return;
// }
bool gi = dataHeader.getGI();
unsigned int srcId = dataHeader.getSrcId();
unsigned int dstId = dataHeader.getDstId();
m_blocks = dataHeader.getBlocks();
m_lc = new CLC(gi ? FLCO_GROUP : FLCO_USER_USER, srcId, dstId);
// Regenerate the Slot Type
CSlotType slotType;
slotType.setColorCode(m_colorCode);
@ -536,12 +586,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
m_state = RS_RELAYING_NETWORK_DATA;
// setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());
setShortLC(m_slotNo, dmrData.getDstId(), gi ? FLCO_GROUP : FLCO_USER_USER);
// m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());
m_display->writeDMR(m_slotNo, dmrData.getSrcId(), gi, dmrData.getDstId());
// LogMessage("DMR Slot %u, received network data header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
LogMessage("DMR Slot %u, received network data header", m_slotNo);
LogMessage("DMR Slot %u, received network data header from %u to %s%u, %u blocks", m_slotNo, dmrData.getSrcId(), gi ? "TG ": "", dmrData.getDstId(), m_blocks);
} else if (dataType == DT_VOICE_SYNC) {
if (m_state == RS_LISTENING) {
m_lc = new CLC(dmrData.getFLCO(), dmrData.getSrcId(), dmrData.getDstId());
@ -650,8 +699,55 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
#if defined(DUMP_DMR)
writeFile(data);
#endif
} else {
// Change the Color Code of the Slot Type
} else if (dataType == DT_CSBK) {
CCSBK csbk(data + 2U);
// if (!csbk.isValid()) {
// LogMessage("DMR Slot %u: unable to decode the CSBK", m_slotNo);
// return;
// }
CSBKO csbko = csbk.getCSBKO();
switch (csbko) {
case CSBKO_BSDWNACT:
return;
case CSBKO_UUVREQ:
case CSBKO_UUANSRSP:
case CSBKO_NACKRSP:
case CSBKO_PRECCSBK: {
// Regenerate the Slot Type
CSlotType slotType;
slotType.putData(data + 2U);
slotType.setColorCode(m_colorCode);
slotType.getData(data + 2U);
// Convert the Data Sync to be from the BS
CDMRSync sync;
sync.addSync(data + 2U, DST_BS_DATA);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueue(data);
#if defined(DUMP_DMR)
openFile();
writeFile(data);
closeFile();
#endif
LogMessage("DMR Slot %u, received network CSBK from %u to %u", m_slotNo, csbk.getSrcId(), csbk.getDstId());
}
break;
default:
LogWarning("DMR Slot %u, unhandled network CSBK type - 0x%02X", m_slotNo, csbko);
break;
}
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
if (m_state != RS_RELAYING_NETWORK_DATA)
return;
// Regenerate the Slot Type
CSlotType slotType;
slotType.putData(data + 2U);
slotType.setColorCode(m_colorCode);
@ -661,14 +757,23 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
CDMRSync sync;
sync.addSync(data + 2U, DST_BS_DATA);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
m_blocks--;
writeQueue(data);
data[0U] = m_blocks == 0U ? TAG_EOT : TAG_DATA;
data[1U] = 0x00U;
#if defined(DUMP_DMR)
writeFile(data);
#endif
writeQueue(data);
if (m_blocks == 0U) {
LogMessage("DMR Slot %u, ended network data transmission", m_slotNo);
writeEndOfTransmission();
}
} else {
// Unhandled data type
LogWarning("DMR Slot %u, unhandled network data type - 0x%02X", m_slotNo, dataType);
}
}

View File

@ -61,6 +61,7 @@ private:
CTimer m_packetTimer;
CStopWatch m_elapsed;
unsigned int m_frames;
unsigned int m_blocks;
unsigned int m_lost;
CAMBEFEC m_fec;
unsigned int m_bits;

View File

@ -155,6 +155,7 @@
<ClInclude Include="Display.h" />
<ClInclude Include="DMRControl.h" />
<ClInclude Include="DMRData.h" />
<ClInclude Include="DMRDataHeader.h" />
<ClInclude Include="DMRDefines.h" />
<ClInclude Include="DMRSlot.h" />
<ClInclude Include="DMRSync.h" />
@ -198,6 +199,7 @@
<ClCompile Include="Display.cpp" />
<ClCompile Include="DMRControl.cpp" />
<ClCompile Include="DMRData.cpp" />
<ClCompile Include="DMRDataHeader.cpp" />
<ClCompile Include="DMRSlot.cpp" />
<ClCompile Include="DMRSync.cpp" />
<ClCompile Include="DStarEcho.cpp" />

View File

@ -137,6 +137,9 @@
<ClInclude Include="DStarNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DMRDataHeader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -247,5 +250,8 @@
<ClCompile Include="DStarNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DMRDataHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -5,12 +5,12 @@ LDFLAGS = -g
all: MMDVMHost
MMDVMHost: AMBEFEC.o BPTC19696.o Conf.o CRC.o CSBK.o Display.o DMRControl.o DMRData.o DMRSlot.o DMRSync.o DStarEcho.o DStarNetwork.o EMB.o EmbeddedLC.o FullLC.o \
Golay2087.o Golay24128.o Hamming.o HomebrewDMRIPSC.o LC.o Log.o MMDVMHost.o Modem.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o ShortLC.o \
SlotType.o StopWatch.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFEcho.o
$(CC) $(LDFLAGS) -o MMDVMHost AMBEFEC.o BPTC19696.o Conf.o CRC.o CSBK.o Display.o DMRControl.o DMRData.o DMRSlot.o DMRSync.o DStarEcho.o DStarNetwork.o EMB.o \
EmbeddedLC.o FullLC.o Golay2087.o Golay24128.o Hamming.o HomebrewDMRIPSC.o LC.o Log.o MMDVMHost.o Modem.o NullDisplay.o QR1676.o RS129.o \
SerialController.o SHA256.o ShortLC.o SlotType.o StopWatch.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFEcho.o $(LIBS)
MMDVMHost: AMBEFEC.o BPTC19696.o Conf.o CRC.o CSBK.o Display.o DMRControl.o DMRData.o DMRDataHeader.o DMRSlot.o DMRSync.o DStarEcho.o DStarNetwork.o EMB.o \
EmbeddedLC.o FullLC.o Golay2087.o Golay24128.o Hamming.o HomebrewDMRIPSC.o LC.o Log.o MMDVMHost.o Modem.o NullDisplay.o QR1676.o RS129.o \
SerialController.o SHA256.o ShortLC.o SlotType.o StopWatch.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFEcho.o
$(CC) $(LDFLAGS) -o MMDVMHost AMBEFEC.o BPTC19696.o Conf.o CRC.o CSBK.o Display.o DMRControl.o DMRData.o DMRDataHeader.o DMRSlot.o DMRSync.o DStarEcho.o \
DStarNetwork.o EMB.o EmbeddedLC.o FullLC.o Golay2087.o Golay24128.o Hamming.o HomebrewDMRIPSC.o LC.o Log.o MMDVMHost.o Modem.o NullDisplay.o QR1676.o \
RS129.o SerialController.o SHA256.o ShortLC.o SlotType.o StopWatch.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFEcho.o $(LIBS)
AMBEFEC.o: AMBEFEC.cpp AMBEFEC.h Golay24128.h
$(CC) $(CFLAGS) -c AMBEFEC.cpp
@ -35,9 +35,12 @@ DMRControl.o: DMRControl.cpp DMRControl.h DMRSlot.h DMRData.h Modem.h HomebrewDM
DMRData.o: DMRData.cpp DMRData.h DMRDefines.h Utils.h Log.h
$(CC) $(CFLAGS) -c DMRData.cpp
DMRDataHeader.o: DMRDataHeader.cpp DMRDataHeader.h DMRDefines.h Utils.h Log.h CRC.h BPTC19696.h
$(CC) $(CFLAGS) -c DMRDataHeader.cpp
DMRSlot.o: DMRSlot.cpp DMRSlot.h DMRData.h Modem.h HomebrewDMRIPSC.h Defines.h Log.h EmbeddedLC.h RingBuffer.h Timer.h LC.h SlotType.h DMRSync.h FullLC.h \
EMB.h CRC.h CSBK.h ShortLC.h Utils.h Display.h StopWatch.h AMBEFEC.h
EMB.h CRC.h CSBK.h ShortLC.h Utils.h Display.h StopWatch.h AMBEFEC.h DMRDataHeader.h
$(CC) $(CFLAGS) -c DMRSlot.cpp
DMRSync.o: DMRSync.cpp DMRSync.h DMRDefines.h