From 075215cd5ba5b77f9975ea48837ebea041dcaa87 Mon Sep 17 00:00:00 2001 From: "Chip L." Date: Mon, 9 Mar 2026 10:23:12 +0800 Subject: [PATCH] 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. --- drivers/wireless/cc1101.c | 202 +++++++++++++++++++++++++++++++- include/nuttx/wireless/cc1101.h | 32 ++++- include/nuttx/wireless/ioctl.h | 7 +- 3 files changed, 236 insertions(+), 5 deletions(-) diff --git a/drivers/wireless/cc1101.c b/drivers/wireless/cc1101.c index 23321851a19..66893072ddd 100644 --- a/drivers/wireless/cc1101.c +++ b/drivers/wireless/cc1101.c @@ -530,8 +530,16 @@ no_data: static ssize_t cc1101_file_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { + uint8_t raw_buf[CC1101_PACKET_MAXTOTALLEN]; + FAR struct wlioc_rx_hdr_s *hdr; FAR struct cc1101_dev_s *dev; + size_t actual_payload_len; 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; inode = filep->f_inode; @@ -560,9 +568,72 @@ static ssize_t cc1101_file_read(FAR struct file *filep, FAR char *buffer, 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); - return buflen; + + return sizeof(struct wlioc_rx_hdr_s); } /**************************************************************************** @@ -1303,6 +1374,25 @@ int cc1101_calc_rssi_dbm(int rssi) 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 * @@ -1361,7 +1451,13 @@ int cc1101_read(FAR struct cc1101_dev_s *dev, FAR uint8_t *buf, size_t size) if (!(buf[nbytes] & 0x80)) { 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: @@ -1914,6 +2010,106 @@ static int cc1101_file_ioctl(FAR struct file *filep, int cmd, ret = -ENOSYS; 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: ret = -ENOTTY; break; diff --git a/include/nuttx/wireless/cc1101.h b/include/nuttx/wireless/cc1101.h index e9ef9ca94d8..605ede8f6a4 100644 --- a/include/nuttx/wireless/cc1101.h +++ b/include/nuttx/wireless/cc1101.h @@ -37,6 +37,7 @@ #include #include #include +#include /**************************************************************************** * Pre-Processor Declarations @@ -236,6 +237,11 @@ #define CC1101_GDO_CLK_XOSC128 0x3e #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 ****************************************************************************/ @@ -271,6 +277,16 @@ enum cc1101_status 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 { const struct c1101_rfsettings_s *rfsettings; @@ -294,7 +310,14 @@ struct cc1101_dev_s mutex_t lock_rx_buffer; /* Protect access to rx fifo */ sem_t sem_rx; /* Wait for availability of received 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 @@ -535,6 +558,13 @@ uint8_t cc1101_setpower(FAR struct cc1101_dev_s *dev, uint8_t power); 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. * If transmission is in progress, receive mode is entered upon its diff --git a/include/nuttx/wireless/ioctl.h b/include/nuttx/wireless/ioctl.h index 408b93248f3..12b2fdfdfe4 100644 --- a/include/nuttx/wireless/ioctl.h +++ b/include/nuttx/wireless/ioctl.h @@ -281,9 +281,14 @@ /* See include/nuttx/wireless/gs2200m.h */ -#define GS2200M_FIRST (SX127X_FIRST + SX127X_NCMDS) +#define GS2200M_FIRST (SX126X_FIRST + SX126X_NCMDS) #define GS2200M_NCMDS 9 +/* See include/nuttx/wireless/cc1101.h */ + +#define CC1101_FIRST (GS2200M_FIRST + GS2200M_NCMDS) +#define CC1101_NCMDS 2 + /**************************************************************************** * Public Types ****************************************************************************/