popravljen decoder, init/start/stop

main
Jurij Podgoršek 2024-08-22 21:39:41 +02:00
parent aa89e70dd2
commit fc469e0fa3
1 changed files with 211 additions and 165 deletions

View File

@ -1,196 +1,242 @@
SLIPDecoder { SLIPDecoder {
// SLIP DECODING // SLIP DECODING
// =================== // ===================
// //
// The packets are SLIP encoded using these special characters: // The packets are SLIP encoded using these special characters:
// end = 8r300 (2r11000000 or 0xc0 or 192) // end = 8r300 (2r11000000 or 0xc0 or 192)
// esc = 8r333 (2r11011011 or 0xdb or 219) // esc = 8r333 (2r11011011 or 0xdb or 219)
// esc_end = 8r334 (2r011011100 or 0xdc or 220) // esc_end = 8r334 (2r011011100 or 0xdc or 220)
// esc_esc = 8r335 (2r011011101 or 0xdd or 221) // esc_esc = 8r335 (2r011011101 or 0xdd or 221)
// original code by Martin Marier & Fredrik Olofsson // original code by Martin Marier & Fredrik Olofsson
const slipEND = 0xC0; const slipEND = 0xC0;
const slipESC = 0xDB; const slipESC = 0xDB;
const slipESC_END = 0xDC; const slipESC_END = 0xDC;
const slipESC_ESC = 0xDD; const slipESC_ESC = 0xDD;
// OSC bundle header "#bundle" // OSC DECODING
const oscBundleHeader = #[35, 98, 117, 110, 100, 108, 101, 0]; // ============
// bundle header "#bundle"
// type separator ","
const oscBundleHeader = #[35, 98, 117, 110, 100, 108, 101, 0];
const oscTypeSeparator = 0x2C;
// OSC type separator "," // Buffer for OSC bundles/messages
const oscTypeSeparator = 0x2C; const bufferSize = 4096;
var deviceName, <>prependAddress, <>rate, <>port, decode, <>actions, firstRead, trace, stop, <>reader; var <>deviceName, <>rate, <>prepend, <port, decode, trace, stop, <reader;
*new {|deviceName="/dev/ttyUSB0", rate=9600, prepend=""| *new { |deviceName="/dev/ttyUSB0", rate=115200, prepend=""|
^super.new.initSLIPDecoder(deviceName, rate, prepend); deviceName.postln;
} //^super.newCopyArgs(deviceName, rate, prepend).init;
^super.newCopyArgs(deviceName, rate, prepend);//.init;
}
readInt32 { |byteArr| readInt32 { |byteArr|
^((byteArr[0] << 24) + (byteArr[1] << 16) + (byteArr[2] << 8) + byteArr[3]); ^((byteArr[0] << 24) + (byteArr[1] << 16) + (byteArr[2] << 8) + byteArr[3]);
} }
readFloat32 { |byteArr| readFloat32 { |byteArr|
^Float.from32Bits(this.readInt32(byteArr)); ^Float.from32Bits(this.readInt32(byteArr));
} }
// Read byte array 4 bytes at a time, return on null termination or if end of buffer reached // Read byte array 4 bytes at a time, return on null termination or if end of buffer reached
// Return array [string, strlen (bytes)] // Return array [string, strlen (bytes)]
readNextString { |byteArr| readNextString { |byteArr|
var str = "", idx = 0; var str = "", idx = 0;
while({ (idx + 4) <= byteArr.size }, while({ (idx + 4) <= byteArr.size },
{ {
str = str ++ String.newFrom( str = str ++ String.newFrom(
byteArr[(idx..(idx + 3))] byteArr[(idx..(idx + 3))]
.removeEvery([0]) .removeEvery([0])
.collect({|x| x.asAscii}) .collect({|x| x.asAscii})
); );
// If last byte is null, return // If last byte is null, return
if ( isNil(byteArr[idx + 3]) || (byteArr[idx + 3] == 0), { if ( isNil(byteArr[idx + 3]) || (byteArr[idx + 3] == 0), {
^[str, idx + 4] ^[str, idx + 4]
}); });
idx = idx + 4; idx = idx + 4;
} }
); );
// If end of byteArr, return // If end of byteArr, return
^[str, idx]; ^[str, idx];
} }
int2chr { |x| int2chr { |x|
// Ce ni stevilo, vrni isto // ce je stevilo, v razponu crk, stevk in znakov, vrni char, sicer kar cifro
if ((x.isInteger.not), { ^x }); if (x.isInteger && (x >= 0x20) && (x <= 0x7E),
// v razponu crk, stevilk in znakov vrni char, sicer kar cifro { ^x.asAscii },
if (x.isInteger && (x >= 0x20) && (x <= 0x7E), { ^x })
{ ^x.asAscii }, }
{ ^x })
}
initSLIPDecoder { |deviceName,rate,prepend| init {
port = SerialPort(deviceName, rate); "init".postln;
prependAddress = prepend; dump(this);
actions = []; // Each action is a function that takes the message contents as an argument. see 'decode' below. deviceName.postln;
firstRead = false; rate.postln;
trace = false; port = SerialPort(deviceName, rate);
stop = false; trace = false;
} stop = false;
"init done".postln;
}
trace { |val| trace { |val|
trace = val; trace = val;
} val;
}
// Function for decoding the properly-SLIP-decoded message. traceMsg { |...msg|
decode { |data| if (trace, { "> ".post; msg.join(' ').postln; });
// Is it a bundle? (read header from first 8 bytes) }
var header = data.at((0..7));
if (header == oscBundleHeader, // Function for decoding the properly-SLIP-decoded message.
// OSC bundle decode { |data|
{ // Is it a bundle? (read header from first 8 bytes)
var timetag, nextMsgLen, nextMsgStart, nextMsgEnd, bundlePart; var header = data.at((0..7));
if (trace, { if (header == oscBundleHeader,
"".postln; // OSC bundle
"======".postln; {
"BUNDLE".postln; var timetag, nextMsgLen, nextMsgStart, nextMsgEnd, bundlePart;
"======".postln;
});
// Next 8 bytes are a time tag (or null) this.traceMsg("BUNDLE");
/* @TODO handle timetags!
timetag = data.at((8..15));
*/
// First message starts after the time tag // Next 8 bytes are a time tag (or null)
nextMsgStart = 16; /* @TODO handle timetags!
timetag = data.at((8..15));
*/
// Loop for each message // First message starts after the time tag
while({ nextMsgStart < data.size }, nextMsgStart = 16;
{
// Further 4 bytes hold the next message length
nextMsgLen = this.readInt32(data.at((nextMsgStart..(nextMsgStart + 3))));
nextMsgStart = nextMsgStart + 4;
nextMsgEnd = nextMsgStart + nextMsgLen - 1;
bundlePart = data.at((nextMsgStart..nextMsgEnd));
// Recursively decode; each bundle part can be another bundle // Loop for each message
this.decode(bundlePart); while({ nextMsgStart < data.size },
{
// Further 4 bytes hold the next message length
nextMsgLen = this.readInt32(data.at((nextMsgStart..(nextMsgStart + 3))));
nextMsgStart = nextMsgStart + 4;
nextMsgEnd = nextMsgStart + nextMsgLen - 1;
bundlePart = data.at((nextMsgStart..nextMsgEnd));
nextMsgStart = nextMsgEnd + 1; // Recursively decode; each bundle part can be another bundle
} this.decode(bundlePart);
);
},
// OSC message
{
var nextString, index, address, type, args = [];
// Message Address nextMsgStart = nextMsgEnd + 1;
nextString = this.readNextString(data); }
address = nextString[0]; );
data = data[(nextString[1]..(data.size - 1))]; },
// OSC message
{
var nextString, index, address, type, args = [];
nextString = this.readNextString(data); // Message Address
type = nextString[0]; nextString = this.readNextString(data);
data = data[(nextString[1]..(data.size - 1))]; address = nextString[0];
data = data[(nextString[1]..(data.size - 1))];
type.do({ |t| nextString = this.readNextString(data);
t.switch ( type = nextString[0];
$i, { data = data[(nextString[1]..(data.size - 1))];
args = args.add(this.readInt32(data));
data = data[(4..(data.size - 1))];
},
$f, {
args = args.add(this.readFloat32(data));
data = data[(4..(data.size - 1))];
},
$s, {
nextString = this.readNextString(data);
args = args.add(nextString[0]);
data = data[(nextString[1]..(data.size - 1))];
}
/* @TODO implement strings, bytearrays */
);
});
// Send OSC message to the engine type.do({ |t|
NetAddr.localAddr.sendMsg(prependAddress ++ address, *args); t.switch (
} $i, {
); args = args.add(this.readInt32(data));
} data = data[(4..(data.size - 1))];
},
$f, {
args = args.add(this.readFloat32(data));
data = data[(4..(data.size - 1))];
},
$s, {
nextString = this.readNextString(data);
args = args.add(nextString[0]);
data = data[(nextString[1]..(data.size - 1))];
}
/* @TODO implement strings, bytearrays */
);
});
this.traceMsg("OSC", prepend ++ address, args);
start { // Send OSC message to the engine
stop = false; NetAddr.localAddr.sendMsg(prepend ++ address, *args);
reader = fork { }
var buffer, serialByte; );
}
var bufferSize = 1024; // 1KB start {
buffer = Int8Array(maxSize: bufferSize); this.traceMsg("Starting...");
while({stop.not}, { dump(this);
serialByte = port.read; // TODO fix restart
serialByte.switch( if ((port == nil), {this.init;});
slipEND, { if (port.isOpen.not, {this.init;});
if (firstRead && buffer.isEmpty.not,
{ this.traceMsg("opened");
this.decode(buffer);
}, reader = fork {
{ firstRead = true; } var serialByte, buffer, firstRead;
); firstRead = true;
buffer = Int8Array(maxSize: bufferSize);
}, // Skip data before the first END character
slipESC, { while({stop.not && firstRead}, {
serialByte = port.read; serialByte = port.read;
serialByte.switch(
slipESC_END, { buffer.add(slipEND) }, //this.traceMsg("Read byte");
slipESC_ESC, { buffer.add(slipESC) }, //this.traceMsg(serialByte.asAscii);
{"SLIP encoding error.".error }
) if (serialByte == slipEND, {
}, buffer = Int8Array(maxSize: bufferSize);
{ buffer.add(serialByte) } firstRead = false;
); }, {
//this.traceMsg("Skip...")
});
});
// Start reading data
this.traceMsg("First read!");
while({stop.not}, {
serialByte = port.read;
//this.traceMsg("Checking", serialByte.asInteger, serialByte.asAscii);
serialByte.switch(
// on END, decode buffer
slipEND, {
//this.traceMsg("SLIP END, decoding ");
//this.traceMsg(buffer);
//3.wait;
if (buffer.isEmpty.not, {
this.traceMsg("decode!", buffer);
this.decode(buffer);
buffer = Int8Array(maxSize: bufferSize);
}); });
}; },
} slipESC, {
serialByte = port.read;
serialByte.switch(
slipESC_END, {
//this.traceMsg("SLIP ESC and ESC_END");
buffer.add(slipEND)
},
slipESC_ESC, {
//this.traceMsg("SLIP ESC and ESC_ESC");
buffer.add(slipESC)
},
{"SLIP encoding error.".error }
);
},
{
// Otherwise just add the byte
//this.traceMsg(buffer);
buffer.add(serialByte);
});
});
};
}
stop { reader.stop } stop {
this.traceMsg("Stopping...");
stop = true;
port.close;
}
} }