Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
USBProtocol.h@35:e959ffba78fd, 2015-12-19 (annotated)
- Committer:
- mjr
- Date:
- Sat Dec 19 06:37:19 2015 +0000
- Revision:
- 35:e959ffba78fd
- Child:
- 38:091e511ce8a0
Keyboard/Media Control interface working, but the extra interface confuses the DOF connector.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 35:e959ffba78fd | 1 | // USB Message Protocol |
mjr | 35:e959ffba78fd | 2 | // |
mjr | 35:e959ffba78fd | 3 | // This file is purely for documentation, to describe our USB protocol. |
mjr | 35:e959ffba78fd | 4 | // We use the standard HID setup with one endpoint in each direction. |
mjr | 35:e959ffba78fd | 5 | // See USBJoystick.cpp/.h for our USB descriptor arrangement. |
mjr | 35:e959ffba78fd | 6 | // |
mjr | 35:e959ffba78fd | 7 | |
mjr | 35:e959ffba78fd | 8 | // ------ OUTGOING MESSAGES (DEVICE TO HOST) ------ |
mjr | 35:e959ffba78fd | 9 | // |
mjr | 35:e959ffba78fd | 10 | // In most cases, our outgoing messages are HID joystick reports, using the |
mjr | 35:e959ffba78fd | 11 | // format defined in USBJoystick.cpp. This allows us to be installed on |
mjr | 35:e959ffba78fd | 12 | // Windows as a standard USB joystick, which all versions of Windows support |
mjr | 35:e959ffba78fd | 13 | // using in-the-box drivers. This allows a completely transparent, driverless, |
mjr | 35:e959ffba78fd | 14 | // plug-and-play installation experience on Windows. |
mjr | 35:e959ffba78fd | 15 | // |
mjr | 35:e959ffba78fd | 16 | // We subvert the joystick report format in certain cases to report other |
mjr | 35:e959ffba78fd | 17 | // types of information, when specifically requested by the host. This allows |
mjr | 35:e959ffba78fd | 18 | // our custom configuration UI on the Windows side to query additional |
mjr | 35:e959ffba78fd | 19 | // information that we don't normally send via the joystick reports. We |
mjr | 35:e959ffba78fd | 20 | // define a custom vendor-specific "status" field in the reports that we |
mjr | 35:e959ffba78fd | 21 | // use to identify these special reports, as described below. |
mjr | 35:e959ffba78fd | 22 | // |
mjr | 35:e959ffba78fd | 23 | // Normal joystick reports always have 0 in the high bit of the first byte |
mjr | 35:e959ffba78fd | 24 | // of the report. Special non-joystick reports always have 1 in the high bit |
mjr | 35:e959ffba78fd | 25 | // of the first byte. (This byte is defined in the HID Report Descriptor |
mjr | 35:e959ffba78fd | 26 | // as an opaque vendor-defined value, so the joystick interface on the |
mjr | 35:e959ffba78fd | 27 | // Windows side simply ignores it.) |
mjr | 35:e959ffba78fd | 28 | // |
mjr | 35:e959ffba78fd | 29 | // Pixel dumps: requested by custom protocol message 65 3 (see below). |
mjr | 35:e959ffba78fd | 30 | // This sends a series of reports to the host in the following format, for |
mjr | 35:e959ffba78fd | 31 | // as many messages as are neessary to report all pixels: |
mjr | 35:e959ffba78fd | 32 | // |
mjr | 35:e959ffba78fd | 33 | // bytes 0:1 = 11-bit index, with high 5 bits set to 10000. For |
mjr | 35:e959ffba78fd | 34 | // example, 0x04 0x80 indicates index 4. This is the |
mjr | 35:e959ffba78fd | 35 | // starting pixel number in the report. The first report |
mjr | 35:e959ffba78fd | 36 | // will be 0x00 0x80 to indicate pixel #0. |
mjr | 35:e959ffba78fd | 37 | // bytes 2:3 = 16-bit unsigned int brightness level of pixel at index |
mjr | 35:e959ffba78fd | 38 | // bytes 4:5 = brightness of pixel at index+1 |
mjr | 35:e959ffba78fd | 39 | // etc for the rest of the packet |
mjr | 35:e959ffba78fd | 40 | // |
mjr | 35:e959ffba78fd | 41 | // Configuration query: requested by custom protocol message 65 4 (see |
mjr | 35:e959ffba78fd | 42 | // below). This sends one report to the host using this format: |
mjr | 35:e959ffba78fd | 43 | // |
mjr | 35:e959ffba78fd | 44 | // bytes 0:1 = 0x8800. This has the bit pattern 10001 in the high |
mjr | 35:e959ffba78fd | 45 | // 5 bits, which distinguishes it from regular joystick |
mjr | 35:e959ffba78fd | 46 | // reports and from exposure status reports. |
mjr | 35:e959ffba78fd | 47 | // bytes 2:3 = total number of outputs, little endian |
mjr | 35:e959ffba78fd | 48 | // bytes 4:5 = plunger calibration zero point, little endian |
mjr | 35:e959ffba78fd | 49 | // bytes 6:7 = plunger calibration maximum point, little endian |
mjr | 35:e959ffba78fd | 50 | // remaining bytes = reserved for future use; set to 0 in current version |
mjr | 35:e959ffba78fd | 51 | // |
mjr | 35:e959ffba78fd | 52 | // |
mjr | 35:e959ffba78fd | 53 | // WHY WE USE THIS HACKY APPROACH TO DIFFERENT REPORT TYPES |
mjr | 35:e959ffba78fd | 54 | // |
mjr | 35:e959ffba78fd | 55 | // The HID report system was specifically designed to provide a clean, |
mjr | 35:e959ffba78fd | 56 | // structured way for devices to describe the data they send to the host. |
mjr | 35:e959ffba78fd | 57 | // Our approach isn't clean or structured; it ignores the promises we |
mjr | 35:e959ffba78fd | 58 | // make about the contents of our report via the HID Report Descriptor |
mjr | 35:e959ffba78fd | 59 | // and stuffs our own different data format into the same structure. |
mjr | 35:e959ffba78fd | 60 | // |
mjr | 35:e959ffba78fd | 61 | // We use this hacky approach only because we can't use the official |
mjr | 35:e959ffba78fd | 62 | // mechanism, due to the constraint that we want to emulate the LedWiz. |
mjr | 35:e959ffba78fd | 63 | // The right way to send different report types is to declare different |
mjr | 35:e959ffba78fd | 64 | // report types via extra HID Report Descriptors, then send each report |
mjr | 35:e959ffba78fd | 65 | // using one of the types we declared. If it weren't for the LedWiz |
mjr | 35:e959ffba78fd | 66 | // constraint, we'd simply define the pixel dump and config query reports |
mjr | 35:e959ffba78fd | 67 | // as their own separate HID Report types, each consisting of opaque |
mjr | 35:e959ffba78fd | 68 | // blocks of bytes. But we can't do this. The snag is that some versions |
mjr | 35:e959ffba78fd | 69 | // of the LedWiz Windows host software parse the USB HID descriptors as part |
mjr | 35:e959ffba78fd | 70 | // of identifying a device as a valid LedWiz unit, and will only recognize |
mjr | 35:e959ffba78fd | 71 | // the device if it matches certain particulars about the descriptor |
mjr | 35:e959ffba78fd | 72 | // structure of a real LedWiz. One of the features that's important to |
mjr | 35:e959ffba78fd | 73 | // some versions of the software is the descriptor link structure, which |
mjr | 35:e959ffba78fd | 74 | // is affected by the layout of HID Report Descriptor entries. In order |
mjr | 35:e959ffba78fd | 75 | // to match the expected layout, we can only define a single kind of output |
mjr | 35:e959ffba78fd | 76 | // report. Since we have to use Joystick reports for the sake of VP and |
mjr | 35:e959ffba78fd | 77 | // other pinball software, and we're only allowed the one report type, we |
mjr | 35:e959ffba78fd | 78 | // have to make that one report type the Joystick type. That's why we |
mjr | 35:e959ffba78fd | 79 | // overload the joystick reports with other meanings. It's a hack, but |
mjr | 35:e959ffba78fd | 80 | // at least it's a fairly reliable and isolated hack, iun that our special |
mjr | 35:e959ffba78fd | 81 | // reports are only generated when clients specifically ask for them. |
mjr | 35:e959ffba78fd | 82 | // Plus, even if a client who doesn't ask for a special report somehow |
mjr | 35:e959ffba78fd | 83 | // gets one, the worst that happens is that they get a momentary spurious |
mjr | 35:e959ffba78fd | 84 | // reading from the accelerometer and plunger. |
mjr | 35:e959ffba78fd | 85 | |
mjr | 35:e959ffba78fd | 86 | |
mjr | 35:e959ffba78fd | 87 | |
mjr | 35:e959ffba78fd | 88 | // ------- INCOMING MESSAGES (HOST TO DEVICE) ------- |
mjr | 35:e959ffba78fd | 89 | // |
mjr | 35:e959ffba78fd | 90 | // For LedWiz compatibility, our incoming message format conforms to the |
mjr | 35:e959ffba78fd | 91 | // basic USB format used by real LedWiz units. This is simply 8 data |
mjr | 35:e959ffba78fd | 92 | // bytes, all private vendor-specific values (meaning that the Windows HID |
mjr | 35:e959ffba78fd | 93 | // driver treats them as opaque and doesn't attempt to parse them). |
mjr | 35:e959ffba78fd | 94 | // |
mjr | 35:e959ffba78fd | 95 | // Within this basic 8-byte format, we recognize the full protocol used |
mjr | 35:e959ffba78fd | 96 | // by real LedWiz units, plus an extended protocol that we define privately. |
mjr | 35:e959ffba78fd | 97 | // The LedWiz protocol leaves a large part of the potential protocol space |
mjr | 35:e959ffba78fd | 98 | // undefined, so we take advantage of this undefined region for our |
mjr | 35:e959ffba78fd | 99 | // extensions. This ensures that we can properly recognize all messages |
mjr | 35:e959ffba78fd | 100 | // intended for a real LedWiz unit, as well as messages from custom host |
mjr | 35:e959ffba78fd | 101 | // software that knows it's talking to a Pinscape unit. |
mjr | 35:e959ffba78fd | 102 | |
mjr | 35:e959ffba78fd | 103 | // --- REAL LED WIZ MESSAGES --- |
mjr | 35:e959ffba78fd | 104 | // |
mjr | 35:e959ffba78fd | 105 | // The real LedWiz protocol has two message types, identified by the first |
mjr | 35:e959ffba78fd | 106 | // byte of the 8-byte USB packet: |
mjr | 35:e959ffba78fd | 107 | // |
mjr | 35:e959ffba78fd | 108 | // 64 -> SBA (64 xx xx xx xx ss uu uu) |
mjr | 35:e959ffba78fd | 109 | // xx = on/off bit mask for 8 outputs |
mjr | 35:e959ffba78fd | 110 | // ss = global flash speed setting (1-7) |
mjr | 35:e959ffba78fd | 111 | // uu = unused |
mjr | 35:e959ffba78fd | 112 | // |
mjr | 35:e959ffba78fd | 113 | // If the first byte has value 64 (0x40), it's an SBA message. This type of |
mjr | 35:e959ffba78fd | 114 | // message sets all 32 outputs individually ON or OFF according to the next |
mjr | 35:e959ffba78fd | 115 | // 32 bits (4 bytes) of the message, and sets the flash speed to the value in |
mjr | 35:e959ffba78fd | 116 | // the sixth byte. (The flash speed sets the global cycle rate for flashing |
mjr | 35:e959ffba78fd | 117 | // outputs - outputs with their values set to the range 128-132 - to a |
mjr | 35:e959ffba78fd | 118 | // relative speed, scaled linearly in frequency. 1 is the slowest at about |
mjr | 35:e959ffba78fd | 119 | // 2 Hz, 7 is the fastest at about 14 Hz.) |
mjr | 35:e959ffba78fd | 120 | // |
mjr | 35:e959ffba78fd | 121 | // 0-49 or 128-132 -> PBA (bb bb bb bb bb bb bb bb) |
mjr | 35:e959ffba78fd | 122 | // bb = brightness level/flash pattern for one output |
mjr | 35:e959ffba78fd | 123 | // |
mjr | 35:e959ffba78fd | 124 | // If the first byte is any valid brightness setting, it's a PBA message. |
mjr | 35:e959ffba78fd | 125 | // Valid brightness settings are: |
mjr | 35:e959ffba78fd | 126 | // |
mjr | 35:e959ffba78fd | 127 | // 0-48 = fixed brightness level, linearly from 0% to 100% intensity |
mjr | 35:e959ffba78fd | 128 | // 49 = fixed brightness level at 100% intensity (same as 48) |
mjr | 35:e959ffba78fd | 129 | // 129 = flashing pattern, fade up / fade down (sawtooth wave) |
mjr | 35:e959ffba78fd | 130 | // 130 = flashing pattern, on / off (square wave) |
mjr | 35:e959ffba78fd | 131 | // 131 = flashing pattern, on for 50% duty cycle / fade down |
mjr | 35:e959ffba78fd | 132 | // 132 = flashing pattern, fade up / on for 50% duty cycle |
mjr | 35:e959ffba78fd | 133 | // |
mjr | 35:e959ffba78fd | 134 | // A PBA message sets 8 outputs out of 32. Which 8 are to be set is |
mjr | 35:e959ffba78fd | 135 | // implicit in the message sequence: the first PBA sets outputs 1-8, the |
mjr | 35:e959ffba78fd | 136 | // second sets 9-16, and so on, rolling around after each fourth PBA. |
mjr | 35:e959ffba78fd | 137 | // An SBA also resets the implicit "bank" for the next PBA to outputs 1-8. |
mjr | 35:e959ffba78fd | 138 | // |
mjr | 35:e959ffba78fd | 139 | // Note that there's no special first byte to indicate the PBA message |
mjr | 35:e959ffba78fd | 140 | // type, as there is in an SBA. The first byte of a PBA is simply the |
mjr | 35:e959ffba78fd | 141 | // first output setting. The way the LedWiz creators conceived this, the |
mjr | 35:e959ffba78fd | 142 | // SBA distinguishable from a PBA because 64 isn't a valid output setting, |
mjr | 35:e959ffba78fd | 143 | // hence a message that starts with a byte value of 64 isn't a valid PBA |
mjr | 35:e959ffba78fd | 144 | // message. |
mjr | 35:e959ffba78fd | 145 | // |
mjr | 35:e959ffba78fd | 146 | // Our extended protocol uses the same principle, taking advantage of the |
mjr | 35:e959ffba78fd | 147 | // other byte value ranges that are invalid in PBA messages. To be a valid |
mjr | 35:e959ffba78fd | 148 | // PBA message, the first byte must be in the range 0-49 or 129-132. As |
mjr | 35:e959ffba78fd | 149 | // already mentioned, byte value 64 indicates an SBA message. This leaves |
mjr | 35:e959ffba78fd | 150 | // these ranges available for other uses: 50-63, 65-128, and 133-255. |
mjr | 35:e959ffba78fd | 151 | |
mjr | 35:e959ffba78fd | 152 | |
mjr | 35:e959ffba78fd | 153 | // --- PRIVATE EXTENDED MESSAGES --- |
mjr | 35:e959ffba78fd | 154 | // |
mjr | 35:e959ffba78fd | 155 | // All of our extended protocol messages are identified by the first byte: |
mjr | 35:e959ffba78fd | 156 | // |
mjr | 35:e959ffba78fd | 157 | // 65 -> Miscellaneous control message. The second byte specifies the specific |
mjr | 35:e959ffba78fd | 158 | // operation: |
mjr | 35:e959ffba78fd | 159 | // |
mjr | 35:e959ffba78fd | 160 | // 1 -> Set device unit number and plunger status, and save the changes immediately |
mjr | 35:e959ffba78fd | 161 | // to flash. The device will automatically reboot after the changes are saved. |
mjr | 35:e959ffba78fd | 162 | // The additional bytes of the message give the parameters: |
mjr | 35:e959ffba78fd | 163 | // |
mjr | 35:e959ffba78fd | 164 | // third byte = new unit number (0-15, corresponding to nominal unit numbers 1-16) |
mjr | 35:e959ffba78fd | 165 | // fourth byte = plunger on/off (0=disabled, 1=enabled) |
mjr | 35:e959ffba78fd | 166 | // |
mjr | 35:e959ffba78fd | 167 | // 2 -> Begin plunger calibration mode. The device stays in this mode for about |
mjr | 35:e959ffba78fd | 168 | // 15 seconds, and sets the zero point and maximum retraction points to the |
mjr | 35:e959ffba78fd | 169 | // observed endpoints of sensor readings while the mode is running. After |
mjr | 35:e959ffba78fd | 170 | // the time limit elapses, the device automatically stores the results in |
mjr | 35:e959ffba78fd | 171 | // non-volatile flash memory and exits the mode. |
mjr | 35:e959ffba78fd | 172 | // |
mjr | 35:e959ffba78fd | 173 | // 3 -> Send pixel dump. The plunger sensor object sends a series of the special |
mjr | 35:e959ffba78fd | 174 | // pixel dump reports, defined in USBJoystick.cpp; the device automatically |
mjr | 35:e959ffba78fd | 175 | // resumes normal joystick messages after sending all pixels. If the |
mjr | 35:e959ffba78fd | 176 | // plunger sensor isn't an image sensor type, no pixel messages are sent. |
mjr | 35:e959ffba78fd | 177 | // |
mjr | 35:e959ffba78fd | 178 | // 4 -> Query configuration. The device sends a special configuration report, |
mjr | 35:e959ffba78fd | 179 | // defined in USBJoystick.cpp, then resumes sending normal joystick reports. |
mjr | 35:e959ffba78fd | 180 | // |
mjr | 35:e959ffba78fd | 181 | // 5 -> Turn all outputs off and restore LedWiz defaults. Sets output ports |
mjr | 35:e959ffba78fd | 182 | // 1-32 to OFF and LedWiz brightness/mode setting 48, sets outputs 33 and |
mjr | 35:e959ffba78fd | 183 | // higher to brightness level 0, and sets the LedWiz global flash speed to 2. |
mjr | 35:e959ffba78fd | 184 | // |
mjr | 35:e959ffba78fd | 185 | // 6 -> Save configuration to flash. This saves all variable updates sent via |
mjr | 35:e959ffba78fd | 186 | // type 66 messages since the last reboot, then automatically reboots the |
mjr | 35:e959ffba78fd | 187 | // device to put the changes into effect. |
mjr | 35:e959ffba78fd | 188 | // |
mjr | 35:e959ffba78fd | 189 | // 66 -> Set configuration variable. The second byte of the message is the config |
mjr | 35:e959ffba78fd | 190 | // variable number, and the remaining bytes give the new value for the variable. |
mjr | 35:e959ffba78fd | 191 | // The value format is specific to each variable; see the list below for details. |
mjr | 35:e959ffba78fd | 192 | // This message only sets the value in RAM - it doesn't write the value to flash |
mjr | 35:e959ffba78fd | 193 | // and doesn't put the change into effect immediately. To put updates into effect, |
mjr | 35:e959ffba78fd | 194 | // the host must send a type 65 subtype 6 message (see above), which saves updates |
mjr | 35:e959ffba78fd | 195 | // to flash and reboots the device. |
mjr | 35:e959ffba78fd | 196 | // |
mjr | 35:e959ffba78fd | 197 | // 200-228 -> Set extended output brightness. This sets outputs N to N+6 to the |
mjr | 35:e959ffba78fd | 198 | // respective brightness values in the 2nd through 8th bytes of the message |
mjr | 35:e959ffba78fd | 199 | // (output N is set to the 2nd byte value, N+1 is set to the 3rd byte value, |
mjr | 35:e959ffba78fd | 200 | // etc). Each brightness level is a linear brightness level from 0-255, |
mjr | 35:e959ffba78fd | 201 | // where 0 is 0% brightness and 255 is 100% brightness. N is calculated as |
mjr | 35:e959ffba78fd | 202 | // (first byte - 200)*7 + 1: |
mjr | 35:e959ffba78fd | 203 | // |
mjr | 35:e959ffba78fd | 204 | // 200 = outputs 1-7 |
mjr | 35:e959ffba78fd | 205 | // 201 = outputs 8-14 |
mjr | 35:e959ffba78fd | 206 | // 202 = outputs 15-21 |
mjr | 35:e959ffba78fd | 207 | // ... |
mjr | 35:e959ffba78fd | 208 | // 228 = outputs 197-203 |
mjr | 35:e959ffba78fd | 209 | // |
mjr | 35:e959ffba78fd | 210 | // This message is the only way to address ports 33 and higher, since standard |
mjr | 35:e959ffba78fd | 211 | // LedWiz messages are inherently limited to ports 1-32. |
mjr | 35:e959ffba78fd | 212 | // |
mjr | 35:e959ffba78fd | 213 | // Note that these extended output messages differ from regular LedWiz settings |
mjr | 35:e959ffba78fd | 214 | // in two ways. First, the brightness is the ONLY attribute when an output is |
mjr | 35:e959ffba78fd | 215 | // set using this mode - there's no separate ON/OFF setting per output as there |
mjr | 35:e959ffba78fd | 216 | // is with the SBA/PBA messages. To turn an output OFF with this message, set |
mjr | 35:e959ffba78fd | 217 | // the intensity to 0. Setting a non-zero intensity turns it on immediately |
mjr | 35:e959ffba78fd | 218 | // without regard to the SBA status for the port. Second, the brightness is |
mjr | 35:e959ffba78fd | 219 | // on a full 8-bit scale (0-255) rather than the LedWiz's approximately 5-bit |
mjr | 35:e959ffba78fd | 220 | // scale, because there are no parts of the range reserved for flashing modes. |
mjr | 35:e959ffba78fd | 221 | // |
mjr | 35:e959ffba78fd | 222 | // Outputs 1-32 can be controlled by EITHER the regular LedWiz SBA/PBA messages |
mjr | 35:e959ffba78fd | 223 | // or by the extended messages. The latest setting for a given port takes |
mjr | 35:e959ffba78fd | 224 | // precedence. If an SBA/PBA message was the last thing sent to a port, the |
mjr | 35:e959ffba78fd | 225 | // normal LedWiz combination of ON/OFF and brightness/flash mode status is used |
mjr | 35:e959ffba78fd | 226 | // to determine the port's physical output setting. If an extended brightness |
mjr | 35:e959ffba78fd | 227 | // message was the last thing sent to a port, the LedWiz ON/OFF status and |
mjr | 35:e959ffba78fd | 228 | // flash modes are ignored, and the fixed brightness is set. Outputs 33 and |
mjr | 35:e959ffba78fd | 229 | // higher inherently can't be addressed or affected by SBA/PBA messages. |
mjr | 35:e959ffba78fd | 230 | |
mjr | 35:e959ffba78fd | 231 | |
mjr | 35:e959ffba78fd | 232 | // ------- CONFIGURATION VARIABLES ------- |
mjr | 35:e959ffba78fd | 233 | // |
mjr | 35:e959ffba78fd | 234 | // Message type 66 (see above) sets one configuration variable. The second byte |
mjr | 35:e959ffba78fd | 235 | // of the message is the variable ID, and the rest of the bytes give the new |
mjr | 35:e959ffba78fd | 236 | // value, in a variable-specific format. 16-bit values are little endian. |
mjr | 35:e959ffba78fd | 237 | // |
mjr | 35:e959ffba78fd | 238 | // 1 -> USB device ID. Bytes 3-4 give the 16-bit USB Vendor ID; bytes |
mjr | 35:e959ffba78fd | 239 | // 5-6 give the 16-bit USB Product ID. For LedWiz emulation, use |
mjr | 35:e959ffba78fd | 240 | // vendor 0xFAFA and product 0x00EF + unit# (where unit# is the |
mjr | 35:e959ffba78fd | 241 | // nominal LedWiz unit number, from 1 to 16). If LedWiz emulation |
mjr | 35:e959ffba78fd | 242 | // isn't desired or causes host conflicts, you can use our private |
mjr | 35:e959ffba78fd | 243 | // ID assigned by http://pid.codes (a registry for open-source USB |
mjr | 35:e959ffba78fd | 244 | // devices) of vendor 0x1209 and product 0xEAEA. (You can also use |
mjr | 35:e959ffba78fd | 245 | // any other values that don't cause a conflict on your PC, but we |
mjr | 35:e959ffba78fd | 246 | // recommend using one of these pre-assigned values if possible.) |
mjr | 35:e959ffba78fd | 247 | // |
mjr | 35:e959ffba78fd | 248 | // 2 -> Pinscape Controller unit number for DOF. Byte 3 is the new |
mjr | 35:e959ffba78fd | 249 | // unit number, from 1 to 16. |
mjr | 35:e959ffba78fd | 250 | // |
mjr | 35:e959ffba78fd | 251 | // 3 -> Enable/disable joystick reports. Byte 2 is 1 to enable, 0 to |
mjr | 35:e959ffba78fd | 252 | // disable. When disabled, the device registers as a generic HID |
mjr | 35:e959ffba78fd | 253 | / device, and only sends the private report types used by the |
mjr | 35:e959ffba78fd | 254 | // Windows config tool. |
mjr | 35:e959ffba78fd | 255 | // |
mjr | 35:e959ffba78fd | 256 | // 4 -> Accelerometer orientation. Byte 3 is the new setting: |
mjr | 35:e959ffba78fd | 257 | // |
mjr | 35:e959ffba78fd | 258 | // 0 = ports at front (USB ports pointing towards front of cabinet) |
mjr | 35:e959ffba78fd | 259 | // 1 = ports at left |
mjr | 35:e959ffba78fd | 260 | // 2 = ports at right |
mjr | 35:e959ffba78fd | 261 | // 3 = ports at rear |
mjr | 35:e959ffba78fd | 262 | // |
mjr | 35:e959ffba78fd | 263 | // 5 -> Plunger sensor type. Byte 3 is the type ID: |
mjr | 35:e959ffba78fd | 264 | // |
mjr | 35:e959ffba78fd | 265 | // 0 = none (disabled) |
mjr | 35:e959ffba78fd | 266 | // 1 = TSL1410R linear image sensor, 1280x1 pixels, serial mode |
mjr | 35:e959ffba78fd | 267 | // 2 = TSL1410R, parallel mode |
mjr | 35:e959ffba78fd | 268 | // 3 = TSL1412R linear image sensor, 1536x1 pixels, serial mode |
mjr | 35:e959ffba78fd | 269 | // 4 = TSL1412R, parallel mode |
mjr | 35:e959ffba78fd | 270 | // 5 = Potentiometer with linear taper, or any other device that |
mjr | 35:e959ffba78fd | 271 | // represents the position reading with a single analog voltage |
mjr | 35:e959ffba78fd | 272 | // 6 = AEDR8300 optical quadrature sensor, 75lpi |
mjr | 35:e959ffba78fd | 273 | // 7 = AS5304 magnetic quadrature sensor, 160 steps per 2mm |
mjr | 35:e959ffba78fd | 274 | // |
mjr | 35:e959ffba78fd | 275 | // 6 -> Plunger pin assignments. Bytes 3-6 give the pin assignments for |
mjr | 35:e959ffba78fd | 276 | // pins 1, 2, 3, and 4. These use the Pin Number Mappings listed |
mjr | 35:e959ffba78fd | 277 | // below. The meaning of each pin depends on the plunger type: |
mjr | 35:e959ffba78fd | 278 | // |
mjr | 35:e959ffba78fd | 279 | // TSL1410R/1412R, serial: SI (DigitalOut), CLK (DigitalOut), AO (AnalogIn), NC |
mjr | 35:e959ffba78fd | 280 | // TSL1410R/1412R, parallel: SI (DigitalOut), CLK (DigitalOut), AO1 (AnalogIn), AO2 (AnalogIn) |
mjr | 35:e959ffba78fd | 281 | // Potentiometer: AO (AnalogIn), NC, NC, NC |
mjr | 35:e959ffba78fd | 282 | // AEDR8300: A (InterruptIn), B (InterruptIn), NC, NC |
mjr | 35:e959ffba78fd | 283 | // AS5304: A (InterruptIn), B (InterruptIn), NC, NC |
mjr | 35:e959ffba78fd | 284 | // |
mjr | 35:e959ffba78fd | 285 | // 7 -> Plunger calibration button pin assignments. Byte 3 is the DigitalIn |
mjr | 35:e959ffba78fd | 286 | // pin for the button switch; byte 4 is the DigitalOut pin for the indicator |
mjr | 35:e959ffba78fd | 287 | // lamp. Either can be set to NC to disable the function. (Use the Pin |
mjr | 35:e959ffba78fd | 288 | // Number Mappins listed below for both bytes.) |
mjr | 35:e959ffba78fd | 289 | // |
mjr | 35:e959ffba78fd | 290 | // 8 -> ZB Launch Ball setup. This configures the ZB Launch Ball feature. Byte |
mjr | 35:e959ffba78fd | 291 | // 3 is the LedWiz port number (1-255) mapped to the "ZB Launch Ball" output |
mjr | 35:e959ffba78fd | 292 | // in DOF. Set the port to 0 to disable the feature. Byte 4 is the button |
mjr | 35:e959ffba78fd | 293 | // number (1-32) that we'll "press" when the feature is activated. Bytes 5-6 |
mjr | 35:e959ffba78fd | 294 | // give the "push distance" for activating the button by pushing forward on |
mjr | 35:e959ffba78fd | 295 | // the plunger knob, in .001 inch increments (e.g., 80 represents 0.08", which |
mjr | 35:e959ffba78fd | 296 | // is the recommended setting). |
mjr | 35:e959ffba78fd | 297 | // |
mjr | 35:e959ffba78fd | 298 | // 9 -> TV ON relay setup. This requires external circuitry implemented on the |
mjr | 35:e959ffba78fd | 299 | // Expansion Board (or an equivalent circuit as described in the Build Guide). |
mjr | 35:e959ffba78fd | 300 | // Byte 3 is the GPIO DigitalIn pin for the "power status" input, using the |
mjr | 35:e959ffba78fd | 301 | // Pin Number Mappings below. Byte 4 is the DigitalOut pin for the "latch" |
mjr | 35:e959ffba78fd | 302 | // output. Byte 5 is the DigitalOut pin for the relay trigger. Bytes 6-7 |
mjr | 35:e959ffba78fd | 303 | // give the delay time in 10ms increments as an unsigned 16-bit value (e.g., |
mjr | 35:e959ffba78fd | 304 | // 550 represents 5.5 seconds). |
mjr | 35:e959ffba78fd | 305 | // |
mjr | 35:e959ffba78fd | 306 | // 10 -> TLC5940NT setup. This chip is an external PWM controller, with 32 outputs |
mjr | 35:e959ffba78fd | 307 | // per chip and a serial data interface that allows the chips to be daisy- |
mjr | 35:e959ffba78fd | 308 | // chained. We can use these chips to add an arbitrary number of PWM output |
mjr | 35:e959ffba78fd | 309 | // ports for the LedWiz emulation. Set the number of chips to 0 to disable |
mjr | 35:e959ffba78fd | 310 | // the feature. The bytes of the message are: |
mjr | 35:e959ffba78fd | 311 | // byte 3 = number of chips attached (connected in daisy chain) |
mjr | 35:e959ffba78fd | 312 | // byte 4 = SIN pin - Serial data (must connect to SPIO MOSI -> PTC6 or PTD2) |
mjr | 35:e959ffba78fd | 313 | // byte 5 = SCLK pin - Serial clock (must connect to SPIO SCLK -> PTC5 or PTD1) |
mjr | 35:e959ffba78fd | 314 | // byte 6 = XLAT pin - XLAT (latch) signal (any GPIO pin) |
mjr | 35:e959ffba78fd | 315 | // byte 7 = BLANK pin - BLANK signal (any GPIO pin) |
mjr | 35:e959ffba78fd | 316 | // byte 8 = GSCLK pin - Grayscale clock signal (must be a PWM-out capable pin) |
mjr | 35:e959ffba78fd | 317 | // |
mjr | 35:e959ffba78fd | 318 | // 11 -> 74HC595 setup. This chip is an external shift register, with 8 outputs per |
mjr | 35:e959ffba78fd | 319 | // chip and a serial data interface that allows daisy-chaining. We use this |
mjr | 35:e959ffba78fd | 320 | // chips to add extra digital outputs for the LedWiz emulation. In particular, |
mjr | 35:e959ffba78fd | 321 | // the Chime Board (part of the Expansion Board suite) uses these to add timer- |
mjr | 35:e959ffba78fd | 322 | // protected outputs for coil devices (knockers, chimes, bells, etc). Set the |
mjr | 35:e959ffba78fd | 323 | // number of chips to 0 to disable the feature. The message bytes are: |
mjr | 35:e959ffba78fd | 324 | // byte 3 = number of chips attached (connected in daisy chain) |
mjr | 35:e959ffba78fd | 325 | // byte 4 = SIN pin - Serial data (any GPIO pin) |
mjr | 35:e959ffba78fd | 326 | // byte 5 = SCLK pin - Serial clock (any GPIO pin) |
mjr | 35:e959ffba78fd | 327 | // byte 6 = LATCH pin - LATCH signal (any GPIO pin) |
mjr | 35:e959ffba78fd | 328 | // byte 7 = ENA pin - ENABLE signal (any GPIO pin) |
mjr | 35:e959ffba78fd | 329 | // |
mjr | 35:e959ffba78fd | 330 | // 12 -> Input button setup. This sets up one button; it can be repeated for each |
mjr | 35:e959ffba78fd | 331 | // button to be configured. There are 32 button slots, numbered 1-32. Each |
mjr | 35:e959ffba78fd | 332 | // key can be configured as a joystick button, a regular keyboard key, a |
mjr | 35:e959ffba78fd | 333 | // keyboard modifier key (such as Shift, Ctrl, or Alt), or a media control |
mjr | 35:e959ffba78fd | 334 | // key (such as volume up/down). |
mjr | 35:e959ffba78fd | 335 | // |
mjr | 35:e959ffba78fd | 336 | // The bytes of the message are: |
mjr | 35:e959ffba78fd | 337 | // byte 3 = Button number (1-32) |
mjr | 35:e959ffba78fd | 338 | // byte 4 = GPIO pin to read for button input |
mjr | 35:e959ffba78fd | 339 | // byte 5 = key type reported to PC when button is pushed: |
mjr | 35:e959ffba78fd | 340 | // 1 = joystick button -> byte 6 is the button number, 1-32 |
mjr | 35:e959ffba78fd | 341 | // 2 = regular keyboard key -> byte 6 is the USB key code (see below) |
mjr | 35:e959ffba78fd | 342 | // 3 = keyboard modifier key -> byte 6 is the USB modifier code (see below) |
mjr | 35:e959ffba78fd | 343 | // 4 = media control key -> byte 6 is the USB key code (see below) |
mjr | 35:e959ffba78fd | 344 | // byte 6 = key code, which depends on the key type in byte 5 |
mjr | 35:e959ffba78fd | 345 | // |
mjr | 35:e959ffba78fd | 346 | // 13 -> LedWiz output port setup. This sets up one output port; it can be repeated |
mjr | 35:e959ffba78fd | 347 | // for each port to be configured. There are 203 possible slots for output ports, |
mjr | 35:e959ffba78fd | 348 | // numbered 1 to 203. The number of ports visible to the host is determined by |
mjr | 35:e959ffba78fd | 349 | // the first DISABLED port (type 0). For example, if ports 1-32 are set as GPIO |
mjr | 35:e959ffba78fd | 350 | // outputs and port 33 is disabled, the host will see 32 ports, regardless of |
mjr | 35:e959ffba78fd | 351 | // the settings for post 34 and higher. |
mjr | 35:e959ffba78fd | 352 | // |
mjr | 35:e959ffba78fd | 353 | // The bytes of the message are: |
mjr | 35:e959ffba78fd | 354 | // byte 3 = LedWiz port number (1 to maximum number or ports) |
mjr | 35:e959ffba78fd | 355 | // byte 4 = physical output type: |
mjr | 35:e959ffba78fd | 356 | // 0 = Disabled. This output isn't used, and isn't visible to the |
mjr | 35:e959ffba78fd | 357 | // LedWiz/DOF software on the host. The FIRST disabled port |
mjr | 35:e959ffba78fd | 358 | // determines the number of ports visible to the host - ALL ports |
mjr | 35:e959ffba78fd | 359 | // after the first disabled port are also implicitly disabled. |
mjr | 35:e959ffba78fd | 360 | // 1 = GPIO PWM output: connected to GPIO pin specified in byte 5, |
mjr | 35:e959ffba78fd | 361 | // operating in PWM mode. Note that only a subset of KL25Z GPIO |
mjr | 35:e959ffba78fd | 362 | // ports are PWM-capable. |
mjr | 35:e959ffba78fd | 363 | // 2 = GPIO Digital output: connected to GPIO pin specified in byte 5, |
mjr | 35:e959ffba78fd | 364 | // operating in digital mode. Digital ports can only be set ON |
mjr | 35:e959ffba78fd | 365 | // or OFF, with no brightness/intensity control. All pins can be |
mjr | 35:e959ffba78fd | 366 | // used in this mode. |
mjr | 35:e959ffba78fd | 367 | // 3 = TLC5940 port: connected to TLC5940 output port number specified |
mjr | 35:e959ffba78fd | 368 | // in byte 5. Ports are numbered sequentially starting from port 0 |
mjr | 35:e959ffba78fd | 369 | // for the first output (OUT0) on the first chip in the daisy chain. |
mjr | 35:e959ffba78fd | 370 | // 4 = 74HC595 port: connected to 74HC595 output port specified in byte 5. |
mjr | 35:e959ffba78fd | 371 | // As with the TLC5940 outputs, ports are numbered sequentially from 0 |
mjr | 35:e959ffba78fd | 372 | // for the first output on the first chip in the daisy chain. |
mjr | 35:e959ffba78fd | 373 | // 5 = Virtual output: this output port exists for the purposes of the |
mjr | 35:e959ffba78fd | 374 | // LedWiz/DOF software on the host, but isn't physically connected |
mjr | 35:e959ffba78fd | 375 | // to any output device. This can be used to create a virtual output |
mjr | 35:e959ffba78fd | 376 | // for the DOF ZB Launch Ball signal, for example, or simply as a |
mjr | 35:e959ffba78fd | 377 | // placeholder in the LedWiz port numbering. The physical output ID |
mjr | 35:e959ffba78fd | 378 | // (byte 5) is ignored for this port type. |
mjr | 35:e959ffba78fd | 379 | // byte 5 = physical output ID, interpreted according to the value in byte 4 |
mjr | 35:e959ffba78fd | 380 | // byte 6 = flags: a combination of these bit values: |
mjr | 35:e959ffba78fd | 381 | // 1 = active-high output (0V on output turns attached device ON) |
mjr | 35:e959ffba78fd | 382 | |
mjr | 35:e959ffba78fd | 383 | |
mjr | 35:e959ffba78fd | 384 | // --- PIN NUMBER MAPPINGS --- |
mjr | 35:e959ffba78fd | 385 | // |
mjr | 35:e959ffba78fd | 386 | // In USB messages that specify GPIO pin assignments, pins are identified with |
mjr | 35:e959ffba78fd | 387 | // our own private numbering scheme. Our numbering scheme only includes the |
mjr | 35:e959ffba78fd | 388 | // ports connected to external header pins on the KL25Z board, so this is only |
mjr | 35:e959ffba78fd | 389 | // a sparse subset of the full GPIO port set. These are numbered in order of |
mjr | 35:e959ffba78fd | 390 | // pin name. The special value 0 = NC = Not Connected can be used where |
mjr | 35:e959ffba78fd | 391 | // appropriate to indicate a disabled or unused pin. |
mjr | 35:e959ffba78fd | 392 | // |
mjr | 35:e959ffba78fd | 393 | // 0 = NC (not connected) |
mjr | 35:e959ffba78fd | 394 | // 1 = PTA1 |
mjr | 35:e959ffba78fd | 395 | // 2 = PTA2 |
mjr | 35:e959ffba78fd | 396 | // 3 = PTA4 |
mjr | 35:e959ffba78fd | 397 | // 4 = PTA5 |
mjr | 35:e959ffba78fd | 398 | // 5 = PTA12 |
mjr | 35:e959ffba78fd | 399 | // 6 = PTA13 |
mjr | 35:e959ffba78fd | 400 | // 7 = PTA16 |
mjr | 35:e959ffba78fd | 401 | // 8 = PTA17 |
mjr | 35:e959ffba78fd | 402 | // 9 = PTB0 |
mjr | 35:e959ffba78fd | 403 | // 10 = PTB1 |
mjr | 35:e959ffba78fd | 404 | // 11 = PTB2 |
mjr | 35:e959ffba78fd | 405 | // 12 = PTB3 |
mjr | 35:e959ffba78fd | 406 | // 13 = PTB8 |
mjr | 35:e959ffba78fd | 407 | // 14 = PTB9 |
mjr | 35:e959ffba78fd | 408 | // 15 = PTB10 |
mjr | 35:e959ffba78fd | 409 | // 16 = PTB11 |
mjr | 35:e959ffba78fd | 410 | // 17 = PTC0 |
mjr | 35:e959ffba78fd | 411 | // 18 = PTC1 |
mjr | 35:e959ffba78fd | 412 | // 19 = PTC2 |
mjr | 35:e959ffba78fd | 413 | // 20 = PTC3 |
mjr | 35:e959ffba78fd | 414 | // 21 = PTC4 |
mjr | 35:e959ffba78fd | 415 | // 22 = PTC5 |
mjr | 35:e959ffba78fd | 416 | // 23 = PTC6 |
mjr | 35:e959ffba78fd | 417 | // 24 = PTC7 |
mjr | 35:e959ffba78fd | 418 | // 25 = PTC8 |
mjr | 35:e959ffba78fd | 419 | // 26 = PTC9 |
mjr | 35:e959ffba78fd | 420 | // 27 = PTC10 |
mjr | 35:e959ffba78fd | 421 | // 28 = PTC11 |
mjr | 35:e959ffba78fd | 422 | // 29 = PTC12 |
mjr | 35:e959ffba78fd | 423 | // 30 = PTC13 |
mjr | 35:e959ffba78fd | 424 | // 31 = PTC16 |
mjr | 35:e959ffba78fd | 425 | // 32 = PTC17 |
mjr | 35:e959ffba78fd | 426 | // 33 = PTD0 |
mjr | 35:e959ffba78fd | 427 | // 34 = PTD1 |
mjr | 35:e959ffba78fd | 428 | // 35 = PTD2 |
mjr | 35:e959ffba78fd | 429 | // 36 = PTD3 |
mjr | 35:e959ffba78fd | 430 | // 37 = PTD4 |
mjr | 35:e959ffba78fd | 431 | // 38 = PTD5 |
mjr | 35:e959ffba78fd | 432 | // 39 = PTD6 |
mjr | 35:e959ffba78fd | 433 | // 40 = PTD7 |
mjr | 35:e959ffba78fd | 434 | // 41 = PTE0 |
mjr | 35:e959ffba78fd | 435 | // 42 = PTE1 |
mjr | 35:e959ffba78fd | 436 | // 43 = PTE2 |
mjr | 35:e959ffba78fd | 437 | // 44 = PTE3 |
mjr | 35:e959ffba78fd | 438 | // 45 = PTE4 |
mjr | 35:e959ffba78fd | 439 | // 46 = PTE5 |
mjr | 35:e959ffba78fd | 440 | // 47 = PTE20 |
mjr | 35:e959ffba78fd | 441 | // 48 = PTE21 |
mjr | 35:e959ffba78fd | 442 | // 49 = PTE22 |
mjr | 35:e959ffba78fd | 443 | // 50 = PTE23 |
mjr | 35:e959ffba78fd | 444 | // 51 = PTE29 |
mjr | 35:e959ffba78fd | 445 | // 52 = PTE30 |
mjr | 35:e959ffba78fd | 446 | // 53 = PTE31 |
mjr | 35:e959ffba78fd | 447 | |
mjr | 35:e959ffba78fd | 448 | |
mjr | 35:e959ffba78fd | 449 | // --- USB KEYBOARD SCAN CODES --- |
mjr | 35:e959ffba78fd | 450 | // |
mjr | 35:e959ffba78fd | 451 | // Use the standard USB HID keyboard codes for regular keys. See the |
mjr | 35:e959ffba78fd | 452 | // HID Usage Tables in the official USB specifications for a full list. |
mjr | 35:e959ffba78fd | 453 | // Here are the most common codes for quick references: |
mjr | 35:e959ffba78fd | 454 | // |
mjr | 35:e959ffba78fd | 455 | // A-Z -> 4-29 |
mjr | 35:e959ffba78fd | 456 | // top row numbers -> 30-39 |
mjr | 35:e959ffba78fd | 457 | // Return -> 40 |
mjr | 35:e959ffba78fd | 458 | // Escape -> 41 |
mjr | 35:e959ffba78fd | 459 | // Backspace -> 42 |
mjr | 35:e959ffba78fd | 460 | // Tab -> 43 |
mjr | 35:e959ffba78fd | 461 | // Spacebar -> 44 |
mjr | 35:e959ffba78fd | 462 | // -_ -> 45 |
mjr | 35:e959ffba78fd | 463 | // =+ -> 46 |
mjr | 35:e959ffba78fd | 464 | // [{ -> 47 |
mjr | 35:e959ffba78fd | 465 | // ]} -> 48 |
mjr | 35:e959ffba78fd | 466 | // \| -> 49 |
mjr | 35:e959ffba78fd | 467 | // ;: -> 51 |
mjr | 35:e959ffba78fd | 468 | // '" -> 52 |
mjr | 35:e959ffba78fd | 469 | // `~ -> 53 |
mjr | 35:e959ffba78fd | 470 | // ,< -> 54 |
mjr | 35:e959ffba78fd | 471 | // .> -> 55 |
mjr | 35:e959ffba78fd | 472 | // /? -> 56 |
mjr | 35:e959ffba78fd | 473 | // Caps Lock -> 57 |
mjr | 35:e959ffba78fd | 474 | // F1-F12 -> 58-69 |
mjr | 35:e959ffba78fd | 475 | // F13-F24 -> 104-115 |
mjr | 35:e959ffba78fd | 476 | // Print Screen -> 70 |
mjr | 35:e959ffba78fd | 477 | // Scroll Lock -> 71 |
mjr | 35:e959ffba78fd | 478 | // Pause -> 72 |
mjr | 35:e959ffba78fd | 479 | // Insert -> 73 |
mjr | 35:e959ffba78fd | 480 | // Home -> 74 |
mjr | 35:e959ffba78fd | 481 | // Page Up -> 75 |
mjr | 35:e959ffba78fd | 482 | // Del -> 76 |
mjr | 35:e959ffba78fd | 483 | // End -> 77 |
mjr | 35:e959ffba78fd | 484 | // Page Down -> 78 |
mjr | 35:e959ffba78fd | 485 | // Right Arrow -> 79 |
mjr | 35:e959ffba78fd | 486 | // Left Arrow -> 80 |
mjr | 35:e959ffba78fd | 487 | // Down Arrow -> 81 |
mjr | 35:e959ffba78fd | 488 | // Up Arrow -> 82 |
mjr | 35:e959ffba78fd | 489 | // Num Lock/Clear -> 83 |
mjr | 35:e959ffba78fd | 490 | // Keypad / * - + -> 84 85 86 87 |
mjr | 35:e959ffba78fd | 491 | // Keypad Enter -> 88 |
mjr | 35:e959ffba78fd | 492 | // Keypad 1-9 -> 89-97 |
mjr | 35:e959ffba78fd | 493 | // Keypad 0 -> 98 |
mjr | 35:e959ffba78fd | 494 | // Keypad . -> 99 |
mjr | 35:e959ffba78fd | 495 | // |
mjr | 35:e959ffba78fd | 496 | |
mjr | 35:e959ffba78fd | 497 | |
mjr | 35:e959ffba78fd | 498 | // --- USB KEYBOARD MODIFIER KEY CODES --- |
mjr | 35:e959ffba78fd | 499 | // |
mjr | 35:e959ffba78fd | 500 | // Use these codes for modifier keys in the button mappings |
mjr | 35:e959ffba78fd | 501 | // |
mjr | 35:e959ffba78fd | 502 | // 0x01 = Left Control |
mjr | 35:e959ffba78fd | 503 | // 0x02 = Left Shift |
mjr | 35:e959ffba78fd | 504 | // 0x04 = Left Alt |
mjr | 35:e959ffba78fd | 505 | // 0x08 = Left GUI ("Windows" key) |
mjr | 35:e959ffba78fd | 506 | // 0x10 = Right Control |
mjr | 35:e959ffba78fd | 507 | // 0x20 = Right Shift |
mjr | 35:e959ffba78fd | 508 | // 0x40 = Right Alt |
mjr | 35:e959ffba78fd | 509 | // 0x80 = Right GUI ("Windows" key) |
mjr | 35:e959ffba78fd | 510 | |
mjr | 35:e959ffba78fd | 511 | |
mjr | 35:e959ffba78fd | 512 | // --- USB KEYBOARD MEDIA KEY CODES --- |
mjr | 35:e959ffba78fd | 513 | // |
mjr | 35:e959ffba78fd | 514 | // Use these for media control keys in the button mappings |
mjr | 35:e959ffba78fd | 515 | // |
mjr | 35:e959ffba78fd | 516 | // 0x01 = Volume Up |
mjr | 35:e959ffba78fd | 517 | // 0x02 = Volume Down |
mjr | 35:e959ffba78fd | 518 | // 0x04 = Mute on/off |
mjr | 35:e959ffba78fd | 519 |