# MMS Programmers Guide

MMS is the resident communications and session layer for Atari Mutineer. It is
loaded before BASIC modules run, publishes a stable USR-call ABI, and in the
HATABS build intercepts normal CIO paths used by the BBS.

## Load Model

`mms/src/mms_sdx.asm` builds an SDX-loadable resident binary. The loader places
the MMS core at `MMS_BASE`, publishes the discovery record, raises `MEMLO`, and
uses the init vector so resident state survives BASIC `RUN` module changes.

Build variants are controlled by assembler defines:

- `mms-com`: base MMS build.
- `mms-com-hayes`: sends modem initialization.
- `mms-com-hatabs`: HATABS-enabled build, currently the default packaged BBS runtime.
- `mms-com-hatabs-d`: includes guarded D: wrapping for probes.
- `mms-com-hatabs-disconnect`: diagnostic disconnect-watchdog build.

The source of truth for the public ABI is `mms/src/public.inc`. The source of
truth for service IDs and status constants is `mms/src/constants.inc`.

## Public Jump Table

The stable public entry points start at `MMS_BASE`:

| Entry | Offset | Purpose |
| --- | ---: | --- |
| `MMS_INIT` | `$00` | Initialize MMS resident state. |
| `MMS_POLL` | `$03` | Poll modem/backend state. |
| `MMS_GET` / `MMS_PUT` | `$06` / `$09` | Buffered translated byte path. |
| `MMS_STATUS` | `$0C` | Publish current status bytes. |
| `MMS_RESET` | `$0F` | Reset resident state. |
| `MMS_SESSION_CLEAR` | `$12` | Clear session state. |
| `MMS_APP_SET` | `$15` | Set current/previous app handles. |
| `MMS_PREP_SWITCH` | `$18` | Prepare for a BASIC module `RUN`. |
| `MMS_RESUME_SWITCH` | `$1B` | Resume after a module load. |
| `MMS_MOPEN` | `$1E` | Open or reattach modem/session state. |
| `MMS_MCLOSE` | `$21` | Close modem IOCB. |
| `MMS_RSTAT` | `$24` | Query raw R: status. |
| `MMS_RGET` / `MMS_RPUT` | `$27` / `$2A` | Raw byte transfer path. |
| `MMS_HANGUP` | `$2D` | Hang up and clear online state. |
| `MMS_MFLUSH` | `$30` | Flush pending modem bytes. |
| `MMS_CONOUT` / `MMS_CONIN` | `$33` / `$36` | Translated console byte path. |
| `MMS_PRINT` / `MMS_INPUT` | `$39` / `$3C` | Resident print/input helpers. |
| `MMS_SET_ROUTE` / `MMS_SET_TERM` | `$3F` / `$42` | Route and terminal mode control. |
| `MMS_SYSOP` | `$45` | Sysop/session command service. |
| `MMS_FB_*` | `$48..$54` | Native fast-call bridge entries. |
| `MMS_SERVICE` | `$57` | Multiplexed service dispatcher. |
| `MMS_SET_BAUD` | `$5A` | Set the R: XIO 36 baud code. |

BASIC discovers `MMS_BASE` through locations `$03EC/$03ED`:

```basic
MBASE=PEEK(1004)+256*PEEK(1005)
MSTAT=MBASE+12:MOPEN=MBASE+30:MSERV=MBASE+87:MBAUD=MBASE+90
```

## Public Blocks

MMS publishes three documented blocks:

- `MMS_PUBLIC = MMS_BASE+$60`, 64 bytes of status and diagnostics.
- `MMS_COMMAND = MMS_BASE+$A0`, 16 bytes of command arguments/results.
- `MMS_HANDOFF = MMS_BASE+$B0`, 128 bytes of resident session handoff state.

Frequently used public bytes:

- `MMS_CONN_STATE`: connection state used by BASIC prompt checks.
- `MMS_CURRENT_APP`, `MMS_PREVIOUS_APP`, `MMS_REQUESTED_APP`, `MMS_RETURN_APP`: compact runtime app handles.
- `MMS_LAST_ERROR` and `MMS_LAST_CIO`: diagnostic status.
- `MMS_RX_COUNT_PUB`: receive count visible to BASIC.
- `MMS_HANDLER_*`: HATABS install/guard diagnostics.
- `MMS_CARRIER_STATUS`: fast handler-facing carrier byte.
- `MMS_BAUD_CODE` at `MMS_PUBLIC+$3C`: R: XIO 36 baud code used by `MMS_MOPEN`.

Connection states:

| Value | Name |
| ---: | --- |
| `0` | offline |
| `1` | waiting |
| `2` | ringing |
| `3` | online |
| `4` | suspect |
| `5` | lost |
| `6` | hangup |
| `7` | WFC |
| `8` | local |

Route values are `0` local, `1` remote, `2` both, `3` printer, `4` quiet, and
`5` host. Terminal values are `0` raw, `1` ATASCII, `2` ASCII, and `3` VT52.

Baud can be changed either by calling `USR(MBAUD,code)` or by poking the public
byte before `MMS_MOPEN` configures R:. The default code is `12` for 2400 baud.

```basic
MBASE=PEEK(1004)+256*PEEK(1005):MBAUD=MBASE+90:MBCODE=MBASE+156
R=USR(MBAUD,13):REM 4800 ON NEXT MMS_MOPEN
POKE MBCODE,14:REM 9600 NEXT TIME MMS_MOPEN CONFIGURES R:
```

Handoff bytes currently used by Mutineer:

- `+0/+1`: magic/version.
- `+2..+42`: caller handle length and text.
- `+43..+83`: secondary identity length and text.
- `+84/+85/+86`: ASCII/ATASCII, line-feed, and expert/raw-related modes.
- `+87`: online flag.
- `+90/+91`: requested stable app key.
- `+92/+93`: return stable app key.
- `+94`: pending module command.
- `+95`: command mode.
- `+96`: transient module flags or transfer mode.
- `+97`: current message base.
- `+98..+122`: transfer or door scratch data.
- `+123`: access level.
- `+124/+125`: user number.
- `+126/+127`: session end minute.

## Service Dispatcher

Call `MMS_SERVICE` with `MMS_CMD_ARG0` set to a service ID. Mutineer uses:

| ID | Service |
| ---: | --- |
| `0` | no-op |
| `1` | clear handoff |
| `2` | prepare switch |
| `3` | resume switch |
| `4` | apply terminal mode |
| `5` | clear session |
| `6` | save caller handle |
| `7` | save secondary identity |
| `8` | restore caller handle |
| `9` | restore secondary identity |
| `10` | set pending command |
| `11` | get pending command |
| `12` | set terminal modes |
| `13` | get terminal modes |
| `14` | enter raw mode |
| `15` | leave raw mode |
| `16` | query carrier |
| `17` | commit handoff |

The dispatcher uses command-block bytes for arguments and returns status in
`MMS_CMD_RESULT`. For string services, BASIC stores the address and length in
the command block before calling `USR(MSERV)`.

## HATABS And CIO

The HATABS build installs guarded handlers for normal BBS I/O. Mutineer modules
reopen CIO devices after every BASIC `RUN`:

```basic
OPEN #3,12,0,"E:"
OPEN #4,4,0,"K:"
```

Normal caller I/O should go through `E:` or `K:`. Raw file transfer code should
use `MMS_RGET`/`MMS_RPUT` after entering raw mode and must restore translated
mode on every exit path.

D: and P: handler wrappers are guarded build options. Treat D: wrapping as a
probe feature unless the D-enabled build passes its dedicated tests and full BBS
acceptance.

## Carrier And Disconnect Handling

MMS keeps `MMS_CONN_STATE` and `MMS_CARRIER_STATUS` synchronized with modem
events and backend failures. BASIC modules currently check status at prompt and
input boundaries:

```basic
R=USR(MSTAT):IF PEEK(MCONN)<>3 THEN RUN "D1:>CORE>WFC"
```

The intended stable behavior is that E:/K: input returns an error promptly when
carrier is gone, letting BASIC return to `WFC`. Do not add long timeout
loops to command modules unless they are explicitly diagnostic.

## Versioning

`MMS_VERSION` is the MMS version. Every `make mms-com*` target increments its
patch field, regenerates `mms/src/version.inc`, and assembles a binary with that
banner version. `VERSION` remains the BBS/ATR version.
