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
|