Compare commits
5 Commits
4fb41a3211
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e6f96ea0e3 | |||
| b125dd33b9 | |||
| d382bdfd1e | |||
| efc6e17ed0 | |||
| 1c3626d58b |
@@ -0,0 +1,25 @@
|
|||||||
|
# C++ specific configuration (akin to Google's C++ style)
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html#adding-additional-style-options
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
UseTab: ForContinuationAndIndentation
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
ColumnLimit: 0
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
FixNamespaceComments: false
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
IndentCaseLabels: false
|
||||||
|
SortIncludes: Never
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLines
|
||||||
|
AlignConsecutiveAssignments: Consecutive
|
||||||
|
BreakStringLiterals: true
|
||||||
|
LineEnding: LF
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
InsertBraces: true
|
||||||
|
BreakAfterAttributes: Always
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.DS_Store
|
||||||
+34
-2
@@ -1,9 +1,9 @@
|
|||||||
DT_COMPAT_SEMTECH_LLCC68 := "semtech,llcc68"
|
DT_COMPAT_SEMTECH_LLCC68_WEIHUA := "semtech,llcc68-weihua"
|
||||||
|
|
||||||
config LLCC68
|
config LLCC68
|
||||||
bool "Semtech LLCC68 LoRa Radio Driver"
|
bool "Semtech LLCC68 LoRa Radio Driver"
|
||||||
depends on SPI && GPIO
|
depends on SPI && GPIO
|
||||||
default $(dt_compat_enabled,$(DT_COMPAT_SEMTECH_LLCC68))
|
default $(dt_compat_enabled,$(DT_COMPAT_SEMTECH_LLCC68_WEIHUA))
|
||||||
help
|
help
|
||||||
Enable the Semtech LLCC68 LoRa Radio Driver.
|
Enable the Semtech LLCC68 LoRa Radio Driver.
|
||||||
|
|
||||||
@@ -32,6 +32,38 @@ config LLCC68_ALWAYS_USE_SX1262_HIGH_PA
|
|||||||
When enabled, the LLCC68/SX1262/SX1261 driver always chooses high
|
When enabled, the LLCC68/SX1262/SX1261 driver always chooses high
|
||||||
power amplifier settings instead of selecting them from chip version.
|
power amplifier settings instead of selecting them from chip version.
|
||||||
|
|
||||||
|
choice LLCC68_RF_SWITCH_DEFAULT
|
||||||
|
prompt "Default LLCC68 RF switch mode"
|
||||||
|
default LLCC68_RF_SWITCH_DEFAULT_AUTO
|
||||||
|
help
|
||||||
|
Default RF switch mode for LLCC68 devicetree nodes that do not set
|
||||||
|
rf-switch-mode.
|
||||||
|
|
||||||
|
config LLCC68_RF_SWITCH_DEFAULT_AUTO
|
||||||
|
bool "Auto"
|
||||||
|
help
|
||||||
|
Preserve legacy behavior: use complementary GPIO control when both
|
||||||
|
tx-enable-gpios and rx-enable-gpios are present, otherwise disable RF
|
||||||
|
switch control.
|
||||||
|
|
||||||
|
config LLCC68_RF_SWITCH_DEFAULT_NONE
|
||||||
|
bool "None"
|
||||||
|
help
|
||||||
|
Disable RF switch control unless rf-switch-mode is set in devicetree.
|
||||||
|
|
||||||
|
config LLCC68_RF_SWITCH_DEFAULT_GPIO_COMPLEMENTARY
|
||||||
|
bool "TXEN/RXEN complementary GPIO"
|
||||||
|
help
|
||||||
|
Use MCU GPIOs for complementary TXEN/RXEN RF switch control by default.
|
||||||
|
|
||||||
|
config LLCC68_RF_SWITCH_DEFAULT_DIO2_SINGLE
|
||||||
|
bool "DIO2 single-pin"
|
||||||
|
help
|
||||||
|
Use LLCC68 DIO2 RF switch control by default. DIO2 drives TXEN, while
|
||||||
|
RXEN is held active externally or by rx-enable-gpios.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
module = LLCC68
|
module = LLCC68
|
||||||
module-str = llcc68
|
module-str = llcc68
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,34 @@
|
|||||||
#include "llcc68_raw.h"
|
#include "llcc68_raw.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <zephyr/devicetree.h>
|
||||||
|
#include <zephyr/sys_clock.h>
|
||||||
#include <zephyr/sys/util.h>
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
#define DT_DRV_COMPAT semtech_llcc68_weihua
|
#define DT_DRV_COMPAT semtech_llcc68_weihua
|
||||||
|
|
||||||
|
#define LLCC68_AUTO_RF_SWITCH_MODE(inst) \
|
||||||
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios), \
|
||||||
|
(COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, rx_enable_gpios), \
|
||||||
|
(LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY), (LLCC68_RF_SWITCH_NONE))), \
|
||||||
|
(LLCC68_RF_SWITCH_NONE))
|
||||||
|
|
||||||
|
#if defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_GPIO_COMPLEMENTARY)
|
||||||
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY
|
||||||
|
#elif defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_DIO2_SINGLE)
|
||||||
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_DIO2_SINGLE
|
||||||
|
#elif defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_NONE)
|
||||||
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_NONE
|
||||||
|
#else
|
||||||
|
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_AUTO_RF_SWITCH_MODE(inst)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LLCC68_RF_SWITCH_MODE(inst) \
|
||||||
|
DT_ENUM_IDX_OR(DT_DRV_INST(inst), rf_switch_mode, LLCC68_DEFAULT_RF_SWITCH_MODE(inst))
|
||||||
|
|
||||||
|
#define LLCC68_SPI_CS_DELAY_US(inst) \
|
||||||
|
DIV_ROUND_UP(DT_INST_PROP(inst, spi_cs_setup_delay_ns), NSEC_PER_USEC)
|
||||||
|
|
||||||
static void dio1_irq_trampoline(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
|
static void dio1_irq_trampoline(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
|
||||||
ARG_UNUSED(port);
|
ARG_UNUSED(port);
|
||||||
|
|
||||||
@@ -20,14 +44,21 @@ int llcc68_init(const struct device *dev) {
|
|||||||
const struct llcc68_config *config = dev->config;
|
const struct llcc68_config *config = dev->config;
|
||||||
struct llcc68_data *data = dev->data;
|
struct llcc68_data *data = dev->data;
|
||||||
|
|
||||||
if (config->tx_enable_gpio.port != NULL) {
|
if (config->rf_switch_mode == LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY &&
|
||||||
|
config->tx_enable_gpio.port != NULL) {
|
||||||
gpio_pin_configure_dt(&config->tx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
gpio_pin_configure_dt(&config->tx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->rx_enable_gpio.port != NULL) {
|
if (config->rf_switch_mode == LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY &&
|
||||||
|
config->rx_enable_gpio.port != NULL) {
|
||||||
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config->rf_switch_mode == LLCC68_RF_SWITCH_DIO2_SINGLE &&
|
||||||
|
config->rx_enable_gpio.port != NULL) {
|
||||||
|
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
|
gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
|
||||||
gpio_pin_configure_dt(&config->busy_gpio, GPIO_INPUT);
|
gpio_pin_configure_dt(&config->busy_gpio, GPIO_INPUT);
|
||||||
gpio_pin_configure_dt(&config->dio1_gpio, GPIO_INPUT);
|
gpio_pin_configure_dt(&config->dio1_gpio, GPIO_INPUT);
|
||||||
@@ -43,15 +74,26 @@ int llcc68_init(const struct device *dev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define LLCC68_DEFINE(inst) \
|
#define LLCC68_DEFINE(inst) \
|
||||||
|
BUILD_ASSERT(LLCC68_RF_SWITCH_MODE(inst) != LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY || \
|
||||||
|
(DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios) && \
|
||||||
|
DT_INST_NODE_HAS_PROP(inst, rx_enable_gpios)), \
|
||||||
|
"LLCC68 gpio-complementary RF switch mode requires tx-enable-gpios " \
|
||||||
|
"and rx-enable-gpios"); \
|
||||||
|
BUILD_ASSERT(LLCC68_RF_SWITCH_MODE(inst) != LLCC68_RF_SWITCH_DIO2_SINGLE || \
|
||||||
|
!DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios), \
|
||||||
|
"LLCC68 dio2-single RF switch mode uses DIO2 for TXEN and must not " \
|
||||||
|
"define tx-enable-gpios"); \
|
||||||
static struct llcc68_data llcc68_data_##inst; \
|
static struct llcc68_data llcc68_data_##inst; \
|
||||||
static const struct llcc68_config llcc68_config_##inst = \
|
static const struct llcc68_config llcc68_config_##inst = \
|
||||||
{ \
|
{ \
|
||||||
.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | SPI_TRANSFER_MSB), \
|
.spi = SPI_DT_SPEC_INST_GET( \
|
||||||
|
inst, SPI_WORD_SET(8) | SPI_TRANSFER_MSB, LLCC68_SPI_CS_DELAY_US(inst)), \
|
||||||
.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \
|
.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \
|
||||||
.busy_gpio = GPIO_DT_SPEC_INST_GET(inst, busy_gpios), \
|
.busy_gpio = GPIO_DT_SPEC_INST_GET(inst, busy_gpios), \
|
||||||
.dio1_gpio = GPIO_DT_SPEC_INST_GET(inst, dio1_gpios), \
|
.dio1_gpio = GPIO_DT_SPEC_INST_GET(inst, dio1_gpios), \
|
||||||
.tx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, tx_enable_gpios, {.port = NULL}), \
|
.tx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, tx_enable_gpios, {.port = NULL}), \
|
||||||
.rx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, {.port = NULL}), \
|
.rx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, {.port = NULL}), \
|
||||||
|
.rf_switch_mode = LLCC68_RF_SWITCH_MODE(inst), \
|
||||||
}; \
|
}; \
|
||||||
DEVICE_DT_INST_DEFINE(inst, \
|
DEVICE_DT_INST_DEFINE(inst, \
|
||||||
llcc68_init, \
|
llcc68_init, \
|
||||||
|
|||||||
@@ -48,8 +48,32 @@ properties:
|
|||||||
Antenna switch RX enable GPIO. If set, the driver tracks the
|
Antenna switch RX enable GPIO. If set, the driver tracks the
|
||||||
state of the radio and controls the RF switch.
|
state of the radio and controls the RF switch.
|
||||||
|
|
||||||
|
rf-switch-mode:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- "none"
|
||||||
|
- "gpio-complementary"
|
||||||
|
- "dio2-single"
|
||||||
|
description: |
|
||||||
|
Optional RF switch control mode.
|
||||||
|
|
||||||
|
"none" disables RF switch handling.
|
||||||
|
|
||||||
|
"gpio-complementary" controls TXEN/RXEN from MCU GPIOs using the
|
||||||
|
complementary table:
|
||||||
|
idle: TXEN=0, RXEN=0
|
||||||
|
RX: TXEN=0, RXEN=1
|
||||||
|
TX: TXEN=1, RXEN=0
|
||||||
|
This mode requires tx-enable-gpios and rx-enable-gpios.
|
||||||
|
|
||||||
|
"dio2-single" enables LLCC68 DIO2-as-RF-switch control for TXEN.
|
||||||
|
RXEN must be externally pulled active or supplied as rx-enable-gpios,
|
||||||
|
which the driver holds active. This mode must not use tx-enable-gpios.
|
||||||
|
|
||||||
spi-cs-setup-delay-ns:
|
spi-cs-setup-delay-ns:
|
||||||
|
type: int
|
||||||
default: 100000
|
default: 100000
|
||||||
|
|
||||||
spi-cs-hold-delay-ns:
|
spi-cs-hold-delay-ns:
|
||||||
|
type: int
|
||||||
default: 100000
|
default: 100000
|
||||||
|
|||||||
+17
-1
@@ -120,7 +120,7 @@ struct LLCC68 {
|
|||||||
uint8_t offset, std::span<const uint8_t> data_from_host,
|
uint8_t offset, std::span<const uint8_t> data_from_host,
|
||||||
timeout_ms_t busy_timeout = DEFAULT_BUSY_TIMEOUT_MS);
|
timeout_ms_t busy_timeout = DEFAULT_BUSY_TIMEOUT_MS);
|
||||||
|
|
||||||
void tx_rx_en_pin_set(TxRxPinState state);
|
expected<unit, error_code> set_rf_switch_state(RfSwitchState state);
|
||||||
|
|
||||||
/** LLCC68 DataSheet Function */
|
/** LLCC68 DataSheet Function */
|
||||||
|
|
||||||
@@ -239,6 +239,21 @@ struct LLCC68 {
|
|||||||
|
|
||||||
expected<unit, error_code> set_tx(uint32_t timeout = TIMEOUT_NONE);
|
expected<unit, error_code> set_tx(uint32_t timeout = TIMEOUT_NONE);
|
||||||
expected<unit, error_code> set_rx(uint32_t timeout = TIMEOUT_INF);
|
expected<unit, error_code> set_rx(uint32_t timeout = TIMEOUT_INF);
|
||||||
|
/**
|
||||||
|
* @brief Start LLCC68 RX duty-cycle/listen mode.
|
||||||
|
*
|
||||||
|
* rx_period and sleep_period are raw 24-bit LLCC68 RTC periods, not
|
||||||
|
* milliseconds. Datasheet section 13.1.7 defines one period as 15.625 us:
|
||||||
|
* RX duration = rx_period * 15.625 us
|
||||||
|
* sleep duration = sleep_period * 15.625 us
|
||||||
|
*
|
||||||
|
* Use rx_duty_cycle_period_from_ms() or set_rx_duty_cycle_ms() when caller
|
||||||
|
* inputs are in milliseconds.
|
||||||
|
*/
|
||||||
|
expected<unit, error_code> set_rx_duty_cycle(uint32_t rx_period,
|
||||||
|
uint32_t sleep_period);
|
||||||
|
expected<unit, error_code> set_rx_duty_cycle_ms(uint32_t rx_period_ms,
|
||||||
|
uint32_t sleep_period_ms);
|
||||||
expected<unit, error_code> set_sleep(sleep_config_t config);
|
expected<unit, error_code> set_sleep(sleep_config_t config);
|
||||||
expected<unit, error_code> set_tx_continuous_wave();
|
expected<unit, error_code> set_tx_continuous_wave();
|
||||||
expected<unit, error_code> set_tx_infinite_preamble();
|
expected<unit, error_code> set_tx_infinite_preamble();
|
||||||
@@ -288,6 +303,7 @@ struct LLCC68 {
|
|||||||
|
|
||||||
/** properties */
|
/** properties */
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
|
std::optional<ChipType> cached_chip_type{};
|
||||||
};
|
};
|
||||||
} // namespace app::driver::llcc68
|
} // namespace app::driver::llcc68
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,42 @@ struct LLCC68;
|
|||||||
using airtime_t = std::chrono::microseconds;
|
using airtime_t = std::chrono::microseconds;
|
||||||
using error_code = std::error_code;
|
using error_code = std::error_code;
|
||||||
|
|
||||||
|
constexpr uint32_t RX_DUTY_CYCLE_PERIOD_MAX = 0x00FFFFFFU;
|
||||||
|
constexpr uint32_t RX_DUTY_CYCLE_PERIOD_UNIT_US_NUMERATOR = 125U;
|
||||||
|
constexpr uint32_t RX_DUTY_CYCLE_PERIOD_UNIT_US_DENOMINATOR = 8U;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert microseconds to a raw SetRxDutyCycle period.
|
||||||
|
*
|
||||||
|
* LLCC68 datasheet section 13.1.7 defines rxPeriod and sleepPeriod as raw
|
||||||
|
* 24-bit RTC periods, not milliseconds. One raw period is 15.625 us.
|
||||||
|
*/
|
||||||
|
constexpr std::optional<uint32_t> rx_duty_cycle_period_from_us(uint64_t us) {
|
||||||
|
constexpr uint64_t scale = RX_DUTY_CYCLE_PERIOD_UNIT_US_DENOMINATOR;
|
||||||
|
constexpr uint64_t divisor = RX_DUTY_CYCLE_PERIOD_UNIT_US_NUMERATOR;
|
||||||
|
if (us > (UINT64_MAX - (divisor - 1U)) / scale) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const uint64_t raw = ((us * scale) + (divisor - 1U)) / divisor;
|
||||||
|
if (raw > RX_DUTY_CYCLE_PERIOD_MAX) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return static_cast<uint32_t>(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert milliseconds to a raw SetRxDutyCycle period.
|
||||||
|
*
|
||||||
|
* Returns std::nullopt if the requested duration does not fit the LLCC68
|
||||||
|
* 24-bit period field.
|
||||||
|
*/
|
||||||
|
constexpr std::optional<uint32_t> rx_duty_cycle_period_from_ms(uint64_t ms) {
|
||||||
|
if (ms > UINT64_MAX / 1000U) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return rx_duty_cycle_period_from_us(ms * 1000U);
|
||||||
|
}
|
||||||
|
|
||||||
enum class Errc : uint8_t {
|
enum class Errc : uint8_t {
|
||||||
FailureToExecuteCommand = 1,
|
FailureToExecuteCommand = 1,
|
||||||
CommandTimeout = 2,
|
CommandTimeout = 2,
|
||||||
@@ -985,7 +1021,8 @@ struct irq_status_bits_t {
|
|||||||
// MSB
|
// MSB
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TxRxPinState : uint8_t {
|
enum class RfSwitchState : uint8_t {
|
||||||
|
Idle,
|
||||||
TX,
|
TX,
|
||||||
RX,
|
RX,
|
||||||
};
|
};
|
||||||
@@ -1106,7 +1143,8 @@ namespace llcc68 = app::driver::llcc68;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template <> struct is_error_code_enum<app::driver::llcc68::Errc> : true_type {};
|
template <>
|
||||||
|
struct is_error_code_enum<app::driver::llcc68::Errc> : true_type {};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
#endif /* ECC594CF_EDF0_42B5_8518_0EB3B3583727 */
|
#endif /* ECC594CF_EDF0_42B5_8518_0EB3B3583727 */
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ extern "C" {
|
|||||||
|
|
||||||
typedef void (*llcc68_user_dio1_handler_t)(const struct device *dev, void *user_data);
|
typedef void (*llcc68_user_dio1_handler_t)(const struct device *dev, void *user_data);
|
||||||
|
|
||||||
|
enum llcc68_rf_switch_mode {
|
||||||
|
LLCC68_RF_SWITCH_NONE = 0,
|
||||||
|
LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY = 1,
|
||||||
|
LLCC68_RF_SWITCH_DIO2_SINGLE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct llcc68_config {
|
struct llcc68_config {
|
||||||
struct spi_dt_spec spi;
|
struct spi_dt_spec spi;
|
||||||
struct gpio_dt_spec reset_gpio;
|
struct gpio_dt_spec reset_gpio;
|
||||||
@@ -21,6 +27,7 @@ struct llcc68_config {
|
|||||||
struct gpio_dt_spec dio1_gpio;
|
struct gpio_dt_spec dio1_gpio;
|
||||||
struct gpio_dt_spec tx_enable_gpio;
|
struct gpio_dt_spec tx_enable_gpio;
|
||||||
struct gpio_dt_spec rx_enable_gpio;
|
struct gpio_dt_spec rx_enable_gpio;
|
||||||
|
enum llcc68_rf_switch_mode rf_switch_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct llcc68_data {
|
struct llcc68_data {
|
||||||
|
|||||||
+184
-39
@@ -108,17 +108,17 @@ error_code LLCC68::init() {
|
|||||||
|
|
||||||
// Internal helpers (TU-local)
|
// Internal helpers (TU-local)
|
||||||
namespace {
|
namespace {
|
||||||
// Max payload the radio supports and buffer sizing helpers
|
// Max payload the radio supports and buffer sizing helpers
|
||||||
constexpr size_t kMaxPayload = 32;
|
constexpr size_t kMaxPayload = 32;
|
||||||
|
|
||||||
constexpr uint64_t ceil_div_u64(uint64_t numerator, uint64_t denominator) {
|
constexpr uint64_t ceil_div_u64(uint64_t numerator, uint64_t denominator) {
|
||||||
if (denominator == 0) {
|
if (denominator == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return numerator / denominator + (numerator % denominator == 0 ? 0 : 1);
|
return numerator / denominator + (numerator % denominator == 0 ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t lora_bw_hz(LoRaBandwidth bw) {
|
constexpr uint32_t lora_bw_hz(LoRaBandwidth bw) {
|
||||||
switch (bw) {
|
switch (bw) {
|
||||||
case LoRaBandwidth::BW_7_8:
|
case LoRaBandwidth::BW_7_8:
|
||||||
return 7'810;
|
return 7'810;
|
||||||
@@ -142,9 +142,9 @@ constexpr uint32_t lora_bw_hz(LoRaBandwidth bw) {
|
|||||||
return 500'000;
|
return 500'000;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_code command_status_to_error(status_t st) {
|
error_code command_status_to_error(status_t st) {
|
||||||
switch (st.command_status) {
|
switch (st.command_status) {
|
||||||
case CommandStatus::FAILURE_TO_EXECUTE_COMMAND:
|
case CommandStatus::FAILURE_TO_EXECUTE_COMMAND:
|
||||||
return make_error_code(Errc::FailureToExecuteCommand);
|
return make_error_code(Errc::FailureToExecuteCommand);
|
||||||
@@ -155,9 +155,9 @@ error_code command_status_to_error(status_t st) {
|
|||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int wait_for_not_busy(const gpio_dt_spec &busy_gpio, uint16_t timeout_ms) {
|
int wait_for_not_busy(const gpio_dt_spec &busy_gpio, uint16_t timeout_ms) {
|
||||||
if (not device_is_ready(busy_gpio.port)) {
|
if (not device_is_ready(busy_gpio.port)) {
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -169,21 +169,46 @@ int wait_for_not_busy(const gpio_dt_spec &busy_gpio, uint16_t timeout_ms) {
|
|||||||
k_busy_wait(50); // ~50 us poll interval
|
k_busy_wait(50); // ~50 us poll interval
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void LLCC68::tx_rx_en_pin_set(TxRxPinState state) {
|
expected<unit, error_code> LLCC68::set_rf_switch_state(RfSwitchState state) {
|
||||||
if (not tx_enable_gpio() or (not rx_enable_gpio())) {
|
auto set_gpio = [](const gpio_dt_spec &gpio, int value)
|
||||||
return;
|
-> expected<unit, error_code> {
|
||||||
|
if (not device_is_ready(gpio.port)) {
|
||||||
|
return ue(-ENODEV);
|
||||||
}
|
}
|
||||||
auto t = *tx_enable_gpio();
|
const int ret = gpio_pin_set_dt(&gpio, value);
|
||||||
auto r = *rx_enable_gpio();
|
if (ret < 0) {
|
||||||
if (state == TxRxPinState::TX) {
|
return ue(ret);
|
||||||
gpio_pin_set_dt(&t, 1);
|
}
|
||||||
gpio_pin_set_dt(&r, 0);
|
return unit{};
|
||||||
} else if (state == TxRxPinState::RX) {
|
};
|
||||||
gpio_pin_set_dt(&t, 0);
|
|
||||||
gpio_pin_set_dt(&r, 1);
|
switch (config().rf_switch_mode) {
|
||||||
|
case LLCC68_RF_SWITCH_DIO2_SINGLE:
|
||||||
|
case LLCC68_RF_SWITCH_NONE:
|
||||||
|
return unit{};
|
||||||
|
case LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY: {
|
||||||
|
const auto tx = tx_enable_gpio();
|
||||||
|
const auto rx = rx_enable_gpio();
|
||||||
|
if (not tx or not rx) {
|
||||||
|
return ue(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
expected<unit, error_code> r;
|
||||||
|
if (state == RfSwitchState::TX) {
|
||||||
|
r = set_gpio(*rx, 0);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
|
return set_gpio(*tx, 1);
|
||||||
|
}
|
||||||
|
r = set_gpio(*tx, 0);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
|
return set_gpio(*rx, state == RfSwitchState::RX ? 1 : 0);
|
||||||
|
}
|
||||||
|
return unit{};
|
||||||
|
default:
|
||||||
|
return ue(-EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,10 +668,16 @@ expected<unit, error_code> LLCC68::reset() {
|
|||||||
|
|
||||||
expected<unit, error_code> LLCC68::set_standby() {
|
expected<unit, error_code> LLCC68::set_standby() {
|
||||||
const uint8_t data[] = {RADIOLIB_SX126X_STANDBY_RC};
|
const uint8_t data[] = {RADIOLIB_SX126X_STANDBY_RC};
|
||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_STANDBY, data);
|
auto r = write_stream(RADIOLIB_SX126X_CMD_SET_STANDBY, data);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
|
return set_rf_switch_state(RfSwitchState::Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
expected<ChipType, error_code> LLCC68::hal_get_chip_type() {
|
expected<ChipType, error_code> LLCC68::hal_get_chip_type() {
|
||||||
|
if (cached_chip_type.has_value()) {
|
||||||
|
return *cached_chip_type;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto SX1262_CHIP_TYPE = "SX1262";
|
constexpr auto SX1262_CHIP_TYPE = "SX1262";
|
||||||
constexpr auto LLCC68_CHIP_TYPE = "LLCC68";
|
constexpr auto LLCC68_CHIP_TYPE = "LLCC68";
|
||||||
constexpr auto SX1261_CHIP_TYPE = "SX1261";
|
constexpr auto SX1261_CHIP_TYPE = "SX1261";
|
||||||
@@ -657,23 +688,31 @@ expected<ChipType, error_code> LLCC68::hal_get_chip_type() {
|
|||||||
auto r = read_register(RADIOLIB_SX126X_REG_VERSION_STRING, version_buf);
|
auto r = read_register(RADIOLIB_SX126X_REG_VERSION_STRING, version_buf);
|
||||||
APP_RADIO_RETURN_ERR(r);
|
APP_RADIO_RETURN_ERR(r);
|
||||||
LOG_HEXDUMP_DBG(version, sizeof(version), "version dump");
|
LOG_HEXDUMP_DBG(version, sizeof(version), "version dump");
|
||||||
|
|
||||||
|
ChipType chip_type = ChipType::Unknown;
|
||||||
if (strncmp(version, LLCC68_CHIP_TYPE, 6) == 0) {
|
if (strncmp(version, LLCC68_CHIP_TYPE, 6) == 0) {
|
||||||
return ChipType::LLCC68;
|
chip_type = ChipType::LLCC68;
|
||||||
|
} else if (strncmp(version, SX1261_CHIP_TYPE, 6) == 0) {
|
||||||
|
chip_type = ChipType::SX1261;
|
||||||
|
} else if (strncmp(version, SX1262_CHIP_TYPE, 6) == 0) {
|
||||||
|
chip_type = ChipType::SX1262;
|
||||||
}
|
}
|
||||||
if (strncmp(version, SX1261_CHIP_TYPE, 6) == 0) {
|
if (chip_type != ChipType::Unknown) {
|
||||||
return ChipType::SX1261;
|
cached_chip_type = chip_type;
|
||||||
}
|
}
|
||||||
if (strncmp(version, SX1262_CHIP_TYPE, 6) == 0) {
|
return chip_type;
|
||||||
return ChipType::SX1262;
|
|
||||||
}
|
|
||||||
return ChipType::Unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expected<unit, error_code> LLCC68::set_dio_irq_params(irq_params_t params) {
|
expected<unit, error_code> LLCC68::set_dio_irq_params(irq_params_t params) {
|
||||||
const uint8_t data[8] = {
|
const uint8_t data[8] = {
|
||||||
params.irqMask.msb(), params.irqMask.lsb(), params.dio1Mask.msb(),
|
params.irqMask.msb(),
|
||||||
params.dio1Mask.lsb(), params.dio2Mask.msb(), params.dio2Mask.lsb(),
|
params.irqMask.lsb(),
|
||||||
params.dio3Mask.msb(), params.dio3Mask.lsb(),
|
params.dio1Mask.msb(),
|
||||||
|
params.dio1Mask.lsb(),
|
||||||
|
params.dio2Mask.msb(),
|
||||||
|
params.dio2Mask.lsb(),
|
||||||
|
params.dio3Mask.msb(),
|
||||||
|
params.dio3Mask.lsb(),
|
||||||
};
|
};
|
||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data);
|
return write_stream(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data);
|
||||||
}
|
}
|
||||||
@@ -1080,6 +1119,8 @@ expected<unit, error_code> LLCC68::set_cad_params(cad_params_t params) {
|
|||||||
|
|
||||||
expected<unit, error_code> LLCC68::set_cad() {
|
expected<unit, error_code> LLCC68::set_cad() {
|
||||||
auto dummy = std::span<uint8_t>{};
|
auto dummy = std::span<uint8_t>{};
|
||||||
|
auto r = set_rf_switch_state(RfSwitchState::RX);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_CAD, dummy);
|
return write_stream(RADIOLIB_SX126X_CMD_SET_CAD, dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1101,21 +1142,56 @@ expected<unit, error_code> LLCC68::set_rx(uint32_t timeout) {
|
|||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_RX, data);
|
return write_stream(RADIOLIB_SX126X_CMD_SET_RX, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expected<unit, error_code> LLCC68::set_rx_duty_cycle(uint32_t rx_period,
|
||||||
|
uint32_t sleep_period) {
|
||||||
|
if (rx_period > RX_DUTY_CYCLE_PERIOD_MAX ||
|
||||||
|
sleep_period > RX_DUTY_CYCLE_PERIOD_MAX) {
|
||||||
|
return ue(-EINVAL);
|
||||||
|
}
|
||||||
|
auto r = set_rf_switch_state(RfSwitchState::RX);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
|
const uint8_t data[] = {
|
||||||
|
static_cast<uint8_t>((rx_period >> 16) & 0xFF),
|
||||||
|
static_cast<uint8_t>((rx_period >> 8) & 0xFF),
|
||||||
|
static_cast<uint8_t>(rx_period & 0xFF),
|
||||||
|
static_cast<uint8_t>((sleep_period >> 16) & 0xFF),
|
||||||
|
static_cast<uint8_t>((sleep_period >> 8) & 0xFF),
|
||||||
|
static_cast<uint8_t>(sleep_period & 0xFF),
|
||||||
|
};
|
||||||
|
return write_stream(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
expected<unit, error_code>
|
||||||
|
LLCC68::set_rx_duty_cycle_ms(uint32_t rx_period_ms, uint32_t sleep_period_ms) {
|
||||||
|
const auto rx_period = rx_duty_cycle_period_from_ms(rx_period_ms);
|
||||||
|
const auto sleep_period = rx_duty_cycle_period_from_ms(sleep_period_ms);
|
||||||
|
if (not rx_period or not sleep_period) {
|
||||||
|
return ue(-EINVAL);
|
||||||
|
}
|
||||||
|
return set_rx_duty_cycle(*rx_period, *sleep_period);
|
||||||
|
}
|
||||||
|
|
||||||
expected<unit, error_code> LLCC68::set_sleep(sleep_config_t config) {
|
expected<unit, error_code> LLCC68::set_sleep(sleep_config_t config) {
|
||||||
auto c = *reinterpret_cast<const uint8_t *>(&config);
|
auto c = *reinterpret_cast<const uint8_t *>(&config);
|
||||||
const uint8_t data[] = {c};
|
const uint8_t data[] = {c};
|
||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_SLEEP, data);
|
auto r = write_stream(RADIOLIB_SX126X_CMD_SET_SLEEP, data);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
|
return set_rf_switch_state(RfSwitchState::Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
expected<unit, error_code> LLCC68::set_tx_continuous_wave() {
|
expected<unit, error_code> LLCC68::set_tx_continuous_wave() {
|
||||||
auto dummy = std::span<uint8_t>{};
|
auto dummy = std::span<uint8_t>{};
|
||||||
// const uint8_t dummy[] = {RADIOLIB_SX126X_CMD_NOP};
|
// const uint8_t dummy[] = {RADIOLIB_SX126X_CMD_NOP};
|
||||||
|
auto r = set_rf_switch_state(RfSwitchState::TX);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, dummy);
|
return write_stream(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
expected<unit, error_code> LLCC68::set_tx_infinite_preamble() {
|
expected<unit, error_code> LLCC68::set_tx_infinite_preamble() {
|
||||||
auto dummy = std::span<uint8_t>{};
|
auto dummy = std::span<uint8_t>{};
|
||||||
// const uint8_t dummy[] = {RADIOLIB_SX126X_CMD_NOP};
|
// const uint8_t dummy[] = {RADIOLIB_SX126X_CMD_NOP};
|
||||||
|
auto r = set_rf_switch_state(RfSwitchState::TX);
|
||||||
|
APP_RADIO_RETURN_ERR(r);
|
||||||
return write_stream(RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE, dummy);
|
return write_stream(RADIOLIB_SX126X_CMD_SET_TX_INFINITE_PREAMBLE, dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1222,7 +1298,9 @@ expected<unit, error_code> LLCC68::hal_modem_init(lora_parameters_t params) {
|
|||||||
"modem_init::set_modulation_params");
|
"modem_init::set_modulation_params");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_lora_sync_word(params.sync_word),
|
APP_RADIO_RETURN_ERR_CTX(set_lora_sync_word(params.sync_word),
|
||||||
"modem_init::set_lora_sync_word");
|
"modem_init::set_lora_sync_word");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_dio2_as_rf_switch(false),
|
APP_RADIO_RETURN_ERR_CTX(set_dio2_as_rf_switch(
|
||||||
|
config().rf_switch_mode ==
|
||||||
|
LLCC68_RF_SWITCH_DIO2_SINGLE),
|
||||||
"modem_init::set_dio2_as_rf_switch");
|
"modem_init::set_dio2_as_rf_switch");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
||||||
"modem_init::set_rf_frequency");
|
"modem_init::set_rf_frequency");
|
||||||
@@ -1278,7 +1356,9 @@ LLCC68::hal_gfsk_modem_init(gfsk_parameters_t params) {
|
|||||||
params.broadcast_address.value_or(0)),
|
params.broadcast_address.value_or(0)),
|
||||||
"gfsk_init::set_address_filtering");
|
"gfsk_init::set_address_filtering");
|
||||||
}
|
}
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_dio2_as_rf_switch(false),
|
APP_RADIO_RETURN_ERR_CTX(set_dio2_as_rf_switch(
|
||||||
|
config().rf_switch_mode ==
|
||||||
|
LLCC68_RF_SWITCH_DIO2_SINGLE),
|
||||||
"gfsk_init::set_dio2_as_rf_switch");
|
"gfsk_init::set_dio2_as_rf_switch");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
||||||
"gfsk_init::set_rf_frequency");
|
"gfsk_init::set_rf_frequency");
|
||||||
@@ -1298,6 +1378,11 @@ LLCC68::hal_async_flush(lora_parameters_t params) {
|
|||||||
return ue(Errc::InvalidState);
|
return ue(Errc::InvalidState);
|
||||||
}
|
}
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_standby(), "tx::standby");
|
APP_RADIO_RETURN_ERR_CTX(set_standby(), "tx::standby");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_packet_type_lora(), "tx::set_packet_type");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_lora_sync_word(params.sync_word),
|
||||||
|
"tx::set_lora_sync_word");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
||||||
|
"tx::set_rf_frequency");
|
||||||
APP_RADIO_RETURN_ERR_CTX(
|
APP_RADIO_RETURN_ERR_CTX(
|
||||||
set_modulation_params(params.mod_params.sf, params.mod_params.bw,
|
set_modulation_params(params.mod_params.sf, params.mod_params.bw,
|
||||||
params.mod_params.cr,
|
params.mod_params.cr,
|
||||||
@@ -1330,7 +1415,8 @@ LLCC68::hal_async_flush(lora_parameters_t params) {
|
|||||||
"tx::set_dio_irq_params");
|
"tx::set_dio_irq_params");
|
||||||
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
||||||
"tx::clear_irq_status");
|
"tx::clear_irq_status");
|
||||||
tx_rx_en_pin_set(TxRxPinState::TX);
|
APP_RADIO_RETURN_ERR_CTX(set_rf_switch_state(RfSwitchState::TX),
|
||||||
|
"tx::set_rf_switch");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_tx(), "tx::set_tx_params");
|
APP_RADIO_RETURN_ERR_CTX(set_tx(), "tx::set_tx_params");
|
||||||
auto air = calc_time_on_air(
|
auto air = calc_time_on_air(
|
||||||
data().tx_xfer_size, params.mod_params.sf, params.mod_params.bw,
|
data().tx_xfer_size, params.mod_params.sf, params.mod_params.bw,
|
||||||
@@ -1358,10 +1444,35 @@ LLCC68::hal_gfsk_async_flush(gfsk_parameters_t params) {
|
|||||||
if (data().tx_xfer_size == 0 || data().tx_xfer_size > MAX_BUFFER_PAYLOAD) {
|
if (data().tx_xfer_size == 0 || data().tx_xfer_size > MAX_BUFFER_PAYLOAD) {
|
||||||
return ue(-EINVAL);
|
return ue(-EINVAL);
|
||||||
}
|
}
|
||||||
|
if (params.sync_word_length > params.sync_word.size() ||
|
||||||
|
params.packet_params.sync_length_bits > params.sync_word.size() * 8) {
|
||||||
|
return ue(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_standby(), "gfsk_tx::standby");
|
APP_RADIO_RETURN_ERR_CTX(set_standby(), "gfsk_tx::standby");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_packet_type_gfsk(),
|
||||||
|
"gfsk_tx::set_packet_type");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
||||||
|
"gfsk_tx::set_rf_frequency");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_gfsk_modulation_params(params.mod_params),
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_modulation_params(params.mod_params),
|
||||||
"gfsk_tx::set_modulation_params");
|
"gfsk_tx::set_modulation_params");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(
|
||||||
|
set_gfsk_sync_word(std::span<const uint8_t>{params.sync_word.data(),
|
||||||
|
params.sync_word_length}),
|
||||||
|
"gfsk_tx::set_sync_word");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_crc_seed(params.crc_seed),
|
||||||
|
"gfsk_tx::set_crc_seed");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_crc_polynomial(params.crc_polynomial),
|
||||||
|
"gfsk_tx::set_crc_polynomial");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_whitening_seed(params.whitening_seed),
|
||||||
|
"gfsk_tx::set_whitening_seed");
|
||||||
|
if (params.packet_params.address_filtering !=
|
||||||
|
GfskAddressFiltering::Disabled) {
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(
|
||||||
|
set_gfsk_address_filtering(params.node_address.value_or(0),
|
||||||
|
params.broadcast_address.value_or(0)),
|
||||||
|
"gfsk_tx::set_address_filtering");
|
||||||
|
}
|
||||||
auto packet_params = params.packet_params;
|
auto packet_params = params.packet_params;
|
||||||
packet_params.payload_length = static_cast<uint8_t>(data().tx_xfer_size);
|
packet_params.payload_length = static_cast<uint8_t>(data().tx_xfer_size);
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_gfsk_packet_params(packet_params),
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_packet_params(packet_params),
|
||||||
@@ -1387,7 +1498,8 @@ LLCC68::hal_gfsk_async_flush(gfsk_parameters_t params) {
|
|||||||
"gfsk_tx::set_dio_irq_params");
|
"gfsk_tx::set_dio_irq_params");
|
||||||
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
||||||
"gfsk_tx::clear_irq_status");
|
"gfsk_tx::clear_irq_status");
|
||||||
tx_rx_en_pin_set(TxRxPinState::TX);
|
APP_RADIO_RETURN_ERR_CTX(set_rf_switch_state(RfSwitchState::TX),
|
||||||
|
"gfsk_tx::set_rf_switch");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_tx(), "gfsk_tx::set_tx");
|
APP_RADIO_RETURN_ERR_CTX(set_tx(), "gfsk_tx::set_tx");
|
||||||
auto air_estimated =
|
auto air_estimated =
|
||||||
calc_gfsk_time_on_air(params, static_cast<uint8_t>(data().tx_xfer_size));
|
calc_gfsk_time_on_air(params, static_cast<uint8_t>(data().tx_xfer_size));
|
||||||
@@ -1404,6 +1516,11 @@ LLCC68::hal_gfsk_async_transmit(std::span<const uint8_t> data,
|
|||||||
|
|
||||||
expected<unit, error_code> LLCC68::hal_async_rx(lora_parameters_t params) {
|
expected<unit, error_code> LLCC68::hal_async_rx(lora_parameters_t params) {
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_standby(), "rx::standby");
|
APP_RADIO_RETURN_ERR_CTX(set_standby(), "rx::standby");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_packet_type_lora(), "rx::set_packet_type");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_lora_sync_word(params.sync_word),
|
||||||
|
"rx::set_lora_sync_word");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
||||||
|
"rx::set_rf_frequency");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_buffer_base_address(),
|
APP_RADIO_RETURN_ERR_CTX(set_buffer_base_address(),
|
||||||
"rx::set_buffer_base_address");
|
"rx::set_buffer_base_address");
|
||||||
|
|
||||||
@@ -1431,17 +1548,44 @@ expected<unit, error_code> LLCC68::hal_async_rx(lora_parameters_t params) {
|
|||||||
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
||||||
"rx::clear_irq_status");
|
"rx::clear_irq_status");
|
||||||
|
|
||||||
tx_rx_en_pin_set(TxRxPinState::RX);
|
APP_RADIO_RETURN_ERR_CTX(set_rf_switch_state(RfSwitchState::RX),
|
||||||
|
"rx::set_rf_switch");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_rx(), "rx::set_rx");
|
APP_RADIO_RETURN_ERR_CTX(set_rx(), "rx::set_rx");
|
||||||
return unit{};
|
return unit{};
|
||||||
}
|
}
|
||||||
|
|
||||||
expected<unit, error_code> LLCC68::hal_gfsk_async_rx(gfsk_parameters_t params) {
|
expected<unit, error_code> LLCC68::hal_gfsk_async_rx(gfsk_parameters_t params) {
|
||||||
|
if (params.sync_word_length > params.sync_word.size() ||
|
||||||
|
params.packet_params.sync_length_bits > params.sync_word.size() * 8) {
|
||||||
|
return ue(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_standby(), "gfsk_rx::standby");
|
APP_RADIO_RETURN_ERR_CTX(set_standby(), "gfsk_rx::standby");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_packet_type_gfsk(),
|
||||||
|
"gfsk_rx::set_packet_type");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_rf_frequency(params.frequency_mhz),
|
||||||
|
"gfsk_rx::set_rf_frequency");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_buffer_base_address(),
|
APP_RADIO_RETURN_ERR_CTX(set_buffer_base_address(),
|
||||||
"gfsk_rx::set_buffer_base_address");
|
"gfsk_rx::set_buffer_base_address");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_gfsk_modulation_params(params.mod_params),
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_modulation_params(params.mod_params),
|
||||||
"gfsk_rx::set_modulation_params");
|
"gfsk_rx::set_modulation_params");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(
|
||||||
|
set_gfsk_sync_word(std::span<const uint8_t>{params.sync_word.data(),
|
||||||
|
params.sync_word_length}),
|
||||||
|
"gfsk_rx::set_sync_word");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_crc_seed(params.crc_seed),
|
||||||
|
"gfsk_rx::set_crc_seed");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_crc_polynomial(params.crc_polynomial),
|
||||||
|
"gfsk_rx::set_crc_polynomial");
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_whitening_seed(params.whitening_seed),
|
||||||
|
"gfsk_rx::set_whitening_seed");
|
||||||
|
if (params.packet_params.address_filtering !=
|
||||||
|
GfskAddressFiltering::Disabled) {
|
||||||
|
APP_RADIO_RETURN_ERR_CTX(
|
||||||
|
set_gfsk_address_filtering(params.node_address.value_or(0),
|
||||||
|
params.broadcast_address.value_or(0)),
|
||||||
|
"gfsk_rx::set_address_filtering");
|
||||||
|
}
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_gfsk_packet_params(params.packet_params),
|
APP_RADIO_RETURN_ERR_CTX(set_gfsk_packet_params(params.packet_params),
|
||||||
"gfsk_rx::set_packet_params");
|
"gfsk_rx::set_packet_params");
|
||||||
|
|
||||||
@@ -1457,7 +1601,8 @@ expected<unit, error_code> LLCC68::hal_gfsk_async_rx(gfsk_parameters_t params) {
|
|||||||
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
APP_RADIO_RETURN_ERR_CTX(clear_irq_status(irq_params.irqMask),
|
||||||
"gfsk_rx::clear_irq_status");
|
"gfsk_rx::clear_irq_status");
|
||||||
|
|
||||||
tx_rx_en_pin_set(TxRxPinState::RX);
|
APP_RADIO_RETURN_ERR_CTX(set_rf_switch_state(RfSwitchState::RX),
|
||||||
|
"gfsk_rx::set_rf_switch");
|
||||||
APP_RADIO_RETURN_ERR_CTX(set_rx(), "gfsk_rx::set_rx");
|
APP_RADIO_RETURN_ERR_CTX(set_rx(), "gfsk_rx::set_rx");
|
||||||
return unit{};
|
return unit{};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user