/* * Copyright (c) 2007, Swedish Institute of Computer Science * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: rf230bb.c,v 1.1 2009/07/08 16:17:07 dak664 Exp $ */ /** * \brief This module contains radio driver code for the Atmel * AT86RF230. It is modified to use the contiki core MAC layer. * * \author Blake Leverett * Mike Vidales * Eric Gnoske * David Kopf * */ /** \addtogroup wireless * @{ */ /** * \defgroup radiorf230 RF230 interface * @{ */ /** * \file * This file contains "barebones" radio driver code for use with the * contiki core MAC layer. * */ #include #include #include "contiki.h" //#if defined(__AVR__) #include #include #include //#elif defined(__MSP430__) //#include //#endif #include "dev/leds.h" #include "dev/spi.h" #include "rf230bb.h" #include "hal.h" //#include "frame.h" #include "radio.h" #include "net/rime/packetbuf.h" #include "net/rime/rimestats.h" #include "sys/timetable.h" #define WITH_SEND_CCA 0 #if RF230_CONF_TIMESTAMPS #include "net/rime/timesynch.h" #define TIMESTAMP_LEN 3 #else /* RF230_CONF_TIMESTAMPS */ #define TIMESTAMP_LEN 0 #endif /* RF230_CONF_TIMESTAMPS */ #define FOOTER_LEN 2 #ifndef RF230_CONF_CHECKSUM #define RF230_CONF_CHECKSUM 0 #endif /* RF230_CONF_CHECKSUM */ #if RF230_CONF_CHECKSUM #include "lib/crc16.h" #define CHECKSUM_LEN 2 #else #define CHECKSUM_LEN 0 #endif /* RF230_CONF_CHECKSUM */ #define AUX_LEN (CHECKSUM_LEN + TIMESTAMP_LEN + FOOTER_LEN) struct timestamp { uint16_t time; uint8_t authority_level; }; #define FOOTER1_CRC_OK 0x80 #define FOOTER1_CORRELATION 0x7f #define DEBUG 0 #if DEBUG #define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args) #else #define PRINTF(...) do {} while (0) #endif /* XXX hack: these will be made as Chameleon packet attributes */ rtimer_clock_t rf230_time_of_arrival, rf230_time_of_departure; int rf230_authority_level_of_sender; #if RF230_CONF_TIMESTAMPS static rtimer_clock_t setup_time_for_transmission; static unsigned long total_time_for_transmission, total_transmission_len; static int num_transmissions; #endif /* RF230_CONF_TIMESTAMPS */ /* RF230 hardware delay times, from datasheet */ typedef enum{ TIME_TO_ENTER_P_ON = 510, /**< Transition time from VCC is applied to P_ON. */ TIME_P_ON_TO_TRX_OFF = 510, /**< Transition time from P_ON to TRX_OFF. */ TIME_SLEEP_TO_TRX_OFF = 880, /**< Transition time from SLEEP to TRX_OFF. */ TIME_RESET = 6, /**< Time to hold the RST pin low during reset */ TIME_ED_MEASUREMENT = 140, /**< Time it takes to do a ED measurement. */ TIME_CCA = 140, /**< Time it takes to do a CCA. */ TIME_PLL_LOCK = 150, /**< Maximum time it should take for the PLL to lock. */ TIME_FTN_TUNING = 25, /**< Maximum time it should take to do the filter tuning. */ TIME_NOCLK_TO_WAKE = 6, /**< Transition time from *_NOCLK to being awake. */ TIME_CMD_FORCE_TRX_OFF = 1, /**< Time it takes to execute the FORCE_TRX_OFF command. */ TIME_TRX_OFF_TO_PLL_ACTIVE = 180, /**< Transition time from TRX_OFF to: RX_ON, PLL_ON, TX_ARET_ON and RX_AACK_ON. */ TIME_STATE_TRANSITION_PLL_ACTIVE = 1, /**< Transition time from PLL active state to another. */ }radio_trx_timing_t; /*---------------------------------------------------------------------------*/ PROCESS(rf230_process, "RF230 receiver"); /*---------------------------------------------------------------------------*/ int rf230_send(const void *data, unsigned short len); int rf230_read(void *buf, unsigned short bufsize); void rf230_set_receiver(void (* recv)(const struct radio_driver *d)); int rf230_on(void); int rf230_off(void); const struct radio_driver rf230_driver = { rf230_send, rf230_read, rf230_set_receiver, rf230_on, rf230_off, }; static void (* receiver_callback)(const struct radio_driver *); //signed char rf230_last_rssi; //uint8_t rf230_last_correlation; static uint8_t receive_on; //static uint8_t rssi_val; uint8_t rx_mode; /* Radio stuff in network byte order. */ //static uint16_t pan_id; //static int channel; /*----------------------------------------------------------------------------*/ /** \brief This function return the Radio Transceivers current state. * * \retval P_ON When the external supply voltage (VDD) is * first supplied to the transceiver IC, the * system is in the P_ON (Poweron) mode. * \retval BUSY_RX The radio transceiver is busy receiving a * frame. * \retval BUSY_TX The radio transceiver is busy transmitting a * frame. * \retval RX_ON The RX_ON mode enables the analog and digital * receiver blocks and the PLL frequency * synthesizer. * \retval TRX_OFF In this mode, the SPI module and crystal * oscillator are active. * \retval PLL_ON Entering the PLL_ON mode from TRX_OFF will * first enable the analog voltage regulator. The * transceiver is ready to transmit a frame. * \retval BUSY_RX_AACK The radio was in RX_AACK_ON mode and received * the Start of Frame Delimiter (SFD). State * transition to BUSY_RX_AACK is done if the SFD * is valid. * \retval BUSY_TX_ARET The radio transceiver is busy handling the * auto retry mechanism. * \retval RX_AACK_ON The auto acknowledge mode of the radio is * enabled and it is waiting for an incomming * frame. * \retval TX_ARET_ON The auto retry mechanism is enabled and the * radio transceiver is waiting for the user to * send the TX_START command. * \retval RX_ON_NOCLK The radio transceiver is listening for * incomming frames, but the CLKM is disabled so * that the controller could be sleeping. * However, this is only true if the controller * is run from the clock output of the radio. * \retval RX_AACK_ON_NOCLK Same as the RX_ON_NOCLK state, but with the * auto acknowledge module turned on. * \retval BUSY_RX_AACK_NOCLK Same as BUSY_RX_AACK, but the controller * could be sleeping since the CLKM pin is * disabled. * \retval STATE_TRANSITION The radio transceiver's state machine is in * transition between two states. */ uint8_t radio_get_trx_state(void) { return hal_subregister_read(SR_TRX_STATUS); } /*----------------------------------------------------------------------------*/ /** \brief This function checks if the radio transceiver is sleeping. * * \retval true The radio transceiver is in SLEEP or one of the *_NOCLK * states. * \retval false The radio transceiver is not sleeping. */ bool radio_is_sleeping(void) { bool sleeping = false; /* The radio transceiver will be at SLEEP or one of the *_NOCLK states only if */ /* the SLP_TR pin is high. */ if (hal_get_slptr() != 0){ sleeping = true; } return sleeping; } /*----------------------------------------------------------------------------*/ /** \brief This function will reset the state machine (to TRX_OFF) from any of * its states, except for the SLEEP state. */ void radio_reset_state_machine(void) { hal_set_slptr_low(); delay_us(TIME_NOCLK_TO_WAKE); hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF); delay_us(TIME_CMD_FORCE_TRX_OFF); } /*----------------------------------------------------------------------------*/ /** \brief This function will change the current state of the radio * transceiver's internal state machine. * * \param new_state Here is a list of possible states: * - RX_ON Requested transition to RX_ON state. * - TRX_OFF Requested transition to TRX_OFF state. * - PLL_ON Requested transition to PLL_ON state. * - RX_AACK_ON Requested transition to RX_AACK_ON state. * - TX_ARET_ON Requested transition to TX_ARET_ON state. * * \retval RADIO_SUCCESS Requested state transition completed * successfully. * \retval RADIO_INVALID_ARGUMENT Supplied function parameter out of bounds. * \retval RADIO_WRONG_STATE Illegal state to do transition from. * \retval RADIO_BUSY_STATE The radio transceiver is busy. * \retval RADIO_TIMED_OUT The state transition could not be completed * within resonable time. */ radio_status_t radio_set_trx_state(uint8_t new_state) { uint8_t original_state; /*Check function paramter and current state of the radio transceiver.*/ if (!((new_state == TRX_OFF) || (new_state == RX_ON) || (new_state == PLL_ON) || (new_state == RX_AACK_ON) || (new_state == TX_ARET_ON))){ return RADIO_INVALID_ARGUMENT; } if (radio_is_sleeping() == true){ return RADIO_WRONG_STATE; } // Wait for radio to finish previous operation for(;;) { original_state = radio_get_trx_state(); if (original_state != BUSY_TX_ARET && original_state != BUSY_RX_AACK && original_state != BUSY_RX && original_state != BUSY_TX) break; } if (new_state == original_state){ return RADIO_SUCCESS; } /* At this point it is clear that the requested new_state is: */ /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON or TX_ARET_ON. */ /* The radio transceiver can be in one of the following states: */ /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON, TX_ARET_ON. */ if(new_state == TRX_OFF){ radio_reset_state_machine(); /* Go to TRX_OFF from any state. */ } else { /* It is not allowed to go from RX_AACK_ON or TX_AACK_ON and directly to */ /* TX_AACK_ON or RX_AACK_ON respectively. Need to go via RX_ON or PLL_ON. */ if ((new_state == TX_ARET_ON) && (original_state == RX_AACK_ON)){ /* First do intermediate state transition to PLL_ON, then to TX_ARET_ON. */ /* The final state transition to TX_ARET_ON is handled after the if-else if. */ hal_subregister_write(SR_TRX_CMD, PLL_ON); delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE); } else if ((new_state == RX_AACK_ON) && (original_state == TX_ARET_ON)){ /* First do intermediate state transition to RX_ON, then to RX_AACK_ON. */ /* The final state transition to RX_AACK_ON is handled after the if-else if. */ hal_subregister_write(SR_TRX_CMD, RX_ON); delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE); } /* Any other state transition can be done directly. */ hal_subregister_write(SR_TRX_CMD, new_state); /* When the PLL is active most states can be reached in 1us. However, from */ /* TRX_OFF the PLL needs time to activate. */ if (original_state == TRX_OFF){ delay_us(TIME_TRX_OFF_TO_PLL_ACTIVE); } else { delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE); } } /* end: if(new_state == TRX_OFF) ... */ /*Verify state transition.*/ radio_status_t set_state_status = RADIO_TIMED_OUT; if (radio_get_trx_state() == new_state){ set_state_status = RADIO_SUCCESS; /* set rx_mode flag based on mode we're changing to */ if (new_state == RX_ON || new_state == RX_AACK_ON){ rx_mode = true; } else { rx_mode = false; } } return set_state_status; } /*---------------------------------------------------------------------------*/ void rf230_waitidle(void) { // PRINTF("rf230_waitidle"); uint8_t radio_state; for(;;) { radio_state = hal_subregister_read(SR_TRX_STATUS); if (radio_state != BUSY_TX_ARET && radio_state != BUSY_RX_AACK && radio_state != BUSY_RX && radio_state != BUSY_TX) break; PRINTF("."); } } /*---------------------------------------------------------------------------*/ static uint8_t locked, lock_on, lock_off; static void on(void) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); PRINTF("rf230 internal on\n"); receive_on = 1; hal_set_slptr_low(); //radio_is_waking=1;//can test this before tx instead of delaying delay_us(TIME_SLEEP_TO_TRX_OFF); delay_us(TIME_SLEEP_TO_TRX_OFF);//extra delay for now radio_set_trx_state(RX_AACK_ON); // flushrx(); } static void off(void) { PRINTF("rf230 internal off\n"); receive_on = 0; /* Wait for transmission to end before turning radio off. */ rf230_waitidle(); /* Force the device into TRX_OFF. */ radio_reset_state_machine(); /* Sleep Radio */ hal_set_slptr_high(); ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } /*---------------------------------------------------------------------------*/ #define GET_LOCK() locked = 1 static void RELEASE_LOCK(void) { if(lock_on) { on(); lock_on = 0; } if(lock_off) { off(); lock_off = 0; } locked = 0; } /*---------------------------------------------------------------------------*/ void rf230_set_receiver(void (* recv)(const struct radio_driver *)) { //PRINTF("rf230_set receiver\n"); receiver_callback = recv; } /*---------------------------------------------------------------------------*/ int rf230_off(void) { // PRINTF("rf230_off\n"); /* Don't do anything if we are already turned off. */ if(receive_on == 0) { return 1; } /* If we are called when the driver is locked, we indicate that the radio should be turned off when the lock is unlocked. */ if(locked) { lock_off = 1; return 1; } off(); return 1; } /*---------------------------------------------------------------------------*/ int rf230_on(void) { //PRINTF("rf230_on\n"); if(receive_on) { return 1; } if(locked) { lock_on = 1; return 1; } on(); return 1; } /*---------------------------------------------------------------------------*/ int rf230_get_channel(void) { return hal_subregister_read(SR_CHANNEL); // return channel; } /*---------------------------------------------------------------------------*/ void rf230_set_channel(int c) { /* Wait for any transmission to end. */ rf230_waitidle(); //channel=c; hal_subregister_write(SR_CHANNEL, c); } /*---------------------------------------------------------------------------*/ void rf230_set_pan_addr(uint16_t pan,uint16_t addr,uint8_t *ieee_addr) { PRINTF("rf230: PAN=%x Short Addr=%x\n",pan,addr); uint8_t abyte; abyte = pan & 0xFF; hal_register_write(RG_PAN_ID_0,abyte); abyte = (pan >> 8*1) & 0xFF; hal_register_write(RG_PAN_ID_1, abyte); abyte = addr & 0xFF; hal_register_write(RG_SHORT_ADDR_0, abyte); abyte = (addr >> 8*1) & 0xFF; hal_register_write(RG_SHORT_ADDR_1, abyte); if (ieee_addr != NULL) { PRINTF("MAC=%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_7, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_6, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_5, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_4, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_3, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_2, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_1, *ieee_addr++); PRINTF(":%x",*ieee_addr); hal_register_write(RG_IEEE_ADDR_0, *ieee_addr); PRINTF("\n"); } } /*---------------------------------------------------------------------------*/ /* Process to handle input packets * Receive interrupts cause this process to be polled * It calls the core MAC layer which calls rf230_read to get the packet */ PROCESS_THREAD(rf230_process, ev, data) { PROCESS_BEGIN(); while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); #if RF230_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(rf230_timetable, "poll"); #endif /* RF230_TIMETABLE_PROFILING */ if(receiver_callback != NULL) { receiver_callback(&rf230_driver); #if RF230_TIMETABLE_PROFILING TIMETABLE_TIMESTAMP(rf230_timetable, "end"); timetable_aggregate_compute_detailed(&aggregate_time, &rf230_timetable); timetable_clear(&rf230_timetable); #endif /* RF230_TIMETABLE_PROFILING */ } else { PRINTF("rf230_process not receiving function\n"); // flushrx(); } } PROCESS_END(); } /*---------------------------------------------------------------------------*/ /* * This routine is called by the radio receive interrupt in hal.c * It just sets the poll flag for the rf230 process. */ #if RF230_CONF_TIMESTAMPS static volatile rtimer_clock_t interrupt_time; static volatile int interrupt_time_set; #endif /* RF230_CONF_TIMESTAMPS */ #if RF230_TIMETABLE_PROFILING #define rf230_timetable_size 16 TIMETABLE(rf230_timetable); TIMETABLE_AGGREGATE(aggregate_time, 10); #endif /* RF230_TIMETABLE_PROFILING */ void rf230_interrupt(void) { #if RF230_CONF_TIMESTAMPS interrupt_time = timesynch_time(); interrupt_time_set = 1; #endif /* RF230_CONF_TIMESTAMPS */ process_poll(&rf230_process); #if RF230_TIMETABLE_PROFILING timetable_clear(&rf230_timetable); TIMETABLE_TIMESTAMP(rf230_timetable, "interrupt"); #endif /* RF230_TIMETABLE_PROFILING */ return; } /* The frame is buffered to rxframe in the interrupt routine in hal.c */ hal_rx_frame_t rxframe; /*---------------------------------------------------------------------------*/ int rf230_read(void *buf, unsigned short bufsize) { uint8_t *framep; // uint8_t footer[2]; uint8_t len; #if RF230_CONF_CHECKSUM uint16_t checksum; #endif /* RF230_CONF_CHECKSUM */ #if RF230_CONF_TIMESTAMPS struct timestamp t; #endif /* RF230_CONF_TIMESTAMPS */ PRINTF("rf230_read: %u bytes lqi %u crc %u\n",rxframe.length,rxframe.lqi,rxframe.crc); #if DEBUG>1 for (len=0;len RF230_MAX_PACKET_LEN) { // // Oops, we must be out of sync. // flushrx(); // RIMESTATS_ADD(badsynch); // RELEASE_LOCK(); // return 0; // } //hal returns two extra bytes containing the checksum //below works because auxlen is 2 len = rxframe.length; 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; } /* Transfer the frame, stripping the checksum */ framep=&(rxframe.data[0]); memcpy(buf,framep,len-2); /* Clear the length field to allow buffering of the next packet */ rxframe.length=0; // framep+=len-AUX_LEN+2; #if RF230_CONF_CHECKSUM bomb memcpy(&checksum,framep,CHECKSUM_LEN); framep+=CHECKSUM_LEN; #endif /* RF230_CONF_CHECKSUM */ #if RF230_CONF_TIMESTAMPS bomb memcpy(&t,framep,TIMESTAMP_LEN); framep+=TIMESTAMP_LEN; #endif /* RF230_CONF_TIMESTAMPS */ // memcpy(&footer,framep,FOOTER_LEN); #if RF230_CONF_CHECKSUM bomb if(checksum != crc16_data(buf, len - AUX_LEN, 0)) { PRINTF("rf230: 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 (rxframe.crc) { #endif /* RF230_CONF_CHECKSUM */ /* packetbuf_copyfrom(parsed_frame->payload, parsed_frame->payload_length); packetbuf_set_datalen(parsed_frame->payload_length); memcpy(dest_reversed, (uint8_t *)parsed_frame->dest_addr, UIP_LLADDR_LEN); memcpy(src_reversed, (uint8_t *)parsed_frame->src_addr, UIP_LLADDR_LEN); //Change addresses to expected byte order byte_reverse((uint8_t *)dest_reversed, UIP_LLADDR_LEN); byte_reverse((uint8_t *)src_reversed, UIP_LLADDR_LEN); packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (const rimeaddr_t *)dest_reversed); packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (const rimeaddr_t *)src_reversed); */ packetbuf_set_attr(PACKETBUF_ATTR_RSSI, hal_subregister_read( SR_RSSI )); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rxframe.lqi); RIMESTATS_ADD(llrx); #if RF230_CONF_TIMESTAMPS bomb rf230_time_of_departure = t.time + setup_time_for_transmission + (total_time_for_transmission * (len - 2)) / total_transmission_len; rf230_authority_level_of_sender = t.authority_level; packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, t.time); #endif /* RF230_CONF_TIMESTAMPS */ } else { PRINTF("rf230: Bad CRC\n"); RIMESTATS_ADD(badcrc); len = AUX_LEN; } // if (?) /* Another packet has been received and needs attention. */ // process_poll(&rf230_process); // } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; } /*---------------------------------------------------------------------------*/ void rf230_set_txpower(uint8_t power) { if (power > TX_PWR_17_2DBM){ power=TX_PWR_17_2DBM; } if (radio_is_sleeping() ==true) { PRINTF("rf230_set_txpower:Sleeping"); } else { hal_subregister_write(SR_TX_PWR, power); } } /*---------------------------------------------------------------------------*/ int rf230_get_txpower(void) { if (radio_is_sleeping() ==true) { PRINTF("rf230_get_txpower:Sleeping"); return 0; } else { return hal_subregister_read(SR_TX_PWR); } } /*---------------------------------------------------------------------------*/ int rf230_rssi(void) { int rssi; int radio_was_off = 0; /*The RSSI measurement should only be done in RX_ON or BUSY_RX.*/ if(!receive_on) { radio_was_off = 1; rf230_on(); } rssi = (int)((signed char)hal_subregister_read(SR_RSSI)); if(radio_was_off) { rf230_off(); } return rssi; } /*---------------------------------------------------------------------------*/ int rf230_send(const void *payload, unsigned short payload_len) { // int i; uint8_t total_len,buffer[RF230_MAX_TX_FRAME_LENGTH],*pbuf; #if RF230_CONF_TIMESTAMPS struct timestamp timestamp; #endif /* RF230_CONF_TIMESTAMPS */ #if RF230_CONF_CHECKSUM uint16_t checksum; #endif /* RF230_CONF_CHECKSUM */ GET_LOCK(); if(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) > 0) { rf230_set_txpower(packetbuf_attr(PACKETBUF_ATTR_RADIO_TXPOWER) - 1); } else { rf230_set_txpower(TX_PWR_17_2DBM); } RIMESTATS_ADD(lltx); #if RF230_CONF_CHECKSUM checksum = crc16_data(payload, payload_len, 0); #endif /* RF230_CONF_CHECKSUM */ total_len = payload_len + AUX_LEN; /*Check function parameters and current state.*/ if (total_len > RF230_MAX_TX_FRAME_LENGTH){ return -1; } pbuf=&buffer[0]; memcpy(pbuf,payload,payload_len); pbuf+=payload_len; #if RF230_CONF_CHECKSUM memcpy(pbuf,&checksum,CHECKSUM_LEN); pbuf+=CHECKSUM_LEN; #endif /* RF230_CONF_CHECKSUM */ #if RF230_CONF_TIMESTAMPS timestamp.authority_level = timesynch_authority_level(); timestamp.time = timesynch_time(); memcpy(pbuf,×tamp,TIMESTAMP_LEN); pbuf+=TIMESTAMP_LEN; #endif /* RF230_CONF_TIMESTAMPS */ /*Below comments were for cc240 radio, don't know how they apply to rf230 - DAK */ /* 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 RF230_TX_ACTIVE check in rf230_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 #define LOOP_20_SYMBOLS 500 /* Wait for any previous transmission to finish. */ rf230_waitidle(); hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF); delay_us(TIME_P_ON_TO_TRX_OFF); radio_set_trx_state(TX_ARET_ON); //enable auto ack //#if WITH_SEND_CCA // radio_set_trx_state(TX_ARET_ON); //enable auto ack //#endif /* WITH_SEND_CCA */ /* Toggle the SLP_TR pin to initiate the frame transmission. */ PRINTF("rf230: sending %d bytes\n", payload_len); hal_set_slptr_high(); hal_set_slptr_low(); hal_frame_write(buffer, total_len); // for(i = LOOP_20_SYMBOLS; i > 0; i--) {//dak was working with this if(1) { #if RF230_CONF_TIMESTAMPS rtimer_clock_t txtime = timesynch_time(); #endif /* RF230_CONF_TIMESTAMPS */ 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.*/ rf230_waitidle(); radio_set_trx_state(RX_AACK_ON);//Re-enable receive mode #if RF230_CONF_TIMESTAMPS setup_time_for_transmission = txtime - timestamp.time; if(num_transmissions < 10000) { total_time_for_transmission += timesynch_time() - txtime; total_transmission_len += total_len; num_transmissions++; } #endif /* RF230_CONF_TIMESTAMPS */ #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,rf230_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } RELEASE_LOCK(); return 0; } // } /* 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("rf230: do_send() transmission never started\n"); RELEASE_LOCK(); return -3; /* Transmission never started! */ }/*---------------------------------------------------------------------------*/ void rf230_init(void) { /* Wait in case VCC just applied */ delay_us(TIME_TO_ENTER_P_ON); /* Calibrate oscillator */ // calibrate_rc_osc_32k(); /* Initialize Hardware Abstraction Layer. */ hal_init(); /* Do full rf230 Reset */ hal_set_rst_low(); hal_set_slptr_low(); delay_us(TIME_RESET); hal_set_rst_high(); /* Force transition to TRX_OFF. */ hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF); delay_us(TIME_P_ON_TO_TRX_OFF); /* Verify that it is a supported version */ uint8_t tvers = hal_register_read(RG_VERSION_NUM); uint8_t tmanu = hal_register_read(RG_MAN_ID_0); if ((tvers != RF230_REVA) && (tvers != RF230_REVB)) PRINTF("rf230: Unsupported version %u\n",tvers); if (tmanu != SUPPORTED_MANUFACTURER_ID) PRINTF("rf230: Unsupported manufacturer ID %u\n",tmanu); PRINTF("rf230: Version %u, ID %u\n",tvers,tmanu); hal_register_write(RG_IRQ_MASK, RF230_SUPPORTED_INTERRUPT_MASK); /* Turn off address decoding. */ // reg = getreg(RF230_MDMCTRL0); // reg &= ~ADR_DECODE; // setreg(RF230_MDMCTRL0, reg); /* Change default values as recomended in the data sheet, */ /* correlation threshold = 20, RX bandpass filter = 1.3uA. */ // setreg(RF230_MDMCTRL1, CORR_THR(20)); // reg = getreg(RF230_RXCTRL1); // reg |= RXBPF_LOCUR; // setreg(RF230_RXCTRL1, reg); /* Set the FIFOP threshold to maximum. */ // setreg(RF230_IOCFG0, FIFOP_THR(127)); /* Turn off "Security enable" (page 32). */ // reg = getreg(RF230_SECCTRL0); // reg &= ~RXFIFO_PROTECTION; // setreg(RF230_SECCTRL0, reg); // rf230_set_pan_addr(0xffff, 0x0000, NULL); // rf230_set_channel(24); /* Set up the radio for auto mode operation. */ hal_subregister_write(SR_MAX_FRAME_RETRIES, 2 ); hal_subregister_write(SR_TX_AUTO_CRC_ON, 1); hal_subregister_write(SR_TRX_CMD, CMD_RX_AACK_ON); /* Start the packet receive process */ process_start(&rf230_process, NULL); }