You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CubeSatSim/cubesatsim/esp32-cam-send-jpeg-serial/esp32-cam-send-jpeg-serial.ino

1282 lines
37 KiB

// ESP32-CAM JPEG over Serial
//
// by Jim McLaughlin and Alan Johnston
//
// Tested on ESP32-CAM-MB Camera Module hardware
// with Arduino 1.8.19 using Board: ESP32 Arduino Selected: AI Thinker ESP32-CAM
//
// example loop() program stores a JPEG and sends it over serial then waits 5 seconds.
//
// Based on code example https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/Camera/CameraWebServer
//
// initialize_camera initializes the ESP32-CAM - only call once per boot!
//
// save_camera_image takes a JPEG image and stores it with selected filename on
// built-in SPIFFS storage on ESP32-CAM (no SD card is needed)
//
// send_image_serial sends a selected filename from built-in storage over the serial
// port at 115200 in binary format with a 30 byte start flag and 40 byte end flag
// CRC-8 checksum is calculated over file and end flag and sent as the last byte.
//
// listDir gives a directory file listing of the built-in file storage
//
#include <Arduino.h>
#include "esp_camera.h"
#include <FastCRC.h>
//#include "FS.h"
#include "SPIFFS.h"
#include <TJpg_Decoder.h>
// some info: https://visualgdb.com/tutorials/esp32/camera/
//#define DEBUG
#define FORMAT_SPIFFS_IF_FAILED true
//FONTS
const uint8_t b_fonts[43][11] = {
{0x00, 0x18, 0x24, 0x62, 0x62, 0x62, 0x7E, 0x62, 0x62, 0x62, 0x00}, //00: A
{0x00, 0x7C, 0x32, 0x32, 0x32, 0x3C, 0x32, 0x32, 0x32, 0x7C, 0x00}, //01: B
{0x00, 0x3C, 0x62, 0x62, 0x60, 0x60, 0x60, 0x62, 0x62, 0x3C, 0x00}, //02: C
{0x00, 0x7C, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x7C, 0x00}, //03: D
{0x00, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x7E, 0x00}, //04: E
{0x00, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00}, //05: F
{0x00, 0x3C, 0x62, 0x62, 0x60, 0x60, 0x66, 0x62, 0x62, 0x3C, 0x00}, //06: G
{0x00, 0x62, 0x62, 0x62, 0x62, 0x7E, 0x62, 0x62, 0x62, 0x62, 0x00}, //07: H
{0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, //08: I
{0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x4C, 0x4C, 0x4C, 0x38, 0x00}, //09: J
{0x00, 0x62, 0x64, 0x68, 0x70, 0x68, 0x64, 0x62, 0x62, 0x62, 0x00}, //10: K
{0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00}, //11: L
{0x00, 0x42, 0x62, 0x76, 0x6A, 0x62, 0x62, 0x62, 0x62, 0x62, 0x00}, //12: M
{0x00, 0x42, 0x62, 0x72, 0x6A, 0x66, 0x62, 0x62, 0x62, 0x62, 0x00}, //13: N
{0x00, 0x3C, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x3C, 0x00}, //14: O
{0x00, 0x7C, 0x62, 0x62, 0x62, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00}, //15: P
{0x00, 0x3C, 0x62, 0x62, 0x62, 0x62, 0x62, 0x6A, 0x6A, 0x3C, 0x08}, //16: Q
{0x00, 0x7C, 0x62, 0x62, 0x62, 0x7C, 0x68, 0x64, 0x62, 0x62, 0x00}, //17: R
{0x00, 0x3C, 0x62, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x46, 0x3C, 0x00}, //18: S
{0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, //19: T
{0x00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x3C, 0x00}, //20: U
{0x00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x22, 0x14, 0x08, 0x00}, //21: V
{0x00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x6A, 0x76, 0x62, 0x42, 0x00}, //22: W
{0x00, 0x42, 0x62, 0x74, 0x38, 0x1C, 0x2E, 0x46, 0x42, 0x42, 0x00}, //23: X
{0x00, 0x42, 0x62, 0x74, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, //24: Y
{0x00, 0x7E, 0x06, 0x0E, 0x0C, 0x18, 0x30, 0x70, 0x60, 0x7E, 0x00}, //25: Z
{0x00, 0x3C, 0x62, 0x62, 0x66, 0x6A, 0x72, 0x62, 0x62, 0x3C, 0x00}, //26: 0
{0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, //27: 1
{0x00, 0x3C, 0x46, 0x06, 0x06, 0x1C, 0x20, 0x60, 0x60, 0x7E, 0x00}, //28: 2
{0x00, 0x3C, 0x46, 0x06, 0x06, 0x1C, 0x06, 0x06, 0x46, 0x3C, 0x00}, //29: 3
{0x00, 0x0C, 0x1C, 0x2C, 0x4C, 0x4C, 0x7E, 0x0C, 0x0C, 0x0C, 0x00}, //30: 4
{0x00, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x06, 0x06, 0x46, 0x3C, 0x00}, //31: 5
{0x00, 0x3C, 0x62, 0x60, 0x60, 0x7C, 0x62, 0x62, 0x62, 0x3C, 0x00}, //32: 6
{0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00}, //33: 7
{0x00, 0x3C, 0x62, 0x62, 0x62, 0x3C, 0x62, 0x62, 0x62, 0x3C, 0x00}, //34: 8
{0x00, 0x3C, 0x46, 0x46, 0x46, 0x3E, 0x06, 0x06, 0x46, 0x3C, 0x00}, //35: 9
{0x00, 0x00, 0x02, 0x06, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0x40, 0x00}, //36: /
{0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00}, //37: -
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00}, //38: .
{0x00, 0x3C, 0x46, 0x06, 0x06, 0x0C, 0x10, 0x00, 0x30, 0x30, 0x00}, //39: ?
{0x00, 0x18, 0x18, 0x18, 0x18, 0x10, 0x10, 0x00, 0x18, 0x18, 0x00}, //40: !
{0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00}, //41: :
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //42: space
};
// Nibble font table
const uint8_t l_fonts[23][5] = {
{ 0xE2, 0xA6, 0xA2, 0xA2, 0xE2 }, // 0: 01
{ 0xEE, 0x22, 0xE6, 0x82, 0xEE }, // 1: 23
{ 0xAE, 0xA8, 0xEE, 0x22, 0x2E }, // 2: 45
{ 0x8E, 0x82, 0xE2, 0xA2, 0xE2 }, // 3: 67
{ 0xEE, 0xAA, 0xEE, 0xA2, 0xE2 }, // 4: 89
{ 0x00, 0x22, 0x00, 0x22, 0x04 }, // 5: :;
{ 0x20, 0x4E, 0x80, 0x4E, 0x20 }, // 6: <=
{ 0x8E, 0x42, 0x26, 0x40, 0x84 }, // 7: >?
{ 0x64, 0x9A, 0xBE, 0x8A, 0x7A }, // 8: @A
{ 0xC6, 0xA8, 0xC8, 0xA8, 0xC6 }, // 9: BC
{ 0xCE, 0xA8, 0xAC, 0xA8, 0xCE }, // 10: DE
{ 0xE6, 0x88, 0xCE, 0x8A, 0x86 }, // 11: FG
{ 0xA4, 0xA4, 0xE4, 0xA4, 0xA4 }, // 12: HI
{ 0x69, 0x2A, 0x2C, 0x2A, 0x49 }, // 13: JK
{ 0x8A, 0x8E, 0x8E, 0x8A, 0xEA }, // 14: LM
{ 0x04, 0x9A, 0xDA, 0xBA, 0x94 }, // 15: NO
{ 0xC4, 0xAA, 0xCA, 0x8E, 0x86 }, // 16: PQ
{ 0xC6, 0xA8, 0xC4, 0xA2, 0xAC }, // 17: RS
{ 0xE0, 0x4A, 0x4A, 0x4A, 0x44 }, // 18: TU
{ 0x09, 0xA9, 0xA9, 0x6F, 0x26 }, // 19: vW (sort of..)
{ 0x0A, 0xAA, 0x46, 0xA2, 0x04 }, // 20: XY
{ 0xE6, 0x24, 0x44, 0x84, 0xE6 }, // 21: Z[
{ 0x00, 0x00, 0x00, 0x00, 0x00 } // 22: SPACE
};
char input_buffer[240][240][3];
void app_main();
void send_image_serial(char *filename);
void save_camera_image(char* filename);
void initialize_camera();
static esp_err_t init_camera();
#define RX2_pin IO16 // AMBE3000 RX to ESP32 TXD
#define TX2_pin IO17 // AMBE3000 TX to ESP32 RXD
#define LED_PIN 33 // LED pin on ESP32-CAM-MB board is 33
const char start_flag[] = "3d99de816e5ad7742b61a37c39141783"; // MD5 hash of "ESP32-CAM" as start flag
const char end_flag[] = "f681a5c52351befe0e3524eb1a40f14b7803317a"; // SHA-1 hash of "ESP32-CAM" as end flag
FastCRC8 CRC8;
char hexValue[6];
char file_buf[50000];
int file_len;
bool file_flag = false;
camera_fb_t *pic;
File inFile;
File outFile;
int blocks = 0;
//int counter = 0;
bool write_complete = false;
// example code from https://github.com/espressif/arduino-esp32/blob/master/libraries/LittleFS/examples/LITTLEFS_test/LITTLEFS_test.ino
//
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if (!root) {
Serial.println("- failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.name(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void deleteFile(fs::FS &fs, const char * path) {
Serial.printf("Deleting file: %s\r\n", path);
if (fs.remove(path)) {
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
}
void setup() {
delay(5000);
Serial.begin(115200);
initialize_camera();
config_camera();
Serial.println("ESP32-CAM Camera initialized");
pinMode(LED_PIN, OUTPUT); // Set the pin as output
// On the ESP32 you can also define another hardware serial interface using pins of your choice like this
// Serial2.begin(115200,SERIAL_8N1,14,15);
// Serial.println("Initializing CRC");
// crc.setPolynome(0x1021);
if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
Serial.println("SPIFFS Mount Failed");
return;
}
listDir(SPIFFS, "/", 0);
}
void loop() {
char filename[] = "/cam.jpg";
save_camera_image(filename);
send_image_serial(filename);
delay(500);
}
/**
This example takes a picture every 5s and print its size on serial monitor.
*/
// =============================== SETUP ======================================
// 1. Board setup (Uncomment):
// #define BOARD_WROVER_KIT
// #define BOARD_ESP32CAM_AITHINKER
/**
2. Kconfig setup
If you have a Kconfig file, copy the content from
https://github.com/espressif/esp32-camera/blob/master/Kconfig into it.
In case you haven't, copy and paste this Kconfig file inside the src directory.
This Kconfig file has definitions that allows more control over the camera and
how it will be initialized.
*/
/**
3. Enable PSRAM on sdkconfig:
CONFIG_ESP32_SPIRAM_SUPPORT=y
More info on
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support
*/
// ================================ CODE ======================================
//#include <esp_log.h>
//#include <esp_system.h>
//#include <nvs_flash.h>
//#include <sys/param.h>
//#include <string.h>
//#include "freertos/FreeRTOS.h"
//#include "freertos/task.h"
// ESP32Cam (AiThinker) PIN Map
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
//static const char *TAG = "example:take_picture";
static camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK,
.pin_sscb_sda = CAM_PIN_SIOD,
.pin_sscb_scl = CAM_PIN_SIOC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF,
.pin_pclk = CAM_PIN_PCLK,
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG, // Options: YUV422, GRAYSCALE, RGB565, JPEG
.frame_size = FRAMESIZE_QVGA, // Options: QQVGA-UXGA, QVGA Do not use sizes above QVGA when not JPEG
.jpeg_quality = 6, // 12, //0-63 lower number means higher quality
.fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG
// .grab_mode = CAMERA_GRAB_WHEN_EMPTY,
};
static esp_err_t init_camera()
{
//initialize the camera
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK)
{
// ESP_LOGE(TAG, "Camera Init Failed");
return err;
}
return ESP_OK;
}
void config_camera() {
sensor_t * s = esp_camera_sensor_get();
// s->set_brightness(s, 2); // -2 to 2
// s->set_contrast(s, 0); // -2 to 2
// s->set_saturation(s, 1); // -2 to 2
s->set_hmirror(s, 1); // 0 = disable , 1 = enable
// s->set_vflip(s, 1);
}
void initialize_camera() {
if (ESP_OK != init_camera()) {
Serial.println("Failed to initialize camera!");
return;
}
}
void save_camera_image(char* filename)
{
Serial.print("Saving camera image to file: ");
Serial.println(filename);
Serial.println("\nBlink...");
digitalWrite(LED_PIN, LOW); // Turn on
delay (100); // Wait 0.1 sec
digitalWrite(LED_PIN, HIGH); // Turn off
Serial.println("\nTaking picture...\n");
pic = esp_camera_fb_get();
const char path[] = "/cam.jpg";
Serial.println("Writing image file"); //: %s\r\n", path);
// File file = SPIFFS.open(path, FILE_WRITE);
File file = SPIFFS.open(filename, FILE_WRITE);
if (!file) {
Serial.println("- failed to open file for writing");
return;
}
for (int k = 0; k < pic->len; k++) {
file.write(pic->buf[k]);
}
file.close();
Serial.println("Write complete");
listDir(SPIFFS, "/", 0);
}
void send_image_serial(char *filename)
{
Serial.println("Sending image over serial");
Serial.println("\nBlink twice");
digitalWrite(LED_PIN, LOW); // Turn on
delay (100); // Wait 0.1 sec
digitalWrite(LED_PIN, HIGH); // Turn off
delay(100); // Wait 0.1 sec
digitalWrite(LED_PIN, LOW); // Turn on
delay (100); // Wait 0.1 sec
digitalWrite(LED_PIN, HIGH); // Turn off
// read from file
const char path[] = "/cam.jpg";
Serial.println("Reading image file"); //: %s\r\n", path);
// File file = SPIFFS.open(path, FILE_READ);
File file = SPIFFS.open(filename, FILE_READ);
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
int k = 0;
while (file.available()) {
// file.write(pic->buf[size]);
file_buf[k] = file.read();
k++;
}
file.close();
file_len = k;
Serial.print(file_len);
Serial.println(" bytes read from file.");
file_flag = true;
// }
// Sending image file
Serial.println("Start of binary data:");
// Serial.println("\nResetting CRC");
// crc.restart();
int j = 0;
// flag at start
for (int i = 0; i < strlen(start_flag); i++) {
sprintf(hexValue, "%02X", start_flag[i]);
// Serial.print(hexValue);
Serial.write(start_flag[i]);
// Serial.print(start_flag[i], HEX);
}
#ifdef DEBUG
#endif
char str[] = "ESP32-CAM";
if (file_flag == true) {
// Serial.println("******************* Sending stored file! ***************************\n");
for (j = 0; j < file_len; j++) {
/// for (int i = 0; i < 9; i++) {
uint8_t *data = (uint8_t *) &file_buf[j];
// crc.add(data[0]);
// crc.add(data[0]);
/// crc.add(str[i]);
#ifndef DEBUG
if (file_buf[j] != 0x66)
sprintf(hexValue, "%02X", file_buf[j]);
else
strcpy(hexValue, "66");
Serial.write(file_buf[j]);
// Serial.print(hexValue);
/// Serial.write(str[j]);
#endif
// Serial.print(pic->buf[j], HEX);
#ifdef DEBUG
// char hexValue[5];
sprintf(hexValue, "%02X", file_buf[j]);
Serial.print(hexValue);
#endif
// Serial.print(" ");
}
} else { // !file_flag - read from camera
for (j = 0; j < pic->len; j++) {
/// for (int i = 0; i < 9; i++) {
uint8_t *data = (uint8_t *) &pic->buf[j];
// crc.add(data[0]);
// crc.add(data[0]);
/// crc.add(str[i]);
file_buf[j] = pic->buf[j];
#ifndef DEBUG
sprintf(hexValue, "%02X", pic->buf[j]);
Serial.write(pic->buf[j]);
// Serial.print(hexValue);
/// Serial.write(str[j]);
#endif
// Serial.print(pic->buf[j], HEX);
#ifdef DEBUG
// char hexValue[5];
sprintf(hexValue, "%02X", pic->buf[j]);
Serial.print(hexValue);
#endif
// Serial.print(" ");
}
}
// Serial.print("j = ");
// Serial.println(j);
// flag at end
for (int i = 0; i < strlen(end_flag); i++) {
sprintf(hexValue, "%02X", end_flag[i]);
// Serial.print(hexValue);
file_buf[j++] = end_flag[i];
Serial.write(end_flag[i]);
// Serial.print(end_flag[i], HEX);
// if (file_flag) {
// file_buf[j++] = end_flag[i];
// } else {
// pic->buf[i++] = end_flag[j];
// }
}
uint8_t * data;
int index1;
data = (uint8_t *) &file_buf[0];
index1 = j;
// int calculated_crc = crc8(data, index1, 0x07, 0x0000, 0x0000, false, false);
int calculated_crc = CRC8.smbus(data, index1);
//#ifndef DEBUG
sprintf(hexValue, "%02X", calculated_crc);
Serial.write(calculated_crc);
// Serial.print(hexValue);
// Serial.write(0xff & calculated_crc);
//#endif
//#ifdef DEBUG
// sprintf(hexValue, "%04X", calculated_crc);
// Serial.print(hexValue);
// Serial.println("\n ");
//#endif
Serial.println("\nEnd of binary data.");
Serial.println("\nCRC cacluation data:");
Serial.println(file_buf[0], HEX);
Serial.println(file_buf[j - 1], HEX);
Serial.println(j);
Serial.print("\nCRC sent with image: ");
// char hexValue[6];
sprintf(hexValue, "%02X", calculated_crc);
Serial.print(hexValue);
Serial.println("\n");
/* remove hex print
for (int i = 0; i < pic->len; i++) {
// Serial.write(pic->buf[i]);
Serial.print(pic->buf[i], HEX);
// Serial.print(" ");
}
Serial.println(" ");
*/
// use pic->buf to access the image
ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len);
// format of the captured picture will be stored in the format field of the
// structure returned by esp_camera_fb_get()
Serial.print("image size ");
if (file_flag)
Serial.println(file_len);
else {
Serial.println(pic->len);
// must free the memory allocated by esp_camera_fb_get()
esp_camera_fb_return(pic);
}
Serial.println("File sent!");
}
void print_hex(byte octet) {
char hexValue[5];
sprintf(hexValue, "%02X", octet);
Serial.print(hexValue);
}
char img_block[320][8][3]; // 320 pixels per row, 8 rows, 3 values (RGB) per.
bool get_block(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
#ifdef DEBUG
Serial.println("\nBlock callback");
Serial.println(x);
Serial.println(y);
Serial.println(w);
Serial.println(h);
#endif
// return 1;
uint16_t pixel_value;
uint16_t *pixel;
bool last_block = ((x == (320 - w)) & (y == (240 - h)));
// char buffer[16 * 8 * 3];
int counter = 0;
//int x_block = (x / w) % w;
//int y_block = (y / h) % h;
/*
if (((y % h) == 0) && ((x % w) == 0)) {
Serial.print("\nStart of row! x = ");
Serial.print(x);
Serial.print(" y = ");
Serial.println(y);
}
*/
pixel = bitmap;
uint32_t total_pixels = w * h;
// while (total_pixels--) {
while (counter < total_pixels) {
pixel_value = *pixel;
int y_rel = counter / w;
int x_rel = counter % w; // - y_rel * w;
/*
Serial.print("Relative x + x = ");
Serial.print(x_rel + x);
Serial.print(" y + y = ");
Serial.print(y_rel);
Serial.print(" counter = ");
Serial.println(counter);
*/
/*
if ((x == 0) && (y == 0)) {
Serial.print(" ");
Serial.print(pixel_value, HEX);
Serial.print(" ");
}
*/
// buffer[counter++] = pixel_value >> 8;
// buffer[counter++] = pixel_value;
byte red = (pixel_value & 0b1111100000000000) >> 8;
byte green = (pixel_value & 0b0000011111100000) >> 3;
byte blue = (pixel_value & 0b0000000000011111) << 3;
// buffer[counter++] = red;
// buffer[counter++] = green;
// buffer[counter++] = blue;
img_block[x_rel + x][y_rel][0] = red;
img_block[x_rel + x][y_rel][1] = green;
img_block[x_rel + x][y_rel][2] = blue;
#ifdef DEBUG
Serial.print("\npixel_value: ");
Serial.print(pixel_value);
Serial.print("\nRGB: ");
print_hex(red);
print_hex(green);
print_hex(blue);
Serial.println("\n img_block: ");
for (int k = 0; k < 3; k ++)
print_hex(*(&img_block[x_rel + x][y_rel][0] + k));
#endif
/*
if (counter >= 155000) {
Serial.println("Resetting counter****************************************\n");
counter = 0;
}
*/
counter++;
pixel++;
}
// Serial.println("\nWriting block to file");
// Serial.print("Sizeof buffer: ");
// Serial.println(sizeof(buffer));
if (x == 304) {
if (outFile) {
Serial.println("********************************************* Writing block!");
outFile.write((const uint8_t*)&img_block[0][0][0], sizeof(img_block));
} else
Serial.println("Problem writing block");
counter = 0;
}
if (last_block) {
Serial.println("Complete!\n\n");
}
/*
for (int i = 0; i < counter; i++) {
// Serial.print(buffer[i], HEX);
char hexValue[5];
sprintf(hexValue, "%02X", buffer[i]);
Serial.print(hexValue);
}
*/
// Serial.print("\n\n Size: ");
// Serial.println(counter);
// write_complete = true;
// }
// delay(1000);
blocks++;
return 1;
}
int JpegDec_i;
int JpegDec_j;
int JpegDec_height = 240;
int JpegDec_width = 320;
byte JpegDec_sortBuf[15360]; //320(px)*16(lines)*3(bytes) // Header buffer
int JpegDec_pxSkip;
uint8_t *JpegDec_pImg;
int JpegDec_x, JpegDec_y, JpegDec_bx, JpegDec_by;
int JpegDec_comps = 3;
bool merged_get_block(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
#ifdef DEBUG
Serial.println("\nBlock callback");
Serial.println(x);
Serial.println(y);
Serial.println(w);
Serial.println(h);
#endif
int JpegDec_MCUx = x;
int JpegDec_MCUy = y;
int JpegDec_MCUHeight = h;
int JpegDec_MCUWidth = w;
// JpegDec_pImg = bitmap;
// JpegDec_pImg = JpegDec_pImage;
for(JpegDec_by=0; JpegDec_by<JpegDec_MCUHeight; JpegDec_by++){
for(JpegDec_bx=0; JpegDec_bx<JpegDec_MCUWidth; JpegDec_bx++){
// JpegDec_x = JpegDec_MCUx * JpegDec_MCUWidth + JpegDec_bx;
// JpegDec_y = JpegDec_MCUy * JpegDec_MCUHeight + JpegDec_by;
JpegDec_x = JpegDec_MCUx + JpegDec_bx;
JpegDec_y = JpegDec_MCUy + JpegDec_by;
if(JpegDec_x<JpegDec_width && JpegDec_y<JpegDec_height){
// if(JpegDec_comps == 1){ // Grayscale
// //sprintf(str,"%u", pImg[0]);
// outFile.write(JpegDec_pImg, 1);
// }else
{ // RGB
// When saving to the SD, write 16 lines on one time
// First we write on the array 16 lines and then we save to SD
JpegDec_pxSkip = ((JpegDec_y - (16 * JpegDec_j)) * 320) + JpegDec_x;
int pixel_value = *bitmap;
byte red = (pixel_value & 0b1111100000000000) >> 8;
byte green = (pixel_value & 0b0000011111100000) >> 3;
byte blue = (pixel_value & 0b0000000000011111) << 3;
JpegDec_sortBuf[(3 * JpegDec_pxSkip) + 0] = red; // JpegDec_pImg[0];
JpegDec_sortBuf[(3 * JpegDec_pxSkip) + 1] = green; // JpegDec_pImg[1];
JpegDec_sortBuf[(3 * JpegDec_pxSkip) + 2] = blue; // JpegDec_pImg[2];
#ifdef DEBUG
Serial.print("sortBuf index = ");
Serial.println((3 * JpegDec_pxSkip));
#endif
JpegDec_i++;
if(JpegDec_i == 5120){ //320(px)x16(lines)
#ifdef DEBUG
Serial.println("Writing lines!");
#endif
// for(k = 0; k < 15360; k++){
// imgFile.write(sortBuf[k]);
// }
outFile.write(JpegDec_sortBuf, sizeof(JpegDec_sortBuf));
JpegDec_i = 0;
JpegDec_j++; //15(sections)
}
}
}
// JpegDec_pImg += JpegDec_comps ;
bitmap++;
}
}
#ifdef DEBUG
Serial.println("Block processed!");
#endif
return 1;
}
void jpeg_decode(char* filename, char* fileout, bool debug){
uint8_t *pImg;
// uint16_t *pImg;
int x,y, bx,by;
byte sortBuf[15360]; //320(px)*16(lines)*3(bytes) // Header buffer
int i,j,k;
int pxSkip;
// Open the file for writing
// File imgFile = SD.open(fileout, FILE_WRITE);
outFile = SPIFFS.open(fileout, "w+");
if (outFile) {
if (debug)
Serial.println("Output opened");
}
else
Serial.println("Failed to open output");
/*
for(i = 0; i < 15360; i++){ // Cleaning Header Buffer array
sortBuf[i] = 0xFF;
}
for(i = 0; i < 12; i++){
byte fontNumber;
char ch;
ch = charId[i];
for(y = 0; y < 11; y++){
for(x = 0; x < 8; x++){
pxSkip = 16 + (320 * (y + 3)) + (3 * 8 * i) + (3 * x); //Width: x3
uint8_t mask;
mask = pow(2, 7 - x);
if(ch >= 65 && ch <= 90){ // A to Z
fontNumber = ch - 65;
}
else if(ch >= 48 && ch <= 57){ //0 to 9
fontNumber = ch - 22;
}
else if(ch == '/'){fontNumber = 36;}
else if(ch == '-'){fontNumber = 37;}
else if(ch == '.'){fontNumber = 38;}
else if(ch == '?'){fontNumber = 39;}
else if(ch == '!'){fontNumber = 40;}
else if(ch == ':'){fontNumber = 41;}
else if(ch == ' '){fontNumber = 42;}
else {fontNumber = 42;}
if((b_fonts[fontNumber][y] & mask) != 0){
for(j = 0; j < 9; j++){
sortBuf[(3 * pxSkip) + j] = 0x00;
}
}
}
}
}
// for(k = 0; k < 15360; k++){ // Adding header to the binary file
// imgFile.write(sortBuf[k]);
// }
outFile.write(sortBuf, sizeof(sortBuf));
*/
// writeFooter(&outFile); //Writing first 10560 bytes (11*320*3) // write footer after rotate
// Decoding start
if (debug)
Serial.println("Starting jpeg decode");
JpegDec_i = 0;
JpegDec_j = 0;
uint16_t w = 0, h = 0;
// TJpgDec.getFsJpgSize(&w, &h, "/cam.jpg", LittleFS); // Note name preceded with "/"
TJpgDec.getFsJpgSize(&w, &h, filename, SPIFFS); // Note name preceded with "/"
if (debug) {
Serial.print("Width = ");
Serial.print(w);
Serial.print(", height = ");
Serial.println(h);
}
if ((w == 0) && (h == 0)) {
Serial.println("Failed to open jpeg input");
return;
}
// counter = 0;
// write_complete = false;
TJpgDec.setJpgScale(1);
TJpgDec.setSwapBytes(false); // was true
// TJpgDec.setCallback(get_block);
TJpgDec.setCallback(merged_get_block);
//TJpgDec.drawFsJpg(0, 0, "/cam.jpg", LittleFS);
TJpgDec.drawFsJpg(0, 0, filename, SPIFFS);
if (debug)
Serial.println("Draw complete");
// while (!write_complete) { Serial.println("Waiting..."); delay(500);}
/*
JpegDec.decodeFile(filename);
// Image Information
Serial.print("Width :");
Serial.println(JpegDec.width);
Serial.print("Height :");
Serial.println(JpegDec.height);
Serial.print("Components:");
Serial.println(JpegDec.comps);
Serial.print("MCU / row :");
Serial.println(JpegDec.MCUSPerRow);
Serial.print("MCU / col :");
Serial.println(JpegDec.MCUSPerCol);
Serial.print("Scan type :");
Serial.println(JpegDec.scanType);
Serial.print("MCU width :");
Serial.println(JpegDec.MCUWidth);
Serial.print("MCU height:");
Serial.println(JpegDec.MCUHeight);
Serial.println("");
*/
if (debug)
Serial.println("Writing bin to FS");
// imgFile.write(JpegDec.pImage, sizeof(JpegDec.pImage));
/*
i = 0;
j = 0;
while(JpegDec.read()){
pImg = JpegDec.pImage ;
for(by=0; by<JpegDec.MCUHeight; by++){
for(bx=0; bx<JpegDec.MCUWidth; bx++){
x = JpegDec.MCUx * JpegDec.MCUWidth + bx;
y = JpegDec.MCUy * JpegDec.MCUHeight + by;
if(x<JpegDec.width && y<JpegDec.height){
if(JpegDec.comps == 1){ // Grayscale
//sprintf(str,"%u", pImg[0]);
imgFile.write(pImg, sizeof(pImg));
}else{ // RGB
// When saving to the SD, write 16 lines on one time
// First we write on the array 16 lines and then we save to SD
pxSkip = ((y - (16 * j)) * 320) + x;
sortBuf[(3 * pxSkip) + 0] = pImg[0];
sortBuf[(3 * pxSkip) + 1] = pImg[1];
sortBuf[(3 * pxSkip) + 2] = pImg[2];
i++;
if(i == 5120){ //320(px)x16(lines)
// for(k = 0; k < 15360; k++){
imgFile.write(sortBuf, sizeof(sortBuf));
// }
i = 0;
j++; //15(sections)
}
}
}
pImg += JpegDec.comps ;
}
}
}
*/
if (debug)
Serial.println("Bin has been written to FS");
outFile.close();
}
/*
//void shot_pic(){
void get_pic() {
int32_t start_time = millis();
time = millis() - start_time;
Serial.println("get_pic done!");
Serial.print(start_time);
Serial.println(" ms elapsed");
return;
}
// Try to locate the camera
if (cam.begin()) {
Serial.println("Camera Found:");
} else {
Serial.println("No camera found?");
return;
}
for (int i = 0; i <= 10; i++){
cam.setImageSize(VC0706_320x240);
}
Serial.println("Snap in 3 secs...");
delay(3000);
if (! cam.takePicture())
Serial.println("Failed to snap!");
else
Serial.println("Picture taken!");
// Create an image with the name IMAGExx.JPG`
strcpy(pic_filename, "IMAGE00.JPG");
for (int i = 0; i < 100; i++) {
pic_filename[5] = '0' + i/10;
pic_filename[6] = '0' + i%10;
// create if does not exist, do not open existing, write, sync after write
if (! SD.exists(pic_filename)) {
break;
}
}
// Open the file for writing
File imgFile = SD.open(pic_filename, FILE_WRITE);
// Get the size of the image (frame) taken
uint16_t jpglen = cam.frameLength();
Serial.print("Storing ");
Serial.print(jpglen, DEC);
Serial.print(" byte image.");
int32_t time = millis();
pinMode(8, OUTPUT);
// Read all the data up to # bytes!
byte wCount = 0; // For counting # of writes
while (jpglen > 0) {
// read 32 bytes at a time;
uint8_t *buffer;
uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
buffer = cam.readPicture(bytesToRead);
imgFile.write(buffer, bytesToRead);
if(++wCount >= 64) { // Every 2K, give a little feedback so it doesn't appear locked up
Serial.print('.');
wCount = 0;
}
//Serial.print("Read "); Serial.print(bytesToRead, DEC); Serial.println(" bytes");
jpglen -= bytesToRead;
}
imgFile.close();
time = millis() - time;
Serial.println("done!");
Serial.print(time); Serial.println(" ms elapsed");
*/
//}
/** Write on a file with 11 lines the values of the GPS
* @param dst Given an opened File stream then write data to dst.
* @param latitude Floating point latitude value in degrees/min as received from the GPS (DDMM.MMMM)
* @param lat N/S
* @param longitude Floating point longitude value in degrees/min as received from the GPS (DDMM.MMMM)
* @param lon E/W
* @param altitude Altitude in meters above MSL
*/
/*
//void writeFooter(File* dst, nmea_float_t latitude, char lat, nmea_float_t longitude, char lon, nmea_float_t altitude){ //Write 16 lines with values
void writeFooter(File* dst){
int x,y;
byte sortBuf[10560]; //320(px)*11(lines)*3(bytes) // Header buffer
int i,j,k;
int pxSkip;
char res[51] = "LAT: 1234.1234N LONG: 1234.1234W ALT:10000";
for(i = 0; i < 10560; i++){ // Cleaning Header Buffer array
sortBuf[i] = 0xFF;
}
for(i = 0; i < sizeof(res); i++){
byte fontNumber;
char ch;
ch = res[i];
for(y = 0; y < 5; y++){
for(x = 0; x < 4; x++){
//pxSkip = HORIZONTALOFFSET + VERSTICALOFFSET + (BITSPERWORD * i);
//pxSkip = 16 + (320 * (y + 3)) + (4 * 2 * i) + (2 * x); Width: x2
pxSkip = 16 + (320 * (y + 3)) + (4 * i) + x;
// If ch is pair mask is: 11110000, if no 00001111
uint8_t sl = (ch % 2)? 3 : 7 ;
uint8_t mask = pow(2, sl - x);
if(ch >= 48 && ch <=91){
fontNumber = (ch-48)/2;
}
else {
fontNumber = 22;
}
if((l_fonts[fontNumber][y] & mask) != 0){
for(j = 0; j < 3; j++){
sortBuf[(3 * pxSkip) + j] = 0x00;
}
}
}
}
}
// for(k = 0; k < 10560; k++){ // Adding header to the binary file
// dst->write(sortBuf[k]);
dst->write(sortBuf, sizeof(sortBuf));
// }
}
*/
void raw_decode(char* filename, char* fileout){ // used to decode .raw files in RGB565 format
// Open the input file for reading
inFile = SPIFFS.open(filename, "r");
if (inFile)
Serial.println("Input opened");
else {
Serial.println("Failed to open input");
return;
}
// Open the output file for writing
outFile = SPIFFS.open(fileout, "w+");
if (outFile)
Serial.println("Output opened");
else {
Serial.println("Failed to open output");
return;
}
char buff[2];
char buffer[3];
int i = 0;
// int redx = 128;
// int greenx = 128;
// int bluex = 128;
// while (i++ < (320 * 240 * 3)) {
while (i++ < (320 * 240 * 1.49)) {
inFile.readBytes(buff, 2);
#ifdef DEBUG
print_hex(buff[0]);
print_hex(buff[1]);
#endif
int pixel_value = (buff[0] << 8) + buff[1]; // endian for raw
byte red = (pixel_value & 0b1111100000000000) >> 8;
byte green = (pixel_value & 0b0000011111100000) >> 3;
byte blue = (pixel_value & 0b0000000000011111) << 3;
#ifdef TEST_PATTERN
int size = 5; // 46;
int y = (int)( i / 320 );
int x = (int)( i - y * 320 );
int box = (int)(x/size) + (int)(y/size);
if (y < 10) { // 20) {
red = 0;
green = 255;
blue = 0;
}
else if ( box == ( (int)(box / 2) * 2)) {
// Serial.println(x);
// Serial.println(y);
// Serial.println(box);
// Serial.println(" ");
red = 255; //(100 + x) % 256;
green = 0; // ;
blue = 0;
} else {
// Serial.println(x);
// Serial.println(y);
// Serial.println(box);
// Serial.println(" ");
red = 0;
green = 0;
blue = 255; //(100 + y) % 256;
}
#endif
buffer[0] = red;
buffer[1] = green;
buffer[2] = blue;
/*
if (y < 20) { // 20) {
buffer[0] = 0;
buffer[1] = 255;
buffer[2] = 0;
} else {
buffer[0] = redx;
buffer[1] = greenx;
buffer[2] = bluex;
}
*/
int bytes = outFile.write((const uint8_t*)buffer, 3);
// Serial.println(bytes);
if (bytes < 3)
Serial.println("Error writing output file");
#ifdef DEBUG
print_hex(red);
print_hex(green);
print_hex(blue);
// delay(100);
#endif
}
inFile.close();
outFile.close();
}
/*
//void writeFooter(File* dst, nmea_float_t latitude, char lat, nmea_float_t longitude, char lon, nmea_float_t altitude){ //Write 16 lines with values
void writeFooter(File* dst, char *telemetry){
int x,y;
byte sortBuf[10560]; //320(px)*11(lines)*3(bytes) // Header buffer
int i,j,k;
int pxSkip;
char res[51]; // = "LAT: 1234.1234N LONG: 1234.1234W ALT:10000";
if (strlen(telemetry) > 50)
telemetry[50] = '\0';
strcpy(res, telemetry);
for(i = 0; i < 10560; i++){ // Cleaning Header Buffer array
sortBuf[i] = 0xFF;
}
for(i = 0; i < sizeof(res); i++){
byte fontNumber;
char ch;
ch = res[i];
for(y = 0; y < 5; y++){
for(x = 0; x < 4; x++){
//pxSkip = HORIZONTALOFFSET + VERSTICALOFFSET + (BITSPERWORD * i);
//pxSkip = 16 + (320 * (y + 3)) + (4 * 2 * i) + (2 * x); Width: x2
pxSkip = 16 + (320 * (y + 3)) + (4 * i) + x;
// If ch is pair mask is: 11110000, if no 00001111
uint8_t sl = (ch % 2)? 3 : 7 ;
uint8_t mask = pow(2, sl - x);
if(ch >= 48 && ch <=91){
fontNumber = (ch-48)/2;
}
else {
fontNumber = 22;
}
if((l_fonts[fontNumber][y] & mask) != 0){
for(j = 0; j < 3; j++){
sortBuf[(3 * pxSkip) + j] = 0x00;
}
}
}
}
}
for(k = 0; k < 10560; k++){ // Adding header to the binary file
dst->write(sortBuf[k]);
}
}
*/
void rotate_image(char *file_input, char *file_output, char *telemetry) {
File input_file = SPIFFS.open(file_input, "r");
char pixel[3];
int side = (320 - 240)/2;
for (int y = 0; y < 240; y++) {
for (int x = 0; x < 320; x++) {
input_file.readBytes(pixel, sizeof(pixel));
if (( x >= side) && (x < (320 - side))) {
input_buffer[y][x - side][0] = pixel[0];
input_buffer[y][x - side][1] = pixel[1];
input_buffer[y][x - side][2] = pixel[2];
}
}
}
input_file.close();
SPIFFS.remove(file_input);
Serial.println("Input file read and deleted");
Serial.println(side);
input_file = SPIFFS.open(file_input, "w+");
//writeFooter(&input_file, telemetry);
char side_pixel[] = { 0xff, 0xff, 0xff };
for (int y = 0; y < 240; y++) {
Serial.println(" ");
for (int x = 0; x < 320; x++) {
if (( x >= side) && (x < (320 - side))) {
Serial.print("+");
// Serial.print(x - side);
// Serial.print(" ");
pixel[0] = input_buffer[x - side][y][0];
pixel[1] = input_buffer[x - side][y][1];
pixel[2] = input_buffer[x - side][y][2];
if (input_file.write((const uint8_t*)pixel, sizeof(pixel)) < 3)
Serial.println("Error writing to file");
} else {
Serial.print("-");
if (input_file.write((const uint8_t*)side_pixel, sizeof(side_pixel)) < 3)
Serial.println("Error writing to file");
}
}
}
input_file.close();
}

Powered by TurnKey Linux.