analog-utilities/src/config.c

1809 lines
47 KiB
C

#include <stdio.h>
#include <conio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#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", "");
}