-
Notifications
You must be signed in to change notification settings - Fork 41
API v0.3.0 How To
As this library only helps you interact with a MetaWear board, you will need to hook in the Bluetooth LE functions needed to communicate with the board. The implementation and handling of these functions will differ depending on what platform you are running the code on.
The MblMwBtleConnection struct holds the functions an MblMwMetaWearBoard instance uses to interact with the gatt characteristics. You must implement functions to write values to and read values from a characteristic and point the MblMwBtleConnection variable to those two functions. The MblMwBtleConnection struct just created will be used to instantiate an MblMwMetaWearBoard struct.
#include "metawear/core/connection.h"
static void write_gatt_char(const MblMwGattChar *characteristic, const uint8_t *value,
uint8_t length) {
// Code to write the value to the characteristic goes here
}
static void read_gatt_char(const MblMwGattChar *characteristic) {
// Code to read the value from the characteristic goes here
}
int main(int argc, char **argv) {
MblMwBtleConnection btle_conn = { write_gatt_char, read_gatt_char };
}
In addition to issuing commands to the characteristics, you will also need to forward responses received from the characteristics to the appropriate functions in the connection.h header file. Specifically, you need to handle responses from the MetaWear notify characteristic and gatt characteristic read requests.
The MetaWear gatt service has a characteristic that will change every time the board sends a response to your device. You will need to enable notifications on that characteristic and pass all responses from that characteristic to the mbl_mw_connection_notify_char_changed function. The connection.h header file defines a constant, METAWEAR_SERVICE_NOTIFY_CHAR, containing the UUIDs of the notify characteristic and the MetaWear gatt service.
Every call to the read_gatt_char function pointer must have its response forwarded to the mbl_mw_connection_char_read function.
When you have setup your MblMwBtleConnection struct, you can instantiate a MblMwMetaWearBoard variable by calling mbl_mw_metawearboard_create. The returned MblMwMetaWearBoard pointer will use the functions pointed to by the MblMwBtleConnection struct passed into the mbl_mw_metawearboard_create function.
After you have your pointer, you need to initialize the internal state by calling mbl_mw_metawearboard_initialize. This function is non-blocking and will asynchronously alert the caller when it is completed through a callback function. You must call this function every time you connect to your MetaWear.
#include <stdio.h>
#include "metawear/core/metawearboard.h"
static MblMwMetaWearBoard *board;
void initialized();
int main(int argc, char **argv) {
MblMwBtleConnection btle_conn = { write_gatt_char, read_gatt_char };
board= mbl_mw_metawearboard_create(&btle_conn);
mbl_mw_metawearboard_initialize(board, initialized);
}
void initialized() {
printf("MetaWear board initialized\n");
}
When you are done using the MetaWear board, you can free the allocated memory by calling mbl_mw_metawearboard_free. This will only free the memory on your device, not the MetaWear board. If you wish to tear down the MetaWear board, you can either issue a soft reset by calling mbl_mw_debug_reset or, if you do not wish to reset the board, mbl_mw_metawearboard_tear_down.
void cleanup() {
mbl_mw_metawearboard_tear_down(board);
mbl_mw_metawearboard_free(board);
}
Events are interrupts generated by the MetaWear board, represented by the MblMwEvent struct. The board can be programmed to react to these events using the mbl_mw_event_record_commands function to execute MetaWear commands in response to an event firing.
The MblMwTimer type is an event that is fired periodically. A timer can be used to periodically read data from the board such as the gpio pins or the temperature sensors. They can be configured to run indefinitely or only fire events for a fixed number of times.
#include "metawear/core/timer.h"
#include "metawear/sensor/gpio.h"
static MblMwTimer* gpio_read_timer;
void timer_created(MblMwTimer* timer);
void commands_recorded();
void setup_timer() {
// Create a timer that runs indefinitely
mbl_mw_timer_create_indefinite(board, 1000, 0, timer_created);
}
void timer_created(MblMwTimer* timer) {
gpio_read_timer = timer;
mbl_mw_event_record_commands(timer);
// Read analog input from pin 0 when a timer event is fired
mbl_mw_gpio_read_analog_input(board, 0, MBL_MW_GPIO_ANALOG_READ_MODE_ABS_REF);
mbl_mw_event_end_record(timer, commands_recorded);
}
void commands_recorded() {
printf("Ready to start the timer\n");
mbl_mw_timer_start(gpio_read_timer);
}
The on board sensors are represented by an MblMwDataSignal struct, which is an event that is accompanied with data. An MblMwDataSignal pointer can be safely typecasted to an MblMwEvent pointer.
You can subscribe to a data signal to receive a live stream of data to your device and attach a handler to process the incoming data. The data handler is a callback function that accepts an MblMwData struct and is called whenever a data signal fires an event. The MblMwData contains a pointer to the data and an enum identifying the data type that can be used to ensure the correct handler is processing in the incoming data.
#include "metawear/core/data.h"
#include "metawear/core/datasignal.h"
#include "metawear/core/types.h"
#include "metawear/sensor/accelerometer.h"
static void acceleration_handler(const MblMwData* data) {
// See if the incoming data is a cartesian float
if (data->type_id == MBL_MW_DT_ID_CARTESIAN_FLOAT) {
CartesianFloat *acc= (CartesianFloat*) data->value;
printf("%.3f, %.3f, %.3f\n", acc->x, acc->y, acc->z);
} else {
fprintf(stderr, "Wrong type of data sent to this handler\n");
}
}
void subscribe_to_accelerometer() {
MblMwDataSignal *acc_signal= mbl_mw_acc_get_acceleration_data_signal(board);
mbl_mw_datasignal_subscribe(acc_signal, acceleration_handler);
}
The MblMwDataProcessor represents a data signal coming from the on board data processor. A data processor signal typically will be an input to another processor. Some processors hold an internal state which can be read by calling mbl_mw_dataprocessor_read_state.
A MblMwDataProcessor pointer can be safely typecasted to an MblMwDataSignal pointer.
#include "metawear/processor/accumulator.h"
#include "metawear/processor/buffer.h"
#include "metawear/processor/rms.h"
#include "metawear/processor/time.h"
static MblMwDataProcessor* accum_processor;
static MblMwDataSignal* buffer_state;
void rms_created(MblMwDataProcessor* processor);
void accum_created(MblMwDataProcessor* processor);
void buffer_created(MblMwDataProcessor* processor);
void time_created(MblMwDataProcessor* processor);
void setup_activity_monitor() {
MblMwDataSignal *acc_signal= mbl_mw_acc_get_acceleration_data_signal(board);
mbl_mw_dataprocessor_rms_create(acc_signal, rms_created);
}
void rms_created(MblMwDataProcessor* processor) {
mbl_mw_dataprocessor_accumulator_create_size((MblMwDataSignal*) processor, 4,
accum_created);
}
void accum_created(MblMwDataProcessor* processor) {
accum_processor = processor;
mbl_mw_dataprocessor_buffer_create((MblMwDataSignal*) processor, buffer_created);
}
void buffer_created(MblMwDataProcessor* processor) {
buffer_state= mbl_mw_dataprocessor_get_state_data_signal(processor);
mbl_mw_dataprocessor_time_create((MblMwDataSignal*) accum_processor,
MBL_MW_TIME_ABSOLUTE, 30000, time_created);
}
void time_created(MblMwDataProcessor* processor) {
printf("Processor chain completed!\n");
}