1
\$\begingroup\$

I am trying to implement input validation on the STM32 side. I am hoping to allow a string in the form "x\n" where "x" can be any character.

To receive a changing number of bytes I have implemented this in USART1_IRQHandler

void USART1_IRQHandler(void)
{
    if((USART1->ISR & USART_ISR_RXNE) != RESET) {
        if((1+RX_BUFFER_POS) < RX_BUFFER_SIZE) {
            UART_Buffer[1+RX_BUFFER_POS++] = USART1->RDR; // reading from DR resets RXNE flag, no need to manually clear it!
    }
  }
  HAL_UART_IRQHandler(&huart1);
}

And in the main while loop of the program

if((RX_BUFFER_POS + 1) >= 2) {
  if(UART_Buffer[1] == 0x0A && !(UART_Buffer[2])) {
    HAL_UART_Transmit_IT(&huart1, (uint8_t*)OK_BUFFER, OKBUFFERSIZE);
  } else {
    UART_Buffer[2] = 0;
    RX_BUFFER_POS = -1;
    HAL_UART_Transmit_IT(&huart1, (uint8_t*)BAD_BUFFER, BADBUFFERSIZE);
  }
RX_BUFFER_POS = -1;
}

The code correctly rejects an invalid character string, I use "00\n" as an example, the first time. After that all strings are rejected, including a "valid" ("x\n") string.

I did some debugging, and found that after an incorrect string, RX_BUFFER_POS was not being reset to -1, instead it stuck at 0. What is the cause of this? I also found that if I added a 1ms delay to the main while loop, the problem was fixed. This makes me suspect that some sort of race condition is occuring.

A side note, I found a way to fix any character being rejected. If I send a string of length 7, with "\n" being the last character the rejection will work once more. When I send the string I receive "BAD" and also "OK".

My question is why is RX_BUFF_POS not being reset to -1 when an incorrect string is received? Also, as there seems to be a race condition occuring, how can I track down the cause of this?

\$\endgroup\$
  • \$\begingroup\$ For this unique case, I'd be tempted to build a tiny state machine which would hold a received character in a static char temporarily and only write it to the buffer if the following newline is seen on the next interrupt, otherwise discard it. You could then go as far as to put the valid characters alone in the buffer, without the newlines, since only those so accompanied would get that far. But if your messages might ever need to become variable length, this optimization would not easily extend. \$\endgroup\$ – Chris Stratton Mar 7 '18 at 18:06
  • \$\begingroup\$ What you may not (yet) have noticed is that you 'RX_BUFFER_POS' is changed in both the ISR and in the main program but is not protected from interrupts in the latter. \$\endgroup\$ – Oldfart Mar 7 '18 at 18:53
1
\$\begingroup\$

How often does the main loop run? It's probably running so often that it runs between every character received by the UART. You are sending a three-character test message. After the first two characters are received the main loop performs the check and detects the invalid message. The main loop sets RX_BUFFER_POS to -1. But then the third character arrives and increments RX_BUFFER_POS to 0.

After you added the delay to the main loop, perhaps all three characters get received before the main loop performs the check. If the third character is received before the check then RX_BUFFER_POS will remain equal to -1 and it will appear to work.

When you sent a string of seven characters, I'll assume that it was seven characters followed by "\n". In this case the main loop checks after every two characters and discards the first six as invalid. Then the last character is received followed by the "\n" and that passes the check. I suspect that any odd length string will end with an "OK". And any even length string will end with RX_BUFFER_POS = to 0 instead of -1 because one extra character is received after the previous check fails.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.