Files
Nonemm/docs/unfinished.md
ericek111 917a05b898 Key MMTTY the way N1MM does, with the control's PTT property
Nothing was ever transmitted. SetMmttyPTT does not start a transmission: N1MM
calls it with 1 to stop once the buffer is empty, which is its XmitOff, and with
0 to stop now, which is its AbortXmit. A transmission starts by setting the
control's PTT property, in XmitOn.

So the bridge learns `key <0|1>` for that property, and MmttyEngine now keys
with it, ends a message with SetMmttyPTT(1) so the buffer still goes out, and
aborts with SetMmttyPTT(0). This is the digital {TX} in the entry window and the
digital window as well as the probe: none of them could key the engine before.

The probe checks that the engine keys before it measures anything, and stops
with a plain statement if it does not, rather than reporting numbers from an
engine sitting still. It also asks a new question: whether the engine holds a
word until the space after it, which is MMTTY's Way to send. Received characters
are marked as noise while the engine is not transmitting, since a machine with a
sound card decodes the band all the way through the run.

The first run on a real engine says MMTTY 1.70 connects, the control answers
TxBufLen and refuses NotAProperty with DISP_E_UNKNOWNNAME. What TxBufLen counts
is still open: read while nothing was transmitting it rose over time and rose by
four after four backspaces, which is not what characters-left would do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtspmWmS7f8kUvcyaHpRWZ
2026-09-01 22:51:43 +00:00

16 KiB

What is not finished, and what has not been tested

Two separate lists. A feature can be finished and untested, or half-built and exercised every day. Written 2026-08-27, updated 2026-08-31.

Never run against the real thing

Everything below is written from a published protocol or from N1MM's source and tested against a fake that speaks the same protocol. A fake agrees with whatever the person who wrote it believed, so these are the places where a wrong belief is still sitting there undiscovered.

What Tested against What has never happened
RigctldRadio a stand-in for rigctld over a real socket no real rigctld, no real radio. The extended answer format, the + prefix and the split commands are from the documented protocol. If the format is wrong, nothing works rather than something being subtly off — check this first.
OtrspBox a MemoryStream, checking the bytes no real SO2R box. Command forms are from N1MM's N1MMPort.cs.
ClusterClient a node fake over a real socket, sending the telnet negotiation, the login prompt and spot lines no live cluster node. Which nodes send bare CR, and which send option negotiation, is guessed from N1MM's code.
StationNetwork the message format, round-tripped no second station, and no N1MM on the same network.
CwDaemonSender the UDP messages, and a fake daemon that answers the <ESC>h reply request no cwdaemon, no radio keyed.
MmttyEngine and the Wine bridge MMTTY 1.70 under Wine 10, started and stopped through XMMT.ocx; on a machine with a sound card it connects and decodes noise off the input nothing has been transmitted yet. Keying was wrong until 2026-09-01 — SetMmttyPTT stops a transmission, it does not start one, and N1MM starts one by setting the control's PTT property — so no tx line has ever come from a real transmission. No FSK through EXTFSK, no PTT on a serial port, and 2Tone has never been run. docs/digital-bridge.md
WinkeyerSender the status-byte reader, on its own no test of the serial side, and no WinKeyer. The host-mode open sequence is from the WinKeyer datasheet; the status bits are from N1MM's Winkey.cs.

The Cabrillo output has not been put in front of a contest sponsor's robot.

Half-built

The digital window: what N1MM has and this does not. The window is here — receive pane in both of N1MM's scroll modes, the Letters/Figs and MouseOver readouts, the pause bar, coloured callsigns with N1MM's validity routines, grab list, call stacking, hover mode, the message buttons, the engine controls, the text file in and out — and the function keys, ESM and the QTC window send through the engine on a digital mode. Left out: the waterfall, the spectrum and the XY scope, which the engine reports and nothing draws; more than one receive pane, which is MMVARI's multi-channel decoding rather than MMTTY's; N1MM's AutoTRXUpdate, which offsets the frequency the entry window and the log record rather than only the one in the title bar; and N1MM's Send All, which keys a whole QTC series at once. The other interfaces N1MM offers — fldigi, MMVARI, the hardware TNCs — are not here either, though DigitalEngine is the place to add them.

The receive pane has been driven with a stand-in bridge that prints prepared text, which is how the printing, the colouring, the Letters/Figs box and the type-ahead transmit pane were checked. Nothing has been decoded from a real signal and nothing has gone on the air: this machine has no sound card, and MMTTY does not start on it.

Who holds the text waiting to go out. There are two answers in the code and a setting to pick between them: Config ▸ Digital ▸ "Let the engine hold the text waiting to go out". Off is what runs today.

Off — TypeAhead. The text is held here and the engine is kept two characters ahead: one being transmitted and one behind it, so it never runs dry and never transmits idle in the middle of a message. When the engine has room is worked out from the clock at the baud rate in the digital settings, corrected whenever the engine reports that it has stopped transmitting. The last two characters cannot be taken back. The one error left is the baud rate: if it does not match what the engine transmits at, the drift shows up as a small gap between characters near the end of a long message.

On — EngineTypeAhead. MMTTY has a type-ahead buffer of its own, which is what its own keyboard drives, so everything is pushed straight into it and an edit is expressed as backspaces followed by the new text. MMTTY paces itself, so no baud rate is needed and there is no gap by construction. TxBufLen says how many characters are left, which is what splits the pane into what has gone and what can still be changed. One character more than the count says is held back (EngineTypeAhead.Guard), because the count is a poll old and a backspace over a transmitted character is refused, which would put the text after it on the air twice.

Three things it rests on have never been seen with a real engine, and MMTTY does not start on this machine:

What is assumed Where it comes from
TxBufLen counts the characters left to transmit the name, and a probe showing the control answers to it. The first probe run, before keying worked, read it while the engine was not transmitting: it rose over time and rose by four after four backspaces, which is not what a count of characters left would do. Nothing is settled until it is read while a message is actually going out
a backspace pushed in as a character deletes one the engine has not transmitted MMTTY's help, which says the backspace key does it and works only until the letter is transmitted; and N1MM printing a received \b by deleting the last character, which can only come from MMTTY's transmit side
backspaces over transmitted characters are refused rather than doing something else nothing — this is the guess with the most to lose

tools/Nonemm.EngineProbe asks the engine all three and writes the answers to a file. It has to run where MMTTY runs:

./build.sh run --project tools/Nonemm.EngineProbe -- \
    --engine ~/mmtty/MMTTY.EXE --prefix ~/.wine-nonemm --out engine-probe.log

It transmits for about half a minute on the sound card and keys no serial port unless --ptt names one. The report says, step by step, what the engine answered; EngineProbe states what each answer means.

There is a fourth question in the report that is not needed for either buffer, but decides whether TxBufLen can be dropped later: what comes back on the receive side while transmitting, and when. With MMTTY's sound loopback off, its help says the receive window is fed from the transmit window, which would be a per-character report of what has gone out, with no polling. With loopback on it is the demodulator hearing the transmission instead, which is late and can contain decode errors, so the count is what the pane uses.

Voice keying. MessageSender was written to cover a voice keyer playing a recording, and nothing implements it. Each operator's recordings folder is stored with the rest of his settings and waits on the same thing. No DVK support either, so the second radio of an SO2R station cannot call CQ by voice. Alternating CQ therefore works on CW only, though nothing in it is CW-specific: a voice keyer that reports when the recording has finished would drive it as it stands.

The QTC window transmits on CW only. The header, the lines, the QRV, the TU and the again messages go out through the keyer, with N1MM's messages and N1MM's defaults. Nothing goes out on SSB or RTTY: N1MM plays four recordings on SSB — QRV, Agn, Cfm and TU — and sends RTTY from its digital window, and this program has neither a voice keyer nor a digital window. N1MM's Send All, which keys a whole series at once, belongs to that RTTY window and is not here either.

Cut numbers are not sent. N1MM can key a serial number as letters — N for 9, T for 0 — and offers several styles. Nothing here does, in a QTC line or in any other message.

Two WAE numbers do not agree with N1MM, both from 2020 and 2021 logs. The disagreements are the country file of the day, not the rules: 4U1A counted as 4U1V then and as OE in today's wl_cty.dat, KP2BH counted as KP2 then and is listed as a US call now, and China was not split by call area yet. The 2022 to 2025 logs agree to the contact.

Telnet window: what N1MM has and this does not. Left out: the special-calls list, and saving received spots to a database — N1MM keeps those spots in its admin database, which is not the log file the two programs share, so there is nothing to be compatible with and nothing asks to read them back. The band plan tab is not repeated either, because Config ▸ Sub bands already edits the same numbers.

The node list is downloaded from the public NG3K page rather than from N1MM's own web service, which asks the operator to opt in to data collection and is N1MM's to run. A page that changes shape would stop the download working; the reading only needs telnet:// links in a table, and the old list stays in place when a download brings back something unreadable.

Not every action macro is acted on. The text macros and the action macros that this program can carry out are listed in the README. What is read and passed over: the {CAT…} and radio-hex families, the audio and rotator macros, {STEREOON} and {STEREOOFF}, {CONDJUMP}, {QSYCQ}, {FORCELOG}, {SwapContests}, the digital TNC macros ({ENTER}, {ESC}, {CTRL-A}…), and the wav-directory macros, which wait on voice keying. A message holding any of them still sends the right characters.

The CW keyer macros are not read either: < and > for speed, ~ for a half space, and the prosign characters ], [, + and =. They belong to the keyer rather than to the expander — cwdaemon and a WinKeyer each have their own way of saying them — and they go out as the characters they are.

The busted-spot check is one character wide. N1MM offers two. Every call one character away from the spotted one is looked up in the callsign database, which is a few hundred lookups per spot; two characters away is a few hundred thousand, which is too much work per spot for the little it would add.

Two BARTG contests share one set of rules. N1MM has a class each for the March HF RTTY contest, BARTGSRTTY, and the September sprint, BARTGRTTYS. This program has one contest, named BARTGRTTYS, holding the March rules — the ones the station's log needs — and both of N1MM's names open a log with it. A sprint log would be scored by the wrong rules, and a log started here writes BARTGRTTYS into the contest name, which N1MM would read as the sprint.

Digital modes. A contact can be logged as RTTY or another digital mode, and the contest rules score it, but there is no digital window: no decoding, no transmitting, no interface to fldigi, MMTTY or similar.

Contest coverage. Twenty-five families are built in, plus whatever .udc files are in the user-defined folder. N1MM ships well over a hundred. Opening a log from a contest that is in neither place fails with the contest name, which is the right answer but it is still a wall.

Most of what is missing does not need code. A contest whose exchange is a report and one value, scored by band, mode, continent or country, and counted by country, zone, section or prefix, is a .udc file, and the file published for N1MM is read as it is. Code is for the ones .udc has no words for: WAE needs QTC traffic, IOTA needs island references as multipliers, and CQ WW RTTY needed a third multiplier and its own points table because it shares a name with the CW and SSB running of the contest.

.udc settings that are still passed over. MultiplierBands and QsoErrorString, which are about the windows rather than the score. GenericPrintString, which is the layout of a printed log rather than a Cabrillo one.

MultWindowType is read as far as the score goes: it names the list a section multiplier is checked against. Four of N1MM's lists are held here — the ARRL sections, the US states, the Canadian provinces and the OK/OM districts — and a file naming any of the hundred-odd others falls back to counting any exchange that is not all digits.

CabrilloString and CabrilloVersion are read: a contest whose sponsor asks for its own columns gets them, in N1MM's shape — the operator's callsign in the first 13 columns, then every column padded to the width the file gives with one space after it, and a value longer than its column cut rather than pushed. The numbered CabrilloFormat layouts 2, 3, 4 and 5 — the NAQP, NA Sprint, Sweepstakes and section-and-serial lines — are read as well, in N1MM's columns. The exchange those layouts split into columns is built from the boxes the file defines, in the order it defines them; N1MM builds it from the section box alone, which writes only half of a two-box exchange. Layout 6, the ARRL RTTY Roundup line, is not read, and a file asking for it gets the default line; no published .udc file asks for it, because the Roundup has a contest class of its own. CabrilloFormat = 0 means the sponsor takes no Cabrillo log at all, and nothing here stops the operator writing one.

N1MM's .udc format has no way to say that the exchange itself differs by the other station's country. OK/OM DX is written in code for that reason — it asks a county from OK and OM stations and a serial number from everyone else — and Contest.SkipsField steps over the box that does not apply. REF, ARRL 10M, the Ukrainian DX contest and the Russian DX RTTY contest ask their exchange the same way, and are written in code for the same reason.

Every contest in the station's own logs can now be opened, and its 78 contest instances score contact for contact as N1MM did apart from the cases below.

What still differs, and why:

  • The EU DX Contest is written from N1MM's own class. The station's logs were made with the EU_DXC.udc file instead, which scores a contact inside your own country 1 point where the class scores 2, and counts a district code once in the contest where the class counts it once per band.
  • Field Day Region 1: every contact in that log holds 1 point and no multiplier, which is not what N1MM's own class works out, so the log looks like it was never scored. The rules here follow the class: 5 points for a portable station, 2 for one in Region 1 at home and 3 from outside it.
  • SA 10 and OK/OM DX on SSB are not written in code at all: both are published as .udc files, and with those files in the user-defined contests folder the station's logs score to the contact. N1MM's OK/OM DX class is the CW running only and says so; the SSB running has different rules and its own pair of files, one for each side of the contest.
  • Two OK/OM DX contacts whose district code was stored with a trailing space. N1MM checks the code against its list without trimming it, finds nothing and counts no multiplier; the code is trimmed here and counts. Both contacts are the same station in the 2026 log.

Known rough edges

The band plan covers 160M to 2M only. 60M and everything above 2M get no CW, digital or phone shading on the bandmap, because N1MM's own numbers for those bands contradict themselves — its CW top for 1.25M is below its phone start, and its 70CM CW top is above the band. Config ▸ Sub bands cannot add a band that has no default.

Available mults and Qs is only as good as the bandmap. It lists what is spotted, so a multiplier nobody has spotted is not there. N1MM's window also shows the mults a contest has and nobody has worked, which needs a list of every multiplier the contest counts. Only the section and state lists are held here, so the zone and country lists would have to come from the country file first.

Two entry windows and one keyer. The SO2R box is told which radio to key before each message, but nothing stops both radios sending at once if the operator asks them to.