ahonoe wrote:I agree with Simon. A message type would be very useful. I am in the process of building my own messaging system using comma delimited strings however I'm running into issues enqueuing these for processing. A message flow that provided enqueuing would be really handy.
I tried a messaging system based on strings containing binary data. The problem I had was that a zero in the data is regarded as the end of the string and nothing is sent past that point, so zeros cannot be sent. So I changed to using text, i.e. zero is ascii '0' character. Increment everything by 1 and you cannot then send 255 !
A parameter can only have one value per bloc for the other end to pick it up, so I invented a queuing system in the script.
Queuing would be easier in a user module as C++ queue or list classes can be used.
My script queuing code also allows you to code a "delay" into the queue, and to shut fo the signal completely (set length to -1).
The code has to work within the limits of the scripting language (based on Pascal).
My code:
// Parameter Output Queueing functionality - relies on the fact that
// for each process cycle Callback() runs before Process()
//
Type ParamQueueRec = record
strqueue : array [1..MAX_VALQUEUE] of AnsiString;
numqueue : array [1..MAX_VALQUEUE] of Single;
waitqueue : array [1..MAX_VALQUEUE] of integer;
Qstart : integer; // barrel Q so can be FIFO
Qend: integer;
queueNext : boolean; // something sent this bloc so anything else must be queued
wantReset : boolean; // want param set to length -1 when queue exhausted
resetLength : integer; // length to reset the paramter to
End;
var ParamOutQueue : Array[1..MAX_PARAMS] of ParamQueueRec; // must be big enough
var procdQinCallback: boolean := false;
procedure resetQueuedParam(p : integer);
var i : integer;
begin
with ParamOutQueue[p] do begin
if Qstart < 0 then Qstart := 0; // preparing for queueing
queueNext := true;
wantReset := true;
end;
end;
procedure processQ(instance : integer);
var i: integer;
begin
for i := 1 to MAX_PARAMS do begin
with ParamOutQueue
do begin
if Qstart < 0 then continue;
if Qstart > 0 then begin
// take value off start of barrel Q and send it
if strQueue[Qstart] <> AnsiString(nil) then begin
setLength(i,1);
setStringValue(i,strQueue[Qstart]);
sTrace('Zoner inst ' + inttostr(instance) + ' Qstart ' + IntToStr(Qstart) + ', sending string value ' + strQueue[Qstart]);
end else if waitQueue[Qstart] > -1 then begin
// delay entry, decrement wait count
waitQueue[Qstart] := waitQueue[Qstart] - 1;
sTrace('queued delay, count is now ' + inttostr(waitQueue[Qstart]));
if waitQueue[Qstart] > -1 then exit; // do not lose queue item
end else begin
setLength(i,1);
setValue(i,numqueue[Qstart]);
sTrace('queued val sending ' + inttostr(Trunc(numqueue[Qstart])));
end;
if Qstart = Qend then begin
Qstart := 0; // done last one, no queue left
end else begin
Qstart := Qstart + 1;
if Qstart > MAX_VALQUEUE then Qstart := 1; // wrap round
end;
end else begin
if (wantReset) then begin
sTrace('Closing parameter ' + IntToStr(i));
setLength(i,resetLength);
wantReset := false;
end;
Qstart := -1; // indicates that reset has been done if required
queueNext := false;
end;
end;
end;
end;
procedure processQfromCallback;
// Call this at the start of the Callback routine
var i:integer;
begin
// Q should only be processed on first callback per bloc
if procdQinCallback = false then begin
processQ(1);
procdQinCallback := true;
end;
end;
procedure processQfromProcess;
// Call this at the start of the Process routine
var i:integer;
begin
if procdQinCallback then begin
// callback will have processed the Q and maybe set some more
procdQinCallback := false;
exit;
end;
processQ(2);
end;
Function allocQueuedParam(p:tparameter) : integer;
begin
// alloc space in the queue and return new index
with ParamOutQueue[p] do begin
if Qstart < 1 then begin
Qstart := 1;
Qend := 1; // first entry in queue
end else begin
Qend := Qend + 1;
if Qend > MAX_VALQUEUE then Qend := 1;
end;
// Set default values in new Q entry
numQueue[Qend] := -1; // why not
strQueue[Qend] := AnsiString(nil); // indicates not a string value
waitQueue[Qend] := -1; // indicates not a wait entry
end;
exit(ParamOutQueue[p].Qend);
end;
procedure setQueuedParam(p:tparameter; num:single);
var newentry : integer;
begin
// Set numeric paramter value, queueing if more than 1 in same bloc
with ParamOutQueue[p] do begin
if (queueNext) then begin
newentry := allocQueuedParam(p);
numQueue[newentry] := num;
wantReset := true;
sTrace('queuing value ' + inttostr(Trunc(num)));
end else begin
SetLength(p,1);
SetValue(p, num);
Qstart := 0; // reset from -1
queueNext := true;
wantReset := true;
sTrace('not queueing value ' + inttostr(Trunc(num)));
end;
end;
end;
procedure setQueuedStrParam(p:tparameter; str:AnsiString);
var newentry : integer;
begin
// Set string parameter, queueing if more than 1 in same bloc
with ParamOutQueue[p] do begin
if (queueNext) then begin
newentry := allocQueuedParam(p);
strQueue[newentry] := str;
wantReset := true;
end else begin
SetLength(p,1);
SetStringValue(p, str);
Qstart := 0; // reset from -1
queueNext := true;
wantReset := true;
end;
end;
end;
procedure setQueuedDelay(p:tparameter; delay:integer);
var newentry : integer;
begin
// Set delay taking up specified number of blocs
with ParamOutQueue[p] do begin
newentry := allocQueuedParam(p);
waitQueue[newentry] := delay;
queueNext := true;
end;
end;
// END OF QUEUED PARAMETER FUNCTIONALITY