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 04:13:57 2014 +0000
Revision:
0:a298d18da239
Child:
1:a71236906eed
initial checkin

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 0:a298d18da239 55 // Salesforce.com Configuration/Tunables
ansond 0:a298d18da239 56 char *hrm_object_name = "HeartRate__c"; // custom object
ansond 0:a298d18da239 57 char *hrm_bpm_field_name = "bpm__c"; // heartrate field
ansond 0:a298d18da239 58 char *hrm_user_field_name = "Name"; // heartrate user
ansond 0:a298d18da239 59 char *hrm_counter_field_name = "count__c"; // heartrate counter
ansond 0:a298d18da239 60 char *hrm_user = "Doug Anson"; // whos heartrate is this?
ansond 0:a298d18da239 61
ansond 0:a298d18da239 62 // main loop toggle
ansond 0:a298d18da239 63 bool do_loop = true;
ansond 0:a298d18da239 64
ansond 0:a298d18da239 65 // # retries before we give up and exit
ansond 0:a298d18da239 66 int num_retries = MAX_TRIES;
ansond 0:a298d18da239 67
ansond 0:a298d18da239 68 // heartrate values and iteration counter
ansond 0:a298d18da239 69 volatile int iteration_counter = 0;
ansond 0:a298d18da239 70 volatile int oldhrmCounter = HRM_MAX+1;
ansond 0:a298d18da239 71 volatile int hrmCounter = HRM_OFF;
ansond 0:a298d18da239 72
ansond 0:a298d18da239 73 // Earbud sensor tunables
ansond 0:a298d18da239 74 #define NUM_SLOTS 11 // larger numbers give more fidelity but slow down the acquisition response rate
ansond 0:a298d18da239 75 volatile unsigned char counter = 0;
ansond 0:a298d18da239 76 volatile unsigned long temp[NUM_SLOTS];
ansond 0:a298d18da239 77 volatile unsigned long sub = 0;
ansond 0:a298d18da239 78 volatile bool data_effect = true;
ansond 0:a298d18da239 79 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 80
ansond 0:a298d18da239 81 // Salesforce.com record ID
ansond 0:a298d18da239 82 DEFINE_SML_BUFFER(bpm_record_id);
ansond 0:a298d18da239 83
ansond 0:a298d18da239 84 // initialize the array
ansond 0:a298d18da239 85 void arrayInit() {
ansond 0:a298d18da239 86 for(int i=0;i<(NUM_SLOTS-1);++i) temp[i]=0;
ansond 0:a298d18da239 87 temp[NUM_SLOTS-1] = t.read_ms();
ansond 0:a298d18da239 88 }
ansond 0:a298d18da239 89
ansond 0:a298d18da239 90 // summation function
ansond 0:a298d18da239 91 void sum() {
ansond 0:a298d18da239 92 if(data_effect) {
ansond 0:a298d18da239 93 int tmp = 60 * (NUM_SLOTS-1) * 1000;
ansond 0:a298d18da239 94 hrmCounter = tmp/(temp[NUM_SLOTS-1]-temp[0]);
ansond 0:a298d18da239 95 LOG_CONSOLE("Heart_rate_is: %d bpm\r\n",hrmCounter);
ansond 0:a298d18da239 96 }
ansond 0:a298d18da239 97 data_effect=1; //sign bit
ansond 0:a298d18da239 98 }
ansond 0:a298d18da239 99
ansond 0:a298d18da239 100 // interrupt() function for earbud
ansond 0:a298d18da239 101 void interrupt() {
ansond 0:a298d18da239 102 temp[counter] = t.read_ms();
ansond 0:a298d18da239 103 switch(counter) {
ansond 0:a298d18da239 104 case 0:
ansond 0:a298d18da239 105 sub=temp[counter]-temp[NUM_SLOTS-1];
ansond 0:a298d18da239 106 break;
ansond 0:a298d18da239 107 default:
ansond 0:a298d18da239 108 sub=temp[counter]-temp[counter-1];
ansond 0:a298d18da239 109 break;
ansond 0:a298d18da239 110 }
ansond 0:a298d18da239 111 if(sub > max_heartpluse_duty) { //set 2 seconds as max heart pluse duty
ansond 0:a298d18da239 112 data_effect=0;//sign bit
ansond 0:a298d18da239 113 counter=0;
ansond 0:a298d18da239 114 LOG_CONSOLE("Heart rate measure error. Restarting...\r\n");
ansond 0:a298d18da239 115 arrayInit();
ansond 0:a298d18da239 116 t.stop();
ansond 0:a298d18da239 117 t.start();
ansond 0:a298d18da239 118 }
ansond 0:a298d18da239 119 if (counter == (NUM_SLOTS-1) && data_effect) {
ansond 0:a298d18da239 120 counter=0;
ansond 0:a298d18da239 121 sum();
ansond 0:a298d18da239 122 }
ansond 0:a298d18da239 123 else if(counter != (NUM_SLOTS-1) && data_effect) {
ansond 0:a298d18da239 124 counter++;
ansond 0:a298d18da239 125 }
ansond 0:a298d18da239 126 else {
ansond 0:a298d18da239 127 counter=0;
ansond 0:a298d18da239 128 data_effect=1;
ansond 0:a298d18da239 129 }
ansond 0:a298d18da239 130 }
ansond 0:a298d18da239 131
ansond 0:a298d18da239 132 // Get the heartrate from the sensor
ansond 0:a298d18da239 133 int get_heartrate() {
ansond 0:a298d18da239 134 ++iteration_counter;
ansond 0:a298d18da239 135 return hrmCounter;
ansond 0:a298d18da239 136 }
ansond 0:a298d18da239 137
ansond 0:a298d18da239 138 // Create the heart rate record in Salesforce.com
ansond 0:a298d18da239 139 void create_heartrate_record(ErrorHandler *logger,SalesforceInterface *sf) {
ansond 0:a298d18da239 140 // create a new record
ansond 0:a298d18da239 141 MbedJSONValue bpm_record;
ansond 0:a298d18da239 142 bpm_record[hrm_bpm_field_name] = (int)get_heartrate();
ansond 0:a298d18da239 143 bpm_record[hrm_user_field_name] = hrm_user;
ansond 0:a298d18da239 144 bpm_record[hrm_counter_field_name] = (int)iteration_counter;
ansond 0:a298d18da239 145
ansond 0:a298d18da239 146 logger->log("ARM Salesforce HRM v%s\r\nCreate: new bpm record(%d): %d\r\nSending...",APP_VERSION,iteration_counter,hrmCounter);
ansond 0:a298d18da239 147 logger->logConsole("Initializing BPM record: %s",bpm_record.serialize().c_str());
ansond 0:a298d18da239 148
ansond 0:a298d18da239 149 // create the BPM record in salesforce.com
ansond 0:a298d18da239 150 MbedJSONValue response = sf->createRecord(hrm_object_name,bpm_record);
ansond 0:a298d18da239 151
ansond 0:a298d18da239 152 // display the result
ansond 0:a298d18da239 153 char *result = (char *)response.serialize().c_str();
ansond 0:a298d18da239 154 if (result != NULL && strlen(result) > 0 && strcmp(result,"null") != 0) {
ansond 0:a298d18da239 155 // save off the token if we succeeded
ansond 0:a298d18da239 156 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 157 logger->logConsole("Create: result: %s http_code = %d",result,sf->httpResponseCode());
ansond 0:a298d18da239 158 RESET_SML_BUFFER(bpm_record_id);
ansond 0:a298d18da239 159 strcpy(bpm_record_id,(char *)response["id"].get<std::string>().c_str());
ansond 0:a298d18da239 160 logger->turnLEDGreen();
ansond 0:a298d18da239 161 }
ansond 0:a298d18da239 162 else {
ansond 0:a298d18da239 163 // failure
ansond 0:a298d18da239 164 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 165 logger->logConsole("Create: FAILED http_code=%d",sf->httpResponseCode());
ansond 0:a298d18da239 166 logger->turnLEDRed();
ansond 0:a298d18da239 167 do_loop = false;
ansond 0:a298d18da239 168 }
ansond 0:a298d18da239 169 }
ansond 0:a298d18da239 170
ansond 0:a298d18da239 171 // Update the heart rate record in Salesforce.com
ansond 0:a298d18da239 172 void update_heartrate_record(ErrorHandler *logger,SalesforceInterface *sf) {
ansond 0:a298d18da239 173 logger->turnLEDOrange();
ansond 0:a298d18da239 174
ansond 0:a298d18da239 175 // update am existing record - assume "name" is the proper key for the record you wish to update...
ansond 0:a298d18da239 176 MbedJSONValue bpm_record;
ansond 0:a298d18da239 177 int bpm = get_heartrate();
ansond 0:a298d18da239 178 bpm_record[hrm_bpm_field_name] = bpm;
ansond 0:a298d18da239 179 bpm_record[hrm_user_field_name] = hrm_user;
ansond 0:a298d18da239 180 bpm_record[hrm_counter_field_name] = (int)iteration_counter;
ansond 0:a298d18da239 181
ansond 0:a298d18da239 182 // DEBUG
ansond 0:a298d18da239 183 logger->log("ARM Salesforce HRM v%s\r\nUpdate HR(%d): %d bpm\r\nSending...",APP_VERSION,iteration_counter,bpm);
ansond 0:a298d18da239 184 logger->logConsole("Update: updated record: %s",bpm_record.serialize().c_str());
ansond 0:a298d18da239 185
ansond 0:a298d18da239 186 // update the BPM record in salesforce.com
ansond 0:a298d18da239 187 bool updated = sf->updateRecord(hrm_object_name,bpm_record_id,bpm_record);
ansond 0:a298d18da239 188
ansond 0:a298d18da239 189 // display the result
ansond 0:a298d18da239 190 if (updated) {
ansond 0:a298d18da239 191 // SUCCESS
ansond 0:a298d18da239 192 logger->log("ARM Salesforce HRM v%s\r\nUpdate HR(%d): %d bpm\r\nSending...SUCCESS",APP_VERSION,iteration_counter,bpm);
ansond 0:a298d18da239 193 logger->logConsole("Update: successful! http_code=%d",sf->httpResponseCode());
ansond 0:a298d18da239 194 logger->turnLEDGreen();
ansond 0:a298d18da239 195 }
ansond 0:a298d18da239 196 else {
ansond 0:a298d18da239 197 if (num_retries > 0) {
ansond 0:a298d18da239 198 // retry state
ansond 0:a298d18da239 199 logger->turnLEDPurple();
ansond 0:a298d18da239 200
ansond 0:a298d18da239 201 // OAUTH token may have expired - reset and retry
ansond 0:a298d18da239 202 if (num_retries == MAX_TRIES) --iteration_counter; // one time only in retries...
ansond 0:a298d18da239 203 --num_retries;
ansond 0:a298d18da239 204 sf->resetSalesforceToken();
ansond 0:a298d18da239 205 update_heartrate_record(logger,sf);
ansond 0:a298d18da239 206 }
ansond 0:a298d18da239 207 else {
ansond 0:a298d18da239 208 // failure
ansond 0:a298d18da239 209 logger->log("ARM Salesforce HRM v%s\r\nUpdate HR(%d): %d bpm\r\nSending...FAILED",APP_VERSION,iteration_counter,bpm);
ansond 0:a298d18da239 210 logger->logConsole("Update: FAILED http_code=%d",sf->httpResponseCode());
ansond 0:a298d18da239 211 do_loop = false;
ansond 0:a298d18da239 212
ansond 0:a298d18da239 213 // give-up state
ansond 0:a298d18da239 214 logger->turnLEDRed();
ansond 0:a298d18da239 215 }
ansond 0:a298d18da239 216 }
ansond 0:a298d18da239 217 }
ansond 0:a298d18da239 218
ansond 0:a298d18da239 219 // Report heart rate to Salesforce.com
ansond 0:a298d18da239 220 void report_heartrate(ErrorHandler *logger,SalesforceInterface *sf) {
ansond 0:a298d18da239 221 if (iteration_counter == 0) create_heartrate_record(logger,sf);
ansond 0:a298d18da239 222 else update_heartrate_record(logger,sf);
ansond 0:a298d18da239 223 }
ansond 0:a298d18da239 224
ansond 0:a298d18da239 225 // Main Task...
ansond 0:a298d18da239 226 void mainTask(void const *v) {
ansond 0:a298d18da239 227
ansond 0:a298d18da239 228 // create our object instances
ansond 0:a298d18da239 229 ErrorHandler logger(&pc,&lcd);
ansond 0:a298d18da239 230 SalesforceInterface *sf = NULL;
ansond 0:a298d18da239 231
ansond 0:a298d18da239 232 // announce
ansond 0:a298d18da239 233 logger.log("\r\n\r\nARM Salesforce HRM v%s",APP_VERSION);
ansond 0:a298d18da239 234 logger.turnLEDBlue();
ansond 0:a298d18da239 235 wait(1);
ansond 0:a298d18da239 236
ansond 0:a298d18da239 237 // initialize Ethernet
ansond 0:a298d18da239 238 logger.log("Initializing Ethernet...");
ansond 0:a298d18da239 239 ethernet.init();
ansond 0:a298d18da239 240
ansond 0:a298d18da239 241 // get a DHCP address and bring the network interface up
ansond 0:a298d18da239 242 logger.log("Getting IP Address...");
ansond 0:a298d18da239 243 logger.turnLEDYellow();
ansond 0:a298d18da239 244 if (ethernet.connect() == 0) {
ansond 0:a298d18da239 245 // log our IP address (DHCP)
ansond 0:a298d18da239 246 logger.log("IP Address: %s",ethernet.getIPAddress());
ansond 0:a298d18da239 247
ansond 0:a298d18da239 248 // allocate the Salesforce.com interface
ansond 0:a298d18da239 249 logger.logConsole("Allocating the Saleforce.com interface...");
ansond 0:a298d18da239 250 sf = new SalesforceInterface(&logger,&http);
ansond 0:a298d18da239 251
ansond 0:a298d18da239 252 // set our Salesforce.com credentials
ansond 0:a298d18da239 253 logger.logConsole("Setting credentials in the Salesforce.com interface...");
ansond 0:a298d18da239 254 sf->setCredentials(username,password,client_id,client_secret);
ansond 0:a298d18da239 255
ansond 0:a298d18da239 256 // initialize the earbud
ansond 0:a298d18da239 257 LOG_CONSOLE("Initializing Earbud...\r\n");
ansond 0:a298d18da239 258 t.start();
ansond 0:a298d18da239 259 arrayInit();
ansond 0:a298d18da239 260 earbud.rise(&interrupt);
ansond 0:a298d18da239 261 hrmCounter = HRM_OFF;
ansond 0:a298d18da239 262
ansond 0:a298d18da239 263 // enter main loop
ansond 0:a298d18da239 264 logger.logConsole("Beginning main event loop...");
ansond 0:a298d18da239 265 while(do_loop) {
ansond 0:a298d18da239 266 report_heartrate(&logger,sf);
ansond 0:a298d18da239 267 Thread::wait(WAIT_TIME_MS);
ansond 0:a298d18da239 268 }
ansond 0:a298d18da239 269
ansond 0:a298d18da239 270 // if we fell out of the loop exit...
ansond 0:a298d18da239 271 logger.log("Application Exiting...");
ansond 0:a298d18da239 272 logger.turnLEDRed();
ansond 0:a298d18da239 273 exit(1);
ansond 0:a298d18da239 274 }
ansond 0:a298d18da239 275 else {
ansond 0:a298d18da239 276 logger.log("No Network... Exiting...");
ansond 0:a298d18da239 277 logger.turnLEDRed();
ansond 0:a298d18da239 278 exit(1);
ansond 0:a298d18da239 279 }
ansond 0:a298d18da239 280 }
ansond 0:a298d18da239 281
ansond 0:a298d18da239 282 // main entry
ansond 0:a298d18da239 283 int main() {
ansond 0:a298d18da239 284 Thread workerTask(mainTask, NULL, osPriorityNormal, STACK_SIZE);
ansond 0:a298d18da239 285 while (true) {
ansond 0:a298d18da239 286 Thread::wait(10*WAIT_TIME_MS);
ansond 0:a298d18da239 287 }
ansond 0:a298d18da239 288 }