Luau Bindings — floppy
The
require("floppy")script API — real floppy disks at the flux level through a Greaseweazle: read and write flux, detect and decode formats, copy disks, format, verify, and inspect bootblocks. Everything here is[antos]. Design & native core: antos_floppy. For the everyday view — a disk as a drive letter — see filesystem.
local floppy = require("floppy")
local dev = floppy.open()
local flux = dev:read_flux{ cyl = 0, head = 0, revs = 3 }
print(floppy.detect(flux).format) --> "amiga.dd"
All functions are AntOS additions ([antos]); failures return nil, errmsg. Cylinders and heads are zero-based throughout.
Devices & media
| Function | Behaviour |
|---|---|
floppy.devices() |
Array of connected units: { id, port, model, firmware }. |
floppy.open([id]) |
Open a unit → device handle. Omit id for the first. |
dev:close() |
Release the device. |
dev:info() |
{ model, firmware, max_revs, can_write }. |
dev:drive(n) |
Select physical drive 0/1 on the cable. |
dev:media() |
{ present, write_protected, rpm, cyls, heads }; present=false for an empty drive. |
dev:on_change(fn) |
Callback on disk insert/remove — the hook the auto-mounter uses. |
dev:motor(on) |
Force the motor; normally managed automatically. |
dev:recalibrate() |
Seek to track 0 and re-establish position. |
local m = dev:media()
if not m.present then print("no disk") end
if m.write_protected then print("read-only") end
Flux
The raw level: magnetic transition timings, no interpretation.
| Function | Behaviour |
|---|---|
dev:read_flux(opts) |
Capture flux → flux object. opts: cyl, head, cyls (range), heads, revs (default 3). |
dev:write_flux(flux, opts) |
Write flux back to disk. Refuses on write-protected media. |
floppy.load_flux(path) |
Load a .scp / .hfe container from any drive letter. |
flux:save(path) |
Save as .scp / .hfe — chosen by extension. |
flux:tracks() |
Iterator over captured tracks: { cyl, head, revs, transitions }. |
flux:stats() |
{ rpm, jitter, weak_regions, unformatted } — the numbers that say why a disk is hard. |
More revolutions cost time and buy confidence on marginal media. Three is the sane default; one is for a quick look; five or more is for a disk you only get one shot at.
Detect, decode, encode
| Function | Behaviour |
|---|---|
floppy.formats() |
Array of known format ids with geometry and whether writing is supported. |
floppy.detect(flux) |
{ format, confidence, geometry }, or nil, err if nothing matches. |
floppy.decode(flux [, format]) |
Decode to sectors. Omit format to auto-detect; pass one to override. |
floppy.encode(image, format) |
Build flux from a decoded image, ready for write_flux. |
decode always returns a status map, because a partly-readable disk is the normal case:
local img, err = floppy.decode(flux)
for _, s in ipairs(img.sectors) do
-- s.status: "ok" | "crc" | "missing" | "weak" | "unformatted"
if s.status ~= "ok" then
print(("c%d h%d s%d: %s"):format(s.cyl, s.head, s.sector, s.status))
end
end
print(img.ok_count .. "/" .. img.total .. " sectors good")
That map is what the tool's error grid is drawn from — do not throw it away by testing only whether decode succeeded.
Images
| Function | Behaviour |
|---|---|
dev:read_image(path [, opts]) |
Read the disk and write an image — .adf, .img, .d64, .dsk, … by extension. |
dev:write_image(path [, opts]) |
Write an image onto the disk. |
floppy.image_info(path) |
{ format, cyls, heads, sectors, bytes } without loading it all. |
opts accepts format, cyls, retries, and on_progress — a callback of { cyl, head, status, done, total } per track, for a progress bar or a live grid.
Copy
The X-Copy modes, kept by name because they are the names people know. See floppy for what each meant and what it means now.
| Mode | Behaviour |
|---|---|
"dos" |
Decode every track, re-encode to the destination. |
"dos+" |
As "dos" with aggressive retries and read-error reporting rather than silent tolerance. |
"bam" |
Filesystem-aware — copy only allocated blocks. Needs a filesystem reader for the format. |
"nibble" |
Copy without interpreting. Now a flux copy, which preserves strictly more than the original nibble mode could. |
floppy.copy(src_dev, dst_dev, {
mode = "nibble",
cyls = { 0, 79 },
verify = true,
on_progress = function(p) grid:set(p.cyl, p.head, p.status) end,
})
floppy.copy also accepts a flux object or image path as src, so "write this .adf to a disk" and "clone this disk" are the same call.
Format, erase, verify
| Function | Behaviour |
|---|---|
dev:format(opts) |
Full format. opts: format, cyls, label, verify. |
dev:qformat(opts) |
Quick format — filesystem structures only, existing data left in place. |
dev:erase(opts) |
Erase tracks to unformatted. |
dev:verify(opts) |
Read back and check without writing; returns the same status map as decode. |
dev:speed([secs]) |
Measure drive RPM and jitter — the SPEEDCHK tool. A drive off-speed is the cause of a surprising share of "bad" disks. |
Inspecting bootblocks
| Function | Behaviour |
|---|---|
floppy.scan_boot(src) |
Scan a decoded image or flux for known bootblock viruses → nil if clean, else { name, offset, provenance }. |
floppy.signatures() |
The loaded signature table, for display or auditing. |
floppy.boot_dump(src) |
The bootblock as bytes, for the ASCII dump the tool shows. |
dev:repair_boot() |
Write a clean bootblock. Checks write-protect first, and replaces rather than zeroing. |
Report, then let the user decide. A signature match is not proof — a custom bootblock can collide — so the tool shows the dump and offers a choice. Nothing here modifies a disk on its own.
local hit = floppy.scan_boot(img)
if hit then
print("possible: " .. hit.name)
print(floppy.boot_dump(img)) -- show it, then ask
end
Mounting
| Function | Behaviour |
|---|---|
dev:mount([letter]) |
Decode the disk and publish it as a drive letter (default: the device's own port letter, normally E:). |
dev:unmount() |
Remove it. |
dev:mounted() |
The letter, or nil. |
After mount, the disk is an ordinary volume — use fs and io on it, and it is catalogued like anything else. This is the same device seen from above; the flux calls remain available on dev throughout.
Related
- antos_floppy — design & native core · floppy — the disk tool and its X-Copy inheritance · filesystem — drive letters and auto-mount · luau_data — the MFM/GCR codecs underneath · luau_fs · AntOS Libraries