Enable SubGhz, changed CC1101 pin assigments for the Lilygo T-Panel.

This commit is contained in:
Skip Hansen
2024-11-16 07:10:15 -08:00
parent c22de350f6
commit 7735612a16
30 changed files with 43 additions and 2951 deletions

View File

@@ -63,7 +63,7 @@ jobs:
# run: |
# cd ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/
# dir build
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_C6.bin
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_H2.bin
# cp merged-firmware.bin ../../espbinaries/OpenEPaperLink_esp32_H2.bin
# - name: Zip web files

View File

@@ -13,6 +13,9 @@ menu "OEPL Hardware config"
config OEPL_HARDWARE_PROFILE_CUSTOM
bool "Custom"
config OEPL_HARDWARE_PROFILE_LILYGO
bool "LILYGO-AP"
endchoice
config OEPL_HARDWARE_UART_TX
@@ -40,6 +43,7 @@ menu "OEPL Hardware config"
default 18 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6
default 30 if IDF_TARGET_ESP32H2
config MISO_GPIO
int "CC1101 MISO GPIO"

View File

@@ -17,7 +17,9 @@
#include "radio.h"
#include "sdkconfig.h"
#include "second_uart.h"
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
#endif
#include "soc/uart_struct.h"
#include "utils.h"
#include <esp_mac.h>
@@ -752,7 +754,11 @@ void app_main(void) {
pr("RES>");
pr("RDY>");
#ifdef CONFIG_IDF_TARGET_ESP32C6
ESP_LOGI(TAG, "C6 ready!");
#else
ESP_LOGI(TAG, "H2 ready!");
#endif
housekeepingTimer = getMillis();
while (1) {

View File

@@ -3,7 +3,11 @@
#include <stdint.h>
#define LED1 22
#ifdef CONFIG_IDF_TARGET_ESP32C6
#define LED2 23
#elif CONFIG_IDF_TARGET_ESP32H2
#define LED2 25
#endif
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used

View File

@@ -17,7 +17,9 @@
#include "sdkconfig.h"
// if you get an error about soc/lp_uart_reg.h not being found,
// you didn't choose the right build target. :-)
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
#endif
#include "soc/uart_struct.h"
#include "utils.h"
#include <esp_mac.h>

View File

@@ -19,10 +19,12 @@
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
static const char *TAG = "SECOND_UART";
#endif
#include "second_uart.h"
static const char *TAG = "SECOND_UART";
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)

View File

@@ -13,8 +13,11 @@ void uart_printf(const char *format, ...);
#define pr uart_printf
#if defined(CONFIG_OEPL_HARDWARE_PROFILE_DEFAULT)
#define CONFIG_OEPL_HARDWARE_UART_TX 3
#define CONFIG_OEPL_HARDWARE_UART_RX 2
#define CONFIG_OEPL_HARDWARE_UART_TX 3
#define CONFIG_OEPL_HARDWARE_UART_RX 2
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_LILYGO)
#define CONFIG_OEPL_HARDWARE_UART_TX 24
#define CONFIG_OEPL_HARDWARE_UART_RX 23
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_POE_AP)
#define CONFIG_OEPL_HARDWARE_UART_TX 5
#define CONFIG_OEPL_HARDWARE_UART_RX 18

View File

@@ -17,7 +17,9 @@
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
#endif
#include "nvs_flash.h"
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }

View File

@@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(OpenEPaperLink_esp32_C6)
project(OpenEPaperLink_esp32_H2)

View File

@@ -1,9 +1,3 @@
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 ".")
SRC_DIRS "../../OpenEPaperLink_esp32_C6_AP/main"
INCLUDE_DIRS "../../OpenEPaperLink_esp32_C6_AP/main")

View File

@@ -13,6 +13,9 @@ menu "OEPL Hardware config"
config OEPL_HARDWARE_PROFILE_CUSTOM
bool "Custom"
config OEPL_HARDWARE_PROFILE_LILYGO
bool "LILYGO-AP"
endchoice
config OEPL_HARDWARE_UART_TX

View File

@@ -1,562 +0,0 @@
#include "sdkconfig.h"
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <driver/spi_master.h>
#include <driver/gpio.h>
#include "esp_log.h"
#include "radio.h"
#include "proto.h"
#include "cc1101_radio.h"
#include "SubGigRadio.h"
void DumpHex(void *AdrIn,int Len);
#define LOGE(format, ... ) \
printf("%s#%d: " format,__FUNCTION__,__LINE__,## __VA_ARGS__)
#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;
}
// return SUBGIG_ERR_NONE aka ESP_OK aka 0 if CC1101 is detected and all is good
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<<CONFIG_GDO0_GPIO,
//set as input mode
.mode = GPIO_MODE_INPUT,
//enable pull-up mode
.pull_up_en = 1,
.pull_down_en = 0
};
int ErrLine = 0;
SubGigErr Ret = SUBGIG_ERR_NONE;
do {
gpio_reset_pin(CONFIG_CSN_GPIO);
gpio_set_direction(CONFIG_CSN_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(CONFIG_CSN_GPIO, 1);
spi_bus_config_t buscfg = {
.sclk_io_num = CONFIG_SCK_GPIO,
.mosi_io_num = CONFIG_MOSI_GPIO,
.miso_io_num = CONFIG_MISO_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1
};
if((Err = spi_bus_initialize(HOST_ID,&buscfg,SPI_DMA_CH_AUTO)) != 0) {
ErrLine = __LINE__;
break;
}
if((Err = spi_bus_add_device(HOST_ID,&devcfg,&gSpiHndl)) != 0) {
ErrLine = __LINE__;
break;
}
// Configure GDO0, interrupt on falling edge
if((Err = gpio_config(&io_conf)) != 0) {
ErrLine = __LINE__;
break;
}
// Configure GDO2, interrupts disabled
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pin_bit_mask = 1ULL<<CONFIG_GDO2_GPIO;
if((Err = gpio_config(&io_conf)) != 0) {
ErrLine = __LINE__;
break;
}
// install gpio isr service
if((Err = gpio_install_isr_service(0)) != 0) {
ErrLine = __LINE__;
break;
}
//hook isr handler for specific gpio pin
Err = gpio_isr_handler_add(CONFIG_GDO0_GPIO,gpio_isr_handler,
(void*) CONFIG_GDO0_GPIO);
if(Err != 0) {
ErrLine = __LINE__;
break;
}
// Check Chip ID
if(!CC1101_Present()) {
Ret = SUBGIG_CC1101_NOT_FOUND;
break;
}
gSubGigData.Present = true;
SubGig_CC1101_reset();
CC1101_SetConfig(NULL);
SubGig_CC1101_SetConfig(gDmitry915);
#if 0
CC1101_DumpRegs();
#endif
if(ch != 0) {
SubGig_radioSetChannel(ch);
}
// good to go!
} while(false);
if(ErrLine != 0) {
LOG("%s#%d: failed %d\n",__FUNCTION__,ErrLine,Err);
if(Err == 0) {
Ret = ESP_FAIL;
}
}
return Ret;
}
SubGigErr SubGig_radioSetChannel(uint8_t ch)
{
SubGigErr Ret = SUBGIG_ERR_NONE;
RfSetting SetChannr[2] = {
{CC1101_CHANNR,0},
{0xff,0} // end of table
};
do {
if(!gSubGigData.Enabled && gSubGigData.Present && ch != 0) {
gSubGigData.Enabled = true;
LOG("SubGhz enabled\n");
}
if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) {
break;
}
if(ch == 0) {
// Disable SubGhz
LOG("SubGhz disabled\n");
gSubGigData.Enabled = false;
break;
}
LOG("Set channel %d\n",ch);
if(ch >= 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);
CC1101_setRxState();
} 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;
}
// Clear RxAvailable, in TX GDO0 deasserts on TX FIFO underflows
gSubGigData.RxAvailable = false;
// 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;
}
CC1101_logState();
if(!gSubGigData.RxAvailable && gpio_get_level(CONFIG_GDO0_GPIO) == 1) {
// Did we miss an interrupt?
if(gpio_get_level(CONFIG_GDO0_GPIO) == 1) {
// Yup!
LOGE("SubGhz lost interrupt\n");
gSubGigData.RxAvailable = true;
}
}
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

View File

@@ -1,40 +0,0 @@
#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 (6)
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_

View File

@@ -1,790 +0,0 @@
// Large portions of this code was copied from:
// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright
/*
* Copyright (c) 2011 panStamp <contact@panstamp.com>
* Copyright (c) 2016 Tyler Sommer <contact@tylersommer.pro>
*
* 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 <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <driver/spi_master.h>
#include "proto.h"
#include "cc1101_radio.h"
#include "radio.h"
#define ENABLE_LOGGING 0
// LOGA - generic logging, always enabled
#define LOGA(format, ... ) printf(format,## __VA_ARGS__)
// LOGE - error logging, always enabled
#define LOGE(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
#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
#define ENABLE_VERBOSE_LOGGING 0
#if ENABLE_VERBOSE_LOGGING
#define LOGV(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
#define LOGV_RAW(format, ... ) printf(format,## __VA_ARGS__)
#else
#define LOGV(format, ... )
#define LOGB_RAW(format, ... )
#endif
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <driver/spi_master.h>
#include <driver/gpio.h>
#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 0x80
// IOCFG2 GDO2: high when TX FIFO at or above the TX FIFO threshold
#define CC1101_DEFVAL_IOCFG2 0x02
// IOCFG1 GDO1: High impedance (3-state)
#define CC1101_DEFVAL_IOCFG1 0x2E
// GDO0 goes high when sync word has been sent / received, and
// goes low at the end of the packet.
// In TX mode the pin will go low if the TX FIFO underflows.
#define CC1101_DEFVAL_IOCFG0 0x06
// Threshold = 32 bytes (1/2 of FIFO len)
#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 0
#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_setTxState(void);
void setIdleState(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 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
int32_t gFreqErrSum;
uint8_t gFreqErrSumCount;
int8_t gFreqCorrection;
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) {
LOGV("0x%x -> %s(0x%x)\n",value,RegNamesCC1101[regAddr],regAddr);
}
else {
LOGV("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("<Register><Name>%s</Name><Value>0x%02X</Value></Register>\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) {
LOGE("TX FIFO underflow, BytesSent %d\n",BytesSent);
ErrLine = __LINE__;
break;
}
CanSend = 64 - CanSend;
if(CanSend == 0) {
LOGE("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__;
LOGE("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) {
LOGE("%s#%d: failure\n",__FUNCTION__,ErrLine);
}
return Ret;
}
// Called when GDO0 goes low, i.e. end of packet.
// Everything has been received.
// NB: this means the entire packet must fit in the FIFO so maximum
// message length is 64 bytes.
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;
int8_t FreqErr;
int8_t FreqCorrection;
// Any data waiting to be read and no overflow?
do {
if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) {
LOGE("RxFifo overflow\n");
Ret = -2;
break;
}
if(rxBytes < 2) {
// should have at least 2 bytes, packet len and one byte of data
LOGE("Internal error, rxBytes = %d\n",rxBytes);
Ret = -2;
break;
}
// Get packet length
Ret = readConfigReg(CC1101_RXFIFO);
if(Ret > RxBufLen) {
// Toss the data
LOGE("RxBuf too small %d < %d\n",RxBufLen,Ret);
Ret = -1;
break;
}
// Read the data
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 error, ignore the packet
LOG("Ignoring %d byte packet, CRC error\n",Ret);
Ret = 0;
break;
}
// CRC is valid
if(pRssi != NULL) {
*pRssi = Rssi;
}
if(pLqi != NULL) {
*pLqi = Lqi & CC1101_LQI_MASK;
}
FreqErr = (int8_t) CC1101_readReg(CC1101_FREQEST,CC1101_STATUS_REGISTER);
if(FreqErr != 0 && gFreqErrSumCount < 255) {
gFreqErrSum += FreqErr + gFreqCorrection;
gFreqErrSumCount++;
FreqCorrection = (int8_t) (gFreqErrSum / gFreqErrSumCount);
if(gFreqCorrection != FreqCorrection) {
LOGA("FreqCorrection %d -> %d\n",gFreqCorrection,FreqCorrection);
gFreqCorrection = FreqCorrection;
CC1101_writeReg(CC1101_FSCTRL0,gFreqCorrection);
}
if(gFreqErrSumCount == 255) {
LOGA("Final FreqCorrection %d\n",gFreqCorrection);
}
}
} while(false);
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 || ChipVersion == 4)) {
LOGA("CC1101 detected\n");
Ret = true;
}
else {
if(PartNum != 0) {
LOGA("Invalid PartNum 0x%x\n",PartNum);
}
else {
LOGA("Invalid or unsupported ChipVersion 0x%x\n",ChipVersion);
}
}
return Ret;
}
void CC1101_SetConfig(const RfSetting *pConfig)
{
int i;
uint8_t RegWasSet[CC1101_TEST0 + 1];
uint8_t Reg;
memset(RegWasSet,0,sizeof(RegWasSet));
setIdleState();
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
}
}
void setIdleState()
{
uint8_t MarcState;
CC1101_cmdStrobe(CC1101_SIDLE);
// Wait for it
do {
MarcState = readStatusReg(CC1101_MARCSTATE);
} while(MarcState != CC1101_STATE_IDLE);
}
void CC1101_logState()
{
static uint8_t LastMarcState = 0xff;
uint8_t MarcState;
MarcState = readStatusReg(CC1101_MARCSTATE);
if(LastMarcState != MarcState) {
LOG("MarcState 0x%x -> 0x%x\n",LastMarcState,MarcState);
LastMarcState = MarcState;
}
}
#endif // CONFIG_OEPL_SUBGIG_SUPPORT

View File

@@ -1,118 +0,0 @@
// Large portions of this code was copied from:
// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright
/*
* Copyright (c) 2011 panStamp <contact@panstamp.com>
* Copyright (c) 2016 Tyler Sommer <contact@tylersommer.pro>
*
* 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);
void CC1101_logState(void);
void CC1101_setRxState(void);
#endif // __CC1101_RADIO_H_

View File

@@ -1,48 +0,0 @@
#include "led.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "proto.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_LEDS 2
const gpio_num_t led_pins[NUM_LEDS] = {LED1, LED2};
TimerHandle_t led_timers[NUM_LEDS] = {0};
void led_timer_callback(TimerHandle_t xTimer) {
int led_index = (int)pvTimerGetTimerID(xTimer);
if (led_index >= 0 && led_index < NUM_LEDS) {
gpio_set_level(led_pins[led_index], 0);
}
}
void init_led() {
gpio_config_t led1 = {};
led1.intr_type = GPIO_INTR_DISABLE;
led1.mode = GPIO_MODE_OUTPUT;
led1.pin_bit_mask = ((1ULL << LED1) | (1ULL << LED2));
led1.pull_down_en = 0;
led1.pull_up_en = 0;
gpio_config(&led1);
for (int i = 0; i < NUM_LEDS; i++) {
led_timers[i] = xTimerCreate("led_timer", pdMS_TO_TICKS(50), pdFALSE, (void *)i, led_timer_callback);
}
}
void led_flash(int nr) {
gpio_set_level(led_pins[nr], 1);
if (nr >= 0 && nr < NUM_LEDS) {
xTimerStart(led_timers[nr], 0);
}
}
void led_set(int nr, bool state) {
gpio_set_level(nr, state);
}

View File

@@ -1,6 +0,0 @@
#pragma once
#include <stdbool.h>
void init_led();
void led_set(int nr, bool state);
void led_flash(int nr);

View File

@@ -1,833 +0,0 @@
// Ported to ESP32-H2 By ATC1441(ATCnetz.de) for OpenEPaperLink at ~08.2023
#include "main.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_ieee802154.h"
#include "esp_log.h"
#include "esp_phy_init.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "led.h"
#include "proto.h"
#include "radio.h"
#include "sdkconfig.h"
#include "second_uart.h"
//#include "soc/lp_uart_reg.h"
#include "soc/uart_struct.h"
#include "utils.h"
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "SubGigRadio.h"
static const char *TAG = "MAIN";
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
#define DATATYPE_NOUPDATE 0
#define HW_TYPE 0xC6
#define MAX_PENDING_MACS 250
#define HOUSEKEEPING_INTERVAL 60UL
struct pendingData pendingDataArr[MAX_PENDING_MACS];
// VERSION GOES HERE!
uint16_t version = 0x001d;
#define RAW_PKT_PADDING 2
uint8_t radiotxbuffer[128];
uint8_t radiorxbuffer[128];
static uint32_t housekeepingTimer;
struct blockRequest requestedData = {0}; // holds which data was requested by the tag
uint8_t dstMac[8]; // target for the block transfer
uint16_t dstPan; //
static uint32_t blockStartTimer = 0; // reference that holds when the AP sends the next block
uint32_t nextBlockAttempt = 0; // reference time for when the AP can request a new block from the ESP32
uint8_t seq = 0; // holds current sequence number for transmission
uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE + 5]; // block transfer buffer
uint8_t lastAckMac[8] = {0};
// these variables hold the current mac were talking to
#define CONCURRENT_REQUEST_DELAY 1200UL
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;
uint8_t curPendingData = 0;
uint8_t curNoUpdate = 0;
bool highspeedSerial = false;
void sendXferCompleteAck(uint8_t *dst);
void sendCancelXfer(uint8_t *dst);
void espNotifyAPInfo();
// tools
void addCRC(void *p, uint8_t len) {
uint8_t total = 0;
for (uint8_t c = 1; c < len; c++) {
total += ((uint8_t *) p)[c];
}
((uint8_t *) p)[0] = total;
}
bool checkCRC(void *p, uint8_t len) {
uint8_t total = 0;
for (uint8_t c = 1; c < len; c++) {
total += ((uint8_t *) p)[c];
}
return ((uint8_t *) p)[0] == total;
}
uint8_t getPacketType(void *buffer) {
struct MacFcs *fcs = buffer;
if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) {
// broadcast frame
uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameBcast)];
return type;
} else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) {
// normal frame
uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameNormal)];
return type;
}
return 0;
}
uint8_t getBlockDataLength() {
uint8_t partNo = 0;
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) {
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
partNo++;
}
}
return partNo;
}
// pendingdata slot stuff
int8_t findSlotForMac(const uint8_t *mac) {
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
if (memcmp(mac, ((uint8_t *) &(pendingDataArr[c].targetMac)), 8) == 0) {
if (pendingDataArr[c].attemptsLeft != 0) {
return c;
}
}
}
return -1;
}
int8_t findFreeSlot() {
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
if (pendingDataArr[c].attemptsLeft == 0) {
return c;
}
}
return -1;
}
int8_t findSlotForVer(const uint8_t *ver) {
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
if (memcmp(ver, ((uint8_t *) &(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) {
if (pendingDataArr[c].attemptsLeft != 0) return c;
}
}
return -1;
}
void deleteAllPendingDataForVer(const uint8_t *ver) {
int8_t slot = -1;
do {
slot = findSlotForVer(ver);
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
} while (slot != -1);
}
void deleteAllPendingDataForMac(const uint8_t *mac) {
int8_t slot = -1;
do {
slot = findSlotForMac(mac);
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
} while (slot != -1);
}
void countSlots() {
curPendingData = 0;
curNoUpdate = 0;
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
if (pendingDataArr[c].attemptsLeft != 0) {
if (pendingDataArr[c].availdatainfo.dataType != 0) {
curPendingData++;
} else {
curNoUpdate++;
}
}
}
}
// processing serial data
#define ZBS_RX_WAIT_HEADER 0
#define ZBS_RX_WAIT_SDA 1 // send data avail
#define ZBS_RX_WAIT_CANCEL 2 // cancel traffic for mac
#define ZBS_RX_WAIT_SCP 3 // set channel power
#define ZBS_RX_WAIT_BLOCKDATA 4
bool isSame(uint8_t *in1, char *in2, int len) {
bool flag = 1;
for (int i = 0; i < len; i++) {
if (in1[i] != in2[i]) flag = 0;
}
return flag;
}
int blockPosition = 0;
void processSerial(uint8_t lastchar) {
static uint8_t cmdbuffer[4];
static uint8_t RXState = 0;
static uint8_t serialbuffer[48];
static uint8_t *serialbufferp;
static uint8_t bytesRemain = 0;
static uint32_t lastSerial = 0;
static uint32_t blockStartTime = 0;
if ((RXState != ZBS_RX_WAIT_HEADER) && ((getMillis() - lastSerial) > 1000)) {
RXState = ZBS_RX_WAIT_HEADER;
ESP_LOGI(TAG, "UART Timeout");
}
lastSerial = getMillis();
switch (RXState) {
case ZBS_RX_WAIT_HEADER:
// shift characters in
for (uint8_t c = 0; c < 3; c++) {
cmdbuffer[c] = cmdbuffer[c + 1];
}
cmdbuffer[3] = lastchar;
if (isSame(cmdbuffer + 1, ">D>", 3)) {
pr("ACK>");
blockStartTime = getMillis();
ESP_LOGI(TAG, "Starting BlkData, %lu ms after request", blockStartTime - nextBlockAttempt );
blockPosition = 0;
RXState = ZBS_RX_WAIT_BLOCKDATA;
}
if (isSame(cmdbuffer, "SDA>", 4)) {
ESP_LOGI(TAG, "SDA In");
RXState = ZBS_RX_WAIT_SDA;
bytesRemain = sizeof(struct pendingData);
serialbufferp = serialbuffer;
break;
}
if (isSame(cmdbuffer, "CXD>", 4)) {
ESP_LOGI(TAG, "CXD In");
RXState = ZBS_RX_WAIT_CANCEL;
bytesRemain = sizeof(struct pendingData);
serialbufferp = serialbuffer;
break;
}
if (isSame(cmdbuffer, "SCP>", 4)) {
ESP_LOGI(TAG, "SCP In");
RXState = ZBS_RX_WAIT_SCP;
bytesRemain = sizeof(struct espSetChannelPower);
serialbufferp = serialbuffer;
break;
}
if (isSame(cmdbuffer, "NFO?", 4)) {
pr("ACK>");
ESP_LOGI(TAG, "NFO? In");
espNotifyAPInfo();
RXState = ZBS_RX_WAIT_HEADER;
}
if (isSame(cmdbuffer, "RDY?", 4)) {
pr("ACK>");
ESP_LOGI(TAG, "RDY? In");
RXState = ZBS_RX_WAIT_HEADER;
}
if (isSame(cmdbuffer, "RSET", 4)) {
pr("ACK>");
ESP_LOGI(TAG, "RSET In");
delay(100);
// TODO RESET US HERE
RXState = ZBS_RX_WAIT_HEADER;
}
if (isSame(cmdbuffer, "HSPD", 4)) {
pr("ACK>");
ESP_LOGI(TAG, "HSPD In, switching to 2000000");
delay(100);
uart_switch_speed(2000000);
delay(100);
highspeedSerial = true;
pr("ACK>");
RXState = ZBS_RX_WAIT_HEADER;
}
break;
case ZBS_RX_WAIT_BLOCKDATA:
blockbuffer[blockPosition++] = 0xAA ^ lastchar;
if (blockPosition >= 4100) {
ESP_LOGI(TAG, "Blockdata fully received in %lu ms, %lu ms after the request", getMillis() - blockStartTime, getMillis() - nextBlockAttempt);
RXState = ZBS_RX_WAIT_HEADER;
}
break;
case ZBS_RX_WAIT_SDA:
*serialbufferp = lastchar;
serialbufferp++;
bytesRemain--;
if (bytesRemain == 0) {
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
struct pendingData *pd = (struct pendingData *) serialbuffer;
int8_t slot = findSlotForMac(pd->targetMac);
if (slot == -1) slot = findFreeSlot();
if (slot != -1) {
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
pr("ACK>");
} else {
pr("NOQ>");
}
} else {
pr("NOK>");
}
RXState = ZBS_RX_WAIT_HEADER;
}
break;
case ZBS_RX_WAIT_CANCEL:
*serialbufferp = lastchar;
serialbufferp++;
bytesRemain--;
if (bytesRemain == 0) {
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
struct pendingData *pd = (struct pendingData *) serialbuffer;
deleteAllPendingDataForMac((uint8_t *) &pd->targetMac);
pr("ACK>");
} else {
pr("NOK>");
}
RXState = ZBS_RX_WAIT_HEADER;
}
break;
case ZBS_RX_WAIT_SCP:
*serialbufferp = lastchar;
serialbufferp++;
bytesRemain--;
if (bytesRemain == 0) {
if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower))) {
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;
}
goto SCPfailed;
SCPchannelFound:
pr("ACK>");
if (curChannel != scp->channel) {
radioSetChannel(scp->channel);
curChannel = scp->channel;
}
curPower = scp->power;
radioSetTxPower(scp->power);
ESP_LOGI(TAG, "Set channel: %d power: %d", curChannel, curPower);
} else {
SCPfailed:
pr("NOK>");
}
RXState = ZBS_RX_WAIT_HEADER;
}
break;
}
}
// sending data to the ESP
void espBlockRequest(const struct blockRequest *br, uint8_t *src) {
struct espBlockRequest *ebr = (struct espBlockRequest *) blockbuffer;
uartTx('R');
uartTx('Q');
uartTx('B');
uartTx('>');
memcpy(&(ebr->ver), &(br->ver), 8);
memcpy(&(ebr->src), src, 8);
ebr->blockId = br->blockId;
addCRC(ebr, sizeof(struct espBlockRequest));
for (uint8_t c = 0; c < sizeof(struct espBlockRequest); c++) {
uartTx(((uint8_t *) ebr)[c]);
}
}
void espNotifyAvailDataReq(const struct AvailDataReq *adr, const uint8_t *src) {
uartTx('A');
uartTx('D');
uartTx('R');
uartTx('>');
struct espAvailDataReq eadr = {0};
memcpy((void *) eadr.src, (void *) src, 8);
memcpy((void *) &eadr.adr, (void *) adr, sizeof(struct AvailDataReq));
addCRC(&eadr, sizeof(struct espAvailDataReq));
for (uint8_t c = 0; c < sizeof(struct espAvailDataReq); c++) {
uartTx(((uint8_t *) &eadr)[c]);
}
}
void espNotifyXferComplete(const uint8_t *src) {
struct espXferComplete exfc;
memcpy(&exfc.src, src, 8);
uartTx('X');
uartTx('F');
uartTx('C');
uartTx('>');
addCRC(&exfc, sizeof(exfc));
for (uint8_t c = 0; c < sizeof(exfc); c++) {
uartTx(((uint8_t *) &exfc)[c]);
}
}
void espNotifyTimeOut(const uint8_t *src) {
struct espXferComplete exfc;
memcpy(&exfc.src, src, 8);
uartTx('X');
uartTx('T');
uartTx('O');
uartTx('>');
addCRC(&exfc, sizeof(exfc));
for (uint8_t c = 0; c < sizeof(exfc); c++) {
uartTx(((uint8_t *) &exfc)[c]);
}
}
void espNotifyAPInfo() {
pr("TYP>%02X", HW_TYPE);
pr("VER>%04X", version);
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
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);
pr("NOP>%02X", curNoUpdate);
}
void espNotifyTagReturnData(uint8_t *src, uint8_t len) {
struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me
struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer;
if (memcmp((void *) & trd->dataVer, lastTagReturn, 8) == 0) {
return;
} else {
memcpy(lastTagReturn, &trd->dataVer, 8);
}
memcpy(etrd->src, src, 8);
etrd->len = len;
memcpy(&etrd->returnData, trd, len);
addCRC(etrd, len + 10);
uartTx('T');
uartTx('R');
uartTx('D');
uartTx('>');
for (uint8_t c = 0; c < len + 10; c++) {
uartTx(((uint8_t *)etrd)[c]);
}
}
// process data from tag
void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer;
struct blockRequest *blockReq = (struct blockRequest *) (buffer + sizeof(struct MacFrameNormal) + 1);
if (!checkCRC(blockReq, sizeof(struct blockRequest))) return;
// check if we're already talking to this mac
if (memcmp(rxHeader->src, lastBlockMac, 8) == 0) {
lastBlockRequest = getMillis();
} else {
// we weren't talking to this mac, see if there was a transfer in progress from another mac, recently
if ((getMillis() - lastBlockRequest) > CONCURRENT_REQUEST_DELAY) {
// mark this mac as the new current mac we're talking to
memcpy((void *) lastBlockMac, (void *) rxHeader->src, 8);
lastBlockRequest = getMillis();
} else {
// we're talking to another mac, let this mac know we can't accomodate another request right now
pr("BUSY!\n");
sendCancelXfer(rxHeader->src);
return;
}
}
// check if we have data for this mac
if (findSlotForMac(rxHeader->src) == -1) {
// no data for this mac, politely tell it to fuck off
sendCancelXfer(rxHeader->src);
return;
}
bool requestDataDownload = false;
if ((blockReq->blockId != requestedData.blockId) || (blockReq->ver != requestedData.ver)) {
// requested block isn't already in the buffer
requestDataDownload = true;
} else {
// requested block is already in the buffer
if (forceBlockDownload) {
if ((getMillis() - nextBlockAttempt) > 380) {
requestDataDownload = true;
pr("FORCED\n");
} else {
pr("IGNORED\n");
}
}
}
// copy blockrequest into requested data
memcpy(&requestedData, blockReq, sizeof(struct blockRequest));
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
struct blockRequestAck *blockRequestAck = (struct blockRequestAck *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct blockRequestAck) + RAW_PKT_PADDING;
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST_ACK;
if (blockStartTimer == 0) {
if (requestDataDownload) {
if (highspeedSerial == true) {
blockRequestAck->pleaseWaitMs = 140;
} else {
blockRequestAck->pleaseWaitMs = 550;
}
} else {
// block is already in buffer
blockRequestAck->pleaseWaitMs = 30;
}
} else {
blockRequestAck->pleaseWaitMs = 30;
}
blockStartTimer = getMillis() + blockRequestAck->pleaseWaitMs;
memcpy(txHeader->src, mSelfMac, 8);
memcpy(txHeader->dst, rxHeader->src, 8);
txHeader->pan = rxHeader->pan;
txHeader->fcs.frameType = 1;
txHeader->fcs.panIdCompressed = 1;
txHeader->fcs.destAddrType = 3;
txHeader->fcs.srcAddrType = 3;
txHeader->seq = seq++;
addCRC((void *) blockRequestAck, sizeof(struct blockRequestAck));
radioTx(radiotxbuffer);
// save the target for the blockdata
memcpy(dstMac, rxHeader->src, 8);
dstPan = rxHeader->pan;
if (requestDataDownload) {
blockPosition = 0;
espBlockRequest(&requestedData, rxHeader->src);
nextBlockAttempt = getMillis();
}
}
void processAvailDataReq(uint8_t *buffer) {
struct MacFrameBcast *rxHeader = (struct MacFrameBcast *) buffer;
struct AvailDataReq *availDataReq = (struct AvailDataReq *) (buffer + sizeof(struct MacFrameBcast) + 1);
if (!checkCRC(availDataReq, sizeof(struct AvailDataReq))) return;
// prepare tx buffer to send a response
memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct AvailDataInfo) + 2); // 120);
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
struct AvailDataInfo *availDataInfo = (struct AvailDataInfo *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct AvailDataInfo) + RAW_PKT_PADDING;
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_AVAIL_DATA_INFO;
// check to see if we have data available for this mac
bool haveData = false;
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
if (pendingDataArr[c].attemptsLeft) {
if (memcmp(pendingDataArr[c].targetMac, rxHeader->src, 8) == 0) {
haveData = true;
memcpy((void *) availDataInfo, &(pendingDataArr[c].availdatainfo), sizeof(struct AvailDataInfo));
break;
}
}
}
// couldn't find data for this mac
if (!haveData) availDataInfo->dataType = DATATYPE_NOUPDATE;
memcpy(txHeader->src, mSelfMac, 8);
memcpy(txHeader->dst, rxHeader->src, 8);
txHeader->pan = rxHeader->dstPan;
txHeader->fcs.frameType = 1;
txHeader->fcs.panIdCompressed = 1;
txHeader->fcs.destAddrType = 3;
txHeader->fcs.srcAddrType = 3;
txHeader->seq = seq++;
addCRC(availDataInfo, sizeof(struct AvailDataInfo));
radioTx(radiotxbuffer);
memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet
espNotifyAvailDataReq(availDataReq, rxHeader->src);
}
void processXferComplete(uint8_t *buffer) {
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer;
sendXferCompleteAck(rxHeader->src);
if (memcmp(lastAckMac, rxHeader->src, 8) != 0) {
memcpy((void *) lastAckMac, (void *) rxHeader->src, 8);
espNotifyXferComplete(rxHeader->src);
int8_t slot = findSlotForMac(rxHeader->src);
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
}
}
void processTagReturnData(uint8_t *buffer, uint8_t len) {
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer;
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) {
return;
}
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK;
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
memcpy(frameHeader->src, mSelfMac, 8);
memcpy(frameHeader->dst, rxframe->src, 8);
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
radiotxbuffer[2] = 0xCC; // normal frame
frameHeader->seq = seq++;
frameHeader->pan = rxframe->srcPan;
radioTx(radiotxbuffer);
espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1));
}
// send block data to the tag
void sendPart(uint8_t partNo) {
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
struct blockPart *blockPart = (struct blockPart *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PART;
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE + 1 + RAW_PKT_PADDING;
memcpy(frameHeader->src, mSelfMac, 8);
memcpy(frameHeader->dst, dstMac, 8);
blockPart->blockId = requestedData.blockId;
blockPart->blockPart = partNo;
memcpy(&(blockPart->data), blockbuffer + (partNo * BLOCK_PART_DATA_SIZE), BLOCK_PART_DATA_SIZE);
addCRC(blockPart, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE);
frameHeader->fcs.frameType = 1;
frameHeader->fcs.panIdCompressed = 1;
frameHeader->fcs.destAddrType = 3;
frameHeader->fcs.srcAddrType = 3;
frameHeader->seq = seq++;
frameHeader->pan = dstPan;
radioTx(radiotxbuffer);
}
void sendBlockData() {
if (getBlockDataLength() == 0) {
pr("Invalid block request received, 0 parts..\n");
requestedData.requestedParts[0] |= 0x01;
}
pr("Sending parts:");
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS); c++) {
if (c % 10 == 0) pr(" ");
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
pr("X");
} else {
pr(".");
}
}
pr("\n");
uint8_t partNo = 0;
while (partNo < BLOCK_MAX_PARTS) {
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++) {
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
sendPart(c);
partNo++;
}
}
if(dstPan == PROTO_PAN_ID_SUBGHZ) {
// Don't send BLOCK_MAX_PARTS for subgig, it requests what it
// can handle with its limited RAM
break;
}
}
}
void sendXferCompleteAck(uint8_t *dst) {
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_XFER_COMPLETE_ACK;
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
memcpy(frameHeader->src, mSelfMac, 8);
memcpy(frameHeader->dst, dst, 8);
frameHeader->fcs.frameType = 1;
frameHeader->fcs.panIdCompressed = 1;
frameHeader->fcs.destAddrType = 3;
frameHeader->fcs.srcAddrType = 3;
frameHeader->seq = seq++;
frameHeader->pan = dstPan;
radioTx(radiotxbuffer);
}
void sendCancelXfer(uint8_t *dst) {
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_CANCEL_XFER;
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
memcpy(frameHeader->src, mSelfMac, 8);
memcpy(frameHeader->dst, dst, 8);
frameHeader->fcs.frameType = 1;
frameHeader->fcs.panIdCompressed = 1;
frameHeader->fcs.destAddrType = 3;
frameHeader->fcs.srcAddrType = 3;
frameHeader->seq = seq++;
frameHeader->pan = dstPan;
radioTx(radiotxbuffer);
}
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);
memcpy(frameHeader->dst, rxframe->src, 8);
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
radiotxbuffer[2] = 0xCC; // normal frame
frameHeader->seq = seq++;
frameHeader->pan = rxframe->srcPan;
radioTx(radiotxbuffer);
}
void app_main(void) {
esp_event_loop_create_default();
init_nvs();
init_led();
init_second_uart();
requestedData.blockId = 0xFF;
// clear the array with pending information
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>");
pr("RDY>");
ESP_LOGI(TAG, "H2 ready!");
housekeepingTimer = getMillis();
while (1) {
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
int8_t ret = commsRxUnencrypted(radiorxbuffer);
if (ret > 1) {
led_flash(0);
// received a packet, lets see what it is
switch (getPacketType(radiorxbuffer)) {
case PKT_AVAIL_DATA_REQ:
if (ret == 28) {
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0,
sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2);
processAvailDataReq(radiorxbuffer);
} else if (ret == 40) {
// new version of the AvailDataReq struct
processAvailDataReq(radiorxbuffer);
}
break;
case PKT_BLOCK_REQUEST:
processBlockRequest(radiorxbuffer, 1);
break;
case PKT_BLOCK_PARTIAL_REQUEST:
processBlockRequest(radiorxbuffer, 0);
break;
case PKT_XFER_COMPLETE:
processXferComplete(radiorxbuffer);
break;
case PKT_PING:
sendPong(radiorxbuffer);
break;
case PKT_AVAIL_DATA_SHORTREQ:
// a short AvailDataReq is basically a very short (1 byte payload) packet that requires little preparation on the tx side, for optimal
// battery use bytes of the struct are set 0, so it passes the checksum test, and the ESP32 can detect that no interesting payload is
// sent
if (ret == 18) {
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2);
processAvailDataReq(radiorxbuffer);
}
break;
case PKT_TAG_RETURN_DATA:
processTagReturnData(radiorxbuffer, ret);
break;
default:
ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer));
break;
}
} else if (blockStartTimer == 0) {
vTaskDelay(10 / portTICK_PERIOD_MS);
}
uint8_t curr_char;
while (getRxCharSecond(&curr_char)) processSerial(curr_char);
if (blockStartTimer) {
if (getMillis() > blockStartTimer) {
sendBlockData();
blockStartTimer = 0;
}
}
}
memset(&lastTagReturn, 0, 8);
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) {
if (pendingDataArr[cCount].attemptsLeft == 1) {
if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) {
espNotifyTimeOut(pendingDataArr[cCount].targetMac);
}
pendingDataArr[cCount].attemptsLeft = 0;
} else if (pendingDataArr[cCount].attemptsLeft > 1) {
pendingDataArr[cCount].attemptsLeft--;
if (pendingDataArr[cCount].availdatainfo.nextCheckIn) pendingDataArr[cCount].availdatainfo.nextCheckIn--;
}
}
housekeepingTimer = getMillis();
}
}

View File

@@ -1 +0,0 @@
#pragma once

View File

@@ -1,194 +0,0 @@
#ifndef _PROTO_H_
#define _PROTO_H_
#include <stdint.h>
#define LED1 22
#define LED2 25
#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
#define ADDR_MODE_NONE (0)
#define ADDR_MODE_SHORT (2)
#define ADDR_MODE_LONG (3)
#define FRAME_TYPE_BEACON (0)
#define FRAME_TYPE_DATA (1)
#define FRAME_TYPE_ACK (2)
#define FRAME_TYPE_MAC_CMD (3)
#define SHORT_MAC_UNUSED (0x10000000UL) // for radioRxFilterCfg's myShortMac
struct MacFcs {
uint8_t frameType : 3;
uint8_t secure : 1;
uint8_t framePending : 1;
uint8_t ackReqd : 1;
uint8_t panIdCompressed : 1;
uint8_t rfu1 : 1;
uint8_t rfu2 : 2;
uint8_t destAddrType : 2;
uint8_t frameVer : 2;
uint8_t srcAddrType : 2;
} __attribute__((packed, aligned(1)));
struct MacFrameFromMaster {
struct MacFcs fcs;
uint8_t seq;
uint16_t pan;
uint8_t dst[8];
uint16_t from;
} __attribute__((packed, aligned(1)));
struct MacFrameNormal {
struct MacFcs fcs;
uint8_t seq;
uint16_t pan;
uint8_t dst[8];
uint8_t src[8];
} __attribute__((packed, aligned(1)));
struct MacFrameBcast {
struct MacFcs fcs;
uint8_t seq;
uint16_t dstPan;
uint16_t dstAddr;
uint16_t srcPan;
uint8_t src[8];
} __attribute__((packed, aligned(1)));
#define PKT_TAG_RETURN_DATA 0xE1
#define PKT_TAG_RETURN_DATA_ACK 0xE2
#define PKT_AVAIL_DATA_SHORTREQ 0xE3
#define PKT_AVAIL_DATA_REQ 0xE5
#define PKT_AVAIL_DATA_INFO 0xE6
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
#define PKT_BLOCK_REQUEST_ACK 0xE9
#define PKT_BLOCK_REQUEST 0xE4
#define PKT_BLOCK_PART 0xE8
#define PKT_XFER_COMPLETE 0xEA
#define PKT_XFER_COMPLETE_ACK 0xEB
#define PKT_CANCEL_XFER 0xEC
#define PKT_PING 0xED
#define PKT_PONG 0xEE
struct AvailDataReq {
uint8_t checksum;
uint8_t lastPacketLQI;
int8_t lastPacketRSSI;
int8_t temperature;
uint16_t batteryMv;
uint8_t hwType;
uint8_t wakeupReason;
uint8_t capabilities;
uint16_t tagSoftwareVersion;
uint8_t currentChannel;
uint8_t customMode;
uint8_t reserved[8];
} __attribute__((packed, aligned(1)));
struct oldAvailDataReq {
uint8_t checksum;
uint8_t lastPacketLQI;
int8_t lastPacketRSSI;
int8_t temperature;
uint16_t batteryMv;
uint8_t hwType;
uint8_t wakeupReason;
uint8_t capabilities;
} __attribute__((packed, aligned(1)));
struct AvailDataInfo {
uint8_t checksum;
uint64_t dataVer; // MD5 of potential traffic
uint32_t dataSize;
uint8_t dataType;
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
} __attribute__((packed, aligned(1)));
struct pendingData {
struct AvailDataInfo availdatainfo;
uint16_t attemptsLeft;
uint8_t targetMac[8];
} __attribute__((packed, aligned(1)));
struct blockPart {
uint8_t checksum;
uint8_t blockId;
uint8_t blockPart;
uint8_t data[];
} __attribute__((packed, aligned(1)));
struct blockData {
uint16_t size;
uint16_t checksum;
uint8_t data[];
} __attribute__((packed, aligned(1)));
#define TAG_RETURN_DATA_SIZE 90
struct tagReturnData {
uint8_t checksum;
uint8_t partId;
uint64_t dataVer;
uint8_t dataType;
uint8_t data[TAG_RETURN_DATA_SIZE];
} __attribute__((packed, aligned(1)));
#define BLOCK_PART_DATA_SIZE 99
#define BLOCK_MAX_PARTS 42
#define BLOCK_DATA_SIZE 4096UL
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
#define BLOCK_REQ_PARTS_BYTES 6
struct blockRequest {
uint8_t checksum;
uint64_t ver;
uint8_t blockId;
uint8_t type;
uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES];
} __attribute__((packed, aligned(1)));
struct blockRequestAck {
uint8_t checksum;
uint16_t pleaseWaitMs;
} __attribute__((packed, aligned(1)));
struct espBlockRequest {
uint8_t checksum;
uint64_t ver;
uint8_t blockId;
uint8_t src[8];
} __attribute__((packed, aligned(1)));
struct espXferComplete {
uint8_t checksum;
uint8_t src[8];
} __attribute__((packed, aligned(1)));
struct espAvailDataReq {
uint8_t checksum;
uint8_t src[8];
struct AvailDataReq adr;
} __attribute__((packed, aligned(1)));
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 {
uint8_t checksum;
uint8_t src[8];
uint8_t len;
struct tagReturnData returnData;
} __attribute__((packed, aligned(1)));
#endif

View File

@@ -1,150 +0,0 @@
#include <stddef.h>
#include "radio.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_ieee802154.h"
#include "esp_log.h"
#include "esp_phy_init.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "led.h"
#include "main.h"
#include "proto.h"
#include "sdkconfig.h"
// if you get an error about soc/lp_uart_reg.h not being found,
// you didn't choose the right build target. :-)
//#include "soc/lp_uart_reg.h"
#include "soc/uart_struct.h"
#include "utils.h"
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include "SubGigRadio.h"
static const char *TAG = "RADIO";
uint8_t mSelfMac[8];
volatile uint8_t isInTransmit = 0;
QueueHandle_t packet_buffer = NULL;
void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) {
ESP_EARLY_LOGI(TAG, "RX %d", frame[0]);
BaseType_t xHigherPriorityTaskWoken;
static uint8_t inner_rxPKT[130];
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
esp_ieee802154_receive_sfd_done();
}
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
isInTransmit = 0;
ESP_EARLY_LOGE(TAG, "TX Err: %d", error);
}
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
isInTransmit = 0;
ESP_EARLY_LOGI(TAG, "TX %d", frame[0]);
esp_ieee802154_receive_sfd_done();
}
static bool zigbee_is_enabled = false;
void radio_init(uint8_t ch) {
if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130);
// this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works
if(zigbee_is_enabled)
{
zigbee_is_enabled = false;
esp_ieee802154_disable();
}
zigbee_is_enabled = true;
esp_ieee802154_enable();
esp_ieee802154_set_channel(ch);
// esp_ieee802154_set_txpower(int8_t power);
esp_ieee802154_set_panid(PROTO_PAN_ID);
esp_ieee802154_set_promiscuous(false);
esp_ieee802154_set_coordinator(false);
esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE);
// esp_ieee802154_set_extended_address needs the MAC in reversed byte order
esp_read_mac(mSelfMac, ESP_MAC_IEEE802154);
uint8_t eui64_rev[8] = {0};
for (int i = 0; i < 8; i++) {
eui64_rev[7 - i] = mSelfMac[i];
}
esp_ieee802154_set_extended_address(eui64_rev);
esp_ieee802154_get_extended_address(mSelfMac);
esp_ieee802154_set_short_address(0xFFFE);
esp_ieee802154_set_rx_when_idle(true);
esp_ieee802154_receive();
led_flash(1);
vTaskDelay(100 / portTICK_PERIOD_MS);
led_flash(0);
vTaskDelay(100 / portTICK_PERIOD_MS);
led_flash(1);
vTaskDelay(100 / portTICK_PERIOD_MS);
led_flash(0);
ESP_LOGI(TAG, "Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x",
esp_ieee802154_get_panid(), esp_ieee802154_get_channel(),
mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3],
mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7],
esp_ieee802154_get_short_address());
}
// 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 (getMillis() - lastZbTx < 6) {
// }
// 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
while (isInTransmit) {
}
isInTransmit = 1;
esp_ieee802154_transmit(txPKT, false);
return true;
}
void radioSetChannel(uint8_t ch) {
radio_init(ch);
}
void radioSetTxPower(uint8_t power) {}
int8_t commsRxUnencrypted(uint8_t *data) {
static uint8_t inner_rxPKT_out[130];
if (xQueueReceive(packet_buffer, (void *)&inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) {
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;
}

View File

@@ -1,20 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#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);
#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

View File

@@ -1,116 +0,0 @@
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_ieee802154.h"
#include "esp_log.h"
#include "esp_phy_init.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "main.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
//#include "soc/lp_uart_reg.h"
#include "second_uart.h"
//static const char *TAG = "SECOND_UART";
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
static QueueHandle_t uart0_queue;
#define MAX_BUFF_POS 8000
volatile int curr_buff_pos = 0;
volatile int worked_buff_pos = 0;
volatile uint8_t buff_pos[MAX_BUFF_POS + 5];
static void uart_event_task(void *pvParameters);
void init_second_uart() {
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0));
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL);
}
void uart_switch_speed(int baudrate) {
uart_config_t uart_config = {
.baud_rate = baudrate,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
}
void uartTx(uint8_t data) { uart_write_bytes(1, (const char *) &data, 1); }
bool getRxCharSecond(uint8_t *newChar) {
if (curr_buff_pos != worked_buff_pos) {
*newChar = buff_pos[worked_buff_pos];
worked_buff_pos++;
worked_buff_pos %= MAX_BUFF_POS;
return true;
}
return false;
}
static void uart_event_task(void *pvParameters) {
uart_event_t event;
uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE);
for (;;) {
if (xQueueReceive(uart0_queue, (void *) &event, (TickType_t) portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
switch (event.type) {
case UART_DATA:
uart_read_bytes(1, dtmp, event.size, portMAX_DELAY);
for (int i = 0; i < event.size; i++) {
buff_pos[curr_buff_pos] = dtmp[i];
curr_buff_pos++;
curr_buff_pos %= MAX_BUFF_POS;
}
break;
default:
// ESP_LOGI(TAG, "uart event type: %d", event.type);
break;
}
}
}
free(dtmp);
dtmp = NULL;
vTaskDelete(NULL);
}
void uart_printf(const char *format, ...) {
va_list args;
va_start(args, format);
char buffer[128];
int len = vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
if (len > 0) {
uart_write_bytes(1, buffer, len);
}
}

View File

@@ -1,18 +0,0 @@
#pragma once
#include <inttypes.h>
void init_second_uart();
void uart_switch_speed(int baudrate);
void uartTx(uint8_t data);
bool getRxCharSecond(uint8_t *newChar);
void uart_printf(const char *format, ...);
#define pr uart_printf
#define CONFIG_OEPL_HARDWARE_UART_TX 24
#define CONFIG_OEPL_HARDWARE_UART_RX 23

View File

@@ -1,36 +0,0 @@
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_ieee802154.h"
#include "esp_log.h"
#include "esp_phy_init.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "main.h"
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
//#include "soc/lp_uart_reg.h"
#include "nvs_flash.h"
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }
uint32_t getMillis() { return (uint32_t) (esp_timer_get_time() / 1000); }
void init_nvs()
{
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
}

View File

@@ -1,5 +0,0 @@
#pragma once
void delay(int ms);
uint32_t getMillis();
void init_nvs();

View File

@@ -1,8 +1,16 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32h2"
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_OEPL_HARDWARE_PROFILE_LILYGO=y
CONFIG_OEPL_SUBGIG_SUPPORT=y
CONFIG_MISO_GPIO=25
CONFIG_SCK_GPIO=3
CONFIG_MOSI_GPIO=11
CONFIG_CSN_GPIO=8
CONFIG_GDO0_GPIO=2
CONFIG_GDO2_GPIO=22

View File

@@ -307,6 +307,7 @@ build_flags =
-D SERIAL_FLASHER_INTERFACE_UART=1
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
-D HAS_SUBGHZ
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
board_build.flash_mode=qio