mirror of
https://github.com/apache/nuttx.git
synced 2026-03-26 18:23:50 +08:00
wireless/cc1101: migrate to wlioc_rx_hdr_s and add operation modes
This commit refactors the CC1101 driver's read interface to comply with
the standard NuttX wireless character driver API and introduces extended
hardware operation modes.
- Migrate `cc1101_file_read` to accept and populate the standard
`struct wlioc_rx_hdr_s` instead of returning raw byte arrays.
- Implement `cc1101_calc_rssi_dbm_x100` to preserve the hardware's
0.5 dBm RSSI precision when scaling to 1/100 dBm units, eliminating
the integer truncation loss present in the legacy calculation.
- Add `CC1101IOC_SETOPMODE` and `CC1101IOC_GETOPMODE` IOCTLs.
- Introduce four RF operation modes (`enum cc1101_opmode_e`):
1. NORMAL: Standard packet mode with hardware filtering.
2. PROMISCUOUS: Packet mode bypassing address filtering and retaining
packets with CRC errors.
3. SYNC_SERIAL: Bypasses FIFO, routes clock and data to GDO0/GDO2.
4. ASYNC_SERIAL: Bypasses FIFO, routes async data to GDO2.
- Fix the `GS2200M_FIRST` IOCTL block offset in `wireless/ioctl.h` and
allocate a dedicated IOCTL block for CC1101.
Signed-off-by: Chip L. <chplee@gmail.com>
This commit is contained in:
@@ -530,8 +530,16 @@ no_data:
|
|||||||
static ssize_t cc1101_file_read(FAR struct file *filep, FAR char *buffer,
|
static ssize_t cc1101_file_read(FAR struct file *filep, FAR char *buffer,
|
||||||
size_t buflen)
|
size_t buflen)
|
||||||
{
|
{
|
||||||
|
uint8_t raw_buf[CC1101_PACKET_MAXTOTALLEN];
|
||||||
|
FAR struct wlioc_rx_hdr_s *hdr;
|
||||||
FAR struct cc1101_dev_s *dev;
|
FAR struct cc1101_dev_s *dev;
|
||||||
|
size_t actual_payload_len;
|
||||||
FAR struct inode *inode;
|
FAR struct inode *inode;
|
||||||
|
size_t user_max_len;
|
||||||
|
size_t copy_len;
|
||||||
|
uint8_t lqi_crc;
|
||||||
|
uint8_t pktlen;
|
||||||
|
int raw_rssi;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
inode = filep->f_inode;
|
inode = filep->f_inode;
|
||||||
@@ -560,9 +568,72 @@ static ssize_t cc1101_file_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen = fifo_get(dev, (FAR uint8_t *)buffer, buflen);
|
/* If in serial mode, return not supported directly, because data does
|
||||||
|
* not go over SPI and FIFO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (dev->opmode == CC1101_OPMODE_SYNC_SERIAL ||
|
||||||
|
dev->opmode == CC1101_OPMODE_ASYNC_SERIAL)
|
||||||
|
{
|
||||||
|
nxmutex_unlock(&dev->devlock);
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify if the user-passed buffer is a valid struct pointer. */
|
||||||
|
|
||||||
|
if (buflen != sizeof(struct wlioc_rx_hdr_s))
|
||||||
|
{
|
||||||
|
nxmutex_unlock(&dev->devlock);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = (FAR struct wlioc_rx_hdr_s *)buffer;
|
||||||
|
|
||||||
|
/* Get the user-provided max capacity of the receive buffer. */
|
||||||
|
|
||||||
|
user_max_len = hdr->payload_length;
|
||||||
|
if (hdr->payload_buffer == NULL)
|
||||||
|
{
|
||||||
|
nxmutex_unlock(&dev->devlock);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pktlen = fifo_get(dev, raw_buf, sizeof(raw_buf));
|
||||||
|
|
||||||
|
if (pktlen == 0)
|
||||||
|
{
|
||||||
|
nxmutex_unlock(&dev->devlock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pktlen contains the payload plus 2 bytes of status. */
|
||||||
|
|
||||||
|
actual_payload_len = (size_t)(pktlen - 2);
|
||||||
|
|
||||||
|
/* Fill metadata (fixed index: subtract 2 and 1). */
|
||||||
|
|
||||||
|
raw_rssi = raw_buf[pktlen - 2];
|
||||||
|
lqi_crc = raw_buf[pktlen - 1];
|
||||||
|
|
||||||
|
hdr->rssi_dbm = cc1101_calc_rssi_dbm_x100(raw_rssi);
|
||||||
|
hdr->snr_db = (int32_t)(lqi_crc & CC1101_LQI_EST_BM) * 100;
|
||||||
|
hdr->error = (lqi_crc & CC1101_LQI_CRC_OK_BM) ? 0 : 1;
|
||||||
|
|
||||||
|
/* Copy the actual data to the user's payload_buffer (fixed starting
|
||||||
|
* point: raw_buf[0]).
|
||||||
|
*/
|
||||||
|
|
||||||
|
copy_len = (actual_payload_len > user_max_len) ?
|
||||||
|
user_max_len : actual_payload_len;
|
||||||
|
memcpy(hdr->payload_buffer, &raw_buf[0], copy_len);
|
||||||
|
|
||||||
|
/* Update the length to the actual written length. */
|
||||||
|
|
||||||
|
hdr->payload_length = copy_len;
|
||||||
|
|
||||||
nxmutex_unlock(&dev->devlock);
|
nxmutex_unlock(&dev->devlock);
|
||||||
return buflen;
|
|
||||||
|
return sizeof(struct wlioc_rx_hdr_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -1303,6 +1374,25 @@ int cc1101_calc_rssi_dbm(int rssi)
|
|||||||
return (rssi >> 1) - 74;
|
return (rssi >> 1) - 74;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: cc1101_calc_rssi_dbm_x100
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int cc1101_calc_rssi_dbm_x100(int rssi)
|
||||||
|
{
|
||||||
|
if (rssi >= 128)
|
||||||
|
{
|
||||||
|
rssi -= 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (rssi / 2 - 74) * 100 => rssi * 50 - 7400 */
|
||||||
|
|
||||||
|
return (rssi * 50) - 7400;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: cc1101_receive
|
* Name: cc1101_receive
|
||||||
*
|
*
|
||||||
@@ -1361,7 +1451,13 @@ int cc1101_read(FAR struct cc1101_dev_s *dev, FAR uint8_t *buf, size_t size)
|
|||||||
if (!(buf[nbytes] & 0x80))
|
if (!(buf[nbytes] & 0x80))
|
||||||
{
|
{
|
||||||
wlwarn("RX CRC error\n");
|
wlwarn("RX CRC error\n");
|
||||||
nbytes = 0;
|
|
||||||
|
/* Only clear nbytes and discard packet in non-promiscuous mode. */
|
||||||
|
|
||||||
|
if (dev->opmode != CC1101_OPMODE_PROMISCUOUS)
|
||||||
|
{
|
||||||
|
nbytes = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
breakout:
|
breakout:
|
||||||
@@ -1914,6 +2010,106 @@ static int cc1101_file_ioctl(FAR struct file *filep, int cmd,
|
|||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CC1101IOC_SETOPMODE:
|
||||||
|
{
|
||||||
|
enum cc1101_opmode_e new_mode = (enum cc1101_opmode_e)arg;
|
||||||
|
uint8_t pktctrl0;
|
||||||
|
uint8_t pktctrl1;
|
||||||
|
uint8_t iocfg0;
|
||||||
|
uint8_t iocfg2;
|
||||||
|
|
||||||
|
/* 1. Restore baseline settings (read from rfsettings). */
|
||||||
|
|
||||||
|
/* Clear PKT_FORMAT bits. */
|
||||||
|
|
||||||
|
pktctrl0 = dev->rfsettings->PKTCTRL0 & ~0x30;
|
||||||
|
pktctrl1 = dev->rfsettings->PKTCTRL1;
|
||||||
|
|
||||||
|
/* 2. Modify registers depending on mode. */
|
||||||
|
|
||||||
|
switch (new_mode)
|
||||||
|
{
|
||||||
|
case CC1101_OPMODE_NORMAL:
|
||||||
|
|
||||||
|
/* Default behavior: Use FIFO, keep rfsettings filtering
|
||||||
|
* rules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CC1101_OPMODE_PROMISCUOUS:
|
||||||
|
|
||||||
|
/* Promiscuous mode: Still use FIFO (PKT_FORMAT=0).
|
||||||
|
* Disable address check (ADR_CHK=00), enable append status
|
||||||
|
* (APPEND_STATUS=1). Disable CRC autoflush
|
||||||
|
* (CRC_AUTOFLUSH=0).
|
||||||
|
*/
|
||||||
|
|
||||||
|
pktctrl1 = (pktctrl1 & ~0x0b) | 0x04;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CC1101_OPMODE_SYNC_SERIAL:
|
||||||
|
|
||||||
|
/* Synchronous serial: PKT_FORMAT=1.
|
||||||
|
* Configure GDO pins to output clock and data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pktctrl0 |= 0x10;
|
||||||
|
|
||||||
|
/* GDO0 outputs synchronous clock. */
|
||||||
|
|
||||||
|
iocfg0 = CC1101_GDO_SSCLK;
|
||||||
|
|
||||||
|
/* GDO2 outputs synchronous data. */
|
||||||
|
|
||||||
|
iocfg2 = CC1101_GDO_SSDO;
|
||||||
|
|
||||||
|
cc1101_setgdo(dev, CC1101_PIN_GDO0, iocfg0);
|
||||||
|
cc1101_setgdo(dev, CC1101_PIN_GDO2, iocfg2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CC1101_OPMODE_ASYNC_SERIAL:
|
||||||
|
|
||||||
|
/* Asynchronous serial: PKT_FORMAT=3. */
|
||||||
|
|
||||||
|
pktctrl0 |= 0x30;
|
||||||
|
|
||||||
|
/* GDO2 outputs asynchronous data. */
|
||||||
|
|
||||||
|
iocfg2 = CC1101_GDO_ASDO;
|
||||||
|
|
||||||
|
cc1101_setgdo(dev, CC1101_PIN_GDO2, iocfg2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto ioctl_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Pre-load configuration to registers. */
|
||||||
|
|
||||||
|
if (cc1101_access(dev, CC1101_PKTCTRL0, &pktctrl0, -1) >= 0 &&
|
||||||
|
cc1101_access(dev, CC1101_PKTCTRL1, &pktctrl1, -1) >= 0)
|
||||||
|
{
|
||||||
|
dev->opmode = new_mode;
|
||||||
|
ret = OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioctl_out:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CC1101IOC_GETOPMODE:
|
||||||
|
{
|
||||||
|
FAR *(enum cc1101_opmode_e *)arg = dev->opmode;
|
||||||
|
ret = OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = -ENOTTY;
|
ret = -ENOTTY;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <nuttx/mutex.h>
|
#include <nuttx/mutex.h>
|
||||||
#include <nuttx/semaphore.h>
|
#include <nuttx/semaphore.h>
|
||||||
#include <nuttx/spi/spi.h>
|
#include <nuttx/spi/spi.h>
|
||||||
|
#include <nuttx/wireless/ioctl.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-Processor Declarations
|
* Pre-Processor Declarations
|
||||||
@@ -236,6 +237,11 @@
|
|||||||
#define CC1101_GDO_CLK_XOSC128 0x3e
|
#define CC1101_GDO_CLK_XOSC128 0x3e
|
||||||
#define CC1101_GDO_CLK_XOSC192 0x3f
|
#define CC1101_GDO_CLK_XOSC192 0x3f
|
||||||
|
|
||||||
|
#define CC1101_FIRST (GS2200M_FIRST + GS2200M_NCMDS)
|
||||||
|
|
||||||
|
#define CC1101IOC_SETOPMODE _WLCIOC(CC1101_FIRST + 0)
|
||||||
|
#define CC1101IOC_GETOPMODE _WLCIOC(CC1101_FIRST + 1)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Data Types
|
* Public Data Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -271,6 +277,16 @@ enum cc1101_status
|
|||||||
CC1101_SXOFF
|
CC1101_SXOFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* CC1101 Operation Mode Enumeration */
|
||||||
|
|
||||||
|
enum cc1101_opmode_e
|
||||||
|
{
|
||||||
|
CC1101_OPMODE_NORMAL = 0, /* Default: Packet mode, enable address and CRC filtering */
|
||||||
|
CC1101_OPMODE_PROMISCUOUS, /* Promiscuous: Packet mode, disable filtering, discard bad packets */
|
||||||
|
CC1101_OPMODE_SYNC_SERIAL, /* Synchronous serial: Bypass FIFO, GDO0 outputs clock, GDO2 outputs data */
|
||||||
|
CC1101_OPMODE_ASYNC_SERIAL /* Asynchronous serial: Bypass FIFO, GDO2 outputs async data */
|
||||||
|
};
|
||||||
|
|
||||||
struct cc1101_dev_s
|
struct cc1101_dev_s
|
||||||
{
|
{
|
||||||
const struct c1101_rfsettings_s *rfsettings;
|
const struct c1101_rfsettings_s *rfsettings;
|
||||||
@@ -294,7 +310,14 @@ struct cc1101_dev_s
|
|||||||
mutex_t lock_rx_buffer; /* Protect access to rx fifo */
|
mutex_t lock_rx_buffer; /* Protect access to rx fifo */
|
||||||
sem_t sem_rx; /* Wait for availability of received data */
|
sem_t sem_rx; /* Wait for availability of received data */
|
||||||
sem_t sem_tx; /* Wait for availability of send data */
|
sem_t sem_tx; /* Wait for availability of send data */
|
||||||
FAR struct pollfd *pfd; /* Polled file descr (or NULL if any) */
|
|
||||||
|
/* Polled file descr (or NULL if any) */
|
||||||
|
|
||||||
|
FAR struct pollfd *pfd;
|
||||||
|
|
||||||
|
/* Record the current operation mode */
|
||||||
|
|
||||||
|
enum cc1101_opmode_e opmode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The RF Settings includes only those fields required to configure
|
/* The RF Settings includes only those fields required to configure
|
||||||
@@ -535,6 +558,13 @@ uint8_t cc1101_setpower(FAR struct cc1101_dev_s *dev, uint8_t power);
|
|||||||
|
|
||||||
int cc1101_calc_rssi_dbm(int rssi);
|
int cc1101_calc_rssi_dbm(int rssi);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Convert RSSI as obtained from CC1101 to [dBm] x 100
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int cc1101_calc_rssi_dbm_x100(int rssi);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Enter receive mode and wait for a packet.
|
* Enter receive mode and wait for a packet.
|
||||||
* If transmission is in progress, receive mode is entered upon its
|
* If transmission is in progress, receive mode is entered upon its
|
||||||
|
|||||||
@@ -281,9 +281,14 @@
|
|||||||
|
|
||||||
/* See include/nuttx/wireless/gs2200m.h */
|
/* See include/nuttx/wireless/gs2200m.h */
|
||||||
|
|
||||||
#define GS2200M_FIRST (SX127X_FIRST + SX127X_NCMDS)
|
#define GS2200M_FIRST (SX126X_FIRST + SX126X_NCMDS)
|
||||||
#define GS2200M_NCMDS 9
|
#define GS2200M_NCMDS 9
|
||||||
|
|
||||||
|
/* See include/nuttx/wireless/cc1101.h */
|
||||||
|
|
||||||
|
#define CC1101_FIRST (GS2200M_FIRST + GS2200M_NCMDS)
|
||||||
|
#define CC1101_NCMDS 2
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
Reference in New Issue
Block a user