:: Arduino + Cocoa/Objective-C ::
Three methods of interfacing with Objective C are presented here.
The easiest and most straight forward way to communicate with your Arduino is to use the C-style command popen() to call a few bash commands (the commands that you use in Terminal or Command Prompt on a PC).
A simple code snippet that would send the words "hello world" to your Arduino is this:
popen("echo hello world > /dev/tty.usbserial-A6006kDo", "r");
If you're wondering what exactly this is doing, basically it takes the output from "echo hello world" which is the text "hello world" and writes it into the file "/dev/tty.usbserial-A6006kDo". The > operator overwrites any existing text in the file its writing to which is okay because any text in this file is deleted once it is sent. By the way, the "r" in popen() denotes that you want to run the commands.
If you're a seasoned Objective-C programmer, you might have noticed that there is no @ operator in front of the quotes. This is because the @ operator denotes that the stuff in the quotes is a string object. Because this is a C-Style command, there are no objects and therefore the @ operator is not needed. Unfortunately the @ operator makes it a different kind of string. This means that you cannot pass an NSString to popen. Before you pass any strings to it they must be converted to C-Style strings. This is how you would do that:
NSString *toSend = [NSString stringWithFormat:@"echo 3 > %@", [SERIALPORTFIELD stringValue]]; char *toCSend = [toSend UTF8String]; //converting part popen(toCSend, "r");
----
Objective C is a strict superset of C, so the most basic way to interface is just use POSIX C. The main downside here is that you will be limited to the baud rates that are pre-defined for POSIX serial ports.
This method is very similar to POSIX C, but allows you to set more options(i.e. any baud rate and read latency) and list available serial ports. Apple's serial example shows the use of ioctl() to set serial port options and IOKit to list serial ports. The explanation and code below are primarily based off Apple's example.
To open the serial port:
// open the serial like POSIX C serialFileDescriptor = open( "/dev/tty.usbserial-A6008cD3", O_RDWR | O_NOCTTY | O_NONBLOCK ); // block non-root users from using this port ioctl(serialFileDescriptor, TIOCEXCL); // clear the O_NONBLOCK flag, so that read() will // block and wait for data. fcntl(serialFileDescriptor, F_SETFL, 0); // grab the options for the serial port tcgetattr(serialFileDescriptor, &options); // setting raw-mode allows the use of tcsetattr() and ioctl() cfmakeraw(&options); // specify any arbitrary baud rate ioctl(serialFileDescriptor, IOSSIOSPEED, &baudRate); // start a thread to read the data coming in [self performSelectorInBackground: @selector(incomingTextUpdateThread:) withObject: [NSThread currentThread]];
To read from the serial port:
// This selector will be called as another thread - (void)incomingTextUpdateThread: (NSThread *) parentThread { char byte_buffer[100]; // buffer for holding incoming data int numBytes=1; // number of bytes read during read // create a pool so we can use regular Cocoa stuff // child threads can't re-use the parent's autorelease pool NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // this will loop until the serial port closes while(numBytes>0) { // read() blocks until data is read or the port is closed numBytes = read(serialFileDescriptor, byte_buffer, 100); // you would want to do something useful here NSLog([NSString stringWithCString:byte_buffer length:numBytes]); } // give back the pool [pool release]; }
To write to the serial port:
uint8_t val = 'A'; write(serialFileDescriptor, &val, 1);
To list availble serial ports:
io_object_t serialPort; io_iterator_t serialPortIterator; // ask for all the serial ports IOServiceGetMatchingServices( kIOMasterPortDefault, IOServiceMatching(kIOSerialBSDServiceValue), &serialPortIterator); // loop through all the serial ports while (serialPort = IOIteratorNext(serialPortIterator)) { // you want to do something useful here NSLog( (NSString*)IORegistryEntryCreateCFProperty( serialPort, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0)); IOObjectRelease(serialPort); } IOObjectRelease(serialPortIterator);
Try looking through the Example XCode Project, the code presented on this website is simplified to make it more readable(at least that was the intention). You may also want to look at Apple's serial example.