analog-firmware/common/config.c

861 lines
26 KiB
C

#include "common/config.h"
#include "common/buffers.h"
#include "common/flash.h"
#include "common/build.h"
#include "common/dmacopy.h"
#ifdef FUNCTION_VGA
#include "vga/render.h"
#include "vga/vgaout.h"
extern volatile uint8_t romx_textbank;
extern volatile uint8_t romx_changed;
#endif
#ifdef FUNCTION_Z80
#include "z80/z80buf.h"
#endif
#include <string.h>
volatile compat_t cfg_machine = MACHINE_AUTO;
volatile compat_t current_machine = MACHINE_AUTO;
#ifdef FUNCTION_Z80
volatile usbmux_t usbmux;
volatile serialmux_t serialmux[2];
volatile wifimode_t wifimode;
uint8_t wifi_ssid[32];
uint8_t wifi_psk[32];
uint32_t wifi_address;
uint32_t wifi_netmask;
uint8_t jd_host[32];
uint16_t jd_port;
#endif
#ifdef FUNCTION_VGA
extern volatile bool userfont;
extern uint8_t character_rom[4096];
extern uint8_t terminal_character_rom[4096];
#endif
extern volatile bool businterface_hold;
extern volatile bool businterface_lockout;
volatile uint16_t cfptr = 0;
volatile uint8_t cfbuf[4096];
uint32_t config_temp[1024];
#define REPLY_OK 0x00
#define REPLY_BUSY 0xBB
#define REPLY_EOF 0x01
#define REPLY_NOFILE 0x02
#define REPLY_EPARAM 0x03
#define REPLY_ECMD 0x04
bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
uint32_t *config = (uint32_t*)address;
int i = 0;
if(config[0] != NEWCONFIG_MAGIC) {
return false;
}
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
if(config[i] == NEWCONFIG_EOF_MARKER) return true;
switch(config[i] & 0x0000FFFF) {
case CFGTOKEN_HOST_AUTO:
cfg_machine = MACHINE_AUTO;
internal_flags |= (IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case CFGTOKEN_HOST_II:
cfg_machine = MACHINE_II;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case CFGTOKEN_HOST_IIE:
cfg_machine = MACHINE_IIE;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
break;
case CFGTOKEN_HOST_IIGS:
cfg_machine = MACHINE_IIGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
break;
case CFGTOKEN_HOST_PRAVETZ:
cfg_machine = MACHINE_PRAVETZ;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case CFGTOKEN_HOST_BASIS:
cfg_machine = MACHINE_BASIS;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
#ifdef FUNCTION_VGA
case CFGTOKEN_FONT_00:
romx_textbank = (config[i] >> 16) & 0x2F;
romx_changed = 1;
break;
case CFGTOKEN_MONO_00:
mono_palette = (config[i] >> 20) & 0xF;
break;
case CFGTOKEN_TBCOLOR:
terminal_tbcolor = (config[i] >> 16) & 0xFF;
break;
case CFGTOKEN_BORDER:
terminal_border = (config[i] >> 16) & 0xF;
break;
case CFGTOKEN_RGBCOLOR:
lores_palette[(config[i] >> 16) & 0xF] = config[i+1];
dhgr_palette[((config[i] >> 17) & 0x7) | ((config[i] >> 13) & 0x8)] = config[i+1];
break;
case CFGTOKEN_VIDEO7:
if((config[i] >> 16) & 1) {
internal_flags |= IFLAGS_VIDEO7 | IFLAGS_V7_MODE3;
} else {
internal_flags &= ~IFLAGS_VIDEO7;
}
break;
#elif defined(FUNCTION_Z80)
case CFGTOKEN_MUX_LOOP:
serialmux[(config[i] >> 16) & 1] = SERIAL_LOOP;
break;
case CFGTOKEN_MUX_UART:
serialmux[(config[i] >> 16) & 1] = SERIAL_UART;
break;
case CFGTOKEN_MUX_USB:
serialmux[(config[i] >> 16) & 1] = SERIAL_USB;
break;
case CFGTOKEN_MUX_WIFI:
serialmux[(config[i] >> 16) & 1] = SERIAL_WIFI;
break;
case CFGTOKEN_MUX_PRN:
serialmux[(config[i] >> 16) & 1] = SERIAL_PRINTER;
break;
case CFGTOKEN_SER_BAUD:
sio[(config[i] >> 16) & 1].baudrate = config[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((char*)wifi_ssid, 0, sizeof(wifi_ssid));
strncpy((char*)wifi_ssid, (char*)(&config[i+1]), (config[i] >> 24));
break;
case CFGTOKEN_WIFI_PSK:
memset((char*)wifi_psk, 0, sizeof(wifi_psk));
strncpy((char*)wifi_psk, (char*)(&config[i+1]), (config[i] >> 24));
break;
case CFGTOKEN_WIFI_IP:
wifi_address = config[i+1];
break;
case CFGTOKEN_WIFI_NM:
wifi_netmask = config[i+1];
break;
case CFGTOKEN_JD_HOST:
memset((uint8_t*)jd_host, 0, sizeof(jd_host));
strncpy(jd_host, (char*)(&config[i+1]), (config[i] >> 24));
break;
case CFGTOKEN_JD_PORT:
jd_port = config[i+1];
break;
#endif
}
// Advance by the number of dwords for this token
i += (((config[i] >> 24) + 3) >> 2);
}
return false;
}
void DELAYED_COPY_CODE(default_config)() {
#ifdef FUNCTION_Z80
serialmux[0] = SERIAL_USB;
serialmux[1] = SERIAL_LOOP;
usbmux = USB_GUEST_CDC;
wifimode = WIFI_AP;
strcpy((char*)wifi_ssid, "V2RetroNet");
strcpy((char*)wifi_psk, "Analog");
#endif
#ifdef ANALOG_GS
cfg_machine = MACHINE_IIGS;
current_machine = MACHINE_IIGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
#else
cfg_machine = MACHINE_AUTO;
current_machine = MACHINE_AUTO;
internal_flags |= (IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
#endif
#ifdef FUNCTION_VGA
apple_tbcolor = 0xf0;
apple_border = 0x00;
terminal_tbcolor = 0xf0;
terminal_border = 0x00;
internal_flags |= IFLAGS_VIDEO7 | IFLAGS_V7_MODE3;
#endif
}
int DELAYED_COPY_CODE(make_config)(uint32_t rev) {
int i = 0;
memset(config_temp, 0, sizeof(config_temp));
config_temp[i++] = NEWCONFIG_MAGIC;
config_temp[i++] = CFGTOKEN_REVISION | ((rev & 0xff) << 16);
switch(cfg_machine) {
default:
case MACHINE_AUTO:
config_temp[i++] = CFGTOKEN_HOST_AUTO;
break;
case MACHINE_II:
config_temp[i++] = CFGTOKEN_HOST_II;
break;
case MACHINE_IIE:
config_temp[i++] = CFGTOKEN_HOST_IIE;
break;
case MACHINE_IIGS:
config_temp[i++] = CFGTOKEN_HOST_IIGS;
break;
case MACHINE_PRAVETZ:
config_temp[i++] = CFGTOKEN_HOST_PRAVETZ;
break;
case MACHINE_BASIS:
config_temp[i++] = CFGTOKEN_HOST_BASIS;
break;
}
#ifdef FUNCTION_Z80
switch(serialmux[0]) {
case SERIAL_USB:
config_temp[i++] = CFGTOKEN_MUX_USB;
break;
case SERIAL_UART:
config_temp[i++] = CFGTOKEN_MUX_UART;
break;
case SERIAL_WIFI:
config_temp[i++] = CFGTOKEN_MUX_WIFI;
break;
case SERIAL_PRINTER:
config_temp[i++] = CFGTOKEN_MUX_PRN;
break;
default:
case SERIAL_LOOP:
config_temp[i++] = CFGTOKEN_MUX_LOOP;
break;
}
switch(serialmux[1]) {
case SERIAL_USB:
config_temp[i++] = CFGTOKEN_MUX_USB | 0x10000;
break;
case SERIAL_UART:
config_temp[i++] = CFGTOKEN_MUX_UART | 0x10000;
break;
case SERIAL_WIFI:
config_temp[i++] = CFGTOKEN_MUX_WIFI | 0x10000;
break;
case SERIAL_PRINTER:
config_temp[i++] = CFGTOKEN_MUX_PRN | 0x10000;
break;
default:
case SERIAL_LOOP:
config_temp[i++] = CFGTOKEN_MUX_LOOP | 0x10000;
break;
}
switch(usbmux) {
case USB_HOST_CDC:
config_temp[i++] = CFGTOKEN_USB_HOST;
break;
default:
case USB_GUEST_CDC:
config_temp[i++] = CFGTOKEN_USB_GUEST;
break;
case USB_GUEST_MIDI:
config_temp[i++] = CFGTOKEN_USB_MIDI;
break;
}
switch(wifimode) {
case WIFI_CLIENT:
config_temp[i++] = CFGTOKEN_WIFI_AP;
break;
case WIFI_AP:
config_temp[i++] = CFGTOKEN_WIFI_CL;
break;
}
config_temp[i] = CFGTOKEN_WIFI_SSID | (((uint32_t)strlen((char*)wifi_ssid)+1) << 24);
strcpy((char*)(&config_temp[i+1]), (char*)wifi_ssid);
i += 1 + (((config_temp[i] >> 24) + 3) >> 2);
config_temp[i] = CFGTOKEN_WIFI_PSK | (((uint32_t)strlen((char*)wifi_psk)+1) << 24);
strcpy((char*)(&config_temp[i+1]), (char*)wifi_psk);
i += 1 + (((config_temp[i] >> 24) + 3) >> 2);
#endif
#ifdef FUNCTION_VGA
config_temp[i++] = CFGTOKEN_FONT_00 | ((romx_textbank & 0x2F) << 16);
config_temp[i++] = CFGTOKEN_MONO_00 | ((mono_palette & 0xF) << 20);
config_temp[i++] = CFGTOKEN_TBCOLOR | ((terminal_tbcolor & 0xFF) << 16);
config_temp[i++] = CFGTOKEN_BORDER | ((terminal_border & 0xF) << 16);
config_temp[i++] = CFGTOKEN_VIDEO7 | ((internal_flags & IFLAGS_VIDEO7) ? (1ul<<16) : 0);
for(uint32_t j = 0; j < 16; j++) {
config_temp[i++] = CFGTOKEN_RGBCOLOR | (j << 16);
config_temp[i++] = lores_palette[j];
}
#endif
config_temp[i++] = NEWCONFIG_EOF_MARKER;
return i * 4;
}
// Verify config block starts with the appropriate magic, has an end marker,
// and doesn't have any fields that would overflow the block.
bool DELAYED_COPY_CODE(is_config_valid)(uint32_t address) {
uint32_t *config = (uint32_t*)address;
int i;
if(config[0] != NEWCONFIG_MAGIC) return false;
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
if(config[i] == NEWCONFIG_EOF_MARKER) return true;
i += ((config[i] >> 24) + 3) >> 2;
}
return false;
}
// Find and return the config revision number for the block
uint8_t DELAYED_COPY_CODE(get_config_rev)(uint32_t address) {
uint32_t *config = (uint32_t*)address;
int i;
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
if((config[i] & 0x0000FFFF) == CFGTOKEN_REVISION)
return (config[i] >> 16) & 0xFF;
if(config[i] == NEWCONFIG_EOF_MARKER) return 0x00;
i += ((config[i] >> 24) + 3) >> 2;
}
return 0x00;
}
// Every time we write the config we overwrite the older slot,
// ensuring we don't leave the user without a configuration.
// We increment the revision number each time, wrapping back to 0x00 from 0xFF.
#if 0
bool DELAYED_COPY_CODE(is_primary_config_newer)() {
uint8_t a=get_config_rev(FLASH_CONFIG_PRIMARY);
uint8_t b=get_config_rev(FLASH_CONFIG_SECONDARY);
return ((int8_t)(a-b)) >= 0;
}
#endif
bool DELAYED_COPY_CODE(read_config)() {
if(is_config_valid(FLASH_CONFIG_ONETIME)) {
internal_flags &= ~IFLAGS_TEST;
soft_switches |= SOFTSW_TEXT_MODE;
if(parse_config(FLASH_CONFIG_ONETIME))
return true;
}
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(parse_config(FLASH_CONFIG_PRIMARY))
return true;
}
#if 0
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) {
if(parse_config(FLASH_CONFIG_PRIMARY))
return true;
}
}
if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
if(parse_config(FLASH_CONFIG_SECONDARY))
return true;
}
#endif
default_config();
return false;
}
bool DELAYED_COPY_CODE(write_config)(bool onetime) {
uint8_t rev = 0xFF;
bool write_secondary = false;
bool retval = false;
#ifdef FUNCTION_VGA
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
#endif
write_secondary = false;
rev = get_config_rev(FLASH_CONFIG_PRIMARY);
#if 0
if(is_config_valid(FLASH_CONFIG_PRIMARY) && is_config_valid(FLASH_CONFIG_SECONDARY)) {
write_secondary = is_primary_config_newer();
rev = write_secondary ? get_config_rev(FLASH_CONFIG_PRIMARY) : get_config_rev(FLASH_CONFIG_SECONDARY);
} else if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
write_secondary = true;
rev = get_config_rev(FLASH_CONFIG_PRIMARY);
} else if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
write_secondary = false;
rev = get_config_rev(FLASH_CONFIG_SECONDARY);
}
#endif
if(make_config(rev + 1) <= CONFIG_SIZE) {
if(onetime) {
flash_range_erase((FLASH_CONFIG_ONETIME-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_ONETIME-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
} else if(write_secondary) {
flash_range_erase((FLASH_CONFIG_SECONDARY-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_SECONDARY-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
} else {
flash_range_erase((FLASH_CONFIG_PRIMARY-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_PRIMARY-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
}
retval = true;
}
#ifdef FUNCTION_VGA
// Enable video output now that we are done
vga_dpms_wake();
#endif
return retval;
}
uint8_t DELAYED_COPY_CODE(get_config_block)() {
uint16_t last_config_block;
uint16_t next_config_block;
last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
next_config_block = last_config_block;
#if 0
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) {
last_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
next_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
} else {
last_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
next_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
}
} else if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
last_config_block = (FLASH_CONFIG_SECONDARY-XIP_BASE) / 4096;
next_config_block = (FLASH_CONFIG_PRIMARY-XIP_BASE) / 4096;
}
#endif
config_rpybuf[5] = (next_config_block >> 8) & 0xFF;
config_rpybuf[4] = (next_config_block >> 0) & 0xFF;
config_rpybuf[3] = (last_config_block >> 8) & 0xFF;
config_rpybuf[2] = (last_config_block >> 0) & 0xFF;
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(cf_readblock)(uint16_t param0) {
if(param0 >= (FLASH_SIZE/4096)) return REPLY_EPARAM;
#ifdef FUNCTION_VGA
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
#endif
memcpy32((void*)cfbuf, (void*)(XIP_BASE+(param0 * 4096)), 4096);
#ifdef FUNCTION_VGA
// Enable video output now that we are done
vga_dpms_wake();
#endif
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(cf_writeblock)(uint16_t param0) {
// Protect bottom 512K of flash
if(param0 < 0x080)
return REPLY_EPARAM;
if(param0 >= (FLASH_SIZE/4096))
return REPLY_EPARAM;
#ifdef FUNCTION_VGA
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
#endif
flash_range_program(((uint32_t)param0) * 4096, (void*)cfbuf, 4096);
#ifdef FUNCTION_VGA
// Enable video output now that we are done
vga_dpms_wake();
#endif
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(cf_eraseblock)(uint16_t param0) {
// Protect bottom 512K of flash
if(param0 < 0x080)
return REPLY_EPARAM;
if(param0 >= (FLASH_SIZE/4096))
return REPLY_EPARAM;
#ifdef FUNCTION_VGA
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
#endif
flash_range_erase(((uint32_t)param0) * 4096, 4096);
#ifdef FUNCTION_VGA
// Enable video output now that we are done
vga_dpms_wake();
#endif
return REPLY_OK;
}
#ifdef FUNCTION_VGA
uint8_t DELAYED_COPY_CODE(test_font)() {
int i;
for(i = 0; i < 2048; i++) {
character_rom[i] = cfbuf[i];
}
userfont = true;
return REPLY_OK;
}
#endif
uint8_t DELAYED_COPY_CODE(read_font)(uint16_t param0) {
if(param0 > 0x27) return REPLY_EPARAM;
return cf_readblock((FLASH_FONT(param0)-XIP_BASE) / 4096);
}
uint8_t DELAYED_COPY_CODE(erase_font)(uint16_t param0) {
int i;
if(param0 > 0x27) return REPLY_EPARAM;
#ifdef FUNCTION_VGA
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
#endif
flash_range_erase((FLASH_FONT(param0)-XIP_BASE), FONT_SIZE);
#ifdef FUNCTION_VGA
// Enable video output now that we are done
vga_dpms_wake();
#endif
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(write_font)(uint16_t param0) {
int i;
if(param0 > 0x27) return REPLY_EPARAM;
#ifdef FUNCTION_VGA
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
#endif
flash_range_program((FLASH_FONT(param0)-XIP_BASE), (void*)cfbuf, FONT_SIZE);
#ifdef FUNCTION_VGA
// Enable video output now that we are done
vga_dpms_wake();
#endif
return REPLY_OK;
}
void DELAYED_COPY_CODE(config_handler)() {
uint8_t retval = 0;
uint16_t param0, param1, param2;
int rs = 1;
if(config_cmdbuf[0] == 0xFF) return;
param0 = config_cmdbuf[3];
param0 <<= 8;
param0 |= config_cmdbuf[2];
param1 = config_cmdbuf[5];
param1 <<= 8;
param1 |= config_cmdbuf[4];
param2 = config_cmdbuf[7];
param2 <<= 8;
param2 |= config_cmdbuf[6];
config_rpybuf[7] = 0x00;
config_rpybuf[6] = 0x00;
config_rpybuf[5] = 0x00;
config_rpybuf[4] = 0x00;
config_rpybuf[3] = 0x00;
config_rpybuf[2] = 0x00;
config_rpybuf[1] = 0x00;
config_rpybuf[0] = REPLY_BUSY;
switch(config_cmdbuf[0]) {
case 'P':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
#ifdef FUNCTION_VGA
case 'r':
memcpy((void *)cfbuf, lores_palette, 16*2);
cfptr = 0;
retval = REPLY_OK;
break;
case 'T':
for(uint j = 0; j < 16; j++) {
#ifdef ANALOG_GS
lores_palette[j] = ((uint16_t *)cfbuf)[j] & 0xFFF;
#else
lores_palette[j] = ((uint16_t *)cfbuf)[j] & 0x1FF;
#endif
}
cfptr = 0;
retval = REPLY_OK;
break;
#endif
}
break;
case 'C':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
#ifdef FUNCTION_VGA
case 'T':
// One-time load of font data (lost at reboot)
retval = test_font();
case 'S':
romx_textbank = param0 & 0x2F;
romx_changed = 1;
retval = REPLY_OK;
#endif
case 'r':
// Read font from flash
retval = read_font(param0);
cfptr = 0;
break;
case 'w':
// Save font to flash
retval = write_font(param0);
cfptr = 0;
break;
case 'e':
// Erase font from flash
retval = erase_font(param0);
cfptr = 0;
break;
}
break;
case 'H':
retval = REPLY_OK;
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case '2':
current_machine = MACHINE_II;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case 'E':
current_machine = MACHINE_IIE;
internal_flags &= ~IFLAGS_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS;
break;
case 'G':
current_machine = MACHINE_IIGS;
internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS;
break;
#if 0
case 'B':
current_machine = MACHINE_BASIS;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case 'P':
current_machine = MACHINE_PRAVETZ;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case '7':
current_machine = MACHINE_AGAT7;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case '9':
current_machine = MACHINE_AGAT9;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
#endif
}
break;
case 'f':
// Flash Commands
// All valid flash commands will reset the cf pointer to 0
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case 'c':
// Current Config Block
retval = get_config_block();
cfptr = 0;
break;
case 'r':
// Read block
retval = cf_readblock(param0);
cfptr = 0;
break;
case 'w':
// Write block
retval = cf_writeblock(param0);
cfptr = 0;
break;
case 'e':
// Erase block
retval = cf_eraseblock(param0);
cfptr = 0;
break;
}
break;
case 'R':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case 'b':
// Reboot and bypass auto-detection of machine type.
cfg_machine = current_machine;
read_config();
write_config(true);
flash_reboot();
break;
}
break;
case 'I':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case 'H':
// Identify Current Host Setting
retval = REPLY_OK;
switch(current_machine) {
case MACHINE_II:
config_rpybuf[rs++] = '2';
break;
case MACHINE_IIE:
config_rpybuf[rs++] = 'E';
break;
case MACHINE_IIGS:
config_rpybuf[rs++] = 'G';
break;
default:
config_rpybuf[rs++] = '?';
retval = REPLY_EPARAM;
break;
}
break;
case 'F':
// Identify Current Firmware Function
retval = REPLY_OK;
#ifdef FUNCTION_VGA
config_rpybuf[rs++] = 'V';
config_rpybuf[rs++] = 'G';
config_rpybuf[rs++] = 'A';
#endif
#ifdef FUNCTION_Z80
config_rpybuf[rs++] = 'Z';
config_rpybuf[rs++] = '8';
config_rpybuf[rs++] = '0';
#endif
break;
case 'h':
// Identify Hardware Type
retval = REPLY_OK;
config_rpybuf[rs++] = 0x02; // V2 Retro Computing
config_rpybuf[rs++] = 'A'; // V2 Analog
config_rpybuf[rs++] = HWBYTE; // 'G'S / 'W'ifi / 'L'C
config_rpybuf[rs++] = HWREV; // '1'
break;
case 'j':
// Read jumpers
retval = REPLY_OK;
config_rpybuf[rs++] = jumpers;
break;
case 'd':
// Identify Date Request
retval = REPLY_OK;
config_rpybuf[rs++] = (BUILDDATE >> 24) & 0xFF;
config_rpybuf[rs++] = (BUILDDATE >> 16) & 0xFF;
config_rpybuf[rs++] = (BUILDDATE >> 8) & 0xFF;
config_rpybuf[rs++] = (BUILDDATE >> 0) & 0xFF;
config_rpybuf[rs++] = (BUILDID >> 8) & 0xFF;
config_rpybuf[rs++] = (BUILDID >> 0) & 0xFF;
break;
}
break;
default:
// Unrecognized command
retval = REPLY_ECMD;
}
config_cmdbuf[7] = 0xFF;
config_cmdbuf[6] = 0xFF;
config_cmdbuf[5] = 0xFF;
config_cmdbuf[4] = 0xFF;
config_cmdbuf[3] = 0xFF;
config_cmdbuf[2] = 0xFF;
config_cmdbuf[1] = 0xFF;
config_cmdbuf[0] = 0xFF;
config_rpybuf[0] = retval;
}