Health Thermometer example for Switch Science mbed TY51822r3

Dependencies:   BLE_API TMP102 mbed nRF51822

Committer:
ytsuboi
Date:
Sun Feb 07 12:23:57 2016 +0000
Revision:
0:b13cc82daed9
first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ytsuboi 0:b13cc82daed9 1 #include "mbed.h"
ytsuboi 0:b13cc82daed9 2 #include "TMP102.h"
ytsuboi 0:b13cc82daed9 3 #include "BLE.h"
ytsuboi 0:b13cc82daed9 4
ytsuboi 0:b13cc82daed9 5 #define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
ytsuboi 0:b13cc82daed9 6 * it will have an impact on code-size and power consumption. */
ytsuboi 0:b13cc82daed9 7
ytsuboi 0:b13cc82daed9 8 #if NEED_CONSOLE_OUTPUT
ytsuboi 0:b13cc82daed9 9 Serial pc(USBTX, USBRX);
ytsuboi 0:b13cc82daed9 10 #define DEBUG(...) { pc.printf(__VA_ARGS__); }
ytsuboi 0:b13cc82daed9 11 #else
ytsuboi 0:b13cc82daed9 12 #define DEBUG(...) /* nothing */
ytsuboi 0:b13cc82daed9 13 #endif /* #if NEED_CONSOLE_OUTPUT */
ytsuboi 0:b13cc82daed9 14
ytsuboi 0:b13cc82daed9 15 const static char DEVICE_NAME[] = "TY51822R3_HTM";
ytsuboi 0:b13cc82daed9 16 static volatile bool triggerSensorPolling = false;
ytsuboi 0:b13cc82daed9 17
ytsuboi 0:b13cc82daed9 18 BLEDevice ble;
ytsuboi 0:b13cc82daed9 19 TMP102 healthThemometer(I2C_SDA0, I2C_SCL0, 0x90); /* The TMP102 connected to our board */
ytsuboi 0:b13cc82daed9 20 //TMP102 healthThemometer(I2C_SDA1, I2C_SCL1, 0x90); /* The TMP102 connected to our board */
ytsuboi 0:b13cc82daed9 21
ytsuboi 0:b13cc82daed9 22 /* LEDs for indication: */
ytsuboi 0:b13cc82daed9 23 DigitalOut oneSecondLed(LED1); /* LED1 is toggled every second. */
ytsuboi 0:b13cc82daed9 24 DigitalOut advertisingStateLed(LED2); /* LED2 is on when we are advertising, otherwise off. */
ytsuboi 0:b13cc82daed9 25
ytsuboi 0:b13cc82daed9 26
ytsuboi 0:b13cc82daed9 27 /* Health Thermometer Service */
ytsuboi 0:b13cc82daed9 28 uint8_t thermTempPayload[5] = { 0, 0, 0, 0, 0 };
ytsuboi 0:b13cc82daed9 29
ytsuboi 0:b13cc82daed9 30 GattCharacteristic tempChar (GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR,
ytsuboi 0:b13cc82daed9 31 thermTempPayload, 5, 5,
ytsuboi 0:b13cc82daed9 32 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
ytsuboi 0:b13cc82daed9 33 /* Battery Level Service */
ytsuboi 0:b13cc82daed9 34 uint8_t batt = 100; /* Battery level */
ytsuboi 0:b13cc82daed9 35 uint8_t read_batt = 0; /* Variable to hold battery level reads */
ytsuboi 0:b13cc82daed9 36 GattCharacteristic battLevel ( GattCharacteristic::UUID_BATTERY_LEVEL_CHAR,
ytsuboi 0:b13cc82daed9 37 (uint8_t *)batt, 1, 1,
ytsuboi 0:b13cc82daed9 38 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
ytsuboi 0:b13cc82daed9 39 GattCharacteristic *htmChars[] = {&tempChar, };
ytsuboi 0:b13cc82daed9 40 GattCharacteristic *battChars[] = {&battLevel, };
ytsuboi 0:b13cc82daed9 41 GattService htmService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, htmChars,
ytsuboi 0:b13cc82daed9 42 sizeof(htmChars) / sizeof(GattCharacteristic *));
ytsuboi 0:b13cc82daed9 43 GattService battService(GattService::UUID_BATTERY_SERVICE, battChars,
ytsuboi 0:b13cc82daed9 44 sizeof(battChars) / sizeof(GattCharacteristic *));
ytsuboi 0:b13cc82daed9 45
ytsuboi 0:b13cc82daed9 46 uint16_t uuid16_list[] = {GattService::UUID_HEALTH_THERMOMETER_SERVICE,
ytsuboi 0:b13cc82daed9 47 GattService::UUID_BATTERY_SERVICE};
ytsuboi 0:b13cc82daed9 48
ytsuboi 0:b13cc82daed9 49 uint32_t quick_ieee11073_from_float(float temperature);
ytsuboi 0:b13cc82daed9 50 void updateServiceValues(void);
ytsuboi 0:b13cc82daed9 51
ytsuboi 0:b13cc82daed9 52 static Gap::ConnectionParams_t connectionParams;
ytsuboi 0:b13cc82daed9 53
ytsuboi 0:b13cc82daed9 54 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) // Mod
ytsuboi 0:b13cc82daed9 55 {
ytsuboi 0:b13cc82daed9 56 advertisingStateLed = 1;
ytsuboi 0:b13cc82daed9 57
ytsuboi 0:b13cc82daed9 58 DEBUG("Disconnected handle %u, reason %u\r\n", params->handle, params->reason);
ytsuboi 0:b13cc82daed9 59 DEBUG("Restarting the advertising process\r\n");
ytsuboi 0:b13cc82daed9 60 ble.gap().startAdvertising();
ytsuboi 0:b13cc82daed9 61 }
ytsuboi 0:b13cc82daed9 62
ytsuboi 0:b13cc82daed9 63 void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) //Mod
ytsuboi 0:b13cc82daed9 64 {
ytsuboi 0:b13cc82daed9 65 advertisingStateLed = 0;
ytsuboi 0:b13cc82daed9 66
ytsuboi 0:b13cc82daed9 67 DEBUG("connected. Got handle %u\r\n", params->handle);
ytsuboi 0:b13cc82daed9 68
ytsuboi 0:b13cc82daed9 69 connectionParams.slaveLatency = 1;
ytsuboi 0:b13cc82daed9 70 if (ble.gap().updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE) {
ytsuboi 0:b13cc82daed9 71 DEBUG("failed to update connection paramter\r\n");
ytsuboi 0:b13cc82daed9 72 }
ytsuboi 0:b13cc82daed9 73 }
ytsuboi 0:b13cc82daed9 74
ytsuboi 0:b13cc82daed9 75 void periodicCallback(void)
ytsuboi 0:b13cc82daed9 76 {
ytsuboi 0:b13cc82daed9 77 oneSecondLed = !oneSecondLed; /* Do blinky on LED1 while we're waiting for BLE events */
ytsuboi 0:b13cc82daed9 78
ytsuboi 0:b13cc82daed9 79 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
ytsuboi 0:b13cc82daed9 80 * heavy-weight sensor polling from the main thread. */
ytsuboi 0:b13cc82daed9 81 triggerSensorPolling = true;
ytsuboi 0:b13cc82daed9 82 }
ytsuboi 0:b13cc82daed9 83
ytsuboi 0:b13cc82daed9 84 /**************************************************************************/
ytsuboi 0:b13cc82daed9 85 /*!
ytsuboi 0:b13cc82daed9 86 @brief Program entry point
ytsuboi 0:b13cc82daed9 87 */
ytsuboi 0:b13cc82daed9 88 /**************************************************************************/
ytsuboi 0:b13cc82daed9 89 int main(void)
ytsuboi 0:b13cc82daed9 90 {
ytsuboi 0:b13cc82daed9 91
ytsuboi 0:b13cc82daed9 92 /* Setup blinky led */
ytsuboi 0:b13cc82daed9 93 oneSecondLed = 1;
ytsuboi 0:b13cc82daed9 94 Ticker ticker;
ytsuboi 0:b13cc82daed9 95 ticker.attach(periodicCallback, 1);
ytsuboi 0:b13cc82daed9 96
ytsuboi 0:b13cc82daed9 97 DEBUG("Initialising the nRF51822\r\n");
ytsuboi 0:b13cc82daed9 98 ble.init();
ytsuboi 0:b13cc82daed9 99 DEBUG("Init done\r\n");
ytsuboi 0:b13cc82daed9 100 ble.gap().onDisconnection(disconnectionCallback);
ytsuboi 0:b13cc82daed9 101 ble.gap().onConnection(onConnectionCallback);
ytsuboi 0:b13cc82daed9 102
ytsuboi 0:b13cc82daed9 103 ble.gap().getPreferredConnectionParams(&connectionParams);
ytsuboi 0:b13cc82daed9 104
ytsuboi 0:b13cc82daed9 105 /* setup advertising */
ytsuboi 0:b13cc82daed9 106 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ytsuboi 0:b13cc82daed9 107 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t*)uuid16_list, sizeof(uuid16_list));
ytsuboi 0:b13cc82daed9 108 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER);
ytsuboi 0:b13cc82daed9 109 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ytsuboi 0:b13cc82daed9 110 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ytsuboi 0:b13cc82daed9 111 ble.gap().setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
ytsuboi 0:b13cc82daed9 112 ble.gap().startAdvertising();
ytsuboi 0:b13cc82daed9 113 advertisingStateLed = 1;
ytsuboi 0:b13cc82daed9 114 DEBUG("Start Advertising\r\n");
ytsuboi 0:b13cc82daed9 115
ytsuboi 0:b13cc82daed9 116 ble.gattServer().addService(htmService);
ytsuboi 0:b13cc82daed9 117 ble.gattServer().addService(battService);
ytsuboi 0:b13cc82daed9 118 DEBUG("Add Service\r\n");
ytsuboi 0:b13cc82daed9 119
ytsuboi 0:b13cc82daed9 120 while (true) {
ytsuboi 0:b13cc82daed9 121 if (triggerSensorPolling) {
ytsuboi 0:b13cc82daed9 122 triggerSensorPolling = false;
ytsuboi 0:b13cc82daed9 123 updateServiceValues();
ytsuboi 0:b13cc82daed9 124 } else {
ytsuboi 0:b13cc82daed9 125 ble.waitForEvent();
ytsuboi 0:b13cc82daed9 126 }
ytsuboi 0:b13cc82daed9 127 }
ytsuboi 0:b13cc82daed9 128 }
ytsuboi 0:b13cc82daed9 129
ytsuboi 0:b13cc82daed9 130 /**************************************************************************/
ytsuboi 0:b13cc82daed9 131 /*!
ytsuboi 0:b13cc82daed9 132 @brief Ticker callback to switch advertisingStateLed state
ytsuboi 0:b13cc82daed9 133 */
ytsuboi 0:b13cc82daed9 134 /**************************************************************************/
ytsuboi 0:b13cc82daed9 135 void updateServiceValues(void)
ytsuboi 0:b13cc82daed9 136 {
ytsuboi 0:b13cc82daed9 137 /* Decrement the battery level. */
ytsuboi 0:b13cc82daed9 138 batt <=50 ? batt=100 : batt--;
ytsuboi 0:b13cc82daed9 139
ytsuboi 0:b13cc82daed9 140 /* Update the temperature. Note that we need to convert to an ieee11073 format float. */
ytsuboi 0:b13cc82daed9 141 float temperature = healthThemometer.read();
ytsuboi 0:b13cc82daed9 142 DEBUG("temp:%f\r\n", temperature);
ytsuboi 0:b13cc82daed9 143 uint32_t temp_ieee11073 = quick_ieee11073_from_float(temperature);
ytsuboi 0:b13cc82daed9 144 memcpy(thermTempPayload+1, &temp_ieee11073, 4);
ytsuboi 0:b13cc82daed9 145 ble.gattServer().write(tempChar.getValueAttribute().getHandle(), thermTempPayload, sizeof(thermTempPayload)); //Mod
ytsuboi 0:b13cc82daed9 146 ble.gattServer().write(battLevel.getValueAttribute().getHandle(), (uint8_t *)&batt, sizeof(batt)); //Mod
ytsuboi 0:b13cc82daed9 147 }
ytsuboi 0:b13cc82daed9 148
ytsuboi 0:b13cc82daed9 149 /**
ytsuboi 0:b13cc82daed9 150 * @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type.
ytsuboi 0:b13cc82daed9 151 * @param temperature The temperature as a float.
ytsuboi 0:b13cc82daed9 152 * @return The temperature in 11073-20601 FLOAT-Type format.
ytsuboi 0:b13cc82daed9 153 */
ytsuboi 0:b13cc82daed9 154 uint32_t quick_ieee11073_from_float(float temperature)
ytsuboi 0:b13cc82daed9 155 {
ytsuboi 0:b13cc82daed9 156 uint8_t exponent = 0xFF; //exponent is -1
ytsuboi 0:b13cc82daed9 157 uint32_t mantissa = (uint32_t)(temperature*10);
ytsuboi 0:b13cc82daed9 158
ytsuboi 0:b13cc82daed9 159 return ( ((uint32_t)exponent) << 24) | mantissa;
ytsuboi 0:b13cc82daed9 160 }