/* * Crude way of flushing the Tx/Rx FIFO: write the first byte as 0, indicating * a zero-length frame in the buffer. This is interpreted by the driver as an * empty buffer. */ static void flush_buffer(void) { /* NB: tentative untested implementation */ uint8_t temp = 0; trx_frame_write(&temp, 1); }
void tal_tx_beacon(frame_info_t *tx_frame) { tal_trx_status_t trx_status; /* Set pointer to actual mpdu to be downloaded to the transceiver. */ uint8_t *tal_beacon_to_tx = tx_frame->mpdu; /* Avoid that the beacon is transmitted while other transmision is * on-going. */ if (tal_state == TAL_TX_AUTO) { Assert( "trying to transmit beacon while ongoing transmission" == 0); return; } /* Send the pre-created beacon frame to the transceiver. */ do { trx_status = set_trx_state(CMD_PLL_ON); #if (_DEBUG_ > 1) if (trx_status != PLL_ON) { Assert("PLL_ON failed for beacon transmission" == 0); } #endif } while (trx_status != PLL_ON); /* \TODO wait for talbeaconTxTime */ pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ trx_frame_write(tal_beacon_to_tx, tal_beacon_to_tx[0]); tal_beacon_transmission = true; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + tal_beacon_to_tx[0]; #endif }
void radio_send_frame(uint8_t len, uint8_t *frm, uint8_t compcrc) { trx_frame_write(len, frm); // frm[2] = frm[2]+1; TRX_SLPTR_HIGH(); TRX_SLPTR_LOW(); }
void radio_send_frame(uint8_t len, uint8_t *frm, uint8_t compcrc) { /* this block should be made atomic */ trx_frame_write(len, frm); TRX_SLPTR_HIGH(); TRX_SLPTR_LOW(); /***********************************/ }
void tal_tx_beacon(frame_info_t *tx_frame) { tal_trx_status_t trx_status; /* Set pointer to actual mpdu to be downloaded to the transceiver. */ uint8_t *tal_beacon_to_tx = tx_frame->mpdu; /* Avoid that the beacon is transmitted while other transmision is *on-going. */ if (tal_state == TAL_TX_AUTO) { Assert( "trying to transmit beacon while ongoing transmission" == 0); return; } /* Send the pre-created beacon frame to the transceiver. */ do { trx_status = set_trx_state(CMD_PLL_ON); #if (_DEBUG_ > 1) if (trx_status != PLL_ON) { Assert("PLL_ON failed for beacon transmission" == 0); } #endif } while (trx_status != PLL_ON); /* \TODO wait for talbeaconTxTime */ ENTER_CRITICAL_REGION(); /* prevent from buffer underrun */ /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ trx_frame_write(tal_beacon_to_tx, tal_beacon_to_tx[0] - 1); tal_beacon_transmission = true; LEAVE_CRITICAL_REGION(); }
void radio_send_frame(uint8_t len, uint8_t *frm, uint8_t compcrc) { #ifdef TRX_TX_PA_EI if (radiostatus.tx_pa) { TRX_TX_PA_EI(); } #endif /* this block should be made atomic */ TRX_SLPTR_HIGH(); TRX_SLPTR_LOW(); trx_frame_write(len, frm); /***********************************/ }
/* * \brief Starts continuous transmission on current channel * * \param tx_mode Mode of continuous transmission (CW or PRBS) * \param random_content Use random content if true */ void tfa_continuous_tx_start(continuous_tx_mode_t tx_mode, bool random_content) { uint8_t txcwdata[128]; trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_DISABLE); trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); trx_reg_write(0x36, 0x0F); /*TST_CTRL_DIGI*/ /* Here: use 2MBPS mode for PSD measurements. * Omit the two following lines, if 250k mode is desired for PRBS mode. **/ trx_reg_write(RG_TRX_CTRL_2, 0x03); trx_reg_write(RG_RX_CTRL, 0xA7); if (tx_mode == CW_MODE) { txcwdata[0] = 1; /* length */ /* Step 12 - frame buffer write access */ txcwdata[1] = 0x00; /* f=fch-0.5 MHz; set value to 0xFF for * f=fch+0.5MHz */ trx_frame_write(txcwdata, 2); } else { /* PRBS mode */ txcwdata[0] = 127; /* = max length */ for (uint8_t i = 1; i < 128; i++) { if (random_content) { txcwdata[i] = (uint8_t)rand(); } else { txcwdata[i] = 0; } } trx_frame_write(txcwdata, 128); } trx_reg_write(RG_PART_NUM, 0x54); trx_reg_write(RG_PART_NUM, 0x46); set_trx_state(CMD_PLL_ON); TRX_SLP_TR_HIGH(); TRX_SLP_TR_LOW(); }
/** * \brief Transmits the frame over-the-air */ static void tx_frame(void) { tal_trx_status_t trx_status; /* * Trigger transmission * In case of an ongoing reception, * the incoming frame is handled first within ISR. */ do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0]); tal_state = TAL_TX_AUTO; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + tal_frame_to_tx[0]; #endif }
int rf233_prepare(const void *payload, unsigned short payload_len) { int i; uint8_t templen; uint8_t radio_status; uint8_t data[130]; /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; data[0] = templen; for (i = 0; i < templen; i++) { data[i + 1] = ((uint8_t*)payload)[i]; } data[3] = (uint8_t)(counter & 0xff); counter++; #if DEBUG_PRINTDATA PRINTF("RF233 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF233: prepare %u\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF233: error, frame too large to tx\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status = rf233_status(); if (radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF233: TRX buffer unavailable: prep when state %s\n", state_str(radio_status)); return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF233: sqno: %02x len = %u\n", counter, payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; }
uint8_t wibo_run(void) { uint8_t isLeave=0; uint8_t isStay=0; unsigned long timeout = WIBO_TIMEOUT; while(!isLeave) { #if !defined(NO_LEDS) LED_CLR(PROGLED); #endif if (!(isStay)) { while(!(wibo_available()) && (timeout--)) _delay_ms(1); // minimum frame time @ 250kbps ~ 2ms. if (!(wibo_available())) // no packets received, bye bye! { isLeave=1; return isLeave; } } else { while(!(wibo_available())); // wait for next packet } trx_reg_write(RG_IRQ_STATUS, TRX_IRQ_RX_END); /* clear the flag */ trx_frame_read(rxbuf.data, sizeof(rxbuf.data) / sizeof(rxbuf.data[0]), &tmp); /* dont use LQI, write into tmp variable */ #if !defined(NO_LEDS) LED_SET(PROGLED); /* light as long as actions are running */ #endif switch (rxbuf.hdr.cmd) { case P2P_PING_REQ: isStay=1; if (0 == deaf) { pingrep.hdr.dst = rxbuf.hdr.src; pingrep.hdr.seq++; pingrep.crc = datacrc; trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); /* no need to make block atomic since no IRQs are used */ TRX_SLPTR_HIGH() ; TRX_SLPTR_LOW() ; trx_frame_write(sizeof(p2p_ping_cnf_t) + sizeof(BOARD_NAME) + 2, (uint8_t*) &pingrep); /*******************************************************/ #if defined(_DEBUG_SERIAL_) printf("Pinged by 0x%04X"EOL, rxbuf.hdr.src); #endif #if defined(TRX_IF_RFA1) while (!(trx_reg_read(RG_IRQ_STATUS) & TRX_IRQ_TX_END)) ; trx_reg_write(RG_IRQ_STATUS, TRX_IRQ_TX_END); /* clear the flag */ #else while (!(trx_reg_read(RG_IRQ_STATUS) & TRX_IRQ_TRX_END)) ; #endif /* defined(TRX_IF_RFA1) */ trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); } /* (0 == deaf) */ break; case P2P_WIBO_TARGET: isStay=1; target = rxbuf.wibo_target.targmem; #if defined(_DEBUG_SERIAL_) printf("Set Target to %c"EOL, target); #endif break; case P2P_WIBO_RESET: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Reset"EOL); #endif addr = SPM_PAGESIZE; /* misuse as counter */ ptr = pagebuf; do { *ptr++ = 0xFF; } while (--addr); addr = 0; datacrc = 0; pagebufidx = 0; deaf = 0; break; case P2P_WIBO_ADDR: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Set address: 0x%08lX"EOL, rxbuf.wibo_addr.address); #endif addr = rxbuf.wibo_addr.address; pagebufidx = 0; break; case P2P_WIBO_DATA: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Data[%d]", rxbuf.wibo_data.dsize); uint8_t len = rxbuf.wibo_data.dsize; if (len > 10) len = 10; for(uint8_t j=0;j<len;j++) { printf(" %02X", rxbuf.wibo_data.data[j]); } if (len != rxbuf.wibo_data.dsize) printf("..."); printf(EOL); #endif tmp = rxbuf.wibo_data.dsize; ptr = rxbuf.wibo_data.data; do { datacrc = _crc_ccitt_update(datacrc, *ptr); pagebuf[pagebufidx++] = *ptr; if (pagebufidx >= PAGEBUFSIZE) { /* LED off to save current and avoid flash corruption * because of possible voltage drops */ #if !defined(NO_LEDS) LED_CLR(PROGLED); #endif if (target == 'F') /* Flash memory */ { boot_program_page(addr, pagebuf); } else if (target == 'E') { /* not implemented */ } else { /* unknown target, dry run */ } /* also for dry run! */ addr += SPM_PAGESIZE; pagebufidx = 0; } ptr++; } while (--tmp); break; #if defined(WIBO_FLAVOUR_BOOTLUP) case P2P_WIBO_BOOTLUP: isStay=1; bootlup(); break; #endif case P2P_WIBO_FINISH: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Finish"EOL); #endif if (target == 'F') /* Flash memory */ { boot_program_page(addr, pagebuf); } else if (target == 'E') { /* not implemented */ } else { /* unknown target, dry run */ } /* also for dry run! */ addr += SPM_PAGESIZE; pagebufidx = 0; break; case P2P_WIBO_EXIT: #if defined(_DEBUG_SERIAL_) printf("Exit"EOL); #endif #if !defined(NO_LEDS) LED_CLR(PROGLED); #endif isLeave=1; break; case P2P_WIBO_DEAF: isStay=1; deaf = 1; break; default: /* unknown or unhandled command */ if (!(isStay)) { if (!(timeout--)) { isLeave = 1; } } break; }; /* switch (rxbuf.hdr.cmd) */ } return isLeave; }
/* * \brief Sends frame * * \param use_csma Flag indicating if CSMA is requested * \param tx_retries Flag indicating if transmission retries are requested * by the MAC layer */ void send_frame(csma_mode_t csma_mode, bool tx_retries) { tal_trx_status_t trx_status; /* Configure tx according to tx_retries */ if (tx_retries) { trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { trx_bit_write(SR_MAX_FRAME_RETRIES, 0); } /* Configure tx according to csma usage */ if ((csma_mode == NO_CSMA_NO_IFS) || (csma_mode == NO_CSMA_WITH_IFS)) { if (tx_retries) { trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); trx_reg_write(RG_CSMA_BE, 0x00); } else { trx_bit_write(SR_MAX_CSMA_RETRIES, 7); } } else { trx_reg_write(RG_CSMA_BE, ((tal_pib.MaxBE << 4) | tal_pib.MinBE)); trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); } do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); /* Handle interframe spacing */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } else { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinSIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } } else { /* * If no delay is applied after switching to TX_ARET_ON, * a short delay is required that allows that a pending TX_END * IRQ for * ACK transmission gets served. */ pal_timer_delay(TRX_IRQ_DELAY_US); } ENTER_CRITICAL_REGION(); /* prevent from buffer underrun */ /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; LEAVE_CRITICAL_REGION(); }
/* * \brief Sends frame using trx features to handle CSMA and re-transmissions * * \param use_csma Flag indicating if CSMA is requested * \param tx_retries Flag indicating if transmission retries are requested * by the MAC layer */ void send_frame(csma_mode_t csma_mode, bool tx_retries) { tal_trx_status_t trx_status; /* Configure tx according to tx_retries */ if (tx_retries) { trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { trx_bit_write(SR_MAX_FRAME_RETRIES, 0); } /* Configure tx according to csma usage */ if ((csma_mode == NO_CSMA_NO_IFS) || (csma_mode == NO_CSMA_WITH_IFS)) { trx_bit_write(SR_MAX_CSMA_RETRIES, 7); /* immediate * transmission */ } else { trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); } do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); pal_trx_irq_dis(); /* Handle interframe spacing */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } else { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinSIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } } /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + frame_tx[0]; #endif }
/** * \brief prepare a frame and the radio for immediate transmission * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ int rf233_prepare(const void *payload, unsigned short payload_len) { #if DEBUG_PRINTDATA int i; #endif /* DEBUG_PRINTDATA */ uint8_t templen; uint8_t radio_status; uint8_t data[130]; #if USE_HW_FCS_CHECK /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; #else /* USE_HW_FCS_CHECK */ /* FCS is assumed to already be included in the payload */ templen = payload_len; #endif /* USE_HW_FCS_CHECK */ //data = templen; /* for(i = 0; i < templen; i++) { data++; data =(uint8_t *)(payload + i); }*/ //memcpy(data,&templen,1); data[0] = templen; memcpy(&data[1],payload,templen); //data--; #if DEBUG_PRINTDATA PRINTF("RF233 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\r\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF233: prepare %u\r\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF233: error, frame too large to tx\r\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status=rf233_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF233: TRX buffer unavailable: prep when %s\r\n", radio_status == STATE_BUSY_RX_AACK ? "rx" : "tx"); #else if(radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX) { PRINTF("RF233: TRX buffer unavailable: prep when %s\r\n", radio_status == STATE_BUSY_RX? "rx" : "tx"); #endif return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF233 len = %u\r\n", payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Transmit a frame already put in the radio with 'prepare' * \param payload_len Length of the frame to send * \return Returns success/fail, refer to radio.h for explanation */ int rf233_transmit(unsigned short payload_len) { static uint8_t status_now; PRINTF("RF233: tx %u\r\n", payload_len); /* prepare for TX */ status_now = rf233_status(); //status_now = trx_reg_read(RF233_REG_TRX_RPC); #if NULLRDC_CONF_802154_AUTOACK_HW if(status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { #else if(status_now == STATE_BUSY_RX || status_now == STATE_BUSY_TX) { #endif PRINTF("RF233: collision, was receiving 0x%02X\r\n",status_now); /* NOTE: to avoid loops */ return RADIO_TX_ERR;; // return RADIO_TX_COLLISION; } if(status_now != STATE_PLL_ON) { /* prepare for going to state TX, should take max 80 us */ //RF233_COMMAND(TRXCMD_PLL_ON); trx_reg_write(RF233_REG_TRX_STATE,0x09); // BUSYWAIT_UNTIL(trx_reg_read(RF233_REG_TRX_STATUS) == STATE_PLL_ON, 1 * RTIMER_SECOND/1000); //delay_ms(10); //status_now = trx_reg_read(RF233_REG_TRX_STATE); do { status_now = trx_bit_read(0x01, 0x1F, 0); } while (status_now == 0x1f); } if(rf233_status() != STATE_PLL_ON) { /* failed moving into PLL_ON state, gracefully try to recover */ PRINTF("RF233: failed going to PLLON\r\n"); RF233_COMMAND(TRXCMD_PLL_ON); /* try again */ static uint8_t state; state = rf233_status(); if(state != STATE_PLL_ON) { /* give up and signal big fail (should perhaps reset radio core instead?) */ PRINTF("RF233: graceful recovery (in tx) failed, giving up. State: 0x%02X\r\n", rf233_status()); return RADIO_TX_ERR; } } /* perform transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); #if NULLRDC_CONF_802154_AUTOACK_HW RF233_COMMAND(TRXCMD_TX_ARET_ON); #endif RF233_COMMAND(TRXCMD_TX_START); flag_transmit=1; //delay_ms(5); //printf("RTIMER value %d",RTIMER_NOW()); #if !NULLRDC_CONF_802154_AUTOACK_HW BUSYWAIT_UNTIL(rf233_status() == STATE_BUSY_TX, RTIMER_SECOND/2000); // printf("RTIMER value1 %d",RTIMER_NOW()); // printf("\r\nSTATE_BUSY_TX"); BUSYWAIT_UNTIL(rf233_status() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); // printf("RTIMER value2 %d",RTIMER_NOW()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); #if !NULLRDC_CONF_802154_AUTOACK_HW if(rf233_status() != STATE_PLL_ON) { // something has failed PRINTF("RF233: radio fatal err after tx\r\n"); radiocore_hard_recovery(); return RADIO_TX_ERR; } RF233_COMMAND(TRXCMD_RX_ON); #else BUSYWAIT_UNTIL(ack_status == 1, 10 * RTIMER_SECOND/1000); if((ack_status)) { // printf("\r\nrf233 sent\r\n "); ack_status=0; // printf("\nACK received"); return RADIO_TX_OK; } else { // printf("\nNOACK received"); return RADIO_TX_NOACK; } #endif PRINTF("RF233: tx ok\r\n"); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Send data: first prepares, then transmits * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ int rf233_send(const void *payload, unsigned short payload_len) { PRINTF("RF233: send %u\r\n", payload_len); if(rf233_prepare(payload, payload_len) == RADIO_TX_ERR) { return RADIO_TX_ERR; } return rf233_transmit(payload_len); } /*---------------------------------------------------------------------------*/ /** * \brief read a received frame out of the radio buffer * \param buf pointer to where to copy received data * \param bufsize Maximum size we can copy into bufsize * \return Returns length of data read (> 0) if successful * \retval -1 Failed, was transmitting so FIFO is invalid * \retval -2 Failed, rx timed out (stuck in rx?) * \retval -3 Failed, too large frame for buffer * \retval -4 Failed, CRC/FCS failed (if USE_HW_FCS_CHECK is true) */ int rf233_read(void *buf, unsigned short bufsize) { // uint8_t radio_state; uint8_t ed; /* frame metadata */ uint8_t frame_len = 0; uint8_t len = 0; int rssi; #if DEBUG_PRINTDATA uint8_t tempreadlen; #endif /* DEBUG_PRINTDATA */ if(pending_frame == 0) { return 0; } pending_frame = 0; /* / * check that data in FIFO is valid * / radio_state = RF233_STATUS(); if(radio_state == STATE_BUSY_TX) { / * data is invalid, bail out * / PRINTF("RF233: read while in BUSY_TX ie invalid, dropping.\n"); return -1; } if(radio_state == STATE_BUSY_RX) { / * still receiving - data is invalid, wait for it to finish * / PRINTF("RF233: read while BUSY_RX, waiting.\n"); BUSYWAIT_UNTIL(RF233_STATUS() != STATE_BUSY_RX, 10 * RTIMER_SECOND/1000); if(RF233_STATUS() == STATE_BUSY_RX) { PRINTF("RF233: timed out, still BUSY_RX, dropping.\n"); return -2; } } */ /* get length of data in FIFO */ trx_frame_read(&frame_len, 1); #if DEBUG_PRINTDATA tempreadlen = frame_len; #endif /* DEBUG_PRINTDATA */ if(frame_len == 1) { frame_len = 0; } len = frame_len; #if USE_HW_FCS_CHECK /* FCS has already been stripped */ len = frame_len - 2; #endif /* USE_HW_FCS_CHECK */ if(frame_len == 0) { return 0; } if(len > bufsize) { /* too large frame for the buffer, drop */ PRINTF("RF233: too large frame for buffer, dropping (%u > %u).\r\n", frame_len, bufsize); flush_buffer(); return -3; } PRINTF("RF233 read %u B\r\n", frame_len); /* read out the data into the buffer, disregarding the length and metadata bytes */ trx_sram_read(1,(uint8_t *)buf, len); #if DEBUG_PRINTDATA { int k; PRINTF("RF233: Read frame (%u/%u): ", tempreadlen, frame_len); for(k = 0; k < frame_len; k++) { PRINTF("%02x", *((uint8_t *)buf + k)); } PRINTF("\r\n"); } #endif /* DEBUG_PRINTDATA */ /* * Energy level during reception, ranges from 0x00 to 0x53 (=83d) with a * resolution of 1dB and accuracy of +/- 5dB. 0xFF means invalid measurement. * 0x00 means <= RSSI(base_val), which is -91dBm (typ). See datasheet 12.7. * Ergo, real RSSI is (ed-91) dBm or less. */ #define RSSI_OFFSET (91) ed = trx_reg_read(RF233_REG_PHY_ED_LEVEL); rssi = (int) ed - RSSI_OFFSET; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); flush_buffer(); /* #if USE_HW_FCS_CHECK { uint8_t crc_ok; / * frame metadata * / crc_ok = rf233_arch_read_reg(RF233_REG_PHY_RSSI) & PHY_RSSI_CRC_VALID; if(crc_ok == 0) { / * CRC/FCS fail, drop * / PRINTF("RF233: CRC/FCS fail, dropping.\n"); flush_buffer(); return -4; } } #endif / * USE_HW_FCS_CHECK * /*/ return len; }
/** * \brief prepare a frame and the radio for immediate transmission * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ static int rf212_prepare(const void *payload, unsigned short payload_len) { #if DEBUG_PRINTDATA int i; #endif /* DEBUG_PRINTDATA */ uint8_t templen; uint8_t radio_status; uint8_t data[130]; #if USE_HW_FCS_CHECK /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; #else /* USE_HW_FCS_CHECK */ /* FCS is assumed to already be included in the payload */ templen = payload_len; #endif /* USE_HW_FCS_CHECK */ data[0] = templen; memcpy(&data[1],payload,templen); #if DEBUG_PRINTDATA PRINTF("RF212 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF212: prepare %u\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF212: error, frame too large to tx\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status = rf212_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF212B: TRX buffer unavailable: prep when %s\n", radio_status == STATE_BUSY_RX_AACK ? "rx" : "tx"); #else if(radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX) { PRINTF("RF212B: TRX buffer unavailable: prep when %s\n", radio_status == STATE_BUSY_RX? "rx" : "tx"); #endif return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF212 len = %u\n", payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Transmit a frame already put in the radio with 'prepare' * \param payload_len Length of the frame to send * \return Returns success/fail, refer to radio.h for explanation */ static int rf212_transmit(unsigned short payload_len) { uint8_t status_now;//,temp; PRINTF("RF212: tx %u\n", payload_len); /* prepare for TX */ status_now = rf212_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { #else if(status_now == STATE_BUSY_RX || status_now == STATE_BUSY_TX) { #endif PRINTF("RF212: collision, was receiving\n"); /* NOTE: to avoid loops */ return RADIO_TX_ERR; // return RADIO_TX_COLLISION; } if(status_now != STATE_PLL_ON) { /* prepare for going to state TX, should take max 80 us */ //RF212_COMMAND(TRXCMD_PLL_ON); trx_reg_write(RF212_REG_TRX_STATE,0x09); do { status_now = trx_bit_read(0x01, 0x1F, 0); } while (status_now == 0x1f); //BUSYWAIT_UNTIL(RF212_STATUS() == STATE_PLL_ON, 1 * RTIMER_SECOND/1000); } if(rf212_status() != STATE_PLL_ON) { /* failed moving into PLL_ON state, gracefully try to recover */ PRINTF("RF212: failed going to PLLON\n"); RF212_COMMAND(TRXCMD_PLL_ON); /* try again */ if(rf212_status() != STATE_PLL_ON) { /* give up and signal big fail (should perhaps reset radio core instead?) */ PRINTF("RF212: graceful recovery (in tx) failed, giving up. State: 0x%02X\n", RF212_STATUS()); return RADIO_TX_ERR; } } /* perform transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); #if NULLRDC_CONF_802154_AUTOACK_HW RF212_COMMAND(TRXCMD_TX_ARET_ON); #endif RF212_COMMAND(TRXCMD_TX_START); flag_transmit=1; #if !NULLRDC_CONF_802154_AUTOACK_HW BUSYWAIT_UNTIL(RF212_STATUS() == STATE_BUSY_TX, RTIMER_SECOND/2000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); #if (DATA_RATE==BPSK_20||BPSK_40||OQPSK_SIN_RC_100) BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); #endif #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); #if !NULLRDC_CONF_802154_AUTOACK_HW if(RF212_STATUS() != STATE_PLL_ON) { /* something has failed */ printf("RF212: radio fatal err after tx\n"); radiocore_hard_recovery(); return RADIO_TX_ERR; } // printf("#RTIMER_SECOND"); RF212_COMMAND(TRXCMD_RX_ON); #else BUSYWAIT_UNTIL(ack_status == 1, 10 * RTIMER_SECOND/1000); if((ack_status)) { // printf("\r\nrf233 sent\r\n "); ack_status=0; // printf("\nACK received"); return RADIO_TX_OK; } else { // printf("\nNOACK received"); return RADIO_TX_NOACK; } #endif PRINTF("RF212: tx ok\n"); return RADIO_TX_OK; } void goto_sleep(void) { port_pin_set_output_level(AT86RFX_SLP_PIN, true); }
/* * \brief Starts continuous transmission on current channel * * \param tx_mode Mode of continuous transmission (CW or PRBS) * \param random_content Use random content if true * * The comment 'step #' refers to the step mentioned in the RF212's datasheet. */ void tfa_continuous_tx_start(continuous_tx_mode_t tx_mode, bool random_content) { uint8_t txcwdata[128]; uint8_t i; /* step 3,6: Channel is assumed to be set before */ trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); /* step 7: Enable continuous transmission - step #1 */ trx_reg_write(0x36, 0x0F); if (tx_mode == CW_MODE) { /* step 8: Register access: CW at Fc +/- 0.1 MHz */ if (((tal_pib.CurrentPage == 0) || (tal_pib.CurrentPage == 2) || \ (tal_pib.CurrentPage == 16) || (tal_pib.CurrentPage == 17)) && (tal_pib.CurrentChannel == 0)) { /* * *868.3MHz **/ trx_reg_write(RG_TRX_CTRL_2, 0x0A); /* 400 kchip/s * mode, step 8 * ,SUB_MODE = 0 */ } else { trx_reg_write(RG_TRX_CTRL_2, 0x0E); /* 1000kchip/s * ,SUB_MODE = 1 */ } txcwdata[0] = 1; /* length */ txcwdata[1] = 0; /* step 9: Frame buffer access */ trx_frame_write(txcwdata, 2); } else { /* PRBS mode */ /* step 8: */ /* * Step 8 is not explicitly written here, because the proper * value is set during reset or by updating the Channel Page. * After finishing CW/PRBS another reset is performed with * parameter set_default_pib set to false, which restores the * original value based on the current Channel Page. * * I.e., in order to use PRBS with a specific data rate, * the Channel Page needs to be udpated before starting PRBS. */ txcwdata[0] = 127; /* = max length */ for (i = 1; i < 128; i++) { if (random_content) { txcwdata[i] = (uint8_t)rand(); } else { txcwdata[i] = 0; } } /* step 9: Frame buffer access */ trx_frame_write(txcwdata, 128); } /* step 10: Enable continuous transmission - step #2 */ trx_reg_write(RG_PART_NUM, 0x54); /* step 11: Enable continuous transmission - step #3 */ trx_reg_write(RG_PART_NUM, 0x46); /* step 12, 13: Stwitch PLL on */ set_trx_state(CMD_PLL_ON); /* step 14: Initiate transmission using SLP_TR line */ TRX_SLP_TR_HIGH(); TRX_SLP_TR_LOW(); }