# Bobcat Miner 300 Documentation below currently based on only observing the G295 model. LoRa interface: SPI over mPCIe Antenna connector: IPEX1 Software: [a Debian image exists](https://github.com/sicXnull/Bobcat300-Debian) '3/5 (101)' means gpiochip 3, line 5, which is 101 in the global pin count. Currently unclear which CS line is which of 3/1 and 3/2 | Bobcat Miner 300 | Spec label | Top side | Bottom side | Spec label | Bobcat Miner 300 | | ---------------------------------------- | ------------ | -------- | ----------- | ----------- | ---------------- | | 4/21 (149) | WAKE# | 1 | 2 | 3.3V | | | SCK 3/19 (115) | Reserved**** | 3 | 4 | GND | GND | | MISO 3/18 (114) | Reserved**** | 5 | 6 | 1.5V | MOSI 3/17 (113) | | CS (`spidev5.0`) on 3/1 (97) or 3/2 (98) | CLKREQ# | 7 | 8 | VCC** | | | GND | GND | 9 | 10 | I/O** | | | | REFCLK- | 11 | 12 | CLK** | | | | REFCLK+ | 13 | 14 | RST** | | | GND | N/C or GND | 15 | 16 | VPP** | | | | | key | key | | | | CS (`spidev5.1`) on 3/2 (98) or 3/1 (97) | Reserved | 17 | 18 | GND | GND | | 4/19 (147) | Reserved | 19 | 20 | Reserved*** | | | GND | GND | 21 | 22 | PERST# | 4/22 (150) | | 3/3 (99) | PERn0 | 23 | 24 | +3.3Vaux | | | | PERp0 | 25 | 26 | GND | GND | | GND | GND | 27 | 28 | +1.5V | | | GND | GND | 29 | 30 | SMB_CLK | 3/24 (120) | | | PETn0 | 31 | 32 | SMB_DATA | 3/23 (119) | | | PETp0 | 33 | 34 | GND | GND | | GND | GND | 35 | 36 | USB_D- | | | | Reserved* | 37 | 38 | USB_D+ | | | | Reserved* | 39 | 40 | GND | GND | | | Reserved* | 41 | 42 | LED_WWAN# | | | GND | Reserved* | 43 | 44 | LED_WLAN# | 3/22 (118) | | i2c SCL 4/23 (151) or 4/24 (152) | Reserved* | 45 | 46 | LED_WPAN# | 3/29 (125) | | i2c SDA 4/24 (152) or 4/23 (151) | Reserved* | 47 | 48 | +1.5V | | | | Reserved* | 49 | 50 | GND | GND | | | Reserved* | 51 | 52 | +3.3V | | ## hacky working pymc setup There is a `newradios` branch in pymc core & repeater that likely makes all of this possible without local patching (other than perhaps the board definition, in core, while repeater has configuration for that). The pinout chosen here may not be the best. Because the bobcat puts SPI on different pins than other boards seen so far, we need to figure out if routing SPI to two sets of pins can create a miniPCIe board that works for the bobcat -and- for other devices. <details> <summary>diff against pymc_core revision ba3ff4c26b9fadda1995c1ef6e21c7f143768c8d (main branch as of 12 Jan 2026)</summary> ```diff diff --git a/examples/common.py b/examples/common.py index 826b542..8e68faa 100644 --- a/examples/common.py +++ b/examples/common.py @@ -121,6 +121,23 @@ def create_radio(radio_type: str = "waveshare", serial_port: str = "/dev/ttyUSB0 "coding_rate": 5, "preamble_length": 17, }, + "wibra": { + "bus_id": 5, + "cs_id": 0, + "cs_pin": -1, + "reset_pin": 150 - 128, + "busy_pin": 147 - 128, + "irq_pin": 149 - 128, + "txen_pin": -1, + "frequency": int(869.618 * 1000000), # EU: 869.525 MHz, + "tx_power": 22, + "spreading_factor": 8, + "bandwidth": int(62.5 * 1000), + "coding_rate": 8, + "preamble_length": 17, + "use_dio3_tcxo": True + } + } if radio_type not in configs: diff --git a/examples/discover_nodes.py b/examples/discover_nodes.py index 097be79..2db003f 100644 --- a/examples/discover_nodes.py +++ b/examples/discover_nodes.py @@ -44,6 +44,11 @@ async def discover_nodes( """ mesh_node, identity = create_mesh_node("DiscoveryNode", radio_type, serial_port) + print(mesh_node.radio) + print(dir(mesh_node.radio)) + print(dir(mesh_node.radio.lora)) + print(''.join(map(chr, mesh_node.radio.lora.readRegister(0x320, 16)))) + # Dictionary to store discovered nodes discovered_nodes = {} @@ -149,7 +154,7 @@ def main(): parser = argparse.ArgumentParser(description="Discover nearby mesh nodes") parser.add_argument( "--radio-type", - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], + choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc", "wibra"], default="waveshare", help="Radio hardware type (default: waveshare)", ) diff --git a/src/pymc_core/hardware/gpio_manager.py b/src/pymc_core/hardware/gpio_manager.py index 399a5da..fa7f900 100644 --- a/src/pymc_core/hardware/gpio_manager.py +++ b/src/pymc_core/hardware/gpio_manager.py @@ -44,7 +44,7 @@ logger = logging.getLogger("GPIOPinManager") class GPIOPinManager: """Manages GPIO pins abstraction using Linux GPIO character device interface""" - def __init__(self, gpio_chip: str = "/dev/gpiochip0"): + def __init__(self, gpio_chip: str = "/dev/gpiochip4"): """ Initialize GPIO Pin Manager diff --git a/src/pymc_core/hardware/lora/LoRaRF/SX126x.py b/src/pymc_core/hardware/lora/LoRaRF/SX126x.py index 31bedd4..3a672ef 100644 --- a/src/pymc_core/hardware/lora/LoRaRF/SX126x.py +++ b/src/pymc_core/hardware/lora/LoRaRF/SX126x.py @@ -468,7 +468,7 @@ class SX126x(BaseLoRa): self._cs_define = 17 # Default to GPIO 17 (safe alternative) else: # Keep original hardcoded value for unknown buses - self._cs_define = 21 + self._cs_define = 1 # open spi line and set bus id, chip select, and spi speed spi.open(bus, cs) @@ -1484,6 +1484,7 @@ class SX126x(BaseLoRa): # Adaptive CS control based on CS pin type if self._cs_define != 8: # Manual CS pin (like Waveshare GPIO 21) # Simple CS control for manual pins + print("_cs_define", self._cs_define) _get_output(self._cs_define).write(False) buf = [opCode] for i in range(nBytes): ``` </details> pinout: * SPI (CLK/MOSI/MISO/CE) on minipcie pins 3, 6, 5, 7. * RST on 22 * BUSY on 19 * IRQ/DIO1 on 1 plus 3v3+GND from a wide choice of pins 
