firmware.ino 14 KB

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