mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
fix: init tabs advert quick add
ref:
This commit is contained in:
@@ -98,6 +98,8 @@ class BleResponseHandler {
|
||||
OnChannelInfoCallback? onChannelInfoReceived;
|
||||
OnMessageEchoDetectedCallback? onMessageEchoDetected;
|
||||
VoidCallback? onRxActivity;
|
||||
void Function(Uint8List publicKey)? onContactDeleted;
|
||||
VoidCallback? onContactsFull;
|
||||
|
||||
// Track the last command that was sent, so we can retry if it fails with ERR_CODE_NOT_FOUND
|
||||
Uint8List? _lastContactPublicKey;
|
||||
@@ -183,6 +185,14 @@ class BleResponseHandler {
|
||||
debugPrint(' → Handling ChannelMessage');
|
||||
_handleChannelMessage(reader);
|
||||
break;
|
||||
case MeshCoreConstants.respContactMsgRecvV3:
|
||||
debugPrint(' → Handling ContactMessage V3');
|
||||
_handleContactMessageV3(reader);
|
||||
break;
|
||||
case MeshCoreConstants.respChannelMsgRecvV3:
|
||||
debugPrint(' → Handling ChannelMessage V3');
|
||||
_handleChannelMessageV3(reader);
|
||||
break;
|
||||
case MeshCoreConstants.pushTelemetryResponse:
|
||||
debugPrint(' → Handling TelemetryResponse');
|
||||
_handleTelemetryResponse(reader);
|
||||
@@ -251,6 +261,20 @@ class BleResponseHandler {
|
||||
debugPrint(' → Response: No More Messages');
|
||||
onNoMoreMessages?.call();
|
||||
break;
|
||||
case MeshCoreConstants.pushPathDiscoveryResponse:
|
||||
debugPrint(' → Path discovery response (not yet handled)');
|
||||
break;
|
||||
case MeshCoreConstants.pushControlData:
|
||||
debugPrint(' → Control data push (not yet handled)');
|
||||
break;
|
||||
case MeshCoreConstants.pushContactDeleted:
|
||||
debugPrint(' → Handling ContactDeleted push');
|
||||
_handleContactDeleted(reader);
|
||||
break;
|
||||
case MeshCoreConstants.pushContactsFull:
|
||||
debugPrint(' → Contacts storage full');
|
||||
onContactsFull?.call();
|
||||
break;
|
||||
case MeshCoreConstants.respOk:
|
||||
debugPrint(' → Response: OK');
|
||||
// Complete any pending ACK command
|
||||
@@ -349,6 +373,43 @@ class BleResponseHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle ContactMessage V3 response (firmware ver >= 3, has SNR header)
|
||||
void _handleContactMessageV3(BufferReader reader) {
|
||||
try {
|
||||
final message = FrameParser.parseContactMessageV3(reader);
|
||||
debugPrint(' ✅ [ContactMessage V3] Parsed successfully');
|
||||
onMessageReceived?.call(message);
|
||||
} catch (e) {
|
||||
debugPrint(' ❌ [ContactMessage V3] Parsing error: $e');
|
||||
onError?.call('Contact message V3 parsing error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle ChannelMessage V3 response (firmware ver >= 3, has SNR header)
|
||||
void _handleChannelMessageV3(BufferReader reader) {
|
||||
try {
|
||||
final message = FrameParser.parseChannelMessageV3(reader);
|
||||
debugPrint(' ✅ [ChannelMessage V3] Parsed successfully');
|
||||
onMessageReceived?.call(message);
|
||||
} catch (e) {
|
||||
debugPrint(' ❌ [ChannelMessage V3] Parsing error: $e');
|
||||
onError?.call('Channel message V3 parsing error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle ContactDeleted push (0x8F) — contact overwritten due to contacts full
|
||||
void _handleContactDeleted(BufferReader reader) {
|
||||
try {
|
||||
if (reader.remainingBytesCount >= 32) {
|
||||
final publicKey = reader.readBytes(32);
|
||||
debugPrint(' ✅ [ContactDeleted] Contact removed by firmware');
|
||||
onContactDeleted?.call(Uint8List.fromList(publicKey));
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint(' ❌ [ContactDeleted] Parsing error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle TelemetryResponse push
|
||||
void _handleTelemetryResponse(BufferReader reader) {
|
||||
try {
|
||||
|
||||
@@ -91,6 +91,8 @@ class MeshCoreBleService {
|
||||
OnErrorCallback? onError;
|
||||
OnContactNotFoundCallback? onContactNotFound;
|
||||
OnChannelInfoCallback? onChannelInfoReceived;
|
||||
void Function(Uint8List publicKey)? onContactDeleted;
|
||||
VoidCallback? onContactsFull;
|
||||
|
||||
// Activity callbacks (for blinking indicators)
|
||||
VoidCallback? onRxActivity;
|
||||
@@ -213,6 +215,12 @@ class MeshCoreBleService {
|
||||
_responseHandler.onChannelInfoReceived = (int channelIdx, String channelName, Uint8List secret, int? flags) {
|
||||
onChannelInfoReceived?.call(channelIdx, channelName, secret, flags);
|
||||
};
|
||||
_responseHandler.onContactDeleted = (publicKey) {
|
||||
onContactDeleted?.call(publicKey);
|
||||
};
|
||||
_responseHandler.onContactsFull = () {
|
||||
onContactsFull?.call();
|
||||
};
|
||||
_responseHandler.onRxActivity = () {
|
||||
onRxActivity?.call();
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// MeshCore BLE and Protocol Constants
|
||||
class MeshCoreConstants {
|
||||
// Supported protocol version
|
||||
static const int supportedCompanionProtocolVersion = 1;
|
||||
// Supported protocol version (firmware uses this to decide V1 vs V3 message frames)
|
||||
static const int supportedCompanionProtocolVersion = 3;
|
||||
|
||||
// BLE Service and Characteristic UUIDs
|
||||
static const String bleServiceUuid =
|
||||
@@ -39,6 +39,8 @@ class MeshCoreConstants {
|
||||
static const int cmdSendRawData = 25;
|
||||
static const int cmdSendLogin = 26;
|
||||
static const int cmdSendStatusReq = 27;
|
||||
static const int cmdHasConnection = 28;
|
||||
static const int cmdLogout = 29;
|
||||
static const int cmdGetContactByKey = 30;
|
||||
static const int cmdGetChannel = 31;
|
||||
static const int cmdSetChannel = 32;
|
||||
@@ -46,9 +48,23 @@ class MeshCoreConstants {
|
||||
static const int cmdSignData = 34;
|
||||
static const int cmdSignFinish = 35;
|
||||
static const int cmdSendTracePath = 36;
|
||||
static const int cmdSetDevicePin = 37;
|
||||
static const int cmdSetOtherParams = 38;
|
||||
static const int cmdSendTelemetryReq = 39;
|
||||
static const int cmdGetCustomVars = 40;
|
||||
static const int cmdSetCustomVar = 41;
|
||||
static const int cmdGetAdvertPath = 42;
|
||||
static const int cmdGetTuningParams = 43;
|
||||
static const int cmdSendBinaryReq = 50;
|
||||
static const int cmdFactoryReset = 51;
|
||||
static const int cmdSendPathDiscoveryReq = 52;
|
||||
static const int cmdSetFloodScope = 54; // v8+
|
||||
static const int cmdSendControlData = 55; // v8+
|
||||
static const int cmdGetStats = 56; // v8+
|
||||
static const int cmdSendAnonReq = 57;
|
||||
static const int cmdSetAutoaddConfig = 58;
|
||||
static const int cmdGetAutoaddConfig = 59;
|
||||
static const int cmdGetAllowedRepeatFreq = 60;
|
||||
|
||||
// Response Codes (Device -> App)
|
||||
static const int respOk = 0;
|
||||
@@ -58,8 +74,8 @@ class MeshCoreConstants {
|
||||
static const int respEndOfContacts = 4;
|
||||
static const int respSelfInfo = 5;
|
||||
static const int respSent = 6;
|
||||
static const int respContactMsgRecv = 7;
|
||||
static const int respChannelMsgRecv = 8;
|
||||
static const int respContactMsgRecv = 7; // firmware ver < 3
|
||||
static const int respChannelMsgRecv = 8; // firmware ver < 3
|
||||
static const int respCurrTime = 9;
|
||||
static const int respNoMoreMessages = 10;
|
||||
static const int respExportContact = 11;
|
||||
@@ -67,12 +83,17 @@ class MeshCoreConstants {
|
||||
static const int respDeviceInfo = 13;
|
||||
static const int respPrivateKey = 14;
|
||||
static const int respDisabled = 15;
|
||||
static const int respContactMsgRecvV3 = 16; // firmware ver >= 3 (adds SNR header)
|
||||
static const int respChannelMsgRecvV3 = 17; // firmware ver >= 3 (adds SNR header)
|
||||
static const int respChannelInfo = 18;
|
||||
static const int respSignStart = 19;
|
||||
static const int respSignature = 20;
|
||||
static const int respCustomVars = 21;
|
||||
static const int respAdvertPath = 22;
|
||||
static const int respTuningParams = 21; // Same as respCustomVars per protocol
|
||||
static const int respTuningParams = 23;
|
||||
static const int respStats = 24; // v8+
|
||||
static const int respAutoaddConfig = 25;
|
||||
static const int respAllowedRepeatFreq = 26;
|
||||
|
||||
// Push Codes (Device -> App, unsolicited)
|
||||
static const int pushAdvert = 0x80;
|
||||
@@ -88,6 +109,15 @@ class MeshCoreConstants {
|
||||
static const int pushNewAdvert = 0x8A;
|
||||
static const int pushTelemetryResponse = 0x8B;
|
||||
static const int pushBinaryResponse = 0x8C;
|
||||
static const int pushPathDiscoveryResponse = 0x8D;
|
||||
static const int pushControlData = 0x8E; // v8+
|
||||
static const int pushContactDeleted = 0x8F; // contact overwritten when contacts full
|
||||
static const int pushContactsFull = 0x90; // contacts storage is full
|
||||
|
||||
// Stats sub-types for cmdGetStats
|
||||
static const int statsTypeCore = 0;
|
||||
static const int statsTypeRadio = 1;
|
||||
static const int statsTypePackets = 2;
|
||||
|
||||
// Error Codes
|
||||
static const int errUnsupportedCmd = 1;
|
||||
|
||||
@@ -59,6 +59,10 @@ class MeshCoreOpcodeNames {
|
||||
return 'SEND_LOGIN';
|
||||
case MeshCoreConstants.cmdSendStatusReq:
|
||||
return 'SEND_STATUS_REQ';
|
||||
case MeshCoreConstants.cmdHasConnection:
|
||||
return 'HAS_CONNECTION';
|
||||
case MeshCoreConstants.cmdLogout:
|
||||
return 'LOGOUT';
|
||||
case MeshCoreConstants.cmdGetContactByKey:
|
||||
return 'GET_CONTACT_BY_KEY';
|
||||
case MeshCoreConstants.cmdGetChannel:
|
||||
@@ -73,12 +77,40 @@ class MeshCoreOpcodeNames {
|
||||
return 'SIGN_FINISH';
|
||||
case MeshCoreConstants.cmdSendTracePath:
|
||||
return 'SEND_TRACE_PATH';
|
||||
case MeshCoreConstants.cmdSetDevicePin:
|
||||
return 'SET_DEVICE_PIN';
|
||||
case MeshCoreConstants.cmdSetOtherParams:
|
||||
return 'SET_OTHER_PARAMS';
|
||||
case MeshCoreConstants.cmdSendTelemetryReq:
|
||||
return 'SEND_TELEMETRY_REQ';
|
||||
case MeshCoreConstants.cmdGetCustomVars:
|
||||
return 'GET_CUSTOM_VARS';
|
||||
case MeshCoreConstants.cmdSetCustomVar:
|
||||
return 'SET_CUSTOM_VAR';
|
||||
case MeshCoreConstants.cmdGetAdvertPath:
|
||||
return 'GET_ADVERT_PATH';
|
||||
case MeshCoreConstants.cmdGetTuningParams:
|
||||
return 'GET_TUNING_PARAMS';
|
||||
case MeshCoreConstants.cmdSendBinaryReq:
|
||||
return 'SEND_BINARY_REQ';
|
||||
case MeshCoreConstants.cmdFactoryReset:
|
||||
return 'FACTORY_RESET';
|
||||
case MeshCoreConstants.cmdSendPathDiscoveryReq:
|
||||
return 'SEND_PATH_DISCOVERY_REQ';
|
||||
case MeshCoreConstants.cmdSetFloodScope:
|
||||
return 'SET_FLOOD_SCOPE';
|
||||
case MeshCoreConstants.cmdSendControlData:
|
||||
return 'SEND_CONTROL_DATA';
|
||||
case MeshCoreConstants.cmdGetStats:
|
||||
return 'GET_STATS';
|
||||
case MeshCoreConstants.cmdSendAnonReq:
|
||||
return 'SEND_ANON_REQ';
|
||||
case MeshCoreConstants.cmdSetAutoaddConfig:
|
||||
return 'SET_AUTOADD_CONFIG';
|
||||
case MeshCoreConstants.cmdGetAutoaddConfig:
|
||||
return 'GET_AUTOADD_CONFIG';
|
||||
case MeshCoreConstants.cmdGetAllowedRepeatFreq:
|
||||
return 'GET_ALLOWED_REPEAT_FREQ';
|
||||
default:
|
||||
return 'CMD_UNKNOWN';
|
||||
}
|
||||
@@ -119,12 +151,28 @@ class MeshCoreOpcodeNames {
|
||||
return 'PRIVATE_KEY';
|
||||
case MeshCoreConstants.respDisabled:
|
||||
return 'DISABLED';
|
||||
case MeshCoreConstants.respContactMsgRecvV3:
|
||||
return 'CONTACT_MSG_RECV_V3';
|
||||
case MeshCoreConstants.respChannelMsgRecvV3:
|
||||
return 'CHANNEL_MSG_RECV_V3';
|
||||
case MeshCoreConstants.respChannelInfo:
|
||||
return 'CHANNEL_INFO';
|
||||
case MeshCoreConstants.respSignStart:
|
||||
return 'SIGN_START';
|
||||
case MeshCoreConstants.respSignature:
|
||||
return 'SIGNATURE';
|
||||
case MeshCoreConstants.respCustomVars:
|
||||
return 'CUSTOM_VARS';
|
||||
case MeshCoreConstants.respAdvertPath:
|
||||
return 'ADVERT_PATH';
|
||||
case MeshCoreConstants.respTuningParams:
|
||||
return 'TUNING_PARAMS';
|
||||
case MeshCoreConstants.respStats:
|
||||
return 'STATS';
|
||||
case MeshCoreConstants.respAutoaddConfig:
|
||||
return 'AUTOADD_CONFIG';
|
||||
case MeshCoreConstants.respAllowedRepeatFreq:
|
||||
return 'ALLOWED_REPEAT_FREQ';
|
||||
default:
|
||||
return 'RESP_UNKNOWN';
|
||||
}
|
||||
@@ -159,6 +207,14 @@ class MeshCoreOpcodeNames {
|
||||
return 'TELEMETRY_RESPONSE';
|
||||
case MeshCoreConstants.pushBinaryResponse:
|
||||
return 'BINARY_RESPONSE';
|
||||
case MeshCoreConstants.pushPathDiscoveryResponse:
|
||||
return 'PATH_DISCOVERY_RESPONSE';
|
||||
case MeshCoreConstants.pushControlData:
|
||||
return 'CONTROL_DATA';
|
||||
case MeshCoreConstants.pushContactDeleted:
|
||||
return 'CONTACT_DELETED';
|
||||
case MeshCoreConstants.pushContactsFull:
|
||||
return 'CONTACTS_FULL';
|
||||
default:
|
||||
return 'PUSH_UNKNOWN';
|
||||
}
|
||||
|
||||
@@ -59,6 +59,23 @@ class FrameParser {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Parse ContactMessage V3 response (firmware ver >= 3)
|
||||
/// V3 prepends 3 bytes: [snr_scaled(int8)][reserved][reserved]
|
||||
/// snr_dB = snr_scaled / 4.0
|
||||
static Message parseContactMessageV3(BufferReader reader) {
|
||||
reader.readInt8(); // snr scaled by 4 (ignored for now)
|
||||
reader.readBytes(2); // reserved
|
||||
return parseContactMessage(reader);
|
||||
}
|
||||
|
||||
/// Parse ChannelMessage V3 response (firmware ver >= 3)
|
||||
/// V3 prepends 3 bytes: [snr_scaled(int8)][reserved][reserved]
|
||||
static Message parseChannelMessageV3(BufferReader reader) {
|
||||
reader.readInt8(); // snr scaled by 4 (ignored for now)
|
||||
reader.readBytes(2); // reserved
|
||||
return parseChannelMessage(reader);
|
||||
}
|
||||
|
||||
/// Parse ContactMessage response
|
||||
static Message parseContactMessage(BufferReader reader) {
|
||||
final pubKeyPrefix = reader.readBytes(6);
|
||||
|
||||
Reference in New Issue
Block a user