Compare commits

...

23 Commits

Author SHA1 Message Date
David Given
8863bda0d0 Make various apple2 parameters configurable. Change the way sync bytes are
written to more match the way real hardware does it.
2024-02-02 22:52:44 +01:00
David Given
df83b558bf Merge pull request #742 from davidgiven/devices
Don't print the detection banner if no devices were detected.
2024-01-30 22:59:18 +01:00
David Given
7c2b5f116d Don't print the detection banner if no devices were detected. 2024-01-30 22:58:40 +01:00
David Given
30fe75f9bf Merge pull request #741 from davidgiven/devices
Add a command to list detectable devices on the command line.
2024-01-30 22:57:01 +01:00
David Given
401e7a9edb The rpm command now defaults to use real hardware, like it should. 2024-01-30 22:36:16 +01:00
David Given
fd4ddc56f2 Add a command to list detectable devices on the command line. 2024-01-30 21:44:11 +01:00
David Given
83d907bf71 Do parallel builds on OSX. 2024-01-30 21:28:03 +01:00
David Given
327bc76c6e Another try at making OSX builds work. 2024-01-22 22:31:51 +01:00
David Given
fdd39fb2d8 Try to fix OSX builds. 2024-01-22 22:16:49 +01:00
David Given
bfcfa8eb19 Merge pull request #738 from davidgiven/overrides
Fix a whole pile of missing 'override' keywords.
2024-01-22 21:08:27 +01:00
David Given
7095c03e28 Fix a whole pile of missing 'override' keywords. 2024-01-22 20:55:38 +01:00
David Given
45e796f15f Merge pull request #736 from davidgiven/ab
Remove stray files.
2024-01-07 23:20:02 +01:00
David Given
3d1dcd6874 imagemagick is just too much trouble for creating icons, so use png2ico instead. 2024-01-08 00:05:18 +01:00
David Given
0033d0759f 32-bit imagemagick has gone. 2024-01-07 21:29:06 +01:00
David Given
53f7dfe6c9 Remove stray files. 2024-01-07 21:24:53 +01:00
David Given
75446de29b Merge pull request #732 from davidgiven/acorn
Update the acorndfs format so that writes actually work.
2023-12-12 23:45:47 +00:00
David Given
1d119d6921 Update the acorndfs format so that writes actually work. 2023-12-13 00:31:12 +01:00
David Given
7462bd995f Merge pull request #731 from davidgiven/ab
Update ab. You can now build individual tools individually.
2023-12-12 22:31:48 +00:00
David Given
0dd99efad3 Update ab. 2023-12-12 23:17:06 +01:00
David Given
1234e81463 Update ab. You can now build individual tools individually. 2023-12-12 23:11:09 +01:00
David Given
ea13d66e6b Merge pull request #725 from davidgiven/dmk
Add support for DMK directory streams.
2023-11-02 01:35:24 +01:00
David Given
a7cb7eb995 Add missing files... 2023-11-02 01:22:09 +01:00
David Given
29f5feb34d Add support for DMK directory streams. 2023-11-02 01:17:44 +01:00
66 changed files with 380 additions and 618 deletions

View File

@@ -29,6 +29,7 @@ IncludeBlocks: Preserve
IndentCaseLabels: 'true'
IndentWidth: '4'
IndentWrappedFunctionNames: 'false'
IndentPPDirectives: BeforeHash
KeepEmptyLinesAtTheStartOfBlocks: 'true'
NamespaceIndentation: All
PointerAlignment: Left

View File

@@ -70,7 +70,7 @@ jobs:
mingw-w64-i686-sqlite3
mingw-w64-i686-wxWidgets
mingw-w64-i686-zlib
mingw-w64-i686-imagemagick
mingw-w64-i686-png2ico
vim
zip
- name: update-protobuf

View File

@@ -34,7 +34,7 @@ jobs:
mingw-w64-i686-sqlite3
mingw-w64-i686-wxWidgets
mingw-w64-i686-zlib
mingw-w64-i686-imagemagick
mingw-w64-i686-png2ico
vim
zip
- uses: actions/checkout@v3
@@ -94,10 +94,12 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: brew
run: brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg
- name: make
run: gmake
run: gmake -j`nproc`
- name: tag
uses: EndBug/latest-tag@latest

View File

@@ -19,4 +19,13 @@ message Apple2EncoderProto
optional uint32 side_one_track_offset = 3
[ default = 0, (help) = "offset to apply to track numbers on side 1" ];
optional uint32 post_index_gap_bytes = 4
[ default = 32, (help) = "the number of resync bytes to write after the index mark" ];
optional uint32 post_address_gap_bytes = 5
[ default = 6, (help) = "the number of resync bytes to write after the address gap" ];
optional uint32 post_data_gap_bytes = 6
[ default = 8, (help) = "the number of resync bytes to write after each sector" ];
}

View File

@@ -79,18 +79,14 @@ private:
auto write_bit = [&](bool val)
{
if (cursor <= bits.size())
{
bits[cursor] = val;
}
cursor++;
};
auto write_bits = [&](uint32_t bits, int width)
{
for (int i = width; i--;)
{
write_bit(bits & (1u << i));
}
};
auto write_gcr44 = [&](uint8_t value)
@@ -104,15 +100,13 @@ private:
};
// The special "FF40" sequence is used to synchronize the receiving
// shift register. It's written as "1111 1111 00"; FF indicates the
// 8 consecutive 1-bits, while "40" indicates the total number of
// shift register. It's written as "0 1111 1111 0"; FF indicates the
// 8 consecutive 1-bits, while "40" indicaes the total number of
// microseconds.
auto write_ff40 = [&](int n = 1)
{
for (; n--;)
{
write_bits(0xff << 2, 10);
}
write_bits(0xff << 1, 10);
};
// There is data to encode to disk.
@@ -127,7 +121,9 @@ private:
//
// In standard formatting, the first logical sector apparently gets
// extra padding.
write_ff40(sector.logicalSector == 0 ? 32 : 8);
write_ff40(sector.logicalSector == 0
? _config.post_index_gap_bytes()
: _config.post_data_gap_bytes());
int track = sector.logicalTrack;
if (sector.logicalSide == 1)
@@ -144,7 +140,7 @@ private:
// Write data syncing leader: FF40 + APPLE2_DATA_RECORD + sector
// data + sum + DE AA EB (+ mystery bits cut off of the scan?)
write_ff40(8);
write_ff40(_config.post_address_gap_bytes());
write_bits(APPLE2_DATA_RECORD, 24);
// Convert the sector data to GCR, append the checksum, and write it

194
build.lua
View File

@@ -1,194 +0,0 @@
vars.cflags = { "$(CFLAGS)" }
vars.cxxflags = { "$(CXXFLAGS)" }
vars.ldflags = { "-pthread" }
include "build/protobuf.lua"
include "build/dependency.lua"
include "build/tests.lua"
dependency {
name = "fmt_dep",
pkg_config = "fmt",
}
dependency {
name = "stb_dep",
pkg_config = "stb",
fallback = "dep/stb+stb"
}
dependency {
name = "protobuf_dep",
pkg_config = "protobuf"
}
dependency {
name = "zlib_dep",
pkg_config = "zlib"
}
proto_cc_library {
name = "config_lib",
srcs = {
"./lib/common.proto",
"./lib/config.proto",
"./lib/decoders/decoders.proto",
"./lib/drive.proto",
"./lib/encoders/encoders.proto",
"./lib/fl2.proto",
"./lib/fluxsink/fluxsink.proto",
"./lib/fluxsource/fluxsource.proto",
"./lib/imagereader/imagereader.proto",
"./lib/imagewriter/imagewriter.proto",
"./lib/mapper.proto",
"./lib/usb/usb.proto",
"./arch/aeslanier/aeslanier.proto",
"./arch/agat/agat.proto",
"./arch/amiga/amiga.proto",
"./arch/apple2/apple2.proto",
"./arch/brother/brother.proto",
"./arch/c64/c64.proto",
"./arch/f85/f85.proto",
"./arch/fb100/fb100.proto",
"./arch/ibm/ibm.proto",
"./arch/macintosh/macintosh.proto",
"./arch/micropolis/micropolis.proto",
"./arch/mx/mx.proto",
"./arch/northstar/northstar.proto",
"./arch/rolandd20/rolandd20.proto",
"./arch/tids990/tids990.proto",
"./arch/victor9k/victor9k.proto",
"./arch/zilogmcz/zilogmcz.proto",
}
}
clibrary {
name = "protocol_lib",
hdrs = { "./protocol.h" }
}
clibrary {
name = "libfluxengine",
srcs = {
"./arch/aeslanier/decoder.cc",
"./arch/agat/agat.cc",
"./arch/agat/decoder.cc",
"./arch/amiga/amiga.cc",
"./arch/amiga/decoder.cc",
"./arch/amiga/encoder.cc",
"./arch/apple2/decoder.cc",
"./arch/apple2/encoder.cc",
"./arch/brother/decoder.cc",
"./arch/brother/encoder.cc",
"./arch/c64/c64.cc",
"./arch/c64/decoder.cc",
"./arch/c64/encoder.cc",
"./arch/f85/decoder.cc",
"./arch/fb100/decoder.cc",
"./arch/ibm/decoder.cc",
"./arch/ibm/encoder.cc",
"./arch/macintosh/decoder.cc",
"./arch/macintosh/encoder.cc",
"./arch/micropolis/decoder.cc",
"./arch/micropolis/encoder.cc",
"./arch/mx/decoder.cc",
"./arch/northstar/decoder.cc",
"./arch/northstar/encoder.cc",
"./arch/rolandd20/rolandd20.cc",
"./arch/tids990/decoder.cc",
"./arch/tids990/encoder.cc",
"./arch/victor9k/decoder.cc",
"./arch/victor9k/encoder.cc",
"./arch/zilogmcz/decoder.cc",
"./lib/bitmap.cc",
"./lib/bytes.cc",
"./lib/crc.cc",
"./lib/csvreader.cc",
"./lib/decoders/decoders.cc",
"./lib/decoders/fluxdecoder.cc",
"./lib/decoders/fluxmapreader.cc",
"./lib/decoders/fmmfm.cc",
"./lib/encoders/encoders.cc",
"./lib/flags.cc",
"./lib/fluxmap.cc",
"./lib/fluxsink/aufluxsink.cc",
"./lib/fluxsink/fl2fluxsink.cc",
"./lib/fluxsink/fluxsink.cc",
"./lib/fluxsink/hardwarefluxsink.cc",
"./lib/fluxsink/scpfluxsink.cc",
"./lib/fluxsink/vcdfluxsink.cc",
"./lib/fluxsource/cwffluxsource.cc",
"./lib/fluxsource/erasefluxsource.cc",
"./lib/fluxsource/fl2fluxsource.cc",
"./lib/fluxsource/fluxsource.cc",
"./lib/fluxsource/hardwarefluxsource.cc",
"./lib/fluxsource/kryoflux.cc",
"./lib/fluxsource/kryofluxfluxsource.cc",
"./lib/fluxsource/scpfluxsource.cc",
"./lib/fluxsource/testpatternfluxsource.cc",
"./lib/globals.cc",
"./lib/hexdump.cc",
"./lib/image.cc",
"./lib/imagereader/d64imagereader.cc",
"./lib/imagereader/d88imagereader.cc",
"./lib/imagereader/dimimagereader.cc",
"./lib/imagereader/diskcopyimagereader.cc",
"./lib/imagereader/fdiimagereader.cc",
"./lib/imagereader/imagereader.cc",
"./lib/imagereader/imdimagereader.cc",
"./lib/imagereader/imgimagereader.cc",
"./lib/imagereader/jv3imagereader.cc",
"./lib/imagereader/nfdimagereader.cc",
"./lib/imagereader/nsiimagereader.cc",
"./lib/imagereader/td0imagereader.cc",
"./lib/imagewriter/d64imagewriter.cc",
"./lib/imagewriter/d88imagewriter.cc",
"./lib/imagewriter/diskcopyimagewriter.cc",
"./lib/imagewriter/imagewriter.cc",
"./lib/imagewriter/imgimagewriter.cc",
"./lib/imagewriter/ldbsimagewriter.cc",
"./lib/imagewriter/nsiimagewriter.cc",
"./lib/imagewriter/rawimagewriter.cc",
"./lib/imginputoutpututils.cc",
"./lib/ldbs.cc",
"./lib/logger.cc",
"./lib/mapper.cc",
"./lib/proto.cc",
"./lib/readerwriter.cc",
"./lib/sector.cc",
"./lib/usb/fluxengineusb.cc",
"./lib/usb/greaseweazle.cc",
"./lib/usb/greaseweazleusb.cc",
"./lib/usb/serial.cc",
"./lib/usb/usb.cc",
"./lib/usb/usbfinder.cc",
"./lib/utils.cc",
"protocol.h",
},
deps = {
"+config_lib",
"+protocol_lib",
"+fmt_dep",
"+protobuf_dep",
"+zlib_dep",
"dep/libusbp+libusbp",
},
dep_cflags = { "-Ilib", "-Iarch", "-I." },
vars = {
["+cflags"] = { "-Ilib", "-Iarch", "-I." }
}
}
installable {
name = "all",
map = {
["fluxengine"] = "src+fluxengine",
["fluxengine-gui"] = "src/gui+fluxengine",
["brother120tool"] = "tools+brother120tool",
["brother240tool"] = "tools+brother240tool",
["upgrade-flux-file"] = "tools+upgrade-flux-file",
}
}
include "tests/build.lua"

View File

@@ -41,7 +41,9 @@ cxxlibrary(
"./lib/fluxsink/scpfluxsink.cc",
"./lib/fluxsink/vcdfluxsink.cc",
"./lib/fluxsource/a2rfluxsource.cc",
"./lib/fluxsource/catweasel.cc",
"./lib/fluxsource/cwffluxsource.cc",
"./lib/fluxsource/dmkfluxsource.cc",
"./lib/fluxsource/erasefluxsource.cc",
"./lib/fluxsource/fl2fluxsource.cc",
"./lib/fluxsource/fluxsource.cc",
@@ -185,6 +187,7 @@ cxxlibrary(
"lib/flux.h": "./lib/flux.h",
"lib/fluxmap.h": "./lib/fluxmap.h",
"lib/fluxsink/fluxsink.h": "./lib/fluxsink/fluxsink.h",
"lib/fluxsource/catweasel.h": "lib/fluxsource/catweasel.h",
"lib/fluxsource/fluxsource.h": "lib/fluxsource/fluxsource.h",
"lib/fluxsource/flx.h": "lib/fluxsource/flx.h",
"lib/fluxsource/kryoflux.h": "lib/fluxsource/kryoflux.h",
@@ -224,6 +227,7 @@ if not glob("../fluxengine-testdata/data"):
print("fluxengine-testdata not found; skipping corpus tests")
else:
corpus = [
("acorndfs", "", "--200"),
("agat", "", ""),
("amiga", "", ""),
("apple2", "", "--140 40track_drive"),

View File

@@ -417,8 +417,6 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []):
for dest, src in items.items():
destf = filenameof(dest)
dir = dirname(destf)
if dir:
cs += ["mkdir -p " + dir]
srcs = filenamesof(src)
if len(srcs) != 1:
@@ -426,13 +424,16 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []):
"a dependency of an export must have exactly one output file"
)
cs += ["cp %s %s" % (srcs[0], destf)]
emitter_rule(self.name + "+" + destf, srcs, [destf])
emitter_label(f"CP {destf}")
if dir:
emitter_exec(["mkdir -p " + dir])
emitter_exec(["cp %s %s" % (srcs[0], destf)])
self.outs += [destf]
emitter_rule(self.name, items.values(), self.outs, deps)
emitter_label(f"EXPORT {self.name}")
emitter_exec(cs)
emitter_rule(self.name, self.outs, [], deps)
emit("\t@")
if self.outs:
emit("clean::")

View File

@@ -1,251 +0,0 @@
local OBJDIR = "$(OBJDIR)"
local function objdir(e)
return concatpath(OBJDIR, e.cwd, e.name)
end
definerule("normalrule",
{
ins = { type="targets" },
deps = { type="targets", default={} },
outs = { type="targets", default={} },
outleaves = { type="strings" },
label = { type="string", optional=true },
objdir = { type="string", optional=true },
commands = { type="strings" },
},
function (e)
local dir = e.objdir or objdir(e)
local realouts = {}
for _, v in pairs(e.outleaves) do
realouts[#realouts+1] = concatpath(dir, v)
end
local vars = inherit(e.vars, {
dir = dir
})
local result = simplerule {
name = e.name,
ins = e.ins,
deps = e.deps,
outs = concat(realouts, filenamesof(e.outs)),
label = e.label,
commands = e.commands,
vars = vars,
}
result.dir = dir
return result
end
)
local function is_clike(f)
return f:find("%.c$") or f:find("%.cc$") or f:find("%.cpp$")
end
definerule("cfile",
{
srcs = { type="targets" },
deps = { type="targets", default={} }
},
function (e)
local cflags = e.vars.cflags
local cxxflags = e.vars.cxxflags
for _, target in ipairs(targetsof(e.deps)) do
if target.is.clibrary then
cflags = concat(cflags, target.dep_cflags)
cxxflags = concat(cxxflags, target.dep_cxxflags)
end
end
local src = filter(filenamesof(e.srcs), is_clike)
local cmd
local cxx = false
if src[1]:find("%.c$") then
cmd = "$(CC) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags}"
else
cmd = "$(CXX) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags} %{cxxflags}"
cxx = true
end
local outleaf = basename(e.name)..".o"
local rule = normalrule {
name = e.name,
cwd = e.cwd,
ins = e.srcs,
deps = e.deps,
outleaves = {outleaf},
label = e.label,
commands = cmd,
vars = {
hdrpaths = {},
cflags = cflags,
cxxflags = cxxflags,
}
}
rule.is.cxxfile = cxx
return rule
end
)
local function do_cfiles(e)
local outs = {}
local srcs = filenamesof(e.srcs)
for _, f in ipairs(sorted(filter(srcs, is_clike))) do
local ofile
if f:find(OBJDIR, 1, true) == 1 then
ofile = e.name.."/"..f:sub(#OBJDIR+1)..".o"
else
ofile = e.name.."/"..f..".o"
end
outs[#outs+1] = cfile {
name = ofile,
srcs = { f },
deps = e.deps
}
end
return outs
end
definerule("clibrary",
{
srcs = { type="targets", default={} },
deps = { type="targets", default={} },
hdrs = { type="targets", default={} },
dep_cflags = { type="strings", default={} },
dep_cxxflags = { type="strings", default={} },
dep_ldflags = { type="strings", default={} },
dep_libs = { type="strings", default={} },
},
function (e)
local ins = do_cfiles(e)
local cxx = false
for _, f in ipairs(ins) do
if f.is.cxxfile then
cxx = true
break
end
end
local mkdirs = {}
local copies = {}
local outs = {}
local function copy_file(src, dest)
mkdirs[#mkdirs+1] = "mkdir -p %{dir}/"..dirname(dest)
copies[#copies+1] = "cp "..src.." %{dir}/"..dest
outs[#outs+1] = objdir(e).."/"..dest
end
local deps = {}
for k, v in pairs(e.hdrs) do
deps[#deps+1] = v
if type(k) == "number" then
v = filenamesof(v)
for _, v in ipairs(v) do
if not startswith(e.cwd, v) then
error(string.format("filename '%s' is not local to '%s' --- "..
"you'll have to specify the output filename manually", v, e.cwd))
end
copy_file(v, v:gsub("^"..e.cwd, ""))
end
else
v = filenamesof(v)
if #v ~= 1 then
error("each mapped hdrs item can only cope with a single file")
end
copy_file(v[1], k)
end
end
ins = sorted(filenamesof(ins))
local has_ar = (#ins ~= 0)
local lib = normalrule {
name = e.name,
cwd = e.cwd,
ins = sorted(filenamesof(ins)),
deps = deps,
outs = outs,
outleaves = { e.name..".a" },
label = e.label,
commands = {
sorted(mkdirs),
sorted(copies),
has_ar and "rm -f %{outs[1]} && $(AR) cqs %{outs[1]} %{ins}" or {},
}
}
lib.dep_cflags = concat(e.dep_cflags, "-I"..lib.dir)
lib.dep_cxxflags = e.dep_cxxflags
lib.dep_ldflags = e.dep_ldflags
lib.dep_libs = concat(e.dep_libs, has_ar and matching(filenamesof(lib), "%.a$") or {})
lib.dep_cxx = cxx
for _, d in pairs(targetsof(e.deps)) do
lib.dep_cflags = concat(lib.dep_cflags, d.dep_cflags)
lib.dep_cxxflags = concat(lib.dep_cxxflags, d.dep_cxxflags)
lib.dep_ldflags = concat(lib.dep_ldflags, d.dep_ldflags)
lib.dep_libs = concat(lib.dep_libs, d.dep_libs)
lib.dep_cxx = lib.dep_cxx or d.dep_cxx
end
return lib
end
)
definerule("cprogram",
{
srcs = { type="targets", default={} },
deps = { type="targets", default={} },
},
function (e)
local deps = e.deps
local ins = {}
local cxx = false
if (#e.srcs > 0) then
local objs = do_cfiles(e)
for _, obj in pairs(objs) do
if obj.is.cxxfile then
cxx = true
end
ins[#ins+1] = obj
end
end
local libs = {}
local cflags = {}
local cxxflags = {}
local ldflags = {}
for _, lib in pairs(e.deps) do
cflags = concat(cflags, lib.dep_cflags)
cxxflags = concat(cxxflags, lib.dep_cxxflags)
ldflags = concat(ldflags, lib.dep_ldflags)
libs = concat(libs, lib.dep_libs)
cxx = cxx or lib.dep_cxx
end
local command
if cxx then
command = "$(CXX) $(LDFLAGS) %{ldflags} -o %{outs[1]} %{ins} %{libs} %{libs}"
else
command = "$(CC) $(LDFLAGS) %{ldflags} -o %{outs[1]} %{ins} %{libs} %{libs}"
end
return normalrule {
name = e.name,
cwd = e.cwd,
deps = deps,
ins = ins,
outleaves = { e.name },
commands = { command },
vars = {
cflags = cflags,
cxxflags = cxxflags,
ldflags = ldflags,
libs = libs,
}
}
end
)

View File

@@ -6,7 +6,7 @@ import subprocess
emit(
"""
PKG_CONFIG ?= pkg-config
PACKAGES := $(shell $(PKG_CONFIG) --list-all | cut -d' ' -f1)
PACKAGES := $(shell $(PKG_CONFIG) --list-all | cut -d' ' -f1 | sort)
"""
)

View File

@@ -1,18 +0,0 @@
definerule("test",
{
srcs = { type="targets", default={} },
},
function (e)
if vars.TESTS == "yes" then
normalrule {
name = e.name,
ins = e.srcs,
outleaves = { "log.txt" },
commands = {
"%{ins} > %{outs}",
}
}
end
end
)

View File

@@ -234,7 +234,7 @@ namespace libusbp
}
/*! Wrapper for libusbp_error_get_message(). */
virtual const char * what() const noexcept
virtual const char * what() const noexcept override
{
return libusbp_error_get_message(pointer);
}

View File

@@ -58,7 +58,14 @@ If _more_ than one device is plugged in, you need to specify which one to use
with the `--usb.serial` parameter, which takes the device serial number as a
parameter. You can find out the serial numbers by running the command without
the `--usb.serial` parameter, and if more than one device is attached they will
be listed. The serial number is also shown whenever a connection is made.
be listed. The serial number is also shown whenever a connection is made. You
can list all the detectable devices with:
```
$ fluxengine test devices
```
This will show you their serial numbers.
You _can_ work with more than one FluxEngine at the same time, using different
invocations of the client; but be careful of USB bandwidth. If the devices are
@@ -221,6 +228,10 @@ FluxEngine supports a number of ways to get or put flux. When using the `-s` or
Read from a Catweasel flux file. **Read only.**
- `dmk:<directory>`
Read from a Catweasel CMK directory. **Read only.**
- `<filename.a2r>`
Write to a AppleSauce flux file. **Write only.**

View File

@@ -38,7 +38,7 @@ normalrule(
ins=["./icon.png"],
outs=["fluxengine.ico"],
commands=[
"convert {ins[0]} -resize 64x46 -define icon:auto-resize=64,48,32,16 {outs[0]}"
"png2ico {outs[0]} {ins[0]}"
],
label="MAKEICON",
)

View File

@@ -71,6 +71,15 @@ Bytes::Bytes(
{
}
Bytes::Bytes(std::istream& istream, size_t len):
_data(createVector(0)),
_low(0),
_high(0)
{
ByteWriter bw(*this);
bw.append(istream, len);
}
Bytes* Bytes::operator=(const Bytes& other)
{
_data = other._data;
@@ -352,13 +361,24 @@ uint64_t ByteReader::read_be64()
return ((uint64_t)read_be32() << 32) | read_be32();
}
ByteWriter& ByteWriter::operator+=(std::istream& stream)
ByteWriter& ByteWriter::append(std::istream& stream, size_t length)
{
Bytes buffer(4096);
while (stream.read((char*)buffer.begin(), buffer.size()))
this->append(buffer);
this->append(buffer.slice(0, stream.gcount()));
while (length != 0)
{
size_t chunk = std::min((size_t)buffer.size(), length);
if (!stream.read((char*)buffer.begin(), chunk))
{
this->append(buffer.slice(0, stream.gcount()));
break;
}
else
this->append(buffer);
length -= chunk;
}
return *this;
}

View File

@@ -19,6 +19,7 @@ public:
Bytes(std::shared_ptr<std::vector<uint8_t>> data,
unsigned start,
unsigned end);
Bytes(std::istream& istream, size_t len = SIZE_MAX);
Bytes* operator=(const Bytes& other);
@@ -323,7 +324,10 @@ public:
return *this;
}
ByteWriter& operator+=(std::istream& stream);
ByteWriter& operator+=(std::istream& stream)
{
return this->append(stream);
}
ByteWriter& append(const char* data)
{
@@ -340,10 +344,7 @@ public:
return *this += data;
}
ByteWriter& append(std::istream& stream)
{
return *this += stream;
}
ByteWriter& append(std::istream& stream, size_t length = SIZE_MAX);
ByteWriter& pad(unsigned count, uint8_t byte = 0);

View File

@@ -32,6 +32,7 @@ enum FluxSourceSinkType {
FLUXTYPE_SCP = 9;
FLUXTYPE_TEST_PATTERN = 10;
FLUXTYPE_VCD = 11;
FLUXTYPE_DMK = 12;
}
enum ImageReaderWriterType {

View File

@@ -78,6 +78,14 @@ static const std::vector<FluxConstructor> fluxConstructors = {
proto->set_type(FLUXTYPE_CWF);
proto->mutable_cwf()->set_filename(s);
}},
{.name = "CatWeazle DMK directory",
.pattern = std::regex("^dmk:(.*)$"),
.source =
[](auto& s, auto* proto)
{
proto->set_type(FLUXTYPE_DMK);
proto->mutable_dmk()->set_directory(s);
}},
{.pattern = std::regex("^erase:$"),
.source =
[](auto& s, auto* proto)

View File

@@ -87,15 +87,17 @@ public:
{
}
bool hasArgument() const
bool hasArgument() const override
{
return false;
}
const std::string defaultValueAsString() const
const std::string defaultValueAsString() const override
{
return "";
}
void set(const std::string& value)
void set(const std::string& value) override
{
_callback();
}
@@ -119,15 +121,17 @@ public:
return _value;
}
bool hasArgument() const
bool hasArgument() const override
{
return false;
}
const std::string defaultValueAsString() const
const std::string defaultValueAsString() const override
{
return "false";
}
void set(const std::string& value)
void set(const std::string& value) override
{
_value = true;
}
@@ -176,7 +180,7 @@ public:
_value = _defaultValue = value;
}
bool hasArgument() const
bool hasArgument() const override
{
return true;
}
@@ -203,11 +207,12 @@ public:
{
}
const std::string defaultValueAsString() const
const std::string defaultValueAsString() const override
{
return _defaultValue;
}
void set(const std::string& value)
void set(const std::string& value) override
{
_value = value;
_callback(_value);
@@ -230,11 +235,12 @@ public:
{
}
const std::string defaultValueAsString() const
const std::string defaultValueAsString() const override
{
return std::to_string(_defaultValue);
}
void set(const std::string& value)
void set(const std::string& value) override
{
_value = std::stoi(value);
_callback(_value);
@@ -257,7 +263,7 @@ public:
{
}
const std::string defaultValueAsString() const;
const std::string defaultValueAsString() const override;
};
class DoubleFlag : public ValueFlag<double>
@@ -275,11 +281,12 @@ public:
{
}
const std::string defaultValueAsString() const
const std::string defaultValueAsString() const override
{
return std::to_string(_defaultValue);
}
void set(const std::string& value)
void set(const std::string& value) override
{
_value = std::stod(value);
_callback(_value);
@@ -302,11 +309,11 @@ public:
{
}
const std::string defaultValueAsString() const
const std::string defaultValueAsString() const override
{
return _defaultValue ? "true" : "false";
}
void set(const std::string& value);
void set(const std::string& value) override;
};
#endif

View File

@@ -0,0 +1,36 @@
#include "lib/globals.h"
#include "lib/fluxmap.h"
#include "lib/bytes.h"
#include "lib/fluxsource/catweasel.h"
std::unique_ptr<Fluxmap> decodeCatweaselData(
const Bytes& bytes, nanoseconds_t clock)
{
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
uint32_t pending = 0;
bool oldindex = true;
const uint8_t* ptr = bytes.begin();
while (ptr != bytes.end())
{
uint32_t b = *ptr++;
bool index = !!(b & 0x80);
b &= 0x7f;
if (b == 0x7f)
{
pending += 0x7f;
continue;
}
b += pending;
pending = 0;
double interval_ns = b * clock;
fluxmap->appendInterval(interval_ns / NS_PER_TICK);
fluxmap->appendPulse();
if (index && !oldindex)
fluxmap->appendIndex();
oldindex = index;
}
return fluxmap;
}

View File

@@ -0,0 +1,10 @@
#ifndef CATWEASEL_H
#define CATWEASEL_H
class Fluxmap;
class Bytes;
extern std::unique_ptr<Fluxmap> decodeCatweaselData(
const Bytes& bytes, nanoseconds_t clock);
#endif

View File

@@ -2,6 +2,7 @@
#include "lib/fluxmap.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/fluxsource/catweasel.h"
#include "lib/proto.h"
#include <fstream>
@@ -50,10 +51,10 @@ public:
switch (_header.clock_rate)
{
case 1:
_clockRate = 14161000.0;
_clockPeriod = 1e9 / 14161000.0;
break;
case 2:
_clockRate = 28322000.0;
_clockPeriod = 1e9 / 28322000.0;
break;
default:
error("unsupported clock rate");
@@ -65,7 +66,7 @@ public:
_header.tracks * _header.step,
_header.sides);
std::cout << fmt::format(
"CWF sample clock rate: {} MHz\n", _clockRate / 1e6);
"CWF sample clock rate: {} MHz\n", 1e3 / _clockPeriod);
int tracks = _header.tracks * _header.sides;
for (int i = 0; i < tracks; i++)
@@ -87,47 +88,22 @@ public:
}
public:
std::unique_ptr<const Fluxmap> readSingleFlux(int track, int side)
std::unique_ptr<const Fluxmap> readSingleFlux(int track, int side) override
{
const auto& p = _trackOffsets.find(std::make_pair(track, side));
if (p == _trackOffsets.end())
return std::make_unique<const Fluxmap>();
off_t pos = p->second.first;
;
size_t length = p->second.second;
_if.seekg(pos);
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
uint32_t pending = 0;
bool oldindex = true;
for (size_t cursor = 0; cursor < length; cursor++)
{
uint32_t b = _if.get();
bool index = !!(b & 0x80);
b &= 0x7f;
if (b == 0x7f)
{
pending += 0x7f;
continue;
}
b += pending;
pending = 0;
double interval_us = b * (1e6 / _clockRate);
fluxmap->appendInterval(interval_us / US_PER_TICK);
fluxmap->appendPulse();
if (index && !oldindex)
fluxmap->appendIndex();
oldindex = index;
}
Bytes fluxdata(_if, length);
check_for_error();
return fluxmap;
return decodeCatweaselData(fluxdata, _clockPeriod);
}
void recalibrate() {}
void recalibrate() override {}
private:
void check_for_error()
@@ -140,7 +116,7 @@ private:
const CwfFluxSourceProto& _config;
std::ifstream _if;
CwfHeader _header;
nanoseconds_t _clockRate;
nanoseconds_t _clockPeriod;
std::map<std::pair<int, int>, std::pair<off_t, size_t>> _trackOffsets;
};

View File

@@ -0,0 +1,77 @@
#include "lib/globals.h"
#include "lib/fluxmap.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/fluxsource/catweasel.h"
#include "lib/proto.h"
#include "lib/logger.h"
#include <fstream>
#include <filesystem>
class DmkFluxSourceIterator : public FluxSourceIterator
{
public:
DmkFluxSourceIterator(const std::string& path, int track, int side):
_path(path),
_track(track),
_side(side)
{
}
bool hasNext() const override
{
std::string p = getPath();
return std::filesystem::exists(getPath());
}
std::unique_ptr<const Fluxmap> next() override
{
std::string path = getPath();
log("DMK: reading {}", path);
std::ifstream ifstream(getPath(), std::ios::binary);
if (!ifstream)
return std::make_unique<Fluxmap>();
_count++;
Bytes bytes(ifstream);
return decodeCatweaselData(bytes, 1e9 / 7080500.0);
}
private:
const std::string getPath() const
{
return fmt::format(
"{}/C_S{:01}T{:02}.{:03}", _path, _side, _track, _count);
}
private:
const std::string _path;
const int _track;
const int _side;
int _count = 0;
};
class DmkFluxSource : public FluxSource
{
public:
DmkFluxSource(const DmkFluxSourceProto& config): _path(config.directory())
{
}
public:
std::unique_ptr<FluxSourceIterator> readFlux(int track, int side) override
{
return std::make_unique<DmkFluxSourceIterator>(_path, track, side);
}
void recalibrate() override {}
private:
const std::string _path;
};
std::unique_ptr<FluxSource> FluxSource::createDmkFluxSource(
const DmkFluxSourceProto& config)
{
return std::unique_ptr<FluxSource>(new DmkFluxSource(config));
}

View File

@@ -31,6 +31,9 @@ std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)
case FLUXTYPE_CWF:
return createCwfFluxSource(config.cwf());
case FLUXTYPE_DMK:
return createDmkFluxSource(config.dmk());
case FLUXTYPE_FLUX:
return createFl2FluxSource(config.fl2());

View File

@@ -37,6 +37,8 @@ private:
const A2rFluxSourceProto& config);
static std::unique_ptr<FluxSource> createCwfFluxSource(
const CwfFluxSourceProto& config);
static std::unique_ptr<FluxSource> createDmkFluxSource(
const DmkFluxSourceProto& config);
static std::unique_ptr<FluxSource> createEraseFluxSource(
const EraseFluxSourceProto& config);
static std::unique_ptr<FluxSource> createFl2FluxSource(
@@ -109,7 +111,7 @@ class EmptyFluxSourceIterator : public FluxSourceIterator
class TrivialFluxSource : public FluxSource
{
public:
std::unique_ptr<FluxSourceIterator> readFlux(int track, int side);
std::unique_ptr<FluxSourceIterator> readFlux(int track, int side) override;
virtual std::unique_ptr<const Fluxmap> readSingleFlux(
int track, int side) = 0;
};

View File

@@ -30,6 +30,11 @@ message CwfFluxSourceProto {
(help) = ".cwf file to read flux from"];
}
message DmkFluxSourceProto {
optional string directory = 1 [
(help) = "path to DMK directory"];
}
message Fl2FluxSourceProto {
optional string filename = 1 [default = "flux.fl2",
(help) = ".fl2 file to read flux from"];
@@ -39,13 +44,14 @@ message FlxFluxSourceProto {
optional string directory = 1 [(help) = "path to FLX stream directory"];
}
// NEXT: 12
// NEXT: 13
message FluxSourceProto {
optional FluxSourceSinkType type = 9
[default = FLUXTYPE_NOT_SET, (help) = "flux source type"];
optional A2rFluxSourceProto a2r = 11;
optional CwfFluxSourceProto cwf = 7;
optional DmkFluxSourceProto dmk = 12;
optional EraseFluxSourceProto erase = 4;
optional Fl2FluxSourceProto fl2 = 8;
optional FlxFluxSourceProto flx = 10;

View File

@@ -18,7 +18,7 @@ public:
return readStream(_path, track, side);
}
void recalibrate() {}
void recalibrate() override {}
private:
const std::string _path;

View File

@@ -47,7 +47,7 @@ public:
return std::make_unique<EmptyFluxSourceIterator>();
}
void recalibrate() {}
void recalibrate() override {}
private:
const DiskFlux& _flux;

View File

@@ -27,7 +27,7 @@ public:
return fluxmap;
}
void recalibrate() {}
void recalibrate() override {}
private:
const TestPatternFluxSourceProto& _config;

View File

@@ -14,7 +14,7 @@ class D64ImageReader : public ImageReader
public:
D64ImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -18,7 +18,7 @@ class D88ImageReader : public ImageReader
public:
D88ImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -18,7 +18,7 @@ class DimImageReader : public ImageReader
public:
DimImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -14,7 +14,7 @@ class DiskCopyImageReader : public ImageReader
public:
DiskCopyImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -18,7 +18,7 @@ class FdiImageReader : public ImageReader
public:
FdiImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -137,7 +137,7 @@ public:
* <End of file>
*/
// clang-format on
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
// Read File
std::ifstream inputFile(

View File

@@ -17,7 +17,7 @@ class ImgImageReader : public ImageReader
public:
ImgImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -89,7 +89,7 @@ class Jv3ImageReader : public ImageReader
public:
Jv3ImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -18,7 +18,7 @@ class NFDImageReader : public ImageReader
public:
NFDImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -16,7 +16,7 @@ class NsiImageReader : public ImageReader
public:
NsiImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -47,7 +47,7 @@ class Td0ImageReader : public ImageReader
public:
Td0ImageReader(const ImageReaderProto& config): ImageReader(config) {}
std::unique_ptr<Image> readImage()
std::unique_ptr<Image> readImage() override
{
std::ifstream inputFile(
_config.filename(), std::ios::in | std::ios::binary);

View File

@@ -26,7 +26,7 @@ class D64ImageWriter : public ImageWriter
public:
D64ImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
log("D64: writing triangular image");

View File

@@ -26,7 +26,7 @@ class D88ImageWriter : public ImageWriter
public:
D88ImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
const Geometry geometry = image.getGeometry();

View File

@@ -30,7 +30,7 @@ class DiskCopyImageWriter : public ImageWriter
public:
DiskCopyImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
const Geometry& geometry = image.getGeometry();

View File

@@ -155,7 +155,7 @@ class ImdImageWriter : public ImageWriter
public:
ImdImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
const Geometry& geometry = image.getGeometry();
unsigned numHeads;

View File

@@ -17,7 +17,7 @@ class ImgImageWriter : public ImageWriter
public:
ImgImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
const Geometry geometry = image.getGeometry();

View File

@@ -15,7 +15,7 @@ class LDBSImageWriter : public ImageWriter
public:
LDBSImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
LDBS ldbs;

View File

@@ -16,7 +16,7 @@ class NsiImageWriter : public ImageWriter
public:
NsiImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
const Geometry& geometry = image.getGeometry();
bool mixedDensity = false;

View File

@@ -16,7 +16,7 @@ class RawImageWriter : public ImageWriter
public:
RawImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
void writeImage(const Image& image)
void writeImage(const Image& image) override
{
const Geometry& geometry = image.getGeometry();

View File

@@ -123,7 +123,7 @@ private:
}
public:
int getVersion()
int getVersion() override
{
struct any_frame f = {
.f = {.type = F_FRAME_GET_VERSION_CMD, .size = sizeof(f)}
@@ -133,7 +133,7 @@ public:
return r->version;
}
void seek(int track)
void seek(int track) override
{
struct seek_frame f = {
.f = {.type = F_FRAME_SEEK_CMD, .size = sizeof(f)},
@@ -143,7 +143,7 @@ public:
await_reply<struct any_frame>(F_FRAME_SEEK_REPLY);
}
void recalibrate()
void recalibrate() override
{
struct any_frame f = {
.f = {.type = F_FRAME_RECALIBRATE_CMD, .size = sizeof(f)},
@@ -152,7 +152,7 @@ public:
await_reply<struct any_frame>(F_FRAME_RECALIBRATE_REPLY);
}
nanoseconds_t getRotationalPeriod(int hardSectorCount)
nanoseconds_t getRotationalPeriod(int hardSectorCount) override
{
struct measurespeed_frame f = {
.f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)},
@@ -164,7 +164,7 @@ public:
return r->period_ms * 1000000;
}
void testBulkWrite()
void testBulkWrite() override
{
struct any_frame f = {
.f = {.type = F_FRAME_BULK_WRITE_TEST_CMD, .size = sizeof(f)}
@@ -204,7 +204,7 @@ public:
await_reply<struct any_frame>(F_FRAME_BULK_WRITE_TEST_REPLY);
}
void testBulkRead()
void testBulkRead() override
{
struct any_frame f = {
.f = {.type = F_FRAME_BULK_READ_TEST_CMD, .size = sizeof(f)}
@@ -242,7 +242,7 @@ public:
Bytes read(int side,
bool synced,
nanoseconds_t readTime,
nanoseconds_t hardSectorThreshold)
nanoseconds_t hardSectorThreshold) override
{
struct read_frame f = {
.f = {.type = F_FRAME_READ_CMD, .size = sizeof(f)},
@@ -265,7 +265,9 @@ public:
return buffer;
}
void write(int side, const Bytes& bytes, nanoseconds_t hardSectorThreshold)
void write(int side,
const Bytes& bytes,
nanoseconds_t hardSectorThreshold) override
{
unsigned safelen = bytes.size() & ~(FRAME_SIZE - 1);
Bytes safeBytes = bytes.slice(0, safelen);
@@ -287,7 +289,7 @@ public:
await_reply<struct any_frame>(F_FRAME_WRITE_REPLY);
}
void erase(int side, nanoseconds_t hardSectorThreshold)
void erase(int side, nanoseconds_t hardSectorThreshold) override
{
struct erase_frame f = {
.f = {.type = F_FRAME_ERASE_CMD, .size = sizeof(f)},
@@ -300,7 +302,7 @@ public:
await_reply<struct any_frame>(F_FRAME_ERASE_REPLY);
}
void setDrive(int drive, bool high_density, int index_mode)
void setDrive(int drive, bool high_density, int index_mode) override
{
struct set_drive_frame f = {
.f = {.type = F_FRAME_SET_DRIVE_CMD, .size = sizeof(f)},
@@ -312,7 +314,7 @@ public:
await_reply<struct any_frame>(F_FRAME_SET_DRIVE_REPLY);
}
void measureVoltages(struct voltages_frame* voltages)
void measureVoltages(struct voltages_frame* voltages) override
{
struct any_frame f = {
{.type = F_FRAME_MEASURE_VOLTAGES_CMD, .size = sizeof(f)},

View File

@@ -109,7 +109,7 @@ public:
do_command({CMD_SET_BUS_TYPE, 3, (uint8_t)config.bus_type()});
}
int getVersion()
int getVersion() override
{
do_command({CMD_GET_INFO, 3, GETINFO_FIRMWARE});
@@ -124,17 +124,17 @@ public:
return br.read_be16();
}
void recalibrate()
void recalibrate() override
{
seek(0);
}
void seek(int track)
void seek(int track) override
{
do_command({CMD_SEEK, 3, (uint8_t)track});
}
nanoseconds_t getRotationalPeriod(int hardSectorCount)
nanoseconds_t getRotationalPeriod(int hardSectorCount) override
{
if (hardSectorCount != 0)
error("hard sectors are currently unsupported on the Greaseweazle");
@@ -214,7 +214,7 @@ public:
return _revolutions;
}
void testBulkWrite()
void testBulkWrite() override
{
std::cout << "Writing data: " << std::flush;
const int LEN = 10 * 1024 * 1024;
@@ -264,7 +264,7 @@ public:
int((LEN / 1024.0) / elapsed_time));
}
void testBulkRead()
void testBulkRead() override
{
std::cout << "Reading data: " << std::flush;
const int LEN = 10 * 1024 * 1024;
@@ -309,7 +309,7 @@ public:
Bytes read(int side,
bool synced,
nanoseconds_t readTime,
nanoseconds_t hardSectorThreshold)
nanoseconds_t hardSectorThreshold) override
{
if (hardSectorThreshold != 0)
error("hard sectors are currently unsupported on the Greaseweazle");
@@ -362,7 +362,9 @@ public:
return fldata;
}
void write(int side, const Bytes& fldata, nanoseconds_t hardSectorThreshold)
void write(int side,
const Bytes& fldata,
nanoseconds_t hardSectorThreshold) override
{
if (hardSectorThreshold != 0)
error("hard sectors are currently unsupported on the Greaseweazle");
@@ -385,7 +387,7 @@ public:
do_command({CMD_GET_FLUX_STATUS, 2});
}
void erase(int side, nanoseconds_t hardSectorThreshold)
void erase(int side, nanoseconds_t hardSectorThreshold) override
{
if (hardSectorThreshold != 0)
error("hard sectors are currently unsupported on the Greaseweazle");
@@ -403,14 +405,14 @@ public:
do_command({CMD_GET_FLUX_STATUS, 2});
}
void setDrive(int drive, bool high_density, int index_mode)
void setDrive(int drive, bool high_density, int index_mode) override
{
do_command({CMD_SELECT, 3, (uint8_t)drive});
do_command({CMD_MOTOR, 4, (uint8_t)drive, 1});
do_command({CMD_SET_PIN, 4, 2, (uint8_t)(high_density ? 1 : 0)});
}
void measureVoltages(struct voltages_frame* voltages)
void measureVoltages(struct voltages_frame* voltages) override
{
error("unsupported operation on the Greaseweazle");
}

View File

@@ -113,12 +113,12 @@ public:
{
}
uint32_t capabilities() const
uint32_t capabilities() const override
{
return OP_GETFSDATA | OP_LIST | OP_GETFILE | OP_GETDIRENT;
}
std::map<std::string, std::string> getMetadata()
std::map<std::string, std::string> getMetadata() override
{
AcornDfsDirectory dir(this);
@@ -130,12 +130,12 @@ public:
return attributes;
}
FilesystemStatus check()
FilesystemStatus check() override
{
return FS_OK;
}
std::vector<std::shared_ptr<Dirent>> list(const Path& path)
std::vector<std::shared_ptr<Dirent>> list(const Path& path) override
{
if (!path.empty())
throw FileNotFoundException();
@@ -148,7 +148,7 @@ public:
return result;
}
Bytes getFile(const Path& path)
Bytes getFile(const Path& path) override
{
AcornDfsDirectory dir(this);
auto dirent = dir.findFile(path);
@@ -166,7 +166,7 @@ public:
return data;
}
std::shared_ptr<Dirent> getDirent(const Path& path)
std::shared_ptr<Dirent> getDirent(const Path& path) override
{
AcornDfsDirectory dir(this);
return dir.findFile(path);

View File

@@ -141,7 +141,7 @@ public:
{
}
uint32_t capabilities() const
uint32_t capabilities() const override
{
return OP_GETFSDATA | OP_LIST | OP_GETFILE | OP_GETDIRENT;
}

View File

@@ -101,7 +101,7 @@ public:
{
}
uint32_t capabilities() const
uint32_t capabilities() const override
{
return OP_GETFSDATA | OP_LIST | OP_GETFILE | OP_GETDIRENT;
}

View File

@@ -189,7 +189,7 @@ public:
{
}
uint32_t capabilities() const
uint32_t capabilities() const override
{
return OP_GETFSDATA | OP_LIST | OP_GETFILE | OP_GETDIRENT;
}

View File

@@ -23,6 +23,7 @@ cxxprogram(
"./fe-rpm.cc",
"./fe-seek.cc",
"./fe-testbandwidth.cc",
"./fe-testdevices.cc",
"./fe-testvoltages.cc",
"./fe-write.cc",
"./fileutils.cc",

View File

@@ -17,6 +17,7 @@ static StringFlag sourceFlux({"-s", "--source"},
int mainRpm(int argc, const char* argv[])
{
globalConfig().set("flux_source.type", "FLUXTYPE_DRIVE");
flags.parseFlagsWithConfigFiles(argc, argv, {});
if (globalConfig()->flux_source().type() != FLUXTYPE_DRIVE)

41
src/fe-testdevices.cc Normal file
View File

@@ -0,0 +1,41 @@
#include "lib/globals.h"
#include "lib/flags.h"
#include "lib/usb/usbfinder.h"
#include <fmt/format.h>
static FlagGroup flags;
int mainTestDevices(int argc, const char* argv[])
{
flags.parseFlagsWithConfigFiles(argc, argv, {});
auto candidates = findUsbDevices();
switch (candidates.size())
{
case 0:
fmt::print("Detected no devices.\n");
break;
case 1:
fmt::print("Detected one device:\n");
break;
default:
fmt::print("Detected {} devices:\n", candidates.size());
}
if (!candidates.empty())
{
fmt::print(
"{:15} {:30} {}\n", "Type", "Serial number", "Port (if any)");
for (auto& candidate : candidates)
{
fmt::print("{:15} {:30} {}\n",
getDeviceName(candidate->type),
candidate->serial,
candidate->serialPort);
}
}
return 0;
}

View File

@@ -23,6 +23,7 @@ extern command_cb mainRm;
extern command_cb mainRpm;
extern command_cb mainSeek;
extern command_cb mainTestBandwidth;
extern command_cb mainTestDevices;
extern command_cb mainTestVoltages;
extern command_cb mainWrite;
@@ -69,6 +70,7 @@ static std::vector<Command> analysables =
static std::vector<Command> testables =
{
{ "bandwidth", mainTestBandwidth, "Measures your USB bandwidth.", },
{ "devices", mainTestDevices, "Displays all detected devices.", },
{ "voltages", mainTestVoltages, "Measures the FDD bus voltages.", },
};
// clang-format on

View File

@@ -47,12 +47,16 @@ layout {
encoder {
ibm {
trackdata {
target_rotational_period_ms: 167
target_clock_period_us: 3.333
target_rotational_period_ms: 166
target_clock_period_us: 3.33
emit_iam: false
gap0: 80
gap2: 22
gap3: 34
use_fm: true
gap0: 0x10
gap2: 0x09
gap3: 0x10
idam_byte: 0xf57e
dam_byte: 0xf56f
gap_fill_byte: 0xffff
}
}
}

View File

@@ -6,11 +6,12 @@ emit(
"""
WX_CONFIG ?= wx-config
ifneq ($(strip $(shell command -v $(WX_CONFIG) >/dev/null 2>&1; echo $$?)),0)
$(error Required binary 'wx-config' not found.)
endif
WX_CFLAGS = $(error Required binary 'wx-config' not found.)
WX_LDFLAGS = $(error Required binary 'wx-config' not found.)
else
WX_CFLAGS := $(shell $(WX_CONFIG) --cxxflags core base adv aui richtext)
WX_LDFLAGS := $(shell $(WX_CONFIG) --libs core base adv aui richtext)
endif
"""
)
@@ -99,7 +100,7 @@ if config.osx:
"dylibbundler -of -x {outs[0]}/Contents/MacOS/fluxengine-gui -b -d {outs[0]}/Contents/libs -cd > /dev/null",
"cp $$(brew --prefix wxwidgets)/README.md $@/Contents/libs/wxWidgets.md",
"cp $$(brew --prefix protobuf)/LICENSE $@/Contents/libs/protobuf.txt",
"cp $$(brew --prefix fmt)/LICENSE.rst $@/Contents/libs/fmt.rst",
"cp $$(brew --prefix fmt)/LICENSE* $@/Contents/libs/fmt.rst",
"cp $$(brew --prefix libpng)/LICENSE $@/Contents/libs/libpng.txt",
"cp $$(brew --prefix libjpeg)/README $@/Contents/libs/libjpeg.txt",
"cp $$(brew --prefix abseil)/LICENSE $@/Contents/libs/abseil.txt",

View File

@@ -33,7 +33,7 @@ static inline R runOnUiThread(std::function<R()> callback)
class FluxEngineApp : public wxApp, public wxThreadHelper
{
public:
virtual bool OnInit();
virtual bool OnInit() override;
void RunOnWorkerThread(std::function<void()> callback);
private:
@@ -44,7 +44,7 @@ public:
bool IsWorkerThreadRunning();
protected:
virtual wxThread::ExitCode Entry();
virtual wxThread::ExitCode Entry() override;
private:
static wxWindow* CreateMainWindow();

View File

@@ -26,7 +26,7 @@ public:
{
}
wxEvent* Clone() const
wxEvent* Clone() const override
{
return new ExecEvent(*this);
}

View File

@@ -10,7 +10,7 @@ public:
{
}
wxEvent* Clone() const
wxEvent* Clone() const override
{
return new EditorSaveEvent(*this);
}

View File

@@ -20,7 +20,7 @@ public:
wxTextCtrl* GetTextControl() const;
private:
void OnClose(wxCloseEvent& event);
void OnClose(wxCloseEvent& event) override;
private:
bool _autodestroy;

View File

@@ -24,7 +24,7 @@ public:
{
}
wxEvent* Clone() const
wxEvent* Clone() const override
{
return new TrackSelectionEvent(*this);
}

View File

@@ -18,7 +18,7 @@ namespace
{
public:
std::shared_ptr<const Sector> get(
unsigned track, unsigned side, unsigned sectorId)
unsigned track, unsigned side, unsigned sectorId) override
{
auto s = _image.get(track, side, sectorId);
if (!s)
@@ -27,7 +27,7 @@ namespace
}
std::shared_ptr<Sector> put(
unsigned track, unsigned side, unsigned sectorId)
unsigned track, unsigned side, unsigned sectorId) override
{
return _image.put(track, side, sectorId);
}