From 1976675f1eb48093ad9dd625f699ef0833b9530a Mon Sep 17 00:00:00 2001 From: Justin Skists Date: Mon, 21 Aug 2023 12:19:17 +0100 Subject: [PATCH 001/158] RC2014: fuji: implement hashing commands Implement the SHA1/SHA256/SHA512 commands. This has only been compile-tested. --- lib/device/rc2014/fuji.cpp | 347 +++++++++++++++++++++++++++++++++++++ lib/device/rc2014/fuji.h | 19 ++ 2 files changed, 366 insertions(+) diff --git a/lib/device/rc2014/fuji.cpp b/lib/device/rc2014/fuji.cpp index 39f7b4cc2..f55803a19 100644 --- a/lib/device/rc2014/fuji.cpp +++ b/lib/device/rc2014/fuji.cpp @@ -1193,6 +1193,341 @@ void rc2014Fuji::rc2014_base64_decode_output() rc2014_send_complete(); } +void rc2014Fuji::rc2014_hash_input() +{ + Debug_printf("FUJI: HASH INPUT\n"); + + uint16_t len = (cmdFrame.aux2 << 8) | cmdFrame.aux1; + if (!len) + { + Debug_printf("Invalid length. Aborting"); + rc2014_send_error(); + return; + } + + unsigned char *p = (unsigned char *)malloc(len); + if (!p) + { + Debug_printf("Could not allocate %u bytes for buffer. Aborting.\n"); + rc2014_send_error(); + return; + } + + rc2014_send_ack(); + + rc2014_recv_buffer((uint8_t *)p, len); + rc2014_send_ack(); + + base64_buffer += string((const char *)p, len); + + free(p); + + rc2014_send_complete(); +} + +void rc2014Fuji::rc2014_hash_compute() +{ + uint16_t m = hash_mode = cmdFrame.aux1; + + Debug_printf("FUJI: HASH COMPUTE\n"); + + rc2014_send_ack(); + + // Initialize hash context + switch (m) + { + case 0: // md5 + // Not implemented + break; + case 1: // sha1 + mbedtls_sha1_init(&_sha1); + mbedtls_sha1_starts(&_sha1); + break; + case 2: // sha256 + mbedtls_sha256_init(&_sha256); + mbedtls_sha256_starts(&_sha256,0); + break; + case 3: // sha512 + mbedtls_sha512_init(&_sha512); + mbedtls_sha512_starts(&_sha512,0); + break; + } + + // Update + switch (m) + { + case 0: // MD5 + // Not implemented + break; + case 1: // SHA1 + mbedtls_sha1_update(&_sha1, (const unsigned char *)base64_buffer.data(), base64_buffer.size()); + break; + case 2: // SHA256 + mbedtls_sha256_update(&_sha256, (const unsigned char *)base64_buffer.data(), base64_buffer.size()); + break; + case 3: // SHA512 + mbedtls_sha512_update(&_sha512, (const unsigned char *)base64_buffer.data(), base64_buffer.size()); + break; + } + + // Clean up + switch (m) + { + case 0: // MD5 + // Not implemented + break; + case 1: // SHA1 + mbedtls_sha1_finish(&_sha1, _sha1_output); + mbedtls_sha1_free(&_sha1); + break; + case 2: // SHA256 + mbedtls_sha256_finish(&_sha256, _sha256_output); + mbedtls_sha256_free(&_sha256); + break; + case 3: // SHA512 + mbedtls_sha512_finish(&_sha512, _sha512_output); + mbedtls_sha512_free(&_sha512); + break; + } + + base64_buffer.clear(); + base64_buffer.shrink_to_fit(); + + rc2014_send_complete(); +} + +void rc2014Fuji::rc2014_hash_length() +{ + unsigned char r = 0; + uint16_t m = cmdFrame.aux1; + + Debug_printf("FUJI: HASH LENGTH\n"); + + switch (hash_mode) + { + case 0: // MD5 + r = 16; + break; + case 1: // SHA1 + r = 20; + break; + case 2: // SHA256 + r = 32; + break; + case 3: // SHA512 + r = 64; + break; + } + + if (m == 1) // Hex output + m <<= 1; // double it. + + rc2014_send_ack(); + + rc2014_send_buffer((uint8_t *)r, 1); + rc2014_flush(); + rc2014_send_complete(); +} + +void rc2014Fuji::rc2014_hash_output() +{ + uint8_t o[129]; + uint16_t olen=0; + uint16_t m = cmdFrame.aux1; + + Debug_printf("FUJI: HASH OUTPUT\n"); + + memset(o, 0x00, sizeof(o)); + + switch (hash_mode) + { + case 0: // MD5 + olen = 16; + + if (m == 0) + memcpy(o, _md5_output, 16); + else if (m == 1) + { + olen <<= 1; + sprintf((char *)o, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + _md5_output[0], + _md5_output[1], + _md5_output[2], + _md5_output[3], + _md5_output[4], + _md5_output[5], + _md5_output[6], + _md5_output[7], + _md5_output[8], + _md5_output[9], + _md5_output[10], + _md5_output[11], + _md5_output[12], + _md5_output[13], + _md5_output[14], + _md5_output[15]); + } + break; + case 1: // SHA1 + olen = 20; + + if (m == 0) + memcpy(o, _sha1_output, 20); + else if (m == 1) + { + olen <<= 1; + sprintf((char *)o, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + _sha1_output[0], + _sha1_output[1], + _sha1_output[2], + _sha1_output[3], + _sha1_output[4], + _sha1_output[5], + _sha1_output[6], + _sha1_output[7], + _sha1_output[8], + _sha1_output[9], + _sha1_output[10], + _sha1_output[11], + _sha1_output[12], + _sha1_output[13], + _sha1_output[14], + _sha1_output[15], + _sha1_output[16], + _sha1_output[17], + _sha1_output[18], + _sha1_output[19]); + } + break; + case 2: // SHA256 + olen = 32; + + if (m == 0) + memcpy(o, _sha256_output, 32); + else if (m == 1) + { + olen <<= 1; + sprintf((char *)o, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + _sha256_output[0], + _sha256_output[1], + _sha256_output[2], + _sha256_output[3], + _sha256_output[4], + _sha256_output[5], + _sha256_output[6], + _sha256_output[7], + _sha256_output[8], + _sha256_output[9], + _sha256_output[10], + _sha256_output[11], + _sha256_output[12], + _sha256_output[13], + _sha256_output[14], + _sha256_output[15], + _sha256_output[16], + _sha256_output[17], + _sha256_output[18], + _sha256_output[19], + _sha256_output[20], + _sha256_output[21], + _sha256_output[22], + _sha256_output[23], + _sha256_output[24], + _sha256_output[25], + _sha256_output[26], + _sha256_output[27], + _sha256_output[28], + _sha256_output[29], + _sha256_output[30], + _sha256_output[31]); + } + break; + case 3: // SHA512 + olen = 64; + + if (m == 0) + memcpy(o, _sha512_output, 64); + else if (m == 1) + { + olen <<= 1; + sprintf((char *)o, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + _sha256_output[0], + _sha256_output[1], + _sha256_output[2], + _sha256_output[3], + _sha256_output[4], + _sha256_output[5], + _sha256_output[6], + _sha256_output[7], + _sha256_output[8], + _sha256_output[9], + _sha256_output[10], + _sha256_output[11], + _sha256_output[12], + _sha256_output[13], + _sha256_output[14], + _sha256_output[15], + _sha256_output[16], + _sha256_output[17], + _sha256_output[18], + _sha256_output[19], + _sha256_output[20], + _sha256_output[21], + _sha256_output[22], + _sha256_output[23], + _sha256_output[24], + _sha256_output[25], + _sha256_output[26], + _sha256_output[27], + _sha256_output[28], + _sha256_output[29], + _sha256_output[30], + _sha256_output[31], + _sha256_output[32], + _sha256_output[33], + _sha256_output[34], + _sha256_output[35], + _sha256_output[36], + _sha256_output[37], + _sha256_output[38], + _sha256_output[39], + _sha256_output[40], + _sha256_output[41], + _sha256_output[42], + _sha256_output[43], + _sha256_output[44], + _sha256_output[45], + _sha256_output[46], + _sha256_output[47], + _sha256_output[48], + _sha256_output[49], + _sha256_output[50], + _sha256_output[51], + _sha256_output[52], + _sha256_output[53], + _sha256_output[54], + _sha256_output[55], + _sha256_output[56], + _sha256_output[57], + _sha256_output[58], + _sha256_output[59], + _sha256_output[60], + _sha256_output[61], + _sha256_output[62], + _sha256_output[63]); + } + break; + } + + rc2014_send_ack(); + + rc2014_send_buffer(o, olen); + rc2014_flush(); + + rc2014_send_complete(); +} + + // Initializes base settings and adds our devices to the SIO bus void rc2014Fuji::setup(systemBus *siobus) { @@ -1444,6 +1779,18 @@ void rc2014Fuji::rc2014_process(uint32_t commanddata, uint8_t checksum) case FUJICMD_BASE64_DECODE_OUTPUT: rc2014_base64_decode_output(); break; + case FUJICMD_HASH_INPUT: + rc2014_hash_input(); + break; + case FUJICMD_HASH_COMPUTE: + rc2014_hash_compute(); + break; + case FUJICMD_HASH_LENGTH: + rc2014_hash_length(); + break; + case FUJICMD_HASH_OUTPUT: + rc2014_hash_output(); + break; default: fnUartDebug.printf("rc2014_process() not implemented yet for this device. Cmd received: %02x\n", cmdFrame.comnd); rc2014_send_nak(); diff --git a/lib/device/rc2014/fuji.h b/lib/device/rc2014/fuji.h index 537b404fe..294f48c37 100644 --- a/lib/device/rc2014/fuji.h +++ b/lib/device/rc2014/fuji.h @@ -3,6 +3,11 @@ #include +#include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" +#include "mbedtls/sha512.h" +#include "mbedtls/md5.h" + #include "network.h" #include "disk.h" @@ -81,6 +86,16 @@ class rc2014Fuji : public virtualDevice std::string base64_buffer; + mbedtls_md5_context _md5; + mbedtls_sha1_context _sha1; + mbedtls_sha256_context _sha256; + mbedtls_sha512_context _sha512; + + char hash_mode = 0; + unsigned char _md5_output[16]; + unsigned char _sha1_output[20]; + unsigned char _sha256_output[32]; + unsigned char _sha512_output[64]; protected: void rc2014_reset_fujinet(); // 0xFF void rc2014_net_get_ssid(); // 0xFE @@ -127,6 +142,10 @@ class rc2014Fuji : public virtualDevice void rc2014_base64_decode_compute(); // 0xCB void rc2014_base64_decode_length(); // 0xCA void rc2014_base64_decode_output(); // 0xC9 + void rc2014_hash_input(); // 0xC8 + void rc2014_hash_compute(); // 0xC7 + void rc2014_hash_length(); // 0xC6 + void rc2014_hash_output(); // 0xC5 void rc2014_test_command(); From 2786b660ba8612b1ed97087f181724b91567aaf9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 21 Aug 2023 19:19:27 -0500 Subject: [PATCH 002/158] [adam][network] send NAK whn sending resp of len 0 --- lib/device/adamnet/network.cpp | 43 ++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index b801d6bae..6e07f7c18 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -49,7 +49,6 @@ adamNetwork::adamNetwork() } /** - * Destructor */ adamNetwork::~adamNetwork() { @@ -259,12 +258,12 @@ void adamNetwork::status() if (protocol == nullptr) { - response[0] = 0; - response[1] = 0; - response[2] = 0; - response[3] = 165; // invalid spec. - response_len = 4; - return; + response[0] = 0; + response[1] = 0; + response[2] = 0; + response[3] = 165; // invalid spec. + response_len = 4; + return; } switch (channelMode) @@ -506,9 +505,9 @@ void adamNetwork::json_query(unsigned short s) AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - json.setReadQuery(std::string((char *)c, s),cmdFrame.aux2); + json.setReadQuery(std::string((char *)c, s), cmdFrame.aux2); - Debug_printf("adamNetwork::json_query(%s)\n", c); + Debug_printv("adamNetwork::json_query(%s)\n", c); free(c); } @@ -777,8 +776,8 @@ void adamNetwork::adamnet_control_receive_channel_json() if (jsonRecvd == false) { response_len = json.readValueLen(); - json.readValue(response,response_len); - jsonRecvd=true; + json.readValue(response, response_len); + jsonRecvd = true; adamnet_response_ack(); } else @@ -801,7 +800,7 @@ void adamNetwork::adamnet_control_receive_channel_protocol() // Get status protocol->status(&ns); if (ns.rxBytesWaiting > 0) - Debug_printf("!!! rxBytesWaiting: %d\n",ns.rxBytesWaiting); + Debug_printf("!!! rxBytesWaiting: %d\n", ns.rxBytesWaiting); if (ns.rxBytesWaiting > 0) adamnet_response_ack(); else @@ -854,12 +853,16 @@ void adamNetwork::adamnet_response_send() { uint8_t c = adamnet_checksum(response, response_len); - adamnet_send(0xB0 | _devnum); - adamnet_send_length(response_len); - adamnet_send_buffer(response, response_len); - adamnet_send(c); - - Debug_printf("adamnet_response_send: %s\n",response); + if (response_len) + { + adamnet_send(0xB0 | _devnum); + adamnet_send_length(response_len); + adamnet_send_buffer(response, response_len); + adamnet_send(c); + } + else + adamnet_send(0xC0 | _devnum); // NAK! + memset(response, 0, response_len); response_len = 0; } @@ -908,7 +911,7 @@ bool adamNetwork::instantiate_protocol() { protocolParser = new ProtocolParser(); } - + protocol = protocolParser->createProtocol(urlParser->scheme, receiveBuffer, transmitBuffer, specialBuffer, &login, &password); if (protocol == nullptr) @@ -933,7 +936,7 @@ void adamNetwork::create_devicespec(string d) /* * The resulting URL is then sent into EdURLParser to get our URLParser object which is used in the rest * of Network. -*/ + */ void adamNetwork::create_url_parser() { std::string url = deviceSpec.substr(deviceSpec.find(":") + 1); From 3034a6a04ec3f9a594e23917fabbfcfba580e38a Mon Sep 17 00:00:00 2001 From: Justin Skists Date: Tue, 22 Aug 2023 08:49:27 +0100 Subject: [PATCH 003/158] RC2014: network: fix json query Since we removed the N: prefix from network device specs for RC2014, we missed one usage in rc2014_set_json_query()! Fix this. --- lib/device/rc2014/network.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/device/rc2014/network.cpp b/lib/device/rc2014/network.cpp index 25949c9d2..5075cdc13 100644 --- a/lib/device/rc2014/network.cpp +++ b/lib/device/rc2014/network.cpp @@ -368,9 +368,8 @@ void rc2014Network::rc2014_set_json_query() in[i] = 0x00; } - inp = strrchr((const char *)in, ':'); + inp = (const char *)in; Debug_printf("#1 %s\n",inp); - inp++; json.setReadQuery(string(inp),cmdFrame.aux2); json_bytes_remaining = json.readValueLen(); tmp = (uint8_t *)malloc(json.readValueLen()); From 444fea6697a11f266c218aa4ac7b3a7351b787ac Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 22 Aug 2023 13:26:26 -0500 Subject: [PATCH 004/158] [adamnet][network] add 2nd device 0x0A --- lib/device/adamnet/fuji.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 24d5eeb35..6761c3bad 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -21,6 +21,7 @@ adamFuji theFuji; // global fuji device object adamNetwork *theNetwork; // global network device object (temporary) +adamNetwork *theNetwork2; // another network device adamPrinter *thePrinter; // global printer adamSerial *theSerial; // global serial @@ -1215,8 +1216,10 @@ void adamFuji::setup(systemBus *siobus) } theNetwork = new adamNetwork(); + theNetwork2 = new adamNetwork(); theSerial = new adamSerial(); _adamnet_bus->addDevice(theNetwork, 0x09); // temporary. + _adamnet_bus->addDevice(theNetwork2,0x0A); // temporary _adamnet_bus->addDevice(&theFuji, 0x0F); // Fuji becomes the gateway device. } From 547c37a0e583a8d6700cd9db17c389288bb016b2 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Tue, 22 Aug 2023 21:26:17 -0400 Subject: [PATCH 005/158] working on floppy latch logic --- lib/device/mac/floppy.h | 20 +++++ pico/mac/commands.c | 192 +++++++++++++++++++++++++++++++++------- 2 files changed, 181 insertions(+), 31 deletions(-) diff --git a/lib/device/mac/floppy.h b/lib/device/mac/floppy.h index 3ddfda2e0..7c332db72 100644 --- a/lib/device/mac/floppy.h +++ b/lib/device/mac/floppy.h @@ -4,6 +4,26 @@ #include "bus.h" #include "../media/media.h" +/* +// drive state bits +#define STAT_DIRTN 0b0000 +#define STAT_STEP 0b0001 +#define STAT_MOTORON 0b0010 +#define STAT_EJECT 0b0011 +#define STAT_DATAHD0 0b0100 + not assigned 0b0101 +#define STAT_SS 0b0110 +#define STAT_DRVIN 0b0111 +#define STAT_CSTIN 0b1000 +#define STAT_WRTPRT 0b1001 +#define STAT_TKO 0b1010 +#define STAT_TACH 0b1011 +#define STAT_DATAHD1 0b1100 + not assigned 0b1101 +#define STAT_READY 0b1110 +#define STAT_REVISED 0b1111 + */ + class macFloppy : public macDevice { diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 4d6635b29..2f69062a8 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -48,36 +48,38 @@ const int tach_lut[5][3] = {{0, 15, 394}, uint32_t a; char c; +PIO pio = pio0; -void setup_esp_uart() { - uart_init(UART_ID, BAUD_RATE); +void setup_esp_uart() +{ + uart_init(UART_ID, BAUD_RATE); - gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); - gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); - uart_set_hw_flow(UART_ID, false, false); - uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY); - uart_set_fifo_enabled(UART_ID, true); + gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); + gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); + uart_set_hw_flow(UART_ID, false, false); + uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY); + uart_set_fifo_enabled(UART_ID, true); } /** * 800 KB GCR Drive -CA2 CA1 CA0 SEL RD Output -Low Low Low Low !DIRTN -Low Low Low High !CSTIN -Low Low High Low !STEP -Low Low High High !WRPROT -Low High Low Low !MOTORON -Low High Low High !TK0 -Low High High Low SWITCHED -Low High High High !TACH -High Low Low Low RDDATA0 -High Low Low High RDDATA1 -High Low High Low SUPERDRIVE -High Low High High + -High High Low Low SIDES -High High Low High !READY -High High High Low !DRVIN -High High High High REVISED +CA2 CA1 CA0 SEL RD Output PIO +Low Low Low Low !DIRTN latch +Low Low Low High !CSTIN latch +Low Low High Low !STEP latch +Low Low High High !WRPROT latch +Low High Low Low !MOTORON latch +Low High Low High !TK0 latch +Low High High Low SWITCHED latch +Low High High High !TACH tach +High Low Low Low RDDATA0 echo +High Low Low High RDDATA1 echo +High Low High Low SUPERDRIVE latch +High Low High High + latch +High High Low Low SIDES latch +High High Low High !READY latch +High High High Low !DRVIN latch +High High High High REVISED latch + TODO Signal Descriptions @@ -105,6 +107,47 @@ DCDDATA Communication channel from DCD device to Macintosh */ +// info from Apple Computer Drawing Number 699-0452-A +enum latch_bits { + DIRTN = 0, // !DIRTN This signal sets the direction of head motion. A zero sets direction toward the center of the disk and a one sets direction towards outer edge. When IENBL is high IDIRTN is set to zero. Change of !DIRTN command is not allowed during head movement nor head settlying time. + STEP, // !STEP At the falling edge of this signal the destination track counter is counted up or down depending on the ID'IIRTN level. After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. + MOTORON, // !MOTORON When this signal is set to low, the disk motor is turned on. When IENBL is high, /MOTORON is set to high. + EJECT, // EJECT At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. EJECT is set to low at rising edge of ICSTIN or 2 sec maximum after rising edge of EJECT. When power is turned on, EJECT is set to low. + DATA0, // read data - not from latch but comes from RMT device + na0101, // not assigned in latch + SINGLESIDE, // !SINGLESIDE A status bit which is read as one for double sided drive. + DRVIN, // !DRVIN This status bit is read as a zero only if the selected drive is connected to the host computer. + CSTIN, // !CSTIN This status bit is read as a zero only when a diskette is in the drive or when the mechanism for ejection and insertion is at the disk-in position without diskette. + WRTPRT, // !WRTPRT This status bit is read as a zero only when a write protected diskette is in the drive or no diskette is inserted in the drive. + TKO, // !TKO This status bit is read as a zero when a head is on track 00 or outer position of track 00. NOTE: rrKO is an output signal of a latch whose status is decided by the track 00 sensor only while the drive is not in power save mode. + TACH, // tachometer - generated by the RP2040 clock device + DATA1, // read data - not from latch but comes from RMT device + na1101, // not assigned in latch + READY, // !READY This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. IREADY is a zero when the head position is settled on disired track, motor is at the desired speed, and a diskette is in the drive. + REVISED // REVISED This status line is used to indicate that the interface definition of the connected external drive. When REVISED is a one, the drive Part No. will be 699-0326 or when REVISED is a zero, the drive Part No. will be 699-0285. +}; + +uint16_t latch; + +uint16_t get_latch() { return latch; } + +uint16_t set_latch(enum latch_bits s) +{ + latch |= (1 << s); + return latch; +}; + +uint16_t clr_latch(enum latch_bits c) +{ + latch &= ~(1 << c); + return latch; +}; + +bool latch_val(enum latch_bits b) +{ + return (latch & (1 << b)); +} + void set_tach_freq(char c) { // To configure a clock, we need to know the following pieces of information: @@ -119,17 +162,16 @@ void set_tach_freq(char c) } } -int main() +void setup() { - // start TACH clock + stdio_init_all(); - set_tach_freq(0); + set_tach_freq(0); // start TACH clock setup_default_uart(); setup_esp_uart(); - PIO pio = pio0; uint offset = pio_add_program(pio, &commands_program); printf("\nLoaded cmd program at %d\n", offset); pio_commands(pio, SM_CMD, offset, MCI_CA0); // read phases starting on pin 8 @@ -141,21 +183,109 @@ int main() pio_latch(pio, SM_LATCH, offset, MCI_CA0, LATCH_OUT); pio_sm_put_blocking(pio, SM_LATCH, 0xffff); // send the register word to the PIO // todo: add other PIO SM's here (mux) +} + + +int main() +{ + setup(); while (true) { if (!pio_sm_is_rx_fifo_empty(pio, SM_CMD)) { a = pio_sm_get_blocking(pio, SM_CMD); + switch (a) + { + // !READY + // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. + // !READY is a zero when + // the head position is settled on disired track, + // motor is at the desired speed, + // and a diskette is in the drive. + case 0: + // !DIRTN + // This signal sets the direction of head motion. + // A zero sets direction toward the center of the disk and a one sets direction towards outer edge. + // When !ENBL is high !DIRTN is set to zero. + // Change of !DIRTN command is not allowed during head movement nor head settlying time. + // set direction to increase track number + clr_latch(DIRTN); + break; + case 4: + set_latch(DIRTN); + break; + case 1: + // !STEP + // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. + // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. + // step the head + clr_latch(STEP); + set_latch(READY); + break; + case 2: + // !MOTORON + // When this signal is set to low, the disk motor is turned on. + // When !ENBL is high, /MOTORON is set to high. + // turn motor on + clr_latch(MOTORON); + set_latch(READY); + break; + case 6: + // turn motor off + set_latch(MOTORON); + set_latch(READY); + break; + case 7: + // EJECT + // At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. + // EJECT is set to low at rising edge of !CSTIN or 2 sec maximum after rising edge of EJECT. + // When power is turned on, EJECT is set to low. + // eject + set_latch(EJECT); + set_latch(READY); + break; + default: + printf("\nUNKNOWN PHASE COMMAND"); + break; + } + pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO uart_putc_raw(UART_ID, (char)(a + '0')); } + + // !STEP + // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. + // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. + if (latch_val(STEP)) + set_latch(STEP); + if (uart_is_readable(uart1)) { + // !READY + // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. + // !READY is a zero when + // the head position is settled on disired track, + // motor is at the desired speed, + // and a diskette is in the drive. c = uart_getc(UART_ID); - if (!(c & 128)) - printf("%c", c); - else + // to do: figure out when to clear !READY + if (c & 128) + { set_tach_freq(c & 127); + clr_latch(READY); + } + else + switch (c) + { + case /* constant-expression */: + /* code */ + break; + + default: + break; + } + + pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO } // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO // to do: read both enable lines and indicate which drive is active when sending single char to esp32 From b0517937ca1cc747dc9eeff9f689219b674ff027 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Aug 2023 09:00:05 -0500 Subject: [PATCH 006/158] [adam] implement high score enabled. --- lib/device/adamnet/disk.cpp | 4 ++++ lib/device/adamnet/disk.h | 1 + lib/device/adamnet/fuji.cpp | 2 ++ lib/media/adam/mediaType.h | 9 +++++++++ lib/media/adam/mediaTypeDDP.cpp | 27 ++++++++++++++++++++++++++- lib/media/adam/mediaTypeDSK.cpp | 22 ++++++++++++++++++++++ 6 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index 4dcedb9ea..374abb458 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -59,10 +59,14 @@ mediatype_t adamDisk::mount(FILE *f, const char *filename, uint32_t disksize, me case MEDIATYPE_DDP: device_active = true; _media = new MediaTypeDDP(); + _media->_media_host = host; + strcpy(_media->_disk_filename, filename); mt = _media->mount(f, disksize); break; case MEDIATYPE_DSK: _media = new MediaTypeDSK(); + _media->_media_host = host; + strcpy(_media->_disk_filename,filename); mt = _media->mount(f, disksize); device_active = true; break; diff --git a/lib/device/adamnet/disk.h b/lib/device/adamnet/disk.h index 7a09863a6..1921ea068 100755 --- a/lib/device/adamnet/disk.h +++ b/lib/device/adamnet/disk.h @@ -30,6 +30,7 @@ class adamDisk : public virtualDevice public: adamDisk(); + fujiHost *host = nullptr; mediatype_t mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type = MEDIATYPE_UNKNOWN); void unmount(); bool write_blank(FILE *f, uint32_t numBlocks); diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 6761c3bad..4072e8ccc 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -296,6 +296,8 @@ void adamFuji::adamnet_disk_image_mount() Debug_printf("Selecting '%s' from host #%u as %s on D%u:\n", disk.filename, disk.host_slot, flag, deviceSlot + 1); + disk.disk_dev.host = &host; + AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); diff --git a/lib/media/adam/mediaType.h b/lib/media/adam/mediaType.h index 8e9bdad70..cddc7db05 100755 --- a/lib/media/adam/mediaType.h +++ b/lib/media/adam/mediaType.h @@ -2,6 +2,7 @@ #define _MEDIA_TYPE_ #include +#include #define INVALID_SECTOR_VALUE 0xFFFFFFFF @@ -26,6 +27,9 @@ class MediaType { protected: FILE *_media_fileh = nullptr; + FILE *oldFileh = nullptr; + FILE *hsFileh = nullptr; + uint32_t _media_image_size = 0; uint32_t _media_num_blocks = 256; uint16_t _media_sector_size = DISK_BYTES_PER_SECTOR_SINGLE; @@ -47,10 +51,15 @@ class MediaType uint8_t reserved3; } _percomBlock; + char _disk_filename[256]; + uint8_t _media_blockbuff[MEDIA_BLOCK_SIZE]; uint32_t _media_last_block = INVALID_SECTOR_VALUE-1; uint8_t _media_controller_status = DISK_CTRL_STATUS_CLEAR; + fujiHost *_media_host = nullptr; + FILE *_media_hsfileh = nullptr; + mediatype_t _mediatype = MEDIATYPE_UNKNOWN; bool _allow_hsio = true; diff --git a/lib/media/adam/mediaTypeDDP.cpp b/lib/media/adam/mediaTypeDDP.cpp index ece7a50d5..375fa009f 100644 --- a/lib/media/adam/mediaTypeDDP.cpp +++ b/lib/media/adam/mediaTypeDDP.cpp @@ -63,12 +63,21 @@ bool MediaTypeDDP::read(uint32_t blockNum, uint16_t *readcount) // Returns TRUE if an error condition occurred bool MediaTypeDDP::write(uint32_t blockNum, bool verify) { - Debug_printf("ATR WRITE\r\n", blockNum, _media_num_blocks); + Debug_printf("DDP WRITE\r\n", blockNum, _media_num_blocks); uint32_t offset = _block_to_offset(blockNum); _media_last_block = INVALID_SECTOR_VALUE; + if (_media_fileh->_flags == 0x1484) // mounted R/O, attempt HS R/W + { + Debug_printf("High score mode activated, attempting write open\r\n"); + + oldFileh = _media_fileh; + hsFileh = _media_host->file_open(_disk_filename, _disk_filename, strlen(_disk_filename) + 1, "r+"); + _media_fileh = hsFileh; + } + // Perform a seek if we're writing to the sector after the last one int e; // if (blockNum != _media_last_block + 1) @@ -97,6 +106,21 @@ bool MediaTypeDDP::write(uint32_t blockNum, bool verify) ret = fsync(fileno(_media_fileh)); // Since we might get reset at any moment, go ahead and sync the file (not clear if fflush does this) Debug_printf("DDP::write fsync:%d\r\n", ret); + Debug_printv("media flags %x\n",_media_fileh->_flags); + + if (_media_fileh->_flags == 0x1484) + { + Debug_printf("Closing high score sector.\r\n"); + + if (hsFileh != nullptr) + fclose(hsFileh); + + _media_fileh = oldFileh; + _media_last_block = INVALID_SECTOR_VALUE; // force a cache invalidate. + } + else + _media_last_block = blockNum; + _media_last_block = INVALID_SECTOR_VALUE; _media_controller_status=0; return false; @@ -121,6 +145,7 @@ mediatype_t MediaTypeDDP::mount(FILE *f, uint32_t disksize) _mediatype = MEDIATYPE_DDP; _media_num_blocks = disksize / 1024; + Debug_printv("FLAGS: %x\n",_media_fileh->_flags); return _mediatype; } diff --git a/lib/media/adam/mediaTypeDSK.cpp b/lib/media/adam/mediaTypeDSK.cpp index b18fbe239..654609c1c 100644 --- a/lib/media/adam/mediaTypeDSK.cpp +++ b/lib/media/adam/mediaTypeDSK.cpp @@ -84,6 +84,15 @@ bool MediaTypeDSK::write(uint32_t blockNum, bool verify) std::pair offsets = _block_to_offsets(blockNum); + if (_media_fileh->_flags == 0x1484) // mounted R/O, attempt HS R/W + { + Debug_printf("High score mode activated, attempting write open\r\n"); + + oldFileh = _media_fileh; + hsFileh = _media_host->file_open(_disk_filename, _disk_filename, strlen(_disk_filename) + 1, "r+"); + _media_fileh = hsFileh; + } + // Write lower part of block err = fseek(_media_fileh, offsets.first, SEEK_SET) != 0; if (err == false) @@ -99,6 +108,19 @@ bool MediaTypeDSK::write(uint32_t blockNum, bool verify) ret = fsync(fileno(_media_fileh)); // Since we might get reset at any moment, go ahead and sync the file (not clear if fflush does this) Debug_printf("DSK::write fsync:%d\r\n", ret); + if (_media_fileh->_flags == 0x1484) + { + Debug_printf("Closing high score sector.\r\n"); + + if (hsFileh != nullptr) + fclose(hsFileh); + + _media_fileh = oldFileh; + _media_last_block = INVALID_SECTOR_VALUE; // force a cache invalidate. + } + else + _media_last_block = blockNum; + _media_controller_status=0; return false; From 1cccedb98a2cb5e3d7843efce1493a8b8bb20408 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Wed, 23 Aug 2023 17:06:58 -0400 Subject: [PATCH 007/158] latch state logic - maybe? --- pico/mac/commands.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2f69062a8..2fcb712a8 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -189,6 +189,20 @@ void setup() int main() { setup(); + + // latch setup + latch = 0; + clr_latch(DIRTN); + set_latch(STEP); + set_latch(MOTORON); + clr_latch(EJECT); + clr_latch(SINGLESIDE); + clr_latch(DRVIN); + set_latch(CSTIN); + clr_latch(WRTPRT); + set_latch(TKO); + set_latch(READY); + set_latch(REVISED); while (true) { @@ -271,16 +285,26 @@ int main() // to do: figure out when to clear !READY if (c & 128) { + if (c==0) + clr_latch(TKO); // at track zero set_tach_freq(c & 127); clr_latch(READY); } else switch (c) { - case /* constant-expression */: - /* code */ + case 's': + // single sided disk is in the slot + set_latch(SINGLESIDE); + clr_latch(CSTIN); + clr_latch(WRTPRT); // everythign is write protected for now + break; + case 'd': + // double sided disk + clr_latch(SINGLESIDE); + clr_latch(CSTIN); + clr_latch(WRTPRT); // everythign is write protected for now break; - default: break; } @@ -289,7 +313,6 @@ int main() } // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO // to do: read both enable lines and indicate which drive is active when sending single char to esp32 - // to do: do we need to make non-blocking so can update latch values? or are latch values only updated after commands? } } From 6805abd5a1d90fdc2cfcc838dc12cb29bdb5bbe4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 23 Aug 2023 19:50:11 -0500 Subject: [PATCH 008/158] [atari][fuji] fix sha512 output bug. --- lib/device/sio/fuji.cpp | 128 ++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index 130fdca06..9b2e5dde0 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -2155,70 +2155,70 @@ void sioFuji::sio_hash_output() { olen <<= 1; sprintf((char *)o, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - _sha256_output[0], - _sha256_output[1], - _sha256_output[2], - _sha256_output[3], - _sha256_output[4], - _sha256_output[5], - _sha256_output[6], - _sha256_output[7], - _sha256_output[8], - _sha256_output[9], - _sha256_output[10], - _sha256_output[11], - _sha256_output[12], - _sha256_output[13], - _sha256_output[14], - _sha256_output[15], - _sha256_output[16], - _sha256_output[17], - _sha256_output[18], - _sha256_output[19], - _sha256_output[20], - _sha256_output[21], - _sha256_output[22], - _sha256_output[23], - _sha256_output[24], - _sha256_output[25], - _sha256_output[26], - _sha256_output[27], - _sha256_output[28], - _sha256_output[29], - _sha256_output[30], - _sha256_output[31], - _sha256_output[32], - _sha256_output[33], - _sha256_output[34], - _sha256_output[35], - _sha256_output[36], - _sha256_output[37], - _sha256_output[38], - _sha256_output[39], - _sha256_output[40], - _sha256_output[41], - _sha256_output[42], - _sha256_output[43], - _sha256_output[44], - _sha256_output[45], - _sha256_output[46], - _sha256_output[47], - _sha256_output[48], - _sha256_output[49], - _sha256_output[50], - _sha256_output[51], - _sha256_output[52], - _sha256_output[53], - _sha256_output[54], - _sha256_output[55], - _sha256_output[56], - _sha256_output[57], - _sha256_output[58], - _sha256_output[59], - _sha256_output[60], - _sha256_output[61], - _sha256_output[62], - _sha256_output[63]); + _sha512_output[0], + _sha512_output[1], + _sha512_output[2], + _sha512_output[3], + _sha512_output[4], + _sha512_output[5], + _sha512_output[6], + _sha512_output[7], + _sha512_output[8], + _sha512_output[9], + _sha512_output[10], + _sha512_output[11], + _sha512_output[12], + _sha512_output[13], + _sha512_output[14], + _sha512_output[15], + _sha512_output[16], + _sha512_output[17], + _sha512_output[18], + _sha512_output[19], + _sha512_output[20], + _sha512_output[21], + _sha512_output[22], + _sha512_output[23], + _sha512_output[24], + _sha512_output[25], + _sha512_output[26], + _sha512_output[27], + _sha512_output[28], + _sha512_output[29], + _sha512_output[30], + _sha512_output[31], + _sha512_output[32], + _sha512_output[33], + _sha512_output[34], + _sha512_output[35], + _sha512_output[36], + _sha512_output[37], + _sha512_output[38], + _sha512_output[39], + _sha512_output[40], + _sha512_output[41], + _sha512_output[42], + _sha512_output[43], + _sha512_output[44], + _sha512_output[45], + _sha512_output[46], + _sha512_output[47], + _sha512_output[48], + _sha512_output[49], + _sha512_output[50], + _sha512_output[51], + _sha512_output[52], + _sha512_output[53], + _sha512_output[54], + _sha512_output[55], + _sha512_output[56], + _sha512_output[57], + _sha512_output[58], + _sha512_output[59], + _sha512_output[60], + _sha512_output[61], + _sha512_output[62], + _sha512_output[63]); } break; } From 2bdfd8b43a9fae95e03ed48baf2c941d72f55905 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Fri, 25 Aug 2023 08:19:24 -0400 Subject: [PATCH 009/158] latch state work --- lib/bus/mac/mac.cpp | 1 + lib/device/mac/floppy.cpp | 57 +++++++++++++++++++++++++++++++++++ pico/mac/commands.c | 62 +++++++++++++++++++++++---------------- 3 files changed, 94 insertions(+), 26 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index f6609651d..b2b219ade 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -112,6 +112,7 @@ void macBus::service(void) { theFuji.get_disks(0)->disk_dev.update_track_buffers(); track_not_copied = false; + fnUartBUS.write('S'); } } diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 2749e5896..1cb0066e3 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -32,6 +32,16 @@ mediatype_t macFloppy::mount(FILE *f, mediatype_t disk_type) //, const char *fil old_pos = 2; // makde different to force change_track buffer copy change_track(0); // initialize rmt buffer change_track(1); // initialize rmt buffer + switch (_disk->num_sides) + { + case 1: + fnUartBUS.write('s'); + break; + case 2: + fnUartBUS.write('d'); + default: + break; + } break; // case MEDIATYPE_DSK: // Debug_printf("\nMounting Media Type DSK"); @@ -56,6 +66,53 @@ mediatype_t macFloppy::mount(FILE *f, mediatype_t disk_type) //, const char *fil // device_active = false; // } +/* MCI/DCD signals + + * 800 KB GCR Drive +CA2 CA1 CA0 SEL RD Output PIO +Low Low Low Low !DIRTN latch +Low Low Low High !CSTIN latch +Low Low High Low !STEP latch +Low Low High High !WRPROT latch +Low High Low Low !MOTORON latch +Low High Low High !TK0 latch +Low High High Low SWITCHED latch +Low High High High !TACH tach +High Low Low Low RDDATA0 echo +High Low Low High RDDATA1 echo +High Low High Low SUPERDRIVE latch +High Low High High + latch +High High Low Low SIDES latch +High High Low High !READY latch +High High High Low !DRVIN latch +High High High High REVISED latch ++ TODO + +Signal Descriptions +Signal Name Description +!DIRTN Step direction; low=toward center (+), high=toward rim (-) +!CSTIN Low when disk is present +!STEP Low when track step has been requested +!WRPROT Low when disk is write protected or not inserted +!MOTORON Low when drive motor is on +!TK0 Low when head is over track 0 (outermost track) +SWITCHED High when disk has been changed since signal was last cleared +!TACH Tachometer; frequency reflects drive speed in RPM +INDEX Pulses high for ~2 ms once per rotation +RDDATA0 Signal from bottom head; falling edge indicates flux transition +RDDATA1 Signal from top head; falling edge indicates flux transition +SUPERDRIVE High when a Superdrive (FDHD) is present +MFMMODE High when drive is in MFM mode +SIDES High when drive has a top head in addition to a bottom head +!READY Low when motor is at proper speed and head is ready to step +!DRVIN Low when drive is installed +REVISED High for double-sided double-density drives, low for single-sided double-density drives +PRESENT/!HD High when a double-density (not high-density) disk is present on a high-density drive +DCDDATA Communication channel from DCD device to Macintosh +!HSHK Low when DCD device is ready to receive or wishes to send + +*/ + void macFloppy::unmount() { } diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2fcb712a8..eefc90b2a 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -63,23 +63,23 @@ void setup_esp_uart() /** * 800 KB GCR Drive -CA2 CA1 CA0 SEL RD Output PIO -Low Low Low Low !DIRTN latch -Low Low Low High !CSTIN latch -Low Low High Low !STEP latch -Low Low High High !WRPROT latch -Low High Low Low !MOTORON latch -Low High Low High !TK0 latch -Low High High Low SWITCHED latch -Low High High High !TACH tach -High Low Low Low RDDATA0 echo -High Low Low High RDDATA1 echo -High Low High Low SUPERDRIVE latch -High Low High High + latch -High High Low Low SIDES latch -High High Low High !READY latch -High High High Low !DRVIN latch -High High High High REVISED latch +CA2 CA1 CA0 SEL RD Output PIO addr +Low Low Low Low !DIRTN latch 0 +Low Low Low High !CSTIN latch 1 +Low Low High Low !STEP latch 2 +Low Low High High !WRPROT latch 3 +Low High Low Low !MOTORON latch 4 +Low High Low High !TK0 latch 5 +Low High High Low SWITCHED latch 6 +Low High High High !TACH tach 7 +High Low Low Low RDDATA0 echo 8 +High Low Low High RDDATA1 echo 9 +High Low High Low SUPERDRIVE latch a +High Low High High + latch b +High High Low Low SIDES latch c +High High Low High !READY latch d +High High High Low !DRVIN latch e +High High High High REVISED latch f + TODO Signal Descriptions @@ -127,7 +127,7 @@ enum latch_bits { REVISED // REVISED This status line is used to indicate that the interface definition of the connected external drive. When REVISED is a one, the drive Part No. will be 699-0326 or when REVISED is a zero, the drive Part No. will be 699-0285. }; -uint16_t latch; +uint16_t latch = 0; uint16_t get_latch() { return latch; } @@ -191,7 +191,6 @@ int main() setup(); // latch setup - latch = 0; clr_latch(DIRTN); set_latch(STEP); set_latch(MOTORON); @@ -202,7 +201,12 @@ int main() clr_latch(WRTPRT); set_latch(TKO); set_latch(READY); - set_latch(REVISED); + set_latch(REVISED); // my mac plus revised looks set + // 11xx x101 00xx 0110 + + pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO + + bool step_state = false; while (true) { @@ -236,6 +240,7 @@ int main() // step the head clr_latch(STEP); set_latch(READY); + step_state = true; break; case 2: // !MOTORON @@ -243,7 +248,7 @@ int main() // When !ENBL is high, /MOTORON is set to high. // turn motor on clr_latch(MOTORON); - set_latch(READY); + set_latch(READY); break; case 6: // turn motor off @@ -256,8 +261,8 @@ int main() // EJECT is set to low at rising edge of !CSTIN or 2 sec maximum after rising edge of EJECT. // When power is turned on, EJECT is set to low. // eject - set_latch(EJECT); - set_latch(READY); + // set_latch(EJECT); // to do - need to clr eject when a disk is inserted - so cheat for now + // set_latch(READY); break; default: printf("\nUNKNOWN PHASE COMMAND"); @@ -270,8 +275,11 @@ int main() // !STEP // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. - if (latch_val(STEP)) + if (step_state) + { set_latch(STEP); + step_state = false; + } if (uart_is_readable(uart1)) { @@ -285,10 +293,9 @@ int main() // to do: figure out when to clear !READY if (c & 128) { - if (c==0) + if (c==128) clr_latch(TKO); // at track zero set_tach_freq(c & 127); - clr_latch(READY); } else switch (c) @@ -305,6 +312,9 @@ int main() clr_latch(CSTIN); clr_latch(WRTPRT); // everythign is write protected for now break; + case 'S': // step complete (data copied to RMT buffer on ESP32) + case 'M': // motor on + clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met default: break; } From fe9d481464acce72aa81346428399caae8e5718c Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 25 Aug 2023 11:59:34 -0500 Subject: [PATCH 010/158] [adam] update config. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 46698007d1f1e710d951f01a241b34d3bd88f27c..4c9b90d5b043aedbe7c82381dbf175ecd24c459a 100644 GIT binary patch literal 262144 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 zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W iOn?b60Vco%m;e)C0!)AjFaajO1egF5U;>{&;C}&Iqm6F> literal 262144 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 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBpb_}r D_BQV4 From feec933019ccf731058fd0756dd835c534669737 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Fri, 25 Aug 2023 13:06:36 -0400 Subject: [PATCH 011/158] mux working me thinks --- pico/mac/CMakeLists.txt | 1 + pico/mac/commands.c | 30 ++++++++++++++++++++---------- pico/mac/commands.pio | 5 +++-- pico/mac/echo.pio | 14 ++++++++------ pico/mac/latch.pio | 7 ++++--- pico/mac/mux.pio | 41 +++++++++++++++-------------------------- 6 files changed, 51 insertions(+), 47 deletions(-) diff --git a/pico/mac/CMakeLists.txt b/pico/mac/CMakeLists.txt index 21c9fd31b..deec035cf 100644 --- a/pico/mac/CMakeLists.txt +++ b/pico/mac/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(commands commands.c) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/commands.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/echo.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/latch.pio) +pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/mux.pio) # however, alternatively you can choose to generate it somewhere else (in this case in the source tree for check in) #pico_generate_pio_header(pio_and ${CMAKE_CURRENT_LIST_DIR}/blink.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index eefc90b2a..f633cb91d 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -13,14 +13,15 @@ #include "commands.pio.h" #include "echo.pio.h" #include "latch.pio.h" +#include "mux.pio.h" // #include "../../include/pinmap/mac_rev0.h" #define UART_TX_PIN 4 #define UART_RX_PIN 5 #define MCI_CA0 8 -#define ECHO_IN 15 +#define ECHO_IN 21 #define TACH_OUT 21 -#define ECHO_OUT 22 +#define ECHO_OUT 18 #define LATCH_OUT 20 #define SM_CMD 0 @@ -29,8 +30,9 @@ #define SM_ECHO 3 void pio_commands(PIO pio, uint sm, uint offset, uint pin); -void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); +void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins); void pio_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); +void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin); #define UART_ID uart1 #define BAUD_RATE 1000000 //230400 //115200 @@ -175,21 +177,23 @@ void setup() uint offset = pio_add_program(pio, &commands_program); printf("\nLoaded cmd program at %d\n", offset); pio_commands(pio, SM_CMD, offset, MCI_CA0); // read phases starting on pin 8 + offset = pio_add_program(pio, &echo_program); printf("Loaded echo program at %d\n", offset); - pio_echo(pio, SM_ECHO, offset, ECHO_IN, ECHO_OUT); + pio_echo(pio, SM_ECHO, offset, ECHO_IN, ECHO_OUT, 2); + offset = pio_add_program(pio, &latch_program); printf("Loaded latch program at %d\n", offset); pio_latch(pio, SM_LATCH, offset, MCI_CA0, LATCH_OUT); pio_sm_put_blocking(pio, SM_LATCH, 0xffff); // send the register word to the PIO - // todo: add other PIO SM's here (mux) + + offset = pio_add_program(pio, &mux_program); + pio_mux(pio, SM_MUX, offset, MCI_CA0, ECHO_OUT); } - int main() { setup(); - // latch setup clr_latch(DIRTN); set_latch(STEP); @@ -295,7 +299,7 @@ int main() { if (c==128) clr_latch(TKO); // at track zero - set_tach_freq(c & 127); + // set_tach_freq(c & 127); } else switch (c) @@ -331,9 +335,9 @@ void pio_commands(PIO pio, uint sm, uint offset, uint pin) { pio_sm_set_enabled(pio, sm, true); } -void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) +void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins) { - echo_program_init(pio, sm, offset, in_pin, out_pin); + echo_program_init(pio, sm, offset, in_pin, out_pin, num_pins); pio_sm_set_enabled(pio, sm, true); } @@ -341,4 +345,10 @@ void pio_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) { latch_program_init(pio, sm, offset, in_pin, out_pin); pio_sm_set_enabled(pio, sm, true); +} + +void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin) +{ + mux_program_init(pio, sm, offset, in_pin, mux_pin); + pio_sm_set_enabled(pio, sm, true); } \ No newline at end of file diff --git a/pico/mac/commands.pio b/pico/mac/commands.pio index c197a5d75..4a19651ae 100644 --- a/pico/mac/commands.pio +++ b/pico/mac/commands.pio @@ -1,7 +1,8 @@ ; -; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; FujiNet Project ; -; SPDX-License-Identifier: BSD-3-Clause +; Vintage Macintosh Microfloppy Controller Interface +; sends the phases to the PICO when the strobe sets ; .define LSTRB 12 diff --git a/pico/mac/echo.pio b/pico/mac/echo.pio index c5a0e5ca6..4eda55970 100644 --- a/pico/mac/echo.pio +++ b/pico/mac/echo.pio @@ -1,7 +1,8 @@ ; -; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; FujiNet Project ; -; SPDX-License-Identifier: BSD-3-Clause +; Vintage Macintosh Microfloppy Controller Interface +; copies input to output - for the ESP32 RMT signal ; .program echo @@ -13,19 +14,20 @@ start: % c-sdk { // this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin -void echo_program_init(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) { +void echo_program_init(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins) { // configure a SM pio_sm_config c = echo_program_get_default_config(offset); // set the out pin to out_pin - sm_config_set_out_pins(&c, out_pin, 1); + sm_config_set_out_pins(&c, out_pin, num_pins); // set the in pin to in_pin sm_config_set_in_pins(&c, in_pin); // there are 1 wires to read, shift to the left, no autopush // sm_config_set_in_shift(&c, false, true, 4); // sm_config_set_out_shift(&c, true, false, 1); // shift to the right // set pin as a GPIO output connected to this SM - pio_gpio_init(pio, out_pin); - pio_sm_set_consecutive_pindirs(pio, sm, out_pin, 1, true); + for (int i=0; i Date: Fri, 25 Aug 2023 13:13:33 -0500 Subject: [PATCH 012/158] [adam][printer] remove backwards. --- lib/printer-emulator/coleco_printer.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/printer-emulator/coleco_printer.cpp b/lib/printer-emulator/coleco_printer.cpp index 72c0ea514..d14ca7014 100644 --- a/lib/printer-emulator/coleco_printer.cpp +++ b/lib/printer-emulator/coleco_printer.cpp @@ -42,13 +42,7 @@ void colecoprinter::pdf_handle_char(uint16_t c, uint8_t aux1, uint8_t aux2) fputc('\\', _file); fputc(c, _file); - if (backwards == true) - { - fprintf(_file, ")%d(", (int)(1200.)); - pdf_X -= charWidth*2; // update x position - } - else - pdf_X += charWidth; // update x position + pdf_X += charWidth; // update x position } else { Debug_printf("ignore %02x\r\n", c); From e658a45d3f640a5dce7c1016f73785a6902172d4 Mon Sep 17 00:00:00 2001 From: Eric Carr Date: Fri, 25 Aug 2023 17:58:51 -0500 Subject: [PATCH 013/158] IEC - Standardize and simplify tokenizing basic commands, AppKey fixes --- lib/device/iec/fuji.cpp | 233 +++++++++++++++++++++++++--------------- lib/device/iec/fuji.h | 1 + 2 files changed, 147 insertions(+), 87 deletions(-) diff --git a/lib/device/iec/fuji.cpp b/lib/device/iec/fuji.cpp index b938ff69f..8279d22e3 100644 --- a/lib/device/iec/fuji.cpp +++ b/lib/device/iec/fuji.cpp @@ -8,6 +8,7 @@ #include #include #include "string_utils.h" +#include "../../../include/petscii.h" #include "../../../include/debug.h" @@ -98,20 +99,20 @@ void iecFuji::net_scan_networks() // Return scanned network entry void iecFuji::net_scan_result() { - std::vector t = util_tokenize(payload, ','); + - // t[0] = SCANRESULT - // t[1] = scan result # (0-numresults) + // pt[0] = SCANRESULT + // pt[1] = scan result # (0-numresults) struct { char ssid[33]; uint8_t rssi; } detail; - if (t.size() > 1) + if (pt.size() > 1) { - util_remove_spaces(t[1]); - int i = atoi(t[1].c_str()); + util_remove_spaces(pt[1]); + int i = atoi(pt[1].c_str()); fnWiFi.get_scan_result(i, detail.ssid, &detail.rssi); Debug_printf("SSID: %s RSSI: %u\r\n", detail.ssid, detail.rssi); } @@ -186,18 +187,17 @@ void iecFuji::net_set_ssid() } else // easy BASIC form { - std::string s = payload.substr(8, std::string::npos); - std::vector t = util_tokenize(s, ','); + - if (t.size() == 2) + if (pt.size() == 3) { - if ( mstr::isNumeric( t[0] ) ) { + if ( mstr::isNumeric( pt[1] ) ) { // Find SSID by CRC8 Number - t[0] = fnWiFi.get_network_name_by_crc8( std::stoi(t[0]) ); + pt[1] = fnWiFi.get_network_name_by_crc8( std::stoi(pt[1]) ); } - strncpy(cfg.ssid, t[0].c_str(), 33); - strncpy(cfg.password, t[1].c_str(), 64); + strncpy(cfg.ssid, pt[1].c_str(), 33); + strncpy(cfg.password, pt[2].c_str(), 64); } } @@ -257,14 +257,14 @@ void iecFuji::unmount_host() } else { - std::vector t = util_tokenize(payload, ':'); - if (t.size() < 2) // send error. + + if (pt.size() < 2) // send error. { response = "invalid # of parameters"; return; } - hs = atoi(t[1].c_str()); + hs = atoi(pt[1].c_str()); } if (!_validate_device_slot(hs, "unmount_host")) @@ -294,15 +294,15 @@ void iecFuji::mount_host() } else { - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 2) // send error. + if (pt.size() < 2) // send error. { response = "INVALID # OF PARAMETERS."; return; } - hs = atoi(t[1].c_str()); + hs = atoi(pt[1].c_str()); } if (!_validate_device_slot(hs, "mount_host")) @@ -330,15 +330,15 @@ void iecFuji::mount_host() void iecFuji::disk_image_mount() { _populate_slots_from_config(); - std::vector t = util_tokenize(payload, ','); - if (t.size() < 3) + + if (pt.size() < 3) { response = "invalid # of parameters"; return; } - uint8_t ds = atoi(t[1].c_str()); - uint8_t mode = atoi(t[2].c_str()); + uint8_t ds = atoi(pt[1].c_str()); + uint8_t mode = atoi(pt[2].c_str()); char flag[3] = {'r', 0, 0}; @@ -389,16 +389,16 @@ void iecFuji::set_boot_config() } else { - std::vector t = util_tokenize(payload, ':'); + - if (t.size() < 2) + if (pt.size() < 2) { Debug_printf("Invalid # of parameters.\r\n"); response = "invalid # of parameters"; return; } - boot_config = atoi(t[1].c_str()); + boot_config = atoi(pt[1].c_str()); } response = "ok"; } @@ -484,9 +484,9 @@ void iecFuji::set_boot_mode() } else { - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 2) + if (pt.size() < 2) { Debug_printf("Invalid # of parameters.\r\n"); // send error @@ -495,7 +495,7 @@ void iecFuji::set_boot_mode() } boot_config = true; - insert_boot_device(atoi(t[1].c_str())); + insert_boot_device(atoi(pt[1].c_str())); } response = "ok"; } @@ -524,23 +524,23 @@ void iecFuji::open_app_key() memcpy(&_current_appkey, &payload.c_str()[1], sizeof(_current_appkey)); else { - std::vector t = util_tokenize(payload, ','); + unsigned int val; - if (t.size() < 5) + if (pt.size() < 5) { Debug_printf("Incorrect number of parameters.\r\n"); response = "invalid # of parameters"; // send error. } - sscanf(t[1].c_str(), "%x", &val); + sscanf(pt[1].c_str(), "%x", &val); _current_appkey.creator = (uint16_t)val; - sscanf(t[2].c_str(), "%x", &val); + sscanf(pt[2].c_str(), "%x", &val); _current_appkey.app = (uint8_t)val; - sscanf(t[3].c_str(), "%x", &val); + sscanf(pt[3].c_str(), "%x", &val); _current_appkey.key = (uint8_t)val; - sscanf(t[4].c_str(), "%x", &val); + sscanf(pt[4].c_str(), "%x", &val); _current_appkey.mode = (appkey_mode)val; _current_appkey.reserved = 0; } @@ -594,16 +594,15 @@ void iecFuji::write_app_key() if (payload[0] == FUJICMD_WRITE_APPKEY) { keylen = payload[1] & 0xFF; - keylen |= payload[2] << 8; + keylen |= payload[2] << 8; strncpy(value, &payload.c_str()[3], MAX_APPKEY_LEN); } else - { - std::vector t = util_tokenize(payload, ':'); - if (t.size() > 3) + { + if (pt.size() > 2) { - keylen = atoi(t[1].c_str()); - strncpy(value, t[2].c_str(), MAX_APPKEY_LEN); + keylen = atoi(pt[1].c_str()); + strncpy(value, pt[2].c_str(), MAX_APPKEY_LEN); } else { @@ -732,8 +731,6 @@ void iecFuji::read_app_key() snprintf(reply, sizeof(reply), "\"%04x\",\"%s\"", _r.size, _r.value); response = std::string(reply); } - - response = "ok\r"; } // Disk Image Unmount @@ -747,8 +744,8 @@ void iecFuji::disk_image_umount() } else { - std::vector t = util_tokenize(payload, ':'); - deviceSlot = atoi(t[1].c_str()); + + deviceSlot = atoi(pt[1].c_str()); } Debug_printf("Fuji cmd: UNMOUNT IMAGE 0x%02X\n", deviceSlot); @@ -789,17 +786,17 @@ void iecFuji::open_directory() { Debug_println("Fuji cmd: OPEN DIRECTORY"); - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 3) + if (pt.size() < 3) { response = "invalid # of parameters."; return; // send error } char dirpath[256]; - uint8_t hostSlot = atoi(t[1].c_str()); - strncpy(dirpath, t[2].c_str(), sizeof(dirpath)); + uint8_t hostSlot = atoi(pt[1].c_str()); + strncpy(dirpath, pt[2].c_str(), sizeof(dirpath)); if (!_validate_host_slot(hostSlot)) { @@ -890,17 +887,17 @@ void _set_additional_direntry_details(fsdir_entry_t *f, uint8_t *dest, uint8_t m void iecFuji::read_directory_entry() { - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 2) + if (pt.size() < 2) { // send error response = "invalid # of parameters"; return; } - uint8_t maxlen = atoi(t[1].c_str()); - uint8_t addtlopts = atoi(t[2].c_str()); + uint8_t maxlen = atoi(pt[1].c_str()); + uint8_t addtlopts = atoi(pt[2].c_str()); Debug_printf("Fuji cmd: READ DIRECTORY ENTRY (max=%hu)\n", maxlen); @@ -1016,15 +1013,15 @@ void iecFuji::set_directory_position() } else { - std::vector t = util_tokenize(payload, ':'); - if (t.size() < 2) + + if (pt.size() < 2) { Debug_println("Invalid directory position"); response = "error: invalid directory position\r"; return; } - pos = atoi(t[1].c_str()); + pos = atoi(pt[1].c_str()); } // Make sure we have a current open directory @@ -1116,17 +1113,17 @@ void iecFuji::read_host_slots() response = std::string((const char *)hostSlots, 256); else { - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 2) + if (pt.size() < 2) { response = "host slot # required"; return; } - util_remove_spaces(t[1]); + util_remove_spaces(pt[1]); - int selected_hs = atoi(t[1].c_str()); + int selected_hs = atoi(pt[1].c_str()); std::string hn = std::string(hostSlots[selected_hs]); if (hn.empty()) @@ -1170,15 +1167,15 @@ void iecFuji::write_host_slots() else { // PUTHOST,, - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 2) + if (pt.size() < 2) { response = "no host slot #"; return; } else - hostSlot = atoi(t[1].c_str()); + hostSlot = atoi(pt[1].c_str()); if (!_validate_host_slot(hostSlot)) { @@ -1187,9 +1184,9 @@ void iecFuji::write_host_slots() return; } - if (t.size() == 3) + if (pt.size() == 3) { - hostname = t[2]; + hostname = pt[2]; } else { @@ -1261,17 +1258,17 @@ void iecFuji::read_device_slots() status_override = std::string((const char *)&diskSlots, returnsize); else { - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 2) + if (pt.size() < 2) { response = "host slot required"; return; } - util_remove_spaces(t[1]); + util_remove_spaces(pt[1]); - int selected_ds = atoi(t[1].c_str()); + int selected_ds = atoi(pt[1].c_str()); response = diskSlots[selected_ds].filename; } @@ -1304,33 +1301,33 @@ void iecFuji::write_device_slots() else { // from BASIC - std::vector t = util_tokenize(payload, ','); + - if (t.size() < 4) + if (pt.size() < 4) { response = "need file mode"; return; } - else if (t.size() < 3) + else if (pt.size() < 3) { response = "need filename"; return; } - else if (t.size() < 2) + else if (pt.size() < 2) { response = "need host slot"; return; } - else if (t.size() < 1) + else if (pt.size() < 1) { response = "need device slot"; return; } - unsigned char ds = atoi(t[1].c_str()); - unsigned char hs = atoi(t[2].c_str()); - string filename = t[3]; - unsigned char m = atoi(t[4].c_str()); + unsigned char ds = atoi(pt[1].c_str()); + unsigned char hs = atoi(pt[2].c_str()); + string filename = pt[3]; + unsigned char m = atoi(pt[4].c_str()); _fnDisks[ds].reset(filename.c_str(),hs,m); strncpy(_fnDisks[ds].filename,filename.c_str(),256); @@ -1420,8 +1417,8 @@ void iecFuji::set_device_filename() } else { - std::vector t = util_tokenize(payload, ','); - if (t.size() < 4) + + if (pt.size() < 4) { Debug_printf("not enough parameters.\n"); response = "error: invalid # of parameters"; @@ -1461,9 +1458,9 @@ void iecFuji::get_device_filename() ds = payload[1]; else { - std::vector t = util_tokenize(payload, ':'); + - if (t.size() < 2) + if (pt.size() < 2) { Debug_printf("Incorrect # of parameters.\n"); response = "invalid # of parameters"; @@ -1471,7 +1468,7 @@ void iecFuji::get_device_filename() return; } - ds = atoi(t[1].c_str()); + ds = atoi(pt[1].c_str()); } if (!_validate_device_slot(ds, "get_device_filename")) @@ -1525,12 +1522,28 @@ device_state_t iecFuji::process() if (commanddata.primary == IEC_TALK && commanddata.secondary == IEC_REOPEN) { - for (int i=0;i0) + { + Debug_printf("Sending: "); + + // Hex + for (int i=0;i0x7f ? '.' : c); + } } Debug_printf("\n"); + #endif while (!IEC.sendBytes(response)) ; @@ -1565,7 +1578,7 @@ void iecFuji::local_ip() void iecFuji::process_basic_commands() { mstr::toASCII(payload); - pt = util_tokenize(payload, ','); + pt = tokenize_basic_command(); if (payload.find("adapterconfig") != std::string::npos) get_adapter_config(); @@ -1629,6 +1642,32 @@ void iecFuji::process_basic_commands() void iecFuji::process_raw_commands() { + #ifdef DEBUG + if (response.size()>0) + { + int size=payload.size(); + Debug_printf("Received RAW Command: (%i bytes) ", size); + + if (size>256) + size=256; + + // Hex + for (int i=0;i0x7f ? '.' : c); + } + Debug_printf("\n"); + } + #endif + switch (payload[0]) { case FUJICMD_RESET: @@ -1734,4 +1773,24 @@ std::string iecFuji::get_host_prefix(int host_slot) return _fnHosts[host_slot].get_prefix(); } +/* @brief Tokenizes the payload command and parameters. + Example: "COMMAND:Param1,Param2" will return a vector of [0]="COMMAND", [1]="Param1",[2]="Param2" + Also supports "COMMAND,Param1,Param2" +*/ +vector iecFuji::tokenize_basic_command() +{ + Debug_printf("Tokenizing basic command: %s\n", payload.c_str()); + + // Replace the first ":" with "," for easy tokenization. + // Assume it is fine to change the payload at this point. + // Technically, "COMMAND,Param1,Param2" will work the smae, if ":" is not in a param value + size_t endOfCommand = payload.find(':'); + if (endOfCommand != std::string::npos) + payload.replace(endOfCommand,1,","); + + vector result = util_tokenize(payload, ','); + return result; + +} + #endif /* BUILD_IEC */ \ No newline at end of file diff --git a/lib/device/iec/fuji.h b/lib/device/iec/fuji.h index ebc956fc9..c3104fa7e 100644 --- a/lib/device/iec/fuji.h +++ b/lib/device/iec/fuji.h @@ -72,6 +72,7 @@ class iecFuji : public virtualDevice void process_raw_commands(); void process_basic_commands(); + vector tokenize_basic_command(); protected: void reset_fujinet(); // 0xFF From c424bcc730c86250339f1ecc4ab0968d9612ce76 Mon Sep 17 00:00:00 2001 From: Eric Carr Date: Fri, 25 Aug 2023 18:02:44 -0500 Subject: [PATCH 014/158] IEC - Add check to prevent crash, reduce redundant expensive json->readValueLen() calls --- lib/device/iec/network.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/device/iec/network.cpp b/lib/device/iec/network.cpp index f75a3fc13..d58490bd5 100644 --- a/lib/device/iec/network.cpp +++ b/lib/device/iec/network.cpp @@ -537,7 +537,7 @@ void iecNetwork::parse_json() void iecNetwork::query_json() { uint8_t *tmp; - int channel = 0; + int channel = 0, readLen; char reply[80]; string s; @@ -563,8 +563,10 @@ void iecNetwork::query_json() s[i] = 0x5F; // wtf? json[channel]->setReadQuery(s, 0); - - if (!json[channel]->readValueLen()) + + // readValLen() can be expensive, so just call it once + readLen = json[channel]->readValueLen(); + if (!readLen) { iecStatus.error = NETWORK_ERROR_COULD_NOT_ALLOCATE_BUFFERS; iecStatus.channel = channel; @@ -573,7 +575,7 @@ void iecNetwork::query_json() return; } - tmp = (uint8_t *)malloc(json[channel]->readValueLen()); + tmp = (uint8_t *)malloc(readLen); if (!tmp) { @@ -586,7 +588,7 @@ void iecNetwork::query_json() return; } - json_bytes_remaining[channel] = json[channel]->readValueLen(); + json_bytes_remaining[channel] = readLen; json[channel]->readValue(tmp, json_bytes_remaining[channel]); *receiveBuffer[channel] += string((const char *)tmp, json_bytes_remaining[channel]); @@ -690,6 +692,11 @@ void iecNetwork::iec_talk_command() void iecNetwork::iec_command() { + // Check pt size before proceeding to avoid a crash + if (pt.size()==0) { + Debug_printf("pt.size()==0!\n"); + return; + } Debug_printf("pt[0]=='%s'\n", pt[0].c_str()); if (pt[0] == "cd") From 1f5a7fc807f143cb43906345cc60d42b5dacc0c3 Mon Sep 17 00:00:00 2001 From: Eric Carr Date: Fri, 25 Aug 2023 18:03:33 -0500 Subject: [PATCH 015/158] fnJson - fix Atari mapping (move next to Petscii mapping), add line endings for IEC when enumerating an object --- lib/fnjson/fnjson.cpp | 98 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 60f1fb4f8..6a1f16e88 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -96,6 +96,45 @@ string FNJSON::processString(string in) mstr::toPETSCII(in); #endif +#ifdef BUILD_ATARI + // SIO AUX bits 0+1 control the mapping + // Bit 0=0 - don't touch the characters + // Bit 0=1 - convert the characters when possible + // Bit 1=0 - convert to generic ASCII/ATASCII (no font change needed) + // Bit 1=1 - convert to ATASCII international charset (need to be switched on ATARI, i.e via POKE 756,204) + + // SIO AUX2 Bit 1 set? + if ((_queryParam & 1) != 0) + { + // yes, map special characters + Debug_printf("S: [Mapping->ATARI]\r\n"); + + // SIO AUX2 Bit 2 set? + if ((_queryParam & 2) != 0) + { + // yes, mapping to international charset + string mapFrom[] = {"á", "ù", "Ñ", "É", "ç", "ô", "ò", "ì", "£", "ï", "ü", "ä", "Ö", "ú", "ó", "ö", "Ü", "â", "û", "î", "é", "è", "ñ", "ê", "å", "à", "Å", "¡", "Ä", "ß"}; + string mapTo[] = {"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x60", "\x7b", "ss"}; + int elementCount = sizeof(mapFrom) / sizeof(mapFrom[0]); + for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) + if (in.find(mapFrom[elementIndex]) != std::string::npos) + in.replace(in.find(mapFrom[elementIndex]), string(mapFrom[elementIndex]).size(), mapTo[elementIndex]); + } + else + { + // no, mapping to normal ASCI (workaround) + string mapFrom[] = {"Ä", "Ö", "Ü", "ä", "ö", "ü", "ß", "é", "è", "á", "à", "ó", "ò", "ú", "ù"}; + string mapTo[] = {"Ae", "Oe", "Ue", "ae", "oe", "ue", "ss", "e", "e", "a", "a", "o", "o", "u", "u"}; + int elementCount = sizeof(mapFrom) / sizeof(mapFrom[0]); + for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) + if (in.find(mapFrom[elementIndex]) != std::string::npos) + in.replace(in.find(mapFrom[elementIndex]), string(mapFrom[elementIndex]).size(), mapTo[elementIndex]); + } + + Debug_printf("S: [Mapping->ATARI] %s\r\n", ss.str().c_str()); + } +#endif + return in; } @@ -108,50 +147,7 @@ string FNJSON::getValue(cJSON *item) if (cJSON_IsString(item)) { - Debug_printf("S: [cJSON_IsString] %s\r\n", cJSON_GetStringValue(item)); - -#ifdef BUILD_ATARI - - // SIO AUX bits 0+1 control the mapping - // Bit 0=0 - don't touch the characters - // Bit 0=1 - convert the characters when possible - // Bit 1=0 - convert to generic ASCII/ATASCII (no font change needed) - // Bit 1=1 - convert to ATASCII international charset (need to be switched on ATARI, i.e via POKE 756,204) - - // SIO AUX2 Bit 1 set? - if ((_queryParam & 1) != 0) - { - // yes, map special characters - string str_utf8mapping = ss.str(); - Debug_printf("S: [Mapping->ATARI]\r\n"); - - // SIO AUX2 Bit 2 set? - if ((_queryParam & 2) != 0) - { - // yes, mapping to international charset - string mapFrom[] = {"á", "ù", "Ñ", "É", "ç", "ô", "ò", "ì", "£", "ï", "ü", "ä", "Ö", "ú", "ó", "ö", "Ü", "â", "û", "î", "é", "è", "ñ", "ê", "å", "à", "Å", "¡", "Ä", "ß"}; - string mapTo[] = {"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x60", "\x7b", "ss"}; - int elementCount = sizeof(mapFrom) / sizeof(mapFrom[0]); - for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) - if (str_utf8mapping.find(mapFrom[elementIndex]) != std::string::npos) - str_utf8mapping.replace(str_utf8mapping.find(mapFrom[elementIndex]), string(mapFrom[elementIndex]).size(), mapTo[elementIndex]); - } - else - { - // no, mapping to normal ASCI (workaround) - string mapFrom[] = {"Ä", "Ö", "Ü", "ä", "ö", "ü", "ß", "é", "è", "á", "à", "ó", "ò", "ú", "ù"}; - string mapTo[] = {"Ae", "Oe", "Ue", "ae", "oe", "ue", "ss", "e", "e", "a", "a", "o", "o", "u", "u"}; - int elementCount = sizeof(mapFrom) / sizeof(mapFrom[0]); - for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) - if (str_utf8mapping.find(mapFrom[elementIndex]) != std::string::npos) - str_utf8mapping.replace(str_utf8mapping.find(mapFrom[elementIndex]), string(mapFrom[elementIndex]).size(), mapTo[elementIndex]); - } - - ss.str(str_utf8mapping); - Debug_printf("S: [Mapping->ATARI] %s\r\n", ss.str().c_str()); - } -#endif ss << processString(cJSON_GetStringValue(item) + lineEnding); } else if (cJSON_IsBool(item)) @@ -189,11 +185,25 @@ string FNJSON::getValue(cJSON *item) } else if (cJSON_IsObject(item)) { + #ifdef BUILD_IEC + // Set line ending when returning multiple values + setLineEnding("\x0a"); + #endif + item = item->child; do { - ss << item->string + lineEnding + getValue(item); + #ifdef BUILD_IEC + // Convert key to PETSCII + string tempStr = string((const char *)item->string); + mstr::toPETSCII(tempStr); + ss << tempStr; + #else + ss << item->string + #endif + + ss << lineEnding + getValue(item); } while ((item = item->next) != NULL); } else if (cJSON_IsArray(item)) From 94377b12c81a9cc053bf9fcc61f285b5fb1714ed Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 25 Aug 2023 18:28:32 -0500 Subject: [PATCH 016/158] [adam][printer] damn, it's close. --- lib/device/adamnet/printer.cpp | 27 +++-- lib/printer-emulator/coleco_printer.cpp | 72 +++++++------ lib/printer-emulator/coleco_printer.h | 129 +++++++++++++++++++++++- 3 files changed, 179 insertions(+), 49 deletions(-) diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index 8ad51f2b5..99c5fba49 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -36,18 +36,17 @@ void printerTask(void *param) { adamPrinter *p = (adamPrinter *)param; - while(1) + while (1) { if (need_print == true) { - fnLedManager.set(LED_BT,true); + fnLedManager.set(LED_BT, true); p->perform_print(); - fnLedManager.set(LED_BT,false); - need_print=false; + fnLedManager.set(LED_BT, false); + need_print = false; } - vTaskDelay(1); - + vTaskDelay(1); } } @@ -57,9 +56,9 @@ adamPrinter::adamPrinter(FileSystem *filesystem, printer_type print_type) _storage = filesystem; set_printer_type(print_type); - getPrinterPtr()->setEOLBypass(true); - getPrinterPtr()->setTranslate850(false); - getPrinterPtr()->setEOL(0x0D); + // getPrinterPtr()->setEOLBypass(true); + // getPrinterPtr()->setTranslate850(false); + // getPrinterPtr()->setEOL(0x0D); xTaskCreate(printerTask, "ptsk", 4096, this, PRINTER_PRIORITY, &thPrinter); } @@ -96,13 +95,13 @@ void adamPrinter::adamnet_control_status() void adamPrinter::perform_print() { - memcpy(_pptr->provideBuffer(),pi.buf,pi.len); - _pptr->process(pi.len,0,0); + memcpy(_pptr->provideBuffer(), pi.buf, pi.len); + _pptr->process(pi.len, 0, 0); } void adamPrinter::adamnet_control_send() { - memset(&pi,0,sizeof(pi)); + memset(&pi, 0, sizeof(pi)); pi.len = adamnet_recv_length(); adamnet_recv_buffer(pi.buf, pi.len); adamnet_recv(); // ck @@ -110,7 +109,7 @@ void adamPrinter::adamnet_control_send() AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - need_print=true; + need_print = true; _last_ms = fnSystem.millis(); } @@ -119,7 +118,7 @@ void adamPrinter::adamnet_control_ready() { AdamNet.start_time = esp_timer_get_time(); - if (need_print==true) + if (need_print == true) adamnet_response_nack(); else adamnet_response_ack(); diff --git a/lib/printer-emulator/coleco_printer.cpp b/lib/printer-emulator/coleco_printer.cpp index d14ca7014..dea1d1eb9 100644 --- a/lib/printer-emulator/coleco_printer.cpp +++ b/lib/printer-emulator/coleco_printer.cpp @@ -1,52 +1,55 @@ +#include #include "coleco_printer.h" -#include "../../include/debug.h" +void colecoprinter::line_output() +{ + for (int i=0;i<80;i++) + { + char c = bdb.get()[i]; + if (c > 31 && c < 128) + { + if (c == '\\' || c == '(' || c == ')') + fputc('\\', _file); + fputc(c, _file); + + pdf_X += charWidth; // update x position + } + } + + pdf_end_line(); + pdf_new_line(); + + bdb.clear(); +} void colecoprinter::pdf_handle_char(uint16_t c, uint8_t aux1, uint8_t aux2) { + bdb.put(c); + switch (c) { - case 8: - fprintf(_file, ")%d(", (int)(charWidth / lineHeight * 900.)); - pdf_X -= charWidth; // update x position - break; - case 9: - break; - case 10: - pdf_dY -= lineHeight; // set pdf_dY and rise to one line - pdf_set_rise(); + case 10: // LF + Debug_printv("LF"); + line_output(); break; case 11: - pdf_dY -= 6.0; // set pdf_dY and rise to one line - pdf_set_rise(); + if (bdb.getIsVT() == true) + { + line_output(); + bdb.setIsVT(false); + } + else + { + bdb.setIsVT(true); + } break; case 12: pdf_end_page(); break; case 13: - pdf_end_line(); - pdf_dY += lineHeight; - pdf_new_line(); + bdb.reset(); break; - case 14: - backwards = true; - break; - case 15: - backwards = false; - break; - default: - if (c > 31 && c < 128) - { - if (c == '\\' || c == '(' || c == ')') - fputc('\\', _file); - fputc(c, _file); - - pdf_X += charWidth; // update x position - } else - { - Debug_printf("ignore %02x\r\n", c); - } } } @@ -65,5 +68,8 @@ void colecoprinter::post_new_file() fontNumber = 1; fontSize = 10; + bdb.clear(); + bdb.reset(); + pdf_header(); } diff --git a/lib/printer-emulator/coleco_printer.h b/lib/printer-emulator/coleco_printer.h index 62c3513a8..a6b7f779d 100644 --- a/lib/printer-emulator/coleco_printer.h +++ b/lib/printer-emulator/coleco_printer.h @@ -1,15 +1,140 @@ #ifndef COLECO_PRINTER_H #define COLECO_PRINTER_H +#include "../../include/debug.h" + #include "printer.h" #include "pdf_printer.h" +class adamBidiBuffer +{ +private: + char _line[80]; + uint8_t _column = 0; + bool _backwards = false; + bool isVT = true; + + void put_bs() + { + isVT = false; + _column--; + } + + void put_lf() + { + isVT = false; + } + + void put_vt() + { + } + + void put_cr() + { + isVT = false; + _column=0; + } + + void put_default(char c) + { + isVT = false; + _line[_column] = c; + + if (_backwards) + { + if (_column > 0) + { + _column--; + } + } + else + { + if (_column < 80) + { + _column++; + } + } + } + + void put_reverse() + { + isVT = false; + _backwards = true; + } + + void put_normal() + { + isVT = false; + _backwards = false; + } + +public: + + bool getIsVT() + { + return isVT; + } + + void setIsVT(bool _isVT) + { + isVT = _isVT; + } + + void reset() + { + _column = 0; + } + + void clear() + { + memset(_line,0x20,sizeof(_line)); + } + + char *get() + { + return _line; + } + + void put(char c) + { + switch (c) + { + case 0x08: // BS + put_bs(); + break; + case 0x0A: // LF + put_lf(); + break; + case 0x0B: // VT + put_vt(); + break; + case 0x0D: // CR + put_cr(); + break; + case 0x0E: // SO (TO REVERSE) + put_reverse(); + break; + case 0x0F: // SI (TO NORMAL) + put_normal(); + break; + case 0x7F: // DEL + break; + default: + put_default(c); + break; + } + + } +}; + class colecoprinter : public pdfPrinter { -protected: +private: + void line_output(); - bool backwards = false; +protected: + adamBidiBuffer bdb; virtual void pdf_clear_modes() override {}; void pdf_handle_char(uint16_t c, uint8_t aux1, uint8_t aux2); virtual void post_new_file() override; From a7b658fbf0ed8e96885fac4cf7d60b16c09d79ab Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Fri, 25 Aug 2023 20:49:31 -0400 Subject: [PATCH 017/158] its alive --- pico/mac/commands.c | 303 ++++++++++++++++++++++-------------------- pico/mac/commands.pio | 2 + pico/mac/latch.pio | 3 + pico/mac/mux.pio | 5 +- 4 files changed, 171 insertions(+), 142 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index f633cb91d..56c9d6901 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -18,6 +18,7 @@ // #include "../../include/pinmap/mac_rev0.h" #define UART_TX_PIN 4 #define UART_RX_PIN 5 +#define ENABLE 7 #define MCI_CA0 8 #define ECHO_IN 21 #define TACH_OUT 21 @@ -111,22 +112,22 @@ DCDDATA Communication channel from DCD device to Macintosh // info from Apple Computer Drawing Number 699-0452-A enum latch_bits { - DIRTN = 0, // !DIRTN This signal sets the direction of head motion. A zero sets direction toward the center of the disk and a one sets direction towards outer edge. When IENBL is high IDIRTN is set to zero. Change of !DIRTN command is not allowed during head movement nor head settlying time. - STEP, // !STEP At the falling edge of this signal the destination track counter is counted up or down depending on the ID'IIRTN level. After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. - MOTORON, // !MOTORON When this signal is set to low, the disk motor is turned on. When IENBL is high, /MOTORON is set to high. - EJECT, // EJECT At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. EJECT is set to low at rising edge of ICSTIN or 2 sec maximum after rising edge of EJECT. When power is turned on, EJECT is set to low. - DATA0, // read data - not from latch but comes from RMT device - na0101, // not assigned in latch - SINGLESIDE, // !SINGLESIDE A status bit which is read as one for double sided drive. - DRVIN, // !DRVIN This status bit is read as a zero only if the selected drive is connected to the host computer. - CSTIN, // !CSTIN This status bit is read as a zero only when a diskette is in the drive or when the mechanism for ejection and insertion is at the disk-in position without diskette. - WRTPRT, // !WRTPRT This status bit is read as a zero only when a write protected diskette is in the drive or no diskette is inserted in the drive. - TKO, // !TKO This status bit is read as a zero when a head is on track 00 or outer position of track 00. NOTE: rrKO is an output signal of a latch whose status is decided by the track 00 sensor only while the drive is not in power save mode. - TACH, // tachometer - generated by the RP2040 clock device - DATA1, // read data - not from latch but comes from RMT device - na1101, // not assigned in latch - READY, // !READY This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. IREADY is a zero when the head position is settled on disired track, motor is at the desired speed, and a diskette is in the drive. - REVISED // REVISED This status line is used to indicate that the interface definition of the connected external drive. When REVISED is a one, the drive Part No. will be 699-0326 or when REVISED is a zero, the drive Part No. will be 699-0285. + DIRTN = 0, // 0 !DIRTN This signal sets the direction of head motion. A zero sets direction toward the center of the disk and a one sets direction towards outer edge. When IENBL is high IDIRTN is set to zero. Change of !DIRTN command is not allowed during head movement nor head settlying time. + STEP, // 1 !STEP At the falling edge of this signal the destination track counter is counted up or down depending on the ID'IIRTN level. After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. + MOTORON, // 2 !MOTORON When this signal is set to low, the disk motor is turned on. When IENBL is high, /MOTORON is set to high. + EJECT, // 3 EJECT At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. EJECT is set to low at rising edge of ICSTIN or 2 sec maximum after rising edge of EJECT. When power is turned on, EJECT is set to low. + DATA0, // 4 read data - not from latch but comes from RMT device + na0101, // 5 not assigned in latch + SINGLESIDE, // 6 !SINGLESIDE A status bit which is read as one for double sided drive. + DRVIN, // 7 !DRVIN This status bit is read as a zero only if the selected drive is connected to the host computer. + CSTIN, // 8 !CSTIN This status bit is read as a zero only when a diskette is in the drive or when the mechanism for ejection and insertion is at the disk-in position without diskette. + WRTPRT, // 9 !WRTPRT This status bit is read as a zero only when a write protected diskette is in the drive or no diskette is inserted in the drive. + TKO, // a !TKO This status bit is read as a zero when a head is on track 00 or outer position of track 00. NOTE: rrKO is an output signal of a latch whose status is decided by the track 00 sensor only while the drive is not in power save mode. + TACH, // b tachometer - generated by the RP2040 clock device + DATA1, // c read data - not from latch but comes from RMT device + na1101, // d not assigned in latch + READY, // e !READY This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. IREADY is a zero when the head position is settled on disired track, motor is at the desired speed, and a diskette is in the drive. + REVISED // f REVISED This status line is used to indicate that the interface definition of the connected external drive. When REVISED is a one, the drive Part No. will be 699-0326 or when REVISED is a zero, the drive Part No. will be 699-0285. }; uint16_t latch = 0; @@ -150,6 +151,22 @@ bool latch_val(enum latch_bits b) return (latch & (1 << b)); } +void preset_latch() +{ + clr_latch(DIRTN); + set_latch(STEP); + set_latch(MOTORON); + clr_latch(EJECT); + set_latch(SINGLESIDE); + clr_latch(DRVIN); + set_latch(CSTIN); + clr_latch(WRTPRT); + set_latch(TKO); + set_latch(READY); + set_latch(REVISED); // my mac plus revised looks set +} + + void set_tach_freq(char c) { // To configure a clock, we need to know the following pieces of information: @@ -164,16 +181,20 @@ void set_tach_freq(char c) } } +void loop(); void setup() { stdio_init_all(); + // gpio_pull_up(ENABLE); set_tach_freq(0); // start TACH clock setup_default_uart(); setup_esp_uart(); + preset_latch(); + uint offset = pio_add_program(pio, &commands_program); printf("\nLoaded cmd program at %d\n", offset); pio_commands(pio, SM_CMD, offset, MCI_CA0); // read phases starting on pin 8 @@ -188,148 +209,148 @@ void setup() pio_sm_put_blocking(pio, SM_LATCH, 0xffff); // send the register word to the PIO offset = pio_add_program(pio, &mux_program); + printf("Loaded mux program at %d\n", offset); pio_mux(pio, SM_MUX, offset, MCI_CA0, ECHO_OUT); } + int main() { setup(); // latch setup - clr_latch(DIRTN); - set_latch(STEP); - set_latch(MOTORON); - clr_latch(EJECT); - clr_latch(SINGLESIDE); - clr_latch(DRVIN); - set_latch(CSTIN); - clr_latch(WRTPRT); - set_latch(TKO); - set_latch(READY); - set_latch(REVISED); // my mac plus revised looks set + // 11xx x101 00xx 0110 pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO - bool step_state = false; + while (true) { - if (!pio_sm_is_rx_fifo_empty(pio, SM_CMD)) - { - a = pio_sm_get_blocking(pio, SM_CMD); - switch (a) - { - // !READY - // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. - // !READY is a zero when - // the head position is settled on disired track, - // motor is at the desired speed, - // and a diskette is in the drive. - case 0: - // !DIRTN - // This signal sets the direction of head motion. - // A zero sets direction toward the center of the disk and a one sets direction towards outer edge. - // When !ENBL is high !DIRTN is set to zero. - // Change of !DIRTN command is not allowed during head movement nor head settlying time. - // set direction to increase track number - clr_latch(DIRTN); - break; - case 4: - set_latch(DIRTN); - break; - case 1: - // !STEP - // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. - // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. - // step the head - clr_latch(STEP); - set_latch(READY); - step_state = true; - break; - case 2: - // !MOTORON - // When this signal is set to low, the disk motor is turned on. - // When !ENBL is high, /MOTORON is set to high. - // turn motor on - clr_latch(MOTORON); - set_latch(READY); - break; - case 6: - // turn motor off - set_latch(MOTORON); - set_latch(READY); - break; - case 7: - // EJECT - // At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. - // EJECT is set to low at rising edge of !CSTIN or 2 sec maximum after rising edge of EJECT. - // When power is turned on, EJECT is set to low. - // eject - // set_latch(EJECT); // to do - need to clr eject when a disk is inserted - so cheat for now - // set_latch(READY); - break; - default: - printf("\nUNKNOWN PHASE COMMAND"); - break; - } - pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO - uart_putc_raw(UART_ID, (char)(a + '0')); - } - - // !STEP - // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. - // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. - if (step_state) - { - set_latch(STEP); - step_state = false; - } - - if (uart_is_readable(uart1)) - { - // !READY - // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. - // !READY is a zero when - // the head position is settled on disired track, - // motor is at the desired speed, - // and a diskette is in the drive. - c = uart_getc(UART_ID); - // to do: figure out when to clear !READY - if (c & 128) - { - if (c==128) - clr_latch(TKO); // at track zero - // set_tach_freq(c & 127); - } - else - switch (c) - { - case 's': - // single sided disk is in the slot - set_latch(SINGLESIDE); - clr_latch(CSTIN); - clr_latch(WRTPRT); // everythign is write protected for now - break; - case 'd': - // double sided disk - clr_latch(SINGLESIDE); - clr_latch(CSTIN); - clr_latch(WRTPRT); // everythign is write protected for now - break; - case 'S': // step complete (data copied to RMT buffer on ESP32) - case 'M': // motor on - clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met - default: - break; - } - - pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO - } - // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO - // to do: read both enable lines and indicate which drive is active when sending single char to esp32 + loop(); + } +} + +bool step_state = false; + +void loop() +{ + if (!pio_sm_is_rx_fifo_empty(pio, SM_CMD)) + { + a = pio_sm_get_blocking(pio, SM_CMD); + switch (a) + { + // !READY + // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. + // !READY is a zero when + // the head position is settled on disired track, + // motor is at the desired speed, + // and a diskette is in the drive. + case 0: + // !DIRTN + // This signal sets the direction of head motion. + // A zero sets direction toward the center of the disk and a one sets direction towards outer edge. + // When !ENBL is high !DIRTN is set to zero. + // Change of !DIRTN command is not allowed during head movement nor head settlying time. + // set direction to increase track number + clr_latch(DIRTN); + break; + case 4: + set_latch(DIRTN); + break; + case 1: + // !STEP + // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. + // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. + // step the head + clr_latch(STEP); + set_latch(READY); + step_state = true; + break; + case 2: + // !MOTORON + // When this signal is set to low, the disk motor is turned on. + // When !ENBL is high, /MOTORON is set to high. + // turn motor on + clr_latch(MOTORON); + set_latch(READY); + break; + case 6: + // turn motor off + set_latch(MOTORON); + set_latch(READY); + break; + case 7: + // EJECT + // At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. + // EJECT is set to low at rising edge of !CSTIN or 2 sec maximum after rising edge of EJECT. + // When power is turned on, EJECT is set to low. + // eject + // set_latch(EJECT); // to do - need to clr eject when a disk is inserted - so cheat for now + // set_latch(READY); + break; + default: + printf("\nUNKNOWN PHASE COMMAND"); + break; + } + pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO + uart_putc_raw(UART_ID, (char)(a + '0')); + } + + // !STEP + // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. + // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. + if (step_state) + { + set_latch(STEP); + step_state = false; } + + if (uart_is_readable(uart1)) + { + // !READY + // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. + // !READY is a zero when + // the head position is settled on disired track, + // motor is at the desired speed, + // and a diskette is in the drive. + c = uart_getc(UART_ID); + // to do: figure out when to clear !READY + if (c & 128) + { + if (c == 128) + clr_latch(TKO); // at track zero + // set_tach_freq(c & 127); + } + else + switch (c) + { + case 's': + // single sided disk is in the slot + set_latch(SINGLESIDE); + clr_latch(CSTIN); + clr_latch(WRTPRT); // everythign is write protected for now + break; + case 'd': + // double sided disk + clr_latch(SINGLESIDE); + clr_latch(CSTIN); + clr_latch(WRTPRT); // everythign is write protected for now + break; + case 'S': // step complete (data copied to RMT buffer on ESP32) + case 'M': // motor on + clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met + default: + break; + } + + pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO + } + // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO + // to do: read both enable lines and indicate which drive is active when sending single char to esp32 } + void pio_commands(PIO pio, uint sm, uint offset, uint pin) { commands_program_init(pio, sm, offset, pin); pio_sm_set_enabled(pio, sm, true); diff --git a/pico/mac/commands.pio b/pico/mac/commands.pio index 4a19651ae..5b9edea33 100644 --- a/pico/mac/commands.pio +++ b/pico/mac/commands.pio @@ -6,10 +6,12 @@ ; .define LSTRB 12 +.define ENABLE 7 .program commands start: .wrap_target + wait 0 gpio ENABLE wait 1 gpio LSTRB ; latch strobe in pins, 4 ; get the phases wait 0 gpio LSTRB ; wait for the strobe to deassert diff --git a/pico/mac/latch.pio b/pico/mac/latch.pio index 56326078a..d0d571656 100644 --- a/pico/mac/latch.pio +++ b/pico/mac/latch.pio @@ -5,8 +5,11 @@ ; Reads the drive phases and output a latch bit ; +.define ENABLE 7 + .program latch start: + wait 0 gpio ENABLE mov osr, pins ; read the GPIO's into the output shift register out y, 4 ; shift the 4 LSBs into Y pull noblock ; get the latch word into OSR, if no new word in FIFO, get it from X diff --git a/pico/mac/mux.pio b/pico/mac/mux.pio index 3c16168da..ada87928f 100644 --- a/pico/mac/mux.pio +++ b/pico/mac/mux.pio @@ -9,6 +9,7 @@ .program mux .side_set 3 opt pindirs start: + jmp pin next4 mov osr, pins ; get the input phases out x, 4 ; copy to X set y, 0b0100 ; RDDATA (head 0) @@ -24,7 +25,8 @@ next2: jmp start side 0b001 next3: ; LATCH jmp start side 0b100 - +next4: + jmp start side 0b000 ; enable high (not enabled) % c-sdk { // this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin @@ -35,6 +37,7 @@ void mux_program_init(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin) // config side set sm_config_set_sideset_pins(&c, mux_pin); sm_config_set_in_pins(&c, in_pin); + sm_config_set_jmp_pin(&c, in_pin-1); // there are 4 wires to read for latch mux, shift to the right, no autopull sm_config_set_out_shift(&c, true, false, 4); for (int i=0; i<3; i++) From 3f706fd0502926c271f7f79a48639c67b83489aa Mon Sep 17 00:00:00 2001 From: Eric Carr Date: Fri, 25 Aug 2023 19:51:39 -0500 Subject: [PATCH 018/158] IEC - Make Basic writeappkey to store raw PETSCII chars so appkeys are compatible with Binary mode --- lib/bus/iec/iec.h | 5 +++++ lib/device/iec/fuji.cpp | 38 ++++++++++++++++++++++---------------- lib/device/iec/fuji.h | 2 +- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/bus/iec/iec.h b/lib/bus/iec/iec.h index fa9d92bae..bebc954a3 100644 --- a/lib/bus/iec/iec.h +++ b/lib/bus/iec/iec.h @@ -173,6 +173,11 @@ class virtualDevice */ std::string payload; + /** + * @brief The current device command in raw PETSCII. Used when payload is converted to ASCII for Basic commands + */ + std::string payloadRaw; + /** * @brief pointer to the current command data */ diff --git a/lib/device/iec/fuji.cpp b/lib/device/iec/fuji.cpp index 8279d22e3..01ffbece0 100644 --- a/lib/device/iec/fuji.cpp +++ b/lib/device/iec/fuji.cpp @@ -590,7 +590,9 @@ void iecFuji::write_app_key() { uint16_t keylen = -1; char value[MAX_APPKEY_LEN]; + std::vector ptRaw; + // Binary mode comes through as-is (PETSCII) if (payload[0] == FUJICMD_WRITE_APPKEY) { keylen = payload[1] & 0xFF; @@ -601,8 +603,16 @@ void iecFuji::write_app_key() { if (pt.size() > 2) { + // Tokenize the raw PETSCII payload to save to the file + ptRaw = tokenize_basic_command(payloadRaw); + keylen = atoi(pt[1].c_str()); - strncpy(value, pt[2].c_str(), MAX_APPKEY_LEN); + + // Bounds check + if (keylen > MAX_APPKEY_LEN) + keylen = MAX_APPKEY_LEN; + + strncpy(value, ptRaw[2].c_str(), keylen); } else { @@ -722,15 +732,8 @@ void iecFuji::read_app_key() _r.size = count; - if (payload[0] == FUJICMD_READ_APPKEY) - response = std::string((char *)&_r, MAX_APPKEY_LEN); - else - { - char reply[128]; - memset(reply, 0, sizeof(reply)); - snprintf(reply, sizeof(reply), "\"%04x\",\"%s\"", _r.size, _r.value); - response = std::string(reply); - } + // Bytes were written raw (PETSCII) so no need to map before sending back + response = std::string((char *)&_r, MAX_APPKEY_LEN); } // Disk Image Unmount @@ -1577,8 +1580,11 @@ void iecFuji::local_ip() void iecFuji::process_basic_commands() { + // Store raw payload before mapping to ASCII, in case it is needed (e.g. storing unmodified appkey data) + payloadRaw = payload; + mstr::toASCII(payload); - pt = tokenize_basic_command(); + pt = tokenize_basic_command(payload); if (payload.find("adapterconfig") != std::string::npos) get_adapter_config(); @@ -1777,18 +1783,18 @@ std::string iecFuji::get_host_prefix(int host_slot) Example: "COMMAND:Param1,Param2" will return a vector of [0]="COMMAND", [1]="Param1",[2]="Param2" Also supports "COMMAND,Param1,Param2" */ -vector iecFuji::tokenize_basic_command() +vector iecFuji::tokenize_basic_command(string command) { - Debug_printf("Tokenizing basic command: %s\n", payload.c_str()); + Debug_printf("Tokenizing basic command: %s\n", command.c_str()); // Replace the first ":" with "," for easy tokenization. // Assume it is fine to change the payload at this point. // Technically, "COMMAND,Param1,Param2" will work the smae, if ":" is not in a param value - size_t endOfCommand = payload.find(':'); + size_t endOfCommand = command.find(':'); if (endOfCommand != std::string::npos) - payload.replace(endOfCommand,1,","); + command.replace(endOfCommand,1,","); - vector result = util_tokenize(payload, ','); + vector result = util_tokenize(command, ','); return result; } diff --git a/lib/device/iec/fuji.h b/lib/device/iec/fuji.h index c3104fa7e..140180ceb 100644 --- a/lib/device/iec/fuji.h +++ b/lib/device/iec/fuji.h @@ -72,7 +72,7 @@ class iecFuji : public virtualDevice void process_raw_commands(); void process_basic_commands(); - vector tokenize_basic_command(); + vector tokenize_basic_command(string command); protected: void reset_fujinet(); // 0xFF From 5d50df54f931fa7ebdf8035726a71fd3616fe728 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 25 Aug 2023 20:02:39 -0500 Subject: [PATCH 019/158] typo. --- lib/fnjson/fnjson.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 6a1f16e88..7db9b8144 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -200,7 +200,7 @@ string FNJSON::getValue(cJSON *item) mstr::toPETSCII(tempStr); ss << tempStr; #else - ss << item->string + ss << item->string; #endif ss << lineEnding + getValue(item); From beb1d6464c574454383d26aaf09929a4af46e1e1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 25 Aug 2023 20:10:21 -0500 Subject: [PATCH 020/158] [fnjson][atari] remove ss debug. --- lib/fnjson/fnjson.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 7db9b8144..e85203fe6 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -131,7 +131,6 @@ string FNJSON::processString(string in) in.replace(in.find(mapFrom[elementIndex]), string(mapFrom[elementIndex]).size(), mapTo[elementIndex]); } - Debug_printf("S: [Mapping->ATARI] %s\r\n", ss.str().c_str()); } #endif From 816de7a2cd986ae66d12ec1731a1b9d754d81ced Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 17:21:20 -0500 Subject: [PATCH 021/158] [apple2] add MALLOC override 32768 for apple2. --- sdkconfig.fujiapple-rev0 | 2272 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 2272 insertions(+) create mode 100644 sdkconfig.fujiapple-rev0 diff --git a/sdkconfig.fujiapple-rev0 b/sdkconfig.fujiapple-rev0 new file mode 100644 index 000000000..52b703b1c --- /dev/null +++ b/sdkconfig.fujiapple-rev0 @@ -0,0 +1,2272 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Configuration +# +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" +CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" +CONFIG_SOC_DPORT_WORKAROUND="Not determined" +CONFIG_SOC_CAPS_ECO_VER_MAX=301 +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DAC_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_SDMMC_HOST_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_EMAC_SUPPORTED=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y +CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5 +CONFIG_SOC_XTAL_SUPPORT_26M=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_XTAL_SUPPORT_AUTO_DETECT=y +CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=2 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2 +CONFIG_SOC_ADC_PATT_LEN_MAX=16 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=2 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=2 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=20 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_RTC_SLOW_CLOCK_SUPPORT_8MD256=y +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=5 +CONFIG_SOC_CPU_CORES_NUM=2 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FPU=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINT_SIZE=64 +CONFIG_SOC_DAC_PERIPH_NUM=2 +CONFIG_SOC_DAC_RESOLUTION=8 +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=40 +CONFIG_SOC_GPIO_VALID_GPIO_MASK=0xFFFFFFFFFF +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_APB=y +CONFIG_SOC_CLK_APLL_SUPPORTED=y +CONFIG_SOC_APLL_MULTIPLIER_OUT_MIN_HZ=350000000 +CONFIG_SOC_APLL_MULTIPLIER_OUT_MAX_HZ=500000000 +CONFIG_SOC_APLL_MIN_HZ=5303031 +CONFIG_SOC_APLL_MAX_HZ=125000000 +CONFIG_SOC_I2S_NUM=2 +CONFIG_SOC_I2S_HW_VERSION_1=y +CONFIG_SOC_I2S_SUPPORTS_APLL=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y +CONFIG_SOC_I2S_SUPPORTS_ADC=y +CONFIG_SOC_I2S_SUPPORTS_DAC=y +CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y +CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y +CONFIG_SOC_I2S_LCD_I80_VARIANT=y +CONFIG_SOC_LCD_I80_SUPPORTED=y +CONFIG_SOC_LCD_I80_BUSES=2 +CONFIG_SOC_LCD_I80_BUS_WIDTH=24 +CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y +CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y +CONFIG_SOC_LEDC_CHANNEL_NUM=8 +CONFIG_SOC_LEDC_TIMER_BIT_WIDE_NUM=20 +CONFIG_SOC_MCPWM_GROUPS=2 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=8 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=64 +CONFIG_SOC_RMT_SUPPORT_REF_TICK=y +CONFIG_SOC_RMT_SUPPORT_APB=y +CONFIG_SOC_RMT_CHANNEL_CLK_INDEPENDENT=y +CONFIG_SOC_RTCIO_PIN_COUNT=18 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8 +CONFIG_SOC_SPI_HD_BOTH_INOUT_SUPPORTED=y +CONFIG_SOC_SPI_AS_CS_SUPPORTED=y +CONFIG_SOC_SPI_PERIPH_NUM=3 +CONFIG_SOC_SPI_DMA_CHAN_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=3 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=8192 +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 +CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y +CONFIG_SOC_TOUCH_VERSION_1=y +CONFIG_SOC_TOUCH_SENSOR_NUM=10 +CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +CONFIG_SOC_UART_SUPPORT_REF_TICK=y +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_SPIRAM_SUPPORTED=y +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SHA_SUPPORT_SHA384=y +CONFIG_SOC_SHA_SUPPORT_SHA512=y +CONFIG_SOC_RSA_MAX_BIT_LEN=4096 +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_192=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_SECURE_BOOT_V1=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_FAST_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_SLOW_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_SDMMC_USE_IOMUX=y +CONFIG_SOC_SDMMC_NUM_SLOTS=2 +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_BT_CLASSIC_SUPPORTED=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET_ARCH="xtensa" +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# end of Build type + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=2 +# CONFIG_BOOTLOADER_SPI_CUSTOM_WP_PIN is not set +CONFIG_BOOTLOADER_SPI_WP_PIN=7 +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V1_SUPPORTED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +# CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_NONE is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NORM=y +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +CONFIG_COMPILER_STACK_CHECK=y +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=y +# CONFIG_BT_NIMBLE_ENABLED is not set +# CONFIG_BT_CONTROLLER_ONLY is not set +CONFIG_BT_CONTROLLER_ENABLED=y +# CONFIG_BT_CONTROLLER_DISABLED is not set + +# +# Bluedroid Options +# +CONFIG_BT_BTC_TASK_STACK_SIZE=3072 +CONFIG_BT_BLUEDROID_PINNED_TO_CORE_0=y +# CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1 is not set +CONFIG_BT_BLUEDROID_PINNED_TO_CORE=0 +CONFIG_BT_BTU_TASK_STACK_SIZE=4096 +# CONFIG_BT_BLUEDROID_MEM_DEBUG is not set +CONFIG_BT_CLASSIC_ENABLED=y +# CONFIG_BT_A2DP_ENABLE is not set +CONFIG_BT_SPP_ENABLED=y +# CONFIG_BT_L2CAP_ENABLED is not set +# CONFIG_BT_HFP_ENABLE is not set +# CONFIG_BT_HID_ENABLED is not set +CONFIG_BT_SSP_ENABLED=y +# CONFIG_BT_BLE_ENABLED is not set +# CONFIG_BT_STACK_NO_LOG is not set + +# +# BT DEBUG LOG LEVEL +# +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_HCI_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BTM_TRACE_LEVEL=2 +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2 +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_SDP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_GAP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_PAN_TRACE_LEVEL=2 +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_A2D_TRACE_LEVEL=2 +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2 +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2 +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2 +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_MCA_TRACE_LEVEL=2 +# CONFIG_BT_LOG_HID_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_HID_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_HID_TRACE_LEVEL=2 +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_APPL_TRACE_LEVEL=2 +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_GATT_TRACE_LEVEL=2 +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_SMP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BTC_TRACE_LEVEL=2 +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_OSI_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2 +# end of BT DEBUG LOG LEVEL + +CONFIG_BT_ACL_CONNECTIONS=4 +CONFIG_BT_MULTI_CONNECTION_ENBALE=y +CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y +CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y +# CONFIG_BT_BLE_HOST_QUEUE_CONG_CHECK is not set +CONFIG_BT_SMP_ENABLE=y +CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT=30 +CONFIG_BT_MAX_DEVICE_NAME_LEN=32 +# CONFIG_BT_BLE_RPA_SUPPORTED is not set +# end of Bluedroid Options + +# +# Controller Options +# +# CONFIG_BTDM_CTRL_MODE_BLE_ONLY is not set +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y +# CONFIG_BTDM_CTRL_MODE_BTDM is not set +CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=2 +CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0 +# CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set +CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM=y +CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=1 +CONFIG_BTDM_CTRL_PCM_ROLE_EDGE_CONFIG=y +CONFIG_BTDM_CTRL_PCM_ROLE_MASTER=y +# CONFIG_BTDM_CTRL_PCM_ROLE_SLAVE is not set +CONFIG_BTDM_CTRL_PCM_POLAR_FALLING_EDGE=y +# CONFIG_BTDM_CTRL_PCM_POLAR_RISING_EDGE is not set +CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 +CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 +CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT=y +CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF=y +CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 +CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2 +CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 +CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y +# CONFIG_BTDM_CTRL_PINNED_TO_CORE_1 is not set +CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 +CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y +# CONFIG_BTDM_CTRL_HCI_MODE_UART_H4 is not set + +# +# MODEM SLEEP Options +# +CONFIG_BTDM_CTRL_MODEM_SLEEP=y +CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG=y +# CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED is not set +CONFIG_BTDM_CTRL_LPCLK_SEL_MAIN_XTAL=y +# end of MODEM SLEEP Options + +CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 +CONFIG_BTDM_RESERVE_DRAM=0xdb5c +CONFIG_BTDM_CTRL_HLI=y +# end of Controller Options +# end of Bluetooth + +# CONFIG_BLE_MESH is not set + +# +# Driver Configurations +# + +# +# Legacy ADC Configuration +# +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y +CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CAL_LUT_ENABLE=y +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Configuration + +# +# SPI Configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI Configuration + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y +CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y +CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y +CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y +CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y +# end of TWAI Configuration + +# +# UART Configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART Configuration + +# +# GPIO Configuration +# +# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of GPIO Configuration + +# +# Sigma Delta Modulator Configuration +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of Sigma Delta Modulator Configuration + +# +# GPTimer Configuration +# +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of GPTimer Configuration + +# +# PCNT Configuration +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of PCNT Configuration + +# +# RMT Configuration +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of RMT Configuration + +# +# MCPWM Configuration +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of MCPWM Configuration + +# +# I2S Configuration +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of I2S Configuration +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set +CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set +CONFIG_EFUSE_MAX_BLK_LEN=192 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +CONFIG_ESP_TLS_INSECURE=y +CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set + +# +# ADC Calibration Configurations +# +CONFIG_ADC_CALI_EFUSE_TP_ENABLE=y +CONFIG_ADC_CALI_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CALI_LUT_ENABLE=y +# end of ADC Calibration Configurations + +CONFIG_ADC_DISABLE_DAC_OUTPUT=y +# end of ADC and ADC Calibration + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +CONFIG_ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_ESP32_EMAC=y +CONFIG_ETH_PHY_INTERFACE_RMII=y +CONFIG_ETH_RMII_CLK_INPUT=y +# CONFIG_ETH_RMII_CLK_OUTPUT is not set +CONFIG_ETH_RMII_CLK_IN_GPIO=0 +CONFIG_ETH_DMA_BUFFER_SIZE=512 +CONFIG_ETH_DMA_RX_BUFFER_NUM=10 +CONFIG_ETH_DMA_TX_BUFFER_NUM=10 +CONFIG_ETH_USE_SPI_ETHERNET=y +CONFIG_ETH_SPI_ETHERNET_DM9051=y +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +CONFIG_HTTPD_WS_SUPPORT=y +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32_REV_MIN_0=y +# CONFIG_ESP32_REV_MIN_1 is not set +# CONFIG_ESP32_REV_MIN_1_1 is not set +# CONFIG_ESP32_REV_MIN_2 is not set +# CONFIG_ESP32_REV_MIN_3 is not set +# CONFIG_ESP32_REV_MIN_3_1 is not set +CONFIG_ESP32_REV_MIN=0 +CONFIG_ESP32_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32 Revision (Rev v3.99) +# +CONFIG_ESP32_REV_MAX_FULL=399 +CONFIG_ESP_REV_MAX_FULL=399 +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set +# end of MAC Config + +# +# Sleep Config +# +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set +CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000 +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +# CONFIG_PERIPH_CTRL_FUNC_IN_IRAM is not set +# end of Peripheral Control + +# +# Main XTAL Config +# +# CONFIG_XTAL_FREQ_26 is not set +CONFIG_XTAL_FREQ_40=y +# CONFIG_XTAL_FREQ_AUTO is not set +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config +# end of Hardware Settings + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# end of ESP NETIF Adapter + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +CONFIG_ESP_PHY_REDUCE_TX_POWER=y +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +# end of Power Management + +# +# ESP PSRAM +# +CONFIG_SPIRAM=y + +# +# SPI RAM config +# +CONFIG_SPIRAM_MODE_QUAD=y +CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SPEED_40M=y +# CONFIG_SPIRAM_SPEED_80M is not set +CONFIG_SPIRAM_SPEED=40 +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_USE_MEMMAP is not set +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +CONFIG_SPIRAM_USE_MALLOC=y +# CONFIG_SPIRAM_MEMTEST is not set +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=32768 +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set +CONFIG_SPIRAM_CACHE_WORKAROUND=y + +# +# SPIRAM cache workaround debugging +# +CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set +# end of SPIRAM cache workaround debugging + +# +# SPIRAM workaround libraries placement +# +CONFIG_SPIRAM_CACHE_LIBJMP_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBMATH_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBIO_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBTIME_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBCHAR_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBMEM_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBSTR_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBRAND_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBENV_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBFILE_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM=y +# end of SPIRAM workaround libraries placement + +CONFIG_SPIRAM_BANKSWITCH_ENABLE=y +CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 +# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set + +# +# PSRAM clock and cs IO for ESP32-DOWD +# +CONFIG_D0WD_PSRAM_CLK_IO=17 +CONFIG_D0WD_PSRAM_CS_IO=16 +# end of PSRAM clock and cs IO for ESP32-DOWD + +# +# PSRAM clock and cs IO for ESP32-D2WD +# +CONFIG_D2WD_PSRAM_CLK_IO=9 +CONFIG_D2WD_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-D2WD + +# +# PSRAM clock and cs IO for ESP32-PICO +# +CONFIG_PICO_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-PICO + +# CONFIG_SPIRAM_2T_MODE is not set +# end of SPI RAM config +# end of ESP PSRAM + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240 + +# +# Memory +# +# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set +# end of Memory + +# +# Trace memory +# +# CONFIG_ESP32_TRAX is not set +CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 +# end of Trace memory + +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=800 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=0 +# end of Brownout Detector + +# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_TG0_LAC=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=128 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=32 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=32 +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +# CONFIG_ESP32_WIFI_IRAM_OPT is not set +# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +# CONFIG_FATFS_SECTOR_512 is not set +# CONFIG_FATFS_SECTOR_1024 is not set +# CONFIG_FATFS_SECTOR_2048 is not set +CONFIG_FATFS_SECTOR_4096=y +CONFIG_FATFS_SECTORS_PER_CLUSTER_1=y +# CONFIG_FATFS_SECTORS_PER_CLUSTER_2 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_4 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_8 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_16 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_32 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_64 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_128 is not set +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_AUTO_TYPE=y +# CONFIG_FATFS_FAT12 is not set +# CONFIG_FATFS_FAT16 is not set +CONFIG_FATFS_CODEPAGE=437 +# CONFIG_FATFS_LFN_NONE is not set +CONFIG_FATFS_LFN_HEAP=y +# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_MAX_LFN=255 +CONFIG_FATFS_API_ENCODING_ANSI_OEM=y +# CONFIG_FATFS_API_ENCODING_UTF_8 is not set +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_HZ=100 +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y +CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y +CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +# CONFIG_FREERTOS_FPU_IN_ISR is not set +CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y +CONFIG_FREERTOS_CORETIMER_0=y +# CONFIG_FREERTOS_CORETIMER_1 is not set +CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y +CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y +# CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK is not set +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# end of Port + +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +# CONFIG_HEAP_POISONING_DISABLED is not set +CONFIG_HEAP_POISONING_LIGHT=y +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +# CONFIG_HEAP_TRACING_OFF is not set +CONFIG_HEAP_TRACING_STANDALONE=y +# CONFIG_HEAP_TRACING_TOHOST is not set +CONFIG_HEAP_TRACING=y +CONFIG_HEAP_TRACING_STACK_DEPTH=2 +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +CONFIG_LOG_DEFAULT_LEVEL_ERROR=y +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=1 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_WARN is not set +# CONFIG_LOG_MAXIMUM_LEVEL_INFO is not set +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=1 +# CONFIG_LOG_COLORS is not set +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="fujinet" +# CONFIG_LWIP_NETIF_API is not set +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +CONFIG_LWIP_SO_RCVBUF=y +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=6 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534 +CONFIG_LWIP_TCP_WND_DEFAULT=65534 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=64 +# CONFIG_LWIP_TCP_QUEUE_OOSEQ is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +# CONFIG_LWIP_WND_SCALE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=64 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +CONFIG_LWIP_DEBUG=y +# CONFIG_LWIP_DEBUG_ESP_LOG is not set +# CONFIG_LWIP_NETIF_DEBUG is not set +# CONFIG_LWIP_PBUF_DEBUG is not set +# CONFIG_LWIP_ETHARP_DEBUG is not set +# CONFIG_LWIP_API_LIB_DEBUG is not set +# CONFIG_LWIP_SOCKETS_DEBUG is not set +# CONFIG_LWIP_IP_DEBUG is not set +# CONFIG_LWIP_ICMP_DEBUG is not set +# CONFIG_LWIP_DHCP_STATE_DEBUG is not set +# CONFIG_LWIP_DHCP_DEBUG is not set +# CONFIG_LWIP_IP6_DEBUG is not set +# CONFIG_LWIP_ICMP6_DEBUG is not set +# CONFIG_LWIP_TCP_DEBUG is not set +# CONFIG_LWIP_SNTP_DEBUG is not set +# CONFIG_LWIP_DNS_DEBUG is not set +# CONFIG_LWIP_BRIDGEIF_DEBUG is not set +# CONFIG_LWIP_BRIDGEIF_FDB_DEBUG is not set +# CONFIG_LWIP_BRIDGEIF_FW_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set +CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# CONFIG_MBEDTLS_CMAC_C is not set +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +CONFIG_MBEDTLS_POLY1305_C=y +CONFIG_MBEDTLS_CHACHA20_C=y +# CONFIG_MBEDTLS_CHACHAPOLY_C is not set +CONFIG_MBEDTLS_HKDF_C=y +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Root Hub configuration +# +# end of Root Hub configuration + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_BONDING is not set +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# end of Supplicant + +# +# mDNS +# +CONFIG_MDNS_MAX_INTERFACES=3 +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +# CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES is not set +# CONFIG_MDNS_ENABLE_DEBUG_PRINTS is not set +# CONFIG_MDNS_RESPOND_REVERSE_QUERIES is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y + +# +# MDNS Predefined interfaces +# +CONFIG_MDNS_PREDEF_NETIF_STA=y +CONFIG_MDNS_PREDEF_NETIF_AP=y +CONFIG_MDNS_PREDEF_NETIF_ETH=y +# end of MDNS Predefined interfaces +# end of mDNS + +# +# LittleFS +# +CONFIG_LITTLEFS_MAX_PARTITIONS=3 +CONFIG_LITTLEFS_PAGE_SIZE=256 +CONFIG_LITTLEFS_OBJ_NAME_LEN=64 +CONFIG_LITTLEFS_READ_SIZE=128 +CONFIG_LITTLEFS_WRITE_SIZE=128 +CONFIG_LITTLEFS_LOOKAHEAD_SIZE=128 +CONFIG_LITTLEFS_CACHE_SIZE=512 +CONFIG_LITTLEFS_BLOCK_CYCLES=512 +CONFIG_LITTLEFS_USE_MTIME=y +# CONFIG_LITTLEFS_USE_ONLY_HASH is not set +# CONFIG_LITTLEFS_HUMAN_READABLE is not set +CONFIG_LITTLEFS_MTIME_USE_SECONDS=y +# CONFIG_LITTLEFS_MTIME_USE_NONCE is not set +# CONFIG_LITTLEFS_SPIFFS_COMPAT is not set +# CONFIG_LITTLEFS_FLUSH_FILE_EVERY_WRITE is not set +# end of LittleFS +# end of Component config + +# Deprecated options for backward compatibility +# CONFIG_NO_BLOBS is not set +# CONFIG_ESP32_NO_BLOBS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=2 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +CONFIG_FLASHMODE_QIO=y +# CONFIG_FLASHMODE_QOUT is not set +# CONFIG_FLASHMODE_DIO is not set +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +# CONFIG_STACK_CHECK_NONE is not set +CONFIG_STACK_CHECK_NORM=y +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +CONFIG_STACK_CHECK=y +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_BLUEDROID_ENABLED=y +# CONFIG_NIMBLE_ENABLED is not set +CONFIG_BTC_TASK_STACK_SIZE=3072 +CONFIG_BLUEDROID_PINNED_TO_CORE_0=y +# CONFIG_BLUEDROID_PINNED_TO_CORE_1 is not set +CONFIG_BLUEDROID_PINNED_TO_CORE=0 +CONFIG_BTU_TASK_STACK_SIZE=4096 +# CONFIG_BLUEDROID_MEM_DEBUG is not set +CONFIG_CLASSIC_BT_ENABLED=y +# CONFIG_A2DP_ENABLE is not set +# CONFIG_HFP_ENABLE is not set +# CONFIG_HCI_TRACE_LEVEL_NONE is not set +# CONFIG_HCI_TRACE_LEVEL_ERROR is not set +CONFIG_HCI_TRACE_LEVEL_WARNING=y +# CONFIG_HCI_TRACE_LEVEL_API is not set +# CONFIG_HCI_TRACE_LEVEL_EVENT is not set +# CONFIG_HCI_TRACE_LEVEL_DEBUG is not set +# CONFIG_HCI_TRACE_LEVEL_VERBOSE is not set +CONFIG_HCI_INITIAL_TRACE_LEVEL=2 +# CONFIG_BTM_TRACE_LEVEL_NONE is not set +# CONFIG_BTM_TRACE_LEVEL_ERROR is not set +CONFIG_BTM_TRACE_LEVEL_WARNING=y +# CONFIG_BTM_TRACE_LEVEL_API is not set +# CONFIG_BTM_TRACE_LEVEL_EVENT is not set +# CONFIG_BTM_TRACE_LEVEL_DEBUG is not set +# CONFIG_BTM_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTM_INITIAL_TRACE_LEVEL=2 +# CONFIG_L2CAP_TRACE_LEVEL_NONE is not set +# CONFIG_L2CAP_TRACE_LEVEL_ERROR is not set +CONFIG_L2CAP_TRACE_LEVEL_WARNING=y +# CONFIG_L2CAP_TRACE_LEVEL_API is not set +# CONFIG_L2CAP_TRACE_LEVEL_EVENT is not set +# CONFIG_L2CAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_L2CAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_L2CAP_INITIAL_TRACE_LEVEL=2 +# CONFIG_RFCOMM_TRACE_LEVEL_NONE is not set +# CONFIG_RFCOMM_TRACE_LEVEL_ERROR is not set +CONFIG_RFCOMM_TRACE_LEVEL_WARNING=y +# CONFIG_RFCOMM_TRACE_LEVEL_API is not set +# CONFIG_RFCOMM_TRACE_LEVEL_EVENT is not set +# CONFIG_RFCOMM_TRACE_LEVEL_DEBUG is not set +# CONFIG_RFCOMM_TRACE_LEVEL_VERBOSE is not set +CONFIG_RFCOMM_INITIAL_TRACE_LEVEL=2 +# CONFIG_SDP_TRACE_LEVEL_NONE is not set +# CONFIG_SDP_TRACE_LEVEL_ERROR is not set +CONFIG_SDP_TRACE_LEVEL_WARNING=y +# CONFIG_SDP_TRACE_LEVEL_API is not set +# CONFIG_SDP_TRACE_LEVEL_EVENT is not set +# CONFIG_SDP_TRACE_LEVEL_DEBUG is not set +# CONFIG_SDP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTH_LOG_SDP_INITIAL_TRACE_LEVEL=2 +# CONFIG_GAP_TRACE_LEVEL_NONE is not set +# CONFIG_GAP_TRACE_LEVEL_ERROR is not set +CONFIG_GAP_TRACE_LEVEL_WARNING=y +# CONFIG_GAP_TRACE_LEVEL_API is not set +# CONFIG_GAP_TRACE_LEVEL_EVENT is not set +# CONFIG_GAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_GAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_GAP_INITIAL_TRACE_LEVEL=2 +CONFIG_BNEP_INITIAL_TRACE_LEVEL=2 +# CONFIG_PAN_TRACE_LEVEL_NONE is not set +# CONFIG_PAN_TRACE_LEVEL_ERROR is not set +CONFIG_PAN_TRACE_LEVEL_WARNING=y +# CONFIG_PAN_TRACE_LEVEL_API is not set +# CONFIG_PAN_TRACE_LEVEL_EVENT is not set +# CONFIG_PAN_TRACE_LEVEL_DEBUG is not set +# CONFIG_PAN_TRACE_LEVEL_VERBOSE is not set +CONFIG_PAN_INITIAL_TRACE_LEVEL=2 +# CONFIG_A2D_TRACE_LEVEL_NONE is not set +# CONFIG_A2D_TRACE_LEVEL_ERROR is not set +CONFIG_A2D_TRACE_LEVEL_WARNING=y +# CONFIG_A2D_TRACE_LEVEL_API is not set +# CONFIG_A2D_TRACE_LEVEL_EVENT is not set +# CONFIG_A2D_TRACE_LEVEL_DEBUG is not set +# CONFIG_A2D_TRACE_LEVEL_VERBOSE is not set +CONFIG_A2D_INITIAL_TRACE_LEVEL=2 +# CONFIG_AVDT_TRACE_LEVEL_NONE is not set +# CONFIG_AVDT_TRACE_LEVEL_ERROR is not set +CONFIG_AVDT_TRACE_LEVEL_WARNING=y +# CONFIG_AVDT_TRACE_LEVEL_API is not set +# CONFIG_AVDT_TRACE_LEVEL_EVENT is not set +# CONFIG_AVDT_TRACE_LEVEL_DEBUG is not set +# CONFIG_AVDT_TRACE_LEVEL_VERBOSE is not set +CONFIG_AVDT_INITIAL_TRACE_LEVEL=2 +# CONFIG_AVCT_TRACE_LEVEL_NONE is not set +# CONFIG_AVCT_TRACE_LEVEL_ERROR is not set +CONFIG_AVCT_TRACE_LEVEL_WARNING=y +# CONFIG_AVCT_TRACE_LEVEL_API is not set +# CONFIG_AVCT_TRACE_LEVEL_EVENT is not set +# CONFIG_AVCT_TRACE_LEVEL_DEBUG is not set +# CONFIG_AVCT_TRACE_LEVEL_VERBOSE is not set +CONFIG_AVCT_INITIAL_TRACE_LEVEL=2 +# CONFIG_AVRC_TRACE_LEVEL_NONE is not set +# CONFIG_AVRC_TRACE_LEVEL_ERROR is not set +CONFIG_AVRC_TRACE_LEVEL_WARNING=y +# CONFIG_AVRC_TRACE_LEVEL_API is not set +# CONFIG_AVRC_TRACE_LEVEL_EVENT is not set +# CONFIG_AVRC_TRACE_LEVEL_DEBUG is not set +# CONFIG_AVRC_TRACE_LEVEL_VERBOSE is not set +CONFIG_AVRC_INITIAL_TRACE_LEVEL=2 +# CONFIG_MCA_TRACE_LEVEL_NONE is not set +# CONFIG_MCA_TRACE_LEVEL_ERROR is not set +CONFIG_MCA_TRACE_LEVEL_WARNING=y +# CONFIG_MCA_TRACE_LEVEL_API is not set +# CONFIG_MCA_TRACE_LEVEL_EVENT is not set +# CONFIG_MCA_TRACE_LEVEL_DEBUG is not set +# CONFIG_MCA_TRACE_LEVEL_VERBOSE is not set +CONFIG_MCA_INITIAL_TRACE_LEVEL=2 +# CONFIG_HID_TRACE_LEVEL_NONE is not set +# CONFIG_HID_TRACE_LEVEL_ERROR is not set +CONFIG_HID_TRACE_LEVEL_WARNING=y +# CONFIG_HID_TRACE_LEVEL_API is not set +# CONFIG_HID_TRACE_LEVEL_EVENT is not set +# CONFIG_HID_TRACE_LEVEL_DEBUG is not set +# CONFIG_HID_TRACE_LEVEL_VERBOSE is not set +CONFIG_HID_INITIAL_TRACE_LEVEL=2 +# CONFIG_APPL_TRACE_LEVEL_NONE is not set +# CONFIG_APPL_TRACE_LEVEL_ERROR is not set +CONFIG_APPL_TRACE_LEVEL_WARNING=y +# CONFIG_APPL_TRACE_LEVEL_API is not set +# CONFIG_APPL_TRACE_LEVEL_EVENT is not set +# CONFIG_APPL_TRACE_LEVEL_DEBUG is not set +# CONFIG_APPL_TRACE_LEVEL_VERBOSE is not set +CONFIG_APPL_INITIAL_TRACE_LEVEL=2 +# CONFIG_GATT_TRACE_LEVEL_NONE is not set +# CONFIG_GATT_TRACE_LEVEL_ERROR is not set +CONFIG_GATT_TRACE_LEVEL_WARNING=y +# CONFIG_GATT_TRACE_LEVEL_API is not set +# CONFIG_GATT_TRACE_LEVEL_EVENT is not set +# CONFIG_GATT_TRACE_LEVEL_DEBUG is not set +# CONFIG_GATT_TRACE_LEVEL_VERBOSE is not set +CONFIG_GATT_INITIAL_TRACE_LEVEL=2 +# CONFIG_SMP_TRACE_LEVEL_NONE is not set +# CONFIG_SMP_TRACE_LEVEL_ERROR is not set +CONFIG_SMP_TRACE_LEVEL_WARNING=y +# CONFIG_SMP_TRACE_LEVEL_API is not set +# CONFIG_SMP_TRACE_LEVEL_EVENT is not set +# CONFIG_SMP_TRACE_LEVEL_DEBUG is not set +# CONFIG_SMP_TRACE_LEVEL_VERBOSE is not set +CONFIG_SMP_INITIAL_TRACE_LEVEL=2 +# CONFIG_BTIF_TRACE_LEVEL_NONE is not set +# CONFIG_BTIF_TRACE_LEVEL_ERROR is not set +CONFIG_BTIF_TRACE_LEVEL_WARNING=y +# CONFIG_BTIF_TRACE_LEVEL_API is not set +# CONFIG_BTIF_TRACE_LEVEL_EVENT is not set +# CONFIG_BTIF_TRACE_LEVEL_DEBUG is not set +# CONFIG_BTIF_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTIF_INITIAL_TRACE_LEVEL=2 +# CONFIG_BTC_TRACE_LEVEL_NONE is not set +# CONFIG_BTC_TRACE_LEVEL_ERROR is not set +CONFIG_BTC_TRACE_LEVEL_WARNING=y +# CONFIG_BTC_TRACE_LEVEL_API is not set +# CONFIG_BTC_TRACE_LEVEL_EVENT is not set +# CONFIG_BTC_TRACE_LEVEL_DEBUG is not set +# CONFIG_BTC_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTC_INITIAL_TRACE_LEVEL=2 +# CONFIG_OSI_TRACE_LEVEL_NONE is not set +# CONFIG_OSI_TRACE_LEVEL_ERROR is not set +CONFIG_OSI_TRACE_LEVEL_WARNING=y +# CONFIG_OSI_TRACE_LEVEL_API is not set +# CONFIG_OSI_TRACE_LEVEL_EVENT is not set +# CONFIG_OSI_TRACE_LEVEL_DEBUG is not set +# CONFIG_OSI_TRACE_LEVEL_VERBOSE is not set +CONFIG_OSI_INITIAL_TRACE_LEVEL=2 +# CONFIG_BLUFI_TRACE_LEVEL_NONE is not set +# CONFIG_BLUFI_TRACE_LEVEL_ERROR is not set +CONFIG_BLUFI_TRACE_LEVEL_WARNING=y +# CONFIG_BLUFI_TRACE_LEVEL_API is not set +# CONFIG_BLUFI_TRACE_LEVEL_EVENT is not set +# CONFIG_BLUFI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BLUFI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BLUFI_INITIAL_TRACE_LEVEL=2 +# CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK is not set +CONFIG_SMP_ENABLE=y +CONFIG_BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT=30 +# CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY is not set +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=y +# CONFIG_BTDM_CONTROLLER_MODE_BTDM is not set +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN=2 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN=0 +CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=2 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 +CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 +CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y +# CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4 is not set +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=y +CONFIG_ADC2_DISABLE_DAC=y +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set +CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y +CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y +CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y +# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set +# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set +# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set +CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 +# CONFIG_ESP32_XTAL_FREQ_26 is not set +CONFIG_ESP32_XTAL_FREQ_40=y +# CONFIG_ESP32_XTAL_FREQ_AUTO is not set +CONFIG_ESP32_XTAL_FREQ=40 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +CONFIG_REDUCE_PHY_TX_POWER=y +CONFIG_ESP32_REDUCE_PHY_TX_POWER=y +CONFIG_SPIRAM_SUPPORT=y +CONFIG_ESP32_SPIRAM_SUPPORT=y +CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=y +# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set +# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 +CONFIG_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32_PANIC_PRINT_HALT is not set +CONFIG_ESP32_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32_PANIC_GDBSTUB is not set +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4096 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=800 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +# CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set +# CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32_DEBUG_OCDAWARE=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_0=y +CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_BROWNOUT_DET_LVL=0 +CONFIG_ESP32_BROWNOUT_DET_LVL=0 +# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_SW_COEXIST_ENABLE=y +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=64 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=6 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=65534 +CONFIG_TCP_WND_DEFAULT=65534 +CONFIG_TCP_RECVMBOX_SIZE=64 +# CONFIG_TCP_QUEUE_OOSEQ is not set +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=64 +CONFIG_TCPIP_TASK_STACK_SIZE=4096 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_HRT is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_ESP32_ULP_COPROC_ENABLED is not set +# End of deprecated options From b3ebddebbfe06ab6d35d34c960ca680b57ab9af4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 17:22:29 -0500 Subject: [PATCH 022/158] [adamnet][fuji] change ack timing. --- lib/device/adamnet/fuji.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 4072e8ccc..d5d383d6e 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -284,6 +284,9 @@ void adamFuji::adamnet_disk_image_mount() adamnet_recv(); // CK + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); + // TODO: Implement FETCH? char flag[3] = {'r', 0, 0}; if (options == DISK_ACCESS_MODE_WRITE) @@ -298,9 +301,6 @@ void adamFuji::adamnet_disk_image_mount() disk.disk_dev.host = &host; - AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); - disk.fileh = host.file_open(disk.filename, disk.filename, sizeof(disk.filename), flag); // We've gotten this far, so make sure our bootable CONFIG disk is disabled From 7902d5834949f18d4c7f333ff62a73c07f5ccef5 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 18:23:51 -0500 Subject: [PATCH 023/158] [adamnet] add adamnet_message_t --- lib/bus/adamnet/adamnet.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/bus/adamnet/adamnet.h b/lib/bus/adamnet/adamnet.h index 09134662d..254d86dbc 100755 --- a/lib/bus/adamnet/adamnet.h +++ b/lib/bus/adamnet/adamnet.h @@ -10,6 +10,16 @@ #include +enum adamnet_message : uint16_t +{ + SIOMSG_DISKSWAP // Rotate disk +}; + +struct adamnet_message_t +{ + adamnet_message message_id; + uint16_t message_arg; +}; #define ADAMNET_BAUDRATE 62500 From a22fe252945f06a59140ea0e842a018fa042aea2 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 18:31:54 -0500 Subject: [PATCH 024/158] [adamnet] call _adamnet_process_queue in service --- lib/bus/adamnet/adamnet.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 906a94212..49cdaefe0 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -291,6 +291,9 @@ void systemBus::_adamnet_process_queue() void systemBus::service() { + // process queue messages (disk swap) + _adamnet_process_queue(); + // Process anything waiting. if (fnUartBUS.available() > 0) _adamnet_process_cmd(); From 70bc8cebe09364de9d2f8f92a190e32f2004ec71 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 18:44:11 -0500 Subject: [PATCH 025/158] [adamnet] implement adamnet_process_queue --- lib/bus/adamnet/adamnet.cpp | 14 +++++++++++++- lib/bus/adamnet/adamnet.h | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 49cdaefe0..e097a3a55 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -10,6 +10,7 @@ #include "fnSystem.h" #include "led.h" #include +#include "fuji.h" #define IDLE_TIME 180 // Idle tolerance in microseconds @@ -287,13 +288,24 @@ void systemBus::_adamnet_process_cmd() void systemBus::_adamnet_process_queue() { + adamnet_message_t msg; + if (xQueueReceive(qAdamNetMessages, &msg, 0) == pdTRUE) + { + switch (msg.message_id) + { + case ADAMNETMSG_DISKSWAP: + if (_fujiDev != nullptr) + _fujiDev->image_rotate(); + break; + } + } } void systemBus::service() { // process queue messages (disk swap) _adamnet_process_queue(); - + // Process anything waiting. if (fnUartBUS.available() > 0) _adamnet_process_cmd(); diff --git a/lib/bus/adamnet/adamnet.h b/lib/bus/adamnet/adamnet.h index 254d86dbc..961a4432c 100755 --- a/lib/bus/adamnet/adamnet.h +++ b/lib/bus/adamnet/adamnet.h @@ -12,7 +12,7 @@ enum adamnet_message : uint16_t { - SIOMSG_DISKSWAP // Rotate disk + ADAMNETMSG_DISKSWAP // Rotate disk }; struct adamnet_message_t From cb0b4cd7c99d0361fd969cfb97a8c2bed63b5734 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 18:49:57 -0500 Subject: [PATCH 026/158] [adamnet] queue message init. --- lib/bus/adamnet/adamnet.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index e097a3a55..e705cf06c 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -317,6 +317,9 @@ void systemBus::setup() // Set up interrupt for RESET line reset_evt_queue = xQueueCreate(10, sizeof(uint32_t)); + // Set up event queue + qAdamNetMessages = xQueueCreate(4, sizeof(adamnet_message_t)); + // Start card detect task xTaskCreate(adamnet_reset_intr_task, "adamnet_reset_intr_task", 2048, this, 10, NULL); // Enable interrupt for card detection From b12ebaa9c9e224d2d04bdf2deafdb53d7fcadd72 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 18:50:20 -0500 Subject: [PATCH 027/158] [adamnet][fuji] temp comment out image_rotate --- lib/device/adamnet/fuji.cpp | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index d5d383d6e..9c47c24fe 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -526,28 +526,28 @@ void adamFuji::image_rotate() { Debug_println("Fuji cmd: IMAGE ROTATE"); - int count = 0; - // Find the first empty slot - while (_fnDisks[count].fileh != nullptr) - count++; - - if (count > 1) - { - count--; - - // Save the device ID of the disk in the last slot - int last_id = _fnDisks[count].disk_dev.id(); - - for (int n = count; n > 0; n--) - { - int swap = _fnDisks[n - 1].disk_dev.id(); - Debug_printf("setting slot %d to ID %hx\n", n, swap); - _adamnet_bus->changeDeviceId(&_fnDisks[n].disk_dev, swap); - } - - // The first slot gets the device ID of the last slot - _adamnet_bus->changeDeviceId(&_fnDisks[0].disk_dev, last_id); - } + // int count = 0; + // // Find the first empty slot + // while (_fnDisks[count].fileh != nullptr) + // count++; + + // if (count > 1) + // { + // count--; + + // // Save the device ID of the disk in the last slot + // int last_id = _fnDisks[count].disk_dev.id(); + + // for (int n = count; n > 0; n--) + // { + // int swap = _fnDisks[n - 1].disk_dev.id(); + // Debug_printf("setting slot %d to ID %hx\n", n, swap); + // _adamnet_bus->changeDeviceId(&_fnDisks[n].disk_dev, swap); + // } + + // // The first slot gets the device ID of the last slot + // _adamnet_bus->changeDeviceId(&_fnDisks[0].disk_dev, last_id); + // } } // This gets called when we're about to shutdown/reboot From 5a1c937ca41fc68e8d9575999d00e03d24156bd6 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 26 Aug 2023 18:54:05 -0500 Subject: [PATCH 028/158] [keys] add disk swap key for adam --- lib/hardware/keys.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/hardware/keys.cpp b/lib/hardware/keys.cpp index 4fcffbcfc..94af2adba 100755 --- a/lib/hardware/keys.cpp +++ b/lib/hardware/keys.cpp @@ -290,6 +290,12 @@ void KeyManager::_keystate_task(void *param) msg.message_id = SIOMSG_DISKSWAP; xQueueSend(SIO.qSioMessages, &msg, 0); #endif /* BUILD_ATARI */ +#ifdef BUILD_ADAM + Debug_println("ACTION: Send image_rotate message to SIO queue"); + adamnet_message_t msg; + msg.message_id = ADAMNETMSG_DISKSWAP; + xQueueSend(AdamNet.qAdamNetMessages, &msg, 0); +#endif /* BUILD_ADAM*/ } break; From eb3602295d845fb9291c1613bb95241454557da4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 27 Aug 2023 18:06:11 -0500 Subject: [PATCH 029/158] [adamnet] image_rotate commented out. --- lib/device/adamnet/fuji.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 9c47c24fe..35b57d9a6 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -524,17 +524,20 @@ void adamFuji::adamnet_disk_image_umount() */ void adamFuji::image_rotate() { - Debug_println("Fuji cmd: IMAGE ROTATE"); + // Debug_println("Fuji cmd: IMAGE ROTATE"); // int count = 0; - // // Find the first empty slot - // while (_fnDisks[count].fileh != nullptr) + // // Find the first empty slot, stop at 8 so we don't catch the cassette + // while (_fnDisks[count].fileh != nullptr && count < 8) // count++; // if (count > 1) // { // count--; + // for (int n = count; n > 0; n--) + // AdamNet.remDevice(_fnDisks[n].disk_dev.id()); + // // Save the device ID of the disk in the last slot // int last_id = _fnDisks[count].disk_dev.id(); @@ -542,11 +545,12 @@ void adamFuji::image_rotate() // { // int swap = _fnDisks[n - 1].disk_dev.id(); // Debug_printf("setting slot %d to ID %hx\n", n, swap); - // _adamnet_bus->changeDeviceId(&_fnDisks[n].disk_dev, swap); + // AdamNet.addDevice(&_fnDisks[n].disk_dev,swap); // } // // The first slot gets the device ID of the last slot - // _adamnet_bus->changeDeviceId(&_fnDisks[0].disk_dev, last_id); + // Debug_printf("setting slot %d to ID %hx\n", 0, last_id); + // AdamNet.addDevice(&_fnDisks[0].disk_dev, last_id); // } } From 008e9b57dda11f387de946357c56c306f41ebb50 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 27 Aug 2023 19:54:07 -0500 Subject: [PATCH 030/158] [adamnet] printer now uses queue. --- lib/device/adamnet/printer.cpp | 54 ++++++++++++++++------------------ lib/device/adamnet/printer.h | 8 +++++ 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index 99c5fba49..2c5b7657c 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -20,33 +20,28 @@ #include "png_printer.h" #include "coleco_printer.h" -#define PRINTER_PRIORITY 9 +#define PRINTER_PRIORITY 10 constexpr const char *const adamPrinter::printer_model_str[PRINTER_INVALID]; -struct _printItem -{ - uint8_t len; - uint8_t buf[16]; -} pi; - -bool need_print = false; - void printerTask(void *param) { - adamPrinter *p = (adamPrinter *)param; + printer_emu *p = (printer_emu *)param; - while (1) + while (true) { - if (need_print == true) + if (uxQueueMessagesWaiting(pxq)) { - fnLedManager.set(LED_BT, true); - p->perform_print(); - fnLedManager.set(LED_BT, false); - need_print = false; + PrintItem pi; + + fnLedManager.set(LED_BT,true); + xQueueReceive(pxq,&pi,portMAX_DELAY); + memcpy(p->provideBuffer(),&pi.buf,pi.len); + p->process(pi.len,0,0); + fnLedManager.set(LED_BT,false); } - vTaskDelay(1); + vTaskDelay(10/portTICK_PERIOD_MS); } } @@ -56,11 +51,9 @@ adamPrinter::adamPrinter(FileSystem *filesystem, printer_type print_type) _storage = filesystem; set_printer_type(print_type); - // getPrinterPtr()->setEOLBypass(true); - // getPrinterPtr()->setTranslate850(false); - // getPrinterPtr()->setEOL(0x0D); + pxq = xQueueCreate(16,sizeof(PrintItem)); - xTaskCreate(printerTask, "ptsk", 4096, this, PRINTER_PRIORITY, &thPrinter); + xTaskCreate(printerTask, "ptsk", 4096, _pptr, PRINTER_PRIORITY, &thPrinter); } adamPrinter::~adamPrinter() @@ -70,6 +63,8 @@ adamPrinter::~adamPrinter() if (_pptr != nullptr) delete _pptr; + + vQueueDelete(pxq); } void adamPrinter::start_printer_task() @@ -95,32 +90,33 @@ void adamPrinter::adamnet_control_status() void adamPrinter::perform_print() { - memcpy(_pptr->provideBuffer(), pi.buf, pi.len); - _pptr->process(pi.len, 0, 0); } void adamPrinter::adamnet_control_send() { - memset(&pi, 0, sizeof(pi)); + PrintItem pi; + pi.len = adamnet_recv_length(); adamnet_recv_buffer(pi.buf, pi.len); adamnet_recv(); // ck - AdamNet.start_time = esp_timer_get_time(); + // AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - need_print = true; + xQueueSend(pxq,&pi,portMAX_DELAY); _last_ms = fnSystem.millis(); } void adamPrinter::adamnet_control_ready() { - AdamNet.start_time = esp_timer_get_time(); + // AdamNet.start_time = esp_timer_get_time(); - if (need_print == true) + if (!uxQueueSpacesAvailable(pxq)) + { adamnet_response_nack(); - else + } + else adamnet_response_ack(); } diff --git a/lib/device/adamnet/printer.h b/lib/device/adamnet/printer.h index 4719cc64c..bcf4dfd41 100755 --- a/lib/device/adamnet/printer.h +++ b/lib/device/adamnet/printer.h @@ -16,6 +16,14 @@ void printerTask(void * param); +typedef struct _printItem +{ + uint8_t len; + uint8_t buf[16]; +} PrintItem; + +static QueueHandle_t pxq; + class adamPrinter : public virtualDevice { protected: From d7cc6849c8a1e51fbe3cfc57c336e6af26cd7507 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Mon, 28 Aug 2023 18:06:05 -0500 Subject: [PATCH 031/158] apple2: update autorun.po --- .../device_specific/BUILD_APPLE/autorun.po | Bin 143360 -> 143360 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_APPLE/autorun.po b/data/webui/device_specific/BUILD_APPLE/autorun.po index 13ec54457ab4c9c74e7aab4f9367c0a815cce266..bb586580db774ec5668d316db1b2c68e1879b9ed 100644 GIT binary patch delta 17010 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 X_JvaG)a|E-$Js4=UOe%l<-q?1@W96Q delta 17027 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 dzPkFt8qb0!i>+B(FAR!aWZC!hnWrsJ{2%T+ Date: Mon, 28 Aug 2023 20:33:35 -0400 Subject: [PATCH 032/158] get TNFS mounting over browser working --- lib/bus/mac/mac.cpp | 12 +-- lib/bus/mac/mac_ll.cpp | 10 ++- lib/device/mac/floppy.cpp | 8 +- lib/device/mac/floppy.h | 10 ++- lib/device/mac/fuji.cpp | 148 +++++++++++++++++++++++++++++++- lib/device/mac/fuji.h | 22 ++--- lib/media/mac/mediaType.cpp | 2 +- lib/media/mac/mediaTypeMOOF.cpp | 4 + pico/mac/commands.c | 4 + 9 files changed, 192 insertions(+), 28 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index b2b219ade..0f9bb1ff2 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -69,35 +69,35 @@ void macBus::service(void) { t0 = fnSystem.micros(); track_not_copied = true; - int tp = theFuji.get_disks(0)->disk_dev.step(); - if (tp < 0) + int track_position = theFuji.get_disks(0)->disk_dev.step(); + if (track_position < 0) { fnUartBUS.write('N'); } else { - fnUartBUS.write(tp | 128); // send the track position(/2) back + fnUartBUS.write(track_position | 128); // send the track position(/2) back // fnUartBUS.flush(); } } break; case 2: // turn motor ons - Debug_printf("\nMOTOR ON"); + Debug_printf("\nMotor ON"); floppy_ll.start(0); fnUartBUS.write('M'); // fnUartBUS.flush(); break; case 6: // turn motor off - Debug_printf("\nMOTOR OFF"); + Debug_printf("\nMotor OFF"); floppy_ll.stop(); fnUartBUS.write('F'); // fnUartBUS.flush(); break; case 7: // eject - Debug_printf("\nEJECT!!!"); + Debug_printf("\neject but do nothing"); fnUartBUS.write('E'); // fnUartBUS.flush(); break; diff --git a/lib/bus/mac/mac_ll.cpp b/lib/bus/mac/mac_ll.cpp index f3fdefc04..1acc7ff7d 100644 --- a/lib/bus/mac/mac_ll.cpp +++ b/lib/bus/mac/mac_ll.cpp @@ -885,13 +885,15 @@ void IRAM_ATTR encode_rmt_bitstream(const void* src, rmt_item32_t* dest, size_t rmt_item32_t* pdest = dest; while (num < wanted_num) { - // move this to nextbit() - // MC34780 behavior for random bit insertion - // https://applesaucefdc.com/woz/reference2/ + // hold over from DISK][ bit stream generation + // move this to nextbit() + // MC34780 behavior for random bit insertion + // https://applesaucefdc.com/woz/reference2/ window <<= 1; window |= (uint8_t)floppy_ll.nextbit(); window &= 0x0f; - outbit = (window != 0) ? window & 0x02 : floppy_ll.fakebit(); + // outbit = (window != 0) ? window & 0x02 : floppy_ll.fakebit(); + outbit = (window != 0) ? window & 0x02 : 0; // turn off random bits pdest->val = (outbit != 0) ? bit1.val : bit0.val; // pdest->val = floppy_ll.nextbit() ? bit1.val : bit0.val; diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 1cb0066e3..589ce10e1 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -5,7 +5,7 @@ #define NS_PER_BIT_TIME 125 #define BLANK_TRACK_LEN 6400 -mediatype_t macFloppy::mount(FILE *f, mediatype_t disk_type) //, const char *filename), uint32_t disksize, mediatype_t disk_type) +mediatype_t macFloppy::mount(FILE *f, const char *filename, mediatype_t disk_type) //, const char *filename), uint32_t disksize, mediatype_t disk_type) { mediatype_t mt = MEDIATYPE_UNKNOWN; @@ -20,6 +20,9 @@ mediatype_t macFloppy::mount(FILE *f, mediatype_t disk_type) //, const char *fil _disk = nullptr; } + if (disk_type == MEDIATYPE_UNKNOWN) + disk_type = MediaType::discover_mediatype(filename); + switch (disk_type) { case MEDIATYPE_MOOF: @@ -36,9 +39,11 @@ mediatype_t macFloppy::mount(FILE *f, mediatype_t disk_type) //, const char *fil { case 1: fnUartBUS.write('s'); + fnUartBUS.write(track_pos | 128); break; case 2: fnUartBUS.write('d'); + fnUartBUS.write(track_pos | 128); default: break; } @@ -115,6 +120,7 @@ DCDDATA Communication channel from DCD device to Macintosh void macFloppy::unmount() { + ((MediaTypeMOOF *)_disk)->unmount(); } int IRAM_ATTR macFloppy::step() diff --git a/lib/device/mac/floppy.h b/lib/device/mac/floppy.h index 7c332db72..83e63ce1a 100644 --- a/lib/device/mac/floppy.h +++ b/lib/device/mac/floppy.h @@ -47,12 +47,14 @@ class macFloppy : public macDevice int head_dir; public: + bool readonly; + macFloppy() {}; ~macFloppy() {}; // void init(); - mediatype_t mount(FILE *f, mediatype_t disk_type = MEDIATYPE_UNKNOWN); - mediatype_t mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type = MEDIATYPE_UNKNOWN) { return mount(f, disk_type); }; + mediatype_t mount(FILE *f, const char *filename, mediatype_t disk_type = MEDIATYPE_UNKNOWN); + mediatype_t mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type = MEDIATYPE_UNKNOWN) { return mount(f, filename, disk_type); }; void unmount(); bool write_blank(FILE *f, uint16_t sectorSize, uint16_t numSectors) { return false; }; int get_track_pos() { return track_pos; }; @@ -61,8 +63,8 @@ class macFloppy : public macDevice int step(); void change_track(int side); void update_track_buffers(); - // void set_disk_number(char c) { disk_num = c; } - // char get_disk_number() { return disk_num; }; + void set_disk_number(char c) { disk_num = c; _devnum = c; } + char get_disk_number() { return disk_num; }; mediatype_t disktype() { return _disk == nullptr ? MEDIATYPE_UNKNOWN : _disk->_mediatype; }; void shutdown() override {}; diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index 15cee9c12..9ca02f983 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -21,7 +21,19 @@ macFuji::macFuji() Debug_printf("Announcing the MacFuji!!!\n"); // Helpful for debugging for (int i = 0; i < MAX_HOSTS; i++) + { _fnHosts[i].slotid = i; + }; + +} + +void macFuji::startup_hack() +{ + Debug_printf("\n Fuji startup hack"); + for (int i = 0; i < MAX_DISK_DEVICES; i++) + { + _fnDisks[i].disk_dev.set_disk_number(i); + } } macFloppy *macFuji::bootdisk() @@ -52,6 +64,7 @@ void macFuji::setup(macBus *macbus) // theCPM = new iwmCPM(); // _iwm_bus->addDevice(theCPM, iwm_fujinet_type_t::CPM); + // 27-aug-23 use something similar for Mac floppy/dcd disks // for (int i = MAX_DISK_DEVICES - MAX_DISK2_DEVICES -1; i >= 0; i--) // { // _fnDisks[i].disk_dev.set_disk_number('0' + i); @@ -63,7 +76,7 @@ void macFuji::setup(macBus *macbus) // { FILE *f = fsFlash.file_open("/autorun.moof"); if (f!=nullptr) - _fnDisks[0].disk_dev.mount(f, MEDIATYPE_MOOF); + _fnDisks[0].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); else Debug_printf("\nCould not open 'autorun.moof'"); // } @@ -87,6 +100,139 @@ void macFuji::setup(macBus *macbus) // _adamnet_bus->addDevice(&sioNetDevs[i], ADAMNET_DEVICEID_FN_NETWORK + i); } + +// Temporary(?) function while we move from old config storage to new +void macFuji::_populate_slots_from_config() +{ + for (int i = 0; i < MAX_HOSTS; i++) + { + if (Config.get_host_type(i) == fnConfig::host_types::HOSTTYPE_INVALID) + _fnHosts[i].set_hostname(""); + else + _fnHosts[i].set_hostname(Config.get_host_name(i).c_str()); + } + + for (int i = 0; i < MAX_DISK_DEVICES; i++) + { + _fnDisks[i].reset(); + + if (Config.get_mount_host_slot(i) != HOST_SLOT_INVALID) + { + if (Config.get_mount_host_slot(i) >= 0 && Config.get_mount_host_slot(i) <= MAX_HOSTS) + { + strlcpy(_fnDisks[i].filename, + Config.get_mount_path(i).c_str(), sizeof(fujiDisk::filename)); + _fnDisks[i].host_slot = Config.get_mount_host_slot(i); + if (Config.get_mount_mode(i) == fnConfig::mount_modes::MOUNTMODE_WRITE) + _fnDisks[i].access_mode = DISK_ACCESS_MODE_WRITE; + else + _fnDisks[i].access_mode = DISK_ACCESS_MODE_READ; + } + } + } +} + +// Temporary(?) function while we move from old config storage to new +void macFuji::_populate_config_from_slots() +{ + for (int i = 0; i < MAX_HOSTS; i++) + { + fujiHostType htype = _fnHosts[i].get_type(); + const char *hname = _fnHosts[i].get_hostname(); + + if (hname[0] == '\0') + { + Config.clear_host(i); + } + else + { + Config.store_host(i, hname, + htype == HOSTTYPE_TNFS ? fnConfig::host_types::HOSTTYPE_TNFS : fnConfig::host_types::HOSTTYPE_SD); + } + } + + for (int i = 0; i < MAX_DISK_DEVICES; i++) + { + if (_fnDisks[i].host_slot >= MAX_HOSTS || _fnDisks[i].filename[0] == '\0') + Config.clear_mount(i); + else + Config.store_mount(i, _fnDisks[i].host_slot, _fnDisks[i].filename, + _fnDisks[i].access_mode == DISK_ACCESS_MODE_WRITE ? fnConfig::mount_modes::MOUNTMODE_WRITE : fnConfig::mount_modes::MOUNTMODE_READ); + } +} + +// Mount all +bool macFuji::mount_all() +{ + bool nodisks = true; // Check at the end if no disks are in a slot and disable config + + for (int i = 0; i < MAX_DISK_DEVICES; i++) + { + fujiDisk &disk = _fnDisks[i]; + fujiHost &host = _fnHosts[disk.host_slot]; + char flag[3] = {'r', 0, 0}; + + if (disk.access_mode == DISK_ACCESS_MODE_WRITE) + flag[1] = '+'; + + if (disk.host_slot != 0xFF) + { + nodisks = false; // We have a disk in a slot + + if (host.mount() == false) + { + return true; + } + + Debug_printf("Selecting '%s' from host #%u as %s on D%u:\n", + disk.filename, disk.host_slot, flag, i + 1); + + disk.fileh = host.file_open(disk.filename, disk.filename, sizeof(disk.filename), flag); + + if (disk.fileh == nullptr) + { + return true; + } + + // We've gotten this far, so make sure our bootable CONFIG disk is disabled + boot_config = false; + + // We need the file size for loading XEX files and for CASSETTE, so get that too + disk.disk_size = host.file_size(disk.fileh); + + // And now mount it + disk.disk_type = disk.disk_dev.mount(disk.fileh, disk.filename, disk.disk_size); + if(disk.access_mode == DISK_ACCESS_MODE_WRITE) {disk.disk_dev.readonly = false;} + } + } + + if (nodisks){ + // No disks in a slot, disable config + boot_config = false; + } + + // Go ahead and respond ok + return false; +} + +int macFuji::get_disk_id(int drive_slot) +{ + return _fnDisks[drive_slot].disk_dev.id(); +} + +std::string macFuji::get_host_prefix(int host_slot) +{ + return _fnHosts[host_slot].get_prefix(); +} + +// This gets called when we're about to shutdown/reboot +void macFuji::shutdown() +{ + for (int i = 0; i < MAX_DISK_DEVICES; i++) + _fnDisks[i].disk_dev.unmount(); +} + + #endif // BUILD_MAC #if 0 diff --git a/lib/device/mac/fuji.h b/lib/device/mac/fuji.h index 7031c1a4b..859807a8c 100644 --- a/lib/device/mac/fuji.h +++ b/lib/device/mac/fuji.h @@ -184,25 +184,25 @@ class macFuji : public macDevice // iwmDisk *bootdisk(); macFloppy *bootdisk(); - void debug_tape() {}; + // 27-Aug-23 get it online: void debug_tape() {}; - void insert_boot_device(uint8_t d) {}; + // 27-Aug-23 get it online: void insert_boot_device(uint8_t d) {}; void setup(macBus *macbus); - void image_rotate() {}; - int get_disk_id(int drive_slot) { return -1; }; - void handle_ctl_eject(uint8_t spid) {}; - std::string get_host_prefix(int host_slot) { return std::string(); }; + // 27-Aug-23 get it online: void image_rotate() {}; + int get_disk_id(int drive_slot); + // 27-Aug-23 get it online: void handle_ctl_eject(uint8_t spid) {}; + std::string get_host_prefix(int host_slot); fujiHost *get_hosts(int i) { return &_fnHosts[i]; } fujiDisk *get_disks(int i) { return &_fnDisks[i]; } // iwmDisk2 _fnDisk2s[MAX_DISK2_DEVICES]; - void _populate_slots_from_config() {}; - void _populate_config_from_slots() {}; + void _populate_slots_from_config(); + void _populate_config_from_slots(); - bool mount_all() { return false; }; // 0xD7 + bool mount_all(); // 0xD7 // void FujiStatus(iwm_decoded_cmd_t cmd) { iwm_status(cmd); } // void FujiControl(iwm_decoded_cmd_t cmd) { iwm_ctrl(cmd); } @@ -210,8 +210,8 @@ class macFuji : public macDevice macFuji(); ~macFuji(){}; - // virtual void startup_hack() override { Debug_printf("\n Fuji startup hack"); } - void shutdown() override {}; + void startup_hack(); + void shutdown() override; void process(mac_cmd_t cmd) override {}; }; diff --git a/lib/media/mac/mediaType.cpp b/lib/media/mac/mediaType.cpp index 4199fce45..b216a0035 100644 --- a/lib/media/mac/mediaType.cpp +++ b/lib/media/mac/mediaType.cpp @@ -30,7 +30,7 @@ mediatype_t MediaType::discover_mediatype(const char *filename) if (l > 5 && filename[l - 5] == '.') { // Check the last 4 characters of the string - const char *ext = filename + l - 2; + const char *ext = filename + l - 4; if (strcasecmp(ext, "MOOF") == 0) return MEDIATYPE_MOOF; } diff --git a/lib/media/mac/mediaTypeMOOF.cpp b/lib/media/mac/mediaTypeMOOF.cpp index d692109c1..4180d2d23 100644 --- a/lib/media/mac/mediaTypeMOOF.cpp +++ b/lib/media/mac/mediaTypeMOOF.cpp @@ -85,14 +85,18 @@ bool MediaTypeMOOF::moof_read_info() case 1: num_sides = 1; moof_disktype = moof_disk_type_t::SSDD_GCR; + Debug_printf("\nSingle sided GCR disk"); break; case 2: num_sides = 2; moof_disktype = moof_disk_type_t::DSDD_GCR; + Debug_printf("\nDouble sided GCR disk"); break; case 3: num_sides = 2; moof_disktype = moof_disk_type_t::DSDD_MFM; + Debug_printf("\nDouble sided MFM disk - not supported"); + return true; break; default: moof_disktype = moof_disk_type_t::UNKNOWN; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 56c9d6901..84176da23 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -330,15 +330,19 @@ void loop() set_latch(SINGLESIDE); clr_latch(CSTIN); clr_latch(WRTPRT); // everythign is write protected for now + printf("\nSS disk mounted"); break; case 'd': // double sided disk clr_latch(SINGLESIDE); clr_latch(CSTIN); clr_latch(WRTPRT); // everythign is write protected for now + printf("\nDS disk mounted"); break; case 'S': // step complete (data copied to RMT buffer on ESP32) + printf("\nStep sequence complete"); case 'M': // motor on + printf("\nMotor is on"); clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met default: break; From 7ee8b94edcc5ea4d0e025453de9812097b50a386 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Wed, 30 Aug 2023 21:25:51 -0400 Subject: [PATCH 033/158] it boots DS! --- lib/bus/mac/mac_ll.cpp | 16 ++++++++-------- lib/bus/mac/mac_ll.h | 2 +- pico/mac/commands.c | 17 ++++++++++------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/bus/mac/mac_ll.cpp b/lib/bus/mac/mac_ll.cpp index 1acc7ff7d..4408edf0e 100644 --- a/lib/bus/mac/mac_ll.cpp +++ b/lib/bus/mac/mac_ll.cpp @@ -889,14 +889,14 @@ void IRAM_ATTR encode_rmt_bitstream(const void* src, rmt_item32_t* dest, size_t // move this to nextbit() // MC34780 behavior for random bit insertion // https://applesaucefdc.com/woz/reference2/ - window <<= 1; - window |= (uint8_t)floppy_ll.nextbit(); - window &= 0x0f; - // outbit = (window != 0) ? window & 0x02 : floppy_ll.fakebit(); - outbit = (window != 0) ? window & 0x02 : 0; // turn off random bits - pdest->val = (outbit != 0) ? bit1.val : bit0.val; + // window <<= 1; + // window |= (uint8_t)floppy_ll.nextbit(); + // window &= 0x0f; + // // outbit = (window != 0) ? window & 0x02 : floppy_ll.fakebit(); + // outbit = (window != 0) ? window & 0x02 : 0; // turn off random bits + // pdest->val = (outbit != 0) ? bit1.val : bit0.val; - // pdest->val = floppy_ll.nextbit() ? bit1.val : bit0.val; + pdest->val = floppy_ll.nextbit() ? bit1.val : bit0.val; num++; pdest++; @@ -929,7 +929,7 @@ void mac_floppy_ll::setup_rmt() else config.gpio_num = (gpio_num_t)PIN_SD_HOST_MOSI; #endif - config.mem_block_num = 8; + config.mem_block_num = 1; config.tx_config.loop_en = false; config.tx_config.carrier_en = false; config.tx_config.idle_output_en = true; diff --git a/lib/bus/mac/mac_ll.h b/lib/bus/mac/mac_ll.h index 6479a533f..d32e7f464 100644 --- a/lib/bus/mac/mac_ll.h +++ b/lib/bus/mac/mac_ll.h @@ -89,7 +89,7 @@ class mac_ll // void iwm_extra_clr(); // void disable_output(); // void enable_output(); - bool mac_headsel_val() { return ((GPIO.in) & (0x01 << MCI_HDSEL)); } + bool mac_headsel_val() { return ((GPIO.in1.val) & (0x01U << (MCI_HDSEL-32))); } public: void setup_gpio(); }; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 84176da23..b49743636 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -136,34 +136,37 @@ uint16_t get_latch() { return latch; } uint16_t set_latch(enum latch_bits s) { - latch |= (1 << s); + latch |= (1u << s); return latch; }; uint16_t clr_latch(enum latch_bits c) { - latch &= ~(1 << c); + latch &= ~(1u << c); return latch; }; bool latch_val(enum latch_bits b) { - return (latch & (1 << b)); + return (latch & (1u << b)); } void preset_latch() { + latch =0; clr_latch(DIRTN); set_latch(STEP); set_latch(MOTORON); clr_latch(EJECT); set_latch(SINGLESIDE); clr_latch(DRVIN); - set_latch(CSTIN); + clr_latch(CSTIN); //set_latch(CSTIN); clr_latch(WRTPRT); set_latch(TKO); set_latch(READY); set_latch(REVISED); // my mac plus revised looks set + // for (int i=0; i<16; i++) + // printf("\nlatch bit %02d = %d",i, latch_val(i)); } @@ -327,14 +330,14 @@ void loop() { case 's': // single sided disk is in the slot - set_latch(SINGLESIDE); + clr_latch(SINGLESIDE); clr_latch(CSTIN); clr_latch(WRTPRT); // everythign is write protected for now printf("\nSS disk mounted"); break; case 'd': // double sided disk - clr_latch(SINGLESIDE); + set_latch(SINGLESIDE); clr_latch(CSTIN); clr_latch(WRTPRT); // everythign is write protected for now printf("\nDS disk mounted"); @@ -347,7 +350,7 @@ void loop() default: break; } - + // printf("latch %04x", get_latch()); pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO } // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO From 11c779dd0dd89e7c38eae29482da5be6517234b3 Mon Sep 17 00:00:00 2001 From: Michael Sternberg Date: Wed, 30 Aug 2023 21:28:29 -0500 Subject: [PATCH 034/158] Apple II - high score enabled --- lib/device/iwm/disk.cpp | 10 ++++++- lib/device/iwm/disk.h | 1 + lib/device/iwm/fuji.cpp | 1 + lib/media/apple/mediaType.h | 10 +++++++ lib/media/apple/mediaTypePO.cpp | 49 ++++++++++++++++++++++++++++++--- 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/lib/device/iwm/disk.cpp b/lib/device/iwm/disk.cpp index 842af6a02..9f927db02 100644 --- a/lib/device/iwm/disk.cpp +++ b/lib/device/iwm/disk.cpp @@ -525,7 +525,15 @@ mediatype_t iwmDisk::mount(FILE *f, const char *filename, uint32_t disksize, med case MEDIATYPE_PO: Debug_printf("\r\nMedia Type PO"); _disk = new MediaTypePO(); + _disk->_media_host = host; + strcpy(_disk->_disk_filename, filename); mt = _disk->mount(f, disksize); + + // firmware needs to believe a high score enabled disk is + // not write-protected. Otherwise it will skip write process + if (_disk->high_score_enabled) + readonly = false; + device_active = true; //change status only after we are mounted //_disk->fileptr() = f; // mt = MEDIATYPE_PO; @@ -631,4 +639,4 @@ bool iwmDisk::write_blank(FILE *f, uint16_t numBlocks) // init(); } */ -#endif /* BUILD_APPLE */ \ No newline at end of file +#endif /* BUILD_APPLE */ diff --git a/lib/device/iwm/disk.h b/lib/device/iwm/disk.h index a526f495d..f5c615e94 100644 --- a/lib/device/iwm/disk.h +++ b/lib/device/iwm/disk.h @@ -44,6 +44,7 @@ class iwmDisk : public iwmDevice public: uint8_t blank_header_type = 0; // unadorned by default. iwmDisk(); + fujiHost *host = nullptr; mediatype_t mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type = MEDIATYPE_UNKNOWN); void unmount(); bool write_blank(FILE *f, uint16_t sectorSize, uint16_t numSectors); diff --git a/lib/device/iwm/fuji.cpp b/lib/device/iwm/fuji.cpp index 70a8c4aa5..3d591274e 100644 --- a/lib/device/iwm/fuji.cpp +++ b/lib/device/iwm/fuji.cpp @@ -217,6 +217,7 @@ void iwmFuji::iwm_ctrl_disk_image_mount() // SP CTRL command Debug_printf("\r\nSelecting '%s' from host #%u as %s on D%u:\n", disk.filename, disk.host_slot, flag, deviceSlot + 1); + disk.disk_dev.host = &host; disk.fileh = host.file_open(disk.filename, disk.filename, sizeof(disk.filename), flag); // We've gotten this far, so make sure our bootable CONFIG disk is disabled diff --git a/lib/media/apple/mediaType.h b/lib/media/apple/mediaType.h index d4773e87f..cc2d30b5c 100644 --- a/lib/media/apple/mediaType.h +++ b/lib/media/apple/mediaType.h @@ -2,6 +2,7 @@ #define _MEDIA_TYPE_ #include +#include #define INVALID_SECTOR_VALUE 65536 @@ -26,11 +27,15 @@ class MediaType { protected: FILE *_media_fileh = nullptr; + FILE *oldFileh = nullptr; /* Temp fileh for high score enabled games */ + FILE *hsFileh = nullptr; /* Temp fileh for high score enabled games */ + uint32_t _media_image_size = 0; uint32_t _media_num_sectors = 0; uint16_t _media_sector_size = DISK_BYTES_PER_SECTOR_SINGLE; int32_t _media_last_sector = INVALID_SECTOR_VALUE; uint8_t _media_controller_status = DISK_CTRL_STATUS_CLEAR; + uint16_t _high_score_block = 0; /* High score block to allow write. 1-65535 */ public: // struct @@ -52,6 +57,11 @@ class MediaType uint32_t num_blocks; // FILE* fileptr() {return _media_fileh;} + char _disk_filename[256]; + fujiHost *_media_host = nullptr; + FILE *_media_hsfileh = nullptr; + bool high_score_enabled = false; + // uint8_t _media_sectorbuff[DISK_SECTORBUF_SIZE]; mediatype_t _mediatype = MEDIATYPE_UNKNOWN; diff --git a/lib/media/apple/mediaTypePO.cpp b/lib/media/apple/mediaTypePO.cpp index a456e6e47..7c7d26dc4 100644 --- a/lib/media/apple/mediaTypePO.cpp +++ b/lib/media/apple/mediaTypePO.cpp @@ -2,6 +2,10 @@ #include "mediaTypePO.h" +#include +#include "utils.h" +#include "../../include/debug.h" + bool MediaTypePO::read(uint32_t blockNum, uint16_t *count, uint8_t* buffer) { size_t readsize = *count; @@ -13,7 +17,12 @@ if (blockNum == 0 || blockNum != last_block_num + 1) // example optimization, on return true; } } - last_block_num = blockNum; + + if (high_score_enabled && _high_score_block == blockNum) + last_block_num = INVALID_SECTOR_VALUE; // try to invalidate cache if game re-reads hs table + else + last_block_num = blockNum; + readsize = fread((unsigned char *)buffer, 1, readsize, _media_fileh); // Reading block from SD Card return (readsize != *count); } @@ -21,6 +30,15 @@ if (blockNum == 0 || blockNum != last_block_num + 1) // example optimization, on bool MediaTypePO::write(uint32_t blockNum, uint16_t *count, uint8_t* buffer) { size_t writesize = *count; + + if (high_score_enabled && blockNum == _high_score_block) + { + Debug_printf("high score: Swapping file handles\r\n"); + oldFileh = _media_fileh; + hsFileh = _media_host->file_open(_disk_filename, _disk_filename, strlen(_disk_filename) +1, "r+"); + _media_fileh = hsFileh; + } + if (blockNum != last_block_num + 1) // example optimization, only do seek if not writing next block -tschak { if (fseek(_media_fileh, (blockNum * writesize) + offset, SEEK_SET)) @@ -36,6 +54,17 @@ bool MediaTypePO::write(uint32_t blockNum, uint16_t *count, uint8_t* buffer) reset_seek_opto(); return true; } + + if (high_score_enabled && blockNum == _high_score_block) + { + Debug_printf("high score: Reverting file handles.\r\n"); + if (hsFileh != nullptr) + fclose(hsFileh); + + _media_fileh = oldFileh; + last_block_num = INVALID_SECTOR_VALUE; // Invalidate cache + } + return false; } @@ -47,10 +76,22 @@ bool MediaTypePO::format(uint16_t *respopnsesize) mediatype_t MediaTypePO::mount(FILE *f, uint32_t disksize) { diskiiemulation = false; - char hdr[4]; - fread(&hdr,sizeof(char),4,f); + char hdr[64]; + fread(&hdr,sizeof(char),64,f); if (hdr[0] == '2' && hdr[1] == 'I' && hdr[2] == 'M' && hdr[3] == 'G') + { + // check for 'high score enabled' signature + if (hdr[48] == 'H' && hdr[49] == 'I') + { + _high_score_block = UINT16_FROM_HILOBYTES(hdr[51], hdr[50]); + if (_high_score_block > 0) + { + Debug_printf("high score: Requested block: 0x%04x\r\n", _high_score_block); + high_score_enabled = true; + } + } offset = 64; + } _media_fileh = f; disksize -= offset; num_blocks = disksize/512; @@ -63,4 +104,4 @@ mediatype_t MediaTypePO::mount(FILE *f, uint32_t disksize) // return false; // } -#endif // BUILD_APPLE \ No newline at end of file +#endif // BUILD_APPLE From 0babc8e479dda3ff7002f137a0410745cf669026 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 1 Sep 2023 16:53:55 -0500 Subject: [PATCH 035/158] [adam][dsk] fill first 12 blocks with 0. --- lib/media/adam/mediaTypeDSK.cpp | 67 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/lib/media/adam/mediaTypeDSK.cpp b/lib/media/adam/mediaTypeDSK.cpp index 654609c1c..85202fa0b 100644 --- a/lib/media/adam/mediaTypeDSK.cpp +++ b/lib/media/adam/mediaTypeDSK.cpp @@ -8,7 +8,6 @@ #include "../../include/debug.h" - #define INTERLEAVE 5 // 5:1 sector layout in image files (WHY?!?!!?) // Returns byte offsets of given block number, with interleave @@ -21,7 +20,7 @@ std::pair MediaTypeDSK::_block_to_offsets(uint32_t blockNum) o2 = ((r == 0) || (r == 1)) ? (blockNum * 1024) + (INTERLEAVE * 512) : (blockNum * 1024) - (4096 - (INTERLEAVE * 512)); - return std::make_pair(o1,o2); + return std::make_pair(o1, o2); } // Returns TRUE if an error condition occurred @@ -29,14 +28,14 @@ bool MediaTypeDSK::read(uint32_t blockNum, uint16_t *readcount) { if (blockNum == _media_last_block) return false; // Already have - + Debug_print("DSK READ\r\n"); // Return an error if we're trying to read beyond the end of the disk if (blockNum > _media_num_blocks - 1) { Debug_printf("::read block %lu > %lu\r\n", blockNum, _media_num_blocks); - _media_controller_status=2; + _media_controller_status = 2; return true; } @@ -44,26 +43,26 @@ bool MediaTypeDSK::read(uint32_t blockNum, uint16_t *readcount) bool err = false; - // Read lower part of block - std::pair offsets = _block_to_offsets(blockNum); + // Read lower part of block + std::pair offsets = _block_to_offsets(blockNum); err = fseek(_media_fileh, offsets.first, SEEK_SET) != 0; if (err == false) err = fread(_media_blockbuff, 1, 512, _media_fileh) != 512; - // Read upper part of block + // Read upper part of block if (err == false) err = fseek(_media_fileh, offsets.second, SEEK_SET) != 0; if (err == false) - err = fread(&_media_blockbuff[512],1,512,_media_fileh) != 512; + err = fread(&_media_blockbuff[512], 1, 512, _media_fileh) != 512; if (err == false) _media_last_block = blockNum; else _media_last_block = INVALID_SECTOR_VALUE; - _media_controller_status=0; + _media_controller_status = 0; return err; } @@ -78,31 +77,31 @@ bool MediaTypeDSK::write(uint32_t blockNum, bool verify) if (blockNum > _media_num_blocks) { Debug_printf("::write block BEYOND END %lu > %lu\r\n", blockNum, _media_num_blocks); - _media_controller_status=2; + _media_controller_status = 2; return true; } - std::pair offsets = _block_to_offsets(blockNum); + std::pair offsets = _block_to_offsets(blockNum); if (_media_fileh->_flags == 0x1484) // mounted R/O, attempt HS R/W { Debug_printf("High score mode activated, attempting write open\r\n"); - + oldFileh = _media_fileh; hsFileh = _media_host->file_open(_disk_filename, _disk_filename, strlen(_disk_filename) + 1, "r+"); - _media_fileh = hsFileh; + _media_fileh = hsFileh; } // Write lower part of block err = fseek(_media_fileh, offsets.first, SEEK_SET) != 0; if (err == false) - err = fwrite(_media_blockbuff,1,512,_media_fileh) != 512; - + err = fwrite(_media_blockbuff, 1, 512, _media_fileh) != 512; + // Write upper part of block if (err == false) err = fseek(_media_fileh, offsets.second, SEEK_SET) != 0; if (err == false) - err = fwrite(&_media_blockbuff[512],1,512,_media_fileh) != 512; + err = fwrite(&_media_blockbuff[512], 1, 512, _media_fileh) != 512; int ret = fflush(_media_fileh); // This doesn't seem to be connected to anything in ESP-IDF VF, so it may not do anything ret = fsync(fileno(_media_fileh)); // Since we might get reset at any moment, go ahead and sync the file (not clear if fflush does this) @@ -121,7 +120,7 @@ bool MediaTypeDSK::write(uint32_t blockNum, bool verify) else _media_last_block = blockNum; - _media_controller_status=0; + _media_controller_status = 0; return false; } @@ -134,9 +133,18 @@ uint8_t MediaTypeDSK::status() // Returns TRUE if an error condition occurred bool MediaTypeDSK::format(uint16_t *responsesize) { - memset(_media_blockbuff,0xE5,1024); - for (uint32_t b=0;b<_media_num_blocks;b++) - write(b,0); + for (uint32_t b = 0; b < _media_num_blocks; b++) + { + if (b<13) + { + memset(_media_blockbuff,0x00,1024); + } + else + { + memset(_media_blockbuff,0xE5,1024); + } + write(b, 0); + } return false; } @@ -147,8 +155,8 @@ mediatype_t MediaTypeDSK::mount(FILE *f, uint32_t disksize) _media_fileh = f; _mediatype = MEDIATYPE_DSK; _media_num_blocks = disksize / 1024; - Debug_printf("_media_num_blocks %lu\r\n",_media_num_blocks); - _media_last_block=0xFFFFFFFE; + Debug_printf("_media_num_blocks %lu\r\n", _media_num_blocks); + _media_last_block = 0xFFFFFFFE; return _mediatype; } @@ -159,9 +167,18 @@ bool MediaTypeDSK::create(FILE *f, uint32_t numBlocks) Debug_print("DSK CREATE\r\n"); uint8_t buf[1024]; - memset(buf,0xE5,1024); - for (uint32_t b=0; b Date: Fri, 1 Sep 2023 17:02:14 -0500 Subject: [PATCH 036/158] [adam][disk] write 00 to first 13 blocks on format --- lib/device/adamnet/disk.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index 374abb458..b40429f13 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -98,10 +98,13 @@ bool adamDisk::write_blank(FILE *fileh, uint32_t numBlocks) { uint8_t buf[256]; - memset(buf, 0xE5, 256); - for (uint32_t b = 0; b < numBlocks; b++) { + if (b<13) + memset(buf, 0x00, 256); + else + memset(buf, 0xE5, 256); + fwrite(buf, 1, 256, fileh); fwrite(buf, 1, 256, fileh); fwrite(buf, 1, 256, fileh); From 491da8bfc02db0d3261075d159ec3453e155de63 Mon Sep 17 00:00:00 2001 From: Michael Sternberg Date: Sat, 2 Sep 2023 15:34:53 -0500 Subject: [PATCH 037/158] Apple II High Score. Use block range --- lib/media/apple/mediaType.h | 3 ++- lib/media/apple/mediaTypePO.cpp | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/media/apple/mediaType.h b/lib/media/apple/mediaType.h index cc2d30b5c..3ce23965c 100644 --- a/lib/media/apple/mediaType.h +++ b/lib/media/apple/mediaType.h @@ -35,7 +35,8 @@ class MediaType uint16_t _media_sector_size = DISK_BYTES_PER_SECTOR_SINGLE; int32_t _media_last_sector = INVALID_SECTOR_VALUE; uint8_t _media_controller_status = DISK_CTRL_STATUS_CLEAR; - uint16_t _high_score_block = 0; /* High score block to allow write. 1-65535 */ + uint16_t _high_score_block_lb = 0; /* High score block (lower bound) to allow write. 1-65535 */ + uint16_t _high_score_block_ub = 0; /* High score block (upper bound) to allow write. 1-65535 */ public: // struct diff --git a/lib/media/apple/mediaTypePO.cpp b/lib/media/apple/mediaTypePO.cpp index 7c7d26dc4..4b9e33137 100644 --- a/lib/media/apple/mediaTypePO.cpp +++ b/lib/media/apple/mediaTypePO.cpp @@ -18,7 +18,7 @@ if (blockNum == 0 || blockNum != last_block_num + 1) // example optimization, on } } - if (high_score_enabled && _high_score_block == blockNum) + if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) last_block_num = INVALID_SECTOR_VALUE; // try to invalidate cache if game re-reads hs table else last_block_num = blockNum; @@ -31,7 +31,7 @@ bool MediaTypePO::write(uint32_t blockNum, uint16_t *count, uint8_t* buffer) { size_t writesize = *count; - if (high_score_enabled && blockNum == _high_score_block) + if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) { Debug_printf("high score: Swapping file handles\r\n"); oldFileh = _media_fileh; @@ -55,7 +55,7 @@ bool MediaTypePO::write(uint32_t blockNum, uint16_t *count, uint8_t* buffer) return true; } - if (high_score_enabled && blockNum == _high_score_block) + if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) { Debug_printf("high score: Reverting file handles.\r\n"); if (hsFileh != nullptr) @@ -80,14 +80,22 @@ mediatype_t MediaTypePO::mount(FILE *f, uint32_t disksize) fread(&hdr,sizeof(char),64,f); if (hdr[0] == '2' && hdr[1] == 'I' && hdr[2] == 'M' && hdr[3] == 'G') { - // check for 'high score enabled' signature + // check for 'high score enabled' + // expected format at offset 0x48 of 2mg hdr: H,I,,,, + // where blk is block range containing high score table, lb = lower bound, ub = upper bound + // if upper bound is undefined (0x0000), then lower bound defines range if (hdr[48] == 'H' && hdr[49] == 'I') { - _high_score_block = UINT16_FROM_HILOBYTES(hdr[51], hdr[50]); - if (_high_score_block > 0) + // read range of blocks from the 2mg header that qualify to be written (little endian) + _high_score_block_lb = UINT16_FROM_HILOBYTES(hdr[51], hdr[50]); + _high_score_block_ub = UINT16_FROM_HILOBYTES(hdr[53], hdr[52]); + if (_high_score_block_lb > 0) { - Debug_printf("high score: Requested block: 0x%04x\r\n", _high_score_block); + if (_high_score_block_ub == 0) + _high_score_block_ub = _high_score_block_lb; + high_score_enabled = true; + Debug_printf("\r\nhigh score: block range: %04x..%04x\r\n", _high_score_block_lb, _high_score_block_ub); } } offset = 64; From 2d1b7281129cb6c68b8dc2fceb52507562988286 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 4 Sep 2023 13:29:30 -0500 Subject: [PATCH 038/158] [adamnet][printer] a bit more efficient. --- lib/device/adamnet/printer.cpp | 45 +++++++++++------------ lib/device/adamnet/printer.h | 2 - lib/printer-emulator/printer_emulator.cpp | 2 + lib/printer-emulator/printer_emulator.h | 5 ++- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index 2c5b7657c..1718dfd16 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -20,28 +20,35 @@ #include "png_printer.h" #include "coleco_printer.h" -#define PRINTER_PRIORITY 10 +#define PRINTER_PRIORITY 9 constexpr const char *const adamPrinter::printer_model_str[PRINTER_INVALID]; void printerTask(void *param) { printer_emu *p = (printer_emu *)param; + unsigned char i = 0; while (true) { - if (uxQueueMessagesWaiting(pxq)) + while (uxQueueMessagesWaiting(pxq)) { PrintItem pi; - fnLedManager.set(LED_BT,true); - xQueueReceive(pxq,&pi,portMAX_DELAY); - memcpy(p->provideBuffer(),&pi.buf,pi.len); - p->process(pi.len,0,0); - fnLedManager.set(LED_BT,false); + xQueueReceive(pxq, &pi, portMAX_DELAY); + memcpy(&p->provideBuffer()[i], &pi.buf, pi.len); + i += pi.len; } - vTaskDelay(10/portTICK_PERIOD_MS); + if (i) + { + fnLedManager.set(LED_BT, true); + p->process(i, 0, 0); + i = 0; + fnLedManager.set(LED_BT, false); + } + + vTaskDelay(1000 / portTICK_PERIOD_MS); } } @@ -51,7 +58,7 @@ adamPrinter::adamPrinter(FileSystem *filesystem, printer_type print_type) _storage = filesystem; set_printer_type(print_type); - pxq = xQueueCreate(16,sizeof(PrintItem)); + pxq = xQueueCreate(160, sizeof(PrintItem)); xTaskCreate(printerTask, "ptsk", 4096, _pptr, PRINTER_PRIORITY, &thPrinter); } @@ -67,10 +74,6 @@ adamPrinter::~adamPrinter() vQueueDelete(pxq); } -void adamPrinter::start_printer_task() -{ -} - adamPrinter::printer_type adamPrinter::match_modelname(std::string model_name) { int i; @@ -88,10 +91,6 @@ void adamPrinter::adamnet_control_status() adamnet_send_buffer(c, sizeof(c)); } -void adamPrinter::perform_print() -{ -} - void adamPrinter::adamnet_control_send() { PrintItem pi; @@ -103,20 +102,20 @@ void adamPrinter::adamnet_control_send() // AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - xQueueSend(pxq,&pi,portMAX_DELAY); + xQueueSend(pxq, &pi, portMAX_DELAY); _last_ms = fnSystem.millis(); } void adamPrinter::adamnet_control_ready() { - // AdamNet.start_time = esp_timer_get_time(); + AdamNet.start_time = esp_timer_get_time(); - if (!uxQueueSpacesAvailable(pxq)) - { + if (getPrinterPtr()->is_printing) adamnet_response_nack(); - } - else + else if (!uxQueueSpacesAvailable(pxq)) + adamnet_response_nack(); + else adamnet_response_ack(); } diff --git a/lib/device/adamnet/printer.h b/lib/device/adamnet/printer.h index bcf4dfd41..7473f144b 100755 --- a/lib/device/adamnet/printer.h +++ b/lib/device/adamnet/printer.h @@ -106,8 +106,6 @@ class adamPrinter : public virtualDevice void set_printer_type(printer_type printer_type); void reset_printer() { set_printer_type(_ptype); }; time_t lastPrintTime() { return _last_ms; }; - void start_printer_task(); - void perform_print(); printer_emu *getPrinterPtr() { return _pptr; }; diff --git a/lib/printer-emulator/printer_emulator.cpp b/lib/printer-emulator/printer_emulator.cpp index df9a8d948..f78a8100b 100755 --- a/lib/printer-emulator/printer_emulator.cpp +++ b/lib/printer-emulator/printer_emulator.cpp @@ -73,6 +73,7 @@ size_t printer_emu::getOutputSize() // All the work is done here in the derived classes. Open and close the output file before proceeding bool printer_emu::process(uint8_t linelen, uint8_t aux1, uint8_t aux2) { + is_printing=true; // Make sure the file has been initialized if(_output_started == false) { @@ -92,6 +93,7 @@ bool printer_emu::process(uint8_t linelen, uint8_t aux1, uint8_t aux2) fclose(_file); _file = nullptr; + is_printing=false; return result; } diff --git a/lib/printer-emulator/printer_emulator.h b/lib/printer-emulator/printer_emulator.h index 0bf571b14..6b4851e14 100755 --- a/lib/printer-emulator/printer_emulator.h +++ b/lib/printer-emulator/printer_emulator.h @@ -38,7 +38,7 @@ class printer_emu bool translate850 = false; // default to sio printer uint8_t _eol = 0x9B; // default to atascii eol - uint8_t buffer[80]; + uint8_t buffer[320]; // Called after a new printer output file is created (allows for providing header data) virtual void post_new_file()=0; @@ -53,6 +53,9 @@ class printer_emu void restart_output(); public: + + bool is_printing=false; + // Destructor must be virtual to allow for proper cleanup of derived classes virtual ~printer_emu(); From 487537a36f6c3a35ee33b1a9c0b81f05e979f740 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 4 Sep 2023 16:03:28 -0500 Subject: [PATCH 039/158] [adam][printer] pin print task to core 0 --- lib/device/adamnet/printer.cpp | 2 +- lib/printer-emulator/coleco_printer.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index 1718dfd16..3c4cee7b1 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -60,7 +60,7 @@ adamPrinter::adamPrinter(FileSystem *filesystem, printer_type print_type) pxq = xQueueCreate(160, sizeof(PrintItem)); - xTaskCreate(printerTask, "ptsk", 4096, _pptr, PRINTER_PRIORITY, &thPrinter); + xTaskCreatePinnedToCore(printerTask,"ptsk",4096,_pptr,PRINTER_PRIORITY,&thPrinter,0); } adamPrinter::~adamPrinter() diff --git a/lib/printer-emulator/coleco_printer.h b/lib/printer-emulator/coleco_printer.h index a6b7f779d..83f6cfa23 100644 --- a/lib/printer-emulator/coleco_printer.h +++ b/lib/printer-emulator/coleco_printer.h @@ -17,6 +17,7 @@ class adamBidiBuffer void put_bs() { + Debug_printf("BS\n"); isVT = false; _column--; } From 36d3b3c68d28c61e7f5437a4a831b3df195bff2f Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 4 Sep 2023 18:23:19 -0500 Subject: [PATCH 040/158] [adam] needs its own version of image rotate. --- lib/device/adamnet/disk.h | 2 + lib/device/adamnet/fuji.cpp | 237 ++++++++++++++++++++++-------------- 2 files changed, 146 insertions(+), 93 deletions(-) diff --git a/lib/device/adamnet/disk.h b/lib/device/adamnet/disk.h index 1921ea068..c9c9a007d 100755 --- a/lib/device/adamnet/disk.h +++ b/lib/device/adamnet/disk.h @@ -35,6 +35,8 @@ class adamDisk : public virtualDevice void unmount(); bool write_blank(FILE *f, uint32_t numBlocks); virtual void reset() override; + MediaType *get_media() { return _media; } + void set_media(MediaType *__media) { _media = __media; } mediatype_t mediatype() { return _media == nullptr ? MEDIATYPE_UNKNOWN : _media->_mediatype; }; diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 35b57d9a6..c807a064a 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -19,11 +19,11 @@ #define COPY_SIZE 532 -adamFuji theFuji; // global fuji device object -adamNetwork *theNetwork; // global network device object (temporary) +adamFuji theFuji; // global fuji device object +adamNetwork *theNetwork; // global network device object (temporary) adamNetwork *theNetwork2; // another network device -adamPrinter *thePrinter; // global printer -adamSerial *theSerial; // global serial +adamPrinter *thePrinter; // global printer +adamSerial *theSerial; // global serial using namespace std; @@ -129,7 +129,7 @@ void adamFuji::adamnet_net_scan_result() // Response to FUJICMD_GET_SCAN_RESULT struct { - char ssid[MAX_SSID_LEN+1]; + char ssid[MAX_SSID_LEN + 1]; uint8_t rssi; } detail; @@ -158,7 +158,7 @@ void adamFuji::adamnet_net_get_ssid() // Response to FUJICMD_GET_SSID struct { - char ssid[MAX_SSID_LEN+1]; + char ssid[MAX_SSID_LEN + 1]; char password[MAX_WIFI_PASS_LEN]; } cfg; @@ -197,7 +197,7 @@ void adamFuji::adamnet_net_set_ssid(uint16_t s) // Data for FUJICMD_SET_SSID struct { - char ssid[MAX_SSID_LEN+1]; + char ssid[MAX_SSID_LEN + 1]; char password[MAX_WIFI_PASS_LEN]; } cfg; @@ -325,7 +325,7 @@ void adamFuji::adamnet_set_boot_config() AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - Debug_printf("Boot config is now %d",boot_config); + Debug_printf("Boot config is now %d", boot_config); if (_fnDisks[0].disk_dev.is_config_device) { @@ -349,7 +349,7 @@ void adamFuji::adamnet_copy_file() char *dataBuf; unsigned char sourceSlot; unsigned char destSlot; - unsigned long total=0; + unsigned long total = 0; Debug_printf("ADAMNET COPY FILE\n"); @@ -357,7 +357,7 @@ void adamFuji::adamnet_copy_file() sourceSlot = adamnet_recv(); destSlot = adamnet_recv(); - adamnet_recv_buffer(csBuf,sizeof(csBuf)); + adamnet_recv_buffer(csBuf, sizeof(csBuf)); ck = adamnet_recv(); AdamNet.wait_for_idle(); @@ -397,7 +397,7 @@ void adamFuji::adamnet_copy_file() count = fread(dataBuf, 1, COPY_SIZE, sourceFile); fwrite(dataBuf, 1, count, destFile); total += count; - Debug_printf("Copied: %lu bytes %u %u\n",total,feof(sourceFile),ferror(sourceFile)); + Debug_printf("Copied: %lu bytes %u %u\n", total, feof(sourceFile), ferror(sourceFile)); taskYIELD(); } @@ -407,7 +407,6 @@ void adamFuji::adamnet_copy_file() free(dataBuf); Debug_printf("COPY DONE\n"); - } // Set boot mode @@ -420,7 +419,6 @@ void adamFuji::adamnet_set_boot_mode() boot_config = true; adamnet_response_ack(); - } char *_generate_appkey_filename(appkey *info) @@ -486,7 +484,6 @@ void adamFuji::adamnet_read_app_key() fp = fnSDFAT.file_open(appkeyfilename, "r"); memset(response, 0, sizeof(response)); - if (fp == nullptr) { @@ -494,7 +491,7 @@ void adamFuji::adamnet_read_app_key() response_len = 1; // if no file found set return length to 1 or adam hangs waiting for response return; } - + response_len = fread(response, sizeof(char), 64, fp); fclose(fp); } @@ -524,34 +521,89 @@ void adamFuji::adamnet_disk_image_umount() */ void adamFuji::image_rotate() { - // Debug_println("Fuji cmd: IMAGE ROTATE"); - - // int count = 0; - // // Find the first empty slot, stop at 8 so we don't catch the cassette - // while (_fnDisks[count].fileh != nullptr && count < 8) - // count++; - - // if (count > 1) - // { - // count--; - - // for (int n = count; n > 0; n--) - // AdamNet.remDevice(_fnDisks[n].disk_dev.id()); - - // // Save the device ID of the disk in the last slot - // int last_id = _fnDisks[count].disk_dev.id(); - - // for (int n = count; n > 0; n--) - // { - // int swap = _fnDisks[n - 1].disk_dev.id(); - // Debug_printf("setting slot %d to ID %hx\n", n, swap); - // AdamNet.addDevice(&_fnDisks[n].disk_dev,swap); - // } - - // // The first slot gets the device ID of the last slot - // Debug_printf("setting slot %d to ID %hx\n", 0, last_id); - // AdamNet.addDevice(&_fnDisks[0].disk_dev, last_id); - // } + Debug_println("Fuji cmd: IMAGE ROTATE"); + + int count = 0; + string filename_save[4]; + unsigned char hostslot_save[4]; + unsigned char accessmode_save[4]; + uint32_t disksize_save[4]; + mediatype_t disktype_save[4]; + FILE *fileh_save[4]; + fujiHost *fujiHost_save[4]; + MediaType *media_save[4]; + + filename_save[0] = string(_fnDisks[0].filename); + filename_save[1] = string(_fnDisks[1].filename); + filename_save[2] = string(_fnDisks[2].filename); + filename_save[3] = string(_fnDisks[3].filename); + hostslot_save[0] = _fnDisks[0].host_slot; + hostslot_save[1] = _fnDisks[1].host_slot; + hostslot_save[2] = _fnDisks[2].host_slot; + hostslot_save[3] = _fnDisks[3].host_slot; + accessmode_save[0] = _fnDisks[0].access_mode; + accessmode_save[1] = _fnDisks[1].access_mode; + accessmode_save[2] = _fnDisks[2].access_mode; + accessmode_save[3] = _fnDisks[3].access_mode; + disksize_save[0] = _fnDisks[0].disk_size; + disksize_save[1] = _fnDisks[1].disk_size; + disksize_save[2] = _fnDisks[2].disk_size; + disksize_save[3] = _fnDisks[3].disk_size; + disktype_save[0] = _fnDisks[0].disk_type; + disktype_save[1] = _fnDisks[1].disk_type; + disktype_save[2] = _fnDisks[2].disk_type; + disktype_save[3] = _fnDisks[3].disk_type; + fileh_save[0] = _fnDisks[0].fileh; + fileh_save[1] = _fnDisks[1].fileh; + fileh_save[2] = _fnDisks[2].fileh; + fileh_save[3] = _fnDisks[3].fileh; + fujiHost_save[0] = _fnDisks[0].host; + fujiHost_save[1] = _fnDisks[1].host; + fujiHost_save[2] = _fnDisks[2].host; + fujiHost_save[3] = _fnDisks[3].host; + media_save[0] = _fnDisks[0].disk_dev.get_media(); + media_save[1] = _fnDisks[1].disk_dev.get_media(); + media_save[2] = _fnDisks[2].disk_dev.get_media(); + media_save[3] = _fnDisks[3].disk_dev.get_media(); + + // Find the first empty slot, stop at 8 so we don't catch the cassette + while (_fnDisks[count].fileh != nullptr) + count++; + + Debug_printf("count is %u\n", count); + + if (count > 1) + { + count--; + + // Save the device ID of the disk in the last slot + int last_id = count; + + for (int n = count; n > 0; n--) + { + _fnDisks[n].access_mode = accessmode_save[n - 1]; + _fnDisks[n].disk_size = disksize_save[n - 1]; + _fnDisks[n].disk_type = disktype_save[n - 1]; + _fnDisks[n].fileh = fileh_save[n - 1]; + strcpy(_fnDisks[n].filename, filename_save[n - 1].c_str()); + _fnDisks[n].host = fujiHost_save[n - 1]; + _fnDisks[n].host_slot = hostslot_save[n - 1]; + _fnDisks[n].disk_dev.set_media(media_save[n-1]); + } + + // The first slot gets the device ID of the last slot + Debug_printf("setting slot %d to ID %hx\n", 0, last_id); + _fnDisks[0].access_mode = accessmode_save[last_id]; + _fnDisks[0].disk_size = disksize_save[last_id]; + _fnDisks[0].disk_type = disktype_save[last_id]; + _fnDisks[0].fileh = fileh_save[last_id]; + strcpy(_fnDisks[0].filename, filename_save[last_id].c_str()); + _fnDisks[0].host = fujiHost_save[last_id]; + _fnDisks[0].host_slot = hostslot_save[last_id]; + _fnDisks[0].disk_dev.set_media(media_save[last_id]); + + _populate_config_from_slots(); + } } // This gets called when we're about to shutdown/reboot @@ -1117,30 +1169,30 @@ void adamFuji::adamnet_enable_device() { unsigned char d = adamnet_recv(); - Debug_printf("FUJI ENABLE DEVICE %02x\n",d); + Debug_printf("FUJI ENABLE DEVICE %02x\n", d); adamnet_recv(); AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - switch(d) + switch (d) { - case 0x02: - Config.store_printer_enabled(true); - break; - case 0x04: - Config.store_device_slot_enable_1(true); - break; - case 0x05: - Config.store_device_slot_enable_2(true); - break; - case 0x06: - Config.store_device_slot_enable_3(true); - break; - case 0x07: - Config.store_device_slot_enable_4(true); - break; + case 0x02: + Config.store_printer_enabled(true); + break; + case 0x04: + Config.store_device_slot_enable_1(true); + break; + case 0x05: + Config.store_device_slot_enable_2(true); + break; + case 0x06: + Config.store_device_slot_enable_3(true); + break; + case 0x07: + Config.store_device_slot_enable_4(true); + break; } Config.save(); @@ -1152,34 +1204,34 @@ void adamFuji::adamnet_disable_device() { unsigned char d = adamnet_recv(); - Debug_printf("FUJI DISABLE DEVICE %02x\n",d); + Debug_printf("FUJI DISABLE DEVICE %02x\n", d); adamnet_recv(); AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - switch(d) + switch (d) { - case 0x02: - Config.store_printer_enabled(false); - break; - case 0x04: - Config.store_device_slot_enable_1(false); - break; - case 0x05: - Config.store_device_slot_enable_2(false); - break; - case 0x06: - Config.store_device_slot_enable_3(false); - break; - case 0x07: - Config.store_device_slot_enable_4(false); - break; + case 0x02: + Config.store_printer_enabled(false); + break; + case 0x04: + Config.store_device_slot_enable_1(false); + break; + case 0x05: + Config.store_device_slot_enable_2(false); + break; + case 0x06: + Config.store_device_slot_enable_3(false); + break; + case 0x07: + Config.store_device_slot_enable_4(false); + break; } Config.save(); - + AdamNet.disableDevice(d); } @@ -1224,9 +1276,9 @@ void adamFuji::setup(systemBus *siobus) theNetwork = new adamNetwork(); theNetwork2 = new adamNetwork(); theSerial = new adamSerial(); - _adamnet_bus->addDevice(theNetwork, 0x09); // temporary. - _adamnet_bus->addDevice(theNetwork2,0x0A); // temporary - _adamnet_bus->addDevice(&theFuji, 0x0F); // Fuji becomes the gateway device. + _adamnet_bus->addDevice(theNetwork, 0x09); // temporary. + _adamnet_bus->addDevice(theNetwork2, 0x0A); // temporary + _adamnet_bus->addDevice(&theFuji, 0x0F); // Fuji becomes the gateway device. } // Mount all @@ -1240,19 +1292,19 @@ void adamFuji::mount_all() fujiHost &host = _fnHosts[disk.host_slot]; char flag[3] = {'r', 0, 0}; - if (i==0 && !Config.get_device_slot_enable_1()) + if (i == 0 && !Config.get_device_slot_enable_1()) { disk.disk_dev.device_active = false; } - else if (i==1 && !Config.get_device_slot_enable_2()) + else if (i == 1 && !Config.get_device_slot_enable_2()) { disk.disk_dev.device_active = false; } - else if (i==2 && !Config.get_device_slot_enable_3()) + else if (i == 2 && !Config.get_device_slot_enable_3()) { disk.disk_dev.device_active = false; } - else if (i==3 && !Config.get_device_slot_enable_4()) + else if (i == 3 && !Config.get_device_slot_enable_4()) { disk.disk_dev.device_active = false; } @@ -1289,7 +1341,7 @@ void adamFuji::mount_all() // And now mount it disk.disk_type = disk.disk_dev.mount(disk.fileh, disk.filename, disk.disk_size); - } + } } } @@ -1321,16 +1373,15 @@ void adamFuji::adamnet_get_time() AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - time_t tt = time(nullptr); - setenv("TZ",Config.get_general_timezone().c_str(),1); + setenv("TZ", Config.get_general_timezone().c_str(), 1); tzset(); - struct tm * now = localtime(&tt); + struct tm *now = localtime(&tt); now->tm_mon++; - now->tm_year-=100; + now->tm_year -= 100; response[0] = now->tm_mday; response[1] = now->tm_mon; @@ -1341,7 +1392,7 @@ void adamFuji::adamnet_get_time() response_len = 6; - Debug_printf("Sending %02X %02X %02X %02X %02X %02X\n",now->tm_mday, now->tm_mon, now->tm_year, now->tm_hour, now->tm_min, now->tm_sec); + Debug_printf("Sending %02X %02X %02X %02X %02X %02X\n", now->tm_mday, now->tm_mon, now->tm_year, now->tm_hour, now->tm_min, now->tm_sec); } void adamFuji::adamnet_device_enable_status() @@ -1356,8 +1407,8 @@ void adamFuji::adamnet_device_enable_status() else adamnet_response_nack(); - response_len=1; - response[0]=AdamNet.deviceEnabled(d); + response_len = 1; + response[0] = AdamNet.deviceEnabled(d); } adamDisk *adamFuji::bootdisk() From 948636a8868b347fd426ab8c594492f892c5e60e Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 4 Sep 2023 18:57:44 -0500 Subject: [PATCH 041/158] [adam][printer] move pxq into impl. --- lib/device/adamnet/printer.cpp | 2 ++ lib/device/adamnet/printer.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index 3c4cee7b1..1b7db8839 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -24,6 +24,8 @@ constexpr const char *const adamPrinter::printer_model_str[PRINTER_INVALID]; +static QueueHandle_t pxq; + void printerTask(void *param) { printer_emu *p = (printer_emu *)param; diff --git a/lib/device/adamnet/printer.h b/lib/device/adamnet/printer.h index 7473f144b..65032ff3a 100755 --- a/lib/device/adamnet/printer.h +++ b/lib/device/adamnet/printer.h @@ -22,8 +22,6 @@ typedef struct _printItem uint8_t buf[16]; } PrintItem; -static QueueHandle_t pxq; - class adamPrinter : public virtualDevice { protected: From c5d8760512dfdab819dd421a5e73eb9ba21c1f94 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 4 Sep 2023 21:45:22 -0500 Subject: [PATCH 042/158] [adam][fuji] swap feedback blink. --- lib/device/adamnet/fuji.cpp | 12 ++++++++++++ lib/device/adamnet/fuji.h | 1 + lib/hardware/keys.cpp | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index c807a064a..a3c838550 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -12,6 +12,7 @@ #include "fnConfig.h" #include "fnWiFi.h" #include "fsFlash.h" +#include "led.h" #include "utils.h" @@ -572,8 +573,17 @@ void adamFuji::image_rotate() Debug_printf("count is %u\n", count); + active_rotate_slot++; + + if (active_rotate_slot>count-1) + active_rotate_slot=0; + if (count > 1) { + Debug_printv("ACTIVE ROTATE SLOT %u\n",active_rotate_slot); + + fnLedManager.blink(LED_BUS,active_rotate_slot+1); + count--; // Save the device ID of the disk in the last slot @@ -1286,6 +1296,8 @@ void adamFuji::mount_all() { bool nodisks = true; // Check at the end if no disks are in a slot and disable config + active_rotate_slot=0; + for (int i = 0; i < 4; i++) { fujiDisk &disk = _fnDisks[i]; diff --git a/lib/device/adamnet/fuji.h b/lib/device/adamnet/fuji.h index 4f5ecdc1f..a65b29239 100755 --- a/lib/device/adamnet/fuji.h +++ b/lib/device/adamnet/fuji.h @@ -59,6 +59,7 @@ class adamFuji : public virtualDevice bool scanStarted = false; bool hostMounted[MAX_HOSTS]; bool setSSIDStarted = false; + unsigned char active_rotate_slot=0; uint8_t response[1024]; uint16_t response_len = 0; diff --git a/lib/hardware/keys.cpp b/lib/hardware/keys.cpp index 94af2adba..518ba1b67 100755 --- a/lib/hardware/keys.cpp +++ b/lib/hardware/keys.cpp @@ -271,7 +271,7 @@ void KeyManager::_keystate_task(void *param) // Debug_printf("himem free: %u\r\n", esp_himem_get_free_size()); // Debug_printf("himem reserved: %u\r\n", esp_himem_reserved_area_size()); #else - fnLedManager.blink(BLUETOOTH_LED, 2); // blink to confirm a button press + //fnLedManager.blink(BLUETOOTH_LED, 2); // blink to confirm a button press #endif // PINMAP_A2_REV0 // Either toggle BT baud rate or do a disk image rotation on B_KEY SHORT PRESS From 6f0e3b5ef8054f8bf6646dcf7909739b76e0954b Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 5 Sep 2023 22:03:01 -0500 Subject: [PATCH 043/158] [adam][printer] only use pptr in main task! --- lib/device/adamnet/printer.cpp | 9 +++++---- lib/device/adamnet/printer.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index 1b7db8839..df57f98d0 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -28,7 +28,7 @@ static QueueHandle_t pxq; void printerTask(void *param) { - printer_emu *p = (printer_emu *)param; + adamPrinter *p = (adamPrinter *)param; unsigned char i = 0; while (true) @@ -36,16 +36,17 @@ void printerTask(void *param) while (uxQueueMessagesWaiting(pxq)) { PrintItem pi; + uint8_t *pbuf = p->getPrinterPtr()->provideBuffer(); xQueueReceive(pxq, &pi, portMAX_DELAY); - memcpy(&p->provideBuffer()[i], &pi.buf, pi.len); + memcpy(&pbuf[i], &pi.buf, pi.len); i += pi.len; } if (i) { fnLedManager.set(LED_BT, true); - p->process(i, 0, 0); + p->getPrinterPtr()->process(i,0,0); i = 0; fnLedManager.set(LED_BT, false); } @@ -62,7 +63,7 @@ adamPrinter::adamPrinter(FileSystem *filesystem, printer_type print_type) pxq = xQueueCreate(160, sizeof(PrintItem)); - xTaskCreatePinnedToCore(printerTask,"ptsk",4096,_pptr,PRINTER_PRIORITY,&thPrinter,0); + xTaskCreatePinnedToCore(printerTask,"ptsk",4096,this,PRINTER_PRIORITY,&thPrinter,0); } adamPrinter::~adamPrinter() diff --git a/lib/device/adamnet/printer.h b/lib/device/adamnet/printer.h index 65032ff3a..de7347541 100755 --- a/lib/device/adamnet/printer.h +++ b/lib/device/adamnet/printer.h @@ -107,6 +107,7 @@ class adamPrinter : public virtualDevice printer_emu *getPrinterPtr() { return _pptr; }; + void do_print(int i); private: printer_type _ptype; From f87bd8887c8d83498261a02f42394d494f7e442c Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Wed, 6 Sep 2023 20:18:13 +0100 Subject: [PATCH 044/158] Add extended Adapter Config information --- lib/device/sio/fuji.cpp | 44 ++++++++++++++++++++++++++++++++++++++++- lib/device/sio/fuji.h | 20 +++++++++++++++++++ lib/utils/utils.cpp | 27 +++++++++++++++++++++++++ lib/utils/utils.h | 3 +++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index 9b2e5dde0..2f94e08d0 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -1118,10 +1118,52 @@ void sioFuji::sio_close_directory() sio_complete(); } +void sioFuji::sio_get_adapter_config_extended() +{ + // return string versions of the data rather than just bytes + AdapterConfigExtended cfg; + memset(&cfg, 0, sizeof(cfg)); // ensures all strings are null terminated + + strlcpy(cfg.fn_version, fnSystem.get_fujinet_version(true), sizeof(cfg.fn_version)); + + if (!fnWiFi.connected()) + { + strlcpy(cfg.ssid, "NOT CONNECTED", sizeof(cfg.ssid)); + } + else + { + strlcpy(cfg.hostname, fnSystem.Net.get_hostname().c_str(), sizeof(cfg.hostname)); + strlcpy(cfg.ssid, fnWiFi.get_current_ssid().c_str(), sizeof(cfg.ssid)); + fnWiFi.get_current_bssid(cfg.bssid); + fnSystem.Net.get_ip4_info(cfg.localIP, cfg.netmask, cfg.gateway); + fnSystem.Net.get_ip4_dns_info(cfg.dnsIP); + } + + fnWiFi.get_mac(cfg.macAddress); + + // convert fields to strings + strlcpy(cfg.sLocalIP, fnSystem.Net.get_ip4_address_str().c_str(), 16); + strlcpy(cfg.sGateway, fnSystem.Net.get_ip4_gateway_str().c_str(), 16); + strlcpy(cfg.sDnsIP, fnSystem.Net.get_ip4_dns_str().c_str(), 16); + strlcpy(cfg.sNetmask, fnSystem.Net.get_ip4_mask_str().c_str(), 16); + + sprintf(cfg.sMacAddress, "%02X:%02X:%02X:%02X:%02X:%02X", cfg.macAddress[0], cfg.macAddress[1], cfg.macAddress[2], cfg.macAddress[3], cfg.macAddress[4], cfg.macAddress[5]); + sprintf(cfg.sBssid, "%02X:%02X:%02X:%02X:%02X:%02X", cfg.bssid[0], cfg.bssid[1], cfg.bssid[2], cfg.bssid[3], cfg.bssid[4], cfg.bssid[5]); + + bus_to_computer((uint8_t *)&cfg, sizeof(cfg), false); + +} + // Get network adapter configuration void sioFuji::sio_get_adapter_config() { - Debug_println("Fuji cmd: GET ADAPTER CONFIG"); + Debug_printf("Fuji cmd: GET ADAPTER CONFIG (aux1:%hu)\r\n", cmdFrame.aux1); + if (cmdFrame.aux1 == 1) + { + Debug_println("Returning extended adapter config information"); + sio_get_adapter_config_extended(); + return; + } // Response to FUJICMD_GET_ADAPTERCONFIG AdapterConfig cfg; diff --git a/lib/device/sio/fuji.h b/lib/device/sio/fuji.h index 91612160e..8a984cba0 100755 --- a/lib/device/sio/fuji.h +++ b/lib/device/sio/fuji.h @@ -42,6 +42,25 @@ typedef struct char fn_version[15]; } AdapterConfig; +typedef struct +{ + char ssid[33]; + char hostname[64]; + unsigned char localIP[4]; + unsigned char gateway[4]; + unsigned char netmask[4]; + unsigned char dnsIP[4]; + unsigned char macAddress[6]; + unsigned char bssid[6]; + char fn_version[15]; + char sLocalIP[16]; + char sGateway[16]; + char sNetmask[16]; + char sDnsIP[16]; + char sMacAddress[18]; + char sBssid[18]; +} AdapterConfigExtended; + enum appkey_mode : uint8_t { APPKEYMODE_READ = 0, @@ -112,6 +131,7 @@ class sioFuji : public virtualDevice void sio_net_get_wifi_enabled(); // 0xEA void sio_disk_image_umount(); // 0xE9 void sio_get_adapter_config(); // 0xE8 + void sio_get_adapter_config_extended(); // 0xE8 void sio_new_disk(); // 0xE7 void sio_unmount_host(); // 0xE6 void sio_get_directory_position(); // 0xE5 diff --git a/lib/utils/utils.cpp b/lib/utils/utils.cpp index 8dd4e0f2d..8a44664db 100644 --- a/lib/utils/utils.cpp +++ b/lib/utils/utils.cpp @@ -863,4 +863,31 @@ void util_ascii_to_petscii_str(std::string &s) std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return util_ascii_to_petscii(c); }); +} + +char *util_hexdump(const void *buf, size_t len) { + const unsigned char *p = (const unsigned char *) buf; + size_t i, idx, n = 0, ofs = 0, dlen = len * 5 + 100; + char ascii[17] = "", *dst = (char *) calloc(1, dlen); + if (dst == NULL) return dst; + for (i = 0; i < len; i++) { + idx = i % 16; + if (idx == 0) { + if (i > 0 && dlen > n) + n += (size_t) snprintf(dst + n, dlen - n, " %s\n", ascii); + if (dlen > n) + n += (size_t) snprintf(dst + n, dlen - n, "%04x ", (int) (i + ofs)); + } + if (dlen < n) break; + n += (size_t) snprintf(dst + n, dlen - n, " %02x", p[i]); + ascii[idx] = (char) (p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i]); + ascii[idx + 1] = '\0'; + } + while (i++ % 16) { + if (n < dlen) n += (size_t) snprintf(dst + n, dlen - n, "%s", " "); + } + if (n < dlen) n += (size_t) snprintf(dst + n, dlen - n, " %s\n", ascii); + if (n > dlen - 1) n = dlen - 1; + dst[n] = '\0'; + return dst; } \ No newline at end of file diff --git a/lib/utils/utils.h b/lib/utils/utils.h index 995bdf15e..4c3d44d99 100644 --- a/lib/utils/utils.h +++ b/lib/utils/utils.h @@ -89,4 +89,7 @@ char util_ascii_to_petscii(char c); void util_petscii_to_ascii_str(std::string &s); void util_ascii_to_petscii_str(std::string &s); +// generic hex dump for debug output +char *util_hexdump(const void *buf, size_t len); + #endif // _FN_UTILS_H From c24d16c6b9735a2cb41e7d82bd08906a80666a9d Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 7 Sep 2023 18:24:49 -0500 Subject: [PATCH 045/158] [adam][network] fix do_inquiry --- lib/device/adamnet/network.cpp | 14 +++++++++----- lib/network-protocol/TCP.cpp | 7 +++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index 6e07f7c18..a79bc5fa2 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -592,11 +592,10 @@ void adamNetwork::adamnet_special_00(unsigned short s) cmdFrame.aux2 = adamnet_recv(); AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); - if (protocol->special_00(&cmdFrame) == false) - adamnet_response_ack(); - else - adamnet_response_nack(); + protocol->special_00(&cmdFrame); + inq_dstats = 0xff; } /** @@ -614,6 +613,8 @@ void adamNetwork::adamnet_special_40(unsigned short s) adamnet_response_ack(); else adamnet_response_nack(); + + inq_dstats = 0xff; } /** @@ -640,6 +641,7 @@ void adamNetwork::adamnet_special_80(unsigned short s) adamnet_response_ack(); else adamnet_response_nack(); + inq_dstats = 0xff; } void adamNetwork::adamnet_response_status() @@ -714,9 +716,12 @@ void adamNetwork::adamnet_control_send() set_password(s); break; default: + Debug_printf("fall through to default\n"); switch (channelMode) { case PROTOCOL: + do_inquiry(c); // set inq_dstats + if (inq_dstats == 0x00) adamnet_special_00(s); else if (inq_dstats == 0x40) @@ -741,7 +746,6 @@ void adamNetwork::adamnet_control_send() Debug_printf("Unknown channel mode\n"); break; } - do_inquiry(c); } } diff --git a/lib/network-protocol/TCP.cpp b/lib/network-protocol/TCP.cpp index 17698a334..bbaa5a958 100755 --- a/lib/network-protocol/TCP.cpp +++ b/lib/network-protocol/TCP.cpp @@ -267,12 +267,15 @@ uint8_t NetworkProtocolTCP::special_inquiry(uint8_t cmd) */ bool NetworkProtocolTCP::special_00(cmdFrame_t *cmdFrame) { + Debug_printf("NetworkProtocolTCP::special_00(%c)\n",cmdFrame->comnd); + switch (cmdFrame->comnd) { case 'A': return special_accept_connection(); break; case 'c': + Debug_printf("CLOSING CLIENT CONNECTION!!!\n"); return special_close_client_connection(); break; } @@ -401,14 +404,14 @@ bool NetworkProtocolTCP::special_close_client_connection() { Debug_printf("Attempted close client connection on NULL server socket. Aborting.\r\n"); error = NETWORK_ERROR_SERVER_NOT_RUNNING; - return true; // Error + return false; } if (!client.connected()) { Debug_printf("Attempted close client with no client connected.\r\n"); error = NETWORK_ERROR_NOT_CONNECTED; - return true; + return false; } remoteIP = client.remoteIP(); From 5af0e7d95296f34f0b3ebb0ca92701b906bc6256 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 9 Sep 2023 20:00:43 -0400 Subject: [PATCH 046/158] link at 2mbps --- lib/bus/mac/mac.h | 2 +- pico/mac/commands.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bus/mac/mac.h b/lib/bus/mac/mac.h index 7f39b20f9..6a0d9c1d2 100644 --- a/lib/bus/mac/mac.h +++ b/lib/bus/mac/mac.h @@ -80,7 +80,7 @@ class macBus // iwmPrinter *_printerdev = nullptr; // iwmClock *_clockDev = nullptr; - const int _mac_baud_rate = 1000000; //230400; //was 115200; + const int _mac_baud_rate = 2000000; //230400; //was 115200; public: std::forward_list _daisyChain; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index b49743636..2415ebb37 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -36,7 +36,7 @@ void pio_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin); #define UART_ID uart1 -#define BAUD_RATE 1000000 //230400 //115200 +#define BAUD_RATE 2000000 //230400 //115200 #define DATA_BITS 8 #define STOP_BITS 1 #define PARITY UART_PARITY_NONE From 428b11faf31602ff15d80d245715df45a859fa73 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sun, 10 Sep 2023 17:36:49 -0400 Subject: [PATCH 047/158] a start at DCD --- pico/mac/CMakeLists.txt | 1 + pico/mac/commands.c | 132 ++++++++++++++++++++++++++++++---------- pico/mac/dcd_latch.pio | 45 ++++++++++++++ 3 files changed, 145 insertions(+), 33 deletions(-) create mode 100644 pico/mac/dcd_latch.pio diff --git a/pico/mac/CMakeLists.txt b/pico/mac/CMakeLists.txt index deec035cf..54fef039b 100644 --- a/pico/mac/CMakeLists.txt +++ b/pico/mac/CMakeLists.txt @@ -31,6 +31,7 @@ pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/commands.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/echo.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/latch.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/mux.pio) +pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_latch.pio) # however, alternatively you can choose to generate it somewhere else (in this case in the source tree for check in) #pico_generate_pio_header(pio_and ${CMAKE_CURRENT_LIST_DIR}/blink.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2415ebb37..626de0eb0 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -4,17 +4,25 @@ * SPDX-License-Identifier: BSD-3-Clause */ +//#define FLOPPY +#undef FLOPPY +//#undef DCD +#define DCD + #include #include "pico/stdlib.h" #include "hardware/uart.h" #include "hardware/clocks.h" #include "hardware/pio.h" + #include "commands.pio.h" #include "echo.pio.h" #include "latch.pio.h" #include "mux.pio.h" +#include "dcd_latch.pio.h" + // #include "../../include/pinmap/mac_rev0.h" #define UART_TX_PIN 4 #define UART_RX_PIN 5 @@ -30,11 +38,18 @@ #define SM_MUX 2 #define SM_ECHO 3 +#define SM_DCD_LATCH 0 +#define SM_DCD_READ 1 +#define SM_DCD_WRITE 2 +#define SM_DCD_MUX 3 + void pio_commands(PIO pio, uint sm, uint offset, uint pin); void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins); void pio_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin); +void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); + #define UART_ID uart1 #define BAUD_RATE 2000000 //230400 //115200 #define DATA_BITS 8 @@ -51,7 +66,8 @@ const int tach_lut[5][3] = {{0, 15, 394}, uint32_t a; char c; -PIO pio = pio0; +PIO pio_floppy = pio0; +PIO pio_dcd = pio1; void setup_esp_uart() { @@ -130,9 +146,11 @@ enum latch_bits { REVISED // f REVISED This status line is used to indicate that the interface definition of the connected external drive. When REVISED is a one, the drive Part No. will be 699-0326 or when REVISED is a zero, the drive Part No. will be 699-0285. }; -uint16_t latch = 0; +uint16_t latch; +uint8_t dcd_latch; uint16_t get_latch() { return latch; } +uint8_t dcd_get_latch() { return dcd_latch; } uint16_t set_latch(enum latch_bits s) { @@ -140,17 +158,43 @@ uint16_t set_latch(enum latch_bits s) return latch; }; +uint8_t dcd_set_latch(uint8_t s) +{ + dcd_latch |= (1u << s); + return dcd_latch; +} + uint16_t clr_latch(enum latch_bits c) { latch &= ~(1u << c); return latch; }; -bool latch_val(enum latch_bits b) +uint8_t dcd_clr_latch(uint8_t c) +{ + dcd_latch &= ~(1u << c); + return dcd_latch; +}; + +uint8_t dcd_assert_hshk() { - return (latch & (1u << b)); + dcd_clr_latch(2); + dcd_clr_latch(3); + return dcd_latch; } +uint8_t dcd_deassert_hshk() +{ + dcd_set_latch(2); + dcd_set_latch(3); + return dcd_latch; +} + +// bool latch_val(enum latch_bits b) +// { +// return (latch & (1u << b)); +// } + void preset_latch() { latch =0; @@ -169,6 +213,10 @@ void preset_latch() // printf("\nlatch bit %02d = %d",i, latch_val(i)); } +void dcd_preset_latch() +{ + dcd_latch = 0b11001100; // DCD signature HHLx + no handshake HHxx +} void set_tach_freq(char c) { @@ -185,52 +233,58 @@ void set_tach_freq(char c) } void loop(); +void dcd_loop(); void setup() { - - stdio_init_all(); - // gpio_pull_up(ENABLE); + uint offset; - set_tach_freq(0); // start TACH clock - + stdio_init_all(); setup_default_uart(); setup_esp_uart(); +#ifdef FLOPPY + set_tach_freq(0); // start TACH clock preset_latch(); - uint offset = pio_add_program(pio, &commands_program); + offset = pio_add_program(pio_floppy, &commands_program); printf("\nLoaded cmd program at %d\n", offset); - pio_commands(pio, SM_CMD, offset, MCI_CA0); // read phases starting on pin 8 + pio_commands(pio_floppy, SM_CMD, offset, MCI_CA0); // read phases starting on pin 8 - offset = pio_add_program(pio, &echo_program); + offset = pio_add_program(pio_floppy, &echo_program); printf("Loaded echo program at %d\n", offset); - pio_echo(pio, SM_ECHO, offset, ECHO_IN, ECHO_OUT, 2); + pio_echo(pio_floppy, SM_ECHO, offset, ECHO_IN, ECHO_OUT, 2); - offset = pio_add_program(pio, &latch_program); + offset = pio_add_program(pio_floppy, &latch_program); printf("Loaded latch program at %d\n", offset); - pio_latch(pio, SM_LATCH, offset, MCI_CA0, LATCH_OUT); - pio_sm_put_blocking(pio, SM_LATCH, 0xffff); // send the register word to the PIO + pio_latch(pio_floppy, SM_LATCH, offset, MCI_CA0, LATCH_OUT); + pio_sm_put_blocking(pio_floppy, SM_LATCH, get_latch()); // send the register word to the PIO - offset = pio_add_program(pio, &mux_program); + offset = pio_add_program(pio_floppy, &mux_program); printf("Loaded mux program at %d\n", offset); - pio_mux(pio, SM_MUX, offset, MCI_CA0, ECHO_OUT); -} + pio_mux(pio_floppy, SM_MUX, offset, MCI_CA0, ECHO_OUT); +#elif defined(DCD) -int main() -{ - setup(); - // latch setup + dcd_preset_latch(); - // 11xx x101 00xx 0110 + offset = pio_add_program(pio_dcd, &dcd_latch_program); + printf("Loaded DCD latch program at %d\n", offset); + pio_dcd_latch(pio_dcd, SM_DCD_LATCH, offset, MCI_CA0, LATCH_OUT); + pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO - pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO - - +#endif // FLOPPY +} +int main() +{ + setup(); while (true) { - loop(); +#ifdef FLOPPY + loop(); +#elif defined(DCD) + dcd_loop(); +#endif } } @@ -238,9 +292,9 @@ bool step_state = false; void loop() { - if (!pio_sm_is_rx_fifo_empty(pio, SM_CMD)) + if (!pio_sm_is_rx_fifo_empty(pio_floppy, SM_CMD)) { - a = pio_sm_get_blocking(pio, SM_CMD); + a = pio_sm_get_blocking(pio_floppy, SM_CMD); switch (a) { // !READY @@ -296,7 +350,7 @@ void loop() printf("\nUNKNOWN PHASE COMMAND"); break; } - pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pio_floppy, SM_LATCH, get_latch()); // send the register word to the PIO uart_putc_raw(UART_ID, (char)(a + '0')); } @@ -351,13 +405,18 @@ void loop() break; } // printf("latch %04x", get_latch()); - pio_sm_put_blocking(pio, SM_LATCH, get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pio_floppy, SM_LATCH, get_latch()); // send the register word to the PIO } // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO // to do: read both enable lines and indicate which drive is active when sending single char to esp32 } +void dcd_loop() +{ + +} + void pio_commands(PIO pio, uint sm, uint offset, uint pin) { commands_program_init(pio, sm, offset, pin); pio_sm_set_enabled(pio, sm, true); @@ -379,4 +438,11 @@ void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin) { mux_program_init(pio, sm, offset, in_pin, mux_pin); pio_sm_set_enabled(pio, sm, true); -} \ No newline at end of file +} + +void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) +{ + dcd_latch_program_init(pio, sm, offset, in_pin, out_pin); + pio_sm_set_enabled(pio, sm, true); +} + diff --git a/pico/mac/dcd_latch.pio b/pico/mac/dcd_latch.pio new file mode 100644 index 000000000..a9b3ec98c --- /dev/null +++ b/pico/mac/dcd_latch.pio @@ -0,0 +1,45 @@ +; +; FujiNet Project +; +; Vintage Macintosh Microfloppy Controller Interface +; Reads the drive phases and output a dcd_latch bit +; + +.define ENABLE 7 + +.program dcd_latch +start: + wait 0 gpio ENABLE + mov osr, pins ; read the GPIO's into the output shift register + out y, 3 ; shift the 3 LSBs into Y + pull noblock ; get the dcd_latch word into OSR, if no new word in FIFO, get it from X + mov x, osr ; put the osr back into X in case it's new +.wrap_target + jmp y-- loop ; if y>0 goto to loop and decrement y + out pins, 1 ; output the desired bit + jmp start ; do it again +loop: + out null, 1 ; get rid of a bit +.wrap + + +% c-sdk { +// this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin + +void dcd_latch_program_init(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) { + // configure a SM + pio_sm_config c = dcd_latch_program_get_default_config(offset); + // set the out pin to out_pin + sm_config_set_out_pins(&c, out_pin, 1); + // start at in_pin to read in the phases + sm_config_set_in_pins(&c, in_pin); + // get 8 bit dcd_latch values through the OSR from the main program + sm_config_set_out_shift(&c, true, false, 8); + // set out_pin as a GPIO output connected to this SM + pio_gpio_init(pio, out_pin); + pio_sm_set_consecutive_pindirs(pio, sm, out_pin, 1, true); // TODO change back - manually set output for now + // sm_config_set_set_pins(&c, pin, 1); + // initialize + pio_sm_init(pio, sm, offset, &c); +} +%} \ No newline at end of file From aa1b7f5e176e835851a8538e5162962e56b4b7ce Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sun, 10 Sep 2023 22:13:47 -0400 Subject: [PATCH 048/158] detect changing phases for DCD --- pico/mac/CMakeLists.txt | 1 + pico/mac/commands.c | 17 ++++++++++++--- pico/mac/dcd_commands.pio | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 pico/mac/dcd_commands.pio diff --git a/pico/mac/CMakeLists.txt b/pico/mac/CMakeLists.txt index 54fef039b..932d5519b 100644 --- a/pico/mac/CMakeLists.txt +++ b/pico/mac/CMakeLists.txt @@ -32,6 +32,7 @@ pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/echo.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/latch.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/mux.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_latch.pio) +pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_commands.pio) # however, alternatively you can choose to generate it somewhere else (in this case in the source tree for check in) #pico_generate_pio_header(pio_and ${CMAKE_CURRENT_LIST_DIR}/blink.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 626de0eb0..2a05ad49e 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -22,6 +22,7 @@ #include "mux.pio.h" #include "dcd_latch.pio.h" +#include "dcd_commands.pio.h" // #include "../../include/pinmap/mac_rev0.h" #define UART_TX_PIN 4 @@ -39,7 +40,7 @@ #define SM_ECHO 3 #define SM_DCD_LATCH 0 -#define SM_DCD_READ 1 +#define SM_DCD_CMD 1 #define SM_DCD_WRITE 2 #define SM_DCD_MUX 3 @@ -270,7 +271,11 @@ void setup() offset = pio_add_program(pio_dcd, &dcd_latch_program); printf("Loaded DCD latch program at %d\n", offset); pio_dcd_latch(pio_dcd, SM_DCD_LATCH, offset, MCI_CA0, LATCH_OUT); - pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO + + offset = pio_add_program(pio_dcd, &dcd_commands_program); + printf("Loaded DCD commands program at %d\n", offset); + pio_dcd_commands(pio_dcd, SM_DCD_CMD, offset, MCI_CA0); #endif // FLOPPY } @@ -414,7 +419,8 @@ void loop() void dcd_loop() { - + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + printf("%c",a+'0'); } void pio_commands(PIO pio, uint sm, uint offset, uint pin) { @@ -446,3 +452,8 @@ void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) pio_sm_set_enabled(pio, sm, true); } +void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin) +{ + dcd_commands_program_init(pio, sm, offset, pin); + pio_sm_set_enabled(pio, sm, true); +} \ No newline at end of file diff --git a/pico/mac/dcd_commands.pio b/pico/mac/dcd_commands.pio new file mode 100644 index 000000000..adc208c2e --- /dev/null +++ b/pico/mac/dcd_commands.pio @@ -0,0 +1,44 @@ +; +; FujiNet Project +; +; Vintage Macintosh Microfloppy Controller Interface +; sends the phases to the PICO when the strobe sets +; + +.define LSTRB 12 +.define ENABLE 7 + +.program dcd_commands +start: +.wrap_target + wait 0 gpio ENABLE ; are we enabled? + mov osr, pins ; get the phase values + out x, 3 ; move 3 bits into X + jmp x!=y next ; pins have changes + jmp start +next: + in x, 3 ; send the phase values to fifo + mov y, x ; remember the current phase state +.wrap + +% c-sdk { +// this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin + +void dcd_commands_program_init(PIO pio, uint sm, uint offset, uint pin) { + // configure a SM + pio_sm_config c = dcd_commands_program_get_default_config(offset); + // set the out pin to pin +// sm_config_set_out_pins(&c, pin, 1); + // start at GPIO2 to read in the dcd_commands + sm_config_set_in_pins(&c, pin); // start at GPIO 2 for the dcd_commands + // there are 3 wires to read for latch mux, shift to the left, autopush + sm_config_set_in_shift(&c, false, true, 3); + // sm_config_set_out_shift(&c, true, false, 1); // shift to the right + // set pin as a GPIO output connected to this SM + // pio_gpio_init(pio, pin); + // pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + // sm_config_set_set_pins(&c, pin, 1); + // initialize + pio_sm_init(pio, sm, offset, &c); +} +%} From 90e8582f1c16059dad314e0140899bf48bcb25a9 Mon Sep 17 00:00:00 2001 From: Jan Krupa Date: Mon, 11 Sep 2023 19:30:18 +0200 Subject: [PATCH 049/158] [atari][fuji] few fixes to bas64 and hash functions --- lib/device/sio/fuji.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index 2f94e08d0..96fd5025d 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -1794,16 +1794,22 @@ void sioFuji::sio_base64_encode_length() Debug_printf("FUJI: BASE64 ENCODE LENGTH\n"); size_t l = base64_buffer.length(); + uint8_t response[4] = { + (uint8_t)(l >> 0), + (uint8_t)(l >> 8), + (uint8_t)(l >> 16), + (uint8_t)(l >> 24) + }; if (!l) { Debug_printf("BASE64 buffer is 0 bytes, sending error.\n"); - bus_to_computer((uint8_t *)l, sizeof(size_t), true); + bus_to_computer(response, sizeof(response), true); } Debug_printf("base64 buffer length: %u bytes\n", l); - bus_to_computer((uint8_t *)&l, sizeof(size_t), false); + bus_to_computer(response, sizeof(response), false); } void sioFuji::sio_base64_encode_output() @@ -1840,6 +1846,7 @@ void sioFuji::sio_base64_encode_output() base64_buffer.shrink_to_fit(); bus_to_computer(p, l, false); + free(p); } void sioFuji::sio_base64_decode_input() @@ -1901,17 +1908,23 @@ void sioFuji::sio_base64_decode_length() Debug_printf("FUJI: BASE64 DECODE LENGTH\n"); size_t l = base64_buffer.length(); + uint8_t response[4] = { + (uint8_t)(l >> 0), + (uint8_t)(l >> 8), + (uint8_t)(l >> 16), + (uint8_t)(l >> 24) + }; if (!l) { Debug_printf("BASE64 buffer is 0 bytes, sending error.\n"); - sio_error(); + bus_to_computer(response, sizeof(response), true); return; } Debug_printf("base64 buffer length: %u bytes\n", l); - bus_to_computer((uint8_t *)&l, sizeof(size_t), false); + bus_to_computer(response, sizeof(response), false); } void sioFuji::sio_base64_decode_output() @@ -1950,6 +1963,7 @@ void sioFuji::sio_base64_decode_output() base64_buffer.erase(0, l); base64_buffer.shrink_to_fit(); bus_to_computer(p, l, false); + free(p); } void sioFuji::sio_hash_input() @@ -2074,7 +2088,7 @@ void sioFuji::sio_hash_length() if (m == 1) // Hex output m <<= 1; // double it. - bus_to_computer((uint8_t *)r, 1, false); + bus_to_computer((uint8_t *)&r, 1, false); } void sioFuji::sio_hash_output() From 2f9137436b36732901665fe15082d49fb05f28f5 Mon Sep 17 00:00:00 2001 From: Jan Krupa Date: Tue, 12 Sep 2023 18:59:57 +0200 Subject: [PATCH 050/158] [atari][fuji] improve error handling for read appkey --- lib/bus/sio/sio.cpp | 5 +++-- lib/device/sio/fuji.cpp | 25 ++++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/bus/sio/sio.cpp b/lib/bus/sio/sio.cpp index 8259116a4..31f7f2854 100755 --- a/lib/bus/sio/sio.cpp +++ b/lib/bus/sio/sio.cpp @@ -66,6 +66,7 @@ void virtualDevice::bus_to_computer(uint8_t *buf, uint16_t len, bool err) uart->flush(); } +// TODO apc: change return type to indicate valid/invalid checksum /* SIO READ from ATARI by DEVICE buf = buffer from atari to fujinet @@ -102,12 +103,12 @@ uint8_t virtualDevice::bus_to_peripheral(uint8_t *buf, unsigned short len) if (ck_rcv != ck_tst) { sio_nak(); - return false; + // return false; // apc } else sio_ack(); - return ck_rcv; + return ck_rcv; // TODO apc: change to true and update all callers, no need to calculate/check checksum again } // SIO NAK diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index 96fd5025d..5d55e7b51 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -694,7 +694,8 @@ void sioFuji::sio_write_app_key() if (sio_checksum((uint8_t *)value, sizeof(value)) != ck) { - sio_error(); + // apc: don't send 'E' on checksum error, 'N' was sent already + // sio_error(); return; } @@ -754,11 +755,20 @@ void sioFuji::sio_read_app_key() Debug_println("Fuji cmd: READ APPKEY"); + struct + { + uint16_t size; + uint8_t value[MAX_APPKEY_LEN]; + } __attribute__((packed)) response; + memset(&response, 0, sizeof(response)); + // Make sure we have an SD card mounted if (fnSDFAT.running() == false) { Debug_println("No SD mounted - can't read app key"); - sio_error(); + // sio_error(); + // apc: we have to send error + dummy data after cmd was acked + bus_to_computer((uint8_t *)&response, sizeof(response), true); return; } @@ -766,7 +776,7 @@ void sioFuji::sio_read_app_key() if (_current_appkey.creator == 0 || _current_appkey.mode != APPKEYMODE_READ) { Debug_println("Invalid app key metadata - aborting"); - sio_error(); + bus_to_computer((uint8_t *)&response, sizeof(response), true); return; } @@ -778,17 +788,10 @@ void sioFuji::sio_read_app_key() if (fIn == nullptr) { Debug_printf("Failed to open input file: errno=%d\n", errno); - sio_error(); + bus_to_computer((uint8_t *)&response, sizeof(response), true); return; } - struct - { - uint16_t size; - uint8_t value[MAX_APPKEY_LEN]; - } __attribute__((packed)) response; - memset(&response, 0, sizeof(response)); - size_t count = fread(response.value, 1, sizeof(response.value), fIn); fclose(fIn); From 87ba53d936d96925f497094288222f06b15c974f Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Wed, 13 Sep 2023 15:13:09 +0100 Subject: [PATCH 051/158] Add bad-connection detection to set-ssid --- lib/config/fnc_wifi.cpp | 3 +- lib/device/sio/fuji.cpp | 315 ++++++++++++++++++++++++++++++++-------- lib/device/sio/fuji.h | 1 + lib/hardware/fnWiFi.cpp | 109 ++++++++++++++ lib/hardware/fnWiFi.h | 10 +- 5 files changed, 376 insertions(+), 62 deletions(-) diff --git a/lib/config/fnc_wifi.cpp b/lib/config/fnc_wifi.cpp index df90301e0..8badf2fa0 100644 --- a/lib/config/fnc_wifi.cpp +++ b/lib/config/fnc_wifi.cpp @@ -57,8 +57,7 @@ void fnConfig::_read_section_wifi(std::stringstream &ss) Debug_println("Reading wifi section"); // Throw out any existing data - _wifi.ssid.clear(); - _wifi.passphrase.clear(); + reset_wifi(); std::string line; // Read lines until one starts with '[' which indicates a new section diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index 2f94e08d0..70909a8f9 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -21,6 +21,8 @@ #include "base64.h" +#define ADDITIONAL_DETAILS_BYTES 10 + sioFuji theFuji; // global fuji device object // sioDisk sioDiskDevs[MAX_HOSTS]; @@ -219,82 +221,94 @@ void sioFuji::sio_net_set_ssid() uint8_t ck = bus_to_peripheral((uint8_t *)&cfg, sizeof(cfg)); - if (sio_checksum((uint8_t *)&cfg, sizeof(cfg)) != ck) + if (sio_checksum((uint8_t *)&cfg, sizeof(cfg)) != ck) { sio_error(); - else - { - bool save = cmdFrame.aux1 != 0; + return; + } - Debug_printf("Connecting to net: %s password: %s\n", cfg.ssid, cfg.password); + bool save = cmdFrame.aux1 != 0; - fnWiFi.connect(cfg.ssid, cfg.password); + Debug_printf("Connecting to net: >%s< password: >%s<\r\n", cfg.ssid, cfg.password); - // Only save these if we're asked to, otherwise assume it was a test for connectivity - if (save) - { - // 1. if this is a new SSID and not in the old stored, we should push the current one to the top of the stored configs, and everything else down. - // 2. If this was already in the stored configs, push the stored one to the top, remove the new one from stored so it becomes current only. - // 3. if this is same as current, then just save it again. User reconnected to current, nothing to change in stored. This is default if above don't happen + int test_result = fnWiFi.test_connect(cfg.ssid, cfg.password); + if (test_result != 0) + { + Debug_println("Could not connect to target SSID. Aborting save."); + sio_error(); + return; + } + + // Only save these if we're asked to, otherwise assume it was a test for connectivity + if (save) + { + // 1. if this is a new SSID and not in the old stored, we should push the current one to the top of the stored configs, and everything else down. + // 2. If this was already in the stored configs, push the stored one to the top, remove the new one from stored so it becomes current only. + // 3. if this is same as current, then just save it again. User reconnected to current, nothing to change in stored. This is default if above don't happen - int ssid_in_stored = -1; - for (i = 0; i < MAX_WIFI_STORED; i++) + int ssid_in_stored = -1; + for (i = 0; i < MAX_WIFI_STORED; i++) + { + if (Config.get_wifi_stored_ssid(i) == cfg.ssid) { - if (Config.get_wifi_stored_ssid(i) == cfg.ssid) - { - ssid_in_stored = i; - break; - } + ssid_in_stored = i; + break; } + } - // case 1 - if (ssid_in_stored == -1 && Config.have_wifi_info() && Config.get_wifi_ssid() != cfg.ssid) + // case 1 + if (ssid_in_stored == -1 && Config.have_wifi_info() && Config.get_wifi_ssid() != cfg.ssid) + { + Debug_println("Case 1: Didn't find new ssid in stored, and it's new. Pushing everything down 1 and old current to 0"); + // Move enabled stored down one, last one will drop off + for (int j = MAX_WIFI_STORED - 1; j > 0; j--) { - Debug_println("Case 1: Didn't find new ssid in stored, and it's new. Pushing everything down 1 and old current to 0"); - // Move enabled stored down one, last one will drop off - for (int j = MAX_WIFI_STORED - 1; j > 0; j--) - { - bool enabled = Config.get_wifi_stored_enabled(j - 1); - if (!enabled) - continue; + bool enabled = Config.get_wifi_stored_enabled(j - 1); + if (!enabled) + continue; - Config.store_wifi_stored_ssid(j, Config.get_wifi_stored_ssid(j - 1)); - Config.store_wifi_stored_passphrase(j, Config.get_wifi_stored_passphrase(j - 1)); - Config.store_wifi_stored_enabled(j, true); // already confirmed this is enabled - } - // push the current to the top of stored - Config.store_wifi_stored_ssid(0, Config.get_wifi_ssid()); - Config.store_wifi_stored_passphrase(0, Config.get_wifi_passphrase()); - Config.store_wifi_stored_enabled(0, true); + Config.store_wifi_stored_ssid(j, Config.get_wifi_stored_ssid(j - 1)); + Config.store_wifi_stored_passphrase(j, Config.get_wifi_stored_passphrase(j - 1)); + Config.store_wifi_stored_enabled(j, true); // already confirmed this is enabled } + // push the current to the top of stored + Config.store_wifi_stored_ssid(0, Config.get_wifi_ssid()); + Config.store_wifi_stored_passphrase(0, Config.get_wifi_passphrase()); + Config.store_wifi_stored_enabled(0, true); + } - // case 2 - if (ssid_in_stored != -1 && Config.have_wifi_info() && Config.get_wifi_ssid() != cfg.ssid) + // case 2 + if (ssid_in_stored != -1 && Config.have_wifi_info() && Config.get_wifi_ssid() != cfg.ssid) + { + Debug_printf("Case 2: Found new ssid in stored at %d, and it's not current (should never happen). Pushing everything down 1 and old current to 0\n", ssid_in_stored); + // found the new SSID at ssid_in_stored, so move everything above it down one slot, and store the current at 0 + for (int j = ssid_in_stored; j > 0; j--) { - Debug_printf("Case 2: Found new ssid in stored at %d, and it's not current (should never happen). Pushing everything down 1 and old current to 0\n", ssid_in_stored); - // found the new SSID at ssid_in_stored, so move everything above it down one slot, and store the current at 0 - for (int j = ssid_in_stored; j > 0; j--) - { - Config.store_wifi_stored_ssid(j, Config.get_wifi_stored_ssid(j - 1)); - Config.store_wifi_stored_passphrase(j, Config.get_wifi_stored_passphrase(j - 1)); - Config.store_wifi_stored_enabled(j, true); - } - - // push the current to the top of stored - Config.store_wifi_stored_ssid(0, Config.get_wifi_ssid()); - Config.store_wifi_stored_passphrase(0, Config.get_wifi_passphrase()); - Config.store_wifi_stored_enabled(0, true); + Config.store_wifi_stored_ssid(j, Config.get_wifi_stored_ssid(j - 1)); + Config.store_wifi_stored_passphrase(j, Config.get_wifi_stored_passphrase(j - 1)); + Config.store_wifi_stored_enabled(j, true); } - // save the new SSID as current - Config.store_wifi_ssid(cfg.ssid, sizeof(cfg.ssid)); - // Clear text here, it will be encrypted internally if enabled for encryption - Config.store_wifi_passphrase(cfg.password, sizeof(cfg.password)); - - Config.save(); + // push the current to the top of stored + Config.store_wifi_stored_ssid(0, Config.get_wifi_ssid()); + Config.store_wifi_stored_passphrase(0, Config.get_wifi_passphrase()); + Config.store_wifi_stored_enabled(0, true); } - sio_complete(); + // save the new SSID as current + Config.store_wifi_ssid(cfg.ssid, sizeof(cfg.ssid)); + // Clear text here, it will be encrypted internally if enabled for encryption + Config.store_wifi_passphrase(cfg.password, sizeof(cfg.password)); + + Config.save(); } + Debug_println("Restarting WiFiManager"); + fnWiFi.start(); + + // give it a few seconds to restart the WiFi before we return to the client, who will immediately start checking status + // and get errors if we're not up yet + fnSystem.delay(3000); + + sio_complete(); } // Get WiFi Status @@ -1003,8 +1017,192 @@ void _set_additional_direntry_details(fsdir_entry_t *f, uint8_t *dest, uint8_t m dest[9] = MediaType::discover_disktype(f->filename); } +// TODO: VERIFY THIS CODE. THE STASH SEEMED CORRUPT +void sioFuji::sio_read_directory_block() +{ + // aux1 holds entry size for each record + uint8_t maxlen = cmdFrame.aux1; + + // aux2: + // b0-2 = number of pages - 1 (i.e. 1 to 8) + // b3,4 = not used + // b5 = extended entry information (as per normal, adds 10 bytes of information to each entry at start) + // b6,7 = block mode marker already checked. + + bool is_extended = ((cmdFrame.aux2 & 0x20) == 0x20); + uint8_t pages = (cmdFrame.aux2 & 0x07) + 1; + + Debug_printf("Fuji cmd: READ DIRECTORY BLOCK (pages=%d, maxlen=%d, extended: %d)\n", pages, maxlen, is_extended); + + std::vector response; + std::vector start_offsets; // holds all the offsets for each dir entry in the response + std::vector data_block; // the data for each dir entry. no terminator char needed as we track the offsets. Double 0x7f is end of dir, and no more entries will come + + uint16_t response_max = pages * 256; + + if (_current_open_directory_slot == -1) + { + Debug_print("No currently open directory\n"); + sio_error(); + return; + } + + bool is_eod = false; + char current_entry[256]; + uint16_t num_entries = 0; + uint16_t total_size = 9; // header bytes + + uint16_t initial_pos = _fnHosts[_current_open_directory_slot].dir_tell(); + + // keep filling buffers up until it can't fit another maxlen (plus header bytes etc) + // or we hit end of dir + while ( !is_eod && num_entries < 256 ) + { + uint16_t additional_size = 0; + uint16_t pos_before_next = _fnHosts[_current_open_directory_slot].dir_tell(); + fsdir_entry_t *f = _fnHosts[_current_open_directory_slot].dir_nextfile(); + if (f == nullptr) + { + // reached end of dir + is_eod = true; + current_entry[0] = 0x7F; + current_entry[1] = 0x7F; + current_entry[2] = 0; + additional_size = 2; + } + else + { + Debug_printf("::read_direntry \"%s\"\n", f->filename); + + int bufsize; + char *filenamedest = current_entry; + + // If 0x80 is set on AUX2, send back additional information + if (is_extended) + { + _set_additional_direntry_details(f, (uint8_t *)current_entry, maxlen); + // Adjust remaining size of buffer and file path destination + bufsize = sizeof(current_entry) - ADDITIONAL_DETAILS_BYTES; + filenamedest = current_entry + ADDITIONAL_DETAILS_BYTES; + } + else + { + bufsize = maxlen; + } + + int filelen = util_ellipsize(f->filename, filenamedest, bufsize); + additional_size = filelen + is_extended ? ADDITIONAL_DETAILS_BYTES : 0; + + // Add a slash at the end of directory entries + if (f->isDir && filelen < (bufsize - 2)) + { + current_entry[filelen] = '/'; + current_entry[filelen + 1] = '\0'; + additional_size++; + } + + } + + // would this take us over the limit? 2 for start_offset bytes. + uint16_t new_size = total_size + 2 + additional_size; + + if (new_size > response_max) { + Debug_printf("skipping add, would have taken us to %d size. additional was: %d\n", new_size, additional_size); + // reset to previous pos, and exit loop + _fnHosts[_current_open_directory_slot].dir_seek(pos_before_next); + break; + } else { + Debug_printf("adding additional entry with size: %d\n", additional_size); + } + + + start_offsets.push_back(static_cast(data_block.size() & 0xFF)); // lo byte of current size (which is same as offset) + start_offsets.push_back(static_cast((data_block.size() >> 8) & 0xFF)); // high byte + + // add the string to the data block without the terminating null + if (is_extended) + { + // strlen doesn't work as we have prepended some additional information + // add the additional bytes first + for(int i=0; i < ADDITIONAL_DETAILS_BYTES; i++) + { + data_block.push_back(static_cast(current_entry[i])); + } + // Then add the string part + int s_len = std::strlen(current_entry + ADDITIONAL_DETAILS_BYTES); + data_block.insert(data_block.end(), current_entry + ADDITIONAL_DETAILS_BYTES, current_entry + ADDITIONAL_DETAILS_BYTES + std::strlen(current_entry + ADDITIONAL_DETAILS_BYTES)); + } else { + data_block.insert(data_block.end(), current_entry, current_entry + std::strlen(current_entry)); + } + + total_size = 9 + data_block.size() + start_offsets.size(); + Debug_printf("current sizes, data: %d, offsets: %d, total: %d\n", data_block.size(), start_offsets.size(), data_block.size() + start_offsets.size()); + + + num_entries++; + } + + // ################################################################### + // CREATE THE RESPONSE BLOCK: + // ################################################################### + // byte 0-1 = "MF" (Multi-File, take your pick :D ) + // byte 2 = Flags (currently 0x80 = Extended Information) + // byte 3 = Max Size Per Entry (maxlen from input) + // byte 4 = Num Entries in block (max 255) + // byte 5-6 = Total size of block (i.e. size without padding) + // byte 7-8 = First Position in block (i.e. dir pos value at start), allows up to 64k entries over all blocks + // Num Entries x 2 = Offsets in Data for each entry + // Data x Num Entries = data for each dir. + // + // All above is < pages x 256 in size + + // HEADER BYTES + std::string headerBytes = "MF"; + response.insert(response.end(), headerBytes.begin(), headerBytes.end()); + + // FLAGS + uint8_t header_flags = is_extended ? 0x80 : 0; // more flags may come + response.push_back(header_flags); + + // MAX SIZE PER ENTRY + response.push_back(maxlen); + + // NUM ENTRIES + response.push_back(static_cast(num_entries)); + + // Total size + int final_size = 9 + data_block.size() + start_offsets.size(); + response.push_back(static_cast(final_size & 0xFF)); + response.push_back(static_cast((final_size >> 8) & 0xFF)); + + // INITIAL POS VALUE + response.push_back(static_cast(initial_pos & 0xFF)); + response.push_back(static_cast((initial_pos >> 8) & 0xFF)); + + // OFFSETS + response.insert(response.end(), start_offsets.begin(), start_offsets.end()); + + // DATA + response.insert(response.end(), data_block.begin(), data_block.end()); + + Debug_printf("Actual data size: %d to atari\n", response.size()); + char *s = util_hexdump(response.data(), response.size()); + Debug_printf("dump: \n%s\n", s); + + // buffer with 0s to requested size + response.resize(response_max, 0); + + bus_to_computer(response.data(), response_max, false); +} + void sioFuji::sio_read_directory_entry() { + if ((cmdFrame.aux2 & 0xC0) == 0xC0) { + // Block mode directory entry + sio_read_directory_block(); + return; + } + uint8_t maxlen = cmdFrame.aux1; Debug_printf("Fuji cmd: READ DIRECTORY ENTRY (max=%hu)\n", maxlen); @@ -1033,7 +1231,6 @@ void sioFuji::sio_read_directory_entry() int bufsize = sizeof(current_entry); char *filenamedest = current_entry; -#define ADDITIONAL_DETAILS_BYTES 10 // If 0x80 is set on AUX2, send back additional information if (cmdFrame.aux2 & 0x80) { diff --git a/lib/device/sio/fuji.h b/lib/device/sio/fuji.h index 8a984cba0..4c2b7e339 100755 --- a/lib/device/sio/fuji.h +++ b/lib/device/sio/fuji.h @@ -122,6 +122,7 @@ class sioFuji : public virtualDevice void sio_disk_image_mount(); // 0xF8 void sio_open_directory(); // 0xF7 void sio_read_directory_entry(); // 0xF6 + void sio_read_directory_block(); // 0xF6 void sio_close_directory(); // 0xF5 void sio_read_host_slots(); // 0xF4 void sio_write_host_slots(); // 0xF3 diff --git a/lib/hardware/fnWiFi.cpp b/lib/hardware/fnWiFi.cpp index c0aff65ab..9199e81cb 100755 --- a/lib/hardware/fnWiFi.cpp +++ b/lib/hardware/fnWiFi.cpp @@ -173,6 +173,115 @@ int WiFiManager::connect(const char *ssid, const char *password) return e; } +static EventGroupHandle_t wifi_event_group; + +void WiFiManager::conn_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_STA_START: + Debug_println("WIFI_EVENT_STA_START received, connecting"); + esp_wifi_connect(); + break; + case WIFI_EVENT_STA_DISCONNECTED: + Debug_println("WIFI_EVENT_STA_DISCONNECTED: settting WIFI_FAIL_BIT"); + xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT); + break; + case WIFI_EVENT_STA_CONNECTED: + Debug_printf("WIFI_EVENT_STA_CONNECTED received, ssid: %s, channel: %d\r\n", ((wifi_event_sta_connected_t*)event_data)->ssid, ((wifi_event_sta_connected_t*)event_data)->channel); + xEventGroupSetBits(wifi_event_group, WIFI_NO_IP_YET_BIT); + break; + default: + Debug_printf("Ignoring event_id: %d\r\n", event_id); + break; + } + } + + if (event_base == IP_EVENT) { + switch (event_id) { + case IP_EVENT_STA_GOT_IP: + // not sure this can happen in our scenario + Debug_println("IP_EVENT_STA_GOT_IP received, setting WIFI_CONNECTED_BIT"); + xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT); + break; + default: + Debug_printf("Ignoring event_id: %d\r\n", event_id); + break; + } + } + +} + +int WiFiManager::test_connect(const char *ssid, const char *password) +{ + stop(); + if (wifi_event_group == nullptr) + wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + if (_wifi_sta == nullptr) + { + ESP_ERROR_CHECK(esp_event_loop_create_default()); + _wifi_sta = esp_netif_create_default_wifi_ap(); + + wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + } + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, conn_event_handler, this)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, conn_event_handler, this)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_LOST_IP, conn_event_handler, this)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + + wifi_config_t wifi_config; + memset(&wifi_config, 0, sizeof(wifi_config)); + + strlcpy((char *)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid)); + strlcpy((char *)wifi_config.sta.password, password, sizeof(wifi_config.sta.password)); + + // Debug_printf("wifi_config.sta.ssid: >%s<\r\n", wifi_config.sta.ssid); + // Debug_printf("wifi_config.sta.pass: >%s<\r\n", wifi_config.sta.password); + + wifi_config.sta.pmf_cfg.capable = true; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); + esp_netif_set_hostname(_wifi_sta, Config.get_general_devicename().c_str()); + + esp_err_t result = block(); + + // clean up + ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_LOST_IP, conn_event_handler)); + ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, conn_event_handler)); + ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, conn_event_handler)); + vEventGroupDelete(wifi_event_group); + wifi_event_group = nullptr; + + return result; +} + +esp_err_t WiFiManager::block() +{ + EventBits_t bits = xEventGroupWaitBits(wifi_event_group, + WIFI_NO_IP_YET_BIT | WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + 30000 / portTICK_PERIOD_MS); + // portMAX_DELAY); + + if (bits & WIFI_CONNECTED_BIT) { + return ESP_OK; + } else if (bits & WIFI_FAIL_BIT) { + return ESP_FAIL; + } else if (bits & WIFI_NO_IP_YET_BIT) { + return ESP_OK; + } else { + return ESP_FAIL; + } +} + bool WiFiManager::connected() { return _connected; diff --git a/lib/hardware/fnWiFi.h b/lib/hardware/fnWiFi.h index 51c4e8893..c4b1a5a3f 100644 --- a/lib/hardware/fnWiFi.h +++ b/lib/hardware/fnWiFi.h @@ -11,7 +11,10 @@ #define FNWIFI_RECONNECT_RETRIES 4 #define FNWIFI_SCAN_RESULTS_MAX 20 -#define FNWIFI_BIT_CONNECTED BIT0 + +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 +#define WIFI_NO_IP_YET_BIT BIT2 // using namespace std; @@ -41,6 +44,9 @@ class WiFiManager char *_mac_to_string(char dest[18], uint8_t mac[6]); + static void conn_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); + static esp_err_t block(); + static void _wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); EventGroupHandle_t _wifi_event_group; @@ -64,6 +70,8 @@ class WiFiManager ~WiFiManager(); + int test_connect(const char *ssid, const char *password); + int connect(const char *ssid, const char *password); int connect(); From 25f8ec660cca4132b36cab816263a44b3cb2a49e Mon Sep 17 00:00:00 2001 From: jagmod Date: Wed, 13 Sep 2023 11:03:14 -0500 Subject: [PATCH 052/158] wrong defined being used, potentially causing buffer overrun --- lib/device/rs232/fuji.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/rs232/fuji.cpp b/lib/device/rs232/fuji.cpp index 605903bb2..48873df24 100755 --- a/lib/device/rs232/fuji.cpp +++ b/lib/device/rs232/fuji.cpp @@ -1097,7 +1097,7 @@ void rs232Fuji::rs232_set_host_prefix() char prefix[MAX_HOST_PREFIX_LEN]; uint8_t hostSlot = cmdFrame.aux1; - uint8_t ck = bus_to_peripheral((uint8_t *)prefix, MAX_FILENAME_LEN); + uint8_t ck = bus_to_peripheral((uint8_t *)prefix, MAX_HOST_PREFIX_LEN); Debug_printf("Fuji cmd: SET HOST PREFIX %uh \"%s\"\n", hostSlot, prefix); From 0606ee6077cdeebb7973ddd322b39f3dd1b99f45 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 15 Sep 2023 13:58:36 -0500 Subject: [PATCH 053/158] [adam][fuji] disk swap now correct orientation. --- lib/device/adamnet/fuji.cpp | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index a3c838550..79155f040 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -589,31 +589,35 @@ void adamFuji::image_rotate() // Save the device ID of the disk in the last slot int last_id = count; - for (int n = count; n > 0; n--) + for (int n = 0; n < count; n++) { - _fnDisks[n].access_mode = accessmode_save[n - 1]; - _fnDisks[n].disk_size = disksize_save[n - 1]; - _fnDisks[n].disk_type = disktype_save[n - 1]; - _fnDisks[n].fileh = fileh_save[n - 1]; - strcpy(_fnDisks[n].filename, filename_save[n - 1].c_str()); - _fnDisks[n].host = fujiHost_save[n - 1]; - _fnDisks[n].host_slot = hostslot_save[n - 1]; - _fnDisks[n].disk_dev.set_media(media_save[n-1]); + _fnDisks[n].access_mode = accessmode_save[n + 1]; + _fnDisks[n].disk_size = disksize_save[n + 1]; + _fnDisks[n].disk_type = disktype_save[n + 1]; + _fnDisks[n].fileh = fileh_save[n + 1]; + strcpy(_fnDisks[n].filename, filename_save[n + 1].c_str()); + _fnDisks[n].host = fujiHost_save[n + 1]; + _fnDisks[n].host_slot = hostslot_save[n + 1]; + _fnDisks[n].disk_dev.set_media(media_save[n + 1]); } // The first slot gets the device ID of the last slot - Debug_printf("setting slot %d to ID %hx\n", 0, last_id); - _fnDisks[0].access_mode = accessmode_save[last_id]; - _fnDisks[0].disk_size = disksize_save[last_id]; - _fnDisks[0].disk_type = disktype_save[last_id]; - _fnDisks[0].fileh = fileh_save[last_id]; - strcpy(_fnDisks[0].filename, filename_save[last_id].c_str()); - _fnDisks[0].host = fujiHost_save[last_id]; - _fnDisks[0].host_slot = hostslot_save[last_id]; - _fnDisks[0].disk_dev.set_media(media_save[last_id]); + _fnDisks[count].access_mode = accessmode_save[0]; + _fnDisks[count].disk_size = disksize_save[0]; + _fnDisks[count].disk_type = disktype_save[0]; + _fnDisks[count].fileh = fileh_save[0]; + strcpy(_fnDisks[count].filename, filename_save[0].c_str()); + _fnDisks[count].host = fujiHost_save[0]; + _fnDisks[count].host_slot = hostslot_save[0]; + _fnDisks[count].disk_dev.set_media(media_save[0]); _populate_config_from_slots(); } + + for (unsigned char n=0;n<4;n++) + { + Debug_printf("%u: %s\n",n,_fnDisks[n].filename); + } } // This gets called when we're about to shutdown/reboot From 575e2ad655f6c7718de8e181ebb8db2be5948092 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sun, 17 Sep 2023 14:08:29 -0400 Subject: [PATCH 054/158] read a command progress --- pico/mac/CMakeLists.txt | 2 ++ pico/mac/commands.c | 65 +++++++++++++++++++++++++++++++++++++-- pico/mac/dcd_commands.pio | 5 +-- pico/mac/dcd_latch.pio | 1 + pico/mac/dcd_mux.pio | 58 ++++++++++++++++++++++++++++++++++ pico/mac/dcd_read.pio | 51 ++++++++++++++++++++++++++++++ 6 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 pico/mac/dcd_mux.pio create mode 100644 pico/mac/dcd_read.pio diff --git a/pico/mac/CMakeLists.txt b/pico/mac/CMakeLists.txt index 932d5519b..607d43aca 100644 --- a/pico/mac/CMakeLists.txt +++ b/pico/mac/CMakeLists.txt @@ -33,6 +33,8 @@ pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/latch.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/mux.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_latch.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_commands.pio) +pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_mux.pio) +pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_read.pio) # however, alternatively you can choose to generate it somewhere else (in this case in the source tree for check in) #pico_generate_pio_header(pio_and ${CMAKE_CURRENT_LIST_DIR}/blink.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2a05ad49e..6b5febf4d 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -23,12 +23,15 @@ #include "dcd_latch.pio.h" #include "dcd_commands.pio.h" +#include "dcd_mux.pio.h" +#include "dcd_read.pio.h" // #include "../../include/pinmap/mac_rev0.h" #define UART_TX_PIN 4 #define UART_RX_PIN 5 #define ENABLE 7 #define MCI_CA0 8 +#define MCI_WR 14 #define ECHO_IN 21 #define TACH_OUT 21 #define ECHO_OUT 18 @@ -41,7 +44,7 @@ #define SM_DCD_LATCH 0 #define SM_DCD_CMD 1 -#define SM_DCD_WRITE 2 +#define SM_DCD_READ 2 #define SM_DCD_MUX 3 void pio_commands(PIO pio, uint sm, uint offset, uint pin); @@ -50,6 +53,9 @@ void pio_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin); void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); +void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin); +void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin); +void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin); #define UART_ID uart1 #define BAUD_RATE 2000000 //230400 //115200 @@ -65,6 +71,7 @@ const int tach_lut[5][3] = {{0, 15, 394}, {64, 79, 590}}; uint32_t a; +uint32_t b; char c; PIO pio_floppy = pio0; @@ -181,6 +188,7 @@ uint8_t dcd_assert_hshk() { dcd_clr_latch(2); dcd_clr_latch(3); + pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO return dcd_latch; } @@ -188,6 +196,7 @@ uint8_t dcd_deassert_hshk() { dcd_set_latch(2); dcd_set_latch(3); + pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO return dcd_latch; } @@ -235,6 +244,7 @@ void set_tach_freq(char c) void loop(); void dcd_loop(); + void setup() { uint offset; @@ -277,6 +287,14 @@ void setup() printf("Loaded DCD commands program at %d\n", offset); pio_dcd_commands(pio_dcd, SM_DCD_CMD, offset, MCI_CA0); + offset = pio_add_program(pio_dcd, &dcd_mux_program); + printf("Loaded DCD mux program at %d\n", offset); + pio_dcd_mux(pio_dcd, SM_DCD_MUX, offset, LATCH_OUT); + + offset = pio_add_program(pio_floppy, &dcd_read_program); + printf("Loaded DCD read program at %d\n", offset); + pio_dcd_read(pio_floppy, SM_DCD_READ, offset, MCI_WR); + #endif // FLOPPY } @@ -419,8 +437,37 @@ void loop() void dcd_loop() { - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); - printf("%c",a+'0'); + // thoughts: + // during boot sequence, need to look for STRB to deal with daisy chained DCD and floppy + // if only one HD20, then after first STRB, READ should go hi-z. + // then maybe we get a reset? the Reset should allow READ to go output when !ENABLED + if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_CMD)) + { + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + switch (a) + { + case 1: // for now receiving a command + printf("\nReceived Command Sequence: "); + while(1) + { + b = pio_sm_get_blocking(pio_floppy, SM_DCD_READ); + printf("%02x ", b); + } + case 3: // handshake + // printf("\nHandshake\n"); + pio_sm_set_enabled(pio_floppy, SM_DCD_READ, true); + dcd_assert_hshk(); + break; + case 4: + // reset + dcd_deassert_hshk(); + pio_sm_exec(pio_dcd, SM_DCD_MUX, 0xe081); // set pindirs 1 + default: + dcd_deassert_hshk(); + break; + } + printf("%c", a + '0'); + } } void pio_commands(PIO pio, uint sm, uint offset, uint pin) { @@ -456,4 +503,16 @@ void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin) { dcd_commands_program_init(pio, sm, offset, pin); pio_sm_set_enabled(pio, sm, true); +} + +void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin) +{ + dcd_mux_program_init(pio, sm, offset, pin); + pio_sm_set_enabled(pio, sm, true); +} + + +void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin) +{ + dcd_read_program_init(pio, sm, offset, pin); } \ No newline at end of file diff --git a/pico/mac/dcd_commands.pio b/pico/mac/dcd_commands.pio index adc208c2e..5d6043202 100644 --- a/pico/mac/dcd_commands.pio +++ b/pico/mac/dcd_commands.pio @@ -15,11 +15,12 @@ start: mov osr, pins ; get the phase values out x, 3 ; move 3 bits into X jmp x!=y next ; pins have changes - jmp start +.wrap next: in x, 3 ; send the phase values to fifo mov y, x ; remember the current phase state -.wrap + jmp start + % c-sdk { // this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin diff --git a/pico/mac/dcd_latch.pio b/pico/mac/dcd_latch.pio index a9b3ec98c..28e16e54b 100644 --- a/pico/mac/dcd_latch.pio +++ b/pico/mac/dcd_latch.pio @@ -6,6 +6,7 @@ ; .define ENABLE 7 +.define LSTRB 12 .program dcd_latch start: diff --git a/pico/mac/dcd_mux.pio b/pico/mac/dcd_mux.pio new file mode 100644 index 000000000..91c66cf0c --- /dev/null +++ b/pico/mac/dcd_mux.pio @@ -0,0 +1,58 @@ +; +; FujiNet Project +; +; Vintage Macintosh Microfloppy Controller Interface +; selects output pins between RMT, TACH and LATCH +; +; + +.define public LSTRB 12 +.define public ENABLE 7 + +; The DCD mux will really control the RD line direction. +; It will ... +; count the number of strobes and disable RD after 1, 2, or 3 of them +; it will reset the counter when disable goes high +; probably at some point should push the strobe counter so the FN can decide which disk image to use + +.program dcd_mux + ; initial state is RD is hi-z and we have 2 DCDs + ; we wait to be enabled then RD goes to output +start: + set pindirs, 0 +.wrap_target + set x, 0 + wait 0 gpio ENABLE + set pindirs, 1 +cont: + ; now we need to wait to be strobed or to be disabled + jmp pin start ; disabled so go back to the beginning! + mov osr, pins ; get LSTRB value into osr + out y, 1 ; stick it in Y + jmp !Y cont ; not strobing loop + wait 0 gpio LSTRB + jmp x-- cont + set pindirs, 0 + wait 1 gpio ENABLE +.wrap + +% c-sdk { +// this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin +// #define LSTRB 12 +// #define ENABLE 7 +void dcd_mux_program_init(PIO pio, uint sm, uint offset, uint set_pin) { + // configure a SM + pio_sm_config c = dcd_mux_program_get_default_config(offset); + // config side set +// sm_config_set_sideset_pins(&c, mux_pin); + sm_config_set_in_pins(&c, LSTRB); + sm_config_set_jmp_pin(&c, ENABLE); + // there are 4 wires to read for latch mux, shift to the right, no autopull + sm_config_set_set_pins(&c, set_pin, 1); + sm_config_set_out_shift(&c, true, false, 1); + pio_gpio_init(pio, set_pin); + pio_sm_set_consecutive_pindirs(pio, sm, set_pin, 1, false); + // initialize + pio_sm_init(pio, sm, offset, &c); +} +%} \ No newline at end of file diff --git a/pico/mac/dcd_read.pio b/pico/mac/dcd_read.pio new file mode 100644 index 000000000..b7931ad04 --- /dev/null +++ b/pico/mac/dcd_read.pio @@ -0,0 +1,51 @@ +; +; FujiNet Project +; +; Vintage Macintosh Microfloppy Controller Interface +; sRead NRZI stream +; +; + +.define ENABLE 7 +.define T0 10 + +.program dcd_read + wait 0 gpio ENABLE ; make sure device is enabled (maybe could remove if SM was triggered by main program) + set y, 0 ; initial state is always 0 (probably unneeded if can reset set whole SM) + wait 1 pin 0 [T0/2-1] ; wait for rising edge on write line from mac +loop: + jmp pin high ; need T0 cycles from jmp to jmp +low: + in y, 1 ; the decoded value is equal to the previous state + set y, 0 ; previous state is now zero + jmp loop [T0-4] +high: + mov y, ~Y + in y, 1 ; the deocded value is the inverse of the previous state + set y, 1 ; previous state is now one + jmp loop [T0-5] +; probably will need to have a counter and wait on edge of next byte + +% c-sdk { +// this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin +void dcd_read_program_init(PIO pio, uint sm, uint offset, uint in_pin) +{ + // configure a SM + pio_sm_config c = dcd_read_program_get_default_config(offset); + // config side set + // sm_config_set_sideset_pins(&c, mux_pin); + sm_config_set_in_pins(&c, in_pin); + sm_config_set_jmp_pin(&c, in_pin); + + // sm_config_set_out_shift(&c, true, false, 1); + sm_config_set_in_shift(&c, false, true, 8); + + pio_gpio_init(pio, in_pin); + pio_sm_set_consecutive_pindirs(pio, sm, in_pin, 1, false); + // initialize + float cycles_per_bit = 10.0; + float div = clock_get_hz(clk_sys) / (500.0e3 * cycles_per_bit); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset, &c); +} +%} \ No newline at end of file From ee5d8677f02c733aecfd93226b3c6f79cba0f91e Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sun, 17 Sep 2023 19:33:57 -0400 Subject: [PATCH 055/158] receiver decoder working --- pico/mac/commands.c | 11 +++++----- pico/mac/dcd_read.pio | 49 ++++++++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 6b5febf4d..db5153680 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -71,7 +71,7 @@ const int tach_lut[5][3] = {{0, 15, 394}, {64, 79, 590}}; uint32_t a; -uint32_t b; +uint32_t b[12]; char c; PIO pio_floppy = pio0; @@ -448,11 +448,10 @@ void dcd_loop() { case 1: // for now receiving a command printf("\nReceived Command Sequence: "); - while(1) - { - b = pio_sm_get_blocking(pio_floppy, SM_DCD_READ); - printf("%02x ", b); - } + for (int i=0; i<12; i++) + b[i] = pio_sm_get_blocking(pio_floppy, SM_DCD_READ); + for (int i=0; i<12; i++) + printf("%02x ", b[i]); case 3: // handshake // printf("\nHandshake\n"); pio_sm_set_enabled(pio_floppy, SM_DCD_READ, true); diff --git a/pico/mac/dcd_read.pio b/pico/mac/dcd_read.pio index b7931ad04..5f6180027 100644 --- a/pico/mac/dcd_read.pio +++ b/pico/mac/dcd_read.pio @@ -7,24 +7,40 @@ ; .define ENABLE 7 -.define T0 10 +.define public T0 10 .program dcd_read - wait 0 gpio ENABLE ; make sure device is enabled (maybe could remove if SM was triggered by main program) - set y, 0 ; initial state is always 0 (probably unneeded if can reset set whole SM) - wait 1 pin 0 [T0/2-1] ; wait for rising edge on write line from mac +.side_set 1 + wait 0 gpio ENABLE side 1 ; make sure device is enabled (maybe could remove if SM was triggered by main program) + set y, 0 side 0 ; initial state is always 0 (probably unneeded if can reset set whole SM) + set x, 7 side 0 +reset: + wait 1 pin 0 side 1 ; wait for rising edge on write line from mac + jmp loop1 side 1 loop: - jmp pin high ; need T0 cycles from jmp to jmp + nop side 1 [T0/2-1] +loop1: + jmp pin high side 0 ; need T0 cycles from jmp to jmp low: - in y, 1 ; the decoded value is equal to the previous state - set y, 0 ; previous state is now zero - jmp loop [T0-4] + in y, 1 side 0 [1] ; the decoded value is equal to the previous state + set y, 0 side 0 ; previous state is now zero + jmp x-- loop side 1 ; last bit? + jmp sync side 1 ; get the next bit high: - mov y, ~Y - in y, 1 ; the deocded value is the inverse of the previous state - set y, 1 ; previous state is now one - jmp loop [T0-5] + mov y, ~y side 0 + in y, 1 side 0 ; the deocded value is the inverse of the previous state + set y, 1 side 1 ; previous state is now one + jmp x-- loop side 1 ; last bit? + ; fall thru // jmp loop ; get the next bit ; probably will need to have a counter and wait on edge of next byte +sync: + set x, 7 side 1 + jmp !y reset side 0 + wait 0 pin 0 side 1 + jmp loop1 side 1 + + + % c-sdk { // this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin @@ -36,15 +52,18 @@ void dcd_read_program_init(PIO pio, uint sm, uint offset, uint in_pin) // sm_config_set_sideset_pins(&c, mux_pin); sm_config_set_in_pins(&c, in_pin); sm_config_set_jmp_pin(&c, in_pin); - + sm_config_set_sideset_pins(&c, 15); // TEMPORARY FOR DEBUGGING // sm_config_set_out_shift(&c, true, false, 1); sm_config_set_in_shift(&c, false, true, 8); pio_gpio_init(pio, in_pin); pio_sm_set_consecutive_pindirs(pio, sm, in_pin, 1, false); + pio_gpio_init(pio, 15); + pio_sm_set_consecutive_pindirs(pio, sm, 15, 1, true); // TEMPORARY FOR DEBUG OUTPUT (EXTRA) + // initialize - float cycles_per_bit = 10.0; - float div = clock_get_hz(clk_sys) / (500.0e3 * cycles_per_bit); + float cycles_per_bit = T0; + float div = clock_get_hz(clk_sys) / (500.0e3 * cycles_per_bit); // 125MHz/500kHz = 250 sm_config_set_clkdiv(&c, div); pio_sm_init(pio, sm, offset, &c); } From 5b8cb29b0bcac86f2082b06142adf831f3d6a34d Mon Sep 17 00:00:00 2001 From: jagmod Date: Mon, 18 Sep 2023 12:17:12 -0500 Subject: [PATCH 056/158] cut/paste error --- lib/device/rc2014/fuji.cpp | 128 ++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/lib/device/rc2014/fuji.cpp b/lib/device/rc2014/fuji.cpp index f55803a19..0f42030cf 100644 --- a/lib/device/rc2014/fuji.cpp +++ b/lib/device/rc2014/fuji.cpp @@ -1451,70 +1451,70 @@ void rc2014Fuji::rc2014_hash_output() { olen <<= 1; sprintf((char *)o, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - _sha256_output[0], - _sha256_output[1], - _sha256_output[2], - _sha256_output[3], - _sha256_output[4], - _sha256_output[5], - _sha256_output[6], - _sha256_output[7], - _sha256_output[8], - _sha256_output[9], - _sha256_output[10], - _sha256_output[11], - _sha256_output[12], - _sha256_output[13], - _sha256_output[14], - _sha256_output[15], - _sha256_output[16], - _sha256_output[17], - _sha256_output[18], - _sha256_output[19], - _sha256_output[20], - _sha256_output[21], - _sha256_output[22], - _sha256_output[23], - _sha256_output[24], - _sha256_output[25], - _sha256_output[26], - _sha256_output[27], - _sha256_output[28], - _sha256_output[29], - _sha256_output[30], - _sha256_output[31], - _sha256_output[32], - _sha256_output[33], - _sha256_output[34], - _sha256_output[35], - _sha256_output[36], - _sha256_output[37], - _sha256_output[38], - _sha256_output[39], - _sha256_output[40], - _sha256_output[41], - _sha256_output[42], - _sha256_output[43], - _sha256_output[44], - _sha256_output[45], - _sha256_output[46], - _sha256_output[47], - _sha256_output[48], - _sha256_output[49], - _sha256_output[50], - _sha256_output[51], - _sha256_output[52], - _sha256_output[53], - _sha256_output[54], - _sha256_output[55], - _sha256_output[56], - _sha256_output[57], - _sha256_output[58], - _sha256_output[59], - _sha256_output[60], - _sha256_output[61], - _sha256_output[62], - _sha256_output[63]); + _sha512_output[0], + _sha512_output[1], + _sha512_output[2], + _sha512_output[3], + _sha512_output[4], + _sha512_output[5], + _sha512_output[6], + _sha512_output[7], + _sha512_output[8], + _sha512_output[9], + _sha512_output[10], + _sha512_output[11], + _sha512_output[12], + _sha512_output[13], + _sha512_output[14], + _sha512_output[15], + _sha512_output[16], + _sha512_output[17], + _sha512_output[18], + _sha512_output[19], + _sha512_output[20], + _sha512_output[21], + _sha512_output[22], + _sha512_output[23], + _sha512_output[24], + _sha512_output[25], + _sha512_output[26], + _sha512_output[27], + _sha512_output[28], + _sha512_output[29], + _sha512_output[30], + _sha512_output[31], + _sha512_output[32], + _sha512_output[33], + _sha512_output[34], + _sha512_output[35], + _sha512_output[36], + _sha512_output[37], + _sha512_output[38], + _sha512_output[39], + _sha512_output[40], + _sha512_output[41], + _sha512_output[42], + _sha512_output[43], + _sha512_output[44], + _sha512_output[45], + _sha512_output[46], + _sha512_output[47], + _sha512_output[48], + _sha512_output[49], + _sha512_output[50], + _sha512_output[51], + _sha512_output[52], + _sha512_output[53], + _sha512_output[54], + _sha512_output[55], + _sha512_output[56], + _sha512_output[57], + _sha512_output[58], + _sha512_output[59], + _sha512_output[60], + _sha512_output[61], + _sha512_output[62], + _sha512_output[63]); } break; } From 9891e38845df6ed2c5d9c50a2e77ac6732f95186 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Fri, 22 Sep 2023 20:03:59 -0400 Subject: [PATCH 057/158] fast ack --- pico/mac/CMakeLists.txt | 1 + pico/mac/commands.c | 67 +++++++++++++++++++++++++++++++---------- pico/mac/dcd_read.pio | 11 ++++--- pico/mac/dcd_write.pio | 57 +++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 20 deletions(-) create mode 100644 pico/mac/dcd_write.pio diff --git a/pico/mac/CMakeLists.txt b/pico/mac/CMakeLists.txt index 607d43aca..e82d8a2f3 100644 --- a/pico/mac/CMakeLists.txt +++ b/pico/mac/CMakeLists.txt @@ -35,6 +35,7 @@ pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_latch.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_commands.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_mux.pio) pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_read.pio) +pico_generate_pio_header(commands ${CMAKE_CURRENT_LIST_DIR}/dcd_write.pio) # however, alternatively you can choose to generate it somewhere else (in this case in the source tree for check in) #pico_generate_pio_header(pio_and ${CMAKE_CURRENT_LIST_DIR}/blink.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index db5153680..cdd4a867a 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -25,6 +25,7 @@ #include "dcd_commands.pio.h" #include "dcd_mux.pio.h" #include "dcd_read.pio.h" +#include "dcd_write.pio.h" // #include "../../include/pinmap/mac_rev0.h" #define UART_TX_PIN 4 @@ -42,10 +43,12 @@ #define SM_MUX 2 #define SM_ECHO 3 -#define SM_DCD_LATCH 0 +#define SM_DCD_LATCH 3 #define SM_DCD_CMD 1 -#define SM_DCD_READ 2 -#define SM_DCD_MUX 3 +#define SM_DCD_MUX 2 +#define SM_DCD_READ 0 +#define SM_DCD_WRITE 0 + void pio_commands(PIO pio, uint sm, uint offset, uint pin); void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins); @@ -56,6 +59,7 @@ void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin); +void pio_dcd_write(PIO pio, uint sm, uint offset, uint pin); #define UART_ID uart1 #define BAUD_RATE 2000000 //230400 //115200 @@ -73,9 +77,11 @@ const int tach_lut[5][3] = {{0, 15, 394}, uint32_t a; uint32_t b[12]; char c; +uint32_t olda; PIO pio_floppy = pio0; PIO pio_dcd = pio1; +PIO pio_dcd_rw = pio0; void setup_esp_uart() { @@ -279,7 +285,7 @@ void setup() dcd_preset_latch(); offset = pio_add_program(pio_dcd, &dcd_latch_program); - printf("Loaded DCD latch program at %d\n", offset); + printf("\nLoaded DCD latch program at %d\n", offset); pio_dcd_latch(pio_dcd, SM_DCD_LATCH, offset, MCI_CA0, LATCH_OUT); pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO @@ -291,9 +297,13 @@ void setup() printf("Loaded DCD mux program at %d\n", offset); pio_dcd_mux(pio_dcd, SM_DCD_MUX, offset, LATCH_OUT); - offset = pio_add_program(pio_floppy, &dcd_read_program); + offset = pio_add_program(pio_dcd_rw, &dcd_read_program); printf("Loaded DCD read program at %d\n", offset); - pio_dcd_read(pio_floppy, SM_DCD_READ, offset, MCI_WR); + pio_dcd_read(pio_dcd_rw, SM_DCD_READ, offset, MCI_WR); + + offset = pio_add_program(pio_dcd, &dcd_write_program); + printf("Loaded DCD write program at %d\n", offset); + pio_dcd_write(pio_dcd, SM_DCD_WRITE, offset, LATCH_OUT); #endif // FLOPPY } @@ -304,7 +314,7 @@ int main() while (true) { #ifdef FLOPPY - loop(); + floppy_loop(); #elif defined(DCD) dcd_loop(); #endif @@ -313,7 +323,7 @@ int main() bool step_state = false; -void loop() +void floppy_loop() { if (!pio_sm_is_rx_fifo_empty(pio_floppy, SM_CMD)) { @@ -441,21 +451,42 @@ void dcd_loop() // during boot sequence, need to look for STRB to deal with daisy chained DCD and floppy // if only one HD20, then after first STRB, READ should go hi-z. // then maybe we get a reset? the Reset should allow READ to go output when !ENABLED + // + // need a state variable to track changes in the "command" phase settings + // + // if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_CMD)) { + olda = a; a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); switch (a) { case 1: // for now receiving a command - printf("\nReceived Command Sequence: "); - for (int i=0; i<12; i++) - b[i] = pio_sm_get_blocking(pio_floppy, SM_DCD_READ); - for (int i=0; i<12; i++) - printf("%02x ", b[i]); + printf("\nReceived Command Sequence"); + for (int i=0; i<11; i++) + b[i] = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + // for (int i=0; i<12; i++) + // printf("%02x ", b[i]); case 3: // handshake // printf("\nHandshake\n"); - pio_sm_set_enabled(pio_floppy, SM_DCD_READ, true); - dcd_assert_hshk(); + if (olda == 2) + { + pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, true); + dcd_assert_hshk(); + } + else if (olda == 1) + { + // printf("\nFast ACK!\n"); + // pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, false); + sleep_us(20); + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa); + sleep_us(20); + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); + + } break; case 4: // reset @@ -510,8 +541,12 @@ void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin) pio_sm_set_enabled(pio, sm, true); } - void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin) { dcd_read_program_init(pio, sm, offset, pin); +} + +void pio_dcd_write(PIO pio, uint sm, uint offset, uint pin) +{ + dcd_write_program_init(pio, sm, offset, pin); } \ No newline at end of file diff --git a/pico/mac/dcd_read.pio b/pico/mac/dcd_read.pio index 5f6180027..f8aae6185 100644 --- a/pico/mac/dcd_read.pio +++ b/pico/mac/dcd_read.pio @@ -18,8 +18,9 @@ reset: wait 1 pin 0 side 1 ; wait for rising edge on write line from mac jmp loop1 side 1 loop: - nop side 1 [T0/2-1] + nop side 1 [T0/2-2] loop1: + wait 0 gpio 9 side 1 ; block on CA1 jmp pin high side 0 ; need T0 cycles from jmp to jmp low: in y, 1 side 0 [1] ; the decoded value is equal to the previous state @@ -52,14 +53,16 @@ void dcd_read_program_init(PIO pio, uint sm, uint offset, uint in_pin) // sm_config_set_sideset_pins(&c, mux_pin); sm_config_set_in_pins(&c, in_pin); sm_config_set_jmp_pin(&c, in_pin); - sm_config_set_sideset_pins(&c, 15); // TEMPORARY FOR DEBUGGING + // sm_config_set_sideset_pins(&c, 15); // TEMPORARY FOR DEBUGGING // sm_config_set_out_shift(&c, true, false, 1); sm_config_set_in_shift(&c, false, true, 8); pio_gpio_init(pio, in_pin); pio_sm_set_consecutive_pindirs(pio, sm, in_pin, 1, false); - pio_gpio_init(pio, 15); - pio_sm_set_consecutive_pindirs(pio, sm, 15, 1, true); // TEMPORARY FOR DEBUG OUTPUT (EXTRA) +// pio_gpio_init(pio, 15); +// pio_sm_set_consecutive_pindirs(pio, sm, 15, 1, true); // TEMPORARY FOR DEBUG OUTPUT (EXTRA) + pio_gpio_init(pio, 9); + pio_sm_set_consecutive_pindirs(pio, sm, 9, 1, false); // for blocking on CA1 // initialize float cycles_per_bit = T0; diff --git a/pico/mac/dcd_write.pio b/pico/mac/dcd_write.pio new file mode 100644 index 000000000..13b1fccc2 --- /dev/null +++ b/pico/mac/dcd_write.pio @@ -0,0 +1,57 @@ +; +; FujiNet Project +; +; Vintage Macintosh Microfloppy Controller Interface +; outputs IWM pulse train to Mac +; +; + +; get a byte from the FIFO into the OSR (autopull?) +; when OSR is not 0, then start outputting data (or maybe always output data) +; output is 1 pulse (1 or 0) followed by 3 blanks (0s) +; pull, shift, set, shift, set .... until 0, then pull again + +; +; logic analyzer looks like 0.4 us pulses in 2.1 us periods +; floppy emulator successfuly works with 0.5 us pulses in 2.0 us periods + +; DOES NOT HAVE HOLDOFF IMPLEMENTED +; CAN SIMPLIFY WITH AUTOPULL, REMOVE WAIT ENABLE, USE WRAPPING +; IF USE SIDESET, THEN CAN ADD 15 CLK DELAY - total 16 clk max +; so would like 16 clks = 1.5 us - maybe make the clock cycle = 0.1 us, so 5=0.5 us pulse and 15 = 1.5 us blank +; but dont want to do fractional divide ... instead clk/13 = 9.6154 MHZ +; 1 tick = 0.104 us +; 4 ticks = .416 us for 1 pulse +; 16 ticks = 1.664 us for blank time +; total = 20 ticks = 2.08 us + +.program dcd_write + ; wait 0 gpio ENABLE ; make sure its us +.wrap_target + set x, 7 ; 8 bits +pulse: + out pins, 1 [3] + set pins, 0 [14] + jmp x-- pulse +.wrap ; stretch by 1 or 2 clocks? + +% c-sdk { +// this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin + +void dcd_write_program_init(PIO pio, uint sm, uint offset, uint pin) { + // configure a SM + pio_sm_config c = dcd_write_program_get_default_config(offset); + // config side set + sm_config_set_set_pins(&c, pin, 1); + sm_config_set_out_pins(&c, pin, 1); + sm_config_set_out_shift(&c, true, true, 8); + // pio_gpio_init(pio, pin); +// pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + // initialize + + //float cycles_per_bit = 20; + // float div = clock_get_hz(clk_sys) / (500.0e3 * cycles_per_bit); // 125MHz/500kHz = 250 + sm_config_set_clkdiv(&c, 13); // do 13 instead of 12.5 + pio_sm_init(pio, sm, offset, &c); +} +%} \ No newline at end of file From 44ff562e939cbdd379972afb844f37846c52ad1b Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 23 Sep 2023 16:46:01 -0400 Subject: [PATCH 058/158] status response and fixed tx bit order --- pico/mac/commands.c | 195 +++++++++++++++++++++++++++++++++----- pico/mac/dcd_commands.pio | 3 +- pico/mac/dcd_mux.pio | 2 +- pico/mac/dcd_read.pio | 1 + pico/mac/dcd_write.pio | 11 ++- 5 files changed, 182 insertions(+), 30 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index cdd4a867a..d0aed03ed 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -10,6 +10,7 @@ #define DCD #include +#include #include "pico/stdlib.h" #include "hardware/uart.h" #include "hardware/clocks.h" @@ -305,6 +306,12 @@ void setup() printf("Loaded DCD write program at %d\n", offset); pio_dcd_write(pio_dcd, SM_DCD_WRITE, offset, LATCH_OUT); + // pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); + // pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); + // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa<<24); + // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0x80<<24); + // while(1) + // ; #endif // FLOPPY } @@ -444,13 +451,27 @@ void floppy_loop() // to do: read both enable lines and indicate which drive is active when sending single char to esp32 } +struct dcd_triad { + uint8_t sync; + uint8_t num_rx; + uint8_t num_tx; +} cmd; + +bool host = false; + +// forward declarations +void dcd_process(uint8_t nrx, uint8_t ntx); void dcd_loop() { + // latest thoughts: + // this loop handshakes and receives the DCD command and fires off the command handler + // todo: make dcd_mux.pio push the DCD volume # (or floppy state) to the input FIFO. + // thoughts: - // during boot sequence, need to look for STRB to deal with daisy chained DCD and floppy + // this is done by a SM: during boot sequence, need to look for STRB to deal with daisy chained DCD and floppy // if only one HD20, then after first STRB, READ should go hi-z. - // then maybe we get a reset? the Reset should allow READ to go output when !ENABLED + // then maybe we get a reset? the Reset should allow READ to go output when ENABLED // // need a state variable to track changes in the "command" phase settings // @@ -461,45 +482,175 @@ void dcd_loop() a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); switch (a) { + case 0: + host = true; + break; case 1: // for now receiving a command - printf("\nReceived Command Sequence"); - for (int i=0; i<11; i++) - b[i] = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); - // for (int i=0; i<12; i++) - // printf("%02x ", b[i]); + host = true; + // The Macintosh's data transfer begins with three bytes which are not encoded using the 7-to-8 encoding. + // The first is an 0xAA "sync" byte. + // The second indicates the number of 7-to-8-encoded groups contained in the transfer to follow, plus 0x80 (because the MSB must be set). + // The third indicates the number of 7-to-8-encoded groups that the Macintosh expects to receive in response, plus 0x80. + // These three bytes are followed by 7-to-8-encoded groups, the number of which was indicated by the second byte. + cmd.sync = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + assert(cmd.sync == 0xaa); + cmd.num_rx = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + cmd.num_tx = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + dcd_process(cmd.num_rx & 0x7f, cmd.num_tx & 0x7f); + break; + case 2: + host = false; + // idle + // if (olda == 3) + // { + // dcd_assert_hshk(); + // } + break; case 3: // handshake + host = true; // printf("\nHandshake\n"); if (olda == 2) { - pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, true); + pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, true); // to do : init or restart and move PC to top of program + //pio_sm_restart(pio_dcd_rw, SM_DCD_READ); dcd_assert_hshk(); } - else if (olda == 1) - { - // printf("\nFast ACK!\n"); - // pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, false); - sleep_us(20); - pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); - pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa); - sleep_us(20); - pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); - pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); - - } break; case 4: + host = false; // reset dcd_deassert_hshk(); pio_sm_exec(pio_dcd, SM_DCD_MUX, 0xe081); // set pindirs 1 + break; default: - dcd_deassert_hshk(); + host = false; + dcd_deassert_hshk(); break; } printf("%c", a + '0'); } } +uint8_t payload[538]; + +void dcd_status(uint8_t ntx) +{ + /* + DCD Device: + Offset Value Sample Value from HD20 + 0 0x83 + 1 0x00 + 2-5 Status + 6-7 Device type 0x0001 + 8-9 Device manufacturer 0x0001 + 10 Device characteristics bit field (see below) 0xE6 + 11-13 Number of blocks 0x009835 + 14-15 Number of spare blocks 0x0045 + 16-17 Number of bad blocks 0x0001 + 18-69 Manufacturer reserved + 70-197 Icon (see below) + 198-325 Icon mask (see below) + 326 Device location string length + 327-341 Device location string + 342 Checksum + */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x83; + payload[7] = 1; + payload[9] = 1; + payload[10] = 0xe6; + payload[11] = 0x35; + payload[12] = 0x98; + uint8_t sum=0; + for (int i=0; i<342; i++) + sum += payload[i]; + sum = ~sum; + payload[342] = ++sum; + // send the response packet encoding along the way + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa<<24); + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, ntx | 0x80<<24); + uint8_t *p = payload; + for (int i=0; i> 1) | 0x80)<<24); + p++; + } + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, (lsb | 0x80)<<24); + } + while (!pio_sm_is_tx_fifo_empty(pio_dcd, SM_DCD_WRITE)) + ; + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); // re-aquire the READ line for the LATCH function + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); +} + + +void dcd_process(uint8_t nrx, uint8_t ntx) +{ + uint8_t *p = payload; + for (int i=0; i < nrx; i++) + { + // probably check for HOLDOFF, then handshake and wait for sync, then continue loop + uint8_t lsb = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + // printf("\nL%02x ",lsb); + for (int j=0; j < 7; j++) + { + *p = (pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ)<<1) | (lsb & 0x01); + lsb >>= 1; + p++; + } + } + pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, false); // stop the read state machine + // + // handshake + // + while (gpio_get(MCI_WR)); // WR needs to return to 0 (at least from a status command at boot) + olda=a; + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==3); + dcd_deassert_hshk(); + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==2); // now back to idle and awaiting DCD response + // is this where I fast ACK? + dcd_assert_hshk(); + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==3); // now back to idle and awaiting DCD response + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==1); // now back to idle and awaiting DCD response + + // // + // printf("\nPayload: "); + // for (uint8_t*ptr=payload; ptr Date: Sun, 24 Sep 2023 08:54:23 -0400 Subject: [PATCH 059/158] get a sector request --- pico/mac/commands.c | 21 ++++++++++++++------- pico/mac/dcd_write.pio | 4 ---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index d0aed03ed..301b94d6b 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -83,6 +83,7 @@ uint32_t olda; PIO pio_floppy = pio0; PIO pio_dcd = pio1; PIO pio_dcd_rw = pio0; +uint pio_read_offset; void setup_esp_uart() { @@ -298,9 +299,9 @@ void setup() printf("Loaded DCD mux program at %d\n", offset); pio_dcd_mux(pio_dcd, SM_DCD_MUX, offset, LATCH_OUT); - offset = pio_add_program(pio_dcd_rw, &dcd_read_program); - printf("Loaded DCD read program at %d\n", offset); - pio_dcd_read(pio_dcd_rw, SM_DCD_READ, offset, MCI_WR); + pio_read_offset = pio_add_program(pio_dcd_rw, &dcd_read_program); + printf("Loaded DCD read program at %d\n", pio_read_offset); + pio_dcd_read(pio_dcd_rw, SM_DCD_READ, pio_read_offset, MCI_WR); offset = pio_add_program(pio_dcd, &dcd_write_program); printf("Loaded DCD write program at %d\n", offset); @@ -511,8 +512,9 @@ void dcd_loop() // printf("\nHandshake\n"); if (olda == 2) { - pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, true); // to do : init or restart and move PC to top of program //pio_sm_restart(pio_dcd_rw, SM_DCD_READ); + pio_dcd_read(pio_dcd_rw, SM_DCD_READ, pio_read_offset, MCI_WR); // re-init + pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, true); dcd_assert_hshk(); } break; @@ -611,13 +613,11 @@ void dcd_process(uint8_t nrx, uint8_t ntx) // handshake // while (gpio_get(MCI_WR)); // WR needs to return to 0 (at least from a status command at boot) - olda=a; a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==3); dcd_deassert_hshk(); a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==2); // now back to idle and awaiting DCD response - // is this where I fast ACK? dcd_assert_hshk(); a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==3); // now back to idle and awaiting DCD response @@ -646,9 +646,16 @@ void dcd_process(uint8_t nrx, uint8_t ntx) break; default: + printf("\nnot implemented %02x\n",payload[0]); break; } - + + + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==3); + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==2); // now back to idle and awaiting DCD response + dcd_deassert_hshk(); } void pio_commands(PIO pio, uint sm, uint offset, uint pin) { diff --git a/pico/mac/dcd_write.pio b/pico/mac/dcd_write.pio index 800e1d69e..d4f893794 100644 --- a/pico/mac/dcd_write.pio +++ b/pico/mac/dcd_write.pio @@ -26,13 +26,9 @@ ; total = 20 ticks = 2.08 us .program dcd_write - ; wait 0 gpio ENABLE ; make sure its us .wrap_target - ;set x, 7 ; 8 bits -;pulse: out pins, 1 [3] set pins, 0 [14] - ;jmp x-- pulse .wrap % c-sdk { From dba71dacf14b32bc81a15b53522eda8530539885 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sun, 24 Sep 2023 12:23:39 -0400 Subject: [PATCH 060/158] add DCD media type --- lib/bus/mac/mac.cpp | 136 ++++++++++++++++++++------------- lib/media/mac/mediaType.cpp | 4 +- lib/media/mac/mediaType.h | 5 +- lib/media/mac/mediaTypeDCD.cpp | 117 ++++++++++++++++++++++++++++ lib/media/mac/mediaTypeDCD.h | 31 ++++++++ lib/media/mac/mediaTypeMOOF.h | 4 +- pico/mac/commands.c | 46 +++++++++++ 7 files changed, 283 insertions(+), 60 deletions(-) create mode 100644 lib/media/mac/mediaTypeDCD.cpp create mode 100644 lib/media/mac/mediaTypeDCD.h diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 0f9bb1ff2..512835e40 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -40,6 +40,15 @@ void macBus::setup(void) * EJECT 0 1 1 1 7 eject the disk */ +/** + * for DCD (HD20) the protocol is different. + * need to read and write blocks + * would be nice to fetch the image name so it can be displayed on the mac + * + * block numbers are 3 bytes, 512 bytes/block - 8GB addressable, but MAC OS limites to 2 GB + * +*/ + void macBus::service(void) { // todo - figure out two floppies - either on RP2040 or ESP32 side. Use the two enable lines - get_disks(0 or 1) @@ -47,65 +56,84 @@ void macBus::service(void) { int c=fnUartBUS.read(); if (c==0) return; - switch (c-'0') + else if (c < 'A') // floppy { - case 0: - // set direction to increase track number - Debug_printf("%c",'I'); - theFuji.get_disks(0)->disk_dev.set_dir(+1); - // fnUartBUS.write('I'); - // fnUartBUS.flush(); - break; - case 4: - // set direction to decrease track number - Debug_printf("%c",'D'); - theFuji.get_disks(0)->disk_dev.set_dir(-1); - // fnUartBUS.write('D'); - // fnUartBUS.flush(); - break; - case 1: - // step the head - Debug_printf("%c",'S'); + switch (c - '0') { - t0 = fnSystem.micros(); - track_not_copied = true; - int track_position = theFuji.get_disks(0)->disk_dev.step(); - if (track_position < 0) - { - fnUartBUS.write('N'); - } - else + case 0: + // set direction to increase track number + Debug_printf("%c", 'I'); + theFuji.get_disks(0)->disk_dev.set_dir(+1); + // fnUartBUS.write('I'); + // fnUartBUS.flush(); + break; + case 4: + // set direction to decrease track number + Debug_printf("%c", 'D'); + theFuji.get_disks(0)->disk_dev.set_dir(-1); + // fnUartBUS.write('D'); + // fnUartBUS.flush(); + break; + case 1: + // step the head + Debug_printf("%c", 'S'); { - fnUartBUS.write(track_position | 128); // send the track position(/2) back - // fnUartBUS.flush(); + t0 = fnSystem.micros(); + track_not_copied = true; + int track_position = theFuji.get_disks(0)->disk_dev.step(); + if (track_position < 0) + { + fnUartBUS.write('N'); + } + else + { + fnUartBUS.write(track_position | 128); // send the track position(/2) back + // fnUartBUS.flush(); + } } + break; + case 2: + // turn motor ons + Debug_printf("\nMotor ON"); + floppy_ll.start(0); + fnUartBUS.write('M'); + // fnUartBUS.flush(); + break; + case 6: + // turn motor off + Debug_printf("\nMotor OFF"); + floppy_ll.stop(); + fnUartBUS.write('F'); + // fnUartBUS.flush(); + break; + case 7: + // eject + Debug_printf("\neject but do nothing"); + fnUartBUS.write('E'); + // fnUartBUS.flush(); + break; + default: + Debug_printf("%03d"); + fnUartBUS.write('X'); + // fnUartBUS.flush(); + break; + } + } + else // DCD + { + switch (c) + { + case 'R': + { + char s[3]; + fnUartBUS.readBytes(s, 3); + uint32_t sector_num = ((uint32_t)s[0] << 16) + ((uint32_t)s[1] << 8) + (uint32_t)s[2]; + Debug_printf("\nDCD sector request: %d", sector_num); + } + break; + default: + break; } - break; - case 2: - // turn motor ons - Debug_printf("\nMotor ON"); - floppy_ll.start(0); - fnUartBUS.write('M'); - // fnUartBUS.flush(); - break; - case 6: - // turn motor off - Debug_printf("\nMotor OFF"); - floppy_ll.stop(); - fnUartBUS.write('F'); - // fnUartBUS.flush(); - break; - case 7: - // eject - Debug_printf("\neject but do nothing"); - fnUartBUS.write('E'); - // fnUartBUS.flush(); - break; - default: - Debug_printf("%03d"); - fnUartBUS.write('X'); - // fnUartBUS.flush(); - break; } } if (track_not_copied && stepper_timeout()) diff --git a/lib/media/mac/mediaType.cpp b/lib/media/mac/mediaType.cpp index b216a0035..dae72003b 100644 --- a/lib/media/mac/mediaType.cpp +++ b/lib/media/mac/mediaType.cpp @@ -38,8 +38,8 @@ mediatype_t MediaType::discover_mediatype(const char *filename) { // Check the last 3 characters of the string const char *ext = filename + l - 3; - // if (strcasecmp(ext, "HDV") == 0) - // return MEDIATYPE_PO; + if (strcasecmp(ext, "HDV") == 0) + return MEDIATYPE_DCD; // else if (strcasecmp(ext,"2MG") == 0) // return MEDIATYPE_PO; // else if (strcasecmp(ext, "WOZ") == 0) diff --git a/lib/media/mac/mediaType.h b/lib/media/mac/mediaType.h index 4a80cdbb7..07a6b544e 100644 --- a/lib/media/mac/mediaType.h +++ b/lib/media/mac/mediaType.h @@ -17,6 +17,7 @@ enum mediatype_t { MEDIATYPE_UNKNOWN = 0, MEDIATYPE_MOOF, + MEDIATYPE_DCD, MEDIATYPE_COUNT }; @@ -65,9 +66,9 @@ class MediaType virtual bool format(uint16_t *respopnsesize); // Returns TRUE if an error condition occurred - virtual bool read(uint32_t blockNum, uint16_t *count, uint8_t *buffer) = 0; + virtual bool read(uint32_t blockNum, uint8_t *buffer) = 0; // Returns TRUE if an error condition occurred - virtual bool write(uint32_t blockNum, uint16_t *count, uint8_t *buffer) = 0; + virtual bool write(uint32_t blockNum, uint8_t *buffer) = 0; // virtual uint16_t sector_size(uint16_t sectornum); diff --git a/lib/media/mac/mediaTypeDCD.cpp b/lib/media/mac/mediaTypeDCD.cpp new file mode 100644 index 000000000..e977cf989 --- /dev/null +++ b/lib/media/mac/mediaTypeDCD.cpp @@ -0,0 +1,117 @@ +#ifdef BUILD_MAC + +#include "mediaTypeDCD.h" + +#include +#include "utils.h" +#include "../../include/debug.h" + +bool MediaTypeDCD::read(uint32_t blockNum, uint8_t* buffer) +{ + size_t readsize = _media_sector_size; +if (blockNum == 0 || blockNum != last_block_num + 1) // example optimization, only do seek if not reading next block -tschak + { + if (fseek(_media_fileh, (blockNum * readsize) + offset, SEEK_SET)) + { + reset_seek_opto(); + return true; + } + } + +// if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) +// last_block_num = INVALID_SECTOR_VALUE; // try to invalidate cache if game re-reads hs table +// else + last_block_num = blockNum; + + readsize = fread((unsigned char *)buffer, 1, readsize, _media_fileh); // Reading block from SD Card + return (readsize != _media_sector_size); +} + +bool MediaTypeDCD::write(uint32_t blockNum, uint8_t* buffer) +{ + size_t writesize = _media_sector_size; + + // if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) + // { + // Debug_printf("high score: Swapping file handles\r\n"); + // oldFileh = _media_fileh; + // hsFileh = _media_host->file_open(_disk_filename, _disk_filename, strlen(_disk_filename) +1, "r+"); + // _media_fileh = hsFileh; + // } + + if (blockNum != last_block_num + 1) // example optimization, only do seek if not writing next block -tschak + { + if (fseek(_media_fileh, (blockNum * writesize) + offset, SEEK_SET)) + { + reset_seek_opto(); + return true; + } + } + last_block_num = blockNum; + writesize = fwrite((unsigned char *)buffer, 1, writesize, _media_fileh); + if (writesize != _media_sector_size) + { + reset_seek_opto(); + return true; + } + + // if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) + // { + // Debug_printf("high score: Reverting file handles.\r\n"); + // if (hsFileh != nullptr) + // fclose(hsFileh); + + // _media_fileh = oldFileh; + // last_block_num = INVALID_SECTOR_VALUE; // Invalidate cache + // } + + return false; +} + +bool MediaTypeDCD::format(uint16_t *responsesize) +{ + return false; +} + +mediatype_t MediaTypeDCD::mount(FILE *f, uint32_t disksize) +{ + // diskiiemulation = false; + // char hdr[64]; + // fread(&hdr,sizeof(char),64,f); + // if (hdr[0] == '2' && hdr[1] == 'I' && hdr[2] == 'M' && hdr[3] == 'G') + // { + // // check for 'high score enabled' + // // expected format at offset 0x48 of 2mg hdr: H,I,,,, + // // where blk is block range containing high score table, lb = lower bound, ub = upper bound + // // if upper bound is undefined (0x0000), then lower bound defines range + // if (hdr[48] == 'H' && hdr[49] == 'I') + // { + // // read range of blocks from the 2mg header that qualify to be written (little endian) + // _high_score_block_lb = UINT16_FROM_HILOBYTES(hdr[51], hdr[50]); + // _high_score_block_ub = UINT16_FROM_HILOBYTES(hdr[53], hdr[52]); + // if (_high_score_block_lb > 0) + // { + // if (_high_score_block_ub == 0) + // _high_score_block_ub = _high_score_block_lb; + + // high_score_enabled = true; + // Debug_printf("\r\nhigh score: block range: %04x..%04x\r\n", _high_score_block_lb, _high_score_block_ub); + // } + // } + // offset = 64; + // } + offset = 0; + _media_fileh = f; + disksize -= offset; + _media_sector_size = 512; + num_blocks = disksize / _media_sector_size; + return MEDIATYPE_DCD; +} + + +// static bool create(FILE *f, uint32_t numBlock) +// { +// return false; +// } + +#endif // BUILD_APPLE diff --git a/lib/media/mac/mediaTypeDCD.h b/lib/media/mac/mediaTypeDCD.h new file mode 100644 index 000000000..f2c765a5f --- /dev/null +++ b/lib/media/mac/mediaTypeDCD.h @@ -0,0 +1,31 @@ +#ifndef _MEDIATYPE_DCD_ +#define _MEDIATYPE_DCD_ + +#include + +#include "mediaType.h" + +class MediaTypeDCD : public MediaType +{ +private: + uint32_t last_block_num = 0xFFFFFFFF; + uint32_t offset = 0; +public: + virtual bool read(uint32_t blockNum, uint8_t* buffer) override; + virtual bool write(uint32_t blockNum, uint8_t* buffer) override; + + virtual bool format(uint16_t *responsesize) override; + + virtual mediatype_t mount(FILE *f, uint32_t disksize) override; + + virtual bool status() override {return (_media_fileh != nullptr);} + + // static bool create(FILE *f, uint32_t numBlock); + + size_t size() {return _media_num_sectors;} + size_t sectorsize() {return _media_sector_size;} + void reset_seek_opto() {last_block_num = 0xFFFFFFFF;}; +}; + + +#endif // _MEDIATYPE_DCD_ diff --git a/lib/media/mac/mediaTypeMOOF.h b/lib/media/mac/mediaTypeMOOF.h index d8e976d60..abb36e817 100644 --- a/lib/media/mac/mediaTypeMOOF.h +++ b/lib/media/mac/mediaTypeMOOF.h @@ -42,8 +42,8 @@ class MediaTypeMOOF : public MediaType public: MediaTypeMOOF() {}; - virtual bool read(uint32_t blockNum, uint16_t *count, uint8_t *buffer) override { return false; }; - virtual bool write(uint32_t blockNum, uint16_t *count, uint8_t *buffer) override { return false; }; + virtual bool read(uint32_t blockNum, uint8_t *buffer) override { return false; }; + virtual bool write(uint32_t blockNum, uint8_t *buffer) override { return false; }; virtual bool format(uint16_t *respopnsesize) override { return false; }; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 301b94d6b..8b2c325ba 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -535,6 +535,48 @@ void dcd_loop() uint8_t payload[538]; +void dcd_read(uint8_t ntx) +{ + /*Macintosh: + + Offset Value + 0 0x00 + 1 Number of sectors to read + 2-4 Sector offset (big-endian) + 5 0x00 + 6 Checksum + DCD Device: + + Offset Value + 0 0x80 + 1 Number of sectors remaining to be read (including sector contained in this response) + 2-5 Status + 6-25 Tags of sector being read (20 bytes) + 26-537 Data of sector being read (512 bytes) + 538 Checksum + + The DCD device then repeats this response for each sector the Macintosh has requested + to be read with the value at offset 1 in the response counting down, beginning at the + value at offset 1 in the command and ending at 0x01. + */ + +// printf("\nRead Command: "); +// for (int i=0; i<7; i++) +// printf("%02x ",payload[i]); +// while(1); + + uint8_t num_sectors = payload[1]; + // uint32_t sector_offset = ((uint32_t)payload[2] << 16) + ((uint32_t)payload[3] << 8) + (uint32_t)payload[4]; + uart_putc_raw(UART_ID,'R'); + uart_putc_raw(UART_ID, payload[2]); + uart_putc_raw(UART_ID, payload[3]); + uart_putc_raw(UART_ID, payload[4]); + + memset(payload, 0, sizeof(payload)); + payload[0]=0x80; + payload[1]=num_sectors; +} + void dcd_status(uint8_t ntx) { /* @@ -634,6 +676,10 @@ void dcd_process(uint8_t nrx, uint8_t ntx) switch (payload[0]) { + case 0x00: + // read sectors + dcd_read(ntx); + break; case 0x03: // status // during boot sequence: From 73e4051511ec8e8be76783f9f7e987eec1f281e0 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sun, 24 Sep 2023 22:32:52 -0400 Subject: [PATCH 061/158] DCD esp work, trying commanding on pico --- lib/bus/mac/mac.cpp | 9 +-- lib/device/mac/floppy.cpp | 27 +++++++++ lib/device/mac/floppy.h | 2 +- lib/device/mac/fuji.h | 5 +- lib/media/mac/mediaType.cpp | 4 +- lib/media/mac/mediaTypeDCD.h | 3 +- lib/media/mac/mediaTypeMOOF.h | 4 +- lib/media/media.h | 1 + pico/mac/commands.c | 106 +++++++++++++++++++++------------- pico/mac/dcd_mux.pio | 2 +- 10 files changed, 108 insertions(+), 55 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 512835e40..ae1314217 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -49,6 +49,8 @@ void macBus::setup(void) * */ +uint8_t sector_buffer[512]; + void macBus::service(void) { // todo - figure out two floppies - either on RP2040 or ESP32 side. Use the two enable lines - get_disks(0 or 1) @@ -124,12 +126,7 @@ void macBus::service(void) switch (c) { case 'R': - { - char s[3]; - fnUartBUS.readBytes(s, 3); - uint32_t sector_num = ((uint32_t)s[0] << 16) + ((uint32_t)s[1] << 8) + (uint32_t)s[2]; - Debug_printf("\nDCD sector request: %d", sector_num); - } + theFuji.get_disks(0)->disk_dev.process('R'); break; default: break; diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 589ce10e1..934fdf616 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -48,6 +48,12 @@ mediatype_t macFloppy::mount(FILE *f, const char *filename, mediatype_t disk_typ break; } break; + case MEDIATYPE_DCD: + Debug_printf("\nMounting Media Type HDV for DCD"); + device_active = true; + _disk = new MediaTypeDCD(); + mt = ((MediaTypeDCD *)_disk)->mount(f); + break; // case MEDIATYPE_DSK: // Debug_printf("\nMounting Media Type DSK"); // device_active = true; @@ -188,6 +194,27 @@ void IRAM_ATTR macFloppy::change_track(int side) } +void macFloppy::process(mac_cmd_t cmd) +{ + uint32_t sector_num; + uint8_t buffer[512]; + + switch (cmd) + { + case 'R': + char s[3]; + fnUartBUS.readBytes(s, 3); + sector_num = ((uint32_t)s[0] << 16) + ((uint32_t)s[1] << 8) + (uint32_t)s[2]; + // Debug_printf("\nDCD sector request: %d", sector_num); + if (_disk->read(sector_num, buffer)) + Debug_printf("\nError Reading Sector %d",sector_num); + fnUartBUS.write(buffer, sizeof(buffer)); + break; + default: + break; + } +} + #endif // BUILD_MAC #if 0 diff --git a/lib/device/mac/floppy.h b/lib/device/mac/floppy.h index 83e63ce1a..92ab59ee9 100644 --- a/lib/device/mac/floppy.h +++ b/lib/device/mac/floppy.h @@ -68,7 +68,7 @@ class macFloppy : public macDevice mediatype_t disktype() { return _disk == nullptr ? MEDIATYPE_UNKNOWN : _disk->_mediatype; }; void shutdown() override {}; - void process(mac_cmd_t cmd) override {}; + void process(mac_cmd_t cmd) override; }; #endif // guard diff --git a/lib/device/mac/fuji.h b/lib/device/mac/fuji.h index 859807a8c..14176aea5 100644 --- a/lib/device/mac/fuji.h +++ b/lib/device/mac/fuji.h @@ -18,8 +18,8 @@ #include "../fuji/fujiCmd.h" #define MAX_HOSTS 8 -#define MAX_DISK_DEVICES 6 // 4 SP devices + 2 DiskII devices -#define MAX_DISK2_DEVICES 2 // for now until we add 3.5" disks +#define MAX_DISK_DEVICES 5 // 4 DCD devices + 1 floppy devices +#define MAX_FLOPPY_DEVICES 1 #define MAX_NETWORK_DEVICES 4 #define MAX_SSID_LEN 32 @@ -197,7 +197,6 @@ class macFuji : public macDevice fujiHost *get_hosts(int i) { return &_fnHosts[i]; } fujiDisk *get_disks(int i) { return &_fnDisks[i]; } - // iwmDisk2 _fnDisk2s[MAX_DISK2_DEVICES]; void _populate_slots_from_config(); void _populate_config_from_slots(); diff --git a/lib/media/mac/mediaType.cpp b/lib/media/mac/mediaType.cpp index dae72003b..6d81687c1 100644 --- a/lib/media/mac/mediaType.cpp +++ b/lib/media/mac/mediaType.cpp @@ -38,8 +38,8 @@ mediatype_t MediaType::discover_mediatype(const char *filename) { // Check the last 3 characters of the string const char *ext = filename + l - 3; - if (strcasecmp(ext, "HDV") == 0) - return MEDIATYPE_DCD; + if (strcasecmp(ext, "DSK") == 0) + return MEDIATYPE_DCD; // todo: check size, if 400 or 800k, then floppy, otherwise DCD // else if (strcasecmp(ext,"2MG") == 0) // return MEDIATYPE_PO; // else if (strcasecmp(ext, "WOZ") == 0) diff --git a/lib/media/mac/mediaTypeDCD.h b/lib/media/mac/mediaTypeDCD.h index f2c765a5f..65eb0da4c 100644 --- a/lib/media/mac/mediaTypeDCD.h +++ b/lib/media/mac/mediaTypeDCD.h @@ -17,7 +17,8 @@ class MediaTypeDCD : public MediaType virtual bool format(uint16_t *responsesize) override; virtual mediatype_t mount(FILE *f, uint32_t disksize) override; - + mediatype_t mount(FILE *f) { return mount(f, 0); }; + virtual bool status() override {return (_media_fileh != nullptr);} // static bool create(FILE *f, uint32_t numBlock); diff --git a/lib/media/mac/mediaTypeMOOF.h b/lib/media/mac/mediaTypeMOOF.h index abb36e817..71062ccda 100644 --- a/lib/media/mac/mediaTypeMOOF.h +++ b/lib/media/mac/mediaTypeMOOF.h @@ -42,8 +42,8 @@ class MediaTypeMOOF : public MediaType public: MediaTypeMOOF() {}; - virtual bool read(uint32_t blockNum, uint8_t *buffer) override { return false; }; - virtual bool write(uint32_t blockNum, uint8_t *buffer) override { return false; }; + virtual bool read(uint32_t blockNum, uint8_t *buffer) override { return true; }; + virtual bool write(uint32_t blockNum, uint8_t *buffer) override { return true; }; virtual bool format(uint16_t *respopnsesize) override { return false; }; diff --git a/lib/media/media.h b/lib/media/media.h index 5dce9fe76..c38252e15 100644 --- a/lib/media/media.h +++ b/lib/media/media.h @@ -39,6 +39,7 @@ #ifdef BUILD_MAC #include "mac/mediaType.h" #include "mac/mediaTypeMOOF.h" +#include "mac/mediaTypeDCD.h" #endif #ifdef BUILD_S100 diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 8b2c325ba..83c0c6652 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -84,6 +84,7 @@ PIO pio_floppy = pio0; PIO pio_dcd = pio1; PIO pio_dcd_rw = pio0; uint pio_read_offset; +uint pio_write_offset; void setup_esp_uart() { @@ -303,9 +304,9 @@ void setup() printf("Loaded DCD read program at %d\n", pio_read_offset); pio_dcd_read(pio_dcd_rw, SM_DCD_READ, pio_read_offset, MCI_WR); - offset = pio_add_program(pio_dcd, &dcd_write_program); - printf("Loaded DCD write program at %d\n", offset); - pio_dcd_write(pio_dcd, SM_DCD_WRITE, offset, LATCH_OUT); + pio_write_offset = pio_add_program(pio_dcd, &dcd_write_program); + printf("Loaded DCD write program at %d\n", pio_write_offset); + pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); // pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); // pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); @@ -533,7 +534,44 @@ void dcd_loop() } } -uint8_t payload[538]; +uint8_t payload[539]; + +void send_packet(uint8_t ntx) +{ + // send the response packet encoding along the way + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); + // pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa << 24); + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, (ntx | 0x80) << 24); + uint8_t *p = payload; + for (int i=0; i> 1) | 0x80)<<24); + p++; + } + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, (lsb | 0x80)<<24); + } + // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0x80 << 24); + while (!pio_sm_is_tx_fifo_empty(pio_dcd, SM_DCD_WRITE)) + ; + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); // re-aquire the READ line for the LATCH function + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); +} + +void compute_checksum(int a) +{ + uint8_t sum = 0; + for (int i = 0; i < a; i++) + sum += payload[i]; + sum = ~sum; + payload[a] = ++sum; +} void dcd_read(uint8_t ntx) { @@ -575,6 +613,11 @@ void dcd_read(uint8_t ntx) memset(payload, 0, sizeof(payload)); payload[0]=0x80; payload[1]=num_sectors; + printf("\n sending back %d groups\n",ntx); + uart_read_blocking(UART_ID,&payload[26],512); + compute_checksum(538); + send_packet(ntx); + // send_packet(539/7); } void dcd_status(uint8_t ntx) @@ -605,47 +648,26 @@ void dcd_status(uint8_t ntx) payload[10] = 0xe6; payload[11] = 0x35; payload[12] = 0x98; - uint8_t sum=0; - for (int i=0; i<342; i++) - sum += payload[i]; - sum = ~sum; - payload[342] = ++sum; - // send the response packet encoding along the way - pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); - pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa<<24); - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, ntx | 0x80<<24); - uint8_t *p = payload; - for (int i=0; i> 1) | 0x80)<<24); - p++; - } - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, (lsb | 0x80)<<24); - } - while (!pio_sm_is_tx_fifo_empty(pio_dcd, SM_DCD_WRITE)) - ; - pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); // re-aquire the READ line for the LATCH function - pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); + // memset(&payload[70],0xaa,128); + compute_checksum(342); + send_packet(ntx); } void dcd_process(uint8_t nrx, uint8_t ntx) { + printf("\n\n%d rx, %d tx",nrx,ntx); uint8_t *p = payload; for (int i=0; i < nrx; i++) { // probably check for HOLDOFF, then handshake and wait for sync, then continue loop uint8_t lsb = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); - // printf("\nL%02x ",lsb); + printf("\nL%02x ",lsb); for (int j=0; j < 7; j++) { - *p = (pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ)<<1) | (lsb & 0x01); + uint8_t b = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + printf("%02x ", b); + *p = (b<<1) | (lsb & 0x01); lsb >>= 1; p++; } @@ -667,17 +689,23 @@ void dcd_process(uint8_t nrx, uint8_t ntx) assert(a==1); // now back to idle and awaiting DCD response // // - // printf("\nPayload: "); - // for (uint8_t*ptr=payload; ptr Date: Mon, 25 Sep 2023 20:14:10 -0400 Subject: [PATCH 062/158] trying to make it work --- pico/mac/commands.c | 105 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 83c0c6652..61f544bb5 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -536,27 +536,33 @@ void dcd_loop() uint8_t payload[539]; +inline static void send_byte(uint8_t c) +{ + pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, c << 24); +} + void send_packet(uint8_t ntx) { // send the response packet encoding along the way pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); // pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa << 24); - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, (ntx | 0x80) << 24); + send_byte(0xaa); + send_byte(ntx | 0x80); uint8_t *p = payload; for (int i=0; i> 1) | 0x80)<<24); + // lsb <<= 1; + lsb |= ((*p) & 0x01) << j; + send_byte(((*p) >> 1) | 0x80); p++; } - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, (lsb | 0x80)<<24); + send_byte(lsb | 0x80); } + send_byte(0x80); // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0x80 << 24); while (!pio_sm_is_tx_fifo_empty(pio_dcd, SM_DCD_WRITE)) ; @@ -564,6 +570,69 @@ void send_packet(uint8_t ntx) pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); } +void simulate_packet(uint8_t ntx) +{ + uint8_t encoded[538]; + encoded[0] = 0xaa; + encoded[1] = ntx | 0x80; + uint8_t *p = payload; + int k=2; + for (int i=0; i> 1) | 0x80); + p++; + k++; + } + encoded[k++]=(lsb | 0x80); + } + + printf("\n"); + + for (int i=0; i> 1) | 0x80); + p++; + k++; + } + encoded[k_lsb]=(lsb | 0x80); + } + + printf("\n"); + + for (int i=0; i Date: Sat, 30 Sep 2023 16:04:15 -0400 Subject: [PATCH 063/158] pushing so its synced - still fighting status --- pico/mac/commands.c | 166 +++++++++++++++++++++++++++++++---------- pico/mac/dcd_write.pio | 4 +- 2 files changed, 128 insertions(+), 42 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 61f544bb5..86f477d4c 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -545,7 +545,7 @@ void send_packet(uint8_t ntx) { // send the response packet encoding along the way pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); - // pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); + pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); send_byte(0xaa); send_byte(ntx | 0x80); @@ -560,12 +560,15 @@ void send_packet(uint8_t ntx) send_byte(((*p) >> 1) | 0x80); p++; } - send_byte(lsb | 0x80); + send_byte(lsb | 0x80); } - send_byte(0x80); + // printf("\nsent %d\n",ct); + // send_byte(0x80); // send_byte(0x80); + send_byte(0x00); // dummy data for a pause to allow the last byte to send // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0x80 << 24); while (!pio_sm_is_tx_fifo_empty(pio_dcd, SM_DCD_WRITE)) ; + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); // re-aquire the READ line for the LATCH function pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); } @@ -639,7 +642,8 @@ void compute_checksum(int a) for (int i = 0; i < a; i++) sum += payload[i]; sum = ~sum; - payload[a] = ++sum; + sum++; + payload[a] = (uint8_t)(0xff & sum); } void dcd_read(uint8_t ntx) @@ -691,60 +695,135 @@ void dcd_read(uint8_t ntx) void dcd_status(uint8_t ntx) { + const uint8_t s[] = {0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xe6, 0x00, 0x98, 0x35, 0x00, + 0x45, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x88, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x7f, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + /* DCD Device: Offset Value Sample Value from HD20 - 0 0x83 - 1 0x00 - 2-5 Status + 0 0x83 + 1 0x00 + 2-5 Status 6-7 Device type 0x0001 8-9 Device manufacturer 0x0001 10 Device characteristics bit field (see below) 0xE6 11-13 Number of blocks 0x009835 14-15 Number of spare blocks 0x0045 16-17 Number of bad blocks 0x0001 - 18-69 Manufacturer reserved - 70-197 Icon (see below) - 198-325 Icon mask (see below) - 326 Device location string length - 327-341 Device location string - 342 Checksum + 18-69 Manufacturer reserved + 70-197 Icon (see below) + 198-325 Icon mask (see below) + 326 Device location string length + 327-341 Device location string + 342 Checksum + + The device characteristics bit field is defined as follows: + Value Meaning + 0x80 Mountable + 0x40 Readable + 0x20 Writable + 0x10 Ejectable (see below) + 0x08 Write protected + 0x04 Icon included + 0x02 Disk in place (see below) + + */ + printf(" status "); + // memset(payload, 0, sizeof(payload)); + // payload[0] = 0x83; + // payload[7] = 1; + // payload[9] = 1; + // payload[10] = 0xe6; //8 | 0x40 | 0x80; // 0xe6; + // payload[12] = 0xA0; + // //memset(&payload[70],0xaa,128); + // // payload[326] = 7; + // // payload[327] = 'F'; + // // payload[328] = 'u'; + // // payload[329] = 'j'; + // // payload[330] = 'i'; + // // payload[331] = 'n'; + // // payload[332] = 'e'; + // // payload[333] = 't'; + // compute_checksum(342); + memcpy(payload,s,sizeof(s)); + send_packet(ntx); + // simulate_packet(ntx); + // assert(false); +} + +void dcd_unknown(uint8_t ntx) +{ + /* + DCD Device: + Offset Value Sample Value from HD20 + 0 0x83 + 1 0x00 + 2-5 Status + 6 checksum + */ + printf(" sending0x22 "); + memset(payload, 0, sizeof(payload)); + payload[0] = 0x80 | 0x22; + compute_checksum(6); + assert(ntx==1); + send_packet(ntx); + // simulate_packet(ntx); + // assert(false); +} + +void dcd_format(uint8_t ntx) +{ + /* + DCD Device: + Offset Value Sample Value from HD20 + 0 0x83 + 1 0x00 + 2-5 Status + 6 checksum */ memset(payload, 0, sizeof(payload)); - payload[0] = 0x83; - payload[7] = 1; - payload[9] = 1; - payload[10] = 0xe6; - payload[11] = 0xA0; - payload[12] = 0x00; - memset(&payload[70],0xaa,128); - payload[326] = 7; - payload[327] = 'F'; - payload[328] = 'u'; - payload[329] = 'j'; - payload[330] = 'i'; - payload[331] = 'n'; - payload[332] = 'e'; - payload[333] = 't'; - compute_checksum(342); + payload[0] = 0x80 + 0x19; + compute_checksum(6); + assert(ntx==1); send_packet(ntx); // simulate_packet(ntx); // assert(false); } + void dcd_process(uint8_t nrx, uint8_t ntx) { - printf("\n\nEncoded data: aa %02x %02x ",nrx | 0x80, ntx | 0x80); + // printf("\n\nEncoded data: aa %02x %02x ",nrx | 0x80, ntx | 0x80); uint8_t *p = payload; for (int i=0; i < nrx; i++) { // probably check for HOLDOFF, then handshake and wait for sync, then continue loop uint8_t lsb = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); - printf("%02x ",lsb); + // printf("%02x ",lsb); for (int j=0; j < 7; j++) { uint8_t b = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); - printf("%02x ", b); + // printf("%02x ", b); *p = (b<<1) | (lsb & 0x01); lsb >>= 1; p++; @@ -757,22 +836,24 @@ void dcd_process(uint8_t nrx, uint8_t ntx) while (gpio_get(MCI_WR)); // WR needs to return to 0 (at least from a status command at boot) a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==3); + //busy_wait_us_32(10); dcd_deassert_hshk(); a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==2); // now back to idle and awaiting DCD response + // busy_wait_us_32(10); dcd_assert_hshk(); a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==3); // now back to idle and awaiting DCD response a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==1); // now back to idle and awaiting DCD response - // // - printf("\nPayload: "); - for (uint8_t*ptr=payload; ptr Date: Sat, 30 Sep 2023 16:11:58 -0400 Subject: [PATCH 064/158] dont send number of groups back --- pico/mac/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 86f477d4c..092583899 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -548,7 +548,7 @@ void send_packet(uint8_t ntx) pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); send_byte(0xaa); - send_byte(ntx | 0x80); + // send_byte(ntx | 0x80); - NOT SENT - OOPS uint8_t *p = payload; for (int i=0; i Date: Sun, 1 Oct 2023 16:09:14 -0500 Subject: [PATCH 065/158] [adam][network] fix receive. --- lib/device/adamnet/network.cpp | 38 +++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index a79bc5fa2..ae1ae6270 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -759,15 +759,7 @@ void adamNetwork::adamnet_control_clr() void adamNetwork::adamnet_control_receive_channel() { - switch (channelMode) - { - case JSON: - adamnet_control_receive_channel_json(); - break; - case PROTOCOL: - adamnet_control_receive_channel_protocol(); - break; - } + } void adamNetwork::adamnet_control_receive_channel_json() @@ -798,20 +790,19 @@ void adamNetwork::adamnet_control_receive_channel_protocol() { NetworkStatus ns; + AdamNet.start_time = esp_timer_get_time(); + if ((protocol == nullptr) || (receiveBuffer == nullptr)) + { + // adamnet_response_nack(); return; // Punch out. + } // Get status protocol->status(&ns); - if (ns.rxBytesWaiting > 0) - Debug_printf("!!! rxBytesWaiting: %d\n", ns.rxBytesWaiting); - if (ns.rxBytesWaiting > 0) - adamnet_response_ack(); - else - { - adamnet_response_nack(); + + if (!ns.rxBytesWaiting) return; - } // Truncate bytes waiting to response size ns.rxBytesWaiting = (ns.rxBytesWaiting > 1024) ? 1024 : ns.rxBytesWaiting; @@ -842,13 +833,18 @@ void adamNetwork::adamnet_control_receive() adamnet_response_ack(); return; } + else if ((response_len == 0) && (channelMode == PROTOCOL)) // this is hacky as hell + { + adamnet_response_nack(); + } - switch (receiveMode) + switch (channelMode) { - case CHANNEL: - adamnet_control_receive_channel(); + case JSON: + adamnet_control_receive_channel_json(); break; - case STATUS: + case PROTOCOL: + adamnet_control_receive_channel_protocol(); break; } } From d335f23cfdbccda372de7178ba4e0465dc822265 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Wed, 4 Oct 2023 13:28:03 -0400 Subject: [PATCH 066/158] DCD boots --- lib/device/mac/floppy.cpp | 4 +- lib/media/mac/mediaType.h | 2 +- lib/media/mac/mediaTypeDCD.cpp | 4 +- pico/mac/commands.c | 222 ++++++++++++++++++++++++++------- 4 files changed, 185 insertions(+), 47 deletions(-) diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 934fdf616..68ec3112c 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -205,9 +205,9 @@ void macFloppy::process(mac_cmd_t cmd) char s[3]; fnUartBUS.readBytes(s, 3); sector_num = ((uint32_t)s[0] << 16) + ((uint32_t)s[1] << 8) + (uint32_t)s[2]; - // Debug_printf("\nDCD sector request: %d", sector_num); + Debug_printf("\nDCD sector request: %06x", sector_num); if (_disk->read(sector_num, buffer)) - Debug_printf("\nError Reading Sector %d",sector_num); + Debug_printf("\nError Reading Sector %06x",sector_num); fnUartBUS.write(buffer, sizeof(buffer)); break; default: diff --git a/lib/media/mac/mediaType.h b/lib/media/mac/mediaType.h index 07a6b544e..357466f6f 100644 --- a/lib/media/mac/mediaType.h +++ b/lib/media/mac/mediaType.h @@ -27,7 +27,7 @@ class MediaType FILE *_media_fileh = nullptr; uint32_t _media_image_size = 0; uint32_t _media_num_sectors = 0; - uint16_t _media_sector_size = DISK_BYTES_PER_SECTOR_SINGLE; + uint16_t _media_sector_size = 512; //DISK_BYTES_PER_SECTOR_SINGLE; int32_t _media_last_sector = INVALID_SECTOR_VALUE; uint8_t _media_controller_status = DISK_CTRL_STATUS_CLEAR; diff --git a/lib/media/mac/mediaTypeDCD.cpp b/lib/media/mac/mediaTypeDCD.cpp index e977cf989..82b38c019 100644 --- a/lib/media/mac/mediaTypeDCD.cpp +++ b/lib/media/mac/mediaTypeDCD.cpp @@ -8,8 +8,8 @@ bool MediaTypeDCD::read(uint32_t blockNum, uint8_t* buffer) { - size_t readsize = _media_sector_size; -if (blockNum == 0 || blockNum != last_block_num + 1) // example optimization, only do seek if not reading next block -tschak + size_t readsize = 512;//_media_sector_size; +if ((blockNum == 0) || (blockNum != last_block_num + 1)) // example optimization, only do seek if not reading next block -tschak { if (fseek(_media_fileh, (blockNum * readsize) + offset, SEEK_SET)) { diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 092583899..577b0da5e 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -541,6 +541,24 @@ inline static void send_byte(uint8_t c) pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, c << 24); } +void handshake_before_send() +{ + dcd_assert_hshk(); + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==3); // now back to idle and awaiting DCD response + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==1); // now back to idle and awaiting DCD response +} + +void handshake_after_send() +{ + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==3); + a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + assert(a==2); // now back to idle and awaiting DCD response +} + + void send_packet(uint8_t ntx) { // send the response packet encoding along the way @@ -563,21 +581,24 @@ void send_packet(uint8_t ntx) send_byte(lsb | 0x80); } // printf("\nsent %d\n",ct); - // send_byte(0x80); // send_byte(0x80); + // send_byte(0xff); // send_byte(0x80); send_byte(0x00); // dummy data for a pause to allow the last byte to send - // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0x80 << 24); while (!pio_sm_is_tx_fifo_empty(pio_dcd, SM_DCD_WRITE)) ; + dcd_deassert_hshk(); pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); // re-aquire the READ line for the LATCH function pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); + + handshake_after_send(); + } void simulate_packet(uint8_t ntx) { uint8_t encoded[538]; encoded[0] = 0xaa; - encoded[1] = ntx | 0x80; + //encoded[1] = ntx | 0x80; uint8_t *p = payload; int k=2; for (int i=0; i> 16) & 0xff); + uart_putc_raw(UART_ID, (sector >> 8) & 0xff); + uart_putc_raw(UART_ID, sector & 0xff); + sector++; + + memset(payload, 0, sizeof(payload)); + payload[0] = 0x80; + payload[1] = num_sectors-i; + + uart_read_blocking(UART_ID, &payload[26], 512); + for (int x=0; x<16; x++) + { + printf("%02x ", payload[26+x]); + } + printf("\n"); + compute_checksum(538); + handshake_before_send(); + send_packet(ntx); + + } +} + +void dcd_write(uint8_t ntx, bool cont) +{ + /*Macintosh: + Offset Value + 0 0x01 + 1 Number of sectors remaining to be written (including sector contained in this response) + 2-4 Sector offset (big-endian) + 5 0x00 + 6-25 Tags of sector to be written (20 bytes) + 26-537 Data of sector to be written (512 bytes) + 538 Checksum + +OR + + Macintosh (if more than one sector is to be written): + Offset Value + 0 0x41 + 1 Number of sectors remaining to be written (including sector contained in this response) + 2-5 0x00 0x00 0x00 0x00 + 6-25 Tags of sector to be written (20 bytes) + 26-537 Data of sector to be written (512 bytes) + 538 Checksum + + Response: + DCD Device: + Offset Value + 0 0x81 + 1 Number of sectors remaining to be written (including sector contained in last command) + 2-5 Status + 6 Checksum + + The Macintosh then repeats this command (and the DCD device repeats its response above) + for each sector the Macintosh has requested to be written with the value at offset 1 in + the command counting down, ending at 0x01. + */ + + // printf("\nRead Command: "); + // for (int i=0; i<7; i++) + // printf("%02x ",payload[i]); + // while(1); + + uint8_t num_sectors = payload[1]; + static uint32_t sector = 0; + if (cont) + { + sector++; + } + else + { + sector = (payload[2] << 16) + (payload[3] << 8) + payload[4]; + printf("write %06x sectors\n", sector); + } + + /// TODO FROM HERE CHANGE FROM READ TO WRITE + + // clear out UART buffer cause there was a residual byte + // while(uart_is_readable(UART_ID)) + // uart_getc(UART_ID); + + // printf("sending sector %06x in %d groups\n", sector, ntx); + + // uart_putc_raw(UART_ID, 'R'); + // uart_putc_raw(UART_ID, (sector >> 16) & 0xff); + // uart_putc_raw(UART_ID, (sector >> 8) & 0xff); + // uart_putc_raw(UART_ID, sector & 0xff); + // sector++; + // uart_read_blocking(UART_ID, &payload[26], 512); + // for (int x=0; x<512; x++) + // { + // printf("%02x ", payload[26+x]); + // } + + // response packet + memset(payload, 0, sizeof(payload)); + payload[0] = 0x81; + payload[1] = num_sectors; + + printf("\n"); + compute_checksum(6); + handshake_before_send(); + send_packet(ntx); } void dcd_status(uint8_t ntx) @@ -748,7 +873,8 @@ void dcd_status(uint8_t ntx) 0x02 Disk in place (see below) */ - printf(" status "); + printf("status\n"); + memcpy(payload,s,sizeof(s)); // memset(payload, 0, sizeof(payload)); // payload[0] = 0x83; // payload[7] = 1; @@ -764,8 +890,10 @@ void dcd_status(uint8_t ntx) // // payload[331] = 'n'; // // payload[332] = 'e'; // // payload[333] = 't'; - // compute_checksum(342); - memcpy(payload,s,sizeof(s)); + compute_checksum(342); + + handshake_before_send(); + send_packet(ntx); // simulate_packet(ntx); // assert(false); @@ -781,11 +909,14 @@ void dcd_unknown(uint8_t ntx) 2-5 Status 6 checksum */ - printf(" sending0x22 "); + printf("sending0x22 "); memset(payload, 0, sizeof(payload)); payload[0] = 0x80 | 0x22; compute_checksum(6); assert(ntx==1); + + handshake_before_send(); + send_packet(ntx); // simulate_packet(ntx); // assert(false); @@ -805,6 +936,10 @@ void dcd_format(uint8_t ntx) payload[0] = 0x80 + 0x19; compute_checksum(6); assert(ntx==1); + printf("format\n"); + + handshake_before_send(); + send_packet(ntx); // simulate_packet(ntx); // assert(false); @@ -817,7 +952,7 @@ void dcd_process(uint8_t nrx, uint8_t ntx) uint8_t *p = payload; for (int i=0; i < nrx; i++) { - // probably check for HOLDOFF, then handshake and wait for sync, then continue loop + // probably check for HOLDOFF, then handshake and wait for sync, then cont loop uint8_t lsb = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); // printf("%02x ",lsb); for (int j=0; j < 7; j++) @@ -840,20 +975,20 @@ void dcd_process(uint8_t nrx, uint8_t ntx) dcd_deassert_hshk(); a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==2); // now back to idle and awaiting DCD response - // busy_wait_us_32(10); - dcd_assert_hshk(); - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); - assert(a==3); // now back to idle and awaiting DCD response - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); - assert(a==1); // now back to idle and awaiting DCD response - - // // // - // printf("\nPayload: "); - // for (uint8_t*ptr=payload; ptr Date: Thu, 5 Oct 2023 18:49:42 -0500 Subject: [PATCH 067/158] remove unused function. --- lib/device/adamnet/network.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/device/adamnet/network.h b/lib/device/adamnet/network.h index 8a14c716d..f27e1ae08 100755 --- a/lib/device/adamnet/network.h +++ b/lib/device/adamnet/network.h @@ -83,7 +83,6 @@ class adamNetwork : public virtualDevice virtual void adamnet_control_ack(); virtual void adamnet_control_clr(); virtual void adamnet_control_receive(); - virtual void adamnet_control_receive_channel(); virtual void adamnet_control_receive_channel_json(); virtual void adamnet_control_receive_channel_protocol(); virtual void adamnet_control_send(); From 32ef1d89e6e809f4b96d3f49cf47bb8ac8fe33ec Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Oct 2023 20:13:29 -0500 Subject: [PATCH 068/158] remove unused function. --- lib/device/adamnet/network.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index ae1ae6270..db0290736 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -757,11 +757,6 @@ void adamNetwork::adamnet_control_clr() jsonRecvd = false; } -void adamNetwork::adamnet_control_receive_channel() -{ - -} - void adamNetwork::adamnet_control_receive_channel_json() { NetworkStatus ns; From 44600a0b0789d2920971e09dd19855a756d49be1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Oct 2023 21:13:05 -0500 Subject: [PATCH 069/158] Add 'E' error command --- lib/device/adamnet/network.cpp | 22 ++++++++++++++++++++++ lib/device/adamnet/network.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index db0290736..b0c35b285 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -63,6 +63,25 @@ adamNetwork::~adamNetwork() /** ADAM COMMANDS ***************************************************************/ +/** + * @brief get error number from protocol adapter + */ +void adamNetwork::get_error() +{ + NetworkStatus ns; + + adamnet_recv(); // CK + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); + response_len = 1; + + if (protocol == nullptr) + response[0] = NETWORK_ERROR_NOT_CONNECTED; + + protocol->status(&ns); + + response[0] = ns.error; +} /** * ADAM Open command * Called in response to 'O' command. Instantiate a protocol, pass URL to it, call its open @@ -694,6 +713,9 @@ void adamNetwork::adamnet_control_send() case '0': get_prefix(); break; + case 'E': + get_error(); + break; case 'O': open(s); break; diff --git a/lib/device/adamnet/network.h b/lib/device/adamnet/network.h index f27e1ae08..34db1aeee 100755 --- a/lib/device/adamnet/network.h +++ b/lib/device/adamnet/network.h @@ -52,6 +52,11 @@ class adamNetwork : public virtualDevice */ bool interruptProceed = false; + /** + * @brief called to return the extended error number from a protocol adapter + */ + virtual void get_error(); + /** * Called for ADAM Command 'O' to open a connection to a network protocol, allocate all buffers, * and start the receive PROCEED interrupt. From 5ef11cb40256f4c10f5b3fa7098744d30517d611 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Thu, 5 Oct 2023 22:53:21 -0400 Subject: [PATCH 070/158] fujinet logo --- pico/mac/commands.c | 255 ++++++++++++++++++++++++++------------------ 1 file changed, 154 insertions(+), 101 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 577b0da5e..172eb2946 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -570,6 +570,15 @@ void send_packet(uint8_t ntx) uint8_t *p = payload; for (int i=0; i> 1) | 0x80); - p++; - k++; - } - encoded[k++]=(lsb | 0x80); - } - - printf("\n"); - - for (int i=0; i> 1) | 0x80); +// p++; +// k++; +// } +// encoded[k++]=(lsb | 0x80); +// } + +// printf("\n"); + +// for (int i=0; i> 1) | 0x80); - p++; - k++; - } - encoded[k_lsb]=(lsb | 0x80); - } - - printf("\n"); +// printf("\n"); +// } - for (int i=0; i> 1) | 0x80); +// p++; +// k++; +// } +// encoded[k_lsb]=(lsb | 0x80); +// } + +// printf("\n"); + +// for (int i=0; i Date: Thu, 5 Oct 2023 22:11:29 -0500 Subject: [PATCH 071/158] [adamnet] fix error. --- lib/device/adamnet/network.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index b0c35b285..417f3eb9f 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -45,6 +45,8 @@ adamNetwork::adamNetwork() transmitBuffer->clear(); specialBuffer->clear(); + protocol = nullptr; + json.setLineEnding("\x00"); } @@ -59,6 +61,11 @@ adamNetwork::~adamNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** ADAM COMMANDS ***************************************************************/ @@ -70,17 +77,21 @@ void adamNetwork::get_error() { NetworkStatus ns; + Debug_printf("Get Error\n"); adamnet_recv(); // CK AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); response_len = 1; if (protocol == nullptr) + { response[0] = NETWORK_ERROR_NOT_CONNECTED; - - protocol->status(&ns); - - response[0] = ns.error; + } + else + { + protocol->status(&ns); + response[0] = ns.error; + } } /** * ADAM Open command From 14c2eb6faea6931e9796c94643cd21ab74bdd698 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Thu, 5 Oct 2023 23:20:37 -0400 Subject: [PATCH 072/158] fix vertical lines in fujinet logo --- pico/mac/commands.c | 82 ++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 172eb2946..2f36c8513 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -851,38 +851,38 @@ void dcd_status(uint8_t ntx) // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; - const uint8_t icon[] = {0b00000000, 0b00000001, 0b00000000, 0b00000000, - 0b00000000, 0b00000001, 0b00000000, 0b00000000, - 0b00000000, 0b00000001, 0b00000000, 0b00000000, - 0b00000000, 0b00000111, 0b11000000, 0b00000000, - 0b00000000, 0b00001111, 0b11100000, 0b00000000, - 0b00000000, 0b10011111, 0b11110010, 0b00000000, - 0b00000000, 0b10011111, 0b11110010, 0b00000000, - 0b00000111, 0b11111111, 0b11111111, 0b11100000, - 0b00000000, 0b10011111, 0b11110010, 0b00000000, - 0b00000000, 0b10011111, 0b11110010, 0b00000000, - 0b00000000, 0b10001111, 0b11100010, 0b00000000, - 0b00000111, 0b11000111, 0b11000111, 0b11000000, - 0b00001111, 0b11101100, 0b01101111, 0b11100000, - 0b00011111, 0b11111000, 0b00111111, 0b11110000, - 0b00011111, 0b11110000, 0b00011111, 0b11110000, - 0b11111111, 0b11110000, 0b00011111, 0b11111000, - 0b00011111, 0b11110000, 0b00011111, 0b11110000, - 0b00011111, 0b11111000, 0b00111111, 0b11110000, - 0b00001111, 0b11101100, 0b01101111, 0b11100000, - 0b00000111, 0b11000111, 0b11000111, 0b11000000, - 0b00000000, 0b10000001, 0b00001111, 0b11100000, - 0b00000000, 0b10000001, 0b00011111, 0b11110000, - 0b00000000, 0b10000001, 0b00011111, 0b11110000, - 0b00000011, 0b11111111, 0b11111111, 0b11111100, - 0b00000000, 0b10000001, 0b00011111, 0b11110000, - 0b00000000, 0b10000001, 0b00011111, 0b11110000, - 0b00000000, 0b10000001, 0b00001111, 0b11100000, - 0b00000000, 0b00000001, 0b00000111, 0b11000000, - 0b00000000, 0b00000001, 0b00000010, 0b00000000, - 0b00000000, 0b00000001, 0b00000010, 0b00000000, - 0b00000000, 0b00000111, 0b11111111, 0b11111111, - 0b00000000, 0b00000001, 0b00000010, 0b00000000}; + const uint8_t icon[] = {0b11111111, 0b11111110, 0b11111111, 0b11111111, + 0b11111111, 0b11111110, 0b11111111, 0b11111111, + 0b11111111, 0b11111110, 0b11111111, 0b11111111, + 0b11111111, 0b11111000, 0b00111111, 0b11111111, + 0b11111111, 0b11110000, 0b00011111, 0b11111111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111000, 0b00000000, 0b00000000, 0b00011111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111110, 0b11110000, 0b00011110, 0b11111111, + 0b11111000, 0b00111000, 0b00111000, 0b00111111, + 0b11110000, 0b00010011, 0b10010000, 0b00011111, + 0b11100000, 0b00000111, 0b11000000, 0b00001111, + 0b11100000, 0b00001111, 0b11100000, 0b00001111, + 0b00000000, 0b00001111, 0b11100000, 0b00000111, + 0b11100000, 0b00001111, 0b11100000, 0b00001111, + 0b11100000, 0b00000111, 0b11000000, 0b00001111, + 0b11110000, 0b00010011, 0b10010000, 0b00011111, + 0b11111000, 0b00111000, 0b00111000, 0b00111111, + 0b11111110, 0b11111110, 0b11110000, 0b00011111, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111100, 0b00000000, 0b00000000, 0b00000011, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111110, 0b11111110, 0b11110000, 0b00011111, + 0b11111111, 0b11111110, 0b11111000, 0b00111111, + 0b11111111, 0b11111110, 0b11111110, 0b11111111, + 0b11111111, 0b11111110, 0b11111110, 0b11111111, + 0b11111111, 0b11111000, 0b00000000, 0b00000000, + 0b11111111, 0b11111110, 0b11111110, 0b11111111}; /* DCD Device: @@ -920,18 +920,18 @@ void dcd_status(uint8_t ntx) payload[0] = 0x83; payload[7] = 1; payload[9] = 1; - payload[10] = 0xe6; //8 | 0x40 | 0x80; // 0xe6; + payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; payload[12] = 0xB0; memcpy(&payload[70], icon, sizeof(icon)); memset(&payload[198],0xff,128); - // payload[326] = 7; - // payload[327] = 'F'; - // payload[328] = 'u'; - // payload[329] = 'j'; - // payload[330] = 'i'; - // payload[331] = 'N'; - // payload[332] = 'e'; - // payload[333] = 't'; + payload[326] = 7; + payload[327] = 'F'; + payload[328] = 'u'; + payload[329] = 'j'; + payload[330] = 'i'; + payload[331] = 'N'; + payload[332] = 'e'; + payload[333] = 't'; compute_checksum(342); handshake_before_send(); From d514c7a8576865f9edd9cf6b22d242214d43f89e Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Thu, 5 Oct 2023 23:56:34 -0400 Subject: [PATCH 073/158] hold off seems to work on sending DCD to Mac --- pico/mac/commands.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2f36c8513..79249d078 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -571,14 +571,16 @@ void send_packet(uint8_t ntx) for (int i=0; i Date: Fri, 6 Oct 2023 10:40:09 -0500 Subject: [PATCH 074/158] [adamnet][network] still not fast enough. shit. --- lib/device/adamnet/network.cpp | 73 ++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index 417f3eb9f..e648a59e2 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -173,6 +173,10 @@ void adamNetwork::open(unsigned short s) // Associate channel mode json.setProtocol(protocol); + + // Clear response + memset(response, 0, sizeof(response)); + response_len = 0; } /** @@ -208,6 +212,9 @@ void adamNetwork::close() // Delete the protocol object delete protocol; protocol = nullptr; + + memset(response, 0, sizeof(response)); + response_len = 0; } /** @@ -387,6 +394,9 @@ void adamNetwork::set_prefix(unsigned short s) } Debug_printf("Prefix now: %s\n", prefix.c_str()); + + response_len = 0; + memset(response, 0, sizeof(response)); } /** @@ -449,6 +459,9 @@ void adamNetwork::del(uint16_t s) statusByte.bits.client_error = true; return; } + + memset(response, 0, sizeof(response)); + response_len = 0; } void adamNetwork::rename(uint16_t s) @@ -472,6 +485,9 @@ void adamNetwork::rename(uint16_t s) statusByte.bits.client_error = true; return; } + + memset(response, 0, sizeof(response)); + response_len = 0; } void adamNetwork::mkdir(uint16_t s) @@ -495,6 +511,9 @@ void adamNetwork::mkdir(uint16_t s) statusByte.bits.client_error = true; return; } + + memset(response, 0, sizeof(response)); + response_len = 0; } void adamNetwork::channel_mode() @@ -521,25 +540,24 @@ void adamNetwork::channel_mode() } Debug_printf("adamNetwork::channel_mode(%u)\n", m); - AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); + memset(response, 0, sizeof(response)); + response_len = 0; } void adamNetwork::json_query(unsigned short s) { - uint8_t *c = (uint8_t *)malloc(s); + memset(response, 0, sizeof(response)); + response_len = 0; - adamnet_recv_buffer(c, s); + adamnet_recv_buffer(response, s); adamnet_recv(); // CK AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); - json.setReadQuery(std::string((char *)c, s), cmdFrame.aux2); + json.setReadQuery(std::string((char *)response, s), cmdFrame.aux2); - Debug_printv("adamNetwork::json_query(%s)\n", c); - - free(c); + Debug_printv("adamNetwork::json_query(%s)\n", response); } void adamNetwork::json_parse() @@ -548,6 +566,8 @@ void adamNetwork::json_parse() AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); json.parse(); + memset(response, 0, sizeof(response)); + response_len = 0; } /** @@ -621,11 +641,16 @@ void adamNetwork::adamnet_special_00(unsigned short s) cmdFrame.aux1 = adamnet_recv(); cmdFrame.aux2 = adamnet_recv(); + adamnet_recv(); // CK + AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); protocol->special_00(&cmdFrame); inq_dstats = 0xff; + + response_len = 0; + memset(response, 0, sizeof(response)); } /** @@ -639,12 +664,17 @@ void adamNetwork::adamnet_special_40(unsigned short s) cmdFrame.aux1 = adamnet_recv(); cmdFrame.aux2 = adamnet_recv(); + adamnet_recv(); // CK + if (protocol->special_40(response, 1024, &cmdFrame) == false) adamnet_response_ack(); else adamnet_response_nack(); inq_dstats = 0xff; + + response_len = 0; + memset(response, 0, sizeof(response)); } /** @@ -666,12 +696,17 @@ void adamNetwork::adamnet_special_80(unsigned short s) Debug_printf("adamNetwork::adamnet_special_80() - %s\n", spData); + adamnet_recv(); // CK + // Do protocol action and return if (protocol->special_80(spData, SPECIAL_BUFFER_SIZE, &cmdFrame) == false) adamnet_response_ack(); else adamnet_response_nack(); inq_dstats = 0xff; + + memset(response, 0, sizeof(response)); + response_len = 0; } void adamNetwork::adamnet_response_status() @@ -724,7 +759,7 @@ void adamNetwork::adamnet_control_send() case '0': get_prefix(); break; - case 'E': + case 'E': get_error(); break; case 'O': @@ -818,11 +853,9 @@ void adamNetwork::adamnet_control_receive_channel_protocol() { NetworkStatus ns; - AdamNet.start_time = esp_timer_get_time(); - if ((protocol == nullptr) || (receiveBuffer == nullptr)) { - // adamnet_response_nack(); + adamnet_response_nack(); return; // Punch out. } @@ -830,7 +863,16 @@ void adamNetwork::adamnet_control_receive_channel_protocol() protocol->status(&ns); if (!ns.rxBytesWaiting) + { + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_nack(); return; + } + else + { + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); + } // Truncate bytes waiting to response size ns.rxBytesWaiting = (ns.rxBytesWaiting > 1024) ? 1024 : ns.rxBytesWaiting; @@ -840,6 +882,7 @@ void adamNetwork::adamnet_control_receive_channel_protocol() { statusByte.bits.client_error = true; err = protocol->error; + adamnet_response_nack(); return; } else // everything ok @@ -861,10 +904,6 @@ void adamNetwork::adamnet_control_receive() adamnet_response_ack(); return; } - else if ((response_len == 0) && (channelMode == PROTOCOL)) // this is hacky as hell - { - adamnet_response_nack(); - } switch (channelMode) { @@ -890,7 +929,7 @@ void adamNetwork::adamnet_response_send() } else adamnet_send(0xC0 | _devnum); // NAK! - + memset(response, 0, response_len); response_len = 0; } From 606f8b08c6d6be2e6ada56ac64583d211f0bf52c Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 6 Oct 2023 11:24:35 -0500 Subject: [PATCH 075/158] [adamnet][network] fix network device. --- lib/bus/adamnet/adamnet.cpp | 19 ++++++++++++------- lib/bus/adamnet/adamnet.h | 6 ++++-- lib/device/adamnet/network.cpp | 10 +++++----- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index e705cf06c..1dd2329c0 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -61,7 +61,7 @@ static void adamnet_reset_intr_task(void *arg) } b->reset(); - vTaskDelay(1); + vTaskDelay(1/portTICK_PERIOD_MS); } } @@ -160,27 +160,32 @@ void virtualDevice::reset() Debug_printf("No Reset implemented for device %u\n", _devnum); } -void virtualDevice::adamnet_response_ack() +void virtualDevice::adamnet_response_ack(bool doNotWaitForIdle) { int64_t t = esp_timer_get_time() - AdamNet.start_time; - if (t < 300) + if (!doNotWaitForIdle) { AdamNet.wait_for_idle(); - adamnet_send(0x90 | _devnum); } - else + + if (t < 300) { + adamnet_send(0x90 | _devnum); } } -void virtualDevice::adamnet_response_nack() +void virtualDevice::adamnet_response_nack(bool doNotWaitForIdle) { int64_t t = esp_timer_get_time() - AdamNet.start_time; - if (t < 300) + if (!doNotWaitForIdle) { AdamNet.wait_for_idle(); + } + + if (t < 300) + { adamnet_send(0xC0 | _devnum); } } diff --git a/lib/bus/adamnet/adamnet.h b/lib/bus/adamnet/adamnet.h index 961a4432c..f0094865d 100755 --- a/lib/bus/adamnet/adamnet.h +++ b/lib/bus/adamnet/adamnet.h @@ -146,13 +146,15 @@ class virtualDevice /** * @brief acknowledge, but not if cmd took too long. + * @param doNotWaitForIdle do not wait for idle if true. */ - virtual void adamnet_response_ack(); + virtual void adamnet_response_ack(bool doNotWaitForIdle=false); /** * @brief non-acknowledge, but not if cmd took too long + * param doNotWaitForIdle do not wait for idle if true. */ - virtual void adamnet_response_nack(); + virtual void adamnet_response_nack(bool doNotWaitForIdle=false); /** * @brief acknowledge if device is ready, but not if cmd took too long. diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index e648a59e2..d08a34d63 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -849,13 +849,13 @@ void adamNetwork::adamnet_control_receive_channel_json() } } -void adamNetwork::adamnet_control_receive_channel_protocol() +inline void adamNetwork::adamnet_control_receive_channel_protocol() { NetworkStatus ns; if ((protocol == nullptr) || (receiveBuffer == nullptr)) { - adamnet_response_nack(); + adamnet_response_nack(true); return; // Punch out. } @@ -865,13 +865,13 @@ void adamNetwork::adamnet_control_receive_channel_protocol() if (!ns.rxBytesWaiting) { AdamNet.start_time = esp_timer_get_time(); - adamnet_response_nack(); + adamnet_response_nack(true); return; } else { AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); + adamnet_response_ack(true); } // Truncate bytes waiting to response size @@ -894,7 +894,7 @@ void adamNetwork::adamnet_control_receive_channel_protocol() } } -void adamNetwork::adamnet_control_receive() +inline void adamNetwork::adamnet_control_receive() { AdamNet.start_time = esp_timer_get_time(); From bb78cfed46d31fcafe72c551d592cf0b2ee3c71c Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Fri, 6 Oct 2023 15:05:36 -0400 Subject: [PATCH 076/158] Mac DCD writing --- lib/bus/mac/mac.cpp | 2 + lib/device/mac/floppy.cpp | 23 ++++- lib/media/mac/mediaTypeDCD.cpp | 2 +- pico/mac/commands.c | 168 +++++++++------------------------ 4 files changed, 72 insertions(+), 123 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index ae1314217..04b5322c6 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -128,6 +128,8 @@ void macBus::service(void) case 'R': theFuji.get_disks(0)->disk_dev.process('R'); break; + case 'W': + theFuji.get_disks(0)->disk_dev.process('W'); default: break; } diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 68ec3112c..1b4425551 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -198,11 +198,11 @@ void macFloppy::process(mac_cmd_t cmd) { uint32_t sector_num; uint8_t buffer[512]; + char s[3]; switch (cmd) { case 'R': - char s[3]; fnUartBUS.readBytes(s, 3); sector_num = ((uint32_t)s[0] << 16) + ((uint32_t)s[1] << 8) + (uint32_t)s[2]; Debug_printf("\nDCD sector request: %06x", sector_num); @@ -210,6 +210,27 @@ void macFloppy::process(mac_cmd_t cmd) Debug_printf("\nError Reading Sector %06x",sector_num); fnUartBUS.write(buffer, sizeof(buffer)); break; + case 'W': + // uart_putc_raw(UART_ID, 'W'); + // uart_putc_raw(UART_ID, (sector >> 16) & 0xff); + // uart_putc_raw(UART_ID, (sector >> 8) & 0xff); + // uart_putc_raw(UART_ID, sector & 0xff); + // sector++; + // uart_write_blocking(UART_ID, &payload[26], 512); + fnUartBUS.readBytes(s, 3); + fnUartBUS.readBytes(buffer, sizeof(buffer)); + sector_num = ((uint32_t)s[0] << 16) + ((uint32_t)s[1] << 8) + (uint32_t)s[2]; + Debug_printf("\nDCD sector write: %06x", sector_num); + if (_disk->write(sector_num, buffer)) + { + Debug_printf("\nError Writing Sector %06x", sector_num); + fnUartBUS.write('e'); + } + else + { + fnUartBUS.write('w'); + } + break; default: break; } diff --git a/lib/media/mac/mediaTypeDCD.cpp b/lib/media/mac/mediaTypeDCD.cpp index 82b38c019..ab3614fa6 100644 --- a/lib/media/mac/mediaTypeDCD.cpp +++ b/lib/media/mac/mediaTypeDCD.cpp @@ -29,7 +29,7 @@ if ((blockNum == 0) || (blockNum != last_block_num + 1)) // example optimization bool MediaTypeDCD::write(uint32_t blockNum, uint8_t* buffer) { - size_t writesize = _media_sector_size; + size_t writesize = 512; //_media_sector_size; // if (high_score_enabled && blockNum >= _high_score_block_lb && blockNum <= _high_score_block_ub) // { diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 79249d078..2a6175de4 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -561,6 +561,9 @@ void handshake_after_send() void send_packet(uint8_t ntx) { + + handshake_before_send(); + // send the response packet encoding along the way pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); @@ -605,69 +608,6 @@ void send_packet(uint8_t ntx) } -// void simulate_packet(uint8_t ntx) -// { -// uint8_t encoded[538]; -// encoded[0] = 0xaa; -// //encoded[1] = ntx | 0x80; -// uint8_t *p = payload; -// int k=2; -// for (int i=0; i> 1) | 0x80); -// p++; -// k++; -// } -// encoded[k++]=(lsb | 0x80); -// } - -// printf("\n"); - -// for (int i=0; i> 1) | 0x80); -// p++; -// k++; -// } -// encoded[k_lsb]=(lsb | 0x80); -// } - -// printf("\n"); - -// for (int i=0; i> 16) & 0xff); - // uart_putc_raw(UART_ID, (sector >> 8) & 0xff); - // uart_putc_raw(UART_ID, sector & 0xff); - // sector++; - // uart_read_blocking(UART_ID, &payload[26], 512); - // for (int x=0; x<512; x++) - // { - // printf("%02x ", payload[26+x]); - // } - - // response packet - memset(payload, 0, sizeof(payload)); - payload[0] = 0x81; - payload[1] = num_sectors; + printf("writing sector %06x in %d groups\n", sector, ntx); + + uart_putc_raw(UART_ID, 'W'); + uart_putc_raw(UART_ID, (sector >> 16) & 0xff); + uart_putc_raw(UART_ID, (sector >> 8) & 0xff); + uart_putc_raw(UART_ID, sector & 0xff); + sector++; + uart_write_blocking(UART_ID, &payload[26], 512); + // for (int x=0; x<512; x++) + // { + // printf("%02x ", payload[26+x]); + // } + while (!uart_is_readable(UART_ID)) + ; + c = uart_getc(UART_ID); + assert(c=='w'); + // response packet + memset(payload, 0, sizeof(payload)); + payload[0] = (!verf) ? 0x81 : 0x82; + payload[1] = num_sectors; - printf("\n"); - compute_checksum(6); - handshake_before_send(); - send_packet(ntx); + printf("\n"); + compute_checksum(6); + + send_packet(ntx); } void dcd_status(uint8_t ntx) { - // const uint8_t s[] = {0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xe6, 0x00, 0x98, 0x35, 0x00, - // 0x45, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, - // 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x88, - // 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x7f, 0xff, 0xff, 0xfe, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; const uint8_t icon[] = {0b11111111, 0b11111110, 0b11111111, 0b11111111, 0b11111111, 0b11111110, 0b11111111, 0b11111111, 0b11111111, 0b11111110, 0b11111111, 0b11111111, @@ -936,8 +863,6 @@ void dcd_status(uint8_t ntx) payload[333] = 't'; compute_checksum(342); - handshake_before_send(); - send_packet(ntx); // simulate_packet(ntx); // assert(false); @@ -959,8 +884,6 @@ void dcd_unknown(uint8_t ntx) compute_checksum(6); assert(ntx==1); - handshake_before_send(); - send_packet(ntx); // simulate_packet(ntx); // assert(false); @@ -982,8 +905,6 @@ void dcd_format(uint8_t ntx) assert(ntx==1); printf("format\n"); - handshake_before_send(); - send_packet(ntx); // simulate_packet(ntx); // assert(false); @@ -1062,9 +983,12 @@ void dcd_process(uint8_t nrx, uint8_t ntx) dcd_read(ntx); break; case 0x01: - // write sectors - dcd_write(ntx, false); + dcd_write(ntx, false, false); + break; + case 0x02: + // write sectors + dcd_write(ntx, false, true); break; case 0x03: // status @@ -1083,15 +1007,17 @@ void dcd_process(uint8_t nrx, uint8_t ntx) dcd_unknown(ntx); break; case 0x41: - // cont to write sectors - dcd_write(ntx, true); + dcd_write(ntx, true, false); + break; + case 0x42: + // cont to write sectors + dcd_write(ntx, true, true); break; default: printf("\nnot implemented %02x\n",payload[0]); break; } - } void pio_commands(PIO pio, uint sm, uint offset, uint pin) { From d531d845404634a6ab1c4e7bbb44bf7a7e9bd2fa Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Fri, 6 Oct 2023 15:58:30 -0400 Subject: [PATCH 077/158] Mac: all the DCD commands --- pico/mac/commands.c | 81 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2a6175de4..28874a892 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -868,6 +868,53 @@ void dcd_status(uint8_t ntx) // assert(false); } +void dcd_id(uint8_t ntx) +{ + + /* + DCD Device: + Offset Value Sample Value from HD20 + 0 0x84 + 1 0x00 + 2-5 Status + 6-18 Name string "Rene-1 RM MH " + 19-21 Device type 0x000210 + 22-23 Firmware revision 0x3372 + 24-26 Capacity (blocks) 0x009835 + 27-28 Bytes per block 0x0214 + 29-30 Number of cylinders 0x0131 + 31 Number of heads 0x04 + 32 Number of sectors 0x20 + 33-35 Number of possible spare blocks 0x00004C + 36-38 Number of spare blocks (?) 0x110100 (?) + 39-41 Number of bad blocks (?) 0x000000 (?) + 42-47 0x00 0x00 0x00 0x00 0x00 0x00 + 48 Checksum + */ + printf("id\n"); + // memcpy(payload,s,sizeof(s)); + memset(payload, 0, sizeof(payload)); + payload[0] = 0x84; + strcpy("FujiNet DCD", &payload[6]); + payload[20]=0x02; + payload[21]=0x10; + payload[22]=0x33; + payload[23]=0x72; + payload[25]=0x98; + payload[26]=0x35; + payload[27]=0x02; + payload[28]=0x14; + payload[29]=0x01; + payload[30]=0x31; + payload[31]=0x04; + payload[32]=0x20; + compute_checksum(48); + + send_packet(ntx); + // simulate_packet(ntx); + // assert(false); +} + void dcd_unknown(uint8_t ntx) { /* @@ -910,6 +957,33 @@ void dcd_format(uint8_t ntx) // assert(false); } +void dcd_verify(uint8_t ntx) +{ + /* + Verify Format + The meaning of this command is guessed from its use in the Erase Disk command in operation. + + The observed status from this command on an actual HD20 was 0x0000008A, + however, returning a status of 0x00000000 does not appear to interrupt + the Erase Disk operation. + + DCD Device: + Offset + 0 0x9a + 1 0x00 + 2-5 Status + 6 checksum + */ + memset(payload, 0, sizeof(payload)); + payload[0] = 0x80 + 0x1a; + compute_checksum(6); + assert(ntx==1); + printf("verify format\n"); + + send_packet(ntx); + // simulate_packet(ntx); + // assert(false); +} void dcd_process(uint8_t nrx, uint8_t ntx) { @@ -1000,9 +1074,16 @@ void dcd_process(uint8_t nrx, uint8_t ntx) // The 7-to-8 group should decode to 03 00 00 00 00 00 FD dcd_status(ntx); break; + case 0x04: + // Read ID + dcd_id(ntx); + break; case 0x19: dcd_format(ntx); break; + case 0x1a: + dcd_verify(ntx); + break; case 0x22: dcd_unknown(ntx); break; From fc8d6abac4d39ebf425a3bcab71948e74b2727bd Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 7 Oct 2023 10:08:22 +1100 Subject: [PATCH 078/158] update for SP/diskII handling with softsp --- lib/bus/iwm/iwm.cpp | 7 +++++++ lib/bus/iwm/iwm_ll.cpp | 20 +++++++++++++------- lib/media/apple/mediaType.h | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/bus/iwm/iwm.cpp b/lib/bus/iwm/iwm.cpp index 31b301851..4740f679a 100644 --- a/lib/bus/iwm/iwm.cpp +++ b/lib/bus/iwm/iwm.cpp @@ -469,6 +469,13 @@ void IRAM_ATTR iwmBus::service() // expect a command packet // should not ACK unless we know this is our Command + // force floppy off when SP bus is enabled, needed for softsp + if (_old_enable_state != iwm_enable_state_t::off) + { + _old_enable_state = iwm_enable_state_t::off; + diskii_xface.stop(); + } + if (sp_command_mode != sp_cmd_state_t::command) { // iwm_ack_deassert(); // go hi-Z diff --git a/lib/bus/iwm/iwm_ll.cpp b/lib/bus/iwm/iwm_ll.cpp index fbd78e239..94324416f 100644 --- a/lib/bus/iwm/iwm_ll.cpp +++ b/lib/bus/iwm/iwm_ll.cpp @@ -27,6 +27,7 @@ void IRAM_ATTR phi_isr_handler(void *arg) // update the head position based on phases // put the right track in the SPI buffer + uint32_t int_gpio_num = (uint32_t) arg; // gpio that triggered the interrupt int error; // checksum error return uint8_t c; @@ -114,7 +115,10 @@ void IRAM_ATTR phi_isr_handler(void *arg) break; } } - else if (diskii_xface.iwm_enable_states() & 0b11) + // add extra condition here to stop edge case where on softsp, the disk is stepping inadvertantly when SP bus is + // disabled. PH1 gets set low first, then PH3 follows a very short time after. We look for the interrupt on PH1 (33) + // and then PH1 = 0 (going low) and PH3 = 1 (still high) + else if ((diskii_xface.iwm_enable_states() & 0b11) && !((int_gpio_num == 33 && _phases == 0b1000))) { if (theFuji._fnDisk2s[diskii_xface.iwm_enable_states() - 1].move_head()) { @@ -633,10 +637,10 @@ void iwm_ll::setup_gpio() // attach the interrupt service routine - gpio_isr_handler_add((gpio_num_t)SP_PHI0, phi_isr_handler, NULL); - gpio_isr_handler_add((gpio_num_t)SP_PHI1, phi_isr_handler, NULL); - gpio_isr_handler_add((gpio_num_t)SP_PHI2, phi_isr_handler, NULL); - gpio_isr_handler_add((gpio_num_t)SP_PHI3, phi_isr_handler, NULL); + gpio_isr_handler_add((gpio_num_t)SP_PHI0, phi_isr_handler, (void*) (gpio_num_t)SP_PHI0); + gpio_isr_handler_add((gpio_num_t)SP_PHI1, phi_isr_handler, (void*) (gpio_num_t)SP_PHI1); + gpio_isr_handler_add((gpio_num_t)SP_PHI2, phi_isr_handler, (void*) (gpio_num_t)SP_PHI2); + gpio_isr_handler_add((gpio_num_t)SP_PHI3, phi_isr_handler, (void*) (gpio_num_t)SP_PHI3); } void iwm_sp_ll::encode_packet(uint8_t source, iwm_packet_type_t packet_type, uint8_t status, const uint8_t* data, uint16_t num) @@ -1055,8 +1059,10 @@ uint8_t IRAM_ATTR iwm_diskii_ll::iwm_enable_states() // only enable diskII if we are either not on an en35 capable host, or we are on an en35host and /EN35=high if (!IWM.en35Host || (IWM.en35Host && (GPIO.in1.val & (0x01 << (SP_EN35 - 32))))) { - states |= (GPIO.in1.val & (0x01 << (SP_DRIVE1 - 32))) ? 0b00 : 0b01; - states |= (GPIO.in & (0x01 << SP_DRIVE2)) ? 0b00 : 0b10; + if (!(states |= (GPIO.in1.val & (0x01 << (SP_DRIVE1 - 32))) ? 0b00 : 0b01)) + { + states |= (GPIO.in & (0x01 << SP_DRIVE2)) ? 0b00 : 0b10; + } } return states; } diff --git a/lib/media/apple/mediaType.h b/lib/media/apple/mediaType.h index 3ce23965c..a5709e71f 100644 --- a/lib/media/apple/mediaType.h +++ b/lib/media/apple/mediaType.h @@ -2,7 +2,7 @@ #define _MEDIA_TYPE_ #include -#include +#include"../fuji/fujiHost.h" #define INVALID_SECTOR_VALUE 65536 From e2e62393fa360cc39cd3b1e119dd6fe1d05ae59c Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 7 Oct 2023 09:29:41 -0400 Subject: [PATCH 079/158] mac: checking in --- lib/bus/mac/mac.h | 2 +- lib/device/mac/floppy.cpp | 7 +++++-- lib/device/mac/floppy.h | 4 ++-- lib/device/mac/fuji.cpp | 2 +- pico/mac/commands.c | 30 ++++++++++++++++++++++++++---- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/bus/mac/mac.h b/lib/bus/mac/mac.h index 6a0d9c1d2..693a30adc 100644 --- a/lib/bus/mac/mac.h +++ b/lib/bus/mac/mac.h @@ -53,7 +53,7 @@ class macDevice friend macBus; protected: - uint8_t _devnum; // assigned by Apple II during INIT + uint8_t _devnum; bool _initialized; public: diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 1b4425551..f950b101b 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -5,7 +5,7 @@ #define NS_PER_BIT_TIME 125 #define BLANK_TRACK_LEN 6400 -mediatype_t macFloppy::mount(FILE *f, const char *filename, mediatype_t disk_type) //, const char *filename), uint32_t disksize, mediatype_t disk_type) +mediatype_t macFloppy::mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type) { mediatype_t mt = MEDIATYPE_UNKNOWN; @@ -53,6 +53,8 @@ mediatype_t macFloppy::mount(FILE *f, const char *filename, mediatype_t disk_typ device_active = true; _disk = new MediaTypeDCD(); mt = ((MediaTypeDCD *)_disk)->mount(f); + fnUartBUS.write('h'); // harddisk + fnUartBUS.write(id()); // DCD number break; // case MEDIATYPE_DSK: // Debug_printf("\nMounting Media Type DSK"); @@ -126,7 +128,8 @@ DCDDATA Communication channel from DCD device to Macintosh void macFloppy::unmount() { - ((MediaTypeMOOF *)_disk)->unmount(); + // todo - check device type and call correct unmount() + // ((MediaTypeMOOF *)_disk)->unmount(); } int IRAM_ATTR macFloppy::step() diff --git a/lib/device/mac/floppy.h b/lib/device/mac/floppy.h index 92ab59ee9..05dadda49 100644 --- a/lib/device/mac/floppy.h +++ b/lib/device/mac/floppy.h @@ -53,8 +53,8 @@ class macFloppy : public macDevice ~macFloppy() {}; // void init(); - mediatype_t mount(FILE *f, const char *filename, mediatype_t disk_type = MEDIATYPE_UNKNOWN); - mediatype_t mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type = MEDIATYPE_UNKNOWN) { return mount(f, filename, disk_type); }; + //mediatype_t mount(FILE *f, const char *filename, mediatype_t disk_type = MEDIATYPE_UNKNOWN); + mediatype_t mount(FILE *f, const char *filename, uint32_t disksize , mediatype_t disk_type = MEDIATYPE_UNKNOWN);// { return mount(f, filename, disk_type); }; void unmount(); bool write_blank(FILE *f, uint16_t sectorSize, uint16_t numSectors) { return false; }; int get_track_pos() { return track_pos; }; diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index 9ca02f983..a528048e5 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -76,7 +76,7 @@ void macFuji::setup(macBus *macbus) // { FILE *f = fsFlash.file_open("/autorun.moof"); if (f!=nullptr) - _fnDisks[0].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); + _fnDisks[4].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); else Debug_printf("\nCould not open 'autorun.moof'"); // } diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 28874a892..ed3d1390f 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -405,7 +405,7 @@ void floppy_loop() step_state = false; } - if (uart_is_readable(uart1)) + if (uart_is_readable(UART_ID)) { // !READY // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. @@ -440,6 +440,7 @@ void floppy_loop() break; case 'S': // step complete (data copied to RMT buffer on ESP32) printf("\nStep sequence complete"); + // fall through????????????????????????????????????????? case 'M': // motor on printf("\nMotor is on"); clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met @@ -531,7 +532,24 @@ void dcd_loop() break; } printf("%c", a + '0'); - } + } + + // handle comms from ESP32 + if (uart_is_readable(UART_ID)) + { + c = uart_getc(UART_ID); + switch (c) + { + case 'h': // harddisk is mounted + c = uart_getc(UART_ID); + printf("\nHard Disk %d mounted", c); + // c is now the drive slot (DCD unit) number + // can add write protection info (or should move status packet generation to ESP32) + break; + default: + break; + } + } } uint8_t payload[539]; @@ -548,6 +566,8 @@ void handshake_before_send() assert(a==3); // now back to idle and awaiting DCD response a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); assert(a==1); // now back to idle and awaiting DCD response + // to do: handshaking error recovery - + // case 1: TNFS seek timeout and abort - need to capture on LogAn to see what's going on } void handshake_after_send() @@ -766,7 +786,7 @@ OR while (!uart_is_readable(UART_ID)) ; c = uart_getc(UART_ID); - assert(c=='w'); + assert(c=='w'); // error handling? // response packet memset(payload, 0, sizeof(payload)); payload[0] = (!verf) ? 0x81 : 0x82; @@ -780,6 +800,7 @@ OR void dcd_status(uint8_t ntx) { + // to do : move status packet generation to ESP32 const uint8_t icon[] = {0b11111111, 0b11111110, 0b11111111, 0b11111111, 0b11111111, 0b11111110, 0b11111111, 0b11111111, 0b11111111, 0b11111110, 0b11111111, 0b11111111, @@ -849,7 +870,8 @@ void dcd_status(uint8_t ntx) payload[0] = 0x83; payload[7] = 1; payload[9] = 1; - payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; + // payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; + payload[10] = 0x80 | 0x40 | 0x08 | 0x04 | 0x02; // 0xe6; payload[12] = 0xB0; memcpy(&payload[70], icon, sizeof(icon)); memset(&payload[198],0xff,128); From 7fcee2beca2329f88c61ea03b7aafb8670219a11 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 7 Oct 2023 20:23:09 -0500 Subject: [PATCH 080/158] [adam] flush change. update config. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes lib/bus/adamnet/adamnet.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 4c9b90d5b043aedbe7c82381dbf175ecd24c459a..c7ea4f57f8a9f9b4a8da04f0b6b25470744ec2ac 100644 GIT binary patch literal 262144 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 z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k m025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;_W&6ZqeDn3}x+ literal 262144 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 zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#W iOn?b60Vco%m;e)C0!)AjFaajO1egF5U;>{&;C}&Iqm6F> diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 1dd2329c0..4aeb52106 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -287,8 +287,8 @@ void systemBus::_adamnet_process_cmd() fnLedManager.set(eLed::LED_BUS, false); } - wait_for_idle(); // to avoid failing edge case where device is connected but disabled. fnUartBUS.flush_input(); + wait_for_idle(); // to avoid failing edge case where device is connected but disabled. } void systemBus::_adamnet_process_queue() From fcd2fdd62908baf62f2be659248fa2dbfb0e9c5a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 7 Oct 2023 20:26:58 -0500 Subject: [PATCH 081/158] v1.2 bump. --- include/version.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/version.h b/include/version.h index 443008d65..679888b23 100644 --- a/include/version.h +++ b/include/version.h @@ -8,11 +8,11 @@ */ #define FN_VERSION_MAJOR 1 -#define FN_VERSION_MINOR 1 +#define FN_VERSION_MINOR 2 -#define FN_VERSION_BUILD "3ad610d" +#define FN_VERSION_BUILD "7fcee2beca2329f88c61ea03b7aafb8670219a11" -#define FN_VERSION_DATE "2023-08-13 10:21:00" +#define FN_VERSION_DATE "2023-10-07 20:25:00" -#define FN_VERSION_FULL "v1.1" +#define FN_VERSION_FULL "v1.2" From 30d285b505a31042b38248f782646cd43ac1fe94 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 7 Oct 2023 20:44:08 -0500 Subject: [PATCH 082/158] [adam] cursor bug fix. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index c7ea4f57f8a9f9b4a8da04f0b6b25470744ec2ac..f9f9c40030dee88178e3295dc74c8635009994c6 100644 GIT binary patch literal 262144 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 zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj mFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCh#9b;C}(lyN5;q literal 262144 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 z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k z025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k m025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;_W&6ZqeDn3}x+ From 1f21ff53084c464e7ce285d1daa5523cc985bfe5 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 7 Oct 2023 22:04:23 -0400 Subject: [PATCH 083/158] mac: optimize a bit on a pio sm --- lib/device/mac/fuji.cpp | 17 +++++++++++------ pico/mac/dcd_mux.pio | 14 ++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index a528048e5..43c2c3b87 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -65,18 +65,23 @@ void macFuji::setup(macBus *macbus) // _iwm_bus->addDevice(theCPM, iwm_fujinet_type_t::CPM); // 27-aug-23 use something similar for Mac floppy/dcd disks - // for (int i = MAX_DISK_DEVICES - MAX_DISK2_DEVICES -1; i >= 0; i--) - // { - // _fnDisks[i].disk_dev.set_disk_number('0' + i); - // _iwm_bus->addDevice(&_fnDisks[i].disk_dev, iwm_fujinet_type_t::BlockDisk); - // } + for (int i = MAX_DISK_DEVICES - MAX_FLOPPY_DEVICES -1; i >= 0; i--) + { + _fnDisks[i].disk_dev.set_disk_number('0' + i); + // _mac_bus->addDevice(&_fnDisks[i].disk_dev, mac_fujinet_type_t::HardDisk); + } + for (int i = MAX_DISK_DEVICES - 1; i >= MAX_DISK_DEVICES - MAX_FLOPPY_DEVICES; i--) + { + _fnDisks[MAX_DISK_DEVICES - 1].disk_dev.set_disk_number('0' + i); + // _mac_bus->addDevice(&_fnDisks[i].disk_dev, mac_fujinet_type_t::Floppy); + } // Debug_printf("\nConfig General Boot Mode: %u\n",Config.get_general_boot_mode()); // if (Config.get_general_boot_mode() == 0) // { FILE *f = fsFlash.file_open("/autorun.moof"); if (f!=nullptr) - _fnDisks[4].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); + _fnDisks[MAX_DISK_DEVICES - MAX_FLOPPY_DEVICES].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); else Debug_printf("\nCould not open 'autorun.moof'"); // } diff --git a/pico/mac/dcd_mux.pio b/pico/mac/dcd_mux.pio index 91c66cf0c..11f462a81 100644 --- a/pico/mac/dcd_mux.pio +++ b/pico/mac/dcd_mux.pio @@ -16,24 +16,22 @@ ; probably at some point should push the strobe counter so the FN can decide which disk image to use .program dcd_mux +.side_set 1 opt pindirs ; initial state is RD is hi-z and we have 2 DCDs ; we wait to be enabled then RD goes to output start: - set pindirs, 0 .wrap_target - set x, 0 + set x, 0 side 0 wait 0 gpio ENABLE - set pindirs, 1 cont: ; now we need to wait to be strobed or to be disabled - jmp pin start ; disabled so go back to the beginning! + jmp pin start side 1 ; disabled so go back to the beginning! mov osr, pins ; get LSTRB value into osr out y, 1 ; stick it in Y jmp !Y cont ; not strobing loop wait 0 gpio LSTRB jmp x-- cont - set pindirs, 0 - wait 1 gpio ENABLE + wait 1 gpio ENABLE side 0 .wrap % c-sdk { @@ -44,11 +42,11 @@ void dcd_mux_program_init(PIO pio, uint sm, uint offset, uint set_pin) { // configure a SM pio_sm_config c = dcd_mux_program_get_default_config(offset); // config side set -// sm_config_set_sideset_pins(&c, mux_pin); + sm_config_set_sideset_pins(&c, set_pin); sm_config_set_in_pins(&c, LSTRB); sm_config_set_jmp_pin(&c, ENABLE); // there are 4 wires to read for latch mux, shift to the right, no autopull - sm_config_set_set_pins(&c, set_pin, 1); + // sm_config_set_set_pins(&c, set_pin, 1); sm_config_set_out_shift(&c, true, false, 1); pio_gpio_init(pio, set_pin); pio_sm_set_consecutive_pindirs(pio, sm, set_pin, 1, false); From 57e75102a63d534b8304b2e7b7d06358460c802b Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Mon, 9 Oct 2023 19:09:21 +0100 Subject: [PATCH 084/158] Add 00 dstats $FB command to change json parameters --- lib/device/sio/network.cpp | 40 ++++++++++++++++++++++++++++++++++++++ lib/device/sio/network.h | 6 ++++++ lib/fnjson/fnjson.cpp | 6 ++++++ lib/fnjson/fnjson.h | 1 + 4 files changed, 53 insertions(+) diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index fa57574ff..aaf282ace 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -703,6 +703,10 @@ void sioNetwork::do_inquiry(unsigned char inq_cmd) case 0xFC: inq_dstats = 0x00; break; + case 0xFB: // String Processing mode, only in JSON mode + if (channelMode == JSON) + inq_dstats = 0x00; + break; case 0x30: inq_dstats = 0x40; break; @@ -749,6 +753,9 @@ void sioNetwork::sio_special_00() case 'Z': sio_set_timer_rate(); break; + case 0xFB: // JSON parameter wrangling + sio_set_json_parameters(); + break; case 0xFC: // SET CHANNEL MODE sio_set_channel_mode(); break; @@ -1108,6 +1115,39 @@ void sioNetwork::sio_set_json_query() sio_complete(); } +void sioNetwork::sio_set_json_parameters() +{ + // aux1 | aux2 | meaning + // 0 | 0/1/2 | Set the json->_queryParam value, which is the translation value for string processing + // 1 | c | Set the json->lineEnding = c, convert from char to single byte string + + switch (cmdFrame.aux1) + { + case 0: // JSON QUERY PARAM + if (cmdFrame.aux2 > 2) + { + sio_error(); + return; + } + json->setQueryParam(cmdFrame.aux2); + sio_complete(); + break; + case 1: // LINE ENDING + { + std::stringstream ss; + ss << cmdFrame.aux2; + string new_le = ss.str(); + Debug_printf("JSON line ending changed to 0x%02hx\r\n", cmdFrame.aux2); + json->setLineEnding(new_le); + sio_complete(); + break; + } + default: + sio_error(); + break; + } +} + void sioNetwork::sio_set_timer_rate() { timerRate = (cmdFrame.aux2 * 256) + cmdFrame.aux1; diff --git a/lib/device/sio/network.h b/lib/device/sio/network.h index 17983373c..ba2048ba3 100755 --- a/lib/device/sio/network.h +++ b/lib/device/sio/network.h @@ -391,6 +391,12 @@ class sioNetwork : public virtualDevice */ void sio_set_json_query(); + /** + * @brief Set JSON parameters. (must be in JSON channelMode) + * Used to affect values on the JSON object + */ + void sio_set_json_parameters(); + /** * @brief Set timer rate for PROCEED timer in ms */ diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index e85203fe6..8a8995e67 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -54,6 +54,12 @@ void FNJSON::setProtocol(NetworkProtocol *newProtocol) _protocol = newProtocol; } +void FNJSON::setQueryParam(uint8_t qp) +{ + Debug_printf("FNJSON::setQueryParam(0x%02hx)\r\n", qp); + _queryParam = qp; +} + /** * Set read query string */ diff --git a/lib/fnjson/fnjson.h b/lib/fnjson/fnjson.h index a19a78ae9..2086c92ee 100644 --- a/lib/fnjson/fnjson.h +++ b/lib/fnjson/fnjson.h @@ -30,6 +30,7 @@ class FNJSON bool readValue(uint8_t *buf, unsigned short len); string processString(string in); int json_bytes_remaining = 0; + void setQueryParam(uint8_t qp); private: cJSON *_json = nullptr; From 035051fcc1ddedd93bcc221fd7e91ade58b1f601 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Mon, 9 Oct 2023 14:19:59 -0500 Subject: [PATCH 085/158] atari: cpm: webui: implement disable cpm option --- data/webui/config/fujinet-atari-v1.yaml | 1 + data/webui/template/www/header.tmpl.html | 70 +++++++++---------- data/webui/template/www/index.tmpl.html | 77 ++++++++++++++++++++- data/webui/template/www/js/settings.tmpl.js | 8 ++- data/webui/template/www/js/storage.js | 10 +-- lib/bus/sio/sio.cpp | 3 +- lib/config/fnConfig.h | 9 ++- lib/config/fnc_cpm.cpp | 13 ++++ lib/config/fnc_save.cpp | 1 + lib/http/httpServiceConfigurator.cpp | 31 +++++++++ lib/http/httpServiceConfigurator.h | 2 + lib/http/httpServiceParser.cpp | 14 +++- lib/modem/modem.cpp | 13 +++- 13 files changed, 199 insertions(+), 53 deletions(-) diff --git a/data/webui/config/fujinet-atari-v1.yaml b/data/webui/config/fujinet-atari-v1.yaml index 60a4f138a..f9ebf0c90 100644 --- a/data/webui/config/fujinet-atari-v1.yaml +++ b/data/webui/config/fujinet-atari-v1.yaml @@ -17,3 +17,4 @@ components: disk_swap: true boot_settings: true apetime: true + cpm_settings: true diff --git a/data/webui/template/www/header.tmpl.html b/data/webui/template/www/header.tmpl.html index 7323e3116..ca36c760e 100644 --- a/data/webui/template/www/header.tmpl.html +++ b/data/webui/template/www/header.tmpl.html @@ -12,39 +12,39 @@ display: inline-block; vertical-align: middle; } - + @font-face { font-family: 'Futura'; src: url('{{ paths.font_path }}/FuturaBT-Light.woff2') format('woff2'); font-weight: 300; font-style: normal; } - + @font-face { font-family: 'Inconsolata'; src: url('{{ paths.font_path }}/Inconsolata-Light.woff2') format('woff2'); font-weight: 300; font-style: normal; } - + html { max-width: 98%; } - + .header { width: 100%; } - + .headerlogo { width: 20rem; margin: 0 auto; } - + .formwrapper { margin: auto; text-align: center; } - + .flexparent { display: flex; flex-wrap: wrap; @@ -53,13 +53,13 @@ align-items: flex-start; align-content: stretch; } - + .flexchild { border: 0.2rem solid #000; width: 99%; margin: 0.5rem; } - + .flexchild header { color: #fff; border: 0.2rem solid #000; @@ -67,7 +67,7 @@ padding: 0.2rem; font-size: 1.5rem; } - + .detline { display: flex; flex-wrap: wrap; @@ -76,7 +76,7 @@ align-items: stretch; align-content: stretch; } - + .deth { border-right: 0.2rem solid #999; background-color: #cccccc; @@ -86,11 +86,11 @@ padding: 0.1rem; text-align: right; } - + .detline.alt .deth { background-color: #aaaaaa; } - + .det { font-family: Inconsolata, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; border: none; @@ -104,12 +104,12 @@ .detline.alt .det { background-color: #eeeeee; } - + .ra { width: 6rem; text-align: right } - + .cicon { border-right: 0.2rem solid #999; background-color: #cccccc; @@ -117,14 +117,14 @@ width: 38%; padding: 0.5rem; } - + .cform { position: relative; min-width: 55%; max-width: 55%; padding: 0.2rem; } - + .svgicon { width: 8rem; min-height: 12rem; @@ -132,17 +132,17 @@ text-align: center; color: #999999; } - + .small { font-size: smaller; line-height: 1.5; } - + .important { color: #000; font-weight: bolder; } - + .fileflex { display: flex; flex-direction: row; @@ -156,7 +156,7 @@ width: 99%; margin: 0.5rem; } - + .filechild header { color: #fff; border: 0.2rem solid #000; @@ -174,28 +174,28 @@ .abortline { background-color: #aaaaaa; } - + body { font-family: Futura, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } - + html, input, optgroup { /* font-size: 140% */ } - + @media only screen and (min-width: 720px) { - + html, input, optgroup { /* font-size: 140%; */ } } - + @media only screen and (min-width: 1024px) { - + html, input, optgroup { @@ -204,35 +204,35 @@ .flexparent { flex-direction: row; } - + .flexchild { width: 47.5%; } - + } - + @media only screen and (min-width: 1280px) { - + html, input, optgroup { /* font-size: 120%; */ } - + .flexparent { flex-direction: row; } - + .flexchild { width: 47.5%; } - + } #txt_hostname { text-align: right; } - + + {% endif %} diff --git a/data/webui/template/www/js/settings.tmpl.js b/data/webui/template/www/js/settings.tmpl.js index 5e514db56..90baf5481 100644 --- a/data/webui/template/www/js/settings.tmpl.js +++ b/data/webui/template/www/js/settings.tmpl.js @@ -18,7 +18,7 @@ function selectListValue(selectName, currentValue) { if (mySelect == null) return; var opts = mySelect.options; - + for (var opt, j = 0; opt = opts[j]; j++) { if (opt.value == currentValue) { mySelect.selectedIndex = j; @@ -93,4 +93,8 @@ setInputValue(current_encrypt_passphrase_enabled == 1, "encrypt-passphrase-yes", {% if components.apetime %} setInputValue(current_apetime == 1, "tz-apetime-yes", "tz-apetime-no"); -{% endif %} \ No newline at end of file +{% endif %} + +{% if components.cpm_settings %} +setInputValue(current_cpm_enabled == 1, "cpm-virt-yes", "cpm-virt-no"); +{% endif %} diff --git a/data/webui/template/www/js/storage.js b/data/webui/template/www/js/storage.js index 61ddb3aa2..26bf7ac83 100644 --- a/data/webui/template/www/js/storage.js +++ b/data/webui/template/www/js/storage.js @@ -14,7 +14,7 @@ var Piechart = function(options) this.canvas = options.canvas; this.ctx = this.canvas.getContext("2d"); this.colors = options.colors; - + this.draw = function(){ var total_value = 0; var color_index = 0; @@ -22,12 +22,12 @@ var Piechart = function(options) var val = this.options.data[categ]; total_value += val; } - + var start_angle = 0; for (categ in this.options.data){ val = this.options.data[categ]; var slice_angle = 2 * Math.PI * val / total_value; - + drawPieSlice( this.ctx, this.canvas.width/2, @@ -37,11 +37,11 @@ var Piechart = function(options) start_angle+slice_angle, this.colors[color_index%this.colors.length] ); - + start_angle += slice_angle; color_index++; } - + } } diff --git a/lib/bus/sio/sio.cpp b/lib/bus/sio/sio.cpp index 31f7f2854..2b1c8a269 100755 --- a/lib/bus/sio/sio.cpp +++ b/lib/bus/sio/sio.cpp @@ -249,6 +249,7 @@ void systemBus::_sio_process_cmd() } } fnLedManager.set(eLed::LED_BUS, false); + //Debug_printv("free low heap: %lu\r\n",esp_get_free_internal_heap_size()); } // Look to see if we have any waiting messages and process them accordingly @@ -300,7 +301,7 @@ void systemBus::service() return; // break! } } - else if (_cpmDev != nullptr && _cpmDev->cpmActive) + else if (_cpmDev != nullptr && _cpmDev->cpmActive && Config.get_cpm_enabled()) { _cpmDev->sio_handle_cpm(); return; // break! diff --git a/lib/config/fnConfig.h b/lib/config/fnConfig.h index 28c512d39..92527c84b 100755 --- a/lib/config/fnConfig.h +++ b/lib/config/fnConfig.h @@ -23,7 +23,7 @@ #define CONFIG_DEFAULT_SNTPSERVER "pool.ntp.org" -#define PHONEBOOK_CHAR_WIDTH 12 +#define PHONEBOOK_CHAR_WIDTH 12 class fnConfig @@ -164,6 +164,8 @@ class fnConfig // CPM std::string get_ccp_filename(){ return _cpm.ccp; }; void store_ccp_filename(const std::string &filename); + void store_cpm_enabled(bool cpm_enabled); + bool get_cpm_enabled(){ return _cpm.cpm_enabled; }; // ENABLE/DISABLE DEVICE SLOTS bool get_device_slot_enable_1(); @@ -206,7 +208,7 @@ class fnConfig void _read_section_host(std::stringstream &ss, int index); void _read_section_mount(std::stringstream &ss, int index); void _read_section_printer(std::stringstream &ss, int index); - void _read_section_tape(std::stringstream &ss, int index); + void _read_section_tape(std::stringstream &ss, int index); void _read_section_modem(std::stringstream &ss); void _read_section_cassette(std::stringstream &ss); void _read_section_phonebook(std::stringstream &ss, int index); @@ -271,7 +273,7 @@ class fnConfig to those limitations. We set asside 33 characters to allow for a zero terminator in a 32-char SSID and treat it as string instead of an array of arbitrary byte values. - + Similarly, the PSK (passphrase/password) is 64 octets. User-facing systems will typically take an 8 to 63 ASCII string and hash that into a 64 octet value. Although we're storing that ASCII string, @@ -332,6 +334,7 @@ class fnConfig struct cpm_info { + bool cpm_enabled = true; std::string ccp; }; diff --git a/lib/config/fnc_cpm.cpp b/lib/config/fnc_cpm.cpp index 94e0c0d17..776a9594a 100644 --- a/lib/config/fnc_cpm.cpp +++ b/lib/config/fnc_cpm.cpp @@ -1,6 +1,17 @@ #include "fnConfig.h" +#include "utils.h" #include +// Saves CPM DIS/ENabled flag +void fnConfig::store_cpm_enabled(bool cpm_enabled) +{ + if (_cpm.cpm_enabled == cpm_enabled) + return; + + _cpm.cpm_enabled = cpm_enabled; + _dirty = true; +} + // Saves CPM Command Control Processor Filename void fnConfig::store_ccp_filename(const std::string &filename) { @@ -24,6 +35,8 @@ void fnConfig::_read_section_cpm(std::stringstream &ss) { if (strcasecmp(name.c_str(), "ccp") == 0) _cpm.ccp = value; + else if (strcasecmp(name.c_str(), "cpm_enabled") == 0) + _cpm.cpm_enabled = util_string_value_is_true(value); } } } diff --git a/lib/config/fnc_save.cpp b/lib/config/fnc_save.cpp index cce4dc9be..70c3f60af 100644 --- a/lib/config/fnc_save.cpp +++ b/lib/config/fnc_save.cpp @@ -143,6 +143,7 @@ void fnConfig::save() // CPM ss << LINETERM << "[CPM]" << LINETERM; + ss << "cpm_enabled=" << _cpm.cpm_enabled << LINETERM; ss << "ccp=" << _cpm.ccp << LINETERM; // ENABLE DEVICE SLOTS diff --git a/lib/http/httpServiceConfigurator.cpp b/lib/http/httpServiceConfigurator.cpp index 87f2ab3ad..835b31b52 100644 --- a/lib/http/httpServiceConfigurator.cpp +++ b/lib/http/httpServiceConfigurator.cpp @@ -415,6 +415,29 @@ void fnHttpServiceConfigurator::config_apetime_enabled(std::string enabled) Config.save(); } +void fnHttpServiceConfigurator::config_cpm_enabled(std::string cpm_enabled) +{ + Debug_printf("New CP/M Enable Value: %s\n", cpm_enabled.c_str()); + Config.store_cpm_enabled(atoi(cpm_enabled.c_str())); + Config.save(); +} + +void fnHttpServiceConfigurator::config_cpm_ccp(std::string cpm_ccp) +{ + // Use $ as a flag to reset to default CCP since empty field never gets to here + if ( !strcmp(cpm_ccp.c_str(), "$") ) + { + Debug_printf("Set CP/M CCP File to DEFAULT\n"); + Config.store_ccp_filename(""); + } + else + { + Debug_printf("Set CP/M CCP File: %s\n", cpm_ccp.c_str()); + Config.store_ccp_filename(cpm_ccp.c_str()); + } + Config.save(); +} + int fnHttpServiceConfigurator::process_config_post(const char *postdata, size_t postlen) { #ifdef DEBUG @@ -506,6 +529,14 @@ int fnHttpServiceConfigurator::process_config_post(const char *postdata, size_t { config_apetime_enabled(i->second); } + else if (i->first.compare("cpm_enabled") == 0) + { + config_cpm_enabled(i->second); + } + else if (i->first.compare("cpm_ccp") == 0) + { + config_cpm_ccp(i->second); + } } return 0; diff --git a/lib/http/httpServiceConfigurator.h b/lib/http/httpServiceConfigurator.h index 464f51bae..2df3777e8 100755 --- a/lib/http/httpServiceConfigurator.h +++ b/lib/http/httpServiceConfigurator.h @@ -29,6 +29,8 @@ class fnHttpServiceConfigurator static void config_modem_sniffer_enabled(std::string modem_sniffer_enabled); static void config_encrypt_passphrase_enabled(std::string encrypt_passphrase_enabled); static void config_apetime_enabled(std::string apetime_enabled); + static void config_cpm_enabled(std::string cpm_enabled); + static void config_cpm_ccp(std::string cpm_ccp); public: diff --git a/lib/http/httpServiceParser.cpp b/lib/http/httpServiceParser.cpp index 573a190f6..d30a4aeba 100644 --- a/lib/http/httpServiceParser.cpp +++ b/lib/http/httpServiceParser.cpp @@ -102,6 +102,8 @@ const string fnHttpServiceParser::substitute_tag(const string &tag) FN_PRINTER_LIST, FN_ENCRYPT_PASSPHRASE_ENABLED, FN_APETIME_ENABLED, + FN_CPM_ENABLED, + FN_CPM_CCP, FN_LASTTAG }; @@ -188,7 +190,9 @@ const string fnHttpServiceParser::substitute_tag(const string &tag) "FN_HARDWARE_VER", "FN_PRINTER_LIST", "FN_ENCRYPT_PASSPHRASE_ENABLED", - "FN_APETIME_ENABLED" + "FN_APETIME_ENABLED", + "FN_CPM_ENABLED", + "FN_CPM_CCP" }; stringstream resultstream; @@ -337,7 +341,7 @@ const string fnHttpServiceParser::substitute_tag(const string &tag) #endif /* BUILD_APPLE */ } break; -#ifdef BUILD_ATARI +#ifdef BUILD_ATARI case FN_PLAY_RECORD: if (theFuji.cassette()->get_buttons()) resultstream << "0 PLAY"; @@ -485,6 +489,12 @@ const string fnHttpServiceParser::substitute_tag(const string &tag) case FN_ENCRYPT_PASSPHRASE_ENABLED: resultstream << Config.get_general_encrypt_passphrase(); break; + case FN_CPM_ENABLED: + resultstream << Config.get_cpm_enabled(); + break; + case FN_CPM_CCP: + resultstream << Config.get_ccp_filename(); + break; default: resultstream << tag; break; diff --git a/lib/modem/modem.cpp b/lib/modem/modem.cpp index a5e639fe6..1870e991b 100755 --- a/lib/modem/modem.cpp +++ b/lib/modem/modem.cpp @@ -1486,9 +1486,16 @@ void modem::modemCommand() at_cmd_println("OK"); break; case AT_CPM: - modemActive = false; - SIO.getCPM()->init_cpm(modemBaud); - SIO.getCPM()->cpmActive = true; + if (Config.get_cpm_enabled()) + { + modemActive = false; + SIO.getCPM()->init_cpm(modemBaud); + SIO.getCPM()->cpmActive = true; + } + else + { + at_cmd_println("CP/M IS DISABLED"); + } break; case AT_PHONEBOOKLIST: at_handle_pblist(); From 7a5ae915509c93d7e6d9d5485e59e2abe786d144 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Mon, 9 Oct 2023 19:24:28 -0400 Subject: [PATCH 086/158] mac: move status to esp32, put disk nums in place --- lib/bus/mac/mac.cpp | 17 +++++-- lib/bus/mac/mac.h | 6 ++- lib/device/mac/floppy.cpp | 86 ++++++++++++++++++++++++++++++++ lib/device/mac/floppy.h | 2 + lib/device/mac/fuji.cpp | 16 +++--- pico/mac/commands.c | 100 ++++++++++++-------------------------- pico/mac/dcd_mux.pio | 13 +++-- 7 files changed, 153 insertions(+), 87 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 04b5322c6..a22c73423 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -124,12 +124,19 @@ void macBus::service(void) else // DCD { switch (c) - { - case 'R': - theFuji.get_disks(0)->disk_dev.process('R'); + { + case 'A': + case 'B': + case 'C': + case 'D': + _active_DCD_disk = c-'A'; // 0, 1, 2, 3 + Debug_printf("\nactive disk %d", _active_DCD_disk); break; + case 'R': + case 'T': case 'W': - theFuji.get_disks(0)->disk_dev.process('W'); + theFuji.get_disks(_active_DCD_disk)->disk_dev.process(c); + break; default: break; } @@ -137,7 +144,7 @@ void macBus::service(void) } if (track_not_copied && stepper_timeout()) { - theFuji.get_disks(0)->disk_dev.update_track_buffers(); + theFuji.get_disks(4)->disk_dev.update_track_buffers(); track_not_copied = false; fnUartBUS.write('S'); } diff --git a/lib/bus/mac/mac.h b/lib/bus/mac/mac.h index 693a30adc..b0f515a7a 100644 --- a/lib/bus/mac/mac.h +++ b/lib/bus/mac/mac.h @@ -53,7 +53,7 @@ class macDevice friend macBus; protected: - uint8_t _devnum; + char _devnum; bool _initialized; public: @@ -62,7 +62,7 @@ class macDevice virtual void shutdown() = 0; virtual void process(mac_cmd_t cmd) = 0; - uint8_t id() { return _devnum; }; + char id() { return _devnum; }; }; class macBus @@ -82,6 +82,8 @@ class macBus const int _mac_baud_rate = 2000000; //230400; //was 115200; + int _active_DCD_disk; + public: std::forward_list _daisyChain; diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index f950b101b..419154809 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -1,6 +1,7 @@ #ifdef BUILD_MAC #include "floppy.h" #include "../bus/mac/mac_ll.h" +#include #define NS_PER_BIT_TIME 125 #define BLANK_TRACK_LEN 6400 @@ -196,6 +197,83 @@ void IRAM_ATTR macFloppy::change_track(int side) // Since the empty track has no data, and therefore no length, using a fake length of 51,200 bits (6400 bytes) works very well. } +void macFloppy::dcd_status(uint8_t* payload) +{ + const uint8_t icon[] = {0b11111111, 0b11111110, 0b11111111, 0b11111111, + 0b11111111, 0b11111110, 0b11111111, 0b11111111, + 0b11111111, 0b11111110, 0b11111111, 0b11111111, + 0b11111111, 0b11111000, 0b00111111, 0b11111111, + 0b11111111, 0b11110000, 0b00011111, 0b11111111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111000, 0b00000000, 0b00000000, 0b00011111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111110, 0b11100000, 0b00001110, 0b11111111, + 0b11111110, 0b11110000, 0b00011110, 0b11111111, + 0b11111000, 0b00111000, 0b00111000, 0b00111111, + 0b11110000, 0b00010011, 0b10010000, 0b00011111, + 0b11100000, 0b00000111, 0b11000000, 0b00001111, + 0b11100000, 0b00001111, 0b11100000, 0b00001111, + 0b00000000, 0b00001111, 0b11100000, 0b00000111, + 0b11100000, 0b00001111, 0b11100000, 0b00001111, + 0b11100000, 0b00000111, 0b11000000, 0b00001111, + 0b11110000, 0b00010011, 0b10010000, 0b00011111, + 0b11111000, 0b00111000, 0b00111000, 0b00111111, + 0b11111110, 0b11111110, 0b11110000, 0b00011111, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111100, 0b00000000, 0b00000000, 0b00000011, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111110, 0b11111110, 0b11100000, 0b00001111, + 0b11111110, 0b11111110, 0b11110000, 0b00011111, + 0b11111111, 0b11111110, 0b11111000, 0b00111111, + 0b11111111, 0b11111110, 0b11111110, 0b11111111, + 0b11111111, 0b11111110, 0b11111110, 0b11111111, + 0b11111111, 0b11111000, 0b00000000, 0b00000000, + 0b11111111, 0b11111110, 0b11111110, 0b11111111}; + + /* + DCD Device: + Offset Value Sample Value from HD20 + 0 0x83 + 1 0x00 + 2-5 Status + 6-7 Device type 0x0001 + 8-9 Device manufacturer 0x0001 + 10 Device characteristics bit field (see below) 0xE6 + 11-13 Number of blocks 0x009835 + 14-15 Number of spare blocks 0x0045 + 16-17 Number of bad blocks 0x0001 + 18-69 Manufacturer reserved + 70-197 Icon (see below) + 198-325 Icon mask (see below) + 326 Device location string length + 327-341 Device location string + 342 Checksum + + The device characteristics bit field is defined as follows: + Value Meaning + 0x80 Mountable + 0x40 Readable + 0x20 Writable + 0x10 Ejectable (see below) + 0x08 Write protected + 0x04 Icon included + 0x02 Disk in place (see below) + + The "ejectable" and "disk in place" bits are ostensibly intended to support removable media, however no mechanism for ejecting disks is known to exist in the protocol. +*/ + payload[7] = 1; + payload[9] = 1; + payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; // to do update using read/write indicator + payload[12] = 0xB0; // to do update using file size / 512 + memcpy(&payload[70], icon, sizeof(icon)); + // to do insert slot number bitmap into icon LL corner + memset(&payload[198],0xff,128); + payload[326] = 7; + strcpy((char*)&payload[327],"FujiNet Slot"); + payload[340] = get_disk_number(); +} void macFloppy::process(mac_cmd_t cmd) { @@ -211,9 +289,17 @@ void macFloppy::process(mac_cmd_t cmd) Debug_printf("\nDCD sector request: %06x", sector_num); if (_disk->read(sector_num, buffer)) Debug_printf("\nError Reading Sector %06x",sector_num); + // todo: error handling fnUartBUS.write(buffer, sizeof(buffer)); break; + case 'T': + memset(buffer,0,sizeof(buffer)); + dcd_status(buffer); + Debug_printf("\nSending STATUS block"); + fnUartBUS.write(&buffer[6], 336); // status info block is 336 char's without header and checksum + break; case 'W': + // code on PICO: // uart_putc_raw(UART_ID, 'W'); // uart_putc_raw(UART_ID, (sector >> 16) & 0xff); // uart_putc_raw(UART_ID, (sector >> 8) & 0xff); diff --git a/lib/device/mac/floppy.h b/lib/device/mac/floppy.h index 05dadda49..db8ab1788 100644 --- a/lib/device/mac/floppy.h +++ b/lib/device/mac/floppy.h @@ -46,6 +46,8 @@ class macFloppy : public macDevice int old_pos; int head_dir; + void dcd_status(uint8_t* buffer); + public: bool readonly; diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index 43c2c3b87..389e65b53 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -27,14 +27,14 @@ macFuji::macFuji() } -void macFuji::startup_hack() -{ - Debug_printf("\n Fuji startup hack"); - for (int i = 0; i < MAX_DISK_DEVICES; i++) - { - _fnDisks[i].disk_dev.set_disk_number(i); - } -} +// void macFuji::startup_hack() +// { +// Debug_printf("\n Fuji startup hack"); +// for (int i = 0; i < MAX_DISK_DEVICES; i++) +// { +// _fnDisks[i].disk_dev.set_disk_number(i); +// } +// } macFloppy *macFuji::bootdisk() { diff --git a/pico/mac/commands.c b/pico/mac/commands.c index ed3d1390f..2c8d1bfcc 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -79,6 +79,7 @@ uint32_t a; uint32_t b[12]; char c; uint32_t olda; +uint32_t active_disk_number; PIO pio_floppy = pio0; PIO pio_dcd = pio1; @@ -234,7 +235,7 @@ void preset_latch() void dcd_preset_latch() { - dcd_latch = 0b11001100; // DCD signature HHLx + no handshake HHxx + dcd_latch = 0b11011100; // DCD signature HHLx + no handshake HHxx } void set_tach_freq(char c) @@ -479,6 +480,13 @@ void dcd_loop() // need a state variable to track changes in the "command" phase settings // // + if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_MUX)) + { + active_disk_number = NUM_DCD + 'A' - pio_sm_get_blocking(pio_dcd, SM_DCD_MUX); + printf("%c", active_disk_number); + uart_putc_raw(UART_ID, active_disk_number); + } + if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_CMD)) { olda = a; @@ -504,7 +512,7 @@ void dcd_loop() case 2: host = false; // idle - // if (olda == 3) + // if (olda == 6) // { // dcd_assert_hshk(); // } @@ -522,9 +530,10 @@ void dcd_loop() break; case 4: host = false; - // reset dcd_deassert_hshk(); - pio_sm_exec(pio_dcd, SM_DCD_MUX, 0xe081); // set pindirs 1 + pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); + pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); + pio_sm_exec(pio_dcd, SM_DCD_MUX, 0xe080); // set pindirs 0 break; default: host = false; @@ -541,8 +550,8 @@ void dcd_loop() switch (c) { case 'h': // harddisk is mounted - c = uart_getc(UART_ID); - printf("\nHard Disk %d mounted", c); + c = uart_getc(UART_ID); // char starting with '0' + printf("\nHard Disk %c mounted", c); // c is now the drive slot (DCD unit) number // can add write protection info (or should move status packet generation to ESP32) break; @@ -800,41 +809,7 @@ OR void dcd_status(uint8_t ntx) { - // to do : move status packet generation to ESP32 - const uint8_t icon[] = {0b11111111, 0b11111110, 0b11111111, 0b11111111, - 0b11111111, 0b11111110, 0b11111111, 0b11111111, - 0b11111111, 0b11111110, 0b11111111, 0b11111111, - 0b11111111, 0b11111000, 0b00111111, 0b11111111, - 0b11111111, 0b11110000, 0b00011111, 0b11111111, - 0b11111110, 0b11100000, 0b00001110, 0b11111111, - 0b11111110, 0b11100000, 0b00001110, 0b11111111, - 0b11111000, 0b00000000, 0b00000000, 0b00011111, - 0b11111110, 0b11100000, 0b00001110, 0b11111111, - 0b11111110, 0b11100000, 0b00001110, 0b11111111, - 0b11111110, 0b11110000, 0b00011110, 0b11111111, - 0b11111000, 0b00111000, 0b00111000, 0b00111111, - 0b11110000, 0b00010011, 0b10010000, 0b00011111, - 0b11100000, 0b00000111, 0b11000000, 0b00001111, - 0b11100000, 0b00001111, 0b11100000, 0b00001111, - 0b00000000, 0b00001111, 0b11100000, 0b00000111, - 0b11100000, 0b00001111, 0b11100000, 0b00001111, - 0b11100000, 0b00000111, 0b11000000, 0b00001111, - 0b11110000, 0b00010011, 0b10010000, 0b00011111, - 0b11111000, 0b00111000, 0b00111000, 0b00111111, - 0b11111110, 0b11111110, 0b11110000, 0b00011111, - 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111100, 0b00000000, 0b00000000, 0b00000011, - 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111110, 0b11111110, 0b11110000, 0b00011111, - 0b11111111, 0b11111110, 0b11111000, 0b00111111, - 0b11111111, 0b11111110, 0b11111110, 0b11111111, - 0b11111111, 0b11111110, 0b11111110, 0b11111111, - 0b11111111, 0b11111000, 0b00000000, 0b00000000, - 0b11111111, 0b11111110, 0b11111110, 0b11111111}; - - /* + /* DCD Device: Offset Value Sample Value from HD20 0 0x83 @@ -853,41 +828,30 @@ void dcd_status(uint8_t ntx) 327-341 Device location string 342 Checksum - The device characteristics bit field is defined as follows: - Value Meaning - 0x80 Mountable - 0x40 Readable - 0x20 Writable - 0x10 Ejectable (see below) - 0x08 Write protected - 0x04 Icon included - 0x02 Disk in place (see below) - */ printf("status\n"); // memcpy(payload,s,sizeof(s)); memset(payload, 0, sizeof(payload)); payload[0] = 0x83; - payload[7] = 1; - payload[9] = 1; - // payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; - payload[10] = 0x80 | 0x40 | 0x08 | 0x04 | 0x02; // 0xe6; - payload[12] = 0xB0; - memcpy(&payload[70], icon, sizeof(icon)); - memset(&payload[198],0xff,128); - payload[326] = 7; - payload[327] = 'F'; - payload[328] = 'u'; - payload[329] = 'j'; - payload[330] = 'i'; - payload[331] = 'N'; - payload[332] = 'e'; - payload[333] = 't'; + // to do receive 336 bytes into payload[6] + + // clear out UART buffer cause there was a residual byte + while (uart_is_readable(UART_ID)) + uart_getc(UART_ID); + + uart_putc_raw(UART_ID, 'T'); + + uart_read_blocking(UART_ID, &payload[6], 336); + + for (int x = 0; x < 16; x++) + { + printf("%02x ", payload[6 + x]); + } + printf("\n"); + compute_checksum(342); send_packet(ntx); - // simulate_packet(ntx); - // assert(false); } void dcd_id(uint8_t ntx) diff --git a/pico/mac/dcd_mux.pio b/pico/mac/dcd_mux.pio index 11f462a81..3ab208d83 100644 --- a/pico/mac/dcd_mux.pio +++ b/pico/mac/dcd_mux.pio @@ -8,6 +8,7 @@ .define public LSTRB 12 .define public ENABLE 7 +.define public NUM_DCD 2 ; The DCD mux will really control the RD line direction. ; It will ... @@ -19,10 +20,12 @@ .side_set 1 opt pindirs ; initial state is RD is hi-z and we have 2 DCDs ; we wait to be enabled then RD goes to output -start: .wrap_target - set x, 0 side 0 - wait 0 gpio ENABLE +start: + set x, NUM_DCD side 0 ; put the number of DCD devices in X + wait 0 gpio ENABLE ; don't do anything until we're enabled + in x, 32 ; say we are at the first DCD + jmp x-- cont ; decrement X to wait for the next strobe cont: ; now we need to wait to be strobed or to be disabled jmp pin start side 1 ; disabled so go back to the beginning! @@ -30,6 +33,7 @@ cont: out y, 1 ; stick it in Y jmp !Y cont ; not strobing loop wait 0 gpio LSTRB + in x, 32 ; push X to the FIFO to tell the program a certain drive is selected jmp x-- cont wait 1 gpio ENABLE side 0 .wrap @@ -46,8 +50,9 @@ void dcd_mux_program_init(PIO pio, uint sm, uint offset, uint set_pin) { sm_config_set_in_pins(&c, LSTRB); sm_config_set_jmp_pin(&c, ENABLE); // there are 4 wires to read for latch mux, shift to the right, no autopull - // sm_config_set_set_pins(&c, set_pin, 1); + sm_config_set_set_pins(&c, set_pin, 1); sm_config_set_out_shift(&c, true, false, 1); + sm_config_set_in_shift(&c, true, true, 32); pio_gpio_init(pio, set_pin); pio_sm_set_consecutive_pindirs(pio, sm, set_pin, 1, false); // initialize From 14ae2db45370161b1a84796b9d924d3de8e3547e Mon Sep 17 00:00:00 2001 From: mozzwald Date: Mon, 9 Oct 2023 18:35:01 -0500 Subject: [PATCH 087/158] appleii: cpm: webui: implement disable cpm option --- data/webui/config/fujiapple-rev0.yaml | 1 + lib/bus/iwm/iwm.cpp | 42 +++++++++++++++++++++++++-- lib/bus/iwm/iwm.h | 17 ++++++----- lib/device/iwm/cpm.cpp | 14 +++++++-- lib/device/iwm/cpm.h | 6 ++-- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/data/webui/config/fujiapple-rev0.yaml b/data/webui/config/fujiapple-rev0.yaml index 987a2da84..7d6287b5d 100644 --- a/data/webui/config/fujiapple-rev0.yaml +++ b/data/webui/config/fujiapple-rev0.yaml @@ -16,3 +16,4 @@ components: disk_swap: true boot_settings: true apetime: false + cpm_settings: true diff --git a/lib/bus/iwm/iwm.cpp b/lib/bus/iwm/iwm.cpp index 4740f679a..777bcc248 100644 --- a/lib/bus/iwm/iwm.cpp +++ b/lib/bus/iwm/iwm.cpp @@ -322,7 +322,8 @@ void iwmDevice::send_reply_packet(uint8_t status) void iwmDevice::iwm_return_badcmd(iwm_decoded_cmd_t cmd) { //Handle possible data packet to avoid crash extended and non-extended - switch(cmd.command) { + switch(cmd.command) + { case 0x42: case 0x44: case 0x49: @@ -351,11 +352,48 @@ void iwmDevice::iwm_return_badcmd(iwm_decoded_cmd_t cmd) uint8_t control_code = get_status_code(cmd); Debug_printf("\r\nbad command was a control command with control code %02x",control_code); } - else{ + else + { send_reply_packet(SP_ERR_BADCMD); //response for Any other command with a data packet } } +void iwmDevice::iwm_return_device_offline(iwm_decoded_cmd_t cmd) +{ + //Handle possible data packet to avoid crash extended and non-extended + switch(cmd.command) { + case 0x42: + case 0x44: + case 0x49: + case 0x4a: + case 0x4b: + case 0x02: + case 0x04: + case 0x09: + case 0x0a: + case 0x0b: + data_len = 512; + IWM.iwm_decode_data_packet((uint8_t *)data_buffer, data_len); + Debug_printf("\r\nUnit %02x Offline, Command with data packet %02x\r\n", id(), cmd.command); + print_packet((uint8_t *)data_buffer, data_len); + break; + default: //just send the response and return like before + send_reply_packet(SP_ERR_OFFLINE); + Debug_printf("\r\nUnit %02x Offline, Command %02x", id(), cmd.command); + return; + } + if(cmd.command == 0x04) //Decode command control code + { + send_reply_packet(SP_ERR_OFFLINE); + uint8_t control_code = get_status_code(cmd); + Debug_printf("\r\nOffline command was a control command with control code %02x",control_code); + } + else + { + send_reply_packet(SP_ERR_OFFLINE); //response for Any other command with a data packet + } +} + void iwmDevice::iwm_return_ioerror() { // Debug_printf("\r\nUnit %02x Bad Command %02x", id(), cmd.command); diff --git a/lib/bus/iwm/iwm.h b/lib/bus/iwm/iwm.h index 5e6b565af..176e372a0 100644 --- a/lib/bus/iwm/iwm.h +++ b/lib/bus/iwm/iwm.h @@ -48,7 +48,7 @@ #define SP_SUBTYPE_BYTE_REMOVABLE 0x00 #define SP_SUBTYPE_BYTE_HARDDISK 0x20 // fixed media #define SP_SUBTYPE_BYTE_SWITCHED 0x40 // removable and supports disk switched errors -#define SP_SUBTYPE_BYTE_HARDDISK_EXTENDED 0xA0 +#define SP_SUBTYPE_BYTE_HARDDISK_EXTENDED 0xA0 #define SP_SUBTYPE_BYTE_REMOVABLE_EXTENDED 0xC0 // removable and extended and supports disk switched errors #define SP_TYPE_BYTE_SCSI 0x03 @@ -252,7 +252,7 @@ friend iwmBus; // put here for prototype, not sure if will need to keep it virtual void send_extended_status_reply_packet() = 0; virtual void send_extended_status_dib_reply_packet() = 0; - + virtual void shutdown() = 0; virtual void process(iwm_decoded_cmd_t cmd) = 0; @@ -273,6 +273,7 @@ friend iwmBus; // put here for prototype, not sure if will need to keep it uint32_t get_address(iwm_decoded_cmd_t cmd) { return cmd.params[4] + (cmd.params[5] << 8) + (cmd.params[6] << 16); } void iwm_return_badcmd(iwm_decoded_cmd_t cmd); + void iwm_return_device_offline(iwm_decoded_cmd_t cmd); void iwm_return_ioerror(); void iwm_return_noerror(); @@ -284,7 +285,7 @@ friend iwmBus; // put here for prototype, not sure if will need to keep it bool device_active; uint8_t prevtype = SP_TYPE_BYTE_HARDDISK; //preserve previous device type when offline bool switched = false; //indicate disk switched condition - bool readonly = true; //write protected + bool readonly = true; //write protected bool is_config_device; /** * @brief get the IWM device Number (1-255) @@ -295,7 +296,7 @@ friend iwmBus; // put here for prototype, not sure if will need to keep it //void assign_id(uint8_t n) { _devnum = n; }; void assign_name(std::string name) {dib.device_name = name;} - + /** * @brief Get the iwmBus object that this iwmDevice is attached to. */ @@ -344,18 +345,18 @@ class iwmBus iwm_decoded_cmd_t command; - void handle_init(); + void handle_init(); int old_track = -1; int new_track = -1; public: std::forward_list _daisyChain; - + cmdPacket_t command_packet; bool iwm_decode_data_packet(uint8_t *a, int &n); int iwm_send_packet(uint8_t source, iwm_packet_type_t packet_type, uint8_t status, const uint8_t* data, uint16_t num); - + // these things stay for the most part void setup(); void service(); @@ -374,7 +375,7 @@ class iwmBus bool shuttingDown = false; // TRUE if we are in shutdown process bool getShuttingDown() { return shuttingDown; }; bool en35Host = false; // TRUE if we are connected to a host that supports the /EN35 signal - + }; extern iwmBus IWM; diff --git a/lib/device/iwm/cpm.cpp b/lib/device/iwm/cpm.cpp index 5366acf73..8a2897a17 100644 --- a/lib/device/iwm/cpm.cpp +++ b/lib/device/iwm/cpm.cpp @@ -9,6 +9,7 @@ #include "fuji.h" #include "fnFS.h" #include "fnFsSD.h" +#include "fnConfig.h" #include "../hardware/led.h" @@ -116,7 +117,7 @@ void iwmCPM::sio_status() void iwmCPM::iwm_open(iwm_decoded_cmd_t cmd) { uint8_t err_result = SP_ERR_NOERROR; - + Debug_printf("\r\nCP/M: Open\n"); if (!fnSystem.spifix()) { @@ -197,8 +198,8 @@ void iwmCPM::iwm_read(iwm_decoded_cmd_t cmd) { if (mw < numbytes) //if there are less than requested, just send what we have { - numbytes = mw; - } + numbytes = mw; + } data_len = 0; for (int i = 0; i < numbytes; i++) @@ -287,6 +288,13 @@ void iwmCPM::iwm_ctrl(iwm_decoded_cmd_t cmd) void iwmCPM::process(iwm_decoded_cmd_t cmd) { + // Respond with device offline if cp/m is disabled + if ( !Config.get_cpm_enabled() ) + { + iwm_return_device_offline(cmd); + return; + } + switch (cmd.command) { case 0x00: // status diff --git a/lib/device/iwm/cpm.h b/lib/device/iwm/cpm.h index 184aaaa25..8511b3f50 100644 --- a/lib/device/iwm/cpm.h +++ b/lib/device/iwm/cpm.h @@ -15,7 +15,7 @@ class iwmCPM : public iwmDevice { private: - TaskHandle_t cpmTaskHandle = NULL; + TaskHandle_t cpmTaskHandle = NULL; void boot(); @@ -36,11 +36,11 @@ class iwmCPM : public iwmDevice void send_extended_status_reply_packet() override{}; void send_status_dib_reply_packet() override; void send_extended_status_dib_reply_packet() override{}; - bool cpmActive = false; + bool cpmActive = false; void init_cpm(int baud); virtual void sio_status(); void sio_handle_cpm(); - + }; #endif /* IWMCPM_H */ \ No newline at end of file From 83b495c339384274e7c0e275e639f09288231fa1 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Mon, 9 Oct 2023 21:27:47 -0400 Subject: [PATCH 088/158] Disk number on icon and location; readonly. --- lib/device/mac/floppy.cpp | 56 ++++++++++++++++++++++++++++++++------- lib/device/mac/fuji.cpp | 6 ++++- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 419154809..eae3b8c1e 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -222,16 +222,50 @@ void macFloppy::dcd_status(uint8_t* payload) 0b11111110, 0b11111110, 0b11110000, 0b00011111, 0b11111110, 0b11111110, 0b11100000, 0b00001111, 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111100, 0b00000000, 0b00000000, 0b00000011, - 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111110, 0b11111110, 0b11100000, 0b00001111, - 0b11111110, 0b11111110, 0b11110000, 0b00011111, + 0b11111110, 0b00000000, 0b00000000, 0b00000011, + 0b11111111, 0b11111110, 0b11100000, 0b00001111, + 0b11111111, 0b11111110, 0b11100000, 0b00001111, + 0b11111111, 0b11111110, 0b11110000, 0b00011111, 0b11111111, 0b11111110, 0b11111000, 0b00111111, 0b11111111, 0b11111110, 0b11111110, 0b11111111, 0b11111111, 0b11111110, 0b11111110, 0b11111111, 0b11111111, 0b11111000, 0b00000000, 0b00000000, 0b11111111, 0b11111110, 0b11111110, 0b11111111}; + const uint8_t numset[4][8] = { + {0b00011000, + 0b01111000, + 0b00011000, + 0b00011000, + 0b00011000, + 0b00011000, + 0b01111110}, + + {0b01111110, + 0b11000011, + 0b00000110, + 0b00001100, + 0b00110000, + 0b01100000, + 0b11111111}, + + {0b01111110, + 0b11000011, + 0b00000011, + 0b00111100, + 0b00000011, + 0b11000011, + 0b01111110}, + + {0b00011110, + 0b00110110, + 0b01100110, + 0b11111111, + 0b00000110, + 0b00000110, + 0b00000110} + }; + /* DCD Device: Offset Value Sample Value from HD20 @@ -266,13 +300,17 @@ void macFloppy::dcd_status(uint8_t* payload) payload[7] = 1; payload[9] = 1; payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; // to do update using read/write indicator + if (readonly) {payload[10] |= 0x08;}; payload[12] = 0xB0; // to do update using file size / 512 memcpy(&payload[70], icon, sizeof(icon)); - // to do insert slot number bitmap into icon LL corner - memset(&payload[198],0xff,128); - payload[326] = 7; - strcpy((char*)&payload[327],"FujiNet Slot"); - payload[340] = get_disk_number(); + for (int i = 0 ; i < 7 ; i++) + { + payload[70+96+4*i]=~numset[get_disk_number()-'0'][i]; + } + memset(&payload[198], 0xff, 128); + payload[326] = 10; // seems to be limited to 12 chars + strcpy((char*)&payload[327],"FujiNet_D"); + payload[336] = get_disk_number()+1; } void macFloppy::process(mac_cmd_t cmd) diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index 389e65b53..363ccead3 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -207,7 +207,11 @@ bool macFuji::mount_all() // And now mount it disk.disk_type = disk.disk_dev.mount(disk.fileh, disk.filename, disk.disk_size); - if(disk.access_mode == DISK_ACCESS_MODE_WRITE) {disk.disk_dev.readonly = false;} + disk.disk_dev.readonly = true; + if (disk.access_mode == DISK_ACCESS_MODE_WRITE) + { + disk.disk_dev.readonly = false; + } } } From 0f17c66317f11b141fa6d16d969bb7e2ea9cd6ae Mon Sep 17 00:00:00 2001 From: mozzwald Date: Mon, 9 Oct 2023 21:24:25 -0500 Subject: [PATCH 089/158] apple2: update autorun.po --- .../device_specific/BUILD_APPLE/autorun.po | Bin 143360 -> 143360 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_APPLE/autorun.po b/data/webui/device_specific/BUILD_APPLE/autorun.po index bb586580db774ec5668d316db1b2c68e1879b9ed..992c36b54f3dd1989a7e477354d4a41dcd5a8ceb 100644 GIT binary patch delta 16932 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 From fe0975fdd44f8e1c3b8d358d8f6cf8af9c04272a Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Tue, 10 Oct 2023 21:53:55 -0400 Subject: [PATCH 090/158] mac: fix my font --- lib/device/mac/floppy.cpp | 40 ++++++++++++++++++--------------------- pico/mac/commands.c | 3 +-- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index eae3b8c1e..363fab425 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -232,38 +232,34 @@ void macFloppy::dcd_status(uint8_t* payload) 0b11111111, 0b11111000, 0b00000000, 0b00000000, 0b11111111, 0b11111110, 0b11111110, 0b11111111}; - const uint8_t numset[4][8] = { + const uint8_t numset[4][6] = { {0b00011000, - 0b01111000, - 0b00011000, + 0b00111000, 0b00011000, 0b00011000, 0b00011000, 0b01111110}, - {0b01111110, - 0b11000011, - 0b00000110, + {0b00111100, + 0b01100110, 0b00001100, + 0b00011000, 0b00110000, - 0b01100000, - 0b11111111}, - - {0b01111110, - 0b11000011, - 0b00000011, - 0b00111100, - 0b00000011, - 0b11000011, 0b01111110}, - {0b00011110, - 0b00110110, + {0b01111110, + 0b00001100, + 0b00011000, + 0b00001100, 0b01100110, - 0b11111111, - 0b00000110, - 0b00000110, - 0b00000110} + 0b00111100}, + + {0b00001100, + 0b00011100, + 0b00111100, + 0b01101100, + 0b01111110, + 0b00001100} }; /* @@ -303,7 +299,7 @@ void macFloppy::dcd_status(uint8_t* payload) if (readonly) {payload[10] |= 0x08;}; payload[12] = 0xB0; // to do update using file size / 512 memcpy(&payload[70], icon, sizeof(icon)); - for (int i = 0 ; i < 7 ; i++) + for (int i = 0 ; i < 6 ; i++) { payload[70+96+4*i]=~numset[get_disk_number()-'0'][i]; } diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 2c8d1bfcc..59eb979dc 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -833,8 +833,7 @@ void dcd_status(uint8_t ntx) // memcpy(payload,s,sizeof(s)); memset(payload, 0, sizeof(payload)); payload[0] = 0x83; - // to do receive 336 bytes into payload[6] - + // clear out UART buffer cause there was a residual byte while (uart_is_readable(UART_ID)) uart_getc(UART_ID); From 9d2e1000fad90d11460939871c41dad913f6240c Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Tue, 10 Oct 2023 22:02:58 -0400 Subject: [PATCH 091/158] mac: report disk size in DCD status response --- lib/device/mac/floppy.cpp | 10 ++++++++-- lib/device/mac/floppy.h | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 363fab425..70ba68562 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -24,6 +24,8 @@ mediatype_t macFloppy::mount(FILE *f, const char *filename, uint32_t disksize, m if (disk_type == MEDIATYPE_UNKNOWN) disk_type = MediaType::discover_mediatype(filename); + _disk_size_in_blocks = disksize/512; + switch (disk_type) { case MEDIATYPE_MOOF: @@ -295,9 +297,13 @@ void macFloppy::dcd_status(uint8_t* payload) */ payload[7] = 1; payload[9] = 1; - payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // 0xe6; // to do update using read/write indicator + payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // real HD20 says 0xe6; if (readonly) {payload[10] |= 0x08;}; - payload[12] = 0xB0; // to do update using file size / 512 + + payload[11] = (_disk_size_in_blocks >> 16) & 0xff; + payload[12] = (_disk_size_in_blocks >> 8) & 0xff; + payload[13] = _disk_size_in_blocks & 0xff; + memcpy(&payload[70], icon, sizeof(icon)); for (int i = 0 ; i < 6 ; i++) { diff --git a/lib/device/mac/floppy.h b/lib/device/mac/floppy.h index db8ab1788..b3b2daa14 100644 --- a/lib/device/mac/floppy.h +++ b/lib/device/mac/floppy.h @@ -46,6 +46,8 @@ class macFloppy : public macDevice int old_pos; int head_dir; + uint32_t _disk_size_in_blocks; + void dcd_status(uint8_t* buffer); public: From d181beddfd7fbaa1fddbe4c3c91767426a31a92a Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 10:01:56 -0500 Subject: [PATCH 092/158] [adamnet] remove flush_input from service loop. --- lib/bus/adamnet/adamnet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 4aeb52106..467d8b6b8 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -287,7 +287,6 @@ void systemBus::_adamnet_process_cmd() fnLedManager.set(eLed::LED_BUS, false); } - fnUartBUS.flush_input(); wait_for_idle(); // to avoid failing edge case where device is connected but disabled. } From c04f174eb5b982b36bc4b6507ab667d72c13f1d8 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 12:50:20 -0500 Subject: [PATCH 093/158] [adamnet] slight refinement of timings. --- lib/bus/adamnet/adamnet.cpp | 18 ++++++++++-------- lib/device/adamnet/disk.cpp | 20 +++++++++----------- lib/device/adamnet/disk.h | 1 + 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 467d8b6b8..622b88260 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -168,11 +168,12 @@ void virtualDevice::adamnet_response_ack(bool doNotWaitForIdle) { AdamNet.wait_for_idle(); } - - if (t < 300) + else { - adamnet_send(0x90 | _devnum); + esp_rom_delay_us(IDLE_TIME); } + + adamnet_send(0x90 | _devnum); } void virtualDevice::adamnet_response_nack(bool doNotWaitForIdle) @@ -183,16 +184,17 @@ void virtualDevice::adamnet_response_nack(bool doNotWaitForIdle) { AdamNet.wait_for_idle(); } - - if (t < 300) + else { - adamnet_send(0xC0 | _devnum); + esp_rom_delay_us(IDLE_TIME); } + + adamnet_send(0xC0 | _devnum); } void virtualDevice::adamnet_control_ready() { - adamnet_response_ack(); + adamnet_response_ack(true); } void systemBus::wait_for_idle() @@ -270,7 +272,6 @@ void systemBus::_adamnet_process_cmd() uint8_t b; b = fnUartBUS.read(); - start_time = esp_timer_get_time(); uint8_t d = b & 0x0F; @@ -282,6 +283,7 @@ void systemBus::_adamnet_process_cmd() { // turn on AdamNet Indicator LED fnLedManager.set(eLed::LED_BUS, true); + start_time = esp_timer_get_time(); _daisyChain[d]->adamnet_process(b); // turn off AdamNet Indicator LED fnLedManager.set(eLed::LED_BUS, false); diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index b40429f13..ae2096b5a 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -116,12 +116,7 @@ bool adamDisk::write_blank(FILE *fileh, uint32_t numBlocks) void adamDisk::adamnet_control_clr() { - int64_t t = esp_timer_get_time() - AdamNet.start_time; - - if (t < 1500) - { - adamnet_response_send(); - } + adamnet_response_send(); } void adamDisk::adamnet_control_receive() @@ -129,10 +124,14 @@ void adamDisk::adamnet_control_receive() if (_media == nullptr) return; - if (_media->read(blockNum, nullptr)) - adamnet_response_nack(); + if (blockNumRead != blockNum) + { + _media->read(blockNum,nullptr); + blockNumRead = blockNum; + return; + } else - adamnet_response_ack(); + adamnet_response_ack(true); } void adamDisk::adamnet_control_send_block_num() @@ -167,8 +166,7 @@ void adamDisk::adamnet_control_send_block_data() return; adamnet_recv_buffer(_media->_media_blockbuff, 1024); - AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); + adamnet_response_ack(true); Debug_printf("Block Data Write\n"); _media->write(blockNum, false); diff --git a/lib/device/adamnet/disk.h b/lib/device/adamnet/disk.h index c9c9a007d..5426fc032 100755 --- a/lib/device/adamnet/disk.h +++ b/lib/device/adamnet/disk.h @@ -17,6 +17,7 @@ class adamDisk : public virtualDevice TaskHandle_t diskTask; unsigned long blockNum=INVALID_SECTOR_VALUE; + unsigned long blockNumRead=INVALID_SECTOR_VALUE; void adamnet_control_clr(); void adamnet_control_receive(); From c5922ce0066c801f7cec69957cc9808b93b0dad0 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 16:41:59 -0500 Subject: [PATCH 094/158] [adam][dsk] remove stupid format. --- lib/media/adam/mediaTypeDSK.cpp | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/media/adam/mediaTypeDSK.cpp b/lib/media/adam/mediaTypeDSK.cpp index 85202fa0b..626b2a22a 100644 --- a/lib/media/adam/mediaTypeDSK.cpp +++ b/lib/media/adam/mediaTypeDSK.cpp @@ -135,14 +135,14 @@ bool MediaTypeDSK::format(uint16_t *responsesize) { for (uint32_t b = 0; b < _media_num_blocks; b++) { - if (b<13) - { - memset(_media_blockbuff,0x00,1024); - } - else - { - memset(_media_blockbuff,0xE5,1024); - } + // if (b<13) + // { + // memset(_media_blockbuff,0x00,1024); + // } + // else + // { + memset(_media_blockbuff,0xE5,1024); + // } write(b, 0); } return false; @@ -169,16 +169,16 @@ bool MediaTypeDSK::create(FILE *f, uint32_t numBlocks) for (uint32_t b = 0; b < numBlocks; b++) { - if (b<13) - { - memset(buf,0x00,1024); - } - else - { - memset(buf,0xE5,1024); - } - } + // if (b<13) + // { + // memset(buf,0x00,1024); + // } + // else + // { + memset(buf,0xE5,1024); fwrite(buf, 1024, 1, f); + // } + } return true; } From fab19876f9217585ecab3319210a93579b06ee80 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 16:42:20 -0500 Subject: [PATCH 095/158] [adam] more timing foo. --- lib/device/adamnet/disk.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index ae2096b5a..0edcf660b 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -1,6 +1,7 @@ #ifdef BUILD_ADAM #include "disk.h" +#include "led.h" #include #include @@ -153,9 +154,9 @@ void adamDisk::adamnet_control_send_block_num() _media->format(NULL); } - AdamNet.start_time=esp_timer_get_time(); - - adamnet_response_ack(); + esp_rom_delay_us(120); + + adamnet_response_ack(true); Debug_printf("BLOCK: %lu\n", blockNum); } @@ -166,6 +167,7 @@ void adamDisk::adamnet_control_send_block_data() return; adamnet_recv_buffer(_media->_media_blockbuff, 1024); + esp_rom_delay_us(160); adamnet_response_ack(true); Debug_printf("Block Data Write\n"); From ee8eda82a264e692ef49771a508df6621c27e09f Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 16:42:37 -0500 Subject: [PATCH 096/158] [adam] still more timing foo. --- lib/bus/adamnet/adamnet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 622b88260..17b11b38e 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -170,7 +170,7 @@ void virtualDevice::adamnet_response_ack(bool doNotWaitForIdle) } else { - esp_rom_delay_us(IDLE_TIME); + esp_rom_delay_us(160); } adamnet_send(0x90 | _devnum); From a3b7d18c4b13bd24dc160eb5d4f35603cd9b2791 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 16:43:04 -0500 Subject: [PATCH 097/158] [adam][config] init build eos dir fixing. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index f9f9c40030dee88178e3295dc74c8635009994c6..2589af2168e68e8da7d973ed93ff48e58d2a2aa4 100644 GIT binary patch literal 262144 zcmeIb3w%`7x%a{E9b?*#dNFaoSOA;j{kN}a8ge2TVFoJco3ZWuGkc2@A za;&wnueP4k{#%aq6xyC6ctNyQWf)_b(A^SjJjQlfrktVWjA@Aqf|tqv_pH75%p`#I z{NHmv=e+O#8O*+{%d?*KUC(;fW$zic<~4p^YD(-NBRmcY5yX6 zHZ?b?R-rZ2Yxhsqx`iWr_I$8te`{hv{BPgL`*ExKM5{JxNualIb3x%&AdjPLWiE^8I~sX)s-2xCZBKek?}`{ z`grY_e*wDTg_)|hN_CEIRIwk>b(_V|LDY6(m~;=ICtK5e|EW$G4Z z?4PfD+Y2uq>V6&vUyC!GeJng>*0Jovz80-^$-7R+#c*=2?X6tjTeEyy4#cXH>P2q&KiPAW)STsEm-$fSbgq=LlO#@y56l~aLPzD09Wg}8g| zpsrwVuPxa~-4&d4eE9LSg30EEQ@2vMXZw4%EzxdU((UsHJWa1D!?*ri8RltvRT;GP zXG-EM)gt_7JqH?H{ zBeiVqZhx||dwciyT-^_JfA`kzZQcLy-Y=|Zfmw4E%$d0{s%lFW-_;{p;FK=R8F+WabHp51;3Vvo$4>}!6Zar^TwpQp3EIc@m% zG+(pTw%uxbz-rrO^#uX}-?pDeHCbIhYTFB$cJ;&%?O$w;57qV|-hZ)KHuWW0&h{l0 zeBS)lu-t^Oy}))sIL8%O#JF7R1u^b~FY95~L=jZupi9_t^iQ^|ujAhPzAft!oIBIM zk|T=MU9O;dUIerDAZXI0NkMJZGLOg8Kc^a}=bRWfAg7tDGd-w|iwa2hgJW;(b2#8?K=CoB3+I24@92h~J0-Mw`(3j%O+zDE5AR3OJ@ z`I<-qub?)|X1Uk6tbkGKmnu2{`kQ*6af_PM?PlY4sD69Dep{S~8mkDq6rm-FsIQ?U z6I**fY`*q(BqS*ZrO07CkFH#jr z+68OsyL}<8)^;)_QB_1?{pwL&<8|Don7wrOoO)PAIZEfP$(+Cy;^@krBYvd1Ld9%G~^u5`J!|VKU)KGr zd_Fz?XuF;6^fajc9k5qf?PN)UO!tSk1l9ewnAC3wAcfbKB&~&-hFT7mgUjZ>xZl}z zvW=q9ueH0Z>JZ7ZGhJ`L7a$1DBimCQB<&0(;jo5!sGqeo*xJnE99X+qMDdKQV$$&bn-Z(lSe|4Hb*f!depVZs=qp* z>fx(Zeb33NWWDNo6^Y$ju~kltsWN%TNf-jOm+djye~^?f{Z2pCqrS-=@lEhnq;iR& zGC4IkMY0C%?IaHf26Gb7k7Ymy2=%j6uZQ%6-@QWXB@7A#??G#e03T78Wq_tTNM+y~bo$PePgZP*;pLaN&_oqW&Ag&+Fm0 z>7$8;QE06(&KRT6I^)(Dg>E;7odgj!mq|%n6I8QwDdrH18W}^ZIj)++tWhI#m^H>#bC^x(Kg`;xz6iUdQW;bA zGPXoD-P&K%rv934Gj5GC9x!f=GPdit#nCdT#b)YdG{?4>xPE{?Q$?oX%S;caJLc~V zg*9ENYd?JQ0~v*mMsrwr$l@f!OXk!>{EBq2G4Ylf>HwIg<{UKAc-w};N0}2fnzCb> zJb0KodyRM4FtrklR^jifsDs(-lQ3#x(k3mJhWNPHA)97d(%Yf?%UQH4GA^5&!An2| zRSb)yG0Qg@LNqKyIk@ioz6Y2MUtno3F2u9%c!?9v<3SPNN~&C$Li>rglyt3%85I~ude zk;A9=4={&k>1q2-*}f-@-Ovrua(?gAo=u)8ZfFiP(u4u+h>;Vs2`HmazdS{U*Td>w zON|<0Gki7_%!cl(aiJE-nK^2hM^1pfX(X6u%&x!Zdrjb>UcVe3&`K{DVN>Glsyt3ErR z5L4xdY7uo_`qC*s{L(2i8YB;MEN(ZZy)on4+y>Kh)#`?zdLRA<+825F{uT%y-#-8z zxPJhAaQ}d`0Rd6Bj6UcIst=&x-Ox72=A=CrOc6rIZ#X{s_!#}z6)cX^C!ro%0S9U6 zmLQTkwfkvPL@reaH~6SAUL*Y7*}`3UvV2Cuk= zsvrY~UZXzM;7yeQ5qsI!(BIZ!l2~7izkF6D{X)zP4AUU2O3Y^02E}8p8fUKlePr5@ zQ#^Q=>x)EL24n1k&ytel{=j8|$P-43jV6ql$5I>3hyPd_)8Eews29>)dDlTzZ|hIs z>M0lNDb0R>ejL=Y7I~z@?LT5d=j4d9zW+9p5;aB6ATvUaC|6r2Q_8_I|Y>cvK0 zvE|8=w>z+UE9!NHhjgrQgh$~ZH<2)Fl1XSEHK@9qg4$hku+P}qG*J|}n+{0u6j`Xm#LrD+YIx^G4aUHqo;rNb%^l(B)NqRW3 zV_|yO-cgetPVQKd4spfPbg{*G#yQ_OPdCmpjPp$6Jj*y280X#kIqL&m^M}&qRVeF2 zQtU?S$%oR_i>{XGDC$7oMOW5ES8>XdCtuWWC=Y48kMul{?tL-6crS^=`DvVsK5*rI z=qmcim3Q7HtJ|FSu}ep-jdvJRkBK7nHWAVuwVkw%q}6TeHo0J%gIm~BVX)=QAJ76= z{+dhQG-Fa`Gn}lC#wiRF`a~uXSuk#3ZBAk7a$LavNJ|LQhQi%xEUDaL}jOyW0ro~7zI{HJ>Q3~`vJc@$sM+c80MPUQmr2aEV z<_zR2oPkF$eTs#yF&FJTkOsYjstR*^z5-i)k;|CSE2-n%HWCPn$58<&@tqwwQ;8w$ z^HP=NYF96NI+Z%)*ELEuOhk*T6pb#1 zK9rBAP0{viMt^#3RCrfM$Ea{?$FE0)cX#||RCsU4A4Y|r?)cLv?_WpB5n+0v2PIUCxGuS8PlI^n3@D;+{uo<6x^9It zg|1<&Jdj88M3j`$e|K4s%r~&vr*&v!Kof_2I!vcSQb!N*`h<8Tjs-7eZ1~$9Q^o>X z-dI3eIM%ynY(Hp`(y_5LVWw<&lqMg`$Wo>86wIWJXeeN)ie0EJax?4iXXz3B8Ig&_ zRxBzS24>30i-wx!MnjCg5RjS-2ePn{-Z9L%eFT-e=l z>o_pGcN~~KJ`T*jGcNo@hj(1~TOGb}0QdelfO9C}XFAH1@Q*rb74NM|)<3Tgq9UE? z8UMT<+G8)`iD~5Qw9&Tg?T3!e8i#(KkKKULwp5$I2H4Sxac~d_foH_=K;Gf?FdQ-; zc@NSM)SP!aZRpzQV(;tYV2<9$#=-0;I)RQ@BJMkSXk4)cIs2&;FJ+sC zrk9aKIbu_3$8yYeE6UiJ_gD)i6i7l1wC|{u>Ik1}Rmj3g<(Jm0Zh;YBu63d(l0IA+f1v=t2N}w47VB?bYUcKccu0_>jO%w*rDvkn*-j56yPAI zMZN|P)i5iDSi|W!of=@vw(BA>y4f@Lwl+yhHTM z7bnp;L%v+*vkL0O^3p<=QdGVVpmtZLwo=zeWTqvXN-#`DA4{<`7%-M%XMLuqUp?H? zXX`l_kZYpILr)ON>5ke`$Fiw zg)Q>=n2wO-LyCu_|9OBEDP8?O`cO#y)P?PMQ^xIbEn~Tj0%#G0N9O8UD67|et^Np@ zBz`bJqBg-6g48Zct_9en>K|P#iO`d%ePJqp^_>M+T7R+VtDpnIM z^lbIlGS8a3EYl)+^7TAaa3s$(nTJ~IcA-6GQ>Rg81KKygdKomcs$_bys%X>CP!i0p z&@czmF+lft8vSt^j22`DTM8pHO3)9fcBx9t#HA3MISDcl19kJhj(?jF2x7|9IU(Q- zdf%jD$cT?*B3TFCPBu&o&B4Nq?JHThK$GjkhfYcd$%Q#N+$L}n&}7C>tf26gTOU00eCMK?-!&(Be&I~ zZMV^SD5MU#T*CxNO4M;9H8eEfJbh0DcaWA&5f#ZSh*l)PtY<7Q!`%Mqo~zW;%oAgD zMwWg5fh^khX6rlh2~~we{q_Om(;%{K?5siAao<2}Ej#O3>dt-di)J-|1Jx zBTdl2o2Gu9&VNc%AEonWQX@IN)K!R)LQO?w|Jq9B{=M~N(j;o|nF-FB!dpAZjGjYt z35w3tqiy}818i#JL+Ske{@ukp4!aWb@iNPlHYt$5^0dAdP|bN@i^J0YRgo<;8tjLk;9G3NWUmz~XF+tFO(-n$@Md)J8JQ5%P zWmC$_)|x?@=WENZh2GLOpSb)Qooli#HnnHIFoG^?`PY@bJ=k;y?!oRTbND9 zugara9=}6JpZ1hf%a4~(v}dpPXd^Ox5DHO+lZBWw*&@m(Tg9TuHnC)KoLD|NUaX#+ zAl6Mz6n9Owi^j=GBtBuXHZ+@#tEbcP`XW01sDO@t&7))eY&!l_rg>;GU1!OZpHPTT z`!JhogHmym`dG92&6bE2Jl2c{k!ZP}*1|S)ipJ&RZW)SIeb!?wvMuFHD9C*IQeV$F z^Ezr)nL6^C#zO2p$z__3nBcy$o)%n~73NHl!f1td3OyL_kbTV^RIBl)$XhLMBI%8# zVd~D{SdlPHfAtLMadXPNfg_rlM!68E$Utq)K?1vCG_Xbm(sNL}_zjPOj;H-D1){t|2Z}x~ML(S*?f%*IU@rB2 zb9YLXBp0^4`CJNh5DA8QHDPhn>g@_RkoUAkb(C`eH~PC#iRfk!5tS8(ox#TFIvVMw z_wU-NdU9K!c1U_TT`!EH0>n>r2-|%GWNhVjyR?d}xaUCFm+|9QP-m`EaXi!~m-=hEA?i0|#YJYE|itxtP=EY;fFe9-My z3epXa+6GM%)ap|`S&i=0IJuuOE?0YgEYM) z!L3{0l_2`Sh-UyGpy(!KJXk~^62iedBgCnX)ju?#70~CkUyb(^C(?!=ZSD1IBUBBx zKqbmiRo~;ff~pZ)AVo09NLvn}_rPAswM4qN$xPCs(UeSNDh$U{E2l%mB9I+y2~VA+ zSmwM}G!3)v`qkKaZrnk3?+JE!8>V$4u!~-wXnyC^_Uq=1`@Q>Q%QTXNXI7o*=x?j0 zp?T1{{Yyh}?N_xX9c9#pQIgT24DAANAHSald+`Ll=cmb+H^SLR&rL&P%MheS@6DSS zfSK)}mZiBe{FGbwQ^opfPrFlT?v$4p?DF&U&epB&lx<2qN!rcbX|h+z>phAmLzzov}Eha^?BNfG%Z;*qOy=;)${A=+Y{7z9vvW9`-Gk&z+cQ#Y0$)2e)PbA zB-6cV14YJ>ZxEIljcyv$_3k%uI=UjpVl7{YxAQF`kZ%=#%Et;VKTdp> zpCGK$MyM< zo34F7BSYEgojaXsrR*fyBZ6{IKyTM~ot^qVfVsH>Jy+O0*bX2sj%Pd5XonqvFVlOO z`gX3RI$(+A8Op=)gH z?ki_{^2)*gqzBVmJrF`l&hYM z1hu1sWVe9>_?})}nT?iykvUCt@RT|JiX296lqaRgJhXm{7?- z$b{rmwIPGx<>@7kPbSe#)_o62l}~5|qciS%$eT9PXTF>I)E9h81K=}Ih)nQ)-A;;-#&S`5HIsK=Owo4bNr4%^@Q|B z9xW%{XsbUIUZJf*QYHBaduS2j^?A5H7N8P5aBfL1_g z(Z`DDSp^5!PKak?s)VH-*Y2s)Qky^Hh#D{1JwPBF>%7wil&bjC&H%T=`ZtCPVDzI z?y!ub{oKnVXId{0451vjG$f97L{td;lSk{iM$4lG>AD+DA4S7IbxzHCt&V@L)1ytk z)`*VkNjs;S1N(N+Qx3-7%Gol5tO4e2Uo<_Zc11djf~kG-#S7X<6DV14HRRT@P>V@T zBNO|}YwgtE6f`n-UJXu2{n>gQgf823NBsf8Sm28G9i2a$da1G&)6tjLQ_W-*yH$am zsctz_vbR!aiPtx3?5*f556u?h?`B)XH)mVLle2B&=Gn5d+&o*`T;#>^NqKCzfv&gE z(Pt5&ovN+oeiqbr<6DO4hw>pM-UgL>VjtCJn;Ws1E{D_+a(n`mkc!tqQ60F}5WW82 zv$tn2=Eb-{R=Tm+Z0(Ys`kEF>+p%MDv_tA7U<-5+0Gp=OmmzN?HJs{VQ?a{i?hoj95^E;eVbo)c{u zlM{BQmzg;iJ}a8DUzscPoVtENO)nD^^_*+xf^alvzcSr=PUH1eBPY%8WIdmni`9BG zXTLJ{%bfHotC0(asOS3CTzIZ%u72g6&~woj2X!sMF=tB*1z+mV*Q-C@Xc2hwPQbCH zFlwIq^Yy{8BNKA4}EisfYYE8q%hR^hQHo)AEyqnuIQgifT>4+>zQ|!vJG^DzLXJa!gVTGe zOdtDnLnbGHD_WQsU5`X+|5$DefoOL)3>xOrF<-$V;bfC6LB24n1Jhra?Nsb!0klISnGefslFa%C6!GDv57OJ|xKzP+c*sTR`%!RB}DCm)@! zQc|cu&dt;+9hK6b?ZVM`)8+@9!Okv9gmAfBcz8a&?7HS!5eQP{DD1sq^C^GJ88==a z#uK@%mnWHXGB!}Y_X`p9xD|5KgWBRcIr+fNB+M7Q!{&SPy}vKlzlAIJ7Vz6JlV!+Ft?E%3QrW7GkResA>aS%;O{+RqhSavIH_DKDGuN_Kb%6|7VdlEIRox~- zZfR9BWv(@?>NjLaL#vu6L)NycPs@Uu{)a$dG%?TpL=|)iPwG zS^B-L>N**6pIQ3-t?HdJWUCpntyS%nA=}MdEv@QB8R9lW9&A;ACqs4_xuRokjX4WZ zU!0HKo+UJOz~(B=Jfn$LMiS9HFER0q1;!AW>*(ec%zC61KQn^A-K{|_y8_)MvT;Nn zg@38YYk;QKmo_Hxkm=ieUO~3QqL3Aen!tnGHTp51}u>Aw{y8f`&QV$D8*= z0A^**v*o-3^NjxU>17cx7_;fS8M3R=>%_HuQ~mj zh5tUwU3g$liIvQu{ta>dJK~G2?b=#fz~>KYnK$_Z1qto=>JDyYu3)=1X%RLy0(hne z<%SO*c_sxvb~N&g^@!8CPp+BaPn>wAE^~a?nmMKGy!Ob-+~K{Q;Y1~=XtyhE_<=M> z0+jT1_98#NHR?LPd*r^%50Ag)_-ob+%OuPv6uPJbbKMkDi@5soP&=_0PBImGy5(@ZXU*yE`+@UuE~tPx7xx_AeXM)$R{` z9tie!`|Q2`(}y#Qy6xu!I)QHc?96Qc*R1}HHUrS+1pj@Bvoo*lMhd(CzNF8CxJdTj zH>leV#CEtB{SDP+J&V58sy^Dtn{{c`TLZ9QcRj^F>w ze_ft(i9!|(6+QF5)w-=+`{Q!Y;G!L_SCkDyMV#ZVu@=fV*5Y_`MyAbquP^Jd)@?zE z@u?rLZE+r-muYEn?mHIl%e?Mq%7~V{M_X@|KS`AFSnC7(w#~`>4gE%u;~ntZ_Ks5B zJo}Y*i@wqNjpk6%0P_*m@~1Z_P(Run5*`J&#Jm5-2Od?f_6 zoyWO%wsLWnkHofRT5|`w>tU!h34b>@)W2mNOqew?)c%$9Be^i2J`jx5e?7 zthUzehmL4_D>K?!eYn9}H$8O}*71D|vqEe?^rm$Q%o{cX&oZgdA8fbmu4%X6CkkP3 zUD?^$cn(89n&I)Fb^J)@FH{erhw9d&oAv?!mOlTM@NEBhCS;!1b}sfG|Lmpkw#*UXI~6+u?^Fgm z?BRQq1cW1JP~E()x@BMHuve5sC%!NlXqU~>6KHb09EAM^{nNvW%|E@bIzhDitCIcm z2en%sSlsU4VE5mVbQV9j)fw=?4JE{@PcDAlsid_$R~=|^I{q@nl5JJ&&Xn9ZXUd-f z{;z%JpZTfq&-_G$vlRS_#^##PX~)oTZo%+yQSPv=Y^|&|O`#oyBB+!FA9Pzhmn zse&vKPabUQPu9^ZW+DHEi~c(<;WY?bAlDM|Xo)qQlp(6GseBN!@6Wv6e>`Enk{Xik z2*3LkY-kKMc||n^WM|LMZh^%#G&9b^Lz8HVj>RGn2JbqIe3b>&Puu zAa0HFVR1IjRZ0lQJ2FT5TRsjaXAVDKoQp)g;S|MQyw$(^bKD#_k9o+3k0*-yTeQzC z-Ob^?^WEE@f8mhw=iZJbHE-pHiwff3x?WG~cz=}f=^8%#?zN8LP#sGD``v5NpXDbQ z3O4P_9D2M3D#cs=KdPklRr{+h;Oo2oH6LFqJpN!;Q2Ri@-n6z_j2nH`!0X?90Zr=< z1}q2rlHlw=@!#?3_CuMeaQL5DJ%QYK^eBf7(>>IGe)})WYdrLOWXb3swo#6chAP_+ z9cypGohRENh7z)6nePwHb^Q5S;a_tBMJz5e8w?U7`b@vD#S`#RlYlE~ZXNCe5d0)s zpq;)j8Zi4hdQ*0GYF}ShdkA_I1}$&uT|YEGyQ*F9`f~r|QV5-&e#K6Xi2A6|bTD(& zAj7@OF$})|XWfMN^mOl!445SboASQZ`as_QYV~yn@U;FZ8=X)m{920*Z}$eW9UruJ zwK!kO92{)P-r%AE(&_kXrw6Kbwc`g06YSbNdh`1DHTdDWmz4N>vp4PYIa5BIYHUA8#T6>4;Kdm3F^6O``bsmD`rxUReBtMb3v?w;D* z`0n)Xo}1^S1R~MF?#}k^z{=&mQQnN&ro)+|4k4eI6j&dhoO1TC zPn%JTRO2UP4jOSyX2Rm_2`P@aP;-JEicUgNxt8>lj}QB{{qyGn$GW?H{_Xxl z9V2VCHI|cuYY&`n*PdVE(dsR;&TBI)N-r$5cZ;*&(`?zy-e1*HYkN=E!g-z!dHZla z?Hy4k1D$nUA?r$?l8B2Tz`@HR!<{1!XAXWn z^W&C4CxQcxKf#lSe7%9rb>}gS+Pq48X{C2{9WG#P#qPZQt@xVF{?=mg+cz-H@?$QF zxlT($B0gu%HDZ!;X4s*;zOAmJ=UdP3%S@)}*|0p(bjW2%6z!GmTK=-$-rjx6;G({* zS%+Kkut|HZ4wAv@S9O8jw_iVx?uTf1^kS--~}=JYg$HQ(vN#1@y-H?v-CHTT=} z_wi`nd?)Q6V7ebt58OdNrx@-#_NsD$`u*AS+KctQs^<>v^?KB2Y@+r=J>*zK9Of9W z)p;LZ9$b!kYhhk);=Vj=eb)d-H1RR`i@RJCIq= z_X+~$(7!X|5VmIYu`wtCSB{VLiv6psm}ojP%&3|JyHCZXs2Xak3Po={R8vph(?7Yk ze<_|y>h0W)Je~tthgwln5XpL>70rEMtnKaBZ&W@VqgXhbZTlk5T?g86nmp5(uJJxfJs|E2=QoR@{dZe(&UodKvFH02QDT8J*M$ zw{p(k;&iU@K2cBa7X`Ck!RoHUrvD-smR&~UOGB5F`YPd{Z-Gtgb25m4>9&(8ok_&h z&J)C(@4aQIcDcDgFBr_SbY+T(KDSTd^GV3(2lI^6l4$%dQzszrpIi!-jS=mpZguizGwFo>hlh{lTmU zT_a#Nm;|p_p0&$Gfg|uiCy_x&=hNJ}c%^MYB4bcsB-s@J)qosoXpG&R1-l7PpBx;Z$=9MI9R`(k(+;fOUte=y-XJmYE) zroI7tuxKqS0{H2OzI6RIq^(#^_ey$9{DA23o)pi71C-aWf^Vz{{Py)U15(6&>CS6g z&#DJq*BsxGnb5Opm+SZ&v<{dwDZL#luLX%es79$>#ddqk@rF$6u$O+EHr#2St(-f) zBGWc%b{c-n_AT-7!w=tDEZobxEU+OcN4lY6xI;a$c)CTqWy#_)^s8b80bSZHD?7Jg zfr0CuMLS#x0_a|7tzVr)3!L+q(W6AvSs2Gt?YDaw6kL zt?ioc<^{!;Oj}~g=P!9bxmku|-z+BhN0%xSvQm!7QU(@qL>3^W z`L?ZcuPR?$Q@>JF&z~<8WqEn!yz0f}N`1BBoWJy@imLK@vAA?zkuo7SZ$;774#=p~ zEvl%&xo%!*RaHgR0%d-6t%BUkt7{k4<>cgu37dqnu%fK2yeb)~>MF{FQd>@`uUx8% zR1-EwBtYEKsxr!1URge`UMV$Wa*(~es=geBl|t|8`9>jTd^B3uMX4#RtAkP`tF)?2 zseux8%BtG(`lYp1tC4zMbyXEgpeg`@Q3FzDlbDd7w@H*$)Gbo#Dy!@3#Dv=?Ov#_N zNi3|ctB(euo=V-q>gCBKYJSB6(x9xOo^(ep+|8|)C$mhmN+bn|R!y5yu-Xix928bx zI(N0Qpqey_DPJkS37QI}x@sy~FB!257F3p_gxK^^K>Z)?I__W+j6E-DFJe09W580eE z!T2v(RMZp+AYNQrx2Q;zRn-|ua`U#5tzGeuEbURuB@-$V^Q)GX*A|Hys16&L1ASJO z*Tvo{Rn z%jT8VmKkd0AYpmVf*d7lUgJGqS=X3_Ld(jaH5m@BAxc>cgDfpVLZf(juhg%sL8~d# z@(PeHZ^ld<^Ye0XoVT>DzIriYX5y}3T45f-l)8$W%je)+1H-8+H~JuIUQt_KX5^4* zk`<+*N~v19crN-Vy63b-%G}E8d5h}sx^Vx@rBs7*vJ~VYBdcFnQ76@&iV74VxuhYT z3lgGv%>2tsE9!HEgjiNyUs_R#zFDwI$;*WiZJrW2kQ3WXhNT~1N%a-dERlA?J)4z9 z$%1Nyl0Y2}qPnV*T2;SMme*F)qjRBuP9M-eBRyGfHPjdVRPVZan$p#(P10go?lL9JIH^n#`da@_U!P5Er)pI%tt>;Iu2*DNi7H2E zqmk6DV`?p`&>rv?O6f8fN9kNRNz=_&S1EN%=gq?)Fn?*KY6dIwk*>VVyhTS=D&d~R z(hYZSXxy?v`O3ZbHr|_~)PCi@dzR4B`aF_f+=f z(_xVqU)gt)$gk|X*V4R5YoulgZ@l~6juiARJs&Qx4#=})B600_BteX4D;(I1l ziQ8+cHm|ALx~{5mY1N83Rde&IMCOLg_uMln(mo1(gd%EcYGhbV%|-l!!`ZrbW9B(U z966Svlsx4SC42Xl>~Fgh?WD+bN{QR;E7KDP&F z#49BwB}l)A{-g6&d&()24khSBXQhNnDN#~z3z<0LnsOq23e;0@-v9DJ_f`x8d-h!1 zvqzlUvxojeIO+wtxWVTf%6Ff0lV0-dmhn&R*(wl;Y?Hy>Rd?ABlJOysrGi%-a#KCfaEwDpNl#hx@&l9&r^4bl9HM`7cR`jeF5+mpgx%^ z^!wa}8*!hTsZdoBpSy5jfgOn`{X&pzKrrer2_R|7!kUc;r%(#V{|RG12;huRgv54n4U8($BJM2OhNBSVwicFkQW7HpK$UA}ay8!Sm&J=BT2(c9gv{g77 zN|cfY2lA5{zZ&E zxrNuoOE-L55@U44!f@2pI?dECu^S$S#ctebb<{DYfsyE#qDA{mN9Jhx7W9X1Oz z7_OIY!&iT7wtReYjgLsQ)2a%#vGE)}Vwl~YY_|^+=TcH?Qc~nS0_gt4i4*dE(4avv z_di*x|0AyE=QHuCdHG*<{_wv{^8X=%d;bs7^M8z*m&64j{!NHK{*TeM$ZE!e0@Pmg$^f|AeqGu!BN9MwUJD9612ZENibAds_$9^txA%Xn zz35}h$A!LNu$wCeyV&}0A3j*#jiv?eXj~N26U1U%?8w4r2QGS-EV=2Xf5SyaM#hK{ zSP6=6KJrLy?e)SQe(<>;Klfl**!y3`*=Tme!6@n$JjL2G*9#um`ty)rPt+%CcLP~R{~5XVj^%8IA3MO32in8caO zC7URr{3Tc~y0O$PaU+e~H&Gx^l$h5T8V?7OhPDzEJ^O0OTR@4dRR!Y2RXghe&-GIamZEfe;+Hi5I?NnRaDO_x% zDsPk_ZFlHGD&g)ZoG4$A90E0pWR ziG#9Gl-?#2Q`s^*g&Z_WKee|Fi8s0%Qm|bF2xu0pV`ZU~3j*~W2D*@2EV!t_hU*>~ zg)2&Yj`o$#fzJ_A;|M}ZN)!eAR0u(nmK*^nv^zK=N`5G@yF^}6$i_BVQ@5LRB&wpp zEzzZ<7*R-b5X9ny0+T>gNY5 z6$G|<8W8x2emvShK_}*7n{fPyxk~Pc@z>ToSW=SW82(^M?g+;NjvJsP3j56 z3_}>Dn>Y&Taz~6xZ+q~ajU{<$Z4Y*AjKitdLc1^n|HagiFPQ)nU;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 k6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e*_{||xx7X^YouK)l5 literal 262144 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 zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj mFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCh#9b;C}(lyN5;q From 54e6c35dcc6d7ce3d69dd62fe81003fa130b936c Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 17:20:09 -0500 Subject: [PATCH 098/158] [adam] fix formatting code. --- lib/device/adamnet/disk.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index 0edcf660b..cc2514e0e 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -101,10 +101,7 @@ bool adamDisk::write_blank(FILE *fileh, uint32_t numBlocks) for (uint32_t b = 0; b < numBlocks; b++) { - if (b<13) - memset(buf, 0x00, 256); - else - memset(buf, 0xE5, 256); + memset(buf, 0xE5, 256); fwrite(buf, 1, 256, fileh); fwrite(buf, 1, 256, fileh); From 4cc184db6d6286af6392d054edde070d19006106 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 17:42:44 -0500 Subject: [PATCH 099/158] [adam] new disk improvements. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes lib/device/adamnet/fuji.cpp | 18 +++++++++--------- lib/device/adamnet/fuji.h | 2 ++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 2589af2168e68e8da7d973ed93ff48e58d2a2aa4..410969ea8e94634c1edfd258305f961bf7869d09 100644 GIT binary patch literal 262144 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 zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N yfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l3H`x literal 262144 zcmeIb3w%`7x%a{E9b?*#dNFaoSOA;j{kN}a8ge2TVFoJco3ZWuGkc2@A za;&wnueP4k{#%aq6xyC6ctNyQWf)_b(A^SjJjQlfrktVWjA@Aqf|tqv_pH75%p`#I z{NHmv=e+O#8O*+{%d?*KUC(;fW$zic<~4p^YD(-NBRmcY5yX6 zHZ?b?R-rZ2Yxhsqx`iWr_I$8te`{hv{BPgL`*ExKM5{JxNualIb3x%&AdjPLWiE^8I~sX)s-2xCZBKek?}`{ z`grY_e*wDTg_)|hN_CEIRIwk>b(_V|LDY6(m~;=ICtK5e|EW$G4Z z?4PfD+Y2uq>V6&vUyC!GeJng>*0Jovz80-^$-7R+#c*=2?X6tjTeEyy4#cXH>P2q&KiPAW)STsEm-$fSbgq=LlO#@y56l~aLPzD09Wg}8g| zpsrwVuPxa~-4&d4eE9LSg30EEQ@2vMXZw4%EzxdU((UsHJWa1D!?*ri8RltvRT;GP zXG-EM)gt_7JqH?H{ zBeiVqZhx||dwciyT-^_JfA`kzZQcLy-Y=|Zfmw4E%$d0{s%lFW-_;{p;FK=R8F+WabHp51;3Vvo$4>}!6Zar^TwpQp3EIc@m% zG+(pTw%uxbz-rrO^#uX}-?pDeHCbIhYTFB$cJ;&%?O$w;57qV|-hZ)KHuWW0&h{l0 zeBS)lu-t^Oy}))sIL8%O#JF7R1u^b~FY95~L=jZupi9_t^iQ^|ujAhPzAft!oIBIM zk|T=MU9O;dUIerDAZXI0NkMJZGLOg8Kc^a}=bRWfAg7tDGd-w|iwa2hgJW;(b2#8?K=CoB3+I24@92h~J0-Mw`(3j%O+zDE5AR3OJ@ z`I<-qub?)|X1Uk6tbkGKmnu2{`kQ*6af_PM?PlY4sD69Dep{S~8mkDq6rm-FsIQ?U z6I**fY`*q(BqS*ZrO07CkFH#jr z+68OsyL}<8)^;)_QB_1?{pwL&<8|Don7wrOoO)PAIZEfP$(+Cy;^@krBYvd1Ld9%G~^u5`J!|VKU)KGr zd_Fz?XuF;6^fajc9k5qf?PN)UO!tSk1l9ewnAC3wAcfbKB&~&-hFT7mgUjZ>xZl}z zvW=q9ueH0Z>JZ7ZGhJ`L7a$1DBimCQB<&0(;jo5!sGqeo*xJnE99X+qMDdKQV$$&bn-Z(lSe|4Hb*f!depVZs=qp* z>fx(Zeb33NWWDNo6^Y$ju~kltsWN%TNf-jOm+djye~^?f{Z2pCqrS-=@lEhnq;iR& zGC4IkMY0C%?IaHf26Gb7k7Ymy2=%j6uZQ%6-@QWXB@7A#??G#e03T78Wq_tTNM+y~bo$PePgZP*;pLaN&_oqW&Ag&+Fm0 z>7$8;QE06(&KRT6I^)(Dg>E;7odgj!mq|%n6I8QwDdrH18W}^ZIj)++tWhI#m^H>#bC^x(Kg`;xz6iUdQW;bA zGPXoD-P&K%rv934Gj5GC9x!f=GPdit#nCdT#b)YdG{?4>xPE{?Q$?oX%S;caJLc~V zg*9ENYd?JQ0~v*mMsrwr$l@f!OXk!>{EBq2G4Ylf>HwIg<{UKAc-w};N0}2fnzCb> zJb0KodyRM4FtrklR^jifsDs(-lQ3#x(k3mJhWNPHA)97d(%Yf?%UQH4GA^5&!An2| zRSb)yG0Qg@LNqKyIk@ioz6Y2MUtno3F2u9%c!?9v<3SPNN~&C$Li>rglyt3%85I~ude zk;A9=4={&k>1q2-*}f-@-Ovrua(?gAo=u)8ZfFiP(u4u+h>;Vs2`HmazdS{U*Td>w zON|<0Gki7_%!cl(aiJE-nK^2hM^1pfX(X6u%&x!Zdrjb>UcVe3&`K{DVN>Glsyt3ErR z5L4xdY7uo_`qC*s{L(2i8YB;MEN(ZZy)on4+y>Kh)#`?zdLRA<+825F{uT%y-#-8z zxPJhAaQ}d`0Rd6Bj6UcIst=&x-Ox72=A=CrOc6rIZ#X{s_!#}z6)cX^C!ro%0S9U6 zmLQTkwfkvPL@reaH~6SAUL*Y7*}`3UvV2Cuk= zsvrY~UZXzM;7yeQ5qsI!(BIZ!l2~7izkF6D{X)zP4AUU2O3Y^02E}8p8fUKlePr5@ zQ#^Q=>x)EL24n1k&ytel{=j8|$P-43jV6ql$5I>3hyPd_)8Eews29>)dDlTzZ|hIs z>M0lNDb0R>ejL=Y7I~z@?LT5d=j4d9zW+9p5;aB6ATvUaC|6r2Q_8_I|Y>cvK0 zvE|8=w>z+UE9!NHhjgrQgh$~ZH<2)Fl1XSEHK@9qg4$hku+P}qG*J|}n+{0u6j`Xm#LrD+YIx^G4aUHqo;rNb%^l(B)NqRW3 zV_|yO-cgetPVQKd4spfPbg{*G#yQ_OPdCmpjPp$6Jj*y280X#kIqL&m^M}&qRVeF2 zQtU?S$%oR_i>{XGDC$7oMOW5ES8>XdCtuWWC=Y48kMul{?tL-6crS^=`DvVsK5*rI z=qmcim3Q7HtJ|FSu}ep-jdvJRkBK7nHWAVuwVkw%q}6TeHo0J%gIm~BVX)=QAJ76= z{+dhQG-Fa`Gn}lC#wiRF`a~uXSuk#3ZBAk7a$LavNJ|LQhQi%xEUDaL}jOyW0ro~7zI{HJ>Q3~`vJc@$sM+c80MPUQmr2aEV z<_zR2oPkF$eTs#yF&FJTkOsYjstR*^z5-i)k;|CSE2-n%HWCPn$58<&@tqwwQ;8w$ z^HP=NYF96NI+Z%)*ELEuOhk*T6pb#1 zK9rBAP0{viMt^#3RCrfM$Ea{?$FE0)cX#||RCsU4A4Y|r?)cLv?_WpB5n+0v2PIUCxGuS8PlI^n3@D;+{uo<6x^9It zg|1<&Jdj88M3j`$e|K4s%r~&vr*&v!Kof_2I!vcSQb!N*`h<8Tjs-7eZ1~$9Q^o>X z-dI3eIM%ynY(Hp`(y_5LVWw<&lqMg`$Wo>86wIWJXeeN)ie0EJax?4iXXz3B8Ig&_ zRxBzS24>30i-wx!MnjCg5RjS-2ePn{-Z9L%eFT-e=l z>o_pGcN~~KJ`T*jGcNo@hj(1~TOGb}0QdelfO9C}XFAH1@Q*rb74NM|)<3Tgq9UE? z8UMT<+G8)`iD~5Qw9&Tg?T3!e8i#(KkKKULwp5$I2H4Sxac~d_foH_=K;Gf?FdQ-; zc@NSM)SP!aZRpzQV(;tYV2<9$#=-0;I)RQ@BJMkSXk4)cIs2&;FJ+sC zrk9aKIbu_3$8yYeE6UiJ_gD)i6i7l1wC|{u>Ik1}Rmj3g<(Jm0Zh;YBu63d(l0IA+f1v=t2N}w47VB?bYUcKccu0_>jO%w*rDvkn*-j56yPAI zMZN|P)i5iDSi|W!of=@vw(BA>y4f@Lwl+yhHTM z7bnp;L%v+*vkL0O^3p<=QdGVVpmtZLwo=zeWTqvXN-#`DA4{<`7%-M%XMLuqUp?H? zXX`l_kZYpILr)ON>5ke`$Fiw zg)Q>=n2wO-LyCu_|9OBEDP8?O`cO#y)P?PMQ^xIbEn~Tj0%#G0N9O8UD67|et^Np@ zBz`bJqBg-6g48Zct_9en>K|P#iO`d%ePJqp^_>M+T7R+VtDpnIM z^lbIlGS8a3EYl)+^7TAaa3s$(nTJ~IcA-6GQ>Rg81KKygdKomcs$_bys%X>CP!i0p z&@czmF+lft8vSt^j22`DTM8pHO3)9fcBx9t#HA3MISDcl19kJhj(?jF2x7|9IU(Q- zdf%jD$cT?*B3TFCPBu&o&B4Nq?JHThK$GjkhfYcd$%Q#N+$L}n&}7C>tf26gTOU00eCMK?-!&(Be&I~ zZMV^SD5MU#T*CxNO4M;9H8eEfJbh0DcaWA&5f#ZSh*l)PtY<7Q!`%Mqo~zW;%oAgD zMwWg5fh^khX6rlh2~~we{q_Om(;%{K?5siAao<2}Ej#O3>dt-di)J-|1Jx zBTdl2o2Gu9&VNc%AEonWQX@IN)K!R)LQO?w|Jq9B{=M~N(j;o|nF-FB!dpAZjGjYt z35w3tqiy}818i#JL+Ske{@ukp4!aWb@iNPlHYt$5^0dAdP|bN@i^J0YRgo<;8tjLk;9G3NWUmz~XF+tFO(-n$@Md)J8JQ5%P zWmC$_)|x?@=WENZh2GLOpSb)Qooli#HnnHIFoG^?`PY@bJ=k;y?!oRTbND9 zugara9=}6JpZ1hf%a4~(v}dpPXd^Ox5DHO+lZBWw*&@m(Tg9TuHnC)KoLD|NUaX#+ zAl6Mz6n9Owi^j=GBtBuXHZ+@#tEbcP`XW01sDO@t&7))eY&!l_rg>;GU1!OZpHPTT z`!JhogHmym`dG92&6bE2Jl2c{k!ZP}*1|S)ipJ&RZW)SIeb!?wvMuFHD9C*IQeV$F z^Ezr)nL6^C#zO2p$z__3nBcy$o)%n~73NHl!f1td3OyL_kbTV^RIBl)$XhLMBI%8# zVd~D{SdlPHfAtLMadXPNfg_rlM!68E$Utq)K?1vCG_Xbm(sNL}_zjPOj;H-D1){t|2Z}x~ML(S*?f%*IU@rB2 zb9YLXBp0^4`CJNh5DA8QHDPhn>g@_RkoUAkb(C`eH~PC#iRfk!5tS8(ox#TFIvVMw z_wU-NdU9K!c1U_TT`!EH0>n>r2-|%GWNhVjyR?d}xaUCFm+|9QP-m`EaXi!~m-=hEA?i0|#YJYE|itxtP=EY;fFe9-My z3epXa+6GM%)ap|`S&i=0IJuuOE?0YgEYM) z!L3{0l_2`Sh-UyGpy(!KJXk~^62iedBgCnX)ju?#70~CkUyb(^C(?!=ZSD1IBUBBx zKqbmiRo~;ff~pZ)AVo09NLvn}_rPAswM4qN$xPCs(UeSNDh$U{E2l%mB9I+y2~VA+ zSmwM}G!3)v`qkKaZrnk3?+JE!8>V$4u!~-wXnyC^_Uq=1`@Q>Q%QTXNXI7o*=x?j0 zp?T1{{Yyh}?N_xX9c9#pQIgT24DAANAHSald+`Ll=cmb+H^SLR&rL&P%MheS@6DSS zfSK)}mZiBe{FGbwQ^opfPrFlT?v$4p?DF&U&epB&lx<2qN!rcbX|h+z>phAmLzzov}Eha^?BNfG%Z;*qOy=;)${A=+Y{7z9vvW9`-Gk&z+cQ#Y0$)2e)PbA zB-6cV14YJ>ZxEIljcyv$_3k%uI=UjpVl7{YxAQF`kZ%=#%Et;VKTdp> zpCGK$MyM< zo34F7BSYEgojaXsrR*fyBZ6{IKyTM~ot^qVfVsH>Jy+O0*bX2sj%Pd5XonqvFVlOO z`gX3RI$(+A8Op=)gH z?ki_{^2)*gqzBVmJrF`l&hYM z1hu1sWVe9>_?})}nT?iykvUCt@RT|JiX296lqaRgJhXm{7?- z$b{rmwIPGx<>@7kPbSe#)_o62l}~5|qciS%$eT9PXTF>I)E9h81K=}Ih)nQ)-A;;-#&S`5HIsK=Owo4bNr4%^@Q|B z9xW%{XsbUIUZJf*QYHBaduS2j^?A5H7N8P5aBfL1_g z(Z`DDSp^5!PKak?s)VH-*Y2s)Qky^Hh#D{1JwPBF>%7wil&bjC&H%T=`ZtCPVDzI z?y!ub{oKnVXId{0451vjG$f97L{td;lSk{iM$4lG>AD+DA4S7IbxzHCt&V@L)1ytk z)`*VkNjs;S1N(N+Qx3-7%Gol5tO4e2Uo<_Zc11djf~kG-#S7X<6DV14HRRT@P>V@T zBNO|}YwgtE6f`n-UJXu2{n>gQgf823NBsf8Sm28G9i2a$da1G&)6tjLQ_W-*yH$am zsctz_vbR!aiPtx3?5*f556u?h?`B)XH)mVLle2B&=Gn5d+&o*`T;#>^NqKCzfv&gE z(Pt5&ovN+oeiqbr<6DO4hw>pM-UgL>VjtCJn;Ws1E{D_+a(n`mkc!tqQ60F}5WW82 zv$tn2=Eb-{R=Tm+Z0(Ys`kEF>+p%MDv_tA7U<-5+0Gp=OmmzN?HJs{VQ?a{i?hoj95^E;eVbo)c{u zlM{BQmzg;iJ}a8DUzscPoVtENO)nD^^_*+xf^alvzcSr=PUH1eBPY%8WIdmni`9BG zXTLJ{%bfHotC0(asOS3CTzIZ%u72g6&~woj2X!sMF=tB*1z+mV*Q-C@Xc2hwPQbCH zFlwIq^Yy{8BNKA4}EisfYYE8q%hR^hQHo)AEyqnuIQgifT>4+>zQ|!vJG^DzLXJa!gVTGe zOdtDnLnbGHD_WQsU5`X+|5$DefoOL)3>xOrF<-$V;bfC6LB24n1Jhra?Nsb!0klISnGefslFa%C6!GDv57OJ|xKzP+c*sTR`%!RB}DCm)@! zQc|cu&dt;+9hK6b?ZVM`)8+@9!Okv9gmAfBcz8a&?7HS!5eQP{DD1sq^C^GJ88==a z#uK@%mnWHXGB!}Y_X`p9xD|5KgWBRcIr+fNB+M7Q!{&SPy}vKlzlAIJ7Vz6JlV!+Ft?E%3QrW7GkResA>aS%;O{+RqhSavIH_DKDGuN_Kb%6|7VdlEIRox~- zZfR9BWv(@?>NjLaL#vu6L)NycPs@Uu{)a$dG%?TpL=|)iPwG zS^B-L>N**6pIQ3-t?HdJWUCpntyS%nA=}MdEv@QB8R9lW9&A;ACqs4_xuRokjX4WZ zU!0HKo+UJOz~(B=Jfn$LMiS9HFER0q1;!AW>*(ec%zC61KQn^A-K{|_y8_)MvT;Nn zg@38YYk;QKmo_Hxkm=ieUO~3QqL3Aen!tnGHTp51}u>Aw{y8f`&QV$D8*= z0A^**v*o-3^NjxU>17cx7_;fS8M3R=>%_HuQ~mj zh5tUwU3g$liIvQu{ta>dJK~G2?b=#fz~>KYnK$_Z1qto=>JDyYu3)=1X%RLy0(hne z<%SO*c_sxvb~N&g^@!8CPp+BaPn>wAE^~a?nmMKGy!Ob-+~K{Q;Y1~=XtyhE_<=M> z0+jT1_98#NHR?LPd*r^%50Ag)_-ob+%OuPv6uPJbbKMkDi@5soP&=_0PBImGy5(@ZXU*yE`+@UuE~tPx7xx_AeXM)$R{` z9tie!`|Q2`(}y#Qy6xu!I)QHc?96Qc*R1}HHUrS+1pj@Bvoo*lMhd(CzNF8CxJdTj zH>leV#CEtB{SDP+J&V58sy^Dtn{{c`TLZ9QcRj^F>w ze_ft(i9!|(6+QF5)w-=+`{Q!Y;G!L_SCkDyMV#ZVu@=fV*5Y_`MyAbquP^Jd)@?zE z@u?rLZE+r-muYEn?mHIl%e?Mq%7~V{M_X@|KS`AFSnC7(w#~`>4gE%u;~ntZ_Ks5B zJo}Y*i@wqNjpk6%0P_*m@~1Z_P(Run5*`J&#Jm5-2Od?f_6 zoyWO%wsLWnkHofRT5|`w>tU!h34b>@)W2mNOqew?)c%$9Be^i2J`jx5e?7 zthUzehmL4_D>K?!eYn9}H$8O}*71D|vqEe?^rm$Q%o{cX&oZgdA8fbmu4%X6CkkP3 zUD?^$cn(89n&I)Fb^J)@FH{erhw9d&oAv?!mOlTM@NEBhCS;!1b}sfG|Lmpkw#*UXI~6+u?^Fgm z?BRQq1cW1JP~E()x@BMHuve5sC%!NlXqU~>6KHb09EAM^{nNvW%|E@bIzhDitCIcm z2en%sSlsU4VE5mVbQV9j)fw=?4JE{@PcDAlsid_$R~=|^I{q@nl5JJ&&Xn9ZXUd-f z{;z%JpZTfq&-_G$vlRS_#^##PX~)oTZo%+yQSPv=Y^|&|O`#oyBB+!FA9Pzhmn zse&vKPabUQPu9^ZW+DHEi~c(<;WY?bAlDM|Xo)qQlp(6GseBN!@6Wv6e>`Enk{Xik z2*3LkY-kKMc||n^WM|LMZh^%#G&9b^Lz8HVj>RGn2JbqIe3b>&Puu zAa0HFVR1IjRZ0lQJ2FT5TRsjaXAVDKoQp)g;S|MQyw$(^bKD#_k9o+3k0*-yTeQzC z-Ob^?^WEE@f8mhw=iZJbHE-pHiwff3x?WG~cz=}f=^8%#?zN8LP#sGD``v5NpXDbQ z3O4P_9D2M3D#cs=KdPklRr{+h;Oo2oH6LFqJpN!;Q2Ri@-n6z_j2nH`!0X?90Zr=< z1}q2rlHlw=@!#?3_CuMeaQL5DJ%QYK^eBf7(>>IGe)})WYdrLOWXb3swo#6chAP_+ z9cypGohRENh7z)6nePwHb^Q5S;a_tBMJz5e8w?U7`b@vD#S`#RlYlE~ZXNCe5d0)s zpq;)j8Zi4hdQ*0GYF}ShdkA_I1}$&uT|YEGyQ*F9`f~r|QV5-&e#K6Xi2A6|bTD(& zAj7@OF$})|XWfMN^mOl!445SboASQZ`as_QYV~yn@U;FZ8=X)m{920*Z}$eW9UruJ zwK!kO92{)P-r%AE(&_kXrw6Kbwc`g06YSbNdh`1DHTdDWmz4N>vp4PYIa5BIYHUA8#T6>4;Kdm3F^6O``bsmD`rxUReBtMb3v?w;D* z`0n)Xo}1^S1R~MF?#}k^z{=&mQQnN&ro)+|4k4eI6j&dhoO1TC zPn%JTRO2UP4jOSyX2Rm_2`P@aP;-JEicUgNxt8>lj}QB{{qyGn$GW?H{_Xxl z9V2VCHI|cuYY&`n*PdVE(dsR;&TBI)N-r$5cZ;*&(`?zy-e1*HYkN=E!g-z!dHZla z?Hy4k1D$nUA?r$?l8B2Tz`@HR!<{1!XAXWn z^W&C4CxQcxKf#lSe7%9rb>}gS+Pq48X{C2{9WG#P#qPZQt@xVF{?=mg+cz-H@?$QF zxlT($B0gu%HDZ!;X4s*;zOAmJ=UdP3%S@)}*|0p(bjW2%6z!GmTK=-$-rjx6;G({* zS%+Kkut|HZ4wAv@S9O8jw_iVx?uTf1^kS--~}=JYg$HQ(vN#1@y-H?v-CHTT=} z_wi`nd?)Q6V7ebt58OdNrx@-#_NsD$`u*AS+KctQs^<>v^?KB2Y@+r=J>*zK9Of9W z)p;LZ9$b!kYhhk);=Vj=eb)d-H1RR`i@RJCIq= z_X+~$(7!X|5VmIYu`wtCSB{VLiv6psm}ojP%&3|JyHCZXs2Xak3Po={R8vph(?7Yk ze<_|y>h0W)Je~tthgwln5XpL>70rEMtnKaBZ&W@VqgXhbZTlk5T?g86nmp5(uJJxfJs|E2=QoR@{dZe(&UodKvFH02QDT8J*M$ zw{p(k;&iU@K2cBa7X`Ck!RoHUrvD-smR&~UOGB5F`YPd{Z-Gtgb25m4>9&(8ok_&h z&J)C(@4aQIcDcDgFBr_SbY+T(KDSTd^GV3(2lI^6l4$%dQzszrpIi!-jS=mpZguizGwFo>hlh{lTmU zT_a#Nm;|p_p0&$Gfg|uiCy_x&=hNJ}c%^MYB4bcsB-s@J)qosoXpG&R1-l7PpBx;Z$=9MI9R`(k(+;fOUte=y-XJmYE) zroI7tuxKqS0{H2OzI6RIq^(#^_ey$9{DA23o)pi71C-aWf^Vz{{Py)U15(6&>CS6g z&#DJq*BsxGnb5Opm+SZ&v<{dwDZL#luLX%es79$>#ddqk@rF$6u$O+EHr#2St(-f) zBGWc%b{c-n_AT-7!w=tDEZobxEU+OcN4lY6xI;a$c)CTqWy#_)^s8b80bSZHD?7Jg zfr0CuMLS#x0_a|7tzVr)3!L+q(W6AvSs2Gt?YDaw6kL zt?ioc<^{!;Oj}~g=P!9bxmku|-z+BhN0%xSvQm!7QU(@qL>3^W z`L?ZcuPR?$Q@>JF&z~<8WqEn!yz0f}N`1BBoWJy@imLK@vAA?zkuo7SZ$;774#=p~ zEvl%&xo%!*RaHgR0%d-6t%BUkt7{k4<>cgu37dqnu%fK2yeb)~>MF{FQd>@`uUx8% zR1-EwBtYEKsxr!1URge`UMV$Wa*(~es=geBl|t|8`9>jTd^B3uMX4#RtAkP`tF)?2 zseux8%BtG(`lYp1tC4zMbyXEgpeg`@Q3FzDlbDd7w@H*$)Gbo#Dy!@3#Dv=?Ov#_N zNi3|ctB(euo=V-q>gCBKYJSB6(x9xOo^(ep+|8|)C$mhmN+bn|R!y5yu-Xix928bx zI(N0Qpqey_DPJkS37QI}x@sy~FB!257F3p_gxK^^K>Z)?I__W+j6E-DFJe09W580eE z!T2v(RMZp+AYNQrx2Q;zRn-|ua`U#5tzGeuEbURuB@-$V^Q)GX*A|Hys16&L1ASJO z*Tvo{Rn z%jT8VmKkd0AYpmVf*d7lUgJGqS=X3_Ld(jaH5m@BAxc>cgDfpVLZf(juhg%sL8~d# z@(PeHZ^ld<^Ye0XoVT>DzIriYX5y}3T45f-l)8$W%je)+1H-8+H~JuIUQt_KX5^4* zk`<+*N~v19crN-Vy63b-%G}E8d5h}sx^Vx@rBs7*vJ~VYBdcFnQ76@&iV74VxuhYT z3lgGv%>2tsE9!HEgjiNyUs_R#zFDwI$;*WiZJrW2kQ3WXhNT~1N%a-dERlA?J)4z9 z$%1Nyl0Y2}qPnV*T2;SMme*F)qjRBuP9M-eBRyGfHPjdVRPVZan$p#(P10go?lL9JIH^n#`da@_U!P5Er)pI%tt>;Iu2*DNi7H2E zqmk6DV`?p`&>rv?O6f8fN9kNRNz=_&S1EN%=gq?)Fn?*KY6dIwk*>VVyhTS=D&d~R z(hYZSXxy?v`O3ZbHr|_~)PCi@dzR4B`aF_f+=f z(_xVqU)gt)$gk|X*V4R5YoulgZ@l~6juiARJs&Qx4#=})B600_BteX4D;(I1l ziQ8+cHm|ALx~{5mY1N83Rde&IMCOLg_uMln(mo1(gd%EcYGhbV%|-l!!`ZrbW9B(U z966Svlsx4SC42Xl>~Fgh?WD+bN{QR;E7KDP&F z#49BwB}l)A{-g6&d&()24khSBXQhNnDN#~z3z<0LnsOq23e;0@-v9DJ_f`x8d-h!1 zvqzlUvxojeIO+wtxWVTf%6Ff0lV0-dmhn&R*(wl;Y?Hy>Rd?ABlJOysrGi%-a#KCfaEwDpNl#hx@&l9&r^4bl9HM`7cR`jeF5+mpgx%^ z^!wa}8*!hTsZdoBpSy5jfgOn`{X&pzKrrer2_R|7!kUc;r%(#V{|RG12;huRgv54n4U8($BJM2OhNBSVwicFkQW7HpK$UA}ay8!Sm&J=BT2(c9gv{g77 zN|cfY2lA5{zZ&E zxrNuoOE-L55@U44!f@2pI?dECu^S$S#ctebb<{DYfsyE#qDA{mN9Jhx7W9X1Oz z7_OIY!&iT7wtReYjgLsQ)2a%#vGE)}Vwl~YY_|^+=TcH?Qc~nS0_gt4i4*dE(4avv z_di*x|0AyE=QHuCdHG*<{_wv{^8X=%d;bs7^M8z*m&64j{!NHK{*TeM$ZE!e0@Pmg$^f|AeqGu!BN9MwUJD9612ZENibAds_$9^txA%Xn zz35}h$A!LNu$wCeyV&}0A3j*#jiv?eXj~N26U1U%?8w4r2QGS-EV=2Xf5SyaM#hK{ zSP6=6KJrLy?e)SQe(<>;Klfl**!y3`*=Tme!6@n$JjL2G*9#um`ty)rPt+%CcLP~R{~5XVj^%8IA3MO32in8caO zC7URr{3Tc~y0O$PaU+e~H&Gx^l$h5T8V?7OhPDzEJ^O0OTR@4dRR!Y2RXghe&-GIamZEfe;+Hi5I?NnRaDO_x% zDsPk_ZFlHGD&g)ZoG4$A90E0pWR ziG#9Gl-?#2Q`s^*g&Z_WKee|Fi8s0%Qm|bF2xu0pV`ZU~3j*~W2D*@2EV!t_hU*>~ zg)2&Yj`o$#fzJ_A;|M}ZN)!eAR0u(nmK*^nv^zK=N`5G@yF^}6$i_BVQ@5LRB&wpp zEzzZ<7*R-b5X9ny0+T>gNY5 z6$G|<8W8x2emvShK_}*7n{fPyxk~Pc@z>ToSW=SW82(^M?g+;NjvJsP3j56 z3_}>Dn>Y&Taz~6xZ+q~ajU{<$Z4Y*AjKitdLc1^n|HagiFPQ)nU;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 k6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e*_{||xx7X^YouK)l5 diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 79155f040..8bb602981 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -916,28 +916,28 @@ void adamFuji::adamnet_new_disk() adamnet_recv(); // CK - fujiDisk &disk = _fnDisks[ds]; - fujiHost &host = _fnHosts[hs]; - - if (host.file_exists((const char *)p)) + if (newImageStarted) { - AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); + adamnet_response_ack(true); + newImageStarted = false; return; } + + fujiDisk &disk = _fnDisks[ds]; + fujiHost &host = _fnHosts[hs]; + disk.host_slot = hs; disk.access_mode = DISK_ACCESS_MODE_WRITE; strlcpy(disk.filename, (const char *)p, 256); + newImageStarted = true; + disk.fileh = host.file_open(disk.filename, disk.filename, sizeof(disk.filename), "w"); Debug_printf("Creating file %s on host slot %u mounting in disk slot %u numblocks: %lu\n", disk.filename, hs, ds, numBlocks); disk.disk_dev.write_blank(disk.fileh, numBlocks); - AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); - fclose(disk.fileh); } diff --git a/lib/device/adamnet/fuji.h b/lib/device/adamnet/fuji.h index a65b29239..a410b70c2 100755 --- a/lib/device/adamnet/fuji.h +++ b/lib/device/adamnet/fuji.h @@ -80,6 +80,8 @@ class adamFuji : public virtualDevice appkey _current_appkey; + bool newImageStarted = false; + protected: void adamnet_reset_fujinet(); // 0xFF void adamnet_net_get_ssid(); // 0xFE From 6e7cdb39dd82e02630a2e18fd91ec69a511f2336 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:02:03 -0500 Subject: [PATCH 100/158] Revert "[adam] new disk improvements." This reverts commit 4cc184db6d6286af6392d054edde070d19006106. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes lib/device/adamnet/fuji.cpp | 18 +++++++++--------- lib/device/adamnet/fuji.h | 2 -- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 410969ea8e94634c1edfd258305f961bf7869d09..2589af2168e68e8da7d973ed93ff48e58d2a2aa4 100644 GIT binary patch literal 262144 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 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 k6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e*_{||xx7X^YouK)l5 literal 262144 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 zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N yfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l3H`x diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 8bb602981..79155f040 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -916,28 +916,28 @@ void adamFuji::adamnet_new_disk() adamnet_recv(); // CK - if (newImageStarted) + fujiDisk &disk = _fnDisks[ds]; + fujiHost &host = _fnHosts[hs]; + + if (host.file_exists((const char *)p)) { - adamnet_response_ack(true); - newImageStarted = false; + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); return; } - - fujiDisk &disk = _fnDisks[ds]; - fujiHost &host = _fnHosts[hs]; - disk.host_slot = hs; disk.access_mode = DISK_ACCESS_MODE_WRITE; strlcpy(disk.filename, (const char *)p, 256); - newImageStarted = true; - disk.fileh = host.file_open(disk.filename, disk.filename, sizeof(disk.filename), "w"); Debug_printf("Creating file %s on host slot %u mounting in disk slot %u numblocks: %lu\n", disk.filename, hs, ds, numBlocks); disk.disk_dev.write_blank(disk.fileh, numBlocks); + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); + fclose(disk.fileh); } diff --git a/lib/device/adamnet/fuji.h b/lib/device/adamnet/fuji.h index a410b70c2..a65b29239 100755 --- a/lib/device/adamnet/fuji.h +++ b/lib/device/adamnet/fuji.h @@ -80,8 +80,6 @@ class adamFuji : public virtualDevice appkey _current_appkey; - bool newImageStarted = false; - protected: void adamnet_reset_fujinet(); // 0xFF void adamnet_net_get_ssid(); // 0xFE From b0f16381e4a183972f421b240a9f1cbf3f47a066 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:03:36 -0500 Subject: [PATCH 101/158] Revert "[adam] fix formatting code." This reverts commit 54e6c35dcc6d7ce3d69dd62fe81003fa130b936c. --- lib/device/adamnet/disk.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index cc2514e0e..0edcf660b 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -101,7 +101,10 @@ bool adamDisk::write_blank(FILE *fileh, uint32_t numBlocks) for (uint32_t b = 0; b < numBlocks; b++) { - memset(buf, 0xE5, 256); + if (b<13) + memset(buf, 0x00, 256); + else + memset(buf, 0xE5, 256); fwrite(buf, 1, 256, fileh); fwrite(buf, 1, 256, fileh); From 7071f5793582860294aab88d791acb9fb239c9e8 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:03:48 -0500 Subject: [PATCH 102/158] Revert "[adam][config] init build eos dir fixing." This reverts commit a3b7d18c4b13bd24dc160eb5d4f35603cd9b2791. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 2589af2168e68e8da7d973ed93ff48e58d2a2aa4..f9f9c40030dee88178e3295dc74c8635009994c6 100644 GIT binary patch literal 262144 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 zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj mFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCh#9b;C}(lyN5;q literal 262144 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 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 z6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz28 k6JP>NfC(@GCcp%k025#WOn?b60Vco%m;e*_{||xx7X^YouK)l5 From 12fdac9e9450115bb66c394b484eea2014b1b01b Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:04:05 -0500 Subject: [PATCH 103/158] Revert "[adam] still more timing foo." This reverts commit ee8eda82a264e692ef49771a508df6621c27e09f. --- lib/bus/adamnet/adamnet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 17b11b38e..622b88260 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -170,7 +170,7 @@ void virtualDevice::adamnet_response_ack(bool doNotWaitForIdle) } else { - esp_rom_delay_us(160); + esp_rom_delay_us(IDLE_TIME); } adamnet_send(0x90 | _devnum); From 74570b5021f48e95dd82e030b95d651b2454898f Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:04:16 -0500 Subject: [PATCH 104/158] Revert "[adam] more timing foo." This reverts commit fab19876f9217585ecab3319210a93579b06ee80. --- lib/device/adamnet/disk.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index 0edcf660b..ae2096b5a 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -1,7 +1,6 @@ #ifdef BUILD_ADAM #include "disk.h" -#include "led.h" #include #include @@ -154,9 +153,9 @@ void adamDisk::adamnet_control_send_block_num() _media->format(NULL); } - esp_rom_delay_us(120); - - adamnet_response_ack(true); + AdamNet.start_time=esp_timer_get_time(); + + adamnet_response_ack(); Debug_printf("BLOCK: %lu\n", blockNum); } @@ -167,7 +166,6 @@ void adamDisk::adamnet_control_send_block_data() return; adamnet_recv_buffer(_media->_media_blockbuff, 1024); - esp_rom_delay_us(160); adamnet_response_ack(true); Debug_printf("Block Data Write\n"); From 51fa9a42709f5c851c46cdcec7482194cf89abfb Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:04:33 -0500 Subject: [PATCH 105/158] Revert "[adam][dsk] remove stupid format." This reverts commit c5922ce0066c801f7cec69957cc9808b93b0dad0. --- lib/media/adam/mediaTypeDSK.cpp | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/media/adam/mediaTypeDSK.cpp b/lib/media/adam/mediaTypeDSK.cpp index 626b2a22a..85202fa0b 100644 --- a/lib/media/adam/mediaTypeDSK.cpp +++ b/lib/media/adam/mediaTypeDSK.cpp @@ -135,14 +135,14 @@ bool MediaTypeDSK::format(uint16_t *responsesize) { for (uint32_t b = 0; b < _media_num_blocks; b++) { - // if (b<13) - // { - // memset(_media_blockbuff,0x00,1024); - // } - // else - // { - memset(_media_blockbuff,0xE5,1024); - // } + if (b<13) + { + memset(_media_blockbuff,0x00,1024); + } + else + { + memset(_media_blockbuff,0xE5,1024); + } write(b, 0); } return false; @@ -169,16 +169,16 @@ bool MediaTypeDSK::create(FILE *f, uint32_t numBlocks) for (uint32_t b = 0; b < numBlocks; b++) { - // if (b<13) - // { - // memset(buf,0x00,1024); - // } - // else - // { - memset(buf,0xE5,1024); - fwrite(buf, 1024, 1, f); - // } + if (b<13) + { + memset(buf,0x00,1024); + } + else + { + memset(buf,0xE5,1024); + } } + fwrite(buf, 1024, 1, f); return true; } From 12d09e3fc3855efac36a5804a59c535582636453 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:04:42 -0500 Subject: [PATCH 106/158] Revert "[adamnet] slight refinement of timings." This reverts commit c04f174eb5b982b36bc4b6507ab667d72c13f1d8. --- lib/bus/adamnet/adamnet.cpp | 18 ++++++++---------- lib/device/adamnet/disk.cpp | 20 +++++++++++--------- lib/device/adamnet/disk.h | 1 - 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/bus/adamnet/adamnet.cpp b/lib/bus/adamnet/adamnet.cpp index 622b88260..467d8b6b8 100755 --- a/lib/bus/adamnet/adamnet.cpp +++ b/lib/bus/adamnet/adamnet.cpp @@ -168,12 +168,11 @@ void virtualDevice::adamnet_response_ack(bool doNotWaitForIdle) { AdamNet.wait_for_idle(); } - else + + if (t < 300) { - esp_rom_delay_us(IDLE_TIME); + adamnet_send(0x90 | _devnum); } - - adamnet_send(0x90 | _devnum); } void virtualDevice::adamnet_response_nack(bool doNotWaitForIdle) @@ -184,17 +183,16 @@ void virtualDevice::adamnet_response_nack(bool doNotWaitForIdle) { AdamNet.wait_for_idle(); } - else + + if (t < 300) { - esp_rom_delay_us(IDLE_TIME); + adamnet_send(0xC0 | _devnum); } - - adamnet_send(0xC0 | _devnum); } void virtualDevice::adamnet_control_ready() { - adamnet_response_ack(true); + adamnet_response_ack(); } void systemBus::wait_for_idle() @@ -272,6 +270,7 @@ void systemBus::_adamnet_process_cmd() uint8_t b; b = fnUartBUS.read(); + start_time = esp_timer_get_time(); uint8_t d = b & 0x0F; @@ -283,7 +282,6 @@ void systemBus::_adamnet_process_cmd() { // turn on AdamNet Indicator LED fnLedManager.set(eLed::LED_BUS, true); - start_time = esp_timer_get_time(); _daisyChain[d]->adamnet_process(b); // turn off AdamNet Indicator LED fnLedManager.set(eLed::LED_BUS, false); diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index ae2096b5a..b40429f13 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -116,7 +116,12 @@ bool adamDisk::write_blank(FILE *fileh, uint32_t numBlocks) void adamDisk::adamnet_control_clr() { - adamnet_response_send(); + int64_t t = esp_timer_get_time() - AdamNet.start_time; + + if (t < 1500) + { + adamnet_response_send(); + } } void adamDisk::adamnet_control_receive() @@ -124,14 +129,10 @@ void adamDisk::adamnet_control_receive() if (_media == nullptr) return; - if (blockNumRead != blockNum) - { - _media->read(blockNum,nullptr); - blockNumRead = blockNum; - return; - } + if (_media->read(blockNum, nullptr)) + adamnet_response_nack(); else - adamnet_response_ack(true); + adamnet_response_ack(); } void adamDisk::adamnet_control_send_block_num() @@ -166,7 +167,8 @@ void adamDisk::adamnet_control_send_block_data() return; adamnet_recv_buffer(_media->_media_blockbuff, 1024); - adamnet_response_ack(true); + AdamNet.start_time = esp_timer_get_time(); + adamnet_response_ack(); Debug_printf("Block Data Write\n"); _media->write(blockNum, false); diff --git a/lib/device/adamnet/disk.h b/lib/device/adamnet/disk.h index 5426fc032..c9c9a007d 100755 --- a/lib/device/adamnet/disk.h +++ b/lib/device/adamnet/disk.h @@ -17,7 +17,6 @@ class adamDisk : public virtualDevice TaskHandle_t diskTask; unsigned long blockNum=INVALID_SECTOR_VALUE; - unsigned long blockNumRead=INVALID_SECTOR_VALUE; void adamnet_control_clr(); void adamnet_control_receive(); From f538245a83c59881df9f5e0c27e4f5d19fef76c8 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 11 Oct 2023 19:11:01 -0500 Subject: [PATCH 107/158] [adam] fix disk formatting. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes lib/device/adamnet/fuji.cpp | 9 +++++---- lib/device/adamnet/fuji.h | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index f9f9c40030dee88178e3295dc74c8635009994c6..410969ea8e94634c1edfd258305f961bf7869d09 100644 GIT binary patch literal 262144 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 zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N yfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l3H`x literal 262144 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 zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj mFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCh#9b;C}(lyN5;q diff --git a/lib/device/adamnet/fuji.cpp b/lib/device/adamnet/fuji.cpp index 79155f040..31f7523c1 100755 --- a/lib/device/adamnet/fuji.cpp +++ b/lib/device/adamnet/fuji.cpp @@ -919,12 +919,14 @@ void adamFuji::adamnet_new_disk() fujiDisk &disk = _fnDisks[ds]; fujiHost &host = _fnHosts[hs]; - if (host.file_exists((const char *)p)) + if (new_disk_completed) { + new_disk_completed = false; AdamNet.start_time = esp_timer_get_time(); adamnet_response_ack(); return; } + disk.host_slot = hs; disk.access_mode = DISK_ACCESS_MODE_WRITE; strlcpy(disk.filename, (const char *)p, 256); @@ -935,10 +937,9 @@ void adamFuji::adamnet_new_disk() disk.disk_dev.write_blank(disk.fileh, numBlocks); - AdamNet.start_time = esp_timer_get_time(); - adamnet_response_ack(); - fclose(disk.fileh); + + new_disk_completed = true; } // Send host slot data to computer diff --git a/lib/device/adamnet/fuji.h b/lib/device/adamnet/fuji.h index a65b29239..159b110ed 100755 --- a/lib/device/adamnet/fuji.h +++ b/lib/device/adamnet/fuji.h @@ -54,6 +54,7 @@ struct appkey class adamFuji : public virtualDevice { private: + bool new_disk_completed = false; bool isReady = false; bool alreadyRunning = false; // Replace isReady and scanStarted with THIS. bool scanStarted = false; From 438af2a6b8fdd595437f1c0c32f79a1e781ff92d Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Oct 2023 12:52:38 -0500 Subject: [PATCH 108/158] [adam] raise mainloop priority. --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 5d952e90b..f0b2e5263 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -351,7 +351,11 @@ extern "C" // Create a new high-priority task to handle the main loop // This is assigned to CPU1; the WiFi task ends up on CPU0 #define MAIN_STACKSIZE 32768 +#ifdef BUILD_ADAM +#define MAIN_PRIORITY 30 +#else #define MAIN_PRIORITY 17 +#endif #define MAIN_CPUAFFINITY 1 xTaskCreatePinnedToCore(fn_service_loop, "fnLoop", From 21c104e4b9e99fd0fdba89d73b4088a4160f50c1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Oct 2023 15:14:59 -0500 Subject: [PATCH 109/158] [tnfslib] only show debug messages on TNFS_DEBUG --- lib/TNFSlib/tnfslib.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/TNFSlib/tnfslib.cpp b/lib/TNFSlib/tnfslib.cpp index c692a776a..827fcbdc3 100644 --- a/lib/TNFSlib/tnfslib.cpp +++ b/lib/TNFSlib/tnfslib.cpp @@ -526,18 +526,23 @@ int _tnfs_cache_seek(tnfsFileHandleInfo *pFHI, int32_t position, uint8_t type) destination_pos = pFHI->file_size + position; uint32_t cache_end = pFHI->cache_start + pFHI->cache_available; +#ifdef TNFS_DEBUG Debug_printf("_tnfs_cache_seek current=%u, destination=%u, cache_start=%u, cache_end=%u\r\n", pFHI->cached_pos, destination_pos, pFHI->cache_start, cache_end); +#endif // Just update our position if we're within the cached region if (destination_pos >= pFHI->cache_start && destination_pos < cache_end) { +#ifdef TNFS_DEBUG Debug_println("_tnfs_cache_seek within cached region"); +#endif pFHI->cached_pos = destination_pos; return 0; } - +#ifdef TNFS_DEBUG Debug_println("_tnfs_cache_seek outside cached region"); +#endif return -1; } @@ -559,7 +564,9 @@ int tnfs_lseek(tnfsMountInfo *m_info, int16_t file_handle, int32_t position, uin if (pFileInf == nullptr) return TNFS_RESULT_BAD_FILE_DESCRIPTOR; +#ifdef TNFS_DEBUG Debug_printf("tnfs_lseek currpos=%d, pos=%d, typ=%d\r\n", pFileInf->cached_pos, position, type); +#endif // Try to fulfill the seek within our internal cache if (skip_cache == false && _tnfs_cache_seek(pFileInf, position, type) == 0) @@ -595,8 +602,9 @@ int tnfs_lseek(tnfsMountInfo *m_info, int16_t file_handle, int32_t position, uin if(new_position != nullptr) *new_position = pFileInf->file_position; uint32_t response_pos = TNFS_UINT32_FROM_LOHI_BYTEPTR(packet.payload + 1); +#ifdef TNFS_DEBUG Debug_printf("tnfs_lseek success, new pos=%u, response pos=%u\r\n", pFileInf->file_position, response_pos); - +#endif // TODO: This is temporary while we confirm that the recently-changed TNFSD code matches what we've been doing prior if(pFileInf->file_position != response_pos) { From ca7e5a111f676fc2ced3ec9d373ce5590bd28576 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 12 Oct 2023 21:05:38 -0500 Subject: [PATCH 110/158] [adam] get rid of dumb formatting. --- lib/device/adamnet/disk.cpp | 5 +---- lib/media/adam/mediaTypeDSK.cpp | 25 +++++++------------------ 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index b40429f13..eb0b5b40c 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -100,10 +100,7 @@ bool adamDisk::write_blank(FILE *fileh, uint32_t numBlocks) for (uint32_t b = 0; b < numBlocks; b++) { - if (b<13) - memset(buf, 0x00, 256); - else - memset(buf, 0xE5, 256); + memset(buf, 0xE5, 256); fwrite(buf, 1, 256, fileh); fwrite(buf, 1, 256, fileh); diff --git a/lib/media/adam/mediaTypeDSK.cpp b/lib/media/adam/mediaTypeDSK.cpp index 85202fa0b..93cf4a1fd 100644 --- a/lib/media/adam/mediaTypeDSK.cpp +++ b/lib/media/adam/mediaTypeDSK.cpp @@ -133,18 +133,13 @@ uint8_t MediaTypeDSK::status() // Returns TRUE if an error condition occurred bool MediaTypeDSK::format(uint16_t *responsesize) { + memset(_media_blockbuff,0xE5,1024); + for (uint32_t b = 0; b < _media_num_blocks; b++) { - if (b<13) - { - memset(_media_blockbuff,0x00,1024); - } - else - { - memset(_media_blockbuff,0xE5,1024); - } write(b, 0); } + return false; } @@ -166,19 +161,13 @@ bool MediaTypeDSK::create(FILE *f, uint32_t numBlocks) { Debug_print("DSK CREATE\r\n"); uint8_t buf[1024]; - + + memset(buf,0xE5,1024); + for (uint32_t b = 0; b < numBlocks; b++) { - if (b<13) - { - memset(buf,0x00,1024); - } - else - { - memset(buf,0xE5,1024); - } - } fwrite(buf, 1024, 1, f); + } return true; } From 16a805e3fa429dad6f67a68a8b506f9bcb8480e1 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Sat, 14 Oct 2023 11:42:52 +0100 Subject: [PATCH 111/158] Set destination slot to 2nd byte of payload for copy --- lib/device/iwm/fuji.cpp | 4 ++-- lib/device/mac/fuji.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/device/iwm/fuji.cpp b/lib/device/iwm/fuji.cpp index 3d591274e..48f7394c5 100644 --- a/lib/device/iwm/fuji.cpp +++ b/lib/device/iwm/fuji.cpp @@ -266,8 +266,8 @@ void iwmFuji::iwm_ctrl_copy_file() unsigned char sourceSlot; unsigned char destSlot; - sourceSlot = data_buffer[0]; // adamnet_recv(); - destSlot = data_buffer[0]; //adamnet_recv(); + sourceSlot = data_buffer[0]; + destSlot = data_buffer[1]; copySpec = std::string((char *)&data_buffer[2]); Debug_printf("copySpec: %s\n", copySpec.c_str()); diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index 363ccead3..4416b194b 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -511,8 +511,8 @@ void iwmFuji::iwm_ctrl_copy_file() unsigned char sourceSlot; unsigned char destSlot; - sourceSlot = data_buffer[0]; // adamnet_recv(); - destSlot = data_buffer[0]; //adamnet_recv(); + sourceSlot = data_buffer[0]; + destSlot = data_buffer[1]; copySpec = std::string((char *)&data_buffer[2]); Debug_printf("copySpec: %s\n", copySpec.c_str()); From 379940c45b3e6644294c4a078837f829549e610f Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 14 Oct 2023 15:37:52 -0500 Subject: [PATCH 112/158] apple2: update autorun.po --- .../device_specific/BUILD_APPLE/autorun.po | Bin 143360 -> 143360 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_APPLE/autorun.po b/data/webui/device_specific/BUILD_APPLE/autorun.po index 992c36b54f3dd1989a7e477354d4a41dcd5a8ceb..9f05668bb9ddd3b41a670a6085a028d36a1ada3c 100644 GIT binary patch delta 18013 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 From 2a20b930c69cb63ec102003c97cb23841f5244b4 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 14 Oct 2023 15:39:48 -0500 Subject: [PATCH 113/158] atari: update autorun.atr --- .../device_specific/BUILD_ATARI/autorun.atr | Bin 92176 -> 92176 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ATARI/autorun.atr b/data/webui/device_specific/BUILD_ATARI/autorun.atr index c7bdaf1d309cc59fda029a0266005ba208bfed32..abcc919f78fda90d7068709b652838daeb096b86 100644 GIT binary patch delta 19590 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 DxjkNN From 0291d5964f87409de2b2f9e800d89818b656d050 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 14 Oct 2023 16:07:32 -0500 Subject: [PATCH 114/158] [adam] update autorun.ddp --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 410969ea8e94634c1edfd258305f961bf7869d09..999de603d9eba5d384936550a878e6eb6ff98c8c 100644 GIT binary patch literal 262144 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 zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G QCcp%k025#W|Emc6UnUseVgLXD literal 262144 zcmeI53tUv!wg30b@EGs~;seCTIgFYS6cG@CL<9wuihzKxm|*ul?O?KhK%Tj`S^;^DJ-O7cof{BGw|>y8O9YE?b1qKKRU6cPy-? zGtL$B7X&SOUGRqqFoFMF1l+glv~5eYttQ%bYqV`;Ter*O*Hnuy^Qhx0|9P~@mWG+z9ie}o z?w!B-zel=%iG!!X5lA^6m@(&g$_t(bt$Nuzj`&M~=rr50G|#a)o*ge7eeQT|V9JSr zb)E+uY@)w6Zrs~x^G*b!Pxz;0k6c90=sbPy#vWhxFsRTbEA8Wz*GDO@`8wx#dVAw9 z)y^#2F>{g40O9cHDB?T^;w^K!UB1q?KWtg1ZCTds@%mh~FDr37eyfad)&52qvg6lE z9P787_E+C7&u4QGuqE>8n$z-%qRvvpEshmZum>dj?@o7})%IJR)_L#D@VKOv z_1$fcZt1S;eyXPX-tH%F?cUk_#2;R_q6X&7L!KVGpfge-N&Szv)a|eF^!Q303mrS2 za}I5A{HDR7^!{3TzxwvG4#N^p-Lb|+JC8NKIInfM?cSH?xrf_OMJF5{5`Zxt)h2TE zi*WNI!o0AX7g6R#v~dBAi=g>MD6Rhube^p{0<}lyO!w6PYD?WOYdo&bw)&BAbt66X zR$HCbcCXd8)9Ug0e4d@Z?YHFSs>GeYa@y4s!?b5@@gJyd!`#o>EZh2`ENAkqW<4+A#$&%)?-^Hh;ipZ>!d^cp!0 z>fV~|2&hkgx<*?O=E>b#gDaWGp+`?3vSBuQjF6Zg)<8s$$s7+?Y)I+xbUZ1bNt%Uuee;={)MpCk2ccf4_;^!3e=$@ z=VSGIYy8@`i{VbEwfh#kw3YcT>J0pT&9=OmAB)n>U< zM1hxIn`5)wWn31+DfLSg4FK&;z1z4&$?5hU<94`y`wjgzFA^nI5%zJAmL#HfASV;s zTLZ9p+S(wJ)1z88Si;1)!|ExFCjN;^#Q1HFn9qC^=U1IV+h$eA!^YPu)Tw%ws)*7q zT4Ueo>(MG~Cu1U2MdVc7oYy!~Rpmv~NHqz1^LCAN7e@|C^qQXNhJlHC@|vV96#4TS zwU4Zw^&{0Q@S%oNlXH-@Lo$4Sji2)I=UJ(;UDQNUM}*=g0eGY#fOzs2vgc#zExKp) zLP*@?SKkQXw71r;+7X8KL)DXK)Ap8A{gDB-U@+Zk_lHr$-rCdTk5RfmhG>U~%qCa` zi*5?_+|QF-KTz`X8w6SW2olV(nbw*%Sq+=W;~NgNKVzp0*(e(hwEoJTynBr&`GGYa zj~?IJW~Vz{2E|_wf0f0KmL$k^p97fZZ!)Q0?}LQf7A3ufs)lL~o`cK!_Z#1S;A9I$ zp+5e=aCO^~m~Ehe$s|j=1fLMR#MZ=`oQ5Gld(j?Z{okW9WWO`O^!~od9_*XYTan56hRM{a zp;IJp(B6u2fuKJ%0_|7^w1dz9Pj$Pq z-Dq2(y?DXReswYaLY1t#SvDwB2^G~s2Kv<>UPH?jZSq^X3bUoijwFoyUH4P?C|zTy zx7bCL-W)Ck$68YxnLn_pQ=9xTtkruF$KZx(3|_LWY1YcvNrDFalQ#_|O{o}n;4kRG zFiel6@?+CZuBE!F` zk0u&Mp|!?1V~j%Uj9X(Ay3H7NB52r=V=`%p)V18+ujT6lwcIgK%f_o}iP5!e>esS) zpq4EIwQRjY%jjGDYPPP$9AZ%-V~91!Rdbj%N@NbR#<*$@voQmQSv!>%VIQlM$6P&+ z?fsVS7-(tjKudQTw?-cK8n;Fsb^2{ye;!n0g?b+Kp*1G18`Phv!fEtnW)G)#%ufx6 zH(jl1KX~%*G71fi=CJ4?^P-GiGPOL|ugDHIB;Ha^4FJ>B)We31yJa}~D08AlQ+7;~ zhmKH}+~OWFLcI};ZpYsal)-HEQ5ZEbX_KByLws21kWDi&+1sJ{%UQH4lCGGWp_hOO zsu&TJG4nSK31+qn8PhC}Ohk%N!4&8*F=g)`5LA(VMTnkr>Ym_?Z*ahs=Ie7%IZ(X6 z%jn3=zTKFo7z1r?jBK7XVC(Z2kNO>uil9Nk7{=ugCQVO`lg;}FD9wQGz{pO-8Qp?O zO|BOP&OND9L9{V|KYdGowlr@VFij=VkyjO^7`yBZX{?2=E9PiFk!8rq#OlzJxqeFu zb>!&N2L_nKv+QXHOxb=Wo!zhv(Qlt)FVbt%qC!rKK*j#c5H&z zy&T)`i1**;R}Vwi(Tchwie=8py%gvEQLOq)*!Lp-jv~_Z$P>7RlenX4=3*>41}pei zso=eS1?1`n+AqdpFmit!t9}ro&w8uWhe1|)dgw4{>JR2USIU|znUDb!lIn(A{pw~2 zn1lvFCCA?O<`W zbx=O0)j>Q#i`u`mWMs7*r_E6>s4937)S0DAn!|CMG4l->;#O3f-m9*w_N#mFH`v9f zlOO1W=;j9opc5V#fNpqTz{o)X{XH|9q06s+2N^#BYg26w+IGP#p{L{ej`1B6^kbJl zFHE0@x@ZyXr`218i0ah7LHi=LYH!e-EceY# z2U^8wbzimHHkyhc17b(3|5WWBB?E$W`4UI4Ge5@Yg}6D!#@giOLP6T-s8tafck zIHs#%{mn+#lQ;B%n$J^Z8H(Wx-ImlOw+OCKM4e%Ow*7*GT4oixkaZzV{*yuF0)(q? zJgBq3I*`D%CBLdmn(Y8h*{@|UamhY+;GhYcql5kRH@|99qN+$8Vn)b8l!6~VL*w=sH;!&&GKEFNUzi+R|?YBD{Q0r?})Xb<=2NP3P*>a zjSY^rl8rtdQk4%Fga|?LK*@+}<`;^UDC!gOtLhBF>d`Ld)u)GVNIt%)?nrxHJkBXe z$2U2W!#7M7d6q{{*2H50mm9tzFs%Kn@qt7fGln|Pt~SJZ%DQyt3!{Td?Q|7^(05( zURz>CK;AHz=Kf|vZuEx0i1u{}$# z_UjV@5$y{S0+H=Y5(4)2%7j34`FOfs135X_31-4=%}^p;*HtIR1y1C(W8Cab~1b%EpTIZ$~D_O z+`^x7{0(RR6*Yhru(|pjY0S&84ws#*hsG%k6Z%{x5=k&_V0lhq336P(7D+=7W)3;K zM^YE4{d2NQ8#2z=Iq{okntJJ*Dg8koBxBd~xp}m)8omKe_02@nW276kK0`K2h3;=A zQjooML?RgqAE=l1&nBI-kt%04p2GAg7P`iCwDZtN*zH$m!`+S+W4AAO84`LmbKLdg zfG}?oWq=&tz7J>0u?JhdRAjl})$`7zyfd|YY_ElH*jzvM=^ENdf+_ll40osL*4Gl% zZwdF;6J^B&t++~8<(#K6Ax_Ywp9+y9d2 z{(GVv5pJCALXMcYS@lf}T-iiY=2{Hn(AOGcNnRXnSKH;r4lvQcIdPmZ z3DZZA5P^IMSV9E`8ak`}$?<`7I%LoxlMb`#kVS_%bjYSdRQt2zQL0~$M=udO0Yw`- z0YyuifTER6K+$fRfTC@g;NCTX&|BW@!w`5ej5<->X1Vtw%QGar9$T;V=}$GOgBLGg zKXih+x56pVfY10%+opL5EB_M75tMUYChi^hEG- zObk5Mo;DHCW={mPB@^9Woj3qmFn8=NJ((*j9=XXUGcs4{Jio}Ly=WL7eeEPLyJr%ZJu(T*o|qJPr2W{W!1vnUm;`Wtn*?x)O5h*c7b$^f+LtTt zwMz2QO@0)lGa>2dCRmT{i2bvuv(v`gQtFPh=1xL8&%lPjcw4MZU=OUdWD+_EgrH}{ z@lbllCZqYudys~r`gHfE^j6YGg0x&qTHC+gdw3Gu(f!>?a65{Qpd(g^2U=g8lxIQ8 z0VahHa9ll)C`u73rM;bM)?4mVP3ij^Frk15RnURfa4IAE+;D|FoJ?-tq&5nS=v1?r zGpXOuWdp-oXDPX@uw<4(y~_Yu)VC?C>sxNnDp0 z)N}e!*(E+jQmguah*FzHj4E?Q(tUbTBh3k`)UYpHo^%Z!^+P;eqQ(*{yFhG;`e`K5 zyGYD!@gl?4ifeV1eWsu((C@EQzQp!t)xfOw7ge-y95U#TNrwm8+f_L4KdbOo9Co+& zsPIvd1Ru30xnq(Hx1wHsKs%?Jp{n(3v*x(W8@=E8Vbh`X-;qD|H*hr0JZmrzqk~M1 z(SgqL0NId91huDiNw9iH60E*I30C8fL5EB_%%(#Y9p=y>n-2ThA0?}QnB@LRQm|8a zstL|48^?eF>MBL~5=I?p|Cb~fcA5;sL7~F~?e8Z6-BbtA&2qSN9I}@)s8Jt>d(egjCt88=f(n6O~RfY$k9w~`!rd|MYPD={q zV7QDvtYVcgXjsKQdzPrWInL5&J9pS8mq)>e9ozG04UKgI9*1Erh86P^3h_{ows@W^ zX>YwJd2c;h37zu3{fdz*c27U?<628xrWcXsVs|<))!vJFbcP4<0h-&P@Ma8hkl~jH zg&Qf_NV-QIw!vbhXRYW4d(e<`8syV59UK0h{xtj@#t2 z#`0APp!EXHjAU z+K<0}1vIm$j~r70nEm>lfu zM94sl+4Tq7|31a%$L!}{r}!Lx_enbT81cbGWJ?&7TlHc`OUtj<>-#5Px7dPph3PEn z8y3k4uvzsq9WtsOojPjj0v54GO_FoT;$?W+42=i-HPTLKPN&YsOhMZ86d)3i?0*h? z2762qLI_Ap!UhsB^%#YLc(59ty+hARJ_e+xTIMu8*a-wZSp8V$eCQ5KB;`!(F|nr_ z7#otm90W#(1mG=MyloH*iyEyit8`{Q7zj_R|Mqlks>&YWdHBQb0sFR@_ zA&f-|RBG;gv^SS~lT-FP1G3m#3k$GW{4|~aG*aD1=g*`?a;B-95Tb>uit>Jw27m1b z){|qWQH5tkII@JhdYTzMkERtAoux2VP>)x@JN^Le+tBs($Yo};&)AgH~SOm7lQPeHjc=6kebj{1PD zHP5(rFHh0VIPh9ZSqid;00NLVNnWw+^wX4ITRjGz3yFR8QbK!aG6YY{cOIYsq1u~c zlK0ieT4_RYR2!RwF!y&csR$#jz?gJ@BhuGn5=EszY;xw>*a#_&beLWLIYo%~Q!L`c z6s!0o#U@@&38R_zt0~%w6guvZ$A{(dCv@~^&p5Pa{AN_JzFIHk!yQACW;UqpjEZcdpu=!j;Hq*Mr0WS}-}1bG4KQXsq5 zO|%E*-b6#G@MB~!HWrpnacM6(uu6M%hMElm-wvlYVNN?k{QSsysLEgm2PChnM?m^IF+s9_+wr@Jnx^Lz+v!-nY z^aC&;zdvsmo~*HzoR=M{l|Gt}Wtw z`>u@FMoI6}9+^m`HuoWPzm;C7J08^ys>ZKX#k!L3Z;TC-TN^Xdv?CLd85a8P(P`+| z8;oVK+=jafV8h=wrG@%xx4H}5y7dhTDm*ayagcAVkqa5m7!e3TbnuQKacX0~yMItE zpv`OVPIl!*ra#prclid?5sC(1pd96>s&98)#nhlLkRcdkq%ZfN^}t`LYY8@QlbNJN zqba$_OgPS)6>>U6EPN^chQQ1@ie=s(7SF=0yXt1_Lf?NM`Mt~E<=#B26M;1MuRe}^P&6r>nt=K z7hZZym#=aJQd$GEP}wpB(rCT;Q+;r=`>1AVu8e-FQSYbn^wpkrhf?1uFEQ8^r0b2X zTWykcN-atH%^f3UtCH8>Qd~)|Z8}$ZY!jw#az{mrww}B5&5Ziz1ZoayA%ri(BL0?P6&EsW;?s;U5uF(!VlukOnW|MRIG3_#*QPI|5TPB{~y_<=rVxMH<>0Rt>w{y07rySeV$FMa& zHQv>&uG3xfeq+ef2h1B_YiR5fS5NfQs|UZN2h%$~P(nt|c7HEZJvl%cJZPdu+3QnM z%=xwW$*vwXyQ!vHtQKe|`3JML?HMt*{jjg3H zJCgaej}z(f1VTMps$E@;ka6Sb4GjvpUV=Xy?$QE|di4iQ+w)=`JL#Q`SN`hLf6%0l z{pV+^|0b<;X{q5v6rD|YmX3D7G`~lhB%g9+QoKGs>pp@)__d!$V1)j7HZ_#2CJY8- z-A#y~fXubJQ)D%f`|2}T6b#N=mnFomEQ{EaWfc!+*~BARa!y*ArM)`ajpIG?_@q2O zD~~s1A>5PfrkN4uVgEOa_As$+Nf@4Jq6t2o@Y)6u(Ff$J({CX zE0aF7EY77Sqgvd_b3Ug##mg+GwZ|sA)L9r38ucLoV{;sh%~ZFPImQ}VQfhy@&INHf z&B1;D%f)2LWZjZ0qqF)bjTSS-71T3hG*%jCMkPPdWX}87tH{Xx&>S=}qhwf0;wuh% zfxnlH64j&Q)2@p%i=w|fY;>sTa%otJxDN9vObW>e8Q*Ur4RV%Aw9j*8WR~^Hz#im- z?H|)}JvW)jw=sBY?~K;+X`=d2w($}(%I4R;f&8`bF*^QohfA9|#)$5>lXg_JsaVg$ zPT5G^chLhjz5Zy<|9K;yA&1U5wog8rr3JP?&NPtAwSi$MY7EoosWd~ZGU90j+h>r(iT%_GGmgiJ2+ApsZD2DaOrO79>>&GX(f4_TAuE+2e?e|k@f;kc05iUu_E9_W=ijAW#NT7fJ)bwEbzz$`#kH?`M(z~+ul@KqA(h!@-t ztV$VA&r7NXh2g8AjF#kX`u&6U7F z2C-(p))44x|KSZ+iIBy^a+=gpwMh|u@?)l@mm&2o%MBG#)M_(4Xv8S=jJYTbRb0kg zD8L2zI&IzPPK3goCLfk9fNGKIzd0Ihf||DefcS@V;Rk5kyXFe9XRbv&Jl857nQNnI z+M2mqeJ&kKuBYQLI_ml3f;2=?=kUh&Z}3=zXoCTMHSIIM_6WXnh}x15De+>c+!M1_ zrkESCm@fCIqom(}QICo@L*YUwau0nO;M~4*`!FxY4U*E0#b#?GH}k76o4V!qXw1i# za=t?J^i68&XQSl0-P{6>p`BUdd0J3L^W;(3+l_xH&7;H(fhXIO^XO@x*;GD9W8GCX zCeAZ7?h9(HGc-yT*x^Kx8by+2>RO+W{jh*?x?0mc)*HoZ`PbrxTB*p6HM8@Xuy_$mukt8DS7 z3u)-p-xNj4&kE$k%S?%vZu?WF=_yf{At~W^dY)PH(Z^jQ&sBO#-9Epj=Lw2>%B}N3 zxIg89JR9|t#+$50O6qrIIiH!22}6I%0p&a>Q_@?lMk?y*WvX}Qqvz^RH6XtedMf%F zp>8EOrfv_R;E6r4NjvkTN6q4GOI z<#&Y210m!S3e|m5-YD-rDR16Ld6UE@%%*4K4>%XDl*0`@fU(e|(ey{?#K1|*^4kjW z#?Chiu{PgRh_(3>g;<;aQz720eWlQ&#v|Q9zuJdYsH_-|-2Fs|WnD02gDzw14{6au z!uvyB)I%csLr&=-QT-uev|I#8v-Ou)@yfF?i@6?~F*E_7ZLyyg;ie%F-8!{M_P?_G zq7H-V;h23pbsYN3obLAv^|4QPWa5)q9P?0eNqTbPA&@h*PbqNOVlMl)q z!bS5-(j+Dc< zySIo+k?Hf-zimJH#6p!sVFGn-rd0_jl>TfN9gSOAh%L*`E)qhx+!lCrA-(r{%NXJF zQ{gD=4-*#38S0rvyi1HHa=Wh-nRhZYP`&~T6~=NQ!LO~Ul#>r+G7a+u_k@M64EJA) z^zY=#DJgy_hWbRjtRCWf#{2i43;4+@dp8}uevFuN7GL&xeZEdtZ?~O}`XmWI>5&zo z&v|ZaMlHwQ*sOYX(8W#7>O>iGOSAg645@Bboib!?vwB*F+}5n7%aHZWYPk&AV5a(d zv${rxY&27CZdMh8~{bO#qISWx+7y7k%%jAzX=urEGRtJS>o);N;#sX&u&UJM6@+a?Y#*dER z?}=u=mQ#%85?pUk5Awod^dPSsb0`rW4^XU~qFc`DxYZ|ht((DV@sFZ<|Ci3y+?2P4;;tgOrvwE_m(j4itwGkQfxgbo<#4q zFz;RA-p#_h-g2kIdynwmZMhu}%t=^r4)<;j^R5riv$kn#Z9b3JuVsD3>&uR4!?$>F zD^vN~v^h(BE{_k-^k7_E+_*C_`01l@XRJpZjstS_i2lTZSL&RT16JpZt_#}ZtJC6o zI|GqQRPGZsBjXN@jE{hkp3YvR_o$E7bnG5?!1+PPvG~6wf4`;&uS~?B@%p{!bi6rw zp59xm-W9ekZ$tP6Z$ns@*B9ISl`j7a$Gi3Dxz1_b-cqY~p-nHWcXNbyedOG3=SXj< z-McW#drP!;#gMKxukW(Y-`nl6_j*si;LPo|U-0P!y6tnFDc(D+-mNwR&^-~}yCdg1 z$8HC^*l|N9Fw7>b@13TwA ze^0+y6#q8(?R;A)tDpPQJGnn9*b3EGdl{mahheuXhgouBAZpWBO9TTt!YDK$#M6#by3)G;eLO~+%xvFhBF^Mw_WOa z+jhntiTl4jw>|#-HhXY`w{Ff=Qds+546{Pi9eFKg8QdE_gPvtt zj@RF2d8E9}Vi9d{xUQ6x6g-EapU`l*P&;18d2`gmXra3I=&pUpyS>l5Juuh1{ZsGu zPrTbd_HMuA&H5-B;g`MJKl5(C2+T^PT8e#QpC>TI8Lq8g8t=uIOQtw4Xx~}t?fC5Z zz)t6=zy`&RzzxdKcza-@5`l1}^s5i8D{DC59PyG8=_qw9^tH)qIp?d5f6)*B^LsM` zip`tZR~8}Kyrt3Jg+tmb4=ru;Znk^ZN1esbZ*}@S=!PP~)gLc?#i5LBc&^OX;D~>J zh9$+S*c~xxVUCzT`Mh_2=FR$4c(Xncfn){0sd0aK&*}K#fwb(nKyKQIt`x1JqQ`sJ zr`~O!bT&A=Ss(X#vo7@oQkC%ykdJa03BtQ{xsScuE;TqhJ>XzPIUYtuoh-#oj5q7@ zsbByl>Z;f7EO*~pKHLI{QWW>+>)d5ahr<#*rTZVse9621W9(qrd})>*mo~b*lM?jXYZ~u| z?r%7+^L9imRAPH%cZ6R7^H*=_sdW!8qkxo@g((g2nCdO@f2D%K*=i5GmTZmxmqj}< zbnSCSYo|os3=}s$El+{ETa*v-QgAL+dT?Ct9OrHLC=l(8yO5U#q254@V$a**-F+E1 zhb~|qviYN_qUt8?GfQ`UpzlI=-7kN2MEP@X`>o~2(gL~J;m5AiW#j*vXneZj;_g@* z9|zN6^k42+i}ox(co1ECz&X650Vai8{y$C9hLw9uFXEfL-djEzBV1m8mtXt4fWK*b zD==;hD+gZhJr_~6Ucb+BxGxHw{U_e_pVl35#-hXj%-X(e>hyJJ950O7I&_ccrl!it#JNzcv}3Q#|ZB&7m>x%LbJl4F=$Wb#qBPi zhpGfzQF3dX2SD%xX}&i4?x@df>u60WDY1QhU2Q$EBgbz!sW<(eg(;6>1MV6NebxyBx#tdvMlmcu!C7{gD8(M1O7iGtKv=A87V;`tY>=aT}db zCj0=24R81QQsV#K*45y6-Z|9Ykg~ak21rNz-#T3|wW|$3R~TW}meHHn9i#CxcF!x} zccpAQ;Bmx!Fvk;6jt8RN2@Id-86(`i%j7QyI_DqqcNZ@8b@gni>2__Y*%6_1cf@wY z;4rrP+}GuQ72W45(!#qFy3gG>FUA*)_IG!-b^BJY^d!2|Dr#SFjz1KUFMkLSiRkwM zyT@kRUdpz9cY4g(7d+a63P??!;v6z+v@>F9T|`WLSWkU~9fnRrR%w=mn2%oY?EI$- z9Xns^wRF_IcGjZ3x2*TP`>e(1^QHDp6-m=--OdW!_>g7}{Yae|I+sE*kRz~LE2-#q zmsI#rL+-g1T8Tx=x1`y%wG}7NS{$Ap?G8(J7=Ai%j@oyh$B2#6nkr775^)s$eTv?B zd`@iNee3SpbK`20JDTxOS?j2TX0Up<(%1XeD;MxJCFP@Dk9KEe{adfrotbwr z|E*WG?UnQ@iLuQz_GCg8UCS@|E5?`nF@^PGm!;!!|9VmvPob?{xu>k(;|_Crn!=jz zbYWtPOKO|RZ#J9zZTkCoG;jU}?H^#e-=n(M(~m0#`i}obxk&B)>;_E$lVMTB9F(NXDsdZm9Q%CYmUSMR;ph(o}hX5Xp4(mX~aY#)y@`LHjZj|7L@ z9hK?Fu(%jqtL+xaV`~8q7e4C$&sBcEMn88pBlGkpY9@*X2QrcebS{o_3tn#yx#u?p zx{|Sjltiuw%Hw6x;bA)?6eNoIbeM8s!Pq)}TzFV&d81A&bb za@yESeOi}wvh-YRSkPum7o<9Ai-H1ijfXK>hSlZAt6KE5diqLTm$Xs;O$kF+zZTT7 zdZ|zDued)T1CXxJNC%S*8(f16Cs!;+`PQ#Q`Fdp29QW2Mak6Rl%Wt-N*V|B!=2C~2 zYe6w2Jh#Tv?DZ!Cf6a;i>Utit16AKJnpIh?%ng{`OuQylS97PM93z*R(N0eF40C2T_C8jM=JyAVa z1^L=Y2FpF@aLIm5R^|6=#t5i@NA5T#7KJ6mT+S0sWl@;)cO<-XW(3v+>hhYX22XNA z?b#lAz#hJ8lX{qaVu zB4e*ejo7Q^^HY*6DXKejY0HjDlO~;+RI}quFdzs7N41O;&klH+Z);zqXXlZ%XYEiaup-_~SMI{T$mKG^hWr}0r@~;$^7FCI* z1q*VODQW4ea<6qjLZxy^aXHSF3kph0i%S z(U7VvE)+^d5lLS?R~1rI?g?suy5*&Xl(ML#XhD@yV8)~(c~NOq5i%=)-DL}nOw9QH zXx$d2yr8lYMv<<9(n6&iMpPSCrli=>=t_rO1Jb00>42$e3+nN=EuNQCM8L zM5!z(tEv=JZksYAW7amYxU90OKM3ViDi@cnj3!kJix-gvg~e55J5u3pewjR(d74Ec zEf88WYex3XW*DWQu&RRjH!F+E$fA(^m7=e}QlXTU&P44+BX-fEk|N{~D&KD$DOylc zR8VoVo=_<$DKX4Ou_=NI9So#O(@j^Z78fZ}k7P_WONOC-pmHEUW#!_cQl+r0vJD-Dsf^d01DS3N{ae-!h{g>uEh z(iKG&xuP7V!w2TUp4CN_p|?tDnNSuiE+}18gh=Uk6-7oJqj+WIMdYp0LDSQ>)lJFX zRwt&+$jaO%)*$d^F=gG9bqL5v+a_j0URe$&Uszm%%!E>2Q~?%Cp?5)9`D(-(&RJMg z3I8dmDlQ{mUjr|{St*!bRza1&Y8Vun<<0}83l>S#X1%W{ zD_M>nucTmpQAw)eoRv;)UQw_Bu34!pEm$=z6cx4LpjL7bqr!A%RQDnZ6P&xg%M_)G$t1EA{?*bMGE{5jJ2E#E2K z+E%)1bm``X()sq%jdM!HZMT%(v$1r?ouymWm9AP^IzPWuI5*$3apSaL{V4PiiYPBH zmtp1Qm+%kW&W?Rso#z#C^mvSt|9HH}-?uOSV9N&7lOpAm{Km${e58!A+wCzpAKZ$6 zh*OkHh6r8fL->+RAPF78+^_q|Hku;WS2ZQ%J|3k>=1}VvOQue znGgFxLE5>eW#7?#EqesC;B!grdFS9klH0TA_`%0X9yeq+Wd;FxPh9Dq(jot?b}FaT zt57~tUY^S3{lSCpkiK#4T-KHc-7%{%Lmjh0KoZL8?_woKa$wA7|)0f%7{6 z@D9!tZI2gX2OMaJh_B99@~h*Kp4B#KCg;Pl%=}%ZsiTDViG*VEa$VO=2tCst$dT5_OGCdTs zLi}0Stt5yKg^IEoOIeL|L5;1rX4%}DzA>x5W&4(G>Z+fux_(vU3c9whPFOua_kW0;|830tSX>n1 z--LMYzl}xzRfhaQ{OP|c>;GQ)VhHROX9bNI{E-A24GtFufAFY?J{R;;|JjiH(EJ$j z9}Yen@jA+MQ2m~i_Tx9 z$Bh3XJ!ZTq|7Fi+y5QOL&%tLyAgI@fXa5fp8E_Hg`2`mP5`E6i7pMtFe~yZ)Mgh{ANYPb;2Il_1sUN+Z7P@zNV(1G&Mm_U(-MQ!?XIu z%P+r77kcg?$Ir1RJS;joEJXA_^HQz=DT8n`7ptH(y=cT1(7t^#Fv8p}!SYbwFo_Vy zPbkW&$FW6}ukV>IicyC0tau96sDw4dLpR zmh&wwxH#2vs-@)=F1AvUx5|(fJ>-1jDeR>nL|#x9)h&&OTSx{Hl-w#PQ6ojg;L}2y z8|A(VUC`$|jMsNoDAkD*hh?V7y+sOB-ZD9b95!-4wXX%jTN|rmuw4WQs1~eaWu}x0 z3iTZZx{zBexG2Yl>mC_}D-u3W`%34*=O~$R6e0Qfih_MAgrG|Ej{+3x9UKuQKP23k zFE1%%Yl|#tVCidL_y{-h=mCSE`jPcQ=Ou+BbDTXOB4{kfm+IMgiK>2 z?K}0OLp8~r7nxk9B0b2>(0%%|tg|=X1 zNOg6K3;`rDag;aW_+d}=jZ1~ zO^7XTDp9N%pEi}~=UpWV0$W_w2>e7pwpLTniTT(joIGm2k~V7cnDSlu`7!ZvyYkaU z#gA@jZN$yU)<)dKoN zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N yfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l3H`x From 4c184943731e427122da16710e6b5f36cd677ed1 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 14 Oct 2023 18:42:14 -0500 Subject: [PATCH 115/158] Bump version date/time --- include/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/version.h b/include/version.h index 679888b23..aff7260ad 100644 --- a/include/version.h +++ b/include/version.h @@ -10,9 +10,9 @@ #define FN_VERSION_MAJOR 1 #define FN_VERSION_MINOR 2 -#define FN_VERSION_BUILD "7fcee2beca2329f88c61ea03b7aafb8670219a11" +#define FN_VERSION_BUILD "0291d5964f87409de2b2f9e800d89818b656d050" -#define FN_VERSION_DATE "2023-10-07 20:25:00" +#define FN_VERSION_DATE "2023-10-14 18:40:00" #define FN_VERSION_FULL "v1.2" From 31ff73ca12d7d96fecef0b131258adf1891bd7a3 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 14 Oct 2023 21:32:40 -0500 Subject: [PATCH 116/158] main: delete app_main() after starting service loop --- src/main.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f0b2e5263..e2d500527 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -361,9 +361,7 @@ extern "C" xTaskCreatePinnedToCore(fn_service_loop, "fnLoop", MAIN_STACKSIZE, nullptr, MAIN_PRIORITY, nullptr, MAIN_CPUAFFINITY); - - // Sit here twiddling our thumbs - while (true) - vTaskDelay(9000 / portTICK_PERIOD_MS); + // Delete app_main() task since we no longer need it + vTaskDelete(NULL); } } From b960a5c87f767b81052997abe5e7db41be606133 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Sun, 15 Oct 2023 14:04:19 +0100 Subject: [PATCH 117/158] apple2: network open: stop at nul if present --- lib/device/iwm/network.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/device/iwm/network.cpp b/lib/device/iwm/network.cpp index 2d83833ec..fbb79c314 100755 --- a/lib/device/iwm/network.cpp +++ b/lib/device/iwm/network.cpp @@ -125,10 +125,15 @@ void iwmNetwork::send_status_dib_reply_packet() */ void iwmNetwork::open() { - int idx = 0; - uint8_t _aux1 = data_buffer[idx++]; - uint8_t _aux2 = data_buffer[idx++]; - string d = string((char *)&data_buffer[idx], 256); + uint8_t _aux1 = data_buffer[0]; + uint8_t _aux2 = data_buffer[1]; + + auto start = data_buffer + 2; + auto end = start + std::min(256, sizeof(data_buffer) - 2); + auto null_pos = std::find(start, end, 0); + + // ensure the string does not go past a null, but can be up to 256 bytes long if one not found + string d(start, null_pos); Debug_printf("\naux1: %u aux2: %u path %s", _aux1, _aux2, d.c_str()); From 73e792bf2bd4704be7c066b81849780832a4d783 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Sun, 15 Oct 2023 14:06:49 +0100 Subject: [PATCH 118/158] Add CRLF to couple of network-protocol debug statements --- lib/network-protocol/HTTP.cpp | 2 +- lib/network-protocol/Protocol.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/network-protocol/HTTP.cpp b/lib/network-protocol/HTTP.cpp index 0ea3057e1..cd0eee849 100755 --- a/lib/network-protocol/HTTP.cpp +++ b/lib/network-protocol/HTTP.cpp @@ -509,7 +509,7 @@ bool NetworkProtocolHTTP::write_file_handle_set_header(uint8_t *buf, unsigned sh if (pos == string::npos) return true; - Debug_printf("NetworkProtocolHTTP::write_file_set_header(%s,%s)", incomingHeader.substr(0, pos).c_str(), incomingHeader.substr(pos + 2).c_str()); + Debug_printf("NetworkProtocolHTTP::write_file_set_header(%s,%s)\r\n", incomingHeader.substr(0, pos).c_str(), incomingHeader.substr(pos + 2).c_str()); client->set_header(incomingHeader.substr(0, pos).c_str(), incomingHeader.substr(pos + 2).c_str()); return false; diff --git a/lib/network-protocol/Protocol.cpp b/lib/network-protocol/Protocol.cpp index 8033d73ca..894544b13 100755 --- a/lib/network-protocol/Protocol.cpp +++ b/lib/network-protocol/Protocol.cpp @@ -103,7 +103,7 @@ bool NetworkProtocol::open(EdUrlParser *urlParser, cmdFrame_t *cmdFrame) // Set translation mode, Bits 0-1 of aux2 translation_mode = cmdFrame->aux2 & 0x7F; // we now have more xlation modes. - Debug_printf("translation mode = %u",translation_mode); + Debug_printf("translation mode = %u\r\n",translation_mode); // Persist aux1/aux2 values for later. aux1_open = cmdFrame->aux1; From e873961258c52782fed8edd66ebbf60b4b212b46 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Sun, 15 Oct 2023 14:08:16 +0100 Subject: [PATCH 119/158] atari read_dir block (new) free debug hexdump memory --- lib/device/sio/fuji.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/device/sio/fuji.cpp b/lib/device/sio/fuji.cpp index 0630300b0..70c7d5a9f 100644 --- a/lib/device/sio/fuji.cpp +++ b/lib/device/sio/fuji.cpp @@ -1191,6 +1191,7 @@ void sioFuji::sio_read_directory_block() Debug_printf("Actual data size: %d to atari\n", response.size()); char *s = util_hexdump(response.data(), response.size()); Debug_printf("dump: \n%s\n", s); + free(s); // buffer with 0s to requested size response.resize(response_max, 0); From d2b2aef4aac1d6dea4db6e88a3c0030d99f9e5cf Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 15 Oct 2023 14:14:34 -0500 Subject: [PATCH 120/158] [adam][rom] read in chunks to avoid contention. --- lib/media/adam/mediaTypeROM.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/media/adam/mediaTypeROM.cpp b/lib/media/adam/mediaTypeROM.cpp index 34de7dbb0..7974a1bad 100644 --- a/lib/media/adam/mediaTypeROM.cpp +++ b/lib/media/adam/mediaTypeROM.cpp @@ -5,6 +5,9 @@ #include #include "../../include/debug.h" +#include "fnSystem.h" + +#define ROM_BLOCK_SIZE 512 MediaTypeROM::MediaTypeROM() { @@ -56,6 +59,8 @@ bool MediaTypeROM::format(uint16_t *responsesize) mediatype_t MediaTypeROM::mount(FILE *f, uint32_t disksize) { + uint16_t o = 0; + Debug_print("ROM MOUNT\r\n"); _media_fileh = f; @@ -65,10 +70,27 @@ mediatype_t MediaTypeROM::mount(FILE *f, uint32_t disksize) disksize = 32768; // Load ROM into memory. - if (fread(rom, 1, disksize, f) != disksize) + // Do this and yield in chonks so we don't starve the other threads + + while (disksize) { - _media_fileh = nullptr; - return MEDIATYPE_UNKNOWN; + uint16_t rsz = (disksize > ROM_BLOCK_SIZE ? ROM_BLOCK_SIZE : disksize); + + Debug_printf("Reading %u bytes, %u bytes remaining\n",rsz,disksize); + + if (fread(&rom[o], sizeof(uint8_t), rsz, f) != rsz) + { + fclose(f); + _media_fileh = nullptr; + return MEDIATYPE_UNKNOWN; + } + else + { + o += rsz; + disksize -= rsz; + } + + fnSystem.yield(); // Let the system breathe. } return _mediatype; From 16a723006e3988a1a6e85010ec24615944540e82 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 15 Oct 2023 15:06:50 -0500 Subject: [PATCH 121/158] [adam][rom] let everything breathe. --- lib/media/adam/mediaTypeROM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/media/adam/mediaTypeROM.cpp b/lib/media/adam/mediaTypeROM.cpp index 7974a1bad..066608a45 100644 --- a/lib/media/adam/mediaTypeROM.cpp +++ b/lib/media/adam/mediaTypeROM.cpp @@ -90,7 +90,7 @@ mediatype_t MediaTypeROM::mount(FILE *f, uint32_t disksize) disksize -= rsz; } - fnSystem.yield(); // Let the system breathe. + fnSystem.delay(100); } return _mediatype; From 0fc385dff49a3c8510a475d1e1348af3ac147644 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 15 Oct 2023 15:34:03 -0500 Subject: [PATCH 122/158] [adam][rom] stream from source like all other media types. --- lib/media/adam/mediaTypeROM.cpp | 101 +++++++++++++++++++++----------- lib/media/adam/mediaTypeROM.h | 3 + 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/lib/media/adam/mediaTypeROM.cpp b/lib/media/adam/mediaTypeROM.cpp index 066608a45..521f3afe2 100644 --- a/lib/media/adam/mediaTypeROM.cpp +++ b/lib/media/adam/mediaTypeROM.cpp @@ -11,7 +11,7 @@ MediaTypeROM::MediaTypeROM() { - rom=(char *)malloc(32768); + rom = (char *)malloc(32768); } MediaTypeROM::~MediaTypeROM() @@ -19,25 +19,82 @@ MediaTypeROM::~MediaTypeROM() free(rom); } +// Returns byte offset of given sector number +uint32_t MediaTypeROM::_block_to_offset(uint32_t blockNum) +{ + return blockNum * 1024; +} + // Returns TRUE if an error condition occurred bool MediaTypeROM::read(uint32_t blockNum, uint16_t *readcount) { + bool err = false; + + if (blockNum == _media_last_block) + return false; // We already have block. + + Debug_print("ROM READ\r\n"); + + // Return an error if we're trying to read beyond the end of the disk + if (blockNum > _media_num_blocks - 1) + { + Debug_printf("::read block %d > %d\r\n", blockNum, _media_num_blocks); + _media_controller_status = 2; + return true; + } + + memset(_media_blockbuff, 0, sizeof(_media_blockbuff)); + if (blockNum == 0) + { memcpy(_media_blockbuff, block0, sizeof(_media_blockbuff)); + } else if (blockNum == 1) + { memcpy(_media_blockbuff, block1, sizeof(_media_blockbuff)); - else + } + else // (blocknum > 1) { - blockNum -= 2; - if (blockNum < 32) - memcpy(_media_blockbuff, &rom[blockNum * 1024], sizeof(_media_blockbuff)); + // // Perform a seek if we're not reading the sector after the last one we read + uint32_t offset = _block_to_offset(blockNum - 2); // minus the two boot blocks + err = fseek(_media_fileh, offset, SEEK_SET) != 0; + _media_last_block = INVALID_SECTOR_VALUE; + + if (err == false) + err = fread(_media_blockbuff, 1, 1024, _media_fileh) != 1024; + + if (err == false) + { + _media_last_block = blockNum; + _media_controller_status = 0; + return false; + } else { + _media_last_block = INVALID_SECTOR_VALUE; _media_controller_status = 2; return true; } } - return false; + return err; + + // The old code is here. + // if (blockNum == 0) + // memcpy(_media_blockbuff, block0, sizeof(_media_blockbuff)); + // else if (blockNum == 1) + // memcpy(_media_blockbuff, block1, sizeof(_media_blockbuff)); + // else + // { + // blockNum -= 2; + // if (blockNum < 32) + // memcpy(_media_blockbuff, &rom[blockNum * 1024], sizeof(_media_blockbuff)); + // else + // { + // _media_controller_status = 2; + // return true; + // } + // } + // return false; } // Returns TRUE if an error condition occurred @@ -59,40 +116,14 @@ bool MediaTypeROM::format(uint16_t *responsesize) mediatype_t MediaTypeROM::mount(FILE *f, uint32_t disksize) { - uint16_t o = 0; - Debug_print("ROM MOUNT\r\n"); _media_fileh = f; _mediatype = MEDIATYPE_ROM; + _media_num_blocks = disksize / 1024; + _media_num_blocks += 2; // to account for the two boot blocks. - if (disksize > 32768) - disksize = 32768; - - // Load ROM into memory. - // Do this and yield in chonks so we don't starve the other threads - - while (disksize) - { - uint16_t rsz = (disksize > ROM_BLOCK_SIZE ? ROM_BLOCK_SIZE : disksize); - - Debug_printf("Reading %u bytes, %u bytes remaining\n",rsz,disksize); - - if (fread(&rom[o], sizeof(uint8_t), rsz, f) != rsz) - { - fclose(f); - _media_fileh = nullptr; - return MEDIATYPE_UNKNOWN; - } - else - { - o += rsz; - disksize -= rsz; - } - - fnSystem.delay(100); - } - + Debug_printv("FLAGS: %x\n", _media_fileh->_flags); return _mediatype; } diff --git a/lib/media/adam/mediaTypeROM.h b/lib/media/adam/mediaTypeROM.h index a22ec7341..8ab766b38 100644 --- a/lib/media/adam/mediaTypeROM.h +++ b/lib/media/adam/mediaTypeROM.h @@ -28,6 +28,9 @@ class MediaTypeROM : public MediaType MediaTypeROM(); virtual ~MediaTypeROM(); + // Returns byte offset of given sector number + virtual uint32_t _block_to_offset(uint32_t blockNum); + virtual bool read(uint32_t blockNum, uint16_t *readcount) override; virtual bool write(uint32_t blockNum, bool verify) override; From 36b8d39d2451a88319e448b38f271a6e1ce2ba82 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 15 Oct 2023 15:53:38 -0500 Subject: [PATCH 123/158] [adam] add alwaysinternal override specifically for adam. --- sdkconfig.fujinet-adam-v1 | 2272 +++++++++++++++++++++++++++++++++++++ 1 file changed, 2272 insertions(+) create mode 100644 sdkconfig.fujinet-adam-v1 diff --git a/sdkconfig.fujinet-adam-v1 b/sdkconfig.fujinet-adam-v1 new file mode 100644 index 000000000..52b703b1c --- /dev/null +++ b/sdkconfig.fujinet-adam-v1 @@ -0,0 +1,2272 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Configuration +# +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" +CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" +CONFIG_SOC_DPORT_WORKAROUND="Not determined" +CONFIG_SOC_CAPS_ECO_VER_MAX=301 +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_DAC_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_SDMMC_HOST_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_SDIO_SLAVE_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_EMAC_SUPPORTED=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y +CONFIG_SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL=5 +CONFIG_SOC_XTAL_SUPPORT_26M=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_XTAL_SUPPORT_AUTO_DETECT=y +CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=2 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2 +CONFIG_SOC_ADC_PATT_LEN_MAX=16 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=2 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=2 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=20 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=9 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_RTC_SLOW_CLOCK_SUPPORT_8MD256=y +CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=5 +CONFIG_SOC_CPU_CORES_NUM=2 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FPU=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINT_SIZE=64 +CONFIG_SOC_DAC_PERIPH_NUM=2 +CONFIG_SOC_DAC_RESOLUTION=8 +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=40 +CONFIG_SOC_GPIO_VALID_GPIO_MASK=0xFFFFFFFFFF +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_APB=y +CONFIG_SOC_CLK_APLL_SUPPORTED=y +CONFIG_SOC_APLL_MULTIPLIER_OUT_MIN_HZ=350000000 +CONFIG_SOC_APLL_MULTIPLIER_OUT_MAX_HZ=500000000 +CONFIG_SOC_APLL_MIN_HZ=5303031 +CONFIG_SOC_APLL_MAX_HZ=125000000 +CONFIG_SOC_I2S_NUM=2 +CONFIG_SOC_I2S_HW_VERSION_1=y +CONFIG_SOC_I2S_SUPPORTS_APLL=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y +CONFIG_SOC_I2S_SUPPORTS_ADC=y +CONFIG_SOC_I2S_SUPPORTS_DAC=y +CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y +CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y +CONFIG_SOC_I2S_LCD_I80_VARIANT=y +CONFIG_SOC_LCD_I80_SUPPORTED=y +CONFIG_SOC_LCD_I80_BUSES=2 +CONFIG_SOC_LCD_I80_BUS_WIDTH=24 +CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y +CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y +CONFIG_SOC_LEDC_CHANNEL_NUM=8 +CONFIG_SOC_LEDC_TIMER_BIT_WIDE_NUM=20 +CONFIG_SOC_MCPWM_GROUPS=2 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=8 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=8 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=64 +CONFIG_SOC_RMT_SUPPORT_REF_TICK=y +CONFIG_SOC_RMT_SUPPORT_APB=y +CONFIG_SOC_RMT_CHANNEL_CLK_INDEPENDENT=y +CONFIG_SOC_RTCIO_PIN_COUNT=18 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_SDM_GROUPS=1 +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8 +CONFIG_SOC_SPI_HD_BOTH_INOUT_SUPPORTED=y +CONFIG_SOC_SPI_AS_CS_SUPPORTED=y +CONFIG_SOC_SPI_PERIPH_NUM=3 +CONFIG_SOC_SPI_DMA_CHAN_NUM=2 +CONFIG_SOC_SPI_MAX_CS_NUM=3 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=8192 +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 +CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y +CONFIG_SOC_TOUCH_VERSION_1=y +CONFIG_SOC_TOUCH_SENSOR_NUM=10 +CONFIG_SOC_TOUCH_PAD_MEASURE_WAIT_MAX=0xFF +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +CONFIG_SOC_UART_SUPPORT_REF_TICK=y +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_SPIRAM_SUPPORTED=y +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SHA_SUPPORT_SHA384=y +CONFIG_SOC_SHA_SUPPORT_SHA512=y +CONFIG_SOC_RSA_MAX_BIT_LEN=4096 +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_192=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_SECURE_BOOT_V1=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32 +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_FAST_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_SLOW_MEM_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_SDMMC_USE_IOMUX=y +CONFIG_SOC_SDMMC_NUM_SLOTS=2 +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_BT_CLASSIC_SUPPORTED=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET_ARCH="xtensa" +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# end of Build type + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=2 +# CONFIG_BOOTLOADER_SPI_CUSTOM_WP_PIN is not set +CONFIG_BOOTLOADER_SPI_WP_PIN=7 +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V1_SUPPORTED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +# CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_NONE is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NORM=y +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +CONFIG_COMPILER_STACK_CHECK=y +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=y +# CONFIG_BT_NIMBLE_ENABLED is not set +# CONFIG_BT_CONTROLLER_ONLY is not set +CONFIG_BT_CONTROLLER_ENABLED=y +# CONFIG_BT_CONTROLLER_DISABLED is not set + +# +# Bluedroid Options +# +CONFIG_BT_BTC_TASK_STACK_SIZE=3072 +CONFIG_BT_BLUEDROID_PINNED_TO_CORE_0=y +# CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1 is not set +CONFIG_BT_BLUEDROID_PINNED_TO_CORE=0 +CONFIG_BT_BTU_TASK_STACK_SIZE=4096 +# CONFIG_BT_BLUEDROID_MEM_DEBUG is not set +CONFIG_BT_CLASSIC_ENABLED=y +# CONFIG_BT_A2DP_ENABLE is not set +CONFIG_BT_SPP_ENABLED=y +# CONFIG_BT_L2CAP_ENABLED is not set +# CONFIG_BT_HFP_ENABLE is not set +# CONFIG_BT_HID_ENABLED is not set +CONFIG_BT_SSP_ENABLED=y +# CONFIG_BT_BLE_ENABLED is not set +# CONFIG_BT_STACK_NO_LOG is not set + +# +# BT DEBUG LOG LEVEL +# +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_HCI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_HCI_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BTM_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BTM_TRACE_LEVEL=2 +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2 +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_SDP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_SDP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_GAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_GAP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_PAN_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_PAN_TRACE_LEVEL=2 +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_A2D_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_A2D_TRACE_LEVEL=2 +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2 +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2 +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2 +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_MCA_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_MCA_TRACE_LEVEL=2 +# CONFIG_BT_LOG_HID_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_HID_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_HID_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_HID_TRACE_LEVEL=2 +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_APPL_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_APPL_TRACE_LEVEL=2 +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_GATT_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_GATT_TRACE_LEVEL=2 +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_SMP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_SMP_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BTC_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BTC_TRACE_LEVEL=2 +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_OSI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_OSI_TRACE_LEVEL=2 +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_NONE is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_ERROR is not set +CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_API is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_EVENT is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2 +# end of BT DEBUG LOG LEVEL + +CONFIG_BT_ACL_CONNECTIONS=4 +CONFIG_BT_MULTI_CONNECTION_ENBALE=y +CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y +CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y +# CONFIG_BT_BLE_HOST_QUEUE_CONG_CHECK is not set +CONFIG_BT_SMP_ENABLE=y +CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT=30 +CONFIG_BT_MAX_DEVICE_NAME_LEN=32 +# CONFIG_BT_BLE_RPA_SUPPORTED is not set +# end of Bluedroid Options + +# +# Controller Options +# +# CONFIG_BTDM_CTRL_MODE_BLE_ONLY is not set +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y +# CONFIG_BTDM_CTRL_MODE_BTDM is not set +CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=2 +CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0 +# CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set +CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM=y +CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=1 +CONFIG_BTDM_CTRL_PCM_ROLE_EDGE_CONFIG=y +CONFIG_BTDM_CTRL_PCM_ROLE_MASTER=y +# CONFIG_BTDM_CTRL_PCM_ROLE_SLAVE is not set +CONFIG_BTDM_CTRL_PCM_POLAR_FALLING_EDGE=y +# CONFIG_BTDM_CTRL_PCM_POLAR_RISING_EDGE is not set +CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 +CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 +CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT=y +CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF=y +CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 +CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2 +CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 +CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y +# CONFIG_BTDM_CTRL_PINNED_TO_CORE_1 is not set +CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 +CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y +# CONFIG_BTDM_CTRL_HCI_MODE_UART_H4 is not set + +# +# MODEM SLEEP Options +# +CONFIG_BTDM_CTRL_MODEM_SLEEP=y +CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG=y +# CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED is not set +CONFIG_BTDM_CTRL_LPCLK_SEL_MAIN_XTAL=y +# end of MODEM SLEEP Options + +CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 +CONFIG_BTDM_RESERVE_DRAM=0xdb5c +CONFIG_BTDM_CTRL_HLI=y +# end of Controller Options +# end of Bluetooth + +# CONFIG_BLE_MESH is not set + +# +# Driver Configurations +# + +# +# Legacy ADC Configuration +# +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y +CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CAL_LUT_ENABLE=y +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Configuration + +# +# SPI Configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI Configuration + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y +CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y +CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y +CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y +CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y +# end of TWAI Configuration + +# +# UART Configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART Configuration + +# +# GPIO Configuration +# +# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of GPIO Configuration + +# +# Sigma Delta Modulator Configuration +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of Sigma Delta Modulator Configuration + +# +# GPTimer Configuration +# +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of GPTimer Configuration + +# +# PCNT Configuration +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of PCNT Configuration + +# +# RMT Configuration +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of RMT Configuration + +# +# MCPWM Configuration +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of MCPWM Configuration + +# +# I2S Configuration +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of I2S Configuration +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set +CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y +# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set +CONFIG_EFUSE_MAX_BLK_LEN=192 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +CONFIG_ESP_TLS_INSECURE=y +CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set + +# +# ADC Calibration Configurations +# +CONFIG_ADC_CALI_EFUSE_TP_ENABLE=y +CONFIG_ADC_CALI_EFUSE_VREF_ENABLE=y +CONFIG_ADC_CALI_LUT_ENABLE=y +# end of ADC Calibration Configurations + +CONFIG_ADC_DISABLE_DAC_OUTPUT=y +# end of ADC and ADC Calibration + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +CONFIG_ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_ESP32_EMAC=y +CONFIG_ETH_PHY_INTERFACE_RMII=y +CONFIG_ETH_RMII_CLK_INPUT=y +# CONFIG_ETH_RMII_CLK_OUTPUT is not set +CONFIG_ETH_RMII_CLK_IN_GPIO=0 +CONFIG_ETH_DMA_BUFFER_SIZE=512 +CONFIG_ETH_DMA_RX_BUFFER_NUM=10 +CONFIG_ETH_DMA_TX_BUFFER_NUM=10 +CONFIG_ETH_USE_SPI_ETHERNET=y +CONFIG_ETH_SPI_ETHERNET_DM9051=y +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +CONFIG_HTTPD_WS_SUPPORT=y +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32_REV_MIN_0=y +# CONFIG_ESP32_REV_MIN_1 is not set +# CONFIG_ESP32_REV_MIN_1_1 is not set +# CONFIG_ESP32_REV_MIN_2 is not set +# CONFIG_ESP32_REV_MIN_3 is not set +# CONFIG_ESP32_REV_MIN_3_1 is not set +CONFIG_ESP32_REV_MIN=0 +CONFIG_ESP32_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32 Revision (Rev v3.99) +# +CONFIG_ESP32_REV_MAX_FULL=399 +CONFIG_ESP_REV_MAX_FULL=399 +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR is not set +# end of MAC Config + +# +# Sleep Config +# +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set +CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set +CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000 +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +# CONFIG_PERIPH_CTRL_FUNC_IN_IRAM is not set +# end of Peripheral Control + +# +# Main XTAL Config +# +# CONFIG_XTAL_FREQ_26 is not set +CONFIG_XTAL_FREQ_40=y +# CONFIG_XTAL_FREQ_AUTO is not set +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config +# end of Hardware Settings + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# end of ESP NETIF Adapter + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +CONFIG_ESP_PHY_REDUCE_TX_POWER=y +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +# end of Power Management + +# +# ESP PSRAM +# +CONFIG_SPIRAM=y + +# +# SPI RAM config +# +CONFIG_SPIRAM_MODE_QUAD=y +CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SPEED_40M=y +# CONFIG_SPIRAM_SPEED_80M is not set +CONFIG_SPIRAM_SPEED=40 +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_USE_MEMMAP is not set +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +CONFIG_SPIRAM_USE_MALLOC=y +# CONFIG_SPIRAM_MEMTEST is not set +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=32768 +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set +CONFIG_SPIRAM_CACHE_WORKAROUND=y + +# +# SPIRAM cache workaround debugging +# +CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set +# end of SPIRAM cache workaround debugging + +# +# SPIRAM workaround libraries placement +# +CONFIG_SPIRAM_CACHE_LIBJMP_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBMATH_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBIO_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBTIME_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBCHAR_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBMEM_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBSTR_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBRAND_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBENV_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBFILE_IN_IRAM=y +CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM=y +# end of SPIRAM workaround libraries placement + +CONFIG_SPIRAM_BANKSWITCH_ENABLE=y +CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 +# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set + +# +# PSRAM clock and cs IO for ESP32-DOWD +# +CONFIG_D0WD_PSRAM_CLK_IO=17 +CONFIG_D0WD_PSRAM_CS_IO=16 +# end of PSRAM clock and cs IO for ESP32-DOWD + +# +# PSRAM clock and cs IO for ESP32-D2WD +# +CONFIG_D2WD_PSRAM_CLK_IO=9 +CONFIG_D2WD_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-D2WD + +# +# PSRAM clock and cs IO for ESP32-PICO +# +CONFIG_PICO_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-PICO + +# CONFIG_SPIRAM_2T_MODE is not set +# end of SPI RAM config +# end of ESP PSRAM + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240 + +# +# Memory +# +# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set +# end of Memory + +# +# Trace memory +# +# CONFIG_ESP32_TRAX is not set +CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 +# end of Trace memory + +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=800 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=0 +# end of Brownout Detector + +# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_TG0_LAC=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=128 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=32 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=32 +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +# CONFIG_ESP32_WIFI_IRAM_OPT is not set +# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +# CONFIG_FATFS_SECTOR_512 is not set +# CONFIG_FATFS_SECTOR_1024 is not set +# CONFIG_FATFS_SECTOR_2048 is not set +CONFIG_FATFS_SECTOR_4096=y +CONFIG_FATFS_SECTORS_PER_CLUSTER_1=y +# CONFIG_FATFS_SECTORS_PER_CLUSTER_2 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_4 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_8 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_16 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_32 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_64 is not set +# CONFIG_FATFS_SECTORS_PER_CLUSTER_128 is not set +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_AUTO_TYPE=y +# CONFIG_FATFS_FAT12 is not set +# CONFIG_FATFS_FAT16 is not set +CONFIG_FATFS_CODEPAGE=437 +# CONFIG_FATFS_LFN_NONE is not set +CONFIG_FATFS_LFN_HEAP=y +# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_MAX_LFN=255 +CONFIG_FATFS_API_ENCODING_ANSI_OEM=y +# CONFIG_FATFS_API_ENCODING_UTF_8 is not set +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_HZ=100 +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y +CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y +CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +# CONFIG_FREERTOS_FPU_IN_ISR is not set +CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y +CONFIG_FREERTOS_CORETIMER_0=y +# CONFIG_FREERTOS_CORETIMER_1 is not set +CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y +CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y +# CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK is not set +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# end of Port + +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +# CONFIG_HEAP_POISONING_DISABLED is not set +CONFIG_HEAP_POISONING_LIGHT=y +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +# CONFIG_HEAP_TRACING_OFF is not set +CONFIG_HEAP_TRACING_STANDALONE=y +# CONFIG_HEAP_TRACING_TOHOST is not set +CONFIG_HEAP_TRACING=y +CONFIG_HEAP_TRACING_STACK_DEPTH=2 +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# Log output +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +CONFIG_LOG_DEFAULT_LEVEL_ERROR=y +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=1 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_WARN is not set +# CONFIG_LOG_MAXIMUM_LEVEL_INFO is not set +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=1 +# CONFIG_LOG_COLORS is not set +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="fujinet" +# CONFIG_LWIP_NETIF_API is not set +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +CONFIG_LWIP_SO_RCVBUF=y +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=6 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534 +CONFIG_LWIP_TCP_WND_DEFAULT=65534 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=64 +# CONFIG_LWIP_TCP_QUEUE_OOSEQ is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +# CONFIG_LWIP_WND_SCALE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=64 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +CONFIG_LWIP_DEBUG=y +# CONFIG_LWIP_DEBUG_ESP_LOG is not set +# CONFIG_LWIP_NETIF_DEBUG is not set +# CONFIG_LWIP_PBUF_DEBUG is not set +# CONFIG_LWIP_ETHARP_DEBUG is not set +# CONFIG_LWIP_API_LIB_DEBUG is not set +# CONFIG_LWIP_SOCKETS_DEBUG is not set +# CONFIG_LWIP_IP_DEBUG is not set +# CONFIG_LWIP_ICMP_DEBUG is not set +# CONFIG_LWIP_DHCP_STATE_DEBUG is not set +# CONFIG_LWIP_DHCP_DEBUG is not set +# CONFIG_LWIP_IP6_DEBUG is not set +# CONFIG_LWIP_ICMP6_DEBUG is not set +# CONFIG_LWIP_TCP_DEBUG is not set +# CONFIG_LWIP_SNTP_DEBUG is not set +# CONFIG_LWIP_DNS_DEBUG is not set +# CONFIG_LWIP_BRIDGEIF_DEBUG is not set +# CONFIG_LWIP_BRIDGEIF_FDB_DEBUG is not set +# CONFIG_LWIP_BRIDGEIF_FW_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set +CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# CONFIG_MBEDTLS_CMAC_C is not set +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +CONFIG_MBEDTLS_POLY1305_C=y +CONFIG_MBEDTLS_CHACHA20_C=y +# CONFIG_MBEDTLS_CHACHAPOLY_C is not set +CONFIG_MBEDTLS_HKDF_C=y +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +# CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP is not set +# CONFIG_SPI_FLASH_SUPPORT_TH_CHIP is not set +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Root Hub configuration +# +# end of Root Hub configuration + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_BONDING is not set +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# +CONFIG_WPA_MBEDTLS_CRYPTO=y +CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# end of Supplicant + +# +# mDNS +# +CONFIG_MDNS_MAX_INTERFACES=3 +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +# CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES is not set +# CONFIG_MDNS_ENABLE_DEBUG_PRINTS is not set +# CONFIG_MDNS_RESPOND_REVERSE_QUERIES is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y + +# +# MDNS Predefined interfaces +# +CONFIG_MDNS_PREDEF_NETIF_STA=y +CONFIG_MDNS_PREDEF_NETIF_AP=y +CONFIG_MDNS_PREDEF_NETIF_ETH=y +# end of MDNS Predefined interfaces +# end of mDNS + +# +# LittleFS +# +CONFIG_LITTLEFS_MAX_PARTITIONS=3 +CONFIG_LITTLEFS_PAGE_SIZE=256 +CONFIG_LITTLEFS_OBJ_NAME_LEN=64 +CONFIG_LITTLEFS_READ_SIZE=128 +CONFIG_LITTLEFS_WRITE_SIZE=128 +CONFIG_LITTLEFS_LOOKAHEAD_SIZE=128 +CONFIG_LITTLEFS_CACHE_SIZE=512 +CONFIG_LITTLEFS_BLOCK_CYCLES=512 +CONFIG_LITTLEFS_USE_MTIME=y +# CONFIG_LITTLEFS_USE_ONLY_HASH is not set +# CONFIG_LITTLEFS_HUMAN_READABLE is not set +CONFIG_LITTLEFS_MTIME_USE_SECONDS=y +# CONFIG_LITTLEFS_MTIME_USE_NONCE is not set +# CONFIG_LITTLEFS_SPIFFS_COMPAT is not set +# CONFIG_LITTLEFS_FLUSH_FILE_EVERY_WRITE is not set +# end of LittleFS +# end of Component config + +# Deprecated options for backward compatibility +# CONFIG_NO_BLOBS is not set +# CONFIG_ESP32_NO_BLOBS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=2 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +CONFIG_FLASHMODE_QIO=y +# CONFIG_FLASHMODE_QOUT is not set +# CONFIG_FLASHMODE_DIO is not set +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +CONFIG_OPTIMIZATION_LEVEL_DEBUG=y +CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +# CONFIG_STACK_CHECK_NONE is not set +CONFIG_STACK_CHECK_NORM=y +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +CONFIG_STACK_CHECK=y +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_BLUEDROID_ENABLED=y +# CONFIG_NIMBLE_ENABLED is not set +CONFIG_BTC_TASK_STACK_SIZE=3072 +CONFIG_BLUEDROID_PINNED_TO_CORE_0=y +# CONFIG_BLUEDROID_PINNED_TO_CORE_1 is not set +CONFIG_BLUEDROID_PINNED_TO_CORE=0 +CONFIG_BTU_TASK_STACK_SIZE=4096 +# CONFIG_BLUEDROID_MEM_DEBUG is not set +CONFIG_CLASSIC_BT_ENABLED=y +# CONFIG_A2DP_ENABLE is not set +# CONFIG_HFP_ENABLE is not set +# CONFIG_HCI_TRACE_LEVEL_NONE is not set +# CONFIG_HCI_TRACE_LEVEL_ERROR is not set +CONFIG_HCI_TRACE_LEVEL_WARNING=y +# CONFIG_HCI_TRACE_LEVEL_API is not set +# CONFIG_HCI_TRACE_LEVEL_EVENT is not set +# CONFIG_HCI_TRACE_LEVEL_DEBUG is not set +# CONFIG_HCI_TRACE_LEVEL_VERBOSE is not set +CONFIG_HCI_INITIAL_TRACE_LEVEL=2 +# CONFIG_BTM_TRACE_LEVEL_NONE is not set +# CONFIG_BTM_TRACE_LEVEL_ERROR is not set +CONFIG_BTM_TRACE_LEVEL_WARNING=y +# CONFIG_BTM_TRACE_LEVEL_API is not set +# CONFIG_BTM_TRACE_LEVEL_EVENT is not set +# CONFIG_BTM_TRACE_LEVEL_DEBUG is not set +# CONFIG_BTM_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTM_INITIAL_TRACE_LEVEL=2 +# CONFIG_L2CAP_TRACE_LEVEL_NONE is not set +# CONFIG_L2CAP_TRACE_LEVEL_ERROR is not set +CONFIG_L2CAP_TRACE_LEVEL_WARNING=y +# CONFIG_L2CAP_TRACE_LEVEL_API is not set +# CONFIG_L2CAP_TRACE_LEVEL_EVENT is not set +# CONFIG_L2CAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_L2CAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_L2CAP_INITIAL_TRACE_LEVEL=2 +# CONFIG_RFCOMM_TRACE_LEVEL_NONE is not set +# CONFIG_RFCOMM_TRACE_LEVEL_ERROR is not set +CONFIG_RFCOMM_TRACE_LEVEL_WARNING=y +# CONFIG_RFCOMM_TRACE_LEVEL_API is not set +# CONFIG_RFCOMM_TRACE_LEVEL_EVENT is not set +# CONFIG_RFCOMM_TRACE_LEVEL_DEBUG is not set +# CONFIG_RFCOMM_TRACE_LEVEL_VERBOSE is not set +CONFIG_RFCOMM_INITIAL_TRACE_LEVEL=2 +# CONFIG_SDP_TRACE_LEVEL_NONE is not set +# CONFIG_SDP_TRACE_LEVEL_ERROR is not set +CONFIG_SDP_TRACE_LEVEL_WARNING=y +# CONFIG_SDP_TRACE_LEVEL_API is not set +# CONFIG_SDP_TRACE_LEVEL_EVENT is not set +# CONFIG_SDP_TRACE_LEVEL_DEBUG is not set +# CONFIG_SDP_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTH_LOG_SDP_INITIAL_TRACE_LEVEL=2 +# CONFIG_GAP_TRACE_LEVEL_NONE is not set +# CONFIG_GAP_TRACE_LEVEL_ERROR is not set +CONFIG_GAP_TRACE_LEVEL_WARNING=y +# CONFIG_GAP_TRACE_LEVEL_API is not set +# CONFIG_GAP_TRACE_LEVEL_EVENT is not set +# CONFIG_GAP_TRACE_LEVEL_DEBUG is not set +# CONFIG_GAP_TRACE_LEVEL_VERBOSE is not set +CONFIG_GAP_INITIAL_TRACE_LEVEL=2 +CONFIG_BNEP_INITIAL_TRACE_LEVEL=2 +# CONFIG_PAN_TRACE_LEVEL_NONE is not set +# CONFIG_PAN_TRACE_LEVEL_ERROR is not set +CONFIG_PAN_TRACE_LEVEL_WARNING=y +# CONFIG_PAN_TRACE_LEVEL_API is not set +# CONFIG_PAN_TRACE_LEVEL_EVENT is not set +# CONFIG_PAN_TRACE_LEVEL_DEBUG is not set +# CONFIG_PAN_TRACE_LEVEL_VERBOSE is not set +CONFIG_PAN_INITIAL_TRACE_LEVEL=2 +# CONFIG_A2D_TRACE_LEVEL_NONE is not set +# CONFIG_A2D_TRACE_LEVEL_ERROR is not set +CONFIG_A2D_TRACE_LEVEL_WARNING=y +# CONFIG_A2D_TRACE_LEVEL_API is not set +# CONFIG_A2D_TRACE_LEVEL_EVENT is not set +# CONFIG_A2D_TRACE_LEVEL_DEBUG is not set +# CONFIG_A2D_TRACE_LEVEL_VERBOSE is not set +CONFIG_A2D_INITIAL_TRACE_LEVEL=2 +# CONFIG_AVDT_TRACE_LEVEL_NONE is not set +# CONFIG_AVDT_TRACE_LEVEL_ERROR is not set +CONFIG_AVDT_TRACE_LEVEL_WARNING=y +# CONFIG_AVDT_TRACE_LEVEL_API is not set +# CONFIG_AVDT_TRACE_LEVEL_EVENT is not set +# CONFIG_AVDT_TRACE_LEVEL_DEBUG is not set +# CONFIG_AVDT_TRACE_LEVEL_VERBOSE is not set +CONFIG_AVDT_INITIAL_TRACE_LEVEL=2 +# CONFIG_AVCT_TRACE_LEVEL_NONE is not set +# CONFIG_AVCT_TRACE_LEVEL_ERROR is not set +CONFIG_AVCT_TRACE_LEVEL_WARNING=y +# CONFIG_AVCT_TRACE_LEVEL_API is not set +# CONFIG_AVCT_TRACE_LEVEL_EVENT is not set +# CONFIG_AVCT_TRACE_LEVEL_DEBUG is not set +# CONFIG_AVCT_TRACE_LEVEL_VERBOSE is not set +CONFIG_AVCT_INITIAL_TRACE_LEVEL=2 +# CONFIG_AVRC_TRACE_LEVEL_NONE is not set +# CONFIG_AVRC_TRACE_LEVEL_ERROR is not set +CONFIG_AVRC_TRACE_LEVEL_WARNING=y +# CONFIG_AVRC_TRACE_LEVEL_API is not set +# CONFIG_AVRC_TRACE_LEVEL_EVENT is not set +# CONFIG_AVRC_TRACE_LEVEL_DEBUG is not set +# CONFIG_AVRC_TRACE_LEVEL_VERBOSE is not set +CONFIG_AVRC_INITIAL_TRACE_LEVEL=2 +# CONFIG_MCA_TRACE_LEVEL_NONE is not set +# CONFIG_MCA_TRACE_LEVEL_ERROR is not set +CONFIG_MCA_TRACE_LEVEL_WARNING=y +# CONFIG_MCA_TRACE_LEVEL_API is not set +# CONFIG_MCA_TRACE_LEVEL_EVENT is not set +# CONFIG_MCA_TRACE_LEVEL_DEBUG is not set +# CONFIG_MCA_TRACE_LEVEL_VERBOSE is not set +CONFIG_MCA_INITIAL_TRACE_LEVEL=2 +# CONFIG_HID_TRACE_LEVEL_NONE is not set +# CONFIG_HID_TRACE_LEVEL_ERROR is not set +CONFIG_HID_TRACE_LEVEL_WARNING=y +# CONFIG_HID_TRACE_LEVEL_API is not set +# CONFIG_HID_TRACE_LEVEL_EVENT is not set +# CONFIG_HID_TRACE_LEVEL_DEBUG is not set +# CONFIG_HID_TRACE_LEVEL_VERBOSE is not set +CONFIG_HID_INITIAL_TRACE_LEVEL=2 +# CONFIG_APPL_TRACE_LEVEL_NONE is not set +# CONFIG_APPL_TRACE_LEVEL_ERROR is not set +CONFIG_APPL_TRACE_LEVEL_WARNING=y +# CONFIG_APPL_TRACE_LEVEL_API is not set +# CONFIG_APPL_TRACE_LEVEL_EVENT is not set +# CONFIG_APPL_TRACE_LEVEL_DEBUG is not set +# CONFIG_APPL_TRACE_LEVEL_VERBOSE is not set +CONFIG_APPL_INITIAL_TRACE_LEVEL=2 +# CONFIG_GATT_TRACE_LEVEL_NONE is not set +# CONFIG_GATT_TRACE_LEVEL_ERROR is not set +CONFIG_GATT_TRACE_LEVEL_WARNING=y +# CONFIG_GATT_TRACE_LEVEL_API is not set +# CONFIG_GATT_TRACE_LEVEL_EVENT is not set +# CONFIG_GATT_TRACE_LEVEL_DEBUG is not set +# CONFIG_GATT_TRACE_LEVEL_VERBOSE is not set +CONFIG_GATT_INITIAL_TRACE_LEVEL=2 +# CONFIG_SMP_TRACE_LEVEL_NONE is not set +# CONFIG_SMP_TRACE_LEVEL_ERROR is not set +CONFIG_SMP_TRACE_LEVEL_WARNING=y +# CONFIG_SMP_TRACE_LEVEL_API is not set +# CONFIG_SMP_TRACE_LEVEL_EVENT is not set +# CONFIG_SMP_TRACE_LEVEL_DEBUG is not set +# CONFIG_SMP_TRACE_LEVEL_VERBOSE is not set +CONFIG_SMP_INITIAL_TRACE_LEVEL=2 +# CONFIG_BTIF_TRACE_LEVEL_NONE is not set +# CONFIG_BTIF_TRACE_LEVEL_ERROR is not set +CONFIG_BTIF_TRACE_LEVEL_WARNING=y +# CONFIG_BTIF_TRACE_LEVEL_API is not set +# CONFIG_BTIF_TRACE_LEVEL_EVENT is not set +# CONFIG_BTIF_TRACE_LEVEL_DEBUG is not set +# CONFIG_BTIF_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTIF_INITIAL_TRACE_LEVEL=2 +# CONFIG_BTC_TRACE_LEVEL_NONE is not set +# CONFIG_BTC_TRACE_LEVEL_ERROR is not set +CONFIG_BTC_TRACE_LEVEL_WARNING=y +# CONFIG_BTC_TRACE_LEVEL_API is not set +# CONFIG_BTC_TRACE_LEVEL_EVENT is not set +# CONFIG_BTC_TRACE_LEVEL_DEBUG is not set +# CONFIG_BTC_TRACE_LEVEL_VERBOSE is not set +CONFIG_BTC_INITIAL_TRACE_LEVEL=2 +# CONFIG_OSI_TRACE_LEVEL_NONE is not set +# CONFIG_OSI_TRACE_LEVEL_ERROR is not set +CONFIG_OSI_TRACE_LEVEL_WARNING=y +# CONFIG_OSI_TRACE_LEVEL_API is not set +# CONFIG_OSI_TRACE_LEVEL_EVENT is not set +# CONFIG_OSI_TRACE_LEVEL_DEBUG is not set +# CONFIG_OSI_TRACE_LEVEL_VERBOSE is not set +CONFIG_OSI_INITIAL_TRACE_LEVEL=2 +# CONFIG_BLUFI_TRACE_LEVEL_NONE is not set +# CONFIG_BLUFI_TRACE_LEVEL_ERROR is not set +CONFIG_BLUFI_TRACE_LEVEL_WARNING=y +# CONFIG_BLUFI_TRACE_LEVEL_API is not set +# CONFIG_BLUFI_TRACE_LEVEL_EVENT is not set +# CONFIG_BLUFI_TRACE_LEVEL_DEBUG is not set +# CONFIG_BLUFI_TRACE_LEVEL_VERBOSE is not set +CONFIG_BLUFI_INITIAL_TRACE_LEVEL=2 +# CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK is not set +CONFIG_SMP_ENABLE=y +CONFIG_BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT=30 +# CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY is not set +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=y +# CONFIG_BTDM_CONTROLLER_MODE_BTDM is not set +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN=2 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN=0 +CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=2 +CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 +CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 +CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y +# CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4 is not set +CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=y +CONFIG_ADC2_DISABLE_DAC=y +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_OTA_ALLOW_HTTP is not set +# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set +CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y +CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y +CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y +# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set +# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set +# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set +# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set +CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 +# CONFIG_ESP32_XTAL_FREQ_26 is not set +CONFIG_ESP32_XTAL_FREQ_40=y +# CONFIG_ESP32_XTAL_FREQ_AUTO is not set +CONFIG_ESP32_XTAL_FREQ=40 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +CONFIG_REDUCE_PHY_TX_POWER=y +CONFIG_ESP32_REDUCE_PHY_TX_POWER=y +CONFIG_SPIRAM_SUPPORT=y +CONFIG_ESP32_SPIRAM_SUPPORT=y +CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=y +# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set +# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 +CONFIG_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32_PANIC_PRINT_HALT is not set +CONFIG_ESP32_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32_PANIC_GDBSTUB is not set +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4096 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=800 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +# CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set +# CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32_DEBUG_OCDAWARE=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_0=y +CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_BROWNOUT_DET_LVL=0 +CONFIG_ESP32_BROWNOUT_DET_LVL=0 +# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set +CONFIG_IPC_TASK_STACK_SIZE=1024 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_SW_COEXIST_ENABLE=y +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=2048 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=64 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=6 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=65534 +CONFIG_TCP_WND_DEFAULT=65534 +CONFIG_TCP_RECVMBOX_SIZE=64 +# CONFIG_TCP_QUEUE_OOSEQ is not set +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=64 +CONFIG_TCPIP_TASK_STACK_SIZE=4096 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_HRT=y +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_HRT is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_ESP32_ULP_COPROC_ENABLED is not set +# End of deprecated options From 1229c5c9e2b979e1f4a3a43ef67699c2754d8b66 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 15 Oct 2023 16:34:58 -0500 Subject: [PATCH 124/158] [adam] remove ESC cliff. --- .../device_specific/BUILD_ADAM/autorun.ddp | Bin 262144 -> 262144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_ADAM/autorun.ddp b/data/webui/device_specific/BUILD_ADAM/autorun.ddp index 999de603d9eba5d384936550a878e6eb6ff98c8c..e816b139b934433352f597e7de8a25520817bf88 100644 GIT binary patch delta 16055 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 GPyR1hEex&z From 156db1e23c81d62eac19fb9fc2599bff45fb7a76 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Mon, 16 Oct 2023 14:45:23 -0400 Subject: [PATCH 125/158] mac: coordinate number of DCDs w/ esp & pico --- lib/bus/mac/mac.cpp | 21 +++++++++++++++++++++ lib/bus/mac/mac.h | 4 ++++ lib/device/mac/floppy.cpp | 15 ++++++++++----- pico/mac/commands.c | 35 +++++++++++++++++++++++++---------- pico/mac/dcd_mux.pio | 3 +-- 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index a22c73423..04b3fa64a 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -150,6 +150,27 @@ void macBus::service(void) } } +void macBus::add_mount(char c) +{ + _mounted_disks |= 1 << (c - '0'); + // find maximum consecutively occupied disk slot + char d = 0; + while (_mounted_disks & (1 << d)) + d++; + fnUartBUS.write('h'); // harddisk + fnUartBUS.write(d); // number of DCD's in a contiguous daisy chain +} + +void macBus::rem_mount(char c) +{ + _mounted_disks &= ~(1 << (c - '0')); + char d = 0; + while (_mounted_disks & (1 << d)) + d++; + fnUartBUS.write('h'); // harddisk + fnUartBUS.write(d); // number of DCD's in a contiguous daisy chain +} + bool macBus::stepper_timeout() { unsigned long tn = fnSystem.micros(); diff --git a/lib/bus/mac/mac.h b/lib/bus/mac/mac.h index b0f515a7a..a4610af5a 100644 --- a/lib/bus/mac/mac.h +++ b/lib/bus/mac/mac.h @@ -83,6 +83,7 @@ class macBus const int _mac_baud_rate = 2000000; //230400; //was 115200; int _active_DCD_disk; + uint8_t _mounted_disks; public: std::forward_list _daisyChain; @@ -105,6 +106,9 @@ class macBus bool getShuttingDown() { return shuttingDown; }; // bool en35Host = false; // TRUE if we are connected to a host that supports the /EN35 signal + void add_mount(char c); + void rem_mount(char c); + bool stepper_timeout(); unsigned long t0; bool track_not_copied; diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 70ba68562..5d5532132 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -52,12 +52,11 @@ mediatype_t macFloppy::mount(FILE *f, const char *filename, uint32_t disksize, m } break; case MEDIATYPE_DCD: - Debug_printf("\nMounting Media Type HDV for DCD"); + Debug_printf("\nMounting Media Type DSK for DCD"); device_active = true; _disk = new MediaTypeDCD(); mt = ((MediaTypeDCD *)_disk)->mount(f); - fnUartBUS.write('h'); // harddisk - fnUartBUS.write(id()); // DCD number + MAC.add_mount(id()); break; // case MEDIATYPE_DSK: // Debug_printf("\nMounting Media Type DSK"); @@ -133,6 +132,11 @@ void macFloppy::unmount() { // todo - check device type and call correct unmount() // ((MediaTypeMOOF *)_disk)->unmount(); + if (disktype() == mediatype_t::MEDIATYPE_MOOF) + ((MediaTypeMOOF *)_disk)->unmount(); + else + _disk->unmount(); + MAC.rem_mount(id()); } int IRAM_ATTR macFloppy::step() @@ -297,9 +301,10 @@ void macFloppy::dcd_status(uint8_t* payload) */ payload[7] = 1; payload[9] = 1; - payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // real HD20 says 0xe6; + payload[10] = 0x80 | 0x40 | 0x20 | 0x04 | 0x02; // real HD20 says 0xe6, which is same; if (readonly) {payload[10] |= 0x08;}; - + // no way to eject DCD's, so 0x10 and 0x02 cannot change. + payload[11] = (_disk_size_in_blocks >> 16) & 0xff; payload[12] = (_disk_size_in_blocks >> 8) & 0xff; payload[13] = _disk_size_in_blocks & 0xff; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 59eb979dc..4ae912570 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -16,6 +16,9 @@ #include "hardware/clocks.h" #include "hardware/pio.h" +#include "hardware/pio_instructions.h" +#include "hardware/regs/pio.h" +#include "hardware/regs/addressmap.h" #include "commands.pio.h" #include "echo.pio.h" @@ -80,12 +83,14 @@ uint32_t b[12]; char c; uint32_t olda; uint32_t active_disk_number; +uint num_dcd_drives; PIO pio_floppy = pio0; PIO pio_dcd = pio1; PIO pio_dcd_rw = pio0; uint pio_read_offset; uint pio_write_offset; +uint pio_mux_offset; void setup_esp_uart() { @@ -297,9 +302,9 @@ void setup() printf("Loaded DCD commands program at %d\n", offset); pio_dcd_commands(pio_dcd, SM_DCD_CMD, offset, MCI_CA0); - offset = pio_add_program(pio_dcd, &dcd_mux_program); - printf("Loaded DCD mux program at %d\n", offset); - pio_dcd_mux(pio_dcd, SM_DCD_MUX, offset, LATCH_OUT); + pio_mux_offset = pio_add_program(pio_dcd, &dcd_mux_program); + printf("Loaded DCD mux program at %d\n", pio_mux_offset); + pio_dcd_mux(pio_dcd, SM_DCD_MUX, pio_mux_offset, LATCH_OUT); pio_read_offset = pio_add_program(pio_dcd_rw, &dcd_read_program); printf("Loaded DCD read program at %d\n", pio_read_offset); @@ -482,7 +487,7 @@ void dcd_loop() // if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_MUX)) { - active_disk_number = NUM_DCD + 'A' - pio_sm_get_blocking(pio_dcd, SM_DCD_MUX); + active_disk_number = num_dcd_drives + 'A' - pio_sm_get_blocking(pio_dcd, SM_DCD_MUX); printf("%c", active_disk_number); uart_putc_raw(UART_ID, active_disk_number); } @@ -549,11 +554,19 @@ void dcd_loop() c = uart_getc(UART_ID); switch (c) { - case 'h': // harddisk is mounted - c = uart_getc(UART_ID); // char starting with '0' - printf("\nHard Disk %c mounted", c); - // c is now the drive slot (DCD unit) number - // can add write protection info (or should move status packet generation to ESP32) + case 'h': // harddisk is mounted/unmounted + num_dcd_drives = uart_getc(UART_ID); + printf("\nNumber of DCD's mounted: %d", num_dcd_drives); + // need to set number in DCD mux PIO and reset the machine + // set x, N side 0 ; put the number of DCD devices in X (0xf02N - last digit is number of DCDs) + // uint instr = 0xf020 + num_dcd_drives; + // pause the machine, change the instruction, move the PC, resume + pio_sm_set_enabled(pio_dcd, SM_DCD_MUX, false); + volatile uint *target; + target = (uint *)(PIO1_BASE + PIO_INSTR_MEM0_OFFSET + 4*pio_mux_offset); + *target = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); + pio_sm_set_enabled(pio_dcd, SM_DCD_MUX, true); + pio_sm_exec(pio_dcd, SM_DCD_MUX, pio_encode_jmp(pio_mux_offset)); break; default: break; @@ -795,7 +808,9 @@ OR while (!uart_is_readable(UART_ID)) ; c = uart_getc(UART_ID); - assert(c=='w'); // error handling? + if (c=='e') + printf("\nMac WROTE TO READONLY DISK!\n"); + // assert(c=='w'); // error handling? // response packet memset(payload, 0, sizeof(payload)); payload[0] = (!verf) ? 0x81 : 0x82; diff --git a/pico/mac/dcd_mux.pio b/pico/mac/dcd_mux.pio index 3ab208d83..0d4f56861 100644 --- a/pico/mac/dcd_mux.pio +++ b/pico/mac/dcd_mux.pio @@ -8,7 +8,6 @@ .define public LSTRB 12 .define public ENABLE 7 -.define public NUM_DCD 2 ; The DCD mux will really control the RD line direction. ; It will ... @@ -22,7 +21,7 @@ ; we wait to be enabled then RD goes to output .wrap_target start: - set x, NUM_DCD side 0 ; put the number of DCD devices in X + set x, 0 side 0 ; put the number of DCD devices in X (0xf022 - last digit is number of DCDs) wait 0 gpio ENABLE ; don't do anything until we're enabled in x, 32 ; say we are at the first DCD jmp x-- cont ; decrement X to wait for the next strobe From b51c40ec4c0cd88668506ab282e27625883cf9f6 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Tue, 17 Oct 2023 20:08:04 -0400 Subject: [PATCH 126/158] mac: get floppy working again --- lib/bus/mac/mac.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 04b3fa64a..e40df6e52 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -65,14 +65,14 @@ void macBus::service(void) case 0: // set direction to increase track number Debug_printf("%c", 'I'); - theFuji.get_disks(0)->disk_dev.set_dir(+1); + theFuji.get_disks(4)->disk_dev.set_dir(+1); // fnUartBUS.write('I'); // fnUartBUS.flush(); break; case 4: // set direction to decrease track number Debug_printf("%c", 'D'); - theFuji.get_disks(0)->disk_dev.set_dir(-1); + theFuji.get_disks(4)->disk_dev.set_dir(-1); // fnUartBUS.write('D'); // fnUartBUS.flush(); break; @@ -82,7 +82,7 @@ void macBus::service(void) { t0 = fnSystem.micros(); track_not_copied = true; - int track_position = theFuji.get_disks(0)->disk_dev.step(); + int track_position = theFuji.get_disks(4)->disk_dev.step(); if (track_position < 0) { fnUartBUS.write('N'); From ab1faec0b5cc6e9e42d3f7027256e421fef27bf2 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Tue, 17 Oct 2023 20:17:19 -0400 Subject: [PATCH 127/158] mac: some fixing in macBus --- lib/bus/mac/mac.cpp | 18 +++++++++++------- lib/bus/mac/mac.h | 2 ++ lib/bus/mac/mac_ll.cpp | 4 ++-- lib/bus/mac/mac_ll.h | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index e40df6e52..41a4e6f45 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -90,14 +90,13 @@ void macBus::service(void) else { fnUartBUS.write(track_position | 128); // send the track position(/2) back - // fnUartBUS.flush(); } } break; case 2: // turn motor ons Debug_printf("\nMotor ON"); - floppy_ll.start(0); + floppy_ll.start(); fnUartBUS.write('M'); // fnUartBUS.flush(); break; @@ -150,13 +149,20 @@ void macBus::service(void) } } -void macBus::add_mount(char c) +char macBus::num_mounts() { - _mounted_disks |= 1 << (c - '0'); // find maximum consecutively occupied disk slot char d = 0; while (_mounted_disks & (1 << d)) d++; + return d; +} + +void macBus::add_mount(char c) +{ + _mounted_disks |= 1 << (c - '0'); + // find maximum consecutively occupied disk slot + char d = num_mounts(); fnUartBUS.write('h'); // harddisk fnUartBUS.write(d); // number of DCD's in a contiguous daisy chain } @@ -164,9 +170,7 @@ void macBus::add_mount(char c) void macBus::rem_mount(char c) { _mounted_disks &= ~(1 << (c - '0')); - char d = 0; - while (_mounted_disks & (1 << d)) - d++; + char d = num_mounts(); fnUartBUS.write('h'); // harddisk fnUartBUS.write(d); // number of DCD's in a contiguous daisy chain } diff --git a/lib/bus/mac/mac.h b/lib/bus/mac/mac.h index a4610af5a..0c14447e5 100644 --- a/lib/bus/mac/mac.h +++ b/lib/bus/mac/mac.h @@ -85,6 +85,8 @@ class macBus int _active_DCD_disk; uint8_t _mounted_disks; + char num_mounts(); + public: std::forward_list _daisyChain; diff --git a/lib/bus/mac/mac_ll.cpp b/lib/bus/mac/mac_ll.cpp index 4408edf0e..c8ace162b 100644 --- a/lib/bus/mac/mac_ll.cpp +++ b/lib/bus/mac/mac_ll.cpp @@ -804,13 +804,13 @@ void mac_ll::setup_gpio() #define RMT_TX_CHANNEL rmt_channel_t::RMT_CHANNEL_0 #define RMT_USEC (APB_CLK_FREQ / MHZ) -void mac_floppy_ll::start(uint8_t drive) +void mac_floppy_ll::start() { // floppy_ll.set_output_to_rmt(); // floppy_ll.enable_output(); ESP_ERROR_CHECK(fnRMT.rmt_write_bitstream(RMT_TX_CHANNEL, track_buffer[0], track_numbits[0], track_bit_period)); fnLedManager.set(LED_BUS, true); - Debug_printf("\nstart floppy %d : ",drive+1); + Debug_printf("\nstart floppy"); } void mac_floppy_ll::stop() diff --git a/lib/bus/mac/mac_ll.h b/lib/bus/mac/mac_ll.h index d32e7f464..db13d621e 100644 --- a/lib/bus/mac/mac_ll.h +++ b/lib/bus/mac/mac_ll.h @@ -188,7 +188,7 @@ class mac_floppy_ll : public mac_ll // Disk II handling by RMT peripheral void setup_rmt(); // install the RMT device - void start(uint8_t drive); + void start(); void stop(); // need a function to remove the RMT device? From 66aa040578b2e5b0e8815443fd75e9795ce2e057 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Tue, 17 Oct 2023 22:13:25 -0400 Subject: [PATCH 128/158] mac: drive slot 5 dedicated to floppy --- lib/bus/mac/mac.cpp | 16 ++++++++-------- lib/bus/mac/mac.h | 8 ++++---- lib/device/mac/floppy.cpp | 7 ++++--- pico/mac/commands.c | 13 ++++++++----- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 41a4e6f45..0a8f0d878 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -149,28 +149,28 @@ void macBus::service(void) } } -char macBus::num_mounts() +char macBus::num_dcd_mounts() { // find maximum consecutively occupied disk slot char d = 0; - while (_mounted_disks & (1 << d)) + while (_mounted_dcd_disks & (1 << d)) d++; return d; } -void macBus::add_mount(char c) +void macBus::add_dcd_mount(char c) { - _mounted_disks |= 1 << (c - '0'); + _mounted_dcd_disks |= 1 << (c - '0'); // find maximum consecutively occupied disk slot - char d = num_mounts(); + char d = num_dcd_mounts(); fnUartBUS.write('h'); // harddisk fnUartBUS.write(d); // number of DCD's in a contiguous daisy chain } -void macBus::rem_mount(char c) +void macBus::rem_dcd_mount(char c) { - _mounted_disks &= ~(1 << (c - '0')); - char d = num_mounts(); + _mounted_dcd_disks &= ~(1 << (c - '0')); + char d = num_dcd_mounts(); fnUartBUS.write('h'); // harddisk fnUartBUS.write(d); // number of DCD's in a contiguous daisy chain } diff --git a/lib/bus/mac/mac.h b/lib/bus/mac/mac.h index 0c14447e5..9a6f24300 100644 --- a/lib/bus/mac/mac.h +++ b/lib/bus/mac/mac.h @@ -83,9 +83,9 @@ class macBus const int _mac_baud_rate = 2000000; //230400; //was 115200; int _active_DCD_disk; - uint8_t _mounted_disks; + uint8_t _mounted_dcd_disks; - char num_mounts(); + char num_dcd_mounts(); public: std::forward_list _daisyChain; @@ -108,8 +108,8 @@ class macBus bool getShuttingDown() { return shuttingDown; }; // bool en35Host = false; // TRUE if we are connected to a host that supports the /EN35 signal - void add_mount(char c); - void rem_mount(char c); + void add_dcd_mount(char c); + void rem_dcd_mount(char c); bool stepper_timeout(); unsigned long t0; diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 5d5532132..8e6dfd09b 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -31,7 +31,7 @@ mediatype_t macFloppy::mount(FILE *f, const char *filename, uint32_t disksize, m case MEDIATYPE_MOOF: Debug_printf("\nMounting Media Type MOOF"); // init(); - device_active = true; + device_active = (id() == '4'); _disk = new MediaTypeMOOF(); mt = ((MediaTypeMOOF *)_disk)->mount(f); track_pos = 0; @@ -56,7 +56,7 @@ mediatype_t macFloppy::mount(FILE *f, const char *filename, uint32_t disksize, m device_active = true; _disk = new MediaTypeDCD(); mt = ((MediaTypeDCD *)_disk)->mount(f); - MAC.add_mount(id()); + MAC.add_dcd_mount(id()); break; // case MEDIATYPE_DSK: // Debug_printf("\nMounting Media Type DSK"); @@ -136,7 +136,8 @@ void macFloppy::unmount() ((MediaTypeMOOF *)_disk)->unmount(); else _disk->unmount(); - MAC.rem_mount(id()); + MAC.rem_dcd_mount(id()); + device_active = false; } int IRAM_ATTR macFloppy::step() diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 4ae912570..6b874fea3 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -4,10 +4,10 @@ * SPDX-License-Identifier: BSD-3-Clause */ -//#define FLOPPY -#undef FLOPPY -//#undef DCD -#define DCD +#define FLOPPY +//#undef FLOPPY +#undef DCD +//#define DCD #include #include @@ -259,6 +259,7 @@ void set_tach_freq(char c) void loop(); void dcd_loop(); +void floppy_loop(); void setup() { @@ -446,10 +447,12 @@ void floppy_loop() break; case 'S': // step complete (data copied to RMT buffer on ESP32) printf("\nStep sequence complete"); - // fall through????????????????????????????????????????? + clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met + break; case 'M': // motor on printf("\nMotor is on"); clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met + break; default: break; } From 929e74d3263833da2c7d2d65c7ed6e6c66f5c32f Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Wed, 18 Oct 2023 15:56:54 +0100 Subject: [PATCH 129/158] nulls after deletes General cleanup by having consistent approach to setting null after deleting a reference. --- lib/TNFSlib/tnfslibMountInfo.cpp | 3 +++ lib/bus/s100spi/s100spi.h | 4 ++++ lib/device/adamnet/disk.cpp | 3 +++ lib/device/adamnet/keyboard.cpp | 1 + lib/device/adamnet/modem.cpp | 1 + lib/device/adamnet/network.cpp | 3 +++ lib/device/adamnet/printer.cpp | 8 +++++++- lib/device/comlynx/disk.cpp | 3 +++ lib/device/comlynx/keyboard.cpp | 1 + lib/device/comlynx/modem.cpp | 1 + lib/device/comlynx/network.cpp | 8 ++++++++ lib/device/comlynx/printer.cpp | 8 +++++++- lib/device/cx16_i2c/disk.cpp | 3 +++ lib/device/cx16_i2c/modem.cpp | 1 + lib/device/cx16_i2c/modem.h | 2 +- lib/device/cx16_i2c/printer.cpp | 11 +++++++++-- lib/device/drivewire/modem.cpp | 1 + lib/device/drivewire/network.cpp | 11 +++++++++++ lib/device/drivewire/printer.cpp | 11 +++++++++-- lib/device/h89/modem.cpp | 1 + lib/device/h89/network.cpp | 8 ++++++++ lib/device/h89/printer.cpp | 6 +++++- lib/device/iec/modem.cpp | 1 + lib/device/iec/network.cpp | 5 +++++ lib/device/iec/printer.cpp | 6 +++++- lib/device/iwm/modem.cpp | 1 + lib/device/iwm/network.cpp | 8 ++++++++ lib/device/iwm/printer.cpp | 6 +++++- lib/device/mac/modem.cpp | 2 ++ lib/device/mac/printer.cpp | 6 +++++- lib/device/new/disk.cpp | 3 +++ lib/device/new/keyboard.cpp | 1 + lib/device/new/modem.cpp | 1 + lib/device/new/network.cpp | 8 ++++++++ lib/device/new/printer.cpp | 6 +++++- lib/device/new/serial.cpp | 1 + lib/device/rc2014/disk.cpp | 3 +++ lib/device/rc2014/modem.cpp | 1 + lib/device/rc2014/network.cpp | 8 ++++++++ lib/device/rc2014/printer.cpp | 6 +++++- lib/device/rs232/disk.cpp | 3 +++ lib/device/rs232/modem.cpp | 9 ++++++++- lib/device/rs232/network.cpp | 8 ++++++++ lib/device/rs232/printer.cpp | 6 +++++- lib/device/s100spi/disk.cpp | 3 +++ lib/device/s100spi/modem.cpp | 1 + lib/device/s100spi/network.cpp | 8 ++++++++ lib/device/s100spi/printer.cpp | 6 +++++- lib/device/s100spi/printer.h | 2 +- lib/device/sio/disk.cpp | 3 +++ lib/device/sio/network.cpp | 12 ++++++++++++ lib/device/sio/printer.cpp | 6 +++++- lib/ftp/fnFTP.cpp | 3 +++ lib/fuji/fujiHost.cpp | 1 + lib/media/atari/diskTypeAtx.cpp | 3 +++ lib/modem/modem.cpp | 1 + lib/network-protocol/FS.cpp | 1 + lib/network-protocol/FTP.cpp | 1 + lib/network-protocol/HTTP.cpp | 2 ++ lib/network-protocol/TCP.cpp | 1 - lib/utils/cbuf.cpp | 1 + platformio-sample.ini | 2 +- 62 files changed, 235 insertions(+), 20 deletions(-) diff --git a/lib/TNFSlib/tnfslibMountInfo.cpp b/lib/TNFSlib/tnfslibMountInfo.cpp index d6e92d3c7..34a6c2468 100644 --- a/lib/TNFSlib/tnfslibMountInfo.cpp +++ b/lib/TNFSlib/tnfslibMountInfo.cpp @@ -21,7 +21,10 @@ tnfsMountInfo::~tnfsMountInfo() for (int i = 0; i < TNFS_MAX_FILE_HANDLES; i++) { if (_file_handles[i] != nullptr) + { delete _file_handles[i]; + _file_handles[i] = nullptr; + } } // Delete any remaining directory cache entries empty_dircache(); diff --git a/lib/bus/s100spi/s100spi.h b/lib/bus/s100spi/s100spi.h index 3be22cfe7..993935266 100644 --- a/lib/bus/s100spi/s100spi.h +++ b/lib/bus/s100spi/s100spi.h @@ -229,6 +229,10 @@ class systemBus virtualDevice *deviceById(uint8_t device_id); void changeDeviceId(virtualDevice *pDevice, uint8_t device_id); QueueHandle_t qs100spiMessages = nullptr; + + bool shuttingDown = false; + bool getShuttingDown() { return shuttingDown; }; + }; extern systemBus s100Bus; diff --git a/lib/device/adamnet/disk.cpp b/lib/device/adamnet/disk.cpp index eb0b5b40c..638074093 100755 --- a/lib/device/adamnet/disk.cpp +++ b/lib/device/adamnet/disk.cpp @@ -23,7 +23,10 @@ adamDisk::adamDisk() adamDisk::~adamDisk() { if (_media != nullptr) + { delete _media; + _media = nullptr; + } } void adamDisk::reset() diff --git a/lib/device/adamnet/keyboard.cpp b/lib/device/adamnet/keyboard.cpp index 6a32a7d89..429f2f6cc 100644 --- a/lib/device/adamnet/keyboard.cpp +++ b/lib/device/adamnet/keyboard.cpp @@ -19,6 +19,7 @@ adamKeyboard::~adamKeyboard() // vTaskDelete(kbTask); server->stop(); delete server; + server = nullptr; } void adamKeyboard::adamnet_control_status() diff --git a/lib/device/adamnet/modem.cpp b/lib/device/adamnet/modem.cpp index 080462e79..c8fb4e198 100755 --- a/lib/device/adamnet/modem.cpp +++ b/lib/device/adamnet/modem.cpp @@ -87,6 +87,7 @@ adamModem::~adamModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/adamnet/network.cpp b/lib/device/adamnet/network.cpp index d08a34d63..110101a77 100755 --- a/lib/device/adamnet/network.cpp +++ b/lib/device/adamnet/network.cpp @@ -61,6 +61,9 @@ adamNetwork::~adamNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; if (protocol != nullptr) delete protocol; diff --git a/lib/device/adamnet/printer.cpp b/lib/device/adamnet/printer.cpp index df57f98d0..b81a48b62 100755 --- a/lib/device/adamnet/printer.cpp +++ b/lib/device/adamnet/printer.cpp @@ -72,7 +72,10 @@ adamPrinter::~adamPrinter() vTaskDelete(thPrinter); if (_pptr != nullptr) + { delete _pptr; + _pptr = nullptr; + } vQueueDelete(pxq); } @@ -147,7 +150,10 @@ void adamPrinter::shutdown() void adamPrinter::set_printer_type(printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/comlynx/disk.cpp b/lib/device/comlynx/disk.cpp index 0da15cc14..c0da7d43a 100755 --- a/lib/device/comlynx/disk.cpp +++ b/lib/device/comlynx/disk.cpp @@ -23,7 +23,10 @@ lynxDisk::lynxDisk() lynxDisk::~lynxDisk() { if (_media != nullptr) + { delete _media; + _media = nullptr; + } } void lynxDisk::reset() diff --git a/lib/device/comlynx/keyboard.cpp b/lib/device/comlynx/keyboard.cpp index 8a35e784c..2d4091509 100644 --- a/lib/device/comlynx/keyboard.cpp +++ b/lib/device/comlynx/keyboard.cpp @@ -19,6 +19,7 @@ lynxKeyboard::~lynxKeyboard() // vTaskDelete(kbTask); server->stop(); delete server; + server = nullptr; } void lynxKeyboard::comlynx_control_status() diff --git a/lib/device/comlynx/modem.cpp b/lib/device/comlynx/modem.cpp index 6f6d0653c..ee4e29daa 100755 --- a/lib/device/comlynx/modem.cpp +++ b/lib/device/comlynx/modem.cpp @@ -87,6 +87,7 @@ lynxModem::~lynxModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/comlynx/network.cpp b/lib/device/comlynx/network.cpp index acb65d816..b3418baa4 100755 --- a/lib/device/comlynx/network.cpp +++ b/lib/device/comlynx/network.cpp @@ -60,6 +60,14 @@ lynxNetwork::~lynxNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** LYNX COMMANDS ***************************************************************/ diff --git a/lib/device/comlynx/printer.cpp b/lib/device/comlynx/printer.cpp index 81d7a2ccc..b34744629 100755 --- a/lib/device/comlynx/printer.cpp +++ b/lib/device/comlynx/printer.cpp @@ -70,7 +70,10 @@ lynxPrinter::~lynxPrinter() vTaskDelete(thPrinter); if (_pptr != nullptr) + { delete _pptr; + _pptr = nullptr; + } } void lynxPrinter::start_printer_task() @@ -150,7 +153,10 @@ void lynxPrinter::shutdown() void lynxPrinter::set_printer_type(printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/cx16_i2c/disk.cpp b/lib/device/cx16_i2c/disk.cpp index 48a24e7f7..a78961a8b 100644 --- a/lib/device/cx16_i2c/disk.cpp +++ b/lib/device/cx16_i2c/disk.cpp @@ -88,7 +88,10 @@ mediatype_t cx16Disk::mount(FILE *f, const char *filename, uint32_t disksize, me cx16Disk::~cx16Disk() { if (_disk != nullptr) + { delete _disk; + _disk = nullptr; + } } // Unmount disk file diff --git a/lib/device/cx16_i2c/modem.cpp b/lib/device/cx16_i2c/modem.cpp index 4019d1759..444e94e43 100644 --- a/lib/device/cx16_i2c/modem.cpp +++ b/lib/device/cx16_i2c/modem.cpp @@ -11,6 +11,7 @@ cx16Modem::cx16Modem(FileSystem *_fs, bool snifferEnable) cx16Modem::~cx16Modem() { delete modemSniffer; + modemSniffer = nullptr; } #endif /* BUILD_CX16 */ diff --git a/lib/device/cx16_i2c/modem.h b/lib/device/cx16_i2c/modem.h index c58d38a6a..b7034b1ad 100644 --- a/lib/device/cx16_i2c/modem.h +++ b/lib/device/cx16_i2c/modem.h @@ -10,8 +10,8 @@ class cx16Modem : public virtualDevice { private: - ModemSniffer* modemSniffer; FileSystem *activeFS; + ModemSniffer* modemSniffer; time_t _lasttime = 0; public: diff --git a/lib/device/cx16_i2c/printer.cpp b/lib/device/cx16_i2c/printer.cpp index 909142f1a..7642354e0 100644 --- a/lib/device/cx16_i2c/printer.cpp +++ b/lib/device/cx16_i2c/printer.cpp @@ -35,7 +35,11 @@ constexpr const char * const cx16Printer::printer_model_str[PRINTER_INVALID]; cx16Printer::~cx16Printer() { - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + _pptr = nullptr; + } } // write for W commands @@ -158,7 +162,10 @@ void cx16Printer::status() void cx16Printer::set_printer_type(cx16Printer::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/drivewire/modem.cpp b/lib/device/drivewire/modem.cpp index fc5094132..a2a819ab1 100644 --- a/lib/device/drivewire/modem.cpp +++ b/lib/device/drivewire/modem.cpp @@ -95,6 +95,7 @@ drivewireModem::~drivewireModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/drivewire/network.cpp b/lib/device/drivewire/network.cpp index b3d81e07a..2fb9f4d79 100755 --- a/lib/device/drivewire/network.cpp +++ b/lib/device/drivewire/network.cpp @@ -54,6 +54,14 @@ drivewireNetwork::~drivewireNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** DRIVEWIRE COMMANDS ***************************************************************/ @@ -403,7 +411,10 @@ bool drivewireNetwork::parseURL() string unit = deviceSpec.substr(0, deviceSpec.find_first_of(":") + 1); if (urlParser != nullptr) + { delete urlParser; + urlParser = nullptr; + } // Prepend prefix, if set. if (prefix.length() > 0) diff --git a/lib/device/drivewire/printer.cpp b/lib/device/drivewire/printer.cpp index 25aac483a..a469f6925 100755 --- a/lib/device/drivewire/printer.cpp +++ b/lib/device/drivewire/printer.cpp @@ -31,7 +31,11 @@ constexpr const char * const drivewirePrinter::printer_model_str[PRINTER_INVALID drivewirePrinter::~drivewirePrinter() { - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + _pptr = nullptr; + } } // write for W commands @@ -57,7 +61,10 @@ void drivewirePrinter::drivewire_status() void drivewirePrinter::set_printer_type(drivewirePrinter::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/h89/modem.cpp b/lib/device/h89/modem.cpp index dd0a0712f..fdd0a7e5d 100644 --- a/lib/device/h89/modem.cpp +++ b/lib/device/h89/modem.cpp @@ -95,6 +95,7 @@ H89Modem::~H89Modem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/h89/network.cpp b/lib/device/h89/network.cpp index 14bec7e0f..ad5778dce 100644 --- a/lib/device/h89/network.cpp +++ b/lib/device/h89/network.cpp @@ -54,6 +54,14 @@ H89Network::~H89Network() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** H89 COMMANDS ***************************************************************/ diff --git a/lib/device/h89/printer.cpp b/lib/device/h89/printer.cpp index 170aa844b..6da78ffea 100644 --- a/lib/device/h89/printer.cpp +++ b/lib/device/h89/printer.cpp @@ -42,6 +42,7 @@ H89Printer::~H89Printer() { //vTaskDelete(thPrinter); delete _pptr; + _pptr = nullptr; } H89Printer::printer_type H89Printer::match_modelname(std::string model_name) @@ -82,7 +83,10 @@ void H89Printer::shutdown() void H89Printer::set_printer_type(printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/iec/modem.cpp b/lib/device/iec/modem.cpp index 06bb83c80..80c0e7cef 100644 --- a/lib/device/iec/modem.cpp +++ b/lib/device/iec/modem.cpp @@ -13,6 +13,7 @@ iecModem::~iecModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } } diff --git a/lib/device/iec/network.cpp b/lib/device/iec/network.cpp index d58490bd5..acf2becfc 100644 --- a/lib/device/iec/network.cpp +++ b/lib/device/iec/network.cpp @@ -53,6 +53,11 @@ iecNetwork::~iecNetwork() delete receiveBuffer[i]; delete transmitBuffer[i]; delete specialBuffer[i]; + protocol[i] = nullptr; + json[i] = nullptr; + receiveBuffer[i] = nullptr; + transmitBuffer[i] = nullptr; + specialBuffer[i] = nullptr; } } diff --git a/lib/device/iec/printer.cpp b/lib/device/iec/printer.cpp index 50216859f..710744994 100755 --- a/lib/device/iec/printer.cpp +++ b/lib/device/iec/printer.cpp @@ -22,6 +22,7 @@ constexpr const char *const iecPrinter::printer_model_str[PRINTER_INVALID]; iecPrinter::~iecPrinter() { delete _pptr; + _pptr = nullptr; } // write for W commands @@ -59,7 +60,10 @@ void iecPrinter::status() void iecPrinter::set_printer_type(iecPrinter::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/iwm/modem.cpp b/lib/device/iwm/modem.cpp index c6155a9db..a30f79758 100644 --- a/lib/device/iwm/modem.cpp +++ b/lib/device/iwm/modem.cpp @@ -105,6 +105,7 @@ iwmModem::~iwmModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/iwm/network.cpp b/lib/device/iwm/network.cpp index fbb79c314..6f37df71a 100755 --- a/lib/device/iwm/network.cpp +++ b/lib/device/iwm/network.cpp @@ -55,6 +55,14 @@ iwmNetwork::~iwmNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** iwm COMMANDS ***************************************************************/ diff --git a/lib/device/iwm/printer.cpp b/lib/device/iwm/printer.cpp index ad5f62d89..8fca1ec42 100644 --- a/lib/device/iwm/printer.cpp +++ b/lib/device/iwm/printer.cpp @@ -18,6 +18,7 @@ iwmPrinter::iwmPrinter(FileSystem *filesystem, printer_type printer_type) iwmPrinter::~iwmPrinter() { delete _pptr; + _pptr = nullptr; } void iwmPrinter::send_status_reply_packet() @@ -208,7 +209,10 @@ void iwmPrinter::process(iwm_decoded_cmd_t cmd) void iwmPrinter::set_printer_type(iwmPrinter::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/mac/modem.cpp b/lib/device/mac/modem.cpp index 5f46bf6c2..9ce8172af 100644 --- a/lib/device/mac/modem.cpp +++ b/lib/device/mac/modem.cpp @@ -29,6 +29,7 @@ macModem::~macModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } // if (telnet != nullptr) @@ -152,6 +153,7 @@ iwmModem::~iwmModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/mac/printer.cpp b/lib/device/mac/printer.cpp index 123de7632..72e0930e0 100644 --- a/lib/device/mac/printer.cpp +++ b/lib/device/mac/printer.cpp @@ -17,6 +17,7 @@ macPrinter::macPrinter(FileSystem *filesystem, printer_type printer_type) macPrinter::~macPrinter() { delete _pptr; + _pptr = nullptr; } /** @@ -41,7 +42,10 @@ void macPrinter::process(mac_cmd_t cmd) void macPrinter::set_printer_type(macPrinter::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/new/disk.cpp b/lib/device/new/disk.cpp index 338fadc63..8836936dd 100755 --- a/lib/device/new/disk.cpp +++ b/lib/device/new/disk.cpp @@ -23,7 +23,10 @@ adamDisk::adamDisk() adamDisk::~adamDisk() { if (_media != nullptr) + { delete _media; + _media = nullptr; + } } void adamDisk::reset() diff --git a/lib/device/new/keyboard.cpp b/lib/device/new/keyboard.cpp index e6acdc646..b9170014d 100644 --- a/lib/device/new/keyboard.cpp +++ b/lib/device/new/keyboard.cpp @@ -19,6 +19,7 @@ adamKeyboard::~adamKeyboard() // vTaskDelete(kbTask); server->stop(); delete server; + server = nullptr; } void adamKeyboard::adamnet_control_status() diff --git a/lib/device/new/modem.cpp b/lib/device/new/modem.cpp index bc6ff0d08..b815b71a4 100755 --- a/lib/device/new/modem.cpp +++ b/lib/device/new/modem.cpp @@ -87,6 +87,7 @@ adamModem::~adamModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/new/network.cpp b/lib/device/new/network.cpp index 091522f13..2a7802c70 100755 --- a/lib/device/new/network.cpp +++ b/lib/device/new/network.cpp @@ -58,6 +58,14 @@ adamNetwork::~adamNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** ADAM COMMANDS ***************************************************************/ diff --git a/lib/device/new/printer.cpp b/lib/device/new/printer.cpp index 9309434ca..7288d5f8c 100755 --- a/lib/device/new/printer.cpp +++ b/lib/device/new/printer.cpp @@ -54,6 +54,7 @@ adamPrinter::~adamPrinter() { vTaskDelete(thPrinter); delete _pptr; + _pptr = nullptr; } adamPrinter::printer_type adamPrinter::match_modelname(std::string model_name) @@ -140,7 +141,10 @@ void adamPrinter::shutdown() void adamPrinter::set_printer_type(printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/new/serial.cpp b/lib/device/new/serial.cpp index 9cc1a8ea0..757f3d362 100644 --- a/lib/device/new/serial.cpp +++ b/lib/device/new/serial.cpp @@ -40,6 +40,7 @@ adamSerial::~adamSerial() { server->stop(); delete server; + server = nullptr; } void adamSerial::command_recv() diff --git a/lib/device/rc2014/disk.cpp b/lib/device/rc2014/disk.cpp index b52e1c1df..aba142aaf 100644 --- a/lib/device/rc2014/disk.cpp +++ b/lib/device/rc2014/disk.cpp @@ -25,7 +25,10 @@ rc2014Disk::rc2014Disk() rc2014Disk::~rc2014Disk() { if (_media != nullptr) + { delete _media; + _media = nullptr; + } } // Read disk data and send to computer diff --git a/lib/device/rc2014/modem.cpp b/lib/device/rc2014/modem.cpp index 23b941b0d..39ae005f7 100644 --- a/lib/device/rc2014/modem.cpp +++ b/lib/device/rc2014/modem.cpp @@ -97,6 +97,7 @@ rc2014Modem::~rc2014Modem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/rc2014/network.cpp b/lib/device/rc2014/network.cpp index 5075cdc13..1b5eb4005 100644 --- a/lib/device/rc2014/network.cpp +++ b/lib/device/rc2014/network.cpp @@ -58,6 +58,14 @@ rc2014Network::~rc2014Network() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** rc2014 COMMANDS ***************************************************************/ diff --git a/lib/device/rc2014/printer.cpp b/lib/device/rc2014/printer.cpp index 64ce0ea07..22d60e7ac 100644 --- a/lib/device/rc2014/printer.cpp +++ b/lib/device/rc2014/printer.cpp @@ -39,6 +39,7 @@ rc2014Printer::rc2014Printer(FileSystem *filesystem, printer_type print_type) rc2014Printer::~rc2014Printer() { delete _pptr; + _pptr = nullptr; } rc2014Printer::printer_type rc2014Printer::match_modelname(std::string model_name) @@ -168,7 +169,10 @@ void rc2014Printer::shutdown() void rc2014Printer::set_printer_type(printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/rs232/disk.cpp b/lib/device/rs232/disk.cpp index 1f08c0cb1..5ca3e71ba 100755 --- a/lib/device/rs232/disk.cpp +++ b/lib/device/rs232/disk.cpp @@ -227,7 +227,10 @@ mediatype_t rs232Disk::mount(FILE *f, const char *filename, uint32_t disksize, m rs232Disk::~rs232Disk() { if (_disk != nullptr) + { delete _disk; + _disk = nullptr; + } } // Unmount disk file diff --git a/lib/device/rs232/modem.cpp b/lib/device/rs232/modem.cpp index d15739036..37aeffe29 100755 --- a/lib/device/rs232/modem.cpp +++ b/lib/device/rs232/modem.cpp @@ -107,6 +107,7 @@ rs232Modem::~rs232Modem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) @@ -160,6 +161,9 @@ void rs232Modem::rs232_poll_3(uint8_t device, uint8_t aux1, uint8_t aux2) if (respond == false) return; + // HACK TO GET IT TO COMPILE, TODO: FIX RS232 + int filesize = 100; + // Simply return (without ACK) if we failed to get this if (filesize < 0) return; @@ -254,7 +258,10 @@ void rs232Modem::rs232_send_firmware(uint8_t loadcommand) } // Load firmware from file - uint8_t *code; + // HACK TO GET RS232 TO COMPILE, TODO: FIX RS232 + uint8_t *code = NULL; + int codesize = 100; + // NAK if we failed to get this if (codesize < 0 || code == NULL) { diff --git a/lib/device/rs232/network.cpp b/lib/device/rs232/network.cpp index 1ec1e91a3..c3109e4c0 100755 --- a/lib/device/rs232/network.cpp +++ b/lib/device/rs232/network.cpp @@ -70,6 +70,14 @@ rs232Network::~rs232Network() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** RS232 COMMANDS ***************************************************************/ diff --git a/lib/device/rs232/printer.cpp b/lib/device/rs232/printer.cpp index f1f38a29d..5b38817be 100755 --- a/lib/device/rs232/printer.cpp +++ b/lib/device/rs232/printer.cpp @@ -38,6 +38,7 @@ constexpr const char * const rs232Printer::printer_model_str[PRINTER_INVALID]; rs232Printer::~rs232Printer() { delete _pptr; + _pptr = nullptr; } // write for W commands @@ -160,7 +161,10 @@ void rs232Printer::rs232_status() void rs232Printer::set_printer_type(rs232Printer::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/s100spi/disk.cpp b/lib/device/s100spi/disk.cpp index eeb7794a4..a61584a72 100644 --- a/lib/device/s100spi/disk.cpp +++ b/lib/device/s100spi/disk.cpp @@ -18,7 +18,10 @@ s100spiDisk::s100spiDisk() s100spiDisk::~s100spiDisk() { if (_media != nullptr) + { delete _media; + _media = nullptr; + } } void s100spiDisk::reset() diff --git a/lib/device/s100spi/modem.cpp b/lib/device/s100spi/modem.cpp index c52d7e1f6..223ade587 100644 --- a/lib/device/s100spi/modem.cpp +++ b/lib/device/s100spi/modem.cpp @@ -87,6 +87,7 @@ s100spiModem::~s100spiModem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/device/s100spi/network.cpp b/lib/device/s100spi/network.cpp index 40e5a06fc..cebf34537 100644 --- a/lib/device/s100spi/network.cpp +++ b/lib/device/s100spi/network.cpp @@ -58,6 +58,14 @@ s100spiNetwork::~s100spiNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** s100spi COMMANDS ***************************************************************/ diff --git a/lib/device/s100spi/printer.cpp b/lib/device/s100spi/printer.cpp index f3ac785f5..f0337d7e5 100644 --- a/lib/device/s100spi/printer.cpp +++ b/lib/device/s100spi/printer.cpp @@ -54,6 +54,7 @@ s100spiPrinter::~s100spiPrinter() { vTaskDelete(thPrinter); delete _pptr; + _pptr = nullptr; } s100spiPrinter::printer_type s100spiPrinter::match_modelname(std::string model_name) @@ -122,7 +123,10 @@ void s100spiPrinter::shutdown() void s100spiPrinter::set_printer_type(printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/device/s100spi/printer.h b/lib/device/s100spi/printer.h index ce4865032..f685614dc 100644 --- a/lib/device/s100spi/printer.h +++ b/lib/device/s100spi/printer.h @@ -20,7 +20,7 @@ class s100spiPrinter : public virtualDevice { protected: // SIO THINGS - TaskHandle_t *thPrinter; + TaskHandle_t thPrinter; uint8_t _buffer[16]; diff --git a/lib/device/sio/disk.cpp b/lib/device/sio/disk.cpp index 09b0dbf4a..aae331026 100755 --- a/lib/device/sio/disk.cpp +++ b/lib/device/sio/disk.cpp @@ -260,7 +260,10 @@ mediatype_t sioDisk::mount(FILE *f, const char *filename, uint32_t disksize, med sioDisk::~sioDisk() { if (_disk != nullptr) + { delete _disk; + _disk = nullptr; + } } // Unmount disk file diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index aaf282ace..0baa235b4 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -68,6 +68,14 @@ sioNetwork::~sioNetwork() delete receiveBuffer; delete transmitBuffer; delete specialBuffer; + receiveBuffer = nullptr; + transmitBuffer = nullptr; + specialBuffer = nullptr; + + if (protocol != nullptr) + delete protocol; + + protocol = nullptr; } /** SIO COMMANDS ***************************************************************/ @@ -211,7 +219,10 @@ void sioNetwork::sio_close() protocol = nullptr; if (json != nullptr) + { delete json; + json = nullptr; + } if (newData) free(newData); @@ -1164,6 +1175,7 @@ void sioNetwork::sio_set_timer_rate() void sioNetwork::sio_do_idempotent_command_80() { + Debug_printf("sioNetwork::sio_do_idempotent_command_80()\r\n"); sio_ack(); parse_and_instantiate_protocol(); diff --git a/lib/device/sio/printer.cpp b/lib/device/sio/printer.cpp index fc631257f..981c925de 100755 --- a/lib/device/sio/printer.cpp +++ b/lib/device/sio/printer.cpp @@ -38,6 +38,7 @@ constexpr const char * const sioPrinter::printer_model_str[PRINTER_INVALID]; sioPrinter::~sioPrinter() { delete _pptr; + _pptr = nullptr; } // write for W commands @@ -160,7 +161,10 @@ void sioPrinter::sio_status() void sioPrinter::set_printer_type(sioPrinter::printer_type printer_type) { // Destroy any current printer emu object - delete _pptr; + if (_pptr != nullptr) + { + delete _pptr; + } _ptype = printer_type; switch (printer_type) diff --git a/lib/ftp/fnFTP.cpp b/lib/ftp/fnFTP.cpp index f15072e7f..dd70de076 100644 --- a/lib/ftp/fnFTP.cpp +++ b/lib/ftp/fnFTP.cpp @@ -650,6 +650,9 @@ fnFTP::~fnFTP() delete control; if (data != nullptr) delete data; + + control = nullptr; + data = nullptr; } bool fnFTP::login(const string &_username, const string &_password, const string &_hostname, unsigned short _port) diff --git a/lib/fuji/fujiHost.cpp b/lib/fuji/fujiHost.cpp index 9e74b10f9..f027b79f2 100755 --- a/lib/fuji/fujiHost.cpp +++ b/lib/fuji/fujiHost.cpp @@ -356,6 +356,7 @@ int fujiHost::unmount_tnfs() if (_fs != nullptr) { delete _fs; + _fs = nullptr; } return 0; diff --git a/lib/media/atari/diskTypeAtx.cpp b/lib/media/atari/diskTypeAtx.cpp index 25e1275e5..c5792834c 100755 --- a/lib/media/atari/diskTypeAtx.cpp +++ b/lib/media/atari/diskTypeAtx.cpp @@ -70,6 +70,8 @@ AtxTrack::~AtxTrack() { if (data != nullptr) delete[] data; + + data = nullptr; }; AtxTrack::AtxTrack(){ @@ -494,6 +496,7 @@ bool MediaTypeATX::_load_atx_chunk_sector_data(chunk_header_t &chunk_hdr, AtxTra { Debug_printf("failed reading %d sector data chunk bytes (%d, %d)\r\n", data_size, i, errno); delete[] track.data; + track.data = nullptr; return false; } diff --git a/lib/modem/modem.cpp b/lib/modem/modem.cpp index 1870e991b..830b23c11 100755 --- a/lib/modem/modem.cpp +++ b/lib/modem/modem.cpp @@ -105,6 +105,7 @@ modem::~modem() if (modemSniffer != nullptr) { delete modemSniffer; + modemSniffer = nullptr; } if (telnet != nullptr) diff --git a/lib/network-protocol/FS.cpp b/lib/network-protocol/FS.cpp index cac9232fb..f29da865e 100755 --- a/lib/network-protocol/FS.cpp +++ b/lib/network-protocol/FS.cpp @@ -389,6 +389,7 @@ void NetworkProtocolFS::resolve() bool NetworkProtocolFS::perform_idempotent_80(EdUrlParser *url, cmdFrame_t *cmdFrame) { + Debug_printf("NetworkProtocolFS::perform_idempotent_80, url: %s\r\n", url->toString().c_str()); switch (cmdFrame->comnd) { case 0x20: diff --git a/lib/network-protocol/FTP.cpp b/lib/network-protocol/FTP.cpp index 94618f011..138b974c2 100755 --- a/lib/network-protocol/FTP.cpp +++ b/lib/network-protocol/FTP.cpp @@ -28,6 +28,7 @@ NetworkProtocolFTP::~NetworkProtocolFTP() { Debug_printf("NetworkProtocolFTP::dtor\r\n"); delete ftp; + ftp = nullptr; } bool NetworkProtocolFTP::open_file_handle() diff --git a/lib/network-protocol/HTTP.cpp b/lib/network-protocol/HTTP.cpp index cd0eee849..ba7dd8c51 100755 --- a/lib/network-protocol/HTTP.cpp +++ b/lib/network-protocol/HTTP.cpp @@ -238,6 +238,7 @@ bool NetworkProtocolHTTP::umount() return false; delete client; + client = nullptr; return false; } @@ -669,6 +670,7 @@ bool NetworkProtocolHTTP::rename(EdUrlParser *url, cmdFrame_t *cmdFrame) bool NetworkProtocolHTTP::del(EdUrlParser *url, cmdFrame_t *cmdFrame) { + Debug_printf("NetworkProtocolHTTP::del, url: %s\r\n", url->toString().c_str()); mount(url); resultCode = client->DELETE(); diff --git a/lib/network-protocol/TCP.cpp b/lib/network-protocol/TCP.cpp index bbaa5a958..a1e9b9362 100755 --- a/lib/network-protocol/TCP.cpp +++ b/lib/network-protocol/TCP.cpp @@ -37,7 +37,6 @@ NetworkProtocolTCP::~NetworkProtocolTCP() if (server != nullptr) { delete server; - server = nullptr; } } diff --git a/lib/utils/cbuf.cpp b/lib/utils/cbuf.cpp index 23bb48b79..d0c9f9818 100644 --- a/lib/utils/cbuf.cpp +++ b/lib/utils/cbuf.cpp @@ -31,6 +31,7 @@ cbuf::cbuf(size_t size) : next(NULL), _size(size + 1), _buf(new char[size + 1]), cbuf::~cbuf() { delete[] _buf; + _buf = nullptr; } size_t cbuf::resizeAdd(size_t addSize) diff --git a/platformio-sample.ini b/platformio-sample.ini index c314a28d7..55eb76a6d 100644 --- a/platformio-sample.ini +++ b/platformio-sample.ini @@ -76,7 +76,7 @@ flash_filesystem = FLASH_SPIFFS ;build_platform = BUILD_H89 ;build_bus = H89 -;build_board = fujinet-heatkit-h89 +;build_board = fujinet-heathkit-h89 ;build_platform = BUILD_COCO ;build_bus = DRIVEWIRE From 3f01654dcfa8cd4f9b40c6e740235182ff5f1b3c Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Wed, 18 Oct 2023 20:53:11 -0400 Subject: [PATCH 130/158] mac: trying MOOFin without caching. Fail over net. --- lib/device/mac/floppy.cpp | 2 +- lib/device/mac/fuji.cpp | 12 +++++----- lib/media/mac/mediaTypeMOOF.cpp | 40 +++++++++++++++++++++++++++++++++ lib/media/mac/mediaTypeMOOF.h | 8 ++++++- pico/mac/commands.c | 2 +- 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 8e6dfd09b..29687ceb0 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -134,7 +134,7 @@ void macFloppy::unmount() // ((MediaTypeMOOF *)_disk)->unmount(); if (disktype() == mediatype_t::MEDIATYPE_MOOF) ((MediaTypeMOOF *)_disk)->unmount(); - else + else if (_disk != nullptr) _disk->unmount(); MAC.rem_dcd_mount(id()); device_active = false; diff --git a/lib/device/mac/fuji.cpp b/lib/device/mac/fuji.cpp index 4416b194b..f854656e1 100644 --- a/lib/device/mac/fuji.cpp +++ b/lib/device/mac/fuji.cpp @@ -76,14 +76,16 @@ void macFuji::setup(macBus *macbus) // _mac_bus->addDevice(&_fnDisks[i].disk_dev, mac_fujinet_type_t::Floppy); } + + // to do AUTORUN // Debug_printf("\nConfig General Boot Mode: %u\n",Config.get_general_boot_mode()); // if (Config.get_general_boot_mode() == 0) // { - FILE *f = fsFlash.file_open("/autorun.moof"); - if (f!=nullptr) - _fnDisks[MAX_DISK_DEVICES - MAX_FLOPPY_DEVICES].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); - else - Debug_printf("\nCould not open 'autorun.moof'"); + // FILE *f = fsFlash.file_open("/autorun.moof"); + // if (f!=nullptr) + // _fnDisks[MAX_DISK_DEVICES - MAX_FLOPPY_DEVICES].disk_dev.mount(f, "/autorun.moof", MEDIATYPE_MOOF); + // else + // Debug_printf("\nCould not open 'autorun.moof'"); // } // else // { diff --git a/lib/media/mac/mediaTypeMOOF.cpp b/lib/media/mac/mediaTypeMOOF.cpp index 4180d2d23..f41229b5f 100644 --- a/lib/media/mac/mediaTypeMOOF.cpp +++ b/lib/media/mac/mediaTypeMOOF.cpp @@ -28,11 +28,16 @@ mediatype_t MediaTypeMOOF::mount(FILE *f, uint32_t disksize) void MediaTypeMOOF::unmount() { MediaType::unmount(); +#ifdef CACHE_IMAGE for (int i = 0; i < MAX_TRACKS; i++) { if (trk_ptrs[i] != nullptr) free(trk_ptrs[i]); } +#else + free(trk_buffer); + trk_buffer = nullptr; +#endif } bool MediaTypeMOOF::moof_check_header() @@ -147,6 +152,22 @@ bool MediaTypeMOOF::moof_read_tmap() return false; } +uint8_t *MediaTypeMOOF::get_track(int t) +{ + +#ifdef CACHE_IMAGE + return trk_ptrs[tmap[t]]; +#else + size_t s = trks[t].block_count * 512; + Debug_printf("\nReading %d bytes of track %d", s, t); + fseek(_media_fileh, trks[t].start_block * 512, SEEK_SET); + fread(trk_buffer, 1, s, _media_fileh); + // Debug_printf("\n%d, %d, %lu", trks[t].start_block, trks[t].block_count, trks[t].bit_count); + return trk_buffer; +#endif + +} + bool MediaTypeMOOF::moof_read_tracks() { // depend upon little endian-ness fseek(_media_fileh, 256, SEEK_SET); @@ -156,6 +177,8 @@ bool MediaTypeMOOF::moof_read_tracks() for (int i = 0; i < MAX_TRACKS; i++) Debug_printf("\n%d, %d, %lu", trks[i].start_block, trks[i].block_count, trks[i].bit_count); #endif + +#ifdef CACHE_IMAGE // read MOOF tracks into RAM for (int i = 0; i < MAX_TRACKS; i++) { @@ -177,6 +200,23 @@ bool MediaTypeMOOF::moof_read_tracks() } } } +#else + size_t s = num_blocks * 512; + if (s != 0) + { + trk_buffer = (uint8_t *)heap_caps_malloc(s, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + if (trk_buffer != nullptr) + { + Debug_printf("\n%d bytes allocated for MOOF track buffer", s); + } + else + { + Debug_printf("\nNo RAM allocated!"); + return true; + } + } +#endif + return false; } diff --git a/lib/media/mac/mediaTypeMOOF.h b/lib/media/mac/mediaTypeMOOF.h index 71062ccda..1bb3bf83f 100644 --- a/lib/media/mac/mediaTypeMOOF.h +++ b/lib/media/mac/mediaTypeMOOF.h @@ -9,6 +9,8 @@ #define MAX_SIDES 2 #define MAX_TRACKS (MAX_SIDES * MAX_CYLINDERS) +#define CACHE_IMAGE + struct TRK_t { uint16_t start_block; @@ -37,7 +39,11 @@ class MediaTypeMOOF : public MediaType protected: uint8_t tmap[MAX_TRACKS]; TRK_t trks[MAX_TRACKS]; +#ifdef CACHE_IMAGE uint8_t *trk_ptrs[MAX_TRACKS] = {}; +#else + uint8_t *trk_buffer; +#endif public: MediaTypeMOOF() {}; @@ -54,7 +60,7 @@ class MediaTypeMOOF : public MediaType virtual bool status() override { return (_media_fileh != nullptr); } uint8_t trackmap(uint8_t t) { return tmap[t]; }; - uint8_t *get_track(int t) { return trk_ptrs[tmap[t]]; }; + uint8_t *get_track(int t); int track_len(int t) { return trks[tmap[t]].block_count * 512; }; int num_bits(int t) { return trks[tmap[t]].bit_count; }; uint8_t optimal_bit_timing; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 6b874fea3..4272f7dde 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -403,7 +403,7 @@ void floppy_loop() uart_putc_raw(UART_ID, (char)(a + '0')); } - // !STEP + // !STEP - a little state machine with !STEP required to make this work // At the falling edge of this signal the destination track counter is counted up or down depending on the !DIRTN level. // After the destination counter in the drive received the falling edge of !STEP, the drive sets !STEP to high. if (step_state) From 86bd948b64508d311e1021f41d679631324cada5 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Wed, 18 Oct 2023 21:01:20 -0400 Subject: [PATCH 131/158] mac: implement floppy eject --- lib/bus/mac/mac.cpp | 4 +++- pico/mac/commands.c | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 0a8f0d878..250c6e54c 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -109,7 +109,9 @@ void macBus::service(void) break; case 7: // eject - Debug_printf("\neject but do nothing"); + Debug_printf("\neject - unmounting"); + floppy_ll.stop(); + theFuji.get_disks(4)->disk_dev.unmount(); fnUartBUS.write('E'); // fnUartBUS.flush(); break; diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 4272f7dde..a5570f3d9 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -229,7 +229,7 @@ void preset_latch() clr_latch(EJECT); set_latch(SINGLESIDE); clr_latch(DRVIN); - clr_latch(CSTIN); //set_latch(CSTIN); + set_latch(CSTIN); // no disk in drive clr_latch(WRTPRT); set_latch(TKO); set_latch(READY); @@ -392,8 +392,8 @@ void floppy_loop() // EJECT is set to low at rising edge of !CSTIN or 2 sec maximum after rising edge of EJECT. // When power is turned on, EJECT is set to low. // eject - // set_latch(EJECT); // to do - need to clr eject when a disk is inserted - so cheat for now - // set_latch(READY); + set_latch(EJECT); // to do - need to clr eject when a disk is inserted - so cheat for now + set_latch(READY); break; default: printf("\nUNKNOWN PHASE COMMAND"); @@ -445,6 +445,15 @@ void floppy_loop() clr_latch(WRTPRT); // everythign is write protected for now printf("\nDS disk mounted"); break; + case 'E': + // EJECT + // At the rising edge of the LSTRB, EJECT is set to high and the ejection operation starts. + // EJECT is set to low at rising edge of !CSTIN or 2 sec maximum after rising edge of EJECT. + // When power is turned on, EJECT is set to low. + set_latch(CSTIN); + clr_latch(EJECT); + printf("\nFloppy Ejected"); + break; case 'S': // step complete (data copied to RMT buffer on ESP32) printf("\nStep sequence complete"); clr_latch(READY); // hack - really should not set READY low until the 3 criteria are met From d0e457c4a56624ff921d7250233723be87467d47 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Mon, 16 Oct 2023 11:32:41 +0100 Subject: [PATCH 132/158] HTTP: Add DELETE as new open mode (5,9) to retrieve body/json response This adds new aux1 open commands of: o 5 = DELETE with no headers o 9 = DELETE with headers and allows clients to retrieve the response of the DELETE in the same way as other open commands on http (i.e. GET/POST/PUT) using JSON or full READ of body. --- lib/device/sio/network.cpp | 56 ++++++----- lib/device/sio/network.h | 5 +- lib/fn_esp_http_client/fn_esp_http_client.cpp | 92 ------------------ lib/fn_esp_http_client/fn_esp_http_client.h | 96 ++++++++++++++++++- lib/fnjson/fnjson.cpp | 53 ++++++---- lib/http/fnHttpClient.cpp | 11 +++ lib/network-protocol/FS.cpp | 2 +- lib/network-protocol/HTTP.cpp | 39 +++++++- lib/network-protocol/HTTP.h | 3 +- lib/utils/utils.cpp | 7 +- lib/utils/utils.h | 3 + 11 files changed, 222 insertions(+), 145 deletions(-) diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index 0baa235b4..696ffbb28 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -93,7 +93,7 @@ void sioNetwork::sio_open() newData = (uint8_t *)malloc(NEWDATA_SIZE); - if (!newData) + if (newData == nullptr) { Debug_printv("Could not allocate write buffer\n"); sio_error(); @@ -139,8 +139,11 @@ void sioNetwork::sio_open() protocolParser = nullptr; } - if (newData) + if (newData != nullptr) + { free(newData); + newData = nullptr; + } sio_error(); return; @@ -159,8 +162,11 @@ void sioNetwork::sio_open() protocolParser = nullptr; } - if (newData) + if (newData != nullptr) + { free(newData); + newData = nullptr; + } sio_error(); return; @@ -224,8 +230,11 @@ void sioNetwork::sio_close() json = nullptr; } - if (newData) + if (newData != nullptr) + { free(newData); + newData = nullptr; + } Debug_printv("After protocol delete %lu\n",esp_get_free_internal_heap_size()); } @@ -693,32 +702,35 @@ void sioNetwork::do_inquiry(unsigned char inq_cmd) // Ask protocol for dstats, otherwise get it locally. if (protocol != nullptr) + { inq_dstats = protocol->special_inquiry(inq_cmd); + Debug_printf("protocol special_inquiry returned %d\r\n", inq_dstats); + } // If we didn't get one from protocol, or unsupported, see if supported globally. if (inq_dstats == 0xFF) { switch (inq_cmd) { - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x2A: - case 0x2B: - case 0x2C: - case 0xFD: - case 0xFE: + case 0x20: // ' ' rename + case 0x21: // '!' delete + case 0x23: // '#' lock + case 0x24: // '$' unlock + case 0x2A: // '*' mkdir + case 0x2B: // '+' rmdir + case 0x2C: // ',' chdir/get prefix + case 0xFD: // login + case 0xFE: // password inq_dstats = 0x80; break; - case 0xFC: + case 0xFC: // channel mode inq_dstats = 0x00; break; case 0xFB: // String Processing mode, only in JSON mode if (channelMode == JSON) inq_dstats = 0x00; break; - case 0x30: + case 0x30: // '0' set prefix inq_dstats = 0x40; break; case 'Z': // Set interrupt rate @@ -812,15 +824,15 @@ void sioNetwork::sio_special_80() // Handle commands that exist outside of an open channel. switch (cmdFrame.comnd) { - case 0x20: // RENAME - case 0x21: // DELETE - case 0x23: // LOCK - case 0x24: // UNLOCK - case 0x2A: // MKDIR - case 0x2B: // RMDIR + case 0x20: // RENAME ' ' + case 0x21: // DELETE '!' + case 0x23: // LOCK '#' + case 0x24: // UNLOCK '$' + case 0x2A: // MKDIR '*' + case 0x2B: // RMDIR '+' sio_do_idempotent_command_80(); return; - case 0x2C: // CHDIR + case 0x2C: // CHDIR ',' sio_set_prefix(); return; case 'Q': diff --git a/lib/device/sio/network.h b/lib/device/sio/network.h index ba2048ba3..d38e59784 100755 --- a/lib/device/sio/network.h +++ b/lib/device/sio/network.h @@ -27,6 +27,8 @@ #define OUTPUT_BUFFER_SIZE 65535 #define SPECIAL_BUFFER_SIZE 256 +#define NEWDATA_SIZE 65535 + class sioNetwork : public virtualDevice { @@ -257,8 +259,7 @@ class sioNetwork : public virtualDevice /** * @brief the write buffer */ - uint8_t *newData; -#define NEWDATA_SIZE 65535 + uint8_t *newData = nullptr; /** * Instantiate protocol object diff --git a/lib/fn_esp_http_client/fn_esp_http_client.cpp b/lib/fn_esp_http_client/fn_esp_http_client.cpp index 13b250ce3..4806ec0bd 100644 --- a/lib/fn_esp_http_client/fn_esp_http_client.cpp +++ b/lib/fn_esp_http_client/fn_esp_http_client.cpp @@ -58,98 +58,6 @@ namespace fujinet static const char *TAG = "HTTP_CLIENT"; -/** - * HTTP Buffer - */ -typedef struct { - char *data; /*!< The HTTP data received from the server */ - int len; /*!< The HTTP data len received from the server */ - char *raw_data; /*!< The HTTP data after decoding */ - int raw_len; /*!< The HTTP data len after decoding */ - char *output_ptr; /*!< The destination address of the data to be copied to after decoding */ -} esp_http_buffer_t; - -/** - * private HTTP Data structure - */ -typedef struct { - http_header_handle_t headers; /*!< http header */ - esp_http_buffer_t *buffer; /*!< data buffer as linked list */ - int status_code; /*!< status code (integer) */ - int content_length; /*!< data length */ - int chunk_length; /*!< last chunk length */ - int total_chunk_length; /*!< total chunk length */ - int data_offset; /*!< offset to http data (Skip header) */ - int data_process; /*!< data processed */ - int method; /*!< http method */ - bool is_chunked; -} esp_http_data_t; - -typedef struct { - char *url; - char *scheme; - char *host; - int port; - char *username; - char *password; - char *path; - char *query; - char *cert_pem; - esp_http_client_method_t method; - esp_http_client_auth_type_t auth_type; - esp_http_client_transport_t transport_type; - int max_store_header_size; -} connection_info_t; - -typedef enum { - HTTP_STATE_UNINIT = 0, - HTTP_STATE_INIT, - HTTP_STATE_CONNECTED, - HTTP_STATE_REQ_COMPLETE_HEADER, - HTTP_STATE_REQ_COMPLETE_DATA, - HTTP_STATE_RES_COMPLETE_HEADER, - HTTP_STATE_RES_COMPLETE_DATA, - HTTP_STATE_CLOSE -} esp_http_state_t; -/** - * HTTP client class - */ -struct esp_http_client { - int redirect_counter; - int max_redirection_count; - int process_again; - struct http_parser *parser; - struct http_parser_settings *parser_settings; - esp_transport_list_handle_t transport_list; - esp_transport_handle_t transport; - esp_http_data_t *request; - esp_http_data_t *response; - void *user_data; - esp_http_auth_data_t *auth_data; - char *post_data; - char *location; - char *auth_header; - char *current_header_key; - char *current_header_value; - int post_len; - connection_info_t connection_info; - bool is_chunk_complete; - esp_http_state_t state; - http_event_handle_cb event_handler; - int timeout_ms; - int buffer_size_rx; - int buffer_size_tx; - bool disable_auto_redirect; - esp_http_client_event_t event; - int data_written_index; - int data_write_left; - bool first_line_prepared; - int header_index; - bool is_async; -}; - -typedef struct esp_http_client esp_http_client_t; - static esp_err_t _clear_connection_info(esp_http_client_handle_t client); /** * Default settings diff --git a/lib/fn_esp_http_client/fn_esp_http_client.h b/lib/fn_esp_http_client/fn_esp_http_client.h index 4a97406c7..fadd1cbdc 100644 --- a/lib/fn_esp_http_client/fn_esp_http_client.h +++ b/lib/fn_esp_http_client/fn_esp_http_client.h @@ -21,7 +21,8 @@ #include "esp_err.h" #include "esp_tls.h" #include "esp_transport.h" - +#include "fn_http_header.h" +#include "fn_http_auth.h" namespace fujinet { @@ -144,6 +145,99 @@ typedef enum { HttpStatus_Unauthorized = 401 } HttpStatus_Code; +/** + * HTTP Buffer + */ +typedef struct { + char *data; /*!< The HTTP data received from the server */ + int len; /*!< The HTTP data len received from the server */ + char *raw_data; /*!< The HTTP data after decoding */ + int raw_len; /*!< The HTTP data len after decoding */ + char *output_ptr; /*!< The destination address of the data to be copied to after decoding */ +} esp_http_buffer_t; + +/** + * private HTTP Data structure + */ +typedef struct { + http_header_handle_t headers; /*!< http header */ + esp_http_buffer_t *buffer; /*!< data buffer as linked list */ + int status_code; /*!< status code (integer) */ + int content_length; /*!< data length */ + int chunk_length; /*!< last chunk length */ + int total_chunk_length; /*!< total chunk length */ + int data_offset; /*!< offset to http data (Skip header) */ + int data_process; /*!< data processed */ + int method; /*!< http method */ + bool is_chunked; +} esp_http_data_t; + +typedef struct { + char *url; + char *scheme; + char *host; + int port; + char *username; + char *password; + char *path; + char *query; + char *cert_pem; + esp_http_client_method_t method; + esp_http_client_auth_type_t auth_type; + esp_http_client_transport_t transport_type; + int max_store_header_size; +} connection_info_t; + +typedef enum { + HTTP_STATE_UNINIT = 0, + HTTP_STATE_INIT, + HTTP_STATE_CONNECTED, + HTTP_STATE_REQ_COMPLETE_HEADER, + HTTP_STATE_REQ_COMPLETE_DATA, + HTTP_STATE_RES_COMPLETE_HEADER, + HTTP_STATE_RES_COMPLETE_DATA, + HTTP_STATE_CLOSE +} esp_http_state_t; +/** + * HTTP client class + */ +struct esp_http_client { + int redirect_counter; + int max_redirection_count; + int process_again; + struct http_parser *parser; + struct http_parser_settings *parser_settings; + esp_transport_list_handle_t transport_list; + esp_transport_handle_t transport; + esp_http_data_t *request; + esp_http_data_t *response; + void *user_data; + esp_http_auth_data_t *auth_data; + char *post_data; + char *location; + char *auth_header; + char *current_header_key; + char *current_header_value; + int post_len; + connection_info_t connection_info; + bool is_chunk_complete; + esp_http_state_t state; + http_event_handle_cb event_handler; + int timeout_ms; + int buffer_size_rx; + int buffer_size_tx; + bool disable_auto_redirect; + esp_http_client_event_t event; + int data_written_index; + int data_write_left; + bool first_line_prepared; + int header_index; + bool is_async; +}; + +typedef struct esp_http_client esp_http_client_t; + + #define ESP_ERR_HTTP_BASE (0x7000) /*!< Starting number of HTTP error codes */ #define ESP_ERR_HTTP_MAX_REDIRECT (ESP_ERR_HTTP_BASE + 1) /*!< The error exceeds the number of HTTP redirects */ #define ESP_ERR_HTTP_CONNECT (ESP_ERR_HTTP_BASE + 2) /*!< Error open the HTTP connection */ diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 8a8995e67..3e77a175b 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -14,6 +14,7 @@ #include #include "string_utils.h" #include "../../include/debug.h" +#include "../utils/utils.h" /** * ctor @@ -152,38 +153,37 @@ string FNJSON::getValue(cJSON *item) if (cJSON_IsString(item)) { - Debug_printf("S: [cJSON_IsString] %s\r\n", cJSON_GetStringValue(item)); - ss << processString(cJSON_GetStringValue(item) + lineEnding); + char *strValue = cJSON_GetStringValue(item); + Debug_printf("S: [cJSON_IsString] %s\r\n", strValue); + ss << processString(strValue + lineEnding); } else if (cJSON_IsBool(item)) { - Debug_printf("S: [cJSON_IsBool] %s\r\n", cJSON_IsTrue(item) ? "true" : "false"); - - if (cJSON_IsTrue(item)) - ss << "TRUE" + lineEnding; - else if (cJSON_IsFalse(item)) - ss << "FALSE" + lineEnding; + bool isTrue = cJSON_IsTrue(item); + Debug_printf("S: [cJSON_IsBool] %s\r\n", isTrue ? "true" : "false"); + ss << (isTrue ? "TRUE" : "FALSE") + lineEnding; } else if (cJSON_IsNull(item)) { Debug_printf("S: [cJSON_IsNull]\r\n"); - ss << "NULL" + lineEnding; } else if (cJSON_IsNumber(item)) { - Debug_printf("S: [cJSON_IsNumber] %f\r\n", cJSON_GetNumberValue(item)); - + double num = cJSON_GetNumberValue(item); + bool isInt = isApproximatelyInteger(num); // Is the number an integer? - if (floor(cJSON_GetNumberValue(item)) == cJSON_GetNumberValue(item)) + if (isInt) { // yes, return as 64 bit integer - ss << (int64_t)(cJSON_GetNumberValue(item)); + Debug_printf("S: [cJSON_IsNumber INT] %d\r\n", (int64_t)num); + ss << (int64_t)num; } else { // no, return as double with max. 10 digits - ss << setprecision(10) << cJSON_GetNumberValue(item); + Debug_printf("S: [cJSON_IsNumber] %f\r\n", num); + ss << setprecision(10) << num; } ss << lineEnding; @@ -257,31 +257,44 @@ bool FNJSON::parse() NetworkStatus ns; if (_json != nullptr) + { + // delete and set to null. we only set a new _json value if the parsebuffer is not empty cJSON_Delete(_json); + _json = nullptr; + } if (_protocol == nullptr) { Debug_printf("FNJSON::parse() - NULL protocol.\r\n"); return false; } - + _parseBuffer.clear(); _protocol->status(&ns); + Debug_printf("json parse, initial status: ns.rxBW: %d, ns.conn: %d, ns.err: %d\r\n", ns.rxBytesWaiting, ns.connected, ns.error); while (ns.connected) { - _protocol->read(ns.rxBytesWaiting); - _parseBuffer += *_protocol->receiveBuffer; - _protocol->receiveBuffer->clear(); + // don't try reading 0 bytes when there's no content. + if (ns.rxBytesWaiting > 0) + { + _protocol->read(ns.rxBytesWaiting); + _parseBuffer += *_protocol->receiveBuffer; + _protocol->receiveBuffer->clear(); + } _protocol->status(&ns); vTaskDelay(10); } Debug_printf("S: %s\r\n", _parseBuffer.c_str()); - _json = cJSON_Parse(_parseBuffer.c_str()); + // only try and parse the buffer if it has data. Empty response doesn't need parsing. + if (!_parseBuffer.empty()) + { + _json = cJSON_Parse(_parseBuffer.c_str()); + } if (_json == nullptr) { - Debug_printf("FNJSON::parse() - Could not parse JSON\r\n"); + Debug_printf("FNJSON::parse() - Could not parse JSON, parseBuffer length: %d\r\n", _parseBuffer.size()); return false; } diff --git a/lib/http/fnHttpClient.cpp b/lib/http/fnHttpClient.cpp index 6b774525f..51eb7a158 100755 --- a/lib/http/fnHttpClient.cpp +++ b/lib/http/fnHttpClient.cpp @@ -8,6 +8,7 @@ #include "../../include/debug.h" #include "fnSystem.h" +#include "../fn_esp_http_client/fn_esp_http_client.h" #include "utils.h" @@ -37,6 +38,7 @@ fnHttpClient::~fnHttpClient() } free(_buffer); + _buffer = nullptr; } // Start an HTTP client session to the given URL @@ -65,7 +67,16 @@ bool fnHttpClient::begin(const std::string &url) int fnHttpClient::available() { if (_handle == nullptr) + { + Debug_printf("fnHttpClient::available() _handle is null\r\n"); + return 0; + } + + if (_handle->response == nullptr) + { + Debug_printf("fnHttpClient::available() _handle->response is null\r\n"); return 0; + } int result = 0; int len = -1; diff --git a/lib/network-protocol/FS.cpp b/lib/network-protocol/FS.cpp index f29da865e..9cba7c97c 100755 --- a/lib/network-protocol/FS.cpp +++ b/lib/network-protocol/FS.cpp @@ -196,7 +196,7 @@ bool NetworkProtocolFS::read_file(unsigned short len) if (buf == nullptr) { - Debug_printf("NetworkProtocolTNFS:read_file(%u) could not allocate.\r\n", len); + Debug_printf("NetworkProtocolFS:read_file(%u) could not allocate.\r\n", len); return true; // error } diff --git a/lib/network-protocol/HTTP.cpp b/lib/network-protocol/HTTP.cpp index ba7dd8c51..d7a74d115 100755 --- a/lib/network-protocol/HTTP.cpp +++ b/lib/network-protocol/HTTP.cpp @@ -19,12 +19,15 @@ Aux1 values =========== 4 = GET, no headers, just grab data. +5 = DELETE, no headers 6 = PROPFIND, WebDAV directory 8 = PUT, write data to server, XIO used to toggle headers to get versus data write +9 = DELETE, with headers 12 = GET, write sets headers to fetch, read grabs data 13 = POST, write sends post data to server, read grabs response, XIO used to change write behavior, toggle headers to get or headers to set. 14 = PUT, write sends post data to server, read grabs response, XIO used to change write behavior, toggle headers to get or headers to set. DELETE, MKCOL, RMCOL, COPY, MOVE, are all handled via idempotent XIO commands. +DELETE can be done via special/XIO if you do not want to handle the response, otherwise use aux1=5/9 with normal open/read. */ NetworkProtocolHTTP::NetworkProtocolHTTP(string *rx_buf, string *tx_buf, string *sp_buf) @@ -45,7 +48,10 @@ NetworkProtocolHTTP::~NetworkProtocolHTTP() { for (int i = 0; i < collect_headers_count; i++) if (collect_headers[i] != nullptr) + { free(collect_headers[i]); + collect_headers[i] = nullptr; + } } uint8_t NetworkProtocolHTTP::special_inquiry(uint8_t cmd) @@ -122,6 +128,10 @@ bool NetworkProtocolHTTP::open_file_handle() case 8: // WRITE, filename resolve, ignored if not found. httpOpenMode = PUT; break; + case 5: // DELETE with no headers + case 9: // DELETE with ability to set headers + httpOpenMode = DELETE; + break; case 13: // POST can set headers, also no filename resolve case 14: // PUT with ability to set headers, no filename resolve httpOpenMode = POST; @@ -323,20 +333,35 @@ bool NetworkProtocolHTTP::status_file(NetworkStatus *status) // if (fromInterrupt == false) // Debug_printf("Channel mode is %u\r\n", httpChannelMode); + if (client == nullptr) { + status->rxBytesWaiting = 0; + status->connected = 0; + status->error = NETWORK_ERROR_GENERAL; + return true; + } + switch (httpChannelMode) { case DATA: + { if (fromInterrupt == false && resultCode == 0) + { + Debug_printf("calling http_transaction\r\n"); http_transaction(); - status->rxBytesWaiting = client->available() > 65535 ? 65535 : client->available(); + } + auto available = client->available(); + status->rxBytesWaiting = available > 65535 ? 65535 : available; status->connected = client->is_transaction_done() ? 0 : 1; - status->error = client->available() == 0 && client->is_transaction_done() && error == NETWORK_ERROR_SUCCESS ? NETWORK_ERROR_END_OF_FILE : error; + status->error = available == 0 && client->is_transaction_done() && error == NETWORK_ERROR_SUCCESS ? NETWORK_ERROR_END_OF_FILE : error; + // Debug_printf("NetworkProtocolHTTP::status_file DATA, available: %d, s.rxBW: %d, s.conn: %d, s.err: %d\r\n", available, status->rxBytesWaiting, status->connected, status->error); return false; + } case SET_HEADERS: case COLLECT_HEADERS: case SEND_POST_DATA: status->rxBytesWaiting = status->connected = 0; status->error = NETWORK_ERROR_SUCCESS; + // Debug_printf("NetworkProtocolHTTP::status_file SH/CH/SPD, s.rxBW: %d, s.conn: %d, s.err: %d\r\n", status->rxBytesWaiting, status->connected, status->error); return false; case GET_HEADERS: if (resultCode == 0) @@ -344,8 +369,10 @@ bool NetworkProtocolHTTP::status_file(NetworkStatus *status) status->rxBytesWaiting = (returned_header_cursor < collect_headers_count ? returned_headers[returned_header_cursor].size() : 0); status->connected = 0; // so that we always ask in this mode. status->error = returned_header_cursor == collect_headers_count && error == NETWORK_ERROR_SUCCESS ? NETWORK_ERROR_END_OF_FILE : error; + // Debug_printf("NetworkProtocolHTTP::status_file GH, s.rxBW: %d, s.conn: %d, s.err: %d\r\n", status->rxBytesWaiting, status->connected, status->error); return false; default: + Debug_printf("ERROR: Unknown httpChannelMode: %d\r\n", httpChannelMode); return true; } } @@ -582,7 +609,6 @@ void NetworkProtocolHTTP::http_transaction() { if ((aux1_open != 4) && (aux1_open != 8) && (collect_headers_count > 0)) { - Debug_printf("CALLING COLLECT HEADERS!\r\n"); client->collect_headers((const char **)collect_headers, collect_headers_count); } @@ -600,6 +626,9 @@ void NetworkProtocolHTTP::http_transaction() case PUT: resultCode = client->PUT(postData.c_str(), postData.size()); break; + case DELETE: + resultCode = client->DELETE(); + break; } if ((aux1_open != 4) && (aux1_open != 8) && (collect_headers_count > 0)) @@ -670,7 +699,7 @@ bool NetworkProtocolHTTP::rename(EdUrlParser *url, cmdFrame_t *cmdFrame) bool NetworkProtocolHTTP::del(EdUrlParser *url, cmdFrame_t *cmdFrame) { - Debug_printf("NetworkProtocolHTTP::del, url: %s\r\n", url->toString().c_str()); + Debug_printf("NetworkProtocolHTTP::del(%s,%s)", url->hostName.c_str(), url->path.c_str()); mount(url); resultCode = client->DELETE(); @@ -683,7 +712,7 @@ bool NetworkProtocolHTTP::del(EdUrlParser *url, cmdFrame_t *cmdFrame) bool NetworkProtocolHTTP::mkdir(EdUrlParser *url, cmdFrame_t *cmdFrame) { - Debug_printf("NetworkProtocolHTTP::mkdir(%s,%s)", url->hostName, url->path); + Debug_printf("NetworkProtocolHTTP::mkdir(%s,%s)", url->hostName.c_str(), url->path.c_str()); mount(url); diff --git a/lib/network-protocol/HTTP.h b/lib/network-protocol/HTTP.h index 2d3b54f11..e0bba45fd 100755 --- a/lib/network-protocol/HTTP.h +++ b/lib/network-protocol/HTTP.h @@ -157,7 +157,8 @@ class NetworkProtocolHTTP : public NetworkProtocolFS { GET, POST, - PUT + PUT, + DELETE } HTTPOpenMode; HTTPOpenMode httpOpenMode = HTTPOpenMode::GET; diff --git a/lib/utils/utils.cpp b/lib/utils/utils.cpp index 8a44664db..5276e9d88 100644 --- a/lib/utils/utils.cpp +++ b/lib/utils/utils.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../include/debug.h" @@ -890,4 +891,8 @@ char *util_hexdump(const void *buf, size_t len) { if (n > dlen - 1) n = dlen - 1; dst[n] = '\0'; return dst; -} \ No newline at end of file +} + +bool isApproximatelyInteger(double value, double tolerance) { + return std::abs(value - std::floor(value)) < tolerance; +} diff --git a/lib/utils/utils.h b/lib/utils/utils.h index 4c3d44d99..a825ed983 100644 --- a/lib/utils/utils.h +++ b/lib/utils/utils.h @@ -92,4 +92,7 @@ void util_ascii_to_petscii_str(std::string &s); // generic hex dump for debug output char *util_hexdump(const void *buf, size_t len); +// check if a double is very close to an integer +bool isApproximatelyInteger(double value, double tolerance = 1e-6); + #endif // _FN_UTILS_H From 3065543d27b0c265f71bd4d194a6aa341a6a0d3c Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Thu, 19 Oct 2023 19:39:44 +0100 Subject: [PATCH 133/158] JSON crash fixes, atari json query no longer needs device prefix Apple test changes to track crashing JSON Ensure json query starts with slash to stop crashes. do not fail atari json query not starting with device spec Fix debug line endings --- lib/device/iwm/network.cpp | 2 +- lib/device/sio/network.cpp | 38 +++++++++++++++++++++++--------------- lib/fnjson/fnjson.cpp | 15 ++++++++++++--- lib/utils/utils.cpp | 7 +++++++ lib/utils/utils.h | 3 +++ 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/lib/device/iwm/network.cpp b/lib/device/iwm/network.cpp index 6f37df71a..c26cfe30d 100755 --- a/lib/device/iwm/network.cpp +++ b/lib/device/iwm/network.cpp @@ -389,7 +389,7 @@ void iwmNetwork::json_query(iwm_decoded_cmd_t cmd) // addy |= ((cmd.g7byte6 & 0x7f) | ((cmd.grp7msb << 6) & 0x80)) << 8; // addy |= ((cmd.g7byte7 & 0x7f) | ((cmd.grp7msb << 7) & 0x80)) << 16; - Debug_printf("Query set to: %s\n", string((char *)data_buffer, data_len).c_str()); + Debug_printf("\r\nQuery set to: %s, data_len: %d\r\n", string((char *)data_buffer, data_len).c_str(), data_len); json.setReadQuery(string((char *)data_buffer, data_len),cmdFrame.aux2); } diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index 696ffbb28..454401427 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -7,7 +7,10 @@ #include "network.h" #include +#include #include +#include +#include #include "../../include/debug.h" #include "../../include/pinmap.h" @@ -1106,7 +1109,6 @@ void sioNetwork::sio_set_json_query() { uint8_t in[256]; const char *inp = NULL; - uint8_t *tmp; memset(in, 0, sizeof(in)); @@ -1119,22 +1121,28 @@ void sioNetwork::sio_set_json_query() in[i] = 0x00; } - inp = strrchr((const char *)in, ':'); - - if (inp == NULL) - { - sio_error(); - return; + std::string in_string(reinterpret_cast(in)); + size_t last_colon_pos = in_string.rfind(':'); + + std::string inp_string; + if (last_colon_pos != std::string::npos) { + Debug_printf("sioNetwork::sio_set_json_query - skipped device spec. Application should be updated to remove it from query."); + inp_string = in_string.substr(last_colon_pos + 1); + } else { + inp_string = in_string; } - inp++; - json->setReadQuery(string(inp), cmdFrame.aux2); - json_bytes_remaining = json->readValueLen(); - tmp = (uint8_t *)malloc(json->readValueLen()); - json->readValue(tmp,json_bytes_remaining); - *receiveBuffer += string((const char *)tmp,json_bytes_remaining); - free(tmp); - Debug_printf("Query set to %s\n",inp); + json->setReadQuery(inp_string, cmdFrame.aux2); + json_bytes_remaining = json->json_bytes_remaining; + + std::vector tmp(json_bytes_remaining); + json->readValue(tmp.data(), json_bytes_remaining); + + // don't copy past first nul char in tmp + auto null_pos = std::find(tmp.begin(), tmp.end(), 0); + *receiveBuffer += std::string(tmp.begin(), null_pos); + + Debug_printf("Query set to >%s<\r\n", inp_string.c_str()); sio_complete(); } diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 3e77a175b..0de875a45 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -66,6 +66,7 @@ void FNJSON::setQueryParam(uint8_t qp) */ void FNJSON::setReadQuery(const string &queryString, uint8_t queryParam) { + Debug_printf("FNJSON::setReadQuery queryString: %s, queryParam: %d\r\n", queryString.c_str(), queryParam); _queryString = queryString; _queryParam = queryParam; _item = resolveQuery(); @@ -77,9 +78,9 @@ void FNJSON::setReadQuery(const string &queryString, uint8_t queryParam) */ cJSON *FNJSON::resolveQuery() { - if (_queryString.empty()) - return _json; - + // Queries must start with a slash, else the JSON parsing crashes FujiNet + // An alternative fix would be to check if the returned value was equal to _json and do something with it, but this is simpler. + _queryString = prependSlash(_queryString); return cJSONUtils_GetPointer(_json, _queryString.c_str()); } @@ -149,6 +150,14 @@ string FNJSON::processString(string in) */ string FNJSON::getValue(cJSON *item) { + if (item == NULL) + { + Debug_printf("\r\nFNJSON::getValue called with null item, returning empty string.\r\n"); + return string(""); + } + + // char *asString = cJSON_PrintUnformatted(item); + // Debug_printf("FNJSON::getValue called with item: >%s<\r\n", asString); stringstream ss; if (cJSON_IsString(item)) diff --git a/lib/utils/utils.cpp b/lib/utils/utils.cpp index 5276e9d88..798d24016 100644 --- a/lib/utils/utils.cpp +++ b/lib/utils/utils.cpp @@ -896,3 +896,10 @@ char *util_hexdump(const void *buf, size_t len) { bool isApproximatelyInteger(double value, double tolerance) { return std::abs(value - std::floor(value)) < tolerance; } + +std::string prependSlash(const std::string& str) { + if (str.empty() || str[0] != '/') { + return "/" + str; + } + return str; +} \ No newline at end of file diff --git a/lib/utils/utils.h b/lib/utils/utils.h index a825ed983..a0c14539f 100644 --- a/lib/utils/utils.h +++ b/lib/utils/utils.h @@ -95,4 +95,7 @@ char *util_hexdump(const void *buf, size_t len); // check if a double is very close to an integer bool isApproximatelyInteger(double value, double tolerance = 1e-6); +// ensure string starts with a "/" +std::string prependSlash(const std::string& str); + #endif // _FN_UTILS_H From ba553dd5e22fbaff6e1e66c3b023d624167d38bd Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 20 Oct 2023 16:07:49 +0100 Subject: [PATCH 134/158] Add CRLF to debug output for json query in SIO --- lib/device/sio/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index 454401427..47b85be16 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -1126,7 +1126,7 @@ void sioNetwork::sio_set_json_query() std::string inp_string; if (last_colon_pos != std::string::npos) { - Debug_printf("sioNetwork::sio_set_json_query - skipped device spec. Application should be updated to remove it from query."); + Debug_printf("sioNetwork::sio_set_json_query - skipped device spec. Application should be updated to remove it from query (%s)\r\n", in_string.c_str()); inp_string = in_string.substr(last_colon_pos + 1); } else { inp_string = in_string; From 6799e3d909dcdddee8cff1fef8e4636abc8c2391 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 20 Oct 2023 18:12:55 +0100 Subject: [PATCH 135/158] Fix JSON parsing crashing on empty objects --- lib/fnjson/fnjson.cpp | 44 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 0de875a45..be0c2f70e 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -78,9 +78,9 @@ void FNJSON::setReadQuery(const string &queryString, uint8_t queryParam) */ cJSON *FNJSON::resolveQuery() { - // Queries must start with a slash, else the JSON parsing crashes FujiNet - // An alternative fix would be to check if the returned value was equal to _json and do something with it, but this is simpler. - _queryString = prependSlash(_queryString); + if (_queryString.empty()) + return _json; + return cJSONUtils_GetPointer(_json, _queryString.c_str()); } @@ -156,8 +156,6 @@ string FNJSON::getValue(cJSON *item) return string(""); } - // char *asString = cJSON_PrintUnformatted(item); - // Debug_printf("FNJSON::getValue called with item: >%s<\r\n", asString); stringstream ss; if (cJSON_IsString(item)) @@ -204,21 +202,29 @@ string FNJSON::getValue(cJSON *item) setLineEnding("\x0a"); #endif - item = item->child; - - do + if (item->child == NULL) + { + Debug_printf("FNJSON::getValue OBJECT has no CHILD, adding empty string\r\n"); + ss << lineEnding; + } + else { - #ifdef BUILD_IEC - // Convert key to PETSCII - string tempStr = string((const char *)item->string); - mstr::toPETSCII(tempStr); - ss << tempStr; - #else - ss << item->string; - #endif - - ss << lineEnding + getValue(item); - } while ((item = item->next) != NULL); + item = item->child; + do + { + #ifdef BUILD_IEC + // Convert key to PETSCII + string tempStr = string((const char *)item->string); + mstr::toPETSCII(tempStr); + ss << tempStr; + #else + ss << item->string; + #endif + + ss << lineEnding + getValue(item); + } while ((item = item->next) != NULL); + } + } else if (cJSON_IsArray(item)) { From be605d15e331d1c56fe2deb62f1bd5559d69729e Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 15:17:38 -0400 Subject: [PATCH 136/158] mac: some PIO asm cleanup --- pico/mac/commands.c | 8 ++++---- pico/mac/dcd_mux.pio | 2 +- pico/mac/dcd_read.pio | 40 +++++++++++++++++++--------------------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index a5570f3d9..4a4ba09e4 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -4,10 +4,10 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#define FLOPPY -//#undef FLOPPY -#undef DCD -//#define DCD +//#define FLOPPY +#undef FLOPPY +//#undef DCD +#define DCD #include #include diff --git a/pico/mac/dcd_mux.pio b/pico/mac/dcd_mux.pio index 0d4f56861..28df7a069 100644 --- a/pico/mac/dcd_mux.pio +++ b/pico/mac/dcd_mux.pio @@ -21,7 +21,7 @@ ; we wait to be enabled then RD goes to output .wrap_target start: - set x, 0 side 0 ; put the number of DCD devices in X (0xf022 - last digit is number of DCDs) + set x, 0 side 0 ; put the number of DCD devices in X (0xf020 - last digit is number of DCDs) wait 0 gpio ENABLE ; don't do anything until we're enabled in x, 32 ; say we are at the first DCD jmp x-- cont ; decrement X to wait for the next strobe diff --git a/pico/mac/dcd_read.pio b/pico/mac/dcd_read.pio index cdda9bd8c..0cfff4fbf 100644 --- a/pico/mac/dcd_read.pio +++ b/pico/mac/dcd_read.pio @@ -11,34 +11,32 @@ .program dcd_read .side_set 1 - wait 0 gpio ENABLE side 1 ; make sure device is enabled (maybe could remove if SM was triggered by main program) - set y, 0 side 0 ; initial state is always 0 (probably unneeded if can reset set whole SM) - set x, 7 side 0 + ; wait 0 gpio ENABLE side 1 ; removed if SM was triggered by main program + set y, 0 side 0 ; initial state is always 0 + set x, 7 side 0 ; bit counter reset: - wait 1 pin 0 side 1 ; wait for rising edge on write line from mac - jmp loop1 side 1 + wait 1 pin 0 side 1 ; wait for rising edge on write line from mac to start reading byte + jmp loop1 side 1 ; loop: - nop side 1 [T0/2-2] + nop side 1 [T0/2-2] ; wait for 1/2 bit width loop1: - wait 0 gpio 9 side 1 ; block on CA1 + wait 0 gpio 9 side 1 ; block on CA1 at the end of the transmission jmp pin high side 0 ; need T0 cycles from jmp to jmp low: - in y, 1 side 0 [1] ; the decoded value is equal to the previous state - set y, 0 side 0 ; previous state is now zero - jmp x-- loop side 1 ; last bit? - jmp sync side 1 ; get the next bit + in y, 1 side 0 [1] ; shift in the decoded value, which is equal to the previous state y + set y, 0 side 0 ; previous state is now low (zero) + jmp x-- loop side 1 ; check to see if we're at the last bit? + jmp sync side 1 ; if so, then wait for the next byte to start high: - mov y, ~y side 0 - in y, 1 side 0 ; the deocded value is the inverse of the previous state - set y, 1 side 1 ; previous state is now one - jmp x-- loop side 1 ; last bit? - ; fall thru // jmp loop ; get the next bit -; probably will need to have a counter and wait on edge of next byte + mov y, ~y side 0 + in y, 1 side 0 ; the deocded value is the inverse of the previous state + set y, 1 side 1 ; previous state is now one + jmp x-- loop side 1 ; last bit? sync: - set x, 7 side 1 - jmp !y reset side 0 - wait 0 pin 0 side 1 - jmp loop1 side 1 + set x, 7 side 1 ; reset the bit counter + jmp !y reset side 0 ; go to top if y was 0 + wait 0 pin 0 side 1 ; otherwise wait for falling edge to sync to next back + jmp loop1 side 1 ; start reading byte again From 2602a96eb9f831eeddaf878156f66ee888ea6d87 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 16:07:21 -0400 Subject: [PATCH 137/158] mac: clean up LATCH code --- pico/mac/commands.c | 129 ++++++++++++++++++-------------------------- pico/mac/latch.pio | 1 + 2 files changed, 52 insertions(+), 78 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 4a4ba09e4..945ee5fef 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -25,7 +25,7 @@ #include "latch.pio.h" #include "mux.pio.h" -#include "dcd_latch.pio.h" +// #include "dcd_latch.pio.h" #include "dcd_commands.pio.h" #include "dcd_mux.pio.h" #include "dcd_read.pio.h" @@ -173,53 +173,30 @@ uint16_t latch; uint8_t dcd_latch; uint16_t get_latch() { return latch; } -uint8_t dcd_get_latch() { return dcd_latch; } +uint16_t dcd_get_latch() { return ((dcd_latch << 8) + dcd_latch); } -uint16_t set_latch(enum latch_bits s) -{ - latch |= (1u << s); - return latch; -}; +void set_latch(enum latch_bits s) { latch |= (1u << s); } -uint8_t dcd_set_latch(uint8_t s) -{ - dcd_latch |= (1u << s); - return dcd_latch; -} +void dcd_set_latch(uint8_t s) { dcd_latch |= (1u << s); } -uint16_t clr_latch(enum latch_bits c) -{ - latch &= ~(1u << c); - return latch; -}; +void clr_latch(enum latch_bits c) { latch &= ~(1u << c); } -uint8_t dcd_clr_latch(uint8_t c) -{ - dcd_latch &= ~(1u << c); - return dcd_latch; -}; +void dcd_clr_latch(uint8_t c) { dcd_latch &= ~(1u << c); } -uint8_t dcd_assert_hshk() -{ - dcd_clr_latch(2); - dcd_clr_latch(3); +void dcd_assert_hshk() +{ // State CA2 CA1 CA0 HOST HOFF RESET RD Function + dcd_clr_latch(2); // 2 Low High Low Low Low Low !HSHK + dcd_clr_latch(3); // 3 Low High High High Low Low !HSHK pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO - return dcd_latch; } -uint8_t dcd_deassert_hshk() -{ - dcd_set_latch(2); - dcd_set_latch(3); +void dcd_deassert_hshk() +{ // State CA2 CA1 CA0 HOST HOFF RESET RD Function + dcd_set_latch(2); // 2 Low High Low Low Low Low !HSHK + dcd_set_latch(3); // 3 Low High High High Low Low !HSHK pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO - return dcd_latch; } -// bool latch_val(enum latch_bits b) -// { -// return (latch & (1u << b)); -// } - void preset_latch() { latch =0; @@ -240,7 +217,16 @@ void preset_latch() void dcd_preset_latch() { - dcd_latch = 0b11011100; // DCD signature HHLx + no handshake HHxx + dcd_latch = 0; + // State CA2 CA1 CA0 HOST HOFF RESET RD Function + dcd_clr_latch(0); // 0 Low Low Low High High Low Data + dcd_clr_latch(1); // 1 Low Low High High Low Low Data + dcd_set_latch(2); // 2 Low High Low Low Low Low !HSHK + dcd_set_latch(3); // 3 Low High High High Low Low !HSHK + dcd_set_latch(4); // 4 High Low Low Low Low High -- + dcd_clr_latch(5); // 5 High Low High Low Low Low Drive Low + dcd_set_latch(6); // 6 High High Low Low Low Low Drive High + dcd_set_latch(7); // 7 High High High Low Low Low Drive High } void set_tach_freq(char c) @@ -257,7 +243,6 @@ void set_tach_freq(char c) } } -void loop(); void dcd_loop(); void floppy_loop(); @@ -294,8 +279,8 @@ void setup() dcd_preset_latch(); - offset = pio_add_program(pio_dcd, &dcd_latch_program); - printf("\nLoaded DCD latch program at %d\n", offset); + offset = pio_add_program(pio_dcd, &latch_program); + printf("\nLoaded latch program at %d\n", offset); pio_dcd_latch(pio_dcd, SM_DCD_LATCH, offset, MCI_CA0, LATCH_OUT); pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO @@ -485,18 +470,6 @@ void dcd_process(uint8_t nrx, uint8_t ntx); void dcd_loop() { - // latest thoughts: - // this loop handshakes and receives the DCD command and fires off the command handler - // todo: make dcd_mux.pio push the DCD volume # (or floppy state) to the input FIFO. - - // thoughts: - // this is done by a SM: during boot sequence, need to look for STRB to deal with daisy chained DCD and floppy - // if only one HD20, then after first STRB, READ should go hi-z. - // then maybe we get a reset? the Reset should allow READ to go output when ENABLED - // - // need a state variable to track changes in the "command" phase settings - // - // if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_MUX)) { active_disk_number = num_dcd_drives + 'A' - pio_sm_get_blocking(pio_dcd, SM_DCD_MUX); @@ -882,7 +855,7 @@ void dcd_status(uint8_t ntx) void dcd_id(uint8_t ntx) { - + // to do - move generation of the ID response packet to the ESP32 so the capacity can be generated /* DCD Device: Offset Value Sample Value from HD20 @@ -927,26 +900,26 @@ void dcd_id(uint8_t ntx) // assert(false); } -void dcd_unknown(uint8_t ntx) -{ - /* - DCD Device: - Offset Value Sample Value from HD20 - 0 0x83 - 1 0x00 - 2-5 Status - 6 checksum - */ - printf("sending0x22 "); - memset(payload, 0, sizeof(payload)); - payload[0] = 0x80 | 0x22; - compute_checksum(6); - assert(ntx==1); - - send_packet(ntx); - // simulate_packet(ntx); - // assert(false); -} +// void dcd_unknown(uint8_t ntx) +// { +// /* +// DCD Device: +// Offset Value Sample Value from HD20 +// 0 0x83 +// 1 0x00 +// 2-5 Status +// 6 checksum +// */ +// printf("sending0x22 "); +// memset(payload, 0, sizeof(payload)); +// payload[0] = 0x80 | 0x22; +// compute_checksum(6); +// assert(ntx==1); + +// send_packet(ntx); +// // simulate_packet(ntx); +// // assert(false); +// } void dcd_format(uint8_t ntx) { @@ -1096,9 +1069,9 @@ void dcd_process(uint8_t nrx, uint8_t ntx) case 0x1a: dcd_verify(ntx); break; - case 0x22: - dcd_unknown(ntx); - break; + // case 0x22: + // dcd_unknown(ntx); + // break; case 0x41: // cont to write sectors dcd_write(ntx, true, false); @@ -1138,7 +1111,7 @@ void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin) void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) { - dcd_latch_program_init(pio, sm, offset, in_pin, out_pin); + latch_program_init(pio, sm, offset, in_pin, out_pin); pio_sm_set_enabled(pio, sm, true); } diff --git a/pico/mac/latch.pio b/pico/mac/latch.pio index d0d571656..5a6228da8 100644 --- a/pico/mac/latch.pio +++ b/pico/mac/latch.pio @@ -3,6 +3,7 @@ ; ; Vintage Macintosh Microfloppy Controller Interface ; Reads the drive phases and output a latch bit +; for DCD, the 8-bit latch register should be copied into upper and lower bytes of the value pulled by the SM ; .define ENABLE 7 From 4eee0c7aa0bf9f331c3ac9ec8d8466b9f389a77e Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 18:10:53 -0400 Subject: [PATCH 138/158] mac: trying to integrate DCD and floppy --- pico/mac/commands.c | 284 ++++++++++++++++++++++++++------------------ 1 file changed, 167 insertions(+), 117 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 945ee5fef..98ef89b3a 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -6,8 +6,8 @@ //#define FLOPPY #undef FLOPPY -//#undef DCD -#define DCD +#undef DCD +//#define DCD #include #include @@ -31,7 +31,7 @@ #include "dcd_read.pio.h" #include "dcd_write.pio.h" -// #include "../../include/pinmap/mac_rev0.h" +// define GPIO pins #define UART_TX_PIN 4 #define UART_RX_PIN 5 #define ENABLE 7 @@ -42,36 +42,73 @@ #define ECHO_OUT 18 #define LATCH_OUT 20 -#define SM_CMD 0 -#define SM_LATCH 1 -#define SM_MUX 2 -#define SM_ECHO 3 +/** + * HERE STARTS PIO DEFINITIONS AND HEADERS +*/ -#define SM_DCD_LATCH 3 +PIO pioblk_read_only = pio0; +#define SM_FPY_CMD 0 #define SM_DCD_CMD 1 -#define SM_DCD_MUX 2 -#define SM_DCD_READ 0 +#define SM_DCD_READ 2 + +PIO pioblk_rw = pio1; #define SM_DCD_WRITE 0 +#define SM_FPY_ECHO 1 +#define SM_LATCH 2 +#define SM_MUX 3 +uint pio_read_offset; +uint pio_write_offset; +uint pio_mux_offset; void pio_commands(PIO pio, uint sm, uint offset, uint pin); void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins); void pio_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin); -void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); +// void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin); void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_write(PIO pio, uint sm, uint offset, uint pin); +void pio_switch_to_floppy_mux() +{ + pio_remove_program(pioblk_rw, &dcd_mux_program, pio_mux_offset); + pio_add_program_at_offset(pioblk_rw, &mux_program, pio_mux_offset); + pio_mux(pioblk_rw, SM_MUX, pio_mux_offset, MCI_CA0, ECHO_OUT); +} + +void pio_switch_to_dcd_mux() +{ + pio_remove_program(pioblk_rw, &mux_program, pio_mux_offset); + pio_add_program_at_offset(pioblk_rw, &dcd_mux_program, pio_mux_offset); + pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); +} + +/** + * HERE IS UART SETUP +*/ #define UART_ID uart1 #define BAUD_RATE 2000000 //230400 //115200 #define DATA_BITS 8 #define STOP_BITS 1 #define PARITY UART_PARITY_NONE +void setup_esp_uart() +{ + uart_init(UART_ID, BAUD_RATE); + gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); + gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); + uart_set_hw_flow(UART_ID, false, false); + uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY); + uart_set_fifo_enabled(UART_ID, true); +} + +/** + * DATA NEEDED FOR OPERATION +*/ const int tach_lut[5][3] = {{0, 15, 394}, {16, 31, 429}, {32, 47, 472}, @@ -84,24 +121,10 @@ uint32_t b[12]; uint32_t olda; uint32_t active_disk_number; uint num_dcd_drives; - -PIO pio_floppy = pio0; -PIO pio_dcd = pio1; -PIO pio_dcd_rw = pio0; -uint pio_read_offset; -uint pio_write_offset; -uint pio_mux_offset; - -void setup_esp_uart() -{ - uart_init(UART_ID, BAUD_RATE); - gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); - gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); - uart_set_hw_flow(UART_ID, false, false); - uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY); - uart_set_fifo_enabled(UART_ID, true); -} +/** + * LATCH INFORMATION AND CODE +*/ /** * 800 KB GCR Drive @@ -187,14 +210,14 @@ void dcd_assert_hshk() { // State CA2 CA1 CA0 HOST HOFF RESET RD Function dcd_clr_latch(2); // 2 Low High Low Low Low Low !HSHK dcd_clr_latch(3); // 3 Low High High High Low Low !HSHK - pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pioblk_rw, SM_LATCH, dcd_get_latch()); // send the register word to the PIO } void dcd_deassert_hshk() { // State CA2 CA1 CA0 HOST HOFF RESET RD Function dcd_set_latch(2); // 2 Low High Low Low Low Low !HSHK dcd_set_latch(3); // 3 Low High High High Low Low !HSHK - pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pioblk_rw, SM_LATCH, dcd_get_latch()); // send the register word to the PIO } void preset_latch() @@ -243,9 +266,6 @@ void set_tach_freq(char c) } } -void dcd_loop(); -void floppy_loop(); - void setup() { uint offset; @@ -254,17 +274,71 @@ void setup() setup_default_uart(); setup_esp_uart(); + // merged setup + set_tach_freq(0); // start TACH clock + preset_latch(); + dcd_preset_latch(); + + /** + * put the read-only SM's in PIO0: floppy cmd, dcd cmd, dcd read + */ + offset = pio_add_program(pioblk_read_only, &commands_program); + printf("\nLoaded Floppy cmd program at %d", offset); + pio_commands(pioblk_read_only, SM_FPY_CMD, offset, MCI_CA0); // read phases starting on pin 8 + + offset = pio_add_program(pioblk_read_only, &dcd_commands_program); + printf("\nLoaded DCD commands program at %d", offset); + // pio_dcd_commands(pioblk_read_only, SM_DCD_CMD, offset, MCI_CA0); // read phases starting on pin 8 + + pio_read_offset = pio_add_program(pioblk_read_only, &dcd_read_program); + printf("\nLoaded DCD read program at %d\n", pio_read_offset); + // pio_dcd_read(pioblk_read_only, SM_DCD_READ, pio_read_offset, MCI_WR); + + /** + * put the output SM's in PIO1: echo, dcd write, common latch + * + * from Section 3.5.6.1 in RP2040 datasheet: + * For each GPIO, PIO collates the writes from all four state machines, + * and applies the write from the highest-numbered state machine. + * This occurs separately for output levels and output values — + * it is possible for a state machine to change both the level and + * direction of the same pin on the same cycle (e.g. via simultaneous + * SET and side-set), or for one state machine to change a GPIO’s + * direction while another changes that GPIO’s level. + */ + offset = pio_add_program(pioblk_rw, &latch_program); + printf("\nLoaded latch program at %d\n", offset); + pio_latch(pioblk_rw, SM_LATCH, offset, MCI_CA0, LATCH_OUT); + // pio_sm_put_blocking(pioblk_rw, SM_LATCH, dcd_get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO + + offset = pio_add_program(pioblk_rw, &echo_program); + printf("Loaded floppy echo program at %d\n", offset); + pio_echo(pioblk_rw, SM_FPY_ECHO, offset, ECHO_IN, ECHO_OUT, 2); + + pio_write_offset = pio_add_program(pioblk_rw, &dcd_write_program); + printf("Loaded DCD write program at %d\n", pio_write_offset); + // pio_dcd_write(pioblk_rw, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); + + // pio_mux_offset = pio_add_program(pioblk_rw, &dcd_mux_program); + // printf("Loaded DCD mux program at %d\n", pio_mux_offset); + // pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); + + pio_mux_offset = pio_add_program(pioblk_rw, &mux_program); + printf("Loaded Floppy mux program at %d\n", pio_mux_offset); + pio_mux(pioblk_rw, SM_MUX, offset, MCI_CA0, ECHO_OUT); + #ifdef FLOPPY set_tach_freq(0); // start TACH clock preset_latch(); offset = pio_add_program(pio_floppy, &commands_program); printf("\nLoaded cmd program at %d\n", offset); - pio_commands(pio_floppy, SM_CMD, offset, MCI_CA0); // read phases starting on pin 8 + pio_commands(pio_floppy, SM_FPY_CMD, offset, MCI_CA0); // read phases starting on pin 8 offset = pio_add_program(pio_floppy, &echo_program); printf("Loaded echo program at %d\n", offset); - pio_echo(pio_floppy, SM_ECHO, offset, ECHO_IN, ECHO_OUT, 2); + pio_echo(pio_floppy, SM_FPY_ECHO, offset, ECHO_IN, ECHO_OUT, 2); offset = pio_add_program(pio_floppy, &latch_program); printf("Loaded latch program at %d\n", offset); @@ -275,60 +349,36 @@ void setup() printf("Loaded mux program at %d\n", offset); pio_mux(pio_floppy, SM_MUX, offset, MCI_CA0, ECHO_OUT); -#elif defined(DCD) - - dcd_preset_latch(); - - offset = pio_add_program(pio_dcd, &latch_program); - printf("\nLoaded latch program at %d\n", offset); - pio_dcd_latch(pio_dcd, SM_DCD_LATCH, offset, MCI_CA0, LATCH_OUT); - pio_sm_put_blocking(pio_dcd, SM_DCD_LATCH, dcd_get_latch()); // send the register word to the PIO - - offset = pio_add_program(pio_dcd, &dcd_commands_program); - printf("Loaded DCD commands program at %d\n", offset); - pio_dcd_commands(pio_dcd, SM_DCD_CMD, offset, MCI_CA0); - - pio_mux_offset = pio_add_program(pio_dcd, &dcd_mux_program); - printf("Loaded DCD mux program at %d\n", pio_mux_offset); - pio_dcd_mux(pio_dcd, SM_DCD_MUX, pio_mux_offset, LATCH_OUT); - - pio_read_offset = pio_add_program(pio_dcd_rw, &dcd_read_program); - printf("Loaded DCD read program at %d\n", pio_read_offset); - pio_dcd_read(pio_dcd_rw, SM_DCD_READ, pio_read_offset, MCI_WR); - - pio_write_offset = pio_add_program(pio_dcd, &dcd_write_program); - printf("Loaded DCD write program at %d\n", pio_write_offset); - pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); - - // pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); - // pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); - // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0xaa<<24); - // pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, 0x80<<24); - // while(1) - // ; #endif // FLOPPY } +void dcd_loop(); +void floppy_loop(); + int main() { setup(); while (true) { + floppy_loop(); #ifdef FLOPPY floppy_loop(); #elif defined(DCD) dcd_loop(); #endif } + } bool step_state = false; - void floppy_loop() { - if (!pio_sm_is_rx_fifo_empty(pio_floppy, SM_CMD)) - { - a = pio_sm_get_blocking(pio_floppy, SM_CMD); + //static bool step_state = false; + + if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_FPY_CMD)) + { + a = pio_sm_get_blocking(pioblk_read_only, SM_FPY_CMD); + printf("%d",a); switch (a) { // !READY @@ -384,7 +434,7 @@ void floppy_loop() printf("\nUNKNOWN PHASE COMMAND"); break; } - pio_sm_put_blocking(pio_floppy, SM_LATCH, get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO uart_putc_raw(UART_ID, (char)(a + '0')); } @@ -451,7 +501,7 @@ void floppy_loop() break; } // printf("latch %04x", get_latch()); - pio_sm_put_blocking(pio_floppy, SM_LATCH, get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO } // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO // to do: read both enable lines and indicate which drive is active when sending single char to esp32 @@ -470,17 +520,17 @@ void dcd_process(uint8_t nrx, uint8_t ntx); void dcd_loop() { - if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_MUX)) + if (!pio_sm_is_rx_fifo_empty(pioblk_rw, SM_MUX)) { - active_disk_number = num_dcd_drives + 'A' - pio_sm_get_blocking(pio_dcd, SM_DCD_MUX); + active_disk_number = num_dcd_drives + 'A' - pio_sm_get_blocking(pioblk_rw, SM_MUX); printf("%c", active_disk_number); uart_putc_raw(UART_ID, active_disk_number); } - if (!pio_sm_is_rx_fifo_empty(pio_dcd, SM_DCD_CMD)) + if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_DCD_CMD)) { olda = a; - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); switch (a) { case 0: @@ -493,10 +543,10 @@ void dcd_loop() // The second indicates the number of 7-to-8-encoded groups contained in the transfer to follow, plus 0x80 (because the MSB must be set). // The third indicates the number of 7-to-8-encoded groups that the Macintosh expects to receive in response, plus 0x80. // These three bytes are followed by 7-to-8-encoded groups, the number of which was indicated by the second byte. - cmd.sync = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + cmd.sync = pio_sm_get_blocking(pioblk_read_only, SM_DCD_READ); assert(cmd.sync == 0xaa); - cmd.num_rx = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); - cmd.num_tx = pio_sm_get_blocking(pio_dcd_rw, SM_DCD_READ); + cmd.num_rx = pio_sm_get_blocking(pioblk_read_only, SM_DCD_READ); + cmd.num_tx = pio_sm_get_blocking(pioblk_read_only, SM_DCD_READ); dcd_process(cmd.num_rx & 0x7f, cmd.num_tx & 0x7f); break; case 2: @@ -513,17 +563,18 @@ void dcd_loop() if (olda == 2) { //pio_sm_restart(pio_dcd_rw, SM_DCD_READ); - pio_dcd_read(pio_dcd_rw, SM_DCD_READ, pio_read_offset, MCI_WR); // re-init - pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, true); + pio_dcd_read(pioblk_read_only, SM_DCD_READ, pio_read_offset, MCI_WR); // re-init + pio_sm_set_enabled(pioblk_read_only, SM_DCD_READ, true); dcd_assert_hshk(); } break; case 4: host = false; dcd_deassert_hshk(); - pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, false); - pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, true); - pio_sm_exec(pio_dcd, SM_DCD_MUX, 0xe080); // set pindirs 0 + pio_sm_set_enabled(pioblk_rw, SM_DCD_WRITE, false); + pio_sm_set_enabled(pioblk_rw, SM_LATCH, true); + pio_sm_exec(pioblk_rw, SM_MUX, 0xe080); // set pindirs 0 to do swap with below + // pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_set(pio_pindirs, 0)); // set pindirs 0 break; default: host = false; @@ -546,12 +597,12 @@ void dcd_loop() // set x, N side 0 ; put the number of DCD devices in X (0xf02N - last digit is number of DCDs) // uint instr = 0xf020 + num_dcd_drives; // pause the machine, change the instruction, move the PC, resume - pio_sm_set_enabled(pio_dcd, SM_DCD_MUX, false); + pio_sm_set_enabled(pioblk_rw, SM_MUX, false); volatile uint *target; target = (uint *)(PIO1_BASE + PIO_INSTR_MEM0_OFFSET + 4*pio_mux_offset); *target = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); - pio_sm_set_enabled(pio_dcd, SM_DCD_MUX, true); - pio_sm_exec(pio_dcd, SM_DCD_MUX, pio_encode_jmp(pio_mux_offset)); + pio_sm_set_enabled(pioblk_rw, SM_MUX, true); + pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_jmp(pio_mux_offset)); break; default: break; @@ -563,15 +614,15 @@ uint8_t payload[539]; inline static void send_byte(uint8_t c) { - pio_sm_put_blocking(pio_dcd, SM_DCD_WRITE, c << 24); + pio_sm_put_blocking(pioblk_rw, SM_DCD_WRITE, c << 24); } void handshake_before_send() { dcd_assert_hshk(); - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); assert(a==3); // now back to idle and awaiting DCD response - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); assert(a==1); // now back to idle and awaiting DCD response // to do: handshaking error recovery - // case 1: TNFS seek timeout and abort - need to capture on LogAn to see what's going on @@ -579,9 +630,9 @@ void handshake_before_send() void handshake_after_send() { - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); assert(a==3); - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); assert(a==2); // now back to idle and awaiting DCD response } @@ -592,22 +643,22 @@ void send_packet(uint8_t ntx) handshake_before_send(); // send the response packet encoding along the way - pio_sm_set_enabled(pio_dcd, SM_DCD_LATCH, false); - pio_dcd_write(pio_dcd, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); - pio_sm_set_enabled(pio_dcd, SM_DCD_WRITE, true); + pio_sm_set_enabled(pioblk_rw, SM_LATCH, false); + pio_dcd_write(pioblk_rw, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); + pio_sm_set_enabled(pioblk_rw, SM_DCD_WRITE, true); send_byte(0xaa); // send_byte(ntx | 0x80); - NOT SENT - OOPS uint8_t *p = payload; for (int i=0; i>= 1; p++; } } - pio_sm_set_enabled(pio_dcd_rw, SM_DCD_READ, false); // stop the read state machine + pio_sm_set_enabled(pioblk_read_only, SM_DCD_READ, false); // stop the read state machine // // handshake // while (gpio_get(MCI_WR)); // WR needs to return to 0 (at least from a status command at boot) - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); assert(a==3); //busy_wait_us_32(10); dcd_deassert_hshk(); - a = pio_sm_get_blocking(pio_dcd, SM_DCD_CMD); + a = pio_sm_get_blocking(pioblk_read_only, SM_DCD_CMD); assert(a==2); // now back to idle and awaiting DCD response // busy_wait_us_32(3000); // dcd_assert_hshk(); @@ -1109,11 +1159,11 @@ void pio_mux(PIO pio, uint sm, uint offset, uint in_pin, uint mux_pin) pio_sm_set_enabled(pio, sm, true); } -void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) -{ - latch_program_init(pio, sm, offset, in_pin, out_pin); - pio_sm_set_enabled(pio, sm, true); -} +// void pio_dcd_latch(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin) +// { +// latch_program_init(pio, sm, offset, in_pin, out_pin); +// pio_sm_set_enabled(pio, sm, true); +// } void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin) { From 926beea62ecc0e4dcd37369a2138dbb7e3ecce93 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 18:41:49 -0400 Subject: [PATCH 139/158] mac: test floppy by itself success --- pico/mac/commands.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 98ef89b3a..544f9f7a7 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -316,8 +316,8 @@ void setup() printf("Loaded floppy echo program at %d\n", offset); pio_echo(pioblk_rw, SM_FPY_ECHO, offset, ECHO_IN, ECHO_OUT, 2); - pio_write_offset = pio_add_program(pioblk_rw, &dcd_write_program); - printf("Loaded DCD write program at %d\n", pio_write_offset); + //pio_write_offset = pio_add_program(pioblk_rw, &dcd_write_program); + //printf("Loaded DCD write program at %d\n", pio_write_offset); // pio_dcd_write(pioblk_rw, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); // pio_mux_offset = pio_add_program(pioblk_rw, &dcd_mux_program); @@ -326,7 +326,7 @@ void setup() pio_mux_offset = pio_add_program(pioblk_rw, &mux_program); printf("Loaded Floppy mux program at %d\n", pio_mux_offset); - pio_mux(pioblk_rw, SM_MUX, offset, MCI_CA0, ECHO_OUT); + pio_mux(pioblk_rw, SM_MUX, pio_mux_offset, MCI_CA0, ECHO_OUT); #ifdef FLOPPY set_tach_freq(0); // start TACH clock @@ -378,7 +378,7 @@ void floppy_loop() if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_FPY_CMD)) { a = pio_sm_get_blocking(pioblk_read_only, SM_FPY_CMD); - printf("%d",a); + // printf("%d",a); switch (a) { // !READY From f16c106c3bea00c0be22ff8d1c0e996311b58e3d Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 19:10:48 -0400 Subject: [PATCH 140/158] mac: dcd boots OK --- pico/mac/commands.c | 92 ++++++++++++++++++++++++++++---------------- pico/mac/dcd_mux.pio | 2 + 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 544f9f7a7..3d186812e 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -60,6 +60,8 @@ PIO pioblk_rw = pio1; uint pio_read_offset; uint pio_write_offset; uint pio_mux_offset; +uint pio_floppy_cmd_offset; +uint pio_dcd_cmd_offset; void pio_commands(PIO pio, uint sm, uint offset, uint pin); void pio_echo(PIO pio, uint sm, uint offset, uint in_pin, uint out_pin, uint num_pins); @@ -72,19 +74,7 @@ void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_write(PIO pio, uint sm, uint offset, uint pin); -void pio_switch_to_floppy_mux() -{ - pio_remove_program(pioblk_rw, &dcd_mux_program, pio_mux_offset); - pio_add_program_at_offset(pioblk_rw, &mux_program, pio_mux_offset); - pio_mux(pioblk_rw, SM_MUX, pio_mux_offset, MCI_CA0, ECHO_OUT); -} -void pio_switch_to_dcd_mux() -{ - pio_remove_program(pioblk_rw, &mux_program, pio_mux_offset); - pio_add_program_at_offset(pioblk_rw, &dcd_mux_program, pio_mux_offset); - pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); -} /** * HERE IS UART SETUP @@ -266,6 +256,44 @@ void set_tach_freq(char c) } } +void switch_to_floppy() +{ + // latch + pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO + + // commands + pio_sm_set_enabled(pioblk_read_only, SM_DCD_CMD, false); // stop the DCD command interpreter + pio_commands(pioblk_read_only, SM_FPY_CMD, pio_floppy_cmd_offset, MCI_CA0); // read phases starting on pin 8 + + // mux + pio_remove_program(pioblk_rw, &dcd_mux_program, pio_mux_offset); + pio_add_program_at_offset(pioblk_rw, &mux_program, pio_mux_offset); + pio_mux(pioblk_rw, SM_MUX, pio_mux_offset, MCI_CA0, ECHO_OUT); + + // echo + // pio_sm_set_enabled(pioblk_rw, SM_FPY_ECHO, true); + +} + +void switch_to_dcd() +{ + // latch + pio_sm_put_blocking(pioblk_rw, SM_LATCH, dcd_get_latch()); // send the register word to the PIO + + // commands + pio_sm_set_enabled(pioblk_read_only, SM_FPY_CMD, false); // stop the floppy command interpreter + pio_dcd_commands(pioblk_read_only, SM_DCD_CMD, pio_dcd_cmd_offset, MCI_CA0); // read phases starting on pin 8 + + // mux + pio_remove_program(pioblk_rw, &mux_program, pio_mux_offset); + pio_add_program_at_offset(pioblk_rw, &dcd_mux_program, pio_mux_offset); + pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); + + // echo + // pio_sm_set_enabled(pioblk_rw, SM_FPY_ECHO, false); + +} + void setup() { uint offset; @@ -281,18 +309,19 @@ void setup() /** * put the read-only SM's in PIO0: floppy cmd, dcd cmd, dcd read + * configure as if DCD is default ON */ - offset = pio_add_program(pioblk_read_only, &commands_program); - printf("\nLoaded Floppy cmd program at %d", offset); - pio_commands(pioblk_read_only, SM_FPY_CMD, offset, MCI_CA0); // read phases starting on pin 8 + pio_floppy_cmd_offset = pio_add_program(pioblk_read_only, &commands_program); + printf("\nLoaded Floppy cmd program at %d", pio_floppy_cmd_offset); + // pio_commands(pioblk_read_only, SM_FPY_CMD, pio_floppy_cmd_offset, MCI_CA0); // read phases starting on pin 8 - offset = pio_add_program(pioblk_read_only, &dcd_commands_program); - printf("\nLoaded DCD commands program at %d", offset); - // pio_dcd_commands(pioblk_read_only, SM_DCD_CMD, offset, MCI_CA0); // read phases starting on pin 8 + pio_dcd_cmd_offset = pio_add_program(pioblk_read_only, &dcd_commands_program); + printf("\nLoaded DCD commands program at %d", pio_dcd_cmd_offset); + pio_dcd_commands(pioblk_read_only, SM_DCD_CMD, pio_dcd_cmd_offset, MCI_CA0); // read phases starting on pin 8 pio_read_offset = pio_add_program(pioblk_read_only, &dcd_read_program); printf("\nLoaded DCD read program at %d\n", pio_read_offset); - // pio_dcd_read(pioblk_read_only, SM_DCD_READ, pio_read_offset, MCI_WR); + pio_dcd_read(pioblk_read_only, SM_DCD_READ, pio_read_offset, MCI_WR); /** * put the output SM's in PIO1: echo, dcd write, common latch @@ -316,17 +345,17 @@ void setup() printf("Loaded floppy echo program at %d\n", offset); pio_echo(pioblk_rw, SM_FPY_ECHO, offset, ECHO_IN, ECHO_OUT, 2); - //pio_write_offset = pio_add_program(pioblk_rw, &dcd_write_program); - //printf("Loaded DCD write program at %d\n", pio_write_offset); - // pio_dcd_write(pioblk_rw, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); + pio_write_offset = pio_add_program(pioblk_rw, &dcd_write_program); + printf("Loaded DCD write program at %d\n", pio_write_offset); + pio_dcd_write(pioblk_rw, SM_DCD_WRITE, pio_write_offset, LATCH_OUT); - // pio_mux_offset = pio_add_program(pioblk_rw, &dcd_mux_program); - // printf("Loaded DCD mux program at %d\n", pio_mux_offset); - // pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); + pio_mux_offset = pio_add_program(pioblk_rw, &dcd_mux_program); + printf("Loaded DCD mux program at %d\n", pio_mux_offset); + pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); - pio_mux_offset = pio_add_program(pioblk_rw, &mux_program); - printf("Loaded Floppy mux program at %d\n", pio_mux_offset); - pio_mux(pioblk_rw, SM_MUX, pio_mux_offset, MCI_CA0, ECHO_OUT); + // pio_mux_offset = pio_add_program(pioblk_rw, &mux_program); + // printf("Loaded Floppy mux program at %d\n", pio_mux_offset); + // pio_mux(pioblk_rw, SM_MUX, pio_mux_offset, MCI_CA0, ECHO_OUT); #ifdef FLOPPY set_tach_freq(0); // start TACH clock @@ -360,14 +389,9 @@ int main() setup(); while (true) { - floppy_loop(); -#ifdef FLOPPY - floppy_loop(); -#elif defined(DCD) + // floppy_loop(); dcd_loop(); -#endif } - } bool step_state = false; diff --git a/pico/mac/dcd_mux.pio b/pico/mac/dcd_mux.pio index 28df7a069..f1b8cbc1e 100644 --- a/pico/mac/dcd_mux.pio +++ b/pico/mac/dcd_mux.pio @@ -36,6 +36,8 @@ cont: jmp x-- cont wait 1 gpio ENABLE side 0 .wrap + nop ; need to pad a couple instructions to make it same length as floppy mux + nop % c-sdk { // this is a raw helper function for use by the user which sets up the GPIO input and output, and configures the SM to output on a particular pin From 8f4263b6f9d8a8bdd2ac16e1eebce62438130707 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 20:56:46 -0400 Subject: [PATCH 141/158] mac: cleanup to make more better --- pico/mac/commands.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 3d186812e..4f1e68396 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -14,6 +14,7 @@ #include "pico/stdlib.h" #include "hardware/uart.h" #include "hardware/clocks.h" +#include "hardware/claim.h" #include "hardware/pio.h" #include "hardware/pio_instructions.h" @@ -387,6 +388,7 @@ void floppy_loop(); int main() { setup(); + // switch_to_floppy(); while (true) { // floppy_loop(); @@ -394,10 +396,9 @@ int main() } } -bool step_state = false; void floppy_loop() { - //static bool step_state = false; + static bool step_state = false; if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_FPY_CMD)) { @@ -586,7 +587,6 @@ void dcd_loop() // printf("\nHandshake\n"); if (olda == 2) { - //pio_sm_restart(pio_dcd_rw, SM_DCD_READ); pio_dcd_read(pioblk_read_only, SM_DCD_READ, pio_read_offset, MCI_WR); // re-init pio_sm_set_enabled(pioblk_read_only, SM_DCD_READ, true); dcd_assert_hshk(); @@ -597,8 +597,7 @@ void dcd_loop() dcd_deassert_hshk(); pio_sm_set_enabled(pioblk_rw, SM_DCD_WRITE, false); pio_sm_set_enabled(pioblk_rw, SM_LATCH, true); - pio_sm_exec(pioblk_rw, SM_MUX, 0xe080); // set pindirs 0 to do swap with below - // pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_set(pio_pindirs, 0)); // set pindirs 0 + pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_set(pio_pindirs, 0)); break; default: host = false; @@ -618,15 +617,13 @@ void dcd_loop() num_dcd_drives = uart_getc(UART_ID); printf("\nNumber of DCD's mounted: %d", num_dcd_drives); // need to set number in DCD mux PIO and reset the machine - // set x, N side 0 ; put the number of DCD devices in X (0xf02N - last digit is number of DCDs) - // uint instr = 0xf020 + num_dcd_drives; - // pause the machine, change the instruction, move the PC, resume + // pause the machine, change the instruction, move the PC, resume pio_sm_set_enabled(pioblk_rw, SM_MUX, false); - volatile uint *target; - target = (uint *)(PIO1_BASE + PIO_INSTR_MEM0_OFFSET + 4*pio_mux_offset); - *target = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); - pio_sm_set_enabled(pioblk_rw, SM_MUX, true); + uint32_t save = hw_claim_lock(); + pioblk_rw->instr_mem[pio_mux_offset] = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); + hw_claim_unlock(save); pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_jmp(pio_mux_offset)); + pio_sm_set_enabled(pioblk_rw, SM_MUX, true); break; default: break; From 4520da19d6f9fe4d3d2584b5d87fb264fe49cd8b Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 22:33:52 -0400 Subject: [PATCH 142/158] mac: remove some debug traffic --- pico/mac/commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 4f1e68396..57b7c2be7 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -759,7 +759,7 @@ void dcd_read(uint8_t ntx) for (uint8_t i=0; i> 16) & 0xff); @@ -849,7 +849,7 @@ OR while(uart_is_readable(UART_ID)) uart_getc(UART_ID); - printf("writing sector %06x in %d groups\n", sector, ntx); + // printf("writing sector %06x in %d groups\n", sector, ntx); uart_putc_raw(UART_ID, 'W'); uart_putc_raw(UART_ID, (sector >> 16) & 0xff); From 9d5ace2f513d6c9b6cbcca6c5a6c3fa49d356e17 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 22:52:52 -0400 Subject: [PATCH 143/158] mac: dont tell esp to use the floppy as active dcd --- pico/mac/commands.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 57b7c2be7..58d174b34 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -547,9 +547,13 @@ void dcd_loop() { if (!pio_sm_is_rx_fifo_empty(pioblk_rw, SM_MUX)) { - active_disk_number = num_dcd_drives + 'A' - pio_sm_get_blocking(pioblk_rw, SM_MUX); - printf("%c", active_disk_number); - uart_putc_raw(UART_ID, active_disk_number); + int m = pio_sm_get_blocking(pioblk_rw, SM_MUX); + if (m != 0) + { + active_disk_number = num_dcd_drives + 'A' - m; + printf("%c", active_disk_number); + uart_putc_raw(UART_ID, active_disk_number); + } } if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_DCD_CMD)) @@ -622,8 +626,9 @@ void dcd_loop() uint32_t save = hw_claim_lock(); pioblk_rw->instr_mem[pio_mux_offset] = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); hw_claim_unlock(save); - pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_jmp(pio_mux_offset)); - pio_sm_set_enabled(pioblk_rw, SM_MUX, true); + pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); + // pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_jmp(pio_mux_offset)); + // pio_sm_set_enabled(pioblk_rw, SM_MUX, true); break; default: break; From cf8f6d654a2737704b7d64377c85e12b8bb1c29e Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 21 Oct 2023 23:04:47 -0400 Subject: [PATCH 144/158] mac: start up as DCD --- pico/mac/commands.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 58d174b34..d982ed98d 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -339,8 +339,7 @@ void setup() offset = pio_add_program(pioblk_rw, &latch_program); printf("\nLoaded latch program at %d\n", offset); pio_latch(pioblk_rw, SM_LATCH, offset, MCI_CA0, LATCH_OUT); - // pio_sm_put_blocking(pioblk_rw, SM_LATCH, dcd_get_latch()); // send the register word to the PIO - pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO + pio_sm_put_blocking(pioblk_rw, SM_LATCH, dcd_get_latch()); // send the register word to the PIO offset = pio_add_program(pioblk_rw, &echo_program); printf("Loaded floppy echo program at %d\n", offset); From 7d6f4d4d87d696e690d02cff63e8d28d2b4588b8 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 21 Oct 2023 22:47:07 -0500 Subject: [PATCH 145/158] keys: disable all buttons if defined --- lib/hardware/keys.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/hardware/keys.cpp b/lib/hardware/keys.cpp index 518ba1b67..8c80325ec 100755 --- a/lib/hardware/keys.cpp +++ b/lib/hardware/keys.cpp @@ -74,6 +74,13 @@ void KeyManager::setup() #endif } +#ifdef NO_BUTTONS + _keys[eKey::BUTTON_A].disabled = true; + _keys[eKey::BUTTON_B].disabled = true; + _keys[eKey::BUTTON_C].disabled = true; + Debug_println("NO_BUTTONS: disabled all buttons"); +#endif /* PINMAP_IEC_NUGGET */ + #endif /* PINMAP_ESP32S3 */ // Start a new task to check the status of the buttons From 35cca9bf48be87c9fb30bbb2b4afc65d1918b3a4 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 21 Oct 2023 22:48:14 -0500 Subject: [PATCH 146/158] Add IEC Nugget build_board --- data/webui/config/nugget-iec.yaml | 18 ++++++++++ include/pinmap.h | 1 + include/pinmap/iec-nugget.h | 59 +++++++++++++++++++++++++++++++ platformio-sample.ini | 14 ++++++++ 4 files changed, 92 insertions(+) create mode 100644 data/webui/config/nugget-iec.yaml create mode 100644 include/pinmap/iec-nugget.h diff --git a/data/webui/config/nugget-iec.yaml b/data/webui/config/nugget-iec.yaml new file mode 100644 index 000000000..80ad06191 --- /dev/null +++ b/data/webui/config/nugget-iec.yaml @@ -0,0 +1,18 @@ +paths: + font_path: /file? + css_path: /file?css + js_path: /file?js +components: + network: true + hardware: true + hosts_list: true + mount_list: true + printer_settings: true + modem_settings: false + hsio_settings: false + timezone: true + udp_stream: true + program_recorder: false + disk_swap: true + boot_settings: true + apetime: false diff --git a/include/pinmap.h b/include/pinmap.h index e15088836..d6912c0a3 100644 --- a/include/pinmap.h +++ b/include/pinmap.h @@ -9,6 +9,7 @@ #include "pinmap/adamv1.h" #include "pinmap/iec.h" #include "pinmap/iec-d32pro.h" +#include "pinmap/iec-nugget.h" #include "pinmap/fujiloaf-rev0.h" #include "pinmap/fujiapple-iec.h" #include "pinmap/esp32s3.h" diff --git a/include/pinmap/iec-nugget.h b/include/pinmap/iec-nugget.h new file mode 100644 index 000000000..ef940fc33 --- /dev/null +++ b/include/pinmap/iec-nugget.h @@ -0,0 +1,59 @@ +#ifndef PINMAP_IEC_NUGGET_H +#define PINMAP_IEC_NUGGET_H + +#ifdef PINMAP_IEC_NUGGET + +/* SD Card */ +// pins 12-15 are used to interface with the JTAG debugger +// so leave them alone if we're using JTAG +#ifndef JTAG +#define PIN_CARD_DETECT GPIO_NUM_12 // fnSystem.h +#define PIN_CARD_DETECT_FIX GPIO_NUM_15 // fnSystem.h +#endif + +#define PIN_SD_HOST_CS GPIO_NUM_4 // LOLIN D32 Pro +#define PIN_SD_HOST_MISO GPIO_NUM_19 +#define PIN_SD_HOST_MOSI GPIO_NUM_23 +#define PIN_SD_HOST_SCK GPIO_NUM_18 + +/* UART */ +#define PIN_UART0_RX GPIO_NUM_3 // fnUART.cpp +#define PIN_UART0_TX GPIO_NUM_1 +#define PIN_UART1_RX GPIO_NUM_9 +#define PIN_UART1_TX GPIO_NUM_10 +#define PIN_UART2_RX GPIO_NUM_33 +#define PIN_UART2_TX GPIO_NUM_21 + +/* Buttons */ +#define PIN_BUTTON_A GPIO_NUM_NC // keys.cpp +#define PIN_BUTTON_B GPIO_NUM_NC +#define PIN_BUTTON_C GPIO_NUM_NC + +/* LEDs */ +#define PIN_LED_WIFI GPIO_NUM_5 // led.cpp +#define PIN_LED_BUS GPIO_NUM_2 // 4 FN + +// pins 12-15 are used to interface with the JTAG debugger +// so leave them alone if we're using JTAG +#ifndef JTAG +#define PIN_LED_BT GPIO_NUM_13 +#else +#define PIN_LED_BT GPIO_NUM_5 // LOLIN D32 PRO +#endif + +/* Audio Output */ +#define PIN_DAC1 GPIO_NUM_25 // samlib.h + +/* Commodore IEC Pins */ +//#define IEC_HAS_RESET // Reset line is available + +#define PIN_IEC_RESET GPIO_NUM_34 +#define PIN_IEC_ATN GPIO_NUM_32 +#define PIN_IEC_CLK_IN GPIO_NUM_33 +#define PIN_IEC_CLK_OUT GPIO_NUM_33 +#define PIN_IEC_DATA_IN GPIO_NUM_14 +#define PIN_IEC_DATA_OUT GPIO_NUM_14 +#define PIN_IEC_SRQ GPIO_NUM_27 + +#endif // PINMAP_IEC_NUGGET +#endif // PINMAP_IEC_NUGGET_H \ No newline at end of file diff --git a/platformio-sample.ini b/platformio-sample.ini index 55eb76a6d..e6b85374d 100644 --- a/platformio-sample.ini +++ b/platformio-sample.ini @@ -52,6 +52,7 @@ flash_filesystem = FLASH_SPIFFS ;build_board = fujiloaf-rev0 ; Commodore IEC FujiLoaf Rev0 Prototype ;build_board = fujiapple-iec ; Commodore IEC using FujiApple Rev0 ;build_board = lolin-d32-iec ; Commodore IEC using Lolin D32 Pro +;build_board = nugget-iec ; Commodore IEC using Lolin D32 Pro "Nugget" ;build_platform = BUILD_LYNX ;build_bus = comlynx @@ -249,6 +250,19 @@ build_flags = ;-D DEBUG_TIMING ; IEC Timing ;-D DATA_STREAM +; Commodore IEC using Lolin D32 Pro "Nugget" (ESP32-WROVER 16MB Flash, 8MB PSRAM) +[env:nugget-iec] +platform = espressif32@${fujinet.esp32_platform_version} +platform_packages = ${fujinet.esp32_platform_packages} +board = fujinet-v1 +build_type = debug +build_flags = + ${env.build_flags} + -D PINMAP_IEC_NUGGET + -D NO_BUTTONS ; Nugget only has Hard Reset button + ;-D DEBUG_TIMING ; IEC Timing + ;-D DATA_STREAM + ; Color Computer Drivewire using Lolin D32 Pro (ESP32-WROVER 16MB Flash, 8MB PSRAM) [env:lolin-d32-dw] platform = espressif32@${fujinet.esp32_platform_version} From 65adf25de63c7827067ad3e647cbf0f838787c32 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 21 Oct 2023 22:48:46 -0500 Subject: [PATCH 147/158] apple: update autorun.po --- .../device_specific/BUILD_APPLE/autorun.po | Bin 143360 -> 143360 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/webui/device_specific/BUILD_APPLE/autorun.po b/data/webui/device_specific/BUILD_APPLE/autorun.po index 9f05668bb9ddd3b41a670a6085a028d36a1ada3c..8b7fb753290f6bb5e32a8006e90196dba439a31d 100644 GIT binary patch delta 16984 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 delta 16982 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 I81}aR28JRpG5`Po From 0912d978d763e720952eef392da51c53afe21886 Mon Sep 17 00:00:00 2001 From: Mike Wiese Date: Sun, 22 Oct 2023 14:13:51 -0700 Subject: [PATCH 148/158] Add .DO support. Look inside .DSK files to detect sector order. --- lib/device/iwm/disk.cpp | 23 ++++++-- lib/device/iwm/disk2.cpp | 4 +- lib/media/apple/mediaType.cpp | 32 ++++++++++- lib/media/apple/mediaType.h | 4 +- lib/media/apple/mediaTypeDO.cpp | 99 ++++++++++++++++++++++++++++++++ lib/media/apple/mediaTypeDO.h | 26 +++++++++ lib/media/apple/mediaTypeDSK.cpp | 6 +- lib/media/media.h | 1 + 8 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 lib/media/apple/mediaTypeDO.cpp create mode 100644 lib/media/apple/mediaTypeDO.h diff --git a/lib/device/iwm/disk.cpp b/lib/device/iwm/disk.cpp index 9f927db02..b5022ca6c 100644 --- a/lib/device/iwm/disk.cpp +++ b/lib/device/iwm/disk.cpp @@ -515,17 +515,33 @@ mediatype_t iwmDisk::mount(FILE *f, const char *filename, uint32_t disksize, med } // Determine MediaType based on filename extension - if (disk_type == MEDIATYPE_UNKNOWN && filename != nullptr) + if (disk_type == MEDIATYPE_UNKNOWN && filename != nullptr) { disk_type = MediaType::discover_mediatype(filename); + if (disk_type == MEDIATYPE_DSK) { + // determine DO or PO based on file contents + disk_type = MediaType::discover_dsk_mediatype(f, disksize); + } + } if (deviceSlot < 4) // SP drive { switch (disk_type) { + case MEDIATYPE_DO: + Debug_printf("\r\nMedia Type DO"); + _disk = new MediaTypeDO(); + _disk->_media_host = host; + _disk->_mediatype = disk_type; + strcpy(_disk->_disk_filename, filename); + mt = _disk->mount(f, disksize); + + device_active = true; //change status only after we are mounted + break; case MEDIATYPE_PO: Debug_printf("\r\nMedia Type PO"); _disk = new MediaTypePO(); _disk->_media_host = host; + _disk->_mediatype = disk_type; strcpy(_disk->_disk_filename, filename); mt = _disk->mount(f, disksize); @@ -535,8 +551,6 @@ mediatype_t iwmDisk::mount(FILE *f, const char *filename, uint32_t disksize, med readonly = false; device_active = true; //change status only after we are mounted - //_disk->fileptr() = f; - // mt = MEDIATYPE_PO; break; default: Debug_printf("\r\nMedia Type UNKNOWN for SP Drive - no mount in disk.cpp"); @@ -548,7 +562,8 @@ mediatype_t iwmDisk::mount(FILE *f, const char *filename, uint32_t disksize, med { switch (disk_type) { - case MEDIATYPE_DSK: + case MEDIATYPE_DO: + case MEDIATYPE_PO: case MEDIATYPE_WOZ: theFuji._fnDisk2s[deviceSlot - 4].init(); theFuji._fnDisk2s[deviceSlot - 4].mount(f, disk_type); // modulo to ensure device 0 or 1 diff --git a/lib/device/iwm/disk2.cpp b/lib/device/iwm/disk2.cpp index a11862ad1..5916a5632 100644 --- a/lib/device/iwm/disk2.cpp +++ b/lib/device/iwm/disk2.cpp @@ -60,10 +60,12 @@ mediatype_t iwmDisk2::mount(FILE *f, mediatype_t disk_type)//, const char *filen mt = ((MediaTypeWOZ *)_disk)->mount(f); change_track(0); // initialize spi buffer break; - case MEDIATYPE_DSK: + case MEDIATYPE_DO: + case MEDIATYPE_PO: Debug_printf("\nMounting Media Type DSK"); device_active = true; _disk = new MediaTypeDSK(); + _disk->_mediatype = disk_type; mt = ((MediaTypeDSK *)_disk)->mount(f); change_track(0); // initialize spi buffer break; diff --git a/lib/media/apple/mediaType.cpp b/lib/media/apple/mediaType.cpp index 7fdd2a2c8..356682143 100644 --- a/lib/media/apple/mediaType.cpp +++ b/lib/media/apple/mediaType.cpp @@ -1,6 +1,7 @@ #ifdef BUILD_APPLE #include "mediaType.h" +#include "utils.h" #include #include @@ -58,8 +59,37 @@ mediatype_t MediaType::discover_mediatype(const char *filename) const char *ext = filename + l - 2; if (strcasecmp(ext, "PO") == 0) return MEDIATYPE_PO; + else if (strcasecmp(ext, "DO") == 0) + return MEDIATYPE_DO; } return MEDIATYPE_UNKNOWN; } -#endif // NEW_TARGET \ No newline at end of file +mediatype_t MediaType::discover_dsk_mediatype(FILE *f, uint32_t disksize) +{ + mediatype_t default_mt = MEDIATYPE_DO; + + const size_t header_size = 64; + uint8_t hdr[header_size]; + + // a ProDOS Volume Directory Header is always in block 2, + // if the file is in ProDOS order, it will be at offset 1024 + if (fseek(f, 1024, SEEK_SET) != 0) + return default_mt; + + if (fread(hdr, 1, header_size, f) != header_size) + return default_mt; + + uint16_t prevPointer = UINT16_FROM_HILOBYTES(hdr[1], hdr[0]); + uint8_t storage_type = hdr[4] >> 4; + uint16_t total_blocks = UINT16_FROM_HILOBYTES(hdr[0x2A], hdr[0x29]); + + if (prevPointer == 0 && storage_type == 0xF && total_blocks == (disksize / 512)) { + // looks like a valid volume header, assume file is in ProDOS order + return MEDIATYPE_PO; + } + + return default_mt; +} + +#endif // BUILD_APPLE diff --git a/lib/media/apple/mediaType.h b/lib/media/apple/mediaType.h index a5709e71f..b36007eef 100644 --- a/lib/media/apple/mediaType.h +++ b/lib/media/apple/mediaType.h @@ -17,9 +17,10 @@ enum mediatype_t { MEDIATYPE_UNKNOWN = 0, + MEDIATYPE_DO, + MEDIATYPE_DSK, MEDIATYPE_PO, MEDIATYPE_WOZ, - MEDIATYPE_DSK, MEDIATYPE_COUNT }; @@ -85,6 +86,7 @@ class MediaType virtual bool status() = 0; static mediatype_t discover_mediatype(const char *filename); + static mediatype_t discover_dsk_mediatype(FILE* f, uint32_t disksize); // void dump_percom_block(); // void derive_percom_block(uint16_t numSectors); diff --git a/lib/media/apple/mediaTypeDO.cpp b/lib/media/apple/mediaTypeDO.cpp new file mode 100644 index 000000000..ddfee8a57 --- /dev/null +++ b/lib/media/apple/mediaTypeDO.cpp @@ -0,0 +1,99 @@ +#ifdef BUILD_APPLE + +#include "mediaTypeDO.h" + +#include +#include "utils.h" +#include "../../include/debug.h" + +#define BYTES_PER_BLOCK 512 +#define BLOCKS_PER_TRACK 8 +#define BYTES_PER_SECTOR 256 +#define BYTES_PER_TRACK 4096 + +// .DO (DOS ordered) disk images are stored in DOS 3.3 logical sector order. +// Each 512 byte ProDOS block is stored as two 256 byte DOS sectors. +// see https://retrocomputing.stackexchange.com/questions/15056/converting-apple-ii-prodos-blocks-to-dos-tracks-and-sectors + +// This table maps ProDOS blocks to pairs of DOS logical sectors. +static const int prodos2dos[8][2] = { {0, 14}, {13, 12}, {11, 10}, {9, 8}, {7, 6}, {5, 4}, {3, 2}, {1, 15} }; + +bool MediaTypeDO::read(uint32_t blockNum, uint16_t *count, uint8_t* buffer) +{ + bool err = false; + uint32_t track = blockNum / BLOCKS_PER_TRACK; + const int* sectors = prodos2dos[blockNum % BLOCKS_PER_TRACK]; + + err = read_sector(track, sectors[0], buffer); + + if (!err) + err = read_sector(track, sectors[1], &buffer[BYTES_PER_SECTOR]); + + return err; +} + +bool MediaTypeDO::read_sector(int track, int sector, uint8_t* buffer) +{ + Debug_printf("\r\nMediaTypeDO read track %d sector %d", track, sector); + + bool err = false; + uint32_t offset = (track * BYTES_PER_TRACK) + (sector * BYTES_PER_SECTOR); + + err = fseek(_media_fileh, offset, SEEK_SET) != 0; + + if (!err) + err = fread(buffer, 1, BYTES_PER_SECTOR, _media_fileh) != BYTES_PER_SECTOR; + + return err; +} + +bool MediaTypeDO::write(uint32_t blockNum, uint16_t *count, uint8_t* buffer) +{ + // Return an error if we're trying to write beyond the end of the disk + if (blockNum >= num_blocks) + { + Debug_printf("\r\nwrite block BEYOND END %lu > %lu", blockNum, num_blocks); + return true; + } + + bool err = false; + uint32_t track = blockNum / BLOCKS_PER_TRACK; + const int* sectors = prodos2dos[blockNum % BLOCKS_PER_TRACK]; + + err = write_sector(track, sectors[0], buffer); + + if (!err) + err = write_sector(track, sectors[1], &buffer[BYTES_PER_SECTOR]); + + return err; +} + +bool MediaTypeDO::write_sector(int track, int sector, uint8_t* buffer) +{ + Debug_printf("\r\nMediaTypeDO write track %d sector %d", track, sector); + + bool err = false; + uint32_t offset = (track * BYTES_PER_TRACK) + (sector * BYTES_PER_SECTOR); + + err = fseek(_media_fileh, offset, SEEK_SET) != 0; + + if (!err) + err = fwrite(buffer, 1, BYTES_PER_SECTOR, _media_fileh) != BYTES_PER_SECTOR; + + return err; +} + +bool MediaTypeDO::format(uint16_t *respopnsesize) +{ + return false; +} + +mediatype_t MediaTypeDO::mount(FILE *f, uint32_t disksize) +{ + diskiiemulation = false; + _media_fileh = f; + num_blocks = disksize / BYTES_PER_BLOCK; + return MEDIATYPE_DO; +} + +#endif // BUILD_APPLE diff --git a/lib/media/apple/mediaTypeDO.h b/lib/media/apple/mediaTypeDO.h new file mode 100644 index 000000000..b29c5bd2f --- /dev/null +++ b/lib/media/apple/mediaTypeDO.h @@ -0,0 +1,26 @@ +#ifndef _MEDIATYPE_DO_ +#define _MEDIATYPE_DO_ + +#include + +#include "mediaType.h" + +class MediaTypeDO : public MediaType +{ +private: + bool read_sector(int track, int sector, uint8_t* buffer); + bool write_sector(int track, int sector, uint8_t* buffer); + +public: + virtual bool read(uint32_t blockNum, uint16_t *count, uint8_t* buffer) override; + virtual bool write(uint32_t blockNum, uint16_t *count, uint8_t* buffer) override; + + virtual bool format(uint16_t *respopnsesize) override; + + virtual mediatype_t mount(FILE *f, uint32_t disksize) override; + + virtual bool status() override {return (_media_fileh != nullptr);} +}; + + +#endif // _MEDIATYPE_DO_ diff --git a/lib/media/apple/mediaTypeDSK.cpp b/lib/media/apple/mediaTypeDSK.cpp index 2837e8d46..ccb40a27e 100644 --- a/lib/media/apple/mediaTypeDSK.cpp +++ b/lib/media/apple/mediaTypeDSK.cpp @@ -25,10 +25,11 @@ mediatype_t MediaTypeDSK::mount(FILE *f, uint32_t disksize) // allocated SPRAM const size_t dsk_image_size = 35 * 16 * 256; uint8_t *dsk = (uint8_t*)heap_caps_malloc(dsk_image_size, MALLOC_CAP_SPIRAM); + if (fseek(f, 0, SEEK_SET) != 0) + return MEDIATYPE_UNKNOWN; size_t bytes_read = fread(dsk, 1, dsk_image_size, f); if (bytes_read != dsk_image_size) return MEDIATYPE_UNKNOWN; - const bool is_prodos = false; dsk2woz_info(); dsk2woz_tmap(); @@ -87,6 +88,7 @@ bool MediaTypeDSK::dsk2woz_tracks(uint8_t *dsk) // Debug_printf("\nStart Block, Block Count, Bit Count"); + Debug_printf("\nMediaTypeDSK is_prodos: %s", _mediatype == MEDIATYPE_PO ? "Y" : "N"); // TODO: adapt this to that // Write out all 35 tracks. @@ -99,7 +101,7 @@ bool MediaTypeDSK::dsk2woz_tracks(uint8_t *dsk) { trk_ptrs[c] = temp_ptr; memset(trk_ptrs[c], 0, WOZ1_NUM_BLKS * 512); - serialise_track(trk_ptrs[c], &dsk[c * 16 * 256], c, false); + serialise_track(trk_ptrs[c], &dsk[c * 16 * 256], c, _mediatype == MEDIATYPE_PO); temp_ptr += WOZ1_TRACK_LEN; bytes_used = temp_ptr[0] + (temp_ptr[1] << 8); temp_ptr += sizeof(uint16_t); diff --git a/lib/media/media.h b/lib/media/media.h index c38252e15..1d6a8c298 100644 --- a/lib/media/media.h +++ b/lib/media/media.h @@ -31,6 +31,7 @@ #ifdef BUILD_APPLE # include "apple/mediaType.h" +# include "apple/mediaTypeDO.h" # include "apple/mediaTypePO.h" # include "apple/mediaTypeWOZ.h" # include "apple/mediaTypeDSK.h" From e61487e991fdb05ef608639b8f503c21063cca25 Mon Sep 17 00:00:00 2001 From: Mike Wiese Date: Mon, 23 Oct 2023 23:26:07 -0700 Subject: [PATCH 149/158] fix web mount list on apple2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix web interface mount list to not show (D�:) on every drive slot. - change `get_disk_id` to return 0 instead of -1 The return type of `get_disk_id` is `int`. but the only caller casts it to `char`, and then checks if it is > 0. Unfortunately `char` is unsigned, so that didn’t work as intended. --- lib/device/iwm/fuji.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/iwm/fuji.cpp b/lib/device/iwm/fuji.cpp index 48f7394c5..4cc115faf 100644 --- a/lib/device/iwm/fuji.cpp +++ b/lib/device/iwm/fuji.cpp @@ -1105,7 +1105,7 @@ void iwmFuji::setup(iwmBus *iwmbus) int iwmFuji::get_disk_id(int drive_slot) { - return -1; + return 0; } std::string iwmFuji::get_host_prefix(int host_slot) { From 9ceebad0f3dd096740e644d9185ceb19e0a8b9f7 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Wed, 25 Oct 2023 19:12:42 -0400 Subject: [PATCH 150/158] committing before surgery --- pico/mac/commands.c | 66 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/pico/mac/commands.c b/pico/mac/commands.c index d982ed98d..63e6aeed4 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -383,22 +383,66 @@ void setup() void dcd_loop(); void floppy_loop(); +void esp_loop(); + +enum disk_mode_t { + DCD = 0, + TO_FPY, + FPY, + TO_DCD +} disk_mode = DCD; int main() { - setup(); - // switch_to_floppy(); - while (true) + setup(); + // switch_to_floppy(); + while (true) + { + switch (disk_mode) { - // floppy_loop(); + case DCD: dcd_loop(); + break; + case TO_FPY: + switch_to_floppy(); + disk_mode = FPY; + // fall thru + case FPY: + floppy_loop(); + break; + case TO_DCD: + switch_to_dcd(); + disk_mode = DCD; + default: + break; } + } } +void esp_loop() +{ + if (uart_is_readable(UART_ID)) + { + // !READY + // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. + // !READY is a zero when + // the head position is settled on disired track, + // motor is at the desired speed, + // and a diskette is in the drive. + c = uart_getc(UART_ID); + } + +} void floppy_loop() { static bool step_state = false; + if (gpio_get(ENABLE)) + { + disk_mode = TO_DCD; + return; + } + if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_FPY_CMD)) { a = pio_sm_get_blocking(pioblk_read_only, SM_FPY_CMD); @@ -471,15 +515,16 @@ void floppy_loop() step_state = false; } - if (uart_is_readable(UART_ID)) + if (c != 0) { + // !READY // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. // !READY is a zero when // the head position is settled on disired track, // motor is at the desired speed, // and a diskette is in the drive. - c = uart_getc(UART_ID); + // to do: figure out when to clear !READY if (c & 128) { @@ -524,8 +569,8 @@ void floppy_loop() default: break; } - // printf("latch %04x", get_latch()); - pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO + // printf("latch %04x", get_latch()); + pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO } // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO // to do: read both enable lines and indicate which drive is active when sending single char to esp32 @@ -553,6 +598,11 @@ void dcd_loop() printf("%c", active_disk_number); uart_putc_raw(UART_ID, active_disk_number); } + else + { + disk_mode = TO_FPY; + return; + } } if (!pio_sm_is_rx_fifo_empty(pioblk_read_only, SM_DCD_CMD)) From 9e2bd9b1e29d145e54a266eed99ddd601aed06b1 Mon Sep 17 00:00:00 2001 From: Jeff Piepmeier Date: Sat, 28 Oct 2023 08:21:11 -0400 Subject: [PATCH 151/158] mac: floppy alone, dcd alone, but cant autoswitch --- lib/bus/mac/mac.cpp | 1 + lib/device/mac/floppy.cpp | 5 ++ lib/media/mac/mediaTypeMOOF.cpp | 3 ++ pico/mac/commands.c | 82 ++++++++++++++++++--------------- 4 files changed, 53 insertions(+), 38 deletions(-) diff --git a/lib/bus/mac/mac.cpp b/lib/bus/mac/mac.cpp index 250c6e54c..87232a4b8 100644 --- a/lib/bus/mac/mac.cpp +++ b/lib/bus/mac/mac.cpp @@ -130,6 +130,7 @@ void macBus::service(void) case 'B': case 'C': case 'D': + case 'E': _active_DCD_disk = c-'A'; // 0, 1, 2, 3 Debug_printf("\nactive disk %d", _active_DCD_disk); break; diff --git a/lib/device/mac/floppy.cpp b/lib/device/mac/floppy.cpp index 29687ceb0..306a3ee61 100644 --- a/lib/device/mac/floppy.cpp +++ b/lib/device/mac/floppy.cpp @@ -136,6 +136,11 @@ void macFloppy::unmount() ((MediaTypeMOOF *)_disk)->unmount(); else if (_disk != nullptr) _disk->unmount(); + if (_disk != nullptr) + free(_disk); + + _disk = nullptr; + MAC.rem_dcd_mount(id()); device_active = false; } diff --git a/lib/media/mac/mediaTypeMOOF.cpp b/lib/media/mac/mediaTypeMOOF.cpp index f41229b5f..a7794edd3 100644 --- a/lib/media/mac/mediaTypeMOOF.cpp +++ b/lib/media/mac/mediaTypeMOOF.cpp @@ -33,6 +33,8 @@ void MediaTypeMOOF::unmount() { if (trk_ptrs[i] != nullptr) free(trk_ptrs[i]); + + trk_ptrs[i] = nullptr; } #else free(trk_buffer); @@ -182,6 +184,7 @@ bool MediaTypeMOOF::moof_read_tracks() // read MOOF tracks into RAM for (int i = 0; i < MAX_TRACKS; i++) { + trk_ptrs[i] = nullptr; size_t s = trks[i].block_count * 512; if (s != 0) { diff --git a/pico/mac/commands.c b/pico/mac/commands.c index 63e6aeed4..690a10fb5 100644 --- a/pico/mac/commands.c +++ b/pico/mac/commands.c @@ -74,6 +74,7 @@ void pio_dcd_commands(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_mux(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_read(PIO pio, uint sm, uint offset, uint pin); void pio_dcd_write(PIO pio, uint sm, uint offset, uint pin); +void set_num_dcd(); @@ -100,12 +101,6 @@ void setup_esp_uart() /** * DATA NEEDED FOR OPERATION */ -const int tach_lut[5][3] = {{0, 15, 394}, - {16, 31, 429}, - {32, 47, 472}, - {48, 63, 525}, - {64, 79, 590}}; - uint32_t a; uint32_t b[12]; char c; @@ -245,11 +240,18 @@ void dcd_preset_latch() void set_tach_freq(char c) { + const int tach_lut[5][3] = {{0, 15, 394}, + {16, 31, 429}, + {32, 47, 472}, + {48, 63, 525}, + {64, 79, 590}}; + // To configure a clock, we need to know the following pieces of information: // The frequency of the clock source // The mux / aux mux position of the clock source // The desired output frequency // use 125 MHZ PLL as a source + for (int i = 0; i < 5; i++) { if ((c >= tach_lut[i][0]) && (c <= tach_lut[i][1])) @@ -289,12 +291,24 @@ void switch_to_dcd() pio_remove_program(pioblk_rw, &mux_program, pio_mux_offset); pio_add_program_at_offset(pioblk_rw, &dcd_mux_program, pio_mux_offset); pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); + set_num_dcd(); // echo // pio_sm_set_enabled(pioblk_rw, SM_FPY_ECHO, false); } +void set_num_dcd() +{ + // need to set number in DCD mux PIO and reset the machine + // pause the machine, change the instruction, move the PC, resume + pio_sm_set_enabled(pioblk_rw, SM_MUX, false); + uint32_t save = hw_claim_lock(); + pioblk_rw->instr_mem[pio_mux_offset] = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); + hw_claim_unlock(save); + pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); +} + void setup() { uint offset; @@ -398,6 +412,7 @@ int main() // switch_to_floppy(); while (true) { + esp_loop(); switch (disk_mode) { case DCD: @@ -423,21 +438,28 @@ void esp_loop() { if (uart_is_readable(UART_ID)) { - // !READY - // This status line is used to indicate that the host system can read the recorded data on the disk or write data to the disk. - // !READY is a zero when - // the head position is settled on disired track, - // motor is at the desired speed, - // and a diskette is in the drive. c = uart_getc(UART_ID); + // handle comms from ESP32 + switch (c) + { + case 'h': // harddisk is mounted/unmounted + num_dcd_drives = uart_getc(UART_ID); + printf("\nNumber of DCD's mounted: %d", num_dcd_drives); + if (disk_mode == DCD) + set_num_dcd(); + c = 0; // need to clear c so not picked up by floppy loop although it would never respond to 'h' + break; + default: + break; + } } - } + void floppy_loop() { static bool step_state = false; - if (gpio_get(ENABLE)) + if (gpio_get(ENABLE) && (num_dcd_drives > 0)) { disk_mode = TO_DCD; return; @@ -571,8 +593,8 @@ void floppy_loop() } // printf("latch %04x", get_latch()); pio_sm_put_blocking(pioblk_rw, SM_LATCH, get_latch()); // send the register word to the PIO + c = 0; // clear c because processed it and don't want infinite loop } - // to do: get response from ESP32 and update latch values (like READY, TACH), push LATCH value to PIO // to do: read both enable lines and indicate which drive is active when sending single char to esp32 } @@ -589,9 +611,16 @@ void dcd_process(uint8_t nrx, uint8_t ntx); void dcd_loop() { + if (num_dcd_drives == 0) + { + disk_mode = TO_FPY; + return; + } + if (!pio_sm_is_rx_fifo_empty(pioblk_rw, SM_MUX)) { int m = pio_sm_get_blocking(pioblk_rw, SM_MUX); + printf("m%dm",m); if (m != 0) { active_disk_number = num_dcd_drives + 'A' - m; @@ -660,29 +689,6 @@ void dcd_loop() printf("%c", a + '0'); } - // handle comms from ESP32 - if (uart_is_readable(UART_ID)) - { - c = uart_getc(UART_ID); - switch (c) - { - case 'h': // harddisk is mounted/unmounted - num_dcd_drives = uart_getc(UART_ID); - printf("\nNumber of DCD's mounted: %d", num_dcd_drives); - // need to set number in DCD mux PIO and reset the machine - // pause the machine, change the instruction, move the PC, resume - pio_sm_set_enabled(pioblk_rw, SM_MUX, false); - uint32_t save = hw_claim_lock(); - pioblk_rw->instr_mem[pio_mux_offset] = pio_encode_set(pio_x, num_dcd_drives) | pio_encode_sideset_opt(1, 0); - hw_claim_unlock(save); - pio_dcd_mux(pioblk_rw, SM_MUX, pio_mux_offset, LATCH_OUT); - // pio_sm_exec(pioblk_rw, SM_MUX, pio_encode_jmp(pio_mux_offset)); - // pio_sm_set_enabled(pioblk_rw, SM_MUX, true); - break; - default: - break; - } - } } uint8_t payload[539]; From 577d0e4c17a168eef47e4ac03a74a71650c1bab7 Mon Sep 17 00:00:00 2001 From: Oliver Schmidt Date: Sat, 28 Oct 2023 14:53:45 +0200 Subject: [PATCH 152/158] Remove esp32s3_platform_version. Now that esp32_platform_version is 6.x there's no more need for a esp32s3_platform_version. --- platformio-sample.ini | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/platformio-sample.ini b/platformio-sample.ini index c314a28d7..8566308cb 100644 --- a/platformio-sample.ini +++ b/platformio-sample.ini @@ -16,8 +16,6 @@ esp32_platform_version = 6.3.2 ; latest esp32_platform_packages = ; toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to the >=5.3.0 -esp32s3_platform_version = 6.1.0 - ; Choose SPIFFS or LITTLEFS for the filesystem used on internal flash flash_filesystem = FLASH_SPIFFS ;flash_filesystem = FLASH_LITTLEFS @@ -303,7 +301,7 @@ build_flags = -D PINMAP_ATARIV1 [env:esp32s3] -platform = espressif32@${fujinet.esp32s3_platform_version} +platform = espressif32@${fujinet.esp32_platform_version} board = fujinet-esp32s3 build_type = debug build_flags = @@ -311,7 +309,7 @@ build_flags = -D PINMAP_ESP32S3 [env:esp32s3-8mb] -platform = espressif32@${fujinet.esp32s3_platform_version} +platform = espressif32@${fujinet.esp32_platform_version} board = fujinet-esp32s3-8mb build_type = debug build_flags = From 03749d02ec1ca4e6f8dfe4f4448fc093f79fdf4c Mon Sep 17 00:00:00 2001 From: mozzwald Date: Sat, 28 Oct 2023 11:34:41 -0500 Subject: [PATCH 153/158] sio: disk: don't process cmd if device not active --- lib/device/sio/disk.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/device/sio/disk.cpp b/lib/device/sio/disk.cpp index aae331026..6dc589217 100755 --- a/lib/device/sio/disk.cpp +++ b/lib/device/sio/disk.cpp @@ -295,8 +295,7 @@ void sioDisk::sio_process(uint32_t commanddata, uint8_t checksum) if (_disk == nullptr || _disk->_disktype == MEDIATYPE_UNKNOWN) return; - if (device_active == false && - (cmdFrame.comnd != SIO_DISKCMD_STATUS && cmdFrame.comnd != SIO_DISKCMD_HSIO_INDEX)) + if (device_active == false) return; Debug_printf("disk sio_process(), baud: %d\n", SIO.getBaudrate()); From fd529b2256cfd4780969f1c33371cf36fa05dfc4 Mon Sep 17 00:00:00 2001 From: Oliver Schmidt Date: Sat, 28 Oct 2023 18:44:16 +0200 Subject: [PATCH 154/158] Remove dependency on os.h The FN code using this code presumes anyhow that 'os_malloc' is the same as 'malloc'. --- lib/base64/base64.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/base64/base64.c b/lib/base64/base64.c index d4fd218cf..3955c53c9 100644 --- a/lib/base64/base64.c +++ b/lib/base64/base64.c @@ -7,8 +7,8 @@ */ #include +#include -#include "os.h" #include "base64.h" static const char base64_table[65] = @@ -33,7 +33,7 @@ static char * base64_gen_encode(const unsigned char *src, size_t len, olen++; /* nul termination */ if (olen < len) return NULL; /* integer overflow */ - out = os_malloc(olen); + out = malloc(olen); if (out == NULL) return NULL; @@ -88,7 +88,7 @@ static unsigned char * base64_gen_decode(const char *src, size_t len, int pad = 0; size_t extra_pad; - os_memset(dtable, 0x80, 256); + memset(dtable, 0x80, 256); for (i = 0; i < sizeof(base64_table) - 1; i++) dtable[(unsigned char) table[i]] = (unsigned char) i; dtable['='] = 0; @@ -104,7 +104,7 @@ static unsigned char * base64_gen_decode(const char *src, size_t len, extra_pad = (4 - count % 4) % 4; olen = (count + extra_pad) / 4 * 3; - pos = out = os_malloc(olen); + pos = out = malloc(olen); if (out == NULL) return NULL; @@ -136,7 +136,7 @@ static unsigned char * base64_gen_decode(const char *src, size_t len, pos -= 2; else { /* Invalid padding */ - os_free(out); + free(out); return NULL; } break; From faf581cbfcc76af99feb33dbed4707c94d2ac3f3 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Thu, 2 Nov 2023 21:11:12 -0500 Subject: [PATCH 155/158] Revert "sio: disk: don't process cmd if device not active" This reverts commit 03749d02ec1ca4e6f8dfe4f4448fc093f79fdf4c. --- lib/device/sio/disk.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/device/sio/disk.cpp b/lib/device/sio/disk.cpp index 6dc589217..aae331026 100755 --- a/lib/device/sio/disk.cpp +++ b/lib/device/sio/disk.cpp @@ -295,7 +295,8 @@ void sioDisk::sio_process(uint32_t commanddata, uint8_t checksum) if (_disk == nullptr || _disk->_disktype == MEDIATYPE_UNKNOWN) return; - if (device_active == false) + if (device_active == false && + (cmdFrame.comnd != SIO_DISKCMD_STATUS && cmdFrame.comnd != SIO_DISKCMD_HSIO_INDEX)) return; Debug_printf("disk sio_process(), baud: %d\n", SIO.getBaudrate()); From 80e9e87a7f86967165d24866d97e9b69be95e542 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Fri, 3 Nov 2023 20:22:23 -0500 Subject: [PATCH 156/158] sio: disk: don't respond to status if disk not active --- lib/device/sio/disk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/sio/disk.cpp b/lib/device/sio/disk.cpp index aae331026..f4850deb5 100755 --- a/lib/device/sio/disk.cpp +++ b/lib/device/sio/disk.cpp @@ -295,8 +295,8 @@ void sioDisk::sio_process(uint32_t commanddata, uint8_t checksum) if (_disk == nullptr || _disk->_disktype == MEDIATYPE_UNKNOWN) return; - if (device_active == false && - (cmdFrame.comnd != SIO_DISKCMD_STATUS && cmdFrame.comnd != SIO_DISKCMD_HSIO_INDEX)) + if ((device_active == false && cmdFrame.device != SIO_DEVICEID_DISK) || // not active and not D1 + (device_active == false && theFuji.boot_config == false)) // not active and not config boot return; Debug_printf("disk sio_process(), baud: %d\n", SIO.getBaudrate()); From b09400171cbed979864d757939ae344a618380c2 Mon Sep 17 00:00:00 2001 From: mozzwald Date: Fri, 3 Nov 2023 20:54:49 -0500 Subject: [PATCH 157/158] autobuild: install python setuptools --- .github/workflows/autobuild.yml | 1 + .github/workflows/release.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/autobuild.yml b/.github/workflows/autobuild.yml index 10a170277..3e765d56b 100644 --- a/.github/workflows/autobuild.yml +++ b/.github/workflows/autobuild.yml @@ -43,6 +43,7 @@ jobs: - name: Install PlatformIO run: | python -m pip install --upgrade pip + pip install setuptools pip install --upgrade platformio pip install Jinja2 pip install pyyaml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9155a52cd..aa82c2b29 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,6 +41,7 @@ jobs: - name: Install PlatformIO run: | python -m pip install --upgrade pip + pip install setuptools pip install --upgrade platformio pip install Jinja2 pip install pyyaml From ec3dd7d7ea9e86b151c65564a568ef9f962e19bd Mon Sep 17 00:00:00 2001 From: Mike Wiese Date: Fri, 3 Nov 2023 23:44:49 -0700 Subject: [PATCH 158/158] apple2: Support 40 track 5.25 inch disk images - support 36 and 40 track .DO, .PO, and .DSK files - check file size is supported size - plumb MEDIATYPE_UNKNOWN errors in mount code --- lib/device/iwm/disk.cpp | 53 +++++++++++++++++--------------- lib/device/iwm/disk2.cpp | 15 +++++---- lib/device/iwm/disk2.h | 2 +- lib/media/apple/mediaTypeDO.cpp | 11 +++++++ lib/media/apple/mediaTypeDSK.cpp | 21 ++++++++++--- lib/media/apple/mediaTypeDSK.h | 3 +- lib/media/apple/mediaTypeWOZ.h | 1 - 7 files changed, 69 insertions(+), 37 deletions(-) diff --git a/lib/device/iwm/disk.cpp b/lib/device/iwm/disk.cpp index b5022ca6c..b9e818a87 100644 --- a/lib/device/iwm/disk.cpp +++ b/lib/device/iwm/disk.cpp @@ -502,8 +502,8 @@ iwmDisk::iwmDisk() mediatype_t iwmDisk::mount(FILE *f, const char *filename, uint32_t disksize, mediatype_t disk_type) { + mediatype_t mt = disk_type; uint8_t deviceSlot = data_buffer[0]; // from mount ctrl cmd - mediatype_t mt = MEDIATYPE_UNKNOWN; Debug_printf("disk MOUNT %s\n", filename); // Destroy any existing MediaType @@ -515,66 +515,71 @@ mediatype_t iwmDisk::mount(FILE *f, const char *filename, uint32_t disksize, med } // Determine MediaType based on filename extension - if (disk_type == MEDIATYPE_UNKNOWN && filename != nullptr) { - disk_type = MediaType::discover_mediatype(filename); - if (disk_type == MEDIATYPE_DSK) { - // determine DO or PO based on file contents - disk_type = MediaType::discover_dsk_mediatype(f, disksize); - } + if (mt == MEDIATYPE_UNKNOWN && filename != nullptr) { + mt = MediaType::discover_mediatype(filename); + } + + if (mt == MEDIATYPE_DSK) { + // determine DO or PO based on file contents + mt = MediaType::discover_dsk_mediatype(f, disksize); } if (deviceSlot < 4) // SP drive { - switch (disk_type) + switch (mt) { case MEDIATYPE_DO: Debug_printf("\r\nMedia Type DO"); _disk = new MediaTypeDO(); - _disk->_media_host = host; - _disk->_mediatype = disk_type; - strcpy(_disk->_disk_filename, filename); - mt = _disk->mount(f, disksize); - - device_active = true; //change status only after we are mounted break; case MEDIATYPE_PO: Debug_printf("\r\nMedia Type PO"); _disk = new MediaTypePO(); + break; + default: + Debug_printf("\r\nUnsupported Media Type for SmartPort"); + mt = MEDIATYPE_UNKNOWN; + break; + } + + if (mt != MEDIATYPE_UNKNOWN) { _disk->_media_host = host; - _disk->_mediatype = disk_type; + _disk->_mediatype = mt; strcpy(_disk->_disk_filename, filename); mt = _disk->mount(f, disksize); + } + if (mt != MEDIATYPE_UNKNOWN) { // firmware needs to believe a high score enabled disk is // not write-protected. Otherwise it will skip write process if (_disk->high_score_enabled) readonly = false; device_active = true; //change status only after we are mounted - break; - default: - Debug_printf("\r\nMedia Type UNKNOWN for SP Drive - no mount in disk.cpp"); - device_active = false; - break; } } else // DiskII drive { - switch (disk_type) + switch (mt) { case MEDIATYPE_DO: case MEDIATYPE_PO: case MEDIATYPE_WOZ: theFuji._fnDisk2s[deviceSlot - 4].init(); - theFuji._fnDisk2s[deviceSlot - 4].mount(f, disk_type); // modulo to ensure device 0 or 1 + mt = theFuji._fnDisk2s[deviceSlot - 4].mount(f, disksize, mt); break; default: - Debug_printf("\r\nMedia Type UNKNOWN for DiskII - no mount in disk.cpp"); - device_active = false; + Debug_printf("\r\nUnsupported Media Type for DiskII"); + mt = MEDIATYPE_UNKNOWN; break; } } + if (mt == MEDIATYPE_UNKNOWN) { + Debug_printf("\r\nMedia Type UNKNOWN - no mount in disk.cpp"); + device_active = false; + } + return mt; } diff --git a/lib/device/iwm/disk2.cpp b/lib/device/iwm/disk2.cpp index 5916a5632..1b23bbd9b 100644 --- a/lib/device/iwm/disk2.cpp +++ b/lib/device/iwm/disk2.cpp @@ -36,7 +36,7 @@ void iwmDisk2::init() device_active = false; } -mediatype_t iwmDisk2::mount(FILE *f, mediatype_t disk_type)//, const char *filename), uint32_t disksize, mediatype_t disk_type) +mediatype_t iwmDisk2::mount(FILE *f, uint32_t disksize, mediatype_t disk_type)//, const char *filename), uint32_t disksize, mediatype_t disk_type) { mediatype_t mt = MEDIATYPE_UNKNOWN; @@ -57,8 +57,7 @@ mediatype_t iwmDisk2::mount(FILE *f, mediatype_t disk_type)//, const char *filen Debug_printf("\nMounting Media Type WOZ"); device_active = true; _disk = new MediaTypeWOZ(); - mt = ((MediaTypeWOZ *)_disk)->mount(f); - change_track(0); // initialize spi buffer + mt = ((MediaTypeWOZ *)_disk)->mount(f, disksize); break; case MEDIATYPE_DO: case MEDIATYPE_PO: @@ -66,13 +65,17 @@ mediatype_t iwmDisk2::mount(FILE *f, mediatype_t disk_type)//, const char *filen device_active = true; _disk = new MediaTypeDSK(); _disk->_mediatype = disk_type; - mt = ((MediaTypeDSK *)_disk)->mount(f); - change_track(0); // initialize spi buffer + mt = ((MediaTypeDSK *)_disk)->mount(f, disksize); break; default: + break; + } + + if (mt == MEDIATYPE_WOZ) { + change_track(0); // initialize spi buffer + } else { Debug_printf("\nMedia Type UNKNOWN - no mount in disk2.cpp"); device_active = false; - break; } return mt; diff --git a/lib/device/iwm/disk2.h b/lib/device/iwm/disk2.h index f3007edfa..66a714a32 100644 --- a/lib/device/iwm/disk2.h +++ b/lib/device/iwm/disk2.h @@ -30,7 +30,7 @@ class iwmDisk2 : public iwmDevice public: iwmDisk2(); void init(); - mediatype_t mount(FILE *f, mediatype_t disk_type = MEDIATYPE_UNKNOWN); + mediatype_t mount(FILE *f, uint32_t disksize, mediatype_t disk_type = MEDIATYPE_UNKNOWN); void unmount(); bool write_blank(FILE *f, uint16_t sectorSize, uint16_t numSectors); int get_track_pos() { return track_pos; }; diff --git a/lib/media/apple/mediaTypeDO.cpp b/lib/media/apple/mediaTypeDO.cpp index ddfee8a57..0aa57e62c 100644 --- a/lib/media/apple/mediaTypeDO.cpp +++ b/lib/media/apple/mediaTypeDO.cpp @@ -90,6 +90,17 @@ bool MediaTypeDO::format(uint16_t *respopnsesize) mediatype_t MediaTypeDO::mount(FILE *f, uint32_t disksize) { + switch (disksize) { + case 35 * BYTES_PER_TRACK: + case 36 * BYTES_PER_TRACK: + case 40 * BYTES_PER_TRACK: + // 35, 36, and 40 tracks are supported (same as Applesauce) + break; + default: + Debug_printf("\nMediaTypeDO error: unsupported disk image size %ld", disksize); + return MEDIATYPE_UNKNOWN; + } + diskiiemulation = false; _media_fileh = f; num_blocks = disksize / BYTES_PER_BLOCK; diff --git a/lib/media/apple/mediaTypeDSK.cpp b/lib/media/apple/mediaTypeDSK.cpp index ccb40a27e..ee952406d 100644 --- a/lib/media/apple/mediaTypeDSK.cpp +++ b/lib/media/apple/mediaTypeDSK.cpp @@ -10,6 +10,7 @@ // #include // #include +#define BYTES_PER_TRACK 4096 // routines to convert DSK to WOZ stolen from DSK2WOZ by Tom Harte // https://github.com/TomHarte/dsk2woz @@ -19,11 +20,23 @@ static void serialise_track(uint8_t *dest, const uint8_t *src, uint8_t track_num mediatype_t MediaTypeDSK::mount(FILE *f, uint32_t disksize) { + switch (disksize) { + case 35 * BYTES_PER_TRACK: + case 36 * BYTES_PER_TRACK: + case 40 * BYTES_PER_TRACK: + // 35, 36, and 40 tracks are supported (same as Applesauce) + break; + default: + Debug_printf("\nMediaTypeDSK error: unsupported disk image size %ld", disksize); + return MEDIATYPE_UNKNOWN; + } + _media_fileh = f; diskiiemulation = true; + num_tracks = disksize / BYTES_PER_TRACK; // allocated SPRAM - const size_t dsk_image_size = 35 * 16 * 256; + const size_t dsk_image_size = num_tracks * BYTES_PER_TRACK; uint8_t *dsk = (uint8_t*)heap_caps_malloc(dsk_image_size, MALLOC_CAP_SPIRAM); if (fseek(f, 0, SEEK_SET) != 0) return MEDIATYPE_UNKNOWN; @@ -59,7 +72,7 @@ void MediaTypeDSK::dsk2woz_tmap() // Let's start by filling the entire TMAP with empty tracks. memset(tmap, 0xff, 160); // Then we will add in the mappings. - for(size_t c = 0; c < 35; ++c) + for(size_t c = 0; c < num_tracks; ++c) { size_t track_position = c << 2; if (c > 0) @@ -91,8 +104,8 @@ bool MediaTypeDSK::dsk2woz_tracks(uint8_t *dsk) Debug_printf("\nMediaTypeDSK is_prodos: %s", _mediatype == MEDIATYPE_PO ? "Y" : "N"); // TODO: adapt this to that - // Write out all 35 tracks. - for (size_t c = 0; c < 35; c++) + // Write out all tracks. + for (size_t c = 0; c < num_tracks; c++) { uint16_t bytes_used; uint16_t bit_count; diff --git a/lib/media/apple/mediaTypeDSK.h b/lib/media/apple/mediaTypeDSK.h index 99be02459..f2259712a 100644 --- a/lib/media/apple/mediaTypeDSK.h +++ b/lib/media/apple/mediaTypeDSK.h @@ -18,6 +18,8 @@ class MediaTypeDSK : public MediaTypeWOZ { private: + size_t num_tracks = 0; + void dsk2woz_info(); void dsk2woz_tmap(); bool dsk2woz_tracks(uint8_t *dsk); @@ -25,7 +27,6 @@ class MediaTypeDSK : public MediaTypeWOZ public: virtual mediatype_t mount(FILE *f, uint32_t disksize) override; - mediatype_t mount(FILE *f) {return mount(f, 0);}; // virtual void unmount() override; // static bool create(FILE *f, uint32_t numBlock); diff --git a/lib/media/apple/mediaTypeWOZ.h b/lib/media/apple/mediaTypeWOZ.h index 1251c836b..6e00a8920 100644 --- a/lib/media/apple/mediaTypeWOZ.h +++ b/lib/media/apple/mediaTypeWOZ.h @@ -40,7 +40,6 @@ class MediaTypeWOZ : public MediaType virtual bool format(uint16_t *respopnsesize) override { return false; }; virtual mediatype_t mount(FILE *f, uint32_t disksize) override; - mediatype_t mount(FILE *f) {return mount(f, 0);}; virtual void unmount() override; virtual bool status() override {return (_media_fileh != nullptr);}