BTLE demo for MAXWSNENV.
Dependencies: BLE_API BMP180 Si7020 mbed MaximBLE
main.cpp
- Committer:
- enginerd
- Date:
- 2016-08-18
- Revision:
- 2:6f76d6160601
- Parent:
- 1:1876781d537e
File content as of revision 2:6f76d6160601:
/******************************************************************************* * 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 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(const Gap::DisconnectionCallbackParams_t *params) { /* 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 = BLEProtocol::AddressType::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 */ 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); } }