Hi, I met a strange issue while communicating with Arduino Uno R3 serial port. Can you please help take a look? Thanks a lot.
In my use case, my host program on Ubuntu sends multiple commands to Arduino via serial port and reads responses from Arduino, via serial port also.
Arduino can successfully receive the 1st command and return the response. My host program on Ubuntu can receive the 1st response as expected.
However, when my host program sends the 2nd command, the communication always fails. Sometimes it looks like Arduino misses the 2nd command and sometimes host program cannot fetch the response.
My current workaround is to close and re-open the serial port in host program before sending the 2nd command. Then the communication runs well.
It is more strange that everything works well if I open a terminal tool to connect to Arduino and manually input those commands.
So I guess something is wrong in my host program or it doesn't match the implementation on Arduino side, for example timing or serial configuration.
May I ask for your suggestion to fix this issue?
My Arduino code is simplified as:
#define MAX_CMD_LEN 8
char cmd[MAX_CMD_LEN];
void setup(void)
{
Serial.begin(BAUD_RATE);
PRINTLN("Test board reset via Arduino");
...
}
void loop(void)
{
char in_ch = '\0';
static uint8_t idx = 0;
while (Serial.available() > 0) {
in_ch = Serial.read();
delay(1);
if (idx < MAX_CMD_LEN) {
if (idx == 0)
continue;
cmd[idx] = '\0';
idx = 0;
if (it is cmd1) {
cmd1_respond();
} else if (it is cmd2) {
cmd2_respond();
} else {
printf("wrong cmd\r\n");
}
} else {
cmd[idx] = in_ch;
idx++;
}
} else {
// Deal with buffer overflow
}
}
}
My host program running in Ubuntu
/* Send command */
static void tx_msg(int port, const char *cmd, size_t len)
{
char tx_msg[CMD_BUF_SIZE];
strncpy(tx_msg, cmd, len);
tx_msg[len] = '\r';
write(port, tx_msg, len + 1);
}
/* Receive response */
static int rx_msg(int port, char *msg, size_t size)
{
uint8_t nr_rd_byte;
int8_t i;
memset(msg, '\0', size);
nr_rd_byte = read(port, msg, size);
if (nr_rd_byte < 0)
return -1;
if (nr_rd_byte >= 2) {
/* Replace \r\n with \0 */
msg[nr_rd_byte - 2] = '\0';
msg[nr_rd_byte - 1] = '\0';
}
return 0;
}
int main(void) {
...
port_fd = open("/dev/ttyACM0", O_RDWR| O_NOCTTY | O_SYNC);
if (port_fd < 0)
...
memset(tty, 0, sizeof(tty));
if (tcgetattr(port, &tty) != 0)
...
/* Setup port. 8-N-1 */
tty->c_cflag &= ~PARENB;
tty->c_cflag |= CSTOPB;
tty->c_cflag &= ~CSIZE;
tty->c_cflag |= CS8;
/* Turn on READ & ignore ctrl lines (CLOCAL = 1) */
tty->c_cflag |= CREAD | CLOCAL;
/* Non-canonical mode */
tty->c_lflag &= ~ICANON;
/* Wait for up to 2s, returning as soon as any data is received. */
tty->c_cc[VTIME] = 20;
tty->c_cc[VMIN] = 0;
/* Baud rate */
cfsetspeed(tty, ARDUINO_BAUD_RATE);
/* Write back configuration */
if (tcsetattr(port, TCSANOW, tty) != 0)
...
/* Wait for a while.*/
sleep(2);
/* Send the 1st cmd */
tx_msg(port_fd, cmd1, strlen(cmd1));
/* Wait for the response of 1st cmd */
err = rx_msg(port_fd, msg, MSG_BUF_SIZE);
if (err)
...
sleep(2);
/* Send cmd2 */
tx_msg(port_fd, cmd2, strlen(cmd2));
/* Wait for the response of cmd2 */
err = rx_msg(port_fd, msg, MSG_BUF_SIZE);
if (err)
...
return 0;
}