📄 cc1000.c
字号:
// This file is part of MANTIS OS, Operating System// See http://mantis.cs.colorado.edu///// Copyright (C) 2003,2004,2005 University of Colorado, Boulder//// This program is free software; you can redistribute it and/or// modify it under the terms of the mos license (see file LICENSE)/** @file cc1000.c * @brief Driver provides: use of cc1000 state machine, generic to most MACs * * Driver requires: AVR architecture with cc1000 connected via SPI bus. * @authors Jeff Rose, Brian Shucker, Hui Dai * @date 03/03/2004 * * This is a conglomeration of cc1000.c and cc1000_defaults.c. We now integrate the SPI * code related to the radio data interface with the configuration code for the radio. [rosejn] */#define INTERRUPT_DRIVEN_SEND 1#include "mos.h"#include "com.h"#if defined(PLATFORM_MICA2) || defined(PLATFORM_MICA2DOT)#include "led.h"#include "sem.h"#include "crc.h"#include "cc1000.h"#include "cc1000_params.h"#include "clock.h"#include "msched.h"#include "mutex.h"#include "stdarg.h"#include "node_id.h"#include "avr-rssi.h"#include "uart.h"#if defined(CC1000) || !defined(SCONS)#ifdef RADIO_USE_FEC#include "fec.h"#endifstatic uint8_t int_handle;/*driver state info*/static comBuf *cc1000_recv_buf; //receive bufferstatic comBuf *cc1000_send_buf; //send buffervoid (*cc1000_state)(void); //current sync state of receiveruint8_t cc1000_com_mode; //current modestatic uint8_t spi_data; //byte pulled off of SPI busstatic uint8_t prev_data; //previous byte pulled off bus (for bit shift)static uint8_t offset; //recv bit offsetstatic uint8_t preamble_count; //preamble bytes receivedstatic uint8_t data_count; //bytes already received or sentstatic uint8_t cc1000_crc_low, cc1000_crc_high; //crc storagestatic uint8_t actual_byte;//error trackinguint16_t cc1000_success_count; //completed packetsuint16_t cc1000_crc_error_count; //dropped packets due to crc erroruint16_t cc1000_mem_error_count; //dropped packets due to out of memoryuint16_t cc1000_sync_error_count; //dropped packets due to sync failureuint16_t cc1000_size_error_count; //dropped packets due to size out of range#ifdef RADIO_USE_FECuint16_t cc1000_fec_error_count; //dropped packets due to fec errors#endif//Enable the GET_RSSI and TS_PACKET switches from com.h//ANS hack:#ifdef GET_RSSIuint16_t rssival;#endif//ANS hack ends#ifdef INTERRUPT_DRIVEN_SENDstatic mos_sem_t cc1000_sem; //to synchronize blocking on send#endif#ifdef RADIO_REDUNDANT_SIZEstatic uint8_t size_bytes[3];#endif#ifdef RADIO_USE_FECuint8_t data_fec[FEC_DATA_PARITY_COUNT];static void state_send_data_fec(void);static void state_recv_data_fec(void);#endifstatic void state_send_pre(void);static void state_send_sync(void);static void state_send_size(void);static void state_send_data(void);static void state_send_flush(void);static void state_send_crc_h(void);static void state_send_crc_l(void);static void state_send_done(void);static void state_recv_data(void);static void state_recv_crc_h(void);static void state_recv_crc_l(void);static void state_recv_size(void);// need reference to this for mac layersvoid state_recv_idle(void);static void state_recv_pre(void);/** @brief this initializes the error checking/correcting bytes * to be used in the mac layer. */inline void cc1000_init_ec (comBuf * sendPkt){ cc1000_send_buf = sendPkt;#ifdef RADIO_USE_FEC fec_init (FEC_DATA_PARITY_COUNT); fec_encode (sendPkt->data, sendPkt->size, data_fec);#else //CRC Code uint16_t crc; //compute crc now, so we don't have to do it in interrupt handler crc = crc_compute (sendPkt->data, sendPkt->size); cc1000_crc_low = crc & 0x00FF; cc1000_crc_high = (crc & 0xFF00) >> 8;#endif}/** @brief routine to start transmission */inline void cc1000_start_transmit(comBuf * sendPkt){ cc1000_init_ec(sendPkt); cc1000_mode(CC1000_MODE_TX); //go to transmit mode int_handle = mos_disable_ints(); cc1000_state = state_send_pre; //init send state machine preamble_count = 1; SPDR = PREAMBLE_BYTE; //start sending first preamble byte#ifdef INTERRUPT_DRIVEN_SEND //INTERRUPT DRIVEN I/O mos_single_threaded(); SPCR |= (1 << SPIE); //turn on spi interrupt //mos_led_display(1); mos_enable_ints(int_handle); mos_sem_wait(&cc1000_sem); mos_multi_threaded();#else //POLLING METHOD: SPCR &= ~(1 << SPIE); //turn off spi interrupt while(cc1000_state != state_recv_idle) { while(!(SPSR & (1 << SPIF))) ; cc1000_state(); } mos_enable_ints(int_handle);#endif if(cc1000_com_mode == IF_LISTEN) { SPCR |= (1 << SPIE); cc1000_mode(CC1000_MODE_RX); }}/** @brief Sets mode for this driver. * @param md Mode * @return New mode set*/void com_mode_IFACE_RADIO (uint8_t md){ switch (md) { case IF_OFF: SPCR &= ~((1 << SPIE)); //disable spi interrupt cc1000_mode (CC1000_MODE_PD); cc1000_com_mode = md; //TODO: could turn off radio here break; case IF_STANDBY: break; case IF_IDLE: break; case IF_LISTEN: cc1000_state = state_recv_idle; // Start recving in the idle state cc1000_com_mode = md; cc1000_mode (CC1000_MODE_RX); SPCR |= (1 << SPIE); //turn on spi interrupt //TODO: might have to turn on radio here (see above) break; }}/** @brief Generic io control for this driver. * @param request i/o request * @param ap Arguements * @return Always returns 0*/void com_ioctl_IFACE_RADIO (uint8_t request, ...){ int arg; uint8_t new_freq; va_list ap; va_start (ap, request); switch (request) { case CC1000_TX_POWER: // Adjust transmit power arg = va_arg (ap, int); cc1000_set_power (arg); break; case CC1000_GET_TX_POWER: { uint8_t* argp = va_arg (ap, uint8_t*); *argp = cc1000_get_power(); break; } case CC1000_FREQ: //set frequency new_freq = va_arg (ap, int); cc1000_change_freq(new_freq); break; case CC1000_RSSI: // Get the received signal strength // TODO: Get signal strength from dev layer, not as an ioctl break; } va_end (ap);}void cc1000_default_init (void){ uint8_t int_handle; int_handle = mos_disable_ints(); //get initial receive buffer com_swap_bufs(IFACE_RADIO, NULL, &cc1000_recv_buf);#ifdef GET_RSSI cc1000_recv_buf->signal = 0;#endif#ifdef TS_PACKET cc1000_recv_buf->ts = 0;#endif #ifdef INTERRUPT_DRIVEN_SEND mos_sem_init(&cc1000_sem, 0);#endif //init radio cc1000_init(FREQ); //now init the SPI bus DDRB &= ~((1 << DDB0) | (1 << DDB1)); // clock pin to input SPCR &= ~((1 << CPOL) | (1 << CPHA)); // Set proper polarity and phase DDRB |= (1 << DDB3); //miso to output DDRB &= ~((1 << DDB0) | (1 << DDB2)); //mosi to input cc1000_mode(CC1000_MODE_RX); //go to recv mode SPCR &= ~(1 << SPIE); //disable SPI interrupt SPCR |= (1 << SPE); cc1000_state = state_recv_idle; //initially in off mode cc1000_com_mode = IF_OFF; mos_enable_ints(int_handle);}static void state_send_pre(void){ SPDR = PREAMBLE_BYTE; preamble_count++; if(preamble_count == PREAMBLE_LEN) cc1000_state = state_send_sync;}static void state_send_sync(void){ SPDR = 0x33; //send sync byte cc1000_state = state_send_size; data_count = 0;}static void state_send_size(void){ SPDR = cc1000_send_buf->size; #ifdef RADIO_REDUNDANT_SIZE // Send redundant size bytes if (data_count++ < 2) return; #endif data_count = 0;#ifdef RADIO_USE_FEC //cc1000_state = STATE_SEND_SIZE_FEC; cc1000_state = state_send_data;#else cc1000_state = state_send_data;#endif }static void state_send_data(void){ SPDR = cc1000_send_buf->data[data_count++]; if(data_count == cc1000_send_buf->size) { //done with data data_count = 0;#ifdef RADIO_USE_FEC cc1000_state = state_send_data_fec;#else cc1000_state = state_send_crc_h;#endif }}#ifdef RADIO_USE_FECstatic void state_send_data_fec(void){ SPDR = data_fec[data_count++]; if(data_count == FEC_DATA_PARITY_COUNT) cc1000_state = state_send_flush;}#endifstatic void state_send_crc_h(void){ SPDR = cc1000_crc_high; cc1000_state = state_send_crc_l;}static void state_send_crc_l(void){ SPDR = cc1000_crc_low; cc1000_state = state_send_flush;}static void state_send_flush(void){ SPDR = FLUSH_BYTE; cc1000_state = state_send_done;}static void state_send_done(void){ //go back to recv mode cc1000_state = state_recv_idle;#ifdef INTERRUPT_DRIVEN_SEND mos_sem_post(&cc1000_sem);#endif}#ifdef RADIO_USE_FECstatic void state_recv_data_fec(void){ spi_data = SPDR; data_fec[data_count++] = (prev_data << offset) | (spi_data >> (8 - offset)); if(data_count == FEC_DATA_PARITY_COUNT) { cc1000_state = state_recv_idle; com_swap_bufs(IFACE_RADIO, cc1000_recv_buf, &cc1000_recv_buf); } prev_data = spi_data;}#endifstatic void state_recv_crc_l(void){ //read low byte and assemble full crc spi_data = SPDR; cc1000_crc_low = (prev_data << offset) | (spi_data >> (8 - offset)); //if crc checks out, swap buffer up to com layer if(crc_compute(cc1000_recv_buf->data, cc1000_recv_buf->size) == ((((uint16_t) cc1000_crc_high) << 8) | cc1000_crc_low)) { //cc1000_state = state_recv_idle; com_swap_bufs(IFACE_RADIO, cc1000_recv_buf, &cc1000_recv_buf); cc1000_success_count++; } else { //if it's bad, record the error //mos_led_toggle(2); cc1000_crc_error_count++; } //either way, we're done and back in idle mode cc1000_state = state_recv_idle;}static void state_recv_crc_h(void){ spi_data = SPDR; cc1000_crc_high = (prev_data << offset) | (spi_data >> (8 - offset)); //ready to recv low byte cc1000_state = state_recv_crc_l; prev_data = spi_data;}static void state_recv_data(void){ spi_data = SPDR; actual_byte = (prev_data << offset) | (spi_data >> (8 - offset)); cc1000_recv_buf->data[data_count++] = actual_byte; if (data_count == cc1000_recv_buf->size) {#ifdef RADIO_USE_FEC data_count = 0; cc1000_state = state_recv_data_fec;#else cc1000_state = state_recv_crc_h;#endif } prev_data = spi_data;}static void state_recv_size(void){ spi_data = SPDR; actual_byte = (prev_data << offset) | (spi_data >> (8 - offset));#ifdef RADIO_REDUNDANT_SIZE // Received redundant size bytes size_bytes[data_count] = actual_byte; if (data_count++ < 2) return; // Majority rules actual_byte = (size_bytes[0] & size_bytes[1]) | (size_bytes[0] & size_bytes[2]) | (size_bytes[1] & size_bytes[2]);#endif if (actual_byte > COM_DATA_SIZE || actual_byte == 0) { cc1000_size_error_count++; cc1000_state = state_recv_idle; return; } else { if (!cc1000_recv_buf) { com_swap_bufs (IFACE_RADIO, NULL, &cc1000_recv_buf); if (!cc1000_recv_buf) { cc1000_mem_error_count++; cc1000_state = state_recv_idle; return; } } } data_count = 0; cc1000_recv_buf->size = actual_byte; cc1000_state = state_recv_data; prev_data = spi_data;}static void state_recv_sync(void){ spi_data = SPDR; // Figure out the bit offset by shifting until we find the sync byte while (prev_data != 0x33) { prev_data = (prev_data << 1) | (spi_data >> (7 - offset)); offset++; if (offset >= 8) { //didn't get the sync byte... Something is wrong cc1000_sync_error_count++; cc1000_state = state_recv_idle; return; } } // We are synced and ready to start getting the packet cc1000_state = state_recv_size; prev_data = spi_data; data_count = 0;}static void state_recv_pre(void){ spi_data = SPDR; if (spi_data != PREAMBLE_BYTE && spi_data != 0x55) { // not in preamble anymore if (preamble_count > PREAMBLE_THRESH) { // reached end of preamble cc1000_state = state_recv_sync; offset = 0; } else { // looking at noise cc1000_state = state_recv_idle;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -