|
|
@@ -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,7 +169,7 @@ 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
|
|
|
|
|
|
|
|
|
|
|
|
expected<unit, error_code> LLCC68::set_rf_switch_state(RfSwitchState state) {
|
|
|
|
expected<unit, error_code> LLCC68::set_rf_switch_state(RfSwitchState state) {
|
|
|
@@ -186,6 +186,7 @@ expected<unit, error_code> LLCC68::set_rf_switch_state(RfSwitchState state) {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
switch (config().rf_switch_mode) {
|
|
|
|
switch (config().rf_switch_mode) {
|
|
|
|
|
|
|
|
case LLCC68_RF_SWITCH_DIO2_SINGLE:
|
|
|
|
case LLCC68_RF_SWITCH_NONE:
|
|
|
|
case LLCC68_RF_SWITCH_NONE:
|
|
|
|
return unit{};
|
|
|
|
return unit{};
|
|
|
|
case LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY: {
|
|
|
|
case LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY: {
|
|
|
@@ -205,10 +206,6 @@ expected<unit, error_code> LLCC68::set_rf_switch_state(RfSwitchState state) {
|
|
|
|
APP_RADIO_RETURN_ERR(r);
|
|
|
|
APP_RADIO_RETURN_ERR(r);
|
|
|
|
return set_gpio(*rx, state == RfSwitchState::RX ? 1 : 0);
|
|
|
|
return set_gpio(*rx, state == RfSwitchState::RX ? 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case LLCC68_RF_SWITCH_DIO2_SINGLE:
|
|
|
|
|
|
|
|
if (auto rx = rx_enable_gpio()) {
|
|
|
|
|
|
|
|
return set_gpio(*rx, 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return unit{};
|
|
|
|
return unit{};
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
return ue(-EINVAL);
|
|
|
|
return ue(-EINVAL);
|
|
|
@@ -677,6 +674,10 @@ expected<unit, error_code> LLCC68::set_standby() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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";
|
|
|
@@ -687,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);
|
|
|
|
}
|
|
|
|
}
|
|
|
@@ -1369,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,
|
|
|
@@ -1430,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),
|
|
|
@@ -1477,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");
|
|
|
|
|
|
|
|
|
|
|
@@ -1511,11 +1555,37 @@ expected<unit, error_code> LLCC68::hal_async_rx(lora_parameters_t params) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
|
|
|
|