1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
#ifndef ANYTONEINTERFACE_HH
#define ANYTONEINTERFACE_HH
#include "usbserial.hh"
/** Implements the interface to Anytone D868UV, D878UV, etc radios.
*
* This interface uses a USB serial-port to communicate with the device. To find the corresponding
* port, the device-specific VID @c 0x28e9 and PID @c 0x018a are used. Hence no udev rules are
* needed to access these devices. The user, however, should be a member of the @c dialout group
* to get access to the serial interfaces.
*
* @ingroup anytone */
class AnytoneInterface : public USBSerial
{
Q_OBJECT
public:
/** Collects information about the particular radio being accessed. */
struct RadioVariant {
/** The name of the radio. */
QString name;
/** A code for which bands are supported. */
char bands;
/** The (firmware/hardware) version. */
QString version;
/** Empty constructor. */
RadioVariant();
/** Returns @c true if the radio info is valid. */
bool isValid() const;
};
public:
/** Constructs a new interface to Anytone radios. If a matching device was found, @c isOpen
* returns @c true. */
explicit AnytoneInterface(const USBDeviceDescriptor &descriptor,
const ErrorStack &err=ErrorStack(), QObject *parent=nullptr);
/** Destructor. */
virtual ~AnytoneInterface();
/** Closes the interface to the device. */
void close();
/** Reads the radio info from the device and returns it.
* The information is only read once. */
bool getInfo(RadioVariant &info);
bool read_start(uint32_t bank, uint32_t addr, const ErrorStack &err=ErrorStack());
bool read(uint32_t bank, uint32_t addr, uint8_t *data, int nbytes, const ErrorStack &err=ErrorStack());
bool read_finish(const ErrorStack &err=ErrorStack());
bool write_start(uint32_t bank, uint32_t addr, const ErrorStack &err=ErrorStack());
bool write(uint32_t bank, uint32_t addr, uint8_t *data, int nbytes, const ErrorStack &err=ErrorStack());
bool write_finish(const ErrorStack &err=ErrorStack());
bool reboot(const ErrorStack &err=ErrorStack());
protected:
/** Send command message to radio to ender program state. */
bool enter_program_mode(const ErrorStack &err=ErrorStack());
/** Sends a request to radio to identify itself. */
bool request_identifier(RadioVariant &info, const ErrorStack &err=ErrorStack());
/** Sends a command message to radio to leave program state and reboot. */
bool leave_program_mode(const ErrorStack &err=ErrorStack());
/** Internal used method to send messages to and receive responses from radio. */
bool send_receive(const char *cmd, int clen, char *resp, int rlen, const ErrorStack &err=ErrorStack());
protected:
/** Binary representation of a read request to the radio. */
struct __attribute__((packed)) ReadRequest {
char cmd; ///< Fixed to 'R'.
uint32_t addr; ///< Memory address in little-endian.
uint8_t size; ///< Fixed to 16.
/// Constructs a read request for the specified address.
ReadRequest(uint32_t addr);
};
/** Binary representation of a read response from the radio. */
struct __attribute__((packed)) ReadResponse {
char cmd; ///< Fixed to 'W'.
uint32_t addr; ///< Memory address in big-endian.
uint8_t size; ///< Fixed to 16.
char data[16]; ///< The actual data.
uint8_t sum; ///< Sum over address, size and data.
uint8_t ack; ///< Fixed to 0x06.
/** Check the response, returns @c true if read request was successful.
* @param addr The read address to verify.
* @param msg On error, contains a message describing the issue. */
bool check(uint32_t addr, QString &msg) const;
};
/** Binary representation of a write request to the radio. */
struct __attribute__((packed)) WriteRequest {
char cmd; ///< Fixed to 'W'
uint32_t addr; ///< Memory address in big-endian.
uint8_t size; ///< Fixed to 16
char data[16]; ///< The actual data.
uint8_t sum; ///< Sum over addr, size and data.
uint8_t ack; ///< Fixed to 0x06;
/** Assembles a write request message to the given address with the given data.
* @param addr Specifies the address to write to.
* @param data 16 bytes of payload. */
WriteRequest(uint32_t addr, const char *data);
};
/** Structure of radio information response. */
struct __attribute__((packed)) RadioInfoResponse {
char prefix; ///< Fixed prefix. Set to 'I' on success.
char model[7]; ///< Model name.
uint8_t bands; ///< Frequency bands supported by radio.
char version[6]; ///< Version number. Either hardware or 'radio' version.
uint8_t eot; ///< Fixed 0x06 on success.
};
/** Possible states of the radio interface. */
enum State {
STATE_INITIALIZED, ///< Initial state.
STATE_OPEN, ///< Interface to radio is open.
STATE_PROGRAM, ///< Radio is in program mode.
STATE_CLOSED, ///< Interface to radio is closed (captive final state).
STATE_ERROR ///< An error occurred (captive final state),
/// use @c errorMessage() to get an error message.
};
/** Holds the state of the interface. */
State _state;
/** Holds the radio info. */
RadioVariant _info;
};
/** Implements the interface to Anytone GD32 revisions of D578UV radios.
*
* This interface is identical to the previous ones, except it uses a different VID/PID combo.
* That is VID @c 0x2e3c and PID @c 0x5740 are used.
*
* @ingroup anytone */
class AnytoneGD32Interface: public AnytoneInterface
{
Q_OBJECT
public:
/** Constructs a new interface to Anytone radios. If a matching device was found, @c isOpen
* returns @c true. */
explicit AnytoneGD32Interface(const USBDeviceDescriptor &descriptor,
const ErrorStack &err=ErrorStack(), QObject *parent=nullptr);
/** Returns an identifier of the radio. */
RadioInfo identifier(const ErrorStack &err=ErrorStack());
public:
/** Returns some information about this interface. */
static USBDeviceInfo interfaceInfo();
/** Tries to find all interfaces connected AnyTone radios. */
static QList<USBDeviceDescriptor> detect(bool saveOnly=true);
};
/** Implements the interface to Anytone SMT32 revisions of D578UV radios.
*
* This interface is identical to the previous ones, except it uses a different VID/PID combo.
* That is VID @c 0x2e3c and PID @c 0x5740 are used.
*
* @ingroup anytone */
class AnytoneSTM32Interface: public AnytoneInterface
{
Q_OBJECT
public:
/** Constructs a new interface to Anytone radios. If a matching device was found, @c isOpen
* returns @c true. */
explicit AnytoneSTM32Interface(const USBDeviceDescriptor &descriptor,
const ErrorStack &err=ErrorStack(), QObject *parent=nullptr);
/** Returns an identifier of the radio. */
RadioInfo identifier(const ErrorStack &err=ErrorStack());
public:
/** Returns some information about this interface. */
static USBDeviceInfo interfaceInfo();
/** Tries to find all interfaces connected AnyTone radios. */
static QList<USBDeviceDescriptor> detect(bool saveOnly=true);
};
#endif // ANYTONEINTERFACE_HH
|