diff --git a/24.10.5-untethering_liberty/qca9531_glinet_gl-xe300.dts b/24.10.5-untethering_liberty/qca9531_glinet_gl-xe300.dts new file mode 100644 index 0000000..a3c369c --- /dev/null +++ b/24.10.5-untethering_liberty/qca9531_glinet_gl-xe300.dts @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qca953x.dtsi" + +#include +#include +#include + +/ { + compatible = "glinet,gl-xe300", "qca,qca9531"; + model = "GL.iNet GL-XE300"; + + aliases { + label-mac-device = ð0; + }; + + gpio-export { + compatible = "gpio-export"; + + gpio_lte_power { + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + gpio-export,name = "lte_power"; + gpio-export,output = <1>; + }; + + gpio_sd_detect { + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + gpio-export,name = "sd_detect"; + gpio-export,output = <0>; + }; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&jtag_disable_pins>; + + reset { + label = "reset"; + linux,code = ; + gpios = <&gpio 3 GPIO_ACTIVE_LOW>; + }; + }; + + i2c_gpio: i2c@0 { + compatible = "i2c-gpio"; + sda-gpios = <&gpio 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <1>; + i2c-gpio,timeout-ms = <5>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; + +}; + +&pcie0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "u-boot-env"; + reg = <0x40000 0x10000>; + }; + + partition@50000 { + label = "art"; + reg = <0x50000 0x10000>; + read-only; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + compatible = "mac-base"; + reg = <0x0 0x6>; + #nvmem-cell-cells = <1>; + }; + + cal_art_1000: calibration@1000 { + reg = <0x1000 0x440>; + }; + }; + }; + + partition@60000 { + label = "kernel"; + reg = <0x60000 0x400000>; + }; + + partition@460000 { + label = "nor_reserved"; + reg = <0x460000 0xba0000>; + }; + }; + }; + + flash@1 { + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <25000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ubi"; + reg = <0x0 0x8000000>; + }; + }; + }; +}; + +ð0 { + status = "okay"; + + phy-handle = <&swphy4>; + + nvmem-cells = <&macaddr_art_0 0>; + nvmem-cell-names = "mac-address"; +}; + +ð1 { + nvmem-cells = <&macaddr_art_0 1>; + nvmem-cell-names = "mac-address"; +}; + +&wmac { + status = "okay"; + + nvmem-cells = <&cal_art_1000>; + nvmem-cell-names = "calibration"; +}; + diff --git a/24.10.5-untethering_liberty/uplink.py b/24.10.5-untethering_liberty/uplink.py new file mode 100644 index 0000000..2b66c68 --- /dev/null +++ b/24.10.5-untethering_liberty/uplink.py @@ -0,0 +1,86 @@ +import meshtastic +import meshtastic.serial_interface +from meshtastic import mqtt_pb2, mesh_pb2 +from pubsub import pub +import paho.mqtt.client as mqtt +import time + +# --- CONFIGURATION --- +MQTT_BROKER = "mqtt.meshtastic.org" +MQTT_USER = "meshdev" +MQTT_PW = "large4cats" +REGION = "US" +CHANNEL = "LongFast" +SERIAL_PORT = "/dev/ttyACM0" + +# --- MQTT SETUP --- +client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) +client.username_pw_set(MQTT_USER, MQTT_PW) + +def on_connect(client, userdata, flags, rc, properties): + if rc == 0: + print("Connected to Meshtastic MQTT Broker!") + else: + print(f"Failed to connect, return code {rc}") + +client.on_connect = on_connect + +try: + client.connect(MQTT_BROKER, 1883, 60) + client.loop_start() +except Exception as e: + print(f"MQTT Connection Error: {e}") + +# --- BRIDGE LOGIC --- +def onReceive(packet, interface): + try: + from_id = packet.get('fromId') + decoded = packet.get('decoded', {}) + portnum = decoded.get('portnum') + + if not from_id or from_id == 'None': + return + + print(f"\n[MESH] From: {from_id} | Type: {portnum}") + + raw_packet = packet.get('raw') + + if raw_packet: + envelope = mqtt_pb2.ServiceEnvelope() + envelope.packet.CopyFrom(raw_packet) + envelope.channel_id = CHANNEL + + # FIXED ATTRIBUTE HERE + envelope.gateway_id = f"!{interface.myInfo.my_node_num:08x}" + + topic = f"msh/{REGION}/2/e/{CHANNEL}/{from_id}" + + client.publish(topic, envelope.SerializeToString()) + print(f" --> Uplinked to {topic}") + else: + print(" (Skipping: No raw packet data found)") + + except Exception as e: + print(f" Error in bridge: {e}") + +# --- MAIN RUNNER --- +print("--- Starting RAK4630 to Global Map Bridge ---") +print(f"Initializing Serial on {SERIAL_PORT}...") + +try: + interface = meshtastic.serial_interface.SerialInterface(devPath=SERIAL_PORT) + pub.subscribe(onReceive, "meshtastic.receive") + + # FIXED ATTRIBUTE HERE + print(f"My Node ID: !{interface.myInfo.my_node_num:08x}") + print("Bridge Active. Waiting for Mesh traffic... (Ctrl+C to stop)") + + while True: + time.sleep(1) + +except KeyboardInterrupt: + print("\nStopping bridge...") + client.loop_stop() + interface.close() +except Exception as e: + print(f"Connection Error: {e}")