Browse Source

Open and close selected port. Can now relist serial ports.

Thomas Buck 8 years ago
parent
commit
2c169110c1

+ 4
- 0
CaseLights/AppDelegate.h View File

@@ -8,6 +8,8 @@
8 8
 
9 9
 #import <Cocoa/Cocoa.h>
10 10
 
11
+@class Serial;
12
+
11 13
 @interface AppDelegate : NSObject <NSApplicationDelegate>
12 14
 
13 15
 @property (weak) IBOutlet NSMenu *statusMenu;
@@ -26,5 +28,7 @@
26 28
 
27 29
 @property (strong) NSDictionary *staticColors;
28 30
 
31
+@property (strong) Serial *serial;
32
+
29 33
 @end
30 34
 

+ 42
- 6
CaseLights/AppDelegate.m View File

@@ -26,8 +26,11 @@
26 26
 @synthesize buttonOff, buttonLights;
27 27
 @synthesize statusItem, statusImage;
28 28
 @synthesize staticColors;
29
+@synthesize serial;
29 30
 
30 31
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
32
+    serial = [[Serial alloc] init];
33
+    
31 34
     // Prepare status bar menu
32 35
     statusImage = [NSImage imageNamed:@"MenuIcon"];
33 36
     [statusImage setTemplate:YES];
@@ -138,12 +141,17 @@
138 141
             // Set Enabled if it was used the last time
139 142
             if ((savedPort != nil) && [[ports objectAtIndex:i] isEqualToString:savedPort]) {
140 143
                 [[menuPorts itemAtIndex:i] setState:NSOnState];
144
+                
145
+                // Try to open serial port
146
+                [serial setPortName:savedPort];
147
+                if ([serial openPort]) {
148
+                    // Unselect it when an error occured opening the port
149
+                    [[menuPorts itemAtIndex:i] setState:NSOffState];
150
+                }
141 151
             }
142 152
         }
143 153
     }
144 154
     
145
-    // TODO Open serial port, if it was already specified and found
146
-    
147 155
     // Restore previously used lights configuration
148 156
     if (turnOnLights) {
149 157
         // TODO Turn on lights
@@ -158,8 +166,27 @@
158 166
 }
159 167
 
160 168
 - (void)applicationWillTerminate:(NSNotification *)aNotification {
161
-    // TODO Close serial port, if it was specified and opened
162
-    
169
+    // Close serial port, if it was opened
170
+    if ([serial isOpen]) {
171
+        [serial closePort];
172
+    }
173
+}
174
+- (IBAction)relistSerialPorts:(id)sender {
175
+    // Refill port list
176
+    NSArray *ports = [Serial listSerialPorts];
177
+    [menuPorts removeAllItems];
178
+    for (int i = 0; i < [ports count]; i++) {
179
+        // Add Menu Item for this port
180
+        NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[ports objectAtIndex:i] action:@selector(selectedSerialPort:) keyEquivalent:@""];
181
+        [menuPorts addItem:item];
182
+        
183
+        // Mark it if it is currently open
184
+        if ([serial isOpen]) {
185
+            if ([[ports objectAtIndex:i] isEqualToString:[serial portName]]) {
186
+                [[menuPorts itemAtIndex:i] setState:NSOnState];
187
+            }
188
+        }
189
+    }
163 190
 }
164 191
 
165 192
 - (IBAction)turnLEDsOff:(NSMenuItem *)sender {
@@ -328,9 +355,18 @@
328 355
     // Select only the current port
329 356
     [source setState:NSOnState];
330 357
     
331
-    // TODO Close previously opened port, if any
358
+    // Close previously opened port, if any
359
+    if ([serial isOpen]) {
360
+        [serial closePort];
361
+    }
332 362
     
333
-    // TODO Try to open selected port
363
+    // Try to open selected port
364
+    [serial setPortName:[source title]];
365
+    if ([serial openPort] != 0) {
366
+        [source setState:NSOffState];
367
+    } else {
368
+        // TODO Restore the current configuration
369
+    }
334 370
 }
335 371
 
336 372
 - (IBAction)showAbout:(id)sender {

+ 6
- 0
CaseLights/Base.lproj/MainMenu.xib View File

@@ -710,6 +710,12 @@
710 710
                         </items>
711 711
                     </menu>
712 712
                 </menuItem>
713
+                <menuItem title="Relist Serial Ports" id="jVd-gl-Z6F">
714
+                    <modifierMask key="keyEquivalentModifierMask"/>
715
+                    <connections>
716
+                        <action selector="relistSerialPorts:" target="Voe-Tx-rLC" id="iFU-PL-xR8"/>
717
+                    </connections>
718
+                </menuItem>
713 719
                 <menuItem title="About CaseLights" id="GeK-ey-XEn">
714 720
                     <modifierMask key="keyEquivalentModifierMask"/>
715 721
                     <connections>

+ 1
- 1
CaseLights/Info.plist View File

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

+ 5
- 3
CaseLights/Serial.h View File

@@ -1,6 +1,6 @@
1 1
 //
2 2
 //  Serial.h
3
-//  SerialGamepad
3
+//  CaseLights
4 4
 //
5 5
 //  Created by Thomas Buck on 14.12.15.
6 6
 //  Copyright © 2015 xythobuz. All rights reserved.
@@ -10,11 +10,13 @@
10 10
 
11 11
 @interface Serial : NSObject
12 12
 
13
-@property int fd;
14 13
 @property (strong) NSString *portName;
15 14
 
16 15
 - (NSInteger)openPort;
17
-- (NSInteger)hasData;
16
+- (void)closePort;
17
+- (BOOL)isOpen;
18
+- (BOOL)hasData;
19
+- (void)sendString:(NSString *)string;
18 20
 
19 21
 + (NSArray *)listSerialPorts;
20 22
 

+ 82
- 14
CaseLights/Serial.m View File

@@ -1,6 +1,6 @@
1 1
 //
2 2
 //  Serial.m
3
-//  SerialGamepad / CaseLights
3
+//  CaseLights
4 4
 //
5 5
 //  For more informations refer to this document:
6 6
 //  https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html
@@ -21,13 +21,28 @@
21 21
 
22 22
 #import "Serial.h"
23 23
 
24
-kern_return_t findSerialPorts(io_iterator_t *matches);
25
-kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceFilePath, CFIndex maxPathCount, CFIndex maxPathSize);
24
+@interface Serial ()
25
+
26
+@property (assign) int fd;
27
+
28
++ (kern_return_t)findSerialPorts:(io_iterator_t *)matches;
29
++ (kern_return_t)getSerialPortPath:(io_iterator_t)serialPortIterator to:(char **)deviceFilePath with:(CFIndex)maxPathCount and:(CFIndex)maxPathSize;
30
+
31
+@end
26 32
 
27 33
 @implementation Serial
28 34
 
29 35
 @synthesize fd, portName;
30 36
 
37
+- (id)init {
38
+    self = [super init];
39
+    if (self != nil) {
40
+        fd = -1;
41
+        portName = nil;
42
+    }
43
+    return self;
44
+}
45
+
31 46
 - (NSInteger)openPort {
32 47
     // We need a port name
33 48
     if (portName == nil) {
@@ -36,11 +51,15 @@ kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceF
36 51
     }
37 52
     
38 53
     // Check if there was already a port opened
39
-    if (fd != -1) {
54
+    if (fd > -1) {
40 55
         NSLog(@"Closing previously opened serial port \"%@\"!\n", portName);
41 56
         close(fd);
42 57
     }
43 58
     
59
+#ifdef DEBUG
60
+    NSLog(@"Opening serial port \"%@\"...\n", portName);
61
+#endif
62
+    
44 63
     // Open port read-only, without controlling terminal, non-blocking
45 64
     fd = open([portName UTF8String], O_RDONLY | O_NOCTTY | O_NONBLOCK);
46 65
     if (fd == -1) {
@@ -84,21 +103,70 @@ kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceF
84 103
     return 0;
85 104
 }
86 105
 
87
-- (NSInteger)hasData {
106
+- (void)closePort {
107
+#ifdef DEBUG
108
+    NSLog(@"Closing serial port \"%@\"...\n", portName);
109
+#endif
110
+    
111
+    if (fd > -1) {
112
+        close(fd);
113
+    } else {
114
+        NSLog(@"Trying to close already closed port!\n");
115
+    }
116
+    fd = -1;
117
+}
118
+
119
+- (BOOL)isOpen {
120
+    if (fd > -1) {
121
+        return YES;
122
+    } else {
123
+        return NO;
124
+    }
125
+}
126
+
127
+- (BOOL)hasData {
128
+    if (fd < 0) {
129
+        NSLog(@"Error trying to poll a closed port!\n");
130
+        return NO;
131
+    }
132
+    
88 133
     struct pollfd fds;
89 134
     fds.fd = fd;
90 135
     fds.events = (POLLIN | POLLPRI); // Data may be read
91
-    if (poll(&fds, 1, 0) > 0) {
92
-        return 1;
136
+    int val = poll(&fds, 1, 0);
137
+    if (val > 0) {
138
+        return YES;
139
+    } else if (val == 0) {
140
+        return NO;
93 141
     } else {
94
-        return 0;
142
+        NSLog(@"Error polling serial port: %s (%d)!\n", strerror(errno), errno);
143
+        return NO;
144
+    }
145
+}
146
+
147
+- (void)sendString:(NSString *)string {
148
+    if (fd < 0) {
149
+        NSLog(@"Error trying to send to a closed port!\n");
150
+        return;
151
+    }
152
+    
153
+    const char *data = [string UTF8String];
154
+    size_t length = strlen(data);
155
+    ssize_t sent = 0;
156
+    while (sent < length) {
157
+        ssize_t ret = write(fd, data + sent, length - sent);
158
+        if (ret < 0) {
159
+            NSLog(@"Error writing to serial port: %s (%d)!\n", strerror(errno), errno);
160
+        } else {
161
+            sent += ret;
162
+        }
95 163
     }
96 164
 }
97 165
 
98 166
 + (NSArray *)listSerialPorts {
99 167
     // Get Iterator with all serial ports
100 168
     io_iterator_t serialPortIterator;
101
-    kern_return_t kernResult = findSerialPorts(&serialPortIterator);
169
+    kern_return_t kernResult = [Serial findSerialPorts:&serialPortIterator];
102 170
     
103 171
     // Create 2D array
104 172
     char **portList;
@@ -106,7 +174,7 @@ kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceF
106 174
     for (int i = 0; i < 100; i++) portList[i] = malloc(200 * sizeof(char));
107 175
     
108 176
     // Copy device name into C-String array
109
-    kernResult = getSerialPortPath(serialPortIterator, portList, 100, 200);
177
+    kernResult = [Serial getSerialPortPath:serialPortIterator to:portList with:100 and:200];
110 178
     IOObjectRelease(serialPortIterator);
111 179
     
112 180
     // Copy contents into NSString Array
@@ -125,9 +193,7 @@ kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceF
125 193
     return [[NSArray alloc] initWithObjects:stringList count:realCount];
126 194
 }
127 195
 
128
-@end
129
-
130
-kern_return_t findSerialPorts(io_iterator_t *matches) {
196
++ (kern_return_t)findSerialPorts:(io_iterator_t *)matches {
131 197
     kern_return_t kernResult;
132 198
     mach_port_t masterPort;
133 199
     CFMutableDictionaryRef classesToMatch;
@@ -165,7 +231,7 @@ kern_return_t findSerialPorts(io_iterator_t *matches) {
165 231
     return kernResult;
166 232
 }
167 233
 
168
-kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceFilePath, CFIndex maxPathCount, CFIndex maxPathSize) {
234
++ (kern_return_t)getSerialPortPath:(io_iterator_t)serialPortIterator to:(char **)deviceFilePath with:(CFIndex)maxPathCount and:(CFIndex)maxPathSize {
169 235
     io_object_t modemService;
170 236
     kern_return_t kernResult = KERN_FAILURE;
171 237
     CFIndex i = 0;
@@ -213,3 +279,5 @@ kern_return_t getSerialPortPath(io_iterator_t serialPortIterator, char **deviceF
213 279
     
214 280
     return kernResult;
215 281
 }
282
+
283
+@end

Loading…
Cancel
Save