diff --git a/.gitignore b/.gitignore index 259148f..8c05a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ *.exe *.out *.app + +Controller/build/*.* diff --git a/Controller/Controller.ino b/Controller/Controller.ino index f526a4a..d277bf3 100644 --- a/Controller/Controller.ino +++ b/Controller/Controller.ino @@ -13,16 +13,26 @@ #include #include #include "flashmem.h" +#include "esp_partition.h" #include #include #include + +#include +#include +#include + #include "ESPIcialWebDAV.h" +#define VERSION "VERA ESPIcial V1.0.1" #define HOSTNAME "X16WebDAV" #define AP_NAME "X16Connect" #define AP_PASSWORD "12345678" +#define UP_NAME "X16Update" +#define UP_PASSWORD "12345678" #define RESET_FILE "/RESETWIFI" +#define VERA_FILE "/VERA.BIN" #define ESP_BUILTIN_LED 2 @@ -56,6 +66,9 @@ void switchToESP(); FS& gfs = SD; //WiFiServerSecure tcp(443); // ToDo: try https WiFiServer tcp(80); + +AsyncWebServer server(8080); + ESPIcialWebDAV dav; uint32_t startTimeoutSD = 0; @@ -226,6 +239,23 @@ void setupWiFi() { Serial.println("connected...yeey :)"); } + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", VERSION); + }); + +} + +//--------------------------------------------------------------------- +// Setup OTA update +//--------------------------------------------------------------------- +void setupOTA() +{ + AsyncElegantOTA.setID(VERSION); + AsyncElegantOTA.begin(&server); // Start ElegantOTA without username/password + //AsyncElegantOTA.begin(&server, UP_NAME, UP_PASSWORD); // Start ElegantOTA with username/password + server.begin(); + Serial.println("Update server started"); } //--------------------------------------------------------------------- @@ -269,6 +299,15 @@ void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(ESP_BUILTIN_LED, OUTPUT); + // setup WiFi + setupWiFi(); + + // setup SebDAV access + setupWebDav(); + + // setup SebDAV access + setupOTA(); + // show reset is done ENABLE_FPGA_CFG(); digitalWrite(ESP_FPGA_RESET, 0); @@ -289,8 +328,8 @@ void setup() { // variables for FPGA binary transfer uint8_t header_bytes_read = 0; uint8_t magic; -uint16_t transfer_size; -uint16_t bytes_transferred = 0; +uint32_t transfer_size; +uint32_t bytes_transferred = 0; //--------------------------------------------------------------------- // switches SD card access to ESP, start timeout to switch back to FPGA @@ -319,49 +358,10 @@ void switchToX16() } //--------------------------------------------------------------------- -// main loop +// handle serial fpga upload //--------------------------------------------------------------------- -void loop() +void handleSerialUploadFPGA() { - uint8_t isX16SD = digitalRead(FPGA_SD_EN); // who is in control of the SD card? - - if (fpga_configured) - { - dav.handleClient(); - - // switch back SD card to FPGA when timeout is due - if (startTimeoutSD - && millis()-startTimeoutSD > 5000 - && !isX16SD) - switchToX16(); - } - - uint8_t cur_fpga_creset = digitalRead(FPGA_CRESET_B); - - if (cur_fpga_creset == 0 && last_fpga_creset == 1) - { - Serial.println("ENABLE_FPGA_CFG()"); - // Reset was just asserted - // Make sure that FPGA SPI bus is connected to config flash - fpga_configured = 0; - ENABLE_FPGA_CFG(); - } else if (cur_fpga_creset == 1 && fpga_configured == 0 && digitalRead(FPGA_CDONE) == 1) { - // FPGA has finished configuration, switch SD card access to SD card - fpga_configured = 1; - - // setup WiFi - setupWiFi(); - - // setup SebDAV access - setupWebDav(); - - // give sd card control to X16 - ENABLE_FPGA_SD(); - switchToX16(); - Serial.println("Init done"); - - } - // // serial management, for uploading FPGA binary // @@ -411,6 +411,141 @@ void loop() } } } +} + + +//--------------------------------------------------------------------- +// handle file based fpga upload. Checks for file "VERA.BIN" +//--------------------------------------------------------------------- +void handleFileUploadFPGA() +{ + char buffer[256]; + + // checking for a vera binary + Serial.println("Checking for VERA update..."); + switchToESP(); + + // no VERA.BIN file? then skip this + if (!gfs.exists(VERA_FILE)) + return; + + Serial.println("VERA.BIN found. Flashing to FPGA"); + + // setup flashing FPGA via SPI + digitalWrite(FPGA_CFG_EN, 0); // Disable communication between FPGA and Flash + spi_begin(); + + cfg_spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0)); + digitalWrite(cfg_spi->pinSS(), LOW); + + bytes_transferred = 0; + + // open vera binary + switchToESP(); + File f = gfs.open(VERA_FILE); + + transfer_size = f.size(); + sprintf(buffer, "Vera file size: %d Bytes", transfer_size); + Serial.println(buffer); + + // transfer file + while(bytes_transferred < transfer_size) + { + uint8_t len = f.readBytes(buffer, 64); + if (len <= 0) + { + sprintf(buffer, "flashed %d", bytes_transferred); + Serial.println(buffer); + Serial.println("EOF?"); + break; + } + + for (int n=0; ntransfer(buffer[n]); + } + digitalWrite(ESP_BUILTIN_LED, (bytes_transferred & 0x200) == 0 ? 0 : 1); + bytes_transferred += len; + + delay(10); + if (bytes_transferred % 1024 == 0) + Serial.print("."); + } + + Serial.println(""); + sprintf(buffer, "flashed %d", bytes_transferred); + Serial.println(buffer); + + // cleanup + f.close(); + gfs.remove(VERA_FILE); + + // ending spi transfer + digitalWrite(cfg_spi->pinSS(), HIGH); + cfg_spi->endTransaction(); + + // reset VERA + Serial.println("Resetting FPGA"); + digitalWrite(FPGA_CFG_EN, 1); // Enable communication between FPGA and Flash + digitalWrite(ESP_FPGA_RESET, 0); + digitalWrite(ESP_BUILTIN_LED, 1); + delay(250); + digitalWrite(ESP_BUILTIN_LED, 0); + digitalWrite(ESP_FPGA_RESET, 1); + + digitalWrite(ESP_BUILTIN_LED, 0); + // Release SPI bus + spi_end(); + +} + +//--------------------------------------------------------------------- +// main loop +//--------------------------------------------------------------------- +void loop() +{ + uint8_t isX16SD = digitalRead(FPGA_SD_EN); // who is in control of the SD card? + uint8_t cur_fpga_creset = digitalRead(FPGA_CRESET_B); + + //if (fpga_configured) + dav.handleClient(); + + // switch back SD card to FPGA when timeout is due + if (startTimeoutSD + && millis()-startTimeoutSD > 5000 + && !isX16SD) + switchToX16(); + + if (cur_fpga_creset == 0 && last_fpga_creset == 1) + { + // Reset was just asserted + // Make sure that FPGA SPI bus is connected to config flash + fpga_configured = 0; + ENABLE_FPGA_CFG(); + } else if (cur_fpga_creset == 1 && fpga_configured == 0 && digitalRead(FPGA_CDONE) == 1) { + // FPGA has finished configuration, switch SD card access to SD card + fpga_configured = 1; + + /*// setup WiFi + setupWiFi(); + + // setup SebDAV access + setupWebDav(); + + // setup SebDAV access + setupOTA(); +*/ + handleFileUploadFPGA(); + + // give sd card control to X16 + switchToX16(); + Serial.println("Init done"); + + + } + + // handle serial upload to FPGA + handleSerialUploadFPGA(); // make led blink digitalWrite(ESP_BUILTIN_LED, (millis() & 0x200) == 0 ? 0 : 1); diff --git a/README.md b/README.md index 4d8cde5..8874b71 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,10 @@ and retro enthusiasts to add to their own designs. Key features of the ESPIcial include: -* Easy update interface for both ESP32 and FPGA through USB C connector +* Easy WebDAV access to the SD card via WiFi +* OTA capability for the ESP32 firmware via WiFi +* Update via SD card for FPGA +* Backup update interface for ESP32 and FPGA through USB C connector via serial * Supports all video and audio features of the original VERA * 640x480 @60Hz Resolution * Video output @@ -58,21 +61,50 @@ Once the ESP32 board is added to Arduino, use these settings for building the fi ### Building Firmware -Press the checkmark button on the Arduino IDE to build the firmware. This may take a few -minutes to complete. +Install the following libraries: + * WiFiMulti_Generic + * WiFiManager + * MDNS_Generic + * ESPAsyncTCP + * ESPAsyncWebCerver + * AsyncElegantOTA +Press the checkmark button on the Arduino IDE to build the firmware. This may take a few minutes to complete. -### Updating the ESP32 Firmware +### Connecting the ESPIcial to your WiFi + +Make sure the X16 is powered on and USB-C on the ESPIcial is NOT connected! +If no WiFi credentials are configured the ESPIcial will create a temporary AP for 60 seconds namend "X16Connect" and provide a captive portal. There you can select your WiFi AP and enter the password. Be aware that the portal is not encrypted, but the credentials will be, once connected. + +If you want to reset credentials or connect to a different network, create a file named "RESETWIFI" in the root folder of the SD card. +At each reset the ESPIcial checks for this file and if found, deletes credentials and creates the temporary AP again for 60 seconds. + +### Using WebDAV + +Connect your webdav client to http://x16webdav. Mount share via file explorer on Windows 10+ or various options on Linux. + +This will give you direct access to the SD card via WiFi. Control of the SD card is shared with the X16. With every request via WebDAV the ESPIcial will get the SD card exclusively for at least 5 seconds. Each request within that time will extend access by 5 seconds. So 5 seconds after the last request control of the SD card is returned to the X16. + +While the ESPIcial has control over the SD card the X16 won't see the SD card and any file access will end with a "device not present" error. + +### Updating the ESP32 Firmware via OTA + +The ESP32 Firmware can be updated via WiFi by connecting to http://x16webdav:8080/update and uploading a sketch in compiled binary form. + +### Updating the FPGA Firmware via SD card + +You can place a file named VERA.BIN in the root folder of the SD card. At each reset the ESPIcial checks if this file exists and updates the FPGA. +The LED is blinking quickly during this time. + +### Updating the ESP32 Firmware via Arduino IDE The ESP32 Firmware can be updated directly from the Arduino IDE by pressing the "Upload" button. -### Updating the FPGA Firmware +### Updating the FPGA Firmware via serial -The ESP32 Firmware contains an interface that allows the FPGA bitstream to be updated over -the USB C serial interface. A Python script, `espi_update_fpga.py` is included here to facilitate -this. The script requires PySerial to communicate with the ESP32 firmware. +The ESP32 Firmware contains an interface that allows the FPGA bitstream to be updated over the USB C serial interface. A Python script, `espi_update_fpga.py` is included here to facilitate this. The script requires PySerial to communicate with the ESP32 firmware. Obtain a VERA firmware and execute the following: `python espi_update_fpga.py /dev/ttyS3 ~/vera.bin` -Replace `/dev/ttyS3` with the path to the serial port device on your computer (could be `COM3` on Windows) and replace `~/vera.bin` with the path to the VERA bitstream. +Replace `/dev/ttyS3` with the path to the serial port device on your computer (could be `COMx` on Windows) and replace `~/vera.bin` with the path to the VERA bitstream.