Merge pull request #822 from davidgiven/config

Overhaul the config file CLI.
This commit is contained in:
David Given
2025-08-21 18:42:21 +02:00
committed by GitHub
51 changed files with 359 additions and 349 deletions

View File

@@ -28,7 +28,7 @@ else:
("acorndfs", "", "--200"),
("agat", "", ""),
("amiga", "", ""),
("apple2", "", "--140 40track_drive"),
("apple2", "", "--140 --drivetype=40"),
("atarist", "", "--360"),
("atarist", "", "--370"),
("atarist", "", "--400"),
@@ -38,17 +38,17 @@ else:
("atarist", "", "--800"),
("atarist", "", "--820"),
("bk", "", ""),
("brother", "", "--120 40track_drive"),
("brother", "", "--120 --drivetype=40"),
("brother", "", "--240"),
(
"commodore",
"scripts/commodore1541_test.textpb",
"--171 40track_drive",
"--171 --drivetype=40",
),
(
"commodore",
"scripts/commodore1541_test.textpb",
"--192 40track_drive",
"--192 --drivetype=40",
),
("commodore", "", "--800"),
("commodore", "", "--1620"),
@@ -60,17 +60,17 @@ else:
("ibm", "", "--1232"),
("ibm", "", "--1440"),
("ibm", "", "--1680"),
("ibm", "", "--180 40track_drive"),
("ibm", "", "--160 40track_drive"),
("ibm", "", "--320 40track_drive"),
("ibm", "", "--360 40track_drive"),
("ibm", "", "--180 --drivetype=40"),
("ibm", "", "--160 --drivetype=40"),
("ibm", "", "--320 --drivetype=40"),
("ibm", "", "--360 --drivetype=40"),
("ibm", "", "--720_96"),
("ibm", "", "--720_135"),
("mac", "scripts/mac400_test.textpb", "--400"),
("mac", "scripts/mac800_test.textpb", "--800"),
("n88basic", "", ""),
("rx50", "", ""),
("tartu", "", "--390 40track_drive"),
("tartu", "", "--390 --drivetype=40"),
("tartu", "", "--780"),
("tids990", "", ""),
("victor9k", "", "--612"),

View File

@@ -31,9 +31,9 @@ they might require nudging as the side order can't be reliably autodetected.
To read:
- `fluxengine read acornadfs --160 -s drive:0 -o acornadfs.img`
- `fluxengine read acornadfs --320 -s drive:0 -o acornadfs.img`
- `fluxengine read acornadfs --640 -s drive:0 -o acornadfs.img`
- `fluxengine read acornadfs --800 -s drive:0 -o acornadfs.img`
- `fluxengine read acornadfs --1600 -s drive:0 -o acornadfs.img`
- `fluxengine read -c acornadfs --160 -s drive:0 -o acornadfs.img`
- `fluxengine read -c acornadfs --320 -s drive:0 -o acornadfs.img`
- `fluxengine read -c acornadfs --640 -s drive:0 -o acornadfs.img`
- `fluxengine read -c acornadfs --800 -s drive:0 -o acornadfs.img`
- `fluxengine read -c acornadfs --1600 -s drive:0 -o acornadfs.img`

View File

@@ -24,13 +24,13 @@ requires a bit of fiddling as they have the same tracks on twice.
To read:
- `fluxengine read acorndfs --100 -s drive:0 -o acorndfs.img`
- `fluxengine read acorndfs --200 -s drive:0 -o acorndfs.img`
- `fluxengine read -c acorndfs --100 -s drive:0 -o acorndfs.img`
- `fluxengine read -c acorndfs --200 -s drive:0 -o acorndfs.img`
To write:
- `fluxengine write acorndfs --100 -d drive:0 -i acorndfs.img`
- `fluxengine write acorndfs --200 -d drive:0 -i acorndfs.img`
- `fluxengine write -c acorndfs --100 -d drive:0 -i acorndfs.img`
- `fluxengine write -c acorndfs --200 -d drive:0 -i acorndfs.img`
## References

View File

@@ -37,7 +37,7 @@ based on what looks right. If anyone knows _anything_ about these disks,
To read:
- `fluxengine read aeslanier -s drive:0 -o aeslanier.img`
- `fluxengine read -c aeslanier -s drive:0 -o aeslanier.img`
## References

View File

@@ -20,11 +20,11 @@ profile.
To read:
- `fluxengine read agat -s drive:0 -o agat.img`
- `fluxengine read -c agat -s drive:0 -o agat.img`
To write:
- `fluxengine write agat -d drive:0 -i agat.img`
- `fluxengine write -c agat -d drive:0 -i agat.img`
## References

View File

@@ -26,11 +26,11 @@ distinctly subpar and not particularly good at detecting errors.
To read:
- `fluxengine read amiga -s drive:0 -o amiga.adf`
- `fluxengine read -c amiga -s drive:0 -o amiga.adf`
To write:
- `fluxengine write amiga -d drive:0 -i amiga.adf`
- `fluxengine write -c amiga -d drive:0 -i amiga.adf`
## References

View File

@@ -43,8 +43,8 @@ kayinfo.lbr
To read:
- `fluxengine read ampro --400 -s drive:0 -o ampro.img`
- `fluxengine read ampro --800 -s drive:0 -o ampro.img`
- `fluxengine read -c ampro --400 -s drive:0 -o ampro.img`
- `fluxengine read -c ampro --800 -s drive:0 -o ampro.img`
## References

View File

@@ -58,13 +58,13 @@ volume.
To read:
- `fluxengine read apple2 --140 -s drive:0 -o apple2.img`
- `fluxengine read apple2 --640 -s drive:0 -o apple2.img`
- `fluxengine read -c apple2 --140 -s drive:0 -o apple2.img`
- `fluxengine read -c apple2 --640 -s drive:0 -o apple2.img`
To write:
- `fluxengine write apple2 --140 -d drive:0 -i apple2.img`
- `fluxengine write apple2 --640 -d drive:0 -i apple2.img`
- `fluxengine write -c apple2 --140 -d drive:0 -i apple2.img`
- `fluxengine write -c apple2 --640 -d drive:0 -i apple2.img`
## References

View File

@@ -29,25 +29,25 @@ Be aware that many PC drives (including mine) won't do the 82 track formats.
To read:
- `fluxengine read atarist --360 -s drive:0 -o atarist.img`
- `fluxengine read atarist --370 -s drive:0 -o atarist.img`
- `fluxengine read atarist --400 -s drive:0 -o atarist.img`
- `fluxengine read atarist --410 -s drive:0 -o atarist.img`
- `fluxengine read atarist --720 -s drive:0 -o atarist.img`
- `fluxengine read atarist --740 -s drive:0 -o atarist.img`
- `fluxengine read atarist --800 -s drive:0 -o atarist.img`
- `fluxengine read atarist --820 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --360 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --370 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --400 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --410 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --720 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --740 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --800 -s drive:0 -o atarist.img`
- `fluxengine read -c atarist --820 -s drive:0 -o atarist.img`
To write:
- `fluxengine write atarist --360 -d drive:0 -i atarist.img`
- `fluxengine write atarist --370 -d drive:0 -i atarist.img`
- `fluxengine write atarist --400 -d drive:0 -i atarist.img`
- `fluxengine write atarist --410 -d drive:0 -i atarist.img`
- `fluxengine write atarist --720 -d drive:0 -i atarist.img`
- `fluxengine write atarist --740 -d drive:0 -i atarist.img`
- `fluxengine write atarist --800 -d drive:0 -i atarist.img`
- `fluxengine write atarist --820 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --360 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --370 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --400 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --410 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --720 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --740 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --800 -d drive:0 -i atarist.img`
- `fluxengine write -c atarist --820 -d drive:0 -i atarist.img`
## References

View File

@@ -22,9 +22,9 @@ on what was available at the time, with the same format on both.
To read:
- `fluxengine read bk -s drive:0 -o bk800.img`
- `fluxengine read -c bk -s drive:0 -o bk800.img`
To write:
- `fluxengine write bk -d drive:0 -i bk800.img`
- `fluxengine write -c bk -d drive:0 -i bk800.img`

View File

@@ -44,13 +44,13 @@ investigate.
To read:
- `fluxengine read brother --120 -s drive:0 -o brother.img`
- `fluxengine read brother --240 -s drive:0 -o brother.img`
- `fluxengine read -c brother --120 -s drive:0 -o brother.img`
- `fluxengine read -c brother --240 -s drive:0 -o brother.img`
To write:
- `fluxengine write brother --120 -d drive:0 -i brother.img`
- `fluxengine write brother --240 -d drive:0 -i brother.img`
- `fluxengine write -c brother --120 -d drive:0 -i brother.img`
- `fluxengine write -c brother --240 -d drive:0 -i brother.img`
Dealing with misaligned disks
-----------------------------

View File

@@ -54,18 +54,18 @@ A CMD FD2000 disk (a popular third-party Commodore disk drive)
To read:
- `fluxengine read commodore --171 -s drive:0 -o commodore.d64`
- `fluxengine read commodore --192 -s drive:0 -o commodore.d64`
- `fluxengine read commodore --800 -s drive:0 -o commodore.d64`
- `fluxengine read commodore --1042 -s drive:0 -o commodore.d64`
- `fluxengine read commodore --1620 -s drive:0 -o commodore.d64`
- `fluxengine read -c commodore --171 -s drive:0 -o commodore.d64`
- `fluxengine read -c commodore --192 -s drive:0 -o commodore.d64`
- `fluxengine read -c commodore --800 -s drive:0 -o commodore.d64`
- `fluxengine read -c commodore --1042 -s drive:0 -o commodore.d64`
- `fluxengine read -c commodore --1620 -s drive:0 -o commodore.d64`
To write:
- `fluxengine write commodore --171 -d drive:0 -i commodore.d64`
- `fluxengine write commodore --192 -d drive:0 -i commodore.d64`
- `fluxengine write commodore --800 -d drive:0 -i commodore.d64`
- `fluxengine write commodore --1620 -d drive:0 -i commodore.d64`
- `fluxengine write -c commodore --171 -d drive:0 -i commodore.d64`
- `fluxengine write -c commodore --192 -d drive:0 -i commodore.d64`
- `fluxengine write -c commodore --800 -d drive:0 -i commodore.d64`
- `fluxengine write -c commodore --1620 -d drive:0 -i commodore.d64`
## References

View File

@@ -33,7 +33,7 @@ images.
To read:
- `fluxengine read eco1 -s drive:0 -o eco1.img`
- `fluxengine read -c eco1 -s drive:0 -o eco1.img`
## References

View File

@@ -15,5 +15,5 @@ format itself is yet another IBM scheme variant.
To read:
- `fluxengine read epsonpf10 -s drive:0 -o epsonpf10.img`
- `fluxengine read -c epsonpf10 -s drive:0 -o epsonpf10.img`

View File

@@ -36,7 +36,7 @@ touch](https://github.com/davidgiven/fluxengine/issues/new).
To read:
- `fluxengine read f85 -s drive:0 -o f85.img`
- `fluxengine read -c f85 -s drive:0 -o f85.img`
## References

View File

@@ -30,7 +30,7 @@ I don't have access to one of those disks.
To read:
- `fluxengine read fb100 -s drive:0 -o fb100.img`
- `fluxengine read -c fb100 -s drive:0 -o fb100.img`
## References

View File

@@ -23,17 +23,17 @@ encoding scheme.
To read:
- `fluxengine read hplif --264 -s drive:0 -o hplif.img`
- `fluxengine read hplif --608 -s drive:0 -o hplif.img`
- `fluxengine read hplif --616 -s drive:0 -o hplif.img`
- `fluxengine read hplif --770 -s drive:0 -o hplif.img`
- `fluxengine read -c hplif --264 -s drive:0 -o hplif.img`
- `fluxengine read -c hplif --608 -s drive:0 -o hplif.img`
- `fluxengine read -c hplif --616 -s drive:0 -o hplif.img`
- `fluxengine read -c hplif --770 -s drive:0 -o hplif.img`
To write:
- `fluxengine write hplif --264 -d drive:0 -i hplif.img`
- `fluxengine write hplif --608 -d drive:0 -i hplif.img`
- `fluxengine write hplif --616 -d drive:0 -i hplif.img`
- `fluxengine write hplif --770 -d drive:0 -i hplif.img`
- `fluxengine write -c hplif --264 -d drive:0 -i hplif.img`
- `fluxengine write -c hplif --608 -d drive:0 -i hplif.img`
- `fluxengine write -c hplif --616 -d drive:0 -i hplif.img`
- `fluxengine write -c hplif --770 -d drive:0 -i hplif.img`
## References

View File

@@ -55,30 +55,30 @@ image format. FluxEngine will use these parameters.
To read:
- `fluxengine read ibm --auto -s drive:0 -o ibm.img`
- `fluxengine read ibm --160 -s drive:0 -o ibm.img`
- `fluxengine read ibm --180 -s drive:0 -o ibm.img`
- `fluxengine read ibm --320 -s drive:0 -o ibm.img`
- `fluxengine read ibm --360 -s drive:0 -o ibm.img`
- `fluxengine read ibm --720_96 -s drive:0 -o ibm.img`
- `fluxengine read ibm --720_135 -s drive:0 -o ibm.img`
- `fluxengine read ibm --1200 -s drive:0 -o ibm.img`
- `fluxengine read ibm --1232 -s drive:0 -o ibm.img`
- `fluxengine read ibm --1440 -s drive:0 -o ibm.img`
- `fluxengine read ibm --1680 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --auto -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --160 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --180 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --320 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --360 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --720_96 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --720_135 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --1200 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --1232 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --1440 -s drive:0 -o ibm.img`
- `fluxengine read -c ibm --1680 -s drive:0 -o ibm.img`
To write:
- `fluxengine write ibm --160 -d drive:0 -i ibm.img`
- `fluxengine write ibm --180 -d drive:0 -i ibm.img`
- `fluxengine write ibm --320 -d drive:0 -i ibm.img`
- `fluxengine write ibm --360 -d drive:0 -i ibm.img`
- `fluxengine write ibm --720_96 -d drive:0 -i ibm.img`
- `fluxengine write ibm --720_135 -d drive:0 -i ibm.img`
- `fluxengine write ibm --1200 -d drive:0 -i ibm.img`
- `fluxengine write ibm --1232 -d drive:0 -i ibm.img`
- `fluxengine write ibm --1440 -d drive:0 -i ibm.img`
- `fluxengine write ibm --1680 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --160 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --180 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --320 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --360 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --720_96 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --720_135 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --1200 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --1232 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --1440 -d drive:0 -i ibm.img`
- `fluxengine write -c ibm --1680 -d drive:0 -i ibm.img`
Mixed-format disks
------------------

View File

@@ -15,5 +15,5 @@ track! Other than that it's another IBM scheme variation.
To read:
- `fluxengine read icl30 -s drive:0 -o icl30.img`
- `fluxengine read -c icl30 -s drive:0 -o icl30.img`

View File

@@ -47,13 +47,13 @@ standard for disk images is to omit it. If you want them, specify that you want
To read:
- `fluxengine read mac --400 -s drive:0 -o mac.dsk`
- `fluxengine read mac --800 -s drive:0 -o mac.dsk`
- `fluxengine read -c mac --400 -s drive:0 -o mac.dsk`
- `fluxengine read -c mac --800 -s drive:0 -o mac.dsk`
To write:
- `fluxengine write mac --400 -d drive:0 -i mac.dsk`
- `fluxengine write mac --800 -d drive:0 -i mac.dsk`
- `fluxengine write -c mac --400 -d drive:0 -i mac.dsk`
- `fluxengine write -c mac --800 -d drive:0 -i mac.dsk`
## References

View File

@@ -63,11 +63,11 @@ need to apply extra options to change the format if desired.
To read:
- `fluxengine read micropolis -s drive:0 -o micropolis.img`
- `fluxengine read -c micropolis -s drive:0 -o micropolis.img`
To write:
- `fluxengine write micropolis -d drive:0 -i micropolis.img`
- `fluxengine write -c micropolis -d drive:0 -i micropolis.img`
## References

View File

@@ -52,10 +52,10 @@ Words are all stored little-endian.
To read:
- `fluxengine read mx --110 -s drive:0 -o mx.img`
- `fluxengine read mx --220ds -s drive:0 -o mx.img`
- `fluxengine read mx --220ss -s drive:0 -o mx.img`
- `fluxengine read mx --440 -s drive:0 -o mx.img`
- `fluxengine read -c mx --110 -s drive:0 -o mx.img`
- `fluxengine read -c mx --220ds -s drive:0 -o mx.img`
- `fluxengine read -c mx --220ss -s drive:0 -o mx.img`
- `fluxengine read -c mx --440 -s drive:0 -o mx.img`
## References

View File

@@ -18,9 +18,9 @@ boot ROM could only read single density data.)
To read:
- `fluxengine read n88basic -s drive:0 -o n88basic.img`
- `fluxengine read -c n88basic -s drive:0 -o n88basic.img`
To write:
- `fluxengine write n88basic -d drive:0 -i n88basic.img`
- `fluxengine write -c n88basic -d drive:0 -i n88basic.img`

View File

@@ -31,15 +31,15 @@ equivalent to .img images.
To read:
- `fluxengine read northstar --87 -s drive:0 -o northstar.nsi`
- `fluxengine read northstar --175 -s drive:0 -o northstar.nsi`
- `fluxengine read northstar --350 -s drive:0 -o northstar.nsi`
- `fluxengine read -c northstar --87 -s drive:0 -o northstar.nsi`
- `fluxengine read -c northstar --175 -s drive:0 -o northstar.nsi`
- `fluxengine read -c northstar --350 -s drive:0 -o northstar.nsi`
To write:
- `fluxengine write northstar --87 -d drive:0 -i northstar.nsi`
- `fluxengine write northstar --175 -d drive:0 -i northstar.nsi`
- `fluxengine write northstar --350 -d drive:0 -i northstar.nsi`
- `fluxengine write -c northstar --87 -d drive:0 -i northstar.nsi`
- `fluxengine write -c northstar --175 -d drive:0 -i northstar.nsi`
- `fluxengine write -c northstar --350 -d drive:0 -i northstar.nsi`
## References

View File

@@ -24,9 +24,9 @@ and, oddly, swapped sides.
To read:
- `fluxengine read psos -s drive:0 -o pme.img`
- `fluxengine read -c psos -s drive:0 -o pme.img`
To write:
- `fluxengine write psos -d drive:0 -i pme.img`
- `fluxengine write -c psos -d drive:0 -i pme.img`

View File

@@ -40,9 +40,9 @@ for assistance with this!
To read:
- `fluxengine read rolandd20 -s drive:0 -o rolandd20.img`
- `fluxengine read -c rolandd20 -s drive:0 -o rolandd20.img`
To write:
- `fluxengine write rolandd20 -d drive:0 -i rolandd20.img`
- `fluxengine write -c rolandd20 -d drive:0 -i rolandd20.img`

View File

@@ -15,9 +15,9 @@ vanilla single-sided IBM scheme variation.
To read:
- `fluxengine read rx50 -s drive:0 -o rx50.img`
- `fluxengine read -c rx50 -s drive:0 -o rx50.img`
To write:
- `fluxengine write rx50 -d drive:0 -i rx50.img`
- `fluxengine write -c rx50 -d drive:0 -i rx50.img`

View File

@@ -26,7 +26,7 @@ this is completely correct, so don't trust it!
To read:
- `fluxengine read smaky6 -s drive:0 -o smaky6.img`
- `fluxengine read -c smaky6 -s drive:0 -o smaky6.img`
## References

View File

@@ -34,13 +34,13 @@ FluxEngine supports reading and writing Tartu disks with CP/M filesystem access.
To read:
- `fluxengine read tartu --390 -s drive:0 -o tartu.img`
- `fluxengine read tartu --780 -s drive:0 -o tartu.img`
- `fluxengine read -c tartu --390 -s drive:0 -o tartu.img`
- `fluxengine read -c tartu --780 -s drive:0 -o tartu.img`
To write:
- `fluxengine write tartu --390 -d drive:0 -i tartu.img`
- `fluxengine write tartu --780 -d drive:0 -i tartu.img`
- `fluxengine write -c tartu --390 -d drive:0 -i tartu.img`
- `fluxengine write -c tartu --780 -d drive:0 -i tartu.img`
## References

View File

@@ -26,11 +26,11 @@ FluxEngine will read and write these (but only the DSDD MFM variant).
To read:
- `fluxengine read tids990 -s drive:0 -o tids990.img`
- `fluxengine read -c tids990 -s drive:0 -o tids990.img`
To write:
- `fluxengine write tids990 -d drive:0 -i tids990.img`
- `fluxengine write -c tids990 -d drive:0 -i tids990.img`
## References

View File

@@ -20,8 +20,8 @@ on the precise format.
To read:
- `fluxengine read tiki --90 -s drive:0 -o tiki.img`
- `fluxengine read tiki --200 -s drive:0 -o tiki.img`
- `fluxengine read tiki --400 -s drive:0 -o tiki.img`
- `fluxengine read tiki --800 -s drive:0 -o tiki.img`
- `fluxengine read -c tiki --90 -s drive:0 -o tiki.img`
- `fluxengine read -c tiki --200 -s drive:0 -o tiki.img`
- `fluxengine read -c tiki --400 -s drive:0 -o tiki.img`
- `fluxengine read -c tiki --800 -s drive:0 -o tiki.img`

View File

@@ -46,13 +46,13 @@ FluxEngine can read and write both the single-sided and double-sided variants.
To read:
- `fluxengine read victor9k --612 -s drive:0 -o victor9k.img`
- `fluxengine read victor9k --1224 -s drive:0 -o victor9k.img`
- `fluxengine read -c victor9k --612 -s drive:0 -o victor9k.img`
- `fluxengine read -c victor9k --1224 -s drive:0 -o victor9k.img`
To write:
- `fluxengine write victor9k --612 -d drive:0 -i victor9k.img`
- `fluxengine write victor9k --1224 -d drive:0 -i victor9k.img`
- `fluxengine write -c victor9k --612 -d drive:0 -i victor9k.img`
- `fluxengine write -c victor9k --1224 -d drive:0 -i victor9k.img`
## References

View File

@@ -31,7 +31,7 @@ system.
To read:
- `fluxengine read zilogmcz -s drive:0 -o zilogmcz.img`
- `fluxengine read -c zilogmcz -s drive:0 -o zilogmcz.img`
## References

View File

@@ -82,16 +82,16 @@ Here are some sample invocations:
```
# Read an PC 1440kB disk, producing a disk image with the default name
# (ibm.img)
$ fluxengine read ibm --1440
$ fluxengine read -c ibm --1440
# Write a PC 1440kB disk to drive 1
$ fluxengine write ibm --1440 -i image.img -d drive:1
$ fluxengine write -c ibm --1440 -i image.img -d drive:1
# Read a Eco1 CP/M disk, making a copy of the flux into a file
$ fluxengine read eco1 --copy-flux-to copy.flux -o eco1.ldbs
$ fluxengine read -c eco1 --copy-flux-to copy.flux -o eco1.ldbs
# Rerun the decode from the flux file, tweaking the parameters
$ fluxengine read eco1 -s copy.flux -o eco1.ldbs --cylinders=1
$ fluxengine read -c eco1 -s copy.flux -o eco1.ldbs --cylinders=1
```
### Configuration
@@ -146,14 +146,14 @@ different task. Run each one with `--help` to get a full list of
(non-configuration-setting) options; this describes only basic usage of the
more common tools.
- `fluxengine read <profile> <options> -s <flux source> -o <image output>`
- `fluxengine read -c <profile> <options> -s <flux source> -o <image output>`
Reads flux (possibly from a disk) and decodes it into a file system image.
`<profile>` is a reference to an internal input configuration file
describing the format. `<options>` may be any combination of options
defined by the profile.
- `fluxengine write <profile> -i <image input> -d <flux destination>`
- `fluxengine write -c <profile> -i <image input> -d <flux destination>`
Reads a filesystem image and encodes it into flux (possibly writing to a
disk). `<profile>` is a reference to an internal output configuration file
@@ -489,7 +489,7 @@ containing valuable historical data, and you want to read them.
Typically I do this:
```
$ fluxengine read brother240 -s drive:0 -o brother.img --copy-flux-to=brother.flux --decoder.write_csv_to=brother.csv
$ fluxengine read -c brother240 -s drive:0 -o brother.img --copy-flux-to=brother.flux --decoder.write_csv_to=brother.csv
```
This will read the disk in drive 0 and write out an information CSV file. It'll
@@ -499,7 +499,7 @@ settings, I can rerun the decode without having to physically touch the disk
like this:
```
$ fluxengine read brother -s brother.flux -o brother.img --decoder.write_csv_to=brother.csv
$ fluxengine read -c brother -s brother.flux -o brother.img --decoder.write_csv_to=brother.csv
```
Apart from being drastically faster, this avoids touching the (potentially

View File

@@ -5,6 +5,7 @@
#include "lib/core/utils.h"
#include <fstream>
#include <google/protobuf/text_format.h>
#include <fmt/ranges.h>
static Config config;
@@ -181,35 +182,8 @@ ConfigProto* Config::combined()
{
_combinedConfig = _baseConfig;
/* First apply any standalone options. */
std::set<std::string> options = _appliedOptions;
for (const auto& option : _baseConfig.option())
{
if (options.find(option.name()) != options.end())
{
_combinedConfig.MergeFrom(option.config());
options.erase(option.name());
}
}
/* Then apply any group options. */
for (auto& group : _baseConfig.option_group())
{
const OptionProto* selectedOption = &*group.option().begin();
for (auto& option : group.option())
{
if (options.find(option.name()) != options.end())
{
selectedOption = &option;
options.erase(option.name());
}
}
_combinedConfig.MergeFrom(selectedOption->config());
}
for (const auto& optionInfo : _appliedOptions)
_combinedConfig.MergeFrom(optionInfo.option->config());
/* Add in the user overrides. */
@@ -241,51 +215,27 @@ std::vector<std::string> Config::validate()
{
std::vector<std::string> results;
std::set<std::string> optionNames = _appliedOptions;
std::set<const OptionProto*> appliedOptions;
for (const auto& option : _baseConfig.option())
{
if (optionNames.find(option.name()) != optionNames.end())
{
appliedOptions.insert(&option);
optionNames.erase(option.name());
}
}
/* Ensure that only one item in each group is set. */
/* Then apply any group options. */
for (auto& group : _baseConfig.option_group())
std::map<const OptionGroupProto*, const OptionProto*> optionsByGroup;
for (auto [group, option, hasArgument] : _appliedOptions)
if (group)
{
int count = 0;
for (auto& option : group.option())
{
if (optionNames.find(option.name()) != optionNames.end())
{
optionNames.erase(option.name());
appliedOptions.insert(&option);
count++;
if (count == 2)
auto& o = optionsByGroup[group];
if (o)
results.push_back(
fmt::format("multiple mutually exclusive options set "
"for group '{}'",
group.comment()));
}
}
}
/* Check for unknown options. */
if (!optionNames.empty())
{
for (auto& name : optionNames)
results.push_back(fmt::format("'{}' is not a known option", name));
fmt::format("multiple mutually exclusive values set for "
"group '{}': valid values are: {}",
group->comment(),
fmt::join(std::views::transform(
group->option(), &OptionProto::name),
", ")));
o = option;
}
/* Check option requirements. */
for (auto& option : appliedOptions)
for (auto [group, option, hasArgument] : _appliedOptions)
{
try
{
@@ -360,11 +310,12 @@ void Config::readBaseConfig(std::string data)
error("couldn't load external config proto");
}
const OptionProto& Config::findOption(const std::string& optionName)
Config::OptionInfo Config::findOption(
const std::string& name, const std::string value)
{
const OptionProto* found = nullptr;
auto searchOptionList = [&](auto& optionList)
auto searchOptionList = [&](auto& optionList, const std::string& optionName)
{
for (const auto& option : optionList)
{
@@ -377,17 +328,39 @@ const OptionProto& Config::findOption(const std::string& optionName)
return false;
};
if (searchOptionList(base()->option()))
return *found;
/* First look for any group names which match. */
if (!value.empty())
for (const auto& optionGroup : base()->option_group())
if (optionGroup.name() == name)
{
/* The option must therefore be one of these. */
if (searchOptionList(optionGroup.option(), value))
return {&optionGroup, found, true};
throw OptionNotFoundException(fmt::format(
"value {} is not valid for option {}; valid values are: {}",
value,
name,
fmt::join(std::views::transform(
optionGroup.option(), &OptionProto::name),
", ")));
}
/* Now search for individual options. */
if (searchOptionList(base()->option(), name))
return {nullptr, found, false};
for (const auto& optionGroup : base()->option_group())
{
if (searchOptionList(optionGroup.option()))
return *found;
if (optionGroup.name().empty())
if (searchOptionList(optionGroup.option(), name))
return {nullptr, found, false};
}
throw OptionNotFoundException(
fmt::format("option {} not found", optionName));
throw OptionNotFoundException(fmt::format("option {} not found", name));
}
void Config::checkOptionValid(const OptionProto& option)
@@ -445,22 +418,20 @@ bool Config::isOptionValid(const OptionProto& option)
}
}
bool Config::isOptionValid(std::string option)
{
return isOptionValid(findOption(option));
}
void Config::applyOption(const OptionProto& option)
void Config::applyOption(const OptionInfo& optionInfo)
{
auto* option = optionInfo.option;
log(OptionLogMessage{
option.has_message() ? option.message() : option.comment()});
option->has_message() ? option->message() : option->comment()});
_appliedOptions.insert(option.name());
_appliedOptions.insert(optionInfo);
}
void Config::applyOption(std::string option)
bool Config::applyOption(const std::string& name, const std::string value)
{
applyOption(findOption(option));
auto optionInfo = findOption(name, value);
applyOption(optionInfo);
return optionInfo.usesValue;
}
void Config::clearOptions()

View File

@@ -66,6 +66,18 @@ struct FluxConstructor
class Config
{
private:
struct OptionInfo
{
bool operator==(const OptionInfo& other) const = default;
std::strong_ordering operator<=>(
const OptionInfo& other) const = default;
const OptionGroupProto* group;
const OptionProto* option;
bool usesValue;
};
public:
/* Direct access to the various proto layers. */
@@ -124,12 +136,12 @@ public:
/* Option management: look up an option by name, determine whether an option
* is valid, and apply an option. */
const OptionProto& findOption(const std::string& option);
OptionInfo findOption(
const std::string& name, const std::string value = "");
void checkOptionValid(const OptionProto& option);
bool isOptionValid(const OptionProto& option);
bool isOptionValid(std::string option);
void applyOption(const OptionProto& option);
void applyOption(std::string option);
void applyOption(const OptionInfo& optionInfo);
bool applyOption(const std::string& name, const std::string value = "");
void clearOptions();
/* Adjust overall inputs and outputs. */
@@ -165,7 +177,7 @@ private:
ConfigProto _baseConfig;
ConfigProto _overridesConfig;
ConfigProto _combinedConfig;
std::set<std::string> _appliedOptions;
std::set<OptionInfo> _appliedOptions;
bool _configValid;
FluxSourceProto _verificationFluxSourceProto;

View File

@@ -73,5 +73,6 @@ message OptionProto
message OptionGroupProto
{
optional string comment = 1 [(help) = "help text for option group"];
repeated OptionProto option = 2;
optional string name = 2 [(help) = "option group name"];
repeated OptionProto option = 3;
}

View File

@@ -13,17 +13,23 @@ static std::vector<Flag*> all_flags;
static std::map<const std::string, Flag*> flags_by_name;
static void doHelp();
static void doLoadConfig(const std::string& filename);
static void doShowConfig();
static void doDoc();
static FlagGroup helpGroup;
static ActionFlag helpFlag = ActionFlag({"--help"}, "Shows the help.", doHelp);
static ActionFlag showConfigFlag = ActionFlag({"--config", "-C"},
static FlagGroup configGroup;
static ActionFlag loadConfigFlag({"--config", "-c"},
"Reads an internal or external configuration file.",
doLoadConfig);
static ActionFlag showConfigFlag({"--show-config", "-C"},
"Shows the currently set configuration and halts.",
doShowConfig);
static ActionFlag docFlag = ActionFlag(
static ActionFlag docFlag(
{"--doc"}, "Shows the available configuration options and halts.", doDoc);
FlagGroup::FlagGroup()
@@ -152,7 +158,7 @@ std::vector<std::string> FlagGroup::parseFlagsWithFilenames(int argc,
index += usesthat;
}
else
globalConfig().applyOption(path);
usesthat = globalConfig().applyOption(path, value);
}
else
error("unrecognised flag '-{}'; try --help", key);
@@ -182,17 +188,17 @@ void FlagGroup::parseFlags(int argc,
"non-option parameter '{}' seen (try --help)", *filenames.begin());
}
static void doLoadConfig(const std::string& filename)
{
globalConfig().readBaseConfigFile(filename);
}
void FlagGroup::parseFlagsWithConfigFiles(int argc,
const char* argv[],
const std::map<std::string, const ConfigProto*>& configFiles)
{
parseFlags(argc,
argv,
[&](const auto& filename)
{
globalConfig().readBaseConfigFile(filename);
return true;
});
globalConfig().readBaseConfigFile("_global_options");
FlagGroup({this, &configGroup}).parseFlags(argc, argv);
}
void FlagGroup::checkInitialised() const

View File

@@ -83,13 +83,23 @@ public:
const std::string helptext,
std::function<void(void)> callback):
Flag(names, helptext),
_callback(callback)
_voidCallback(callback),
_hasArgument(false)
{
}
ActionFlag(const std::vector<std::string>& names,
const std::string helptext,
std::function<void(const std::string&)> callback):
Flag(names, helptext),
_callback(callback),
_hasArgument(true)
{
}
bool hasArgument() const override
{
return false;
return _hasArgument;
}
const std::string defaultValueAsString() const override
@@ -99,11 +109,16 @@ public:
void set(const std::string& value) override
{
_callback();
if (_hasArgument)
_callback(value);
else
_voidCallback();
}
private:
const std::function<void(void)> _callback;
const std::function<void(const std::string&)> _callback;
const std::function<void(void)> _voidCallback;
bool _hasArgument;
};
class SettableFlag : public Flag

View File

@@ -14,10 +14,10 @@ destfile=$dir/dest.img
dd if=/dev/urandom of=$srcfile bs=1048576 count=2 2>&1
echo $fluxengine write $format -i $srcfile -d $fluxfile --drive.rotational_period_ms=200 $flags
$fluxengine write $format -i $srcfile -d $fluxfile --drive.rotational_period_ms=200 $flags
echo $fluxengine read $format -s $fluxfile -o $destfile --drive.rotational_period_ms=200 $flags
$fluxengine read $format -s $fluxfile -o $destfile --drive.rotational_period_ms=200 $flags
echo $fluxengine write -c $format -i $srcfile -d $fluxfile --drive.rotational_period_ms=200 $flags
$fluxengine write -c $format -i $srcfile -d $fluxfile --drive.rotational_period_ms=200 $flags
echo $fluxengine read -c $format -s $fluxfile -o $destfile --drive.rotational_period_ms=200 $flags
$fluxengine read -c $format -s $fluxfile -o $destfile --drive.rotational_period_ms=200 $flags
if [ ! -s $destfile ]; then
echo "Zero length output file!" >&2
exit 1

View File

@@ -28,7 +28,7 @@ static void addExample(std::vector<std::string>& examples,
else
return;
r += fmt::format(" {}", name);
r += fmt::format(" -c {}", name);
if (format)
r += fmt::format(" --{}", format->name());

View File

@@ -43,8 +43,9 @@ int main(int argc, const char* argv[])
{
const auto* descriptor =
FilesystemProto::FilesystemType_descriptor();
std::string name =
descriptor->FindValueByNumber(fs.type())->name();
auto name =
(std::string)descriptor->FindValueByNumber(fs.type())
->name();
filesystems.insert(name);
}

View File

@@ -22,9 +22,7 @@ static StringFlag destFlux({"--dest", "-d"},
globalConfig().setFluxSink(value);
});
static IntFlag destTrack({"--cylinder", "-c"}, "track to write to", 0);
static IntFlag destHead({"--head", "-h"}, "head to write to", 0);
static StringFlag destTracks({"--tracks", "-t"}, "tracks to write to", "c0h0");
static DoubleFlag minInterval(
{"--min-interval-us"}, "Minimum pulse interval", 2.0);
@@ -251,11 +249,14 @@ int mainAnalyseDriveResponse(int argc, const char* argv[])
if (globalConfig()->flux_sink().type() != FLUXTYPE_DRIVE)
error("this only makes sense with a real disk drive");
auto tracks = parseCylinderHeadsString(destTracks);
if (tracks.size() != 1)
error("you must specify exactly one track");
usbSetDrive(globalConfig()->drive().drive(),
globalConfig()->drive().high_density(),
globalConfig()->drive().index_mode());
usbSeek(destTrack);
usbSeek(tracks[0].cylinder);
std::cout << "Measuring rotational speed...\n";
nanoseconds_t period = usbGetRotationalPeriod(0);
@@ -291,12 +292,12 @@ int mainAnalyseDriveResponse(int argc, const char* argv[])
outFluxmap.appendPulse();
}
usbWrite(destHead, outFluxmap.rawBytes(), 0);
usbWrite(tracks[0].head, outFluxmap.rawBytes(), 0);
/* Read the test pattern in again. */
Fluxmap inFluxmap;
inFluxmap.appendBytes(usbRead(destHead, true, period, 0));
inFluxmap.appendBytes(usbRead(tracks[0].head, true, period, 0));
/* Compute histogram. */

View File

@@ -21,9 +21,7 @@ static StringFlag sourceFlux({"--source", "-s"},
globalConfig().setFluxSource(value);
});
static IntFlag trackFlag({"--cylinder", "-c"}, "Track to read.", 0);
static IntFlag headFlag({"--head", "-h"}, "Head to read.", 0);
static StringFlag destTracks({"--tracks", "-t"}, "tracks to write to", "c0h0");
static SettableFlag dumpFluxFlag(
{"--dump-flux", "-F"}, "Dump raw magnetic disk flux.");
@@ -135,7 +133,10 @@ int mainInspect(int argc, const char* argv[])
flags.parseFlagsWithConfigFiles(argc, argv, {});
auto fluxSource = FluxSource::create(globalConfig());
const auto fluxmap = fluxSource->readFlux(trackFlag, headFlag)->next();
auto tracks = parseCylinderHeadsString(destTracks);
if (tracks.size() != 1)
error("you must specify exactly one track");
const auto fluxmap = fluxSource->readFlux(tracks[0])->next();
std::cout << fmt::format("0x{:x} bytes of data in {:.3f}ms\n",
fluxmap->bytes(),

View File

@@ -16,7 +16,7 @@ static StringFlag sourceFlux({"-s", "--source"},
globalConfig().setFluxSource(value);
});
static IntFlag track({"--cylinder", "-c"}, "track to seek to", 0);
static IntFlag track({"--cylinder", "-t"}, "track to seek to", 0);
extern const std::map<std::string, std::string> readables;

View File

@@ -1,22 +0,0 @@
comment: 'Adjust configuration for a 40-track drive'
is_extension: true
documentation:
<<<
This is an extension profile; adding this to the command line will configure
FluxEngine to read from 40-track, 48tpi 5.25" drives. You have to tell it because there is
no way to detect this automatically.
For example:
```
fluxengine read ibm --180 40track_drive
```
>>>
drive {
tracks: "c0-40h0-1"
drive_type: DRIVETYPE_40TRACK
}

View File

@@ -0,0 +1,77 @@
comment: 'Options which can be applied everywhere.'
is_extension: true
option_group {
comment: "Drive type"
name: "drivetype"
option {
name: "80"
comment: '80 track drive'
set_by_default: true
config {
}
}
option {
name: "40"
comment: '40 track drive'
config {
drive {
tracks: "c0-40h0-1"
drive_type: DRIVETYPE_40TRACK
}
}
}
option {
name: "160"
comment: '160 track Apple II drive'
config {
drive {
tracks: "c0-159h0"
drive_type: DRIVETYPE_APPLE2
}
}
}
}
option_group {
comment: 'Bus interface'
name: "bus"
option {
name: "pc"
comment: 'PC drive interface'
set_by_default: true
}
option {
name: "shugart"
comment: 'Shugart bus interface (only on Greaseweazle)'
config {
usb {
greaseweazle {
bus_type: SHUGART
}
}
}
}
option {
name: "appleii"
comment: 'Apple II bus interface (only on Greaseweazle)'
config {
usb {
greaseweazle {
bus_type: APPLE2
}
}
}
}
}

View File

@@ -1,29 +0,0 @@
comment: 'Adjust configuration for a 40-track Apple II drive'
is_extension: true
documentation:
<<<
This is an extension profile; adding this to the command line will configure
FluxEngine to adjust the pinout and track spacing to work with an Apple II
drive. This only works on Greaseweazle hardware and requires a custom
connector.
For example:
```
fluxengine read apple2 --160 apple2_drive
```
>>>
usb {
greaseweazle {
bus_type: APPLE2
}
}
drive {
tracks: "c0-159h0"
drive_type: DRIVETYPE_APPLE2
}

View File

@@ -3,14 +3,13 @@ from build.c import cxxlibrary
from scripts.build import protoencode
formats = [
"40track_drive",
"_global_options",
"acornadfs",
"acorndfs",
"aeslanier",
"agat",
"amiga",
"ampro",
"apple2_drive",
"apple2",
"atarist",
"bk",
@@ -33,7 +32,6 @@ formats = [
"psos",
"rolandd20",
"rx50",
"shugart_drive",
"smaky6",
"tartu",
"ti99",

View File

@@ -1,22 +0,0 @@
comment: 'Adjust configuration for a Shugart drive'
is_extension: true
documentation:
<<<
This is an extension profile; adding this to the command line will configure
FluxEngine to adjust the pinout to work with a Shugart drive. This only works
on Greaseweazle hardware.
For example:
```
fluxengine read ibm --720 shugart_drive
```
>>>
usb {
greaseweazle {
bus_type: SHUGART
}
}

View File

@@ -55,14 +55,14 @@ static void test_option_validity()
}
)M");
AssertThat(
globalConfig().isOptionValid(globalConfig().findOption("option1")),
AssertThat(globalConfig().isOptionValid(
*globalConfig().findOption("option1").option),
Equals(true));
AssertThat(
globalConfig().isOptionValid(globalConfig().findOption("option2")),
AssertThat(globalConfig().isOptionValid(
*globalConfig().findOption("option2").option),
Equals(false));
AssertThat(
globalConfig().isOptionValid(globalConfig().findOption("option3")),
AssertThat(globalConfig().isOptionValid(
*globalConfig().findOption("option3").option),
Equals(true));
}