Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Marco Merlin
Published © CC BY

MIDI rIoT!

Implements a wireless controller that takes signals from sensors and translates them into MIDI to control a software synthesizer.

IntermediateFull instructions provided20 hours1,540

Things used in this project

Hardware components

Rapid IoT Prototyping Kit
NXP Rapid IoT Prototyping Kit
×1
NXP QN9080DK
×1

Software apps and online services

NXP Rapid IoT Studio online IDE
NXP SDK Builder
IAR Embedded workbench
hairless MIDI
loopMIDI
vsthost
TAL bassline
asio4all

Story

Read more

Code

NXP MIDI RioT online IDE code

C/C++
This is the code I wrote on the online IDE editor
#include "callbacks.h"

//HEADER START
#define MIDI_CHANNEL 0
#define MIDI_CHANNEL_FX 1
#define MIDI_CHANNEL_PERCUSSION 10
#define CONTROL_ROTATIONX 34
#define CONTROL_ROTATIONY 35
#define CONTROL_ROTATIONZ 36
#define CONTROL_MAGX 31
#define CONTROL_MAGY 32
#define CONTROL_MAGZ 33
#define CONTROL_ALL 31

//MIDI STATUS HEADERS

#define MIDI_STATUS_NOTE_OFF        0b10000000
#define MIDI_STATUS_NOTE_ON         0b10010000
#define MIDI_STATUS_POLY_KEY_PRESS  0b10100000
#define MIDI_STATUS_CC              0b10110000 // control change
#define MIDI_STATUS_PC              0b10110000 // program change
#define MIDI_STATUS_PRESSURE        0b11010000
#define MIDI_STATUS_PITCH_BEND      0b11100000

// MIDI Notes Pitch
#define MIDI_ALLNOTEOFF 123
#define MIDI_C1 36
#define MIDI_A2 57
#define MIDI_B2 59
#define MIDI_C3 60
#define MIDI_D3 62
#define MIDI_E3 64
#define MIDI_F3 65
#define MIDI_G3 67

static unsigned short int ctrl_select = CONTROL_ALL;
//HEADER END

void ATMO_Setup() {

}


ATMO_Status_t FastSensorPoll_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t FastSensorPoll_setup(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_INTERVAL_Handle_t intervalHandle;
    ATMO_INTERVAL_AddAbilityInterval(
		ATMO_PROPERTY(FastSensorPoll, instance), 
		ATMO_ABILITY(FastSensorPoll, interval), 
		ATMO_PROPERTY(FastSensorPoll, time), 
		&intervalHandle
	);
	
	return ATMO_Status_Success;
	
}


ATMO_Status_t FastSensorPoll_interval(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight_setup(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_TSL2572_Config_t config;
	config.address = ATMO_PROPERTY(TSL2572AmbientLight, i2cAddress);
	config.i2cDriverInstance = ATMO_PROPERTY(TSL2572AmbientLight, i2cInstance);

	return ( ATMO_TSL2572_Init(&config) == ATMO_TSL2572_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;

}


ATMO_Status_t TSL2572AmbientLight_setEnabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_TSL2572_SetEnabled(true);
return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight_setDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_TSL2572_SetEnabled(false);
return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight_setEnabledDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
bool enabled = false;
ATMO_GetBool(in, &enabled);
ATMO_TSL2572_SetEnabled(enabled);
return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight_readAmbientLight(ATMO_Value_t *in, ATMO_Value_t *out) {
    float lightLux;
    if(ATMO_TSL2572_GetAmbientLight(&lightLux) != ATMO_TSL2572_Status_Success)
    {
        ATMO_CreateValueVoid(out);
        return ATMO_Status_Fail;
    }
    ATMO_CreateValueInt(out, (int)lightLux);
    return ATMO_Status_Success;
}


ATMO_Status_t EmbeddedIconLinesDisplay_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t EmbeddedIconLinesDisplay_displayPage(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_UI_Page_DisplayPageByCoord(ATMO_PROPERTY(EmbeddedIconLinesDisplay, x), ATMO_PROPERTY(EmbeddedIconLinesDisplay, y), false);
	return ATMO_Status_Success;
	
}


ATMO_Status_t EmbeddedIconLinesDisplay_onDisplayed(ATMO_Value_t *in, ATMO_Value_t *out) {

	return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_onLeave(ATMO_Value_t *in, ATMO_Value_t *out) {

	return ATMO_Status_Success;
	
}


ATMO_Status_t EmbeddedIconLinesDisplay_setIconLabelAndColor(ATMO_Value_t *in, ATMO_Value_t *out) {

    struct {
        char str[32];
        GUI_COLOR color;
    } icon_data;
 
    ATMO_GetBinary(in, &icon_data, sizeof(icon_data));
    ATMO_UI_ICONLINES_SetIconLabelColor(ATMO_VARIABLE(EmbeddedIconLinesDisplay, pageHandle), icon_data.str, icon_data.color);
    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_setIconLabel(ATMO_Value_t *in, ATMO_Value_t *out) {

    char str[32];
    ATMO_GetString(in, str, 32);
    ATMO_UI_ICONLINES_SetIconLabel(ATMO_VARIABLE(EmbeddedIconLinesDisplay, pageHandle), str);
    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_setup(ATMO_Value_t *in, ATMO_Value_t *out) {

    ATMO_UI_PAGE_Config_t config;
    config.hidden = ATMO_PROPERTY(EmbeddedIconLinesDisplay, pageHidden);
    config.textColor = ATMO_PROPERTY(EmbeddedIconLinesDisplay, textColor);
    config.activeButtons = ATMO_UI_Page_GetButtonMask(ATMO_PROPERTY(EmbeddedIconLinesDisplay, topRightButtonEnabled),
    ATMO_PROPERTY(EmbeddedIconLinesDisplay,bottomRightButtonEnabled), ATMO_PROPERTY(EmbeddedIconLinesDisplay, topLeftButtonEnabled), ATMO_PROPERTY(EmbeddedIconLinesDisplay, bottomLeftButtonEnabled));
	config.x = ATMO_PROPERTY(EmbeddedIconLinesDisplay, x);
    config.y = ATMO_PROPERTY(EmbeddedIconLinesDisplay, y);
	strncpy(config.topLeftButtonLabel, ATMO_PROPERTY(EmbeddedIconLinesDisplay, topLeftButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);
	strncpy(config.topRightButtonLabel, ATMO_PROPERTY(EmbeddedIconLinesDisplay, topRightButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);
	strncpy(config.bottomLeftButtonLabel, ATMO_PROPERTY(EmbeddedIconLinesDisplay, bottomLeftButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);
	strncpy(config.bottomRightButtonLabel, ATMO_PROPERTY(EmbeddedIconLinesDisplay, bottomRightButtonLabel), ATMO_BUTTON_LABEL_MAXLEN);
    config.spanX = ATMO_PROPERTY(EmbeddedIconLinesDisplay, spanX);
	config.spanY = ATMO_PROPERTY(EmbeddedIconLinesDisplay, spanY);
    config.title = ATMO_PROPERTY(EmbeddedIconLinesDisplay, pageTitle);
    config.titleHidden = ATMO_PROPERTY(EmbeddedIconLinesDisplay, titleHidden);
	ATMO_UI_ICONLINES_Init(&config, ATMO_PROPERTY(EmbeddedIconLinesDisplay, numLines), false);
	ATMO_VARIABLE(EmbeddedIconLinesDisplay, pageHandle) = config.templateInstance;
    ATMO_UI_ICONLINES_SetMainText(config.templateInstance, 0, ATMO_PROPERTY(EmbeddedIconLinesDisplay, line1Text));
    ATMO_UI_ICONLINES_SetMainText(config.templateInstance, 1, ATMO_PROPERTY(EmbeddedIconLinesDisplay, line2Text));
    ATMO_UI_ICONLINES_SetMainText(config.templateInstance, 2, ATMO_PROPERTY(EmbeddedIconLinesDisplay, line3Text));
    ATMO_UI_ICONLINES_SetMainText(config.templateInstance, 3, ATMO_PROPERTY(EmbeddedIconLinesDisplay, line4Text));
    ATMO_UI_ICONLINES_SetIconLabel(config.templateInstance, ATMO_PROPERTY(EmbeddedIconLinesDisplay, iconLabel));
    ATMO_UI_ICONLINES_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 1, ATMO_ABILITY(EmbeddedIconLinesDisplay, topRightButtonPressed));
	ATMO_UI_ICONLINES_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 2, ATMO_ABILITY(EmbeddedIconLinesDisplay, bottomRightButtonPressed));
	ATMO_UI_ICONLINES_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 3, ATMO_ABILITY(EmbeddedIconLinesDisplay, topLeftButtonPressed));
    ATMO_UI_ICONLINES_RegisterButtonAbilityHandle(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 4, ATMO_ABILITY(EmbeddedIconLinesDisplay, bottomLeftButtonPressed));
    ATMO_UI_ICONLINES_SetIcon(config.templateInstance, ATMO_PROPERTY(EmbeddedIconLinesDisplay, icon));
    ATMO_UI_ICONLINES_RegisterOnDisplayedAbilityHandle(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), ATMO_ABILITY(EmbeddedIconLinesDisplay, onDisplayed));
    ATMO_UI_ICONLINES_RegisterOnLeaveAbilityHandle(config.templateInstance, ATMO_ABILITY(EmbeddedIconLinesDisplay, onLeave));
    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_setLine1Text(ATMO_Value_t *in, ATMO_Value_t *out) {

    char label[32];
    if(ATMO_GetString(in, label, 32) == ATMO_Status_Success)
    {
        ATMO_UI_ICONLINES_SetMainText(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 0, label);
    }
    else
    {
        return ATMO_Status_Fail;
    }

    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_setLine2Text(ATMO_Value_t *in, ATMO_Value_t *out) {

    char label[32];
    if(ATMO_GetString(in, label, 32) == ATMO_Status_Success)
    {
        ATMO_UI_ICONLINES_SetMainText(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 1, label);
    }
    else
    {
        return ATMO_Status_Fail;
    }

    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_setLine3Text(ATMO_Value_t *in, ATMO_Value_t *out) {

    char label[32];
    if(ATMO_GetString(in, label, 32) == ATMO_Status_Success)
    {
        ATMO_UI_ICONLINES_SetMainText(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 2, label);
    }
    else
    {
        return ATMO_Status_Fail;
    }

    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_setLine4Text(ATMO_Value_t *in, ATMO_Value_t *out) {

    char label[32];
    if(ATMO_GetString(in, label, 32) == ATMO_Status_Success)
    {
        ATMO_UI_ICONLINES_SetMainText(ATMO_VARIABLE(EmbeddedIconLinesDisplay,pageHandle), 3, label);
    }
    else
    {
        return ATMO_Status_Fail;
    }

    return ATMO_Status_Success;
    
}


ATMO_Status_t EmbeddedIconLinesDisplay_topRightButtonPressed(ATMO_Value_t *in, ATMO_Value_t *out) {
    //return FunctionTRbutton2MIdi_trigger(in, out);
    	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_C3; //0kkkkkkk, k = key (60 = middle C)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
	
}


ATMO_Status_t EmbeddedIconLinesDisplay_bottomRightButtonPressed(ATMO_Value_t *in, ATMO_Value_t *out) {
    // FunctionBRbutton2MIdi_trigger(in, out);
    char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_F3; //0kkkkkkk, k = key (66 = middle F)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
	
}


ATMO_Status_t EmbeddedIconLinesDisplay_topLeftButtonPressed(ATMO_Value_t *in, ATMO_Value_t *out) {
    // FunctionTLbutton2MIdi_trigger(in, out);
    char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_ALLNOTEOFF; //0kkkkkkk, k = key (123 = all note off)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
	
}


ATMO_Status_t EmbeddedIconLinesDisplay_bottomLeftButtonPressed(ATMO_Value_t *in, ATMO_Value_t *out) {
    // FunctionBLbutton2MIdi_trigger(in, out);
    char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_G3; //0kkkkkkk, k = key (68 = middle G)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t BLEConnection_setup(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_BLE_PairingCfg_t pairingCfg;
	pairingCfg.pairingKey = ATMO_PROPERTY(BLEConnection, pairingKey);
	pairingCfg.type = ATMO_PROPERTY(BLEConnection, pairingType);
	ATMO_BLE_GAPPairingCfg(ATMO_PROPERTY(BLEConnection, instance), &pairingCfg);

	ATMO_BLE_RegisterEventAbilityHandle(ATMO_PROPERTY(BLEConnection, instance), ATMO_BLE_EVENT_Connected, ATMO_ABILITY(BLEConnection, connected));
	ATMO_BLE_RegisterEventAbilityHandle(ATMO_PROPERTY(BLEConnection, instance), ATMO_BLE_EVENT_Disconnected, ATMO_ABILITY(BLEConnection, disconnected));
	ATMO_BLE_RegisterEventAbilityHandle(ATMO_PROPERTY(BLEConnection, instance), ATMO_BLE_EVENT_PairingRequested, ATMO_ABILITY(BLEConnection, pairingRequested));
	ATMO_BLE_RegisterEventAbilityHandle(ATMO_PROPERTY(BLEConnection, instance), ATMO_BLE_EVENT_PairingSuccess, ATMO_ABILITY(BLEConnection, pairingSucceeded));
	ATMO_BLE_RegisterEventAbilityHandle(ATMO_PROPERTY(BLEConnection, instance), ATMO_BLE_EVENT_PairingFailed, ATMO_ABILITY(BLEConnection, pairingFailed));
	
	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_disconnect(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_BLE_GAPDisconnect(ATMO_PROPERTY(BLEConnection, instance));
	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_connected(ATMO_Value_t *in, ATMO_Value_t *out) {

	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_disconnected(ATMO_Value_t *in, ATMO_Value_t *out) {

	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_pairingRequested(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_CreateValueCopy(out, in);
	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_pairingSucceeded(ATMO_Value_t *in, ATMO_Value_t *out) {

	return ATMO_Status_Success;
	
}


ATMO_Status_t BLEConnection_pairingFailed(ATMO_Value_t *in, ATMO_Value_t *out) {

	return ATMO_Status_Success;
	
}


ATMO_Status_t TSL2572AmbientLight1_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight1_setup(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_TSL2572_Config_t config;
	config.address = ATMO_PROPERTY(TSL2572AmbientLight1, i2cAddress);
	config.i2cDriverInstance = ATMO_PROPERTY(TSL2572AmbientLight1, i2cInstance);

	return ( ATMO_TSL2572_Init(&config) == ATMO_TSL2572_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;

}


ATMO_Status_t TSL2572AmbientLight1_setEnabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_TSL2572_SetEnabled(true);
return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight1_setDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_TSL2572_SetEnabled(false);
return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight1_setEnabledDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
bool enabled = false;
ATMO_GetBool(in, &enabled);
ATMO_TSL2572_SetEnabled(enabled);
return ATMO_Status_Success;
}


ATMO_Status_t TSL2572AmbientLight1_readAmbientLight(ATMO_Value_t *in, ATMO_Value_t *out) {
    float lightLux;
    if(ATMO_TSL2572_GetAmbientLight(&lightLux) != ATMO_TSL2572_Status_Success)
    {
        ATMO_CreateValueVoid(out);
        return ATMO_Status_Fail;
    }
    ATMO_CreateValueInt(out, (int)lightLux);
    return ATMO_Status_Success;
}


ATMO_Status_t DisplaySensorPoll_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t DisplaySensorPoll_setup(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_INTERVAL_Handle_t intervalHandle;
    ATMO_INTERVAL_AddAbilityInterval(
		ATMO_PROPERTY(DisplaySensorPoll, instance), 
		ATMO_ABILITY(DisplaySensorPoll, interval), 
		ATMO_PROPERTY(DisplaySensorPoll, time), 
		&intervalHandle
	);
	
	return ATMO_Status_Success;
	
}


ATMO_Status_t DisplaySensorPoll_interval(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t ENS210TemperatureHumidity_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t ENS210TemperatureHumidity_setup(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_ENS210_Config_t config;
	config.address = ATMO_PROPERTY(ENS210TemperatureHumidity, i2cAddress);
	config.i2cDriverInstance = ATMO_PROPERTY(ENS210TemperatureHumidity, i2cInstance);
	config.tempCalibrationOffset = ATMO_PROPERTY(ENS210TemperatureHumidity, tempCalibrationOffset);

	return ( ATMO_ENS210_Init(&config) == ATMO_ENS210_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;

}


ATMO_Status_t ENS210TemperatureHumidity_setEnabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_ENS210_SetEnabled(true);
return ATMO_Status_Success;
}


ATMO_Status_t ENS210TemperatureHumidity_setDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_ENS210_SetEnabled(false);
return ATMO_Status_Success;
}


ATMO_Status_t ENS210TemperatureHumidity_setEnabledDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
bool enabled = false;
ATMO_GetBool(in, &enabled);
ATMO_ENS210_SetEnabled(enabled);
return ATMO_Status_Success;
}


ATMO_Status_t ENS210TemperatureHumidity_readTemperature(ATMO_Value_t *in, ATMO_Value_t *out) {
    float tempC;
    
    if(ATMO_ENS210_GetTemperatureFloat(&tempC) == ATMO_ENS210_Status_Success)
    {
        ATMO_CreateValueFloat(out, tempC);
    }
    else
    {
        ATMO_CreateValueVoid(out);
    }
    
    return ATMO_Status_Success;
}


ATMO_Status_t ENS210TemperatureHumidity_readHumidity(ATMO_Value_t *in, ATMO_Value_t *out) {
    float humidityPct;

    if(ATMO_ENS210_GetHumidityFloat(&humidityPct) == ATMO_ENS210_Status_Success)
    {
        ATMO_CreateValueFloat(out, humidityPct);
    }
    else
    {
        ATMO_CreateValueVoid(out);
    }
    
    return ATMO_Status_Success;
}


ATMO_Status_t GATT_NRF_UART_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t GATT_NRF_UART_setup(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_BLE_GATTSAddService(
		ATMO_PROPERTY(GATT_NRF_UART, instance),
		&ATMO_VARIABLE(GATT_NRF_UART, bleServiceHandle), 
		ATMO_PROPERTY(GATT_NRF_UART, bleServiceUuid));
	
	uint8_t property = 0;
	uint8_t permission = 0;
	
	property |= ATMO_PROPERTY(GATT_NRF_UART, read) ? ATMO_BLE_Property_Read : 0;
	property |= ATMO_PROPERTY(GATT_NRF_UART, write) ? ATMO_BLE_Property_Write : 0;
	property |= ATMO_PROPERTY(GATT_NRF_UART, notify) ? ATMO_BLE_Property_Notify : 0;

	permission |= ATMO_PROPERTY(GATT_NRF_UART, read) ? ATMO_BLE_Permission_Read : 0;
	permission |= ATMO_PROPERTY(GATT_NRF_UART, write) ? ATMO_BLE_Permission_Write : 0;

	ATMO_DATATYPE types[3] = {ATMO_PROPERTY(GATT_NRF_UART, writeDataType), ATMO_PROPERTY(GATT_NRF_UART, readDataType), ATMO_PROPERTY(GATT_NRF_UART, notifyDataType)};
	
	ATMO_BLE_GATTSAddCharacteristic(
		ATMO_PROPERTY(GATT_NRF_UART, instance),
		&ATMO_VARIABLE(GATT_NRF_UART, bleCharacteristicHandle), 
		ATMO_VARIABLE(GATT_NRF_UART, bleServiceHandle), 
		ATMO_PROPERTY(GATT_NRF_UART, bleCharacteristicUuid), 
		property, permission, ATMO_GetMaxValueSize(3, 64, types));
	
	ATMO_BLE_GATTSRegisterCharacteristicAbilityHandle(
		ATMO_PROPERTY(GATT_NRF_UART, instance),
		ATMO_VARIABLE(GATT_NRF_UART, bleCharacteristicHandle), 
		ATMO_BLE_Characteristic_Written, 
		ATMO_ABILITY(GATT_NRF_UART, written));
	
	return ATMO_Status_Success;
	
}


ATMO_Status_t GATT_NRF_UART_setValue(ATMO_Value_t *in, ATMO_Value_t *out) {

	
	// Convert to the desired write data type
	ATMO_Value_t convertedValue;
	ATMO_InitValue(&convertedValue);
	ATMO_CreateValueConverted(&convertedValue, ATMO_PROPERTY(GATT_NRF_UART, readDataType), in);

	ATMO_BLE_GATTSSetCharacteristic(
		ATMO_PROPERTY(GATT_NRF_UART, instance),
		ATMO_VARIABLE(GATT_NRF_UART, bleCharacteristicHandle),
		convertedValue.size, 
		(uint8_t *)convertedValue.data,
		NULL);
	
	ATMO_FreeValue(&convertedValue);
		
	return ATMO_Status_Success;
	
}


ATMO_Status_t GATT_NRF_UART_written(ATMO_Value_t *in, ATMO_Value_t *out) {

	ATMO_CreateValueConverted(out, ATMO_PROPERTY(GATT_NRF_UART, writeDataType), in);
	return ATMO_Status_Success;
	
}


ATMO_Status_t GATT_NRF_UART_subscibed(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t GATT_NRF_UART_unsubscribed(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t FunctionLight2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
    unsigned int light = 0;
    
	ATMO_GetUnsignedInt(in, &light);
	
	midi_msg[0] = MIDI_STATUS_PITCH_BEND | (MIDI_CHANNEL & 0b1111); // 1110nnnn, n = channel. Pitch Bend
	/*midi_msg[1] = light & 0x7F; //0ffffff, f = fine
	midi_msg[2] = (light >> 7 ) & 0x7F; //0ccccccc, c= coarse*/
	
	midi_msg[1] = 0x0; //0ffffff, f = fine
	midi_msg[2] = light & 0x7F; //0ccccccc, c= coarse
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));

	return ATMO_Status_Success;
}


ATMO_Status_t FunctionTRbutton2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_C3; //0kkkkkkk, k = key (60 = middle C)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
}


ATMO_Status_t FunctionTLbutton2MIdi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_ALLNOTEOFF; //0kkkkkkk, k = key (123 = all note off)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;

}


ATMO_Status_t FunctionBRbutton2MIdi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_F3; //0kkkkkkk, k = key (66 = middle F)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
}


ATMO_Status_t FunctionBLbutton2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	ctrl_select++;
	if ( ctrl_select > CONTROL_MAGZ) 
	    ctrl_select = CONTROL_ALL;
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_G3; //0kkkkkkk, k = key (68 = middle G)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	
	return ATMO_Status_Success;
}


ATMO_Status_t SX9500TouchUp_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t SX9500TouchUp_setup(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_SX9500_Config_t config;
	config.address = ATMO_PROPERTY(SX9500TouchUp, i2cAddress);
	config.i2cDriverInstance = ATMO_PROPERTY(SX9500TouchUp, i2cInstance);
	config.gpioDriverInstance = ATMO_PROPERTY(SX9500TouchUp, gpioInstance);
	config.interruptEnabled = ATMO_PROPERTY(SX9500TouchUp, interruptEnabled);
	config.interruptPin = ATMO_PROPERTY(SX9500TouchUp, interruptGpio);
	ATMO_SX9500_Init(&config);
	ATMO_SX9500_RegisterTouchedAbilityHandle(SX9500_Touched_Up, ATMO_ABILITY(SX9500TouchUp, pressUp));
	ATMO_SX9500_RegisterTouchedAbilityHandle(SX9500_Touched_Down, ATMO_ABILITY(SX9500TouchUp, pressDown));
	ATMO_SX9500_RegisterTouchedAbilityHandle(SX9500_Touched_Left, ATMO_ABILITY(SX9500TouchUp, pressLeft));
	ATMO_SX9500_RegisterTouchedAbilityHandle(SX9500_Touched_Right, ATMO_ABILITY(SX9500TouchUp, pressRight));
	return ATMO_Status_Success;
}


ATMO_Status_t SX9500TouchUp_getTouchData(ATMO_Value_t *in, ATMO_Value_t *out) {
	return;
}


ATMO_Status_t SX9500TouchUp_pressUp(ATMO_Value_t *in, ATMO_Value_t *out) {
SX9500_TouchState_t touchState;
ATMO_GetBinary(in, &touchState, sizeof(touchState));
ATMO_CreateValueBinary(out, &touchState, sizeof(touchState));
return ATMO_Status_Success;
}


ATMO_Status_t SX9500TouchUp_pressDown(ATMO_Value_t *in, ATMO_Value_t *out) {
SX9500_TouchState_t touchState;
ATMO_GetBinary(in, &touchState, sizeof(touchState));
ATMO_CreateValueBinary(out, &touchState, sizeof(touchState));
return ATMO_Status_Success;
}


ATMO_Status_t SX9500TouchUp_pressLeft(ATMO_Value_t *in, ATMO_Value_t *out) {
SX9500_TouchState_t touchState;
ATMO_GetBinary(in, &touchState, sizeof(touchState));
ATMO_CreateValueBinary(out, &touchState, sizeof(touchState));
return ATMO_Status_Success;
}


ATMO_Status_t SX9500TouchUp_pressRight(ATMO_Value_t *in, ATMO_Value_t *out) {
SX9500_TouchState_t touchState;
ATMO_GetBinary(in, &touchState, sizeof(touchState));
ATMO_CreateValueBinary(out, &touchState, sizeof(touchState));
return ATMO_Status_Success;
}


ATMO_Status_t FunctionTouchUp2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_A2; //0kkkkkkk, k = key (57 = A-1)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
}


ATMO_Status_t FunctionTouchDown2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_E3; //0kkkkkkk, k = key (64 = E0)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
}


ATMO_Status_t FunctionTouchLeft2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_B2; //0kkkkkkk, k = key (59 = B-1)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
}


ATMO_Status_t FunctionTouchRight2Midi_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	char midi_msg[4] = "dea";
	
	midi_msg[0] = MIDI_STATUS_NOTE_ON | (MIDI_CHANNEL & 0b1111); // 1001nnnn, n = channel. Note On
	midi_msg[1] = 0x0fffffff & MIDI_D3; //0kkkkkkk, k = key (62 = D0)
	midi_msg[2] = 0x7F; //0vvvvvvv, v = velocity
	
	ATMO_CreateValueBinary(out, (void*)midi_msg, 3*sizeof(void));
	return ATMO_Status_Success;
}


ATMO_Status_t DetectMotion_trigger(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;
}


ATMO_Status_t DetectMotion_setup(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_Config_t config;
	config.address = ATMO_PROPERTY(DetectMotion, i2cAddress);
	config.i2cDriverInstance = ATMO_PROPERTY(DetectMotion, i2cInstance);
	config.gpioDriverInstance = ATMO_PROPERTY(DetectMotion, gpioInstance);
	config.int1En = ATMO_PROPERTY(DetectMotion, interrupt1Enabled);
    config.int2En = ATMO_PROPERTY(DetectMotion, interrupt2Enabled);
    config.int1Pin = ATMO_PROPERTY(DetectMotion, interrupt1Gpio);
    config.int2Pin = ATMO_PROPERTY(DetectMotion, interrupt2Gpio);

    switch(ATMO_PROPERTY(DetectMotion, motionDetectType))
    {
        case FXOS8700_NoDetect:
        {
            config.freefallEnabled = false;
            config.motionEnabled = false;
            config.tapDetectionEnabled = false;
            break;
        }
        case FXOS8700_FreefallDetect:
        {
            config.freefallEnabled = true;
            config.motionEnabled = false;
            config.tapDetectionEnabled = false;
            break;
        }
        case FXOS8700_MotionDetect:
        {
            config.freefallEnabled = false;
            config.motionEnabled = true;
            config.tapDetectionEnabled = false;
            break;
        }
        case FXOS8700_TapDetect:
        {
            config.freefallEnabled = false;
            config.motionEnabled = false;
            config.tapDetectionEnabled = true;
            break; 
        }
        default:
        {
            config.freefallEnabled = false;
            config.motionEnabled = false;  
            config.tapDetectionEnabled = false;
            break;
        }
    }

    ATMO_FXOS8700_SetMotionDetectedAbilityHandle(ATMO_ABILITY(DetectMotion, detectMotion));
    ATMO_FXOS8700_SetFreefallDetectedAbilityHandle(ATMO_ABILITY(DetectMotion, detectFreefall));
    ATMO_FXOS8700_SetTapDetectedAbilityHandle(ATMO_ABILITY(DetectMotion, detectTap));
	ATMO_FXOS8700_Init(&config);

    return ATMO_Status_Success;
	
}


ATMO_Status_t DetectMotion_setEnabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_FXOS8700_SetEnabled(true);
return ATMO_Status_Success;
}


ATMO_Status_t DetectMotion_setDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
ATMO_FXOS8700_SetEnabled(false);
return ATMO_Status_Success;
}


ATMO_Status_t DetectMotion_setEnabledDisabled(ATMO_Value_t *in, ATMO_Value_t *out) {
bool enabled = false;
ATMO_GetBool(in, &enabled);
ATMO_FXOS8700_SetEnabled(enabled);
return ATMO_Status_Success;
}


ATMO_Status_t DetectMotion_getSensorData(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueBinary(out, &data, sizeof(data));
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_getAccelX(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueFloat(out, data.accelX);
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_getAccelY(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueFloat(out, data.accelY);
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_getAccelZ(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueFloat(out, data.accelZ);
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_getMagX(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueFloat(out, data.magX);
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_getMagY(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueFloat(out, data.magY);
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_getMagZ(ATMO_Value_t *in, ATMO_Value_t *out) {
	ATMO_FXOS8700_SensorData_t data;

	if(ATMO_FXOS8700_GetSensorData(&data) != ATMO_FXOS8700_Status_Success)
	{
		ATMO_CreateValueVoid(out);
		return ATMO_Status_Fail;
	}

	ATMO_CreateValueFloat(out, data.magZ);
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_detectTap(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_detectMotion(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;

}


ATMO_Status_t DetectMotion_detectFreefall(ATMO_Value_t *in, ATMO_Value_t *out) {
	return ATMO_Status_Success;

}
...

This file has been truncated, please download it to see its full contents.

gatt_uuid128.h

C/C++
QN9080 SDK header file found under /source folder
/* 
* Declare all custom 128-bit UUIDs here using the format:
*
*  UUID128(name, bytes)
*
* where: 
*	-name : an unique tag for the newly defined UUID;
		will be used to reference this UUID when defining
		services and characteristics in <<gatt_db.h>>
*	-bytes: 16 bytes representing the 128-bit value
*
* One definition per line. No semicolon required after each definition.
*
* example:
*  UUID128(uuid_service_robot_characteristics, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF)
*  UUID128(uuid_char_robot_direction, 0x12, 0x34, 0x50, 0x00, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF)
*	
*/
/* Services */

/* Temperature */ 
UUID128(uuid_service_temperature, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x00, 0x02, 0xFF, 0x01)

// MIDI-BLE Service: 03B80E5A-EDE8-4B33-A751-6CE34EC4C700
UUID128(uuid_service_midile, 0x00, 0xC7, 0xC4, 0x4E, 0xE3, 0x6C, 0x51, 0xA7, 0x33, 0x4B, 0xE8, 0xED, 0x5A, 0x0E, 0xB8, 0x03)
// MIDI-BLE characteristic: 7772E5DB-3868-4112-A1A9-F2669D106BF3
UUID128(uuid_characteristic_midile, 0xF3, 0x6B, 0x10, 0x9D, 0x66, 0xF2, 0xA9, 0xA1, 0x12, 0x41, 0x68, 0x38, 0xDB, 0xE5, 0x72, 0x77)

// NRF UART Service UUID128: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
UUID128(uuid_service_nrfuart,           0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E)
// NRF UART Rx characteristic UUID128: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E
UUID128(uuid_characteristic_nrfuart_rx, 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E)
// NRF UART Tx characteristic UUID128: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
UUID128(uuid_characteristic_nrfuart_tx, 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E)

temperature_collector.c

C/C++
Main updated code of temperature collector example modified to connect to a nRF UART protocol to stream MIDI messages through the debug COM port.
/*! *********************************************************************************
* \addtogroup Temperature Collector
* @{
********************************************************************************** */
/*! *********************************************************************************
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* This file is the source file for the Temperature Collector application
*
* SPDX-License-Identifier: BSD-3-Clause
********************************************************************************** */

/************************************************************************************
*************************************************************************************
* Include
*************************************************************************************
************************************************************************************/
/* Framework / Drivers */
#include "RNG_Interface.h"
#include "Keyboard.h"
#include "LED.h"
#include "Panic.h"
#include "TimersManager.h"
#include "FunctionLib.h"
#include "shell.h"
#if (cPWR_UsePowerDownMode)
#include "PWR_Interface.h"
#include "PWR_Configuration.h"
#endif

/* BLE Host Stack */
#include "gatt_server_interface.h"
#include "gatt_client_interface.h"
#include "gap_interface.h"
#include "gatt_db_app_interface.h"
#include "gatt_db_handles.h"

/* Profile / Services */
#include "temperature_interface.h"

#include "ble_conn_manager.h"
#include "ble_service_discovery.h"

#include "ApplMain.h"
#include "temperature_collector.h"

// mmerlin: for atoi
#include <stdlib.h>

/*************************************************************************************
**************************************************************************************
* Public macros
**************************************************************************************
*************************************************************************************/
const char* mGattStatus[] = {
    "NoError",
    "InvalidHandle",
    "ReadNotPermitted",
    "WriteNotPermitted",
    "InvalidPdu",
    "InsufficientAuthentication",
    "RequestNotSupported",
    "InvalidOffset",
    "InsufficientAuthorization",
    "PrepareQueueFull",
    "AttributeNotFound",
    "AttributeNotLong",
    "InsufficientEncryptionKeySize",
    "InvalidAttributeValueLength",
    "UnlikelyError",
    "InsufficientEncryption",
    "UnsupportedGroupType",
    "InsufficientResources",
};

/************************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
************************************************************************************/
#define mShellGattCmdsCount_c               6

#define mMaxServicesCount_d                 6
#define mMaxServiceCharCount_d              8
#define mMaxCharDescriptorsCount_d          2
#define mMaxCharValueLength_d               128 // ATMO_STATIC_SIZE

#define mThroughputReportThreshold_c        100
#define hNrfUartTxHandle                    34

/************************************************************************************
*************************************************************************************
* Shell Configuration
*************************************************************************************
************************************************************************************/
#define DEBUG_SHELL 0
#define debug_shell_write(fmt) if(DEBUG_SHELL) shell_write(fmt);
#define debug_shell_writeDec(fmt) if(DEBUG_SHELL) shell_writeDec(fmt);
#define debug_shell_writeLe(fmt) if(DEBUG_SHELL) shell_writeLe(fmt);
#define debug_shell_writeN(fmt,len) if(DEBUG_SHELL) shell_writeN(fmt,len);
#define debug_shell_writeHexLe(fmt,len) if(DEBUG_SHELL) shell_writeHexLe(fmt,len);

#define MIDI_SHELL 1
#define midi_write(fmt,len) if(MIDI_SHELL) shell_writeN(fmt,len);

/************************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
************************************************************************************/

typedef enum appEvent_tag{
    mAppEvt_PeerConnected_c,
    mAppEvt_PairingComplete_c,
    mAppEvt_ServiceDiscoveryComplete_c,
    mAppEvt_ServiceDiscoveryFailed_c,
    mAppEvt_GattProcComplete_c,
    mAppEvt_GattProcError_c
}appEvent_t;

typedef enum appState_tag{
    mAppIdle_c,
    mAppExchangeMtu_c,
    mAppServiceDisc_c,
    mAppReadDescriptor_c,
    mAppRunning_c,
}appState_t;

/*! Temperature Client - Configuration 
typedef struct tmcConfig_tag
{
    uint16_t    hService;
    uint16_t    hTemperature;
    uint16_t    hTempCccd;
    uint16_t    hTempDesc;
    gattDbCharPresFormat_t  tempFormat;
} tmcConfig_t;*/

typedef struct nrfUartConfig_tag
{  uint16_t    hService;
   gattDbCharPresFormat_t  dataFormat;   
   uint16_t    hNrfuart;
} nrfUartConfig_t;

typedef struct appCustomInfo_tag
{
    // tmcConfig_t     tempClientConfig;
    /* Add persistent information here */
    nrfUartConfig_t nrfuartClientConfig;
}appCustomInfo_t;

typedef struct appPeerInfo_tag
{
    deviceId_t      deviceId;
    appCustomInfo_t customInfo;
    bool_t          isBonded;
    appState_t      appState;
}appPeerInfo_t;


/************************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
************************************************************************************/
static appPeerInfo_t mPeerInformation;

#if gAppUseBonding_d
static bool_t mRestoringBondedLink = FALSE;
#endif

static bool_t   mScanningOn = FALSE;
static bool_t   mFoundDeviceToConnect = FALSE;

/* Buffer used for Characteristic related procedures */
static gattAttribute_t      *mpCharProcBuffer = NULL;

/* Timers */
static tmrTimerID_t mAppTimerId;

/************************************************************************************
*************************************************************************************
* mmerlin: ported from ble_shell
*************************************************************************************
************************************************************************************/

/* Buffer used for Service Discovery */
/*static gattService_t *mpServiceDiscoveryBuffer = NULL;
static uint8_t  mcPrimaryServices = 0;*/

/* Buffer used for Characteristic Discovery */
static gattCharacteristic_t *mpCharBuffer = NULL;
/*static uint8_t mCurrentServiceInDiscoveryIndex;
static uint8_t mCurrentCharInDiscoveryIndex;
static uint8_t mcCharacteristics = 0;*/

/* Buffer used for Characteristic Descriptor Discovery */
/*static gattAttribute_t *mpCharDescriptorBuffer = NULL;*/

/************************************************************************************
*************************************************************************************
* Private functions prototypes
*************************************************************************************
************************************************************************************/

//mmerlin: ported from ble_shell
static int8_t MidiLeGatt_Read(uint8_t CharHandle);
static uint8_t MidiLeGatt_Print(deviceId_t serverDeviceId);

static void BleApp_PrintMidile ( uint8_t *msg, uint16_t msgLen);


/* Host Stack callbacks */
static void BleApp_ScanningCallback
(
    gapScanningEvent_t* pScanningEvent
);

static void BleApp_ConnectionCallback
(
    deviceId_t peerDeviceId,
    gapConnectionEvent_t* pConnectionEvent
);

static void BleApp_GattClientCallback
(
    deviceId_t              serverDeviceId,
    gattProcedureType_t     procedureType,
    gattProcedureResult_t   procedureResult,
    bleResult_t             error
);

static void BleApp_GattNotificationCallback
(
    deviceId_t          serverDeviceId,
    uint16_t characteristicValueHandle,
    uint8_t* aValue,
    uint16_t valueLength
);

static void BleApp_ServiceDiscoveryCallback
(
	deviceId_t deviceId,
	servDiscEvent_t* pEvent
);

static void BleApp_Config(void);

void BleApp_StateMachineHandler
(
    deviceId_t peerDeviceId,
    uint8_t event
);

static bool_t CheckScanEvent(gapScannedDevice_t* pData);

static void BleApp_StoreServiceHandles
(
    gattService_t   *pService
);

static void BleApp_StoreDescValues
(
    gattAttribute_t     *pDesc
);

/*static void BleApp_PrintTemperature
(
    uint16_t temperature
);*/

static bleResult_t BleApp_ConfigureNotifications(void);

static void ScanningTimeoutTimerCallback(void* pParam);
#if (cPWR_UsePowerDownMode)
static void DisconnectTimerCallback(void* pParam);
#endif
/************************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
************************************************************************************/

/*! *********************************************************************************
* \brief    Initializes application specific functionality before the BLE stack init.
*
********************************************************************************** */
void BleApp_Init(void)
{
    /* UI */
    shell_init("BLE Temp Collector>");
}

/*! *********************************************************************************
* \brief    Starts the BLE application.
*
********************************************************************************** */
void BleApp_Start(void)
{
    if (!mScanningOn)
    {
        App_StartScanning(&gScanParams, BleApp_ScanningCallback, TRUE);
    }
}

/*! *********************************************************************************
* \brief        Handles keyboard events.
*
* \param[in]    events    Key event structure.
********************************************************************************** */
void BleApp_HandleKeys(key_event_t events)
{
#if (cPWR_UsePowerDownMode)
    BleApp_Start();
#else
    switch (events)
    {
        case gKBD_EventPressPB1_c:
        {
            BleApp_Start();
            break;
        }
        case gKBD_EventLongPB1_c:
        {
            if (mPeerInformation.deviceId != gInvalidDeviceId_c)
                Gap_Disconnect(mPeerInformation.deviceId);
            break;
        }
        case gKBD_EventPressPB2_c:
        case gKBD_EventLongPB2_c:
        default:
            break;
    }
#endif
}

/*! *********************************************************************************
* \brief        Handles BLE generic callback.
*
* \param[in]    pGenericEvent    Pointer to gapGenericEvent_t.
********************************************************************************** */
void BleApp_GenericCallback (gapGenericEvent_t* pGenericEvent)
{
    /* Call BLE Conn Manager */
    BleConnManager_GenericEvent(pGenericEvent);

    switch (pGenericEvent->eventType)
    {
        case gInitializationComplete_c:
        {
            BleApp_Config();
        }
        break;
        default:
            break;
    }
}

/************************************************************************************
*************************************************************************************
* Private functions
*************************************************************************************
************************************************************************************/

/*! *********************************************************************************
* \brief        Configures BLE Stack after initialization. Usually used for
*               configuring advertising, scanning, white list, services, et al.
*
********************************************************************************** */
static void BleApp_Config()
{
    /* Configure as GAP Central */
    BleConnManager_GapCentralConfig();

    /* Register for callbacks*/
    App_RegisterGattClientProcedureCallback(BleApp_GattClientCallback);
    App_RegisterGattClientNotificationCallback(BleApp_GattNotificationCallback);
    BleServDisc_RegisterCallback(BleApp_ServiceDiscoveryCallback);
    
    /* Initialize private variables */
    mPeerInformation.appState = mAppIdle_c;
    mScanningOn = FALSE;
    mFoundDeviceToConnect = FALSE;

    /* Allocate scann timeout timer */
    mAppTimerId = TMR_AllocateTimer();

    /* UI */
    debug_shell_write("\r\nPress SCANSW to connect to a Temperature Sensor!\r\n");

#if (cPWR_UsePowerDownMode)
    /* Allow entering sleep mode until any user interaction */
    PWR_AllowDeviceToSleep();
#endif
}


/*! *********************************************************************************
* \brief        Handles BLE Scanning callback from host stack.
*
* \param[in]    pScanningEvent    Pointer to gapScanningEvent_t.
********************************************************************************** */
static void BleApp_ScanningCallback (gapScanningEvent_t* pScanningEvent)
{
    switch (pScanningEvent->eventType)
    {
        case gDeviceScanned_c:
        {
            mFoundDeviceToConnect = CheckScanEvent(&pScanningEvent->eventData.scannedDevice);
            //mFoundDeviceToConnect = TRUE;
            if (mFoundDeviceToConnect)
            {
                gConnReqParams.peerAddressType = pScanningEvent->eventData.scannedDevice.addressType;
                FLib_MemCpy(gConnReqParams.peerAddress, 
                            pScanningEvent->eventData.scannedDevice.aAddress,
                            sizeof(bleDeviceAddress_t));
                
                Gap_StopScanning();
#if gAppUsePrivacy_d
                gConnReqParams.usePeerIdentityAddress = pScanningEvent->eventData.scannedDevice.advertisingAddressResolved;
#endif
                App_Connect(&gConnReqParams, BleApp_ConnectionCallback);
           }
        }
        break;
        case gScanStateChanged_c:
        {
            mScanningOn = !mScanningOn;

            /* Node starts scanning */
            if (mScanningOn)
            {
                mFoundDeviceToConnect = FALSE;

                debug_shell_write("\r\nScanning...\r\n");

                /* Start advertising timer */
                TMR_StartLowPowerTimer(mAppTimerId,
                           gTmrLowPowerSecondTimer_c,
                           TmrSeconds(gScanningTime_c),
                           ScanningTimeoutTimerCallback, NULL);
#if (cPWR_UsePowerDownMode)
                PWR_ChangeDeepSleepMode(1);
                PWR_AllowDeviceToSleep();
                Led1On();
#else
                LED_StopFlashingAllLeds();
                Led1Flashing();
#endif
            }
            /* Node is not scanning */
            else
            {
                TMR_StopTimer(mAppTimerId);

                if (mFoundDeviceToConnect)
                {
                    App_Connect(&gConnReqParams, BleApp_ConnectionCallback);
                }
                else
                {
#if (cPWR_UsePowerDownMode)
                    Led1Off();
                    /* Go to sleep */
                    PWR_ChangeDeepSleepMode(3);
#else
                    LED_StopFlashingAllLeds();
                    Led1Flashing();
                    Led2Flashing();
                    Led3Flashing();
                    Led4Flashing();
#endif
                }
            }
        }
        break;

        case gScanCommandFailed_c:
        {
        }
    default:
      {
      shell_write("Scanning Event: ");
      shell_writeDec(pScanningEvent->eventType);
      break;
      }
    }
}

/*! *********************************************************************************
* \brief        Handles BLE Connection callback from host stack.
*
* \param[in]    peerDeviceId        Peer device ID.
* \param[in]    pConnectionEvent    Pointer to gapConnectionEvent_t.
********************************************************************************** */
static void BleApp_ConnectionCallback (deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent)
{
	/* Connection Manager to handle Host Stack interactions */
	BleConnManager_GapCentralEvent(peerDeviceId, pConnectionEvent);

    switch (pConnectionEvent->eventType)
    {
        case gConnEvtConnected_c:
        {
            /* UI */
            LED_StopFlashingAllLeds();
            Led1On();
            debug_shell_write("\r\nConnected!\r\n");

            mPeerInformation.deviceId = peerDeviceId;
            mPeerInformation.isBonded = FALSE;

#if (cPWR_UsePowerDownMode)
            PWR_ChangeDeepSleepMode(1);
            PWR_AllowDeviceToSleep();
#endif

            
#if gAppUseBonding_d
            Gap_CheckIfBonded(peerDeviceId, &mPeerInformation.isBonded);

            if ((mPeerInformation.isBonded) &&
                (gBleSuccess_c == Gap_LoadCustomPeerInformation(peerDeviceId,
                    (void*) &mPeerInformation.customInfo, 0, sizeof (appCustomInfo_t))))
            {
                mRestoringBondedLink = TRUE;
                /* Restored custom connection information. Encrypt link */
                Gap_EncryptLink(peerDeviceId);
            }
#endif
            BleApp_StateMachineHandler(mPeerInformation.deviceId, mAppEvt_PeerConnected_c);
        }
        break;

        case gConnEvtDisconnected_c:
        {
            mPeerInformation.deviceId = gInvalidDeviceId_c;
            mPeerInformation.appState = mAppIdle_c;

            /* Reset Service Discovery to be sure*/
            BleServDisc_Stop(peerDeviceId);

            /* UI */
            debug_shell_write("\r\nDisconnected!\r\n");

#if (cPWR_UsePowerDownMode)
            /* Go to sleep */
            PWR_ChangeDeepSleepMode(3);
            Led1Off();
#else
            LED_TurnOffAllLeds();
            LED_StartFlash(LED_ALL);
#endif
        }
        break;

#if gAppUsePairing_d
        case gConnEvtPairingComplete_c:
        {
            if (pConnectionEvent->eventData.pairingCompleteEvent.pairingSuccessful)
            {
                BleApp_StateMachineHandler(mPeerInformation.deviceId, mAppEvt_PairingComplete_c);
            }
        }
        break;

#if gAppUseBonding_d        
        case gConnEvtEncryptionChanged_c:
        {
            if( pConnectionEvent->eventData.encryptionChangedEvent.newEncryptionState )
            {
                if( mRestoringBondedLink )
                {
                    if( gBleSuccess_c != BleApp_ConfigureNotifications() )
                    {
                        Gap_Disconnect(peerDeviceId);
                    }
                    else
                    {
                        mRestoringBondedLink = FALSE;
                    }
                }
            }
        }
        break;
        
        case gConnEvtAuthenticationRejected_c:
        {
            /* Start Pairing Procedure */
            Gap_Pair(peerDeviceId, &gPairingParameters);
        }
        break;
#endif /* gAppUseBonding_d */
#endif /* gAppUsePairing_d */

    default:
        break;
    }
}

static void BleApp_ServiceDiscoveryCallback(deviceId_t peerDeviceId, servDiscEvent_t* pEvent)
{
	switch(pEvent->eventType)
	{
		case gServiceDiscovered_c:
		{
                        debug_shell_write("\n\rService Discovered!\n");
			BleApp_StoreServiceHandles(pEvent->eventData.pService);
		}
		break;

		case gDiscoveryFinished_c:
		{
			if (pEvent->eventData.success)
			{
				BleApp_StateMachineHandler(peerDeviceId, mAppEvt_ServiceDiscoveryComplete_c);
			}
			else
			{
				BleApp_StateMachineHandler(peerDeviceId, mAppEvt_ServiceDiscoveryFailed_c);
			}
		}
		break;

		default:
		break;
	}
}

/*! *********************************************************************************
* \brief        Stores handles for the specified service.
*
* \param[in]    pService    Pointer to gattService_t.
********************************************************************************** */
static void BleApp_StoreServiceHandles
(
    gattService_t   *pService
)
{
    uint8_t i,j;

    debug_shell_write("\n\rService UUID 128: ");
    debug_shell_writeHexLe(pService->uuid.uuid128,16);
    // debug_shell_write("\n\rService UUID 16: ");
    // debug_shell_writeHexLe(&(pService->uuid.uuid16),2);
    
    /*if ((pService->uuidType == gBleUuidType16_c) &&
        FLib_MemCmp(pService->uuid.uuid128, uuid_service_temperature, 16))*/
    if ( FLib_MemCmp(pService->uuid.uuid128, uuid_service_nrfuart, 16))    
    {
        debug_shell_write("\n\r Explore Service Characteristics!");
        /* Found Temperature Service */
        // mPeerInformation.customInfo.tempClientConfig.hService = pService->startHandle;
        mPeerInformation.customInfo.nrfuartClientConfig.hService = pService->startHandle;

        for (i = 0; i < pService->cNumCharacteristics; i++)
        {            
              debug_shell_write("\n\rCharacteristic UUID 128: ");
              debug_shell_writeHexLe(pService->aCharacteristics[i].value.uuid.uuid128,16);
              // debug_shell_write("\n\rCharacteristic UUID 16: ");
              // debug_shell_writeHexLe(&(pService->aCharacteristics[i].value.uuid.uuid16),2);

                /*if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&
                (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Temperature_d))*/
            if (FLib_MemCmp(pService->aCharacteristics[i].value.uuid.uuid128, uuid_characteristic_nrfuart_tx,16))
            {
              debug_shell_write("\n\rFound NRF TX! Handle: ");
              debug_shell_writeDec(pService->aCharacteristics[i].value.handle);
                /* Found Temperature Char */
                // mPeerInformation.customInfo.tempClientConfig.hTemperature = pService->aCharacteristics[i].value.handle;
                mPeerInformation.customInfo.nrfuartClientConfig.hService= pService->aCharacteristics[i].value.handle;

                for (j = 0; j < pService->aCharacteristics[i].cNumDescriptors; j++)
                {
                    if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType16_c)
                    //if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType128_c)
                    {  
                        switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16)
                        //switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid128)
                        {
                            /*case gBleSig_CharPresFormatDescriptor_d:
                            {
                                debug_shell_write("\n\rgBleSig_CharPresFormatDescriptor_d!\n");
                                debug_shell_writeDec(pService->aCharacteristics[i].aDescriptors[j].handle);
                                mPeerInformation.customInfo.tempClientConfig.hTempDesc = pService->aCharacteristics[i].aDescriptors[j].handle;
                                break;
                            }*/
                            case gBleSig_CCCD_d:
                            {
                                debug_shell_write("\n\rgBleSig_CCCD_d: ");
                                debug_shell_writeDec(pService->aCharacteristics[i].aDescriptors[j].handle);
                                // mPeerInformation.customInfo.tempClientConfig.hTempCccd = pService->aCharacteristics[i].aDescriptors[j].handle;
                                mPeerInformation.customInfo.nrfuartClientConfig.hNrfuart = pService->aCharacteristics[i].aDescriptors[j].handle;
                                break;
                            }

                            default:
                              debug_shell_write("\n\rUnknown Characteristic Descriptor! \n");
                              debug_shell_writeDec(pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16);
                            break;
                        }
                    }
                }
            }
        }
    }
}


static void BleApp_StoreDescValues
(
    gattAttribute_t     *pDesc
)
{
    debug_shell_write("\n\rBleApp_StoreDescValues \n\r");
    // if (pDesc->handle == mPeerInformation.customInfo.tempClientConfig.hTempDesc)
    if (pDesc->handle == hNrfUartTxHandle)
    {
        /* Store temperature format*/
        // FLib_MemCpy(&mPeerInformation.customInfo.tempClientConfig.tempFormat,
        FLib_MemCpy(&mPeerInformation.customInfo.nrfuartClientConfig.dataFormat,
                    pDesc->paValue,
                    pDesc->valueLength);
    }

}

/*static void BleApp_PrintTemperature
(
    uint16_t temperature
)
{
    debug_shell_write("Temperature: ");
    debug_shell_writeDec(temperature/100);
   //  if (mPeerInformation.customInfo.tempClientConfig.tempFormat.unitUuid16 == 0x272F)
    if (mPeerInformation.customInfo.nrfuartClientConfig.dataFormat.unitUuid16 == 0x272F)
    {
        debug_shell_write(" C\r\n");
    }
    else
    {
        debug_shell_write("\r\n");
    }
}*/

static void BleApp_PrintMidile
(
    uint8_t *msg,
    uint16_t msgLen
)
{
    debug_shell_write("MIDI Message: ");
    debug_shell_writeHexLe(msg,msgLen);
    debug_shell_write("\n\rRAW MIDI Message: ");
    midi_write(msg,msgLen);
}

/*! *********************************************************************************
* \brief        Handles GATT client callback from host stack.
*
* \param[in]    serverDeviceId      GATT Server device ID.
* \param[in]    procedureType    	Procedure type.
* \param[in]    procedureResult    	Procedure result.
* \param[in]    error    			Callback result.
********************************************************************************** */
static void BleApp_GattClientCallback(
    deviceId_t              serverDeviceId,
    gattProcedureType_t     procedureType,
    gattProcedureResult_t   procedureResult,
    bleResult_t             error
)
{
    if (procedureResult == gGattProcError_c)
    {
      debug_shell_write("\r\ngGattProcError_c !\n\r");
      uint8_t lattError = (uint8_t) (error & 0xFF);
      debug_shell_write("\n\r-->  GATT Event: Procedure Error ");
      debug_shell_write((char*)mGattStatus[lattError]);
      // SHELL_NEWLINE();
      
        attErrorCode_t attError = (attErrorCode_t) (error & 0xFF);
        if (attError == gAttErrCodeInsufficientEncryption_c     ||
            attError == gAttErrCodeInsufficientAuthorization_c  ||
            attError == gAttErrCodeInsufficientAuthentication_c 
            )
        {
            /* Start Pairing Procedure */
            Gap_Pair(serverDeviceId, &gPairingParameters);           
        }

        BleApp_StateMachineHandler(serverDeviceId, mAppEvt_GattProcError_c);
    }
    else if (procedureResult == gGattProcSuccess_c)
    {
        switch(procedureType)
        {
            case gGattProcExchangeMtu_c:
              {
              debug_shell_write("\r\ngGattProcExchangeMtu_c\r\n");
              // GattClient_ExchangeMtu(serverDeviceId);
              break; 
              }
            case gGattProcReadCharacteristicDescriptor_c:
            {
                if (mpCharProcBuffer != NULL)
                {
                    debug_shell_write("\r\ngGattProcReadCharacteristicDescriptor_c\r\n");
                    BleApp_StoreDescValues(mpCharProcBuffer);
                }
            break;
            }
            case gGattProcDiscoverAllCharacteristics_c: 
              {
              debug_shell_write("\r\ngGattProcDiscoverAllCharacteristics_c\r\n");
              break; 
              }
  
            case gGattProcDiscoverAllCharacteristicDescriptors_c:               
              {
              debug_shell_write("\r\ngGattProcDiscoverAllCharacteristicDescriptors_c\r\n");
              break; 
              }
           
            case gGattProcDiscoverAllPrimaryServices_c:
              {
              debug_shell_write("\r\ngGattProcDiscoverAllPrimaryServices_c\r\n");
              break; 
              }
           
            case gGattProcDiscoverPrimaryServicesByUuid_c:
            {
            debug_shell_write("\r\ngGattProcDiscoverPrimaryServicesByUuid_c\r\n");
            break;
            }

            
            case gGattProcDiscoverCharacteristicByUuid_c:
            {
            debug_shell_write("\r\ngGattProcDiscoverCharacteristicByUuid_c\r\n");
            break;
            }
            
            case gGattProcReadCharacteristicValue_c:
            {
              
                MidiLeGatt_Print(serverDeviceId);
                /*debug_shell_write("\n\r-->  GATT Event: Characteristic Value Read ");
                debug_shell_write("\n\r     Value: ");
                debug_shell_writeHexLe(mpCharBuffer->value.paValue, mpCharBuffer->value.valueLength);
                // shell_cmd_finished();
                
                // mmerlin: trigger a new read
        	BleApp_StateMachineHandler(serverDeviceId, mAppEvt_ServiceDiscoveryComplete_c);
                
                MEM_BufferFree(mpCharBuffer->value.paValue);
                MEM_BufferFree(mpCharBuffer);
                mpCharBuffer = NULL;*/
                break;
            }

            case gGattProcWriteCharacteristicValue_c:
            {
                debug_shell_write("\n\r-->  GATT Event: Characteristic Value Written!");
                break;            
            }
            
            default:
              {
              debug_shell_write("\n\rUnknown procedure: ");
              debug_shell_writeDec(procedureResult);
              break;
              }
              
        }

    	BleApp_StateMachineHandler(serverDeviceId, mAppEvt_GattProcComplete_c);
    }

    /* Signal Service Discovery Module */
    BleServDisc_SignalGattClientEvent(serverDeviceId, procedureType,procedureResult, error);

}

/*! *********************************************************************************
* \brief        Handles GATT client notification callback from host stack.
*
* \param[in]    serverDeviceId      		GATT Server device ID.
* \param[in]    characteristicValueHandle   Handle.
* \param[in]    aValue    					Pointer to value.
* \param[in]    valueLength    				Value length.
********************************************************************************** */
static void BleApp_GattNotificationCallback
(
    deviceId_t  serverDeviceId,
    uint16_t    characteristicValueHandle,
    uint8_t*    aValue,
    uint16_t    valueLength
)
{
  debug_shell_write("\r\nNotification Callback!\n\r");
  
    //if (characteristicValueHandle == mPeerInformation.customInfo.tempClientConfig.hTemperature)
    if (characteristicValueHandle == hNrfUartTxHandle)
    {
        // BleApp_PrintTemperature(*(uint16_t*)aValue);
        BleApp_PrintMidile(aValue,valueLength);

#if (cPWR_UsePowerDownMode)
        /* Restart Wait For Data timer */
        TMR_StartLowPowerTimer(mAppTimerId,
                       gTmrLowPowerSecondTimer_c,
                       TmrSeconds(gWaitForDataTime_c),
                       DisconnectTimerCallback, NULL);
#endif
    }
}

static bool_t MatchDataInAdvElementList(gapAdStructure_t *pElement, void *pData, uint8_t iDataLen)
{
    uint8_t i;

    for (i=0; i < pElement->length; i+=iDataLen)
    {
        if (FLib_MemCmp(pData, &pElement->aData[i], iDataLen))
        {
            return TRUE;
        }
    }
    return FALSE;
}

uint8_t riot_mac[] = {0xB3, 0xAF , 0x0A , 0x37 , 0x60, 0x00 };
char riot_dname[] = "PAFB3";

static bool_t CheckScanEvent(gapScannedDevice_t* pData)
{
    uint8_t index = 0;
    uint8_t name[10];
    uint8_t nameLength;
    bool_t foundMatch = FALSE;

    while (index < pData->dataLength)
    {
        gapAdStructure_t adElement;

        adElement.length = pData->data[index];
        adElement.adType = (gapAdType_t)pData->data[index + 1];
        adElement.aData = &pData->data[index + 2];

         /* Search for Temperature Custom Service */
        if ((adElement.adType == gAdIncomplete128bitServiceList_c) ||
          (adElement.adType == gAdComplete128bitServiceList_c))
        {
            //foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_temperature, 16);
        }

        if ((adElement.adType == gAdShortenedLocalName_c) ||
          (adElement.adType == gAdCompleteLocalName_c))
        {
            nameLength = MIN(adElement.length, 10);
            FLib_MemCpy(name, adElement.aData, nameLength);
            
            //mmerlin:  check MAC                
            // foundMatch = FLib_MemCmp(riot_mac, pData->aAddress, 6);
            foundMatch = FLib_MemCmp((uint8_t*)  riot_dname, name, 5);
        }

        /* Move on to the next AD elemnt type */
        index += adElement.length + sizeof(uint8_t);
    }

    if (foundMatch)
    {
        /* UI */
        debug_shell_write("\r\nFound device: \r\n");
        debug_shell_writeN((char*)name, nameLength-1);
        SHELL_NEWLINE();
        debug_shell_writeHexLe(pData->aAddress, 6);
    }
    return foundMatch;
}

void BleApp_StateMachineHandler(deviceId_t peerDeviceId, uint8_t event)
{
    switch (mPeerInformation.appState)
    {
        case mAppIdle_c:
        {
            debug_shell_write("\nState mAppIdle_c\n");

            if (event == mAppEvt_PeerConnected_c)
            {
#if gAppUseBonding_d
                if (mPeerInformation.customInfo.tempClientConfig.hTemperature != gGattDbInvalidHandle_d)
                {
                    /* Moving to Running State */
...

This file has been truncated, please download it to see its full contents.

Credits

Marco Merlin

Marco Merlin

4 projects • 7 followers
Electronics Engineer, passionate for tech and music, able to "get things done", curious and aspiring to "solve real-life problems".

Comments