串口通信跨平台

    xiaoxiao2021-03-25  104

    mac 下用python模拟串口

    #! /usr/bin/env python #coding=utf-8 import pty import os  import select import time def mkpty():     #     master1, slave = pty.openpty()     slaveName1 = os.ttyname(slave)     master2, slave = pty.openpty()     slaveName2 = os.ttyname(slave)     print '\nslave device names: ', slaveName1, slaveName2     return master1, master2 if __name__ == "__main__":     datasend = "jack.hong"      global data     master1, master2 = mkpty()     bl = True     while True:               rl, wl, el = select.select([master1, master2], [], [], 60)         for master in rl:               data = ""                                 if master==master1:                 data = os.read(master, 2048)                                 print "read from master1 %d len data." % len(data), data                                                                             os.write(master2, datasend)              else:                 #if bl == True:                 data = os.read(master, 2048)                  print "read from master2 %d len data." % len(data), data                                                      os.write(master1, datasend)                 bl = False                 #time.sleep(3)

    串口通信代码头文件

    #pragma once #include <thread> #include <string> #include <stdio.h> #include <stdlib.h> #ifdef WIN32 #include <windows.h> #else #include <fcntl.h> #include <unistd.h> #include <termios.h> #include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <errno.h> #include <sys/stat.h> #endif /* #include <winbase.h> #define NOPARITY            0 #define ODDPARITY           1 #define EVENPARITY          2 #define MARKPARITY          3 #define SPACEPARITY         4 #define ONESTOPBIT          0 #define ONE5STOPBITS        1 #define TWOSTOPBITS         2 */ struct SerialPortInfo{     std::string name;     unsigned int baudRate{9600};     unsigned int parity{'e'};     unsigned int dataBits{7};     unsigned int stopBits{1}; }; class BaseCom  { public: BaseCom(); virtual ~BaseCom(); public:     bool Connect(const SerialPortInfo& portinfo);     void Close();     bool IsOpen(); #ifdef WIN32 public: bool Connect(const std::string& portName, unsigned int baudRate = CBR_9600, unsigned int parity = NOPARITY, unsigned int dataBits = 8, unsigned int stopBits = ONESTOPBIT); bool Connect(int port, unsigned int baudRate = CBR_9600, unsigned int parity = NOPARITY, unsigned int dataBits = 8, unsigned int stopBits = ONESTOPBIT); protected: virtual bool OpenPort() = 0; void Init(); bool SetupPort(); void SetComPort(int port); bool SetState(int BaudRate, int ByteSize, int Parity, int StopBits); protected: volatile int _port;   volatile HANDLE _com_handle; char _com_str[20]; DCB _dcb;      COMMTIMEOUTS _co;  #else public: bool Connect(const std::string& portName, unsigned int baudRate = 9600, unsigned int parity = 'N', unsigned int dataBits = 8, unsigned int stopBits = 1); protected:     bool openLinuxPort(const SerialPortInfo& portinfo);     bool setLinuxPortOpt(const SerialPortInfo& portinfo); protected:     int _fdSerial{-1};     bool _isOpen{false}; #endif protected:     SerialPortInfo _portinfo; }; //ͬ������ #ifdef WIN32 class SyncCom : public BaseCom { public: SyncCom(); int Read(char *buf, int buf_len); int SendData(const char* buf, int buf_len); int SendData(const char* buf); protected: virtual bool OpenPort(); }; #endif //�첽���� typedef void(*RecvDataCallBack)(const std::string& data, void* context); class ASynCom : public BaseCom { public: ASynCom(); virtual ~ASynCom(); int Read(char* buf, int buf_len); bool SendData(const char* buf, int buf_len); bool SendData(const std::string& buf); void Start(); void Stop();     void SetRecvDataCallBack(RecvDataCallBack callback, void* context); protected: static void OnProcRecvData(void* context); #ifdef WIN32 protected:     virtual bool OpenPort(); protected: OVERLAPPED _ro, _wo; // �ص�I/O     OVERLAPPED _wait_o; //WaitCommEvent use #else     ssize_t readDataTty(int fd, char *rcv_buf, int TimeOut, int Len);     ssize_t sendDataTty(int fd, const char *send_buf, int Len);     void reInit(); #endif     bool _isExit = false; std::thread* _workThread = NULL; RecvDataCallBack _recvDataCallback = NULL; void* _recvDataContext = NULL; }; 串口通信代码CPP文件

    #include "SerialPort.h" #include <cassert> BaseCom::BaseCom() { #ifdef WIN32     Init(); #endif } BaseCom::~BaseCom() { Close(); } bool BaseCom::Connect(const SerialPortInfo& portinfo) { _portinfo = portinfo; #ifdef WIN32 return Connect(portinfo.name, portinfo.baudRate, portinfo.parity, portinfo.dataBits, portinfo.stopBits); #else        bool result{false};    result = openLinuxPort(_portinfo);    if(result)        result = setLinuxPortOpt(_portinfo);    return result; #endif } bool BaseCom::Connect(const std::string& portName, unsigned int baudRate, unsigned int parity, unsigned int dataBits, unsigned int stopBits) { #ifdef WIN32 int pos = portName.find("COM"); if (pos == std::string::npos){ printf("COM name is error. %s\n", portName.c_str()); return false; } std::string sport = portName.substr(pos + 3, portName.size()); int port = atoi(sport.c_str()); return Connect(port, baudRate, parity, dataBits, stopBits); #else         _portinfo.name = portName;     _portinfo.baudRate = baudRate;     _portinfo.parity = parity;     _portinfo.dataBits = dataBits;     _portinfo.stopBits = stopBits;     return Connect(_portinfo); #endif } #ifdef WIN32 bool BaseCom::Connect(int port, unsigned int baudRate, unsigned int parity, unsigned int dataBits, unsigned int stopBits) { if (port < 1 || port > 1024) return false; SetComPort(port); if (!OpenPort()) return false; if (!SetupPort()) return false; return SetState(baudRate, dataBits, parity, stopBits); } bool BaseCom::SetState(int BaudRate, int ByteSize, int Parity, int StopBits) {     if (IsOpen())     {         if (!GetCommState(_com_handle, &_dcb))             return false;         _dcb.BaudRate = BaudRate;         _dcb.ByteSize = ByteSize;         _dcb.Parity = Parity;         _dcb.StopBits = StopBits;         return SetCommState(_com_handle, &_dcb) == TRUE;     }     return false; } void BaseCom::Init() {     memset(_com_str, 0, 20);     memset(&_co, 0, sizeof(_co));     memset(&_dcb, 0, sizeof(_dcb));     _dcb.DCBlength = sizeof(_dcb);     _com_handle = INVALID_HANDLE_VALUE; } bool BaseCom::SetupPort() {     if (!IsOpen())         return false;     if (!SetupComm(_com_handle, 8192, 8192))         return false;     if (!GetCommTimeouts(_com_handle, &_co))         return false;     _co.ReadIntervalTimeout = 0xFFFFFFFF;     _co.ReadTotalTimeoutMultiplier = 0;     _co.ReadTotalTimeoutConstant = 0;     _co.WriteTotalTimeoutMultiplier = 0;     _co.WriteTotalTimeoutConstant = 2000;     if (!SetCommTimeouts(_com_handle, &_co))         return false;     if (!PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR))         return false;     return true; } void BaseCom::SetComPort(int port) {     char p[12];     _port = port;     strcpy_s(_com_str, "\\\\.\\COM");     _ltoa_s(_port, p, 10);     strcat_s(_com_str, p); } #else bool BaseCom::openLinuxPort(const SerialPortInfo& portinfo) {     _fdSerial = open(portinfo.name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);     if (-1 == _fdSerial)     {         printf("Can't Open %s Serial Port \n", portinfo.name.c_str());         return(false);     }     else     {         printf("open %s .....\n", portinfo.name.c_str());     }     if(fcntl(_fdSerial, F_SETFL, FNDELAY) < 0)//非阻塞,覆盖前面open的属性     {         printf("set %s noblock failed\n", _portinfo.name.c_str());     }     else{         printf("set %s noblock succ\n", _portinfo.name.c_str());     }      /*     int ifcntl = fcntl(_fdSerial, F_SETFL, 0); //阻塞     if (ifcntl < 0)     {         printf("fcntl %s  failed, result is %d!\n", portinfo.name.c_str(), ifcntl);     }     else     {         printf("fcntl %s succ, result is %d!\n", portinfo.name.c_str(), ifcntl);     }  */     if (isatty(STDIN_FILENO) == 0)     {         printf("%s is not a terminal device\n", portinfo.name.c_str());     }     else     {         printf("%s is a tty success!\n", portinfo.name.c_str());     }     printf("%s is open fdSerial = %d\n", portinfo.name.c_str(), _fdSerial);     return true; } bool BaseCom::setLinuxPortOpt(const SerialPortInfo& portinfo) {     int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, };     int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };     struct termios newtio, oldtio;     if (tcgetattr(_fdSerial, &oldtio) != 0)     {         printf("getSerial %s attr fail", portinfo.name.c_str());         return false;     }     bzero(&newtio, sizeof(newtio));     newtio.c_cflag |= CLOCAL | CREAD;     newtio.c_cflag &= ~CSIZE;              switch (portinfo.dataBits)     {         case 5:             newtio.c_cflag |= CS5;             break;         case 6:             newtio.c_cflag |= CS6;             break;         case 7:             newtio.c_cflag |= CS7;             break;         case 8:             newtio.c_cflag |= CS8;             break;         default:             printf("%s bits is not 7 or 8, please check", portinfo.name.c_str());             newtio.c_cflag |= CS8;             break;       }              switch (portinfo.parity)     {         case 'o':         case 'O':                     //奇校验             newtio.c_cflag |= PARENB;             newtio.c_cflag |= PARODD;             newtio.c_iflag |= (INPCK);             break;         case 'e':         case 'E':                     //偶校验             newtio.c_iflag |= (INPCK | ISTRIP);             newtio.c_cflag |= PARENB;             newtio.c_cflag &= ~PARODD;             break;         case 'n':         case 'N':                    //无校验             newtio.c_cflag &= ~PARENB;             newtio.c_iflag &= ~INPCK;             break;         case 's':         case 'S':             newtio.c_cflag &= ~PARENB; //清除校验位             newtio.c_cflag &= ~CSTOPB; //??????????????             newtio.c_iflag |= INPCK; //disable pairty checking             break;         default:             printf("%s Unsupported parity.\n", _portinfo.name.c_str());             return false;     }          for(auto i = 0; i < sizeof(speed_arr) / sizeof(int); i++)     {         if(portinfo.baudRate == name_arr[i])         {             tcflush(_fdSerial, TCIOFLUSH);             cfsetispeed(&newtio, speed_arr[i]);             cfsetospeed(&newtio, speed_arr[i]);             /*              TCSANOW:立即执行而不等待数据发送或者接受完成。              TCSADRAIN:等待所有数据传递完成后执行。              TCSAFLUSH:Flush input and output buffers and make the change              */             if ((tcsetattr(_fdSerial, TCSANOW, &newtio)) != 0)             {                 printf("%s set error", portinfo.name.c_str());                 return false;             }             tcflush(_fdSerial, TCIOFLUSH);             break;         }     }              if (portinfo.stopBits == 1)     {         newtio.c_cflag &= ~CSTOPB;     }     else if(portinfo.stopBits == 2)     {         newtio.c_cflag |= CSTOPB;     }     else     {         printf("%s Unsupported stopbits error", portinfo.name.c_str());         return false;     }          newtio.c_cflag |= IXON | IXOFF | IXANY;          newtio.c_cflag &= ~CSIZE;          newtio.c_oflag &= ~OPOST;          newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);          newtio.c_cc[VTIME] = 0;     newtio.c_cc[VMIN] = 0;     if( tcflush(_fdSerial, TCIOFLUSH) == -1)     {         printf(" %s  tcflush failed\n", portinfo.name.c_str());     }     printf("%s set done!\n", portinfo.name.c_str());     _isOpen = true;     return true; } #endif void BaseCom::Close() { #ifdef WIN32 if (IsOpen()) { CloseHandle(_com_handle); _com_handle = INVALID_HANDLE_VALUE; } #else     if (_fdSerial > 0)         close(_fdSerial); #endif } bool BaseCom::IsOpen() { #ifdef WIN32     return _com_handle != INVALID_HANDLE_VALUE; #else     return _isOpen; #endif } #ifdef WIN32 SyncCom::SyncCom() { } bool SyncCom::OpenPort() { if (IsOpen()) Close(); _com_handle = CreateFileA( _com_str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); return IsOpen(); } int SyncCom::Read(char* buf, int buf_len) { if (!IsOpen()) return 0; buf[0] = '\0'; COMSTAT  stat; DWORD error; if (ClearCommError(_com_handle, &error, &stat) && error > 0)  { PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); return 0; } unsigned long r_len = 0; buf_len = min(buf_len - 1, (int)stat.cbInQue); if (!ReadFile(_com_handle, buf, buf_len, &r_len, NULL)) r_len = 0; buf[r_len] = '\0';     return r_len; } int SyncCom::SendData(const char* buf, int buf_len) { if (!IsOpen() || !buf) return 0; DWORD    error; if (ClearCommError(_com_handle, &error, NULL) && error > 0)  PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR); unsigned long w_len = 0; if (!WriteFile(_com_handle, buf, buf_len, &w_len, NULL)) w_len = 0; return w_len; } int SyncCom::SendData(const char* buf) { return SendData(buf, strlen(buf)); }  #endif ASynCom::ASynCom() { #ifdef WIN32 memset(&_ro, 0, sizeof(_ro)); memset(&_wo, 0, sizeof(_wo)); _ro.hEvent = CreateEvent(NULL, true, false, NULL); assert(_ro.hEvent != INVALID_HANDLE_VALUE); _wo.hEvent = CreateEvent(NULL, true, false, NULL); assert(_wo.hEvent != INVALID_HANDLE_VALUE); memset(&_wait_o, 0, sizeof(_wait_o)); _wait_o.hEvent = CreateEvent(NULL, true, false, NULL); assert(_wait_o.hEvent != INVALID_HANDLE_VALUE); #endif } ASynCom::~ASynCom() {     Close(); #ifdef WIN32 if (_ro.hEvent != INVALID_HANDLE_VALUE) CloseHandle(_ro.hEvent); if (_wo.hEvent != INVALID_HANDLE_VALUE) CloseHandle(_wo.hEvent); if (_wait_o.hEvent != INVALID_HANDLE_VALUE) CloseHandle(_wait_o.hEvent); #endif } #ifdef WIN32 bool ASynCom::OpenPort() { #ifdef WIN32 if (IsOpen()) Close(); _com_handle = CreateFileA( _com_str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,  NULL ); return IsOpen();  #endif     return false; } #endif int ASynCom::Read(char* buf, int buf_len) { #ifdef WIN32 if (!IsOpen()) return 0; buf[0] = '\0'; COMSTAT  stat; DWORD error; if (ClearCommError(_com_handle, &error, &stat) && error > 0)  { PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR);  return 0; } if (!stat.cbInQue) return 0; unsigned long r_len = 0; buf_len = min((int)(buf_len - 1), (int)stat.cbInQue); if (!ReadFile(_com_handle, buf, buf_len, &r_len, &_ro))  { if (GetLastError() == ERROR_IO_PENDING)  { if (!GetOverlappedResult(_com_handle, &_ro, &r_len, false)) { if (GetLastError() != ERROR_IO_INCOMPLETE) r_len = 0; } } else r_len = 0; } buf[r_len] = '\0'; return r_len;  #else     return (int)readDataTty(_fdSerial, buf, 20, buf_len); //100 没有数据就等待100毫秒  #endif    } bool ASynCom::SendData(const char* buf, int buf_len) { #ifdef WIN32 if (!IsOpen()) return false; DWORD error; if (ClearCommError(_com_handle, &error, NULL) && error > 0)  PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR); unsigned long w_len = 0, o_len = 0; if (!WriteFile(_com_handle, buf, buf_len, &w_len, &_wo)){ if (GetLastError() != ERROR_IO_PENDING) return false; } return true; #else    ssize_t sendlen = sendDataTty(_fdSerial, buf, buf_len);    return sendlen != -1; #endif } bool ASynCom::SendData(const std::string& buf) { #ifdef WIN32 return SendData(buf.c_str(), buf.size()); #else     ssize_t sendlen = sendDataTty(_fdSerial, buf.c_str(), (int)buf.size());     return sendlen != -1; #endif } void ASynCom::SetRecvDataCallBack(RecvDataCallBack callback, void* context) { _recvDataCallback = callback; _recvDataContext = context; } void ASynCom::Start() { _isExit = false; _workThread = new std::thread(ASynCom::OnProcRecvData, this); } void ASynCom::Stop() { if (!_isExit && _workThread != NULL && _workThread->joinable()){ _isExit = true; #ifdef WIN32 TerminateThread(_workThread->native_handle(), 1); #endif if (_workThread->joinable()){ _workThread->join(); } delete _workThread; _workThread = NULL; } } void ASynCom::OnProcRecvData(void* context) { ASynCom *pcom = (ASynCom *)context; #ifdef WIN32 if (!SetCommMask(pcom->_com_handle, EV_RXCHAR | EV_ERR)) return; COMSTAT  stat; DWORD error; DWORD mask; DWORD length; while (!pcom->_isExit){ if (!WaitCommEvent(pcom->_com_handle, &mask, &pcom->_wait_o)) { if (GetLastError() == ERROR_IO_PENDING) { GetOverlappedResult(pcom->_com_handle, &pcom->_wait_o, &length, true); } } if (mask & EV_ERR)  ClearCommError(pcom->_com_handle, &error, &stat); if (mask & EV_RXCHAR)  { ClearCommError(pcom->_com_handle, &error, &stat); if (stat.cbInQue > 0){ char buf[1024] = { 0 }; int buflen = sizeof(buf); int r = pcom->Read(buf, buflen); if (r > 0){ std::string msg; msg.assign(buf, r); if (pcom->_recvDataCallback != NULL && !msg.empty()){ pcom->_recvDataCallback(msg, pcom->_recvDataContext); } else{ printf("SerialPort recv data:%s\n", msg.c_str()); } } } } } #else     char buf[1024] = { 0 };     int ibuflen = sizeof(buf)/ sizeof(char);     while (!pcom->_isExit)     {         memset(buf,0,ibuflen);                 int r = pcom->Read(buf, ibuflen);         if (r > 0)         {             std::string msg;             msg.assign(buf, r);             if (pcom->_recvDataCallback != NULL && !msg.empty())             {                 pcom->_recvDataCallback(msg, pcom->_recvDataContext);             }             else{                 if(!msg.empty())                     printf("%s recv data:%s\n", pcom->_portinfo.name.c_str(), msg.c_str());             }          }              } #endif } #ifndef WIN32 ssize_t ASynCom::readDataTty(int fd, char *rcv_buf, int TimeOut, int Len) {     if(!_isOpen)     {         if(Connect(_portinfo))         {             fd = _fdSerial;         }         else         {             return -1;         }     }     int retval;     fd_set rfds;     struct timeval tv;     ssize_t ret = 0, pos = 0;     tv.tv_sec = TimeOut / 1000;  //set the rcv wait time     tv.tv_usec = TimeOut % 1000 * 1000;  //100000us = 0.1s     FD_ZERO(&rfds);     FD_SET(fd, &rfds);     while (FD_ISSET(fd, &rfds))     {         FD_ZERO(&rfds);         FD_SET(fd, &rfds);              retval = select(fd + 1, &rfds, NULL, NULL, &tv);         if (retval == -1)         {             break;         }         else if (retval)         {             ret = read(fd, rcv_buf + pos, Len-pos);             if (-1 == ret)             {                 close(_fdSerial);                 _isOpen = false;                 break;             }             if (ret == 0) {                 break;             }             pos += ret;             if (Len <= pos)             {                 break;             }             FD_ZERO(&rfds);             FD_SET(fd,&rfds);             retval = select(fd+1,&rfds,NULL,NULL,&tv);             if(retval <= 0)             {                 break;             }         }         else         {             //printf("%s read data time out", _portinfo.name.c_str());             break;         }     }     return pos; } ssize_t ASynCom::sendDataTty(int fd, const char *send_buf, int Len) {     ssize_t ret;     if(!_isOpen)     {         if(Connect(_portinfo))             fd = _fdSerial;         else             return -1;     }     std::string sbuf;     sbuf.assign(send_buf, Len);     int pos = 0, ilen = (int)sbuf.size();     while(pos != ilen)     {         ret = write(fd, sbuf.c_str()+ pos, ilen-pos);         if (ret == -1)         {             //close(_fdSerial);             //_isOpen = false;             printf("%s write %s error \n", _portinfo.name.c_str(), sbuf.c_str());             return -1;         }         pos += ret;     }     return pos; } #endif

    测试程序代码

    //

    //  main.cpp

    //  SerialPort

    //

    //  Created by soft on 6/3/2017.

    //  Copyright © 2017 Reginald. All rights reserved.

    //

    #include <iostream>

    #include "SerialPort.h"

    static int com1count =0;

    static int com2count =0;

    static void senddata(ASynCom* com,conststd::string& msg,int* cont)

    {

        std::string temp;

        while (true) {

            (*cont)++;

            temp = msg + " times is " +std::to_string(*cont);

            com->SendData(temp);

            temp = "";

            usleep(800);

        }

    }

    void dohandleReadData(conststd::string& data,void* context)

    {

        SerialPortInfo* own =static_cast<SerialPortInfo*>(context);

        printf("[%s] %s", own->name.c_str(), data.c_str());

        

    }

    int main(int argc,constchar * argv[]) {

        SerialPortInfo Com1info;

        SerialPortInfo Com2info;

        Com1info.name ="/dev/ttys029";

        Com2info.name ="/dev/ttys030";

        ASynCom Com1;

        ASynCom Com2;

        Com1.SetRecvDataCallBack(dohandleReadData, &Com1info);

        Com2.SetRecvDataCallBack(dohandleReadData, &Com2info);

        if (Com1.Connect(Com1info) &&  Com2.Connect(Com2info))

        {

            Com1.Start();

            Com2.Start();

            std::thread tcom1(senddata, &Com1,"com1_AAAAA", &com1count);

            std::thread tcom2(senddata, &Com2,"com2_BBBBB", &com2count);

            if(tcom1.joinable())

                tcom1.join();

            if(tcom2.joinable())

                tcom2.join();

        }

        

        return0;

    }

    转载请注明原文地址: https://ju.6miu.com/read-20608.html

    最新回复(0)