diff --git a/docs/docs/examples.md b/docs/docs/examples.md index 9748475..4e3e1fa 100644 --- a/docs/docs/examples.md +++ b/docs/docs/examples.md @@ -23,7 +23,8 @@ All examples support multiple radio types via `--radio-type` argument: ### SX1262 Direct Radio - **waveshare**: Waveshare SX1262 HAT for Raspberry Pi - **uconsole**: ClockworkPi uConsole LoRa module -- **meshadv-mini**: MeshAdviser Mini board +- **meshav**: MeshAdviser Raspberry Pi HAT +- **meshadv-mini**: MeshAdviser Mini Raspberry Pi HAT ### KISS TNC - **kiss-tnc**: Serial KISS TNC devices (MeshTNC) @@ -34,7 +35,7 @@ All examples support multiple radio types via `--radio-type` argument: Creates radio instances for different hardware types: - **SX1262 Radios**: Direct hardware control via SPI/GPIO - **KISS TNC**: Serial protocol wrapper for TNC devices -- Supports waveshare, uconsole, meshadv-mini, and kiss-tnc types +- Supports waveshare, uconsole, meshadv, meshadv-mini, and kiss-tnc types ### `create_mesh_node(name, radio_type, serial_port)` Helper function that creates a mesh node setup: @@ -85,7 +86,7 @@ python examples/send_tracked_advert.py --help ``` **Arguments:** -- `--radio-type`: Choose hardware type (waveshare, uconsole, meshadv-mini, kiss-tnc) +- `--radio-type`: Choose hardware type (waveshare, uconsole, meshadv, meshadv-mini, kiss-tnc) - `--serial-port`: Serial port for KISS TNC (default: /dev/ttyUSB0) ### SX1262 Direct Radio Examples @@ -148,6 +149,14 @@ pyMC_Core supports both direct SX1262 radio control and KISS TNC devices: - **GPIO Pins**: CS=-1, Reset=25, Busy=24, IRQ=26 - **Additional Setup**: Requires SPI1 overlay and GPS/RTC configuration (see uConsole setup guide) +#### Frequency Labs meshadv +- **Hardware**: FrequencyLabs meshadv Hat +- **Platform**: Raspberry Pi (or compatible single-board computer) +- **Frequency**: 868MHz (EU) or 915MHz (US) +- **TX Power**: Up to 27dBm (Note: Actual tx power is [10dB higher than configured value](https://github.com/chrismyers2000/MeshAdv-Pi-Hat/issues/18)) +- **SPI Bus**: SPI0 +- **GPIO Pins**: CS=21, Reset=18, Busy=20, IRQ=16 + #### Frequency Labs meshadv-mini - **Hardware**: FrequencyLabs meshadv-mini Hat - **Platform**: Raspberry Pi (or compatible single-board computer) @@ -178,6 +187,16 @@ pyMC_Core supports both direct SX1262 radio control and KISS TNC devices: - TX Enable: Not used (-1) - RX Enable: Not used (-1) +#### meshadv (Frequency Labs) +- SPI Bus: 0 +- CS ID: 0 +- CS Pin: GPIO 21 +- Busy Pin: GPIO 20 +- Reset Pin: GPIO 18 +- IRQ Pin: GPIO 16 +- TX Enable: GPIO 13 +- RX Enable: GPIO 12 + #### meshadv-mini (Frequency Labs) - SPI Bus: 0 - CS ID: 0 @@ -320,6 +339,22 @@ All examples use the SX1262 LoRa radio with the following default settings: - **TX Enable**: Not used (-1) - **RX Enable**: Not used (-1) +#### meshadv (Frequency Labs) +- **Radio Type**: SX1262 direct hardware control +- **Frequency**: 869.525MHz (European standard) +- **TX Power**: 22dBm (Note: Actual tx power is [10dB higher than configured value](https://github.com/chrismyers2000/MeshAdv-Pi-Hat/issues/18)) +- **Spreading Factor**: 11 +- **Bandwidth**: 250kHz +- **Coding Rate**: 4/5 +- **Preamble Length**: 17 symbols +- **SPI Bus**: 0 +- **CS Pin**: GPIO 21 +- **Reset Pin**: GPIO 18 +- **Busy Pin**: GPIO 20 +- **IRQ Pin**: GPIO 16 +- **TX Enable**: GPIO 13 +- **RX Enable**: GPIO 12 + #### meshadv-mini (Frequency Labs) - **Radio Type**: SX1262 direct hardware control - **Frequency**: 869.525MHz (European standard) diff --git a/docs/docs/node.md b/docs/docs/node.md index cc1dc38..7950a7f 100644 --- a/docs/docs/node.md +++ b/docs/docs/node.md @@ -149,7 +149,7 @@ The meshadv and meshadv-mini are available from FrequencyLabs, and are open sour 2. Ensure SPI interface is enabled in Raspberry Pi configuration 3. Install required GPIO library: `sudo apt install python3-rpi.lgpio` -**Pin Configuration (Raspberry Pi):** +** meshadv-mini Pin Configuration (Raspberry Pi):** - SPI Bus: SPI0 (MOSI, MISO, SCLK pins) - CS: GPIO 21 - Reset: GPIO 18 @@ -204,22 +204,22 @@ radio.begin() ### Radio Configuration Parameters -| Parameter | Description | Waveshare HAT | meshadv-mini | uConsole | -|--------------------|----------------------------------|----------------|----------------|----------------| -| `bus_id` | SPI bus ID | 0 | 0 | 1 | -| `cs_id` | SPI chip select ID | 0 | 0 | 0 | -| `cs_pin` | Chip select GPIO pin | 21 | 8 | -1 | -| `reset_pin` | Reset GPIO pin | 18 | 24 | 25 | -| `busy_pin` | Busy GPIO pin | 20 | 20 | 24 | -| `irq_pin` | Interrupt GPIO pin | 16 | 16 | 26 | -| `txen_pin` | TX enable GPIO pin | 6 | -1 | -1 | -| `rxen_pin` | RX enable GPIO pin | -1 | 12 | -1 | -| `frequency` | Operating frequency in Hz | 869525000 (EU) | 910525000 (US) | 869525000 (EU) | -| `tx_power` | Transmit power in dBm | 22 | 22 | 22 | -| `spreading_factor` | LoRa spreading factor (7-12) | 11 | 7 | 11 | -| `bandwidth` | Bandwidth in Hz | 250000 | 62500 | 250000 | -| `coding_rate` | Coding rate (5=4/5, 6=4/6, etc.) | 5 | 5 | 5 | -| `preamble_length` | Preamble length | 17 | 17 | 17 | +| Parameter | Description | Waveshare HAT | meshadv | meshadv-mini | uConsole | +|--------------------|----------------------------------|----------------|----------------|----------------|----------------| +| `bus_id` | SPI bus ID | 0 | 0 | 0 | 1 | +| `cs_id` | SPI chip select ID | 0 | 0 | 0 | 0 | +| `cs_pin` | Chip select GPIO pin | 21 | 21 | 8 | -1 | +| `reset_pin` | Reset GPIO pin | 18 | 18 | 24 | 25 | +| `busy_pin` | Busy GPIO pin | 20 | 20 | 20 | 24 | +| `irq_pin` | Interrupt GPIO pin | 16 | 16 | 16 | 26 | +| `txen_pin` | TX enable GPIO pin | 6 | 13 | -1 | -1 | +| `rxen_pin` | RX enable GPIO pin | -1 | 12 | 12 | -1 | +| `frequency` | Operating frequency in Hz | 869525000 (EU) | 910525000 (US) | 910525000 (US) | 869525000 (EU) | +| `tx_power` | Transmit power in dBm | 22 | 22 | 22 | 22 | +| `spreading_factor` | LoRa spreading factor (7-12) | 11 | 7 | 7 | 11 | +| `bandwidth` | Bandwidth in Hz | 250000 | 62500 | 62500 | 250000 | +| `coding_rate` | Coding rate (5=4/5, 6=4/6, etc.) | 5 | 5 | 5 | 5 | +| `preamble_length` | Preamble length | 17 | 17 | 17 | 17 | **Note:** Adjust the `frequency` parameter based on your regional LoRa regulations (868MHz for EU, 915MHz for US, 433MHz for Asia). diff --git a/examples/common.py b/examples/common.py index 826b542..02bf5ca 100644 --- a/examples/common.py +++ b/examples/common.py @@ -24,6 +24,80 @@ from pymc_core.hardware.base import LoRaRadio from pymc_core.node.node import MeshNode +# Radio configurations for different hardware +RADIOS = { + "waveshare": { + "bus_id": 0, + "cs_id": 0, + "cs_pin": 21, # Waveshare HAT CS pin + "reset_pin": 18, + "busy_pin": 20, + "irq_pin": 16, + "txen_pin": 13, # GPIO 13 for TX enable + "rxen_pin": 12, + "frequency": int(869.618 * 1000000), # EU: 869.618 MHz + "tx_power": 22, + "spreading_factor": 8, + "bandwidth": int(62.5 * 1000), + "coding_rate": 8, + "preamble_length": 17, + "is_waveshare": True, + }, + "uconsole": { + "bus_id": 1, # SPI1 + "cs_id": 0, + "cs_pin": -1, # Use hardware CS + "reset_pin": 25, + "busy_pin": 24, + "irq_pin": 26, + "txen_pin": -1, + "rxen_pin": -1, + "frequency": int(869.525 * 1000000), # EU: 869.525 MHz + "tx_power": 22, + "spreading_factor": 11, + "bandwidth": int(250 * 1000), + "coding_rate": 5, + "preamble_length": 17, + }, + "meshadv": { + "bus_id": 0, + "cs_id": 0, + "cs_pin": 21, + "reset_pin": 18, + "busy_pin": 20, + "irq_pin": 16, + "txen_pin": 13, + "rxen_pin": 12, + "use_dio3_tcxo": True, + "frequency": int(910.525 * 1000000), # US: 910.525 MHz + "tx_power": 12, # real meshadv power is 10dB higher, see https://github.com/chrismyers2000/MeshAdv-Pi-Hat/issues/18 + "spreading_factor": 7, + "bandwidth": int(62.5 * 1000), + "coding_rate": 5, + "preamble_length": 17, + }, + "meshadv-mini": { + "bus_id": 0, + "cs_id": 0, + "cs_pin": 8, + "reset_pin": 24, + "busy_pin": 20, + "irq_pin": 16, + "txen_pin": -1, + "rxen_pin": 12, + "frequency": int(910.525 * 1000000), # US: 910.525 MHz + "tx_power": 22, + "spreading_factor": 7, + "bandwidth": int(62.5 * 1000), + "coding_rate": 5, + "preamble_length": 17, + }, +} + + +def get_supported_radios(): + return list(RADIOS.keys()) + ["kiss-tnc"] + def create_radio(radio_type: str = "waveshare", serial_port: str = "/dev/ttyUSB0") -> LoRaRadio: """Create a radio instance with configuration for specified hardware. @@ -70,63 +144,8 @@ def create_radio(radio_type: str = "waveshare", serial_port: str = "/dev/ttyUSB0 logger.debug("Imported SX1262Radio successfully") - # Radio configurations for different hardware - configs = { - "waveshare": { - "bus_id": 0, - "cs_id": 0, - "cs_pin": 21, # Waveshare HAT CS pin - "reset_pin": 18, - "busy_pin": 20, - "irq_pin": 16, - "txen_pin": 13, # GPIO 13 for TX enable - "rxen_pin": 12, - "frequency": int(869.618 * 1000000), # EU: 869.618 MHz - "tx_power": 22, - "spreading_factor": 8, - "bandwidth": int(62.5 * 1000), - "coding_rate": 8, - "preamble_length": 17, - "is_waveshare": True, - }, - "uconsole": { - "bus_id": 1, # SPI1 - "cs_id": 0, - "cs_pin": -1, # Use hardware CS - "reset_pin": 25, - "busy_pin": 24, - "irq_pin": 26, - "txen_pin": -1, - "rxen_pin": -1, - "frequency": int(869.525 * 1000000), # EU: 869.525 MHz - "tx_power": 22, - "spreading_factor": 11, - "bandwidth": int(250 * 1000), - "coding_rate": 5, - "preamble_length": 17, - }, - "meshadv-mini": { - "bus_id": 0, - "cs_id": 0, - "cs_pin": 8, - "reset_pin": 24, - "busy_pin": 20, - "irq_pin": 16, - "txen_pin": -1, - "rxen_pin": 12, - "frequency": int(910.525 * 1000000), # US: 910.525 MHz - "tx_power": 22, - "spreading_factor": 7, - "bandwidth": int(62.5 * 1000), - "coding_rate": 5, - "preamble_length": 17, - }, - } - - if radio_type not in configs: - raise ValueError( - f"Unknown radio type: {radio_type}. Use 'waveshare', 'meshadv-mini', 'uconsole', or 'kiss-tnc'" - ) + if radio_type not in RADIOS: + raise ValueError(f"Unknown radio type: {radio_type}. Use f{get_supported_radios()}") radio_kwargs = configs[radio_type] logger.debug(f"Radio configuration for {radio_type}: {radio_kwargs}") @@ -153,7 +172,7 @@ def create_mesh_node( Args: node_name: Name for the mesh node - radio_type: Type of radio hardware ("waveshare", "uconsole", "meshadv-mini", or "kiss-tnc") + radio_type: Type of radio hardware ("waveshare", "uconsole", "meshadv", "meshadv-mini", or "kiss-tnc") serial_port: Serial port for KISS TNC (only used with "kiss-tnc" type) Returns: diff --git a/examples/discover_nodes.py b/examples/discover_nodes.py index 097be79..a1ed495 100644 --- a/examples/discover_nodes.py +++ b/examples/discover_nodes.py @@ -19,7 +19,7 @@ import random import time -from common import create_mesh_node +from common import create_mesh_node, get_supported_radios from pymc_core.protocol.packet_builder import PacketBuilder @@ -149,7 +149,7 @@ def main(): parser = argparse.ArgumentParser(description="Discover nearby mesh nodes") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) @@ -177,9 +177,7 @@ def main(): if args.radio_type == "kiss-tnc": print(f"Serial port: {args.serial_port}") - asyncio.run( - discover_nodes(args.radio_type, args.serial_port, args.timeout, args.filter) - ) + asyncio.run(discover_nodes(args.radio_type, args.serial_port, args.timeout, args.filter)) if __name__ == "__main__": diff --git a/examples/login_server.py b/examples/login_server.py index f3dbb61..37d8443 100644 --- a/examples/login_server.py +++ b/examples/login_server.py @@ -21,7 +21,7 @@ import time from typing import Dict, Optional -from common import create_mesh_node +from common import create_mesh_node, get_supported_radios from pymc_core.node.handlers.login_server import LoginServerHandler from pymc_core.protocol import Identity, LocalIdentity @@ -381,7 +381,7 @@ def main(): ) parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/ping_repeater_trace.py b/examples/ping_repeater_trace.py index 340864f..2b70c7b 100644 --- a/examples/ping_repeater_trace.py +++ b/examples/ping_repeater_trace.py @@ -17,7 +17,7 @@ import asyncio import random -from common import create_mesh_node, print_packet_info +from common import create_mesh_node, get_supported_radios, print_packet_info from pymc_core.protocol.constants import PAYLOAD_TYPE_TRACE from pymc_core.protocol.packet_builder import PacketBuilder @@ -86,7 +86,7 @@ def main(): parser = argparse.ArgumentParser(description="Ping a repeater using trace packets") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/respond_to_discovery.py b/examples/respond_to_discovery.py index bf8fb93..fdbbadd 100644 --- a/examples/respond_to_discovery.py +++ b/examples/respond_to_discovery.py @@ -10,7 +10,7 @@ import asyncio -from common import create_mesh_node +from common import create_mesh_node, get_supported_radios from pymc_core.protocol.packet_builder import PacketBuilder @@ -121,7 +121,7 @@ def main(): parser = argparse.ArgumentParser(description="Respond to mesh node discovery requests") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/send_channel_message.py b/examples/send_channel_message.py index 0280506..29ee59c 100644 --- a/examples/send_channel_message.py +++ b/examples/send_channel_message.py @@ -8,7 +8,7 @@ import asyncio -from common import create_mesh_node, print_packet_info +from common import create_mesh_node, get_supported_radios, print_packet_info from pymc_core.protocol import Packet from pymc_core.protocol.packet_builder import PacketBuilder @@ -71,7 +71,7 @@ def main(): parser = argparse.ArgumentParser(description="Send a channel message to the Public channel") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/send_direct_advert.py b/examples/send_direct_advert.py index 2953fc0..f5d4da4 100644 --- a/examples/send_direct_advert.py +++ b/examples/send_direct_advert.py @@ -10,7 +10,7 @@ import asyncio -from common import create_mesh_node, print_packet_info +from common import create_mesh_node, get_supported_radios, print_packet_info from pymc_core.protocol.constants import ADVERT_FLAG_IS_CHAT_NODE from pymc_core.protocol.packet_builder import PacketBuilder @@ -51,7 +51,7 @@ def main(): parser = argparse.ArgumentParser(description="Send a direct advertisement packet") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/send_flood_advert.py b/examples/send_flood_advert.py index d6288ef..6c83ad6 100644 --- a/examples/send_flood_advert.py +++ b/examples/send_flood_advert.py @@ -17,7 +17,7 @@ import asyncio import sys -from common import create_mesh_node, print_packet_info +from common import create_mesh_node, get_supported_radios, print_packet_info from pymc_core.protocol.constants import ADVERT_FLAG_IS_CHAT_NODE from pymc_core.protocol.packet_builder import PacketBuilder @@ -58,7 +58,7 @@ def main(): parser = argparse.ArgumentParser(description="Send a flood advertisement packet") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/send_text_message.py b/examples/send_text_message.py index 01bfcf1..4d1e0a4 100644 --- a/examples/send_text_message.py +++ b/examples/send_text_message.py @@ -8,7 +8,7 @@ import asyncio -from common import create_mesh_node, print_packet_info +from common import create_mesh_node, get_supported_radios, print_packet_info from pymc_core.protocol import Packet from pymc_core.protocol.packet_builder import PacketBuilder @@ -78,7 +78,7 @@ def main(): parser = argparse.ArgumentParser(description="Send a text message to the mesh network") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/send_tracked_advert.py b/examples/send_tracked_advert.py index d7c6591..06952c5 100644 --- a/examples/send_tracked_advert.py +++ b/examples/send_tracked_advert.py @@ -12,7 +12,7 @@ import asyncio import time -from common import create_mesh_node, print_packet_info +from common import create_mesh_node, get_supported_radios, print_packet_info from pymc_core.protocol.constants import ( ADVERT_FLAG_HAS_LOCATION, @@ -93,7 +93,7 @@ def main(): parser = argparse.ArgumentParser(description="Send a location-tracked advertisement") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=get_supported_radios(), default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/examples/wireshark_stream.py b/examples/wireshark_stream.py index f0ff3f8..4fcefc1 100644 --- a/examples/wireshark_stream.py +++ b/examples/wireshark_stream.py @@ -5,7 +5,7 @@ import struct import time -from common import create_mesh_node +from common import create_mesh_node, get_supported_radios LINKTYPE_USER0 = 147