Mercurial > public > ostc4
comparison Discovery/Src/cv_heartbeat.c @ 1032:33b91584d827 Puls_Integration
New CV Pulse:
The basic infrastructure for external puls measurement via Bluetooth has been added. Precondition is an OSTC with an activated central role. The OSTC will then search for a BLE device with puls measurement service. Reading data and visualization is not implemented yet.
| author | Ideenmodellierer |
|---|---|
| date | Mon, 28 Jul 2025 18:34:45 +0200 |
| parents | |
| children | 5f66e44d69f0 |
comparison
equal
deleted
inserted
replaced
| 1031:cd4561c33758 | 1032:33b91584d827 |
|---|---|
| 1 /////////////////////////////////////////////////////////////////////////////// | |
| 2 /// -*- coding: UTF-8 -*- | |
| 3 /// | |
| 4 /// \file Discovery/Src/cv_heartbeat.c | |
| 5 /// \brief providing functionality to connect OSTC to a Polar HC10 heartbeat sensor | |
| 6 /// \author heinrichs weikamp gmbh | |
| 7 /// \date 03-July-2025 | |
| 8 /// | |
| 9 /// $Id$ | |
| 10 /////////////////////////////////////////////////////////////////////////////// | |
| 11 /// \par Copyright (c) 2014-2025 Heinrichs Weikamp gmbh | |
| 12 /// | |
| 13 /// This program is free software: you can redistribute it and/or modify | |
| 14 /// it under the terms of the GNU General Public License as published by | |
| 15 /// the Free Software Foundation, either version 3 of the License, or | |
| 16 /// (at your option) any later version. | |
| 17 /// | |
| 18 /// This program is distributed in the hope that it will be useful, | |
| 19 /// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 20 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 21 /// GNU General Public License for more details. | |
| 22 /// | |
| 23 /// You should have received a copy of the GNU General Public License | |
| 24 /// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 25 ////////////////////////////////////////////////////////////////////////////// | |
| 26 | |
| 27 #include "cv_heartbeat.h" | |
| 28 #include "tMenuEdit.h" | |
| 29 | |
| 30 #include "gfx_fonts.h" | |
| 31 #include "tHome.h" | |
| 32 #include "ostc.h" | |
| 33 #include "tComm.h" | |
| 34 #include "tInfoLogger.h" | |
| 35 | |
| 36 static sensorHeartbeat_State_t heartbeatState = SENSOR_HB_OFFLINE; | |
| 37 | |
| 38 static uint8_t OnAction_Heartbeat(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action); | |
| 39 static uint32_t startDetection_ms; | |
| 40 | |
| 41 #define MAX_BT_DEVICE 10 /* max number of device which may be handled */ | |
| 42 static btDdeviceData_t btDeviceList[MAX_BT_DEVICE]; | |
| 43 static btDeviceService_t curDeviceService[10]; | |
| 44 static uint8_t curServiceIndex = 0; | |
| 45 static uint8_t curBtIndex = 0; | |
| 46 static uint8_t connHandle = ' '; | |
| 47 | |
| 48 static indicatior_t checkIndicators(uint8_t* pdata) | |
| 49 { | |
| 50 #if 0 | |
| 51 static uint8_t foundRSSI = 0; | |
| 52 static uint8_t foundNAME = 0; | |
| 53 static uint8_t foundMNF = 0; | |
| 54 static uint8_t foundUUID = 0; | |
| 55 static uint8_t foundOK = 0; | |
| 56 #endif | |
| 57 indicatior_t ret = NO_INDICATOR; | |
| 58 | |
| 59 if(strcmp((char*)pdata,"+UBTD:") == 0) | |
| 60 { | |
| 61 ret = DEVICE_INDICATOR; | |
| 62 } | |
| 63 else if(strcmp((char*)pdata,"+UUBTACLC:") == 0) | |
| 64 { | |
| 65 ret = CONNECTION_INDICATOR; | |
| 66 } | |
| 67 else if(strcmp((char*)pdata,"+UBTGDP:") == 0) | |
| 68 { | |
| 69 ret = SERVICE_INDICATOR; | |
| 70 } | |
| 71 | |
| 72 return ret; | |
| 73 } | |
| 74 | |
| 75 static void handleOK() | |
| 76 { | |
| 77 switch(heartbeatState) | |
| 78 { | |
| 79 case SENSOR_HB_ENABLE_BLE: heartbeatState = SENSOR_HB_CHECK_CONFIG; | |
| 80 break; | |
| 81 case SENSOR_HB_CHECK_CONFIG: heartbeatState = SENSOR_HB_DISCOVER; | |
| 82 break; | |
| 83 case SENSOR_HB_RESTART: heartbeatState = SENSOR_HB_OFFLINE; | |
| 84 break; | |
| 85 case SENSOR_HB_DISCOVER: heartbeatState = SENSOR_HB_CONNECT; | |
| 86 break; | |
| 87 case SENSOR_HB_SERVICES: heartbeatState = SENSOR_HB_OFFLINE; | |
| 88 break; | |
| 89 default: | |
| 90 break; | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 static void handleERROR() | |
| 95 { | |
| 96 | |
| 97 } | |
| 98 | |
| 99 static uint8_t getDeviceList() | |
| 100 { | |
| 101 static uint8_t firstDevice = 1; | |
| 102 static uint8_t curLine[MAX_CHAR_PER_LINE]; /* holds complete line and is used for logging */ | |
| 103 static uint8_t curLineIndex = 0; | |
| 104 static uint8_t parameter[40]; /* content of the parameter in read state */ | |
| 105 static uint8_t writeIndex = 0; | |
| 106 static uint8_t complete = 0; | |
| 107 | |
| 108 static readDataType_t readType = BT_READ_NOTHING; | |
| 109 | |
| 110 char text[40]; | |
| 111 uint8_t data = 0; | |
| 112 data = UART_getChar(); | |
| 113 | |
| 114 while((data != 0) && (complete == 0)) | |
| 115 { | |
| 116 if(curLineIndex == MAX_CHAR_PER_LINE) /* avoid overflow */ | |
| 117 { | |
| 118 InfoLogger_writeLine(curLine,curLineIndex,0); | |
| 119 memset(curLine,0,sizeof(curLine)); | |
| 120 curLineIndex = 0; | |
| 121 } | |
| 122 if((data == '\r') || (data == '\n')) | |
| 123 { | |
| 124 if(curLineIndex > 0) | |
| 125 { | |
| 126 InfoLogger_writeLine(curLine,curLineIndex,0); | |
| 127 if(strcmp((char*)curLine,"OK") == 0) | |
| 128 { | |
| 129 handleOK(); | |
| 130 } | |
| 131 else | |
| 132 { | |
| 133 if(strcmp((char*)curLine,"ERROR") == 0) | |
| 134 { | |
| 135 handleERROR(); | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 switch(readType) | |
| 140 { | |
| 141 case BT_READ_DEVICE_NAME: if(writeIndex < BLUEMOD_NAME_SIZE) | |
| 142 { | |
| 143 memcpy (btDeviceList[curBtIndex].name, parameter, writeIndex); | |
| 144 } | |
| 145 break; | |
| 146 case BT_READ_SERV_UUID: if(writeIndex < 50) | |
| 147 { | |
| 148 memcpy(curDeviceService[curServiceIndex].uuid, parameter, writeIndex); | |
| 149 } | |
| 150 curServiceIndex++; | |
| 151 break; | |
| 152 default: | |
| 153 break; | |
| 154 } | |
| 155 curLineIndex = 0; | |
| 156 writeIndex = 0; | |
| 157 memset(curLine,0,sizeof(curLine)); | |
| 158 readType = BT_READ_NOTHING; | |
| 159 } | |
| 160 else | |
| 161 { | |
| 162 if(curLineIndex < MAX_CHAR_PER_LINE) curLine[curLineIndex++] = data; | |
| 163 | |
| 164 if(data == ':') | |
| 165 { | |
| 166 switch(checkIndicators(curLine)) | |
| 167 { | |
| 168 case DEVICE_INDICATOR: readType = BT_READ_DEVICE_ADDR; | |
| 169 break; | |
| 170 case CONNECTION_INDICATOR: readType = BT_READ_CON_DETAILS; | |
| 171 break; | |
| 172 case SERVICE_INDICATOR: readType = BT_READ_SERV_HANDLE; | |
| 173 break; | |
| 174 default: | |
| 175 break; | |
| 176 } | |
| 177 writeIndex = 0; | |
| 178 memset(parameter,0,sizeof(parameter)); | |
| 179 } | |
| 180 else | |
| 181 { | |
| 182 if(data == ',') /* parameter end */ | |
| 183 { | |
| 184 switch(readType) | |
| 185 { | |
| 186 case BT_READ_DEVICE_ADDR: if(writeIndex < BLUEMOD_ADDR_SIZE-1) | |
| 187 { | |
| 188 if(firstDevice) | |
| 189 { | |
| 190 firstDevice = 0; | |
| 191 } | |
| 192 else | |
| 193 { | |
| 194 curBtIndex++; | |
| 195 } | |
| 196 parameter[writeIndex-1] = 0; /*remove 'p' from address */ | |
| 197 strcpy((char*)btDeviceList[curBtIndex].address, (char*)parameter); | |
| 198 } | |
| 199 readType = BT_READ_DEVICE_RSSI; | |
| 200 break; | |
| 201 case BT_READ_DEVICE_RSSI: if(writeIndex < BLUEMOD_RSSI_SIZE-1) | |
| 202 { | |
| 203 strcpy((char*)btDeviceList[curBtIndex].rssi, (char*)parameter); | |
| 204 } | |
| 205 readType = BT_READ_DEVICE_NAME; | |
| 206 break; | |
| 207 case BT_READ_DEVICE_NAME: if(writeIndex < BLUEMOD_NAME_SIZE-1) | |
| 208 { | |
| 209 memcpy(btDeviceList[curBtIndex].name, parameter, writeIndex); | |
| 210 } | |
| 211 readType = BT_READ_NOTHING; | |
| 212 break; | |
| 213 case BT_READ_CON_DETAILS: connHandle = parameter[0]; | |
| 214 heartbeatState = SENSOR_HB_SERVICES; | |
| 215 readType = BT_READ_NOTHING; | |
| 216 break; | |
| 217 case BT_READ_SERV_HANDLE: curDeviceService[curServiceIndex].handle = parameter[0]; | |
| 218 readType = BT_READ_SERV_START; | |
| 219 break; | |
| 220 case BT_READ_SERV_START: if(writeIndex < 6) | |
| 221 { | |
| 222 memcpy(curDeviceService[curServiceIndex].start, parameter, writeIndex); | |
| 223 } | |
| 224 readType = BT_READ_SERV_END; | |
| 225 break; | |
| 226 case BT_READ_SERV_END: if(writeIndex < 6) | |
| 227 { | |
| 228 memcpy(curDeviceService[curServiceIndex].end, parameter, writeIndex); | |
| 229 } | |
| 230 readType = BT_READ_SERV_UUID; | |
| 231 break; | |
| 232 | |
| 233 default: readType = BT_READ_NOTHING; | |
| 234 break; | |
| 235 } | |
| 236 writeIndex = 0; | |
| 237 memset(parameter,0 , sizeof(parameter)); | |
| 238 } | |
| 239 else | |
| 240 { | |
| 241 // if(readType != BT_READ_NOTHING) | |
| 242 { | |
| 243 parameter[writeIndex++] = data; | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 } | |
| 248 data = UART_getChar(); | |
| 249 } | |
| 250 return complete; | |
| 251 } | |
| 252 | |
| 253 sensorHeartbeat_State_t cv_heartbeat_getState() | |
| 254 { | |
| 255 return heartbeatState; | |
| 256 } | |
| 257 | |
| 258 void openEdit_Heartbeat(void) | |
| 259 { | |
| 260 SSettings *settings = settingsGetPointer(); | |
| 261 | |
| 262 char text[32]; | |
| 263 snprintf(text, 32, "\001%c%c", TXT_2BYTE, TXT2BYTE_Pulse); | |
| 264 write_topline(text); | |
| 265 | |
| 266 set_globalState(StMOption_Heartbeat); | |
| 267 resetMenuEdit(CLUT_MenuPageCvOption); | |
| 268 | |
| 269 snprintf(text, 32, "%c%c", TXT_2BYTE, TXT2BYTE_SensorDetect); | |
| 270 write_field_button(StMOption_Heartbeat, 30, 299, ME_Y_LINE1, &FontT48, text); | |
| 271 | |
| 272 write_buttonTextline(TXT2BYTE_ButtonMinus, TXT2BYTE_ButtonEnter, TXT2BYTE_ButtonPlus); | |
| 273 | |
| 274 setEvent(StMOption_Heartbeat, (uint32_t)OnAction_Heartbeat); | |
| 275 } | |
| 276 | |
| 277 static uint8_t OnAction_Heartbeat(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action) | |
| 278 { | |
| 279 switch(heartbeatState) | |
| 280 { | |
| 281 case SENSOR_HB_OFFLINE: | |
| 282 HAL_UART_AbortReceive_IT(&UartHandle); | |
| 283 MX_UART_BT_Init_DMA(); | |
| 284 UART_StartDMARx(); | |
| 285 heartbeatState = SENSOR_HB_ENABLE_BLE; | |
| 286 startDetection_ms = HAL_GetTick(); | |
| 287 curBtIndex = 0; | |
| 288 memset(btDeviceList, 0, sizeof(btDeviceList)); | |
| 289 break; | |
| 290 | |
| 291 default: | |
| 292 break; | |
| 293 } | |
| 294 return UNSPECIFIC_RETURN; | |
| 295 } | |
| 296 | |
| 297 void cv_heartbeat_Control(void) | |
| 298 { | |
| 299 static uint8_t action = 0; | |
| 300 static uint8_t retry = 0; | |
| 301 static uint8_t lastState = 0; | |
| 302 static uint8_t devicesIndex = 0; | |
| 303 | |
| 304 | |
| 305 char cmd[50]; | |
| 306 | |
| 307 cmd[0] = 0; | |
| 308 | |
| 309 getDeviceList(); | |
| 310 | |
| 311 if(action == 3) | |
| 312 { | |
| 313 action = 0; | |
| 314 switch(heartbeatState) | |
| 315 { | |
| 316 case SENSOR_HB_ENABLE_BLE: HAL_Delay(1000); | |
| 317 snprintf(cmd, sizeof(cmd), "+++" ); //"AT+UBTD=2,1,5000\r\n" | |
| 318 InfoLogger_writeLine((uint8_t*)cmd,3,1); | |
| 319 HAL_UART_Transmit(&UartHandle, (uint8_t*)cmd, 3, 5000); | |
| 320 HAL_Delay(1000); | |
| 321 cmd[0] = 0; | |
| 322 break; | |
| 323 case SENSOR_HB_CHECK_CONFIG: snprintf(cmd, sizeof(cmd), "AT+UBTCFG=2\r\n" ); // AT+UBTLE? | |
| 324 | |
| 325 #if 0 | |
| 326 if(settingsGetPointer()->dive_mode == DIVEMODE_OC) | |
| 327 { | |
| 328 snprintf(cmd, sizeof(cmd), "AT+UBTLE=2\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" | |
| 329 } | |
| 330 else | |
| 331 { | |
| 332 snprintf(cmd, sizeof(cmd), "AT+UBTLE=3\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" | |
| 333 } | |
| 334 #endif | |
| 335 break; | |
| 336 case SENSOR_HB_DISCOVER: if(lastState != SENSOR_HB_DISCOVER) | |
| 337 { | |
| 338 snprintf(cmd, sizeof(cmd), "AT+UBTD=2,1\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" | |
| 339 devicesIndex = 0; | |
| 340 } | |
| 341 | |
| 342 //snprintf(cmd, sizeof(cmd), "AT&W\r\n" ); // AT+UBTD=2,1\r\n "AT+UBTD=2,1,5000\r\n" | |
| 343 break; | |
| 344 #if 0 | |
| 345 case SENSOR_HB_RESTART: snprintf(cmd, sizeof(cmd), "AT+UBTD=2,1\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" | |
| 346 | |
| 347 // snprintf(cmd, sizeof(cmd), "AT+CPWROFF\r\n" ); // AT+UBTD=2,1\r\n "AT+UBTD=2,1,5000\r\n" | |
| 348 break; | |
| 349 #endif | |
| 350 case SENSOR_HB_CONNECT: if(curBtIndex != devicesIndex) | |
| 351 { | |
| 352 snprintf(cmd, sizeof(cmd), "AT+UBTACLC=%s\r\n",btDeviceList[devicesIndex].address); | |
| 353 devicesIndex++; | |
| 354 } | |
| 355 break; | |
| 356 case SENSOR_HB_SERVICES: if((connHandle >= '0') && (connHandle <= '9') && (lastState != SENSOR_HB_SERVICES)) | |
| 357 { | |
| 358 snprintf(cmd, sizeof(cmd), "AT+UBTGDP=0%c\r\n",connHandle); | |
| 359 } | |
| 360 else | |
| 361 { | |
| 362 heartbeatState = SENSOR_HB_OFFLINE; | |
| 363 } | |
| 364 break; | |
| 365 | |
| 366 default: | |
| 367 break; | |
| 368 } | |
| 369 if(cmd[0] != 0) | |
| 370 { | |
| 371 { | |
| 372 InfoLogger_writeLine((uint8_t*)cmd,strlen(cmd),1); | |
| 373 HAL_UART_Transmit(&UartHandle, (uint8_t*)cmd, strlen(cmd), 5000); | |
| 374 retry++; | |
| 375 if(retry == 3) | |
| 376 { | |
| 377 heartbeatState = SENSOR_HB_OFFLINE; | |
| 378 } | |
| 379 } | |
| 380 } | |
| 381 if(lastState != heartbeatState) | |
| 382 { | |
| 383 lastState = heartbeatState; | |
| 384 retry = 0; | |
| 385 } | |
| 386 } | |
| 387 else | |
| 388 { | |
| 389 action++; | |
| 390 } | |
| 391 } | |
| 392 void refresh_Heartbeat(void) | |
| 393 { | |
| 394 char text[32]; | |
| 395 uint8_t index = 0; | |
| 396 | |
| 397 snprintf(text, 32, "\001%c%c", TXT_2BYTE, TXT2BYTE_Pulse); | |
| 398 write_topline(text); | |
| 399 | |
| 400 switch(heartbeatState) | |
| 401 { | |
| 402 case SENSOR_HB_OFFLINE: | |
| 403 default: snprintf(text, 32, "%c%c", TXT_2BYTE, TXT2BYTE_SensorDetect); | |
| 404 write_label_var(30, 299, ME_Y_LINE1, &FontT48, text); | |
| 405 | |
| 406 if(curBtIndex > 0) | |
| 407 { | |
| 408 while((index < curBtIndex) && (index < 3)) | |
| 409 { | |
| 410 snprintf(text, 40, "%s", btDeviceList[index].address); | |
| 411 write_label_var( 30, 300, ME_Y_LINE3 + (index * ME_Y_LINE_STEP), &FontT48, text); | |
| 412 index++; | |
| 413 } | |
| 414 } | |
| 415 break; | |
| 416 case SENSOR_HB_ENABLE_BLE: snprintf(text, 32, "Activate BLE"); | |
| 417 write_label_var( 30, 300, ME_Y_LINE1, &FontT48, text); | |
| 418 break; | |
| 419 case SENSOR_HB_DISCOVER: | |
| 420 snprintf(text, 32, "Searching"); | |
| 421 write_label_var( 30, 300, ME_Y_LINE1, &FontT48, text); | |
| 422 | |
| 423 if(curBtIndex > 0) | |
| 424 { | |
| 425 while((index < curBtIndex) && (index < 4)) | |
| 426 { | |
| 427 snprintf(text, 40, "%s", btDeviceList[index].address); | |
| 428 write_label_var( 30, 300, ME_Y_LINE2 + (index * ME_Y_LINE_STEP), &FontT48, text); | |
| 429 index++; | |
| 430 } | |
| 431 } | |
| 432 break; | |
| 433 } | |
| 434 | |
| 435 write_buttonTextline(TXT2BYTE_ButtonMinus, TXT2BYTE_ButtonEnter, TXT2BYTE_ButtonPlus); | |
| 436 } | |
| 437 |
