Skip to content

Commit 4e4c268

Browse files
authored
Merge pull request #7 from rightup/dev
Fix LDRO configuration and add automatic detection for SF8+ with narrow bandwidth
2 parents 2cf250e + aa32c6e commit 4e4c268

File tree

3 files changed

+39
-14
lines changed

3 files changed

+39
-14
lines changed

src/pymc_core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Clean, simple API for building mesh network applications.
44
"""
55

6-
__version__ = "1.0.1"
6+
__version__ = "1.0.2"
77

88
# Core mesh functionality
99
from .node.node import MeshNode

src/pymc_core/hardware/sx1262_wrapper.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def __init__(
195195

196196
logger.info(
197197
f"SX1262Radio configured: freq={frequency/1e6:.1f}MHz, "
198-
f"power={tx_power}dBm, sf={spreading_factor}, pre={preamble_length}"
198+
f"power={tx_power}dBm, sf={spreading_factor}, bw={bandwidth/1000:.1f}kHz, pre={preamble_length}"
199199
)
200200
# Register this instance as the active radio for IRQ callback access
201201
SX1262Radio._active_instance = self
@@ -315,7 +315,7 @@ def set_rx_callback(self, callback):
315315

316316
async def _rx_irq_background_task(self):
317317
"""Background task: waits for RX_DONE IRQ and processes received packets automatically."""
318-
logger.info("[RX] Starting RX IRQ background task")
318+
logger.debug("[RX] Starting RX IRQ background task")
319319
rx_check_count = 0
320320
last_preamble_time = 0
321321
preamble_timeout = 5.0 # 5 seconds timeout for incomplete preamble detection
@@ -456,14 +456,14 @@ async def _rx_irq_background_task(self):
456456
raw_rssi = self.lora.getRssiInst()
457457
if raw_rssi is not None:
458458
noise_floor_dbm = -(float(raw_rssi) / 2)
459-
logger.info(
459+
logger.debug(
460460
f"[RX Task] Status check #{rx_check_count}, "
461461
f"Noise: {noise_floor_dbm:.1f}dBm"
462462
)
463463
else:
464-
logger.info(f"[RX Task] Status check #{rx_check_count}")
464+
logger.debug(f"[RX Task] Status check #{rx_check_count}")
465465
except Exception:
466-
logger.info(f"[RX Task] Status check #{rx_check_count}")
466+
logger.debug(f"[RX Task] Status check #{rx_check_count}")
467467
else:
468468
await asyncio.sleep(0.1) # Longer delay when interrupts not set up
469469

@@ -484,7 +484,7 @@ def begin(self) -> bool:
484484
self.irq_pin = Button(self.irq_pin_number, pull_up=False)
485485
self.irq_pin.when_activated = self._handle_interrupt
486486
self._interrupt_setup = True
487-
logger.info(f"[RX] IRQ setup successful on pin {self.irq_pin_number}")
487+
logger.debug(f"[RX] IRQ setup successful on pin {self.irq_pin_number}")
488488
except Exception as e:
489489
logger.error(f"IRQ setup failed: {e}")
490490
raise RuntimeError(f"Failed to set up IRQ pin {self.irq_pin_number}: {e}")
@@ -525,7 +525,11 @@ def begin(self) -> bool:
525525

526526
self.lora.setBufferBaseAddress(0x00, 0x80) # TX=0x00, RX=0x80
527527

528-
self.lora.setLoRaModulation(self.spreading_factor, self.bandwidth, self.coding_rate)
528+
# Enable LDRO if symbol duration > 16ms (SF11/62.5kHz = 32.768ms)
529+
symbol_duration_ms = (2 ** self.spreading_factor) / (self.bandwidth / 1000)
530+
ldro = symbol_duration_ms > 16.0
531+
logger.info(f"LDRO {'enabled' if ldro else 'disabled'} (symbol duration: {symbol_duration_ms:.3f}ms)")
532+
self.lora.setLoRaModulation(self.spreading_factor, self.bandwidth, self.coding_rate, ldro)
529533

530534
self.lora.setLoRaPacket(
531535
self.lora.HEADER_EXPLICIT,
@@ -564,7 +568,11 @@ def begin(self) -> bool:
564568
self.lora.setTxParams(self.tx_power, self.lora.PA_RAMP_200U)
565569

566570
# Configure modulation and packet parameters
567-
self.lora.setLoRaModulation(self.spreading_factor, self.bandwidth, self.coding_rate)
571+
# Enable LDRO if symbol duration > 16ms (SF11/62.5kHz = 32.768ms)
572+
symbol_duration_ms = (2 ** self.spreading_factor) / (self.bandwidth / 1000)
573+
ldro = symbol_duration_ms > 16.0
574+
logger.info(f"LDRO {'enabled' if ldro else 'disabled'} (symbol duration: {symbol_duration_ms:.3f}ms)")
575+
self.lora.setLoRaModulation(self.spreading_factor, self.bandwidth, self.coding_rate, ldro)
568576
self.lora.setPacketParamsLoRa(
569577
self.preamble_length,
570578
self.lora.HEADER_EXPLICIT,
@@ -600,9 +608,9 @@ def begin(self) -> bool:
600608
return True
601609

602610
self._rx_irq_task = loop.create_task(self._rx_irq_background_task())
603-
logger.info("[RX] RX IRQ background task started")
611+
logger.debug("[RX] RX IRQ background task started")
604612
else:
605-
logger.info("[RX] RX IRQ background task already running")
613+
logger.debug("[RX] RX IRQ background task already running")
606614
except Exception as e:
607615
logger.warning(f"Failed to start RX IRQ background handler: {e}")
608616
return True
@@ -759,13 +767,13 @@ async def _execute_transmission(self, driver_timeout: int) -> bool:
759767

760768
async def _wait_for_transmission_complete(self, timeout_seconds: float) -> bool:
761769
"""Wait for transmission to complete using interrupts. Returns True if successful."""
762-
logger.info(f"[TX] Waiting for TX completion (timeout: {timeout_seconds}s)")
770+
logger.debug(f"[TX] Waiting for TX completion (timeout: {timeout_seconds}s)")
763771
start_time = time.time()
764772

765773
# IRQ setup is required
766774
try:
767775
await asyncio.wait_for(self._tx_done_event.wait(), timeout=timeout_seconds)
768-
logger.info("[TX] TX completion interrupt received!")
776+
logger.debug("[TX] TX completion interrupt received!")
769777
return True
770778
except asyncio.TimeoutError:
771779
logger.error("[TX] TX completion timeout - no interrupt received!")
@@ -918,6 +926,23 @@ def get_last_snr(self) -> float:
918926
"""Return last received SNR in dB"""
919927
return self.last_snr
920928

929+
def get_noise_floor(self) -> Optional[float]:
930+
"""
931+
Get current noise floor (instantaneous RSSI) in dBm.
932+
Returns None if radio is not initialized or if reading fails.
933+
"""
934+
if not self._initialized or self.lora is None:
935+
return None
936+
try:
937+
raw_rssi = self.lora.getRssiInst()
938+
if raw_rssi is not None:
939+
noise_floor_dbm = -(float(raw_rssi) / 2)
940+
return noise_floor_dbm
941+
return None
942+
except Exception as e:
943+
logger.debug(f"Failed to read noise floor: {e}")
944+
return None
945+
921946
def set_frequency(self, frequency: int) -> bool:
922947
"""Set operating frequency"""
923948

tests/test_basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
def test_version():
5-
assert __version__ == "1.0.1"
5+
assert __version__ == "1.0.2"
66

77

88
def test_import():

0 commit comments

Comments
 (0)