diff --git a/radio/src/gui/Taranis/menu_general_sdmanager.cpp b/radio/src/gui/Taranis/menu_general_sdmanager.cpp index a26884c74..8b327ed63 100755 --- a/radio/src/gui/Taranis/menu_general_sdmanager.cpp +++ b/radio/src/gui/Taranis/menu_general_sdmanager.cpp @@ -116,39 +116,54 @@ void onSdManagerMenu(const char *result) { TCHAR lfn[_MAX_LFN+1]; + // TODO possible buffer overflows here! + uint8_t index = m_posVert-1-s_pgOfs; + char *line = reusableBuffer.sdmanager.lines[index]; + if (result == STR_SD_INFO) { pushMenu(menuGeneralSdManagerInfo); } else if (result == STR_SD_FORMAT) { POPUP_CONFIRMATION(STR_CONFIRM_FORMAT); } + else if (result == STR_COPY_FILE) { + clipboard.type = CLIPBOARD_TYPE_SD_FILE; + f_getcwd(clipboard.data.sd.directory, CLIPBOARD_PATH_LEN); + strncpy(clipboard.data.sd.filename, line, CLIPBOARD_PATH_LEN-1); + } + else if (result == STR_PASTE) { + f_getcwd(lfn, _MAX_LFN); + POPUP_WARNING(fileCopy(clipboard.data.sd.filename, clipboard.data.sd.directory, lfn)); + reusableBuffer.sdmanager.offset = -1; + } else if (result == STR_DELETE_FILE) { f_getcwd(lfn, _MAX_LFN); - strcat_P(lfn, PSTR("/")); - strcat(lfn, reusableBuffer.sdmanager.lines[index]); + strcat(lfn, PSTR("/")); + strcat(lfn, line); f_unlink(lfn); - strncpy(statusLineMsg, reusableBuffer.sdmanager.lines[index], 13); + strncpy(statusLineMsg, line, 13); strcpy_P(statusLineMsg+min((uint8_t)strlen(statusLineMsg), (uint8_t)13), STR_REMOVED); showStatusLine(); - if ((uint16_t)m_posVert == reusableBuffer.sdmanager.count) m_posVert--; - reusableBuffer.sdmanager.offset = s_pgOfs-1; + reusableBuffer.sdmanager.offset = -1; + if (m_posVert == reusableBuffer.sdmanager.count) + m_posVert--; } /* TODO else if (result == STR_LOAD_FILE) { f_getcwd(lfn, _MAX_LFN); strcat(lfn, "/"); - strcat(lfn, reusableBuffer.sdmanager.lines[index]); + strcat(lfn, line); POPUP_WARNING(eeLoadModelSD(lfn)); } */ else if (result == STR_PLAY_FILE) { f_getcwd(lfn, _MAX_LFN); strcat(lfn, "/"); - strcat(lfn, reusableBuffer.sdmanager.lines[index]); + strcat(lfn, line); audioQueue.stopAll(); audioQueue.playFile(lfn, 0, ID_PLAY_FROM_SD_MANAGER); } else if (result == STR_ASSIGN_BITMAP) { - strAppendFilename(g_model.header.bitmap, reusableBuffer.sdmanager.lines[index], sizeof(g_model.header.bitmap)); + strAppendFilename(g_model.header.bitmap, line, sizeof(g_model.header.bitmap)); LOAD_MODEL_BITMAP(); memcpy(modelHeaders[g_eeGeneral.currModel].bitmap, g_model.header.bitmap, sizeof(g_model.header.bitmap)); eeDirty(EE_MODEL); @@ -156,20 +171,20 @@ void onSdManagerMenu(const char *result) else if (result == STR_VIEW_TEXT) { f_getcwd(lfn, _MAX_LFN); strcat(lfn, "/"); - strcat(lfn, reusableBuffer.sdmanager.lines[index]); + strcat(lfn, line); pushMenuTextView(lfn); } else if (result == STR_FLASH_BOOTLOADER) { f_getcwd(lfn, _MAX_LFN); strcat(lfn, "/"); - strcat(lfn, reusableBuffer.sdmanager.lines[index]); + strcat(lfn, line); flashBootloader(lfn); } #if defined(LUA) else if (result == STR_EXECUTE_FILE) { f_getcwd(lfn, _MAX_LFN); strcat(lfn, "/"); - strcat(lfn, reusableBuffer.sdmanager.lines[index]); + strcat(lfn, line); luaExec(lfn); } #endif @@ -242,9 +257,9 @@ void menuGeneralSdManager(uint8_t _event) { uint8_t index = m_posVert-1-s_pgOfs; // TODO duplicated code for finding extension - char * ext = reusableBuffer.sdmanager.lines[index]; - int len = strlen(ext) - 4; - ext += len; + char *line = reusableBuffer.sdmanager.lines[index]; + int len = strlen(line) - 4; + char *ext = line+len; /* TODO if (!strcasecmp(ext, MODELS_EXT)) { s_menu[s_menu_count++] = STR_LOAD_FILE; } @@ -266,9 +281,12 @@ void menuGeneralSdManager(uint8_t _event) } #endif if (!READ_ONLY()) { - MENU_ADD_ITEM(STR_DELETE_FILE); + if (line[SD_SCREEN_FILE_LENGTH+1]) // it's a file + MENU_ADD_ITEM(STR_COPY_FILE); + if (clipboard.type == CLIPBOARD_TYPE_SD_FILE) + MENU_ADD_ITEM(STR_PASTE); // MENU_ADD_ITEM(STR_RENAME_FILE); TODO: Implement - // MENU_ADD_ITEM(STR_COPY_FILE); TODO: Implement + MENU_ADD_ITEM(STR_DELETE_FILE); } } menuHandler = onSdManagerMenu; diff --git a/radio/src/gui/Taranis/menu_model_logical_switches.cpp b/radio/src/gui/Taranis/menu_model_logical_switches.cpp index e66644e5d..256557a2d 100755 --- a/radio/src/gui/Taranis/menu_model_logical_switches.cpp +++ b/radio/src/gui/Taranis/menu_model_logical_switches.cpp @@ -73,22 +73,6 @@ void putsEdgeDelayParam(coord_t x, coord_t y, LogicalSwitchData *cs, uint8_t lat lcd_putc(lcdLastPos, y, ']'); } -enum ClipboardType { - CLIPBOARD_TYPE_NONE, - CLIPBOARD_TYPE_CUSTOM_SWITCH, - CLIPBOARD_TYPE_CUSTOM_FUNCTION, -}; - -struct Clipboard { - ClipboardType type; - union { - LogicalSwitchData csw; - CustomFunctionData cfn; - } data; -}; - -Clipboard clipboard; - void onLogicalSwitchesMenu(const char *result) { int8_t sub = m_posVert-1; diff --git a/radio/src/gui/Taranis/menus.cpp b/radio/src/gui/Taranis/menus.cpp index 2f5e0c059..34b501811 100755 --- a/radio/src/gui/Taranis/menus.cpp +++ b/radio/src/gui/Taranis/menus.cpp @@ -83,3 +83,5 @@ void pushModelNotes() strcpy(buf, TEXT_EXT); pushMenuTextView(filename); } + +Clipboard clipboard; diff --git a/radio/src/gui/Taranis/menus.h b/radio/src/gui/Taranis/menus.h index 38240260e..ea1055a02 100755 --- a/radio/src/gui/Taranis/menus.h +++ b/radio/src/gui/Taranis/menus.h @@ -375,4 +375,31 @@ void menuChannelsView(uint8_t event); typedef int16_t (*FnFuncP) (int16_t x); void DrawFunction(FnFuncP fn, uint8_t offset=0); +enum ClipboardType { + CLIPBOARD_TYPE_NONE, + CLIPBOARD_TYPE_CUSTOM_SWITCH, + CLIPBOARD_TYPE_CUSTOM_FUNCTION, + CLIPBOARD_TYPE_SD_FILE, +}; + +#if defined(SIMU) + #define CLIPBOARD_PATH_LEN 1024 +#else + #define CLIPBOARD_PATH_LEN 32 +#endif + +struct Clipboard { + ClipboardType type; + union { + LogicalSwitchData csw; + CustomFunctionData cfn; + struct { + char directory[CLIPBOARD_PATH_LEN]; + char filename[CLIPBOARD_PATH_LEN]; + } sd; + } data; +}; + +extern Clipboard clipboard; + #endif // _MENUS_H_ diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 868fc29b3..0b2b208dd 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1509,6 +1509,7 @@ extern uint8_t requiredSpeakerVolume; #define SD_SCREEN_FILE_LENGTH (32) union ReusableBuffer { + // 263 bytes on Taranis struct { char listnames[LCD_LINES-1][LEN_MODEL_NAME]; @@ -1522,6 +1523,7 @@ union ReusableBuffer } modelsel; + // 103 bytes on Taranis struct { int16_t midVals[NUM_STICKS+NUM_POTS]; @@ -1539,6 +1541,7 @@ union ReusableBuffer } calib; #if defined(SDCARD) + // 246 bytes on Taranis struct { char lines[LCD_LINES-1][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line diff --git a/radio/src/sdcard.cpp b/radio/src/sdcard.cpp index e8bb710cb..dc20e13d1 100644 --- a/radio/src/sdcard.cpp +++ b/radio/src/sdcard.cpp @@ -141,3 +141,47 @@ bool listSdFiles(const char *path, const char *extension, const uint8_t maxlen, return s_menu_count; } + +const char *fileCopy(const char *filename, const char *srcDir, const char *destDir) +{ + FIL srcFile; + FIL dstFile; + char buf[256]; + UINT read = sizeof(buf); + UINT written = sizeof(buf); + + char path[2*CLIPBOARD_PATH_LEN+1]; + char *tmp = strAppend(path, srcDir, CLIPBOARD_PATH_LEN); + *tmp++ = '/'; + strAppend(tmp, filename, CLIPBOARD_PATH_LEN); + + FRESULT result = f_open(&srcFile, path, FA_OPEN_EXISTING | FA_READ); + if (result != FR_OK) { + return SDCARD_ERROR(result); + } + + tmp = strAppend(path, destDir, CLIPBOARD_PATH_LEN); + *tmp++ = '/'; + strAppend(tmp, filename, CLIPBOARD_PATH_LEN); + + result = f_open(&dstFile, path, FA_CREATE_ALWAYS | FA_WRITE); + if (result != FR_OK) { + return SDCARD_ERROR(result); + } + + while (result==FR_OK && read==sizeof(buf) && written==sizeof(buf)) { + result = f_read(&srcFile, buf, sizeof(buf), &read); + if (result == FR_OK) { + result = f_write(&dstFile, buf, read, &written); + } + } + + f_close(&dstFile); + f_close(&srcFile); + + if (result != FR_OK) { + return SDCARD_ERROR(result); + } + + return NULL; +} diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 9a31be9c9..efe91da54 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -34,8 +34,8 @@ * */ -#ifndef sdcard_h -#define sdcard_h +#ifndef _SDCARD_H_ +#define _SDCARD_H_ #include "FatFs/ff.h" @@ -68,10 +68,10 @@ extern FATFS g_FATFS_Obj; extern uint8_t logDelay; -extern const pm_char * openLogs(); +const pm_char *openLogs(); void writeHeader(); -extern void closeLogs(); -extern void writeLogs(); +void closeLogs(); +void writeLogs(); #if !defined(BOOT) inline const pm_char *SDCARD_ERROR(FRESULT result) @@ -91,5 +91,7 @@ inline const pm_char *SDCARD_ERROR(FRESULT result) #define O9X_FOURCC 0x3178396F // o9x for gruvin9x/MEGA2560 #endif +const char *fileCopy(const char *filename, const char *srcDir, const char *destDir); + #endif diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 338324fa0..87208ecd7 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -552,7 +552,10 @@ FRESULT f_read (FIL* fil, void* data, UINT size, UINT* read) FRESULT f_write (FIL* fil, const void* data, UINT size, UINT* written) { - if (fil && fil->fs) *written = fwrite(data, 1, size, (FILE*)fil->fs); + if (fil && fil->fs) { + *written = fwrite(data, 1, size, (FILE*)fil->fs); + // TRACE("fwrite(%p) %u, %u", fil->fs, size, *written); + } return FR_OK; }