mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | acf32c2a5c | ||
|  | 41460457a3 | 
							
								
								
									
										73
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,49 +2,47 @@ name: C/C++ CI | ||||
|  | ||||
| on: [push] | ||||
|  | ||||
| concurrency:  | ||||
|   group: environment-${{ github.head_ref }} | ||||
|   cancel-in-progress: true | ||||
|  | ||||
| jobs: | ||||
|   build-linux: | ||||
|     runs-on: ubuntu-22.04 | ||||
|     runs-on: ubuntu-20.04 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|     - uses: actions/checkout@v1 | ||||
|     - name: apt | ||||
|       run: | | ||||
|         sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev libprotobuf-dev wx-common | ||||
|       run: sudo apt update && sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev | ||||
|     - name: make | ||||
|       run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j`nproc` -C fluxengine | ||||
|       run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j2 | ||||
|  | ||||
|   build-macos-current: | ||||
|     runs-on: macos-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|     - name: brew | ||||
|       run: brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg | ||||
|     - name: make | ||||
|       run: gmake -j`nproc` -C fluxengine | ||||
|       run: gmake -j2 | ||||
|  | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v2 | ||||
|       with: | ||||
|         name: ${{ github.event.repository.name }}.${{ github.sha }} | ||||
|         path: fluxengine/FluxEngine.pkg | ||||
|         path: FluxEngine.pkg | ||||
|  | ||||
|   build-macos-10-15: | ||||
|     runs-on: macos-10.15 | ||||
|     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 -j2 | ||||
|         mv FluxEngine.pkg FluxEngine-10.15.pkg | ||||
|  | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v2 | ||||
|       with: | ||||
|         name: ${{ github.event.repository.name }}.${{ github.sha }} | ||||
|         path: FluxEngine-10.15.pkg | ||||
|  | ||||
|   build-windows: | ||||
|     runs-on: windows-latest | ||||
| @@ -59,48 +57,33 @@ jobs: | ||||
|         install: >- | ||||
|           diffutils | ||||
|           make | ||||
|           mingw-w64-i686-binutils | ||||
|           mingw-w64-i686-fmt | ||||
|           mingw-w64-i686-gcc | ||||
|           mingw-w64-i686-libusb | ||||
|           mingw-w64-i686-nsis | ||||
|           mingw-w64-i686-pkg-config | ||||
|           mingw-w64-i686-protobuf | ||||
|           mingw-w64-i686-python | ||||
|           mingw-w64-i686-sqlite3 | ||||
|           mingw-w64-i686-wxWidgets | ||||
|           mingw-w64-i686-zlib | ||||
|           mingw-w64-i686-png2ico | ||||
|           vim | ||||
|           mingw-w64-i686-nsis | ||||
|           zip | ||||
|     - name: update-protobuf | ||||
|       run: | | ||||
|          pacman -U --noconfirm https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-protobuf-21.9-1-any.pkg.tar.zst | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|           vim | ||||
|     - uses: actions/checkout@v1 | ||||
|     - name: build | ||||
|       run: MAGICK_TIME_LIMIT=100 make -j`nproc` -C fluxengine | ||||
|       run: make -j2 | ||||
|  | ||||
|     - name: nsis | ||||
|       run: | | ||||
|         cd fluxengine | ||||
|         strip fluxengine.exe -o fluxengine-stripped.exe | ||||
|         strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe | ||||
|         makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi | ||||
|  | ||||
|     - name: zip | ||||
|       run: | | ||||
|         cd fluxengine | ||||
|         zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe | ||||
|  | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v2 | ||||
|       with: | ||||
|         name: ${{ github.event.repository.name }}.${{ github.sha }} | ||||
|         path: fluxengine/fluxengine-windows.zip | ||||
|         path: fluxengine-windows.zip | ||||
|   | ||||
							
								
								
									
										21
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,9 +1,5 @@ | ||||
| name: Autorelease | ||||
|  | ||||
| concurrency:  | ||||
|   group: environment-release-${{ github.head_ref }} | ||||
|   cancel-in-progress: true | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
| @@ -23,29 +19,22 @@ jobs: | ||||
|         install: >- | ||||
|           diffutils | ||||
|           make | ||||
|           mingw-w64-i686-binutils | ||||
|           mingw-w64-i686-fmt | ||||
|           mingw-w64-i686-gcc | ||||
|           mingw-w64-i686-libusb | ||||
|           mingw-w64-i686-nsis | ||||
|           mingw-w64-i686-pkg-config | ||||
|           mingw-w64-i686-protobuf | ||||
|           mingw-w64-i686-python | ||||
|           mingw-w64-i686-sqlite3 | ||||
|           mingw-w64-i686-wxWidgets | ||||
|           mingw-w64-i686-zlib | ||||
|           mingw-w64-i686-png2ico | ||||
|           vim | ||||
|           mingw-w64-i686-nsis | ||||
|           zip | ||||
|           vim | ||||
|     - uses: actions/checkout@v3 | ||||
|  | ||||
|     - name: update-protobuf | ||||
|       run: | | ||||
|          pacman -U --noconfirm https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-protobuf-21.9-1-any.pkg.tar.zst | ||||
|  | ||||
|     - name: build | ||||
|       run: | | ||||
|         MAGICK_TIME_LIMIT=100 make -j`nproc` | ||||
|         make -j2 | ||||
|  | ||||
|     - name: nsis | ||||
|       run: | | ||||
| @@ -94,12 +83,10 @@ 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 -j`nproc` | ||||
|       run: gmake | ||||
|  | ||||
|     - name: tag | ||||
|       uses: EndBug/latest-tag@latest | ||||
|   | ||||
							
								
								
									
										261
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										261
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,65 +1,256 @@ | ||||
| CC = gcc | ||||
| CXX = g++ -std=c++17 | ||||
| CFLAGS = -g -O3 | ||||
| LDFLAGS = | ||||
|  | ||||
| OBJ = .obj | ||||
| DESTDIR ?= | ||||
| PREFIX ?= /usr/local | ||||
| BINDIR ?= $(PREFIX)/bin | ||||
|  | ||||
| # Special Windows settings. | ||||
|  | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	EXT ?= .exe | ||||
| 	MINGWBIN = /mingw32/bin | ||||
| 	CCPREFIX = $(MINGWBIN)/ | ||||
| 	LUA = $(MINGWBIN)/lua | ||||
| 	PKG_CONFIG = $(MINGWBIN)/pkg-config | ||||
| 	WX_CONFIG = /usr/bin/sh $(MINGWBIN)/wx-config --static=yes | ||||
| 	PROTOC = $(MINGWBIN)/protoc | ||||
| 	WINDRES = windres | ||||
| 	PLATFORM = WINDOWS | ||||
| 	LDFLAGS += \ | ||||
| 		-static | ||||
| 	CXXFLAGS += \ | ||||
| 		-std=c++17 \ | ||||
| 		-fext-numeric-literals \ | ||||
| 		-Wno-deprecated-enum-float-conversion \ | ||||
| 		-Wno-deprecated-enum-enum-conversion | ||||
|  | ||||
| 	# Required to get the gcc run - time libraries on the path. | ||||
| 	# Required to get the gcc run-time libraries on the path. | ||||
| 	export PATH := $(PATH):$(MINGWBIN) | ||||
| 	EXT ?= .exe | ||||
| endif | ||||
|  | ||||
| # Special OSX settings. | ||||
|  | ||||
| ifeq ($(shell uname),Darwin) | ||||
| 	PLATFORM = OSX | ||||
| 	LDFLAGS += \ | ||||
| 		-framework IOKit \ | ||||
| 		-framework Foundation  | ||||
| 		-framework Foundation | ||||
| endif | ||||
|  | ||||
| .PHONY: all | ||||
| all: +all README.md | ||||
| # Check the Make version. | ||||
|  | ||||
| .PHONY: binaries tests | ||||
| binaries: all | ||||
| tests: all | ||||
| 	 | ||||
| README.md: $(OBJ)/scripts+mkdocindex/scripts+mkdocindex$(EXT) | ||||
| 	@echo MKDOC $@ | ||||
| 	@csplit -s -f$(OBJ)/README. README.md '/<!-- FORMATSSTART -->/' '%<!-- FORMATSEND -->%' | ||||
| 	@(cat $(OBJ)/README.00 && $< && cat $(OBJ)/README.01) > README.md | ||||
|  | ||||
| .PHONY: tests | ||||
| ifeq ($(findstring 4.,$(MAKE_VERSION)),) | ||||
| $(error You need GNU Make 4.x for this (if you're on OSX, use gmake).) | ||||
| endif | ||||
|  | ||||
| .PHONY: install install-bin | ||||
| install:: all install-bin | ||||
| # Normal settings. | ||||
|  | ||||
| install-bin: | ||||
| 	@echo "INSTALL" | ||||
| 	$(hide) install -D -v "$(OBJ)/src+fluxengine/src+fluxengine" "$(DESTDIR)$(BINDIR)/fluxengine" | ||||
| 	$(hide) install -D -v "$(OBJ)/src/gui+gui/gui+gui" "$(DESTDIR)$(BINDIR)/fluxengine-gui" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+brother120tool/tools+brother120tool" "$(DESTDIR)$(BINDIR)/brother120tool" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+brother240tool/tools+brother240tool" "$(DESTDIR)$(BINDIR)/brother240tool" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+upgrade-flux-file/tools+upgrade-flux-file" "$(DESTDIR)$(BINDIR)/upgrade-flux-file" | ||||
| OBJDIR ?= .obj | ||||
| CCPREFIX ?= | ||||
| LUA ?= lua | ||||
| CC ?= $(CCPREFIX)gcc | ||||
| CXX ?= $(CCPREFIX)g++ | ||||
| AR ?= $(CCPREFIX)ar | ||||
| PKG_CONFIG ?= pkg-config | ||||
| WX_CONFIG ?= wx-config | ||||
| PROTOC ?= protoc | ||||
| CFLAGS ?= -g -O3 | ||||
| CXXFLAGS += -std=c++17 | ||||
| LDFLAGS ?= | ||||
| PLATFORM ?= UNIX | ||||
| TESTS ?= yes | ||||
| EXT ?= | ||||
| DESTDIR ?= | ||||
| PREFIX ?= /usr/local | ||||
| BINDIR ?= $(PREFIX)/bin | ||||
|  | ||||
| include build/ab.mk | ||||
| CFLAGS += \ | ||||
| 	-Iarch \ | ||||
| 	-Ilib \ | ||||
| 	-I. \ | ||||
| 	-I$(OBJDIR)/arch \ | ||||
| 	-I$(OBJDIR)/lib \ | ||||
| 	-I$(OBJDIR) \ | ||||
|  | ||||
| LDFLAGS += \ | ||||
| 	-lz \ | ||||
| 	-lfmt | ||||
|  | ||||
| .SUFFIXES: | ||||
| .DELETE_ON_ERROR: | ||||
|  | ||||
| define nl | ||||
|  | ||||
| endef | ||||
|  | ||||
| use-library = $(eval $(use-library-impl)) | ||||
| define use-library-impl | ||||
| $1: $(call $3_LIB) | ||||
| $1: private LDFLAGS += $(call $3_LDFLAGS) | ||||
| $2: private CFLAGS += $(call $3_CFLAGS) | ||||
| endef | ||||
|  | ||||
| use-pkgconfig = $(eval $(use-pkgconfig-impl)) | ||||
| define use-pkgconfig-impl | ||||
| ifneq ($(strip $(shell $(PKG_CONFIG) $3; echo $$?)),0) | ||||
| $$(error Missing required pkg-config dependency: $3) | ||||
| endif | ||||
|  | ||||
| $(1): private LDFLAGS += $(shell $(PKG_CONFIG) --libs $(3)) | ||||
| $(2): private CFLAGS += $(shell $(PKG_CONFIG) --cflags $(3)) | ||||
| endef | ||||
|  | ||||
| .PHONY: all binaries tests clean install install-bin | ||||
| all: binaries tests | ||||
|  | ||||
| PROTOS = \ | ||||
| 	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/smaky6/smaky6.proto \ | ||||
| 	arch/tids990/tids990.proto \ | ||||
| 	arch/victor9k/victor9k.proto \ | ||||
| 	arch/zilogmcz/zilogmcz.proto \ | ||||
| 	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/layout.proto \ | ||||
| 	lib/usb/usb.proto \ | ||||
| 	lib/vfs/vfs.proto \ | ||||
| 	tests/testproto.proto \ | ||||
|  | ||||
| PROTO_HDRS = $(patsubst %.proto, $(OBJDIR)/%.pb.h, $(PROTOS)) | ||||
| PROTO_SRCS = $(patsubst %.proto, $(OBJDIR)/%.pb.cc, $(PROTOS)) | ||||
| PROTO_OBJS = $(patsubst %.cc, %.o, $(PROTO_SRCS)) | ||||
| PROTO_CFLAGS = $(shell $(PKG_CONFIG) --cflags protobuf) | ||||
| $(PROTO_SRCS): | $(PROTO_HDRS) | ||||
| $(PROTO_OBJS): CFLAGS += $(PROTO_CFLAGS) | ||||
| PROTO_LIB = $(OBJDIR)/libproto.a | ||||
| $(PROTO_LIB): $(PROTO_OBJS) | ||||
| PROTO_LDFLAGS = $(shell $(PKG_CONFIG) --libs protobuf) -pthread $(PROTO_LIB) | ||||
| .PRECIOUS: $(PROTO_HDRS) $(PROTO_SRCS) | ||||
|  | ||||
| include dep/agg/build.mk | ||||
| include dep/libusbp/build.mk | ||||
| include dep/stb/build.mk | ||||
| include dep/emu/build.mk | ||||
| include dep/fatfs/build.mk | ||||
| include dep/adflib/build.mk | ||||
| include dep/hfsutils/build.mk | ||||
| include scripts/build.mk | ||||
|  | ||||
| include lib/build.mk | ||||
| include arch/build.mk | ||||
| include src/build.mk | ||||
| include src/gui/build.mk | ||||
| include tools/build.mk | ||||
| include tests/build.mk | ||||
|  | ||||
| do-encodedecodetest = $(eval $(do-encodedecodetest-impl)) | ||||
| define do-encodedecodetest-impl | ||||
|  | ||||
| tests: $(OBJDIR)/$1$3.flux.encodedecode | ||||
| $(OBJDIR)/$1$3.flux.encodedecode: scripts/encodedecodetest.sh $(FLUXENGINE_BIN) $2 | ||||
| 	@mkdir -p $(dir $$@) | ||||
| 	@echo ENCODEDECODETEST $1 flux $(FLUXENGINE_BIN) $2 $3 | ||||
| 	@scripts/encodedecodetest.sh $1 flux $(FLUXENGINE_BIN) $2 $3 > $$@ | ||||
|  | ||||
| tests: $(OBJDIR)/$1$3.scp.encodedecode | ||||
| $(OBJDIR)/$1$3.scp.encodedecode: scripts/encodedecodetest.sh $(FLUXENGINE_BIN) $2 | ||||
| 	@mkdir -p $(dir $$@) | ||||
| 	@echo ENCODEDECODETEST $1 scp $(FLUXENGINE_BIN) $2 $3 | ||||
| 	@scripts/encodedecodetest.sh $1 scp $(FLUXENGINE_BIN) $2 $3 > $$@ | ||||
|  | ||||
| endef | ||||
|  | ||||
| $(call do-encodedecodetest,agat840) | ||||
| $(call do-encodedecodetest,amiga) | ||||
| $(call do-encodedecodetest,appleii140) | ||||
| $(call do-encodedecodetest,atarist360) | ||||
| $(call do-encodedecodetest,atarist370) | ||||
| $(call do-encodedecodetest,atarist400) | ||||
| $(call do-encodedecodetest,atarist410) | ||||
| $(call do-encodedecodetest,atarist720) | ||||
| $(call do-encodedecodetest,atarist740) | ||||
| $(call do-encodedecodetest,atarist800) | ||||
| $(call do-encodedecodetest,atarist820) | ||||
| $(call do-encodedecodetest,bk800) | ||||
| $(call do-encodedecodetest,brother120) | ||||
| $(call do-encodedecodetest,brother240) | ||||
| $(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb,--35) | ||||
| $(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb,--40) | ||||
| $(call do-encodedecodetest,commodore1581) | ||||
| $(call do-encodedecodetest,cmd_fd2000) | ||||
| $(call do-encodedecodetest,hp9121) | ||||
| $(call do-encodedecodetest,ibm1200) | ||||
| $(call do-encodedecodetest,ibm1232) | ||||
| $(call do-encodedecodetest,ibm1440) | ||||
| $(call do-encodedecodetest,ibm180) | ||||
| $(call do-encodedecodetest,ibm360) | ||||
| $(call do-encodedecodetest,ibm720) | ||||
| $(call do-encodedecodetest,mac400,scripts/mac400_test.textpb) | ||||
| $(call do-encodedecodetest,mac800,scripts/mac800_test.textpb) | ||||
| $(call do-encodedecodetest,n88basic) | ||||
| $(call do-encodedecodetest,rx50) | ||||
| $(call do-encodedecodetest,tids990) | ||||
| $(call do-encodedecodetest,victor9k_ss) | ||||
| $(call do-encodedecodetest,victor9k_ds) | ||||
|  | ||||
| $(OBJDIR)/%.a: | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo AR $@ | ||||
| 	@$(AR) rc $@ $^ | ||||
|  | ||||
| %.exe: | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo LINK $@ | ||||
| 	@$(CXX) -o $@ $^ $(LDFLAGS) $(LDFLAGS) | ||||
|  | ||||
| $(OBJDIR)/%.o: %.cpp | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CXX $< | ||||
| 	@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
|  | ||||
| $(OBJDIR)/%.o: %.cc | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CXX $< | ||||
| 	@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
|  | ||||
| $(OBJDIR)/%.o: $(OBJDIR)/%.cc | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CXX $< | ||||
| 	@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
|  | ||||
| $(OBJDIR)/%.o: %.c | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CC $< | ||||
| 	@$(CC) $(CFLAGS) $(CFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
|  | ||||
| $(OBJDIR)/%.pb.h: %.proto | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo PROTOC $@ | ||||
| 	@$(PROTOC) -I. --cpp_out=$(OBJDIR) $< | ||||
|  | ||||
| clean: | ||||
| 	rm -rf $(OBJDIR) | ||||
|  | ||||
| install: install-bin # install-man install-docs ... | ||||
|  | ||||
| install-bin: fluxengine$(EXT) fluxengine-gui$(EXT) brother120tool$(EXT) brother240tool$(EXT) upgrade-flux-file$(EXT) | ||||
| 	install -d "$(DESTDIR)$(BINDIR)" | ||||
| 	for target in $^; do \ | ||||
| 		install $$target "$(DESTDIR)$(BINDIR)/$$target"; \ | ||||
| 	done | ||||
|  | ||||
| -include $(OBJS:%.o=%.d) | ||||
|   | ||||
							
								
								
									
										112
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								README.md
									
									
									
									
									
								
							| @@ -35,11 +35,11 @@ Don't believe me? Watch the demo reel! | ||||
| </div> | ||||
|  | ||||
| **New!** The FluxEngine client software now works with | ||||
| [Greaseweazle](https://github.com/keirf/Greaseweazle/wiki) hardware. So, if you | ||||
| [GreaseWeazle](https://github.com/keirf/Greaseweazle/wiki) hardware. So, if you | ||||
| can't find a PSoC5 development kit, or don't want to use the Cypress Windows | ||||
| tools for programming it, you can use one of these instead. Very nearly all | ||||
| FluxEngine features are available with the Greaseweazle and it works out-of-the | ||||
| box. See the [dedicated Greaseweazle documentation page](doc/greaseweazle.md) | ||||
| FluxEngine features are available with the GreaseWeazle and it works out-of-the | ||||
| box. See the [dedicated GreaseWeazle documentation page](doc/greaseweazle.md) | ||||
| for more information. | ||||
|  | ||||
| Where? | ||||
| @@ -65,7 +65,7 @@ following friendly articles: | ||||
|   - [Using a FluxEngine](doc/using.md) ∾ what to do with your new hardware ∾ | ||||
|     flux files and image files ∾ knowing what you're doing | ||||
|  | ||||
|   - [Using Greaseweazle hardware with the FluxEngine client | ||||
|   - [Using GreaseWeazle hardware with the FluxEngine client | ||||
|     software](doc/greaseweazle.md) ∾ what works ∾ what doesn't work ∾ where to | ||||
|     go for help | ||||
|  | ||||
| @@ -88,61 +88,63 @@ Which? | ||||
|  | ||||
| The current support state is as follows. | ||||
|  | ||||
| Dinosaurs (🦖) have yet to be observed in real life --- I've written the encoder | ||||
| and/or decoder based on Kryoflux (or other) dumps I've found. I don't (yet) have | ||||
| real, physical disks in my hand to test the capture process, or hardware to | ||||
| verify that written disks work. | ||||
| Dinosaurs (🦖) have yet to be observed in real life --- I've written the | ||||
| decoder based on Kryoflux (or other) dumps I've found. I don't (yet) have | ||||
| real, physical disks in my hand to test the capture process. | ||||
|  | ||||
| Unicorns (🦄) are completely real --- this means that I've read actual, physical | ||||
| disks with these formats and/or written real, physical disks and then used them | ||||
| on real hardware, and so know they work (or had reports from people who've had | ||||
| it work). | ||||
| Unicorns (🦄) are completely real --- this means that I've read actual, | ||||
| physical disks with these formats and so know they work (or had reports from | ||||
| people who've had it work). | ||||
|  | ||||
| If a filesystem is listed, this means that FluxEngine natively supports that | ||||
| particular filesystem and can read (and sometimes write, support varies) files | ||||
| directly from disks, flux files or disk images. Some formats have multiple | ||||
| choices because they can store multiple types of file system. | ||||
| ### Old disk formats | ||||
|  | ||||
| <!-- FORMATSSTART --> | ||||
| <!-- This section is automatically generated. Do not edit. --> | ||||
|  | ||||
| | Profile | Format | Read? | Write? | Filesystem? | | ||||
| |:--------|:-------|:-----:|:------:|:------------| | ||||
| | [`acornadfs`](doc/disk-acornadfs.md) | Acorn ADFS: BBC Micro, Archimedes | 🦖 |  |  | | ||||
| | [`acorndfs`](doc/disk-acorndfs.md) | Acorn DFS: Acorn Atom, BBC Micro series | 🦄 |  | ACORNDFS  | | ||||
| | [`aeslanier`](doc/disk-aeslanier.md) | AES Lanier "No Problem": 616kB 5.25" 77-track SSDD hard sectored | 🦖 |  |  | | ||||
| | [`agat`](doc/disk-agat.md) | Agat: 840kB 5.25" 80-track DS | 🦖 | 🦖 |  | | ||||
| | [`amiga`](doc/disk-amiga.md) | Amiga: 880kB 3.5" DSDD | 🦄 | 🦄 | AMIGAFFS  | | ||||
| | [`ampro`](doc/disk-ampro.md) | Ampro Little Board: CP/M | 🦖 |  | CPMFS  | | ||||
| | [`apple2`](doc/disk-apple2.md) | Apple II: Prodos, Appledos, and CP/M | 🦄 | 🦄 | APPLEDOS CPMFS PRODOS  | | ||||
| | [`atarist`](doc/disk-atarist.md) | Atari ST: Almost PC compatible | 🦄 | 🦄 |  | | ||||
| | [`bk`](doc/disk-bk.md) | BK: 800kB 5.25"/3.5" 80-track 10-sector DSDD | 🦖 | 🦖 |  | | ||||
| | [`brother`](doc/disk-brother.md) | Brother word processors: GCR family | 🦄 | 🦄 | BROTHER120 FATFS  | | ||||
| | [`commodore`](doc/disk-commodore.md) | Commodore: 1541, 1581, 8050 and variations | 🦄 | 🦄 | CBMFS  | | ||||
| | [`eco1`](doc/disk-eco1.md) | VDS Eco1: CP/M; 1210kB 77-track mixed format DSHD | 🦖 |  | CPMFS  | | ||||
| | [`epsonpf10`](doc/disk-epsonpf10.md) | Epson PF-10: CP/M; 3.5" 40-track DSDD | 🦖 |  | CPMFS  | | ||||
| | [`f85`](doc/disk-f85.md) | Durango F85: 461kB 5.25" 77-track SS | 🦖 |  |  | | ||||
| | [`fb100`](doc/disk-fb100.md) | Brother FB-100: 100kB 3.5" 40-track SSSD | 🦖 |  |  | | ||||
| | [`hplif`](doc/disk-hplif.md) | Hewlett-Packard LIF: a variety of disk formats used by HP | 🦄 | 🦄 | LIF  | | ||||
| | [`ibm`](doc/disk-ibm.md) | IBM PC: Generic PC 3.5"/5.25" disks | 🦄 | 🦄 | FATFS  | | ||||
| | [`icl30`](doc/disk-icl30.md) | ICL Model 30: CP/M; 263kB 35-track DSSD | 🦖 |  | CPMFS  | | ||||
| | [`mac`](doc/disk-mac.md) | Macintosh: 400kB/800kB 3.5" GCR | 🦄 | 🦄 | MACHFS  | | ||||
| | [`micropolis`](doc/disk-micropolis.md) | Micropolis: 100tpi MetaFloppy disks | 🦄 | 🦄 |  | | ||||
| | [`ms2000`](doc/disk-ms2000.md) | : MS2000 Microdisk Development System |  |  | MICRODOS  | | ||||
| | [`mx`](doc/disk-mx.md) | DVK MX: Soviet-era PDP-11 clone | 🦖 |  |  | | ||||
| | [`n88basic`](doc/disk-n88basic.md) | N88-BASIC: PC8800/PC98 5.25" 77-track 26-sector DSHD | 🦄 | 🦄 |  | | ||||
| | [`northstar`](doc/disk-northstar.md) | Northstar: 5.25" hard sectored | 🦄 | 🦄 |  | | ||||
| | [`psos`](doc/disk-psos.md) | pSOS: 800kB DSDD with PHILE | 🦄 | 🦄 | PHILE  | | ||||
| | [`rolandd20`](doc/disk-rolandd20.md) | Roland D20: 3.5" electronic synthesiser disks | 🦄 | 🦖 | ROLAND  | | ||||
| | [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 |  | | ||||
| | [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 |  | SMAKY6  | | ||||
| | [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 |  | | ||||
| | [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M |  |  | CPMFS  | | ||||
| | [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 |  | | ||||
| | [`zilogmcz`](doc/disk-zilogmcz.md) | Zilog MCZ: 320kB 8" 77-track SSSD hard-sectored | 🦖 |  | ZDOS  | | ||||
| | Format                                    | Read? | Write? | Notes | | ||||
| |:------------------------------------------|:-----:|:------:|-------| | ||||
| | [IBM PC compatible](doc/disk-ibm.md)      |  🦄   |   🦄   | and compatibles (like the Atari ST) | | ||||
| | [Atari ST](doc/disk-atarist.md)           |  🦄   |   🦄   | technically the same as IBM, almost | | ||||
| | [Acorn ADFS](doc/disk-acornadfs.md)       |  🦄   |   🦖*  | single- and double- sided           | | ||||
| | [Acorn DFS](doc/disk-acorndfs.md)         |  🦄   |   🦖*  |                                     | | ||||
| | [Ampro Little Board](doc/disk-ampro.md)   |  🦖   |   🦖*  |                                     | | ||||
| | [Agat](doc/disk-agat.md)                  |  🦖   |        | Soviet Union Apple-II-like computer | | ||||
| | [Apple II](doc/disk-apple2.md)            |  🦄   |   🦄   | both 140kB and 640kB formats        | | ||||
| | [Amiga](doc/disk-amiga.md)                |  🦄   |   🦄   |                                     | | ||||
| | [Commodore 64 1541/1581](doc/disk-c64.md) |  🦄   |   🦄   | and probably the other formats      | | ||||
| | [Brother 120kB](doc/disk-brother.md)      |  🦄   |   🦄   |                                     | | ||||
| | [Brother 240kB](doc/disk-brother.md)      |  🦄   |   🦄   |                                     | | ||||
| | [Brother FB-100](doc/disk-fb100.md)       |  🦖   |        | Tandy Model 100, Husky Hunter, knitting machines | | ||||
| | [Elektronika BK](doc/disk-bd.md)          |  🦄   |   🦄   | Soviet Union PDP-11 clone           | | ||||
| | [Macintosh 400kB/800kB](doc/disk-macintosh.md)  |  🦄   |   🦄   |                                     | | ||||
| | [NEC PC-98](doc/disk-ibm.md)              |  🦄   |   🦄   | trimode drive not required          | | ||||
| | [pSOS](doc/disk-ibm.md)                   |  🦄   |   🦖*  | pSOS PHILE file system              | | ||||
| | [Sharp X68000](doc/disk-ibm.md)           |  🦄   |   🦄   | yet another IBM scheme             | | ||||
| | [Smaky 6](doc/disk-smaky6.md)             |  🦖   |       | 5.25" hard sectored | | ||||
| | [TRS-80](doc/disk-trs80.md)               |  🦖   |   🦖*  | a minor variation of the IBM scheme | | ||||
| {: .datatable } | ||||
|  | ||||
| <!-- FORMATSEND --> | ||||
| `*`: these formats are variations of the generic IBM format, and since the | ||||
| IBM writer is completely generic, it should be configurable for these | ||||
| formats... theoretically. I don't have the hardware to try it. | ||||
|  | ||||
| ### Even older disk formats | ||||
|  | ||||
| These formats are for particularly old, weird architectures, even by the | ||||
| standards of floppy disks. They've largely been implemented from single flux | ||||
| files with no access to physical hardware. Typically the reads were pretty | ||||
| bad and I've had to make a number of guesses as to how things work. They do, | ||||
| at least, check the CRC so what data's there is probably good. | ||||
|  | ||||
| | Format                                   | Read? | Write? | Notes | | ||||
| |:-----------------------------------------|:-----:|:------:|-------| | ||||
| | [AES Superplus / No Problem](doc/disk-aeslanier.md) |  🦖   | | hard sectors! | | ||||
| | [Durango F85](doc/disk-durangof85.md)    |  🦖   |        | 5.25" | | ||||
| | [DVK MX](doc/disk-mx.md)                 |  🦖   |        | Soviet PDP-11 clone | | ||||
| | [VDS Eco1](doc/disk-eco1.md)             |  🦖   |        | 8" mixed format | | ||||
| | [Micropolis](doc/disk-micropolis.md)     |  🦄   |        | Micropolis 100tpi drives | | ||||
| | [Northstar](doc/disk-northstar.md)       |  🦖   |   🦖   | 5.25" hard sectors | | ||||
| | [TI DS990 FD1000](doc/disk-tids990.md)   |  🦄   |  🦄    | 8" | | ||||
| | [Victor 9000](doc/disk-victor9k.md)      |  🦖   |        | 5.25" GCR encoded | | ||||
| | [Zilog MCZ](doc/disk-zilogmcz.md)        |  🦖   |        | 8" _and_ hard sectors | | ||||
| {: .datatable } | ||||
|  | ||||
| ### Notes | ||||
|  | ||||
| @@ -261,3 +263,5 @@ __Important:__ Because of all these exceptions, if you distribute the | ||||
| FluxEngine package as a whole, you must comply with the terms of _all_ of the | ||||
| licensing terms. This means that __effectively the FluxEngine package is | ||||
| distributable under the terms of the GPL 2.0__. | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -2,10 +2,9 @@ | ||||
| #define AESLANIER_H | ||||
|  | ||||
| #define AESLANIER_RECORD_SEPARATOR 0x55555122 | ||||
| #define AESLANIER_SECTOR_LENGTH 256 | ||||
| #define AESLANIER_RECORD_SIZE (AESLANIER_SECTOR_LENGTH + 5) | ||||
| #define AESLANIER_SECTOR_LENGTH    256 | ||||
| #define AESLANIER_RECORD_SIZE      (AESLANIER_SECTOR_LENGTH + 5) | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createAesLanierDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createAesLanierDecoder(const DecoderProto& config); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,64 +1,66 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "aeslanier.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
|  | ||||
| static const FluxPattern SECTOR_PATTERN(32, AESLANIER_RECORD_SEPARATOR); | ||||
|  | ||||
| /* This is actually M2FM, rather than MFM, but it our MFM/FM decoder copes fine | ||||
|  * with it. */ | ||||
| /* This is actually M2FM, rather than MFM, but it our MFM/FM decoder copes fine with it. */ | ||||
|  | ||||
| class AesLanierDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     AesLanierDecoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	AesLanierDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(SECTOR_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(SECTOR_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         /* Skip ID mark (we know it's a AESLANIER_RECORD_SEPARATOR). */ | ||||
| 	{ | ||||
| 		/* Skip ID mark (we know it's a AESLANIER_RECORD_SEPARATOR). */ | ||||
|  | ||||
|         readRawBits(16); | ||||
| 		readRawBits(16); | ||||
|  | ||||
|         const auto& rawbits = readRawBits(AESLANIER_RECORD_SIZE * 16); | ||||
|         const auto& bytes = | ||||
|             decodeFmMfm(rawbits).slice(0, AESLANIER_RECORD_SIZE); | ||||
|         const auto& reversed = bytes.reverseBits(); | ||||
| 		const auto& rawbits = readRawBits(AESLANIER_RECORD_SIZE*16); | ||||
| 		const auto& bytes = decodeFmMfm(rawbits).slice(0, AESLANIER_RECORD_SIZE); | ||||
| 		const auto& reversed = bytes.reverseBits(); | ||||
|  | ||||
|         _sector->logicalTrack = reversed[1]; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalSector = reversed[2]; | ||||
| 		_sector->logicalTrack = reversed[1]; | ||||
| 		_sector->logicalSide = 0; | ||||
| 		_sector->logicalSector = reversed[2]; | ||||
|  | ||||
|         /* Check header 'checksum' (which seems far too simple to mean much). */ | ||||
| 		/* Check header 'checksum' (which seems far too simple to mean much). */ | ||||
|  | ||||
|         { | ||||
|             uint8_t wanted = reversed[3]; | ||||
|             uint8_t got = reversed[1] + reversed[2]; | ||||
|             if (wanted != got) | ||||
|                 return; | ||||
|         } | ||||
| 		{ | ||||
| 			uint8_t wanted = reversed[3]; | ||||
| 			uint8_t got = reversed[1] + reversed[2]; | ||||
| 			if (wanted != got) | ||||
| 				return; | ||||
| 		} | ||||
|  | ||||
|         /* Check data checksum, which also includes the header and is | ||||
|          * significantly better. */ | ||||
| 		/* Check data checksum, which also includes the header and is | ||||
| 			* significantly better. */ | ||||
|  | ||||
|         _sector->data = reversed.slice(1, AESLANIER_SECTOR_LENGTH); | ||||
|         uint16_t wanted = reversed.reader().seek(0x101).read_le16(); | ||||
|         uint16_t got = crc16ref(MODBUS_POLY_REF, _sector->data); | ||||
|         _sector->status = (wanted == got) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = reversed.slice(1, AESLANIER_SECTOR_LENGTH); | ||||
| 		uint16_t wanted = reversed.reader().seek(0x101).read_le16(); | ||||
| 		uint16_t got = crc16ref(MODBUS_POLY_REF, _sector->data); | ||||
| 		_sector->status = (wanted == got) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createAesLanierDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new AesLanierDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new AesLanierDecoder(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,20 +1,22 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "agat.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| uint8_t agatChecksum(const Bytes& bytes) | ||||
| { | ||||
|     uint16_t checksum = 0; | ||||
|  | ||||
|     for (uint8_t b : bytes) | ||||
|     { | ||||
|         if (checksum > 0xff) | ||||
|             checksum = (checksum + 1) & 0xff; | ||||
| 	for (uint8_t b : bytes) | ||||
| 	{ | ||||
| 		if (checksum > 0xff) | ||||
| 			checksum = (checksum + 1) & 0xff; | ||||
|  | ||||
|         checksum += b; | ||||
|     } | ||||
| 		checksum += b; | ||||
| 	} | ||||
|  | ||||
|     return checksum & 0xff; | ||||
| 	return checksum & 0xff; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -17,3 +17,4 @@ extern std::unique_ptr<Encoder> createAgatEncoder(const EncoderProto& config); | ||||
| extern uint8_t agatChecksum(const Bytes& bytes); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1,22 +1,21 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "agat.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
|  | ||||
| // clang-format off | ||||
| /* | ||||
|  * data:    X  X  X  X   X  X  X  X   X  -  -  X   -  X  -  X   -  X  X  -   X  -  X  -  = 0xff956a | ||||
|  * flux:   01 01 01 01  01 01 01 01  01 00 10 01  00 01 00 01  00 01 01 00  01 00 01 00  = 0x555549111444 | ||||
|  *  | ||||
|  * data:    X  X  X  X   X  X  X  X   -  X  X  -   X  -  X  -   X  -  -  X   -  X  -  X  = 0xff6a95 | ||||
|  * flux:   01 01 01 01  01 01 01 01  00 01 01 00  01 00 01 00  01 00 10 01  00 01 00 01  = 0x555514444911 | ||||
|  * | ||||
|  *  | ||||
|  * Each pattern is prefixed with this one: | ||||
|  * | ||||
|  * data:          -  -   -  X   -  -   X  - = 0x12 | ||||
| @@ -31,59 +30,65 @@ | ||||
|  *          0100010010010010  = MFM encoded | ||||
|  *           1000100100100100 = with trailing zero | ||||
|  *            - - - X - - X - = effective bitstream = 0x12 | ||||
|  * | ||||
|  */ | ||||
| // clang-format on | ||||
|  | ||||
| static const FluxPattern SECTOR_PATTERN(64, SECTOR_ID); | ||||
| static const FluxPattern DATA_PATTERN(64, DATA_ID); | ||||
|  | ||||
| static const FluxMatchers ALL_PATTERNS = {&SECTOR_PATTERN, &DATA_PATTERN}; | ||||
| static const FluxMatchers ALL_PATTERNS = { | ||||
| 	&SECTOR_PATTERN, | ||||
| 	&DATA_PATTERN | ||||
| }; | ||||
|  | ||||
| class AgatDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     AgatDecoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	AgatDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ALL_PATTERNS); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(ALL_PATTERNS); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         if (readRaw64() != SECTOR_ID) | ||||
|             return; | ||||
| 	{ | ||||
| 		if (readRaw64() != SECTOR_ID) | ||||
| 			return; | ||||
|  | ||||
|         auto bytes = decodeFmMfm(readRawBits(64)).slice(0, 4); | ||||
|         if (bytes[3] != 0x5a) | ||||
|             return; | ||||
| 		auto bytes = decodeFmMfm(readRawBits(64)).slice(0, 4); | ||||
| 		if (bytes[3] != 0x5a) | ||||
| 			return; | ||||
|  | ||||
|         _sector->logicalTrack = bytes[1] >> 1; | ||||
|         _sector->logicalSector = bytes[2]; | ||||
|         _sector->logicalSide = bytes[1] & 1; | ||||
|         _sector->status = Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|     } | ||||
| 		_sector->logicalTrack = bytes[1] >> 1; | ||||
| 		_sector->logicalSector = bytes[2]; | ||||
| 		_sector->logicalSide = bytes[1] & 1; | ||||
| 		_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
| 	} | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         if (readRaw64() != DATA_ID) | ||||
|             return; | ||||
| 	void decodeDataRecord() override | ||||
| 	{ | ||||
| 		if (readRaw64() != DATA_ID) | ||||
| 			return; | ||||
|  | ||||
|         Bytes bytes = decodeFmMfm(readRawBits((AGAT_SECTOR_SIZE + 2) * 16)) | ||||
|                           .slice(0, AGAT_SECTOR_SIZE + 2); | ||||
| 		Bytes bytes = decodeFmMfm(readRawBits((AGAT_SECTOR_SIZE+2)*16)).slice(0, AGAT_SECTOR_SIZE+2); | ||||
|  | ||||
|         if (bytes[AGAT_SECTOR_SIZE + 1] != 0x5a) | ||||
|             return; | ||||
| 		if (bytes[AGAT_SECTOR_SIZE+1] != 0x5a) | ||||
| 			return; | ||||
|  | ||||
|         _sector->data = bytes.slice(0, AGAT_SECTOR_SIZE); | ||||
|         uint8_t wantChecksum = bytes[AGAT_SECTOR_SIZE]; | ||||
|         uint8_t gotChecksum = agatChecksum(_sector->data); | ||||
|         _sector->status = | ||||
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = bytes.slice(0, AGAT_SECTOR_SIZE); | ||||
| 		uint8_t wantChecksum = bytes[AGAT_SECTOR_SIZE]; | ||||
| 		uint8_t gotChecksum = agatChecksum(_sector->data); | ||||
| 		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createAgatDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new AgatDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new AgatDecoder(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -95,7 +95,7 @@ public: | ||||
|         } | ||||
|  | ||||
|         if (_cursor >= _bits.size()) | ||||
|             error("track data overrun"); | ||||
|             Error() << "track data overrun"; | ||||
|         fillBitmapTo(_bits, _cursor, _bits.size(), {true, false}); | ||||
|  | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "amiga.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| uint32_t amigaChecksum(const Bytes& bytes) | ||||
| @@ -18,61 +18,61 @@ uint32_t amigaChecksum(const Bytes& bytes) | ||||
|  | ||||
| static uint8_t everyother(uint16_t x) | ||||
| { | ||||
|     /* aabb ccdd eeff gghh */ | ||||
|     x &= 0x6666; /* 0ab0 0cd0 0ef0 0gh0 */ | ||||
|     x >>= 1;     /* 00ab 00cd 00ef 00gh */ | ||||
|     x |= x << 2; /* abab cdcd efef ghgh */ | ||||
|     x &= 0x3c3c; /* 00ab cd00 00ef gh00 */ | ||||
|     x >>= 2;     /* 0000 abcd 0000 efgh */ | ||||
|     x |= x >> 4; /* 0000 abcd abcd efgh */ | ||||
|     return x; | ||||
| 	                  /* aabb ccdd eeff gghh */ | ||||
| 	x &= 0x6666;      /* 0ab0 0cd0 0ef0 0gh0 */ | ||||
| 	x >>= 1;          /* 00ab 00cd 00ef 00gh */ | ||||
| 	x |= x << 2;      /* abab cdcd efef ghgh */ | ||||
| 	x &= 0x3c3c;      /* 00ab cd00 00ef gh00 */ | ||||
| 	x >>= 2;          /* 0000 abcd 0000 efgh */ | ||||
| 	x |= x >> 4;      /* 0000 abcd abcd efgh */ | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| Bytes amigaInterleave(const Bytes& input) | ||||
| { | ||||
|     Bytes output; | ||||
|     ByteWriter bw(output); | ||||
| 	Bytes output; | ||||
| 	ByteWriter bw(output); | ||||
|  | ||||
|     /* Write all odd bits. (Numbering starts at 0...) */ | ||||
| 	/* Write all odd bits. (Numbering starts at 0...) */ | ||||
|  | ||||
|     { | ||||
|         ByteReader br(input); | ||||
|         while (!br.eof()) | ||||
|         { | ||||
|             uint16_t x = br.read_be16(); | ||||
|             x &= 0xaaaa;       /* a0b0 c0d0 e0f0 g0h0 */ | ||||
|             x |= x >> 1;       /* aabb ccdd eeff gghh */ | ||||
|             x = everyother(x); /* 0000 0000 abcd efgh */ | ||||
|             bw.write_8(x); | ||||
|         } | ||||
|     } | ||||
| 	{ | ||||
| 		ByteReader br(input); | ||||
| 		while (!br.eof()) | ||||
| 		{ | ||||
| 			uint16_t x = br.read_be16(); | ||||
| 			x &= 0xaaaa;       /* a0b0 c0d0 e0f0 g0h0 */ | ||||
| 			x |= x >> 1;       /* aabb ccdd eeff gghh */ | ||||
| 			x = everyother(x); /* 0000 0000 abcd efgh */ | ||||
| 			bw.write_8(x); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     /* Write all even bits. */ | ||||
| 	/* Write all even bits. */ | ||||
|  | ||||
|     { | ||||
|         ByteReader br(input); | ||||
|         while (!br.eof()) | ||||
|         { | ||||
|             uint16_t x = br.read_be16(); | ||||
|             x &= 0x5555;       /* 0a0b 0c0d 0e0f 0g0h */ | ||||
|             x |= x << 1;       /* aabb ccdd eeff gghh */ | ||||
|             x = everyother(x); /* 0000 0000 abcd efgh */ | ||||
|             bw.write_8(x); | ||||
|         } | ||||
|     } | ||||
| 	{ | ||||
| 		ByteReader br(input); | ||||
| 		while (!br.eof()) | ||||
| 		{ | ||||
| 			uint16_t x = br.read_be16(); | ||||
| 			x &= 0x5555;       /* 0a0b 0c0d 0e0f 0g0h */ | ||||
| 			x |= x << 1;       /* aabb ccdd eeff gghh */ | ||||
| 			x = everyother(x); /* 0000 0000 abcd efgh */ | ||||
| 			bw.write_8(x); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     return output; | ||||
| 	return output; | ||||
| } | ||||
|  | ||||
| Bytes amigaDeinterleave(const uint8_t*& input, size_t len) | ||||
| { | ||||
|     assert(!(len & 1)); | ||||
|     const uint8_t* odds = &input[0]; | ||||
|     const uint8_t* evens = &input[len / 2]; | ||||
|     const uint8_t* evens = &input[len/2]; | ||||
|     Bytes output; | ||||
|     ByteWriter bw(output); | ||||
|  | ||||
|     for (size_t i = 0; i < len / 2; i++) | ||||
|     for (size_t i=0; i<len/2; i++) | ||||
|     { | ||||
|         uint8_t o = *odds++; | ||||
|         uint8_t e = *evens++; | ||||
| @@ -81,15 +81,11 @@ Bytes amigaDeinterleave(const uint8_t*& input, size_t len) | ||||
|          * http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN | ||||
|          */ | ||||
|         uint16_t result = | ||||
|             (((e * 0x0101010101010101ULL & 0x8040201008040201ULL) * | ||||
|                      0x0102040810204081ULL >> | ||||
|                  49) & | ||||
|                 0x5555) | | ||||
|             (((o * 0x0101010101010101ULL & 0x8040201008040201ULL) * | ||||
|                      0x0102040810204081ULL >> | ||||
|                  48) & | ||||
|                 0xAAAA); | ||||
|  | ||||
|             (((e * 0x0101010101010101ULL & 0x8040201008040201ULL) | ||||
|                 * 0x0102040810204081ULL >> 49) & 0x5555) | | ||||
|             (((o * 0x0101010101010101ULL & 0x8040201008040201ULL) | ||||
|                 * 0x0102040810204081ULL >> 48) & 0xAAAA); | ||||
|          | ||||
|         bw.write_be16(result); | ||||
|     } | ||||
|  | ||||
| @@ -99,6 +95,6 @@ Bytes amigaDeinterleave(const uint8_t*& input, size_t len) | ||||
|  | ||||
| Bytes amigaDeinterleave(const Bytes& input) | ||||
| { | ||||
|     const uint8_t* ptr = input.cbegin(); | ||||
|     return amigaDeinterleave(ptr, input.size()); | ||||
| 	const uint8_t* ptr = input.cbegin(); | ||||
| 	return amigaDeinterleave(ptr, input.size()); | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #ifndef AMIGA_H | ||||
| #define AMIGA_H | ||||
|  | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "encoders/encoders.h" | ||||
|  | ||||
| #define AMIGA_SECTOR_RECORD 0xaaaa44894489LL | ||||
|  | ||||
|   | ||||
| @@ -1,84 +1,80 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "amiga.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|  | ||||
| /* | ||||
| /*  | ||||
|  * Amiga disks use MFM but it's not quite the same as IBM MFM. They only use | ||||
|  * a single type of record with a different marker byte. | ||||
|  * | ||||
|  *  | ||||
|  * See the big comment in the IBM MFM decoder for the gruesome details of how | ||||
|  * MFM works. | ||||
|  */ | ||||
|  | ||||
|           | ||||
| static const FluxPattern SECTOR_PATTERN(48, AMIGA_SECTOR_RECORD); | ||||
|  | ||||
| class AmigaDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     AmigaDecoder(const DecoderProto& config): | ||||
|         Decoder(config), | ||||
|         _config(config.amiga()) | ||||
|     { | ||||
|     } | ||||
| 	AmigaDecoder(const DecoderProto& config): | ||||
| 		Decoder(config), | ||||
| 		_config(config.amiga()) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(SECTOR_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(SECTOR_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         if (readRaw48() != AMIGA_SECTOR_RECORD) | ||||
|             return; | ||||
| 	{ | ||||
| 		if (readRaw48() != AMIGA_SECTOR_RECORD) | ||||
| 			return; | ||||
| 			 | ||||
| 		const auto& rawbits = readRawBits(AMIGA_RECORD_SIZE*16); | ||||
| 		if (rawbits.size() < (AMIGA_RECORD_SIZE*16)) | ||||
| 			return; | ||||
| 		const auto& rawbytes = toBytes(rawbits).slice(0, AMIGA_RECORD_SIZE*2); | ||||
| 		const auto& bytes = decodeFmMfm(rawbits).slice(0, AMIGA_RECORD_SIZE); | ||||
|  | ||||
|         const auto& rawbits = readRawBits(AMIGA_RECORD_SIZE * 16); | ||||
|         if (rawbits.size() < (AMIGA_RECORD_SIZE * 16)) | ||||
|             return; | ||||
|         const auto& rawbytes = toBytes(rawbits).slice(0, AMIGA_RECORD_SIZE * 2); | ||||
|         const auto& bytes = decodeFmMfm(rawbits).slice(0, AMIGA_RECORD_SIZE); | ||||
| 		const uint8_t* ptr = bytes.begin(); | ||||
|  | ||||
|         const uint8_t* ptr = bytes.begin(); | ||||
| 		Bytes header = amigaDeinterleave(ptr, 4); | ||||
| 		Bytes recoveryinfo = amigaDeinterleave(ptr, 16); | ||||
|  | ||||
|         Bytes header = amigaDeinterleave(ptr, 4); | ||||
|         Bytes recoveryinfo = amigaDeinterleave(ptr, 16); | ||||
| 		_sector->logicalTrack = header[1] >> 1; | ||||
| 		_sector->logicalSide = header[1] & 1; | ||||
| 		_sector->logicalSector = header[2]; | ||||
|  | ||||
|         _sector->logicalTrack = header[1] >> 1; | ||||
|         _sector->logicalSide = header[1] & 1; | ||||
|         _sector->logicalSector = header[2]; | ||||
| 		uint32_t wantedheaderchecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); | ||||
| 		uint32_t gotheaderchecksum = amigaChecksum(rawbytes.slice(0, 40)); | ||||
| 		if (gotheaderchecksum != wantedheaderchecksum) | ||||
| 			return; | ||||
|  | ||||
|         uint32_t wantedheaderchecksum = | ||||
|             amigaDeinterleave(ptr, 4).reader().read_be32(); | ||||
|         uint32_t gotheaderchecksum = amigaChecksum(rawbytes.slice(0, 40)); | ||||
|         if (gotheaderchecksum != wantedheaderchecksum) | ||||
|             return; | ||||
| 		uint32_t wanteddatachecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); | ||||
| 		uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(56, 1024)); | ||||
|  | ||||
|         uint32_t wanteddatachecksum = | ||||
|             amigaDeinterleave(ptr, 4).reader().read_be32(); | ||||
|         uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(56, 1024)); | ||||
|  | ||||
|         Bytes data; | ||||
|         data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); | ||||
|         _sector->data = data; | ||||
|         _sector->status = (gotdatachecksum == wanteddatachecksum) | ||||
|                               ? Sector::OK | ||||
|                               : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		Bytes data; | ||||
| 		data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); | ||||
| 		_sector->data = data; | ||||
| 		_sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
|  | ||||
| private: | ||||
|     const AmigaDecoderProto& _config; | ||||
|     nanoseconds_t _clock; | ||||
| 	const AmigaDecoderProto& _config; | ||||
| 	nanoseconds_t _clock; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createAmigaDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new AmigaDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new AmigaDecoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "amiga.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "arch/amiga/amiga.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
| @@ -59,7 +59,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|     const std::shared_ptr<const Sector>& sector) | ||||
| { | ||||
|     if ((sector->data.size() != 512) && (sector->data.size() != 528)) | ||||
|         error("unsupported sector size --- you must pick 512 or 528"); | ||||
|         Error() << "unsupported sector size --- you must pick 512 or 528"; | ||||
|  | ||||
|     uint32_t checksum = 0; | ||||
|  | ||||
| @@ -114,8 +114,7 @@ public: | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         /* Number of bits for one nominal revolution of a real 200ms Amiga disk. | ||||
|          */ | ||||
|         /* Number of bits for one nominal revolution of a real 200ms Amiga disk. */ | ||||
|         int bitsPerRevolution = 200e3 / _config.clock_rate_us(); | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
|         unsigned cursor = 0; | ||||
| @@ -130,12 +129,13 @@ public: | ||||
|             write_sector(bits, cursor, sector); | ||||
|  | ||||
|         if (cursor >= bits.size()) | ||||
|             error("track data overrun"); | ||||
|             Error() << "track data overrun"; | ||||
|         fillBitmapTo(bits, cursor, bits.size(), {true, false}); | ||||
|  | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|         fluxmap->appendBits(bits, | ||||
|             calculatePhysicalClockPeriod(_config.clock_rate_us() * 1e3, 200e6)); | ||||
|             calculatePhysicalClockPeriod( | ||||
|                 _config.clock_rate_us() * 1e3, 200e6)); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -2,18 +2,19 @@ | ||||
| #define APPLE2_H | ||||
|  | ||||
| #include <memory.h> | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
|  | ||||
| #define APPLE2_SECTOR_RECORD 0xd5aa96 | ||||
| #define APPLE2_DATA_RECORD 0xd5aaad | ||||
| #define APPLE2_SECTOR_RECORD   0xd5aa96 | ||||
| #define APPLE2_DATA_RECORD     0xd5aaad | ||||
|  | ||||
| #define APPLE2_SECTOR_LENGTH 256 | ||||
| #define APPLE2_SECTOR_LENGTH   256 | ||||
| #define APPLE2_ENCODED_SECTOR_LENGTH 342 | ||||
|  | ||||
| #define APPLE2_SECTORS 16 | ||||
| #define APPLE2_SECTORS         16 | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createApple2Decoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createApple2Encoder(const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "apple2.h" | ||||
| #include "arch/apple2/apple2.pb.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "globals.h" | ||||
| #include "arch/apple2/apple2.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "sector.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include <ctype.h> | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
|  | ||||
| static int encode_data_gcr(uint8_t data) | ||||
| { | ||||
| @@ -50,7 +50,8 @@ public: | ||||
|             writeSector(bits, cursor, *sector); | ||||
|  | ||||
|         if (cursor >= bits.size()) | ||||
|             error("track data overrun by {} bits", cursor - bits.size()); | ||||
|             Error() << fmt::format( | ||||
|                 "track data overrun by {} bits", cursor - bits.size()); | ||||
|         fillBitmapTo(bits, cursor, bits.size(), {true, false}); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| @@ -117,7 +118,8 @@ private: | ||||
|  | ||||
|             // There is data to encode to disk. | ||||
|             if ((sector.data.size() != APPLE2_SECTOR_LENGTH)) | ||||
|                 error("unsupported sector size {} --- you must pick 256", | ||||
|                 Error() << fmt::format( | ||||
|                     "unsupported sector size {} --- you must pick 256", | ||||
|                     sector.data.size()); | ||||
|  | ||||
|             // Write address syncing leader : A sequence of "FF40"s; 5 of them | ||||
|   | ||||
| @@ -3,19 +3,17 @@ | ||||
|  | ||||
| /* Brother word processor format (or at least, one of them) */ | ||||
|  | ||||
| #define BROTHER_SECTOR_RECORD 0xFFFFFD57 | ||||
| #define BROTHER_DATA_RECORD 0xFFFFFDDB | ||||
| #define BROTHER_DATA_RECORD_PAYLOAD 256 | ||||
| #define BROTHER_DATA_RECORD_CHECKSUM 3 | ||||
| #define BROTHER_SECTOR_RECORD            0xFFFFFD57 | ||||
| #define BROTHER_DATA_RECORD              0xFFFFFDDB | ||||
| #define BROTHER_DATA_RECORD_PAYLOAD      256 | ||||
| #define BROTHER_DATA_RECORD_CHECKSUM     3 | ||||
| #define BROTHER_DATA_RECORD_ENCODED_SIZE 415 | ||||
|  | ||||
| #define BROTHER_TRACKS_PER_240KB_DISK 78 | ||||
| #define BROTHER_TRACKS_PER_120KB_DISK 39 | ||||
| #define BROTHER_SECTORS_PER_TRACK 12 | ||||
| #define BROTHER_TRACKS_PER_240KB_DISK    78 | ||||
| #define BROTHER_TRACKS_PER_120KB_DISK    39 | ||||
| #define BROTHER_SECTORS_PER_TRACK        12 | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createBrotherDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createBrotherEncoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createBrotherDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createBrotherEncoder(const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| GCR_ENTRY(0x55, 0)  // 00000 | ||||
| GCR_ENTRY(0x57, 1)  // 00001 | ||||
| GCR_ENTRY(0x5b, 2)  // 00010 | ||||
| GCR_ENTRY(0x5d, 3)  // 00011 | ||||
| GCR_ENTRY(0x5f, 4)  // 00100 | ||||
| GCR_ENTRY(0x6b, 5)  // 00101 | ||||
| GCR_ENTRY(0x6d, 6)  // 00110 | ||||
| GCR_ENTRY(0x6f, 7)  // 00111 | ||||
| GCR_ENTRY(0x75, 8)  // 01000 | ||||
| GCR_ENTRY(0x77, 9)  // 01001 | ||||
| GCR_ENTRY(0x55, 0) // 00000 | ||||
| GCR_ENTRY(0x57, 1) // 00001 | ||||
| GCR_ENTRY(0x5b, 2) // 00010 | ||||
| GCR_ENTRY(0x5d, 3) // 00011 | ||||
| GCR_ENTRY(0x5f, 4) // 00100  | ||||
| GCR_ENTRY(0x6b, 5) // 00101 | ||||
| GCR_ENTRY(0x6d, 6) // 00110 | ||||
| GCR_ENTRY(0x6f, 7) // 00111 | ||||
| GCR_ENTRY(0x75, 8) // 01000 | ||||
| GCR_ENTRY(0x77, 9) // 01001 | ||||
| GCR_ENTRY(0x7b, 10) // 01010 | ||||
| GCR_ENTRY(0x7d, 11) // 01011 | ||||
| GCR_ENTRY(0x7f, 12) // 01100 | ||||
| @@ -30,3 +30,4 @@ GCR_ENTRY(0xef, 28) // 11100 | ||||
| GCR_ENTRY(0xf5, 29) // 11101 | ||||
| GCR_ENTRY(0xf7, 30) // 11110 | ||||
| GCR_ENTRY(0xfb, 31) // 11111 | ||||
|  | ||||
|   | ||||
| @@ -1,18 +1,17 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "brother.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "crc.h" | ||||
| #include <ctype.h> | ||||
|  | ||||
| const FluxPattern SECTOR_RECORD_PATTERN(32, BROTHER_SECTOR_RECORD); | ||||
| const FluxPattern DATA_RECORD_PATTERN(32, BROTHER_DATA_RECORD); | ||||
| const FluxMatchers ANY_RECORD_PATTERN( | ||||
|     {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN}); | ||||
| const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN }); | ||||
|  | ||||
| static std::vector<uint8_t> outputbuffer; | ||||
|  | ||||
| @@ -33,89 +32,88 @@ static int decode_data_gcr(uint8_t gcr) | ||||
| { | ||||
|     switch (gcr) | ||||
|     { | ||||
| #define GCR_ENTRY(gcr, data) \ | ||||
|     case gcr:                \ | ||||
|         return data; | ||||
| #include "data_gcr.h" | ||||
| #undef GCR_ENTRY | ||||
| 		#define GCR_ENTRY(gcr, data) \ | ||||
| 			case gcr: return data; | ||||
| 		#include "data_gcr.h" | ||||
| 		#undef GCR_ENTRY | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static int decode_header_gcr(uint16_t word) | ||||
| { | ||||
|     switch (word) | ||||
|     { | ||||
| #define GCR_ENTRY(gcr, data) \ | ||||
|     case gcr:                \ | ||||
|         return data; | ||||
| #include "header_gcr.h" | ||||
| #undef GCR_ENTRY | ||||
|     } | ||||
|     return -1; | ||||
| 	switch (word) | ||||
| 	{ | ||||
| 		#define GCR_ENTRY(gcr, data) \ | ||||
| 			case gcr: return data; | ||||
| 		#include "header_gcr.h" | ||||
| 		#undef GCR_ENTRY | ||||
| 	}                        | ||||
| 	return -1;              | ||||
| } | ||||
|  | ||||
| class BrotherDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     BrotherDecoder(const DecoderProto& config): Decoder(config) {} | ||||
|     BrotherDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(ANY_RECORD_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         if (readRaw32() != BROTHER_SECTOR_RECORD) | ||||
|             return; | ||||
| 	{ | ||||
| 		if (readRaw32() != BROTHER_SECTOR_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         const auto& rawbits = readRawBits(32); | ||||
|         const auto& bytes = toBytes(rawbits).slice(0, 4); | ||||
| 		const auto& rawbits = readRawBits(32); | ||||
| 		const auto& bytes = toBytes(rawbits).slice(0, 4); | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
|         _sector->logicalTrack = decode_header_gcr(br.read_be16()); | ||||
|         _sector->logicalSector = decode_header_gcr(br.read_be16()); | ||||
| 		ByteReader br(bytes); | ||||
| 		_sector->logicalTrack = decode_header_gcr(br.read_be16()); | ||||
| 		_sector->logicalSector = decode_header_gcr(br.read_be16()); | ||||
|  | ||||
|         /* Sanity check the values read; there's no header checksum and | ||||
|          * occasionally we get garbage due to bit errors. */ | ||||
|         if (_sector->logicalSector > 11) | ||||
|             return; | ||||
|         if (_sector->logicalTrack > 79) | ||||
|             return; | ||||
|  | ||||
|         _sector->status = Sector::DATA_MISSING; | ||||
|     } | ||||
| 		/* Sanity check the values read; there's no header checksum and | ||||
| 			* occasionally we get garbage due to bit errors. */ | ||||
| 		if (_sector->logicalSector > 11) | ||||
| 			return; | ||||
| 		if (_sector->logicalTrack > 79) | ||||
| 			return; | ||||
|  | ||||
| 		_sector->status = Sector::DATA_MISSING; | ||||
| 	} | ||||
| 	 | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         if (readRaw32() != BROTHER_DATA_RECORD) | ||||
|             return; | ||||
| 	{ | ||||
| 		if (readRaw32() != BROTHER_DATA_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         const auto& rawbits = readRawBits(BROTHER_DATA_RECORD_ENCODED_SIZE * 8); | ||||
|         const auto& rawbytes = | ||||
|             toBytes(rawbits).slice(0, BROTHER_DATA_RECORD_ENCODED_SIZE); | ||||
| 		const auto& rawbits = readRawBits(BROTHER_DATA_RECORD_ENCODED_SIZE*8); | ||||
| 		const auto& rawbytes = toBytes(rawbits).slice(0, BROTHER_DATA_RECORD_ENCODED_SIZE); | ||||
|  | ||||
|         Bytes bytes; | ||||
|         ByteWriter bw(bytes); | ||||
|         BitWriter bitw(bw); | ||||
|         for (uint8_t b : rawbytes) | ||||
|         { | ||||
|             uint32_t nibble = decode_data_gcr(b); | ||||
|             bitw.push(nibble, 5); | ||||
|         } | ||||
|         bitw.flush(); | ||||
| 		Bytes bytes; | ||||
| 		ByteWriter bw(bytes); | ||||
| 		BitWriter bitw(bw); | ||||
| 		for (uint8_t b : rawbytes) | ||||
| 		{ | ||||
| 			uint32_t nibble = decode_data_gcr(b); | ||||
| 			bitw.push(nibble, 5); | ||||
| 		} | ||||
| 		bitw.flush(); | ||||
|  | ||||
|         _sector->data = bytes.slice(0, BROTHER_DATA_RECORD_PAYLOAD); | ||||
|         uint32_t realCrc = crcbrother(_sector->data); | ||||
|         uint32_t wantCrc = | ||||
|             bytes.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24(); | ||||
|         _sector->status = | ||||
|             (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = bytes.slice(0, BROTHER_DATA_RECORD_PAYLOAD); | ||||
| 		uint32_t realCrc = crcbrother(_sector->data); | ||||
| 		uint32_t wantCrc = bytes.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24(); | ||||
| 		_sector->status = (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createBrotherDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new BrotherDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new BrotherDecoder(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "brother.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "arch/brother/brother.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
| @@ -67,7 +67,7 @@ static void write_sector_data( | ||||
|     int width = 0; | ||||
|  | ||||
|     if (data.size() != BROTHER_DATA_RECORD_PAYLOAD) | ||||
|         error("unsupported sector size"); | ||||
|         Error() << "unsupported sector size"; | ||||
|  | ||||
|     auto write_byte = [&](uint8_t byte) | ||||
|     { | ||||
| @@ -107,7 +107,8 @@ public: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode( | ||||
| 		std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
| @@ -115,8 +116,8 @@ public: | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
|         unsigned cursor = 0; | ||||
|  | ||||
|         int sectorCount = 0; | ||||
|         for (const auto& sectorData : sectors) | ||||
| 		int sectorCount = 0; | ||||
| 		for (const auto& sectorData : sectors) | ||||
|         { | ||||
|             double headerMs = _config.post_index_gap_ms() + | ||||
|                               sectorCount * _config.sector_spacing_ms(); | ||||
| @@ -125,18 +126,16 @@ public: | ||||
|             unsigned dataCursor = dataMs * 1e3 / _config.clock_rate_us(); | ||||
|  | ||||
|             fillBitmapTo(bits, cursor, headerCursor, {true, false}); | ||||
|             write_sector_header(bits, | ||||
|                 cursor, | ||||
|                 sectorData->logicalTrack, | ||||
|                 sectorData->logicalSector); | ||||
|             write_sector_header( | ||||
|                 bits, cursor, sectorData->logicalTrack, sectorData->logicalSector); | ||||
|             fillBitmapTo(bits, cursor, dataCursor, {true, false}); | ||||
|             write_sector_data(bits, cursor, sectorData->data); | ||||
|  | ||||
|             sectorCount++; | ||||
| 			sectorCount++; | ||||
|         } | ||||
|  | ||||
|         if (cursor >= bits.size()) | ||||
|             error("track data overrun"); | ||||
|             Error() << "track data overrun"; | ||||
|         fillBitmapTo(bits, cursor, bits.size(), {true, false}); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| @@ -148,7 +147,8 @@ private: | ||||
|     const BrotherEncoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createBrotherEncoder(const EncoderProto& config) | ||||
| std::unique_ptr<Encoder> createBrotherEncoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new BrotherEncoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -76,3 +76,4 @@ GCR_ENTRY(0x6BAB, 74) | ||||
| GCR_ENTRY(0xAD5F, 75) | ||||
| GCR_ENTRY(0xDBED, 76) | ||||
| GCR_ENTRY(0x55BB, 77) | ||||
|  | ||||
|   | ||||
							
								
								
									
										43
									
								
								arch/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								arch/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| LIBARCH_SRCS = \ | ||||
| 	arch/aeslanier/decoder.cc \ | ||||
| 	arch/agat/agat.cc \ | ||||
| 	arch/agat/decoder.cc \ | ||||
| 	arch/agat/encoder.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/smaky6/decoder.cc \ | ||||
| 	arch/tids990/decoder.cc \ | ||||
| 	arch/tids990/encoder.cc \ | ||||
| 	arch/victor9k/decoder.cc \ | ||||
| 	arch/victor9k/encoder.cc \ | ||||
| 	arch/zilogmcz/decoder.cc \ | ||||
|  | ||||
| LIBARCH_OBJS = $(patsubst %.cc, $(OBJDIR)/%.o, $(LIBARCH_SRCS)) | ||||
| OBJS += $(LIBARCH_OBJS) | ||||
| $(LIBARCH_SRCS): | $(PROTO_HDRS) | ||||
| $(LIBARCH_SRCS): CFLAGS += $(PROTO_CFLAGS) | ||||
| LIBARCH_LIB = $(OBJDIR)/libarch.a | ||||
| $(LIBARCH_LIB): $(LIBARCH_OBJS) | ||||
|  | ||||
| LIBARCH_LDFLAGS = $(LIBARCH_LIB) | ||||
|  | ||||
| $(call use-pkgconfig, $(LIBARCH_LIB), $(LIBARCH_OBJS), fmt) | ||||
| @@ -1,26 +0,0 @@ | ||||
| from build.c import cxxlibrary | ||||
| from build.protobuf import proto, protocc | ||||
|  | ||||
| proto( | ||||
|     name="arch_proto", | ||||
|     srcs=[ | ||||
|         "./aeslanier/aeslanier.proto", | ||||
|         "./agat/agat.proto", | ||||
|         "./amiga/amiga.proto", | ||||
|         "./apple2/apple2.proto", | ||||
|         "./brother/brother.proto", | ||||
|         "./c64/c64.proto", | ||||
|         "./f85/f85.proto", | ||||
|         "./fb100/fb100.proto", | ||||
|         "./ibm/ibm.proto", | ||||
|         "./macintosh/macintosh.proto", | ||||
|         "./micropolis/micropolis.proto", | ||||
|         "./mx/mx.proto", | ||||
|         "./northstar/northstar.proto", | ||||
|         "./rolandd20/rolandd20.proto", | ||||
|         "./smaky6/smaky6.proto", | ||||
|         "./tids990/tids990.proto", | ||||
|         "./victor9k/victor9k.proto", | ||||
|         "./zilogmcz/zilogmcz.proto", | ||||
|     ], | ||||
| ) | ||||
| @@ -1,28 +1,28 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "globals.h" | ||||
| #include "c64.h" | ||||
|  | ||||
| /* | ||||
|  *   Track   Sectors/track   # Sectors   Storage in Bytes   Clock rate | ||||
|  *   -----   -------------   ---------   ----------------   ---------- | ||||
|  *    1-17        21            357           7820             3.25 | ||||
|  *   18-24        19            133           7170             3.5 | ||||
|  *   25-30        18            108           6300             3.75 | ||||
|  *   31-40(*)     17             85           6020             4 | ||||
|  *                              --- | ||||
|  *                              683 (for a 35 track image) | ||||
|  * | ||||
|  * The clock rate is normalised for a 200ms drive. | ||||
|  */ | ||||
|     *   Track   Sectors/track   # Sectors   Storage in Bytes   Clock rate | ||||
|     *   -----   -------------   ---------   ----------------   ---------- | ||||
|     *    1-17        21            357           7820             3.25 | ||||
|     *   18-24        19            133           7170             3.5 | ||||
|     *   25-30        18            108           6300             3.75 | ||||
|     *   31-40(*)     17             85           6020             4 | ||||
|     *                              --- | ||||
|     *                              683 (for a 35 track image) | ||||
|     *  | ||||
|     * The clock rate is normalised for a 200ms drive. | ||||
|     */ | ||||
|  | ||||
| nanoseconds_t clockPeriodForC64Track(unsigned track) | ||||
| { | ||||
|     constexpr double b = 8.0; | ||||
|     constexpr double BYTE_SIZE = 8.0; | ||||
|  | ||||
|     if (track < 17) | ||||
|         return 26.0 / b; | ||||
|         return 26.0 / BYTE_SIZE; | ||||
|     if (track < 24) | ||||
|         return 28.0 / b; | ||||
|         return 28.0 / BYTE_SIZE; | ||||
|     if (track < 30) | ||||
|         return 30.0 / b; | ||||
|     return 32.0 / b; | ||||
|         return 30.0 / BYTE_SIZE; | ||||
|     return 32.0 / BYTE_SIZE; | ||||
| } | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| #ifndef C64_H | ||||
| #define C64_H | ||||
|  | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
|  | ||||
| #define C64_SECTOR_RECORD 0xffd49 | ||||
| #define C64_DATA_RECORD 0xffd57 | ||||
| #define C64_SECTOR_LENGTH 256 | ||||
| #define C64_SECTOR_RECORD    0xffd49 | ||||
| #define C64_DATA_RECORD      0xffd57 | ||||
| #define C64_SECTOR_LENGTH    256 | ||||
|  | ||||
| /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html | ||||
| /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html  | ||||
|    1. Header sync       FF FF FF FF FF (40 'on' bits, not GCR) | ||||
|    2. Header info       52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes) | ||||
|    3. Header gap        55 55 55 55 55 55 55 55 55 (9 bytes, never read) | ||||
| @@ -17,20 +17,18 @@ | ||||
|    6. Inter-sector gap  55 55 55 55...55 55 (4 to 12 bytes, never read) | ||||
|    1. Header sync       (SYNC for the next sector) | ||||
| */ | ||||
| #define C64_HEADER_DATA_SYNC 0xFF | ||||
| #define C64_HEADER_BLOCK_ID 0x08 | ||||
| #define C64_DATA_BLOCK_ID 0x07 | ||||
| #define C64_HEADER_GAP 0x55 | ||||
| #define C64_INTER_SECTOR_GAP 0x55 | ||||
| #define C64_PADDING 0x0F | ||||
| #define C64_HEADER_DATA_SYNC        0xFF | ||||
| #define C64_HEADER_BLOCK_ID         0x08 | ||||
| #define C64_DATA_BLOCK_ID           0x07 | ||||
| #define C64_HEADER_GAP              0x55 | ||||
| #define C64_INTER_SECTOR_GAP        0x55 | ||||
| #define C64_PADDING                 0x0F | ||||
|  | ||||
| #define C64_TRACKS_PER_DISK 40 | ||||
| #define C64_BAM_TRACK 17 | ||||
| #define C64_TRACKS_PER_DISK         40 | ||||
| #define C64_BAM_TRACK               17 | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createCommodore64Decoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createCommodore64Encoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createCommodore64Decoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createCommodore64Encoder(const EncoderProto& config); | ||||
|  | ||||
| extern nanoseconds_t clockPeriodForC64Track(unsigned track); | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "c64.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
| @@ -96,7 +96,8 @@ public: | ||||
|     } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createCommodore64Decoder(const DecoderProto& config) | ||||
| std::unique_ptr<Decoder> createCommodore64Decoder( | ||||
|     const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new Commodore64Decoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "c64.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "sector.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "arch/c64/c64.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "lib/layout.h" | ||||
| #include <ctype.h> | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
| @@ -51,6 +51,26 @@ static void write_bits( | ||||
|     } | ||||
| } | ||||
|  | ||||
| void bindump(std::ostream& stream, std::vector<bool>& buffer) | ||||
| { | ||||
|     size_t pos = 0; | ||||
|  | ||||
|     while ((pos < buffer.size()) and (pos < 520)) | ||||
|     { | ||||
|         stream << fmt::format("{:5d} : ", pos); | ||||
|         for (int i = 0; i < 40; i++) | ||||
|         { | ||||
|             if ((pos + i) < buffer.size()) | ||||
|                 stream << fmt::format("{:01b}", (buffer[pos + i])); | ||||
|             else | ||||
|                 stream << "-- "; | ||||
|             if ((((pos + i + 1) % 8) == 0) and i != 0) | ||||
|                 stream << "  "; | ||||
|         } | ||||
|         stream << std::endl; | ||||
|         pos += 40; | ||||
|     } | ||||
| } | ||||
| static std::vector<bool> encode_data(uint8_t input) | ||||
| { | ||||
|     /* | ||||
| @@ -194,7 +214,8 @@ public: | ||||
|             writeSector(bits, cursor, sector); | ||||
|  | ||||
|         if (cursor >= bits.size()) | ||||
|             error("track data overrun by {} bits", cursor - bits.size()); | ||||
|             Error() << fmt::format( | ||||
|                 "track data overrun by {} bits", cursor - bits.size()); | ||||
|         fillBitmapTo(bits, cursor, bits.size(), {true, false}); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| @@ -222,7 +243,8 @@ private: | ||||
|         { | ||||
|             // There is data to encode to disk. | ||||
|             if ((sector->data.size() != C64_SECTOR_LENGTH)) | ||||
|                 error("unsupported sector size {} --- you must pick 256", | ||||
|                 Error() << fmt::format( | ||||
|                     "unsupported sector size {} --- you must pick 256", | ||||
|                     sector->data.size()); | ||||
|  | ||||
|             // 1. Write header Sync (not GCR) | ||||
|   | ||||
| @@ -1,30 +1,28 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "f85.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|  | ||||
| const FluxPattern SECTOR_RECORD_PATTERN(24, F85_SECTOR_RECORD); | ||||
| const FluxPattern DATA_RECORD_PATTERN(24, F85_DATA_RECORD); | ||||
| const FluxMatchers ANY_RECORD_PATTERN( | ||||
|     {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN}); | ||||
| const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN }); | ||||
|  | ||||
| static int decode_data_gcr(uint8_t gcr) | ||||
| { | ||||
|     switch (gcr) | ||||
|     { | ||||
| #define GCR_ENTRY(gcr, data) \ | ||||
|     case gcr:                \ | ||||
|         return data; | ||||
| #include "data_gcr.h" | ||||
| #undef GCR_ENTRY | ||||
| 		#define GCR_ENTRY(gcr, data) \ | ||||
| 			case gcr: return data; | ||||
| 		#include "data_gcr.h" | ||||
| 		#undef GCR_ENTRY | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
| @@ -39,11 +37,11 @@ static Bytes decode(const std::vector<bool>& bits) | ||||
|     while (ii != bits.end()) | ||||
|     { | ||||
|         uint8_t inputfifo = 0; | ||||
|         for (size_t i = 0; i < 5; i++) | ||||
|         for (size_t i=0; i<5; i++) | ||||
|         { | ||||
|             if (ii == bits.end()) | ||||
|                 break; | ||||
|             inputfifo = (inputfifo << 1) | *ii++; | ||||
|             inputfifo = (inputfifo<<1) | *ii++; | ||||
|         } | ||||
|  | ||||
|         bitw.push(decode_data_gcr(inputfifo), 4); | ||||
| @@ -56,55 +54,56 @@ static Bytes decode(const std::vector<bool>& bits) | ||||
| class DurangoF85Decoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     DurangoF85Decoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	DurangoF85Decoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(ANY_RECORD_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         /* Skip sync bits and ID byte. */ | ||||
| 	{ | ||||
| 		/* Skip sync bits and ID byte. */ | ||||
|  | ||||
|         if (readRaw24() != F85_SECTOR_RECORD) | ||||
|             return; | ||||
| 		if (readRaw24() != F85_SECTOR_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         /* Read header. */ | ||||
| 		/* Read header. */ | ||||
|  | ||||
|         const auto& bytes = decode(readRawBits(6 * 10)); | ||||
| 		const auto& bytes = decode(readRawBits(6*10)); | ||||
|  | ||||
|         _sector->logicalSector = bytes[2]; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalTrack = bytes[0]; | ||||
| 		_sector->logicalSector = bytes[2]; | ||||
| 		_sector->logicalSide = 0; | ||||
| 		_sector->logicalTrack = bytes[0]; | ||||
|  | ||||
|         uint16_t wantChecksum = bytes.reader().seek(4).read_be16(); | ||||
|         uint16_t gotChecksum = crc16(CCITT_POLY, 0xef21, bytes.slice(0, 4)); | ||||
|         if (wantChecksum == gotChecksum) | ||||
|             _sector->status = | ||||
|                 Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|     } | ||||
| 		uint16_t wantChecksum = bytes.reader().seek(4).read_be16(); | ||||
| 		uint16_t gotChecksum = crc16(CCITT_POLY, 0xef21, bytes.slice(0, 4)); | ||||
| 		if (wantChecksum == gotChecksum) | ||||
| 			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
| 	} | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         /* Skip sync bits ID byte. */ | ||||
| 	{ | ||||
| 		/* Skip sync bits ID byte. */ | ||||
|  | ||||
|         if (readRaw24() != F85_DATA_RECORD) | ||||
|             return; | ||||
| 		if (readRaw24() != F85_DATA_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         const auto& bytes = decode(readRawBits((F85_SECTOR_LENGTH + 3) * 10)) | ||||
|                                 .slice(0, F85_SECTOR_LENGTH + 3); | ||||
|         ByteReader br(bytes); | ||||
| 		const auto& bytes = decode(readRawBits((F85_SECTOR_LENGTH+3)*10)) | ||||
| 			.slice(0, F85_SECTOR_LENGTH+3); | ||||
| 		ByteReader br(bytes); | ||||
|  | ||||
|         _sector->data = br.read(F85_SECTOR_LENGTH); | ||||
|         uint16_t wantChecksum = br.read_be16(); | ||||
|         uint16_t gotChecksum = crc16(CCITT_POLY, 0xbf84, _sector->data); | ||||
|         _sector->status = | ||||
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = br.read(F85_SECTOR_LENGTH); | ||||
| 		uint16_t wantChecksum = br.read_be16(); | ||||
| 		uint16_t gotChecksum = crc16(CCITT_POLY, 0xbf84, _sector->data); | ||||
| 		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createDurangoF85Decoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new DurangoF85Decoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new DurangoF85Decoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -2,10 +2,9 @@ | ||||
| #define F85_H | ||||
|  | ||||
| #define F85_SECTOR_RECORD 0xffffce /* 1111 1111 1111 1111 1100 1110 */ | ||||
| #define F85_DATA_RECORD 0xffffcb   /* 1111 1111 1111 1111 1100 1101 */ | ||||
| #define F85_SECTOR_LENGTH 512 | ||||
| #define F85_DATA_RECORD 0xffffcb /* 1111 1111 1111 1111 1100 1101 */ | ||||
| #define F85_SECTOR_LENGTH    512 | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createDurangoF85Decoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createDurangoF85Decoder(const DecoderProto& config); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,23 +1,23 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "fb100.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/decoders/rawbits.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "decoders/rawbits.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|  | ||||
| const FluxPattern SECTOR_ID_PATTERN(16, 0xabaa); | ||||
|  | ||||
| /* | ||||
| /*  | ||||
|  * Reverse engineered from a dump of the floppy drive's ROM. I have no idea how | ||||
|  * it works. | ||||
|  * | ||||
|  *  | ||||
|  * LF8BA: | ||||
|  *         clra | ||||
|  *         staa    X00B0 | ||||
| @@ -100,43 +100,45 @@ static uint16_t checksum(const Bytes& bytes) | ||||
| class Fb100Decoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     Fb100Decoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	Fb100Decoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(SECTOR_ID_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(SECTOR_ID_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         auto rawbits = readRawBits(FB100_RECORD_SIZE * 16); | ||||
| 	{ | ||||
| 		auto rawbits = readRawBits(FB100_RECORD_SIZE*16); | ||||
|  | ||||
|         const Bytes bytes = decodeFmMfm(rawbits).slice(0, FB100_RECORD_SIZE); | ||||
|         ByteReader br(bytes); | ||||
|         br.seek(1); | ||||
|         const Bytes id = br.read(FB100_ID_SIZE); | ||||
|         uint16_t wantIdCrc = br.read_be16(); | ||||
|         uint16_t gotIdCrc = checksum(id); | ||||
|         const Bytes payload = br.read(FB100_PAYLOAD_SIZE); | ||||
|         uint16_t wantPayloadCrc = br.read_be16(); | ||||
|         uint16_t gotPayloadCrc = checksum(payload); | ||||
| 		const Bytes bytes = decodeFmMfm(rawbits).slice(0, FB100_RECORD_SIZE); | ||||
| 		ByteReader br(bytes); | ||||
| 		br.seek(1); | ||||
| 		const Bytes id = br.read(FB100_ID_SIZE); | ||||
| 		uint16_t wantIdCrc = br.read_be16(); | ||||
| 		uint16_t gotIdCrc = checksum(id); | ||||
| 		const Bytes payload = br.read(FB100_PAYLOAD_SIZE); | ||||
| 		uint16_t wantPayloadCrc = br.read_be16(); | ||||
| 		uint16_t gotPayloadCrc = checksum(payload); | ||||
|  | ||||
|         if (wantIdCrc != gotIdCrc) | ||||
|             return; | ||||
| 		if (wantIdCrc != gotIdCrc) | ||||
| 			return; | ||||
|  | ||||
|         uint8_t abssector = id[2]; | ||||
|         _sector->logicalTrack = abssector >> 1; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalSector = abssector & 1; | ||||
|         _sector->data.writer().append(id.slice(5, 12)).append(payload); | ||||
| 		uint8_t abssector = id[2]; | ||||
| 		_sector->logicalTrack = abssector >> 1; | ||||
| 		_sector->logicalSide = 0; | ||||
| 		_sector->logicalSector = abssector & 1; | ||||
| 		_sector->data.writer().append(id.slice(5, 12)).append(payload); | ||||
|  | ||||
|         _sector->status = (wantPayloadCrc == gotPayloadCrc) | ||||
|                               ? Sector::OK | ||||
|                               : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->status = (wantPayloadCrc == gotPayloadCrc) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createFb100Decoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new Fb100Decoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new Fb100Decoder(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -8,3 +8,4 @@ | ||||
| extern std::unique_ptr<Decoder> createFb100Decoder(const DecoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "ibm.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "arch/ibm/ibm.pb.h" | ||||
| #include "lib/proto.h" | ||||
| #include "proto.h" | ||||
| #include "lib/layout.h" | ||||
| #include <string.h> | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "ibm.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "arch/ibm/ibm.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "fmt/format.h" | ||||
| @@ -112,11 +112,10 @@ public: | ||||
|         const Image& image) override | ||||
|     { | ||||
|         IbmEncoderProto::TrackdataProto trackdata; | ||||
|         getEncoderTrackData( | ||||
|             trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|         getEncoderTrackData(trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|  | ||||
|         auto trackLayout = Layout::getLayoutOfTrack( | ||||
|             trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|         auto trackLayout = | ||||
|             Layout::getLayoutOfTrack(trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|  | ||||
|         auto writeBytes = [&](const Bytes& bytes) | ||||
|         { | ||||
| @@ -258,7 +257,7 @@ public: | ||||
|         } | ||||
|  | ||||
|         if (_cursor >= _bits.size()) | ||||
|             error("track data overrun"); | ||||
|             Error() << "track data overrun"; | ||||
|         while (_cursor < _bits.size()) | ||||
|             writeFillerRawBytes(1, gapFill); | ||||
|  | ||||
|   | ||||
| @@ -31,7 +31,9 @@ class Decoder; | ||||
| class DecoderProto; | ||||
| class EncoderProto; | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createIbmDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createIbmEncoder(const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createIbmDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createIbmEncoder( | ||||
|     const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,36 +1,33 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "macintosh.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|  | ||||
| const FluxPattern SECTOR_RECORD_PATTERN(24, MAC_SECTOR_RECORD); | ||||
| const FluxPattern DATA_RECORD_PATTERN(24, MAC_DATA_RECORD); | ||||
| const FluxMatchers ANY_RECORD_PATTERN( | ||||
|     {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN}); | ||||
| const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN }); | ||||
|  | ||||
| static int decode_data_gcr(uint8_t gcr) | ||||
| { | ||||
|     switch (gcr) | ||||
|     { | ||||
| #define GCR_ENTRY(gcr, data) \ | ||||
|     case gcr:                \ | ||||
|         return data; | ||||
| #include "data_gcr.h" | ||||
| #undef GCR_ENTRY | ||||
| 		#define GCR_ENTRY(gcr, data) \ | ||||
| 			case gcr: return data; | ||||
| 		#include "data_gcr.h" | ||||
| 		#undef GCR_ENTRY | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| /* This is extremely inspired by the MESS implementation, written by Nathan | ||||
|  * Woods and R. Belmont: | ||||
|  * https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp | ||||
| /* This is extremely inspired by the MESS implementation, written by Nathan Woods | ||||
|  * and R. Belmont: https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp | ||||
|  */ | ||||
| static Bytes decode_crazy_data(const Bytes& input, Sector::Status& status) | ||||
| { | ||||
| @@ -44,7 +41,7 @@ static Bytes decode_crazy_data(const Bytes& input, Sector::Status& status) | ||||
|     uint8_t b2[LOOKUP_LEN + 1]; | ||||
|     uint8_t b3[LOOKUP_LEN + 1]; | ||||
|  | ||||
|     for (int i = 0; i <= LOOKUP_LEN; i++) | ||||
|     for (int i=0; i<=LOOKUP_LEN; i++) | ||||
|     { | ||||
|         uint8_t w4 = br.read_8(); | ||||
|         uint8_t w1 = br.read_8(); | ||||
| @@ -128,68 +125,67 @@ uint8_t decode_side(uint8_t side) | ||||
| class MacintoshDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     MacintoshDecoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	MacintoshDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(ANY_RECORD_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         if (readRaw24() != MAC_SECTOR_RECORD) | ||||
|             return; | ||||
| 	{ | ||||
| 		if (readRaw24() != MAC_SECTOR_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         /* Read header. */ | ||||
| 		/* Read header. */ | ||||
|  | ||||
|         auto header = toBytes(readRawBits(7 * 8)).slice(0, 7); | ||||
| 		auto header = toBytes(readRawBits(7*8)).slice(0, 7); | ||||
| 					 | ||||
| 		uint8_t encodedTrack = decode_data_gcr(header[0]); | ||||
| 		if (encodedTrack != (_sector->physicalTrack & 0x3f)) | ||||
| 			return; | ||||
| 					 | ||||
| 		uint8_t encodedSector = decode_data_gcr(header[1]); | ||||
| 		uint8_t encodedSide = decode_data_gcr(header[2]); | ||||
| 		uint8_t formatByte = decode_data_gcr(header[3]); | ||||
| 		uint8_t wantedsum = decode_data_gcr(header[4]); | ||||
|  | ||||
|         uint8_t encodedTrack = decode_data_gcr(header[0]); | ||||
|         if (encodedTrack != (_sector->physicalTrack & 0x3f)) | ||||
|             return; | ||||
| 		if (encodedSector > 11) | ||||
| 			return; | ||||
|  | ||||
|         uint8_t encodedSector = decode_data_gcr(header[1]); | ||||
|         uint8_t encodedSide = decode_data_gcr(header[2]); | ||||
|         uint8_t formatByte = decode_data_gcr(header[3]); | ||||
|         uint8_t wantedsum = decode_data_gcr(header[4]); | ||||
|  | ||||
|         if (encodedSector > 11) | ||||
|             return; | ||||
|  | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
|         _sector->logicalSide = decode_side(encodedSide); | ||||
|         _sector->logicalSector = encodedSector; | ||||
|         uint8_t gotsum = | ||||
|             (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f; | ||||
|         if (wantedsum == gotsum) | ||||
|             _sector->status = | ||||
|                 Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|     } | ||||
| 		_sector->logicalTrack = _sector->physicalTrack; | ||||
| 		_sector->logicalSide = decode_side(encodedSide); | ||||
| 		_sector->logicalSector = encodedSector; | ||||
| 		uint8_t gotsum = (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f; | ||||
| 		if (wantedsum == gotsum) | ||||
| 			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
| 	} | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         if (readRaw24() != MAC_DATA_RECORD) | ||||
|             return; | ||||
| 	{ | ||||
| 		if (readRaw24() != MAC_DATA_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         /* Read data. */ | ||||
| 		/* Read data. */ | ||||
|  | ||||
|         readRawBits(8); /* skip spare byte */ | ||||
|         auto inputbuffer = toBytes(readRawBits(MAC_ENCODED_SECTOR_LENGTH * 8)) | ||||
|                                .slice(0, MAC_ENCODED_SECTOR_LENGTH); | ||||
| 		readRawBits(8); /* skip spare byte */ | ||||
| 		auto inputbuffer = toBytes(readRawBits(MAC_ENCODED_SECTOR_LENGTH*8)) | ||||
| 			.slice(0, MAC_ENCODED_SECTOR_LENGTH); | ||||
|  | ||||
|         for (unsigned i = 0; i < inputbuffer.size(); i++) | ||||
|             inputbuffer[i] = decode_data_gcr(inputbuffer[i]); | ||||
|  | ||||
|         _sector->status = Sector::BAD_CHECKSUM; | ||||
|         Bytes userData = decode_crazy_data(inputbuffer, _sector->status); | ||||
|         _sector->data.clear(); | ||||
|         _sector->data.writer() | ||||
|             .append(userData.slice(12, 512)) | ||||
|             .append(userData.slice(0, 12)); | ||||
|     } | ||||
| 		for (unsigned i=0; i<inputbuffer.size(); i++) | ||||
| 			inputbuffer[i] = decode_data_gcr(inputbuffer[i]); | ||||
| 			 | ||||
| 		_sector->status = Sector::BAD_CHECKSUM; | ||||
| 		Bytes userData = decode_crazy_data(inputbuffer, _sector->status); | ||||
| 		_sector->data.clear(); | ||||
| 		_sector->data.writer().append(userData.slice(12, 512)).append(userData.slice(0, 12)); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createMacintoshDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new MacintoshDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new MacintoshDecoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "macintosh.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "lib/layout.h" | ||||
| @@ -174,7 +174,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|     const std::shared_ptr<const Sector>& sector) | ||||
| { | ||||
|     if ((sector->data.size() != 512) && (sector->data.size() != 524)) | ||||
|         error("unsupported sector size --- you must pick 512 or 524"); | ||||
|         Error() << "unsupported sector size --- you must pick 512 or 524"; | ||||
|  | ||||
|     write_bits(bits, cursor, 0xff, 1 * 8); /* pad byte */ | ||||
|     for (int i = 0; i < 7; i++) | ||||
| @@ -239,12 +239,13 @@ public: | ||||
|             write_sector(bits, cursor, sector); | ||||
|  | ||||
|         if (cursor >= bits.size()) | ||||
|             error("track data overrun by {} bits", cursor - bits.size()); | ||||
|             Error() << fmt::format( | ||||
|                 "track data overrun by {} bits", cursor - bits.size()); | ||||
|         fillBitmapTo(bits, cursor, bits.size(), {true, false}); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
|         fluxmap->appendBits( | ||||
|             bits, calculatePhysicalClockPeriod(clockRateUs * 1e3, 200e6)); | ||||
|         fluxmap->appendBits(bits, | ||||
|             calculatePhysicalClockPeriod(clockRateUs * 1e3, 200e6)); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
| @@ -252,7 +253,8 @@ private: | ||||
|     const MacintoshEncoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createMacintoshEncoder(const EncoderProto& config) | ||||
| std::unique_ptr<Encoder> createMacintoshEncoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new MacintoshEncoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #ifndef MACINTOSH_H | ||||
| #define MACINTOSH_H | ||||
|  | ||||
| #define MAC_SECTOR_RECORD 0xd5aa96 /* 1101 0101 1010 1010 1001 0110 */ | ||||
| #define MAC_DATA_RECORD 0xd5aaad   /* 1101 0101 1010 1010 1010 1101 */ | ||||
| #define MAC_SECTOR_RECORD   0xd5aa96 /* 1101 0101 1010 1010 1001 0110 */ | ||||
| #define MAC_DATA_RECORD     0xd5aaad /* 1101 0101 1010 1010 1010 1101 */ | ||||
|  | ||||
| #define MAC_SECTOR_LENGTH 524 /* yes, really */ | ||||
| #define MAC_SECTOR_LENGTH   524 /* yes, really */ | ||||
| #define MAC_ENCODED_SECTOR_LENGTH 703 | ||||
| #define MAC_FORMAT_BYTE 0x22 | ||||
| #define MAC_FORMAT_BYTE     0x22 | ||||
|  | ||||
| #define MAC_TRACKS_PER_DISK 80 | ||||
|  | ||||
| @@ -15,9 +15,8 @@ class Decoder; | ||||
| class DecoderProto; | ||||
| class EncoderProto; | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createMacintoshDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createMacintoshEncoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createMacintoshDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createMacintoshEncoder(const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "micropolis.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
|  | ||||
| @@ -20,20 +20,17 @@ static const FluxPattern SECTOR_SYNC_PATTERN(64, 0xAAAAAAAAAAAA5555LL); | ||||
| static const FluxPattern SECTOR_ADVANCE_PATTERN(64, 0xAAAAAAAAAAAAAAAALL); | ||||
|  | ||||
| /* Standard Micropolis checksum.  Adds all bytes, with carry. */ | ||||
| uint8_t micropolisChecksum(const Bytes& bytes) | ||||
| { | ||||
|     ByteReader br(bytes); | ||||
|     uint16_t sum = 0; | ||||
|     while (!br.eof()) | ||||
|     { | ||||
|         if (sum > 0xFF) | ||||
|         { | ||||
|             sum -= 0x100 - 1; | ||||
|         } | ||||
|         sum += br.read_8(); | ||||
|     } | ||||
|     /* The last carry is ignored */ | ||||
|     return sum & 0xFF; | ||||
| uint8_t micropolisChecksum(const Bytes& bytes) { | ||||
| 	ByteReader br(bytes); | ||||
| 	uint16_t sum = 0; | ||||
| 	while (!br.eof()) { | ||||
| 		if (sum > 0xFF) { | ||||
| 			sum -= 0x100 - 1; | ||||
| 		} | ||||
| 		sum += br.read_8(); | ||||
| 	} | ||||
| 	/* The last carry is ignored */ | ||||
| 	return sum & 0xFF; | ||||
| } | ||||
|  | ||||
| /* Vector MZOS does not use the standard Micropolis checksum. | ||||
| @@ -44,251 +41,145 @@ uint8_t micropolisChecksum(const Bytes& bytes) | ||||
|  * Unlike the Micropolis checksum, this does not cover the 12-byte | ||||
|  * header (track, sector, 10 OS-specific bytes.) | ||||
|  */ | ||||
| uint8_t mzosChecksum(const Bytes& bytes) | ||||
| { | ||||
|     ByteReader br(bytes); | ||||
|     uint8_t checksum = 0; | ||||
|     uint8_t databyte; | ||||
| uint8_t mzosChecksum(const Bytes& bytes) { | ||||
| 	ByteReader br(bytes); | ||||
| 	uint8_t checksum = 0; | ||||
| 	uint8_t databyte; | ||||
|  | ||||
|     while (!br.eof()) | ||||
|     { | ||||
|         databyte = br.read_8(); | ||||
|         checksum ^= ((databyte << 1) | (databyte >> 7)); | ||||
|     } | ||||
| 	while (!br.eof()) { | ||||
| 		databyte = br.read_8(); | ||||
| 	checksum ^= ((databyte << 1) | (databyte >> 7)); | ||||
| 	} | ||||
|  | ||||
|     return checksum; | ||||
| } | ||||
|  | ||||
| static uint8_t b(uint32_t field, uint8_t pos) | ||||
| { | ||||
|     return (field >> pos) & 1; | ||||
| } | ||||
|  | ||||
| static uint8_t eccNextBit(uint32_t ecc, uint8_t data_bit) | ||||
| { | ||||
|     // This is 0x81932080 which is 0x0104C981 with reversed bits | ||||
|     return b(ecc, 7) ^ b(ecc, 13) ^ b(ecc, 16) ^ b(ecc, 17) ^ b(ecc, 20) ^ | ||||
|            b(ecc, 23) ^ b(ecc, 24) ^ b(ecc, 31) ^ data_bit; | ||||
| } | ||||
|  | ||||
| uint32_t vectorGraphicEcc(const Bytes& bytes) | ||||
| { | ||||
|     uint32_t e = 0; | ||||
|     Bytes payloadBytes = bytes.slice(0, bytes.size() - 4); | ||||
|     ByteReader payload(payloadBytes); | ||||
|     while (!payload.eof()) | ||||
|     { | ||||
|         uint8_t byte = payload.read_8(); | ||||
|         for (int i = 0; i < 8; i++) | ||||
|         { | ||||
|             e = (e << 1) | eccNextBit(e, byte >> 7); | ||||
|             byte <<= 1; | ||||
|         } | ||||
|     } | ||||
|     Bytes trailerBytes = bytes.slice(bytes.size() - 4); | ||||
|     ByteReader trailer(trailerBytes); | ||||
|     uint32_t res = e; | ||||
|     while (!trailer.eof()) | ||||
|     { | ||||
|         uint8_t byte = trailer.read_8(); | ||||
|         for (int i = 0; i < 8; i++) | ||||
|         { | ||||
|             res = (res << 1) | eccNextBit(e, byte >> 7); | ||||
|             e <<= 1; | ||||
|             byte <<= 1; | ||||
|         } | ||||
|     } | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| /* Fixes bytes when possible, returning true if changed. */ | ||||
| static bool vectorGraphicEccFix(Bytes& bytes, uint32_t syndrome) | ||||
| { | ||||
|     uint32_t ecc = syndrome; | ||||
|     int pos = (MICROPOLIS_ENCODED_SECTOR_SIZE - 5) * 8 + 7; | ||||
|     bool aligned = false; | ||||
|     while ((ecc & 0xff000000) == 0) | ||||
|     { | ||||
|         pos += 8; | ||||
|         ecc <<= 8; | ||||
|     } | ||||
|     for (; pos >= 0; pos--) | ||||
|     { | ||||
|         bool bit = ecc & 1; | ||||
|         ecc >>= 1; | ||||
|         if (bit) | ||||
|             ecc ^= 0x808264c0; | ||||
|         if ((ecc & 0xff07ffff) == 0) | ||||
|             aligned = true; | ||||
|         if (aligned && pos % 8 == 0) | ||||
|             break; | ||||
|     } | ||||
|     if (pos < 0) | ||||
|         return false; | ||||
|     bytes[pos / 8] ^= ecc >> 16; | ||||
|     return true; | ||||
| 	return checksum; | ||||
| } | ||||
|  | ||||
| class MicropolisDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     MicropolisDecoder(const DecoderProto& config): | ||||
|         Decoder(config), | ||||
|         _config(config.micropolis()) | ||||
|     { | ||||
|         _checksumType = _config.checksum_type(); | ||||
|     } | ||||
| 	MicropolisDecoder(const DecoderProto& config): | ||||
| 		Decoder(config), | ||||
| 		_config(config.micropolis()) | ||||
| 	{ | ||||
| 		_checksumType = _config.checksum_type(); | ||||
| 	} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         nanoseconds_t now = tell().ns(); | ||||
| 	nanoseconds_t advanceToNextRecord() override | ||||
| 	{ | ||||
| 		nanoseconds_t now = tell().ns(); | ||||
|  | ||||
|         /* For all but the first sector, seek to the next sector pulse. | ||||
|          * The first sector does not contain the sector pulse in the fluxmap. | ||||
|          */ | ||||
|         if (now != 0) | ||||
|         { | ||||
|             seekToIndexMark(); | ||||
|             now = tell().ns(); | ||||
|         } | ||||
| 		/* For all but the first sector, seek to the next sector pulse. | ||||
| 		 * The first sector does not contain the sector pulse in the fluxmap. | ||||
| 		 */ | ||||
| 		if (now != 0) { | ||||
| 			seekToIndexMark(); | ||||
| 			now = tell().ns(); | ||||
| 		} | ||||
|  | ||||
|         /* Discard a possible partial sector at the end of the track. | ||||
|          * This partial sector could be mistaken for a conflicted sector, if | ||||
|          * whatever data read happens to match the checksum of 0, which is | ||||
|          * rare, but has been observed on some disks. There's 570uS of slack in | ||||
|          * each sector, after accounting for preamble, data, and postamble. | ||||
|          */ | ||||
|         if (now > (getFluxmapDuration() - 12.0e6)) | ||||
|         { | ||||
|             seekToIndexMark(); | ||||
|             return 0; | ||||
|         } | ||||
| 		/* Discard a possible partial sector at the end of the track. | ||||
| 		 * This partial sector could be mistaken for a conflicted sector, if | ||||
| 		 * whatever data read happens to match the checksum of 0, which is | ||||
| 		 * rare, but has been observed on some disks. | ||||
| 		 */ | ||||
| 		if (now > (getFluxmapDuration() - 12.5e6)) { | ||||
| 			seekToIndexMark(); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
|         nanoseconds_t clock = seekToPattern(SECTOR_SYNC_PATTERN); | ||||
| 		nanoseconds_t clock = seekToPattern(SECTOR_SYNC_PATTERN); | ||||
|  | ||||
|         auto syncDelta = tell().ns() - now; | ||||
|         /* Due to the weak nature of the Micropolis SYNC patern, | ||||
|          * it's possible to detect a false SYNC during the gap | ||||
|          * between the sector pulse and the write gate.  If the SYNC | ||||
|          * is detected less than 100uS after the sector pulse, search | ||||
|          * for another valid SYNC. | ||||
|          * | ||||
|          * Reference: Vector Micropolis Disk Controller Board Technical | ||||
|          * Information Manual, pp. 1-16. | ||||
|          */ | ||||
|         if ((syncDelta > 0) && (syncDelta < 100e3)) | ||||
|         { | ||||
|             seekToPattern(SECTOR_ADVANCE_PATTERN); | ||||
|             clock = seekToPattern(SECTOR_SYNC_PATTERN); | ||||
|         } | ||||
| 		auto syncDelta = tell().ns() - now; | ||||
| 		/* Due to the weak nature of the Micropolis SYNC patern, | ||||
| 		 * it's possible to detect a false SYNC during the gap | ||||
| 		 * between the sector pulse and the write gate.  If the SYNC | ||||
| 		 * is detected less than 100uS after the sector pulse, search | ||||
| 		 * for another valid SYNC. | ||||
| 		 * | ||||
| 		 * Reference: Vector Micropolis Disk Controller Board Technical | ||||
| 		 * Information Manual, pp. 1-16. | ||||
| 		 */ | ||||
| 		if ((syncDelta > 0) && (syncDelta < 100e3)) { | ||||
| 			seekToPattern(SECTOR_ADVANCE_PATTERN); | ||||
| 			clock = seekToPattern(SECTOR_SYNC_PATTERN); | ||||
| 		} | ||||
|  | ||||
|         _sector->headerStartTime = tell().ns(); | ||||
| 		_sector->headerStartTime = tell().ns(); | ||||
|  | ||||
|         /* seekToPattern() can skip past the index hole, if this happens | ||||
|          * too close to the end of the Fluxmap, discard the sector. The | ||||
|          * preamble was expected to be 640uS long. | ||||
|          */ | ||||
|         if (_sector->headerStartTime > (getFluxmapDuration() - 11.3e6)) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
| 		/* seekToPattern() can skip past the index hole, if this happens | ||||
| 		 * too close to the end of the Fluxmap, discard the sector. | ||||
| 		 */ | ||||
| 		if (_sector->headerStartTime > (getFluxmapDuration() - 12.5e6)) { | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
|         return clock; | ||||
|     } | ||||
| 		return clock; | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         readRawBits(48); | ||||
|         auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE * 16); | ||||
|         auto bytes = | ||||
|             decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE); | ||||
| 	void decodeSectorRecord() override | ||||
| 	{ | ||||
| 		readRawBits(48); | ||||
| 		auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE*16); | ||||
| 		auto bytes = decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE); | ||||
| 		ByteReader br(bytes); | ||||
|  | ||||
|         bool eccPresent = bytes[274] == 0xaa; | ||||
|         uint32_t ecc = 0; | ||||
|         if (_config.ecc_type() == MicropolisDecoderProto::VECTOR && eccPresent) | ||||
|         { | ||||
|             ecc = vectorGraphicEcc(bytes.slice(0, 274)); | ||||
|             if (ecc != 0) | ||||
|             { | ||||
|                 vectorGraphicEccFix(bytes, ecc); | ||||
|                 ecc = vectorGraphicEcc(bytes.slice(0, 274)); | ||||
|             } | ||||
|         } | ||||
| 		int syncByte = br.read_8();  /* sync */ | ||||
| 		if (syncByte != 0xFF) | ||||
| 			return; | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
| 		_sector->logicalTrack = br.read_8(); | ||||
| 		_sector->logicalSide = _sector->physicalSide; | ||||
| 		_sector->logicalSector = br.read_8(); | ||||
| 		if (_sector->logicalSector > 15) | ||||
| 			return; | ||||
| 		if (_sector->logicalTrack > 76) | ||||
| 			return; | ||||
| 		if (_sector->logicalTrack != _sector->physicalTrack) | ||||
| 			return; | ||||
|  | ||||
|         int syncByte = br.read_8(); /* sync */ | ||||
|         if (syncByte != 0xFF) | ||||
|             return; | ||||
| 		br.read(10);  /* OS data or padding */ | ||||
| 		auto data = br.read(MICROPOLIS_PAYLOAD_SIZE); | ||||
| 		uint8_t wantChecksum = br.read_8(); | ||||
|  | ||||
|         _sector->logicalTrack = br.read_8(); | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         if (_sector->logicalSector > 15) | ||||
|             return; | ||||
|         if (_sector->logicalTrack > 76) | ||||
|             return; | ||||
|         if (_sector->logicalTrack != _sector->physicalTrack) | ||||
|             return; | ||||
| 		/* If not specified, automatically determine the checksum type. | ||||
| 		* Once the checksum type is determined, it will be used for the | ||||
| 		* entire disk. | ||||
| 		*/ | ||||
| 		if (_checksumType == MicropolisDecoderProto::AUTO) { | ||||
| 			/* Calculate both standard Micropolis (MDOS, CP/M, OASIS) and MZOS checksums */ | ||||
| 			if (wantChecksum == micropolisChecksum(bytes.slice(1, 2+266))) { | ||||
| 				_checksumType = MicropolisDecoderProto::MICROPOLIS; | ||||
| 			} else if (wantChecksum == mzosChecksum(bytes.slice(MICROPOLIS_HEADER_SIZE, MICROPOLIS_PAYLOAD_SIZE))) { | ||||
| 				_checksumType = MicropolisDecoderProto::MZOS; | ||||
| 				std::cout << "Note: MZOS checksum detected." << std::endl; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         br.read(10); /* OS data or padding */ | ||||
|         auto data = br.read(MICROPOLIS_PAYLOAD_SIZE); | ||||
|         uint8_t wantChecksum = br.read_8(); | ||||
| 		uint8_t gotChecksum; | ||||
|  | ||||
|         /* If not specified, automatically determine the checksum type. | ||||
|          * Once the checksum type is determined, it will be used for the | ||||
|          * entire disk. | ||||
|          */ | ||||
|         if (_checksumType == MicropolisDecoderProto::AUTO) | ||||
|         { | ||||
|             /* Calculate both standard Micropolis (MDOS, CP/M, OASIS) and MZOS | ||||
|              * checksums */ | ||||
|             if (wantChecksum == micropolisChecksum(bytes.slice(1, 2 + 266))) | ||||
|             { | ||||
|                 _checksumType = MicropolisDecoderProto::MICROPOLIS; | ||||
|             } | ||||
|             else if (wantChecksum == | ||||
|                      mzosChecksum(bytes.slice( | ||||
|                          MICROPOLIS_HEADER_SIZE, MICROPOLIS_PAYLOAD_SIZE))) | ||||
|             { | ||||
|                 _checksumType = MicropolisDecoderProto::MZOS; | ||||
|                 std::cout << "Note: MZOS checksum detected." << std::endl; | ||||
|             } | ||||
|         } | ||||
| 		if (_checksumType == MicropolisDecoderProto::MZOS) { | ||||
| 			gotChecksum = mzosChecksum(bytes.slice(MICROPOLIS_HEADER_SIZE, MICROPOLIS_PAYLOAD_SIZE)); | ||||
| 		} else { | ||||
| 			gotChecksum = micropolisChecksum(bytes.slice(1, 2+266)); | ||||
| 		} | ||||
|  | ||||
|         uint8_t gotChecksum; | ||||
| 		br.read(5);  /* 4 byte ECC and ECC-present flag */ | ||||
|  | ||||
|         if (_checksumType == MicropolisDecoderProto::MZOS) | ||||
|         { | ||||
|             gotChecksum = mzosChecksum( | ||||
|                 bytes.slice(MICROPOLIS_HEADER_SIZE, MICROPOLIS_PAYLOAD_SIZE)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             gotChecksum = micropolisChecksum(bytes.slice(1, 2 + 266)); | ||||
|         } | ||||
|  | ||||
|         br.read(5); /* 4 byte ECC and ECC-present flag */ | ||||
|  | ||||
|         if (_config.sector_output_size() == MICROPOLIS_PAYLOAD_SIZE) | ||||
|             _sector->data = data; | ||||
|         else if (_config.sector_output_size() == MICROPOLIS_ENCODED_SECTOR_SIZE) | ||||
|             _sector->data = bytes; | ||||
|         else | ||||
|             error("Sector output size may only be 256 or 275"); | ||||
|         if (wantChecksum == gotChecksum && (!eccPresent || ecc == 0)) | ||||
|             _sector->status = Sector::OK; | ||||
|         else | ||||
|             _sector->status = Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		if (_config.sector_output_size() == MICROPOLIS_PAYLOAD_SIZE) | ||||
| 			_sector->data = data; | ||||
| 		else if (_config.sector_output_size() == MICROPOLIS_ENCODED_SECTOR_SIZE) | ||||
| 			_sector->data = bytes; | ||||
| 		else | ||||
| 			Error() << "Sector output size may only be 256 or 275"; | ||||
| 		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
|  | ||||
| private: | ||||
|     const MicropolisDecoderProto& _config; | ||||
|     MicropolisDecoderProto_ChecksumType | ||||
|         _checksumType; /* -1 = auto, 1 = Micropolis, 2=MZOS */ | ||||
| 	const MicropolisDecoderProto& _config; | ||||
| 	MicropolisDecoderProto_ChecksumType _checksumType;	/* -1 = auto, 1 = Micropolis, 2=MZOS */ | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createMicropolisDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new MicropolisDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new MicropolisDecoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,19 +1,18 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "globals.h" | ||||
| #include "micropolis.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "lib/image.h" | ||||
| #include "sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "image.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
| static void write_sector(std::vector<bool>& bits, | ||||
|     unsigned& cursor, | ||||
|     const std::shared_ptr<const Sector>& sector, | ||||
|     MicropolisEncoderProto::EccType eccType) | ||||
|     const std::shared_ptr<const Sector>& sector) | ||||
| { | ||||
|     if ((sector->data.size() != 256) && | ||||
|         (sector->data.size() != MICROPOLIS_ENCODED_SECTOR_SIZE)) | ||||
|         error("unsupported sector size --- you must pick 256 or 275"); | ||||
|         Error() << "unsupported sector size --- you must pick 256 or 275"; | ||||
|  | ||||
|     int fullSectorSize = 40 + MICROPOLIS_ENCODED_SECTOR_SIZE + 40 + 35; | ||||
|     auto fullSector = std::make_shared<std::vector<uint8_t>>(); | ||||
| @@ -25,9 +24,8 @@ static void write_sector(std::vector<bool>& bits, | ||||
|     if (sector->data.size() == MICROPOLIS_ENCODED_SECTOR_SIZE) | ||||
|     { | ||||
|         if (sector->data[0] != 0xFF) | ||||
|             error( | ||||
|                 "275 byte sector doesn't start with sync byte 0xFF. " | ||||
|                 "Corrupted sector"); | ||||
|             Error() << "275 byte sector doesn't start with sync byte 0xFF. " | ||||
|                        "Corrupted sector"; | ||||
|         uint8_t wantChecksum = sector->data[1 + 2 + 266]; | ||||
|         uint8_t gotChecksum = | ||||
|             micropolisChecksum(sector->data.slice(1, 2 + 266)); | ||||
| @@ -46,16 +44,8 @@ static void write_sector(std::vector<bool>& bits, | ||||
|             writer.write_8(0); /* Padding */ | ||||
|         writer += sector->data; | ||||
|         writer.write_8(micropolisChecksum(sectorData.slice(1))); | ||||
|  | ||||
|         uint8_t eccPresent = 0; | ||||
|         uint32_t ecc = 0; | ||||
|         if (eccType == MicropolisEncoderProto::VECTOR) | ||||
|         { | ||||
|             eccPresent = 0xaa; | ||||
|             ecc = vectorGraphicEcc(sectorData + Bytes(4)); | ||||
|         } | ||||
|         writer.write_be32(ecc); | ||||
|         writer.write_8(eccPresent); | ||||
|         for (int i = 0; i < 5; i++) | ||||
|             writer.write_8(0); /* 4 byte ECC and ECC not present flag */ | ||||
|     } | ||||
|     for (uint8_t b : sectorData) | ||||
|         fullSector->push_back(b); | ||||
| @@ -67,7 +57,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|         fullSector->push_back(0); | ||||
|  | ||||
|     if (fullSector->size() != fullSectorSize) | ||||
|         error("sector mismatched length"); | ||||
|         Error() << "sector mismatched length"; | ||||
|     bool lastBit = false; | ||||
|     encodeMfm(bits, cursor, fullSector, lastBit); | ||||
|     /* filler */ | ||||
| @@ -95,34 +85,19 @@ public: | ||||
|             (_config.rotational_period_ms() * 1e3) / _config.clock_period_us(); | ||||
|  | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
|         std::vector<unsigned> indexes; | ||||
|         unsigned prev_cursor = 0; | ||||
|         unsigned cursor = 0; | ||||
|  | ||||
|         for (const auto& sectorData : sectors) | ||||
|         { | ||||
|             indexes.push_back(cursor); | ||||
|             prev_cursor = cursor; | ||||
|             write_sector(bits, cursor, sectorData, _config.ecc_type()); | ||||
|         } | ||||
|         indexes.push_back(prev_cursor + (cursor - prev_cursor) / 2); | ||||
|         indexes.push_back(cursor); | ||||
|             write_sector(bits, cursor, sectorData); | ||||
|  | ||||
|         if (cursor != bits.size()) | ||||
|             error("track data mismatched length"); | ||||
|             Error() << "track data mismatched length"; | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
|         nanoseconds_t clockPeriod = | ||||
|             calculatePhysicalClockPeriod(_config.clock_period_us() * 1e3, | ||||
|                 _config.rotational_period_ms() * 1e6); | ||||
|         auto pos = bits.begin(); | ||||
|         for (int i = 1; i < indexes.size(); i++) | ||||
|         { | ||||
|             auto end = bits.begin() + indexes[i]; | ||||
|             fluxmap->appendBits(std::vector<bool>(pos, end), clockPeriod); | ||||
|             fluxmap->appendIndex(); | ||||
|             pos = end; | ||||
|         } | ||||
|         fluxmap->appendBits(bits, | ||||
|             calculatePhysicalClockPeriod( | ||||
|                 _config.clock_period_us() * 1e3, | ||||
|                 _config.rotational_period_ms() * 1e6)); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
| @@ -130,7 +105,8 @@ private: | ||||
|     const MicropolisEncoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createMicropolisEncoder(const EncoderProto& config) | ||||
| std::unique_ptr<Encoder> createMicropolisEncoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new MicropolisEncoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -1,22 +1,18 @@ | ||||
| #ifndef MICROPOLIS_H | ||||
| #define MICROPOLIS_H | ||||
|  | ||||
| #define MICROPOLIS_PAYLOAD_SIZE (256) | ||||
| #define MICROPOLIS_HEADER_SIZE (1 + 2 + 10) | ||||
| #define MICROPOLIS_ENCODED_SECTOR_SIZE \ | ||||
|     (MICROPOLIS_HEADER_SIZE + MICROPOLIS_PAYLOAD_SIZE + 6) | ||||
| #define MICROPOLIS_PAYLOAD_SIZE         (256) | ||||
| #define MICROPOLIS_HEADER_SIZE          (1+2+10) | ||||
| #define MICROPOLIS_ENCODED_SECTOR_SIZE  (MICROPOLIS_HEADER_SIZE + MICROPOLIS_PAYLOAD_SIZE + 6) | ||||
|  | ||||
| class Decoder; | ||||
| class Encoder; | ||||
| class EncoderProto; | ||||
| class DecoderProto; | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createMicropolisDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createMicropolisEncoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createMicropolisDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createMicropolisEncoder(const EncoderProto& config); | ||||
|  | ||||
| extern uint8_t micropolisChecksum(const Bytes& bytes); | ||||
| extern uint32_t vectorGraphicEcc(const Bytes& bytes); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -8,30 +8,17 @@ message MicropolisDecoderProto { | ||||
| 		MICROPOLIS = 1; | ||||
| 		MZOS = 2; | ||||
| 	} | ||||
| 	enum EccType { | ||||
| 		NONE = 0; | ||||
| 		VECTOR = 1; | ||||
| 	} | ||||
|  | ||||
| 	optional int32 sector_output_size = 1 [default = 256, | ||||
| 		(help) = "How much of the raw sector should be saved. Must be 256 or 275"]; | ||||
| 	optional ChecksumType checksum_type = 2 [default = AUTO, | ||||
| 		(help) = "Checksum type to use: AUTO, MICROPOLIS, MZOS"]; | ||||
| 	optional EccType ecc_type = 3 [default = NONE, | ||||
| 		(help) = "ECC type to use: NONE, VECTOR"]; | ||||
| } | ||||
|  | ||||
| message MicropolisEncoderProto { | ||||
|     enum EccType { | ||||
|         NONE = 0; | ||||
|         VECTOR = 1; | ||||
|     } | ||||
|  | ||||
|     optional double clock_period_us = 1 | ||||
|         [ default = 2.0, (help) = "clock rate on the real device" ]; | ||||
|     optional double rotational_period_ms = 2 | ||||
|         [ default = 200.0, (help) = "rotational period on the real device" ]; | ||||
|     optional EccType ecc_type = 3 [default = NONE, | ||||
|         (help) = "ECC type to use for IMG data: NONE, VECTOR"]; | ||||
|         [ default = 166.0, (help) = "rotational period on the real device" ]; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "arch/mx/mx.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "mx/mx.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include <string.h> | ||||
|  | ||||
| const int SECTOR_SIZE = 256; | ||||
| @@ -26,51 +26,52 @@ const FluxPattern ID_PATTERN(32, 0xaaaaffaf); | ||||
| class MxDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     MxDecoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	MxDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     void beginTrack() override | ||||
|     { | ||||
|         _clock = _sector->clock = seekToPattern(ID_PATTERN); | ||||
|         _currentSector = 0; | ||||
|     } | ||||
| 	{ | ||||
| 		_clock = _sector->clock = seekToPattern(ID_PATTERN); | ||||
| 		_currentSector = 0; | ||||
| 	} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         if (_currentSector == 11) | ||||
|         { | ||||
|             /* That was the last sector on the disk. */ | ||||
|             return 0; | ||||
|         } | ||||
|         else | ||||
|             return _clock; | ||||
|     } | ||||
| 	{ | ||||
| 		if (_currentSector == 11) | ||||
| 		{ | ||||
| 			/* That was the last sector on the disk. */ | ||||
| 			return 0; | ||||
| 		} | ||||
| 		else | ||||
| 			return _clock; | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         /* Skip the ID pattern and track word, which is only present on the | ||||
|          * first sector. We don't trust the track word because some driver | ||||
|          * don't write it correctly. */ | ||||
| 	{ | ||||
| 		/* Skip the ID pattern and track word, which is only present on the | ||||
| 		 * first sector. We don't trust the track word because some driver | ||||
| 		 * don't write it correctly. */ | ||||
|  | ||||
|         if (_currentSector == 0) | ||||
|             readRawBits(64); | ||||
| 		if (_currentSector == 0) | ||||
| 			readRawBits(64); | ||||
|  | ||||
|         auto bits = readRawBits((SECTOR_SIZE + 2) * 16); | ||||
|         auto bytes = decodeFmMfm(bits).slice(0, SECTOR_SIZE + 2); | ||||
| 		auto bits = readRawBits((SECTOR_SIZE+2)*16); | ||||
| 		auto bytes = decodeFmMfm(bits).slice(0, SECTOR_SIZE+2); | ||||
|  | ||||
|         uint16_t gotChecksum = 0; | ||||
|         ByteReader br(bytes); | ||||
|         for (int i = 0; i < (SECTOR_SIZE / 2); i++) | ||||
|             gotChecksum += br.read_be16(); | ||||
|         uint16_t wantChecksum = br.read_be16(); | ||||
| 		uint16_t gotChecksum = 0; | ||||
| 		ByteReader br(bytes); | ||||
| 		for (int i=0; i<(SECTOR_SIZE/2); i++) | ||||
| 			gotChecksum += br.read_be16(); | ||||
| 		uint16_t wantChecksum = br.read_be16(); | ||||
|  | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalSector = _currentSector; | ||||
|         _sector->data = bytes.slice(0, SECTOR_SIZE).swab(); | ||||
|         _sector->status = | ||||
|             (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|         _currentSector++; | ||||
|     } | ||||
| 		_sector->logicalTrack = _sector->physicalTrack; | ||||
| 		_sector->logicalSide = _sector->physicalSide; | ||||
| 		_sector->logicalSector = _currentSector; | ||||
| 		_sector->data = bytes.slice(0, SECTOR_SIZE).swab(); | ||||
| 		_sector->status = (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 		_currentSector++; | ||||
| 	} | ||||
|  | ||||
| private: | ||||
|     nanoseconds_t _clock; | ||||
| @@ -79,5 +80,7 @@ private: | ||||
|  | ||||
| std::unique_ptr<Decoder> createMxDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new MxDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new MxDecoder(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #ifndef MX_H | ||||
| #define MX_H | ||||
|  | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "decoders/decoders.h" | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createMxDecoder(const DecoderProto& config); | ||||
|  | ||||
|   | ||||
| @@ -11,18 +11,18 @@ | ||||
|  * sure that the hardSectorId is correct. | ||||
|  */ | ||||
|  | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "northstar.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| #define MFM_ID 0xaaaaaaaaaaaa5545LL | ||||
| #define FM_ID 0xaaaaaaaaaaaaffefLL | ||||
| #define FM_ID  0xaaaaaaaaaaaaffefLL | ||||
| /* | ||||
|  * MFM sectors have 32 bytes of 00's followed by two sync characters, | ||||
|  * specified in the North Star MDS manual as 0xFBFB. | ||||
| @@ -44,143 +44,133 @@ static const FluxPattern MFM_PATTERN(64, MFM_ID); | ||||
|  */ | ||||
| static const FluxPattern FM_PATTERN(64, FM_ID); | ||||
|  | ||||
| const FluxMatchers ANY_SECTOR_PATTERN({ | ||||
|     &MFM_PATTERN, | ||||
|     &FM_PATTERN, | ||||
| }); | ||||
| const FluxMatchers ANY_SECTOR_PATTERN( | ||||
| 	{ | ||||
| 		&MFM_PATTERN, | ||||
| 		&FM_PATTERN, | ||||
| 	} | ||||
| ); | ||||
|  | ||||
| /* Checksum is initially 0. | ||||
|  * For each data byte, XOR with the current checksum. | ||||
|  * Rotate checksum left, carrying bit 7 to bit 0. | ||||
|  */ | ||||
| uint8_t northstarChecksum(const Bytes& bytes) | ||||
| { | ||||
|     ByteReader br(bytes); | ||||
|     uint8_t checksum = 0; | ||||
| uint8_t northstarChecksum(const Bytes& bytes) { | ||||
| 	ByteReader br(bytes); | ||||
| 	uint8_t checksum = 0; | ||||
|  | ||||
|     while (!br.eof()) | ||||
|     { | ||||
|         checksum ^= br.read_8(); | ||||
|         checksum = ((checksum << 1) | ((checksum >> 7))); | ||||
|     } | ||||
| 	while (!br.eof()) { | ||||
| 		checksum ^= br.read_8(); | ||||
| 		checksum = ((checksum << 1) | ((checksum >> 7))); | ||||
| 	} | ||||
|  | ||||
|     return checksum; | ||||
| 	return checksum; | ||||
| } | ||||
|  | ||||
| class NorthstarDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     NorthstarDecoder(const DecoderProto& config): | ||||
|         Decoder(config), | ||||
|         _config(config.northstar()) | ||||
|     { | ||||
|     } | ||||
| 	NorthstarDecoder(const DecoderProto& config): | ||||
| 		Decoder(config), | ||||
| 		_config(config.northstar()) | ||||
| 	{} | ||||
|  | ||||
|     /* Search for FM or MFM sector record */ | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         nanoseconds_t now = tell().ns(); | ||||
| 	/* Search for FM or MFM sector record */ | ||||
| 	nanoseconds_t advanceToNextRecord() override | ||||
| 	{ | ||||
| 		nanoseconds_t now = tell().ns(); | ||||
|  | ||||
|         /* For all but the first sector, seek to the next sector pulse. | ||||
|          * The first sector does not contain the sector pulse in the fluxmap. | ||||
|          */ | ||||
|         if (now != 0) | ||||
|         { | ||||
|             seekToIndexMark(); | ||||
|             now = tell().ns(); | ||||
|         } | ||||
| 		/* For all but the first sector, seek to the next sector pulse. | ||||
| 		 * The first sector does not contain the sector pulse in the fluxmap. | ||||
| 		 */ | ||||
| 		if (now != 0) { | ||||
| 			seekToIndexMark(); | ||||
| 			now = tell().ns(); | ||||
| 		} | ||||
|  | ||||
|         /* Discard a possible partial sector at the end of the track. | ||||
|          * This partial sector could be mistaken for a conflicted sector, if | ||||
|          * whatever data read happens to match the checksum of 0, which is | ||||
|          * rare, but has been observed on some disks. | ||||
|          */ | ||||
|         if (now > (getFluxmapDuration() - 21e6)) | ||||
|         { | ||||
|             seekToIndexMark(); | ||||
|             return 0; | ||||
|         } | ||||
| 		/* Discard a possible partial sector at the end of the track. | ||||
| 		 * This partial sector could be mistaken for a conflicted sector, if | ||||
| 		 * whatever data read happens to match the checksum of 0, which is | ||||
| 		 * rare, but has been observed on some disks. | ||||
| 		 */ | ||||
| 		if (now > (getFluxmapDuration() - 21e6)) { | ||||
| 			seekToIndexMark(); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
|         int msSinceIndex = std::round(now / 1e6); | ||||
| 		int msSinceIndex = std::round(now / 1e6); | ||||
|  | ||||
|         /* Note that the seekToPattern ignores the sector pulses, so if | ||||
|          * a sector is not found for some reason, the seek will advance | ||||
|          * past one or more sector pulses.  For this reason, calculate | ||||
|          * _hardSectorId after the sector header is found. | ||||
|          */ | ||||
|         nanoseconds_t clock = seekToPattern(ANY_SECTOR_PATTERN); | ||||
|         _sector->headerStartTime = tell().ns(); | ||||
| 		/* Note that the seekToPattern ignores the sector pulses, so if | ||||
| 		 * a sector is not found for some reason, the seek will advance | ||||
| 		 * past one or more sector pulses.  For this reason, calculate | ||||
| 		 * _hardSectorId after the sector header is found. | ||||
| 		 */ | ||||
| 		nanoseconds_t clock = seekToPattern(ANY_SECTOR_PATTERN); | ||||
| 		_sector->headerStartTime = tell().ns(); | ||||
|  | ||||
|         /* Discard a possible partial sector. */ | ||||
|         if (_sector->headerStartTime > (getFluxmapDuration() - 21e6)) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
| 		/* Discard a possible partial sector. */ | ||||
| 		if (_sector->headerStartTime > (getFluxmapDuration() - 21e6)) { | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
|         int sectorFoundTimeRaw = std::round(_sector->headerStartTime / 1e6); | ||||
|         int sectorFoundTime; | ||||
| 		int sectorFoundTimeRaw = std::round(_sector->headerStartTime / 1e6); | ||||
| 		int sectorFoundTime; | ||||
|  | ||||
|         /* Round time to the nearest 20ms */ | ||||
|         if ((sectorFoundTimeRaw % 20) < 10) | ||||
|         { | ||||
|             sectorFoundTime = (sectorFoundTimeRaw / 20) * 20; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             sectorFoundTime = ((sectorFoundTimeRaw + 20) / 20) * 20; | ||||
|         } | ||||
| 		/* Round time to the nearest 20ms */ | ||||
| 		if ((sectorFoundTimeRaw % 20) < 10) { | ||||
| 			sectorFoundTime = (sectorFoundTimeRaw / 20) * 20; | ||||
| 		} | ||||
| 		else { | ||||
| 			sectorFoundTime = ((sectorFoundTimeRaw + 20) / 20) * 20; | ||||
| 		} | ||||
|  | ||||
|         /* Calculate the sector ID based on time since the index */ | ||||
|         _hardSectorId = (sectorFoundTime / 20) % 10; | ||||
| 		/* Calculate the sector ID based on time since the index */ | ||||
| 		_hardSectorId = (sectorFoundTime / 20) % 10; | ||||
|  | ||||
|         return clock; | ||||
|     } | ||||
| 		return clock; | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         uint64_t id = toBytes(readRawBits(64)).reader().read_be64(); | ||||
|         unsigned recordSize, payloadSize, headerSize; | ||||
| 	void decodeSectorRecord() override | ||||
| 	{ | ||||
| 		uint64_t id = toBytes(readRawBits(64)).reader().read_be64(); | ||||
| 		unsigned recordSize, payloadSize, headerSize; | ||||
|  | ||||
|         if (id == MFM_ID) | ||||
|         { | ||||
|             recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_DD; | ||||
|             payloadSize = NORTHSTAR_PAYLOAD_SIZE_DD; | ||||
|             headerSize = NORTHSTAR_HEADER_SIZE_DD; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_SD; | ||||
|             payloadSize = NORTHSTAR_PAYLOAD_SIZE_SD; | ||||
|             headerSize = NORTHSTAR_HEADER_SIZE_SD; | ||||
|         } | ||||
| 		if (id == MFM_ID) { | ||||
| 			recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_DD; | ||||
| 			payloadSize = NORTHSTAR_PAYLOAD_SIZE_DD; | ||||
| 			headerSize = NORTHSTAR_HEADER_SIZE_DD; | ||||
| 		} | ||||
| 		else { | ||||
| 			recordSize = NORTHSTAR_ENCODED_SECTOR_SIZE_SD; | ||||
| 			payloadSize = NORTHSTAR_PAYLOAD_SIZE_SD; | ||||
| 			headerSize = NORTHSTAR_HEADER_SIZE_SD; | ||||
| 		} | ||||
|  | ||||
|         auto rawbits = readRawBits(recordSize * 16); | ||||
|         auto bytes = decodeFmMfm(rawbits).slice(0, recordSize); | ||||
|         ByteReader br(bytes); | ||||
| 		auto rawbits = readRawBits(recordSize * 16); | ||||
| 		auto bytes = decodeFmMfm(rawbits).slice(0, recordSize); | ||||
| 		ByteReader br(bytes); | ||||
|  | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalSector = _hardSectorId; | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
| 		_sector->logicalSide = _sector->physicalSide; | ||||
| 		_sector->logicalSector = _hardSectorId; | ||||
| 		_sector->logicalTrack = _sector->physicalTrack; | ||||
|  | ||||
|         if (headerSize == NORTHSTAR_HEADER_SIZE_DD) | ||||
|         { | ||||
|             br.read_8(); /* MFM second Sync char, usually 0xFB */ | ||||
|         } | ||||
| 		if (headerSize == NORTHSTAR_HEADER_SIZE_DD) { | ||||
| 			br.read_8();	/* MFM second Sync char, usually 0xFB */ | ||||
| 		} | ||||
|  | ||||
|         _sector->data = br.read(payloadSize); | ||||
|         uint8_t wantChecksum = br.read_8(); | ||||
|         uint8_t gotChecksum = | ||||
|             northstarChecksum(bytes.slice(headerSize - 1, payloadSize)); | ||||
|         _sector->status = | ||||
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = br.read(payloadSize); | ||||
| 		uint8_t wantChecksum = br.read_8(); | ||||
| 		uint8_t gotChecksum = northstarChecksum(bytes.slice(headerSize - 1, payloadSize)); | ||||
| 		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
|  | ||||
| private: | ||||
|     const NorthstarDecoderProto& _config; | ||||
|     uint8_t _hardSectorId; | ||||
| 	const NorthstarDecoderProto& _config; | ||||
| 	uint8_t _hardSectorId; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createNorthstarDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new NorthstarDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new NorthstarDecoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "globals.h" | ||||
| #include "northstar.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "lib/image.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "image.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
| #define GAP_FILL_SIZE_SD 30 | ||||
| @@ -49,7 +49,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|             doubleDensity = true; | ||||
|             break; | ||||
|         default: | ||||
|             error("unsupported sector size --- you must pick 256 or 512"); | ||||
|             Error() << "unsupported sector size --- you must pick 256 or 512"; | ||||
|             break; | ||||
|     } | ||||
|  | ||||
| @@ -96,10 +96,9 @@ static void write_sector(std::vector<bool>& bits, | ||||
|             fullSector->push_back(GAP2_FILL_BYTE); | ||||
|  | ||||
|         if (fullSector->size() != fullSectorSize) | ||||
|             error("sector mismatched length ({}); expected {}, got {}", | ||||
|                 sector->data.size(), | ||||
|                 fullSector->size(), | ||||
|                 fullSectorSize); | ||||
|             Error() << "sector mismatched length (" << sector->data.size() | ||||
|                     << ") expected: " << fullSector->size() << " got " | ||||
|                     << fullSectorSize; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| @@ -149,7 +148,7 @@ public: | ||||
|             write_sector(bits, cursor, sectorData); | ||||
|  | ||||
|         if (cursor > bits.size()) | ||||
|             error("track data overrun"); | ||||
|             Error() << "track data overrun"; | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
|         fluxmap->appendBits(bits, | ||||
| @@ -162,7 +161,8 @@ private: | ||||
|     const NorthstarEncoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createNorthstarEncoder(const EncoderProto& config) | ||||
| std::unique_ptr<Encoder> createNorthstarEncoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new NorthstarEncoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| #ifndef NORTHSTAR_H | ||||
| #define NORTHSTAR_H | ||||
|  | ||||
| /* Northstar floppies are 10-hard sectored disks with a sector format as | ||||
|  * follows: | ||||
| /* Northstar floppies are 10-hard sectored disks with a sector format as follows: | ||||
|  * | ||||
|  * |----------------------------------| | ||||
|  * | SYNC Byte  | Payload  | Checksum | | ||||
| @@ -13,19 +12,15 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #define NORTHSTAR_PREAMBLE_SIZE_SD (16) | ||||
| #define NORTHSTAR_PREAMBLE_SIZE_DD (32) | ||||
| #define NORTHSTAR_HEADER_SIZE_SD (1) | ||||
| #define NORTHSTAR_HEADER_SIZE_DD (2) | ||||
| #define NORTHSTAR_PAYLOAD_SIZE_SD (256) | ||||
| #define NORTHSTAR_PAYLOAD_SIZE_DD (512) | ||||
| #define NORTHSTAR_CHECKSUM_SIZE (1) | ||||
| #define NORTHSTAR_ENCODED_SECTOR_SIZE_SD                    \ | ||||
|     (NORTHSTAR_HEADER_SIZE_SD + NORTHSTAR_PAYLOAD_SIZE_SD + \ | ||||
|         NORTHSTAR_CHECKSUM_SIZE) | ||||
| #define NORTHSTAR_ENCODED_SECTOR_SIZE_DD                    \ | ||||
|     (NORTHSTAR_HEADER_SIZE_DD + NORTHSTAR_PAYLOAD_SIZE_DD + \ | ||||
|         NORTHSTAR_CHECKSUM_SIZE) | ||||
| #define NORTHSTAR_PREAMBLE_SIZE_SD		(16) | ||||
| #define NORTHSTAR_PREAMBLE_SIZE_DD		(32) | ||||
| #define NORTHSTAR_HEADER_SIZE_SD		(1) | ||||
| #define NORTHSTAR_HEADER_SIZE_DD		(2) | ||||
| #define NORTHSTAR_PAYLOAD_SIZE_SD		(256) | ||||
| #define NORTHSTAR_PAYLOAD_SIZE_DD		(512) | ||||
| #define NORTHSTAR_CHECKSUM_SIZE		(1) | ||||
| #define NORTHSTAR_ENCODED_SECTOR_SIZE_SD	(NORTHSTAR_HEADER_SIZE_SD + NORTHSTAR_PAYLOAD_SIZE_SD + NORTHSTAR_CHECKSUM_SIZE) | ||||
| #define NORTHSTAR_ENCODED_SECTOR_SIZE_DD	(NORTHSTAR_HEADER_SIZE_DD + NORTHSTAR_PAYLOAD_SIZE_DD + NORTHSTAR_CHECKSUM_SIZE) | ||||
|  | ||||
| class Decoder; | ||||
| class Encoder; | ||||
| @@ -34,9 +29,7 @@ class DecoderProto; | ||||
|  | ||||
| extern uint8_t northstarChecksum(const Bytes& bytes); | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createNorthstarDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createNorthstarEncoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createNorthstarDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createNorthstarEncoder(const EncoderProto& config); | ||||
|  | ||||
| #endif /* NORTHSTAR */ | ||||
|   | ||||
| @@ -1,51 +0,0 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "rolandd20.h" | ||||
| #include <string.h> | ||||
|  | ||||
| /* Sector header record: | ||||
|  * | ||||
|  * BF FF FF FF FF FF FE AB | ||||
|  * | ||||
|  * This encodes to: | ||||
|  * | ||||
|  *    e    d    5    5    5    5    5    5 | ||||
|  * 1110 1101 0101 0101 0101 0101 0101 0101 | ||||
|  *    5    5    5    5    5    5    5    5 | ||||
|  * 0101 0101 0101 0101 0101 0101 0101 0101 | ||||
|  *    5    5    5    5    5    5    5    5 | ||||
|  * 0101 0101 0101 0101 0101 0101 0101 0101 | ||||
|  *    5    5    5    4    4    4    4    5 | ||||
|  * 0101 0101 0101 0100 0100 0100 0100 0101 | ||||
|  */ | ||||
|  | ||||
| static const FluxPattern SECTOR_PATTERN(64, 0xed55555555555555LL); | ||||
|  | ||||
| class RolandD20Decoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     RolandD20Decoder(const DecoderProto& config): Decoder(config) {} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(SECTOR_PATTERN); | ||||
|     } | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         auto rawbits = readRawBits(256); | ||||
|         const auto& bytes = decodeFmMfm(rawbits); | ||||
|         fmt::print("{} ", _sector->clock); | ||||
|         hexdump(std::cout, bytes); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createRolandD20Decoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new RolandD20Decoder(config)); | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createRolandD20Decoder( | ||||
|     const DecoderProto& config); | ||||
| @@ -1,5 +0,0 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| message RolandD20DecoderProto {} | ||||
|  | ||||
|  | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "smaky6.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "bytes.h" | ||||
| #include "crc.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include <string.h> | ||||
|   | ||||
| @@ -7,3 +7,4 @@ | ||||
| extern std::unique_ptr<Decoder> createSmaky6Decoder(const DecoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "arch/tids990/tids990.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "tids990/tids990.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include <string.h> | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| @@ -38,63 +38,61 @@ const FluxPattern SECTOR_RECORD_PATTERN(32, 0x11112244); | ||||
| const uint16_t DATA_ID = 0x550b; | ||||
| const FluxPattern DATA_RECORD_PATTERN(32, 0x11112245); | ||||
|  | ||||
| const FluxMatchers ANY_RECORD_PATTERN( | ||||
|     {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN}); | ||||
| const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN }); | ||||
|  | ||||
| class Tids990Decoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     Tids990Decoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	Tids990Decoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(ANY_RECORD_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         auto bits = readRawBits(TIDS990_SECTOR_RECORD_SIZE * 16); | ||||
|         auto bytes = decodeFmMfm(bits).slice(0, TIDS990_SECTOR_RECORD_SIZE); | ||||
| 	{ | ||||
| 		auto bits = readRawBits(TIDS990_SECTOR_RECORD_SIZE*16); | ||||
| 		auto bytes = decodeFmMfm(bits).slice(0, TIDS990_SECTOR_RECORD_SIZE); | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
|         if (br.read_be16() != SECTOR_ID) | ||||
|             return; | ||||
| 		ByteReader br(bytes); | ||||
| 		if (br.read_be16() != SECTOR_ID) | ||||
| 			return; | ||||
|  | ||||
|         uint16_t gotChecksum = | ||||
|             crc16(CCITT_POLY, bytes.slice(1, TIDS990_SECTOR_RECORD_SIZE - 3)); | ||||
| 		uint16_t gotChecksum = crc16(CCITT_POLY, bytes.slice(1, TIDS990_SECTOR_RECORD_SIZE-3)); | ||||
|  | ||||
|         _sector->logicalSide = br.read_8() >> 3; | ||||
|         _sector->logicalTrack = br.read_8(); | ||||
|         br.read_8(); /* number of sectors per track */ | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         br.read_be16(); /* sector size */ | ||||
|         uint16_t wantChecksum = br.read_be16(); | ||||
| 		_sector->logicalSide = br.read_8() >> 3; | ||||
| 		_sector->logicalTrack = br.read_8(); | ||||
| 		br.read_8(); /* number of sectors per track */ | ||||
| 		_sector->logicalSector = br.read_8(); | ||||
| 		br.read_be16(); /* sector size */ | ||||
| 		uint16_t wantChecksum = br.read_be16(); | ||||
|  | ||||
|         if (wantChecksum == gotChecksum) | ||||
|             _sector->status = | ||||
|                 Sector::DATA_MISSING; /* correct but unintuitive */ | ||||
|     } | ||||
| 		if (wantChecksum == gotChecksum) | ||||
| 			_sector->status = Sector::DATA_MISSING; /* correct but unintuitive */ | ||||
| 	} | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         auto bits = readRawBits(TIDS990_DATA_RECORD_SIZE * 16); | ||||
|         auto bytes = decodeFmMfm(bits).slice(0, TIDS990_DATA_RECORD_SIZE); | ||||
| 	void decodeDataRecord() override | ||||
| 	{ | ||||
| 		auto bits = readRawBits(TIDS990_DATA_RECORD_SIZE*16); | ||||
| 		auto bytes = decodeFmMfm(bits).slice(0, TIDS990_DATA_RECORD_SIZE); | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
|         if (br.read_be16() != DATA_ID) | ||||
|             return; | ||||
| 		ByteReader br(bytes); | ||||
| 		if (br.read_be16() != DATA_ID) | ||||
| 			return; | ||||
|  | ||||
|         uint16_t gotChecksum = | ||||
|             crc16(CCITT_POLY, bytes.slice(1, TIDS990_DATA_RECORD_SIZE - 3)); | ||||
| 		uint16_t gotChecksum = crc16(CCITT_POLY, bytes.slice(1, TIDS990_DATA_RECORD_SIZE-3)); | ||||
|  | ||||
|         _sector->data = br.read(TIDS990_PAYLOAD_SIZE); | ||||
|         uint16_t wantChecksum = br.read_be16(); | ||||
|         _sector->status = | ||||
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = br.read(TIDS990_PAYLOAD_SIZE); | ||||
| 		uint16_t wantChecksum = br.read_be16(); | ||||
| 		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createTids990Decoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new Tids990Decoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new Tids990Decoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "tids990.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "arch/tids990/tids990.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include <fmt/format.h> | ||||
| @@ -127,14 +127,14 @@ public: | ||||
|         } | ||||
|  | ||||
|         if (_cursor >= _bits.size()) | ||||
|             error("track data overrun"); | ||||
|             Error() << "track data overrun"; | ||||
|         while (_cursor < _bits.size()) | ||||
|             writeBytes(1, 0x55); | ||||
|  | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
|         fluxmap->appendBits(_bits, | ||||
|             calculatePhysicalClockPeriod( | ||||
|                 clockRateUs * 1e3, _config.rotational_period_ms() * 1e6)); | ||||
|             calculatePhysicalClockPeriod(clockRateUs * 1e3, | ||||
|                 _config.rotational_period_ms() * 1e6)); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
| @@ -145,7 +145,8 @@ private: | ||||
|     bool _lastBit; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createTids990Encoder(const EncoderProto& config) | ||||
| std::unique_ptr<Encoder> createTids990Encoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new Tids990Encoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| #ifndef TIDS990_H | ||||
| #define TIDS990_H | ||||
|  | ||||
| #define TIDS990_PAYLOAD_SIZE 288                            /* bytes */ | ||||
| #define TIDS990_SECTOR_RECORD_SIZE 10                       /* bytes */ | ||||
| #define TIDS990_DATA_RECORD_SIZE (TIDS990_PAYLOAD_SIZE + 4) /* bytes */ | ||||
| #define TIDS990_PAYLOAD_SIZE       288 /* bytes */ | ||||
| #define TIDS990_SECTOR_RECORD_SIZE 10 /* bytes */ | ||||
| #define TIDS990_DATA_RECORD_SIZE   (TIDS990_PAYLOAD_SIZE + 4) /* bytes */ | ||||
|  | ||||
| class Encoder; | ||||
| class Decoder; | ||||
| class DecoderProto; | ||||
| class EncoderProto; | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createTids990Decoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createTids990Encoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createTids990Decoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createTids990Encoder(const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,30 +1,28 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "victor9k.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|  | ||||
| const FluxPattern SECTOR_RECORD_PATTERN(32, VICTOR9K_SECTOR_RECORD); | ||||
| const FluxPattern DATA_RECORD_PATTERN(32, VICTOR9K_DATA_RECORD); | ||||
| const FluxMatchers ANY_RECORD_PATTERN( | ||||
|     {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN}); | ||||
| const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN }); | ||||
|  | ||||
| static int decode_data_gcr(uint8_t gcr) | ||||
| { | ||||
|     switch (gcr) | ||||
|     { | ||||
| #define GCR_ENTRY(gcr, data) \ | ||||
|     case gcr:                \ | ||||
|         return data; | ||||
| #include "data_gcr.h" | ||||
| #undef GCR_ENTRY | ||||
| 		#define GCR_ENTRY(gcr, data) \ | ||||
| 			case gcr: return data; | ||||
| 		#include "data_gcr.h" | ||||
| 		#undef GCR_ENTRY | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
| @@ -39,11 +37,11 @@ static Bytes decode(const std::vector<bool>& bits) | ||||
|     while (ii != bits.end()) | ||||
|     { | ||||
|         uint8_t inputfifo = 0; | ||||
|         for (size_t i = 0; i < 5; i++) | ||||
|         for (size_t i=0; i<5; i++) | ||||
|         { | ||||
|             if (ii == bits.end()) | ||||
|                 break; | ||||
|             inputfifo = (inputfifo << 1) | *ii++; | ||||
|             inputfifo = (inputfifo<<1) | *ii++; | ||||
|         } | ||||
|  | ||||
|         uint8_t decoded = decode_data_gcr(inputfifo); | ||||
| @@ -57,62 +55,63 @@ static Bytes decode(const std::vector<bool>& bits) | ||||
| class Victor9kDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     Victor9kDecoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	Victor9kDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		return seekToPattern(ANY_RECORD_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         /* Check the ID. */ | ||||
| 	{ | ||||
| 		/* Check the ID. */ | ||||
|  | ||||
|         if (readRaw32() != VICTOR9K_SECTOR_RECORD) | ||||
|             return; | ||||
| 		if (readRaw32() != VICTOR9K_SECTOR_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         /* Read header. */ | ||||
| 		/* Read header. */ | ||||
|  | ||||
|         auto bytes = decode(readRawBits(3 * 10)).slice(0, 3); | ||||
| 		auto bytes = decode(readRawBits(3*10)).slice(0, 3); | ||||
|  | ||||
|         uint8_t rawTrack = bytes[0]; | ||||
|         _sector->logicalSector = bytes[1]; | ||||
|         uint8_t gotChecksum = bytes[2]; | ||||
| 		uint8_t rawTrack = bytes[0]; | ||||
| 		_sector->logicalSector = bytes[1]; | ||||
| 		uint8_t gotChecksum = bytes[2]; | ||||
|  | ||||
|         _sector->logicalTrack = rawTrack & 0x7f; | ||||
|         _sector->logicalSide = rawTrack >> 7; | ||||
|         uint8_t wantChecksum = bytes[0] + bytes[1]; | ||||
|         if ((_sector->logicalSector > 20) || (_sector->logicalTrack > 85) || | ||||
|             (_sector->logicalSide > 1)) | ||||
|             return; | ||||
|  | ||||
|         if (wantChecksum == gotChecksum) | ||||
|             _sector->status = | ||||
|                 Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|     } | ||||
| 		_sector->logicalTrack = rawTrack & 0x7f; | ||||
| 		_sector->logicalSide = rawTrack >> 7; | ||||
| 		uint8_t wantChecksum = bytes[0] + bytes[1]; | ||||
| 		if ((_sector->logicalSector > 20) || (_sector->logicalTrack > 85) || (_sector->logicalSide > 1)) | ||||
| 			return; | ||||
| 					 | ||||
| 		if (wantChecksum == gotChecksum) | ||||
| 			_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
| 	} | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         /* Check the ID. */ | ||||
| 	{ | ||||
| 		/* Check the ID. */ | ||||
|  | ||||
|         if (readRaw32() != VICTOR9K_DATA_RECORD) | ||||
|             return; | ||||
| 		if (readRaw32() != VICTOR9K_DATA_RECORD) | ||||
| 			return; | ||||
|  | ||||
|         /* Read data. */ | ||||
| 		/* Read data. */ | ||||
|  | ||||
|         auto bytes = decode(readRawBits((VICTOR9K_SECTOR_LENGTH + 4) * 10)) | ||||
|                          .slice(0, VICTOR9K_SECTOR_LENGTH + 4); | ||||
|         ByteReader br(bytes); | ||||
| 		auto bytes = decode(readRawBits((VICTOR9K_SECTOR_LENGTH+4)*10)) | ||||
| 			.slice(0, VICTOR9K_SECTOR_LENGTH+4); | ||||
| 		ByteReader br(bytes); | ||||
|  | ||||
|         _sector->data = br.read(VICTOR9K_SECTOR_LENGTH); | ||||
|         uint16_t gotChecksum = sumBytes(_sector->data); | ||||
|         uint16_t wantChecksum = br.read_le16(); | ||||
|         _sector->status = | ||||
|             (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->data = br.read(VICTOR9K_SECTOR_LENGTH); | ||||
| 		uint16_t gotChecksum = sumBytes(_sector->data); | ||||
| 		uint16_t wantChecksum = br.read_le16(); | ||||
| 		_sector->status = (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createVictor9kDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new Victor9kDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new Victor9kDecoder(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "victor9k.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "crc.h" | ||||
| #include "sector.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "arch/victor9k/victor9k.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "lib/layout.h" | ||||
| #include <ctype.h> | ||||
| #include "lib/bytes.h" | ||||
| #include "bytes.h" | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
| @@ -169,15 +169,14 @@ public: | ||||
|         const Image& image) override | ||||
|     { | ||||
|         Victor9kEncoderProto::TrackdataProto trackdata; | ||||
|         getTrackFormat( | ||||
|             trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|         getTrackFormat(trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|  | ||||
|         unsigned bitsPerRevolution = (trackdata.rotational_period_ms() * 1e3) / | ||||
|                                      trackdata.clock_period_us(); | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
|         nanoseconds_t clockPeriod = | ||||
|             calculatePhysicalClockPeriod(trackdata.clock_period_us() * 1e3, | ||||
|                 trackdata.rotational_period_ms() * 1e6); | ||||
|         nanoseconds_t clockPeriod = calculatePhysicalClockPeriod( | ||||
|             trackdata.clock_period_us() * 1e3, | ||||
|             trackdata.rotational_period_ms() * 1e6); | ||||
|         unsigned cursor = 0; | ||||
|  | ||||
|         fillBitmapTo(bits, | ||||
| @@ -190,7 +189,8 @@ public: | ||||
|             write_sector(bits, cursor, trackdata, *sector); | ||||
|  | ||||
|         if (cursor >= bits.size()) | ||||
|             error("track data overrun by {} bits", cursor - bits.size()); | ||||
|             Error() << fmt::format( | ||||
|                 "track data overrun by {} bits", cursor - bits.size()); | ||||
|         fillBitmapTo(bits, cursor, bits.size(), {true, false}); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| @@ -202,7 +202,8 @@ private: | ||||
|     const Victor9kEncoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createVictor9kEncoder(const EncoderProto& config) | ||||
| std::unique_ptr<Encoder> createVictor9kEncoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new Victor9kEncoder(config)); | ||||
| } | ||||
|   | ||||
| @@ -13,14 +13,12 @@ class DecoderProto; | ||||
|  | ||||
| /* ... 1101 0100 1001 | ||||
|  *       ^^ ^^^^ ^^^^ ten bit IO byte */ | ||||
| #define VICTOR9K_DATA_RECORD 0xfffffd49 | ||||
| #define VICTOR9K_DATA_RECORD   0xfffffd49 | ||||
| #define VICTOR9K_DATA_ID 0x8 | ||||
|  | ||||
| #define VICTOR9K_SECTOR_LENGTH 512 | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createVictor9kDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createVictor9kEncoder( | ||||
|     const EncoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createVictor9kDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createVictor9kEncoder(const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "zilogmcz.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "bytes.h" | ||||
| #include "crc.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
| @@ -16,40 +16,42 @@ static const FluxPattern SECTOR_START_PATTERN(16, 0xaaab); | ||||
| class ZilogMczDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     ZilogMczDecoder(const DecoderProto& config): Decoder(config) {} | ||||
| 	ZilogMczDecoder(const DecoderProto& config): | ||||
| 		Decoder(config) | ||||
| 	{} | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         seekToIndexMark(); | ||||
|         return seekToPattern(SECTOR_START_PATTERN); | ||||
|     } | ||||
| 	{ | ||||
| 		seekToIndexMark(); | ||||
| 		return seekToPattern(SECTOR_START_PATTERN); | ||||
| 	} | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         readRawBits(14); | ||||
| 	{ | ||||
| 		readRawBits(14); | ||||
|  | ||||
|         auto rawbits = readRawBits(140 * 16); | ||||
|         auto bytes = decodeFmMfm(rawbits).slice(0, 140); | ||||
|         ByteReader br(bytes); | ||||
| 		auto rawbits = readRawBits(140*16); | ||||
| 		auto bytes = decodeFmMfm(rawbits).slice(0, 140); | ||||
| 		ByteReader br(bytes); | ||||
|  | ||||
|         _sector->logicalSector = br.read_8() & 0x1f; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalTrack = br.read_8() & 0x7f; | ||||
|         if (_sector->logicalSector > 31) | ||||
|             return; | ||||
|         if (_sector->logicalTrack > 80) | ||||
|             return; | ||||
| 		_sector->logicalSector = br.read_8() & 0x1f; | ||||
| 		_sector->logicalSide = 0; | ||||
| 		_sector->logicalTrack = br.read_8() & 0x7f; | ||||
| 		if (_sector->logicalSector > 31) | ||||
| 			return; | ||||
| 		if (_sector->logicalTrack > 80) | ||||
| 			return; | ||||
|  | ||||
|         _sector->data = br.read(132); | ||||
|         uint16_t wantChecksum = br.read_be16(); | ||||
|         uint16_t gotChecksum = crc16(MODBUS_POLY, 0x0000, bytes.slice(0, 134)); | ||||
| 		_sector->data = br.read(132); | ||||
| 		uint16_t wantChecksum = br.read_be16(); | ||||
| 		uint16_t gotChecksum = crc16(MODBUS_POLY, 0x0000, bytes.slice(0, 134)); | ||||
|  | ||||
|         _sector->status = | ||||
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
| 		_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createZilogMczDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new ZilogMczDecoder(config)); | ||||
| 	return std::unique_ptr<Decoder>(new ZilogMczDecoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| #ifndef ZILOGMCZ_H | ||||
| #define ZILOGMCZ_H | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createZilogMczDecoder( | ||||
|     const DecoderProto& config); | ||||
| extern std::unique_ptr<Decoder> createZilogMczDecoder(const DecoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										192
									
								
								build.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								build.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| 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/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/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" | ||||
|  | ||||
							
								
								
									
										314
									
								
								build.py
									
									
									
									
									
								
							
							
						
						
									
										314
									
								
								build.py
									
									
									
									
									
								
							| @@ -1,314 +0,0 @@ | ||||
| from build.ab import export | ||||
| from build.c import clibrary, cxxlibrary | ||||
| from build.protobuf import proto, protocc | ||||
| from build.pkg import package | ||||
| from build.utils import test | ||||
| from glob import glob | ||||
| import config | ||||
| import re | ||||
|  | ||||
| package(name="protobuf_lib", package="protobuf") | ||||
| package(name="z_lib", package="zlib") | ||||
| package(name="fmt_lib", package="fmt") | ||||
| package(name="sqlite3_lib", package="sqlite3") | ||||
|  | ||||
| clibrary(name="protocol", hdrs={"protocol.h": "./protocol.h"}) | ||||
|  | ||||
| proto(name="fl2_proto", srcs=["lib/fl2.proto"]) | ||||
| protocc(name="fl2_proto_lib", srcs=["+fl2_proto"]) | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="lib", | ||||
|     srcs=[ | ||||
|         "./lib/bitmap.cc", | ||||
|         "./lib/bytes.cc", | ||||
|         "./lib/config.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/fl2.cc", | ||||
|         "./lib/flags.cc", | ||||
|         "./lib/fluxmap.cc", | ||||
|         "./lib/fluxsink/a2rfluxsink.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/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", | ||||
|         "./lib/fluxsource/flx.cc", | ||||
|         "./lib/fluxsource/flxfluxsource.cc", | ||||
|         "./lib/fluxsource/hardwarefluxsource.cc", | ||||
|         "./lib/fluxsource/kryoflux.cc", | ||||
|         "./lib/fluxsource/kryofluxfluxsource.cc", | ||||
|         "./lib/fluxsource/memoryfluxsource.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/imdimagewriter.cc", | ||||
|         "./lib/imagewriter/imgimagewriter.cc", | ||||
|         "./lib/imagewriter/ldbsimagewriter.cc", | ||||
|         "./lib/imagewriter/nsiimagewriter.cc", | ||||
|         "./lib/imagewriter/rawimagewriter.cc", | ||||
|         "./lib/layout.cc", | ||||
|         "./lib/ldbs.cc", | ||||
|         "./lib/logger.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", | ||||
|         "./lib/vfs/acorndfs.cc", | ||||
|         "./lib/vfs/amigaffs.cc", | ||||
|         "./lib/vfs/appledos.cc", | ||||
|         "./lib/vfs/applesingle.cc", | ||||
|         "./lib/vfs/brother120fs.cc", | ||||
|         "./lib/vfs/cbmfs.cc", | ||||
|         "./lib/vfs/cpmfs.cc", | ||||
|         "./lib/vfs/fatfs.cc", | ||||
|         "./lib/vfs/fluxsectorinterface.cc", | ||||
|         "./lib/vfs/imagesectorinterface.cc", | ||||
|         "./lib/vfs/lif.cc", | ||||
|         "./lib/vfs/machfs.cc", | ||||
|         "./lib/vfs/microdos.cc", | ||||
|         "./lib/vfs/philefs.cc", | ||||
|         "./lib/vfs/prodos.cc", | ||||
|         "./lib/vfs/roland.cc", | ||||
|         "./lib/vfs/smaky6fs.cc", | ||||
|         "./lib/vfs/vfs.cc", | ||||
|         "./lib/vfs/zdos.cc", | ||||
|         "./arch/aeslanier/decoder.cc", | ||||
|         "./arch/agat/agat.cc", | ||||
|         "./arch/agat/decoder.cc", | ||||
|         "./arch/agat/encoder.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/decoder.cc", | ||||
|         "./arch/smaky6/decoder.cc", | ||||
|         "./arch/tids990/decoder.cc", | ||||
|         "./arch/tids990/encoder.cc", | ||||
|         "./arch/victor9k/decoder.cc", | ||||
|         "./arch/victor9k/encoder.cc", | ||||
|         "./arch/zilogmcz/decoder.cc", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "arch/ibm/ibm.h": "./arch/ibm/ibm.h", | ||||
|         "arch/apple2/data_gcr.h": "./arch/apple2/data_gcr.h", | ||||
|         "arch/apple2/apple2.h": "./arch/apple2/apple2.h", | ||||
|         "arch/smaky6/smaky6.h": "./arch/smaky6/smaky6.h", | ||||
|         "arch/tids990/tids990.h": "./arch/tids990/tids990.h", | ||||
|         "arch/zilogmcz/zilogmcz.h": "./arch/zilogmcz/zilogmcz.h", | ||||
|         "arch/amiga/amiga.h": "./arch/amiga/amiga.h", | ||||
|         "arch/f85/data_gcr.h": "./arch/f85/data_gcr.h", | ||||
|         "arch/f85/f85.h": "./arch/f85/f85.h", | ||||
|         "arch/mx/mx.h": "./arch/mx/mx.h", | ||||
|         "arch/aeslanier/aeslanier.h": "./arch/aeslanier/aeslanier.h", | ||||
|         "arch/northstar/northstar.h": "./arch/northstar/northstar.h", | ||||
|         "arch/brother/data_gcr.h": "./arch/brother/data_gcr.h", | ||||
|         "arch/brother/brother.h": "./arch/brother/brother.h", | ||||
|         "arch/brother/header_gcr.h": "./arch/brother/header_gcr.h", | ||||
|         "arch/macintosh/data_gcr.h": "./arch/macintosh/data_gcr.h", | ||||
|         "arch/macintosh/macintosh.h": "./arch/macintosh/macintosh.h", | ||||
|         "arch/agat/agat.h": "./arch/agat/agat.h", | ||||
|         "arch/fb100/fb100.h": "./arch/fb100/fb100.h", | ||||
|         "arch/victor9k/data_gcr.h": "./arch/victor9k/data_gcr.h", | ||||
|         "arch/victor9k/victor9k.h": "./arch/victor9k/victor9k.h", | ||||
|         "arch/rolandd20/rolandd20.h": "./arch/rolandd20/rolandd20.h", | ||||
|         "arch/micropolis/micropolis.h": "./arch/micropolis/micropolis.h", | ||||
|         "arch/c64/data_gcr.h": "./arch/c64/data_gcr.h", | ||||
|         "arch/c64/c64.h": "./arch/c64/c64.h", | ||||
|         "lib/a2r.h": "./lib/a2r.h", | ||||
|         "lib/bitmap.h": "./lib/bitmap.h", | ||||
|         "lib/bytes.h": "./lib/bytes.h", | ||||
|         "lib/config.h": "./lib/config.h", | ||||
|         "lib/crc.h": "./lib/crc.h", | ||||
|         "lib/csvreader.h": "./lib/csvreader.h", | ||||
|         "lib/decoders/decoders.h": "./lib/decoders/decoders.h", | ||||
|         "lib/decoders/fluxdecoder.h": "./lib/decoders/fluxdecoder.h", | ||||
|         "lib/decoders/fluxmapreader.h": "./lib/decoders/fluxmapreader.h", | ||||
|         "lib/decoders/rawbits.h": "./lib/decoders/rawbits.h", | ||||
|         "lib/encoders/encoders.h": "./lib/encoders/encoders.h", | ||||
|         "lib/scp.h": "./lib/scp.h", | ||||
|         "lib/fl2.h": "./lib/fl2.h", | ||||
|         "lib/flags.h": "./lib/flags.h", | ||||
|         "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", | ||||
|         "lib/globals.h": "./lib/globals.h", | ||||
|         "lib/image.h": "./lib/image.h", | ||||
|         "lib/imagereader/imagereader.h": "./lib/imagereader/imagereader.h", | ||||
|         "lib/imagewriter/imagewriter.h": "./lib/imagewriter/imagewriter.h", | ||||
|         "lib/layout.h": "./lib/layout.h", | ||||
|         "lib/ldbs.h": "./lib/ldbs.h", | ||||
|         "lib/logger.h": "./lib/logger.h", | ||||
|         "lib/proto.h": "./lib/proto.h", | ||||
|         "lib/readerwriter.h": "./lib/readerwriter.h", | ||||
|         "lib/sector.h": "./lib/sector.h", | ||||
|         "lib/usb/greaseweazle.h": "./lib/usb/greaseweazle.h", | ||||
|         "lib/usb/usb.h": "./lib/usb/usb.h", | ||||
|         "lib/usb/usbfinder.h": "./lib/usb/usbfinder.h", | ||||
|         "lib/utils.h": "./lib/utils.h", | ||||
|         "lib/vfs/applesingle.h": "./lib/vfs/applesingle.h", | ||||
|         "lib/vfs/sectorinterface.h": "./lib/vfs/sectorinterface.h", | ||||
|         "lib/vfs/vfs.h": "./lib/vfs/vfs.h", | ||||
|     }, | ||||
|     deps=[ | ||||
|         "+fl2_proto_lib", | ||||
|         "+protocol", | ||||
|         "lib+config_proto_lib", | ||||
|         "dep/adflib", | ||||
|         "dep/agg", | ||||
|         "dep/fatfs", | ||||
|         "dep/hfsutils", | ||||
|         "dep/libusbp", | ||||
|         "dep/stb", | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| corpustests = [] | ||||
| if not glob("../fluxengine-testdata/data"): | ||||
|     print("fluxengine-testdata not found; skipping corpus tests") | ||||
| else: | ||||
|     corpus = [ | ||||
|         ("acorndfs", "", "--200"), | ||||
|         ("agat", "", ""), | ||||
|         ("amiga", "", ""), | ||||
|         ("apple2", "", "--140 40track_drive"), | ||||
|         ("atarist", "", "--360"), | ||||
|         ("atarist", "", "--370"), | ||||
|         ("atarist", "", "--400"), | ||||
|         ("atarist", "", "--410"), | ||||
|         ("atarist", "", "--720"), | ||||
|         ("atarist", "", "--740"), | ||||
|         ("atarist", "", "--800"), | ||||
|         ("atarist", "", "--820"), | ||||
|         ("bk", "", ""), | ||||
|         ("brother", "", "--120 40track_drive"), | ||||
|         ("brother", "", "--240"), | ||||
|         ( | ||||
|             "commodore", | ||||
|             "scripts/commodore1541_test.textpb", | ||||
|             "--171 40track_drive", | ||||
|         ), | ||||
|         ( | ||||
|             "commodore", | ||||
|             "scripts/commodore1541_test.textpb", | ||||
|             "--192 40track_drive", | ||||
|         ), | ||||
|         ("commodore", "", "--800"), | ||||
|         ("commodore", "", "--1620"), | ||||
|         ("hplif", "", "--264"), | ||||
|         ("hplif", "", "--608"), | ||||
|         ("hplif", "", "--616"), | ||||
|         ("hplif", "", "--770"), | ||||
|         ("ibm", "", "--1200"), | ||||
|         ("ibm", "", "--1232"), | ||||
|         ("ibm", "", "--1440"), | ||||
|         ("ibm", "", "--1680"), | ||||
|         ("ibm", "", "--180 40track_drive"), | ||||
|         ("ibm", "", "--160 40track_drive"), | ||||
|         ("ibm", "", "--320 40track_drive"), | ||||
|         ("ibm", "", "--360 40track_drive"), | ||||
|         ("ibm", "", "--720_96"), | ||||
|         ("ibm", "", "--720_135"), | ||||
|         ("mac", "scripts/mac400_test.textpb", "--400"), | ||||
|         ("mac", "scripts/mac800_test.textpb", "--800"), | ||||
|         ("n88basic", "", ""), | ||||
|         ("rx50", "", ""), | ||||
|         ("tids990", "", ""), | ||||
|         ("victor9k", "", "--612"), | ||||
|         ("victor9k", "", "--1224"), | ||||
|     ] | ||||
|  | ||||
|     for c in corpus: | ||||
|         name = re.sub(r"[^a-zA-Z0-9]", "_", "".join(c), 0) | ||||
|         corpustests += [ | ||||
|             test( | ||||
|                 name=f"corpustest_{name}_{format}", | ||||
|                 ins=["src+fluxengine"], | ||||
|                 deps=["scripts/encodedecodetest.sh"], | ||||
|                 commands=[ | ||||
|                     "{deps[0]} " | ||||
|                     + c[0] | ||||
|                     + " " | ||||
|                     + format | ||||
|                     + " {ins[0]} '" | ||||
|                     + c[1] | ||||
|                     + "' '" | ||||
|                     + c[2] | ||||
|                     + "' $(dir {outs[0]}) > /dev/null" | ||||
|                 ], | ||||
|                 label="CORPUSTEST", | ||||
|             ) | ||||
|             for format in ["scp", "flux"] | ||||
|         ] | ||||
|  | ||||
| export( | ||||
|     name="all", | ||||
|     items={ | ||||
|         "fluxengine$(EXT)": "src+fluxengine", | ||||
|         "fluxengine-gui$(EXT)": "src/gui", | ||||
|         "brother120tool$(EXT)": "tools+brother120tool", | ||||
|         "brother240tool$(EXT)": "tools+brother240tool", | ||||
|         "upgrade-flux-file$(EXT)": "tools+upgrade-flux-file", | ||||
|     } | ||||
|     | ({"FluxEngine.pkg": "src/gui+fluxengine_pkg"} if config.osx else {}), | ||||
|     deps=["tests", "src/formats+docs", "scripts+mkdocindex"] + corpustests, | ||||
| ) | ||||
| @@ -1,19 +0,0 @@ | ||||
| import sys | ||||
| from functools import partial | ||||
|  | ||||
| if len(sys.argv) != 3: | ||||
|     sys.exit("Usage: %s <file> <symbol>" % sys.argv[0]) | ||||
| filename = sys.argv[1] | ||||
| symbol = sys.argv[2] | ||||
|  | ||||
| print("const uint8_t " + symbol + "[] = {") | ||||
| n = 0 | ||||
| with open(filename, "rb") as in_file: | ||||
|     for c in iter(partial(in_file.read, 1), b""): | ||||
|         print("0x%02X," % ord(c), end="") | ||||
|         n += 1 | ||||
|         if n % 16 == 0: | ||||
|             print() | ||||
| print("};") | ||||
|  | ||||
| print("const size_t " + symbol + "_len = sizeof(" + symbol + ");") | ||||
							
								
								
									
										42
									
								
								build/ab.mk
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								build/ab.mk
									
									
									
									
									
								
							| @@ -1,42 +0,0 @@ | ||||
| ifeq ($(findstring 4.,$(MAKE_VERSION)),) | ||||
| $(error You need GNU Make 4.x for this (if you're on OSX, use gmake).) | ||||
| endif | ||||
|  | ||||
| OBJ ?= .obj | ||||
| PYTHON ?= python3 | ||||
| CC ?= gcc | ||||
| CXX ?= g++ | ||||
| AR ?= ar | ||||
| CFLAGS ?= -g -Og | ||||
| LDFLAGS ?= -g | ||||
| hide = @ | ||||
| PKG_CONFIG ?= pkg-config | ||||
| ECHO ?= echo | ||||
|  | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	EXT ?= .exe | ||||
| endif | ||||
| EXT ?= | ||||
|  | ||||
| include $(OBJ)/build.mk | ||||
|  | ||||
| .PHONY: update-ab | ||||
| update-ab: | ||||
| 	@echo "Press RETURN to update ab from the repository, or CTRL+C to cancel." \ | ||||
| 		&& read a \ | ||||
| 		&& (curl -L https://github.com/davidgiven/ab/releases/download/dev/distribution.tar.xz | tar xvJf -) \ | ||||
| 		&& echo "Done." | ||||
|  | ||||
| .PHONY: clean | ||||
| clean:: | ||||
| 	@echo CLEAN | ||||
| 	$(hide) rm -rf $(OBJ) bin | ||||
|  | ||||
| export PYTHONHASHSEED = 1 | ||||
| build-files = $(shell find . -name 'build.py') build/*.py config.py | ||||
| $(OBJ)/build.mk: Makefile $(build-files) | ||||
| 	@echo "AB" | ||||
| 	@mkdir -p $(OBJ) | ||||
| 	$(hide) $(PYTHON) -X pycache_prefix=$(OBJ) build/ab.py -t +all -o $@ \ | ||||
| 		build.py || rm -f $@ | ||||
|  | ||||
							
								
								
									
										487
									
								
								build/ab.py
									
									
									
									
									
								
							
							
						
						
									
										487
									
								
								build/ab.py
									
									
									
									
									
								
							| @@ -1,487 +0,0 @@ | ||||
| from collections.abc import Iterable, Sequence | ||||
| from os.path import * | ||||
| from types import SimpleNamespace | ||||
| import argparse | ||||
| import copy | ||||
| import functools | ||||
| import importlib | ||||
| import importlib.abc | ||||
| import importlib.util | ||||
| import inspect | ||||
| import re | ||||
| import sys | ||||
| import types | ||||
| import pathlib | ||||
| import builtins | ||||
| import os | ||||
|  | ||||
| defaultGlobals = {} | ||||
| targets = {} | ||||
| unmaterialisedTargets = set() | ||||
| materialisingStack = [] | ||||
| outputFp = None | ||||
| cwdStack = [""] | ||||
|  | ||||
| sys.path += ["."] | ||||
| old_import = builtins.__import__ | ||||
|  | ||||
|  | ||||
| def new_import(name, *args, **kwargs): | ||||
|     if name not in sys.modules: | ||||
|         path = name.replace(".", "/") + ".py" | ||||
|         if isfile(path): | ||||
|             sys.stderr.write(f"loading {path}\n") | ||||
|             loader = importlib.machinery.SourceFileLoader(name, path) | ||||
|  | ||||
|             spec = importlib.util.spec_from_loader( | ||||
|                 name, loader, origin="built-in" | ||||
|             ) | ||||
|             module = importlib.util.module_from_spec(spec) | ||||
|             sys.modules[name] = module | ||||
|             cwdStack.append(dirname(path)) | ||||
|             spec.loader.exec_module(module) | ||||
|             cwdStack.pop() | ||||
|  | ||||
|     return old_import(name, *args, **kwargs) | ||||
|  | ||||
|  | ||||
| builtins.__import__ = new_import | ||||
|  | ||||
|  | ||||
| class ABException(BaseException): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class ParameterList(Sequence): | ||||
|     def __init__(self, parent=[]): | ||||
|         self.data = parent | ||||
|  | ||||
|     def __getitem__(self, i): | ||||
|         return self.data[i] | ||||
|  | ||||
|     def __len__(self): | ||||
|         return len(self.data) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return " ".join(self.data) | ||||
|  | ||||
|     def __add__(self, other): | ||||
|         newdata = self.data.copy() + other | ||||
|         return ParameterList(newdata) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return f"<PList: {self.data}>" | ||||
|  | ||||
|  | ||||
| class Invocation: | ||||
|     name = None | ||||
|     callback = None | ||||
|     types = None | ||||
|     ins = None | ||||
|     outs = None | ||||
|     binding = None | ||||
|  | ||||
|     def materialise(self, replacing=False): | ||||
|         if self in unmaterialisedTargets: | ||||
|             if not replacing and (self in materialisingStack): | ||||
|                 print("Found dependency cycle:") | ||||
|                 for i in materialisingStack: | ||||
|                     print(f"  {i.name}") | ||||
|                 print(f"  {self.name}") | ||||
|                 sys.exit(1) | ||||
|  | ||||
|             materialisingStack.append(self) | ||||
|  | ||||
|             # Perform type conversion to the declared rule parameter types. | ||||
|  | ||||
|             try: | ||||
|                 self.args = {} | ||||
|                 for k, v in self.binding.arguments.items(): | ||||
|                     if k != "kwargs": | ||||
|                         t = self.types.get(k, None) | ||||
|                         if t: | ||||
|                             v = t(v).convert(self) | ||||
|                         self.args[k] = v | ||||
|                     else: | ||||
|                         for kk, vv in v.items(): | ||||
|                             t = self.types.get(kk, None) | ||||
|                             if t: | ||||
|                                 vv = t(vv).convert(self) | ||||
|                             self.args[kk] = vv | ||||
|  | ||||
|                 # Actually call the callback. | ||||
|  | ||||
|                 cwdStack.append(self.cwd) | ||||
|                 self.callback(**self.args) | ||||
|                 cwdStack.pop() | ||||
|             except BaseException as e: | ||||
|                 print( | ||||
|                     f"Error materialising {self} ({id(self)}): {self.callback}" | ||||
|                 ) | ||||
|                 print(f"Arguments: {self.args}") | ||||
|                 raise e | ||||
|  | ||||
|             if self.outs is None: | ||||
|                 raise ABException(f"{self.name} didn't set self.outs") | ||||
|  | ||||
|             if self in unmaterialisedTargets: | ||||
|                 unmaterialisedTargets.remove(self) | ||||
|  | ||||
|             materialisingStack.pop() | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return "<Invocation %s>" % self.name | ||||
|  | ||||
|  | ||||
| def Rule(func): | ||||
|     sig = inspect.signature(func) | ||||
|  | ||||
|     @functools.wraps(func) | ||||
|     def wrapper(*, name=None, replaces=None, **kwargs): | ||||
|         cwd = None | ||||
|         if name: | ||||
|             if ("+" in name) and not name.startswith("+"): | ||||
|                 (cwd, _) = name.split("+", 1) | ||||
|         if not cwd: | ||||
|             cwd = cwdStack[-1] | ||||
|  | ||||
|         if name: | ||||
|             i = Invocation() | ||||
|             if name.startswith("./"): | ||||
|                 name = join(cwd, name) | ||||
|             elif "+" not in name: | ||||
|                 name = cwd + "+" + name | ||||
|  | ||||
|             i.name = name | ||||
|             i.localname = name.split("+")[-1] | ||||
|  | ||||
|             if name in targets: | ||||
|                 raise ABException(f"target {i.name} has already been defined") | ||||
|             targets[name] = i | ||||
|         elif replaces: | ||||
|             i = replaces | ||||
|             name = i.name | ||||
|         else: | ||||
|             raise ABException("you must supply either name or replaces") | ||||
|  | ||||
|         i.cwd = cwd | ||||
|         i.types = func.__annotations__ | ||||
|         i.callback = func | ||||
|         setattr(i, func.__name__, SimpleNamespace()) | ||||
|  | ||||
|         i.binding = sig.bind(name=name, self=i, **kwargs) | ||||
|         i.binding.apply_defaults() | ||||
|  | ||||
|         unmaterialisedTargets.add(i) | ||||
|         if replaces: | ||||
|             i.materialise(replacing=True) | ||||
|         return i | ||||
|  | ||||
|     defaultGlobals[func.__name__] = wrapper | ||||
|     return wrapper | ||||
|  | ||||
|  | ||||
| class Type: | ||||
|     def __init__(self, value): | ||||
|         self.value = value | ||||
|  | ||||
|  | ||||
| class Targets(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if type(value) is str: | ||||
|             value = [value] | ||||
|         if type(value) is list: | ||||
|             value = targetsof(value, cwd=invocation.cwd) | ||||
|         return value | ||||
|  | ||||
|  | ||||
| class Target(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if not value: | ||||
|             return None | ||||
|         return targetof(value, cwd=invocation.cwd) | ||||
|  | ||||
|  | ||||
| class TargetsMap(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if type(value) is dict: | ||||
|             return { | ||||
|                 k: targetof(v, cwd=invocation.cwd) for k, v in value.items() | ||||
|             } | ||||
|         raise ABException(f"wanted a dict of targets, got a {type(value)}") | ||||
|  | ||||
|  | ||||
| def flatten(*xs): | ||||
|     def recurse(xs): | ||||
|         for x in xs: | ||||
|             if isinstance(x, Iterable) and not isinstance(x, (str, bytes)): | ||||
|                 yield from recurse(x) | ||||
|             else: | ||||
|                 yield x | ||||
|  | ||||
|     return list(recurse(xs)) | ||||
|  | ||||
|  | ||||
| def fileinvocation(s): | ||||
|     i = Invocation() | ||||
|     i.name = s | ||||
|     i.outs = [s] | ||||
|     targets[s] = i | ||||
|     return i | ||||
|  | ||||
|  | ||||
| def targetof(s, cwd): | ||||
|     if isinstance(s, Invocation): | ||||
|         s.materialise() | ||||
|         return s | ||||
|  | ||||
|     if s in targets: | ||||
|         t = targets[s] | ||||
|         t.materialise() | ||||
|         return t | ||||
|  | ||||
|     if s.startswith(".+"): | ||||
|         s = cwd + s[1:] | ||||
|     elif s.startswith("./"): | ||||
|         s = normpath(join(cwd, s)) | ||||
|     elif s.endswith("/"): | ||||
|         return fileinvocation(s) | ||||
|     elif s.startswith("$"): | ||||
|         return fileinvocation(s) | ||||
|  | ||||
|     if "+" not in s: | ||||
|         if isdir(s): | ||||
|             s = s + "+" + basename(s) | ||||
|         else: | ||||
|             return fileinvocation(s) | ||||
|  | ||||
|     (path, target) = s.split("+", 2) | ||||
|     loadbuildfile(join(path, "build.py")) | ||||
|     if not s in targets: | ||||
|         raise ABException(f"build file at {path} doesn't contain +{target}") | ||||
|     i = targets[s] | ||||
|     i.materialise() | ||||
|     return i | ||||
|  | ||||
|  | ||||
| def targetsof(*xs, cwd): | ||||
|     return flatten([targetof(x, cwd) for x in flatten(xs)]) | ||||
|  | ||||
|  | ||||
| def filenamesof(*xs): | ||||
|     s = [] | ||||
|     for t in flatten(xs): | ||||
|         if type(t) == str: | ||||
|             t = normpath(t) | ||||
|             s += [t] | ||||
|         else: | ||||
|             s += [f for f in [normpath(f) for f in filenamesof(t.outs)]] | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def targetnamesof(*xs): | ||||
|     s = [] | ||||
|     for x in flatten(xs): | ||||
|         if type(x) == str: | ||||
|             x = normpath(x) | ||||
|             if x not in s: | ||||
|                 s += [x] | ||||
|         else: | ||||
|             if x.name not in s: | ||||
|                 s += [x.name] | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def filenameof(x): | ||||
|     xs = filenamesof(x) | ||||
|     if len(xs) != 1: | ||||
|         raise ABException("expected a single item") | ||||
|     return xs[0] | ||||
|  | ||||
|  | ||||
| def stripext(path): | ||||
|     return splitext(path)[0] | ||||
|  | ||||
|  | ||||
| def emit(*args): | ||||
|     outputFp.write(" ".join(flatten(args))) | ||||
|     outputFp.write("\n") | ||||
|  | ||||
|  | ||||
| def templateexpand(s, invocation): | ||||
|     class Converter: | ||||
|         def __getitem__(self, key): | ||||
|             if key == "self": | ||||
|                 return invocation | ||||
|             f = filenamesof(invocation.args[key]) | ||||
|             if isinstance(f, Sequence): | ||||
|                 f = ParameterList(f) | ||||
|             return f | ||||
|  | ||||
|     return eval("f%r" % s, invocation.callback.__globals__, Converter()) | ||||
|  | ||||
|  | ||||
| def emitter_rule(name, ins, outs, deps=[]): | ||||
|     emit("") | ||||
|     emit(".PHONY:", name) | ||||
|     if outs: | ||||
|         emit(name, ":", filenamesof(outs), ";") | ||||
|         emit(filenamesof(outs), "&:", filenamesof(ins), filenamesof(deps)) | ||||
|     else: | ||||
|         emit(name, "&:", filenamesof(ins), filenamesof(deps)) | ||||
|  | ||||
|  | ||||
| def emitter_endrule(name): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| def emitter_label(s): | ||||
|     emit("\t$(hide)", "$(ECHO)", s) | ||||
|  | ||||
|  | ||||
| def emitter_exec(cs): | ||||
|     for c in cs: | ||||
|         emit("\t$(hide)", c) | ||||
|  | ||||
|  | ||||
| def unmake(*ss): | ||||
|     return [ | ||||
|         re.sub(r"\$\(([^)]*)\)", r"$\1", s) for s in flatten(filenamesof(ss)) | ||||
|     ] | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def simplerule( | ||||
|     self, | ||||
|     name, | ||||
|     ins: Targets = [], | ||||
|     outs=[], | ||||
|     deps: Targets = [], | ||||
|     commands=[], | ||||
|     label="RULE", | ||||
|     **kwargs, | ||||
| ): | ||||
|     self.ins = ins | ||||
|     self.outs = outs | ||||
|     self.deps = deps | ||||
|     emitter_rule(self.name, ins + deps, outs) | ||||
|     emitter_label(templateexpand("{label} {name}", self)) | ||||
|  | ||||
|     dirs = [] | ||||
|     for out in filenamesof(outs): | ||||
|         dir = dirname(out) | ||||
|         if dir and dir not in dirs: | ||||
|             dirs += [dir] | ||||
|  | ||||
|         cs = [("mkdir -p %s" % dir) for dir in dirs] | ||||
|     for c in commands: | ||||
|         cs += [templateexpand(c, self)] | ||||
|     emitter_exec(cs) | ||||
|     emitter_endrule(self.name) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def normalrule( | ||||
|     self, | ||||
|     name=None, | ||||
|     ins: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     outs=[], | ||||
|     label="RULE", | ||||
|     objdir=None, | ||||
|     commands=[], | ||||
|     **kwargs, | ||||
| ): | ||||
|     objdir = objdir or join("$(OBJ)", name) | ||||
|  | ||||
|     self.normalrule.objdir = objdir | ||||
|     simplerule( | ||||
|         replaces=self, | ||||
|         ins=ins, | ||||
|         deps=deps, | ||||
|         outs=[join(objdir, f) for f in outs], | ||||
|         label=label, | ||||
|         commands=commands, | ||||
|         **kwargs, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def export(self, name=None, items: TargetsMap = {}, deps: Targets = []): | ||||
|     cs = [] | ||||
|     self.ins = items.values() | ||||
|     self.outs = [] | ||||
|     for dest, src in items.items(): | ||||
|         destf = filenameof(dest) | ||||
|         dir = dirname(destf) | ||||
|  | ||||
|         srcs = filenamesof(src) | ||||
|         if len(srcs) != 1: | ||||
|             raise ABException( | ||||
|                 "a dependency of an export must have exactly one output file" | ||||
|             ) | ||||
|  | ||||
|         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, self.outs, [], deps) | ||||
|     emit("\t@") | ||||
|  | ||||
|     if self.outs: | ||||
|         emit("clean::") | ||||
|         emit("\t$(hide) rm -f " + (" ".join(filenamesof(self.outs)))) | ||||
|     self.outs += deps | ||||
|  | ||||
|     emitter_endrule(self.name) | ||||
|  | ||||
|  | ||||
| def loadbuildfile(filename): | ||||
|     filename = filename.replace("/", ".").removesuffix(".py") | ||||
|     builtins.__import__(filename) | ||||
|  | ||||
|  | ||||
| def load(filename): | ||||
|     loadbuildfile(filename) | ||||
|     callerglobals = inspect.stack()[1][0].f_globals | ||||
|     for k, v in defaultGlobals.items(): | ||||
|         callerglobals[k] = v | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument("-o", "--output") | ||||
|     parser.add_argument("files", nargs="+") | ||||
|     parser.add_argument("-t", "--targets", action="append") | ||||
|     args = parser.parse_args() | ||||
|     if not args.targets: | ||||
|         raise ABException("no targets supplied") | ||||
|  | ||||
|     global outputFp | ||||
|     outputFp = open(args.output, "wt") | ||||
|  | ||||
|     for k in ("Rule", "Targets", "load", "filenamesof", "stripext"): | ||||
|         defaultGlobals[k] = globals()[k] | ||||
|  | ||||
|     global __name__ | ||||
|     sys.modules["build.ab"] = sys.modules[__name__] | ||||
|     __name__ = "build.ab" | ||||
|  | ||||
|     for f in args.files: | ||||
|         loadbuildfile(f) | ||||
|  | ||||
|     for t in flatten([a.split(",") for a in args.targets]): | ||||
|         if t not in targets: | ||||
|             raise ABException("target %s is not defined" % t) | ||||
|         targets[t].materialise() | ||||
|     emit("AB_LOADED = 1\n") | ||||
|  | ||||
|  | ||||
| main() | ||||
							
								
								
									
										251
									
								
								build/build.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								build/build.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| 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 | ||||
| ) | ||||
|  | ||||
							
								
								
									
										265
									
								
								build/c.py
									
									
									
									
									
								
							
							
						
						
									
										265
									
								
								build/c.py
									
									
									
									
									
								
							| @@ -1,265 +0,0 @@ | ||||
| from os.path import basename, join | ||||
| from build.ab import ( | ||||
|     ABException, | ||||
|     Rule, | ||||
|     Targets, | ||||
|     TargetsMap, | ||||
|     filenameof, | ||||
|     flatten, | ||||
|     filenamesof, | ||||
|     normalrule, | ||||
|     stripext, | ||||
| ) | ||||
| from os.path import * | ||||
| from types import SimpleNamespace | ||||
|  | ||||
|  | ||||
| def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags): | ||||
|     outleaf = stripext(basename(filenameof(srcs[0]))) + suffix | ||||
|  | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=srcs, | ||||
|         deps=deps, | ||||
|         outs=[outleaf], | ||||
|         label=label, | ||||
|         commands=commands, | ||||
|         cflags=cflags, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cfile( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     cflags=[], | ||||
|     suffix=".o", | ||||
|     commands=["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"], | ||||
|     label="CC", | ||||
| ): | ||||
|     cfileimpl(self, name, srcs, deps, suffix, commands, label, "cfile", cflags) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cxxfile( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     cflags=[], | ||||
|     suffix=".o", | ||||
|     commands=["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"], | ||||
|     label="CXX", | ||||
| ): | ||||
|     cfileimpl( | ||||
|         self, name, srcs, deps, suffix, commands, label, "cxxfile", cflags | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def findsources(name, srcs, deps, cflags, filerule): | ||||
|     objs = [] | ||||
|     for s in flatten(srcs): | ||||
|         objs += [ | ||||
|             filerule( | ||||
|                 name=join(name, f.removeprefix("$(OBJ)/")), | ||||
|                 srcs=[f], | ||||
|                 deps=deps, | ||||
|                 cflags=cflags, | ||||
|             ) | ||||
|             for f in filenamesof(s) | ||||
|             if f.endswith(".c") or f.endswith(".cc") or f.endswith(".cpp") | ||||
|         ] | ||||
|         if any(f.endswith(".o") for f in filenamesof(s)): | ||||
|             objs += [s] | ||||
|  | ||||
|     return objs | ||||
|  | ||||
|  | ||||
| def libraryimpl( | ||||
|     self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, kind | ||||
| ): | ||||
|     if not srcs and not hdrs: | ||||
|         raise ABException( | ||||
|             "clibrary contains no sources and no exported headers" | ||||
|         ) | ||||
|  | ||||
|     libraries = [d for d in deps if hasattr(d, "clibrary")] | ||||
|     for library in libraries: | ||||
|         if library.clibrary.cflags: | ||||
|             cflags += library.clibrary.cflags | ||||
|         if library.clibrary.ldflags: | ||||
|             ldflags += library.clibrary.ldflags | ||||
|  | ||||
|     for f in filenamesof(srcs): | ||||
|         if f.endswith(".h"): | ||||
|             deps += [f] | ||||
|  | ||||
|     hdrcs = [] | ||||
|     hdrins = list(hdrs.values()) | ||||
|     hdrouts = [] | ||||
|     i = 0 | ||||
|     for dest, src in hdrs.items(): | ||||
|         s = filenamesof(src) | ||||
|         if len(s) != 1: | ||||
|             raise ABException( | ||||
|                 "a dependency of an export must have exactly one output file" | ||||
|             ) | ||||
|  | ||||
|         hdrcs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"] | ||||
|         hdrouts += [dest] | ||||
|         i = i + 1 | ||||
|  | ||||
|     if not hasattr(self, "clibrary"): | ||||
|         self.clibrary = SimpleNamespace() | ||||
|     if srcs: | ||||
|         hr = None | ||||
|         if hdrcs: | ||||
|             hr = normalrule( | ||||
|                 name=f"{name}_hdrs", | ||||
|                 ins=hdrins, | ||||
|                 outs=hdrouts, | ||||
|                 label="HEADERS", | ||||
|                 commands=hdrcs, | ||||
|             ) | ||||
|             hr.materialise() | ||||
|  | ||||
|         actualsrcs = findsources( | ||||
|             name, | ||||
|             srcs, | ||||
|             deps + ([f"{name}_hdrs"] if hr else []), | ||||
|             cflags + ([f"-I{hr.normalrule.objdir}"] if hr else []), | ||||
|             kind, | ||||
|         ) | ||||
|  | ||||
|         normalrule( | ||||
|             replaces=self, | ||||
|             ins=actualsrcs, | ||||
|             outs=[basename(name) + ".a"], | ||||
|             label=label, | ||||
|             commands=commands if actualsrcs else [], | ||||
|         ) | ||||
|  | ||||
|         self.clibrary.ldflags = ldflags | ||||
|         self.clibrary.cflags = ["-I" + hr.normalrule.objdir] if hr else [] | ||||
|     else: | ||||
|         r = normalrule( | ||||
|             replaces=self, | ||||
|             ins=hdrins, | ||||
|             outs=hdrouts, | ||||
|             label="HEADERS", | ||||
|             commands=hdrcs, | ||||
|         ) | ||||
|         r.materialise() | ||||
|  | ||||
|         self.clibrary.ldflags = ldflags | ||||
|         self.clibrary.cflags = ["-I" + r.normalrule.objdir] | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def clibrary( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     hdrs: TargetsMap = {}, | ||||
|     cflags=[], | ||||
|     ldflags=[], | ||||
|     commands=["$(AR) cqs {outs[0]} {ins}"], | ||||
|     label="LIB", | ||||
| ): | ||||
|     return libraryimpl( | ||||
|         self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cfile | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cxxlibrary( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     hdrs: TargetsMap = {}, | ||||
|     cflags=[], | ||||
|     ldflags=[], | ||||
|     commands=["$(AR) cqs {outs[0]} {ins}"], | ||||
|     label="LIB", | ||||
| ): | ||||
|     return libraryimpl( | ||||
|         self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cxxfile | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def programimpl( | ||||
|     self, name, srcs, deps, cflags, ldflags, commands, label, filerule, kind | ||||
| ): | ||||
|     libraries = [d for d in deps if hasattr(d, "clibrary")] | ||||
|     for library in libraries: | ||||
|         if library.clibrary.cflags: | ||||
|             cflags += library.clibrary.cflags | ||||
|         if library.clibrary.ldflags: | ||||
|             ldflags += library.clibrary.ldflags | ||||
|  | ||||
|     deps += [f for f in filenamesof(srcs) if f.endswith(".h")] | ||||
|  | ||||
|     ars = [f for f in filenamesof(libraries) if f.endswith(".a")] | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=(findsources(name, srcs, deps, cflags, filerule) + ars + ars), | ||||
|         outs=[basename(name) + "$(EXT)"], | ||||
|         deps=deps, | ||||
|         label=label, | ||||
|         commands=commands, | ||||
|         ldflags=ldflags, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cprogram( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     cflags=[], | ||||
|     ldflags=[], | ||||
|     commands=["$(CC) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"], | ||||
|     label="CLINK", | ||||
| ): | ||||
|     programimpl( | ||||
|         self, | ||||
|         name, | ||||
|         srcs, | ||||
|         deps, | ||||
|         cflags, | ||||
|         ldflags, | ||||
|         commands, | ||||
|         label, | ||||
|         cfile, | ||||
|         "cprogram", | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cxxprogram( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     cflags=[], | ||||
|     ldflags=[], | ||||
|     commands=["$(CXX) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"], | ||||
|     label="CXXLINK", | ||||
| ): | ||||
|     programimpl( | ||||
|         self, | ||||
|         name, | ||||
|         srcs, | ||||
|         deps, | ||||
|         cflags, | ||||
|         ldflags, | ||||
|         commands, | ||||
|         label, | ||||
|         cxxfile, | ||||
|         "cxxprogram", | ||||
|     ) | ||||
							
								
								
									
										38
									
								
								build/pkg.py
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								build/pkg.py
									
									
									
									
									
								
							| @@ -1,38 +0,0 @@ | ||||
| from build.ab import Rule, emit, Target | ||||
| from types import SimpleNamespace | ||||
| import os | ||||
| import subprocess | ||||
|  | ||||
| emit( | ||||
|     """ | ||||
| PKG_CONFIG ?= pkg-config | ||||
| PACKAGES := $(shell $(PKG_CONFIG) --list-all | cut -d' ' -f1 | sort) | ||||
| """ | ||||
| ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def package(self, name, package=None, fallback: Target = None): | ||||
|     emit("ifeq ($(filter %s, $(PACKAGES)),)" % package) | ||||
|     if fallback: | ||||
|         emit(f"PACKAGE_CFLAGS_{package} :=", fallback.clibrary.cflags) | ||||
|         emit(f"PACKAGE_LDFLAGS_{package} := ", fallback.clibrary.ldflags) | ||||
|         emit(f"PACKAGE_DEP_{package} := ", fallback.name) | ||||
|     else: | ||||
|         emit(f"$(error Required package '{package}' not installed.)") | ||||
|     emit("else") | ||||
|     emit( | ||||
|         f"PACKAGE_CFLAGS_{package} := $(shell $(PKG_CONFIG) --cflags {package})" | ||||
|     ) | ||||
|     emit( | ||||
|         f"PACKAGE_LDFLAGS_{package} := $(shell $(PKG_CONFIG) --libs {package})" | ||||
|     ) | ||||
|     emit(f"PACKAGE_DEP_{package} := ") | ||||
|     emit("endif") | ||||
|  | ||||
|     self.clibrary = SimpleNamespace() | ||||
|     self.clibrary.cflags = [f"$(PACKAGE_CFLAGS_{package})"] | ||||
|     self.clibrary.ldflags = [f"$(PACKAGE_LDFLAGS_{package})"] | ||||
|  | ||||
|     self.ins = [] | ||||
|     self.outs = [f"$(PACKAGE_DEP_{package})"] | ||||
| @@ -1,65 +0,0 @@ | ||||
| from os.path import join | ||||
| from build.ab import Rule, Targets, emit, normalrule, filenamesof, flatten | ||||
| from build.c import cxxlibrary | ||||
| import build.pkg | ||||
| from types import SimpleNamespace | ||||
|  | ||||
| emit( | ||||
|     """ | ||||
| PROTOC ?= protoc | ||||
| ifeq ($(filter protobuf, $(PACKAGES)),) | ||||
| $(error Required package 'protobuf' not installed.)" | ||||
| endif | ||||
| """ | ||||
| ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def proto(self, name, srcs: Targets = [], deps: Targets = []): | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=srcs, | ||||
|         outs=[f"{name}.descriptor"], | ||||
|         deps=deps, | ||||
|         commands=[ | ||||
|             "$(PROTOC) --include_source_info --descriptor_set_out={outs[0]} {ins}" | ||||
|         ], | ||||
|         label="PROTO", | ||||
|     ) | ||||
|     self.proto.srcs = filenamesof(srcs) + flatten( | ||||
|         [s.proto.srcs for s in flatten(deps)] | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def protocc(self, name, srcs: Targets = [], deps: Targets = []): | ||||
|     outs = [] | ||||
|     protos = [] | ||||
|     for f in flatten([s.proto.srcs for s in flatten(srcs + deps)]): | ||||
|         if f.endswith(".proto"): | ||||
|             cc = f.replace(".proto", ".pb.cc") | ||||
|             h = f.replace(".proto", ".pb.h") | ||||
|             protos += [f] | ||||
|             srcs += [f] | ||||
|             outs += [cc, h] | ||||
|  | ||||
|     r = normalrule( | ||||
|         name=f"{name}_srcs", | ||||
|         ins=protos, | ||||
|         outs=outs, | ||||
|         deps=deps, | ||||
|         commands=["$(PROTOC) --cpp_out={self.normalrule.objdir} {ins}"], | ||||
|         label="PROTOCC", | ||||
|     ) | ||||
|  | ||||
|     r.materialise() | ||||
|     headers = { | ||||
|         f: join(r.normalrule.objdir, f) for f in outs if f.endswith(".pb.h") | ||||
|     } | ||||
|  | ||||
|     cxxlibrary( | ||||
|         replaces=self, | ||||
|         srcs=[f"{name}_srcs"], | ||||
|         hdrs=headers, | ||||
|         cflags=[f"-I{r.normalrule.objdir}"], | ||||
|     ) | ||||
							
								
								
									
										18
									
								
								build/tests.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								build/tests.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| 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 | ||||
| ) | ||||
|  | ||||
| @@ -1,43 +0,0 @@ | ||||
| from build.ab import Rule, normalrule, Target, filenameof, Targets | ||||
| from os.path import basename | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def objectify(self, name, src: Target, symbol): | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=["build/_objectify.py", src], | ||||
|         outs=[basename(filenameof(src)) + ".h"], | ||||
|         commands=["$(PYTHON) {ins[0]} {ins[1]} " + symbol + " > {outs}"], | ||||
|         label="OBJECTIFY", | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def test( | ||||
|     self, | ||||
|     name, | ||||
|     command: Target = None, | ||||
|     commands=None, | ||||
|     ins: Targets = [], | ||||
|     deps: Targets = [], | ||||
|     label="TEST", | ||||
| ): | ||||
|     if command: | ||||
|         normalrule( | ||||
|             replaces=self, | ||||
|             ins=[command], | ||||
|             outs=["sentinel"], | ||||
|             commands=["{ins[0]}", "touch {outs}"], | ||||
|             deps=deps, | ||||
|             label=label, | ||||
|         ) | ||||
|     else: | ||||
|         normalrule( | ||||
|             replaces=self, | ||||
|             ins=ins, | ||||
|             outs=["sentinel"], | ||||
|             commands=commands + ["touch {outs}"], | ||||
|             deps=deps, | ||||
|             label=label, | ||||
|         ) | ||||
| @@ -1,5 +0,0 @@ | ||||
| import platform | ||||
|  | ||||
| windows = platform.system() == "Windows" | ||||
| osx = platform.system() == "Darwin" | ||||
| unix = not windows | ||||
							
								
								
									
										22
									
								
								dep/adflib/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								dep/adflib/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| ADFLIB_SRCS = \ | ||||
| 	dep/adflib/src/adf_bitm.c \ | ||||
| 	dep/adflib/src/adf_cache.c \ | ||||
| 	dep/adflib/src/adf_dir.c \ | ||||
| 	dep/adflib/src/adf_disk.c \ | ||||
| 	dep/adflib/src/adf_dump.c \ | ||||
| 	dep/adflib/src/adf_env.c \ | ||||
| 	dep/adflib/src/adf_file.c \ | ||||
| 	dep/adflib/src/adf_hd.c \ | ||||
| 	dep/adflib/src/adf_link.c \ | ||||
| 	dep/adflib/src/adf_raw.c \ | ||||
| 	dep/adflib/src/adf_salv.c \ | ||||
| 	dep/adflib/src/adf_util.c \ | ||||
|  | ||||
| ADFLIB_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(ADFLIB_SRCS)) | ||||
| $(ADFLIB_OBJS): CFLAGS += -Idep/adflib/src -Idep/adflib | ||||
| ADFLIB_LIB = $(OBJDIR)/libadflib.a | ||||
| $(ADFLIB_LIB): $(ADFLIB_OBJS) | ||||
| ADFLIB_CFLAGS = -Idep/adflib/src | ||||
| ADFLIB_LDFLAGS = $(ADFLIB_LIB) | ||||
| OBJS += $(ADFLIB_OBJS) | ||||
|  | ||||
| @@ -1,47 +0,0 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="adflib", | ||||
|     srcs=[ | ||||
|         "./src/adf_bitm.c", | ||||
|         "./src/adf_bitm.h", | ||||
|         "./src/adf_cache.c", | ||||
|         "./src/adf_cache.h", | ||||
|         "./src/adf_dir.c", | ||||
|         "./src/adf_dir.h", | ||||
|         "./src/adf_disk.c", | ||||
|         "./src/adf_disk.h", | ||||
|         "./src/adf_dump.c", | ||||
|         "./src/adf_dump.h", | ||||
|         "./src/adf_env.c", | ||||
|         "./src/adf_env.h", | ||||
|         "./src/adf_file.c", | ||||
|         "./src/adf_file.h", | ||||
|         "./src/adf_hd.c", | ||||
|         "./src/adf_hd.h", | ||||
|         "./src/adf_link.c", | ||||
|         "./src/adf_link.h", | ||||
|         "./src/adf_raw.c", | ||||
|         "./src/adf_raw.h", | ||||
|         "./src/adf_salv.c", | ||||
|         "./src/adf_salv.h", | ||||
|         "./src/adf_str.h", | ||||
|         "./src/adf_util.c", | ||||
|         "./src/adf_util.h", | ||||
|         "./src/defendian.h", | ||||
|         "./src/hd_blk.h", | ||||
|         "./src/prefix.h", | ||||
|         "./adf_nativ.h", | ||||
|         "./config.h", | ||||
|         "./src/adflib.h", | ||||
|     ], | ||||
|     cflags=["-Idep/adflib", "-Idep/adflib/src"], | ||||
|     hdrs={ | ||||
|         "adf_blk.h": "./src/adf_blk.h", | ||||
|         "adf_defs.h": "./src/adf_defs.h", | ||||
|         "adf_err.h": "./src/adf_err.h", | ||||
|         "adf_nativ.h": "./adf_nativ.h", | ||||
|         "adf_str.h": "./src/adf_str.h", | ||||
|         "adflib.h": "./src/adflib.h", | ||||
|     }, | ||||
| ) | ||||
							
								
								
									
										38
									
								
								dep/agg/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								dep/agg/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| AGG_SRCS = \ | ||||
| 	dep/agg/src/agg_arrowhead.cpp \ | ||||
| 	dep/agg/src/agg_line_aa_basics.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_bspline.cpp \ | ||||
| 	dep/agg/src/agg_vpgen_segmentator.cpp \ | ||||
| 	dep/agg/src/agg_color_rgba.cpp \ | ||||
| 	dep/agg/src/agg_sqrt_tables.cpp \ | ||||
| 	dep/agg/src/agg_bspline.cpp \ | ||||
| 	dep/agg/src/agg_curves.cpp \ | ||||
| 	dep/agg/src/agg_rounded_rect.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_markers_term.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_dash.cpp \ | ||||
| 	dep/agg/src/agg2d.cpp \ | ||||
| 	dep/agg/src/agg_trans_affine.cpp \ | ||||
| 	dep/agg/src/agg_gsv_text.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_smooth_poly1.cpp \ | ||||
| 	dep/agg/src/agg_trans_single_path.cpp \ | ||||
| 	dep/agg/src/agg_vpgen_clip_polygon.cpp \ | ||||
| 	dep/agg/src/agg_embedded_raster_fonts.cpp \ | ||||
| 	dep/agg/src/agg_trans_double_path.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_stroke.cpp \ | ||||
| 	dep/agg/src/agg_arc.cpp \ | ||||
| 	dep/agg/src/agg_image_filters.cpp \ | ||||
| 	dep/agg/src/agg_trans_warp_magnifier.cpp \ | ||||
| 	dep/agg/src/agg_vpgen_clip_polyline.cpp \ | ||||
| 	dep/agg/src/agg_bezier_arc.cpp \ | ||||
| 	dep/agg/src/agg_line_profile_aa.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_contour.cpp \ | ||||
| 	 | ||||
| AGG_OBJS = $(patsubst %.cpp, $(OBJDIR)/%.o, $(AGG_SRCS)) | ||||
| AGG_LIB = $(OBJDIR)/libagg.a | ||||
| $(AGG_LIB): $(AGG_OBJS) | ||||
| AGG_LDFLAGS = $(AGG_LIB) | ||||
| AGG_CFLAGS = -Idep/agg/include | ||||
| OBJS += $(AGG_OBJS) | ||||
|  | ||||
| $(AGG_OBJS): CFLAGS += $(AGG_CFLAGS) | ||||
|  | ||||
							
								
								
									
										164
									
								
								dep/agg/build.py
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								dep/agg/build.py
									
									
									
									
									
								
							| @@ -1,164 +0,0 @@ | ||||
| from build.c import cxxlibrary | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="agg", | ||||
|     srcs=[ | ||||
|         "./src/agg_arrowhead.cpp", | ||||
|         "./src/agg_line_aa_basics.cpp", | ||||
|         "./src/agg_vcgen_bspline.cpp", | ||||
|         "./src/agg_vpgen_segmentator.cpp", | ||||
|         "./src/agg_color_rgba.cpp", | ||||
|         "./src/agg_sqrt_tables.cpp", | ||||
|         "./src/agg_bspline.cpp", | ||||
|         "./src/agg_curves.cpp", | ||||
|         "./src/agg_rounded_rect.cpp", | ||||
|         "./src/agg_vcgen_markers_term.cpp", | ||||
|         "./src/agg_vcgen_dash.cpp", | ||||
|         "./src/agg2d.cpp", | ||||
|         "./src/agg_trans_affine.cpp", | ||||
|         "./src/agg_gsv_text.cpp", | ||||
|         "./src/agg_vcgen_smooth_poly1.cpp", | ||||
|         "./src/agg_trans_single_path.cpp", | ||||
|         "./src/agg_vpgen_clip_polygon.cpp", | ||||
|         "./src/agg_embedded_raster_fonts.cpp", | ||||
|         "./src/agg_trans_double_path.cpp", | ||||
|         "./src/agg_vcgen_stroke.cpp", | ||||
|         "./src/agg_arc.cpp", | ||||
|         "./src/agg_image_filters.cpp", | ||||
|         "./src/agg_trans_warp_magnifier.cpp", | ||||
|         "./src/agg_vpgen_clip_polyline.cpp", | ||||
|         "./src/agg_bezier_arc.cpp", | ||||
|         "./src/agg_line_profile_aa.cpp", | ||||
|         "./src/agg_vcgen_contour.cpp", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "agg2d.h": "./include/agg2d.h", | ||||
|         "agg_alpha_mask_u8.h": "./include/agg_alpha_mask_u8.h", | ||||
|         "agg_arc.h": "./include/agg_arc.h", | ||||
|         "agg_array.h": "./include/agg_array.h", | ||||
|         "agg_arrowhead.h": "./include/agg_arrowhead.h", | ||||
|         "agg_basics.h": "./include/agg_basics.h", | ||||
|         "agg_bezier_arc.h": "./include/agg_bezier_arc.h", | ||||
|         "agg_bitset_iterator.h": "./include/agg_bitset_iterator.h", | ||||
|         "agg_blur.h": "./include/agg_blur.h", | ||||
|         "agg_bounding_rect.h": "./include/agg_bounding_rect.h", | ||||
|         "agg_bspline.h": "./include/agg_bspline.h", | ||||
|         "agg_clip_liang_barsky.h": "./include/agg_clip_liang_barsky.h", | ||||
|         "agg_color_gray.h": "./include/agg_color_gray.h", | ||||
|         "agg_color_rgba.h": "./include/agg_color_rgba.h", | ||||
|         "agg_config.h": "./include/agg_config.h", | ||||
|         "agg_conv_adaptor_vcgen.h": "./include/agg_conv_adaptor_vcgen.h", | ||||
|         "agg_conv_adaptor_vpgen.h": "./include/agg_conv_adaptor_vpgen.h", | ||||
|         "agg_conv_bspline.h": "./include/agg_conv_bspline.h", | ||||
|         "agg_conv_clip_polygon.h": "./include/agg_conv_clip_polygon.h", | ||||
|         "agg_conv_clip_polyline.h": "./include/agg_conv_clip_polyline.h", | ||||
|         "agg_conv_close_polygon.h": "./include/agg_conv_close_polygon.h", | ||||
|         "agg_conv_concat.h": "./include/agg_conv_concat.h", | ||||
|         "agg_conv_contour.h": "./include/agg_conv_contour.h", | ||||
|         "agg_conv_curve.h": "./include/agg_conv_curve.h", | ||||
|         "agg_conv_dash.h": "./include/agg_conv_dash.h", | ||||
|         "agg_conv_gpc.h": "./include/agg_conv_gpc.h", | ||||
|         "agg_conv_marker_adaptor.h": "./include/agg_conv_marker_adaptor.h", | ||||
|         "agg_conv_marker.h": "./include/agg_conv_marker.h", | ||||
|         "agg_conv_segmentator.h": "./include/agg_conv_segmentator.h", | ||||
|         "agg_conv_shorten_path.h": "./include/agg_conv_shorten_path.h", | ||||
|         "agg_conv_smooth_poly1.h": "./include/agg_conv_smooth_poly1.h", | ||||
|         "agg_conv_stroke.h": "./include/agg_conv_stroke.h", | ||||
|         "agg_conv_transform.h": "./include/agg_conv_transform.h", | ||||
|         "agg_conv_unclose_polygon.h": "./include/agg_conv_unclose_polygon.h", | ||||
|         "agg_curves.h": "./include/agg_curves.h", | ||||
|         "agg_dda_line.h": "./include/agg_dda_line.h", | ||||
|         "agg_ellipse_bresenham.h": "./include/agg_ellipse_bresenham.h", | ||||
|         "agg_ellipse.h": "./include/agg_ellipse.h", | ||||
|         "agg_embedded_raster_fonts.h": "./include/agg_embedded_raster_fonts.h", | ||||
|         "agg_font_cache_manager2.h": "./include/agg_font_cache_manager2.h", | ||||
|         "agg_font_cache_manager.h": "./include/agg_font_cache_manager.h", | ||||
|         "agg_gamma_functions.h": "./include/agg_gamma_functions.h", | ||||
|         "agg_gamma_lut.h": "./include/agg_gamma_lut.h", | ||||
|         "agg_glyph_raster_bin.h": "./include/agg_glyph_raster_bin.h", | ||||
|         "agg_gradient_lut.h": "./include/agg_gradient_lut.h", | ||||
|         "agg_gsv_text.h": "./include/agg_gsv_text.h", | ||||
|         "agg_image_accessors.h": "./include/agg_image_accessors.h", | ||||
|         "agg_image_filters.h": "./include/agg_image_filters.h", | ||||
|         "agg_line_aa_basics.h": "./include/agg_line_aa_basics.h", | ||||
|         "agg_math.h": "./include/agg_math.h", | ||||
|         "agg_math_stroke.h": "./include/agg_math_stroke.h", | ||||
|         "agg_path_length.h": "./include/agg_path_length.h", | ||||
|         "agg_path_storage.h": "./include/agg_path_storage.h", | ||||
|         "agg_path_storage_integer.h": "./include/agg_path_storage_integer.h", | ||||
|         "agg_pattern_filters_rgba.h": "./include/agg_pattern_filters_rgba.h", | ||||
|         "agg_pixfmt_amask_adaptor.h": "./include/agg_pixfmt_amask_adaptor.h", | ||||
|         "agg_pixfmt_base.h": "./include/agg_pixfmt_base.h", | ||||
|         "agg_pixfmt_gray.h": "./include/agg_pixfmt_gray.h", | ||||
|         "agg_pixfmt_rgba.h": "./include/agg_pixfmt_rgba.h", | ||||
|         "agg_pixfmt_rgb.h": "./include/agg_pixfmt_rgb.h", | ||||
|         "agg_pixfmt_rgb_packed.h": "./include/agg_pixfmt_rgb_packed.h", | ||||
|         "agg_pixfmt_transposer.h": "./include/agg_pixfmt_transposer.h", | ||||
|         "agg_rasterizer_cells_aa.h": "./include/agg_rasterizer_cells_aa.h", | ||||
|         "agg_rasterizer_compound_aa.h": "./include/agg_rasterizer_compound_aa.h", | ||||
|         "agg_rasterizer_outline_aa.h": "./include/agg_rasterizer_outline_aa.h", | ||||
|         "agg_rasterizer_outline.h": "./include/agg_rasterizer_outline.h", | ||||
|         "agg_rasterizer_scanline_aa.h": "./include/agg_rasterizer_scanline_aa.h", | ||||
|         "agg_rasterizer_scanline_aa_nogamma.h": "./include/agg_rasterizer_scanline_aa_nogamma.h", | ||||
|         "agg_rasterizer_sl_clip.h": "./include/agg_rasterizer_sl_clip.h", | ||||
|         "agg_renderer_base.h": "./include/agg_renderer_base.h", | ||||
|         "agg_renderer_markers.h": "./include/agg_renderer_markers.h", | ||||
|         "agg_renderer_mclip.h": "./include/agg_renderer_mclip.h", | ||||
|         "agg_renderer_outline_aa.h": "./include/agg_renderer_outline_aa.h", | ||||
|         "agg_renderer_outline_image.h": "./include/agg_renderer_outline_image.h", | ||||
|         "agg_renderer_primitives.h": "./include/agg_renderer_primitives.h", | ||||
|         "agg_renderer_raster_text.h": "./include/agg_renderer_raster_text.h", | ||||
|         "agg_renderer_scanline.h": "./include/agg_renderer_scanline.h", | ||||
|         "agg_rendering_buffer_dynarow.h": "./include/agg_rendering_buffer_dynarow.h", | ||||
|         "agg_rendering_buffer.h": "./include/agg_rendering_buffer.h", | ||||
|         "agg_rounded_rect.h": "./include/agg_rounded_rect.h", | ||||
|         "agg_scanline_bin.h": "./include/agg_scanline_bin.h", | ||||
|         "agg_scanline_boolean_algebra.h": "./include/agg_scanline_boolean_algebra.h", | ||||
|         "agg_scanline_p.h": "./include/agg_scanline_p.h", | ||||
|         "agg_scanline_storage_aa.h": "./include/agg_scanline_storage_aa.h", | ||||
|         "agg_scanline_storage_bin.h": "./include/agg_scanline_storage_bin.h", | ||||
|         "agg_scanline_u.h": "./include/agg_scanline_u.h", | ||||
|         "agg_shorten_path.h": "./include/agg_shorten_path.h", | ||||
|         "agg_simul_eq.h": "./include/agg_simul_eq.h", | ||||
|         "agg_span_allocator.h": "./include/agg_span_allocator.h", | ||||
|         "agg_span_converter.h": "./include/agg_span_converter.h", | ||||
|         "agg_span_gouraud_gray.h": "./include/agg_span_gouraud_gray.h", | ||||
|         "agg_span_gouraud.h": "./include/agg_span_gouraud.h", | ||||
|         "agg_span_gouraud_rgba.h": "./include/agg_span_gouraud_rgba.h", | ||||
|         "agg_span_gradient_alpha.h": "./include/agg_span_gradient_alpha.h", | ||||
|         "agg_span_gradient_contour.h": "./include/agg_span_gradient_contour.h", | ||||
|         "agg_span_gradient.h": "./include/agg_span_gradient.h", | ||||
|         "agg_span_gradient_image.h": "./include/agg_span_gradient_image.h", | ||||
|         "agg_span_image_filter_gray.h": "./include/agg_span_image_filter_gray.h", | ||||
|         "agg_span_image_filter.h": "./include/agg_span_image_filter.h", | ||||
|         "agg_span_image_filter_rgba.h": "./include/agg_span_image_filter_rgba.h", | ||||
|         "agg_span_image_filter_rgb.h": "./include/agg_span_image_filter_rgb.h", | ||||
|         "agg_span_interpolator_adaptor.h": "./include/agg_span_interpolator_adaptor.h", | ||||
|         "agg_span_interpolator_linear.h": "./include/agg_span_interpolator_linear.h", | ||||
|         "agg_span_interpolator_persp.h": "./include/agg_span_interpolator_persp.h", | ||||
|         "agg_span_interpolator_trans.h": "./include/agg_span_interpolator_trans.h", | ||||
|         "agg_span_pattern_gray.h": "./include/agg_span_pattern_gray.h", | ||||
|         "agg_span_pattern_rgba.h": "./include/agg_span_pattern_rgba.h", | ||||
|         "agg_span_pattern_rgb.h": "./include/agg_span_pattern_rgb.h", | ||||
|         "agg_span_solid.h": "./include/agg_span_solid.h", | ||||
|         "agg_span_subdiv_adaptor.h": "./include/agg_span_subdiv_adaptor.h", | ||||
|         "agg_trans_affine.h": "./include/agg_trans_affine.h", | ||||
|         "agg_trans_bilinear.h": "./include/agg_trans_bilinear.h", | ||||
|         "agg_trans_double_path.h": "./include/agg_trans_double_path.h", | ||||
|         "agg_trans_perspective.h": "./include/agg_trans_perspective.h", | ||||
|         "agg_trans_single_path.h": "./include/agg_trans_single_path.h", | ||||
|         "agg_trans_viewport.h": "./include/agg_trans_viewport.h", | ||||
|         "agg_trans_warp_magnifier.h": "./include/agg_trans_warp_magnifier.h", | ||||
|         "agg_vcgen_bspline.h": "./include/agg_vcgen_bspline.h", | ||||
|         "agg_vcgen_contour.h": "./include/agg_vcgen_contour.h", | ||||
|         "agg_vcgen_dash.h": "./include/agg_vcgen_dash.h", | ||||
|         "agg_vcgen_markers_term.h": "./include/agg_vcgen_markers_term.h", | ||||
|         "agg_vcgen_smooth_poly1.h": "./include/agg_vcgen_smooth_poly1.h", | ||||
|         "agg_vcgen_stroke.h": "./include/agg_vcgen_stroke.h", | ||||
|         "agg_vcgen_vertex_sequence.h": "./include/agg_vcgen_vertex_sequence.h", | ||||
|         "agg_vertex_sequence.h": "./include/agg_vertex_sequence.h", | ||||
|         "agg_vpgen_clip_polygon.h": "./include/agg_vpgen_clip_polygon.h", | ||||
|         "agg_vpgen_clip_polyline.h": "./include/agg_vpgen_clip_polyline.h", | ||||
|         "agg_vpgen_segmentator.h": "./include/agg_vpgen_segmentator.h", | ||||
|     }, | ||||
| ) | ||||
							
								
								
									
										21
									
								
								dep/emu/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								dep/emu/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| ifeq ($(OS), Windows_NT) | ||||
|  | ||||
| EMU_SRCS = \ | ||||
| 	dep/emu/fnmatch.c | ||||
|  | ||||
| EMU_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(EMU_SRCS)) | ||||
| $(EMU_OBJS): CFLAGS += -Idep/emu | ||||
| EMU_LIB = $(OBJDIR)/libemu.a | ||||
| $(EMU_LIB): $(EMU_OBJS) | ||||
| EMU_CFLAGS = -Idep/emu | ||||
| EMU_LDFLAGS = $(EMU_LIB) | ||||
| OBJS += $(EMU_OBJS) | ||||
|  | ||||
| else | ||||
|  | ||||
| EMU_LIB = | ||||
| EMU_CFLAGS = | ||||
| EMU_LDFLAGS = | ||||
|  | ||||
| endif | ||||
|  | ||||
| @@ -1,3 +0,0 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary(name="emu", srcs=["./fnmatch.c"], hdrs={"fnmatch.h": "./fnmatch.h"}) | ||||
							
								
								
									
										13
									
								
								dep/fatfs/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								dep/fatfs/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| FATFS_SRCS = \ | ||||
| 	dep/fatfs/source/ff.c \ | ||||
| 	dep/fatfs/source/ffsystem.c \ | ||||
| 	dep/fatfs/source/ffunicode.c \ | ||||
| 	 | ||||
| FATFS_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(FATFS_SRCS)) | ||||
| $(FATFS_OBJS): CFLAGS += -Idep/fatfs/source | ||||
| FATFS_LIB = $(OBJDIR)/libfatfs.a | ||||
| $(FATFS_LIB): $(FATFS_OBJS) | ||||
| FATFS_CFLAGS = -Idep/fatfs/source | ||||
| FATFS_LDFLAGS = $(FATFS_LIB) | ||||
| OBJS += $(FATFS_OBJS) | ||||
|  | ||||
| @@ -1,18 +0,0 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="fatfs", | ||||
|     srcs=[ | ||||
|         "./source/ff.c", | ||||
|         "./source/ffsystem.c", | ||||
|         "./source/ffunicode.c", | ||||
|         "./source/ff.h", | ||||
|         "./source/ffconf.h", | ||||
|         "./source/diskio.h", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "ff.h": "./source/ff.h", | ||||
|         "ffconf.h": "./source/ffconf.h", | ||||
|         "diskio.h": "./source/diskio.h", | ||||
|     }, | ||||
| ) | ||||
							
								
								
									
										22
									
								
								dep/hfsutils/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								dep/hfsutils/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| HFSUTILS_SRCS = \ | ||||
| 	dep/hfsutils/libhfs/block.c \ | ||||
| 	dep/hfsutils/libhfs/btree.c \ | ||||
| 	dep/hfsutils/libhfs/data.c \ | ||||
| 	dep/hfsutils/libhfs/file.c \ | ||||
| 	dep/hfsutils/libhfs/hfs.c \ | ||||
| 	dep/hfsutils/libhfs/low.c \ | ||||
| 	dep/hfsutils/libhfs/medium.c \ | ||||
| 	dep/hfsutils/libhfs/memcmp.c \ | ||||
| 	dep/hfsutils/libhfs/node.c \ | ||||
| 	dep/hfsutils/libhfs/record.c \ | ||||
| 	dep/hfsutils/libhfs/version.c \ | ||||
| 	dep/hfsutils/libhfs/volume.c \ | ||||
| 	 | ||||
| HFSUTILS_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(HFSUTILS_SRCS)) | ||||
| $(HFSUTILS_OBJS): CFLAGS += -Idep/hfsutils/libhfs | ||||
| HFSUTILS_LIB = $(OBJDIR)/libhfsutils.a | ||||
| $(HFSUTILS_LIB): $(HFSUTILS_OBJS) | ||||
| HFSUTILS_CFLAGS = -Idep/hfsutils/libhfs | ||||
| HFSUTILS_LDFLAGS = $(HFSUTILS_LIB) | ||||
| OBJS += $(HFSUTILS_OBJS) | ||||
|  | ||||
| @@ -1,25 +0,0 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="hfsutils", | ||||
|     srcs=[ | ||||
|         "./libhfs/block.c", | ||||
|         "./libhfs/btree.c", | ||||
|         "./libhfs/data.c", | ||||
|         "./libhfs/file.c", | ||||
|         "./libhfs/hfs.c", | ||||
|         "./libhfs/low.c", | ||||
|         "./libhfs/medium.c", | ||||
|         "./libhfs/memcmp.c", | ||||
|         "./libhfs/node.c", | ||||
|         "./libhfs/record.c", | ||||
|         "./libhfs/version.c", | ||||
|         "./libhfs/volume.c", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "apple.h": "./libhfs/apple.h", | ||||
|         "hfs.h": "./libhfs/hfs.h", | ||||
|         "libhfs.h": "./libhfs/libhfs.h", | ||||
|         "os.h": "./libhfs/os.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -1,4 +1,4 @@ | ||||
| cmake_minimum_required (VERSION 3.10.0) | ||||
| cmake_minimum_required (VERSION 2.8.11) | ||||
|  | ||||
| # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. | ||||
| if (POLICY CMP0025) | ||||
| @@ -18,7 +18,7 @@ endif () | ||||
| project (libusbp) | ||||
|  | ||||
| set (LIBUSBP_VERSION_MAJOR 1) | ||||
| set (LIBUSBP_VERSION_MINOR 3) | ||||
| set (LIBUSBP_VERSION_MINOR 2) | ||||
| set (LIBUSBP_VERSION_PATCH 0) | ||||
|  | ||||
| # Make 'Release' be the default build type, since the debug builds | ||||
| @@ -49,8 +49,28 @@ set(VBOX_LINUX_ON_WINDOWS FALSE CACHE BOOL | ||||
| set(ENABLE_GCOV FALSE CACHE BOOL | ||||
|   "Compile with special options needed for gcov.") | ||||
|  | ||||
| set (CMAKE_C_STANDARD 99) | ||||
| set (CMAKE_CXX_STANDARD 11) | ||||
| # Our C code uses features from the C99 standard. | ||||
| macro(use_c99) | ||||
|   if (CMAKE_VERSION VERSION_LESS "3.1") | ||||
|     if (CMAKE_C_COMPILER_ID STREQUAL "GNU") | ||||
|       set (CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}") | ||||
|     endif () | ||||
|   else () | ||||
|     set (CMAKE_C_STANDARD 99) | ||||
|   endif () | ||||
| endmacro(use_c99) | ||||
|  | ||||
| # Our C++ code uses features from the C++11 standard. | ||||
| macro(use_cxx11) | ||||
|   if (CMAKE_VERSION VERSION_LESS "3.1") | ||||
|     if (CMAKE_C_COMPILER_ID STREQUAL "GNU") | ||||
|       # Use --std=gnu++0x instead of --std=gnu++11 in order to support GCC 4.6. | ||||
|       set (CMAKE_CXX_FLAGS "--std=gnu++0x ${CMAKE_C_FLAGS}") | ||||
|     endif () | ||||
|   else () | ||||
|     set (CMAKE_CXX_STANDARD 11) | ||||
|   endif () | ||||
| endmacro(use_cxx11) | ||||
|  | ||||
| set (LIBUSBP_VERSION ${LIBUSBP_VERSION_MAJOR}.${LIBUSBP_VERSION_MINOR}.${LIBUSBP_VERSION_PATCH}) | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| # libusbp: Pololu USB Library | ||||
|  | ||||
| Version: 1.2.0<br/> | ||||
| Release date: 2020-11-16<br/> | ||||
| [www.pololu.com](https://www.pololu.com/) | ||||
|  | ||||
| The **Pololu USB Library** (also known as **libusbp**) is a cross-platform C library for accessing USB devices. | ||||
| @@ -15,7 +17,7 @@ The **Pololu USB Library** (also known as **libusbp**) is a cross-platform C lib | ||||
| - Provides detailed error information to the caller. | ||||
|   - Each error includes one or more English sentences describing the error, including error codes from underlying APIs. | ||||
|   - Some errors have libusbp-defined error codes that can be used to programmatically decide how to handle the error. | ||||
| - Provides an object-oriented C++ wrapper. | ||||
| - Provides an object-oriented C++ wrapper (using features of C++11). | ||||
| - Provides access to underlying identifiers, handles, and file descriptors. | ||||
|  | ||||
|  | ||||
| @@ -137,9 +139,9 @@ If you are using GCC and a shell that supports Bash-like syntax, here is an exam | ||||
|  | ||||
|     gcc program.c `pkg-config --cflags --libs libusbp-1` | ||||
|  | ||||
| Here is an equivalent command for C++: | ||||
| Here is an equivalent command for C++.  Note that we use the `--std=gnu++11` option because the libusbp C++ API requires features from C++11: | ||||
|  | ||||
|     g++ program.cpp `pkg-config --cflags --libs libusbp-1` | ||||
|     g++ --std=gnu++11 program.cpp `pkg-config --cflags --libs libusbp-1` | ||||
|  | ||||
| The order of the arguments above matters: the user program must come before libusbp because it relies on symbols that are defined by libusbp. | ||||
|  | ||||
| @@ -165,9 +167,6 @@ For detailed documentation of this library, see the header files `libusb.h` and | ||||
|  | ||||
| ## Version history | ||||
|  | ||||
| * 1.3.0 (2023-01-02): | ||||
|   * Windows: Added support for detecting FTDI serial ports.  (FTDI devices with more than one port have not been tested and the interface for detecting them might change in the future.) | ||||
|   * macOS: Fixed the detection of serial ports for devices that are not CDC ACM. | ||||
| * 1.2.0 (2020-11-16): | ||||
|   * Linux: Made the library work with devices attached to the cp210x driver. | ||||
|   * Windows: Made the library work with devices that have lowercase letters in their hardware IDs. | ||||
|   | ||||
| @@ -1,3 +1,2 @@ | ||||
| This is version 1.3.0 taken from https://github.com/pololu/libusbp on | ||||
| 2023-05-06. | ||||
| This was taken from https://github.com/pololu/libusbp on 2021-12-11. | ||||
|  | ||||
|   | ||||
							
								
								
									
										61
									
								
								dep/libusbp/build.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								dep/libusbp/build.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| LIBUSBP_SRCS = \ | ||||
| 	dep/libusbp/src/async_in_pipe.c \ | ||||
| 	dep/libusbp/src/error.c \ | ||||
| 	dep/libusbp/src/error_hresult.c \ | ||||
| 	dep/libusbp/src/find_device.c \ | ||||
| 	dep/libusbp/src/list.c \ | ||||
| 	dep/libusbp/src/pipe_id.c \ | ||||
| 	dep/libusbp/src/string.c \ | ||||
| 	 | ||||
| ifeq ($(OS), Windows_NT) | ||||
|  | ||||
| LIBUSBP_LDFLAGS += -lsetupapi -lwinusb -lole32 -luuid | ||||
| LIBUSBP_SRCS += \ | ||||
| 	dep/libusbp/src/windows/async_in_transfer_windows.c \ | ||||
| 	dep/libusbp/src/windows/device_instance_id_windows.c \ | ||||
| 	dep/libusbp/src/windows/device_windows.c \ | ||||
| 	dep/libusbp/src/windows/error_windows.c \ | ||||
| 	dep/libusbp/src/windows/generic_handle_windows.c \ | ||||
| 	dep/libusbp/src/windows/generic_interface_windows.c \ | ||||
| 	dep/libusbp/src/windows/interface_windows.c \ | ||||
| 	dep/libusbp/src/windows/list_windows.c \ | ||||
| 	dep/libusbp/src/windows/serial_port_windows.c \ | ||||
|  | ||||
| else ifeq ($(shell uname),Darwin) | ||||
|  | ||||
| LIBUSBP_SRCS += \ | ||||
| 	dep/libusbp/src/mac/async_in_transfer_mac.c \ | ||||
| 	dep/libusbp/src/mac/device_mac.c \ | ||||
| 	dep/libusbp/src/mac/error_mac.c \ | ||||
| 	dep/libusbp/src/mac/generic_handle_mac.c \ | ||||
| 	dep/libusbp/src/mac/generic_interface_mac.c \ | ||||
| 	dep/libusbp/src/mac/iokit_mac.c \ | ||||
| 	dep/libusbp/src/mac/list_mac.c \ | ||||
| 	dep/libusbp/src/mac/serial_port_mac.c \ | ||||
|  | ||||
| else | ||||
|  | ||||
| LIBUSBP_CFLAGS += $(shell pkg-config --cflags libudev) | ||||
| LIBUSBP_LDFLAGS += $(shell pkg-config --libs libudev) | ||||
| LIBUSBP_SRCS += \ | ||||
| 	dep/libusbp/src/linux/async_in_transfer_linux.c \ | ||||
| 	dep/libusbp/src/linux/device_linux.c \ | ||||
| 	dep/libusbp/src/linux/error_linux.c \ | ||||
| 	dep/libusbp/src/linux/generic_handle_linux.c \ | ||||
| 	dep/libusbp/src/linux/generic_interface_linux.c \ | ||||
| 	dep/libusbp/src/linux/list_linux.c \ | ||||
| 	dep/libusbp/src/linux/serial_port_linux.c \ | ||||
| 	dep/libusbp/src/linux/udev_linux.c \ | ||||
| 	dep/libusbp/src/linux/usbfd_linux.c \ | ||||
|  | ||||
| endif | ||||
|  | ||||
| LIBUSBP_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(LIBUSBP_SRCS)) | ||||
| $(LIBUSBP_OBJS): private CFLAGS += -Idep/libusbp/src -Idep/libusbp/include | ||||
| LIBUSBP_LIB = $(OBJDIR)/libusbp.a | ||||
| LIBUSBP_CFLAGS += -Idep/libusbp/include | ||||
| LIBUSBP_LDFLAGS += $(LIBUSBP_LIB) | ||||
| $(LIBUSBP_LIB): $(LIBUSBP_OBJS) | ||||
| OBJS += $(LIBUSBP_OBJS) | ||||
|  | ||||
|  | ||||
| @@ -1,72 +0,0 @@ | ||||
| from build.ab import emit | ||||
| from build.c import clibrary | ||||
| from build.pkg import package | ||||
| from config import windows, osx, unix | ||||
|  | ||||
| srcs = [ | ||||
|     "./src/async_in_pipe.c", | ||||
|     "./src/error.c", | ||||
|     "./src/error_hresult.c", | ||||
|     "./src/find_device.c", | ||||
|     "./src/list.c", | ||||
|     "./src/pipe_id.c", | ||||
|     "./src/string.c", | ||||
|     "./src/libusbp_internal.h", | ||||
|     "./include/libusbp_config.h", | ||||
|     "./include/libusbp.h", | ||||
| ] | ||||
| deps = [] | ||||
| ldflags = [] | ||||
|  | ||||
| if windows: | ||||
|     srcs += [ | ||||
|         "./src/windows/async_in_transfer_windows.c", | ||||
|         "./src/windows/device_instance_id_windows.c", | ||||
|         "./src/windows/device_windows.c", | ||||
|         "./src/windows/error_windows.c", | ||||
|         "./src/windows/generic_handle_windows.c", | ||||
|         "./src/windows/generic_interface_windows.c", | ||||
|         "./src/windows/interface_windows.c", | ||||
|         "./src/windows/list_windows.c", | ||||
|         "./src/windows/serial_port_windows.c", | ||||
|     ] | ||||
|     ldflags += ["-lsetupapi", "-lwinusb", "-lole32", "-luuid"] | ||||
| elif osx: | ||||
|     srcs += [ | ||||
|         "./src/mac/async_in_transfer_mac.c", | ||||
|         "./src/mac/device_mac.c", | ||||
|         "./src/mac/error_mac.c", | ||||
|         "./src/mac/generic_handle_mac.c", | ||||
|         "./src/mac/generic_interface_mac.c", | ||||
|         "./src/mac/iokit_mac.c", | ||||
|         "./src/mac/list_mac.c", | ||||
|         "./src/mac/serial_port_mac.c", | ||||
|     ] | ||||
| else: | ||||
|     package(name="udev_lib", package="libudev") | ||||
|     srcs += [ | ||||
|         "./src/linux/async_in_transfer_linux.c", | ||||
|         "./src/linux/device_linux.c", | ||||
|         "./src/linux/error_linux.c", | ||||
|         "./src/linux/generic_handle_linux.c", | ||||
|         "./src/linux/generic_interface_linux.c", | ||||
|         "./src/linux/list_linux.c", | ||||
|         "./src/linux/serial_port_linux.c", | ||||
|         "./src/linux/udev_linux.c", | ||||
|         "./src/linux/usbfd_linux.c", | ||||
|     ] | ||||
|     deps += [".+udev_lib"] | ||||
|  | ||||
| clibrary( | ||||
|     name="libusbp", | ||||
|     srcs=srcs, | ||||
|     cflags=["-Idep/libusbp/include", "-Idep/libusbp/src"], | ||||
|     ldflags=ldflags, | ||||
|     deps=deps, | ||||
|     hdrs={ | ||||
|         "libusbp_internal.h": "./src/libusbp_internal.h", | ||||
|         "libusbp_config.h": "./include/libusbp_config.h", | ||||
|         "libusbp.hpp": "./include/libusbp.hpp", | ||||
|         "libusbp.h": "./include/libusbp.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(async_in async_in.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(lsport lsport.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(lsusb lsusb.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(port_name port_name.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -41,6 +41,7 @@ extern "C" { | ||||
| #ifdef LIBUSBP_STATIC | ||||
| #  define LIBUSBP_API | ||||
| #else | ||||
| #error not static | ||||
| #  ifdef LIBUSBP_EXPORTS | ||||
| #    define LIBUSBP_API LIBUSBP_DLL_EXPORT | ||||
| #  else | ||||
|   | ||||
| @@ -107,7 +107,7 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer. */ | ||||
|         explicit unique_pointer_wrapper(T * p = NULL) noexcept | ||||
|         explicit unique_pointer_wrapper(T * p = nullptr) noexcept | ||||
|             : pointer(p) | ||||
|         { | ||||
|         } | ||||
| @@ -133,9 +133,9 @@ namespace libusbp | ||||
|  | ||||
|         /*! Implicit conversion to bool.  Returns true if the underlying pointer | ||||
|          *  is not NULL. */ | ||||
|         operator bool() const noexcept | ||||
|         explicit operator bool() const noexcept | ||||
|         { | ||||
|             return pointer != NULL; | ||||
|             return pointer != nullptr; | ||||
|         } | ||||
|  | ||||
|         /*! Returns the underlying pointer. */ | ||||
| @@ -146,19 +146,19 @@ namespace libusbp | ||||
|  | ||||
|         /*! Sets the underlying pointer to the specified value, freeing the | ||||
|          * previous pointer and taking ownership of the specified one. */ | ||||
|         void pointer_reset(T * p = NULL) noexcept | ||||
|         void pointer_reset(T * p = nullptr) noexcept | ||||
|         { | ||||
|             pointer_free(pointer); | ||||
|             pointer = p; | ||||
|         } | ||||
|  | ||||
|         /*! Releases the pointer, transferring ownership of it to the caller and | ||||
|          * resetting the underlying pointer of this object to NULL.  The caller | ||||
|          * resetting the underlying pointer of this object to nullptr.  The caller | ||||
|          * is responsible for freeing the returned pointer if it is not NULL. */ | ||||
|         T * pointer_release() noexcept | ||||
|         { | ||||
|             T * p = pointer; | ||||
|             pointer = NULL; | ||||
|             pointer = nullptr; | ||||
|             return p; | ||||
|         } | ||||
|  | ||||
| @@ -193,14 +193,14 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer. */ | ||||
|         explicit unique_pointer_wrapper_with_copy(T * p = NULL) noexcept | ||||
|         explicit unique_pointer_wrapper_with_copy(T * p = nullptr) noexcept | ||||
|             : unique_pointer_wrapper<T>(p) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Move constructor. */ | ||||
|         unique_pointer_wrapper_with_copy( | ||||
|             unique_pointer_wrapper_with_copy && other) = default; | ||||
|             unique_pointer_wrapper_with_copy && other) noexcept = default; | ||||
|  | ||||
|         /*! Copy constructor */ | ||||
|         unique_pointer_wrapper_with_copy( | ||||
| @@ -228,14 +228,13 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  */ | ||||
|         explicit error(libusbp_error * p = NULL) noexcept | ||||
|         explicit error(libusbp_error * p = nullptr) noexcept | ||||
|             : unique_pointer_wrapper_with_copy(p) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Wrapper for libusbp_error_get_message(). */ | ||||
|         virtual const char * what() const noexcept override | ||||
|         { | ||||
|         const char * what() const noexcept override { | ||||
|             return libusbp_error_get_message(pointer); | ||||
|         } | ||||
|  | ||||
| @@ -256,7 +255,7 @@ namespace libusbp | ||||
|     /*! \cond */ | ||||
|     inline void throw_if_needed(libusbp_error * err) | ||||
|     { | ||||
|         if (err != NULL) | ||||
|         if (err != nullptr) | ||||
|         { | ||||
|             throw error(err); | ||||
|         } | ||||
| @@ -268,7 +267,7 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer. */ | ||||
|         explicit async_in_pipe(libusbp_async_in_pipe * pointer = NULL) | ||||
|         explicit async_in_pipe(libusbp_async_in_pipe * pointer = nullptr) | ||||
|             : unique_pointer_wrapper(pointer) | ||||
|         { | ||||
|         } | ||||
| @@ -304,8 +303,8 @@ namespace libusbp | ||||
|         bool handle_finished_transfer(void * buffer, size_t * transferred, | ||||
|             error * transfer_error) | ||||
|         { | ||||
|             libusbp_error ** error_out = NULL; | ||||
|             if (transfer_error != NULL) | ||||
|             libusbp_error ** error_out = nullptr; | ||||
|             if (transfer_error != nullptr) | ||||
|             { | ||||
|                 transfer_error->pointer_reset(); | ||||
|                 error_out = transfer_error->pointer_to_pointer_get(); | ||||
| @@ -329,7 +328,7 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer. */ | ||||
|         explicit device(libusbp_device * pointer = NULL) : | ||||
|         explicit device(libusbp_device * pointer = nullptr) : | ||||
|             unique_pointer_wrapper_with_copy(pointer) | ||||
|         { | ||||
|         } | ||||
| @@ -388,7 +387,7 @@ namespace libusbp | ||||
|         std::vector<device> vector; | ||||
|         for(size_t i = 0; i < size; i++) | ||||
|         { | ||||
|             vector.push_back(device(device_list[i])); | ||||
|             vector.emplace_back(device_list[i]); | ||||
|         } | ||||
|         libusbp_list_free(device_list); | ||||
|         return vector; | ||||
| @@ -409,13 +408,13 @@ namespace libusbp | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  This object will free the pointer | ||||
|          *  when it is destroyed. */ | ||||
|         explicit generic_interface(libusbp_generic_interface * pointer = NULL) | ||||
|         explicit generic_interface(libusbp_generic_interface * pointer = nullptr) | ||||
|             : unique_pointer_wrapper_with_copy(pointer) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Wrapper for libusbp_generic_interface_create. */ | ||||
|         generic_interface(const device & device, | ||||
|         explicit generic_interface(const device & device, | ||||
|             uint8_t interface_number = 0, bool composite = false) | ||||
|         { | ||||
|             throw_if_needed(libusbp_generic_interface_create( | ||||
| @@ -449,13 +448,13 @@ namespace libusbp | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  This object will free the pointer | ||||
|          *  when it is destroyed. */ | ||||
|         explicit generic_handle(libusbp_generic_handle * pointer = NULL) noexcept | ||||
|         explicit generic_handle(libusbp_generic_handle * pointer = nullptr) noexcept | ||||
|             : unique_pointer_wrapper(pointer) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Wrapper for libusbp_generic_handle_open(). */ | ||||
|         generic_handle(const generic_interface & gi) | ||||
|         explicit generic_handle(const generic_interface & gi) | ||||
|         { | ||||
|             throw_if_needed(libusbp_generic_handle_open(gi.pointer_get(), &pointer)); | ||||
|         } | ||||
| @@ -487,9 +486,9 @@ namespace libusbp | ||||
|             uint8_t bRequest, | ||||
|             uint16_t wValue, | ||||
|             uint16_t wIndex, | ||||
|             void * buffer = NULL, | ||||
|             void * buffer = nullptr, | ||||
|             uint16_t wLength = 0, | ||||
|             size_t * transferred = NULL) | ||||
|             size_t * transferred = nullptr) | ||||
|         { | ||||
|             throw_if_needed(libusbp_control_transfer(pointer, | ||||
|                 bmRequestType, bRequest, wValue, wIndex, | ||||
| @@ -543,13 +542,13 @@ namespace libusbp | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  This object will free the pointer | ||||
|          *  when it is destroyed. */ | ||||
|         explicit serial_port(libusbp_serial_port * pointer = NULL) | ||||
|         explicit serial_port(libusbp_serial_port * pointer = nullptr) | ||||
|             : unique_pointer_wrapper_with_copy(pointer) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Wrapper for libusbp_serial_port_create(). */ | ||||
|         serial_port(const device & device, | ||||
|         explicit serial_port(const device & device, | ||||
|             uint8_t interface_number = 0, bool composite = false) | ||||
|         { | ||||
|             throw_if_needed(libusbp_serial_port_create( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_c99() | ||||
|  | ||||
| add_library (install_helper SHARED install_helper_windows.c dll.def) | ||||
|  | ||||
| target_link_libraries (install_helper setupapi msi) | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_async_in test_async_in.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_long_read test_long_read.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_long_write test_long_write.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_transitions test_transitions.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| use_c99() | ||||
|  | ||||
| # Settings for GCC | ||||
| if (CMAKE_C_COMPILER_ID STREQUAL "GNU") | ||||
|   # By default, symbols are not visible outside of the library. | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user