ByteArray empty during BLE onCharacteristicRead() call, unsure how to correct the issue.

Was unable to find a similar enough problem on the existing forum posts.  Any help will be appreciated.

Attempting to implement BLE within an Edge1030 CIQ app, to work with custom hardware/firmware.

Testing is done through the Simulator current, with the nRF Connect simulator setup.

CIQ SDK 7.4.3.  App is being written in VSCode.

Have gotten as far with the BLE implementation as to pair the device and call the following onCharacteristicRead() function:

  • On, that screen shot only shows what you can get for weather.  There's a bunch of different services.  (you can use up to 3).  With the ui service, there is a led you can control and a button you can get input from.  And with the speaker service, make sounds (see the coin collector sample)


    //see 
    // https://nordicsemiconductor.github.io/Nordic-Thingy52-FW/documentation/firmware_architecture.html    
        
        var PI_SERVICE                              = Ble.longToUuid(uuid1+0x010000000000L, uuid2);
    // config service
        /*public*/ var THINGY_CONFIGURATION_SERVICE = Ble.longToUuid(0xEF6801009B354933L, 0x9B1052FFA9740042L);
        //var THINGY_CONFIGURATION_SERVICE = Ble.longToUuid(uuid1+0x010000000000L, uuid2);
        /*public*/ var DEVNAME_CHARACTERISTIC       = Ble.longToUuid(0xEF6801019B354933L, 0x9B1052FFA9740042L);
        /*public*/ var ADVERT_CHARACTERISTIC        = Ble.longToUuid(0xEF6801029B354933L, 0x9B1052FFA9740042L);
        /*public*/ var CONPARAM_CHARACTERISTIC      = Ble.longToUuid(0xEF6801049B354933L, 0x9B1052FFA9740042L);
        /*public*/ var EDDYSTONE_CHARACTERISTIC     = Ble.longToUuid(0xEF6801059B354933L, 0x9B1052FFA9740042L);
        /*public*/ var CLOUD_CHARACTERISTIC         = Ble.longToUuid(0xEF6801069B354933L, 0x9B1052FFA9740042L);
        /*public*/ var FWVERSION_CHARACTERISTIC     = Ble.longToUuid(0xEF6801079B354933L, 0x9B1052FFA9740042L);
        /*public*/ var MTU_CHARACTERISTIC           = Ble.longToUuid(0xEF6801089B354933L, 0x9B1052FFA9740042L);
        /*public*/ var NFCTAG_CHARACTERISTIC        = Ble.longToUuid(0xEF6801099B354933L, 0x9B1052FFA9740042L);
    
    //env service
        /*public*/ var THINGY_ENVIRONMENTAL_SERVICE = Ble.longToUuid(0xEF6802009B354933L, 0x9B1052FFA9740042L);
        /*public*/ var TEMPERATURE_CHARACTERISTIC   = Ble.longToUuid(0xEF6802019B354933L, 0x9B1052FFA9740042L);
        /*public*/ var PRESSURE_CHARACTERISTIC      = Ble.longToUuid(0xEF6802029B354933L, 0x9B1052FFA9740042L);
        /*public*/ var HUMIDITY_CHARACTERISTIC      = Ble.longToUuid(0xEF6802039B354933L, 0x9B1052FFA9740042L);
        /*public*/ var AIR_QUALITY_CHARACTERISTIC   = Ble.longToUuid(0xEF6802049B354933L, 0x9B1052FFA9740042L);
        /*public*/ var COLOR_CHARACTERISTIC         = Ble.longToUuid(0xEF6802059B354933L, 0x9B1052FFA9740042L);
        /*public*/ var ENVCFG_CHARACTERISTIC        = Ble.longToUuid(0xEF6802069B354933L, 0x9B1052FFA9740042L);
    
    //ui service
    	/*public*/ var THINGY_UI_SERVICE            = Ble.longToUuid(0xEF6803009B354933L, 0x9B1052FFA9740042L);
    	/*public*/ var LED_CHARACTERISTIC           = Ble.longToUuid(0xEF6803019B354933L, 0x9B1052FFA9740042L); 
    	/*public*/ var BUTTON_CHARACTERISTIC        = Ble.longToUuid(0xEF6803029B354933L, 0x9B1052FFA9740042L);
    	/*public*/ var EXTPIN_CHARACTERISTIC        = Ble.longToUuid(0xEF6803039B354933L, 0x9B1052FFA9740042L);     
    
    //motion service
        /*public*/ var THINGY_MOTION_SERVICE        = Ble.longToUuid(0xEF6804009B354933L, 0x9B1052FFA9740042L);
        /*public*/ var MOTCFG_CHARACTERISTIC        = Ble.longToUuid(0xEF6804019B354933L, 0x9B1052FFA9740042L);
        /*public*/ var TAP_CHARACTERISTIC           = Ble.longToUuid(0xEF6804029B354933L, 0x9B1052FFA9740042L);
        /*public*/ var ORIENTATION_CHARACTERISTIC   = Ble.longToUuid(0xEF6804039B354933L, 0x9B1052FFA9740042L);
        /*public*/ var QUATERNION_CHARACTERISTIC    = Ble.longToUuid(0xEF6804049B354933L, 0x9B1052FFA9740042L);    
        /*public*/ var STEPS_CHARACTERISTIC         = Ble.longToUuid(0xEF6804059B354933L, 0x9B1052FFA9740042L);
        /*public*/ var MOTRAW_CHARACTERISTIC        = Ble.longToUuid(0xEF6804069B354933L, 0x9B1052FFA9740042L);    
        /*public*/ var EULER_CHARACTERISTIC         = Ble.longToUuid(0xEF6804079B354933L, 0x9B1052FFA9740042L);
        /*public*/ var ROTMATRIX_CHARACTERISTIC     = Ble.longToUuid(0xEF6804089B354933L, 0x9B1052FFA9740042L);
        /*public*/ var HEADING_CHARACTERISTIC       = Ble.longToUuid(0xEF6804099B354933L, 0x9B1052FFA9740042L);
    	/*public*/ var GRAVITY_CHARACTERISTIC       = Ble.longToUuid(0xEF68040A9B354933L, 0x9B1052FFA9740042L);    
    
    //speaker service
        /*public*/ var THINGY_SPEAKER_SERVICE       = Ble.longToUuid(0xEF6805009B354933L, 0x9B1052FFA9740042L);
        /*public*/ var SPKCFG_CHARACTERISTIC        = Ble.longToUuid(0xEF6805019B354933L, 0x9B1052FFA9740042L);
        /*public*/ var SPKDATA_CHARACTERISTIC       = Ble.longToUuid(0xEF6805029B354933L, 0x9B1052FFA9740042L);
        /*public*/ var SPKSTAT_CHARACTERISTIC       = Ble.longToUuid(0xEF6805039B354933L, 0x9B1052FFA9740042L);
        /*public*/ var MIKE_CHARACTERISTIC          = Ble.longToUuid(0xEF6805039B354933L, 0x9B1052FFA9740042L);
    
    // battery service
    	var THINGY_BATTERY_SERVICE       = Ble.longToUuid(0x0000180f00001000L, 0x800000805f9b34fbL);
        var BATTERY_LEVEL_CHARACTERISTIC = Ble.longToUuid(0x00002a1900001000L, 0x800000805f9b34fbL);

  • uuids match, verified.

    Pairing successful, verified.

    Not sure why this line in onChracteristicRead() crashed the simulator:

    But when switching from a requestRead() to a cccd.requestWrite, as shown here:

    Now able to print to the debug console using this function in the BLE delegate:

    Will be looking into all the postings on queuing next and understanding how to manage the notifications.  Appreciate that the Thing52 device is all setup for ble, unfortunately working with custom hardware on this project.  Have been following the sample code for Thingy52, Thing52CoinCollector and the RaspPi app code you provide (much appreciated).

    Unclear why directly calling value.decodeNumber() in the onCharacteristicRead() fails.  New to using BLE and CIQ, it's taking a bit to figure out.

  • Saw the documentation mentioning max three services.  Was unclear if multiple services could be registered under a single registerProfile() call?

    All the sample code only registers a single service under a registerProfile() call

  • Again, what do you see for the status when onCharacteristicRead is called?  You notice there is no status for onCharacteristicChanged, because it won't be called if there is a bad status.

    In my thingy52 test app, I have this:

        function registerProfiles() {
            try {      
                Ble.registerProfile( _envProfileDef );
                Ble.registerProfile( _uiProfileDef );     
                //Ble.registerProfile( _motProfileDef );
                Ble.registerProfile( _spkProfileDef );        
                //Ble.registerProfile( _batProfileDef );
            } catch(e) {
                System.println("e="+e.getErrorMessage());
            }
        }
    }

    It's set to use the env, ui, and speaker services.  Others are commented out and the try/catch is there if I use too many.  So when I run my test app, I get the env data, turn the led on, and beep the speaker when connected.

  • For the onCharacteristicRead() call:

    My understanding is the status is BluetoothLowEnergy.STATUS_SUCCESS (line 95-98) and the following Debug Console output:

    Am I misunderstanding something?

  • And againg, the byte array has a size of zero, and you get the crash because you are telling decodeNumber which is expecting 4 bytes.

    surrounding the like that causes the crach with an if statement

    if(value.size()>=4) {(here)}

    As far as why it's a size of 0, are you sure that's due to the "other end"?

  • status is BluetoothLowEnergy.STATUS_SUCCESS

    According to the API docs:

    value(Lang.ByteArray) — Characteristic value that was read. null if status is not STATUS_SUCCESS

    In other words, if you were expecting the status to indicate an error because the byte array is 0-length or vice versa, that's apparently not how it works. It seems that the byte array value will be null if the status indicates an error (and vice versa).

    Similarly, just because status is STATUS_SUCCESS, doesn't mean you read enough data for your purposes.

    [1/x]

  • Unclear why directly calling value.decodeNumber() in the onCharacteristicRead() fails. 

    As jim_m_58 said, it's because the byte array doesn't have enough data for the specified format, which is basically what the error message says: "format is too large for array"

    // System.println("value as a numeric SINT16 = " + value.decodeNumber (Lang.NUMBER_FORMAT_SINT16, {}));

    ^ In this case (if you this code was actually uncommented), the above line would crash because NUMBER_FORMAT_SINT16 requires 2 bytes, but value contains 0 bytes. SINT16 is a signed 16-bit integer, which requires a byte array containing at least 2 bytes (8 bits = 1 byte). (Any additional bytes will be ignored.)

    System.println("value as a numeric SINT32 = " + value.decodeNumber (Lang.NUMBER_FORMAT_SINT32, {})) ;

    ^ This line is crashing because NUMBER_FORMAT_SINT32 requires 4 bytes, but value contains 0 bytes.

    The problem is that you are apparently expecting to get 4 bytes back in onCharacteristicRead() (or perhaps 2 bytes), but you are getting 0 bytes.

    It makes sense that decodeNumber will throw an exception if you ask it to decode a byte array which doesn't have enough data to fulfill the requested number format, since decodeNumber returns a Numeric value (and there's no possibility to return null, for example, if decoding fails.)

    For example, what value would you expect the following code to print if it didn't crash?

    var byteArray = []b;
    System.println(byteArray.decodeNumber(Lang.NUMBER_FORMAT_SINT32, {}));

    A 32-bit integer has 4 bytes, so there's no way to decode 0 bytes to produce a 32-bit integer.

    The real question is: why are you reading 0 bytes in the first place? (I have no idea)

    [2/2]

  • Update on the learning developments from this thread:

    Had to write in BLE queuing in order to test the SERVICE without crashing the app.  Modelled the queue similar to s RaspPi `CommQueue.mc`.  Without queuing significant problems were experienced.  A queue with as low as 1s delay before next BLE Delegate function call corrected this.

    - can successfully perform characteristic reads, however, the characteristics always returns an empty array during a read.  Issue as to 'why no value is on the characteristic during a read' has been isolated to within firmware.  Currently, investigating firmware to find out how to correct this.

    - can successfully read or write to the descriptors, turning on/off notifications

    - descriptors can be read properly to confirm correct values

    - characteristic is sending expected values when descriptor is set to `notify`

    This discussion has been very helpful for what to investigate while learning to control BLE.  Everyone's guidance is appreciated.

    Currently trying to switch to custom Uuids rather that just broadcasting to Thingy nRF recognized uuids.  Seems like either vscode or nRF has the old uuids cached somewhere, since even though the uuids have been changes in the mc registration profile and in firmware, the onScanResults() still sees the old uuids.

  • Do you have access to the BLE profile for your sensor?  That can tell you a great deal about what you can do

    For example, here's the details for the Thiny52.  Notice where is talks about if read/write/notify are allowed for a specific characteristic.

    https://nordicsemiconductor.github.io/Nordic-Thingy52-FW/documentation/firmware_architecture.html

    Maybe you are trying to read one that only supports notify, for example.