Registering Ble profiles works just fine with the simulator, simulating a VivoActive 4, and a Nordic nRF52.
Registering Ble profiles when the app runs on a VivoActive 4 is only successful for the 1st profile registered.
Every 2nd and 3rd register fails or better returns state value 2.
This value is not defined in the enumerators of BlueToothLowEnergy.
As a result any app registering more then 1 profile doesn't work on a VivoActive 4.
Changing the order of registering profiles does not help, always only the 1st is SUCCESSful.
There is no difference in results if you call registerProfile, 3 times, and then Ble.setScanState(Ble.SCAN_STATE_SCANNING) or
first call Ble.setScanState(Ble.SCAN_STATE_SCANNING) and then call registerProfile, 3 times.
Log file of the console with the simulator, see BleProfileTest_OK.TXT
Log file of the VivoActive 4, see BleProfileTest_ERROR.TXT
ble:initialize
bleInitProfiles1 avail:3
bleInitProfiles2 avail:3
bleInitProfiles3 avail:3
bleInitProfiles done:3
ble:setScanState SCAN_STATE_SCANNING
ble:onScanStateChange SCAN_STATE_SCANNING SUCCESS
ble:onProfileRegister 0000180F-0000-1000-8000-00805F9B34FB SUCCESS
ble:onProfileRegister 000018EF-5348-494D-414E-4F5F424C4500 STATE_ERROR ? 2
ble:onProfileRegister 000018FE-1212-EFDE-1523-785FEABCD123 STATE_ERROR ? 2
ble:onScanResults avail:3
ble:onScanResults avail:3
ble:onScanResults avail:3
The watch app, see code, registers 3 profiles and prints the results of the BleDelegate callback functions.
using Toybox.BluetoothLowEnergy as Ble; class TestBleDelegate extends Ble.BleDelegate { var batteryServiceUuid = Ble.stringToUuid("0000180f-0000-1000-8000-00805f9b34fb"); var batteryCharacteristicUuid = Ble.stringToUuid("00002a19-0000-1000-8000-00805f9b34fb"); var modeServiceUuid = Ble.stringToUuid("000018ef-5348-494d-414e-4f5f424c4500"); var modeCharacteristicUuid = Ble.stringToUuid("00002ac1-5348-494d-414e-4f5f424c4500"); var MACServiceUuid = Ble.stringToUuid("000018fe-1212-efde-1523-785feabcd123"); var MACCharacteristicUuid = Ble.stringToUuid("00002ae3-1212-efde-1523-785feabcd123"); //========================================================== function bleInitProfiles() { var profile1 = { :uuid => batteryServiceUuid, :characteristics => [ { :uuid => batteryCharacteristicUuid } ] }; var profile2 = { :uuid => modeServiceUuid, :characteristics => [ { :uuid => modeCharacteristicUuid, :descriptors => [ Ble.cccdUuid() ] } ] }; var profile3 = { :uuid => MACServiceUuid, :characteristics => [ { :uuid => MACCharacteristicUuid } ] }; try { System.println("bleInitProfiles1 avail:" + Ble.getAvailableConnectionCount() ); Ble.registerProfile(profile1); System.println("bleInitProfiles2 avail:" + Ble.getAvailableConnectionCount() ); Ble.registerProfile(profile2); System.println("bleInitProfiles3 avail:" + Ble.getAvailableConnectionCount() ); Ble.registerProfile(profile3); System.println("bleInitProfiles done:" + Ble.getAvailableConnectionCount() ); } catch (e) { System.println("catch = " + e.getErrorMessage()); } } //========================================================== function initialize() { System.println("ble:initialize"); BleDelegate.initialize(); bleInitProfiles(); System.println("ble:setScanState SCAN_STATE_SCANNING"); Ble.setScanState(Ble.SCAN_STATE_SCANNING); } function onCharacteristicChanged(characteristic, value) { System.println("ble:onCharacteristicChanged "+ characteristic.getUuid().toString() + " " + value); } function onCharacteristicRead(characteristic, status, value) { System.println("ble:onCharacteristicRead "+ characteristic.getUuid().toString() + " " + stateToString(status) + " " + value); } function onCharacteristicWrite(characteristic, status) { System.println("ble:onCharacteristicWrite "+ characteristic.getUuid().toString() + " " + stateToString(status)); } function onConnectedStateChanged(device, connectionState) { System.println("ble:onConnectedStateChanged " + device + " " + connectionStateToString(connectionState)); } function onDescriptorRead(descriptor, status, value) { System.println("ble:onDescriptorRead " + descriptor.getCharacteristic().getUuid().toString() + " " + stateToString(status) + " " + value); } function onDescriptorWrite(descriptor, status) { System.println("ble:onDescriptorWrite " + descriptor.getCharacteristic().getUuid().toString() + " " + stateToString(status)); } function onProfileRegister(uuid, status) { System.println("ble:onProfileRegister " + uuid.toString() + " " + stateToString(status)); } function onScanResults(scanResults) { System.println("ble:onScanResults avail:" + Ble.getAvailableConnectionCount() ); } function onScanStateChange(scanState, status) { System.println("ble:onScanStateChange " + scanStateToString(scanState) +" "+ stateToString(status)); } //====================================================== private function stateToString(state){ switch(state){ case Ble.STATUS_NOT_ENOUGH_RESOURCES: { return "NOT_ENOUGH_RESOURCES"; } case Ble.STATUS_READ_FAIL: { return "READ_FAIL"; } case Ble.STATUS_SUCCESS: { return "SUCCESS"; } case Ble.STATUS_WRITE_FAIL: { return "WRITE_FAIL"; } } return "STATE_ERROR ? " + state; } private function scanStateToString(state){ switch(state){ case Ble.SCAN_STATE_OFF: { return "SCAN_STATE_OFF"; } case Ble.SCAN_STATE_SCANNING: { return "SCAN_STATE_SCANNING"; } } return "SCAN_STATE_ERROR ? " + state; } private function connectionStateToString(state){ switch(state){ case Ble.CONNECTION_STATE_CONNECTED: { return "CONNECTED"; } case Ble.CONNECTION_STATE_DISCONNECTED: { return "DISCONNECTED"; } case Ble.CONNECTION_STATE_NOT_CONNECTED: { return "NOT_CONNECTED"; } case Ble.CONNECTION_STATE_NOT_INITIALIZED: { return "NOT_INITIALIZED"; } } return "CONNECTION_STATE_ERROR ? " + state; } }
using Toybox.Application; using Toybox.WatchUi; using Toybox.BluetoothLowEnergy as Ble; class BleProfileTestApp extends Application.AppBase { private var view; function initialize() { AppBase.initialize(); } // onStart() is called on application start up function onStart(state) { } // onStop() is called when your application is exiting function onStop(state) { } // Return the initial view of your application here function getInitialView() { view = new BleProfileTestView(); Ble.setDelegate(new TestBleDelegate()); return [ view, new BleProfileTestDelegate() ]; } }