salesforce HeartRate monitor sample application. This application sends periodic heart rate values into salesforce.com via the mbed SalesforceInterface API.

Dependencies:   BufferedSerial C12832 EthernetInterface GroveEarbudSensor Logger SalesforceInterface mbed-rtos mbed

Fork of df-2014-salesforce-hrm-k64f by Doug Anson

Committer:
ansond
Date:
Wed Sep 24 21:54:21 2014 +0000
Revision:
1:a71236906eed
Parent:
0:a298d18da239
Child:
3:3a5fdfdabca3
updates for latest HRM

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ansond 0:a298d18da239 1 /* Copyright C2014 ARM, MIT License
ansond 0:a298d18da239 2 *
ansond 0:a298d18da239 3 * Author: Doug Anson (doug.anson@arm.com)
ansond 0:a298d18da239 4 *
ansond 0:a298d18da239 5 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
ansond 0:a298d18da239 6 * and associated documentation files the "Software", to deal in the Software without restriction,
ansond 0:a298d18da239 7 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
ansond 0:a298d18da239 8 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
ansond 0:a298d18da239 9 * furnished to do so, subject to the following conditions:
ansond 0:a298d18da239 10 *
ansond 0:a298d18da239 11 * The above copyright notice and this permission notice shall be included in all copies or
ansond 0:a298d18da239 12 * substantial portions of the Software.
ansond 0:a298d18da239 13 *
ansond 0:a298d18da239 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
ansond 0:a298d18da239 15 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ansond 0:a298d18da239 16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
ansond 0:a298d18da239 17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ansond 0:a298d18da239 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ansond 0:a298d18da239 19 */
ansond 0:a298d18da239 20
ansond 0:a298d18da239 21 #include "Definitions.h" // definitions including platform specifics...
ansond 0:a298d18da239 22 #include "ErrorHandler.h"
ansond 0:a298d18da239 23
ansond 0:a298d18da239 24 // HRM sensor defines
ansond 0:a298d18da239 25 #define HRM_OFF 0 // earbud sensor is offline
ansond 0:a298d18da239 26 #define HRM_MIN 10 // min HRM
ansond 0:a298d18da239 27 #define HRM_MAX 250 // max HRM
ansond 0:a298d18da239 28
ansond 0:a298d18da239 29 // include salesforce.com credentials
ansond 0:a298d18da239 30 #include "sf_creds.h"
ansond 0:a298d18da239 31
ansond 0:a298d18da239 32 // our Serial port
ansond 0:a298d18da239 33 #include "BufferedSerial.h"
ansond 0:a298d18da239 34 BufferedSerial pc(USBTX, USBRX);
ansond 0:a298d18da239 35 #define LOG_CONSOLE(...) { pc.printf(__VA_ARGS__); }
ansond 0:a298d18da239 36
ansond 0:a298d18da239 37 // mbed AppBoard Shield LCD
ansond 0:a298d18da239 38 C12832 lcd(D11, D13, D12, D7, D10);
ansond 0:a298d18da239 39
ansond 0:a298d18da239 40 // Earbud
ansond 0:a298d18da239 41 InterruptIn earbud(D0);
ansond 0:a298d18da239 42 Timer t;
ansond 0:a298d18da239 43
ansond 0:a298d18da239 44 // Ethernet
ansond 0:a298d18da239 45 #include "EthernetInterface.h"
ansond 0:a298d18da239 46 EthernetInterface ethernet;
ansond 0:a298d18da239 47
ansond 0:a298d18da239 48 // HTTP
ansond 0:a298d18da239 49 #include "HTTPClient.h"
ansond 0:a298d18da239 50 HTTPClient http;
ansond 0:a298d18da239 51
ansond 0:a298d18da239 52 // Salesforce.com Interface
ansond 0:a298d18da239 53 #include "SalesforceInterface.h"
ansond 0:a298d18da239 54
ansond 1:a71236906eed 55 // Sensor Lat/Long
ansond 1:a71236906eed 56 #define SENSOR_LATITUDE "37.404120"
ansond 1:a71236906eed 57 #define SENSOR_LONGITUDE "-121.973195"
ansond 1:a71236906eed 58
ansond 0:a298d18da239 59 // Salesforce.com Configuration/Tunables
ansond 0:a298d18da239 60 char *hrm_object_name = "HeartRate__c"; // custom object
ansond 0:a298d18da239 61 char *hrm_bpm_field_name = "bpm__c"; // heartrate field
ansond 0:a298d18da239 62 char *hrm_user_field_name = "Name"; // heartrate user
ansond 0:a298d18da239 63 char *hrm_counter_field_name = "count__c"; // heartrate counter
ansond 1:a71236906eed 64 char *hrm_latitude = "latitude__c"; // sensor latitude
ansond 1:a71236906eed 65 char *hrm_longitude = "longitude__c"; // sensor longitude
ansond 0:a298d18da239 66 char *hrm_user = "Doug Anson"; // whos heartrate is this?
ansond 0:a298d18da239 67
ansond 0:a298d18da239 68 // main loop toggle
ansond 0:a298d18da239 69 bool do_loop = true;
ansond 0:a298d18da239 70
ansond 0:a298d18da239 71 // # retries before we give up and exit
ansond 0:a298d18da239 72 int num_retries = MAX_TRIES;
ansond 0:a298d18da239 73
ansond 0:a298d18da239 74 // heartrate values and iteration counter
ansond 0:a298d18da239 75 volatile int iteration_counter = 0;
ansond 0:a298d18da239 76 volatile int oldhrmCounter = HRM_MAX+1;
ansond 0:a298d18da239 77 volatile int hrmCounter = HRM_OFF;
ansond 0:a298d18da239 78
ansond 0:a298d18da239 79 // Earbud sensor tunables
ansond 0:a298d18da239 80 #define NUM_SLOTS 11 // larger numbers give more fidelity but slow down the acquisition response rate
ansond 0:a298d18da239 81 volatile unsigned char counter = 0;
ansond 0:a298d18da239 82 volatile unsigned long temp[NUM_SLOTS];
ansond 0:a298d18da239 83 volatile unsigned long sub = 0;
ansond 0:a298d18da239 84 volatile bool data_effect = true;
ansond 0:a298d18da239 85 const int max_heartpluse_duty = 2000; // Change to follow your system's request. System returns error if the duty overtrips by 2 seconds. (in MS)
ansond 0:a298d18da239 86
ansond 0:a298d18da239 87 // Salesforce.com record ID
ansond 0:a298d18da239 88 DEFINE_SML_BUFFER(bpm_record_id);
ansond 0:a298d18da239 89
ansond 0:a298d18da239 90 // initialize the array
ansond 0:a298d18da239 91 void arrayInit() {
ansond 0:a298d18da239 92 for(int i=0;i<(NUM_SLOTS-1);++i) temp[i]=0;
ansond 0:a298d18da239 93 temp[NUM_SLOTS-1] = t.read_ms();
ansond 0:a298d18da239 94 }
ansond 0:a298d18da239 95
ansond 0:a298d18da239 96 // summation function
ansond 0:a298d18da239 97 void sum() {
ansond 0:a298d18da239 98 if(data_effect) {
ansond 0:a298d18da239 99 int tmp = 60 * (NUM_SLOTS-1) * 1000;
ansond 0:a298d18da239 100 hrmCounter = tmp/(temp[NUM_SLOTS-1]-temp[0]);
ansond 0:a298d18da239 101 LOG_CONSOLE("Heart_rate_is: %d bpm\r\n",hrmCounter);
ansond 0:a298d18da239 102 }
ansond 0:a298d18da239 103 data_effect=1; //sign bit
ansond 0:a298d18da239 104 }
ansond 0:a298d18da239 105
ansond 0:a298d18da239 106 // interrupt() function for earbud
ansond 0:a298d18da239 107 void interrupt() {
ansond 0:a298d18da239 108 temp[counter] = t.read_ms();
ansond 0:a298d18da239 109 switch(counter) {
ansond 0:a298d18da239 110 case 0:
ansond 0:a298d18da239 111 sub=temp[counter]-temp[NUM_SLOTS-1];
ansond 0:a298d18da239 112 break;
ansond 0:a298d18da239 113 default:
ansond 0:a298d18da239 114 sub=temp[counter]-temp[counter-1];
ansond 0:a298d18da239 115 break;
ansond 0:a298d18da239 116 }
ansond 0:a298d18da239 117 if(sub > max_heartpluse_duty) { //set 2 seconds as max heart pluse duty
ansond 0:a298d18da239 118 data_effect=0;//sign bit
ansond 0:a298d18da239 119 counter=0;
ansond 0:a298d18da239 120 LOG_CONSOLE("Heart rate measure error. Restarting...\r\n");
ansond 0:a298d18da239 121 arrayInit();
ansond 0:a298d18da239 122 t.stop();
ansond 0:a298d18da239 123 t.start();
ansond 0:a298d18da239 124 }
ansond 0:a298d18da239 125 if (counter == (NUM_SLOTS-1) && data_effect) {
ansond 0:a298d18da239 126 counter=0;
ansond 0:a298d18da239 127 sum();
ansond 0:a298d18da239 128 }
ansond 0:a298d18da239 129 else if(counter != (NUM_SLOTS-1) && data_effect) {
ansond 0:a298d18da239 130 counter++;
ansond 0:a298d18da239 131 }
ansond 0:a298d18da239 132 else {
ansond 0:a298d18da239 133 counter=0;
ansond 0:a298d18da239 134 data_effect=1;
ansond 0:a298d18da239 135 }
ansond 0:a298d18da239 136 }
ansond 0:a298d18da239 137
ansond 0:a298d18da239 138 // Get the heartrate from the sensor
ansond 0:a298d18da239 139 int get_heartrate() {
ansond 0:a298d18da239 140 ++iteration_counter;
ansond 0:a298d18da239 141 return hrmCounter;
ansond 0:a298d18da239 142 }
ansond 0:a298d18da239 143
ansond 0:a298d18da239 144 // Create the heart rate record in Salesforce.com
ansond 0:a298d18da239 145 void create_heartrate_record(ErrorHandler *logger,SalesforceInterface *sf) {
ansond 0:a298d18da239 146 // create a new record
ansond 0:a298d18da239 147 MbedJSONValue bpm_record;
ansond 0:a298d18da239 148 bpm_record[hrm_bpm_field_name] = (int)get_heartrate();
ansond 0:a298d18da239 149 bpm_record[hrm_user_field_name] = hrm_user;
ansond 0:a298d18da239 150 bpm_record[hrm_counter_field_name] = (int)iteration_counter;
ansond 1:a71236906eed 151 bpm_record[hrm_latitude] = SENSOR_LATITUDE;
ansond 1:a71236906eed 152 bpm_record[hrm_longitude] = SENSOR_LONGITUDE;
ansond 0:a298d18da239 153
ansond 0:a298d18da239 154 logger->log("ARM Salesforce HRM v%s\r\nCreate: new bpm record(%d): %d\r\nSending...",APP_VERSION,iteration_counter,hrmCounter);
ansond 0:a298d18da239 155 logger->logConsole("Initializing BPM record: %s",bpm_record.serialize().c_str());
ansond 0:a298d18da239 156
ansond 0:a298d18da239 157 // create the BPM record in salesforce.com
ansond 0:a298d18da239 158 MbedJSONValue response = sf->createRecord(hrm_object_name,bpm_record);
ansond 0:a298d18da239 159
ansond 0:a298d18da239 160 // display the result
ansond 0:a298d18da239 161 char *result = (char *)response.serialize().c_str();
ansond 0:a298d18da239 162 if (result != NULL && strlen(result) > 0 && strcmp(result,"null") != 0) {
ansond 0:a298d18da239 163 // save off the token if we succeeded
ansond 0:a298d18da239 164 logger->log("ARM Salesforce HRM v%s\r\nCreate: new bpm record(%d): %d\r\nSending...SUCCESS",APP_VERSION,iteration_counter,hrmCounter);
ansond 0:a298d18da239 165 logger->logConsole("Create: result: %s http_code = %d",result,sf->httpResponseCode());
ansond 0:a298d18da239 166 RESET_SML_BUFFER(bpm_record_id);
ansond 0:a298d18da239 167 strcpy(bpm_record_id,(char *)response["id"].get<std::string>().c_str());
ansond 0:a298d18da239 168 logger->turnLEDGreen();
ansond 0:a298d18da239 169 }
ansond 0:a298d18da239 170 else {
ansond 0:a298d18da239 171 // failure
ansond 0:a298d18da239 172 logger->log("ARM Salesforce HRM v%s\r\nCreate: new bpm record(%d): %d\r\nSending...FAILED",APP_VERSION,iteration_counter,hrmCounter);
ansond 0:a298d18da239 173 logger->logConsole("Create: FAILED http_code=%d",sf->httpResponseCode());
ansond 0:a298d18da239 174 logger->turnLEDRed();
ansond 0:a298d18da239 175 do_loop = false;
ansond 0:a298d18da239 176 }
ansond 0:a298d18da239 177 }
ansond 0:a298d18da239 178
ansond 0:a298d18da239 179 // Update the heart rate record in Salesforce.com
ansond 0:a298d18da239 180 void update_heartrate_record(ErrorHandler *logger,SalesforceInterface *sf) {
ansond 0:a298d18da239 181 logger->turnLEDOrange();
ansond 0:a298d18da239 182
ansond 0:a298d18da239 183 // update am existing record - assume "name" is the proper key for the record you wish to update...
ansond 0:a298d18da239 184 MbedJSONValue bpm_record;
ansond 0:a298d18da239 185 int bpm = get_heartrate();
ansond 0:a298d18da239 186 bpm_record[hrm_bpm_field_name] = bpm;
ansond 0:a298d18da239 187 bpm_record[hrm_user_field_name] = hrm_user;
ansond 0:a298d18da239 188 bpm_record[hrm_counter_field_name] = (int)iteration_counter;
ansond 1:a71236906eed 189 bpm_record[hrm_latitude] = SENSOR_LATITUDE;
ansond 1:a71236906eed 190 bpm_record[hrm_longitude] = SENSOR_LONGITUDE;
ansond 1:a71236906eed 191
ansond 0:a298d18da239 192 // DEBUG
ansond 0:a298d18da239 193 logger->log("ARM Salesforce HRM v%s\r\nUpdate HR(%d): %d bpm\r\nSending...",APP_VERSION,iteration_counter,bpm);
ansond 0:a298d18da239 194 logger->logConsole("Update: updated record: %s",bpm_record.serialize().c_str());
ansond 0:a298d18da239 195
ansond 0:a298d18da239 196 // update the BPM record in salesforce.com
ansond 0:a298d18da239 197 bool updated = sf->updateRecord(hrm_object_name,bpm_record_id,bpm_record);
ansond 0:a298d18da239 198
ansond 0:a298d18da239 199 // display the result
ansond 0:a298d18da239 200 if (updated) {
ansond 0:a298d18da239 201 // SUCCESS
ansond 0:a298d18da239 202 logger->log("ARM Salesforce HRM v%s\r\nUpdate HR(%d): %d bpm\r\nSending...SUCCESS",APP_VERSION,iteration_counter,bpm);
ansond 0:a298d18da239 203 logger->logConsole("Update: successful! http_code=%d",sf->httpResponseCode());
ansond 0:a298d18da239 204 logger->turnLEDGreen();
ansond 0:a298d18da239 205 }
ansond 0:a298d18da239 206 else {
ansond 0:a298d18da239 207 if (num_retries > 0) {
ansond 0:a298d18da239 208 // retry state
ansond 0:a298d18da239 209 logger->turnLEDPurple();
ansond 0:a298d18da239 210
ansond 0:a298d18da239 211 // OAUTH token may have expired - reset and retry
ansond 0:a298d18da239 212 if (num_retries == MAX_TRIES) --iteration_counter; // one time only in retries...
ansond 0:a298d18da239 213 --num_retries;
ansond 0:a298d18da239 214 sf->resetSalesforceToken();
ansond 0:a298d18da239 215 update_heartrate_record(logger,sf);
ansond 0:a298d18da239 216 }
ansond 0:a298d18da239 217 else {
ansond 0:a298d18da239 218 // failure
ansond 0:a298d18da239 219 logger->log("ARM Salesforce HRM v%s\r\nUpdate HR(%d): %d bpm\r\nSending...FAILED",APP_VERSION,iteration_counter,bpm);
ansond 0:a298d18da239 220 logger->logConsole("Update: FAILED http_code=%d",sf->httpResponseCode());
ansond 0:a298d18da239 221 do_loop = false;
ansond 0:a298d18da239 222
ansond 0:a298d18da239 223 // give-up state
ansond 0:a298d18da239 224 logger->turnLEDRed();
ansond 0:a298d18da239 225 }
ansond 0:a298d18da239 226 }
ansond 0:a298d18da239 227 }
ansond 0:a298d18da239 228
ansond 0:a298d18da239 229 // Report heart rate to Salesforce.com
ansond 0:a298d18da239 230 void report_heartrate(ErrorHandler *logger,SalesforceInterface *sf) {
ansond 0:a298d18da239 231 if (iteration_counter == 0) create_heartrate_record(logger,sf);
ansond 0:a298d18da239 232 else update_heartrate_record(logger,sf);
ansond 0:a298d18da239 233 }
ansond 0:a298d18da239 234
ansond 0:a298d18da239 235 // Main Task...
ansond 0:a298d18da239 236 void mainTask(void const *v) {
ansond 0:a298d18da239 237
ansond 0:a298d18da239 238 // create our object instances
ansond 0:a298d18da239 239 ErrorHandler logger(&pc,&lcd);
ansond 0:a298d18da239 240 SalesforceInterface *sf = NULL;
ansond 0:a298d18da239 241
ansond 0:a298d18da239 242 // announce
ansond 0:a298d18da239 243 logger.log("\r\n\r\nARM Salesforce HRM v%s",APP_VERSION);
ansond 0:a298d18da239 244 logger.turnLEDBlue();
ansond 0:a298d18da239 245 wait(1);
ansond 0:a298d18da239 246
ansond 0:a298d18da239 247 // initialize Ethernet
ansond 0:a298d18da239 248 logger.log("Initializing Ethernet...");
ansond 0:a298d18da239 249 ethernet.init();
ansond 0:a298d18da239 250
ansond 0:a298d18da239 251 // get a DHCP address and bring the network interface up
ansond 0:a298d18da239 252 logger.log("Getting IP Address...");
ansond 0:a298d18da239 253 logger.turnLEDYellow();
ansond 0:a298d18da239 254 if (ethernet.connect() == 0) {
ansond 0:a298d18da239 255 // log our IP address (DHCP)
ansond 0:a298d18da239 256 logger.log("IP Address: %s",ethernet.getIPAddress());
ansond 0:a298d18da239 257
ansond 0:a298d18da239 258 // allocate the Salesforce.com interface
ansond 0:a298d18da239 259 logger.logConsole("Allocating the Saleforce.com interface...");
ansond 0:a298d18da239 260 sf = new SalesforceInterface(&logger,&http);
ansond 0:a298d18da239 261
ansond 0:a298d18da239 262 // set our Salesforce.com credentials
ansond 0:a298d18da239 263 logger.logConsole("Setting credentials in the Salesforce.com interface...");
ansond 0:a298d18da239 264 sf->setCredentials(username,password,client_id,client_secret);
ansond 0:a298d18da239 265
ansond 0:a298d18da239 266 // initialize the earbud
ansond 0:a298d18da239 267 LOG_CONSOLE("Initializing Earbud...\r\n");
ansond 0:a298d18da239 268 t.start();
ansond 0:a298d18da239 269 arrayInit();
ansond 0:a298d18da239 270 earbud.rise(&interrupt);
ansond 0:a298d18da239 271 hrmCounter = HRM_OFF;
ansond 0:a298d18da239 272
ansond 0:a298d18da239 273 // enter main loop
ansond 0:a298d18da239 274 logger.logConsole("Beginning main event loop...");
ansond 0:a298d18da239 275 while(do_loop) {
ansond 0:a298d18da239 276 report_heartrate(&logger,sf);
ansond 0:a298d18da239 277 Thread::wait(WAIT_TIME_MS);
ansond 0:a298d18da239 278 }
ansond 0:a298d18da239 279
ansond 0:a298d18da239 280 // if we fell out of the loop exit...
ansond 0:a298d18da239 281 logger.log("Application Exiting...");
ansond 0:a298d18da239 282 logger.turnLEDRed();
ansond 0:a298d18da239 283 exit(1);
ansond 0:a298d18da239 284 }
ansond 0:a298d18da239 285 else {
ansond 0:a298d18da239 286 logger.log("No Network... Exiting...");
ansond 0:a298d18da239 287 logger.turnLEDRed();
ansond 0:a298d18da239 288 exit(1);
ansond 0:a298d18da239 289 }
ansond 0:a298d18da239 290 }
ansond 0:a298d18da239 291
ansond 0:a298d18da239 292 // main entry
ansond 0:a298d18da239 293 int main() {
ansond 0:a298d18da239 294 Thread workerTask(mainTask, NULL, osPriorityNormal, STACK_SIZE);
ansond 0:a298d18da239 295 while (true) {
ansond 0:a298d18da239 296 Thread::wait(10*WAIT_TIME_MS);
ansond 0:a298d18da239 297 }
ansond 0:a298d18da239 298 }