Mercurial > public > ostc4
view Small_CPU/Src/uart.c @ 780:e40790a67165
Discovery<=>SmallCPU inferface update:
The sensor data struct is extended to store the data of up to three (three visible O2 sensors). To avoid unnecessary payload on the SPI only the last update sensor data item is transfered. The sender receiver uses the sensor ID which is provided in parallel to identify the correct storage location.
author | Ideenmodellierer |
---|---|
date | Tue, 23 May 2023 21:50:19 +0200 |
parents | 0b5f45448eb6 |
children | 01b3eb9d55c3 |
line wrap: on
line source
/** ****************************************************************************** * @file uart.c * @author heinrichs weikamp gmbh * @version V0.0.1 * @date 27-March-2014 * @brief button control * @verbatim ============================================================================== ##### How to use ##### ============================================================================== @endverbatim ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2> * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "uart.h" #include "externalInterface.h" #include "data_exchange.h" #include <string.h> /* memset */ /* Private variables ---------------------------------------------------------*/ #define CHUNK_SIZE (25u) /* the DMA will handle chunk size transfers */ #define CHUNKS_PER_BUFFER (5u) #define COMMAND_TX_DELAY (30u) /* The time the sensor needs to recover from a invalid command request */ UART_HandleTypeDef huart1; DMA_HandleTypeDef hdma_usart1_rx; uint8_t rxBuffer[CHUNK_SIZE * CHUNKS_PER_BUFFER]; /* The complete buffer has a X * chunk size to allow fariations in buffer read time */ static uint8_t rxWriteIndex; /* Index of the data item which is analysed */ static uint8_t rxReadIndex; /* Index at which new data is stared */ static uint8_t lastCmdIndex; /* Index of last command which has not been completly received */ static uint8_t dmaActive; /* Indicator if DMA reception needs to be started */ static uint8_t digO2Connected = 0; /* Binary indicator if a sensor is connected or not */ static uint8_t CO2Connected = 0; /* Binary indicator if a sensor is connected or not */ static uint8_t SentinelConnected = 0; /* Binary indicator if a sensor is connected or not */ static uint8_t ppO2TargetChannel = 0; /* The OSTC4 supports three slots for visualization of the ppo2. This one is reserved for the digital sensor */ static SSensorDataDiveO2 tmpSensorDataDiveO2; /* intermediate storage for additional sensor data */ char tmpRxBuf[30]; uint8_t tmpRxIdx = 0; static uartO2Status_t Comstatus_O2 = UART_O2_INIT; static uint8_t activeSensor = 0; static uint8_t sensorMapping[MAX_ADC_CHANNEL]; /* The mapping is used to assign the visible sensor channel to the mux address (DiveO2) */ 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; /* Exported functions --------------------------------------------------------*/ void MX_USART1_UART_Init(void) { /* regular init */ huart1.Instance = USART1; 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; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1); MX_USART1_DMA_Init(); memset(rxBuffer,0,sizeof(rxBuffer)); rxReadIndex = 0; lastCmdIndex = 0; rxWriteIndex = 0; dmaActive = 0; digO2Connected = 0; CO2Connected = 0; SentinelConnected = 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); } void MX_USART1_DMA_Init() { /* DMA controller clock enable */ __DMA2_CLK_ENABLE(); /* Peripheral DMA init*/ hdma_usart1_rx.Instance = DMA2_Stream5; hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4; hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; //DMA_MEMORY_TO_PERIPH; hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.Mode = DMA_NORMAL; hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(&hdma_usart1_rx); __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx); /* DMA interrupt init */ HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn); } void DigitalO2_SelectSensor(uint8_t channel) { uint8_t indexstr[4]; uint8_t muxAddress = 0; indexstr[0] = '~'; indexstr[1] = '1'; indexstr[2] = 0x0D; indexstr[3] = 0x0A; if((channel < MAX_ADC_CHANNEL) && (sensorMapping[channel] != 0xff)) { muxAddress = sensorMapping[channel]; } else { muxAddress = MAX_ADC_CHANNEL; /* default to mux */ } indexstr[1] = '0' + muxAddress; HAL_UART_Transmit(&huart1,indexstr,4,10); } 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; case UART_O2_REQ_RAW: *cmdLength = snprintf((char*)cmdString, 10, "#DRAW"); break; default: *cmdLength = 0; break; } if(*cmdLength != 0) { cmdString[*cmdLength] = 0x0D; *cmdLength = *cmdLength + 1; } } void StringToInt(char *pstr, uint32_t *puInt32) { uint8_t index = 0; uint32_t result = 0; while((pstr[index] >= '0') && (pstr[index] <= '9')) { result *=10; result += pstr[index] - '0'; index++; } *puInt32 = result; } void StringToUInt64(char *pstr, uint64_t *puint64) { uint8_t index = 0; uint64_t result = 0; while((pstr[index] >= '0') && (pstr[index] <= '9')) { result *=10; result += pstr[index] - '0'; index++; } *puint64 = result; } void ConvertByteToHexString(uint8_t byte, char* str) { uint8_t worker = 0; uint8_t digit = 0; uint8_t digitCnt = 1; worker = byte; while((worker!=0) && (digitCnt != 255)) { digit = worker % 16; if( digit < 10) { digit += '0'; } else { digit += 'A' - 10; } str[digitCnt--]= digit; worker = worker / 16; } } void UART_StartDMA_Receiption() { if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE)) { dmaActive = 1; } } #ifdef ENABLE_CO2_SUPPORT void UART_HandleCO2Data(void) { uint8_t localRX = rxReadIndex; static uint8_t dataType = 0; static uint32_t dataValue = 0; static receiveState_t rxState = RX_Ready; static uint32_t lastReceiveTick = 0; while((rxBuffer[localRX]!=0)) { lastReceiveTick = HAL_GetTick(); if(rxState == RX_Ready) /* identify data content */ { switch(rxBuffer[localRX]) { case 'l': case 'D': case 'Z': dataType = rxBuffer[localRX]; rxState = RX_Data0; dataValue = 0; break; default: /* unknown or corrupted => ignore */ break; } } else if((rxBuffer[localRX] >= '0') && (rxBuffer[localRX] <= '9')) { if((rxState >= RX_Data0) && (rxState <= RX_Data4)) { dataValue = dataValue * 10 + (rxBuffer[localRX] - '0'); rxState++; if(rxState == RX_Data5) { rxState = RX_DataComplete; CO2Connected = 1; } } else /* protocol error data has max 5 digits */ { rxState = RX_Ready; } } if((rxBuffer[localRX] == ' ') || (rxBuffer[localRX] == '\n')) /* Abort data detection */ { if(rxState == RX_DataComplete) { if(externalInterface_GetCO2State() == 0) { externalInterface_SetCO2State(EXT_INTERFACE_33V_ON); } switch(dataType) { case 'D': externalInterface_SetCO2SignalStrength(dataValue); break; case 'l': LED_ZeroOffset = dataValue; break; case 'Z': externalInterface_SetCO2Value(dataValue); break; default: rxState = RX_Ready; break; } } if(rxState != RX_Data0) /* reset state machine because message in wrong format */ { rxState = RX_Ready; } } rxBuffer[localRX] = 0; localRX++; rxReadIndex++; if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { localRX = 0; rxReadIndex = 0; } } if(time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 2000) /* check for communication timeout */ { externalInterface_SetCO2State(0); CO2Connected = 0; } if((dmaActive == 0) && (externalInterface_isEnabledPower33())) /* Should never happen in normal operation => restart in case of communication error */ { UART_StartDMA_Receiption(); } } #endif #ifdef ENABLE_SENTINEL_MODE void UART_HandleSentinelData(void) { uint8_t localRX = rxReadIndex; static uint8_t dataType = 0; static uint32_t dataValue[3]; static uint8_t dataValueIdx = 0; static receiveState_t rxState = RX_Ready; static uint32_t lastReceiveTick = 0; static uint8_t lastAlive = 0; static uint8_t curAlive = 0; static uint8_t checksum = 0; static char checksum_str[]="00"; while((rxBuffer[localRX]!=0)) { lastReceiveTick = HAL_GetTick(); switch(rxState) { case RX_Ready: if((rxBuffer[localRX] >= 'a') && (rxBuffer[localRX] <= 'z')) { rxState = RX_DetectStart; curAlive = rxBuffer[localRX]; checksum = 0; } break; case RX_DetectStart: checksum += rxBuffer[localRX]; if(rxBuffer[localRX] == '1') { rxState = RX_SelectData; dataType = 0xFF; } else { rxState = RX_Ready; } break; case RX_SelectData: checksum += rxBuffer[localRX]; switch(rxBuffer[localRX]) { case 'T': dataType = rxBuffer[localRX]; break; case '0': if(dataType != 0xff) { rxState = RX_Data0; dataValueIdx = 0; dataValue[0] = 0; } else { rxState = RX_Ready; } break; default: rxState = RX_Ready; } break; case RX_Data0: case RX_Data1: case RX_Data2: case RX_Data4: case RX_Data5: case RX_Data6: case RX_Data8: case RX_Data9: case RX_Data10: checksum += rxBuffer[localRX]; if((rxBuffer[localRX] >= '0') && (rxBuffer[localRX] <= '9')) { dataValue[dataValueIdx] = dataValue[dataValueIdx] * 10 + (rxBuffer[localRX] - '0'); rxState++; } else { rxState = RX_Ready; } break; case RX_Data3: case RX_Data7: checksum += rxBuffer[localRX]; if(rxBuffer[localRX] == '0') { rxState++; dataValueIdx++; dataValue[dataValueIdx] = 0; } else { rxState = RX_Ready; } break; case RX_Data11: rxState = RX_DataComplete; ConvertByteToHexString(checksum,checksum_str); if(rxBuffer[localRX] == checksum_str[0]) { rxState = RX_DataComplete; } else { rxState = RX_Ready; } break; case RX_DataComplete: if(rxBuffer[localRX] == checksum_str[1]) { setExternalInterfaceChannel(0,(float)(dataValue[0] / 10.0)); setExternalInterfaceChannel(1,(float)(dataValue[1] / 10.0)); setExternalInterfaceChannel(2,(float)(dataValue[2] / 10.0)); SentinelConnected = 1; } rxState = RX_Ready; break; default: rxState = RX_Ready; 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); SentinelConnected = 0; } lastAlive = curAlive; } if((dmaActive == 0) && (externalInterface_isEnabledPower33())) /* Should never happen in normal operation => restart in case of communication error */ { UART_StartDMA_Receiption(); } } #endif void UART_HandleDigitalO2(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; static uint32_t tickToTX = 0; static uint32_t delayStartTick = 0; uint8_t switchChannel = 0; uint8_t index = 0; uint32_t tmpO2 = 0; uint32_t tmpData = 0; uint8_t localRX = rxReadIndex; uint32_t tick = HAL_GetTick(); uint8_t *pmap = externalInterface_GetSensorMapPointer(0); /* The channel switch will cause the sensor to respond with an error message. */ /* The sensor needs ~30ms to recover before he is ready to receive the next command => transmission delay needed */ if((tickToTX) && (time_elapsed_ms(delayStartTick,tick) >= tickToTX )) { HAL_UART_Transmit(&huart1,cmdString,cmdLength,10); tickToTX = 0; } else { if(Comstatus_O2 == UART_O2_INIT) { memset((char*)&rxBuffer[rxWriteIndex],(int)0,CHUNK_SIZE); memset((char*) &tmpSensorDataDiveO2, 0, sizeof(tmpSensorDataDiveO2)); externalInterface_SetSensorData(0,(uint8_t*)&tmpSensorDataDiveO2); lastAlive = 0; curAlive = 0; Comstatus_O2 = UART_O2_CHECK; DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength); DigitalO2_SelectSensor(activeSensor); if(activeSensor < MAX_ADC_CHANNEL) { externalInterface_GetSensorData(activeSensor + 1, (uint8_t*)&tmpSensorDataDiveO2); } delayStartTick = tick; tickToTX = COMMAND_TX_DELAY; rxState = O2RX_CONFIRM; cmdReadIndex = 0; lastO2ReqTick = tick; UART_StartDMA_Receiption(); } if(time_elapsed_ms(lastO2ReqTick,tick) > 1000) /* repeat request once per second */ { lastO2ReqTick = tick; index = activeSensor; if(Comstatus_O2 == UART_O2_IDLE) /* cyclic request of o2 value */ { if(pmap[EXT_INTERFACE_SENSOR_CNT-1] == SENSOR_MUX) /* select next sensor if mux is connected */ { if(activeSensor < MAX_ADC_CHANNEL) { do { index++; if(index == MAX_ADC_CHANNEL) { index = 0; } if(pmap[index] == SENSOR_DIGO2) { activeSensor = index; switchChannel = 1; break; } } while(index != activeSensor); } } Comstatus_O2 = UART_O2_REQ_RAW; rxState = O2RX_CONFIRM; } if(switchChannel) { delayStartTick = tick; DigitalO2_SelectSensor(activeSensor); externalInterface_GetSensorData(activeSensor + 1, (uint8_t*)&tmpSensorDataDiveO2); tickToTX = COMMAND_TX_DELAY; if(tmpSensorDataDiveO2.sensorId == 0) { Comstatus_O2 = UART_O2_REQ_ID; } } else { HAL_UART_Transmit(&huart1,cmdString,cmdLength,10); } DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength); } 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) { digO2Connected = 1; tmpRxIdx = 0; memset((char*) tmpRxBuf, 0, sizeof(tmpRxBuf)); switch (Comstatus_O2) { case UART_O2_CHECK: Comstatus_O2 = UART_O2_IDLE; break; case UART_O2_REQ_ID: rxState = O2RX_GETNR; break; case UART_O2_REQ_INFO: rxState = O2RX_GETTYPE; break; case UART_O2_REQ_RAW: 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: case O2RX_GETDPHI: case O2RX_INTENSITY: case O2RX_AMBIENTLIGHT: case O2RX_PRESSURE: case O2RX_HUMIDITY: if(rxBuffer[localRX] != 0x0D) { if(rxBuffer[localRX] != ' ') /* the following data entities are placed within the data stream => no need to store data at the end */ { 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(activeSensor,(float)(tmpO2 / 10000.0)); rxState = O2RX_GETTEMP; break; case O2RX_GETTEMP: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.temperature); rxState = O2RX_GETSTATUS; break; case O2RX_GETSTATUS: StringToInt(tmpRxBuf,&tmpSensorDataDiveO2.status); /* raw data cycle */ rxState = O2RX_GETDPHI; break; case O2RX_GETDPHI: /* ignored to save memory and most likly irrelevant for diver */ rxState = O2RX_INTENSITY; break; case O2RX_INTENSITY: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.intensity); /* raw data cycle */ rxState = O2RX_AMBIENTLIGHT; break; case O2RX_AMBIENTLIGHT: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.ambient); /* raw data cycle */ rxState = O2RX_PRESSURE; break; case O2RX_PRESSURE: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.pressure); /* raw data cycle */ rxState = O2RX_HUMIDITY; break; default: break; } memset((char*) tmpRxBuf, 0, tmpRxIdx); tmpRxIdx = 0; } } } else { /* the following data items are the last of a sensor respond => store temporal data */ switch (rxState) { case O2RX_GETSTATUS: StringToInt(tmpRxBuf,&tmpSensorDataDiveO2.status); externalInterface_SetSensorData(activeSensor+1,(uint8_t*)&tmpSensorDataDiveO2); 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_HUMIDITY: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.humidity); /* raw data cycle */ externalInterface_SetSensorData(activeSensor+1,(uint8_t*)&tmpSensorDataDiveO2); Comstatus_O2 = UART_O2_IDLE; rxState = O2RX_IDLE; break; case O2RX_GETNR: StringToUInt64((char*)tmpRxBuf,&tmpSensorDataDiveO2.sensorId); externalInterface_SetSensorData(activeSensor+1,(uint8_t*)&tmpSensorDataDiveO2); index = activeSensor; if(switchChannel == 0) { Comstatus_O2 = UART_O2_IDLE; rxState = O2RX_IDLE; } break; default: Comstatus_O2 = UART_O2_IDLE; rxState = O2RX_IDLE; break; } } break; default: rxState = O2RX_IDLE; break; } rxBuffer[localRX] = 0; localRX++; rxReadIndex++; if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { localRX = 0; rxReadIndex = 0; } } if((digO2Connected) && time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 4000) /* check for communication timeout */ { digO2Connected = 0; if(curAlive == lastAlive) { setExternalInterfaceChannel(ppO2TargetChannel,0.0); } lastAlive = curAlive; } if((dmaActive == 0) && (externalInterface_isEnabledPower33())) /* Should never happen in normal operation => restart in case of communication error */ { UART_StartDMA_Receiption(); } } } void UART_SetDigO2_Channel(uint8_t channel) { if(channel <= MAX_ADC_CHANNEL) { activeSensor = channel; } } void UART_MapDigO2_Channel(uint8_t channel, uint8_t muxAddress) { if((channel < MAX_ADC_CHANNEL) && (muxAddress < MAX_ADC_CHANNEL)) { sensorMapping[channel] = muxAddress; } } uint8_t UART_isDigO2Connected() { return digO2Connected; } uint8_t UART_isCO2Connected() { return CO2Connected; } uint8_t UART_isSentinelConnected() { return SentinelConnected; } void UART_setTargetChannel(uint8_t channel) { ppO2TargetChannel = channel; } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart == &huart1) { dmaActive = 0; rxWriteIndex+=CHUNK_SIZE; if(rxWriteIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { rxWriteIndex = 0; } if((rxWriteIndex / CHUNK_SIZE) != (rxReadIndex / CHUNK_SIZE)) /* start next transfer if we did not catch up with read index */ { if(externalInterface_isEnabledPower33()) { memset((char*)&rxBuffer[rxWriteIndex],(int)0,CHUNK_SIZE); UART_StartDMA_Receiption(); } } } } /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/