Rikita YAMADA / Mbed OS my-ble

Files at this revision

API Documentation at this revision

Comitter:
rikita
Date:
Fri May 25 01:34:23 2018 +0000
Commit message:
First commit.

Changed in this revision

mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
my-ble-config.h Show annotated file Show diff for this revision Revisions of this file
my-ble.cpp Show annotated file Show diff for this revision Revisions of this file
my-ble/main.cpp Show annotated file Show diff for this revision Revisions of this file
my-ble/my-ble-definition.h Show annotated file Show diff for this revision Revisions of this file
my-ble/my-ble-hardware.cpp Show annotated file Show diff for this revision Revisions of this file
my-ble/my-ble-hardware.h Show annotated file Show diff for this revision Revisions of this file
my-ble/my-ble-service.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 72ab2fd9994b mbed-os.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#ae6c7c60f91c89cbf755a2f3c8ec9c66635849fd
diff -r 000000000000 -r 72ab2fd9994b my-ble-config.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble-config.h	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 ASAHI KASEI MICRODEVICES CORPORATION, Japan
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+/** You can change these definition */
+
+/** Define your device name. The length of name must be less than 10
+ */
+#define MY_DEVICE_NAME    "MyDevice"
+
+/** Define timer interval in second.
+ */
+#define MY_TIMER_INTERVAL (5)
+
+/** Define triggers. When these events occur, then your program 
+ * (i.e. my-ble_trigger() function) will be called.
+ * This value must be a conjunction of #my_ble_trigger_t type.
+ */
+#define MY_TRIGGERS (MY_TRIGGER_TIMER | MY_TRIGGER_INT2_FALL | MY_TRIGGER_INT1_RISE)
+
+/** Define if you want to assign TRIGGER_INT1 to Button 1, or
+ * TRIGGER_INT2 to Button 2, please uncomment the below
+ */
+#define USE_BUTTON1
+#define USE_BUTTON2
+
diff -r 000000000000 -r 72ab2fd9994b my-ble.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble.cpp	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 ASAHI KASEI MICRODEVICES CORPORATION, Japan
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#include <mbed.h>
+#include "my-ble-definition.h"
+
+/** @brief Initialize device.
+ * @return MY_SUCCESS when device is successfully initialized.
+ * @return Other when device is not initialized.
+ */
+uint32_t my_ble_init(void) {
+    DPRINTF("my init\r\n");
+    return MY_SUCCESS;
+}
+
+/** @brief This function is called when timer period is elapsed.
+ * The timer interval is defined as #MY_TIMER_INTERVAL.
+ */
+void my_ble_timer(void) {
+    /* get current time
+     * this time is elapsed time since the board boots up.
+     */
+    uint32_t tm = (uint32_t)time(NULL);
+
+    /** send data to BLE module */
+    MY_BLE->update_data1(tm);
+
+    DPRINTF("my timer (%d)\r\n", tm);
+}
+
+/** @brief This function is called when INT1 pin changes
+ * from LOW to HIGH. In case of BUTTON1, the button 1 is released.
+ */
+void my_ble_int1_rise(void) {
+    /* do something */
+    DPRINTF("my int1 rise\r\n");
+}
+
+/** @brief This function is called when INT1 pin changes
+ * from HIGH to LOW. In case of BUTTON1, the button 1 is pressed.
+ */
+void my_ble_int1_fall(void) {
+    /* do something */
+    DPRINTF("my int1 fall\r\n");
+}
+
+void my_ble_int2_rise(void) {
+    /* do something */
+    DPRINTF("my int2 rise\r\n");
+}
+
+void my_ble_int2_fall(void) {
+    /* do something */
+    DPRINTF("my int2 fall\r\n");
+}
+
+void my_ble_received(const uint32_t data) {
+    /* do something */
+    DPRINTF("Data received (%d)\r\n", data);
+}
diff -r 000000000000 -r 72ab2fd9994b my-ble/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble/main.cpp	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,220 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2014 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <events/mbed_events.h>
+#include <mbed.h>
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "my-ble-definition.h"
+
+/** BLE service definition. don't edit this */
+const static char     DEVICE_NAME[] = MY_DEVICE_NAME;
+const static uint32_t trigger_flags = MY_TRIGGERS;
+static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
+UUID MY_SERVICE_UUID("4c592000-0000-0000-0000-000000000000");
+MyBLEservice* MY_BLE;
+
+char *ble_error_string(const ble_error_t error) {
+    switch(error) {
+    case BLE_ERROR_BUFFER_OVERFLOW:
+        return ((char*)"The requested action would cause a buffer overflow and has been aborted.");
+    case BLE_ERROR_NOT_IMPLEMENTED:
+        return ((char*)"Requested a feature that isn't yet implemented or isn't supported by the target HW.");
+    case BLE_ERROR_PARAM_OUT_OF_RANGE:
+        return ((char*)"One of the supplied parameters is outside the valid range.");
+    case BLE_ERROR_INVALID_PARAM:
+        return ((char*)"One of the supplied parameters is invalid.");
+    case BLE_STACK_BUSY:
+        return ((char*)"The stack is busy.");
+    case BLE_ERROR_INVALID_STATE:
+        return ((char*)"Invalid state.");
+    case BLE_ERROR_NO_MEM:
+        return ((char*)"Out of memory.");
+    case BLE_ERROR_OPERATION_NOT_PERMITTED:
+        return ((char*)"The operation requested is not permitted.");
+    case BLE_ERROR_INITIALIZATION_INCOMPLETE:
+        return ((char*)"The BLE subsystem has not completed its initialization.");
+    case BLE_ERROR_ALREADY_INITIALIZED:
+        return ((char*)"The BLE system has already been initialized.");
+    case BLE_ERROR_UNSPECIFIED:
+        return ((char*)"Unknown error.");
+    case BLE_ERROR_INTERNAL_STACK_FAILURE:
+        return ((char*)"The platform-specific stack failed.");
+    default:
+        return ((char*)"Unknown error");
+    }
+}
+
+static void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+    set_led(BLEST_LED, true);
+
+#ifdef MY_BLE_DEBUG
+    DPRINTF("Connected: %x", params->peerAddr[Gap::ADDR_LEN - 1]);
+    for (int i = Gap::ADDR_LEN - 2; i >= 0; i--)
+    {
+        DPRINTF(":%x", params->peerAddr[i]);
+    }
+    DPRINTF("\r\n");
+#endif
+}
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+    ble_error_t error;
+    set_led(BLEST_LED, false);
+    error = BLE::Instance().gap().startAdvertising();
+
+#ifdef MY_BLE_DEBUG
+    if (error == BLE_ERROR_NONE) {
+        DPRINTF("Disconnecte and start advertising.\r\n");
+    } else {
+        DPRINTF("Disconnected, but advertising failed.\r\n");
+        DPRINTF(" %s\r\n", ble_error_string(error))
+    }
+#endif
+}
+
+void timerCallback(void) {
+    set_led(SYSST_LED, true);
+    wait_ms(50);
+    set_led(SYSST_LED, false);
+
+    eventQueue.call(my_ble_timer);
+}
+
+void int1_rise(void) {
+    eventQueue.call(my_ble_int1_rise);
+}
+
+void int1_fall(void) {
+    eventQueue.call(my_ble_int1_fall);
+}
+
+void int2_rise(void) {
+    eventQueue.call(my_ble_int2_rise);
+}
+
+void int2_fall(void) {
+    eventQueue.call(my_ble_int2_fall);
+}
+
+void ble_received(const uint8_t *buf) {
+    eventQueue.call(my_ble_received, *((uint32_t *)buf));
+}
+
+/**
+ * This function is called when the ble initialization process has failled
+ */
+void onBleInitError(BLE &ble, ble_error_t error)
+{
+    DPRINTF("BLE initialize error.\r\n");
+    DPRINTF(" %s\r\n", ble_error_string(error));
+}
+
+/**
+ * Callback triggered when the ble initialization process has finished
+ */
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+    BLE&        ble   = params->ble;
+    ble_error_t error = params->error;
+
+    if (error != BLE_ERROR_NONE) {
+        /* In case of error, forward the error handling to onBleInitError */
+        onBleInitError(ble, error);
+        return;
+    }
+
+    /* Ensure that it is the default instance of BLE */
+    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
+        return;
+    }
+
+    /* return value is void */
+    ble.gap().onConnection(onConnectionCallback);
+    /* return value is void */
+    ble.gap().onDisconnection(disconnectionCallback);
+
+    /* Setup primary service */
+    MY_BLE = new MyBLEservice(ble);
+    if (MY_BLE == NULL) {
+        return;
+    }
+
+    /* set write callback */
+    MY_BLE->set_write_callback(ble_received);
+
+    /* setup user program */
+    if (my_ble_init() != MY_SUCCESS) {
+        return;
+    }
+
+    /* Setup advertising */
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+        MY_SERVICE_UUID.getBaseUUID(),
+        UUID::LENGTH_OF_LONG_UUID);
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::SHORTENED_LOCAL_NAME,
+        reinterpret_cast<const uint8_t *>(DEVICE_NAME),
+        sizeof(DEVICE_NAME));
+
+    ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(DEVICE_NAME));
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
+    ble.gap().startAdvertising();
+
+#ifdef MY_BLE_DEBUG
+    DPRINTF("Successfully started!\r\n");
+#endif
+}
+
+void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
+    BLE &ble = BLE::Instance();
+    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
+}
+
+int main()
+{
+    DPRINTF("Start %s program\r\n", MY_DEVICE_NAME);
+
+    /* setup callback */
+    if (trigger_flags & MY_TRIGGER_TIMER) {
+        eventQueue.call_every((uint32_t)(MY_TIMER_INTERVAL) * 1000, timerCallback);
+    }
+    if (trigger_flags & MY_TRIGGER_INT1_RISE) {
+        set_isr(MY_INT1_RISE, int1_rise);
+    }
+    if (trigger_flags & MY_TRIGGER_INT1_FALL) {
+        set_isr(MY_INT1_FALL, int1_fall);
+    }
+    if (trigger_flags & MY_TRIGGER_INT2_RISE) {
+        set_isr(MY_INT2_RISE, int2_rise);
+    }
+    if (trigger_flags & MY_TRIGGER_INT2_FALL) {
+        set_isr(MY_INT2_FALL, int2_fall);
+    }
+
+    BLE &ble = BLE::Instance();
+    ble.onEventsToProcess(scheduleBleEventsProcessing);
+    ble.init(bleInitComplete);
+    eventQueue.dispatch_forever();
+
+    return 0;
+}
diff -r 000000000000 -r 72ab2fd9994b my-ble/my-ble-definition.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble/my-ble-definition.h	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 ASAHI KASEI MICRODEVICES CORPORATION, Japan
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+#include <mbed.h>
+#include "my-ble-service.h"
+#include "my-ble-hardware.h"
+
+/** Utility macro
+ */
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#define MAKE_U16(U8H, U8L) \
+    (uint16_t)(((uint16_t)(U8H) << 8) | (uint16_t)(U8L))
+
+#define MAKE_S16(U8H, U8L) \
+    (int16_t)(((uint16_t)(U8H) << 8) | (uint16_t)(U8L))
+
+/** BLE service instance */
+extern MyBLEservice* MY_BLE;
+
+/** Don't edit these definition */
+#define MY_SUCCESS (0)
+#define MY_ERROR   (-1)
+
+enum my_ble_trigger_t {
+    MY_TRIGGER_TIMER     = 0x01,
+    MY_TRIGGER_INT1_RISE = 0x10,
+    MY_TRIGGER_INT1_FALL = 0x20,
+    MY_TRIGGER_INT2_RISE = 0x40,
+    MY_TRIGGER_INT2_FALL = 0x80
+};
+
+/* prototype of function. don't edit this */
+uint32_t my_ble_init(void);
+void my_ble_timer(void);
+void my_ble_int1_rise(void);
+void my_ble_int1_fall(void);
+void my_ble_int2_rise(void);
+void my_ble_int2_fall(void);
+void my_ble_received(const uint32_t data);
diff -r 000000000000 -r 72ab2fd9994b my-ble/my-ble-hardware.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble/my-ble-hardware.cpp	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 ASAHI KASEI MICRODEVICES CORPORATION, Japan
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#include "my-ble-hardware.h"
+
+#ifdef USE_BUTTON1
+#define MY_INTERRUPT1 BUTTON1 /* p13 */
+#else
+#define MY_INTERRUPT1 p11
+#endif
+
+#ifdef USE_BUTTON2
+#define MY_INTERRUPT2 BUTTON2 /* p14 */
+#else
+#define MY_INTERRUPT2 p12
+#endif
+
+#define LED_ON  (0)
+#define LED_OFF (1)
+
+I2C my_i2c(I2C_SDA0, I2C_SCL0);
+SPI my_spi(SPI_PSELMOSI0, SPI_PSELMISO0, SPI_PSELSCK0);
+DigitalOut my_spi_cs(SPI_PSELSS0);
+
+InterruptIn my_interrupt1(MY_INTERRUPT1);
+InterruptIn my_interrupt2(MY_INTERRUPT2);
+
+DigitalOut my_gpio1(p30, 0);
+DigitalOut my_gpio2(p31, 0);
+DigitalOut my_led1(LED1, LED_OFF);
+DigitalOut my_led2(LED2, LED_OFF);
+DigitalOut ble_status(LED3, LED_OFF);
+DigitalOut system_status(LED4, LED_OFF);
+
+AnalogIn my_ad1(p3);
+AnalogIn my_ad2(p4);
+
+#ifndef NDEBUG
+Serial debug_uart(TX_PIN_NUMBER, RX_PIN_NUMBER, 9600);
+#endif
+
+void set_led(MY_LED led, bool on) {
+    switch (led) {
+    case MY_LED1:
+        if (on) {
+            my_led1 = LED_ON;
+        } else {
+            my_led1 = LED_OFF;
+        }
+        break;
+    case MY_LED2:
+        if (on) {
+            my_led2 = LED_ON;
+        } else {
+            my_led2 = LED_OFF;
+        }
+        break;
+    case BLEST_LED:
+        if (on) {
+            ble_status = LED_ON;
+        } else {
+            ble_status = LED_OFF;
+        }
+        break;
+    case SYSST_LED:
+        if (on) {
+            system_status = LED_ON;
+        } else {
+            system_status = LED_OFF;
+        }
+        break;
+    }
+}
+
+void set_isr(MY_INTERRUPT interrupt, Callback<void()> fp) {
+    switch (interrupt) {
+    case MY_INT1_RISE:
+        if (fp) {
+            my_interrupt1.rise(fp);
+            my_interrupt1.enable_irq();
+        } else {
+            my_interrupt1.disable_irq();
+        }
+        break;
+    case MY_INT1_FALL:
+        if (fp) {
+            my_interrupt1.fall(fp);
+            my_interrupt1.enable_irq();
+        } else {
+            my_interrupt1.disable_irq();
+        }
+        break;
+    case MY_INT2_RISE:
+        if (fp) {
+            my_interrupt2.rise(fp);
+            my_interrupt2.enable_irq();
+        } else {
+            my_interrupt2.disable_irq();
+        }
+        break;
+    case MY_INT2_FALL:
+        if (fp) {
+            my_interrupt2.fall(fp);
+            my_interrupt2.enable_irq();
+        } else {
+            my_interrupt2.disable_irq();
+        }
+        break;
+    }
+}
diff -r 000000000000 -r 72ab2fd9994b my-ble/my-ble-hardware.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble/my-ble-hardware.h	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 ASAHI KASEI MICRODEVICES CORPORATION, Japan
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+#include <mbed.h>
+
+/** user definition */
+#include "my-ble-config.h"
+
+enum MY_LED {
+    MY_LED1,
+    MY_LED2,
+    SYSST_LED,
+    BLEST_LED
+};
+
+enum MY_INTERRUPT {
+    MY_INT1_RISE,
+    MY_INT1_FALL,
+    MY_INT2_RISE,
+    MY_INT2_FALL
+};
+
+extern I2C my_i2c;
+extern SPI my_spi;
+extern DigitalOut my_spi_cs;
+extern DigitalOut my_gpio1;
+extern DigitalOut my_gpio2;
+extern AnalogIn my_ad1;
+extern AnalogIn my_ad2;
+
+/** Debug macro
+ */
+#ifdef NDEBUG
+#define DPRINTF(...)
+#else
+extern Serial debug_uart;
+#define DPRINTF(...) debug_uart.printf(__VA_ARGS__)
+#endif
+
+void set_led(MY_LED led, bool on);
+void set_isr(MY_INTERRUPT interrupt, Callback<void()> fp);
diff -r 000000000000 -r 72ab2fd9994b my-ble/my-ble-service.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/my-ble/my-ble-service.h	Fri May 25 01:34:23 2018 +0000
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 ASAHI KASEI MICRODEVICES CORPORATION, Japan
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+#include "ble/BLE.h"
+#include "my-ble-hardware.h"
+
+extern UUID MY_SERVICE_UUID;
+
+class MyBLEservice {
+public:
+    enum {
+        UUID_READ_DATA1 = 0x2001,
+        UUID_READ_DATA2 = 0x2002,
+        UUID_WRITE = 0x1001
+    };
+
+    static const unsigned BLE_WRITE_BUF_LEN = 20;
+
+public:
+    /**
+     * @brief   EnvironmentalService constructor.
+     * @param   _ble Reference to BLE device.
+     */
+    MyBLEservice(BLE& _ble) :
+        ble(_ble),
+        data1Characteristic(UUID_READ_DATA1, &u32_data1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
+        data2Characteristic(UUID_READ_DATA2, &u32_data2, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
+        writeCharacteristic(UUID_WRITE, write_buf)
+    {
+        static bool serviceAdded = false; /* We should only ever need to add the information service once. */
+        if (serviceAdded) {
+            return;
+        }
+
+        /* set callback */
+        writeCharacteristic.setWriteAuthorizationCallback(this, &MyBLEservice::onWritten);
+
+        GattCharacteristic *charTable[] = { &data1Characteristic,
+                                            &data2Characteristic,
+                                            &writeCharacteristic };
+
+        GattService myService(MY_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+
+        ble.gattServer().addService(myService);
+        serviceAdded = true;
+    }
+
+    /**
+     * @brief   Update data1 characteristic.
+     * @param   data New value.
+     */
+    void update_data1(uint32_t data)
+    {
+        u32_data1 = data;
+        ble.gattServer().write(data1Characteristic.getValueHandle(), (uint8_t *) &u32_data1, sizeof(uint32_t));
+    }
+
+    /**
+     * @brief   Update data2 characteristic.
+     * @param   data New value.
+     */
+    void update_data2(uint32_t data)
+    {
+        u32_data2 = data;
+        ble.gattServer().write(data1Characteristic.getValueHandle(), (uint8_t *)&u32_data2, sizeof(uint32_t));
+    }
+
+    void set_write_callback(Callback<void(const uint8_t *)> fp)
+    {
+        if (fp) {
+            this->wfp = fp;
+        }
+    }
+
+private:
+    /**
+     * @brief   Update data1 characteristic.
+     * @param   data New value.
+     */
+    void onWritten(GattWriteAuthCallbackParams *param)
+    {
+        uint16_t len = param->len;
+
+        if (len > BLE_WRITE_BUF_LEN) {
+            len = BLE_WRITE_BUF_LEN;
+        }
+        memset(write_buf, 0x00, BLE_WRITE_BUF_LEN);
+        memcpy(write_buf, param->data, len);
+        ble.gattServer().write(writeCharacteristic.getValueHandle(), (uint8_t *)&write_buf, sizeof(write_buf));
+
+        if (this->wfp) {
+            this->wfp(this->write_buf);
+        }
+    }
+
+    BLE& ble;
+
+    uint32_t u32_data1;
+    uint32_t u32_data2;
+    uint8_t  write_buf[BLE_WRITE_BUF_LEN];
+
+    Callback<void(const uint8_t *buf)> wfp;
+
+    ReadOnlyGattCharacteristic<uint32_t> data1Characteristic;
+    ReadOnlyGattCharacteristic<uint32_t> data2Characteristic;
+    WriteOnlyArrayGattCharacteristic<uint8_t, BLE_WRITE_BUF_LEN> writeCharacteristic;
+};
+