mirror of
https://github.com/g4klx/ircDDBGateway.git
synced 2025-12-06 05:32:02 +01:00
359 lines
11 KiB
C++
359 lines
11 KiB
C++
/*
|
|
* Copyright (C) 2010 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; version 2 of the License.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "SlowDataEncoder.h"
|
|
#include "CCITTChecksum.h"
|
|
#include "DStarDefines.h"
|
|
|
|
const unsigned int SLOW_DATA_BLOCK_SIZE = 6U;
|
|
|
|
const unsigned int SLOW_DATA_FULL_BLOCK_SIZE = SLOW_DATA_BLOCK_SIZE * 10U;
|
|
|
|
const unsigned char SLOW_DATA_FILLER_BYTES[] = {'f', 'f', 'f' };
|
|
|
|
const unsigned int HEADER_SIZE = 54U;
|
|
const unsigned int TEXT_SIZE = 24U;
|
|
|
|
CSlowDataEncoder::CSlowDataEncoder() :
|
|
m_headerData(NULL),
|
|
m_textData(NULL),
|
|
m_gpsData(NULL),
|
|
m_interleavedData(NULL),
|
|
m_headerPtr(0U),
|
|
m_textPtr(0U),
|
|
m_gpsPtr(0U),
|
|
m_interleavedPtr(0U),
|
|
m_gpsDataSize(0U),
|
|
m_gpsDataFullSize(0U),
|
|
m_interleavedDataFullSize(0U)
|
|
{
|
|
}
|
|
|
|
CSlowDataEncoder::~CSlowDataEncoder()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
void CSlowDataEncoder::clearHeaderData()
|
|
{
|
|
if(m_headerData)
|
|
{
|
|
delete[] m_headerData;
|
|
m_headerData = NULL;
|
|
m_headerPtr = 0U;
|
|
}
|
|
}
|
|
|
|
void CSlowDataEncoder::clearTextData()
|
|
{
|
|
if(m_textData)
|
|
{
|
|
delete[] m_textData;
|
|
m_textData = NULL;
|
|
m_textPtr = 0U;
|
|
}
|
|
}
|
|
|
|
void CSlowDataEncoder::clearGPSData()
|
|
{
|
|
if(m_gpsData)
|
|
{
|
|
delete[] m_gpsData;
|
|
m_gpsData = NULL;
|
|
m_gpsPtr = 0U;
|
|
}
|
|
}
|
|
|
|
void CSlowDataEncoder::clearInterleavedData()
|
|
{
|
|
if(m_interleavedData)
|
|
{
|
|
delete[] m_interleavedData;
|
|
m_interleavedData = NULL;
|
|
m_interleavedPtr = 0U;
|
|
}
|
|
}
|
|
|
|
void CSlowDataEncoder::getData(unsigned char* source, unsigned char* data, unsigned int &sourcePtr, unsigned int sourceLength)
|
|
{
|
|
wxASSERT(data != NULL);
|
|
if(source != NULL){
|
|
data[0U] = source[sourcePtr++] ^ SCRAMBLER_BYTE1;
|
|
data[1U] = source[sourcePtr++] ^ SCRAMBLER_BYTE2;
|
|
data[2U] = source[sourcePtr++] ^ SCRAMBLER_BYTE3;
|
|
}
|
|
else{
|
|
data[0U] = SLOW_DATA_FILLER_BYTES[sourcePtr++] ^ SCRAMBLER_BYTE1;
|
|
data[1U] = SLOW_DATA_FILLER_BYTES[sourcePtr++] ^ SCRAMBLER_BYTE2;
|
|
data[2U] = SLOW_DATA_FILLER_BYTES[sourcePtr++] ^ SCRAMBLER_BYTE3;
|
|
}
|
|
|
|
if (sourcePtr >= sourceLength)
|
|
sourcePtr = 0U;
|
|
}
|
|
|
|
void CSlowDataEncoder::getHeaderData(unsigned char* data)
|
|
{
|
|
getData(m_headerData, data, m_headerPtr, SLOW_DATA_FULL_BLOCK_SIZE);
|
|
}
|
|
|
|
void CSlowDataEncoder::getTextData(unsigned char* data)
|
|
{
|
|
getData(m_textData, data, m_textPtr, SLOW_DATA_FULL_BLOCK_SIZE);
|
|
}
|
|
|
|
void CSlowDataEncoder::getGPSData(unsigned char* data)
|
|
{
|
|
getData(m_gpsData, data, m_gpsPtr, m_gpsDataFullSize);
|
|
}
|
|
|
|
void CSlowDataEncoder::getInterleavedData(unsigned char* data)
|
|
{
|
|
if(m_textData && !m_gpsData && !m_headerData)
|
|
getTextData(data);
|
|
else if(!m_textData && m_gpsData && !m_headerData)
|
|
getGPSData(data);
|
|
else if(!m_textData && !m_gpsData && m_headerData)
|
|
getHeaderData(data);
|
|
else {
|
|
buildInterleavedData();
|
|
getData(m_interleavedData, data, m_interleavedPtr, m_gpsDataFullSize);
|
|
}
|
|
}
|
|
|
|
void CSlowDataEncoder::buildInterleavedData()
|
|
{
|
|
//first build interleaved data if we do not have it
|
|
if(!m_interleavedData)
|
|
{
|
|
getInterleavedDataLength();
|
|
m_interleavedData = new unsigned char[m_interleavedDataFullSize];
|
|
::memset(m_interleavedData, 'f', m_interleavedDataFullSize);
|
|
|
|
unsigned int textPtr = 0U;
|
|
unsigned int gpsPtr = 0U;
|
|
unsigned int headerPtr = 0U;
|
|
|
|
//now proceed with data copying, according to this document http://www.qsl.net/kb9mwr/projects/dv/dstar/Slow%20Data.pdf
|
|
if(m_textData && m_gpsData){
|
|
for(unsigned int interleavedPtr = 0; interleavedPtr < m_interleavedDataFullSize; interleavedPtr += SLOW_DATA_BLOCK_SIZE){
|
|
if(textPtr < TEXT_SIZE
|
|
&& ((interleavedPtr / SLOW_DATA_BLOCK_SIZE) & 0x01U) == 0)
|
|
{
|
|
::memcpy(m_interleavedData + interleavedPtr, m_textData + textPtr, SLOW_DATA_BLOCK_SIZE);
|
|
textPtr += SLOW_DATA_BLOCK_SIZE;
|
|
}
|
|
else if(gpsPtr < m_gpsDataSize){
|
|
::memcpy(m_interleavedData + interleavedPtr, m_gpsData + gpsPtr, SLOW_DATA_BLOCK_SIZE);
|
|
gpsPtr += SLOW_DATA_BLOCK_SIZE;
|
|
}
|
|
else if(m_headerData && headerPtr < HEADER_SIZE){
|
|
::memcpy(m_interleavedData + interleavedPtr, m_headerData + headerPtr, SLOW_DATA_BLOCK_SIZE);
|
|
headerPtr += SLOW_DATA_BLOCK_SIZE;
|
|
}
|
|
}
|
|
}
|
|
else if(m_textData && !m_gpsData && m_headerData){
|
|
//according to above doc, header and text are not interleaved, just on after the other. filler bytes between resync bytes.
|
|
::memcpy(m_interleavedData, m_textData, SLOW_DATA_FULL_BLOCK_SIZE);
|
|
::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE);
|
|
}
|
|
else if(!m_textData && m_gpsData && m_headerData){
|
|
//could not find any spec about this particular case, let's put the data one after the other
|
|
::memcpy(m_interleavedData, m_gpsData, SLOW_DATA_FULL_BLOCK_SIZE);
|
|
::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE);
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int CSlowDataEncoder::getInterleavedDataLength()
|
|
{
|
|
//calculate size (including filler bytes);
|
|
m_interleavedDataFullSize = 0U;
|
|
if(m_textData) m_interleavedDataFullSize += TEXT_SIZE;
|
|
if(m_headerData) m_interleavedDataFullSize += HEADER_SIZE;
|
|
if(m_gpsData) m_interleavedDataFullSize += m_gpsDataSize;
|
|
m_interleavedDataFullSize = SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_interleavedDataFullSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE));
|
|
return m_interleavedDataFullSize;
|
|
}
|
|
|
|
void CSlowDataEncoder::sync()
|
|
{
|
|
m_headerPtr = 0U;
|
|
m_textPtr = 0U;
|
|
m_gpsPtr = 0U;
|
|
m_interleavedPtr = 0U;
|
|
}
|
|
|
|
void CSlowDataEncoder::reset()
|
|
{
|
|
clearHeaderData();
|
|
clearTextData();
|
|
clearGPSData();
|
|
clearInterleavedData();
|
|
}
|
|
|
|
void CSlowDataEncoder::setHeaderData(const CHeaderData& header)
|
|
{
|
|
clearInterleavedData();
|
|
if(!m_headerData) m_headerData = new unsigned char[SLOW_DATA_FULL_BLOCK_SIZE];
|
|
::memset(m_headerData, 'f', SLOW_DATA_FULL_BLOCK_SIZE);
|
|
|
|
m_headerData[0U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[1U] = header.getFlag1();
|
|
m_headerData[2U] = header.getFlag2();
|
|
m_headerData[3U] = header.getFlag3();
|
|
m_headerData[4U] = header.getRptCall2().GetChar(0);
|
|
m_headerData[5U] = header.getRptCall2().GetChar(1);
|
|
|
|
m_headerData[6U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[7U] = header.getRptCall2().GetChar(2);
|
|
m_headerData[8U] = header.getRptCall2().GetChar(3);
|
|
m_headerData[9U] = header.getRptCall2().GetChar(4);
|
|
m_headerData[10U] = header.getRptCall2().GetChar(5);
|
|
m_headerData[11U] = header.getRptCall2().GetChar(6);
|
|
|
|
m_headerData[12U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[13U] = header.getRptCall2().GetChar(7);
|
|
m_headerData[14U] = header.getRptCall1().GetChar(0);
|
|
m_headerData[15U] = header.getRptCall1().GetChar(1);
|
|
m_headerData[16U] = header.getRptCall1().GetChar(2);
|
|
m_headerData[17U] = header.getRptCall1().GetChar(3);
|
|
|
|
m_headerData[18U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[19U] = header.getRptCall1().GetChar(4);
|
|
m_headerData[20U] = header.getRptCall1().GetChar(5);
|
|
m_headerData[21U] = header.getRptCall1().GetChar(6);
|
|
m_headerData[22U] = header.getRptCall1().GetChar(7);
|
|
m_headerData[23U] = header.getYourCall().GetChar(0);
|
|
|
|
m_headerData[24U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[25U] = header.getYourCall().GetChar(1);
|
|
m_headerData[26U] = header.getYourCall().GetChar(2);
|
|
m_headerData[27U] = header.getYourCall().GetChar(3);
|
|
m_headerData[28U] = header.getYourCall().GetChar(4);
|
|
m_headerData[29U] = header.getYourCall().GetChar(5);
|
|
|
|
m_headerData[30U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[31U] = header.getYourCall().GetChar(6);
|
|
m_headerData[32U] = header.getYourCall().GetChar(7);
|
|
m_headerData[33U] = header.getMyCall1().GetChar(0);
|
|
m_headerData[34U] = header.getMyCall1().GetChar(1);
|
|
m_headerData[35U] = header.getMyCall1().GetChar(2);
|
|
|
|
m_headerData[36U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[37U] = header.getMyCall1().GetChar(3);
|
|
m_headerData[38U] = header.getMyCall1().GetChar(4);
|
|
m_headerData[39U] = header.getMyCall1().GetChar(5);
|
|
m_headerData[40U] = header.getMyCall1().GetChar(6);
|
|
m_headerData[41U] = header.getMyCall1().GetChar(7);
|
|
|
|
m_headerData[42U] = SLOW_DATA_TYPE_HEADER | 5U;
|
|
m_headerData[43U] = header.getMyCall2().GetChar(0);
|
|
m_headerData[44U] = header.getMyCall2().GetChar(1);
|
|
m_headerData[45U] = header.getMyCall2().GetChar(2);
|
|
m_headerData[46U] = header.getMyCall2().GetChar(3);
|
|
|
|
CCCITTChecksum cksum;
|
|
cksum.update(m_headerData + 1U, 5U);
|
|
cksum.update(m_headerData + 7U, 5U);
|
|
cksum.update(m_headerData + 13U, 5U);
|
|
cksum.update(m_headerData + 19U, 5U);
|
|
cksum.update(m_headerData + 25U, 5U);
|
|
cksum.update(m_headerData + 31U, 5U);
|
|
cksum.update(m_headerData + 37U, 5U);
|
|
cksum.update(m_headerData + 43U, 4U);
|
|
|
|
unsigned char checkSum[2U];
|
|
cksum.result(checkSum);
|
|
|
|
m_headerData[47U] = checkSum[0];
|
|
|
|
m_headerData[48U] = SLOW_DATA_TYPE_HEADER | 1U;
|
|
m_headerData[49U] = checkSum[1];
|
|
|
|
m_headerPtr = 0U;
|
|
}
|
|
|
|
void CSlowDataEncoder::setTextData(const wxString& text)
|
|
{
|
|
clearInterleavedData();
|
|
if(!m_textData) m_textData = new unsigned char[SLOW_DATA_FULL_BLOCK_SIZE];
|
|
::memset(m_textData, 'f', SLOW_DATA_FULL_BLOCK_SIZE);
|
|
|
|
wxString paddedText = text;
|
|
paddedText.Append(wxT(" "));
|
|
paddedText.Truncate(20U);
|
|
|
|
m_textData[0U] = SLOW_DATA_TYPE_TEXT | 0U;
|
|
m_textData[1U] = paddedText.GetChar(0);
|
|
m_textData[2U] = paddedText.GetChar(1);
|
|
m_textData[3U] = paddedText.GetChar(2);
|
|
m_textData[4U] = paddedText.GetChar(3);
|
|
m_textData[5U] = paddedText.GetChar(4);
|
|
|
|
m_textData[6U] = SLOW_DATA_TYPE_TEXT | 1U;
|
|
m_textData[7U] = paddedText.GetChar(5);
|
|
m_textData[8U] = paddedText.GetChar(6);
|
|
m_textData[9U] = paddedText.GetChar(7);
|
|
m_textData[10U] = paddedText.GetChar(8);
|
|
m_textData[11U] = paddedText.GetChar(9);
|
|
|
|
m_textData[12U] = SLOW_DATA_TYPE_TEXT | 2U;
|
|
m_textData[13U] = paddedText.GetChar(10);
|
|
m_textData[14U] = paddedText.GetChar(11);
|
|
m_textData[15U] = paddedText.GetChar(12);
|
|
m_textData[16U] = paddedText.GetChar(13);
|
|
m_textData[17U] = paddedText.GetChar(14);
|
|
|
|
m_textData[18U] = SLOW_DATA_TYPE_TEXT | 3U;
|
|
m_textData[19U] = paddedText.GetChar(15);
|
|
m_textData[20U] = paddedText.GetChar(16);
|
|
m_textData[21U] = paddedText.GetChar(17);
|
|
m_textData[22U] = paddedText.GetChar(18);
|
|
m_textData[23U] = paddedText.GetChar(19);
|
|
|
|
m_textPtr = 0U;
|
|
}
|
|
|
|
void CSlowDataEncoder::setGPSData(const wxString& gpsData)
|
|
{
|
|
size_t gpsDataStrLen;
|
|
clearInterleavedData();
|
|
|
|
if(m_gpsData) delete[] m_gpsData;
|
|
m_gpsDataSize = 0U;
|
|
m_gpsPtr = 0U;
|
|
|
|
if((gpsDataStrLen = gpsData.length()) > 0){
|
|
unsigned int gpsDataPos;
|
|
unsigned int strPos = 0;
|
|
m_gpsDataSize = 1U + ((gpsDataStrLen - 1U) / 6U);//to make room for the type bytes
|
|
m_gpsDataSize += gpsDataStrLen;
|
|
m_gpsDataFullSize = SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_gpsDataSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE));
|
|
|
|
m_gpsData = new unsigned char[m_gpsDataFullSize];
|
|
::memset(m_gpsData, 'f', m_gpsDataFullSize);
|
|
|
|
for(gpsDataPos = 0; gpsDataPos < m_gpsDataFullSize;){
|
|
unsigned int dataLen = gpsDataStrLen - strPos < 5U ? gpsDataStrLen - strPos : 5U;
|
|
m_gpsData[gpsDataPos++] = SLOW_DATA_TYPE_GPS | dataLen;
|
|
|
|
for(unsigned int i = 0U; i < dataLen; i++){
|
|
m_gpsData[gpsDataPos++] = gpsData.GetChar(strPos++);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|