|
| 1 | +# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: MIT |
| 4 | + |
| 5 | +from .mbus import spi2 |
| 6 | + |
| 7 | +from machine import Pin, SPI |
| 8 | +from lora import SX1278 |
| 9 | +from lora import SX1276 |
| 10 | +from lora import RxPacket |
| 11 | +from micropython import const |
| 12 | + |
| 13 | + |
| 14 | +class LoraModule: |
| 15 | + """ |
| 16 | + note: |
| 17 | + cn: LoRa433_V1.1 模块是 M5Stack 堆叠模块系列的一部分,它是一个在 433MHz 频率下运行的 LoRa 通信模块,使用了 Ra-02 模块(SX1278 芯片)方案。 |
| 18 | + en: The LoRa433_V1.1 Module is part of the M5Stack stackable module series. It is a LoRa communication module that operates at a 433MHz frequency and utilizes the Ra-02 module (SX1278 chip) solution. |
| 19 | +
|
| 20 | + details: |
| 21 | + color: "#0FE6D7" |
| 22 | + link: https://docs.m5stack.com/en/module/Module-LoRa433_V1.1 |
| 23 | + image: https://static-cdn.m5stack.com/resource/docs/products/module/Module-LoRa433_V1.1/img-dac09b0a-7367-4ed9-9374-b604f646ec3b.webp |
| 24 | + category: Module |
| 25 | +
|
| 26 | + example: | |
| 27 | + from module import LoraModule |
| 28 | + lora = LoraModule() |
| 29 | + lora.send("Hello, LoRa!") |
| 30 | + print(lora.recv()) |
| 31 | +
|
| 32 | + """ |
| 33 | + |
| 34 | + """ |
| 35 | + constant: Select the LoRa frequency band. |
| 36 | + """ |
| 37 | + LORA_433 = const(1) |
| 38 | + LORA_868 = const(2) |
| 39 | + |
| 40 | + """ |
| 41 | + constant: Valid bandwidth |
| 42 | + """ |
| 43 | + BANDWIDTHS = ("7.8", "10.4", "15.6", "20.8", "31.25", "41.7", "62.5", "125", "250", "500") |
| 44 | + |
| 45 | + def __init__( |
| 46 | + self, |
| 47 | + pin_cs=0, |
| 48 | + pin_irq=35, |
| 49 | + pin_rst=25, |
| 50 | + freq_band=LORA_433, |
| 51 | + sf=8, |
| 52 | + bw: str = "500", |
| 53 | + coding_rate=8, |
| 54 | + preamble_len=12, |
| 55 | + output_power=0, |
| 56 | + ): |
| 57 | + """ |
| 58 | + note: Initialize the LoRa module. |
| 59 | +
|
| 60 | + params: |
| 61 | + pin_cs: |
| 62 | + note: Chip select pin |
| 63 | + pin_irq: |
| 64 | + note: Interrupt pin |
| 65 | + pin_rst: |
| 66 | + note: Reset pin |
| 67 | + freq_band: |
| 68 | + field: dropdown |
| 69 | + note: LoRa RF frequency in kHz. |
| 70 | + options: |
| 71 | + 433M: LORA_433 |
| 72 | + 868M: LORA_868 |
| 73 | + sf: |
| 74 | + note: Spreading factor, Higher spreading factors allow reception of weaker signals but have slower data rate. |
| 75 | + bw: |
| 76 | + note: Bandwidth value in kHz. Must be exactly one of BANDWIDTHS |
| 77 | + coding_rate: |
| 78 | + note: Forward Error Correction (FEC) coding rate is expressed as a ratio, `4/N`. |
| 79 | + preamble_len: |
| 80 | + note: Length of the preamble sequence, in units of symbols. |
| 81 | + output_power: |
| 82 | + note: Output power in dBm. |
| 83 | + """ |
| 84 | + freq_khz = freq_band == self.LORA_433 and 433000 or 868000 |
| 85 | + sx_instance = freq_band == self.LORA_433 and SX1278 or SX1276 |
| 86 | + self._validate_range(sf, 6, 12) |
| 87 | + self._validate_range(coding_rate, 5, 8) |
| 88 | + |
| 89 | + if bw not in self.BANDWIDTHS: |
| 90 | + raise ValueError(f"Invalid bandwidth {bw}") |
| 91 | + |
| 92 | + lora_cfg = { |
| 93 | + "freq_khz": freq_khz, |
| 94 | + "sf": sf, |
| 95 | + "bw": bw, # kHz |
| 96 | + "coding_rate": coding_rate, |
| 97 | + "preamble_len": preamble_len, |
| 98 | + "output_power": output_power, # dBm |
| 99 | + } |
| 100 | + |
| 101 | + self.modem = sx_instance( |
| 102 | + spi=spi2, |
| 103 | + cs=Pin(pin_cs), |
| 104 | + dio0=Pin(pin_irq), |
| 105 | + # dio1=Pin(35), |
| 106 | + reset=Pin(pin_rst), |
| 107 | + lora_cfg=lora_cfg, |
| 108 | + ) |
| 109 | + |
| 110 | + def _validate_range(self, value, min, max): |
| 111 | + if value < min or value > max: |
| 112 | + raise ValueError(f"Value {value} out of range {min} to {max}") |
| 113 | + |
| 114 | + def send(self, packet, tx_at_ms=None) -> int: |
| 115 | + """ |
| 116 | + note: Send a data packet. |
| 117 | +
|
| 118 | + label: |
| 119 | + en: "%1 send packet %2 at time %3" |
| 120 | + cn: "%1 在 %3 时发送数据包 %2" |
| 121 | +
|
| 122 | + params: |
| 123 | + packet: |
| 124 | + note: The data packet to send. |
| 125 | + tx_at_ms: |
| 126 | + note: Time to transmit the packet in milliseconds. For precise timing of sent packets, there is an optional `tx_at_ms` argument which is a timestamp (as a `time.ticks_ms()` value). If set, the packet will be sent as close as possible to this timestamp and the function will block until that time arrives |
| 127 | +
|
| 128 | + return: |
| 129 | + note: The return value is the timestamp when transmission completed, as a`time.ticks_ms()` result. It will be more accurate if the modem was initialized to use interrupts. |
| 130 | + """ |
| 131 | + return self.modem.send(packet, tx_at_ms) |
| 132 | + |
| 133 | + def recv(self, timeout_ms=None, rx_length=0xFF, rx_packet: RxPacket = None) -> RxPacket: |
| 134 | + """ |
| 135 | +
|
| 136 | + note: Receive a data packet. |
| 137 | +
|
| 138 | + label: |
| 139 | + en: "%1 receive packet with timeout %2, rx_length %3, rx_packet %4" |
| 140 | + cn: "%1 接收数据包,超时 %2, 接收长度 %3, 接收数据包 %4" |
| 141 | +
|
| 142 | + params: |
| 143 | + timeout_ms: |
| 144 | + note: Optional, sets a receive timeout in milliseconds. If None (default value), then the function will block indefinitely until a packet is received. |
| 145 | + rx_length: |
| 146 | + note: Necessary to set if `implicit_header` is set to `True` (see above). This is the length of the packet to receive. Ignored in the default LoRa explicit header mode, where the received radio header includes the length. |
| 147 | + rx_packet: |
| 148 | + note: Optional, this can be an `RxPacket` object previously received from the modem. If the newly received packet has the same length, this object is reused and returned to save an allocation. If the newly received packet has a different length, a new `RxPacket` object is allocated and returned instead. |
| 149 | +
|
| 150 | + return: |
| 151 | + note: Returns None on timeout, or an `RxPacket` instance with the packet on success. |
| 152 | + """ |
| 153 | + return self.modem.recv(timeout_ms, rx_length, rx_packet) |
0 commit comments