diff --git a/zephcore/CMakeLists.txt b/zephcore/CMakeLists.txt index f04f55e..7be5667 100644 --- a/zephcore/CMakeLists.txt +++ b/zephcore/CMakeLists.txt @@ -4,56 +4,128 @@ cmake_minimum_required(VERSION 3.20.0) # ============================================================================ -# Zephyr Patch Auto-Apply +# Zephyr Patch Auto-Apply (unified diffs via git apply) # ============================================================================ -# Patches stored in zephcore/patches/zephyr/ are copied to Zephyr source tree -# at configure time. This survives `west update` - patches are reapplied on -# next build. +# Patches are applied at configure time using `git apply`. This means: +# - If upstream changed in a conflicting area → build FAILS with clear error +# - If upstream changed in non-conflicting areas → changes are preserved +# - Idempotent: re-running cmake without west update detects already-applied patches # -# Current patches: -# zephyr/: -# - drivers/lora/loramac-node/sx12xx_common.c: bandwidth enum→index mapping -# - drivers/lora/lr11xx/*: LR11xx Zephyr LoRa driver (for future upstream PR) -# - drivers/lora/CMakeLists.txt: adds lr11xx subdirectory -# - drivers/lora/Kconfig: adds lr11xx Kconfig -# - dts/bindings/lora/semtech,lr1110.yaml: LR1110 DTS binding -# - drivers/gnss/gnss_luatos_air530z.c: EASY ephemeris prediction (PMTK869) -# - drivers/gnss/Kconfig.luatos_air530z: CONFIG_GNSS_LUATOS_AIR530Z_EASY -# - drivers/lora/native/sx126x/sx126x.c: fix rx-enable-gpios not toggled -# when dio2-tx-enable is set (breaks E22-900M30S and similar PA modules) -# modules/: -# - lib/loramac-node/src/radio/sx126x/radio.c: restore full 10-element -# Bandwidths[] array + fix LDRO for sub-125kHz bandwidths +# Directory layout: +# patches/zephyr/*.patch - unified diffs applied to the Zephyr tree +# patches/zephyr-new/ - new files copied to the Zephyr tree (no upstream) +# patches/loramac-node/*.patch - unified diffs for modules/lib/loramac-node +# patches/espressif/*.patch - unified diffs for modules/hal/espressif # +# Zephyr patches: +# 0001-lora-lr11xx-build - CMakeLists.txt + Kconfig (lr11xx subdirectory) +# 0002-lora-sx12xx-common - RX error callback, bandwidth mapping, fast TX/RX +# 0003-lora-sx126x-native - PA module RF switch fix (dio2-tx-enable) +# 0004-lora-sx126x-standalone - DIO1 IRQ error logging +# 0005-gnss-air530z-easy - EASY ephemeris prediction (PMTK869) + Kconfig +# 0006-blobs-py - west blobs command fix +# New files (copied, not patched): +# drivers/lora/lr11xx/* - LR11xx Zephyr LoRa driver +# dts/bindings/lora/semtech,lr1110.yaml - LR1110 DTS binding +# Module patches: +# loramac-node: restore 10-element Bandwidths[] + LDRO fix +# espressif: MCUboot config flexibility (mbedtls, validation, sector count) +# + +# --- Helper: apply unified diff patches via git apply --- +function(zephcore_apply_patches PATCH_DIR TARGET_DIR LABEL) + file(GLOB PATCH_FILES "${PATCH_DIR}/*.patch") + list(SORT PATCH_FILES) + foreach(PATCH_FILE ${PATCH_FILES}) + get_filename_component(PATCH_NAME ${PATCH_FILE} NAME) + # Check if already applied (idempotent for re-configure without west update) + execute_process( + COMMAND git apply --reverse --check "${PATCH_FILE}" + WORKING_DIRECTORY "${TARGET_DIR}" + RESULT_VARIABLE ALREADY_APPLIED + OUTPUT_QUIET ERROR_QUIET + ) + if(ALREADY_APPLIED EQUAL 0) + message(STATUS " [${LABEL}] Already applied: ${PATCH_NAME}") + continue() + endif() + # Verify patch applies cleanly + execute_process( + COMMAND git apply --check "${PATCH_FILE}" + WORKING_DIRECTORY "${TARGET_DIR}" + RESULT_VARIABLE PATCH_CHECK + ERROR_VARIABLE PATCH_ERR + ) + if(NOT PATCH_CHECK EQUAL 0) + message(FATAL_ERROR + "ZephCore patch FAILED to apply: ${PATCH_NAME}\n" + "Target tree: ${TARGET_DIR}\n" + "Error:\n${PATCH_ERR}\n" + "Upstream likely changed — rebase the patch:\n" + " cd ${TARGET_DIR}\n" + " git diff -- # inspect current upstream\n" + " # Regenerate: git diff -- > ${PATCH_FILE}\n" + ) + endif() + # Apply the patch + execute_process( + COMMAND git apply "${PATCH_FILE}" + WORKING_DIRECTORY "${TARGET_DIR}" + RESULT_VARIABLE APPLY_RESULT + ERROR_VARIABLE APPLY_ERR + ) + if(NOT APPLY_RESULT EQUAL 0) + message(FATAL_ERROR "git apply failed unexpectedly: ${PATCH_NAME}\n${APPLY_ERR}") + endif() + message(STATUS " [${LABEL}] Applied: ${PATCH_NAME}") + endforeach() +endfunction() + +# Resolve target directories (before find_package(Zephyr) sets ZEPHYR_BASE) +get_filename_component(ZEPHYR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../zephyr ABSOLUTE) +get_filename_component(MODULES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../modules ABSOLUTE) + +# Apply unified diff patches to Zephyr tree if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr) message(STATUS "Applying ZephCore patches to Zephyr...") - file(GLOB_RECURSE ZEPHCORE_PATCH_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr - ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr/*) - foreach(REL_PATH ${ZEPHCORE_PATCH_FILES}) - set(SRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr/${REL_PATH}) - # ZEPHYR_BASE is set by find_package(Zephyr), but we're before that. - # Use the parent directory structure: zephcore/../zephyr - get_filename_component(ZEPHYR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../zephyr ABSOLUTE) + zephcore_apply_patches( + "${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr" + "${ZEPHYR_DIR}" + "zephyr" + ) +endif() + +# Copy new files (no upstream equivalent) to Zephyr tree +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr-new) + file(GLOB_RECURSE ZEPHCORE_NEW_FILES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr-new + ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr-new/*) + foreach(REL_PATH ${ZEPHCORE_NEW_FILES}) + set(SRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr-new/${REL_PATH}) set(DST_FILE ${ZEPHYR_DIR}/${REL_PATH}) - message(STATUS " Patching: ${REL_PATH}") configure_file(${SRC_FILE} ${DST_FILE} COPYONLY) + message(STATUS " [zephyr-new] ${REL_PATH}") endforeach() endif() -# Patch modules (loramac-node, etc.) - same mechanism, different target dir -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/modules) - message(STATUS "Applying ZephCore patches to modules...") - file(GLOB_RECURSE ZEPHCORE_MODULE_PATCH_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/patches/modules - ${CMAKE_CURRENT_SOURCE_DIR}/patches/modules/*) - foreach(REL_PATH ${ZEPHCORE_MODULE_PATCH_FILES}) - set(SRC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/patches/modules/${REL_PATH}) - get_filename_component(MODULES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../modules ABSOLUTE) - set(DST_FILE ${MODULES_DIR}/${REL_PATH}) - message(STATUS " Patching: ${REL_PATH}") - configure_file(${SRC_FILE} ${DST_FILE} COPYONLY) - endforeach() +# Apply unified diff patches to loramac-node module +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/loramac-node) + message(STATUS "Applying ZephCore patches to loramac-node...") + zephcore_apply_patches( + "${CMAKE_CURRENT_SOURCE_DIR}/patches/loramac-node" + "${MODULES_DIR}/lib/loramac-node" + "loramac-node" + ) +endif() + +# Apply unified diff patches to espressif module +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/espressif) + message(STATUS "Applying ZephCore patches to espressif...") + zephcore_apply_patches( + "${CMAKE_CURRENT_SOURCE_DIR}/patches/espressif" + "${MODULES_DIR}/hal/espressif" + "espressif" + ) endif() # Add custom boards directory (for Wio Tracker L1, etc.) diff --git a/zephcore/patches/espressif/0001-mcuboot-config.patch b/zephcore/patches/espressif/0001-mcuboot-config.patch new file mode 100644 index 0000000..f0035e9 --- /dev/null +++ b/zephcore/patches/espressif/0001-mcuboot-config.patch @@ -0,0 +1,51 @@ +diff --git a/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h b/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h +index 472ebbc5ab..9cec9f7e12 100644 +--- a/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h ++++ b/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h +@@ -2,6 +2,10 @@ + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 ++ * ++ * ZephCore patch: Added #ifndef guards for MCUBOOT_MAX_IMG_SECTORS, ++ * fixed mbedTLS detection (also check CONFIG_BOOT_USE_MBEDTLS), and ++ * made MCUBOOT_VALIDATE_PRIMARY_SLOT conditional on Kconfig. + */ + + #ifndef __MCUBOOT_CONFIG_H__ +@@ -76,8 +80,8 @@ + * available. + */ + +-/* Uncomment to use Mbed TLS cryptographic primitives */ +-#if defined(CONFIG_ESP_USE_MBEDTLS) ++/* ZephCore patch: also check CONFIG_BOOT_USE_MBEDTLS (Zephyr Kconfig) */ ++#if defined(CONFIG_ESP_USE_MBEDTLS) || defined(CONFIG_BOOT_USE_MBEDTLS) + #define MCUBOOT_USE_MBED_TLS + #else + /* MCUboot requires the definition of a crypto lib, +@@ -90,7 +94,11 @@ + * even if no upgrade was performed. This is recommended if the boot + * time penalty is acceptable. + */ ++/* ZephCore patch: honor Kconfig CONFIG_BOOT_VALIDATE_SLOT0 instead of ++ * always validating. When unset, skip per-boot validation for faster boot. */ ++#if !defined(CONFIG_BOOT_VALIDATE_SLOT0) || CONFIG_BOOT_VALIDATE_SLOT0 + #define MCUBOOT_VALIDATE_PRIMARY_SLOT ++#endif + + #ifdef CONFIG_ESP_DOWNGRADE_PREVENTION + #define MCUBOOT_DOWNGRADE_PREVENTION 1 +@@ -114,7 +122,12 @@ + + /* Default maximum number of flash sectors per image slot; change + * as desirable. */ ++/* ZephCore patch: allow override via -D or MIN_SECTOR_COUNT from AUTO mode */ ++#if defined(MIN_SECTOR_COUNT) ++#define MCUBOOT_MAX_IMG_SECTORS MIN_SECTOR_COUNT ++#elif !defined(MCUBOOT_MAX_IMG_SECTORS) + #define MCUBOOT_MAX_IMG_SECTORS 512 ++#endif + + /* Default number of separately updateable images; change in case of + * multiple images. */ diff --git a/zephcore/patches/loramac-node/0001-bandwidth-array-ldro.patch b/zephcore/patches/loramac-node/0001-bandwidth-array-ldro.patch new file mode 100644 index 0000000..c9ae812 --- /dev/null +++ b/zephcore/patches/loramac-node/0001-bandwidth-array-ldro.patch @@ -0,0 +1,75 @@ +diff --git a/src/radio/sx126x/radio.c b/src/radio/sx126x/radio.c +index c4a40dab..bf6b4c9b 100644 +--- a/src/radio/sx126x/radio.c ++++ b/src/radio/sx126x/radio.c +@@ -421,7 +421,26 @@ const FskBandwidth_t FskBandwidths[] = + { 500000, 0x00 }, // Invalid Bandwidth + }; + +-const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 }; ++/* ++ * ZephCore patch: restore full 10-element Bandwidths array. ++ * Upstream Zephyr reduced this to {125, 250, 500} but the Zephyr LoRa API ++ * now defines enums for all bandwidths (BW_7_KHZ through BW_500_KHZ). ++ * sx12xx_common.c maps these enums to indices into this array, so all 10 ++ * entries must be present to avoid out-of-bounds access. ++ */ ++const RadioLoRaBandwidths_t Bandwidths[] = ++{ ++ LORA_BW_007, ++ LORA_BW_010, ++ LORA_BW_015, ++ LORA_BW_020, ++ LORA_BW_031, ++ LORA_BW_041, ++ LORA_BW_062, ++ LORA_BW_125, ++ LORA_BW_250, ++ LORA_BW_500, ++}; + + uint8_t MaxPayloadLength = 0xFF; + +@@ -702,8 +721,14 @@ void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, + SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth]; + SX126x.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t )coderate; + +- if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || +- ( ( bandwidth == 1 ) && ( datarate == 12 ) ) ) ++ /* ++ * ZephCore patch: LDRO check updated for 10-element Bandwidths[]. ++ * Enable LDRO when symbol duration > 16ms. ++ * Old indices (0=125k,1=250k) → new (7=125k,8=250k,6=62.5k, etc.) ++ */ ++ if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || ++ ( ( bandwidth == 8 ) && ( datarate == 12 ) ) || ++ ( ( bandwidth <= 6 ) && ( datarate >= 10 ) ) ) + { + SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01; + } +@@ -809,8 +834,10 @@ void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, + SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth]; + SX126x.ModulationParams.Params.LoRa.CodingRate= ( RadioLoRaCodingRates_t )coderate; + +- if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || +- ( ( bandwidth == 1 ) && ( datarate == 12 ) ) ) ++ /* ZephCore patch: LDRO check updated for 10-element Bandwidths[] */ ++ if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || ++ ( ( bandwidth == 8 ) && ( datarate == 12 ) ) || ++ ( ( bandwidth <= 6 ) && ( datarate >= 10 ) ) ) + { + SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01; + } +@@ -946,8 +973,10 @@ static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth, + } + } + +- if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || +- ( ( bandwidth == 1 ) && ( datarate == 12 ) ) ) ++ /* ZephCore patch: LDRO check updated for 10-element Bandwidths[] */ ++ if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || ++ ( ( bandwidth == 8 ) && ( datarate == 12 ) ) || ++ ( ( bandwidth <= 6 ) && ( datarate >= 10 ) ) ) + { + lowDatareOptimize = true; + } diff --git a/zephcore/patches/modules/hal/espressif/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h b/zephcore/patches/modules/hal/espressif/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h deleted file mode 100644 index 9cec9f7..0000000 --- a/zephcore/patches/modules/hal/espressif/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - * - * ZephCore patch: Added #ifndef guards for MCUBOOT_MAX_IMG_SECTORS, - * fixed mbedTLS detection (also check CONFIG_BOOT_USE_MBEDTLS), and - * made MCUBOOT_VALIDATE_PRIMARY_SLOT conditional on Kconfig. - */ - -#ifndef __MCUBOOT_CONFIG_H__ -#define __MCUBOOT_CONFIG_H__ - -#include -#include - -/* - * Signature types - * - * You must choose exactly one signature type - check bootloader.conf - * configuration file - */ - -/* Uncomment for RSA signature support */ -#if defined(CONFIG_ESP_SIGN_RSA) -#define MCUBOOT_SIGN_RSA -# if (CONFIG_ESP_SIGN_RSA_LEN != 2048 && \ - CONFIG_ESP_SIGN_RSA_LEN != 3072) -# error "Invalid RSA key size (must be 2048 or 3072)" -# else -# define MCUBOOT_SIGN_RSA_LEN CONFIG_ESP_SIGN_RSA_LEN -# endif -#elif defined(CONFIG_ESP_SIGN_EC256) -#define MCUBOOT_SIGN_EC256 -#elif defined(CONFIG_ESP_SIGN_ED25519) -#define MCUBOOT_SIGN_ED25519 -#endif - -/* This mcuboot_config.h is used only by Zephyr builds, such as MCUboot - * Zephyr Port for ESP chips or a Zephyr application with MCUboot - * compatibilty (that builds the bootutil lib). - * In these cases, MCUBOOT_BOOT_MAX_ALIGN value must be taken from DT if - * the write-block-size is greater than 8 */ -#if DT_PROP(DT_CHOSEN(zephyr_flash), write_block_size) > 8 -#define MCUBOOT_BOOT_MAX_ALIGN DT_PROP(DT_CHOSEN(zephyr_flash), write_block_size) -#endif - -/* - * Upgrade mode - * - * The default is to support A/B image swapping with rollback. Other modes - * with simpler code path, which only supports overwriting the existing image - * with the update image or running the newest image directly from its flash - * partition, are also available. - * - * You can enable only one mode at a time from the list below to override - * the default upgrade mode. - */ - -/* Uncomment to enable the overwrite-only code path. */ -/* #define MCUBOOT_OVERWRITE_ONLY */ - -#ifdef MCUBOOT_OVERWRITE_ONLY -/* Uncomment to only erase and overwrite those primary slot sectors needed - * to install the new image, rather than the entire image slot. */ -/* #define MCUBOOT_OVERWRITE_ONLY_FAST */ -#endif - -/* Uncomment to enable the direct-xip code path. */ -/* #define MCUBOOT_DIRECT_XIP */ - -/* Uncomment to enable the ram-load code path. */ -/* #define MCUBOOT_RAM_LOAD */ - -/* - * Cryptographic settings - * - * You must choose between Mbed TLS and Tinycrypt as source of - * cryptographic primitives. Other cryptographic settings are also - * available. - */ - -/* ZephCore patch: also check CONFIG_BOOT_USE_MBEDTLS (Zephyr Kconfig) */ -#if defined(CONFIG_ESP_USE_MBEDTLS) || defined(CONFIG_BOOT_USE_MBEDTLS) -#define MCUBOOT_USE_MBED_TLS -#else -/* MCUboot requires the definition of a crypto lib, - * using Tinycrypt as default */ -#define MCUBOOT_USE_TINYCRYPT -#endif - -/* - * Always check the signature of the image in the primary slot before booting, - * even if no upgrade was performed. This is recommended if the boot - * time penalty is acceptable. - */ -/* ZephCore patch: honor Kconfig CONFIG_BOOT_VALIDATE_SLOT0 instead of - * always validating. When unset, skip per-boot validation for faster boot. */ -#if !defined(CONFIG_BOOT_VALIDATE_SLOT0) || CONFIG_BOOT_VALIDATE_SLOT0 -#define MCUBOOT_VALIDATE_PRIMARY_SLOT -#endif - -#ifdef CONFIG_ESP_DOWNGRADE_PREVENTION -#define MCUBOOT_DOWNGRADE_PREVENTION 1 -/* MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER is used later as bool value so it is - * always defined, (unlike MCUBOOT_DOWNGRADE_PREVENTION which is only used in - * preprocessor condition and my be not defined) */ -# ifdef CONFIG_ESP_DOWNGRADE_PREVENTION_SECURITY_COUNTER -# define MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER 1 -# else -# define MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER 0 -# endif -#endif - -/* - * Flash abstraction - */ - -/* Uncomment if your flash map API supports flash_area_get_sectors(). - * See the flash APIs for more details. */ -#define MCUBOOT_USE_FLASH_AREA_GET_SECTORS - -/* Default maximum number of flash sectors per image slot; change - * as desirable. */ -/* ZephCore patch: allow override via -D or MIN_SECTOR_COUNT from AUTO mode */ -#if defined(MIN_SECTOR_COUNT) -#define MCUBOOT_MAX_IMG_SECTORS MIN_SECTOR_COUNT -#elif !defined(MCUBOOT_MAX_IMG_SECTORS) -#define MCUBOOT_MAX_IMG_SECTORS 512 -#endif - -/* Default number of separately updateable images; change in case of - * multiple images. */ -#if defined(CONFIG_ESP_IMAGE_NUMBER) -#define MCUBOOT_IMAGE_NUMBER CONFIG_ESP_IMAGE_NUMBER -#else -#define MCUBOOT_IMAGE_NUMBER 1 -#endif - -/* - * Logging - */ - -/* - * If logging is enabled the following functions must be defined by the - * platform: - * - * MCUBOOT_LOG_MODULE_REGISTER(domain) - * Register a new log module and add the current C file to it. - * - * MCUBOOT_LOG_MODULE_DECLARE(domain) - * Add the current C file to an existing log module. - * - * MCUBOOT_LOG_ERR(...) - * MCUBOOT_LOG_WRN(...) - * MCUBOOT_LOG_INF(...) - * MCUBOOT_LOG_DBG(...) - * - * The function priority is: - * - * MCUBOOT_LOG_ERR > MCUBOOT_LOG_WRN > MCUBOOT_LOG_INF > MCUBOOT_LOG_DBG - */ -#define MCUBOOT_HAVE_LOGGING 1 -/* #define MCUBOOT_LOG_LEVEL MCUBOOT_LOG_LEVEL_INFO */ - -/* - * Assertions - */ - -/* Uncomment if your platform has its own mcuboot_config/mcuboot_assert.h. - * If so, it must provide an ASSERT macro for use by bootutil. Otherwise, - * "assert" is used. */ -#define MCUBOOT_HAVE_ASSERT_H 1 - -#ifdef CONFIG_ESP_MCUBOOT_SERIAL -#define CONFIG_MCUBOOT_SERIAL -#endif - -/* - * When a serial recovery process is receiving the image data, this option - * enables it to erase flash progressively (by sectors) instead of the - * default behavior that is erasing whole image size of flash area after - * receiving first frame. - * Enabling this options prevents stalling the beginning of transfer - * for the time needed to erase large chunk of flash. - */ -#ifdef CONFIG_ESP_MCUBOOT_ERASE_PROGRESSIVELY -#define MCUBOOT_ERASE_PROGRESSIVELY -#endif - -/* Serial extensions are not implemented - */ -#define MCUBOOT_PERUSER_MGMT_GROUP_ENABLED 0 - -#define MCUBOOT_CPU_IDLE() \ - do { \ - } while (0) - -#endif /* __MCUBOOT_CONFIG_H__ */ diff --git a/zephcore/patches/modules/lib/loramac-node/src/radio/sx126x/radio.c b/zephcore/patches/modules/lib/loramac-node/src/radio/sx126x/radio.c deleted file mode 100644 index a15dd07..0000000 --- a/zephcore/patches/modules/lib/loramac-node/src/radio/sx126x/radio.c +++ /dev/null @@ -1,1413 +0,0 @@ -/*! - * \file radio.c - * - * \brief Radio driver API definition - * - * \copyright Revised BSD License, see section \ref LICENSE. - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013-2017 Semtech - * - * \endcode - * - * \author Miguel Luis ( Semtech ) - * - * \author Gregory Cristian ( Semtech ) - */ -#include -#include -#include "utilities.h" -#include "timer.h" -#include "delay.h" -#include "radio.h" -#include "sx126x.h" -#include "sx126x-board.h" -#include "board.h" - -/*! - * \brief Initializes the radio - * - * \param [IN] events Structure containing the driver callback functions - */ -void RadioInit( RadioEvents_t *events ); - -/*! - * Return current radio status - * - * \param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING] - */ -RadioState_t RadioGetStatus( void ); - -/*! - * \brief Configures the radio with the given modem - * - * \param [IN] modem Modem to be used [0: FSK, 1: LoRa] - */ -void RadioSetModem( RadioModems_t modem ); - -/*! - * \brief Sets the channel frequency - * - * \param [IN] freq Channel RF frequency - */ -void RadioSetChannel( uint32_t freq ); - -/*! - * \brief Checks if the channel is free for the given time - * - * \remark The FSK modem is always used for this task as we can select the Rx bandwidth at will. - * - * \param [IN] freq Channel RF frequency in Hertz - * \param [IN] rxBandwidth Rx bandwidth in Hertz - * \param [IN] rssiThresh RSSI threshold in dBm - * \param [IN] maxCarrierSenseTime Max time in milliseconds while the RSSI is measured - * - * \retval isFree [true: Channel is free, false: Channel is not free] - */ -bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime ); - -/*! - * \brief Generates a 32 bits random value based on the RSSI readings - * - * \remark This function sets the radio in LoRa modem mode and disables - * all interrupts. - * After calling this function either Radio.SetRxConfig or - * Radio.SetTxConfig functions must be called. - * - * \retval randomValue 32 bits random value - */ -uint32_t RadioRandom( void ); - -/*! - * \brief Sets the reception parameters - * - * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] - * \param [IN] bandwidth Sets the bandwidth - * FSK : >= 2600 and <= 250000 Hz - * LoRa: [0: 125 kHz, 1: 250 kHz, - * 2: 500 kHz, 3: Reserved] - * \param [IN] datarate Sets the Datarate - * FSK : 600..300000 bits/s - * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, - * 10: 1024, 11: 2048, 12: 4096 chips] - * \param [IN] coderate Sets the coding rate (LoRa only) - * FSK : N/A ( set to 0 ) - * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] - * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only) - * FSK : >= 2600 and <= 250000 Hz - * LoRa: N/A ( set to 0 ) - * \param [IN] preambleLen Sets the Preamble length - * FSK : Number of bytes - * LoRa: Length in symbols (the hardware adds 4 more symbols) - * \param [IN] symbTimeout Sets the RxSingle timeout value - * FSK : timeout in number of bytes - * LoRa: timeout in symbols - * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] - * \param [IN] payloadLen Sets payload length when fixed length is used - * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON] - * \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping - * FSK : N/A ( set to 0 ) - * LoRa: [0: OFF, 1: ON] - * \param [IN] HopPeriod Number of symbols between each hop - * FSK : N/A ( set to 0 ) - * LoRa: Number of symbols - * \param [IN] iqInverted Inverts IQ signals (LoRa only) - * FSK : N/A ( set to 0 ) - * LoRa: [0: not inverted, 1: inverted] - * \param [IN] rxContinuous Sets the reception in continuous mode - * [false: single mode, true: continuous mode] - */ -void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, - uint32_t datarate, uint8_t coderate, - uint32_t bandwidthAfc, uint16_t preambleLen, - uint16_t symbTimeout, bool fixLen, - uint8_t payloadLen, - bool crcOn, bool FreqHopOn, uint8_t HopPeriod, - bool iqInverted, bool rxContinuous ); - -/*! - * \brief Sets the transmission parameters - * - * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] - * \param [IN] power Sets the output power [dBm] - * \param [IN] fdev Sets the frequency deviation (FSK only) - * FSK : [Hz] - * LoRa: 0 - * \param [IN] bandwidth Sets the bandwidth (LoRa only) - * FSK : 0 - * LoRa: [0: 125 kHz, 1: 250 kHz, - * 2: 500 kHz, 3: Reserved] - * \param [IN] datarate Sets the Datarate - * FSK : 600..300000 bits/s - * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, - * 10: 1024, 11: 2048, 12: 4096 chips] - * \param [IN] coderate Sets the coding rate (LoRa only) - * FSK : N/A ( set to 0 ) - * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] - * \param [IN] preambleLen Sets the preamble length - * FSK : Number of bytes - * LoRa: Length in symbols (the hardware adds 4 more symbols) - * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] - * \param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON] - * \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping - * FSK : N/A ( set to 0 ) - * LoRa: [0: OFF, 1: ON] - * \param [IN] HopPeriod Number of symbols between each hop - * FSK : N/A ( set to 0 ) - * LoRa: Number of symbols - * \param [IN] iqInverted Inverts IQ signals (LoRa only) - * FSK : N/A ( set to 0 ) - * LoRa: [0: not inverted, 1: inverted] - * \param [IN] timeout Transmission timeout [ms] - */ -void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, - uint32_t bandwidth, uint32_t datarate, - uint8_t coderate, uint16_t preambleLen, - bool fixLen, bool crcOn, bool FreqHopOn, - uint8_t HopPeriod, bool iqInverted, uint32_t timeout ); - -/*! - * \brief Checks if the given RF frequency is supported by the hardware - * - * \param [IN] frequency RF frequency to be checked - * \retval isSupported [true: supported, false: unsupported] - */ -bool RadioCheckRfFrequency( uint32_t frequency ); - -/*! - * \brief Computes the packet time on air in ms for the given payload - * - * \Remark Can only be called once SetRxConfig or SetTxConfig have been called - * - * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] - * \param [IN] bandwidth Sets the bandwidth - * FSK : >= 2600 and <= 250000 Hz - * LoRa: [0: 125 kHz, 1: 250 kHz, - * 2: 500 kHz, 3: Reserved] - * \param [IN] datarate Sets the Datarate - * FSK : 600..300000 bits/s - * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, - * 10: 1024, 11: 2048, 12: 4096 chips] - * \param [IN] coderate Sets the coding rate (LoRa only) - * FSK : N/A ( set to 0 ) - * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] - * \param [IN] preambleLen Sets the Preamble length - * FSK : Number of bytes - * LoRa: Length in symbols (the hardware adds 4 more symbols) - * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed] - * \param [IN] payloadLen Sets payload length when fixed length is used - * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON] - * - * \retval airTime Computed airTime (ms) for the given packet payload length - */ -uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth, - uint32_t datarate, uint8_t coderate, - uint16_t preambleLen, bool fixLen, uint8_t payloadLen, - bool crcOn ); - -/*! - * \brief Sends the buffer of size. Prepares the packet to be sent and sets - * the radio in transmission - * - * \param [IN]: buffer Buffer pointer - * \param [IN]: size Buffer size - */ -void RadioSend( uint8_t *buffer, uint8_t size ); - -/*! - * \brief Sets the radio in sleep mode - */ -void RadioSleep( void ); - -/*! - * \brief Sets the radio in standby mode - */ -void RadioStandby( void ); - -/*! - * \brief Sets the radio in reception mode for the given time - * \param [IN] timeout Reception timeout [ms] - * [0: continuous, others timeout] - */ -void RadioRx( uint32_t timeout ); - -/*! - * \brief Start a Channel Activity Detection - */ -void RadioStartCad( void ); - -/*! - * \brief Sets the radio in continuous wave transmission mode - * - * \param [IN]: freq Channel RF frequency - * \param [IN]: power Sets the output power [dBm] - * \param [IN]: time Transmission mode timeout [s] - */ -void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ); - -/*! - * \brief Reads the current RSSI value - * - * \retval rssiValue Current RSSI value in [dBm] - */ -int16_t RadioRssi( RadioModems_t modem ); - -/*! - * \brief Writes the radio register at the specified address - * - * \param [IN]: addr Register address - * \param [IN]: data New register value - */ -void RadioWrite( uint32_t addr, uint8_t data ); - -/*! - * \brief Reads the radio register at the specified address - * - * \param [IN]: addr Register address - * \retval data Register value - */ -uint8_t RadioRead( uint32_t addr ); - -/*! - * \brief Writes multiple radio registers starting at address - * - * \param [IN] addr First Radio register address - * \param [IN] buffer Buffer containing the new register's values - * \param [IN] size Number of registers to be written - */ -void RadioWriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size ); - -/*! - * \brief Reads multiple radio registers starting at address - * - * \param [IN] addr First Radio register address - * \param [OUT] buffer Buffer where to copy the registers data - * \param [IN] size Number of registers to be read - */ -void RadioReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size ); - -/*! - * \brief Sets the maximum payload length. - * - * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] - * \param [IN] max Maximum payload length in bytes - */ -void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max ); - -/*! - * \brief Sets the network to public or private. Updates the sync byte. - * - * \remark Applies to LoRa modem only - * - * \param [IN] enable if true, it enables a public network - */ -void RadioSetPublicNetwork( bool enable ); - -/*! - * \brief Gets the time required for the board plus radio to get out of sleep.[ms] - * - * \retval time Radio plus board wakeup time in ms. - */ -uint32_t RadioGetWakeupTime( void ); - -/*! - * \brief Process radio irq - */ -void RadioIrqProcess( void ); - -/*! - * \brief Sets the radio in reception mode with Max LNA gain for the given time - * \param [IN] timeout Reception timeout [ms] - * [0: continuous, others timeout] - */ -void RadioRxBoosted( uint32_t timeout ); - -/*! - * \brief Sets the Rx duty cycle management parameters - * - * \param [in] rxTime Structure describing reception timeout value - * \param [in] sleepTime Structure describing sleep timeout value - */ -void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ); - -/*! - * \brief Add a register to the retention list - * - * \param [in] registerAddress The address of the register to be kept in retention - */ -void RadioAddRegisterToRetentionList( uint16_t registerAddress ); - -/*! - * Radio driver structure initialization - */ -const struct Radio_s Radio = -{ - RadioInit, - RadioGetStatus, - RadioSetModem, - RadioSetChannel, - RadioIsChannelFree, - RadioRandom, - RadioSetRxConfig, - RadioSetTxConfig, - RadioCheckRfFrequency, - RadioTimeOnAir, - RadioSend, - RadioSleep, - RadioStandby, - RadioRx, - RadioStartCad, - RadioSetTxContinuousWave, - RadioRssi, - RadioWrite, - RadioRead, - RadioWriteBuffer, - RadioReadBuffer, - RadioSetMaxPayloadLength, - RadioSetPublicNetwork, - RadioGetWakeupTime, - RadioIrqProcess, - // Available on SX126x only - RadioRxBoosted, - RadioSetRxDutyCycle -}; - -/* - * Local types definition - */ - - - /*! - * FSK bandwidth definition - */ -typedef struct -{ - uint32_t bandwidth; - uint8_t RegValue; -}FskBandwidth_t; - -/*! - * Precomputed FSK bandwidth registers values - */ -const FskBandwidth_t FskBandwidths[] = -{ - { 4800 , 0x1F }, - { 5800 , 0x17 }, - { 7300 , 0x0F }, - { 9700 , 0x1E }, - { 11700 , 0x16 }, - { 14600 , 0x0E }, - { 19500 , 0x1D }, - { 23400 , 0x15 }, - { 29300 , 0x0D }, - { 39000 , 0x1C }, - { 46900 , 0x14 }, - { 58600 , 0x0C }, - { 78200 , 0x1B }, - { 93800 , 0x13 }, - { 117300, 0x0B }, - { 156200, 0x1A }, - { 187200, 0x12 }, - { 234300, 0x0A }, - { 312000, 0x19 }, - { 373600, 0x11 }, - { 467000, 0x09 }, - { 500000, 0x00 }, // Invalid Bandwidth -}; - -/* - * ZephCore patch: restore full 10-element Bandwidths array. - * Upstream Zephyr reduced this to {125, 250, 500} but the Zephyr LoRa API - * now defines enums for all bandwidths (BW_7_KHZ through BW_500_KHZ). - * sx12xx_common.c maps these enums to indices into this array, so all 10 - * entries must be present to avoid out-of-bounds access. - */ -const RadioLoRaBandwidths_t Bandwidths[] = -{ - LORA_BW_007, - LORA_BW_010, - LORA_BW_015, - LORA_BW_020, - LORA_BW_031, - LORA_BW_041, - LORA_BW_062, - LORA_BW_125, - LORA_BW_250, - LORA_BW_500, -}; - -uint8_t MaxPayloadLength = 0xFF; - -uint32_t TxTimeout = 0; -uint32_t RxTimeout = 0; - -bool RxContinuous = false; - - -PacketStatus_t RadioPktStatus; -uint8_t RadioRxPayload[255]; - -bool IrqFired = false; - -/* - * SX126x DIO IRQ callback functions prototype - */ - -/*! - * \brief DIO 0 IRQ callback - */ -void RadioOnDioIrq( void* context ); - -/*! - * \brief Tx timeout timer callback - */ -void RadioOnTxTimeoutIrq( void* context ); - -/*! - * \brief Rx timeout timer callback - */ -void RadioOnRxTimeoutIrq( void* context ); - -/* - * Private global variables - */ - - -/*! - * Holds the current network type for the radio - */ -typedef struct -{ - bool Previous; - bool Current; -}RadioPublicNetwork_t; - -static RadioPublicNetwork_t RadioPublicNetwork = { false }; - -/*! - * Radio callbacks variable - */ -static RadioEvents_t* RadioEvents; - -/* - * Public global variables - */ - -/*! - * Radio hardware and global parameters - */ -SX126x_t SX126x; - -/*! - * Tx and Rx timers - */ -TimerEvent_t TxTimeoutTimer; -TimerEvent_t RxTimeoutTimer; - -/*! - * Returns the known FSK bandwidth registers value - * - * \param [IN] bandwidth Bandwidth value in Hz - * \retval regValue Bandwidth register value. - */ -static uint8_t RadioGetFskBandwidthRegValue( uint32_t bandwidth ) -{ - uint8_t i; - - if( bandwidth == 0 ) - { - return( 0x1F ); - } - - for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( FskBandwidth_t ) ) - 1; i++ ) - { - if( ( bandwidth >= FskBandwidths[i].bandwidth ) && ( bandwidth < FskBandwidths[i + 1].bandwidth ) ) - { - return FskBandwidths[i+1].RegValue; - } - } - // ERROR: Value not found - while( 1 ); -} - -void RadioInit( RadioEvents_t *events ) -{ - RadioEvents = events; - - SX126xInit( RadioOnDioIrq ); - SX126xSetStandby( STDBY_RC ); - SX126xSetRegulatorMode( USE_DCDC ); - - SX126xSetBufferBaseAddress( 0x00, 0x00 ); - SX126xSetTxParams( 0, RADIO_RAMP_200_US ); - SX126xSetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE ); - - // Add registers to the retention list (4 is the maximum possible number) - RadioAddRegisterToRetentionList( REG_RX_GAIN ); - RadioAddRegisterToRetentionList( REG_TX_MODULATION ); - - // Initialize driver timeout timers - TimerInit( &TxTimeoutTimer, RadioOnTxTimeoutIrq ); - TimerInit( &RxTimeoutTimer, RadioOnRxTimeoutIrq ); - - IrqFired = false; -} - -RadioState_t RadioGetStatus( void ) -{ - switch( SX126xGetOperatingMode( ) ) - { - case MODE_TX: - return RF_TX_RUNNING; - case MODE_RX: - return RF_RX_RUNNING; - case MODE_CAD: - return RF_CAD; - default: - return RF_IDLE; - } -} - -void RadioSetModem( RadioModems_t modem ) -{ - switch( modem ) - { - default: - case MODEM_FSK: - SX126xSetPacketType( PACKET_TYPE_GFSK ); - // When switching to GFSK mode the LoRa SyncWord register value is reset - // Thus, we also reset the RadioPublicNetwork variable - RadioPublicNetwork.Current = false; - break; - case MODEM_LORA: - SX126xSetPacketType( PACKET_TYPE_LORA ); - // Public/Private network register is reset when switching modems - if( RadioPublicNetwork.Current != RadioPublicNetwork.Previous ) - { - RadioPublicNetwork.Current = RadioPublicNetwork.Previous; - RadioSetPublicNetwork( RadioPublicNetwork.Current ); - } - break; - } -} - -void RadioSetChannel( uint32_t freq ) -{ - SX126xSetRfFrequency( freq ); -} - -bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime ) -{ - bool status = true; - int16_t rssi = 0; - uint32_t carrierSenseTime = 0; - - RadioSetModem( MODEM_FSK ); - - RadioSetChannel( freq ); - - // Set Rx bandwidth. Other parameters are not used. - RadioSetRxConfig( MODEM_FSK, rxBandwidth, 600, 0, rxBandwidth, 3, 0, false, - 0, false, 0, 0, false, true ); - RadioRx( 0 ); - - DelayMs( 1 ); - - carrierSenseTime = TimerGetCurrentTime( ); - - // Perform carrier sense for maxCarrierSenseTime - while( TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime ) - { - rssi = RadioRssi( MODEM_FSK ); - - if( rssi > rssiThresh ) - { - status = false; - break; - } - } - RadioSleep( ); - return status; -} - -uint32_t RadioRandom( void ) -{ - uint32_t rnd = 0; - - /* - * Radio setup for random number generation - */ - // Set LoRa modem ON - RadioSetModem( MODEM_LORA ); - - // Disable LoRa modem interrupts - SX126xSetDioIrqParams( IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE ); - - rnd = SX126xGetRandom( ); - - return rnd; -} - -void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, - uint32_t datarate, uint8_t coderate, - uint32_t bandwidthAfc, uint16_t preambleLen, - uint16_t symbTimeout, bool fixLen, - uint8_t payloadLen, - bool crcOn, bool freqHopOn, uint8_t hopPeriod, - bool iqInverted, bool rxContinuous ) -{ - - RxContinuous = rxContinuous; - if( rxContinuous == true ) - { - symbTimeout = 0; - } - if( fixLen == true ) - { - MaxPayloadLength = payloadLen; - } - else - { - MaxPayloadLength = 0xFF; - } - - switch( modem ) - { - case MODEM_FSK: - SX126xSetStopRxTimerOnPreambleDetect( false ); - SX126x.ModulationParams.PacketType = PACKET_TYPE_GFSK; - - SX126x.ModulationParams.Params.Gfsk.BitRate = datarate; - SX126x.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1; - SX126x.ModulationParams.Params.Gfsk.Bandwidth = RadioGetFskBandwidthRegValue( bandwidth << 1 ); // SX126x badwidth is double sided - - SX126x.PacketParams.PacketType = PACKET_TYPE_GFSK; - SX126x.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit - SX126x.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS; - SX126x.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3; // convert byte into bit - SX126x.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF; - SX126x.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH; - SX126x.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength; - if( crcOn == true ) - { - SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT; - } - else - { - SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF; - } - SX126x.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING; - - RadioStandby( ); - RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); - SX126xSetModulationParams( &SX126x.ModulationParams ); - SX126xSetPacketParams( &SX126x.PacketParams ); - SX126xSetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } ); - SX126xSetWhiteningSeed( 0x01FF ); - - RxTimeout = ( uint32_t )symbTimeout * 8000UL / datarate; - break; - - case MODEM_LORA: - SX126xSetStopRxTimerOnPreambleDetect( false ); - SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA; - SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t )datarate; - SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth]; - SX126x.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t )coderate; - - /* - * ZephCore patch: LDRO check updated for 10-element Bandwidths[]. - * Enable LDRO when symbol duration > 16ms. - * Old indices (0=125k,1=250k) → new (7=125k,8=250k,6=62.5k, etc.) - */ - if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || - ( ( bandwidth == 8 ) && ( datarate == 12 ) ) || - ( ( bandwidth <= 6 ) && ( datarate >= 10 ) ) ) - { - SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01; - } - else - { - SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00; - } - - SX126x.PacketParams.PacketType = PACKET_TYPE_LORA; - - if( ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) || - ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) ) - { - if( preambleLen < 12 ) - { - SX126x.PacketParams.Params.LoRa.PreambleLength = 12; - } - else - { - SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; - } - } - else - { - SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; - } - - SX126x.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen; - - SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength; - SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn; - SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted; - - RadioStandby( ); - RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); - SX126xSetModulationParams( &SX126x.ModulationParams ); - SX126xSetPacketParams( &SX126x.PacketParams ); - SX126xSetLoRaSymbNumTimeout( symbTimeout ); - - // WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4 - if( SX126x.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED ) - { - SX126xWriteRegister( REG_IQ_POLARITY, SX126xReadRegister( REG_IQ_POLARITY ) & ~( 1 << 2 ) ); - } - else - { - SX126xWriteRegister( REG_IQ_POLARITY, SX126xReadRegister( REG_IQ_POLARITY ) | ( 1 << 2 ) ); - } - // WORKAROUND END - - // Timeout Max, Timeout handled directly in SetRx function - RxTimeout = 0xFFFF; - - break; - } -} - -void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, - uint32_t bandwidth, uint32_t datarate, - uint8_t coderate, uint16_t preambleLen, - bool fixLen, bool crcOn, bool freqHopOn, - uint8_t hopPeriod, bool iqInverted, uint32_t timeout ) -{ - - switch( modem ) - { - case MODEM_FSK: - SX126x.ModulationParams.PacketType = PACKET_TYPE_GFSK; - SX126x.ModulationParams.Params.Gfsk.BitRate = datarate; - - SX126x.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1; - SX126x.ModulationParams.Params.Gfsk.Bandwidth = RadioGetFskBandwidthRegValue( bandwidth << 1 ); // SX126x badwidth is double sided - SX126x.ModulationParams.Params.Gfsk.Fdev = fdev; - - SX126x.PacketParams.PacketType = PACKET_TYPE_GFSK; - SX126x.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit - SX126x.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS; - SX126x.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3 ; // convert byte into bit - SX126x.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF; - SX126x.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH; - - if( crcOn == true ) - { - SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT; - } - else - { - SX126x.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF; - } - SX126x.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING; - - RadioStandby( ); - RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); - SX126xSetModulationParams( &SX126x.ModulationParams ); - SX126xSetPacketParams( &SX126x.PacketParams ); - SX126xSetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } ); - SX126xSetWhiteningSeed( 0x01FF ); - break; - - case MODEM_LORA: - SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA; - SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) datarate; - SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth]; - SX126x.ModulationParams.Params.LoRa.CodingRate= ( RadioLoRaCodingRates_t )coderate; - - /* ZephCore patch: LDRO check updated for 10-element Bandwidths[] */ - if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || - ( ( bandwidth == 8 ) && ( datarate == 12 ) ) || - ( ( bandwidth <= 6 ) && ( datarate >= 10 ) ) ) - { - SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01; - } - else - { - SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00; - } - - SX126x.PacketParams.PacketType = PACKET_TYPE_LORA; - - if( ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) || - ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) ) - { - if( preambleLen < 12 ) - { - SX126x.PacketParams.Params.LoRa.PreambleLength = 12; - } - else - { - SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; - } - } - else - { - SX126x.PacketParams.Params.LoRa.PreambleLength = preambleLen; - } - - SX126x.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen; - SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength; - SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn; - SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted; - - RadioStandby( ); - RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA ); - SX126xSetModulationParams( &SX126x.ModulationParams ); - SX126xSetPacketParams( &SX126x.PacketParams ); - break; - } - - // WORKAROUND - Modulation Quality with 500 kHz LoRa Bandwidth, see DS_SX1261-2_V1.2 datasheet chapter 15.1 - if( ( modem == MODEM_LORA ) && ( SX126x.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 ) ) - { - SX126xWriteRegister( REG_TX_MODULATION, SX126xReadRegister( REG_TX_MODULATION ) & ~( 1 << 2 ) ); - } - else - { - SX126xWriteRegister( REG_TX_MODULATION, SX126xReadRegister( REG_TX_MODULATION ) | ( 1 << 2 ) ); - } - // WORKAROUND END - - SX126xSetRfTxPower( power ); - TxTimeout = timeout; -} - -bool RadioCheckRfFrequency( uint32_t frequency ) -{ - return true; -} - -static uint32_t RadioGetLoRaBandwidthInHz( RadioLoRaBandwidths_t bw ) -{ - uint32_t bandwidthInHz = 0; - - switch( bw ) - { - case LORA_BW_007: - bandwidthInHz = 7812UL; - break; - case LORA_BW_010: - bandwidthInHz = 10417UL; - break; - case LORA_BW_015: - bandwidthInHz = 15625UL; - break; - case LORA_BW_020: - bandwidthInHz = 20833UL; - break; - case LORA_BW_031: - bandwidthInHz = 31250UL; - break; - case LORA_BW_041: - bandwidthInHz = 41667UL; - break; - case LORA_BW_062: - bandwidthInHz = 62500UL; - break; - case LORA_BW_125: - bandwidthInHz = 125000UL; - break; - case LORA_BW_250: - bandwidthInHz = 250000UL; - break; - case LORA_BW_500: - bandwidthInHz = 500000UL; - break; - } - - return bandwidthInHz; -} - -static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate, - uint16_t preambleLen, bool fixLen, uint8_t payloadLen, - bool crcOn ) -{ - const RadioAddressComp_t addrComp = RADIO_ADDRESSCOMP_FILT_OFF; - const uint8_t syncWordLength = 3; - - return ( preambleLen << 3 ) + - ( ( fixLen == false ) ? 8 : 0 ) + - ( syncWordLength << 3 ) + - ( ( payloadLen + - ( addrComp == RADIO_ADDRESSCOMP_FILT_OFF ? 0 : 1 ) + - ( ( crcOn == true ) ? 2 : 0 ) - ) << 3 - ); -} - -static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth, - uint32_t datarate, uint8_t coderate, - uint16_t preambleLen, bool fixLen, uint8_t payloadLen, - bool crcOn ) -{ - int32_t crDenom = coderate + 4; - bool lowDatareOptimize = false; - - // Ensure that the preamble length is at least 12 symbols when using SF5 or - // SF6 - if( ( datarate == 5 ) || ( datarate == 6 ) ) - { - if( preambleLen < 12 ) - { - preambleLen = 12; - } - } - - /* ZephCore patch: LDRO check updated for 10-element Bandwidths[] */ - if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || - ( ( bandwidth == 8 ) && ( datarate == 12 ) ) || - ( ( bandwidth <= 6 ) && ( datarate >= 10 ) ) ) - { - lowDatareOptimize = true; - } - - int32_t ceilDenominator; - int32_t ceilNumerator = ( payloadLen << 3 ) + - ( crcOn ? 16 : 0 ) - - ( 4 * datarate ) + - ( fixLen ? 0 : 20 ); - - if( datarate <= 6 ) - { - ceilDenominator = 4 * datarate; - } - else - { - ceilNumerator += 8; - - if( lowDatareOptimize == true ) - { - ceilDenominator = 4 * ( datarate - 2 ); - } - else - { - ceilDenominator = 4 * datarate; - } - } - - if( ceilNumerator < 0 ) - { - ceilNumerator = 0; - } - - // Perform integral ceil() - int32_t intermediate = - ( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12; - - if( datarate <= 6 ) - { - intermediate += 2; - } - - return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) ); -} - -uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth, - uint32_t datarate, uint8_t coderate, - uint16_t preambleLen, bool fixLen, uint8_t payloadLen, - bool crcOn ) -{ - uint32_t numerator = 0; - uint32_t denominator = 1; - - switch( modem ) - { - case MODEM_FSK: - { - numerator = 1000U * RadioGetGfskTimeOnAirNumerator( datarate, coderate, - preambleLen, fixLen, - payloadLen, crcOn ); - denominator = datarate; - } - break; - case MODEM_LORA: - { - numerator = 1000U * RadioGetLoRaTimeOnAirNumerator( bandwidth, datarate, - coderate, preambleLen, - fixLen, payloadLen, crcOn ); - denominator = RadioGetLoRaBandwidthInHz( Bandwidths[bandwidth] ); - } - break; - } - // Perform integral ceil() - return ( numerator + denominator - 1 ) / denominator; -} - -void RadioSend( uint8_t *buffer, uint8_t size ) -{ - SX126xSetDioIrqParams( IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT, - IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT, - IRQ_RADIO_NONE, - IRQ_RADIO_NONE ); - - if( SX126xGetPacketType( ) == PACKET_TYPE_LORA ) - { - SX126x.PacketParams.Params.LoRa.PayloadLength = size; - } - else - { - SX126x.PacketParams.Params.Gfsk.PayloadLength = size; - } - SX126xSetPacketParams( &SX126x.PacketParams ); - - SX126xSendPayload( buffer, size, 0 ); - TimerSetValue( &TxTimeoutTimer, TxTimeout ); - TimerStart( &TxTimeoutTimer ); -} - -void RadioSleep( void ) -{ - SleepParams_t params = { 0 }; - - params.Fields.WarmStart = 1; - SX126xSetSleep( params ); - - DelayMs( 2 ); -} - -void RadioStandby( void ) -{ - SX126xSetStandby( STDBY_RC ); -} - -void RadioRx( uint32_t timeout ) -{ - SX126xSetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, - IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, - IRQ_RADIO_NONE, - IRQ_RADIO_NONE ); - - if( timeout != 0 ) - { - TimerSetValue( &RxTimeoutTimer, timeout ); - TimerStart( &RxTimeoutTimer ); - } - - if( RxContinuous == true ) - { - SX126xSetRx( 0xFFFFFF ); // Rx Continuous - } - else - { - SX126xSetRx( RxTimeout << 6 ); - } -} - -void RadioRxBoosted( uint32_t timeout ) -{ - SX126xSetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, - IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, - IRQ_RADIO_NONE, - IRQ_RADIO_NONE ); - - if( timeout != 0 ) - { - TimerSetValue( &RxTimeoutTimer, timeout ); - TimerStart( &RxTimeoutTimer ); - } - - if( RxContinuous == true ) - { - SX126xSetRxBoosted( 0xFFFFFF ); // Rx Continuous - } - else - { - SX126xSetRxBoosted( RxTimeout << 6 ); - } -} - -void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ) -{ - SX126xSetRxDutyCycle( rxTime, sleepTime ); -} - -void RadioAddRegisterToRetentionList( uint16_t registerAddress ) -{ - uint8_t buffer[9]; - - // Read the address and registers already added to the list - SX126xReadRegisters( REG_RETENTION_LIST_BASE_ADDRESS, buffer, 9 ); - - const uint8_t nbOfRegisters = buffer[0]; - uint8_t* registerList = &buffer[1]; - - // Check if the register given as parameter is already added to the list - for( uint8_t i = 0; i < nbOfRegisters; i++ ) - { - if( registerAddress == ( ( uint16_t ) registerList[2 * i] << 8 ) + registerList[2 * i + 1] ) - { - return; - } - } - - if( nbOfRegisters < MAX_NB_REG_IN_RETENTION ) - { - buffer[0] += 1; - registerList[2 * nbOfRegisters] = ( uint8_t )( registerAddress >> 8 ); - registerList[2 * nbOfRegisters + 1] = ( uint8_t )( registerAddress >> 0 ); - - // Update radio with modified list - SX126xWriteRegisters( REG_RETENTION_LIST_BASE_ADDRESS, buffer, 9 ); - } -} - -void RadioStartCad( void ) -{ - SX126xSetDioIrqParams( IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, IRQ_RADIO_NONE, IRQ_RADIO_NONE ); - SX126xSetCad( ); -} - -void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ) -{ - uint32_t timeout = ( uint32_t )time * 1000; - - SX126xSetRfFrequency( freq ); - SX126xSetRfTxPower( power ); - SX126xSetTxContinuousWave( ); - - TimerSetValue( &TxTimeoutTimer, timeout ); - TimerStart( &TxTimeoutTimer ); -} - -int16_t RadioRssi( RadioModems_t modem ) -{ - return SX126xGetRssiInst( ); -} - -void RadioWrite( uint32_t addr, uint8_t data ) -{ - SX126xWriteRegister( addr, data ); -} - -uint8_t RadioRead( uint32_t addr ) -{ - return SX126xReadRegister( addr ); -} - -void RadioWriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size ) -{ - SX126xWriteRegisters( addr, buffer, size ); -} - -void RadioReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size ) -{ - SX126xReadRegisters( addr, buffer, size ); -} - -void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max ) -{ - if( modem == MODEM_LORA ) - { - SX126x.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength = max; - SX126xSetPacketParams( &SX126x.PacketParams ); - } - else - { - if( SX126x.PacketParams.Params.Gfsk.HeaderType == RADIO_PACKET_VARIABLE_LENGTH ) - { - SX126x.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength = max; - SX126xSetPacketParams( &SX126x.PacketParams ); - } - } -} - -void RadioSetPublicNetwork( bool enable ) -{ - RadioPublicNetwork.Current = RadioPublicNetwork.Previous = enable; - - RadioSetModem( MODEM_LORA ); - if( enable == true ) - { - // Change LoRa modem SyncWord - SX126xWriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PUBLIC_SYNCWORD >> 8 ) & 0xFF ); - SX126xWriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PUBLIC_SYNCWORD & 0xFF ); - } - else - { - // Change LoRa modem SyncWord - SX126xWriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF ); - SX126xWriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF ); - } -} - -uint32_t RadioGetWakeupTime( void ) -{ - return SX126xGetBoardTcxoWakeupTime( ) + RADIO_WAKEUP_TIME; -} - -void RadioOnTxTimeoutIrq( void* context ) -{ - if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) ) - { - RadioEvents->TxTimeout( ); - } -} - -void RadioOnRxTimeoutIrq( void* context ) -{ - if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) ) - { - RadioEvents->RxTimeout( ); - } -} - -void RadioOnDioIrq( void* context ) -{ - IrqFired = true; -} - -void RadioIrqProcess( void ) -{ - CRITICAL_SECTION_BEGIN( ); - // Clear IRQ flag - const bool isIrqFired = IrqFired; - IrqFired = false; - CRITICAL_SECTION_END( ); - - if( isIrqFired == true ) - { - uint16_t irqRegs = SX126xGetIrqStatus( ); - SX126xClearIrqStatus( irqRegs ); - - // Check if DIO1 pin is High. If it is the case revert IrqFired to true - CRITICAL_SECTION_BEGIN_REPEAT( ); - if( SX126xGetDio1PinState( ) == 1 ) - { - IrqFired = true; - } - CRITICAL_SECTION_END( ); - - if( ( irqRegs & IRQ_TX_DONE ) == IRQ_TX_DONE ) - { - TimerStop( &TxTimeoutTimer ); - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - if( ( RadioEvents != NULL ) && ( RadioEvents->TxDone != NULL ) ) - { - RadioEvents->TxDone( ); - } - } - - if( ( irqRegs & IRQ_RX_DONE ) == IRQ_RX_DONE ) - { - TimerStop( &RxTimeoutTimer ); - - if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR ) - { - if( RxContinuous == false ) - { - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - } - if( ( RadioEvents != NULL ) && ( RadioEvents->RxError ) ) - { - RadioEvents->RxError( ); - } - } - else - { - uint8_t size; - - if( RxContinuous == false ) - { - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - - // WORKAROUND - Implicit Header Mode Timeout Behavior, see DS_SX1261-2_V1.2 datasheet chapter 15.3 - SX126xWriteRegister( REG_RTC_CTRL, 0x00 ); - SX126xWriteRegister( REG_EVT_CLR, SX126xReadRegister( REG_EVT_CLR ) | ( 1 << 1 ) ); - // WORKAROUND END - } - SX126xGetPayload( RadioRxPayload, &size , 255 ); - SX126xGetPacketStatus( &RadioPktStatus ); - if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) ) - { - RadioEvents->RxDone( RadioRxPayload, size, RadioPktStatus.Params.LoRa.RssiPkt, RadioPktStatus.Params.LoRa.SnrPkt ); - } - } - } - - if( ( irqRegs & IRQ_CAD_DONE ) == IRQ_CAD_DONE ) - { - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) ) - { - RadioEvents->CadDone( ( ( irqRegs & IRQ_CAD_ACTIVITY_DETECTED ) == IRQ_CAD_ACTIVITY_DETECTED ) ); - } - } - - if( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT ) - { - if( SX126xGetOperatingMode( ) == MODE_TX ) - { - TimerStop( &TxTimeoutTimer ); - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) ) - { - RadioEvents->TxTimeout( ); - } - } - else if( SX126xGetOperatingMode( ) == MODE_RX ) - { - TimerStop( &RxTimeoutTimer ); - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) ) - { - RadioEvents->RxTimeout( ); - } - } - } - - if( ( irqRegs & IRQ_PREAMBLE_DETECTED ) == IRQ_PREAMBLE_DETECTED ) - { - //__NOP( ); - } - - if( ( irqRegs & IRQ_SYNCWORD_VALID ) == IRQ_SYNCWORD_VALID ) - { - //__NOP( ); - } - - if( ( irqRegs & IRQ_HEADER_VALID ) == IRQ_HEADER_VALID ) - { - //__NOP( ); - } - - if( ( irqRegs & IRQ_HEADER_ERROR ) == IRQ_HEADER_ERROR ) - { - TimerStop( &RxTimeoutTimer ); - if( RxContinuous == false ) - { - //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC - SX126xSetOperatingMode( MODE_STDBY_RC ); - } - if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) ) - { - RadioEvents->RxTimeout( ); - } - } - } -} diff --git a/zephcore/patches/zephyr/drivers/lora/lr11xx/CMakeLists.txt b/zephcore/patches/zephyr-new/drivers/lora/lr11xx/CMakeLists.txt similarity index 100% rename from zephcore/patches/zephyr/drivers/lora/lr11xx/CMakeLists.txt rename to zephcore/patches/zephyr-new/drivers/lora/lr11xx/CMakeLists.txt diff --git a/zephcore/patches/zephyr/drivers/lora/lr11xx/Kconfig b/zephcore/patches/zephyr-new/drivers/lora/lr11xx/Kconfig similarity index 100% rename from zephcore/patches/zephyr/drivers/lora/lr11xx/Kconfig rename to zephcore/patches/zephyr-new/drivers/lora/lr11xx/Kconfig diff --git a/zephcore/patches/zephyr/drivers/lora/lr11xx/lr11xx_lora.c b/zephcore/patches/zephyr-new/drivers/lora/lr11xx/lr11xx_lora.c similarity index 100% rename from zephcore/patches/zephyr/drivers/lora/lr11xx/lr11xx_lora.c rename to zephcore/patches/zephyr-new/drivers/lora/lr11xx/lr11xx_lora.c diff --git a/zephcore/patches/zephyr/drivers/lora/lr11xx/lr11xx_lora.h b/zephcore/patches/zephyr-new/drivers/lora/lr11xx/lr11xx_lora.h similarity index 100% rename from zephcore/patches/zephyr/drivers/lora/lr11xx/lr11xx_lora.h rename to zephcore/patches/zephyr-new/drivers/lora/lr11xx/lr11xx_lora.h diff --git a/zephcore/patches/zephyr/dts/bindings/lora/semtech,lr1110.yaml b/zephcore/patches/zephyr-new/dts/bindings/lora/semtech,lr1110.yaml similarity index 100% rename from zephcore/patches/zephyr/dts/bindings/lora/semtech,lr1110.yaml rename to zephcore/patches/zephyr-new/dts/bindings/lora/semtech,lr1110.yaml diff --git a/zephcore/patches/zephyr/0001-lora-lr11xx-build.patch b/zephcore/patches/zephyr/0001-lora-lr11xx-build.patch new file mode 100644 index 0000000..46936f0 --- /dev/null +++ b/zephcore/patches/zephyr/0001-lora-lr11xx-build.patch @@ -0,0 +1,35 @@ +diff --git a/drivers/lora/CMakeLists.txt b/drivers/lora/CMakeLists.txt +index 9cd035fcf2b..cda2f6dbaf3 100644 +--- a/drivers/lora/CMakeLists.txt ++++ b/drivers/lora/CMakeLists.txt +@@ -1,7 +1,10 @@ + # SPDX-License-Identifier: Apache-2.0 ++# ZephCore patch: adds lr11xx driver subdirectory. + + zephyr_sources_ifdef(CONFIG_LORA_SHELL shell.c) + ++add_subdirectory_ifdef(CONFIG_LORA_LR11XX lr11xx) ++ + # zephyr-keep-sorted-start + add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_LORAMAC_NODE loramac-node) + add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_LORA_BASICS_MODEM lora-basics-modem) +diff --git a/drivers/lora/Kconfig b/drivers/lora/Kconfig +index 657bdb9ce28..0ebee4246f3 100644 +--- a/drivers/lora/Kconfig ++++ b/drivers/lora/Kconfig +@@ -5,6 +5,7 @@ + # + + # Top-level configuration file for LORA drivers. ++# ZephCore patch: adds lr11xx driver Kconfig. + + menuconfig LORA + bool "LoRa drivers" +@@ -60,6 +61,7 @@ config LORA_INIT_PRIORITY + + rsource "Kconfig.sx12xx" + rsource "Kconfig.rylrxxx" ++rsource "lr11xx/Kconfig" + rsource "lora-basics-modem/Kconfig" + rsource "native/Kconfig" + diff --git a/zephcore/patches/zephyr/0002-lora-sx12xx-common.patch b/zephcore/patches/zephyr/0002-lora-sx12xx-common.patch new file mode 100644 index 0000000..0efca66 --- /dev/null +++ b/zephcore/patches/zephyr/0002-lora-sx12xx-common.patch @@ -0,0 +1,173 @@ +diff --git a/drivers/lora/loramac-node/sx12xx_common.c b/drivers/lora/loramac-node/sx12xx_common.c +index 17689720dd2..85186893fc8 100644 +--- a/drivers/lora/loramac-node/sx12xx_common.c ++++ b/drivers/lora/loramac-node/sx12xx_common.c +@@ -3,6 +3,9 @@ + * Copyright (c) 2020 Grinn + * + * SPDX-License-Identifier: Apache-2.0 ++ * ++ * ZEPHCORE PATCH: Modified sx12xx_ev_rx_error() to notify async callback ++ * with NULL data on RX errors (CRC/header). This allows error counting. + */ + + #include +@@ -38,6 +41,12 @@ static struct sx12xx_data { + struct lora_modem_config tx_cfg; + atomic_t modem_usage; + struct sx12xx_rx_params rx_params; ++ /* Fast TX↔RX switching: cache last full config to detect ++ * direction-only changes and skip redundant SPI reconfigure. */ ++ struct lora_modem_config last_cfg; ++ bool last_cfg_valid; ++ bool tx_configured; /* RadioSetTxConfig has been called with current params */ ++ bool rx_configured; /* RadioSetRxConfig has been called with current params */ + } dev_data; + + int __sx12xx_configure_pin(const struct gpio_dt_spec *gpio, gpio_flags_t flags) +@@ -179,6 +188,13 @@ static void sx12xx_ev_rx_error(void) + if (dev_data.async_rx_cb) { + /* Start receiving again */ + Radio.Rx(0); ++ /* ++ * ZEPHCORE PATCH: Notify callback with NULL data to indicate ++ * RX error (CRC mismatch, header error). This allows the ++ * application to count receive errors for diagnostics. ++ */ ++ dev_data.async_rx_cb(dev_data.dev, NULL, 0, 0, 0, ++ dev_data.async_user_data); + /* Don't run the synchronous code */ + return; + } +@@ -195,26 +211,24 @@ static void sx12xx_ev_rx_error(void) + /** + * @brief Convert Zephyr bandwidth enum to loramac-node bandwidth index + * +- * The loramac-node library expects bandwidth as an index (0, 1, 2) into its +- * internal Bandwidths[] array, not the actual kHz value. +- * +- * @param bandwidth Zephyr lora_signal_bandwidth enum value +- * @param bw_idx Pointer to store the resulting bandwidth index +- * @return 0 on success, -EINVAL if bandwidth is not supported ++ * The loramac-node library expects bandwidth as an index into its internal ++ * Bandwidths[] array: {BW_007, BW_010, BW_015, BW_020, BW_031, ++ * BW_041, BW_062, BW_125, BW_250, BW_500} + */ + static int sx12xx_get_bandwidth_idx(enum lora_signal_bandwidth bandwidth, + uint32_t *bw_idx) + { + switch (bandwidth) { +- case BW_125_KHZ: +- *bw_idx = 0; +- break; +- case BW_250_KHZ: +- *bw_idx = 1; +- break; +- case BW_500_KHZ: +- *bw_idx = 2; +- break; ++ case BW_7_KHZ: *bw_idx = 0; break; ++ case BW_10_KHZ: *bw_idx = 1; break; ++ case BW_15_KHZ: *bw_idx = 2; break; ++ case BW_20_KHZ: *bw_idx = 3; break; ++ case BW_31_KHZ: *bw_idx = 4; break; ++ case BW_41_KHZ: *bw_idx = 5; break; ++ case BW_62_KHZ: *bw_idx = 6; break; ++ case BW_125_KHZ: *bw_idx = 7; break; ++ case BW_250_KHZ: *bw_idx = 8; break; ++ case BW_500_KHZ: *bw_idx = 9; break; + default: + return -EINVAL; + } +@@ -225,7 +239,6 @@ uint32_t sx12xx_airtime(const struct device *dev, uint32_t data_len) + { + uint32_t bw_idx; + +- /* Translate bandwidth to loramac-node index, default to 0 if invalid */ + if (sx12xx_get_bandwidth_idx(dev_data.tx_cfg.bandwidth, &bw_idx) < 0) { + bw_idx = 0; + } +@@ -375,6 +388,21 @@ int sx12xx_lora_recv_async(const struct device *dev, lora_recv_cb cb, void *user + return 0; + } + ++/* Check if only the TX/RX direction changed (all radio params identical). */ ++static bool sx12xx_only_direction_changed(const struct lora_modem_config *a, ++ const struct lora_modem_config *b) ++{ ++ return a->frequency == b->frequency && ++ a->bandwidth == b->bandwidth && ++ a->datarate == b->datarate && ++ a->coding_rate == b->coding_rate && ++ a->preamble_len == b->preamble_len && ++ a->tx_power == b->tx_power && ++ a->iq_inverted == b->iq_inverted && ++ a->public_network == b->public_network && ++ a->tx != b->tx; ++} ++ + int sx12xx_lora_config(const struct device *dev, + struct lora_modem_config *config) + { +@@ -388,6 +416,39 @@ int sx12xx_lora_config(const struct device *dev, + return ret; + } + ++ /* Fast path: if only TX↔RX direction changed and the target direction ++ * was already configured once with the same params, skip the full ++ * RadioSetTxConfig/RadioSetRxConfig (saves ~35ms of SPI traffic). ++ * RadioSetTxConfig MUST have been called at least once to set ++ * TxTimeout=4000; RadioSetRxConfig MUST have been called at least ++ * once to set PayloadLength/SymbTimeout/IQ polarity workaround. */ ++ if (dev_data.last_cfg_valid && ++ sx12xx_only_direction_changed(config, &dev_data.last_cfg)) { ++ if (config->tx && dev_data.tx_configured) { ++ LOG_DBG("lora_config: fast TX switch (skip full reconfig)"); ++ if (!modem_acquire(&dev_data)) { ++ return -EBUSY; ++ } ++ memcpy(&dev_data.tx_cfg, config, sizeof(dev_data.tx_cfg)); ++ dev_data.last_cfg = *config; ++ modem_release(&dev_data); ++ return 0; ++ } ++ if (!config->tx && dev_data.rx_configured) { ++ LOG_DBG("lora_config: fast RX switch (skip full reconfig)"); ++ if (!modem_acquire(&dev_data)) { ++ return -EBUSY; ++ } ++ dev_data.last_cfg = *config; ++ modem_release(&dev_data); ++ return 0; ++ } ++ } ++ ++ LOG_INF("lora_config: bw_enum=%d bw_idx=%u tx=%d freq=%u sf=%d", ++ config->bandwidth, bw_idx, config->tx, config->frequency, ++ config->datarate); ++ + /* Ensure available, decremented after configuration */ + if (!modem_acquire(&dev_data)) { + return -EBUSY; +@@ -403,16 +464,21 @@ int sx12xx_lora_config(const struct device *dev, + bw_idx, config->datarate, + config->coding_rate, config->preamble_len, + false, crc, 0, 0, config->iq_inverted, 4000); ++ dev_data.tx_configured = true; + } else { + /* TODO: Get symbol timeout value from config parameters */ + Radio.SetRxConfig(MODEM_LORA, bw_idx, + config->datarate, config->coding_rate, + 0, config->preamble_len, 10, false, 0, + crc, false, 0, config->iq_inverted, true); ++ dev_data.rx_configured = true; + } + + Radio.SetPublicNetwork(config->public_network); + ++ dev_data.last_cfg = *config; ++ dev_data.last_cfg_valid = true; ++ + modem_release(&dev_data); + return 0; + } diff --git a/zephcore/patches/zephyr/0003-lora-sx126x-native.patch b/zephcore/patches/zephyr/0003-lora-sx126x-native.patch new file mode 100644 index 0000000..3e67c92 --- /dev/null +++ b/zephcore/patches/zephyr/0003-lora-sx126x-native.patch @@ -0,0 +1,20 @@ +diff --git a/drivers/lora/native/sx126x/sx126x.c b/drivers/lora/native/sx126x/sx126x.c +index 8e0ca45c271..828faaaf37f 100644 +--- a/drivers/lora/native/sx126x/sx126x.c ++++ b/drivers/lora/native/sx126x/sx126x.c +@@ -451,7 +451,14 @@ static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx) + const struct sx126x_hal_config *config = dev->config; + + sx126x_hal_set_antenna_enable(dev, enable); +- if (!config->dio2_tx_enable) { ++ if (config->dio2_tx_enable) { ++ /* DIO2 handles TX enable in hardware — but rx-enable-gpios ++ * (e.g. E22-900M30S RXEN) still needs explicit GPIO control. ++ * RXEN HIGH when receiving, LOW otherwise. */ ++ if (config->rx_enable.port != NULL) { ++ gpio_pin_set_dt(&config->rx_enable, enable && !tx); ++ } ++ } else { + sx126x_hal_set_rf_switch(dev, enable && tx); + } + } diff --git a/zephcore/patches/zephyr/0004-lora-sx126x-standalone.patch b/zephcore/patches/zephyr/0004-lora-sx126x-standalone.patch new file mode 100644 index 0000000..8f1df59 --- /dev/null +++ b/zephcore/patches/zephyr/0004-lora-sx126x-standalone.patch @@ -0,0 +1,17 @@ +diff --git a/drivers/lora/loramac-node/sx126x_standalone.c b/drivers/lora/loramac-node/sx126x_standalone.c +index c9b16965bc7..3a2ff8b20c9 100644 +--- a/drivers/lora/loramac-node/sx126x_standalone.c ++++ b/drivers/lora/loramac-node/sx126x_standalone.c +@@ -40,8 +40,11 @@ uint32_t sx126x_get_dio1_pin_state(struct sx126x_data *dev_data) + + void sx126x_dio1_irq_enable(struct sx126x_data *dev_data) + { +- gpio_pin_interrupt_configure_dt(&sx126x_gpio_dio1, ++ int ret = gpio_pin_interrupt_configure_dt(&sx126x_gpio_dio1, + GPIO_INT_EDGE_TO_ACTIVE); ++ if (ret != 0) { ++ LOG_ERR("DIO1 irq enable FAILED: %d", ret); ++ } + } + + void sx126x_dio1_irq_disable(struct sx126x_data *dev_data) diff --git a/zephcore/patches/zephyr/0005-gnss-air530z-easy.patch b/zephcore/patches/zephyr/0005-gnss-air530z-easy.patch new file mode 100644 index 0000000..2b911ac --- /dev/null +++ b/zephcore/patches/zephyr/0005-gnss-air530z-easy.patch @@ -0,0 +1,119 @@ +diff --git a/drivers/gnss/Kconfig.luatos_air530z b/drivers/gnss/Kconfig.luatos_air530z +index c5d09261da5..ffc218b22e2 100644 +--- a/drivers/gnss/Kconfig.luatos_air530z ++++ b/drivers/gnss/Kconfig.luatos_air530z +@@ -28,4 +28,16 @@ config GNSS_LUATOS_AIR530Z_SATELLITES_COUNT + the device is actually tracking, just how many of those can + be reported in the satellites callback. + ++config GNSS_LUATOS_AIR530Z_EASY ++ bool "Enable EASY (Embedded Assist System) for faster TTFF" ++ default y ++ help ++ Enable MediaTek EASY (Embedded Assist System) mode via PMTK869 ++ command. EASY caches predicted ephemeris in the GNSS module's ++ internal flash, reducing Time-To-First-Fix from 15-45s (cold) ++ to 1-3s (warm). Sent on every driver init (boot and PM resume). ++ The setting persists in GNSS flash, so resending is a no-op. ++ Compatible with L76K/L76KB and other MediaTek-based GNSS chips ++ that accept PMTK commands alongside PCAS. ++ + endif +diff --git a/drivers/gnss/gnss_luatos_air530z.c b/drivers/gnss/gnss_luatos_air530z.c +index 74708edbd62..7de70ad93c8 100644 +--- a/drivers/gnss/gnss_luatos_air530z.c ++++ b/drivers/gnss/gnss_luatos_air530z.c +@@ -9,7 +9,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -36,6 +35,13 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(init_script_cmds, + /* receive only GGA and RMC NMEA messages */ + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PCAS03,1,0,0,0,1,0,0,0,0,0,0,0,0*1E", 10), + #endif ++#if IS_ENABLED(CONFIG_GNSS_LUATOS_AIR530Z_EASY) ++ /* Enable EASY (Embedded Assist System) — caches predicted ephemeris ++ * in GNSS internal flash for 1-3s warm start instead of 15-45s cold. ++ * PMTK869,1,1 = Set EASY, Enable. Persists across power cycles. ++ * L76K/L76KB accept PMTK alongside PCAS (both MediaTek MT33xx). */ ++ MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PMTK869,1,1*36", 10), ++#endif + ); + + MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(init_script, init_script_cmds, NULL, 5); +@@ -217,54 +223,11 @@ static int gnss_luatos_air530z_init(const struct device *dev) + return 0; + } + +-static int luatos_air530z_pm_resume(const struct device *dev) +-{ +- struct gnss_luatos_air530z_data *data = dev->data; +- int ret; +- +- ret = modem_pipe_open(data->uart_pipe, K_SECONDS(10)); +- if (ret < 0) { +- return ret; +- } +- +- ret = modem_chat_attach(&data->chat, data->uart_pipe); +- if (ret < 0) { +- modem_pipe_close(data->uart_pipe, K_SECONDS(10)); +- return ret; +- } +- +- ret = modem_chat_run_script(&data->chat, &init_script); +- if (ret < 0) { +- modem_pipe_close(data->uart_pipe, K_SECONDS(10)); +- return ret; +- } +- +- return 0; +-} +- +-static int luatos_air530z_pm_action(const struct device *dev, enum pm_device_action action) +-{ +- struct gnss_luatos_air530z_data *data = dev->data; +- const struct gnss_luatos_air530z_config *config = dev->config; +- int ret = -ENOTSUP; +- +- switch (action) { +- case PM_DEVICE_ACTION_SUSPEND: +- gpio_pin_set_dt(&config->on_off_gpio, 0); +- ret = modem_pipe_close(data->uart_pipe, K_SECONDS(10)); +- break; +- +- case PM_DEVICE_ACTION_RESUME: +- gpio_pin_set_dt(&config->on_off_gpio, 1); +- ret = luatos_air530z_pm_resume(dev); +- break; +- +- default: +- break; +- } +- +- return ret; +-} ++/* PM intentionally removed — the L76K ignores $PMTK161,0 (AT6558-based, ++ * not genuine MediaTek). GPS standby uses GPIO FORCE_ON pin instead. ++ * Also, CONFIG_PM_DEVICE_SYSTEM_MANAGED can auto-suspend devices during ++ * idle, calling modem_chat_run_script() from an unexpected context and ++ * potentially deadlocking the system. */ + + static int luatos_air530z_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) + { +@@ -356,10 +319,8 @@ static DEVICE_API(gnss, gnss_api) = { + .dynamic_separators_buf = {',', '*'}, \ + }; \ + \ +- PM_DEVICE_DT_INST_DEFINE(inst, luatos_air530z_pm_action); \ +- \ + DEVICE_DT_INST_DEFINE(inst, gnss_luatos_air530z_init, \ +- PM_DEVICE_DT_INST_GET(inst), \ ++ NULL, \ + &gnss_luatos_air530z_data_##inst, \ + &gnss_luatos_air530z_cfg_##inst, \ + POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); diff --git a/zephcore/patches/zephyr/0006-blobs-py.patch b/zephcore/patches/zephyr/0006-blobs-py.patch new file mode 100644 index 0000000..76aceed --- /dev/null +++ b/zephcore/patches/zephyr/0006-blobs-py.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/west_commands/blobs.py b/scripts/west_commands/blobs.py +index 14f0412cda5..615ba602a6b 100644 +--- a/scripts/west_commands/blobs.py ++++ b/scripts/west_commands/blobs.py +@@ -288,7 +288,7 @@ class Blobs(WestCommand): + continue + self.inf(f"Fetching blob {blob['module']}: {blob['abspath']}") + +- if blob['click-through'] and not args.auto_accept: ++ if blob.get('click-through') and not args.auto_accept: + while True: + user_input = input( + "For this blob, need to read and accept " diff --git a/zephcore/patches/zephyr/drivers/gnss/Kconfig.luatos_air530z b/zephcore/patches/zephyr/drivers/gnss/Kconfig.luatos_air530z deleted file mode 100644 index ffc218b..0000000 --- a/zephcore/patches/zephyr/drivers/gnss/Kconfig.luatos_air530z +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2024 Jerónimo Agulló -# SPDX-License-Identifier: Apache-2.0 - -config GNSS_LUATOS_AIR530Z - bool "Luatos Air530z GNSS device" - default y - depends on GNSS - depends on DT_HAS_LUATOS_AIR530Z_ENABLED - depends on GNSS_REFERENCE_FRAME_WGS84 - select MODEM_MODULES - select MODEM_BACKEND_UART - select MODEM_CHAT - select GNSS_PARSE - select GNSS_NMEA0183 - select GNSS_NMEA0183_MATCH - help - Enable Luatos Air530z GNSS driver. - -if GNSS_LUATOS_AIR530Z - -config GNSS_LUATOS_AIR530Z_SATELLITES_COUNT - int "Maximum satellite count" - depends on GNSS_SATELLITES - default 24 - help - Maximum number of satellites that can be decoded from the - GNSS device. This does not affect the number of devices that - the device is actually tracking, just how many of those can - be reported in the satellites callback. - -config GNSS_LUATOS_AIR530Z_EASY - bool "Enable EASY (Embedded Assist System) for faster TTFF" - default y - help - Enable MediaTek EASY (Embedded Assist System) mode via PMTK869 - command. EASY caches predicted ephemeris in the GNSS module's - internal flash, reducing Time-To-First-Fix from 15-45s (cold) - to 1-3s (warm). Sent on every driver init (boot and PM resume). - The setting persists in GNSS flash, so resending is a no-op. - Compatible with L76K/L76KB and other MediaTek-based GNSS chips - that accept PMTK commands alongside PCAS. - -endif diff --git a/zephcore/patches/zephyr/drivers/gnss/gnss_luatos_air530z.c b/zephcore/patches/zephyr/drivers/gnss/gnss_luatos_air530z.c deleted file mode 100644 index 7de70ad..0000000 --- a/zephcore/patches/zephyr/drivers/gnss/gnss_luatos_air530z.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2024 Jerónimo Agulló - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "gnss_nmea0183.h" -#include "gnss_nmea0183_match.h" -#include "gnss_parse.h" - -#include -LOG_MODULE_REGISTER(luatos_air530z, CONFIG_GNSS_LOG_LEVEL); - -#define DT_DRV_COMPAT luatos_air530z - -#define UART_RECV_BUF_SZ 128 -#define UART_TRANS_BUF_SZ 64 - -#define CHAT_RECV_BUF_SZ 256 -#define CHAT_ARGV_SZ 32 - -MODEM_CHAT_SCRIPT_CMDS_DEFINE(init_script_cmds, -#if CONFIG_GNSS_SATELLITES - /* receive only GGA, RMC and GSV NMEA messages */ - MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PCAS03,1,0,0,1,1,0,0,0,0,0,0,0,0*1F", 10), -#else - /* receive only GGA and RMC NMEA messages */ - MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PCAS03,1,0,0,0,1,0,0,0,0,0,0,0,0*1E", 10), -#endif -#if IS_ENABLED(CONFIG_GNSS_LUATOS_AIR530Z_EASY) - /* Enable EASY (Embedded Assist System) — caches predicted ephemeris - * in GNSS internal flash for 1-3s warm start instead of 15-45s cold. - * PMTK869,1,1 = Set EASY, Enable. Persists across power cycles. - * L76K/L76KB accept PMTK alongside PCAS (both MediaTek MT33xx). */ - MODEM_CHAT_SCRIPT_CMD_RESP_NONE("$PMTK869,1,1*36", 10), -#endif -); - -MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(init_script, init_script_cmds, NULL, 5); - -struct gnss_luatos_air530z_config { - const struct device *uart; - const struct gpio_dt_spec on_off_gpio; - const int uart_baudrate; -}; - -struct gnss_luatos_air530z_data { - struct gnss_nmea0183_match_data match_data; -#if CONFIG_GNSS_SATELLITES - struct gnss_satellite satellites[CONFIG_GNSS_LUATOS_AIR530Z_SATELLITES_COUNT]; -#endif - - /* UART backend */ - struct modem_pipe *uart_pipe; - struct modem_backend_uart uart_backend; - uint8_t uart_backend_receive_buf[UART_RECV_BUF_SZ]; - uint8_t uart_backend_transmit_buf[UART_TRANS_BUF_SZ]; - - /* Modem chat */ - struct modem_chat chat; - uint8_t chat_receive_buf[CHAT_RECV_BUF_SZ]; - uint8_t chat_delimiter[2]; - uint8_t *chat_argv[CHAT_ARGV_SZ]; - - /* Dynamic chat script */ - uint8_t dynamic_separators_buf[2]; - uint8_t dynamic_request_buf[32]; - struct modem_chat_script_chat dynamic_script_chat; - struct modem_chat_script dynamic_script; - - struct k_sem lock; -}; - -MODEM_CHAT_MATCHES_DEFINE(unsol_matches, - MODEM_CHAT_MATCH_WILDCARD("$??GGA,", ",*", gnss_nmea0183_match_gga_callback), - MODEM_CHAT_MATCH_WILDCARD("$??RMC,", ",*", gnss_nmea0183_match_rmc_callback), -#if CONFIG_GNSS_SATELLITES - MODEM_CHAT_MATCH_WILDCARD("$??GSV,", ",*", gnss_nmea0183_match_gsv_callback), -#endif -); - -static void luatos_air530z_lock(const struct device *dev) -{ - struct gnss_luatos_air530z_data *data = dev->data; - - (void)k_sem_take(&data->lock, K_FOREVER); -} - -static void luatos_air530z_unlock(const struct device *dev) -{ - struct gnss_luatos_air530z_data *data = dev->data; - - k_sem_give(&data->lock); -} - -static int gnss_luatos_air530z_init_nmea0183_match(const struct device *dev) -{ - struct gnss_luatos_air530z_data *data = dev->data; - - const struct gnss_nmea0183_match_config match_config = { - .gnss = dev, -#if CONFIG_GNSS_SATELLITES - .satellites = data->satellites, - .satellites_size = ARRAY_SIZE(data->satellites), -#endif - }; - - return gnss_nmea0183_match_init(&data->match_data, &match_config); -} - -static void gnss_luatos_air530z_init_pipe(const struct device *dev) -{ - const struct gnss_luatos_air530z_config *config = dev->config; - struct gnss_luatos_air530z_data *data = dev->data; - - const struct modem_backend_uart_config uart_backend_config = { - .uart = config->uart, - .receive_buf = data->uart_backend_receive_buf, - .receive_buf_size = sizeof(data->uart_backend_receive_buf), - .transmit_buf = data->uart_backend_transmit_buf, - .transmit_buf_size = ARRAY_SIZE(data->uart_backend_transmit_buf), - }; - - data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config); -} - -static int gnss_luatos_air530z_init_chat(const struct device *dev) -{ - struct gnss_luatos_air530z_data *data = dev->data; - - const struct modem_chat_config chat_config = { - .user_data = data, - .receive_buf = data->chat_receive_buf, - .receive_buf_size = sizeof(data->chat_receive_buf), - .delimiter = data->chat_delimiter, - .delimiter_size = ARRAY_SIZE(data->chat_delimiter), - .filter = NULL, - .filter_size = 0, - .argv = data->chat_argv, - .argv_size = ARRAY_SIZE(data->chat_argv), - .unsol_matches = unsol_matches, - .unsol_matches_size = ARRAY_SIZE(unsol_matches), - }; - - return modem_chat_init(&data->chat, &chat_config); -} - -static void luatos_air530z_init_dynamic_script(const struct device *dev) -{ - struct gnss_luatos_air530z_data *data = dev->data; - - /* Air530z doesn't respond to commands. Thus, response_matches_size = 0; */ - data->dynamic_script_chat.request = data->dynamic_request_buf; - data->dynamic_script_chat.response_matches = NULL; - data->dynamic_script_chat.response_matches_size = 0; - data->dynamic_script_chat.timeout = 0; - - data->dynamic_script.name = "PCAS"; - data->dynamic_script.script_chats = &data->dynamic_script_chat; - data->dynamic_script.script_chats_size = 1; - data->dynamic_script.abort_matches = NULL; - data->dynamic_script.abort_matches_size = 0; - data->dynamic_script.callback = NULL; - data->dynamic_script.timeout = 5; -} - -static int gnss_luatos_air530z_init(const struct device *dev) -{ - struct gnss_luatos_air530z_data *data = dev->data; - const struct gnss_luatos_air530z_config *config = dev->config; - int ret; - - k_sem_init(&data->lock, 1, 1); - - ret = gnss_luatos_air530z_init_nmea0183_match(dev); - if (ret < 0) { - return ret; - } - - gnss_luatos_air530z_init_pipe(dev); - - ret = gnss_luatos_air530z_init_chat(dev); - if (ret < 0) { - return ret; - } - - luatos_air530z_init_dynamic_script(dev); - - ret = modem_pipe_open(data->uart_pipe, K_SECONDS(10)); - if (ret < 0) { - return ret; - } - - ret = modem_chat_attach(&data->chat, data->uart_pipe); - if (ret < 0) { - modem_pipe_close(data->uart_pipe, K_SECONDS(10)); - return ret; - } - - ret = modem_chat_run_script(&data->chat, &init_script); - if (ret < 0) { - LOG_ERR("Failed to run init_script"); - modem_pipe_close(data->uart_pipe, K_SECONDS(10)); - return ret; - } - - /* setup on-off gpio for power management */ - if (!gpio_is_ready_dt(&config->on_off_gpio)) { - LOG_ERR("on-off GPIO device not ready"); - return -ENODEV; - } - - gpio_pin_configure_dt(&config->on_off_gpio, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* PM intentionally removed — the L76K ignores $PMTK161,0 (AT6558-based, - * not genuine MediaTek). GPS standby uses GPIO FORCE_ON pin instead. - * Also, CONFIG_PM_DEVICE_SYSTEM_MANAGED can auto-suspend devices during - * idle, calling modem_chat_run_script() from an unexpected context and - * potentially deadlocking the system. */ - -static int luatos_air530z_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) -{ - struct gnss_luatos_air530z_data *data = dev->data; - int ret; - - if (fix_interval_ms < 100 || fix_interval_ms > 1000) { - return -EINVAL; - } - - luatos_air530z_lock(dev); - - ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), - "PCAS02,%u", fix_interval_ms); - if (ret < 0) { - goto unlock_return; - } - - data->dynamic_script_chat.request_size = ret; - - ret = modem_chat_run_script(&data->chat, &data->dynamic_script); - if (ret < 0) { - goto unlock_return; - } - -unlock_return: - luatos_air530z_unlock(dev); - return ret; -} - -static int luatos_air530z_set_enabled_systems(const struct device *dev, gnss_systems_t systems) -{ - struct gnss_luatos_air530z_data *data = dev->data; - gnss_systems_t supported_systems; - uint8_t encoded_systems = 0; - int ret; - - supported_systems = (GNSS_SYSTEM_GPS | GNSS_SYSTEM_GLONASS | GNSS_SYSTEM_BEIDOU); - - if ((~supported_systems) & systems) { - return -EINVAL; - } - - luatos_air530z_lock(dev); - - WRITE_BIT(encoded_systems, 0, systems & GNSS_SYSTEM_GPS); - WRITE_BIT(encoded_systems, 1, systems & GNSS_SYSTEM_GLONASS); - WRITE_BIT(encoded_systems, 2, systems & GNSS_SYSTEM_BEIDOU); - - ret = gnss_nmea0183_snprintk(data->dynamic_request_buf, sizeof(data->dynamic_request_buf), - "PCAS04,%u", encoded_systems); - if (ret < 0) { - goto unlock_return; - } - - data->dynamic_script_chat.request_size = ret; - - ret = modem_chat_run_script(&data->chat, &data->dynamic_script); - if (ret < 0) { - goto unlock_return; - } - -unlock_return: - luatos_air530z_unlock(dev); - return ret; - -} - -static int luatos_air530z_get_supported_systems(const struct device *dev, gnss_systems_t *systems) -{ - *systems = (GNSS_SYSTEM_GPS | GNSS_SYSTEM_GLONASS | GNSS_SYSTEM_BEIDOU); - return 0; -} - -static DEVICE_API(gnss, gnss_api) = { - .set_fix_rate = luatos_air530z_set_fix_rate, - .set_enabled_systems = luatos_air530z_set_enabled_systems, - .get_supported_systems = luatos_air530z_get_supported_systems, -}; - -#define LUATOS_AIR530Z(inst) \ - static const struct gnss_luatos_air530z_config gnss_luatos_air530z_cfg_##inst = { \ - .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ - .on_off_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, on_off_gpios, { 0 }), \ - }; \ - \ - static struct gnss_luatos_air530z_data gnss_luatos_air530z_data_##inst = { \ - .chat_delimiter = {'\r', '\n'}, \ - .dynamic_separators_buf = {',', '*'}, \ - }; \ - \ - DEVICE_DT_INST_DEFINE(inst, gnss_luatos_air530z_init, \ - NULL, \ - &gnss_luatos_air530z_data_##inst, \ - &gnss_luatos_air530z_cfg_##inst, \ - POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); - -DT_INST_FOREACH_STATUS_OKAY(LUATOS_AIR530Z) diff --git a/zephcore/patches/zephyr/drivers/lora/CMakeLists.txt b/zephcore/patches/zephyr/drivers/lora/CMakeLists.txt deleted file mode 100644 index cda2f6d..0000000 --- a/zephcore/patches/zephyr/drivers/lora/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# ZephCore patch: adds lr11xx driver subdirectory. - -zephyr_sources_ifdef(CONFIG_LORA_SHELL shell.c) - -add_subdirectory_ifdef(CONFIG_LORA_LR11XX lr11xx) - -# zephyr-keep-sorted-start -add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_LORAMAC_NODE loramac-node) -add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_LORA_BASICS_MODEM lora-basics-modem) -add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_NATIVE native) -# zephyr-keep-sorted-stop diff --git a/zephcore/patches/zephyr/drivers/lora/Kconfig b/zephcore/patches/zephyr/drivers/lora/Kconfig deleted file mode 100644 index 0ebee42..0000000 --- a/zephcore/patches/zephyr/drivers/lora/Kconfig +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright (c) 2019 Manivannan Sadhasivam -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Top-level configuration file for LORA drivers. -# ZephCore patch: adds lr11xx driver Kconfig. - -menuconfig LORA - bool "LoRa drivers" - select POLL - help - Include LoRa drivers in the system configuration. - -if LORA - -choice LORA_MODULE_BACKEND - prompt "Low-level LoRa modem integration to use" - default LORA_MODULE_BACKEND_LORA_BASICS_MODEM if DT_HAS_SEMTECH_SX1268_ENABLED \ - || DT_HAS_SEMTECH_LLCC68_ENABLED || DT_HAS_SEMTECH_SX1278_ENABLED - -config LORA_MODULE_BACKEND_LORAMAC_NODE - bool "loramac-node backend" - depends on ZEPHYR_LORAMAC_NODE_MODULE - -config LORA_MODULE_BACKEND_LORA_BASICS_MODEM - bool "LoRa Basic modem backend" - depends on ZEPHYR_LORA_BASICS_MODEM_MODULE - depends on DT_HAS_SEMTECH_SX1262_ENABLED || DT_HAS_SEMTECH_SX1261_ENABLED \ - || DT_HAS_SEMTECH_SX1272_ENABLED || DT_HAS_SEMTECH_SX1276_ENABLED \ - || DT_HAS_SEMTECH_SX1268_ENABLED || DT_HAS_SEMTECH_LLCC68_ENABLED \ - || DT_HAS_SEMTECH_SX1278_ENABLED - select USE_LORA_BASICS_MODEM_DRIVERS - help - LoRa API support using the LoRa Basics Modem module. - -config LORA_MODULE_BACKEND_NATIVE - bool "Native Zephyr backend" - help - Use Zephyr's built-in LoRa drivers without external modules. - Currently supports SX1261/SX1262 transceivers. - -endchoice - -module = LORA -module-str = lora -source "subsys/logging/Kconfig.template.log_config" - -config LORA_SHELL - bool "LoRa Shell" - depends on SHELL - help - Enable LoRa Shell for testing. - -config LORA_INIT_PRIORITY - int "LoRa initialization priority" - default 90 - help - System initialization priority for LoRa drivers. - -rsource "Kconfig.sx12xx" -rsource "Kconfig.rylrxxx" -rsource "lr11xx/Kconfig" -rsource "lora-basics-modem/Kconfig" -rsource "native/Kconfig" - -endif # LORA diff --git a/zephcore/patches/zephyr/drivers/lora/loramac-node/sx12xx_common.c b/zephcore/patches/zephyr/drivers/lora/loramac-node/sx12xx_common.c deleted file mode 100644 index 8518689..0000000 --- a/zephcore/patches/zephyr/drivers/lora/loramac-node/sx12xx_common.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2019 Manivannan Sadhasivam - * Copyright (c) 2020 Grinn - * - * SPDX-License-Identifier: Apache-2.0 - * - * ZEPHCORE PATCH: Modified sx12xx_ev_rx_error() to notify async callback - * with NULL data on RX errors (CRC/header). This allows error counting. - */ - -#include -#include -#include -#include -#include - -/* LoRaMac-node specific includes */ -#include - -#include "sx12xx_common.h" - -#define STATE_FREE 0 -#define STATE_BUSY 1 -#define STATE_CLEANUP 2 - -LOG_MODULE_REGISTER(sx12xx_common, CONFIG_LORA_LOG_LEVEL); - -struct sx12xx_rx_params { - uint8_t *buf; - uint8_t *size; - int16_t *rssi; - int8_t *snr; -}; - -static struct sx12xx_data { - const struct device *dev; - struct k_poll_signal *operation_done; - lora_recv_cb async_rx_cb; - void *async_user_data; - RadioEvents_t events; - struct lora_modem_config tx_cfg; - atomic_t modem_usage; - struct sx12xx_rx_params rx_params; - /* Fast TX↔RX switching: cache last full config to detect - * direction-only changes and skip redundant SPI reconfigure. */ - struct lora_modem_config last_cfg; - bool last_cfg_valid; - bool tx_configured; /* RadioSetTxConfig has been called with current params */ - bool rx_configured; /* RadioSetRxConfig has been called with current params */ -} dev_data; - -int __sx12xx_configure_pin(const struct gpio_dt_spec *gpio, gpio_flags_t flags) -{ - int err; - - if (!device_is_ready(gpio->port)) { - LOG_ERR("GPIO device not ready %s", gpio->port->name); - return -ENODEV; - } - - err = gpio_pin_configure_dt(gpio, flags); - if (err) { - LOG_ERR("Cannot configure gpio %s %d: %d", gpio->port->name, - gpio->pin, err); - return err; - } - - return 0; -} - -/** - * @brief Attempt to acquire the modem for operations - * - * @param data common sx12xx data struct - * - * @retval true if modem was acquired - * @retval false otherwise - */ -static inline bool modem_acquire(struct sx12xx_data *data) -{ - return atomic_cas(&data->modem_usage, STATE_FREE, STATE_BUSY); -} - -/** - * @brief Safely release the modem from any context - * - * This function can be called from any context and guarantees that the - * release operations will only be run once. - * - * @param data common sx12xx data struct - * - * @retval true if modem was released by this function - * @retval false otherwise - */ -static bool modem_release(struct sx12xx_data *data) -{ - /* Increment atomic so both acquire and release will fail */ - if (!atomic_cas(&data->modem_usage, STATE_BUSY, STATE_CLEANUP)) { - return false; - } - /* Put radio back into sleep mode */ - Radio.Sleep(); - /* Completely release modem */ - data->operation_done = NULL; - atomic_clear(&data->modem_usage); - return true; -} - -static void sx12xx_ev_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, - int8_t snr) -{ - struct k_poll_signal *sig = dev_data.operation_done; - - /* Receiving in asynchronous mode */ - if (dev_data.async_rx_cb) { - /* Start receiving again */ - Radio.Rx(0); - /* Run the callback */ - dev_data.async_rx_cb(dev_data.dev, payload, size, rssi, snr, - dev_data.async_user_data); - /* Don't run the synchronous code */ - return; - } - - /* Manually release the modem instead of just calling modem_release - * as we need to perform cleanup operations while still ensuring - * others can't use the modem. - */ - if (!atomic_cas(&dev_data.modem_usage, STATE_BUSY, STATE_CLEANUP)) { - return; - } - /* We can make two observations here: - * 1. lora_recv hasn't already exited due to a timeout. - * (modem_release would have been successfully called) - * 2. If the k_poll in lora_recv times out before we raise the signal, - * but while this code is running, it will block on the - * signal again. - * This lets us guarantee that the operation_done signal and pointers - * in rx_params are always valid in this function. - */ - - /* Store actual size */ - if (size < *dev_data.rx_params.size) { - *dev_data.rx_params.size = size; - } - /* Copy received data to output buffer */ - memcpy(dev_data.rx_params.buf, payload, - *dev_data.rx_params.size); - /* Output RSSI and SNR */ - if (dev_data.rx_params.rssi) { - *dev_data.rx_params.rssi = rssi; - } - if (dev_data.rx_params.snr) { - *dev_data.rx_params.snr = snr; - } - /* Put radio back into sleep mode */ - Radio.Sleep(); - /* Completely release modem */ - dev_data.operation_done = NULL; - atomic_clear(&dev_data.modem_usage); - /* Notify caller RX is complete */ - k_poll_signal_raise(sig, 0); -} - -static void sx12xx_ev_tx_done(void) -{ - struct k_poll_signal *sig = dev_data.operation_done; - - if (modem_release(&dev_data)) { - /* Raise signal if provided */ - if (sig) { - k_poll_signal_raise(sig, 0); - } - } -} - -static void sx12xx_ev_tx_timed_out(void) -{ - /* Just release the modem */ - modem_release(&dev_data); -} - -static void sx12xx_ev_rx_error(void) -{ - struct k_poll_signal *sig = dev_data.operation_done; - - /* Receiving in asynchronous mode */ - if (dev_data.async_rx_cb) { - /* Start receiving again */ - Radio.Rx(0); - /* - * ZEPHCORE PATCH: Notify callback with NULL data to indicate - * RX error (CRC mismatch, header error). This allows the - * application to count receive errors for diagnostics. - */ - dev_data.async_rx_cb(dev_data.dev, NULL, 0, 0, 0, - dev_data.async_user_data); - /* Don't run the synchronous code */ - return; - } - - /* Finish synchronous receive with error */ - if (modem_release(&dev_data)) { - /* Raise signal if provided */ - if (sig) { - k_poll_signal_raise(sig, -EIO); - } - } -} - -/** - * @brief Convert Zephyr bandwidth enum to loramac-node bandwidth index - * - * The loramac-node library expects bandwidth as an index into its internal - * Bandwidths[] array: {BW_007, BW_010, BW_015, BW_020, BW_031, - * BW_041, BW_062, BW_125, BW_250, BW_500} - */ -static int sx12xx_get_bandwidth_idx(enum lora_signal_bandwidth bandwidth, - uint32_t *bw_idx) -{ - switch (bandwidth) { - case BW_7_KHZ: *bw_idx = 0; break; - case BW_10_KHZ: *bw_idx = 1; break; - case BW_15_KHZ: *bw_idx = 2; break; - case BW_20_KHZ: *bw_idx = 3; break; - case BW_31_KHZ: *bw_idx = 4; break; - case BW_41_KHZ: *bw_idx = 5; break; - case BW_62_KHZ: *bw_idx = 6; break; - case BW_125_KHZ: *bw_idx = 7; break; - case BW_250_KHZ: *bw_idx = 8; break; - case BW_500_KHZ: *bw_idx = 9; break; - default: - return -EINVAL; - } - return 0; -} - -uint32_t sx12xx_airtime(const struct device *dev, uint32_t data_len) -{ - uint32_t bw_idx; - - if (sx12xx_get_bandwidth_idx(dev_data.tx_cfg.bandwidth, &bw_idx) < 0) { - bw_idx = 0; - } - - return Radio.TimeOnAir(MODEM_LORA, - bw_idx, - dev_data.tx_cfg.datarate, - dev_data.tx_cfg.coding_rate, - dev_data.tx_cfg.preamble_len, - 0, data_len, !dev_data.tx_cfg.packet_crc_disable); -} - -int sx12xx_lora_send(const struct device *dev, uint8_t *data, - uint32_t data_len) -{ - struct k_poll_signal done = K_POLL_SIGNAL_INITIALIZER(done); - struct k_poll_event evt = K_POLL_EVENT_INITIALIZER( - K_POLL_TYPE_SIGNAL, - K_POLL_MODE_NOTIFY_ONLY, - &done); - uint32_t air_time; - int ret; - - /* Validate that we have a TX configuration */ - if (!dev_data.tx_cfg.frequency) { - return -EINVAL; - } - - ret = sx12xx_lora_send_async(dev, data, data_len, &done); - if (ret < 0) { - return ret; - } - - /* Calculate expected airtime of the packet */ - air_time = sx12xx_airtime(dev, data_len); - LOG_DBG("Expected air time of %u bytes = %u ms", data_len, air_time); - - /* Wait for the packet to finish transmitting. - * Use twice the tx duration to ensure that we are actually detecting - * a failed transmission, and not some minor timing variation between - * modem and driver. - */ - ret = k_poll(&evt, 1, K_MSEC(2 * air_time)); - if (ret < 0) { - LOG_ERR("Packet transmission failed!"); - if (!modem_release(&dev_data)) { - /* TX done interrupt is currently running */ - k_poll(&evt, 1, K_FOREVER); - } - } - return ret; -} - -int sx12xx_lora_send_async(const struct device *dev, uint8_t *data, - uint32_t data_len, struct k_poll_signal *async) -{ - /* Ensure available, freed by sx12xx_ev_tx_done */ - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - - /* Store signal */ - dev_data.operation_done = async; - - Radio.SetMaxPayloadLength(MODEM_LORA, data_len); - - Radio.Send(data, data_len); - - return 0; -} - -int sx12xx_lora_recv(const struct device *dev, uint8_t *data, uint8_t size, - k_timeout_t timeout, int16_t *rssi, int8_t *snr) -{ - struct k_poll_signal done = K_POLL_SIGNAL_INITIALIZER(done); - struct k_poll_event evt = K_POLL_EVENT_INITIALIZER( - K_POLL_TYPE_SIGNAL, - K_POLL_MODE_NOTIFY_ONLY, - &done); - int ret; - - /* Ensure available, decremented by sx12xx_ev_rx_done or on timeout */ - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - - dev_data.async_rx_cb = NULL; - /* Store operation signal */ - dev_data.operation_done = &done; - /* Set data output location */ - dev_data.rx_params.buf = data; - dev_data.rx_params.size = &size; - dev_data.rx_params.rssi = rssi; - dev_data.rx_params.snr = snr; - - Radio.SetMaxPayloadLength(MODEM_LORA, 255); - Radio.Rx(0); - - ret = k_poll(&evt, 1, timeout); - if (ret < 0) { - if (!modem_release(&dev_data)) { - /* Releasing the modem failed, which means that - * the RX callback is currently running. Wait until - * the RX callback finishes and we get our packet. - */ - k_poll(&evt, 1, K_FOREVER); - - /* We did receive a packet */ - return size; - } - LOG_INF("Receive timeout"); - return ret; - } - - if (done.result < 0) { - LOG_ERR("Receive error"); - return done.result; - } - - return size; -} - -int sx12xx_lora_recv_async(const struct device *dev, lora_recv_cb cb, void *user_data) -{ - /* Cancel ongoing reception */ - if (cb == NULL) { - if (!modem_release(&dev_data)) { - /* Not receiving or already being stopped */ - return -EINVAL; - } - return 0; - } - - /* Ensure available */ - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - - /* Store parameters */ - dev_data.async_rx_cb = cb; - dev_data.async_user_data = user_data; - - /* Start reception */ - Radio.SetMaxPayloadLength(MODEM_LORA, 255); - Radio.Rx(0); - - return 0; -} - -/* Check if only the TX/RX direction changed (all radio params identical). */ -static bool sx12xx_only_direction_changed(const struct lora_modem_config *a, - const struct lora_modem_config *b) -{ - return a->frequency == b->frequency && - a->bandwidth == b->bandwidth && - a->datarate == b->datarate && - a->coding_rate == b->coding_rate && - a->preamble_len == b->preamble_len && - a->tx_power == b->tx_power && - a->iq_inverted == b->iq_inverted && - a->public_network == b->public_network && - a->tx != b->tx; -} - -int sx12xx_lora_config(const struct device *dev, - struct lora_modem_config *config) -{ - bool crc = !config->packet_crc_disable; - uint32_t bw_idx; - int ret; - - ret = sx12xx_get_bandwidth_idx(config->bandwidth, &bw_idx); - if (ret < 0) { - LOG_ERR("Unsupported bandwidth: %d", config->bandwidth); - return ret; - } - - /* Fast path: if only TX↔RX direction changed and the target direction - * was already configured once with the same params, skip the full - * RadioSetTxConfig/RadioSetRxConfig (saves ~35ms of SPI traffic). - * RadioSetTxConfig MUST have been called at least once to set - * TxTimeout=4000; RadioSetRxConfig MUST have been called at least - * once to set PayloadLength/SymbTimeout/IQ polarity workaround. */ - if (dev_data.last_cfg_valid && - sx12xx_only_direction_changed(config, &dev_data.last_cfg)) { - if (config->tx && dev_data.tx_configured) { - LOG_DBG("lora_config: fast TX switch (skip full reconfig)"); - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - memcpy(&dev_data.tx_cfg, config, sizeof(dev_data.tx_cfg)); - dev_data.last_cfg = *config; - modem_release(&dev_data); - return 0; - } - if (!config->tx && dev_data.rx_configured) { - LOG_DBG("lora_config: fast RX switch (skip full reconfig)"); - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - dev_data.last_cfg = *config; - modem_release(&dev_data); - return 0; - } - } - - LOG_INF("lora_config: bw_enum=%d bw_idx=%u tx=%d freq=%u sf=%d", - config->bandwidth, bw_idx, config->tx, config->frequency, - config->datarate); - - /* Ensure available, decremented after configuration */ - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - - Radio.SetChannel(config->frequency); - - if (config->tx) { - /* Store TX config locally for airtime calculations */ - memcpy(&dev_data.tx_cfg, config, sizeof(dev_data.tx_cfg)); - /* Configure radio driver */ - Radio.SetTxConfig(MODEM_LORA, config->tx_power, 0, - bw_idx, config->datarate, - config->coding_rate, config->preamble_len, - false, crc, 0, 0, config->iq_inverted, 4000); - dev_data.tx_configured = true; - } else { - /* TODO: Get symbol timeout value from config parameters */ - Radio.SetRxConfig(MODEM_LORA, bw_idx, - config->datarate, config->coding_rate, - 0, config->preamble_len, 10, false, 0, - crc, false, 0, config->iq_inverted, true); - dev_data.rx_configured = true; - } - - Radio.SetPublicNetwork(config->public_network); - - dev_data.last_cfg = *config; - dev_data.last_cfg_valid = true; - - modem_release(&dev_data); - return 0; -} - -int sx12xx_lora_test_cw(const struct device *dev, uint32_t frequency, - int8_t tx_power, - uint16_t duration) -{ - /* Ensure available, freed in sx12xx_ev_tx_done */ - if (!modem_acquire(&dev_data)) { - return -EBUSY; - } - - Radio.SetTxContinuousWave(frequency, tx_power, duration); - return 0; -} - -int sx12xx_init(const struct device *dev) -{ - atomic_set(&dev_data.modem_usage, 0); - - dev_data.dev = dev; - dev_data.events.TxDone = sx12xx_ev_tx_done; - dev_data.events.RxDone = sx12xx_ev_rx_done; - dev_data.events.RxError = sx12xx_ev_rx_error; - /* TX timeout event raises at the end of the test CW transmission */ - dev_data.events.TxTimeout = sx12xx_ev_tx_timed_out; - Radio.Init(&dev_data.events); - - /* - * Automatically place the radio into sleep mode upon boot. - * The required `lora_config` call before transmission or reception - * will bring the radio out of sleep mode before it is used. The radio - * is automatically placed back into sleep mode upon TX or RX - * completion. - */ - Radio.Sleep(); - - return 0; -} diff --git a/zephcore/patches/zephyr/drivers/lora/native/sx126x/sx126x.c b/zephcore/patches/zephyr/drivers/lora/native/sx126x/sx126x.c deleted file mode 100644 index 828faaa..0000000 --- a/zephcore/patches/zephyr/drivers/lora/native/sx126x/sx126x.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* - * Copyright (c) 2026 Carlo Caione - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -#include "sx126x.h" - -#include -LOG_MODULE_REGISTER(sx126x, CONFIG_LORA_LOG_LEVEL); - -static uint8_t bandwidth_to_reg(enum lora_signal_bandwidth bw) -{ - switch (bw) { - case BW_7_KHZ: - return SX126X_LORA_BW_7_8; - case BW_10_KHZ: - return SX126X_LORA_BW_10_4; - case BW_15_KHZ: - return SX126X_LORA_BW_15_6; - case BW_20_KHZ: - return SX126X_LORA_BW_20_8; - case BW_31_KHZ: - return SX126X_LORA_BW_31_25; - case BW_41_KHZ: - return SX126X_LORA_BW_41_7; - case BW_62_KHZ: - return SX126X_LORA_BW_62_5; - case BW_125_KHZ: - return SX126X_LORA_BW_125; - case BW_250_KHZ: - return SX126X_LORA_BW_250; - case BW_500_KHZ: - return SX126X_LORA_BW_500; - default: - return SX126X_LORA_BW_125; - } -} - -static uint32_t bandwidth_to_hz(enum lora_signal_bandwidth bw) -{ - switch (bw) { - case BW_7_KHZ: - return 7810; - case BW_10_KHZ: - return 10420; - case BW_15_KHZ: - return 15630; - case BW_20_KHZ: - return 20830; - case BW_31_KHZ: - return 31250; - case BW_41_KHZ: - return 41670; - case BW_62_KHZ: - return 62500; - case BW_125_KHZ: - return 125000; - case BW_250_KHZ: - return 250000; - case BW_500_KHZ: - return 500000; - default: - return 125000; - } -} - -static bool should_enable_ldro(enum lora_datarate sf, enum lora_signal_bandwidth bw, - const struct sx126x_hal_config *config) -{ - if (config->force_ldro) { - return true; - } - - uint32_t bw_hz = bandwidth_to_hz(bw); - /* Symbol time = 2^SF / BW (in seconds) */ - /* 16.38 ms = 16380 us */ - /* 2^SF / BW > 0.01638 => 2^SF * 1000000 / BW > 16380 */ - uint32_t symbol_time_us = ((1 << sf) * 1000000UL) / bw_hz; - - return symbol_time_us > 16380; -} - -static int sx126x_set_standby(const struct device *dev, uint8_t mode) -{ - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_STANDBY, &mode, 1); -} - -static int sx126x_set_regulator_mode(const struct device *dev, uint8_t mode) -{ - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_REGULATOR_MODE, &mode, 1); -} - -static int sx126x_set_buffer_base_address(const struct device *dev, - uint8_t tx_base, uint8_t rx_base) -{ - uint8_t buf[2] = { tx_base, rx_base }; - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_BUFFER_BASE_ADDRESS, buf, 2); -} - -static int sx126x_set_packet_type(const struct device *dev, uint8_t type) -{ - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_PACKET_TYPE, &type, 1); -} - -static int sx126x_set_dio_irq_params(const struct device *dev, - uint16_t irq_mask, uint16_t dio1_mask, - uint16_t dio2_mask, uint16_t dio3_mask) -{ - uint8_t buf[8]; - - sys_put_be16(irq_mask, &buf[0]); - sys_put_be16(dio1_mask, &buf[2]); - sys_put_be16(dio2_mask, &buf[4]); - sys_put_be16(dio3_mask, &buf[6]); - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_DIO_IRQ_PARAMS, buf, 8); -} - -static int sx126x_clear_irq_status(const struct device *dev, uint16_t mask) -{ - uint8_t buf[2]; - - sys_put_be16(mask, buf); - return sx126x_hal_write_cmd(dev, SX126X_CMD_CLR_IRQ_STATUS, buf, 2); -} - -static int sx126x_get_irq_status(const struct device *dev, uint16_t *status) -{ - uint8_t buf[2]; - int ret; - - ret = sx126x_hal_read_cmd(dev, SX126X_CMD_GET_IRQ_STATUS, buf, 2); - if (ret == 0) { - *status = ((uint16_t)buf[0] << 8) | buf[1]; - } - - return ret; -} - -static int sx126x_set_dio2_as_rf_switch(const struct device *dev, bool enable) -{ - uint8_t val = enable; - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_DIO2_AS_RF_SWITCH, &val, 1); -} - -static int sx126x_set_dio3_as_tcxo_ctrl(const struct device *dev, - uint8_t voltage, uint32_t timeout_ms) -{ - /* Timeout in units of 15.625 us */ - uint32_t timeout = SX126X_MS_TO_TIMEOUT(timeout_ms); - uint8_t buf[4]; - - buf[0] = voltage; - sys_put_be24(timeout, &buf[1]); - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, buf, 4); -} - -static int sx126x_calibrate(const struct device *dev, uint8_t mask) -{ - return sx126x_hal_write_cmd(dev, SX126X_CMD_CALIBRATE, &mask, 1); -} - -static int sx126x_calibrate_image(const struct device *dev, uint32_t freq) -{ - uint8_t buf[2]; - - if (freq > 900000000) { - buf[0] = 0xE1; - buf[1] = 0xE9; - } else if (freq > 850000000) { - buf[0] = 0xD7; - buf[1] = 0xDB; - } else if (freq > 770000000) { - buf[0] = 0xC1; - buf[1] = 0xC5; - } else if (freq > 460000000) { - buf[0] = 0x75; - buf[1] = 0x81; - } else { - buf[0] = 0x6B; - buf[1] = 0x6F; - } - - return sx126x_hal_write_cmd(dev, SX126X_CMD_CALIBRATE_IMAGE, buf, 2); -} - -static int sx126x_set_rf_frequency(const struct device *dev, uint32_t freq) -{ - uint32_t freq_reg = SX126X_FREQ_TO_REG(freq); - uint8_t buf[4]; - - sys_put_be32(freq_reg, buf); - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_RF_FREQUENCY, buf, 4); -} - -static int sx126x_set_pa_config(const struct device *dev, uint8_t pa_duty_cycle, - uint8_t hp_max, uint8_t device_sel, uint8_t pa_lut) -{ - uint8_t buf[4] = { pa_duty_cycle, hp_max, device_sel, pa_lut }; - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_PA_CONFIG, buf, 4); -} - -static int sx126x_configure_pa_and_tx_params(const struct device *dev, - int8_t power, uint32_t frequency, - uint8_t ramp_time) -{ - const struct sx126x_hal_config *config = dev->config; - uint8_t pa_duty_cycle; - int8_t tx_power; - int ret; - - if (config->is_sx1261) { - /* - * SX1261: Low power PA, up to +15 dBm - * For +15 dBm at >400 MHz, use higher paDutyCycle. - * For lower power, use lower paDutyCycle for efficiency. - */ - pa_duty_cycle = (power >= SX1261_MAX_POWER && frequency >= 400000000) - ? SX1261_PA_DUTY_CYCLE_HIGH - : SX1261_PA_DUTY_CYCLE_LOW; - ret = sx126x_set_pa_config(dev, pa_duty_cycle, SX1261_HP_MAX, - SX126X_DEVICE_SEL_SX1261, - SX126X_PA_LUT); - if (ret < 0) { - return ret; - } - tx_power = CLAMP(power, SX1261_MIN_POWER, SX1261_MAX_POWER_TX_PARAM); - } else { - /* SX1262: High power PA, up to +22 dBm */ - ret = sx126x_set_pa_config(dev, SX1262_PA_DUTY_CYCLE, - SX1262_HP_MAX, - SX126X_DEVICE_SEL_SX1262, - SX126X_PA_LUT); - if (ret < 0) { - return ret; - } - tx_power = CLAMP(power, SX1262_MIN_POWER, SX1262_MAX_POWER); - } - - uint8_t buf[2] = { (uint8_t)tx_power, ramp_time }; - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_TX_PARAMS, buf, 2); -} - -static int sx126x_set_modulation_params(const struct device *dev, - uint8_t sf, uint8_t bw, uint8_t cr, - bool ldro) -{ - uint8_t buf[4] = { sf, bw, cr, ldro }; - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_MODULATION_PARAMS, buf, 4); -} - -static int sx126x_set_packet_params(const struct device *dev, - uint16_t preamble_len, uint8_t header_type, - uint8_t payload_len, uint8_t crc_mode, - uint8_t invert_iq) -{ - uint8_t buf[6]; - - sys_put_be16(preamble_len, &buf[0]); - buf[2] = header_type; - buf[3] = payload_len; - buf[4] = crc_mode; - buf[5] = invert_iq; - - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_PACKET_PARAMS, buf, 6); -} - -static int sx126x_set_sync_word(const struct device *dev, bool public_network) -{ - uint16_t sync_word = public_network ? - SX126X_LORA_SYNC_WORD_PUBLIC : - SX126X_LORA_SYNC_WORD_PRIVATE; - uint8_t buf[2]; - - sys_put_be16(sync_word, buf); - return sx126x_hal_write_regs(dev, SX126X_REG_LORA_SYNC_WORD_MSB, buf, 2); -} - -static int sx126x_set_rx_gain(const struct device *dev, bool boosted) -{ - uint8_t val = boosted ? SX126X_RX_GAIN_BOOSTED : SX126X_RX_GAIN_POWER_SAVING; - - return sx126x_hal_write_regs(dev, SX126X_REG_RX_GAIN, &val, 1); -} - -static int sx126x_set_tx(const struct device *dev, uint32_t timeout_ms) -{ - uint32_t timeout = SX126X_MS_TO_TIMEOUT(timeout_ms); - uint8_t buf[3]; - - sys_put_be24(timeout, buf); - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_TX, buf, 3); -} - -static int sx126x_set_rx(const struct device *dev, uint32_t timeout_ms) -{ - uint32_t timeout; - - if (timeout_ms == 0) { - timeout = SX126X_RX_TIMEOUT_CONTINUOUS; - } else { - timeout = SX126X_MS_TO_TIMEOUT(timeout_ms); - } - - uint8_t buf[3]; - - sys_put_be24(timeout, buf); - return sx126x_hal_write_cmd(dev, SX126X_CMD_SET_RX, buf, 3); -} - -static int sx126x_get_rx_buffer_status(const struct device *dev, - uint8_t *payload_len, uint8_t *offset) -{ - uint8_t buf[2]; - int ret; - - ret = sx126x_hal_read_cmd(dev, SX126X_CMD_GET_RX_BUFFER_STATUS, buf, 2); - if (ret == 0) { - *payload_len = buf[0]; - *offset = buf[1]; - } - - return ret; -} - -static int sx126x_get_packet_status(const struct device *dev, - int16_t *rssi, int8_t *snr) -{ - uint8_t buf[3]; - int ret; - - ret = sx126x_hal_read_cmd(dev, SX126X_CMD_GET_PACKET_STATUS, buf, 2); - if (ret == 0) { - /* RSSI is -value/2 dBm */ - *rssi = -((int16_t)buf[0] >> 1); - /* SNR is value/4 dB (signed) */ - *snr = ((int8_t)buf[1]) >> 2; - } - - return ret; -} - -static int sx126x_chip_init(const struct device *dev) -{ - const struct sx126x_hal_config *config = dev->config; - int ret; - - /* Hardware reset */ - ret = sx126x_hal_reset(dev); - if (ret < 0) { - LOG_ERR("Reset failed: %d", ret); - return ret; - } - - /* Set standby mode */ - ret = sx126x_set_standby(dev, SX126X_STANDBY_RC); - if (ret < 0) { - LOG_ERR("Set standby failed: %d", ret); - return ret; - } - - /* Configure TCXO if enabled */ - if (config->dio3_tcxo_enable) { - ret = sx126x_set_dio3_as_tcxo_ctrl(dev, config->dio3_tcxo_voltage, - config->tcxo_startup_delay_ms); - if (ret < 0) { - LOG_ERR("Set TCXO failed: %d", ret); - return ret; - } - - /* Run full calibration after TCXO setup */ - ret = sx126x_calibrate(dev, SX126X_CALIBRATE_ALL); - if (ret < 0) { - LOG_ERR("Calibration failed: %d", ret); - return ret; - } - } - - /* Configure DIO2 as RF switch if enabled */ - if (config->dio2_tx_enable) { - ret = sx126x_set_dio2_as_rf_switch(dev, true); - if (ret < 0) { - LOG_ERR("Set DIO2 RF switch failed: %d", ret); - return ret; - } - } - - /* Set regulator mode */ - ret = sx126x_set_regulator_mode(dev, config->regulator_ldo ? - SX126X_REGULATOR_LDO : SX126X_REGULATOR_DCDC); - if (ret < 0) { - LOG_ERR("Set regulator failed: %d", ret); - return ret; - } - - /* Set buffer base addresses */ - ret = sx126x_set_buffer_base_address(dev, 0x00, 0x00); - if (ret < 0) { - LOG_ERR("Set buffer base failed: %d", ret); - return ret; - } - - /* Set packet type to LoRa */ - ret = sx126x_set_packet_type(dev, SX126X_PACKET_TYPE_LORA); - if (ret < 0) { - LOG_ERR("Set packet type failed: %d", ret); - return ret; - } - - /* Configure IRQs on DIO1: TX done, RX done, timeout */ - uint16_t irq_mask = SX126X_IRQ_TX_DONE | SX126X_IRQ_RX_DONE | - SX126X_IRQ_RX_TX_TIMEOUT | SX126X_IRQ_CRC_ERR; - ret = sx126x_set_dio_irq_params(dev, irq_mask, irq_mask, 0, 0); - if (ret < 0) { - LOG_ERR("Set IRQ params failed: %d", ret); - return ret; - } - - /* Clear any pending IRQs */ - ret = sx126x_clear_irq_status(dev, SX126X_IRQ_ALL); - if (ret < 0) { - LOG_ERR("Clear IRQ failed: %d", ret); - return ret; - } - - LOG_INF("SX126x initialized"); - return 0; -} - -static void sx126x_dio1_callback(const struct device *dev) -{ - struct sx126x_data *data = dev->data; - - k_work_submit(&data->irq_work); -} - -static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx) -{ - const struct sx126x_hal_config *config = dev->config; - - sx126x_hal_set_antenna_enable(dev, enable); - if (config->dio2_tx_enable) { - /* DIO2 handles TX enable in hardware — but rx-enable-gpios - * (e.g. E22-900M30S RXEN) still needs explicit GPIO control. - * RXEN HIGH when receiving, LOW otherwise. */ - if (config->rx_enable.port != NULL) { - gpio_pin_set_dt(&config->rx_enable, enable && !tx); - } - } else { - sx126x_hal_set_rf_switch(dev, enable && tx); - } -} - -static void sx126x_handle_irq_tx_done(const struct device *dev) -{ - struct sx126x_data *data = dev->data; - struct sx126x_tx_result result = { .status = 0 }; - - LOG_DBG("TX done"); - atomic_set(&data->state, SX126X_STATE_IDLE); - sx126x_set_rf_path(dev, false, false); - - if (data->tx_async_signal != NULL) { - k_poll_signal_raise(data->tx_async_signal, 0); - data->tx_async_signal = NULL; - } - k_msgq_put(&data->tx_msgq, &result, K_NO_WAIT); -} - -static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_status) -{ - struct sx126x_data *data = dev->data; - struct sx126x_rx_result result = { 0 }; - uint8_t payload_len = 0, offset = 0; - int ret; - - /* Get received packet info */ - ret = sx126x_get_rx_buffer_status(dev, &payload_len, &offset); - if (ret < 0) { - LOG_ERR("Failed to get RX buffer status"); - result.status = ret; - } else { - /* Get signal quality */ - sx126x_get_packet_status(dev, &result.rssi, &result.snr); - - /* Check for CRC error */ - if (irq_status & SX126X_IRQ_CRC_ERR) { - LOG_WRN("CRC error"); - result.status = -EIO; - } else { - /* Read payload into shared buffer */ - result.len = MIN(payload_len, sizeof(data->rx_buf)); - ret = sx126x_hal_read_buffer(dev, offset, - data->rx_buf, result.len); - if (ret < 0) { - LOG_ERR("Failed to read RX buffer"); - result.status = ret; - } else { - result.status = result.len; - LOG_DBG("RX done: %d bytes, RSSI=%d, SNR=%d", - result.len, result.rssi, result.snr); - } - } - } - - /* Handle async callback or signal sync receiver */ - if (data->rx_cb != NULL) { - /* Async mode - call callback and restart RX */ - data->rx_cb(dev, data->rx_buf, result.len, - result.rssi, result.snr, - data->rx_cb_user_data); - /* Restart RX for continuous reception */ - sx126x_set_rx(dev, 0); - } else { - /* Sync mode */ - atomic_set(&data->state, SX126X_STATE_IDLE); - sx126x_set_rf_path(dev, false, false); - k_msgq_put(&data->rx_msgq, &result, K_NO_WAIT); - } -} - -static void sx126x_handle_irq_timeout(const struct device *dev) -{ - struct sx126x_data *data = dev->data; - - LOG_DBG("Timeout"); - atomic_set(&data->state, SX126X_STATE_IDLE); - sx126x_set_rf_path(dev, false, false); - - if (data->tx_async_signal != NULL) { - struct sx126x_tx_result result = { .status = -ETIMEDOUT }; - - k_poll_signal_raise(data->tx_async_signal, -ETIMEDOUT); - data->tx_async_signal = NULL; - k_msgq_put(&data->tx_msgq, &result, K_NO_WAIT); - } else if (data->rx_cb == NULL) { - /* Sync RX timeout */ - struct sx126x_rx_result result = { .status = -EAGAIN }; - - k_msgq_put(&data->rx_msgq, &result, K_NO_WAIT); - } -} - -static void sx126x_irq_work_handler(struct k_work *work) -{ - struct sx126x_data *data = CONTAINER_OF(work, struct sx126x_data, irq_work); - const struct device *dev = data->dev; - uint16_t irq_status = 0; - int ret; - - ret = sx126x_get_irq_status(dev, &irq_status); - if (ret < 0) { - LOG_ERR("Failed to get IRQ status"); - return; - } - - LOG_DBG("IRQ status: 0x%04x", irq_status); - - /* Clear handled IRQs */ - sx126x_clear_irq_status(dev, irq_status); - - if (irq_status & SX126X_IRQ_TX_DONE) { - sx126x_handle_irq_tx_done(dev); - } - - if (irq_status & SX126X_IRQ_RX_DONE) { - sx126x_handle_irq_rx_done(dev, irq_status); - } - - if (irq_status & SX126X_IRQ_RX_TX_TIMEOUT) { - sx126x_handle_irq_timeout(dev); - } -} - -static int sx126x_lora_config(const struct device *dev, - struct lora_modem_config *config) -{ - struct sx126x_data *data = dev->data; - const struct sx126x_hal_config *hal_config = dev->config; - bool ldro; - int ret; - - k_mutex_lock(&data->lock, K_FOREVER); - - /* Store configuration */ - memcpy(&data->config, config, sizeof(*config)); - - /* Run image calibration for frequency band */ - ret = sx126x_calibrate_image(dev, config->frequency); - if (ret < 0) { - goto out; - } - - /* Set RF frequency */ - ret = sx126x_set_rf_frequency(dev, config->frequency); - if (ret < 0) { - goto out; - } - - /* Configure PA and TX power based on chip variant and frequency */ - ret = sx126x_configure_pa_and_tx_params(dev, config->tx_power, - config->frequency, - SX126X_RAMP_200_US); - if (ret < 0) { - goto out; - } - - /* Set modulation parameters */ - ldro = should_enable_ldro(config->datarate, config->bandwidth, hal_config); - ret = sx126x_set_modulation_params(dev, - config->datarate, - bandwidth_to_reg(config->bandwidth), - config->coding_rate, - ldro); - if (ret < 0) { - goto out; - } - - /* Set sync word */ - ret = sx126x_set_sync_word(dev, config->public_network); - if (ret < 0) { - goto out; - } - - /* Set RX gain */ - ret = sx126x_set_rx_gain(dev, hal_config->rx_boosted); - if (ret < 0) { - goto out; - } - - data->config_valid = true; - LOG_DBG("Config: freq=%u, SF=%d, BW=%d, CR=%d, power=%d", - config->frequency, config->datarate, config->bandwidth, - config->coding_rate, config->tx_power); - -out: - k_mutex_unlock(&data->lock); - return ret; -} - -static int sx126x_lora_send_async(const struct device *dev, - uint8_t *data_buf, uint32_t data_len, - struct k_poll_signal *async) -{ - struct sx126x_data *data = dev->data; - int ret; - - if (!data->config_valid) { - LOG_ERR("Not configured"); - return -EINVAL; - } - - if (data_len > SX126X_MAX_PAYLOAD_LEN) { - LOG_ERR("Payload too long: %u", data_len); - return -EINVAL; - } - - if (!atomic_cas(&data->state, SX126X_STATE_IDLE, SX126X_STATE_TX)) { - LOG_ERR("Busy"); - return -EBUSY; - } - - k_mutex_lock(&data->lock, K_FOREVER); - data->tx_async_signal = async; - k_msgq_purge(&data->tx_msgq); - - /* Set packet parameters */ - ret = sx126x_set_packet_params(dev, - data->config.preamble_len, - SX126X_LORA_HEADER_EXPLICIT, - data_len, - data->config.packet_crc_disable ? - SX126X_LORA_CRC_OFF : SX126X_LORA_CRC_ON, - data->config.iq_inverted ? - SX126X_LORA_IQ_INVERTED : SX126X_LORA_IQ_STANDARD); - if (ret < 0) { - goto out_error; - } - - /* Write payload to buffer */ - ret = sx126x_hal_write_buffer(dev, 0x00, data_buf, data_len); - if (ret < 0) { - goto out_error; - } - - /* Enable antenna and set TX path */ - sx126x_set_rf_path(dev, true, true); - - /* Start transmission with 10 second timeout */ - ret = sx126x_set_tx(dev, 10000); - if (ret < 0) { - goto out_error; - } - - k_mutex_unlock(&data->lock); - return 0; - -out_error: - data->tx_async_signal = NULL; - k_mutex_unlock(&data->lock); - atomic_set(&data->state, SX126X_STATE_IDLE); - return ret; -} - -static int sx126x_lora_send(const struct device *dev, - uint8_t *data_buf, uint32_t data_len) -{ - struct sx126x_data *data = dev->data; - struct sx126x_tx_result result; - int ret; - - ret = sx126x_lora_send_async(dev, data_buf, data_len, NULL); - if (ret < 0) { - return ret; - } - - /* Wait for TX completion */ - ret = k_msgq_get(&data->tx_msgq, &result, K_SECONDS(15)); - if (ret < 0) { - LOG_ERR("TX timeout"); - atomic_set(&data->state, SX126X_STATE_IDLE); - return -ETIMEDOUT; - } - - return result.status; -} - -static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf, - uint8_t size, k_timeout_t timeout, - int16_t *rssi, int8_t *snr) -{ - struct sx126x_data *data = dev->data; - struct sx126x_rx_result result; - uint32_t timeout_ms; - int ret; - - if (!data->config_valid) { - LOG_ERR("Not configured"); - return -EINVAL; - } - - if (!atomic_cas(&data->state, SX126X_STATE_IDLE, SX126X_STATE_RX)) { - LOG_ERR("Busy"); - return -EBUSY; - } - - k_mutex_lock(&data->lock, K_FOREVER); - data->rx_cb = NULL; - k_msgq_purge(&data->rx_msgq); - - /* Set packet parameters for variable length reception */ - ret = sx126x_set_packet_params(dev, - data->config.preamble_len, - SX126X_LORA_HEADER_EXPLICIT, - SX126X_MAX_PAYLOAD_LEN, - data->config.packet_crc_disable ? - SX126X_LORA_CRC_OFF : SX126X_LORA_CRC_ON, - data->config.iq_inverted ? - SX126X_LORA_IQ_INVERTED : SX126X_LORA_IQ_STANDARD); - if (ret < 0) { - k_mutex_unlock(&data->lock); - atomic_set(&data->state, SX126X_STATE_IDLE); - return ret; - } - - /* Enable antenna and set RX path */ - sx126x_set_rf_path(dev, true, false); - - /* Start reception (0 = continuous for K_FOREVER) */ - timeout_ms = K_TIMEOUT_EQ(timeout, K_FOREVER) - ? 0 : k_ticks_to_ms_ceil32(timeout.ticks); - ret = sx126x_set_rx(dev, timeout_ms); - if (ret < 0) { - sx126x_set_rf_path(dev, false, false); - k_mutex_unlock(&data->lock); - atomic_set(&data->state, SX126X_STATE_IDLE); - return ret; - } - - k_mutex_unlock(&data->lock); - - /* Wait for RX completion */ - ret = k_msgq_get(&data->rx_msgq, &result, timeout); - if (ret < 0) { - LOG_DBG("RX timeout"); - atomic_set(&data->state, SX126X_STATE_IDLE); - sx126x_set_standby(dev, SX126X_STANDBY_RC); - sx126x_set_rf_path(dev, false, false); - return -EAGAIN; - } - - /* Copy received data from shared buffer */ - if (result.status > 0) { - int copy_len = MIN(result.status, size); - - memcpy(data_buf, data->rx_buf, copy_len); - if (rssi != NULL) { - *rssi = result.rssi; - } - if (snr != NULL) { - *snr = result.snr; - } - return copy_len; - } - - return result.status; -} - -static int sx126x_lora_recv_async(const struct device *dev, - lora_recv_cb cb, void *user_data) -{ - struct sx126x_data *data = dev->data; - int ret; - - k_mutex_lock(&data->lock, K_FOREVER); - - if (cb == NULL) { - /* Stop async reception */ - data->rx_cb = NULL; - data->rx_cb_user_data = NULL; - if (atomic_cas(&data->state, SX126X_STATE_RX, SX126X_STATE_IDLE)) { - sx126x_set_standby(dev, SX126X_STANDBY_RC); - sx126x_set_rf_path(dev, false, false); - } - k_mutex_unlock(&data->lock); - return 0; - } - - if (!data->config_valid) { - LOG_ERR("Not configured"); - k_mutex_unlock(&data->lock); - return -EINVAL; - } - - if (!atomic_cas(&data->state, SX126X_STATE_IDLE, SX126X_STATE_RX)) { - LOG_ERR("Busy"); - k_mutex_unlock(&data->lock); - return -EBUSY; - } - - data->rx_cb = cb; - data->rx_cb_user_data = user_data; - - /* Set packet parameters */ - ret = sx126x_set_packet_params(dev, - data->config.preamble_len, - SX126X_LORA_HEADER_EXPLICIT, - SX126X_MAX_PAYLOAD_LEN, - data->config.packet_crc_disable ? - SX126X_LORA_CRC_OFF : SX126X_LORA_CRC_ON, - data->config.iq_inverted ? - SX126X_LORA_IQ_INVERTED : SX126X_LORA_IQ_STANDARD); - if (ret < 0) { - data->rx_cb = NULL; - k_mutex_unlock(&data->lock); - atomic_set(&data->state, SX126X_STATE_IDLE); - return ret; - } - - /* Enable antenna and set RX path */ - sx126x_set_rf_path(dev, true, false); - - /* Start continuous reception */ - ret = sx126x_set_rx(dev, 0); - if (ret < 0) { - data->rx_cb = NULL; - sx126x_set_rf_path(dev, false, false); - k_mutex_unlock(&data->lock); - atomic_set(&data->state, SX126X_STATE_IDLE); - return ret; - } - - k_mutex_unlock(&data->lock); - return 0; -} - -static uint32_t sx126x_lora_airtime(const struct device *dev, uint32_t data_len) -{ - struct sx126x_data *data = dev->data; - uint32_t t_preamble_us, t_payload_us, t_sym_us, n_payload, bw_hz; - uint8_t sf, cr; - int32_t tmp; - bool de, crc; - - if (!data->config_valid) { - return 0; - } - - /* Calculate symbol time in microseconds */ - bw_hz = bandwidth_to_hz(data->config.bandwidth); - sf = data->config.datarate; - - /* Symbol time = 2^SF / BW (seconds) */ - /* In microseconds: (2^SF * 1000000) / BW */ - t_sym_us = ((1UL << sf) * 1000000UL) / bw_hz; - - /* Preamble time (4.25 extra symbols) */ - t_preamble_us = (data->config.preamble_len + 4) * t_sym_us + - (t_sym_us / 4); - - /* Payload symbol count calculation (from LoRa modem designer's guide) */ - de = should_enable_ldro(sf, data->config.bandwidth, dev->config); - crc = !data->config.packet_crc_disable; - cr = data->config.coding_rate; - - /* ih (implicit header) = false for explicit header mode */ - tmp = 8 * data_len - 4 * sf + 28 + 16 * crc; - if (tmp < 0) { - tmp = 0; - } - - n_payload = 8 + (((tmp + 4 * (sf - 2 * de) - 1) / - (4 * (sf - 2 * de))) * (cr + 4)); - t_payload_us = n_payload * t_sym_us; - - /* Total airtime in milliseconds */ - return (t_preamble_us + t_payload_us + 500) / 1000; -} - -static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency, - int8_t tx_power, uint16_t duration) -{ - struct sx126x_data *data = dev->data; - int ret; - - if (atomic_get(&data->state) != SX126X_STATE_IDLE) { - return -EBUSY; - } - - k_mutex_lock(&data->lock, K_FOREVER); - - /* Set frequency */ - ret = sx126x_set_rf_frequency(dev, frequency); - if (ret < 0) { - k_mutex_unlock(&data->lock); - return ret; - } - - /* Set PA config and TX power */ - ret = sx126x_configure_pa_and_tx_params(dev, tx_power, frequency, - SX126X_RAMP_200_US); - if (ret < 0) { - k_mutex_unlock(&data->lock); - return ret; - } - - /* Enable antenna and TX path */ - sx126x_set_rf_path(dev, true, true); - - /* Start CW transmission */ - ret = sx126x_hal_write_cmd(dev, SX126X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0); - if (ret < 0) { - sx126x_set_rf_path(dev, false, false); - k_mutex_unlock(&data->lock); - return ret; - } - - k_mutex_unlock(&data->lock); - - /* Wait for duration */ - k_sleep(K_SECONDS(duration)); - - /* Stop CW */ - k_mutex_lock(&data->lock, K_FOREVER); - sx126x_set_standby(dev, SX126X_STANDBY_RC); - sx126x_set_rf_path(dev, false, false); - k_mutex_unlock(&data->lock); - - return 0; -} - -static const struct lora_driver_api sx126x_lora_api = { - .config = sx126x_lora_config, - .send = sx126x_lora_send, - .send_async = sx126x_lora_send_async, - .recv = sx126x_lora_recv, - .recv_async = sx126x_lora_recv_async, - .airtime = sx126x_lora_airtime, - .test_cw = sx126x_lora_test_cw, -}; - -static int sx126x_init(const struct device *dev) -{ - struct sx126x_data *data = dev->data; - int ret; - - /* Initialize data structures */ - k_mutex_init(&data->lock); - k_msgq_init(&data->tx_msgq, (char *)&data->tx_result, - sizeof(struct sx126x_tx_result), 1); - k_msgq_init(&data->rx_msgq, (char *)&data->rx_result, - sizeof(struct sx126x_rx_result), 1); - k_work_init(&data->irq_work, sx126x_irq_work_handler); - data->dev = dev; - atomic_set(&data->state, SX126X_STATE_IDLE); - data->config_valid = false; - - /* Initialize HAL */ - ret = sx126x_hal_init(dev); - if (ret < 0) { - LOG_ERR("HAL init failed: %d", ret); - return ret; - } - - /* Setup DIO1 interrupt callback */ - ret = sx126x_hal_set_dio1_callback(dev, sx126x_dio1_callback); - if (ret < 0) { - LOG_ERR("DIO1 callback setup failed: %d", ret); - return ret; - } - - /* Initialize chip */ - ret = sx126x_chip_init(dev); - if (ret < 0) { - LOG_ERR("Chip init failed: %d", ret); - return ret; - } - - return 0; -} - -#define SX126X_INIT(inst, is_1261) \ - static struct sx126x_data sx126x_data_##inst; \ - \ - static const struct sx126x_hal_config sx126x_config_##inst = { \ - .spi = SPI_DT_SPEC_INST_GET(inst, \ - SPI_WORD_SET(8) | SPI_TRANSFER_MSB), \ - .reset = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ - .busy = GPIO_DT_SPEC_INST_GET(inst, busy_gpios), \ - .dio1 = GPIO_DT_SPEC_INST_GET(inst, dio1_gpios), \ - .antenna_enable = GPIO_DT_SPEC_INST_GET_OR(inst, \ - antenna_enable_gpios, \ - {0}), \ - .tx_enable = GPIO_DT_SPEC_INST_GET_OR(inst, tx_enable_gpios, \ - {0}), \ - .rx_enable = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, \ - {0}), \ - .is_sx1261 = is_1261, \ - .dio2_tx_enable = DT_INST_PROP(inst, dio2_tx_enable), \ - .dio3_tcxo_enable = DT_INST_NODE_HAS_PROP(inst, dio3_tcxo_voltage), \ - .dio3_tcxo_voltage = DT_INST_PROP_OR(inst, dio3_tcxo_voltage, 0), \ - .tcxo_startup_delay_ms = DT_INST_PROP_OR(inst, \ - tcxo_power_startup_delay_ms, 10), \ - .rx_boosted = DT_INST_PROP(inst, rx_boosted), \ - .regulator_ldo = DT_INST_PROP(inst, regulator_ldo), \ - .force_ldro = DT_INST_PROP(inst, force_ldro), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(inst, sx126x_init, NULL, \ - &sx126x_data_##inst, &sx126x_config_##inst, \ - POST_KERNEL, CONFIG_LORA_INIT_PRIORITY, \ - &sx126x_lora_api); - -#define DT_DRV_COMPAT semtech_sx1262 -DT_INST_FOREACH_STATUS_OKAY_VARGS(SX126X_INIT, false) - -#undef DT_DRV_COMPAT -#define DT_DRV_COMPAT semtech_sx1261 -DT_INST_FOREACH_STATUS_OKAY_VARGS(SX126X_INIT, true) diff --git a/zephcore/patches/zephyr/scripts/west_commands/blobs.py b/zephcore/patches/zephyr/scripts/west_commands/blobs.py deleted file mode 100644 index 615ba60..0000000 --- a/zephcore/patches/zephyr/scripts/west_commands/blobs.py +++ /dev/null @@ -1,346 +0,0 @@ -# Copyright (c) 2022 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 - -import argparse -import os -import re -import shutil -import sys -import textwrap -from pathlib import Path -from urllib.parse import urlparse - -from west.commands import WestCommand - -from zephyr_ext_common import ZEPHYR_BASE - -sys.path.append(os.fspath(Path(__file__).parent.parent)) -import zephyr_module - - -class Blobs(WestCommand): - DEFAULT_LIST_FMT = '{module} {status} {path} {type} {abspath}' - - def __init__(self): - super().__init__( - 'blobs', - # Keep this in sync with the string in west-commands.yml. - 'work with binary blobs', - 'Work with binary blobs', - accepts_unknown_args=False, - ) - - def do_add_parser(self, parser_adder): - parser = parser_adder.add_parser( - self.name, - help=self.help, - formatter_class=argparse.RawDescriptionHelpFormatter, - description=self.description, - epilog=textwrap.dedent(f'''\ - FORMAT STRINGS - -------------- - - Blobs are listed using a Python 3 format string. Arguments - to the format string are accessed by name. - - The default format string is: - - "{self.DEFAULT_LIST_FMT}" - - The following arguments are available: - - - module: name of the module that contains this blob - - abspath: blob absolute path - - status: short status (A: present, M: hash failure, D: not present) - - path: blob local path from /zephyr/blobs/ - - sha256: blob SHA256 hash in hex - - type: type of blob - - version: version string - - license_path: path to the license file for the blob - - license-abspath: absolute path to the license file for the blob - - click-through: need license click-through or not - - uri: URI to the remote location of the blob - - description: blob text description - - doc-url: URL to the documentation for this blob - '''), - ) - - # Remember to update west-completion.bash if you add or remove - # flags - parser.add_argument( - 'subcmd', nargs=1, choices=['list', 'fetch', 'clean'], help='sub-command to execute' - ) - - parser.add_argument( - 'modules', - metavar='MODULE', - nargs='*', - help='''zephyr modules to operate on; - all modules will be used if not given''', - ) - - group = parser.add_argument_group('west blob list options') - group.add_argument( - '-f', - '--format', - help='''format string to use to list each blob; - see FORMAT STRINGS below''', - ) - - group = parser.add_argument_group('west blobs fetch options') - group.add_argument( - '-l', - '--allow-regex', - help='''Regex pattern to apply to the blob local path. - Only local paths matching this regex will be fetched. - Note that local paths are relative to the module directory''', - ) - group.add_argument( - '-a', - '--auto-accept', - action='store_true', - help='''auto accept license if the fetching needs click-through''', - ) - group.add_argument( - '--cache-dirs', - help='''Semicolon-separated list of directories to search for cached - blobs before downloading. Cache files may use the original - filename or be suffixed with `.`.''', - ) - group.add_argument( - '--auto-cache', - help='''Path to a directory that is automatically populated when a blob - is downloaded. Cached blobs are stored using the original - filename suffixed with `.`.''', - ) - - return parser - - def get_blobs(self, args): - blobs = [] - modules = args.modules - all_modules = zephyr_module.parse_modules(ZEPHYR_BASE, self.manifest) - all_names = [m.meta.get('name', None) for m in all_modules] - - unknown = set(modules) - set(all_names) - - if len(unknown): - self.die(f'Unknown module(s): {unknown}') - - for module in all_modules: - # Filter by module - module_name = module.meta.get('name', None) - if len(modules) and module_name not in modules: - continue - - blobs += zephyr_module.process_blobs(module.project, module.meta) - - return blobs - - def list(self, args): - blobs = self.get_blobs(args) - fmt = args.format or self.DEFAULT_LIST_FMT - for blob in blobs: - self.inf(fmt.format(**blob)) - - def ensure_folder(self, path): - path.parent.mkdir(parents=True, exist_ok=True) - - def handle_auto_cache(self, blob, auto_cache_dir) -> Path: - """ - This function guarantees that a given blob exists in the auto-cache. - It first checks whether the blob is already present. If so, it - returns the path of this cached blob. If the blob is not yet cached, - the blob is downloaded into the auto-cache directory and the path of - the freshly cached blob is returned. - """ - cached_blob = self.get_cached_blob(blob, [auto_cache_dir]) - if cached_blob: - return cached_blob - name = Path(blob['path']).name - sha256 = blob['sha256'] - self.download_blob(blob, auto_cache_dir / f'{name}.{sha256}') - cached_blob = self.get_cached_blob(blob, [auto_cache_dir]) - assert cached_blob, f'Blob {name} still not cached in auto-cache.' - return cached_blob - - def get_cached_blob(self, blob, cache_dirs: list) -> Path | None: - """ - Look for a cached blob in the provided cache directories. - A blob may be stored using either its original name or suffixed with - its SHA256 hash (e.g. "."). - Return the first matching path, or None if not found. - """ - name = Path(blob['path']).name - sha256 = blob["sha256"] - candidate_names = [ - f"{name}.{sha256}", # suffixed version - name, # original blob name - ] - - for cache_dir in cache_dirs: - if not cache_dir.exists(): - continue - for name in candidate_names: - candidate_path = cache_dir / name - if ( - zephyr_module.get_blob_status(candidate_path, sha256) - == zephyr_module.BLOB_PRESENT - ): - return candidate_path - return None - - def download_blob(self, blob, path): - '''Download a blob from its url to a given path.''' - url = blob['url'] - scheme = urlparse(url).scheme - self.dbg(f'Fetching blob from url {url} with {scheme} to path: {path}') - import fetchers - - fetcher = fetchers.get_fetcher_cls(scheme) - self.dbg(f'Found fetcher: {fetcher}') - inst = fetcher() - self.ensure_folder(path) - inst.fetch(url, path) - - def fetch_blob(self, args, blob): - """ - Ensures that the specified blob is available at its path. - If caching is enabled and the blob exists in the cache, it is copied - from there. Otherwise, the blob is downloaded from its URL and placed - at the target path. - """ - path = Path(blob['abspath']) - - # collect existing cache dirs specified as args, otherwise from west config - cache_dirs = args.cache_dirs - auto_cache_dir = args.auto_cache - if self.has_config: - if cache_dirs is None: - cache_dirs = self.config.get('blobs.cache-dirs') - if auto_cache_dir is None: - auto_cache_dir = self.config.get('blobs.auto-cache') - - # expand user home for each cache directory - if auto_cache_dir is not None: - auto_cache_dir = Path(auto_cache_dir).expanduser() - if cache_dirs is not None: - cache_dirs = [Path(p).expanduser() for p in cache_dirs.split(';') if p] - - # search for cached blob in the cache directories - cached_blob = self.get_cached_blob(blob, cache_dirs or []) - - # If blob is not found in cache directories: Use auto-cache if enabled - if not cached_blob and auto_cache_dir: - cached_blob = self.handle_auto_cache(blob, auto_cache_dir) - - # Copy blob if it is cached, otherwise download it - if cached_blob: - self.dbg(f'Copy cached blob: {cached_blob}') - self.ensure_folder(path) - shutil.copy(cached_blob, path) - else: - self.download_blob(blob, path) - - # Compare the checksum of a file we've just downloaded - # to the digest in blob metadata, warn user if they differ. - def verify_blob(self, blob) -> bool: - self.dbg(f"Verifying blob {blob['module']}: {blob['abspath']}") - - status = zephyr_module.get_blob_status(blob['abspath'], blob['sha256']) - if status == zephyr_module.BLOB_OUTDATED: - self.err( - textwrap.dedent( - f'''\ - The checksum of the downloaded file does not match that - in the blob metadata: - - if it is not certain that the download was successful, - try running 'west blobs fetch {blob['module']}' - to re-download the file - - if the error persists, please consider contacting - the maintainers of the module so that they can check - the corresponding blob metadata - - Module: {blob['module']} - Blob: {blob['path']} - URL: {blob['url']} - Info: {blob['description']}''' - ) - ) - return False - return True - - def fetch(self, args): - bad_checksum_count = 0 - blobs = self.get_blobs(args) - for blob in blobs: - if blob['status'] == zephyr_module.BLOB_PRESENT: - self.dbg(f"Blob {blob['module']}: {blob['abspath']} is up to date") - continue - - # if args.allow_regex is set, use it to filter the blob by path - if args.allow_regex and not re.match(args.allow_regex, blob['path']): - self.dbg( - f"Blob {blob['module']}: {blob['abspath']} does not match regex " - f"'{args.allow_regex}', skipping" - ) - continue - self.inf(f"Fetching blob {blob['module']}: {blob['abspath']}") - - if blob.get('click-through') and not args.auto_accept: - while True: - user_input = input( - "For this blob, need to read and accept " - "license to continue. Read it?\n" - "Please type 'y' or 'n' and press enter to confirm: " - ) - if user_input.upper() == "Y" or user_input.upper() == "N": - break - - if user_input.upper() != "Y": - self.wrn('Skip fetching this blob.') - continue - - with open(blob['license-abspath'], encoding="utf-8") as license_file: - license_content = license_file.read() - print(license_content) - - while True: - user_input = input( - "Accept license to continue?\n" - "Please type 'y' or 'n' and press enter to confirm: " - ) - if user_input.upper() == "Y" or user_input.upper() == "N": - break - - if user_input.upper() != "Y": - self.wrn('Skip fetching this blob.') - continue - - self.fetch_blob(args, blob) - if not self.verify_blob(blob): - bad_checksum_count += 1 - - if bad_checksum_count: - self.err(f"{bad_checksum_count} blobs have bad checksums") - sys.exit(os.EX_DATAERR) - - def clean(self, args): - blobs = self.get_blobs(args) - for blob in blobs: - if blob['status'] == zephyr_module.BLOB_NOT_PRESENT: - self.dbg(f"Blob {blob['module']}: {blob['abspath']} not in filesystem") - continue - self.inf(f"Deleting blob {blob['module']}: {blob['status']} {blob['abspath']}") - blob['abspath'].unlink() - - def do_run(self, args, _): - self.dbg(f"subcmd: '{args.subcmd[0]}' modules: {args.modules}") - - subcmd = getattr(self, args.subcmd[0]) - - if args.subcmd[0] != 'list' and args.format is not None: - self.die('unexpected --format argument; this is a "west blobs list" option') - - subcmd(args)