Complete
over 3 years ago

WERETECH-10085

Fix has been applied to update for VA4 in FW: 5.63

VivoActive 4: BleDelegate.onProfileRegister returns status value 2 on every 2nd and 3rd registerProfile

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

}