| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- // GxEPD2_SerialFlash_Loader : Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
- //
- // Display Library based on Demo Example from Good Display: http://www.good-display.com/download_list/downloadcategoryid=34&isMode=false.html
- //
- // Author: Jean-Marc Zingg
- //
- // Version: see library.properties
- //
- // Library: https://github.com/ZinggJM/GxEPD2
- //
- // this example uses the SerialFlash library from: https://github.com/PaulStoffregen/SerialFlash
- // with a modification for use with ESP32 or the STM32 package available here: https://github.com/ZinggJM/SerialFlash
- // download it as .zip file and install with Library Mananger method "Add .ZIP Library..."
- //
- // this example can run on ESP6266 or ESP32 using WiFi connection
- // Supporting Arduino Forum Topics:
- // Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0
- // Good Display ePaper for Arduino : https://forum.arduino.cc/index.php?topic=436411.0
- #include <SerialFlash.h>
- // digital pin for flash chip CS pin:
- //const int FlashChipSelect = SS; // for standard slave select pin
- const int FlashChipSelect = 5; // use D1 on my Wemos D1 mini wired for e-papers
- //const int FlashChipSelect = 32; // on my LOLIN32 Lite breadboard
- #if defined (ESP8266)
- #include <ESP8266WiFi.h>
- #define USE_BearSSL true
- #endif
- #include <WiFiClient.h>
- #include <WiFiClientSecure.h>
- const char* ssid = "........";
- const char* password = "........";
- const int httpPort = 80;
- const int httpsPort = 443;
- const char* fp_api_github_com = "df b2 29 c6 a6 38 1a 59 9d c9 ad 92 2d 26 f5 3c 83 8f a5 87"; // as of 25.11.2020
- const char* fp_github_com = "5f 3f 7a c2 56 9f 50 a4 66 76 47 c6 a1 8c a0 07 aa ed bb 8e"; // as of 25.11.2020
- const char* fp_rawcontent = "70 94 de dd e6 c4 69 48 3a 92 70 a1 48 56 78 2d 18 64 e0 b7"; // as of 25.11.2020
- // how to find the certificate was not easy. finally I found it using Mozilla Firefox.
- // opened one of the bitmaps, e.g. https://raw.githubusercontent.com/ZinggJM/GxEPD2/master/extras/bitmaps/logo200x200.bmp
- // clicked the lock symbol, Connection secure clicked >, show connection details, clicked More Information, clicked View Certificate, clicked Download PEM (chain),
- // selected Open with Notepad. Copied the middle certificate and editted to the following format:
- // the number of characters per line is of no importance, but the 3 \n are needed
- const char* certificate_rawcontent =
- "-----BEGIN CERTIFICATE-----\n"
- "MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln"
- "aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBS"
- "b290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu"
- "YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3VyYW5jZSBTZXJ2ZXIg"
- "Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC24C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+U"
- "DlqUH1VWtMICKq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1itrSxwUfqJfJ3KSxgoQtxq2l"
- "nMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaSc"
- "us0Xsh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcftbZvySC/zA/WiaJJTL17jAgMBAAGjggFJ"
- "MIIBRTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNAYI"
- "KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDov"
- "L2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAo"
- "BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYD"
- "VR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwdaOpKj4PWUS+Na0QWnqxj"
- "9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNHE+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJ"
- "qvIni5ly/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zuxICaEnL6VpPX/78whQYwvwt/Tv9X"
- "BZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0AecPUeybQ=\n"
- "-----END CERTIFICATE-----\n";
- const char* host_rawcontent = "raw.githubusercontent.com";
- const char* path_rawcontent = "/ZinggJM/GxEPD2/master/extras/bitmaps/";
- const char* path_prenticedavid = "/prenticedavid/MCUFRIEND_kbv/master/extras/bitmaps/";
- const char* path_waveshare_c = "/waveshare/e-Paper/master/RaspberryPi_JetsonNano/c/pic/";
- const char* path_waveshare_py = "/waveshare/e-Paper/master/RaspberryPi_JetsonNano/python/pic/";
- void setup()
- {
- Serial.begin(115200);
- Serial.println();
- Serial.println("GxEPD2_SerialFlash_Loader");
- #ifdef RE_INIT_NEEDED
- WiFi.persistent(true);
- WiFi.mode(WIFI_STA); // switch off AP
- WiFi.setAutoConnect(true);
- WiFi.setAutoReconnect(true);
- WiFi.disconnect();
- #endif
- if (!WiFi.getAutoConnect() || ( WiFi.getMode() != WIFI_STA) || ((WiFi.SSID() != ssid) && String(ssid) != "........"))
- {
- Serial.println();
- Serial.print("WiFi.getAutoConnect()=");
- Serial.println(WiFi.getAutoConnect());
- Serial.print("WiFi.SSID()=");
- Serial.println(WiFi.SSID());
- WiFi.mode(WIFI_STA); // switch off AP
- Serial.print("Connecting to ");
- Serial.println(ssid);
- WiFi.begin(ssid, password);
- }
- int ConnectTimeout = 30; // 15 seconds
- while (WiFi.status() != WL_CONNECTED)
- {
- delay(500);
- Serial.print(".");
- Serial.print(WiFi.status());
- if (--ConnectTimeout <= 0)
- {
- Serial.println();
- Serial.println("WiFi connect timeout");
- return;
- }
- }
- Serial.println();
- Serial.println("WiFi connected");
- // Print the IP address
- Serial.println(WiFi.localIP());
- if (!SerialFlash.begin(FlashChipSelect))
- {
- Serial.println("Unable to access SPI Flash chip");
- return;
- }
- Serial.println("SerialFlash started");
- eraseSerialFlash();
- listFiles();
- downloadBitmaps_200x200();
- downloadBitmaps_other();
- downloadBitmaps_test();
- listFiles();
- }
- void loop()
- {
- }
- void listFiles()
- {
- Serial.println("All Files on SPI Flash chip:");
- SerialFlash.opendir();
- while (1)
- {
- char filename[64];
- uint32_t filesize;
- if (SerialFlash.readdir(filename, sizeof(filename), filesize))
- {
- Serial.print(" ");
- Serial.print(filename);
- spaces(20 - strlen(filename));
- Serial.print(" ");
- Serial.print(filesize);
- Serial.print(" bytes");
- Serial.println();
- }
- else
- {
- Serial.println("no more files...");
- break; // no more files
- }
- }
- }
- void spaces(int num)
- {
- for (int i=0; i < num; i++)
- {
- Serial.print(" ");
- }
- }
- void downloadFile_HTTPS(const char* host, const char* path, const char* filename, const char* fingerprint, const char* target, const char* certificate = certificate_rawcontent);
- void downloadBitmaps_200x200()
- {
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "logo200x200.bmp", fp_rawcontent, "logo200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "first200x200.bmp", fp_rawcontent, "first200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "second200x200.bmp", fp_rawcontent, "second200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "third200x200.bmp", fp_rawcontent, "third200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "fourth200x200.bmp", fp_rawcontent, "fourth200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "fifth200x200.bmp", fp_rawcontent, "fifth200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "sixth200x200.bmp", fp_rawcontent, "sixth200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "seventh200x200.bmp", fp_rawcontent, "seventh200x200.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "eighth200x200.bmp", fp_rawcontent, "eighth200x200.bmp");
- }
- void downloadBitmaps_other()
- {
- downloadFile_HTTP("www.squix.org", "/blog/wunderground/", "chanceflurries.bmp", "chanceflurries.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "betty_1.bmp", fp_rawcontent, "betty_1.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "betty_4.bmp", fp_rawcontent, "betty_4.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "marilyn_240x240x8.bmp", fp_rawcontent, "marilyn_240x240x8.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "miniwoof.bmp", fp_rawcontent, "miniwoof.bmp");
- //downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "test.bmp", fp_rawcontent, "test.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "tiger.bmp", fp_rawcontent, "tiger.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "tiger_178x160x4.bmp", fp_rawcontent, "tiger_178x160x4.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "tiger_240x317x4.bmp", fp_rawcontent, "tiger_240x317x4.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "tiger_320x200x24.bmp", fp_rawcontent, "tiger_320x200x24.bmp");
- //downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "tiger16T.bmp", fp_rawcontent, "tiger16T.bmp");
- downloadFile_HTTPS(host_rawcontent, path_prenticedavid, "woof.bmp", fp_rawcontent, "woof.bmp");
- }
- void downloadBitmaps_test()
- {
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "output5.bmp", fp_rawcontent, "output5.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "output6.bmp", fp_rawcontent, "output6.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "tractor_1.bmp", fp_rawcontent, "tractor_1.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "tractor_4.bmp", fp_rawcontent, "tractor_4.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "tractor_8.bmp", fp_rawcontent, "tractor_8.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "tractor_11.bmp", fp_rawcontent, "tractor_11.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "tractor_44.bmp", fp_rawcontent, "tractor_44.bmp");
- downloadFile_HTTPS(host_rawcontent, path_rawcontent, "tractor_88.bmp", fp_rawcontent, "tractor_88.bmp");
- }
- void downloadFile_HTTP(const char* host, const char* path, const char* filename, const char* target)
- {
- WiFiClient client;
- Serial.print("connecting to ");
- Serial.println(host);
- if (!client.connect(host, httpPort))
- {
- Serial.println("connection failed");
- return;
- }
- Serial.print("requesting URL: ");
- Serial.println(String("http://") + host + path + filename);
- client.print(String("GET ") + path + filename + " HTTP/1.1\r\n" +
- "Host: " + host + "\r\n" +
- "User-Agent: GxEPD2_SerialFlash_Loader\r\n" +
- "Connection: close\r\n\r\n");
- Serial.println("request sent");
- bool ok = false;
- int32_t content_length = 0;
- while (client.connected() || client.available())
- {
- String line = client.readStringUntil('\n');
- if (!ok)
- {
- ok = line.startsWith("HTTP/1.1 200 OK");
- if (ok) Serial.println(line);
- //if (!ok) Serial.println(line);
- }
- if (!ok) Serial.println(line);
- //Serial.println(line);
- if (line.startsWith("Content-Length: "))
- {
- content_length = line.substring(16, line.length()).toInt();
- Serial.print("content_length is "); Serial.println(content_length);
- }
- if (line == "\r")
- {
- Serial.println("headers received");
- break;
- }
- }
- if (!ok) return;
- uint8_t buffer[512];
- #if defined(ESP8266)
- client.peekBytes(buffer, 2);
- Serial.write(buffer[0]); Serial.write(buffer[1]); Serial.println();
- #endif
- size_t total = 0;
- //if (!SerialFlash.createErasable(target, content_length)) // would use much more space
- if (!SerialFlash.create(target, content_length))
- {
- Serial.print(target); Serial.println(" create failed");
- return;
- }
- SerialFlashFile file = SerialFlash.open(target);
- if (!file)
- {
- Serial.print(target); Serial.println(" open failed");
- return;
- }
- while (client.connected() || client.available())
- {
- size_t available = client.available();
- size_t fetch = available <= sizeof(buffer) ? available : sizeof(buffer);
- if (fetch > 0)
- {
- size_t got = client.read(buffer, fetch);
- file.write(buffer, got);
- total += got;
- }
- delay(1); // yield();
- }
- file.close();
- Serial.print("done, "); Serial.print(total); Serial.println(" bytes transferred");
- }
- void downloadFile_HTTPS(const char* host, const char* path, const char* filename, const char* fingerprint, const char* target, const char* certificate)
- {
- // Use WiFiClientSecure class to create TLS connection
- #if USE_BearSSL
- BearSSL::WiFiClientSecure client;
- #else
- WiFiClientSecure client;
- #endif
- Serial.println(); Serial.print("downloading file \""); Serial.print(filename); Serial.println("\"");
- Serial.print("connecting to "); Serial.println(host);
- #if defined (ESP8266)
- if (fingerprint) client.setFingerprint(fingerprint);
- #elif defined (ESP32)
- if (certificate) client.setCACert(certificate);
- #endif
- if (!client.connect(host, httpsPort))
- {
- Serial.println("connection failed");
- return;
- }
- Serial.print("requesting URL: ");
- Serial.println(String("https://") + host + path + filename);
- client.print(String("GET ") + path + filename + " HTTP/1.1\r\n" +
- "Host: " + host + "\r\n" +
- "User-Agent: GxEPD2_SerialFlash_Loader\r\n" +
- "Connection: close\r\n\r\n");
- Serial.println("request sent");
- bool ok = false;
- int32_t content_length = 0;
- while (client.connected() || client.available())
- {
- String line = client.readStringUntil('\n');
- if (!ok)
- {
- ok = line.startsWith("HTTP/1.1 200 OK");
- if (ok) Serial.println(line);
- //if (!ok) Serial.println(line);
- }
- if (!ok) Serial.println(line);
- //Serial.print("line: "); Serial.println(line);
- if (line.startsWith("Content-Length: "))
- {
- content_length = line.substring(16, line.length()).toInt();
- Serial.print("content_length is "); Serial.println(content_length);
- }
- if (line == "\r")
- {
- Serial.println("headers received");
- break;
- }
- }
- if (!ok) return;
- //return;
- uint8_t buffer[512];
- #if defined(ESP8266)
- client.peekBytes(buffer, 2);
- Serial.write(buffer[0]); Serial.write(buffer[1]); Serial.println();
- #endif
- size_t total = 0;
- //if (!SerialFlash.createErasable(target, content_length)) // would use much more space
- if (!SerialFlash.create(target, content_length))
- {
- Serial.print(target); Serial.println(" create failed");
- return;
- }
- SerialFlashFile file = SerialFlash.open(target);
- if (!file)
- {
- Serial.print(target); Serial.println(" open failed");
- return;
- }
- while (client.connected() || client.available())
- {
- // this doesn't work as expected, but it helps for long downloads
- int32_t start = millis();
- for (int16_t t = 0, dly = 50; t < 20; t++, dly += 50)
- {
- if (!(client.connected() || client.available())) break;
- if (client.available()) break; // read would not recover after having returned 0
- delay(dly);
- }
- if (!(client.connected() || client.available())) break;
- int32_t elapsed = millis() - start;
- if (elapsed > 250)
- {
- Serial.print("waited for available "); Serial.print(millis() - start); Serial.print(" ms @ "); Serial.println(total);
- }
- size_t available = client.available();
- if (0 == available)
- {
- Serial.print("download error: timeout on available() after "); Serial.print(total); Serial.println(" bytes");
- break; // don't hang forever
- }
- size_t fetch = available <= sizeof(buffer) ? available : sizeof(buffer);
- if (fetch > 0)
- {
- size_t got = client.read(buffer, fetch);
- file.write(buffer, got);
- total += got;
- }
- delay(1); // yield();
- if (total > 30000) delay(250); // helps for long downloads
- }
- file.close();
- Serial.print("done, "); Serial.print(total); Serial.println(" bytes transferred");
- }
- void eraseSerialFlash()
- {
- unsigned char id[5];
- SerialFlash.readID(id);
- unsigned long size = SerialFlash.capacity(id);
- unsigned long startMillis = millis();
- if (size > 0)
- {
- Serial.print("Flash Memory has ");
- Serial.print(size);
- Serial.println(" bytes.");
- Serial.println("Erasing ALL Flash Memory:");
- // Estimate the (lengthy) wait time.
- Serial.print(" estimated wait: ");
- int seconds = (float)size / eraseBytesPerSecond(id) + 0.5;
- Serial.print(seconds);
- Serial.println(" seconds.");
- Serial.println(" Yes, full chip erase is SLOW!");
- SerialFlash.eraseAll();
- unsigned long dotMillis = millis();
- unsigned char dotcount = 0;
- while (SerialFlash.ready() == false)
- {
- if (millis() - dotMillis > 1000)
- {
- dotMillis = dotMillis + 1000;
- Serial.print(".");
- dotcount = dotcount + 1;
- if (dotcount >= 60)
- {
- Serial.println();
- dotcount = 0;
- }
- }
- yield();
- }
- if (dotcount > 0) Serial.println();
- Serial.println("Erase completed");
- unsigned long elapsed = millis() - startMillis;
- Serial.print(" actual wait: ");
- Serial.print(elapsed / 1000ul);
- Serial.println(" seconds.");
- }
- }
- float eraseBytesPerSecond(const unsigned char *id)
- {
- if (id[0] == 0x20) return 152000.0; // Micron
- if (id[0] == 0x01) return 500000.0; // Spansion
- if (id[0] == 0xEF) return 419430.0; // Winbond
- if (id[0] == 0xC2) return 279620.0; // Macronix
- return 320000.0; // guess?
- }
|