I rewrote the code for efficiency because in my case I want get the response ASAP after writing. So if the UART driver is a char device driver that I can control, I can use poll mode in some senario.
I'm not sure if the original seria driver is ok for all application cases because my application code is a very simple case : read after write in 1 thread.(1000000/8/N/2)
I designed a test case for 2 IMX6Q boards : dual ways 4000000/8/N/2
hardware:2 IMX6Q boards with rx/tx of UART1 connected
software:2 threads for read and write data, the data is made up of head/counts/tail. Counts will be checked in read thread and there is a sync mechanism that write is haused if 10 steps ahead of read operation.
The same error can be reproduced also about 1 error / 20millions test rounds.
Test code is listed below:
using std::cout;
using std::string;
#define START (static_cast<char>(0x7f))
unsigned long long g_revcount = 0;
int g_sendcount = 10;
void writeUart()
{
char wrbuf[1000];
std::ofstream log("wrlog", std::ofstream::app);
std::uniform_int_distribution<unsigned> u(2, 10);
std::default_random_engine e(std::time(0));
unsigned long long count = 0;
string data;
while (g_delay)
{
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
while (g_writeEnable)
{
if (g_sendcount > 0){
data = std::to_string(count);
int sample = u(e);
wrbuf[0] = START;
wrbuf[1] = data.size() + sample;
for (int i = 2; i < sample+2; ++i)
{
wrbuf[i] = '0';
}
for (int i = 0, j = 2 + sample; i < data.size(); ++i,++j)
{
wrbuf[j] = data.c_str()[i];
}
int size = write(g_fd, wrbuf, wrbuf[1] + 2);
if (count % 10000 == 0)
{
log << "writetest: count:" << data << " sendlength: " << size << std::endl;
log << "receive test: count:" << g_revcount << std::endl;
}
++count;
--g_sendcount;
}
else{
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}
}
void readUart()
{
int numflag = 1;
const int maxsize = 500;
char rdbuf[maxsize];
char handbuf[200];
std::ofstream log("log", std::ofstream::app);
int nget=0,nput = 0;
int ndata;
while (true)
{
try{
if (nput >= nget){
ndata = nput - nget;
}
else{
ndata = nput + maxsize - nget;
}
if (ndata > 0){
if (rdbuf[nget] != START){
log << "receive test: read head eror! count:" << g_revcount << std::endl;
cout << "receive test: read head eror! count:" << g_revcount << std::endl;
cout << "receive test: nget:" << nget << " nput:" << nput << std::endl;
g_writeEnable = false;
return;
}
int cmdlengpos = (nget + 1) % maxsize;
int cmdsize = rdbuf[cmdlengpos] + 2;
if (ndata > cmdsize){
for (int i = 0; i < cmdsize; ++i) {
handbuf[i] = rdbuf[nget];
++nget;
if (nget == maxsize) {
nget = 0;
}
}
string num(handbuf + 2, handbuf[1]);
if(numflag)
{
g_revcount = std::stoull(num);
cout << "find first message : " << g_revcount << std::endl;
numflag = 0;
}
else
{
if (g_revcount != std::stoull(num)) {
log << "receive test: count:" << g_revcount << " receive count:" << std::stoull(num) << " receive string:" << num << " count eror!" << std::endl;
//cout << "receive test: count:" << g_revcount << " receive count:" << std::stoull(num) << " receive string:" << num << " count eror!" << std::endl;
log << "receive test: nget:" << nget << " nput:" << nput << std::endl;
g_writeEnable = false;
cout << std::showbase;
for (int i = 0; i < maxsize; ++i)
{
//printf("%x ", rdbuf[i]);
cout << std::hex << rdbuf[i];
}
cout << std::noshowbase;
//printf("\n");
return;
}
}
++g_revcount;
g_sendcount = 5;
g_delay = false;
}
else{
throw int(ndata);
}
}
else{
throw int(ndata);
}
}catch(int&) {
int nread = read(g_fd, rdbuf + nput, maxsize - nput);
nput += nread;
if (nput == maxsize){
nput = 0;
}
// cout << "receive test: receive size :" << nread << std::endl;
}
}
}
int main(int argc, char *argv[])
{
char devname[1024];
sprintf(devname, "/dev/ttymxc%d", atoi(argv[1]));
mlockall(MCL_FUTURE | MCL_CURRENT);
if ((g_fd = open_port(devname)) < 0) {
perror("open_port error");
return -1;
}
if ( set_opt(g_fd, atoi(argv[2]), 8, 'N', 1) < 0) {
perror("set_opt error");
return -1;
}
auto rd = std::async(std::launch::async, readUart);
auto wt = std::async(std::launch::async, writeUart);
rd.get();
wt.get();
close(g_fd);
return 0;
}