changeset 704:f1b40364b0af

Added protocol functions for UART DiveO2 sensor: The code has been modified to support the handling of several protocols (including baud rate changes). The data is requested by polling and passed via DMA into a ringbuffer which is then parsed by a cyclic function call in the main loop. At the moment only the O2 values are forwarded but because the sensor send several types of data within a signle message already more is extracted but yet discarded.
author Ideenmodellierer
date Fri, 28 Oct 2022 20:49:21 +0200
parents 2f457024049b
children 158d612a9f4d
files Small_CPU/Inc/externalInterface.h Small_CPU/Inc/uart.h Small_CPU/Src/baseCPU2.c Small_CPU/Src/externalInterface.c Small_CPU/Src/scheduler.c Small_CPU/Src/uart.c
diffstat 6 files changed, 315 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/Small_CPU/Inc/externalInterface.h	Fri Oct 28 20:32:24 2022 +0200
+++ b/Small_CPU/Inc/externalInterface.h	Fri Oct 28 20:49:21 2022 +0200
@@ -43,8 +43,10 @@
 uint8_t setExternalInterfaceChannel(uint8_t channel, float value);
 void externalInterface_SwitchPower33(uint8_t state);
 void externalInterface_SwitchADC(uint8_t state);
+void externalInterface_SwitchUART(uint8_t protocol);
 uint8_t externalInterface_isEnabledPower33(void);
 uint8_t externalInterface_isEnabledADC(void);
+uint8_t externalInterface_GetUARTProtocol();
 
 void externalInterface_SetCO2Value(uint16_t CO2_ppm);
 void externalInterface_SetCO2SignalStrength(uint16_t LED_qa);
--- a/Small_CPU/Inc/uart.h	Fri Oct 28 20:32:24 2022 +0200
+++ b/Small_CPU/Inc/uart.h	Fri Oct 28 20:49:21 2022 +0200
@@ -46,6 +46,31 @@
 	RX_DataComplete
  } receiveState_t;
 
+ typedef enum
+ {
+ 	UART_O2_INIT = 0,
+ 	UART_O2_CHECK,			/* send blink command and check if sensor answers */
+ 	UART_O2_REQ_INFO,		/* request information about available internal sensors of sensor */
+	UART_O2_REQ_ID,		/* request ID of sensor */
+ 	UART_O2_IDLE,			/* sensor detected and no communication pending */
+ 	UART_O2_REQ_O2,			/* O2 value has been requested and is in receiption progress */
+ 	UART_O2_ERROR			/* Error state which could not be resolved => only exit via de-/activation cycle */
+ } uartO2Status_t;
+
+
+ typedef enum
+  {
+	O2RX_IDLE = 0,			/* no receiption pending */
+	O2RX_CONFIRM,			/* check the command echo */
+	O2RX_GETNR,				/* extract the sensor number */
+	O2RX_GETO2,				/* extract the ppo2 */
+	O2RX_GETTEMP,			/* extract the temperature */
+	O2RX_GETSTATUS,			/* extract the sensor status */
+	O2RX_GETTYPE,			/* extract the sensor type (should be 8) */
+	O2RX_GETCHANNEL,		/* extract the number of sensor channels (should be 1) */
+	O2RX_GETVERSION,		/* extract the sensor version */
+	O2RX_GETSUBSENSORS		/* extract the available measures (O2, temperature, humidity etc) */
+  } uartO2RxState_t;
 
 void MX_USART1_UART_Init(void);
 void MX_USART1_UART_DeInit(void);
@@ -57,6 +82,8 @@
 #ifdef ENABLE_SENTINEL_MODE
 void HandleUARTSentinelData(void);
 #endif
+void HandleUARTDigitalO2(void);
+
 #ifdef __cplusplus
 }
 #endif
--- a/Small_CPU/Src/baseCPU2.c	Fri Oct 28 20:32:24 2022 +0200
+++ b/Small_CPU/Src/baseCPU2.c	Fri Oct 28 20:49:21 2022 +0200
@@ -422,7 +422,7 @@
 			SPI_synchronize_with_Master();
 			MX_DMA_Init();
 			MX_SPI1_Init();
-			MX_USART1_UART_Init();
+			externalInterface_SwitchUART(externalInterface_GetUARTProtocol());
 			SPI_Start_single_TxRx_with_Master(); /* be prepared for the first data exchange */
 			Scheduler_Request_sync_with_SPI(SPI_SYNC_METHOD_HARD);
 			EXTI_Test_Button_Init();
--- a/Small_CPU/Src/externalInterface.c	Fri Oct 28 20:32:24 2022 +0200
+++ b/Small_CPU/Src/externalInterface.c	Fri Oct 28 20:49:21 2022 +0200
@@ -57,6 +57,7 @@
 float externalChannel_mV[MAX_ADC_CHANNEL];
 static uint8_t  externalV33_On = 0;
 static uint8_t  externalADC_On = 0;
+static uint8_t  externalUART_Protocol = 0;
 static uint16_t externalCO2Value;
 static uint16_t externalCO2SignalStrength;
 static uint16_t  externalCO2Status = 0;
@@ -111,7 +112,14 @@
 				activeChannel++;
 				if(activeChannel == MAX_ADC_CHANNEL)
 				{
-					activeChannel = 0;
+					if(externalUART_Protocol == (EXT_INTERFACE_UART_O2 >> 8))		/* mixed mode digital and analog o2 sensors => channel 0 is reserved for digital sensor */
+					{
+						activeChannel = 1;
+					}
+					else
+					{
+						activeChannel = 0;
+					}
 				}
 				externalInterface_StartConversion(activeChannel);
 				timeoutCnt = 0;
@@ -218,6 +226,11 @@
 	return externalADC_On;
 }
 
+uint8_t externalInterface_GetUARTProtocol()
+{
+	return externalUART_Protocol;
+}
+
 void externalInterface_SwitchPower33(uint8_t state)
 {
 	if(state != externalV33_On)
@@ -226,7 +239,6 @@
 		{
 			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
 			externalV33_On = 1;
-			MX_USART1_UART_Init();
 		}
 		else
 		{
@@ -234,7 +246,6 @@
 			externalV33_On = 0;
 			externalInterface_SetCO2Value(0);
 			externalInterface_SetCO2SignalStrength(0);
-			MX_USART1_UART_DeInit();
 		}
 	}
 }
@@ -251,6 +262,19 @@
 	}
 }
 
+void externalInterface_SwitchUART(uint8_t protocol)
+{
+	if(protocol < 0x08)
+	{
+		externalUART_Protocol = protocol;
+		MX_USART1_UART_DeInit();
+		if( protocol != 0)
+		{
+			MX_USART1_UART_Init();
+		}
+	}
+}
+
 void externalInterface_SetCO2Value(uint16_t CO2_ppm)
 {
 	externalCO2Value = CO2_ppm;
--- a/Small_CPU/Src/scheduler.c	Fri Oct 28 20:32:24 2022 +0200
+++ b/Small_CPU/Src/scheduler.c	Fri Oct 28 20:49:21 2022 +0200
@@ -318,6 +318,10 @@
 		externalInterface_SwitchADC(global.dataSendToSlave.data.externalInterface_Cmd && EXT_INTERFACE_ADC_ON);
 	}
 
+	if(((global.dataSendToSlave.data.externalInterface_Cmd >> 8) & 0x0F) != externalInterface_GetUARTProtocol())
+	{
+		externalInterface_SwitchUART((global.dataSendToSlave.data.externalInterface_Cmd >> 8) & 0x0F);
+	}
 
 	if(global.dataSendToSlave.data.externalInterface_Cmd & 0x00FF)	/* lowest nibble for commands */
 	{
@@ -523,7 +527,10 @@
 			HandleUARTSentinelData();
 		}
 #endif
-
+		if(global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_UART_O2)
+		{
+			HandleUARTDigitalO2();
+		}
 
 		if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
 		{
@@ -843,6 +850,11 @@
 		}
 #endif
 
+		if(global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_UART_O2)
+		{
+			HandleUARTDigitalO2();
+		}
+
 		/* Evaluate received data at 10 ms, 110 ms, 210 ms,... duration ~<1ms */
 		if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
 		{
--- a/Small_CPU/Src/uart.c	Fri Oct 28 20:32:24 2022 +0200
+++ b/Small_CPU/Src/uart.c	Fri Oct 28 20:49:21 2022 +0200
@@ -22,6 +22,7 @@
 #include "uart.h"
 #include "externalInterface.h"
 #include "data_exchange.h"
+#include <string.h>	/* memset */
 
 /* Private variables ---------------------------------------------------------*/
 
@@ -37,6 +38,13 @@
 static uint8_t lastCmdIndex;					/* Index of last command which has not been completly received */
 static uint8_t dmaActive;						/* Indicator if DMA receiption needs to be started */
 
+char tmpRxBuf[30];
+uint8_t tmpRxIdx = 0;
+
+static uartO2Status_t Comstatus_O2 = UART_O2_INIT;
+
+static uint32_t DigitalO2ID = 0;
+
 float LED_Level = 0.0;							/* Normalized LED value which may be used as indication for the health status of the sensor */
 float LED_ZeroOffset = 0.0;
 float pCO2 = 0.0;
@@ -47,7 +55,16 @@
 /* regular init */	
 
   huart1.Instance = USART1;
-  huart1.Init.BaudRate = 9600;
+
+  if(externalInterface_GetUARTProtocol() == 0x04)
+  {
+	  huart1.Init.BaudRate = 19200;
+	  Comstatus_O2 = UART_O2_INIT;
+  }
+  else
+  {
+	  huart1.Init.BaudRate = 9600;
+  }
   huart1.Init.WordLength = UART_WORDLENGTH_8B;
   huart1.Init.StopBits = UART_STOPBITS_1;
   huart1.Init.Parity = UART_PARITY_NONE;
@@ -57,14 +74,18 @@
 
   HAL_UART_Init(&huart1);
 
+  MX_USART1_DMA_Init();
+
   rxReadIndex = 0;
   lastCmdIndex = 0;
   rxWriteIndex = 0;
   dmaActive = 0;
+  Comstatus_O2 = UART_O2_INIT;
 }
 
 void MX_USART1_UART_DeInit(void)
 {
+	HAL_DMA_Abort(&hdma_usart1_rx);
 	HAL_DMA_DeInit(&hdma_usart1_rx);
 	HAL_UART_DeInit(&huart1);
 }
@@ -356,6 +377,228 @@
 }
 #endif
 
+void DigitalO2_SetupCmd(uint8_t O2State, uint8_t *cmdString, uint8_t *cmdLength)
+{
+	switch (O2State)
+	{
+		case UART_O2_CHECK:		*cmdLength = snprintf((char*)cmdString, 10, "#LOGO");
+			break;
+		case UART_O2_REQ_INFO: 	*cmdLength = snprintf((char*)cmdString, 10, "#VERS");
+					break;
+		case UART_O2_REQ_ID: 	*cmdLength = snprintf((char*)cmdString, 10, "#IDNR");
+			break;
+		case UART_O2_REQ_O2: 	*cmdLength = snprintf((char*)cmdString, 10, "#DOXY");
+			break;
+
+		default: *cmdLength = 0;
+			break;
+	}
+	if(*cmdLength != 0)
+	{
+		cmdString[*cmdLength] = 0x0D;
+		*cmdLength = *cmdLength + 1;
+	}
+}
+
+void StringToInt(char *pstr, uint32_t *pInt)
+{
+	uint8_t index = 0;
+	uint32_t result = 0;
+	while((pstr[index] >= '0') && (pstr[index] <= '9'))
+	{
+		result *=10;
+		result += pstr[index] - '0';
+		index++;
+	}
+	*pInt = result;
+}
+
+void HandleUARTDigitalO2(void)
+{
+	static uint32_t lastO2ReqTick = 0;
+
+	static uartO2RxState_t rxState = O2RX_IDLE;
+	static uint32_t lastReceiveTick = 0;
+	static uint8_t lastAlive = 0;
+	static uint8_t curAlive = 0;
+
+	static uint8_t cmdLength = 0;
+	static uint8_t cmdString[10];
+	static uint8_t cmdReadIndex = 0;
+
+	uint32_t tmpO2 = 0;
+	uint32_t tmpData = 0;
+	uint8_t localRX = rxReadIndex;
+	uint32_t tick =  HAL_GetTick();
+
+
+	if(Comstatus_O2 == UART_O2_INIT)
+	{
+		memset((char*)&rxBuffer[rxWriteIndex],(int)0,CHUNK_SIZE);
+		lastAlive = 0;
+		curAlive = 0;
+
+		Comstatus_O2 = UART_O2_CHECK;
+		DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength);
+		HAL_UART_Transmit(&huart1,cmdString,cmdLength,10);
+
+		rxState = O2RX_CONFIRM;
+		cmdReadIndex = 0;
+		lastO2ReqTick = tick;
+
+		if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE))
+		{
+			dmaActive = 1;
+		}
+	}
+	if(time_elapsed_ms(lastO2ReqTick,tick) > 1000)		/* repeat request once per second */
+	{
+		lastO2ReqTick = tick;
+		if(Comstatus_O2 == UART_O2_IDLE)				/* cyclic request of o2 value */
+		{
+			Comstatus_O2 = UART_O2_REQ_O2;
+			rxState = O2RX_CONFIRM;
+		}
+		DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength);
+
+		HAL_UART_Transmit(&huart1,cmdString,cmdLength,10);
+	}
+
+	while((rxBuffer[localRX]!=0))
+	{
+
+		lastReceiveTick = tick;
+		switch(rxState)
+		{
+			case O2RX_CONFIRM:	if(rxBuffer[localRX] == '#')
+								{
+									cmdReadIndex = 0;
+								}
+								if(rxBuffer[localRX] == cmdString[cmdReadIndex])
+							    {
+								cmdReadIndex++;
+								if(cmdReadIndex == cmdLength - 1)
+								{
+									tmpRxIdx = 0;
+									memset((char*) tmpRxBuf, 0, sizeof(tmpRxBuf));
+									switch (Comstatus_O2)
+									{
+											case UART_O2_CHECK:	Comstatus_O2 = UART_O2_REQ_INFO;
+																DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength);
+																HAL_UART_Transmit(&huart1,cmdString,cmdLength,10);
+												break;
+											case UART_O2_REQ_ID: rxState = O2RX_GETNR;
+												break;
+											case UART_O2_REQ_INFO: rxState = O2RX_GETTYPE;
+												break;
+											case UART_O2_REQ_O2:	rxState = O2RX_GETO2;
+												break;
+											default:	Comstatus_O2 = UART_O2_IDLE;
+														rxState = O2RX_IDLE;
+													break;
+									}
+								}
+						  	}
+				break;
+
+			case O2RX_GETSTATUS:
+			case O2RX_GETTEMP:
+			case O2RX_GETTYPE:
+			case O2RX_GETVERSION:
+			case O2RX_GETCHANNEL:
+			case O2RX_GETSUBSENSORS:
+			case O2RX_GETO2:
+			case O2RX_GETNR:	if(rxBuffer[localRX] != 0x0D)
+								{
+									if(rxBuffer[localRX] != ' ')
+									{
+										tmpRxBuf[tmpRxIdx++] = rxBuffer[localRX];
+									}
+									else
+									{
+										if(tmpRxIdx != 0)
+										{
+											switch(rxState)
+											{
+												case O2RX_GETCHANNEL:	StringToInt(tmpRxBuf,&tmpData);
+																		rxState = O2RX_GETVERSION;
+														break;
+												case O2RX_GETVERSION:	StringToInt(tmpRxBuf,&tmpData);
+																		rxState = O2RX_GETSUBSENSORS;
+														break;
+												case O2RX_GETTYPE: 		StringToInt(tmpRxBuf,&tmpData);
+																		rxState = O2RX_GETCHANNEL;
+														break;
+
+												case O2RX_GETO2: 		StringToInt(tmpRxBuf,&tmpO2);
+																		setExternalInterfaceChannel(0,(float)(tmpO2 / 10000.0));
+																		rxState = O2RX_GETTEMP;
+													break;
+												case O2RX_GETTEMP:		rxState = O2RX_GETSTATUS;
+													break;
+												default:
+													break;
+											}
+											memset((char*) tmpRxBuf, 0, tmpRxIdx);
+											tmpRxIdx = 0;
+										}
+									}
+								}
+								else
+								{
+									switch (rxState)
+									{
+										case O2RX_GETSTATUS:		StringToInt(tmpRxBuf,&tmpData);
+																	Comstatus_O2 = UART_O2_IDLE;
+																	rxState = O2RX_IDLE;
+												break;
+										case O2RX_GETSUBSENSORS:	StringToInt(tmpRxBuf,&tmpData);
+																	Comstatus_O2 = UART_O2_IDLE;
+																	rxState = O2RX_IDLE;
+												break;
+										case  O2RX_GETNR: 			StringToInt((char*)rxBuffer,&DigitalO2ID);
+											/* no break */
+										default:		Comstatus_O2 = UART_O2_IDLE;
+														rxState = O2RX_IDLE;
+											break;
+									}
+								}
+					break;
+			default:				rxState = O2RX_IDLE;
+				break;
+
+		}
+
+		localRX++;
+		rxReadIndex++;
+		if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER)
+		{
+			localRX = 0;
+			rxReadIndex = 0;
+		}
+	}
+
+	if(time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 4000)	/* check for communication timeout */
+	{
+		if(curAlive == lastAlive)
+		{
+			setExternalInterfaceChannel(0,0.0);
+			setExternalInterfaceChannel(1,0.0);
+			setExternalInterfaceChannel(2,0.0);
+		}
+		lastAlive = curAlive;
+	}
+
+	if((dmaActive == 0)	&& (externalInterface_isEnabledPower33()))	/* Should never happen in normal operation => restart in case of communication error */
+	{
+		if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE))
+		{
+			dmaActive = 1;
+		}
+	}
+}
+
+
 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
 {
     if(huart == &huart1)
@@ -370,6 +613,7 @@
     	{
     		if(externalInterface_isEnabledPower33())
     		{
+    			memset((char*)&rxBuffer[rxWriteIndex],(int)0,CHUNK_SIZE);
 				if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE))
 				{
 					dmaActive = 1;