Blame
| 362e46 | Peter van Dijk | 2026-01-28 23:15:48 | 1 | # Bobcat Miner 300 |
| 2 | ||||
| 257e20 | Peter van Dijk | 2026-02-17 17:08:08 | 3 | Documentation below currently based on only observing the G295 model. |
| 4 | ||||
| 362e46 | Peter van Dijk | 2026-01-28 23:15:48 | 5 | LoRa interface: SPI over mPCIe |
| 6 | ||||
| 7 | Antenna connector: IPEX1 |
|||
| 8 | ||||
| 9 | Software: [a Debian image exists](https://github.com/sicXnull/Bobcat300-Debian) |
|||
| 257e20 | Peter van Dijk | 2026-02-17 17:08:08 | 10 | |
| e47e2c | Peter van Dijk | 2026-02-20 15:51:41 | 11 | '3/5 (101)' means gpiochip 3, line 5, which is 101 in the global pin count. |
| 257e20 | Peter van Dijk | 2026-02-17 17:08:08 | 12 | |
| 93c2b1 | Peter van Dijk | 2026-02-17 21:01:13 | 13 | Currently unclear which CS line is which of 3/1 and 3/2 |
| 257e20 | Peter van Dijk | 2026-02-17 17:08:08 | 14 | |
| e47e2c | Peter van Dijk | 2026-02-20 15:51:41 | 15 | | Bobcat Miner 300 | Spec label | Top side | Bottom side | Spec label | Bobcat Miner 300 | |
| 16 | | ---------------------------------------- | ------------ | -------- | ----------- | ----------- | ---------------- | |
|||
| 17 | | 4/21 (149) | WAKE# | 1 | 2 | 3.3V | | |
|||
| 18 | | SCK 3/19 (115) | Reserved**** | 3 | 4 | GND | GND | |
|||
| 19 | | MISO 3/18 (114) | Reserved**** | 5 | 6 | 1.5V | MOSI 3/17 (113) | |
|||
| 20 | | CS (`spidev5.0`) on 3/1 (97) or 3/2 (98) | CLKREQ# | 7 | 8 | VCC** | | |
|||
| 21 | | GND | GND | 9 | 10 | I/O** | | |
|||
| 22 | | | REFCLK- | 11 | 12 | CLK** | | |
|||
| 23 | | | REFCLK+ | 13 | 14 | RST** | | |
|||
| 24 | | GND | N/C or GND | 15 | 16 | VPP** | | |
|||
| 25 | | | | key | key | | | |
|||
| 26 | | CS (`spidev5.1`) on 3/2 (98) or 3/1 (97) | Reserved | 17 | 18 | GND | GND | |
|||
| 27 | | 4/19 (147) | Reserved | 19 | 20 | Reserved*** | | |
|||
| 28 | | GND | GND | 21 | 22 | PERST# | 4/22 (150) | |
|||
| 29 | | 3/3 (99) | PERn0 | 23 | 24 | +3.3Vaux | | |
|||
| 30 | | | PERp0 | 25 | 26 | GND | GND | |
|||
| 31 | | GND | GND | 27 | 28 | +1.5V | | |
|||
| 32 | | GND | GND | 29 | 30 | SMB_CLK | 3/24 (120) | |
|||
| 33 | | | PETn0 | 31 | 32 | SMB_DATA | 3/23 (119) | |
|||
| 34 | | | PETp0 | 33 | 34 | GND | GND | |
|||
| 35 | | GND | GND | 35 | 36 | USB_D- | | |
|||
| 36 | | | Reserved* | 37 | 38 | USB_D+ | | |
|||
| 37 | | | Reserved* | 39 | 40 | GND | GND | |
|||
| 38 | | | Reserved* | 41 | 42 | LED_WWAN# | | |
|||
| 39 | | GND | Reserved* | 43 | 44 | LED_WLAN# | 3/22 (118) | |
|||
| 40 | | i2c SCL 4/23 (151) or 4/24 (152) | Reserved* | 45 | 46 | LED_WPAN# | 3/29 (125) | |
|||
| 41 | | i2c SDA 4/24 (152) or 4/23 (151) | Reserved* | 47 | 48 | +1.5V | | |
|||
| 42 | | | Reserved* | 49 | 50 | GND | GND | |
|||
| 43 | | | Reserved* | 51 | 52 | +3.3V | | |
|||
| eb369c | Peter van Dijk | 2026-02-21 13:26:16 | 44 | |
| 45 | ## hacky working pymc setup |
|||
| 46 | ||||
| 47 | 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). |
|||
| 48 | ||||
| 49 | The pinout chosen here may not be the best. |
|||
| 50 | 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. |
|||
| 51 | ||||
| 52 | <details> |
|||
| 53 | <summary>diff against pymc_core revision ba3ff4c26b9fadda1995c1ef6e21c7f143768c8d (main branch as of 12 Jan 2026)</summary> |
|||
| 54 | ||||
| 55 | ```diff |
|||
| 56 | diff --git a/examples/common.py b/examples/common.py |
|||
| 57 | index 826b542..8e68faa 100644 |
|||
| 58 | --- a/examples/common.py |
|||
| 59 | +++ b/examples/common.py |
|||
| 60 | @@ -121,6 +121,23 @@ def create_radio(radio_type: str = "waveshare", serial_port: str = "/dev/ttyUSB0 |
|||
| 61 | "coding_rate": 5, |
|||
| 62 | "preamble_length": 17, |
|||
| 63 | }, |
|||
| 64 | + "wibra": { |
|||
| 65 | + "bus_id": 5, |
|||
| 66 | + "cs_id": 0, |
|||
| 67 | + "cs_pin": -1, |
|||
| 68 | + "reset_pin": 150 - 128, |
|||
| 69 | + "busy_pin": 147 - 128, |
|||
| 70 | + "irq_pin": 149 - 128, |
|||
| 71 | + "txen_pin": -1, |
|||
| 72 | + "frequency": int(869.618 * 1000000), # EU: 869.525 MHz, |
|||
| 73 | + "tx_power": 22, |
|||
| 74 | + "spreading_factor": 8, |
|||
| 75 | + "bandwidth": int(62.5 * 1000), |
|||
| 76 | + "coding_rate": 8, |
|||
| 77 | + "preamble_length": 17, |
|||
| 78 | + "use_dio3_tcxo": True |
|||
| 79 | + } |
|||
| 80 | + |
|||
| 81 | } |
|||
| 82 | ||||
| 83 | if radio_type not in configs: |
|||
| 84 | diff --git a/examples/discover_nodes.py b/examples/discover_nodes.py |
|||
| 85 | index 097be79..2db003f 100644 |
|||
| 86 | --- a/examples/discover_nodes.py |
|||
| 87 | +++ b/examples/discover_nodes.py |
|||
| 88 | @@ -44,6 +44,11 @@ async def discover_nodes( |
|||
| 89 | """ |
|||
| 90 | mesh_node, identity = create_mesh_node("DiscoveryNode", radio_type, serial_port) |
|||
| 91 | ||||
| 92 | + print(mesh_node.radio) |
|||
| 93 | + print(dir(mesh_node.radio)) |
|||
| 94 | + print(dir(mesh_node.radio.lora)) |
|||
| 95 | + print(''.join(map(chr, mesh_node.radio.lora.readRegister(0x320, 16)))) |
|||
| 96 | + |
|||
| 97 | # Dictionary to store discovered nodes |
|||
| 98 | discovered_nodes = {} |
|||
| 99 | ||||
| 100 | @@ -149,7 +154,7 @@ def main(): |
|||
| 101 | parser = argparse.ArgumentParser(description="Discover nearby mesh nodes") |
|||
| 102 | parser.add_argument( |
|||
| 103 | "--radio-type", |
|||
| 104 | - choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc"], |
|||
| 105 | + choices=["waveshare", "uconsole", "meshadv-mini", "kiss-tnc", "wibra"], |
|||
| 106 | default="waveshare", |
|||
| 107 | help="Radio hardware type (default: waveshare)", |
|||
| 108 | ) |
|||
| 109 | diff --git a/src/pymc_core/hardware/gpio_manager.py b/src/pymc_core/hardware/gpio_manager.py |
|||
| 110 | index 399a5da..fa7f900 100644 |
|||
| 111 | --- a/src/pymc_core/hardware/gpio_manager.py |
|||
| 112 | +++ b/src/pymc_core/hardware/gpio_manager.py |
|||
| 113 | @@ -44,7 +44,7 @@ logger = logging.getLogger("GPIOPinManager") |
|||
| 114 | class GPIOPinManager: |
|||
| 115 | """Manages GPIO pins abstraction using Linux GPIO character device interface""" |
|||
| 116 | ||||
| 117 | - def __init__(self, gpio_chip: str = "/dev/gpiochip0"): |
|||
| 118 | + def __init__(self, gpio_chip: str = "/dev/gpiochip4"): |
|||
| 119 | """ |
|||
| 120 | Initialize GPIO Pin Manager |
|||
| 121 | ||||
| 122 | diff --git a/src/pymc_core/hardware/lora/LoRaRF/SX126x.py b/src/pymc_core/hardware/lora/LoRaRF/SX126x.py |
|||
| 123 | index 31bedd4..3a672ef 100644 |
|||
| 124 | --- a/src/pymc_core/hardware/lora/LoRaRF/SX126x.py |
|||
| 125 | +++ b/src/pymc_core/hardware/lora/LoRaRF/SX126x.py |
|||
| 126 | @@ -468,7 +468,7 @@ class SX126x(BaseLoRa): |
|||
| 127 | self._cs_define = 17 # Default to GPIO 17 (safe alternative) |
|||
| 128 | else: |
|||
| 129 | # Keep original hardcoded value for unknown buses |
|||
| 130 | - self._cs_define = 21 |
|||
| 131 | + self._cs_define = 1 |
|||
| 132 | ||||
| 133 | # open spi line and set bus id, chip select, and spi speed |
|||
| 134 | spi.open(bus, cs) |
|||
| 135 | @@ -1484,6 +1484,7 @@ class SX126x(BaseLoRa): |
|||
| 136 | # Adaptive CS control based on CS pin type |
|||
| 137 | if self._cs_define != 8: # Manual CS pin (like Waveshare GPIO 21) |
|||
| 138 | # Simple CS control for manual pins |
|||
| 139 | + print("_cs_define", self._cs_define) |
|||
| 140 | _get_output(self._cs_define).write(False) |
|||
| 141 | buf = [opCode] |
|||
| 142 | for i in range(nBytes): |
|||
| 143 | ``` |
|||
| 144 | </details> |
|||
| 145 | ||||
| 146 | pinout: |
|||
| 147 | ||||
| 148 | * SPI (CLK/MOSI/MISO/CE) on minipcie pins 3, 6, 5, 7. |
|||
| 149 | * RST on 22 |
|||
| 150 | * BUSY on 19 |
|||
| 151 | * IRQ/DIO1 on 1 |
|||
| 152 | ||||
| 153 | plus 3v3+GND from a wide choice of pins |
|||
| d9f0c0 | Peter van Dijk | 2026-02-21 13:29:12 | 154 | |
| 155 |  |
