cancel
Showing results for 
Search instead for 
Did you mean: 

Parsing Raw Data

AE104
Senior

Hello,

I need to parse a raw data that I receive UART3 interface. Then, I will send to a PC to show results in serial monitor. Before implementing in the microcontroller, I tested my approach in a C compiler. A sample raw data in the buffer array and here is C code to do this job 

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char buffer[] = "e\nM0000\nPda7F85F3Fu;ba48D503Dp,10,288\nPda7F9234Bu;ba4E2C324p,10,288\nPda806EC24u;baAE16C6Dp,10,288\nPda807B031u;baB360495p,10,288\n*\n\n";
    char *token;
    token = strtok(buffer, "\n");
    int package_nr = 0;

    while (token != NULL) {
        if (strcmp(token, "e") == 0) {
            printf("Response begin\n");
        } else if (token[0] == 'M') {
            printf("Measuring...\n");
            package_nr = 0;
        } else if (token[0] == 'P') {
            if (package_nr++ == 0) {
                printf("Receiving measurement responses:");
            }
            printf("\n%d. ", package_nr);
            char *P = strchr(token, 'P');
            char *packageLine = P + 1;
            char *running = packageLine;
            char *param;
            while ((param = strtok_r(running, ";,", &running)) != NULL) {
                if (strlen(param) == 0) {
                    continue;
                }
                char paramIdentifier[3];
                char paramValue[10];
                strncpy(paramIdentifier, param, 2);
                paramIdentifier[2] = '\0';
                strncpy(paramValue, param + 2, 9);
                paramValue[9] = '\0';
                printf("%s%s ", paramIdentifier, paramValue);
            }
        } else if (strcmp(token, "*") == 0) {
            printf("\nMeasurement completed.\n");
            printf("%d data point(s) received.\n", package_nr);
        } else {
            printf("%s", token);
        }
        token = strtok(NULL, "\n");
    }

    return 0;
}

 

Then I got this result:

 

Response begin
Measuring...
Receiving measurement responses:
1. da7F85F3Fu ba48D503Dp 10 288 
2. da7F9234Bu ba4E2C324p 10 288 
3. da806EC24u baAE16C6Dp 10 288 
4. da807B031u baB360495p 10 288 
Measurement completed.
4 data point(s) received.

 

 

 

To implement this code in the microcontroller, I simply removed the buffer array and replace it with Rx_Buffer which collects all raw data with HAL_UART_RxCpltCallback function. Then, here is the modified code:

 

 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
 
	  char *token;
          char msg[100];
	      token = strtok(RX_Buffer, "\n");

	      while (token != NULL) {
	          if (strcmp(token, "e") == 0) {
	              sprintf(msg, "Response begin\n");
	              HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	          } else if (token[0] == 'M') {
	              sprintf(msg, "Measuring...\n");
	              HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	              package_nr = 0;
	          } else if (token[0] == 'P') {
	              if (package_nr++ == 0) {
	                  sprintf(msg, "Receiving measurement responses:");
	                  HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	              }
	              sprintf(msg, "\n%d. ", package_nr);
	              HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	              char *P = strchr(token, 'P');
	              char *packageLine = P + 1;
	              char *running = packageLine;
	              char *param;
	              while ((param = strtok_r(running, ";,", &running)) != NULL) {
	                  if (strlen(param) == 0) {
	                      continue;
	                  }
	                  char paramIdentifier[3];
	                  char paramValue[10];
	                  strncpy(paramIdentifier, param, 2);
	                  paramIdentifier[2] = '\0';
	                  strncpy(paramValue, param + 2, 9);
	                  paramValue[9] = '\0';
	                  sprintf(msg, "%s%s ", paramIdentifier, paramValue);
	                  HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	              }
	          } else if (strcmp(token, "*") == 0) {
	              sprintf(msg, "\nMeasurement completed.\n");
	              HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	              sprintf(msg, "%d data point(s) received.\n", package_nr);
	              HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	          } else {
	              sprintf(msg, "%s", token);
	              HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
	          }
	          token = strtok(NULL, "\n");
	      }
	      return 0;


	}

 

Then I got this result in the serial monitor:

 

Response begin
              e!0006Receiving measurement responses:
                                                    1.

 


So what can be source of the problem?
Thank you,

 

12 REPLIES 12

LPUART, UART and USART's all function in a materially similar fashion.

Synchronous USARTs aren't particularly prevalent these days, and I'm not sure I care for ST's implementations in any case.

Some newer model STM32's have UARTs with FIFO's. These aren't particularly deep and not 16550+ implementations.

The LPUART tends to have lower frequency expectations, and clocking.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

The development board that I used defaults to using LPUART1. It doesn't matter which UART port you use. You can assign the UART instance when creating the UART data structure.   

UART_Handler.c is where you can create/init a data structure. Here I assign hlpuart1 to the structure but you can use huart2 also, which I commented out because I'm not using it. But I have other development boards that use huart2.

/*
 * UART_Handler.c
 *
 *  Created on: Jul 21, 2023
 *      Author: karl.yamashita
 */



#include "main.h"

//extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef hlpuart1;

// Init uart2 or lpuart1
UartBufferStruct uart1_msg =
{
	.huart = &hlpuart1,
	.rx.uartType = UART_ASCII,
	.rx.irqByte = 0
};

 

You may want to look at this project where I use 3 UART ports and created 3 data structures. This uses the DMA with idle so a little different but has the same buffer queue concept. I'm not sure how your data is being sent to the STM32 is in packets or one long string of multiple packets? This project will only work if messages are sent separately. If a string with multiple messages with LF are sent as one string, then the DMA with idle will not be able to separate each message in a queue. 

 

As for NotifyUser, that buffers each message in a queue. The messages get sent using HAL_UART_Transmit_IT which is interrupt based. Even if the 1st message is still being sent, you can add more message to the queue (queue size is adjustable) which get sent after the previous message is done. And also, while the messages are being sent, your FW can be doing other tasks, like parsing more messages or calculations. 

 

The problem with using HAL_UART_Transmit is that it is blocking so you have to wait for the data to be sent or times out before your FW can continue doing other tasks. Lets say your 1st message is still being sent and you want to send another message, you can't until the 1st message is done sending. HAL_UART_Transmit has its place but IMO for what your doing with you received data, I steer away from using it as it will slow down your other tasks.

If you find my answers useful, click the accept button so that way others can see the solution.

Basically, I send this comment: 

char const * LS = "e\n"
                             "var c\n"
                             "var p\n"
                             "set_pgstat_mode 3\n"
                             "set_max_bandwidth 200\n"
                             "set_range ba 500u\n"
                             "set_e -500m\n"
                             "cell_on\n"
                             "wait 1\n"
                             "meas_loop_lsv p c -500m 500m 50m 100m\n"
                             "pck_start\n"
                             "pck_add p\n"
                             "pck_add c\n"
                             "pck_end\n"
                             "endloop\n"
                             "cell_off\n"
                             "\n";

 With this functions:

void HAL_WriteStr(UART_HandleTypeDef *huart, const char *buf) {
    while (*buf != '\0') {
        // Transmit one character
        HAL_UART_Transmit(&huart3, (uint8_t *)buf, 1, HAL_MAX_DELAY);
        // Increment the buffer pointer to the next character
        buf++;
    }
}

void SendScriptToDevice(const char *scriptText) {
    HAL_WriteStr(&huart3, scriptText);
}

I called the SendScriptToDevice(LS); function in int main() structure. Basically, the concept is that I command to sensor with UART3 Transmit, and collect sensor measurements with UART3 Receive. Whenever I get the measurements, I want to send to a PC with UART2 Transmit.

I see let me try to implement multiple UARTs.