BTLE demo for MAXWSNENV.
Dependencies: BLE_API BMP180 Si7020 mbed MaximBLE
Diff: main.cpp
- Revision:
- 0:f71931ae3db1
- Child:
- 1:1876781d537e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Jul 10 21:28:56 2015 +0000 @@ -0,0 +1,400 @@ +/******************************************************************************* + * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Maxim Integrated + * Products, Inc. shall not be used except as stated in the Maxim Integrated + * Products, Inc. Branding Policy. + * + * The mere transfer of this software does not imply any licenses + * of trade secrets, proprietary technology, copyrights, patents, + * trademarks, maskwork rights, or any other form of intellectual + * property whatsoever. Maxim Integrated Products, Inc. retains all + * ownership rights. + ******************************************************************************* + */ + +#include <string.h> +#include "mbed.h" +#include "btle_addr.h" +#include "BLE.h" +#include "DeviceInformationService.h" +#include "EnvironmentalService.h" +#include "CurrentTimeService.h" +#include "BMP180.h" +#include "Si7020.h" +#include "LED.h" +#include "pwrseq_regs.h" +#include "pwrman_regs.h" +#include "ioman_regs.h" + +#define DEMO_DURATION 30 // sec +#define SENSOR_DEMO_PERIOD 1 // sec +#define NORMAL_SENSOR_PERIOD 60 // sec +#define SENSOR_DELAY_US 30000 // usec + +// in multiples of 0.625ms. +#define ADVERT_HIGH_PERIOD 1600 // 1000ms +#define ADVERT_LOW_PERIOD 8000 // 5000ms +#define BLE_UPDATE_DURATION 20 // sec + +#define PIN_NUMBER(pinname) ((PINNAME_TO_PORT(pinname) << 3) + PINNAME_TO_PIN(pinname)) +#define PIN_MASK(pinname) (1 << PIN_NUMBER(pinname)) + +#ifdef BTLE_PWR +DigitalOut ble_pwr(BTLE_PWR, PWR_ON); +#endif + +// User I/O objects +DigitalIn sw1(SW1); +DigitalOut red(LED_RED, LED_OFF); +DigitalOut blue(LED_BLUE, LED_OFF); + +// BLE Objects +static BLE ble; +static DeviceInformationService *devInfoService; +static EnvironmentalService *envService; +static CurrentTimeService *timeService; +static LowPowerTimeout bleUpdateTimeout; +static const char DEVICE_NAME[] = "Environmental Board"; +static const uint16_t uuid16_list[] = {GattService::UUID_DEVICE_INFORMATION_SERVICE}; +static const Gap::ConnectionParams_t paramsLowPower = { + 400, /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + 400, /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + 60, /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ + 3100 /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ +}; +static Gap::Handle_t connHandle = 0; +static bool connUpdateRequested; + +// Sensor objects +I2C i2c(I2C_SDA, I2C_SCL); +BMP180 bmp180(&i2c); +Si7020 si7020(&i2c); +static LowPowerTimeout sampleTimeout; +static LowPowerTicker sampleTicker; +static LowPowerTimeout demoTimeout; +static bool demoMode; + +static void bleUpdateCallback(void); + +// ***************************************************************************** +static void sampleComplete(void) +{ + int currentPressure; + float currentHumidity; + float currentTemperature; + time_t currentTime; + + red = LED_OFF; + blue = LED_OFF; + + // Update timestamp + currentTime = time(NULL); + if (demoMode) { + printf("\n%s", ctime(¤tTime)); + } + + /* Get next pressure reading, can be oversampled */ + if(bmp180.getPressure(¤tPressure) != 0) { + printf("Error getting pressure\n"); + } else { + envService->updatePressure((float)(currentPressure)/1000.0, currentTime); + if (demoMode) { + printf("Press = %0.1f kPa\n", (float)(currentPressure/1000.0)); + } + } + + // Get Humidity + if(si7020.checkHumidity(¤tHumidity) != 0) { + printf("Error getting humidity\n"); + } else { + envService->updateHumidity(currentHumidity, currentTime); + if (demoMode) { + printf("Humid = %0.1f %%\n", currentHumidity); + } + } + + // Get temperature + if(si7020.getPrevTemperature(¤tTemperature) != 0) { + printf("Error getting temperature\n"); + } else { + envService->updateTemperature(currentTemperature, currentTime); + if (demoMode) { + printf("Temp = %0.1f C\n", currentTemperature); + } + } + + // Update the CurrentTime characteristic value + timeService->updateCurrentTimeValue(); +} + +// ***************************************************************************** +static void sampleStart(void) +{ + if (demoMode) { + // Blink red LED if connected, blue if disconnected + if (ble.getGapState().connected) { + red = LED_ON; + blue = LED_OFF; + } else { + blue = LED_ON; + red = LED_OFF; + } + } + + // Start pressure conversion + bmp180.startPressure(BMP180::STANDARD); + + /* Start taking measurement for next reading*/ + si7020.startHumidity(); + + // Set timeout to read sensors and sample + sampleTimeout.attach_us(sampleComplete, SENSOR_DELAY_US); +} + +// ***************************************************************************** +static void setAdvertising(uint16_t interval) +{ + static uint16_t currentInterval = 0; + + if (interval == 0) { + ble.gap().stopAdvertising(); + currentInterval = 0; + } else if (!ble.getGapState().connected && (interval != currentInterval)) { + if (interval > currentInterval) { + bleUpdateTimeout.attach(bleUpdateCallback, BLE_UPDATE_DURATION); + } + ble.gap().stopAdvertising(); + ble.gap().setAdvertisingInterval(interval); + ble.gap().startAdvertising(); + currentInterval = interval; + } +} + +// ***************************************************************************** +static void bleUpdateCallback(void) +{ + if (ble.getGapState().connected) { + // Reduce connection interval + ble.gap().updateConnectionParams(connHandle, ¶msLowPower); + connUpdateRequested = true; + } else { + // Reduce advertising interval + setAdvertising(ADVERT_LOW_PERIOD); + } +} + +// ***************************************************************************** +static void demoTimeoutCallback(void) +{ + sampleTicker.attach(sampleStart, NORMAL_SENSOR_PERIOD); + demoMode = false; +} + +// ***************************************************************************** +static void demoStart(void) +{ + sampleTicker.attach(sampleStart, SENSOR_DEMO_PERIOD); + demoMode = true; + + if (!ble.getGapState().connected) { + // Increase advertising interval + setAdvertising(ADVERT_HIGH_PERIOD); + } + + demoTimeout.attach(demoTimeoutCallback, DEMO_DURATION); +} + +// ***************************************************************************** +void connectionCallback(const Gap::ConnectionCallbackParams_t *params) +{ + /* Record handle and connection settings */ + connHandle = params->handle; + setAdvertising(0); + + /* Prepare for a connection update */ + connUpdateRequested = false; + bleUpdateTimeout.attach(bleUpdateCallback, BLE_UPDATE_DURATION); + + printf("Connected\n"); +} + +// ***************************************************************************** +void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) +{ + /* Restart Advertising on disconnection */ + connHandle = 0; + setAdvertising(ADVERT_HIGH_PERIOD); + printf("Disconnected\n"); +} + +// ***************************************************************************** +void dataReadCallback(const GattReadCallbackParams *eventDataP) +{ + if (!connUpdateRequested) { + /* Restart the connection update timeout */ + bleUpdateTimeout.attach(bleUpdateCallback, BLE_UPDATE_DURATION); + } +} + +//****************************************************************************** +static int setGPIOWUD(PinName pinname, int act_high) +{ + MXC_IOMAN->wud_req0 |= PIN_MASK(pinname); + if (!(MXC_IOMAN->wud_ack0 & PIN_MASK(pinname))) { + printf("setGPIOWUD() failed to set P%u.%u as a WUD\n", PINNAME_TO_PORT(pinname), PINNAME_TO_PIN(pinname)); + return -1; + } + + // Configure WUD for active high/low + MXC_PWRMAN->wud_ctrl = (PIN_NUMBER(pinname) << MXC_F_PWRMAN_WUD_CTRL_PAD_SELECT_POS) | + (MXC_E_PWRMAN_PAD_MODE_ACT_HI_LO << MXC_F_PWRMAN_WUD_CTRL_PAD_MODE_POS); + if (act_high) { + MXC_PWRMAN->wud_pulse0 = 1; + } else { + MXC_PWRMAN->wud_pulse1 = 1; + } + + // Activate WUD + MXC_PWRMAN->wud_ctrl = (PIN_NUMBER(pinname) << MXC_F_PWRMAN_WUD_CTRL_PAD_SELECT_POS) | + (MXC_E_PWRMAN_PAD_MODE_CLEAR_SET << MXC_F_PWRMAN_WUD_CTRL_PAD_MODE_POS); + MXC_PWRMAN->wud_pulse1 = 1; // activate + + // Try to clear I/O wakeup flag + MXC_PWRSEQ->flags = MXC_F_PWRSEQ_FLAGS_PWR_IO_WAKEUP; + if (MXC_PWRSEQ->flags & MXC_F_PWRSEQ_FLAGS_PWR_IO_WAKEUP) { + return -1; + } + + return 0; +} + +//****************************************************************************** +static void clearGPIOWUD(PinName pinname) +{ + // I/O must be a wakeup detect to clear + MXC_IOMAN->wud_req0 |= PIN_MASK(pinname); + + // Clear WUD + MXC_PWRMAN->wud_ctrl = (PIN_NUMBER(pinname) << MXC_F_PWRMAN_WUD_CTRL_PAD_SELECT_POS) | + (MXC_E_PWRMAN_PAD_MODE_CLEAR_SET << MXC_F_PWRMAN_WUD_CTRL_PAD_MODE_POS); + MXC_PWRMAN->wud_pulse0 = 1; // clear + MXC_PWRMAN->wud_pulse1 = 1; // activate + MXC_PWRMAN->wud_pulse0 = 1; // clear + + MXC_IOMAN->wud_req0 &= ~PIN_MASK(pinname); +} + +// ***************************************************************************** +int main(void) +{ + printf("\n\nEnvironmental demo\n"); + + // This wait is needed to prevent the micro from entering DeepSleep before it can be halted by the debugger + wait(1); + + // Initialize the RTC + time(NULL); + + // clear wakeup detect requests, flags and mask all wakeups + MXC_IOMAN->wud_req0 = 0; + MXC_PWRSEQ->msk_flags = ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER; + + /* Initialize BLE baselayer */ + ble.init(); + + /* Set MAC Address */ + Gap::addr_type_t typeP = Gap::ADDR_TYPE_RANDOM_STATIC; + Gap::address_t address; + getBtleAddress((uint8_t*)&address); + ble.gap().setAddress(typeP, address); + ble.gap().getAddress(&typeP, address); + printf("BTLE Addr %02X:%02X:%02X:%02X:%02X:%02X\n", (unsigned int)address[5], + (unsigned int)address[4], + (unsigned int)address[3], + (unsigned int)address[2], + (unsigned int)address[1], + (unsigned int)address[0]); + + /* Setup Advertising */ + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t*)DEVICE_NAME, sizeof(DEVICE_NAME)); + + ble.gap().accumulateScanResponse(GapAdvertisingData::INCOMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t*)uuid16_list, sizeof(uuid16_list)); + ble.gap().accumulateScanResponse(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, envServiceUUID, sizeof(envServiceUUID)); + + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t*)DEVICE_NAME, sizeof(DEVICE_NAME)); + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + + /* Prepare Services */ + devInfoService = new DeviceInformationService(ble, "Maxim Integrated", + "WSNENV", + "000001", + "1", + "1", + "1"); + + envService = new EnvironmentalService(ble, PressureChar::PRES_UNIT_KPA, TemperatureChar::TEMP_UNIT_C); + + timeService = new CurrentTimeService(ble); + + /* Setup Callbacks */ + ble.gap().onDisconnection(disconnectionCallback); + ble.gap().onConnection(connectionCallback); + ble.gattServer().onDataRead(dataReadCallback); + + /* Setup BMP180 */ + if (bmp180.init() != 0) { + printf("Failed to initialize barometer\n"); + while(1); + } + + /* Start non-blocking pressure reading */ + bmp180.startPressure(BMP180::STANDARD); + si7020.startHumidity(); + + /* Start Advertising */ + setAdvertising(ADVERT_HIGH_PERIOD); + + // Setup reset sample, sample every second for first 10 seconds + sampleTicker.attach(sampleStart, SENSOR_DEMO_PERIOD); + demoTimeout.attach(demoTimeoutCallback, DEMO_DURATION); + demoMode = true; + + while (true) { + + // Prepare to wakeup from SW1 + if (sw1) { + setGPIOWUD(SW1, 0); + MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_PWR_IO_WAKEUP; + } + + ble.waitForEvent(); + + // Check if the button was pressed + if (MXC_PWRMAN->wud_seen0 & PIN_MASK(SW1)) { + demoStart(); + } + + // disable wakeup + clearGPIOWUD(SW1); + } +}