Mercurial > public > ostc4
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Discovery/Src/cv_heartbeat.c Mon Jul 28 18:34:45 2025 +0200 @@ -0,0 +1,437 @@ +/////////////////////////////////////////////////////////////////////////////// +/// -*- coding: UTF-8 -*- +/// +/// \file Discovery/Src/cv_heartbeat.c +/// \brief providing functionality to connect OSTC to a Polar HC10 heartbeat sensor +/// \author heinrichs weikamp gmbh +/// \date 03-July-2025 +/// +/// $Id$ +/////////////////////////////////////////////////////////////////////////////// +/// \par Copyright (c) 2014-2025 Heinrichs Weikamp gmbh +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU General Public License for more details. +/// +/// You should have received a copy of the GNU General Public License +/// along with this program. If not, see <http://www.gnu.org/licenses/>. +////////////////////////////////////////////////////////////////////////////// + +#include "cv_heartbeat.h" +#include "tMenuEdit.h" + +#include "gfx_fonts.h" +#include "tHome.h" +#include "ostc.h" +#include "tComm.h" +#include "tInfoLogger.h" + +static sensorHeartbeat_State_t heartbeatState = SENSOR_HB_OFFLINE; + +static uint8_t OnAction_Heartbeat(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action); +static uint32_t startDetection_ms; + +#define MAX_BT_DEVICE 10 /* max number of device which may be handled */ +static btDdeviceData_t btDeviceList[MAX_BT_DEVICE]; +static btDeviceService_t curDeviceService[10]; +static uint8_t curServiceIndex = 0; +static uint8_t curBtIndex = 0; +static uint8_t connHandle = ' '; + +static indicatior_t checkIndicators(uint8_t* pdata) +{ +#if 0 + static uint8_t foundRSSI = 0; + static uint8_t foundNAME = 0; + static uint8_t foundMNF = 0; + static uint8_t foundUUID = 0; + static uint8_t foundOK = 0; +#endif + indicatior_t ret = NO_INDICATOR; + + if(strcmp((char*)pdata,"+UBTD:") == 0) + { + ret = DEVICE_INDICATOR; + } + else if(strcmp((char*)pdata,"+UUBTACLC:") == 0) + { + ret = CONNECTION_INDICATOR; + } + else if(strcmp((char*)pdata,"+UBTGDP:") == 0) + { + ret = SERVICE_INDICATOR; + } + + return ret; +} + +static void handleOK() +{ + switch(heartbeatState) + { + case SENSOR_HB_ENABLE_BLE: heartbeatState = SENSOR_HB_CHECK_CONFIG; + break; + case SENSOR_HB_CHECK_CONFIG: heartbeatState = SENSOR_HB_DISCOVER; + break; + case SENSOR_HB_RESTART: heartbeatState = SENSOR_HB_OFFLINE; + break; + case SENSOR_HB_DISCOVER: heartbeatState = SENSOR_HB_CONNECT; + break; + case SENSOR_HB_SERVICES: heartbeatState = SENSOR_HB_OFFLINE; + break; + default: + break; + } +} + +static void handleERROR() +{ + +} + +static uint8_t getDeviceList() +{ + static uint8_t firstDevice = 1; + static uint8_t curLine[MAX_CHAR_PER_LINE]; /* holds complete line and is used for logging */ + static uint8_t curLineIndex = 0; + static uint8_t parameter[40]; /* content of the parameter in read state */ + static uint8_t writeIndex = 0; + static uint8_t complete = 0; + + static readDataType_t readType = BT_READ_NOTHING; + + char text[40]; + uint8_t data = 0; + data = UART_getChar(); + + while((data != 0) && (complete == 0)) + { + if(curLineIndex == MAX_CHAR_PER_LINE) /* avoid overflow */ + { + InfoLogger_writeLine(curLine,curLineIndex,0); + memset(curLine,0,sizeof(curLine)); + curLineIndex = 0; + } + if((data == '\r') || (data == '\n')) + { + if(curLineIndex > 0) + { + InfoLogger_writeLine(curLine,curLineIndex,0); + if(strcmp((char*)curLine,"OK") == 0) + { + handleOK(); + } + else + { + if(strcmp((char*)curLine,"ERROR") == 0) + { + handleERROR(); + } + } + } + switch(readType) + { + case BT_READ_DEVICE_NAME: if(writeIndex < BLUEMOD_NAME_SIZE) + { + memcpy (btDeviceList[curBtIndex].name, parameter, writeIndex); + } + break; + case BT_READ_SERV_UUID: if(writeIndex < 50) + { + memcpy(curDeviceService[curServiceIndex].uuid, parameter, writeIndex); + } + curServiceIndex++; + break; + default: + break; + } + curLineIndex = 0; + writeIndex = 0; + memset(curLine,0,sizeof(curLine)); + readType = BT_READ_NOTHING; + } + else + { + if(curLineIndex < MAX_CHAR_PER_LINE) curLine[curLineIndex++] = data; + + if(data == ':') + { + switch(checkIndicators(curLine)) + { + case DEVICE_INDICATOR: readType = BT_READ_DEVICE_ADDR; + break; + case CONNECTION_INDICATOR: readType = BT_READ_CON_DETAILS; + break; + case SERVICE_INDICATOR: readType = BT_READ_SERV_HANDLE; + break; + default: + break; + } + writeIndex = 0; + memset(parameter,0,sizeof(parameter)); + } + else + { + if(data == ',') /* parameter end */ + { + switch(readType) + { + case BT_READ_DEVICE_ADDR: if(writeIndex < BLUEMOD_ADDR_SIZE-1) + { + if(firstDevice) + { + firstDevice = 0; + } + else + { + curBtIndex++; + } + parameter[writeIndex-1] = 0; /*remove 'p' from address */ + strcpy((char*)btDeviceList[curBtIndex].address, (char*)parameter); + } + readType = BT_READ_DEVICE_RSSI; + break; + case BT_READ_DEVICE_RSSI: if(writeIndex < BLUEMOD_RSSI_SIZE-1) + { + strcpy((char*)btDeviceList[curBtIndex].rssi, (char*)parameter); + } + readType = BT_READ_DEVICE_NAME; + break; + case BT_READ_DEVICE_NAME: if(writeIndex < BLUEMOD_NAME_SIZE-1) + { + memcpy(btDeviceList[curBtIndex].name, parameter, writeIndex); + } + readType = BT_READ_NOTHING; + break; + case BT_READ_CON_DETAILS: connHandle = parameter[0]; + heartbeatState = SENSOR_HB_SERVICES; + readType = BT_READ_NOTHING; + break; + case BT_READ_SERV_HANDLE: curDeviceService[curServiceIndex].handle = parameter[0]; + readType = BT_READ_SERV_START; + break; + case BT_READ_SERV_START: if(writeIndex < 6) + { + memcpy(curDeviceService[curServiceIndex].start, parameter, writeIndex); + } + readType = BT_READ_SERV_END; + break; + case BT_READ_SERV_END: if(writeIndex < 6) + { + memcpy(curDeviceService[curServiceIndex].end, parameter, writeIndex); + } + readType = BT_READ_SERV_UUID; + break; + + default: readType = BT_READ_NOTHING; + break; + } + writeIndex = 0; + memset(parameter,0 , sizeof(parameter)); + } + else + { + // if(readType != BT_READ_NOTHING) + { + parameter[writeIndex++] = data; + } + } + } + } + data = UART_getChar(); + } + return complete; +} + +sensorHeartbeat_State_t cv_heartbeat_getState() +{ + return heartbeatState; +} + +void openEdit_Heartbeat(void) +{ + SSettings *settings = settingsGetPointer(); + + char text[32]; + snprintf(text, 32, "\001%c%c", TXT_2BYTE, TXT2BYTE_Pulse); + write_topline(text); + + set_globalState(StMOption_Heartbeat); + resetMenuEdit(CLUT_MenuPageCvOption); + + snprintf(text, 32, "%c%c", TXT_2BYTE, TXT2BYTE_SensorDetect); + write_field_button(StMOption_Heartbeat, 30, 299, ME_Y_LINE1, &FontT48, text); + + write_buttonTextline(TXT2BYTE_ButtonMinus, TXT2BYTE_ButtonEnter, TXT2BYTE_ButtonPlus); + + setEvent(StMOption_Heartbeat, (uint32_t)OnAction_Heartbeat); +} + +static uint8_t OnAction_Heartbeat(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action) +{ + switch(heartbeatState) + { + case SENSOR_HB_OFFLINE: + HAL_UART_AbortReceive_IT(&UartHandle); + MX_UART_BT_Init_DMA(); + UART_StartDMARx(); + heartbeatState = SENSOR_HB_ENABLE_BLE; + startDetection_ms = HAL_GetTick(); + curBtIndex = 0; + memset(btDeviceList, 0, sizeof(btDeviceList)); + break; + + default: + break; + } + return UNSPECIFIC_RETURN; +} + +void cv_heartbeat_Control(void) +{ + static uint8_t action = 0; + static uint8_t retry = 0; + static uint8_t lastState = 0; + static uint8_t devicesIndex = 0; + + + char cmd[50]; + + cmd[0] = 0; + + getDeviceList(); + + if(action == 3) + { + action = 0; + switch(heartbeatState) + { + case SENSOR_HB_ENABLE_BLE: HAL_Delay(1000); + snprintf(cmd, sizeof(cmd), "+++" ); //"AT+UBTD=2,1,5000\r\n" + InfoLogger_writeLine((uint8_t*)cmd,3,1); + HAL_UART_Transmit(&UartHandle, (uint8_t*)cmd, 3, 5000); + HAL_Delay(1000); + cmd[0] = 0; + break; + case SENSOR_HB_CHECK_CONFIG: snprintf(cmd, sizeof(cmd), "AT+UBTCFG=2\r\n" ); // AT+UBTLE? + +#if 0 + if(settingsGetPointer()->dive_mode == DIVEMODE_OC) + { + snprintf(cmd, sizeof(cmd), "AT+UBTLE=2\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" + } + else + { + snprintf(cmd, sizeof(cmd), "AT+UBTLE=3\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" + } +#endif + break; + case SENSOR_HB_DISCOVER: if(lastState != SENSOR_HB_DISCOVER) + { + snprintf(cmd, sizeof(cmd), "AT+UBTD=2,1\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" + devicesIndex = 0; + } + + //snprintf(cmd, sizeof(cmd), "AT&W\r\n" ); // AT+UBTD=2,1\r\n "AT+UBTD=2,1,5000\r\n" + break; +#if 0 + case SENSOR_HB_RESTART: snprintf(cmd, sizeof(cmd), "AT+UBTD=2,1\r\n" ); //+UBTLE=1 //"AT+UBTD=2,1,5000\r\n" + + // snprintf(cmd, sizeof(cmd), "AT+CPWROFF\r\n" ); // AT+UBTD=2,1\r\n "AT+UBTD=2,1,5000\r\n" + break; +#endif + case SENSOR_HB_CONNECT: if(curBtIndex != devicesIndex) + { + snprintf(cmd, sizeof(cmd), "AT+UBTACLC=%s\r\n",btDeviceList[devicesIndex].address); + devicesIndex++; + } + break; + case SENSOR_HB_SERVICES: if((connHandle >= '0') && (connHandle <= '9') && (lastState != SENSOR_HB_SERVICES)) + { + snprintf(cmd, sizeof(cmd), "AT+UBTGDP=0%c\r\n",connHandle); + } + else + { + heartbeatState = SENSOR_HB_OFFLINE; + } + break; + + default: + break; + } + if(cmd[0] != 0) + { + { + InfoLogger_writeLine((uint8_t*)cmd,strlen(cmd),1); + HAL_UART_Transmit(&UartHandle, (uint8_t*)cmd, strlen(cmd), 5000); + retry++; + if(retry == 3) + { + heartbeatState = SENSOR_HB_OFFLINE; + } + } + } + if(lastState != heartbeatState) + { + lastState = heartbeatState; + retry = 0; + } + } + else + { + action++; + } +} +void refresh_Heartbeat(void) +{ + char text[32]; + uint8_t index = 0; + + snprintf(text, 32, "\001%c%c", TXT_2BYTE, TXT2BYTE_Pulse); + write_topline(text); + + switch(heartbeatState) + { + case SENSOR_HB_OFFLINE: + default: snprintf(text, 32, "%c%c", TXT_2BYTE, TXT2BYTE_SensorDetect); + write_label_var(30, 299, ME_Y_LINE1, &FontT48, text); + + if(curBtIndex > 0) + { + while((index < curBtIndex) && (index < 3)) + { + snprintf(text, 40, "%s", btDeviceList[index].address); + write_label_var( 30, 300, ME_Y_LINE3 + (index * ME_Y_LINE_STEP), &FontT48, text); + index++; + } + } + break; + case SENSOR_HB_ENABLE_BLE: snprintf(text, 32, "Activate BLE"); + write_label_var( 30, 300, ME_Y_LINE1, &FontT48, text); + break; + case SENSOR_HB_DISCOVER: + snprintf(text, 32, "Searching"); + write_label_var( 30, 300, ME_Y_LINE1, &FontT48, text); + + if(curBtIndex > 0) + { + while((index < curBtIndex) && (index < 4)) + { + snprintf(text, 40, "%s", btDeviceList[index].address); + write_label_var( 30, 300, ME_Y_LINE2 + (index * ME_Y_LINE_STEP), &FontT48, text); + index++; + } + } + break; + } + + write_buttonTextline(TXT2BYTE_ButtonMinus, TXT2BYTE_ButtonEnter, TXT2BYTE_ButtonPlus); +} +
