class:: SerialPort
summary:: serial port interface
categories:: External Control

ClassMethods::

private::initClass

method::new
opening the port.

argument::port
device path or index.

argument::baudrate
baudrate [4800..230400]

argument::databits
5 | 6 | 7 | 8

argument::stopbit
true | false

argument::parity
nil | 'even' | 'odd'

argument::crtscts
hardware flow control (true | false)

argument::xonxoff
software flow control (true | false)

argument::exclusive
open the device exclusively (true | false)

method::devices
returns an array of available device.
code::
SerialPort.devices;
::

method::listDevices
prints to postbuffer
code::
SerialPort.listDevices;
::

method::devicePattern
change device selection
code::
SerialPort.devicePattern = "/dev/ttyUSB*"; // linux usb serial
SerialPort.devices;

SerialPort.devicePattern = nil;
SerialPort.devices;
::

method::closeAll
close all ports.

InstanceMethods::

private::initSerialPort, prOpen, prClose, primCleanup, prCleanup, prPut, prDataAvailable, prDoneAction

method::next
Read a byte from the device. Non-blocking read.

method::read
Read a byte from the device. Blocking read.

method::rxErrors
Rx errors since last query.

method::put
Write a byte to the device. Always blocks.

method::putAll
Write multiple bytes to the device. Collection may be link::Classes/Int8Array:: or link::Classes/String::.

method::doneAction
A link::Classes/Function:: which will be evaluated if the port gets closed (maybe unexpectedly so, due to hardware failure or accidental disconnection). This allows you to for example to make a backup solution and activate it (like using fake input data for your algorithm, or trying to reopen the device). By default it will post a message to the post window.

method::close
close the port.

Examples::

code::
(
p = SerialPort(
	"/dev/tty.usbserial-181",
	baudrate: 9600,
	crtscts: true);
)

// read a byte from the device

p.next;			// doesn't block
fork{p.read.postln};	// may suspend thisThread - should be called within a routine

// write a byte to the device

fork{p.put(42)};	// may suspend thisThread - should be called within a routine

// write multiple bytes to the device

p.putAll("whaddayawant");
p.putAll(Int8Array[13, 10]);

p.doneAction = { "my serial port got closed".postln; }

p.close;	// close the port

SerialPort.closeAll;	// close all ports
::

subsection::Arduino write example

First load the sketch Examples/Communication/Dimmer. See http://www.arduino.cc/en/Tutorial/Dimmer

note::
Always make sure the serial monitor is closed in the Arduino application before opening the port in SuperCollider.
::

code::
(
p = SerialPort(
	"/dev/tty.usbserial-A800crTT",	//edit to match your port. SerialPort.listDevices
	baudrate: 9600,	//check that baudrate is the same as in arduino sketch
	crtscts: true);
)

//send serial data - slow pulsating
(
r= Routine({
	inf.do{|i|
		p.put(i.fold(0, 100).linexp(0, 100, 1, 255).asInteger.postln);
		0.02.wait;
	};
}).play;
)

r.stop;
p.close;
::

subsection::Arduino read example

First load the sketch Examples/Communication/Graph. See http://www.arduino.cc/en/Tutorial/Graph

note::
Always make sure the serial monitor is closed in the Arduino application before opening the port in SuperCollider.
::

code::
(
p = SerialPort(
	"/dev/tty.usbserial-A800crTT",	//edit to match your port. SerialPort.listDevices
	baudrate: 9600,	//check that baudrate is the same as in arduino sketch
	crtscts: true);
)

//read 10bit serial data sent from Arduino's Serial.println
(
r= Routine({
	var byte, str, res;
	99999.do{|i|
		if(p.read==10, {
			str = "";
			while({byte = p.read; byte !=13 }, {
				str= str++byte.asAscii;
			});
			res= str.asInteger;
			("read value:"+res).postln;
		});
	};
}).play;
)

r.stop;
p.close;
::
