diff --git a/ios/Runner.app.dSYM.zip b/ios/Runner.app.dSYM.zip
index 571e481..2d0a1fe 100644
Binary files a/ios/Runner.app.dSYM.zip and b/ios/Runner.app.dSYM.zip differ
diff --git a/ios/Runner.ipa b/ios/Runner.ipa
index f20f106..0ce6b15 100644
Binary files a/ios/Runner.ipa and b/ios/Runner.ipa differ
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index ad54059..8e7b361 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -489,7 +489,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -511,7 +511,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = JND55328G8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -530,7 +530,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = JND55328G8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -547,7 +547,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = JND55328G8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -679,7 +679,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -702,7 +702,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 13a4ca8..d073400 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -43,7 +43,7 @@
CFBundleSignature
????
CFBundleVersion
- 41
+ 42
LSRequiresIPhoneOS
NSBluetoothAlwaysUsageDescription
diff --git a/lib/providers/app_provider.dart b/lib/providers/app_provider.dart
index b3d0fca..d7b3ea4 100644
--- a/lib/providers/app_provider.dart
+++ b/lib/providers/app_provider.dart
@@ -245,6 +245,25 @@ class AppProvider with ChangeNotifier {
});
};
+ // When an advertisement is received (PUSH_CODE_ADVERT 0x80)
+ // This may be sent by the radio for existing contacts instead of PUSH_CODE_NEW_ADVERT (0x8A)
+ connectionProvider.onAdvertReceived = (publicKey) {
+ debugPrint('๐ก [AppProvider] Advertisement received: ${publicKey.sublist(0, 6).map((b) => b.toRadixString(16).padLeft(2, '0')).join(':')}...');
+ // Check if this is an existing contact that might have updated location
+ final contact = contactsProvider.findContactByKey(publicKey);
+ if (contact != null) {
+ debugPrint(' Existing contact "${contact.advName}" - triggering contact sync for updates');
+ // Trigger a contact sync to get the updated contact information
+ Future.delayed(const Duration(milliseconds: 100), () {
+ if (connectionProvider.deviceInfo.isConnected) {
+ connectionProvider.getContacts();
+ }
+ });
+ } else {
+ debugPrint(' New contact - waiting for PUSH_CODE_NEW_ADVERT (0x8A) with full details');
+ }
+ };
+
// When a message is sent (RESP_CODE_SENT received)
connectionProvider.onMessageSent = (messageId, expectedAckTag, suggestedTimeoutMs) {
debugPrint('๐ค [AppProvider] Message sent - Message ID: $messageId, ACK tag: $expectedAckTag');
diff --git a/lib/providers/connection_provider.dart b/lib/providers/connection_provider.dart
index 38423d0..db8aa1d 100644
--- a/lib/providers/connection_provider.dart
+++ b/lib/providers/connection_provider.dart
@@ -130,6 +130,7 @@ class ConnectionProvider with ChangeNotifier {
Function(int channelIdx, String channelName)? onChannelInfoReceived;
Function(Uint8List publicKeyPrefix, int tag, Uint8List responseData)?
onBinaryResponse;
+ Function(Uint8List publicKey)? onAdvertReceived;
Function(Uint8List publicKey)? onPathUpdated;
Function(Uint8List publicKeyPrefix, int permissions, bool isAdmin, int tag)?
onLoginSuccess;
@@ -262,10 +263,14 @@ class ConnectionProvider with ChangeNotifier {
};
_bleService.onContactReceived = (contact) {
+ debugPrint('๐ฅ [Provider] Contact received (0x8A): "${contact.advName}"');
+ debugPrint(' Forwarding to AppProvider via onContactReceived callback');
onContactReceived?.call(contact);
};
_bleService.onContactsComplete = (contacts) {
+ debugPrint('๐ฅ [Provider] Contacts sync complete: ${contacts.length} contacts');
+ debugPrint(' Forwarding to AppProvider via onContactsComplete callback');
onContactsComplete?.call(contacts);
};
@@ -286,8 +291,14 @@ class ConnectionProvider with ChangeNotifier {
};
_bleService.onTelemetryReceived = (publicKey, lppData) {
+ debugPrint('๐ฅ [Provider] Telemetry response (0x8B) received');
+ debugPrint(
+ ' Public key: ${publicKey.sublist(0, 6).map((b) => b.toRadixString(16).padLeft(2, '0')).join(':')}...',
+ );
+ debugPrint(' LPP data: ${lppData.length} bytes');
// Mark ping as successful if this was a ping request
_pingTracker.markPingSuccessful(publicKey);
+ debugPrint(' Forwarding to AppProvider via onTelemetryReceived callback');
onTelemetryReceived?.call(publicKey, lppData);
};
@@ -362,11 +373,10 @@ class ConnectionProvider with ChangeNotifier {
debugPrint(
' Public key: ${publicKey.sublist(0, 6).map((b) => b.toRadixString(16).padLeft(2, '0')).join(':')}...',
);
- debugPrint(
- ' Note: Waiting for PUSH_CODE_NEW_ADVERT (0x8A) with full contact details',
- );
- // The companion radio will automatically send PUSH_CODE_NEW_ADVERT if manual_add_contacts=0
- // which will trigger onContactReceived callback and add/update the contact
+ // Forward to AppProvider to trigger contact update
+ // The radio may send only PUSH_CODE_ADVERT (0x80) for existing contacts
+ // instead of PUSH_CODE_NEW_ADVERT (0x8A), so we need to handle this
+ onAdvertReceived?.call(publicKey);
};
_bleService.onPathUpdated = (publicKey) {
diff --git a/lib/services/ble/ble_response_handler.dart b/lib/services/ble/ble_response_handler.dart
index 5ad285d..3133e58 100644
--- a/lib/services/ble/ble_response_handler.dart
+++ b/lib/services/ble/ble_response_handler.dart
@@ -409,11 +409,13 @@ class BleResponseHandler {
}
}
- /// Handle Advert push
+ /// Handle Advert push (0x80) - basic advertisement with public key only
void _handleAdvert(BufferReader reader) {
try {
final publicKey = FrameParser.parseAdvert(reader);
if (publicKey != null) {
+ final shortKey = publicKey.sublist(0, 8).map((b) => b.toRadixString(16).padLeft(2, '0')).join('');
+ debugPrint(' โ
[Advert 0x80] From node: $shortKey... (public key only, no location data)');
onAdvertReceived?.call(publicKey);
}
debugPrint(' โ
[Advert] Parsed successfully');
@@ -856,14 +858,20 @@ class BleResponseHandler {
debugPrint(' ๐งน [Echo] Cleaned up ${toRemove.length} old trackers');
}
- /// Handle NewAdvert push
+ /// Handle NewAdvert push (0x8A) - full contact info with location
void _handleNewAdvert(BufferReader reader) {
try {
final contact = FrameParser.parseContact(reader);
- debugPrint(' โ
[NewAdvert] Parsed successfully: ${contact.advName}');
+ debugPrint(' โ
[NewAdvert 0x8A] Parsed successfully: ${contact.advName}');
debugPrint(
' outPathLen: ${contact.outPathLen} (${contact.pathDescription})',
);
+ if (contact.advLat != 0 || contact.advLon != 0) {
+ final location = contact.advertLocation;
+ if (location != null) {
+ debugPrint(' ๐ Location: ${location.latitude}, ${location.longitude}');
+ }
+ }
onContactReceived?.call(contact);
} catch (e) {
debugPrint(' โ [NewAdvert] Parsing error: $e');
diff --git a/lib/services/meshcore_ble_service.dart b/lib/services/meshcore_ble_service.dart
index 4cac04b..98041ca 100644
--- a/lib/services/meshcore_ble_service.dart
+++ b/lib/services/meshcore_ble_service.dart
@@ -122,15 +122,19 @@ class MeshCoreBleService {
// Response handler callbacks
_responseHandler.onContactReceived = (contact) {
+ debugPrint('๐ [BleService] onContactReceived - "${contact.advName}" - forwarding to ConnectionProvider');
onContactReceived?.call(contact);
};
_responseHandler.onContactsComplete = (contacts) {
+ debugPrint('๐ [BleService] onContactsComplete - ${contacts.length} contacts - forwarding to ConnectionProvider');
onContactsComplete?.call(contacts);
};
_responseHandler.onMessageReceived = (message) {
+ debugPrint('๐ [BleService] onMessageReceived - forwarding to ConnectionProvider');
onMessageReceived?.call(message);
};
_responseHandler.onTelemetryReceived = (publicKey, lppData) {
+ debugPrint('๐ [BleService] onTelemetryReceived - ${lppData.length} bytes - forwarding to ConnectionProvider');
onTelemetryReceived?.call(publicKey, lppData);
};
_responseHandler.onSelfInfoReceived = (selfInfo) {
@@ -160,9 +164,11 @@ class MeshCoreBleService {
onLoginFail?.call(publicKeyPrefix);
};
_responseHandler.onAdvertReceived = (publicKey) {
+ debugPrint('๐ [BleService] onAdvertReceived - forwarding to ConnectionProvider');
onAdvertReceived?.call(publicKey);
};
_responseHandler.onPathUpdated = (publicKey) {
+ debugPrint('๐ [BleService] onPathUpdated - forwarding to ConnectionProvider');
onPathUpdated?.call(publicKey);
};
_responseHandler.onMessageSent =