cancel
Showing results for 
Search instead for 
Did you mean: 

Inquiry about DMA and Uart

imenjazirii
Associate II

Hello, 

I am making a project where i'm using usart2 as a virtual com port and where i'm making a CLI based HMI using teraterm , so there's a lot of diplay and hal_uart_transmit functions , it all worked fine until I added a DMA in the uart1 in order to read gps data.

What happened is that the HMI menu doesn't work as it used to but when i removed the gps reading data part from dma receive to idle it worked like it used to.

Someone told me that using DMA in receive mode like that + Hal_Uart_Transmit causes a block.

Since HAl_uart_transmit is a blocking function, it will cause problems for dma receive ,

And among the problems is that my functions in HMI don't work anymore like they used to, but at the same time i can implement dma with adc and it works fine, the problem is in the uart 

Can anyone please explain to me the logic behind it? The issue reminded me of the Hal_delay() block when used inside an interrupt.

You'll find in the first picture how the normal behaviour should be and in the second one what actually happened when dma is also used 

imenjazirii_0-1749829169644.png

imenjazirii_1-1749829260086.png

 

 

 

9 REPLIES 9
TDK
Super User

There are no inherent issues using HAL_UART_Transmit and HAL_UART_Receive_DMA at the same time.

The issues you describe are likely due to a bug in user code, perhaps in how you are using the HAL functions.

If you feel a post has answered your question, please click "Accept as Solution".
Saket_Om
ST Employee

Hello @imenjazirii 

Could share your code please? 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
Karl Yamashita
Principal

If you're sending "gps" and not getting anything back, then it's probably has to do how you've set up the DMA.

Show your code.

I was told that if a devices starts to smoke, put the smoke back in. I guess I never got all the smoke because the device never worked afterwards.
Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

this is the code for the gps task : 

 * MyGps.c

 *

 *  Created on: Jun 12, 2025

 *      Author: ThinkPad

 

 * gps.c

 *

 *  Created on: Jun 4, 2025

 *      Author: ThinkPad

 */

#include "mygps.h"

#define UART_RX_BUFFER_SIZE  500

#define NMEA_BUFFER_SIZE  500

const size_t xGpsMessageBufferSizeBytes = 500;

uint8_t UART1_RxBuffer[UART_RX_BUFFER_SIZE] = {0};

uint16_t RxDataLen = 0;

MessageBufferHandle_t GpsMessageBufferHandle;

uint8_t RxIdx;

uint8_t NMEA_ToParse[NMEA_BUFFER_SIZE]={0};

char received_nmea[NMEA_BUFFER_SIZE]={0};

BaseType_t xHigherPriorityTaskWokenGps = pdFALSE;

uint8_t xGpsBytesSent;

uint8_t gps_message_buffer_flag;

 

 

void Start_GPS_Task(void const * argument)

{

            GpsMessageBufferHandle = xMessageBufferCreate(xGpsMessageBufferSizeBytes);

            if( GpsMessageBufferHandle != NULL )

            {

            }

            else

            {

                        gps_message_buffer_flag=1;

            }

 

            HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART1_RxBuffer, UART_RX_BUFFER_SIZE);

 

            for(;;)

            {

                        xMessageBufferReceive( GpsMessageBufferHandle, received_nmea, sizeof(received_nmea), portMAX_DELAY);

                        Sentence_parse((char*)received_nmea);

                        memset(received_nmea,0,sizeof(received_nmea));

        osDelay(100);

            }

}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

{

            if (huart->Instance == USART1) {

                        RxDataLen = Size;

                        RxIdx=RxDataLen;

                        if (Size < UART_RX_BUFFER_SIZE) {

                                   UART1_RxBuffer[Size] = '\0';

                        } else {

                                   UART1_RxBuffer[UART_RX_BUFFER_SIZE - 1] = '\0';

                        }

                        memcpy(NMEA_ToParse,UART1_RxBuffer,RxIdx);

            xGpsBytesSent=xMessageBufferSendFromISR(GpsMessageBufferHandle,NMEA_ToParse,strlen((char*)NMEA_ToParse),&xHigherPriorityTaskWokenGps);

                        if( xGpsBytesSent != strlen((char*)NMEA_ToParse))

                        {

                                   HAL_UART_Transmit(&huart2, (const uint8_t *)"GPS Message sent different from buffer data\r\n",strlen("GPS Message sent different from buffer data\r\n"),100);

                        }

                        memset(UART1_RxBuffer,0,UART_RX_BUFFER_SIZE);

                        RxIdx = 0;

 

                        HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART1_RxBuffer, UART_RX_BUFFER_SIZE);

            }

}

void Sentence_parse(char *sentence)

{

            sentence= strtok((char*)sentence, "\r\n");

            while (sentence != NULL) {

                        if (GPS_validate(sentence)) {

                                   GPS_parse(sentence);

                        }

                        sentence = strtok(NULL, "\r\n");

            }

            MyGps.time_gps=GPS.utc_time;

            MyGps.alt_gps=GPS.msl_altitude;

            MyGps.lat_gps=GPS.dec_latitude;

}

int GPS_validate(char *nmeastr){
char check[3];
char checkcalcstr[3];
int i;
int calculated_check;

i=0;
calculated_check=0;

// check to ensure that the string starts with a $
if(nmeastr[i] == '$')
i++;
else
return 0;

//No NULL reached, 75 char largest possible NMEA message, no '*' reached
while((nmeastr[i] != 0) && (nmeastr[i] != '*') && (i < 75)){
calculated_check ^= nmeastr[i];// calculate the checksum
i++;
}

if(i >= 75){
return 0;// the string was too long so return an error
}

if (nmeastr[i] == '*'){
check[0] = nmeastr[i+1]; //put hex chars in check string
check[1] = nmeastr[i+2];
check[2] = 0;
}
else
return 0;// no checksum separator found there for invalid

sprintf(checkcalcstr,"%02X",calculated_check);
return((checkcalcstr[0] == check[0])
&& (checkcalcstr[1] == check[1])) ? 1 : 0 ;
}

void GPS_parse(char *GPSstrParse){
if(!strncmp(GPSstrParse, "$GPGGA", 6)){
if (sscanf(GPSstrParse, "$GPGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.lock, &GPS.satelites, &GPS.hdop, &GPS.msl_altitude, &GPS.msl_units) >= 1){
GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
return;
}
}
else if (!strncmp(GPSstrParse, "$GPRMC", 6)){
if(sscanf(GPSstrParse, "$GPRMC,%f,%f,%c,%f,%c,%f,%f,%d", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.speed_k, &GPS.course_d, &GPS.date) >= 1)
return;

}
else if (!strncmp(GPSstrParse, "$GPGLL", 6)){
if(sscanf(GPSstrParse, "$GPGLL,%f,%c,%f,%c,%f,%c", &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.utc_time, &GPS.gll_status) >= 1)
return;
}
else if (!strncmp(GPSstrParse, "$GPVTG", 6)){
if(sscanf(GPSstrParse, "$GPVTG,%f,%c,%f,%c,%f,%c,%f,%c", &GPS.course_t, &GPS.course_t_unit, &GPS.course_m, &GPS.course_m_unit, &GPS.speed_k, &GPS.speed_k_unit, &GPS.speed_km, &GPS.speed_km_unit) >= 1)
return;
}
}

float GPS_nmea_to_dec(float deg_coord, char nsew) {
int degree = (int)(deg_coord/100);
float minutes = deg_coord - degree*100;
float dec_deg = minutes / 60;
float decimal = degree + dec_deg;
if (nsew == 'S' || nsew == 'W') { // return negative
decimal *= -1;
}
return decimal;
}

And here the code for ihm task (I won't share the whole code since it's 867 lines , but here's the important part : 

 
void Start_IHM_Task(void const * argument)
{
/* USER CODE BEGIN Start_IHM_Task */
MainMenu();
IhmMessageBufferHandle = xMessageBufferCreate(xIhmMessageBufferSizeBytes);
if( IhmMessageBufferHandle != NULL )
{
}
else
{
HAL_UART_Transmit(&huart2,(uint8_t*)"Error in MessageBuffer Creation\r\n", 34, 100);
}
 
/* Infinite loop */
for(;;)
{
xMessageBufferReceive( IhmMessageBufferHandle, received_data, sizeof(received_data), portMAX_DELAY);
memset(new_buff,0,sizeof(new_buff));
UpperCase((char*)received_data);
tokenization((char*)received_data);
ParseCommand();
memset(received_data,0,sizeof(received_data));
osDelay(1);
}
/* USER CODE END Start_IHM_Task */
}
 
// Fonction pour afficher le menu principal complet
 
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  if (huart==&huart2)
{if (!processing)
{ if ((rxByte == '\r')||(rxByte=='\n'))
{   if (rxIndex!=0)
{
processing=1;
rxBuffer[rxIndex] = '\0';
memcpy(new_buff,rxBuffer,rxIndex);
xBytesSent=xMessageBufferSendFromISR(IhmMessageBufferHandle,new_buff,strlen((char*)new_buff),&xHigherPriorityTaskWoken);
//The number of bytes actually written to the message buffer.  If the
// * message buffer didn't have enough free space for the message to be stored
// * then 0 is returned, otherwise xDataLengthBytes is returned.
if( xBytesSent != strlen((char*)new_buff))
{
HAL_UART_Transmit(&huart2, (const uint8_t *)"Message sent !=buffer data\r\n",26,100);
}
memset(rxBuffer,0,sizeof(rxBuffer));
rxIndex = 0;}
}
 
else { if (rxIndex > 0){
 
if (rxByte == '\b') {
rxBuffer[rxIndex]=' ';
rxIndex=rxIndex-1;
rxBuffer[rxIndex]=' ';
retour=rxIndex-1;
HAL_UART_Transmit(huart, (uint8_t *)" \b", 2, 100);
 
// for (uint8_t i=0;i< strlen((char*)rxBuffer);i++)
//{rxBuffer[i]=rxBuffer[retour++];
//if (i==retour)
//rxBuffer[i]='\0';}
}
}
if (rxIndex < RX_BUFFER_SIZE-1) {
 
rxBuffer[rxIndex++] = rxByte;
}
else {
rxIndex=0;
}
}
}
HAL_UART_Receive_IT(&huart2, &rxByte, 1);
}
}
 
//tableau de liste des commandes
CMD cmd_list[]={
{"LORA",(char*)":TO ACCESS LORA MENU WRITE LORA",LoraMenu,Main_Menu},
{"SENSORS",(char*)":TO ACCESS SENSORS MENU WRITE SENSORS",SensorsMenu,Main_Menu},
{"GPS",(char*)":TO ACCESS GPS MENU WRITE GPS",GPSMenu,Main_Menu},
{"SYSCONF",(char*)":TO ACCESS SYSTEM CONFIGURATION WRITE SYSCONF",SysConfigMenu,Main_Menu},
//Lora Menu Command List
{"SETSF",(char*)":TO SET SF VALUE WRITE SETSF 7\r\n[Possible Values :{6,7,8,9,10,11,12}]",SetSF_f,Lora_Menu},
{"GETSF",(char*)":TO GET SF VALUE WRITE GETSF",GetSF_f,Lora_Menu},
{"SETCR",(char*)":TO SET CR VALUE WRITE SETCR VALUE\r\n[Value for each CR :{4/5 -> 1 ; 4/6 -> 2 ; 4/7 -> 3 ; 4/8 -> 4}] ",SetCR_f,Lora_Menu},
{"GETCR",(char*)":TO GET CR WRITE GETCR",GetCR_f,Lora_Menu},
{"SETBW",(char*)":TO SET BANDWIDTH VALUE WRITE SETBW 4 \r\n[Values for BW :{125Khz->4 ; 250Khz->5 ; 500Khz->6}] ",SetBW_f,Lora_Menu},
{"GETBW",(char*)":TO GET BANDWIDTH VALUE WRITE GETBW\r\nNote : you must respect the Values provided ",GetBW_f,Lora_Menu},
//Sensors Menu Command List
{"GETST",(char*)":TO GET SOIL TEMPERATURE VALUE WRITE GETST",GetSoilTemp_f,Sensors_Menu},
{"GETAT",(char*)":TO GET AIR TEMPERATURE VALUE WRITE GETAT",GetAirTemp_f,Sensors_Menu},
{"GETAP",(char*)":TO GET AIR PRESSURE VALUE WRITE GETAP",GetAirPressure_f,Sensors_Menu},
{"GETRH",(char*)":TO GET RELATIVE HUMIDITY VALUE WRITE GETRH",GetRelativeHumidity_f,Sensors_Menu},
{"GETSH",(char*)":TO GET SOIL HUMIDITY VALUE WRITE GETSH",GetSoilHumidity_f,Sensors_Menu},
{"GETWS",(char*)":TO GET WIND SPEED VALUE WRITE GETWS",GetWindSpeed_f,Sensors_Menu},
{"SETH",(char*)":TO SET THE HEIGH VALUE IN METERS WRITE SETH 2\r\n",SetHeigh_f,Sensors_Menu},
{"GETH",(char*)":TO GET THE HEIGH VALUE IN METERS WRITE GETH \r\n",GetHeigh_f,Sensors_Menu},
{"SETR",(char*)":TO SET RADIATION VALUE WRITE SETR 7.3\r\nPossible Values [0,40]",SetRadiation_f,Sensors_Menu},
{"GETR",(char*)":TO GET RADIATION VALUE WRITE GETR",GetRadiation_f,Sensors_Menu},
{"SETKC",(char*)":TO SET Kc VALUE WRITE SETKC 1.12",SetKc_f,Sensors_Menu},
{"GETKC",(char*)":TO GET Kc VALUE WRITE GETKC",GetKc_f,Sensors_Menu},
{"SETKP",(char*)":TO SET Kp VALUE WRITE SETKP 0.7\r\nPossible Values [0,1]",SetKp_f,Sensors_Menu},
{"GETKP",(char*)":TO GET Kp VALUE WRITE GETKP",GetKp_f,Sensors_Menu},
{"SETET0",(char*)":TO SET ET0 VALUE WRITE SETET0 8.4",SetET0_f,Sensors_Menu},
{"SETET0",(char*)":TO GET ET0 VALUE WRITE GETET0",GetET0_f,Sensors_Menu},
{"SETETC",(char*)":TO SET ETC=Kc*ET0 VALUE WRITE SETETC 6.8",SetETC_f,Sensors_Menu},
{"GETETC",(char*)":TO GET ETC VALUE WRITE GETETC",GetETC_f,Sensors_Menu},
{"SETETCADJ",(char*)":TO SET ETc(adj)=Kc*Kp*ET0 VALUE WRITE SETETCADJ\r\nNote: ETc(adj) must be < than ETc",SetETCadj_f,Sensors_Menu},
{"GETETCADJ",(char*)":TO GET ET0 VALUE WRITE GETET0\r\nPossible values [0,30]",GetETCadj_f,Sensors_Menu},
//GPS Menu Command List
{"SETALT",(char*)"TO SET ALTITUDE VALUE WRITE SETALT\r\nPossible Values : [-430.0,12000.0]",SetAltGPS_f,GPS_Menu},
{"GETALT",(char*)":TO GET ALTITUDE VALUE WRITE GETALT",GetAltGPS_f,GPS_Menu},
{"SETLAT",(char*)":TO SET LATITUDE VALUE WRITE SETLAT\r\nPossible Values : [-90.0,90.0]",SetLatGPS_f,GPS_Menu},
{"GETLAT",(char*)":TO GET LATITUDE VALUE WRITE GETLAT",GetLatGPS_f,GPS_Menu},
{"SETUTC",(char*)":TO SET TIME VALUE WRITE SETUTC 12361500\r\n 12361500 is equivalent to 12H36 minutes and 15 seconds",SetTimeGPS_f,GPS_Menu},
{"GETUTC",(char*)":TO GET TIME VALUE WRITE GETUTC",GetTimeGPS_f,GPS_Menu},
//SystemConfig Menu
{"SAVE",(char*)":TO SAVE MODIFIED PARAMETERS PERMANENTLY WRITE SAVE",Save_f,SysConfig_Menu},
{"RESTORE",(char*)":TO RESTORE OLD PARAMETERS WRITE RESTORE",Restore_f,SysConfig_Menu},
 
};
void MainMenu(void) {
// Afficher tout le menu une seule fois
currentMenu=Main_Menu;
char* weekday_str[] = {
"Invalid",      // index 0 (not used)
"Monday",       // 1
"Tuesday",      // 2
"Wednesday",    // 3
"Thursday",     // 4
"Friday",       // 5
"Saturday",     // 6
"Sunday"        // 7
};
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
if (Reset_Flag==1)
{
 
day=sDate.WeekDay;
date=sDate.Date;
month=sDate.Month;
year=sDate.Year;
hour=sTime.Hours;
minutes=sTime.Minutes;
seconds=sTime.Seconds;
Reset_Flag=0;
}
 
sprintf((char*)txBuffer,"\033[1;30;107m----------------Main Menu---------------\033[0m\n \r\nDate : %s , %02d/%02d/%02d        Session opened at: %02d:%02d:%02d\r\n",
weekday_str[day],date,month, 2000+year,hour,minutes, seconds);
HAL_UART_Transmit(&huart2, txBuffer, strlen((char*)txBuffer), 100);
for (uint8_t l=0;l<sizeof(cmd_list)/sizeof(cmd_list[0]);l++)
{if (cmd_list[l].MenuIndex==Main_Menu)
{sprintf((char*)txBuffer,"%s %s \r\n",cmd_list[l].Name, cmd_list[l].helper);
HAL_UART_Transmit(&huart2, txBuffer, strlen((char*)txBuffer), 100);
}
}
HAL_UART_Receive_IT(&huart2, &rxByte, 1);
 
}
void tokenization(char *str) //function to tokenize input string
{
tokens[0]=strtok(str," ");
for (uint8_t i=1; i<10;i++)
{   tokens[i]=strtok(NULL," ");
if (tokens[i]==NULL)
break;
}
}
uint8_t cl_elements=sizeof(cmd_list)/sizeof(cmd_list[0]);
void ParseCommand() {
uint8_t c=0;
uint8_t correspond=0;
uint8_t true=0;
uint8_t goback=0;
if (strcmp(tokens[0],"..")==0)
{MainMenu();
goback=1;}
while (c<cl_elements)
{if (strcmp(tokens[0], cmd_list[c].Name)== 0)
{ true=1;
if (currentMenu==cmd_list[c].MenuIndex)
{cmd_list[c].handler(tokens[1]);
correspond=1;}
else HAL_UART_Transmit(&huart2, (uint8_t*)"Wrong Menu\r\n",strlen("Wrong Menu\r\n"),100);
break;
}
c++;
}
if (true==0 && correspond==0 && goback==0)
HAL_UART_Transmit(&huart2, (uint8_t*)"COMMAND ERROR\r\n",16,100);
 
processing=0;
}

 

 

 

I have just posted in as a reply to Karl Yamashita, I wasn't able to add the same reply here too , thanks in advance for your help

Can you please explain to me more? I shared my code in reply to Karl Yamashita maybe it will help explain more the issue , thanks a lot in advance 

TDK
Super User

> void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

> {

> ...

>                                    HAL_UART_Transmit(...

 

Don't use blocking function within an interrupt context. Set a flag and do it in the main loop instead. The UART interrupt will be unable to trigger until HAL_UART_Transmit returns, which takes quite a while.

If you feel a post has answered your question, please click "Accept as Solution".

Edit your post and use the </> when posting code. That way it's properly formatted and readable. Right now it's all left adjusted and hard to read.

 

Code Snippet.jpg

I was told that if a devices starts to smoke, put the smoke back in. I guess I never got all the smoke because the device never worked afterwards.
Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.
// GPS CODE 
#include "mygps.h"
#define UART_RX_BUFFER_SIZE  100
#define NMEA_BUFFER_SIZE  100
const size_t xGpsMessageBufferSizeBytes = 100;
uint8_t UART1_RxBuffer[UART_RX_BUFFER_SIZE] = {0};
uint16_t RxDataLen = 0;
MessageBufferHandle_t GpsMessageBufferHandle;
uint8_t RxIdx;
uint8_t NMEA_ToParse[NMEA_BUFFER_SIZE]={0};
char received_nmea[NMEA_BUFFER_SIZE]={0};
BaseType_t xHigherPriorityTaskWokenGps = pdFALSE;
uint8_t xGpsBytesSent;


void Start_GPS_Task(void const * argument)
{
	GpsMessageBufferHandle = xMessageBufferCreate(xGpsMessageBufferSizeBytes);
	if( GpsMessageBufferHandle != NULL )
	{
	}
	else
	{
		HAL_UART_Transmit(&huart2,(uint8_t*)"Error in MessageBuffer Creation\r\n", 34, 100);
	}

	HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART1_RxBuffer, UART_RX_BUFFER_SIZE);

	for(;;)
	{
		xMessageBufferReceive( GpsMessageBufferHandle, received_nmea, sizeof(received_nmea), portMAX_DELAY);
		Sentence_parse((char*)received_nmea);
		memset(received_nmea,0,sizeof(received_nmea));

	}
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if (huart->Instance == USART1) {
		RxDataLen = Size;
		RxIdx=RxDataLen;
		UART1_RxBuffer[Size] = '\0';
		memcpy(NMEA_ToParse,UART1_RxBuffer,RxIdx);
		xGpsBytesSent=xMessageBufferSendFromISR(GpsMessageBufferHandle,NMEA_ToParse,strlen((char*)NMEA_ToParse),&xHigherPriorityTaskWokenGps);
		if( xGpsBytesSent != strlen((char*)NMEA_ToParse))
		{
			HAL_UART_Transmit(&huart2, (const uint8_t *)"GPS Message sent different from buffer data\r\n",strlen("GPS Message sent different from buffer data\r\n"),100);
		}
		memset(UART1_RxBuffer,0,UART_RX_BUFFER_SIZE);
		RxIdx = 0;

		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART1_RxBuffer, UART_RX_BUFFER_SIZE);
	}
}
void Sentence_parse(char *sentence)
{
	sentence= strtok((char*)received_nmea, "\r\n");
	while (sentence != NULL) {
	        if (GPS_validate(sentence)) {
	            GPS_parse(sentence);
	        }
	        sentence = strtok(NULL, "\r\n");
	    }

}
int GPS_validate(char *nmeastr){
    char check[3];
    char checkcalcstr[3];
    int i;
    int calculated_check;

    i=0;
    calculated_check=0;

    // check to ensure that the string starts with a $
    if(nmeastr[i] == '$')
        i++;
    else
        return 0;

    //No NULL reached, 75 char largest possible NMEA message, no '*' reached
    while((nmeastr[i] != 0) && (nmeastr[i] != '*') && (i < 75)){
        calculated_check ^= nmeastr[i];// calculate the checksum
        i++;
    }

    if(i >= 75){
        return 0;// the string was too long so return an error
    }

    if (nmeastr[i] == '*'){
        check[0] = nmeastr[i+1];    //put hex chars in check string
        check[1] = nmeastr[i+2];
        check[2] = 0;
    }
    else
        return 0;// no checksum separator found there for invalid

    sprintf(checkcalcstr,"%02X",calculated_check);
    return((checkcalcstr[0] == check[0])
        && (checkcalcstr[1] == check[1])) ? 1 : 0 ;
}

void GPS_parse(char *GPSstrParse){
    if(!strncmp(GPSstrParse, "$GPGGA", 6)){
    	if (sscanf(GPSstrParse, "$GPGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.lock, &GPS.satelites, &GPS.hdop, &GPS.msl_altitude, &GPS.msl_units) >= 1){
    		GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, GPS.ns);
    		GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, GPS.ew);
    		return;
    	}
    }
    else if (!strncmp(GPSstrParse, "$GPRMC", 6)){
    	if(sscanf(GPSstrParse, "$GPRMC,%f,%f,%c,%f,%c,%f,%f,%d", &GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.speed_k, &GPS.course_d, &GPS.date) >= 1)
    		return;

    }
    else if (!strncmp(GPSstrParse, "$GPGLL", 6)){
        if(sscanf(GPSstrParse, "$GPGLL,%f,%c,%f,%c,%f,%c", &GPS.nmea_latitude, &GPS.ns, &GPS.nmea_longitude, &GPS.ew, &GPS.utc_time, &GPS.gll_status) >= 1)
            return;
    }
    else if (!strncmp(GPSstrParse, "$GPVTG", 6)){
        if(sscanf(GPSstrParse, "$GPVTG,%f,%c,%f,%c,%f,%c,%f,%c", &GPS.course_t, &GPS.course_t_unit, &GPS.course_m, &GPS.course_m_unit, &GPS.speed_k, &GPS.speed_k_unit, &GPS.speed_km, &GPS.speed_km_unit) >= 1)
            return;
    }
}

float GPS_nmea_to_dec(float deg_coord, char nsew) {
    int degree = (int)(deg_coord/100);
    float minutes = deg_coord - degree*100;
    float dec_deg = minutes / 60;
    float decimal = degree + dec_deg;
    if (nsew == 'S' || nsew == 'W') { // return negative
        decimal *= -1;
    }
    return decimal;
}
//IHM CODE 
//Useful functions for the code
void UpperCase(char *str){
	while (*str)
	{
		*str=toupper(*str);
		str++;
	}
}

void Start_IHM_Task(void const * argument)
{
	/* USER CODE BEGIN Start_IHM_Task */
	MainMenu();
	IhmMessageBufferHandle = xMessageBufferCreate(xIhmMessageBufferSizeBytes);
	if( IhmMessageBufferHandle != NULL )
	{
	}
	else
	{
		HAL_UART_Transmit(&huart2,(uint8_t*)"Error in MessageBuffer Creation\r\n", 34, 100);
	}

	/* Infinite loop */
	for(;;)
	{
		xMessageBufferReceive( IhmMessageBufferHandle, received_data, sizeof(received_data), portMAX_DELAY);
		memset(new_buff,0,sizeof(new_buff));
		UpperCase((char*)received_data);
		tokenization((char*)received_data);
		ParseCommand();
		memset(received_data,0,sizeof(received_data));
		osDelay(1);
	}
	/* USER CODE END Start_IHM_Task */
}

// Fonction pour afficher le menu principal complet


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
	  if (huart==&huart2)
	{if (!processing)
	{ if ((rxByte == '\r')||(rxByte=='\n'))
	{   if (rxIndex!=0)
	{
		processing=1;
		rxBuffer[rxIndex] = '\0';
		memcpy(new_buff,rxBuffer,rxIndex);
		xBytesSent=xMessageBufferSendFromISR(IhmMessageBufferHandle,new_buff,strlen((char*)new_buff),&xHigherPriorityTaskWoken);
		//The number of bytes actually written to the message buffer.  If the
		// * message buffer didn't have enough free space for the message to be stored
		// * then 0 is returned, otherwise xDataLengthBytes is returned.
		if( xBytesSent != strlen((char*)new_buff))
		{
			HAL_UART_Transmit(&huart2, (const uint8_t *)"Message sent !=buffer data\r\n",26,100);
		}
		memset(rxBuffer,0,sizeof(rxBuffer));
		rxIndex = 0;}
	}

	else { if (rxIndex > 0){

		if (rxByte == '\b') {
			rxBuffer[rxIndex]=' ';
			rxIndex=rxIndex-1;
			rxBuffer[rxIndex]=' ';
			retour=rxIndex-1;
			HAL_UART_Transmit(huart, (uint8_t *)" \b", 2, 100);

			//	for (uint8_t i=0;i< strlen((char*)rxBuffer);i++)
			//{rxBuffer[i]=rxBuffer[retour++];
			//if (i==retour)
			//rxBuffer[i]='\0';}
		}
	}
	if (rxIndex < RX_BUFFER_SIZE-1) {

		rxBuffer[rxIndex++] = rxByte;
	}
	else {
		rxIndex=0;
	}
	}
	}
	HAL_UART_Receive_IT(&huart2, &rxByte, 1);
}
}

//tableau de liste des commandes
CMD cmd_list[]={
		{"LORA",(char*)":TO ACCESS LORA MENU WRITE LORA",LoraMenu,Main_Menu},
		{"SENSORS",(char*)":TO ACCESS SENSORS MENU WRITE SENSORS",SensorsMenu,Main_Menu},
		{"GPS",(char*)":TO ACCESS GPS MENU WRITE GPS",GPSMenu,Main_Menu},
		{"SYSCONF",(char*)":TO ACCESS SYSTEM CONFIGURATION WRITE SYSCONF",SysConfigMenu,Main_Menu},
		//Lora Menu Command List
		{"SETSF",(char*)":TO SET SF VALUE WRITE SETSF 7\r\n[Possible Values :{6,7,8,9,10,11,12}]",SetSF_f,Lora_Menu},
		{"GETSF",(char*)":TO GET SF VALUE WRITE GETSF",GetSF_f,Lora_Menu},
		{"SETCR",(char*)":TO SET CR VALUE WRITE SETCR VALUE\r\n[Value for each CR :{4/5 -> 1 ; 4/6 -> 2 ; 4/7 -> 3 ; 4/8 -> 4}] ",SetCR_f,Lora_Menu},
		{"GETCR",(char*)":TO GET CR WRITE GETCR",GetCR_f,Lora_Menu},
		{"SETBW",(char*)":TO SET BANDWIDTH VALUE WRITE SETBW 4 \r\n[Values for BW :{125Khz->4 ; 250Khz->5 ; 500Khz->6}] ",SetBW_f,Lora_Menu},
		{"GETBW",(char*)":TO GET BANDWIDTH VALUE WRITE GETBW\r\nNote : you must respect the Values provided ",GetBW_f,Lora_Menu},
		//Sensors Menu Command List
		{"GETST",(char*)":TO GET SOIL TEMPERATURE VALUE WRITE GETST",GetSoilTemp_f,Sensors_Menu},
		{"GETAT",(char*)":TO GET AIR TEMPERATURE VALUE WRITE GETAT",GetAirTemp_f,Sensors_Menu},
		{"GETAP",(char*)":TO GET AIR PRESSURE VALUE WRITE GETAP",GetAirPressure_f,Sensors_Menu},
		{"GETRH",(char*)":TO GET RELATIVE HUMIDITY VALUE WRITE GETRH",GetRelativeHumidity_f,Sensors_Menu},
		{"GETSH",(char*)":TO GET SOIL HUMIDITY VALUE WRITE GETSH",GetSoilHumidity_f,Sensors_Menu},
		{"GETWS",(char*)":TO GET WIND SPEED VALUE WRITE GETWS",GetWindSpeed_f,Sensors_Menu},
		{"SETH",(char*)":TO SET THE HEIGH VALUE IN METERS WRITE SETH 2\r\n",SetHeigh_f,Sensors_Menu},
		{"GETH",(char*)":TO GET THE HEIGH VALUE IN METERS WRITE GETH \r\n",GetHeigh_f,Sensors_Menu},
		{"SETR",(char*)":TO SET RADIATION VALUE WRITE SETR 7.3\r\nPossible Values [0,40]",SetRadiation_f,Sensors_Menu},
		{"GETR",(char*)":TO GET RADIATION VALUE WRITE GETR",GetRadiation_f,Sensors_Menu},
		{"SETKC",(char*)":TO SET Kc VALUE WRITE SETKC 1.12",SetKc_f,Sensors_Menu},
		{"GETKC",(char*)":TO GET Kc VALUE WRITE GETKC",GetKc_f,Sensors_Menu},
		{"SETKP",(char*)":TO SET Kp VALUE WRITE SETKP 0.7\r\nPossible Values [0,1]",SetKp_f,Sensors_Menu},
		{"GETKP",(char*)":TO GET Kp VALUE WRITE GETKP",GetKp_f,Sensors_Menu},
		{"SETET0",(char*)":TO SET ET0 VALUE WRITE SETET0 8.4",SetET0_f,Sensors_Menu},
		{"SETET0",(char*)":TO GET ET0 VALUE WRITE GETET0",GetET0_f,Sensors_Menu},
		{"SETETC",(char*)":TO SET ETC=Kc*ET0 VALUE WRITE SETETC 6.8",SetETC_f,Sensors_Menu},
		{"GETETC",(char*)":TO GET ETC VALUE WRITE GETETC",GetETC_f,Sensors_Menu},
		{"SETETCADJ",(char*)":TO SET ETc(adj)=Kc*Kp*ET0 VALUE WRITE SETETCADJ\r\nNote: ETc(adj) must be < than ETc",SetETCadj_f,Sensors_Menu},
		{"GETETCADJ",(char*)":TO GET ET0 VALUE WRITE GETET0\r\nPossible values [0,30]",GetETCadj_f,Sensors_Menu},
		//GPS Menu Command List
		{"SETALT",(char*)"TO SET ALTITUDE VALUE WRITE SETALT\r\nPossible Values : [-430.0,12000.0]",SetAltGPS_f,GPS_Menu},
		{"GETALT",(char*)":TO GET ALTITUDE VALUE WRITE GETALT",GetAltGPS_f,GPS_Menu},
		{"SETLAT",(char*)":TO SET LATITUDE VALUE WRITE SETLAT\r\nPossible Values : [-90.0,90.0]",SetLatGPS_f,GPS_Menu},
		{"GETLAT",(char*)":TO GET LATITUDE VALUE WRITE GETLAT",GetLatGPS_f,GPS_Menu},
		{"SETUTC",(char*)":TO SET TIME VALUE WRITE SETUTC 12361500\r\n 12361500 is equivalent to 12H36 minutes and 15 seconds",SetTimeGPS_f,GPS_Menu},
		{"GETUTC",(char*)":TO GET TIME VALUE WRITE GETUTC",GetTimeGPS_f,GPS_Menu},
		//SystemConfig Menu
		{"SAVE",(char*)":TO SAVE MODIFIED PARAMETERS PERMANENTLY WRITE SAVE",Save_f,SysConfig_Menu},
		{"RESTORE",(char*)":TO RESTORE OLD PARAMETERS WRITE RESTORE",Restore_f,SysConfig_Menu},

};
void MainMenu(void) {
	// Afficher tout le menu une seule fois
	currentMenu=Main_Menu;
	char* weekday_str[] = {
			"Invalid",      // index 0 (not used)
			"Monday",       // 1
			"Tuesday",      // 2
			"Wednesday",    // 3
			"Thursday",     // 4
			"Friday",       // 5
			"Saturday",     // 6
			"Sunday"        // 7
	};
	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
	if (Reset_Flag==1)
	{

		day=sDate.WeekDay;
		date=sDate.Date;
		month=sDate.Month;
		year=sDate.Year;
		hour=sTime.Hours;
		minutes=sTime.Minutes;
		seconds=sTime.Seconds;
		Reset_Flag=0;
	}

	sprintf((char*)txBuffer,"\033[1;30;107m----------------Main Menu---------------\033[0m\n \r\nDate : %s , %02d/%02d/%02d        Session opened at: %02d:%02d:%02d\r\n",
			weekday_str[day],date,month, 2000+year,hour,minutes, seconds);
	HAL_UART_Transmit(&huart2, txBuffer, strlen((char*)txBuffer), 100);
	for (uint8_t l=0;l<sizeof(cmd_list)/sizeof(cmd_list[0]);l++)
	{if (cmd_list[l].MenuIndex==Main_Menu)
	{sprintf((char*)txBuffer,"%s %s \r\n",cmd_list[l].Name, cmd_list[l].helper);
	HAL_UART_Transmit(&huart2, txBuffer, strlen((char*)txBuffer), 100);
	}
	}
	HAL_UART_Receive_IT(&huart2, &rxByte, 1);

}
void tokenization(char *str) //function to tokenize input string
{
	tokens[0]=strtok(str," ");
	for (uint8_t i=1; i<10;i++)
	{   tokens[i]=strtok(NULL," ");
	if (tokens[i]==NULL)
		break;
	}
}
uint8_t cl_elements=sizeof(cmd_list)/sizeof(cmd_list[0]);
void ParseCommand() {
	uint8_t c=0;
	uint8_t correspond=0;
	uint8_t true=0;
	uint8_t goback=0;
	if (strcmp(tokens[0],"..")==0)
	{MainMenu();
	goback=1;}
	while (c<cl_elements)
	{if (strcmp(tokens[0], cmd_list[c].Name)== 0)
	{ true=1;
	if (currentMenu==cmd_list[c].MenuIndex)
	{cmd_list[c].handler(tokens[1]);
	correspond=1;}
	else HAL_UART_Transmit(&huart2, (uint8_t*)"Wrong Menu\r\n",strlen("Wrong Menu\r\n"),100);
	break;
	}
	c++;
	}
	if (true==0 && correspond==0 && goback==0)
		HAL_UART_Transmit(&huart2, (uint8_t*)"COMMAND ERROR\r\n",16,100);

	processing=0;
}