<ep> <azk> <cr> <fd 12> <msd period 1200> <t 1100>
<vm desktop> <id Keyboard>
<mpr +Left> <mnr +Right> <nfb> <id tcpip> </ep>
0 <send "<SET
ID=''USER_DATA'' VALUE=''0'' />"> <fd 1> <! initially set user data
to zero as it's value can run on from the previous run> /
<send "<SET
ID=''ENABLE_SEND_COUNTER'' STATE=''1'' />"> <fd 1> /
<send
"<SET
ID=''ENABLE_SEND_TIME'' STATE=''1'' />"> <fd 1> /
<send
"<SET
ID=''ENABLE_SEND_PUPILMM'' STATE=''1'' />"> <fd 1> /
<send "<SET
ID=''ENABLE_SEND_USER_DATA'' STATE=''1'' />"> <fd 1> /
<send
"<SET
ID=''ENABLE_SEND_PUPIL_LEFT'' STATE=''1'' />"> <fd 1> /
<send
"<SET
ID=''ENABLE_SEND_DATA'' STATE=''1'' />">
"Instructions";
111 <send
"<SET
ID=''USER_DATA'' VALUE=''ITEM 111'' />"> <ms% 1000> "ITEM 111" /;
222 <send
"<SET ID=''USER_DATA'' VALUE=''ITEM 222'' />"> <ms% 1000> "ITEM 222" /;
333
<send
"<SET ID=''USER_DATA'' VALUE=''ITEM 333' />"> <ms% 1000> "ITEM 333" /;
0 "Done" <send
"<SET ID=''ENABLE_SEND_DATA'' STATE=''0'' />"> ;
One
note about the timing of <send> frames and that is that
as the code currently stands DMDX doesn't hang around
and wait to make sure the network sent the last string so while you could
conceivably stuff all those initialization commands into a series of frames with
zero tick durations (for instance using the comma frame separator) if the thread
that sends the data hasn't begun sending the previous string depending on
machine timing either the next one will
overwrite it or only the first one will get through and the other one(s) will be lost (you'd also get a memory leak but
almost no machine these days is going to be negatively impacted by that).
As of version 6.5.1.1 <send> is no longer
allowed in zero tick duration items and you'll get an error if you try to do
so..
As far as testing <send>'s functionality is concerned you can use the Monitor application that DMDX uses to monitor a run from another machine, by default it uses port 27100 so you can either set it up on another port or specify the port number in your <id tcpip> keyword with <id tcpip 127.0.0.1:27100> for instance. While Monitor will not send any replies back (I used a special Debug build of it to do the testing needed to get the whole tcpip device / <send> functionality going) you can at least see what strings it is you'll be sending and hell, if people really want it I can expose a testing interface for wider use.
If you want to parse replies from a machine in the .tcpipreply. macro I built an example parsing replies from that Debug version of Monitor. When I send it a <requestack num=24 delay=1000 subsequentdelay=300> request it will respond with the requested number of replies of the form <ACK number="1"> and we parse out the numeric value between the quotes and display it using the newly added character constants in the expression evaluator to find the field we want (although here we could just look for double quotes as there are no other fields but the point of this is exposition and not brevity) and stop when we see the number 24. There are few special gotchas here, first off we're setting the macro .tcpipreply. empty to begin with as we will probably be running before the first reply is received and would get a reference to an undefined macro unless we first set it up. Second we operate on a copy of .tcpipreply. in T in case a new reply comes in as we're processing it. Another thing is we can't put a double quote in a character constant, DMDX special characters will cause syntax errors as (at this stage at least) I'm not making the rest of DMDX's parsers ignore what's in single quotes as well as double quotes. So instead we go and look up what the ASCII decimal code for a double quote is and see that it's 34 and just hard code it, hey at least I didn't have to look up the other letters in "number=". Lastly we just run processing .tcpipreply. repeatedly not caring if we've already processed a given reply, if we wanted to block that item 2250 would set .tcpipreply. empty again with m.tcpipreply.++. Of course if you were going to use this code you'd make item 2250 a <return> item and you'd call item 1111 each time you wanted to know what the tcpip host last sent...
<ep> <cr> <nfb> <safemode 1> <fd 10>
<id tcpip> <!branchdiagnostics>
<eop>
0 "test tcpip reply parsing"
m.tcpipreply.++ <set c1=0>;
1 <SEND "<requestack num=24 delay=1000
subsequentdelay=300>">
"send <requestack num=24 delay=1000 subsequentdelay=300>";
~1111 mT+~.tcpipreply.+;
~2222 <macro pop T, c1> <bi 1111, c1 .eq. 0>;
~1
<bi 2222, c1 .ne. 'n'>;
~1 <macro pop T, c1> <bi 2222, c1 .ne. 'u'>;
~1
<macro pop T, c1> <bi 2222, c1 .ne. 'm'>;
~1 <macro pop T, c1> <bi 2222, c1
.ne. 'b'>;
~1 <macro pop T, c1> <bi 2222, c1 .ne. 'e'>;
~1 <macro pop T,
c1> <bi 2222, c1 .ne. 'r'>;
~1 <macro pop T, c1> <bi 2222, c1 .ne. '='>;
~1 <macro pop T, c1> <bi 2222, c1 .ne. 34> <!double quote>;
~1 mN++ <!
extract the field we want into N>;
~2230 <macro pop T, c1> <bi 1111, c1 .eq.
0>;
~1 <bi 2240, c1 .eq. 34> <!double quote>;
~1 <macro push N, c1> <bu
2230>;
~2240 mm++ <! reverse N before displaying it>;
~2245 <macro pop N,
c1> <bi 2250, c1 .eq. 0>;
~1 <macro push M, c1> <bu 2245>;
2250 d2 "~M"
<bi 1111, ~M .ne. 24>;
0
"Done";