File: gd77_codeplug.hh

package info (click to toggle)
qdmr 0.13.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 22,420 kB
  • sloc: cpp: 95,929; xml: 10,749; python: 1,108; makefile: 78; sh: 9
file content (379 lines) | stat: -rw-r--r-- 16,237 bytes parent folder | download
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
#ifndef GD77_CODEPLUG_HH
#define GD77_CODEPLUG_HH

#include "radioddity_codeplug.hh"
#include "signaling.hh"


/** Represents, encodes and decodes the device specific codeplug for a Radioddity GD-77.
 *
 * The GD-77 & GD-77S codeplugs are almost identical to the Radioddity/Baofeng @c RD5RCodeplug, in fact
 * the memory layout (see below) and almost all of the single components of the codeplug are encoded in
 * exactly the same way. Obviously, when Baofeng and Radioddity joint to create the RD5R,
 * Radioddity provided the firmware. However, there are some small subtle differences between
 * these two codeplug formats, requiring a separate class for the GD-77. For example, the contacts
 * and scan-lists swapped the addresses and the @c channel_t encoding analog and digital channels
 * for the codeplugs are identical except for the squelch settings. Thanks for that!
 *
 * @section gd77ver Matching firmware versions
 * This class implements the codeplug for the firmware version @b 4.03.06. The codeplug format usually
 * does not change much with firmware revisions, in particular not with older radios. Unfortunately,
 * it is not possible to detect the firmware version running on the device. Consequenly, only the
 * newest firmware version is supported. However, older revisions may still work.
 *
 * @section gd77cpl Codeplug structure within radio
 * The memory representation of the codeplug within the radio is divided into two segments.
 * The first segment starts at the address 0x00080 and ends at 0x07c00 while the second section
 * starts at 0x08000 and ends at 0x1e300.
 *
 * <table>
 *  <tr><th>Start</th>   <th>End</th>      <th>Size</th>    <th>Content</th></tr>
 *  <tr><th colspan="4">First segment 0x00080-0x07c00</th></tr>
 *  <tr><td>0x00080</td> <td>0x000e0</td> <td>0x0070</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x000e0</td> <td>0x000ec</td> <td>0x000c</td> <td>General settings, see @c RadioddityCodeplug::GeneralSettingsElement.</td></tr>
 *  <tr><td>0x000ec</td> <td>0x00108</td> <td>0x0028</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x00108</td> <td>0x00128</td> <td>0x0020</td> <td>Button settings, see @c RadioddityCodeplug::ButtonSettingsElement.</td></tr>
 *  <tr><td>0x00128</td> <td>0x01370</td> <td>0x1248</td> <td>32 preset message texts, see @c RadioddityCodeplug::MessageBankElement.</td></tr>
 *  <tr><td>0x01370</td> <td>0x01790</td> <td>0x0420</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x01790</td> <td>0x02dd0</td> <td>0x1640</td> <td>64 scan lists, see @c GD77Codeplug::ScanListBankElement and @c GD77Codeplug::ScanListElement</td></tr>
 *  <tr><td>0x02dd0</td> <td>0x02f88</td> <td>0x01b8</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x02f88</td> <td>0x03388</td> <td>0x0400</td> <td>DTMF contacts, see RadioddityCodeplug::DTMFContactElement.</td></tr>
 *  <tr><td>0x03388</td> <td>0x03780</td> <td>0x03f8</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x03780</td> <td>0x05390</td> <td>0x1c10</td> <td>First 128 channels (bank 0), see @c RadioddityCodeplug::ChannelBankElement and GD77Codeplug::ChannelElement</td></tr>
 *  <tr><td>0x05390</td> <td>0x07518</td> <td>0x2188</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x07518</td> <td>0x07538</td> <td>0x0020</td> <td>Boot settings, see @c RadioddityCodeplug::BootSettingsElement.</td></tr>
 *  <tr><td>0x07538</td> <td>0x07540</td> <td>0x0008</td> <td>Menu settings, see @c RadioddityCodeplug::MenuSettingsElement.</td></tr>
 *  <tr><td>0x07540</td> <td>0x07560</td> <td>0x0020</td> <td>2 intro lines, @c RadioddityCodeplug::BootTextElement.</td></tr>
 *  <tr><td>0x07560</td> <td>0x07590</td> <td>0x0030</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x07590</td> <td>0x075c8</td> <td>0x0038</td> <td>VFO A settings @c RadioddityCodeplug::VFOChannelElement</td></tr>
 *  <tr><td>0x075c8</td> <td>0x07600</td> <td>0x0038</td> <td>VFO B settings @c RadioddityCodeplug::VFOChannelElement</td></tr>
 *  <tr><td>0x07600</td> <td>0x07c00</td> <td>0x0600</td> <td>??? Unknown ???</td></tr>
 *
 *  <tr><th colspan="4">Second segment 0x08000-0x1e300</th></tr>
 *  <tr><td>0x08000</td> <td>0x08010</td> <td>0x0010</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x08010</td> <td>0x0af10</td> <td>0x2f00</td> <td>68 zones of 80 channels each, see @c RadioddityCodeplug::ZoneBankElement @c RadioddityCodeplug::ZoneElement.</td></tr>
 *  <tr><td>0x0af10</td> <td>0x0b1b0</td> <td>0x02a0</td> <td>??? Unknown ???</td></tr>
 *  <tr><td>0x0b1b0</td> <td>0x17620</td> <td>0xc470</td> <td>Remaining 896 channels (bank 1-7), see @c RadioddityCodeplug::ChannelBankElement, @c GD77Codeplug::ChannelElement.</td></tr>
 *  <tr><td>0x17620</td> <td>0x1d620</td> <td>0x6000</td> <td>1024 contacts, see @c GD77Codeplug::ContactElement.</td></tr>
 *  <tr><td>0x1d620</td> <td>0x1eaa0</td> <td>0x1480</td> <td>64 RX group lists, see @c GD77Codeplug::GroupListBankElement, @c GD77Codeplug::GroupListElement.</td></tr>
 *  <tr><td>0x1eaa0</td> <td>0x1eb00</td> <td>0x0060</td> <td>??? Unknown ???</td></tr>
 * </table>
 * @ingroup gd77 */
class GD77Codeplug: public RadioddityCodeplug
{
	Q_OBJECT

public:
  /** Channel representation within the binary codeplug.
   *
   * Each channel requires 0x38b:
   * @verbinclude gd77_channel.txt */
  class ChannelElement: public RadioddityCodeplug::ChannelElement
  {
  public:
    /** ARTS send. */
    enum ARTSMode {
      ARTS_OFF      = 0,
      ARTS_TX       = 1,
      ARTS_RX       = 2,
      ARTS_BOTH     = 3
    };

    /** STE angle. */
    enum STEAngle {
      STE_FREQUENCY = 0,              ///< STE Frequency.
      STE_120DEG    = 1,              ///< 120 degree.
      STE_180DEG    = 2,              ///< 180 degree.
      STE_240DEG    = 3               ///< 240 degree.
    };

    /** PTT ID send. */
    enum PTTId {
      PTTID_OFF     = 0,
      PTTID_START   = 1,
      PTTID_END     = 2,
      PTTID_BOTH    = 3
    };

  protected:
    /** Hidden Constructor. */
    ChannelElement(uint8_t *ptr, size_t size);

  public:
    /** Constructor. */
    explicit ChannelElement(uint8_t *ptr);

    void clear();

    /** Returns the ARTS mode. */
    virtual ARTSMode artsMode() const;
    /** Sets the ARTS mode. */
    virtual void setARTSMode(ARTSMode mode);

    /** Returns the STE angle. */
    virtual STEAngle steAngle() const;
    /** Sets the STE angle. */
    virtual void setSTEAngle(STEAngle angle);

    /** Returns the PTT ID mode. */
    virtual PTTId pttIDMode() const;
    /** Sets the PTT ID mode. */
    virtual void setPTTIDMode(PTTId mode);

    /** Returns @c true if the squech type is tight. */
    virtual bool squelchIsTight() const;
    /** Enables/disables tight squelch. */
    virtual void enableTightSquelch(bool enable);

    /** Returns @c true if lone worker is enabled. */
    virtual bool loneWorker() const;
    /** Enables/disables lone worker. */
    virtual void enableLoneWorker(bool enable);

    /** Returns @c true if auto scan is enabled. */
    virtual bool autoscan() const;
    /** Enables/disables auto scan. */
    virtual void enableAutoscan(bool enable);
  };

  /** Specific codeplug representation of a DMR contact for the GD77.
   *
   * Memory layout of the contact (0x18b):
   * @verbinclude gd77_contact.txt
   */
  class ContactElement: public RadioddityCodeplug::ContactElement
  {
  protected:
    /** Hidden constructor. */
    ContactElement(uint8_t *ptr, unsigned size);

  public:
    /** Constructor. */
    ContactElement(uint8_t *ptr);

    /** Resets the contact. */
    void clear();

    /** Returns @c true if the contact is valid. */
    bool isValid() const;
    /** Marks the entry as valid/invalid. */
    virtual void markValid(bool valid=true);

    bool fromContactObj(const DMRContact *obj, Context &ctx, const ErrorStack &err=ErrorStack());

  protected:
    /** Some internal offsets. */
    struct Offset: RadioddityCodeplug::ContactElement::Offset {
      /// @cond DO_NOT_DOCUMENT
      static constexpr unsigned int validFlag() { return 0x0017; }
      /// @endcond
    };
  };

  /** Represents an RX group list within the codeplug.
   *
   * The group list is encoded as (size 0x50b):
   * @verbinclude gd77_grouplist.txt */
  class GroupListElement: public RadioddityCodeplug::GroupListElement
  {
  protected:
    /** Hidden constructor. */
    GroupListElement(uint8_t *ptr, unsigned size);

  public:
    /** Constructor. */
    GroupListElement(uint8_t *ptr);

    /** The size of the element. */
    static constexpr unsigned int size() { return 0x0050; }

    virtual bool linkRXGroupListObj(unsigned int ncnt, RXGroupList *lst, Context &ctx, const ErrorStack &err = ErrorStack()) const;
    virtual bool fromRXGroupListObj(const RXGroupList *lst, Context &ctx, const ErrorStack &err = ErrorStack());

  public:
    /** Some limits for the group list. */
    struct Limit: public RadioddityCodeplug::GroupListElement {
      static constexpr unsigned int memberCount() { return 32; }  ///< Maximum number of entries.
    };
  };

  /** Table of RX group lists.
   *
   * The RX group list table constsis of a table of number of members per group list and the actual
   * list of RX group lists. The former also acts as a byte map for valid RX group lists. If 0, the
   * group list is disabled, if 1 the group list is empty, etc. So the entry is N+1, where N is the
   * number of entries per group list.
   *
   * Encoding of group list table:
   * @verbinclude gd77_grouplistbank.txt*/
  class GroupListBankElement: public RadioddityCodeplug::GroupListBankElement
  {
  protected:
    /** Hidden constructor. */
    GroupListBankElement(uint8_t *ptr, unsigned size);

  public:
    /** Constructor. */
    GroupListBankElement(uint8_t *ptr);

    /** The size of the group list bank. */
    static constexpr unsigned int size() { return 0x1480; }

    uint8_t *get(unsigned n) const;

  public:
    /** Some limits for the group list bank. */
    struct Limit: public RadioddityCodeplug::GroupListBankElement::Limit {
      static constexpr unsigned int groupListCount() { return 64; }   ///< Number of group lists.
    };
  };

  /** Represents a single scan list within the GD77 codeplug.
   *
   * Encoding of scan list (size: 0x58b):
   * @verbinclude gd77_scanlist.txt */
  class ScanListElement: public RadioddityCodeplug::ScanListElement
  {
  protected:
    /** Hidden constructor. */
    ScanListElement(uint8_t *ptr, unsigned size);

  public:
    /** Constructor. */
    ScanListElement(uint8_t *ptr);

    /** Resets the scan list. */
    void clear();
  };

  /** Bank of scan lists for the GD77.
   *
   * Encoding of scan list table (size 0x1640b):
   * @verbinclude gd77_scanlistbank.txt */
  class ScanListBankElement: public RadioddityCodeplug::ScanListBankElement
  {
  protected:
    /** Hidden constructor. */
    ScanListBankElement(uint8_t *ptr, unsigned size);

  public:
    /** Constructor. */
    ScanListBankElement(uint8_t *ptr);

    /** The size of the scan list bank. */
    static constexpr unsigned int size() { return 0x1640; }

    /** Clears the scan list bank. */
    void clear();

    uint8_t *get(unsigned n) const;

  public:
    /** Some limits for the scan list bank. */
    struct Limit: public RadioddityCodeplug::ScanListBankElement::Limit {
      static constexpr unsigned int scanListCount() { return 64; } ///< Maximum number of scan lists.
    };

  protected:
    /** Internal offsets within the element. */
    struct Offset: public RadioddityCodeplug::ScanListBankElement::Offset {
      /// @cond DO_NOT_DOCUMENT
      static constexpr unsigned int bytemap()   { return 0x0000; }
      static constexpr unsigned int scanLists() { return 0x0040; }
      /// @endcond
    };
  };

public:
  /** Constructs an empty codeplug for the GD-77. */
	explicit GD77Codeplug(QObject *parent=nullptr);

public:
  void clearGeneralSettings();
  bool encodeGeneralSettings(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool decodeGeneralSettings(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearButtonSettings();
  bool encodeButtonSettings(Context &ctx, const Flags &flags, const ErrorStack &err=ErrorStack());
  bool decodeButtonSettings(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearMessages();
  bool encodeMessages(Context &ctx, const Flags &flags, const ErrorStack &err=ErrorStack());
  bool decodeMessages(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearScanLists();
  bool encodeScanLists(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool createScanLists(Context &ctx, const ErrorStack &err=ErrorStack());
  bool linkScanLists(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearContacts();
  bool encodeContacts(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool createContacts(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearDTMFContacts();
  bool encodeDTMFContacts(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool createDTMFContacts(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearChannels();
  bool encodeChannels(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool createChannels(Context &ctx, const ErrorStack &err=ErrorStack());
  bool linkChannels(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearBootSettings();
  void clearMenuSettings();

  void clearBootText();
  bool encodeBootText(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool decodeBootText(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearVFOSettings();

  void clearZones();
  bool encodeZones(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool createZones(Context &ctx, const ErrorStack &err=ErrorStack());
  bool linkZones(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearGroupLists();
  bool encodeGroupLists(const Flags &flags, Context &ctx, const ErrorStack &err=ErrorStack());
  bool createGroupLists(Context &ctx, const ErrorStack &err=ErrorStack());
  bool linkGroupLists(Context &ctx, const ErrorStack &err=ErrorStack());

  void clearEncryption();
  bool encodeEncryption(const Flags &flags, Context &ctx, const ErrorStack &err);
  bool createEncryption(Context &ctx, const ErrorStack &err);
  bool linkEncryption(Context &ctx, const ErrorStack &err);

public:
  /** Some limits for the GD77 codeplug. */
  struct Limit {
    static constexpr unsigned int dtmfContactCount() { return 32; }   ///< Maximum number of DTMF contacts.
    static constexpr unsigned int channelBankCount() { return 8; }    ///< Number of channel banks.
    static constexpr unsigned int channelCount()     { return 1024; } ///< Maximum number of channels.
    static constexpr unsigned int contactCount()     { return 1024; } ///< Maximum number of contacts.
  };

protected:
  /** Some internal offsets within the codeplug. */
  struct Offset {
    /// @cond DO_NOT_DOCUMENT
    static constexpr unsigned int settings()        { return 0x0000e0; }
    static constexpr unsigned int buttons()         { return 0x000108; }
    static constexpr unsigned int messages()        { return 0x000128; }
    static constexpr unsigned int encryption()      { return 0x001370; }
    static constexpr unsigned int scanListBank()    { return 0x001790; }
    static constexpr unsigned int dtmfContacts()    { return 0x002f88; }
    static constexpr unsigned int channelBank0()    { return 0x003780; } // Channels 1-128
    static constexpr unsigned int bootSettings()    { return 0x007518; }
    static constexpr unsigned int bootText()        { return 0x007540; }
    static constexpr unsigned int menuSettings()    { return 0x007538; }
    static constexpr unsigned int vfoA()            { return 0x007590; }
    static constexpr unsigned int vfoB()            { return 0x0075c8; }
    static constexpr unsigned int zoneBank()        { return 0x008010; }
    static constexpr unsigned int channelBank1()    { return 0x00b1b0; } // Channels 129-1024
    static constexpr unsigned int contacts()        { return 0x017620; }
    static constexpr unsigned int groupListBank()   { return 0x01d620; }
    /// @endcond
  };
};

#endif // GD77_CODEPLUG_HH