From 34c697e2aad89d9dd33d29ba3fa665429a4bcc0f Mon Sep 17 00:00:00 2001 From: David Kuder Date: Thu, 13 Apr 2023 04:15:46 -0400 Subject: [PATCH] Menu changes --- Makefile | 251 +++++++ src/cfgtoken.h | 55 ++ src/config.c | 1766 ++++++++++++++++++++++++++++++++++++++++++++++++ src/fontmgr.c | 765 +++++++++++++++++++++ src/menu.c | 21 +- src/v2analog.h | 110 +-- 6 files changed, 2849 insertions(+), 119 deletions(-) create mode 100644 Makefile create mode 100644 src/cfgtoken.h create mode 100644 src/config.c create mode 100644 src/fontmgr.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..097bfaf --- /dev/null +++ b/Makefile @@ -0,0 +1,251 @@ +DISK525A_OBJS = menu config +DISK525B_OBJS = menu +DISK525C_OBJS = menu fontmgr +DISK525D_OBJS = menu fontmgr +DISK35_OBJS = menu config fontmgr + +FONT_OBJS = 01.us.une.cf 02.clintonv1.cf 03.reactive.cf 04.danpaymar.cf \ + 05.blippo.cf 06.byte.cf 07.colossal.cf 08.count.cf \ + 09.flow.cf 0a.gothic.cf 0b.outline.cf 0c.pigfont.cf \ + 0d.pinocchio.cf 0e.slant.cf 0f.stop.cf 10.euro.une.cf \ + 11.euro.enh.cf 12.clintonv2.cf 13.germanenh.cf 14.germanune.cf \ + 15.frenchenh.cf 16.frenchune.cf 17.hebrewenh.cf 18.hebrewune.cf \ + 19.plus.enh.cf 1a.plus.une.cf 1b.katakana.cf 1c.cyrillic.cf \ + 1d.greek.cf 1e.esperanto.cf 1f.videx.cf 20.plus.une.cf \ + 21.us.enh.cf 22.us.enh.cf 23.cyrillic.cf 24.pcbold.cf + +SYSTEM_TARGETS = menu +BASE_TARGETS = menu config fontmgr +ENH_TARGETS = menu config fontmgr +DISK_TARGETS = disk35 disk525a disk525b disk525c disk525d + + +# For this one see https://applecommander.github.io/ +AC ?= tools/ac.jar +ACX ?= tools/acx.jar +DEFLATE ?= tools/deflater + +# Just the usual way to find out if we're +# using cmd.exe to execute make rules. +ifneq ($(shell echo),) + CMD_EXE = 1 +endif + +ifdef CMD_EXE + NULLDEV = nul: + DEL = -del /f + RMDIR = rmdir /s /q +else + NULLDEV = /dev/null + DEL = $(RM) + RMDIR = $(RM) -r +endif + +ifdef CC65_HOME + AS = $(CC65_HOME)/bin/ca65 + CC = $(CC65_HOME)/bin/cc65 + CL = $(CC65_HOME)/bin/cl65 + LD = $(CC65_HOME)/bin/ld65 +else + AS := $(if $(wildcard ../../bin/ca65*),../../bin/ca65,ca65) + CC := $(if $(wildcard ../../bin/cc65*),../../bin/cc65,cc65) + CL := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65) + LD := $(if $(wildcard ../../bin/ld65*),../../bin/ld65,ld65) +endif + +ENFORCESIZE = @(FILESIZE=`stat -c%s $1` ; \ + if [ $2 -gt 0 ]; then \ + if [ $$FILESIZE -gt $2 ] ; then \ + echo "ERROR: File $1 exceeds size limit ($$FILESIZE > $2)" ; \ + exit 1 ; \ + fi ; \ + fi ) + +OBJDIR = obj +SRCDIR = src + +all: binaries disks +binaries: fonts systems bases enhs +fonts: $(addprefix $(OBJDIR)/,$(FONT_OBJS)) +systems: fonts $(addprefix $(OBJDIR)/,$(addsuffix .system,$(SYSTEM_TARGETS))) +bases: $(addprefix $(OBJDIR)/,$(addsuffix .base,$(BASE_TARGETS))) +enhs: $(addprefix $(OBJDIR)/,$(addsuffix .enh,$(ENH_TARGETS))) +disks: $(addprefix $(OBJDIR)/,$(addsuffix .po,$(DISK_TARGETS))) + +.PHONY: binaries fonts systems bases enhs disks $(SYSTEM_TARGETS) + +$(OBJDIR)/%.xf: fonts/00.us.enh.pf fonts/%.pf + tools/xorfont US.ENH....00.PF $^ $@ + +$(OBJDIR)/%.cf: $(OBJDIR)/%.xf + tools/rlefont $< $@ + +$(OBJDIR)/%.base: $(SRCDIR)/%.c + $(CL) -O -t apple2 -C apple2-system.cfg -m $@.map -o $@.AppleSingle $^ + @~/applesingle/applesingle -r < $@.AppleSingle > $@ 2>$(NULLDEV) + @echo $@"\r\t\t\t" `wc -c $@ | cut -d ' ' -f 1` + +$(OBJDIR)/%.enh: $(SRCDIR)/%.c + $(CL) -O -t apple2enh -C apple2-system.cfg -m $@.map -o $@.AppleSingle $^ + @~/applesingle/applesingle -r < $@.AppleSingle > $@ 2>$(NULLDEV) + @echo $@"\r\t\t\t" `wc -c $@ | cut -d ' ' -f 1` + +$(OBJDIR)/%.system: $(SRCDIR)/loader.c + $(CL) -O -t apple2 -DNEXTNAME=\"`echo $(notdir $(basename $@)) | tr a-z A-Z`\" -C apple2-system.cfg -m $@.map -o $@.AppleSingle $(SRCDIR)/loader.c + @~/applesingle/applesingle -r < $@.AppleSingle > $@ 2>$(NULLDEV) + @echo $@"\r\t\t\t" `wc -c $@ | cut -d ' ' -f 1` + +$(OBJDIR)/disk525a.po: $(OBJDIR)/menu.system $(addprefix $(OBJDIR)/,$(addsuffix .base,$(DISK525A_OBJS))) $(addprefix $(OBJDIR)/,$(addsuffix .enh,$(DISK525A_OBJS))) + @cp prodos/pd525.po $@ + java -jar $(AC) -n $@ V2A.SIDEA + java -jar $(AC) -p $@ MENU.SYSTEM SYS 0x2000 <$(OBJDIR)/menu.system + java -jar $(AC) -p $@ MENU.BASE SYS 0x2000 <$(OBJDIR)/menu.base + java -jar $(AC) -p $@ MENU.ENH SYS 0x2000 <$(OBJDIR)/menu.enh + java -jar $(AC) -p $@ CONFIG.BASE SYS 0x2000 <$(OBJDIR)/config.base + java -jar $(AC) -p $@ CONFIG.ENH SYS 0x2000 <$(OBJDIR)/config.enh + java -jar $(AC) -p $@ BASIC.SYSTEM SYS 0x2000 $(NULLDEV) + diff --git a/src/cfgtoken.h b/src/cfgtoken.h new file mode 100644 index 0000000..bd04c89 --- /dev/null +++ b/src/cfgtoken.h @@ -0,0 +1,55 @@ + +#define NEWCONFIG_MAGIC 0x0001434E // "NC\x01\x00" +#define NEWCONFIG_EOF_MARKER 0x00464F45 // "EOF\x00" +#define CFGTOKEN_REVISION 0x0001434E // "RV\xXX\x00" + +#define CFGTOKEN_MODE_VGA 0x0000564D // "MV\x00\x00" VGA +#define CFGTOKEN_MODE_PCPI 0x00005A4D // "MZ\x00\x00" PCPI Applicard +#define CFGTOKEN_MODE_SER 0x0000534D // "MS\x00\x00" Serial +#define CFGTOKEN_MODE_PAR 0x0000504D // "MP\x00\x00" Parallel +#define CFGTOKEN_MODE_SNES 0x0000474D // "MG\x00\x00" SNESMAX +#define CFGTOKEN_MODE_NET 0x0000454D // "ME\x00\x00" Ethernet +#define CFGTOKEN_MODE_FILE 0x0000464D // "MF\x00\x00" Filesystem + +#define CFGTOKEN_HOST_AUTO 0x00004148 // "HA\x00\x00" Autodetect +#define CFGTOKEN_HOST_II 0x00003248 // "H2\x00\x00" II/II+ +#define CFGTOKEN_HOST_IIE 0x00004548 // "HE\x00\x00" IIe +#define CFGTOKEN_HOST_IIGS 0x00004748 // "HG\x00\x00" IIgs +#define CFGTOKEN_HOST_PRAVETZ 0x00005048 // "HP\x00\x00" Pravetz +#define CFGTOKEN_HOST_BASIS 0x00004248 // "HB\x00\x00" Basis 108 + +#define CFGTOKEN_MUX_LOOP 0x00004C53 // "SL\x00\x00" Serial Loopback +#define CFGTOKEN_MUX_UART 0x00005353 // "SS\x00\x00" UART +#define CFGTOKEN_MUX_USB 0x00005553 // "SU\x00\x00" USB CDC +#define CFGTOKEN_MUX_WIFI 0x00005753 // "SW\x00\x00" WiFi Modem +#define CFGTOKEN_MUX_PRN 0x00005053 // "SP\x00\x00" WiFi Printer +#define CFGTOKEN_SER_BAUD 0x02004253 // "SB\x00\x01" Serial Baudrate Divisor + +#define CFGTOKEN_USB_HOST 0x00004855 // "UH\x00\x00" USB CDC Host +#define CFGTOKEN_USB_GUEST 0x00004755 // "UG\x00\x00" USB CDC Guest Device +#define CFGTOKEN_USB_MIDI 0x00004D55 // "UM\x00\x00" USB MIDI Guest Device + +#define CFGTOKEN_WIFI_AP 0x00004157 // "WA\x00\x00" WiFi AP +#define CFGTOKEN_WIFI_CL 0x00004357 // "WC\x00\x00" WiFi Client + +#define CFGTOKEN_WIFI_SSID 0x00005357 // "WS\x00\xSS" WiFi SSID +#define CFGTOKEN_WIFI_PSK 0x00005057 // "WP\x00\xSS" WiFi PSK + +#define CFGTOKEN_WIFI_IP 0x04004957 // "WI\x00\xSS" WiFi IP +#define CFGTOKEN_WIFI_NM 0x04004E57 // "WN\x00\xSS" WiFi Netmask + +#define CFGTOKEN_JD_HOST 0x0000484A // "JH\x00\x01" JetDirect Hostname +#define CFGTOKEN_JD_PORT 0x0200444A // "JD\x00\x01" JetDirect Port + +#define CFGTOKEN_MONO_00 0x00005056 // "VP\x00\x00" Full Color Video +#define CFGTOKEN_MONO_80 0x00805056 // "VP\x80\x00" B&W Video +#define CFGTOKEN_MONO_90 0x00905056 // "VP\x90\x00" B&W Inverse +#define CFGTOKEN_MONO_A0 0x00A05056 // "VP\xA0\x00" Amber +#define CFGTOKEN_MONO_B0 0x00B05056 // "VP\xB0\x00" Amber Inverse +#define CFGTOKEN_MONO_C0 0x00C05056 // "VP\xC0\x00" Green +#define CFGTOKEN_MONO_D0 0x00D05056 // "VP\xD0\x00" Green Inverse +#define CFGTOKEN_MONO_E0 0x00E05056 // "VP\xE0\x00" C64 +#define CFGTOKEN_MONO_F0 0x00F05056 // "VP\xF0\x00" Custom + +#define CFGTOKEN_TBCOLOR 0x00005456 // "VT\xXX\x00" Custom default TBCOLOR +#define CFGTOKEN_BORDER 0x00004256 // "VB\xXX\x00" Custom default BORDER diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..39d75b8 --- /dev/null +++ b/src/config.c @@ -0,0 +1,1766 @@ +#include +#include +#include +#include +#include +#include +#include "v2types.h" +#include "cfgtoken.h" +#include "v2loader.h" + +#define PROGNAME "Config Utility" +volatile uint16_t cardslot = 3; + +#include "v2analog.h" +#include "menu.h" + +#define menutop 3 +#define menuleft 2 + +uint16_t cfb; + +serialmux_t serialmux[2] = { SERIAL_PRINTER, SERIAL_WIFI }; +uint16_t baud[2] = { 19200, 19200 }; + +usbmux_t usbmux = USB_GUEST_CDC; +compat_t machine = MACHINE_AUTO; +wifimode_t wifimode = WIFI_AP; +char wifi_ssid[32] = "V2RetroNet"; +char wifi_psk[32] = "Analog"; +uint32_t wifi_address = 0x00000000; +uint32_t wifi_netmask = 0xFFFFFF00; + +char jd_host[32] = "192.168.0.1"; +uint16_t jd_port = 9100; + +uint8_t blockbuffer[4096]; + +#define CARD_TIMEOUT 0x3fff +uint16_t timeout = CARD_TIMEOUT; + +uint8_t default_font = 0; +uint8_t mono_palette = 0; +uint8_t terminal_fgcolor = 0xF; +uint8_t terminal_bgcolor = 0x0; +uint8_t terminal_border = 0x0; + +uint8_t config_rev = 0x00; + +typedef struct menu_strings_s { + char *str; +} menu_strings_t; + +uint16_t baudvalue[9] = { + 75, 150, 300, 600, 1200, 2400, 4800, 9600, 19200 +}; + +menu_strings_t baud_strings[9] = { + { "75" }, + { "150" }, + { "300" }, + { "600" }, + { "1200" }, + { "2400" }, + { "4800" }, + { "9600" }, + { "19200" } +}; + +menu_strings_t wifi_mode_str[2] = { + {"Access Point"}, + {"Client"} +}; + +menu_strings_t serialmux_strings[4] = { + { "Loopback" }, + { "USB CDC" }, + { "WiFi Modem" }, + { "Printer" } +}; + +menu_strings_t font_strings[40] = { + { "00: US Enhanced " }, + { "01: US Un-Enhanced " }, + { "02: Clinton V1 Enh " }, + { "03: Reactive Micro " }, + { "04: Dan Paymar Enh " }, + { "05: Blippo Enhanced " }, + { "06: Byte Enhanced " }, + { "07: Colossal Enh " }, + { "08: Count Enhanced " }, + { "09: Flow Enhanced " }, + { "0A: Gothic Enhanced " }, + { "0B: Outline Enhanced" }, + { "0C: PigFont Enhanced" }, + { "0D: Pinocchio Enh " }, + { "0E: Slant Enhanced " }, + { "0F: Stop Enhanced " }, + { "10: Euro UnEnhanced " }, + { "11: Euro Enhanced " }, + { "12: Clinton V2 " }, + { "13: German Enh " }, + { "14: German Un-Enh " }, + { "15: French Enh " }, + { "16: French Un-Enh " }, + { "17: Hebrew Enh " }, + { "18: Hebrew Un-Enh " }, + { "19: Plus Enhanced " }, + { "1A: Plus Un-Enhanced" }, + { "1B: KataKana " }, + { "1C: Cyrillic " }, + { "1D: Greek " }, + { "1E: Esperanto " }, + { "1F: Videx Enhanced " }, + { "20: Apple II Un-Enh " }, + { "21: Apple IIe Enh " }, + { "22: Apple IIgs Enh " }, + { "23: Pravetz Enhanced" }, + { "24: PCBold Enhanced " }, + { "25: Custom " }, + { "26: Custom " }, + { "27: Custom " }, +}; + +menu_strings_t monochrome_strings[9] = { + { "Disabled" }, + { "B&W" }, + { "Inverse" }, + { "Amber" }, + { "Amber I" }, + { "Green" }, + { "Green I" }, + { "C64" }, + { "Custom" } +}; + +menu_strings_t color_strings[16] = { + { "Black" }, + { "Magenta" }, + { "D.Blue" }, + { "H.Violet" }, + { "D.Green" }, + { "D.Grey" }, + { "H.Blue" }, + { "L.Blue" }, + { "Brown" }, + { "H.Orange" }, + { "L.Grey" }, + { "Pink" }, + { "H.Green" }, + { "Yellow" }, + { "Aqua" }, + { "White" } +}; + +menu_strings_t machine_strings[MACHINE_MAXVALUE] = { + { "Auto Detect" }, + { "Apple II" }, + { "Apple IIe" }, + { "Apple IIgs" }, + { "Pravetz" }, + { "Basis" }, +}; + +void ok_button(void) { + gotoy(14); gotox(18); + revers(1); + cputs(" OK "); + revers(0); + + for(;;) { + switch(cgetc()) { + case 0x0A: + case 0x0D: + case 0x1B: + case 'O': + case 'o': + return; + } + } +} + +void print_menu_select(char *str, int width, int highlighted, int selected) { + revers(highlighted); + if(selected) { + cputs(" ["); + } else { + cputs(" "); + } + printlimited(str, width - 4); + if(selected) { + cputs("] "); + } else { + cputs(" "); + } + width -= longmin(width, strlen(str) + 4); + if(width > 0) + repeatchar(' ', width); + revers(0); +} + +void print_menu_select_int(char *str, int i, int width, int highlighted, int selected) { + revers(highlighted); + if(selected) { + cputs(" ["); + } else { + cputs(" "); + } + width -= 4 + cprintf(str, i); + if(selected) { + cputs("] "); + } else { + cputs(" "); + } + if(width > 0) + repeatchar(' ', width); + revers(0); +} + +void print_menu_select_ip(uint32_t ip, int width, int highlighted, int selected) { + uint8_t temp_ip[4]; + + temp_ip[0] = (ip >> 24) & 0xff; + temp_ip[1] = (ip >> 16) & 0xff; + temp_ip[2] = (ip >> 8) & 0xff; + temp_ip[3] = (ip >> 0) & 0xff; + + width -= 11; + if(temp_ip[0] > 99) width--; + if(temp_ip[0] > 9) width--; + if(temp_ip[1] > 99) width--; + if(temp_ip[1] > 9) width--; + if(temp_ip[2] > 99) width--; + if(temp_ip[2] > 9) width--; + if(temp_ip[3] > 99) width--; + if(temp_ip[3] > 9) width--; + + revers(highlighted); + if(selected) { + cputs(" ["); + } else { + cputs(" "); + } + if(width > 0) + repeatchar(' ', width); + cprintf("%d.%d.%d.%d", temp_ip[0], temp_ip[1], temp_ip[2], temp_ip[3]); + if(selected) { + cputs("] "); + } else { + cputs(" "); + } + revers(0); +} + +void print_menu_select_str(char *str1, char *str2, int width, int highlighted, int selected) { + revers(highlighted); + if(selected) { + cputs(" ["); + } else { + cputs(" "); + } + width -= 4 + cprintf(str1, str2); + if(selected) { + cputs("] "); + } else { + cputs(" "); + } + if(width > 0) + repeatchar(' ', width); + revers(0); +} + +int list_menu(char *screen_title, char *window_title, menu_strings_t *menu_str, int max_item, int current_item) { + int paint_menu = 2; + int selected_item = (current_item > max_item) ? 0 : current_item; + int y; + int top = -1; + int i; + + y = 12 - 5; + + while(paint_menu >= 0) { + if(top != ((selected_item / 10) * 10)) { + top = (selected_item / 10) * 10; + } + if(paint_menu == 2) { + backdrop(screen_title); + window(window_title, 26, 12, 0); + } + if(paint_menu > 0) { + for(i = 0; i < longmin((max_item-top)+1, 10); i++) { + gotoy(y+i); gotox(8); + print_menu_select(menu_str[i+top].str, 24, (selected_item == i+top), (current_item == i+top)); + } + if(max_item > 9) while(i < 10) { + gotoy(y+i); gotox(8); + repeatchar(' ', 24); + i++; + } + paint_menu = 0; + } + switch(cgetc()) { + case 0x08: + case 0x0B: + if(selected_item > 0) { + selected_item--; + paint_menu = 1; + } + break; + case 0x15: + case 0x0A: + if(selected_item < max_item) { + selected_item++; + paint_menu = 1; + } + break; + case 0x0D: + return selected_item; + case 0x1B: + paint_menu = -1; + } + } + + return current_item; +} + +void default_config() { + serialmux[0] = SERIAL_PRINTER; + serialmux[1] = SERIAL_WIFI; + baud[0] = 19200; + baud[1] = 19200; + usbmux = USB_GUEST_CDC; + + wifimode = WIFI_AP; + strcpy(wifi_ssid, "V2RetroNet"); + strcpy(wifi_psk, "Analog"); + wifi_address = 0x00000000; + wifi_netmask = 0xFFFFFF00; + + strcpy(jd_host, "192.168.0.1"); + jd_port = 9100; + machine = MACHINE_AUTO; +} + +int parse_config() { + int i = 0; + uint32_t *ptr = (uint32_t*)blockbuffer; + uint32_t configlen = sizeof(blockbuffer)/sizeof(uint32_t); + + if(ptr[i++] != NEWCONFIG_MAGIC) { + return 0; + } + + while(i < configlen) { + if(ptr[i] == NEWCONFIG_EOF_MARKER) { + configlen = i++; + } else + switch(ptr[i] & 0x0000FFFF) { + case CFGTOKEN_REVISION: + config_rev = (ptr[i] >> 16) & 0xFF; + break; + case CFGTOKEN_HOST_AUTO: + machine = MACHINE_AUTO; + break; + case CFGTOKEN_HOST_II: + machine = MACHINE_APPLE_II; + break; + case CFGTOKEN_HOST_IIE: + machine = MACHINE_APPLE_IIE; + break; + case CFGTOKEN_HOST_IIGS: + machine = MACHINE_APPLE_IIGS; + break; + case CFGTOKEN_HOST_PRAVETZ: + machine = MACHINE_PRAVETZ; + break; + case CFGTOKEN_MUX_LOOP: + serialmux[(ptr[i] >> 16) & 1] = SERIAL_LOOP; + break; + case CFGTOKEN_MUX_USB: + serialmux[(ptr[i] >> 16) & 1] = SERIAL_USB; + break; + case CFGTOKEN_MUX_WIFI: + serialmux[(ptr[i] >> 16) & 1] = SERIAL_WIFI; + break; + case CFGTOKEN_MUX_PRN: + serialmux[(ptr[i] >> 16) & 1] = SERIAL_PRINTER; + break; + case CFGTOKEN_SER_BAUD: + baud[(ptr[i] >> 16) & 1] = ptr[i+1]; + break; + case CFGTOKEN_USB_HOST: + usbmux = USB_HOST_CDC; + break; + case CFGTOKEN_USB_GUEST: + usbmux = USB_GUEST_CDC; + break; + case CFGTOKEN_USB_MIDI: + usbmux = USB_GUEST_MIDI; + break; + case CFGTOKEN_WIFI_AP: + wifimode = WIFI_AP; + break; + case CFGTOKEN_WIFI_CL: + wifimode = WIFI_CLIENT; + break; + case CFGTOKEN_WIFI_SSID: + memset(wifi_ssid, 0, sizeof(wifi_ssid)); + strncpy(wifi_ssid, (char*)(ptr+1), (ptr[i] >> 24)); + break; + case CFGTOKEN_WIFI_PSK: + memset(wifi_psk, 0, sizeof(wifi_psk)); + strncpy(wifi_psk, (char*)(ptr+1), (ptr[i] >> 24)); + break; + case CFGTOKEN_WIFI_IP: + wifi_address = ptr[i+1]; + break; + case CFGTOKEN_WIFI_NM: + wifi_netmask = ptr[i+1]; + break; + case CFGTOKEN_JD_HOST: + memset(jd_host, 0, sizeof(jd_host)); + strncpy(jd_host, (char*)(ptr+1), (ptr[i] >> 24)); + break; + case CFGTOKEN_JD_PORT: + jd_port = ptr[i+1]; + break; + } + + // Advance by the number of dwords for this token + i += 1 + (((ptr[i] >> 24) + 3) >> 2); + } + + return i*4; +} + +int build_config(uint32_t rev) { + int i = 0; + uint32_t *ptr = (uint32_t*)blockbuffer; + + memset(blockbuffer, 0, sizeof(blockbuffer)); + + ptr[i++] = NEWCONFIG_MAGIC; + ptr[i++] = CFGTOKEN_REVISION | ((rev & 0xff) << 16); + ptr[i++] = CFGTOKEN_MONO_00 | ((((uint32_t)mono_palette) & 0xF) << 20); + ptr[i++] = CFGTOKEN_TBCOLOR | ((((uint32_t)terminal_fgcolor) & 0xF) << 20) | ((((uint32_t)terminal_bgcolor) & 0xF) << 16); + ptr[i++] = CFGTOKEN_BORDER | ((((uint32_t)terminal_border) & 0xF) << 16); + + switch(machine) { + default: + case MACHINE_AUTO: + ptr[i++] = CFGTOKEN_HOST_AUTO; + break; + case MACHINE_APPLE_II: + ptr[i++] = CFGTOKEN_HOST_II; + break; + case MACHINE_APPLE_IIE: + ptr[i++] = CFGTOKEN_HOST_IIE; + break; + case MACHINE_APPLE_IIGS: + ptr[i++] = CFGTOKEN_HOST_IIGS; + break; +#if 0 + case MACHINE_PRAVETZ: + ptr[i++] = CFGTOKEN_HOST_PRAVETZ; + break; + case MACHINE_BASIS: + ptr[i++] = CFGTOKEN_HOST_BASIS; + break; +#endif + } + + switch(serialmux[0]) { + case SERIAL_USB: + ptr[i++] = CFGTOKEN_MUX_USB; + break; + case SERIAL_WIFI: + ptr[i++] = CFGTOKEN_MUX_WIFI; + break; + case SERIAL_PRINTER: + ptr[i++] = CFGTOKEN_MUX_PRN; + break; + default: + case SERIAL_LOOP: + ptr[i++] = CFGTOKEN_MUX_LOOP; + break; + } + ptr[i++] = CFGTOKEN_SER_BAUD; + ptr[i++] = baud[0]; + + switch(serialmux[1]) { + case SERIAL_USB: + ptr[i++] = CFGTOKEN_MUX_USB | 0x010000; + break; + case SERIAL_WIFI: + ptr[i++] = CFGTOKEN_MUX_WIFI | 0x010000; + break; + case SERIAL_PRINTER: + ptr[i++] = CFGTOKEN_MUX_PRN | 0x010000; + break; + default: + case SERIAL_LOOP: + ptr[i++] = CFGTOKEN_MUX_LOOP | 0x010000; + break; + } + ptr[i++] = CFGTOKEN_SER_BAUD | 0x010000; + ptr[i++] = baud[1]; + + + switch(usbmux) { + case USB_HOST_CDC: + ptr[i++] = CFGTOKEN_USB_HOST; + break; + default: + case USB_GUEST_CDC: + ptr[i++] = CFGTOKEN_USB_GUEST; + break; + case USB_GUEST_MIDI: + ptr[i++] = CFGTOKEN_USB_MIDI; + break; + } + + switch(wifimode) { + case WIFI_AP: + ptr[i++] = CFGTOKEN_WIFI_AP; + break; + case WIFI_CLIENT: + ptr[i++] = CFGTOKEN_WIFI_CL; + break; + } + + ptr[i++] = CFGTOKEN_WIFI_SSID | (((uint32_t)strlen(wifi_ssid)+1) << 24); + strncpy((char*)ptr, wifi_ssid, 31); + i += (strlen(wifi_ssid)+4) >> 2; + + ptr[i++] = CFGTOKEN_WIFI_PSK | (((uint32_t)strlen(wifi_psk)+1) << 24); + strncpy((char*)ptr, wifi_psk, 31); + i += (strlen(wifi_psk)+4) >> 2; + + ptr[i++] = CFGTOKEN_WIFI_IP; + ptr[i++] = wifi_address; + + ptr[i++] = CFGTOKEN_WIFI_NM; + ptr[i++] = wifi_netmask; + + ptr[i++] = CFGTOKEN_JD_HOST | (((uint32_t)strlen(jd_host)+1) << 24); + strncpy((char*)ptr, jd_host, 31); + ptr += (strlen(jd_host)+4) >> 2; + + ptr[i++] = CFGTOKEN_JD_PORT; + ptr[i++] = jd_port; + + return i*4; +} + +void cfgfile_upload(char *pdfile, uint16_t block) { + FILE *f; + size_t bytesread; + int i; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Writing file,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + f = fopen(pdfile, "rb"); + if(f == NULL) { + backdrop(PROGNAME); + window(" Error ", longmax(28, strlen(pdfile)+2), 7, 1); + gotoy(11); gotox(7); + cputs("Unable to open prodos file"); + gotoy(12); gotox(20 - (strlen(pdfile)/2)); + cputs(pdfile); + ok_button(); + + return; + } + + memset(blockbuffer, 0xff, 4096); + bytesread = fread(blockbuffer, 1, 4096, f); + if(bytesread == 0) { + backdrop(PROGNAME); + window(" Error ", longmax(28, strlen(pdfile)+2), 7, 1); + gotoy(11); gotox(7); + cputs("Unable to read prodos file"); + gotoy(12); gotox(20 - (strlen(pdfile)/2)); + cputs(pdfile); + ok_button(); + + goto cleanup; + } + + if(cfg_cmd1("fe", block)) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cprintf("Unable to erase block $%4X", block); + ok_button(); + + goto cleanup; + } + + CF_PTRL = 0; + CF_PTRH = 0; + for(i = 0; i < sizeof(blockbuffer); i++) { + CF_DATA = blockbuffer[i]; + } + + if(cfg_cmd1("fw", block)) { + ok_button(); + + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cprintf("Unable to write block $%4X", block); + ok_button(); + + goto cleanup; + } + +cleanup: + if(f != NULL) + fclose(f); +} + +void cfgfile_download(char *pdfile, uint16_t block) { + FILE *f; + size_t byteswritten; + int i; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Reading file,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + f = fopen(pdfile, "wb"); + if(f == NULL) { + backdrop(PROGNAME); + window(" Error ", longmax(28, strlen(pdfile)+2), 7, 1); + gotoy(11); gotox(7); + cputs("Unable to open prodos file"); + gotoy(12); gotox(20 - (strlen(pdfile)/2)); + cputs(pdfile); + ok_button(); + + return; + } + + if(cfg_cmd1("fr", block)) { + ok_button(); + + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cprintf("Unable to read block $%4X", block); + ok_button(); + + goto cleanup; + } + + CF_PTRL = 0; + CF_PTRH = 0; + for(i = 0; i < sizeof(blockbuffer); i++) { + blockbuffer[i] = CF_DATA; + } + + byteswritten = fwrite(blockbuffer, 1, sizeof(blockbuffer), f); + if(byteswritten != sizeof(blockbuffer)) { + ok_button(); + + backdrop(PROGNAME); + window(" Error ", longmax(30, strlen(pdfile)+2), 7, 1); + gotoy(11); gotox(6); + cputs("Unable to write prodos file"); + gotoy(12); gotox(20 - (strlen(pdfile)/2)); + cputs(pdfile); + ok_button(); + + goto cleanup; + } + +cleanup: + if(f != NULL) + fclose(f); +} + +void restore_config() { + uint16_t next; + + // Get current config blocks + if(cfg_cmd0("fc")) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cputs("Unable to get config block"); + ok_button(); + return; + } + + next = RPY_BUFFER[5]; + next <<= 8; + next |= RPY_BUFFER[4]; + + cfgfile_upload("CONFIG.BACKUP", next); +} + +void backup_config() { + uint16_t last; + + // Get current config blocks + if(cfg_cmd0("fc")) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cputs("Unable to get config block"); + ok_button(); + goto cleanup; + } + + last = RPY_BUFFER[3]; + last <<= 8; + last |= RPY_BUFFER[2]; + + cfgfile_download("CONFIG.BACKUP", last); + +cleanup: + return; +} + +void read_config() { + int i; + uint16_t last; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Reading file,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + // Get current config blocks + if(cfg_cmd0("fc")) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cputs("Unable to get config block"); + ok_button(); + goto cleanup; + } + + last = RPY_BUFFER[3]; + last <<= 8; + last |= RPY_BUFFER[2]; + + if(cfg_cmd1("fr", last)) { + backdrop(PROGNAME); + window(" Error ", 30, 7, 1); + gotoy(11); gotox(7); + cprintf("Unable to read block $%4X", last); + ok_button(); + + goto cleanup; + } + + CF_PTRL = 0; + CF_PTRH = 0; + for(i = 0; i < sizeof(blockbuffer); i++) { + blockbuffer[i] = CF_DATA; + } + + parse_config(); + +cleanup: + return; +} + +int write_config() { + int i; + uint16_t next; + + build_config(config_rev+1); + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(10); + cputs("Saving configuration,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + // Get current config blocks + if(cfg_cmd0("fc")) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(7); + cputs("Unable to get config block"); + ok_button(); + goto cleanup; + } + + next = RPY_BUFFER[5]; + next <<= 8; + next |= RPY_BUFFER[4]; + + if(cfg_cmd1("fe", next)) { + backdrop(PROGNAME); + window(" Error ", 32, 7, 1); + gotoy(11); gotox(6); + cprintf("Unable to erase block $%4X", next); + ok_button(); + + goto cleanup; + } + + CF_PTRL = 0; + CF_PTRH = 0; + for(i = 0; i < sizeof(blockbuffer); i++) { + CF_DATA = blockbuffer[i]; + } + + if(cfg_cmd1("fw", next)) { + ok_button(); + + backdrop(PROGNAME); + window(" Error ", 32, 7, 1); + gotoy(11); gotox(6); + cprintf("Unable to write block $%04X", next); + ok_button(); + + goto cleanup; + } + return 1; + +cleanup: + return 0; +} + +void apply_config(void) { + timeout = CARD_TIMEOUT; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(10); gotox(13); + cputs("Rebooting card"); + gotoy(11); gotox(9); + cputs("to apply configuration,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + // Ask card to reboot. + cfg_cmd0("RB"); + + while(timeout--); +} + +int format_card(void) { + uint16_t last, next; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(12); + cputs("Erasing configs,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + // Get current config blocks + if(cfg_cmd0("fc")) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(8); + cputs("Unable to get config block"); + ok_button(); + + goto cleanup; + } + + last = RPY_BUFFER[3]; + last <<= 8; + last |= RPY_BUFFER[2]; + next = RPY_BUFFER[5]; + next <<= 8; + next |= RPY_BUFFER[4]; + if(last != next) { + if(cfg_cmd1("fe", last)) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(8); + cprintf("Unable to erase block $%04X", last); + ok_button(); + + goto cleanup; + } + if(cfg_cmd1("fe", next)) { + backdrop(PROGNAME); + window(" Error ", 28, 7, 1); + gotoy(11); gotox(8); + cprintf("Unable to erase block $%04X", next); + ok_button(); + + goto cleanup; + } + } + + return 1; + +cleanup: + return 0; +} + +int baud_menu(char *screen_title, int baudrate) { + int i, selected_item = 0; + + for(i = 0; i < (sizeof(baudvalue)/sizeof(uint16_t)); i++) { + if(baudrate == baudvalue[i]) { + selected_item = i; + } + } + + selected_item = list_menu(screen_title, " Baud Rate ", baud_strings, (sizeof(baud_strings)/sizeof(menu_strings_t))-1, selected_item); + + return baudvalue[selected_item]; +} + +static char tolower(char c) { + if((c >= 'A') && (c <= 'Z')) { + return (c-'A')+'a'; + } + return c; +} + +void jdhost_edit(void) { + char temp_host[32]; + int c, l; + int paint_menu = 1; + int y = 12 - 1; + int x = 7; + + strcpy(temp_host, jd_host); + l = strlen(temp_host); + + for(;;) { + if(paint_menu) { + backdrop("JetDirect"); + window(" Server ", 30, 5, 1); + gotoy(y+0); gotox(x); + cputs("Enter hostname or IP:"); + gotoy(y+2); gotox(x); + cputs("_________________________"); + gotoy(y+2); gotox(x); + cputs(temp_host); + paint_menu = 0; + } + + gotox(x+l); + cputc(CHAR_CURSOR); + c = cgetc(); + if(c == 0x08) { + if(l > 0) { + // Remove flashing cursor + gotox(x+l); + cputc('_'); + + // Remove deleted character + l--; + gotox(x+l); + cputc('_'); + temp_host[l] = 0; + } + } else if(c == 0x0D) { + strcpy(jd_host, temp_host); + return; + } else if(c == 0x1B) { + if(confirm(" Are you sure? ", "Go back without saving?")) { + return; + } + paint_menu = 1; + } else if(((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '.')) { + if(l < 24) { + gotox(x+l); + cputc(tolower(c)); + temp_host[l] = tolower(c); + l++; + temp_host[l] = 0; + } + } + } +} + +void jdport_edit(void) { + char temp_port[8]; + int c, l; + int paint_menu = 1; + int y = 12 - 1; + int x = 15; + + sprintf(temp_port, "%i", jd_port); + l = strlen(temp_port); + + for(;;) { + if(paint_menu) { + backdrop("JetDirect"); + window(" TCP/IP Port ", 16, 5, 1); + gotoy(y+0); gotox(x); + cputs("Enter port:"); + gotoy(y+2); gotox(x); + cputs("______"); + gotoy(y+2); gotox(x); + cputs(temp_port); + paint_menu = 0; + } + + gotox(x+l); + cputc(CHAR_CURSOR); + c = cgetc(); + if(c == 0x08) { + if(l > 0) { + // Remove flashing cursor + gotox(x+l); + cputc('_'); + + // Remove deleted character + l--; + gotox(x+l); + cputc('_'); + temp_port[l] = 0; + } + } else if(c == 0x0D) { + jd_port = strtoul(temp_port, NULL, 0); + return; + } else if(c == 0x1B) { + gotox(x+l); + cputc('_'); + if(confirm(" Are you sure? ", "Go back without saving?")) { + return; + } + paint_menu = 1; + } else if((c >= '0') && (c <= '9')) { + if(l < 5) { + gotox(x+l); + cputc(c); + temp_port[l] = c; + l++; + temp_port[l] = 0; + } + } + } +} + +void ssid_edit(void) { + char temp_ssid[32]; + int c, l; + int paint_menu = 1; + int y = 12 - 1; + int x = 7; + + strcpy(temp_ssid, wifi_ssid); + l = strlen(temp_ssid); + + for(;;) { + if(paint_menu) { + backdrop("WiFi"); + window(" Network Name (SSID) ", 30, 5, 1); + gotoy(y+0); gotox(x); + cputs("Enter network name:"); + gotoy(y+2); gotox(x); + cputs("_________________________"); + gotoy(y+2); gotox(x); + cputs(temp_ssid); + paint_menu = 0; + } + + gotox(x+l); + cputc(CHAR_CURSOR); + c = cgetc(); + if(c == 0x08) { + if(l > 0) { + // Remove flashing cursor + gotox(x+l); + cputc('_'); + + // Remove deleted character + l--; + gotox(x+l); + cputc('_'); + temp_ssid[l] = 0; + } + } else if(c == 0x0D) { + strcpy(wifi_ssid, temp_ssid); + return; + } else if(c == 0x1B) { + gotox(x+l); + cputc('_'); + if(confirm(" Are you sure? ", "Go back without saving?")) { + return; + } + paint_menu = 1; + } else if(c >= 32) { + if(l < 24) { + gotox(x+l); + cputc(c); + temp_ssid[l] = c; + l++; + temp_ssid[l] = 0; + } + } + } +} + +void psk_edit(void) { + char temp_psk[32]; + int c, l; + int paint_menu = 1; + int y = 12 - 1; + int x = 7; + + strcpy(temp_psk, wifi_psk); + l = strlen(temp_psk); + + for(;;) { + if(paint_menu) { + backdrop("WiFi"); + window(" Passphrase (PSK) ", 30, 5, 1); + gotoy(y+0); gotox(x); + cputs("Enter passphrase:"); + gotoy(y+1); gotox(x); + cputs("_________________________"); + gotoy(y+1); gotox(x); + cputs(temp_psk); + paint_menu = 0; + } + + gotox(x+l); + cputc(CHAR_CURSOR); + c = cgetc(); + if(c == 0x08) { + if(l > 0) { + // Remove flashing cursor + gotox(x+l); + cputc('_'); + + // Remove deleted character + l--; + gotox(x+l); + cputc('_'); + temp_psk[l] = 0; + } + } else if(c == 0x0D) { + strcpy(wifi_psk, temp_psk); + return; + } else if(c == 0x1B) { + gotox(x+l); + cputc('_'); + if(confirm(" Are you sure? ", "Go back without saving?")) { + return; + } + paint_menu = 1; + } else if(c >= 32) { + if(l < 24) { + gotox(x+l); + cputc(c); + temp_psk[l] = c; + l++; + temp_psk[l] = 0; + } + } + } +} + +int valid_netmask(uint32_t ip) { + int i; + uint32_t first_one = 32; + uint32_t bit_test = 1; + + if((ip & 0x80000000) == 0) return 0; + + for(i = 0; i < 31; i++) { + if(ip & bit_test) { // Bit is set + if(i < first_one) { + first_one = i; + } + } else { // Bit is clear + if(i > first_one) { // But we've seen a 1 already + return 0; + } + } + bit_test <<= 1; + } + + return 1; +} + +int valid_ip_or_dhcp(uint32_t ip) { + if(ip == 0) return 1; + + if((ip & 0xFF000000) == 0) return 0; + if(ip == wifi_netmask) return 0; + + if((ip & ~wifi_netmask) == 0) return 0; + if((ip & ~wifi_netmask) == ~wifi_netmask) return 0; + + return 1; +} + +// Parse a decimal dotted quad segment +uint16_t parse_dq(char *ptr, char **ptr_out) { + uint16_t rv = 0; + while((*ptr != 0) && (*ptr != '.')) { + if((*ptr >= '0') && (*ptr <= '9')) { + rv *= 10; + rv += *ptr - '0'; + } else { + *ptr_out = ptr; + return 0xFFFF; + } + ptr++; + } + + if(*ptr == 0) { + *ptr_out = NULL; + } else { + *ptr_out = ptr; + } + + return rv; +} + +uint32_t address_edit(uint32_t ip, int is_netmask) { + char temp_address[32]; + int c, l; + int paint_menu = 1; + uint16_t temp_ip[4]; + int y = 12 - 1; + int x = is_netmask ? 12 : 5; + + temp_ip[0] = (ip >> 24) & 0xff; + temp_ip[1] = (ip >> 16) & 0xff; + temp_ip[2] = (ip >> 8) & 0xff; + temp_ip[3] = (ip >> 0) & 0xff; + + sprintf(temp_address, "%d.%d.%d.%d", temp_ip[0], temp_ip[1], temp_ip[2], temp_ip[3]); + l = strlen(temp_address); + + for(;;) { + if(paint_menu) { + backdrop("WiFi"); + window(is_netmask ? "Netmask" : "IP Address", is_netmask ? 20 : 32, 5, 1); + if(is_netmask) { + gotoy(y+0); gotox(x); + cputs("Enter netmask:"); + } else { + gotoy(y+0); gotox(x); + cputs("Enter IP or 0.0.0.0 for DHCP:"); + } + gotoy(y+2); gotox(x); + cputs("________________"); + gotoy(y+2); gotox(x); + cputs(temp_address); + paint_menu = 0; + } + + gotox(x+l); + cputc(CHAR_CURSOR); + c = cgetc(); + if(c == 0x08) { + if(l > 0) { + // Remove flashing cursor + gotox(x+l); + cputc('_'); + + // Remove deleted character + l--; + gotox(x+l); + cputc('_'); + temp_address[l] = 0; + } + } else if((c == 0x0A) || (c == 0x0D)) { + char *ptr = temp_address; + temp_ip[0] = parse_dq(ptr, &ptr); + if((ptr != NULL) && (*ptr == '.')) { + ptr++; + temp_ip[1] = parse_dq(ptr, &ptr); + } + if((ptr != NULL) && (*ptr == '.')) { + ptr++; + temp_ip[2] = parse_dq(ptr, &ptr); + } + if((ptr != NULL) && (*ptr == '.')) { + ptr++; + temp_ip[3] = parse_dq(ptr, &ptr); + if((temp_ip[0] < 256) && (temp_ip[1] < 256) && + (temp_ip[2] < 256) && (temp_ip[3] < 256)) { + ip = temp_ip[0]; + ip <<= 8; + ip |= temp_ip[1]; + ip <<= 8; + ip |= temp_ip[2]; + ip <<= 8; + ip |= temp_ip[3]; + if((is_netmask && valid_netmask(ip)) || (!is_netmask && valid_ip_or_dhcp(ip))) + return ip; + } + } + message(" Error ", "Invalid Address Specified"); + paint_menu = 1; + } else if(c == 0x1B) { + backdrop("WiFi"); + if(confirm(" Are you sure? ", "Go back without saving?")) { + return ip; + } + paint_menu = 2; + } else if(c >= 32) { + if(l < 15) { + gotox(x+l); + cputc(c); + temp_address[l] = c; + l++; + temp_address[l] = 0; + } + } + } +} + +int video_menu_action(int action) { + switch(action) { + case 0: + default_font = list_menu("Video Settings", "Default Font", font_strings, (sizeof(font_strings)/sizeof(menu_strings_t))-1, default_font); + return 2; + case 1: + mono_palette = list_menu("Video Settings", "Monochrome Mode", monochrome_strings, (sizeof(monochrome_strings)/sizeof(menu_strings_t))-1, mono_palette); + return 2; + case 2: + terminal_fgcolor = list_menu("Video Settings", "Foreground Color", color_strings, (sizeof(color_strings)/sizeof(menu_strings_t))-1, terminal_fgcolor); + return 2; + case 3: + terminal_bgcolor = list_menu("Video Settings", "Background Color", color_strings, (sizeof(color_strings)/sizeof(menu_strings_t))-1, terminal_bgcolor); + return 2; + case 4: + terminal_border = list_menu("Video Settings", "Border Color", color_strings, (sizeof(color_strings)/sizeof(menu_strings_t))-1, terminal_border); + return 2; + case 5: + return -1; + } +} + +void video_menu(void) { + int paint_menu = 2; + int selected_item = 0; + int y = 12 - 7; + + while(paint_menu >= 0) { + if(paint_menu == 2) { + backdrop("Video Settings"); + window(" Video Settings ", 26, 17, 0); + } + if(paint_menu > 0) { + gotoy(y+0); gotox(8); + print_menu_select_int("Default Font: %6x", default_font, 24, (selected_item == 0), 0); + gotoy(y+2); gotox(8); + print_menu_select_str("Monochrome: %8s", monochrome_strings[mono_palette].str, 24, (selected_item == 1), 0); + gotoy(y+4); gotox(8); + print_menu_select_str("Foreground: %8s", color_strings[terminal_fgcolor].str, 24, (selected_item == 2), 0); + gotoy(y+6); gotox(8); + print_menu_select_str("Background: %8s", color_strings[terminal_bgcolor].str, 24, (selected_item == 3), 0); + gotoy(y+8); gotox(8); + print_menu_select_str("Border: %12s", color_strings[terminal_border & 0xf].str, 24, (selected_item == 4), 0); + + gotoy(y+14); gotox(8); + print_menu_select(" Back to Main Menu", 24, (selected_item == 5), 0); + + paint_menu = 0; + } + switch(cgetc()) { + case 0x08: + case 0x0B: + if(selected_item > 0) { + selected_item--; + paint_menu = 1; + } + break; + case 0x15: + case 0x0A: + if(selected_item < 5) { + selected_item++; + paint_menu = 1; + } + break; + case 0x0D: + paint_menu = video_menu_action(selected_item); + break; + case 0x1B: + paint_menu = -1; + } + } +} + +int wifi_menu_action(int action) { + switch(action) { + case 0: + wifimode = (wifimode == WIFI_AP) ? WIFI_CLIENT : WIFI_AP; + return 1; + case 1: + ssid_edit(); + return 2; + case 2: + psk_edit(); + return 2; + case 3: + if(wifimode != WIFI_AP) { + wifi_address = address_edit(wifi_address, 0); + return 2; + } + return 0; + case 4: + if(wifimode != WIFI_AP) { + wifi_netmask = address_edit(wifi_netmask, 1); + return 2; + } + return 0; + case 5: + return -1; + } +} + +void wifi_menu(void) { + int paint_menu = 2; + int selected_item = 0; + int y = 12 - 7; + + while(paint_menu >= 0) { + if(paint_menu == 2) { + backdrop(PROGNAME); + window(" WiFi Options ", 26, 17, 0); + } + if(paint_menu > 0) { + gotoy(y+0); gotox(8); + print_menu_select_str("Mode: %14s", wifi_mode_str[wifimode == WIFI_CLIENT].str, 24, (selected_item == 0), 0); + + gotoy(y+2); gotox(8); + print_menu_select("Network Name:", 24, (selected_item == 1), 0); + gotoy(y+3); gotox(8); + print_menu_select_str("%20s", wifi_ssid, 24, (selected_item == 1), 1); + + gotoy(y+5); gotox(8); + print_menu_select("Pre-Shared Key:", 24, (selected_item == 2), 0); + gotoy(y+6); gotox(8); + print_menu_select_str("%20s", "*****", 24, (selected_item == 2), 1); + + gotoy(y+8); gotox(8); + print_menu_select("IP Address:", 24, (selected_item == 3), 0); + gotoy(y+9); gotox(8); + if(wifimode == WIFI_AP) { + print_menu_select_str("%20s", "10.65.50.1", 24, (selected_item == 3), 1); + } else if(wifi_address == 0) { + print_menu_select_str("%20s", "DHCP", 24, (selected_item == 3), 1); + } else { + print_menu_select_ip(wifi_address, 24, (selected_item == 3), 1); + } + + gotoy(y+11); gotox(8); + print_menu_select("Netmask:", 24, (selected_item == 4), 0); + gotoy(y+12); gotox(8); + if(wifimode == WIFI_AP) { + print_menu_select_str("%20s", "255.255.255.0", 24, (selected_item == 4), 1); + } else { + print_menu_select_ip(wifi_netmask, 24, (selected_item == 4), 1); + } + + gotoy(y+14); gotox(8); + print_menu_select("Back to Main Menu", 24, (selected_item == 5), 0); + + paint_menu = 0; + } + + switch(cgetc()) { + case 0x08: + case 0x0B: + if(selected_item > 0) { + selected_item--; + paint_menu = 1; + } + break; + case 0x15: + case 0x0A: + if(selected_item < 5) { + selected_item++; + paint_menu = 1; + } + break; + case 0x0D: + paint_menu = wifi_menu_action(selected_item); + break; + case 0x1B: + paint_menu = -1; + } + } +} + +int io_menu_action(int action) { + switch(action) { + case 0: + serialmux[0] = list_menu("Serial Port 0", " Port Mux ", serialmux_strings, (sizeof(serialmux_strings)/sizeof(menu_strings_t))-1, serialmux[0]); + return 2; + case 1: + baud[0] = baud_menu("Serial Port 0", baud[0]); + return 2; + case 2: + serialmux[1] = list_menu("Serial Port 1", " Port Mux ", serialmux_strings, (sizeof(serialmux_strings)/sizeof(menu_strings_t))-1, serialmux[1]); + return 2; + case 3: + baud[1] = baud_menu("Serial Port 1", baud[1]); + return 2; + case 4: + jdhost_edit(); + return 2; + case 5: + jdport_edit(); + return 2; + case 6: + return -1; + } +} + +void io_menu(void) { + int paint_menu = 2; + int selected_item = 0; + int y = 12 - 7; + + while(paint_menu >= 0) { + if(paint_menu == 2) { + backdrop(PROGNAME); + window(" I/O Settings ", 26, 17, 0); + } + if(paint_menu > 0) { + gotoy(y+0); gotox(8); + print_menu_select_str("Serial 0: %10s", serialmux_strings[serialmux[0]].str, 24, (selected_item == 0), 0); + gotoy(y+1); gotox(8); + print_menu_select_int(" Baud: %13d", baud[0], 24, (selected_item == 1), 0); + + gotoy(y+3); gotox(8); + print_menu_select_str("Serial 1: %10s", serialmux_strings[serialmux[1]].str, 24, (selected_item == 2), 0); + gotoy(y+4); gotox(8); + print_menu_select_int(" Baud: %13d", baud[1], 24, (selected_item == 3), 0); + + gotoy(y+6); gotox(8); + print_menu_select("JetDirect Server:", 24, (selected_item == 4), 0); + gotoy(y+7); gotox(8); + print_menu_select_str("%20s", jd_host, 24, (selected_item == 4), 1); + + gotoy(y+9); gotox(8); + print_menu_select("JetDirect Port:", 24, (selected_item == 5), 0); + gotoy(y+10); gotox(8); + print_menu_select_int("%20d", jd_port, 24, (selected_item == 5), 1); + + gotoy(y+14); gotox(8); + print_menu_select("Back to Main Menu", 24, (selected_item == 6), 0); + + paint_menu = 0; + } + + switch(cgetc()) { + case 0x08: + case 0x0B: + if(selected_item > 0) { + selected_item--; + paint_menu = 1; + } + break; + case 0x15: + case 0x0A: + if(selected_item < 6) { + selected_item++; + paint_menu = 1; + } + break; + case 0x0D: + paint_menu = io_menu_action(selected_item); + break; + case 0x1B: + paint_menu = -1; + } + } +} + +int main_menu_action(int action) { + switch(action) { + case 0: + machine = list_menu(PROGNAME, " Host Type ", machine_strings, (sizeof(machine_strings)/sizeof(menu_strings_t))-1, machine); + return 2; + case 1: + video_menu(); + return 2; + case 2: + wifi_menu(); + return 2; + case 3: + io_menu(); + return 2; + case 4: + backup_config(); + return 2; + case 5: + restore_config(); + return 2; + case 6: + backdrop(PROGNAME); + if(confirm(" Are you sure? ", "Format Card?")) { + format_card(); + default_config(); + return 2; + } + return 2; + case 7: + backdrop(PROGNAME); + if(confirm(" Are you sure? ", "Quit without saving?")) { + clrscr(); + exec("MENU.SYSTEM", ""); + return -1; + } + return 2; + case 8: + backdrop(PROGNAME); + if(confirm(" Are you sure? ", "Save and exit?")) { + write_config(); + clrscr(); + exec("MENU.SYSTEM", ""); + return -1; + } + return 2; + } +} + +void main (void) { + int paint_menu = 2; + int selected_item = 0; + int y = 12 - 6; + +#if 0 + if(!prompt_slot(PROGNAME)) { + exec("MENU.SYSTEM", ""); + return; + } +#endif + + switch(get_ostype() & 0xF0) { + default: + case 0x10: + machine = MACHINE_APPLE_II; + break; + case 0x30: + machine = MACHINE_APPLE_IIE; + break; + case 0x80: + machine = MACHINE_APPLE_IIGS; + break; + } + +#if 0 + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(9); + cputs("Reading configuration,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + read_config(); +#endif + + while(paint_menu >= 0) { + if(paint_menu == 2) { + backdrop(PROGNAME); + + window(" Main Menu ", 24, 15, 0); + gotoy(y+5); gotox(8); + repeatchar(CHAR_BORDER_BOTTOM, 24); + gotoy(y+10); gotox(8); + repeatchar(CHAR_BORDER_BOTTOM, 24); + } + if(paint_menu) { + gotoy(y+0); gotox(8); + if(machine < MACHINE_MAXVALUE) { + print_menu_select_str("Machine: %11s", machine_strings[machine].str, 24, (selected_item == 0), 0); + } else { + print_menu_select("Machine: Unknown", 24, (selected_item == 0), 0); + } + gotoy(y+1); gotox(8); + print_menu_select("Video Settings", 24, (selected_item == 1), 0); + gotoy(y+2); gotox(8); + print_menu_select("WiFi Settings", 24, (selected_item == 2), 0); + gotoy(y+3); gotox(8); + print_menu_select("I/O Settings", 24, (selected_item == 3), 0); + + gotoy(y+6); gotox(8); + print_menu_select("Backup config file", 24, (selected_item == 4), 0); + gotoy(y+7); gotox(8); + print_menu_select("Restore config file", 24, (selected_item == 5), 0); + gotoy(y+8); gotox(8); + print_menu_select("Erase config files", 24, (selected_item == 6), 0); + + gotoy(y+11); gotox(8); + print_menu_select("Quit without saving", 24, (selected_item == 7), 0); + gotoy(y+12); gotox(8); + print_menu_select("Save config & Exit", 24, (selected_item == 8), 0); + paint_menu = 0; + } + + switch(cgetc()) { + case 0x08: + case 0x0B: + if(selected_item > 0) { + selected_item--; + paint_menu = 1; + } + break; + case 0x15: + case 0x0A: + if(selected_item < 8) { + selected_item++; + paint_menu = 1; + } + break; + case 'M': + case 'm': + paint_menu = main_menu_action(selected_item = 0); + break; + case 'V': + case 'v': + paint_menu = main_menu_action(selected_item = 1); + break; + case 'W': + case 'w': + paint_menu = main_menu_action(selected_item = 2); + break; + case 'I': + case 'i': + paint_menu = main_menu_action(selected_item = 3); + break; + case 'B': + case 'b': + paint_menu = main_menu_action(selected_item = 4); + break; + case 'R': + case 'r': + paint_menu = main_menu_action(selected_item = 5); + break; + case 'F': + case 'f': + paint_menu = main_menu_action(selected_item = 6); + break; + case 0x1B: + case 'Q': + case 'q': + paint_menu = main_menu_action(selected_item = 7); + break; + case 'S': + case 's': + paint_menu = main_menu_action(selected_item = 8); + break; + case 0x0D: + paint_menu = main_menu_action(selected_item); + break; + } + } + exec("MENU.SYSTEM", ""); +} diff --git a/src/fontmgr.c b/src/fontmgr.c new file mode 100644 index 0000000..4d05587 --- /dev/null +++ b/src/fontmgr.c @@ -0,0 +1,765 @@ +#include +#include +#include +#include +#include +#include +#include "v2types.h" +#include "v2loader.h" + +#define PROGNAME "Font Manager" +volatile uint16_t cardslot = 3; + +#include "v2analog.h" +#include "menu.h" + +#if defined(__APPLE2ENH__) +#define UP_ARROW 0xCB +#define RIGHT_ARROW 0xD5 +#define DOWN_ARROW 0xCA +#else +#define UP_ARROW '^' +#define RIGHT_ARROW ('>' | 0x80) +#define DOWN_ARROW 'v' +#endif + +#define FONT_MAX 18 + +int selected_entry = 0; +int top_entry = 0; +int more_fonts = 0; +int arrow_line = 0; +int total_fonts = 0; +int total_pages = 0; +int line_count = 0; + +DIR *fontdir; +uint8_t fontbuffer[2048]; +uint8_t filebuffer[2048]; +char prefix[FILENAME_MAX]; +char pathname[FILENAME_MAX]; +char fontname[FILENAME_MAX]; + +void print_menu_item(char *str, int highlighted) { + revers(highlighted); + cputs(str); + revers(0); +} + +void remove_font(uint16_t block) { + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Removing Font,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + if(cfg_cmd1("fe", block)) { + backdrop(PROGNAME); + message(" Error ", "Unable to erase block."); + return; + } + + backdrop(PROGNAME); + message(" Success ", "Block erased."); +} + +void upload_font(uint8_t *buffer) { + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Uploading font,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + if(cfg_cmd1("CT", (uint16_t)buffer)) { + backdrop(PROGNAME); + message(" Error ", "Communication Error"); + return; + } + + backdrop(PROGNAME); + message(" Success ", "Font uploaded."); +} + +int write_font(uint8_t *buffer, uint16_t block) { + int rv = 1; + char dummy; + uint16_t i; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Flashing font,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + dummy = *(volatile char*)0xCFFF; + + for(i = 0; i < 4096; i++) { + CF_DATA = buffer[i]; + } + if(cfg_cmd1("fw", block)) { + backdrop(PROGNAME); + message(" Error ", "Unable to write block."); + goto cleanup; + } + + backdrop(PROGNAME); + message(" Success ", "Font uploaded."); + rv = 0; + +cleanup: + dummy = *(volatile char*)0xCFFF; + return rv; +} + +int read_font(uint8_t *buffer, uint16_t block) { + int rv = 1; + char dummy; + uint16_t i; + + backdrop(PROGNAME); + window(" Please Wait ", 26, 6, 1); + gotoy(11); gotox(13); + cputs("Retrieving font,"); + gotoy(12); gotox(8); + cputs("your screen may flicker."); + + dummy = *(volatile char*)0xCFFF; + + if(cfg_cmd1("fr", block)) { + backdrop(PROGNAME); + message(" Error ", "Unable to read block."); + goto cleanup; + } + for(i = 0; i < 4096; i++) { + buffer[i] = CF_DATA; + } + + backdrop(PROGNAME); + message(" Success ", "Font downloaded."); + rv = 0; + +cleanup: + dummy = *(volatile char*)0xCFFF; + return rv; +} + + +typedef struct font_slot_s { + char *entry; + uint16_t block; +} font_slot_t; + +font_slot_t font_slot[] = { + { " 00 US (Enh) ", 0x00 }, + { " 01 US (UnEnh) ", 0x01 }, + { " 02 Clinton Turner V1 ", 0x02 }, + { " 03 ReActiveMicro (Enh) ", 0x03 }, + { " 04 Dan Paymar (Enh) ", 0x04 }, + { " 05 Blippo Black (Enh) ", 0x05 }, + { " 06 Byte (Enh) ", 0x06 }, + { " 07 Colossal (Enh) ", 0x07 }, + { " 08 Count (Enh) ", 0x08 }, + { " 09 Flow (Enh) ", 0x09 }, + { " 0A Gothic (Enh) ", 0x0a }, + { " 0B Outline (Enh) ", 0x0b }, + { " 0C PigFont (Enh) ", 0x0c }, + { " 0D Pinocchio (Enh) ", 0x0d }, + { " 0E Slant (Enh) ", 0x0e }, + { " 0F Stop (Enh) ", 0x0f }, + + { " 10 Euro (UnEnh) ", 0x10 }, + { " 11 Euro (Enh) ", 0x11 }, + { " 12 Clinton Turner V2 ", 0x12 }, + { " 13 German (Enh) ", 0x13 }, + { " 14 German (UnEnh) ", 0x14 }, + { " 15 French (Enh) ", 0x15 }, + { " 16 French (UnEnh) ", 0x16 }, + { " 17 Hebrew (Enh) ", 0x17 }, + { " 18 Hebrew (UnEnh) ", 0x18 }, + { " 19 Apple II+ (Enh) ", 0x19 }, + { " 1A Apple II+ (UnEnh) ", 0x1a }, + { " 1B Katakana (Enh) ", 0x1b }, + { " 1C Cyrillic (Enh) ", 0x1c }, + { " 1D Greek (Enh) ", 0x1d }, + { " 1E Esperanto (Enh) ", 0x1e }, + { " 1F Videx (Enh) ", 0x1f }, + + { " 20 Apple II/II+ ", 0x20 }, + { " 21 Apple IIe ", 0x21 }, + { " 22 Apple IIgs ", 0x22 }, + { " 23 Pravetz ", 0x23 }, + { " 24 Custom ", 0x24 }, + { " 25 Custom ", 0x25 }, + { " 26 Custom ", 0x26 }, + { " 27 Custom ", 0x27 }, +}; + +uint8_t parsehex8(char *str) { + uint8_t ch = 0; + switch(str[0]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + ch = (str[0] - '0') << 4; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + ch = (str[0] + 0xa - 'a') << 4; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + ch = (str[0] + 0xA - 'A') << 4; + break; + } + switch(str[1]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + ch |= (str[1] - '0'); + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + ch |= (str[1] + 0xa - 'a'); + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + ch |= (str[1] + 0xA - 'A'); + break; + } + return ch; +} + +int slot_menu() { + int paint_menu = 2; + int selected_slot = 0; + int top = 0; + int y, i; + uint8_t block = parsehex8(fontname); + +#if 0 + // Try to find a matching slot from our table + for(i = 0; i < (sizeof(font_slot)/sizeof(font_slot_t)); i++) { + if(block == font_slot[i].block) { + selected_slot = i; + top = (selected_slot / 15) * 15; + break; + } + } +#endif + + while(paint_menu >= 0) { + if(paint_menu == 2) { + backdrop(PROGNAME); + window(" Font Slot? ", 24, 17, 0); + paint_menu = 1; + } + if(paint_menu > 0) { + for(y = 0; y < 15; y++) { + i = y+top; + if(i < (sizeof(font_slot)/sizeof(font_slot_t))) { + gotoy(5+y); gotox(9); + print_menu_item(font_slot[i].entry, (selected_slot == i)); + } else { + gotoy(5+y); gotox(9); + repeatchar(' ', 22); + } + } + + paint_menu = 0; + } + + switch(cgetc()) { + case 0x08: + case 0x0B: + if(selected_slot > 0) { + selected_slot--; + if(selected_slot < top) + top = (selected_slot / 15) * 15; + } + paint_menu = 1; + break; + case 0x0A: + case 0x15: + if(selected_slot < ((sizeof(font_slot)/sizeof(font_slot_t))-1)) { + selected_slot++; + if(selected_slot > top + 14) + top = (selected_slot / 15) * 15; + } + paint_menu = 1; + break; + case 0x1B: + return -1; + case 0x0D: + // Select + return(selected_slot); + } + } +} + +int action_menu_action(int action) { + int selected_slot; + switch(action) { + case 0: + upload_font(fontbuffer); + return 2; + case 1: + selected_slot = slot_menu(); + if(selected_slot >= 0) { + write_font(fontbuffer, font_slot[selected_slot].block); + } + return 2; + } + return 1; +} + +void action_menu(void) { + int paint_menu = 2; + int selected_action = 0; + + while(paint_menu >= 0) { + if(paint_menu == 2) { + backdrop(PROGNAME); + window(" Action? ", 18, 7, 0); + paint_menu = 1; + } + if(paint_menu > 0) { + gotoy(11); gotox(13); + revers(selected_action == 0); + cputs(" Test "); + + gotoy(13); gotox(13); + revers(selected_action == 1); + cputs(" Install "); + + revers(0); + paint_menu = 0; + } + + switch(cgetc()) { + case 'T': + case 't': + paint_menu = action_menu_action(selected_action = 0); + break; + case 'I': + case 'i': + paint_menu = action_menu_action(selected_action = 1); + break; + case 0x08: + case 0x0A: + case 0x0B: + case 0x15: + selected_action = !selected_action; + paint_menu = 1; + break; + case 0x1B: + return; + case 0x0D: + // Select + paint_menu = action_menu_action(selected_action); + break; + } + } +} + +int open_fontdir(void) { + struct dirent *ent; + char *ext; + + fontdir = opendir ("FONTS"); + if(fontdir == NULL) { + fontdir = opendir ("."); + prefix[0] = 0; + } else { + strcpy(prefix, "FONTS/"); + } + + if(fontdir == NULL) + return 0; + + total_fonts = 0; + + while (ent = readdir(fontdir)) { + ext = strrchr (ent->d_name, '.'); + if (!ext || (strcasecmp (ext, ".pf") && strcasecmp (ext, ".cf"))) + continue; + total_fonts++; + } + + total_pages = (total_fonts - 1) / FONT_MAX; + + return 1; +} + +int load_font(void) { + struct dirent *ent; + char *ext; + int current_entry = 0; + FILE *f; + uint8_t ch, last = 0; + uint16_t i, o, len; + + backdrop(PROGNAME); + gotoy(12); gotox(14); + cputs("Loading Font"); + + rewinddir(fontdir); + while (ent = readdir(fontdir)) { + ext = strrchr (ent->d_name, '.'); + if (!ext || (strcasecmp (ext, ".pf") && strcasecmp (ext, ".cf"))) + continue; + + // Seek to first entry on the screen + if(current_entry < selected_entry) { + current_entry++; + continue; + } + + strcpy(pathname, prefix); + strcat(pathname, ent->d_name); + strcpy(fontname, ent->d_name); + + // Pixel Font + if(!strcasecmp (ext, ".pf")) { + f = fopen(pathname, "rb"); + if(f == NULL) { + backdrop(PROGNAME); + gotoy(4); gotox(2); + cputs(pathname); + message(" Error ", "Unable to open font file."); + return 0; + } + fread(fontbuffer, 512, 4, f); + fclose(f); + return 1; + } + + // XOR & RLE Compressed Font + if(!strcasecmp (ext, ".cf")) { + f = fopen(pathname, "rb"); + if(f == NULL) { + backdrop(PROGNAME); + gotoy(4); gotox(2); + cputs(pathname); + message(" Error ", "Unable to open font file."); + return 0; + } + + // Get base font name + strcpy(pathname, prefix); + fread(pathname + strlen(prefix), 1, 16, f); + pathname[strlen(prefix)+15] = 0; + + fread(filebuffer, 512, 4, f); + fclose(f); + + // Undo the RLE compression + i = 0; + o = 0; + while(o < 2048) { + ch = filebuffer[i++]; + if(ch & 0x80) { + ch = (ch & 0x7f) ? (ch & 0x7f) : 128; + len = longmin(ch, (2048-o)); + memset(fontbuffer+o, last, len); + o += len; + } else { + fontbuffer[o++] = ch; + last = ch; + } + } + + // If this font is XOR'ed with a base font, undo that now. + if(strlen(pathname) != strlen(prefix)) { + f = fopen(pathname, "rb"); + if(f == NULL) { + backdrop(PROGNAME); + gotoy(4); gotox(2); + cputs(pathname); + message(" Error ", "Unable to open base font."); + return 0; + } + + fread(filebuffer, 512, 4, f); + fclose(f); + + i = 0; + while(i < 2048) { + fontbuffer[i++] ^= filebuffer[i++]; + } + fclose(f); + } + + return 1; + } + } + return 0; +} + +int save_font(char *filename) { + int current_entry = 0; + FILE *f; + + strcpy(pathname, prefix); + strcat(pathname, filename); + + f = fopen(pathname, "wb"); + if(f == NULL) { + backdrop(PROGNAME); + message(" Error ", "Unable to open font file."); + return 0; + } + + backdrop(PROGNAME); + gotoy(12); gotox(14); + cputs("Saving Font"); + + fwrite(fontbuffer, 512, 4, f); + + fclose(f); + + return 1; +} + +void index_fonts(void) { + struct dirent *ent; + char *ext; + int current_entry = 0; + + rewinddir(fontdir); + + backdrop(PROGNAME); + line_count = 0; + if(top_entry > 0) { + gotoy(2); gotox(1); + cputc(UP_ARROW); + } + while (ent = readdir(fontdir)) { + ext = strrchr (ent->d_name, '.'); + if (!ext || (strcasecmp (ext, ".pf") && strcasecmp (ext, ".cf"))) + continue; + + // Seek to first entry on the screen + if(current_entry < top_entry) { + current_entry++; + continue; + } + + if(line_count < FONT_MAX) { + gotoy(3+line_count); + if(current_entry == selected_entry) { + gotox(1); + cputc(RIGHT_ARROW); + arrow_line = 3+line_count; + } + gotox(3); + printlimited(ent->d_name, 32); + cputs("\r\n"); + current_entry++; + line_count++; + } + } + + more_fonts = (total_fonts > current_entry); + if(more_fonts) { + gotoy(21); gotox(1); + cputc(DOWN_ARROW); + } +} + +int select_font(void) { + for(;;) { + switch(cgetc()) { + case 0x0D: + // Select + if(load_font()) { + action_menu(); + } + return 1; + case 'T': + case 't': + if(load_font()) { + upload_font(fontbuffer); + } + return 1; + case 'I': + case 'i': + if(load_font()) { + int selected_slot = slot_menu(); + if(selected_slot >= 0) { + write_font(fontbuffer, font_slot[selected_slot].block); + } + } + return 1; + case 0x08: + case 0x0B: + // Left (UP) + if(selected_entry > 0) { + selected_entry--; + } + if(selected_entry < 0) { + selected_entry = 0; + } + + // Entry is on the same page, don't re-read the disk directory + if((selected_entry >= top_entry) && (selected_entry < (top_entry + line_count))) { + gotoy(arrow_line); gotox(1); + cputc(' '); + + arrow_line = 3+(selected_entry - top_entry); + gotoy(arrow_line); gotox(1); + cputc(RIGHT_ARROW); + break; + } else { + // Entry is on another page, re-read the disk directory + top_entry = (selected_entry / FONT_MAX) * FONT_MAX; + return 1; + } + return 1; + case 0x0A: + case 0x15: + // Right (DOWN) + if(selected_entry < (total_fonts - 1)) { + selected_entry++; + } + if(selected_entry >= total_fonts) { + selected_entry = total_fonts - 1; + } + + // Entry is on the same page, don't re-read the disk directory + if((selected_entry >= top_entry) && (selected_entry < (top_entry + line_count))) { + gotoy(arrow_line); gotox(1); + cputc(' '); + + arrow_line = 3+(selected_entry - top_entry); + gotoy(arrow_line); gotox(1); + cputc(RIGHT_ARROW); + break; + } else { + // Entry is on another page, re-read the disk directory + top_entry = (selected_entry / FONT_MAX) * FONT_MAX; + return 1; + } + return 1; + case 0x1B: + // Abort + return 0; + } + } +} + +void browse_fonts(void) { + if(!open_fontdir()) { + backdrop(PROGNAME); + message(" Error ", "Unable to open font folder."); + return; + } + + do { + index_fonts(); + } while(select_font()); + closedir(fontdir); +} + +int main_menu_action(int action) { + int selected_slot; + + switch(action) { + case 0: + browse_fonts(); + return 2; + case 1: + memset(fontname, 0, sizeof(fontname)); + selected_slot = slot_menu(); + if(selected_slot >= 0) { + read_font(fontbuffer, font_slot[selected_slot].block); + //save_font(font_slot[selected_slot].diskname); + } + return 2; + case 2: + memset(fontname, 0, sizeof(fontname)); + selected_slot = slot_menu(); + if(selected_slot >= 0) { + remove_font(font_slot[selected_slot].block); + } + return 2; + } + return 1; +} + +void main_menu(void) { + int paint_menu = 2; + int selected_action = 0; + + for(;;) { + if(paint_menu == 2) { + backdrop(PROGNAME); + window(" Main Menu ", 24, 7, 0); + paint_menu = 1; + } + if(paint_menu > 0) { + gotoy(10); gotox(9); + revers(selected_action == 0); + cputs(" Browse fonts "); + + gotoy(12); gotox(9); + revers(selected_action == 1); + cputs(" Download stored font "); + + gotoy(14); gotox(9); + revers(selected_action == 2); + cputs(" Remove stored font "); + + revers(0); + paint_menu = 0; + } + + switch(cgetc()) { + case 'B': + case 'b': + paint_menu = main_menu_action(selected_action = 0); + break; + case 'D': + case 'd': + paint_menu = main_menu_action(selected_action = 1); + break; + case 'R': + case 'r': + paint_menu = main_menu_action(selected_action = 2); + break; + case 0x08: + case 0x0B: + if(selected_action > 0) + selected_action--; + paint_menu = 1; + break; + case 0x0A: + case 0x15: + if(selected_action < 2) + selected_action++; + paint_menu = 1; + break; + case 0x1B: + if(confirm(" Are you sure? ", "Quit the Font Manager?")) + return; + + paint_menu = 2; + break; + case 0x0D: + // Select + paint_menu = main_menu_action(selected_action); + break; + } + } +} + +void main (void) { + if(!prompt_slot(PROGNAME)) { + exec("MENU.SYSTEM", ""); + return; + } + + backdrop(PROGNAME); + gotoy(12); gotox(13); + cputs("Indexing Fonts"); + + main_menu(); + clrscr(); + exec("MENU.SYSTEM", ""); +} diff --git a/src/menu.c b/src/menu.c index 348c417..59a9e1b 100644 --- a/src/menu.c +++ b/src/menu.c @@ -32,6 +32,7 @@ typedef enum { } menu_type_t; typedef struct menu_s { + int enabled; menu_type_t type; char *entry; char *filename_enhanced; @@ -40,17 +41,15 @@ typedef struct menu_s { } menu_t; menu_t launcher[] = { - { MENU_LAUNCH_NOCHECKARGS, " Config Utility ", "CONFIG.ENH", "CONFIG.BASE", "" }, - { MENU_LAUNCH_NOCHECKARGS, " Font Manager ", "FONTMGR.ENH", "FONTMGR.BASE", "" }, - { MENU_LAUNCH_CHECKARGS, " Theme Chooser ", "BASIC.SYSTEM", "BASIC.SYSTEM", "THEMES.BAS" }, - { MENU_LAUNCH_NOCHECKARGS, " Format Utility ", "FORMAT.ENH", "FORMAT.BASE", "" }, - { MENU_LAUNCH_NOCHECKARGS, " Config Remover ", "RMCFG.ENH", "RMCFG.BASE", "" }, - { MENU_LAUNCH_NOCHECKARGS, " One-time VGA Tool ", "OTVGA.ENH", "OTVGA.BASE", "" }, - { MENU_SEPARATOR, NULL, NULL, NULL, NULL }, - { MENU_LAUNCH_NOCHECKARGS, " Applesoft Basic ", "BASIC.SYSTEM", "BASIC.SYSTEM", "" }, - { MENU_SEPARATOR, NULL, NULL, NULL, NULL }, - { MENU_EXIT, " Exit ", NULL, NULL, NULL }, - { MENU_TERMINATOR, NULL, NULL, NULL, NULL }, + { 0, MENU_LAUNCH_NOCHECKARGS, " Config Utility ", "CONFIG.ENH", "CONFIG.BASE", "" }, + { 0, MENU_LAUNCH_NOCHECKARGS, " Font Manager ", "FONTMGR.ENH", "FONTMGR.BASE", "" }, + { 0, MENU_SEPARATOR, NULL, NULL, NULL, NULL }, + { 0, MENU_LAUNCH_NOCHECKARGS, " Applesoft Basic ", "BASIC.SYSTEM", "BASIC.SYSTEM", "" }, + { 0, MENU_LAUNCH_NOCHECKARGS, " ADTPRO ", "ADTPRO/ADTPRO", "ADTPRO/ADTPRO", "" }, + { 0, MENU_LAUNCH_NOCHECKARGS, " VSDRIVE ", "VDRIVE/VSDRIVE", "VDRIVE/VSDRIVE", "" }, + { 0, MENU_SEPARATOR, NULL, NULL, NULL, NULL }, + { 1, MENU_EXIT, " Exit ", NULL, NULL, NULL }, + { 0, MENU_TERMINATOR, NULL, NULL, NULL, NULL }, }; int main_menu_action(int action) { diff --git a/src/v2analog.h b/src/v2analog.h index 79b436f..f6a3445 100644 --- a/src/v2analog.h +++ b/src/v2analog.h @@ -52,64 +52,14 @@ typedef enum { WIFI_AP, } wifimode_t; -#define FS_COMMAND CARD_REGISTER(0x0) -#define FS_FILE CARD_REGISTER(0x1) -#define FS_FLAGS CARD_REGISTER(0x1) -#define FS_SIZELSB CARD_REGISTER(0x2) -#define FS_SIZEMSB CARD_REGISTER(0x3) -#define FS_OFFLSB CARD_REGISTER(0x2) -#define FS_OFFMSB CARD_REGISTER(0x3) -#define FS_WHENCE CARD_REGISTER(0x4) -#define FS_BUSY CARD_REGISTER(0xD) -#define FS_STATUS CARD_REGISTER(0xE) -#define FS_EXECUTE CARD_REGISTER(0xF) - -#define FS_O_RDONLY 0x0001 -#define FS_O_WRONLY 0x0002 -#define FS_O_RDWR 0x0003 -#define FS_O_CREAT 0x0100 -#define FS_O_EXCL 0x0200 -#define FS_O_TRUNC 0x0400 -#define FS_O_APPEND 0x0800 - -#define FS_SEEK_SET 0 -#define FS_SEEK_CUR 1 -#define FS_SEEK_END 2 - -typedef enum { - FS_OPEN = 0x10, - FS_CLOSE = 0x11, - FS_READ = 0x12, - FS_WRITE = 0x13, - FS_SEEK = 0x14, - FS_TELL = 0x15, -} fscommand_t; - -typedef enum { - FS_ERR_OK = 0, // No error - FS_ERR_IO = -1, // Error during device operation - FS_ERR_CORRUPT = -2, // Corrupted - FS_ERR_NOENT = -3, // No directory entry - FS_ERR_EXIST = -4, // Entry already exists - FS_ERR_NOTDIR = -5, // Entry is not a dir - FS_ERR_ISDIR = -5, // Entry is a dir - FS_ERR_NOTEMPTY = -7, // Dir is not empty - FS_ERR_BADF = -8, // Bad file number - FS_ERR_FBIG = -9, // File too large - FS_ERR_INVAL = -10, // Invalid parameter - FS_ERR_NOSPC = -11, // No space left on device - FS_ERR_NOMEM = -12, // No more memory available - FS_ERR_NOATTR = -13, // No data/attr available - FS_ERR_NAMETOOLONG = -14 // File name too long -} fserror_t; - typedef enum { MACHINE_AUTO = 0, MACHINE_APPLE_II = 1, MACHINE_APPLE_IIE = 2, MACHINE_APPLE_IIGS = 3, MACHINE_PRAVETZ = 4, - MACHINE_MAXVALUE = 5 + MACHINE_BASIS = 5, + MACHINE_MAXVALUE = 6 } compat_t; void hexprint(volatile uint8_t *buf, int size) { @@ -171,60 +121,4 @@ int cfg_cmd0(char *cmd) { return cfg_cmd3(cmd, 0, 0, 0); } - - - -#define NEWCONFIG_MAGIC 0x0001434E // "NC\x01\x00" - -#define CFGTOKEN_MODE_VGA 0x0000564D // "MV\x00\x00" VGA -#define CFGTOKEN_MODE_PCPI 0x00005A4D // "MZ\x00\x00" PCPI Applicard -#define CFGTOKEN_MODE_SER 0x0000534D // "MS\x00\x00" Serial -#define CFGTOKEN_MODE_PAR 0x0000504D // "MP\x00\x00" Parallel -#define CFGTOKEN_MODE_SNES 0x0000474D // "MG\x00\x00" SNESMAX -#define CFGTOKEN_MODE_MIDI 0x00004D4D // "MM\x00\x00" SNESMAX -#define CFGTOKEN_MODE_NET 0x0000454D // "ME\x00\x00" Ethernet -#define CFGTOKEN_MODE_FILE 0x0000464D // "MF\x00\x00" Filesystem - -#define CFGTOKEN_HOST_AUTO 0x00004148 // "HA\x00\x00" Autodetect -#define CFGTOKEN_HOST_II 0x00003248 // "H2\x00\x00" II/II+ -#define CFGTOKEN_HOST_IIE 0x00004548 // "HE\x00\x00" IIe -#define CFGTOKEN_HOST_IIGS 0x00004748 // "HG\x00\x00" IIgs -#define CFGTOKEN_HOST_PRAVETZ 0x00005048 // "HP\x00\x00" Pravetz - -#define CFGTOKEN_MUX_LOOP 0x00004C53 // "SL\x00\x00" Serial Loopback -#define CFGTOKEN_MUX_USB 0x00005553 // "SU\x00\x00" USB CDC -#define CFGTOKEN_MUX_WIFI 0x00005753 // "SW\x00\x00" WiFi Modem -#define CFGTOKEN_MUX_PRN 0x00005053 // "SP\x00\x00" WiFi Printer -#define CFGTOKEN_SER_BAUD 0x02004253 // "SB\x00\x00" Serial Baudrate - -#define CFGTOKEN_USB_HOST 0x00004855 // "UH\x00\x00" USB CDC Host -#define CFGTOKEN_USB_GUEST 0x00004755 // "UG\x00\x00" USB CDC Guest Device -#define CFGTOKEN_USB_MIDI 0x00004D55 // "UM\x00\x00" USB MIDI Guest Device - -#define CFGTOKEN_WIFI_AP 0x00004157 // "WA\x00\x00" WiFi AP -#define CFGTOKEN_WIFI_CL 0x00004357 // "WC\x00\x00" WiFi Client - -#define CFGTOKEN_WIFI_SSID 0x00005357 // "WS\x00\xSS" WiFi SSID -#define CFGTOKEN_WIFI_PSK 0x00005057 // "WS\x00\xSS" WiFi PSK - -#define CFGTOKEN_WIFI_IP 0x04504957 // "WIP\xSS" WiFi IP -#define CFGTOKEN_WIFI_NM 0x044D4E57 // "WNM\xSS" WiFi Netmask - -#define CFGTOKEN_JD_HOST 0x0000484A // "JH\x00\x01" JetDirect Hostname -#define CFGTOKEN_JD_PORT 0x0200444A // "JD\x00\x01" JetDirect Port - -#define CFGTOKEN_MONO_00 0x00005056 // "VP\x00\x00" Full Color Video -#define CFGTOKEN_MONO_80 0x00805056 // "VP\x80\x00" B&W Video -#define CFGTOKEN_MONO_90 0x00905056 // "VP\x90\x00" B&W Inverse -#define CFGTOKEN_MONO_A0 0x00A05056 // "VP\xA0\x00" Amber -#define CFGTOKEN_MONO_B0 0x00B05056 // "VP\xB0\x00" Amber Inverse -#define CFGTOKEN_MONO_C0 0x00C05056 // "VP\xC0\x00" Green -#define CFGTOKEN_MONO_D0 0x00D05056 // "VP\xD0\x00" Green Inverse -#define CFGTOKEN_MONO_E0 0x00E05056 // "VP\xE0\x00" C64 -#define CFGTOKEN_MONO_F0 0x00F05056 // "VP\xF0\x00" Custom - -#define CFGTOKEN_TBCOLOR 0x00005456 // "VT\xXX\x00" Custom default TBCOLOR -#define CFGTOKEN_BORDER 0x00004256 // "VB\xXX\x00" Custom default BORDER - - #endif /* __V2ANALOG_H */