瀏覽代碼

Can now list available serial ports

Thomas Buck 9 年之前
父節點
當前提交
cf15fad9df

+ 6
- 0
SerialGamepad.xcodeproj/project.pbxproj 查看文件

@@ -8,6 +8,7 @@
8 8
 
9 9
 /* Begin PBXBuildFile section */
10 10
 		E9B6A1D21C1F623B00DA3C80 /* MainWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B6A1D11C1F623B00DA3C80 /* MainWindow.m */; };
11
+		E9B6A1D61C1F683300DA3C80 /* Serial.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B6A1D51C1F683300DA3C80 /* Serial.m */; };
11 12
 		E9F5FFB21C1F5E2B00AA4E3B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E9F5FFB11C1F5E2B00AA4E3B /* AppDelegate.m */; };
12 13
 		E9F5FFB51C1F5E2B00AA4E3B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E9F5FFB41C1F5E2B00AA4E3B /* main.m */; };
13 14
 		E9F5FFB71C1F5E2B00AA4E3B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E9F5FFB61C1F5E2B00AA4E3B /* Assets.xcassets */; };
@@ -17,6 +18,8 @@
17 18
 /* Begin PBXFileReference section */
18 19
 		E9B6A1D01C1F623B00DA3C80 /* MainWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainWindow.h; sourceTree = "<group>"; };
19 20
 		E9B6A1D11C1F623B00DA3C80 /* MainWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainWindow.m; sourceTree = "<group>"; };
21
+		E9B6A1D41C1F683300DA3C80 /* Serial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Serial.h; sourceTree = "<group>"; };
22
+		E9B6A1D51C1F683300DA3C80 /* Serial.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Serial.m; sourceTree = "<group>"; };
20 23
 		E9F5FFAD1C1F5E2B00AA4E3B /* SerialGamepad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SerialGamepad.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 24
 		E9F5FFB01C1F5E2B00AA4E3B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
22 25
 		E9F5FFB11C1F5E2B00AA4E3B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -62,6 +65,8 @@
62 65
 				E9F5FFB81C1F5E2B00AA4E3B /* MainMenu.xib */,
63 66
 				E9B6A1D01C1F623B00DA3C80 /* MainWindow.h */,
64 67
 				E9B6A1D11C1F623B00DA3C80 /* MainWindow.m */,
68
+				E9B6A1D41C1F683300DA3C80 /* Serial.h */,
69
+				E9B6A1D51C1F683300DA3C80 /* Serial.m */,
65 70
 				E9F5FFBB1C1F5E2B00AA4E3B /* Info.plist */,
66 71
 				E9F5FFB31C1F5E2B00AA4E3B /* Supporting Files */,
67 72
 			);
@@ -166,6 +171,7 @@
166 171
 				E9F5FFB51C1F5E2B00AA4E3B /* main.m in Sources */,
167 172
 				E9F5FFB21C1F5E2B00AA4E3B /* AppDelegate.m in Sources */,
168 173
 				E9B6A1D21C1F623B00DA3C80 /* MainWindow.m in Sources */,
174
+				E9B6A1D61C1F683300DA3C80 /* Serial.m in Sources */,
169 175
 			);
170 176
 			runOnlyForDeploymentPostprocessing = 0;
171 177
 		};

二進制
SerialGamepad.xcodeproj/project.xcworkspace/xcuserdata/thomas.xcuserdatad/UserInterfaceState.xcuserstate 查看文件


+ 5
- 0
SerialGamepad.xcodeproj/xcuserdata/thomas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 查看文件

@@ -0,0 +1,5 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Bucket
3
+   type = "1"
4
+   version = "2.0">
5
+</Bucket>

+ 6
- 2
SerialGamepad/AppDelegate.m 查看文件

@@ -7,20 +7,24 @@
7 7
 //
8 8
 
9 9
 #import "AppDelegate.h"
10
+#import "MainWindow.h"
10 11
 
11 12
 @interface AppDelegate ()
12 13
 
13
-@property (weak) IBOutlet NSWindow *window;
14
+@property (weak) IBOutlet MainWindow *window;
15
+
14 16
 @end
15 17
 
16 18
 @implementation AppDelegate
17 19
 
20
+@synthesize window;
21
+
18 22
 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)application {
19 23
     return YES;
20 24
 }
21 25
 
22 26
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
23
-    // Insert code here to initialize your application
27
+    [window populatePortList];
24 28
 }
25 29
 
26 30
 - (void)applicationWillTerminate:(NSNotification *)aNotification {

+ 15
- 9
SerialGamepad/Base.lproj/MainMenu.xib 查看文件

@@ -696,14 +696,6 @@
696 696
                             <action selector="createButtonPressed:" target="QvC-M9-y7g" id="Iff-L2-DFe"/>
697 697
                         </connections>
698 698
                     </button>
699
-                    <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5dN-Rl-Vkt">
700
-                        <rect key="frame" x="18" y="214" width="295" height="26"/>
701
-                        <popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="ofz-Zj-Lba">
702
-                            <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
703
-                            <font key="font" metaFont="menu"/>
704
-                            <menu key="menu" id="hsu-7G-Ltg"/>
705
-                        </popUpButtonCell>
706
-                    </popUpButton>
707 699
                     <levelIndicator verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Bo5-fb-a0u">
708 700
                         <rect key="frame" x="20" y="140" width="290" height="16"/>
709 701
                         <levelIndicatorCell key="cell" alignment="left" doubleValue="-511" minValue="-511" maxValue="511" warningValue="2000" criticalValue="2000" levelIndicatorStyle="continuousCapacity" id="xcx-tB-hUl"/>
@@ -728,6 +720,20 @@
728 720
                         <rect key="frame" x="20" y="20" width="290" height="16"/>
729 721
                         <levelIndicatorCell key="cell" alignment="left" doubleValue="-511" minValue="-511" maxValue="511" warningValue="2000" criticalValue="2000" levelIndicatorStyle="continuousCapacity" id="nfv-aV-cRB"/>
730 722
                     </levelIndicator>
723
+                    <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mvV-p0-WO6">
724
+                        <rect key="frame" x="18" y="214" width="295" height="26"/>
725
+                        <popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="p4h-ja-UZg">
726
+                            <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
727
+                            <font key="font" metaFont="menu"/>
728
+                            <menu key="menu" id="njN-zA-NVu">
729
+                                <items>
730
+                                    <menuItem title="Item 1" id="W0M-vU-Ybd"/>
731
+                                    <menuItem title="Item 2" id="SHC-AR-wFp"/>
732
+                                    <menuItem title="Item 3" id="PqD-oG-Ww4"/>
733
+                                </items>
734
+                            </menu>
735
+                        </popUpButtonCell>
736
+                    </popUpButton>
731 737
                 </subviews>
732 738
             </view>
733 739
             <connections>
@@ -739,7 +745,7 @@
739 745
                 <outlet property="level4" destination="txY-x4-Zyp" id="XfN-HH-2lT"/>
740 746
                 <outlet property="level5" destination="VyV-eY-7y9" id="Ea2-ot-aqN"/>
741 747
                 <outlet property="level6" destination="vCW-tD-iWD" id="Il2-Xb-sB9"/>
742
-                <outlet property="portList" destination="ofz-Zj-Lba" id="lNL-1h-cEf"/>
748
+                <outlet property="portList" destination="mvV-p0-WO6" id="TqL-rb-GiB"/>
743 749
             </connections>
744 750
             <point key="canvasLocation" x="598" y="439"/>
745 751
         </window>

+ 1
- 1
SerialGamepad/Info.plist 查看文件

@@ -21,7 +21,7 @@
21 21
 	<key>CFBundleSignature</key>
22 22
 	<string>????</string>
23 23
 	<key>CFBundleVersion</key>
24
-	<string>2</string>
24
+	<string>28</string>
25 25
 	<key>LSApplicationCategoryType</key>
26 26
 	<string>public.app-category.utilities</string>
27 27
 	<key>LSMinimumSystemVersion</key>

+ 3
- 1
SerialGamepad/MainWindow.h 查看文件

@@ -10,7 +10,7 @@
10 10
 
11 11
 @interface MainWindow : NSWindow
12 12
 
13
-@property (weak) IBOutlet NSPopUpButtonCell *portList;
13
+@property (weak) IBOutlet NSPopUpButton *portList;
14 14
 @property (weak) IBOutlet NSButton *connectButton;
15 15
 @property (weak) IBOutlet NSButton *createButton;
16 16
 @property (weak) IBOutlet NSLevelIndicator *level1;
@@ -20,4 +20,6 @@
20 20
 @property (weak) IBOutlet NSLevelIndicator *level5;
21 21
 @property (weak) IBOutlet NSLevelIndicator *level6;
22 22
 
23
+- (void)populatePortList;
24
+
23 25
 @end

+ 11
- 0
SerialGamepad/MainWindow.m 查看文件

@@ -8,12 +8,23 @@
8 8
 
9 9
 #import "MainWindow.h"
10 10
 
11
+#import "Serial.h"
12
+
11 13
 @implementation MainWindow
12 14
 
15
+@synthesize portList, connectButton, createButton, level1, level2, level3, level4, level5, level6;
16
+
13 17
 - (IBAction)connectButtonPressed:(id)sender {
14 18
 }
15 19
 
16 20
 - (IBAction)createButtonPressed:(id)sender {
17 21
 }
18 22
 
23
+- (void)populatePortList {
24
+    NSArray *ports = [Serial listSerialPorts];
25
+    
26
+    [portList removeAllItems];
27
+    [portList addItemsWithTitles:ports];
28
+}
29
+
19 30
 @end

+ 19
- 0
SerialGamepad/Serial.h 查看文件

@@ -0,0 +1,19 @@
1
+//
2
+//  Serial.h
3
+//  SerialGamepad
4
+//
5
+//  Created by Thomas Buck on 14.12.15.
6
+//  Copyright © 2015 xythobuz. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+
11
+@interface Serial : NSObject
12
+
13
++ (NSArray *)listSerialPorts;
14
+
15
+@end
16
+
17
+// Internal
18
+kern_return_t findSerialPorts(io_iterator_t *matches);
19
+kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceFilePath, CFIndex maxPathCount, CFIndex maxPathSize);

+ 135
- 0
SerialGamepad/Serial.m 查看文件

@@ -0,0 +1,135 @@
1
+//
2
+//  Serial.m
3
+//  SerialGamepad
4
+//
5
+//  For more informations refer to this document:
6
+//  https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html
7
+//
8
+//  Created by Thomas Buck on 14.12.15.
9
+//  Copyright © 2015 xythobuz. All rights reserved.
10
+//
11
+
12
+#import <IOKit/serial/IOSerialKeys.h>
13
+
14
+#import "Serial.h"
15
+
16
+@implementation Serial
17
+
18
++ (NSArray *)listSerialPorts {
19
+    // Get Iterator with all serial ports
20
+    io_iterator_t serialPortIterator;
21
+    kern_return_t kernResult = findSerialPorts(&serialPortIterator);
22
+    
23
+    // Create 2D array
24
+    char **portList;
25
+    portList = malloc(100 * sizeof(char *));
26
+    for (int i = 0; i < 100; i++) portList[i] = malloc(200 * sizeof(char));
27
+    
28
+    // Copy device name into C-String array
29
+    kernResult = getSerialPortPath(serialPortIterator, portList, 100, 200);
30
+    IOObjectRelease(serialPortIterator);
31
+    
32
+    // Copy contents into NSString Array
33
+    NSString *stringList[100];
34
+    NSUInteger realCount = 0;
35
+    while (portList[realCount] != NULL) {
36
+        stringList[realCount] = [NSString stringWithCString:portList[realCount] encoding:NSUTF8StringEncoding];
37
+        realCount++;
38
+    }
39
+    
40
+    // Destroy 2D array
41
+    for (int i = 0; i < 100; i++) free(portList[i]);
42
+    free(portList);
43
+    
44
+    // And return them as NSArray
45
+    return [[NSArray alloc] initWithObjects:stringList count:realCount];
46
+}
47
+
48
+@end
49
+
50
+kern_return_t findSerialPorts(io_iterator_t *matches) {
51
+    kern_return_t kernResult;
52
+    mach_port_t masterPort;
53
+    CFMutableDictionaryRef classesToMatch;
54
+    
55
+    kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
56
+    if (KERN_SUCCESS != kernResult) {
57
+        NSLog(@"IOMasterPort returned %d\n", kernResult);
58
+        return kernResult;
59
+    }
60
+    
61
+    // Serial devices are instances of class IOSerialBSDClient.
62
+    classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
63
+    if (classesToMatch == NULL) {
64
+        NSLog(@"IOServiceMatching returned a NULL dictionary.\n");
65
+    } else {
66
+        CFDictionarySetValue(classesToMatch,
67
+                             CFSTR(kIOSerialBSDTypeKey),
68
+                             CFSTR(kIOSerialBSDRS232Type));
69
+        
70
+        // Each serial device object has a property with key
71
+        // kIOSerialBSDTypeKey and a value that is one of
72
+        // kIOSerialBSDAllTypes, kIOSerialBSDModemType,
73
+        // or kIOSerialBSDRS232Type. You can change the
74
+        // matching dictionary to find other types of serial
75
+        // devices by changing the last parameter in the above call
76
+        // to CFDictionarySetValue.
77
+    }
78
+    
79
+    kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, matches);
80
+    if (KERN_SUCCESS != kernResult) {
81
+        NSLog(@"IOServiceGetMatchingServices returned %d\n", kernResult);
82
+        return kernResult;
83
+    }
84
+    
85
+    return kernResult;
86
+}
87
+
88
+kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceFilePath, CFIndex maxPathCount, CFIndex maxPathSize) {
89
+    io_object_t modemService;
90
+    kern_return_t kernResult = KERN_FAILURE;
91
+    CFIndex i = 0;
92
+    
93
+    while ((modemService = IOIteratorNext(serialPortIterator)) && (i < (maxPathCount - 1))) {
94
+        CFTypeRef   deviceFilePathAsCFString;
95
+        
96
+        // Get the callout device's path (/dev/cu.xxxxx).
97
+        // The callout device should almost always be
98
+        // used. You would use the dialin device (/dev/tty.xxxxx) when
99
+        // monitoring a serial port for
100
+        // incoming calls, for example, a fax listener.
101
+        
102
+        deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(modemService,
103
+                                                                   CFSTR(kIODialinDeviceKey),
104
+                                                                   kCFAllocatorDefault,
105
+                                                                   0);
106
+        if (deviceFilePathAsCFString) {
107
+            Boolean result;
108
+            
109
+            deviceFilePath[i][0] = '\0';
110
+            
111
+            // Convert the path from a CFString to a NULL-terminated C string
112
+            // for use with the POSIX open() call.
113
+            
114
+            result = CFStringGetCString(deviceFilePathAsCFString,
115
+                                        deviceFilePath[i],
116
+                                        maxPathSize,
117
+                                        kCFStringEncodingASCII);
118
+            CFRelease(deviceFilePathAsCFString);
119
+            
120
+            if (result) {
121
+                NSLog(@"BSD path: %s\n", deviceFilePath[i]);
122
+                i++;
123
+                kernResult = KERN_SUCCESS;
124
+            }
125
+        }
126
+        
127
+        // Release the io_service_t now that we are done with it.
128
+        
129
+        (void) IOObjectRelease(modemService);
130
+    }
131
+    
132
+    deviceFilePath[i] = NULL;
133
+    
134
+    return kernResult;
135
+}

Loading…
取消
儲存