#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_HOST_BASIS: machine = MACHINE_BASIS; 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[i+1]), (ptr[i] >> 24)); break; case CFGTOKEN_WIFI_PSK: memset(wifi_psk, 0, sizeof(wifi_psk)); strncpy(wifi_psk, (char*)(&ptr[i+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[i+1]), (ptr[i] >> 24)); break; case CFGTOKEN_JD_PORT: jd_port = ptr[i+1]; break; case CFGTOKEN_FONT_00: default_font = (ptr[i] >> 16) & 0x2F; break; case CFGTOKEN_MONO_00: mono_palette = (ptr[i] >> 20) & 0xF; if(mono_palette) mono_palette = (mono_palette & 0x7) + 1; break; case CFGTOKEN_TBCOLOR: terminal_fgcolor = (ptr[i] >> 20) & 0xF; terminal_bgcolor = (ptr[i] >> 16) & 0xF; break; case CFGTOKEN_BORDER: terminal_border = (ptr[i] >> 16) & 0xF; 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, 0xFF, sizeof(blockbuffer)); ptr[i++] = NEWCONFIG_MAGIC; ptr[i++] = CFGTOKEN_REVISION | ((rev & 0xff) << 16); ptr[i++] = CFGTOKEN_FONT_00 | ((((uint32_t)default_font) & 0x2F) << 20); if(mono_palette) { ptr[i++] = CFGTOKEN_MONO_80 | ((((uint32_t)mono_palette-1) & 0xF) << 20); } else { ptr[i++] = CFGTOKEN_MONO_00; } 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[i]), wifi_ssid, longmin(strlen(wifi_ssid)+1,31)); i += (strlen(wifi_ssid)+4) >> 2; ptr[i++] = CFGTOKEN_WIFI_PSK | (((uint32_t)strlen(wifi_psk)+1) << 24); strncpy((char*)(&ptr[i]), wifi_psk, longmin(strlen(wifi_psk)+1,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[i]), jd_host, longmin(strlen(jd_host)+1,31)); ptr += (strlen(jd_host)+4) >> 2; ptr[i++] = CFGTOKEN_JD_PORT; ptr[i++] = jd_port; ptr[i++] = NEWCONFIG_EOF_MARKER; 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_DATW = 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_DATR; } 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 last, 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]; last = RPY_BUFFER[3]; last <<= 8; last |= RPY_BUFFER[2]; if(cfg_cmd1("fe", last)) { backdrop(PROGNAME); window(" Error ", 28, 7, 1); gotoy(11); gotox(7); cprintf("Unable to erase block $%4X", block); ok_button(); goto cleanup; } 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 next, 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_DATR; } 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_DATW = 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; } next = RPY_BUFFER[5]; next <<= 8; next |= RPY_BUFFER[4]; last = RPY_BUFFER[3]; last <<= 8; last |= RPY_BUFFER[2]; 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(!prompt_slot(PROGNAME)) { goto cleanup; } 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; } 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(); while(paint_menu >= 0) { if(paint_menu == 2) { backdrop(PROGNAME); window(" Main Menu ", 26, 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; } } cleanup: backdrop(PROGNAME); gotoy(12); gotox(13); cputs("Launching Menu"); exec("MENU.SYSTEM", ""); }