MacOS开发 -- OC操作串口

MacOS上的串口访问,有2个用的比较多的框架,这两个框架功能都比较强大,但也都很大,很复杂

AMSerialPort、ORSSerialPort

参考这两个框架及其它  资料,经过详细了解,发现在MacOS上串口编程的核心部分就是对

两个部分内容的使用,这里简单总结了其具体过程

1.定义fileDescriptor

int fileDescriptor = 0

2.通过设备名字全称打开串口
假设串口名字为comDeviceName = @"/dev/cu.usbserial-ABCDEFG"

fileDescriptor = open([comDeviceName UTF8String], O_RDWR | O_NONBLOCK); 

fileDescriptor <= 0, 表示有串口打开失败,每次打开串口前,最好先检查fileDescriptor的状态

open-only flags 每种flags的含义及取值如下
#define O_RDONLY        0x0000          // open for reading only 只读
#define O_WRONLY        0x0001          // open for writing only 只写
#define O_RDWR          0x0002          // open for reading and writing 读写
#define O_ACCMODE       0x0003          // mask for above modes 综合以上模式
#define FREAD           0x0001
#define FWRITE          0x0002
#define O_NONBLOCK      0x0004          // no delay 无延迟
#define O_APPEND        0x0008          // set append mode 

3.设置端口初始化默认参数

struct termios term; //声明结构体
tcgetattr(fileDescriptor, &term); //获取端口的配置参数
cfmakeraw(&term);//设置为默认参数
term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //设置c_lflag local flag
tcsetattr(fileDescriptor, TCSANOW, &term); //TCSANOW将新的配置立即应用于端口,立即生效

term结构体的具体含义定义如下
struct termios {
    tcflag_t        c_iflag;        // input flags 
    tcflag_t        c_oflag;        // output flags 
    tcflag_t        c_cflag;        // control flags 
    tcflag_t        c_lflag;        // local flags 
    cc_t              c_cc[NCCS];     // control chars 
    speed_t         c_ispeed;       // input speed 
    speed_t         c_ospeed;       // output speed 
};

int     tcgetattr(fd, struct termios *);

将当前fileDescriptor的配置读取到结构体term中

void    cfmakeraw(struct termios *);
将终端设置为原始模式,该模式下所有的输入数据以字节为单位被处理
端口模式区分为Row mode或者line mode,row mode就是以字节为单位处理数据
在原始模式下,终端是不可回显的,而且所有特定的终端输入/输出模式不可用。
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;

term.c_lflag中各种flag的定义
 * 每种配置的具体含义定义如下:
 * "Local" flags - dumping ground for other state
 * Warning: some flags in this structure begin with
 * the letter "I" and look like they belong in the
 * input flag.
 *
#define ECHOKE          0x00000001      // visual erase for line kill 
#define ECHOE           0x00000002      // visually erase chars 
#define ECHOK           0x00000004      // echo NL after line kill 
#define ECHO            0x00000008      // enable echoing 
#define ECHONL          0x00000010      // echo NL even if ECHO is off 
#define ECHOPRT         0x00000020      // visual erase mode for hardcopy 
#define ECHOCTL         0x00000040      // echo control chars as ^(Char) 
#define ISIG            0x00000080      // enable signals INTR, QUIT, [D]SUSP 
#define ICANON          0x00000100      // canonicalize input lines 
#define ALTWERASE       0x00000200      // use alternate WERASE algorithm 
#define IEXTEN          0x00000400      // enable DISCARD and LNEXT 
#define EXTPROC         0x00000800      // external processing 
#define TOSTOP          0x00400000      // stop background jobs from output 
#define FLUSHO          0x00800000      // output being flushed (state) 
#define NOKERNINFO      0x02000000      // no kernel output from VSTATUS 
#define PENDIN          0x20000000      // XXX retype pending input (state) 
#define NOFLSH          0x80000000      // don't flush after interrupt 

int     tcsetattr(fd, int, const struct termios *);      将新的配置应用于端口
int值的定义:Commands passed to tcsetattr() for setting the termios structure.
#define TCSANOW         0               // make change immediate  立即生效
#define TCSADRAIN       1               // drain output, then change  输出完毕后改变
#define TCSAFLUSH       2               // drain output, flush input 输入/输出完毕
#define TCSASOFT        0x10            // flag - don't alter h.w. state 
 

4.波特率baudRate设置

常用的函数形式如下
speed_t cfgetispeed(const struct termios *);
speed_t cfgetospeed(const struct termios *);
int     cfsetispeed(struct termios *, speed_t);
int     cfsetospeed(struct termios *, speed_t);
int     tcgetattr(int, struct termios *);
int     tcsetattr(int, int, const struct termios *);
int     tcdrain(int) __DARWIN_ALIAS_C(tcdrain);
int     tcflow(int, int);
int     tcflush(int, int);
int     tcsendbreak(int, int);

void    cfmakeraw(struct termios *);
int     cfsetspeed(struct termios *, speed_t);

 


int     ioctl(int, unsigned long, ...);
函数返回值如果!=0表示设置参数失败

_IOW()的宏定义如下
#define _IOC(inout, group, num, len) \
    (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define _IO(g, n)        _IOC(IOC_VOID,    (g), (n), 0)
#define _IOR(g, n, t)     _IOC(IOC_OUT,    (g), (n), sizeof(t))
#define _IOW(g, n, t)     _IOC(IOC_IN,    (g), (n), sizeof(t))
// this should be _IORW, but stdio got there first 
#define _IOWR(g, n, t)    _IOC(IOC_INOUT,    (g), (n), sizeof(t))

//网上看了些例子,对于baudRate<115200的时候,可以直接按以下方式设置
tcgetattr(fileDescriptor, &term);
cfsetspeed(&term, baudRate); //设置波特率
tcsetattr(fileDescriptor, TCSANOW, &term);
//但是对于更高的波特率设置,他们采用的是ioctl()方式
ioctl(fileDescriptor, _IOW('T', 2, speed_t), &baudRate);

5.使用GCD技术后台读取数据

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT , 0), ^(){
        @autoreleasepool {//后台读取串口数据
            [self readDataInBackground];
        }
});

6.后台读取数据

-(void) readDataInBackground
{
    void *recvData = malloc(1024); //1024的容量
    //memory allocation,向系统申请分配指定size个字节的内存空间
    memset(recvData, 0, 1024); // 初始化recvData
    ssize_t length = 0; //实际读取到的字符字节数
    while (YES)
    {
        @autoreleasepool
        {
            if(fileDescriptor>0) //检查串口是否已经打开)
            {
                memset(recvData, 0, 1024); //每次读取数据前先清空
                length = read(fileDescriptor, recvData, 1024);//读取数据
                //read函数是阻塞型的,只有读取到数据了才运行到下边
                NSData *data = [NSData dataWithBytes: recvData length:length]; 
                //bytes转为data
                //读取到数据后可做进一步处理
                //参考AMSerialPort的做法,可使用delegate调用其它方法具体处理读取到的数据
            }
        }
    }
}

7.发送数据
发送数据主要使用中的write()函数
ssize_t     write(int __fd, const void * __buf, size_t __nbyte)
  函数返回值是真实发送了多少个byte的数据
  fd:file descriptor
  buf:发送数据的buf 通常为Byte或char型数组
  nbyte:表示number of byte,即表示几个字节
row mode下是一次发送1个字节数据,line mode下是一次性将所有数据发送出去

//假设要发送的数据定义为NSData *data
//line mode下发送数据为:
const char *dataBytes = (const char*)[data bytes];
write(fileDescriptor, dataBytes, [data length]);//发送所有数据
//row模式下发送数据为:
write(fileDescriptor, dataBytes++, 1); //一次发送1个byte的数据

 

你可能感兴趣的:(通信)