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.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,
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