Advanced Features

High Frequency Streaming

Some developers may want to stream data from multiple motion sensors simultaneously or individually at frequencies higher than 100Hz. To accommodate this use case, acceleration, angular velocity, and magnetic field data have a packed output mode that combines 3 data samples into 1 ble packett increasing the data throughput by 3x.

// stream at 200Hz
accelerometer.Configure(odr: 200f, range: 4f);
await accelerometer.PackedAcceleration.AddRouteAsync(source =>
    source.Stream(data => Console.WriteLine(data.Value<Acceleration>()))
);
accelerometer.PackedAcceleration.Start();
accelerometer.Start();

In addition to using packed output, developers will also need to reduce the max connection interval to 7.5ms (11.25ms for Android M+). Reducing the max connection interval can also be used to speed up log downloads.

settings.EditBleConnParams(maxConnInterval: 7.5f);

Serialization

The internal state of the IMetaWearBoard interface can be saved to persist the object through app crashes or combined with the Macro ssystem to rebuild the object state after saved commands are executed. Use SerializeAsync to save the state to the local disk and call DeserializeAsync to restore the state.

With regards to data routes, the delegates that are used with the Stream and Log components cannot be serialized so you will need to reassign them after deserialization by calling AttachSubscriber.

public async Task SerializeAccRoute() {
    var route = await accelerometer.Acceleration.AddRouteAsync(source => source.Log());
    Console.WriteLine("route id = " + route.ID);
    // save route ID as well
    await metawear.SerializeAsync();
}

public async Task DeserializeAccRoute() {
    await metawear.DeserializeAsync();
    // deserialize route ID: uint id = ...
    var route = metawear.LookupRoute(id);
    route.AttachSubscriber(0, data => Console.WriteLine(data.Value<Acceleration>()));
}

Forwarding Data

As you may have noticed, there are variant Map and Filter components that accept strings rather than numbers. These strings are used to signify that right hand operands for math and comparison operations should come from the data producer, and will automatically update with the newest data vaues.

For example, lets say you wanted to find the difference between the y and x axis values for acceleration data. Setup the mapper to use the x-axis data by naming it then using the same name in the Map construct.

await accelerometer.Acceleration.AddRouteAsync(source =>
    source.Split()
        .Index(0).Name("x-axis")
        .Index(1).Delay(1).Map(Function2.Subtract, "x-axis")
            .Stream(data => Console.WriteLine("y - x = " + data.Value<float>())
);

You can use the same ideas to create feedback loops by passing in the name assigned to the source processor.

await metawear.GetModule<IGpio>().Pins[0].Adc.AddRouteAsync(source =>
    source.Filter(Comparison.Gt, "reference").Name("reference")
);

Data Token

The IDataToken interface is another mechanism for forwarding data. Unlike the string keys, IDataToken objects are used with the API functions that are not a part of the data route API.

var iswitch = metawear.GetModule<ISwitch>();
await iswitch.State.AddRouteAsync(source => source.Count().React(token => ibeacon.SetMajor(token)));

Anonymous Routes

Anonymous routes are a pared down variant of the IRoute interface that only has one subscriber. They are used to retrieved logged data from a board that was not programmed by the current device.

Because of the anonymous nature of the interface, users will need to rely on an identifier string to determine what kind of data is being passed to each route. Developers can manage these identifiers by calling GenerateIdentifier for every logging subscriber and hardcoding the strings into the anonymous routes.

// create a route to log gyro y-axis data
var route = await metawear.GetModule<IGyroBmi160>().AngularVelocity.AddRouteAsync(source =>
    source.Split().Index(1).Log()
);
Console.WriteLine("subscriber(0) = " + route.Subscribers[0].Identifier);
// Use createAnonymousRoutesAsync to retrieve log data from
// another device
foreach(var route in await metawear.CreateAnonymousRoutesAsync()) {
    route.Subscribe(data => {
        switch (route.Identifier) {
            case "angular-velocity[1]":
                Console.WriteLine("gyro y-axis: " + data.Value<float>());
                break;
        }
    });
}

await metawear.GetModule<ILogging>().DownloadAsync();
Console.WriteLine("Log download completed");