GxEPD2_WiFi_Native4c.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. uint8_t output_row_native4c_buffer[max_row_width / 4]; // buffer for at least one row of native color bits
  2. uint8_t color4(uint16_t red, uint16_t green, uint16_t blue)
  3. {
  4. uint8_t cv4 = 0x00;
  5. if ((red < 0x80) && (green < 0x80) && (blue < 0x80)) cv4 = 0x00; // black
  6. else if ((red >= 0x80) && (green >= 0x80) && (blue >= 0x80)) cv4 = 0x01; // white
  7. else if ((red >= 0x80) && (blue >= 0x80)) cv4 = 0x03; // red, blue > red
  8. else if ((green >= 0x80) && (blue >= 0x80)) cv4 = 0x01; // green, blue > white
  9. else if ((red >= 0x80) && (green >= 0xC0)) cv4 = 0x02; // yellow
  10. else if ((red >= 0x80) && (green >= 0x40)) cv4 = 0x03; // orange > red
  11. else if (red >= 0x80) cv4 = 0x03; // red
  12. else if (green >= 0x80) cv4 = 0x00; // green > black
  13. else cv4 = 0x03; // blue
  14. return cv4;
  15. }
  16. void showNative4cFrom_HTTP(const char* host, const char* path, const char* filename, int16_t x, int16_t y)
  17. {
  18. WiFiClient client;
  19. bool connection_ok = false;
  20. bool valid = false; // valid format to be handled
  21. bool flip = true; // bitmap is stored bottom-to-top
  22. uint32_t startTime = millis();
  23. if ((x >= display.epd2.WIDTH) || (y >= display.epd2.HEIGHT)) return;
  24. Serial.println(); Serial.print("downloading file \""); Serial.print(filename); Serial.println("\"");
  25. Serial.print("connecting to "); Serial.println(host);
  26. if (!client.connect(host, httpPort))
  27. {
  28. Serial.println("connection failed");
  29. return;
  30. }
  31. Serial.print("requesting URL: ");
  32. Serial.println(String("http://") + host + path + filename);
  33. client.print(String("GET ") + path + filename + " HTTP/1.1\r\n" +
  34. "Host: " + host + "\r\n" +
  35. "User-Agent: GxEPD2_WiFi_Example\r\n" +
  36. "Connection: close\r\n\r\n");
  37. Serial.println("request sent");
  38. while (client.connected())
  39. {
  40. String line = client.readStringUntil('\n');
  41. if (!connection_ok)
  42. {
  43. connection_ok = line.startsWith("HTTP/1.1 200 OK");
  44. if (connection_ok) Serial.println(line);
  45. }
  46. if (!connection_ok) Serial.println(line);
  47. if (line == "\r")
  48. {
  49. Serial.println("headers received");
  50. break;
  51. }
  52. }
  53. if (!connection_ok) return;
  54. // Parse BMP header
  55. if (read16(client) == 0x4D42) // BMP signature
  56. {
  57. uint32_t fileSize = read32(client);
  58. uint32_t creatorBytes = read32(client); (void)creatorBytes; //unused
  59. uint32_t imageOffset = read32(client); // Start of image data
  60. uint32_t headerSize = read32(client);
  61. uint32_t width = read32(client);
  62. int32_t height = (int32_t) read32(client);
  63. uint16_t planes = read16(client);
  64. uint16_t depth = read16(client); // bits per pixel
  65. uint32_t format = read32(client);
  66. uint32_t bytes_read = 7 * 4 + 3 * 2; // read so far
  67. if ((planes == 1) && ((format == 0) || (format == 3))) // uncompressed is handled, 565 also
  68. {
  69. Serial.print("File size: "); Serial.println(fileSize);
  70. Serial.print("Image Offset: "); Serial.println(imageOffset);
  71. Serial.print("Header size: "); Serial.println(headerSize);
  72. Serial.print("Bit Depth: "); Serial.println(depth);
  73. Serial.print("Image size: ");
  74. Serial.print(width);
  75. Serial.print('x');
  76. Serial.println(abs(height));
  77. // BMP rows are padded (if needed) to 4-byte boundary
  78. uint32_t rowSize = (width * depth / 8 + 3) & ~3;
  79. if (depth < 8) rowSize = ((width * depth + 8 - depth) / 8 + 3) & ~3;
  80. if (height < 0)
  81. {
  82. height = -height;
  83. flip = false;
  84. }
  85. uint16_t w = width;
  86. uint16_t h = height;
  87. if ((x + w - 1) >= display.epd2.WIDTH) w = display.epd2.WIDTH - x;
  88. if ((y + h - 1) >= display.epd2.HEIGHT) h = display.epd2.HEIGHT - y;
  89. if (w <= max_row_width) // handle with direct drawing
  90. {
  91. valid = true;
  92. uint8_t bitmask = 0xFF;
  93. uint8_t bitshift = 8 - depth;
  94. uint16_t red, green, blue;
  95. uint8_t cv4 = 0x00;
  96. if (depth <= 8)
  97. {
  98. if (depth < 8) bitmask >>= depth;
  99. bytes_read += skip(client, imageOffset - (4 << depth) - bytes_read); // 54 for regular, diff for colorsimportant
  100. for (uint16_t pn = 0; pn < (1 << depth); pn++)
  101. {
  102. blue = client.read();
  103. green = client.read();
  104. red = client.read();
  105. client.read();
  106. bytes_read += 4;
  107. rgb_palette_buffer[pn] = color4(red, green, blue);
  108. }
  109. }
  110. display.clearScreen();
  111. uint32_t rowPosition = flip ? imageOffset + (height - h) * rowSize : imageOffset;
  112. bytes_read += skip(client, rowPosition - bytes_read);
  113. for (uint16_t row = 0; row < h; row++, rowPosition += rowSize) // for each line
  114. {
  115. if (!connection_ok || !(client.connected() || client.available())) break;
  116. delay(1); // yield() to avoid WDT
  117. uint32_t in_remain = rowSize;
  118. uint32_t in_idx = 0;
  119. uint32_t in_bytes = 0;
  120. uint8_t in_byte = 0; // for depth <= 8
  121. uint8_t in_bits = 0; // for depth <= 8
  122. uint8_t out_cv4_byte = 0x00;
  123. uint32_t out_idx = 0;
  124. for (uint16_t col = 0; col < w; col++) // for each pixel
  125. {
  126. yield();
  127. if (!connection_ok || !(client.connected() || client.available())) break;
  128. // Time to read more pixel data?
  129. if (in_idx >= in_bytes) // ok, exact match for 24bit also (size IS multiple of 3)
  130. {
  131. uint32_t get = in_remain > sizeof(input_buffer) ? sizeof(input_buffer) : in_remain;
  132. uint32_t got = read8n(client, input_buffer, get);
  133. while ((got < get) && connection_ok)
  134. {
  135. //Serial.print("got "); Serial.print(got); Serial.print(" < "); Serial.print(get); Serial.print(" @ "); Serial.println(bytes_read);
  136. uint32_t gotmore = read8n(client, input_buffer + got, get - got);
  137. got += gotmore;
  138. connection_ok = gotmore > 0;
  139. }
  140. in_bytes = got;
  141. in_remain -= got;
  142. bytes_read += got;
  143. in_idx = 0;
  144. }
  145. if (!connection_ok)
  146. {
  147. Serial.print("Error: got no more after "); Serial.print(bytes_read); Serial.println(" bytes read!");
  148. break;
  149. }
  150. switch (depth)
  151. {
  152. case 32:
  153. blue = input_buffer[in_idx++];
  154. green = input_buffer[in_idx++];
  155. red = input_buffer[in_idx++];
  156. in_idx++; // skip alpha
  157. cv4 = color4(red, green, blue);
  158. break;
  159. case 24:
  160. blue = input_buffer[in_idx++];
  161. green = input_buffer[in_idx++];
  162. red = input_buffer[in_idx++];
  163. cv4 = color4(red, green, blue);
  164. break;
  165. case 16:
  166. {
  167. uint8_t lsb = input_buffer[in_idx++];
  168. uint8_t msb = input_buffer[in_idx++];
  169. if (format == 0) // 555
  170. {
  171. blue = (lsb & 0x1F) << 3;
  172. green = ((msb & 0x03) << 6) | ((lsb & 0xE0) >> 2);
  173. red = (msb & 0x7C) << 1;
  174. }
  175. else // 565
  176. {
  177. blue = (lsb & 0x1F) << 3;
  178. green = ((msb & 0x07) << 5) | ((lsb & 0xE0) >> 3);
  179. red = (msb & 0xF8);
  180. }
  181. }
  182. cv4 = color4(red, green, blue);
  183. break;
  184. case 1:
  185. case 2:
  186. case 4:
  187. case 8:
  188. {
  189. if (0 == in_bits)
  190. {
  191. in_byte = input_buffer[in_idx++];
  192. in_bits = 8;
  193. }
  194. uint16_t pn = (in_byte >> bitshift) & bitmask;
  195. cv4 = rgb_palette_buffer[pn];
  196. in_byte <<= depth;
  197. in_bits -= depth;
  198. }
  199. break;
  200. }
  201. out_cv4_byte |= cv4 << (2 * (3 - col % 4));
  202. if ((3 == col % 4) || (col == w - 1)) // write that last byte! (for w%4!=0 border)
  203. {
  204. output_row_native4c_buffer[out_idx++] = out_cv4_byte;
  205. out_cv4_byte = 0x00;
  206. }
  207. } // end pixel
  208. int16_t yrow = y + (flip ? h - row - 1 : row);
  209. display.writeNative(output_row_native4c_buffer, 0, x, yrow, w, 1, false, false, false);
  210. } // end line
  211. Serial.print("downloaded in ");
  212. Serial.print(millis() - startTime);
  213. Serial.println(" ms");
  214. display.refresh();
  215. }
  216. Serial.print("bytes read "); Serial.println(bytes_read);
  217. }
  218. }
  219. client.stop();
  220. if (!valid)
  221. {
  222. Serial.println("bitmap format not handled.");
  223. }
  224. }
  225. void showNative4cFrom_HTTPS(const char* host, const char* path, const char* filename, const char* fingerprint, int16_t x, int16_t y, bool with_color, const char* certificate)
  226. {
  227. // Use WiFiClientSecure class to create TLS connection
  228. #if defined (ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
  229. BearSSL::WiFiClientSecure client;
  230. BearSSL::X509List cert(certificate ? certificate : certificate_rawcontent);
  231. #else
  232. WiFiClientSecure client;
  233. #endif
  234. bool connection_ok = false;
  235. bool valid = false; // valid format to be handled
  236. bool flip = true; // bitmap is stored bottom-to-top
  237. uint32_t startTime = millis();
  238. if ((x >= display.epd2.WIDTH) || (y >= display.epd2.HEIGHT)) return;
  239. Serial.println(); Serial.print("downloading file \""); Serial.print(filename); Serial.println("\"");
  240. Serial.print("connecting to "); Serial.println(host);
  241. #if defined (ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
  242. if (certificate) client.setTrustAnchors(&cert);
  243. else if (fingerprint) client.setFingerprint(fingerprint);
  244. else client.setInsecure();
  245. #elif defined (ESP32)
  246. if (certificate) client.setCACert(certificate);
  247. #endif
  248. if (!client.connect(host, httpsPort))
  249. {
  250. Serial.println("connection failed");
  251. return;
  252. }
  253. Serial.print("requesting URL: ");
  254. Serial.println(String("https://") + host + path + filename);
  255. client.print(String("GET ") + path + filename + " HTTP/1.1\r\n" +
  256. "Host: " + host + "\r\n" +
  257. "User-Agent: GxEPD2_WiFi_Example\r\n" +
  258. "Connection: close\r\n\r\n");
  259. Serial.println("request sent");
  260. while (client.connected())
  261. {
  262. String line = client.readStringUntil('\n');
  263. if (!connection_ok)
  264. {
  265. connection_ok = line.startsWith("HTTP/1.1 200 OK");
  266. if (connection_ok) Serial.println(line);
  267. }
  268. if (!connection_ok) Serial.println(line);
  269. if (line == "\r")
  270. {
  271. Serial.println("headers received");
  272. break;
  273. }
  274. }
  275. if (!connection_ok) return;
  276. // Parse BMP header
  277. uint16_t signature = 0;
  278. for (int16_t i = 0; i < 50; i++)
  279. {
  280. if (!client.available()) delay(100);
  281. else signature = read16(client);
  282. if (signature == 0x4D42) break;
  283. }
  284. if (signature == 0x4D42) // BMP signature
  285. {
  286. uint32_t fileSize = read32(client);
  287. uint32_t creatorBytes = read32(client); (void)creatorBytes; //unused
  288. uint32_t imageOffset = read32(client); // Start of image data
  289. uint32_t headerSize = read32(client);
  290. uint32_t width = read32(client);
  291. int32_t height = (int32_t) read32(client);
  292. uint16_t planes = read16(client);
  293. uint16_t depth = read16(client); // bits per pixel
  294. uint32_t format = read32(client);
  295. uint32_t bytes_read = 7 * 4 + 3 * 2; // read so far
  296. if ((planes == 1) && ((format == 0) || (format == 3))) // uncompressed is handled, 565 also
  297. {
  298. Serial.print("File size: "); Serial.println(fileSize);
  299. Serial.print("Image Offset: "); Serial.println(imageOffset);
  300. Serial.print("Header size: "); Serial.println(headerSize);
  301. Serial.print("Bit Depth: "); Serial.println(depth);
  302. Serial.print("Image size: ");
  303. Serial.print(width);
  304. Serial.print('x');
  305. Serial.println(abs(height));
  306. // BMP rows are padded (if needed) to 4-byte boundary
  307. uint32_t rowSize = (width * depth / 8 + 3) & ~3;
  308. if (depth < 8) rowSize = ((width * depth + 8 - depth) / 8 + 3) & ~3;
  309. if (height < 0)
  310. {
  311. height = -height;
  312. flip = false;
  313. }
  314. uint16_t w = width;
  315. uint16_t h = height;
  316. if ((x + w - 1) >= display.epd2.WIDTH) w = display.epd2.WIDTH - x;
  317. if ((y + h - 1) >= display.epd2.HEIGHT) h = display.epd2.HEIGHT - y;
  318. if (w <= max_row_width) // handle with direct drawing
  319. {
  320. valid = true;
  321. uint8_t bitmask = 0xFF;
  322. uint8_t bitshift = 8 - depth;
  323. uint16_t red, green, blue;
  324. uint8_t cv4 = 0x00;
  325. if (depth <= 8)
  326. {
  327. if (depth < 8) bitmask >>= depth;
  328. bytes_read += skip(client, imageOffset - (4 << depth) - bytes_read); // 54 for regular, diff for colorsimportant
  329. for (uint16_t pn = 0; pn < (1 << depth); pn++)
  330. {
  331. blue = client.read();
  332. green = client.read();
  333. red = client.read();
  334. client.read();
  335. bytes_read += 4;
  336. rgb_palette_buffer[pn] = color4(red, green, blue);
  337. }
  338. }
  339. display.clearScreen();
  340. uint32_t rowPosition = flip ? imageOffset + (height - h) * rowSize : imageOffset;
  341. bytes_read += skip(client, rowPosition - bytes_read);
  342. for (uint16_t row = 0; row < h; row++, rowPosition += rowSize) // for each line
  343. {
  344. if (!connection_ok || !(client.connected() || client.available())) break;
  345. delay(1); // yield() to avoid WDT
  346. uint32_t in_remain = rowSize;
  347. uint32_t in_idx = 0;
  348. uint32_t in_bytes = 0;
  349. uint8_t in_byte = 0; // for depth <= 8
  350. uint8_t in_bits = 0; // for depth <= 8
  351. uint8_t out_cv4_byte = 0x00;
  352. uint32_t out_idx = 0;
  353. for (uint16_t col = 0; col < w; col++) // for each pixel
  354. {
  355. yield();
  356. if (!connection_ok || !(client.connected() || client.available())) break;
  357. // Time to read more pixel data?
  358. if (in_idx >= in_bytes) // ok, exact match for 24bit also (size IS multiple of 3)
  359. {
  360. uint32_t get = in_remain > sizeof(input_buffer) ? sizeof(input_buffer) : in_remain;
  361. uint32_t got = read8n(client, input_buffer, get);
  362. while ((got < get) && connection_ok)
  363. {
  364. //Serial.print("got "); Serial.print(got); Serial.print(" < "); Serial.print(get); Serial.print(" @ "); Serial.println(bytes_read);
  365. uint32_t gotmore = read8n(client, input_buffer + got, get - got);
  366. got += gotmore;
  367. connection_ok = gotmore > 0;
  368. }
  369. in_bytes = got;
  370. in_remain -= got;
  371. bytes_read += got;
  372. in_idx = 0;
  373. }
  374. if (!connection_ok)
  375. {
  376. Serial.print("Error: got no more after "); Serial.print(bytes_read); Serial.println(" bytes read!");
  377. break;
  378. }
  379. switch (depth)
  380. {
  381. case 32:
  382. blue = input_buffer[in_idx++];
  383. green = input_buffer[in_idx++];
  384. red = input_buffer[in_idx++];
  385. in_idx++; // skip alpha
  386. cv4 = color4(red, green, blue);
  387. break;
  388. case 24:
  389. blue = input_buffer[in_idx++];
  390. green = input_buffer[in_idx++];
  391. red = input_buffer[in_idx++];
  392. cv4 = color4(red, green, blue);
  393. break;
  394. case 16:
  395. {
  396. uint8_t lsb = input_buffer[in_idx++];
  397. uint8_t msb = input_buffer[in_idx++];
  398. if (format == 0) // 555
  399. {
  400. blue = (lsb & 0x1F) << 3;
  401. green = ((msb & 0x03) << 6) | ((lsb & 0xE0) >> 2);
  402. red = (msb & 0x7C) << 1;
  403. }
  404. else // 565
  405. {
  406. blue = (lsb & 0x1F) << 3;
  407. green = ((msb & 0x07) << 5) | ((lsb & 0xE0) >> 3);
  408. red = (msb & 0xF8);
  409. }
  410. }
  411. cv4 = color4(red, green, blue);
  412. break;
  413. case 1:
  414. case 2:
  415. case 4:
  416. case 8:
  417. {
  418. if (0 == in_bits)
  419. {
  420. in_byte = input_buffer[in_idx++];
  421. in_bits = 8;
  422. }
  423. uint16_t pn = (in_byte >> bitshift) & bitmask;
  424. cv4 = rgb_palette_buffer[pn];
  425. in_byte <<= depth;
  426. in_bits -= depth;
  427. }
  428. break;
  429. }
  430. out_cv4_byte |= cv4 << (2 * (3 - col % 4));
  431. if ((3 == col % 4) || (col == w - 1)) // write that last byte! (for w%4!=0 border)
  432. {
  433. output_row_native4c_buffer[out_idx++] = out_cv4_byte;
  434. out_cv4_byte = 0x00;
  435. }
  436. } // end pixel
  437. int16_t yrow = y + (flip ? h - row - 1 : row);
  438. // void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
  439. display.writeNative(output_row_native4c_buffer, 0, x, yrow, w, 1, false, false, false);
  440. } // end line
  441. Serial.print("downloaded in ");
  442. Serial.print(millis() - startTime);
  443. Serial.println(" ms");
  444. display.refresh();
  445. }
  446. Serial.print("bytes read "); Serial.println(bytes_read);
  447. }
  448. }
  449. client.stop();
  450. if (!valid)
  451. {
  452. Serial.println("bitmap format not handled.");
  453. }
  454. }