52 uint32_t bw_hz = 125000;
55 }
else if (cfg.bw == 0x06) {
58 return (1000000u << cfg.sf) / bw_hz;
69 return static_cast<uint32_t
>((
static_cast<uint64_t
>(freq_hz) << 25) /
74 const int sf = cfg.sf;
75 const uint32_t tsym_us = symbol_us(cfg);
76 const bool ldro = use_ldro(cfg);
78 int num = 8 * payload_len + 16 - 4 * sf + 8 + 20;
82 const int den = 4 * (ldro ? sf - 2 : sf);
83 const int blocks = (num + den - 1) / den;
84 const uint32_t quarters =
static_cast<uint32_t
>(4 * cfg.preamble + 17 + 32 +
85 4 * blocks * (cfg.cr + 4));
86 return quarters * tsym_us / 4;
90 if (!
bus_.wait_busy()) {
99 const uint8_t tx[5] = {kOpReadRegister,
static_cast<uint8_t
>(addr >> 8),
100 static_cast<uint8_t
>(addr), 0, 0};
114 tx[0] = kOpWriteRegister;
115 tx[1] =
static_cast<uint8_t
>(addr >> 8);
116 tx[2] =
static_cast<uint8_t
>(addr);
117 memcpy(tx + 3, data,
n);
118 return cmd(tx,
static_cast<uint16_t
>(3 +
n));
124 const uint8_t tx[7] = {kOpSetPacketParams,
125 static_cast<uint8_t
>(
cfg_.preamble >> 8),
126 static_cast<uint8_t
>(
cfg_.preamble),
131 return cmd(tx,
sizeof tx);
139 irq =
static_cast<uint16_t
>((
rx_[2] << 8) |
rx_[3]);
144 const uint8_t dc[7] = {
153 return cmd(dc,
sizeof dc);
163 const uint8_t rx_cont[4] = {
kOpSetRx, 0xFF, 0xFF, 0xFF};
164 return cmd(rx_cont,
sizeof rx_cont);
169 const uint8_t standby[2] = {kOpSetStandby, 0x00};
170 if (!
cmd(standby,
sizeof standby))
179 const uint8_t standby[2] = {kOpSetStandby, 0x00};
180 if (!
cmd(standby,
sizeof standby))
194 const uint8_t standby[2] = {kOpSetStandby, 0x00};
195 if (!
cmd(standby,
sizeof standby)) {
198 const uint8_t regulator[2] = {kOpSetRegulatorMode, 0x01};
199 if (!
cmd(regulator,
sizeof regulator)) {
202 const uint8_t tcxo[5] = {kOpSetDio3AsTcxoCtrl, kTcxo1V8,
203 static_cast<uint8_t
>(kTcxoDelaySteps >> 16),
204 static_cast<uint8_t
>(kTcxoDelaySteps >> 8),
205 static_cast<uint8_t
>(kTcxoDelaySteps)};
206 if (!
cmd(tcxo,
sizeof tcxo)) {
212 const uint8_t calibrate[2] = {kOpCalibrate, 0x7F};
213 const uint8_t clear_errors[3] = {kOpClearDeviceErrors, 0, 0};
214 if (!
cmd(calibrate,
sizeof calibrate) ||
215 !
cmd(clear_errors,
sizeof clear_errors)) {
218 const uint8_t rf_switch[2] = {kOpSetDio2AsRfSwitch, 0x01};
219 if (!
cmd(rf_switch,
sizeof rf_switch)) {
222 const uint8_t packet_type[2] = {kOpSetPacketType, 0x01};
223 if (!
cmd(packet_type,
sizeof packet_type)) {
227 const uint8_t freq[5] = {kOpSetRfFrequency,
static_cast<uint8_t
>(f >> 24),
228 static_cast<uint8_t
>(f >> 16),
229 static_cast<uint8_t
>(f >> 8),
230 static_cast<uint8_t
>(f)};
231 if (!
cmd(freq,
sizeof freq)) {
234 const uint8_t image[3] = {kOpCalibrateImage, 0xE1, 0xE9};
235 if (!
cmd(image,
sizeof image)) {
240 const uint8_t pa[5] = {kOpSetPaConfig, 0x04, 0x07, 0x00, 0x01};
241 if (!
cmd(pa,
sizeof pa)) {
244 const uint8_t tx_params[3] = {
245 kOpSetTxParams,
static_cast<uint8_t
>(
cfg_.power_dbm), kRamp200us};
246 if (!
cmd(tx_params,
sizeof tx_params)) {
249 const uint8_t base[3] = {kOpSetBufferBase, 0x00, 0x00};
250 if (!
cmd(base,
sizeof base)) {
253 const uint8_t modulation[5] = {
255 static_cast<uint8_t
>(use_ldro(
cfg_) ? 1 : 0)};
256 if (!
cmd(modulation,
sizeof modulation)) {
262 const uint8_t irq[9] = {kOpSetDioIrqParams,
263 static_cast<uint8_t
>(kIrqMask >> 8),
264 static_cast<uint8_t
>(kIrqMask),
265 static_cast<uint8_t
>(kIrqMask >> 8),
266 static_cast<uint8_t
>(kIrqMask),
271 if (!
cmd(irq,
sizeof irq)) {
279 clamp =
static_cast<uint8_t
>(clamp | 0x1E);
283 const uint8_t sync[2] = {
static_cast<uint8_t
>(
cfg_.sync_word >> 8),
284 static_cast<uint8_t
>(
cfg_.sync_word)};
288 const uint8_t
errors[4] = {kOpGetDeviceErrors, 0, 0, 0};
300 if (bytes ==
nullptr || len == 0) {
303 const uint8_t standby[2] = {kOpSetStandby, 0x00};
304 if (!
cmd(standby,
sizeof standby)) {
315 mod =
cfg_.bw == 0x06 ?
static_cast<uint8_t
>(mod & ~0x04)
316 :
static_cast<uint8_t
>(mod | 0x04);
317 tx_[0] = kOpWriteBuffer;
319 memcpy(
tx_ + 2, bytes, len);
322 const uint8_t clear[3] = {
324 static_cast<uint8_t
>((kIrqTxDone | kIrqTimeout) >> 8),
325 static_cast<uint8_t
>(kIrqTxDone | kIrqTimeout)};
328 const uint32_t steps = (2u * toa_us * 64u + 999u) / 1000u;
329 const uint8_t set_tx[4] = {kOpSetTx,
static_cast<uint8_t
>(steps >> 16),
330 static_cast<uint8_t
>(steps >> 8),
331 static_cast<uint8_t
>(steps)};
333 !
cmd(
tx_,
static_cast<uint16_t
>(2 + len)) ||
334 !
cmd(clear,
sizeof clear) || !
cmd(set_tx,
sizeof set_tx)) {
341 const uint32_t limit_ms = 2u * toa_us / 1000u + 50u;
343 for (uint32_t waited = 0;; ++waited) {
349 if (irq & kIrqTxDone) {
353 if (irq & kIrqTimeout) {
356 if (waited == limit_ms) {
361 cmd(clear,
sizeof clear);
static volatile uint32_t errors
bool read_register(uint16_t addr, uint8_t &value)
bool start_rx_continuous()
uint32_t duty_sleep_steps_
bool start_rx_duty_cycle(uint32_t rx_ms, uint32_t sleep_ms)
RadioStatus send(const uint8_t *bytes, uint8_t len)
bool irq_status(uint16_t &irq)
bool write_register(uint16_t addr, const uint8_t *data, uint8_t n)
bool cmd(const uint8_t *tx, uint16_t n)
bool set_packet_params(uint8_t payload_len)
*brief user defined string literal for JSON values *sa std::size_t n
constexpr uint8_t kOpSetRegulatorMode
constexpr uint8_t kOpWriteBuffer
constexpr uint8_t kTcxo1V8
constexpr uint8_t kOpSetPaConfig
constexpr uint8_t kOpReadRegister
constexpr uint8_t kOpSetPacketType
constexpr uint16_t kIrqTimeout
constexpr uint8_t kOpSetDioIrqParams
constexpr uint16_t kRegSyncWord
constexpr uint8_t kOpSetBufferBase
uint32_t symbol_us(const LoraConfig &cfg)
constexpr uint8_t kOpWriteRegister
constexpr uint8_t kOpSetDio2AsRfSwitch
constexpr uint8_t kOpCalibrate
constexpr uint16_t kRegTxModulation
constexpr uint8_t kOpGetDeviceErrors
constexpr uint8_t kRamp200us
constexpr uint8_t kOpSetStandby
bool use_ldro(const LoraConfig &cfg)
constexpr uint8_t kOpSetModulation
constexpr uint8_t kOpClearDeviceErrors
constexpr uint16_t kIrqTxDone
constexpr uint8_t kOpSetPacketParams
constexpr uint8_t kOpSetRxDutyCycle
constexpr uint8_t kOpCalibrateImage
constexpr uint8_t kOpSetTx
constexpr uint16_t kRegTxClamp
constexpr uint8_t kOpSetRfFrequency
constexpr uint8_t kOpSetTxParams
constexpr uint16_t kIrqMask
constexpr uint32_t kTcxoDelaySteps
constexpr uint8_t kOpSetDio3AsTcxoCtrl
constexpr uint8_t kOpGetIrqStatus
uint32_t lora_time_on_air_us(const LoraConfig &cfg, uint8_t payload_len)
uint32_t sx1262_frequency_word(uint32_t freq_hz)
constexpr uint8_t kOpClearIrqStatus
bool sx1262_status_ok(uint8_t status)
constexpr uint16_t kIrqRxDone
constexpr uint16_t kIrqHeaderErr
constexpr uint16_t kIrqCrcErr
constexpr uint8_t kOpSetRx