基于MAC OSX的串口助手源代码讲解(上)

2017-09-26 08:19:52来源:CSDN作者:qq_33324878人点击

分享
网上对于mac的资料相对于windows和linux来比杯水车薪,博主在大学是从单片机学到了linux的应用开发,刚刚工作,主要方向是mac系统上的应用开发。博主是菜鸡一枚,但是愿意分享我写的代码,有大神来交流我很是欢迎。话不多说,先说一些基础的东西。首先mac osx和linux都属于从unix系统演变而来的,那么博主当时学习linux的时候看的书是《UNIX环境高级编程》,那么这里隐含的一个意思就是,书里面的大部分posix接口都是可以用的,最简单的open read write也是可以用的,并且OC里面的有的开源串口库的底层写函数也是用的write,由此可见,大部分的OC库里面也大量的封装了这些接口。底层部分不难实现,只是对于串口的一些配置,这部分的代码,我直接用的网上的现成代码,以前在linux写过,这里懒了就直接copy了。那么我先展示一下我在XCODE写串口助手的文件架构。![文件架构](http://img.blog.csdn.net/20170925184816913?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzMzMjQ4Nzg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)在有界面的编程世界中,MVC模式是流行的,也就是说,界面部分只负责处理控件。也就是MVC里的V,也就是view。而真正的难点在于contreller部分。这部分是负责界面控件与你底层数据结构之间的通讯。所以我的文件架构,就是底层的数据结构放在support文件里,而appdelete部分是界面部分的处理。前面也说了我底层代码这一部分是基于网上的代码改的,由于第一天发博客不知道怎么引用,所以这里跟原创道个歉。代码如下:
    ////  SeriportSetting.h//  SerialPort////  Created by gdlocal on 19/09/2017.//  Copyright © 2017 yang. All rights reserved.//#import <Foundation/Foundation.h>#import     <stdio.h>      /*标准输入输出定义*/#import     <stdlib.h>     /*标准函数库定义*/#import     <unistd.h>     /*Unix 标准函数定义*/#import     <sys/types.h>#import     <sys/stat.h>#import     "string.h"#import     <fcntl.h>      /*文件控制定义*/#import     <termios.h>    /*PPSIX 终端控制定义*/#import     <errno.h>      /*错误号定义*/@interface SeriportSetting : NSObject{@public    int SerialPort_fd;    NSString*DevName;    int speed;    int databits;    int stopbits;    char parity;}int OpenDev(char *DevName);void set_speed(int fd, int speed);int set_Parity(int SerialPort_fd,int databits,int stopbits,int parity);@end上面这部分代码我用的是OC与C的混合,定义了SeriportSetting类其实就是串口的底层函数封装。 ////  SeriportSetting.m//  SerialPort////  Created by gdlocal on 19/09/2017.//  Copyright © 2017 yang. All rights reserved.//#import "SeriportSetting.h"//#define FALSE  -1//#define TRUE   0int SerialPort_fd;@implementation SeriportSetting-(id)init{    self=[super init];    if(self)    {    }    return self;}int OpenDev(char *DevName){    SerialPort_fd = open(DevName, O_RDWR | O_NOCTTY );         //| O_NOCTTY | O_NDELAY    if (-1 == SerialPort_fd)    {        perror("Can't Open Serial Port");        return -1;    }    else        return SerialPort_fd;}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, };void set_speed(int fd, int speed){    int   i;    int   status;    struct termios   Opt;    tcgetattr(SerialPort_fd, &Opt);    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) {        if  (speed == name_arr[i]) {            tcflush(fd, TCIOFLUSH);            cfsetispeed(&Opt, speed_arr[i]);            cfsetospeed(&Opt, speed_arr[i]);            status = tcsetattr(SerialPort_fd, TCSANOW, &Opt);            if  (status != 0) {                perror("tcsetattr fd1");                return;            }            tcflush(SerialPort_fd,TCIOFLUSH);        }    }}int set_Parity(int SerialPort_fd,int databits,int stopbits,int parity){    struct termios options;    options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/    options.c_oflag  &= ~OPOST;   /*Output*/    if  ( tcgetattr(SerialPort_fd,&options)  !=  0) {        perror("SetupSerial 1");        return 0;    }    options.c_cflag &= ~CSIZE;    switch (databits) /*设置数据位数*/    {        case 7:            options.c_cflag |= CS7;            break;        case 8:            options.c_cflag |= CS8;            break;        default:           // fprintf(stderr,"Unsupported data size/n");            return 0;    }    switch (parity)    {        case 'n':        case 'N':            options.c_cflag &= ~PARENB;   /* Clear parity enable */            options.c_iflag &= ~INPCK;     /* Enable parity checking */            break;        case 'o':        case 'O':            options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/            options.c_iflag |= INPCK;             /* Disnable parity checking */            break;        case 'e':        case 'E':            options.c_cflag |= PARENB;     /* Enable parity */            options.c_cflag &= ~PARODD;   /* 转换为偶效验*/            options.c_iflag |= INPCK;       /* Disnable parity checking */            break;        case 'S':        case 's':  /*as no parity*/            options.c_cflag &= ~PARENB;            options.c_cflag &= ~CSTOPB;break;        default:            //fprintf(stderr,"Unsupported parity/n");            return 0;    }    /* 设置停止位*/    switch (stopbits)    {        case 1:            options.c_cflag &= ~CSTOPB;            break;        case 2:            options.c_cflag |= CSTOPB;            break;        default:           // fprintf(stderr,"Unsupported stop bits/n");            return 0;    }    /* Set input parity option */    if (parity != 'n')        options.c_iflag |= INPCK;    tcflush(SerialPort_fd,TCIFLUSH);    options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */    if (tcsetattr(SerialPort_fd,TCSANOW,&options) != 0)    {        perror("SetupSerial 3");        return 0;    }    return 1;}@end.m文件在OC里的意思是OC与C的混合文件,由于OC是完全兼容C的,所以熟悉C的朋友可以很快的上手。底层这部分代码主要是设置波特率,数据位,停止位,奇偶校验位。以及串口的打开操作,这部分只要是懂linux得朋友基本都能看懂,网上关于这部分的代码也是非常之多的。那么底层文件写完之后最主要的部分来了,就是界面部分。那么我先把我的xib文件的界面布局用图片表示出来。![界面布局](http://img.blog.csdn.net/20170925192849790?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzMzMjQ4Nzg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)    介绍完界面布局,我们重点来讲解一下界面是如何实现的。////  AppDelegate.h//  SerialPort////  Created by gdlocal on 19/09/2017.//  Copyright © 2017 yang. All rights reserved.//#import <Cocoa/Cocoa.h>#import "SeriportSetting.h"#import <CoreLib/SerialportEx.h>@interface AppDelegate : NSObject<NSApplicationDelegate>      IBOutlet NSComboBox * Stopbits;    IBOutlet NSComboBox * Databits;    IBOutlet NSComboBox * Burrate;    IBOutlet NSButton * Check;    IBOutlet NSButton *Open;    IBOutlet NSComboBox * Device;    IBOutlet NSButton *Close;    IBOutlet NSButton *Send;    IBOutlet NSTextField * Sendbuffer;    IBOutlet NSButton *Add;    IBOutlet NSButton *RepelyReceive;    IBOutlet NSTextView *My_textView;    IBOutlet NSComboBox *AddComBox;    IBOutlet NSButton *add;    NSMutableDictionary *dicConfiguration;    SeriportSetting *My_Com;    NSMutableDictionary *dic;    SerialportEx* My_Scom;}-(IBAction)SetStopbits:(id)sender;-(IBAction)SetBuratte:(id)sender;-(IBAction)Close:(id)sender;-(IBAction)Send:(id)sender;-(IBAction)RepelyReceive:(id)sender;-(void)My_textView;-(IBAction)Open:(id)sender;-(IBAction)Setdatabit:(id)sender;-(IBAction)add:(id)sender;@end
网上串口助手的界面布局有很多,可以看出在所有的界面之中,波特率,停止位,数据位,校验位大多数都是以选择形式来提供的,所以这几个的控件我选的combox控件。开始,关闭,发送,加末尾换行符这些控件我选择了按钮,如果各位看官想直接COPY我代码去自己试试的时候一定要把 SerialportEx* My_Scom注释掉,这部分涉及的功能可以先不写。用的是闭源的库。NSTextField控件表示得是文本编辑区,发送功能可以用这个控件,但是接收就不可以用了,因为一般的串口助手在接收的时候是要显示所有你收到的数据的,如果你再用NSTextField控件的话,你会发现在你收到第二次数据的时候,就会把第一次的数据覆盖了,但是OC的控件是丰富的。 NSTextView控件完美的解决了这个问题。以后会讲。至于上面h文件的方法部分,都是设置以及action,方法名字也都是见名知意。所以就不多说了。下面来看实现的m文件。
#import "AppDelegate.h"#import "SeriportSetting.h"NSInteger addstate=0;@interface AppDelegate ()@property (weak) IBOutlet NSWindow *window;@end@implementation AppDelegate-(instancetype)init{    self=[super init];    if(self)    {        My_Com = [[SeriportSetting alloc]init];        dicConfiguration=[[NSMutableDictionary alloc]init];        My_Scom = [[SerialportEx alloc]init];        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];    }    return self;}- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{}- (void)applicationWillTerminate:(NSNotification *)aNotification {    // Insert code here to tear down your application}-(IBAction)SetStopbits:(id)sender{    NSInteger stopbits = [Stopbits intValue];    My_Com->stopbits = stopbits;}-(IBAction)Setdatabit:(id)sender{     NSInteger databits = [Databits intValue];     My_Com->databits=databits;}-(IBAction)SetBuratte:(id)sender{    NSInteger burrate = [Burrate intValue];    My_Com->speed =burrate ;}-(void)threadDemo{    ssize_t nread;    char buffer[1024];    BOOL notstop=true;      while (notstop)    {        memset(buffer, 0, sizeof(buffer));        nread = read(My_Com->SerialPort_fd, buffer, 1024);        if (nread>0)        {            NSString * str = [NSString stringWithUTF8String:buffer];            [self performSelectorOnMainThread: @selector(view:) withObject:str waitUntilDone:NO];        }        [NSThread sleepForTimeInterval:0.01];   }}-(IBAction)Open:(id)sender{    My_Com->DevName=[Device stringValue];    if([My_Com->DevName length]==0)    {        NSAlert *alert = [[NSAlert alloc] init];        [alert setMessageText:[NSString stringWithUTF8String:"Please Input your Seriport Name"]];        [alert setInformativeText:[NSString stringWithFormat:@"name is nil"]];        [alert setAlertStyle:NSAlertStyleWarning];        [alert runModal];        return;    }    My_Com->SerialPort_fd=OpenDev([My_Com->DevName UTF8String]);    if(My_Com->SerialPort_fd==-1)    {        NSAlert *alert = [[NSAlert alloc] init];        [alert setMessageText:[NSString stringWithUTF8String:"Open Serial error"]];        [alert setInformativeText:[NSString stringWithFormat:@"Unkown error"]];        [alert setAlertStyle:NSAlertStyleWarning];        [alert runModal];        return;    }    My_Com->parity='o';    set_speed(My_Com->SerialPort_fd, My_Com->speed);    set_Parity(My_Com->SerialPort_fd,My_Com->databits,My_Com->stopbits,My_Com->parity);    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadDemo) object:nil];    [thread start];}-(IBAction)Send:(id)sender{    NSString *str=[Sendbuffer stringValue];    if([str length]==0)    {        NSAlert *alert = [[NSAlert alloc] init];        [alert setMessageText:[NSString stringWithUTF8String:"Please Input "]];        [alert setInformativeText:[NSString stringWithFormat:@"Unkown error"]];        [alert setAlertStyle:NSAlertStyleWarning];        [alert runModal];        return;    }    if(addstate==1)    {        if([[AddComBox stringValue] isEqualToString:@"//n"])        {            NSString *str1=[str stringByAppendingString:@"/n"];            NSData* data = [str1 dataUsingEncoding:NSUTF8StringEncoding];            NSUInteger dataLen = [data length];            const char *dataBytes = (const char*)[data bytes];            write(My_Com->SerialPort_fd, dataBytes, dataLen);        }        else if ([[AddComBox stringValue] isEqualToString:@"//r//n"])        {            NSString *str1=[str stringByAppendingString:@"/r/n"];            NSData* data = [str1 dataUsingEncoding:NSUTF8StringEncoding];            NSUInteger dataLen = [data length];            const char *dataBytes = (const char*)[data bytes];            write(My_Com->SerialPort_fd, dataBytes, dataLen);        }        else if ([[AddComBox stringValue] isEqualToString:@"//r"])        {            NSString *str1=[str stringByAppendingString:@"/r"];            NSData* data = [str1 dataUsingEncoding:NSUTF8StringEncoding];            NSUInteger dataLen = [data length];            const char *dataBytes = (const char*)[data bytes];            write(My_Com->SerialPort_fd, dataBytes, dataLen);        }    else{        NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];        NSUInteger dataLen = [data length];        const char *dataBytes = (const char*)[data bytes];        write(My_Com->SerialPort_fd, dataBytes, dataLen);        }    }}-(IBAction)Close:(id)sender{    int fd=close(My_Com->SerialPort_fd);    if(fd==-1)    {        NSAlert *alert = [[NSAlert alloc] init];        [alert setMessageText:[NSString stringWithUTF8String:"Close error "]];        [alert setInformativeText:[NSString stringWithFormat:@"Unkown error"]];        [alert setAlertStyle:NSAlertStyleWarning];        [alert runModal];        return;    }}-(IBAction)add:(id)sender{    if([sender state])    {       addstate=1;    }}-(IBAction)Scanf:(id)sender{    [Device removeAllItems] ;    NSEnumerator *enumerator = [AMSerialPortList portEnumerator];    AMSerialPort *aPort;    while (aPort = [enumerator nextObject]) {        [Device addItemWithObjectValue:[aPort bsdPath]];    }    return ;}-(void)view:(NSString*)str{    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];    [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss.SSS : "];    NSUInteger length = 0;    NSAttributedString *theString;    NSRange theRange;    theString = [[NSAttributedString alloc] initWithString:str];    [[My_textView textStorage] appendAttributedString: theString];    length = [[My_textView textStorage] length];    theRange = NSMakeRange(length, 0);    [My_textView scrollRangeToVisible:theRange];}@end

界面部分的代码明天再讲,今天有点累了。谢谢各位看官!

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台