comparison Small_CPU/Src/uart.c @ 779:0b5f45448eb6

Added UART multiplexer support for DiveO2: The existing autodetect function now includes a UART multiplexer. The datastructures and protocol handling has been adapted to support several DiveO2 sensors connected to the UART.
author Ideenmodellierer
date Tue, 23 May 2023 21:45:34 +0200
parents df0d43da1614
children 01b3eb9d55c3
comparison
equal deleted inserted replaced
778:74253a41cf80 779:0b5f45448eb6
26 26
27 /* Private variables ---------------------------------------------------------*/ 27 /* Private variables ---------------------------------------------------------*/
28 28
29 #define CHUNK_SIZE (25u) /* the DMA will handle chunk size transfers */ 29 #define CHUNK_SIZE (25u) /* the DMA will handle chunk size transfers */
30 #define CHUNKS_PER_BUFFER (5u) 30 #define CHUNKS_PER_BUFFER (5u)
31 #define COMMAND_TX_DELAY (30u) /* The time the sensor needs to recover from a invalid command request */
31 UART_HandleTypeDef huart1; 32 UART_HandleTypeDef huart1;
32 33
33 DMA_HandleTypeDef hdma_usart1_rx; 34 DMA_HandleTypeDef hdma_usart1_rx;
34 35
35 uint8_t rxBuffer[CHUNK_SIZE * CHUNKS_PER_BUFFER]; /* The complete buffer has a X * chunk size to allow fariations in buffer read time */ 36 uint8_t rxBuffer[CHUNK_SIZE * CHUNKS_PER_BUFFER]; /* The complete buffer has a X * chunk size to allow fariations in buffer read time */
40 static uint8_t digO2Connected = 0; /* Binary indicator if a sensor is connected or not */ 41 static uint8_t digO2Connected = 0; /* Binary indicator if a sensor is connected or not */
41 static uint8_t CO2Connected = 0; /* Binary indicator if a sensor is connected or not */ 42 static uint8_t CO2Connected = 0; /* Binary indicator if a sensor is connected or not */
42 static uint8_t SentinelConnected = 0; /* Binary indicator if a sensor is connected or not */ 43 static uint8_t SentinelConnected = 0; /* Binary indicator if a sensor is connected or not */
43 static uint8_t ppO2TargetChannel = 0; /* The OSTC4 supports three slots for visualization of the ppo2. This one is reserved for the digital sensor */ 44 static uint8_t ppO2TargetChannel = 0; /* The OSTC4 supports three slots for visualization of the ppo2. This one is reserved for the digital sensor */
44 45
45 static SSensorDataDiveO2 sensorDataDiveO2; /* intermediate storage for additional sensor data */ 46 static SSensorDataDiveO2 tmpSensorDataDiveO2; /* intermediate storage for additional sensor data */
46 47
47 char tmpRxBuf[30]; 48 char tmpRxBuf[30];
48 uint8_t tmpRxIdx = 0; 49 uint8_t tmpRxIdx = 0;
49 50
50 static uartO2Status_t Comstatus_O2 = UART_O2_INIT; 51 static uartO2Status_t Comstatus_O2 = UART_O2_INIT;
52 static uint8_t activeSensor = 0;
53 static uint8_t sensorMapping[MAX_ADC_CHANNEL]; /* The mapping is used to assign the visible sensor channel to the mux address (DiveO2) */
51 54
52 float LED_Level = 0.0; /* Normalized LED value which may be used as indication for the health status of the sensor */ 55 float LED_Level = 0.0; /* Normalized LED value which may be used as indication for the health status of the sensor */
53 float LED_ZeroOffset = 0.0; 56 float LED_ZeroOffset = 0.0;
54 float pCO2 = 0.0; 57 float pCO2 = 0.0;
55 /* Exported functions --------------------------------------------------------*/ 58 /* Exported functions --------------------------------------------------------*/
121 /* DMA interrupt init */ 124 /* DMA interrupt init */
122 HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0); 125 HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
123 HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn); 126 HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
124 } 127 }
125 128
129
130 void DigitalO2_SelectSensor(uint8_t channel)
131 {
132 uint8_t indexstr[4];
133 uint8_t muxAddress = 0;
134 indexstr[0] = '~';
135 indexstr[1] = '1';
136 indexstr[2] = 0x0D;
137 indexstr[3] = 0x0A;
138
139 if((channel < MAX_ADC_CHANNEL) && (sensorMapping[channel] != 0xff))
140 {
141 muxAddress = sensorMapping[channel];
142 }
143 else
144 {
145 muxAddress = MAX_ADC_CHANNEL; /* default to mux */
146 }
147 indexstr[1] = '0' + muxAddress;
148 HAL_UART_Transmit(&huart1,indexstr,4,10);
149 }
126 150
127 void DigitalO2_SetupCmd(uint8_t O2State, uint8_t *cmdString, uint8_t *cmdLength) 151 void DigitalO2_SetupCmd(uint8_t O2State, uint8_t *cmdString, uint8_t *cmdLength)
128 { 152 {
129 switch (O2State) 153 switch (O2State)
130 { 154 {
461 static uint8_t curAlive = 0; 485 static uint8_t curAlive = 0;
462 486
463 static uint8_t cmdLength = 0; 487 static uint8_t cmdLength = 0;
464 static uint8_t cmdString[10]; 488 static uint8_t cmdString[10];
465 static uint8_t cmdReadIndex = 0; 489 static uint8_t cmdReadIndex = 0;
466 490 static uint32_t tickToTX = 0;
491 static uint32_t delayStartTick = 0;
492
493 uint8_t switchChannel = 0;
494 uint8_t index = 0;
467 uint32_t tmpO2 = 0; 495 uint32_t tmpO2 = 0;
468 uint32_t tmpData = 0; 496 uint32_t tmpData = 0;
469 uint8_t localRX = rxReadIndex; 497 uint8_t localRX = rxReadIndex;
470 uint32_t tick = HAL_GetTick(); 498 uint32_t tick = HAL_GetTick();
471 499
472 500 uint8_t *pmap = externalInterface_GetSensorMapPointer(0);
473 if(Comstatus_O2 == UART_O2_INIT) 501
474 { 502 /* The channel switch will cause the sensor to respond with an error message. */
475 memset((char*)&rxBuffer[rxWriteIndex],(int)0,CHUNK_SIZE); 503 /* The sensor needs ~30ms to recover before he is ready to receive the next command => transmission delay needed */
476 memset((char*) &sensorDataDiveO2, 0, sizeof(sensorDataDiveO2)); 504 if((tickToTX) && (time_elapsed_ms(delayStartTick,tick) >= tickToTX ))
477 externalInterface_SetSensorData(0,(uint8_t*)&sensorDataDiveO2); 505 {
478
479 lastAlive = 0;
480 curAlive = 0;
481
482 Comstatus_O2 = UART_O2_CHECK;
483 DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength);
484 HAL_UART_Transmit(&huart1,cmdString,cmdLength,10); 506 HAL_UART_Transmit(&huart1,cmdString,cmdLength,10);
485 507 tickToTX = 0;
486 rxState = O2RX_CONFIRM; 508 }
487 cmdReadIndex = 0; 509 else
488 lastO2ReqTick = tick; 510 {
489 511 if(Comstatus_O2 == UART_O2_INIT)
490 UART_StartDMA_Receiption(); 512 {
491 } 513 memset((char*)&rxBuffer[rxWriteIndex],(int)0,CHUNK_SIZE);
492 if(time_elapsed_ms(lastO2ReqTick,tick) > 1000) /* repeat request once per second */ 514 memset((char*) &tmpSensorDataDiveO2, 0, sizeof(tmpSensorDataDiveO2));
493 { 515 externalInterface_SetSensorData(0,(uint8_t*)&tmpSensorDataDiveO2);
494 lastO2ReqTick = tick; 516
495 if(Comstatus_O2 == UART_O2_IDLE) /* cyclic request of o2 value */ 517 lastAlive = 0;
496 { 518 curAlive = 0;
497 Comstatus_O2 = UART_O2_REQ_RAW; 519
520 Comstatus_O2 = UART_O2_CHECK;
521 DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength);
522 DigitalO2_SelectSensor(activeSensor);
523 if(activeSensor < MAX_ADC_CHANNEL)
524 {
525 externalInterface_GetSensorData(activeSensor + 1, (uint8_t*)&tmpSensorDataDiveO2);
526 }
527 delayStartTick = tick;
528 tickToTX = COMMAND_TX_DELAY;
529
498 rxState = O2RX_CONFIRM; 530 rxState = O2RX_CONFIRM;
499 } 531 cmdReadIndex = 0;
500 DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength); 532 lastO2ReqTick = tick;
501 533
502 HAL_UART_Transmit(&huart1,cmdString,cmdLength,10); 534 UART_StartDMA_Receiption();
503 } 535 }
504 536 if(time_elapsed_ms(lastO2ReqTick,tick) > 1000) /* repeat request once per second */
505 while((rxBuffer[localRX]!=0)) 537 {
506 { 538 lastO2ReqTick = tick;
507 539 index = activeSensor;
508 lastReceiveTick = tick; 540 if(Comstatus_O2 == UART_O2_IDLE) /* cyclic request of o2 value */
509 switch(rxState) 541 {
510 { 542 if(pmap[EXT_INTERFACE_SENSOR_CNT-1] == SENSOR_MUX) /* select next sensor if mux is connected */
511 case O2RX_CONFIRM: if(rxBuffer[localRX] == '#') 543 {
512 { 544 if(activeSensor < MAX_ADC_CHANNEL)
513 cmdReadIndex = 0; 545 {
514 } 546 do
515 if(rxBuffer[localRX] == cmdString[cmdReadIndex]) 547 {
516 { 548 index++;
517 cmdReadIndex++; 549 if(index == MAX_ADC_CHANNEL)
518 if(cmdReadIndex == cmdLength - 1) 550 {
519 { 551 index = 0;
520 digO2Connected = 1; 552 }
521 tmpRxIdx = 0; 553 if(pmap[index] == SENSOR_DIGO2)
522 memset((char*) tmpRxBuf, 0, sizeof(tmpRxBuf)); 554 {
523 switch (Comstatus_O2) 555 activeSensor = index;
556 switchChannel = 1;
557 break;
558 }
559 } while(index != activeSensor);
560 }
561 }
562
563 Comstatus_O2 = UART_O2_REQ_RAW;
564 rxState = O2RX_CONFIRM;
565 }
566 if(switchChannel)
567 {
568 delayStartTick = tick;
569 DigitalO2_SelectSensor(activeSensor);
570 externalInterface_GetSensorData(activeSensor + 1, (uint8_t*)&tmpSensorDataDiveO2);
571 tickToTX = COMMAND_TX_DELAY;
572 if(tmpSensorDataDiveO2.sensorId == 0)
573 {
574 Comstatus_O2 = UART_O2_REQ_ID;
575 }
576 }
577 else
578 {
579 HAL_UART_Transmit(&huart1,cmdString,cmdLength,10);
580 }
581 DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength);
582 }
583
584 while((rxBuffer[localRX]!=0))
585 {
586 lastReceiveTick = tick;
587 switch(rxState)
588 {
589 case O2RX_CONFIRM: if(rxBuffer[localRX] == '#')
524 { 590 {
525 case UART_O2_CHECK: Comstatus_O2 = UART_O2_REQ_ID; 591 cmdReadIndex = 0;
526 rxState = O2RX_CONFIRM; 592 }
527 DigitalO2_SetupCmd(Comstatus_O2,cmdString,&cmdLength); 593 if(rxBuffer[localRX] == cmdString[cmdReadIndex])
528 HAL_UART_Transmit(&huart1,cmdString,cmdLength,10); 594 {
529 break; 595 cmdReadIndex++;
530 case UART_O2_REQ_ID: rxState = O2RX_GETNR; 596 if(cmdReadIndex == cmdLength - 1)
531 break; 597 {
532 case UART_O2_REQ_INFO: rxState = O2RX_GETTYPE; 598 digO2Connected = 1;
533 break; 599 tmpRxIdx = 0;
534 case UART_O2_REQ_RAW: 600 memset((char*) tmpRxBuf, 0, sizeof(tmpRxBuf));
535 case UART_O2_REQ_O2: rxState = O2RX_GETO2; 601 switch (Comstatus_O2)
536 break; 602 {
537 default: Comstatus_O2 = UART_O2_IDLE; 603 case UART_O2_CHECK: Comstatus_O2 = UART_O2_IDLE;
538 rxState = O2RX_IDLE;
539 break; 604 break;
540 } 605 case UART_O2_REQ_ID: rxState = O2RX_GETNR;
541 } 606 break;
542 } 607 case UART_O2_REQ_INFO: rxState = O2RX_GETTYPE;
543 break; 608 break;
544 609 case UART_O2_REQ_RAW:
545 case O2RX_GETSTATUS: 610 case UART_O2_REQ_O2: rxState = O2RX_GETO2;
546 case O2RX_GETTEMP: 611 break;
547 case O2RX_GETTYPE: 612 default: Comstatus_O2 = UART_O2_IDLE;
548 case O2RX_GETVERSION: 613 rxState = O2RX_IDLE;
549 case O2RX_GETCHANNEL:
550 case O2RX_GETSUBSENSORS:
551 case O2RX_GETO2:
552 case O2RX_GETNR:
553 case O2RX_GETDPHI:
554 case O2RX_INTENSITY:
555 case O2RX_AMBIENTLIGHT:
556 case O2RX_PRESSURE:
557 case O2RX_HUMIDITY:
558 if(rxBuffer[localRX] != 0x0D)
559 {
560 if(rxBuffer[localRX] != ' ')
561 {
562 tmpRxBuf[tmpRxIdx++] = rxBuffer[localRX];
563 }
564 else
565 {
566 if(tmpRxIdx != 0)
567 {
568 switch(rxState)
569 {
570 case O2RX_GETCHANNEL: StringToInt(tmpRxBuf,&tmpData);
571 rxState = O2RX_GETVERSION;
572 break; 614 break;
573 case O2RX_GETVERSION: StringToInt(tmpRxBuf,&tmpData);
574 rxState = O2RX_GETSUBSENSORS;
575 break;
576 case O2RX_GETTYPE: StringToInt(tmpRxBuf,&tmpData);
577 rxState = O2RX_GETCHANNEL;
578 break;
579
580 case O2RX_GETO2: StringToInt(tmpRxBuf,&tmpO2);
581 setExternalInterfaceChannel(ppO2TargetChannel,(float)(tmpO2 / 10000.0));
582 rxState = O2RX_GETTEMP;
583 break;
584 case O2RX_GETTEMP: StringToInt(tmpRxBuf,(uint32_t*)&sensorDataDiveO2.temperature);
585 rxState = O2RX_GETSTATUS;
586 break;
587 case O2RX_GETSTATUS: StringToInt(tmpRxBuf,&sensorDataDiveO2.status); /* raw data cycle */
588 rxState = O2RX_GETDPHI;
589 break;
590 case O2RX_GETDPHI: /* ignored to save memory and most likly irrelevant for diver */
591 rxState = O2RX_INTENSITY;
592 break;
593 case O2RX_INTENSITY: StringToInt(tmpRxBuf,(uint32_t*)&sensorDataDiveO2.intensity); /* raw data cycle */
594 rxState = O2RX_AMBIENTLIGHT;
595 break;
596 case O2RX_AMBIENTLIGHT: StringToInt(tmpRxBuf,(uint32_t*)&sensorDataDiveO2.ambient); /* raw data cycle */
597 rxState = O2RX_PRESSURE;
598 break;
599 case O2RX_PRESSURE: StringToInt(tmpRxBuf,(uint32_t*)&sensorDataDiveO2.pressure); /* raw data cycle */
600 rxState = O2RX_HUMIDITY;
601 break;
602 default:
603 break;
604 }
605 memset((char*) tmpRxBuf, 0, tmpRxIdx);
606 tmpRxIdx = 0;
607 } 615 }
608 } 616 }
609 } 617 }
610 else 618 break;
611 { 619
612 switch (rxState) 620 case O2RX_GETSTATUS:
621 case O2RX_GETTEMP:
622 case O2RX_GETTYPE:
623 case O2RX_GETVERSION:
624 case O2RX_GETCHANNEL:
625 case O2RX_GETSUBSENSORS:
626 case O2RX_GETO2:
627 case O2RX_GETNR:
628 case O2RX_GETDPHI:
629 case O2RX_INTENSITY:
630 case O2RX_AMBIENTLIGHT:
631 case O2RX_PRESSURE:
632 case O2RX_HUMIDITY:
633 if(rxBuffer[localRX] != 0x0D)
613 { 634 {
614 case O2RX_GETSTATUS: StringToInt(tmpRxBuf,&sensorDataDiveO2.status); 635 if(rxBuffer[localRX] != ' ') /* the following data entities are placed within the data stream => no need to store data at the end */
615 externalInterface_SetSensorData(1,(uint8_t*)&sensorDataDiveO2); 636 {
616 Comstatus_O2 = UART_O2_IDLE; 637 tmpRxBuf[tmpRxIdx++] = rxBuffer[localRX];
617 rxState = O2RX_IDLE; 638 }
639 else
640 {
641 if(tmpRxIdx != 0)
642 {
643 switch(rxState)
644 {
645 case O2RX_GETCHANNEL: StringToInt(tmpRxBuf,&tmpData);
646 rxState = O2RX_GETVERSION;
647 break;
648 case O2RX_GETVERSION: StringToInt(tmpRxBuf,&tmpData);
649 rxState = O2RX_GETSUBSENSORS;
650 break;
651 case O2RX_GETTYPE: StringToInt(tmpRxBuf,&tmpData);
652 rxState = O2RX_GETCHANNEL;
653 break;
654
655 case O2RX_GETO2: StringToInt(tmpRxBuf,&tmpO2);
656 setExternalInterfaceChannel(activeSensor,(float)(tmpO2 / 10000.0));
657 rxState = O2RX_GETTEMP;
658 break;
659 case O2RX_GETTEMP: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.temperature);
660 rxState = O2RX_GETSTATUS;
661 break;
662 case O2RX_GETSTATUS: StringToInt(tmpRxBuf,&tmpSensorDataDiveO2.status); /* raw data cycle */
663 rxState = O2RX_GETDPHI;
664 break;
665 case O2RX_GETDPHI: /* ignored to save memory and most likly irrelevant for diver */
666 rxState = O2RX_INTENSITY;
667 break;
668 case O2RX_INTENSITY: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.intensity); /* raw data cycle */
669 rxState = O2RX_AMBIENTLIGHT;
670 break;
671 case O2RX_AMBIENTLIGHT: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.ambient); /* raw data cycle */
672 rxState = O2RX_PRESSURE;
673 break;
674 case O2RX_PRESSURE: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.pressure); /* raw data cycle */
675 rxState = O2RX_HUMIDITY;
676 break;
677 default:
678 break;
679 }
680 memset((char*) tmpRxBuf, 0, tmpRxIdx);
681 tmpRxIdx = 0;
682 }
683 }
684 }
685 else
686 { /* the following data items are the last of a sensor respond => store temporal data */
687 switch (rxState)
688 {
689 case O2RX_GETSTATUS: StringToInt(tmpRxBuf,&tmpSensorDataDiveO2.status);
690 externalInterface_SetSensorData(activeSensor+1,(uint8_t*)&tmpSensorDataDiveO2);
691 Comstatus_O2 = UART_O2_IDLE;
692 rxState = O2RX_IDLE;
693 break;
694 case O2RX_GETSUBSENSORS: StringToInt(tmpRxBuf,&tmpData);
695 Comstatus_O2 = UART_O2_IDLE;
696 rxState = O2RX_IDLE;
697 break;
698 case O2RX_HUMIDITY: StringToInt(tmpRxBuf,(uint32_t*)&tmpSensorDataDiveO2.humidity); /* raw data cycle */
699 externalInterface_SetSensorData(activeSensor+1,(uint8_t*)&tmpSensorDataDiveO2);
700 Comstatus_O2 = UART_O2_IDLE;
701 rxState = O2RX_IDLE;
702 break;
703 case O2RX_GETNR: StringToUInt64((char*)tmpRxBuf,&tmpSensorDataDiveO2.sensorId);
704 externalInterface_SetSensorData(activeSensor+1,(uint8_t*)&tmpSensorDataDiveO2);
705 index = activeSensor;
706
707 if(switchChannel == 0)
708 {
709 Comstatus_O2 = UART_O2_IDLE;
710 rxState = O2RX_IDLE;
711 }
618 break; 712 break;
619 case O2RX_GETSUBSENSORS: StringToInt(tmpRxBuf,&tmpData); 713 default: Comstatus_O2 = UART_O2_IDLE;
620 Comstatus_O2 = UART_O2_IDLE; 714 rxState = O2RX_IDLE;
621 rxState = O2RX_IDLE;
622 break; 715 break;
623 case O2RX_HUMIDITY: StringToInt(tmpRxBuf,(uint32_t*)&sensorDataDiveO2.humidity); /* raw data cycle */ 716 }
624 externalInterface_SetSensorData(1,(uint8_t*)&sensorDataDiveO2);
625 Comstatus_O2 = UART_O2_IDLE;
626 rxState = O2RX_IDLE;
627 break;
628 case O2RX_GETNR: StringToUInt64((char*)tmpRxBuf,&sensorDataDiveO2.sensorId);
629 /* no break */
630 default: Comstatus_O2 = UART_O2_IDLE;
631 rxState = O2RX_IDLE;
632 break;
633 } 717 }
634 } 718 break;
635 break; 719 default: rxState = O2RX_IDLE;
636 default: rxState = O2RX_IDLE; 720 break;
637 break; 721
638 722 }
639 } 723 rxBuffer[localRX] = 0;
640 rxBuffer[localRX] = 0; 724 localRX++;
641 localRX++; 725 rxReadIndex++;
642 rxReadIndex++; 726 if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER)
643 if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) 727 {
644 { 728 localRX = 0;
645 localRX = 0; 729 rxReadIndex = 0;
646 rxReadIndex = 0; 730 }
647 } 731 }
648 } 732
649 733 if((digO2Connected) && time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 4000) /* check for communication timeout */
650 if((digO2Connected) && time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 4000) /* check for communication timeout */ 734 {
651 { 735 digO2Connected = 0;
652 digO2Connected = 0; 736 if(curAlive == lastAlive)
653 if(curAlive == lastAlive) 737 {
654 { 738 setExternalInterfaceChannel(ppO2TargetChannel,0.0);
655 setExternalInterfaceChannel(ppO2TargetChannel,0.0); 739 }
656 } 740 lastAlive = curAlive;
657 lastAlive = curAlive; 741 }
658 } 742 if((dmaActive == 0) && (externalInterface_isEnabledPower33())) /* Should never happen in normal operation => restart in case of communication error */
659 if((dmaActive == 0) && (externalInterface_isEnabledPower33())) /* Should never happen in normal operation => restart in case of communication error */ 743 {
660 { 744 UART_StartDMA_Receiption();
661 UART_StartDMA_Receiption(); 745 }
746 }
747 }
748
749 void UART_SetDigO2_Channel(uint8_t channel)
750 {
751 if(channel <= MAX_ADC_CHANNEL)
752 {
753 activeSensor = channel;
754 }
755 }
756 void UART_MapDigO2_Channel(uint8_t channel, uint8_t muxAddress)
757 {
758 if((channel < MAX_ADC_CHANNEL) && (muxAddress < MAX_ADC_CHANNEL))
759 {
760 sensorMapping[channel] = muxAddress;
662 } 761 }
663 } 762 }
664 763
665 uint8_t UART_isDigO2Connected() 764 uint8_t UART_isDigO2Connected()
666 { 765 {