linux下的串口通信类

来源:互联网 发布:公务员照片修改软件 编辑:程序博客网 时间:2024/06/05 09:26

    众所周知, 计算机内部CPU与接口之间是按并行方式进行工作的,而许多外设和计算机之间是按串行方式进行通信,所谓的串行方式,就是在一根传输线上一位一位的传送信息,所用的传输线少,并且可以借助现成的电话网进行信息传送,因此,特别适合于远距离传输.对于那些与计算机相距不远的人-机交换设备和串行存储的外部设备如终端、打印机、逻辑分析仪、磁盘等,采用串行方式交换数据也很普遍. 所以不要看不起串行通信,它是一种经典的传统的通信方式。网上用C写的串口通信程序很多,这里我用C++封装了一个类,并加入了自己写的日志操作。

/* 加入了日志功能,记录串口的状态信息及接收信息,对发送信息新建日志; 加入自动锁的功能,使主线程与接收线程和发送线程自动同步 */#ifndef MY_COM_H#define MY_COM_H#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <termios.h>#include <pthread.h>#include <sys/types.h>#include <sys/epoll.h>#include <errno.h>#include <fcntl.h>#include <time.h>#include "my_log/my_log.h"#include <string>#include <string.h>#include "my_locker/auto_lock.h"using namespace std;const int MAXREADLEN = 256;const int MAXSENDLEN = 256;const int MINSIZE = 256;     //the minsize  of g_bufferconst int MAXSIZE = 10240;   // the maxsize of g_bufferconst int SLEEPTIME = 60;const int SLEEPTINES = 5;enum mutex{    RDLK = 0,    WRLK = 1,};class My_com{public:    My_com();    My_com(char* log_path, char *log_name);    ~My_com();    int open_com(const int nport);    int set_com(const int baud_rate, const int data_bits,                char parity, const int stop_bits);    int read_com(int rdlen = MAXREADLEN);    int  write_com(int wrlen = MAXSENDLEN);    static void* read_thread_function(void*);    static void* send_thread_function(void*);    int create_read_thread();    int create_send_thread();    friend int parse(My_com *pcom, string &str);  //find the str betweeb '$' and '\n'    friend int send(My_com* , int fd, int wrlen = MAXSENDLEN);  //send to fd    char m_recv_buf[MAXREADLEN];    char m_send_buf[MAXSENDLEN];    pthread_t m_read_thrdID; //default two thread    pthread_t m_send_thrdID;    My_log *m_plog;private:    int m_port;};#endif // MY_COM_H
以下实现:
#include "my_com.h"string g_buffer;   //接收BUFFERMutex_locker g_locker;   //全局锁, 用于读写线程对全局BUFFER的加锁//Mutex_locker g_log_locker;My_com::My_com(){    this->m_read_thrdID = 0;    this->m_send_thrdID = 0;    this->m_port = 0;        memset(m_recv_buf, 0, sizeof(m_recv_buf));    memset(m_send_buf, 0 , sizeof(m_send_buf));        m_plog = new  My_log("./", "com_status.log");}My_com::My_com(char *log_path, char *log_name){    this->m_read_thrdID = 0;    this->m_send_thrdID = 0;    this->m_port = 0;    memset(m_recv_buf, 0, sizeof(m_recv_buf));    memset(m_send_buf, 0 , sizeof(m_send_buf));    m_plog = new My_log(log_path, log_name);}My_com::~My_com(){    if(close(m_port))    {        char msg[100] = {0};        sprintf(msg, "close port failed :%s\n", strerror(errno));        m_plog->write_log(msg, ERR);        exit(-1);    }    m_plog->write_log("close port done\n", INFO);    delete m_plog;}int My_com::open_com(const int nport){    char path_name[20];    if((nport < 0) || (nport > 3))    {        char msg[100] = {0};        sprintf(msg, "the port id [%d] is out of rang\n", nport);        m_plog->write_log(msg, ERR);        return -1;    }    sprintf(path_name, "/dev/ttyS%d", nport);    if(m_port != 0)    {        m_plog->write_log("the port is busying", ERR);        return -1;    }    if((m_port = open(path_name, O_RDWR | O_NOCTTY)) <= 0)    {        char msg[100] = {0};        sprintf(msg, "can not open port [%d]: %s \n", nport, strerror(errno));        m_plog->write_log(msg, ERR);        exit(-1);    }    if(!isatty(m_port))    {        m_plog->write_log("is not a terminal\n", ERR);    }    char msg[100] = {0};    sprintf(msg, "open port done, the port id is %d\n", m_port);    m_plog->write_log(msg, INFO);    return 0;}int My_com::set_com(const int baud_rate, const int data_bits, char parity, const int stop_bits){    struct termios newtio;    memset(&newtio,  0, sizeof(newtio));    if(tcgetattr(m_port, &newtio))    {        char msg[100] = {0};        sprintf(msg, "tcgetattr error : %s\n", strerror(errno));        m_plog->write_log(msg, ERR);        return -1;    }    m_plog->write_log("tcgetattr done\n", INFO);    //set data bits    newtio.c_cflag &= ~CSIZE;    switch(data_bits)    {    case 7:        newtio.c_cflag |= CS7;        break;    case 8:        newtio .c_cflag |= CS8;        break;    default:        newtio.c_cflag |= CS8;        break;    }    //set baud rate    switch (baud_rate)    {    case 2400:        cfsetispeed(&newtio, B2400);        cfsetospeed(&newtio, B2400);        break;    case 4800:        cfsetispeed(&newtio, B4800);        cfsetospeed(&newtio, B4800);        break;    case 9600:        cfsetispeed(&newtio, B9600);        cfsetospeed(&newtio, B9600);        break;    case 115200:        cfsetispeed(&newtio, B115200);        cfsetospeed(&newtio, B115200);        break;    default:        cfsetispeed(&newtio, B9600);        cfsetospeed(&newtio, B9600);    }    //set stop bits    switch (stop_bits)    {    case 1:        newtio.c_cflag |= ~CSTOPB;        break;    case 2:        newtio.c_cflag |= CSTOPB;        break;    default:        newtio.c_cflag |= ~CSTOPB;        break;    }    //set parity    switch (parity)    {    case 'O':        newtio.c_cflag |= PARENB;        newtio.c_cflag |= PARODD;        newtio.c_iflag |= (INPCK | ISTRIP);        break;    case 'E':        newtio.c_iflag |= (INPCK | ISTRIP);        newtio.c_cflag |= PARENB;        newtio.c_cflag &= ~PARODD;        break;    case 'N':        newtio.c_cflag &= ~PARENB;        newtio.c_cflag &= ~PARODD;        break;    }    newtio.c_cflag |= CLOCAL | CREAD;    newtio.c_cflag &= ~CRTSCTS;    //raw model    newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);    newtio.c_oflag &= ~OPOST;    newtio.c_iflag &= ~(INLCR|IGNCR|ICRNL);    newtio.c_iflag &= ~(ONLCR|OCRNL);    newtio.c_oflag &= ~(INLCR|IGNCR|ICRNL);    newtio.c_oflag &= ~(ONLCR|OCRNL);    //different from minicom set    newtio.c_cflag &= ~HUPCL;    newtio.c_iflag &= ~INPCK;    newtio.c_iflag |= IGNBRK;    newtio.c_iflag &= ~ICRNL;    newtio.c_iflag &= ~IXON;    newtio.c_lflag &= ~IEXTEN;    newtio.c_lflag &= ~ECHOK;    newtio.c_lflag &= ~ECHOCTL;    newtio.c_lflag &= ~ECHOKE;    newtio.c_oflag &= ~ONLCR;    //    newtio.c_cc[VMIN] = 1;    newtio.c_cc[VTIME] = 0;    tcflush(m_port, TCIOFLUSH);    if(tcsetattr(m_port, TCSANOW, &newtio))    {        char msg[100] = {0};        sprintf(msg, "tcsetattr error : %s\n", strerror(errno));        m_plog->write_log(msg, ERR);        return -1;    }    char msg[100];    sprintf(msg, "tcsetattr done, baud_rate:%d, data_bits:%d, parity:%c, stop_bit:%d\n", baud_rate, data_bits, parity, stop_bits);    m_plog->write_log(msg, INFO);}//@param read_len: read number one timeint My_com::read_com(int read_len){    static long int rdcnt = 0;    int rdlen = 0;    int len = 0;    if((m_recv_buf == NULL) || (read_len > MAXREADLEN))    {        m_plog->write_log("the recv_buf is null or out of range", ERR);        return -1;    }    m_plog->write_log("\nstarting recving.........", INFO);    do    {        while (true)        {            pthread_testcancel();    //set cancel state            rdlen = read(m_port, m_recv_buf+ len, read_len);            //m_plog->write_log(".", INFO);            pthread_testcancel();            len += rdlen;            if(len >= MAXREADLEN)            {                rdlen = 0;                break;            }        }        rdcnt += len;  //in all read        len = 0;        char msg[100] = {0};        sprintf(msg, "have read %ld : ", rdcnt);        m_plog->write_log(msg, INFO);        m_plog->write_log(m_recv_buf, INFO);        //m_plog->write_log("\n", INFO);    }while(false);}int My_com::write_com(int wrlen){    m_plog->write_log("\nstarting sending.........", INFO);    static long int sdcnt = 0;    int len = write(m_port, m_send_buf, wrlen);    sdcnt += len;    if(len <= 0)    {        char msg[100] = {0};        sprintf(msg, "send error: %s ", strerror(errno));        m_plog->write_log(msg, ERR);        return len;    }    char msg[100] = {0};    sprintf(msg, "have send %ld :", sdcnt);    m_plog->write_log(msg, INFO);    m_plog->write_log(m_send_buf, INFO);    //m_plog->write_log("\n", INFO);    return len;}void* My_com::read_thread_function(void *arg){    //My_log rd_thrd_log;    char msg[100];    sprintf(msg, "new read thead create, ID: %x", pthread_self());    //rd_thrd_log.write_log(msg, INFO)    My_com *pcom = (My_com*)arg;    int cnt_sleep = 0;    do    {        if(g_buffer.size() >= MAXSIZE)        {            sleep(SLEEPTIME);            ++cnt_sleep;            if(cnt_sleep >= SLEEPTINES)            {                break;            }        }        pthread_testcancel();  //set cancel point        pcom->read_com(1);        Auto_lock lock(g_locker);        g_buffer.append(pcom->m_recv_buf);    }while (true);    pthread_exit(NULL);}void* My_com::send_thread_function(void *arg){    My_com *pcom = (My_com*)arg;    int cnt_sleep = 0;    do    {        pthread_testcancel();    //set cancel point        if(g_buffer.size() <= MINSIZE)        {            sleep(SLEEPTIME);            ++cnt_sleep;            if(cnt_sleep >= SLEEPTINES)            {                break;            }        }        Auto_lock lock(g_locker);       cout<<g_buffer.size()<<endl;        parse(pcom, g_buffer);        cout<<g_buffer.size()<<endl;        pcom->write_com(MAXSENDLEN);        //pthread_testcancel();    }while(true);    pthread_exit(NULL);}int parse(My_com *pcom, string &str){    int start = 0;    int end = 0;    int len = 0;    start = str.find_first_of('$', 0);    end = str.find('\n', start);    len = end - start +1;    strncpy(pcom->m_send_buf, str.substr(start, end).c_str(), len);    str.erase(0, start + len);    //cout<<str.size()<<endl;}int My_com::create_read_thread(){    pthread_attr_t attr;    pthread_attr_init(&attr);    int res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);    res += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);    if(pthread_create(&m_read_thrdID, &attr, read_thread_function, (void*)this) != 0)    {        m_plog->write_log("create read thread error", ERR);        return -1;    }    return 0;}int My_com::create_send_thread(){    pthread_attr_t attr;    pthread_attr_init(&attr);    int res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);    res += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);    if(pthread_create(&m_read_thrdID, &attr, send_thread_function, (void*)this) != 0)    {        m_plog->write_log("create read thread error", ERR);        return -1;    }    return 0;}int send(My_com* pcom, int fd, int wrlen){    pcom->m_plog->write_log("\nstating sending.........", INFO);    static long int sdcnt = 0;    int len = write(fd, pcom->m_send_buf, wrlen);    sdcnt += len;    if(len <= 0)    {        char msg[100] = {0};        sprintf(msg, "send error: %s ", strerror(errno));        pcom->m_plog->write_log(msg, ERR);        return len;    }    char msg[100] = {0};    sprintf(msg, "have send %ld :", sdcnt);    pcom->m_plog->write_log(msg, INFO);    pcom->m_plog->write_log(pcom->m_send_buf, INFO);    //m_plog->write_log("\n", INFO);    return len;}

demo:

#include <iostream>#include "my_com.h"#include "my_locker/auto_lock.h"using namespace std;extern string g_buffer;extern Mutex_locker g_locker;     //lock the g_bufferextern Mutex_locker g_log_locker;bool rdstop_flag = false;bool wrstop_flag = false;int main(){    My_com com("./", "chen");    com.open_com(0);    com.set_com(9600, 8, 'N', 1);//    string buf;//    while(true)//    {//        com.read_com(1);//        buf.append(com.m_recv_buf);//    }    com.create_read_thread();    sleep(5);    com.create_send_thread();    sleep(10);    com.m_plog->write_log("will cancel read thread\n", INFO);    pthread_cancel(com.m_read_thrdID);    pthread_join(com.m_read_thrdID, NULL);    com.m_plog->write_log("cancel read thread done\n", INFO);    com.m_plog->write_log("will cancel send thread\n", INFO);    pthread_join(com.m_send_thrdID, NULL);    com.m_plog->write_log("cancel send thread done\n", INFO);    return 0;}


原创粉丝点击