USART not reading all modem responses - c

I send commands to the modem via USART1 and copy them to USART2. I copy the modem response to USART2. USART2 displays the modem's response to the first AT command (AT\r\n) "AT OK". The response to the second command (AT+CSCS?\r\n) is not displayed by USART2, or USART1 for some reason does not read the second response from the modem. Why? The code:
{
char Test[]="AT\r\n";
char Reply[]="";
char Text[]="Module Connected";
char Text1[]="SMS with GSM Module";
char Text2[]="Checking Module...";
char Text3[]="Module Unconnected";
char NewLine[]="\r\n";
char Line[]="--------------------------------------------";
uint8_t flag = 1;
uint8_t flag1=1;
char STM32Req[]="STM32 request: ";
char MdmAnswr[]="Modem Answer: ";
char GsmTest[6] = "AT\r\n";
char SmsEncoding[] = "AT+CSCS?\r\n";
/* Infinite loop */
for(;;)
{
HAL_UART_Transmit(&huart2, (uint8_t*)Text1, strlen(Text1), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
osDelay(500);
HAL_UART_Transmit(&huart2, (uint8_t*)Text2, strlen(Text2), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
osDelay(500);
while(flag==1){
HAL_UART_Transmit(&huart2, (uint8_t*)STM32Req, strlen(STM32Req), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)Test, strlen(Test), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, (uint8_t*)Test, strlen(Test), HAL_MAX_DELAY);
HAL_UART_Receive(&huart1, (uint8_t*)Reply, 10, 100);
osDelay(1000);
HAL_UART_Transmit(&huart2, (uint8_t*)MdmAnswr, strlen(MdmAnswr), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)Reply, 10, HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
osDelay(500);
if (strstr(Reply,"OK\r\n"))
{
HAL_UART_Transmit(&huart2, (uint8_t*)Text, strlen(Text), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
osDelay(500);
HAL_UART_Transmit(&huart2, (uint8_t*)Line, strlen(Line), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)Line, strlen(Line), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
osDelay(500);
flag=0;
}
}
}
while(flag1==1){
HAL_UART_Transmit(&huart2, (uint8_t*)STM32Req, strlen(STM32Req), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)SmsEncoding, strlen(SmsEncoding), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, (uint8_t*)SmsEncoding, strlen(SmsEncoding), HAL_MAX_DELAY);
HAL_UART_Receive(&huart1, (uint8_t*)Reply, 500, 100);
osDelay(1000);
HAL_UART_Transmit(&huart2, (uint8_t*)MdmAnswr, strlen(MdmAnswr), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)Reply, strlen(Reply), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)NewLine, strlen(NewLine), HAL_MAX_DELAY);
}
enter image description here

You have some things that are correct and some things that needs improvement or are wrong. The correct thing is to wait for a final result code like OK like you do, however you cannot wait for OK just some of the commands. You need to wait for a final result code from the modem every single time you send an AT command line. No exceptions! And also you need to check for more than just OK, there are several other final result codes like ERROR and more.
Also regarding how to receive data from the modem your attempt to read up till 10 bytes with HAL_UART_Receive into the Reply buffer of only size 1 will cause some memory corruption when more than one byte is read. That bug by itself makes all bets off with regards to behaviour since it is of type undefined behaviour (that phrase has very specific meaning in the C standard and is something that demands attention to avoid invoking).
But regardless, reading 10 bytes at the time is the wrong approach. The serial connection is just a stream of bytes with no inherent structure. I assume HAL_UART_Receive uses/implements a small (say 16 bytes) FIFO buffer, and exactly how bytes received on the wire are grouped and forwarded to your program code you do not know and you cannot depend on any specific behaviour here.
If the modem sends four bytes O, K, \r and \n, calling HAL_UART_Receive might return "OK\r\n" if you are lucky however it might also first return just "O" and then on the next call return "K\r\n".
This is perfectly valid behaviour by the USART and your code must be able to handle this. The simplest way to do this properly is to just read one character at the time and then copy that character into a temporary buffer until you have received a complete line of data because all responses (final and intermediate) ends with "\r\n", and then process that response line (where checking for if the line is a final result code is the first thing that should be done).
This problem is in data communication protocols known as framing. See this answer for some more information.
Related to what I wrote above about ALWAYS reading and parsing responses from the modem for every single command line send, your calls to osDelay must be thrown out and permanently banished to never return.
Your lack of waiting for a final result code from the modem before sending the next command line will likely trigger abort behaviour. Abortion of AT commands is defined in chapter "5.6.1 Aborting commands" in V.250.
So the answer to your "why" question is probably AT command abortion, but you have several issues you need to fix before you can have any hope of having reliable behaviour (and please do before asking a new question with the same unfixed code), so without those things fixed guesses of causes of problems are of little value.

Related

STM32 Nucleo-WL55JC1 UART reading wrong

I'm trying to read my GNSS module using STM32 Nucleo-WL55JC1. Here's my main loop code first
while (1)
{
uint8_t buff[500];
HAL_UART_Receive(&huart1, buff, strlen((char*)buff), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, buff, strlen((char*)buff), HAL_MAX_DELAY);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
When I run the code my serial monitor only print few messages and then it freezes
$PSTMVER,GNSSLIB_8.4.18.25_CP_ARM*07
$GPTXT,DEFAULT LIV3FL CONFIGURATION*12
$PSTMVER,OS20LIB_4.4.0_ARM*40
$PSTMVER,GPSAPP_2.11.0_CP_LIV3FL_RC9_ARM*20
$PSTMVER,BINIMG_4.6.15_CP_LIV3FL_RC9_ARM*27
Then I changed the receive timeout to 1000 it started outputing some NMEA data, but as you can see it mixed up with other messages
$PSTMCPU,20.86,-1,98*4F
$GPRMC,060732.000,V,0745.75046,S,11023.31916,E,,,071222,,,N*64 $GPGGA,060732.000,0745.75046,S,11023.31916,E,0,00,99.0,172.57,M,0.0,M11023.31916,E,060731.000,V,N*54
Then I unplugged and try to plug the MCU and now it only looping on this message
$PSTMVER,GPSAPP_2.11.0_CP_LIV3FL_RC9_ARM*20
$PSTMVPSTMVER,OS20LIB_4.4.0_ARM*40
$PSTMVER,GPSAPP_2.11.0_CP_LIV3FL_RC9_ARM*20
$PSTMVPSTMVER,OS20LIB_4.4.0_ARM*40
$PSTMVER,GPSAPP_2.11.0_CP_LIV3FL_RC9_ARM*20
$PSTMVPSTMVER,OS20LIB_4.4.0_ARM*40
I've tried using the same module on ESP it prints the message correctly
$PSTMCPU,21.69,-1,98*4F
$GPRMC,062153.000,V,0745.76371,S,11023.30606,E,,,071222,,,N*6C
$GPGGA,062153.000,0745.76371,S,11023.30606,E,0,02,99.0,189.71,M,0.0,M,,*77
$GPVTG,,T,,M,,N,,K,N*2C
$GNGSA,A,1,26,27,,,,,,,,,,,99.0,99.0,99.0*1F
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GPGSV,2,1,05,26,53,342,32,27,39,189,27,22,35,019,,23,14,149,*75
$GPGSV,2,2,05,21,07,251,,,,,,,,,,,,,*4E
$GLGSV,2,1,06,70,70,053,,74,33,309,,71,29,352,,69,26,142,27*6F
$GLGSV,2,2,06,80,15,158,,85,11,205,,,,,,,,,*69
$GPGLL,0745.76371,S,11023.30606,E,062153.000,V,N*5F
This is my first time using STM32 IDE and its HAL (I only use Arduino IDE before) so I kinda lost why my output is really different compared with the ESP.
Edit 1
As chux - Reinstate Monica's suggests I've modified the code to the following
uint8_t buff[500];
ret = HAL_UART_Receive(&huart1, buff, sizeof buff , HAL_MAX_DELAY);
while(ret != HAL_OK); // Continue when Receive returns HAL_OK
HAL_UART_Transmit(&huart2, buff, sizeof buff, HAL_MAX_DELAY);
The stuck problem is still there, but the output now changes to
$PSTMVER,GNSSLIB_8.4.18.25_CP_ARM*07
$GPTXT,DEFAULT LIV3FL CONFIGURATION*12
$PSTMVER,OS20LIB_4.4.0_ARM*40
$PSTMVER,GPSAPP_2.11.0_CP_LIV3FL_RC9_ARM*20
$PSTMVER,BINIMG_4.6.15_CP_LIV3FL_RC9_ARM*27
$PSTMVER,SWCFG_8306532d*33
$PSTMVER,STAGPSLIB_6.0.0_ARM*5A
$PSTMVER,STA8090_822bc043*61
$GPTXT,(C)2000-2018 ST Microelectronics*29
$GPTXT,DEFAULT LIV3FL CONFIGURATION*12
$PSTMSWCONFIG,1,0,12,000205f105070a0a0e0d0c0b0a090608070203630e110c04180c0155030110500f00000f071402050a40fffffffffffffffffffff (stuck here)
Reflashing without unplug and plugging the MCU
$GNGSA,A,3,03,16,32,27,26,22,,,,,,,1.9,1.0,1.6*26
$GNGSA,A,3,,,,,,,,,,,,,1.9,1.0,1.6*22
$GPGSV,3,1,10,16,58,305,23,27,53,179,23,32,47,086,23,22,46,034,22*72
$GPGSV,3,2,10,26,39,354,20,10,30,157,14,08,25,206,13,03,14,310,27*7B
$GPGSV,3,3,10,31,12,021,,21,10,237,,,,,,,,,*7E
$GLGSV,2,1,08,70,72,122,,71,48,350,,84,23,127,,74,22,326,*6C
$GLGSV,2,2,08,75,19,269,19,85,17,189,,69,11,151,18,80,11,144,19*6B
$GPGLL,0745.76098,S,11023.30836,E,065605.000,A,A*4D
$PSTMCPU,36.35,-1,98*40
$G (stuck here)
strlen((char*)buff) is invalid as the contents of buff are indeterminate.
Consider HAL_UART_Receive(&huart1, buff, sizeof buff, HAL_MAX_DELAY);
.. and use the return value of HAL_UART_Receive() to determine success level.
HAL_UART_Transmit() should only attempt to transmit the number of characters received, not strlen((char*)buff).

receiving part is not working well in TCP socket programming

I'm making a TCP socket programming.
client:
a client will receive a list of files from a server --> send a file name to the server --> receive the file from the server
My problems:
the server sends the list of files correctly. I printed out all and all of them are sent well. however, the client receives it well but while the loop isn't finished even if the server sending while loop is finished.
[client]
while ((read_cnt=read(sd, buf, BUF_SIZE)) != 0) {
read_cnt=read(sd, buf, BUF_SIZE);
printf("%s\n", buf);
}
[server]
while ((entry=readdir(dir)) != NULL) {
sprintf(buf, "%s\n", entry->d_name);
write(clnt_sd, buf, strlen(buf));
}
the server sends 17 messages but the client receives 15 messages and while loop is not finished. when while loop receives "finish", make client finishes the while loop --> still it receives 15 messages even if the server sent 17 messages.
[client]
while (1) {
read_cnt=read(sd, buf, BUF_SIZE);
fwrite((void*)buf, 1, read_cnt, fp);
printf("%s\n", buf);
if (strstr(buf, "fin") != NULL) {
break;
}
total_read += read_cnt;
pcnt = ((total_read/ file_size) * 100.0)/10;
printf("(%.0d %%) Send %.0f / %.0f bytes.\n", pcnt*10, total_read, file_size);
}
[server]
FILE *fp;
fp = fopen(file_name, "r");
if (fp == NULL) {
printf("File not Exist");
exit(1);
}
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
sprintf(buf, "%d", file_size);
write(clnt_sd, buf, read_cnt);
fseek(fp, 0, SEEK_SET);
while (feof(fp) == 0) {
read_cnt = fread((void*)buf, 1, BUF_SIZE, fp);
write(clnt_sd, buf, read_cnt);
}
fclose(fp);
I tried memset, bzero to make buffer empty but it didn't work.
I think the problem is the client part because when I checked server side by using print, they are sending well and finished the while loops. But I don't know what's the problem in receiving process on the client side. Please, Let me know what's the problem is.
the server sends 17 messages but the client receives 15 messages
Completely normal.
TCP is a stream protocol, not a message passing protocol. What you "send" on one side may not be the exact number of bytes received at the other end. You have to expect messages to arrive chunked, coalesced, or segmented between and within read/recv calls. You can't even assume that the initial "size" write you send as a 4-byte message is received within the same read call either as an entire message.
Implement your client side code to expect read and recv to return a random number of bytes up to the size of the buffer you pass in. If you get less bytes than expected, you need to make another read/recv call to receive the rest - adjusting your destination buffer pointer as needed. Or use the MSG_WAITALL flag with recv (instead of read) to get all the data in one call. You still need to check the result of the buffer to make sure you got the expected number of bytes, that the stream didn't close, and to validate that an error (-1 return) didn't occur.

Number of bytes recv()'d larger than the amount of data stored in the buffer?

My code looks something like this:
char buffer[BUFSIZE];
while (1) {
memset(buffer, 0, BUFSIZE);
ssize_t received = recv(csock, buffer, BUFSIZE, 0);
printf("Received %lu blen %lu\n", received, strlen(buffer));
...
}
Sometimes, the output of my printf statement is:
Received 1045 buffer GETFILE OK 233174
���� blen 25
How is this possible? If recv() store all the data it got in the buffer, shouldn't strlen(buffer) be the number of bytes received?
strlen counts the number of bytes until one of the bytes is 0.
It does not tell you how many bytes are received. That's just not what it does.
Only recv knows how many bytes it received.

C - Color characters in console window (Linux)

I'm building a server and client (chatroom) in Linux, and I want to colorize one word (the username) in the character buffer that echoes in the client. Here how the buffer is echoed when a user enters the chat:
strncpy(clients[clientIndex].username, buf, BUF_SIZE); // copy buffer to username
bzero(buf, BUF_SIZE); // zero out buffer
strncpy(buf, "User added to chat.", BUF_SIZE); // new user added
strncpy(buf, "Welcome, ", 9); // add welcome message to buffer
// concatenate so that the buffer reads "Welcome, [username]"
strncat(buf, clients[clientIndex].username, BUF_SIZE - 9);
The only method I know of coloring text is:
#define KMAG "\x1B[35m"
.
.
.
printf(KMAG "Welcome\n");
But obviously I am not using printf() since the server and client must send and receive these messages. I need a way to color only one word in the buffer. I imagine something that might look like this:
strcpy(clients[clientIndex].username, KMAG);
Where I can assign a color to characters themselves, and not just change the way it is printed.
Does such a method of coloring text exist?
EDIT: my mistake. I am using printf... just very unsure how to implement a color on certain characters in the buffer I am printing
This is how the code is printed in client:
void recvMessageFromServer() {
while (1) {
/* print the server's reply */
n = recvfrom(sockfd, buf, BUFSIZE, 0, (struct sockaddr *) &serveraddr,
&serverlen);
if (n < 0)
error("ERROR in recvfrom");
printf("%s\n", buf);
}
}
the server 'could' set the colors by:
strcat( buf, '%s", "\x1B[35m" );
strncat( buf, "clients[clientIndex].username, 9);
strcat( buf, "%s", "\x1b[30m" );
which will set the 'username' (limited to 9 characters) text to magneta, then set any following text to black

Unexpected value read from socket fd

Implementing a TCP server/client chat, I wanted to validate that the username of a new client doesn't exist already.
The server's code part is:
do
{
err=0;
if(write(socketFd[(int)idx], nickMsg, strlen(nickMsg))<0)
perror("write");
memset(buff, 0, sizeof(buff));
read(socketFd[(int)idx], buff, sizeof(buff));
for(i=0; i<supportedUsrsNum; i++)
{
if(*names[i]!=0)
{
if(strncmp(buff, names[i], strlen(buff))==0)
{
err=-1;
write(socketFd[(int)idx], usrExstMsg, strlen(usrExstMsg));
break;
}
}
}
if(!err)
break;
}
while(err==-1);
and the client writes:
do
{
gets(sendBuff);
write(sockFd, &sendBuff, sizeof(sendBuff));
sleep(1);
}while(1);
When the second client tries an existing name, the server detects it and goes for a second iteration, in which its read() gets an ASCII value of 3, though no further input occurred on the client side. What am I missing and how do I get to re-read a new value from the client?
It may be that the read() is not actually reading ASCII 3 but readings zero bytes. Perhaps an error condition occurred. Always check the return value of the call to read() since
It may return with a failure condition, or
It may read fewer than the requested number of bytes.
ALSO:
The client is sending the ENTIRE 'sendBuff' with this line:
write(sockFd, &sendBuff, sizeof(sendBuff));
where you probably want to only send the string itself (with some terminating character like '\0' or '\n'). Using sizeof(sendBuff) will send the actual text entered at gets(), the '\0' terminator, and then any random bytes that already existed in sendBuff before the call to gets().
Change that line to something like
write(sockFd, &sendBuff, strlen(sendBuff) + 1);
to write the text and the '\0' only, and not any extra garbage after it.
ALSO, don't use gets(). IT IS EVIL. (Thanks Jonathan Leffler for the reminder on this.)

Resources