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.

161 lines
4.7 KiB

/*
* Copyright (C) 2011-2014 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 DVAPController_H
#define DVAPController_H
#define DVAP_DUMP
#include "SerialDataController.h"
#include "RingBuffer.h"
#include "HeaderData.h"
#include "Modem.h"
#include "Utils.h"
#include "StdCompat.h"
#include <string>
#include <cstdint>
enum RESP_TYPE {
RT_TIMEOUT,
RT_ERROR,
RT_UNKNOWN,
RT_NAME,
RT_SERIAL,
RT_FIRMWARE,
RT_START,
RT_STOP,
RT_MODULATION,
RT_MODE,
RT_SQUELCH,
RT_POWER,
RT_FREQUENCY,
RT_FREQLIMITS,
RT_STATE,
RT_PTT,
RT_ACK,
RT_HEADER,
RT_HEADER_ACK,
RT_GMSK_DATA,
RT_FM_DATA
};
/*
* CDVAPController - Driver for the DVAP USB dongle (Digital Voice Access Point).
*
* Hardware interface: USB CDC-ACM serial at 230400 baud.
*
* Protocol: Binary, little-endian framing.
* Every frame begins with a 2-byte header:
* byte[0] = total frame length (low byte)
* byte[1] = flags in upper 3 bits; length high bits in lower 5
* The command/type is encoded in bytes[2..3].
*
* Startup sequence (enforced in start()):
* getName() -> getFirmware() -> getSerial() ->
* setModulation() -> setMode() -> setSquelch() -> setPower() -> setFrequency() ->
* startDVAP()
*
* During operation (entry() thread):
* - Polls every ~2s by sending a 3-byte ACK (writePoll()).
* - The DVAP sends RT_STATE packets every ~20ms containing RSSI, squelch
* state, and TX buffer space; these are used to clock outbound data writes.
* - Received headers and GMSK voice frames are forwarded to m_rxData (the
* CModem shared RX ring buffer) as DSMTT_HEADER / DSMTT_DATA / DSMTT_EOT
* typed records.
* - If the DVAP spontaneously sends an FM_DATA packet it has lost GMSK lock;
* the driver restarts modulation to recover.
*
* Power: -12 to +10 dBm (int16_t, little-endian in wire frame).
* Squelch: -128 to -45 (int8_t, signed dBm threshold).
* Frequency: 32-bit Hz, validated against dongle-reported hardware limits.
*
* DVAP_DUMP build flag enables a circular packet trace buffer (last 30 frames)
* that is dumped to the log on any error or unexpected FM mode event.
*/
class CDVAPController : public CModem {
public:
CDVAPController(const std::string& port, unsigned int frequency, int power, int squelch);
virtual ~CDVAPController();
virtual bool start();
virtual unsigned int getSpace();
virtual bool isTXReady();
virtual bool getSquelch() const;
virtual int getSignal() const;
virtual bool writeHeader(const CHeaderData& header);
virtual bool writeData(const unsigned char* data, unsigned int length, bool end);
private:
void entry();
CSerialDataController m_serial;
uint32_t m_frequency;
int16_t m_power;
int8_t m_squelch;
std::atomic<bool> m_squelchOpen;
std::atomic<int> m_signal;
unsigned char* m_buffer;
uint16_t m_streamId;
uint8_t m_framePos;
uint8_t m_seq;
CRingBuffer<unsigned char> m_txData;
#if defined(DVAP_DUMP)
unsigned char** m_dvapData;
unsigned int* m_dvapLength;
unsigned int m_dvapIndex;
#endif
bool getName();
bool getFirmware();
bool getSerial();
bool setModulation();
bool setMode();
bool setSquelch();
bool setPower();
bool setFrequency();
bool startDVAP();
bool stopDVAP();
// Sends a 3-byte keepalive ACK; DVAP requires periodic traffic to stay active.
void writePoll();
// Resynchronises the byte stream after a framing error by discarding bytes
// one at a time until a complete RT_STATE (status) header is found.
// Called when getResponse() receives an unrecognisable or oversized frame.
void resync();
// Reads one complete binary frame from the serial port into buffer.
// Returns a RESP_TYPE identifying the frame kind, or RT_TIMEOUT if no
// data is available and RT_ERROR on a read failure.
RESP_TYPE getResponse(unsigned char* buffer, unsigned int& length);
#if defined(DVAP_DUMP)
void storePacket(const unsigned char* data, unsigned int length);
void dumpPackets();
#endif
};
#endif

Powered by TurnKey Linux.