Firmware for Keewi v1 electronic board
Dependencies: BLE_API mbed nRF51822
Fork of Keewi_v1 by
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(); } }