Crash in creating Fuser Data Route in Java

I have been experimenting with the Fuser in Java recently. I can't get it to work it keeps crashing every single time I run it, even though I followed the example from the documentation (https://mbientlab.com/androiddocs/latest/data_route.html#fuser).

I am using MetaWear SDK 3.7.1. I also tried 3.8.0 b00, with the same result.

Code, based on the FreeFall example:

public void onServiceConnected(ComponentName name, IBinder service) {
    BtleService.LocalBinder serviceBinder = (BtleService.LocalBinder) service;

    String mwMacAddress = "XX:XX:XX:XX:XX:XX";   ///< Removed MAC address for privacy reasons
    BluetoothManager btManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    BluetoothDevice btDevice = btManager.getAdapter().getRemoteDevice(mwMacAddress);

    mwBoard = serviceBinder.getMetaWearBoard(btDevice);
    mwBoard.connectAsync().onSuccessTask(task -> {
        Log.d(LOG_TAG, "connectAsync");

        final Accelerometer accelerometer = mwBoard.getModule(Accelerometer.class);
        accelerometer.configure()
                .odr(100f) // 100 Hz sample rate
                .range(4f) // +- 4g range
                .commit();
        accelCapture.set(accelerometer);
        final AsyncDataProducer acceleration;
        if (accelerometer instanceof AccelerometerBosch) {
            acceleration = ((AccelerometerBosch) accelerometer).acceleration();
        } else {
            acceleration = ((AccelerometerMma8452q) accelerometer).acceleration();
        }
        accelerationCapture.set(acceleration);

        final GyroBmi160 gyro = mwBoard.getModule(GyroBmi160.class);
        gyro.configure()
                .odr(GyroBmi160.OutputDataRate.ODR_100_HZ) // 100 Hz
                .range(GyroBmi160.Range.FSR_2000) // 2000 deg/s max
                .commit();
        gyroCapture.set(gyro);
        final AsyncDataProducer angularvelocity = gyro.angularVelocity();
        angvelCapture.set(angularvelocity);

        return angvelCapture.get().addRouteAsync(source -> source.buffer().name("gyro-buffer"))
                .onSuccessTask(ignored -> angvelCapture.get().addRouteAsync(source ->
                        source.fuse("gyro-buffer").stream((data, env) -> {
                            Data[] values = data.value(Data[].class);
                            Acceleration accdata = values[0].value(Acceleration.class);
                            Log.d(LOG_TAG, "acc = " + accdata.toString());
                            AngularVelocity gyrodata = values[1].value(AngularVelocity.class);
                            Log.d(LOG_TAG, "gyr = " + gyrodata.toString());
                        })))
                .continueWith((Continuation<Route, Void>) continuetask -> {
                    if (continuetask.isFaulted()) {
                        Log.e(LOG_TAG, mwBoard.isConnected() ? "Error setting up route" : "Error connecting", continuetask.getError());
                    } else {
                        Log.d(LOG_TAG, "Connected");
                        debug = mwBoard.getModule(Debug.class);
                    }

                    return null;
                });
    });
}

Stack trace:

2020-10-11 14:18:13.678 29267-29425/com.mbientlab.metawear.acquisition E/acquisition: Error setting up route
java.lang.NullPointerException: Attempt to read from field 'com.mbientlab.metawear.impl.DataTypeBase com.mbientlab.metawear.impl.DataProcessorImpl$Processor.state' on a null object reference
at com.mbientlab.metawear.impl.DataTypeBase.dataProcessorTransform(DataTypeBase.java:351)
at com.mbientlab.metawear.impl.FloatVectorData.dataProcessorTransform(FloatVectorData.java:57)
at com.mbientlab.metawear.impl.RouteComponentImpl.fuse(RouteComponentImpl.java:877)
at com.mbientlab.metawear.acquisition.MainActivity.lambda$null$4(MainActivity.java:153)
at com.mbientlab.metawear.acquisition.-$$Lambda$MainActivity$Ny3LVMOUTY5OPcoJHdUmJCqU4-s.configure(Unknown Source:0)
at com.mbientlab.metawear.impl.JseMetaWearBoard.createRoute(JseMetaWearBoard.java:1404)
at com.mbientlab.metawear.impl.JseMetaWearBoard.access$1100(JseMetaWearBoard.java:93)
at com.mbientlab.metawear.impl.JseMetaWearBoard$1.queueRouteBuilder(JseMetaWearBoard.java:312)
at com.mbientlab.metawear.impl.GyroBmi160Impl$2.addRouteAsync(GyroBmi160Impl.java:255)
at com.mbientlab.metawear.acquisition.MainActivity.lambda$null$5$MainActivity(MainActivity.java:152)
at com.mbientlab.metawear.acquisition.-$$Lambda$MainActivity$MtqEXyHIMj-gS7aooSVhtz_phuQ.then(Unknown Source:2)
at bolts.Task$15.run(Task.java:917)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)

I have extensively tried to debug this code. The crash occurs in line 351 of DataTypeBase.java:
346 case DataProcessorConfig.Fuser.ID: {
347 byte fusedLength = attributes.length();
348 DataProcessorConfig.Fuser casted = (DataProcessorConfig.Fuser) config;
349
350 for(byte id: casted.filterIds) {
351 fusedLength+= dpModule.activeProcessors.get(id).state.attributes.length();
352 }
353
354 return new Pair<>(new ArrayData(this, DATA_PROCESSOR, DataProcessorImpl.NOTIFY, new DataAttributes(new byte[] {fusedLength}, (byte) 1, (byte) 0, false)), null);

The problem here is that filterIds in the DataProcessorConfig.Fuser.config structure have been set to 0 for all buffer names specified as arguments to the fuser in the Fuser constructor. This result in id == 0 in the get(id), returning a null pointer and causing the crash on the state property.
It seems to me that Fuser.syncFilterIds() should have been called somewhere prior to executing this line, since that is where the buffer names are linked to activeProcessors using ids in the config. I have manually set the id to the right value, and the code continued to run. I can't see any way in which my code could influence this behaviour, so I don't know how to solve this. Any help would be kindly appreciated.

Sign In or Register to comment.