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.

1027 lines
24 KiB

/*
* Copyright (C) 2011-2014,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 "CCITTChecksumReverse.h"
#include "DVAPController.h"
#include "DStarDefines.h"
#include "Timer.h"
const unsigned char DVAP_REQ_NAME[] = {0x04, 0x20, 0x01, 0x00};
const unsigned int DVAP_REQ_NAME_LEN = 4U;
const unsigned char DVAP_RESP_NAME[] = {0x10, 0x00, 0x01, 0x00, 'D', 'V', 'A', 'P', ' ', 'D', 'o', 'n', 'g', 'l', 'e', 0x00};
const unsigned int DVAP_RESP_NAME_LEN = 16U;
const unsigned char DVAP_REQ_SERIAL[] = {0x04, 0x20, 0x02, 0x00};
const unsigned int DVAP_REQ_SERIAL_LEN = 4U;
const unsigned char DVAP_RESP_SERIAL[] = {0x0C, 0x00, 0x02, 0x00};
const unsigned int DVAP_RESP_SERIAL_LEN = 4U;
const unsigned char DVAP_REQ_FIRMWARE[] = {0x05, 0x20, 0x04, 0x00, 0x01};
const unsigned int DVAP_REQ_FIRMWARE_LEN = 5U;
const unsigned char DVAP_RESP_FIRMWARE[] = {0x07, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00};
const unsigned int DVAP_RESP_FIRMWARE_LEN = 7U;
const unsigned char DVAP_REQ_MODULATION[] = {0x05, 0x00, 0x28, 0x00, 0x01};
const unsigned int DVAP_REQ_MODULATION_LEN = 5U;
const unsigned char DVAP_RESP_MODULATION[] = {0x05, 0x00, 0x28, 0x00, 0x01};
const unsigned int DVAP_RESP_MODULATION_LEN = 5U;
const unsigned char DVAP_REQ_MODE[] = {0x05, 0x00, 0x2A, 0x00, 0x00};
const unsigned int DVAP_REQ_MODE_LEN = 5U;
const unsigned char DVAP_RESP_MODE[] = {0x05, 0x00, 0x2A, 0x00, 0x00};
const unsigned int DVAP_RESP_MODE_LEN = 5U;
const unsigned char DVAP_REQ_SQUELCH[] = {0x05, 0x00, 0x80, 0x00, 0x00};
const unsigned int DVAP_REQ_SQUELCH_LEN = 5U;
const unsigned char DVAP_RESP_SQUELCH[] = {0x05, 0x00, 0x80, 0x00, 0x00};
const unsigned int DVAP_RESP_SQUELCH_LEN = 5U;
const unsigned char DVAP_REQ_POWER[] = {0x06, 0x00, 0x38, 0x01, 0x00, 0x00};
const unsigned int DVAP_REQ_POWER_LEN = 6U;
const unsigned char DVAP_RESP_POWER[] = {0x06, 0x00, 0x38, 0x01, 0x00, 0x00};
const unsigned int DVAP_RESP_POWER_LEN = 6U;
const unsigned char DVAP_REQ_FREQUENCY[] = {0x08, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00};
const unsigned int DVAP_REQ_FREQUENCY_LEN = 8U;
const unsigned char DVAP_RESP_FREQUENCY[] = {0x08, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00};
const unsigned int DVAP_RESP_FREQUENCY_LEN = 8U;
const unsigned char DVAP_REQ_FREQLIMITS[] = {0x04, 0x20, 0x30, 0x02};
const unsigned int DVAP_REQ_FREQLIMITS_LEN = 4U;
const unsigned char DVAP_RESP_FREQLIMITS[] = {0x0C, 0x00, 0x30, 0x02};
const unsigned int DVAP_RESP_FREQLIMITS_LEN = 4U;
const unsigned char DVAP_REQ_START[] = {0x05, 0x00, 0x18, 0x00, 0x01};
const unsigned int DVAP_REQ_START_LEN = 5U;
const unsigned char DVAP_RESP_START[] = {0x05, 0x00, 0x18, 0x00, 0x01};
const unsigned int DVAP_RESP_START_LEN = 5U;
const unsigned char DVAP_REQ_STOP[] = {0x05, 0x00, 0x18, 0x00, 0x00};
const unsigned int DVAP_REQ_STOP_LEN = 5U;
const unsigned char DVAP_RESP_STOP[] = {0x05, 0x00, 0x18, 0x00, 0x00};
const unsigned int DVAP_RESP_STOP_LEN = 5U;
const unsigned char DVAP_HEADER[] = {0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned int DVAP_HEADER_LEN = 47U;
const unsigned char DVAP_RESP_HEADER[] = {0x2F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned int DVAP_RESP_HEADER_LEN = 47U;
const unsigned char DVAP_RESP_PTT[] = {0x05, 0x20, 0x18, 0x01, 0x00};
const unsigned int DVAP_RESP_PTT_LEN = 5U;
const unsigned char DVAP_GMSK_DATA[] = {0x12, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned int DVAP_GMSK_DATA_LEN = 18U;
const unsigned char DVAP_STATUS[] = {0x07, 0x20, 0x90, 0x00, 0x00, 0x00, 0x00};
const unsigned int DVAP_STATUS_LEN = 7U;
const unsigned char DVAP_ACK[] = {0x03, 0x60, 0x00};
const unsigned int DVAP_ACK_LEN = 3U;
const unsigned char DVAP_FM_DATA[] = {0x42, 0x81};
const unsigned int DVAP_FM_DATA_LEN = 2U;
const unsigned int DVAP_HEADER_LENGTH = 2U;
const unsigned int MAX_RESPONSES = 20U;
const unsigned int BUFFER_LENGTH = 200U;
const unsigned int DVAP_DUMP_LENGTH = 30U;
CDVAPController::CDVAPController(const wxString& port, unsigned int frequency, int power, int squelch) :
CModem(),
m_serial(port, SERIAL_230400),
m_frequency(frequency),
m_power(power),
m_squelch(squelch),
m_squelchOpen(false),
m_signal(0),
m_buffer(NULL),
m_streamId(0U),
m_framePos(0U),
m_seq(0U),
m_txData(1000U)
#if defined(DVAP_DUMP)
,
m_dvapData(NULL),
m_dvapLength(NULL),
m_dvapIndex(0U)
#endif
{
wxASSERT(!port.IsEmpty());
wxASSERT((frequency >= 144000000U && frequency <= 148000000U) ||
(frequency >= 220000000U && frequency <= 225000000U) ||
(frequency >= 420000000U && frequency <= 450000000U));
wxASSERT(power >= -12 && power <= 10);
wxASSERT(squelch >= -128 && squelch <= -45);
m_buffer = new unsigned char[BUFFER_LENGTH];
#if defined(DVAP_DUMP)
m_dvapData = new unsigned char*[DVAP_DUMP_LENGTH];
for (unsigned int i = 0U; i < DVAP_DUMP_LENGTH; i++)
m_dvapData[i] = new unsigned char[100U];
m_dvapLength = new unsigned int[DVAP_DUMP_LENGTH];
for (unsigned int i = 0U; i < DVAP_DUMP_LENGTH; i++)
m_dvapLength[i] = 0U;
#endif
}
CDVAPController::~CDVAPController()
{
delete[] m_buffer;
#if defined(DVAP_DUMP)
for (unsigned int i = 0U; i < DVAP_DUMP_LENGTH; i++)
delete[] m_dvapData[i];
delete[] m_dvapData;
delete[] m_dvapLength;
#endif
}
bool CDVAPController::start()
{
bool res = m_serial.open();
if (!res)
return false;
res = getName();
if (!res) {
m_serial.close();
return false;
}
res = getFirmware();
if (!res) {
m_serial.close();
return false;
}
res = getSerial();
if (!res) {
m_serial.close();
return false;
}
res = setModulation();
if (!res) {
m_serial.close();
return false;
}
res = setMode();
if (!res) {
m_serial.close();
return false;
}
res = setSquelch();
if (!res) {
m_serial.close();
return false;
}
res = setPower();
if (!res) {
m_serial.close();
return false;
}
res = setFrequency();
if (!res) {
m_serial.close();
return false;
}
res = startDVAP();
if (!res) {
m_serial.close();
return false;
}
Create();
SetPriority(100U);
Run();
return true;
}
void* CDVAPController::Entry()
{
wxLogMessage(wxT("Starting DVAP Controller thread"));
// Clock every 5ms-ish
CTimer pollTimer(200U, 2U);
pollTimer.start();
unsigned char writeLength = 0U;
unsigned char* writeBuffer = new unsigned char[BUFFER_LENGTH];
unsigned int space = 0U;
while (!m_stopped) {
// Poll the modem every 2s
if (pollTimer.hasExpired()) {
writePoll();
pollTimer.start();
}
unsigned int length;
RESP_TYPE type = getResponse(m_buffer, length);
switch (type) {
case RT_TIMEOUT:
break;
case RT_ERROR:
wxLogMessage(wxT("Stopping DVAP Controller thread"));
#if defined(DVAP_DUMP)
dumpPackets();
#endif
m_serial.close();
return NULL;
case RT_STATE:
m_signal = int(m_buffer[4U]) - 256;
m_squelchOpen = m_buffer[5U] == 0x01U;
space = m_buffer[6U];
break;
case RT_PTT:
m_tx = m_buffer[4U] == 0x01U;
break;
case RT_START:
break;
case RT_STOP:
wxLogWarning(wxT("DVAP has stopped, restarting"));
#if defined(DVAP_DUMP)
dumpPackets();
#endif
startDVAP();
break;
case RT_HEADER: {
wxMutexLocker locker(m_mutex);
unsigned char hdr[2U];
hdr[0U] = DSMTT_HEADER;
hdr[1U] = RADIO_HEADER_LENGTH_BYTES;
m_rxData.addData(hdr, 2U);
m_rxData.addData(m_buffer + 6U, RADIO_HEADER_LENGTH_BYTES);
}
break;
case RT_HEADER_ACK:
break;
case RT_GMSK_DATA: {
wxMutexLocker locker(m_mutex);
bool end = (m_buffer[4U] & 0x40U) == 0x40U;
if (end) {
unsigned char hdr[2U];
hdr[0U] = DSMTT_EOT;
hdr[1U] = 0U;
m_rxData.addData(hdr, 2U);
} else {
unsigned char hdr[2U];
hdr[0U] = DSMTT_DATA;
hdr[1U] = length - 6U;
m_rxData.addData(hdr, 2U);
m_rxData.addData(m_buffer + 6U, length - 6U);
}
}
break;
case RT_FM_DATA:
wxLogWarning(wxT("The DVAP has gone into FM mode, restarting the DVAP"));
#if defined(DVAP_DUMP)
dumpPackets();
#endif
stopDVAP();
setModulation();
startDVAP();
break;
default:
wxLogMessage(wxT("Unknown message"));
CUtils::dump(wxT("Buffer dump"), m_buffer, length);
#if defined(DVAP_DUMP)
dumpPackets();
#endif
break;
}
// Use the status packet every 20ms to trigger the sending of data to the DVAP
if (space > 0U && type == RT_STATE) {
if (writeLength == 0U && m_txData.hasData()) {
wxMutexLocker locker(m_mutex);
m_txData.getData(&writeLength, 1U);
m_txData.getData(writeBuffer, writeLength);
}
// Only send the header when the TX is off
if (!m_tx && writeLength == DVAP_HEADER_LEN) {
// CUtils::dump(wxT("Write Header"), writeBuffer, writeLength);
#if defined(DVAP_DUMP)
storePacket(writeBuffer, writeLength);
#endif
int ret = m_serial.write(writeBuffer, writeLength);
if (ret != int(writeLength))
wxLogWarning(wxT("Error when writing the header to the DVAP"));
writeLength = 0U;
space--;
}
if (writeLength == DVAP_GMSK_DATA_LEN) {
// CUtils::dump(wxT("Write Data"), writeBuffer, writeLength);
#if defined(DVAP_DUMP)
storePacket(writeBuffer, writeLength);
#endif
int ret = m_serial.write(writeBuffer, writeLength);
if (ret != int(writeLength))
wxLogWarning(wxT("Error when writing data to the DVAP"));
writeLength = 0U;
space--;
}
}
Sleep(5UL);
pollTimer.clock();
}
wxLogMessage(wxT("Stopping DVAP Controller thread"));
stopDVAP();
delete[] writeBuffer;
m_serial.close();
return NULL;
}
bool CDVAPController::writeHeader(const CHeaderData& header)
{
bool ret = m_txData.hasSpace(DVAP_HEADER_LEN + 1U);
if (!ret) {
wxLogWarning(wxT("No space to write the header"));
return false;
}
m_streamId++;
unsigned char buffer[50U];
::memcpy(buffer, DVAP_HEADER, DVAP_HEADER_LEN);
wxUint16 sid = wxUINT16_SWAP_ON_BE(m_streamId);
::memcpy(buffer + 2U, &sid, sizeof(wxUint16));
buffer[4U] = 0x80U;
buffer[5U] = 0U;
::memset(buffer + 6U, ' ', RADIO_HEADER_LENGTH_BYTES);
buffer[6U] = header.getFlag1();
buffer[7U] = header.getFlag2();
buffer[8U] = header.getFlag3();
wxString rpt2 = header.getRptCall2();
for (unsigned int i = 0U; i < rpt2.Len() && i < LONG_CALLSIGN_LENGTH; i++)
buffer[i + 9U] = rpt2.GetChar(i);
wxString rpt1 = header.getRptCall1();
for (unsigned int i = 0U; i < rpt1.Len() && i < LONG_CALLSIGN_LENGTH; i++)
buffer[i + 17U] = rpt1.GetChar(i);
wxString your = header.getYourCall();
for (unsigned int i = 0U; i < your.Len() && i < LONG_CALLSIGN_LENGTH; i++)
buffer[i + 25U] = your.GetChar(i);
wxString my1 = header.getMyCall1();
for (unsigned int i = 0U; i < my1.Len() && i < LONG_CALLSIGN_LENGTH; i++)
buffer[i + 33U] = my1.GetChar(i);
wxString my2 = header.getMyCall2();
for (unsigned int i = 0U; i < my2.Len() && i < SHORT_CALLSIGN_LENGTH; i++)
buffer[i + 41U] = my2.GetChar(i);
CCCITTChecksumReverse cksum;
cksum.update(buffer + 6U, RADIO_HEADER_LENGTH_BYTES - 2U);
cksum.result(buffer + 45U);
m_framePos = 0U;
m_seq = 0U;
wxMutexLocker locker(m_mutex);
unsigned char len = DVAP_HEADER_LEN;
m_txData.addData(&len, 1U);
m_txData.addData(buffer, DVAP_HEADER_LEN);
return true;
}
bool CDVAPController::writeData(const unsigned char* data, unsigned int, bool end)
{
bool ret = m_txData.hasSpace(DVAP_GMSK_DATA_LEN + 1U);
if (!ret) {
wxLogWarning(wxT("No space to write data"));
return false;
}
unsigned char buffer[20U];
::memcpy(buffer + 0U, DVAP_GMSK_DATA, DVAP_GMSK_DATA_LEN);
if (::memcmp(data + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES) == 0)
m_framePos = 0U;
wxUint16 sid = wxUINT16_SWAP_ON_BE(m_streamId);
::memcpy(buffer + 2U, &sid, sizeof(wxUint16));
buffer[4U] = m_framePos;
buffer[5U] = m_seq;
if (end)
buffer[4U] |= 0x40U;
::memcpy(buffer + 6U, data, DV_FRAME_LENGTH_BYTES);
wxMutexLocker locker(m_mutex);
unsigned char len = DVAP_GMSK_DATA_LEN;
m_txData.addData(&len, 1U);
m_txData.addData(buffer, DVAP_GMSK_DATA_LEN);
m_framePos++;
m_seq++;
return true;
}
unsigned int CDVAPController::getSpace()
{
return m_txData.freeSpace() / (DVAP_GMSK_DATA_LEN + 1U);
}
bool CDVAPController::isTXReady()
{
if (m_tx)
return false;
return m_txData.isEmpty();
}
bool CDVAPController::getSquelch() const
{
return m_squelchOpen;
}
int CDVAPController::getSignal() const
{
return m_signal;
}
void CDVAPController::writePoll()
{
#if defined(DVAP_DUMP)
storePacket(DVAP_ACK, DVAP_ACK_LEN);
#endif
m_serial.write(DVAP_ACK, DVAP_ACK_LEN);
}
bool CDVAPController::getName()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_NAME, DVAP_REQ_NAME_LEN);
if (ret != int(DVAP_REQ_NAME_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_NAME) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The Dongle is not replying with its name"));
return false;
}
}
} while (resp != RT_NAME);
bool cmp = ::memcmp(m_buffer, DVAP_RESP_NAME, length) == 0;
if (!cmp) {
wxLogError(wxT("The Dongle is not responding as a DVAP"));
return false;
}
return true;
}
bool CDVAPController::getFirmware()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_FIRMWARE, DVAP_REQ_FIRMWARE_LEN);
if (ret != int(DVAP_REQ_FIRMWARE_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_FIRMWARE) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding with its firmware version"));
return false;
}
}
} while (resp != RT_FIRMWARE);
unsigned int version = m_buffer[6U] * 256U + m_buffer[5U];
wxLogInfo(wxT("DVAP Firmware version: %u.%u"), version / 100U, version % 100U);
return true;
}
bool CDVAPController::getSerial()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_SERIAL, DVAP_REQ_SERIAL_LEN);
if (ret != int(DVAP_REQ_SERIAL_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_SERIAL) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding with its serial number"));
return false;
}
}
} while (resp != RT_SERIAL);
wxString serial((char*)(m_buffer + 4U), wxConvLocal, length - 5U);
wxLogInfo(wxT("DVAP Serial number: %s"), serial.c_str());
return true;
}
bool CDVAPController::startDVAP()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_START, DVAP_REQ_START_LEN);
if (ret != int(DVAP_REQ_START_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_START) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the start command"));
return false;
}
}
} while (resp != RT_START);
return true;
}
bool CDVAPController::stopDVAP()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_STOP, DVAP_REQ_STOP_LEN);
if (ret != int(DVAP_REQ_STOP_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_STOP) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the stop command"));
return false;
}
}
} while (resp != RT_STOP);
return true;
}
bool CDVAPController::setModulation()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_MODULATION, DVAP_REQ_MODULATION_LEN);
if (ret != int(DVAP_REQ_MODULATION_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_MODULATION) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the modulation command"));
return false;
}
}
} while (resp != RT_MODULATION);
return true;
}
bool CDVAPController::setMode()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_MODE, DVAP_REQ_MODE_LEN);
if (ret != int(DVAP_REQ_MODE_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_MODE) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the mode command"));
return false;
}
}
} while (resp != RT_MODE);
return true;
}
bool CDVAPController::setSquelch()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
unsigned char buffer[10U];
::memcpy(buffer, DVAP_REQ_SQUELCH, DVAP_REQ_SQUELCH_LEN);
::memcpy(buffer + 4U, &m_squelch, sizeof(wxInt8));
int ret = m_serial.write(buffer, DVAP_REQ_SQUELCH_LEN);
if (ret != int(DVAP_REQ_SQUELCH_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_SQUELCH) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the squelch command"));
return false;
}
}
} while (resp != RT_SQUELCH);
return true;
}
bool CDVAPController::setPower()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
unsigned char buffer[10U];
::memcpy(buffer, DVAP_REQ_POWER, DVAP_REQ_POWER_LEN);
wxInt16 power = wxINT16_SWAP_ON_BE(m_power);
::memcpy(buffer + 4U, &power, sizeof(wxInt16));
int ret = m_serial.write(buffer, DVAP_REQ_POWER_LEN);
if (ret != int(DVAP_REQ_POWER_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_POWER) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the power command"));
return false;
}
}
} while (resp != RT_POWER);
return true;
}
bool CDVAPController::setFrequency()
{
unsigned int count = 0U;
unsigned int length;
RESP_TYPE resp;
do {
int ret = m_serial.write(DVAP_REQ_FREQLIMITS, DVAP_REQ_FREQLIMITS_LEN);
if (ret != int(DVAP_REQ_FREQLIMITS_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_FREQLIMITS) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the frequency limits command"));
return false;
}
}
} while (resp != RT_FREQLIMITS);
wxUint32* pFreq1 = (wxUint32*)(m_buffer + 4U);
wxUint32* pFreq2 = (wxUint32*)(m_buffer + 8U);
wxUint32 lower = wxUINT32_SWAP_ON_BE(*pFreq1);
wxUint32 upper = wxUINT32_SWAP_ON_BE(*pFreq2);
wxLogInfo(wxT("DVAP frequency limits are %u Hz to %u Hz"), lower, upper);
if (m_frequency < lower || m_frequency > upper) {
wxLogError(wxT("The required frequency is out of the range of the DVAP hardware"));
m_serial.close();
return false;
}
count = 0U;
do {
unsigned char buffer[10U];
::memcpy(buffer, DVAP_REQ_FREQUENCY, DVAP_REQ_FREQUENCY_LEN);
wxUint32 frequency = wxUINT32_SWAP_ON_BE(m_frequency);
::memcpy(buffer + 4U, &frequency, sizeof(wxUint32));
int ret = m_serial.write(buffer, DVAP_REQ_FREQUENCY_LEN);
if (ret != int(DVAP_REQ_FREQUENCY_LEN)) {
m_serial.close();
return false;
}
::wxMilliSleep(50UL);
resp = getResponse(m_buffer, length);
if (resp != RT_FREQUENCY) {
count++;
if (count >= MAX_RESPONSES) {
wxLogError(wxT("The DVAP is not responding to the frequency command"));
return false;
}
}
} while (resp != RT_FREQUENCY);
return true;
}
RESP_TYPE CDVAPController::getResponse(unsigned char *buffer, unsigned int& length)
{
int ret = m_serial.read(buffer, DVAP_HEADER_LENGTH);
if (ret == 0)
return RT_TIMEOUT;
if (ret != int(DVAP_HEADER_LENGTH))
return RT_ERROR;
unsigned int offset = DVAP_HEADER_LENGTH;
// First byte has gone missing from the operation status message, fix it
if (buffer[0U] == 0x20U && buffer[1U] == 0x90U) {
buffer[0U] = 0x07U;
buffer[1U] = 0x20U;
buffer[2U] = 0x90U;
offset = DVAP_HEADER_LENGTH + 1U;
}
length = buffer[0U] + (buffer[1U] & 0x1FU) * 256U;
// Check for silliness
if (length > 50U) {
CUtils::dump(wxT("Bad DVAP header"), buffer, DVAP_HEADER_LENGTH);
#if defined(DVAP_DUMP)
dumpPackets();
#endif
resync();
return RT_TIMEOUT;
}
while (offset < length) {
ret = m_serial.read(buffer + offset, length - offset);
if (ret < 0)
return RT_ERROR;
if (ret > 0)
offset += ret;
if (ret == 0)
Sleep(5UL);
}
// CUtils::dump(wxT("Received"), buffer, length);
if (::memcmp(buffer, DVAP_STATUS, 4U) == 0)
return RT_STATE;
else if (::memcmp(buffer, DVAP_GMSK_DATA, 2U) == 0)
return RT_GMSK_DATA;
else if (::memcmp(buffer, DVAP_HEADER, 2U) == 0)
return RT_HEADER;
else if (::memcmp(buffer, DVAP_RESP_HEADER, 2U) == 0)
return RT_HEADER_ACK;
else if (::memcmp(buffer, DVAP_RESP_PTT, 4U) == 0)
return RT_PTT;
else if (::memcmp(buffer, DVAP_ACK, DVAP_ACK_LEN) == 0)
return RT_ACK;
else if (::memcmp(buffer, DVAP_FM_DATA, 2U) == 0)
return RT_FM_DATA;
else if (::memcmp(buffer, DVAP_RESP_START, DVAP_RESP_START_LEN) == 0)
return RT_START;
else if (::memcmp(buffer, DVAP_RESP_STOP, DVAP_RESP_STOP_LEN) == 0)
return RT_STOP;
else if (::memcmp(buffer, DVAP_RESP_NAME, 4U) == 0)
return RT_NAME;
else if (::memcmp(buffer + 1U, DVAP_RESP_SERIAL + 1U, 3U) == 0)
return RT_SERIAL;
else if (::memcmp(buffer, DVAP_RESP_FIRMWARE, 5U) == 0)
return RT_FIRMWARE;
else if (::memcmp(buffer, DVAP_RESP_FREQUENCY, 4U) == 0)
return RT_FREQUENCY;
else if (::memcmp(buffer, DVAP_RESP_FREQLIMITS, 4U) == 0)
return RT_FREQLIMITS;
else if (::memcmp(buffer, DVAP_RESP_MODULATION, DVAP_RESP_MODULATION_LEN) == 0)
return RT_MODULATION;
else if (::memcmp(buffer, DVAP_RESP_MODE, DVAP_RESP_MODE_LEN) == 0)
return RT_MODE;
else if (::memcmp(buffer, DVAP_RESP_POWER, 4U) == 0)
return RT_POWER;
else if (::memcmp(buffer, DVAP_RESP_SQUELCH, 4U) == 0)
return RT_SQUELCH;
else {
CUtils::dump(wxT("Bad DVAP data"), buffer, length);
#if defined(DVAP_DUMP)
dumpPackets();
#endif
resync();
return RT_TIMEOUT;
}
}
void CDVAPController::resync()
{
wxLogWarning(wxT("Resynchronising the DVAP data stream"));
unsigned char data[DVAP_STATUS_LEN];
::memset(data, 0x00U, DVAP_STATUS_LEN);
while (::memcmp(data, DVAP_STATUS, 4U) != 0) {
unsigned char c;
int n = m_serial.read(&c, 1U);
if (n > 0) {
data[0U] = data[1U];
data[1U] = data[2U];
data[2U] = data[3U];
data[3U] = data[4U];
data[4U] = data[5U];
data[5U] = data[6U];
data[6U] = c;
// CUtils::dump(wxT("Resync buffer"), data, DVAP_STATUS_LEN);
}
}
wxLogMessage(wxT("End resynchronising"));
}
#if defined(DVAP_DUMP)
void CDVAPController::storePacket(const unsigned char* data, unsigned int length)
{
::memcpy(m_dvapData[m_dvapIndex], data, length);
m_dvapLength[m_dvapIndex] = length;
m_dvapIndex++;
if (m_dvapIndex >= DVAP_DUMP_LENGTH)
m_dvapIndex = 0U;
}
void CDVAPController::dumpPackets()
{
unsigned int n = m_dvapIndex;
unsigned int i = 0U;
while (n != m_dvapIndex) {
if (m_dvapLength[n] > 0U) {
wxString text;
text.Printf(wxT("Packet: %u"), i);
CUtils::dump(text, m_dvapData[n], m_dvapLength[n]);
}
i++;
n++;
if (n >= DVAP_DUMP_LENGTH)
n = 0U;
}
m_dvapIndex = 0U;
}
#endif

Powered by TurnKey Linux.