commit b179e63a7f0f52de18d77536f8749b456b9d99a8 Author: Bruno Rybársky Date: Mon Apr 14 07:06:29 2025 +0200 init diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..dafb8ad --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +ARG DOCKER_TAG=latest +FROM espressif/idf:${DOCKER_TAG} + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN apt-get update -y && apt-get install udev -y + +RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] + +CMD ["/bin/bash", "-c"] \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..b801786 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,21 @@ +{ + "name": "ESP-IDF QEMU", + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.espIdfPath": "/opt/esp/idf", + "idf.toolsPath": "/opt/esp", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension", + "espressif.esp-idf-web" + ] + } + }, + "runArgs": ["--privileged"] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51c9513 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +sdkconfig +sdkconfig.old \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..837c329 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "ESP-IDF", + "compilerPath": "${config:idf.toolsPath}/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32s3-elf-gcc", + "compileCommands": "${config:idf.buildPath}/compile_commands.json", + "includePath": [ + "${config:idf.espIdfPath}/components/**", + "${config:idf.espIdfPathWin}/components/**", + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "${config:idf.espIdfPath}/components", + "${config:idf.espIdfPathWin}/components", + "${workspaceFolder}" + ], + "limitSymbolsToIncludedHeaders": true + } + } + ], + "version": 4 +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2511a38 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdbtarget", + "request": "attach", + "name": "Eclipse CDT GDB Adapter" + }, + { + "type": "espidf", + "name": "Launch", + "request": "launch" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8c30dd5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "C_Cpp.intelliSenseEngine": "default", + "idf.espIdfPath": "/home/bruno/esp/master/esp-idf", + "idf.pythonInstallPath": "/usr/bin/python", + "idf.openOcdConfigs": [ + "board/esp32s3-builtin.cfg" + ], + "idf.port": "/dev/ttyUSB0", + "idf.toolsPath": "/home/bruno/.espressif", + "idf.flashType": "UART", + "idf.customExtraVars": { + "OPENOCD_SCRIPTS": "/home/bruno/.espressif/tools/openocd-esp32/v0.12.0-esp32-20240821/openocd-esp32/share/openocd/scripts", + "ESP_ROM_ELF_DIR": "/home/bruno/.espressif/tools/esp-rom-elfs/20240305/", + "IDF_TARGET": "esp32s3" + }, + "files.associations": { + "**/debian/*.install": "plain", + "sx1262.h": "c" + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1184abf --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(LoRaIDF) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..455eb90 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# _Sample project_ + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This is the simplest buildable example. The example is used by command `idf.py create-project` +that copies the project to user specified path and set it's name. For more information follow the [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project) + + + +## How to use example +We encourage the users to use the example as a template for the new projects. +A recommended way is to follow the instructions on a [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project). + +## Example folder contents + +The project **sample_project** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main). + +ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` +files that provide set of directives and instructions describing the project's source files and targets +(executable, library, or both). + +Below is short explanation of remaining files in the project folder. + +``` +├── CMakeLists.txt +├── main +│   ├── CMakeLists.txt +│   └── main.c +└── README.md This is the file you are currently reading +``` +Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system. +They are not used or needed when building with CMake and idf.py. diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..94cc747 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "sx1262.c" "sx1262.h" "main.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..43f0735 --- /dev/null +++ b/main/main.c @@ -0,0 +1,215 @@ +#include +#include "sx1262.h" + +#define TAG "SX1262" + +const char *msg = "Testing 123 test why is this not on air"; + +void app_main(void) +{ + sx1262_init(); + sx1262_resetStats(); + ESP_LOGI(TAG, "Setting standby RC"); + sx1262_setStandby(SX1262_STANDBY_RC); + + ESP_LOGI(TAG, "Getting version"); + unsigned char versDat[16]; + sx1262_readRegister(0x0320, versDat, 16); + ESP_LOGI(TAG, "Version: %s", versDat); + + sx1262_status_t status = sx1262_get_status(); + + // Read status + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting TCXO"); + sx1262_setDIO3AsTCXOCtrl(SX1262_TCXO_VOLTAGE18dV, 320); + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting Buffer base address"); + sx1262_setBufferBaseAddress(0, 0); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting packet Type"); + sx1262_setPacketType(SX1262_PACKET_TYPE_LORA); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting RXTX fallback mode"); + sx1262_setRxTXFallbackMode(SX1262_FALLBACK_RC); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting CAD params"); + sx1262_setCadParams(0x03, 0x16, 0x0A, 0, 0); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Clearing IRQ status"); + sx1262_clearIrqStatus(0x43FF); + status = sx1262_get_status(); + + + + ESP_LOGI(TAG, "Setting Image rejection"); + sx1262_calibrateImage(0xD7, 0xDB); + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Calibrating Image rejection"); + sx1262_calibrate(SX1262_CALIBRATION_ALL); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting regulator"); + sx1262_setRegulatorMode(SX1262_REGULATOR_DC_DC_LDO); + status = sx1262_get_status(); + + uint8_t modType; + modType = sx1262_getPacketType(); + status = sx1262_get_status(); + ESP_LOGI(TAG, "ModType %d", modType); + + sx1262_LoRaModulationParams_t loraModParams; + + loraModParams.bandwidth = SX1262_LORA_BW_125; + loraModParams.codingRate = SX1262_LORA_CR_4_5; + loraModParams.lowDataRateOpt = 1; + loraModParams.spreadingFactor = SX1262_LORA_SF7; + + ESP_LOGI(TAG, "Setting modulation params"); + sx1262_setLoRaModulationParams(&loraModParams); + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting Sync word"); + uint8_t syncWord[2] = {0x14, 0x24}; + + sx1262_writeRegister(SX1262_LORA_SYNC_WORD_MSB, syncWord, 2); + status = sx1262_get_status(); + + uint8_t ocpBuf[1] = {SX126X_OCP_LEVEL_SX1262}; + + ESP_LOGI(TAG, "Setting overcurrent protection"); + sx1262_writeRegister(SX126X_OCP_CONFIGURATION, ocpBuf, 1); + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting RF Switch out"); + sx1262_setDIO2AsRfSwitchCtrl(1); + + status = sx1262_get_status(); + + sx1262_LoRaPacketParams_t loraPacketParams; + loraPacketParams.preambleLength = 10; + loraPacketParams.crcType = SX1262_CRC_ON; + loraPacketParams.headerType = SX1262_HEADER_TYPE_VARIABLE; + loraPacketParams.invertIQ = SX1262_STANDARD_IQ; + loraPacketParams.payloadLength = sizeof(msg); + + ESP_LOGI(TAG, "Setting packet params"); + sx1262_setLoRaPacketParams(&loraPacketParams); + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting frequency"); + sx1262_setFrequency(869525000); + + uint8_t clampConfig[1] = {0xDE}; + + ESP_LOGI(TAG, "Setting TX clamp"); + sx1262_writeRegister(SX126X_TX_CLAMP_CONFIG, clampConfig, 1); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting TX power"); + sx1262_configure_tx_power(0x04, 0x07, 0x01, 22, SX1262_Ramp_200U); + + status = sx1262_get_status(); + + + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting standby XOSC"); + sx1262_setStandby(SX1262_STANDBY_XOSC); + + status = sx1262_get_status(); + + + sx1262_setDioIrqParams(SX1262_IRQ_ALL, SX1262_IRQ_TXDone, 0, 0); + + + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Setting buffer base address"); + sx1262_setBufferBaseAddress(0, 0); + + status = sx1262_get_status(); + + + ESP_LOGI(TAG, "Writing message"); + sx1262_writeBuffer(0, (uint8_t *)msg, sizeof(msg)); + + ESP_LOGI(TAG, "Clearing IRQs"); + sx1262_clearIrqStatus(SX1262_IRQ_ALL); + + // sx1262_setTxContinuousWave(); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Getting modulation type..."); + modType = sx1262_getPacketType(); + ESP_LOGI(TAG, "ModType %d", modType); + status = sx1262_get_status(); + + // ESP_LOGI(TAG, "Enabling CW..."); + // sx1262_setTxContinuousWave(); + // status = sx1262_get_status(); + + uint8_t txModulation[1] = {0x04}; + + ESP_LOGI(TAG, "Setting modulation thing"); + sx1262_writeRegister(SX126X_TX_MODULATION, txModulation, 1); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Clearing IRQs"); + sx1262_clearIrqStatus(SX1262_IRQ_ALL); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Enabling TX..."); + sx1262_setMode(SX1262_TRANSMIT_MODE, 0); + status = sx1262_get_status(); + + ESP_LOGI(TAG, "Waiting for TX finish"); + while (1) + { + if (gpio_get_level(PIN_DIO1)) + { + ESP_LOGI(TAG, "Got IRQin"); + uint16_t irqS = sx1262_getIrqStatus(); + if (irqS & SX1262_IRQ_TXDone) + { + break; + } + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + + // vTaskDelay(pdMS_TO_TICKS(2000)); + // ESP_LOGI(TAG, "Returning back to sleep"); + // sx1262_setStandby(SX1262_STANDBY_XOSC); + + // status = sx1262_get_status(); + + ESP_LOGI(TAG, "Clearing IRQs"); + sx1262_clearIrqStatus(SX1262_IRQ_TXDone); + + status = sx1262_get_status(); + while (1) + { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + + // Set frequency to 868 MHz + + // Set TX power to 22 dBm + + // sx1262_setTxContinuousWave(); +} \ No newline at end of file diff --git a/main/sx1262.c b/main/sx1262.c new file mode 100644 index 0000000..4682117 --- /dev/null +++ b/main/sx1262.c @@ -0,0 +1,591 @@ +#include "sx1262.h" + +spi_device_handle_t spiSXko; + +#define TAG_SPIDUMP "[SPI]" + +void sx1262_init() +{ + ESP_LOGI(TAG, "Initializing SX1262..."); + + gpio_set_direction(PIN_NSS, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_RESET, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_BUSY, GPIO_MODE_INPUT); + + gpio_set_level(PIN_NSS, 1); + gpio_set_level(PIN_RESET, 1); + + spi_bus_config_t buscfg; + memset(&buscfg, 0, sizeof(spi_bus_config_t)); + buscfg.miso_io_num = PIN_MISO; + buscfg.mosi_io_num = PIN_MOSI; + buscfg.sclk_io_num = PIN_SCK; + buscfg.max_transfer_sz = 32; + buscfg.quadwp_io_num = -1; + buscfg.quadhd_io_num = -1; + + spi_device_interface_config_t devcfg = { + .command_bits = 0, + .address_bits = 0, + .mode = 0, + .cs_ena_pretrans = 10, + .clock_speed_hz = 8 * 1000 * 1000, + .spics_io_num = -1, + .flags = 0, + .queue_size = 1}; + + ESP_LOGI(TAG, "Initializing SPI bus..."); + esp_err_t ret = spi_bus_initialize(LORA_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "SPI bus init failed!"); + return; + } + + ESP_LOGI(TAG, "Adding SPI device..."); + ret = spi_bus_add_device(LORA_SPI_HOST, &devcfg, &spiSXko); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "SPI device init failed!"); + return; + } + + ESP_LOGI(TAG, "SX1262 Initialized"); + sx1262_reset(); +} + +void sx1262_reset() +{ + ESP_LOGI(TAG, "Resetting SX1262..."); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level(PIN_RESET, 0); + vTaskDelay(pdMS_TO_TICKS(20)); + gpio_set_level(PIN_RESET, 1); + vTaskDelay(pdMS_TO_TICKS(10)); + sx1262_wait_for_busy(); + ESP_LOGI(TAG, "SX1262 Reset complete."); +} + +void sx1262_wait_for_busy() +{ + ESP_LOGV("WAIT", "Waiting for SX1262 to be ready..."); + while (gpio_get_level(PIN_BUSY) == 1) + { + vTaskDelay(pdMS_TO_TICKS(10)); + } + ESP_LOGV("WAIT", "SX1262 is ready."); +} + +void sx1262_write_command(uint8_t cmd, uint8_t *data, uint8_t len) +{ + ESP_LOGV(TAG, "Writing command 0x%02X with length %d", cmd, len); + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + t.length = (len + 1) * 8; + uint8_t *tx_data = malloc(len + 1); + memset(tx_data, 0, len + 1); + tx_data[0] = cmd; + if (len) + { + memcpy(tx_data + 1, data, len); + } + t.tx_buffer = tx_data; + + sx1262_wait_for_busy(); + + ESP_LOGI(TAG_SPIDUMP, "SPI TX (cmd 0x%02X):", cmd); + ESP_LOG_BUFFER_HEXDUMP(TAG_SPIDUMP, tx_data, len + 1, ESP_LOG_INFO); + + gpio_set_level(PIN_NSS, 0); + esp_err_t ret = spi_device_transmit(spiSXko, &t); + gpio_set_level(PIN_NSS, 1); + + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "SPI write failed!"); + } + else + { + ESP_LOGV(TAG, "SPI write successful"); + } + free(tx_data); +} + +uint8_t SX1262_STATUS = 0; + +void sx1262_read_command(uint8_t cmd, uint8_t *tx_payload_buffer, uint8_t tx_payload_len, uint8_t *rx_buffer, uint8_t len) +{ + ESP_LOGV(TAG, "Reading command 0x%02X with expected length %d", cmd, len); + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + t.length = (len + 2) * 8; + uint8_t *tx_data = malloc(len + 2); + uint8_t *rx_data = malloc(len + 2); + memset(tx_data, 0, len + 2); + memset(rx_data, 0, len + 2); + + memset(tx_data, 0, sizeof(tx_data)); + memset(rx_data, 0, sizeof(rx_data)); + if (tx_payload_buffer != NULL && tx_payload_len > 0) + { + if (tx_payload_len > len + 1) + { + tx_payload_len = len + 1; + } + memcpy(tx_data + 1, tx_payload_buffer, tx_payload_len); + } + tx_data[0] = cmd; + + t.tx_buffer = tx_data; + t.rx_buffer = rx_data; + + sx1262_wait_for_busy(); + + ESP_LOGI(TAG_SPIDUMP, "SPI TX (cmd 0x%02X):", cmd); + ESP_LOG_BUFFER_HEXDUMP(TAG_SPIDUMP, tx_data, len + 1, ESP_LOG_INFO); + + gpio_set_level(PIN_NSS, 0); + esp_err_t ret = spi_device_transmit(spiSXko, &t); + gpio_set_level(PIN_NSS, 1); + + if (ret == ESP_OK) + { + SX1262_STATUS = rx_data[1]; + memcpy(rx_buffer, &rx_data[2], len); + ESP_LOGI(TAG_SPIDUMP, "SPI RX (cmd 0x%02X):", cmd); + ESP_LOG_BUFFER_HEXDUMP(TAG_SPIDUMP, rx_data, len + 2, ESP_LOG_INFO); + ESP_LOGV(TAG_SPIDUMP, "SPI read successful, status: 0x%02X", SX1262_STATUS); + } + else + { + ESP_LOGE(TAG, "SPI read failed!"); + } + free(rx_data); + free(tx_data); +} + +void resolve_status_byte(uint8_t status, uint16_t op_error) +{ + const char *chip_modes[] = { + "Unused", "RFU", "STBY_RC", "STBY_XOSC", + "FS", "RX", "TX", "RFU"}; + + const char *command_statuses[] = { + "Reserved", "RFU", "Data is available to host", "Command timeout", + "Command processing error", "Failure to execute command", "Command TX done", "RFU"}; + + uint8_t chip_mode = (status >> 4) & 0x07; // Bits 6:4 + uint8_t command_status = (status >> 1) & 0x07; // Bits 3:1 + + const char *chip_mode_str = chip_modes[chip_mode]; + const char *command_status_str = command_statuses[command_status]; + + const char *op_errors[] = { + "RC64k calibration failed", + "RC13M calibration failed", + "PLL calibration failed", + "ADC calibration failed", + "IMG calibration failed", + "XOSC failed to start", + "PLL failed to lock", + "RFU", + "PA ramping failed"}; + + char errorStr[1024]; + memset(errorStr, 0, sizeof(errorStr)); + + if (command_status == 0x05) + { + strcat(errorStr, "Command error: "); + } + + for (int i = 0; i < 9; i++) + { + if (op_error & (1 << i)) + { + strcat(errorStr, op_errors[i]); + strcat(errorStr, ", "); + ESP_LOGV(TAG, "OpError: %s", op_errors[i]); + } + } + + ESP_LOGI(TAG, "Chip Mode: %s(0x%02X), Command Status: %s(0x%02X) %s", chip_mode_str, chip_mode, command_status_str, command_status, errorStr); +} + +sx1262_status_t sx1262_get_status() +{ + ESP_LOGV(TAG, "Getting SX1262 status..."); + sx1262_status_t status; + uint8_t buffer[1] = {0}; + sx1262_read_command(0xC0, NULL, 0, buffer, 1); + status.status = buffer[0]; + status.error = sx1262_getDeviceErrors(); + sx1262_clearDeviceErrors(); + resolve_status_byte(status.status, status.error); + return status; +} + +void sx1262_setSleep(uint8_t sleepCFG) +{ + sx1262_write_command(0x84, &sleepCFG, 1); +} + +void sx1262_setStandby(uint8_t standbyConf) +{ + sx1262_write_command(0x80, &standbyConf, 1); +} + +void sx1262_setFrequencySynthesis() +{ + sx1262_write_command(0xC1, NULL, 0); +} + +void sx1262_setMode(uint8_t mode, uint32_t timeout) +{ + + uint32_t timeoutUnits = 0; + + if (timeout != 0) + { + uint64_t timeoutInUs = (uint64_t)timeout * 1000; // Convert ms → us + timeoutUnits = (uint32_t)((timeoutInUs * 64) / 1000); // Convert us → SX1262 units + } + + uint8_t buffer[4] = { + (uint8_t)((timeoutUnits >> 24) & 0xFF), + (uint8_t)((timeoutUnits >> 16) & 0xFF), + (uint8_t)((timeoutUnits >> 8) & 0xFF), + (uint8_t)((timeoutUnits) & 0xFF)}; + if (mode) + { + sx1262_write_command(0x83, buffer, 3); + } + else + { + sx1262_write_command(0x82, buffer, 3); + } +} + +void sx1262_stopTimerOnPreamble(uint8_t enable) +{ + sx1262_write_command(0x9F, &enable, 1); +} + +void sx1262_setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) +{ + uint8_t payload[6]; + payload[0] = (rxPeriod >> 16) & 0xFF; + payload[1] = (rxPeriod >> 8) & 0xFF; + payload[2] = rxPeriod & 0xFF; + payload[3] = (sleepPeriod >> 16) & 0xFF; + payload[4] = (sleepPeriod >> 8) & 0xFF; + payload[5] = sleepPeriod & 0xFF; + sx1262_write_command(0x94, payload, 6); +} + +void sx1262_setChannelActivityDetection(void) +{ + sx1262_write_command(0xC5, NULL, 0); +} + +void sx1262_setTxContinuousWave(void) +{ + sx1262_write_command(0xD1, NULL, 0); +} + +void sx1262_setTxInfinitePreamble(void) +{ + sx1262_write_command(0xD2, NULL, 0); +} + +void sx1262_setRegulatorMode(uint8_t mode) +{ + sx1262_write_command(0x96, &mode, 1); +} + +void sx1262_calibrate(uint8_t calibParam) +{ + sx1262_write_command(0x89, &calibParam, 1); +} + +void sx1262_calibrateImage(uint8_t freq1, uint8_t freq2) +{ + uint8_t payload[2] = {freq1, freq2}; + sx1262_write_command(0x98, payload, 2); +} + +void sx1262_setRxTXFallbackMode(uint8_t fallbackMode) +{ + sx1262_write_command(0x93, &fallbackMode, 1); +} + +// Write to register function +void sx1262_writeRegister(uint16_t address, const uint8_t *data, size_t length) +{ + uint8_t payload[length + 2]; + payload[0] = (address >> 8) & 0xFF; + payload[1] = address & 0xFF; + for (size_t i = 0; i < length; i++) + { + payload[i + 2] = data[i]; + } + sx1262_write_command(0x0D, payload, length + 2); +} + +// Read from register function +void sx1262_readRegister(uint16_t address, uint8_t *data, size_t length) +{ + uint8_t payload[2]; + payload[0] = (address >> 8) & 0xFF; + payload[1] = address & 0xFF; + uint8_t rx_payload[2 + length]; + sx1262_read_command(0x1D, payload, 2, rx_payload, 2 + length); + for (size_t i = 0; i < length; i++) + { + data[i] = rx_payload[i + 2]; + } +} + +// Write to buffer function +void sx1262_writeBuffer(uint8_t offset, const uint8_t *data, size_t length) +{ + uint8_t payload[length + 1]; + payload[0] = offset; + for (size_t i = 0; i < length; i++) + { + payload[i + 1] = data[i]; + } + sx1262_write_command(0x0E, payload, length + 1); +} + +// Read from buffer function +void sx1262_readBuffer(uint8_t offset, uint8_t *data, size_t length) +{ + uint8_t tx_payload[1]; + uint8_t payload[1 + length]; + tx_payload[0] = offset; + sx1262_read_command(0x1E, tx_payload, 1, payload, 1 + length); + for (size_t i = 0; i < length; i++) + { + data[i] = payload[i + 1]; + } +} + +void sx1262_setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) +{ + uint8_t payload[8] = { + (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)((irqMask) & 0xFF), + (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), + (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), + (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)}; + sx1262_write_command(0x08, payload, 8); +} + +uint16_t sx1262_getIrqStatus(void) +{ + uint8_t response[2] = {0}; + sx1262_read_command(0x12, NULL, 0, response, 2); + return (response[0] << 8) | response[1]; +} + +void sx1262_clearIrqStatus(uint16_t clearIrqParam) +{ + uint8_t payload[2] = { + (uint8_t)((clearIrqParam >> 8) & 0xFF), + (uint8_t)(clearIrqParam & 0xFF)}; + sx1262_write_command(0x02, payload, 2); +} + +void sx1262_setDIO2AsRfSwitchCtrl(uint8_t enable) +{ + uint8_t buf[1]; + buf[0] = enable; + sx1262_write_command(0x9D, buf, 1); +} + +void sx1262_setDIO3AsTCXOCtrl(uint8_t tcxoVoltage, uint32_t delay) +{ + uint8_t payload[4] = { + tcxoVoltage, + (uint8_t)((delay >> 16) & 0xFF), + (uint8_t)((delay >> 8) & 0xFF), + (uint8_t)(delay & 0xFF)}; + sx1262_write_command(0x97, payload, 4); +} + +void sx1262_setFrequency(uint32_t frequency) +{ + uint32_t freq_reg = frequency * FREQ_STEP; + uint8_t buffer[4] = { + (uint8_t)((freq_reg >> 24) & 0xFF), + (uint8_t)((freq_reg >> 16) & 0xFF), + (uint8_t)((freq_reg >> 8) & 0xFF), + (uint8_t)((freq_reg) & 0xFF)}; + sx1262_write_command(0x86, buffer, 4); +} + +void sx1262_setPacketType(uint8_t packetType) +{ + uint8_t data[1]; + data[0] = packetType; + sx1262_write_command(0x8A, data, 1); +} + +void sx1262_setLoRaModulationParams(const sx1262_LoRaModulationParams_t *params) +{ + uint8_t payload[4] = { + params->spreadingFactor, + params->bandwidth, + params->codingRate, + params->lowDataRateOpt}; + sx1262_write_command(0x8B, payload, sizeof(payload)); +} + +void sx1262_setGFSKModulationParams(const sx1262_GFSKModulationParams_t *params) +{ + uint8_t payload[8] = { + (uint8_t)((params->bitRate >> 16) & 0xFF), + (uint8_t)((params->bitRate >> 8) & 0xFF), + (uint8_t)(params->bitRate & 0xFF), + params->pulseShape, + params->bandwidth, + (uint8_t)((params->frequencyDev >> 16) & 0xFF), + (uint8_t)((params->frequencyDev >> 8) & 0xFF), + (uint8_t)(params->frequencyDev & 0xFF)}; + sx1262_write_command(0x8B, payload, sizeof(payload)); +} + +uint8_t sx1262_getPacketType() +{ + uint8_t response; + sx1262_read_command(0x11, NULL, 0, &response, 1); + return response; +} + +void sx1262_configure_tx_power(uint8_t paDutyCycle, uint8_t hpMax, uint8_t paLut, int8_t power, uint8_t rampTime) +{ + if (paDutyCycle > 0x04) + paDutyCycle = 0x04; + if (rampTime > 0x07) + rampTime = 0x07; + if (hpMax > 0x07) + hpMax = 0x07; + + uint8_t deviceSel; + if (power >= -9) + { + deviceSel = 0x00; // High Power PA + if (power > 22) + power = 22; + if (power < -9) + power = -9; + } + else + { + deviceSel = 0x01; // Low Power PA + if (power > 14) + power = 14; + if (power < -17) + power = -17; + } + + uint8_t paConfig[4] = {paDutyCycle, hpMax, deviceSel, paLut}; + sx1262_write_command(0x95, paConfig, 4); + + // Direct cast keeps correct 2's complement representation + uint8_t txPower[2] = {(uint8_t)power, rampTime}; + sx1262_write_command(0x8E, txPower, 2); +} + +void sx1262_setLoRaPacketParams(sx1262_LoRaPacketParams_t *params) +{ + uint8_t payload[6] = { + (uint8_t)((params->preambleLength >> 8) & 0xFF), + (uint8_t)(params->preambleLength & 0xFF), + params->headerType, + params->payloadLength, + params->crcType, + params->invertIQ}; + sx1262_write_command(0x8C, payload, sizeof(payload)); +} + +void sx1262_setCadParams(uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout) +{ + uint8_t payload[7] = { + cadSymbolNum, + cadDetPeak, + cadDetMin, + cadExitMode, + (uint8_t)((cadTimeout >> 16) & 0xFF), + (uint8_t)((cadTimeout >> 8) & 0xFF), + (uint8_t)(cadTimeout & 0xFF)}; + sx1262_write_command(0x88, payload, sizeof(payload)); +} + +void sx1262_setBufferBaseAddress(uint8_t txBaseAddr, uint8_t rxBaseAddr) +{ + uint8_t payload[2] = {txBaseAddr, rxBaseAddr}; + sx1262_write_command(0x8F, payload, sizeof(payload)); +} + +void sx1262_setLoRaSymbNumTimeout(uint8_t symbNum) +{ + sx1262_write_command(0xA0, &symbNum, 1); +} + +void sx1262_getStatus(uint8_t *status) +{ + sx1262_read_command(0xC0, NULL, 0, status, 0); +} + +void sx1262_getRxBufferStatus(uint8_t *payloadLengthRx, uint8_t *rxStartBufferPointer) +{ + uint8_t response[2]; + sx1262_read_command(0x13, NULL, 0, response, sizeof(response)); + *payloadLengthRx = response[0]; + *rxStartBufferPointer = response[1]; +} + +void sx1262_getPacketStatus(uint8_t *rssi, uint8_t *snr, uint8_t *signalRssi) +{ + uint8_t response[3]; + sx1262_read_command(0x14, NULL, 0, response, sizeof(response)); + *rssi = response[0]; + *snr = response[1]; + *signalRssi = response[2]; +} + +uint8_t sx1262_getRssiInst(uint8_t *rssiInst) +{ + uint8_t response; + sx1262_read_command(0x15, NULL, 0, &response, 1); + return response; +} + +void sx1262_getStats(uint16_t *pktReceived, uint16_t *pktCrcError, uint16_t *pktHeaderErr) +{ + uint8_t response[6]; + sx1262_read_command(0x10, NULL, 0, response, sizeof(response)); + *pktReceived = (response[0] << 8) | response[1]; + *pktCrcError = (response[2] << 8) | response[3]; + *pktHeaderErr = (response[4] << 8) | response[5]; +} + +void sx1262_resetStats(void) +{ + uint8_t payload[6] = {0}; + sx1262_write_command(0x00, payload, sizeof(payload)); +} + +uint16_t sx1262_getDeviceErrors() +{ + uint8_t response[2]; + sx1262_read_command(0x17, NULL, 0, response, sizeof(response)); + return (((uint16_t)response[0]) << 8) | (uint16_t)response[1]; +} + +void sx1262_clearDeviceErrors(void) +{ + uint8_t payload[2] = {0x00, 0x00}; + sx1262_write_command(0x07, payload, sizeof(payload)); +} diff --git a/main/sx1262.h b/main/sx1262.h new file mode 100644 index 0000000..6ae4187 --- /dev/null +++ b/main/sx1262.h @@ -0,0 +1,335 @@ +#ifndef SX1262_H +#define SX1262_H + +#include "driver/spi_master.h" +#include "driver/gpio.h" +#include + +#include + +#include "esp_task.h" + +#define TAG "SX1262" + +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#include "esp_log.h" + +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + +#define LORA_SPI_HOST SPI2_HOST +#define PIN_MOSI GPIO_NUM_10 +#define PIN_MISO GPIO_NUM_11 +#define PIN_SCK GPIO_NUM_9 +#define PIN_NSS GPIO_NUM_8 +#define PIN_RESET GPIO_NUM_12 +#define PIN_BUSY GPIO_NUM_13 +#define PIN_DIO1 GPIO_NUM_14 + +extern spi_device_handle_t spi; + +typedef struct +{ + uint8_t status; + uint16_t error; +} sx1262_status_t; + +typedef struct +{ + uint16_t preambleLength; + uint8_t headerType; + uint8_t payloadLength; + uint8_t crcType; + uint8_t invertIQ; +} sx1262_LoRaPacketParams_t; + +#define SX126X_DIOX_OUTPUT_ENABLE 0x0580 +#define SX126X_DIOX_INPUT_ENABLE 0x0583 +#define SX126X_DIOX_PULL_UP_CONTROL 0x0584 +#define SX126X_DIOX_PULL_DOWN_CONTROL 0x0585 + +#define SX126X_WHITENING_INIT_MSB 0x06B8 +#define SX126X_WHITENING_INIT_LSB 0x06B9 + +#define SX126X_CRC_INIT_MSB 0x06BC +#define SX126X_CRC_INIT_LSB 0x06BD + +#define SX126X_CRC_POLY_MSB 0x06BE +#define SX126X_CRC_POLY_LSB 0x06BF + +#define SX126X_SYNCWORD_0 0x06C0 +#define SX126X_SYNCWORD_1 0x06C1 +#define SX126X_SYNCWORD_2 0x06C2 +#define SX126X_SYNCWORD_3 0x06C3 +#define SX126X_SYNCWORD_4 0x06C4 +#define SX126X_SYNCWORD_5 0x06C5 +#define SX126X_SYNCWORD_6 0x06C6 +#define SX126X_SYNCWORD_7 0x06C7 + +#define SX126X_NODE_ADDRESS 0x06CD +#define SX126X_BROADCAST_ADDRESS 0x06CE + +#define SX126X_IQ_POLARITY_SETUP 0x0736 + +#define SX126X_LORA_SYNCWORD_MSB 0x0740 +#define SX126X_LORA_SYNCWORD_LSB 0x0741 + +#define SX126X_RANDOM_NUMBER_0 0x0819 +#define SX126X_RANDOM_NUMBER_1 0x081A +#define SX126X_RANDOM_NUMBER_2 0x081B +#define SX126X_RANDOM_NUMBER_3 0x081C + +#define SX126X_TX_MODULATION 0x0889 +#define SX126X_RX_GAIN 0x08AC + +#define SX126X_TX_CLAMP_CONFIG 0x08D8 +#define SX126X_OCP_CONFIGURATION 0x08E7 + +#define SX126X_RTC_CONTROL 0x0902 + +#define SX126X_XTA_TRIM 0x0911 +#define SX126X_XTB_TRIM 0x0912 + +#define SX126X_DIO3_OUTPUT_VOLTAGE 0x0920 +#define SX126X_EVENT_MASK 0x0944 + +// Default values where applicable +#define SX126X_RX_GAIN_POWER_SAVING 0x94 +#define SX126X_RX_GAIN_BOOSTED 0x96 + +#define SX126X_LORA_SYNCWORD_PUBLIC 0x3444 +#define SX126X_LORA_SYNCWORD_PRIVATE 0x1424 + +#define SX126X_OCP_LEVEL_SX1262 0x38 // 140mA +#define SX126X_OCP_LEVEL_SX1261 0x18 // 60mA + +typedef struct +{ + uint8_t spreadingFactor; // LoRa SF: 0x05 (SF5) to 0x0C (SF12) + uint8_t bandwidth; // LoRa BW: 0x00 (7.81 kHz) to 0x06 (500 kHz) + uint8_t codingRate; // LoRa CR: 0x01 (4/5) to 0x04 (4/8) + uint8_t lowDataRateOpt; // LDRO: 0x00 (disabled) or 0x01 (enabled) +} sx1262_LoRaModulationParams_t; + +typedef struct +{ + uint32_t bitRate; // GFSK bitrate (BR), calculated as 32 * Fxtal / BR + uint8_t pulseShape; // GFSK filter: 0x00 (none) to 0x0B (Gaussian BT 1) + uint8_t bandwidth; // GFSK RX bandwidth: 0x1F (4.8 kHz) to 0x09 (467 kHz) + uint32_t frequencyDev; // GFSK frequency deviation (Fdev) +} sx1262_GFSKModulationParams_t; + +#include + +#define XTAL_FREQ (double)32000000 +#define FREQ_DIV (double)pow(2.0, 25.0) +#define FREQ_STEP (double)(XTAL_FREQ / FREQ_DIV) + +#define SX1262_SLEEPCFG_ColdStart_RTCDisable 0 +#define SX1262_SLEEPCFG_ColdStart_RTCEnable 1 +#define SX1262_SLEEPCFG_WarmStart_RTCDisable 4 +#define SX1262_SLEEPCFG_WarmStart_RTCEnable 5 + +#define SX1262_STANDBY_RC 0 +#define SX1262_STANDBY_XOSC 1 + +#define SX1262_TIMEOUT_ONCE 0 +#define SX1262_TIMEOUT_RX_CONTINOUS 0xFFFFFF + +#define SX1262_RECEIVE_MODE 0 +#define SX1262_TRANSMIT_MODE 1 + +#define SX1262_STOP_TIMER_ON_PREAMBLE_DISABLE 0x00 +#define SX1262_STOP_TIMER_ON_PREAMBLE_ENABLE 0x01 + +#define SX1262_REGULATOR_LDO_ONLY 0x00 +#define SX1262_REGULATOR_DC_DC_LDO 0x01 + +#define SX1262_FALLBACK_FS 0x40 +#define SX1262_FALLBACK_STANDBY_XOSC 0x30 +#define SX1262_FALLBACK_RC 0x20 + +#define SX1262_IRQ_TXDone (1 << 0) +#define SX1262_IRQ_RXDone (1 << 1) +#define SX1262_IRQ_PreambleDetected (1 << 2) +#define SX1262_IRQ_SyncWordValid (1 << 3) +#define SX1262_IRQ_HeaderValid (1 << 4) +#define SX1262_IRQ_HeaderError (1 << 5) +#define SX1262_IRQ_CRCError (1 << 6) +#define SX1262_IRQ_ChannelActivityDetectionDone (1 << 7) +#define SX1262_IRQ_ChannelActivityDetected (1 << 8) +#define SX1262_IRQ_Timeout (1 << 9) +#define SX1262_IRQ_ALL (SX1262_IRQ_TXDone | SX1262_IRQ_RXDone | SX1262_IRQ_PreambleDetected | SX1262_IRQ_SyncWordValid | SX1262_IRQ_HeaderValid | SX1262_IRQ_HeaderError | SX1262_IRQ_CRCError | SX1262_IRQ_ChannelActivityDetectionDone | SX1262_IRQ_ChannelActivityDetected | SX1262_IRQ_Timeout) + +#define SX1262_TCXO_VOLTAGE16dV 0x00 +#define SX1262_TCXO_VOLTAGE17dV 0x01 +#define SX1262_TCXO_VOLTAGE18dV 0x02 +#define SX1262_TCXO_VOLTAGE22dV 0x03 +#define SX1262_TCXO_VOLTAGE24dV 0x04 +#define SX1262_TCXO_VOLTAGE27dV 0x05 +#define SX1262_TCXO_VOLTAGE30dV 0x06 +#define SX1262_TCXO_VOLTAGE33dV 0x07 + +#define SX1262_PACKET_TYPE_GFSK 0x00 +#define SX1262_PACKET_TYPE_LORA 0x01 + +#define SX1262_Ramp_10U (0x00) +#define SX1262_Ramp_20U (0x01) +#define SX1262_Ramp_40U (0x02) +#define SX1262_Ramp_80U (0x03) +#define SX1262_Ramp_200U (0x04) +#define SX1262_Ramp_800U (0x05) +#define SX1262_Ramp_1700U (0x06) +#define SX1262_Ramp_3400U (0x07) + +#define SX1262_HEADER_TYPE_VARIABLE 0x00 +#define SX1262_HEADER_TYPE_FIXED 0x01 + +#define SX1262_CRC_OFF 0x00 +#define SX1262_CRC_ON 0x01 + +#define SX1262_STANDARD_IQ 0x00 +#define SX1262_INVERTED_IQ 0x01 + +#define SX1262_CAD_ON_1_SYMB 0x00 +#define SX1262_CAD_ON_2_SYMB 0x01 +#define SX1262_CAD_ON_4_SYMB 0x02 +#define SX1262_CAD_ON_8_SYMB 0x03 +#define SX1262_CAD_ON_16_SYMB 0x04 +#define SX1262_CAD_ONLY 0x00 +#define SX1262_CAD_RX 0x01 + +#define SX1262_ERROR_CALIBRATION_RC64K (1 << 0) +#define SX1262_ERROR_CALIBRATION_RC13M (1 << 1) +#define SX1262_ERROR_CALIBRATION_PLL (1 << 2) +#define SX1262_ERROR_CALIBRATION_ADC (1 << 3) +#define SX1262_ERROR_CALIBRATION_IMG (1 << 4) +#define SX1262_ERROR_CALIBRATION_XOSC (1 << 5) +#define SX1262_ERROR_PLL_LOCK (1 << 6) +#define SX1262_ERROR_PA_RAMP (1 << 8) + +#define SX1262_CALIB_RC64K (1 << 0) // RC64k calibration enabled +#define SX1262_CALIB_RC13M (1 << 1) // RC13M calibration enabled +#define SX1262_CALIB_PLL (1 << 2) // PLL calibration enabled +#define SX1262_CALIB_ADC_PULSE (1 << 3) // ADC pulse calibration enabled +#define SX1262_CALIB_ADC_BULK_N (1 << 4) // ADC bulk N calibration enabled +#define SX1262_CALIB_ADC_BULK_P (1 << 5) // ADC bulk P calibration enabled +#define SX1262_CALIB_IMAGE (1 << 6) // Image calibration enabled +#define SX1262_CALIB_RESERVED (1 << 7) // Reserved bit (RFU) + +// Combined mask for all calibration settings +#define SX1262_CALIBRATION_ALL (SX1262_CALIB_RC64K | SX1262_CALIB_RC13M | \ + SX1262_CALIB_PLL | SX1262_CALIB_ADC_PULSE | \ + SX1262_CALIB_ADC_BULK_N | SX1262_CALIB_ADC_BULK_P | \ + SX1262_CALIB_IMAGE) + +// GFSK Pulse Shape +#define SX1262_GFSK_NO_FILTER (0x00) +#define SX1262_GFSK_BT_0_3 (0x08) +#define SX1262_GFSK_BT_0_5 (0x09) +#define SX1262_GFSK_BT_0_7 (0x0A) +#define SX1262_GFSK_BT_1_0 (0x0B) + +// GFSK Bandwidth +#define SX1262_GFSK_RX_BW_4800 (0x1F) +#define SX1262_GFSK_RX_BW_5800 (0x17) +#define SX1262_GFSK_RX_BW_7300 (0x0F) +#define SX1262_GFSK_RX_BW_9700 (0x1E) +#define SX1262_GFSK_RX_BW_11700 (0x16) +#define SX1262_GFSK_RX_BW_14600 (0x0E) +#define SX1262_GFSK_RX_BW_19500 (0x1D) +#define SX1262_GFSK_RX_BW_23400 (0x15) +#define SX1262_GFSK_RX_BW_29300 (0x0D) +#define SX1262_GFSK_RX_BW_39000 (0x1C) +#define SX1262_GFSK_RX_BW_46900 (0x14) +#define SX1262_GFSK_RX_BW_58600 (0x0C) +#define SX1262_GFSK_RX_BW_78200 (0x1B) +#define SX1262_GFSK_RX_BW_93800 (0x13) +#define SX1262_GFSK_RX_BW_117300 (0x0B) +#define SX1262_GFSK_RX_BW_156200 (0x1A) +#define SX1262_GFSK_RX_BW_187200 (0x12) +#define SX1262_GFSK_RX_BW_234300 (0x0A) +#define SX1262_GFSK_RX_BW_312000 (0x19) +#define SX1262_GFSK_RX_BW_373600 (0x11) +#define SX1262_GFSK_RX_BW_467000 (0x09) + +// LoRa Spreading Factor (SF) +#define SX1262_LORA_SF5 (0x05) +#define SX1262_LORA_SF6 (0x06) +#define SX1262_LORA_SF7 (0x07) +#define SX1262_LORA_SF8 (0x08) +#define SX1262_LORA_SF9 (0x09) +#define SX1262_LORA_SF10 (0x0A) +#define SX1262_LORA_SF11 (0x0B) +#define SX1262_LORA_SF12 (0x0C) + +// LoRa Bandwidth (BW) +#define SX1262_LORA_BW_7 (0x00) // 7.81 kHz +#define SX1262_LORA_BW_10 (0x08) // 10.42 kHz +#define SX1262_LORA_BW_15 (0x01) // 15.63 kHz +#define SX1262_LORA_BW_20 (0x09) // 20.83 kHz +#define SX1262_LORA_BW_31 (0x02) // 31.25 kHz +#define SX1262_LORA_BW_41 (0x0A) // 41.67 kHz +#define SX1262_LORA_BW_62 (0x03) // 62.50 kHz +#define SX1262_LORA_BW_125 (0x04) // 125 kHz +#define SX1262_LORA_BW_250 (0x05) // 250 kHz +#define SX1262_LORA_BW_500 (0x06) // 500 kHz + +// LoRa Coding Rate (CR) +#define SX1262_LORA_CR_4_5 (0x01) +#define SX1262_LORA_CR_4_6 (0x02) +#define SX1262_LORA_CR_4_7 (0x03) +#define SX1262_LORA_CR_4_8 (0x04) + +#define SX1262_LORA_SYNC_WORD_MSB (0x0740) +#define SX1262_LORA_SYNC_WORD_LSB (0x0741) + +void sx1262_setPacketType(uint8_t packetType); +void sx1262_init(); +void sx1262_reset(); +void sx1262_wait_for_busy(); +void sx1262_write_command(uint8_t cmd, uint8_t *data, uint8_t len); +void sx1262_read_command(uint8_t cmd, uint8_t *tx_payload_buffer, uint8_t tx_payload_len, uint8_t *rx_buffer, uint8_t len); +sx1262_status_t sx1262_get_status(); +void sx1262_setSleep(uint8_t sleepCFG); +void sx1262_setStandby(uint8_t standbyConf); +void sx1262_setFrequencySynthesis(); +void sx1262_setMode(uint8_t mode, uint32_t timeout); +void sx1262_stopTimerOnPreamble(uint8_t enable); +void sx1262_setRxDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod); +void sx1262_setChannelActivityDetection(void); +void sx1262_setTxContinuousWave(void); +void sx1262_setTxInfinitePreamble(void); +void sx1262_setRegulatorMode(uint8_t mode); +void sx1262_calibrate(uint8_t calibParam); +void sx1262_calibrateImage(uint8_t freq1, uint8_t freq2); +void sx1262_setRxTXFallbackMode(uint8_t fallbackMode); +void sx1262_writeRegister(uint16_t address, const uint8_t *data, size_t length); +void sx1262_readRegister(uint16_t address, uint8_t *data, size_t length); +void sx1262_writeBuffer(uint8_t offset, const uint8_t *data, size_t length); +void sx1262_readBuffer(uint8_t offset, uint8_t *data, size_t length); +void sx1262_setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask); +uint16_t sx1262_getIrqStatus(void); +void sx1262_clearIrqStatus(uint16_t clearIrqParam); +void sx1262_setDIO2AsRfSwitchCtrl(uint8_t enable); +void sx1262_setDIO3AsTCXOCtrl(uint8_t tcxoVoltage, uint32_t delay); +void sx1262_setFrequency(uint32_t frequency); +uint8_t sx1262_getPacketType(); +void sx1262_configure_tx_power(uint8_t paDutyCycle, uint8_t hpMax, uint8_t paLut, int8_t power, uint8_t rampTime); +void sx1262_setLoRaPacketParams(sx1262_LoRaPacketParams_t *params); +void sx1262_setCadParams(uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout); +void sx1262_setBufferBaseAddress(uint8_t txBaseAddr, uint8_t rxBaseAddr); +void sx1262_setLoRaSymbNumTimeout(uint8_t symbNum); +void sx1262_getStatus(uint8_t *status); +void sx1262_getRxBufferStatus(uint8_t *payloadLengthRx, uint8_t *rxStartBufferPointer); +void sx1262_getPacketStatus(uint8_t *rssi, uint8_t *snr, uint8_t *signalRssi); +uint8_t sx1262_getRssiInst(uint8_t *rssiInst); +void sx1262_getStats(uint16_t *pktReceived, uint16_t *pktCrcError, uint16_t *pktHeaderErr); +void sx1262_resetStats(void); +uint16_t sx1262_getDeviceErrors(); +void sx1262_clearDeviceErrors(void); + +void sx1262_setLoRaModulationParams(const sx1262_LoRaModulationParams_t *params); + +void sx1262_setGFSKModulationParams(const sx1262_GFSKModulationParams_t *params); + +#endif