MODULE OSCService;
IMPORT
OSC, OSCRegistry, OSCQueue, KernelLog, Objects;
CONST
Trace* = FALSE;
TYPE
OSCService* = OBJECT
VAR
reg: OSCRegistry.OSCRegistry;
q: OSCQueue.OSCQueue;
newpacket: OSC.OSCPacket;
gotpacket: BOOLEAN;
stopping: BOOLEAN;
processing: OSC.OSCPacket;
queuetimer: Objects.Timer;
queuetimeout: BOOLEAN;
storedbundleready: BOOLEAN;
storedbundle: OSC.OSCBundle;
PROCEDURE &Init*(reg: OSCRegistry.OSCRegistry);
BEGIN
SELF.reg := reg;
NEW(q);
NEW(queuetimer);
gotpacket := FALSE;
stopping := FALSE;
queuetimeout := FALSE;
END Init;
PROCEDURE NewPacket*(p: OSC.OSCPacket);
BEGIN { EXCLUSIVE }
AWAIT(~gotpacket OR stopping);
IF stopping THEN RETURN; END;
newpacket := p;
gotpacket := TRUE;
END NewPacket;
PROCEDURE Stop*;
BEGIN { EXCLUSIVE }
stopping := TRUE;
END Stop;
PROCEDURE queueTimeout;
BEGIN { EXCLUSIVE }
queuetimeout := TRUE;
END queueTimeout;
PROCEDURE updateTimer;
VAR
b: OSC.OSCBundle;
bundletimeout: LONGINT;
BEGIN
b := q.Peek();
bundletimeout := b.GetTimeout();
queuetimeout := FALSE;
Objects.SetTimeout(queuetimer, queueTimeout, bundletimeout);
END updateTimer;
PROCEDURE processPacket(processing: OSC.OSCPacket);
BEGIN
IF processing IS OSC.OSCMessage THEN
WITH processing: OSC.OSCMessage DO
reg.Run(processing);
END;
ELSIF processing IS OSC.OSCBundle THEN
WITH processing: OSC.OSCBundle DO
q.Queue(processing);
END;
ELSE
KernelLog.String('OSCServer: Recieved unknown OSCPacket-Subclass'); KernelLog.Ln;
END;
END processPacket;
PROCEDURE processBundle(b: OSC.OSCBundle);
VAR
i: INTEGER;
BEGIN
FOR i:=0 TO b.messagescount-1 DO
processPacket(b.messages[i]);
END;
END processBundle;
BEGIN {ACTIVE}
IF Trace THEN KernelLog.String('OSCService started'); KernelLog.Ln; END;
REPEAT
(* check if an stored bundle is ready *)
storedbundleready := FALSE;
IF ~q.IsEmpty() THEN
storedbundle := q.Peek();
IF Trace THEN KernelLog.String('Stored Bundle has timeout of '); KernelLog.Int(storedbundle.GetTimeout(),10); KernelLog.Ln; END;
IF storedbundle.GetTimeout() = 0 THEN
storedbundleready := TRUE;
END;
END;
(* process first stored bundle, if one is ready *)
IF storedbundleready THEN
storedbundle := q.Dequeue();
processBundle(storedbundle);
(* if none was ready, process a newly received packet *)
ELSIF gotpacket THEN
(* we got a new packet. Store the new packet in processing to release the buffer as soon as possible *)
BEGIN { EXCLUSIVE }
gotpacket := FALSE;
processing := newpacket;
END;
processPacket(processing);
ELSE (* we havn't processed any packet *)
BEGIN { EXCLUSIVE }
IF q.IsEmpty() THEN
AWAIT(gotpacket OR stopping); (* if no packet is queued wait for a new packet or the stop signal *)
ELSE
updateTimer;
(* wait for a timeout of the queue, a new packet or the stop signal *)
AWAIT(queuetimeout OR gotpacket OR stopping);
END;
END;
END;
UNTIL stopping;
(* cleanup *)
Objects.CancelTimeout(queuetimer);
IF Trace THEN KernelLog.String('OSCService stopped'); KernelLog.Ln; END;
END OSCService;
(* these global variables are only used for the testing function *)
(*
VAR
ts: OSCService;
reg: OSCRegistry.OSCRegistry;
PROCEDURE TestService*(ptr: ANY): ANY;
BEGIN
NEW(reg);
NEW(ts, reg);
RETURN NIL;
END TestService;
PROCEDURE EndTestService*(ptr: ANY): ANY;
BEGIN
ts.Stop;
RETURN NIL;
END EndTestService; *)
END OSCService.
(*
SystemTools.Free OSCService ~
OSCService.TestService ~
OSCService.EndTestService ~
*)