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.

159 lines
3.7 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"
#include <cassert>
#include <cstring>
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(nullptr),
m_state(SDD_FIRST),
m_headerData(nullptr),
m_headerPtr(0U),
m_header(nullptr)
{
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)
{
assert(data != nullptr);
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 == nullptr)
return nullptr;
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 = nullptr;
}
void CSlowDataDecoder::processHeader()
{
// Do we have a complete and valid header already?
if (m_header != nullptr)
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;
}

Powered by TurnKey Linux.