Sending and receiving messages in Exapunks is a tricky business. Timing problems can ruin the proper execution of your Axiom code.
Consider these two Exas trading messages via the M
register. Exa XA
reads from a file and sends them to the network register M
…
NOTE XA - SENDER
GRAB 199
MARK READING
COPY F M
TEST EOF
FJMP READING
…where XB
reads from M
and writes these messages to another file:
NOTE XB - RECEIVER
MAKE
MARK WRITING
COPY M F
TEST MRD
TJMP WRITING
As you can see, XA
tests for the end of file (EOF
), while XB
tests for receivable messages (MRD
). This seems to be rather well designed, but most often ends up in XB
never finishing its job because there is nothing waiting in M
when TEST MRD
is executed. Why is that?
Transfers via the M
register are not instantaneous. Before writing to M
it needs to be empty, before reading from M
the corresponding write operation has to be finished.
NOOP
for timing
One solution for timing issues is to add additional NOOP
commands in your writing loop, telling your receiver to wait until the sender is back online.
NOTE XB - RECEIVER
MAKE
MARK WRITING
COPY M F
NOOP
NOOP
TEST MRD
TJMP WRITING
If the job of XA
is to just read its file and die afterwards, your programme could be written even more compact:
NOTE XA - SENDER
GRAB 199
MARK READING
COPY F M
JUMP READING
NOTE CRASH AND BURN AT END OF FILE
…with XB
having to wait one operation less than before:
NOTE XB - RECEIVER
MAKE
MARK WRITING
COPY M F
NOOP
TEST MRD
TJMP WRITING
By a rule of thumb the number of instructions in your receiver loop after your last read from M
and before doing TEST MRD
has to be as many instructions as it takes the sender to reach its next write to M
after its last write to M
.
Sending „End Of Message“
If you do not want to think about timing, the receiving XB
can test for a marker which tells it that the end of the message has been reached.
This only works if you know for sure that the file you are reading from never contains the symbol 0
, as XA
will use this as its „End Of Message“ message (EOM
):
NOTE XA - SENDER
GRAB 199
MARK READING
COPY F M
TEST EOF
FJMP READING
NOTE EOF, SEND EOM
COPY 0 M
The receiver XB
now copies the message to T
, from where it is written into the file and is also executable from TJMP
or FJMP
. Remember: If T
is 0
, it is evaluated to false
– all other values will evaluate to true
.
NOTE XB - RECEIVER
MAKE
MARK WRITING
COPY M T
COPY T F
NOTE TEST EOM FROM `T`
TJMP WRITING
NOTE DELETE EOM FROM FILE
SEEK -1
VOID F
Sending „Packet Size“
If XA
knows the file size it is reading to the network in advance, it is a very clever trick to send the file size to the receiver XB
as well. This way the XB
does not have to test for the message to end, but will know when all message chunks have been delivered.
XA
will send the message size to XB
and use it for its own loop:
NOTE XA - SENDER
GRAB 199
NOTE `T` CONTAINS THE NUMBER OF CHUNKS TO READ
COPY T M
MARK READING
COPY F M
NOTE COUNT DOWN REMAINING CHUNKS
SUBI T 1 T
TJMP READING
XA
and XB
will have the same loop conditions:
NOTE XB - RECEIVER
MAKE
NOTE NOW `T` CONTAINS THE MESSAGE SIZE
COPY M T
MARK WRITING
COPY M F
NOTE COUNT DOWN REMAINING CHUNKS
SUBI T 1 T
TJMP WRITING
Sending „Keep Alive Messages“
For bullet-proof communication your best choice is to have XA
send a „keep alive message“…
NOTE XA - SENDER
GRAB 199
MARK READING
COPY F M
TEST EOF
NOTE SEND RESULT OF TEST TO M...
COPY T M
NOTE ...AND USE RESULT FOR YOUR OWN LOOP
FJMP READING
…to XB
:
NOTE XB - RECEIVER
MAKE
MARK WRITING
COPY M F
NOTE USE TEST RESULT TO TEST FOR YOURSELF
TEST M = 1
FJMP WRITING
Every reading cycle XB
reads two messages from M
, where the second message contains 0
if XA
reached the end of its file. In this manner XB
continues to wait for messages as long as XA
explicitly tells it to by sending 1
in the second message.
This lets you skip all timing issues on the expends of more writes to the M
register. It adds just one extra line of Axiom code (but one less than having to NOOP
), but may end up producing more cycles.
The Terminator
If you are facing a multi-sender communication, things may get hairy. In this scenario, multiple senders transmit data to one receiver, which has to combine these messages into a single on.
Above solutions may apply, but if you are forced to deal with different message lengths which need to be combined, if may become very tricky to shut down the other sender as well, so your receiver stops its receiving cycle.
Imagine a scenario where first sender XA
knows when to quit, but second sender XB
does not; in this case, receiver XC
may go on receiving messages from XB
ad infinitum.
To solve this problem, XA
could literally use the KILL
command to shut down XB
. You may even opt to kill the receiver XC
as well with this method.
Update 2018–09–06: Added section for „End Of Message“ & „Packet Size“.
Update 2018–09–16: Added section for „Terminator“