三个星期后,我无法摆脱这个问题。 我在Ubuntu 18.04.3上运行以下代码,该代码成功将字符串发送到另一台设备。 当远程设备接收到该字符串时……它又发送回一个字符串……但是下面的代码(即使设置为1秒)在select()上超时。
当我注释掉select()而只是read()...也看不到任何数据吗?
它已经在三周前开始工作了……但是最近的代码更改使它崩溃了……我不知道为什么。 文件描述符上的write()如何可以从串行口中退出,但是使用相同文件描述符的select()和read()却什么也没回来。 我有第三台设备(一台带腻子的PC),因此可以看到线路上的所有内容。 这三个都在RS-485总线上。
任何其他与代码有关的问题将不胜感激!
谢谢!
// main.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <term.h>
#include <signal.h>
#include <sys/time.h>
#include "SER.h"
static
struct sigaction mySigActTerm;
volatile
int terminate = 0;
void terminateHandler(int signum, siginfo_t *info, void *ptr)
{
//------------------------------------------------------------
// set a flag here and get out.
terminate = 1;
}
int main()
{
int rtn;
pthread_t serialThdID;
SER* mySER;
//------------------------------------------------------------
// setup terminate signal
memset(&mySigActTerm, 0, sizeof(mySigActTerm));
mySigActTerm.sa_sigaction = terminateHandler;
mySigActTerm.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &mySigActTerm, NULL);
//------------------------------------------------------------
// initialize the serial port.
mySER = SERinit("/dev/ttyUSB0", 2);
if (mySER == NULL)
{
fprintf(stderr, "main() - SERinit() returned NULL");
exit(EXIT_FAILURE);
}
//------------------------------------------------------------
// start the serial thread.
rtn = pthread_create(&serialThdID, NULL, serialThread, mySER);
if(rtn == 0)
fprintf(stderr, "starting serial thread.\n");
else
{
fprintf(stderr, "main() - pthread_create() returned %d\n%s\n", rtn, strerror(errno));
free(mySER);
exit(EXIT_FAILURE);
}
//------------------------------------------------------------
// wait till serialThread() indicates it is running.
while (mySER->ThreadStatus != threadRuning)
{
fprintf(stderr, "waiting for thread running status.\n");
sleep(1);
}
//------------------------------------------------------------
// main loop here.
while (terminate == 0)
{
// do stuff here.
}
//------------------------------------------------------------
// tell the serial thread to stop.
mySER->ThreadCtrl = threadCtrlKill;
//------------------------------------------------------------
// verify serial thread is dead!
while (mySER->ThreadStatus != threadStopped)
{
}
//------------------------------------------------------------
// clean up.
SERclose(mySER);
free(mySER);
}
serialThread.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#include <term.h>
#include <inttypes.h>
#include "SER.h"
void* serialThread(void* arg)
{
char* rtn;
SER* mySER = arg;
mySER->tid = pthread_self();
mySER->ThreadStatus = threadRuning;
// thread Loop!
while(mySER->ThreadCtrl != threadCtrlKill)
{
rtn = SERwrapperFunc(mySER);
// code to print the response here
printf("%.*s\n", 8, rtn);
sleep(30);
}
mySER->ThreadStatus = threadStopped;
pthread_exit(NULL);
}
SERmaster.c
#define responseSize 4584
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
//#include <linux/serial.h>
//#include <aio.h>
#include <sys/time.h>
#include "SER.h"
// array used to get termios BAUD.
const
int BAUDarray[9] = { 0, // not used.
B4800, // 208
B9600, // 104
B19200, // 52
B38400, // 26
B57600, // 17.363636
B115200, // 8.727272
B230400, // 4.363636
B460800 // 2.181818
};
// delay (in uS) per character transmitted.
// 1 start, Even parity, 7bits, 1 stop.
// bit time (times 10 bits)
// Plus one bit time between characters.
const
int BAUDdelay[9] = { 0, // not used.
2288,
1144,
572,
286,
191,
96,
48,
24
};
static
char response[4584];
static
unsigned
int respIndex;
static
struct termios newtio, oldtio;
extern
volatile
int terminate;
static
int sendRecieve(SER* mySER, const char* msgBuffer, int msgCnt, int sendFlag, int receiveFlag)
{
int rtn;
char myChar;
fd_set myfds;
struct
timeval tm_out;
if (sendFlag == true)
{
while (1)
{
rtn = write(mySER->sfd, msgBuffer, msgCnt);
if (rtn == -1)
{
if (errno == EINTR)
{
fprintf(stderr, "sendRecieve() - write() EINTR !\n");
if (terminate == 1)
break; // deal with SIGTERM !
continue; // if not SIGTERM then retry.
}
else
{
fprintf(stderr, "sendRecieve() - write()\n%s\n", strerror(errno));
return EXIT_FAILURE;
}
}
else
{
if (rtn == msgCnt)
break;
else
{
fprintf(stderr, "sendRecieve() - write() returned less than msgCnt !\n");
return EXIT_FAILURE;
}
}
}
}
if (receiveFlag == true)
{
respIndex = 0;
while (1)
{
tm_out.tv_sec = 1;
tm_out.tv_usec = mySER->BAUDmult * msgCnt;
FD_ZERO(&myfds);
FD_SET(mySER->sfd, &myfds);
rtn = select(mySER->sfd + 1, &myfds, NULL, NULL, &tm_out);
if (rtn == 0)
{
fprintf(stderr, "sendRecieve() - select() timeout!\n");
return EXIT_FAILURE;
}
if (rtn == -1)
{
if (errno == EINTR)
{
fprintf(stderr, "sendRecieve() - select() EINTR !\n");
if (terminate == 1)
break;
continue;
}
else
{
fprintf(stderr, "sendRecieve() - select()\n%s\n", strerror(errno));
return EXIT_FAILURE;
}
}
while (1)
{
rtn = read(mySER->sfd, &myChar, 1);
if (rtn == -1)
{
if (errno == EINTR)
{
fprintf(stderr, "sendRecieve() - read() EINTR !\n");
if (terminate == 1)
break;
continue;
}
else
{
fprintf(stderr, "sendRecieve() - read()\n%s\n", strerror(errno));
return EXIT_FAILURE;
}
}
else
break;
response[respIndex] = myChar;
if (respIndex < responseSize - 1)
respIndex++;
else
break;
if (myChar == '\n')
return EXIT_SUCCESS;
}
}
fprintf(stderr, "sendRecieve() - select/read while loop Dumped (response frame too big)!!\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
char* SERwrapperFunc(SER* mySER)
{
char myCharArray[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
int myCharArrayCountToSend = sizeof(myCharArray);
sendRecieve(mySER, myCharArray, myCharArrayCountToSend, true, true);
return response;
}
void serPrint()
{
printf("NCCS = %d OLD: NEW:\n", NCCS);
printf("c_iflag - %08x %08x\n", oldtio.c_iflag, newtio.c_iflag);
printf("c_oflag - %08x %08x\n", oldtio.c_oflag, newtio.c_oflag);
printf("c_cflag - %08x %08x\n", oldtio.c_cflag, newtio.c_cflag);
printf("c_lflag - %08x %08x\n", oldtio.c_lflag, newtio.c_lflag);
printf("c_line - %08x %08x\n", oldtio.c_line, newtio.c_line);
printf("c_ispeed - %08x %08x\n", oldtio.c_ispeed, newtio.c_ispeed);
printf("c_ospeed - %08x %08x\n", oldtio.c_ospeed, newtio.c_ospeed);
printf("\n");
printf("VINTR - %02x %02x\n", oldtio.c_cc[VINTR], newtio.c_cc[VINTR]);
printf("VQUIT - %02x %02x\n", oldtio.c_cc[VQUIT], newtio.c_cc[VQUIT]);
printf("VERASE - %02x %02x\n", oldtio.c_cc[VERASE], newtio.c_cc[VERASE]);
printf("VKILL - %02x %02x\n", oldtio.c_cc[VKILL], newtio.c_cc[VKILL]);
printf("VEOF - %02x %02x\n", oldtio.c_cc[VEOF], newtio.c_cc[VEOF]);
printf("VTIME - %02x %02x\n", oldtio.c_cc[VTIME], newtio.c_cc[VTIME]);
printf("VMIN - %02x %02x\n", oldtio.c_cc[VMIN], newtio.c_cc[VMIN]);
printf("VSWTC - %02x %02x\n", oldtio.c_cc[VSWTC], newtio.c_cc[VSWTC]);
printf("VSTART - %02x %02x\n", oldtio.c_cc[VSTART], newtio.c_cc[VSTART]);
printf("VSTOP - %02x %02x\n", oldtio.c_cc[VSTOP], newtio.c_cc[VSTOP]);
printf("VSUSP - %02x %02x\n", oldtio.c_cc[VSUSP], newtio.c_cc[VSUSP]);
printf("VEOL - %02x %02x\n", oldtio.c_cc[VEOL], newtio.c_cc[VEOL]);
printf("VREPRINT - %02x %02x\n", oldtio.c_cc[VREPRINT], newtio.c_cc[VREPRINT]);
printf("VDISCARD - %02x %02x\n", oldtio.c_cc[VDISCARD], newtio.c_cc[VDISCARD]);
printf("VWERASE - %02x %02x\n", oldtio.c_cc[VWERASE], newtio.c_cc[VWERASE]);
printf("VLNEXT - %02x %02x\n", oldtio.c_cc[VLNEXT], newtio.c_cc[VLNEXT]);
printf("VEOL2 - %02x %02x\n", oldtio.c_cc[VEOL2], newtio.c_cc[VEOL2]);
printf("\n");
printf("\n");
}
SER* SERinit(const char* strPort, int myBAUD)
{
SER* mySER;
//------------------------------------------------------------
// create the global SER struct instance.
if ((mySER = malloc(sizeof(SER))) == NULL)
{
fprintf(stderr, "SERinit() - mySER malloc()\n%s\n", strerror(errno));
return NULL;
}
memset(mySER, 0, sizeof(SER));
//------------------------------------------------------------
// setup the BAUD.
mySER->BAUDindex = myBAUD;
mySER->BAUDvalue = BAUDarray[myBAUD];
mySER->BAUDmult = BAUDdelay[myBAUD];
//------------------------------------------------------------
// open the serial port.
mySER->sfd = open(strPort, O_RDWR | O_NOCTTY);
if (mySER->sfd < 0)
{
fprintf(stderr, "SERInit() - open()\n%s\n", strerror(errno));
free(mySER);
return NULL;
}
//------------------------------------------------------------
// save old port settings for when we exit.
tcgetattr(mySER->sfd, &oldtio);
//------------------------------------------------------------
// prepare the newtio struct with current settings.
newtio = oldtio;
//------------------------------------------------------------
// set BAUD
if (cfsetspeed(&newtio, B9600) != 0)//mySER->BAUDvalue
{
fprintf(stderr, "SERInit() - cfsetspeed()\n%s\n", strerror(errno));
free(mySER);
return NULL;
}
//------------------------------------------------------------
// set for non-canonical (raw).
cfmakeraw(&newtio);
newtio.c_cflag |= (CLOCAL | CREAD);
newtio.c_cflag &= ~(CRTSCTS | CSTOB)
// read() blocks until one char or until 100 mS timeout.
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 1;
// flush the toilet.
tcflush(mySER->sfd, TCIFLUSH);
// write new port settings.
tcsetattr(mySER->sfd, TCSANOW, &newtio);
serPrint();
return mySER;
}
void SERclose(SER* mySER)
{
// restore old port settings.
tcsetattr(mySER->sfd, TCSANOW, &oldtio);
close(mySER->sfd);
}
SER.h
#ifndef SER_H_
#define SER_H_
#define threadInit 0x00
#define threadStarting 0x01
#define threadRuning 0x02
#define threadFailed 0x03
#define threadStopped 0x0f
#define threadCtrlRestart 0xFE
#define threadCtrlKill 0xFF
#include <stdint.h>
#include <pthread.h>
typedef struct SER
{
int BAUDindex; // the BAUD rate.
int BAUDmult; // uS per character ... plus one bite time between characters.
// used as a multiplier used to calculate sleep times after write().
// (bit time x 10 bits) 71E.
int BAUDvalue; // array used to set termios BAUD and get BAUDmult.
// 4800 = 1 2080 uS
// 9600 = 2 1040
// 19,200 = 3 520
// 38,400 = 4 260
// 76,800 = 5 130
// 115,200 = 6 65
// 230,400 = 7 32.5
// 460,800 = 8 16.25
pthread_t tid; // Stores thread ID.
uint8_t ThreadStatus; // written only by thread.
uint8_t ThreadCtrl; // written only by main.
int sfd; // serial port file descriptor.
}SER;
char* SERwrapperFunc(SER* mySER);
SER* SERinit(const char* strPort, int myBAUD);
void SERclose(SER* mySER);
void* serialThread(void* arg);
#endif /* SER_H_ */
答案 0 :(得分:0)
感谢木屑,我发现了问题,并更正了其他问题!
最初的SERmaster.c被select()和read()丢弃,并带有最终的select(),由于消息结束时,由于没有其他串行数据,最终的select()当然会超时。
我以为select()仅触发一次并超时。
已更正SERmaster.c
#define responseSize 4584
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
//#include <linux/serial.h>
//#include <aio.h>
#include <sys/time.h>
#include "SER.h"
// array used to get termios BAUD.
const
int BAUDarray[9] = { 0, // not used.
B4800, // 208
B9600, // 104
B19200, // 52
B38400, // 26
B57600, // 17.363636
B115200, // 8.727272
B230400, // 4.363636
B460800 // 2.181818
};
// delay (in uS) per character transmitted.
// 1 start, Even parity, 7bits, 1 stop.
// bit time (times 10 bits)
// Plus one bit time between characters.
const
int BAUDdelay[9] = { 0, // not used.
2288,
1144,
572,
286,
191,
96,
48,
24
};
static
char response[4584];
static
unsigned
int respIndex;
static
struct termios newtio, oldtio;
extern
volatile
int terminate;
static
int sendRecieve(SER* mySER, const char* msgBuffer, int msgCnt, int sendFlag, int receiveFlag)
{
int rtn;
char myChar;
fd_set myfds;
struct
timeval tm_out;
if (sendFlag == true)
{
while (1)
{
rtn = write(mySER->sfd, msgBuffer, msgCnt);
if (rtn == -1)
{
if (errno == EINTR)
{
fprintf(stderr, "sendRecieve() - write() EINTR !\n");
if (terminate == 1)
break; // deal with SIGTERM !
continue; // if not SIGTERM then retry.
}
else
{
fprintf(stderr, "sendRecieve() - write()\n%s\n", strerror(errno));
return EXIT_FAILURE;
}
}
else
{
if (rtn == msgCnt)
break;
else
{
fprintf(stderr, "sendRecieve() - write() returned less than msgCnt !\n");
return EXIT_FAILURE;
}
}
}
}
if (receiveFlag == true)
{
for (int i = 0; i < responseSize; i++)
response[i] = '\0';
respIndex = 0;
// set our first select() time out for (x + 2) char times where x is what we sent via write().
tm_out.tv_sec = 0;
tm_out.tv_usec = mySER->BAUDmult * (msgCnt + 2);
while (1)
{
FD_ZERO(&myfds);
FD_SET(mySER->sfd, &myfds);
rtn = select(mySER->sfd + 1, &myfds, NULL, NULL, &tm_out);
if (rtn == 0)
{
fprintf(stderr, "sendRecieve() - select() timeout!\n");
return EXIT_FAILURE;
}
if (rtn == -1)
{
if (errno == EINTR)
{
if (terminate == 1)
{
fprintf(stderr, "sendRecieve() - select() EINTR, terminating!\n");
return EXIT_FAILURE;
}
fprintf(stderr, "sendRecieve() - select() EINTR, restarting, tm_out.tv_usec = %d, remaining = %ld\n", mySER->BAUDmult * msgCnt, tm_out.tv_usec);
continue;
}
else
{
fprintf(stderr, "sendRecieve() - select()\n%s\n", strerror(errno));
return EXIT_FAILURE;
}
}
// select() indicates ready for reading !!
while (1)
{
rtn = read(mySER->sfd, &myChar, 1);
if (rtn == -1)
{
if (errno == EINTR)
{
fprintf(stderr, "sendRecieve() - read() EINTR !\n");
if (terminate == 1)
return EXIT_FAILURE;
continue;
}
else
{
fprintf(stderr, "sendRecieve() - read()\n%s\n", strerror(errno));
return EXIT_FAILURE;
}
}
if (rtn == 0)
{
fprintf(stderr, "sendRecieve() - read() returned 0 yet select() reported ready for reading ??? should never see this !\n");
return EXIT_FAILURE;
}
// break from read while() loop to process the char.
break;
}// end read() while loop
// save the new char.
response[respIndex] = myChar;
// point to the nest storage location.
respIndex++;
if (myChar == '\n')
return EXIT_SUCCESS;
// are we pointing beyond max buffer size?
if (respIndex == responseSize)
{
fprintf(stderr, "sendRecieve() - exceeded response buffer size ... before message termination char!!\n");
return EXIT_FAILURE;
}
// set our next select() time out for 2 char times based on baud rate.
tm_out.tv_sec = 0;
tm_out.tv_usec = mySER->BAUDmult * 2;
}//end select() while loop
fprintf(stderr, "sendRecieve() - select/read outer while loop Dumped, should not see this ever !!\n");
return EXIT_FAILURE;
}// end if (receiveFlag == true)
return EXIT_SUCCESS;
}
char* SERwrapperFunc(SER* mySER)
{
char myCharArray[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
int myCharArrayCountToSend = sizeof(myCharArray);
sendRecieve(mySER, myCharArray, myCharArrayCountToSend, true, true);
return response;
}
void serPrint()
{
printf("NCCS = %d OLD: NEW:\n", NCCS);
printf("c_iflag - %08x %08x\n", oldtio.c_iflag, newtio.c_iflag);
printf("c_oflag - %08x %08x\n", oldtio.c_oflag, newtio.c_oflag);
printf("c_cflag - %08x %08x\n", oldtio.c_cflag, newtio.c_cflag);
printf("c_lflag - %08x %08x\n", oldtio.c_lflag, newtio.c_lflag);
printf("c_line - %08x %08x\n", oldtio.c_line, newtio.c_line);
printf("c_ispeed - %08x %08x\n", oldtio.c_ispeed, newtio.c_ispeed);
printf("c_ospeed - %08x %08x\n", oldtio.c_ospeed, newtio.c_ospeed);
printf("\n");
printf("VINTR - %02x %02x\n", oldtio.c_cc[VINTR], newtio.c_cc[VINTR]);
printf("VQUIT - %02x %02x\n", oldtio.c_cc[VQUIT], newtio.c_cc[VQUIT]);
printf("VERASE - %02x %02x\n", oldtio.c_cc[VERASE], newtio.c_cc[VERASE]);
printf("VKILL - %02x %02x\n", oldtio.c_cc[VKILL], newtio.c_cc[VKILL]);
printf("VEOF - %02x %02x\n", oldtio.c_cc[VEOF], newtio.c_cc[VEOF]);
printf("VTIME - %02x %02x\n", oldtio.c_cc[VTIME], newtio.c_cc[VTIME]);
printf("VMIN - %02x %02x\n", oldtio.c_cc[VMIN], newtio.c_cc[VMIN]);
printf("VSWTC - %02x %02x\n", oldtio.c_cc[VSWTC], newtio.c_cc[VSWTC]);
printf("VSTART - %02x %02x\n", oldtio.c_cc[VSTART], newtio.c_cc[VSTART]);
printf("VSTOP - %02x %02x\n", oldtio.c_cc[VSTOP], newtio.c_cc[VSTOP]);
printf("VSUSP - %02x %02x\n", oldtio.c_cc[VSUSP], newtio.c_cc[VSUSP]);
printf("VEOL - %02x %02x\n", oldtio.c_cc[VEOL], newtio.c_cc[VEOL]);
printf("VREPRINT - %02x %02x\n", oldtio.c_cc[VREPRINT], newtio.c_cc[VREPRINT]);
printf("VDISCARD - %02x %02x\n", oldtio.c_cc[VDISCARD], newtio.c_cc[VDISCARD]);
printf("VWERASE - %02x %02x\n", oldtio.c_cc[VWERASE], newtio.c_cc[VWERASE]);
printf("VLNEXT - %02x %02x\n", oldtio.c_cc[VLNEXT], newtio.c_cc[VLNEXT]);
printf("VEOL2 - %02x %02x\n", oldtio.c_cc[VEOL2], newtio.c_cc[VEOL2]);
printf("\n");
printf("\n");
}
SER* SERinit(const char* strPort, int myBAUD)
{
SER* mySER;
//------------------------------------------------------------
// create the global SER struct instance.
if ((mySER = malloc(sizeof(SER))) == NULL)
{
fprintf(stderr, "SERinit() - mySER malloc()\n%s\n", strerror(errno));
return NULL;
}
memset(mySER, 0, sizeof(SER));
//------------------------------------------------------------
// setup the BAUD.
mySER->BAUDindex = myBAUD;
mySER->BAUDvalue = BAUDarray[myBAUD];
mySER->BAUDmult = BAUDdelay[myBAUD];
//------------------------------------------------------------
// open the serial port.
mySER->sfd = open(strPort, O_RDWR | O_NOCTTY);
if (mySER->sfd < 0)
{
fprintf(stderr, "SERInit() - open()\n%s\n", strerror(errno));
free(mySER);
return NULL;
}
//------------------------------------------------------------
// save old port settings for when we exit.
tcgetattr(mySER->sfd, &oldtio);
//------------------------------------------------------------
// prepare the newtio struct with current settings.
newtio = oldtio;
//------------------------------------------------------------
// set BAUD
if (cfsetspeed(&newtio, B9600) != 0)//mySER->BAUDvalue
{
fprintf(stderr, "SERInit() - cfsetspeed()\n%s\n", strerror(errno));
free(mySER);
return NULL;
}
//------------------------------------------------------------
// set for non-canonical (raw).
cfmakeraw(&newtio);
newtio.c_cflag |= (CLOCAL | CREAD);
newtio.c_cflag &= ~(CRTSCTS | CSTOPB);
// read() blocks until one char or until 100 mS timeout.
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 1;
// flush the toilet.
tcflush(mySER->sfd, TCIFLUSH);
// write new port settings.
tcsetattr(mySER->sfd, TCSANOW, &newtio);
serPrint();
return mySER;
}
void SERclose(SER* mySER)
{
// restore old port settings.
tcsetattr(mySER->sfd, TCSANOW, &oldtio);
close(mySER->sfd);
}