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() ];
}
}