You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.6 KiB
156 lines
3.6 KiB
/*
|
|
* Copyright (C) 2009,2010,2011 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 "CCITTChecksumReverse.h"
|
|
#include "SlowDataDecoder.h"
|
|
#include "DStarDefines.h"
|
|
|
|
const unsigned int SLOW_DATA_BLOCK_SIZE = 6U;
|
|
|
|
const unsigned int SLOW_DATA_FULL_BLOCK_SIZE = (SLOW_DATA_BLOCK_SIZE - 1U) * 10U;
|
|
|
|
CSlowDataDecoder::CSlowDataDecoder() :
|
|
m_buffer(NULL),
|
|
m_state(SDD_FIRST),
|
|
m_headerData(NULL),
|
|
m_headerPtr(0U),
|
|
m_header(NULL)
|
|
{
|
|
m_buffer = new unsigned char[SLOW_DATA_BLOCK_SIZE];
|
|
m_headerData = new unsigned char[SLOW_DATA_FULL_BLOCK_SIZE];
|
|
}
|
|
|
|
CSlowDataDecoder::~CSlowDataDecoder()
|
|
{
|
|
delete[] m_buffer;
|
|
delete[] m_headerData;
|
|
|
|
delete m_header;
|
|
}
|
|
|
|
void CSlowDataDecoder::addData(const unsigned char* data)
|
|
{
|
|
wxASSERT(data != NULL);
|
|
|
|
switch (m_state) {
|
|
case SDD_FIRST:
|
|
m_buffer[0] = data[0] ^ SCRAMBLER_BYTE1;
|
|
m_buffer[1] = data[1] ^ SCRAMBLER_BYTE2;
|
|
m_buffer[2] = data[2] ^ SCRAMBLER_BYTE3;
|
|
m_state = SDD_SECOND;
|
|
return;
|
|
|
|
case SDD_SECOND:
|
|
m_buffer[3] = data[0] ^ SCRAMBLER_BYTE1;
|
|
m_buffer[4] = data[1] ^ SCRAMBLER_BYTE2;
|
|
m_buffer[5] = data[2] ^ SCRAMBLER_BYTE3;
|
|
m_state = SDD_FIRST;
|
|
processHeader();
|
|
break;
|
|
}
|
|
}
|
|
|
|
CHeaderData* CSlowDataDecoder::getHeaderData()
|
|
{
|
|
if (m_header == NULL)
|
|
return NULL;
|
|
|
|
CHeaderData* temp = new CHeaderData(*m_header);
|
|
|
|
reset();
|
|
|
|
return temp;
|
|
}
|
|
|
|
void CSlowDataDecoder::sync()
|
|
{
|
|
m_headerPtr = 0U;
|
|
|
|
m_state = SDD_FIRST;
|
|
}
|
|
|
|
void CSlowDataDecoder::reset()
|
|
{
|
|
m_headerPtr = 0U;
|
|
|
|
m_state = SDD_FIRST;
|
|
|
|
::memset(m_headerData, 0x00, SLOW_DATA_FULL_BLOCK_SIZE * sizeof(unsigned char));
|
|
|
|
delete m_header;
|
|
m_header = NULL;
|
|
}
|
|
|
|
void CSlowDataDecoder::processHeader()
|
|
{
|
|
// Do we have a complete and valid header already?
|
|
if (m_header != NULL)
|
|
return;
|
|
|
|
for (unsigned int i = 1U; i <= (SLOW_DATA_BLOCK_SIZE - 1U); i++, m_headerPtr++) {
|
|
m_headerData[m_headerPtr] = m_buffer[i];
|
|
|
|
if (m_headerPtr >= SLOW_DATA_FULL_BLOCK_SIZE)
|
|
m_headerPtr = 0U;
|
|
}
|
|
|
|
// Look for a header starting immediately after the data sync
|
|
bool res = processHeader(m_headerData);
|
|
if (res)
|
|
return;
|
|
|
|
// Look for a header starting one block after the data sync
|
|
processHeader(m_headerData + SLOW_DATA_BLOCK_SIZE - 1U);
|
|
}
|
|
|
|
bool CSlowDataDecoder::processHeader(const unsigned char* bytes)
|
|
{
|
|
unsigned char buffer[RADIO_HEADER_LENGTH_BYTES];
|
|
|
|
// Clean up the header data
|
|
for (unsigned int n = 0U; n < RADIO_HEADER_LENGTH_BYTES; n++) {
|
|
switch (n) {
|
|
case 0U: // Flag 1
|
|
// Only allow BK and EMR bits and always assert the repeater bit
|
|
buffer[n] = (bytes[n] & (INTERRUPTED_MASK | URGENT_MASK)) | REPEATER_MASK;
|
|
break;
|
|
case 1U: // Flag 2
|
|
case 2U: // Flag 3
|
|
// Always 0x00 in current implementations
|
|
buffer[n] = 0x00;
|
|
break;
|
|
case 39U: // Checksum 1
|
|
case 40U: // Checksum 2
|
|
// These bytes can be any value
|
|
buffer[n] = bytes[n];
|
|
break;
|
|
default: // Callsign text
|
|
// Only ASCII text so MSB is always clear
|
|
buffer[n] = bytes[n] & 0x7F;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CCCITTChecksumReverse cksum;
|
|
cksum.update(buffer, RADIO_HEADER_LENGTH_BYTES - 2U);
|
|
|
|
bool valid = cksum.check(buffer + RADIO_HEADER_LENGTH_BYTES - 2U);
|
|
if (!valid)
|
|
return false;
|
|
|
|
// The checksum has already been checked
|
|
m_header = new CHeaderData(buffer, RADIO_HEADER_LENGTH_BYTES, false);
|
|
|
|
return true;
|
|
}
|