Skip to content

Advanced Data Route Features

Metawear edited this page Jul 16, 2015 · 3 revisions

In this tutorial, we will introduce two more components that can be added to your data route: the signal splitter and monitor. A signal splitter allows you to separate a signal and chain different components that share the same data source. You can combine this component with filters, such as a comparison filter, to create logic branches in your route. A signal monitor watches the data source it is attached to and executes MetaWear commands when that signal is active. Like subscribers and loggers, signal monitors and splitters do not modify the data or alter its flow.

Splitter

To split a signal, add the split function after the signal you are splitting. After the split function, call the branch function, which signifies a new processing chain is to be attached to the split source, and then add the remainder of your data signal components. You can add as many branches as desired, provided the board has enough memory to handle the amount of filters and transformers being added.

When you are done attaching branches to a split, call the end method. If there are still unfinished branch splits, the most recent split will be returned. Otherwise, you can only commit the route as the route construction has been completed.

mwBoard.routeData().fromAnalogGpio((byte) 0, Gpio.AnalogReadMode.ADC)
.split()
    .branch().filter("comparison?operation=lt&reference=511")
    .split()
        ///< attach (adc < 255) filter giving us (adc < 511) -> (adc > 255) here
        .branch().filter("comparison?operation=lt&reference=255")
        ///< Calling branch returns the (adc < 511) signal.  Attach an (adc >= 255) filter to it
        ///< giving us (adc < 511) -> (adc >= 255) at this branch
        .branch().filter("comparison?operation=gte&reference=255")
    ///< Calling end here returns the unfiltered adc signal
    .end()
    ///< Attach (adc >= 511) filter to the adc source
    .branch().filter("comparison?operation=gte&reference=511")
///< Since there are no more branch splits to work with, can only call commit
.end().commit();

Activity Monitor

Like a subscriber and logger, activity monitors function like a wire tap, only listening for data. Instead of reporting the data back to the user or logging it, it instead executes MetaWear commands in response to receiving data. Activity monitors are added with the monitor function, passing in an ActivityMonitor object. Any MetaWear commands (i.e. functions calls from the Module subclasses) in the onSignalActive callback function will be executed when data is received.

mwBoard.routeData().fromAnalogGpio((byte) 0, Gpio.AnalogReadMode.ADC)
    .monitor(new DataSignal.ActivityMonitor() {
         @Override
         public void onSignalActive(Map<String, DataProcessor> processors, MessageToken signalData) {
             ///< Start the LED when adc data is read
             Led ledCtrllr = mwBoard.getModule(Led.class);
             ledCtrllr.writeChannelAttributes(Led.ColorChannel.GREEN)
                     .withRiseTime((short) 0).withPulseDuration((short) 1000)
                     .withRepeatCount((byte) -1).withHighTime((short) 500)
                     .withHighIntensity((byte) 16).withLowIntensity((byte) 16)
                     .commit();
             ledCtrllr.play(false);
         }
    })
.commit();

mwBoard.routeData().fromSwitch().monitor(new DataSignal.ActivityMonitor() {
    @Override
    public void onSignalActive(Map<String, DataProcessor> processors, MessageToken signalData) {
        ///< Stop the led when the button is pressed
        mwBoard.getModule(Led.class).stop(true);
    }
}).commit();

Switch Controller Example

To fully showcase the spliiter and signal monitor, we will implement the LED switch controller from the event processing blog post. As you may recall, the switch controller was created by accumulating the switch data and computing sum mod 2, giving us an off/on setup for button presses. The result of the modulus computation was then fed through two comparisons to see if it were 0 or 1, then execute the appropriate MetaWear command. This example uses a string URI to configure the data processors, more details are provided on its [wiki page](Data Processor URI Scheme).

For the first step, lets attach the accumulator and math transformers to the switch.

mwBoard.routeData().fromSwitch().transform("accumulator")
        .transform("math?operation=modulus&rhs=2")

At this point, we will use the splitter to attach different processing chains to all possible results of the modulus computation. The first branch we attach handles the case of the operation equaling 1. If the result is one, turn on the blue LED.

mwBoard.routeData().fromSwitch().transform("accumulator")
.transform("math?operation=modulus&rhs=2")
.split()
    .branch().filter("comparison?operation=eq&reference=1")
    .monitor(new DataSignal.ActivityMonitor() {
         @Override
         public void onSignalActive() {
             Led ledCtrllr = mwBoard.getModule(Led.class);
             ledCtrllr.writeChannelAttributes(Led.ColorChannel.BLUE)
                     .withRiseTime((short) 0).withPulseDuration((short) 1000)
                     .withRepeatCount((byte) -1).withHighTime((short) 500)
                     .withHighIntensity((byte) 16).withLowIntensity((byte) 16)
                     .commit();
             ledCtrllr.play(false);
         }
    })

On the second branch, in which the result is 0, we turn off the LED.

mwBoard.routeData().fromSwitch().transform("accumulator")
.transform("math?operation=modulus&rhs=2")
.split()
    .branch().filter("comparison?operation=eq&reference=1")
    .monitor(new DataSignal.ActivityMonitor() {
         @Override
         public void onSignalActive(Map<String, DataProcessor> processors, MessageToken signalData) {
             Led ledCtrllr = mwBoard.getModule(Led.class);
             ledCtrllr.writeChannelAttributes(Led.ColorChannel.BLUE)
                     .withRiseTime((short) 0).withPulseDuration((short) 1000)
                     .withRepeatCount((byte) -1).withHighTime((short) 500)
                     .withHighIntensity((byte) 16).withLowIntensity((byte) 16)
                     .commit();
             ledCtrllr.play(false);
         }
    })
    .branch().filter("comparison?operation=eq&reference=0")
    .monitor(new DataSignal.ActivityMonitor(Map<String, DataProcessor> processors, MessageToken signalData) {
        @Override
        public void onSignalActive() {
            mwBoard.getModule(Led.class).stop(true);
        }
    })
.end().commit();

Once the commit function has succeeded, you can disconnect your MetaWear board and start controlling the LED with the button.