Loading...
BETA OPEN MODE ONLY

DMD-LoRa Open API

Drive the LoRa module in a DMD device from your own Android app — read & change radio settings and send/receive raw LoRa messages, over a bound service or simple broadcasts.

Bind action
com.thorkracing.dmdlora.OPEN_API
Package
com.thorkracing.dmdLora

Overview

The DMD-LoRa app owns the LoRa radio module built into a DMD device. The Open API lets any app on the same device use that radio — change its configuration and exchange raw LoRa messages — without touching the hardware directly.

Two ways to integrate:

  • Bound service (AIDL) — the primary API. Typed calls with return values plus a push channel for incoming messages.
  • Broadcasts — a fire-and-forget veneer for scripted integrations (Tasker, etc.) that don't want to bind.

Open Mode

A DMD device has one radio with one owner, so it runs in one of two modes:

  • DMD2 Mode (default) — the radio belongs to the DMD2 / DMD2-Next riding-group features. The Open API is inert.
  • Open Mode — the radio is free for general use. The Open API is live, and DMD group features are disabled.

So the first thing your app does is take the radio with setOpenMode(true). While not in Open Mode, readSettingsJson() returns "{}", writeSetting() / sendMessage() return false, and no messages are delivered.

Quick Start (AIDL)

1. Copy these two .aidl files into your app under src/main/aidl/com/thorkracing/dmdLora/:

// ILoraOpenService.aidl
package com.thorkracing.dmdLora;
import com.thorkracing.dmdLora.ILoraEventListener;

interface ILoraOpenService {
    boolean isOpenMode();
    boolean setOpenMode(boolean open);
    String  readSettingsJson();
    boolean writeSetting(String key, String value);
    boolean sendMessage(String text, int targetAddr, int targetChannel);
    void    registerListener(ILoraEventListener listener);
    void    unregisterListener(ILoraEventListener listener);
}

// ILoraEventListener.aidl
package com.thorkracing.dmdLora;
oneway interface ILoraEventListener {
    void onMessageReceived(String text, long timestamp);
}

2. Bind to the service:

Intent intent = new Intent("com.thorkracing.dmdlora.OPEN_API");
intent.setPackage("com.thorkracing.dmdLora");
bindService(intent, connection, Context.BIND_AUTO_CREATE);

3. Use it once connected:

ILoraOpenService api = ILoraOpenService.Stub.asInterface(binder);

api.setOpenMode(true);                 // take the radio
api.sendMessage("hello", -1, -1);      // broadcast on the current channel
api.registerListener(myListener);      // receive incoming messages
// … later …
api.setOpenMode(false);                // hand the radio back to DMD2

Interface Reference

ILoraOpenService

MethodReturnsDescription
isOpenMode()booleanTrue if the radio is currently in Open Mode (API live).
setOpenMode(boolean open)booleanSwitch modes. Returns the resulting mode (true = now Open). Passing false re-applies the DMD2 group radio config.
readSettingsJson()StringCurrent module configuration as a JSON object (see Settings). "{}" if unavailable / not in Open Mode.
writeSetting(key, value)booleanWrite one setting. false if rejected (unknown key / not in Open Mode).
sendMessage(text, addr, ch)booleanTransmit a raw text message. false if rejected.
registerListener(cb)voidSubscribe to incoming messages.
unregisterListener(cb)voidUnsubscribe.

ILoraEventListener

onMessageReceived(String text, long timestamp)Fired (oneway) for each raw LoRa message received while in Open Mode. timestamp is device-local epoch milliseconds at receipt.

Mode Control

setOpenMode(boolean) is the gateway. A typical session:

if (!api.isOpenMode()) {
    api.setOpenMode(true);   // disables DMD group features, frees the radio
}
// … read settings, send/receive …
api.setOpenMode(false);      // restores the DMD2 group radio config

You can also flip the mode without binding, via broadcast — see Broadcast API.

Reading & Writing Settings

Reading

readSettingsJson() returns the live register read-back:

{
  "deviceType": "...", "address": "0x0000", "channel": 18,
  "frequencyMhz": 868, "airRate": "2.4k", "power": "30dBm",
  "packetSize": "200", "fixedMode": false, "appendRssi": false,
  "worCycle": "2000", "uartBaud": "9600", "parity": "8N1",
  "serialTimeout": "...", "lbtParams": "..."
}

Writing

writeSetting(key, value) takes a key and an AT value (an enum index, a number, or "0"/"1" for toggles):

keyvalueNotes
address0–65535Module network address
channel0–80RF channel (maps to frequency)
powerindex 0–30 = highest power
airrate / rateindex 0–7Air data rate (lower index = longer range)
packetindex 0–3Sub-packet size
key0–65535Hardware encryption key (write-only)
lbt0 / 1Listen-before-talk
wtime / worcycleindex 0–7WOR wake cycle
urxt1–255Serial frame-break timeout
drssi0 / 1Append RSSI byte to received data
trans / fixed0 / 10 = transparent, 1 = fixed (point-to-point)

Sending & Receiving

Send

api.sendMessage("hello world", -1, -1);          // broadcast on current channel
api.sendMessage("to node 5", 5, 18);             // fixed-mode: address 5, channel 18
textThe message. Kept short — the LoRa payload is ~180–200 bytes; longer text may be truncated.
targetAddrDestination address for fixed mode, or -1 for a transparent broadcast.
targetChannelDestination channel for fixed mode, or -1 for the current channel.

Receive

ILoraEventListener listener = new ILoraEventListener.Stub() {
    @Override public void onMessageReceived(String text, long timestamp) {
        // handle incoming raw LoRa text
    }
};
api.registerListener(listener);

Broadcast API

For integrations that won't bind (scripts, Tasker), the same operations are available as broadcasts. Send them directed to the DMD-LoRa package:

Intent i = new Intent("com.thorkracing.dmdlora.open.SEND_MESSAGE");
i.setPackage("com.thorkracing.dmdLora");
i.putExtra("message", "hello");
i.putExtra("target_addr", -1);
i.putExtra("target_channel", -1);
sendBroadcast(i);
ActionExtrasNotes
…open.SET_MODEopen_mode (bool)Switch modes. Works in either mode.
…open.SEND_MESSAGEmessage, target_addr, target_channelOpen Mode only.
…open.WRITE_SETTINGkey, valueOpen Mode only.

To receive messages without binding, register a receiver for the outbound action:

ActionExtras
com.thorkracing.dmdlora.open.MESSAGE_RECEIVEDmessage (String), timestamp (long)

(All prefixes above are com.thorkracing.dmdlora.)

Security & Privacy

  • No special permission is required to bind or use the API — any app on the device may use the radio while it is in Open Mode.
  • DMD riding-group data is never exposed here. The API and its message channel are live only in Open Mode; DMD2 group locations and group chat are private and never delivered through this API.
  • Anything you broadcast over LoRa is unencrypted at the app layer and receivable by any DMD-LoRa module on the same channel. Don't send sensitive data in the clear.
  • The dangerous radio settings (UART baud, AUX pin, factory reset, reboot) are excluded from the API so a third-party app cannot brick the module.
Top