diff --git a/cubesatsim/cubesatsim.h b/cubesatsim/cubesatsim.h index dd7eb8eb..15482d55 100644 --- a/cubesatsim/cubesatsim.h +++ b/cubesatsim/cubesatsim.h @@ -33,7 +33,7 @@ #include "hardware/pwm.h" // pwm #include "hardware/sync.h" // wait for interrupt #include "RPi_Pico_TimerInterrupt.h" -#include +//#include #include "hardware/gpio.h" #include "hardware/adc.h" #include @@ -137,7 +137,7 @@ char serial_string[128]; //#define WAV_DATA_LENGTH (50000 * 8) uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; -uint8_t data[1024]; +//uint8_t data[1024]; uint32_t tx_channel = 0; //ax5043_conf_t hax5043; @@ -231,7 +231,8 @@ long time_start; //char cmdbuffer[1000]; //FILE * file1;// #define BUFFER_SIZE 5841 //970 // (970 * 2) // * 2) -short int buffer[BUFFER_SIZE]; // 50000]; //BUFFER_SIZE]; // ctr is an int // 100000]; // 50000]; // 25000]; // 10240]; // was 2336400]; // max size for 10 frames count of BPSK +//short int buffer[BUFFER_SIZE]; // 50000]; //BUFFER_SIZE]; // ctr is an int // 100000]; // 50000]; // 25000]; // 10240]; // was 2336400]; // max size for 10 frames count of BPSK +byte buffer[BUFFER_SIZE]; // 50000]; //BUFFER_SIZE]; // ctr is an int // 100000]; // 50000]; // 25000]; // 10240]; // was 2336400]; // max size for 10 frames count of BPSK //short int buffer[(WAV_DATA_LENGTH/8)]; //FILE *sopen(const char *program); char tlm_str[1000]; @@ -372,7 +373,8 @@ bool timer0_on = false; char callsign[20]; int morse_timing = 60; // ms for a dit int morse_freq = 1800; // Hz -int morse_table[44][6] = { // 0-9, A-Z only by (ASCII - 48) +//int morse_table[44][6] = { // 0-9, A-Z only by (ASCII - 48) +byte morse_table[44][6] = { // 0-9, A-Z only by (ASCII - 48) { 3, 3, 3, 3, 3, 0 }, // 0 { 1, 3, 3, 3, 3, 0 }, // 1 { 1, 1, 3, 3, 3, 0 }, // 2 diff --git a/cubesatsim/cubesatsim.ino b/cubesatsim/cubesatsim.ino index 560e26ac..8084baa4 100644 --- a/cubesatsim/cubesatsim.ino +++ b/cubesatsim/cubesatsim.ino @@ -36,7 +36,7 @@ #include "hardware/sync.h" // wait for interrupt #include "RPi_Pico_ISR_Timer.h" #include "RPi_Pico_TimerInterrupt.h" -#include +//#include #include "hardware/gpio.h" #include "hardware/adc.h" #include "SSTV-Arduino-Scottie1-Library.h" @@ -44,7 +44,7 @@ // jpg files to be stored in flash storage on Pico (FS 512kB setting) #include "sstv1.h" -#include "sstv2.h" +//#include "sstv2.h" Adafruit_INA219 ina219_1_0x40; Adafruit_INA219 ina219_1_0x41(0x41); @@ -55,8 +55,8 @@ Adafruit_INA219 ina219_2_0x41(0x41); Adafruit_INA219 ina219_2_0x44(0x44); Adafruit_INA219 ina219_2_0x45(0x45); -WiFiServer server(port); -WiFiClient client; +//WiFiServer server(port); +//WiFiClient client; //#define PICO_W // define if Pico W board. Otherwise, compilation fail for Pico or runtime fail if compile as Pico W @@ -139,7 +139,9 @@ void setup() { start_button_isr(); setup_sstv(); + camera_detected = start_camera(); + start_isr(); start_pwm(); @@ -198,6 +200,7 @@ void loop() { } else if (mode == SSTV) { + first_time_sstv = false; char image_file[128]; if (first_time_sstv) { // if (false) { // turn this off for now @@ -211,7 +214,7 @@ void loop() { char camera_file[] = "/cam.jpg"; strcpy(image_file, camera_file); } else - strcpy(image_file, sstv2_filename); // 2nd stored image + strcpy(image_file, sstv1_filename); // 2nd stored image } if (debug_mode) { Serial.print("\nSending SSTV image "); @@ -220,14 +223,21 @@ void loop() { // send_sstv("/cam.raw"); // send_sstv(image_file); +// LittleFS.remove("/cam.bin"); + show_dir(); + char output_file2[] = "/cam2.bin"; + jpeg_decode(image_file, output_file2, true); // debug_mode); + show_dir(); + char telem_display[] = " BATT: STATUS: TEMP: "; + char output_file[] = "/cam.bin"; + digitalWrite(PTT_PIN, HIGH); // shouldn't need this but + rotate_image(output_file2, output_file, telem_display); + show_dir(); - char output_file[] = "/cam.bin"; - jpeg_decode(image_file, output_file, debug_mode); - if (debug_mode) Serial.println("Start transmit!!!"); digitalWrite(PTT_PIN, LOW); // start transmit - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, HIGH); digitalWrite(MAIN_LED_BLUE, HIGH); @@ -236,7 +246,7 @@ void loop() { if (debug_mode) Serial.println("Stop transmit!"); digitalWrite(PTT_PIN, HIGH); // stop transmit - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, HIGH); digitalWrite(MAIN_LED_BLUE, LOW); @@ -255,14 +265,14 @@ void loop() { // test_radio(); if ((mode == FSK) || (mode == BPSK)) { - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, LOW); digitalWrite(MAIN_LED_BLUE, LOW); // delay(3000); sleep(0.2); // 2.845); // 3.0); - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, HIGH); digitalWrite(MAIN_LED_BLUE, HIGH); } @@ -303,8 +313,8 @@ bool TimerHandler1(struct repeating_timer *t) { if (BOOTSEL) // boot selector button is pressed on Pico process_bootsel(); - if (wifi) - check_for_browser(); +// if (wifi) +// check_for_browser(); return(true); } @@ -1327,7 +1337,8 @@ void get_tlm_fox() { } } -void write_wave(int i, short int *buffer) +//void write_wave(int i, short int *buffer) +void write_wave(int i, byte *buffer) { if (mode == FSK) { @@ -2631,6 +2642,7 @@ void read_payload() // delay(100); } +/* void payload_OK_only() { payload_str[0] = '\0'; // clear the payload string @@ -2818,7 +2830,8 @@ void payload_OK_only() delay(100); } - + +*/ /* void eeprom_word_write(int addr, int val) { @@ -3147,7 +3160,7 @@ void process_pushbutton() { // return; /// just skip for now - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, HIGH); // make sure built in LED is on before starting to blink sleep(1.0); @@ -3245,7 +3258,7 @@ void process_bootsel() { int release = FALSE; - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, HIGH); // make sure built in LED is on before blinking sleep(1.0); @@ -3340,11 +3353,11 @@ void process_bootsel() { void blinkTimes(int blinks) { for (int i = 0; i < blinks; i++) { digitalWrite(MAIN_LED_GREEN, LOW); - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, LOW); sleep(0.1); digitalWrite(MAIN_LED_GREEN, HIGH); - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, HIGH); sleep(0.1); } @@ -3368,7 +3381,7 @@ void config_gpio() { pinMode(AUDIO_OUT_PIN, OUTPUT); // set LEDs and blink once - if (!wifi) +// if (!wifi) pinMode(LED_BUILTIN, OUTPUT); // Set LED pin to output pinMode(MAIN_LED_GREEN, OUTPUT); // Set Main Green LED pin to output blink_pin(MAIN_LED_GREEN, 150); @@ -3535,7 +3548,8 @@ void start_button_isr() { Serial.println(F("Can't set ITimer1. Select another Timer, freq. or timer")); } - + +/* void client_print_string(char *string) { int count = 0; @@ -3629,13 +3643,13 @@ void check_for_browser() { } } } -/* + Serial.println(" "); print_string(var); print_string(val); Serial.println(" "); Serial.println(strlen(val)); -*/ + if (!strcmp(var, "call") && (strlen(val) > 0)) { Serial.print("Changing callsign to "); print_string(val); @@ -3678,9 +3692,10 @@ void configure_wifi() { server.begin(); } } - +*/ + void transmit_cw(int freq, float duration) { // freq in Hz, duration in milliseconds - if (!wifi) + // if (!wifi) digitalWrite(LED_BUILTIN, HIGH); // Transmit LED on digitalWrite(MAIN_LED_BLUE, HIGH); @@ -3695,7 +3710,7 @@ void transmit_cw(int freq, float duration) { // freq in Hz, duration in millise sleep(min(time_left, period_us) / 1.0E6); } digitalWrite(AUDIO_OUT_PIN, LOW); - if (!wifi) +// if (!wifi) digitalWrite(LED_BUILTIN, LOW); // Transmit LED off digitalWrite(MAIN_LED_BLUE, LOW); } @@ -3831,7 +3846,7 @@ void load_files() { } f.close(); } - +/* f = LittleFS.open("sstv_image_2_320_x_240.jpg", "r"); if (f) { Serial.println("Image sstv_image_2_320_x_240.jpg already in FS"); @@ -3845,7 +3860,7 @@ void load_files() { } f.close(); } - +*/ show_dir(); } @@ -4226,6 +4241,9 @@ void set_lat_lon() { void program_radio() { + digitalWrite(PD_PIN, HIGH); // enable SR_FRS + digitalWrite(PTT_PIN, HIGH); // stop transmit + DumbTXSWS mySerial(SWTX_PIN); // TX pin mySerial.begin(9600); diff --git a/cubesatsim/esp32-cam-send-jpeg-serial/esp32-cam-send-jpeg-serial.ino b/cubesatsim/esp32-cam-send-jpeg-serial/esp32-cam-send-jpeg-serial.ino index 71449d30..fcb62e9d 100644 --- a/cubesatsim/esp32-cam-send-jpeg-serial/esp32-cam-send-jpeg-serial.ino +++ b/cubesatsim/esp32-cam-send-jpeg-serial/esp32-cam-send-jpeg-serial.ino @@ -23,14 +23,91 @@ #include #include "esp_camera.h" #include -#include "FS.h" +//#include "FS.h" #include "SPIFFS.h" +#include // 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); @@ -49,6 +126,11 @@ 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 // @@ -96,9 +178,11 @@ void setup() { delay(5000); - Serial.begin(112500); + Serial.begin(115200); initialize_camera(); + + config_camera(); Serial.println("ESP32-CAM Camera initialized"); @@ -234,9 +318,22 @@ static esp_err_t init_camera() // 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!"); @@ -461,3 +558,724 @@ void send_image_serial(char *filename) } 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> 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 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(); +}