diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/CMakeLists.txt b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/CMakeLists.txt index 033028d8..88baa379 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/CMakeLists.txt +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/CMakeLists.txt @@ -2,6 +2,8 @@ idf_component_register( SRCS SRCS "utils.c" SRCS "second_uart.c" SRCS "radio.c" + SRCS "SubGigRadio.c" + SRCS "cc1101_radio.c" SRCS "led.c" SRCS "main.c" INCLUDE_DIRS ".") diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/Kconfig.projbuild b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/Kconfig.projbuild index a431cce8..5ad733cb 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/Kconfig.projbuild +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/Kconfig.projbuild @@ -25,4 +25,79 @@ menu "OEPL Hardware config" int "GPIO - UART RX" default 2 + config OEPL_SUBGIG_SUPPORT + bool "Enable SubGhz Support" + default "n" + + menu "CC1101 Configuration" + depends on OEPL_SUBGIG_SUPPORT + + config GPIO_RANGE_MAX + int + default 33 if IDF_TARGET_ESP32 + default 46 if IDF_TARGET_ESP32S2 + default 48 if IDF_TARGET_ESP32S3 + default 18 if IDF_TARGET_ESP32C2 + default 19 if IDF_TARGET_ESP32C3 + default 30 if IDF_TARGET_ESP32C6 + + config MISO_GPIO + int "CC1101 MISO GPIO" + range 0 GPIO_RANGE_MAX + default 7 + help + Pin Number to be used as the MISO SPI signal. + + config SCK_GPIO + int "CC1101 SCK GPIO" + range 0 GPIO_RANGE_MAX + default 0 + help + Pin Number to be used as the SCK SPI signal. + + config MOSI_GPIO + int "CC1101 MOSI GPIO" + default 1 + help + Pin Number to be used as the MOSI SPI signal. + + config CSN_GPIO + int "CC1101 CSN GPIO" + range 0 GPIO_RANGE_MAX + default 4 + help + Pin Number to be used as the CSN SPI signal. + + config GDO0_GPIO + int "CC1101 GDO0 GPIO" + range 0 GPIO_RANGE_MAX + default 5 + help + Pin Number to be used as the GDO0 signal. + + config GDO2_GPIO + int "CC1101 GDO2 GPIO" + range 0 GPIO_RANGE_MAX + default 6 + help + Pin Number to be used as the GDO2 signal. + + choice SPI_HOST + prompt "SPI peripheral that controls this bus" + default SPI2_HOST + help + Select SPI peripheral that controls this bus. + config SPI2_HOST + bool "SPI2_HOST" + help + Use SPI2_HOST. This is also called HSPI_HOST. + config SPI3_HOST + depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + bool "SPI3_HOST" + help + USE SPI3_HOST. This is also called VSPI_HOST + endchoice + endmenu endmenu + + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/SubGigRadio.c b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/SubGigRadio.c new file mode 100755 index 00000000..450604ea --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/SubGigRadio.c @@ -0,0 +1,542 @@ +#include "sdkconfig.h" +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include +#include +#include "esp_log.h" + +#include "radio.h" +#include "proto.h" +#include "cc1101_radio.h" +#include "SubGigRadio.h" + +void DumpHex(void *AdrIn,int Len); + +#if 0 +#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__) +#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__) +#define LOG_HEX(x,y) DumpHex(x,y) +#else +#define LOG(format, ... ) +#define LOG_RAW(format, ... ) +#define LOG_HEX(x,y) +#endif + + +// SPI Stuff +#if CONFIG_SPI2_HOST + #define HOST_ID SPI2_HOST +#elif CONFIG_SPI3_HOST + #define HOST_ID SPI3_HOST +#endif + +// Address Config = No address check +// Base Frequency = xxx.xxx +// CRC Enable = false +// Carrier Frequency = 915.000000 +// Channel Number = 0 +// Channel Spacing = 199.951172 +// Data Rate = 1.19948 +// Deviation = 5.157471 +// Device Address = 0 +// Manchester Enable = false +// Modulated = false +// Modulation Format = ASK/OOK +// PA Ramping = false +// Packet Length = 255 +// Packet Length Mode = Reserved +// Preamble Count = 4 +// RX Filter BW = 58.035714 +// Sync Word Qualifier Mode = No preamble/sync +// TX Power = 10 +// Whitening = false +// Rf settings for CC1110 +const RfSetting gCW[] = { + {CC1101_PKTCTRL0,0x22}, // PKTCTRL0: Packet Automation Control + {CC1101_FSCTRL1,0x06}, // FSCTRL1: Frequency Synthesizer Control + {CC1101_MDMCFG4,0xF5}, // MDMCFG4: Modem configuration + {CC1101_MDMCFG3,0x83}, // MDMCFG3: Modem Configuration + {CC1101_MDMCFG2,0xb0}, // MDMCFG2: Modem Configuration + {CC1101_DEVIATN,0x15}, // DEVIATN: Modem Deviation Setting + {CC1101_MCSM0,0x18}, // MCSM0: Main Radio Control State Machine Configuration + {CC1101_FOCCFG,0x17}, // FOCCFG: Frequency Offset Compensation Configuration + {CC1101_FSCAL3,0xE9}, // FSCAL3: Frequency Synthesizer Calibration + {CC1101_FSCAL2,0x2A}, // FSCAL2: Frequency Synthesizer Calibration + {CC1101_FSCAL1,0x00}, // FSCAL1: Frequency Synthesizer Calibration + {CC1101_FSCAL0,0x1F}, // FSCAL0: Frequency Synthesizer Calibration + {CC1101_TEST1,0x31}, // TEST1: Various Test Settings + {CC1101_TEST0,0x09}, // TEST0: Various Test Settings + {0xff,0} // end of table +}; + + +// Set Base Frequency to 865.999634 +const RfSetting g866Mhz[] = { + {CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0x4e}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0xc4}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + +// Set Base Frequency to 863.999756 +const RfSetting g864Mhz[] = { + {CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0x3b}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + +// Set Base Frequency to 902.999756 +const RfSetting g903Mhz[] = { + {CC1101_FREQ2,0x22}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0xbb}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + + +// Seet Base Frequency to 915.000000 +const RfSetting g915Mhz[] = { + {CC1101_FREQ2,0x23}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0x31}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0x3B}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + +// Address Config = No address check +// Base Frequency = 901.934937 (adjusted to compensate for the crappy crystal on the CC1101 board) +// CRC Enable = true +// Carrier Frequency = 901.934937 +// Channel Number = 0 +// Channel Spacing = 199.951172 +// Data Rate = 38.3835 +// Deviation = 20.629883 +// Device Address = ff +// Manchester Enable = false +// Modulated = true +// Modulation Format = GFSK +// PA Ramping = false +// Packet Length = 61 +// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word +// Preamble Count = 4 +// RX Filter BW = 101.562500 +// Sync Word Qualifier Mode = 30/32 sync word bits detected +// TX Power = 10 +// Whitening = false +// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@}," +const RfSetting gIDF_Basic[] = { + {CC1101_SYNC1,0xC7}, + {CC1101_SYNC0,0x0A}, + {CC1101_PKTLEN,0x3D}, + {CC1101_PKTCTRL0,0x05}, + {CC1101_ADDR,0xFF}, + {CC1101_FSCTRL1,0x08}, + {CC1101_FREQ2,0x22}, + {CC1101_FREQ1,0xB1}, + {CC1101_FREQ0,0x3B}, + {CC1101_MDMCFG4,0xCA}, + {CC1101_MDMCFG3,0x83}, + {CC1101_MDMCFG2,0x93}, + {CC1101_DEVIATN,0x35}, +// {CC1101_MCSM0,0x18}, FS_AUTOCAL = 1, PO_TIMEOUT = 2 + {CC1101_MCSM0,0x18}, + {CC1101_FOCCFG,0x16}, + {CC1101_AGCCTRL2,0x43}, + {CC1101_FSCAL3,0xEF}, + {CC1101_FSCAL2,0x2D}, + {CC1101_FSCAL1,0x25}, + {CC1101_FSCAL0,0x1F}, + {CC1101_TEST2,0x81}, + {CC1101_TEST1,0x35}, + {CC1101_TEST0,0x09}, + {0xff,0} // end of table +}; + +// RF configuration from Dimitry's orginal code +// Address Config = No address check +// Base Frequency = 902.999756 +// CRC Autoflush = false +// CRC Enable = true +// Carrier Frequency = 902.999756 +// Channel Number = 0 +// Channel Spacing = 335.632324 +// Data Format = Normal mode +// Data Rate = 249.939 +// Deviation = 165.039063 +// Device Address = 22 +// Manchester Enable = false +// Modulated = true +// Modulation Format = GFSK +// PA Ramping = false +// Packet Length = 255 +// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word +// Preamble Count = 24 +// RX Filter BW = 650.000000 +// Sync Word Qualifier Mode = 30/32 sync word bits detected +// TX Power = 0 +// Whitening = true +// Rf settings for CC1101 +// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@}," +const RfSetting gDmitry915[] = { + {CC1101_FREQ2,0x22}, + {CC1101_FREQ1,0xBB}, + {CC1101_FREQ0,0x13}, + {CC1101_MDMCFG4,0x1D}, + {CC1101_MDMCFG3,0x3B}, + {CC1101_MDMCFG2,0x13}, + {CC1101_MDMCFG1,0x73}, + {CC1101_MDMCFG0,0xA7}, + {CC1101_DEVIATN,0x65}, + {CC1101_MCSM0,0x18}, + {CC1101_FOCCFG,0x1E}, + {CC1101_BSCFG,0x1C}, + {CC1101_AGCCTRL2,0xC7}, + {CC1101_AGCCTRL1,0x00}, + {CC1101_AGCCTRL0,0xB0}, + {CC1101_FREND1,0xB6}, + {CC1101_FSCAL3,0xEA}, + {CC1101_FSCAL2,0x2A}, + {CC1101_FSCAL1,0x00}, + {CC1101_FSCAL0,0x1F}, + {CC1101_TEST0,0x09}, + {0xff,0} // end of table +}; + +SubGigData gSubGigData; + +int CheckSubGigState(void); +void SubGig_CC1101_reset(void); +void SubGig_CC1101_SetConfig(const RfSetting *pConfig); + +static void IRAM_ATTR gpio_isr_handler(void *arg) +{ + gSubGigData.RxAvailable = true; +} + +SubGigErr SubGig_radio_init(uint8_t ch) +{ + esp_err_t Err; + spi_device_interface_config_t devcfg = { + .clock_speed_hz = 5000000, // SPI clock is 5 MHz! + .queue_size = 7, + .mode = 0, // SPI mode 0 + .spics_io_num = -1, // we will use manual CS control + .flags = SPI_DEVICE_NO_DUMMY + }; + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_NEGEDGE, // GPIO interrupt type : falling edge + //bit mask of the pins + .pin_bit_mask = 1ULL<= FIRST_866_CHAN && ch < FIRST_866_CHAN + NUM_866_CHANNELS) { + // Base Frequency = 863.999756 + // total channels 6 (0 -> 5) (CHANNR 0 -> 15) + // Channel 100 / CHANNR 0: 863.999756 + // Channel 101 / CHANNR 3: 865.006 Mhz + // Channel 102 / CHANNR 6: 866.014 Mhz + // Channel 103 / CHANNR 9: 867.020 Mhz + // Channel 104 / CHANNR 12: 868.027 Mhz + // Channel 105 / CHANNR 15: 869.034 Mhz + SubGig_CC1101_SetConfig(g864Mhz); + SetChannr[0].Value = (ch - FIRST_866_CHAN) * 3; + } + else { + // Base Frequency = 902.999756 + // Dmitry's orginal code used 25 channels in 915 Mhz + // We don't want to have to scan that many so for OEPL we'll just use 6 + // to match 866. + // Channel 200 / CHANNR 0: 903.000 Mhz + // Channel 201 / CHANNR 12: 907.027 Mhz + // Channel 202 / CHANNR 24: 911.054 Mhz + // Channel 203 / CHANNR 24: 915.083 Mhz + // Channel 204 / CHANNR 48: 919.110 Mhz + // Channel 205 / CHANNR 60: 923.138 Mhz + SubGig_CC1101_SetConfig(g903Mhz); + + if(ch >= FIRST_915_CHAN && ch < FIRST_915_CHAN + NUM_915_CHANNELS) { + SetChannr[0].Value = (ch - FIRST_915_CHAN) * 12; + } + else { + Ret = SUBGIG_INVALID_CHANNEL; + SetChannr[0].Value = 0; // default to the first channel on 915 + } + } + SubGig_CC1101_SetConfig(SetChannr); + } while(false); + + return Ret; +} + +SubGigErr SubGig_radioTx(uint8_t *packet) +{ + SubGigErr Ret = SUBGIG_ERR_NONE; + + do { + if(gSubGigData.FreqTest) { + break; + } + if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) { + break; + } + + if(packet[0] < 3 || packet[0] > RADIO_MAX_PACKET_LEN + RAW_PKT_PADDING) { + Ret = SUBGIG_TX_BAD_LEN; + break; + } + + // All packets seem to be padded by RAW_PKT_PADDING (2 bytes) + // Remove the padding before sending so the length is correct when received + packet[0] -= RAW_PKT_PADDING; + LOG("Sending %d byte subgig frame:\n",packet[0]); + LOG_HEX(&packet[1],packet[0]); + if(CC1101_Tx(packet)) { + Ret = SUBGIG_TX_FAILED; + } + // restore original len just in case anyone cares + packet[0] += RAW_PKT_PADDING; + } while(false); + + return Ret; +} + +// returns packet size in bytes data in data +int8_t SubGig_commsRxUnencrypted(uint8_t *data) +{ + int RxBytes; + int8_t Ret = 0; + + do { + if(CheckSubGigState() != SUBGIG_ERR_NONE) { + break; + } + + if(gSubGigData.FreqTest) { + break; + } + if(gSubGigData.RxAvailable) { + gSubGigData.RxAvailable = false; + RxBytes = CC1101_Rx(data,128,NULL,NULL); + + if(RxBytes >= 2) { + // NB: RxBytes includes the CRC, deduct it + Ret = (uint8_t) RxBytes - 2; + LOG("Received %d byte subgig frame:\n",Ret); + LOG_HEX(data,Ret); + } + } + } while(false); + + return Ret; +} + +int CheckSubGigState() +{ + int Err = SUBGIG_ERR_NONE; + + if(!gSubGigData.Present) { + Err = SUBGIG_CC1101_NOT_FOUND; + } + else if(!gSubGigData.Initialized) { + Err = SUBGIG_NOT_INITIALIZED; + } + else if(!gSubGigData.Enabled) { + Err = SUBGIG_NOT_ENABLED; + } + + if(Err != SUBGIG_ERR_NONE) { + LOG("CheckSubGigState: returing %d\n",Err); + } + + return Err; +} + +SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart) +{ + SubGigErr Err = SUBGIG_ERR_NONE; +#if 0 + uint8_t TxData = 0; // len = 0 + + do { + if((Err = CheckSubGigState()) != SUBGIG_ERR_NONE) { + break; + } + if(bStart) { + LOG_RAW("Starting %sMhz Freq test\n",b866Mhz ? "866" : "915"); + SubGig_CC1101_reset(); + SubGig_CC1101_SetConfig(gCW); + SubGig_CC1101_SetConfig(b866Mhz ? g866Mhz : g915Mhz); + CC1101_cmdStrobe(CC1101_SIDLE); + CC1101_cmdStrobe(CC1101_SFTX); // flush Tx Fifo + CC1101_cmdStrobe(CC1101_STX); + gRfState = RFSTATE_TX; + gSubGigData.FreqTest = true; + } + else { + LOG_RAW("Ending Freq test\n"); + gSubGigData.FreqTest = false; + SubGig_CC1101_reset(); + SubGig_CC1101_SetConfig(gSubGigData.pConfig); + } + } while(false); +#endif + return Err; +} + +void SubGig_CC1101_reset() +{ + gSubGigData.Initialized = false; + gSubGigData.FixedRegsSet = false; + CC1101_reset(); +} + +void SubGig_CC1101_SetConfig(const RfSetting *pConfig) +{ + CC1101_SetConfig(pConfig); + gSubGigData.Initialized = true; +} + +void DumpHex(void *AdrIn,int Len) +{ + unsigned char *Adr = (unsigned char *) AdrIn; + int i = 0; + int j; + + while(i < Len) { + for(j = 0; j < 16; j++) { + if((i + j) == Len) { + break; + } + LOG_RAW("%02x ",Adr[i+j]); + } + + LOG_RAW(" "); + for(j = 0; j < 16; j++) { + if((i + j) == Len) { + break; + } + if(isprint(Adr[i+j])) { + LOG_RAW("%c",Adr[i+j]); + } + else { + LOG_RAW("."); + } + } + i += 16; + LOG_RAW("\n"); + } +} +#endif // CONFIG_OEPL_SUBGIG_SUPPORT + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/SubGigRadio.h b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/SubGigRadio.h new file mode 100755 index 00000000..1dfa61e6 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/SubGigRadio.h @@ -0,0 +1,40 @@ +#ifndef _SUBGIG_RADIO_H_ +#define _SUBGIG_RADIO_H_ + +//sub-GHz 866 Mhz channels start at 100 +#define FIRST_866_CHAN (100) +#define NUM_866_CHANNELS (6) + +//sub-GHz 915 Mhz channels start at 200 +#define FIRST_915_CHAN (200) +#define NUM_915_CHANNELS (25) + +typedef enum { + SUBGIG_ERR_NONE, + SUBGIG_CC1101_NOT_FOUND, + SUBGIG_NOT_INITIALIZED, + SUBGIG_NOT_ENABLED, + SUBGIG_TX_FAILED, + SUBGIG_TX_BAD_LEN, + SUBGIG_INVALID_CHANNEL, +} SubGigErr; + +typedef struct { + uint8_t Present:1; + uint8_t Enabled:1; + uint8_t FreqTest:1; + uint8_t RxAvailable:1; + uint8_t Initialized:1; + uint8_t FixedRegsSet:1; +} SubGigData; + +extern SubGigData gSubGigData; + +SubGigErr SubGig_radio_init(uint8_t ch); +SubGigErr SubGig_radioTx(uint8_t *packet); +SubGigErr SubGig_radioSetChannel(uint8_t ch); +int8_t SubGig_commsRxUnencrypted(uint8_t *data); +SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart); + +#endif // _SUBGIG_RADIO_H_ + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/cc1101_radio.c b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/cc1101_radio.c new file mode 100755 index 00000000..a66966fd --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/cc1101_radio.c @@ -0,0 +1,706 @@ +// Large portions of this code was copied from: +// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright + +/* + * Copyright (c) 2011 panStamp + * Copyright (c) 2016 Tyler Sommer + * + * This file is part of the CC1101 project. + * + * CC1101 is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * CC1101 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CC1101; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * Author: Daniel Berenguer + * Creation date: 03/03/2011 + */ + +#include "sdkconfig.h" +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + +#include +#include +#include +#include +#include "proto.h" +#include "cc1101_radio.h" +#include "radio.h" + +#define ENABLE_LOGGING 0 + +#if ENABLE_LOGGING +#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__) +#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__) +#else +#define LOG(format, ... ) +#define LOG_RAW(format, ... ) +#endif + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include +#include +#include "esp_log.h" + +#include "sdkconfig.h" + +/** + * RF STATES + */ +enum RFSTATE { + RFSTATE_IDLE = 0, + RFSTATE_RX, + RFSTATE_TX +}; + +/** + * Type of transfers + */ +#define WRITE_BURST 0x40 +#define READ_SINGLE 0x80 +#define READ_BURST 0xC0 + +/** + * Type of register + */ +#define CC1101_CONFIG_REGISTER READ_SINGLE +#define CC1101_STATUS_REGISTER READ_BURST + +/** + * PATABLE & FIFO's + */ +#define CC1101_PATABLE 0x3E // PATABLE address +#define CC1101_TXFIFO 0x3F // TX FIFO address +#define CC1101_RXFIFO 0x3F // RX FIFO address + +/** + * Command strobes + */ +#define CC1101_SRES 0x30 // Reset CC1101 chip +#define CC1101_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA): +// Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround). +#define CC1101_SXOFF 0x32 // Turn off crystal oscillator +#define CC1101_SCAL 0x33 // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without +// setting manual calibration mode (MCSM0.FS_AUTOCAL=0) +#define CC1101_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1 +#define CC1101_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1. +// If in RX state and CCA is enabled: Only go to TX if channel is clear +#define CC1101_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable +#define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if +// WORCTRL.RC_PD=0 +#define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high +#define CC1101_SFRX 0x3A // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states +#define CC1101_SFTX 0x3B // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states +#define CC1101_SWORRST 0x3C // Reset real time clock to Event1 value +#define CC1101_SNOP 0x3D // No operation. May be used to get access to the chip status byte + +#define CC1101_STATE_SLEEP 0x00 +#define CC1101_STATE_IDLE 0x01 +#define CC1101_STATE_XOFF 0x02 +#define CC1101_STATE_VCOON_MC 0x03 +#define CC1101_STATE_REGON_MC 0x04 +#define CC1101_STATE_MANCAL 0x05 +#define CC1101_STATE_VCOON 0x06 +#define CC1101_STATE_REGON 0x07 +#define CC1101_STATE_STARTCAL 0x08 +#define CC1101_STATE_BWBOOST 0x09 +#define CC1101_STATE_FS_LOCK 0x0A +#define CC1101_STATE_IFADCON 0x0B +#define CC1101_STATE_ENDCAL 0x0C +#define CC1101_STATE_RX 0x0D +#define CC1101_STATE_RX_END 0x0E +#define CC1101_STATE_RX_RST 0x0F +#define CC1101_STATE_TXRX_SWITCH 0x10 +#define CC1101_STATE_RXFIFO_OVERFLOW 0x11 +#define CC1101_STATE_FSTXON 0x12 +#define CC1101_STATE_TX 0x13 +#define CC1101_STATE_TX_END 0x14 +#define CC1101_STATE_RXTX_SWITCH 0x15 +#define CC1101_STATE_TXFIFO_UNDERFLOW 0x16 + +// Masks for first byte read from RXFIFO +#define CC1101_NUM_RXBYTES_MASK 0x7f +#define CC1101_RXFIFO_OVERFLOW_MASK 0x80 + +// Masks for last byte read from RXFIFO +#define CC1101_LQI_MASK 0x7f +#define CC1101_CRC_OK_MASK 0x6f + +// IOCFG2 GDO2: high when TX FIFO at or above the TX FIFO threshold +#define CC1101_DEFVAL_IOCFG2 0x02 +#define CC1101_DEFVAL_IOCFG1 0x2E +// GDO0 Asserts when sync word has been sent / received, and +// de-asserts at the end of the packet. +#define CC1101_DEFVAL_IOCFG0 0x06 +#define CC1101_DEFVAL_FIFOTHR 0x07 +#define CC1101_DEFVAL_RCCTRL1 0x41 +#define CC1101_DEFVAL_RCCTRL0 0x00 +#define CC1101_DEFVAL_AGCTEST 0x3F +#define CC1101_DEFVAL_MCSM1 0x20 +#define CC1101_DEFVAL_WORCTRL 0xFB +#define CC1101_DEFVAL_FSCTRL0 40 // Your value may be different! +#define CC1101_DEFVAL_PATABLE 0xc0 // full power + +RfSetting gFixedConfig[] = { + {CC1101_IOCFG2,CC1101_DEFVAL_IOCFG2}, + {CC1101_IOCFG1,CC1101_DEFVAL_IOCFG1}, + {CC1101_IOCFG0,CC1101_DEFVAL_IOCFG0}, + {CC1101_FIFOTHR,CC1101_DEFVAL_FIFOTHR}, + {CC1101_FSCTRL0,CC1101_DEFVAL_FSCTRL0}, + {CC1101_RCCTRL1,CC1101_DEFVAL_RCCTRL1}, + {CC1101_RCCTRL0,CC1101_DEFVAL_RCCTRL0}, + {CC1101_MCSM1,CC1101_DEFVAL_MCSM1}, + {CC1101_WORCTRL,CC1101_DEFVAL_WORCTRL}, + {0xff,0}, +}; + +void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len); +void CC1101_cmdStrobe(uint8_t cmd); +void CC1101_wakeUp(void); +uint8_t CC1101_readReg(uint8_t regAddr, uint8_t regType); +void CC1101_writeReg(uint8_t regAddr, uint8_t value); +void CC1101_setRxState(void); +void CC1101_setTxState(void); + +spi_device_handle_t gSpiHndl; + +#define readConfigReg(regAddr) CC1101_readReg(regAddr, CC1101_CONFIG_REGISTER) +#define readStatusReg(regAddr) CC1101_readReg(regAddr, CC1101_STATUS_REGISTER) +#define setIdleState() CC1101_cmdStrobe(CC1101_SIDLE) +#define flushRxFifo() CC1101_cmdStrobe(CC1101_SFRX) +#define flushTxFifo() CC1101_cmdStrobe(CC1101_SFTX) + +const char *RegNamesCC1101[] = { + "IOCFG2", // 0x00 GDO2 output pin configuration + "IOCFG1", // 0x01 GDO1 output pin configuration + "IOCFG0", // 0x02 GDO0 output pin configuration + "FIFOTHR", // 0x03 RX FIFO and TX FIFO thresholds + "SYNC1", // 0x04 Sync word, high INT8U + "SYNC0", // 0x05 Sync word, low INT8U + "PKTLEN", // 0x06 Packet length + "PKTCTRL1", // 0x07 Packet automation control + "PKTCTRL0", // 0x08 Packet automation control + "ADDR", // 0x09 Device address + "CHANNR", // 0x0A Channel number + "FSCTRL1", // 0x0B Frequency synthesizer control + "FSCTRL0", // 0x0C Frequency synthesizer control + "FREQ2", // 0x0D Frequency control word, high INT8U + "FREQ1", // 0x0E Frequency control word, middle INT8U + "FREQ0", // 0x0F Frequency control word, low INT8U + "MDMCFG4", // 0x10 Modem configuration + "MDMCFG3", // 0x11 Modem configuration + "MDMCFG2", // 0x12 Modem configuration + "MDMCFG1", // 0x13 Modem configuration + "MDMCFG0", // 0x14 Modem configuration + "DEVIATN", // 0x15 Modem deviation setting + "MCSM2", // 0x16 Main Radio Control State Machine configuration + "MCSM1", // 0x17 Main Radio Control State Machine configuration + "MCSM0", // 0x18 Main Radio Control State Machine configuration + "FOCCFG", // 0x19 Frequency Offset Compensation configuration + "BSCFG", // 0x1A Bit Synchronization configuration + "AGCCTRL2", // 0x1B AGC control + "AGCCTRL1", // 0x1C AGC control + "AGCCTRL0", // 0x1D AGC control + "WOREVT1", // 0x1E High INT8U Event 0 timeout + "WOREVT0", // 0x1F Low INT8U Event 0 timeout + "WORCTRL", // 0x20 Wake On Radio control + "FREND1", // 0x21 Front end RX configuration + "FREND0", // 0x22 Front end TX configuration + "FSCAL3", // 0x23 Frequency synthesizer calibration + "FSCAL2", // 0x24 Frequency synthesizer calibration + "FSCAL1", // 0x25 Frequency synthesizer calibration + "FSCAL0", // 0x26 Frequency synthesizer calibration + "RCCTRL1", // 0x27 RC oscillator configuration + "RCCTRL0", // 0x28 RC oscillator configuration + "FSTEST", // 0x29 Frequency synthesizer calibration control + "PTEST", // 0x2A Production test + "AGCTEST", // 0x2B AGC test + "TEST2", // 0x2C Various test settings + "TEST1", // 0x2D Various test settings + "TEST0", // 0x2E Various test settings + "0x2f", // 0x2f +//CC1101 Strobe commands + "SRES", // 0x30 Reset chip. + "SFSTXON", // 0x31 Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). + "SXOFF", // 0x32 Turn off crystal oscillator. + "SCAL", // 0x33 Calibrate frequency synthesizer and turn it off + "SRX", // 0x34 Enable RX. Perform calibration first if coming from IDLE and + "STX", // 0x35 In IDLE state: Enable TX. Perform calibration first if + "SIDLE", // 0x36 Exit RX / TX, turn off frequency synthesizer and exit + "SAFC", // 0x37 Perform AFC adjustment of the frequency synthesizer + "SWOR", // 0x38 Start automatic RX polling sequence (Wake-on-Radio) + "SPWD", // 0x39 Enter power down mode when CSn goes high. + "SFRX", // 0x3A Flush the RX FIFO buffer. + "SFTX", // 0x3B Flush the TX FIFO buffer. + "SWORRST", // 0x3C Reset real time clock. + "SNOP", // 0x3D No operation. May be used to pad strobe commands to two + "PATABLE" // 0x3E +}; + + +// SPI Stuff +#if CONFIG_SPI2_HOST + #define HOST_ID SPI2_HOST +#elif CONFIG_SPI3_HOST + #define HOST_ID SPI3_HOST +#endif + +/* + * RF state + */ +static uint8_t gRfState; + +#define cc1101_Select() gpio_set_level(CONFIG_CSN_GPIO, LOW) +#define cc1101_Deselect() gpio_set_level(CONFIG_CSN_GPIO, HIGH) +#define wait_Miso() while(gpio_get_level(CONFIG_MISO_GPIO)>0) +#define getGDO0state() gpio_get_level(CONFIG_GDO0_GPIO) +#define wait_GDO0_high() while(!getGDO0state()) +#define wait_GDO0_low() while(getGDO0state()) +#define getGDO2state() gpio_get_level(CONFIG_GDO2_GPIO) +#define wait_GDO2_low() while(getGDO2state()) + +/** + * Arduino Macros + */ +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) +#define delayMicroseconds(us) esp_rom_delay_us(us) +#define LOW 0 +#define HIGH 1 + +bool spi_write_byte(uint8_t* Dataout,size_t DataLength) +{ + spi_transaction_t SPITransaction; + + if(DataLength > 0) { + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.length = DataLength * 8; + SPITransaction.tx_buffer = Dataout; + SPITransaction.rx_buffer = NULL; + spi_device_transmit(gSpiHndl,&SPITransaction); + } + + return true; +} + +bool spi_read_byte(uint8_t* Datain,uint8_t* Dataout,size_t DataLength) +{ + spi_transaction_t SPITransaction; + + if(DataLength > 0) { + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.length = DataLength * 8; + SPITransaction.tx_buffer = Dataout; + SPITransaction.rx_buffer = Datain; + spi_device_transmit(gSpiHndl,&SPITransaction); + } + + return true; +} + +uint8_t spi_transfer(uint8_t address) +{ + uint8_t datain[1]; + uint8_t dataout[1]; + dataout[0] = address; + //spi_write_byte(dev, dataout, 1 ); + //spi_read_byte(datain, dataout, 1 ); + + spi_transaction_t SPITransaction; + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.length = 8; + SPITransaction.tx_buffer = dataout; + SPITransaction.rx_buffer = datain; + spi_device_transmit(gSpiHndl,&SPITransaction); + + return datain[0]; +} + +/** + * CC1101_wakeUp + * + * Wake up CC1101 from Power Down state + */ +void CC1101_wakeUp(void) +{ + cc1101_Select(); + wait_Miso(); + cc1101_Deselect(); +} + +/** + * CC1101_writeReg + * + * Write single register into the CC1101 IC via SPI + * + * @param regAddr Register address + * @param value Value to be writen + */ +void CC1101_writeReg(uint8_t regAddr, uint8_t value) +{ + if(regAddr < 0x3f) { + LOG("0x%x -> %s(0x%x)\n",value,RegNamesCC1101[regAddr],regAddr); + } + else { + LOG("0x%x -> 0x%x\n",value,regAddr); + } + cc1101_Select(); // Select CC1101 + wait_Miso(); // Wait until MISO goes low + spi_transfer(regAddr); // Send register address + spi_transfer(value); // Send value + cc1101_Deselect(); // Deselect CC1101 +} + + +/** + * CC1101_cmdStrobe + * + * Send command strobe to the CC1101 IC via SPI + * + * @param cmd Command strobe + */ +void CC1101_cmdStrobe(uint8_t cmd) +{ + cc1101_Select(); + wait_Miso(); + spi_transfer(cmd); + cc1101_Deselect(); +} + +/** + * CC1101_readReg + * + * Read CC1101 register via SPI + * + * @param regAddr Register address + * @param regType Type of register: CONFIG_REGISTER or STATUS_REGISTER + * + * Return: + * Data uint8_t returned by the CC1101 IC + */ +uint8_t CC1101_readReg(uint8_t regAddr,uint8_t regType) +{ + uint8_t addr, val; + + addr = regAddr | regType; + cc1101_Select(); + wait_Miso(); + spi_transfer(addr); + val = spi_transfer(0x00); // Read result + cc1101_Deselect(); + + return val; +} + +/** + * CC1101_readBurstReg + * + * Read burst data from CC1101 via SPI + * + * @param buffer Buffer where to copy the result to + * @param regAddr Register address + * @param len Data length + */ +void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len) +{ + uint8_t addr, i; + + addr = regAddr | READ_BURST; + cc1101_Select(); + wait_Miso(); + spi_transfer(addr); // Send register address + for(i = 0; i < len; i++) { + buffer[i] = spi_transfer(0x00); // Read result uint8_t by uint8_t + } + cc1101_Deselect(); +} + +/** + * reset + * + * Reset CC1101 + */ +void CC1101_reset(void) +{ +// See sectin 19.1.2 of the CC1101 spec sheet for reasons for the following + cc1101_Deselect(); + delayMicroseconds(5); + cc1101_Select(); + delayMicroseconds(10); + cc1101_Deselect(); + delayMicroseconds(41); + cc1101_Select(); + +// Wait until MISO goes low indicating XOSC stable + wait_Miso(); + spi_transfer(CC1101_SRES); // Send reset command strobe + wait_Miso(); + cc1101_Deselect(); +} + + +/** + * CC1101_setRxState + * + * Enter Rx state + */ +void CC1101_setRxState(void) +{ + CC1101_cmdStrobe(CC1101_SRX); + gRfState = RFSTATE_RX; +} + +/** + * CC1101_setTxState + * + * Enter Tx state + */ +void CC1101_setTxState(void) +{ + CC1101_cmdStrobe(CC1101_STX); + gRfState = RFSTATE_TX; +} + + +void CC1101_DumpRegs() +{ +#if ENABLE_LOGGING + uint8_t regAddr; + uint8_t value; + + LOG("\n"); + for(regAddr = 0; regAddr < 0x2f; regAddr++) { + value = CC1101_readReg(regAddr,READ_SINGLE); + LOG("%02x %s: 0x%02X\n",regAddr,RegNamesCC1101[regAddr],value); + } + +#if 0 + for(regAddr = 0; regAddr < 0x2f; regAddr++) { + value = CC1101_readReg(regAddr,READ_SINGLE); + LOG("%s0x%02X\n",RegNamesCC1101[regAddr],value); + } +#endif +#endif +} + + +bool CC1101_Tx(uint8_t *TxData) +{ + bool Ret = false; + int ErrLine = 0; + spi_transaction_t SPITransaction; + uint8_t BytesSent = 0; + uint8_t Bytes2Send; + uint8_t len; + uint8_t CanSend; + esp_err_t Err; + + do { + // The first byte in the buffer is the number of data bytes to send, + // we also need to send the first byte + len = 1 + *TxData; + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.tx_buffer = TxData; + + setIdleState(); + flushTxFifo(); + + while(BytesSent < len) { + Bytes2Send = len - BytesSent; + if(BytesSent == 0) { + // First chunk, the FIFO is empty and can take 64 bytes + if(Bytes2Send > 64) { + Bytes2Send = 64; + } + } + else { + // Not the first chunk, we can only send FIFO_THRESHOLD bytes + // and only when GDO2 says we can + if(getGDO2state()) { + wait_GDO2_low(); + } + CanSend = readStatusReg(CC1101_TXBYTES); + if(CanSend & 0x80) { + LOG("TX FIFO underflow, BytesSent %d\n",BytesSent); + ErrLine = __LINE__; + break; + } + CanSend = 64 - CanSend; + if(CanSend == 0) { + LOG("CanSend == 0, GDO2 problem\n"); + ErrLine = __LINE__; + break; + } + + if(Bytes2Send > CanSend) { + Bytes2Send = CanSend; + } + } + SPITransaction.length = Bytes2Send * 8; + SPITransaction.rxlength = 0; + cc1101_Select(); + wait_Miso(); + spi_transfer(CC1101_TXFIFO | WRITE_BURST); + if((Err = spi_device_transmit(gSpiHndl,&SPITransaction)) != ESP_OK) { + ErrLine = __LINE__; + LOG("spi_device_transmit failed %d\n",Err); + break; + } + cc1101_Deselect(); +// LOG("Sending %d bytes\n",Bytes2Send); + if(BytesSent == 0) { + // some or all of the tx data has been written to the FIFO, + // start transmitting +// LOG("Start tx\n"); + CC1101_setTxState(); + // Wait for the sync word to be transmitted + wait_GDO0_high(); + } + SPITransaction.tx_buffer += Bytes2Send; + BytesSent += Bytes2Send; + } + + // Wait until the end of the TxData transmission + wait_GDO0_low(); + Ret = true; + } while(false); + + setIdleState(); + CC1101_setRxState(); + + if(ErrLine != 0) { + LOG("%s#%d: failure\n",__FUNCTION__,ErrLine); + } + + return Ret; +} + +int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi) +{ + uint8_t rxBytes = readStatusReg(CC1101_RXBYTES); + uint8_t Rssi; + uint8_t Lqi; + int Ret; + + Ret = rxBytes & CC1101_NUM_RXBYTES_MASK; +// Any uint8_t waiting to be read and no overflow? + if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) { + LOG("RxFifo overflow\n"); + Ret = -2; + } + else if(Ret != 0) { + // Read RxBuf length + Ret = readConfigReg(CC1101_RXFIFO); + // If TxData is too long + if(Ret > RxBufLen) { + // Toss the data + LOG("RxBuf too small %d < %d\n",RxBufLen,Ret); + Ret = -1; + } + else { + // Read RxBuf TxData + CC1101_readBurstReg(RxBuf,CC1101_RXFIFO,Ret); + // Read RSSI + Rssi = readConfigReg(CC1101_RXFIFO); + // Read LQI and CRC_OK + Lqi = readConfigReg(CC1101_RXFIFO); + if(Lqi & CC1101_CRC_OK_MASK) { + // CRC is valid + if(pRssi != NULL) { + *pRssi = Rssi; + } + if(pLqi != NULL) { + *pLqi = Lqi & CC1101_LQI_MASK; + } + } + else { + // Crc error, ignore the packet + Ret = 0; + } + } + } + + setIdleState(); + flushRxFifo(); + CC1101_setRxState(); + + return Ret; +} + +bool CC1101_Present() +{ + bool Ret = false; + uint8_t PartNum = CC1101_readReg(CC1101_PARTNUM, CC1101_STATUS_REGISTER); + uint8_t ChipVersion = CC1101_readReg(CC1101_VERSION, CC1101_STATUS_REGISTER); + + if(PartNum == 0 && ChipVersion == 20) { + LOG("CC1101 detected\n"); + Ret = true; + } + + return Ret; +} + +void CC1101_SetConfig(const RfSetting *pConfig) +{ + int i; + uint8_t RegWasSet[CC1101_TEST0 + 1]; + uint8_t Reg; + + memset(RegWasSet,0,sizeof(RegWasSet)); + + if(pConfig == NULL) { +// Just set the fixed registers + LOG("Setting fixed registers\n"); + for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) { + CC1101_writeReg(Reg,gFixedConfig[i].Value); + } + // Set TX power + CC1101_writeReg(CC1101_PATABLE,CC1101_DEFVAL_PATABLE); + } + else { + for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) { + RegWasSet[Reg] = 1; + } + + while((Reg = pConfig->Reg) != 0xff) { + if(RegWasSet[Reg] == 1) { + LOG("%s value ignored\n",RegNamesCC1101[Reg]); + } + else { + if(RegWasSet[Reg] == 2) { + LOG("%s value set before\n",RegNamesCC1101[Reg]); + } + CC1101_writeReg(pConfig->Reg,pConfig->Value); + RegWasSet[Reg] = 2; + } + pConfig++; + } +#if 0 + for(Reg = 0; Reg <= CC1101_TEST0; Reg++) { + if(RegWasSet[Reg] == 0) { + LOG("%s value not set\n",RegNamesCC1101[Reg]); + } + } +#endif + } +} + +#endif // CONFIG_OEPL_SUBGIG_SUPPORT + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/cc1101_radio.h b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/cc1101_radio.h new file mode 100755 index 00000000..f2a7f115 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/cc1101_radio.h @@ -0,0 +1,116 @@ +// Large portions of this code was copied from: +// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright + +/* + * Copyright (c) 2011 panStamp + * Copyright (c) 2016 Tyler Sommer + * + * This file is part of the CC1101 project. + * + * CC1101 is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * CC1101 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CC1101; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * Author: Daniel Berenguer + * Creation date: 03/03/2011 + */ + +#ifndef __CC1101_RADIO_H_ +#define __CC1101_RADIO_H_ + +/** + * CC1101 configuration registers + */ +#define CC1101_IOCFG2 0x00 // GDO2 Output Pin Configuration +#define CC1101_IOCFG1 0x01 // GDO1 Output Pin Configuration +#define CC1101_IOCFG0 0x02 // GDO0 Output Pin Configuration +#define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO Thresholds +#define CC1101_SYNC1 0x04 // Sync Word, High Byte +#define CC1101_SYNC0 0x05 // Sync Word, Low Byte +#define CC1101_PKTLEN 0x06 // Packet Length +#define CC1101_PKTCTRL1 0x07 // Packet Automation Control +#define CC1101_PKTCTRL0 0x08 // Packet Automation Control +#define CC1101_ADDR 0x09 // Device Address +#define CC1101_CHANNR 0x0A // Channel Number +#define CC1101_FSCTRL1 0x0B // Frequency Synthesizer Control +#define CC1101_FSCTRL0 0x0C // Frequency Synthesizer Control +#define CC1101_FREQ2 0x0D // Frequency Control Word, High Byte +#define CC1101_FREQ1 0x0E // Frequency Control Word, Middle Byte +#define CC1101_FREQ0 0x0F // Frequency Control Word, Low Byte +#define CC1101_MDMCFG4 0x10 // Modem Configuration +#define CC1101_MDMCFG3 0x11 // Modem Configuration +#define CC1101_MDMCFG2 0x12 // Modem Configuration +#define CC1101_MDMCFG1 0x13 // Modem Configuration +#define CC1101_MDMCFG0 0x14 // Modem Configuration +#define CC1101_DEVIATN 0x15 // Modem Deviation Setting +#define CC1101_MCSM2 0x16 // Main Radio Control State Machine Configuration +#define CC1101_MCSM1 0x17 // Main Radio Control State Machine Configuration +#define CC1101_MCSM0 0x18 // Main Radio Control State Machine Configuration +#define CC1101_FOCCFG 0x19 // Frequency Offset Compensation Configuration +#define CC1101_BSCFG 0x1A // Bit Synchronization Configuration +#define CC1101_AGCCTRL2 0x1B // AGC Control +#define CC1101_AGCCTRL1 0x1C // AGC Control +#define CC1101_AGCCTRL0 0x1D // AGC Control +#define CC1101_WOREVT1 0x1E // High Byte Event0 Timeout +#define CC1101_WOREVT0 0x1F // Low Byte Event0 Timeout +#define CC1101_WORCTRL 0x20 // Wake On Radio Control +#define CC1101_FREND1 0x21 // Front End RX Configuration +#define CC1101_FREND0 0x22 // Front End TX Configuration +#define CC1101_FSCAL3 0x23 // Frequency Synthesizer Calibration +#define CC1101_FSCAL2 0x24 // Frequency Synthesizer Calibration +#define CC1101_FSCAL1 0x25 // Frequency Synthesizer Calibration +#define CC1101_FSCAL0 0x26 // Frequency Synthesizer Calibration +#define CC1101_RCCTRL1 0x27 // RC Oscillator Configuration +#define CC1101_RCCTRL0 0x28 // RC Oscillator Configuration +#define CC1101_FSTEST 0x29 // Frequency Synthesizer Calibration Control +#define CC1101_PTEST 0x2A // Production Test +#define CC1101_AGCTEST 0x2B // AGC Test +#define CC1101_TEST2 0x2C // Various Test Settings +#define CC1101_TEST1 0x2D // Various Test Settings +#define CC1101_TEST0 0x2E // Various Test Settings + +/** + * Status registers + */ +#define CC1101_PARTNUM 0x30 // Chip ID +#define CC1101_VERSION 0x31 // Chip ID +#define CC1101_FREQEST 0x32 // Frequency Offset Estimate from Demodulator +#define CC1101_LQI 0x33 // Demodulator Estimate for Link Quality +#define CC1101_RSSI 0x34 // Received Signal Strength Indication +#define CC1101_MARCSTATE 0x35 // Main Radio Control State Machine State +#define CC1101_WORTIME1 0x36 // High Byte of WOR Time +#define CC1101_WORTIME0 0x37 // Low Byte of WOR Time +#define CC1101_PKTSTATUS 0x38 // Current GDOx Status and Packet Status +#define CC1101_VCO_VC_DAC 0x39 // Current Setting from PLL Calibration Module +#define CC1101_TXBYTES 0x3A // Underflow and Number of Bytes +#define CC1101_RXBYTES 0x3B // Overflow and Number of Bytes +#define CC1101_RCCTRL1_STATUS 0x3C // Last RC Oscillator Calibration Result +#define CC1101_RCCTRL0_STATUS 0x3D // Last RC Oscillator Calibration Result + +typedef struct { + uint16_t Reg; + uint8_t Value; +} RfSetting; + +extern spi_device_handle_t gSpiHndl; + +void CC1101_SetConfig(const RfSetting *pConfig); +int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi); +bool CC1101_Tx(uint8_t *TxData); +bool CC1101_Present(void); +void CC1101_DumpRegs(void); +void CC1101_reset(void); + +#endif // __CC1101_RADIO_H_ + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.c b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.c index 0e163e50..e7611aba 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.c +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/main.c @@ -26,6 +26,8 @@ #include #include #include +#include "SubGigRadio.h" + static const char *TAG = "MAIN"; @@ -66,6 +68,8 @@ uint32_t lastBlockRequest = 0; uint8_t lastBlockMac[8]; uint8_t lastTagReturn[8]; +#define NO_SUBGHZ_CHANNEL 255 +uint8_t curSubGhzChannel; uint8_t curChannel = 25; uint8_t curPower = 10; @@ -320,7 +324,20 @@ void processSerial(uint8_t lastchar) { bytesRemain--; if (bytesRemain == 0) { if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower))) { - struct espSetChannelPower *scp = (struct espSetChannelPower *) serialbuffer; + struct espSetChannelPower *scp = (struct espSetChannelPower *) serialbuffer; +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(curSubGhzChannel != scp->subghzchannel + && curSubGhzChannel != NO_SUBGHZ_CHANNEL) + { + curSubGhzChannel = scp->subghzchannel; + ESP_LOGI(TAG,"Set SubGhz channel: %d",curSubGhzChannel); + SubGig_radioSetChannel(scp->subghzchannel); + if(scp->channel == 0) { + // Not setting 802.15.4 channel + goto SCPchannelFound; + } + } +#endif for (uint8_t c = 0; c < sizeof(channelList); c++) { if (channelList[c] == scp->channel) goto SCPchannelFound; } @@ -405,6 +422,9 @@ void espNotifyAPInfo() { pr("%02X%02X", mSelfMac[4], mSelfMac[5]); pr("%02X%02X", mSelfMac[6], mSelfMac[7]); pr("ZCH>%02X", curChannel); +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + pr("SCH>%03d",curSubGhzChannel); +#endif pr("ZPW>%02X", curPower); countSlots(); pr("PEN>%02X", curPendingData); @@ -684,6 +704,12 @@ void sendPong(void *buf) { struct MacFrameBcast *rxframe = (struct MacFrameBcast *) buf; struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG; +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(rxframe->srcPan == PROTO_PAN_ID_SUBGHZ) { + radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curSubGhzChannel; + } + else +#endif radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curChannel; radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + 1 + RAW_PKT_PADDING; memcpy(frameHeader->src, mSelfMac, 8); @@ -707,6 +733,16 @@ void app_main(void) { memset(pendingDataArr, 0, sizeof(pendingDataArr)); radio_init(curChannel); +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(!SubGig_radio_init(curSubGhzChannel)) { + // Ether we don't have a cc1101 or it's not working + curSubGhzChannel = NO_SUBGHZ_CHANNEL; + ESP_LOGI(TAG,"CC1101 NOT detected."); + } + else { + ESP_LOGI(TAG,"CC1101 detected."); + } +#endif radioSetTxPower(10); pr("RES>"); diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/proto.h b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/proto.h index 83cd0a4c..1f32fa69 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/proto.h +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/proto.h @@ -6,6 +6,7 @@ #define LED2 23 #define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used +#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used #define RADIO_MAX_PACKET_LEN (125) // useful payload, not including the crc @@ -178,6 +179,9 @@ struct espSetChannelPower { uint8_t checksum; uint8_t channel; uint8_t power; +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + uint8_t subghzchannel; +#endif } __attribute__((packed, aligned(1))); struct espTagReturnData { diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.c b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.c index 41f7a13c..71c1ae3a 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.c +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.c @@ -1,3 +1,4 @@ +#include #include "radio.h" #include "driver/gpio.h" #include "driver/uart.h" @@ -23,6 +24,8 @@ #include #include #include +#include "SubGigRadio.h" + static const char *TAG = "RADIO"; @@ -91,7 +94,12 @@ void radio_init(uint8_t ch) { // uint32_t lastZbTx = 0; bool radioTx(uint8_t *packet) { +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT +// The subghz driver uses DMA + static DMA_ATTR uint8_t txPKT[130]; +#else static uint8_t txPKT[130]; +#endif led_flash(1); while (isInTransmit) { } @@ -99,6 +107,13 @@ bool radioTx(uint8_t *packet) { // } // lastZbTx = getMillis(); memcpy(txPKT, packet, packet[0]); +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (packet + 1); + + if(txHeader->pan == PROTO_PAN_ID_SUBGHZ) { + return SubGig_radioTx(packet); + } +#endif isInTransmit = 1; esp_ieee802154_transmit(txPKT, false); return true; @@ -116,5 +131,13 @@ int8_t commsRxUnencrypted(uint8_t *data) { memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1); return inner_rxPKT_out[0] - 2; } +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(gSubGigData.Enabled) { + int8_t Ret = SubGig_commsRxUnencrypted(data); + if(Ret > 0) { + return Ret; + } + } +#endif return 0; } diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.h b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.h index 73cd5286..6bd55d42 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.h +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/radio.h @@ -2,10 +2,19 @@ #include #include +#define RAW_PKT_PADDING 2 extern uint8_t mSelfMac[8]; void radio_init(uint8_t ch); bool radioTx(uint8_t *packet); void radioSetChannel(uint8_t ch); void radioSetTxPower(uint8_t power); -int8_t commsRxUnencrypted(uint8_t *data); \ No newline at end of file +int8_t commsRxUnencrypted(uint8_t *data); + +#ifdef SUBGIG_SUPPORT +void SubGig_radio_init(uint8_t ch); +bool SubGig_radioTx(uint8_t *packet); +void SubGig_radioSetChannel(uint8_t ch); +void SubGig_radioSetTxPower(uint8_t power); +int8_t SubGig_commsRxUnencrypted(uint8_t *data); +#endif \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig.defaults b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig.defaults index 33d54434..07ac3251 100644 --- a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig.defaults +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig.defaults @@ -6,3 +6,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_OEPL_SUBGIG_SUPPORT=y + diff --git a/ESP32_AP-Flasher/data/tagtypes/80.json b/ESP32_AP-Flasher/data/tagtypes/80.json new file mode 100755 index 00000000..921fa1f8 --- /dev/null +++ b/ESP32_AP-Flasher/data/tagtypes/80.json @@ -0,0 +1,57 @@ +{ + "name": "Chroma 7.4\"", + "width": 640, + "height": 384, + "rotatebuffer": 0, + "bpp": 2, + "colors": 3, + "colortable": { + "white": [255, 255, 255], + "black": [0, 0, 0], + "red": [255, 0, 0], + "gray": [150, 150, 150] + }, + "shortlut": 1, + "options": [], + "contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20], + "template": { + "1": { + "weekday": [ 320, -5, "Signika-SB.ttf", 100 ], + "month": [ 320, 265, "Signika-SB.ttf", 100 ], + "day": [ 320, 60, "Signika-SB.ttf", 220 ] + }, + "4": { + "location": [ 20, 20, "fonts/calibrib30" ], + "wind": [ 90, 83, "fonts/calibrib30" ], + "temp": [ 20, 170, "fonts/calibrib30" ], + "icon": [ 385, 0, 100, 2 ], + "dir": [ 40, 50, 80 ], + "umbrella": [ 325, 155, 78 ] + }, + "8": { + "location": [ 10, 10, "fonts/calibrib30" ], + "column": [ 6, 66 ], + "day": [ 33, 60, "fonts/bahnschrift20", 104, 230 ], + "rain": [ 34, 260 ], + "icon": [ 32, 145, 30 ], + "wind": [ 17, 90 ], + "line": [ 50, 300 ] + }, + "9": { + "title": [ 6, 0, "Signika-SB.ttf", 32 ], + "items": 5, + "line": [ 9, 40, "calibrib16.vlw" ], + "desc": [ 2, 8, "REFSAN12.vlw", 1.2 ] + }, + "10": { + "title": [ 320, 10, "fonts/bahnschrift20" ], + "pos": [ 320, 40 ] + }, + "11": { + "rotate": 0, + "mode": 1, + "days": 7, + "gridparam": [ 3, 17, 30, "calibrib16.vlw", "BellCent10.vlw", 14 ] + } + } +} diff --git a/ESP32_AP-Flasher/data/tagtypes/81.json b/ESP32_AP-Flasher/data/tagtypes/81.json new file mode 100755 index 00000000..8b00f36c --- /dev/null +++ b/ESP32_AP-Flasher/data/tagtypes/81.json @@ -0,0 +1,17 @@ +{ + "name": "Chroma29 2.9\" (UC8154)", + "width": 296, + "height": 128, + "rotatebuffer": 1, + "bpp": 2, + "colors": 3, + "colortable": { + "white": [255, 255, 255], + "black": [0, 0, 0], + "red": [255, 0, 0], + "gray": [150, 150, 150] + }, + "shortlut": 0, + "contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 27], + "usetemplate": 1 +} diff --git a/ESP32_AP-Flasher/data/tagtypes/82.json b/ESP32_AP-Flasher/data/tagtypes/82.json new file mode 100755 index 00000000..c9fa4af6 --- /dev/null +++ b/ESP32_AP-Flasher/data/tagtypes/82.json @@ -0,0 +1,17 @@ +{ + "name": "Chroma29 2.9\"", + "width": 296, + "height": 128, + "rotatebuffer": 1, + "bpp": 2, + "colors": 3, + "colortable": { + "white": [255, 255, 255], + "black": [0, 0, 0], + "red": [255, 0, 0], + "gray": [150, 150, 150] + }, + "shortlut": 0, + "contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 27], + "usetemplate": 1 +} diff --git a/ESP32_AP-Flasher/data/tagtypes/83.json b/ESP32_AP-Flasher/data/tagtypes/83.json new file mode 100755 index 00000000..460c6eee --- /dev/null +++ b/ESP32_AP-Flasher/data/tagtypes/83.json @@ -0,0 +1,56 @@ +{ + "name": "Chroma42 4.2\"", + "width": 400, + "height": 300, + "rotatebuffer": 0, + "bpp": 2, + "colors": 3, + "colortable": { + "white": [255, 255, 255], + "black": [0, 0, 0], + "red": [255, 0, 0], + "gray": [150, 150, 150] + }, + "shortlut": 0, + "contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20], + "template": { + "1": { + "weekday": [ 200, 0, "Signika-SB.ttf", 70 ], + "month": [ 200, 210, "Signika-SB.ttf", 70 ], + "day": [ 200, 45, "Signika-SB.ttf", 170 ] + }, + "4": { + "location": [ 20, 20, "fonts/calibrib30" ], + "wind": [ 90, 83, "fonts/calibrib50" ], + "temp": [ 20, 170, "fonts/calibrib100" ], + "icon": [ 385, 0, 100, 2 ], + "dir": [ 40, 50, 80 ], + "umbrella": [ 325, 155, 78 ] + }, + "8": { + "location": [ 10, 10, "fonts/calibrib30" ], + "column": [ 6, 66 ], + "day": [ 33, 60, "fonts/bahnschrift20", 104, 230 ], + "rain": [ 34, 260 ], + "icon": [ 32, 145, 30 ], + "wind": [ 17, 90 ], + "line": [ 50, 300 ] + }, + "9": { + "title": [ 6, 0, "Signika-SB.ttf", 25 ], + "items": 4, + "line": [ 9, 40, "calibrib16.vlw" ], + "desc": [ 2, 8, "REFSAN12.vlw", 1.2 ] + }, + "10": { + "title": [ 200, 10, "fonts/bahnschrift20" ], + "pos": [ 200, 35 ] + }, + "11": { + "rotate": 0, + "mode": 1, + "days": 4, + "gridparam": [ 5, 17, 20, "calibrib16.vlw", "BellCent10.vlw", 14 ] + } + } +} diff --git a/ESP32_AP-Flasher/include/serialap.h b/ESP32_AP-Flasher/include/serialap.h index 635ad1ce..5b0ef378 100644 --- a/ESP32_AP-Flasher/include/serialap.h +++ b/ESP32_AP-Flasher/include/serialap.h @@ -21,6 +21,10 @@ struct APInfoS { uint8_t power; uint8_t pendingBuffer; uint8_t nop; +#ifdef HAS_SUBGHZ + bool hasSubGhz = false; + uint8_t SubGhzChannel; +#endif }; extern struct APInfoS apInfo; diff --git a/ESP32_AP-Flasher/include/tag_db.h b/ESP32_AP-Flasher/include/tag_db.h index 8a5331f7..b58fef74 100644 --- a/ESP32_AP-Flasher/include/tag_db.h +++ b/ESP32_AP-Flasher/include/tag_db.h @@ -12,6 +12,7 @@ #define RUNSTATUS_RUN 2 #define RUNSTATUS_INIT 3 +#define NO_SUBGHZ_CHANNEL 255 class tagRecord { public: tagRecord() : mac{0}, version(0), alias(""), lastseen(0), nextupdate(0), contentMode(0), pendingCount(0), md5{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), apIp(IPAddress(0, 0, 0, 0)), pendingIdle(0), hasCustomLUT(false), rotate(0), lut(0), tagSoftwareVersion(0), currentChannel(0), dataType(0), filename(""), data(nullptr), len(0), invert(0) {} diff --git a/ESP32_AP-Flasher/platformio.ini b/ESP32_AP-Flasher/platformio.ini index fb95ac22..3045c726 100644 --- a/ESP32_AP-Flasher/platformio.ini +++ b/ESP32_AP-Flasher/platformio.ini @@ -257,6 +257,7 @@ build_flags = -D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50 -D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100 -D C6_OTA_FLASHING + -D HAS_SUBGHZ build_src_filter = +<*>--- board_build.flash_mode=qio diff --git a/ESP32_AP-Flasher/src/newproto.cpp b/ESP32_AP-Flasher/src/newproto.cpp index fe12e6cc..79295597 100644 --- a/ESP32_AP-Flasher/src/newproto.cpp +++ b/ESP32_AP-Flasher/src/newproto.cpp @@ -523,8 +523,13 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP tagRecord* taginfo = tagRecord::findByMAC(eadr->src); if (taginfo == nullptr) { if (config.lock == 1 || (config.lock == 2 && eadr->adr.wakeupReason != WAKEUP_REASON_FIRSTBOOT)) return; +#ifdef HAS_SUBGHZ + if(apInfo.hasSubGhz && eadr->adr.currentChannel > 0 && eadr->adr.currentChannel == apInfo.SubGhzChannel) { + // Empty intentionally + } else +#endif if (eadr->adr.currentChannel > 0 && eadr->adr.currentChannel != apInfo.channel) { - Serial.printf("Tag %s reports illegal channel %d\n", hexmac, eadr->adr.currentChannel); + Serial.printf("Tag %s reports illegal channel %d\n", hexmac, eadr->adr.currentChannel); return; } taginfo = new tagRecord; @@ -643,6 +648,8 @@ void updateContent(const uint8_t* dst) { } void setAPchannel() { + bool bSendRadioLayer = false; + struct espSetChannelPower tmp; if (config.channel == 0) { // trigger channel autoselect UDPcomm udpsync; @@ -650,12 +657,23 @@ void setAPchannel() { } else { if (curChannel.channel != config.channel) { curChannel.channel = config.channel; -#ifdef HAS_SUBGHZ - curChannel.subghzchannel = config.subghzchannel; -#endif - sendChannelPower(&curChannel); + bSendRadioLayer = true; } } +#ifdef HAS_SUBGHZ + if(curChannel.subghzchannel != config.subghzchannel) { + curChannel.subghzchannel = config.subghzchannel; + apInfo.SubGhzChannel = config.subghzchannel; + bSendRadioLayer = true; + } +#endif + if(bSendRadioLayer) { + tmp = curChannel; + if(config.channel == 0) { + tmp.channel = 0; // don't set the 802.15.4 channel + } + sendChannelPower(&tmp); + } } bool sendAPSegmentedData(const uint8_t* dst, String data, uint16_t icons, bool inverted, bool local) { diff --git a/ESP32_AP-Flasher/src/serialap.cpp b/ESP32_AP-Flasher/src/serialap.cpp index 585c83b5..1ad2b71b 100644 --- a/ESP32_AP-Flasher/src/serialap.cpp +++ b/ESP32_AP-Flasher/src/serialap.cpp @@ -66,6 +66,7 @@ struct rxCmd { #define ZBS_RX_WAIT_NOP 16 #define ZBS_RX_WAIT_TYPE 17 #define ZBS_RX_WAIT_TAG_RETURN_DATA 18 +#define ZBS_RX_WAIT_SUBCHANNEL 19 bool txStart() { while (1) { @@ -458,6 +459,13 @@ void rxSerialTask(void* parameter) { charindex = 0; memset(cmdbuffer, 0x00, 4); } +#ifdef HAS_SUBGHZ + if ((strncmp(cmdbuffer, "SCH>", 4) == 0)) { + RXState = ZBS_RX_WAIT_SUBCHANNEL; + charindex = 0; + memset(cmdbuffer, 0x00, 4); + } +#endif if ((strncmp(cmdbuffer, "ZPW>", 4) == 0)) { RXState = ZBS_RX_WAIT_POWER; charindex = 0; @@ -595,6 +603,24 @@ void rxSerialTask(void* parameter) { apInfo.channel = (uint8_t)strtoul(cmdbuffer, NULL, 16); } break; +#ifdef HAS_SUBGHZ + case ZBS_RX_WAIT_SUBCHANNEL: + cmdbuffer[charindex] = lastchar; + charindex++; + if(charindex == 3) { + RXState = ZBS_RX_WAIT_HEADER; + int Channel = atoi(cmdbuffer); + if(Channel != NO_SUBGHZ_CHANNEL) { + apInfo.hasSubGhz = true; + apInfo.SubGhzChannel = Channel; + } + else { + apInfo.hasSubGhz = false; + apInfo.SubGhzChannel = 0; + } + } + break; +#endif case ZBS_RX_WAIT_POWER: cmdbuffer[charindex] = lastchar; charindex++; diff --git a/ESP32_AP-Flasher/src/web.cpp b/ESP32_AP-Flasher/src/web.cpp index 0b6af745..809319dc 100644 --- a/ESP32_AP-Flasher/src/web.cpp +++ b/ESP32_AP-Flasher/src/web.cpp @@ -511,7 +511,7 @@ void init_web() { #endif #ifdef HAS_SUBGHZ - response->print("\"hasSubGhz\": \"1\", "); + response->print("\"hasSubGhz\": \"" + String(apInfo.hasSubGhz) + "\","); #else response->print("\"hasSubGhz\": \"0\", "); #endif