BTLE demo for MAXWSNENV.

Dependencies:   BLE_API BMP180 Si7020 mbed MaximBLE

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(&currentTime));
+    }
+
+    /* Get next pressure reading, can be oversampled */
+    if(bmp180.getPressure(&currentPressure) != 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(&currentHumidity) != 0) {
+        printf("Error getting humidity\n");
+    } else {
+        envService->updateHumidity(currentHumidity, currentTime);
+        if (demoMode) {
+            printf("Humid = %0.1f %%\n", currentHumidity);
+        }
+    }
+
+    // Get temperature
+    if(si7020.getPrevTemperature(&currentTemperature) != 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, &paramsLowPower);
+        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);
+    }
+}