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