Plan: a SINTRAN-native chat - RT server and PROG client¶
The chat that exists today runs on OUR node in C#. A SINTRAN user reaches it by connecting to us. This plan is the other way round: the chat server runs ON the ND as a real-time program, and the client is an ordinary SINTRAN PROG - so two ND machines can chat with no C# in the path at all.
Written to be built together. Nothing here is started, and the open questions are marked as such rather than guessed at.
1. What we already know, and it is a lot¶
The C# work is not thrown away - it is the specification, and it is verified against real machines:
- The room rules are already isolated and transport-free (
ChatRoom), with tests. The RT program implements the same rules; the tests say what "same" means. - The message format is ours to choose and is already small and byte-defined
(
ChatMessage: kind, nickname length, name, 2-byte text length, text). A PLANC record and an assembler layout can mirror it exactly. - The XMSG calls an RT server needs are the ones already modelled and exercised:
XSOPN(open a port),XSNAM(claim a name),XSCON(a connection port with seats),XSSND/XSRCV,XSCLS. SeeDOC/XMSG-API.mdfor the MON 200B calling convention andXmsg.Apifor a working model of each. - The seat mechanism is XROUT's free-connection count, which is how the real file server builds its 30 seats. We do not have to invent admission control.
2. The two programs¶
2a. CHATSV - the server, an RT program¶
Runs under SINTRAN as an RT program (@RT CHATSV), like XFTRAD and FSART do.
Its whole life:
open a port
claim the name CHAT-<room> with N connection seats
loop forever:
wait for a message
decode it
apply the room rules
send what has to be sent to each member
Language: PLANC first. The room is a table of (magic number, name) and the rules are string comparisons and list edits - exactly what PLANC is comfortable with, and the ND PLANC compiler is already in use in this repo. Assembler only for anything PLANC cannot reach.
How it waits: ANSWERED from the COSMOS guide, no machine needed. XFRCV with the
XFWTF flag (bit 15, "wait if the operation is not terminated") blocks until a message arrives.
That is the whole RT server loop, and the guide gives the server shape outright:
XMPOPCN open a CONNECTION port, name it, and set the seat count
XMPFRCV wait for a message (FLAGS + XFWTF)
XMPFMST learn the sender's FULL magic number (XMPFRCV gives only a hash)
XMPFGET reserve a buffer - it becomes the CURRENT message
XMPFWRI write the reply into the current message
XMPFSND send it
XMPFREL release the message you received
Use XMPOPCN, not XMPOPNM. A room has seats, and the free-connection counter that enforces
them belongs to a CONNECTION port. XMPOPNM is a plain named port with no counter, so the seat
limit would be silently absent - and the C# side WOULD still be enforcing it, leaving the two
doors disagreeing about a rule they are meant to share. Signature:
XMPOPCN(flags, portName, uniqueName, maxConnections, portNumber).
XMSG-API.md section 7 carries this and the flag table; XFWTF=15 is in
XMSG-PL-VALUES-M.INCL. So the server does NOT need an RT wait plus polling, and nothing has to
be read off the machine to start.
Still open, and both are decisions rather than unknowns:
- Where the room table lives. An RT program's data area, sized at compile time. Eight seats times a 16-character name is small; the number just has to be chosen and stated.
- What happens on restart. An RT program that is aborted and restarted loses the room. That is acceptable and must be said out loud rather than discovered.
2b. CHAT - the client, an ordinary PROG¶
Runs from the terminal (@CHAT), like any other SINTRAN program.
open a port
find CHAT-<room> and send a join letter
loop:
read a line from the terminal, non-blocking
check for an arrived message, non-blocking
print anything that arrived
until the user types a command that leaves
The hard part is not XMSG - it is doing two things at once on a SINTRAN terminal: waiting for a keystroke while also waiting for a message.
ANSWERED, and it is simpler than feared. XFWTF is a FLAG, not a requirement: a receive
WITHOUT it returns immediately with status MXNEXTM - "not terminated", the COSMOS guide's own
example being "no message waiting when XMPFRCV is called without the XFWTF option". So XMSG can be polled without blocking, and the
client is an ordinary loop:
loop:
no-wait read from the terminal -> anything typed?
XFRCV without XFWTF -> T = 0 means nothing arrived, carry on
print whatever did arrive
No second RT program, no shared buffer, no timeout trickery. The zero-means-not-terminated
convention is in XMSG-API.md section 2 and the flag table lists XFWTF as optional on every
waitable call.
The terminal half is ANSWERED too, from Reference-Manuals/ND-860228-2-EN SINTRAN III
Monitor Calls.md, so nothing in this plan now needs a program read off the machine.
InByte (INBT, MON 1B) normally waits: "The program waits if there is no bytes in the input
buffer of the device. You can change this with NoWaitSwitch or TerminalNoWait." So switch no-wait
on first:
| Call | MON | Signature |
|---|---|---|
TerminalNoWait |
307B |
TerminalNoWait(DevNo, IOFlag, NoWaitFlag, RetStatus) |
NoWaitSwitch |
36B |
the general switch, same idea |
InByte |
1B |
InByte(DevNo, Char) |
IOFlag is 0 for input and 1 for output; NoWaitFlag is 0 to switch no-wait off and anything
else to switch it on. Use device number 1 for your own terminal.
Monitor_Call('TerminalNoWait', 1, 0, 1, status) % our terminal, input, no-wait ON
loop:
Monitor_Call('InByte', 1, ch) % returns at once now
ch := ch AND 127 % strip the parity bit - see below
XFRCV without XFWTF % T = 0 means nothing arrived
print whatever did arrive
The parity trap, and the manual warns about it in so many words. Terminal input sets bit 7 as an even-parity bit, so a carriage return arrives as 141, not 13 - the manual uses exactly that example. A client comparing against ASCII 13 would never see the user press return, and would look like a hung program rather than a bug. Mask with 127 before comparing anything.
The one thing genuinely left to measure: what InByte returns when no-wait is on and no byte
is waiting. The manual says only that the program stops waiting, not what comes back instead. That
is a five-minute experiment on the machine, not a design question, and everything else can be
written before it is answered.
3. Order of work¶
- A five-minute measurement on the machine: what
InBytereturns with no-wait on and nothing typed. It is the last unknown, and it is a value to observe rather than a decision to make. Everything below can be written before it is answered. - A one-way spike:
CHATSVopens and names a port, waits withXFRCV + XFWTF, and prints an arriving join on the operator console.CHATsends one. Nothing else. This proves the XMSG plumbing end to end inside SINTRAN, and both halves are now fully specified. - The client loop, once the no-wait terminal read is known.
- The room rules, ported from
ChatRoomwith its tests as the specification. - Two ND machines, one room, two terminals.
- Interoperate with the C# node: our
ChatClientjoins a room served byCHATSV, and a SINTRANCHATjoins a room served by ours. Same message bytes, so this should work - and if it does not, the message format is where to look first.
4. What would make this fail, stated in advance¶
- Polling where a wait belongs. The server must use
XFRCV + XFWTFand block. A polling RT program burns the machine for nothing, and the flag exists precisely so it does not have to. - Inventing a name-listing exchange. There is still no capture of one.
CHATshould take the room name as a parameter rather than offer a menu it cannot honestly build. - Assuming our message format is on the wire somewhere. It is not - we chose it. That is fine for our own two programs, and it means no capture will ever confirm it. The C# tests are the only specification, so keep them.
- Forgetting the parity bit on terminal input. Carriage return arrives as 141. Compare against 13 and the client never sees the user press return, and it looks hung rather than wrong.
5. What this gives that today's chat does not¶
Two ND machines can talk with the C# node switched off entirely. That is the point: the chat stops being a thing our emulator offers SINTRAN and becomes a thing SINTRAN does.