2025-12-26 11:42:02 -07:00
|
|
|
|
import 'dart:convert';
|
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
2026-03-22 10:50:11 -07:00
|
|
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
|
|
|
2026-01-11 13:44:01 -07:00
|
|
|
|
// Buffer Reader - sequential binary data reader with pointer tracking
|
|
|
|
|
|
class BufferReader {
|
|
|
|
|
|
int _pointer = 0;
|
2026-03-07 01:23:46 -08:00
|
|
|
|
int _lastPointer = 0;
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final Uint8List _buffer;
|
|
|
|
|
|
|
|
|
|
|
|
BufferReader(Uint8List data) : _buffer = Uint8List.fromList(data);
|
|
|
|
|
|
|
|
|
|
|
|
int get remaining => _buffer.length - _pointer;
|
|
|
|
|
|
|
|
|
|
|
|
int readByte() => readBytes(1)[0];
|
|
|
|
|
|
|
|
|
|
|
|
Uint8List readBytes(int count) {
|
2026-03-07 01:23:46 -08:00
|
|
|
|
_lastPointer = _pointer;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
if (_pointer + count > _buffer.length) {
|
|
|
|
|
|
throw RangeError(
|
|
|
|
|
|
'Attempted to read $count bytes at offset $_pointer, but only $remaining bytes remaining in buffer of length ${_buffer.length}',
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final data = _buffer.sublist(_pointer, _pointer + count);
|
|
|
|
|
|
_pointer += count;
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-28 11:04:34 -08:00
|
|
|
|
void skipBytes(int count) {
|
2026-03-07 01:23:46 -08:00
|
|
|
|
_lastPointer = _pointer;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
if (_pointer + count > _buffer.length) {
|
|
|
|
|
|
throw RangeError(
|
|
|
|
|
|
'Attempted to skip $count bytes at offset $_pointer, but only $remaining bytes remaining in buffer of length ${_buffer.length}',
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-01-28 11:04:34 -08:00
|
|
|
|
_pointer += count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-11 13:44:01 -07:00
|
|
|
|
Uint8List readRemainingBytes() => readBytes(remaining);
|
|
|
|
|
|
|
2026-03-07 01:23:46 -08:00
|
|
|
|
String readCStringGreedy(int maxLength) {
|
|
|
|
|
|
_lastPointer = _pointer;
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final value = <int>[];
|
|
|
|
|
|
final bytes = readBytes(maxLength);
|
|
|
|
|
|
for (final byte in bytes) {
|
|
|
|
|
|
if (byte == 0) break;
|
|
|
|
|
|
value.add(byte);
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
return utf8.decode(Uint8List.fromList(value), allowMalformed: true);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return String.fromCharCodes(value); // Latin-1 fallback
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-22 10:50:11 -07:00
|
|
|
|
String readCString({int maxLength = -1}) {
|
2026-03-07 01:23:46 -08:00
|
|
|
|
final backupPointer = _pointer;
|
|
|
|
|
|
final value = <int>[];
|
|
|
|
|
|
int counter = 0;
|
2026-03-22 10:50:11 -07:00
|
|
|
|
final maxLen = maxLength >= 0 ? maxLength : remaining;
|
|
|
|
|
|
while (counter < maxLen) {
|
2026-03-07 01:23:46 -08:00
|
|
|
|
final byte = readByte();
|
|
|
|
|
|
if (byte == 0) break;
|
|
|
|
|
|
value.add(byte);
|
|
|
|
|
|
counter++;
|
|
|
|
|
|
}
|
|
|
|
|
|
_lastPointer = backupPointer;
|
|
|
|
|
|
try {
|
|
|
|
|
|
return utf8.decode(Uint8List.fromList(value), allowMalformed: true);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return String.fromCharCodes(value); // Latin-1 fallback
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-11 13:44:01 -07:00
|
|
|
|
int readUInt8() => readBytes(1).buffer.asByteData().getUint8(0);
|
|
|
|
|
|
int readInt8() => readBytes(1).buffer.asByteData().getInt8(0);
|
2026-01-18 01:02:48 -08:00
|
|
|
|
int readUInt16LE() =>
|
|
|
|
|
|
readBytes(2).buffer.asByteData().getUint16(0, Endian.little);
|
|
|
|
|
|
int readUInt16BE() =>
|
|
|
|
|
|
readBytes(2).buffer.asByteData().getUint16(0, Endian.big);
|
|
|
|
|
|
int readUInt32LE() =>
|
|
|
|
|
|
readBytes(4).buffer.asByteData().getUint32(0, Endian.little);
|
|
|
|
|
|
int readUInt32BE() =>
|
|
|
|
|
|
readBytes(4).buffer.asByteData().getUint32(0, Endian.big);
|
|
|
|
|
|
int readInt16LE() =>
|
|
|
|
|
|
readBytes(2).buffer.asByteData().getInt16(0, Endian.little);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
int readInt16BE() => readBytes(2).buffer.asByteData().getInt16(0, Endian.big);
|
2026-01-18 01:02:48 -08:00
|
|
|
|
int readInt32LE() =>
|
|
|
|
|
|
readBytes(4).buffer.asByteData().getInt32(0, Endian.little);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
|
|
|
|
|
|
int readInt24BE() {
|
|
|
|
|
|
var value = (readByte() << 16) | (readByte() << 8) | readByte();
|
|
|
|
|
|
if ((value & 0x800000) != 0) value -= 0x1000000;
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
2026-03-07 01:23:46 -08:00
|
|
|
|
|
|
|
|
|
|
void resetPointer() => _pointer = 0;
|
|
|
|
|
|
void rewind() => _pointer = _lastPointer;
|
2026-01-11 13:44:01 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Buffer Writer - accumulating binary data builder
|
|
|
|
|
|
class BufferWriter {
|
|
|
|
|
|
final BytesBuilder _builder = BytesBuilder();
|
|
|
|
|
|
|
|
|
|
|
|
Uint8List toBytes() => _builder.toBytes();
|
|
|
|
|
|
|
|
|
|
|
|
void writeByte(int byte) => _builder.addByte(byte);
|
|
|
|
|
|
void writeBytes(Uint8List bytes) => _builder.add(bytes);
|
|
|
|
|
|
|
|
|
|
|
|
void writeUInt16LE(int num) {
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final bytes = Uint8List(2)
|
|
|
|
|
|
..buffer.asByteData().setUint16(0, num, Endian.little);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writeBytes(bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void writeUInt32LE(int num) {
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final bytes = Uint8List(4)
|
|
|
|
|
|
..buffer.asByteData().setUint32(0, num, Endian.little);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writeBytes(bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void writeInt32LE(int num) {
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final bytes = Uint8List(4)
|
|
|
|
|
|
..buffer.asByteData().setInt32(0, num, Endian.little);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writeBytes(bytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 01:02:48 -08:00
|
|
|
|
void writeString(String string) =>
|
|
|
|
|
|
writeBytes(Uint8List.fromList(utf8.encode(string)));
|
2026-01-11 13:44:01 -07:00
|
|
|
|
|
|
|
|
|
|
void writeCString(String string, int maxLength) {
|
|
|
|
|
|
final bytes = Uint8List(maxLength);
|
|
|
|
|
|
final encoded = utf8.encode(string);
|
|
|
|
|
|
for (var i = 0; i < maxLength - 1 && i < encoded.length; i++) {
|
|
|
|
|
|
bytes[i] = encoded[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
writeBytes(bytes);
|
|
|
|
|
|
}
|
2026-01-26 16:11:21 -08:00
|
|
|
|
|
|
|
|
|
|
void writeHex(String hex) {
|
feat(localization): update contact settings translations for multiple languages
- Translated contact settings and related strings in Slovenian, Swedish, Ukrainian, Chinese, Dutch, Polish, Portuguese, Russian, and Slovak.
- Added new strings for discovered contacts actions such as adding, copying, and deleting contacts.
- Enhanced the DiscoveryContact model to include a rawPacket field for better data handling.
- Updated the contacts screen to support new actions in the context menu for discovered contacts.
- Improved the contact discovery store to handle the serialization of the new rawPacket field.
2026-03-01 10:13:17 -08:00
|
|
|
|
writeBytes(hex2Uint8List(hex));
|
|
|
|
|
|
}
|
2026-03-12 23:08:46 -07:00
|
|
|
|
|
|
|
|
|
|
void writeBytesPadded(Uint8List bytes, int totalLength) {
|
|
|
|
|
|
// Path data (64 bytes, zero-padded)
|
|
|
|
|
|
final bytesPadded = Uint8List(totalLength);
|
|
|
|
|
|
final len = bytes.length < totalLength ? bytes.length : totalLength;
|
|
|
|
|
|
if (bytes.isNotEmpty && len > 0) {
|
|
|
|
|
|
final copyLen = bytes.length < totalLength ? bytes.length : totalLength;
|
|
|
|
|
|
for (int i = 0; i < copyLen; i++) {
|
|
|
|
|
|
bytesPadded[i] = bytes[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
writeBytes(bytesPadded);
|
|
|
|
|
|
}
|
feat(localization): update contact settings translations for multiple languages
- Translated contact settings and related strings in Slovenian, Swedish, Ukrainian, Chinese, Dutch, Polish, Portuguese, Russian, and Slovak.
- Added new strings for discovered contacts actions such as adding, copying, and deleting contacts.
- Enhanced the DiscoveryContact model to include a rawPacket field for better data handling.
- Updated the contacts screen to support new actions in the context menu for discovered contacts.
- Improved the contact discovery store to handle the serialization of the new rawPacket field.
2026-03-01 10:13:17 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Uint8List hex2Uint8List(String hex) {
|
|
|
|
|
|
// Validate hex string length is even and not empty
|
|
|
|
|
|
if (hex.isEmpty || hex.length % 2 != 0) {
|
|
|
|
|
|
throw FormatException('Invalid hex string length: ${hex.length}');
|
|
|
|
|
|
}
|
|
|
|
|
|
List<int> result = [];
|
|
|
|
|
|
for (int i = 0; i < hex.length ~/ 2; i++) {
|
|
|
|
|
|
final hexByte = hex.substring(i * 2, i * 2 + 2);
|
|
|
|
|
|
final byte = int.tryParse(hexByte, radix: 16);
|
|
|
|
|
|
if (byte == null) {
|
|
|
|
|
|
throw FormatException('Invalid hex characters at position $i: $hexByte');
|
2026-01-26 16:11:21 -08:00
|
|
|
|
}
|
feat(localization): update contact settings translations for multiple languages
- Translated contact settings and related strings in Slovenian, Swedish, Ukrainian, Chinese, Dutch, Polish, Portuguese, Russian, and Slovak.
- Added new strings for discovered contacts actions such as adding, copying, and deleting contacts.
- Enhanced the DiscoveryContact model to include a rawPacket field for better data handling.
- Updated the contacts screen to support new actions in the context menu for discovered contacts.
- Improved the contact discovery store to handle the serialization of the new rawPacket field.
2026-03-01 10:13:17 -08:00
|
|
|
|
result.add(byte);
|
2026-01-26 16:11:21 -08:00
|
|
|
|
}
|
feat(localization): update contact settings translations for multiple languages
- Translated contact settings and related strings in Slovenian, Swedish, Ukrainian, Chinese, Dutch, Polish, Portuguese, Russian, and Slovak.
- Added new strings for discovered contacts actions such as adding, copying, and deleting contacts.
- Enhanced the DiscoveryContact model to include a rawPacket field for better data handling.
- Updated the contacts screen to support new actions in the context menu for discovered contacts.
- Improved the contact discovery store to handle the serialization of the new rawPacket field.
2026-03-01 10:13:17 -08:00
|
|
|
|
return Uint8List.fromList(result);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Command codes (to device)
|
|
|
|
|
|
const int cmdAppStart = 1;
|
|
|
|
|
|
const int cmdSendTxtMsg = 2;
|
|
|
|
|
|
const int cmdSendChannelTxtMsg = 3;
|
|
|
|
|
|
const int cmdGetContacts = 4;
|
|
|
|
|
|
const int cmdGetDeviceTime = 5;
|
|
|
|
|
|
const int cmdSetDeviceTime = 6;
|
|
|
|
|
|
const int cmdSendSelfAdvert = 7;
|
|
|
|
|
|
const int cmdSetAdvertName = 8;
|
|
|
|
|
|
const int cmdAddUpdateContact = 9;
|
|
|
|
|
|
const int cmdSyncNextMessage = 10;
|
|
|
|
|
|
const int cmdSetRadioParams = 11;
|
|
|
|
|
|
const int cmdSetRadioTxPower = 12;
|
|
|
|
|
|
const int cmdResetPath = 13;
|
|
|
|
|
|
const int cmdSetAdvertLatLon = 14;
|
|
|
|
|
|
const int cmdRemoveContact = 15;
|
|
|
|
|
|
const int cmdShareContact = 16;
|
|
|
|
|
|
const int cmdExportContact = 17;
|
|
|
|
|
|
const int cmdImportContact = 18;
|
|
|
|
|
|
const int cmdReboot = 19;
|
|
|
|
|
|
const int cmdGetBattAndStorage = 20;
|
|
|
|
|
|
const int cmdDeviceQuery = 22;
|
|
|
|
|
|
const int cmdSendLogin = 26;
|
|
|
|
|
|
const int cmdSendStatusReq = 27;
|
2025-12-31 22:19:48 -07:00
|
|
|
|
const int cmdGetContactByKey = 30;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
const int cmdGetChannel = 31;
|
|
|
|
|
|
const int cmdSetChannel = 32;
|
2026-01-28 11:04:34 -08:00
|
|
|
|
const int cmdSendTracePath = 36;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
const int cmdSetOtherParams = 38;
|
2026-03-19 22:49:16 -07:00
|
|
|
|
const int cmdSendTelemetryReq = 39;
|
2026-01-19 16:55:39 -08:00
|
|
|
|
const int cmdGetCustomVar = 40;
|
2026-01-18 01:02:48 -08:00
|
|
|
|
const int cmdSetCustomVar = 41;
|
2026-01-07 00:49:35 -08:00
|
|
|
|
const int cmdSendBinaryReq = 50;
|
2026-03-26 16:44:52 -07:00
|
|
|
|
const int cmdGetStats = 56;
|
|
|
|
|
|
const int cmdSendAnonReq = 57;
|
2026-02-28 19:11:11 -08:00
|
|
|
|
const int cmdSetAutoAddConfig = 58;
|
|
|
|
|
|
const int cmdGetAutoAddConfig = 59;
|
2026-03-23 19:24:27 -07:00
|
|
|
|
const int cmdSetPathHashMode = 61;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
// Text message types
|
|
|
|
|
|
const int txtTypePlain = 0;
|
|
|
|
|
|
const int txtTypeCliData = 1;
|
2026-03-21 13:01:02 -07:00
|
|
|
|
const int txtTypeSigned = 2;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
// Repeater request types (for server requests)
|
|
|
|
|
|
const int reqTypeGetStatus = 0x01;
|
|
|
|
|
|
const int reqTypeKeepAlive = 0x02;
|
|
|
|
|
|
const int reqTypeGetTelemetry = 0x03;
|
|
|
|
|
|
const int reqTypeGetAccessList = 0x05;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
const int reqTypeGetNeighbors = 0x06;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
// Repeater response codes
|
|
|
|
|
|
const int respServerLoginOk = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Response codes (from device)
|
|
|
|
|
|
const int respCodeOk = 0;
|
|
|
|
|
|
const int respCodeErr = 1;
|
|
|
|
|
|
const int respCodeContactsStart = 2;
|
|
|
|
|
|
const int respCodeContact = 3;
|
|
|
|
|
|
const int respCodeEndOfContacts = 4;
|
|
|
|
|
|
const int respCodeSelfInfo = 5;
|
|
|
|
|
|
const int respCodeSent = 6;
|
|
|
|
|
|
const int respCodeContactMsgRecv = 7;
|
|
|
|
|
|
const int respCodeChannelMsgRecv = 8;
|
|
|
|
|
|
const int respCodeCurrTime = 9;
|
|
|
|
|
|
const int respCodeNoMoreMessages = 10;
|
2026-01-26 12:19:45 -08:00
|
|
|
|
const int respCodeExportContact = 11;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
const int respCodeBattAndStorage = 12;
|
|
|
|
|
|
const int respCodeDeviceInfo = 13;
|
|
|
|
|
|
const int respCodeContactMsgRecvV3 = 16;
|
|
|
|
|
|
const int respCodeChannelMsgRecvV3 = 17;
|
|
|
|
|
|
const int respCodeChannelInfo = 18;
|
2026-01-19 16:55:39 -08:00
|
|
|
|
const int respCodeCustomVars = 21;
|
2026-02-28 19:11:11 -08:00
|
|
|
|
const int respCodeAutoAddConfig = 25;
|
2026-03-23 19:24:27 -07:00
|
|
|
|
const int respCodeStats = 24;
|
|
|
|
|
|
|
|
|
|
|
|
const int statsTypeCore = 0;
|
|
|
|
|
|
const int statsTypeRadio = 1;
|
|
|
|
|
|
const int statsTypePackets = 2;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
// Push codes (async from device)
|
|
|
|
|
|
const int pushCodeAdvert = 0x80;
|
|
|
|
|
|
const int pushCodePathUpdated = 0x81;
|
|
|
|
|
|
const int pushCodeSendConfirmed = 0x82;
|
|
|
|
|
|
const int pushCodeMsgWaiting = 0x83;
|
|
|
|
|
|
const int pushCodeLoginSuccess = 0x85;
|
|
|
|
|
|
const int pushCodeLoginFail = 0x86;
|
|
|
|
|
|
const int pushCodeStatusResponse = 0x87;
|
|
|
|
|
|
const int pushCodeLogRxData = 0x88;
|
2026-01-28 11:04:34 -08:00
|
|
|
|
const int pushCodeTraceData = 0x89;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
const int pushCodeNewAdvert = 0x8A;
|
2026-01-07 00:49:35 -08:00
|
|
|
|
const int pushCodeTelemetryResponse = 0x8B;
|
|
|
|
|
|
const int pushCodeBinaryResponse = 0x8C;
|
|
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Contact/advertisement types
|
|
|
|
|
|
const int advTypeChat = 1;
|
|
|
|
|
|
const int advTypeRepeater = 2;
|
|
|
|
|
|
const int advTypeRoom = 3;
|
|
|
|
|
|
const int advTypeSensor = 4;
|
|
|
|
|
|
|
2026-03-19 22:49:16 -07:00
|
|
|
|
const int teleModeDeny = 0;
|
|
|
|
|
|
const int teleModeAllowFlags = 1; // use contact.flags
|
|
|
|
|
|
const int teleModeAllowAll = 2;
|
|
|
|
|
|
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
// Payload Types
|
|
|
|
|
|
const int payloadTypeREQ =
|
|
|
|
|
|
0x00; // request (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob)
|
|
|
|
|
|
const int payloadTypeRESPONSE =
|
|
|
|
|
|
0x01; // response to REQ or ANON_REQ (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob)
|
|
|
|
|
|
const int payloadTypeTXTMSG =
|
|
|
|
|
|
0x02; // a plain text message (prefixed with dest/src hashes, MAC) (enc data: timestamp, text)
|
|
|
|
|
|
const int payloadTypeACK = 0x03; // a simple ack
|
|
|
|
|
|
const int payloadTypeADVERT = 0x04; // a node advertising its Identity
|
|
|
|
|
|
const int payloadTypeGRPTXT =
|
|
|
|
|
|
0x05; // an (unverified) group text message (prefixed with channel hash, MAC) (enc data: timestamp, "name: msg")
|
|
|
|
|
|
const int payloadTypeGRPDATA =
|
|
|
|
|
|
0x06; // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: timestamp, blob)
|
|
|
|
|
|
const int payloadTypeANONREQ =
|
|
|
|
|
|
0x07; // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
|
|
|
|
|
|
const int payloadTypePATH =
|
|
|
|
|
|
0x08; // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
|
|
|
|
|
|
const int payloadTypeTRACE = 0x09; // trace a path, collecting SNI for each hop
|
|
|
|
|
|
const int payloadTypeMULTIPART = 0x0A; // packet is one of a set of packets
|
|
|
|
|
|
const int payloadTypeCONTROL = 0x0B; // a control/discovery packet
|
|
|
|
|
|
//...
|
|
|
|
|
|
const int payloadTypeRawCustom =
|
|
|
|
|
|
0x0F; // custom packet as raw bytes, for applications with custom encryption, payloads, etc
|
|
|
|
|
|
|
2026-02-28 19:11:11 -08:00
|
|
|
|
//auto-add flags
|
|
|
|
|
|
const int autoAddOverwriteOldestFlag =
|
|
|
|
|
|
1 << 0; // 0x01 - overwrite oldest non-favourite when full
|
|
|
|
|
|
const int autoAddChatFlag =
|
|
|
|
|
|
1 << 1; // 0x02 - auto-add Chat (Companion) (ADV_TYPE_CHAT)
|
|
|
|
|
|
const int autoAddRepeaterFlag =
|
|
|
|
|
|
1 << 2; // 0x04 - auto-add Repeater (ADV_TYPE_REPEATER)
|
|
|
|
|
|
const int autoAddRoomServerFlag =
|
|
|
|
|
|
1 << 3; // 0x08 - auto-add Room Server (ADV_TYPE_ROOM)
|
|
|
|
|
|
const int autoAddSensorFlag =
|
|
|
|
|
|
1 << 4; // 0x10 - auto-add Sensor (ADV_TYPE_SENSOR)
|
|
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Sizes
|
|
|
|
|
|
const int pubKeySize = 32;
|
2026-03-21 13:01:02 -07:00
|
|
|
|
const int signatureSize = 64;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
const int maxPathSize = 64;
|
|
|
|
|
|
const int pathHashSize = 1;
|
|
|
|
|
|
const int maxNameSize = 32;
|
|
|
|
|
|
const int maxFrameSize = 172;
|
|
|
|
|
|
const int appProtocolVersion = 3;
|
2025-12-26 13:33:03 -07:00
|
|
|
|
// Matches firmware MAX_TEXT_LEN (10 * CIPHER_BLOCK_SIZE).
|
|
|
|
|
|
const int maxTextPayloadBytes = 160;
|
2026-02-04 08:32:35 -08:00
|
|
|
|
const int _sendTextMsgOverheadBytes =
|
|
|
|
|
|
1 + 1 + 1 + 4 + 6 + 1 + 2; // +2 safety margin
|
|
|
|
|
|
const int _sendChannelTextMsgOverheadBytes =
|
|
|
|
|
|
1 + 1 + 1 + 4 + 1 + 2; // +2 safety margin
|
2025-12-26 13:33:03 -07:00
|
|
|
|
|
|
|
|
|
|
int maxContactMessageBytes() {
|
|
|
|
|
|
final byFrame = maxFrameSize - _sendTextMsgOverheadBytes;
|
|
|
|
|
|
return _minPositive(byFrame, maxTextPayloadBytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int maxChannelMessageBytes(String? senderName) {
|
|
|
|
|
|
final nameLength = _senderNameBytes(senderName);
|
|
|
|
|
|
final prefixBytes = nameLength + 2; // "<name>: "
|
|
|
|
|
|
final byPayload = maxTextPayloadBytes - prefixBytes;
|
|
|
|
|
|
final byFrame = maxFrameSize - _sendChannelTextMsgOverheadBytes;
|
|
|
|
|
|
return _minPositive(byPayload, byFrame);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int _senderNameBytes(String? senderName) {
|
|
|
|
|
|
if (senderName == null || senderName.isEmpty) return maxNameSize - 1;
|
|
|
|
|
|
final bytes = utf8.encode(senderName);
|
|
|
|
|
|
final maxBytes = maxNameSize - 1;
|
|
|
|
|
|
return bytes.length > maxBytes ? maxBytes : bytes.length;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int _minPositive(int a, int b) {
|
|
|
|
|
|
final minValue = a < b ? a : b;
|
|
|
|
|
|
return minValue < 0 ? 0 : minValue;
|
|
|
|
|
|
}
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
// Contact frame offsets
|
|
|
|
|
|
const int contactPubKeyOffset = 1;
|
|
|
|
|
|
const int contactTypeOffset = 33;
|
|
|
|
|
|
const int contactFlagsOffset = 34;
|
2026-02-24 23:56:30 +01:00
|
|
|
|
const int contactFlagFavorite = 0x01;
|
2026-03-19 22:49:16 -07:00
|
|
|
|
const int contactFlagTeleBase = 0x02; // 'base' permission includes battery
|
|
|
|
|
|
const int contactFlagTeleLoc = 0x04;
|
|
|
|
|
|
const int contactFlagTeleEnv = 0x08; //access environment sensors
|
2025-12-26 11:42:02 -07:00
|
|
|
|
const int contactPathLenOffset = 35;
|
|
|
|
|
|
const int contactPathOffset = 36;
|
|
|
|
|
|
const int contactNameOffset = 100;
|
|
|
|
|
|
const int contactTimestampOffset = 132;
|
|
|
|
|
|
const int contactLatOffset = 136;
|
|
|
|
|
|
const int contactLonOffset = 140;
|
2026-02-28 19:11:11 -08:00
|
|
|
|
const int contactLastModOffset = 144;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
const int contactFrameSize = 148;
|
|
|
|
|
|
|
|
|
|
|
|
// Message frame offsets
|
|
|
|
|
|
const int msgPubKeyOffset = 1;
|
|
|
|
|
|
const int msgTimestampOffset = 33;
|
|
|
|
|
|
const int msgFlagsOffset = 37;
|
|
|
|
|
|
const int msgTextOffset = 38;
|
|
|
|
|
|
|
|
|
|
|
|
class ParsedContactText {
|
|
|
|
|
|
final Uint8List senderPrefix;
|
|
|
|
|
|
final String text;
|
2026-01-18 01:02:48 -08:00
|
|
|
|
const ParsedContactText({required this.senderPrefix, required this.text});
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ParsedContactText? parseContactMessageText(Uint8List frame) {
|
|
|
|
|
|
if (frame.isEmpty) return null;
|
|
|
|
|
|
|
2026-03-21 13:01:02 -07:00
|
|
|
|
final message = BufferReader(frame);
|
|
|
|
|
|
try {
|
|
|
|
|
|
final code = message.readByte();
|
|
|
|
|
|
if (code != respCodeContactMsgRecv && code != respCodeContactMsgRecvV3) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
2026-03-21 13:01:02 -07:00
|
|
|
|
// Companion radio layout:
|
|
|
|
|
|
// [code][snr?][res?][res?][prefix x6][path_len][txt_type][timestamp x4][extra?][text...]
|
|
|
|
|
|
if (code == respCodeContactMsgRecvV3) {
|
|
|
|
|
|
// Skip SNR and reserved bytes in v3 layout
|
|
|
|
|
|
message.skipBytes(3);
|
|
|
|
|
|
}
|
|
|
|
|
|
final senderPrefix = message.readBytes(6); // public key
|
|
|
|
|
|
message.skipBytes(1); // path length
|
|
|
|
|
|
final textType = message.readByte();
|
|
|
|
|
|
message.skipBytes(4); // timestamp (4 bytes)
|
|
|
|
|
|
|
|
|
|
|
|
final shiftedType = textType >> 2;
|
|
|
|
|
|
final isSigned = shiftedType == txtTypeSigned || textType == txtTypeSigned;
|
|
|
|
|
|
if (isSigned) {
|
|
|
|
|
|
// Signed messages have a 4-byte signature after the timestamp, before the text
|
|
|
|
|
|
message.skipBytes(4);
|
|
|
|
|
|
}
|
2026-03-22 10:50:11 -07:00
|
|
|
|
final text = message.readCString();
|
2026-03-21 13:01:02 -07:00
|
|
|
|
if (text.isEmpty) return null;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
2026-03-21 13:01:02 -07:00
|
|
|
|
return ParsedContactText(senderPrefix: senderPrefix, text: text);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
} catch (e) {
|
2026-03-22 10:50:11 -07:00
|
|
|
|
debugPrint('Error parsing contact message text: $e');
|
2026-03-21 13:01:02 -07:00
|
|
|
|
return null;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-22 10:50:11 -07:00
|
|
|
|
// Helper to read uint32 little-endian
|
|
|
|
|
|
int readUint32LE(Uint8List data, int offset) {
|
|
|
|
|
|
return data[offset] |
|
|
|
|
|
|
(data[offset + 1] << 8) |
|
|
|
|
|
|
(data[offset + 2] << 16) |
|
|
|
|
|
|
(data[offset + 3] << 24);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Helper to read uint16 little-endian
|
|
|
|
|
|
int readUint16LE(Uint8List data, int offset) {
|
|
|
|
|
|
return data[offset] | (data[offset + 1] << 8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Helper to read int32 little-endian
|
|
|
|
|
|
int readInt32LE(Uint8List data, int offset) {
|
|
|
|
|
|
int val = readUint32LE(data, offset);
|
|
|
|
|
|
if (val >= 0x80000000) val -= 0x100000000;
|
|
|
|
|
|
return val;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Helper to convert uint32 to hex string
|
|
|
|
|
|
String ackHashToHex(int ackHash) {
|
|
|
|
|
|
return ackHash.toRadixString(16).padLeft(8, '0');
|
|
|
|
|
|
}
|
2026-03-21 13:01:02 -07:00
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Helper to convert public key to hex string
|
|
|
|
|
|
String pubKeyToHex(Uint8List pubKey) {
|
|
|
|
|
|
return pubKey.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Helper to convert hex string to public key
|
|
|
|
|
|
Uint8List hexToPubKey(String hex) {
|
|
|
|
|
|
final result = Uint8List(pubKeySize);
|
|
|
|
|
|
for (int i = 0; i < pubKeySize && i * 2 + 1 < hex.length; i++) {
|
|
|
|
|
|
result[i] = int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16);
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_GET_CONTACTS frame
|
|
|
|
|
|
Uint8List buildGetContactsFrame({int? since}) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdGetContacts);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
if (since != null) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeUInt32LE(since);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
2026-01-11 13:44:01 -07:00
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SEND_LOGIN frame
|
|
|
|
|
|
// Format: [cmd][pub_key x32][password...]\0
|
|
|
|
|
|
Uint8List buildSendLoginFrame(Uint8List recipientPubKey, String password) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendLogin);
|
|
|
|
|
|
writer.writeBytes(recipientPubKey);
|
|
|
|
|
|
writer.writeString(password);
|
|
|
|
|
|
writer.writeByte(0);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SEND_STATUS_REQ frame
|
|
|
|
|
|
// Format: [cmd][pub_key x32]
|
|
|
|
|
|
Uint8List buildSendStatusRequestFrame(Uint8List recipientPubKey) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendStatusReq);
|
|
|
|
|
|
writer.writeBytes(recipientPubKey);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SEND_TXT_MSG frame (companion_radio format)
|
|
|
|
|
|
// Format: [cmd][txt_type][attempt][timestamp x4][pub_key_prefix x6][text...]\0
|
|
|
|
|
|
Uint8List buildSendTextMsgFrame(
|
|
|
|
|
|
Uint8List recipientPubKey,
|
|
|
|
|
|
String text, {
|
|
|
|
|
|
int attempt = 0,
|
|
|
|
|
|
int? timestampSeconds,
|
|
|
|
|
|
}) {
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final timestamp =
|
|
|
|
|
|
timestampSeconds ?? (DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendTxtMsg);
|
|
|
|
|
|
writer.writeByte(txtTypePlain);
|
2026-03-20 01:54:31 -07:00
|
|
|
|
writer.writeByte(attempt.clamp(0, 255));
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeUInt32LE(timestamp);
|
|
|
|
|
|
writer.writeBytes(recipientPubKey.sublist(0, 6));
|
|
|
|
|
|
writer.writeString(text);
|
|
|
|
|
|
writer.writeByte(0);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SEND_CHANNEL_TXT_MSG frame
|
|
|
|
|
|
// Format: [cmd][txt_type][channel_idx][timestamp x4][text...]
|
|
|
|
|
|
Uint8List buildSendChannelTextMsgFrame(int channelIndex, String text) {
|
|
|
|
|
|
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendChannelTxtMsg);
|
|
|
|
|
|
writer.writeByte(txtTypePlain);
|
|
|
|
|
|
writer.writeByte(channelIndex);
|
|
|
|
|
|
writer.writeUInt32LE(timestamp);
|
|
|
|
|
|
writer.writeString(text);
|
|
|
|
|
|
writer.writeByte(0);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_REMOVE_CONTACT frame
|
|
|
|
|
|
Uint8List buildRemoveContactFrame(Uint8List pubKey) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdRemoveContact);
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_APP_START frame
|
2025-12-26 13:33:03 -07:00
|
|
|
|
// Format: [cmd][app_ver][reserved x6][app_name...]
|
|
|
|
|
|
Uint8List buildAppStartFrame({
|
|
|
|
|
|
String appName = 'MeshCoreOpen',
|
|
|
|
|
|
int appVersion = 1,
|
|
|
|
|
|
}) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdAppStart);
|
|
|
|
|
|
writer.writeByte(appVersion);
|
|
|
|
|
|
writer.writeBytes(Uint8List(6)); // reserved bytes
|
|
|
|
|
|
writer.writeString(appName);
|
|
|
|
|
|
writer.writeByte(0);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_DEVICE_QUERY frame
|
|
|
|
|
|
Uint8List buildDeviceQueryFrame({int appVersion = appProtocolVersion}) {
|
|
|
|
|
|
return Uint8List.fromList([cmdDeviceQuery, appVersion]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_GET_DEVICE_TIME frame
|
|
|
|
|
|
Uint8List buildGetDeviceTimeFrame() {
|
|
|
|
|
|
return Uint8List.fromList([cmdGetDeviceTime]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_GET_BATT_AND_STORAGE frame
|
|
|
|
|
|
Uint8List buildGetBattAndStorageFrame() {
|
|
|
|
|
|
return Uint8List.fromList([cmdGetBattAndStorage]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-23 19:24:27 -07:00
|
|
|
|
/// Companion radio stats: [56][statsType] where statsType is statsTypeCore/Radio/Packets.
|
|
|
|
|
|
Uint8List buildGetStatsFrame(int statsType) {
|
|
|
|
|
|
return Uint8List.fromList([cmdGetStats, statsType & 0xFF]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Path hash width on air: [61][0][mode], mode 0..2 → (mode+1) bytes per hop hash.
|
|
|
|
|
|
Uint8List buildSetPathHashModeFrame(int mode) {
|
|
|
|
|
|
final m = mode.clamp(0, 2);
|
|
|
|
|
|
return Uint8List.fromList([cmdSetPathHashMode, 0, m]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Build CMD_SET_DEVICE_TIME frame
|
|
|
|
|
|
Uint8List buildSetDeviceTimeFrame(int timestamp) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetDeviceTime);
|
|
|
|
|
|
writer.writeUInt32LE(timestamp);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-29 20:01:16 -07:00
|
|
|
|
// Build CMD_SEND_SELF_ADVERT frame
|
|
|
|
|
|
// Format: [cmd][flood_flag]
|
|
|
|
|
|
Uint8List buildSendSelfAdvertFrame({bool flood = false}) {
|
|
|
|
|
|
return Uint8List.fromList([cmdSendSelfAdvert, flood ? 1 : 0]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_ADVERT_NAME frame
|
|
|
|
|
|
// Format: [cmd][name...]
|
|
|
|
|
|
Uint8List buildSetAdvertNameFrame(String name) {
|
|
|
|
|
|
final nameBytes = utf8.encode(name);
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final nameLen = nameBytes.length < maxNameSize
|
|
|
|
|
|
? nameBytes.length
|
|
|
|
|
|
: maxNameSize - 1;
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetAdvertName);
|
|
|
|
|
|
writer.writeBytes(Uint8List.fromList(nameBytes.sublist(0, nameLen)));
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-29 20:01:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_ADVERT_LATLON frame
|
|
|
|
|
|
// Format: [cmd][lat x4][lon x4]
|
|
|
|
|
|
Uint8List buildSetAdvertLatLonFrame(double lat, double lon) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetAdvertLatLon);
|
|
|
|
|
|
writer.writeInt32LE((lat * 1000000).round());
|
|
|
|
|
|
writer.writeInt32LE((lon * 1000000).round());
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-29 20:01:16 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 01:02:48 -08:00
|
|
|
|
Uint8List buildSetCustomVarFrame(String value) {
|
|
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetCustomVar);
|
|
|
|
|
|
writer.writeString(value);
|
|
|
|
|
|
writer.writeByte(0);
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-29 20:01:16 -07:00
|
|
|
|
// Build CMD_REBOOT frame
|
|
|
|
|
|
// Format: [cmd]["reboot"]
|
|
|
|
|
|
Uint8List buildRebootFrame() {
|
|
|
|
|
|
return Uint8List.fromList([cmdReboot, ...utf8.encode('reboot')]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Build CMD_SYNC_NEXT_MESSAGE frame
|
|
|
|
|
|
Uint8List buildSyncNextMessageFrame() {
|
|
|
|
|
|
return Uint8List.fromList([cmdSyncNextMessage]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_GET_CHANNEL frame
|
|
|
|
|
|
Uint8List buildGetChannelFrame(int channelIndex) {
|
|
|
|
|
|
return Uint8List.fromList([cmdGetChannel, channelIndex]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_CHANNEL frame
|
|
|
|
|
|
// Format: [cmd][idx][name x32][psk x16]
|
|
|
|
|
|
Uint8List buildSetChannelFrame(int channelIndex, String name, Uint8List psk) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetChannel);
|
|
|
|
|
|
writer.writeByte(channelIndex);
|
|
|
|
|
|
writer.writeCString(name, 32);
|
|
|
|
|
|
// Write PSK (16 bytes, zero-padded)
|
|
|
|
|
|
final pskPadded = Uint8List(16);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
for (int i = 0; i < 16 && i < psk.length; i++) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
pskPadded[i] = psk[i];
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeBytes(pskPadded);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_RADIO_PARAMS frame
|
2026-02-17 23:42:04 -07:00
|
|
|
|
// Format: [cmd][freq x4][bw x4][sf][cr] (pre-v9)
|
|
|
|
|
|
// [cmd][freq x4][bw x4][sf][cr][repeat] (firmware v9+)
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// freq: frequency in Hz (300000-2500000)
|
|
|
|
|
|
// bw: bandwidth in Hz (7000-500000)
|
|
|
|
|
|
// sf: spreading factor (5-12)
|
|
|
|
|
|
// cr: coding rate (5-8)
|
2026-02-17 23:42:04 -07:00
|
|
|
|
// clientRepeat: enable off-grid packet repeat (firmware v9+, omit for older)
|
2026-02-17 23:50:11 -07:00
|
|
|
|
Uint8List buildSetRadioParamsFrame(
|
|
|
|
|
|
int freqHz,
|
|
|
|
|
|
int bwHz,
|
|
|
|
|
|
int sf,
|
|
|
|
|
|
int cr, {
|
|
|
|
|
|
bool? clientRepeat,
|
|
|
|
|
|
}) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetRadioParams);
|
|
|
|
|
|
writer.writeUInt32LE(freqHz);
|
|
|
|
|
|
writer.writeUInt32LE(bwHz);
|
|
|
|
|
|
writer.writeByte(sf);
|
|
|
|
|
|
writer.writeByte(cr);
|
2026-02-17 23:42:04 -07:00
|
|
|
|
if (clientRepeat != null) {
|
|
|
|
|
|
writer.writeByte(clientRepeat ? 1 : 0);
|
|
|
|
|
|
}
|
2026-01-11 13:44:01 -07:00
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_RADIO_TX_POWER frame
|
|
|
|
|
|
// Format: [cmd][power_dbm]
|
|
|
|
|
|
Uint8List buildSetRadioTxPowerFrame(int powerDbm) {
|
|
|
|
|
|
return Uint8List.fromList([cmdSetRadioTxPower, powerDbm]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_RESET_PATH frame
|
|
|
|
|
|
// Format: [cmd][pub_key x32]
|
|
|
|
|
|
Uint8List buildResetPathFrame(Uint8List pubKey) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdResetPath);
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CMD_ADD_UPDATE_CONTACT frame to set custom path
|
2026-03-12 23:08:46 -07:00
|
|
|
|
// Format: [cmd][pub_key x32][type][flags][path_len][path x64][name x32][Lat? x4, Lon? x4][timestamp? x4]
|
2025-12-26 11:42:02 -07:00
|
|
|
|
Uint8List buildUpdateContactPathFrame(
|
|
|
|
|
|
Uint8List pubKey,
|
2026-03-12 23:08:46 -07:00
|
|
|
|
Uint8List path,
|
2025-12-26 11:42:02 -07:00
|
|
|
|
int pathLen, {
|
|
|
|
|
|
int type = 1, // ADV_TYPE_CHAT
|
|
|
|
|
|
int flags = 0,
|
|
|
|
|
|
String name = '',
|
2026-03-12 23:08:46 -07:00
|
|
|
|
double? lat,
|
|
|
|
|
|
double? lon,
|
|
|
|
|
|
DateTime? lastModified,
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdAddUpdateContact);
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
writer.writeByte(type);
|
|
|
|
|
|
writer.writeByte(flags);
|
|
|
|
|
|
writer.writeByte(pathLen);
|
|
|
|
|
|
|
2026-03-12 23:08:46 -07:00
|
|
|
|
writer.writeBytesPadded(path, maxPathSize);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
// Name (32 bytes, null-padded)
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeCString(name, maxNameSize);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
2026-01-11 13:44:01 -07:00
|
|
|
|
// Timestamp
|
2025-12-26 11:42:02 -07:00
|
|
|
|
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeUInt32LE(timestamp);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
2026-03-12 23:08:46 -07:00
|
|
|
|
if ((lat == null || lon == null) && lastModified != null) {
|
|
|
|
|
|
// If lat/lon not provided, write zeros
|
|
|
|
|
|
writer.writeInt32LE(0);
|
|
|
|
|
|
writer.writeInt32LE(0);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Latitude and Longitude are expected in degrees, convert to int by multiplying by 1e6
|
|
|
|
|
|
// Latitude
|
|
|
|
|
|
final latitude = lat ?? 0.0;
|
|
|
|
|
|
writer.writeInt32LE((latitude * 1e6).round());
|
|
|
|
|
|
|
|
|
|
|
|
// Longitude
|
|
|
|
|
|
final longitude = lon ?? 0.0;
|
|
|
|
|
|
writer.writeInt32LE((longitude * 1e6).round());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (lastModified != null) {
|
|
|
|
|
|
// Last modified
|
|
|
|
|
|
final lastModifiedTimestamp = lastModified.millisecondsSinceEpoch ~/ 1000;
|
|
|
|
|
|
writer.writeUInt32LE(lastModifiedTimestamp);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-11 13:44:01 -07:00
|
|
|
|
return writer.toBytes();
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-31 22:19:48 -07:00
|
|
|
|
// Build CMD_GET_CONTACT_BY_KEY frame
|
|
|
|
|
|
// Format: [cmd][pub_key x32]
|
|
|
|
|
|
Uint8List buildGetContactByKeyFrame(Uint8List pubKey) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdGetContactByKey);
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
return writer.toBytes();
|
2025-12-31 22:19:48 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 16:55:39 -08:00
|
|
|
|
//Build CMD_GET_CUSTOM_VARS frame
|
|
|
|
|
|
Uint8List buildGetCustomVarsFrame() {
|
|
|
|
|
|
return Uint8List.fromList([cmdGetCustomVar]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-28 19:11:11 -08:00
|
|
|
|
Uint8List buildGetAutoAddFlagsFrame() {
|
|
|
|
|
|
return Uint8List.fromList([cmdGetAutoAddConfig]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 11:42:02 -07:00
|
|
|
|
// Calculate LoRa airtime for a packet
|
|
|
|
|
|
// Based on Semtech SX127x datasheet formula
|
|
|
|
|
|
// Returns airtime in milliseconds
|
|
|
|
|
|
int calculateLoRaAirtime({
|
|
|
|
|
|
required int payloadBytes,
|
|
|
|
|
|
required int spreadingFactor,
|
|
|
|
|
|
required int bandwidthHz,
|
|
|
|
|
|
required int codingRate,
|
|
|
|
|
|
int preambleSymbols = 8,
|
|
|
|
|
|
bool lowDataRateOptimize = false,
|
|
|
|
|
|
bool explicitHeader = true,
|
|
|
|
|
|
}) {
|
|
|
|
|
|
// Symbol duration (Ts) in milliseconds
|
|
|
|
|
|
final symbolDuration = (1 << spreadingFactor) / (bandwidthHz / 1000.0);
|
|
|
|
|
|
|
|
|
|
|
|
// Preamble time
|
|
|
|
|
|
final preambleTime = (preambleSymbols + 4.25) * symbolDuration;
|
|
|
|
|
|
|
|
|
|
|
|
// Payload symbol count
|
|
|
|
|
|
final headerBytes = explicitHeader ? 0 : 20;
|
|
|
|
|
|
final crc = 1; // CRC enabled
|
|
|
|
|
|
final de = lowDataRateOptimize ? 1 : 0;
|
|
|
|
|
|
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final numerator =
|
|
|
|
|
|
8 * payloadBytes - 4 * spreadingFactor + 28 + 16 * crc - headerBytes;
|
2025-12-26 11:42:02 -07:00
|
|
|
|
final denominator = 4 * (spreadingFactor - 2 * de);
|
2026-01-18 01:02:48 -08:00
|
|
|
|
var payloadSymbols =
|
|
|
|
|
|
8 + ((numerator / denominator).ceil()) * (codingRate + 4);
|
2025-12-26 11:42:02 -07:00
|
|
|
|
|
|
|
|
|
|
if (payloadSymbols < 0) {
|
|
|
|
|
|
payloadSymbols = 8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
final payloadTime = payloadSymbols * symbolDuration;
|
|
|
|
|
|
|
|
|
|
|
|
return (preambleTime + payloadTime).ceil();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate timeout for a message based on radio settings
|
|
|
|
|
|
// Returns timeout in milliseconds
|
|
|
|
|
|
int calculateMessageTimeout({
|
|
|
|
|
|
required int freqHz,
|
|
|
|
|
|
required int bwHz,
|
|
|
|
|
|
required int sf,
|
|
|
|
|
|
required int cr,
|
|
|
|
|
|
required int pathLength,
|
|
|
|
|
|
int messageBytes = 100, // Average message size
|
|
|
|
|
|
}) {
|
|
|
|
|
|
// Calculate airtime for one packet
|
|
|
|
|
|
final airtime = calculateLoRaAirtime(
|
|
|
|
|
|
payloadBytes: messageBytes,
|
|
|
|
|
|
spreadingFactor: sf,
|
|
|
|
|
|
bandwidthHz: bwHz,
|
|
|
|
|
|
codingRate: cr,
|
|
|
|
|
|
lowDataRateOptimize: sf >= 11,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (pathLength < 0) {
|
|
|
|
|
|
// Flood mode: Base delay + 16× airtime
|
|
|
|
|
|
return 500 + (16 * airtime);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Direct path: Base delay + ((airtime×6 + 250ms)×(hops+1))
|
|
|
|
|
|
return 500 + ((airtime * 6 + 250) * (pathLength + 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build CLI command text message frame (companion_radio format)
|
|
|
|
|
|
// Format: [cmd][txt_type][attempt][timestamp x4][pub_key_prefix x6][text...]\0
|
|
|
|
|
|
Uint8List buildSendCliCommandFrame(
|
|
|
|
|
|
Uint8List repeaterPubKey,
|
|
|
|
|
|
String command, {
|
|
|
|
|
|
int attempt = 0,
|
2026-01-02 14:22:39 -07:00
|
|
|
|
int? timestampSeconds,
|
2025-12-26 11:42:02 -07:00
|
|
|
|
}) {
|
2026-01-18 01:02:48 -08:00
|
|
|
|
final timestamp =
|
|
|
|
|
|
timestampSeconds ?? (DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendTxtMsg);
|
|
|
|
|
|
writer.writeByte(txtTypeCliData);
|
2026-03-20 01:54:31 -07:00
|
|
|
|
writer.writeByte(attempt.clamp(0, 255));
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeUInt32LE(timestamp);
|
|
|
|
|
|
writer.writeBytes(repeaterPubKey.sublist(0, 6));
|
|
|
|
|
|
writer.writeString(command);
|
|
|
|
|
|
writer.writeByte(0);
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build a telemetry request frame
|
|
|
|
|
|
// Format: [cmd][pub_key x32][payload]
|
2026-01-18 01:02:48 -08:00
|
|
|
|
Uint8List buildSendBinaryReq(Uint8List repeaterPubKey, {Uint8List? payload}) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendBinaryReq);
|
|
|
|
|
|
writer.writeBytes(repeaterPubKey);
|
2026-01-07 00:49:35 -08:00
|
|
|
|
if (payload != null && payload.isNotEmpty) {
|
2026-01-11 13:44:01 -07:00
|
|
|
|
writer.writeBytes(payload);
|
2026-01-07 00:49:35 -08:00
|
|
|
|
}
|
2026-01-11 13:44:01 -07:00
|
|
|
|
return writer.toBytes();
|
2026-01-18 01:02:48 -08:00
|
|
|
|
}
|
2026-01-26 11:56:42 -08:00
|
|
|
|
|
2026-01-28 11:04:34 -08:00
|
|
|
|
//Build a trace request frame
|
|
|
|
|
|
//[cmd][tag x4][auth x4][flag][payload]
|
2026-02-04 08:32:35 -08:00
|
|
|
|
Uint8List buildTraceReq(int tag, int auth, int flag, {Uint8List? payload}) {
|
2026-01-28 11:04:34 -08:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendTracePath);
|
|
|
|
|
|
writer.writeUInt32LE(tag);
|
|
|
|
|
|
writer.writeUInt32LE(auth);
|
|
|
|
|
|
writer.writeByte(flag);
|
|
|
|
|
|
if (payload != null && payload.isNotEmpty) {
|
|
|
|
|
|
writer.writeBytes(payload);
|
|
|
|
|
|
}
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-26 11:56:42 -08:00
|
|
|
|
// Build a export contact frame
|
|
|
|
|
|
// [cmd][pub_key x32 / if empty exports your contact info]
|
|
|
|
|
|
Uint8List buildExportContactFrame(Uint8List pubKey) {
|
|
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdExportContact);
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build a import contact frame
|
2026-01-26 16:11:21 -08:00
|
|
|
|
// [cmd][contact_frame x98+]
|
feat(localization): update contact settings translations for multiple languages
- Translated contact settings and related strings in Slovenian, Swedish, Ukrainian, Chinese, Dutch, Polish, Portuguese, Russian, and Slovak.
- Added new strings for discovered contacts actions such as adding, copying, and deleting contacts.
- Enhanced the DiscoveryContact model to include a rawPacket field for better data handling.
- Updated the contacts screen to support new actions in the context menu for discovered contacts.
- Improved the contact discovery store to handle the serialization of the new rawPacket field.
2026-03-01 10:13:17 -08:00
|
|
|
|
Uint8List buildImportContactFrame(Uint8List contactFrame) {
|
2026-01-26 11:56:42 -08:00
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdImportContact);
|
feat(localization): update contact settings translations for multiple languages
- Translated contact settings and related strings in Slovenian, Swedish, Ukrainian, Chinese, Dutch, Polish, Portuguese, Russian, and Slovak.
- Added new strings for discovered contacts actions such as adding, copying, and deleting contacts.
- Enhanced the DiscoveryContact model to include a rawPacket field for better data handling.
- Updated the contacts screen to support new actions in the context menu for discovered contacts.
- Improved the contact discovery store to handle the serialization of the new rawPacket field.
2026-03-01 10:13:17 -08:00
|
|
|
|
writer.writeBytes(contactFrame);
|
2026-01-26 11:56:42 -08:00
|
|
|
|
return writer.toBytes();
|
2026-01-31 15:00:33 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build a export contact frame
|
|
|
|
|
|
// [cmd][pub_key x32]
|
|
|
|
|
|
Uint8List buildZeroHopContact(Uint8List pubKey) {
|
|
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdShareContact);
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
return writer.toBytes();
|
2026-02-01 16:57:17 -07:00
|
|
|
|
}
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_OTHER_PARAMS frame
|
2026-02-28 19:11:11 -08:00
|
|
|
|
// Format: [cmd][allowTelemetryFlags][advertLocationPolicy][multiAcks]
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
Uint8List buildSetOtherParamsFrame(
|
|
|
|
|
|
int allowTelemetryFlags,
|
|
|
|
|
|
int advertLocationPolicy,
|
|
|
|
|
|
int multiAcks,
|
|
|
|
|
|
) {
|
|
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetOtherParams);
|
2026-02-28 19:11:11 -08:00
|
|
|
|
//Going forward the app will just set Auto Add Contacts to disabled, and use the filter flags
|
|
|
|
|
|
//Allow Auto Add Contacts use inverted logic (0x01 = disabled, 0x00 = enabled).
|
|
|
|
|
|
writer.writeByte(0x01);
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
writer.writeByte(allowTelemetryFlags); // Allow Telemetry Flags
|
|
|
|
|
|
writer.writeByte(advertLocationPolicy); // Advertisement Location Policy
|
|
|
|
|
|
writer.writeByte(multiAcks); // Multi Acknowledgements
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|
2026-02-28 19:11:11 -08:00
|
|
|
|
|
|
|
|
|
|
// Build CMD_SET_AUTO_ADD_CONFIG frame
|
|
|
|
|
|
// Format: [cmd][flags]
|
|
|
|
|
|
Uint8List buildSetAutoAddConfigFrame({
|
|
|
|
|
|
required bool autoAddChat,
|
|
|
|
|
|
required bool autoAddRepeater,
|
|
|
|
|
|
required bool autoAddRoomServer,
|
|
|
|
|
|
required bool autoAddSensor,
|
|
|
|
|
|
required bool overwriteOldest,
|
|
|
|
|
|
}) {
|
|
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSetAutoAddConfig);
|
|
|
|
|
|
int flags = 0;
|
|
|
|
|
|
if (autoAddChat) flags |= autoAddChatFlag;
|
|
|
|
|
|
if (autoAddRepeater) flags |= autoAddRepeaterFlag;
|
|
|
|
|
|
if (autoAddRoomServer) flags |= autoAddRoomServerFlag;
|
|
|
|
|
|
if (autoAddSensor) flags |= autoAddSensorFlag;
|
|
|
|
|
|
if (overwriteOldest) flags |= autoAddOverwriteOldestFlag;
|
|
|
|
|
|
writer.writeByte(flags);
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|
2026-03-19 22:49:16 -07:00
|
|
|
|
|
|
|
|
|
|
//Build CMD_SEND_TELEMETRY_REQ
|
|
|
|
|
|
// Format: [cmd][reserved x3][pub_key? x32]
|
|
|
|
|
|
Uint8List buildSendTelemetryReq(Uint8List? pubKey) {
|
|
|
|
|
|
final writer = BufferWriter();
|
|
|
|
|
|
writer.writeByte(cmdSendTelemetryReq);
|
|
|
|
|
|
|
|
|
|
|
|
if (pubKey != null && pubKey.length == pubKeySize) {
|
|
|
|
|
|
writer.writeBytes(Uint8List(3)); // reserved bytes
|
|
|
|
|
|
writer.writeBytes(pubKey);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
writer.writeBytes(Uint8List(4)); // reserved bytes
|
|
|
|
|
|
}
|
|
|
|
|
|
return writer.toBytes();
|
|
|
|
|
|
}
|