From 41b4aed456607fba8e38c703624419a705bfebed Mon Sep 17 00:00:00 2001 From: crosstyan Date: Tue, 19 May 2026 12:20:49 +0800 Subject: [PATCH] feat: add shared GMSK radio profile helpers Add a fixed 6-byte 100 kbps GMSK profile matching the health-band telemetry packet, plus FSK packet-status helpers for RSSI and error checks. Expose instantaneous RSSI reads for CCA and image calibration for 430-440 MHz GFSK bring-up. --- include/llcc68.hpp | 2 ++ include/llcc68_definitions.hpp | 54 ++++++++++++++++++++++++++++++++++ src/llcc68.cpp | 17 +++++++++++ 3 files changed, 73 insertions(+) diff --git a/include/llcc68.hpp b/include/llcc68.hpp index bf25676..2397def 100644 --- a/include/llcc68.hpp +++ b/include/llcc68.hpp @@ -125,6 +125,7 @@ struct LLCC68 { expected get_status(); expected get_packet_status(); + expected get_rssi_inst_x2_neg(); expected reset(); expected set_standby(); expected hal_get_chip_type(); @@ -164,6 +165,7 @@ struct LLCC68 { expected set_gfsk_crc_seed(uint16_t seed); expected set_gfsk_crc_polynomial(uint16_t polynomial); expected set_gfsk_whitening_seed(uint16_t seed); + expected calibrate_image(uint8_t freq1, uint8_t freq2); expected set_tx_params(tx_params_t params); expected set_tx_params(int8_t pwr, LoRaTxRampTime ramp_time); diff --git a/include/llcc68_definitions.hpp b/include/llcc68_definitions.hpp index 5cf534d..fd95a96 100644 --- a/include/llcc68_definitions.hpp +++ b/include/llcc68_definitions.hpp @@ -476,6 +476,40 @@ struct gfsk_parameters_t { .broadcast_address = std::nullopt, }; } + + static constexpr gfsk_parameters_t + Gmsk100kFixed6(freq_t frequency_mhz = 433.45, + tx_params_t tx_params = tx_params_t::Default()) { + return { + .mod_params = + { + .bitrate_bps = 100'000, + .frequency_deviation_hz = 25'000, + .pulse_shape = GfskPulseShape::Gauss05, + .rx_bandwidth = GfskRxBandwidth::Bw187200, + }, + .packet_params = + { + .preamble_bits = 32, + .detector_length = GfskPreambleDetector::Bits16, + .sync_length_bits = 32, + .address_filtering = GfskAddressFiltering::Disabled, + .packet_length_mode = GfskPacketLengthMode::Fixed, + .payload_length = 6, + .crc_type = GfskCrcType::Off, + .whitening = GfskWhitening::On, + }, + .tx_params = tx_params, + .frequency_mhz = frequency_mhz, + .sync_word = {0x2D, 0xD4, 0xA1, 0x7E, 0, 0, 0, 0}, + .sync_word_length = 4, + .crc_seed = 0x1D0F, + .crc_polynomial = 0x1021, + .whitening_seed = 0x0100, + .node_address = std::nullopt, + .broadcast_address = std::nullopt, + }; + } void log(const char *tag) const; }; @@ -656,6 +690,26 @@ struct __attribute__((packed)) fsk_packet_status_t { // the pkt_done IRQ. [negated, dBm, fixdt(0,8,1)] Actual signal power is // –RssiAvg/2 (dBm) uint8_t rssi_avg; + + [[nodiscard]] + bool has_error() const { + return (rx_status & 0b11111100U) != 0; + } + + [[nodiscard]] + bool packet_received() const { + return (rx_status & 0b00000010U) != 0; + } + + [[nodiscard]] + auto rssi_sync_dbm() const -> float { + return -static_cast(rssi_sync) / 2.0F; + } + + [[nodiscard]] + auto rssi_avg_dbm() const -> float { + return -static_cast(rssi_avg) / 2.0F; + } }; union packet_status_t { diff --git a/src/llcc68.cpp b/src/llcc68.cpp index 13e0e4f..378cd27 100644 --- a/src/llcc68.cpp +++ b/src/llcc68.cpp @@ -569,6 +569,14 @@ expected LLCC68::get_packet_status() { return ps; } +expected LLCC68::get_rssi_inst_x2_neg() { + uint8_t raw = 0; + auto r = read_stream(RADIOLIB_SX126X_CMD_GET_RSSI_INST, + std::span{&raw, 1}); + APP_RADIO_RETURN_ERR_IGNORE_PROC_ERR(r); + return raw; +} + expected LLCC68::reset() { // Drive RESET low-high with delays per datasheet, then poll standby if (not device_is_ready(config().reset_gpio.port)) { @@ -899,6 +907,12 @@ expected LLCC68::set_gfsk_whitening_seed(uint16_t seed) { std::span{&lsb, 1}); } +expected LLCC68::calibrate_image(uint8_t freq1, + uint8_t freq2) { + const uint8_t data[] = {freq1, freq2}; + return write_stream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data); +} + expected LLCC68::fix_inverted_iq(uint8_t iq_config) { uint8_t iqCfg = 0; auto r = read_register(RADIOLIB_SX126X_REG_IQ_CONFIG, @@ -1202,6 +1216,9 @@ LLCC68::hal_gfsk_modem_init(gfsk_parameters_t params) { APP_RADIO_RETURN_ERR_CTX(set_packet_type_gfsk(), "gfsk_init::set_packet_type"); + APP_RADIO_RETURN_ERR_CTX(calibrate_image(RADIOLIB_SX126X_CAL_IMG_430_MHZ_1, + RADIOLIB_SX126X_CAL_IMG_430_MHZ_2), + "gfsk_init::calibrate_image"); APP_RADIO_RETURN_ERR_CTX(set_gfsk_modulation_params(params.mod_params), "gfsk_init::set_modulation_params"); APP_RADIO_RETURN_ERR_CTX(