2012-02-29 05:30:06 +01:00
/**
2012-03-18 18:22:05 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ addtogroup PIOS PIOS Core hardware abstraction layer
* @ {
* @ addtogroup PIOS_RFM22B Radio Functions
* @ brief PIOS interface for for the RFM22B radio
* @ {
*
* @ file pios_rfm22b . c
* @ author The OpenPilot Team , http : //www.openpilot.org Copyright (C) 2012.
* @ brief Implements a driver the the RFM22B driver
* @ see The GNU Public License ( GPL ) Version 3
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-02-29 05:30:06 +01:00
/*
* 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 ; either version 3 of the License , or
* ( at your option ) any later version .
*
* 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
*/
2012-03-18 18:22:05 +01:00
// *****************************************************************
// RFM22B hardware layer
//
// This module uses the RFM22B's internal packet handling hardware to
// encapsulate our own packet data.
//
// The RFM22B internal hardware packet handler configuration is as follows ..
//
// 4-byte (32-bit) preamble .. alternating 0's & 1's
// 4-byte (32-bit) sync
// 1-byte packet length (number of data bytes to follow)
// 0 to 255 user data bytes
//
// Our own packet data will also contain it's own header and 32-bit CRC
// as a single 16-bit CRC is not sufficient for wireless comms.
//
// *****************************************************************
2012-02-29 05:30:06 +01:00
/* Project Includes */
# include "pios.h"
# if defined(PIOS_INCLUDE_RFM22B)
2012-08-25 04:25:02 +02:00
# include <pios_spi_priv.h>
2012-03-16 03:29:54 +01:00
# include <packet_handler.h>
# include <pios_rfm22b_priv.h>
2012-10-03 04:52:21 +02:00
# include <ecc.h>
2012-03-08 02:05:42 +01:00
2012-03-18 18:22:05 +01:00
/* Local Defines */
2012-09-12 05:34:26 +02:00
# define STACK_SIZE_BYTES 200
# define TASK_PRIORITY (tskIDLE_PRIORITY + 2)
# define ISR_TIMEOUT 5 // ms
2012-09-17 04:33:30 +02:00
# define EVENT_QUEUE_SIZE 5
# define PACKET_QUEUE_SIZE 3
2012-02-29 05:30:06 +01:00
2012-10-03 04:52:21 +02:00
// The maximum amount of time without activity before initiating a reset.
2012-09-15 04:30:02 +02:00
# define PIOS_RFM22B_SUPERVISOR_TIMEOUT 100 // ms
2012-04-22 03:31:49 +02:00
2012-10-03 04:52:21 +02:00
// The time between updates over the radio link.
# define RADIOSTATS_UPDATE_PERIOD_MS 250
2012-03-18 18:22:05 +01:00
// this is too adjust the RF module so that it is on frequency
# define OSC_LOAD_CAP 0x7F // cap = 12.5pf .. default
# define OSC_LOAD_CAP_1 0x7D // board 1
# define OSC_LOAD_CAP_2 0x7B // board 2
# define OSC_LOAD_CAP_3 0x7E // board 3
# define OSC_LOAD_CAP_4 0x7F // board 4
2012-03-16 03:29:54 +01:00
2012-03-18 18:22:05 +01:00
// ************************************
2012-02-29 05:30:06 +01:00
2012-03-18 18:22:05 +01:00
# define TX_PREAMBLE_NIBBLES 12 // 7 to 511 (number of nibbles)
# define RX_PREAMBLE_NIBBLES 6 // 5 to 31 (number of nibbles)
2012-04-06 05:24:50 +02:00
// the size of the rf modules internal FIFO buffers
# define FIFO_SIZE 64
2012-03-18 18:22:05 +01:00
# define TX_FIFO_HI_WATERMARK 62 // 0-63
# define TX_FIFO_LO_WATERMARK 32 // 0-63
# define RX_FIFO_HI_WATERMARK 32 // 0-63
# define PREAMBLE_BYTE 0x55 // preamble byte (preceeds SYNC_BYTE's)
# define SYNC_BYTE_1 0x2D // RF sync bytes (32-bit in all)
# define SYNC_BYTE_2 0xD4 //
# define SYNC_BYTE_3 0x4B //
# define SYNC_BYTE_4 0x59 //
2012-08-25 04:25:02 +02:00
# ifndef RX_LED_ON
# define RX_LED_ON
# define RX_LED_OFF
# define TX_LED_ON
# define TX_LED_OFF
# define LINK_LED_ON
# define LINK_LED_OFF
# define USB_LED_ON
# define USB_LED_OFF
# endif
2012-03-18 18:22:05 +01:00
// ************************************
// Normal data streaming
// GFSK modulation
// no manchester encoding
// data whitening
// FIFO mode
// 5-nibble rx preamble length detection
// 10-nibble tx preamble length
// AFC enabled
/* Local type definitions */
2012-02-29 05:30:06 +01:00
enum pios_rfm22b_dev_magic {
PIOS_RFM22B_DEV_MAGIC = 0x68e971b6 ,
} ;
2012-09-15 04:30:02 +02:00
enum pios_rfm22b_state {
2012-09-17 04:33:30 +02:00
RFM22B_STATE_UNINITIALIZED ,
2012-09-15 04:30:02 +02:00
RFM22B_STATE_INITIALIZING ,
2012-09-17 04:33:30 +02:00
RFM22B_STATE_RX_MODE ,
RFM22B_STATE_WAIT_PREAMBLE ,
RFM22B_STATE_WAIT_SYNC ,
2012-09-15 04:30:02 +02:00
RFM22B_STATE_RX_DATA ,
RFM22B_STATE_TX_START ,
RFM22B_STATE_TX_DATA ,
2012-09-25 05:51:34 +02:00
RFM22B_STATE_TIMEOUT ,
RFM22B_STATE_ERROR ,
2012-09-17 04:33:30 +02:00
RFM22B_STATE_FATAL_ERROR ,
RFM22B_STATE_NUM_STATES // Must be last
2012-09-15 04:30:02 +02:00
} ;
enum pios_rfm22b_event {
2012-09-17 04:33:30 +02:00
RFM22B_EVENT_INITIALIZE ,
2012-09-23 05:07:50 +02:00
RFM22B_EVENT_INITIALIZED ,
2012-09-17 04:33:30 +02:00
RFM22B_EVENT_INT_RECEIVED ,
RFM22B_EVENT_RX_MODE ,
RFM22B_EVENT_PREAMBLE_DETECTED ,
RFM22B_EVENT_SYNC_DETECTED ,
RFM22B_EVENT_RX_COMPLETE ,
RFM22B_EVENT_SEND_PACKET ,
RFM22B_EVENT_TX_START ,
2012-09-23 05:07:50 +02:00
RFM22B_EVENT_TX_STARTED ,
2012-09-17 04:33:30 +02:00
RFM22B_EVENT_TX_COMPLETE ,
2012-09-23 05:07:50 +02:00
RFM22B_EVENT_TIMEOUT ,
2012-09-17 04:33:30 +02:00
RFM22B_EVENT_ERROR ,
RFM22B_EVENT_FATAL_ERROR ,
RFM22B_EVENT_NUM_EVENTS // Must be last
2012-09-15 04:30:02 +02:00
} ;
2012-02-29 05:30:06 +01:00
struct pios_rfm22b_dev {
enum pios_rfm22b_dev_magic magic ;
2012-05-07 05:47:21 +02:00
struct pios_rfm22b_cfg cfg ;
2012-02-29 05:30:06 +01:00
2012-09-05 07:25:06 +02:00
uint32_t spi_id ;
uint32_t slave_num ;
2012-04-11 05:22:53 +02:00
uint32_t deviceID ;
2012-02-29 05:30:06 +01:00
2012-09-12 05:34:26 +02:00
// The task handle
xTaskHandle taskHandle ;
2012-08-26 09:41:19 +02:00
// ISR pending
xSemaphoreHandle isrPending ;
2012-09-23 17:36:38 +02:00
// Receive packet complete
xSemaphoreHandle rxsem ;
2012-04-11 05:22:53 +02:00
// The COM callback functions.
2012-02-29 05:30:06 +01:00
pios_com_callback rx_in_cb ;
uint32_t rx_in_context ;
pios_com_callback tx_out_cb ;
uint32_t tx_out_context ;
2012-04-22 03:31:49 +02:00
2012-09-13 03:24:19 +02:00
// the transmit power to use for data transmissions
uint8_t tx_power ;
2012-09-15 04:30:02 +02:00
// The state machine state and the current event
enum pios_rfm22b_state state ;
2012-09-17 04:33:30 +02:00
// The event queue handle
xQueueHandle eventQueue ;
// device status register
uint8_t device_status ;
// interrupt status register 1
uint8_t int_status1 ;
// interrupt status register 2
uint8_t int_status2 ;
// ezmac status register
uint8_t ezmac_status ;
2012-09-15 04:30:02 +02:00
2012-09-12 05:34:26 +02:00
// Stats
2012-09-15 04:30:02 +02:00
uint16_t resets ;
uint32_t errors ;
uint32_t irqs_processed ;
2012-09-17 04:33:30 +02:00
// the current RSSI (register value)
uint8_t rssi ;
// RSSI in dBm
int8_t rssi_dBm ;
// The packet queue handle
xQueueHandle packetQueue ;
2012-09-23 05:07:50 +02:00
// The current tx packet
PHPacketHandle tx_packet ;
// the tx data read index
uint16_t tx_data_rd ;
// the tx data write index
uint16_t tx_data_wr ;
2012-09-23 17:36:38 +02:00
// The current rx packet
PHPacketHandle rx_packet ;
// The previous rx packet
PHPacketHandle rx_packet_prev ;
// The next rx packet
PHPacketHandle rx_packet_next ;
// the receive buffer write index
uint16_t rx_buffer_wr ;
// the receive buffer write index
uint16_t rx_packet_len ;
2012-09-23 05:07:50 +02:00
// The frequency hopping step size
float frequency_step_size ;
// current frequency hop channel
uint8_t frequency_hop_channel ;
// the frequency hop step size
uint8_t frequency_hop_step_size_reg ;
// afc correction reading (in Hz)
int32_t afc_correction_Hz ;
int8_t rx_packet_start_afc_Hz ;
2012-09-25 05:51:34 +02:00
2012-10-03 04:52:21 +02:00
// The status packet
PHStatusPacket status_packet ;
2012-09-25 05:51:34 +02:00
// The maximum time (ms) that it should take to transmit / receive a packet.
uint32_t max_packet_time ;
2012-10-03 04:52:21 +02:00
portTickType packet_start_ticks ;
2012-09-17 04:33:30 +02:00
} ;
struct pios_rfm22b_transition {
enum pios_rfm22b_event ( * entry_fn ) ( struct pios_rfm22b_dev * rfm22b_dev ) ;
enum pios_rfm22b_state next_state [ RFM22B_EVENT_NUM_EVENTS ] ;
2012-02-29 05:30:06 +01:00
} ;
2012-09-02 20:31:09 +02:00
// Must ensure these prefilled arrays match the define sizes
static const uint8_t FULL_PREAMBLE [ FIFO_SIZE ] =
{ PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE ,
PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE } ; // 64 bytes
static const uint8_t HEADER [ ( TX_PREAMBLE_NIBBLES + 1 ) / 2 + 2 ] = { PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , PREAMBLE_BYTE , SYNC_BYTE_1 , SYNC_BYTE_2 } ;
2012-09-05 07:56:48 +02:00
static const uint8_t OUT_FF [ 64 ] = { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
2012-09-02 20:31:09 +02:00
2012-03-18 18:22:05 +01:00
/* Local function forwared declarations */
2012-09-12 05:34:26 +02:00
static void PIOS_RFM22B_Task ( void * parameters ) ;
2012-09-15 04:30:02 +02:00
static void PIOS_RFM22B_InjectEvent ( struct pios_rfm22b_dev * rfm22b_dev , enum pios_rfm22b_event event , bool inISR ) ;
2012-09-17 04:33:30 +02:00
static bool rfm22_readStatus ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_setRxMode ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_detectPreamble ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_detectSync ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_rxData ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_init ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_txStart ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_txData ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_process_state_transition ( struct pios_rfm22b_dev * rfm22b_dev , enum pios_rfm22b_event event ) ;
2012-09-25 05:51:34 +02:00
static enum pios_rfm22b_event rfm22_timeout ( struct pios_rfm22b_dev * rfm22b_dev ) ;
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_error ( struct pios_rfm22b_dev * rfm22b_dev ) ;
static enum pios_rfm22b_event rfm22_fatal_error ( struct pios_rfm22b_dev * rfm22b_dev ) ;
2012-10-03 04:52:21 +02:00
static bool rfm22_sendStatus ( struct pios_rfm22b_dev * rfm22b_dev ) ;
2012-04-06 05:24:50 +02:00
// SPI read/write functions
2012-09-17 04:33:30 +02:00
static void rfm22_assertCs ( ) ;
static void rfm22_deassertCs ( ) ;
static void rfm22_claimBus ( ) ;
static void rfm22_releaseBus ( ) ;
2012-09-05 07:25:06 +02:00
static void rfm22_write ( uint8_t addr , uint8_t data ) ;
static uint8_t rfm22_read ( uint8_t addr ) ;
2012-09-17 04:33:30 +02:00
static uint8_t rfm22_read_noclaim ( uint8_t addr ) ;
2012-03-18 18:22:05 +01:00
/* Provide a COM driver */
static void PIOS_RFM22B_ChangeBaud ( uint32_t rfm22b_id , uint32_t baud ) ;
static void PIOS_RFM22B_RegisterRxCallback ( uint32_t rfm22b_id , pios_com_callback rx_in_cb , uint32_t context ) ;
static void PIOS_RFM22B_RegisterTxCallback ( uint32_t rfm22b_id , pios_com_callback tx_out_cb , uint32_t context ) ;
static void PIOS_RFM22B_TxStart ( uint32_t rfm22b_id , uint16_t tx_bytes_avail ) ;
static void PIOS_RFM22B_RxStart ( uint32_t rfm22b_id , uint16_t rx_bytes_avail ) ;
/* Local variables */
const struct pios_com_driver pios_rfm22b_com_driver = {
. set_baud = PIOS_RFM22B_ChangeBaud ,
. tx_start = PIOS_RFM22B_TxStart ,
. rx_start = PIOS_RFM22B_RxStart ,
. bind_tx_cb = PIOS_RFM22B_RegisterTxCallback ,
. bind_rx_cb = PIOS_RFM22B_RegisterRxCallback ,
} ;
2012-09-17 04:33:30 +02:00
/* Te state transition table */
const static struct pios_rfm22b_transition rfm22b_transitions [ RFM22B_STATE_NUM_STATES ] = {
[ RFM22B_STATE_UNINITIALIZED ] = {
. entry_fn = 0 ,
. next_state = {
[ RFM22B_EVENT_INITIALIZE ] = RFM22B_STATE_INITIALIZING ,
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
} ,
} ,
[ RFM22B_STATE_INITIALIZING ] = {
. entry_fn = rfm22_init ,
. next_state = {
2012-09-23 05:07:50 +02:00
[ RFM22B_EVENT_INITIALIZED ] = RFM22B_STATE_TX_START ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_RX_MODE ] = {
. entry_fn = rfm22_setRxMode ,
. next_state = {
[ RFM22B_EVENT_INT_RECEIVED ] = RFM22B_STATE_WAIT_PREAMBLE ,
2012-09-23 05:07:50 +02:00
[ RFM22B_EVENT_SEND_PACKET ] = RFM22B_STATE_TX_START ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_TX_START ] = RFM22B_STATE_TX_START ,
2012-09-25 05:51:34 +02:00
[ RFM22B_EVENT_TIMEOUT ] = RFM22B_STATE_TIMEOUT ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_WAIT_PREAMBLE ] = {
. entry_fn = rfm22_detectPreamble ,
. next_state = {
[ RFM22B_EVENT_INT_RECEIVED ] = RFM22B_STATE_WAIT_PREAMBLE ,
[ RFM22B_EVENT_PREAMBLE_DETECTED ] = RFM22B_STATE_WAIT_SYNC ,
2012-09-23 05:07:50 +02:00
[ RFM22B_EVENT_SEND_PACKET ] = RFM22B_STATE_TX_START ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_TX_START ] = RFM22B_STATE_TX_START ,
2012-09-25 05:51:34 +02:00
[ RFM22B_EVENT_TIMEOUT ] = RFM22B_STATE_TIMEOUT ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_WAIT_SYNC ] = {
. entry_fn = rfm22_detectSync ,
. next_state = {
[ RFM22B_EVENT_INT_RECEIVED ] = RFM22B_STATE_WAIT_SYNC ,
[ RFM22B_EVENT_SYNC_DETECTED ] = RFM22B_STATE_RX_DATA ,
[ RFM22B_EVENT_TX_START ] = RFM22B_STATE_TX_START ,
2012-09-25 05:51:34 +02:00
[ RFM22B_EVENT_TIMEOUT ] = RFM22B_STATE_TIMEOUT ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_RX_DATA ] = {
. entry_fn = rfm22_rxData ,
. next_state = {
[ RFM22B_EVENT_INT_RECEIVED ] = RFM22B_STATE_RX_DATA ,
[ RFM22B_EVENT_RX_COMPLETE ] = RFM22B_STATE_TX_START ,
2012-09-25 05:51:34 +02:00
[ RFM22B_EVENT_TIMEOUT ] = RFM22B_STATE_TIMEOUT ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_TX_START ] = {
. entry_fn = rfm22_txStart ,
. next_state = {
[ RFM22B_EVENT_INT_RECEIVED ] = RFM22B_STATE_TX_DATA ,
[ RFM22B_EVENT_RX_MODE ] = RFM22B_STATE_RX_MODE ,
2012-09-25 05:51:34 +02:00
[ RFM22B_EVENT_TIMEOUT ] = RFM22B_STATE_TIMEOUT ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_TX_DATA ] = {
. entry_fn = rfm22_txData ,
. next_state = {
[ RFM22B_EVENT_INT_RECEIVED ] = RFM22B_STATE_TX_DATA ,
[ RFM22B_EVENT_TX_COMPLETE ] = RFM22B_STATE_TX_START ,
2012-09-25 05:51:34 +02:00
[ RFM22B_EVENT_TIMEOUT ] = RFM22B_STATE_TIMEOUT ,
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_TIMEOUT ] = {
. entry_fn = rfm22_timeout ,
. next_state = {
[ RFM22B_EVENT_TX_START ] = RFM22B_STATE_TX_START ,
[ RFM22B_EVENT_INITIALIZE ] = RFM22B_STATE_INITIALIZING ,
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_ERROR ] = {
. entry_fn = rfm22_error ,
. next_state = {
[ RFM22B_EVENT_INITIALIZE ] = RFM22B_STATE_INITIALIZING ,
2012-09-17 04:33:30 +02:00
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
[ RFM22B_STATE_FATAL_ERROR ] = {
. entry_fn = rfm22_fatal_error ,
. next_state = {
[ RFM22B_EVENT_ERROR ] = RFM22B_STATE_ERROR ,
[ RFM22B_EVENT_FATAL_ERROR ] = RFM22B_STATE_FATAL_ERROR ,
} ,
} ,
} ;
2012-03-18 18:22:05 +01:00
// xtal 10 ppm, 434MHz
2012-04-06 05:24:50 +02:00
# define LOOKUP_SIZE 14
2012-09-23 05:07:50 +02:00
static const uint32_t data_rate [ ] = { 500 , 1000 , 2000 , 4000 , 8000 , 9600 , 16000 , 19200 , 24000 , 32000 , 64000 , 128000 , 192000 , 256000 } ;
static const uint8_t modulation_index [ ] = { 16 , 8 , 4 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 } ;
static const uint32_t freq_deviation [ ] = { 4000 , 4000 , 4000 , 4000 , 4000 , 4800 , 8000 , 9600 , 12000 , 16000 , 32000 , 64000 , 96000 , 128000 } ;
static const uint32_t rx_bandwidth [ ] = { 17500 , 17500 , 17500 , 17500 , 17500 , 19400 , 32200 , 38600 , 51200 , 64100 , 137900 , 269300 , 420200 , 518800 } ;
static const int8_t est_rx_sens_dBm [ ] = { - 118 , - 118 , - 117 , - 116 , - 115 , - 115 , - 112 , - 112 , - 110 , - 109 , - 106 , - 103 , - 101 , - 100 } ; // estimated receiver sensitivity for BER = 1E-3
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t reg_1C [ ] = { 0x37 , 0x37 , 0x37 , 0x37 , 0x3A , 0x3B , 0x26 , 0x28 , 0x2E , 0x16 , 0x07 , 0x83 , 0x8A , 0x8C } ; // rfm22_if_filter_bandwidth
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t reg_1D [ ] = { 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 , 0x44 } ; // rfm22_afc_loop_gearshift_override
static const uint8_t reg_1E [ ] = { 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x0A , 0x02 } ; // rfm22_afc_timing_control
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t reg_1F [ ] = { 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 } ; // rfm22_clk_recovery_gearshift_override
static const uint8_t reg_20 [ ] = { 0xE8 , 0xF4 , 0xFA , 0x70 , 0x3F , 0x34 , 0x3F , 0x34 , 0x2A , 0x3F , 0x3F , 0x5E , 0x3F , 0x2F } ; // rfm22_clk_recovery_oversampling_ratio
static const uint8_t reg_21 [ ] = { 0x60 , 0x20 , 0x00 , 0x01 , 0x02 , 0x02 , 0x02 , 0x02 , 0x03 , 0x02 , 0x02 , 0x01 , 0x02 , 0x02 } ; // rfm22_clk_recovery_offset2
static const uint8_t reg_22 [ ] = { 0x20 , 0x41 , 0x83 , 0x06 , 0x0C , 0x75 , 0x0C , 0x75 , 0x12 , 0x0C , 0x0C , 0x5D , 0x0C , 0xBB } ; // rfm22_clk_recovery_offset1
static const uint8_t reg_23 [ ] = { 0xC5 , 0x89 , 0x12 , 0x25 , 0x4A , 0x25 , 0x4A , 0x25 , 0x6F , 0x4A , 0x4A , 0x86 , 0x4A , 0x0D } ; // rfm22_clk_recovery_offset0
static const uint8_t reg_24 [ ] = { 0x00 , 0x00 , 0x00 , 0x02 , 0x07 , 0x07 , 0x07 , 0x07 , 0x07 , 0x07 , 0x07 , 0x05 , 0x07 , 0x07 } ; // rfm22_clk_recovery_timing_loop_gain1
static const uint8_t reg_25 [ ] = { 0x0A , 0x23 , 0x85 , 0x0E , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x74 , 0xFF , 0xFF } ; // rfm22_clk_recovery_timing_loop_gain0
2012-03-18 18:22:05 +01:00
2012-09-30 17:04:36 +02:00
static const uint8_t reg_2A [ ] = { 0x0E , 0x0E , 0x0E , 0x0E , 0x0E , 0x0D , 0x0D , 0x0E , 0x12 , 0x17 , 0x31 , 0x50 , 0x50 , 0x50 } ; // rfm22_afc_limiter .. AFC_pull_in_range = <20> AFCLimiter[7:0] x (hbsel+1) x 625 Hz
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t reg_6E [ ] = { 0x04 , 0x08 , 0x10 , 0x20 , 0x41 , 0x4E , 0x83 , 0x9D , 0xC4 , 0x08 , 0x10 , 0x20 , 0x31 , 0x41 } ; // rfm22_tx_data_rate1
static const uint8_t reg_6F [ ] = { 0x19 , 0x31 , 0x62 , 0xC5 , 0x89 , 0xA5 , 0x12 , 0x49 , 0x9C , 0x31 , 0x62 , 0xC5 , 0x27 , 0x89 } ; // rfm22_tx_data_rate0
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t reg_70 [ ] = { 0x2D , 0x2D , 0x2D , 0x2D , 0x2D , 0x2D , 0x2D , 0x2D , 0x2D , 0x0D , 0x0D , 0x0D , 0x0D , 0x0D } ; // rfm22_modulation_mode_control1
static const uint8_t reg_71 [ ] = { 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 , 0x23 } ; // rfm22_modulation_mode_control2
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t reg_72 [ ] = { 0x06 , 0x06 , 0x06 , 0x06 , 0x06 , 0x08 , 0x0D , 0x0F , 0x13 , 0x1A , 0x33 , 0x66 , 0x9A , 0xCD } ; // rfm22_frequency_deviation
2012-03-18 18:22:05 +01:00
// ************************************
// Scan Spectrum settings
// GFSK modulation
// no manchester encoding
// data whitening
// FIFO mode
// 5-nibble rx preamble length detection
// 10-nibble tx preamble length
# define SS_LOOKUP_SIZE 2
// xtal 1 ppm, 434MHz
2012-09-23 05:07:50 +02:00
static const uint32_t ss_rx_bandwidth [ ] = { 2600 , 10600 } ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t ss_reg_1C [ ] = { 0x51 , 0x32 } ; // rfm22_if_filter_bandwidth
static const uint8_t ss_reg_1D [ ] = { 0x00 , 0x00 } ; // rfm22_afc_loop_gearshift_override
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t ss_reg_20 [ ] = { 0xE8 , 0x38 } ; // rfm22_clk_recovery_oversampling_ratio
static const uint8_t ss_reg_21 [ ] = { 0x60 , 0x02 } ; // rfm22_clk_recovery_offset2
static const uint8_t ss_reg_22 [ ] = { 0x20 , 0x4D } ; // rfm22_clk_recovery_offset1
static const uint8_t ss_reg_23 [ ] = { 0xC5 , 0xD3 } ; // rfm22_clk_recovery_offset0
static const uint8_t ss_reg_24 [ ] = { 0x00 , 0x07 } ; // rfm22_clk_recovery_timing_loop_gain1
static const uint8_t ss_reg_25 [ ] = { 0x0F , 0xFF } ; // rfm22_clk_recovery_timing_loop_gain0
2012-03-18 18:22:05 +01:00
2012-09-30 17:04:36 +02:00
static const uint8_t ss_reg_2A [ ] = { 0xFF , 0xFF } ; // rfm22_afc_limiter .. AFC_pull_in_range = <20> AFCLimiter[7:0] x (hbsel+1) x 625 Hz
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
static const uint8_t ss_reg_70 [ ] = { 0x24 , 0x2D } ; // rfm22_modulation_mode_control1
static const uint8_t ss_reg_71 [ ] = { 0x2B , 0x23 } ; // rfm22_modulation_mode_control2
2012-04-06 05:24:50 +02:00
2012-03-18 18:22:05 +01:00
2012-02-29 05:30:06 +01:00
static bool PIOS_RFM22B_validate ( struct pios_rfm22b_dev * rfm22b_dev )
{
2012-09-05 07:25:06 +02:00
return ( rfm22b_dev ! = NULL & & rfm22b_dev - > magic = = PIOS_RFM22B_DEV_MAGIC ) ;
2012-02-29 05:30:06 +01:00
}
# if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_rfm22b_dev * PIOS_RFM22B_alloc ( void )
{
struct pios_rfm22b_dev * rfm22b_dev ;
rfm22b_dev = ( struct pios_rfm22b_dev * ) pvPortMalloc ( sizeof ( * rfm22b_dev ) ) ;
2012-09-05 07:25:06 +02:00
rfm22b_dev - > spi_id = 0 ;
2012-02-29 05:30:06 +01:00
if ( ! rfm22b_dev ) return ( NULL ) ;
rfm22b_dev - > magic = PIOS_RFM22B_DEV_MAGIC ;
return ( rfm22b_dev ) ;
}
# else
static struct pios_rfm22b_dev pios_rfm22b_devs [ PIOS_RFM22B_MAX_DEVS ] ;
static uint8_t pios_rfm22b_num_devs ;
static struct pios_rfm22b_dev * PIOS_RFM22B_alloc ( void )
{
struct pios_rfm22b_dev * rfm22b_dev ;
2012-03-18 18:22:05 +01:00
if ( pios_rfm22b_num_devs > = PIOS_RFM22B_MAX_DEVS )
return NULL ;
2012-02-29 05:30:06 +01:00
rfm22b_dev = & pios_rfm22b_devs [ pios_rfm22b_num_devs + + ] ;
rfm22b_dev - > magic = PIOS_RFM22B_DEV_MAGIC ;
return ( rfm22b_dev ) ;
}
# endif
2012-09-05 07:25:06 +02:00
static struct pios_rfm22b_dev * g_rfm22b_dev = NULL ;
2012-08-26 09:41:19 +02:00
2012-02-29 05:30:06 +01:00
/**
2012-03-18 18:22:05 +01:00
* Initialise an RFM22B device
*/
2012-09-05 07:25:06 +02:00
int32_t PIOS_RFM22B_Init ( uint32_t * rfm22b_id , uint32_t spi_id , uint32_t slave_num , const struct pios_rfm22b_cfg * cfg )
2012-02-29 05:30:06 +01:00
{
PIOS_DEBUG_Assert ( rfm22b_id ) ;
PIOS_DEBUG_Assert ( cfg ) ;
2012-03-16 03:29:54 +01:00
// Allocate the device structure.
2012-06-06 06:10:32 +02:00
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) PIOS_RFM22B_alloc ( ) ;
2012-02-29 05:30:06 +01:00
if ( ! rfm22b_dev )
return ( - 1 ) ;
2012-09-05 07:25:06 +02:00
// Store the SPI handle
rfm22b_dev - > slave_num = slave_num ;
rfm22b_dev - > spi_id = spi_id ;
2012-09-15 04:30:02 +02:00
// Set the state to initializing.
2012-09-17 04:33:30 +02:00
rfm22b_dev - > state = RFM22B_STATE_UNINITIALIZED ;
// Create the event queue
rfm22b_dev - > eventQueue = xQueueCreate ( EVENT_QUEUE_SIZE , sizeof ( enum pios_rfm22b_event ) ) ;
// Initialize the register values.
rfm22b_dev - > device_status = 0 ;
rfm22b_dev - > int_status1 = 0 ;
rfm22b_dev - > int_status2 = 0 ;
rfm22b_dev - > ezmac_status = 0 ;
2012-09-15 04:30:02 +02:00
// Initialize the stats.
rfm22b_dev - > resets = 0 ;
rfm22b_dev - > errors = 0 ;
rfm22b_dev - > irqs_processed = 0 ;
2012-09-17 04:33:30 +02:00
rfm22b_dev - > rssi = 0 ;
rfm22b_dev - > rssi_dBm = - 127 ;
2012-03-16 03:29:54 +01:00
// Bind the configuration to the device instance
2012-05-07 05:47:21 +02:00
rfm22b_dev - > cfg = * cfg ;
2012-08-25 04:25:02 +02:00
2012-09-23 17:36:38 +02:00
// Initialize the packets.
rfm22b_dev - > rx_packet = NULL ;
rfm22b_dev - > rx_packet_next = NULL ;
rfm22b_dev - > rx_packet_prev = NULL ;
rfm22b_dev - > rx_packet_len = 0 ;
rfm22b_dev - > tx_packet = NULL ;
2012-02-29 05:30:06 +01:00
* rfm22b_id = ( uint32_t ) rfm22b_dev ;
2012-08-26 09:41:19 +02:00
g_rfm22b_dev = rfm22b_dev ;
2012-09-25 05:51:34 +02:00
// Calculate the (approximate) maximum amount of time that it should take to transmit / receive a packet.
rfm22b_dev - > max_packet_time = ( uint16_t ) ( ( float ) ( PIOS_PH_MAX_PACKET * 8 * 1000 ) / ( float ) ( rfm22b_dev - > cfg . maxRFBandwidth ) + 0.5 ) ;
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-09-25 05:51:34 +02:00
2012-08-26 09:41:19 +02:00
// Create a semaphore to know if an ISR needs responding to
vSemaphoreCreateBinary ( rfm22b_dev - > isrPending ) ;
2012-02-29 05:30:06 +01:00
2012-09-23 17:36:38 +02:00
// Create a semaphore to know when an rx packet is available
vSemaphoreCreateBinary ( rfm22b_dev - > rxsem ) ;
2012-09-17 04:33:30 +02:00
// Create the packet queue.
rfm22b_dev - > packetQueue = xQueueCreate ( PACKET_QUEUE_SIZE , sizeof ( PHPacketHandle ) ) ;
2012-09-13 03:24:19 +02:00
// Initialize the max tx power level.
PIOS_RFM22B_SetTxPower ( * rfm22b_id , cfg - > maxTxPower ) ;
2012-04-11 05:22:53 +02:00
// Create our (hopefully) unique 32 bit id from the processor serial number.
uint8_t crcs [ ] = { 0 , 0 , 0 , 0 } ;
{
char serial_no_str [ 33 ] ;
PIOS_SYS_SerialNumberGet ( serial_no_str ) ;
// Create a 32 bit value using 4 8 bit CRC values.
for ( uint8_t i = 0 ; serial_no_str [ i ] ! = 0 ; + + i )
crcs [ i % 4 ] = PIOS_CRC_updateByte ( crcs [ i % 4 ] , serial_no_str [ i ] ) ;
}
rfm22b_dev - > deviceID = crcs [ 0 ] | crcs [ 1 ] < < 8 | crcs [ 2 ] < < 16 | crcs [ 3 ] < < 24 ;
DEBUG_PRINTF ( 2 , " RF device ID: %x \n \r " , rfm22b_dev - > deviceID ) ;
2012-08-25 04:25:02 +02:00
// Initialize the external interrupt.
PIOS_EXTI_Init ( cfg - > exti_cfg ) ;
2012-09-12 05:34:26 +02:00
// Register the watchdog timer for the radio driver task
# ifdef PIOS_WDG_RFM22B
PIOS_WDG_RegisterFlag ( PIOS_WDG_RFM22B ) ;
# endif /* PIOS_WDG_RFM22B */
// Start the driver task. This task controls the radio state machine and removed all of the IO from the IRQ handler.
xTaskCreate ( PIOS_RFM22B_Task , ( signed char * ) " PIOS_RFM22B_Task " , STACK_SIZE_BYTES , ( void * ) rfm22b_dev , TASK_PRIORITY , & ( rfm22b_dev - > taskHandle ) ) ;
2012-09-17 04:33:30 +02:00
// Initialize the radio device.
PIOS_RFM22B_InjectEvent ( rfm22b_dev , RFM22B_EVENT_INITIALIZE , false ) ;
2012-02-29 05:30:06 +01:00
return ( 0 ) ;
}
2012-09-15 04:30:02 +02:00
/**
* The RFM22B external interrupt routine .
*/
2012-09-30 17:04:36 +02:00
bool PIOS_RFM22_EXT_Int ( void )
2012-09-15 04:30:02 +02:00
{
if ( ! PIOS_RFM22B_validate ( g_rfm22b_dev ) )
2012-09-30 17:04:36 +02:00
return false ;
2012-09-15 04:30:02 +02:00
// Inject an interrupt event into the state machine.
PIOS_RFM22B_InjectEvent ( g_rfm22b_dev , RFM22B_EVENT_INT_RECEIVED , true ) ;
2012-09-30 17:04:36 +02:00
return false ;
2012-09-15 04:30:02 +02:00
}
/**
* Inject an event into the RFM22B state machine .
* \ param [ in ] rfm22b_dev The device structure
* \ param [ in ] event The event to inject
* \ param [ in ] inISR Is this being called from an interrrup service routine ?
*/
static void PIOS_RFM22B_InjectEvent ( struct pios_rfm22b_dev * rfm22b_dev , enum pios_rfm22b_event event , bool inISR )
{
// Store the event.
2012-09-17 04:33:30 +02:00
if ( xQueueSend ( rfm22b_dev - > eventQueue , & event , portMAX_DELAY ) ! = pdTRUE )
return ;
2012-09-15 04:30:02 +02:00
// Signal the semaphore to wake up the handler thread.
if ( inISR ) {
portBASE_TYPE pxHigherPriorityTaskWoken ;
if ( xSemaphoreGiveFromISR ( rfm22b_dev - > isrPending , & pxHigherPriorityTaskWoken ) ! = pdTRUE ) {
// Something went fairly seriously wrong
rfm22b_dev - > errors + + ;
}
portEND_SWITCHING_ISR ( pxHigherPriorityTaskWoken ) ;
}
else
{
if ( xSemaphoreGive ( rfm22b_dev - > isrPending ) ! = pdTRUE ) {
// Something went fairly seriously wrong
rfm22b_dev - > errors + + ;
}
}
}
/**
* Returns the unique device ID for th RFM22B device .
* \ param [ in ] rfm22b_id The RFM22B device index .
* \ return The unique device ID
*/
2012-04-11 05:22:53 +02:00
uint32_t PIOS_RFM22B_DeviceID ( uint32_t rfm22b_id )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
2012-09-15 04:30:02 +02:00
if ( PIOS_RFM22B_validate ( rfm22b_dev ) )
return rfm22b_dev - > deviceID ;
else
return 0 ;
2012-04-11 05:22:53 +02:00
}
2012-09-13 03:24:19 +02:00
void PIOS_RFM22B_SetTxPower ( uint32_t rfm22b_id , uint8_t tx_pwr )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
2012-09-15 04:30:02 +02:00
if ( ! PIOS_RFM22B_validate ( rfm22b_dev ) )
return ;
2012-09-13 03:24:19 +02:00
switch ( tx_pwr )
{
case 0 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_0 ; break ; // +1dBm ... 1.25mW
case 1 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_1 ; break ; // +2dBm ... 1.6mW
case 2 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_2 ; break ; // +5dBm ... 3.16mW
case 3 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_3 ; break ; // +8dBm ... 6.3mW
case 4 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_4 ; break ; // +11dBm .. 12.6mW
case 5 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_5 ; break ; // +14dBm .. 25mW
case 6 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_6 ; break ; // +17dBm .. 50mW
case 7 : rfm22b_dev - > tx_power = RFM22_tx_pwr_txpow_7 ; break ; // +20dBm .. 100mW
default : break ;
}
}
2012-04-22 03:31:49 +02:00
int16_t PIOS_RFM22B_Resets ( uint32_t rfm22b_id )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
return rfm22b_dev - > resets ;
}
2012-02-29 05:30:06 +01:00
static void PIOS_RFM22B_RxStart ( uint32_t rfm22b_id , uint16_t rx_bytes_avail )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
bool valid = PIOS_RFM22B_validate ( rfm22b_dev ) ;
PIOS_Assert ( valid ) ;
}
2012-03-08 02:05:42 +01:00
2012-09-17 04:33:30 +02:00
/**
* Insert a packet on the packet queue for sending .
* Note : If this finction succedds , the packet will be released by the driver , so no release is necessary .
* If this function doesn ' t success , the caller is still responsible for the packet .
* \ param [ in ] rfm22b_id The rfm22b device .
* \ param [ in ] p The packet handle .
* \ param [ in ] max_delay The maximum time to delay waiting to queue the packet .
* \ return true on success , false on failue to queue the packet .
*/
bool PIOS_RFM22B_Send_Packet ( uint32_t rfm22b_id , PHPacketHandle p , uint32_t max_delay )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
if ( ! PIOS_RFM22B_validate ( rfm22b_dev ) )
return false ;
// Store the packet handle in the packet queue
if ( xQueueSend ( rfm22b_dev - > packetQueue , & p , max_delay ) ! = pdTRUE )
return false ;
// Inject a send packet event
PIOS_RFM22B_InjectEvent ( g_rfm22b_dev , RFM22B_EVENT_SEND_PACKET , false ) ;
// Success
return true ;
}
2012-09-23 17:36:38 +02:00
/**
* Receive a packet from the radio .
* \ param [ in ] rfm22b_id The rfm22b device .
* \ param [ in ] p A pointer to the packet handle .
* \ param [ in ] max_delay The maximum time to delay waiting for a packet .
* \ return The number of bytes received .
*/
uint32_t PIOS_RFM22B_Receive_Packet ( uint32_t rfm22b_id , PHPacketHandle * p , uint32_t max_delay )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
if ( ! PIOS_RFM22B_validate ( rfm22b_dev ) )
return 0 ;
// Allocate the next Rx packet
if ( rfm22b_dev - > rx_packet_next = = NULL )
rfm22b_dev - > rx_packet_next = PHGetRXPacket ( pios_packet_handler ) ;
// Block on the semephore until the a packet has been received.
if ( xSemaphoreTake ( rfm22b_dev - > rxsem , max_delay / portTICK_RATE_MS ) ! = pdTRUE )
return 0 ;
// Return the Rx packet if it's available.
uint32_t rx_len = 0 ;
if ( rfm22b_dev - > rx_packet_prev )
{
* p = rfm22b_dev - > rx_packet_prev ;
rfm22b_dev - > rx_packet_prev = NULL ;
rx_len = rfm22b_dev - > rx_packet_len ;
}
return rx_len ;
}
2012-09-12 05:34:26 +02:00
/**
* The task that controls the radio state machine .
*/
static void PIOS_RFM22B_Task ( void * parameters )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) parameters ;
2012-09-15 04:30:02 +02:00
if ( ! PIOS_RFM22B_validate ( rfm22b_dev ) )
return ;
2012-10-03 04:52:21 +02:00
portTickType lastEventTicks = xTaskGetTickCount ( ) ;
portTickType lastStatusTicks = lastEventTicks ;
2012-09-12 05:34:26 +02:00
while ( 1 )
{
# ifdef PIOS_WDG_RFM22B
// Update the watchdog timer
2012-09-15 04:30:02 +02:00
PIOS_WDG_UpdateFlag ( PIOS_WDG_RFM22B ) ;
2012-09-12 05:34:26 +02:00
# endif /* PIOS_WDG_RFM22B */
2012-09-15 04:30:02 +02:00
// Wait for a signal indicating an external interrupt or a pending send/receive request.
2012-09-12 05:34:26 +02:00
if ( xSemaphoreTake ( g_rfm22b_dev - > isrPending , ISR_TIMEOUT / portTICK_RATE_MS ) = = pdTRUE ) {
2012-09-15 04:30:02 +02:00
rfm22b_dev - > irqs_processed + + ;
2012-10-03 04:52:21 +02:00
lastEventTicks = xTaskGetTickCount ( ) ;
2012-09-17 04:33:30 +02:00
// Process events through the state machine.
enum pios_rfm22b_event event ;
while ( xQueueReceive ( rfm22b_dev - > eventQueue , & event , 0 ) = = pdTRUE )
{
if ( ( event = = RFM22B_EVENT_INT_RECEIVED ) & &
( ( rfm22b_dev - > state = = RFM22B_STATE_UNINITIALIZED ) | | ( rfm22b_dev - > state = = RFM22B_STATE_INITIALIZING ) ) )
continue ;
// Process all state transitions.
while ( event ! = RFM22B_EVENT_NUM_EVENTS )
event = rfm22_process_state_transition ( rfm22b_dev , event ) ;
}
2012-09-15 04:30:02 +02:00
}
else
{
// Has it been too long since the last event?
2012-10-03 04:52:21 +02:00
portTickType curTicks = xTaskGetTickCount ( ) ;
if ( curTicks < lastEventTicks )
lastEventTicks = curTicks ;
portTickType ticksSinceEvent = curTicks - lastEventTicks ;
if ( ( ticksSinceEvent / portTICK_RATE_MS ) > PIOS_RFM22B_SUPERVISOR_TIMEOUT )
2012-09-15 04:30:02 +02:00
{
2012-09-17 04:33:30 +02:00
// Transsition through an error event.
enum pios_rfm22b_event event = RFM22B_EVENT_ERROR ;
while ( event ! = RFM22B_EVENT_NUM_EVENTS )
event = rfm22_process_state_transition ( rfm22b_dev , event ) ;
2012-09-15 04:30:02 +02:00
2012-09-17 04:33:30 +02:00
// Clear the event queue.
while ( xQueueReceive ( rfm22b_dev - > eventQueue , & event , 0 ) = = pdTRUE )
;
2012-10-03 04:52:21 +02:00
lastEventTicks = xTaskGetTickCount ( ) ;
2012-09-15 04:30:02 +02:00
}
2012-09-12 05:34:26 +02:00
}
2012-09-25 05:51:34 +02:00
// Have we locked up sending / receiving a packet?
2012-10-03 04:52:21 +02:00
if ( rfm22b_dev - > packet_start_ticks > 0 )
2012-09-25 05:51:34 +02:00
{
2012-10-03 04:52:21 +02:00
portTickType cur_ticks = xTaskGetTickCount ( ) ;
2012-09-25 05:51:34 +02:00
// Did the clock wrap around?
2012-10-03 04:52:21 +02:00
if ( cur_ticks < rfm22b_dev - > packet_start_ticks )
rfm22b_dev - > packet_start_ticks = ( cur_ticks > 0 ) ? cur_ticks : 1 ;
2012-09-25 05:51:34 +02:00
// Have we been sending this packet too long?
2012-10-03 04:52:21 +02:00
if ( ( ( cur_ticks - rfm22b_dev - > packet_start_ticks ) / portTICK_RATE_MS ) > ( rfm22b_dev - > max_packet_time * 3 ) )
2012-09-25 05:51:34 +02:00
{
enum pios_rfm22b_event event = RFM22B_EVENT_TIMEOUT ;
while ( event ! = RFM22B_EVENT_NUM_EVENTS )
event = rfm22_process_state_transition ( rfm22b_dev , event ) ;
}
}
2012-10-03 04:52:21 +02:00
// Queue up a status packet if it's time.
portTickType curTicks = xTaskGetTickCount ( ) ;
// Rollover
if ( curTicks < lastStatusTicks )
lastStatusTicks = curTicks ;
if ( ( ( curTicks - lastStatusTicks ) / portTICK_RATE_MS ) > RADIOSTATS_UPDATE_PERIOD_MS )
if ( rfm22_sendStatus ( rfm22b_dev ) )
lastStatusTicks = curTicks ;
2012-09-12 05:34:26 +02:00
}
}
2012-02-29 05:30:06 +01:00
static void PIOS_RFM22B_TxStart ( uint32_t rfm22b_id , uint16_t tx_bytes_avail )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
bool valid = PIOS_RFM22B_validate ( rfm22b_dev ) ;
PIOS_Assert ( valid ) ;
2012-09-23 05:07:50 +02:00
# ifdef NEVER
2012-04-06 05:24:50 +02:00
// Get some data to send
bool need_yield = false ;
2012-06-06 06:10:32 +02:00
if ( tx_pre_buffer_size = = 0 )
2012-04-06 05:24:50 +02:00
tx_pre_buffer_size = ( rfm22b_dev - > tx_out_cb ) ( rfm22b_dev - > tx_out_context , tx_pre_buffer ,
2012-06-06 06:10:32 +02:00
TX_BUFFER_SIZE , NULL , & need_yield ) ;
2012-04-06 05:24:50 +02:00
2012-09-17 04:33:30 +02:00
// Inject a send packet event
PIOS_RFM22B_InjectEvent ( g_rfm22b_dev , RFM22B_EVENT_TX_START , false ) ;
2012-09-23 05:07:50 +02:00
# endif
2012-02-29 05:30:06 +01:00
}
/**
2012-03-18 18:22:05 +01:00
* Changes the baud rate of the RFM22B peripheral without re - initialising .
* \ param [ in ] rfm22b_id RFM22B name ( GPS , TELEM , AUX )
* \ param [ in ] baud Requested baud rate
*/
2012-02-29 05:30:06 +01:00
static void PIOS_RFM22B_ChangeBaud ( uint32_t rfm22b_id , uint32_t baud )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
bool valid = PIOS_RFM22B_validate ( rfm22b_dev ) ;
PIOS_Assert ( valid ) ;
}
static void PIOS_RFM22B_RegisterRxCallback ( uint32_t rfm22b_id , pios_com_callback rx_in_cb , uint32_t context )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
bool valid = PIOS_RFM22B_validate ( rfm22b_dev ) ;
PIOS_Assert ( valid ) ;
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it ' s ok to dereference _cb and _context
*/
rfm22b_dev - > rx_in_context = context ;
rfm22b_dev - > rx_in_cb = rx_in_cb ;
}
static void PIOS_RFM22B_RegisterTxCallback ( uint32_t rfm22b_id , pios_com_callback tx_out_cb , uint32_t context )
{
struct pios_rfm22b_dev * rfm22b_dev = ( struct pios_rfm22b_dev * ) rfm22b_id ;
bool valid = PIOS_RFM22B_validate ( rfm22b_dev ) ;
PIOS_Assert ( valid ) ;
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it ' s ok to dereference _cb and _context
*/
rfm22b_dev - > tx_out_context = context ;
rfm22b_dev - > tx_out_cb = tx_out_cb ;
}
2012-03-18 18:22:05 +01:00
// ************************************
// SPI read/write
2012-09-05 07:25:06 +02:00
//! Assert the CS line
static void rfm22_assertCs ( )
2012-08-26 06:07:00 +02:00
{
2012-09-05 07:25:06 +02:00
PIOS_DELAY_WaituS ( 1 ) ;
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) & & g_rfm22b_dev - > spi_id ! = 0 )
PIOS_SPI_RC_PinSet ( g_rfm22b_dev - > spi_id , g_rfm22b_dev - > slave_num , 0 ) ;
2012-08-26 06:07:00 +02:00
}
2012-09-05 07:25:06 +02:00
//! Deassert the CS line
static void rfm22_deassertCs ( )
2012-08-26 06:07:00 +02:00
{
2012-09-05 07:25:06 +02:00
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) & & g_rfm22b_dev - > spi_id ! = 0 )
PIOS_SPI_RC_PinSet ( g_rfm22b_dev - > spi_id , g_rfm22b_dev - > slave_num , 1 ) ;
2012-08-26 06:07:00 +02:00
}
2012-09-05 07:25:06 +02:00
//! Claim the SPI bus semaphore
static void rfm22_claimBus ( )
2012-03-18 18:22:05 +01:00
{
2012-09-05 07:25:06 +02:00
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) & & g_rfm22b_dev - > spi_id ! = 0 )
PIOS_SPI_ClaimBus ( g_rfm22b_dev - > spi_id ) ;
2012-03-18 18:22:05 +01:00
}
2012-09-05 07:25:06 +02:00
//! Release the SPI bus semaphore
static void rfm22_releaseBus ( )
2012-03-18 18:22:05 +01:00
{
2012-09-05 07:25:06 +02:00
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) & & g_rfm22b_dev - > spi_id ! = 0 )
PIOS_SPI_ReleaseBus ( g_rfm22b_dev - > spi_id ) ;
2012-03-18 18:22:05 +01:00
}
2012-09-05 07:56:48 +02:00
/**
* Claim the semaphore and write a byte to a register
* @ param [ in ] addr The address to write to
* @ param [ in ] data The datat to write to that address
*/
2012-09-05 07:25:06 +02:00
static void rfm22_write ( uint8_t addr , uint8_t data )
2012-03-18 18:22:05 +01:00
{
2012-09-05 07:25:06 +02:00
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) ) {
rfm22_claimBus ( ) ;
rfm22_assertCs ( ) ;
uint8_t buf [ 2 ] = { addr | 0x80 , data } ;
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , buf , NULL , sizeof ( buf ) , NULL ) ;
rfm22_deassertCs ( ) ;
rfm22_releaseBus ( ) ;
}
2012-03-18 18:22:05 +01:00
}
2012-09-02 20:31:09 +02:00
/**
* Write a byte to a register without claiming the bus . Also
* toggle the NSS line
2012-09-05 07:56:48 +02:00
* @ param [ in ] addr The address of the RFM22b register to write
* @ param [ in ] data The data to write to that register
2012-09-02 20:31:09 +02:00
static void rfm22_write_noclaim ( uint8_t addr , uint8_t data )
{
uint8_t buf [ 2 ] = { addr | 0x80 , data } ;
2012-09-05 07:25:06 +02:00
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) ) {
rfm22_assertCs ( ) ;
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , buf , NULL , sizeof ( buf ) , NULL ) ;
rfm22_deassertCs ( ) ;
}
2012-09-02 20:31:09 +02:00
}
2012-09-15 04:30:02 +02:00
*/
2012-09-02 20:31:09 +02:00
2012-09-05 07:25:06 +02:00
/**
2012-03-18 18:22:05 +01:00
2012-09-05 07:25:06 +02:00
* Read a byte from an RFM22b register
* @ param [ in ] addr The address to read from
* @ return Returns the result of the register read
*/
static uint8_t rfm22_read ( uint8_t addr )
2012-03-18 18:22:05 +01:00
{
2012-09-05 07:25:06 +02:00
uint8_t in [ 2 ] ;
uint8_t out [ 2 ] = { addr & 0x7f , 0xFF } ;
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) ) {
rfm22_claimBus ( ) ;
rfm22_assertCs ( ) ;
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , out , in , sizeof ( out ) , NULL ) ;
rfm22_deassertCs ( ) ;
rfm22_releaseBus ( ) ;
}
return in [ 1 ] ;
2012-03-18 18:22:05 +01:00
}
2012-09-02 20:31:09 +02:00
/**
2012-09-05 07:25:06 +02:00
* Read a byte from an RFM22b register without claiming the bus
* @ param [ in ] addr The address to read from
* @ return Returns the result of the register read
2012-09-02 20:31:09 +02:00
*/
static uint8_t rfm22_read_noclaim ( uint8_t addr )
{
2012-09-05 07:25:06 +02:00
uint8_t out [ 2 ] = { addr & 0x7F , 0xFF } ;
uint8_t in [ 2 ] ;
2012-09-15 04:30:02 +02:00
if ( PIOS_RFM22B_validate ( g_rfm22b_dev ) ) {
2012-09-05 07:25:06 +02:00
rfm22_assertCs ( ) ;
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , out , in , sizeof ( out ) , NULL ) ;
rfm22_deassertCs ( ) ;
}
return in [ 1 ] ;
2012-09-02 20:31:09 +02:00
}
2012-03-18 18:22:05 +01:00
// ************************************
2012-03-16 03:29:54 +01:00
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_process_state_transition ( struct pios_rfm22b_dev * rfm22b_dev , enum pios_rfm22b_event event )
{
// No event
if ( event = = RFM22B_EVENT_NUM_EVENTS )
return RFM22B_EVENT_NUM_EVENTS ;
// Don't transition if there is no transition defined
enum pios_rfm22b_state next_state = rfm22b_transitions [ rfm22b_dev - > state ] . next_state [ event ] ;
if ( ! next_state )
return RFM22B_EVENT_NUM_EVENTS ;
/*
* Move to the next state
*
* This is done prior to calling the new state ' s entry function to
* guarantee that the entry function never depends on the previous
* state . This way , it cannot ever know what the previous state was .
*/
enum pios_rfm22b_state prev_state = rfm22b_dev - > state ;
if ( prev_state ) ;
rfm22b_dev - > state = next_state ;
/* Call the entry function (if any) for the next state. */
if ( rfm22b_transitions [ rfm22b_dev - > state ] . entry_fn )
return rfm22b_transitions [ rfm22b_dev - > state ] . entry_fn ( rfm22b_dev ) ;
return RFM22B_EVENT_NUM_EVENTS ;
}
// ************************************
2012-09-23 05:07:50 +02:00
static void rfm22_setNominalCarrierFrequency ( struct pios_rfm22b_dev * rfm22b_dev , uint32_t frequency_hz )
2012-03-18 18:22:05 +01:00
{
2012-09-23 05:07:50 +02:00
uint32_t min_frequency_hz = rfm22b_dev - > cfg . minFrequencyHz ;
uint32_t max_frequency_hz = rfm22b_dev - > cfg . maxFrequencyHz ;
if ( frequency_hz < min_frequency_hz )
frequency_hz = min_frequency_hz ;
else if ( frequency_hz > max_frequency_hz )
frequency_hz = max_frequency_hz ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
// holds the hbsel (1 or 2)
uint8_t hbsel ;
2012-03-18 18:22:05 +01:00
if ( frequency_hz < 480000000 )
hbsel = 1 ;
else
hbsel = 2 ;
uint8_t fb = ( uint8_t ) ( frequency_hz / ( 10000000 * hbsel ) ) ;
uint32_t fc = ( uint32_t ) ( frequency_hz - ( 10000000 * hbsel * fb ) ) ;
fc = ( fc * 64u ) / ( 10000ul * hbsel ) ;
fb - = 24 ;
if ( hbsel > 1 )
fb | = RFM22_fbs_hbsel ;
fb | = RFM22_fbs_sbse ; // is this the RX LO polarity?
2012-09-23 05:07:50 +02:00
// frequency hopping channel (0-255)
rfm22b_dev - > frequency_step_size = 156.25f * hbsel ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
// frequency hopping channel (0-255)
rfm22_write ( RFM22_frequency_hopping_channel_select , rfm22b_dev - > frequency_hop_channel ) ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
// no frequency offset
rfm22_write ( RFM22_frequency_offset1 , 0 ) ;
// no frequency offset
rfm22_write ( RFM22_frequency_offset2 , 0 ) ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
// set the carrier frequency
rfm22_write ( RFM22_frequency_band_select , fb ) ;
rfm22_write ( RFM22_nominal_carrier_frequency1 , fc > > 8 ) ;
rfm22_write ( RFM22_nominal_carrier_frequency0 , fc & 0xff ) ;
2012-03-18 18:22:05 +01:00
}
void rfm22_setFreqHopChannel ( uint8_t channel )
{ // set the frequency hopping channel
2012-09-23 05:07:50 +02:00
g_rfm22b_dev - > frequency_hop_channel = channel ;
rfm22_write ( RFM22_frequency_hopping_channel_select , channel ) ;
2012-03-18 18:22:05 +01:00
}
uint32_t rfm22_freqHopSize ( void )
{ // return the frequency hopping step size
2012-09-23 05:07:50 +02:00
return ( ( uint32_t ) g_rfm22b_dev - > frequency_hop_step_size_reg * 10000 ) ;
2012-03-18 18:22:05 +01:00
}
// ************************************
// radio datarate about 19200 Baud
// radio frequency deviation 45kHz
// radio receiver bandwidth 67kHz.
//
// Carson's rule:
// The signal bandwidth is about 2(Delta-f + fm) ..
//
// Delta-f = frequency deviation
// fm = maximum frequency of the signal
//
// This gives 2(45 + 9.6) = 109.2kHz.
void rfm22_setDatarate ( uint32_t datarate_bps , bool data_whitening )
{
2012-09-23 05:07:50 +02:00
// Find the closest data rate that is >= the value passed in
int lookup_index = 0 ;
2012-03-18 18:22:05 +01:00
while ( lookup_index < ( LOOKUP_SIZE - 1 ) & & data_rate [ lookup_index ] < datarate_bps )
lookup_index + + ;
2012-10-03 05:59:43 +02:00
lookup_index = 10 ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
datarate_bps = data_rate [ lookup_index ] ;
2012-03-18 18:22:05 +01:00
2012-04-07 02:36:35 +02:00
// rfm22_if_filter_bandwidth
rfm22_write ( 0x1C , reg_1C [ lookup_index ] ) ;
// rfm22_afc_loop_gearshift_override
rfm22_write ( 0x1D , reg_1D [ lookup_index ] ) ;
// RFM22_afc_timing_control
rfm22_write ( 0x1E , reg_1E [ lookup_index ] ) ;
// RFM22_clk_recovery_gearshift_override
rfm22_write ( 0x1F , reg_1F [ lookup_index ] ) ;
// rfm22_clk_recovery_oversampling_ratio
rfm22_write ( 0x20 , reg_20 [ lookup_index ] ) ;
// rfm22_clk_recovery_offset2
rfm22_write ( 0x21 , reg_21 [ lookup_index ] ) ;
// rfm22_clk_recovery_offset1
rfm22_write ( 0x22 , reg_22 [ lookup_index ] ) ;
// rfm22_clk_recovery_offset0
rfm22_write ( 0x23 , reg_23 [ lookup_index ] ) ;
// rfm22_clk_recovery_timing_loop_gain1
rfm22_write ( 0x24 , reg_24 [ lookup_index ] ) ;
// rfm22_clk_recovery_timing_loop_gain0
rfm22_write ( 0x25 , reg_25 [ lookup_index ] ) ;
// rfm22_afc_limiter
rfm22_write ( 0x2A , reg_2A [ lookup_index ] ) ;
2012-03-18 18:22:05 +01:00
2012-10-03 05:59:43 +02:00
/* This breaks all bit rates < 100000!
2012-09-23 05:07:50 +02:00
if ( datarate_bps < 100000 )
2012-04-07 02:36:35 +02:00
// rfm22_chargepump_current_trimming_override
rfm22_write ( 0x58 , 0x80 ) ;
2012-03-18 18:22:05 +01:00
else
2012-04-07 02:36:35 +02:00
// rfm22_chargepump_current_trimming_override
rfm22_write ( 0x58 , 0xC0 ) ;
2012-10-03 05:59:43 +02:00
*/
2012-03-18 18:22:05 +01:00
2012-04-07 02:36:35 +02:00
// rfm22_tx_data_rate1
rfm22_write ( 0x6E , reg_6E [ lookup_index ] ) ;
// rfm22_tx_data_rate0
rfm22_write ( 0x6F , reg_6F [ lookup_index ] ) ;
2012-03-18 18:22:05 +01:00
// Enable data whitening
// uint8_t txdtrtscale_bit = rfm22_read(RFM22_modulation_mode_control1) & RFM22_mmc1_txdtrtscale;
// rfm22_write(RFM22_modulation_mode_control1, txdtrtscale_bit | RFM22_mmc1_enwhite);
if ( ! data_whitening )
2012-04-07 02:36:35 +02:00
// rfm22_modulation_mode_control1
rfm22_write ( 0x70 , reg_70 [ lookup_index ] & ~ RFM22_mmc1_enwhite ) ;
2012-03-18 18:22:05 +01:00
else
2012-04-07 02:36:35 +02:00
// rfm22_modulation_mode_control1
rfm22_write ( 0x70 , reg_70 [ lookup_index ] | RFM22_mmc1_enwhite ) ;
2012-03-18 18:22:05 +01:00
2012-04-07 02:36:35 +02:00
// rfm22_modulation_mode_control2
rfm22_write ( 0x71 , reg_71 [ lookup_index ] ) ;
2012-03-18 18:22:05 +01:00
2012-04-07 02:36:35 +02:00
// rfm22_frequency_deviation
rfm22_write ( 0x72 , reg_72 [ lookup_index ] ) ;
2012-03-18 18:22:05 +01:00
rfm22_write ( RFM22_ook_counter_value1 , 0x00 ) ;
rfm22_write ( RFM22_ook_counter_value2 , 0x00 ) ;
}
// ************************************
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_setRxMode ( struct pios_rfm22b_dev * rfm22b_dev )
2012-03-18 18:22:05 +01:00
{
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-03-18 18:22:05 +01:00
// disable interrupts
rfm22_write ( RFM22_interrupt_enable1 , 0x00 ) ;
rfm22_write ( RFM22_interrupt_enable2 , 0x00 ) ;
2012-04-06 05:24:50 +02:00
// Switch to TUNE mode
rfm22_write ( RFM22_op_and_func_ctrl1 , RFM22_opfc1_pllon ) ;
2012-03-18 18:22:05 +01:00
RX_LED_OFF ;
TX_LED_OFF ;
2012-04-06 05:24:50 +02:00
// empty the rx buffer
2012-09-23 17:36:38 +02:00
rfm22b_dev - > rx_buffer_wr = 0 ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// Clear the TX buffer.
2012-09-23 05:07:50 +02:00
rfm22b_dev - > tx_data_rd = rfm22b_dev - > tx_data_wr = 0 ;
2012-03-18 18:22:05 +01:00
// clear FIFOs
2012-09-15 04:30:02 +02:00
rfm22_write ( RFM22_op_and_func_ctrl2 , RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx ) ;
rfm22_write ( RFM22_op_and_func_ctrl2 , 0x00 ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// enable RX interrupts
rfm22_write ( RFM22_interrupt_enable1 , RFM22_ie1_encrcerror | RFM22_ie1_enpkvalid |
2012-06-07 02:44:56 +02:00
RFM22_ie1_enrxffafull | RFM22_ie1_enfferr ) ;
2012-04-06 05:24:50 +02:00
rfm22_write ( RFM22_interrupt_enable2 , RFM22_ie2_enpreainval | RFM22_ie2_enpreaval |
2012-06-07 02:44:56 +02:00
RFM22_ie2_enswdet ) ;
2012-04-06 05:24:50 +02:00
2012-03-18 18:22:05 +01:00
// enable the receiver
rfm22_write ( RFM22_op_and_func_ctrl1 , RFM22_opfc1_pllon | RFM22_opfc1_rxon ) ;
2012-09-17 04:33:30 +02:00
// No event generated
return RFM22B_EVENT_NUM_EVENTS ;
2012-03-18 18:22:05 +01:00
}
// ************************************
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_txStart ( struct pios_rfm22b_dev * rfm22b_dev )
2012-04-06 05:24:50 +02:00
{
2012-09-23 05:07:50 +02:00
// See if there's a packet on the packet queue.
PHPacketHandle p ;
if ( xQueueReceive ( rfm22b_dev - > packetQueue , & p , 0 ) ! = pdTRUE )
2012-04-06 05:24:50 +02:00
{
// Clear the TX buffer.
2012-09-23 05:07:50 +02:00
rfm22b_dev - > tx_data_rd = rfm22b_dev - > tx_data_wr = 0 ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_RX_MODE ;
2012-04-06 05:24:50 +02:00
}
2012-09-23 05:07:50 +02:00
rfm22b_dev - > tx_packet = p ;
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = xTaskGetTickCount ( ) ;
if ( rfm22b_dev - > packet_start_ticks = = 0 )
rfm22b_dev - > packet_start_ticks = 1 ;
2012-04-06 05:24:50 +02:00
// disable interrupts
2012-09-03 05:16:59 +02:00
rfm22_write ( RFM22_interrupt_enable1 , 0x00 ) ;
rfm22_write ( RFM22_interrupt_enable2 , 0x00 ) ;
2012-04-06 05:24:50 +02:00
// TUNE mode
2012-09-03 05:16:59 +02:00
rfm22_write ( RFM22_op_and_func_ctrl1 , RFM22_opfc1_pllon ) ;
2012-04-06 05:24:50 +02:00
// Queue the data up for sending
2012-09-23 05:07:50 +02:00
rfm22b_dev - > tx_data_wr = PH_PACKET_SIZE ( rfm22b_dev - > tx_packet ) ;
2012-04-06 05:24:50 +02:00
RX_LED_OFF ;
2012-04-18 02:36:05 +02:00
// Set the destination address in the transmit header.
// The destination address is the first 4 bytes of the message.
2012-09-23 05:07:50 +02:00
uint8_t * tx_buffer = ( uint8_t * ) ( rfm22b_dev - > tx_packet ) ;
2012-09-03 05:16:59 +02:00
rfm22_write ( RFM22_transmit_header0 , tx_buffer [ 0 ] ) ;
rfm22_write ( RFM22_transmit_header1 , tx_buffer [ 1 ] ) ;
rfm22_write ( RFM22_transmit_header2 , tx_buffer [ 2 ] ) ;
rfm22_write ( RFM22_transmit_header3 , tx_buffer [ 3 ] ) ;
2012-04-18 02:36:05 +02:00
2012-04-06 05:24:50 +02:00
// FIFO mode, GFSK modulation
2012-09-03 05:16:59 +02:00
uint8_t fd_bit = rfm22_read ( RFM22_modulation_mode_control2 ) & RFM22_mmc2_fd ;
rfm22_write ( RFM22_modulation_mode_control2 , fd_bit | RFM22_mmc2_dtmod_fifo |
2012-06-07 02:44:56 +02:00
RFM22_mmc2_modtyp_gfsk ) ;
2012-04-06 05:24:50 +02:00
2012-09-03 05:16:59 +02:00
// set the tx power
rfm22_write ( RFM22_tx_power , RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_1 |
2012-09-13 03:24:19 +02:00
RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | g_rfm22b_dev - > tx_power ) ;
2012-04-06 05:24:50 +02:00
// clear FIFOs
2012-09-03 05:16:59 +02:00
rfm22_write ( RFM22_op_and_func_ctrl2 , RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx ) ;
rfm22_write ( RFM22_op_and_func_ctrl2 , 0x00 ) ;
2012-04-06 05:24:50 +02:00
2012-09-03 05:16:59 +02:00
// *******************
2012-04-06 05:24:50 +02:00
// add some data to the chips TX FIFO before enabling the transmitter
2012-09-03 05:16:59 +02:00
// set the total number of data bytes we are going to transmit
2012-09-23 05:07:50 +02:00
rfm22_write ( RFM22_transmit_packet_length , rfm22b_dev - > tx_data_wr ) ;
2012-09-03 05:16:59 +02:00
// add some data
rfm22_claimBus ( ) ;
2012-09-05 07:25:06 +02:00
rfm22_assertCs ( ) ;
PIOS_SPI_TransferByte ( g_rfm22b_dev - > spi_id , RFM22_fifo_access | 0x80 ) ;
2012-09-23 05:07:50 +02:00
int bytes_to_write = ( rfm22b_dev - > tx_data_wr - rfm22b_dev - > tx_data_rd ) ;
2012-09-02 04:24:42 +02:00
bytes_to_write = ( bytes_to_write > FIFO_SIZE ) ? FIFO_SIZE : bytes_to_write ;
2012-09-23 05:07:50 +02:00
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , & tx_buffer [ rfm22b_dev - > tx_data_rd ] , NULL , bytes_to_write , NULL ) ;
rfm22b_dev - > tx_data_rd + = bytes_to_write ;
2012-09-05 07:25:06 +02:00
rfm22_deassertCs ( ) ;
2012-09-03 05:16:59 +02:00
rfm22_releaseBus ( ) ;
2012-04-06 05:24:50 +02:00
// enable TX interrupts
2012-09-03 05:16:59 +02:00
rfm22_write ( RFM22_interrupt_enable1 , RFM22_ie1_enpksent | RFM22_ie1_entxffaem ) ;
2012-04-06 05:24:50 +02:00
// enable the transmitter
2012-09-03 05:16:59 +02:00
rfm22_write ( RFM22_op_and_func_ctrl1 , RFM22_opfc1_pllon | RFM22_opfc1_txon ) ;
2012-04-06 05:24:50 +02:00
TX_LED_ON ;
2012-09-23 05:07:50 +02:00
return RFM22B_EVENT_TX_STARTED ;
2012-04-06 05:24:50 +02:00
}
2012-10-03 04:52:21 +02:00
static bool rfm22_sendStatus ( struct pios_rfm22b_dev * rfm22b_dev )
{
PHPacketHandle sph = ( PHPacketHandle ) & ( rfm22b_dev - > status_packet ) ;
// Queue the status message
rfm22b_dev - > status_packet . header . source_id = rfm22b_dev - > deviceID ;
rfm22b_dev - > status_packet . header . destination_id = 0xffffffff ; // Broadcast
rfm22b_dev - > status_packet . header . type = PACKET_TYPE_STATUS ;
rfm22b_dev - > status_packet . header . data_size = PH_STATUS_DATA_SIZE ( & ( rfm22b_dev - > status_packet ) ) ;
rfm22b_dev - > status_packet . header . tx_seq = 0 ;
rfm22b_dev - > status_packet . header . rx_seq = 0 ;
rfm22b_dev - > status_packet . errors = rfm22b_dev - > errors ;
rfm22b_dev - > status_packet . resets = rfm22b_dev - > resets ;
rfm22b_dev - > status_packet . retries = 0 ;
rfm22b_dev - > status_packet . uavtalk_errors = 0 ;
rfm22b_dev - > status_packet . dropped = 0 ;
// Add the error correcting code.
encode_data ( ( unsigned char * ) sph , PHPacketSize ( sph ) , ( unsigned char * ) sph ) ;
if ( xQueueSend ( rfm22b_dev - > packetQueue , & sph , 0 ) ! = pdTRUE )
return false ;
// Process a SEND_PACKT event.
enum pios_rfm22b_event event = RFM22B_EVENT_SEND_PACKET ;
while ( event ! = RFM22B_EVENT_NUM_EVENTS )
event = rfm22_process_state_transition ( rfm22b_dev , event ) ;
return true ;
}
2012-03-18 18:22:05 +01:00
// ************************************
2012-09-17 04:33:30 +02:00
/**
* Read the RFM22B interrupt and device status registers
* \ param [ in ] rfm22b_dev The device structure
*/
static bool rfm22_readStatus ( struct pios_rfm22b_dev * rfm22b_dev )
2012-03-18 18:22:05 +01:00
{
2012-09-17 04:33:30 +02:00
// 1. Read the interrupt statuses with burst read
rfm22_claimBus ( ) ; // Set RC and the semaphore
uint8_t write_buf [ 3 ] = { RFM22_interrupt_status1 & 0x7f , 0xFF , 0xFF } ;
uint8_t read_buf [ 3 ] ;
rfm22_assertCs ( ) ;
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , write_buf , read_buf , sizeof ( write_buf ) , NULL ) ;
rfm22_deassertCs ( ) ;
rfm22b_dev - > int_status1 = read_buf [ 1 ] ;
rfm22b_dev - > int_status2 = read_buf [ 2 ] ;
// Device status
rfm22b_dev - > device_status = rfm22_read_noclaim ( RFM22_device_status ) ;
// EzMAC status
rfm22b_dev - > ezmac_status = rfm22_read_noclaim ( RFM22_ezmac_status ) ;
// Release the bus
rfm22_releaseBus ( ) ;
// the RF module has gone and done a reset - we need to re-initialize the rf module
if ( rfm22b_dev - > int_status2 & RFM22_is2_ipor )
return false ;
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
return true ;
}
static enum pios_rfm22b_event rfm22_detectPreamble ( struct pios_rfm22b_dev * rfm22b_dev )
{
// Read the device status registers
if ( ! rfm22_readStatus ( rfm22b_dev ) )
return RFM22B_EVENT_ERROR ;
2012-04-06 05:24:50 +02:00
// Valid preamble detected
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > int_status2 & RFM22_is2_ipreaval )
2012-04-06 05:24:50 +02:00
{
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = xTaskGetTickCount ( ) ;
if ( rfm22b_dev - > packet_start_ticks = = 0 )
rfm22b_dev - > packet_start_ticks = 1 ;
2012-06-07 02:44:56 +02:00
RX_LED_ON ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_PREAMBLE_DETECTED ;
2012-04-06 05:24:50 +02:00
}
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_NUM_EVENTS ;
}
static enum pios_rfm22b_event rfm22_detectSync ( struct pios_rfm22b_dev * rfm22b_dev )
{
// Read the device status registers
if ( ! rfm22_readStatus ( rfm22b_dev ) )
return RFM22B_EVENT_ERROR ;
2012-04-06 05:24:50 +02:00
// Sync word detected
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > int_status2 & RFM22_is2_iswdet )
2012-04-06 05:24:50 +02:00
{
2012-06-07 02:44:56 +02:00
RX_LED_ON ;
// read the 10-bit signed afc correction value
// bits 9 to 2
2012-09-23 05:07:50 +02:00
uint16_t afc_correction = ( uint16_t ) rfm22_read ( RFM22_afc_correction_read ) < < 8 ;
2012-06-07 02:44:56 +02:00
// bits 1 & 0
afc_correction | = ( uint16_t ) rfm22_read ( RFM22_ook_counter_value1 ) & 0x00c0 ;
afc_correction > > = 6 ;
// convert the afc value to Hz
2012-09-23 05:07:50 +02:00
rfm22b_dev - > afc_correction_Hz = ( int32_t ) ( rfm22b_dev - > frequency_step_size * afc_correction + 0.5f ) ;
2012-06-07 02:44:56 +02:00
2012-09-17 04:33:30 +02:00
// read rx signal strength .. 45 = -100dBm, 205 = -20dBm
rfm22b_dev - > rssi = rfm22_read ( RFM22_rssi ) ;
// convert to dBm
rfm22b_dev - > rssi_dBm = ( int8_t ) ( rfm22b_dev - > rssi > > 1 ) - 122 ;
2012-06-07 02:44:56 +02:00
// remember the afc value for this packet
2012-09-23 05:07:50 +02:00
rfm22b_dev - > rx_packet_start_afc_Hz = rfm22b_dev - > afc_correction_Hz ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_SYNC_DETECTED ;
2012-03-18 18:22:05 +01:00
}
2012-09-26 03:10:15 +02:00
else if ( rfm22b_dev - > int_status2 & ! RFM22_is2_ipreaval )
{
// Waiting for sync timed out.
return RFM22B_EVENT_TX_START ;
}
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_NUM_EVENTS ;
}
static enum pios_rfm22b_event rfm22_rxData ( struct pios_rfm22b_dev * rfm22b_dev )
{
2012-09-23 17:36:38 +02:00
// Swap in the next packet buffer if required.
if ( rfm22b_dev - > rx_packet = = NULL )
{
if ( rfm22b_dev - > rx_packet_next ! = NULL )
rfm22b_dev - > rx_packet = rfm22b_dev - > rx_packet_next ;
else
return RFM22B_EVENT_ERROR ;
}
uint8_t * rx_buffer = ( uint8_t * ) ( rfm22b_dev - > rx_packet ) ;
2012-09-17 04:33:30 +02:00
// Read the device status registers
if ( ! rfm22_readStatus ( rfm22b_dev ) )
return RFM22B_EVENT_ERROR ;
// FIFO under/over flow error. Restart RX mode.
if ( rfm22b_dev - > device_status & ( RFM22_ds_ffunfl | RFM22_ds_ffovfl ) )
return RFM22B_EVENT_ERROR ;
2012-04-06 05:24:50 +02:00
// RX FIFO almost full, it needs emptying
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > int_status1 & RFM22_is1_irxffafull )
2012-04-06 05:24:50 +02:00
{
2012-09-17 04:33:30 +02:00
// read data from the rf chips FIFO buffer
// read the total length of the packet data
uint16_t len = rfm22_read ( RFM22_received_packet_length ) ;
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
// The received packet is going to be larger than the specified length
2012-09-23 17:36:38 +02:00
if ( ( rfm22b_dev - > rx_buffer_wr + RX_FIFO_HI_WATERMARK ) > len )
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_ERROR ;
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
// Another packet length error.
2012-09-23 17:36:38 +02:00
if ( ( ( rfm22b_dev - > rx_buffer_wr + RX_FIFO_HI_WATERMARK ) > = len ) & & ! ( rfm22b_dev - > int_status1 & RFM22_is1_ipkvalid ) )
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_ERROR ;
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
// Fetch the data from the RX FIFO
rfm22_claimBus ( ) ;
rfm22_assertCs ( ) ;
PIOS_SPI_TransferByte ( rfm22b_dev - > spi_id , RFM22_fifo_access & 0x7F ) ;
2012-09-23 17:36:38 +02:00
rfm22b_dev - > rx_buffer_wr + = ( PIOS_SPI_TransferBlock ( rfm22b_dev - > spi_id , OUT_FF , ( uint8_t * ) & rx_buffer [ rfm22b_dev - > rx_buffer_wr ] , RX_FIFO_HI_WATERMARK , NULL ) = = 0 ) ? RX_FIFO_HI_WATERMARK : 0 ;
2012-09-17 04:33:30 +02:00
rfm22_deassertCs ( ) ;
rfm22_releaseBus ( ) ;
2012-03-18 18:22:05 +01:00
}
2012-04-06 05:24:50 +02:00
// CRC error .. discard the received data
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > int_status1 & RFM22_is1_icrerror )
return RFM22B_EVENT_ERROR ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// Valid packet received
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > int_status1 & RFM22_is1_ipkvalid )
2012-04-06 05:24:50 +02:00
{
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// read the total length of the packet data
2012-09-05 07:56:48 +02:00
uint32_t len = rfm22_read ( RFM22_received_packet_length ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// their must still be data in the RX FIFO we need to get
2012-09-23 17:36:38 +02:00
if ( rfm22b_dev - > rx_buffer_wr < len )
2012-03-18 18:22:05 +01:00
{
2012-09-23 17:36:38 +02:00
int32_t bytes_to_read = len - rfm22b_dev - > rx_buffer_wr ;
2012-04-06 05:24:50 +02:00
// Fetch the data from the RX FIFO
2012-09-05 07:56:48 +02:00
rfm22_claimBus ( ) ;
rfm22_assertCs ( ) ;
2012-09-15 04:30:02 +02:00
PIOS_SPI_TransferByte ( rfm22b_dev - > spi_id , RFM22_fifo_access & 0x7F ) ;
2012-09-23 17:36:38 +02:00
rfm22b_dev - > rx_buffer_wr + = ( PIOS_SPI_TransferBlock ( rfm22b_dev - > spi_id , OUT_FF , ( uint8_t * ) & rx_buffer [ rfm22b_dev - > rx_buffer_wr ] , bytes_to_read , NULL ) = = 0 ) ? bytes_to_read : 0 ;
2012-09-05 07:56:48 +02:00
rfm22_deassertCs ( ) ;
rfm22_releaseBus ( ) ;
2012-03-18 18:22:05 +01:00
}
2012-09-05 07:56:48 +02:00
2012-09-23 17:36:38 +02:00
if ( rfm22b_dev - > rx_buffer_wr ! = len )
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_ERROR ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// we have a valid received packet
2012-03-18 18:22:05 +01:00
2012-09-23 17:36:38 +02:00
if ( rfm22b_dev - > rx_buffer_wr > 0 )
2012-03-18 18:22:05 +01:00
{
2012-04-18 02:36:05 +02:00
// Add the rssi and afc to the end of the packet.
2012-09-23 17:36:38 +02:00
rx_buffer [ rfm22b_dev - > rx_buffer_wr + + ] = rfm22b_dev - > rssi_dBm ;
rx_buffer [ rfm22b_dev - > rx_buffer_wr + + ] = rfm22b_dev - > rx_packet_start_afc_Hz ;
// Swap the Rx packets.
if ( rfm22b_dev - > rx_packet_prev = = NULL )
{
rfm22b_dev - > rx_packet_prev = rfm22b_dev - > rx_packet ;
rfm22b_dev - > rx_packet = rfm22b_dev - > rx_packet_next ;
rfm22b_dev - > rx_packet_len = rfm22b_dev - > rx_buffer_wr ;
// Signal the receive thread.
xSemaphoreGive ( rfm22b_dev - > rxsem ) ;
}
rfm22b_dev - > rx_buffer_wr = 0 ;
2012-03-18 18:22:05 +01:00
}
2012-09-17 04:33:30 +02:00
// Start a new transaction
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_RX_COMPLETE ;
2012-03-18 18:22:05 +01:00
}
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_NUM_EVENTS ;
2012-03-18 18:22:05 +01:00
}
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_txData ( struct pios_rfm22b_dev * rfm22b_dev )
2012-03-18 18:22:05 +01:00
{
2012-09-17 04:33:30 +02:00
// Read the device status registers
if ( ! rfm22_readStatus ( rfm22b_dev ) )
2012-09-23 05:07:50 +02:00
{
// Free the tx packet
PHReleaseTXPacket ( pios_packet_handler , rfm22b_dev - > tx_packet ) ;
rfm22b_dev - > tx_packet = 0 ;
rfm22b_dev - > tx_data_wr = rfm22b_dev - > tx_data_rd = 0 ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_ERROR ;
2012-09-23 05:07:50 +02:00
}
2012-04-06 05:24:50 +02:00
// FIFO under/over flow error. Back to RX mode.
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > device_status & ( RFM22_ds_ffunfl | RFM22_ds_ffovfl ) )
2012-04-06 05:24:50 +02:00
{
2012-09-23 05:07:50 +02:00
// Free the tx packet
PHReleaseTXPacket ( pios_packet_handler , rfm22b_dev - > tx_packet ) ;
rfm22b_dev - > tx_packet = 0 ;
rfm22b_dev - > tx_data_wr = rfm22b_dev - > tx_data_rd = 0 ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_ERROR ;
2012-04-06 05:24:50 +02:00
}
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// TX FIFO almost empty, it needs filling up
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > int_status1 & RFM22_is1_ixtffaem )
2012-04-06 05:24:50 +02:00
{
// top-up the rf chips TX FIFO buffer
2012-09-23 05:07:50 +02:00
uint8_t * tx_buffer = ( uint8_t * ) ( rfm22b_dev - > tx_packet ) ;
2012-04-06 05:24:50 +02:00
uint16_t max_bytes = FIFO_SIZE - TX_FIFO_LO_WATERMARK - 1 ;
2012-09-02 04:24:42 +02:00
rfm22_claimBus ( ) ;
2012-09-05 07:25:06 +02:00
rfm22_assertCs ( ) ;
PIOS_SPI_TransferByte ( g_rfm22b_dev - > spi_id , RFM22_fifo_access | 0x80 ) ;
2012-09-23 05:07:50 +02:00
int bytes_to_write = ( rfm22b_dev - > tx_data_wr - rfm22b_dev - > tx_data_rd ) ;
2012-09-02 04:24:42 +02:00
bytes_to_write = ( bytes_to_write > max_bytes ) ? max_bytes : bytes_to_write ;
2012-09-23 05:07:50 +02:00
PIOS_SPI_TransferBlock ( g_rfm22b_dev - > spi_id , & tx_buffer [ rfm22b_dev - > tx_data_rd ] , NULL , bytes_to_write , NULL ) ;
rfm22b_dev - > tx_data_rd + = bytes_to_write ;
2012-09-05 07:25:06 +02:00
rfm22_deassertCs ( ) ;
2012-09-02 04:24:42 +02:00
rfm22_releaseBus ( ) ;
2012-03-18 18:22:05 +01:00
}
2012-04-06 05:24:50 +02:00
// Packet has been sent
2012-10-03 05:59:43 +02:00
else if ( rfm22b_dev - > int_status1 & RFM22_is1_ipksent )
2012-03-18 18:22:05 +01:00
{
2012-09-23 05:07:50 +02:00
// Free the tx packet
PHReleaseTXPacket ( pios_packet_handler , rfm22b_dev - > tx_packet ) ;
rfm22b_dev - > tx_packet = 0 ;
rfm22b_dev - > tx_data_wr = rfm22b_dev - > tx_data_rd = 0 ;
2012-09-17 04:33:30 +02:00
// Start a new transaction
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_TX_COMPLETE ;
2012-03-18 18:22:05 +01:00
}
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_NUM_EVENTS ;
2012-03-18 18:22:05 +01:00
}
// ************************************
// return the current mode
int8_t rfm22_currentMode ( void )
{
2012-09-15 04:30:02 +02:00
return g_rfm22b_dev - > state ;
2012-03-18 18:22:05 +01:00
}
2012-08-25 04:25:02 +02:00
// return true if we are transmitting
2012-03-18 18:22:05 +01:00
bool rfm22_transmitting ( void )
{
2012-09-15 04:30:02 +02:00
return ( g_rfm22b_dev - > state = = RFM22B_STATE_TX_DATA ) ;
2012-03-18 18:22:05 +01:00
}
2012-08-25 04:25:02 +02:00
// return true if the channel is clear to transmit on
2012-03-18 18:22:05 +01:00
bool rfm22_channelIsClear ( void )
{
2012-09-17 04:33:30 +02:00
if ( g_rfm22b_dev - > state ! = RFM22B_STATE_RX_MODE & & g_rfm22b_dev - > state ! = RFM22B_STATE_WAIT_PREAMBLE & & g_rfm22b_dev - > state ! = RFM22B_STATE_WAIT_SYNC )
2012-04-06 05:24:50 +02:00
// we are receiving something or we are transmitting or we are scanning the spectrum
2012-08-25 04:25:02 +02:00
return false ;
2012-03-18 18:22:05 +01:00
2012-08-25 04:25:02 +02:00
return true ;
2012-03-18 18:22:05 +01:00
}
// ************************************
// set/get the frequency calibration value
void rfm22_setFreqCalibration ( uint8_t value )
{
2012-09-23 05:07:50 +02:00
rfm22_write ( RFM22_xtal_osc_load_cap , value ) ;
2012-03-18 18:22:05 +01:00
}
// ************************************
2012-09-17 04:33:30 +02:00
// Initialise this hardware layer module and the rf module
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_init ( struct pios_rfm22b_dev * rfm22b_dev )
2012-03-18 18:22:05 +01:00
{
2012-09-17 04:33:30 +02:00
uint32_t id = rfm22b_dev - > deviceID ;
uint32_t min_frequency_hz = rfm22b_dev - > cfg . minFrequencyHz ;
uint32_t max_frequency_hz = rfm22b_dev - > cfg . maxFrequencyHz ;
uint32_t freq_hop_step_size = 50000 ;
2012-03-18 18:22:05 +01:00
// software reset the RF chip .. following procedure according to Si4x3x Errata (rev. B)
2012-09-17 04:33:30 +02:00
rfm22_write ( RFM22_op_and_func_ctrl1 , RFM22_opfc1_swres ) ;
2012-03-18 18:22:05 +01:00
2012-08-25 04:25:02 +02:00
// wait 26ms
PIOS_DELAY_WaitmS ( 26 ) ;
2012-03-18 18:22:05 +01:00
for ( int i = 50 ; i > 0 ; i - - )
{
2012-08-25 04:25:02 +02:00
// wait 1ms
PIOS_DELAY_WaitmS ( 1 ) ;
2012-03-18 18:22:05 +01:00
// read the status registers
2012-09-17 04:33:30 +02:00
rfm22b_dev - > int_status1 = rfm22_read ( RFM22_interrupt_status1 ) ;
rfm22b_dev - > int_status2 = rfm22_read ( RFM22_interrupt_status2 ) ;
if ( rfm22b_dev - > int_status2 & RFM22_is2_ichiprdy ) break ;
2012-03-18 18:22:05 +01:00
}
// ****************
// read status - clears interrupt
2012-09-17 04:33:30 +02:00
rfm22b_dev - > device_status = rfm22_read ( RFM22_device_status ) ;
rfm22b_dev - > int_status1 = rfm22_read ( RFM22_interrupt_status1 ) ;
rfm22b_dev - > int_status2 = rfm22_read ( RFM22_interrupt_status2 ) ;
rfm22b_dev - > ezmac_status = rfm22_read ( RFM22_ezmac_status ) ;
2012-03-18 18:22:05 +01:00
// disable all interrupts
rfm22_write ( RFM22_interrupt_enable1 , 0x00 ) ;
rfm22_write ( RFM22_interrupt_enable2 , 0x00 ) ;
// ****************
2012-09-17 04:33:30 +02:00
rfm22b_dev - > device_status = rfm22b_dev - > int_status1 = rfm22b_dev - > int_status2 = rfm22b_dev - > ezmac_status = 0 ;
2012-03-18 18:22:05 +01:00
2012-09-23 17:36:38 +02:00
rfm22b_dev - > rx_buffer_wr = 0 ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
rfm22b_dev - > tx_data_rd = rfm22b_dev - > tx_data_wr = 0 ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
rfm22b_dev - > frequency_hop_channel = 0 ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
rfm22b_dev - > afc_correction_Hz = 0 ;
2012-03-18 18:22:05 +01:00
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-09-25 05:51:34 +02:00
2012-03-18 18:22:05 +01:00
// ****************
// read the RF chip ID bytes
2012-09-23 05:07:50 +02:00
// read the device type
uint8_t device_type = rfm22_read ( RFM22_DEVICE_TYPE ) & RFM22_DT_MASK ;
// read the device version
uint8_t device_version = rfm22_read ( RFM22_DEVICE_VERSION ) & RFM22_DV_MASK ;
2012-03-18 18:22:05 +01:00
# if defined(RFM22_DEBUG)
DEBUG_PRINTF ( 2 , " rf device type: %d \n \r " , device_type ) ;
DEBUG_PRINTF ( 2 , " rf device version: %d \n \r " , device_version ) ;
# endif
if ( device_type ! = 0x08 )
{
# if defined(RFM22_DEBUG)
DEBUG_PRINTF ( 2 , " rf device type: INCORRECT - should be 0x08 \n \r " ) ;
# endif
2012-09-17 04:33:30 +02:00
// incorrect RF module type
return RFM22B_EVENT_FATAL_ERROR ;
2012-03-18 18:22:05 +01:00
}
2012-09-17 04:33:30 +02:00
if ( device_version ! = RFM22_DEVICE_VERSION_B1 )
2012-03-18 18:22:05 +01:00
{
# if defined(RFM22_DEBUG)
DEBUG_PRINTF ( 2 , " rf device version: INCORRECT \n \r " ) ;
# endif
2012-09-17 04:33:30 +02:00
// incorrect RF module version
return RFM22B_EVENT_FATAL_ERROR ;
2012-03-18 18:22:05 +01:00
}
// ****************
// set the minimum and maximum carrier frequency allowed
if ( min_frequency_hz < RFM22_MIN_CARRIER_FREQUENCY_HZ ) min_frequency_hz = RFM22_MIN_CARRIER_FREQUENCY_HZ ;
else
if ( min_frequency_hz > RFM22_MAX_CARRIER_FREQUENCY_HZ ) min_frequency_hz = RFM22_MAX_CARRIER_FREQUENCY_HZ ;
if ( max_frequency_hz < RFM22_MIN_CARRIER_FREQUENCY_HZ ) max_frequency_hz = RFM22_MIN_CARRIER_FREQUENCY_HZ ;
else
if ( max_frequency_hz > RFM22_MAX_CARRIER_FREQUENCY_HZ ) max_frequency_hz = RFM22_MAX_CARRIER_FREQUENCY_HZ ;
if ( min_frequency_hz > max_frequency_hz )
{ // swap them over
uint32_t tmp = min_frequency_hz ;
min_frequency_hz = max_frequency_hz ;
max_frequency_hz = tmp ;
}
// ****************
// calibrate our RF module to be exactly on frequency .. different for every module
2012-09-23 05:07:50 +02:00
rfm22_write ( RFM22_xtal_osc_load_cap , OSC_LOAD_CAP ) ;
2012-03-18 18:22:05 +01:00
// ****************
// disable Low Duty Cycle Mode
rfm22_write ( RFM22_op_and_func_ctrl2 , 0x00 ) ;
2012-09-23 05:07:50 +02:00
// 1MHz clock output
rfm22_write ( RFM22_cpu_output_clk , RFM22_coc_1MHz ) ;
2012-03-18 18:22:05 +01:00
2012-09-23 05:07:50 +02:00
// READY mode
rfm22_write ( RFM22_op_and_func_ctrl1 , RFM22_opfc1_xton ) ;
2012-03-18 18:22:05 +01:00
// choose the 3 GPIO pin functions
2012-09-23 05:07:50 +02:00
// GPIO port use default value
rfm22_write ( RFM22_io_port_config , RFM22_io_port_default ) ;
2012-09-17 04:33:30 +02:00
if ( rfm22b_dev - > cfg . gpio_direction = = GPIO0_TX_GPIO1_RX ) {
2012-09-05 06:22:56 +02:00
rfm22_write ( RFM22_gpio0_config , RFM22_gpio0_config_drv3 | RFM22_gpio0_config_txstate ) ; // GPIO0 = TX State (to control RF Switch)
rfm22_write ( RFM22_gpio1_config , RFM22_gpio1_config_drv3 | RFM22_gpio1_config_rxstate ) ; // GPIO1 = RX State (to control RF Switch)
} else {
rfm22_write ( RFM22_gpio0_config , RFM22_gpio0_config_drv3 | RFM22_gpio0_config_rxstate ) ; // GPIO0 = TX State (to control RF Switch)
rfm22_write ( RFM22_gpio1_config , RFM22_gpio1_config_drv3 | RFM22_gpio1_config_txstate ) ; // GPIO1 = RX State (to control RF Switch)
}
2012-03-18 18:22:05 +01:00
rfm22_write ( RFM22_gpio2_config , RFM22_gpio2_config_drv3 | RFM22_gpio2_config_cca ) ; // GPIO2 = Clear Channel Assessment
// ****************
2012-04-06 05:24:50 +02:00
// initialize the frequency hopping step size
2012-03-18 18:22:05 +01:00
freq_hop_step_size / = 10000 ; // in 10kHz increments
if ( freq_hop_step_size > 255 ) freq_hop_step_size = 255 ;
2012-09-23 05:07:50 +02:00
rfm22b_dev - > frequency_hop_step_size_reg = freq_hop_step_size ;
2012-03-18 18:22:05 +01:00
// FIFO mode, GFSK modulation
uint8_t fd_bit = rfm22_read ( RFM22_modulation_mode_control2 ) & RFM22_mmc2_fd ;
rfm22_write ( RFM22_modulation_mode_control2 , RFM22_mmc2_trclk_clk_none | RFM22_mmc2_dtmod_fifo | fd_bit | RFM22_mmc2_modtyp_gfsk ) ;
// setup to read the internal temperature sensor
2012-04-06 05:24:50 +02:00
// ADC used to sample the temperature sensor
2012-09-23 05:07:50 +02:00
uint8_t adc_config = RFM22_ac_adcsel_temp_sensor | RFM22_ac_adcref_bg ;
2012-04-06 05:24:50 +02:00
rfm22_write ( RFM22_adc_config , adc_config ) ;
// adc offset
rfm22_write ( RFM22_adc_sensor_amp_offset , 0 ) ;
2012-09-30 17:04:36 +02:00
// temp sensor calibration .. <20> 40C to +64C 0.5C resolution
2012-04-06 05:24:50 +02:00
rfm22_write ( RFM22_temp_sensor_calib , RFM22_tsc_tsrange0 | RFM22_tsc_entsoffs ) ;
// temp sensor offset
rfm22_write ( RFM22_temp_value_offset , 0 ) ;
// start an ADC conversion
rfm22_write ( RFM22_adc_config , adc_config | RFM22_ac_adcstartbusy ) ;
// set the RSSI threshold interrupt to about -90dBm
rfm22_write ( RFM22_rssi_threshold_clear_chan_indicator , ( - 90 + 122 ) * 2 ) ;
2012-03-18 18:22:05 +01:00
// enable the internal Tx & Rx packet handlers (without CRC)
rfm22_write ( RFM22_data_access_control , RFM22_dac_enpacrx | RFM22_dac_enpactx ) ;
2012-04-06 05:24:50 +02:00
// x-nibbles tx preamble
rfm22_write ( RFM22_preamble_length , TX_PREAMBLE_NIBBLES ) ;
// x-nibbles rx preamble detection
rfm22_write ( RFM22_preamble_detection_ctrl1 , RX_PREAMBLE_NIBBLES < < 3 ) ;
2012-03-18 18:22:05 +01:00
2012-04-11 05:22:53 +02:00
# ifdef PIOS_RFM22_NO_HEADER
2012-04-06 05:24:50 +02:00
// header control - we are not using the header
rfm22_write ( RFM22_header_control1 , RFM22_header_cntl1_bcen_none | RFM22_header_cntl1_hdch_none ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// no header bytes, synchronization word length 3, 2, 1 & 0 used, packet length included in header.
rfm22_write ( RFM22_header_control2 , RFM22_header_cntl2_hdlen_none |
RFM22_header_cntl2_synclen_3210 | ( ( TX_PREAMBLE_NIBBLES > > 8 ) & 0x01 ) ) ;
2012-04-11 05:22:53 +02:00
# else
// header control - using a 4 by header with broadcast of 0xffffffff
rfm22_write ( RFM22_header_control1 ,
RFM22_header_cntl1_bcen_0 |
RFM22_header_cntl1_bcen_1 |
RFM22_header_cntl1_bcen_2 |
RFM22_header_cntl1_bcen_3 |
RFM22_header_cntl1_hdch_0 |
RFM22_header_cntl1_hdch_1 |
RFM22_header_cntl1_hdch_2 |
RFM22_header_cntl1_hdch_3 ) ;
// Check all bit of all bytes of the header
rfm22_write ( RFM22_header_enable0 , 0xff ) ;
rfm22_write ( RFM22_header_enable1 , 0xff ) ;
rfm22_write ( RFM22_header_enable2 , 0xff ) ;
rfm22_write ( RFM22_header_enable3 , 0xff ) ;
// Set the ID to be checked
2012-04-18 02:36:05 +02:00
rfm22_write ( RFM22_check_header0 , id & 0xff ) ;
rfm22_write ( RFM22_check_header1 , ( id > > 8 ) & 0xff ) ;
rfm22_write ( RFM22_check_header2 , ( id > > 16 ) & 0xff ) ;
rfm22_write ( RFM22_check_header3 , ( id > > 24 ) & 0xff ) ;
2012-04-11 05:22:53 +02:00
// 4 header bytes, synchronization word length 3, 2, 1 & 0 used, packet length included in header.
rfm22_write ( RFM22_header_control2 ,
RFM22_header_cntl2_hdlen_3210 |
RFM22_header_cntl2_synclen_3210 |
( ( TX_PREAMBLE_NIBBLES > > 8 ) & 0x01 ) ) ;
# endif
2012-04-06 05:24:50 +02:00
2012-09-23 05:07:50 +02:00
// sync word
2012-04-06 05:24:50 +02:00
rfm22_write ( RFM22_sync_word3 , SYNC_BYTE_1 ) ;
rfm22_write ( RFM22_sync_word2 , SYNC_BYTE_2 ) ;
rfm22_write ( RFM22_sync_word1 , SYNC_BYTE_3 ) ;
rfm22_write ( RFM22_sync_word0 , SYNC_BYTE_4 ) ;
2012-03-18 18:22:05 +01:00
rfm22_write ( RFM22_agc_override1 , RFM22_agc_ovr1_agcen ) ;
2012-04-06 05:24:50 +02:00
// set frequency hopping channel step size (multiples of 10kHz)
2012-09-23 05:07:50 +02:00
rfm22_write ( RFM22_frequency_hopping_step_size , rfm22b_dev - > frequency_hop_step_size_reg ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// set our nominal carrier frequency
2012-09-23 05:07:50 +02:00
rfm22_setNominalCarrierFrequency ( rfm22b_dev , ( min_frequency_hz + max_frequency_hz ) / 2 ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// set the tx power
2012-09-17 04:33:30 +02:00
rfm22_write ( RFM22_tx_power , RFM22_tx_pwr_papeaken | RFM22_tx_pwr_papeaklvl_0 | RFM22_tx_pwr_lna_sw | rfm22b_dev - > tx_power ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// TX FIFO Almost Full Threshold (0 - 63)
rfm22_write ( RFM22_tx_fifo_control1 , TX_FIFO_HI_WATERMARK ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// TX FIFO Almost Empty Threshold (0 - 63)
rfm22_write ( RFM22_tx_fifo_control2 , TX_FIFO_LO_WATERMARK ) ;
2012-03-18 18:22:05 +01:00
2012-04-06 05:24:50 +02:00
// RX FIFO Almost Full Threshold (0 - 63)
rfm22_write ( RFM22_rx_fifo_control , RX_FIFO_HI_WATERMARK ) ;
2012-03-18 18:22:05 +01:00
2012-09-17 04:33:30 +02:00
rfm22_setFreqCalibration ( rfm22b_dev - > cfg . RFXtalCap ) ;
2012-09-23 05:07:50 +02:00
rfm22_setNominalCarrierFrequency ( rfm22b_dev , rfm22b_dev - > cfg . frequencyHz ) ;
2012-09-17 04:33:30 +02:00
rfm22_setDatarate ( rfm22b_dev - > cfg . maxRFBandwidth , true ) ;
2012-09-23 05:07:50 +02:00
return RFM22B_EVENT_INITIALIZED ;
2012-09-17 04:33:30 +02:00
}
2012-09-25 05:51:34 +02:00
static enum pios_rfm22b_event rfm22_timeout ( struct pios_rfm22b_dev * rfm22b_dev )
{
rfm22b_dev - > resets + + ;
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-09-25 05:51:34 +02:00
return RFM22B_EVENT_TX_START ;
}
2012-09-17 04:33:30 +02:00
static enum pios_rfm22b_event rfm22_error ( struct pios_rfm22b_dev * rfm22b_dev )
{
2012-09-25 05:51:34 +02:00
rfm22b_dev - > resets + + ;
2012-10-03 04:52:21 +02:00
rfm22b_dev - > packet_start_ticks = 0 ;
2012-09-17 04:33:30 +02:00
return RFM22B_EVENT_INITIALIZE ;
}
/**
* A fatal error has occured in the state machine .
* this should not happen .
* \ parem [ in ] rfm22b_dev The device structure
* \ return enum pios_rfm22b_event The next event to inject
*/
static enum pios_rfm22b_event rfm22_fatal_error ( struct pios_rfm22b_dev * rfm22b_dev )
{
// RF module error .. flash the LED's
for ( unsigned int j = 0 ; j < 16 ; j + + )
{
USB_LED_ON ;
LINK_LED_ON ;
RX_LED_OFF ;
TX_LED_OFF ;
PIOS_DELAY_WaitmS ( 200 ) ;
USB_LED_OFF ;
LINK_LED_OFF ;
RX_LED_ON ;
TX_LED_ON ;
PIOS_DELAY_WaitmS ( 200 ) ;
}
PIOS_DELAY_WaitmS ( 1000 ) ;
PIOS_Assert ( 0 ) ;
return RFM22B_EVENT_FATAL_ERROR ;
2012-03-18 18:22:05 +01:00
}
// ************************************
# endif
/**
* @ }
* @ }
*/