From f6b016c5d4cf4c67b6f96f91b6398073a93644b3 Mon Sep 17 00:00:00 2001 From: Edvard Pettersen Date: Fri, 15 Jun 2018 16:37:51 +0200 Subject: [PATCH] Working prop-mode --- arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h | 85 +- arch/cpu/cc13xx-cc26xx/dev/rf-common.c | 11 +- arch/cpu/cc13xx-cc26xx/dev/rf-common.h | 26 +- arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c | 27 +- arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c | 797 ++++++++++-------- .../rf-settings/cc13x0/prop-settings.c | 20 +- .../rf-settings/cc13x0/prop-settings.h | 2 +- .../rf-settings/cc26x2/ieee-settings.c | 28 +- .../rf-settings/cc26x2/ieee-settings.h | 4 +- .../simplelink/cc13xx-cc26xx/contiki-conf.h | 4 +- .../launchpad/button-sensor-arch.c | 120 +-- .../launchpad/launchpad-sensors.c | 8 +- os/sys/cc.h | 4 + 13 files changed, 593 insertions(+), 543 deletions(-) diff --git a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h index fe91d840c..f86ceb521 100644 --- a/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc13xx-cc26xx/cc13xx-cc26xx-conf.h @@ -56,12 +56,10 @@ #define CC2650_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) #endif -#ifdef RF_CHANNEL -#define RF_CORE_CONF_CHANNEL RF_CHANNEL -#endif - -#ifndef RF_CORE_CONF_CHANNEL -#define RF_CORE_CONF_CHANNEL 25 +#ifdef RF_CORE_CONF_CHANNEL +#define RF_CHANNEL RF_CORE_CONF_CHANNEL +#else +#define RF_CHANNEL 25 #endif /* Number of Prop Mode RX buffers */ @@ -70,54 +68,59 @@ #endif /* Configure Radio mode, i.e. prop or ieee */ + + +/*----- CC13xx Device Line --------------------------------------------------*/ /* CC13xx supports both IEEE and Prop mode, depending on which device */ -/* CC26xx only supports IEEE mode */ #if defined(DEVICE_LINE_CC13XX) -/* Default mode should be prop for prop-only devices (CC1310, CC1312); +/* Default mode should be prop for prop-only devices (CC1310, CC1312R); * Else, IEEE mode is default. */ -# ifndef CC13XX_CONF_PROP_MODE -# if (SUPPORTS_IEEE_MODE == 0) -# define CC13XX_CONF_PROP_MODE 1 -# else -# define CC13XX_CONF_PROP_MODE 0 -# endif -# endif - - -# if (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) -/*----- CC13xx Prop Mode ----------------------------------------------------*/ -# define NETSTACK_CONF_RADIO prop_mode_driver - -# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) -# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME \ - (RTIMER_SECOND / 1000) -# define CSMA_CONF_SEND_SOFT_ACK 1 - -# elif (CC13XX_CONF_PROP_MODE == 0) && (SUPPORTS_IEEE_MODE == 1) -/*----- CC13xx IEEE Mode ----------------------------------------------------*/ -# define NETSTACK_CONF_RADIO ieee_mode_driver - -# define CSMA_CONF_SEND_SOFT_ACK 0 - +# ifndef CC13XX_CONF_PROP_MODE +# if (SUPPORTS_IEEE_MODE == 0) +# define CC13XX_CONF_PROP_MODE 1 # else -# error "Invalid radio mode configuration of CC13xx device" -# endif /* (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) */ +# define CC13XX_CONF_PROP_MODE 0 +# endif +# endif +# if (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) +/*----- CC13xx Prop Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO prop_mode_driver + +# define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 300) +# define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +# define CSMA_CONF_SEND_SOFT_ACK 1 + +# elif (CC13XX_CONF_PROP_MODE == 0) && (SUPPORTS_IEEE_MODE == 1) +/*----- CC13xx IEEE Mode ----------------------------------------------------*/ +# define NETSTACK_CONF_RADIO ieee_mode_driver + +# define CSMA_CONF_SEND_SOFT_ACK 0 + +# else +/*----- CC13xx Non-supported Mode -------------------------------------------*/ +# error "Invalid radio mode configuration of CC13xx device" +# endif /* (CC13XX_CONF_PROP_MODE == 1) && (SUPPORTS_PROP_MODE == 1) */ + +/*----- CC26xx Device Line --------------------------------------------------*/ +/* CC26xx only supports IEEE mode */ #elif defined(DEVICE_LINE_CC26XX) -# if (SUPPORTS_IEEE_MODE == 1) +# if (SUPPORTS_IEEE_MODE == 1) /*----- CC26xx IEEE Mode ----------------------------------------------------*/ -# define NETSTACK_CONF_RADIO ieee_mode_driver +# define NETSTACK_CONF_RADIO ieee_mode_driver -# define CSMA_CONF_SEND_SOFT_ACK 0 +# define CSMA_CONF_SEND_SOFT_ACK 0 -# else -# error "IEEE mode only supported by CC26xx devices" -# endif /* (SUPPORTS_IEEE_MODE == 1) */ +# else +/*----- CC26xx Non-supported Mode -------------------------------------------*/ +# error "IEEE mode only supported by CC26xx devices" +# endif /* (SUPPORTS_IEEE_MODE == 1) */ +/*----- Unsupported device line ---------------------------------------------*/ #else -# error "Unsupported Device Line defined" +# error "Unsupported Device Line defined" #endif /* defined(DEVICE_LINE_CC13xx) */ #define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.c b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c index 76d6f31f2..92339e1ab 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-common.c @@ -39,25 +39,18 @@ #include #include #include -#include #include #include #include /*---------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -/*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RF" #define LOG_LEVEL LOG_LEVEL_DBG /*---------------------------------------------------------------------------*/ -PROCESS(RF_coreProcess, "SimpleLink RF process"); +PROCESS(rf_process, "SimpleLink RF Process"); /*---------------------------------------------------------------------------*/ -PROCESS_THREAD(RF_coreProcess, ev, data) +PROCESS_THREAD(rf_process, ev, data) { int len; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h index cd646064f..9c3f244b9 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-common.h +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-common.h @@ -43,34 +43,12 @@ #ifndef RF_COMMON_H_ #define RF_COMMON_H_ /*---------------------------------------------------------------------------*/ -/* Contiki API */ -#include -#include -/*---------------------------------------------------------------------------*/ -/* Standard library */ -#include -/*---------------------------------------------------------------------------*/ -#ifdef RF_CORE_CONF_CHANNEL -# define RF_CORE_CHANNEL RF_CORE_CONF_CHANNEL -#else -# define RF_CORE_CHANNEL 25 -#endif -/*---------------------------------------------------------------------------*/ typedef enum { CMD_RESULT_ERROR = 0, CMD_RESULT_OK = 1, -} CmdResult; +} cmd_result_t; /*---------------------------------------------------------------------------*/ -typedef struct { - radio_value_t dbm; - uint16_t power; ///< Value for the .txPower field -} RF_TxPower; - -#define TX_POWER_UNKNOWN 0xFFFF -/*---------------------------------------------------------------------------*/ -#define RSSI_UNKNOWN -128 -/*---------------------------------------------------------------------------*/ -PROCESS_NAME(RF_coreProcess); +PROCESS_NAME(rf_process); /*---------------------------------------------------------------------------*/ #endif /* RF_COMMON_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c index 4940ff50b..69ec00233 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-ieee-mode.c @@ -121,7 +121,7 @@ #ifdef IEEE_MODE_CONF_CHANNEL # define IEEE_MODE_CHANNEL IEEE_MODE_CONF_CHANNEL #else -# define IEEE_MODE_CHANNEL RF_CORE_CHANNEL +# define IEEE_MODE_CHANNEL RF_CHANNEL #endif /* Configuration for TX power table */ @@ -301,10 +301,7 @@ static void rx_cb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventRxOk) { - process_poll(&RF_coreProcess); - } - if (e & RF_EventRxBufFull) { - + process_poll(&rf_process); } } /*---------------------------------------------------------------------------*/ @@ -343,7 +340,7 @@ init_data_queue(void) static void init_rf_params(void) { - cmd_rx.channel = RF_CORE_CHANNEL; + cmd_rx.channel = IEEE_MODE_CHANNEL; cmd_rx.pRxQ = &g_rxDataQueue; cmd_rx.pOutput = &g_rxStats; @@ -555,7 +552,7 @@ init(void) ctimer_set(&g_ratOverflowTimer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, rat_overflow_cb, NULL); - process_start(&RF_coreProcess, NULL); + process_start(&rf_process, NULL); return CMD_RESULT_OK; } @@ -812,23 +809,25 @@ pending_packet(void) const rfc_dataEntry_t *const pStartEntry = (rfc_dataEntry_t *)g_rxDataQueue.pCurrEntry; volatile const rfc_dataEntry_t *pCurrEntry = pStartEntry; + int rv = 0; + // Check all RX buffers and check their statuses, stopping when looping the circular buffer - int bIsPending = 0; do { const uint8_t status = pCurrEntry->status; if ((status == DATA_ENTRY_FINISHED) || (status == DATA_ENTRY_BUSY)) { - bIsPending = 1; - if (!g_bPollMode) { - process_poll(&RF_coreProcess); - } + rv += 1; } pCurrEntry = (rfc_dataEntry_t *)pCurrEntry->pNextEntry; } while (pCurrEntry != pStartEntry); + if ((rv > 0) && !g_bPollMode) { + process_poll(&rf_process); + } + // If we didn't find an entry at status finished or busy, no frames are pending - return bIsPending; + return rv; } /*---------------------------------------------------------------------------*/ static int @@ -909,7 +908,7 @@ get_value(radio_param_t param, radio_value_t *value) case RADIO_PARAM_TXPOWER: *value = get_tx_power(); - return (*value == TX_POWER_UNKNOWN) + return (*value == RF_TxPowerTable_INVALID_DBM) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; diff --git a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c index 70d355623..c1642a2ba 100644 --- a/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c +++ b/arch/cpu/cc13xx-cc26xx/dev/rf-prop-mode.c @@ -57,9 +57,9 @@ /*---------------------------------------------------------------------------*/ /* RF settings */ #ifdef PROP_MODE_CONF_RF_SETTINGS -# define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS +# define PROP_MODE_RF_SETTINGS PROP_MODE_CONF_RF_SETTINGS #else -# define PROP_MODE_RF_SETTINGS "prop-settings.h" +# define PROP_MODE_RF_SETTINGS "prop-settings.h" #endif #include PROP_MODE_RF_SETTINGS @@ -75,37 +75,31 @@ #include /*---------------------------------------------------------------------------*/ #ifdef NDEBUG -# define PRINTF(...) +# define PRINTF(...) #else -# define PRINTF(...) printf(__VA_ARGS__) +# define PRINTF(...) printf(__VA_ARGS__) +#endif +/*---------------------------------------------------------------------------*/ +/* Configuration for default Prop channel */ +#ifdef PROP_MODE_CONF_CHANNEL +# define PROP_MODE_CHANNEL PROP_MODE_CONF_CHANNEL +#else +# define PROP_MODE_CHANNEL RF_CHANNEL #endif /*---------------------------------------------------------------------------*/ /* Data whitener. 1: Whitener, 0: No whitener */ #ifdef PROP_MODE_CONF_DW -# define PROP_MODE_DW PROP_MODE_CONF_DW +# define PROP_MODE_DW PROP_MODE_CONF_DW #else -# define PROP_MODE_DW 0 +# define PROP_MODE_DW 0 #endif #ifdef PROP_MODE_CONF_USE_CRC16 -# define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 +# define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 #else -# define PROP_MODE_USE_CRC16 0 +# define PROP_MODE_USE_CRC16 0 #endif /*---------------------------------------------------------------------------*/ -/** - * \brief Returns the current status of a running Radio Op command - * \param a A pointer with the buffer used to initiate the command - * \return The value of the Radio Op buffer's status field - * - * This macro can be used to e.g. return the status of a previously - * initiated background operation, or of an immediate command - */ -#define RF_RADIO_OP_GET_STATUS(a) GET_FIELD_V(a, radioOp, status) -/*---------------------------------------------------------------------------*/ -/* Special value returned by CMD_IEEE_CCA_REQ when an RSSI is not available */ -#define RF_CMD_CCA_REQ_RSSI_UNKNOWN -128 - /* Used for the return value of channel_clear */ #define RF_CCA_CLEAR 1 #define RF_CCA_BUSY 0 @@ -122,17 +116,10 @@ #define RF_CMD_CCA_REQ_CCA_STATE_INVALID 2 /* 10 */ #ifdef PROP_MODE_CONF_RSSI_THRESHOLD -#define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD +# define PROP_MODE_RSSI_THRESHOLD PROP_MODE_CONF_RSSI_THRESHOLD #else -#define PROP_MODE_RSSI_THRESHOLD 0xA6 +# define PROP_MODE_RSSI_THRESHOLD 0xA6 #endif - -static int8_t rssi_threshold = PROP_MODE_RSSI_THRESHOLD; -/*---------------------------------------------------------------------------*/ -static int rf_switch_on(void); -static int rf_switch_off(void); - -static rfc_propRxOutput_t rx_stats; /*---------------------------------------------------------------------------*/ /* Defines and variables related to the .15.4g PHY HDR */ #define DOT_4G_MAX_FRAME_LEN 2047 @@ -144,31 +131,28 @@ static rfc_propRxOutput_t rx_stats; #if PROP_MODE_USE_CRC16 /* CRC16 */ -#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 -#define CRC_LEN 2 +# define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 +# define CRC_LEN 2 #else /* CRC32 */ -#define DOT_4G_PHR_CRC_BIT 0 -#define CRC_LEN 4 -#endif +# define DOT_4G_PHR_CRC_BIT 0 +# define CRC_LEN 4 +#endif /* PROP_MODE_USE_CRC16 */ #if PROP_MODE_DW -#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW +# define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW #else -#define DOT_4G_PHR_DW_BIT 0 + #define DOT_4G_PHR_DW_BIT 0 #endif /*---------------------------------------------------------------------------*/ -/* How long to wait for an ongoing ACK TX to finish before starting frame TX */ -#define TX_WAIT_TIMEOUT (RTIMER_SECOND >> 11) - /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ #define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) /*---------------------------------------------------------------------------*/ /* Configuration for TX power table */ #ifdef PROP_MODE_CONF_TX_POWER_TABLE -# define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE +# define TX_POWER_TABLE PROP_MODE_CONF_TX_POWER_TABLE #else -# define TX_POWER_TABLE propTxPowerTable +# define TX_POWER_TABLE propTxPowerTable #endif /*---------------------------------------------------------------------------*/ /* TX power table convenience macros */ @@ -179,119 +163,131 @@ static rfc_propRxOutput_t rx_stats; #define TX_POWER_IN_RANGE(dbm) (((dbm) >= TX_POWER_MIN) && ((dbm) <= TX_POWER_MAX)) /*---------------------------------------------------------------------------*/ +/* TX buf configuration */ +#define TX_BUF_HDR_LEN 2 +#define TX_BUF_PAYLOAD_LEN 180 + +#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) + +/* RX buf configuration */ #ifdef PROP_MODE_CONF_RX_BUF_CNT -#define PROP_MODE_RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT +# define RX_BUF_CNT PROP_MODE_CONF_RX_BUF_CNT #else -#define PROP_MODE_RX_BUF_CNT 4 +# define RX_BUF_CNT 4 #endif + +#define RX_BUF_SIZE 140 /*---------------------------------------------------------------------------*/ #define DATA_ENTRY_LENSZ_NONE 0 #define DATA_ENTRY_LENSZ_BYTE 1 #define DATA_ENTRY_LENSZ_WORD 2 /* 2 bytes */ - -/* - * RX buffers. - * PROP_MODE_RX_BUF_CNT buffers of RX_BUF_SIZE bytes each. The start of each - * buffer must be 4-byte aligned, therefore RX_BUF_SIZE must divide by 4 - */ -#define RX_BUF_SIZE 140 -static uint8_t rx_buf[PROP_MODE_RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); - -/* The RX Data Queue */ -static dataQueue_t rx_data_queue = { 0 }; - -/* Receive entry pointer to keep track of read items */ -volatile static uint8_t *rx_read_entry; /*---------------------------------------------------------------------------*/ -/* The outgoing frame buffer */ -#define TX_BUF_PAYLOAD_LEN 180 -#define TX_BUF_HDR_LEN 2 +#define MAC_RADIO_RECEIVER_SENSITIVITY_DBM -110 +#define MAC_RADIO_RECEIVER_SATURATION_DBM 10 +#define MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY 10 +#define MAC_SPEC_ED_MAX 0xFF -static uint8_t tx_buf[TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN] CC_ALIGN(4); +#define ED_RF_POWER_MIN_DBM (MAC_RADIO_RECEIVER_SENSITIVITY_DBM + MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY) +#define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM /*---------------------------------------------------------------------------*/ -#define cmd_radio_setup ((volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) -#define cmd_fs ((volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) -#define cmd_tx ((volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) -#define cmd_rx ((volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) +typedef struct { + /* Outgoing frame buffer */ + uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4); + /* Incoming frame buffer */ + uint8_t rx_buf[RX_BUF_CNT][RX_BUF_SIZE] CC_ALIGN(4); + + /* RX Data Queue */ + dataQueue_t rx_data_queue; + /* RX Statistics struct */ + rfc_propRxOutput_t rx_stats; + /* Receive entry pointer to keep track of read items */ + volatile uint8_t* rx_read_entry; + + /* RSSI Threshold */ + int8_t rssi_threshold; + + /* Indicates RF is supposed to be on or off */ + uint8_t rf_is_on; + + /* RF driver */ + RF_Object rf_object; + RF_Handle rf_handle; +} prop_radio_t; + +static prop_radio_t prop_radio; /*---------------------------------------------------------------------------*/ -/* RF driver */ -static RF_Object rfObject; -static RF_Handle rfHandle; +#define cmd_radio_setup (*(volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) +#define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) +#define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) +#define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) /*---------------------------------------------------------------------------*/ -static CC_INLINE bool rf_is_transmitting(void) { return cmd_tx->status == ACTIVE; } -static CC_INLINE bool rf_is_receiving(void) { return cmd_rx->status == ACTIVE; } -static CC_INLINE bool rf_is_on(void) { return rf_is_transmitting() || rf_is_receiving(); } +static CC_INLINE bool tx_active(void) { return cmd_tx.status == ACTIVE; } +static CC_INLINE bool rx_active(void) { return cmd_rx.status == ACTIVE; } +/*---------------------------------------------------------------------------*/ +static int on(void); +static int off(void); /*---------------------------------------------------------------------------*/ static void -rf_rx_callback(RF_Handle client, RF_CmdHandle command, RF_EventMask events) +cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events) { - if (events & RF_EventRxEntryDone) { - process_poll(&RF_coreProcess); - } + /* Unused arguments */ + (void)client; + (void)command; + + if (events & RF_EventRxEntryDone) { + process_poll(&rf_process); + } } /*---------------------------------------------------------------------------*/ -static CmdResult -rf_start_rx() +static cmd_result_t +start_rx(void) { - cmd_rx->status = IDLE; + cmd_rx.status = IDLE; + RF_CmdHandle rx_handle = RF_postCmd(prop_radio.rf_handle, (RF_Op*)&cmd_rx, RF_PriorityNormal, + &cmd_rx_cb, RF_EventRxEntryDone); + if (rx_handle == RF_ALLOC_ERROR) { + PRINTF("start_rx: RF_ALLOC_ERROR for cmd_rx\n"); + return CMD_RESULT_ERROR; + } - /* - * Set the max Packet length. This is for the payload only, therefore - * 2047 - length offset - */ - cmd_rx->maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx->lenOffset; + /* Wait to enter RX */ + const rtimer_clock_t t0 = RTIMER_NOW(); + while (!rx_active() && + (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - RF_CmdHandle rxCmdHandle = RF_postCmd(rfHandle, (RF_Op*)cmd_rx, RF_PriorityNormal, - &rf_rx_callback, RF_EventRxEntryDone); - if (rxCmdHandle == RF_ALLOC_ERROR) { - return CMD_RESULT_ERROR; - } + if (!rx_active()) { + PRINTF("cmd_rx: status=0x%04x\n", cmd_rx.status); + return CMD_RESULT_ERROR; + } - /* Wait to enter RX */ - const rtimer_clock_t t0 = RTIMER_NOW(); - while (!rf_is_receiving() && - (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT))); - - if (!rf_is_receiving()) { - PRINTF("RF_cmdPropRxAdv: handle=0x%08lx, status=0x%04x\n", - (unsigned long)rxCmdHandle, cmd_rx->status); - rf_switch_off(); - return CMD_RESULT_ERROR; - } - - return CMD_RESULT_OK; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ -static CmdResult -rf_stop_rx(void) +static cmd_result_t +stop_rx(void) { - /* If we are off, do nothing */ - if (!rf_is_receiving()) { - return CMD_RESULT_OK; - } + /* Abort any ongoing operation. Don't care about the result. */ + RF_cancelCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, 1); - /* Abort any ongoing operation. Don't care about the result. */ - RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 1); + /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ - /* Todo: maybe do a RF_pendCmd() to synchronize with command execution. */ + if(cmd_rx.status != PROP_DONE_STOPPED && + cmd_rx.status != PROP_DONE_ABORT) { + PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", + cmd_rx.status); + return CMD_RESULT_ERROR; + } - if(cmd_rx->status != PROP_DONE_STOPPED && - cmd_rx->status != PROP_DONE_ABORT) { - PRINTF("RF_cmdPropRxAdv cancel: status=0x%04x\n", - cmd_rx->status); - return CMD_RESULT_ERROR; - } - - /* Stopped gracefully */ - ENERGEST_OFF(ENERGEST_TYPE_LISTEN); - return CMD_RESULT_OK; + /* Stopped gracefully */ + ENERGEST_OFF(ENERGEST_TYPE_LISTEN); + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ -static CmdResult +static cmd_result_t rf_run_setup() { - RF_runCmd(rfHandle, (RF_Op*)cmd_radio_setup, RF_PriorityNormal, NULL, 0); - if (cmd_radio_setup->status != PROP_DONE_OK) { + RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_radio_setup, RF_PriorityNormal, NULL, 0); + if (cmd_radio_setup.status != PROP_DONE_OK) { return CMD_RESULT_ERROR; } @@ -301,35 +297,33 @@ rf_run_setup() static radio_value_t get_rssi(void) { - if (rf_is_transmitting()) { - PRINTF("get_rssi: called while in TX\n"); - return RF_GET_RSSI_ERROR_VAL; - } + if (tx_active()) { + PRINTF("get_rssi: called while in TX\n"); + return RF_GET_RSSI_ERROR_VAL; + } - const bool was_off = !rf_is_receiving(); - if (was_off && rf_start_rx() == CMD_RESULT_ERROR) { - PRINTF("get_rssi: unable to start RX\n"); - return RF_GET_RSSI_ERROR_VAL; - } + const bool was_off = !rx_active(); + if (was_off && start_rx() == CMD_RESULT_ERROR) { + PRINTF("get_rssi: unable to start RX\n"); + return RF_GET_RSSI_ERROR_VAL; + } - int8_t rssi = RF_GET_RSSI_ERROR_VAL; - while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { - rssi = RF_getRssi(rfHandle); - } + int8_t rssi = RF_GET_RSSI_ERROR_VAL; + while(rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { + rssi = RF_getRssi(prop_radio.rf_handle); + } - if(was_off) { - rf_switch_off(); - } + if (was_off) { + stop_rx(); + } - return rssi; + return rssi; } /*---------------------------------------------------------------------------*/ static uint8_t get_channel(void) { - uint32_t freq_khz; - - freq_khz = cmd_fs->frequency * 1000; + uint32_t freq_khz = cmd_fs.frequency * 1000; /* * For some channels, fractFreq * 1000 / 65536 will return 324.99xx. @@ -337,40 +331,48 @@ get_channel(void) * function returning channel - 1 instead of channel. Thus, we do a quick * positive integer round up. */ - freq_khz += (((cmd_fs->fractFreq * 1000) + 65535) / 65536); + freq_khz += (((cmd_fs.fractFreq * 1000) + 65535) / 65536); return (freq_khz - DOT_15_4G_CHAN0_FREQUENCY) / DOT_15_4G_CHANNEL_SPACING; } /*---------------------------------------------------------------------------*/ -static void +static cmd_result_t set_channel(uint8_t channel) { - uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); + uint32_t new_freq = DOT_15_4G_CHAN0_FREQUENCY + (channel * DOT_15_4G_CHANNEL_SPACING); - uint16_t freq = (uint16_t)(new_freq / 1000); - uint16_t frac = (new_freq - (freq * 1000)) * 65536 / 1000; + uint16_t freq = (uint16_t)(new_freq / 1000); + uint16_t frac = (new_freq - (freq * 1000)) * 65536 / 1000; - PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", - channel, freq, frac, new_freq); + PRINTF("set_channel: %u = 0x%04x.0x%04x (%lu)\n", + channel, freq, frac, new_freq); - cmd_radio_setup->centerFreq = freq; - cmd_fs->frequency = freq; - cmd_fs->fractFreq = frac; + cmd_radio_setup.centerFreq = freq; + cmd_fs.frequency = freq; + cmd_fs.fractFreq = frac; - // Todo: Need to re-run setup command when deviation from previous frequency - // is too large - // rf_run_setup(); + // We don't care whether the FS command is successful because subsequent + // TX and RX commands will tell us indirectly. + RF_EventMask rf_events = RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_fs, + RF_PriorityNormal, NULL, 0); + if ((rf_events & (RF_EventCmdDone | RF_EventLastCmdDone)) == 0) { + PRINTF("set_channel: RF_runCmd failed, events=0x%llx\n", rf_events); + return CMD_RESULT_ERROR; + } - // We don't care whether the FS command is successful because subsequent - // TX and RX commands will tell us indirectly. - RF_postCmd(rfHandle, (RF_Op*)cmd_fs, RF_PriorityNormal, NULL, 0); + if (cmd_fs.status != DONE_OK) { + PRINTF("set_channel: cmd_fs failed, status=0x%04x\n", cmd_fs.status); + return CMD_RESULT_ERROR; + } + + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ /* Returns the current TX power in dBm */ static radio_value_t get_tx_power(void) { - const RF_TxPowerTable_Value value = RF_getTxPower(rfHandle); + const RF_TxPowerTable_Value value = RF_getTxPower(prop_radio.rf_handle); return (radio_value_t)RF_TxPowerTable_findPowerLevel(TX_POWER_TABLE, value); } /*---------------------------------------------------------------------------*/ @@ -385,80 +387,97 @@ set_tx_power(const radio_value_t power) return RADIO_RESULT_INVALID_VALUE; } const RF_TxPowerTable_Value value = RF_TxPowerTable_findValue(TX_POWER_TABLE, power); - RF_Stat stat = RF_setTxPower(rfHandle, value); + RF_Stat stat = RF_setTxPower(prop_radio.rf_handle, value); return (stat == RF_StatSuccess) ? RADIO_RESULT_OK : RADIO_RESULT_ERROR; } /*---------------------------------------------------------------------------*/ +static uint8_t +calculate_lqi(int8_t rssi) +{ + /* Note : Currently the LQI value is simply the energy detect measurement. + * A more accurate value could be derived by using the correlation + * value along with the RSSI value. */ + rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM); + + /* Create energy detect measurement by normalizing and scaling RF power level. + * Note : The division operation below is designed for maximum accuracy and + * best granularity. This is done by grouping the math operations to + * compute the entire numerator before doing any division. */ + return (MAC_SPEC_ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); +} +/*---------------------------------------------------------------------------*/ static void init_rx_buffers(void) { - rfc_dataEntry_t *entry; - int i; - - for(i = 0; i < PROP_MODE_RX_BUF_CNT; i++) { - entry = (rfc_dataEntry_t *)rx_buf[i]; - entry->status = DATA_ENTRY_PENDING; - entry->config.type = DATA_ENTRY_TYPE_GEN; - entry->config.lenSz = DATA_ENTRY_LENSZ_WORD; - entry->length = RX_BUF_SIZE - 8; - entry->pNextEntry = rx_buf[i + 1]; + size_t i = 0; + for (i = 0; i < RX_BUF_CNT; i++) { + const rfc_dataEntry_t data_entry = { + .status = DATA_ENTRY_PENDING, + .config.type = DATA_ENTRY_TYPE_GEN, + .config.lenSz = DATA_ENTRY_LENSZ_WORD, + .length = RX_BUF_SIZE - sizeof(rfc_dataEntry_t), /* TODO is this sizeof sound? */ + /* Point to fist entry if this is last entry, else point to next entry */ + .pNextEntry = (i == (RX_BUF_CNT - 1)) + ? prop_radio.rx_buf[0] + : prop_radio.rx_buf[i] + }; + /* Write back data entry struct */ + *(rfc_dataEntry_t *)prop_radio.rx_buf[i] = data_entry; } - - ((rfc_dataEntry_t *)rx_buf[PROP_MODE_RX_BUF_CNT - 1])->pNextEntry = rx_buf[0]; } /*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { - int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); + int len = MIN(payload_len, TX_BUF_PAYLOAD_LEN); - memcpy(&tx_buf[TX_BUF_HDR_LEN], payload, len); - return 0; + memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, len); + return 0; } /*---------------------------------------------------------------------------*/ static int transmit(unsigned short transmit_len) { - int ret; - uint8_t was_off = 0; + int ret; + uint8_t was_off = 0; - if (rf_is_transmitting()) { - PRINTF("transmit: not allowed while transmitting\n"); - return RADIO_TX_ERR; - } else if (rf_is_receiving()) { - rf_stop_rx(); - } else { - was_off = 1; - } + if (tx_active()) { + PRINTF("transmit: not allowed while transmitting\n"); + return RADIO_TX_ERR; + } else if (rx_active()) { + stop_rx(); + } else { + was_off = 1; + } - /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ - uint16_t total_length; + /* Length in .15.4g PHY HDR. Includes the CRC but not the HDR itself */ + uint16_t total_length; - /* - * Prepare the .15.4g PHY header - * MS=0, Length MSBits=0, DW and CRC configurable - * Total length = transmit_len (payload) + CRC length - * - * The Radio will flip the bits around, so tx_buf[0] must have the length - * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] - */ - total_length = transmit_len + CRC_LEN; + /* + * Prepare the .15.4g PHY header + * MS=0, Length MSBits=0, DW and CRC configurable + * Total length = transmit_len (payload) + CRC length + * + * The Radio will flip the bits around, so tx_buf[0] must have the length + * LSBs (PHR[15:8] and tx_buf[1] will have PHR[7:0] + */ + total_length = transmit_len + CRC_LEN; - tx_buf[0] = total_length & 0xFF; - tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; + prop_radio.tx_buf[0] = total_length & 0xFF; + prop_radio.tx_buf[1] = (total_length >> 8) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT; - /* - * pktLen: Total number of bytes in the TX buffer, including the header if - * one exists, but not including the CRC (which is not present in the buffer) - */ - cmd_tx->pktLen = transmit_len + DOT_4G_PHR_LEN; - cmd_tx->pPkt = tx_buf; + /* + * pktLen: Total number of bytes in the TX buffer, including the header if + * one exists, but not including the CRC (which is not present in the buffer) + */ + cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN; + cmd_tx.pPkt = prop_radio.tx_buf; - // TODO: Register callback - RF_runCmd(rfHandle, (RF_Op*)cmd_tx, RF_PriorityNormal, NULL, 0); + // TODO: Register callback + RF_runCmd(prop_radio.rf_handle, (RF_Op*)&cmd_tx, RF_PriorityNormal, NULL, 0); // if (txHandle == RF_ALLOC_ERROR) // { // /* Failure sending the CMD_PROP_TX command */ @@ -472,173 +491,194 @@ transmit(unsigned short transmit_len) // // watchdog_periodic(); // // /* Idle away while the command is running */ -// RF_pendCmd(rfHandle, txHandle, RF_EventLastCmdDone); +// RF_pendCmd(rf_handle, txHandle, RF_EventLastCmdDone); - if(cmd_tx->status == PROP_DONE_OK) { - /* Sent OK */ - ret = RADIO_TX_OK; - } else { - /* Operation completed, but frame was not sent */ - PRINTF("transmit: Not Sent OK status=0x%04x\n", - cmd_tx->status); - ret = RADIO_TX_ERR; - } + if(cmd_tx.status == PROP_DONE_OK) { + /* Sent OK */ + ret = RADIO_TX_OK; + } else { + /* Operation completed, but frame was not sent */ + PRINTF("transmit: Not Sent OK status=0x%04x\n", + cmd_tx.status); + ret = RADIO_TX_ERR; + } - ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); + ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); - /* Workaround. Set status to IDLE */ - cmd_tx->status = IDLE; + /* Workaround. Set status to IDLE */ + cmd_tx.status = IDLE; - if (was_off) { - RF_yield(rfHandle); - } else { - rf_start_rx(); - } + if (was_off) { + RF_yield(prop_radio.rf_handle); + } else { + start_rx(); + } - return ret; + return ret; } /*---------------------------------------------------------------------------*/ static int send(const void *payload, unsigned short payload_len) { - prepare(payload, payload_len); - return transmit(payload_len); + prepare(payload, payload_len); + return transmit(payload_len); } /*---------------------------------------------------------------------------*/ static int -read_frame(void *buf, unsigned short buf_len) +read(void *buf, unsigned short buf_len) { - rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; - uint8_t *data_ptr = &entry->data; - int len = 0; + rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)prop_radio.rx_read_entry; + uint8_t *data_ptr = &entry->data; + uint16_t len = 0; - if(entry->status == DATA_ENTRY_FINISHED) { + if (entry->status != DATA_ENTRY_FINISHED) { + return 0; + } - /* - * First 2 bytes in the data entry are the length. - * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) - * This length includes all of those. - */ - len = (*(uint16_t *)data_ptr); - data_ptr += 2; - len -= 2; + /* First 2 bytes in the data entry are the length. + * Our data entry consists of: Payload + RSSI (1 byte) + Status (1 byte) + * This length includes all of those. */ + len = *(uint16_t *)data_ptr; + data_ptr += 2; + len -= 2; - if(len > 0) { - if(len <= buf_len) { - memcpy(buf, data_ptr, len); - } + const bool len_ok = (0 < len) && (len <= (uint16_t)buf_len); + if (len_ok) { + memcpy(buf, data_ptr, len); - packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (int8_t)data_ptr[len]); - packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, 0x7F); - } + int8_t rssi = (int8_t)data_ptr[len]; + uint8_t lqi = calculate_lqi(rssi); - /* Move read entry pointer to next entry */ - rx_read_entry = entry->pNextEntry; - entry->status = DATA_ENTRY_PENDING; - } + packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi); + packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi); + } - return len; + /* Move read entry pointer to next entry */ + prop_radio.rx_read_entry = entry->pNextEntry; + entry->status = DATA_ENTRY_PENDING; + + return (len_ok) + ? (int)len + : 0; } /*---------------------------------------------------------------------------*/ static int channel_clear(void) { - uint8_t was_off = 0; - int8_t rssi = RF_CMD_CCA_REQ_RSSI_UNKNOWN; - -// /* -// * If we are in the middle of a BLE operation, we got called by ContikiMAC -// * from within an interrupt context. Indicate a clear channel -// */ -// if(rf_ble_is_active() == RF_BLE_ACTIVE) { -// return RF_CCA_CLEAR; -// } - - if (rf_is_transmitting()) { - PRINTF("channel_clear: called while in TX\n"); - return RF_CCA_CLEAR; - } else if (!rf_is_receiving()) { - was_off = 1; - rf_start_rx(); - } - - while(rssi == RF_CMD_CCA_REQ_RSSI_UNKNOWN || rssi == 0) { - rssi = RF_getRssi(rfHandle); - } - - if(was_off) { - rf_switch_off(); - } - - if(rssi >= rssi_threshold) { - return RF_CCA_BUSY; - } - + if (tx_active()) { + PRINTF("channel_clear: called while in TX\n"); return RF_CCA_CLEAR; + } + + const bool rx_was_off = !rx_active(); + if (rx_was_off) { + start_rx(); + } + + int8_t rssi = RF_GET_RSSI_ERROR_VAL; + while (rssi == RF_GET_RSSI_ERROR_VAL || rssi == 0) { + rssi = RF_getRssi(prop_radio.rf_handle); + } + + if (rx_was_off) { + stop_rx(); + } + + if(rssi >= prop_radio.rssi_threshold) { + return RF_CCA_BUSY; + } + + return RF_CCA_CLEAR; } /*---------------------------------------------------------------------------*/ static int receiving_packet(void) { - if(!rf_is_receiving()) { - return 0; - } + if (!rx_active()) { + return 0; + } - if(channel_clear() == RF_CCA_CLEAR) { - return 0; - } + if (channel_clear() == RF_CCA_CLEAR) { + return 0; + } - return 1; + return 1; } /*---------------------------------------------------------------------------*/ static int pending_packet(void) { - int rv = 0; - volatile rfc_dataEntry_t *entry = (rfc_dataEntry_t *)rx_data_queue.pCurrEntry; + const rfc_dataEntry_t *const first_entry = (rfc_dataEntry_t *)prop_radio.rx_data_queue.pCurrEntry; + volatile const rfc_dataEntry_t *entry = first_entry; - /* Go through all RX buffers and check their status */ - do { - if(entry->status == DATA_ENTRY_FINISHED) { - rv += 1; - process_poll(&RF_coreProcess); - } + int rv = 0; - entry = (rfc_dataEntry_t *)entry->pNextEntry; - } while(entry != (rfc_dataEntry_t *)rx_data_queue.pCurrEntry); + /* Go through RX Circular buffer and check their status */ + do { + const uint8_t status = entry->status; + if ((status == DATA_ENTRY_FINISHED) || + (status == DATA_ENTRY_BUSY)) { + rv += 1; + } - /* If we didn't find an entry at status finished, no frames are pending */ - return rv; + entry = (rfc_dataEntry_t *)entry->pNextEntry; + } while (entry != first_entry); + + if (rv > 0) { + process_poll(&rf_process); + } + + /* If we didn't find an entry at status finished, no frames are pending */ + return rv; } /*---------------------------------------------------------------------------*/ static int -rf_switch_on(void) +on(void) { - init_rx_buffers(); - return rf_start_rx(); -} -/*---------------------------------------------------------------------------*/ -static int -rf_switch_off(void) -{ -// /* -// * If we are in the middle of a BLE operation, we got called by ContikiMAC -// * from within an interrupt context. Abort, but pretend everything is OK. -// */ -// if(rf_ble_is_active() == RF_BLE_ACTIVE) { -// return CMD_RESULT_OK; -// } - - // Force abort of any ongoing RF operation. - RF_cancelCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 0); - - // Trigger a manual power-down - RF_yield(rfHandle); - - /* We pulled the plug, so we need to restore the status manually */ - cmd_rx->status = IDLE; - + if (prop_radio.rf_is_on) { + PRINTF("RF on: Radio already in RX\n"); return CMD_RESULT_OK; + } + + /* Reset all RF command statuses */ + cmd_radio_setup.status = IDLE; + cmd_fs.status = IDLE; + cmd_tx.status = IDLE; + cmd_rx.status = IDLE; + + init_rx_buffers(); + + const int rx_ok = start_rx(); + if (!rx_ok) { + off(); + return CMD_RESULT_ERROR; + } + + prop_radio.rf_is_on = true; + return CMD_RESULT_OK; +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + if (!prop_radio.rf_is_on) { + return CMD_RESULT_OK; + } + + // Force abort of any ongoing RF operation. + RF_flushCmd(prop_radio.rf_handle, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY); + + // Trigger a manual power-down + RF_yield(prop_radio.rf_handle); + + /* We pulled the plug, so we need to restore the status manually */ + cmd_radio_setup.status = IDLE; + cmd_fs.status = IDLE; + cmd_tx.status = IDLE; + cmd_rx.status = IDLE; + + prop_radio.rf_is_on = false; + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ static radio_result_t @@ -651,7 +691,10 @@ get_value(radio_param_t param, radio_value_t *value) switch (param) { case RADIO_PARAM_POWER_MODE: /* On / off */ - *value = rf_is_on() ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + *value = (prop_radio.rf_is_on) + ? RADIO_POWER_MODE_ON + : RADIO_POWER_MODE_OFF; + return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: @@ -663,12 +706,12 @@ get_value(radio_param_t param, radio_value_t *value) return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - *value = rssi_threshold; + *value = prop_radio.rssi_threshold; return RADIO_RESULT_OK; case RADIO_PARAM_RSSI: *value = get_rssi(); - return (*value == RF_CMD_CCA_REQ_RSSI_UNKNOWN) + return (*value == RF_GET_RSSI_ERROR_VAL) ? RADIO_RESULT_ERROR : RADIO_RESULT_OK; @@ -703,7 +746,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; } if(value == RADIO_POWER_MODE_OFF) { - rf_switch_off(); + off(); return RADIO_RESULT_OK; } return RADIO_RESULT_INVALID_VALUE; @@ -730,7 +773,7 @@ set_value(radio_param_t param, radio_value_t value) return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: - rssi_threshold = (int8_t)value; + prop_radio.rssi_threshold = (int8_t)value; return RADIO_RESULT_OK; default: @@ -738,20 +781,20 @@ set_value(radio_param_t param, radio_value_t value) } /* If we reach here we had no errors. Apply new settings */ - if (rf_is_receiving()) { - rf_stop_rx(); - if (rf_run_setup() != CMD_RESULT_OK) { - return RADIO_RESULT_ERROR; - } - rf_start_rx(); - } else if (rf_is_transmitting()) { - // Should not happen. TX is always synchronous and blocking. - // Todo: maybe remove completely here. - PRINTF("set_value: cannot apply new value while transmitting. \n"); + if (rx_active()) { + stop_rx(); + if (rf_run_setup() != CMD_RESULT_OK) { return RADIO_RESULT_ERROR; + } + start_rx(); + } else if (tx_active()) { + // Should not happen. TX is always synchronous and blocking. + // Todo: maybe remove completely here. + PRINTF("set_value: cannot apply new value while transmitting. \n"); + return RADIO_RESULT_ERROR; } else { - // was powered off. Nothing to do. New values will be - // applied automatically on next power-up. + // was powered off. Nothing to do. New values will be + // applied automatically on next power-up. } return RADIO_RESULT_OK; @@ -770,49 +813,63 @@ set_object(radio_param_t param, const void *src, size_t size) } /*---------------------------------------------------------------------------*/ static int -rf_init(void) +init(void) { - RF_Params params; - RF_Params_init(¶ms); - // Disable automatic power-down just to not interfere with stack timing - params.nInactivityTimeout = 0; + /* Zero initalize TX and RX buffers */ + memset(prop_radio.tx_buf, 0x0, sizeof(prop_radio.tx_buf)); + memset(prop_radio.rx_buf, 0x0, sizeof(prop_radio.rx_buf)); - rfHandle = RF_open(&rfObject, &rf_prop_mode, (RF_RadioSetup*)cmd_radio_setup, ¶ms); - assert(rfHandle != NULL); + /* Circular buffer, no last entry */ + prop_radio.rx_data_queue.pCurrEntry = prop_radio.rx_buf[0]; + prop_radio.rx_data_queue.pLastEntry = NULL; - /* Initialise RX buffers */ - memset(rx_buf, 0, sizeof(rx_buf)); + /* Initialize current read pointer to first element (used in ISR) */ + prop_radio.rx_read_entry = prop_radio.rx_buf[0]; - /* Set of RF Core data queue. Circular buffer, no last entry */ - rx_data_queue.pCurrEntry = rx_buf[0]; - rx_data_queue.pLastEntry = NULL; + /* Set configured RSSI threshold */ + prop_radio.rssi_threshold = PROP_MODE_RSSI_THRESHOLD; - /* Initialize current read pointer to first element (used in ISR) */ - rx_read_entry = rx_buf[0]; + /* RX is off */ + prop_radio.rf_is_on = false; - cmd_rx->pQueue = &rx_data_queue; - cmd_rx->pOutput = (uint8_t *)&rx_stats; + /* Configure RX command */ + cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset; + cmd_rx.pQueue = &prop_radio.rx_data_queue; + cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats; - set_channel(RF_CORE_CHANNEL); + /* Init RF params and specify non-default params */ + RF_Params rf_params; + RF_Params_init(&rf_params); + rf_params.nInactivityTimeout = 2000; /* 2 ms */ - ENERGEST_ON(ENERGEST_TYPE_LISTEN); + /* Open RF Driver */ + prop_radio.rf_handle = RF_open(&prop_radio.rf_object, &rf_prop_mode, + (RF_RadioSetup*)&cmd_radio_setup, &rf_params); + if (prop_radio.rf_handle == NULL) { + return CMD_RESULT_ERROR; + } - process_start(&RF_coreProcess, NULL); + set_channel(PROP_MODE_CHANNEL); - return CMD_RESULT_OK; + ENERGEST_ON(ENERGEST_TYPE_LISTEN); + + /* Start RF process */ + process_start(&rf_process, NULL); + + return CMD_RESULT_OK; } /*---------------------------------------------------------------------------*/ const struct radio_driver prop_mode_driver = { - rf_init, + init, prepare, transmit, send, - read_frame, + read, channel_clear, receiving_packet, pending_packet, - rf_switch_on, - rf_switch_off, + on, + off, get_value, set_value, get_object, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c index e0608075a..8c79d3ab7 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.c @@ -97,7 +97,7 @@ RF_TxPowerTable_Entry rf_prop_tx_power_table[RF_PROP_TX_POWER_TABLE_SIZE+1] = }; /*---------------------------------------------------------------------------*/ // Overrides for CMD_PROP_RADIO_DIV_SETUP -uint32_t p_prop_overrides[] CC_ALIGN(4) = +uint32_t rf_prop_overrides[] CC_ALIGN(4) = { // override_use_patch_prop_genfsk.xml MCE_RFE_OVERRIDE(0,4,0,1,0,0), // PHY: Use MCE ROM bank 4, RFE RAM patch @@ -137,15 +137,15 @@ uint32_t p_prop_overrides[] CC_ALIGN(4) = // Proprietary Mode Radio Setup Command for All Frequency Bands rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = { - .commandNo = 0x3807, - .status = 0x0000, + .commandNo = CMD_PROP_RADIO_DIV_SETUP, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .modulation.modType = 0x1, .modulation.deviation = 0x64, @@ -164,7 +164,7 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = .config.analogCfgMode = 0x0, .config.bNoFsPowerUp = 0x0, .txPower = 0xAB3F, - .pRegOverride = pPropOverrides, + .pRegOverride = rf_prop_overrides, .centerFreq = 0x0364, .intFreq = 0x8000, .loDivider = 0x05, @@ -174,15 +174,15 @@ rfc_CMD_PROP_RADIO_DIV_SETUP_t rf_cmd_prop_radio_div_setup = // Frequency Synthesizer Programming Command rfc_CMD_FS_t rf_cmd_prop_fs = { - .commandNo = 0x0803, - .status = 0x0000, + .commandNo = CMD_FS, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x0, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .frequency = 0x0364, .fractFreq = 0x0000, @@ -199,14 +199,14 @@ rfc_CMD_FS_t rf_cmd_prop_fs = rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv = { .commandNo = CMD_PROP_TX_ADV, - .status = 0x0000, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = 0x2, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x1, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, .pktConf.bFsOff = 0x0, .pktConf.bUseCrc = 0x1, diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h index ec580734d..e6dd45962 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc13x0/prop-settings.h @@ -52,7 +52,7 @@ extern rfc_CMD_PROP_TX_ADV_t rf_cmd_prop_tx_adv; extern rfc_CMD_PROP_RX_ADV_t rf_cmd_prop_rx_adv; /*---------------------------------------------------------------------------*/ // RF Core API Overrides -extern uint32_t p_prop_overrides[]; +extern uint32_t rf_prop_overrides[]; /*---------------------------------------------------------------------------*/ #endif /* PROP_SETTINGS_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c index 91db86f41..709314db6 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.c @@ -109,7 +109,7 @@ uint32_t rf_ieee_overrides[] CC_ALIGN(4) = rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = { .commandNo = CMD_RADIO_SETUP, - .status = 0x0000, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = TRIG_NOW, @@ -133,7 +133,7 @@ rfc_CMD_RADIO_SETUP_t rf_cmd_ieee_radio_setup = rfc_CMD_FS_t rf_cmd_ieee_fs = { .commandNo = CMD_FS, - .status = 0x0000, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = TRIG_NOW, @@ -142,8 +142,8 @@ rfc_CMD_FS_t rf_cmd_ieee_fs = .startTrigger.pastTrig = 0x0, .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .frequency = 0x0965, - .fractFreq = 0x0000, + .frequency = 0x0965, /* set by driver */ + .fractFreq = 0x0000, /* set by driver */ .synthConf.bTxMode = 0x1, .synthConf.refFreq = 0x0, .__dummy0 = 0x00, @@ -156,8 +156,8 @@ rfc_CMD_FS_t rf_cmd_ieee_fs = // IEEE 802.15.4 Transmit Command rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = { - .commandNo = CMD_IEEE_RX, - .status = 0x0000, + .commandNo = CMD_IEEE_TX, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, .startTrigger.triggerType = TRIG_NOW, @@ -178,25 +178,25 @@ rfc_CMD_IEEE_TX_t rf_cmd_ieee_tx = // IEEE 802.15.4 Receive Command rfc_CMD_IEEE_RX_t rf_cmd_ieee_rx = { - .commandNo = 0x2801, - .status = 0x0000, + .commandNo = CMD_IEEE_RX, + .status = IDLE, .pNextOp = 0, .startTime = 0x00000000, - .startTrigger.triggerType = 0x0, + .startTrigger.triggerType = TRIG_NOW, .startTrigger.bEnaCmd = 0x0, .startTrigger.triggerNo = 0x0, .startTrigger.pastTrig = 0x0, - .condition.rule = 0x1, + .condition.rule = COND_NEVER, .condition.nSkip = 0x0, - .channel = 0x00, - .rxConfig.bAutoFlushCrc = 0x0, + .channel = 0x00, /* set by driver */ + .rxConfig.bAutoFlushCrc = 0x1, .rxConfig.bAutoFlushIgn = 0x0, .rxConfig.bIncludePhyHdr = 0x0, - .rxConfig.bIncludeCrc = 0x0, + .rxConfig.bIncludeCrc = 0x1, .rxConfig.bAppendRssi = 0x1, .rxConfig.bAppendCorrCrc = 0x1, .rxConfig.bAppendSrcInd = 0x0, - .rxConfig.bAppendTimestamp = 0x0, + .rxConfig.bAppendTimestamp = 0x1, .pRxQ = 0, /* set by driver */ .pOutput = 0, /* set by driver */ .frameFiltOpt.frameFiltEn = 0x0, /* set by driver */ diff --git a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h index a97730988..f92283afc 100644 --- a/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h +++ b/arch/cpu/cc13xx-cc26xx/rf-settings/cc26x2/ieee-settings.h @@ -34,8 +34,8 @@ #include #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) -#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h -#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)) +#include DeviceFamily_constructPath(driverlib/rf_ieee_cmd.h) +#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h) #include /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h index 468e74170..afb69933b 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h +++ b/arch/platform/simplelink/cc13xx-cc26xx/contiki-conf.h @@ -59,8 +59,8 @@ * Override button symbols from dev/button-sensor.h, for the examples that * include it */ -#define btn1_sensor button_left_sensor -#define btn2_sensor button_right_sensor +#define button_left_sensor btn1_sensor +#define button_right_sensor btn2_sensor /** @} */ /*---------------------------------------------------------------------------*/ /* Platform-specific define to signify sensor reading failure */ diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c index b6ecdbc23..efc24a7c2 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/button-sensor-arch.c @@ -41,23 +41,24 @@ #include /*---------------------------------------------------------------------------*/ #include -#include +#include #include /*---------------------------------------------------------------------------*/ #include +#include /*---------------------------------------------------------------------------*/ #include "button-sensor.h" #include "button-sensor-arch.h" /*---------------------------------------------------------------------------*/ /* LaunchPad has 2 buttons: BTN1 and BTN2 */ /* Map the GPIO defines from the Board file */ -#define BTN1_GPIO Board_GPIO_BTN1 -#define BTN2_GPIO Board_GPIO_BTN2 +#define BTN1_PIN Board_PIN_BTN1 +#define BTN2_PIN Board_PIN_BTN2 /*---------------------------------------------------------------------------*/ #ifdef BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN # define BUTTON_SENSOR_ENABLE_SHUTDOWN BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN #else -# define BUTTON_SENSOR_ENABLE_SHUTDOWN 1 +# define BUTTON_SENSOR_ENABLE_SHUTDOWN 0 #endif /*---------------------------------------------------------------------------*/ #define DEBOUNCE_DURATION (CLOCK_SECOND >> 5) @@ -68,56 +69,92 @@ typedef struct { clock_time_t duration; } BtnTimer; /*---------------------------------------------------------------------------*/ -static BtnTimer g_btn1Timer; -static BtnTimer g_btn2Timer; +static BtnTimer btn1_timer; +static BtnTimer btn2_timer; +/*---------------------------------------------------------------------------*/ +static const PIN_Config btn_pin_table[] = { + BTN1_PIN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + BTN2_PIN | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + PIN_TERMINATE +}; + +static PIN_State pin_state; +static PIN_Handle pin_handle; /*---------------------------------------------------------------------------*/ static void -button_press_cb(uint8_t index, BtnTimer *btnTimer, const struct sensors_sensor *btnSensor) +button_press_cb(PIN_Handle handle, PIN_Id pin_id) { - if (!timer_expired(&btnTimer->debounce)) { +#ifdef BUTTON_SENSOR_ENABLE_SHUTDOWN + if (pin_id == BTN2_PIN) { + Power_shutdown(Power_ENTERING_SHUTDOWN, 0); + return; + } +#endif + + BtnTimer *btn_timer = NULL; + const struct sensors_sensor *btn_sensor = NULL; + + switch (pin_id) { + case BTN1_PIN: btn_timer = &btn1_timer; + btn_sensor = &btn1_sensor; break; + case BTN2_PIN: btn_timer = &btn2_timer; + btn_sensor = &btn2_sensor; break; + default: return; /* No matching PIN */ + } + + if (!timer_expired(&btn_timer->debounce)) { return; } - timer_set(&btnTimer->debounce, DEBOUNCE_DURATION); + timer_set(&btn_timer->debounce, DEBOUNCE_DURATION); // Start press duration counter on press (falling), notify on release (rising) - if (GPIO_read(index) == 0) { - btnTimer->start = clock_time(); - btnTimer->duration = 0; + if (PIN_getInputValue(pin_id) == 0) { + btn_timer->start = clock_time(); + btn_timer->duration = 0; } else { - btnTimer->duration = clock_time() - btnTimer->start; - sensors_changed(btnSensor); + btn_timer->duration = clock_time() - btn_timer->start; + sensors_changed(btn_sensor); } } /*---------------------------------------------------------------------------*/ static int -button_value(int type, uint8_t index, BtnTimer *btnTimer) +button_value(int type, uint8_t pin, BtnTimer *btn_timer) { if (type == BUTTON_SENSOR_VALUE_STATE) { - return (GPIO_read(index) == 0) + return (PIN_getInputValue(pin) == 0) ? BUTTON_SENSOR_VALUE_PRESSED : BUTTON_SENSOR_VALUE_RELEASED; } else if (type == BUTTON_SENSOR_VALUE_DURATION) { - return (int)btnTimer->duration; + return (int)btn_timer->duration; } return 0; } /*---------------------------------------------------------------------------*/ static int -button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) +button_config(int type, int value, uint8_t pin) { switch (type) { case SENSORS_HW_INIT: - GPIO_clearInt(index); - GPIO_setCallback(index, callback); + // Open PIN handle + if (pin_handle) { + return 1; + } + pin_handle = PIN_open(&pin_state, btn_pin_table); + if (!pin_handle) { + return 0; + } + // Register button callback function + PIN_registerIntCb(pin_handle, button_press_cb); break; case SENSORS_ACTIVE: if (value) { - GPIO_clearInt(index); - GPIO_enableInt(index); + // Enable interrupts on both edges + PIN_setInterrupt(pin_handle, pin | PIN_IRQ_BOTHEDGES); } else { - GPIO_disableInt(index); + // Disable pin interrupts + PIN_setInterrupt(pin_handle, pin | PIN_IRQ_DIS); } break; } @@ -126,70 +163,53 @@ button_config(int type, int value, uint8_t index, GPIO_CallbackFxn callback) } /*---------------------------------------------------------------------------*/ static int -button_status(int type, uint8_t index) +button_status(int type, uint8_t pin) { switch(type) { case SENSORS_ACTIVE: /* fallthrough */ case SENSORS_READY: { - GPIO_PinConfig pinCfg = 0; - GPIO_getConfig(index, &pinCfg); - return (pinCfg & GPIO_CFG_IN_INT_NONE) == 0; + PIN_Config pin_cfg = PIN_getConfig(pin); + return (pin_cfg & PIN_BM_IRQ) == PIN_IRQ_DIS; } + default: break; } return 0; } /*---------------------------------------------------------------------------*/ -static void -btn1_press_cb(unsigned char unusued) -{ - button_press_cb(BTN1_GPIO, &g_btn1Timer, &btn1_sensor); -} -/*---------------------------------------------------------------------------*/ static int btn1_value(int type) { - return button_value(type, BTN1_GPIO, &g_btn1Timer); + return button_value(type, BTN1_PIN, &btn1_timer); } /*---------------------------------------------------------------------------*/ static int btn1_config(int type, int value) { - return button_config(type, value, BTN1_GPIO, btn1_press_cb); + return button_config(type, value, BTN1_PIN); } /*---------------------------------------------------------------------------*/ static int btn1_status(int type) { - return button_status(type, BTN1_GPIO); -} -/*---------------------------------------------------------------------------*/ -static void -btn2_press_cb(unsigned char unusued) -{ - if (BUTTON_SENSOR_ENABLE_SHUTDOWN) { - Power_shutdown(Power_ENTERING_SHUTDOWN, 0); - return; - } - - button_press_cb(BTN2_GPIO, &g_btn2Timer, &btn2_sensor); + return button_status(type, BTN1_PIN); } /*---------------------------------------------------------------------------*/ static int btn2_value(int type) { - return button_value(type, BTN2_GPIO, &g_btn2Timer); + return button_value(type, BTN2_PIN, &btn2_timer); } /*---------------------------------------------------------------------------*/ static int btn2_config(int type, int value) { - return button_config(type, value, BTN2_GPIO, btn2_press_cb); + return button_config(type, value, BTN2_PIN); } /*---------------------------------------------------------------------------*/ static int btn2_status(int type) { - return button_status(type, BTN1_GPIO); + return button_status(type, BTN2_PIN); } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(btn1_sensor, BUTTON_SENSOR, btn1_value, btn1_config, btn1_status); diff --git a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c index c9c7b6d2e..f2a669037 100644 --- a/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c +++ b/arch/platform/simplelink/cc13xx-cc26xx/launchpad/launchpad-sensors.c @@ -43,12 +43,8 @@ /*---------------------------------------------------------------------------*/ /* Exports a global symbol to be used by the sensor API */ SENSORS( -#ifdef BUTTON_SENSOR_ARCH_BTN1 - &button_sensor, -#endif -#ifdef BUTTON_SENSOR_ARCH_BTN2 - &button_sensor2, -#endif + &btn1_sensor, + &btn2_sensor, NULL ); /*---------------------------------------------------------------------------*/ diff --git a/os/sys/cc.h b/os/sys/cc.h index 6670eca46..2fa5439df 100644 --- a/os/sys/cc.h +++ b/os/sys/cc.h @@ -145,6 +145,10 @@ #define ABS(n) (((n) < 0) ? -(n) : (n)) #endif +#ifndef CLAMP +#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin)) +#endif + #define CC_CONCAT2(s1, s2) s1##s2 /**