static uint16_t tx_delay(void) { if (delay_count==0) { // if first try, quick timerB_set_alarm_from_now(ALARM_RETRY, 2, 0); timerB_register_cb(ALARM_RETRY, tx_try); } else if (delay_count >= DELAY_COUNT_MAX) { // to many tries, abort // delete packet txframe.length = 0; // reset callback cc1101_gdo0_register_callback(rx_parse); // reset rx cc1101_cmd_idle(); rx_set(); PRINTF("too many tries\n"); // call the error callback if (error_cb) { return error_cb(); } } else { uint16_t delay; // delay randomly between 1ms and 63ms delay = rand(); delay &= ((1<<11)-1); delay += 32; timerB_set_alarm_from_now(ALARM_RETRY, delay, 0); timerB_register_cb(ALARM_RETRY, tx_try); } delay_count ++; return 0; }
static uint16_t tx_ack(void) { uint8_t status[2]; uint16_t dst; uint16_t ret_val; /* Check if there are bytes in FIFO */ if (cc1101_status_rxbytes() == 0) { return rx_set(); } /* Check Length is correct */ cc1101_fifo_get( (uint8_t*) &(ack.length), 1); // if too big, flush if ( ack.length != HEADER_LENGTH ) { return rx_set(); } /* Get Data */ cc1101_fifo_get( (uint8_t*) &(ack.length)+1, ack.length); /* Get Status Bytes */ cc1101_fifo_get(status, 2); /* Check CRC */ if ( (status[1] & 0x80) == 0 ) { return rx_set(); } ret_val = 0; /* Compute addresses */ dst = (((uint16_t)ack.dst_addr[0])<<8) + ack.dst_addr[1]; /* Check addresses */ if ( (dst==node_addr) && (ack.src_addr[0]==txframe.dst_addr[0]) \ && (ack.src_addr[1]==txframe.dst_addr[1]) ) { txframe.length = 0; timerB_unset_alarm(ALARM_RETRY); cc1101_gdo0_register_callback(rx_parse); rx_set(); if (sent_cb) { return sent_cb(); } } return rx_set(); }
static uint16_t tx_try(void) { uint8_t status; if (txframe.length == 0) { PRINTF("tx_try no packet error\n"); return rx_set(); } // if radio not in RX, delay status = cc1101_status() & 0x70; if ( status != 0x10) { PRINTF("try sending radio state error (%x)\n", status); tx_delay(); return rx_set(); } // if there are some weird bytes in TX FIFO, flush everything if (cc1101_status_txbytes()!=0) { PRINTF("mac had to flush\n"); cc1101_cmd_idle(); cc1101_cmd_flush_tx(); cc1101_cmd_flush_rx(); } // try to send cc1101_cmd_tx(); // get chip status status = cc1101_status() & 0x70; // if status is not RX if ( status != 0x10) { // put data in fifo cc1101_fifo_put((uint8_t*)&txframe, txframe.length+1); cc1101_gdo0_register_callback(tx_done); } else { tx_delay(); rx_set(); } return 0; }
static uint16_t tx_done(void) { // if destination is broadcast, don't wait for ACK if ((txframe.dst_addr[0]==0xFF) && (txframe.dst_addr[1]==0xFF)) { cc1101_gdo0_register_callback(rx_parse); txframe.length = 0; rx_set(); if (sent_cb) { return sent_cb(); } } else { cc1101_gdo0_register_callback(tx_ack); timerB_set_alarm_from_now(ALARM_RETRY, ACK_TIMEOUT, 0); timerB_register_cb(ALARM_RETRY, tx_delay); } return 0; }
static uint16_t rx_ackdone(void) { cc1101_gdo0_register_callback(rx_parse); return rx_set(); }
static uint16_t rx_parse(void) { uint8_t status[2]; uint16_t src, dst; uint16_t ret_val; int16_t rssi; /* Check if there are bytes in FIFO */ if ( (cc1101_status_rxbytes() == 0) || (cc1101_status_rxbytes() > 64) ) { return rx_set(); } /* Check Length is correct */ cc1101_fifo_get( (uint8_t*) &(rxframe.length), 1); // if too big, flush if ( rxframe.length > sizeof(rxframe)-1 ) { return rx_set(); } /* Get Data */ cc1101_fifo_get( (uint8_t*) &(rxframe.length)+1, rxframe.length); /* Get Status Bytes */ cc1101_fifo_get(status, 2); /* Check CRC */ if ( (status[1] & 0x80) == 0 ) { return rx_set(); } /* Check for min length */ if ( rxframe.length < HEADER_LENGTH ) { return rx_set(); } /* Compute addresses */ dst = (((uint16_t)rxframe.dst_addr[0])<<8) + rxframe.dst_addr[1]; src = (((uint16_t)rxframe.src_addr[0])<<8) + rxframe.src_addr[1]; ret_val = 0; int len; len = rxframe.length; len -= HEADER_LENGTH; rssi = status[0] >= 128 ? status[0]-256 : status[0]; rssi -= 140; // if for me, send an ACK if (dst==node_addr) { ack.length = HEADER_LENGTH; ack.type = TYPE_ACK; ack.dst_addr[0] = rxframe.src_addr[0]; ack.dst_addr[1] = rxframe.src_addr[1]; ack.src_addr[0] = rxframe.dst_addr[0]; ack.src_addr[1] = rxframe.dst_addr[1]; if (cc1101_status_txbytes()) { cc1101_cmd_flush_tx(); } cc1101_cmd_tx(); cc1101_fifo_put((uint8_t*)&ack, ack.length+1); cc1101_gdo0_register_callback(rx_ackdone); if (received_cb) { return received_cb(rxframe.payload, len, src, rssi); } } else if ( (dst==0xFFFF) && received_cb ) { /* Call the packet received function */ ret_val = received_cb(rxframe.payload, len, src, rssi); ret_val |= rx_set(); return ret_val; } else { return rx_set(); } return 0; }
critical void mac_restart(void) { rx_set(); }
void mac_init(uint8_t channel) { // initialize the unique serial number chip and set node address accordingly ds2411_init(); node_addr = (((uint16_t)ds2411_id.serial1)<<8) + (ds2411_id.serial0); // seed the random number generator srand(node_addr); // reset callbacks received_cb = 0x0; sent_cb = 0x0; error_cb = 0x0; // initialize the timerB timerB_init(); timerB_start_ACLK_div(1); timerB_register_cb(ALARM_RETRY, tx_try); // configure the radio cc1101_init(); cc1101_cmd_idle(); /* configure the radio behaviour */ cc1101_cfg_append_status(CC1101_APPEND_STATUS_ENABLE); cc1101_cfg_crc_autoflush(CC1101_CRC_AUTOFLUSH_DISABLE); cc1101_cfg_white_data(CC1101_DATA_WHITENING_ENABLE); cc1101_cfg_crc_en(CC1101_CRC_CALCULATION_ENABLE); cc1101_cfg_freq_if(0x0E); cc1101_cfg_fs_autocal(CC1101_AUTOCAL_IDLE_TO_TX_RX); cc1101_cfg_mod_format(CC1101_MODULATION_MSK); cc1101_cfg_sync_mode(CC1101_SYNCMODE_30_32); cc1101_cfg_manchester_en(CC1101_MANCHESTER_DISABLE); cc1101_cfg_cca_mode(CC1101_CCA_MODE_RSSI_PKT_RX); // freq = 860MHz cc1101_write_reg(CC1101_REG_FREQ2, 0x1F); cc1101_write_reg(CC1101_REG_FREQ1, 0xDA); cc1101_write_reg(CC1101_REG_FREQ0, 0x12); // configure the radio channel (300kHz spacing) cc1101_cfg_chanspc_e(0x3); cc1101_cfg_chanspc_m(0x6C); cc1101_cfg_chan(channel<<1); // channel x2 to get 600kHz spacing // rise CCA threshold cc1101_cfg_carrier_sense_abs_thr(5); // set channel bandwidth (560 kHz) cc1101_cfg_chanbw_e(0); cc1101_cfg_chanbw_m(2); // set data rate (0xD/0x2F is 250kbps) cc1101_cfg_drate_e(0x0D); cc1101_cfg_drate_m(0x2F); // go to RX after RX and TX cc1101_cfg_rxoff_mode(CC1101_RXOFF_MODE_IDLE); cc1101_cfg_txoff_mode(CC1101_TXOFF_MODE_RX); uint8_t table[1] = {CC1101_868MHz_TX_0dBm}; // table[0] = CC1101_868MHz_TX_m30dBm; // table[0] = CC1101_868MHz_TX_m20dBm; // table[0] = CC1101_868MHz_TX_m15dBm; // table[0] = CC1101_868MHz_TX_m10dBm; // table[0] = CC1101_868MHz_TX_m6dBm; table[0] = CC1101_868MHz_TX_0dBm; // table[0] = CC1101_868MHz_TX_5dBm; // table[0] = CC1101_868MHz_TX_7dBm; // table[0] = CC1101_868MHz_TX_10dBm; // table[0] = CC1101_868MHz_TX_12dBm; cc1101_cfg_patable(table, 1); cc1101_cfg_pa_power(0); // set IDLE state, flush everything, and start rx cc1101_cmd_idle(); cc1101_cmd_flush_rx(); cc1101_cmd_flush_tx(); cc1101_cmd_calibrate(); // configure irq cc1101_cfg_gdo0(CC1101_GDOx_SYNC_WORD); cc1101_gdo0_int_set_falling_edge(); cc1101_gdo0_int_clear(); cc1101_gdo0_int_enable(); cc1101_gdo0_register_callback(rx_parse); // start the machine rx_set(); txframe.length = 0; }
void mac_init(uint8_t channel) { // initialize the unique serial number chip and set node address accordingly ds2411_init(); node_addr = (((uint16_t)ds2411_id.serial1)<<8) + (ds2411_id.serial0); // seed the random number generator srand(node_addr); // reset callbacks received_cb = 0x0; sent_cb = 0x0; error_cb = 0x0; // initialize the timerB timerB_init(); timerB_start_ACLK_div(1); timerB_register_cb(ALARM_RETRY, check); // configure the radio cc1100_init(); cc1100_cmd_idle(); /* configure the radio behaviour */ cc1100_cfg_append_status(CC1100_APPEND_STATUS_ENABLE); cc1100_cfg_crc_autoflush(CC1100_CRC_AUTOFLUSH_DISABLE); cc1100_cfg_white_data(CC1100_DATA_WHITENING_ENABLE); cc1100_cfg_crc_en(CC1100_CRC_CALCULATION_ENABLE); cc1100_cfg_freq_if(0x0E); cc1100_cfg_fs_autocal(CC1100_AUTOCAL_IDLE_TO_TX_RX); cc1100_cfg_mod_format(CC1100_MODULATION_GFSK); cc1100_cfg_sync_mode(CC1100_SYNCMODE_30_32); cc1100_cfg_manchester_en(CC1100_MANCHESTER_DISABLE); cc1100_cfg_cca_mode(CC1100_CCA_MODE_RSSI_PKT_RX); // freq = 860MHz cc1100_write_reg(CC1100_REG_FREQ2, 0x1F); cc1100_write_reg(CC1100_REG_FREQ1, 0xDA); cc1100_write_reg(CC1100_REG_FREQ0, 0x12); //packet length to 61 cc1100_write_reg(CC1100_REG_PKTLEN, 0x3D); // configure the radio channel cc1100_cfg_chanspc_e(0x2); cc1100_cfg_chanspc_m(0xF8); cc1100_write_reg(CC1100_REG_DEVIATN, 0x47); // rise CCA threshold cc1100_cfg_carrier_sense_abs_thr(5); // set channel bandwidth cc1100_cfg_chanbw_e(1); cc1100_cfg_chanbw_m(3); // set data rate cc1100_cfg_drate_e(0xB); cc1100_cfg_drate_m(0x74); // go to RX after RX and TX cc1100_cfg_rxoff_mode(CC1100_RXOFF_MODE_IDLE); cc1100_cfg_txoff_mode(CC1100_TXOFF_MODE_RX); uint8_t table[1]; table[0] = 0x1E; // -15dBm 13.4mA cc1100_cfg_patable(table, 1); cc1100_cfg_pa_power(0); // set IDLE state, flush everything, and start rx cc1100_cmd_idle(); cc1100_cmd_flush_rx(); cc1100_cmd_flush_tx(); cc1100_cmd_calibrate(); // configure irq cc1100_cfg_gdo0(CC1100_GDOx_SYNC_WORD); cc1100_gdo0_int_set_falling_edge(); cc1100_gdo0_int_clear(); cc1100_gdo0_int_enable(); cc1100_gdo0_register_callback(rx_parse); // start the machine rx_set(); txframe.length = 0; }