Code used for Sensor Expo 2016 - Balloon Game. More details can be found here: https://github.com/ROHMUSDC/ROHM-SensorExpo2016-Pressure-Sensor-Demo/

Dependencies:   BLE_API mbed nRF51822

Fork of Nordic_UART_TEMPLATE_ROHM_SHLD1Update by ROHMUSDC

ROHM Balloon Game Demo Code featured at Sensors Expo 2016

This code was written to be used with the Nordic Semiconductor nRF51-DK.

This Code allows the user to configure two known pressure distances and save pressure readings onto the application. Then it will automatically extrapolate these values and allow the user to see the height of the board. When connected to a balloon, greater heights can be achieved and the board will return the current height of the board.

Additional information about the ROHM MultiSensor Shield Board can be found at the following link: https://github.com/ROHMUSDC/ROHM-SensorExpo2016-Pressure-Sensor-Demo/

For code example for the ROHM SENSORSHLD0-EVK-101, please see the following link: https://developer.mbed.org/teams/ROHMUSDC/code/ROHMSensorShield_BALOONGAME/

Operation

See Github Repositoy for additional information on how to operate this demo application.

Supported ROHM Sensor Devices

  • BM1383GLV Pressure Sensor

Questions/Feedback

Please feel free to let us know any questions/feedback/comments/concerns on the ROHM shield implementation by contacting the following e-mail:

main.cpp

Committer:
kbahar3
Date:
2016-06-20
Revision:
11:c989bcb5d497
Parent:
10:aa05fb52aaa3

File content as of revision 11:c989bcb5d497:

/* 
 * 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.
 */
 
 //BALLOON GAME!
 /*
 *  Code Example for ROHM Sensor Expo Balloon Game
 * 
 *  Description: This Application interfaces ROHM's BM1383AGLV with Nordic's nRF51-DK
 *  This Code supports the following sensor devices:
 *      > BM1383AGLV Pressure Sensor
 *
 *  This Code allows the user to configure two known pressure distances and save pressure readings
 *  onto the application.  Then it will automatically extrapolate these values and allow the user to see
 *  the height of the board.  When connected to a balloon, greater heights can be achieved and the board
 *  will return the current height of the board.
 *   
 *  Additional information about the this Balloon Game can be found at the following link:
 *      asdfasdfasdf
 * 
 *  Last Upadtaed: 6/19/2016 
 *  Author: ROHM USDC
 *  Contact Information: engineering@rohmsemiconductor.com
 *  GitHub Link: https://github.com/ROHMUSDC/ROHM-SensorExpo2016-Pressure-Sensor-Demo/
 *  MBED Repository Link: https://developer.mbed.org/teams/ROHMUSDC/code/ROHMSensorShield_BALLOONGAME/
 */

#define nRF52DevKit         //Comment out and change target to Nordic NRf51822 for DemoBoard.  Comment in and change target to Nordic nRF51-DK for Nordic DK Board (and ROHM SHLD0 or SHLD1)
#define NRFDK               //Comment out and change target to Nordic NRf51822 for DemoBoard.  Comment in and change target to Nordic nRF51-DK for Nordic DK Board (and ROHM SHLD0 or SHLD1)
#define Pressure            //BM1383, Barometric Pressure Sensor
#define BM1383A             //Comment in for SHLD1. Comment out for SHLD0 and DemoBoard.

#include "mbed.h"
#include "BLEDevice.h"
#include "UARTService.h"
#include "nrf_temp.h"
#include "I2C.h"
#include <string>

#define MAX_REPLY_LEN           (UARTService::BLE_UART_SERVICE_MAX_DATA_LEN)    //Actually equal to 20
#define SENSOR_READ_INTERVAL_S  (1.0F) 
#define ADV_INTERVAL_MS         (1000UL)
#define UART_BAUD_RATE          (19200UL)
#define DEVICE_NAME             ("ROHM DEMO  ") // This can be read AFTER connecting to the device.
#define SHORT_NAME              ("BALLOONK")    // Keep this short: max 8 chars if a 128bit UUID is also advertised.
#define DEBUG(...)              { m_serial_port.printf(__VA_ARGS__); }

// Function Prototypes
void PBTrigger();               //Interrupt function for PB4
void BTLE_DataWrittenHandler();

// Global Variables
BLEDevice   m_ble;
Serial      m_serial_port(p9, p11);  // TX pin, RX pin Original
//Serial      m_serial_port(p8, p10);  // TX pin, RX pin 
DigitalOut  m_cmd_led(LED1);
DigitalOut  m_error_led(LED2);
UARTService *m_uart_service_ptr;
DigitalIn   testButton(p20);
InterruptIn sw4Press(p20);
#ifdef NRFDK
I2C         i2c(p30,p7);
#endif
#ifndef NRFDK
I2C         i2c(p7,p30);
#endif
bool        RepStart = true;
bool        NoRepStart = false;
int         i = 1;
unsigned char   printQue = 0;
string      ReceivedValue;
char        FormattedData[30];
uint8_t     buf[MAX_REPLY_LEN];
uint32_t    len = 0;

//Sensor Variables
#ifdef Pressure
int         Press_addr_w = 0xBA;
int         Press_addr_r = 0xBB;

char        PWR_ON[2] = {0x12, 0x01};
char        PWR_OFF[2] = {0x12, 0x00};
char        SLEEP_OFF[2] = {0x13, 0x01};
char        SLEEP_ON[2] = {0x13, 0x00};

char        Press_Content_ReadData[6];
#ifdef BM1383A
char        Press_Addr_ReadData =0x1A;
char        Mode_Control[2] = {0x14, 0xCA};
#endif
#ifndef BM1383A
char        Press_Addr_ReadData =0x1C;
char        PWR_DOWN[2] = {0x12, 0x01};
char        SLEEP[2] = {0x13, 0x01};
char        Mode_Control[2] = {0x14, 0xC4}; 
#endif

int         BM1383_Temp_highByte;
int         BM1383_Temp_lowByte;
int         BM1383_Pres_highByte;
int         BM1383_Pres_lowByte;
int         BM1383_Pres_leastByte; 

short int   BM1383_Temp_Out;
float       BM1383_Temp_Conv_Out;
float       BM1383_Pres_Conv_Out;

float       BM1383_Var;
float       BM1383_Deci;

uint32_t    BM1383_TempPressure;


#endif

//Balloon Game Variables
float       BM1383_Pres_0Level;
float       BM1383_Pres_KnownLevel;
float       HeightBase = 0;
float       HeightKnown_Total = 68;
float       HeightKnown_Foot = 60;
float       HeightKnown_Inches = 8;
float       slope;
float       yInt;
float       pressureCurr;
float       HeightExtrapolated; //Assuming linear pressure curve
float       HeightExtrapolated_Foot = 60;
float       HeightExtrapolated_Inches = 8;


/**
 * This callback is used whenever a disconnection occurs.
 */
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    switch (reason) {
    case Gap::REMOTE_USER_TERMINATED_CONNECTION:
        DEBUG("Disconnected (REMOTE_USER_TERMINATED_CONNECTION)\n\r");
        break;
    case Gap::LOCAL_HOST_TERMINATED_CONNECTION:
        DEBUG("Disconnected (LOCAL_HOST_TERMINATED_CONNECTION)\n\r");
        break;
    case Gap::CONN_INTERVAL_UNACCEPTABLE:
        DEBUG("Disconnected (CONN_INTERVAL_UNACCEPTABLE)\n\r");
        break;
    }

    DEBUG("Restarting the advertising process\n\r");
    m_ble.startAdvertising();
}

/**
 * This callback is used whenever the host writes data to one of our GATT characteristics.
 */
void dataWrittenCallback(const GattCharacteristicWriteCBParams *params)
{
    // Ensure that initialization is finished and the host has written to the TX characteristic.
    if ((m_uart_service_ptr != NULL) && (params->charHandle == m_uart_service_ptr->getTXCharacteristicHandle())) {
        int i;
        ReceivedValue.clear();
        for(i = 0; i < params->len; i++)
        {
            ReceivedValue += params->data[i];
        }
        printQue = 1;
    }
}

/**
 * This callback is used whenever a write to a GATT characteristic causes data to be sent to the host.
 */
void dataSentCallback(unsigned count)
{
    // NOTE: The count always seems to be 1 regardless of data.
    DEBUG("%d bytes sent to host\n\r", count);
}


/**
 * This callback is scheduled to be called periodically via a low-priority interrupt.
 */
void periodicCallback(void)
{
    //uint8_t  buf[MAX_REPLY_LEN];
    //uint32_t len = 0;
}

void error(ble_error_t err, uint32_t line)
{
    m_error_led = 1;
    DEBUG("Error %d on line number %d\n\r", err, line);
}

void PBTrigger()
{
    uint8_t  buf[MAX_REPLY_LEN];
    uint32_t len = 0;
    
    m_cmd_led = !m_cmd_led;
    
    if (m_ble.getGapState().connected) {
        len = snprintf((char*) buf, MAX_REPLY_LEN, "Button Pressed!");
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
}

int main(void)
{
    ble_error_t err;
    Ticker      ticker;

    m_serial_port.baud(UART_BAUD_RATE);

    DEBUG("Initialising...\n\r");

    m_cmd_led      = 0;
    m_error_led    = 0;

    ticker.attach(periodicCallback, SENSOR_READ_INTERVAL_S);

    sw4Press.fall(&PBTrigger);

    #ifdef Pressure  //no Initialization because we keep in low power mode until we need to measure pressure
    //i2c.write(Press_addr_w, &PWR_OFF[0], 2, false);
    //i2c.write(Press_addr_w, &SLEEP_ON[0], 2, false);
    //i2c.write(Press_addr_w, &Mode_Control[0], 2, false);
    #endif

    #ifndef BM1383A
    i2c.write(Press_addr_w, &PWR_DOWN[0], 2, false);
    i2c.write(Press_addr_w, &SLEEP[0], 2, false);
    i2c.write(Press_addr_w, &Mode_Control[0], 2, false);
    #endif
    
    //Start BTLE Initialization Section
    m_ble.init();
    m_ble.onDisconnection(disconnectionCallback);
    m_ble.onDataWritten(dataWrittenCallback);
    m_ble.onDataSent(dataSentCallback);

    // Set the TX power in dBm units.
    // Possible values (in decreasing order): 4, 0, -4, -8, -12, -16, -20.
    err = m_ble.setTxPower(4);
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    // Setup advertising (GAP stuff).
    err = m_ble.setDeviceName(DEVICE_NAME);
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    err = m_ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    m_ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);

    err = m_ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                                (const uint8_t *)SHORT_NAME,
                                                (sizeof(SHORT_NAME) - 1));
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    err = m_ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                                (const uint8_t *)UARTServiceUUID_reversed,
                                                sizeof(UARTServiceUUID_reversed));
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    m_ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADV_INTERVAL_MS));
    m_ble.startAdvertising();

    // Create a UARTService object (GATT stuff).
    UARTService uartService(m_ble);
    m_uart_service_ptr = &uartService;

    while (true) {
        m_ble.waitForEvent();
        
        #ifdef Pressure
        /*
        //Read color Portion from the IC
        i2c.write(Press_addr_w, &Press_Addr_ReadData, 1, RepStart);
        i2c.read(Press_addr_r, &Press_Content_ReadData[0], 3, NoRepStart);
        
        BM1383_Var  = (Press_Content_ReadData[0]<<3) | (Press_Content_ReadData[1] >> 5);
        BM1383_Deci = ((Press_Content_ReadData[1] & 0x1f) << 6 | ((Press_Content_ReadData[2] >> 2)));
        BM1383_Deci = (float)BM1383_Deci* 0.00048828125;  //0.00048828125 = 2^-11
        BM1383_Pres_Conv_Out = (BM1383_Var + BM1383_Deci);   //question pending here...
        */
        #endif
        
        
        if(printQue)    //Handle Data Written Interrupt
        {
            BTLE_DataWrittenHandler();
            printQue = 0;
        }
    }
}

void BTLE_DataWrittenHandler(){    
    int i;
    if (ReceivedValue.length() == 1) {
        switch (ReceivedValue[0]) { 
            case 'F':
                len = snprintf((char*) buf, MAX_REPLY_LEN, "  Pres= %0.2f hPa", BM1383_Pres_Conv_Out);
                break;
            
            case 'r': //System Reset
                NVIC_SystemReset(); //Q. What is this? no break statement?
                                    //A. SoftReset... No need for break because this resets the program...
                break;
                
            default:
                len = snprintf((char*) buf, MAX_REPLY_LEN, "1b,ERROR");
                break;
        }
    }
    else if (ReceivedValue.length() > 1) {
        
        //BTLE Interface Code, Added 5/29/2016
        for(i = 0; i < 29; i++)
        {
            FormattedData[i] = '\0';
        }
        
        if(ReceivedValue.compare(0,4,"CAL0") == 0)
        {
            pressureCurr = 0;
            #ifdef BM1383A
            i2c.write(Press_addr_w, &PWR_ON[0], 2, false);
            i2c.write(Press_addr_w, &SLEEP_OFF[0], 2, false);
            i2c.write(Press_addr_w, &Mode_Control[0], 2, false);
            #endif
            for(i = 0; i < 10; i++)
            {
                #ifdef Pressure
                wait_ms(200);
                i2c.write(Press_addr_w, &Press_Addr_ReadData, 1, RepStart);
                i2c.read(Press_addr_r, &Press_Content_ReadData[0], 3, NoRepStart);
                BM1383_TempPressure = (Press_Content_ReadData[0]<<14)|(Press_Content_ReadData[1]<<6)|(Press_Content_ReadData[2]);
                BM1383_Pres_Conv_Out = (float)BM1383_TempPressure / (float)2048;
                #endif
                pressureCurr += BM1383_Pres_Conv_Out;
            }
            i2c.write(Press_addr_w, &PWR_OFF[0], 2, false);
            i2c.write(Press_addr_w, &SLEEP_ON[0], 2, false);
            BM1383_Pres_0Level = pressureCurr/10;
            len = snprintf((char*) buf, MAX_REPLY_LEN, "BaseLvl=%.3f",BM1383_Pres_0Level);  
        }
        
        else if(ReceivedValue.compare(0,4,"CAL1") == 0)
        {
            pressureCurr = 0;
            #ifdef BM1383A
            i2c.write(Press_addr_w, &PWR_ON[0], 2, false);
            i2c.write(Press_addr_w, &SLEEP_OFF[0], 2, false);
            i2c.write(Press_addr_w, &Mode_Control[0], 2, false);
            #endif
            for(i = 0; i < 10; i++)
            {
                #ifdef Pressure
                wait_ms(200);
                i2c.write(Press_addr_w, &Press_Addr_ReadData, 1, RepStart);
                i2c.read(Press_addr_r, &Press_Content_ReadData[0], 3, NoRepStart);
                BM1383_TempPressure = (Press_Content_ReadData[0]<<14)|(Press_Content_ReadData[1]<<6)|(Press_Content_ReadData[2]);
                BM1383_Pres_Conv_Out = (float)BM1383_TempPressure / (float)2048;
                #endif
                pressureCurr += BM1383_Pres_Conv_Out;
            }
            i2c.write(Press_addr_w, &PWR_OFF[0], 2, false);
            i2c.write(Press_addr_w, &SLEEP_ON[0], 2, false);
            BM1383_Pres_KnownLevel = pressureCurr/10;
            len = snprintf((char*) buf, MAX_REPLY_LEN, "KnownLv=%.3f",BM1383_Pres_KnownLevel);              
        }
        
        
        else if(ReceivedValue.compare(0,4,"HEI?") == 0)
        {
            HeightKnown_Total = HeightKnown_Foot + HeightKnown_Inches;
            slope = (HeightKnown_Total - HeightBase) / (BM1383_Pres_KnownLevel - BM1383_Pres_0Level);
            yInt = HeightBase - (slope * BM1383_Pres_0Level);
            pressureCurr = 0;
            #ifdef BM1383A
            i2c.write(Press_addr_w, &PWR_ON[0], 2, false);
            i2c.write(Press_addr_w, &SLEEP_OFF[0], 2, false);
            i2c.write(Press_addr_w, &Mode_Control[0], 2, false);
            #endif
            for(i = 0; i < 10; i++)
            {
                #ifdef Pressure
                wait_ms(200);
                i2c.write(Press_addr_w, &Press_Addr_ReadData, 1, RepStart);
                i2c.read(Press_addr_r, &Press_Content_ReadData[0], 3, NoRepStart);
                BM1383_TempPressure = (Press_Content_ReadData[0]<<14)|(Press_Content_ReadData[1]<<6)|(Press_Content_ReadData[2]);
                BM1383_Pres_Conv_Out = (float)BM1383_TempPressure / (float)2048;
                #endif
                pressureCurr += BM1383_Pres_Conv_Out;
            }
            i2c.write(Press_addr_w, &PWR_OFF[0], 2, false);
            i2c.write(Press_addr_w, &SLEEP_ON[0], 2, false);
            pressureCurr = pressureCurr/10;
            
            HeightExtrapolated = ((pressureCurr * slope) + yInt)/12;
            //len = snprintf((char*) buf, MAX_REPLY_LEN, "Height=%f FT",HeightExtrapolated);
            //m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
            
            HeightExtrapolated_Foot = int(HeightExtrapolated);
            HeightExtrapolated_Inches = (HeightExtrapolated - HeightExtrapolated_Foot)* 12;
            len = snprintf((char*) buf, MAX_REPLY_LEN, "H=%.0fFT, %.0fIN",HeightExtrapolated_Foot,HeightExtrapolated_Inches);
        }
        
        else if(ReceivedValue.compare(0,2,"FT") == 0)
        {
            HeightKnown_Foot = (ReceivedValue[2]-48) * 12;  //Convert ASCII to INT, then Convert to Inches
            sprintf(FormattedData, "%2.0f", HeightKnown_Foot);
            len = snprintf((char*) buf, MAX_REPLY_LEN, "FT = %s inchs", FormattedData);
            wait_ms(200);
        }
        
        else if(ReceivedValue.compare(0,2,"IN") == 0)
        {
            if((ReceivedValue[3]>= 48) && (ReceivedValue[3]<=57)){
                HeightKnown_Inches = ((ReceivedValue[2]-48)*10) + (ReceivedValue[3]-48);    //Convert ASCII to INT, then Convert to Inches  
                
            }
            else{
                HeightKnown_Inches = (ReceivedValue[2]-48); //Convert ASCII to INT
            }
            sprintf(FormattedData, "%2.0f", HeightKnown_Inches);
            len = snprintf((char*) buf, MAX_REPLY_LEN, "IN = %s inchs", FormattedData);
            wait_ms(200);
        }
        
        else
        {
            len = snprintf((char*) buf, MAX_REPLY_LEN, "??? = %s", ReceivedValue.c_str());
            //m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        }

    }
    else
    {
        len = snprintf((char*) buf, MAX_REPLY_LEN, "ERR:NUL");
    }
    m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
}