列举 Mac 下可用的串列埠(Serial Port)
I/O 浏览工具
Mac下使用Objective-C来了解硬体资讯必需要依靠 IOKit Framework ,如果在还未写程式时也可以利用 IORegistry Explorer 看一下硬体资讯,要取得该工具程式的方法很多,如果您是开发者更可以在Downloads for Apple Developer取得工具 Hardwre Tools for Xcode ,其中内建许多硬体有关的资讯,包含了 IORegistry Explorer。
寻找可用的Serial Port
还未写程式之前,使用IORegistry Explorer 寻找可用的Serial Port,Mac上规范如果你的驱动是Serial Port的话,它的IOClass
必需为IOSerilaBSDClient
,利用此特性将寻找的关键字定为IOSerialBSDClient
:
上图中能看到符合的条件的数量有3,如此一来就取得可用的Serial Port,接下来就要使用IOKit Framework来完成。
使用IOKit
IOKit Framework 必需要先引用标头档:
//-----------start----------- #import <IOKit/IOKitLib.h> #import <IOKit/serial/IOSerialKeys.h> //------------end------------
依照先前工具操作方式,寻找IOSerialBSDClient
的程式如下:
//-----------start----------- CFMutableDictionaryRef keywordDict = IOServiceMatching(kIOSerialBSDServiceValue); // io_object_t port; io_iterator_t portIterator = 0; kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, keywordDict, &portIterator); if (result){ NSLog(@"Error getting for serial port"); return; } //------------end------------
- IOServiceMatching 使用它来产生要被寻找的关键字,它以字典的型式,所以可以输入多个条件
- io_iterator_t portIterator 存放列举资讯的变数
- IOServiceGetMatchingServices 当寻找到成立的条件时会将资料纪录并加入
portIterator
,portIterator
这是一个Iterator结构,必需要使用它提供的Function将内容列举。
上述程式最后确认result没问题的话就不会有Error getting for serial port
讯息,之后使用portIterator
将符合的条件内容显示:
//-----------start----------- while ((port = IOIteratorNext(portIterator))) { CFStringRef stringIOTTYBaseNameKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIOTTYBaseNameKey), kCFAllocatorDefault, 0); CFStringRef stringIOSerialBSDTypeKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIOSerialBSDTypeKey), kCFAllocatorDefault, 0); CFStringRef stringIOCalloutDeviceKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); CFStringRef stringIODialinDeviceKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, 0); NSLog(@"\r Name:%@ \r SerialBSDTypeKey:%@ \r CalloutDevice:%@ \r DialinDevice:%@",stringIOTTYBaseNameKey,stringIOSerialBSDTypeKey,stringIOCalloutDeviceKey,stringIODialinDeviceKey); // CFRelease(stringIOTTYBaseNameKey); CFRelease(stringIOSerialBSDTypeKey); CFRelease(stringIOCalloutDeviceKey); CFRelease(stringIODialinDeviceKey); IOObjectRelease(port); } //------------end------------
- IOIteratorNext 检查并取得符合条件的物件,在这里因为取得的都是
值
,还需要利用一些相关的Function取得资讯 - IORegistryEntryCreateCFProperty 取得的物件后,在其中取得所指定的资讯并会转换成Objective-C的NSString,上面例子取用四个栏位的资讯
依照<IOKit/serial/IOSerialKeys.h>
所提供能取得的资讯栏位如下:
/* Service Matching That is the 'IOProviderClass' */ #define kIOSerialBSDServiceValue "IOSerialBSDClient" /* Matching keys */ #define kIOSerialBSDTypeKey "IOSerialBSDClientType" /* Currently possible kIOSerialBSDTypeKey values. */ #define kIOSerialBSDAllTypes "IOSerialStream" #define kIOSerialBSDModemType "IOModemSerialStream" #define kIOSerialBSDRS232Type "IORS232SerialStream" // Properties that resolve to a /dev device node to open for // a particular service #define kIOTTYDeviceKey "IOTTYDevice" #define kIOTTYBaseNameKey "IOTTYBaseName" #define kIOTTYSuffixKey "IOTTYSuffix" #define kIOCalloutDeviceKey "IOCalloutDevice" #define kIODialinDeviceKey "IODialinDevice" // Property 'ioctl' wait for the tty device to go idle. #define kIOTTYWaitForIdleKey "IOTTYWaitForIdle"
最后程式执行的结果:
2014-05-05 17:13:35.924 GetSerialBSDService[29208:303] Name:Bluetooth-Incoming-Port SerialBSDTypeKey:IORS232SerialStream CalloutDevice:/dev/cu.Bluetooth-Incoming-Port DialinDevice:/dev/tty.Bluetooth-Incoming-Port 2014-05-05 17:13:35.925 GetSerialBSDService[29208:303] Name:Bluetooth-Modem SerialBSDTypeKey:IOModemSerialStream CalloutDevice:/dev/cu.Bluetooth-Modem DialinDevice:/dev/tty.Bluetooth-Modem 2014-05-05 17:13:35.925 GetSerialBSDService[29208:303] Name:HOLUX_M-241-SPPSlave SerialBSDTypeKey:IORS232SerialStream CalloutDevice:/dev/cu.HOLUX_M-241-SPPSlave DialinDevice:/dev/tty.HOLUX_M-241-SPPSlave 2014-05-05 17:13:35.926 GetSerialBSDService[29208:303] Name:usbserial SerialBSDTypeKey:IORS232SerialStream CalloutDevice:/dev/cu.usbserial DialinDevice:/dev/tty.usbserial
以测试环境中能看到执行结果列举了4个Serial Port,其中CalloutDevice
、DialinDevice
与Linux类似结构,它就是Serial周边存取的装置名称,我们执行命令查看一下:
ls -l /dev/cu* tty.*
命令结果:
crw-rw-rw- 1 root wheel 17, 1 5 5 09:52 /dev/cu.Bluetooth-Incoming-Port crw-rw-rw- 1 root wheel 17, 3 5 5 09:52 /dev/cu.Bluetooth-Modem crw-rw-rw- 1 root wheel 17, 5 5 5 09:52 /dev/cu.HOLUX_M-241-SPPSlave crw-rw-rw- 1 root wheel 17, 13 5 5 16:30 /dev/cu.usbserial crw-rw-rw- 1 root wheel 17, 0 5 5 09:52 /dev/tty.Bluetooth-Incoming-Port crw-rw-rw- 1 root wheel 17, 2 5 5 09:52 /dev/tty.Bluetooth-Modem crw-rw-rw- 1 root wheel 17, 4 5 5 09:52 /dev/tty.HOLUX_M-241-SPPSlave crw-rw-rw- 1 root wheel 17, 12 5 5 16:30 /dev/tty.usbserial
如果你要使用Serial Port就能在CalloutDevice
、DialinDevice
取得之后,使用Open/Read/Write的档案存取命令来对Serial Port操作。
程式内容:
//-----------start----------- - (void)runTest1 { CFMutableDictionaryRef keywordDict = IOServiceMatching(kIOSerialBSDServiceValue); // io_object_t port; io_iterator_t portIterator = 0; kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, keywordDict, &portIterator); NSLog(@"%i",result); if (result){ NSLog(@"Error getting for serial port"); return; } while ((port = IOIteratorNext(portIterator))) { CFStringRef stringIOTTYBaseNameKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIOTTYBaseNameKey), kCFAllocatorDefault, 0); CFStringRef stringIOSerialBSDTypeKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIOSerialBSDTypeKey), kCFAllocatorDefault, 0); CFStringRef stringIOCalloutDeviceKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); CFStringRef stringIODialinDeviceKey = (CFStringRef)IORegistryEntryCreateCFProperty(port, (__bridge CFStringRef)(NSString*)CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, 0); NSLog(@"\r Name:%@ \r SerialBSDTypeKey:%@ \r CalloutDevice:%@ \r DialinDevice:%@",stringIOTTYBaseNameKey,stringIOSerialBSDTypeKey,stringIOCalloutDeviceKey,stringIODialinDeviceKey); // CFRelease(stringIOTTYBaseNameKey); CFRelease(stringIOSerialBSDTypeKey); CFRelease(stringIOCalloutDeviceKey); CFRelease(stringIODialinDeviceKey); IOObjectRelease(port); } //CFRelease(keywordDict); } //------------end------------