AVRSack/AVRsack/ASSerial.mm

103 lines
2.9 KiB
Plaintext
Raw Normal View History

//
// ASSerial.m
// AVRsack
//
// Created by Matthias Neeracher on 12/15/14.
// Copyright © 2014 Aere Perennius. All rights reserved.
//
#import "ASSerial.h"
#include <dispatch/dispatch.h>
2014-12-29 06:35:07 +00:00
#include <termios.h>
#include <sys/ioctl.h>
2014-12-29 06:35:07 +00:00
static dispatch_source_t watchSlashDev;
static NSMutableDictionary * savedAttrs;
NSString * kASSerialPortsChanged = @"PortsChanged";
@implementation NSFileHandle (ExceptionSafety)
- (NSData *)availableDataIgnoringExceptions {
@try {
return [self availableData];
}
@catch (NSException *exception) {
return [NSData data];
}
}
@end
@implementation ASSerial
+ (void)initialize {
int fd = open("/dev", O_EVTONLY);
watchSlashDev =
dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_WRITE, dispatch_get_main_queue());
dispatch_source_set_event_handler(watchSlashDev, ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kASSerialPortsChanged object: nil];
});
dispatch_resume(watchSlashDev);
}
2015-11-16 01:56:33 +00:00
+ (NSArray<NSString *> *)ports {
NSMutableArray * cuPorts = [NSMutableArray array];
for (NSString * port in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/dev" error: nil]) {
if ([[port substringToIndex:2] isEqualToString:@"cu"])
2014-12-29 08:00:11 +00:00
[cuPorts addObject:[port substringFromIndex:3]];
}
2014-12-31 09:03:30 +00:00
return [cuPorts sortedArrayUsingSelector:@selector(compare:)];
}
+ (NSString *) fileNameForPort:(NSString *)port
{
if ([port containsString:@"/"])
return port;
else
return [NSString stringWithFormat:@"/dev/cu.%@", port];
}
2014-12-29 06:35:07 +00:00
+ (NSFileHandle *)openPort:(NSString *)port withSpeed:(int)speed {
int fd = open([[self fileNameForPort:port] UTF8String], O_RDWR | O_NOCTTY | O_NONBLOCK);
2014-12-29 06:35:07 +00:00
if (fd < 0)
return nil;
if (ioctl(fd, TIOCEXCL) < 0)
goto failed;
termios origAttr, newAttr;
if (tcgetattr(fd, &origAttr) < 0)
goto failed;
newAttr = origAttr;
cfmakeraw(&newAttr);
cfsetspeed(&newAttr, speed);
2015-01-02 06:26:10 +00:00
newAttr.c_cflag &= ~(PARENB | CSIZE | CSTOPB | CRTSCTS);
newAttr.c_cflag |= CS8;
2014-12-29 06:35:07 +00:00
tcsetattr(fd, TCSANOW, &newAttr);
2015-01-02 06:26:10 +00:00
tcsetattr(fd, TCSAFLUSH, &newAttr);
2014-12-29 06:35:07 +00:00
if (!savedAttrs) {
savedAttrs = [NSMutableDictionary dictionary];
}
[savedAttrs setObject:[NSData dataWithBytes:&origAttr length:sizeof(origAttr)] forKey:[NSNumber numberWithInt:fd]];
return [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:NO];
failed:
close(fd);
return nil;
}
+ (void)restorePort:(int)fileDescriptor {
NSNumber * fd = [NSNumber numberWithInt:fileDescriptor];
if (NSData * attr = [savedAttrs objectForKey:fd]) {
tcsetattr(fileDescriptor, TCSADRAIN, (termios *)[attr bytes]);
[savedAttrs removeObjectForKey:fd];
}
}
+ (void)closePort:(int)fileDescriptor {
NSNumber * fd = [NSNumber numberWithInt:fileDescriptor];
close(fileDescriptor);
[savedAttrs removeObjectForKey:fd];
}
@end