File: anytone_interface.hh

package info (click to toggle)
qdmr 0.13.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 22,424 kB
  • sloc: cpp: 96,043; xml: 10,749; python: 1,108; makefile: 78; sh: 9
file content (189 lines) | stat: -rw-r--r-- 7,193 bytes parent folder | download | duplicates (2)
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