mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
247 lines
8.2 KiB
Dart
247 lines
8.2 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
import '../../models/contact.dart';
|
|
import '../buffer_writer.dart';
|
|
import '../meshcore_constants.dart';
|
|
|
|
/// Builds outgoing BLE frames for the MeshCore device
|
|
class FrameBuilder {
|
|
/// Build DeviceQuery command
|
|
static Uint8List buildDeviceQuery() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdDeviceQuery);
|
|
writer.writeByte(MeshCoreConstants.supportedCompanionProtocolVersion);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build AppStart command
|
|
static Uint8List buildAppStart() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdAppStart);
|
|
writer.writeByte(1); // appVer
|
|
writer.writeBytes(Uint8List(6)); // reserved
|
|
writer.writeString('MeshCore SAR'); // appName
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build GetContacts command
|
|
static Uint8List buildGetContacts() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdGetContacts);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build AddUpdateContact command
|
|
static Uint8List buildAddUpdateContact(Contact contact) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdAddUpdateContact); // 0x09
|
|
writer.writeBytes(contact.publicKey); // 32 bytes
|
|
writer.writeByte(contact.type.value); // ADV_TYPE_*
|
|
writer.writeByte(contact.flags); // flags
|
|
writer.writeInt8(contact.outPathLen); // path length (signed byte)
|
|
writer.writeBytes(contact.outPath); // 64 bytes
|
|
|
|
// Write name as null-terminated string in 32-byte field
|
|
final nameBytes = Uint8List(32);
|
|
final encoded = utf8.encode(contact.advName);
|
|
final copyLen = encoded.length > 31 ? 31 : encoded.length;
|
|
nameBytes.setRange(0, copyLen, encoded);
|
|
writer.writeBytes(nameBytes);
|
|
|
|
writer.writeUInt32LE(contact.lastAdvert); // timestamp
|
|
writer.writeInt32LE(contact.advLat); // latitude * 1E6
|
|
writer.writeInt32LE(contact.advLon); // longitude * 1E6
|
|
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendTxtMsg command
|
|
static Uint8List buildSendTxtMsg({
|
|
required Uint8List contactPublicKey,
|
|
required String text,
|
|
int textType = 0,
|
|
int attempt = 0,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendTxtMsg); // 0x02
|
|
writer.writeByte(textType); // TXT_TYPE_*
|
|
writer.writeByte(attempt); // 0-3
|
|
writer.writeUInt32LE(DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
|
writer.writeBytes(contactPublicKey.sublist(0, 6));
|
|
writer.writeString(text);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendChannelTxtMsg command
|
|
static Uint8List buildSendChannelTxtMsg({
|
|
required int channelIdx,
|
|
required String text,
|
|
int textType = 0,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendChannelTxtMsg); // 0x03
|
|
writer.writeByte(textType); // TXT_TYPE_*
|
|
writer.writeByte(channelIdx); // 0 for 'public' channel
|
|
writer.writeUInt32LE(DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
|
writer.writeString(text);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendTelemetryReq command (deprecated)
|
|
@Deprecated('Use buildSendBinaryReq() instead')
|
|
static Uint8List buildSendTelemetryReq(Uint8List contactPublicKey, {bool zeroHop = false}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendTelemetryReq);
|
|
writer.writeByte(zeroHop ? 0 : 255);
|
|
writer.writeByte(0); // reserved
|
|
writer.writeByte(0); // reserved
|
|
writer.writeBytes(contactPublicKey);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendBinaryReq command
|
|
static Uint8List buildSendBinaryReq({
|
|
required Uint8List contactPublicKey,
|
|
required Uint8List requestData,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendBinaryReq); // 0x32 (50)
|
|
writer.writeBytes(contactPublicKey); // 32 bytes
|
|
writer.writeBytes(requestData); // request code + params
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build GetBatteryVoltage command
|
|
static Uint8List buildGetBatteryAndStorage() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdGetBatteryVoltage);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SyncNextMessage command
|
|
static Uint8List buildSyncNextMessage() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSyncNextMessage);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build GetDeviceTime command
|
|
static Uint8List buildGetDeviceTime() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdGetDeviceTime);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SetDeviceTime command
|
|
static Uint8List buildSetDeviceTime() {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSetDeviceTime);
|
|
writer.writeUInt32LE(DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendSelfAdvert command
|
|
static Uint8List buildSendSelfAdvert({bool floodMode = true}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendSelfAdvert);
|
|
writer.writeByte(floodMode ? MeshCoreConstants.selfAdvertFlood : MeshCoreConstants.selfAdvertZeroHop);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SetAdvertName command
|
|
static Uint8List buildSetAdvertName(String name) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSetAdvertName);
|
|
writer.writeString(name);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SetAdvertLatLon command
|
|
static Uint8List buildSetAdvertLatLon({
|
|
required double latitude,
|
|
required double longitude,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSetAdvertLatLon);
|
|
writer.writeInt32LE((latitude * 1000000).round());
|
|
writer.writeInt32LE((longitude * 1000000).round());
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SetRadioParams command
|
|
static Uint8List buildSetRadioParams({
|
|
required int frequency,
|
|
required int bandwidth,
|
|
required int spreadingFactor,
|
|
required int codingRate,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSetRadioParams);
|
|
writer.writeUInt32LE(frequency);
|
|
writer.writeUInt16LE(bandwidth);
|
|
writer.writeByte(spreadingFactor);
|
|
writer.writeByte(codingRate);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SetTxPower command
|
|
static Uint8List buildSetTxPower(int powerDbm) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSetTxPower);
|
|
writer.writeByte(powerDbm);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SetOtherParams command
|
|
static Uint8List buildSetOtherParams({
|
|
required int manualAddContacts,
|
|
required int telemetryModes,
|
|
required int advertLocationPolicy,
|
|
int multiAcks = 0,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSetOtherParams);
|
|
writer.writeByte(manualAddContacts);
|
|
writer.writeByte(telemetryModes);
|
|
writer.writeByte(advertLocationPolicy);
|
|
writer.writeByte(multiAcks);
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendLogin command
|
|
static Uint8List buildSendLogin({
|
|
required Uint8List roomPublicKey,
|
|
required String password,
|
|
}) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendLogin); // 0x1A
|
|
writer.writeBytes(roomPublicKey); // 32 bytes
|
|
writer.writeString(password); // Max 15 bytes, null-terminated
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build SendStatusReq command
|
|
static Uint8List buildSendStatusReq(Uint8List contactPublicKey) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdSendStatusReq); // 0x1B
|
|
writer.writeBytes(contactPublicKey); // 32 bytes
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build ResetPath command - clears learned path for a contact
|
|
static Uint8List buildResetPath(Uint8List contactPublicKey) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdResetPath); // 0x0D (13)
|
|
writer.writeBytes(contactPublicKey); // 32 bytes
|
|
return writer.toBytes();
|
|
}
|
|
|
|
/// Build RemoveContact command - removes a contact from the device
|
|
static Uint8List buildRemoveContact(Uint8List contactPublicKey) {
|
|
final writer = BufferWriter();
|
|
writer.writeByte(MeshCoreConstants.cmdRemoveContact); // 0x0F (15)
|
|
writer.writeBytes(contactPublicKey); // 32 bytes
|
|
return writer.toBytes();
|
|
}
|
|
}
|