2
votes

I'm working with the Tiva Launchpad EK-TM4C123GXL and the ESP8266 WIFI module.

When this module gets a wifi packet, it sends it to the microcontroller through the UART port.

The format used by ESP8266 to send a packet (to the uC via UART) is:

+IPD,n:xxxxx\r\nOK\r\n

where:

  • n is the length (in bytes) of the data packet
  • : indicates that the next byte will be the first data byte
  • xxxxx is the data packet
  • \r\nOK\r\n are 6 bytes and they are useless for me.

For example:

+IPD,5:hello\r\nOK\r\n

Here is my situation:

I'm working on an existing project, where I can't change these two things:

1- The UART module is already configured to generate an interrupt when its Receive FIFO (of 16 bytes) is half-full.

2- The ISR (Interrupt Service Routine) which handles this interrupt:

  • reads only one byte from the UARTDR (UART Data Register)

  • saves it into a variable

  • calls a function (called rx_data()) which will handle that byte.

Now, I have to write this function, called rx_data(), in C language.

So, the message coming form the ESP8266 module is passed to this function, rx_data(), one byte at a time, and this function must be able to:

  • identify the header +IPD,

  • read the length n of the data packet

  • save the data packet xxxxx (which is located after the : character and before the first \r character) into a buffer

  • discard the final bytes \r\nOK\r\n (these 6 bytes are useless for me, but, anyway, I must read them to remove them from the Receive FIFO)

I think to work step by step, so now I' m reasoning on:

how to identify the +IPD, , considering that only one byte at a time is passed to this function?

1
Save the state to somewhere that won't be cleared on exiting from the function.MikeCAT
You could create a global RX buffer to store the bytes, and each time rx_data is called the byte is added to the buffer and the index (also a global var) is incremented. Do this until you have a full message or until you see/have the data you want, and clear the buffer and reset the index to start again.DigitalNinja

1 Answers

3
votes

It's time to make a state machine. Every time rx_data is called, you would update the state of your state machine, and eventually at some point you will know that you have received the string "+IPD,".

The simplest thing that could work would be something like this, assuming that the byte received from the UART is passed as an argument to rx_data:

void rx_data(uint8_t byte)
{
    static uint8_t state = 0;
    if (byte == '+') { state = 1; }
    else if (state == 1 && byte == 'I') { state = 2; }
    else if (state == 2 && byte == 'P') { state = 3; }
    else if (state == 3 && byte == 'D') { state = 4; }
    else if (state == 4 && byte == ',') {
      state = 0;
      handleIPDMessage();  // we received "+IPD,"
    }
    else { state = 0; }
}

You can see that handleIPDMessage() is called if and only if the last characters received were "+IPD,".

However, you should consider writing a more general state machine that would operate on lines instead of just looking for this one string. That would probably be easier to write and more robust. When a complete line is received, you would call a function named handleLineReceived() to handle that line. That function would have access to a buffer with the entire line, and it could parse it in whatever way it wants to. (Just be careful that you never write beyond the end of that buffer.)

By the way, I wouldn't be putting logic like that in an ISR. It's generally best to keep ISRs simple and fast. If you are not doing so already, store the byte to a circular buffer in the ISR and then read from the circular buffer in your main loop, and every time you read a byte from the circular buffer then call a function like the rx_data function described above to process the byte.