/*************************************************************************** * Copyright (C) 11/2014 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License, * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include "target.h" #include "rfm12_hw.h" #include "rfm12.h" /* *********************************************************************** */ #define RFM12_PREAMBLE 0xAA #define RFM12_SYNC_LSB 0xD4 #define RFM12_SYNC_MSB 0x2D #define RFM12_BASEBAND RFM12_BAND_868 #define RFM12_XTAL_LOAD RFM12_XTAL_11_5PF #define RFM12_FREQUENCY_CALC RFM12_FREQUENCY_CALC_868 #define RFM12_FREQUENCY 869800000UL #define RFM12_DATARATE RFM12_DATARATE_CALC_HIGH(19200.0) #define RFM12_FILTER_BW RFM12_RXCTRL_BW_400 #define RFM12_LNA_GAIN RFM12_RXCTRL_LNA_6 #define RFM12_RSSI_THRESHOLD RFM12_RXCTRL_RSSI_79 #define RFM12_POWER RFM12_TXCONF_POWER_0 #define RFM12_FSK_SHIFT 125000 /* *********************************************************************** */ #define RFM12_DATA_STATE_FREE 0x00 #define RFM12_DATA_STATE_USED 0x01 struct rfm12_data { uint8_t state; /* RFM12_DATA_STATE_* */ struct rfm12_packet packet; }; #define RFM12_CTX_STATE_INAVTIVE 0x00 #define RFM12_CTX_STATE_RX_IDLE 0x01 #define RFM12_CTX_STATE_RX_ACTIVE 0x02 #define RFM12_CTX_STATE_TX_ACTIVE 0x03 struct rfm12_context { uint8_t state; /* RFM12_CTX_STATE_* */ uint8_t ch_free_ticks; /* number of ticks channel is unused */ uint8_t own_address; uint8_t rx_idx_in; /* pkt receiving */ uint8_t rx_idx_out; /* pkt given to app */ uint8_t rx_checksum; /* receive checksum */ uint8_t rx_data_idx; /* byte position inside rx[].packet */ uint8_t tx_data_idx; /* byte position inside tx.packet */ struct rfm12_data rx[2]; struct rfm12_data tx; }; static struct rfm12_context rfm12_ctx; /* *********************************************************************** */ static uint16_t rfm12_data(uint16_t txdata) { uint16_t retval; RFM12_CS_ACTIVE(); SPDR = (txdata >> 8); while (!(SPSR & (1<= (RFM12_PKT_HEADER_SIZE + RFM12_PKT_MAX_DATA_SIZE)) { rfm12_reset_fifo = 1; break; } /* store data */ (& rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.sync[RFM12_PKT_SYNC_SIZE])[rfm12_ctx.rx_data_idx++] = data; /* calculate checksum */ rfm12_ctx.rx_checksum ^= data; /* check if header address, data_length and checksum are ok */ if ((rfm12_ctx.rx_data_idx == RFM12_PKT_HEADER_SIZE) && ((rfm12_ctx.rx_checksum != 0xFF) || (rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.dest_address != rfm12_ctx.own_address) || (rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.source_address == rfm12_ctx.own_address) || (rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.data_length > RFM12_PKT_MAX_DATA_SIZE) )) { rfm12_reset_fifo = 1; break; } /* packet complete? */ if (rfm12_ctx.rx_data_idx == (RFM12_PKT_HEADER_SIZE + rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.data_length)) { /* mark buffer as full */ rfm12_ctx.rx[rfm12_ctx.rx_idx_in].state = RFM12_DATA_STATE_USED; /* switch to other buffer */ rfm12_ctx.rx_idx_in ^= 1; /* receiving is complete, reset fifo anyway */ rfm12_reset_fifo = 1; } break; case RFM12_CTX_STATE_TX_ACTIVE: /* send one additional byte! (<= not <) */ if (rfm12_ctx.tx_data_idx <= (RFM12_PKT_SYNC_SIZE + RFM12_PKT_HEADER_SIZE + rfm12_ctx.tx.packet.data_length)) { rfm12_data(RFM12_CMD_TX | rfm12_ctx.tx.packet.sync[rfm12_ctx.tx_data_idx++]); } else { /* enable RX */ rfm12_data(RFM12_CMD_PWRMGT | RFM12_PWRMGT_ER | RFM12_PWRMGT_DC); /* TX dummy byte to clear interrupt */ rfm12_data(RFM12_CMD_TX | RFM12_PREAMBLE); /* mark buffer as empty */ rfm12_ctx.tx.state = RFM12_DATA_STATE_FREE; /* transmit is complete, reset fifo */ rfm12_reset_fifo = 1; } break; default: rfm12_reset_fifo = 1; break; } if (rfm12_reset_fifo) { /* flush fifo and wait for sync pattern */ rfm12_data(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4)); rfm12_data(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4) | RFM12_FIFORESET_FF); /* wait for RX data */ rfm12_ctx.state = RFM12_CTX_STATE_RX_IDLE; } } /* enable interrupt again */ RFM12_INT_ON(); } /* INT1_vect */ void rfm12_tick(uint8_t channel_free_time) { uint16_t status; /* receiver not idle, come back later */ if (rfm12_ctx.state != RFM12_CTX_STATE_RX_IDLE) { return; } RFM12_INT_OFF(); status = rfm12_data(RFM12_CMD_STATUS); RFM12_INT_ON(); /* check if module receives a carrier */ if (status & RFM12_STATUS_RSSI) { rfm12_ctx.ch_free_ticks = 0; return; } else if (rfm12_ctx.ch_free_ticks <= channel_free_time) { rfm12_ctx.ch_free_ticks++; return; } if (rfm12_ctx.tx.state == RFM12_DATA_STATE_USED) { RFM12_INT_OFF(); /* disable receiver */ rfm12_data(RFM12_CMD_PWRMGT | RFM12_PWRMGT_DC); /* put preamble in fifo */ rfm12_data(RFM12_CMD_TX | RFM12_PREAMBLE); rfm12_data(RFM12_CMD_TX | RFM12_PREAMBLE); /* start TX */ rfm12_data(RFM12_CMD_PWRMGT | RFM12_PWRMGT_ET | RFM12_PWRMGT_DC); /* change state */ rfm12_ctx.state = RFM12_CTX_STATE_TX_ACTIVE; rfm12_ctx.tx_data_idx = 0; RFM12_INT_ON(); } } /* rfm12_tick */ static uint16_t rfm12_calc_crc(const struct rfm12_packet *pkt) { uint16_t crc = 0x0000; uint8_t i; const uint8_t *tmp = pkt->data; for (i = 0; i < pkt->data_length; i++) crc = _crc_ccitt_update(crc, *tmp++); return crc; } /* pkt_check_crc */ struct rfm12_packet * rfm12_get_txpkt(void) { if (rfm12_ctx.tx.state != RFM12_DATA_STATE_FREE) { return (void *)0; } return &rfm12_ctx.tx.packet; } /* rfm12_get_txpkt */ uint8_t rfm12_start_tx(void) { struct rfm12_packet *pkt = &rfm12_ctx.tx.packet; if ((rfm12_ctx.tx.state != RFM12_DATA_STATE_FREE) && (pkt->data_length > RFM12_PKT_MAX_DATA_SIZE) ) { return 0; } /* calculate data crc */ uint16_t *data_crc = (uint16_t *)(pkt->data + pkt->data_length); *data_crc = rfm12_calc_crc(pkt); pkt->data_length += 2; /* setup packet */ pkt->sync[0] = RFM12_SYNC_MSB; pkt->sync[1] = RFM12_SYNC_LSB; pkt->source_address = rfm12_ctx.own_address; pkt->header_checksum = pkt->dest_address ^ pkt->source_address ^ pkt->data_length ^ 0xFF; /* change state */ rfm12_ctx.tx.state = RFM12_DATA_STATE_USED; return 1; } /* rfm12_start_tx */ struct rfm12_packet * rfm12_get_rxpkt(void) { if (rfm12_ctx.rx[rfm12_ctx.rx_idx_out].state != RFM12_DATA_STATE_USED) { return (void *)0; } /* calculate data crc */ struct rfm12_packet *pkt = &rfm12_ctx.rx[rfm12_ctx.rx_idx_out].packet; pkt->data_length -= 2; uint16_t *data_crc = (uint16_t *)(pkt->data + pkt->data_length); if (*data_crc != rfm12_calc_crc(pkt)) { rfm12_clear_rx(); return (void *)0; } return pkt; } /* rfm12_get_rxpkt */ void rfm12_clear_rx(void) { /* mark buffer as empty */ rfm12_ctx.rx[rfm12_ctx.rx_idx_out].state = RFM12_DATA_STATE_FREE; /* switch to other buffer */ rfm12_ctx.rx_idx_out ^= 1; } /* rfm12_clear_rx */ static const uint16_t init_cmds[] PROGMEM = { /* set power default state (disable clock output) */ (RFM12_CMD_PWRMGT | RFM12_PWRMGT_DC), /* dummy write after power management change, prevent lockup of module */ (RFM12_CMD_TX), /* enable internal data register and fifo, setup selected band */ (RFM12_CMD_CFG | RFM12_CFG_EL | RFM12_CFG_EF | RFM12_BASEBAND | RFM12_XTAL_LOAD), /* set frequency */ (RFM12_CMD_FREQUENCY | RFM12_FREQUENCY_CALC(RFM12_FREQUENCY)), /* set data rate */ (RFM12_CMD_DATARATE | RFM12_DATARATE), /* set rx parameters: vdi-out, bandwidth, LNA, RSSI */ (RFM12_CMD_RXCTRL | RFM12_RXCTRL_P16_VDI | RFM12_RXCTRL_VDI_FAST | RFM12_FILTER_BW | RFM12_LNA_GAIN | RFM12_RSSI_THRESHOLD), /* automatic clock lock control, digital Filter, * Data quality detector value 3, slow clock recovery lock */ (RFM12_CMD_DATAFILTER | RFM12_DATAFILTER_AL | 3), /* 2 Byte Sync Pattern, Start fifo fill when sychron pattern received, * disable sensitive reset, Fifo filled interrupt at 8 bits */ (RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4)), /* set AFC to automatic, (+4 or -3)*2.5kHz Limit, fine mode, active and enabled */ (RFM12_CMD_AFC | RFM12_AFC_AUTO_KEEP | RFM12_AFC_LIMIT_4 | RFM12_AFC_FI | RFM12_AFC_OE | RFM12_AFC_EN), /* set TX Power, frequency shift */ (RFM12_CMD_TXCONF | RFM12_POWER | RFM12_TXCONF_FS_CALC(RFM12_FSK_SHIFT)), /* disable low dutycycle mode */ (RFM12_CMD_DUTYCYCLE), /* disable wakeup timer */ (RFM12_CMD_WAKEUP), /* enable rf receiver chain */ (RFM12_CMD_PWRMGT | RFM12_PWRMGT_ER | RFM12_PWRMGT_DC), /* flush fifo, start receiving */ (RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4)), (RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4) | RFM12_FIFORESET_FF), }; void rfm12_init(uint8_t own_address) { uint8_t i; /* init chipselect GPIO */ RFM12_CS_INIT(); RFM12_CS_INACTIVE(); /* init internal SPI */ RFM12_SPI_INIT(); /* send init commands */ for (i = 0; i < ( sizeof(init_cmds) / 2) ; i++) { rfm12_data(pgm_read_word(&init_cmds[i])); } /* store own address */ rfm12_ctx.own_address = own_address; rfm12_ctx.state = RFM12_CTX_STATE_RX_IDLE; /* initalize & activate interrupt */ RFM12_INT_INIT(); RFM12_INT_CLEAR(); RFM12_INT_ON(); } /* rfm12_init */