Files
esp_llcc68_driver/inc/llcc68_definitions.hpp
2025-05-14 12:17:06 +08:00

392 lines
9.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// Created by Kurosu Chan on 2024/1/26.
//
#ifndef LLCC68_DEFINITIONS_H
#define LLCC68_DEFINITIONS_H
#include <cstddef>
#include <cstdint>
#include <tuple>
#include <variant>
#include "radiolib_definitions.hpp"
namespace app::driver::llcc68 {
using freq_t = float;
constexpr uint8_t DEFAULT_SYNC_WORD = RADIOLIB_SX126X_SYNC_WORD_PRIVATE;
constexpr uint16_t DEFAULT_PREAMBLE_LEN = 6; // recommended is 8 symbols though
constexpr uint8_t DEFAULT_CRC_TYPE = RADIOLIB_SX126X_LORA_CRC_OFF;
constexpr uint8_t DEFAULT_HEADER_TYPE = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT;
constexpr uint8_t DEFAULT_IQ_TYPE = RADIOLIB_SX126X_LORA_IQ_STANDARD;
constexpr uint8_t PACKET_TYPE = RADIOLIB_SX126X_PACKET_TYPE_LORA;
constexpr auto DEFAULT_BW = RADIOLIB_SX126X_LORA_BW_125_0;
constexpr auto DEFAULT_SF = 9;
constexpr auto DEFAULT_CR = RADIOLIB_SX126X_LORA_CR_4_6;
constexpr auto DEFAULT_LDR_OPTIMIZE = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
constexpr auto DEFAULT_FREQUENCY = freq_t{433.2};
enum class ChipType {
Unknown,
LLCC68,
SX1261,
SX1262,
};
inline const char *chip_type_str(const ChipType &chip) {
switch (chip) {
case ChipType::LLCC68:
return "LLCC68";
case ChipType::SX1261:
return "SX1261";
case ChipType::SX1262:
return "SX1262";
default:
return "Unknown";
}
}
/// @note suitable SX1262/LLCC68
enum class PaOptimalPresetHigh : uint8_t {
DBM_14,
DBM_17,
DBM_20,
DBM_22,
};
/// @note suitable SX1261
enum class PaOptimalPresetLow : uint8_t {
DBM_10,
DBM_14,
DBM_15,
};
using PaOptimalPreset = std::variant<PaOptimalPresetHigh, PaOptimalPresetLow>;
struct pa_config_t {
uint8_t pa_duty_cycle;
uint8_t hp_max;
uint8_t device_sel;
};
enum class PacketType : uint8_t {
FSK = RADIOLIB_SX126X_PACKET_TYPE_GFSK,
LORA = RADIOLIB_SX126X_PACKET_TYPE_LORA,
LR_FHSS = RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS,
};
enum class TcxoVoltage : uint8_t {
V_1_6 = 0x00,
V_1_7 = 0x01,
V_1_8 = 0x02,
V_2_2 = 0x03,
V_2_4 = 0x04,
V_2_7 = 0x05,
V_3_0 = 0x06,
V_3_3 = 0x07,
};
enum class CommandStatus : uint8_t {
RESERVED = 0x00, // 0b000
RFU = 0x01, // 0b001
DATA_AVAILABLE = 0x02, // 0b010
COMMAND_TIMEOUT = 0x03, // 0b011 i.e. TIMEOUT
COMMAND_PROCESSING_ERROR = 0x04, // 0b100 i.e. INVALID
FAILURE_TO_EXECUTE_COMMAND = 0x05, // 0b101 i.e. FAILED
COMMAND_TX_DONE = 0x06, // 0b110
};
enum class ChipMode : uint8_t {
UNUSED = 0x00, // 0b000
RFU = 0x01, // 0b001
STBY_RC = 0x02, // 0b010
STBY_XOSC = 0x03, // 0b011
FS = 0x04, // 0b100
RX = 0x05, // 0b101
TX = 0x06, // 0b110
};
struct __attribute__((packed)) status_t {
uint8_t reserved_1 : 1;
CommandStatus command_status : 3;
ChipMode chip_mode : 3;
uint8_t reserved_2 : 1;
};
static_assert(sizeof(status_t) == 1);
struct parameters_t {
uint8_t bw;
uint8_t sf;
uint8_t cr;
uint8_t ldr_optimize;
uint16_t preamble_len;
uint8_t sync_word;
freq_t frequency;
static parameters_t Default() {
return parameters_t{
.bw = DEFAULT_BW,
.sf = DEFAULT_SF,
.cr = DEFAULT_CR,
.ldr_optimize = DEFAULT_LDR_OPTIMIZE,
.preamble_len = DEFAULT_PREAMBLE_LEN,
.sync_word = DEFAULT_SYNC_WORD,
.frequency = DEFAULT_FREQUENCY,
};
}
constexpr static size_t size() {
return sizeof(parameters_t);
}
} __attribute__((packed));
struct __attribute__((packed)) lora_packet_status_t {
// Average over last packet received of RSSI
// Actual signal power is RssiPkt/2 (dBm)
uint8_t rssi_pkt;
// Estimation of SNR on last packet received in twos compliment format multiplied by 4.
// Actual SNR in dB =SnrPkt/4
uint8_t snr_pkt;
// Estimation of RSSI of the LoRa® signal (after despreading) on last packet received.
// Actual Rssi in dB = -SignalRssiPkt/2
uint8_t signal_rssi_pkt;
float rssi_pkt_dbm() const {
return -rssi_pkt / 2.0f;
}
float snr_pkt_db() const {
return snr_pkt / 4.0f;
}
float signal_rssi_pkt_dbm() const {
return -signal_rssi_pkt / 2.0f;
}
};
struct __attribute__((packed)) fsk_packet_status_t {
// bit 7: preamble err
// bit 6: sync err
// bit 5: adrs err
// bit 4: crc err
// bit 3: length err
// bit 2: abort err
// bit 1: pkt received
// bit 0: pkt sent
uint8_t rx_status;
// RSSI value latched upon the detection of the sync address.
// [negated, dBm, fixdt(0,8,1)]
// Actual signal power is RssiSync/2 (dBm)
uint8_t rssi_sync;
// RSSI average value over the payload of the received packet. Latched upon the pkt_done IRQ.
// [negated, dBm, fixdt(0,8,1)]
// Actual signal power is RssiAvg/2 (dBm)
uint8_t rssi_avg;
};
union packet_status_t {
uint8_t raw[3];
lora_packet_status_t lora;
fsk_packet_status_t fsk;
};
struct __attribute__((packed)) op_error_t {
bool RC64K_CALIB_ERR : 1; // RC64k calibration failed
bool RC13M_CALIB_ERR : 1; // RC13M calibration failed
bool PLL_CALIB_ERR : 1; // PLL calibration failed
bool ADC_CALIB_ERR : 1; // ADC calibration failed
bool IMG_CALIB_ERR : 1; // IMG calibration failed
bool XOSC_START_ERR : 1; // XOSC failed to start
bool PLL_LOCK_ERR : 1; // PLL failed to lock
uint8_t rfu_1 : 1; // RFU
bool PA_RAMP_ERR : 1; // PA ramping failed
uint8_t rfu_2 : 7; // RFU
};
static_assert(sizeof(op_error_t) == 2);
struct calc_time_on_air_t {
uint8_t bw;
uint8_t sf;
uint8_t cr;
uint16_t preamble_length;
static constexpr uint8_t ldro = DEFAULT_LDR_OPTIMIZE;
static constexpr uint8_t crc_type = DEFAULT_CRC_TYPE;
static constexpr uint8_t header_type = DEFAULT_HEADER_TYPE;
static constexpr uint8_t iq_type = DEFAULT_IQ_TYPE;
static constexpr uint8_t sync_word = DEFAULT_SYNC_WORD;
static calc_time_on_air_t from_parameters(const parameters_t &params) {
return calc_time_on_air_t{
.bw = params.bw,
.sf = params.sf,
.cr = params.cr,
.preamble_length = params.preamble_len};
}
};
constexpr bool in_range(const auto v, const auto min, const auto max) {
return v >= min && v <= max;
}
constexpr bool valid_cr(const uint8_t cr) {
switch (cr) {
case RADIOLIB_SX126X_LORA_CR_4_5:
case RADIOLIB_SX126X_LORA_CR_4_6:
case RADIOLIB_SX126X_LORA_CR_4_7:
case RADIOLIB_SX126X_LORA_CR_4_8:
return true;
default:
return false;
}
}
constexpr std::tuple<uint8_t, uint8_t>
cr_to_ratio(const uint8_t cr) {
switch (cr) {
case RADIOLIB_SX126X_LORA_CR_4_5:
return {4, 5};
case RADIOLIB_SX126X_LORA_CR_4_6:
return {4, 6};
case RADIOLIB_SX126X_LORA_CR_4_7:
return {4, 7};
case RADIOLIB_SX126X_LORA_CR_4_8:
return {4, 8};
default:
return {0, 1};
}
}
constexpr bool valid_ldr_optimize(const uint8_t ldr_optimize) {
if (ldr_optimize > RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON) {
return false;
}
return true;
}
constexpr bool valid_bw(const uint8_t bw) {
switch (bw) {
case RADIOLIB_SX126X_LORA_BW_7_8:
case RADIOLIB_SX126X_LORA_BW_10_4:
case RADIOLIB_SX126X_LORA_BW_15_6:
case RADIOLIB_SX126X_LORA_BW_20_8:
case RADIOLIB_SX126X_LORA_BW_31_25:
case RADIOLIB_SX126X_LORA_BW_41_7:
case RADIOLIB_SX126X_LORA_BW_62_5:
case RADIOLIB_SX126X_LORA_BW_125_0:
case RADIOLIB_SX126X_LORA_BW_250_0:
case RADIOLIB_SX126X_LORA_BW_500_0:
return true;
default:
return false;
}
}
using bw_t = float;
constexpr bw_t bw_khz(const uint8_t bw) {
switch (bw) {
case RADIOLIB_SX126X_LORA_BW_7_8:
return bw_t{7.8f};
case RADIOLIB_SX126X_LORA_BW_10_4:
return bw_t{10.4f};
case RADIOLIB_SX126X_LORA_BW_15_6:
return bw_t{15.6f};
case RADIOLIB_SX126X_LORA_BW_20_8:
return bw_t{20.8f};
case RADIOLIB_SX126X_LORA_BW_31_25:
return bw_t{31.25f};
case RADIOLIB_SX126X_LORA_BW_41_7:
return bw_t{41.7f};
case RADIOLIB_SX126X_LORA_BW_62_5:
return bw_t{62.5f};
case RADIOLIB_SX126X_LORA_BW_125_0:
return bw_t{125.0f};
case RADIOLIB_SX126X_LORA_BW_250_0:
return bw_t{250.0f};
case RADIOLIB_SX126X_LORA_BW_500_0:
return bw_t{500.0f};
default:
return bw_t{0};
}
}
constexpr bool valid_sf(const uint8_t bw, const uint8_t sf) {
if (const bool ok = valid_bw(bw); not ok) {
return false;
}
switch (bw) {
case RADIOLIB_SX126X_LORA_BW_125_0:
return in_range(sf, 5, 9);
case RADIOLIB_SX126X_LORA_BW_250_0:
return in_range(sf, 5, 10);
case RADIOLIB_SX126X_LORA_BW_500_0:
return in_range(sf, 5, 11);
default:
return in_range(sf, 5, 12);
}
}
constexpr bool valid_freq(const freq_t freq) {
return in_range(freq, freq_t{150.0}, freq_t{960.0});
}
/**
* \brief check if the parameters are valid. if not, set them to default.
* \param params the parameters to check
* \return if the parameters are valid, and the modified parameters
*/
constexpr std::tuple<bool, parameters_t>
check_fix_params(parameters_t params) {
bool ok = true;
if (not valid_bw(params.bw)) {
params.bw = DEFAULT_BW;
ok = false;
}
if (not valid_sf(params.bw, params.sf)) {
params.sf = DEFAULT_SF;
ok = false;
}
if (not valid_cr(params.cr)) {
params.cr = DEFAULT_CR;
ok = false;
}
if (not valid_freq(params.frequency)) {
params.frequency = DEFAULT_FREQUENCY;
ok = false;
}
if (not valid_ldr_optimize(params.ldr_optimize)) {
params.ldr_optimize = DEFAULT_LDR_OPTIMIZE;
ok = false;
}
return {ok, params};
}
/**
* \brief only do the check
*/
constexpr bool check_params(const parameters_t &params) {
if (not valid_bw(params.bw)) {
return false;
}
if (not valid_sf(params.bw, params.sf)) {
return false;
}
if (not valid_cr(params.cr)) {
return false;
}
if (not valid_freq(params.frequency)) {
return false;
}
if (not valid_ldr_optimize(params.ldr_optimize)) {
return false;
}
return true;
}
}
#endif // LLCC68_DEFINITIONS_H