diff --git a/nanovna.h b/nanovna.h index e5f0839..198abe1 100644 --- a/nanovna.h +++ b/nanovna.h @@ -1580,8 +1580,6 @@ void SD_PowerOff(void); #define fs_volume (FATFS *)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS)) // FatFS file object (at the end of spi_buffer) #define fs_file ( FIL*)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS) - sizeof(FIL)) -// Filename object (at the end of spi_buffer) -#define fs_filename ( char*)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS) - sizeof(FIL) - FF_LFN_BUF - 4) #endif void testLog(void); // debug log void sd_card_load_config(char *filename); diff --git a/ui.c b/ui.c index d595e7c..78e0b40 100644 --- a/ui.c +++ b/ui.c @@ -86,6 +86,8 @@ static char *kp_help_text = NULL; static uint8_t menu_current_level = 0; static int selection = 0; +static void save_csv(uint8_t mask); + static const uint8_t slider_bitmap[]= { _BMP8(0b11111110), @@ -2825,7 +2827,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_traces_acb) #ifdef TINYSA4 case 6: - save_to_sd(1+(2<>0)&0xFF, ((val)>>8)&0xFF, ((val)>>16)&0xFF, ((val)>>24)&0xFF +#define BMP_UINT16(val) ((val)>>0)&0xFF, ((val)>>8)&0xFF #define BMP_H1_SIZE (14) // BMP header 14 bytes -#define BMP_V4_SIZE (56) // v4 header 56 bytes +#define BMP_V4_SIZE (108) // v4 header 108 bytes #define BMP_HEAD_SIZE (BMP_H1_SIZE + BMP_V4_SIZE) // Size of all headers #define BMP_SIZE (2*LCD_WIDTH*LCD_HEIGHT) // Bitmap size = 2*w*h #define BMP_FILE_SIZE (BMP_SIZE + BMP_HEAD_SIZE) // File size = headers + bitmap -static const uint8_t bmp_header_v4[14+56] = { +static const uint8_t bmp_header_v4[BMP_H1_SIZE + BMP_V4_SIZE] = { // BITMAPFILEHEADER (14 byte size) 0x42, 0x4D, // BM signature BMP_UINT32(BMP_FILE_SIZE), // File size (h + v4 + bitmap) - 0x00, 0x00, // reserved - 0x00, 0x00, // reserved + BMP_UINT16(0), // reserved + BMP_UINT16(0), // reserved BMP_UINT32(BMP_HEAD_SIZE), // Size of all headers (h + v4) -// BITMAPINFOv4 (56 byte size) +// BITMAPINFOv4 (108 byte size) BMP_UINT32(BMP_V4_SIZE), // Data offset after this point (v4 size) BMP_UINT32(LCD_WIDTH), // Width BMP_UINT32(LCD_HEIGHT), // Height - 0x01, 0x00, // Planes - 0x10, 0x00, // 16bpp - 0x03, 0x00, 0x00, 0x00, // Compression (BI_BITFIELDS) + BMP_UINT16(1), // Planes + BMP_UINT16(16), // 16bpp + BMP_UINT32(3), // Compression (BI_BITFIELDS) BMP_UINT32(BMP_SIZE), // Bitmap size (w*h*2) - 0xC4, 0x0E, 0x00, 0x00, // x Resolution (96 DPI = 96 * 39.3701 inches per metre = 0x0EC4) - 0xC4, 0x0E, 0x00, 0x00, // y Resolution (96 DPI = 96 * 39.3701 inches per metre = 0x0EC4) - 0x00, 0x00, 0x00, 0x00, // Palette size - 0x00, 0x00, 0x00, 0x00, // Palette used + BMP_UINT32(0x0EC4), // x Resolution (96 DPI = 96 * 39.3701 inches per meter = 0x0EC4) + BMP_UINT32(0x0EC4), // y Resolution (96 DPI = 96 * 39.3701 inches per meter = 0x0EC4) + BMP_UINT32(0), // Palette size + BMP_UINT32(0), // Palette used // Extend v4 header data (color mask for RGB565) - 0x00, 0xF8, 0x00, 0x00, // R mask = 0b11111000 00000000 - 0xE0, 0x07, 0x00, 0x00, // G mask = 0b00000111 11100000 - 0x1F, 0x00, 0x00, 0x00, // B mask = 0b00000000 00011111 - 0x00, 0x00, 0x00, 0x00 // A mask = 0b00000000 00000000 + BMP_UINT32(0b1111100000000000),// R mask = 0b11111000 00000000 + BMP_UINT32(0b0000011111100000),// G mask = 0b00000111 11100000 + BMP_UINT32(0b0000000000011111),// B mask = 0b00000000 00011111 + BMP_UINT32(0b0000000000000000),// A mask = 0b00000000 00000000 + 'B','G','R','s', // CSType = 'sRGB' + BMP_UINT32(0), // ciexyzRed.ciexyzX Endpoints + BMP_UINT32(0), // ciexyzRed.ciexyzY + BMP_UINT32(0), // ciexyzRed.ciexyzZ + BMP_UINT32(0), // ciexyzGreen.ciexyzX + BMP_UINT32(0), // ciexyzGreen.ciexyzY + BMP_UINT32(0), // ciexyzGreen.ciexyzZ + BMP_UINT32(0), // ciexyzBlue.ciexyzX + BMP_UINT32(0), // ciexyzBlue.ciexyzY + BMP_UINT32(0), // ciexyzBlue.ciexyzZ + BMP_UINT32(0), // GammaRed + BMP_UINT32(0), // GammaGreen + BMP_UINT32(0), // GammaBlue }; -FRESULT open_file(char *ext) +static void swap_bytes(uint16_t *buf, int size) { + for (int i = 0; i < size; i++) + buf[i] = __REVSH(buf[i]); // swap byte order (example 0x10FF to 0xFF10) +} + +// Create file name from current time +static FRESULT sa_create_file(char *fs_filename) { -#ifdef __DISABLE_HOT_INSERT__ - if (!sd_card_inserted_at_boot) { - drawMessageBox("Warning:", "Restart tinySA to use SD card", 2000); - return FR_NOT_READY; - } -#endif +// shell_printf("S file\r\n"); FRESULT res = f_mount(fs_volume, "", 1); - // fs_volume, fs_file and fs_filename stored at end of spi_buffer!!!!! // shell_printf("Mount = %d\r\n", res); if (res != FR_OK) return res; -#if FF_USE_LFN >= 1 - uint32_t tr = rtc_get_tr_bcd(); // TR read first - uint32_t dr = rtc_get_dr_bcd(); // DR read second - plot_printf(fs_filename, FF_LFN_BUF, "SA_%06x_%06x.%s", dr, tr, ext); -#else - plot_printf(fs_filename, FF_LFN_BUF, "%08x.%s", rtc_get_FAT(), ext); -#endif res = f_open(fs_file, fs_filename, FA_CREATE_ALWAYS | FA_READ | FA_WRITE); - return res; +// shell_printf("Open %s, = %d\r\n", fs_filename, res); + return res; } -void close_file(FRESULT res) -{ - if (res == FR_OK) - res = f_close(fs_file); -// time = chVTGetSystemTimeX() - time; -// shell_printf("Total time: %dms (write %d byte/sec)\r\n", time/10, (LCD_WIDTH*LCD_HEIGHT*sizeof(uint16_t)+sizeof(bmp_header_v4))*10000/time); - drawMessageBox("Save:", res == FR_OK ? fs_filename : " Write failed ", 2000); - redraw_request|= REDRAW_AREA; -} -static bool -made_screenshot(int touch_x, int touch_y) -{ - int y, i; +static void sa_save_file(char *name, uint8_t format) { + uint16_t *buf_16; + int i, y; UINT size; - if (touch_y < SD_CARD_START || touch_y > SD_CARD_START + 20 || touch_x > OFFSETX) - return FALSE; - ili9341_set_background(LCD_BG_COLOR); - ili9341_fill(4, SD_CARD_START, 16, 16); - touch_wait_release(); + char fs_filename[FF_LFN_BUF]; #ifdef __DISABLE_HOT_INSERT__ if (!sd_card_inserted_at_boot) { drawMessageBox("Warning:", "Restart tinySA to use SD card", 2000); - return FALSE; + return; } #endif -// uint32_t time = chVTGetSystemTimeX(); -// shell_printf("Screenshot\r\n"); - FRESULT res = open_file("bmp"); - uint16_t *buf = (uint16_t *)spi_buffer; -// shell_printf("Open %s, result = %d\r\n", fs_filename, res); - if (res == FR_OK){ - res = f_write(fs_file, bmp_header_v4, sizeof(bmp_header_v4), &size); - for (y = LCD_HEIGHT-1; y >= 0 && res == FR_OK; y--) { - ili9341_read_memory(0, y, LCD_WIDTH, 1, buf); - for (i = 0; i < LCD_WIDTH; i++) - buf[i] = __REVSH(buf[i]); // swap byte order (example 0x10FF to 0xFF10) - res = f_write(fs_file, buf, LCD_WIDTH*sizeof(uint16_t), &size); - } -// res = f_close(fs_file); -// shell_printf("Close %d\r\n", res); -// testLog(); + // For screenshot need back to normal mode and redraw screen before capture!! + // Redraw use spi_buffer so need do it before any file ops + if (format == FMT_BMP_FILE && ui_mode != UI_NORMAL){ + ui_mode_normal(); + draw_all(false); } - close_file(res); - return TRUE; -} -void save_to_sd(int mask) -{ - FRESULT res = open_file("csv"); - UINT size; + // Prepare filename and open for write + if (name == NULL) { // Auto name, use date / time +#if FF_USE_LFN >= 1 + uint32_t tr = rtc_get_tr_bcd(); // TR read first + uint32_t dr = rtc_get_dr_bcd(); // DR read second + plot_printf(fs_filename, FF_LFN_BUF, "SA_%06x_%06x.%s", dr, tr, file_ext[format]); +#else + plot_printf(fs_filename, FF_LFN_BUF, "%08x.%s", rtc_get_FAT(), file_ext[format]); +#endif + } + else + plot_printf(fs_filename, FF_LFN_BUF, "%s.%s", name, file_ext[format]); + +// UINT total_size = 0; +// systime_t time = chVTGetSystemTimeX(); + // Prepare filename = .bmp / .csv and open for write + FRESULT res = sa_create_file(fs_filename); if (res == FR_OK) { - for (int i = 0; i < sweep_points; i++) { - char *buf = (char *)spi_buffer; - if (mask & 1) buf += plot_printf(buf, 100, "%U, ", getFrequency(i)); - if (mask & 2) buf += plot_printf(buf, 100, "%f ", value(measured[TRACE_ACTUAL][i])); - if (mask & 4) buf += plot_printf(buf, 100, "%f ", value(measured[TRACE_STORED][i])); - if (mask & 8) buf += plot_printf(buf, 100, "%f", value(measured[TRACE_TEMP][i])); - buf += plot_printf(buf, 100, "\r\n"); - res = f_write(fs_file, (char *)spi_buffer, buf - (char *)spi_buffer, &size); - if (res != FR_OK) - break; + switch(format) { + /* + * Save bitmap file (use v4 format allow set RGB mask) + */ + case FMT_BMP_FILE: + buf_16 = spi_buffer; + res = f_write(fs_file, bmp_header_v4, BMP_HEAD_SIZE, &size); // Write header struct +// total_size+=size; + ili9341_set_background(LCD_SWEEP_LINE_COLOR); + for (y = LCD_HEIGHT-1; y >= 0 && res == FR_OK; y--) { + ili9341_read_memory(0, y, LCD_WIDTH, 1, buf_16); + swap_bytes(buf_16, LCD_WIDTH); + res = f_write(fs_file, buf_16, LCD_WIDTH*sizeof(uint16_t), &size); +// total_size+=size; + ili9341_fill(LCD_WIDTH-1, y, 1, 1); + } + break; + case FMT_CSV_FILE: + for (i = 0; i < sweep_points && res == FR_OK; i++) { + char *buf = (char *)spi_buffer; + if (file_mask & 1) buf += plot_printf(buf, 100, "%U, ", getFrequency(i)); + if (file_mask & 2) buf += plot_printf(buf, 100, "%f ", value(measured[TRACE_ACTUAL][i])); + if (file_mask & 4) buf += plot_printf(buf, 100, "%f ", value(measured[TRACE_STORED][i])); + if (file_mask & 8) buf += plot_printf(buf, 100, "%f", value(measured[TRACE_TEMP][i])); + buf += plot_printf(buf, 100, "\r\n"); + res = f_write(fs_file, (char *)spi_buffer, buf - (char *)spi_buffer, &size); + } + break; +//#ifdef __SD_CARD_DUMP_FIRMWARE__ +// /* +// * Dump firmware to SD card as bin file image +// */ +// case FMT_BIN_FILE: +// { +// const char *src = (const char*)FLASH_START_ADDRESS; +// const uint32_t total = FLASH_TOTAL_SIZE; +// res = f_write(fs_file, src, total, &size); +// } +// break; +//#endif } + f_close(fs_file); +// shell_printf("Close = %d\r\n", res); +// testLog(); +// time = chVTGetSystemTimeX() - time; +// shell_printf("Total time: %dms (write %d byte/sec)\r\n", time/10, total_size*10000/time); } - close_file(res); + + drawMessageBox("SD CARD SAVE", res == FR_OK ? fs_filename : " Fail write ", 2000); + redraw_request|= REDRAW_AREA|REDRAW_FREQUENCY; + ui_mode_normal(); +} + +static UI_FUNCTION_CALLBACK(menu_sdcard_cb) { + (void)item; + sa_save_file(0, data); +} + +static void save_csv(uint8_t mask) { + file_mask = mask; + menu_sdcard_cb(0, FMT_CSV_FILE); } +static bool +made_screenshot(int touch_x, int touch_y) { + if (touch_y < SD_CARD_START || touch_y > SD_CARD_START + 20 || touch_x > OFFSETX) + return FALSE; + ili9341_set_background(LCD_BG_COLOR); + ili9341_fill(4, SD_CARD_START, 16, 16); + touch_wait_release(); + menu_sdcard_cb(0, FMT_BMP_FILE); + return TRUE; +} #endif static int