OricTel — full feature list
Minitel 1B terminal for the Oric 1 / Atmos · C + 6502 assembly (cc65) · EUPL 1.2 license
This page lists every OricTel feature, with an explanation of each. The GitHub repository is the authoritative, up-to-date source; the user manual and the architecture documentation cover usage and internals.
Contents
1. Videotex decoder
The heart of OricTel is a decoder for the Teletel/Antiope Videotex protocol (STUM 1B), implemented as a full state machine.
State machine
Handles ESC, CSI (with parameters), US, SS2, REP
(repeat), SEP, and the PRO1/PRO2/PRO3 protocol modes. Cursor
positioning (US row/column), moves, erases, carriage return.
PRO2 / PRO3 modes
Roll mode, lowercase, keyboard switches, extended/cursor keyboard. The left/right arrows only send cursor
sequences (ESC[D / ESC[C) if the server has enabled cursor mode (PRO3), just like a real
Minitel 1B.
Terminal identification
ENQ/ENQROM identification is deliberately silent: modern servers (MiniPavi) echo the reply into the
input field instead of consuming it — the same behaviour as the reference emulator miedit.
2. HIRES display
Resolution & grid
HIRES 240×200 pixels, i.e. 40 columns × 25 rows (6×8-pixel cells). Video inversion via bit 7, Oric serial attributes set per scanline. All 25 rows of the page belong to the server; the status bar lives on the 3 text rows the Oric still displays below the HIRES area.
Assembly rendering engine
6502 blits (blit_cell8 ~190 cycles per cell vs ~2,000 in C, blit_run for runs of
cells, blit_cell4x2 for double height). Refresh by “dirty” spans: each modified
row remembers the touched column range, and rendering is budgeted at one row per pass from the
main loop, which yields as soon as a byte is waiting in reception. Costs measured in 6502 cycles
(make bench-render): render pass ~151,000, realistic coloured text row ~79,000, single-cell update
~30,000 — a full page takes 2 to 4 s of rendering against ~8 s of arrival at 1200 baud.
Oric-1 and Atmos compatible
The HIRES switch detects the ROM at startup: jsr $EC33 on BASIC 1.1 (Atmos),
jsr $F8E3 on BASIC 1.0 (Oric-1). On-target tests are run with both ROMs.
3. Character sets
G0 / G1 / G2
- G0 — alphanumeric (Minitel ASCII, French accents).
- G1 — 2×3-block semigraphic mosaics (64 patterns), precomputed cache.
- G2 — extended CEPT, diacritics and precomposed accents (lower/uppercase).
G0/G1 switching via SI/SO; G2 characters via SS2.
4. Per-cell attributes
Complete attributes
Ink colour (0-7), background colour (0-7), flash, video inverse, underline / mosaic separation, conceal, and size: normal, double height, double width, double size. A hybrid colour heuristic approximates the Minitel's per-cell colours using the Oric's serial attributes: attributes placed on empty cells with look-ahead (colour of the following text), mosaics in solid colour when the attribute matches, luminance dithering as a fallback.
5. Rendering modes (CTRL+D)
The Oric cannot colour each cell individually like the Minitel; OricTel offers three hot-swappable strategies:
| Mode | Behaviour |
|---|---|
| AUTO (default) | Best compromise, decided line by line: attribute colours where the line allows, luminance dithering for dense multi-colour zones, white rendering for unsuitable lines. |
| DITHERING | All density dithering: the brightness hierarchy of colours is preserved as textured “greyscale”. |
| RAW | All white on black: maximum shape legibility, no colour. |
6. Connection
AT modem (the only method)
OricTel drives a Hayes modem via the ACIA 6551 at $0380 (PicoWiFiModemUSB, real or emulated by
Phosphoric --serial modem/picowifi): ATZ (reset) then
ATDT host:port (dialling = TCP connection). The server is chosen from the menu, so you can switch
without restarting the emulator.
WiFi config from the Oric
On a real LOCI + PicoWiFiModemUSB setup, the “WiFi Config” menu configures everything from the
Oric: scan (AT$SCAN) for in-range 2.4 GHz networks, selection, password entry (masked), then
association (AT$SSID=/AT$PASS=/ATC1) and saving to the Pico's NVRAM
(AT&W).
WebSocket bridge
orictel_bridge.py (Python asyncio) relays TCP (port 3615) to a WebSocket Minitel server
(ws://3617.fr/ws). Transparent binary relay, single-client, statistics, -v mode.
Link robustness
Modem left online (Oric reset, emulator closed without hanging up): the missing “OK” after
ATZ is detected, OricTel hangs up (+++, ATH) and replays ATZ
before dialling. Without “CONNECT”, an explicit failure screen offers Retry / Another server /
Enter anyway, instead of a blind session. Carrier loss: the modem's NO CARRIER,
confirmed by 4 s of silence, opens the “CARRIER LOST” screen with “1 Reconnect” — no silent redial. Delays are
counted on the VIA 6522 Timer 2, a real time base. Validated with a physical PicoWiFiModemUSB on PAVI 3617.
7. Minitel servers
| Server | Address | Notes |
|---|---|---|
| PAVI 3617 | pavi.3617.fr:3617 | recommended, Teletel home page |
| MiniPavi | go.minipavi.fr:516 | multi-service gateway |
| Other | free entry host:port | option 3 of the server menu |
8. Minitel keyboard
OricTel runs on the Oric-1 and Atmos. Function keys use CTRL+letter (both machines) or FUNCT+letter (Atmos only).
| Minitel function | Oric-1 & Atmos | Atmos only | Code sent |
|---|---|---|---|
| Send | RETURN | SEP $41 | |
| Back | CTRL+R or UP arrow | FUNCT+R | SEP $42 |
| Repeat | CTRL+E | FUNCT+E | SEP $43 |
| Guide | CTRL+G | FUNCT+G | SEP $44 |
| Cancel | CTRL+A | FUNCT+A | SEP $45 |
| Index | CTRL+S | FUNCT+S | SEP $46 |
| Correction | DELETE | SEP $47 | |
| Next | CTRL+N | FUNCT+N | SEP $48 |
| Connect/End | CTRL+C | FUNCT+C | SEP $49 |
| Left/Right arrows | LEFT/RIGHT arrow | ESC[D / ESC[C (PRO3 cursor mode) |
Local shortcuts (send nothing to the server): CTRL+D switches the
rendering mode, CTRL+L clears the screen locally, CTRL+F resets the serial link (ACIA).
ESC is the escape key: in session, ESC then ESC hangs up and returns to the menu; in a menu or an
input field, ESC cancels; on the main menu, ESC exits OricTel to BASIC.
9. Screen & status
Display area
Rows 0-24: the server's Videotex page (40 columns), row 0 included — OricTel no longer writes anything there, like a real Minitel. Cursor: blinking bar under the current cell when the server enables it (input fields). Splash screen at startup with an AY-3-8912 jingle.
Status bar (3 text rows below HIRES)
C PAVI 3617 00:12 AUTO ESC <- state (cyan)
ESC: quitter? ESC=menu autre=reprendre <- messages (yellow)
^A Annul ^R Retour ^S Somm ^N Suite <- help (white)
Inverted C = data received recently (connected), F = no data for 30 s (link probably
down); then the chosen server, the session timer (mm:ss) and the current
rendering mode (AUTO/TRAME/BRUT). The middle row carries
messages (ESC prompt, ACIA reset), the last one the key help.
10. Technical specifications
Serial (ACIA 6551)
ACIA 6551 at the LOCI base ($0380). Registers: data $0380, status/reset
$0381, command $0382, control $0383. Control $18
(1200 baud, 8N1, internal clock), command $0B (DTR, RX IRQ disabled, RTS low without TX IRQ).
Pure polling of the STATUS register, no ACIA IRQ; the init and every byte access are
SEI/PLP-protected (MIA constraint of the real LOCI). Non-blocking software transmit queue drained by the main
loop. The LOCI firmware puts a 32-byte ring in front of the register: ~250,000 cycles of
tolerance between two reads at 1200 baud. As the /DCD bit does not follow the call state on LOCI, carrier loss
is detected through the NO CARRIER response.
Memory
TAP ~28 KB (CODE 25.5 KB, RODATA 2.3 KB, BSS 7.7 KB); code+data below $9800; status-bar
character set $9800-$9BFF; cc65 stack $9C00-$9FFF (1 KB); HIRES framebuffer
$A000-$BF3F; 3 text rows $BF68-$BFDF.
Protocol & performance
Teletel/Antiope Videotex (STUM 1B). Budget of one byte at 1200 baud: 8,333 cycles. Measured:
vtx_process() ~2,600 cycles per byte, render pass ~151,000 cycles (18.8 byte-times), single-cell
update ~30,000 (3.6). Validity reference: the JS emulator miedit/telenet; fidelity checked against real
servers (make test-servers, PAVI 3617 and MiniPavi).
11. Build & run
make # build orictel.tap
make dsk # Sedoric floppy orictel.dsk (MFM_DISK, bootable)
make test # host + target tests (Videotex, ACIA/SMC, AT modem, keyboard, UI, menus, carrier, bridge)
make fuzz # Videotex decoder fuzzing (ASAN/UBSAN)
make coverage # host gcov coverage
make bench-render # HIRES rendering benchmark in 6502 cycles
make test-servers # decoding fidelity against real servers (dongle required)
make run # run under Phosphoric in AT modem mode
make run-loci # physical PicoWiFiModemUSB on /dev/ttyACM*
make run-ws # run the WebSocket bridge + the emulator
make run-dsk # Microdisc boot of the Sedoric floppy
Prerequisites: cc65 (≥ 2.19), Python 3.8+ with websockets ≥ 12.0 (bridge
only), the Phosphoric emulator (or a physical LOCI/PicoWiFiModemUSB), and the Oric
ROMs (basic11b.rom for Atmos, basic10.rom for Oric-1). Test suite:
344 checks, including menu walkthroughs and an on-target measurement of the carrier-loss delay.
12. Known limitations
- Minitel per-cell colours are approximated with the Oric's serial attributes: on a row with no usable empty cell, a text's colour may be lost (rendered white).
- MIXED mode (80-column tele-computing) is not supported.
- Terminal identification (ENQ/ENQROM) is deliberately silent (aligned with miedit).
- The asymmetric V23 configuration (1200/75 baud, 7E1) is no longer a target: the supported setup is LOCI + PicoWiFiModemUSB, which talks 1200 8N1.
- Validated with a physical PicoWiFiModemUSB through Phosphoric's co-simulated chain (real LOCI firmware); end-to-end validation on a real Oric-1 remains to be confirmed.