Firmware for Keewi v1 electronic board

Dependencies:   BLE_API mbed nRF51822

Fork of Keewi_v1 by Clément Bertolini

main.cpp

Committer:
clemberto
Date:
2014-08-20
Revision:
3:6e08445f54f3
Parent:
2:8ebada2e4924

File content as of revision 3:6e08445f54f3:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 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 "mbed.h"
#include "BLEDevice.h"

BLEDevice  ble;
DigitalOut led1(LED1);

#define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
                               * it will have an impact on code-size and power consumption. */

#if NEED_CONSOLE_OUTPUT
Serial  pc(USBTX, USBRX);

#define DEBUG(...) { pc.printf(__VA_ARGS__); }
#else
#define DEBUG(...) /* nothing */
#endif /* #if NEED_CONSOLE_OUTPUT */

const static char  DEVICE_NAME[] = "Keewi v1";

// DEVICE_NAME_UUID = '2A00'; // Nordic fixed this to nRF5, can be written
 
// Temperature 0-100 C, simulated
static uint8_t      temperature = 32;
GattCharacteristic  tempMeas(GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, (uint8_t *)temperature, sizeof(temperature), sizeof(temperature),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *temperatureChars[] = {&tempMeas };
// TODO: config service Health thermo
GattService         temperatureService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, temperatureChars, sizeof(temperatureChars) / sizeof(GattCharacteristic *));
 
// SYSTEM
static char         systemId = 'A';
GattCharacteristic  systemID(GattCharacteristic::UUID_SYSTEM_ID_CHAR, (uint8_t *)systemId, sizeof(systemId), sizeof(systemId),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *systemChars[] = {&systemID };
GattService         systemService(GattService::UUID_DEVICE_INFORMATION_SERVICE, systemChars, sizeof(systemChars) / sizeof(GattCharacteristic *));
 
// MODEL
static char         model[31] = "mBed nRF51822";
GattCharacteristic  modelID(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR, (uint8_t *)model, sizeof(model), sizeof(model),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *modelChars[] = {&modelID };
GattService         modelService(GattService::UUID_DEVICE_INFORMATION_SERVICE, modelChars, sizeof(modelChars) / sizeof(GattCharacteristic *));
 
// Firmware
static char         fwversion[31] = "Firmware: 0216";
GattCharacteristic  fwChars(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR, (uint8_t *)fwversion, sizeof(fwversion), sizeof(fwversion),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *firmwareChars[] = {&fwChars };
GattService         firmwareService(GattService::UUID_DEVICE_INFORMATION_SERVICE, firmwareChars, sizeof(firmwareChars) / sizeof(GattCharacteristic *));
 
// Software
static char         swversion[31] = "Sensor build (0001)";
GattCharacteristic  swChars(GattCharacteristic::UUID_SOFTWARE_REVISION_STRING_CHAR, (uint8_t *)swversion, sizeof(swversion), sizeof(swversion),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *softwareChars[] = {&swChars };
GattService         softwareService(GattService::UUID_DEVICE_INFORMATION_SERVICE, softwareChars, sizeof(softwareChars) / sizeof(GattCharacteristic *));
// Hardware
static char         hwversion[31] = "Sensor hw proto 0";
GattCharacteristic  hwChars(GattCharacteristic::UUID_HARDWARE_REVISION_STRING_CHAR, (uint8_t *)hwversion, sizeof(hwversion), sizeof(hwversion),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *hardwareChars[] = {&hwChars };
GattService         hardwareService(GattService::UUID_DEVICE_INFORMATION_SERVICE, hardwareChars, sizeof(hardwareChars) / sizeof(GattCharacteristic *));
// Manufacturer
static char         vendor[31] = "Busybee.io";
GattCharacteristic  vendorChars(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR, (uint8_t *)vendor, sizeof(vendor), sizeof(vendor),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *manufacturerChars[] = {&vendorChars };
GattService         manufacturerService(GattService::UUID_DEVICE_INFORMATION_SERVICE, manufacturerChars, sizeof(manufacturerChars) / sizeof(GattCharacteristic *));
// Serial number
static char         serial[31] = "1234567890";
GattCharacteristic  serialChars(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR, (uint8_t *)serial, sizeof(serial), sizeof(serial),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *serialNumberChars[] = {&serialChars };
GattService         serialNumberService(GattService::UUID_DEVICE_INFORMATION_SERVICE, serialNumberChars, sizeof(serialNumberChars) / sizeof(GattCharacteristic *));
 
static uint8_t      batteryLevel = 100;
GattCharacteristic  batteryPercentage(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, (uint8_t *)batteryLevel, sizeof(batteryLevel), sizeof(batteryLevel),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *batteryChars[] = {&batteryPercentage };
GattService         batteryService(GattService::UUID_BATTERY_SERVICE, batteryChars, sizeof(batteryChars) / sizeof(GattCharacteristic *));


/* CSC Service */
/* Service:  https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.cycling_speed_and_cadence.xml*/
/* CSC Mes: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.csc_measurement.xml */
/* Feature: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.csc_feature.xml */
/* Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.sensor_location.xml */
/* Control point: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.sc_control_point.xml */
static uint8_t cscWheelRevolutionDataSPresent = 1;
static uint8_t cscCrankRevolutionDataSPresent = 1;
static uint32_t cscCumulativeWheelRevolutions = 0;
static uint16_t cscLastWheelEventTime = 0;          // Unit is second & has a resolution of 1/1024s. 
static uint16_t cscCumulativeCrankRevolutions = 0;
static uint16_t cscLastCrankEventTime = 0;          // Unit is second & has a resolution of 1/1024s.
static uint8_t csc_mes_flags = (cscCrankRevolutionDataSPresent << 1) + cscWheelRevolutionDataSPresent;
static uint8_t csc_mes[] = {    csc_mes_flags,
                                cscCumulativeWheelRevolutions & 0x000000FF  ,
                                cscCumulativeWheelRevolutions & 0x0000FF00  ,
                                cscCumulativeWheelRevolutions & 0x00FF0000  ,
                                cscCumulativeWheelRevolutions & 0xFF000000  ,
                                cscLastWheelEventTime & 0x00FF              ,
                                cscLastWheelEventTime & 0xFF00              ,
                                cscCumulativeCrankRevolutions & 0x00FF      ,
                                cscCumulativeCrankRevolutions & 0xFF00      ,
                                cscLastCrankEventTime & 0x00FF              ,
                                cscLastCrankEventTime & 0xFF00               };
GattCharacteristic cscMeasurement(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR, csc_mes, sizeof(csc_mes), sizeof(csc_mes),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
static bool cscWheelRevolutionDataSupported = true;
static bool cscWCrankRevolutionDataSupported = true;
static bool cscMultipleSensorLocationsSupported = false;
static uint8_t csc_feat_flags = (cscWheelRevolutionDataSupported << 2) + (cscWCrankRevolutionDataSupported << 1) + cscMultipleSensorLocationsSupported;
static uint8_t csc_feat[2] = { 0x00, csc_feat_flags };
GattCharacteristic cscFeature(GattCharacteristic::UUID_CSC_FEATURE_CHAR, csc_feat, sizeof(csc_feat), sizeof(csc_feat),
                           GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
/* Sensor location */
enum BLE_SENSOR_LOCATION_LIST {                  /**< possible location for the CSC sensor. */
    BLE_SENSOR_LOCATION_OTHER       ,
    BLE_SENSOR_LOCATION_TOP_OF_SHOE ,
    BLE_SENSOR_LOCATION_IN_SHOE     ,
    BLE_SENSOR_LOCATION_HIP         ,
    BLE_SENSOR_LOCATION_FRONT_WHEEL ,
    BLE_SENSOR_LOCATION_LEFT_CRANK  ,
    BLE_SENSOR_LOCATION_RIGHT_CRANK ,
    BLE_SENSOR_LOCATION_LEFT_PEDAL  ,
    BLE_SENSOR_LOCATION_RIGHT_PEDAL ,
    BLE_SENSOR_LOCATION_FRONT_HUB   ,
    BLE_SENSOR_LOCATION_REAR_DROPOUT,
    BLE_SENSOR_LOCATION_CHAINSTAY   ,
    BLE_SENSOR_LOCATION_REAR_WHEEL  ,
    BLE_SENSOR_LOCATION_REAR_HUB    ,
    BLE_SENSOR_LOCATION_CHEST       
};
static uint8_t keewi_v1_location_possibilities[] = {                  /**< possible location for Keewi. */
    BLE_SENSOR_LOCATION_OTHER       ,
    BLE_SENSOR_LOCATION_FRONT_WHEEL ,
    BLE_SENSOR_LOCATION_LEFT_CRANK  ,
    BLE_SENSOR_LOCATION_RIGHT_CRANK ,
    BLE_SENSOR_LOCATION_FRONT_HUB   ,
    BLE_SENSOR_LOCATION_REAR_WHEEL  ,
    BLE_SENSOR_LOCATION_REAR_HUB
};
static const uint8_t location = BLE_SENSOR_LOCATION_FRONT_WHEEL;                // Keewi v1 speed sensor default location
GattCharacteristic cscLocation(GattCharacteristic::UUID_SENSOR_LOCATION,
                               (uint8_t *)&location, sizeof(location), sizeof(location),
                               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
                               
// SC Control Point
//TODO: implement a Write charac. cf. paramUpdateCallback()
GattCharacteristic cscCtrlPoint(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR,
                               (uint8_t *)&location, sizeof(location), sizeof(location),
                               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
GattCharacteristic *cscChars[] = {&cscMeasurement, &cscFeature, &cscLocation, };     // &cscControlPoint,
GattService        cscService(GattService::UUID_CYCLING_SPEED_AND_CADENCE, cscChars, sizeof(cscChars) / sizeof(GattCharacteristic *));

/*  Led & button service (LBS)
    Switch: Front & rear lights
    Led: Alarm state
*/
#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
#define LBS_UUID_LED_CHAR 0x1525
#define LBS_UUID_BUTTON_CHAR 0x1524
static bool rLightState = true;
static bool fLightState = true;
static uint8_t lbs_butt_flags = fLightState + (rLightState << 1);
GattCharacteristic lbsButtons(LBS_UUID_BUTTON_CHAR,
                               (uint8_t *)&lbs_butt_flags, sizeof(lbs_butt_flags), sizeof(lbs_butt_flags),
                               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
static bool alarmState = false;
static uint8_t lbs_led_flags = alarmState;
GattCharacteristic lbsLeds(LBS_UUID_LED_CHAR,
                               (uint8_t *)&lbs_led_flags, sizeof(lbs_led_flags), sizeof(lbs_led_flags),
                               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *lbsChars[] = {&lbsButtons, &lbsLeds, };
#define LBS_UUID_SERVICE 0x1523
GattService        lbsService(LBS_UUID_SERVICE, lbsChars, sizeof(lbsChars) / sizeof(GattCharacteristic *));

/*  Nordic UART Service (nus)
    TX: sending ride data
    RX: receiving ack, unlocking alarm
*/
#define BLE_UUID_NUS_SERVICE            0x0001                       /**< The UUID of the Nordic UART Service. */
#define BLE_UUID_NUS_TX_CHARACTERISTIC  0x0002                       /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC  0x0003                       /**< The UUID of the RX Characteristic. */
#define BLE_NUS_MAX_DATA_LEN            (GATT_MTU_SIZE_DEFAULT - 3)  /**< Maximum length of data (in bytes) that can be transmitted by the Nordic UART service module to the peer. */
#define BLE_NUS_MAX_RX_CHAR_LEN         BLE_NUS_MAX_DATA_LEN         /**< Maximum length of the RX Characteristic (in bytes). */
#define BLE_NUS_MAX_TX_CHAR_LEN         9                           /**< Maximum length of the TX Characteristic (in bytes). */
static const uint8_t uart_base_uuid[] = {0x6e, 0x40, 0x00, 0x01, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5,0x0e, 0x24, 0xdc, 0xca, 0x9e};
static const uint8_t uart_tx_uuid[]   = {0x6e, 0x40, 0x00, 0x02, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5,0x0e, 0x24, 0xdc, 0xca, 0x9e};
static const uint8_t uart_rx_uuid[]   = {0x6e, 0x40, 0x00, 0x03, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5,0x0e, 0x24, 0xdc, 0xca, 0x9e};
static const uint8_t uart_base_uuid_rev[] = {0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 0x01, 0x00, 0x40, 0x6e};
uint8_t nus_rx_buffer[BLE_NUS_MAX_RX_CHAR_LEN] = {0,};
GattCharacteristic nusRx(uart_rx_uuid,
                               (uint8_t *)&nus_rx_buffer, sizeof(nus_rx_buffer), BLE_NUS_MAX_RX_CHAR_LEN,
                               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
uint8_t nus_tx_buffer[BLE_NUS_MAX_TX_CHAR_LEN] = {0,};
GattCharacteristic nusTx(uart_tx_uuid,
                               (uint8_t *)&nus_tx_buffer, sizeof(nus_tx_buffer), BLE_NUS_MAX_TX_CHAR_LEN,
                               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
GattCharacteristic *nusChars[] = {&nusTx, &nusRx, };
GattService        nusService(uart_base_uuid, nusChars, sizeof(nusChars) / sizeof(GattCharacteristic *));

/* List of all available services */
static const uint16_t uuid16_list[] = {
    GattService::UUID_CYCLING_SPEED_AND_CADENCE,
    GattService::UUID_BATTERY_SERVICE,
    GattService::UUID_CURRENT_TIME_SERVICE,
    LBS_UUID_SERVICE,
    BLE_UUID_NUS_SERVICE,
};


void paramUpdateCallback() {
    DEBUG("Param change request ack!");
    return;
}


void disconnectionCallback(void)
{
    DEBUG("Disconnected!\n\r");
    DEBUG("Restarting the advertising process\n\r");
    ble.startAdvertising();
}

/**
 * Triggered periodically by the 'ticker' interrupt; updates cycling stats & battery value.
 */
void periodicCallback(void)
{
    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */

    if (ble.getGapState().connected) {
        led1 = 1;
        
        // Simulate evolution of battery level
        batteryLevel--;
        ble.updateCharacteristicValue(batteryPercentage.getHandle(), &batteryLevel, sizeof(batteryLevel));

        // Simulate evolution of Speed & Cadence
        cscCumulativeWheelRevolutions+=5;
        cscCumulativeCrankRevolutions+=2;
        cscLastWheelEventTime+=1000;
        cscLastCrankEventTime+=1000;
        uint8_t new_csc_mes[] = {csc_mes_flags, cscCumulativeWheelRevolutions & 0x000000FF, cscCumulativeWheelRevolutions & 0x0000FF00, cscCumulativeWheelRevolutions & 0x00FF0000, cscCumulativeWheelRevolutions & 0xFF000000, cscLastWheelEventTime & 0x00FF, cscLastWheelEventTime & 0xFF00, cscCumulativeCrankRevolutions & 0x00FF, cscCumulativeCrankRevolutions & 0xFF00, cscLastCrankEventTime & 0x00FF, cscLastCrankEventTime & 0xFF00 };
        ble.updateCharacteristicValue(cscMeasurement.getHandle(), new_csc_mes, sizeof(new_csc_mes));
        
        // Notify alarm & lights status
        alarmState ^= 1;
        uint8_t new_lbs_butt_flags = (uint8_t)alarmState;
        ble.updateCharacteristicValue(lbsLeds.getHandle(), &new_lbs_butt_flags, sizeof(new_lbs_butt_flags));
        
        DEBUG("led val = %d\r\n", new_lbs_butt_flags);

    }
}

int main(void)
{
    led1 = 1;
    Ticker ticker;
    ticker.attach(periodicCallback, 1);

    DEBUG("Initialized the nRF51822\n\r");
    ble.init();
    ble.onDisconnection(disconnectionCallback);
    ble.onDataSent(paramUpdateCallback);

    /* setup advertising */
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
                                        (uint8_t*)uuid16_list, sizeof(uuid16_list));
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                        (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
    ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_CYCLING);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
    ble.startAdvertising();
    
    /* Setup services */
    ble.addService(cscService);
    ble.addService(batteryService);
    //ble.addService(firmwareService);
    ble.addService(manufacturerService);
    ble.addService(lbsService);
    ble.addService(nusService);

    DEBUG("Initialized the BLE stack\n\r");

    while (true) {
        ble.waitForEvent();
    }
}