1 /****************************************************************************** 2 * Filename: rf_hid_cmd.h 3 * 4 * Description: CC13x2/CC26x2 API for HID commands 5 * 6 * Copyright (c) 2015 - 2020, Texas Instruments Incorporated 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * 12 * 1) Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * 2) Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 ******************************************************************************/ 36 /*!***************************************************************************** 37 * @file rf_hid_cmd.h 38 * @brief RF HID command interface for CC13x2, CC26x2 39 * 40 * 41 * To use the CMD_HID_TX and CMD_HID_RX commands, make sure that the following 42 * override list is being used: 43 * @code 44 * #define TURNAROUND_TIME 64 // 64 µs turnaround time 45 * uint32_t pOverridesCommon[] = 46 * { 47 * // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x3 (DITHER_EN=0 and IPEAK=3). 48 * (uint32_t)0x00F388D3, 49 * // Set pilot tone length to 4 us (enable phase error discard as early as possible) 50 * HW_REG_OVERRIDE(0x6024,0x0020), 51 * // Bluetooth 5: Default to no CTE. 52 * HW_REG_OVERRIDE(0x5328,0x0000), 53 * // Synth: Increase mid code calibration time to 5 us 54 * (uint32_t)0x00058683, 55 * // Synth: Increase mid code calibration time to 5 us 56 * HW32_ARRAY_OVERRIDE(0x4004,1), 57 * // Synth: Increase mid code calibration time to 5 us 58 * (uint32_t)0x38183C30, 59 * // HID: Reduce turnaround times: 60 * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0263, // modify tx to rx turnaround time 61 * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0283, // modify rx to tx turnaround time 62 * // Of of override list 63 * (uint32_t)0xFFFFFFFF 64 * }; 65 * @endcode 66 * 67 * @anchor rf_hid_overview 68 * # Overview 69 * The HID commands are designed to be compatible with CC254x devices, 70 * using the same protocol as the CC254x. 71 * The packet are defined as: 72 * 8 bit preamble, 32 bit sync word, optional 8 bit address, 8 or 9 bit header, 73 * [0-n] byte payload and 16 bit CRC at 2 Mbps. 74 * The HID commands uses the same automode functionality as found in the 75 * CC254x devices, see [CC254x user guide](https://www.ti.com/lit/ug/swru283b/swru283b.pdf). 76 * 77 * The CMD_HID_TX utlizes a TX queue to evaluate if the subsequent packet 78 * should be sent, given that the device is not retranmitting the previous packet. 79 * On submission of the CMD_HID_TX, the radio will check if there are TX 80 * entries in the queue. If TX entires are present, the radio will start sending 81 * the packets as defined by the startTrigger. If no packets are present, the radio 82 * will enter a wait-state, waiting on CMD_TRIGGER_HID_TX. Once CMD_TRIGGER_HID_TX 83 * is submitted, the radio will re-evaluate the TX queue, and if packets are present 84 * , the radio will start sending the TX packets as defined by the startTrigger. 85 * If no entries in the TX queue has been submitted, or CMD_STOP/CMD_ABORT was 86 * submitted, the CMD_HID_TX will end and the radio is ready for another command. 87 * 88 * 89 * <hr> 90 * @anchor rf_hid_Usage 91 * # Usage 92 * 93 * This documentation provides basic @ref rf_hid_settings_c 94 * "rf_hid_settings.c", @ref rf_hid_settings_h 95 * "rf_hid_settings.h" and a set of @ref rf_hid_Examples "examples" 96 * in the form of commented code fragments. Detailed descriptions of the 97 * APIs are provided in subsequent sections. 98 * 99 * @anchor rf_hid_settings 100 * ## RF HID settings 101 * @anchor rf_hid_settings_c 102 * @code 103 * // Filename: rf_hid_settings.c 104 * 105 * // Import the settings header file 106 * #include "rf_hid_settings.h" 107 * 108 * // Import the RF driver definitions 109 * #include <ti/drivers/rf/RF.h> 110 * 111 * // Import the needed radio files 112 * #include <ti/devices/DeviceFamily.h> 113 * #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) 114 * #include DeviceFamily_constructPath(driverlib/rf_hid_cmd.h) 115 * #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_multi_protocol_hid.h) 116 * #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) 117 * #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) 118 * 119 * 120 * // TI-RTOS RF Mode Object 121 * RF_Mode RF_hid = 122 * { 123 * .rfMode = RF_MODE_PROPRIETARY, 124 * .cpePatchFxn = &rf_patch_cpe_multi_protocol_hid, 125 * .mcePatchFxn = 0, 126 * .rfePatchFxn = 0 127 * }; 128 * 129 * // TX and RX queue declarations 130 * uint8_t txEntry1[BUFFER_LEN]; 131 * uint8_t txEntry2[BUFFER_LEN]; 132 * uint8_t rxEntry1[BUFFER_LEN]; 133 * uint8_t rxEntry2[BUFFER_LEN]; 134 * 135 * dataQueue_t txQ = { 136 * .pCurrEntry = NULL, 137 * .pLastEntry = NULL, 138 * }; 139 * 140 * dataQueue_t rxQ = { 141 * .pCurrEntry = NULL, 142 * .pLastEntry = NULL, 143 * }; 144 * 145 * // Statistics 146 * rfc_hidRxTxOutput_t rxTxStatistics; 147 * 148 * // Override list. 64 us turnaround compatible with fastest setting 149 * // for CC254x devices 150 * #define TURNAROUND_TIME 64 // Turnaround time in usec 151 * uint32_t pOverridesCommon[] = 152 * { 153 * // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x3 (DITHER_EN=0 and IPEAK=3). 154 * (uint32_t)0x00F388D3, 155 * // Set pilot tone length to 4 us (enable phase error discard as early as possible) 156 * HW_REG_OVERRIDE(0x6024,0x0020), 157 * // Bluetooth 5: Default to no CTE. 158 * HW_REG_OVERRIDE(0x5328,0x0000), 159 * // Synth: Increase mid code calibration time to 5 us 160 * (uint32_t)0x00058683, 161 * // Synth: Increase mid code calibration time to 5 us 162 * HW32_ARRAY_OVERRIDE(0x4004,1), 163 * // Synth: Increase mid code calibration time to 5 us 164 * (uint32_t)0x38183C30, 165 * // HID: Reduce turnaround times: 166 * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0263, // modify tx to rx turnaround time 167 * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0283, // modify rx to tx turnaround time 168 * // Of of override list 169 * (uint32_t)0xFFFFFFFF 170 * }; 171 * 172 * // CMD_RADIO_SETUP 173 * // Radio setup for HID command 174 * rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = 175 * { 176 * .commandNo = CMD_RADIO_SETUP, 177 * .status = 0x0000, 178 * .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx 179 * .startTime = 0x00000000, 180 * .startTrigger.triggerType = 0x0, 181 * .startTrigger.bEnaCmd = 0x0, 182 * .startTrigger.triggerNo = 0x0, 183 * .startTrigger.pastTrig = 0x0, 184 * .condition.rule = 0x1, 185 * .condition.nSkip = 0x0, 186 * .mode = 0x2, // HID mode 187 * .loDivider = 0x00, 188 * .config.frontEndMode = 0x0, 189 * .config.biasMode = 0x0, 190 * .config.analogCfgMode = 0x0, 191 * .config.bNoFsPowerUp = 0x0, 192 * .txPower = 0x7217, 193 * .pRegOverride = pOverridesCommon, 194 * }; 195 * 196 * // CMD_FS 197 * // Frequency Synthesizer Programming Command 198 * rfc_CMD_FS_t RF_cmdFs = 199 * { 200 * .commandNo = 0x0803, 201 * .status = 0x0000, 202 * .pNextOp = 0, 203 * .startTime = 0x00000000, 204 * .startTrigger.triggerType = 0x0, 205 * .startTrigger.bEnaCmd = 0x0, 206 * .startTrigger.triggerNo = 0x0, 207 * .startTrigger.pastTrig = 0x1, 208 * .condition.rule = 0x1, 209 * .condition.nSkip = 0x0, 210 * .frequency = 2440, 211 * .fractFreq = 0x0000, 212 * .synthConf.bTxMode = 0x0, 213 * .synthConf.refFreq = 0x0, 214 * .__dummy0 = 0x00, 215 * .__dummy1 = 0x00, 216 * .__dummy2 = 0x00, 217 * .__dummy3 = 0x0000 218 * }; 219 * 220 * // CMD_HID_TX 221 * // HID TX command 222 * rfc_CMD_HID_TX_t RF_cmdTxHID = 223 * { 224 * .commandNo = CMD_HID_TX, 225 * .status = 0x0000, 226 * .pNextOp = 0x00000000, 227 * .startTime = 0x00000000, 228 * .startTrigger.triggerType = 0x0, 229 * .startTrigger.bEnaCmd = 0x0, 230 * .startTrigger.triggerNo = 0x0, 231 * .startTrigger.pastTrig = 0x0, 232 * .condition.rule = COND_NEVER, 233 * .condition.nSkip = 0x0, 234 * .pktConf.bFsOff = 0x0, // Keep synth on 235 * .pktConf.bAutoRetransmit = 0x1, // Listen for ack and retransmit 236 * .pktConf.bVarLen = 0x1, // Variable length mode 237 * .pktConf.hdrMode = 0x0, // 9 bit mode 238 * .pktConf.bIncludeAddr = 0x1, // Include address after sync word 239 * .pktConf.hdrConf = 0x0, // Automatically generate header 240 * .pktConf.bFixedTxLen = 0x0, // Calculate length when sending packet 241 * .rxConf.bAutoFlushIgnored = 0x0, // Do not flush ignored packets 242 * .rxConf.bAutoFlushCrcErr = 0x1, // Flush packets with CRC error 243 * .rxConf.bIncludeAddr = 0x0, // Do not include address in queue 244 * .rxConf.bIncludeHdr = 0x1, // Include header in queue 245 * .rxConf.bIncludeCrc = 0x0, // Do not include CRC in queue 246 * .rxConf.bAppendStatus = 0x0, // Do not append status byte in queue 247 * .rxConf.bAppendTimestamp = 0x0, // Do not append time stamp of received packet in queue 248 * .syncWord = 0x29417671, 249 * .address = 0xEF, 250 * .seqNo = 0x00, 251 * .maxAckLen = 0x1E, // Maximum length of ack 252 * .pktLen = 32, // Packet is 32 bytes 253 * .maxRetrans = 3, // Maximum three retransmissions 254 * .noAckMode.noAckVal = 0, // Set automatic NO_ACK value to inverse of bAutoRetransmit 255 * .noAckMode.bAlwaysAutoRetransmit = 1, // Never disable auto retransmit 256 * .retransDelay = 0x1E, // Number of RAT ticks from start of transmission of a packet to retransmission 257 * .pPkt = 0, 258 * .pRxQueue = 0, 259 * .pOutput = 0, 260 * }; 261 * 262 * // CMD_HID_RX 263 * // HID RX command 264 * rfc_CMD_HID_RX_t RF_cmdRxHID = 265 * { 266 * .commandNo = CMD_HID_RX, 267 * .status = 0x0000, 268 * .pNextOp = 0x00000000, 269 * .startTime = 0x00000000, 270 * .startTrigger.triggerType = 0x0, 271 * .startTrigger.bEnaCmd = 0x0, 272 * .startTrigger.triggerNo = 0x0, 273 * .startTrigger.pastTrig = 0x0, 274 * .condition.rule = COND_NEVER, 275 * .condition.nSkip = 0x0, 276 * .pktConf.bFsOff = 0x0, // Keep synth on 277 * .pktConf.bRepeatOk = 1, // If packet was received OK, then end 278 * .pktConf.bRepeatNok = 1, // If packer was NOK, then go back to sync search 279 * .pktConf.hdrMode = 0x0, // 9 bit mode 280 * .pktConf.bIncludeAddr = 0x1, // Include address after sync word 281 * .pktConf.hdrConf = 0x0, // Automatically generate header 282 * .rxConf.bAutoFlushIgnored = 0x0, // Do not flush ignored packets 283 * .rxConf.bAutoFlushCrcErr = 0x0, // Do not flush packets with CRC error 284 * .rxConf.bIncludeAddr = 0x0, // Do not include address in queue 285 * .rxConf.bIncludeHdr = 0x0, // Do not include header in queue 286 * .rxConf.bIncludeCrc = 0x0, // Do not include CRC in queue 287 * .rxConf.bAppendRssi = 0x0, // Do not append RSSI in queue 288 * .rxConf.bAppendStatus = 0x0, // Do not append status byte in queue 289 * .rxConf.bAppendTimestamp = 0x0, // Do not append time stamp of received packet in queue 290 * .syncWord0 = 0x29417671, 291 * .syncWord1 = 0x0, 292 * .numAddr = 1, // Number of address entries in pAddrEntry 293 * .__dummy0 = 0, 294 * .__dummy1 = 0, 295 * .endTrigger.triggerType = 1, // Trig never 296 * .endTrigger.bEnaCmd = 0, 297 * .endTrigger.triggerNo = 0, 298 * .endTrigger.pastTrig = 0, 299 * .endTime = 0, 300 * .pAddrEntry = 0, //pointer to array of address entries 301 * .pRxQueue = 0, 302 * .pOutput = 0, 303 * }; 304 * 305 * // Struct used for the address entry 306 * rfc_hidAddrEntry_t addrEntry = 307 * { 308 * .addrConfig.ena0 = 1, // Enable entry for sync word 0 309 * .addrConfig.ena1 = 0, // Disable entry for sync word 0 310 * .addrConfig.autoAckMode = 2, // Always enable auto-acknowledgement for the entry 311 * .addrConfig.bVarLen = 1, // Use variable length in receiver when receiving packets 312 * .addrConfig.bFixedTxLen = 0, // Use actual length in header when sending ACK 313 * .maxPktLen = 100, 314 * .address = 0xEF, // Address of packet 315 * .pTxQueue = 0, // Pointer to transmit queue for acknowledgements in use for the address 316 * .crcVal = 0, 317 * }; 318 * @endcode 319 * 320 * @anchor rf_hid_settings_h 321 * @code 322 * // Filename: rf_hid_settings.h 323 * 324 * #include <ti/devices/DeviceFamily.h> 325 * #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) 326 * #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) 327 * #include DeviceFamily_constructPath(driverlib/rf_hid_cmd.h) 328 * #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) 329 * #include <ti/drivers/rf/RF.h> 330 * 331 * extern RF_Mode RF_hid; 332 * 333 * #define BUFFER_LEN 20 // Set the appropriate length here 334 * 335 * // RF Core API commands 336 * extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; 337 * extern rfc_CMD_FS_t RF_cmdFs; 338 * extern rfc_CMD_HID_TX_t RF_cmdTxHID; 339 * extern rfc_CMD_HID_RX_t RF_cmdRxHID; 340 * extern rfc_hidAddrEntry_t addrEntry; 341 * 342 * // RF HID queue and statistics 343 * extern dataQueue_t txQ; 344 * extern dataQueue_t rxQ; 345 * extern uint8_t txEntry1[BUFFER_LEN]; 346 * extern uint8_t rxEntry1[BUFFER_LEN]; 347 * extern uint8_t txEntry2[BUFFER_LEN]; 348 * extern uint8_t rxEntry2[BUFFER_LEN]; 349 * extern rfc_hidRxTxOutput_t rxTxStatistics; 350 * 351 * @endcode 352 * 353 * <hr> 354 * @anchor rf_hid_Examples 355 * # Examples 356 * The following code example opens the RF driver, setup the radio for CMD_HID_TX, 357 * initiates the TX/RX queues so that the packet is being transmitted as fast 358 * as possible once the CMD_HID_TX is submitted. 359 * 360 * ### Using the RF CMD_HID_TX without trigger # 361 * The example below does not use the CMD_HID_TRIGGER_TX, since the 362 * queues are committed to the command before the RF_cmdTxHID is submitted. 363 * The radio will evaluate the TX queue as containing data and proceed to start the 364 * transmission. 365 * The radio will continue to send packets and receive ACK's as long as there are 366 * enough space in the queues to allow reception of ACK's, TX queue is filled and 367 * retramission count is below the threshold, and no other error has occured. 368 * The command will terminate if the RX queue ran out of free entries, 369 * or the maximum number of retransmissions (RF_cmdTxHID.maxRetrans) was done, 370 * or the CMD_STOP/CMD_ABORT command was submitted, 371 * or any error occured. 372 * If the TX queue runs out of valid entires, the radio will enter the same wait state 373 * as if command is submitted without committed TX queues. 374 * @code 375 * // Initialize the radio 376 * RF_Params rfParams; 377 * RF_Params_init(&rfParams); 378 * 379 * // Open the radio and submit setup command 380 * RF_Handle rfHandle = RF_open(pObj, &RF_hid, (RF_RadioSetup *)&RF_cmdRadioSetup, NULL); 381 * RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); 382 * // Initialize the queues 383 * rfc_dataEntryGeneral_t *txEntry = (rfc_dataEntryGeneral_t *)txEntry1; 384 * txEntry->pNextEntry = txEntry2; 385 * txEntry->status = DATA_ENTRY_PENDING; 386 * txEntry->config.type = DATA_ENTRY_TYPE_GEN; 387 * txEntry->config.irqIntv = 0; 388 * txEntry->config.lenSz = 0; 389 * txEntry->config.type = 0; 390 * txEntry->length = 10; // Set the appropriate length here 391 * 392 * txEntry = (rfc_dataEntryGeneral_t *)txEntry2; 393 * txEntry->pNextEntry = txEntry1; 394 * txEntry->status = DATA_ENTRY_PENDING; 395 * txEntry->config.type = DATA_ENTRY_TYPE_GEN; 396 * txEntry->config.irqIntv = 0; 397 * txEntry->config.lenSz = 0; 398 * txEntry->config.type = 0; 399 * txEntry->length = 10; // Set the appropriate length here 400 * txQ.pCurrEntry = txEntry1; 401 * txQ.pLastEntry = NULL; 402 * 403 * rfc_dataEntryGeneral_t *rxEntry = (rfc_dataEntryGeneral_t*)rxEntry1; 404 * rxEntry->pNextEntry = rxEntry2; 405 * rxEntry->status = DATA_ENTRY_PENDING; 406 * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; 407 * rxEntry->config.lenSz = 1; 408 * rxEntry->length = BUFFER_LEN-8; 409 * 410 * rxEntry = (rfc_dataEntryGeneral_t*)rxEntry2; 411 * rxEntry->pNextEntry = rxEntry1; 412 * rxEntry->status = DATA_ENTRY_PENDING; 413 * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; 414 * rxEntry->config.lenSz = 1; 415 * rxEntry->length = BUFFER_LEN-8; 416 * rxQ.pCurrEntry = rxEntry1; 417 * rxQ.pLastEntry = NULL; 418 * 419 * // Commit the queues and statistics to the TX command 420 * RF_cmdTxHID.pPkt = (uint8_t*)&txQ; 421 * RF_cmdTxHID.pRxQueue = &rxQ; 422 * RF_cmdTxHID.pOutput = &rxTxStatistics; 423 * 424 * // Submit the command and handle the queue fill/empty in the hidTxCb callback 425 * RF_runCmd(rfHandle, 426 * (RF_Op*)&RF_cmdTxHID, 427 * RF_PriorityNormal, 428 * &hidTxCb, 429 * RF_EventTxDone | RF_EventTxEntryDone | RF_EventRxEntryDone | RF_EventLastCmdDone); 430 * @endcode 431 * 432 * 433 * ### Using the RF CMD_HID_TX with trigger # 434 * The example below is using the CMD_HID_TRIGGER_TX to trigger the transmission of 435 * the TX packet and ACK reception. 436 * The setup for the command is the same as for the example without the trigger, with 437 * the only difference being that the queues are commited to the command after it has 438 * been submitted. 439 * This is a way to enable faster TX start up, compared to regular command submission. 440 * 441 * The example below is using the same data as the above. 442 * The transmission is then triggered 500 usec after CMD_HID_TX command submission. 443 * The delta between RF_runCmd(..., RF_cmdTxHID, ...) and TX start without trigger 444 * is greater than delta between RF_runDirectCmd(rfHandle, CMD_TRIGGER_HID_TX) and 445 * TX start, but will consume more power. 446 * 447 * @code 448 * // Initialize the radio 449 * RF_Params rfParams; 450 * RF_Params_init(&rfParams); 451 * 452 * // Open the radio and submit setup command 453 * RF_Handle rfHandle = RF_open(pObj, &RF_hid, (RF_RadioSetup *)&RF_cmdRadioSetup, NULL); 454 * RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); 455 * // Initialize the queues 456 * rfc_dataEntryGeneral_t *txEntry = (rfc_dataEntryGeneral_t *)txEntry1; 457 * txEntry->pNextEntry = txEntry2; 458 * txEntry->status = DATA_ENTRY_PENDING; 459 * txEntry->config.type = DATA_ENTRY_TYPE_GEN; 460 * txEntry->config.irqIntv = 0; 461 * txEntry->config.lenSz = 0; 462 * txEntry->config.type = 0; 463 * txEntry->length = 10; // Set the appropriate length here 464 * 465 * txEntry = (rfc_dataEntryGeneral_t *)txEntry2; 466 * txEntry->pNextEntry = txEntry1; 467 * txEntry->status = DATA_ENTRY_PENDING; 468 * txEntry->config.type = DATA_ENTRY_TYPE_GEN; 469 * txEntry->config.irqIntv = 0; 470 * txEntry->config.lenSz = 0; 471 * txEntry->config.type = 0; 472 * txEntry->length = 10; // Set the appropriate length here 473 * txQ.pCurrEntry = txEntry1; 474 * txQ.pLastEntry = NULL; 475 * 476 * rfc_dataEntryGeneral_t *rxEntry = (rfc_dataEntryGeneral_t*)rxEntry1; 477 * rxEntry->pNextEntry = rxEntry2; 478 * rxEntry->status = DATA_ENTRY_PENDING; 479 * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; 480 * rxEntry->config.lenSz = 1; 481 * rxEntry->length = BUFFER_LEN-8; 482 * 483 * rxEntry = (rfc_dataEntryGeneral_t*)rxEntry2; 484 * rxEntry->pNextEntry = rxEntry1; 485 * rxEntry->status = DATA_ENTRY_PENDING; 486 * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; 487 * rxEntry->config.lenSz = 1; 488 * rxEntry->length = BUFFER_LEN-8; 489 * rxQ.pCurrEntry = rxEntry1; 490 * rxQ.pLastEntry = NULL; 491 * 492 * RF_cmdTxHID.pRxQueue = &rxQ; 493 * RF_cmdTxHID.pOutput = &rxTxStatistics; 494 * 495 * // Submit the command and handle the queue fill/empty in the hidTxCb callback 496 * RF_CmdHandle ch = RF_postCmd(rfHandle, 497 * (RF_Op*)&RF_cmdTxHID, 498 * RF_PriorityNormal, 499 * &hidTxCb, 500 * RF_EventTxDone | RF_EventTxEntryDone | RF_EventRxEntryDone | RF_EventLastCmdDone); 501 * // Wait 500 usec 502 * usleep(500); 503 * 504 * // Commit the queues and statistics to the TX command 505 * RF_cmdTxHID.pPkt = (uint8_t*)&txQ; 506 * 507 * // Submit the trigger 508 * RF_runDirectCmd(rfHandle, CMD_TRIGGER_HID_TX); 509 * 510 * // Pend on the command end. 511 * RF_pendCmd(rfHandle, ch, RF_EventCmdDone); 512 * 513 * @endcode 514 * 515 * 516 * 517 * ### Using the RF CMD_HID_RX command # 518 * The CMD_HID_RX is not using the trigger as done with the CMD_HID_TX, instead 519 * the reception is handled by the startTrigger. 520 * 521 * The TX queues are used for sending the ACK's, and the TX queue to use is decided 522 * by the address entry, meaning that it's possible to have different TX queues for 523 * different received addresses, allowing for different ACK's for different addresses. 524 * 525 * If pktConf.bIncludeAddr is zero, meaning that no address is sent, the address entry 526 * used will be the first entry that matches the received sync word with the sync word 527 * ID in the address entry. 528 * 529 * The command will terminate if the RX queue is full, CMD_STOP/CMD_ABORT is being sent 530 * or if any error occured. 531 * 532 * An example of the CMD_HID_RX is shown below. 533 * @code 534 * // Initialize the radio 535 * RF_Params rfParams; 536 * RF_Params_init(&rfParams); 537 * 538 * // Open the radio and submit setup command 539 * RF_Handle rfHandle = RF_open(pObj, &RF_hid, (RF_RadioSetup *)&RF_cmdRadioSetup, NULL); 540 * RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); 541 * // Initialize the queues 542 * rfc_dataEntryGeneral_t *txEntry = (rfc_dataEntryGeneral_t *)txEntry1; 543 * txEntry->pNextEntry = txEntry2; 544 * txEntry->status = DATA_ENTRY_PENDING; 545 * txEntry->config.type = DATA_ENTRY_TYPE_GEN; 546 * txEntry->config.irqIntv = 0; 547 * txEntry->config.lenSz = 0; 548 * txEntry->config.type = 0; 549 * txEntry->length = 10; // Set the appropriate length here 550 * 551 * txEntry = (rfc_dataEntryGeneral_t *)txEntry2; 552 * txEntry->pNextEntry = txEntry1; 553 * txEntry->status = DATA_ENTRY_PENDING; 554 * txEntry->config.type = DATA_ENTRY_TYPE_GEN; 555 * txEntry->config.irqIntv = 0; 556 * txEntry->config.lenSz = 0; 557 * txEntry->config.type = 0; 558 * txEntry->length = 10; // Set the appropriate length here 559 * 560 * rfc_dataEntryGeneral_t *rxEntry = (rfc_dataEntryGeneral_t*)rxEntry1; 561 * rxEntry->pNextEntry = rxEntry2; 562 * rxEntry->status = DATA_ENTRY_PENDING; 563 * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; 564 * rxEntry->config.lenSz = 1; 565 * rxEntry->length = BUFFER_LEN-8; 566 * 567 * rxEntry = (rfc_dataEntryGeneral_t*)rxEntry2; 568 * rxEntry->pNextEntry = rxEntry1; 569 * rxEntry->status = DATA_ENTRY_PENDING; 570 * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; 571 * rxEntry->config.lenSz = 1; 572 * rxEntry->length = BUFFER_LEN-8; 573 * rxQ.pCurrEntry = rxEntry1; 574 * rxQ.pLastEntry = NULL; 575 * 576 * // Attach the TX queue to the address entry. Used for ACK's 577 * addrEntry.pTxQueue = &txQ; 578 * RF_cmdRxHID.pAddrEntry = &addrEntry; 579 * RF_cmdRxHID.pRxQueue = &rxQ; 580 * RF_cmdRxHID.pOutput = &rxTxStatistics; 581 * 582 * // Submit the command and handle the queue fill/empty in the hidRxCb callback 583 * RF_runCmd(rfHandle, 584 * (RF_Op*)&RF_cmdRxHID, 585 * RF_PriorityNormal, 586 * &hidRxCb, 587 * RF_EventTxDone | RF_EventTxEntryDone | RF_EventRxEntryDone | RF_EventLastCmdDone); 588 * @endcode 589 * 590 * 591 * <hr> 592 * 593 * ============================================================================ 594 */ 595 #ifndef __HID_CMD_H 596 #define __HID_CMD_H 597 598 #ifndef __RFC_STRUCT 599 #define __RFC_STRUCT 600 #endif 601 602 #ifndef __RFC_STRUCT_ATTR 603 #if defined(__GNUC__) 604 #define __RFC_STRUCT_ATTR __attribute__ ((aligned (4))) 605 #elif defined(__TI_ARM__) 606 #define __RFC_STRUCT_ATTR __attribute__ ((__packed__,aligned (4))) 607 #else 608 #define __RFC_STRUCT_ATTR 609 #endif 610 #endif 611 612 //! \addtogroup rfc 613 //! @{ 614 615 //! \addtogroup hid_cmd 616 //! @{ 617 618 #include <stdint.h> 619 #include "rf_mailbox.h" 620 #include "rf_common_cmd.h" 621 622 typedef struct __RFC_STRUCT rfc_CMD_HID_TX_s rfc_CMD_HID_TX_t; 623 typedef struct __RFC_STRUCT rfc_CMD_HID_RX_s rfc_CMD_HID_RX_t; 624 typedef struct __RFC_STRUCT rfc_hidAddrEntry_s rfc_hidAddrEntry_t; 625 typedef struct __RFC_STRUCT rfc_hidRxTxOutput_s rfc_hidRxTxOutput_t; 626 typedef struct __RFC_STRUCT rfc_hidRxStatus_s rfc_hidRxStatus_t; 627 628 //! \addtogroup CMD_HID_TX 629 //! @{ 630 #define CMD_HID_TX 0x5801 631 //! HID Transmit Command with Auto Retransmission 632 struct __RFC_STRUCT rfc_CMD_HID_TX_s { 633 uint16_t commandNo; //!< The command ID number 0x5801 634 uint16_t status; //!< \brief An integer telling the status of the command. This value is 635 //!< updated by the radio CPU during operation and may be read by the 636 //!< system CPU at any time. 637 rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done 638 ratmr_t startTime; //!< Absolute or relative start time (depending on the value of <code>startTrigger</code>) 639 struct { 640 uint8_t triggerType:4; //!< The type of trigger 641 uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command<br> 642 //!< 1: CMD_TRIGGER can be used as an alternative trigger 643 uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action 644 uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error<br> 645 //!< 1: A trigger in the past is triggered as soon as possible 646 } startTrigger; //!< Identification of the trigger that starts the operation 647 struct { 648 uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed 649 uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... 650 } condition; 651 struct { 652 uint8_t bFsOff:1; //!< \brief 0: Keep frequency synth on after command<br> 653 //!< 1: Turn frequency synth off after command 654 uint8_t bAutoRetransmit:1; //!< \brief 0: Do not listen for ACK<br> 655 //!< 1: Listen for ACK and retransmit if missing 656 uint8_t bVarLen:1; //!< \brief 0: Fixed length mode<br> 657 //!< 1: Variable length mode 658 uint8_t hdrMode:1; //!< \brief 0: 9-bit header<br> 659 //!< 1: 10-bit header 660 uint8_t bIncludeAddr:1; //!< \brief 0: Do not include address byte after sync word<br> 661 //!< 1: Include address byte after sync word 662 uint8_t hdrConf:2; //!< \brief 0: Automatically generate header (no header byte in buffer\)<br> 663 //!< 1: Insert NO_ACK field from TX buffer<br> 664 //!< 2: Insert SEQ field from TX buffer<br> 665 //!< 3: Insert SEQ and NO_ACK field from TX buffer 666 uint8_t bFixedTxLen:1; //!< \brief 0: Use actual length in header when sending packet<br> 667 //!< 1: Use fixed word in length field of header when sending packet 668 //!< (only for peer without variable length packets) 669 } pktConf; 670 struct { 671 uint8_t bAutoFlushIgnored:1; //!< If 1, automatically remove ignored packets (RX) or empty ACKs (TX) from RX queue 672 uint8_t bAutoFlushCrcErr:1; //!< If 1, automatically remove packets with CRC error from Rx queue 673 uint8_t bIncludeAddr:1; //!< If 1, the received address byte is included in the Rx queue 674 uint8_t bIncludeHdr:1; //!< If 1, the received header is included in the Rx queue 675 uint8_t bIncludeCrc:1; //!< If 1, include the received CRC field in the stored packet; otherwise discard it 676 uint8_t bAppendRssi:1; //!< If 1, append an RSSI byte to the packet in the Rx queue 677 uint8_t bAppendStatus:1; //!< If 1, append a status byte to the packet in the Rx queue 678 uint8_t bAppendTimestamp:1; //!< If 1, append a timestamp to the packet in the Rx queue 679 } rxConf; //!< Receive entry configuration 680 uint32_t syncWord; //!< Sync word to send 681 uint8_t address; //!< Address byte 682 uint8_t seqNo; //!< Sequence number to use for next packet 683 uint8_t maxAckLen; //!< Maximum length of ACKs 684 uint8_t pktLen; //!< Length of transmitted packet 685 uint8_t maxRetrans; //!< Maximum number of retransmissions 686 struct { 687 uint8_t noAckVal:2; //!< \brief 0: Set automatic NO_ACK value to inverse of bAutoRetransmit<br> 688 //!< 1: Set automatic NO_ACK value to bAutoRetransmit<br> 689 //!< 2: Set automatic NO_ACK value to 0<br> 690 //!< 3: Set automatic NO_ACK value to 1 691 uint8_t bAlwaysAutoRetransmit:1; //!< \brief 0: Disable auto retransmit if transmitted NO_ACK was 1<br> 692 //!< 1: Never disable auto retransmit 693 } noAckMode; 694 uint16_t retransDelay; //!< Number of RAT ticks from start of transmission of a packet to retransmission 695 uint8_t* pPkt; //!< Pointer to transmit queue for packets 696 dataQueue_t* pRxQueue; //!< Pointer to receive queue for ACKs 697 rfc_hidRxTxOutput_t *pOutput; //!< Pointer to output structure 698 } __RFC_STRUCT_ATTR; 699 700 //! @} 701 702 //! \addtogroup CMD_HID_RX 703 //! @{ 704 #define CMD_HID_RX 0x5802 705 //! HID Recieve Command with Auto Ack 706 struct __RFC_STRUCT rfc_CMD_HID_RX_s { 707 uint16_t commandNo; //!< The command ID number 0x5802 708 uint16_t status; //!< \brief An integer telling the status of the command. This value is 709 //!< updated by the radio CPU during operation and may be read by the 710 //!< system CPU at any time. 711 rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done 712 ratmr_t startTime; //!< Absolute or relative start time (depending on the value of <code>startTrigger</code>) 713 struct { 714 uint8_t triggerType:4; //!< The type of trigger 715 uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command<br> 716 //!< 1: CMD_TRIGGER can be used as an alternative trigger 717 uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action 718 uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error<br> 719 //!< 1: A trigger in the past is triggered as soon as possible 720 } startTrigger; //!< Identification of the trigger that starts the operation 721 struct { 722 uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed 723 uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... 724 } condition; 725 struct { 726 uint8_t bFsOff:1; //!< \brief 0: Keep frequency synth on after command<br> 727 //!< 1: Turn frequency synth off after command 728 uint8_t bRepeatOk:1; //!< \brief 0: End operation after receiving a packet correctly<br> 729 //!< 1: Go back to sync search after receiving a packet correctly 730 uint8_t bRepeatNok:1; //!< \brief 0: End operation after receiving a packet with CRC error<br> 731 //!< 1: Go back to sync search after receiving a packet with CRC error 732 uint8_t hdrMode:1; //!< \brief 0: 9-bit header<br> 733 //!< 1: 10-bit header 734 uint8_t bIncludeAddr:1; //!< \brief 0: Include address byte after sync word<br> 735 //!< 1: Do not include address byte after sync word 736 uint8_t hdrConf:2; //!< \brief 0: Automatically generate header (no header byte in buffer) 737 //!< 1: Insert NO_ACK field from TX buffer 738 //!< 2: Insert SEQ field from TX buffer 739 //!< 3: Insert SEQ and NO_ACK field from TX buffer 740 } pktConf; 741 struct { 742 uint8_t bAutoFlushIgnored:1; //!< If 1, automatically remove ignored packets (RX) or empty ACKs (TX) from RX queue 743 uint8_t bAutoFlushCrcErr:1; //!< If 1, automatically remove packets with CRC error from Rx queue 744 uint8_t bIncludeAddr:1; //!< If 1, the received address byte is included in the Rx queue 745 uint8_t bIncludeHdr:1; //!< If 1, the received header is included in the Rx queue 746 uint8_t bIncludeCrc:1; //!< If 1, include the received CRC field in the stored packet; otherwise discard it 747 uint8_t bAppendRssi:1; //!< If 1, append an RSSI byte to the packet in the Rx queue 748 uint8_t bAppendStatus:1; //!< If 1, append a status byte to the packet in the Rx queue 749 uint8_t bAppendTimestamp:1; //!< If 1, append a timestamp to the packet in the Rx queue 750 } rxConf; //!< Receive entry configuration 751 uint32_t syncWord0; //!< Sync word to listen for 752 uint32_t syncWord1; //!< Alternative sync word if non-zero 753 uint8_t numAddr; //!< Number of address entries 754 uint8_t __dummy0; 755 uint8_t __dummy1; 756 struct { 757 uint8_t triggerType:4; //!< The type of trigger 758 uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command<br> 759 //!< 1: CMD_TRIGGER can be used as an alternative trigger 760 uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action 761 uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error<br> 762 //!< 1: A trigger in the past is triggered as soon as possible 763 } endTrigger; //!< Trigger classifier for ending the operation 764 ratmr_t endTime; //!< Time used together with <code>endTrigger</code> for ending the operation 765 rfc_hidAddrEntry_t *pAddrEntry; //!< Pointer to array of address entries 766 dataQueue_t* pRxQueue; //!< Pointer to receive queue 767 rfc_hidRxTxOutput_t *pOutput; //!< Pointer to output structure 768 } __RFC_STRUCT_ATTR; 769 770 //! @} 771 772 //! \addtogroup hidAddrEntry 773 //! @{ 774 //! Address entry structure for CMD_HID_RX 775 776 struct __RFC_STRUCT rfc_hidAddrEntry_s { 777 struct { 778 uint8_t ena0:1; //!< \brief 0: Disable entry for syncWord0<br> 779 //!< 1: Enable entry for syncWord0 780 uint8_t ena1:1; //!< \brief 0: Disable entry for syncWord1<br> 781 //!< 1: Enable entry for syncWord1 782 uint8_t autoAckMode:2; //!< \brief 0: Always disable auto-acknowledgement for the entry<br> 783 //!< 1: Always enable auto-acknowledgement for the entry<br> 784 //!< 2: Enable auto-acknowledgement for the entry only if received NO_ACK bit is 0<br> 785 //!< 3: Enable auto-acknowledgement for the entry only if received NO_ACK bit is 1 786 uint8_t bVarLen:1; //!< \brief 0: Use fixed length given by maxPktLen in receiver when receiving packets<br> 787 //!< 1: Use variable length in receiver when receiving packets 788 uint8_t bFixedTxLen:1; //!< \brief 0: Use actual length in header when sending ACK 789 //!< 1: Use fixed word in length field of header when sending ACK and no payload 790 //!< (only for peer without variable length ACKs) 791 } addrConfig; 792 uint8_t maxPktLen; //!< Packet length for fixed length, maximum packet length for variable length 793 uint8_t address; //!< Address byte of packet 794 struct { 795 uint8_t bValid:1; //!< \brief 0: The status is not valid. Any packet is viewed as new.<br> 796 //!< 1: The status is valid. Only packets with a sequence number and CRC different 797 //!< from the previous one are accepted. 798 uint8_t seq:2; //!< Sequence number of last successfully received packet 799 uint8_t ackSeq:2; //!< Sequence number of the next or current ACK to be transmitted 800 uint8_t bAckPayloadSent:1; //!< \brief 0: The last received packet was not acknowledged with payload.<br> 801 //!< 1: The last received packet was acknowledged with payload. 802 } seqStat; 803 dataQueue_t* pTxQueue; //!< Pointer to transmit queue for acknowledgements in use for the address 804 uint16_t crcVal; //!< CRC value (last two bytes if more than 2 CRC bytes) of last successfully received packet 805 } __RFC_STRUCT_ATTR; 806 807 //! @} 808 809 //! \addtogroup hidRxTxOutput 810 //! @{ 811 //! Output structure for CMD_HID_RX and CMD_HID_TX 812 813 struct __RFC_STRUCT rfc_hidRxTxOutput_s { 814 uint8_t nTx; //!< Number of packets or acknowledgements transmitted 815 uint8_t nRxOk; //!< Number of packets that have been received with CRC OK 816 uint8_t nRxNok; //!< Number of packets that have been received with CRC error 817 uint8_t nRxIgnored; //!< Number of packets ignored as retransmissions or empty ACKs 818 uint8_t nRxBufFull; //!< Number of packets that have been received and discarded due to lack of buffer space 819 uint8_t nRxAborted; //!< Number of packets not received due to device address mismatch, invalid length, or abort command 820 uint8_t __dummy0; 821 int8_t lastRssi; //!< RSSI of last received packet 822 ratmr_t timeStamp; //!< Time stamp of last received packet 823 } __RFC_STRUCT_ATTR; 824 825 //! @} 826 827 //! \addtogroup hidRxStatus 828 //! @{ 829 //! Receive status byte that may be appended to message in receive buffer 830 831 struct __RFC_STRUCT rfc_hidRxStatus_s { 832 struct { 833 uint8_t addrInd:5; //!< Index of address found 834 uint8_t syncWordId:1; //!< 0 for primary sync word, 1 for alternate sync word 835 uint8_t bIgnore:1; //!< 1 if the packet is marked as ignored, 0 otherwise 836 uint8_t bCrcErr:1; //!< 1 if the packet was received with CRC error, 0 otherwise 837 } status; 838 } __RFC_STRUCT_ATTR; 839 840 //! @} 841 842 //! @} 843 //! @} 844 #endif 845