/****************************************************************************** * Filename: rf_hid_cmd.h * * Description: CC13x2/CC26x2 API for HID commands * * Copyright (c) 2015 - 2020, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2) Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3) Neither the name of the ORGANIZATION nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ /*!***************************************************************************** * @file rf_hid_cmd.h * @brief RF HID command interface for CC13x2, CC26x2 * * * To use the CMD_HID_TX and CMD_HID_RX commands, make sure that the following * override list is being used: * @code * #define TURNAROUND_TIME 64 // 64 µs turnaround time * uint32_t pOverridesCommon[] = * { * // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x3 (DITHER_EN=0 and IPEAK=3). * (uint32_t)0x00F388D3, * // Set pilot tone length to 4 us (enable phase error discard as early as possible) * HW_REG_OVERRIDE(0x6024,0x0020), * // Bluetooth 5: Default to no CTE. * HW_REG_OVERRIDE(0x5328,0x0000), * // Synth: Increase mid code calibration time to 5 us * (uint32_t)0x00058683, * // Synth: Increase mid code calibration time to 5 us * HW32_ARRAY_OVERRIDE(0x4004,1), * // Synth: Increase mid code calibration time to 5 us * (uint32_t)0x38183C30, * // HID: Reduce turnaround times: * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0263, // modify tx to rx turnaround time * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0283, // modify rx to tx turnaround time * // Of of override list * (uint32_t)0xFFFFFFFF * }; * @endcode * * @anchor rf_hid_overview * # Overview * The HID commands are designed to be compatible with CC254x devices, * using the same protocol as the CC254x. * The packet are defined as: * 8 bit preamble, 32 bit sync word, optional 8 bit address, 8 or 9 bit header, * [0-n] byte payload and 16 bit CRC at 2 Mbps. * The HID commands uses the same automode functionality as found in the * CC254x devices, see [CC254x user guide](https://www.ti.com/lit/ug/swru283b/swru283b.pdf). * * The CMD_HID_TX utlizes a TX queue to evaluate if the subsequent packet * should be sent, given that the device is not retranmitting the previous packet. * On submission of the CMD_HID_TX, the radio will check if there are TX * entries in the queue. If TX entires are present, the radio will start sending * the packets as defined by the startTrigger. If no packets are present, the radio * will enter a wait-state, waiting on CMD_TRIGGER_HID_TX. Once CMD_TRIGGER_HID_TX * is submitted, the radio will re-evaluate the TX queue, and if packets are present * , the radio will start sending the TX packets as defined by the startTrigger. * If no entries in the TX queue has been submitted, or CMD_STOP/CMD_ABORT was * submitted, the CMD_HID_TX will end and the radio is ready for another command. * * *
* @anchor rf_hid_Usage * # Usage * * This documentation provides basic @ref rf_hid_settings_c * "rf_hid_settings.c", @ref rf_hid_settings_h * "rf_hid_settings.h" and a set of @ref rf_hid_Examples "examples" * in the form of commented code fragments. Detailed descriptions of the * APIs are provided in subsequent sections. * * @anchor rf_hid_settings * ## RF HID settings * @anchor rf_hid_settings_c * @code * // Filename: rf_hid_settings.c * * // Import the settings header file * #include "rf_hid_settings.h" * * // Import the RF driver definitions * #include * * // Import the needed radio files * #include * #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) * #include DeviceFamily_constructPath(driverlib/rf_hid_cmd.h) * #include DeviceFamily_constructPath(rf_patches/rf_patch_cpe_multi_protocol_hid.h) * #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) * #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) * * * // TI-RTOS RF Mode Object * RF_Mode RF_hid = * { * .rfMode = RF_MODE_PROPRIETARY, * .cpePatchFxn = &rf_patch_cpe_multi_protocol_hid, * .mcePatchFxn = 0, * .rfePatchFxn = 0 * }; * * // TX and RX queue declarations * uint8_t txEntry1[BUFFER_LEN]; * uint8_t txEntry2[BUFFER_LEN]; * uint8_t rxEntry1[BUFFER_LEN]; * uint8_t rxEntry2[BUFFER_LEN]; * * dataQueue_t txQ = { * .pCurrEntry = NULL, * .pLastEntry = NULL, * }; * * dataQueue_t rxQ = { * .pCurrEntry = NULL, * .pLastEntry = NULL, * }; * * // Statistics * rfc_hidRxTxOutput_t rxTxStatistics; * * // Override list. 64 us turnaround compatible with fastest setting * // for CC254x devices * #define TURNAROUND_TIME 64 // Turnaround time in usec * uint32_t pOverridesCommon[] = * { * // DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x3 (DITHER_EN=0 and IPEAK=3). * (uint32_t)0x00F388D3, * // Set pilot tone length to 4 us (enable phase error discard as early as possible) * HW_REG_OVERRIDE(0x6024,0x0020), * // Bluetooth 5: Default to no CTE. * HW_REG_OVERRIDE(0x5328,0x0000), * // Synth: Increase mid code calibration time to 5 us * (uint32_t)0x00058683, * // Synth: Increase mid code calibration time to 5 us * HW32_ARRAY_OVERRIDE(0x4004,1), * // Synth: Increase mid code calibration time to 5 us * (uint32_t)0x38183C30, * // HID: Reduce turnaround times: * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0263, // modify tx to rx turnaround time * (uint32_t)((TURNAROUND_TIME*4)<<16)|0x0283, // modify rx to tx turnaround time * // Of of override list * (uint32_t)0xFFFFFFFF * }; * * // CMD_RADIO_SETUP * // Radio setup for HID command * rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup = * { * .commandNo = CMD_RADIO_SETUP, * .status = 0x0000, * .pNextOp = 0, // INSERT APPLICABLE POINTER: (uint8_t*)&xxx * .startTime = 0x00000000, * .startTrigger.triggerType = 0x0, * .startTrigger.bEnaCmd = 0x0, * .startTrigger.triggerNo = 0x0, * .startTrigger.pastTrig = 0x0, * .condition.rule = 0x1, * .condition.nSkip = 0x0, * .mode = 0x2, // HID mode * .loDivider = 0x00, * .config.frontEndMode = 0x0, * .config.biasMode = 0x0, * .config.analogCfgMode = 0x0, * .config.bNoFsPowerUp = 0x0, * .txPower = 0x7217, * .pRegOverride = pOverridesCommon, * }; * * // CMD_FS * // Frequency Synthesizer Programming Command * rfc_CMD_FS_t RF_cmdFs = * { * .commandNo = 0x0803, * .status = 0x0000, * .pNextOp = 0, * .startTime = 0x00000000, * .startTrigger.triggerType = 0x0, * .startTrigger.bEnaCmd = 0x0, * .startTrigger.triggerNo = 0x0, * .startTrigger.pastTrig = 0x1, * .condition.rule = 0x1, * .condition.nSkip = 0x0, * .frequency = 2440, * .fractFreq = 0x0000, * .synthConf.bTxMode = 0x0, * .synthConf.refFreq = 0x0, * .__dummy0 = 0x00, * .__dummy1 = 0x00, * .__dummy2 = 0x00, * .__dummy3 = 0x0000 * }; * * // CMD_HID_TX * // HID TX command * rfc_CMD_HID_TX_t RF_cmdTxHID = * { * .commandNo = CMD_HID_TX, * .status = 0x0000, * .pNextOp = 0x00000000, * .startTime = 0x00000000, * .startTrigger.triggerType = 0x0, * .startTrigger.bEnaCmd = 0x0, * .startTrigger.triggerNo = 0x0, * .startTrigger.pastTrig = 0x0, * .condition.rule = COND_NEVER, * .condition.nSkip = 0x0, * .pktConf.bFsOff = 0x0, // Keep synth on * .pktConf.bAutoRetransmit = 0x1, // Listen for ack and retransmit * .pktConf.bVarLen = 0x1, // Variable length mode * .pktConf.hdrMode = 0x0, // 9 bit mode * .pktConf.bIncludeAddr = 0x1, // Include address after sync word * .pktConf.hdrConf = 0x0, // Automatically generate header * .pktConf.bFixedTxLen = 0x0, // Calculate length when sending packet * .rxConf.bAutoFlushIgnored = 0x0, // Do not flush ignored packets * .rxConf.bAutoFlushCrcErr = 0x1, // Flush packets with CRC error * .rxConf.bIncludeAddr = 0x0, // Do not include address in queue * .rxConf.bIncludeHdr = 0x1, // Include header in queue * .rxConf.bIncludeCrc = 0x0, // Do not include CRC in queue * .rxConf.bAppendStatus = 0x0, // Do not append status byte in queue * .rxConf.bAppendTimestamp = 0x0, // Do not append time stamp of received packet in queue * .syncWord = 0x29417671, * .address = 0xEF, * .seqNo = 0x00, * .maxAckLen = 0x1E, // Maximum length of ack * .pktLen = 32, // Packet is 32 bytes * .maxRetrans = 3, // Maximum three retransmissions * .noAckMode.noAckVal = 0, // Set automatic NO_ACK value to inverse of bAutoRetransmit * .noAckMode.bAlwaysAutoRetransmit = 1, // Never disable auto retransmit * .retransDelay = 0x1E, // Number of RAT ticks from start of transmission of a packet to retransmission * .pPkt = 0, * .pRxQueue = 0, * .pOutput = 0, * }; * * // CMD_HID_RX * // HID RX command * rfc_CMD_HID_RX_t RF_cmdRxHID = * { * .commandNo = CMD_HID_RX, * .status = 0x0000, * .pNextOp = 0x00000000, * .startTime = 0x00000000, * .startTrigger.triggerType = 0x0, * .startTrigger.bEnaCmd = 0x0, * .startTrigger.triggerNo = 0x0, * .startTrigger.pastTrig = 0x0, * .condition.rule = COND_NEVER, * .condition.nSkip = 0x0, * .pktConf.bFsOff = 0x0, // Keep synth on * .pktConf.bRepeatOk = 1, // If packet was received OK, then end * .pktConf.bRepeatNok = 1, // If packer was NOK, then go back to sync search * .pktConf.hdrMode = 0x0, // 9 bit mode * .pktConf.bIncludeAddr = 0x1, // Include address after sync word * .pktConf.hdrConf = 0x0, // Automatically generate header * .rxConf.bAutoFlushIgnored = 0x0, // Do not flush ignored packets * .rxConf.bAutoFlushCrcErr = 0x0, // Do not flush packets with CRC error * .rxConf.bIncludeAddr = 0x0, // Do not include address in queue * .rxConf.bIncludeHdr = 0x0, // Do not include header in queue * .rxConf.bIncludeCrc = 0x0, // Do not include CRC in queue * .rxConf.bAppendRssi = 0x0, // Do not append RSSI in queue * .rxConf.bAppendStatus = 0x0, // Do not append status byte in queue * .rxConf.bAppendTimestamp = 0x0, // Do not append time stamp of received packet in queue * .syncWord0 = 0x29417671, * .syncWord1 = 0x0, * .numAddr = 1, // Number of address entries in pAddrEntry * .__dummy0 = 0, * .__dummy1 = 0, * .endTrigger.triggerType = 1, // Trig never * .endTrigger.bEnaCmd = 0, * .endTrigger.triggerNo = 0, * .endTrigger.pastTrig = 0, * .endTime = 0, * .pAddrEntry = 0, //pointer to array of address entries * .pRxQueue = 0, * .pOutput = 0, * }; * * // Struct used for the address entry * rfc_hidAddrEntry_t addrEntry = * { * .addrConfig.ena0 = 1, // Enable entry for sync word 0 * .addrConfig.ena1 = 0, // Disable entry for sync word 0 * .addrConfig.autoAckMode = 2, // Always enable auto-acknowledgement for the entry * .addrConfig.bVarLen = 1, // Use variable length in receiver when receiving packets * .addrConfig.bFixedTxLen = 0, // Use actual length in header when sending ACK * .maxPktLen = 100, * .address = 0xEF, // Address of packet * .pTxQueue = 0, // Pointer to transmit queue for acknowledgements in use for the address * .crcVal = 0, * }; * @endcode * * @anchor rf_hid_settings_h * @code * // Filename: rf_hid_settings.h * * #include * #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) * #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) * #include DeviceFamily_constructPath(driverlib/rf_hid_cmd.h) * #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) * #include * * extern RF_Mode RF_hid; * * #define BUFFER_LEN 20 // Set the appropriate length here * * // RF Core API commands * extern rfc_CMD_RADIO_SETUP_t RF_cmdRadioSetup; * extern rfc_CMD_FS_t RF_cmdFs; * extern rfc_CMD_HID_TX_t RF_cmdTxHID; * extern rfc_CMD_HID_RX_t RF_cmdRxHID; * extern rfc_hidAddrEntry_t addrEntry; * * // RF HID queue and statistics * extern dataQueue_t txQ; * extern dataQueue_t rxQ; * extern uint8_t txEntry1[BUFFER_LEN]; * extern uint8_t rxEntry1[BUFFER_LEN]; * extern uint8_t txEntry2[BUFFER_LEN]; * extern uint8_t rxEntry2[BUFFER_LEN]; * extern rfc_hidRxTxOutput_t rxTxStatistics; * * @endcode * *
* @anchor rf_hid_Examples * # Examples * The following code example opens the RF driver, setup the radio for CMD_HID_TX, * initiates the TX/RX queues so that the packet is being transmitted as fast * as possible once the CMD_HID_TX is submitted. * * ### Using the RF CMD_HID_TX without trigger # * The example below does not use the CMD_HID_TRIGGER_TX, since the * queues are committed to the command before the RF_cmdTxHID is submitted. * The radio will evaluate the TX queue as containing data and proceed to start the * transmission. * The radio will continue to send packets and receive ACK's as long as there are * enough space in the queues to allow reception of ACK's, TX queue is filled and * retramission count is below the threshold, and no other error has occured. * The command will terminate if the RX queue ran out of free entries, * or the maximum number of retransmissions (RF_cmdTxHID.maxRetrans) was done, * or the CMD_STOP/CMD_ABORT command was submitted, * or any error occured. * If the TX queue runs out of valid entires, the radio will enter the same wait state * as if command is submitted without committed TX queues. * @code * // Initialize the radio * RF_Params rfParams; * RF_Params_init(&rfParams); * * // Open the radio and submit setup command * RF_Handle rfHandle = RF_open(pObj, &RF_hid, (RF_RadioSetup *)&RF_cmdRadioSetup, NULL); * RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); * // Initialize the queues * rfc_dataEntryGeneral_t *txEntry = (rfc_dataEntryGeneral_t *)txEntry1; * txEntry->pNextEntry = txEntry2; * txEntry->status = DATA_ENTRY_PENDING; * txEntry->config.type = DATA_ENTRY_TYPE_GEN; * txEntry->config.irqIntv = 0; * txEntry->config.lenSz = 0; * txEntry->config.type = 0; * txEntry->length = 10; // Set the appropriate length here * * txEntry = (rfc_dataEntryGeneral_t *)txEntry2; * txEntry->pNextEntry = txEntry1; * txEntry->status = DATA_ENTRY_PENDING; * txEntry->config.type = DATA_ENTRY_TYPE_GEN; * txEntry->config.irqIntv = 0; * txEntry->config.lenSz = 0; * txEntry->config.type = 0; * txEntry->length = 10; // Set the appropriate length here * txQ.pCurrEntry = txEntry1; * txQ.pLastEntry = NULL; * * rfc_dataEntryGeneral_t *rxEntry = (rfc_dataEntryGeneral_t*)rxEntry1; * rxEntry->pNextEntry = rxEntry2; * rxEntry->status = DATA_ENTRY_PENDING; * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; * rxEntry->config.lenSz = 1; * rxEntry->length = BUFFER_LEN-8; * * rxEntry = (rfc_dataEntryGeneral_t*)rxEntry2; * rxEntry->pNextEntry = rxEntry1; * rxEntry->status = DATA_ENTRY_PENDING; * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; * rxEntry->config.lenSz = 1; * rxEntry->length = BUFFER_LEN-8; * rxQ.pCurrEntry = rxEntry1; * rxQ.pLastEntry = NULL; * * // Commit the queues and statistics to the TX command * RF_cmdTxHID.pPkt = (uint8_t*)&txQ; * RF_cmdTxHID.pRxQueue = &rxQ; * RF_cmdTxHID.pOutput = &rxTxStatistics; * * // Submit the command and handle the queue fill/empty in the hidTxCb callback * RF_runCmd(rfHandle, * (RF_Op*)&RF_cmdTxHID, * RF_PriorityNormal, * &hidTxCb, * RF_EventTxDone | RF_EventTxEntryDone | RF_EventRxEntryDone | RF_EventLastCmdDone); * @endcode * * * ### Using the RF CMD_HID_TX with trigger # * The example below is using the CMD_HID_TRIGGER_TX to trigger the transmission of * the TX packet and ACK reception. * The setup for the command is the same as for the example without the trigger, with * the only difference being that the queues are commited to the command after it has * been submitted. * This is a way to enable faster TX start up, compared to regular command submission. * * The example below is using the same data as the above. * The transmission is then triggered 500 usec after CMD_HID_TX command submission. * The delta between RF_runCmd(..., RF_cmdTxHID, ...) and TX start without trigger * is greater than delta between RF_runDirectCmd(rfHandle, CMD_TRIGGER_HID_TX) and * TX start, but will consume more power. * * @code * // Initialize the radio * RF_Params rfParams; * RF_Params_init(&rfParams); * * // Open the radio and submit setup command * RF_Handle rfHandle = RF_open(pObj, &RF_hid, (RF_RadioSetup *)&RF_cmdRadioSetup, NULL); * RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); * // Initialize the queues * rfc_dataEntryGeneral_t *txEntry = (rfc_dataEntryGeneral_t *)txEntry1; * txEntry->pNextEntry = txEntry2; * txEntry->status = DATA_ENTRY_PENDING; * txEntry->config.type = DATA_ENTRY_TYPE_GEN; * txEntry->config.irqIntv = 0; * txEntry->config.lenSz = 0; * txEntry->config.type = 0; * txEntry->length = 10; // Set the appropriate length here * * txEntry = (rfc_dataEntryGeneral_t *)txEntry2; * txEntry->pNextEntry = txEntry1; * txEntry->status = DATA_ENTRY_PENDING; * txEntry->config.type = DATA_ENTRY_TYPE_GEN; * txEntry->config.irqIntv = 0; * txEntry->config.lenSz = 0; * txEntry->config.type = 0; * txEntry->length = 10; // Set the appropriate length here * txQ.pCurrEntry = txEntry1; * txQ.pLastEntry = NULL; * * rfc_dataEntryGeneral_t *rxEntry = (rfc_dataEntryGeneral_t*)rxEntry1; * rxEntry->pNextEntry = rxEntry2; * rxEntry->status = DATA_ENTRY_PENDING; * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; * rxEntry->config.lenSz = 1; * rxEntry->length = BUFFER_LEN-8; * * rxEntry = (rfc_dataEntryGeneral_t*)rxEntry2; * rxEntry->pNextEntry = rxEntry1; * rxEntry->status = DATA_ENTRY_PENDING; * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; * rxEntry->config.lenSz = 1; * rxEntry->length = BUFFER_LEN-8; * rxQ.pCurrEntry = rxEntry1; * rxQ.pLastEntry = NULL; * * RF_cmdTxHID.pRxQueue = &rxQ; * RF_cmdTxHID.pOutput = &rxTxStatistics; * * // Submit the command and handle the queue fill/empty in the hidTxCb callback * RF_CmdHandle ch = RF_postCmd(rfHandle, * (RF_Op*)&RF_cmdTxHID, * RF_PriorityNormal, * &hidTxCb, * RF_EventTxDone | RF_EventTxEntryDone | RF_EventRxEntryDone | RF_EventLastCmdDone); * // Wait 500 usec * usleep(500); * * // Commit the queues and statistics to the TX command * RF_cmdTxHID.pPkt = (uint8_t*)&txQ; * * // Submit the trigger * RF_runDirectCmd(rfHandle, CMD_TRIGGER_HID_TX); * * // Pend on the command end. * RF_pendCmd(rfHandle, ch, RF_EventCmdDone); * * @endcode * * * * ### Using the RF CMD_HID_RX command # * The CMD_HID_RX is not using the trigger as done with the CMD_HID_TX, instead * the reception is handled by the startTrigger. * * The TX queues are used for sending the ACK's, and the TX queue to use is decided * by the address entry, meaning that it's possible to have different TX queues for * different received addresses, allowing for different ACK's for different addresses. * * If pktConf.bIncludeAddr is zero, meaning that no address is sent, the address entry * used will be the first entry that matches the received sync word with the sync word * ID in the address entry. * * The command will terminate if the RX queue is full, CMD_STOP/CMD_ABORT is being sent * or if any error occured. * * An example of the CMD_HID_RX is shown below. * @code * // Initialize the radio * RF_Params rfParams; * RF_Params_init(&rfParams); * * // Open the radio and submit setup command * RF_Handle rfHandle = RF_open(pObj, &RF_hid, (RF_RadioSetup *)&RF_cmdRadioSetup, NULL); * RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); * // Initialize the queues * rfc_dataEntryGeneral_t *txEntry = (rfc_dataEntryGeneral_t *)txEntry1; * txEntry->pNextEntry = txEntry2; * txEntry->status = DATA_ENTRY_PENDING; * txEntry->config.type = DATA_ENTRY_TYPE_GEN; * txEntry->config.irqIntv = 0; * txEntry->config.lenSz = 0; * txEntry->config.type = 0; * txEntry->length = 10; // Set the appropriate length here * * txEntry = (rfc_dataEntryGeneral_t *)txEntry2; * txEntry->pNextEntry = txEntry1; * txEntry->status = DATA_ENTRY_PENDING; * txEntry->config.type = DATA_ENTRY_TYPE_GEN; * txEntry->config.irqIntv = 0; * txEntry->config.lenSz = 0; * txEntry->config.type = 0; * txEntry->length = 10; // Set the appropriate length here * * rfc_dataEntryGeneral_t *rxEntry = (rfc_dataEntryGeneral_t*)rxEntry1; * rxEntry->pNextEntry = rxEntry2; * rxEntry->status = DATA_ENTRY_PENDING; * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; * rxEntry->config.lenSz = 1; * rxEntry->length = BUFFER_LEN-8; * * rxEntry = (rfc_dataEntryGeneral_t*)rxEntry2; * rxEntry->pNextEntry = rxEntry1; * rxEntry->status = DATA_ENTRY_PENDING; * rxEntry->config.type = DATA_ENTRY_TYPE_GEN; * rxEntry->config.lenSz = 1; * rxEntry->length = BUFFER_LEN-8; * rxQ.pCurrEntry = rxEntry1; * rxQ.pLastEntry = NULL; * * // Attach the TX queue to the address entry. Used for ACK's * addrEntry.pTxQueue = &txQ; * RF_cmdRxHID.pAddrEntry = &addrEntry; * RF_cmdRxHID.pRxQueue = &rxQ; * RF_cmdRxHID.pOutput = &rxTxStatistics; * * // Submit the command and handle the queue fill/empty in the hidRxCb callback * RF_runCmd(rfHandle, * (RF_Op*)&RF_cmdRxHID, * RF_PriorityNormal, * &hidRxCb, * RF_EventTxDone | RF_EventTxEntryDone | RF_EventRxEntryDone | RF_EventLastCmdDone); * @endcode * * *
* * ============================================================================ */ #ifndef __HID_CMD_H #define __HID_CMD_H #ifndef __RFC_STRUCT #define __RFC_STRUCT #endif #ifndef __RFC_STRUCT_ATTR #if defined(__GNUC__) #define __RFC_STRUCT_ATTR __attribute__ ((aligned (4))) #elif defined(__TI_ARM__) #define __RFC_STRUCT_ATTR __attribute__ ((__packed__,aligned (4))) #else #define __RFC_STRUCT_ATTR #endif #endif //! \addtogroup rfc //! @{ //! \addtogroup hid_cmd //! @{ #include #include "rf_mailbox.h" #include "rf_common_cmd.h" typedef struct __RFC_STRUCT rfc_CMD_HID_TX_s rfc_CMD_HID_TX_t; typedef struct __RFC_STRUCT rfc_CMD_HID_RX_s rfc_CMD_HID_RX_t; typedef struct __RFC_STRUCT rfc_hidAddrEntry_s rfc_hidAddrEntry_t; typedef struct __RFC_STRUCT rfc_hidRxTxOutput_s rfc_hidRxTxOutput_t; typedef struct __RFC_STRUCT rfc_hidRxStatus_s rfc_hidRxStatus_t; //! \addtogroup CMD_HID_TX //! @{ #define CMD_HID_TX 0x5801 //! HID Transmit Command with Auto Retransmission struct __RFC_STRUCT rfc_CMD_HID_TX_s { uint16_t commandNo; //!< The command ID number 0x5801 uint16_t status; //!< \brief An integer telling the status of the command. This value is //!< updated by the radio CPU during operation and may be read by the //!< system CPU at any time. rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) struct { uint8_t triggerType:4; //!< The type of trigger uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
//!< 1: CMD_TRIGGER can be used as an alternative trigger uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
//!< 1: A trigger in the past is triggered as soon as possible } startTrigger; //!< Identification of the trigger that starts the operation struct { uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... } condition; struct { uint8_t bFsOff:1; //!< \brief 0: Keep frequency synth on after command
//!< 1: Turn frequency synth off after command uint8_t bAutoRetransmit:1; //!< \brief 0: Do not listen for ACK
//!< 1: Listen for ACK and retransmit if missing uint8_t bVarLen:1; //!< \brief 0: Fixed length mode
//!< 1: Variable length mode uint8_t hdrMode:1; //!< \brief 0: 9-bit header
//!< 1: 10-bit header uint8_t bIncludeAddr:1; //!< \brief 0: Do not include address byte after sync word
//!< 1: Include address byte after sync word uint8_t hdrConf:2; //!< \brief 0: Automatically generate header (no header byte in buffer\)
//!< 1: Insert NO_ACK field from TX buffer
//!< 2: Insert SEQ field from TX buffer
//!< 3: Insert SEQ and NO_ACK field from TX buffer uint8_t bFixedTxLen:1; //!< \brief 0: Use actual length in header when sending packet
//!< 1: Use fixed word in length field of header when sending packet //!< (only for peer without variable length packets) } pktConf; struct { uint8_t bAutoFlushIgnored:1; //!< If 1, automatically remove ignored packets (RX) or empty ACKs (TX) from RX queue uint8_t bAutoFlushCrcErr:1; //!< If 1, automatically remove packets with CRC error from Rx queue uint8_t bIncludeAddr:1; //!< If 1, the received address byte is included in the Rx queue uint8_t bIncludeHdr:1; //!< If 1, the received header is included in the Rx queue uint8_t bIncludeCrc:1; //!< If 1, include the received CRC field in the stored packet; otherwise discard it uint8_t bAppendRssi:1; //!< If 1, append an RSSI byte to the packet in the Rx queue uint8_t bAppendStatus:1; //!< If 1, append a status byte to the packet in the Rx queue uint8_t bAppendTimestamp:1; //!< If 1, append a timestamp to the packet in the Rx queue } rxConf; //!< Receive entry configuration uint32_t syncWord; //!< Sync word to send uint8_t address; //!< Address byte uint8_t seqNo; //!< Sequence number to use for next packet uint8_t maxAckLen; //!< Maximum length of ACKs uint8_t pktLen; //!< Length of transmitted packet uint8_t maxRetrans; //!< Maximum number of retransmissions struct { uint8_t noAckVal:2; //!< \brief 0: Set automatic NO_ACK value to inverse of bAutoRetransmit
//!< 1: Set automatic NO_ACK value to bAutoRetransmit
//!< 2: Set automatic NO_ACK value to 0
//!< 3: Set automatic NO_ACK value to 1 uint8_t bAlwaysAutoRetransmit:1; //!< \brief 0: Disable auto retransmit if transmitted NO_ACK was 1
//!< 1: Never disable auto retransmit } noAckMode; uint16_t retransDelay; //!< Number of RAT ticks from start of transmission of a packet to retransmission uint8_t* pPkt; //!< Pointer to transmit queue for packets dataQueue_t* pRxQueue; //!< Pointer to receive queue for ACKs rfc_hidRxTxOutput_t *pOutput; //!< Pointer to output structure } __RFC_STRUCT_ATTR; //! @} //! \addtogroup CMD_HID_RX //! @{ #define CMD_HID_RX 0x5802 //! HID Recieve Command with Auto Ack struct __RFC_STRUCT rfc_CMD_HID_RX_s { uint16_t commandNo; //!< The command ID number 0x5802 uint16_t status; //!< \brief An integer telling the status of the command. This value is //!< updated by the radio CPU during operation and may be read by the //!< system CPU at any time. rfc_radioOp_t *pNextOp; //!< Pointer to the next operation to run after this operation is done ratmr_t startTime; //!< Absolute or relative start time (depending on the value of startTrigger) struct { uint8_t triggerType:4; //!< The type of trigger uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
//!< 1: CMD_TRIGGER can be used as an alternative trigger uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
//!< 1: A trigger in the past is triggered as soon as possible } startTrigger; //!< Identification of the trigger that starts the operation struct { uint8_t rule:4; //!< Condition for running next command: Rule for how to proceed uint8_t nSkip:4; //!< Number of skips + 1 if the rule involves skipping. 0: same, 1: next, 2: skip next, ... } condition; struct { uint8_t bFsOff:1; //!< \brief 0: Keep frequency synth on after command
//!< 1: Turn frequency synth off after command uint8_t bRepeatOk:1; //!< \brief 0: End operation after receiving a packet correctly
//!< 1: Go back to sync search after receiving a packet correctly uint8_t bRepeatNok:1; //!< \brief 0: End operation after receiving a packet with CRC error
//!< 1: Go back to sync search after receiving a packet with CRC error uint8_t hdrMode:1; //!< \brief 0: 9-bit header
//!< 1: 10-bit header uint8_t bIncludeAddr:1; //!< \brief 0: Include address byte after sync word
//!< 1: Do not include address byte after sync word uint8_t hdrConf:2; //!< \brief 0: Automatically generate header (no header byte in buffer) //!< 1: Insert NO_ACK field from TX buffer //!< 2: Insert SEQ field from TX buffer //!< 3: Insert SEQ and NO_ACK field from TX buffer } pktConf; struct { uint8_t bAutoFlushIgnored:1; //!< If 1, automatically remove ignored packets (RX) or empty ACKs (TX) from RX queue uint8_t bAutoFlushCrcErr:1; //!< If 1, automatically remove packets with CRC error from Rx queue uint8_t bIncludeAddr:1; //!< If 1, the received address byte is included in the Rx queue uint8_t bIncludeHdr:1; //!< If 1, the received header is included in the Rx queue uint8_t bIncludeCrc:1; //!< If 1, include the received CRC field in the stored packet; otherwise discard it uint8_t bAppendRssi:1; //!< If 1, append an RSSI byte to the packet in the Rx queue uint8_t bAppendStatus:1; //!< If 1, append a status byte to the packet in the Rx queue uint8_t bAppendTimestamp:1; //!< If 1, append a timestamp to the packet in the Rx queue } rxConf; //!< Receive entry configuration uint32_t syncWord0; //!< Sync word to listen for uint32_t syncWord1; //!< Alternative sync word if non-zero uint8_t numAddr; //!< Number of address entries uint8_t __dummy0; uint8_t __dummy1; struct { uint8_t triggerType:4; //!< The type of trigger uint8_t bEnaCmd:1; //!< \brief 0: No alternative trigger command
//!< 1: CMD_TRIGGER can be used as an alternative trigger uint8_t triggerNo:2; //!< The trigger number of the CMD_TRIGGER command that triggers this action uint8_t pastTrig:1; //!< \brief 0: A trigger in the past is never triggered, or for start of commands, give an error
//!< 1: A trigger in the past is triggered as soon as possible } endTrigger; //!< Trigger classifier for ending the operation ratmr_t endTime; //!< Time used together with endTrigger for ending the operation rfc_hidAddrEntry_t *pAddrEntry; //!< Pointer to array of address entries dataQueue_t* pRxQueue; //!< Pointer to receive queue rfc_hidRxTxOutput_t *pOutput; //!< Pointer to output structure } __RFC_STRUCT_ATTR; //! @} //! \addtogroup hidAddrEntry //! @{ //! Address entry structure for CMD_HID_RX struct __RFC_STRUCT rfc_hidAddrEntry_s { struct { uint8_t ena0:1; //!< \brief 0: Disable entry for syncWord0
//!< 1: Enable entry for syncWord0 uint8_t ena1:1; //!< \brief 0: Disable entry for syncWord1
//!< 1: Enable entry for syncWord1 uint8_t autoAckMode:2; //!< \brief 0: Always disable auto-acknowledgement for the entry
//!< 1: Always enable auto-acknowledgement for the entry
//!< 2: Enable auto-acknowledgement for the entry only if received NO_ACK bit is 0
//!< 3: Enable auto-acknowledgement for the entry only if received NO_ACK bit is 1 uint8_t bVarLen:1; //!< \brief 0: Use fixed length given by maxPktLen in receiver when receiving packets
//!< 1: Use variable length in receiver when receiving packets uint8_t bFixedTxLen:1; //!< \brief 0: Use actual length in header when sending ACK //!< 1: Use fixed word in length field of header when sending ACK and no payload //!< (only for peer without variable length ACKs) } addrConfig; uint8_t maxPktLen; //!< Packet length for fixed length, maximum packet length for variable length uint8_t address; //!< Address byte of packet struct { uint8_t bValid:1; //!< \brief 0: The status is not valid. Any packet is viewed as new.
//!< 1: The status is valid. Only packets with a sequence number and CRC different //!< from the previous one are accepted. uint8_t seq:2; //!< Sequence number of last successfully received packet uint8_t ackSeq:2; //!< Sequence number of the next or current ACK to be transmitted uint8_t bAckPayloadSent:1; //!< \brief 0: The last received packet was not acknowledged with payload.
//!< 1: The last received packet was acknowledged with payload. } seqStat; dataQueue_t* pTxQueue; //!< Pointer to transmit queue for acknowledgements in use for the address uint16_t crcVal; //!< CRC value (last two bytes if more than 2 CRC bytes) of last successfully received packet } __RFC_STRUCT_ATTR; //! @} //! \addtogroup hidRxTxOutput //! @{ //! Output structure for CMD_HID_RX and CMD_HID_TX struct __RFC_STRUCT rfc_hidRxTxOutput_s { uint8_t nTx; //!< Number of packets or acknowledgements transmitted uint8_t nRxOk; //!< Number of packets that have been received with CRC OK uint8_t nRxNok; //!< Number of packets that have been received with CRC error uint8_t nRxIgnored; //!< Number of packets ignored as retransmissions or empty ACKs uint8_t nRxBufFull; //!< Number of packets that have been received and discarded due to lack of buffer space uint8_t nRxAborted; //!< Number of packets not received due to device address mismatch, invalid length, or abort command uint8_t __dummy0; int8_t lastRssi; //!< RSSI of last received packet ratmr_t timeStamp; //!< Time stamp of last received packet } __RFC_STRUCT_ATTR; //! @} //! \addtogroup hidRxStatus //! @{ //! Receive status byte that may be appended to message in receive buffer struct __RFC_STRUCT rfc_hidRxStatus_s { struct { uint8_t addrInd:5; //!< Index of address found uint8_t syncWordId:1; //!< 0 for primary sync word, 1 for alternate sync word uint8_t bIgnore:1; //!< 1 if the packet is marked as ignored, 0 otherwise uint8_t bCrcErr:1; //!< 1 if the packet was received with CRC error, 0 otherwise } status; } __RFC_STRUCT_ATTR; //! @} //! @} //! @} #endif