Newer
Older
/****************************************************************************
* drivers/wireless/generic/si4463.c
* Copyright (C) 2017-2018 Sebastien Lorquet. All rights reserved.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
* Author: Sebastien Lorquet <sebastien@lorquet.fr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <nuttx/semaphore.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/spi/spi.h>
#include <nuttx/wireless/generic/si4463.h>
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
#ifndef CONFIG_SCHED_HPWORK
#error High priority work queue required in this driver
#endif
#ifndef CONFIG_GENERICRADIO_SI4463_SPIMODE
# define CONFIG_GENERICRADIO_SI4463_SPIMODE SPIDEV_MODE0
#ifndef CONFIG_GENERICRADIO_SI4463_FREQUENCY
# define CONFIG_GENERICRADIO_SI4463_FREQUENCY 10000000 /* max 10 MHz */
/* Default to a 32-bit preamble length */
#ifndef CONFIG_GENERICRADIO_SI4463_DEFAULT_PREAMBLELEN
#define CONFIG_GENERICRADIO_SI4463_DEFAULT_PREAMBLELEN 32
#warning preamble length not defined, using 32
#elif CONFIG_GENERICRADIO_SI4463_DEFAULT_PREAMBLELEN == 0
#define CONFIG_GENERICRADIO_SI4463_DEFAULT_PREAMBLELEN 32
#warning preamble length was 0, using 32
#endif
/* Default to no preset base frequency */
#ifndef CONFIG_GENERICRADIO_SI4463_DEFAULT_FREQ
#define CONFIG_GENERICRADIO_SI4463_DEFAULT_FREQ 0
#endif
#ifndef CONFIG_GENERICRADIO_SI4463_DEFAULT_CHSPC
#define CONFIG_GENERICRADIO_SI4463_DEFAULT_CHSPC 0
#endif
#ifndef CONFIG_SPI_EXCHANGE
# error CONFIG_SPI_EXCHANGE required for this driver
#endif
/* Values used to know what RF registers should be reprogrammed */
#define SI4463_APPLY_MODTYPE (1 << 0)
#define SI4463_APPLY_BASEFREQ (1 << 1)
#define SI4463_APPLY_DEVIATION (1 << 2)
#define SI4463_APPLY_CHANSPACING (1 << 3)
#define SI4463_APPLY_DATARATE (1 << 4)
#define SI4463_APPLY_BT (1 << 5)
#define SI4463_APPLY_RXBW (1 << 6)
#define SI4463_APPLY_TXFILT (1 << 10)
#define SI4463_APPLY_RXFILT (1 << 11)
/****************************************************************************
****************************************************************************/
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* A SI4463 device instance */
struct si4463_dev_s
{
struct genradio_dev_s genradio; /* The public device instance */
FAR struct spi_dev_s *spi; /* Underlying SPI bus */
int spiid; /* Device identifier within type SPIDEVTYPE_GENRADIO */
struct work_s irqwork; /* Interrupt continuation work queue support */
FAR const struct si4463_lower_s *lower; /* Low-level MCU-specific support */
uint32_t xtal; /* Frequency of the attached oscillator */
bool hdr_done; /* Set to TRUE when field 1 (header) has been received. */
#if defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L1 )
uint8_t header[1]; /* Packet header, si4463 field 1, fixed size */
#elif defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L2B ) || \
defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L2L )
uint8_t header[2];
#endif
/* Requested parameters, input to modem calculator */
uint8_t requested_modtype; /* Requested modulation */
uint32_t requested_datarate; /* Requested data rate in milli bps */
uint32_t requested_basefreq; /* Requested base frequency in Hz */
uint32_t requested_deviation; /* Requested FSK deviation in mHz */
uint32_t requested_chanspacing; /* Requested channel spacing in mHz */
uint32_t requested_bt; /* Requested GFSK parameter */
uint32_t requested_rxbw; /* Requested RX bandwidth */
};
/****************************************************************************
* Private function prototypes
****************************************************************************/
static void si4463_lock (FAR struct spi_dev_s *spi);
static int si4463_initialize(FAR struct si4463_dev_s *dev, int txpin,
int rxpin);
static void si4463_irqworker (FAR void *arg);
static int si4463_interrupt (int irq, FAR void *context, FAR void *arg);
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
static int si4463_setbasefreq (FAR struct genradio_dev_s *dev,
uint32_t Hz);
static int si4463_setchanspacing (FAR struct genradio_dev_s *dev,
uint32_t mHz);
static int si4463_setchannel (FAR struct genradio_dev_s *dev,
int32_t chan);
static int si4463_setdatarate (FAR struct genradio_dev_s *dev,
uint32_t bps);
static int si4463_ioctl (FAR struct genradio_dev_s *dev, int cmd,
unsigned long arg);
static int si4463_setmodulation (FAR struct genradio_dev_s *dev,
uint32_t mod);
static int si4463_setmodulationindex(FAR struct genradio_dev_s *dev,
uint32_t ppm);
static int si4463_setdeviation (FAR struct genradio_dev_s *dev,
uint32_t mHz);
static int si4463_setfilterbt (FAR struct genradio_dev_s *dev,
uint32_t bt);
static int si4463_setpreamblelength (FAR struct genradio_dev_s *dev,
uint32_t bits);
static int si4463_setsyncword (FAR struct genradio_dev_s *dev,
FAR uint8_t *data, uint32_t bits);
static int si4463_setrxbandwidth (FAR struct genradio_dev_s *dev,
uint32_t mHz);
static int si4463_getrssi (FAR struct genradio_dev_s *dev,
FAR int32_t *mB);
static int si4463_getlqi (FAR struct genradio_dev_s *dev,
FAR int32_t *lqi);
static int si4463_rxenable (FAR struct genradio_dev_s *dev,
int state);
static int si4463_settxpower (FAR struct genradio_dev_s *dev,
int32_t mB);
FAR const uint8_t *packet, size_t len);
/****************************************************************************
* Global variables
****************************************************************************/
struct genradio_devops_s si4463_devops =
{
si4463_setbasefreq, NULL,
si4463_setchanspacing, NULL,
si4463_setchannel, NULL,
si4463_setdatarate, NULL,
si4463_setmodulation, NULL,
si4463_setmodulationindex, NULL,
si4463_setdeviation, NULL,
si4463_setfilterbt, NULL,
si4463_setpreamblelength, NULL,
si4463_setsyncword, NULL,
si4463_setrxbandwidth, NULL,
si4463_getrssi,
si4463_getlqi,
si4463_rxenable,
#ifdef CONFIG_GENERICRADIO_SI4463_USE_WDS_CONFIG
#include "si4463_config.h"
static const uint8_t si4463_config_wds[] = RADIO_CONFIGURATION_DATA_ARRAY;
#endif
/****************************************************************************
* Private functions
****************************************************************************/
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/* htobel: convert uint32_t from host order to big endian
* htobes: convert uint16_t from host order to big endian
* betohl: convert uint32_t from big endian to host order
* betohs: convert uint16_t from big endian to host order
*/
#ifdef CONFIG_ENDIAN_BIG
#define htobel(n) (n)
#define htobes(n) (n)
#define betohl(n) (n)
#define betohs(n) (n)
#else
static inline uint32_t htobel(uint32_t n)
{
return ( n &0xFF)<<24 |
((n>> 8)&0xFF)<<16 |
((n>>16)&0xFF)<< 8 |
((n>>24)&0xFF);
}
static inline uint16_t htobes(uint16_t n)
{
return ( (n&0xFF)<<8 | n>>8 );
}
#define betohl(n) htobel(n)
#define betohs(n) htobes(n)
#endif
/* Hardware access routines */
/****************************************************************************
*
* Description:
* Acquire exclusive access to the shared SPI bus.
*
****************************************************************************/
static void si4463_lock(FAR struct spi_dev_s *spi)
{
SPI_LOCK (spi, 1);
SPI_SETBITS (spi, 8);
SPI_SETMODE (spi, CONFIG_GENERICRADIO_SI4463_SPIMODE);
SPI_SETFREQUENCY(spi, CONFIG_GENERICRADIO_SI4463_FREQUENCY);
}
/****************************************************************************
*
* Description:
* Release exclusive access to the shared SPI bus.
*
****************************************************************************/
static inline void si4463_unlock(FAR struct spi_dev_s *spi)
{
SPI_LOCK(spi,0);
}
/****************************************************************************
* Send a command to a si4463 device
*
****************************************************************************/
static int si4463_command(FAR struct si4463_dev_s *dev, uint8_t command,
FAR void *param , uint16_t paramlen,
FAR void *response, uint16_t rsplen)
uint8_t pollbuf[2];
int retries = SI4463_RETRIES;
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), true);
/* Send command */
SPI_SEND (dev->spi, command);
/* Send additional parameters */
if(param && paramlen)
{
SPI_SNDBLOCK(dev->spi, (uint8_t*)param, paramlen);
}
/* Execute */
SPI_SELECT(dev->spi, SPIDEV_GENRADIO(dev->spiid), false);
/* Then, poll CTS until RX data is available */
/* wait tSW = 80 ns */
up_udelay(1);
/* Store command at each attemt, it will get overwritten */
pollbuf[0] = SI4463_CMD_READ_CMD_BUFF;
pollbuf[1] = 0xFF;
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), true);
SPI_EXCHANGE(dev->spi, pollbuf, pollbuf, 2);
if (pollbuf[1] == 0xFF)
{
/* we're done */
/* command not completed yet */
SPI_SELECT(dev->spi, SPIDEV_GENRADIO(dev->spiid), false);
retries -= 1;
}
else
{
/* unexpected value! */
_err("Unexpected rx value when reading CTS!\n");
ret = -EIO; /* Transaction failed */
goto unlock;
{
_err("Command timeout!\n");
ret = -ETIMEDOUT;
goto unlock;
}
/* Continue by reading the response data */
if(response && rsplen)
{
SPI_RECVBLOCK(dev->spi, (uint8_t*)response, rsplen);
}
SPI_SELECT(dev->spi, SPIDEV_GENRADIO(dev->spiid), false);
return ret; /* Transaction finished */
/****************************************************************************
* Name: si4463_getfrr
*
* Description:
* Return the value of the SI4463 fast registers. The transaction is executed
* as a single burst to avoid the DMA setup/teardown delays and be as fast
* as possible.
*
****************************************************************************/
static int si4463_getfrr(FAR struct si4463_dev_s *dev, uint32_t firstreg,
FAR uint8_t *dest, size_t count)
{
static const uint8_t cmds[4] =
{
SI4463_CMD_FRR_A_READ,
SI4463_CMD_FRR_B_READ,
SI4463_CMD_FRR_C_READ,
SI4463_CMD_FRR_D_READ
};
uint8_t buf[5];
if(firstreg > 3 || count < 0 || count > 4)
}
buf[0] = cmds[firstreg];
si4463_lock (dev->spi);
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), true);
SPI_RECVBLOCK(dev->spi, buf, count + 1);
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), false);
si4463_unlock(dev->spi);
return 0;
}
/****************************************************************************
* Name: si4463_writetxfifo
*
* Description:
* Write data to the TX FIFO. There is no need to poll CTS.
*
****************************************************************************/
static int si4463_writetxfifo(FAR struct si4463_dev_s *dev,
FAR const uint8_t *data, size_t len)
if(len < 1)
{
return 0; /* Nothing to do and wommand will not work in that case */
}
si4463_lock (dev->spi);
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), true);
SPI_SEND (dev->spi, SI4463_CMD_WRITE_TX_FIFO);
SPI_SNDBLOCK (dev->spi, data, len);
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), false);
si4463_unlock(dev->spi);
return 0;
}
/****************************************************************************
* Name: si4463_readrxfifo
*
* Description:
* Read data from the RX FIFO. There is no need to poll CTS.
*
****************************************************************************/
static int si4463_readrxfifo(FAR struct si4463_dev_s *dev, FAR uint8_t *data,
size_t len)
si4463_lock (dev->spi);
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), true);
SPI_SEND (dev->spi, SI4463_CMD_READ_RX_FIFO);
SPI_RECVBLOCK(dev->spi, data, len);
SPI_SELECT (dev->spi, SPIDEV_GENRADIO(dev->spiid), false);
si4463_unlock(dev->spi);
return 0;
/****************************************************************************
* Name: si4463_getchipstatus
*
* Description:
* Return information about the execution of the last command.
*
****************************************************************************/
static int si4463_getchipstatus(FAR struct si4463_dev_s *dev)
{
struct si4463_cmd_getchipstatus_s cmd;
struct si4463_rsp_getchipstatus_s rsp;
int ret;
cmd.chip_clr_pend = ~CHIP_STATUS_CMD_ERROR; //clear cmd_error status only
ret = si4463_command(dev, SI4463_CMD_GET_CHIP_STATUS,
&cmd, sizeof(struct si4463_cmd_getchipstatus_s),
&rsp, sizeof(struct si4463_rsp_getchipstatus_s));
if (ret)
{
return ret;
}
if(rsp.chip_pend & CHIP_STATUS_CMD_ERROR)
{
_err("Command ID 0x%02X: error %d\n",
rsp.cmd_err_cmd_id, rsp.cmd_err_status);
if(!rsp.cmd_err_status)
{
return OK; /* Should not happen ??? */
}
switch(rsp.cmd_err_status)
{
case CMD_ERROR_BAD_COMMAND /*16*/ : return -EBADMSG;
case CMD_ERROR_BAD_ARG /*17*/ : return -EINVAL;
case CMD_ERROR_COMMAND_BUSY /*18*/ : return -EBUSY;
case CMD_ERROR_INVALID_STATE /*19*/ : return -EPROTO;
case CMD_ERROR_BAD_BOOTMODE /*49*/ : return -ENOSYS;
case CMD_ERROR_BAD_PROPERTY /*64*/ : return -ENOENT;
case CMD_ERROR_TIMEOUT /*240*/ : return -ETIMEDOUT;
}
return 0;
}
/****************************************************************************
* Return information about the current pending interrupts, then clear them.
*
****************************************************************************/
static int si4463_getintstatus(FAR struct si4463_dev_s *dev,
FAR uint8_t *phpend, FAR uint8_t *modempend,
FAR uint8_t *chippend)
{
struct si4463_cmd_getintstatus_s cmd;
struct si4463_rsp_getintstatus_s rsp;
int ret;
//Clear all pending ints after call
cmd.ph_clr_pend = 0;
cmd.modem_clr_pend = 0;
cmd.chip_clr_pend = 0;
ret = si4463_command(dev, SI4463_CMD_GET_INT_STATUS,
&cmd, sizeof(struct si4463_cmd_getintstatus_s),
&rsp, sizeof(struct si4463_rsp_getintstatus_s));
if(ret == 0)
{
ret = si4463_getchipstatus(dev);
}
if (ret != 0)
if(phpend)
{
*phpend = rsp.ph_pend;
}
if(modempend)
{
*modempend = rsp.modem_pend;
}
if(chippend)
{
*chippend = rsp.chip_pend;
}
return 0;
/****************************************************************************
* Name: si4463_getfifoinfo
*
* Description:
* Return the number of bytes in each fifo, and provide means to flush
* these FIFOs.
*
****************************************************************************/
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
static int si4463_getfifoinfo(FAR struct si4463_dev_s *priv,
bool clean_tx, bool clean_rx,
FAR uint8_t *txlen, FAR uint8_t *rxlen)
{
struct si4463_cmd_fifoinfo_s cmd_fifo;
struct si4463_rsp_fifoinfo_s rsp_fifo;
int ret;
cmd_fifo.fifo = 0;
if(clean_tx)
{
cmd_fifo.fifo |= FIFOINFO_CLEAR_TX;
}
if(clean_rx)
{
cmd_fifo.fifo |= FIFOINFO_CLEAR_RX;
}
ret = si4463_command(priv, SI4463_CMD_FIFO_INFO, &cmd_fifo, sizeof(cmd_fifo),
&rsp_fifo, sizeof(rsp_fifo));
if(ret == 0)
{
ret = si4463_getchipstatus(priv);
}
if(ret != 0)
{
return ret;
}
if(txlen)
{
*txlen = rsp_fifo.tx_fifo_space;
}
if(rxlen)
{
*rxlen = rsp_fifo.rx_fifo_count;
}
return ret;
}
/****************************************************************************
* Name: si4463_changestate
*
* Description:
* Transition the chip to a specific operating mode.
*
****************************************************************************/
static int si4463_changestate(FAR struct si4463_dev_s *priv, uint8_t state)
{
struct si4463_cmd_changestate_s cmd_chstate;
int ret;
cmd_chstate.next_state1 = state;
ret = si4463_command(priv, SI4463_CMD_CHANGE_STATE,
&cmd_chstate, sizeof(cmd_chstate), NULL, 0);
if(ret == 0)
{
ret = si4463_getchipstatus(priv);
}
return ret;
}
/****************************************************************************
* Name: si4463_setprop
*
* Description:
* Set the value of a SI4463 property (or successive properties)
*
****************************************************************************/
static int si4463_setprop(FAR struct si4463_dev_s *dev, uint16_t prop,
FAR uint8_t* val, size_t len)
{
struct si4463_cmd_setproperty_s cmd;
int ret;
{
return -E2BIG;
}
cmd.num_props = len;
cmd.start_prop = prop & 0xFF;
memcpy(&cmd.data, val, len);
ret = si4463_command(dev, SI4463_CMD_SET_PROPERTY,
&cmd,
sizeof(struct si4463_cmd_setproperty_s) -
SI4463_SETPROP_DATALEN + len,
if(ret == 0)
{
ret = si4463_getchipstatus(dev);
}
return ret;
}
/****************************************************************************
* Name: si4463_setprop_byte
*
* Description:
* Set the value of a single byte SI4463 property
*
****************************************************************************/
static inline int si4463_setprop_byte(FAR struct si4463_dev_s *dev,
uint16_t prop, uint8_t val)
{
return si4463_setprop(dev, prop, &val, 1);
}
/****************************************************************************
* Name: si4463_setprop_short
*
* Description:
* Set the value of a short (big endian) SI4463 property
*
****************************************************************************/
static inline int si4463_setprop_short(FAR struct si4463_dev_s *dev,
uint16_t prop, uint16_t val)
{
uint8_t arr[2];
arr[0] = val >> 8;
arr[1] = val & 0xFF;
return si4463_setprop(dev, prop, arr, 2);
}
/****************************************************************************
* Name: si4463_getprop
*
* Description:
* Return the value of a SI4463 property (or successive properties)
*
****************************************************************************/
static int si4463_getprop(FAR struct si4463_dev_s *dev, uint16_t prop,
FAR uint8_t*val, size_t len)
{
struct si4463_cmd_getproperty_s cmd;
int ret;
{
return -E2BIG;
}
cmd.num_props = len;
cmd.start_prop = prop & 0xFF;
ret = si4463_command(dev, SI4463_CMD_GET_PROPERTY,
&cmd, sizeof(struct si4463_cmd_getproperty_s),
val, len);
if(ret == 0)
{
ret = si4463_getchipstatus(dev);
}
return ret;
/****************************************************************************
* Name: si4463_getadcreading
*
* Description:
* Return the values read on the internal or external ADC lines.
*
****************************************************************************/
static int si4463_getadcreading(FAR struct si4463_dev_s *dev, int pin,
FAR uint16_t *gpio, FAR uint16_t *temp,
FAR uint16_t *vbat)
{
struct si4463_cmd_getadcreading_s cmd;
struct si4463_rsp_getadcreading_s rsp;
int ret;
cmd.adc_en = 0;
cmd.adc_cfg = 0;
if (pin < SI4463_IO0 || pin > SI4463_IO3)
{
_err("Invalid ADC pin %d\n", pin);
return -EINVAL;
}
cmd.adc_en |= ADC_EN_GPIO_EN;
cmd.adc_en &= ~ADC_EN_GPIO_PIN_MASK;
cmd.adc_en |= ADC_EN_GPIO_PIN(pin);
}
{
cmd.adc_en |= ADC_EN_TEMPERATURE_EN;
}
{
cmd.adc_en |= ADC_EN_BATTERY_VOLTAGE_EN;
cmd.adc_cfg &= ~ADC_CFG_GPIOATT_MASK;
cmd.adc_cfg |= ADC_CFG_GPIOATT_3P2;
}
if (!cmd.adc_en)
{
_err("No ADC reading selected!\n");
return -EINVAL;
}
/* Use the slow conversion rate */
cmd.adc_cfg &= ~ADC_CFG_UDTIME_MASK;
cmd.adc_cfg |= ADC_CFG_UDTIME_305HZ;
ret = si4463_command(dev, SI4463_CMD_GET_ADC_READING,
&cmd, sizeof(struct si4463_cmd_getadcreading_s),
&rsp, sizeof(struct si4463_rsp_getadcreading_s));
if(ret == 0)
{
ret = si4463_getchipstatus(dev);
}
if (ret != 0)
if(gpio)
{
*gpio = betohs(rsp.gpio_adc ) & ADC_VALUE_MASK;
}
if(temp)
{
*temp = betohs(rsp.temp_adc ) & ADC_VALUE_MASK;
}
if(vbat)
{
*vbat = betohs(rsp.battery_adc) & ADC_VALUE_MASK;
}
/****************************************************************************
* Name: si4463_packetconfig
*
* Description:
* Configure the packet handler. 3 configs are available at the moment.
* - 1 byte length in header, followed by data payload
* - 2 bytes big endian length in header, followed by data payload
* - 2 bytes lil endian length in header, followed by data payload
* All packets end with a 2-byte CRC16.
* The format is the same for TX and RX.
* Address bytes in header are not managed yet.
*
****************************************************************************/
static int si4463_packetconfig(FAR struct si4463_dev_s *dev)
{
int ret;
_info("Configuring packet handler\n");
Sebastien Lorquet
committed
do
{
/* Configure CRC */
Sebastien Lorquet
committed
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_CRC_CONFIG,
PKT_CRC_CONFIG_SEED_FFFF |
PKT_CRC_CONFIG_POLY_CCITT_16);
if(ret != 0)
{
break;
}
Sebastien Lorquet
committed
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_CONFIG1,
PKT_CONFIG1_CRC_INVERT);
if(ret != 0)
{
break;
}
/* Configure field 1 as a one or two bytes length field */
#if defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L1 )
Sebastien Lorquet
committed
ret = si4463_setprop_short(dev, SI4463_PROP_PKT_FIELD_1_LENGTH_0, 1);
#elif defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L2B ) || \
defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L2L )
Sebastien Lorquet
committed
ret = si4463_setprop_short(dev, SI4463_PROP_PKT_FIELD_1_LENGTH_0, 2);
Sebastien Lorquet
committed
if(ret != 0)
{
break;
}
Sebastien Lorquet
committed
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_FIELD_1_CONFIG, 0);
if(ret != 0)
{
break;
}
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_FIELD_1_CRC_CONFIG,
PKT_FIELD_CRC_CONFIG_START |
PKT_FIELD_CRC_CONFIG_ENABLE );
if(ret != 0)
{
break;
}
/* Configure field 2 - length will be set before tx */
Sebastien Lorquet
committed
ret = si4463_setprop_short(dev, SI4463_PROP_PKT_FIELD_2_LENGTH_0, 1);
if(ret != 0)
{
break;
}
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_FIELD_2_CONFIG, 0);
if(ret != 0)
{
break;
}
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_FIELD_2_CRC_CONFIG,
PKT_FIELD_CRC_CONFIG_ENABLE |
PKT_FIELD_CRC_CONFIG_CHECK |
PKT_FIELD_CRC_CONFIG_SEND);
if(ret != 0)
{
break;
}
Sebastien Lorquet
committed
ret = si4463_setprop_short(dev, SI4463_PROP_PKT_FIELD_3_LENGTH_0, 0);
if(ret != 0)
{
break;
}
/* Configure rx length: in field 1, defines length of field 2. */
#if defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L1 )
Sebastien Lorquet
committed
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_LEN, 2 | PKT_LEN_IN_FIFO |
PKT_LEN_SIZE_1);
#elif defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L2B )
Sebastien Lorquet
committed
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_LEN, 2 | PKT_LEN_IN_FIFO |
PKT_LEN_SIZE_2 | PKT_LEN_ENDIAN_BIG);
#elif defined( CONFIG_GENERICRADIO_SI4463_FRAMING_L2L )
Sebastien Lorquet
committed
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_LEN, 2 | PKT_LEN_IN_FIFO |
PKT_LEN_SIZE_2 | PKT_LEN_ENDIAN_LIL);
Sebastien Lorquet
committed
if(ret != 0)
{
break;
}
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_LEN_FIELD_SOURCE, 1);
if(ret != 0)
{
break;
}
ret = si4463_setprop_byte(dev, SI4463_PROP_PKT_LEN_ADJUST, 0);
}
while(0);
if(ret != 0)
{
_err("something failed\n", ret);
}
/****************************************************************************
* Name: si4463_initialize
*
* Description:
* Put the SI4463 in working order. Returns 0 if all is ok, else a negative
* errno value.
*
****************************************************************************/
static int si4463_initialize(FAR struct si4463_dev_s *dev,
int ret;
#ifndef CONFIG_GENERICRADIO_SI4463_USE_WDS_CONFIG
uint8_t regs[2];
struct si4463_cmd_pwrup_s pwrup;
Sebastien Lorquet
committed
int i;
struct si4463_cmdrsp_gpiopincfg_s gpio;
struct si4463_rsp_partinfo_s part;
struct si4463_rsp_funcinfo_s func;
/* check parameters */
if(papin < SI4463_IO0 || papin > SI4463_IO3)
{
_err("Invalid PA control pin %d\n", papin);
}
if(lnapin < SI4463_IO0 || lnapin > SI4463_IO3)
{
_err("Invalid LNA control pin %d\n", lnapin);
#ifndef CONFIG_GENERICRADIO_SI4463_USE_WDS_CONFIG
_info("power up...\n");
pwrup.boot_options = PWRUP_BOOTOPT_NO_PATCH | PWRUP_BOOTOPT_FUNC_PRO;
pwrup.xtal_options = PWRUP_XTALOPT_XTAL;
pwrup.xo_freq = htobel(dev->xtal);
ret = si4463_command(dev, SI4463_CMD_POWER_UP,
&pwrup, sizeof(struct si4463_cmd_pwrup_s), NULL, 0);
_err("Could not power up chip (errno %d)\n", ret);
return ret;
/* Clean any pending interrupt */
_info("clean up status...\n");
ret = si4463_getintstatus(dev, NULL, NULL, NULL);