Merge branch 'M17_AX25_FM' into I2C
This commit is contained in:
commit
4d08e23127
12 changed files with 3294 additions and 3289 deletions
|
@ -147,23 +147,28 @@ bool CPOCSAGControl::readNetwork()
|
|||
|
||||
addAddress(functional, output->m_ric, output->m_buffer);
|
||||
|
||||
char rubric[20U];
|
||||
std::string out;
|
||||
|
||||
switch (functional) {
|
||||
case FUNCTIONAL_ALPHANUMERIC:
|
||||
output->m_text = std::string((char*)(data + 4U), length - 4U);
|
||||
switch (output->m_ric) {
|
||||
case 4512U:
|
||||
decodeROT1(output->m_text, 3U, output->m_display);
|
||||
LogDebug("Message to %07u, func Alphanumeric: (%u) \"%s\"", output->m_ric, output->m_text.at(1U) - 0x1FU, output->m_display.c_str());
|
||||
::sprintf(rubric, "(%u) \"", output->m_text.at(1U) - 0x1FU);
|
||||
decodeROT1(output->m_text, 3U, out);
|
||||
output->m_display = rubric + out + "\"";
|
||||
break;
|
||||
case 4520U:
|
||||
decodeROT1(output->m_text, 2U, output->m_display);
|
||||
LogDebug("Message to %07u, func Alphanumeric: (%u-%u) \"%s\"", output->m_ric, output->m_text.at(0U) - 0x1FU, output->m_text.at(1U) - 0x20U, output->m_display.c_str());
|
||||
::sprintf(rubric, "(%u-%u) \"", output->m_text.at(0U) - 0x1FU, output->m_text.at(1U) - 0x20U);
|
||||
decodeROT1(output->m_text, 2U, out);
|
||||
output->m_display = rubric + out + "\"";
|
||||
break;
|
||||
default:
|
||||
output->m_display = output->m_text;
|
||||
LogDebug("Message to %07u, func Alphanumeric: \"%s\"", output->m_ric, output->m_display.c_str());
|
||||
output->m_display = "\"" + output->m_text + "\"";
|
||||
break;
|
||||
}
|
||||
LogDebug("Message to %07u, func Alphanumeric: %s", output->m_ric, output->m_display.c_str());
|
||||
packASCII(output->m_text, output->m_buffer);
|
||||
break;
|
||||
case FUNCTIONAL_NUMERIC:
|
||||
|
|
2458
YSFControl.cpp
2458
YSFControl.cpp
File diff suppressed because it is too large
Load diff
224
YSFControl.h
224
YSFControl.h
|
@ -1,112 +1,112 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2020 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(YSFControl_H)
|
||||
#define YSFControl_H
|
||||
|
||||
#include "RSSIInterpolator.h"
|
||||
#include "YSFNetwork.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "YSFPayload.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "StopWatch.h"
|
||||
#include "YSFFICH.h"
|
||||
#include "Display.h"
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Modem.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CYSFControl {
|
||||
public:
|
||||
CYSFControl(const std::string& callsign, bool selfOnly, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool lowDeviation, bool remoteGateway, CRSSIInterpolator* rssiMapper);
|
||||
~CYSFControl();
|
||||
|
||||
bool writeModem(unsigned char* data, unsigned int len);
|
||||
|
||||
unsigned int readModem(unsigned char* data);
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
bool isBusy() const;
|
||||
|
||||
void enable(bool enabled);
|
||||
|
||||
private:
|
||||
unsigned char* m_callsign;
|
||||
unsigned char* m_selfCallsign;
|
||||
bool m_selfOnly;
|
||||
CYSFNetwork* m_network;
|
||||
CDisplay* m_display;
|
||||
bool m_duplex;
|
||||
bool m_lowDeviation;
|
||||
bool m_remoteGateway;
|
||||
CRingBuffer<unsigned char> m_queue;
|
||||
RPT_RF_STATE m_rfState;
|
||||
RPT_NET_STATE m_netState;
|
||||
CTimer m_rfTimeoutTimer;
|
||||
CTimer m_netTimeoutTimer;
|
||||
CTimer m_packetTimer;
|
||||
CTimer m_networkWatchdog;
|
||||
CStopWatch m_elapsed;
|
||||
unsigned int m_rfFrames;
|
||||
unsigned int m_netFrames;
|
||||
unsigned int m_netLost;
|
||||
unsigned int m_rfErrs;
|
||||
unsigned int m_rfBits;
|
||||
unsigned int m_netErrs;
|
||||
unsigned int m_netBits;
|
||||
unsigned char* m_rfSource;
|
||||
unsigned char* m_rfDest;
|
||||
unsigned char* m_netSource;
|
||||
unsigned char* m_netDest;
|
||||
CYSFFICH m_lastFICH;
|
||||
unsigned char m_netN;
|
||||
CYSFPayload m_rfPayload;
|
||||
CYSFPayload m_netPayload;
|
||||
CRSSIInterpolator* m_rssiMapper;
|
||||
unsigned char m_rssi;
|
||||
unsigned char m_maxRSSI;
|
||||
unsigned char m_minRSSI;
|
||||
unsigned int m_aveRSSI;
|
||||
unsigned int m_rssiCount;
|
||||
bool m_enabled;
|
||||
FILE* m_fp;
|
||||
|
||||
bool processVWData(bool valid, unsigned char *data);
|
||||
bool processDNData(bool valid, unsigned char *data);
|
||||
bool processFRData(bool valid, unsigned char *data);
|
||||
|
||||
void writeQueueRF(const unsigned char* data);
|
||||
void writeQueueNet(const unsigned char* data);
|
||||
void writeNetwork(const unsigned char* data, unsigned int count);
|
||||
void writeNetwork();
|
||||
|
||||
void writeEndRF();
|
||||
void writeEndNet();
|
||||
|
||||
bool openFile();
|
||||
bool writeFile(const unsigned char* data);
|
||||
void closeFile();
|
||||
|
||||
bool checkCallsign(const unsigned char* callsign) const;
|
||||
void processNetCallsigns(const unsigned char* data, unsigned char dgid);
|
||||
};
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (C) 2015-2020 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(YSFControl_H)
|
||||
#define YSFControl_H
|
||||
|
||||
#include "RSSIInterpolator.h"
|
||||
#include "YSFNetwork.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "YSFPayload.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "StopWatch.h"
|
||||
#include "YSFFICH.h"
|
||||
#include "Display.h"
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Modem.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CYSFControl {
|
||||
public:
|
||||
CYSFControl(const std::string& callsign, bool selfOnly, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool lowDeviation, bool remoteGateway, CRSSIInterpolator* rssiMapper);
|
||||
~CYSFControl();
|
||||
|
||||
bool writeModem(unsigned char* data, unsigned int len);
|
||||
|
||||
unsigned int readModem(unsigned char* data);
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
bool isBusy() const;
|
||||
|
||||
void enable(bool enabled);
|
||||
|
||||
private:
|
||||
unsigned char* m_callsign;
|
||||
unsigned char* m_selfCallsign;
|
||||
bool m_selfOnly;
|
||||
CYSFNetwork* m_network;
|
||||
CDisplay* m_display;
|
||||
bool m_duplex;
|
||||
bool m_lowDeviation;
|
||||
bool m_remoteGateway;
|
||||
CRingBuffer<unsigned char> m_queue;
|
||||
RPT_RF_STATE m_rfState;
|
||||
RPT_NET_STATE m_netState;
|
||||
CTimer m_rfTimeoutTimer;
|
||||
CTimer m_netTimeoutTimer;
|
||||
CTimer m_packetTimer;
|
||||
CTimer m_networkWatchdog;
|
||||
CStopWatch m_elapsed;
|
||||
unsigned int m_rfFrames;
|
||||
unsigned int m_netFrames;
|
||||
unsigned int m_netLost;
|
||||
unsigned int m_rfErrs;
|
||||
unsigned int m_rfBits;
|
||||
unsigned int m_netErrs;
|
||||
unsigned int m_netBits;
|
||||
unsigned char* m_rfSource;
|
||||
unsigned char* m_rfDest;
|
||||
unsigned char* m_netSource;
|
||||
unsigned char* m_netDest;
|
||||
CYSFFICH m_lastFICH;
|
||||
unsigned char m_netN;
|
||||
CYSFPayload m_rfPayload;
|
||||
CYSFPayload m_netPayload;
|
||||
CRSSIInterpolator* m_rssiMapper;
|
||||
unsigned char m_rssi;
|
||||
unsigned char m_maxRSSI;
|
||||
unsigned char m_minRSSI;
|
||||
unsigned int m_aveRSSI;
|
||||
unsigned int m_rssiCount;
|
||||
bool m_enabled;
|
||||
FILE* m_fp;
|
||||
|
||||
bool processVWData(bool valid, unsigned char *data);
|
||||
bool processDNData(bool valid, unsigned char *data);
|
||||
bool processFRData(bool valid, unsigned char *data);
|
||||
|
||||
void writeQueueRF(const unsigned char* data);
|
||||
void writeQueueNet(const unsigned char* data);
|
||||
void writeNetwork(const unsigned char* data, unsigned int count);
|
||||
void writeNetwork();
|
||||
|
||||
void writeEndRF();
|
||||
void writeEndNet();
|
||||
|
||||
bool openFile();
|
||||
bool writeFile(const unsigned char* data);
|
||||
void closeFile();
|
||||
|
||||
bool checkCallsign(const unsigned char* callsign) const;
|
||||
void processNetCallsigns(const unsigned char* data, unsigned char dgid);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,141 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2009-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 "YSFConvolution.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
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])
|
||||
|
||||
const uint8_t BRANCH_TABLE1[] = {0U, 0U, 0U, 0U, 1U, 1U, 1U, 1U};
|
||||
const uint8_t BRANCH_TABLE2[] = {0U, 1U, 1U, 0U, 0U, 1U, 1U, 0U};
|
||||
|
||||
const unsigned int NUM_OF_STATES_D2 = 8U;
|
||||
const unsigned int NUM_OF_STATES = 16U;
|
||||
const uint32_t M = 2U;
|
||||
const unsigned int K = 5U;
|
||||
|
||||
CYSFConvolution::CYSFConvolution() :
|
||||
m_metrics1(NULL),
|
||||
m_metrics2(NULL),
|
||||
m_oldMetrics(NULL),
|
||||
m_newMetrics(NULL),
|
||||
m_decisions(NULL),
|
||||
m_dp(NULL)
|
||||
{
|
||||
m_metrics1 = new uint16_t[16U];
|
||||
m_metrics2 = new uint16_t[16U];
|
||||
m_decisions = new uint64_t[180U];
|
||||
}
|
||||
|
||||
CYSFConvolution::~CYSFConvolution()
|
||||
{
|
||||
delete[] m_metrics1;
|
||||
delete[] m_metrics2;
|
||||
delete[] m_decisions;
|
||||
}
|
||||
|
||||
void CYSFConvolution::start()
|
||||
{
|
||||
::memset(m_metrics1, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
|
||||
::memset(m_metrics2, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
|
||||
|
||||
m_oldMetrics = m_metrics1;
|
||||
m_newMetrics = m_metrics2;
|
||||
m_dp = m_decisions;
|
||||
}
|
||||
|
||||
void CYSFConvolution::decode(uint8_t s0, uint8_t s1)
|
||||
{
|
||||
*m_dp = 0U;
|
||||
|
||||
for (uint8_t i = 0U; i < NUM_OF_STATES_D2; i++) {
|
||||
uint8_t j = i * 2U;
|
||||
|
||||
uint16_t metric = (BRANCH_TABLE1[i] ^ s0) + (BRANCH_TABLE2[i] ^ s1);
|
||||
|
||||
uint16_t m0 = m_oldMetrics[i] + metric;
|
||||
uint16_t m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + (M - metric);
|
||||
uint8_t decision0 = (m0 >= m1) ? 1U : 0U;
|
||||
m_newMetrics[j + 0U] = decision0 != 0U ? m1 : m0;
|
||||
|
||||
m0 = m_oldMetrics[i] + (M - metric);
|
||||
m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + metric;
|
||||
uint8_t decision1 = (m0 >= m1) ? 1U : 0U;
|
||||
m_newMetrics[j + 1U] = decision1 != 0U ? m1 : m0;
|
||||
|
||||
*m_dp |= (uint64_t(decision1) << (j + 1U)) | (uint64_t(decision0) << (j + 0U));
|
||||
}
|
||||
|
||||
++m_dp;
|
||||
|
||||
assert((m_dp - m_decisions) <= 180);
|
||||
|
||||
uint16_t* tmp = m_oldMetrics;
|
||||
m_oldMetrics = m_newMetrics;
|
||||
m_newMetrics = tmp;
|
||||
}
|
||||
|
||||
void CYSFConvolution::chainback(unsigned char* out, unsigned int nBits)
|
||||
{
|
||||
assert(out != NULL);
|
||||
|
||||
uint32_t state = 0U;
|
||||
|
||||
while (nBits-- > 0) {
|
||||
--m_dp;
|
||||
|
||||
uint32_t i = state >> (9 - K);
|
||||
uint8_t bit = uint8_t(*m_dp >> i) & 1;
|
||||
state = (bit << 7) | (state >> 1);
|
||||
|
||||
WRITE_BIT1(out, nBits, bit != 0U);
|
||||
}
|
||||
}
|
||||
|
||||
void CYSFConvolution::encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const
|
||||
{
|
||||
assert(in != NULL);
|
||||
assert(out != NULL);
|
||||
assert(nBits > 0U);
|
||||
|
||||
uint8_t d1 = 0U, d2 = 0U, d3 = 0U, d4 = 0U;
|
||||
uint32_t k = 0U;
|
||||
for (unsigned int i = 0U; i < nBits; i++) {
|
||||
uint8_t d = READ_BIT1(in, i) ? 1U : 0U;
|
||||
|
||||
uint8_t g1 = (d + d3 + d4) & 1;
|
||||
uint8_t g2 = (d + d1 + d2 + d4) & 1;
|
||||
|
||||
d4 = d3;
|
||||
d3 = d2;
|
||||
d2 = d1;
|
||||
d1 = d;
|
||||
|
||||
WRITE_BIT1(out, k, g1 != 0U);
|
||||
k++;
|
||||
|
||||
WRITE_BIT1(out, k, g2 != 0U);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2009-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 "YSFConvolution.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
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])
|
||||
|
||||
const uint8_t BRANCH_TABLE1[] = {0U, 0U, 0U, 0U, 1U, 1U, 1U, 1U};
|
||||
const uint8_t BRANCH_TABLE2[] = {0U, 1U, 1U, 0U, 0U, 1U, 1U, 0U};
|
||||
|
||||
const unsigned int NUM_OF_STATES_D2 = 8U;
|
||||
const unsigned int NUM_OF_STATES = 16U;
|
||||
const uint32_t M = 2U;
|
||||
const unsigned int K = 5U;
|
||||
|
||||
CYSFConvolution::CYSFConvolution() :
|
||||
m_metrics1(NULL),
|
||||
m_metrics2(NULL),
|
||||
m_oldMetrics(NULL),
|
||||
m_newMetrics(NULL),
|
||||
m_decisions(NULL),
|
||||
m_dp(NULL)
|
||||
{
|
||||
m_metrics1 = new uint16_t[16U];
|
||||
m_metrics2 = new uint16_t[16U];
|
||||
m_decisions = new uint64_t[180U];
|
||||
}
|
||||
|
||||
CYSFConvolution::~CYSFConvolution()
|
||||
{
|
||||
delete[] m_metrics1;
|
||||
delete[] m_metrics2;
|
||||
delete[] m_decisions;
|
||||
}
|
||||
|
||||
void CYSFConvolution::start()
|
||||
{
|
||||
::memset(m_metrics1, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
|
||||
::memset(m_metrics2, 0x00U, NUM_OF_STATES * sizeof(uint16_t));
|
||||
|
||||
m_oldMetrics = m_metrics1;
|
||||
m_newMetrics = m_metrics2;
|
||||
m_dp = m_decisions;
|
||||
}
|
||||
|
||||
void CYSFConvolution::decode(uint8_t s0, uint8_t s1)
|
||||
{
|
||||
*m_dp = 0U;
|
||||
|
||||
for (uint8_t i = 0U; i < NUM_OF_STATES_D2; i++) {
|
||||
uint8_t j = i * 2U;
|
||||
|
||||
uint16_t metric = (BRANCH_TABLE1[i] ^ s0) + (BRANCH_TABLE2[i] ^ s1);
|
||||
|
||||
uint16_t m0 = m_oldMetrics[i] + metric;
|
||||
uint16_t m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + (M - metric);
|
||||
uint8_t decision0 = (m0 >= m1) ? 1U : 0U;
|
||||
m_newMetrics[j + 0U] = decision0 != 0U ? m1 : m0;
|
||||
|
||||
m0 = m_oldMetrics[i] + (M - metric);
|
||||
m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + metric;
|
||||
uint8_t decision1 = (m0 >= m1) ? 1U : 0U;
|
||||
m_newMetrics[j + 1U] = decision1 != 0U ? m1 : m0;
|
||||
|
||||
*m_dp |= (uint64_t(decision1) << (j + 1U)) | (uint64_t(decision0) << (j + 0U));
|
||||
}
|
||||
|
||||
++m_dp;
|
||||
|
||||
assert((m_dp - m_decisions) <= 180);
|
||||
|
||||
uint16_t* tmp = m_oldMetrics;
|
||||
m_oldMetrics = m_newMetrics;
|
||||
m_newMetrics = tmp;
|
||||
}
|
||||
|
||||
void CYSFConvolution::chainback(unsigned char* out, unsigned int nBits)
|
||||
{
|
||||
assert(out != NULL);
|
||||
|
||||
uint32_t state = 0U;
|
||||
|
||||
while (nBits-- > 0) {
|
||||
--m_dp;
|
||||
|
||||
uint32_t i = state >> (9 - K);
|
||||
uint8_t bit = uint8_t(*m_dp >> i) & 1;
|
||||
state = (bit << 7) | (state >> 1);
|
||||
|
||||
WRITE_BIT1(out, nBits, bit != 0U);
|
||||
}
|
||||
}
|
||||
|
||||
void CYSFConvolution::encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const
|
||||
{
|
||||
assert(in != NULL);
|
||||
assert(out != NULL);
|
||||
assert(nBits > 0U);
|
||||
|
||||
uint8_t d1 = 0U, d2 = 0U, d3 = 0U, d4 = 0U;
|
||||
uint32_t k = 0U;
|
||||
for (unsigned int i = 0U; i < nBits; i++) {
|
||||
uint8_t d = READ_BIT1(in, i) ? 1U : 0U;
|
||||
|
||||
uint8_t g1 = (d + d3 + d4) & 1;
|
||||
uint8_t g2 = (d + d1 + d2 + d4) & 1;
|
||||
|
||||
d4 = d3;
|
||||
d3 = d2;
|
||||
d2 = d1;
|
||||
d1 = d;
|
||||
|
||||
WRITE_BIT1(out, k, g1 != 0U);
|
||||
k++;
|
||||
|
||||
WRITE_BIT1(out, k, g2 != 0U);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,45 +1,45 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !defined(YSFConvolution_H)
|
||||
#define YSFConvolution_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class CYSFConvolution {
|
||||
public:
|
||||
CYSFConvolution();
|
||||
~CYSFConvolution();
|
||||
|
||||
void start();
|
||||
void decode(uint8_t s0, uint8_t s1);
|
||||
void chainback(unsigned char* out, unsigned int nBits);
|
||||
|
||||
void encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const;
|
||||
|
||||
private:
|
||||
uint16_t* m_metrics1;
|
||||
uint16_t* m_metrics2;
|
||||
uint16_t* m_oldMetrics;
|
||||
uint16_t* m_newMetrics;
|
||||
uint64_t* m_decisions;
|
||||
uint64_t* m_dp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !defined(YSFConvolution_H)
|
||||
#define YSFConvolution_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class CYSFConvolution {
|
||||
public:
|
||||
CYSFConvolution();
|
||||
~CYSFConvolution();
|
||||
|
||||
void start();
|
||||
void decode(uint8_t s0, uint8_t s1);
|
||||
void chainback(unsigned char* out, unsigned int nBits);
|
||||
|
||||
void encode(const unsigned char* in, unsigned char* out, unsigned int nBits) const;
|
||||
|
||||
private:
|
||||
uint16_t* m_metrics1;
|
||||
uint16_t* m_metrics2;
|
||||
uint16_t* m_oldMetrics;
|
||||
uint16_t* m_newMetrics;
|
||||
uint64_t* m_decisions;
|
||||
uint64_t* m_dp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
106
YSFDefines.h
106
YSFDefines.h
|
@ -1,53 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017 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(YSFDefines_H)
|
||||
#define YSFDefines_H
|
||||
|
||||
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
|
||||
|
||||
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
|
||||
const unsigned int YSF_SYNC_LENGTH_BYTES = 5U;
|
||||
|
||||
const unsigned int YSF_FICH_LENGTH_BYTES = 25U;
|
||||
|
||||
const unsigned char YSF_SYNC_OK = 0x01U;
|
||||
|
||||
const unsigned int YSF_CALLSIGN_LENGTH = 10U;
|
||||
|
||||
const unsigned int YSF_FRAME_TIME = 100U;
|
||||
|
||||
const unsigned char YSF_FI_HEADER = 0x00U;
|
||||
const unsigned char YSF_FI_COMMUNICATIONS = 0x01U;
|
||||
const unsigned char YSF_FI_TERMINATOR = 0x02U;
|
||||
const unsigned char YSF_FI_TEST = 0x03U;
|
||||
|
||||
const unsigned char YSF_DT_VD_MODE1 = 0x00U;
|
||||
const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
|
||||
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
|
||||
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
|
||||
|
||||
const unsigned char YSF_CM_GROUP1 = 0x00U;
|
||||
const unsigned char YSF_CM_GROUP2 = 0x01U;
|
||||
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
|
||||
|
||||
const unsigned char YSF_MR_DIRECT = 0x00U;
|
||||
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
|
||||
const unsigned char YSF_MR_BUSY = 0x02U;
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2017 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(YSFDefines_H)
|
||||
#define YSFDefines_H
|
||||
|
||||
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
|
||||
|
||||
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
|
||||
const unsigned int YSF_SYNC_LENGTH_BYTES = 5U;
|
||||
|
||||
const unsigned int YSF_FICH_LENGTH_BYTES = 25U;
|
||||
|
||||
const unsigned char YSF_SYNC_OK = 0x01U;
|
||||
|
||||
const unsigned int YSF_CALLSIGN_LENGTH = 10U;
|
||||
|
||||
const unsigned int YSF_FRAME_TIME = 100U;
|
||||
|
||||
const unsigned char YSF_FI_HEADER = 0x00U;
|
||||
const unsigned char YSF_FI_COMMUNICATIONS = 0x01U;
|
||||
const unsigned char YSF_FI_TERMINATOR = 0x02U;
|
||||
const unsigned char YSF_FI_TEST = 0x03U;
|
||||
|
||||
const unsigned char YSF_DT_VD_MODE1 = 0x00U;
|
||||
const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
|
||||
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
|
||||
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
|
||||
|
||||
const unsigned char YSF_CM_GROUP1 = 0x00U;
|
||||
const unsigned char YSF_CM_GROUP2 = 0x01U;
|
||||
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
|
||||
|
||||
const unsigned char YSF_MR_DIRECT = 0x00U;
|
||||
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
|
||||
const unsigned char YSF_MR_BUSY = 0x02U;
|
||||
|
||||
#endif
|
||||
|
|
572
YSFFICH.cpp
572
YSFFICH.cpp
|
@ -1,286 +1,286 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017,2019,2020 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 "YSFConvolution.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "Golay24128.h"
|
||||
#include "YSFFICH.h"
|
||||
#include "CRC.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
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])
|
||||
|
||||
const unsigned int INTERLEAVE_TABLE[] = {
|
||||
0U, 40U, 80U, 120U, 160U,
|
||||
2U, 42U, 82U, 122U, 162U,
|
||||
4U, 44U, 84U, 124U, 164U,
|
||||
6U, 46U, 86U, 126U, 166U,
|
||||
8U, 48U, 88U, 128U, 168U,
|
||||
10U, 50U, 90U, 130U, 170U,
|
||||
12U, 52U, 92U, 132U, 172U,
|
||||
14U, 54U, 94U, 134U, 174U,
|
||||
16U, 56U, 96U, 136U, 176U,
|
||||
18U, 58U, 98U, 138U, 178U,
|
||||
20U, 60U, 100U, 140U, 180U,
|
||||
22U, 62U, 102U, 142U, 182U,
|
||||
24U, 64U, 104U, 144U, 184U,
|
||||
26U, 66U, 106U, 146U, 186U,
|
||||
28U, 68U, 108U, 148U, 188U,
|
||||
30U, 70U, 110U, 150U, 190U,
|
||||
32U, 72U, 112U, 152U, 192U,
|
||||
34U, 74U, 114U, 154U, 194U,
|
||||
36U, 76U, 116U, 156U, 196U,
|
||||
38U, 78U, 118U, 158U, 198U};
|
||||
|
||||
CYSFFICH::CYSFFICH(const CYSFFICH& fich) :
|
||||
m_fich(NULL)
|
||||
{
|
||||
m_fich = new unsigned char[6U];
|
||||
|
||||
::memcpy(m_fich, fich.m_fich, 6U);
|
||||
}
|
||||
|
||||
CYSFFICH::CYSFFICH() :
|
||||
m_fich(NULL)
|
||||
{
|
||||
m_fich = new unsigned char[6U];
|
||||
|
||||
memset(m_fich, 0x00U, 6U);
|
||||
}
|
||||
|
||||
CYSFFICH::~CYSFFICH()
|
||||
{
|
||||
delete[] m_fich;
|
||||
}
|
||||
|
||||
bool CYSFFICH::decode(const unsigned char* bytes)
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
// Skip the sync bytes
|
||||
bytes += YSF_SYNC_LENGTH_BYTES;
|
||||
|
||||
CYSFConvolution viterbi;
|
||||
viterbi.start();
|
||||
|
||||
// Deinterleave the FICH and send bits to the Viterbi decoder
|
||||
for (unsigned int i = 0U; i < 100U; i++) {
|
||||
unsigned int n = INTERLEAVE_TABLE[i];
|
||||
uint8_t s0 = READ_BIT1(bytes, n) ? 1U : 0U;
|
||||
|
||||
n++;
|
||||
uint8_t s1 = READ_BIT1(bytes, n) ? 1U : 0U;
|
||||
|
||||
viterbi.decode(s0, s1);
|
||||
}
|
||||
|
||||
unsigned char output[13U];
|
||||
viterbi.chainback(output, 96U);
|
||||
|
||||
unsigned int b0 = CGolay24128::decode24128(output + 0U);
|
||||
unsigned int b1 = CGolay24128::decode24128(output + 3U);
|
||||
unsigned int b2 = CGolay24128::decode24128(output + 6U);
|
||||
unsigned int b3 = CGolay24128::decode24128(output + 9U);
|
||||
|
||||
m_fich[0U] = (b0 >> 4) & 0xFFU;
|
||||
m_fich[1U] = ((b0 << 4) & 0xF0U) | ((b1 >> 8) & 0x0FU);
|
||||
m_fich[2U] = (b1 >> 0) & 0xFFU;
|
||||
m_fich[3U] = (b2 >> 4) & 0xFFU;
|
||||
m_fich[4U] = ((b2 << 4) & 0xF0U) | ((b3 >> 8) & 0x0FU);
|
||||
m_fich[5U] = (b3 >> 0) & 0xFFU;
|
||||
|
||||
return CCRC::checkCCITT162(m_fich, 6U);
|
||||
}
|
||||
|
||||
void CYSFFICH::encode(unsigned char* bytes)
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
// Skip the sync bytes
|
||||
bytes += YSF_SYNC_LENGTH_BYTES;
|
||||
|
||||
CCRC::addCCITT162(m_fich, 6U);
|
||||
|
||||
unsigned int b0 = ((m_fich[0U] << 4) & 0xFF0U) | ((m_fich[1U] >> 4) & 0x00FU);
|
||||
unsigned int b1 = ((m_fich[1U] << 8) & 0xF00U) | ((m_fich[2U] >> 0) & 0x0FFU);
|
||||
unsigned int b2 = ((m_fich[3U] << 4) & 0xFF0U) | ((m_fich[4U] >> 4) & 0x00FU);
|
||||
unsigned int b3 = ((m_fich[4U] << 8) & 0xF00U) | ((m_fich[5U] >> 0) & 0x0FFU);
|
||||
|
||||
unsigned int c0 = CGolay24128::encode24128(b0);
|
||||
unsigned int c1 = CGolay24128::encode24128(b1);
|
||||
unsigned int c2 = CGolay24128::encode24128(b2);
|
||||
unsigned int c3 = CGolay24128::encode24128(b3);
|
||||
|
||||
unsigned char conv[13U];
|
||||
conv[0U] = (c0 >> 16) & 0xFFU;
|
||||
conv[1U] = (c0 >> 8) & 0xFFU;
|
||||
conv[2U] = (c0 >> 0) & 0xFFU;
|
||||
conv[3U] = (c1 >> 16) & 0xFFU;
|
||||
conv[4U] = (c1 >> 8) & 0xFFU;
|
||||
conv[5U] = (c1 >> 0) & 0xFFU;
|
||||
conv[6U] = (c2 >> 16) & 0xFFU;
|
||||
conv[7U] = (c2 >> 8) & 0xFFU;
|
||||
conv[8U] = (c2 >> 0) & 0xFFU;
|
||||
conv[9U] = (c3 >> 16) & 0xFFU;
|
||||
conv[10U] = (c3 >> 8) & 0xFFU;
|
||||
conv[11U] = (c3 >> 0) & 0xFFU;
|
||||
conv[12U] = 0x00U;
|
||||
|
||||
CYSFConvolution convolution;
|
||||
unsigned char convolved[25U];
|
||||
convolution.encode(conv, convolved, 100U);
|
||||
|
||||
unsigned int j = 0U;
|
||||
for (unsigned int i = 0U; i < 100U; i++) {
|
||||
unsigned int n = INTERLEAVE_TABLE[i];
|
||||
|
||||
bool s0 = READ_BIT1(convolved, j) != 0U;
|
||||
j++;
|
||||
|
||||
bool s1 = READ_BIT1(convolved, j) != 0U;
|
||||
j++;
|
||||
|
||||
WRITE_BIT1(bytes, n, s0);
|
||||
|
||||
n++;
|
||||
WRITE_BIT1(bytes, n, s1);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getFI() const
|
||||
{
|
||||
return (m_fich[0U] >> 6) & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getCM() const
|
||||
{
|
||||
return (m_fich[0U] >> 2) & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getBN() const
|
||||
{
|
||||
return m_fich[0U] & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getBT() const
|
||||
{
|
||||
return (m_fich[1U] >> 6) & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getFN() const
|
||||
{
|
||||
return (m_fich[1U] >> 3) & 0x07U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getFT() const
|
||||
{
|
||||
return m_fich[1U] & 0x07U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getDT() const
|
||||
{
|
||||
return m_fich[2U] & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getMR() const
|
||||
{
|
||||
return (m_fich[2U] >> 3) & 0x03U;
|
||||
}
|
||||
|
||||
bool CYSFFICH::getDev() const
|
||||
{
|
||||
return (m_fich[2U] & 0x40U) == 0x40U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getDGId() const
|
||||
{
|
||||
return m_fich[3U] & 0x7FU;
|
||||
}
|
||||
|
||||
void CYSFFICH::setFI(unsigned char fi)
|
||||
{
|
||||
m_fich[0U] &= 0x3FU;
|
||||
m_fich[0U] |= (fi << 6) & 0xC0U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setBN(unsigned char bn)
|
||||
{
|
||||
m_fich[0U] &= 0xFCU;
|
||||
m_fich[0U] |= bn & 0x03U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setBT(unsigned char bt)
|
||||
{
|
||||
m_fich[1U] &= 0x3FU;
|
||||
m_fich[1U] |= (bt << 6) & 0xC0U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setFN(unsigned char fn)
|
||||
{
|
||||
m_fich[1U] &= 0xC7U;
|
||||
m_fich[1U] |= (fn << 3) & 0x38U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setFT(unsigned char ft)
|
||||
{
|
||||
m_fich[1U] &= 0xF8U;
|
||||
m_fich[1U] |= ft & 0x07U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setMR(unsigned char mr)
|
||||
{
|
||||
m_fich[2U] &= 0xC7U;
|
||||
m_fich[2U] |= (mr << 3) & 0x38U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setVoIP(bool on)
|
||||
{
|
||||
if (on)
|
||||
m_fich[2U] |= 0x04U;
|
||||
else
|
||||
m_fich[2U] &= 0xFBU;
|
||||
}
|
||||
|
||||
void CYSFFICH::setDev(bool on)
|
||||
{
|
||||
if (on)
|
||||
m_fich[2U] |= 0x40U;
|
||||
else
|
||||
m_fich[2U] &= 0xBFU;
|
||||
}
|
||||
|
||||
void CYSFFICH::setDGId(unsigned char id)
|
||||
{
|
||||
m_fich[3U] &= 0x80U;
|
||||
m_fich[3U] |= id & 0x7FU;
|
||||
}
|
||||
|
||||
CYSFFICH& CYSFFICH::operator=(const CYSFFICH& fich)
|
||||
{
|
||||
if (&fich != this)
|
||||
::memcpy(m_fich, fich.m_fich, 6U);
|
||||
|
||||
return *this;
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2016,2017,2019,2020 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 "YSFConvolution.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "Golay24128.h"
|
||||
#include "YSFFICH.h"
|
||||
#include "CRC.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
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])
|
||||
|
||||
const unsigned int INTERLEAVE_TABLE[] = {
|
||||
0U, 40U, 80U, 120U, 160U,
|
||||
2U, 42U, 82U, 122U, 162U,
|
||||
4U, 44U, 84U, 124U, 164U,
|
||||
6U, 46U, 86U, 126U, 166U,
|
||||
8U, 48U, 88U, 128U, 168U,
|
||||
10U, 50U, 90U, 130U, 170U,
|
||||
12U, 52U, 92U, 132U, 172U,
|
||||
14U, 54U, 94U, 134U, 174U,
|
||||
16U, 56U, 96U, 136U, 176U,
|
||||
18U, 58U, 98U, 138U, 178U,
|
||||
20U, 60U, 100U, 140U, 180U,
|
||||
22U, 62U, 102U, 142U, 182U,
|
||||
24U, 64U, 104U, 144U, 184U,
|
||||
26U, 66U, 106U, 146U, 186U,
|
||||
28U, 68U, 108U, 148U, 188U,
|
||||
30U, 70U, 110U, 150U, 190U,
|
||||
32U, 72U, 112U, 152U, 192U,
|
||||
34U, 74U, 114U, 154U, 194U,
|
||||
36U, 76U, 116U, 156U, 196U,
|
||||
38U, 78U, 118U, 158U, 198U};
|
||||
|
||||
CYSFFICH::CYSFFICH(const CYSFFICH& fich) :
|
||||
m_fich(NULL)
|
||||
{
|
||||
m_fich = new unsigned char[6U];
|
||||
|
||||
::memcpy(m_fich, fich.m_fich, 6U);
|
||||
}
|
||||
|
||||
CYSFFICH::CYSFFICH() :
|
||||
m_fich(NULL)
|
||||
{
|
||||
m_fich = new unsigned char[6U];
|
||||
|
||||
memset(m_fich, 0x00U, 6U);
|
||||
}
|
||||
|
||||
CYSFFICH::~CYSFFICH()
|
||||
{
|
||||
delete[] m_fich;
|
||||
}
|
||||
|
||||
bool CYSFFICH::decode(const unsigned char* bytes)
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
// Skip the sync bytes
|
||||
bytes += YSF_SYNC_LENGTH_BYTES;
|
||||
|
||||
CYSFConvolution viterbi;
|
||||
viterbi.start();
|
||||
|
||||
// Deinterleave the FICH and send bits to the Viterbi decoder
|
||||
for (unsigned int i = 0U; i < 100U; i++) {
|
||||
unsigned int n = INTERLEAVE_TABLE[i];
|
||||
uint8_t s0 = READ_BIT1(bytes, n) ? 1U : 0U;
|
||||
|
||||
n++;
|
||||
uint8_t s1 = READ_BIT1(bytes, n) ? 1U : 0U;
|
||||
|
||||
viterbi.decode(s0, s1);
|
||||
}
|
||||
|
||||
unsigned char output[13U];
|
||||
viterbi.chainback(output, 96U);
|
||||
|
||||
unsigned int b0 = CGolay24128::decode24128(output + 0U);
|
||||
unsigned int b1 = CGolay24128::decode24128(output + 3U);
|
||||
unsigned int b2 = CGolay24128::decode24128(output + 6U);
|
||||
unsigned int b3 = CGolay24128::decode24128(output + 9U);
|
||||
|
||||
m_fich[0U] = (b0 >> 4) & 0xFFU;
|
||||
m_fich[1U] = ((b0 << 4) & 0xF0U) | ((b1 >> 8) & 0x0FU);
|
||||
m_fich[2U] = (b1 >> 0) & 0xFFU;
|
||||
m_fich[3U] = (b2 >> 4) & 0xFFU;
|
||||
m_fich[4U] = ((b2 << 4) & 0xF0U) | ((b3 >> 8) & 0x0FU);
|
||||
m_fich[5U] = (b3 >> 0) & 0xFFU;
|
||||
|
||||
return CCRC::checkCCITT162(m_fich, 6U);
|
||||
}
|
||||
|
||||
void CYSFFICH::encode(unsigned char* bytes)
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
// Skip the sync bytes
|
||||
bytes += YSF_SYNC_LENGTH_BYTES;
|
||||
|
||||
CCRC::addCCITT162(m_fich, 6U);
|
||||
|
||||
unsigned int b0 = ((m_fich[0U] << 4) & 0xFF0U) | ((m_fich[1U] >> 4) & 0x00FU);
|
||||
unsigned int b1 = ((m_fich[1U] << 8) & 0xF00U) | ((m_fich[2U] >> 0) & 0x0FFU);
|
||||
unsigned int b2 = ((m_fich[3U] << 4) & 0xFF0U) | ((m_fich[4U] >> 4) & 0x00FU);
|
||||
unsigned int b3 = ((m_fich[4U] << 8) & 0xF00U) | ((m_fich[5U] >> 0) & 0x0FFU);
|
||||
|
||||
unsigned int c0 = CGolay24128::encode24128(b0);
|
||||
unsigned int c1 = CGolay24128::encode24128(b1);
|
||||
unsigned int c2 = CGolay24128::encode24128(b2);
|
||||
unsigned int c3 = CGolay24128::encode24128(b3);
|
||||
|
||||
unsigned char conv[13U];
|
||||
conv[0U] = (c0 >> 16) & 0xFFU;
|
||||
conv[1U] = (c0 >> 8) & 0xFFU;
|
||||
conv[2U] = (c0 >> 0) & 0xFFU;
|
||||
conv[3U] = (c1 >> 16) & 0xFFU;
|
||||
conv[4U] = (c1 >> 8) & 0xFFU;
|
||||
conv[5U] = (c1 >> 0) & 0xFFU;
|
||||
conv[6U] = (c2 >> 16) & 0xFFU;
|
||||
conv[7U] = (c2 >> 8) & 0xFFU;
|
||||
conv[8U] = (c2 >> 0) & 0xFFU;
|
||||
conv[9U] = (c3 >> 16) & 0xFFU;
|
||||
conv[10U] = (c3 >> 8) & 0xFFU;
|
||||
conv[11U] = (c3 >> 0) & 0xFFU;
|
||||
conv[12U] = 0x00U;
|
||||
|
||||
CYSFConvolution convolution;
|
||||
unsigned char convolved[25U];
|
||||
convolution.encode(conv, convolved, 100U);
|
||||
|
||||
unsigned int j = 0U;
|
||||
for (unsigned int i = 0U; i < 100U; i++) {
|
||||
unsigned int n = INTERLEAVE_TABLE[i];
|
||||
|
||||
bool s0 = READ_BIT1(convolved, j) != 0U;
|
||||
j++;
|
||||
|
||||
bool s1 = READ_BIT1(convolved, j) != 0U;
|
||||
j++;
|
||||
|
||||
WRITE_BIT1(bytes, n, s0);
|
||||
|
||||
n++;
|
||||
WRITE_BIT1(bytes, n, s1);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getFI() const
|
||||
{
|
||||
return (m_fich[0U] >> 6) & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getCM() const
|
||||
{
|
||||
return (m_fich[0U] >> 2) & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getBN() const
|
||||
{
|
||||
return m_fich[0U] & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getBT() const
|
||||
{
|
||||
return (m_fich[1U] >> 6) & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getFN() const
|
||||
{
|
||||
return (m_fich[1U] >> 3) & 0x07U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getFT() const
|
||||
{
|
||||
return m_fich[1U] & 0x07U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getDT() const
|
||||
{
|
||||
return m_fich[2U] & 0x03U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getMR() const
|
||||
{
|
||||
return (m_fich[2U] >> 3) & 0x03U;
|
||||
}
|
||||
|
||||
bool CYSFFICH::getDev() const
|
||||
{
|
||||
return (m_fich[2U] & 0x40U) == 0x40U;
|
||||
}
|
||||
|
||||
unsigned char CYSFFICH::getDGId() const
|
||||
{
|
||||
return m_fich[3U] & 0x7FU;
|
||||
}
|
||||
|
||||
void CYSFFICH::setFI(unsigned char fi)
|
||||
{
|
||||
m_fich[0U] &= 0x3FU;
|
||||
m_fich[0U] |= (fi << 6) & 0xC0U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setBN(unsigned char bn)
|
||||
{
|
||||
m_fich[0U] &= 0xFCU;
|
||||
m_fich[0U] |= bn & 0x03U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setBT(unsigned char bt)
|
||||
{
|
||||
m_fich[1U] &= 0x3FU;
|
||||
m_fich[1U] |= (bt << 6) & 0xC0U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setFN(unsigned char fn)
|
||||
{
|
||||
m_fich[1U] &= 0xC7U;
|
||||
m_fich[1U] |= (fn << 3) & 0x38U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setFT(unsigned char ft)
|
||||
{
|
||||
m_fich[1U] &= 0xF8U;
|
||||
m_fich[1U] |= ft & 0x07U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setMR(unsigned char mr)
|
||||
{
|
||||
m_fich[2U] &= 0xC7U;
|
||||
m_fich[2U] |= (mr << 3) & 0x38U;
|
||||
}
|
||||
|
||||
void CYSFFICH::setVoIP(bool on)
|
||||
{
|
||||
if (on)
|
||||
m_fich[2U] |= 0x04U;
|
||||
else
|
||||
m_fich[2U] &= 0xFBU;
|
||||
}
|
||||
|
||||
void CYSFFICH::setDev(bool on)
|
||||
{
|
||||
if (on)
|
||||
m_fich[2U] |= 0x40U;
|
||||
else
|
||||
m_fich[2U] &= 0xBFU;
|
||||
}
|
||||
|
||||
void CYSFFICH::setDGId(unsigned char id)
|
||||
{
|
||||
m_fich[3U] &= 0x80U;
|
||||
m_fich[3U] |= id & 0x7FU;
|
||||
}
|
||||
|
||||
CYSFFICH& CYSFFICH::operator=(const CYSFFICH& fich)
|
||||
{
|
||||
if (&fich != this)
|
||||
::memcpy(m_fich, fich.m_fich, 6U);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
118
YSFFICH.h
118
YSFFICH.h
|
@ -1,59 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017,2019,2020 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(YSFFICH_H)
|
||||
#define YSFFICH_H
|
||||
|
||||
class CYSFFICH {
|
||||
public:
|
||||
CYSFFICH(const CYSFFICH& fich);
|
||||
CYSFFICH();
|
||||
~CYSFFICH();
|
||||
|
||||
bool decode(const unsigned char* bytes);
|
||||
|
||||
void encode(unsigned char* bytes);
|
||||
|
||||
unsigned char getFI() const;
|
||||
unsigned char getCM() const;
|
||||
unsigned char getBN() const;
|
||||
unsigned char getBT() const;
|
||||
unsigned char getFN() const;
|
||||
unsigned char getFT() const;
|
||||
unsigned char getDT() const;
|
||||
unsigned char getMR() const;
|
||||
bool getDev() const;
|
||||
unsigned char getDGId() const;
|
||||
|
||||
void setFI(unsigned char fi);
|
||||
void setBN(unsigned char bn);
|
||||
void setBT(unsigned char bt);
|
||||
void setFN(unsigned char fn);
|
||||
void setFT(unsigned char ft);
|
||||
void setMR(unsigned char mr);
|
||||
void setVoIP(bool set);
|
||||
void setDev(bool set);
|
||||
void setDGId(unsigned char id);
|
||||
|
||||
CYSFFICH& operator=(const CYSFFICH& fich);
|
||||
|
||||
private:
|
||||
unsigned char* m_fich;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (C) 2016,2017,2019,2020 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(YSFFICH_H)
|
||||
#define YSFFICH_H
|
||||
|
||||
class CYSFFICH {
|
||||
public:
|
||||
CYSFFICH(const CYSFFICH& fich);
|
||||
CYSFFICH();
|
||||
~CYSFFICH();
|
||||
|
||||
bool decode(const unsigned char* bytes);
|
||||
|
||||
void encode(unsigned char* bytes);
|
||||
|
||||
unsigned char getFI() const;
|
||||
unsigned char getCM() const;
|
||||
unsigned char getBN() const;
|
||||
unsigned char getBT() const;
|
||||
unsigned char getFN() const;
|
||||
unsigned char getFT() const;
|
||||
unsigned char getDT() const;
|
||||
unsigned char getMR() const;
|
||||
bool getDev() const;
|
||||
unsigned char getDGId() const;
|
||||
|
||||
void setFI(unsigned char fi);
|
||||
void setBN(unsigned char bn);
|
||||
void setBT(unsigned char bt);
|
||||
void setFN(unsigned char fn);
|
||||
void setFT(unsigned char ft);
|
||||
void setMR(unsigned char mr);
|
||||
void setVoIP(bool set);
|
||||
void setDev(bool set);
|
||||
void setDGId(unsigned char id);
|
||||
|
||||
CYSFFICH& operator=(const CYSFFICH& fich);
|
||||
|
||||
private:
|
||||
unsigned char* m_fich;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
402
YSFNetwork.cpp
402
YSFNetwork.cpp
|
@ -1,201 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014,2016,2019,2020 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 "YSFDefines.h"
|
||||
#include "YSFNetwork.h"
|
||||
#include "Defines.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 200U;
|
||||
|
||||
CYSFNetwork::CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug) :
|
||||
m_socket(myAddress, myPort),
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_callsign(),
|
||||
m_debug(debug),
|
||||
m_enabled(false),
|
||||
m_buffer(1000U, "YSF Network"),
|
||||
m_pollTimer(1000U, 5U),
|
||||
m_tag(NULL)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
m_callsign.resize(YSF_CALLSIGN_LENGTH, ' ');
|
||||
|
||||
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
|
||||
m_addrLen = 0U;
|
||||
|
||||
m_tag = new unsigned char[YSF_CALLSIGN_LENGTH];
|
||||
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
|
||||
}
|
||||
|
||||
CYSFNetwork::~CYSFNetwork()
|
||||
{
|
||||
delete[] m_tag;
|
||||
}
|
||||
|
||||
bool CYSFNetwork::open()
|
||||
{
|
||||
if (m_addrLen == 0U) {
|
||||
LogError("Unable to resolve the address of the YSF Gateway");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("Opening YSF network connection");
|
||||
|
||||
m_pollTimer.start();
|
||||
|
||||
return m_socket.open(m_addr);
|
||||
}
|
||||
|
||||
bool CYSFNetwork::write(const unsigned char* src, const unsigned char* dest, const unsigned char* data, unsigned int count, bool end)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char buffer[200U];
|
||||
|
||||
buffer[0] = 'Y';
|
||||
buffer[1] = 'S';
|
||||
buffer[2] = 'F';
|
||||
buffer[3] = 'D';
|
||||
|
||||
for (unsigned int i = 0U; i < YSF_CALLSIGN_LENGTH; i++)
|
||||
buffer[i + 4U] = m_callsign.at(i);
|
||||
|
||||
if (src != NULL)
|
||||
::memcpy(buffer + 14U, src, YSF_CALLSIGN_LENGTH);
|
||||
else
|
||||
::memset(buffer + 14U, ' ', YSF_CALLSIGN_LENGTH);
|
||||
|
||||
if (dest != NULL)
|
||||
::memcpy(buffer + 24U, dest, YSF_CALLSIGN_LENGTH);
|
||||
else
|
||||
::memset(buffer + 24U, ' ', YSF_CALLSIGN_LENGTH);
|
||||
|
||||
buffer[34U] = end ? 0x01U : 0x00U;
|
||||
buffer[34U] |= (count & 0x7FU) << 1;
|
||||
|
||||
::memcpy(buffer + 35U, data, YSF_FRAME_LENGTH_BYTES);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Data Sent", buffer, 155U);
|
||||
|
||||
return m_socket.write(buffer, 155U, m_addr, m_addrLen);
|
||||
}
|
||||
|
||||
bool CYSFNetwork::writePoll()
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
buffer[0] = 'Y';
|
||||
buffer[1] = 'S';
|
||||
buffer[2] = 'F';
|
||||
buffer[3] = 'P';
|
||||
|
||||
for (unsigned int i = 0U; i < YSF_CALLSIGN_LENGTH; i++)
|
||||
buffer[i + 4U] = m_callsign.at(i);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
|
||||
|
||||
return m_socket.write(buffer, 14U, m_addr, m_addrLen);
|
||||
}
|
||||
|
||||
void CYSFNetwork::clock(unsigned int ms)
|
||||
{
|
||||
m_pollTimer.clock(ms);
|
||||
if (m_pollTimer.hasExpired()) {
|
||||
writePoll();
|
||||
m_pollTimer.start();
|
||||
}
|
||||
|
||||
unsigned char buffer[BUFFER_LENGTH];
|
||||
|
||||
sockaddr_storage address;
|
||||
unsigned int addrLen;
|
||||
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrLen);
|
||||
if (length <= 0)
|
||||
return;
|
||||
|
||||
if (!CUDPSocket::match(m_addr, address)) {
|
||||
LogMessage("YSF, packet received from an invalid source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Data Received", buffer, length);
|
||||
|
||||
// Invalid packet type?
|
||||
if (::memcmp(buffer, "YSFD", 4U) != 0)
|
||||
return;
|
||||
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
if (::memcmp(m_tag, " ", YSF_CALLSIGN_LENGTH) == 0) {
|
||||
::memcpy(m_tag, buffer + 4U, YSF_CALLSIGN_LENGTH);
|
||||
} else {
|
||||
if (::memcmp(m_tag, buffer + 4U, YSF_CALLSIGN_LENGTH) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
bool end = (buffer[34U] & 0x01U) == 0x01U;
|
||||
if (end)
|
||||
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
|
||||
|
||||
m_buffer.addData(buffer, 155U);
|
||||
}
|
||||
|
||||
unsigned int CYSFNetwork::read(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_buffer.isEmpty())
|
||||
return 0U;
|
||||
|
||||
m_buffer.getData(data, 155U);
|
||||
|
||||
return 155U;
|
||||
}
|
||||
|
||||
void CYSFNetwork::reset()
|
||||
{
|
||||
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
|
||||
}
|
||||
|
||||
void CYSFNetwork::close()
|
||||
{
|
||||
m_socket.close();
|
||||
|
||||
LogMessage("Closing YSF network connection");
|
||||
}
|
||||
|
||||
void CYSFNetwork::enable(bool enabled)
|
||||
{
|
||||
if (enabled && !m_enabled)
|
||||
reset();
|
||||
else if (!enabled && m_enabled)
|
||||
m_buffer.clear();
|
||||
|
||||
m_enabled = enabled;
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2009-2014,2016,2019,2020 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 "YSFDefines.h"
|
||||
#include "YSFNetwork.h"
|
||||
#include "Defines.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 200U;
|
||||
|
||||
CYSFNetwork::CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug) :
|
||||
m_socket(myAddress, myPort),
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_callsign(),
|
||||
m_debug(debug),
|
||||
m_enabled(false),
|
||||
m_buffer(1000U, "YSF Network"),
|
||||
m_pollTimer(1000U, 5U),
|
||||
m_tag(NULL)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
m_callsign.resize(YSF_CALLSIGN_LENGTH, ' ');
|
||||
|
||||
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
|
||||
m_addrLen = 0U;
|
||||
|
||||
m_tag = new unsigned char[YSF_CALLSIGN_LENGTH];
|
||||
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
|
||||
}
|
||||
|
||||
CYSFNetwork::~CYSFNetwork()
|
||||
{
|
||||
delete[] m_tag;
|
||||
}
|
||||
|
||||
bool CYSFNetwork::open()
|
||||
{
|
||||
if (m_addrLen == 0U) {
|
||||
LogError("Unable to resolve the address of the YSF Gateway");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogMessage("Opening YSF network connection");
|
||||
|
||||
m_pollTimer.start();
|
||||
|
||||
return m_socket.open(m_addr);
|
||||
}
|
||||
|
||||
bool CYSFNetwork::write(const unsigned char* src, const unsigned char* dest, const unsigned char* data, unsigned int count, bool end)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char buffer[200U];
|
||||
|
||||
buffer[0] = 'Y';
|
||||
buffer[1] = 'S';
|
||||
buffer[2] = 'F';
|
||||
buffer[3] = 'D';
|
||||
|
||||
for (unsigned int i = 0U; i < YSF_CALLSIGN_LENGTH; i++)
|
||||
buffer[i + 4U] = m_callsign.at(i);
|
||||
|
||||
if (src != NULL)
|
||||
::memcpy(buffer + 14U, src, YSF_CALLSIGN_LENGTH);
|
||||
else
|
||||
::memset(buffer + 14U, ' ', YSF_CALLSIGN_LENGTH);
|
||||
|
||||
if (dest != NULL)
|
||||
::memcpy(buffer + 24U, dest, YSF_CALLSIGN_LENGTH);
|
||||
else
|
||||
::memset(buffer + 24U, ' ', YSF_CALLSIGN_LENGTH);
|
||||
|
||||
buffer[34U] = end ? 0x01U : 0x00U;
|
||||
buffer[34U] |= (count & 0x7FU) << 1;
|
||||
|
||||
::memcpy(buffer + 35U, data, YSF_FRAME_LENGTH_BYTES);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Data Sent", buffer, 155U);
|
||||
|
||||
return m_socket.write(buffer, 155U, m_addr, m_addrLen);
|
||||
}
|
||||
|
||||
bool CYSFNetwork::writePoll()
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
buffer[0] = 'Y';
|
||||
buffer[1] = 'S';
|
||||
buffer[2] = 'F';
|
||||
buffer[3] = 'P';
|
||||
|
||||
for (unsigned int i = 0U; i < YSF_CALLSIGN_LENGTH; i++)
|
||||
buffer[i + 4U] = m_callsign.at(i);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
|
||||
|
||||
return m_socket.write(buffer, 14U, m_addr, m_addrLen);
|
||||
}
|
||||
|
||||
void CYSFNetwork::clock(unsigned int ms)
|
||||
{
|
||||
m_pollTimer.clock(ms);
|
||||
if (m_pollTimer.hasExpired()) {
|
||||
writePoll();
|
||||
m_pollTimer.start();
|
||||
}
|
||||
|
||||
unsigned char buffer[BUFFER_LENGTH];
|
||||
|
||||
sockaddr_storage address;
|
||||
unsigned int addrLen;
|
||||
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrLen);
|
||||
if (length <= 0)
|
||||
return;
|
||||
|
||||
if (!CUDPSocket::match(m_addr, address)) {
|
||||
LogMessage("YSF, packet received from an invalid source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Data Received", buffer, length);
|
||||
|
||||
// Invalid packet type?
|
||||
if (::memcmp(buffer, "YSFD", 4U) != 0)
|
||||
return;
|
||||
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
if (::memcmp(m_tag, " ", YSF_CALLSIGN_LENGTH) == 0) {
|
||||
::memcpy(m_tag, buffer + 4U, YSF_CALLSIGN_LENGTH);
|
||||
} else {
|
||||
if (::memcmp(m_tag, buffer + 4U, YSF_CALLSIGN_LENGTH) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
bool end = (buffer[34U] & 0x01U) == 0x01U;
|
||||
if (end)
|
||||
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
|
||||
|
||||
m_buffer.addData(buffer, 155U);
|
||||
}
|
||||
|
||||
unsigned int CYSFNetwork::read(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_buffer.isEmpty())
|
||||
return 0U;
|
||||
|
||||
m_buffer.getData(data, 155U);
|
||||
|
||||
return 155U;
|
||||
}
|
||||
|
||||
void CYSFNetwork::reset()
|
||||
{
|
||||
::memset(m_tag, ' ', YSF_CALLSIGN_LENGTH);
|
||||
}
|
||||
|
||||
void CYSFNetwork::close()
|
||||
{
|
||||
m_socket.close();
|
||||
|
||||
LogMessage("Closing YSF network connection");
|
||||
}
|
||||
|
||||
void CYSFNetwork::enable(bool enabled)
|
||||
{
|
||||
if (enabled && !m_enabled)
|
||||
reset();
|
||||
else if (!enabled && m_enabled)
|
||||
m_buffer.clear();
|
||||
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
|
126
YSFNetwork.h
126
YSFNetwork.h
|
@ -1,63 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014,2016,2020 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 YSFNetwork_H
|
||||
#define YSFNetwork_H
|
||||
|
||||
#include "YSFDefines.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class CYSFNetwork {
|
||||
public:
|
||||
CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug);
|
||||
~CYSFNetwork();
|
||||
|
||||
bool open();
|
||||
|
||||
void enable(bool enabled);
|
||||
|
||||
bool write(const unsigned char* src, const unsigned char* dest, const unsigned char* data, unsigned int count, bool end);
|
||||
|
||||
unsigned int read(unsigned char* data);
|
||||
|
||||
void reset();
|
||||
|
||||
void close();
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
CUDPSocket m_socket;
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
std::string m_callsign;
|
||||
bool m_debug;
|
||||
bool m_enabled;
|
||||
CRingBuffer<unsigned char> m_buffer;
|
||||
CTimer m_pollTimer;
|
||||
unsigned char* m_tag;
|
||||
|
||||
bool writePoll();
|
||||
};
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (C) 2009-2014,2016,2020 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 YSFNetwork_H
|
||||
#define YSFNetwork_H
|
||||
|
||||
#include "YSFDefines.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class CYSFNetwork {
|
||||
public:
|
||||
CYSFNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, const std::string& callsign, bool debug);
|
||||
~CYSFNetwork();
|
||||
|
||||
bool open();
|
||||
|
||||
void enable(bool enabled);
|
||||
|
||||
bool write(const unsigned char* src, const unsigned char* dest, const unsigned char* data, unsigned int count, bool end);
|
||||
|
||||
unsigned int read(unsigned char* data);
|
||||
|
||||
void reset();
|
||||
|
||||
void close();
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
CUDPSocket m_socket;
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
std::string m_callsign;
|
||||
bool m_debug;
|
||||
bool m_enabled;
|
||||
CRingBuffer<unsigned char> m_buffer;
|
||||
CTimer m_pollTimer;
|
||||
unsigned char* m_tag;
|
||||
|
||||
bool writePoll();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
2054
YSFPayload.cpp
2054
YSFPayload.cpp
File diff suppressed because it is too large
Load diff
134
YSFPayload.h
134
YSFPayload.h
|
@ -1,67 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017,2020 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(YSFPayload_H)
|
||||
#define YSFPayload_H
|
||||
|
||||
#include "AMBEFEC.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CYSFPayload {
|
||||
public:
|
||||
CYSFPayload();
|
||||
~CYSFPayload();
|
||||
|
||||
bool processHeaderData(unsigned char* bytes);
|
||||
|
||||
bool processVDMode1Data(unsigned char* bytes, unsigned char fn, bool gateway = false);
|
||||
unsigned int processVDMode1Audio(unsigned char* bytes);
|
||||
|
||||
bool processVDMode2Data(unsigned char* bytes, unsigned char fn, bool gateway = false);
|
||||
unsigned int processVDMode2Audio(unsigned char* bytes);
|
||||
|
||||
bool processDataFRModeData(unsigned char* bytes, unsigned char fn, bool gateway = false);
|
||||
|
||||
bool processVoiceFRModeData(unsigned char* bytes);
|
||||
|
||||
unsigned int processVoiceFRModeAudio2(unsigned char* bytes);
|
||||
unsigned int processVoiceFRModeAudio5(unsigned char* bytes);
|
||||
|
||||
void writeHeader(unsigned char* data, const unsigned char* csd1, const unsigned char* csd2);
|
||||
|
||||
void writeDataFRModeData1(const unsigned char* dt, unsigned char* data);
|
||||
void writeDataFRModeData2(const unsigned char* dt, unsigned char* data);
|
||||
|
||||
unsigned char* getSource();
|
||||
unsigned char* getDest();
|
||||
|
||||
void setUplink(const std::string& callsign);
|
||||
void setDownlink(const std::string& callsign);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
unsigned char* m_uplink;
|
||||
unsigned char* m_downlink;
|
||||
unsigned char* m_source;
|
||||
unsigned char* m_dest;
|
||||
CAMBEFEC m_fec;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (C) 2016,2017,2020 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(YSFPayload_H)
|
||||
#define YSFPayload_H
|
||||
|
||||
#include "AMBEFEC.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CYSFPayload {
|
||||
public:
|
||||
CYSFPayload();
|
||||
~CYSFPayload();
|
||||
|
||||
bool processHeaderData(unsigned char* bytes);
|
||||
|
||||
bool processVDMode1Data(unsigned char* bytes, unsigned char fn, bool gateway = false);
|
||||
unsigned int processVDMode1Audio(unsigned char* bytes);
|
||||
|
||||
bool processVDMode2Data(unsigned char* bytes, unsigned char fn, bool gateway = false);
|
||||
unsigned int processVDMode2Audio(unsigned char* bytes);
|
||||
|
||||
bool processDataFRModeData(unsigned char* bytes, unsigned char fn, bool gateway = false);
|
||||
|
||||
bool processVoiceFRModeData(unsigned char* bytes);
|
||||
|
||||
unsigned int processVoiceFRModeAudio2(unsigned char* bytes);
|
||||
unsigned int processVoiceFRModeAudio5(unsigned char* bytes);
|
||||
|
||||
void writeHeader(unsigned char* data, const unsigned char* csd1, const unsigned char* csd2);
|
||||
|
||||
void writeDataFRModeData1(const unsigned char* dt, unsigned char* data);
|
||||
void writeDataFRModeData2(const unsigned char* dt, unsigned char* data);
|
||||
|
||||
unsigned char* getSource();
|
||||
unsigned char* getDest();
|
||||
|
||||
void setUplink(const std::string& callsign);
|
||||
void setDownlink(const std::string& callsign);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
unsigned char* m_uplink;
|
||||
unsigned char* m_downlink;
|
||||
unsigned char* m_source;
|
||||
unsigned char* m_dest;
|
||||
CAMBEFEC m_fec;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue