diff --git a/iodevices/cromemco-88ccc.c b/iodevices/cromemco-88ccc.c index b7f1b313..b5c0993d 100644 --- a/iodevices/cromemco-88ccc.c +++ b/iodevices/cromemco-88ccc.c @@ -33,7 +33,7 @@ static const char *TAG = "88CCC"; /* 88CCC stuff */ -static int state; +static bool state; static WORD dma_addr; static BYTE flags; static BYTE format; @@ -64,7 +64,6 @@ static void *store_image(void *arg) while (state) { /* do until total frame is received */ if (net_device_alive(DEV_88ACC)) { - msg.auxiliary = flags & 0x0f; msg.bias = (flags & 0x20) >> 5; msg.fields = format & 0x0f; @@ -72,19 +71,21 @@ static void *store_image(void *arg) msgB = format | (msg.bias << 6); - LOGD(TAG, "CCC/ACC Capture: to addr %04x, fields: %d, interval %d", dma_addr, msg.fields, msg.interval); + LOGD(TAG, "CCC/ACC Capture: to addr %04x, fields: %d, interval %d", + dma_addr, msg.fields, msg.interval); - net_device_send(DEV_88ACC, (char *)&msgB, sizeof(msgB)); + net_device_send(DEV_88ACC, (char *) &msgB, sizeof(msgB)); for (i = 0; i < msg.fields; i++) { len = net_device_get_data(DEV_88ACC, (char *) buffer, FIELDSIZE); if (len != FIELDSIZE) { - LOGW(TAG,"Error in frame length, received %d of %d bytes.", len, FIELDSIZE); + LOGW(TAG, "Error in frame length, received %d of %d bytes.", + len, FIELDSIZE); } else { - LOGD(TAG, "received frame %d, length %d, %d stored at %04x", i, len, (BYTE)*buffer, dma_addr + (i * FIELDSIZE)); - for (j = 0; j < FIELDSIZE; j++) { - dma_write(dma_addr + (i * FIELDSIZE) + j, buffer[j]); - } + LOGD(TAG, "received frame %d, length %d, %d stored at %04x", + i, len, (BYTE) *buffer, dma_addr + (i * FIELDSIZE)); + for (j = 0; j < FIELDSIZE; j++) + dma_write(dma_addr + i * FIELDSIZE + j, buffer[j]); } } } else { @@ -93,35 +94,34 @@ static void *store_image(void *arg) } /* frame done, calculate total frame time */ - j = msg.fields * (msg.interval +1) * 2; + j = msg.fields * (msg.interval + 1) * 2; /* sleep_for_ms(j); */ /* sleep rest of total frame time */ t2 = get_clock_us(); tdiff = t2 - t1; - if (tdiff < (j*1000)) - sleep_for_ms(j - tdiff/1000); + if (tdiff < (j * 1000)) + sleep_for_ms(j - tdiff / 1000); LOGD(TAG, "Time: %d", tdiff); - state = 0; + state = false; } /* DMA complete, end the thread */ - state = 0; + state = false; thread = 0; pthread_exit(NULL); } void cromemco_88ccc_ctrl_a_out(BYTE data) { - flags = data & 0x7f; if (data & 0x80) { if (net_device_alive(DEV_88ACC)) { - state = 1; + state = true; if (thread == 0) { if (pthread_create(&thread, NULL, store_image, (void *) NULL)) { @@ -134,11 +134,11 @@ void cromemco_88ccc_ctrl_a_out(BYTE data) } else { /* No 88ACC camera attached */ LOGW(TAG, "No Cromemeco Cyclops 88ACC attached."); - state = 0; + state = false; } } else { - if (state == 1) { - state = 0; + if (state) { + state = false; sleep_for_ms(50); /* Arbitrary 50ms timeout to let thread exit after state change, TODO: maybe should end thread? */ @@ -154,13 +154,13 @@ void cromemco_88ccc_ctrl_b_out(BYTE data) void cromemco_88ccc_ctrl_c_out(BYTE data) { /* get DMA address for storage memory */ - dma_addr = (WORD)data << 7; + dma_addr = (WORD) data << 7; } BYTE cromemco_88ccc_ctrl_a_in(void) { /* return flags along with state in the msb */ - return flags | (state << 7); + return flags | (state ? 128 : 0); } #endif /* HAS_NETSERVER && HAS_CYCLOPS */ diff --git a/iodevices/cromemco-88ccc.h b/iodevices/cromemco-88ccc.h index 803b9d19..575774fc 100644 --- a/iodevices/cromemco-88ccc.h +++ b/iodevices/cromemco-88ccc.h @@ -1,10 +1,10 @@ /** * cromemco-88ccc.h - * + * * Emulation of the Cromemco 88 CCC - Cyclops Camera Controller * * Copyright (C) 2018 by David McNaughton - * + * * History: * 14-AUG-2018 1.0 Initial Release * 04-NOV-2019 remove fake DMA bus request diff --git a/iodevices/cromemco-d+7a.c b/iodevices/cromemco-d+7a.c index 9ddcbe9f..60b65e0b 100644 --- a/iodevices/cromemco-d+7a.c +++ b/iodevices/cromemco-d+7a.c @@ -31,44 +31,42 @@ static BYTE inPort[PORT_COUNT]; static BYTE outPort[PORT_COUNT]; #ifdef HAS_NETSERVER -static void cromemco_d7a_callback(BYTE *data) { +static void cromemco_d7a_callback(BYTE *data) +{ + int i; - int i; - inPort[0] = *data++; - for (i=1; i < PORT_COUNT; i++) { - inPort[i] = (*data++) - 128; - } + inPort[0] = *data++; + for (i = 1; i < PORT_COUNT; i++) + inPort[i] = (*data++) - 128; } #endif -void cromemco_d7a_init(void) { - - inPort[0] = 0xFF; +void cromemco_d7a_init(void) +{ + inPort[0] = 0xFF; #ifdef HAS_NETSERVER - if (n_flag) { - net_device_service(DEV_D7AIO, cromemco_d7a_callback); - } + if (n_flag) + net_device_service(DEV_D7AIO, cromemco_d7a_callback); #endif - } static void cromemco_d7a_out(BYTE port, BYTE data) { - outPort[port] = data; + outPort[port] = data; - LOGD(TAG, "Output %d on port %d", data, port); + LOGD(TAG, "Output %d on port %d", data, port); #ifdef HAS_NETSERVER - if (n_flag) { - // if (net_device_alive(DEV_D7AIO)) { - net_device_send(DEV_D7AIO, (char *)&data, 1); - // } - } + if (n_flag) { + // if (net_device_alive(DEV_D7AIO)) { + net_device_send(DEV_D7AIO, (char *) &data, 1); + // } + } #endif } -void cromemco_d7a_D_out(BYTE data) { cromemco_d7a_out(0, data); } +void cromemco_d7a_D_out (BYTE data) { cromemco_d7a_out(0, data); } void cromemco_d7a_A1_out(BYTE data) { cromemco_d7a_out(1, data); } void cromemco_d7a_A2_out(BYTE data) { cromemco_d7a_out(2, data); } void cromemco_d7a_A3_out(BYTE data) { cromemco_d7a_out(3, data); } @@ -82,7 +80,7 @@ static BYTE cromemco_d7a_in(BYTE port) return inPort[port]; } -BYTE cromemco_d7a_D_in(void) { return cromemco_d7a_in(0); }; +BYTE cromemco_d7a_D_in (void) { return cromemco_d7a_in(0); }; BYTE cromemco_d7a_A1_in(void) { return cromemco_d7a_in(1); }; BYTE cromemco_d7a_A2_in(void) { return cromemco_d7a_in(2); }; BYTE cromemco_d7a_A3_in(void) { return cromemco_d7a_in(3); }; diff --git a/iodevices/cromemco-d+7a.h b/iodevices/cromemco-d+7a.h index 8728cec5..048a0bb4 100644 --- a/iodevices/cromemco-d+7a.h +++ b/iodevices/cromemco-d+7a.h @@ -1,10 +1,10 @@ /** * cromemco-d+7a.h - * - * Emulation of the Cromemco D+7A I/O + * + * Emulation of the Cromemco D+7A I/O * * Copyright (C) 2020 by David McNaughton - * + * * History: * 14-JAN-2020 1.0 Initial Release */ diff --git a/iodevices/cromemco-dazzler.c b/iodevices/cromemco-dazzler.c index a3ff4cca..2757de8a 100644 --- a/iodevices/cromemco-dazzler.c +++ b/iodevices/cromemco-dazzler.c @@ -50,6 +50,7 @@ #ifdef HAS_DAZZLER #ifdef HAS_NETSERVER +#include #include "netsrv.h" #endif diff --git a/iodevices/cromemco-hal.c b/iodevices/cromemco-hal.c index 1b1301dc..423b5088 100644 --- a/iodevices/cromemco-hal.c +++ b/iodevices/cromemco-hal.c @@ -1,14 +1,14 @@ - /* - * cromemco-hal.c - * - * Copyright (C) 2022 by David McNaughton - * - * Cromemco TU-ART hardware abstraction layer - * - * History: - * 9-JUL-2022 1.0 Initial Release - * - */ +/* +* cromemco-hal.c +* +* Copyright (C) 2022 by David McNaughton +* +* Cromemco TU-ART hardware abstraction layer +* +* History: +* 9-JUL-2022 1.0 Initial Release +* +*/ #include #include @@ -38,148 +38,169 @@ static const char *TAG = "HAL"; /* -------------------- NULL device HAL -------------------- */ -static int null_alive(int dev) { - UNUSED(dev); +static bool null_alive(int dev) +{ + UNUSED(dev); - return 1; /* NULL is always alive */ + return true; /* NULL is always alive */ } + #if !defined(HAS_NETSERVER) || !defined(HAS_MODEM) -static int null_dead(int dev) { - UNUSED(dev); +static bool null_dead(int dev) +{ + UNUSED(dev); - return 0; /* NULL is always dead */ + return false; /* NULL is always dead */ } #endif -static void null_status(int dev, BYTE *stat) { - UNUSED(dev); - UNUSED(stat); - return; +static void null_status(int dev, BYTE *stat) +{ + UNUSED(dev); + UNUSED(stat); + + return; } -static int null_in(int dev) { - UNUSED(dev); - return -1; +static int null_in(int dev) +{ + UNUSED(dev); + + return -1; } -static void null_out(int dev, BYTE data) { - UNUSED(dev); - UNUSED(data); - return; +static void null_out(int dev, BYTE data) +{ + UNUSED(dev); + UNUSED(data); + + return; } /* -------------------- WEBTTY HAL -------------------- */ #ifdef HAS_NETSERVER -static int net_tty_alive(int dev) { - if (n_flag) { - // LOG(TAG, "WEBTTY %d: %d\r\n", dev, net_device_alive(dev)); - /* WEBTTY is only alive if websocket is connected */ - return net_device_alive((net_device_t) dev); - } else { - return 0; - } + +static bool net_tty_alive(int dev) +{ + if (n_flag) { + // LOG(TAG, "WEBTTY %d: %d\r\n", dev, net_device_alive(dev)); + /* WEBTTY is only alive if websocket is connected */ + return net_device_alive((net_device_t) dev); + } else + return false; } -static void net_tty_status(int dev, BYTE *stat) { - *stat &= (BYTE)(~3); - if (n_flag) { - if (net_device_poll((net_device_t) dev)) { - *stat |= 2; - } - *stat |= 1; - } + +static void net_tty_status(int dev, BYTE *stat) +{ + *stat &= (BYTE) (~3); + if (n_flag) { + if (net_device_poll((net_device_t) dev)) + *stat |= 2; + *stat |= 1; + } } -static int net_tty_in(int dev) { - if (n_flag) { - return net_device_get((net_device_t) dev); - } else { - return -1; - } + +static int net_tty_in(int dev) +{ + if (n_flag) + return net_device_get((net_device_t) dev); + else + return -1; } -static void net_tty_out(int dev, BYTE data) { - if (n_flag) { - net_device_send((net_device_t) dev, (char *)&data, 1); - } + +static void net_tty_out(int dev, BYTE data) +{ + if (n_flag) + net_device_send((net_device_t) dev, (char *)&data, 1); } -#endif + +#endif /* HAS_NETSERVER */ /* -------------------- STDIO HAL -------------------- */ -static int stdio_alive(int dev) { - UNUSED(dev); +static bool stdio_alive(int dev) +{ + UNUSED(dev); - return 1; /* STDIO is always alive */ + return true; /* STDIO is always alive */ } -static void stdio_status(int dev, BYTE *stat) { - struct pollfd p[1]; - - UNUSED(dev); - - p[0].fd = fileno(stdin); - p[0].events = POLLIN; - p[0].revents = 0; - poll(p, 1, 0); - *stat &= (BYTE)(~3); - if (p[0].revents & POLLIN) - *stat |= 2; - if (p[0].revents & POLLNVAL) { - LOGE(TAG, "can't use terminal, try 'screen simulation ...'"); - exit(EXIT_FAILURE); - // cpu_error = IOERROR; - // cpu_state = STOPPED; - } - *stat |= 1; +static void stdio_status(int dev, BYTE *stat) +{ + struct pollfd p[1]; + + UNUSED(dev); + + p[0].fd = fileno(stdin); + p[0].events = POLLIN; + p[0].revents = 0; + poll(p, 1, 0); + *stat &= (BYTE) (~3); + if (p[0].revents & POLLIN) + *stat |= 2; + if (p[0].revents & POLLNVAL) { + LOGE(TAG, "can't use terminal, try 'screen simulation ...'"); + exit(EXIT_FAILURE); + // cpu_error = IOERROR; + // cpu_state = STOPPED; + } + *stat |= 1; } -static int stdio_in(int dev) { - int data; - struct pollfd p[1]; - UNUSED(dev); +static int stdio_in(int dev) +{ + int data; + struct pollfd p[1]; + + UNUSED(dev); again: - /* if no input waiting return last */ - p[0].fd = fileno(stdin); - p[0].events = POLLIN; - p[0].revents = 0; - poll(p, 1, 0); - if (!(p[0].revents & POLLIN)) - return -1; - - if (read(fileno(stdin), &data, 1) == 0) { - /* try to reopen tty, input redirection exhausted */ - if (freopen("/dev/tty", "r", stdin) == NULL) - LOGE(TAG, "can't reopen /dev/tty"); - set_unix_terminal(); - goto again; - } - - return data; + /* if no input waiting return last */ + p[0].fd = fileno(stdin); + p[0].events = POLLIN; + p[0].revents = 0; + poll(p, 1, 0); + if (!(p[0].revents & POLLIN)) + return -1; + + if (read(fileno(stdin), &data, 1) == 0) { + /* try to reopen tty, input redirection exhausted */ + if (freopen("/dev/tty", "r", stdin) == NULL) + LOGE(TAG, "can't reopen /dev/tty"); + set_unix_terminal(); + goto again; + } + + return data; } -static void stdio_out(int dev, BYTE data) { - UNUSED(dev); + +static void stdio_out(int dev, BYTE data) +{ + UNUSED(dev); again: - if (write(fileno(stdout), (char *) &data, 1) != 1) { - if (errno == EINTR) { - goto again; - } else { - LOGE(TAG, "can't write data"); - cpu_error = IOERROR; - cpu_state = ST_STOPPED; - } - } + if (write(fileno(stdout), (char *) &data, 1) != 1) { + if (errno == EINTR) + goto again; + else { + LOGE(TAG, "can't write data"); + cpu_error = IOERROR; + cpu_state = ST_STOPPED; + } + } } /* -------------------- SOCKET SERVER HAL -------------------- */ -static int scktsrv_alive(int dev) { - - return ncons[dev].ssc; /* SCKTSRV is alive if there is an open socket */ +static bool scktsrv_alive(int dev) +{ + return ncons[dev].ssc != 0; /* SCKTSRV is alive if there is an open socket */ } -static void scktsrv_status(int dev, BYTE *stat) { - struct pollfd p[1]; +static void scktsrv_status(int dev, BYTE *stat) +{ + struct pollfd p[1]; /* if socket is connected check for I/O */ if (ncons[dev].ssc != 0) { @@ -187,22 +208,22 @@ static void scktsrv_status(int dev, BYTE *stat) { p[0].events = POLLIN; p[0].revents = 0; poll(p, 1, 0); - *stat &= (BYTE)(~3); + *stat &= (BYTE) (~3); if (p[0].revents & POLLHUP) { close(ncons[dev].ssc); ncons[dev].ssc = 0; - *stat = 0; - } else if (p[0].revents & POLLIN) { + *stat = 0; + } else if (p[0].revents & POLLIN) *stat |= 2; - } else { + else *stat |= 1; - } - } else { + } else *stat = 0; - } } -static int scktsrv_in(int dev) { - BYTE data, dummy; + +static int scktsrv_in(int dev) +{ + BYTE data, dummy; struct pollfd p[1]; /* if not connected return last */ @@ -218,30 +239,30 @@ static int scktsrv_in(int dev) { return -1; if (read(ncons[dev].ssc, &data, 1) != 1) { - if ((errno == EAGAIN) || (errno == EINTR)) { - /* EOF, close socket and return last */ - close(ncons[dev].ssc); - ncons[dev].ssc = 0; - return -1; - } else { - LOGE(TAG, "can't read tcpsocket %d data", dev); - cpu_error = IOERROR; - cpu_state = ST_STOPPED; - return 0; - } + if ((errno == EAGAIN) || (errno == EINTR)) { + /* EOF, close socket and return last */ + close(ncons[dev].ssc); + ncons[dev].ssc = 0; + return -1; + } else { + LOGE(TAG, "can't read tcpsocket %d data", dev); + cpu_error = IOERROR; + cpu_state = ST_STOPPED; + return 0; + } } - /* process read data */ - /* telnet client sends \r\n or \r\0, drop second character */ - if (ncons[dev].telnet && (data == '\r')) - if (read(ncons[dev].ssc, &dummy, 1) != 1) - LOGE(TAG, "can't read tcpsocket %d data", dev); - + /* process read data */ + /* telnet client sends \r\n or \r\0, drop second character */ + if (ncons[dev].telnet && (data == '\r')) + if (read(ncons[dev].ssc, &dummy, 1) != 1) + LOGE(TAG, "can't read tcpsocket %d data", dev); - return data; + return data; } -static void scktsrv_out(int dev, BYTE data) { +static void scktsrv_out(int dev, BYTE data) +{ /* return if socket not connected */ if (ncons[dev].ssc == 0) return; @@ -251,9 +272,9 @@ static void scktsrv_out(int dev, BYTE data) { if (errno == EINTR) { goto again; } else { - LOGE(TAG, "can't write socket %d data", dev); - cpu_error = IOERROR; - cpu_state = ST_STOPPED; + LOGE(TAG, "can't write socket %d data", dev); + cpu_error = IOERROR; + cpu_state = ST_STOPPED; } } } @@ -261,233 +282,237 @@ static void scktsrv_out(int dev, BYTE data) { /* -------------------- MODEM HAL -------------------- */ #ifdef HAS_MODEM + #include "generic-at-modem.h" -static int modem_alive(int dev) { - UNUSED(dev); +static bool modem_alive(int dev) +{ + UNUSED(dev); - return modem_device_alive(0); + return modem_device_alive(0); } -static void modem_status(int dev, BYTE *stat) { - UNUSED(dev); - - *stat &= (BYTE)(~3); - if (modem_device_poll(0)) { - *stat |= 2; - } - *stat |= 1; + +static void modem_status(int dev, BYTE *stat) +{ + UNUSED(dev); + + *stat &= (BYTE) (~3); + if (modem_device_poll(0)) + *stat |= 2; + *stat |= 1; } -static int modem_in(int dev) { - UNUSED(dev); - return modem_device_get(0); +static int modem_in(int dev) +{ + UNUSED(dev); + + return modem_device_get(0); } -static void modem_out(int dev, BYTE data){ - UNUSED(dev); - modem_device_send(0, (char) data); +static void modem_out(int dev, BYTE data) +{ + UNUSED(dev); + + modem_device_send(0, (char) data); } -#endif /*HAS_MODEM*/ + +#endif /* HAS_MODEM */ /* -------------------- HAL port/device mappings -------------------- */ -const char *tuart_port_name[MAX_TUART_PORT] = { "TUART0.deviceA", "TUART1.deviceA", "TUART1.deviceB" }; +const char *tuart_port_name[MAX_TUART_PORT] = + { "TUART0.deviceA", "TUART1.deviceA", "TUART1.deviceB" }; static const hal_device_t devices[] = { #ifdef HAS_NETSERVER - { "WEBTTY", 0, DEV_TTY, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, - { "WEBTTY2", 0, DEV_TTY2, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, - { "WEBTTY3", 0, DEV_TTY3, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, - { "WEBPTR", 0, DEV_PTR, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, + { "WEBTTY", false, DEV_TTY, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, + { "WEBTTY2", false, DEV_TTY2, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, + { "WEBTTY3", false, DEV_TTY3, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, + { "WEBPTR", false, DEV_PTR, net_tty_alive, net_tty_status, net_tty_in, net_tty_out }, #else - { "WEBTTY", 0, 0, null_dead, null_status, null_in, null_out }, - { "WEBTTY2", 0, 0, null_dead, null_status, null_in, null_out }, - { "WEBTTY3", 0, 0, null_dead, null_status, null_in, null_out }, - { "WEBPTR", 0, 0, null_dead, null_status, null_in, null_out }, + { "WEBTTY", false, 0, null_dead, null_status, null_in, null_out }, + { "WEBTTY2", false, 0, null_dead, null_status, null_in, null_out }, + { "WEBTTY3", false, 0, null_dead, null_status, null_in, null_out }, + { "WEBPTR", false, 0, null_dead, null_status, null_in, null_out }, #endif - { "STDIO", 0, 0, stdio_alive, stdio_status, stdio_in, stdio_out }, - { "SCKTSRV1", 0, 0, scktsrv_alive, scktsrv_status, scktsrv_in, scktsrv_out }, - { "SCKTSRV2", 0, 1, scktsrv_alive, scktsrv_status, scktsrv_in, scktsrv_out }, + { "STDIO", false, 0, stdio_alive, stdio_status, stdio_in, stdio_out }, + { "SCKTSRV1", false, 0, scktsrv_alive, scktsrv_status, scktsrv_in, scktsrv_out }, + { "SCKTSRV2", false, 1, scktsrv_alive, scktsrv_status, scktsrv_in, scktsrv_out }, #ifdef HAS_MODEM - { "MODEM", 0, 0, modem_alive, modem_status, modem_in, modem_out }, + { "MODEM", false, 0, modem_alive, modem_status, modem_in, modem_out }, #else - { "MODEM", 0, 0, null_dead, null_status, null_in, null_out }, + { "MODEM", false, 0, null_dead, null_status, null_in, null_out }, #endif - { "", 0, 0, null_alive, null_status, null_in, null_out } + { "", false, 0, null_alive, null_status, null_in, null_out } }; hal_device_t tuart[MAX_TUART_PORT][MAX_HAL_DEV]; /* -------------------- HAL utility functions -------------------- */ -static void hal_report(void) { - - int i, j; - - LOG(TAG, "\r\nTU-ART DEVICE MAP:\r\n"); - - for (i = 0; i < MAX_TUART_PORT; i++) { - - LOG(TAG, "%s = ", tuart_port_name[i]); - j = 0; - - while (tuart[i][j].name && j < MAX_HAL_DEV) { - - LOG(TAG, "%s%s", tuart[i][j].name, (tuart[i][j].fallthrough?"+":" ")); - - j++; - } - LOG(TAG, "\r\n"); - } +static void hal_report(void) +{ + int i, j; + + LOG(TAG, "\r\nTU-ART DEVICE MAP:\r\n"); + for (i = 0; i < MAX_TUART_PORT; i++) { + LOG(TAG, "%s = ", tuart_port_name[i]); + j = 0; + while (tuart[i][j].name && j < MAX_HAL_DEV) { + LOG(TAG, "%s%s", tuart[i][j].name, tuart[i][j].fallthrough ? "+" : " "); + j++; + } + LOG(TAG, "\r\n"); + } } -static int hal_find_device(char *dev) { - - int i=0; - while (i < MAX_HAL_DEV) { - if (!strcmp(dev, devices[i].name)) { - return i; - } - i++; - } - return -1; +static int hal_find_device(char *dev) +{ + int i = 0; + while (i < MAX_HAL_DEV) { + if (!strcmp(dev, devices[i].name)) + return i; + i++; + } + return -1; } -static void hal_init(void) { - - int i, j, d; - char *setting; - char match[80]; - char *dev; - - /** - * Initialize HAL with default configuration, as follows: - * - * TUART0.deviceA.device=WEBTTY,STDIO - * TUART1.deviceA.device=SCKTSRV1,WEBTTY2 - * TUART1.deviceB.device=SCKTSRV2,WEBTTY3 - * - * Notes: - * - all ports end with NULL and that is always alive - * - the first HAL device in the list that is alive will service the request - */ - tuart[0][0] = devices[WEBTTYDEV]; - tuart[0][1] = devices[STDIODEV]; - tuart[0][2] = devices[NULLDEV]; - - tuart[1][0] = devices[SCKTSRV1DEV]; - tuart[1][1] = devices[WEBTTY2DEV]; - tuart[1][2] = devices[NULLDEV]; - - tuart[2][0] = devices[SCKTSRV2DEV]; - tuart[2][1] = devices[WEBTTY3DEV]; - tuart[2][2] = devices[NULLDEV]; - - for (i = 0; i < MAX_TUART_PORT; i++) { - - j = 0; - strcpy(match, tuart_port_name[i]); - strcat(match, ".device"); - - if ((setting = getenv(match)) != NULL) { - LOGI(TAG, "%s = %s", match, setting); - - strcpy(match, setting); - - dev = strtok(match, ",\r"); - while (dev) { - - char k = dev[strlen(dev) - 1]; - int fallthrough = 0; - if (k == '+') { - dev[strlen(dev) - 1] = 0; - fallthrough = 1; - } - - d = hal_find_device(dev); - LOGI(TAG, "\tAdding %s to %s", dev, tuart_port_name[i]); - - if (d >= 0) { - memcpy(&tuart[i][j], &devices[d], sizeof(hal_device_t)); - tuart[i][j].fallthrough = fallthrough; - j++; - } - dev = strtok(NULL, ",\r"); - } - memcpy(&tuart[i][j], &devices[NULLDEV], sizeof(hal_device_t)); - } - } +static void hal_init(void) +{ + int i, j, d; + char *setting; + char match[80]; + char *dev; + + /** + * Initialize HAL with default configuration, as follows: + * + * TUART0.deviceA.device=WEBTTY,STDIO + * TUART1.deviceA.device=SCKTSRV1,WEBTTY2 + * TUART1.deviceB.device=SCKTSRV2,WEBTTY3 + * + * Notes: + * - all ports end with NULL and that is always alive + * - the first HAL device in the list that is alive will service the request + */ + tuart[0][0] = devices[WEBTTYDEV]; + tuart[0][1] = devices[STDIODEV]; + tuart[0][2] = devices[NULLDEV]; + + tuart[1][0] = devices[SCKTSRV1DEV]; + tuart[1][1] = devices[WEBTTY2DEV]; + tuart[1][2] = devices[NULLDEV]; + + tuart[2][0] = devices[SCKTSRV2DEV]; + tuart[2][1] = devices[WEBTTY3DEV]; + tuart[2][2] = devices[NULLDEV]; + + for (i = 0; i < MAX_TUART_PORT; i++) { + j = 0; + strcpy(match, tuart_port_name[i]); + strcat(match, ".device"); + + if ((setting = getenv(match)) != NULL) { + LOGI(TAG, "%s = %s", match, setting); + + strcpy(match, setting); + + dev = strtok(match, ",\r"); + while (dev) { + char k = dev[strlen(dev) - 1]; + bool fallthrough = false; + + if (k == '+') { + dev[strlen(dev) - 1] = 0; + fallthrough = true; + } + + d = hal_find_device(dev); + LOGI(TAG, "\tAdding %s to %s", dev, tuart_port_name[i]); + + if (d >= 0) { + memcpy(&tuart[i][j], &devices[d], sizeof(hal_device_t)); + tuart[i][j].fallthrough = fallthrough; + j++; + } + dev = strtok(NULL, ",\r"); + } + memcpy(&tuart[i][j], &devices[NULLDEV], sizeof(hal_device_t)); + } + } } -void hal_reset(void) { - hal_init(); - hal_report(); +void hal_reset(void) +{ + hal_init(); + hal_report(); } /* -------------------- HAL - TU-ART interface -------------------- */ -void hal_status_in(tuart_port_t dev, BYTE *stat) { - - int p = 0; - BYTE s; - *stat = 0; +void hal_status_in(tuart_port_t dev, BYTE *stat) +{ + int p = 0; + BYTE s; + *stat = 0; next: - while(!tuart[dev][p].alive(tuart[dev][p].device_id)) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!tuart[dev][p].alive(tuart[dev][p].device_id)) + p++; - tuart[dev][p].status(tuart[dev][p].device_id, &s); - *stat |= s; + tuart[dev][p].status(tuart[dev][p].device_id, &s); + *stat |= s; - if (tuart[dev][p].fallthrough) { - p++; - goto next; - } + if (tuart[dev][p].fallthrough) { + p++; + goto next; + } } -int hal_data_in(tuart_port_t dev) { - - int p = 0; - int in = 0; +int hal_data_in(tuart_port_t dev) +{ + int p = 0; + int in = 0; next: - while(!tuart[dev][p].alive(tuart[dev][p].device_id)) { /* Find the first device that is alive */ - p++; - } - - in = tuart[dev][p].in(tuart[dev][p].device_id); - - if (in < 0 && tuart[dev][p].fallthrough) { - p++; - goto next; - } else { - return in; - } -} + /* Find the first device that is alive */ + while (!tuart[dev][p].alive(tuart[dev][p].device_id)) + p++; + + in = tuart[dev][p].in(tuart[dev][p].device_id); -void hal_data_out(tuart_port_t dev, BYTE data) { + if (in < 0 && tuart[dev][p].fallthrough) { + p++; + goto next; + } else + return in; +} - int p = 0; +void hal_data_out(tuart_port_t dev, BYTE data) +{ + int p = 0; next: - while(!tuart[dev][p].alive(tuart[dev][p].device_id)) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!tuart[dev][p].alive(tuart[dev][p].device_id)) + p++; tuart[dev][p].out(tuart[dev][p].device_id, data); - if (tuart[dev][p].fallthrough) { - p++; - goto next; - } + if (tuart[dev][p].fallthrough) { + p++; + goto next; + } } -int hal_alive(tuart_port_t dev) { +bool hal_alive(tuart_port_t dev) +{ + int p = 0; - int p = 0; - while(!tuart[dev][p].alive(tuart[dev][p].device_id)) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!tuart[dev][p].alive(tuart[dev][p].device_id)) + p++; - return tuart[dev][p].name?1:0; /* return "alive" (true) when not the NULL device */ + /* return "alive" (true) when not the NULL device */ + return tuart[dev][p].name ? true : false; } diff --git a/iodevices/cromemco-hal.h b/iodevices/cromemco-hal.h index 67271ae0..9b5951a7 100644 --- a/iodevices/cromemco-hal.h +++ b/iodevices/cromemco-hal.h @@ -16,46 +16,42 @@ #include "sim.h" #include "simdefs.h" -enum tuart_port { +typedef enum tuart_port { TUART0A, TUART1A, TUART1B, - MAX_TUART_PORT -}; - -typedef enum tuart_port tuart_port_t; - -enum hal_dev { - WEBTTYDEV, - WEBTTY2DEV, - WEBTTY3DEV, - WEBPTRDEV, - STDIODEV, - SCKTSRV1DEV, - SCKTSRV2DEV, - MODEMDEV, - NULLDEV, - MAX_HAL_DEV -}; - -struct hal_device { - const char *name; - int fallthrough; - int device_id; - int (*alive)(int dev); - void (*status)(int dev, BYTE *stat); - int (*in)(int dev); - void (*out)(int dev, BYTE data); -}; - -typedef struct hal_device hal_device_t; + MAX_TUART_PORT +} tuart_port_t; + +typedef enum hal_dev { + WEBTTYDEV, + WEBTTY2DEV, + WEBTTY3DEV, + WEBPTRDEV, + STDIODEV, + SCKTSRV1DEV, + SCKTSRV2DEV, + MODEMDEV, + NULLDEV, + MAX_HAL_DEV +} hal_dev_t; + +typedef struct hal_device { + const char *name; + bool fallthrough; + int device_id; + bool (*alive)(int dev); + void (*status)(int dev, BYTE *stat); + int (*in)(int dev); + void (*out)(int dev, BYTE data); +} hal_device_t; extern void hal_reset(void); extern void hal_status_in(tuart_port_t dev, BYTE *stat); extern int hal_data_in(tuart_port_t dev); extern void hal_data_out(tuart_port_t dev, BYTE data); -extern int hal_alive(tuart_port_t dev); +extern bool hal_alive(tuart_port_t dev); extern const char *tuart_port_name[MAX_TUART_PORT]; extern hal_device_t tuart[MAX_TUART_PORT][MAX_HAL_DEV]; diff --git a/iodevices/cromemco-wdi.c b/iodevices/cromemco-wdi.c index fc4f5c4f..5a7a652a 100644 --- a/iodevices/cromemco-wdi.c +++ b/iodevices/cromemco-wdi.c @@ -34,613 +34,653 @@ #include "log.h" static const char *TAG = "wdi"; -#define WDI_UNITS 3 -#define WDI_SECTORS 0x14 -#define WDI_BLOCK_SIZE 512 +#define WDI_UNITS 3 +#define WDI_SECTORS 0x14 +#define WDI_BLOCK_SIZE 512 + +#define WDI_MAX_BUFFER (WDI_BLOCK_SIZE + 8) -#define WDI_MAX_BUFFER WDI_BLOCK_SIZE + 8 static BYTE buffer[WDI_MAX_BUFFER]; -static const char *images[WDI_UNITS] = { "hd0.hdd", "hd1.hdd", "hd2.hdd" }; //, "hd3.hdd" }; +static const char *images[WDI_UNITS] = + { "hd0.hdd", "hd1.hdd", "hd2.hdd" }; //, "hd3.hdd" }; + +#define MAX_DISK_PARAM 3 -#define MAX_DISK_PARAM 3 static struct { - int rpm; - int heads; - int cyl; - const char *type; + int rpm; + int heads; + int cyl; + const char *type; } disk_param[MAX_DISK_PARAM] = { - { 3600, 3, 0x162, "H8-1" }, - { 3600, 5, 0x184, "H8-3" }, - { 3600, 5, 0x308, "H8-4" } + { 3600, 3, 0x162, "H8-1" }, + { 3600, 5, 0x184, "H8-3" }, + { 3600, 5, 0x308, "H8-4" } }; -#define INDEX_INT (1000000*60*4) /* Index interval in T ticks per minute @ 4MHz */ +/* Index interval in T ticks per minute @ 4MHz */ +#define INDEX_INT (1000000 * 60 * 4) -enum wreg { WR_BASE, WR0, WR1, WR2, WR3, WR4, WR5, WR6 }; -typedef enum wreg wreg_t; +typedef enum wreg { WR_BASE, WR0, WR1, WR2, WR3, WR4, WR5, WR6 } wreg_t; -enum rreg { RR_BASE, RR0, RR1, RR2, RR3, RR4, RR5, RR6 }; -typedef enum rreg rreg_t; +typedef enum rreg { RR_BASE, RR0, RR1, RR2, RR3, RR4, RR5, RR6 } rreg_t; -enum dma_dev { MREQ, IORQ }; -typedef enum dma_dev dma_dev_t; +typedef enum dma_dev { MREQ, IORQ } dma_dev_t; static struct { - struct { - BYTE cmd_A; - BYTE cmd_B; - BYTE data_A; - BYTE data_B; - } pio0; - struct { - BYTE cmd_A; - BYTE cmd_A_state; - BYTE cmd_B; - BYTE cmd_B_state; - BYTE data_A; - BYTE data_B; - BYTE dir_A; - BYTE dir_B; - BYTE mode_A; - BYTE mode_B; - - BYTE _cmd_ak; - BYTE brd; - BYTE _seek_cmp; - BYTE dsk_id; - BYTE _cmd_stb; - BYTE _cmd_sel1; - BYTE _cmd_sel0; - BYTE cmd__r_w; - - BYTE _sel_un_ad3; - BYTE _sel_un_ad2; - BYTE _sel_un_ad1; - BYTE _sel_un_ad0; - BYTE dma_rdy; - BYTE _disk_op; - - BYTE bus_addr; - } pio1; - struct { - wreg_t wr_state; - rreg_t rr_state; - struct { - BYTE base; - BYTE dest; - BYTE mode; - WORD a_start; - WORD len; - WORD a_addr_counter; - WORD byte_counter; - } wr0; - struct { - BYTE base; - BYTE a_timing; - - dma_dev_t a_device; - BYTE a_fixed; - } wr1; - struct { - BYTE base; - BYTE b_timing; - - dma_dev_t b_device; - BYTE b_fixed; - } wr2; - struct { - BYTE base; - BYTE mask; - BYTE match; - } wr3; - struct { - BYTE base; - WORD b_start; - WORD b_addr_counter; - BYTE intr_control; - BYTE pulse_control; - BYTE intr_vector; - } wr4; - struct { - BYTE base; - } wr5; - struct { - BYTE base; - BYTE mask; - } wr6; - struct { - BYTE status; - } rr0; - BYTE force_ready; - BYTE enable_dma; - } dma; - struct { - BYTE mode0; - BYTE mode1; - BYTE mode2; - BYTE time0; - BYTE time1; - BYTE time2; - BYTE now0; - BYTE now1; - BYTE now2; - BYTE state0; - BYTE state1; - BYTE state2; - Tstates_t T0; - Tstates_t T1; - Tstates_t T2; - } ctc; - struct { - BYTE sector; - - int fd; - BYTE online; - BYTE _crc_error; - BYTE _fault; - - const char *fn; - int type; - char type_s[8]; - - struct { - BYTE uas; - BYTE has; - WORD cas; - BYTE write_gate; - BYTE read_gate; - } command; - struct { - BYTE uav; - BYTE hav; - WORD cav; - BYTE unit_rdy; - BYTE on_cyl; - BYTE seeking; - BYTE rezeroing; - BYTE write_prot; - BYTE illegal_address; - } status; - } hd[8]; /* always allow for the maximum number of units */ - - int unit; /* current selected hard disk unit*/ + struct { + BYTE cmd_A; + BYTE cmd_B; + BYTE data_A; + BYTE data_B; + } pio0; + struct { + BYTE cmd_A; + BYTE cmd_A_state; + BYTE cmd_B; + BYTE cmd_B_state; + BYTE data_A; + BYTE data_B; + BYTE dir_A; + BYTE dir_B; + BYTE mode_A; + BYTE mode_B; + + BYTE _cmd_ak; + BYTE brd; + BYTE _seek_cmp; + BYTE dsk_id; + BYTE _cmd_stb; + BYTE _cmd_sel1; + BYTE _cmd_sel0; + BYTE cmd__r_w; + + BYTE _sel_un_ad3; + BYTE _sel_un_ad2; + BYTE _sel_un_ad1; + BYTE _sel_un_ad0; + BYTE dma_rdy; + BYTE _disk_op; + + BYTE bus_addr; + } pio1; + struct { + wreg_t wr_state; + rreg_t rr_state; + struct { + BYTE base; + BYTE dest; + BYTE mode; + WORD a_start; + WORD len; + WORD a_addr_counter; + WORD byte_counter; + } wr0; + struct { + BYTE base; + BYTE a_timing; + + dma_dev_t a_device; + BYTE a_fixed; + } wr1; + struct { + BYTE base; + BYTE b_timing; + + dma_dev_t b_device; + BYTE b_fixed; + } wr2; + struct { + BYTE base; + BYTE mask; + BYTE match; + } wr3; + struct { + BYTE base; + WORD b_start; + WORD b_addr_counter; + BYTE intr_control; + BYTE pulse_control; + BYTE intr_vector; + } wr4; + struct { + BYTE base; + } wr5; + struct { + BYTE base; + BYTE mask; + } wr6; + struct { + BYTE status; + } rr0; + BYTE force_ready; + BYTE enable_dma; + } dma; + struct { + BYTE mode0; + BYTE mode1; + BYTE mode2; + BYTE time0; + BYTE time1; + BYTE time2; + BYTE now0; + BYTE now1; + BYTE now2; + BYTE state0; + BYTE state1; + BYTE state2; + Tstates_t T0; + Tstates_t T1; + Tstates_t T2; + } ctc; + struct { + BYTE sector; + + int fd; + BYTE online; + BYTE _crc_error; + BYTE _fault; + + const char *fn; + int type; + char type_s[8]; + + struct { + BYTE uas; + BYTE has; + WORD cas; + BYTE write_gate; + BYTE read_gate; + } command; + struct { + BYTE uav; + BYTE hav; + WORD cav; + BYTE unit_rdy; + BYTE on_cyl; + BYTE seeking; + BYTE rezeroing; + BYTE write_prot; + BYTE illegal_address; + } status; + } hd[8]; /* always allow for the maximum number of units */ + + int unit; /* current selected hard disk unit*/ } wdi; void wdi_exit(void) { - int unit; - - for (unit = 0; unit < WDI_UNITS; unit++) { - - if (wdi.hd[unit].fd) { - fsync(wdi.hd[unit].fd); - close(wdi.hd[unit].fd); - wdi.hd[unit].fd =0; - } - wdi.hd[unit].online = 0; - } + int unit; + + for (unit = 0; unit < WDI_UNITS; unit++) { + if (wdi.hd[unit].fd) { + fsync(wdi.hd[unit].fd); + close(wdi.hd[unit].fd); + wdi.hd[unit].fd = 0; + } + wdi.hd[unit].online = 0; + } } + void wdi_init(void) { - char fn[MAX_LFN]; /* path/filename for hard disk image */ - int fd; /* fd for hard disk i/o */ - int unit; - int i; - - wdi.pio1.cmd_A = 0xff; - wdi.pio1.cmd_B = 0xff; - wdi.pio1.cmd_A_state = 0; - wdi.pio1.cmd_B_state = 0; - wdi.pio1.data_A = 0; - wdi.pio1.data_B = 0; - wdi.pio1.dir_A = 0xFF; - wdi.pio1.dir_B = 0xFF; - wdi.pio1.mode_A = 1; - wdi.pio1.mode_B = 1; - - wdi.dma.wr_state = WR_BASE; - wdi.dma.rr_state = RR_BASE; - - wdi.ctc.now0 = 0; - wdi.ctc.now1 = 0; - wdi.ctc.now2 = 0; - - wdi.ctc.state0 = 0; - wdi.ctc.state1 = 0; - wdi.ctc.state2 = 0; - - LOG(TAG, "HARD DISK MAP: [%s]\r\n", dsk_path()); - - for (unit = 0; unit < WDI_UNITS; unit++) { - - wdi.hd[unit].online = 0; - wdi.hd[unit]._fault = 1; - wdi.hd[unit]._crc_error = 0; - - wdi.hd[unit].command.write_gate = 0; - wdi.hd[unit].command.read_gate = 0; - - wdi.hd[unit].status.unit_rdy = 0; - wdi.hd[unit].status.on_cyl = 0; - wdi.hd[unit].status.seeking = 0; - wdi.hd[unit].status.rezeroing = 0; - wdi.hd[unit].status.write_prot = 0; - wdi.hd[unit].status.illegal_address = 0; - - wdi.hd[unit].fn = images[unit]; - - strcpy(fn, (const char *)dsk_path()); - strcat(fn, "/"); - strcat(fn, wdi.hd[unit].fn); - - int got_eintr = 0; + char fn[MAX_LFN]; /* path/filename for hard disk image */ + int fd; /* fd for hard disk i/o */ + int unit; + int i; + + wdi.pio1.cmd_A = 0xff; + wdi.pio1.cmd_B = 0xff; + wdi.pio1.cmd_A_state = 0; + wdi.pio1.cmd_B_state = 0; + wdi.pio1.data_A = 0; + wdi.pio1.data_B = 0; + wdi.pio1.dir_A = 0xFF; + wdi.pio1.dir_B = 0xFF; + wdi.pio1.mode_A = 1; + wdi.pio1.mode_B = 1; + + wdi.dma.wr_state = WR_BASE; + wdi.dma.rr_state = RR_BASE; + + wdi.ctc.now0 = 0; + wdi.ctc.now1 = 0; + wdi.ctc.now2 = 0; + + wdi.ctc.state0 = 0; + wdi.ctc.state1 = 0; + wdi.ctc.state2 = 0; + + LOG(TAG, "HARD DISK MAP: [%s]\r\n", dsk_path()); + + for (unit = 0; unit < WDI_UNITS; unit++) { + wdi.hd[unit].online = 0; + wdi.hd[unit]._fault = 1; + wdi.hd[unit]._crc_error = 0; + + wdi.hd[unit].command.write_gate = 0; + wdi.hd[unit].command.read_gate = 0; + + wdi.hd[unit].status.unit_rdy = 0; + wdi.hd[unit].status.on_cyl = 0; + wdi.hd[unit].status.seeking = 0; + wdi.hd[unit].status.rezeroing = 0; + wdi.hd[unit].status.write_prot = 0; + wdi.hd[unit].status.illegal_address = 0; + + wdi.hd[unit].fn = images[unit]; + + strcpy(fn, (const char *)dsk_path()); + strcat(fn, "/"); + strcat(fn, wdi.hd[unit].fn); + + int got_eintr = 0; again: - if ((fd = open(fn, O_RDWR)) == -1) { - if (errno == EINTR) { - if (!got_eintr) LOGW(TAG, "INIT: GOT EINTR - %s : errno %d", fn, errno); - got_eintr++; - goto again; - } else if ((fd = open(fn, O_RDONLY)) != -1) { - wdi.hd[unit].status.write_prot = 1; - } else { - LOGW(TAG, "INIT: HDD FILE DOES NOT EXIST - %s : %s [%d]", fn, strerror(errno), errno); - wdi.hd[unit]._fault = 0; /* SET FAULT */ - wdi.hd[unit].online = 0; - LOG(TAG, "HD%d: OFFLINE - NO FILE '%s'\r\n", unit, wdi.hd[unit].fn); - continue; - } - } - - if (got_eintr) LOGW(TAG, "INIT: GOT EINTR: total %d", got_eintr); - - wdi.hd[unit].online = 1; - wdi.hd[unit].fd = fd; - - struct stat s; - fstat(fd, &s); - - wdi.hd[unit].type = -1; - - for (i = 0; i < MAX_DISK_PARAM; i++) { - - int size = WDI_BLOCK_SIZE * WDI_SECTORS * disk_param[i].cyl * disk_param[i].heads; - - if (s.st_size == size) { - wdi.hd[unit].type = i; - if (read(fd, buffer, WDI_BLOCK_SIZE) == WDI_BLOCK_SIZE) { - memcpy(wdi.hd[unit].type_s, (char *)&buffer[0x78], 4); - wdi.hd[unit].type_s[5] = '\0'; - } else { - wdi.hd[unit]._fault = 0; /* read fault */ - } - } - } - if (wdi.hd[unit].type < 0) { - wdi.hd[unit]._fault = 0; - wdi.hd[unit].type = 0; - strcpy(wdi.hd[unit].type_s, disk_param[wdi.hd[unit].type].type); - LOGW(TAG, "UNKNOWN DISK IMAGE SIZE [%lld] FOR %s", (long long) s.st_size, wdi.hd[unit].fn); - } - - LOG(TAG, "HD%d:[%s]='%s'\r\n", unit, wdi.hd[unit].type_s, wdi.hd[unit].fn); - } - - LOG(TAG, "\r\n"); - - wdi.unit = 0; + if ((fd = open(fn, O_RDWR)) == -1) { + if (errno == EINTR) { + if (!got_eintr) + LOGW(TAG, "INIT: GOT EINTR - %s : errno %d", + fn, errno); + got_eintr++; + goto again; + } else if ((fd = open(fn, O_RDONLY)) != -1) + wdi.hd[unit].status.write_prot = 1; + else { + LOGW(TAG, "INIT: HDD FILE DOES NOT EXIST - %s : %s [%d]", + fn, strerror(errno), errno); + wdi.hd[unit]._fault = 0; /* SET FAULT */ + wdi.hd[unit].online = 0; + LOG(TAG, "HD%d: OFFLINE - NO FILE '%s'\r\n", + unit, wdi.hd[unit].fn); + continue; + } + } + + if (got_eintr) + LOGW(TAG, "INIT: GOT EINTR: total %d", got_eintr); + + wdi.hd[unit].online = 1; + wdi.hd[unit].fd = fd; + + struct stat s; + + fstat(fd, &s); + + wdi.hd[unit].type = -1; + + for (i = 0; i < MAX_DISK_PARAM; i++) { + int size = (WDI_BLOCK_SIZE * WDI_SECTORS * disk_param[i].cyl + * disk_param[i].heads); + + if (s.st_size == size) { + wdi.hd[unit].type = i; + if (read(fd, buffer, WDI_BLOCK_SIZE) == WDI_BLOCK_SIZE) { + memcpy(wdi.hd[unit].type_s, (char *) &buffer[0x78], 4); + wdi.hd[unit].type_s[5] = '\0'; + } else + wdi.hd[unit]._fault = 0; /* read fault */ + } + } + if (wdi.hd[unit].type < 0) { + wdi.hd[unit]._fault = 0; + wdi.hd[unit].type = 0; + strcpy(wdi.hd[unit].type_s, disk_param[wdi.hd[unit].type].type); + LOGW(TAG, "UNKNOWN DISK IMAGE SIZE [%lld] FOR %s", + (long long) s.st_size, wdi.hd[unit].fn); + } + + LOG(TAG, "HD%d:[%s]='%s'\r\n", unit, wdi.hd[unit].type_s, wdi.hd[unit].fn); + } + + LOG(TAG, "\r\n"); + + wdi.unit = 0; } + #ifdef HAS_NETSERVER void sendHardDisks(HttpdConnection_t *conn) { - int i; - for (i = 0; i < WDI_UNITS; i++) { - httpdPrintf(conn, ",\"HD%d\": { \"type\": \"%s\", \"file\": \"%s\"}", i, wdi.hd[i].type_s, wdi.hd[i].online?wdi.hd[i].fn:""); - } + int i; + + for (i = 0; i < WDI_UNITS; i++) + httpdPrintf(conn, ",\"HD%d\": { \"type\": \"%s\", \"file\": \"%s\"}", + i, wdi.hd[i].type_s, wdi.hd[i].online ? wdi.hd[i].fn : ""); } #endif + static off_t wdi_pos(BYTE *buf) { - off_t p; - const int c = disk_param[wdi.hd[wdi.unit].type].cyl; - const int s = WDI_SECTORS; - const int b = WDI_BLOCK_SIZE; + off_t p; + const int c = disk_param[wdi.hd[wdi.unit].type].cyl; + const int s = WDI_SECTORS; + const int b = WDI_BLOCK_SIZE; - int cyl = buf[1] + (buf[2] << 8); + int cyl = buf[1] + (buf[2] << 8); - p = buf[0] * c * s * b; - p += cyl * s * b; - p += buf[3] * b; + p = buf[0] * c * s * b; + p += cyl * s * b; + p += buf[3] * b; - return p; + return p; } + static Tstates_t wdi_dma_write(BYTE bus_ack) { - int i; - - if (!bus_ack) return 0; - - LOGI(TAG, "WRITE: head: %d, cyl: %x", wdi.hd[wdi.unit].status.hav, wdi.hd[wdi.unit].status.cav); - LOGI(TAG, " start: %04x, addr: %04x, len: %d", wdi.dma.wr4.b_start, wdi.dma.wr4.b_addr_counter, wdi.dma.wr0.len); - - if (wdi.dma.wr0.len >= WDI_MAX_BUFFER) { - wdi.hd[wdi.unit]._fault = 0; /* SET FAULT */ - LOGE(TAG, "DMA length: %d > buffer: %d", wdi.dma.wr0.len, WDI_MAX_BUFFER); - return 0; - } - - for (i = 0; i <= wdi.dma.wr0.len; i++) { - buffer[i] = dma_read(wdi.dma.wr4.b_addr_counter++); - } - - LOGI(TAG, " SYNC: %02x, HEAD: %02x, CYL: %02x%02x, SEC: %02x", buffer[0], buffer[1], buffer[3], buffer[2], buffer[4]); - - int cyl = (buffer[3] << 8 ) | buffer[2]; - - if (wdi.hd[wdi.unit].status.hav != buffer[1]) { - LOGE(TAG, "DISK WRITE ERROR UNIT [%d] - BAD HEAD %d : %d", wdi.unit, wdi.hd[wdi.unit].status.hav, buffer[1]); - wdi.hd[wdi.unit]._fault = 0; /* SET FAULT */ - return 0; - } - if (wdi.hd[wdi.unit].status.cav != cyl) { - LOGE(TAG, "DISK WRITE ERROR UNIT [%d] - BAD CYLINDER %d : %d", wdi.unit, wdi.hd[wdi.unit].status.cav, cyl); - wdi.hd[wdi.unit]._fault = 0; /* SET FAULT */ - return 0; - } - - struct stat s; - - fstat(wdi.hd[wdi.unit].fd, &s); - if (s.st_mode & S_IWUSR) - wdi.hd[wdi.unit].status.write_prot = 0; - else - wdi.hd[wdi.unit].status.write_prot = 1; - - off_t pos = wdi_pos(&buffer[1]); - - if (lseek(wdi.hd[wdi.unit].fd, pos, SEEK_SET) == -1L) { - wdi.hd[wdi.unit]._fault = 0; /* write fault */ - return 0; - } - - /* write the sector */ - if (write(wdi.hd[wdi.unit].fd, &buffer[5], WDI_BLOCK_SIZE) == WDI_BLOCK_SIZE) - wdi.hd[wdi.unit]._fault = 1; - else - wdi.hd[wdi.unit]._fault = 0; /* write fault */ - - // if (fsync(wdi.hd[wdi.unit].fd) == -1) { - // LOGW(TAG, "WRITE: SYNC FAILED - %s [%d]", strerror(errno), errno); - // }; - - return wdi.dma.wr0.len * 3; /* 3 t-states per byte of DMA */ + int i; + + if (!bus_ack) + return 0; + + LOGI(TAG, "WRITE: head: %d, cyl: %x", wdi.hd[wdi.unit].status.hav, + wdi.hd[wdi.unit].status.cav); + LOGI(TAG, " start: %04x, addr: %04x, len: %d", wdi.dma.wr4.b_start, + wdi.dma.wr4.b_addr_counter, wdi.dma.wr0.len); + + if (wdi.dma.wr0.len >= WDI_MAX_BUFFER) { + wdi.hd[wdi.unit]._fault = 0; /* SET FAULT */ + LOGE(TAG, "DMA length: %d > buffer: %d", wdi.dma.wr0.len, WDI_MAX_BUFFER); + return 0; + } + + for (i = 0; i <= wdi.dma.wr0.len; i++) + buffer[i] = dma_read(wdi.dma.wr4.b_addr_counter++); + + LOGI(TAG, " SYNC: %02x, HEAD: %02x, CYL: %02x%02x, SEC: %02x", + buffer[0], buffer[1], buffer[3], buffer[2], buffer[4]); + + int cyl = (buffer[3] << 8) | buffer[2]; + + if (wdi.hd[wdi.unit].status.hav != buffer[1]) { + LOGE(TAG, "DISK WRITE ERROR UNIT [%d] - BAD HEAD %d : %d", + wdi.unit, wdi.hd[wdi.unit].status.hav, buffer[1]); + wdi.hd[wdi.unit]._fault = 0; /* SET FAULT */ + return 0; + } + if (wdi.hd[wdi.unit].status.cav != cyl) { + LOGE(TAG, "DISK WRITE ERROR UNIT [%d] - BAD CYLINDER %d : %d", + wdi.unit, wdi.hd[wdi.unit].status.cav, cyl); + wdi.hd[wdi.unit]._fault = 0; /* SET FAULT */ + return 0; + } + + struct stat s; + + fstat(wdi.hd[wdi.unit].fd, &s); + if (s.st_mode & S_IWUSR) + wdi.hd[wdi.unit].status.write_prot = 0; + else + wdi.hd[wdi.unit].status.write_prot = 1; + + off_t pos = wdi_pos(&buffer[1]); + + if (lseek(wdi.hd[wdi.unit].fd, pos, SEEK_SET) == -1L) { + wdi.hd[wdi.unit]._fault = 0; /* write fault */ + return 0; + } + + /* write the sector */ + if (write(wdi.hd[wdi.unit].fd, &buffer[5], WDI_BLOCK_SIZE) == WDI_BLOCK_SIZE) + wdi.hd[wdi.unit]._fault = 1; + else + wdi.hd[wdi.unit]._fault = 0; /* write fault */ + + // if (fsync(wdi.hd[wdi.unit].fd) == -1) { + // LOGW(TAG, "WRITE: SYNC FAILED - %s [%d]", strerror(errno), errno); + // }; + + return wdi.dma.wr0.len * 3; /* 3 t-states per byte of DMA */ } + static Tstates_t wdi_dma_read(BYTE bus_ack) { - register int v; - int i; - - if (!bus_ack) return 0; - - buffer[0] = wdi.hd[wdi.unit].status.hav; - buffer[1] = wdi.hd[wdi.unit].status.cav & 0xff; - buffer[2] = wdi.hd[wdi.unit].status.cav >> 8; - buffer[3] = wdi.hd[wdi.unit].sector; - - LOGI(TAG, "READ %s: head: %d, cyl: %d, sec: %d", (wdi.dma.wr0.len==4)?"HEADER":"DATA", wdi.hd[wdi.unit].status.hav, wdi.hd[wdi.unit].status.cav, wdi.hd[wdi.unit].sector); - LOGI(TAG, " start: %04x, addr: %04x, len: %d", wdi.dma.wr4.b_start, wdi.dma.wr4.b_addr_counter, wdi.dma.wr0.len); - - wdi.hd[wdi.unit].sector++; - wdi.hd[wdi.unit].sector %= WDI_SECTORS; - - struct stat s; - - fstat(wdi.hd[wdi.unit].fd, &s); - if (s.st_mode & S_IWUSR) - wdi.hd[wdi.unit].status.write_prot = 0; - else - wdi.hd[wdi.unit].status.write_prot = 1; - - off_t pos = wdi_pos(buffer); - - if (lseek(wdi.hd[wdi.unit].fd, pos, SEEK_SET) == -1L) { - wdi.hd[wdi.unit]._fault = 0; /* read fault */ - return 0; - } - - /* read the sector */ - if (read(wdi.hd[wdi.unit].fd, &buffer[4], WDI_BLOCK_SIZE) == WDI_BLOCK_SIZE) { - wdi.hd[wdi.unit]._fault = 1; - } else { - wdi.hd[wdi.unit]._fault = 0; /* read fault */ - return 0; - } - - for (i = 0; i < wdi.dma.wr0.len; i++) { - v = buffer[i]; - - dma_write(wdi.dma.wr4.b_addr_counter, v); - wdi.dma.wr4.b_addr_counter++; - } - - return wdi.dma.wr0.len * 3; /* 3 t-states per byte of DMA */ + register int v; + int i; + + if (!bus_ack) + return 0; + + buffer[0] = wdi.hd[wdi.unit].status.hav; + buffer[1] = wdi.hd[wdi.unit].status.cav & 0xff; + buffer[2] = wdi.hd[wdi.unit].status.cav >> 8; + buffer[3] = wdi.hd[wdi.unit].sector; + + LOGI(TAG, "READ %s: head: %d, cyl: %d, sec: %d", + (wdi.dma.wr0.len == 4) ? "HEADER" : "DATA", + wdi.hd[wdi.unit].status.hav, wdi.hd[wdi.unit].status.cav, + wdi.hd[wdi.unit].sector); + LOGI(TAG, " start: %04x, addr: %04x, len: %d", wdi.dma.wr4.b_start, + wdi.dma.wr4.b_addr_counter, wdi.dma.wr0.len); + + wdi.hd[wdi.unit].sector++; + wdi.hd[wdi.unit].sector %= WDI_SECTORS; + + struct stat s; + + fstat(wdi.hd[wdi.unit].fd, &s); + if (s.st_mode & S_IWUSR) + wdi.hd[wdi.unit].status.write_prot = 0; + else + wdi.hd[wdi.unit].status.write_prot = 1; + + off_t pos = wdi_pos(buffer); + + if (lseek(wdi.hd[wdi.unit].fd, pos, SEEK_SET) == -1L) { + wdi.hd[wdi.unit]._fault = 0; /* read fault */ + return 0; + } + + /* read the sector */ + if (read(wdi.hd[wdi.unit].fd, &buffer[4], WDI_BLOCK_SIZE) == WDI_BLOCK_SIZE) + wdi.hd[wdi.unit]._fault = 1; + else { + wdi.hd[wdi.unit]._fault = 0; /* read fault */ + return 0; + } + + for (i = 0; i < wdi.dma.wr0.len; i++) { + v = buffer[i]; + + dma_write(wdi.dma.wr4.b_addr_counter, v); + wdi.dma.wr4.b_addr_counter++; + } + + return wdi.dma.wr0.len * 3; /* 3 t-states per byte of DMA */ } + BYTE cromemco_wdi_pio0a_data_in(void) { LOGW(TAG, "E0 IN:"); return (BYTE) 0xFF; } + BYTE cromemco_wdi_pio0b_data_in(void) { - BYTE val = 0; - int bus = wdi.pio1.bus_addr; - - LOGD(TAG, "E1 IN: - bus %d",bus); - - switch (bus) - { - case 0: - case 1: - case 2: - case 3: - val = wdi.pio0.data_A; - break; - case 4: - case 5: - case 6: - case 7: - val = wdi.pio0.data_B; - break; - default: - break; - } - LOGD(TAG, "STATUS %d = %02x", bus, val); + BYTE val = 0; + int bus = wdi.pio1.bus_addr; + + LOGD(TAG, "E1 IN: - bus %d", bus); + + switch (bus) { + case 0: + case 1: + case 2: + case 3: + val = wdi.pio0.data_A; + break; + case 4: + case 5: + case 6: + case 7: + val = wdi.pio0.data_B; + break; + default: + break; + } + LOGD(TAG, "STATUS %d = %02x", bus, val); return val; } + BYTE cromemco_wdi_pio0a_cmd_in(void) { LOGW(TAG, "E2 IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_pio0b_cmd_in(void) { LOGW(TAG, "E3 IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_pio1a_data_in(void) { BYTE val = wdi.pio1.dir_A; /* pull inputs HIGH */ - if (!wdi.pio1.brd) { - val ^= 0x40; - } + if (!wdi.pio1.brd) + val ^= 0x40; - if (wdi.hd[wdi.unit].online) { /* Only respond if online */ - if (!wdi.hd[wdi.unit].status.seeking) { - val ^= 0x20; /* _SEEK_COMPLETE if not SEEKING */ - } - if (wdi.pio1._cmd_stb) { - val ^= 0x80; /* _CMD_AK on _CMD_STB */ - } - } + if (wdi.hd[wdi.unit].online) { /* Only respond if online */ + if (!wdi.hd[wdi.unit].status.seeking) + val ^= 0x20; /* _SEEK_COMPLETE if not SEEKING */ + if (wdi.pio1._cmd_stb) + val ^= 0x80; /* _CMD_AK on _CMD_STB */ + } - val = (wdi.pio1.data_A & ~wdi.pio1.dir_A) | val; + val = (wdi.pio1.data_A & ~wdi.pio1.dir_A) | val; - LOGD(TAG, "E4 IN: = %02x", val); + LOGD(TAG, "E4 IN: = %02x", val); return val; } + BYTE cromemco_wdi_pio1b_data_in(void) { BYTE val = wdi.pio1.dir_B; /* pull inputs HIGH */ - if (wdi.hd[wdi.unit].online) { /* Only respond if online */ - if (!wdi.hd[wdi.unit]._fault) { - val ^= 0x02; - } - if (!wdi.hd[wdi.unit]._crc_error) { /* Note: CRC_ERROR is not inverted */ - val ^= 0x80; - } - val ^= wdi.hd[wdi.unit].status.uav << 3; - } + if (wdi.hd[wdi.unit].online) { /* Only respond if online */ + if (!wdi.hd[wdi.unit]._fault) + val ^= 0x02; + if (!wdi.hd[wdi.unit]._crc_error) /* Note: CRC_ERROR is not inverted */ + val ^= 0x80; + val ^= wdi.hd[wdi.unit].status.uav << 3; + } - val = (wdi.pio1.data_B & ~wdi.pio1.dir_B) | val; + val = (wdi.pio1.data_B & ~wdi.pio1.dir_B) | val; LOGD(TAG, "E5 IN: = %02x", val); return val; } + BYTE cromemco_wdi_pio1a_cmd_in(void) { LOGW(TAG, "E6 IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_pio1b_cmd_in(void) { LOGW(TAG, "E7 IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_dma0_in(void) { - /* DMA READ STATUS NOT YET COMPLETE */ + /* DMA READ STATUS NOT YET COMPLETE */ LOGE(TAG, "E8 IN: [%d]", wdi.dma.rr_state); - if (wdi.dma.rr_state == RR_BASE) return wdi.dma.rr0.status; - else return (BYTE) 0xff; + if (wdi.dma.rr_state == RR_BASE) + return wdi.dma.rr0.status; + else + return (BYTE) 0xff; } + BYTE cromemco_wdi_dma1_in(void) { LOGW(TAG, "E9 IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_dma2_in(void) { LOGW(TAG, "EA IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_dma3_in(void) { LOGW(TAG, "EB IN:"); return (BYTE) 0xff; } + BYTE cromemco_wdi_ctc0_in(void) { - BYTE val = wdi.ctc.now0; - Tstates_t index_ticks = INDEX_INT / disk_param[wdi.hd[wdi.unit].type].rpm; + BYTE val = wdi.ctc.now0; + Tstates_t index_ticks = INDEX_INT / disk_param[wdi.hd[wdi.unit].type].rpm; LOGD(TAG, "IN: CTC #0 = %02x - Tdiff=%" PRIu64 "", val, T - wdi.ctc.T0); - if (wdi.hd[wdi.unit].online) { /* Only count indexes if online */ - - if (T < wdi.ctc.T0) wdi.ctc.T0 = T; /* clock rollover has occurred in T */ - else if ((T - wdi.ctc.T0) > index_ticks) { - if (val > 0) wdi.ctc.now0--; - wdi.hd[wdi.unit].sector = 0; - wdi.ctc.T0 += index_ticks; - } - } + if (wdi.hd[wdi.unit].online) { /* Only count indexes if online */ + if (T < wdi.ctc.T0) + wdi.ctc.T0 = T; /* clock rollover has occurred in T */ + else if ((T - wdi.ctc.T0) > index_ticks) { + if (val > 0) + wdi.ctc.now0--; + wdi.hd[wdi.unit].sector = 0; + wdi.ctc.T0 += index_ticks; + } + } return val; } + BYTE cromemco_wdi_ctc1_in(void) { - Tstates_t Tdiff = T - wdi.ctc.T1; - Tstates_t index_ticks = INDEX_INT / disk_param[wdi.hd[wdi.unit].type].rpm; - unsigned int sectors = (Tdiff * WDI_SECTORS + index_ticks / 10) / index_ticks; /* -10% on sector time */ - - LOGD(TAG, "IN: CTC #1 = %02x - Tdiff=%" PRIu64 " = %d sectors", wdi.ctc.now1, T - wdi.ctc.T1, sectors); - - if (sectors && wdi.hd[wdi.unit].online) { /* Only count sectors if online */ - if (wdi.ctc.now1 > 0) { - int r = (int)wdi.ctc.now1 - sectors; - if (r < 0) r = 0; - wdi.ctc.now1 = r; - } - wdi.hd[wdi.unit].sector += sectors; - wdi.hd[wdi.unit].sector %= WDI_SECTORS; - // LOGI(TAG, "IN: CTC #1 = %02x, sect: %02x", wdi.ctc.now1, wdi.hd[wdi.unit].sector); - - wdi.ctc.T1 = T; - } + Tstates_t Tdiff = T - wdi.ctc.T1; + Tstates_t index_ticks = INDEX_INT / disk_param[wdi.hd[wdi.unit].type].rpm; + /* -10% on sector time */ + unsigned int sectors = (Tdiff * WDI_SECTORS + index_ticks / 10) / index_ticks; + + LOGD(TAG, "IN: CTC #1 = %02x - Tdiff=%" PRIu64 " = %d sectors", + wdi.ctc.now1, T - wdi.ctc.T1, sectors); + + if (sectors && wdi.hd[wdi.unit].online) { /* Only count sectors if online */ + if (wdi.ctc.now1 > 0) { + int r = (int) wdi.ctc.now1 - sectors; + + if (r < 0) + r = 0; + wdi.ctc.now1 = r; + } + wdi.hd[wdi.unit].sector += sectors; + wdi.hd[wdi.unit].sector %= WDI_SECTORS; + // LOGI(TAG, "IN: CTC #1 = %02x, sect: %02x", wdi.ctc.now1, + // wdi.hd[wdi.unit].sector); + + wdi.ctc.T1 = T; + } return wdi.ctc.now1; } + BYTE cromemco_wdi_ctc2_in(void) { - BYTE val = wdi.ctc.now2; + BYTE val = wdi.ctc.now2; LOGD(TAG, "IN: CTC #2 = %d", val); -/** - * COULD SIMULATE HEAD SEEK TIME HERE - * IMI-7710 spec gives: - * single track access time 10 ms - * average access time 50 ms - * maximum access time 100 ms - * - * For now, seek is complete the first time this counter is checked - */ + /** + * COULD SIMULATE HEAD SEEK TIME HERE + * IMI-7710 spec gives: + * single track access time 10 ms + * average access time 50 ms + * maximum access time 100 ms + * + * For now, seek is complete the first time this counter is checked + */ - /* Only count seek complete if online */ - if (val > 0 && wdi.hd[wdi.unit].online) wdi.ctc.now2--; + /* Only count seek complete if online */ + if (val > 0 && wdi.hd[wdi.unit].online) + wdi.ctc.now2--; return val; } + BYTE cromemco_wdi_ctc3_in(void) { LOGW(TAG, "EF IN:"); @@ -649,563 +689,595 @@ BYTE cromemco_wdi_ctc3_in(void) static void command_bus_strobe(void) { - - int bus = wdi.pio1.bus_addr; - BYTE data = wdi.pio0.data_A; - BYTE _head; - WORD _cyl; - - /* Only rezero if online */ - if (wdi.hd[wdi.unit].status.rezeroing && wdi.hd[wdi.unit].online) { - LOGI(TAG, "REZEROING"); - wdi.hd[wdi.unit].status.hav = 0; - wdi.hd[wdi.unit].status.cav = 0; - wdi.hd[wdi.unit].status.rezeroing = 0; - wdi.hd[wdi.unit].status.on_cyl = 1; - wdi.hd[wdi.unit].status.unit_rdy = 1; - } - /* Only seek if online */ - if (wdi.hd[wdi.unit].status.seeking && wdi.hd[wdi.unit].online) { - LOGI(TAG, "SEEKING: UNIT: %02x, HEAD: %02x, CYL: %03x", wdi.hd[wdi.unit].command.uas, wdi.hd[wdi.unit].command.has, wdi.hd[wdi.unit].command.cas); - wdi.hd[wdi.unit].status.uav = wdi.hd[wdi.unit].command.uas; - wdi.hd[wdi.unit].status.hav = wdi.hd[wdi.unit].command.has; - wdi.hd[wdi.unit].status.cav = wdi.hd[wdi.unit].command.cas; - wdi.hd[wdi.unit].status.seeking = 0; - wdi.hd[wdi.unit].status.on_cyl = 1; - wdi.hd[wdi.unit].status.unit_rdy = 1; - } - - switch (bus) - { - case 0: - wdi.unit = (data >> 4) & 0x07; /* only 3 LSB of Unit */ - _head = ((data & 0x0c) >> 2) | ((data & 0x80) >> 5); /* reuse MSB of Unit for Head*/ - _cyl = (wdi.hd[wdi.unit].command.cas & 0xff) | ((data & 0x03) << 8); - - if ((wdi.unit >= WDI_UNITS)) { - LOGE(TAG, "DISK COMMAND 0 - ILLEGAL UNIT: %02x", wdi.unit); - wdi.hd[wdi.unit].online = 0; - wdi.hd[wdi.unit].command.uas = wdi.unit; - wdi.hd[wdi.unit].status.illegal_address = 1; - wdi.hd[wdi.unit].status.unit_rdy = 0; - wdi.hd[wdi.unit]._fault = 0; - } else if (!wdi.hd[wdi.unit].online) { - LOGW(TAG, "DISK COMMAND 0 - UNIT: %02x - OFFLINE", wdi.unit); - wdi.hd[wdi.unit].command.uas = wdi.unit; - wdi.hd[wdi.unit].status.illegal_address = 1; - wdi.hd[wdi.unit].status.unit_rdy = 0; - wdi.hd[wdi.unit]._fault = 0; - } else if (_head >= disk_param[wdi.hd[wdi.unit].type].heads) { - LOGE(TAG, "DISK COMMAND 0 - ILLEGAL HEAD: %02x", _head); - wdi.hd[wdi.unit].command.uas = wdi.unit; - wdi.hd[wdi.unit].status.uav = wdi.unit; - wdi.hd[wdi.unit].status.illegal_address = 1; - wdi.hd[wdi.unit].status.unit_rdy = 0; - wdi.hd[wdi.unit]._fault = 0; - /* - * Illegal cylinder should only be checked on COMMAND 1 - * when a full cylinder address is received (COMMAND 0 followed by COMMAND 1) - * otherwise there can be a false negative (illegal address) - */ - } else { - wdi.hd[wdi.unit].command.uas = wdi.unit; - wdi.hd[wdi.unit].command.has = _head; - wdi.hd[wdi.unit].command.cas = _cyl; - wdi.hd[wdi.unit].status.seeking = 1; - wdi.hd[wdi.unit].status.on_cyl = 0; - wdi.hd[wdi.unit].status.unit_rdy = 0; - wdi.hd[wdi.unit].status.illegal_address = 0; - - LOGI(TAG, "DISK COMMAND 0 - UNIT: %02x, HEAD: %02x, CYL: %03x", wdi.hd[wdi.unit].command.uas, wdi.hd[wdi.unit].command.has, wdi.hd[wdi.unit].command.cas); - } - break; - case 1: - _cyl = (wdi.hd[wdi.unit].command.cas & 0xf00) | data; - - if (_cyl >= disk_param[wdi.hd[wdi.unit].type].cyl) { - LOGE(TAG, "DISK COMMAND 1 - ILLEGAL CYLINDER: %03x", _cyl); - wdi.hd[wdi.unit].status.illegal_address = 1; - wdi.hd[wdi.unit].status.unit_rdy = 0; - wdi.hd[wdi.unit]._fault = 0; - } else { - wdi.hd[wdi.unit].command.cas = _cyl; - wdi.hd[wdi.unit].status.cav = wdi.hd[wdi.unit].command.cas; - wdi.hd[wdi.unit].status.seeking = 1; - wdi.hd[wdi.unit].status.on_cyl = 0; - wdi.hd[wdi.unit].status.unit_rdy = 0; - - LOGI(TAG, "DISK COMMAND 1 - CYL: %03x", wdi.hd[wdi.unit].status.cav); - } - break; - case 2: - if (data & 0xfc) { - LOGE(TAG, "DISK COMMAND 2 - %d NOT IMPLEMENTED - %02x", bus, data); - } - break; - case 3: - if (data & 1) { - LOGI(TAG, "DISK COMMAND 3 - FAULT CLEAR "); - wdi.hd[wdi.unit]._fault = 1; /* CLEAR FAULT */ - } - if (data & 2) { - LOGI(TAG, "DISK COMMAND 3 - REZERO"); - - wdi.hd[wdi.unit].status.rezeroing = 1; - wdi.hd[wdi.unit].status.on_cyl = 0; - wdi.hd[wdi.unit].status.unit_rdy = 0; - wdi.hd[wdi.unit]._fault = 1; /* CLEAR FAULT */ - } - break; - case 4: - wdi.pio0.data_B = wdi.hd[wdi.unit].status.unit_rdy; - wdi.pio0.data_B |= wdi.hd[wdi.unit].status.on_cyl << 1; - wdi.pio0.data_B |= wdi.hd[wdi.unit].status.seeking << 2; - wdi.pio0.data_B |= wdi.hd[wdi.unit].status.rezeroing << 3; - wdi.pio0.data_B |= wdi.hd[wdi.unit].status.illegal_address << 6; - break; - case 5: - wdi.pio0.data_B = !(wdi.hd[wdi.unit]._fault); /* Inverse of _fault */ - wdi.pio0.data_B |= wdi.hd[wdi.unit].type << 5; /* Drive type in unused bits 5 & 6 of Status #5 */ - wdi.pio0.data_B |= wdi.hd[wdi.unit].status.write_prot << 4; - break; - case 6: - wdi.pio0.data_B = wdi.hd[wdi.unit].status.cav & 0xff; - break; - case 7: - wdi.pio0.data_B = wdi.hd[wdi.unit].status.cav >> 8; - wdi.pio0.data_B |= wdi.hd[wdi.unit].status.uav << 4; - wdi.pio0.data_B |= (wdi.hd[wdi.unit].status.hav & 0x3) << 2; - wdi.pio0.data_B |= (wdi.hd[wdi.unit].status.hav & 0x4) << 5; /* reuse MSB of Unit for Head*/ - break; - default: - break; - } + int bus = wdi.pio1.bus_addr; + BYTE data = wdi.pio0.data_A; + BYTE _head; + WORD _cyl; + + /* Only rezero if online */ + if (wdi.hd[wdi.unit].status.rezeroing && wdi.hd[wdi.unit].online) { + LOGI(TAG, "REZEROING"); + wdi.hd[wdi.unit].status.hav = 0; + wdi.hd[wdi.unit].status.cav = 0; + wdi.hd[wdi.unit].status.rezeroing = 0; + wdi.hd[wdi.unit].status.on_cyl = 1; + wdi.hd[wdi.unit].status.unit_rdy = 1; + } + /* Only seek if online */ + if (wdi.hd[wdi.unit].status.seeking && wdi.hd[wdi.unit].online) { + LOGI(TAG, "SEEKING: UNIT: %02x, HEAD: %02x, CYL: %03x", + wdi.hd[wdi.unit].command.uas, wdi.hd[wdi.unit].command.has, + wdi.hd[wdi.unit].command.cas); + wdi.hd[wdi.unit].status.uav = wdi.hd[wdi.unit].command.uas; + wdi.hd[wdi.unit].status.hav = wdi.hd[wdi.unit].command.has; + wdi.hd[wdi.unit].status.cav = wdi.hd[wdi.unit].command.cas; + wdi.hd[wdi.unit].status.seeking = 0; + wdi.hd[wdi.unit].status.on_cyl = 1; + wdi.hd[wdi.unit].status.unit_rdy = 1; + } + + switch (bus) { + case 0: + /* only 3 LSB of Unit */ + wdi.unit = (data >> 4) & 0x07; + /* reuse MSB of Unit for Head */ + _head = ((data & 0x0c) >> 2) | ((data & 0x80) >> 5); + _cyl = (wdi.hd[wdi.unit].command.cas & 0xff) | ((data & 0x03) << 8); + + if ((wdi.unit >= WDI_UNITS)) { + LOGE(TAG, "DISK COMMAND 0 - ILLEGAL UNIT: %02x", wdi.unit); + wdi.hd[wdi.unit].online = 0; + wdi.hd[wdi.unit].command.uas = wdi.unit; + wdi.hd[wdi.unit].status.illegal_address = 1; + wdi.hd[wdi.unit].status.unit_rdy = 0; + wdi.hd[wdi.unit]._fault = 0; + } else if (!wdi.hd[wdi.unit].online) { + LOGW(TAG, "DISK COMMAND 0 - UNIT: %02x - OFFLINE", wdi.unit); + wdi.hd[wdi.unit].command.uas = wdi.unit; + wdi.hd[wdi.unit].status.illegal_address = 1; + wdi.hd[wdi.unit].status.unit_rdy = 0; + wdi.hd[wdi.unit]._fault = 0; + } else if (_head >= disk_param[wdi.hd[wdi.unit].type].heads) { + LOGE(TAG, "DISK COMMAND 0 - ILLEGAL HEAD: %02x", _head); + wdi.hd[wdi.unit].command.uas = wdi.unit; + wdi.hd[wdi.unit].status.uav = wdi.unit; + wdi.hd[wdi.unit].status.illegal_address = 1; + wdi.hd[wdi.unit].status.unit_rdy = 0; + wdi.hd[wdi.unit]._fault = 0; + /* + * Illegal cylinder should only be checked on COMMAND 1 when a full + * cylinder address is received (COMMAND 0 followed by COMMAND 1) + * otherwise there can be a false negative (illegal address) + */ + } else { + wdi.hd[wdi.unit].command.uas = wdi.unit; + wdi.hd[wdi.unit].command.has = _head; + wdi.hd[wdi.unit].command.cas = _cyl; + wdi.hd[wdi.unit].status.seeking = 1; + wdi.hd[wdi.unit].status.on_cyl = 0; + wdi.hd[wdi.unit].status.unit_rdy = 0; + wdi.hd[wdi.unit].status.illegal_address = 0; + + LOGI(TAG, "DISK COMMAND 0 - UNIT: %02x, HEAD: %02x, CYL: %03x", + wdi.hd[wdi.unit].command.uas, wdi.hd[wdi.unit].command.has, + wdi.hd[wdi.unit].command.cas); + } + break; + case 1: + _cyl = (wdi.hd[wdi.unit].command.cas & 0xf00) | data; + + if (_cyl >= disk_param[wdi.hd[wdi.unit].type].cyl) { + LOGE(TAG, "DISK COMMAND 1 - ILLEGAL CYLINDER: %03x", _cyl); + wdi.hd[wdi.unit].status.illegal_address = 1; + wdi.hd[wdi.unit].status.unit_rdy = 0; + wdi.hd[wdi.unit]._fault = 0; + } else { + wdi.hd[wdi.unit].command.cas = _cyl; + wdi.hd[wdi.unit].status.cav = wdi.hd[wdi.unit].command.cas; + wdi.hd[wdi.unit].status.seeking = 1; + wdi.hd[wdi.unit].status.on_cyl = 0; + wdi.hd[wdi.unit].status.unit_rdy = 0; + + LOGI(TAG, "DISK COMMAND 1 - CYL: %03x", wdi.hd[wdi.unit].status.cav); + } + break; + case 2: + if (data & 0xfc) { + LOGE(TAG, "DISK COMMAND 2 - %d NOT IMPLEMENTED - %02x", bus, data); + } + break; + case 3: + if (data & 1) { + LOGI(TAG, "DISK COMMAND 3 - FAULT CLEAR "); + wdi.hd[wdi.unit]._fault = 1; /* CLEAR FAULT */ + } + if (data & 2) { + LOGI(TAG, "DISK COMMAND 3 - REZERO"); + + wdi.hd[wdi.unit].status.rezeroing = 1; + wdi.hd[wdi.unit].status.on_cyl = 0; + wdi.hd[wdi.unit].status.unit_rdy = 0; + wdi.hd[wdi.unit]._fault = 1; /* CLEAR FAULT */ + } + break; + case 4: + wdi.pio0.data_B = wdi.hd[wdi.unit].status.unit_rdy; + wdi.pio0.data_B |= wdi.hd[wdi.unit].status.on_cyl << 1; + wdi.pio0.data_B |= wdi.hd[wdi.unit].status.seeking << 2; + wdi.pio0.data_B |= wdi.hd[wdi.unit].status.rezeroing << 3; + wdi.pio0.data_B |= wdi.hd[wdi.unit].status.illegal_address << 6; + break; + case 5: + /* Inverse of _fault */ + wdi.pio0.data_B = !(wdi.hd[wdi.unit]._fault); + /* Drive type in unused bits 5 & 6 of Status #5 */ + wdi.pio0.data_B |= wdi.hd[wdi.unit].type << 5; + wdi.pio0.data_B |= wdi.hd[wdi.unit].status.write_prot << 4; + break; + case 6: + wdi.pio0.data_B = wdi.hd[wdi.unit].status.cav & 0xff; + break; + case 7: + wdi.pio0.data_B = wdi.hd[wdi.unit].status.cav >> 8; + wdi.pio0.data_B |= wdi.hd[wdi.unit].status.uav << 4; + wdi.pio0.data_B |= (wdi.hd[wdi.unit].status.hav & 0x3) << 2; + /* reuse MSB of Unit for Head*/ + wdi.pio0.data_B |= (wdi.hd[wdi.unit].status.hav & 0x4) << 5; + break; + default: + break; + } } + void cromemco_wdi_pio0a_data_out(BYTE data) { - int bus = wdi.pio1.bus_addr; + int bus = wdi.pio1.bus_addr; LOGD(TAG, "E0 OUT: %02x - bus:%d", data, bus); - wdi.pio0.data_A = data; + wdi.pio0.data_A = data; - if (bus == 2) { - wdi.hd[wdi.unit].command.write_gate = data & 1; - wdi.hd[wdi.unit].command.read_gate = data & 2; - } + if (bus == 2) { + wdi.hd[wdi.unit].command.write_gate = data & 1; + wdi.hd[wdi.unit].command.read_gate = data & 2; + } } + void cromemco_wdi_pio0b_data_out(BYTE data) { LOGD(TAG, "E1 OUT: %02x", data); - wdi.pio0.data_B = data; + wdi.pio0.data_B = data; - if (data) LOGE(TAG, "Extended Address non-zero [%02x]", data); + if (data) + LOGE(TAG, "Extended Address non-zero [%02x]", data); } + void cromemco_wdi_pio0a_cmd_out(BYTE data) { LOGW(TAG, "E2 OUT: %02x", data); } + void cromemco_wdi_pio0b_cmd_out(BYTE data) { LOGW(TAG, "E3 OUT: %02x", data); } + void cromemco_wdi_pio1a_data_out(BYTE data) { LOGD(TAG, "E4 OUT: %02x", data); - wdi.pio1.data_A = data; - wdi.pio1.dsk_id = data & 0x10; - wdi.pio1.brd = wdi.pio1.dsk_id << 2; - wdi.pio1._cmd_stb = data & 0x08; - wdi.pio1._cmd_sel1 = data & 0x04; - wdi.pio1._cmd_sel0 = data & 0x02; - wdi.pio1.cmd__r_w = data & 0x01; - - wdi.pio1.bus_addr = (wdi.pio1.cmd__r_w << 2) | (wdi.pio1._cmd_sel1 >> 1) | (wdi.pio1._cmd_sel0 >> 1); + wdi.pio1.data_A = data; + wdi.pio1.dsk_id = data & 0x10; + wdi.pio1.brd = wdi.pio1.dsk_id << 2; + wdi.pio1._cmd_stb = data & 0x08; + wdi.pio1._cmd_sel1 = data & 0x04; + wdi.pio1._cmd_sel0 = data & 0x02; + wdi.pio1.cmd__r_w = data & 0x01; + + wdi.pio1.bus_addr = (wdi.pio1.cmd__r_w << 2) | (wdi.pio1._cmd_sel1 >> 1) | + (wdi.pio1._cmd_sel0 >> 1); LOGD(TAG, "OUT - PIO A : %02x - bus: %d", data, wdi.pio1.bus_addr); - if (wdi.pio1._cmd_stb) { - LOGD(TAG, "PIO A - STROBE: %02x - bus: %d", data, wdi.pio1.bus_addr); + if (wdi.pio1._cmd_stb) { + LOGD(TAG, "PIO A - STROBE: %02x - bus: %d", data, wdi.pio1.bus_addr); - command_bus_strobe(); - } + command_bus_strobe(); + } } + void cromemco_wdi_pio1b_data_out(BYTE data) { LOGD(TAG, "E5 OUT: %02x", data); - wdi.pio1.data_B = data; - wdi.pio1.dma_rdy = data & 0x04; - wdi.pio1._disk_op = data & 0x01; - - LOGD(TAG, "E5 OUT: %02x, DMA RDY: %d, DISK_OP: %d", data, wdi.pio1.dma_rdy, wdi.pio1._disk_op); - - if (wdi.pio1._disk_op) { - /* NOTHING YET IDENTIFIED TO HAPPEN HERE */ - } - - if (wdi.pio1.dma_rdy && wdi.hd[wdi.unit].command.write_gate) { - start_bus_request(BUS_DMA_CONTINUOUS, &wdi_dma_write); - }; - if (wdi.pio1.dma_rdy && wdi.hd[wdi.unit].command.read_gate) { - start_bus_request(BUS_DMA_CONTINUOUS, &wdi_dma_read); - } + wdi.pio1.data_B = data; + wdi.pio1.dma_rdy = data & 0x04; + wdi.pio1._disk_op = data & 0x01; + + LOGD(TAG, "E5 OUT: %02x, DMA RDY: %d, DISK_OP: %d", + data, wdi.pio1.dma_rdy, wdi.pio1._disk_op); + + if (wdi.pio1._disk_op) { + /* NOTHING YET IDENTIFIED TO HAPPEN HERE */ + } + + if (wdi.pio1.dma_rdy && wdi.hd[wdi.unit].command.write_gate) + start_bus_request(BUS_DMA_CONTINUOUS, &wdi_dma_write); + if (wdi.pio1.dma_rdy && wdi.hd[wdi.unit].command.read_gate) + start_bus_request(BUS_DMA_CONTINUOUS, &wdi_dma_read); } + void cromemco_wdi_pio1a_cmd_out(BYTE data) { LOGD(TAG, "E6 OUT: %02x", data); - wdi.pio1.cmd_A = data; - - switch (wdi.pio1.cmd_A_state) - { - case 0: - if (data & 0x0f) { - if ((wdi.pio1.mode_A = data >> 6) == 3) { - wdi.pio1.cmd_A_state = 1; - } else { - // LOGW(TAG, "Unexpected PIO A mode [%02x]", wdi.pio1.mode_A); - } - } else { - // LOGW(TAG, "Unexpected PIO A command [%02x]", data); - } - break; - case 1: - wdi.pio1.cmd_A_state = 0; - wdi.pio1.dir_A = data; - LOGD(TAG, "PIO1_A DIR=[%02x]", data); - - break; - default: - LOGE(TAG, "Unknown PIO A cmd state [%d]", wdi.pio1.cmd_A_state); - break; - } + wdi.pio1.cmd_A = data; + + switch (wdi.pio1.cmd_A_state) { + case 0: + if (data & 0x0f) { + if ((wdi.pio1.mode_A = data >> 6) == 3) + wdi.pio1.cmd_A_state = 1; + else { + // LOGW(TAG, "Unexpected PIO A mode [%02x]", wdi.pio1.mode_A); + } + } else { + // LOGW(TAG, "Unexpected PIO A command [%02x]", data); + } + break; + case 1: + wdi.pio1.cmd_A_state = 0; + wdi.pio1.dir_A = data; + LOGD(TAG, "PIO1_A DIR=[%02x]", data); + + break; + default: + LOGE(TAG, "Unknown PIO A cmd state [%d]", wdi.pio1.cmd_A_state); + break; + } } + void cromemco_wdi_pio1b_cmd_out(BYTE data) { LOGD(TAG, "E7 OUT: %02x", data); - wdi.pio1.cmd_B = data; - - switch (wdi.pio1.cmd_B_state) - { - case 0: - if (data & 0x0f) { - if ((wdi.pio1.mode_B = data >> 6) == 3) { - wdi.pio1.cmd_B_state = 1; - } else { - // LOGW(TAG, "Unexpected PIO B mode [%02x]", wdi.pio1.mode_B); - } - } else { - // LOGW(TAG, "Unexpected PIO B command [%02x]", data); - } - break; - case 1: - wdi.pio1.cmd_B_state = 0; - wdi.pio1.dir_B = data; - LOGD(TAG, "PIO1_B DIR=[%02x]", data); - break; - default: - LOGE(TAG, "Unknown PIO B cmd state [%d]", wdi.pio1.cmd_B_state); - break; - } + wdi.pio1.cmd_B = data; + + switch (wdi.pio1.cmd_B_state) { + case 0: + if (data & 0x0f) { + if ((wdi.pio1.mode_B = data >> 6) == 3) + wdi.pio1.cmd_B_state = 1; + else { + // LOGW(TAG, "Unexpected PIO B mode [%02x]", wdi.pio1.mode_B); + } + } else { + // LOGW(TAG, "Unexpected PIO B command [%02x]", data); + } + break; + case 1: + wdi.pio1.cmd_B_state = 0; + wdi.pio1.dir_B = data; + LOGD(TAG, "PIO1_B DIR=[%02x]", data); + break; + default: + LOGE(TAG, "Unknown PIO B cmd state [%d]", wdi.pio1.cmd_B_state); + break; + } } + static Tstates_t wdi_dma_mem_to_mem(BYTE bus_ack) { - register int v; - int i; + register int v; + int i; - if (!bus_ack) return 0; + if (!bus_ack) + return 0; - for (i = 0; i <= wdi.dma.wr0.len; i++) { - v = dma_read(wdi.dma.wr0.a_addr_counter++); - dma_write(wdi.dma.wr4.b_addr_counter++, v); - } - return wdi.dma.wr0.len * 6; /* 6 t-states (3 read + 3 write) for each byte */ + for (i = 0; i <= wdi.dma.wr0.len; i++) { + v = dma_read(wdi.dma.wr0.a_addr_counter++); + dma_write(wdi.dma.wr4.b_addr_counter++, v); + } + return wdi.dma.wr0.len * 6; /* 6 t-states (3 read + 3 write) for each byte */ } + void cromemco_wdi_dma0_out(BYTE data) { - const char *cmd; + const char *cmd; - cmd = ""; + cmd = ""; LOGD(TAG, "E8 OUT: %02x", data); - switch (wdi.dma.wr_state) - { - case WR_BASE: - - if (data & 0x80) { /* WR4 - WR6 */ - - if ((data & 0x03) == 1) { /* WR4 */ - wdi.dma.wr4.base = data; - if (wdi.dma.wr4.base & 0x1C) { - wdi.dma.wr_state = WR4; - } - } else if ((data & 0x03) == 2) { /* WR5 */ - wdi.dma.wr5.base = data; - LOGD(TAG, "WR5 = %02x", data); - } else if ((data & 0x03) == 3) { /* WR6 */ - wdi.dma.wr6.base = data; - - switch (data) - { - case 0x83: - cmd = "DISABLE DMA"; - wdi.dma.enable_dma = 0; - break; - case 0x87: - cmd = "ENABLE DMA"; - wdi.dma.enable_dma = 1; - - if (wdi.dma.force_ready - && wdi.dma.wr0.dest - && (wdi.dma.wr0.mode == 3) /* TRANSFER/SEARCH */ - && (wdi.dma.wr1.a_device == MREQ)) { - - LOGD(TAG, "DMA: MEMORY-TO-MEMORY from: %04x to: %04x length: %04x", - wdi.dma.wr0.a_addr_counter, - wdi.dma.wr4.b_addr_counter, - wdi.dma.wr0.len - ); - - start_bus_request(BUS_DMA_CONTINUOUS, &wdi_dma_mem_to_mem); - - } else if (!wdi.dma.force_ready - && !wdi.dma.wr0.dest - && (wdi.dma.wr0.mode == 2) /* SEARCH */ - && (wdi.dma.wr1.a_device == MREQ)) { - - LOGD(TAG, "DMA: R/W-TO/FROM-DISK addr: %04x length: %04x", - wdi.dma.wr4.b_addr_counter, - wdi.dma.wr0.len - ); - LOGD(TAG, "UNIT: %d, HEAD: %d, CYL: %d", wdi.hd[wdi.unit].status.uav, wdi.hd[wdi.unit].status.hav, wdi.hd[wdi.unit].status.cav); - - } else { - LOGE(TAG, "DMA FUNCTION NOT IMPLEMENTED"); - LOGE(TAG, "FORCE_READY = %02x", wdi.dma.force_ready); - LOGE(TAG, "DEVICE = %02x", wdi.dma.wr1.a_device); - LOGE(TAG, "MODE = %02x", wdi.dma.wr0.mode); - LOGE(TAG, "DEST = %02x", wdi.dma.wr0.dest); - } - break; - case 0xB3: - cmd = "FORCE READY"; - wdi.dma.force_ready = 1; - break; - case 0xC3: - cmd = "RESET"; - wdi.dma.enable_dma = 0; - wdi.dma.force_ready = 0; - wdi.dma.wr1.a_timing = 0; - wdi.dma.wr2.b_timing = 0; - break; - case 0xcf: - cmd = "LOAD"; - wdi.dma.wr0.a_addr_counter = wdi.dma.wr0.a_start; - wdi.dma.wr4.b_addr_counter = wdi.dma.wr4.b_start; - wdi.dma.wr0.byte_counter = 0; - wdi.dma.force_ready = 0; - break; - default: - cmd = "NOT IMPLEMENTED"; - break; - } - LOGD(TAG, "DMA WR6 = %02x - %s", data, cmd); - } else { - LOGE(TAG, "DMA WR [%02x] NOT IMPLEMENTED", data); - } - } else { /* WR0 - WR3 */ - - if (data & 0x03) { /* WR0 */ - wdi.dma.wr0.base = data; - wdi.dma.wr0.dest = data & 0x04; - wdi.dma.wr0.mode = data & 0x03; - - LOGD(TAG, "DMA WR0: source %c, mode %d", wdi.dma.wr0.dest?'A':'B', wdi.dma.wr0.mode); - - if (wdi.dma.wr0.base & 0x78) { - wdi.dma.wr_state = WR0; - } - } else { /* WR1 - WR3 */ - - if ((data & 0x07) == 4) { /* WR1 */ - wdi.dma.wr1.base = data; - wdi.dma.wr1.a_device = (dma_dev_t) ((data & 0x08) >> 3); - wdi.dma.wr1.a_fixed = (data & 0x30) >> 4; - if (wdi.dma.wr1.base & 0x40) { - wdi.dma.wr_state = WR1; - } - LOGD(TAG, "DMA WR1: Port A: inc. mode %d, dev %c", wdi.dma.wr1.a_device, wdi.dma.wr1.a_device?'I':'M'); - } else if ((data & 0x07) == 0) { /* WR2 */ - wdi.dma.wr2.base = data; - wdi.dma.wr2.b_device = (dma_dev_t) ((data & 0x08) >> 3); - wdi.dma.wr2.b_fixed = (data & 0x30) >> 4; - if (wdi.dma.wr2.base & 0x40) { - wdi.dma.wr_state = WR2; - } - LOGD(TAG, "DMA WR2: Port B: inc. mode %d, dev %c", wdi.dma.wr1.a_device, wdi.dma.wr1.a_device?'I':'M'); - } else { - - LOGE(TAG, "WR [%02x] NOT IMPLEMENTED", data); - } - } - } - break; - case WR0: - if (wdi.dma.wr0.base & 0x08) { - wdi.dma.wr0.a_start = (wdi.dma.wr0.a_start & 0xff00) | data; - wdi.dma.wr0.base &= ~0x08; - } else if (wdi.dma.wr0.base & 0x10) { - wdi.dma.wr0.a_start = (wdi.dma.wr0.a_start & 0xff) | (data << 8); - wdi.dma.wr0.base &= ~0x10; - } else if (wdi.dma.wr0.base & 0x20) { - wdi.dma.wr0.len = (wdi.dma.wr0.len & 0xff00) | data; - wdi.dma.wr0.base &= ~0x20; - } else if (wdi.dma.wr0.base & 0x40) { - wdi.dma.wr0.len = (wdi.dma.wr0.len & 0xff) | (data << 8); - wdi.dma.wr0.base &= ~0x40; - } - - if (!(wdi.dma.wr0.base & 0x78)) { - wdi.dma.wr_state = WR_BASE; - LOGD(TAG, "DMA WR0 [%02x] A start: %04x len: %02x", wdi.dma.wr0.base, wdi.dma.wr0.a_start, wdi.dma.wr0.len); - } - break; - case WR1: - wdi.dma.wr1.a_timing = data; - wdi.dma.wr_state = WR_BASE; - LOGD(TAG, "DMA WR1 [%02x] A timing: %02x", wdi.dma.wr1.base, wdi.dma.wr1.a_timing); - break; - case WR2: - wdi.dma.wr2.b_timing = data; - wdi.dma.wr_state = WR_BASE; - LOGD(TAG, "DMA WR2 [%02x] B timing: %02x", wdi.dma.wr2.base, wdi.dma.wr2.b_timing); - break; - case WR4: - if (wdi.dma.wr4.base & 0x04) { - wdi.dma.wr4.b_start = (wdi.dma.wr4.b_start & 0xff00) | data; - wdi.dma.wr4.base &= ~0x04; - } else if (wdi.dma.wr4.base & 0x08) { - wdi.dma.wr4.b_start = (wdi.dma.wr4.b_start & 0xff) | (data << 8); - wdi.dma.wr4.base &= ~0x08; - } else if (wdi.dma.wr4.base & 0x10) { - wdi.dma.wr4.intr_control = data; - wdi.dma.wr4.base &= ~0x10; - } - - if (!(wdi.dma.wr4.base & 0x1C)) { - wdi.dma.wr_state = WR_BASE; - LOGD(TAG, "DMA WR4 [%02x] B start: %04x int: %02x", wdi.dma.wr4.base, wdi.dma.wr4.b_start, wdi.dma.wr4.intr_control); - } - break; - default: - LOGE(TAG, "DMA WR STATE [%d] NOT IMPLEMENTED", wdi.dma.wr_state); - break; - } + switch (wdi.dma.wr_state) { + case WR_BASE: + if (data & 0x80) { /* WR4 - WR6 */ + if ((data & 0x03) == 1) { /* WR4 */ + wdi.dma.wr4.base = data; + if (wdi.dma.wr4.base & 0x1C) + wdi.dma.wr_state = WR4; + } else if ((data & 0x03) == 2) { /* WR5 */ + wdi.dma.wr5.base = data; + LOGD(TAG, "WR5 = %02x", data); + } else if ((data & 0x03) == 3) { /* WR6 */ + wdi.dma.wr6.base = data; + + switch (data) { + case 0x83: + cmd = "DISABLE DMA"; + wdi.dma.enable_dma = 0; + break; + case 0x87: + cmd = "ENABLE DMA"; + wdi.dma.enable_dma = 1; + + if (wdi.dma.force_ready + && wdi.dma.wr0.dest + && (wdi.dma.wr0.mode == 3) /* TRANSFER/SEARCH */ + && (wdi.dma.wr1.a_device == MREQ)) { + LOGD(TAG, "DMA: MEMORY-TO-MEMORY from: " + "%04x to: %04x length: %04x", + wdi.dma.wr0.a_addr_counter, + wdi.dma.wr4.b_addr_counter, + wdi.dma.wr0.len); + + start_bus_request(BUS_DMA_CONTINUOUS, + &wdi_dma_mem_to_mem); + } else if (!wdi.dma.force_ready + && !wdi.dma.wr0.dest + && (wdi.dma.wr0.mode == 2) /* SEARCH */ + && (wdi.dma.wr1.a_device == MREQ)) { + LOGD(TAG, "DMA: R/W-TO/FROM-DISK addr: " + "%04x length: %04x", + wdi.dma.wr4.b_addr_counter, + wdi.dma.wr0.len); + LOGD(TAG, "UNIT: %d, HEAD: %d, CYL: %d", + wdi.hd[wdi.unit].status.uav, + wdi.hd[wdi.unit].status.hav, + wdi.hd[wdi.unit].status.cav); + } else { + LOGE(TAG, "DMA FUNCTION NOT IMPLEMENTED"); + LOGE(TAG, "FORCE_READY = %02x", + wdi.dma.force_ready); + LOGE(TAG, "DEVICE = %02x", wdi.dma.wr1.a_device); + LOGE(TAG, "MODE = %02x", wdi.dma.wr0.mode); + LOGE(TAG, "DEST = %02x", wdi.dma.wr0.dest); + } + break; + case 0xB3: + cmd = "FORCE READY"; + wdi.dma.force_ready = 1; + break; + case 0xC3: + cmd = "RESET"; + wdi.dma.enable_dma = 0; + wdi.dma.force_ready = 0; + wdi.dma.wr1.a_timing = 0; + wdi.dma.wr2.b_timing = 0; + break; + case 0xCF: + cmd = "LOAD"; + wdi.dma.wr0.a_addr_counter = wdi.dma.wr0.a_start; + wdi.dma.wr4.b_addr_counter = wdi.dma.wr4.b_start; + wdi.dma.wr0.byte_counter = 0; + wdi.dma.force_ready = 0; + break; + default: + cmd = "NOT IMPLEMENTED"; + break; + } + LOGD(TAG, "DMA WR6 = %02x - %s", data, cmd); + } else { + LOGE(TAG, "DMA WR [%02x] NOT IMPLEMENTED", data); + } + } else { /* WR0 - WR3 */ + if (data & 0x03) { /* WR0 */ + wdi.dma.wr0.base = data; + wdi.dma.wr0.dest = data & 0x04; + wdi.dma.wr0.mode = data & 0x03; + + LOGD(TAG, "DMA WR0: source %c, mode %d", + wdi.dma.wr0.dest ? 'A' : 'B', wdi.dma.wr0.mode); + + if (wdi.dma.wr0.base & 0x78) + wdi.dma.wr_state = WR0; + } else { /* WR1 - WR3 */ + if ((data & 0x07) == 4) { /* WR1 */ + wdi.dma.wr1.base = data; + wdi.dma.wr1.a_device = (dma_dev_t) ((data & 0x08) >> 3); + wdi.dma.wr1.a_fixed = (data & 0x30) >> 4; + if (wdi.dma.wr1.base & 0x40) + wdi.dma.wr_state = WR1; + LOGD(TAG, "DMA WR1: Port A: inc. mode %d, dev %c", + wdi.dma.wr1.a_device, + wdi.dma.wr1.a_device ? 'I' : 'M'); + } else if ((data & 0x07) == 0) { /* WR2 */ + wdi.dma.wr2.base = data; + wdi.dma.wr2.b_device = (dma_dev_t) ((data & 0x08) >> 3); + wdi.dma.wr2.b_fixed = (data & 0x30) >> 4; + if (wdi.dma.wr2.base & 0x40) + wdi.dma.wr_state = WR2; + LOGD(TAG, "DMA WR2: Port B: inc. mode %d, dev %c", + wdi.dma.wr1.a_device, + wdi.dma.wr1.a_device ? 'I' : 'M'); + } else { + LOGE(TAG, "WR [%02x] NOT IMPLEMENTED", data); + } + } + } + break; + case WR0: + if (wdi.dma.wr0.base & 0x08) { + wdi.dma.wr0.a_start = (wdi.dma.wr0.a_start & 0xff00) | data; + wdi.dma.wr0.base &= ~0x08; + } else if (wdi.dma.wr0.base & 0x10) { + wdi.dma.wr0.a_start = (wdi.dma.wr0.a_start & 0xff) | (data << 8); + wdi.dma.wr0.base &= ~0x10; + } else if (wdi.dma.wr0.base & 0x20) { + wdi.dma.wr0.len = (wdi.dma.wr0.len & 0xff00) | data; + wdi.dma.wr0.base &= ~0x20; + } else if (wdi.dma.wr0.base & 0x40) { + wdi.dma.wr0.len = (wdi.dma.wr0.len & 0xff) | (data << 8); + wdi.dma.wr0.base &= ~0x40; + } + + if (!(wdi.dma.wr0.base & 0x78)) { + wdi.dma.wr_state = WR_BASE; + LOGD(TAG, "DMA WR0 [%02x] A start: %04x len: %02x", + wdi.dma.wr0.base, wdi.dma.wr0.a_start, wdi.dma.wr0.len); + } + break; + case WR1: + wdi.dma.wr1.a_timing = data; + wdi.dma.wr_state = WR_BASE; + LOGD(TAG, "DMA WR1 [%02x] A timing: %02x", wdi.dma.wr1.base, wdi.dma.wr1.a_timing); + break; + case WR2: + wdi.dma.wr2.b_timing = data; + wdi.dma.wr_state = WR_BASE; + LOGD(TAG, "DMA WR2 [%02x] B timing: %02x", wdi.dma.wr2.base, wdi.dma.wr2.b_timing); + break; + case WR4: + if (wdi.dma.wr4.base & 0x04) { + wdi.dma.wr4.b_start = (wdi.dma.wr4.b_start & 0xff00) | data; + wdi.dma.wr4.base &= ~0x04; + } else if (wdi.dma.wr4.base & 0x08) { + wdi.dma.wr4.b_start = (wdi.dma.wr4.b_start & 0xff) | (data << 8); + wdi.dma.wr4.base &= ~0x08; + } else if (wdi.dma.wr4.base & 0x10) { + wdi.dma.wr4.intr_control = data; + wdi.dma.wr4.base &= ~0x10; + } + + if (!(wdi.dma.wr4.base & 0x1C)) { + wdi.dma.wr_state = WR_BASE; + LOGD(TAG, "DMA WR4 [%02x] B start: %04x int: %02x", + wdi.dma.wr4.base, wdi.dma.wr4.b_start, wdi.dma.wr4.intr_control); + } + break; + default: + LOGE(TAG, "DMA WR STATE [%d] NOT IMPLEMENTED", wdi.dma.wr_state); + break; + } } void cromemco_wdi_dma1_out(BYTE data) { LOGW(TAG, "E9 OUT: %02x", data); } + void cromemco_wdi_dma2_out(BYTE data) { LOGW(TAG, "EA OUT: %02x", data); } + void cromemco_wdi_dma3_out(BYTE data) { LOGW(TAG, "EB OUT: %02x", data); } + void cromemco_wdi_ctc0_out(BYTE data) { LOGD(TAG, "OUT: CTC #0 - %02x", data); - switch (wdi.ctc.state0) - { - case 0: - wdi.ctc.mode0 = data; - - if (data & 0x80 ) LOGE(TAG, "CTC #0 - INT set"); - if (!(data & 0x40)) LOGE(TAG, "CTC #0 - TIMER set"); - if (data & 0x04 ) wdi.ctc.state0 = 1; - if (data & 0x02 ) wdi.ctc.now0 = 0; - if (!(data & 0x01)) LOGE(TAG, "CTC #0 - not CONTROL"); - break; - case 1: - if (wdi.ctc.mode0 & 0x40) LOGD(TAG, "CTC #0 - COUNTER set to %02x", data); - wdi.ctc.state0 = 0; - wdi.ctc.time0 = data; - wdi.ctc.now0 = data; - wdi.ctc.T0 = T; - break; - default: - LOGE(TAG, "CTC #0 - unknown state %d", wdi.ctc.state0); - break; - } + switch (wdi.ctc.state0) { + case 0: + wdi.ctc.mode0 = data; + + if (data & 0x80) + LOGE(TAG, "CTC #0 - INT set"); + if (!(data & 0x40)) + LOGE(TAG, "CTC #0 - TIMER set"); + if (data & 0x04) + wdi.ctc.state0 = 1; + if (data & 0x02) + wdi.ctc.now0 = 0; + if (!(data & 0x01)) + LOGE(TAG, "CTC #0 - not CONTROL"); + break; + case 1: + if (wdi.ctc.mode0 & 0x40) + LOGD(TAG, "CTC #0 - COUNTER set to %02x", data); + wdi.ctc.state0 = 0; + wdi.ctc.time0 = data; + wdi.ctc.now0 = data; + wdi.ctc.T0 = T; + break; + default: + LOGE(TAG, "CTC #0 - unknown state %d", wdi.ctc.state0); + break; + } } + void cromemco_wdi_ctc1_out(BYTE data) { - LOGD(TAG, "OUT: CTC #1 - %02x", data); - - switch (wdi.ctc.state1) - { - case 0: - wdi.ctc.mode1 = data; - - if (data & 0x80 ) LOGE(TAG, "CTC #1 - INT set"); - - if (!(data & 0x40)) { - LOGD(TAG, "CTC #1 - TIMER set"); - } else { - LOGD(TAG, "CTC #1 - COUNTER set"); - } - - if (data & 0x04 ) wdi.ctc.state1 = 1; - if (data & 0x02 ) wdi.ctc.now1 = 0; - if (!(data & 0x01)) LOGE(TAG, "CTC #1 - not CONTROL"); - break; - case 1: - wdi.ctc.state1 = 0; - wdi.ctc.time1 = data; - wdi.ctc.now1 = data; - wdi.ctc.T1 = T; - - if (wdi.ctc.mode1 & 0x40) { - LOGD(TAG, "CTC #1 - COUNTER set to %02x", data); - LOGI(TAG, "COUNT %d SECTOR PULSES", data - 1); - } else { - LOGD(TAG, "CTC #1 - TIMER set to %02x", data); - } - - break; - default: - LOGE(TAG, "CTC #1 - unknown state %d", wdi.ctc.state0); - break; - } + LOGD(TAG, "OUT: CTC #1 - %02x", data); + + switch (wdi.ctc.state1) { + case 0: + wdi.ctc.mode1 = data; + + if (data & 0x80) + LOGE(TAG, "CTC #1 - INT set"); + + if (!(data & 0x40)) { + LOGD(TAG, "CTC #1 - TIMER set"); + } else { + LOGD(TAG, "CTC #1 - COUNTER set"); + } + + if (data & 0x04) + wdi.ctc.state1 = 1; + if (data & 0x02) + wdi.ctc.now1 = 0; + if (!(data & 0x01)) + LOGE(TAG, "CTC #1 - not CONTROL"); + break; + case 1: + wdi.ctc.state1 = 0; + wdi.ctc.time1 = data; + wdi.ctc.now1 = data; + wdi.ctc.T1 = T; + + if (wdi.ctc.mode1 & 0x40) { + LOGD(TAG, "CTC #1 - COUNTER set to %02x", data); + LOGI(TAG, "COUNT %d SECTOR PULSES", data - 1); + } else { + LOGD(TAG, "CTC #1 - TIMER set to %02x", data); + } + + break; + default: + LOGE(TAG, "CTC #1 - unknown state %d", wdi.ctc.state0); + break; + } } + void cromemco_wdi_ctc2_out(BYTE data) { LOGD(TAG, "OUT: CTC #2 - %02x", data); - switch (wdi.ctc.state2) - { - case 0: - wdi.ctc.mode2 = data; - - if (data & 0x80 ) LOGE(TAG, "CTC #2 - INT set"); - if (!(data & 0x40)) LOGE(TAG, "CTC #2 - TIMER set"); - if (data & 0x04 ) wdi.ctc.state2 = 1; - if (data & 0x02 ) wdi.ctc.now2 = 0; - if (!(data & 0x01)) LOGE(TAG, "CTC #2 - not CONTROL"); - break; - case 1: - wdi.ctc.state2 = 0; - wdi.ctc.time2 = data; - wdi.ctc.now2 = data; - wdi.ctc.T2 = T; - break; - default: - LOGE(TAG, "CTC #2 - unknown state %d", wdi.ctc.state2); - break; - } + switch (wdi.ctc.state2) { + case 0: + wdi.ctc.mode2 = data; + + if (data & 0x80) + LOGE(TAG, "CTC #2 - INT set"); + if (!(data & 0x40)) + LOGE(TAG, "CTC #2 - TIMER set"); + if (data & 0x04) + wdi.ctc.state2 = 1; + if (data & 0x02) + wdi.ctc.now2 = 0; + if (!(data & 0x01)) + LOGE(TAG, "CTC #2 - not CONTROL"); + break; + case 1: + wdi.ctc.state2 = 0; + wdi.ctc.time2 = data; + wdi.ctc.now2 = data; + wdi.ctc.T2 = T; + break; + default: + LOGE(TAG, "CTC #2 - unknown state %d", wdi.ctc.state2); + break; + } } + void cromemco_wdi_ctc3_out(BYTE data) { LOGW(TAG, "EF OUT: %02x", data); diff --git a/iodevices/diskmanager.c b/iodevices/diskmanager.c index 85c3afb4..7b0b7596 100644 --- a/iodevices/diskmanager.c +++ b/iodevices/diskmanager.c @@ -10,34 +10,34 @@ /** * This diskmanager module provides an alternate interface for the array * - * char *disks[]; + * char *disks[]; * * that is typically implemented in a disk controller simulators e.g. - * - imsai-fif.c - * - tarbell_fdc.c + * - imsai-fif.c + * - tarbell_fdc.c * * It persists the array in a file, typically "disk.map" [DISKMAP] in the * provided path. * * The "disk.map" file is a simple text file with a line for each disk * starting at 'A' up to [LAST_DISK], typically 'D'. - * - If a line is empty of starts with '#' the disk is "ejected" - * - If a disk image is "inserted" the line contains only the file name + * - If a line is empty of starts with '#' the disk is "ejected" + * - If a disk image is "inserted" the line contains only the file name * * The diskmanager provides functions to: - * - populate the array from the file - * - write the array to the file - * - insert a disk - * - stat() disk image files to validate them before inserting - * - reject inserting the same disk image in 2 disk drives - * - eject a disk - * - and some other support functions. + * - populate the array from the file + * - write the array to the file + * - insert a disk + * - stat() disk image files to validate them before inserting + * - reject inserting the same disk image in 2 disk drives + * - eject a disk + * - and some other support functions. * * TODO: - * - fully support paths to allow a disk library hierarchy - * - support more complex disk arrays that contain structures e.g. - * * cpmsim::iosim.c - * * cromemco-fdc.c + * - fully support paths to allow a disk library hierarchy + * - support more complex disk arrays that contain structures e.g. + * * cpmsim::iosim.c + * * cromemco-fdc.c */ #include @@ -60,371 +60,376 @@ #include "log.h" static const char *TAG = "diskmanager"; -static char path[MAX_LFN+1]; /* path/filename for disk image */ +static char path[MAX_LFN + 1]; /* path/filename for disk image */ static char *file_start; + #define APPENDTOPATH(file) strncpy(file_start, file, MAX_LFN - strlen(path)); -enum disk_err { - SUCCESS, - INVALID_DISK_NUM, - DRIVE_EMPTY, - DRIVE_NOT_EMPTY, - IMAGE_ALREADY_INSERTED, - IMAGE_NOT_VALID, - FAILURE -}; - -typedef enum disk_err disk_err_t; - -static disk_err_t insertDisk(int disk, const char *image) { - - char *name; - struct stat image_status; - int i; - - if (disk >= 0 && disk < _MAX_DISK) { - - if (DISKNAME(disk) != NULL) { - return DRIVE_NOT_EMPTY; - } - - if (image != NULL && strlen(image) < MAX_LFN) { - - for (i = 0; i < _MAX_DISK; i++) { - if (DISKNAME(i) != NULL && strcmp(image, DISKNAME(i)) == 0) { - return IMAGE_ALREADY_INSERTED; - } - } - - APPENDTOPATH(image); - - if (stat(path, &image_status) == 0) { - if (S_ISREG(image_status.st_mode)) { - name = strndup(image, MAX_LFN); - if (name == NULL) { - LOGW(TAG, "Failed to insert disk, not enough memory."); - return FAILURE; - } else { - /* Everything is OK, we can insert the disk */ - DISKNAME(disk) = name; - return SUCCESS; - } - } else { - return IMAGE_NOT_VALID; - } - } else { - LOGW(TAG, "Failed to stat disk image: %s, error: %d", image, errno); - return IMAGE_NOT_VALID; - } - } - - return IMAGE_NOT_VALID; - } - - return INVALID_DISK_NUM; +typedef enum disk_err { + SUCCESS, + INVALID_DISK_NUM, + DRIVE_EMPTY, + DRIVE_NOT_EMPTY, + IMAGE_ALREADY_INSERTED, + IMAGE_NOT_VALID, + FAILURE +} disk_err_t; + +static disk_err_t insertDisk(int disk, const char *image) +{ + char *name; + struct stat image_status; + int i; + + if (disk >= 0 && disk < _MAX_DISK) { + if (DISKNAME(disk) != NULL) + return DRIVE_NOT_EMPTY; + + if (image != NULL && strlen(image) < MAX_LFN) { + for (i = 0; i < _MAX_DISK; i++) { + if (DISKNAME(i) != NULL && strcmp(image, DISKNAME(i)) == 0) + return IMAGE_ALREADY_INSERTED; + } + + APPENDTOPATH(image); + + if (stat(path, &image_status) == 0) { + if (S_ISREG(image_status.st_mode)) { + name = strndup(image, MAX_LFN); + if (name == NULL) { + LOGW(TAG, "Failed to insert disk, " + "not enough memory."); + return FAILURE; + } else { + /* Everything is OK, we can insert the disk */ + DISKNAME(disk) = name; + return SUCCESS; + } + } else + return IMAGE_NOT_VALID; + } else { + LOGW(TAG, "Failed to stat disk image: %s, error: %d", + image, errno); + return IMAGE_NOT_VALID; + } + } + + return IMAGE_NOT_VALID; + } + + return INVALID_DISK_NUM; } -static void writeDiskmap(void) { - FILE *map; - int i; +static void writeDiskmap(void) +{ + FILE *map; + int i; - if (*path == '\0') { - LOGW(TAG, "Path to disk map not set. Call readDiskmap(path) first."); - return; - } + if (*path == '\0') { + LOGW(TAG, "Path to disk map not set. Call readDiskmap(path) first."); + return; + } - APPENDTOPATH(DISKMAP); + APPENDTOPATH(DISKMAP); - map = fopen(path, "w"); - if (map == NULL) { - LOGW(TAG, "Can't create disk map: %s", path); - return; - } + map = fopen(path, "w"); + if (map == NULL) { + LOGW(TAG, "Can't create disk map: %s", path); + return; + } - for (i = 0; i < _MAX_DISK; i++) { - fprintf(map, "%s\n", DISKNAME(i)==NULL?"#":DISKNAME(i)); - } - fclose(map); + for (i = 0; i < _MAX_DISK; i++) + fprintf(map, "%s\n", DISKNAME(i) == NULL ? "#" : DISKNAME(i)); + fclose(map); } -void readDiskmap(char *path_name) { - FILE *map; - char *line = NULL; - char *name; - size_t len; - ssize_t res; - int i; - disk_err_t insert; +void readDiskmap(char *path_name) +{ + FILE *map; + char *line = NULL; + char *name; + size_t len; + ssize_t res; + int i; + disk_err_t insert; - for (i = 0; i < _MAX_DISK; i++) { - DISKNAME(i) = NULL; - } + for (i = 0; i < _MAX_DISK; i++) + DISKNAME(i) = NULL; - strncpy(path, path_name, MAX_LFN); - strncat(path, "/", MAX_LFN - strlen(path)); - file_start = path + strlen(path); + strncpy(path, path_name, MAX_LFN); + strncat(path, "/", MAX_LFN - strlen(path)); + file_start = path + strlen(path); - APPENDTOPATH(DISKMAP); - LOGD(TAG, "LIB: path: %s, diskmap: %s", path, file_start); + APPENDTOPATH(DISKMAP); + LOGD(TAG, "LIB: path: %s, diskmap: %s", path, file_start); - i = 0; + i = 0; again: - map = fopen(path, "r"); - if (map == NULL) { - if (i++ == 0) { - LOGW(TAG, "No disk map: %s, attempting to create file.", path); - writeDiskmap(); - goto again; - } - return; - } - - LOG(TAG, "DISK MAP: [%s]\r\n", path); - - for (i = 0; i < _MAX_DISK; i++) { - line = NULL; - res = getline(&line, &len, map); - - if (res != -1) { - if (line[res-1] == '\n') - line[res-1] = '\0'; - - /* empty lines or lines that begin with # are empty disks */ - name = ((line[0]=='\0') || (line[0]=='#'))?NULL:line; - if (name != NULL) { - insert = insertDisk(i, name); - - switch (insert) { - case SUCCESS : - LOG(TAG, "%c:DSK:='%s'\r\n", i+'A', DISKNAME(i)); - break; - case IMAGE_ALREADY_INSERTED : - LOGW(TAG, "%c:DSK: Image file '%s' already in use", i+'A', name); - break; - case IMAGE_NOT_VALID : - LOGW(TAG, "%c:DSK: Image file '%s' is invalid", i+'A', name); - break; - default: - LOGW(TAG, "%c:DSK: Failed to insert disk, error: %d", i+'A', insert); - break; - } - } - } - free(line); - } - fclose(map); + map = fopen(path, "r"); + if (map == NULL) { + if (i++ == 0) { + LOGW(TAG, "No disk map: %s, attempting to create file.", path); + writeDiskmap(); + goto again; + } + return; + } + + LOG(TAG, "DISK MAP: [%s]\r\n", path); + + for (i = 0; i < _MAX_DISK; i++) { + line = NULL; + res = getline(&line, &len, map); + + if (res != -1) { + if (line[res - 1] == '\n') + line[res - 1] = '\0'; + + /* empty lines or lines that begin with # are empty disks */ + name = ((line[0] == '\0') || (line[0] == '#')) ? NULL : line; + if (name != NULL) { + insert = insertDisk(i, name); + + switch (insert) { + case SUCCESS : + LOG(TAG, "%c:DSK:='%s'\r\n", i + 'A', DISKNAME(i)); + break; + case IMAGE_ALREADY_INSERTED : + LOGW(TAG, "%c:DSK: Image file '%s' already in use", + i + 'A', name); + break; + case IMAGE_NOT_VALID : + LOGW(TAG, "%c:DSK: Image file '%s' is invalid", + i + 'A', name); + break; + default: + LOGW(TAG, "%c:DSK: Failed to insert disk, error: %d", + i + 'A', insert); + break; + } + } + } + free(line); + } + fclose(map); } #ifdef HAS_NETSERVER -static int findDiskImage(const char *image) { - int i; - - for (i = 0; i < _MAX_DISK; i++) { - if (DISKNAME(i) != NULL) { - if (strcmp(image, DISKNAME(i)) == 0) { - return 1; - } - } - } - return 0; -} +static bool findDiskImage(const char *image) +{ + int i; -static int getDiskNumByID(const char *id) { - int disk = -1; - - /* id is in the form X:DSK: making it 6 characters long */ - LOGD(TAG, "GET ID: %s, %ld", id, strlen(id)); - if (id != NULL && strlen(id) == 6 && strcmp(id+1, ":DSK:") == 0) { - disk = *id - 'A'; - if (disk < 0 || disk > (_MAX_DISK - 1)) { - LOGW(TAG, "BAD DISK ID: %c", *id); - disk = -1; - } - } else { - LOGW(TAG, "DISK ID required, got: %s", id); - disk = -1; - } - return disk; + for (i = 0; i < _MAX_DISK; i++) { + if (DISKNAME(i) != NULL) { + if (strcmp(image, DISKNAME(i)) == 0) + return true; + } + } + return false; } -static disk_err_t ejectDisk(int disk) { - - char *name; +static int getDiskNumByID(const char *id) +{ + int disk = -1; + + /* id is in the form X:DSK: making it 6 characters long */ + LOGD(TAG, "GET ID: %s, %ld", id, strlen(id)); + if (id != NULL && strlen(id) == 6 && strcmp(id + 1, ":DSK:") == 0) { + disk = *id - 'A'; + if (disk < 0 || disk > (_MAX_DISK - 1)) { + LOGW(TAG, "BAD DISK ID: %c", *id); + disk = -1; + } + } else { + LOGW(TAG, "DISK ID required, got: %s", id); + disk = -1; + } + return disk; +} - if (disk >= 0 || disk < _MAX_DISK) { +static disk_err_t ejectDisk(int disk) +{ + char *name; - if (DISKNAME(disk) == NULL) { - return DRIVE_EMPTY; - } + if (disk >= 0 || disk < _MAX_DISK) { + if (DISKNAME(disk) == NULL) + return DRIVE_EMPTY; - name = DISKNAME(disk); - DISKNAME(disk) = NULL; - free(name); + name = DISKNAME(disk); + DISKNAME(disk) = NULL; + free(name); - return SUCCESS; - } + return SUCCESS; + } - return INVALID_DISK_NUM; + return INVALID_DISK_NUM; } /** * Web Server handlers for LIB: and X:DSK: * */ -int LibraryHandler(HttpdConnection_t *conn, void *unused) { - request_t *req = get_request(conn); +int LibraryHandler(HttpdConnection_t *conn, void *unused) +{ + request_t *req = get_request(conn); int i = 0; - UNUSED(unused); - - if (*path == '\0') { - LOGW(TAG, "Path to disk map not set. Call readDiskmap(path) first."); - return 0; - } - - *file_start = '\0'; - - switch (req->method) { - case HTTP_GET: - DirectoryHandler(conn, path); - break; - case HTTP_PUT: - UploadHandler(conn, path); - LOGI(TAG, "PUT image: image uploaded."); - break; - case HTTP_DELETE: - if (req->len > 0) { - i = mg_read(conn, file_start, MAX_LFN - strlen(path)); - *(file_start + i) = '\0'; - - LOGD(TAG, "DELETE image: %s, length: %lld", file_start, req->len); - - if (findDiskImage(file_start)) { - LOGW(TAG, "DELETE image: %s, currently inserted in disks", file_start); - httpdStartResponse(conn, 404); /* http error code 'Not Found' */ - httpdEndHeaders(conn); - return 1; - } - - if (unlink(path) < 0) { - LOGW(TAG, "DELETE image: %s, unlink failed [%d]", path, errno); - httpdStartResponse(conn, 410); /* http error code 'Gone' */ - httpdEndHeaders(conn); - } else { - LOGI(TAG, "DELETE image: %s, deleted.", path); - httpdStartResponse(conn, 200); - httpdEndHeaders(conn); - httpdPrintf(conn, "Deleted"); - }; - } - break; - default: - httpdStartResponse(conn, 405); /* http error code 'Method Not Allowed' */ - httpdEndHeaders(conn); - break; - } + UNUSED(unused); + + if (*path == '\0') { + LOGW(TAG, "Path to disk map not set. Call readDiskmap(path) first."); + return 0; + } + + *file_start = '\0'; + + switch (req->method) { + case HTTP_GET: + DirectoryHandler(conn, path); + break; + case HTTP_PUT: + UploadHandler(conn, path); + LOGI(TAG, "PUT image: image uploaded."); + break; + case HTTP_DELETE: + if (req->len > 0) { + i = mg_read(conn, file_start, MAX_LFN - strlen(path)); + *(file_start + i) = '\0'; + + LOGD(TAG, "DELETE image: %s, length: %lld", file_start, req->len); + + if (findDiskImage(file_start)) { + LOGW(TAG, "DELETE image: %s, currently inserted in disks", + file_start); + httpdStartResponse(conn, 404); /* http error code 'Not Found' */ + httpdEndHeaders(conn); + return 1; + } + + if (unlink(path) < 0) { + LOGW(TAG, "DELETE image: %s, unlink failed [%d]", path, errno); + httpdStartResponse(conn, 410); /* http error code 'Gone' */ + httpdEndHeaders(conn); + } else { + LOGI(TAG, "DELETE image: %s, deleted.", path); + httpdStartResponse(conn, 200); + httpdEndHeaders(conn); + httpdPrintf(conn, "Deleted"); + }; + } + break; + default: + httpdStartResponse(conn, 405); /* http error code 'Method Not Allowed' */ + httpdEndHeaders(conn); + break; + } return 1; } -static void sendDisks(HttpdConnection_t *conn) { - - int i; +static void sendDisks(HttpdConnection_t *conn) +{ + int i; - httpdStartResponse(conn, 200); - httpdHeader(conn, "Content-Type", "application/json"); - httpdEndHeaders(conn); + httpdStartResponse(conn, 200); + httpdHeader(conn, "Content-Type", "application/json"); + httpdEndHeaders(conn); - httpdPrintf(conn, "{"); + httpdPrintf(conn, "{"); - for (i = 0; i < _MAX_DISK; i++) { - httpdPrintf(conn, "\"%c\": \"%s\"", i+'A', DISKNAME(i)==NULL?"":DISKNAME(i)); - if (i < (_MAX_DISK - 1)) httpdPrintf(conn, ","); - } + for (i = 0; i < _MAX_DISK; i++) { + httpdPrintf(conn, "\"%c\": \"%s\"", i + 'A', + DISKNAME(i) == NULL ? "" : DISKNAME(i)); + if (i < (_MAX_DISK - 1)) + httpdPrintf(conn, ","); + } - sendHardDisks(conn); + sendHardDisks(conn); - httpdPrintf(conn, "}"); + httpdPrintf(conn, "}"); } -int DiskHandler(HttpdConnection_t *conn, void *unused) { - request_t *req = get_request(conn); - int disk, i; - char image[MAX_LFN]; - disk_err_t result; - UNUSED(unused); - - switch (req->method) { - case HTTP_GET: - LOGD(TAG, "GET /disks"); - sendDisks(conn); - break; - case HTTP_PUT: - LOGD(TAG, "PUT /disks: %s", req->args[0]); - - disk = getDiskNumByID(req->args[0]); - image[0] = '\0'; - - if (req->len > 0) { - i = mg_read(conn, image, MAX_LFN); - image[i] = '\0'; - }; - - LOGD(TAG, "PUT image length: %d [%s]", (int) req->len, image); - - result = insertDisk(disk, image); - - switch (result) { - case SUCCESS : - writeDiskmap(); - sendDisks(conn); - break; - case DRIVE_NOT_EMPTY : - LOGW(TAG, "PUT /disks NOT EMPTY"); - httpdStartResponse(conn, 404); /* http error code 'Not Found' */ - httpdEndHeaders(conn); - break; - case IMAGE_ALREADY_INSERTED : - LOGW(TAG, "PUT image: %s, already inserted in disks", image); - httpdStartResponse(conn, 404); /* http error code 'Not Found' */ - httpdEndHeaders(conn); - break; - default: - LOGW(TAG, "PUT image: %s, failed to insert disk: %d, error: %d", image, disk, result); - httpdStartResponse(conn, 404); /* http error code 'Not Found' */ - httpdEndHeaders(conn); - break; - } - break; - case HTTP_DELETE: - LOGD(TAG, "DELETE /disks: %s", req->args[0]); - - disk = getDiskNumByID(req->args[0]); - result = ejectDisk(disk); - - switch (result) { - case SUCCESS : - sendDisks(conn); - writeDiskmap(); - break; - case DRIVE_EMPTY : - LOGW(TAG, "DELETE /disks ALREADY EMPTY"); - httpdStartResponse(conn, 404); /* http error code 'Not Found' */ - httpdEndHeaders(conn); - break; - default: - LOGW(TAG, "DELETE /disks failed to eject disk: %d, error: %d", disk, result); - httpdStartResponse(conn, 404); /* http error code 'Not Found' */ - httpdEndHeaders(conn); - break; - } - break; - default: - httpdStartResponse(conn, 405); /* http error code 'Method Not Allowed' */ - httpdEndHeaders(conn); - break; +int DiskHandler(HttpdConnection_t *conn, void *unused) +{ + request_t *req = get_request(conn); + int disk, i; + char image[MAX_LFN]; + disk_err_t result; + UNUSED(unused); + + switch (req->method) { + case HTTP_GET: + LOGD(TAG, "GET /disks"); + sendDisks(conn); + break; + case HTTP_PUT: + LOGD(TAG, "PUT /disks: %s", req->args[0]); + + disk = getDiskNumByID(req->args[0]); + image[0] = '\0'; + + if (req->len > 0) { + i = mg_read(conn, image, MAX_LFN); + image[i] = '\0'; + }; + + LOGD(TAG, "PUT image length: %d [%s]", (int) req->len, image); + + result = insertDisk(disk, image); + + switch (result) { + case SUCCESS: + writeDiskmap(); + sendDisks(conn); + break; + case DRIVE_NOT_EMPTY: + LOGW(TAG, "PUT /disks NOT EMPTY"); + httpdStartResponse(conn, 404); /* http error code 'Not Found' */ + httpdEndHeaders(conn); + break; + case IMAGE_ALREADY_INSERTED: + LOGW(TAG, "PUT image: %s, already inserted in disks", image); + httpdStartResponse(conn, 404); /* http error code 'Not Found' */ + httpdEndHeaders(conn); + break; + default: + LOGW(TAG, "PUT image: %s, failed to insert disk: %d, error: %d", + image, disk, result); + httpdStartResponse(conn, 404); /* http error code 'Not Found' */ + httpdEndHeaders(conn); + break; + } + break; + case HTTP_DELETE: + LOGD(TAG, "DELETE /disks: %s", req->args[0]); + + disk = getDiskNumByID(req->args[0]); + result = ejectDisk(disk); + + switch (result) { + case SUCCESS: + sendDisks(conn); + writeDiskmap(); + break; + case DRIVE_EMPTY: + LOGW(TAG, "DELETE /disks ALREADY EMPTY"); + httpdStartResponse(conn, 404); /* http error code 'Not Found' */ + httpdEndHeaders(conn); + break; + default: + LOGW(TAG, "DELETE /disks failed to eject disk: %d, error: %d", + disk, result); + httpdStartResponse(conn, 404); /* http error code 'Not Found' */ + httpdEndHeaders(conn); + break; + } + break; + default: + httpdStartResponse(conn, 405); /* http error code 'Method Not Allowed' */ + httpdEndHeaders(conn); + break; } - return 1; + return 1; } -#endif +#endif /* HAS_NETSERVER */ diff --git a/iodevices/generic-at-modem.c b/iodevices/generic-at-modem.c index 931e3401..6c90d106 100644 --- a/iodevices/generic-at-modem.c +++ b/iodevices/generic-at-modem.c @@ -38,65 +38,66 @@ #define LOG_LOCAL_LEVEL LOG_WARN #include "log.h" -static const char* TAG = "at-modem"; - -#define MODEM_ID "'AT' Modem" - -#define BASE_DECIMAL 10 - -#define AT_BUF_LEN 81 -#define DEFAULT_LISTENER_PORT 8023 -#define _QUOTE(arg) #arg -#define STR_VALUE(arg) _QUOTE(arg) - -#define SREG_AA 0 -#define SREG_RINGS 1 -#define SREG_ESCAPE 2 -#define SREG_CR 3 -#define SREG_LF 4 -#define SREG_BS 5 -#define SREG_HUP_DELAY 10 -#define SREG_OPT 13 -#define SREG_PORT 14 -#define SREG_TELNET 15 -#define SREG_TN_SGA 16 -#define SREG_TN_ECHO 17 -#define SREG_TN_BIN 18 -#define SREG_TN_NAWS 19 -#define SREG_COLS 20 -#define SREG_ROWS 21 -#define SREG_TN_TTYPE 22 -#define SREG_FLOW_CTRL 39 -#define MAX_REG_NUM 50 +static const char *TAG = "at-modem"; + +#define MODEM_ID "'AT' Modem" + +#define BASE_DECIMAL 10 + +#define AT_BUF_LEN 81 +#define DEFAULT_LISTENER_PORT 8023 + +#define _QUOTE(arg) #arg +#define STR_VALUE(arg) _QUOTE(arg) + +#define SREG_AA 0 +#define SREG_RINGS 1 +#define SREG_ESCAPE 2 +#define SREG_CR 3 +#define SREG_LF 4 +#define SREG_BS 5 +#define SREG_HUP_DELAY 10 +#define SREG_OPT 13 +#define SREG_PORT 14 +#define SREG_TELNET 15 +#define SREG_TN_SGA 16 +#define SREG_TN_ECHO 17 +#define SREG_TN_BIN 18 +#define SREG_TN_NAWS 19 +#define SREG_COLS 20 +#define SREG_ROWS 21 +#define SREG_TN_TTYPE 22 +#define SREG_FLOW_CTRL 39 +#define MAX_REG_NUM 50 #define SREG_DEFAULTS { \ - /* SREG_AA */ 0, \ - /* SREG_RINGS */ 0, \ - /* SREG_ESCAPE */ 43, \ - /* SREG_CR */ 13, \ - /* SREG_LF */ 10, \ - /* SREG_BS */ 8, \ - 0, 0, 0, 0, \ - /* SREG_HUP_DELAY */ 14, \ - 0, 0, \ - /* SREG_OPT */ 1, \ - /* SREG_PORT */ DEFAULT_LISTENER_PORT, \ - /* SREG_TELNET */ 0, \ - /* SREG_TN_SGA */ 3, \ - /* SREG_TN_ECHO */ 3, \ - /* SREG_TN_BIN */ 0, \ - /* SREG_TN_NAWS */ 3, \ - /* SREG_COLS */ 80, \ - /* SREG_ROWS */ 24, \ - /* SREG_TN_TTYPE */ 3, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, \ -}; - -#define OPT_ECHO 0x1 -#define OPT_QUIET 0x2 + /* SREG_AA */ 0, \ + /* SREG_RINGS */ 0, \ + /* SREG_ESCAPE */ 43, \ + /* SREG_CR */ 13, \ + /* SREG_LF */ 10, \ + /* SREG_BS */ 8, \ + 0, 0, 0, 0, \ + /* SREG_HUP_DELAY */ 14, \ + 0, 0, \ + /* SREG_OPT */ 1, \ + /* SREG_PORT */ DEFAULT_LISTENER_PORT, \ + /* SREG_TELNET */ 0, \ + /* SREG_TN_SGA */ 3, \ + /* SREG_TN_ECHO */ 3, \ + /* SREG_TN_BIN */ 0, \ + /* SREG_TN_NAWS */ 3, \ + /* SREG_COLS */ 80, \ + /* SREG_ROWS */ 24, \ + /* SREG_TN_TTYPE */ 3, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, \ + }; + +#define OPT_ECHO 0x1 +#define OPT_QUIET 0x2 static bool daemon_f = false; @@ -115,382 +116,381 @@ static char port_num[11]; static telnet_telopt_t telnet_opts[10]; -static int carrier_detect; - -static void init_telnet_opts(void) { - - int i=0; - - telnet_opts[i].telopt = TELNET_TELOPT_SGA; - telnet_opts[i].us = (s_reg[SREG_TN_SGA] & 1)? TELNET_WILL : TELNET_WONT; - telnet_opts[i].him = (s_reg[SREG_TN_SGA] & 2)? TELNET_DO : TELNET_DONT; - i++; - telnet_opts[i].telopt = TELNET_TELOPT_ECHO; - telnet_opts[i].us = (s_reg[SREG_TN_ECHO] & 1)? TELNET_WILL : TELNET_WONT; - telnet_opts[i].him = (s_reg[SREG_TN_ECHO] & 2)? TELNET_DO : TELNET_DONT; - i++; - telnet_opts[i].telopt = TELNET_TELOPT_BINARY; - telnet_opts[i].us = (s_reg[SREG_TN_BIN] & 1)? TELNET_WILL : TELNET_WONT; - telnet_opts[i].him = (s_reg[SREG_TN_BIN] & 2)? TELNET_DO : TELNET_DONT; - i++; - telnet_opts[i].telopt = TELNET_TELOPT_NAWS; - telnet_opts[i].us = (s_reg[SREG_TN_NAWS] & 1)? TELNET_WILL : TELNET_WONT; - telnet_opts[i].him = (s_reg[SREG_TN_NAWS] & 2)? TELNET_DO : TELNET_DONT; - i++; - telnet_opts[i].telopt = TELNET_TELOPT_TTYPE; - telnet_opts[i].us = (s_reg[SREG_TN_TTYPE] & 1)? TELNET_WILL : TELNET_WONT; - telnet_opts[i].him = (s_reg[SREG_TN_TTYPE] & 2)? TELNET_DO : TELNET_DONT; - i++; - telnet_opts[i].telopt = -1; - telnet_opts[i].us = 0; - telnet_opts[i].him = 0; +static bool carrier_detect; + +static void init_telnet_opts(void) +{ + int i = 0; + + telnet_opts[i].telopt = TELNET_TELOPT_SGA; + telnet_opts[i].us = (s_reg[SREG_TN_SGA] & 1) ? TELNET_WILL : TELNET_WONT; + telnet_opts[i].him = (s_reg[SREG_TN_SGA] & 2) ? TELNET_DO : TELNET_DONT; + i++; + telnet_opts[i].telopt = TELNET_TELOPT_ECHO; + telnet_opts[i].us = (s_reg[SREG_TN_ECHO] & 1) ? TELNET_WILL : TELNET_WONT; + telnet_opts[i].him = (s_reg[SREG_TN_ECHO] & 2) ? TELNET_DO : TELNET_DONT; + i++; + telnet_opts[i].telopt = TELNET_TELOPT_BINARY; + telnet_opts[i].us = (s_reg[SREG_TN_BIN] & 1) ? TELNET_WILL : TELNET_WONT; + telnet_opts[i].him = (s_reg[SREG_TN_BIN] & 2) ? TELNET_DO : TELNET_DONT; + i++; + telnet_opts[i].telopt = TELNET_TELOPT_NAWS; + telnet_opts[i].us = (s_reg[SREG_TN_NAWS] & 1) ? TELNET_WILL : TELNET_WONT; + telnet_opts[i].him = (s_reg[SREG_TN_NAWS] & 2) ? TELNET_DO : TELNET_DONT; + i++; + telnet_opts[i].telopt = TELNET_TELOPT_TTYPE; + telnet_opts[i].us = (s_reg[SREG_TN_TTYPE] & 1) ? TELNET_WILL : TELNET_WONT; + telnet_opts[i].him = (s_reg[SREG_TN_TTYPE] & 2) ? TELNET_DO : TELNET_DONT; + i++; + telnet_opts[i].telopt = -1; + telnet_opts[i].us = 0; + telnet_opts[i].him = 0; } -#define TELNET_TTYPE "ansi" +#define TELNET_TTYPE "ansi" static telnet_t *telnet = NULL; static unsigned char tn_recv; static int tn_len = 0; -static void telnet_hdlr(telnet_t *telnet, telnet_event_t *ev, void *user_data) { +static void telnet_hdlr(telnet_t *telnet, telnet_event_t *ev, void *user_data) +{ + char buf[81]; + char *p; + int i; - char buf[81]; - char * p; - int i; + UNUSED(user_data); - UNUSED(user_data); - - switch (ev->type) { - case TELNET_EV_DATA: + switch (ev->type) { + case TELNET_EV_DATA: if (ev->data.size) { - if (ev->data.size != 1) { - LOGW(TAG, "LONGER THAN EXPECTED [%zd]", ev->data.size); - } else { - tn_recv = *(ev->data.buffer); - tn_len = ev->data.size; - } - LOGD(TAG, "Telnet IN: %c[%zd]", tn_recv, ev->data.size); + if (ev->data.size != 1) { + LOGW(TAG, "LONGER THAN EXPECTED [%zd]", ev->data.size); + } else { + tn_recv = *(ev->data.buffer); + tn_len = ev->data.size; + } + LOGD(TAG, "Telnet IN: %c[%zd]", tn_recv, ev->data.size); } break; - case TELNET_EV_SEND: + case TELNET_EV_SEND: if (ev->data.size) { - p = buf; - for(i=0;i<(int)ev->data.size;i++) { - p += sprintf (p, "%d ", *(ev->data.buffer+i)); - } - LOGD(TAG, "Telnet OUT: %s[%zd]", buf, ev->data.size); + p = buf; + for (i = 0; i < (int) ev->data.size; i++) + p += sprintf(p, "%d ", *(ev->data.buffer + i)); + LOGD(TAG, "Telnet OUT: %s[%zd]", buf, ev->data.size); } if (write(*active_sfd, ev->data.buffer, ev->data.size) != (ssize_t) ev->data.size) LOGE(TAG, "Telnet OUT: can't send data"); break; - case TELNET_EV_WILL: - if (ev->neg.telopt == TELNET_TELOPT_SGA) { - LOGI(TAG, "Telnet WILL SGA"); - } else if (ev->neg.telopt == TELNET_TELOPT_ECHO) { - LOGI(TAG, "Telnet WILL ECHO"); - } else if (ev->neg.telopt == TELNET_TELOPT_BINARY) { - LOGI(TAG, "Telnet WILL BINARY"); - } else { - LOGW(TAG, "Telnet WILL unknown opt: %d", ev->neg.telopt); - } + case TELNET_EV_WILL: + if (ev->neg.telopt == TELNET_TELOPT_SGA) { + LOGI(TAG, "Telnet WILL SGA"); + } else if (ev->neg.telopt == TELNET_TELOPT_ECHO) { + LOGI(TAG, "Telnet WILL ECHO"); + } else if (ev->neg.telopt == TELNET_TELOPT_BINARY) { + LOGI(TAG, "Telnet WILL BINARY"); + } else { + LOGW(TAG, "Telnet WILL unknown opt: %d", ev->neg.telopt); + } + break; + case TELNET_EV_DO: + if (ev->neg.telopt == TELNET_TELOPT_SGA) { + LOGI(TAG, "Telnet DO SGA"); + } else if (ev->neg.telopt == TELNET_TELOPT_ECHO) { + LOGI(TAG, "Telnet DO ECHO"); + } else if (ev->neg.telopt == TELNET_TELOPT_BINARY) { + LOGI(TAG, "Telnet DO BINARY"); + } else if (ev->neg.telopt == TELNET_TELOPT_TTYPE) { + LOGI(TAG, "Telnet DO TTYPE"); + } else if (ev->neg.telopt == TELNET_TELOPT_NAWS) { + telnet_begin_sb(telnet, TELNET_TELOPT_NAWS); + buf[0] = 0; + buf[1] = s_reg[SREG_COLS]; + buf[2] = 0; + buf[3] = s_reg[SREG_ROWS]; + telnet_send(telnet, buf, 4); + telnet_finish_sb(telnet); + LOGI(TAG, "Telnet DO NAWS [%d x %d]", + (buf[0] << 8) + buf[1], (buf[2] << 8) + buf[3]); + } else { + LOGW(TAG, "Telnet DO unknown opt: %d", ev->neg.telopt); + } break; - case TELNET_EV_DO: - if (ev->neg.telopt == TELNET_TELOPT_SGA) { - LOGI(TAG, "Telnet DO SGA"); - } else if (ev->neg.telopt == TELNET_TELOPT_ECHO) { - LOGI(TAG, "Telnet DO ECHO"); - } else if (ev->neg.telopt == TELNET_TELOPT_BINARY) { - LOGI(TAG, "Telnet DO BINARY"); - } else if (ev->neg.telopt == TELNET_TELOPT_TTYPE) { - LOGI(TAG, "Telnet DO TTYPE"); - } else if (ev->neg.telopt == TELNET_TELOPT_NAWS) { - telnet_begin_sb(telnet, TELNET_TELOPT_NAWS); - buf[0] = 0; - buf[1] = s_reg[SREG_COLS]; - buf[2] = 0; - buf[3] = s_reg[SREG_ROWS]; - telnet_send(telnet, buf, 4); - telnet_finish_sb(telnet); - LOGI(TAG, "Telnet DO NAWS [%d x %d]", (buf[0]<<8) + buf[1], (buf[2]<<8) + buf[3]); - } else { - LOGW(TAG, "Telnet DO unknown opt: %d", ev->neg.telopt); - } - break; - case TELNET_EV_SUBNEGOTIATION: + case TELNET_EV_SUBNEGOTIATION: LOGI(TAG, "SUBNEGOTIATION [%d]", ev->sub.telopt); - break; - case TELNET_EV_TTYPE: + break; + case TELNET_EV_TTYPE: LOGI(TAG, "TTYPE negotiation cmd:%d", ev->ttype.cmd); - const char *ttype; - if (((ttype = getenv("TERM")) == NULL) || (s_reg[SREG_TN_TTYPE] & 4)) { - ttype = TELNET_TTYPE; - } - if (ev->ttype.cmd == TELNET_TTYPE_SEND) { - LOGI(TAG, "TTYPE SEND : %s", ttype); - telnet_ttype_is(telnet, ttype); - } else if (ev->ttype.cmd == TELNET_TTYPE_IS) { - LOGI(TAG, "TTYPE IS : %s", ev->ttype.name); - } - break; - case TELNET_EV_ERROR: + const char *ttype; + if (((ttype = getenv("TERM")) == NULL) || (s_reg[SREG_TN_TTYPE] & 4)) + ttype = TELNET_TTYPE; + if (ev->ttype.cmd == TELNET_TTYPE_SEND) { + LOGI(TAG, "TTYPE SEND : %s", ttype); + telnet_ttype_is(telnet, ttype); + } else if (ev->ttype.cmd == TELNET_TTYPE_IS) { + LOGI(TAG, "TTYPE IS : %s", ev->ttype.name); + } + break; + case TELNET_EV_ERROR: LOGE(TAG, "ERROR: %s", ev->error.msg); - break; - default: - LOGW(TAG, "Telnet Event unknown [%d] opt: %d", ev->type, ev->neg.telopt); - break; - } + break; + default: + LOGW(TAG, "Telnet Event unknown [%d] opt: %d", ev->type, ev->neg.telopt); + break; + } } -/****************************************************************************************************************************/ -static void close_socket(void) { - - if (telnet != NULL) { - telnet_free(telnet); - telnet = NULL; - LOGI(TAG, "Telnet session ended"); - } - - if (shutdown(*active_sfd, SHUT_RDWR) == 0) { - LOGI(TAG, "Socket shutdown"); - } - if (close(*active_sfd) == 0) { - LOGI(TAG, "Socket closed"); - *active_sfd = 0; - } - carrier_detect = 0; -} +/*************************************************************************************************/ + +static void close_socket(void) +{ + if (telnet != NULL) { + telnet_free(telnet); + telnet = NULL; + LOGI(TAG, "Telnet session ended"); + } -static int open_socket(void) { - - struct addrinfo hints; - struct addrinfo *result, *rp; - int s; - void *addrptr = NULL; - uint16_t port = 0; - struct sockaddr_in *sktv4 = NULL; - /* struct sockaddr_in6 *sktv6 = NULL; */ - int on = 1; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; /* Allow only IPv4 not IPv6 */ - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = 0; - hints.ai_protocol = 0; /* Any protocol */ - - s = getaddrinfo(addr, port_num, &hints, &result); - if (s != 0) { - LOGI(TAG, "getaddrinfo: %s", "failed"); - return 1; - } - - for (rp = result; rp != NULL; rp = rp->ai_next) { - - LOGD(TAG, "Address: %d", rp->ai_family); - switch (rp->ai_family) { - case AF_INET: - sktv4 = (struct sockaddr_in *)rp->ai_addr; - port = sktv4->sin_port; - addrptr = &sktv4->sin_addr; - break; - case AF_INET6: - /* - sktv6 = (struct sockaddr_in6 *)rp->ai_addr; - port = sktv6->sin6_port; - addrptr = &sktv6->sin6_addr; - */ - LOGE(TAG, "Not expecting IPV6 addresses"); - return 1; - default: - LOGE(TAG, "Not expecting address family type %d", rp->ai_family); - return 1; - } - - inet_ntop(rp->ai_family, addrptr, addr, 100); - LOGI(TAG, "Address: %s:%d", addr, ntohs(port)); - - if ((sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) { - LOGE(TAG, "Failed to create socket"); - return 1; - }; - - active_sfd = &sfd; - carrier_detect = 1; - LOGI(TAG, "Socket created"); - - if (connect(sfd, rp->ai_addr, sizeof(struct sockaddr_in)) < 0) { - LOGW(TAG, "Failed to connect to socket: %d", errno); - close_socket(); - return 1; - } - LOGI(TAG, "Socket connected"); - - if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)) == -1) { - LOGE(TAG, "can't set sockopt TCP_NODELAY"); - close_socket(); - return 1; - } - - /* Initialize Telnet session */ - if (s_reg[SREG_TELNET]) { - init_telnet_opts(); - if ((telnet = telnet_init(telnet_opts, telnet_hdlr, 0, NULL)) == 0) { - LOGE(TAG, "can't initialize telnet session"); - close_socket(); - return 1; - } else { - LOGI(TAG, "Telnet session started"); - }; - }; - - return 0; - } - - return 1; + if (shutdown(*active_sfd, SHUT_RDWR) == 0) { + LOGI(TAG, "Socket shutdown"); + } + if (close(*active_sfd) == 0) { + LOGI(TAG, "Socket closed"); + *active_sfd = 0; + } + carrier_detect = false; } -static int hangup_timeout(bool start) { - static uint64_t hup_t1, hup_t2; - static int waiting = 0; - int tdiff; - - if (*active_sfd) { - - if (start) { - hup_t1 = get_clock_us(); - waiting = 1; - LOGI(TAG, "Waiting to HUP"); - } else if (waiting) { - hup_t2 = get_clock_us(); - tdiff = (hup_t2 - hup_t1) / 100000; /* scale usec to 10ths of seconds */ - if (tdiff >= (int)(s_reg[SREG_HUP_DELAY])) { /* SREG_HUP_DELAY is in 10ths of seconds */ - waiting = 0; - s_reg[SREG_RINGS] = 0; - close_socket(); - LOGI(TAG, "HUP timeout - closing socket"); - return 1; - } - } - } else { - waiting = 0; - } - return 0; +static int open_socket(void) +{ + struct addrinfo hints; + struct addrinfo *result, *rp; + int s; + void *addrptr = NULL; + uint16_t port = 0; + struct sockaddr_in *sktv4 = NULL; + /* struct sockaddr_in6 *sktv6 = NULL; */ + int on = 1; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; /* Allow only IPv4 not IPv6 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; /* Any protocol */ + + s = getaddrinfo(addr, port_num, &hints, &result); + if (s != 0) { + LOGI(TAG, "getaddrinfo: %s", "failed"); + return 1; + } + + for (rp = result; rp != NULL; rp = rp->ai_next) { + LOGD(TAG, "Address: %d", rp->ai_family); + switch (rp->ai_family) { + case AF_INET: + sktv4 = (struct sockaddr_in *)rp->ai_addr; + port = sktv4->sin_port; + addrptr = &sktv4->sin_addr; + break; + case AF_INET6: + /* + sktv6 = (struct sockaddr_in6 *)rp->ai_addr; + port = sktv6->sin6_port; + addrptr = &sktv6->sin6_addr; + */ + LOGE(TAG, "Not expecting IPV6 addresses"); + return 1; + default: + LOGE(TAG, "Not expecting address family type %d", rp->ai_family); + return 1; + } + + inet_ntop(rp->ai_family, addrptr, addr, 100); + LOGI(TAG, "Address: %s:%d", addr, ntohs(port)); + + if ((sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) { + LOGE(TAG, "Failed to create socket"); + return 1; + }; + + active_sfd = &sfd; + carrier_detect = true; + LOGI(TAG, "Socket created"); + + if (connect(sfd, rp->ai_addr, sizeof(struct sockaddr_in)) < 0) { + LOGW(TAG, "Failed to connect to socket: %d", errno); + close_socket(); + return 1; + } + LOGI(TAG, "Socket connected"); + + if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)) == -1) { + LOGE(TAG, "can't set sockopt TCP_NODELAY"); + close_socket(); + return 1; + } + + /* Initialize Telnet session */ + if (s_reg[SREG_TELNET]) { + init_telnet_opts(); + if ((telnet = telnet_init(telnet_opts, telnet_hdlr, 0, NULL)) == 0) { + LOGE(TAG, "can't initialize telnet session"); + close_socket(); + return 1; + } else { + LOGI(TAG, "Telnet session started"); + }; + }; + + return 0; + } + + return 1; } -/****************************************************************************************************************************/ - -static int answer_init(void) { - - struct sockaddr_in serv_addr; - int enable = 1; - - if (answer_sfd) { - LOGE(TAG, "Already listening"); - return 1; - } - - if ((answer_sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - LOGE(TAG, "Failed to create Answer socket"); - answer_sfd = 0; - return 1; - }; - if (setsockopt(answer_sfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) { - LOGE(TAG, "Failed to setsockopt Answer socket"); - return 1; - }; - - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = INADDR_ANY; - serv_addr.sin_port = htons(s_reg[SREG_PORT]); - if (bind(answer_sfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - LOGE(TAG, "ERROR on binding %d %s", errno, strerror(errno)); - return 1; - } - listen(answer_sfd,1); - inet_ntop(AF_INET, &serv_addr.sin_addr, addr, 100); - LOGI(TAG, "Listening on %s:%d", addr, ntohs(serv_addr.sin_port)); - return 0; +static int hangup_timeout(bool start) +{ + static uint64_t hup_t1, hup_t2; + static int waiting = 0; + int tdiff; + + if (*active_sfd) { + if (start) { + hup_t1 = get_clock_us(); + waiting = 1; + LOGI(TAG, "Waiting to HUP"); + } else if (waiting) { + hup_t2 = get_clock_us(); + /* scale usec to 10ths of seconds */ + tdiff = (hup_t2 - hup_t1) / 100000; + /* SREG_HUP_DELAY is in 10ths of seconds */ + if (tdiff >= (int) (s_reg[SREG_HUP_DELAY])) { + waiting = 0; + s_reg[SREG_RINGS] = 0; + close_socket(); + LOGI(TAG, "HUP timeout - closing socket"); + return 1; + } + } + } else + waiting = 0; + return 0; } -static int answer(void) { - - struct sockaddr_in cli_addr; - socklen_t clilen; - int on = 1; - - clilen = sizeof(cli_addr); - newsockfd = accept(answer_sfd, (struct sockaddr *) &cli_addr, &clilen); - if (newsockfd < 0) { - LOGE(TAG, "ERROR on accept"); - return 1; - } - - inet_ntop(AF_INET, &cli_addr.sin_addr, addr, 100); - LOGI(TAG, "New Remote Connection: %s:%d", addr, ntohs(cli_addr.sin_port)); - active_sfd = &newsockfd; - carrier_detect = 1; - - if (setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)) == -1) { - LOGE(TAG, "can't set sockopt TCP_NODELAY"); - close_socket(); - return 1; - } - - /* Initialize Telnet session */ - if (s_reg[SREG_TELNET]) { - init_telnet_opts(); - if ((telnet = telnet_init(telnet_opts, telnet_hdlr, 0, NULL)) == 0) { - LOGE(TAG, "can't initialize telnet server session"); - close_socket(); - return 1; - } else { - LOGI(TAG, "Telnet server session started"); - }; - telnet_negotiate(telnet, (s_reg[SREG_TN_SGA] & 1) ? TELNET_WILL : TELNET_WONT , TELNET_TELOPT_SGA); - telnet_negotiate(telnet, (s_reg[SREG_TN_ECHO] & 1) ? TELNET_WILL : TELNET_WONT, TELNET_TELOPT_ECHO); - }; - - return 0; +/*************************************************************************************************/ + +static int answer_init(void) +{ + struct sockaddr_in serv_addr; + int enable = 1; + + if (answer_sfd) { + LOGE(TAG, "Already listening"); + return 1; + } + + if ((answer_sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + LOGE(TAG, "Failed to create Answer socket"); + answer_sfd = 0; + return 1; + }; + if (setsockopt(answer_sfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) { + LOGE(TAG, "Failed to setsockopt Answer socket"); + return 1; + }; + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(s_reg[SREG_PORT]); + if (bind(answer_sfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + LOGE(TAG, "ERROR on binding %d %s", errno, strerror(errno)); + return 1; + } + listen(answer_sfd, 1); + inet_ntop(AF_INET, &serv_addr.sin_addr, addr, 100); + LOGI(TAG, "Listening on %s:%d", addr, ntohs(serv_addr.sin_port)); + return 0; } -static int answer_check_ring(void) { +static int answer(void) +{ + struct sockaddr_in cli_addr; + socklen_t clilen; + int on = 1; + + clilen = sizeof(cli_addr); + newsockfd = accept(answer_sfd, (struct sockaddr *) &cli_addr, &clilen); + if (newsockfd < 0) { + LOGE(TAG, "ERROR on accept"); + return 1; + } + + inet_ntop(AF_INET, &cli_addr.sin_addr, addr, 100); + LOGI(TAG, "New Remote Connection: %s:%d", addr, ntohs(cli_addr.sin_port)); + active_sfd = &newsockfd; + carrier_detect = true; + + if (setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)) == -1) { + LOGE(TAG, "can't set sockopt TCP_NODELAY"); + close_socket(); + return 1; + } + + /* Initialize Telnet session */ + if (s_reg[SREG_TELNET]) { + init_telnet_opts(); + if ((telnet = telnet_init(telnet_opts, telnet_hdlr, 0, NULL)) == 0) { + LOGE(TAG, "can't initialize telnet server session"); + close_socket(); + return 1; + } else { + LOGI(TAG, "Telnet server session started"); + }; + telnet_negotiate(telnet, (s_reg[SREG_TN_SGA] & 1) ? TELNET_WILL : TELNET_WONT, + TELNET_TELOPT_SGA); + telnet_negotiate(telnet, (s_reg[SREG_TN_ECHO] & 1) ? TELNET_WILL : TELNET_WONT, + TELNET_TELOPT_ECHO); + }; + return 0; +} + +static int answer_check_ring(void) +{ struct pollfd p[1]; - static int ringing = 0; - static uint64_t ring_t1, ring_t2; - int tdiff; - - if (answer_sfd) { - - if (ringing) { - ring_t2 = get_clock_us(); - tdiff = (ring_t2 - ring_t1) / 1000000; - if (tdiff < 3) { - return 0; - } else { - ringing = 0; - } - } - - p[0].fd = answer_sfd; - p[0].events = POLLIN; - p[0].revents = 0; - poll(p, 1, 0); - - if (p[0].revents == POLLIN) { - - if (!ringing) { - ring_t1 = get_clock_us(); - ringing = 1; - LOGI(TAG, "Ringing"); - } - return 1; - } - } - return 0; + static int ringing = 0; + static uint64_t ring_t1, ring_t2; + int tdiff; + + if (answer_sfd) { + if (ringing) { + ring_t2 = get_clock_us(); + tdiff = (ring_t2 - ring_t1) / 1000000; + if (tdiff < 3) + return 0; + else + ringing = 0; + } + + p[0].fd = answer_sfd; + p[0].events = POLLIN; + p[0].revents = 0; + poll(p, 1, 0); + + if (p[0].revents == POLLIN) { + if (!ringing) { + ring_t1 = get_clock_us(); + ringing = 1; + LOGI(TAG, "Ringing"); + } + return 1; + } + } + return 0; } -/****************************************************************************************************************************/ +/*************************************************************************************************/ static char at_buf[AT_BUF_LEN * 2] = ""; static char at_cmd[AT_BUF_LEN] = ""; @@ -498,545 +498,542 @@ static char at_prev[AT_BUF_LEN] = ""; static char at_err[AT_BUF_LEN * 2] = ""; static char *at_out = at_buf; -enum at_states { cmd, A_recv, AT_recv, AS_recv, dat, intr, help }; -typedef enum at_states at_state_t; + +typedef enum at_state { cmd, A_recv, AT_recv, AS_recv, dat, intr, help } at_state_t; static at_state_t at_state = cmd; -#define CR "\r" -#define LF "\n" +#define CR "\r" +#define LF "\n" #define CRLF CR LF -#define END NULL +#define END NULL -#define AT_OK "OK" CRLF -#define AT_ERROR "ERROR" CRLF +#define AT_OK "OK" CRLF +#define AT_ERROR "ERROR" CRLF #define AT_NO_ANSWER "NO ANSWER" CRLF #define AT_NO_CARRIER "NO CARRIER" CRLF #define AT_NO_DIALTONE "NO DIALTONE" CRLF -#define AT_RING "RING" CRLF +#define AT_RING "RING" CRLF static const char *at_help[] = { - LF "AT COMMANDS:" CRLF, - "AT - 'AT' Test ", - "| A/ - (immediate) Repeat last" CRLF, - "AT$ - Help ", - "| ATIn - Information " CRLF, - "ATZ - Reset modem" CRLF, - "AT&F - Restore factory defaults ", + LF "AT COMMANDS:" CRLF, + "AT - 'AT' Test ", + "| A/ - (immediate) Repeat last" CRLF, + "AT$ - Help ", + "| ATIn - Information " CRLF, + "ATZ - Reset modem" CRLF, + "AT&F - Restore factory defaults ", #ifdef MODEM_NVRAM - "| AT&W - Write settings to NVRAM" CRLF, + "| AT&W - Write settings to NVRAM" CRLF, #else - CRLF, + CRLF, #endif - "ATDhostname:port - Dial hostname, port optional (default:" STR_VALUE(DEFAULT_LISTENER_PORT) ")" CRLF, - "+++ - Return to command mode ", - "| ATO - Return Online" CRLF, - "ATH - Hangup" CRLF, - "AT&An - Enable Answer mode - 0=interactive, 1=daemon" CRLF, - "ATA - Answer" CRLF, - "ATSn - Select register n" CRLF, - "AT? - Query current register ", - "| AT=r - Set current register to r" CRLF, - "ATEn - Command Echo 0=off, 1=on ", - "| ATQn - Quiet Results 0=off, 1=on" CRLF, + "ATDhostname:port - Dial hostname, port optional (default:" + STR_VALUE(DEFAULT_LISTENER_PORT) ")" CRLF, + "+++ - Return to command mode ", + "| ATO - Return Online" CRLF, + "ATH - Hangup" CRLF, + "AT&An - Enable Answer mode - 0=interactive, 1=daemon" CRLF, + "ATA - Answer" CRLF, + "ATSn - Select register n" CRLF, + "AT? - Query current register ", + "| AT=r - Set current register to r" CRLF, + "ATEn - Command Echo 0=off, 1=on ", + "| ATQn - Quiet Results 0=off, 1=on" CRLF, #ifdef MODEM_UART - "AT&K0 - Disable flow control ", - "| AT&K1 - Enable RTS/CTS flow control" CRLF, + "AT&K0 - Disable flow control ", + "| AT&K1 - Enable RTS/CTS flow control" CRLF, #endif #ifdef MODEM_WIFI - "AT+W? - Query WiFi AP Join status" CRLF, - "AT+W=ssid,password - Join WiFI AP" CRLF, - "AT+W$ - Show WiFi IP address ", - "| AT+W# - Show WiFi MAC address" CRLF, - "AT+W+ - Reconnect WiFI AP ", - "| AT+W- - Quit WiFi AP" CRLF, - "AT+U? - Query OTA Update ", - "| AT+U=url - Set custom URL for OTA update" CRLF, - "AT+U^ - Upgrade to OTA Update ", - "| AT+U! - Force Upgrade to OTA Update" CRLF, - "AT+U$ - Show OTA Partition Status" CRLF, + "AT+W? - Query WiFi AP Join status" CRLF, + "AT+W=ssid,password - Join WiFI AP" CRLF, + "AT+W$ - Show WiFi IP address ", + "| AT+W# - Show WiFi MAC address" CRLF, + "AT+W+ - Reconnect WiFI AP ", + "| AT+W- - Quit WiFi AP" CRLF, + "AT+U? - Query OTA Update ", + "| AT+U=url - Set custom URL for OTA update" CRLF, + "AT+U^ - Upgrade to OTA Update ", + "| AT+U! - Force Upgrade to OTA Update" CRLF, + "AT+U$ - Show OTA Partition Status" CRLF, #endif #ifdef MODEM_UART - "AT+B? - Query Baud Rate ", - "| AT+B=nnn - Set Baud Rate (4800..115200)" CRLF, + "AT+B? - Query Baud Rate ", + "| AT+B=nnn - Set Baud Rate (4800..115200)" CRLF, #endif - "AT+T? - Query Telnet TERM ", - "| AT+T=name - Set Telnet TERM" CRLF, - END + "AT+T? - Query Telnet TERM ", + "| AT+T=name - Set Telnet TERM" CRLF, + END }; static const char **msg; -static void at_cat_c(char c) { - if (strlen(at_cmd) >= AT_BUF_LEN - 1) { - LOGE(TAG, "Buffer overflow"); - return; - } +static void at_cat_c(char c) +{ + if (strlen(at_cmd) >= AT_BUF_LEN - 1) { + LOGE(TAG, "Buffer overflow"); + return; + } if (c == '\b') { /*TODO: use s_reg[SREG_BS] */ - if(strlen(at_cmd) > 2) { - if (s_reg[SREG_OPT] & OPT_ECHO) { - at_buf[strlen(at_buf) + 3] = 0; - at_buf[strlen(at_buf) + 2] = c; - at_buf[strlen(at_buf) + 1] = ' '; - at_buf[strlen(at_buf)] = c; - } + if (strlen(at_cmd) > 2) { + if (s_reg[SREG_OPT] & OPT_ECHO) { + at_buf[strlen(at_buf) + 3] = 0; + at_buf[strlen(at_buf) + 2] = c; + at_buf[strlen(at_buf) + 1] = ' '; + at_buf[strlen(at_buf)] = c; + } at_cmd[strlen(at_cmd) - 1] = 0; } } else { - if (s_reg[SREG_OPT] & OPT_ECHO) { - at_buf[strlen(at_buf) + 1] = 0; - at_buf[strlen(at_buf)] = c; - } + if (s_reg[SREG_OPT] & OPT_ECHO) { + at_buf[strlen(at_buf) + 1] = 0; + at_buf[strlen(at_buf)] = c; + } at_cmd[strlen(at_cmd) + 1] = 0; at_cmd[strlen(at_cmd)] = c; } LOGD(TAG, "AT CMD: [%s]", at_cmd); } -static void at_cat_s(const char *s) { - if (s_reg[SREG_OPT] & OPT_QUIET) return; - if ((strlen(at_buf) + strlen(s)) >= (AT_BUF_LEN*2) - 1) { - LOGE(TAG, "Buffer overflow"); - return; - } +static void at_cat_s(const char *s) +{ + if (s_reg[SREG_OPT] & OPT_QUIET) + return; + if ((strlen(at_buf) + strlen(s)) >= (AT_BUF_LEN * 2) - 1) { + LOGE(TAG, "Buffer overflow"); + return; + } strcat(at_buf, s); } -static int process_at_cmd(void) { - int tmp_reg; +static int process_at_cmd(void) +{ + int tmp_reg; char *at_ptr = at_cmd; - char *arg_ptr; + char *arg_ptr; + strcpy(at_prev, at_cmd); - if ((*at_ptr++ =='A') && (*at_ptr++ == 'T')) { + if ((*at_ptr++ == 'A') && (*at_ptr++ == 'T')) at_cmd[0] = 0; - } else { + else { at_cmd[0] = 0; strcpy(at_err, LF AT_ERROR CRLF); return 1; } -#define AT_END_CMD (at_ptr = &at_cmd[strlen(at_cmd)]) -#define AT_NEXT_CMD (at_ptr++) -#define AT_NEXT_CMD2 (at_ptr += 2) -#define AT_NEXT_CMD_ARGS (at_ptr = arg_ptr) +#define AT_END_CMD (at_ptr = &at_cmd[strlen(at_cmd)]) +#define AT_NEXT_CMD (at_ptr++) +#define AT_NEXT_CMD2 (at_ptr += 2) +#define AT_NEXT_CMD_ARGS (at_ptr = arg_ptr) - while (*at_ptr != 0) { - LOGD(__func__, "AT CMD: [%s]", at_ptr); - switch (*at_ptr++) { - /*TODO: add a command to check connection status */ + while (*at_ptr != 0) { + LOGD(__func__, "AT CMD: [%s]", at_ptr); + switch (*at_ptr++) { + /*TODO: add a command to check connection status */ case '\r': /* AT */ /*TODO: use s_reg[SREG_CR] */ break; - case 'I': - tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); + case 'I': + tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); - if (tmp_reg == 0) { - strcpy(at_err, LF MODEM_ID CRLF); - at_cat_s(at_err); + if (tmp_reg == 0) { + strcpy(at_err, LF MODEM_ID CRLF); + at_cat_s(at_err); #ifdef MODEM_ESP32 - } else if (tmp_reg == 1) { - const esp_app_desc_t* desc = esp_ota_get_app_description(); - sprintf(at_err, LF "%s" CRLF, desc->version); - at_cat_s(at_err); - } else if (tmp_reg == 2) { - sprintf(at_err, LF "%s" CRLF, esp_get_idf_version()); - at_cat_s(at_err); - } else if (tmp_reg == 3) { - const esp_app_desc_t* desc = esp_ota_get_app_description(); - sprintf(at_err, LF "%s" CRLF, desc->project_name); - at_cat_s(at_err); - } else if (tmp_reg == 4) { - sprintf(at_err, LF "DMA %d" CRLF, heap_caps_get_free_size(MALLOC_CAP_DMA)); - at_cat_s(at_err); - } else if (tmp_reg == 5) { - sprintf(at_err, LF "INTERNAL %d" CRLF, heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); - at_cat_s(at_err); - } else if (tmp_reg == 6) { - sprintf(at_err, LF "TOTAL %d" CRLF, heap_caps_get_free_size(MALLOC_CAP_32BIT)); - at_cat_s(at_err); + } else if (tmp_reg == 1) { + const esp_app_desc_t *desc = esp_ota_get_app_description(); + + sprintf(at_err, LF "%s" CRLF, desc->version); + at_cat_s(at_err); + } else if (tmp_reg == 2) { + sprintf(at_err, LF "%s" CRLF, esp_get_idf_version()); + at_cat_s(at_err); + } else if (tmp_reg == 3) { + const esp_app_desc_t *desc = esp_ota_get_app_description(); + + sprintf(at_err, LF "%s" CRLF, desc->project_name); + at_cat_s(at_err); + } else if (tmp_reg == 4) { + sprintf(at_err, LF "DMA %d" CRLF, + heap_caps_get_free_size(MALLOC_CAP_DMA)); + at_cat_s(at_err); + } else if (tmp_reg == 5) { + sprintf(at_err, LF "INTERNAL %d" CRLF, + heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + at_cat_s(at_err); + } else if (tmp_reg == 6) { + sprintf(at_err, LF "TOTAL %d" CRLF, + heap_caps_get_free_size(MALLOC_CAP_32BIT)); + at_cat_s(at_err); #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS - } else if (tmp_reg == 8) { - char buff[1024]; - vTaskGetRunTimeStats(buff); - fwrite(buff, strlen(buff), 1, stdout); /* Writes to FTDI UART not the modem */ - at_cat_s(LF "TASK TIMES" CRLF); + } else if (tmp_reg == 8) { + char buff[1024]; + vTaskGetRunTimeStats(buff); + /* Writes to FTDI UART not the modem */ + fwrite(buff, strlen(buff), 1, stdout); + at_cat_s(LF "TASK TIMES" CRLF); #endif #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS - } else if (tmp_reg == 9) { - char buff[1024]; - vTaskList(buff); - fwrite(buff, strlen(buff), 1, stdout); /* Writes to FTDI UART not the modem */ - at_cat_s(LF "TASKS" CRLF); -#endif + } else if (tmp_reg == 9) { + char buff[1024]; + vTaskList(buff); + /* Writes to FTDI UART not the modem */ + fwrite(buff, strlen(buff), 1, stdout); + at_cat_s(LF "TASKS" CRLF); #endif - } else { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - AT_NEXT_CMD_ARGS; - break; +#endif /* MODEM_ESP32 */ + } else { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + AT_NEXT_CMD_ARGS; + break; case '$': /* AT$ */ - at_state = help; - msg = at_help; + at_state = help; + msg = at_help; break; case 'Z': /* ATZ */ - memset(at_prev, 0, sizeof(at_prev)); - modem_device_init(); + memset(at_prev, 0, sizeof(at_prev)); + modem_device_init(); AT_END_CMD; - break; + break; case 'H': /* ATH */ - if (*active_sfd) { - AT_END_CMD; - s_reg[SREG_RINGS] = 0; - close_socket(); - at_cat_s(LF "HANGUP" CR); - } + if (*active_sfd) { + AT_END_CMD; + s_reg[SREG_RINGS] = 0; + close_socket(); + at_cat_s(LF "HANGUP" CR); + } break; case 'D': /* ATDaddr[:port=23] */ #ifdef MODEM_WIFI - if (WiFi_status() != 3) { - strcpy(at_err, LF AT_NO_DIALTONE CRLF); - return 1; - } + if (WiFi_status() != 3) { + strcpy(at_err, LF AT_NO_DIALTONE CRLF); + return 1; + } #endif - if (*active_sfd) { - strcpy(at_err, LF "ALREADY IN CALL" CRLF); - return 1; - } - - strcpy(at_err, at_ptr); - arg_ptr = strtok(at_err, ":\r"); - - if(arg_ptr == NULL) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - - strncpy(addr, arg_ptr, AT_BUF_LEN - 1); - LOGI(TAG, "Addr: [%s]", addr); - arg_ptr = strtok(NULL, "\r"); - if (arg_ptr != NULL) { - strncpy(port_num, arg_ptr, 10); - } else { - strcpy(port_num, STR_VALUE(DEFAULT_LISTENER_PORT)); - } - LOGI(TAG, "Port: [%s]", port_num); - - if (open_socket()) { - strcpy(at_err, LF AT_NO_ANSWER CRLF); - return 1; - }; + if (*active_sfd) { + strcpy(at_err, LF "ALREADY IN CALL" CRLF); + return 1; + } + + strcpy(at_err, at_ptr); + arg_ptr = strtok(at_err, ":\r"); + + if (arg_ptr == NULL) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + + strncpy(addr, arg_ptr, AT_BUF_LEN - 1); + LOGI(TAG, "Addr: [%s]", addr); + arg_ptr = strtok(NULL, "\r"); + if (arg_ptr != NULL) + strncpy(port_num, arg_ptr, 10); + else + strcpy(port_num, STR_VALUE(DEFAULT_LISTENER_PORT)); + LOGI(TAG, "Port: [%s]", port_num); + + if (open_socket()) { + strcpy(at_err, LF AT_NO_ANSWER CRLF); + return 1; + }; AT_END_CMD; - at_state = dat; - if (telnet) { - at_cat_s(LF "CONNECT TELNET" CRLF); - } else { - at_cat_s(LF "CONNECT" CRLF); - } - *at_err = 0; - return 1; /* Not an error, just want to suppress the OK message */ + at_state = dat; + if (telnet) + at_cat_s(LF "CONNECT TELNET" CRLF); + else + at_cat_s(LF "CONNECT" CRLF); + *at_err = 0; + return 1; /* Not an error, just want to suppress the OK message */ case 'S': /* ATSn */ - tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); + tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); - if (tmp_reg < 0 || tmp_reg > (MAX_REG_NUM - 1) || arg_ptr == at_ptr) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } + if (tmp_reg < 0 || tmp_reg > (MAX_REG_NUM - 1) || arg_ptr == at_ptr) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } - reg = tmp_reg; - LOGI(TAG, "AT Register set to %d", reg); - AT_NEXT_CMD_ARGS; + reg = tmp_reg; + LOGI(TAG, "AT Register set to %d", reg); + AT_NEXT_CMD_ARGS; break; case '?': /* AT? */ - LOGI(TAG, "ATS%d? is %d", reg, s_reg[reg]); - sprintf(at_err, LF "%d" CRLF, s_reg[reg]); - at_cat_s(at_err); + LOGI(TAG, "ATS%d? is %d", reg, s_reg[reg]); + sprintf(at_err, LF "%d" CRLF, s_reg[reg]); + at_cat_s(at_err); break; case '=': /* AT=r */ - tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); + tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); - if (tmp_reg < 0 || tmp_reg > 255 || arg_ptr == at_ptr) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } + if (tmp_reg < 0 || tmp_reg > 255 || arg_ptr == at_ptr) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } - LOGI(TAG, "ATS%d = %d", reg, tmp_reg); - AT_NEXT_CMD_ARGS; - s_reg[reg] = tmp_reg; + LOGI(TAG, "ATS%d = %d", reg, tmp_reg); + AT_NEXT_CMD_ARGS; + s_reg[reg] = tmp_reg; break; case 'O': /* ATO */ AT_END_CMD; - if (*active_sfd == 0) { - strcpy(at_err, LF AT_NO_CARRIER CRLF); - return 1; - } - at_state = dat; + if (*active_sfd == 0) { + strcpy(at_err, LF AT_NO_CARRIER CRLF); + return 1; + } + at_state = dat; + break; + case 'E': /* ATE - Command echo */ + tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); + AT_NEXT_CMD_ARGS; + if (tmp_reg < 0 || tmp_reg > 1) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + if (tmp_reg) + s_reg[SREG_OPT] |= OPT_ECHO; + else + s_reg[SREG_OPT] &= ~OPT_ECHO; + break; + case 'Q': /* ATQ - Quiet mode */ + tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); + AT_NEXT_CMD_ARGS; + if (tmp_reg < 0 || tmp_reg > 1) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + if (tmp_reg) + s_reg[SREG_OPT] |= OPT_QUIET; + else + s_reg[SREG_OPT] &= ~OPT_QUIET; break; - case 'E': /* ATE - Command echo */ - tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); - AT_NEXT_CMD_ARGS; - if (tmp_reg < 0 || tmp_reg > 1) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - if (tmp_reg) { - s_reg[SREG_OPT] |= OPT_ECHO; - } else { - s_reg[SREG_OPT] &= ~OPT_ECHO; - } - break; - case 'Q': /* ATQ - Quiet mode */ - tmp_reg = strtol(at_ptr, &arg_ptr, BASE_DECIMAL); - AT_NEXT_CMD_ARGS; - if (tmp_reg < 0 || tmp_reg > 1) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - if (tmp_reg) { - s_reg[SREG_OPT] |= OPT_QUIET; - } else { - s_reg[SREG_OPT] &= ~OPT_QUIET; - } - break; - case '&': - if (*at_ptr == 'A') { /* AT&A - enable answer - listen */ - tmp_reg = strtol(++at_ptr, &arg_ptr, BASE_DECIMAL); - AT_NEXT_CMD_ARGS; + case '&': + if (*at_ptr == 'A') { /* AT&A - enable answer - listen */ + tmp_reg = strtol(++at_ptr, &arg_ptr, BASE_DECIMAL); + AT_NEXT_CMD_ARGS; #ifdef MODEM_WIFI - if (WiFi_status() != 3) { - strcpy(at_err, LF AT_NO_DIALTONE CRLF); - return 1; - } + if (WiFi_status() != 3) { + strcpy(at_err, LF AT_NO_DIALTONE CRLF); + return 1; + } #endif - if (answer_init()) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - }; - if (tmp_reg) { - daemon_f = true; - s_reg[SREG_OPT] &= ~OPT_ECHO; - s_reg[SREG_OPT] |= OPT_QUIET; - LOGI(TAG, "MODEM will be daemon and listen (No Echo & Quiet)"); - } - break; - } else if (*at_ptr == 'F') { /* AT&F - reset to Factory defaults */ - for (tmp_reg = 0; tmp_reg < MAX_REG_NUM; tmp_reg++) { - s_reg[tmp_reg] = s_reg_defaults[tmp_reg]; - } - LOGI(TAG, "Reset to Factory defaults"); - AT_NEXT_CMD; - break; + if (answer_init()) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + }; + if (tmp_reg) { + daemon_f = true; + s_reg[SREG_OPT] &= ~OPT_ECHO; + s_reg[SREG_OPT] |= OPT_QUIET; + LOGI(TAG, "MODEM will be daemon and listen " + "(No Echo & Quiet)"); + } + break; + } else if (*at_ptr == 'F') { /* AT&F - reset to Factory defaults */ + for (tmp_reg = 0; tmp_reg < MAX_REG_NUM; tmp_reg++) + s_reg[tmp_reg] = s_reg_defaults[tmp_reg]; + LOGI(TAG, "Reset to Factory defaults"); + AT_NEXT_CMD; + break; #ifdef MODEM_NVRAM - } else if (*at_ptr == 'W') { /* AT&W - write settings to NVRAM */ - Modem_nvramWriteAllSreg(s_reg, MAX_REG_NUM); - LOGI(TAG, "Settings written to NVRAM"); - AT_NEXT_CMD; - break; + } else if (*at_ptr == 'W') { /* AT&W - write settings to NVRAM */ + Modem_nvramWriteAllSreg(s_reg, MAX_REG_NUM); + LOGI(TAG, "Settings written to NVRAM"); + AT_NEXT_CMD; + break; #endif #ifdef MODEM_UART - } else if (*at_ptr == 'K') { - tmp_reg = strtol(++at_ptr, &arg_ptr, BASE_DECIMAL); - AT_NEXT_CMD_ARGS; - if (tmp_reg == 0) { /* AT&K0 - disable flow control */ - s_reg[SREG_FLOW_CTRL] = 0; - /* clear UART flow control */ - Modem_setFlowControl(0); - LOGI(TAG, "Flow Control Disabled"); - } else if (tmp_reg == 1) { /* AT&K1 - enable RTS/CTS flow control */ - s_reg[SREG_FLOW_CTRL] = 1; - /* set UART RTS/CTS flow control */ - Modem_setFlowControl(1); - LOGI(TAG, "RTS/CTS Flow Control Enabled"); - } else { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } + } else if (*at_ptr == 'K') { + tmp_reg = strtol(++at_ptr, &arg_ptr, BASE_DECIMAL); + AT_NEXT_CMD_ARGS; + if (tmp_reg == 0) { /* AT&K0 - disable flow control */ + s_reg[SREG_FLOW_CTRL] = 0; + /* clear UART flow control */ + Modem_setFlowControl(0); + LOGI(TAG, "Flow Control Disabled"); + } else if (tmp_reg == 1) { /* AT&K1 - enable RTS/CTS flow control */ + s_reg[SREG_FLOW_CTRL] = 1; + /* set UART RTS/CTS flow control */ + Modem_setFlowControl(1); + LOGI(TAG, "RTS/CTS Flow Control Enabled"); + } else { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } #endif - } else { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - break; - case '+': - if (*at_ptr == 'T' && *(at_ptr+1) == '?') { - const char *ttype; - if ((ttype = getenv("TERM")) == NULL) { - ttype = TELNET_TTYPE; - } - sprintf(at_err, LF "%s" CRLF, ttype); - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'T' && *(at_ptr+1) == '=') { - strcpy(at_err, at_ptr+2); - arg_ptr = strtok(at_err, "\r"); - - if(arg_ptr == NULL) { - unsetenv("TERM"); - LOGI(TAG, "TERM cleared"); - } else { - setenv("TERM", arg_ptr, 1); - LOGI(TAG, "TERM: [%s]", getenv("TERM")); - } + } else { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + break; + case '+': + if (*at_ptr == 'T' && *(at_ptr + 1) == '?') { + const char *ttype; + + if ((ttype = getenv("TERM")) == NULL) { + ttype = TELNET_TTYPE; + } + sprintf(at_err, LF "%s" CRLF, ttype); + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'T' && *(at_ptr + 1) == '=') { + strcpy(at_err, at_ptr + 2); + arg_ptr = strtok(at_err, "\r"); + + if (arg_ptr == NULL) { + unsetenv("TERM"); + LOGI(TAG, "TERM cleared"); + } else { + setenv("TERM", arg_ptr, 1); + LOGI(TAG, "TERM: [%s]", getenv("TERM")); + } #ifdef MODEM_NVRAM - Modem_nvramWriteEnv("TERM"); + Modem_nvramWriteEnv("TERM"); #endif - AT_END_CMD; + AT_END_CMD; #ifdef MODEM_WIFI -/** - * WIFI CONFIG HANDLING - */ - } else if (*at_ptr == 'W' && *(at_ptr+1) == '=') { - - char ssid[MAX_SSID + 1] = ""; - char psw[MAX_PWD + 1] = ""; - - strcpy(at_err, at_ptr+2); - arg_ptr = strtok(at_err, ",\r"); - - if(arg_ptr == NULL) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - strncpy(ssid, arg_ptr, MAX_SSID); - - arg_ptr = strtok(NULL, "\r"); - if (arg_ptr != NULL) { - strncpy(psw, arg_ptr, MAX_PWD); - } - - WiFi_begin(ssid, psw); - AT_END_CMD; - } else if (*at_ptr == 'W' && *(at_ptr+1) == '?') { - sprintf(at_err, LF "%s" CRLF, WiFi_status_str()); - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'W' && *(at_ptr+1) == '+') { - if (WiFi_status() == 255) { - WiFi_begin_x(); - } - sprintf(at_err, LF "%s" CRLF, WiFi_reconnect()); - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'W' && *(at_ptr+1) == '-') { - sprintf(at_err, LF "%s" CRLF, WiFi_disconnect()); - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'W' && *(at_ptr+1) == '$') { - sprintf(at_err, LF "%s" CRLF, WiFi_IP()); - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'W' && *(at_ptr+1) == '#') { - sprintf(at_err, LF "%s" CRLF, WiFi_MAC()); - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'U' && *(at_ptr+1) == '=') { - - if (WiFi_status() != 3) { - strcpy(at_err, LF AT_NO_DIALTONE CRLF); - return 1; - } - - strcpy(at_err, at_ptr+2); - arg_ptr = strtok(at_err, "\r"); - - if(arg_ptr == NULL) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - - if (ota_setURL(at_err, arg_ptr)) { - return 1; - } - - at_cat_s(at_err); - AT_END_CMD; - } else if (*at_ptr == 'U' && *(at_ptr+1) == '?') { - - if (WiFi_status() != 3) { - strcpy(at_err, LF AT_NO_DIALTONE CRLF); - return 1; - } - - at_err[0] = *(at_ptr+2); - - if (ota_start(at_err)) { - return 1; - } - - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'U' && *(at_ptr+1) == '$') { - - if (ota_partitionQuery(at_err)) { - return 1; - } - - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'U' && *(at_ptr+1) == '^') { - - if (ota_upgrade(at_err)) { - return 1; - } - - at_cat_s(at_err); - AT_NEXT_CMD2; - } else if (*at_ptr == 'U' && *(at_ptr+1) == '!') { - - if (ota_forceUpgrade(at_err)) { - return 1; - } - - at_cat_s(at_err); - AT_NEXT_CMD2; -#endif + /** + * WIFI CONFIG HANDLING + */ + } else if (*at_ptr == 'W' && *(at_ptr + 1) == '=') { + char ssid[MAX_SSID + 1] = ""; + char psw[MAX_PWD + 1] = ""; + + strcpy(at_err, at_ptr + 2); + arg_ptr = strtok(at_err, ",\r"); + + if (arg_ptr == NULL) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + strncpy(ssid, arg_ptr, MAX_SSID); + + arg_ptr = strtok(NULL, "\r"); + if (arg_ptr != NULL) + strncpy(psw, arg_ptr, MAX_PWD); + + WiFi_begin(ssid, psw); + AT_END_CMD; + } else if (*at_ptr == 'W' && *(at_ptr + 1) == '?') { + sprintf(at_err, LF "%s" CRLF, WiFi_status_str()); + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'W' && *(at_ptr + 1) == '+') { + if (WiFi_status() == 255) + WiFi_begin_x(); + sprintf(at_err, LF "%s" CRLF, WiFi_reconnect()); + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'W' && *(at_ptr + 1) == '-') { + sprintf(at_err, LF "%s" CRLF, WiFi_disconnect()); + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'W' && *(at_ptr + 1) == '$') { + sprintf(at_err, LF "%s" CRLF, WiFi_IP()); + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'W' && *(at_ptr + 1) == '#') { + sprintf(at_err, LF "%s" CRLF, WiFi_MAC()); + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'U' && *(at_ptr + 1) == '=') { + if (WiFi_status() != 3) { + strcpy(at_err, LF AT_NO_DIALTONE CRLF); + return 1; + } + + strcpy(at_err, at_ptr + 2); + arg_ptr = strtok(at_err, "\r"); + + if (arg_ptr == NULL) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + + if (ota_setURL(at_err, arg_ptr)) + return 1; + + at_cat_s(at_err); + AT_END_CMD; + } else if (*at_ptr == 'U' && *(at_ptr + 1) == '?') { + if (WiFi_status() != 3) { + strcpy(at_err, LF AT_NO_DIALTONE CRLF); + return 1; + } + + at_err[0] = *(at_ptr + 2); + + if (ota_start(at_err)) + return 1; + + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'U' && *(at_ptr + 1) == '$') { + if (ota_partitionQuery(at_err)) + return 1; + + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'U' && *(at_ptr + 1) == '^') { + if (ota_upgrade(at_err)) + return 1; + + at_cat_s(at_err); + AT_NEXT_CMD2; + } else if (*at_ptr == 'U' && *(at_ptr + 1) == '!') { + if (ota_forceUpgrade(at_err)) + return 1; + + at_cat_s(at_err); + AT_NEXT_CMD2; +#endif /* MODEM_WIFI */ #ifdef MODEM_UART -/** - * SERIAL CONFIG HANDLING - */ - } else if (*at_ptr == 'B' && *(at_ptr+1) == '=') { - tmp_reg = strtol(at_ptr+2, &arg_ptr, BASE_DECIMAL); - - if (tmp_reg < 4800 || tmp_reg > 115200 || arg_ptr == (at_ptr+2)) { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - - Modem_updateBaudRate(tmp_reg); - sprintf(at_err, LF "%d" CRLF, Modem_baudRate()); - at_cat_s(at_err); - AT_NEXT_CMD_ARGS; - } else if (*at_ptr == 'B' && *(at_ptr+1) == '?') { - sprintf(at_err, LF "%d" CRLF, Modem_baudRate()); - at_cat_s(at_err); - AT_NEXT_CMD2; -#endif -/** - * - */ - } else { - strcpy(at_err, LF AT_ERROR CRLF); - return 1; - } - break; - case 'A': /* ATA - answer */ + /** + * SERIAL CONFIG HANDLING + */ + } else if (*at_ptr == 'B' && *(at_ptr + 1) == '=') { + tmp_reg = strtol(at_ptr + 2, &arg_ptr, BASE_DECIMAL); + + if (tmp_reg < 4800 || tmp_reg > 115200 || arg_ptr == (at_ptr + 2)) { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + + Modem_updateBaudRate(tmp_reg); + sprintf(at_err, LF "%d" CRLF, Modem_baudRate()); + at_cat_s(at_err); + AT_NEXT_CMD_ARGS; + } else if (*at_ptr == 'B' && *(at_ptr + 1) == '?') { + sprintf(at_err, LF "%d" CRLF, Modem_baudRate()); + at_cat_s(at_err); + AT_NEXT_CMD2; +#endif /* MODEM_UART */ + /** + * + */ + } else { + strcpy(at_err, LF AT_ERROR CRLF); + return 1; + } + break; + case 'A': /* ATA - answer */ #ifdef MODEM_WIFI - if (WiFi_status() != 3) { - strcpy(at_err, LF AT_NO_DIALTONE CRLF); - return 1; - } + if (WiFi_status() != 3) { + strcpy(at_err, LF AT_NO_DIALTONE CRLF); + return 1; + } #endif - answer(); - AT_END_CMD; - at_state = dat; - break; + answer(); + AT_END_CMD; + at_state = dat; + break; default: strcpy(at_err, LF AT_ERROR CRLF); return 1; + } } - } return 0; } @@ -1044,308 +1041,299 @@ static int process_at_cmd(void) { static uint64_t at_t1, at_t2; static int tdiff; -int modem_device_poll(int i); +bool modem_device_alive(int i) +{ + UNUSED(i); -int modem_device_alive(int i) { + if (!daemon_f) + return true; - UNUSED(i); - - if (!daemon_f) return 1; - - if (answer_sfd) { - if (*active_sfd) { - return 1; - } else { - if (at_state == cmd) { - modem_device_poll(0); - return 0; - } - } - } - return 0; + if (answer_sfd) { + if (*active_sfd) + return true; + else { + if (at_state == cmd) { + modem_device_poll(0); + return false; + } + } + } + return false; } -static int _read(void) { - - unsigned char data; - - if (read(*active_sfd, &data, 1) == 0) { - /* this will occur if the socket is disconnected */ - LOGI(TAG, "Socket disconnected"); - at_buf[0] = 0; - at_cat_s(CRLF AT_NO_CARRIER); - hangup_timeout(true); - at_cmd[0] = 0; - at_state = cmd; - carrier_detect = 0; +static int _read(void) +{ + unsigned char data; - return -1; - } + if (read(*active_sfd, &data, 1) == 0) { + /* this will occur if the socket is disconnected */ + LOGI(TAG, "Socket disconnected"); + at_buf[0] = 0; + at_cat_s(CRLF AT_NO_CARRIER); + hangup_timeout(true); + at_cmd[0] = 0; + at_state = cmd; + carrier_detect = false; - return data; -} + return -1; + } -int modem_device_poll(int i) { - - UNUSED(i); - - struct pollfd p[1]; - - if (at_state == help) { - if (strlen(at_buf) == 0) { - at_cat_s(*msg); - msg++; - if (*msg == NULL) { - at_state = cmd; - } - } - return strlen(at_out) > 0; - } else if (at_state == intr) { - if (strlen(at_buf) == 3) { - at_t2 = get_clock_us(); - tdiff = (at_t2 - at_t1) / 1000000; - if (tdiff > 0) { - at_state = cmd; - LOGI(TAG, "+++ Returning to CMD mode"); - at_cat_s(CRLF AT_OK); - return strlen(at_buf) > 0; - } - } - return 0; - } else if (at_state == dat && strlen(at_out) == 0) { - - /** - * In telnet mode this "clocks" the inbound connection into telnet_recv() - * and lets the event handler buffer the input (1 character) - * then it can check the buffer and report on available data in the buffer - */ - - if ((telnet != NULL) && tn_len) return POLLIN; - - p[0].fd = *active_sfd; - p[0].events = POLLIN | POLLOUT; - p[0].revents = 0; - poll(p, 1, 0); - - if (telnet == NULL) return p[0].revents & POLLIN; - - if (p[0].revents & POLLIN) { - int res; - char data; - res = _read(); - if (res != -1) { - data = res; - telnet_recv(telnet, (char *) &data, 1); - } - if (tn_len) return POLLIN; - } - - return 0; - - } else { - if (answer_check_ring()) { - s_reg[SREG_RINGS]++; - at_cat_s(CRLF AT_RING); - if ((s_reg[SREG_AA] > 0) && (s_reg[SREG_RINGS] >= s_reg[SREG_AA])) { - if (!answer()) { - at_state = dat; - } - } - } else if(hangup_timeout(false)) { - at_cat_s(CRLF "HANGUP" CRLF); - } - - return strlen(at_out) > 0; - } + return data; } -int modem_device_get(int i) { +int modem_device_poll(int i) +{ + UNUSED(i); - UNUSED(i); - - struct pollfd p[1]; - unsigned char data; - - if (at_state == dat && strlen(at_out) == 0) { + struct pollfd p[1]; - if (telnet != NULL) { - if (tn_len) { - tn_len = 0; - return tn_recv; - } else { - return -1; - } - } else { + if (at_state == help) { + if (strlen(at_buf) == 0) { + at_cat_s(*msg); + msg++; + if (*msg == NULL) + at_state = cmd; + } + return strlen(at_out) > 0; + } else if (at_state == intr) { + if (strlen(at_buf) == 3) { + at_t2 = get_clock_us(); + tdiff = (at_t2 - at_t1) / 1000000; + if (tdiff > 0) { + at_state = cmd; + LOGI(TAG, "+++ Returning to CMD mode"); + at_cat_s(CRLF AT_OK); + return strlen(at_buf) > 0; + } + } + return 0; + } else if (at_state == dat && strlen(at_out) == 0) { + /** + * In telnet mode this "clocks" the inbound connection into telnet_recv() + * and lets the event handler buffer the input (1 character) + * then it can check the buffer and report on available data in the buffer + */ + + if ((telnet != NULL) && tn_len) + return POLLIN; + + p[0].fd = *active_sfd; + p[0].events = POLLIN | POLLOUT; + p[0].revents = 0; + poll(p, 1, 0); + + if (telnet == NULL) + return p[0].revents & POLLIN; + + if (p[0].revents & POLLIN) { + int res; + char data; + res = _read(); + if (res != -1) { + data = res; + telnet_recv(telnet, (char *) &data, 1); + } + if (tn_len) + return POLLIN; + } - p[0].fd = *active_sfd; - p[0].events = POLLIN; - p[0].revents = 0; - poll(p, 1, 0); + return 0; + } else { + if (answer_check_ring()) { + s_reg[SREG_RINGS]++; + at_cat_s(CRLF AT_RING); + if ((s_reg[SREG_AA] > 0) && (s_reg[SREG_RINGS] >= s_reg[SREG_AA])) { + if (!answer()) + at_state = dat; + } + } else if (hangup_timeout(false)) + at_cat_s(CRLF "HANGUP" CRLF); - if (!(p[0].revents & POLLIN)) return -1; + return strlen(at_out) > 0; + } +} - return _read(); - } - } else { +int modem_device_get(int i) +{ + UNUSED(i); - if (strlen(at_out) > 0) { - data = *at_out; - at_out++; - if (strlen(at_out) == 0) { - at_out = at_buf; - at_buf[0] = 0; - } - } else { - return -1; - } - } + struct pollfd p[1]; + unsigned char data; + + if (at_state == dat && strlen(at_out) == 0) { + if (telnet != NULL) { + if (tn_len) { + tn_len = 0; + return tn_recv; + } else + return -1; + } else { + p[0].fd = *active_sfd; + p[0].events = POLLIN; + p[0].revents = 0; + poll(p, 1, 0); + + if (!(p[0].revents & POLLIN)) + return -1; + + return _read(); + } + } else { + if (strlen(at_out) > 0) { + data = *at_out; + at_out++; + if (strlen(at_out) == 0) { + at_out = at_buf; + at_buf[0] = 0; + } + } else + return -1; + } - return data; + return data; } -void modem_device_send(int i, char data) { - - UNUSED(i); +void modem_device_send(int i, char data) +{ + UNUSED(i); switch (at_state) { - /*** - * data mode - */ - case intr: - if (data == '+' && strlen(at_buf) < 3) { - at_buf[strlen(at_buf)+1] = 0; - at_buf[strlen(at_buf)] = data; - at_t1 = get_clock_us(); - return; - } else { - if (telnet != NULL) { - telnet_send(telnet, at_buf, strlen(at_buf)); - } else { - if (write(*active_sfd, at_buf, strlen(at_buf)) != (ssize_t) strlen(at_buf)) - LOGE(TAG, "can't send at_buf to active_sfd"); - } - - at_state = dat; - } - /*** - * NO break; - * Intentional fallthrough here. - */ - /* fall through */ - case dat: - at_t2 = get_clock_us(); - tdiff = (at_t2 - at_t1) / 1000000; - - if (data == '+' && (tdiff > 0) && !daemon_f) { - at_buf[0] = data; - at_buf[1] = 0; - at_out = at_buf; - at_state = intr; - return; - } - if (telnet != NULL) { - telnet_send(telnet, (char *) &data, 1); - } else { - if (write(*active_sfd, (char *) &data, 1) != 1) - LOGE(TAG, "can't send data to active_sfd"); - } - break; /*** - * AT command mode + * data mode */ - case cmd: - at_cat_c(data); - if (data == 'A') { - at_state = A_recv; - } else { - at_cat_s(CRLF AT_ERROR); - at_cmd[0] = 0; - at_state = cmd; + case intr: + if (data == '+' && strlen(at_buf) < 3) { + at_buf[strlen(at_buf) +1] = 0; + at_buf[strlen(at_buf)] = data; + at_t1 = get_clock_us(); + return; + } else { + if (telnet != NULL) + telnet_send(telnet, at_buf, strlen(at_buf)); + else { + if (write(*active_sfd, at_buf, strlen(at_buf)) + != (ssize_t) strlen(at_buf)) + LOGE(TAG, "can't send at_buf to active_sfd"); } - break; - case A_recv: - at_cat_c(data); - if (data == 'T') { - at_state = AT_recv; - } else if (data == '/') { - at_state = AS_recv; - at_cat_s(CR); - strcpy(at_cmd, at_prev); - if (process_at_cmd()) { - at_cat_s(at_err); - } else { - at_cat_s(LF AT_OK); - } - at_state = cmd; - } else { - at_cat_s(CRLF AT_ERROR); - at_cmd[0] = 0; - at_state = cmd; - } - break; - case AT_recv: - at_cat_c(data); - if (data == '\r') { - at_state = cmd; - if (process_at_cmd()) { - at_cat_s(at_err); - } else { - at_cat_s(LF AT_OK); - } - } - break; - case AS_recv: - LOGE(TAG, "A/: Didn't expect to get here"); - break; - default: - LOGE(TAG, "AT statemachine unknown [%d]", at_state); - break; + + at_state = dat; + } + /*** + * NO break; + * Intentional fallthrough here. + */ + /* fall through */ + case dat: + at_t2 = get_clock_us(); + tdiff = (at_t2 - at_t1) / 1000000; + + if (data == '+' && (tdiff > 0) && !daemon_f) { + at_buf[0] = data; + at_buf[1] = 0; + at_out = at_buf; + at_state = intr; + return; + } + if (telnet != NULL) + telnet_send(telnet, (char *) &data, 1); + else { + if (write(*active_sfd, (char *) &data, 1) != 1) + LOGE(TAG, "can't send data to active_sfd"); + } + break; + /*** + * AT command mode + */ + case cmd: + at_cat_c(data); + if (data == 'A') + at_state = A_recv; + else { + at_cat_s(CRLF AT_ERROR); + at_cmd[0] = 0; + at_state = cmd; + } + break; + case A_recv: + at_cat_c(data); + if (data == 'T') + at_state = AT_recv; + else if (data == '/') { + at_state = AS_recv; + at_cat_s(CR); + strcpy(at_cmd, at_prev); + if (process_at_cmd()) + at_cat_s(at_err); + else + at_cat_s(LF AT_OK); + at_state = cmd; + } else { + at_cat_s(CRLF AT_ERROR); + at_cmd[0] = 0; + at_state = cmd; + } + break; + case AT_recv: + at_cat_c(data); + if (data == '\r') { + at_state = cmd; + if (process_at_cmd()) + at_cat_s(at_err); + else + at_cat_s(LF AT_OK); + } + break; + case AS_recv: + LOGE(TAG, "A/: Didn't expect to get here"); + break; + default: + LOGE(TAG, "AT statemachine unknown [%d]", at_state); + break; } - if (at_state == dat) at_t1 = get_clock_us(); + if (at_state == dat) + at_t1 = get_clock_us(); } -int modem_device_carrier(int i) { - UNUSED(i); +bool modem_device_carrier(int i) +{ + UNUSED(i); - return carrier_detect; + return carrier_detect; } -void modem_device_init(void) { - if (*active_sfd) { - close_socket(); - } - if (answer_sfd) { - active_sfd = &answer_sfd; - close_socket(); - active_sfd = &sfd; +void modem_device_init(void) +{ + if (*active_sfd) + close_socket(); + if (answer_sfd) { + active_sfd = &answer_sfd; + close_socket(); + active_sfd = &sfd; - } - at_state = cmd; + } + at_state = cmd; #ifdef MODEM_NVRAM - int tmp_reg; - for (tmp_reg = 0; tmp_reg < MAX_REG_NUM; tmp_reg++) { - s_reg[tmp_reg] = Modem_nvramReadSreg(tmp_reg, s_reg_defaults[tmp_reg]); - } - Modem_nvramReadEnv("TERM"); - Modem_nvramReadEnv("MODEM.init"); + int tmp_reg; + for (tmp_reg = 0; tmp_reg < MAX_REG_NUM; tmp_reg++) + s_reg[tmp_reg] = Modem_nvramReadSreg(tmp_reg, s_reg_defaults[tmp_reg]); + Modem_nvramReadEnv("TERM"); + Modem_nvramReadEnv("MODEM.init"); #else - memcpy(s_reg, s_reg_defaults, sizeof(s_reg_defaults)); + memcpy(s_reg, s_reg_defaults, sizeof(s_reg_defaults)); #endif - char *modem_init_string; - if ((modem_init_string = getenv("MODEM.init")) != NULL) { - LOG(TAG, "MODEM.init string: %s\r\n", modem_init_string); - while (*modem_init_string) { - modem_device_send(0, *modem_init_string++); - } - modem_device_send(0, '\r'); - while (modem_device_poll(0)) { - modem_device_get(0); - } - } + char *modem_init_string; + if ((modem_init_string = getenv("MODEM.init")) != NULL) { + LOG(TAG, "MODEM.init string: %s\r\n", modem_init_string); + while (*modem_init_string) + modem_device_send(0, *modem_init_string++); + modem_device_send(0, '\r'); + while (modem_device_poll(0)) + modem_device_get(0); + } #ifdef MODEM_UART - /* set/clear UART flow control based on S39 */ - Modem_setFlowControl(s_reg[SREG_FLOW_CTRL]); + /* set/clear UART flow control based on S39 */ + Modem_setFlowControl(s_reg[SREG_FLOW_CTRL]); #endif } diff --git a/iodevices/generic-at-modem.h b/iodevices/generic-at-modem.h index e6379f3c..cf6eb8db 100644 --- a/iodevices/generic-at-modem.h +++ b/iodevices/generic-at-modem.h @@ -17,11 +17,11 @@ #ifndef GENERIC_AT_MODEM_INC #define GENERIC_AT_MODEM_INC -extern int modem_device_alive(int i); +extern bool modem_device_alive(int i); extern int modem_device_poll(int i); extern int modem_device_get(int i); extern void modem_device_send(int i, char data); -extern int modem_device_carrier(int i); +extern bool modem_device_carrier(int i); extern void modem_device_init(void); #define DEV_SIO2B 0 diff --git a/iodevices/imsai-hal.c b/iodevices/imsai-hal.c index 849ff47c..48bdbb1e 100644 --- a/iodevices/imsai-hal.c +++ b/iodevices/imsai-hal.c @@ -1,14 +1,14 @@ - /* - * imsai-hal.c - * - * Copyright (C) 2021 by David McNaiughton - * - * IMSAI SIO-2 hardware abstraction layer - * - * History: - * 1-JUL-2021 1.0 Initial Release - * - */ +/* +* imsai-hal.c +* +* Copyright (C) 2021 by David McNaiughton +* +* IMSAI SIO-2 hardware abstraction layer +* +* History: +* 1-JUL-2021 1.0 Initial Release +* +*/ #include #include @@ -39,192 +39,223 @@ static const char *TAG = "HAL"; /* -------------------- NULL device HAL -------------------- */ -static int null_alive(void) { - return 1; /* NULL is always alive */ +static bool null_alive(void) +{ + return true; /* NULL is always alive */ } + #if !defined(HAS_NETSERVER) || !defined(HAS_MODEM) -static int null_dead(void) { - return 0; /* NULL is always dead */ +static bool null_dead(void) +{ + return false; /* NULL is always dead */ } #endif -static void null_status(BYTE *stat) { - UNUSED(stat); - return; +static void null_status(BYTE *stat) +{ + UNUSED(stat); + + return; } -static int null_in(void) { - return -1; + +static int null_in(void) +{ + return -1; } -static void null_out(BYTE data) { - UNUSED(data); - return; +static void null_out(BYTE data) +{ + UNUSED(data); + + return; } -static int null_cd(void) { - return 0; + +static bool null_cd(void) +{ + return false; } /* -------------------- VIOKBD HAL -------------------- */ -static int vio_kbd_alive(void) { +static bool vio_kbd_alive(void) +{ #ifdef HAS_NETSERVER - if (n_flag) { - /* VIO (webUI) keyboard is only alive if websocket is connected */ - return net_device_alive(DEV_VIO); - } else { + if (n_flag) { + /* VIO (webUI) keyboard is only alive if websocket is connected */ + return net_device_alive(DEV_VIO); + } else { #endif - /* VIO (xterm) keyboard is always alive */ - return 1; + /* VIO (xterm) keyboard is always alive */ + return true; #ifdef HAS_NETSERVER - } + } #endif } + static void vio_kbd_status(BYTE *stat) { - *stat = imsai_vio_kbd_status_in(); + *stat = imsai_vio_kbd_status_in(); } + static int vio_kbd_in(void) { - return imsai_vio_kbd_in(); + return imsai_vio_kbd_in(); } -static void vio_kbd_out(BYTE data) { - UNUSED(data); + +static void vio_kbd_out(BYTE data) +{ + UNUSED(data); } /* -------------------- WEBTTY HAL -------------------- */ #ifdef HAS_NETSERVER -static int net_tty_alive(void) { - if (n_flag) { - /* WEBTTY is only alive if websocket is connected */ - return net_device_alive(DEV_TTY); - } else { - return 0; - } -} -static void net_tty_status(BYTE *stat) { - *stat &= (BYTE)(~3); - if (n_flag) { - if (net_device_poll(DEV_TTY)) { - *stat |= 2; - } - *stat |= 1; - } -} -static int net_tty_in(void) { - if (n_flag) { - return net_device_get(DEV_TTY); - } else { - return -1; - } -} -static void net_tty_out(BYTE data) { - if (n_flag) { - net_device_send(DEV_TTY, (char *)&data, 1); - } + +static bool net_tty_alive(void) +{ + if (n_flag) { + /* WEBTTY is only alive if websocket is connected */ + return net_device_alive(DEV_TTY); + } else + return false; } -#endif + +static void net_tty_status(BYTE *stat) +{ + *stat &= (BYTE) (~3); + if (n_flag) { + if (net_device_poll(DEV_TTY)) + *stat |= 2; + *stat |= 1; + } +} + +static int net_tty_in(void) +{ + if (n_flag) + return net_device_get(DEV_TTY); + else + return -1; +} + +static void net_tty_out(BYTE data) +{ + if (n_flag) + net_device_send(DEV_TTY, (char *)&data, 1); +} + +#endif /* HAS_NETSERVER */ /* -------------------- WEBPTR HAL -------------------- */ #ifdef HAS_NETSERVER -static int net_ptr_alive(void) { - if (n_flag) { - /* WEBPTR is only alive if websocket is connected */ - return net_device_alive(DEV_PTR); - } else { - return 0; - } -} -static void net_ptr_status(BYTE *stat) { - *stat &= (BYTE)(~3); - if (n_flag) { - if (net_device_poll(DEV_PTR)) { - *stat |= 2; - } - *stat |= 1; - } -} -static int net_ptr_in(void) { - if (n_flag) { - return net_device_get(DEV_PTR); - } else { - return -1; - } -} -static void net_ptr_out(BYTE data) { - if (n_flag) { - net_device_send(DEV_PTR, (char *)&data, 1); - } + +static bool net_ptr_alive(void) +{ + if (n_flag) { + /* WEBPTR is only alive if websocket is connected */ + return net_device_alive(DEV_PTR); + } else + return false; } -#endif + +static void net_ptr_status(BYTE *stat) +{ + *stat &= (BYTE) (~3); + if (n_flag) { + if (net_device_poll(DEV_PTR)) + *stat |= 2; + *stat |= 1; + } +} + +static int net_ptr_in(void) +{ + if (n_flag) + return net_device_get(DEV_PTR); + else + return -1; +} + +static void net_ptr_out(BYTE data) +{ + if (n_flag) + net_device_send(DEV_PTR, (char *)&data, 1); +} + +#endif /* HAS_NETSERVER */ /* -------------------- STDIO HAL -------------------- */ -static int stdio_alive(void) { - return 1; /* STDIO is always alive */ -} -static void stdio_status(BYTE *stat) { - struct pollfd p[1]; - - p[0].fd = fileno(stdin); - p[0].events = POLLIN; - p[0].revents = 0; - poll(p, 1, 0); - *stat &= (BYTE)(~3); - if (p[0].revents & POLLIN) - *stat |= 2; - if (p[0].revents & POLLNVAL) { - LOGE(TAG, "can't use terminal, try 'screen simulation ...'"); - cpu_error = IOERROR; - cpu_state = ST_STOPPED; - } - *stat |= 1; - -} -static int stdio_in(void) { - int data; +static bool stdio_alive(void) +{ + return true; /* STDIO is always alive */ +} + +static void stdio_status(BYTE *stat) +{ + struct pollfd p[1]; + + p[0].fd = fileno(stdin); + p[0].events = POLLIN; + p[0].revents = 0; + poll(p, 1, 0); + *stat &= (BYTE) (~3); + if (p[0].revents & POLLIN) + *stat |= 2; + if (p[0].revents & POLLNVAL) { + LOGE(TAG, "can't use terminal, try 'screen simulation ...'"); + cpu_error = IOERROR; + cpu_state = ST_STOPPED; + } + *stat |= 1; +} + +static int stdio_in(void) +{ + int data; struct pollfd p[1]; again: - /* if no input waiting return last */ - p[0].fd = fileno(stdin); - p[0].events = POLLIN; - p[0].revents = 0; - poll(p, 1, 0); - if (!(p[0].revents & POLLIN)) - return -1; - - if (read(fileno(stdin), &data, 1) == 0) { - /* try to reopen tty, input redirection exhausted */ - if (freopen("/dev/tty", "r", stdin) == NULL) - LOGE(TAG, "can't reopen /dev/tty"); - set_unix_terminal(); - goto again; - } - - return data; -} -static void stdio_out(BYTE data) { + /* if no input waiting return last */ + p[0].fd = fileno(stdin); + p[0].events = POLLIN; + p[0].revents = 0; + poll(p, 1, 0); + if (!(p[0].revents & POLLIN)) + return -1; + if (read(fileno(stdin), &data, 1) == 0) { + /* try to reopen tty, input redirection exhausted */ + if (freopen("/dev/tty", "r", stdin) == NULL) + LOGE(TAG, "can't reopen /dev/tty"); + set_unix_terminal(); + goto again; + } + + return data; +} + +static void stdio_out(BYTE data) +{ again: - if (write(fileno(stdout), (char *) &data, 1) != 1) { - if (errno == EINTR) { - goto again; - } else { - LOGE(TAG, "can't write data"); - cpu_error = IOERROR; - cpu_state = ST_STOPPED; - } - } + if (write(fileno(stdout), (char *) &data, 1) != 1) { + if (errno == EINTR) + goto again; + else { + LOGE(TAG, "can't write data"); + cpu_error = IOERROR; + cpu_state = ST_STOPPED; + } + } } /* -------------------- SOCKET SERVER HAL -------------------- */ -static int scktsrv_alive(void) { - - struct pollfd p[1]; +static bool scktsrv_alive(void) +{ + struct pollfd p[1]; /* if socket not connected check for a new connection */ if (ucons[0].ssc == 0) { @@ -234,19 +265,19 @@ static int scktsrv_alive(void) { poll(p, 1, 0); /* accept a new connection */ if (p[0].revents) { - if ((ucons[0].ssc = accept(ucons[0].ss, NULL, - NULL)) == -1) { + if ((ucons[0].ssc = accept(ucons[0].ss, NULL, NULL)) == -1) { LOGW(TAG, "can't accept server socket"); ucons[0].ssc = 0; } } } - return ucons[0].ssc; /* SCKTSRV is alive if there is an open socket */ + return ucons[0].ssc != 0; /* SCKTSRV is alive if there is an open socket */ } -static void scktsrv_status(BYTE *stat) { - struct pollfd p[1]; +static void scktsrv_status(BYTE *stat) +{ + struct pollfd p[1]; /* if socket is connected check for I/O */ if (ucons[0].ssc != 0) { @@ -254,17 +285,18 @@ static void scktsrv_status(BYTE *stat) { p[0].events = POLLIN | POLLOUT; p[0].revents = 0; poll(p, 1, 0); - *stat &= (BYTE)(~3); + *stat &= (BYTE) (~3); if (p[0].revents & POLLIN) *stat |= 2; if (p[0].revents & POLLOUT) *stat |= 1; - } else { + } else *stat = 0; - } } -static int scktsrv_in(void) { - BYTE data; + +static int scktsrv_in(void) +{ + BYTE data; struct pollfd p[1]; /* if not connected return last */ @@ -286,10 +318,11 @@ static int scktsrv_in(void) { return -1; } - return data; + return data; } -static void scktsrv_out(BYTE data) { +static void scktsrv_out(BYTE data) +{ struct pollfd p[1]; /* return if socket not connected */ @@ -309,9 +342,9 @@ static void scktsrv_out(BYTE data) { again: if (write(ucons[0].ssc, &data, 1) != 1) { - if (errno == EINTR) { + if (errno == EINTR) goto again; - } else { + else { close(ucons[0].ssc); ucons[0].ssc = 0; } @@ -321,225 +354,234 @@ static void scktsrv_out(BYTE data) { /* -------------------- MODEM HAL -------------------- */ #ifdef HAS_MODEM + #include "generic-at-modem.h" -static int modem_alive(void) { - return modem_device_alive(0); +static bool modem_alive(void) +{ + return modem_device_alive(0); } -static void modem_status(BYTE *stat) { - *stat &= (BYTE)(~3); - if (modem_device_poll(0)) { - *stat |= 2; - } - *stat |= 1; + +static void modem_status(BYTE *stat) +{ + *stat &= (BYTE) (~3); + if (modem_device_poll(0)) + *stat |= 2; + *stat |= 1; } -static int modem_in(void) { - return modem_device_get(0); + +static int modem_in(void) +{ + return modem_device_get(0); } -static void modem_out(BYTE data){ - modem_device_send(0, (char) data); + +static void modem_out(BYTE data) +{ + modem_device_send(0, (char) data); } -static int modem_cd(void) { - return modem_device_carrier(0); + +static bool modem_cd(void) +{ + return modem_device_carrier(0); } -#endif /*HAS_MODEM*/ + +#endif /* HAS_MODEM */ /* -------------------- HAL port/device mappings -------------------- */ -const char *sio_port_name[MAX_SIO_PORT] = { "SIO1.portA", "SIO1.portB", "SIO2.portA", "SIO2.portB" }; +const char *sio_port_name[MAX_SIO_PORT] = + { "SIO1.portA", "SIO1.portB", "SIO2.portA", "SIO2.portB" }; static const hal_device_t devices[] = { #ifdef HAS_NETSERVER - { "WEBTTY", 0, net_tty_alive, net_tty_status, net_tty_in, net_tty_out, null_cd }, - { "WEBPTR", 0, net_ptr_alive, net_ptr_status, net_ptr_in, net_ptr_out, null_cd }, + { "WEBTTY", false, net_tty_alive, net_tty_status, net_tty_in, net_tty_out, null_cd }, + { "WEBPTR", false, net_ptr_alive, net_ptr_status, net_ptr_in, net_ptr_out, null_cd }, #else - { "WEBTTY", 0, null_dead, null_status, null_in, null_out, null_cd }, - { "WEBPTR", 0, null_dead, null_status, null_in, null_out, null_cd }, + { "WEBTTY", false, null_dead, null_status, null_in, null_out, null_cd }, + { "WEBPTR", false, null_dead, null_status, null_in, null_out, null_cd }, #endif - { "STDIO", 0, stdio_alive, stdio_status, stdio_in, stdio_out, null_cd }, - { "SCKTSRV", 0, scktsrv_alive, scktsrv_status, scktsrv_in, scktsrv_out, null_cd }, + { "STDIO", false, stdio_alive, stdio_status, stdio_in, stdio_out, null_cd }, + { "SCKTSRV", false, scktsrv_alive, scktsrv_status, scktsrv_in, scktsrv_out, null_cd }, #ifdef HAS_MODEM - { "MODEM", 0, modem_alive, modem_status, modem_in, modem_out, modem_cd }, + { "MODEM", false, modem_alive, modem_status, modem_in, modem_out, modem_cd }, #else - { "MODEM", 0, null_dead, null_status, null_in, null_out, null_cd }, + { "MODEM", false, null_dead, null_status, null_in, null_out, null_cd }, #endif - { "VIOKBD", 0, vio_kbd_alive, vio_kbd_status, vio_kbd_in, vio_kbd_out, null_cd }, - { "", 0, null_alive, null_status, null_in, null_out, null_cd } + { "VIOKBD", false, vio_kbd_alive, vio_kbd_status, vio_kbd_in, vio_kbd_out, null_cd }, + { "", false, null_alive, null_status, null_in, null_out, null_cd } }; hal_device_t sio[MAX_SIO_PORT][MAX_HAL_DEV]; /* -------------------- HAL utility functions -------------------- */ -static void hal_report(void) { - - int i, j; - - LOG(TAG, "\r\nSIO PORT MAP:\r\n"); - - for (i = 0; i < MAX_SIO_PORT; i++) { - - LOG(TAG, "%s = ", sio_port_name[i]); - j = 0; - - while (sio[i][j].name && j < MAX_HAL_DEV) { - - LOG(TAG, "%s%s", sio[i][j].name, (sio[i][j].fallthrough?"+":" ")); - - j++; - } - LOG(TAG, "\r\n"); - } +static void hal_report(void) +{ + int i, j; + + LOG(TAG, "\r\nSIO PORT MAP:\r\n"); + for (i = 0; i < MAX_SIO_PORT; i++) { + LOG(TAG, "%s = ", sio_port_name[i]); + j = 0; + while (sio[i][j].name && j < MAX_HAL_DEV) { + LOG(TAG, "%s%s", sio[i][j].name, (sio[i][j].fallthrough ? "+" : " ")); + j++; + } + LOG(TAG, "\r\n"); + } } -static int hal_find_device(char *dev) { +static int hal_find_device(char *dev) +{ + int i = 0; - int i=0; - while (i < MAX_HAL_DEV) { - if (!strcmp(dev, devices[i].name)) { - return i; - } - i++; - } - return -1; + while (i < MAX_HAL_DEV) { + if (!strcmp(dev, devices[i].name)) + return i; + i++; + } + return -1; } -static void hal_init(void) { - - int i, j, d; - char *setting; - char match[80]; - char *dev; - - /** - * Initialize HAL with default configuration, as follows: - * - * SIO1.portA.device=WEBTTY,STDIO - * SIO1.portB.device=VIOKBD - * SIO2.portA.device=SCKTSRV - * SIO2.portB.device=MODEM - * - * Notes: - * - all ports end with NULL and that is always alive - * - the first HAL device in the list that is alive will service the request - */ - sio[0][0] = devices[WEBTTYDEV]; - sio[0][1] = devices[STDIODEV]; - sio[0][2] = devices[NULLDEV]; - - sio[1][0] = devices[VIOKBD]; - sio[1][1] = devices[NULLDEV]; - - sio[2][0] = devices[WEBPTRDEV]; - sio[2][1] = devices[SCKTSRVDEV]; - sio[2][2] = devices[NULLDEV]; - - sio[3][0] = devices[MODEMDEV]; - sio[3][1] = devices[NULLDEV]; - - for (i = 0; i < MAX_SIO_PORT; i++) { - - j = 0; - strcpy(match, sio_port_name[i]); - strcat(match, ".device"); - - if ((setting = getenv(match)) != NULL) { - LOGI(TAG, "%s = %s", match, setting); - - strcpy(match, setting); - - dev = strtok(match, ",\r"); - while (dev) { - - char k = dev[strlen(dev) - 1]; - int fallthrough = 0; - if (k == '+') { - dev[strlen(dev) - 1] = 0; - fallthrough = 1; - } - - d = hal_find_device(dev); - LOGI(TAG, "\tAdding %s to %s", dev, sio_port_name[i]); - - if (d >= 0) { - memcpy(&sio[i][j], &devices[d], sizeof(hal_device_t)); - sio[i][j].fallthrough = fallthrough; - j++; - } - dev = strtok(NULL, ",\r"); - } - memcpy(&sio[i][j], &devices[NULLDEV], sizeof(hal_device_t)); - } - } +static void hal_init(void) +{ + int i, j, d; + char *setting; + char match[80]; + char *dev; + + /** + * Initialize HAL with default configuration, as follows: + * + * SIO1.portA.device=WEBTTY,STDIO + * SIO1.portB.device=VIOKBD + * SIO2.portA.device=SCKTSRV + * SIO2.portB.device=MODEM + * + * Notes: + * - all ports end with NULL and that is always alive + * - the first HAL device in the list that is alive will service the request + */ + sio[0][0] = devices[WEBTTYDEV]; + sio[0][1] = devices[STDIODEV]; + sio[0][2] = devices[NULLDEV]; + + sio[1][0] = devices[VIOKBD]; + sio[1][1] = devices[NULLDEV]; + + sio[2][0] = devices[WEBPTRDEV]; + sio[2][1] = devices[SCKTSRVDEV]; + sio[2][2] = devices[NULLDEV]; + + sio[3][0] = devices[MODEMDEV]; + sio[3][1] = devices[NULLDEV]; + + for (i = 0; i < MAX_SIO_PORT; i++) { + j = 0; + strcpy(match, sio_port_name[i]); + strcat(match, ".device"); + + if ((setting = getenv(match)) != NULL) { + LOGI(TAG, "%s = %s", match, setting); + + strcpy(match, setting); + + dev = strtok(match, ",\r"); + while (dev) { + char k = dev[strlen(dev) - 1]; + bool fallthrough = false; + + if (k == '+') { + dev[strlen(dev) - 1] = 0; + fallthrough = true; + } + + d = hal_find_device(dev); + LOGI(TAG, "\tAdding %s to %s", dev, sio_port_name[i]); + + if (d >= 0) { + memcpy(&sio[i][j], &devices[d], sizeof(hal_device_t)); + sio[i][j].fallthrough = fallthrough; + j++; + } + dev = strtok(NULL, ",\r"); + } + memcpy(&sio[i][j], &devices[NULLDEV], sizeof(hal_device_t)); + } + } } -void hal_reset(void) { - hal_init(); - hal_report(); +void hal_reset(void) +{ + hal_init(); + hal_report(); } /* -------------------- HAL - SIO interface -------------------- */ -void hal_status_in(sio_port_t dev, BYTE *stat) { +void hal_status_in(sio_port_t dev, BYTE *stat) +{ + int p = 0; + BYTE s; - int p = 0; - BYTE s; - *stat = 0; + *stat = 0; next: - while(!sio[dev][p].alive()) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!sio[dev][p].alive()) + p++; - sio[dev][p].status(&s); - *stat |= s; + sio[dev][p].status(&s); + *stat |= s; - if (sio[dev][p].fallthrough) { - p++; - goto next; - } + if (sio[dev][p].fallthrough) { + p++; + goto next; + } } -int hal_data_in(sio_port_t dev) { +int hal_data_in(sio_port_t dev) +{ + int p = 0; + int in = 0; - int p = 0; - int in = 0; next: - while(!sio[dev][p].alive()) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!sio[dev][p].alive()) + p++; - in = sio[dev][p].in(); + in = sio[dev][p].in(); - if (in < 0 && sio[dev][p].fallthrough) { - p++; - goto next; - } else { - return in; - } + if (in < 0 && sio[dev][p].fallthrough) { + p++; + goto next; + } else + return in; } -void hal_data_out(sio_port_t dev, BYTE data) { +void hal_data_out(sio_port_t dev, BYTE data) +{ + int p = 0; - int p = 0; next: - while(!sio[dev][p].alive()) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!sio[dev][p].alive()) + p++; sio[dev][p].out(data); - if (sio[dev][p].fallthrough) { - p++; - goto next; - } + if (sio[dev][p].fallthrough) { + p++; + goto next; + } } -int hal_carrier_detect(sio_port_t dev) { +bool hal_carrier_detect(sio_port_t dev) +{ + int p = 0; - int p = 0; - while(!sio[dev][p].alive()) { /* Find the first device that is alive */ - p++; - } + /* Find the first device that is alive */ + while (!sio[dev][p].alive()) + p++; return sio[dev][p].cd(); } diff --git a/iodevices/imsai-hal.h b/iodevices/imsai-hal.h index 4baef04d..906cbc23 100644 --- a/iodevices/imsai-hal.h +++ b/iodevices/imsai-hal.h @@ -16,45 +16,41 @@ #include "sim.h" #include "simdefs.h" -enum sio_port { +typedef enum sio_port { SIO1A, SIO1B, SIO2A, SIO2B, - MAX_SIO_PORT -}; - -typedef enum sio_port sio_port_t; - -enum hal_dev { - WEBTTYDEV, - WEBPTRDEV, - STDIODEV, - SCKTSRVDEV, - MODEMDEV, - VIOKBD, - NULLDEV, - MAX_HAL_DEV -}; - -struct hal_device { - const char *name; - int fallthrough; - int (*alive)(void); - void (*status)(BYTE *stat); - int (*in)(void); - void (*out)(BYTE data); - int (*cd)(void); -}; - -typedef struct hal_device hal_device_t; + MAX_SIO_PORT +} sio_port_t; + +typedef enum hal_dev { + WEBTTYDEV, + WEBPTRDEV, + STDIODEV, + SCKTSRVDEV, + MODEMDEV, + VIOKBD, + NULLDEV, + MAX_HAL_DEV +} hal_dev_t; + +typedef struct hal_device { + const char *name; + bool fallthrough; + bool (*alive)(void); + void (*status)(BYTE *stat); + int (*in)(void); + void (*out)(BYTE data); + bool (*cd)(void); +} hal_device_t; extern void hal_reset(void); extern void hal_status_in(sio_port_t sio, BYTE *stat); extern int hal_data_in(sio_port_t sio); extern void hal_data_out(sio_port_t sio, BYTE data); -extern int hal_carrier_detect(sio_port_t sio); +extern bool hal_carrier_detect(sio_port_t sio); extern const char *sio_port_name[MAX_SIO_PORT]; extern hal_device_t sio[MAX_SIO_PORT][MAX_HAL_DEV]; diff --git a/iodevices/imsai-sio2.c b/iodevices/imsai-sio2.c index a411a79a..5940b8fa 100644 --- a/iodevices/imsai-sio2.c +++ b/iodevices/imsai-sio2.c @@ -438,18 +438,18 @@ void imsai_sio2b_data_out(BYTE data) */ BYTE imsai_sio1_ctl_in(void) { - int cd_a = hal_carrier_detect(SIO1A); - int cd_b = hal_carrier_detect(SIO1B); + bool cd_a = hal_carrier_detect(SIO1A); + bool cd_b = hal_carrier_detect(SIO1B); - return 0b10111011 | (cd_a << 2) | cd_b << 6; + return 0b10111011 | (cd_a ? 4 : 0) | (cd_b ? 64 : 0); } BYTE imsai_sio2_ctl_in(void) { - int cd_a = hal_carrier_detect(SIO2A); - int cd_b = hal_carrier_detect(SIO2B); + bool cd_a = hal_carrier_detect(SIO2A); + bool cd_b = hal_carrier_detect(SIO2B); - return 0b10111011 | (cd_a << 2) | cd_b << 6; + return 0b10111011 | (cd_a ? 4 : 0) | (cd_b ? 64 : 0); } /* diff --git a/iodevices/imsai-vio.c b/iodevices/imsai-vio.c index 19029198..5dbdeb4f 100644 --- a/iodevices/imsai-vio.c +++ b/iodevices/imsai-vio.c @@ -43,6 +43,7 @@ #endif #ifdef HAS_NETSERVER +#include #include "netsrv.h" #endif diff --git a/webfrontend/netsrv.c b/webfrontend/netsrv.c index b7b9284e..ec54722d 100644 --- a/webfrontend/netsrv.c +++ b/webfrontend/netsrv.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -51,21 +53,31 @@ static const char *TAG = "netsrv"; #define MAX_WS_CLIENTS (_DEV_MAX) +typedef struct msgbuf_s { + long mtype; + unsigned char mtext[128]; +} msgbuf_t; + static msgbuf_t msg; -struct { +typedef struct ws_client { + struct mg_connection *conn; + int state; +} ws_client_t; + +static struct { int queue; - ws_client_t ws_client; - void (*cbfunc)(BYTE *); + ws_client_t ws_client; + void (*cbfunc)(BYTE *); } dev[MAX_WS_CLIENTS]; -net_device_t net_device_a[_DEV_MAX] = { +static net_device_t net_device_a[_DEV_MAX] = { DEV_TTY, DEV_TTY2, DEV_TTY3, DEV_LPT, DEV_VIO, DEV_CPA, DEV_DZLR, DEV_88ACC, DEV_D7AIO, DEV_PTR }; -const char *dev_name[] = { +static const char *dev_name[] = { "TTY", "TTY2", "TTY3", @@ -78,7 +90,8 @@ const char *dev_name[] = { "PTR" }; -int last_error = 0; //TODO: replace +static int last_error = 0; //TODO: replace + /* extern int reset; extern int power; @@ -88,70 +101,73 @@ extern void quit_callback(void); /** * Check if a queue is provisioned */ -int net_device_alive(net_device_t device) { - return dev[device].queue; +bool net_device_alive(net_device_t device) +{ + return dev[device].queue >= 0; } -void net_device_service(net_device_t device, void (*cbfunc)(BYTE *data)) { - dev[device].cbfunc = cbfunc; +void net_device_service(net_device_t device, void (*cbfunc)(BYTE *data)) +{ + dev[device].cbfunc = cbfunc; } /** * Assumes the data is: - * TEXT if only a single byte - * BINARY if there are multiple bytes - * TTY & LPT are always BINARY now + * TEXT if only a single byte + * BINARY if there are multiple bytes + * TTY & LPT are always BINARY now */ -void net_device_send(net_device_t device, char *msg, int len) { - +void net_device_send(net_device_t device, char *msg, int len) +{ int op_code; switch (device) { - case DEV_TTY: - case DEV_TTY2: - case DEV_TTY3: - case DEV_PTR: - case DEV_LPT: - op_code = MG_WEBSOCKET_OPCODE_BINARY; - break; - default: - op_code = (len==1)?MG_WEBSOCKET_OPCODE_TEXT:MG_WEBSOCKET_OPCODE_BINARY; - break; + case DEV_TTY: + case DEV_TTY2: + case DEV_TTY3: + case DEV_PTR: + case DEV_LPT: + op_code = MG_WEBSOCKET_OPCODE_BINARY; + break; + default: + op_code = (len == 1) ? MG_WEBSOCKET_OPCODE_TEXT : MG_WEBSOCKET_OPCODE_BINARY; + break; } - if(dev[device].queue) { + if (dev[device].queue >= 0) mg_websocket_write(dev[device].ws_client.conn, - op_code, - msg, len); - } + op_code, + msg, len); } /** * Always removes something from the queue is data waiting * returns: - * char if data is waiting in the queue - * -1 if the queue is not open, is empty + * char if data is waiting in the queue + * -1 if the queue is not open, is empty */ -int net_device_get(net_device_t device) { +int net_device_get(net_device_t device) +{ ssize_t res; msgbuf_t msg; - if (dev[device].queue) { + if (dev[device].queue >= 0) { res = msgrcv(dev[device].queue, &msg, 2, 1L, IPC_NOWAIT); - LOGD(TAG, "GET: device[%d] res[%ld] msg[%ld, %s]", device, res, msg.mtype, msg.mtext); - if (res == 2) { + LOGD(TAG, "GET: device[%d] res[%ld] msg[%ld, %s]", + device, res, msg.mtype, msg.mtext); + if (res == 2) return msg.mtext[0]; - } } return -1; } -int net_device_get_data(net_device_t device, char *dst, int len) { +int net_device_get_data(net_device_t device, char *dst, int len) +{ ssize_t res; msgbuf_t msg; - if (dev[device].queue) { + if (dev[device].queue >= 0) { res = msgrcv(dev[device].queue, &msg, len, 1L, MSG_NOERROR); memcpy((void *)dst, (void *)msg.mtext, res); return res; @@ -163,14 +179,15 @@ int net_device_get_data(net_device_t device, char *dst, int len) { /** * Doesn't remove data from the queue * returns: - * 1 if data is waiting in the queue - * 0 if the queue is not open or is empty + * 1 if data is waiting in the queue + * 0 if the queue is not open or is empty */ -int net_device_poll(net_device_t device) { +int net_device_poll(net_device_t device) +{ ssize_t res; msgbuf_t msg; - if (dev[device].queue) { + if (dev[device].queue >= 0) { res = msgrcv(dev[device].queue, &msg, 1, 1L, IPC_NOWAIT); LOGV(TAG, "POLL: device[%d] res[%ld] errno[%d]", device, res, errno); if (res == -1 && errno == E2BIG) { @@ -181,22 +198,22 @@ int net_device_poll(net_device_t device) { return 0; } -request_t *get_request(const HttpdConnection_t *conn) { +request_t *get_request(const HttpdConnection_t *conn) +{ static request_t req; req.mg = mg_get_request_info(conn); - if (!strcmp(req.mg->request_method, "GET")) { + if (!strcmp(req.mg->request_method, "GET")) req.method = HTTP_GET; - } else if (!strcmp(req.mg->request_method, "POST")) { + else if (!strcmp(req.mg->request_method, "POST")) req.method = HTTP_POST; - } else if (!strcmp(req.mg->request_method, "PUT")) { + else if (!strcmp(req.mg->request_method, "PUT")) req.method = HTTP_PUT; - } else if (!strcmp(req.mg->request_method, "DELETE")) { + else if (!strcmp(req.mg->request_method, "DELETE")) req.method = HTTP_DELETE; - } else { + else req.method = HTTP_UNKNOWN; - } //TODO: split query_string on '&' into args[] - for now its all jammed into args[0] req.args[0] = req.mg->query_string; @@ -226,276 +243,292 @@ static void InformWebsockets(struct mg_context *ctx) mg_lock_context(ctx); for (i = 0; i < MAX_WS_CLIENTS; i++) { - if (dev[i].ws_client.state == 2) { + if (dev[i].ws_client.state == 2) mg_websocket_write(dev[i].ws_client.conn, - MG_WEBSOCKET_OPCODE_TEXT, - text, - strlen(text)); - } + MG_WEBSOCKET_OPCODE_TEXT, + text, + strlen(text)); } mg_unlock_context(ctx); } -struct utsname uts; +static struct utsname uts; -static int SystemHandler(HttpdConnection_t *conn, void *unused) { - request_t *req = get_request(conn); +static int SystemHandler(HttpdConnection_t *conn, void *unused) +{ + request_t *req = get_request(conn); UNUSED(unused); - switch (req->method) { - case HTTP_GET: + switch (req->method) { + case HTTP_GET: LOGD(TAG, "Sending SYS: details."); if (req->args[0] && *req->args[0] == 'm') { + httpdStartResponse(conn, 200); + httpdHeader(conn, "Content-Type", "application/json"); + httpdEndHeaders(conn); - httpdStartResponse(conn, 200); - httpdHeader(conn, "Content-Type", "application/json"); - httpdEndHeaders(conn); + httpdPrintf(conn, "{ \"machine\": \"" MACHINE "\" }"); - httpdPrintf(conn, "{ \"machine\": \"" MACHINE "\" }"); - - return 1; - } + return 1; + } - httpdStartResponse(conn, 200); - httpdHeader(conn, "Content-Type", "application/json"); - httpdEndHeaders(conn); + httpdStartResponse(conn, 200); + httpdHeader(conn, "Content-Type", "application/json"); + httpdEndHeaders(conn); uname(&uts); - httpdPrintf(conn, "{"); + httpdPrintf(conn, "{"); - httpdPrintf(conn, "\"machine\": \"" MACHINE "\", "); + httpdPrintf(conn, "\"machine\": \"" MACHINE "\", "); - httpdPrintf(conn, "\"platform\": \"%s\", ", uts.sysname); + httpdPrintf(conn, "\"platform\": \"%s\", ", uts.sysname); - httpdPrintf(conn, "\"network\": { "); + httpdPrintf(conn, "\"network\": { "); - httpdPrintf(conn, "\"hostname\": \"%s\" ", uts.nodename); + httpdPrintf(conn, "\"hostname\": \"%s\" ", uts.nodename); - httpdPrintf(conn, "}, "); + httpdPrintf(conn, "}, "); - httpdPrintf(conn, "\"paths\": { "); - httpdPrintf(conn, "\"%s\": \"%s\", ", "CONFDIR", confdir); - httpdPrintf(conn, "\"%s\": \"%s\", ", "DISKSDIR", diskdir); - httpdPrintf(conn, "\"%s\": \"%s\" ", "BOOTROM", rompath); - httpdPrintf(conn, "}, "); + httpdPrintf(conn, "\"paths\": { "); + httpdPrintf(conn, "\"%s\": \"%s\", ", "CONFDIR", confdir); + httpdPrintf(conn, "\"%s\": \"%s\", ", "DISKSDIR", diskdir); + httpdPrintf(conn, "\"%s\": \"%s\" ", "BOOTROM", rompath); + httpdPrintf(conn, "}, "); - httpdPrintf(conn, "\"system\": { "); - httpdPrintf(conn, "\"%s\": \"%s\",", "VER", uts.version); - httpdPrintf(conn, "\"%s\": \"%s\",", "MACHINE", uts.machine); - httpdPrintf(conn, "\"free_mem\": %d, ", 0); - httpdPrintf(conn, "\"time\": %ld, ", time(NULL)); - httpdPrintf(conn, "\"uptime\": %d ", 0); - httpdPrintf(conn, "}, "); + httpdPrintf(conn, "\"system\": { "); + httpdPrintf(conn, "\"%s\": \"%s\",", "VER", uts.version); + httpdPrintf(conn, "\"%s\": \"%s\",", "MACHINE", uts.machine); + httpdPrintf(conn, "\"free_mem\": %d, ", 0); + httpdPrintf(conn, "\"time\": %ld, ", time(NULL)); + httpdPrintf(conn, "\"uptime\": %d ", 0); + httpdPrintf(conn, "}, "); - httpdPrintf(conn, "\"state\": { "); - httpdPrintf(conn, "\"last_error\": %d, ", last_error); - httpdPrintf(conn, "\"cpu_error\": %d, ", cpu_error); - httpdPrintf(conn, "\"reset\": %d, ", 0 /*reset*/); - httpdPrintf(conn, "\"power\": %d ", 0 /*power*/); - httpdPrintf(conn, "}, "); + httpdPrintf(conn, "\"state\": { "); + httpdPrintf(conn, "\"last_error\": %d, ", last_error); + httpdPrintf(conn, "\"cpu_error\": %d, ", cpu_error); + httpdPrintf(conn, "\"reset\": %d, ", 0 /*reset*/); + httpdPrintf(conn, "\"power\": %d ", 0 /*power*/); + httpdPrintf(conn, "}, "); - httpdPrintf(conn, "\"about\": { "); - httpdPrintf(conn, "\"%s\": \"%s\", ", "USR_COM", USR_COM); - httpdPrintf(conn, "\"%s\": \"%s\", ", "USR_REL", USR_REL); - httpdPrintf(conn, "\"%s\": \"%s\", ", "USR_CPR", USR_CPR); - httpdPrintf(conn, "\"%s\": \"%s\", ", "cpu", cpu==Z80?"Z80":"I8080"); - if(x_flag) { - httpdPrintf(conn, "\"%s\": \"%s\", ", "bootrom", xfn); - } + httpdPrintf(conn, "\"about\": { "); + httpdPrintf(conn, "\"%s\": \"%s\", ", "USR_COM", USR_COM); + httpdPrintf(conn, "\"%s\": \"%s\", ", "USR_REL", USR_REL); + httpdPrintf(conn, "\"%s\": \"%s\", ", "USR_CPR", USR_CPR); + httpdPrintf(conn, "\"%s\": \"%s\", ", "cpu", cpu == Z80 ? "Z80" : "I8080"); + if (x_flag) + httpdPrintf(conn, "\"%s\": \"%s\", ", "bootrom", xfn); #ifdef FRONTPANEL - if (F_flag) { - httpdPrintf(conn, "\"%s\": %d, ", "cpa", 1); - } + if (F_flag) + httpdPrintf(conn, "\"%s\": %d, ", "cpa", 1); #endif - httpdPrintf(conn, "\"%s\": %d ", "clock", f_value); - httpdPrintf(conn, "} "); + httpdPrintf(conn, "\"%s\": %d ", "clock", f_value); + httpdPrintf(conn, "} "); #ifdef HAS_HAL #ifdef IMSAISIM - httpdPrintf(conn, ", \"hal\": \"SIO Ports\""); - httpdPrintf(conn, ", \"hal_ports\": [ "); - for(int i = 0; i < MAX_SIO_PORT; i++) { - httpdPrintf(conn, "{ "); - httpdPrintf(conn, "\"%s\": \"%s\", ", "name", sio_port_name[i]); - int j = 0; - httpdPrintf(conn, "\"%s\": [ ", "devices"); - while (sio[i][j].name && j < MAX_HAL_DEV) { - if (*sio[i][j].name) - httpdPrintf(conn, "%s\"%s%s\"", - (j==0)?"":", ", - sio[i][j].name, - sio[i][j].fallthrough?"+":"" - ); - j++; - } - httpdPrintf(conn, "] }%s ", (i < (MAX_SIO_PORT-1))?",":""); - } - httpdPrintf(conn, "]"); + httpdPrintf(conn, ", \"hal\": \"SIO Ports\""); + httpdPrintf(conn, ", \"hal_ports\": [ "); + for (int i = 0; i < MAX_SIO_PORT; i++) { + httpdPrintf(conn, "{ "); + httpdPrintf(conn, "\"%s\": \"%s\", ", "name", sio_port_name[i]); + + int j = 0; + httpdPrintf(conn, "\"%s\": [ ", "devices"); + while (sio[i][j].name && j < MAX_HAL_DEV) { + if (*sio[i][j].name) + httpdPrintf(conn, "%s\"%s%s\"", + (j == 0) ? "" : ", ", + sio[i][j].name, + sio[i][j].fallthrough ? "+" : "" + ); + j++; + } + httpdPrintf(conn, "] }%s ", (i < (MAX_SIO_PORT - 1)) ? "," : ""); + } + httpdPrintf(conn, "]"); #endif #ifdef CROMEMCOSIM - httpdPrintf(conn, ", \"hal\": \"TU-ART Devices\""); - httpdPrintf(conn, ", \"hal_ports\": [ "); - for(int i = 0; i < MAX_TUART_PORT; i++) { - httpdPrintf(conn, "{ "); - httpdPrintf(conn, "\"%s\": \"%s\", ", "name", tuart_port_name[i]); - int j = 0; - httpdPrintf(conn, "\"%s\": [ ", "devices"); - while (tuart[i][j].name && j < MAX_HAL_DEV) { - if (*tuart[i][j].name) - httpdPrintf(conn, "%s\"%s%s\"", - (j==0)?"":", ", - tuart[i][j].name, - tuart[i][j].fallthrough?"+":"" - ); - j++; - } - httpdPrintf(conn, "] }%s ", (i < (MAX_TUART_PORT-1))?",":""); - } - httpdPrintf(conn, "]"); + httpdPrintf(conn, ", \"hal\": \"TU-ART Devices\""); + httpdPrintf(conn, ", \"hal_ports\": [ "); + for (int i = 0; i < MAX_TUART_PORT; i++) { + httpdPrintf(conn, "{ "); + httpdPrintf(conn, "\"%s\": \"%s\", ", "name", tuart_port_name[i]); + + int j = 0; + httpdPrintf(conn, "\"%s\": [ ", "devices"); + while (tuart[i][j].name && j < MAX_HAL_DEV) { + if (*tuart[i][j].name) + httpdPrintf(conn, "%s\"%s%s\"", + (j == 0) ? "" : ", ", + tuart[i][j].name, + tuart[i][j].fallthrough ? "+" : "" + ); + j++; + } + httpdPrintf(conn, "] }%s ", (i < (MAX_TUART_PORT - 1)) ? "," : ""); + } + httpdPrintf(conn, "]"); #endif #endif #ifdef HAS_CONFIG - httpdPrintf(conn, ", \"memmap\": [ "); + httpdPrintf(conn, ", \"memmap\": [ "); + + for (int i = 0; i < MAXMEMMAP; i++) { + if (memconf[M_value][i].size) { + if (i > 0) + httpdPrintf(conn, ", "); + httpdPrintf(conn, "{ \"type\": \"%s\"", + (memconf[M_value][i].type == MEM_RW) ? "RAM" : "ROM"); + httpdPrintf(conn, ", \"from\": %d", + memconf[M_value][i].spage << 8); + httpdPrintf(conn, ", \"to\": %d", + ((memconf[M_value][i].spage << 8) + + (memconf[M_value][i].size << 8) - 1)); + if (memconf[M_value][i].type == MEM_RO + && memconf[M_value][i].rom_file) + httpdPrintf(conn, ", \"file\": \"%s\"", + memconf[M_value][i].rom_file); + httpdPrintf(conn, "}"); + } + } - for (int i=0; i < MAXMEMMAP; i++) { - if (memconf[M_value][i].size) { + httpdPrintf(conn, "]"); + httpdPrintf(conn, ", \"memextra\": [ "); - if (i > 0) httpdPrintf(conn, ", "); - httpdPrintf(conn, "{ \"type\": \"%s\"", (memconf[M_value][i].type==MEM_RW)?"RAM":"ROM"); - httpdPrintf(conn, ", \"from\": %d", memconf[M_value][i].spage << 8); - httpdPrintf(conn, ", \"to\": %d", (memconf[M_value][i].spage << 8) + (memconf[M_value][i].size << 8) - 1); - if (memconf[M_value][i].type==MEM_RO && memconf[M_value][i].rom_file) - httpdPrintf(conn, ", \"file\": \"%s\"", memconf[M_value][i].rom_file); - httpdPrintf(conn, "}"); - } - } + if (boot_switch[M_value]) + httpdPrintf(conn, "\"Power-on jump address %04XH\", ", + boot_switch[M_value]); + if (R_flag) + httpdPrintf(conn, "\"%s\", ", BANKED_ROM_MSG); - httpdPrintf(conn, "]"); + if (num_banks) + httpdPrintf(conn, "\"MMU has %d additional RAM banks of %d KB\",", + num_banks, SEGSIZ >> 10); - httpdPrintf(conn, ", \"memextra\": [ "); - - if (boot_switch[M_value]) { - httpdPrintf(conn, "\"Power-on jump address %04XH\", ", boot_switch[M_value]); - } - if (R_flag) { - httpdPrintf(conn, "\"%s\", ", BANKED_ROM_MSG); - } - - if (num_banks) { - httpdPrintf(conn, "\"MMU has %d additional RAM banks of %d KB\",", num_banks, SEGSIZ >> 10); - } - - httpdPrintf(conn, " \"\" ]"); + httpdPrintf(conn, " \"\" ]"); #endif - { - int i=0, o=0; - const char *t1, *t2; - extern char **environ; - char buf[2048]; - - httpdPrintf(conn, ", \"env\": { "); - while(environ[i] != NULL) { - strcpy(buf, environ[i]); - t1 = strtok(buf, "="); - t2 = strtok(NULL, "\0"); + { + int i = 0, o = 0; + const char *t1, *t2; + extern char **environ; + char buf[2048]; + + httpdPrintf(conn, ", \"env\": { "); + while (environ[i] != NULL) { + strcpy(buf, environ[i]); + t1 = strtok(buf, "="); + t2 = strtok(NULL, "\0"); #define BULLET "\xE2\x80\xA2" - if(!strcmp(t1, "PASSWORD") && (getenv("WIFI.password.hide") != NULL)) - t2 = BULLET BULLET BULLET BULLET BULLET BULLET BULLET BULLET; - /* Filter out only TERM and non-shell environment variables of the form '*.*' ie. contain '.' */ - if(!strcmp(t1, "TERM") || index(t1, '.')) - httpdPrintf(conn, "%s \"%s\": \"%s\" ", (o++)==0?"":",", t1, (t2==NULL)?"":t2); - i++; - } - httpdPrintf(conn, "} "); - } - - httpdPrintf(conn, "}"); + if (!strcmp(t1, "PASSWORD") + && (getenv("WIFI.password.hide") != NULL)) + t2 = BULLET BULLET BULLET BULLET + BULLET BULLET BULLET BULLET; + /* Filter out only TERM and non-shell environment + variables of the form '*.*' ie. contain '.' */ + if (!strcmp(t1, "TERM") || strchr(t1, '.')) + httpdPrintf(conn, "%s \"%s\": \"%s\" ", + (o++) == 0 ? "" : ",", + t1, (t2 == NULL) ? "" : t2); + i++; + } + httpdPrintf(conn, "} "); + } + + httpdPrintf(conn, "}"); break; - case HTTP_DELETE: - httpdStartResponse(conn, 205); + case HTTP_DELETE: + httpdStartResponse(conn, 205); httpdEndHeaders(conn); //TODO: make this a bit smarter // quit_callback(); break; default: httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' - httpdEndHeaders(conn); - break; + httpdEndHeaders(conn); + break; } return 1; } -int DirectoryHandler(HttpdConnection_t *conn, void *path) { - request_t *req = get_request(conn); - struct dirent *pDirent; - DIR *pDir; - int i = 0; - struct stat sb; - char fullpath[MAX_LFN]; - bool showSize = false; - - if (req->args[0] && *req->args[0] == 'S') { - showSize = true; - } - - switch (req->method) { - case HTTP_GET: - pDir = opendir ((char *)path); - if (pDir == NULL) { - httpdStartResponse(conn, 404); //http error code 'Not Found' - httpdEndHeaders(conn); - } else { - httpdStartResponse(conn, 200); - httpdHeader(conn, "Content-Type", "application/json"); - httpdEndHeaders(conn); - - httpdPrintf(conn, "["); - - while ((pDirent = readdir(pDir)) != NULL) { - LOGD(TAG, "GET directory: %s type: %d", pDirent->d_name, pDirent->d_type); - snprintf(fullpath, MAX_LFN, "%s/%s", (char *) path, pDirent->d_name); - /* - * not working with some filesystems like Linux xfs, need to use stat() - * if (pDirent->d_type==DT_REG) { - */ - if (stat(fullpath, &sb) != -1 && S_ISREG(sb.st_mode)) { - if (showSize) { - httpdPrintf(conn, "%c{ \"%s\":\"%s\",", (i++ > 0)?',':' ', "filename",pDirent->d_name); - httpdPrintf(conn, "\"%s\":%lld}", "size", (long long) sb.st_size); - } else { - httpdPrintf(conn, "%c\"%s\"", (i++ > 0)?',':' ', pDirent->d_name); +int DirectoryHandler(HttpdConnection_t *conn, void *path) +{ + request_t *req = get_request(conn); + struct dirent *pDirent; + DIR *pDir; + int i = 0; + struct stat sb; + char fullpath[MAX_LFN]; + bool showSize = false; + + if (req->args[0] && *req->args[0] == 'S') + showSize = true; + + switch (req->method) { + case HTTP_GET: + pDir = opendir((char *)path); + if (pDir == NULL) { + httpdStartResponse(conn, 404); //http error code 'Not Found' + httpdEndHeaders(conn); + } else { + httpdStartResponse(conn, 200); + httpdHeader(conn, "Content-Type", "application/json"); + httpdEndHeaders(conn); + + httpdPrintf(conn, "["); + + while ((pDirent = readdir(pDir)) != NULL) { + LOGD(TAG, "GET directory: %s type: %d", + pDirent->d_name, pDirent->d_type); + snprintf(fullpath, MAX_LFN, "%s/%s", + (char *) path, pDirent->d_name); + /* + * not working with some filesystems like Linux xfs, + * need to use stat() + * if (pDirent->d_type==DT_REG) { + */ + if (stat(fullpath, &sb) != -1 && S_ISREG(sb.st_mode)) { + if (showSize) { + httpdPrintf(conn, "%c{ \"%s\":\"%s\",", + (i++ > 0) ? ',' : ' ', + "filename", pDirent->d_name); + httpdPrintf(conn, "\"%s\":%lld}", "size", + (long long) sb.st_size); + } else + httpdPrintf(conn, "%c\"%s\"", + (i++ > 0) ? ',' : ' ', + pDirent->d_name); + } } - } - } - closedir (pDir); - httpdPrintf(conn, "]"); - } + closedir(pDir); + httpdPrintf(conn, "]"); + } break; default: - httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' - httpdEndHeaders(conn); + httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' + httpdEndHeaders(conn); break; - } + } return 1; } -int UploadHandler(HttpdConnection_t *conn, void *path) { - request_t *req = get_request(conn); +int UploadHandler(HttpdConnection_t *conn, void *path) +{ + request_t *req = get_request(conn); int filelen; char output[MAX_LFN]; - switch (req->method) { - case HTTP_PUT: + switch (req->method) { + case HTTP_PUT: strncpy(output, (char *) path, MAX_LFN - 1); output[MAX_LFN - 1] = '\0'; - if (output[strlen(output)-1] != '/') + if (output[strlen(output) -1] != '/') strncat(output, "/", MAX_LFN - strlen(output)); strncat(output, req->args[0], MAX_LFN - strlen(output)); @@ -503,76 +536,77 @@ int UploadHandler(HttpdConnection_t *conn, void *path) { //filelen = 0; filelen = mg_store_body(conn, output); - LOGI(TAG, "%d bytes written to %s, received %d", filelen, output, (int) req->len); - httpdStartResponse(conn, 200); - httpdHeader(conn, "Content-Type", "application/json"); - httpdEndHeaders(conn); + LOGI(TAG, "%d bytes written to %s, received %d", filelen, output, (int) req->len); + httpdStartResponse(conn, 200); + httpdHeader(conn, "Content-Type", "application/json"); + httpdEndHeaders(conn); - httpdPrintf(conn, "{"); - httpdPrintf(conn, "\"filename\": \"%s\", ", output); - httpdPrintf(conn, "\"size\": \"%d\" ", filelen); - httpdPrintf(conn, "}"); + httpdPrintf(conn, "{"); + httpdPrintf(conn, "\"filename\": \"%s\", ", output); + httpdPrintf(conn, "\"size\": \"%d\" ", filelen); + httpdPrintf(conn, "}"); break; default: - httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' - httpdEndHeaders(conn); + httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' + httpdEndHeaders(conn); break; - } + } return 1; } -static int ConfigHandler(HttpdConnection_t *conn, void *path) { - request_t *req = get_request(conn); +static int ConfigHandler(HttpdConnection_t *conn, void *path) +{ + request_t *req = get_request(conn); - switch (req->method) { - case HTTP_GET: - DirectoryHandler(conn, path); + switch (req->method) { + case HTTP_GET: + DirectoryHandler(conn, path); break; - case HTTP_PUT: - UploadHandler(conn, path); + case HTTP_PUT: + UploadHandler(conn, path); break; default: - httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' - httpdEndHeaders(conn); + httpdStartResponse(conn, 405); //http error code 'Method Not Allowed' + httpdEndHeaders(conn); break; - } + } return 1; } -static int WebSocketConnectHandler(const HttpdConnection_t *conn, void *device) { +static int WebSocketConnectHandler(const HttpdConnection_t *conn, void *device) +{ struct mg_context *ctx = mg_get_context(conn); int reject = 1; int res; net_device_t d = *(net_device_t *) device; mg_lock_context(ctx); - if (dev[d].ws_client.conn == NULL) { - dev[d].ws_client.conn = (struct mg_connection *)conn; - dev[d].ws_client.state = 1; - mg_set_user_connection_data(dev[d].ws_client.conn, (void *)(&(dev[d].ws_client))); - - switch (d) { - case DEV_TTY: - case DEV_TTY2: - case DEV_TTY3: - case DEV_PTR: - case DEV_VIO: - case DEV_LPT: - case DEV_DZLR: - case DEV_88ACC: - case DEV_D7AIO: - res = msgget(IPC_PRIVATE, 0644 | IPC_CREAT); //TODO: check flags - if (res > 0) { - dev[d].queue = res; - } else { - perror("msgget()"); - } - break; - default: - break; - } - reject = 0; + if (dev[d].ws_client.conn == NULL) { + dev[d].ws_client.conn = (struct mg_connection *) conn; + dev[d].ws_client.state = 1; + mg_set_user_connection_data(dev[d].ws_client.conn, (void *) (&(dev[d].ws_client))); + + switch (d) { + case DEV_TTY: + case DEV_TTY2: + case DEV_TTY3: + case DEV_PTR: + case DEV_VIO: + case DEV_LPT: + case DEV_DZLR: + case DEV_88ACC: + case DEV_D7AIO: + res = msgget(IPC_PRIVATE, 0644 | IPC_CREAT); //TODO: check flags + if (res < 0) + perror("msgget()"); + else + dev[d].queue = res; + break; + default: + break; } + reject = 0; + } mg_unlock_context(ctx); LOGD(TAG, "Websocket client %s", (reject ? "rejected" : "accepted")); @@ -580,7 +614,8 @@ static int WebSocketConnectHandler(const HttpdConnection_t *conn, void *device) return reject; } -static void WebSocketReadyHandler(HttpdConnection_t *conn, void *device) { +static void WebSocketReadyHandler(HttpdConnection_t *conn, void *device) +{ const char *text = "\r\nConnected to the OSX port of Z80PACK\r\n"; ws_client_t *client = (ws_client_t *) mg_get_user_connection_data(conn); net_device_t d = *(net_device_t *) device; @@ -590,6 +625,7 @@ static void WebSocketReadyHandler(HttpdConnection_t *conn, void *device) { if (d == DEV_VIO) { BYTE mode = dma_read(0xf7ff); + dma_write(0xf7ff, 0x00); sleep_for_ms(100); dma_write(0xf7ff, mode); @@ -601,18 +637,15 @@ static void WebSocketReadyHandler(HttpdConnection_t *conn, void *device) { } static int WebsocketDataHandler(HttpdConnection_t *conn, - int bits, - char *data, - size_t len, - void *device) { - + int bits, char *data, size_t len, void *device) +{ net_device_t d = *(net_device_t *) device; UNUSED(conn); #ifdef DEBUG - fprintf(stdout, "Websocket [%d] got %z bytes of ", (int)device, len); - switch (((unsigned char)bits) & 0x0F) { + fprintf(stdout, "Websocket [%d] got %z bytes of ", (int) device, len); + switch (((unsigned char) bits) & 0x0F) { case MG_WEBSOCKET_OPCODE_CONTINUATION: fprintf(stdout, "continuation"); break; @@ -632,7 +665,7 @@ static int WebsocketDataHandler(HttpdConnection_t *conn, fprintf(stdout, "pong"); break; default: - fprintf(stdout, "unknown(%1xh)", ((unsigned char)bits) & 0x0F); + fprintf(stdout, "unknown(%1xh)", ((unsigned char) bits) & 0x0F); break; } fprintf(stdout, " data:\r\n"); @@ -640,83 +673,82 @@ static int WebsocketDataHandler(HttpdConnection_t *conn, fprintf(stdout, "\r\n"); #endif - if ((((unsigned char)bits) & 0x0F) == MG_WEBSOCKET_OPCODE_BINARY) { - - switch (d) { + if ((((unsigned char) bits) & 0x0F) == MG_WEBSOCKET_OPCODE_BINARY) { + switch (d) { case DEV_D7AIO: if (dev[DEV_D7AIO].cbfunc != NULL && (len == 8)) { - (*(dev[DEV_D7AIO].cbfunc))((BYTE *)data); - } + (*(dev[DEV_D7AIO].cbfunc))((BYTE *) data); + } break; case DEV_PTR: if (len != 1) { - LOGW(TAG, "Websocket received too many [%d] characters", (int)len); + LOGW(TAG, "Websocket received too many [%d] characters", + (int) len); return 0; } - msg.mtype = 1L; - msg.mtext[0] = data[0]; - msg.mtext[1] = '\0'; - if (msgsnd(dev[d].queue, &msg, 2, IPC_NOWAIT)) { - if (errno == EAGAIN) { + msg.mtype = 1L; + msg.mtext[0] = data[0]; + msg.mtext[1] = '\0'; + if (msgsnd(dev[d].queue, &msg, 2, IPC_NOWAIT)) { + if (errno == EAGAIN) { LOGW(TAG, "%s Overflow", dev_name[d]); - } else { + } else perror("msgsnd()"); - } return 0; - }; - break; + }; + break; case DEV_88ACC: // LOGI(TAG, "rec: %d, %d", (int)len, (BYTE)*data); - msg.mtype = 1L; - memcpy(msg.mtext, data, len); + msg.mtype = 1L; + memcpy(msg.mtext, data, len); if (msgsnd(dev[d].queue, &msg, len, IPC_NOWAIT)) { - if (errno == EAGAIN) { + if (errno == EAGAIN) { LOGW(TAG, "%s Overflow", dev_name[d]); - } else { + } else perror("msgsnd()"); - } return 0; - }; + }; break; default: break; }; } - if ((((unsigned char)bits) & 0x0F) == MG_WEBSOCKET_OPCODE_TEXT) { - - switch (d) { + if ((((unsigned char) bits) & 0x0F) == MG_WEBSOCKET_OPCODE_TEXT) { + switch (d) { case DEV_LPT: - if (len == 1 && *data == 'R') lpt_reset(); + if (len == 1 && *data == 'R') + lpt_reset(); break; - case DEV_TTY: - case DEV_TTY2: - case DEV_TTY3: - case DEV_VIO: + case DEV_TTY: + case DEV_TTY2: + case DEV_TTY3: + case DEV_VIO: if (len != 1) { - LOGW(TAG, "Websocket received too many [%d] characters", (int)len); + LOGW(TAG, "Websocket received too many [%d] characters", + (int) len); return 0; } - msg.mtype = 1L; - msg.mtext[0] = data[0]; - msg.mtext[1] = '\0'; - if (msgsnd(dev[d].queue, &msg, 2, IPC_NOWAIT)) { - if (errno == EAGAIN) { + msg.mtype = 1L; + msg.mtext[0] = data[0]; + msg.mtext[1] = '\0'; + if (msgsnd(dev[d].queue, &msg, 2, IPC_NOWAIT)) { + if (errno == EAGAIN) { LOGW(TAG, "%s Overflow", dev_name[d]); - } else { + } else perror("msgsnd()"); - } return 0; - }; - break; - default: - break; + }; + break; + default: + break; }; - } + } return 1; } -static void WebSocketCloseHandler(const HttpdConnection_t *conn, void *device) { +static void WebSocketCloseHandler(const HttpdConnection_t *conn, void *device) +{ struct mg_context *ctx = mg_get_context(conn); ws_client_t *client = (ws_client_t *) mg_get_user_connection_data(conn); net_device_t d = *(net_device_t *) device; @@ -728,18 +760,18 @@ static void WebSocketCloseHandler(const HttpdConnection_t *conn, void *device) { LOGI(TAG, "WS CLIENT CLOSED %s", dev_name[d]); - if (dev[d].queue && msgctl(dev[d].queue, IPC_RMID, NULL) == -1) { + if (dev[d].queue >= 0 && msgctl(dev[d].queue, IPC_RMID, NULL) == -1) perror("msgctl()"); - } - dev[d].queue = 0; LOGD(TAG, "Message queue closed (%d) [%08X]", d, dev[d].queue); + + dev[d].queue = -1; } static struct mg_context *ctx = NULL; -void stop_net_services (void) { - +void stop_net_services(void) +{ if (ctx != NULL) { InformWebsockets(ctx); @@ -752,30 +784,34 @@ void stop_net_services (void) { } } -int start_net_services (int port) { +int start_net_services(int port) +{ //TODO: add config for DOCUMENT_ROOT - char sport[6]; + int i; + char sport[6]; #ifdef SYSDOCROOT struct stat sbuf; #endif const char *options[] = { - "document_root", - DOCUMENT_ROOT, - "listening_ports", - sport, - "request_timeout_ms", - "10000", - "error_log_file", - "error.log", - "websocket_timeout_ms", - "3600000", - "enable_auth_domain_check", - "no", + "document_root", + DOCUMENT_ROOT, + "listening_ports", + sport, + "request_timeout_ms", + "10000", + "error_log_file", + "error.log", + "websocket_timeout_ms", + "3600000", + "enable_auth_domain_check", + "no", "url_rewrite_patterns", - "/" MACHINE "/disks/=./disks/, /" MACHINE "/conf/=./conf/, /" MACHINE "/printer.txt=./printer.txt", - 0}; + "/" MACHINE "/disks/=./disks/, /" MACHINE "/conf/=./conf/, /" + MACHINE "/printer.txt=./printer.txt", + 0 + }; struct mg_callbacks callbacks; @@ -783,20 +819,22 @@ int start_net_services (int port) { struct mg_server_ports ports[32]; int port_cnt, n; int err = 0; - const struct mg_option *opts; + const struct mg_option *opts; #endif + for (i = 0; i < MAX_WS_CLIENTS; i++) + dev[i].queue = -1; + atexit(stop_net_services); snprintf(sport, sizeof(sport), "%d", port); #ifdef SYSDOCROOT - if (stat(DOCUMENT_ROOT, &sbuf) == -1 || !S_ISDIR(sbuf.st_mode)) { + if (stat(DOCUMENT_ROOT, &sbuf) == -1 || !S_ISDIR(sbuf.st_mode)) options[1] = SYSDOCROOT; - } #endif - /* Start CivetWeb web server */ + /* Start CivetWeb web server */ memset(&callbacks, 0, sizeof(callbacks)); callbacks.log_message = log_message; @@ -809,80 +847,80 @@ int start_net_services (int port) { } //TODO: sort out all the paths for the handlers - mg_set_request_handler(ctx, "/system", SystemHandler, 0); - mg_set_request_handler(ctx, "/conf", ConfigHandler, (void *) "conf"); - mg_set_request_handler(ctx, "/library", LibraryHandler, 0); - mg_set_request_handler(ctx, "/disks", DiskHandler, 0); + mg_set_request_handler(ctx, "/system", SystemHandler, 0); + mg_set_request_handler(ctx, "/conf", ConfigHandler, (void *) "conf"); + mg_set_request_handler(ctx, "/library", LibraryHandler, 0); + mg_set_request_handler(ctx, "/disks", DiskHandler, 0); mg_set_websocket_handler(ctx, "/tty", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_TTY]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_TTY]); mg_set_websocket_handler(ctx, "/tty2", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_TTY2]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_TTY2]); mg_set_websocket_handler(ctx, "/tty3", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_TTY3]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_TTY3]); mg_set_websocket_handler(ctx, "/ptr", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_PTR]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_PTR]); mg_set_websocket_handler(ctx, "/lpt", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_LPT]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_LPT]); mg_set_websocket_handler(ctx, "/vio", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_VIO]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_VIO]); mg_set_websocket_handler(ctx, "/dazzler", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_DZLR]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_DZLR]); mg_set_websocket_handler(ctx, "/cpa", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_CPA]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_CPA]); mg_set_websocket_handler(ctx, "/acc", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_88ACC]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_88ACC]); mg_set_websocket_handler(ctx, "/d7aio", - WebSocketConnectHandler, - WebSocketReadyHandler, - WebsocketDataHandler, - WebSocketCloseHandler, - (void *) &net_device_a[DEV_D7AIO]); + WebSocketConnectHandler, + WebSocketReadyHandler, + WebsocketDataHandler, + WebSocketCloseHandler, + (void *) &net_device_a[DEV_D7AIO]); #ifdef DEBUG /* List all listening ports */ @@ -893,4 +931,5 @@ int start_net_services (int port) { return EXIT_SUCCESS; } + #endif /* HAS_NETSERVER */ diff --git a/webfrontend/netsrv.h b/webfrontend/netsrv.h index 528b0f97..dd461715 100644 --- a/webfrontend/netsrv.h +++ b/webfrontend/netsrv.h @@ -13,16 +13,12 @@ /** * This web server module provides... */ -#include -#include -#include - #include "sim.h" #include "simdefs.h" #include "civetweb.h" -enum net_device { +typedef enum net_device { DEV_TTY, DEV_TTY2, DEV_TTY3, @@ -34,21 +30,9 @@ enum net_device { DEV_D7AIO, DEV_PTR, _DEV_MAX -}; - -typedef enum net_device net_device_t; - -typedef struct msgbuf_s { - long mtype; - unsigned char mtext[128]; -} msgbuf_t; +} net_device_t; -typedef struct ws_client { - struct mg_connection *conn; - int state; -} ws_client_t; - -extern int net_device_alive(net_device_t device); +extern bool net_device_alive(net_device_t device); extern void net_device_service(net_device_t device, void (*cbfunc)(BYTE *data)); extern void net_device_send(net_device_t device, char *msg, int len); extern int net_device_get(net_device_t device); @@ -56,26 +40,24 @@ extern int net_device_get_data(net_device_t device, char *dst, int len); extern int net_device_poll(net_device_t device); /* -* convenience macros for http output -*/ + * convenience macros for http output + */ typedef struct mg_connection HttpdConnection_t; -#define httpdPrintf(conn, args...) mg_printf(conn, args) -#define httpdStartResponse(conn, code) mg_printf(conn, "HTTP/1.1 %d OK\r\n", code) -#define httpdHeader(conn, key, val) mg_printf(conn, "%s: %s\r\n", key, val) -#define httpdEndHeaders(conn) mg_printf(conn, "\r\n") +#define httpdPrintf(conn, args...) mg_printf(conn, args) +#define httpdStartResponse(conn, code) mg_printf(conn, "HTTP/1.1 %d OK\r\n", code) +#define httpdHeader(conn, key, val) mg_printf(conn, "%s: %s\r\n", key, val) +#define httpdEndHeaders(conn) mg_printf(conn, "\r\n") #define _HTTP_MAX_ARGS 8 -enum http_method { +typedef enum http_method { HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE, HTTP_UNKNOWN -}; - -typedef enum http_method http_method_t; +} http_method_t; typedef struct request { const struct mg_request_info *mg; @@ -89,7 +71,7 @@ extern request_t *get_request(const HttpdConnection_t *conn); extern int DirectoryHandler(HttpdConnection_t *conn, void *path); extern int UploadHandler(HttpdConnection_t *conn, void *path); -extern void stop_net_services (void); -extern int start_net_services (int port); +extern void stop_net_services(void); +extern int start_net_services(int port); #endif /* !NETSRV_INC */