1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
SerialPort
{
classvar <>devicePattern, allPorts;
var dataptr, semaphore;
var <>doneAction;
*initClass {
allPorts = Array[];
ShutDown.add {
this.cleanupAll;
};
}
// device listing
*devices {
^(devicePattern ?? {
thisProcess.platform.name.switch(
\linux, "/dev/tty[A,S,U]*",
\osx, "/dev/tty.*",
\windows, "COM"
)
}).pathMatch
}
*listDevices {
this.devices.do(_.postln);
}
*new {
| port,
baudrate(9600),
databits(8),
stopbit(true),
parity(nil),
crtscts(false),
xonxoff(false)
exclusive(false) |
if (port.isNumber) {
port = this.devices[port] ?? {
Error("invalid port index").throw;
};
}
^super.new.initSerialPort(
port,
exclusive,
baudrate,
databits,
stopbit,
( even: 1, odd: 2 ).at(parity) ? 0,
crtscts,
xonxoff
)
}
initSerialPort { | ... args |
semaphore = Semaphore(0);
if ( dataptr.isNil ){
this.prOpen(*args);
allPorts = allPorts.add(this);
doneAction = { ("SerialPort"+args[0]+"was closed").postln; };
}
}
isOpen {
^dataptr.notNil
}
close {
if (this.isOpen) {
this.prClose;
allPorts.remove(this);
}
}
*closeAll {
var ports = allPorts;
allPorts = Array[];
ports.do(_.close);
}
*cleanupAll {
var ports = allPorts;
allPorts = Array[];
ports.do(_.primCleanup);
}
// non-blocking read
next {
_SerialPort_Next
^this.primitiveFailed
}
// blocking read
read {
var byte;
while { (byte = this.next).isNil } {
semaphore.wait;
};
^byte
}
// rx errors since last query
rxErrors {
_SerialPort_RXErrors
}
// always blocks
put { | byte, timeout=0.005 |
if ( dataptr.notNil ){
while { this.prPut(byte).not } {
timeout.wait;
timeout = timeout * 2;
}
}{
"SerialPort not open".warn;
}
}
putAll { | bytes, timeout=0.005 |
bytes.do { |byte|
this.put(byte, timeout);
}
}
// PRIMITIVE
prOpen { | ... args | // was: | port, baudRate | but that misses out on all the other args?
_SerialPort_Open
^this.primitiveFailed
}
prClose {
_SerialPort_Close
^this.primitiveFailed
}
primCleanup {
_SerialPort_Cleanup
^this.primitiveFailed
}
prCleanup{
if (this.isOpen) {
this.primCleanup;
allPorts.remove(this);
}
}
prPut { | byte |
_SerialPort_Put
^this.primitiveFailed
}
prDataAvailable {
// callback
semaphore.signal;
}
prDoneAction {
// callback
this.doneAction.value;
// cleanup the port
this.prCleanup
}
}
|