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
|
#ifndef TYTINTERFACE_HH
#define TYTINTERFACE_HH
#include "dfu_libusb.hh"
#include "radiointerface.hh"
/** Interface to TyT (and Retevis) devices.
*
* This class extends the @c DFUDevice and implements the @c RadioInterface to identify the radio,
* reading/writing and erasing codeplugs or the callsign DB.
*
* @section tytif TyT protocol
* The communication with the device is kind of weird. It all happens through memory reads and
* writes. This is not unusual as such, but they implemented a weird memory mapping. Everything
* written to block 0 (i.e., memory address 0x00000000) is a command to the radio. Responses to
* these commands are read back from the same address/block.
*
* The funny thing is, however, that there is a command that sets the memory read and write address,
* although the DFU interface actually provides means to specify that address. Moreover, commands
* and data are sent and written to the same DFU interface number. Someone did not understand the
* DFU interface.
*
* @subsection Commands
* The following commands has been seen.
*
* @subsubsection tytifepm Enter program mode
* The request written is
* @code
* +------+------+
* | 0x91 | 0x01 |
* +------+------+
* @endcode
* There is no explicit response read back.
*
* @subsubsection tytiferb Reboot
* The request written is
* @code
* +------+------+
* | 0x91 | 0x05 |
* +------+------+
* @endcode
* There is no explicit response read back.
*
* @subsubsection tyifid Identify/Get Info
* The request written is
* @code
* +------+------+
* | 0xa2 | What |
* +------+------+
* @endcode
* There is always some response read back. The size varies with whatever is read back.
* <table>
* <tr><th>WhatCode</th> <th>Resp. Len.</th> <th>Description></th></tr>
* <tr><td>0x01</td> <td>32</td> <td>The radio identifier as a string + some unknown
* information.</td></tr>
* <tr><td>0x02</td> <td>4</td> <td>Unknown</td></tr>
* <tr><td>0x03</td> <td>24</td> <td>Unknown</td></tr>
* <tr><td>0x04</td> <td>8</td> <td>Unknown</td></tr>
* <tr><td>0x07</td> <td>16</td> <td>Unknown</td></tr>
* </table>
*
* @ingroup tyt */
class TyTInterface : public DFUSEDevice, public RadioInterface
{
Q_OBJECT
public:
/** Constructor. Opens an interface to the specified interface. */
TyTInterface(const USBDeviceDescriptor &descr,
const ErrorStack &err=ErrorStack(), QObject *parent=nullptr);
/** Destructor. */
~TyTInterface();
bool isOpen() const;
RadioInfo identifier(const ErrorStack &err=ErrorStack());
void close();
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());
/** Erases a memory section at @c start of size @c size. */
bool erase(unsigned start, unsigned size, void (*progress)(unsigned, void *)=nullptr, void *ctx=nullptr, const ErrorStack &err=ErrorStack());
public:
/** Returns some information about the interface. */
static USBDeviceInfo interfaceInfo();
/** Tries to find all interfaces connected TyT radios. */
static QList<USBDeviceDescriptor> detect(bool saveOnly=true);
protected:
/** Internal used function to send a control command to the device. */
int md380_command(uint8_t a, uint8_t b, const ErrorStack &err=ErrorStack());
/** Internal used function to set the current I/O address. */
int set_address(uint32_t address, const ErrorStack &err=ErrorStack());
/** Internal used function to erase a specific block. */
int erase_block(uint32_t address, const ErrorStack &err=ErrorStack());
/** Internal used function to read the device identifier. */
const char *identify(const ErrorStack &err=ErrorStack());
protected:
/** Read identifier. */
RadioInfo _ident;
};
#endif // TYTINTERFACE_HH
|