Mac串口助手源代码详解(下)

上篇博客我们讲了串口助手源码的思路及编程思想,那么这一篇我主要讲解我写串口助手界面的完整代码。

@implementation AppDelegate

-(instancetype)init

{

    self=[superinit];

    if(self)

    {

        My_Com = [[SeriportSettingalloc]init];

      }

    returnself;

}

	以上是我初始化的代码,这段代码重写了父类的init,但是这里的类型我用的是instancetype,这个类型相比于ID类型来说是一种优化写法,能让编译器迅速的知道我们的类属于什么类型的。具体的话可以百度一下,有许多博客和大神讲解的比我更加的清楚。那么在这里我们把我们所写的串口类进行了实例化。
	

-(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 ;

}

上段代码我实现了三个触发事件,分别是设置停止位,数据位和波特率,这三个控件我是用的Combox控件来实现的,那么在这些简单控件上,只要[(控件实例) 数据类型],以这种方式我们就可以获得Combox 乃至许多简单控件上的数据,所以当事件触发的时候,就把值赋予我们所定义的串口类的实例里的成员变量就好了。

-(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];

}

上面这段代码实现了打开串口的事件,这里使用的是按钮这个控件。由于我们需要在textField上写下我们串口的名字,其格式就是“/dev/...”,那么我们得到了这个字符串之后,需要进行判断,字符串的长度不能为空,所以我们判断字符串为空时,就弹出警告框, NSAlert 这个类就是警告框的应用,如果下次需要警告框,可以把我这段代码直接复制过去,你想提示什么讯息,就改变那两个字符串的内容,两个字符串,分别是大框的字符串和小框的字符串,大家自己去试的时候就知道了。
判断结束之后,我们需要用open 这个系统调用来打开文件,但是由于open的第一个参数是const char *类型,属于c语言的字符串类型,所以这里我们用NString里面的方法把我们所接收到的字符串进行格式转换。当fd也就是文件描述符为-1时,再次弹出警告框。接下来,就开始设置我们的串口数据,这里注意的一点是,在我写的这个应用程序里,是要先设置这些数据,在进行打开串口的操作。在函数的最后,我们开启了一个线程,因为读动作,需要一直不断的读串口的数据,所以但凡执行超过0.2秒的代码段我们都要开启线程。所以这里的线程为读操作的线程。其实也可以用pthread,这也是我更加习惯用的,因为之前一直在linux下写代码。

-(IBAction)add:(id)sender

{

    if([sender state])

    {

       addstate=1;

    }

}

上面这段代码的控件是一个勾选框,勾选框无非两种状态,一种是选中了,另一种是没有选中,那么在Cocoa框架里,参数sender里的state方法就可以判断勾选框是否勾选上了,当勾选框选上的时候,我们把addstate这个全局变量赋值为1,这里读者看了可能有些懵,这段代码是为了发送时的某一功能设定的,其实可以写的更优雅一些,但是本代码目的就是为了教会初学者,所以采用得是标志位的方式实现。下面来看发送函数的代码。

-(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);

        }

    }

}

上面这段代码就是发送函数,这个功能就是以textfeild和一个按钮控件,加上Combox,ComBox的作用是为了在发送的时候我们可以选择add不add一个/r/n,这样我们就可以选择我们发送过去的数据到底换行还是不换行。这也就是我们勾选框的目的。

当发送区的textfield被写上数据时,我们先判断他是否是空字符串,如果是空字符串,那么我们一样要弹出警告框。接下来就是判断全局的addstate是否为1,如果为1,我们判断Combox里的值是否为/r/n或者/r或者/n,如果都不是那么我们就直接发送,如果是那么就在字符串的后面加上,这里面是有坑的,读者看我的/r/n不是正常的。至于为什么自己思考一下。NSdata是比特流的意思。也就是串口接收的元数据流,这里其实也可以直接发送,但是这么写更加的安全一些。

-(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];

   }

}

-(void)view:(NSString*)str

{

    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];

}

上面这段代码结合起来实现了接收功能与视图的滚动显示。 [ self performSelectorOnMainThread : @selector (view:) withObject :str waitUntilDone : NO ];这句话的意思是刷新当前的界面,把数据传输到主线程里,如果不加这句话,你会发现,你的控件是不会更新数据的。

上述就是我串口助手源码重要部分的讲解,博主也实现了自动遍历当前可用串口功能,只是这部分的功能是基于第三方库实现的。所以这部分就不写上了,如果调试过程之中发现有乱码,大部分是设置数据错误,可能是参数没对,主要也可能是波特率的问题。希望大家看了我的博客,能自己写出自己的串口助手!

猜你喜欢

转载自blog.csdn.net/qq_33324878/article/details/78117340