I'm trying to check whether (and where) a substring ("DATA") is located in a big string (located in a buffer - linearBuffer) by strstr() function, but it doesn't seem to work and I don't know why eventhough my source string (located in the linearBuffer) in null terminated.
What really happended is that a ringbuffer (buf) fills with characters for every USART interrupt. Then, in some point of the code its content copied into a linear buffer (through ringBuff_to_linearBuff()) and I apply the strstr() function on it in order to find a wanted substring. The value that I get when the function strstr() returns is the value 244 and not the location of the substring eventhough I know its there from setting a breakpoint
** Note that my code is spread on many files so I tried to gather all question related code together.
#include <string.h>
#define BUFFER_SIZE 400
#define LINEAR_BUFFER_SIZE (BUFFER_SIZE+1)
#define WIFI_CMD_DATA "DATA"
typedef RingBuff_Data_t uint8_t;
typedef struct
{
RingBuff_Data_t Buffer[BUFFER_SIZE]; /**< Internal ring buffer data, referenced by the buffer pointers. */
RingBuff_Data_t* In; /**< Current storage location in the circular buffer */
RingBuff_Data_t* Out; /**< Current retrieval location in the circular buffer */
} RingBuff_t;
volatile RingBuff_t buf;
uint8_t linearBuffer[LINEAR_BUFFER_SIZE]="";
static inline void RingBuffer_Insert(RingBuff_t* const Buffer, const RingBuff_Data_t Data)
{
*Buffer->In = Data;
if (++Buffer->In == &Buffer->Buffer[BUFFER_SIZE])
Buffer->In = Buffer->Buffer;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
Buffer->Count++;
}
}
ISR(USART1_RX_vect)
{
//code to be executed when the rx pin of the USART receives a char
uint8_t c = UDR_N;
if (c != '\n')
RingBuffer_Insert(&buf,c);
else
RingBuffer_Insert(&buf,'\0');
}
void ringBuff_to_linearBuff(uint8_t linearBuffer[])
{
memset(linearBuffer,0,LINEAR_BUFFER_SIZE);
RingBuff_Data_t* tempIn = buf.In;
if (buf.Out < tempIn){
memcpy(linearBuffer, buf.Out, tempIn - buf.Out);
}
else if (buf.Out > tempIn){
size_t s1 = buf.Buffer + BUFFER_SIZE - buf.Out;
size_t s2 = buf.In - buf.Buffer;
memcpy(linearBuffer, buf.Out, s1);
memcpy(linearBuffer + s1, buf.Buffer, s2);
}
}
void main ()
{
uint8_t* linearBufferp;
while (1)
{
if (buf.Out != buf.In)
{
ringBuff_to_linearBuff(linearBuffer);
linearBufferp = strstr(linearBuffer, WIFI_CMD_DATA); // Checking if a new DATA msg from a client had arrived
if (linearBufferp != NULL)
{
//do something
}
}
}
}
When strstr
returns NULL it means that it didn't find the substring (and when that happens, the value it points to have no meaning at all, so forget about the 224).
So your question should be:
Why doesn't strstr find my substring?
When looking at the debug picture you posted, your linearBuffer
contains:
13
0
13
0
43
....
....
68 <---- This is what you want to find
65
....
However, there are multiple strings in your buffer:
13 <----- Start of first string
0 <----- End of first string
13 <----- Start of second string
0 <----- End of second string
43 <----- Start of thrid string
....
....
68 <---- This is what you want to find
65
....
strstr
will only search the first string. When strstr
sees the first 0
(index [1]), it returns NULL
because it didn't find what it was looking for.
In other words - strstr
never looks at the part of the buffer where the match is. It returns long before that.
So what's wrong with your code?
It is hard to say since you haven't posted a complete code base. So this is a guess. I think you receive a number of "newlines" in the form:
13 10 13 10
before the message. So you receive:
13 10 13 10 43 ...... 68 65 .....
Your ISR turns the 10
into 0
so the buffer becomes
13 0 13 0 43 ...... 68 65 .....
which is 3 strings instead of 1 string.
What to do?
Well, there could be several different solutions. The correct depends on your system requirements. A simple solution would be to skip the extra 13 0
before calling strstr
. Something like:
ringBuff_to_linearBuff(linearBuffer);
// Skip "13 0"
while (*linearBuffer == 13 && *(linearBuffer+1) == 0)
{
linearBuffer += 2;
}
linearBufferp = strstr(linearBuffer, WIFI_CMD_DATA);
Note: You should add some range check also so that linearBuffer
isn't incremented so much that you read out of bounds