firmware.ino 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include "FS.h"
  2. #include "esp_camera.h"
  3. #include "SD_MMC.h"
  4. // Define Pin numbers used by the camera.
  5. #define FLASH_GPIO_NUM 4
  6. #define HREF_GPIO_NUM 23
  7. #define PCLK_GPIO_NUM 22
  8. #define PWDN_GPIO_NUM 32
  9. #define RESET_GPIO_NUM -1
  10. #define SIOC_GPIO_NUM 27
  11. #define SIOD_GPIO_NUM 26
  12. #define XCLK_GPIO_NUM 0
  13. #define VSYNC_GPIO_NUM 25
  14. #define Y2_GPIO_NUM 5
  15. #define Y3_GPIO_NUM 18
  16. #define Y4_GPIO_NUM 19
  17. #define Y5_GPIO_NUM 21
  18. #define Y6_GPIO_NUM 36
  19. #define Y7_GPIO_NUM 39
  20. #define Y8_GPIO_NUM 34
  21. #define Y9_GPIO_NUM 35
  22. // Structure to hold the camera configuration parameters.
  23. camera_config_t config;
  24. // Function prototypes.
  25. void handleSerialInput();
  26. void initializeCamera();
  27. void processImage(camera_fb_t *frame_buffer);
  28. void ditherImage(camera_fb_t *frame_buffer);
  29. void saveJpegPictureToSDCard();
  30. // Enumeration to represent the available dithering algorithms.
  31. enum DitheringAlgorithm : uint8_t
  32. {
  33. FLOYD_STEINBERG,
  34. JARVIS_JUDICE_NINKE,
  35. STUCKI
  36. };
  37. // Holds the currently selected dithering algorithm.
  38. DitheringAlgorithm ditherAlgorithm = FLOYD_STEINBERG;
  39. // Flag to enable or disable dithering.
  40. bool disableDithering = false;
  41. // Flag to invert pixel colors.
  42. bool invert = false;
  43. // Flag to represent the flash state when saving pictures to the Flipper.
  44. bool isFlashEnabled = false;
  45. // Flag to represent whether the image is rotated.
  46. bool rotated = false;
  47. // Flag to stop or start the stream.
  48. bool stopStream = false;
  49. // Flag to store jpeg images to sd card.
  50. bool storeJpeg = false;
  51. void setup()
  52. {
  53. Serial.begin(230400); // 115200
  54. initializeCamera();
  55. }
  56. void loop()
  57. {
  58. if (!stopStream)
  59. {
  60. camera_fb_t *frame_buffer = esp_camera_fb_get();
  61. if (frame_buffer)
  62. {
  63. // Process and Send Grayscale image.
  64. processImage(frame_buffer);
  65. // Return the frame buffer back to the camera driver.
  66. esp_camera_fb_return(frame_buffer);
  67. }
  68. delay(25);
  69. }
  70. // Handle any available serial input commands.
  71. handleSerialInput();
  72. }
  73. void handleSerialInput()
  74. {
  75. if (Serial.available() > 0)
  76. {
  77. char input = Serial.read();
  78. sensor_t *cameraSensor = esp_camera_sensor_get();
  79. switch (input)
  80. {
  81. case '>': // Toggle dithering.
  82. disableDithering = !disableDithering;
  83. break;
  84. case '<': // Toggle invert.
  85. invert = !invert;
  86. break;
  87. case 'b': // Remove brightness.
  88. cameraSensor->set_contrast(
  89. cameraSensor,
  90. cameraSensor->status.brightness - 1);
  91. break;
  92. case 'B': // Add brightness.
  93. cameraSensor->set_contrast(
  94. cameraSensor,
  95. cameraSensor->status.brightness + 1);
  96. break;
  97. case 'c': // Remove contrast.
  98. cameraSensor->set_contrast(
  99. cameraSensor,
  100. cameraSensor->status.contrast - 1);
  101. break;
  102. case 'C': // Add contrast.
  103. cameraSensor->set_contrast(
  104. cameraSensor,
  105. cameraSensor->status.contrast + 1);
  106. break;
  107. case 'f': // Toggle flash off.
  108. isFlashEnabled = false;
  109. break;
  110. case 'F': // Toggle flash on.
  111. isFlashEnabled = true;
  112. break;
  113. case 'j': // Toggle store jpeg to sd card off.
  114. storeJpeg = false;
  115. break;
  116. case 'J': // Toggle store jpeg to sd card on.
  117. storeJpeg = true;
  118. break;
  119. case 'P': // Picture sequence.
  120. if (isFlashEnabled)
  121. {
  122. // Turn on torch.
  123. pinMode(FLASH_GPIO_NUM, OUTPUT);
  124. digitalWrite(FLASH_GPIO_NUM, HIGH);
  125. // Give some time (500ms) for Flipper to save locally with flash on.
  126. delay(500);
  127. // Turn off torch.
  128. digitalWrite(FLASH_GPIO_NUM, LOW);
  129. }
  130. // @todo - Future feature.
  131. // if (storeJpeg) { saveJpegPictureToSDCard(); }
  132. break;
  133. case 'M': // Toggle Mirror.
  134. cameraSensor->set_hmirror(cameraSensor, !cameraSensor->status.hmirror);
  135. break;
  136. case 's': // Stop stream.
  137. stopStream = true;
  138. break;
  139. case 'S': // Start stream.
  140. stopStream = false;
  141. break;
  142. case '0': // Use Floyd Steinberg dithering.
  143. ditherAlgorithm = FLOYD_STEINBERG;
  144. break;
  145. case '1': // Use Jarvis Judice dithering.
  146. ditherAlgorithm = JARVIS_JUDICE_NINKE;
  147. break;
  148. case '2': // Use Stucki dithering.
  149. ditherAlgorithm = STUCKI;
  150. break;
  151. default:
  152. // Do nothing.
  153. break;
  154. }
  155. }
  156. }
  157. void initializeCamera()
  158. {
  159. // Set initial camera configurations for grayscale.
  160. config.ledc_channel = LEDC_CHANNEL_0;
  161. config.ledc_timer = LEDC_TIMER_0;
  162. config.pin_d0 = Y2_GPIO_NUM;
  163. config.pin_d1 = Y3_GPIO_NUM;
  164. config.pin_d2 = Y4_GPIO_NUM;
  165. config.pin_d3 = Y5_GPIO_NUM;
  166. config.pin_d4 = Y6_GPIO_NUM;
  167. config.pin_d5 = Y7_GPIO_NUM;
  168. config.pin_d6 = Y8_GPIO_NUM;
  169. config.pin_d7 = Y9_GPIO_NUM;
  170. config.pin_xclk = XCLK_GPIO_NUM;
  171. config.pin_pclk = PCLK_GPIO_NUM;
  172. config.pin_vsync = VSYNC_GPIO_NUM;
  173. config.pin_href = HREF_GPIO_NUM;
  174. config.pin_sscb_sda = SIOD_GPIO_NUM;
  175. config.pin_sscb_scl = SIOC_GPIO_NUM;
  176. config.pin_pwdn = PWDN_GPIO_NUM;
  177. config.pin_reset = RESET_GPIO_NUM;
  178. config.xclk_freq_hz = 20000000;
  179. config.pixel_format = PIXFORMAT_GRAYSCALE;
  180. config.frame_size = FRAMESIZE_QQVGA;
  181. config.fb_count = 1;
  182. // Initialize camera.
  183. esp_err_t err = esp_camera_init(&config);
  184. if (err != ESP_OK)
  185. {
  186. return;
  187. }
  188. // Make sure torch starts as off.
  189. pinMode(FLASH_GPIO_NUM, OUTPUT);
  190. digitalWrite(FLASH_GPIO_NUM, LOW);
  191. // Set initial contrast.
  192. sensor_t *s = esp_camera_sensor_get();
  193. s->set_contrast(s, 0);
  194. // Set rotation.
  195. s->set_vflip(s, true); // Vertical flip.
  196. s->set_hmirror(s, true); // Horizontal mirror.
  197. }
  198. void processImage(camera_fb_t *frame_buffer)
  199. {
  200. // If dithering is not disabled, perform dithering on the image. Dithering is the
  201. // process of approximating the look of a high-resolution grayscale image in a
  202. // lower resolution by binary values (black & white), thereby representing
  203. // different shades of gray.
  204. if (!disableDithering)
  205. {
  206. ditherImage(frame_buffer); // Invokes the dithering process on the frame buffer.
  207. }
  208. uint8_t flipper_y = 0;
  209. // Iterating over specific rows of the frame buffer.
  210. for (uint8_t y = 28; y < 92; ++y)
  211. {
  212. Serial.print("Y:"); // Print "Y:" for every new row.
  213. Serial.write(flipper_y); // Send the row identifier as a byte.
  214. // Calculate the actual y index in the frame buffer 1D array by multiplying the
  215. // y value with the width of the frame buffer. This gives the starting index of
  216. // the row in the 1D array.
  217. size_t true_y = y * frame_buffer->width;
  218. // Iterating over specific columns of each row in the frame buffer.
  219. for (uint8_t x = 16; x < 144; x += 8)
  220. { // step by 8 as we're packing 8 pixels per byte.
  221. uint8_t packed_pixels = 0;
  222. // Packing 8 pixel values into one byte.
  223. for (uint8_t bit = 0; bit < 8; ++bit)
  224. {
  225. // Check the invert flag and pack the pixels accordingly.
  226. if (invert)
  227. {
  228. // If invert is true, consider pixel as 1 if it's more than 127.
  229. if (frame_buffer->buf[true_y + x + bit] > 127)
  230. {
  231. packed_pixels |= (1 << (7 - bit));
  232. }
  233. }
  234. else
  235. {
  236. // If invert is false, consider pixel as 1 if it's less than 127.
  237. if (frame_buffer->buf[true_y + x + bit] < 127)
  238. {
  239. packed_pixels |= (1 << (7 - bit));
  240. }
  241. }
  242. }
  243. Serial.write(packed_pixels); // Sending packed pixel byte.
  244. }
  245. ++flipper_y; // Move to the next row.
  246. Serial.flush(); // Ensure all data in the Serial buffer is sent before moving to the next iteration.
  247. }
  248. }
  249. void ditherImage(camera_fb_t *frame_buffer)
  250. {
  251. for (uint8_t y = 0; y < frame_buffer->height; ++y)
  252. {
  253. for (uint8_t x = 0; x < frame_buffer->width; ++x)
  254. {
  255. size_t current = (y * frame_buffer->width) + x;
  256. uint8_t oldpixel = frame_buffer->buf[current];
  257. uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
  258. frame_buffer->buf[current] = newpixel;
  259. int8_t quant_error = oldpixel - newpixel;
  260. // Apply error diffusion based on the selected algorithm
  261. switch (ditherAlgorithm)
  262. {
  263. case JARVIS_JUDICE_NINKE:
  264. frame_buffer->buf[(y * frame_buffer->width) + x + 1] += quant_error * 7 / 48;
  265. frame_buffer->buf[(y * frame_buffer->width) + x + 2] += quant_error * 5 / 48;
  266. frame_buffer->buf[(y + 1) * frame_buffer->width + x - 2] += quant_error * 3 / 48;
  267. frame_buffer->buf[(y + 1) * frame_buffer->width + x - 1] += quant_error * 5 / 48;
  268. frame_buffer->buf[(y + 1) * frame_buffer->width + x] += quant_error * 7 / 48;
  269. frame_buffer->buf[(y + 1) * frame_buffer->width + x + 1] += quant_error * 5 / 48;
  270. frame_buffer->buf[(y + 1) * frame_buffer->width + x + 2] += quant_error * 3 / 48;
  271. frame_buffer->buf[(y + 2) * frame_buffer->width + x - 2] += quant_error * 1 / 48;
  272. frame_buffer->buf[(y + 2) * frame_buffer->width + x - 1] += quant_error * 3 / 48;
  273. frame_buffer->buf[(y + 2) * frame_buffer->width + x] += quant_error * 5 / 48;
  274. frame_buffer->buf[(y + 2) * frame_buffer->width + x + 1] += quant_error * 3 / 48;
  275. frame_buffer->buf[(y + 2) * frame_buffer->width + x + 2] += quant_error * 1 / 48;
  276. break;
  277. case STUCKI:
  278. frame_buffer->buf[(y * frame_buffer->width) + x + 1] += quant_error * 8 / 42;
  279. frame_buffer->buf[(y * frame_buffer->width) + x + 2] += quant_error * 4 / 42;
  280. frame_buffer->buf[(y + 1) * frame_buffer->width + x - 2] += quant_error * 2 / 42;
  281. frame_buffer->buf[(y + 1) * frame_buffer->width + x - 1] += quant_error * 4 / 42;
  282. frame_buffer->buf[(y + 1) * frame_buffer->width + x] += quant_error * 8 / 42;
  283. frame_buffer->buf[(y + 1) * frame_buffer->width + x + 1] += quant_error * 4 / 42;
  284. frame_buffer->buf[(y + 1) * frame_buffer->width + x + 2] += quant_error * 2 / 42;
  285. frame_buffer->buf[(y + 2) * frame_buffer->width + x - 2] += quant_error * 1 / 42;
  286. frame_buffer->buf[(y + 2) * frame_buffer->width + x - 1] += quant_error * 2 / 42;
  287. frame_buffer->buf[(y + 2) * frame_buffer->width + x] += quant_error * 4 / 42;
  288. frame_buffer->buf[(y + 2) * frame_buffer->width + x + 1] += quant_error * 2 / 42;
  289. frame_buffer->buf[(y + 2) * frame_buffer->width + x + 2] += quant_error * 1 / 42;
  290. break;
  291. case FLOYD_STEINBERG:
  292. default:
  293. // Default to Floyd-Steinberg dithering if an invalid algorithm is selected
  294. frame_buffer->buf[(y * frame_buffer->width) + x + 1] += quant_error * 7 / 16;
  295. frame_buffer->buf[(y + 1) * frame_buffer->width + x - 1] += quant_error * 3 / 16;
  296. frame_buffer->buf[(y + 1) * frame_buffer->width + x] += quant_error * 5 / 16;
  297. frame_buffer->buf[(y + 1) * frame_buffer->width + x + 1] += quant_error * 1 / 16;
  298. break;
  299. }
  300. }
  301. }
  302. }
  303. // @todo - Future feature.
  304. void saveJpegPictureToSDCard()
  305. {
  306. // Get camera sensor.
  307. sensor_t *s = esp_camera_sensor_get();
  308. // Check if the sensor is valid.
  309. if (!s)
  310. {
  311. Serial.println("Failed to acquire camera sensor");
  312. return;
  313. }
  314. // Set pixel format to JPEG for saving picture.
  315. s->set_pixformat(s, PIXFORMAT_JPEG);
  316. // Set frame size based on available PSRAM.
  317. if (psramFound())
  318. {
  319. s->set_framesize(s, FRAMESIZE_UXGA);
  320. }
  321. else
  322. {
  323. s->set_framesize(s, FRAMESIZE_SVGA);
  324. }
  325. // Get a frame buffer from camera.
  326. camera_fb_t *frame_buffer = esp_camera_fb_get();
  327. if (!frame_buffer)
  328. {
  329. Serial.println("Camera capture failed");
  330. return;
  331. }
  332. if (!SD_MMC.begin())
  333. {
  334. // SD Card Mount Failed.
  335. Serial.println("SD Card Mount Failed");
  336. esp_camera_fb_return(frame_buffer);
  337. return;
  338. }
  339. // Generate a unique filename.
  340. String path = "/picture";
  341. path += String(millis());
  342. path += ".jpg";
  343. fs::FS &fs = SD_MMC;
  344. File file = fs.open(path.c_str(), FILE_WRITE);
  345. if (!file)
  346. {
  347. Serial.println("Failed to open file in writing mode");
  348. }
  349. else
  350. {
  351. if (file.write(frame_buffer->buf, frame_buffer->len) != frame_buffer->len)
  352. {
  353. Serial.println("Failed to write the image to the file");
  354. }
  355. file.close(); // Close the file in any case.
  356. }
  357. // Update framesize back to the default.
  358. s->set_framesize(s, FRAMESIZE_QQVGA);
  359. // Return the frame buffer back to the camera driver.
  360. esp_camera_fb_return(frame_buffer);
  361. }