/*---------------------------------------------------------------------------*/ void cc2520_set_txpower(uint8_t power) { GET_LOCK(); set_txpower(power); RELEASE_LOCK(); }
void hw_fem_set_txpower_ftdf(bool high) { #if defined(dg_configFEM_SKY66112_11_CHL_PORT) && defined(dg_configFEM_SKY66112_11_CHL_PIN) GLOBAL_INT_DISABLE(); fem_config.tx_power_ftdf = high; set_txpower(); GLOBAL_INT_RESTORE(); #endif }
/*---------------------------------------------------------------------------*/ static radio_result_t set_value(radio_param_t param, radio_value_t value) { switch(param) { case RADIO_PARAM_POWER_MODE: if(value == RADIO_POWER_MODE_ON) { on(); return RADIO_RESULT_OK; } if(value == RADIO_POWER_MODE_OFF) { off(); return RADIO_RESULT_OK; } return RADIO_RESULT_INVALID_VALUE; case RADIO_PARAM_CHANNEL: if(value < 11 || value > 26) { return RADIO_RESULT_INVALID_VALUE; } set_channel(value); return RADIO_RESULT_OK; case RADIO_PARAM_RX_MODE: if(value & ~(RADIO_RX_MODE_ADDRESS_FILTER | RADIO_RX_MODE_AUTOACK | RADIO_RX_MODE_POLL_MODE)) { return RADIO_RESULT_INVALID_VALUE; } set_frame_filtering((value & RADIO_RX_MODE_ADDRESS_FILTER) != 0); set_autoack((value & RADIO_RX_MODE_AUTOACK) != 0); set_poll_mode((value & RADIO_RX_MODE_POLL_MODE) != 0); return RADIO_RESULT_OK; case RADIO_PARAM_TX_MODE: if(value & ~(RADIO_TX_MODE_SEND_ON_CCA)) { return RADIO_RESULT_INVALID_VALUE; } set_send_on_cca((value & RADIO_TX_MODE_SEND_ON_CCA) != 0); return RADIO_RESULT_OK; case RADIO_PARAM_TXPOWER: if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) { return RADIO_RESULT_INVALID_VALUE; /* Find the closest higher PA_LEVEL for the desired output power */ } set_txpower(value); return RADIO_RESULT_OK; case RADIO_PARAM_CCA_THRESHOLD: cca_thershold = value; return RADIO_RESULT_OK; default: return RADIO_RESULT_NOT_SUPPORTED; } }
/*---------------------------------------------------------------------------*/ static int cc2520_transmit(unsigned short payload_len) { int i, txpower; GET_LOCK(); txpower = 0; if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Remember the current transmission power */ txpower = cc2520_get_txpower(); /* Set the specified transmission power */ set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1); } /* The TX FIFO can only hold one packet. Make sure to not overrun * FIFO by waiting for transmission to start here and synchronizing * with the CC2520_TX_ACTIVE check in cc2520_send. * * Note that we may have to wait up to 320 us (20 symbols) before * transmission starts. */ #ifndef CC2520_CONF_SYMBOL_LOOP_COUNT #error CC2520_CONF_SYMBOL_LOOP_COUNT needs to be set!!! #else #define LOOP_20_SYMBOLS CC2520_CONF_SYMBOL_LOOP_COUNT #endif #if WITH_SEND_CCA strobe(CC2520_INS_SRXON); BUSYWAIT_UNTIL(status() & BV(CC2520_RSSI_VALID) , RTIMER_SECOND / 10); strobe(CC2520_INS_STXONCCA); #else /* WITH_SEND_CCA */ strobe(CC2520_INS_STXON); #endif /* WITH_SEND_CCA */ for(i = LOOP_20_SYMBOLS; i > 0; i--) { if(CC2520_SFD_IS_1) { { rtimer_clock_t sfd_timestamp; sfd_timestamp = cc2520_sfd_start_time; if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP) { /* Write timestamp to last two bytes of packet in TXFIFO. */ CC2520_WRITE_RAM(&sfd_timestamp, CC2520RAM_TXFIFO + payload_len - 1, 2); } } if(!(status() & BV(CC2520_TX_ACTIVE))) { /* SFD went high but we are not transmitting. This means that we just started receiving a packet, so we drop the transmission. */ RELEASE_LOCK(); return RADIO_TX_COLLISION; } if(receive_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* We wait until transmission has ended so that we get an accurate measurement of the transmission time.*/ //BUSYWAIT_UNTIL(getreg(CC2520_EXCFLAG0) & TX_FRM_DONE , RTIMER_SECOND / 100); BUSYWAIT_UNTIL(!(status() & BV(CC2520_TX_ACTIVE)), RTIMER_SECOND / 10); #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2520_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } else { /* We need to explicitly turn off the radio, * since STXON[CCA] -> TX_ACTIVE -> RX_ACTIVE */ off(); } if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_OK; } } /* If we are using WITH_SEND_CCA, we get here if the packet wasn't transmitted because of other channel activity. */ RIMESTATS_ADD(contentiondrop); PRINTF("cc2520: do_send() transmission never started\n"); if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_COLLISION; }
/*---------------------------------------------------------------------------*/ static int cc2420_read(void *buf, unsigned short bufsize) { uint8_t footer[2]; uint8_t len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ if(!CC2420_FIFOP_IS_1) { return 0; } /* if(!pending) { return 0; }*/ pending = 0; GET_LOCK(); cc2420_packets_read++; getrxbyte(&len); if(len > CC2420_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ flushrx(); RIMESTATS_ADD(badsynch); RELEASE_LOCK(); return 0; } if(len <= AUX_LEN) { flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - AUX_LEN > bufsize) { flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } getrxdata(buf, len - AUX_LEN); #if CC2420_CONF_CHECKSUM getrxdata(&checksum, CHECKSUM_LEN); #endif /* CC2420_CONF_CHECKSUM */ getrxdata(footer, FOOTER_LEN); #if CC2420_CONF_CHECKSUM if(checksum != crc16_data(buf, len - AUX_LEN, 0)) { PRINTF("checksum failed 0x%04x != 0x%04x\n", checksum, crc16_data(buf, len - AUX_LEN, 0)); } if(footer[1] & FOOTER1_CRC_OK && checksum == crc16_data(buf, len - AUX_LEN, 0)) { #else if(footer[1] & FOOTER1_CRC_OK) { #endif /* CC2420_CONF_CHECKSUM */ cc2420_last_rssi = footer[0]; cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2420_last_rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2420_last_correlation); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); len = AUX_LEN; } if(CC2420_FIFOP_IS_1) { if(!CC2420_FIFO_IS_1) { /* Clean up in case of FIFO overflow! This happens for every * full length frame and is signaled by FIFOP = 1 and FIFO = * 0. */ flushrx(); } else { /* Another packet has been received and needs attention. */ process_poll(&cc2420_process); } } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; } /*---------------------------------------------------------------------------*/ void cc2420_set_txpower(uint8_t power) { GET_LOCK(); set_txpower(power); RELEASE_LOCK(); }
/*---------------------------------------------------------------------------*/ static int cc2420_transmit(unsigned short payload_len) { int i, txpower; uint8_t total_len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ GET_LOCK(); txpower = 0; if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Remember the current transmission power */ txpower = cc2420_get_txpower(); /* Set the specified transmission power */ set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1); } total_len = payload_len + AUX_LEN; /* The TX FIFO can only hold one packet. Make sure to not overrun * FIFO by waiting for transmission to start here and synchronizing * with the CC2420_TX_ACTIVE check in cc2420_send. * * Note that we may have to wait up to 320 us (20 symbols) before * transmission starts. */ #ifdef TMOTE_SKY #define LOOP_20_SYMBOLS 400 /* 326us (msp430 @ 2.4576MHz) */ #elif __AVR__ #define LOOP_20_SYMBOLS 500 /* XXX */ #endif #if WITH_SEND_CCA strobe(CC2420_SRXON); while(!(status() & BV(CC2420_RSSI_VALID))); strobe(CC2420_STXONCCA); #else /* WITH_SEND_CCA */ strobe(CC2420_STXON); #endif /* WITH_SEND_CCA */ for(i = LOOP_20_SYMBOLS; i > 0; i--) { if(SFD_IS_1) { if(!(status() & BV(CC2420_TX_ACTIVE))) { /* SFD went high but we are not transmitting. This means that we just started receiving a packet, so we drop the transmission. */ return RADIO_TX_ERR; } if(receive_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* We wait until transmission has ended so that we get an accurate measurement of the transmission time.*/ while(status() & BV(CC2420_TX_ACTIVE)); #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2420_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } else { /* We need to explicitly turn off the radio, * since STXON[CCA] -> TX_ACTIVE -> RX_ACTIVE */ off(); } if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_OK; } } /* If we are using WITH_SEND_CCA, we get here if the packet wasn't transmitted because of other channel activity. */ RIMESTATS_ADD(contentiondrop); PRINTF("cc2420: do_send() transmission never started\n"); if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { /* Restore the transmission power */ set_txpower(txpower & 0xff); } RELEASE_LOCK(); return RADIO_TX_ERR; /* Transmission never started! */ }
/*---------------------------------------------------------------------------*/ static int init(void) { int put_index; tsExtAddr node_long_address; uint16_t node_short_address; tx_in_progress = 0; u32JPT_Init(); vMMAC_Enable(); /* Enable/disable interrupts */ if(poll_mode) { vMMAC_EnableInterrupts(NULL); vMMAC_ConfigureInterruptSources(0); } else { vMMAC_EnableInterrupts(&radio_interrupt_handler); } vMMAC_ConfigureRadio(); set_channel(MICROMAC_CONF_CHANNEL); set_txpower(MICROMAC_CONF_TX_POWER); vMMAC_GetMacAddress(&node_long_address); /* Short addresses are disabled by default */ node_short_address = (uint16_t)node_long_address.u32L; vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address); /* Disable hardware backoff */ vMMAC_SetTxParameters(1, 0, 0, 0); vMMAC_SetCutOffTimer(0, FALSE); /* Initialize ring buffer and first input packet pointer */ ringbufindex_init(&input_ringbuf, MIRCOMAC_CONF_BUF_NUM); /* get pointer to next input slot */ put_index = ringbufindex_peek_put(&input_ringbuf); if(put_index == -1) { rx_frame_buffer = NULL; printf("micromac_radio init:! no buffer available. Abort init.\n"); off(); return 0; } else { rx_frame_buffer = &input_array[put_index]; } input_frame_buffer = rx_frame_buffer; process_start(µmac_radio_process, NULL); #if RADIO_TEST_MODE == RADIO_TEST_MODE_HIGH_PWR /* Enable high power mode. * In this mode DIO2 goes high during RX * and DIO3 goes high during TX **/ vREG_SysWrite(REG_SYS_PWR_CTRL, u32REG_SysRead(REG_SYS_PWR_CTRL) | REG_SYSCTRL_PWRCTRL_RFRXEN_MASK | REG_SYSCTRL_PWRCTRL_RFTXEN_MASK); #elif RADIO_TEST_MODE == RADIO_TEST_MODE_ADVANCED /* output internal radio status on IO pins. * See Chris@NXP email */ vREG_SysWrite(REG_SYS_PWR_CTRL, u32REG_SysRead(REG_SYS_PWR_CTRL) | (1UL << 26UL)); #endif /* TEST_MODE */ return 1; }
void hw_fem_start(void) { GLOBAL_INT_DISABLE(); fem_config.started = true; uint8_t set_delay; uint8_t reset_delay; uint16_t rf_port_en; /****************************************************** * Setup GPIOs */ /* CSD GPIO Config */ #if defined(dg_configFEM_SKY66112_11_CSD_PORT) && defined(dg_configFEM_SKY66112_11_CSD_PIN) # if dg_configFEM_SKY66112_11_CSD_USE_DCF == 0 /* Manually set CSD (Enable FEM) */ hw_gpio_configure_pin(dg_configFEM_SKY66112_11_CSD_PORT, dg_configFEM_SKY66112_11_CSD_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_GPIO, true); # else /* Use DCF for CSD */ hw_gpio_set_pin_function(dg_configFEM_SKY66112_11_CSD_PORT, dg_configFEM_SKY66112_11_CSD_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_PORT2_DCF); # endif #endif /* Timer 27 GPIO (DCF Port 0). Used for TX EN */ hw_gpio_set_pin_function(dg_configFEM_SKY66112_11_CTX_PORT, dg_configFEM_SKY66112_11_CTX_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_PORT0_DCF); /* Timer 28 (DCF Port 1). Used for RX EN */ hw_gpio_set_pin_function(dg_configFEM_SKY66112_11_CRX_PORT, dg_configFEM_SKY66112_11_CRX_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_PORT1_DCF); /* Antenna selection */ #if defined(dg_configFEM_SKY66112_11_ANTSEL_PORT) && defined(dg_configFEM_SKY66112_11_ANTSEL_PIN) hw_gpio_configure_pin(dg_configFEM_SKY66112_11_ANTSEL_PORT, dg_configFEM_SKY66112_11_ANTSEL_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_GPIO, fem_config.antsel); #endif /****************************************************** * Setup RF_ANT_TRIM GPIOs */ /* RF_ANT_TRIM_0 Config */ #if defined(dg_configFEM_SKY66112_11_ANT_TRIM_0_PORT) && defined(dg_configFEM_SKY66112_11_ANT_TRIM_0_PIN) hw_gpio_set_pin_function(dg_configFEM_SKY66112_11_ANT_TRIM_0_PORT, dg_configFEM_SKY66112_11_ANT_TRIM_0_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_RF_ANT_TRIM0); #endif /* RF_ANT_TRIM_1 Config */ #if defined(dg_configFEM_SKY66112_11_ANT_TRIM_1_PORT) && defined(dg_configFEM_SKY66112_11_ANT_TRIM_1_PIN) hw_gpio_set_pin_function(dg_configFEM_SKY66112_11_ANT_TRIM_1_PORT, dg_configFEM_SKY66112_11_ANT_TRIM_1_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_RF_ANT_TRIM1); #endif /* RF_ANT_TRIM_2 Config */ #if defined(dg_configFEM_SKY66112_11_ANT_TRIM_2_PORT) && defined(dg_configFEM_SKY66112_11_ANT_TRIM_2_PIN) hw_gpio_set_pin_function(dg_configFEM_SKY66112_11_ANT_TRIM_2_PORT, dg_configFEM_SKY66112_11_ANT_TRIM_2_PIN, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_RF_ANT_TRIM2); #endif /****************************************************** * Setup DCFs */ /* assign values to the timer registers for CTX/CRX (in usec) */ REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_27_REG, SET_OFFSET, dg_configFEM_SKY66112_11_TXSET_DCF); REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_27_REG, RESET_OFFSET, dg_configFEM_SKY66112_11_TXRESET_DCF); REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_28_REG, SET_OFFSET, dg_configFEM_SKY66112_11_RXSET_DCF); REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_28_REG, RESET_OFFSET, dg_configFEM_SKY66112_11_RXRESET_DCF); rf_port_en = 0x6; /* Start with Port 0: TX, Port 1: RX */ /* Compute set/reset delays to use for CSD, CPS, CHL DCFs: For setting delay, * smaller of TXSET, RXSET, and for resetting delay, larger of TXSET, RXSET */ #if dg_configFEM_SKY66112_11_RXSET_DCF > dg_configFEM_SKY66112_11_TXSET_DCF set_delay = dg_configFEM_SKY66112_11_TXSET_DCF; #else set_delay = dg_configFEM_SKY66112_11_RXSET_DCF; #endif #if dg_configFEM_SKY66112_11_RXRESET_DCF > dg_configFEM_SKY66112_11_TXRESET_DCF reset_delay = dg_configFEM_SKY66112_11_RXRESET_DCF; #else reset_delay = dg_configFEM_SKY66112_11_TXRESET_DCF; #endif /* CSD DCF (if enabled) configuration */ #if defined(dg_configFEM_SKY66112_11_CSD_PORT) && defined(dg_configFEM_SKY66112_11_CSD_PIN) # if dg_configFEM_SKY66112_11_CSD_USE_DCF != 0 REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_29_REG, SET_OFFSET, set_delay); REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_29_REG, RESET_OFFSET, reset_delay); /* enable DCF Signals for Port 2 (CSD) for both rx/tx */ rf_port_en |= 0x30; # endif /* dg_configFEM_SKY66112_11_CSD_USE_DCF != 0 */ #endif /* Set bypass (CPS) DCF timers (but don't enable yet) */ REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_30_REG, SET_OFFSET, set_delay); REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_30_REG, RESET_OFFSET, reset_delay); /* Set TX Power (CHL) DCF timers (but don't enable yet) */ REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_31_REG, SET_OFFSET, dg_configFEM_SKY66112_11_TXSET_DCF); REG_SETF(RFCU_POWER, RF_CNTRL_TIMER_31_REG, RESET_OFFSET, dg_configFEM_SKY66112_11_TXRESET_DCF); /* Enable DCFs */ #if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A RFCU_POWER->RF_PORT_EN_REG = rf_port_en; hw_fem_set_txpower(fem_config.tx_power); #else RFCU_POWER->RF_PORT_EN_BLE_REG = rf_port_en; RFCU_POWER->RF_PORT_EN_FTDF_REG = rf_port_en; set_txpower(); #endif set_bypass(); GLOBAL_INT_RESTORE(); }
/*---------------------------------------------------------------------------*/ void uz2400_set_txpower(uint8_t power) { set_txpower(power); }