952 lines
27 KiB
C
952 lines
27 KiB
C
/**
|
|
******************************************************************************
|
|
* @file ff_shell.c
|
|
* @author AMG Energy Solution Team
|
|
* @version V1.0.0
|
|
* @date 07-Feb-2022
|
|
* @brief This file provides all the headers of the fatfs shell functions.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
|
*
|
|
* <h2><center>© COPYRIGHT 2022 AMG</center></h2>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/** @addtogroup mBMS2
|
|
* @{
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <includes.h>
|
|
#include "ff.h"
|
|
#include "ff_shell.h"
|
|
#include "brtc.h"
|
|
#include "date_calc.h"
|
|
#include "xprintf.h"
|
|
#include "diskio.h"
|
|
#include "usart.h"
|
|
#include "exfuns.h"
|
|
#include "malloc.h"
|
|
#include "delay.h"
|
|
//#include "boot_update.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
#define FBUFF_MAX 4096
|
|
#define CLINE_MAX 256
|
|
#define WORK_SPACE_MAX 1024
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
DWORD AccSize; /* Work register for fs command */
|
|
WORD AccFiles, AccDirs;
|
|
FILINFO Finfo;
|
|
|
|
BYTE *fBuff;
|
|
char *cLine;
|
|
BYTE *work_space;
|
|
|
|
FATFS FatFs; /* File system object for each logical drive */
|
|
FIL File[2]; /* File objects */
|
|
DIR Dir; /* Directory object */
|
|
|
|
volatile UINT Timer;
|
|
|
|
uint8_t sem_file_used = 0;
|
|
uint32_t sem_file_time = 0;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* Private functions ---------------------------------------------------------*/
|
|
void ff_init(void)
|
|
{
|
|
FRESULT rc;
|
|
|
|
work_space = mymalloc(WORK_SPACE_MAX); // Allocate memory for the fatfs file system
|
|
|
|
/* Mount the file system */
|
|
rc = f_mount(&FatFs, "0:", 1); //Mount FLASH
|
|
|
|
if (rc == FR_NO_FILESYSTEM)
|
|
{
|
|
#ifdef CONSOLE_DEBUG
|
|
printf("f_mount = %d\r\n", rc);
|
|
#endif /* CONSOLE_DEBUG */
|
|
put_rc(f_mkfs("0:", 1, 512, work_space, 1024));
|
|
}
|
|
}
|
|
|
|
unsigned char ReqUseFatfs(void)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
if (sem_file_used == 0)
|
|
{
|
|
CPU_CRITICAL_ENTER();
|
|
sem_file_used = 1;
|
|
sem_file_time = 5000;
|
|
CPU_CRITICAL_EXIT();
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
unsigned char ReqUseFatfsWhile(void)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
while (sem_file_used)
|
|
{
|
|
delay_os_ms(5);
|
|
}
|
|
CPU_CRITICAL_ENTER();
|
|
sem_file_used = 1;
|
|
sem_file_time = 5000;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
return 1;
|
|
}
|
|
|
|
void leaveFatfs(void)
|
|
{
|
|
sem_file_used = 0;
|
|
}
|
|
|
|
void UpdateFatfsSemTime(void)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
sem_file_time = 5000;
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
|
|
void CheckTimeOutFatfsSem(void)
|
|
{
|
|
if (sem_file_used == 1)
|
|
{
|
|
if (sem_file_time == 0)
|
|
sem_file_used = false;
|
|
}
|
|
}
|
|
|
|
void DecFatfsSemTime(uint32_t tick)
|
|
{
|
|
if (sem_file_time > tick)
|
|
sem_file_time -= tick;
|
|
}
|
|
|
|
int FileOpen(char *filename, int mode)
|
|
{
|
|
FRESULT rc;
|
|
|
|
rc = f_open(&File[0], filename, mode);
|
|
|
|
return (int)rc;
|
|
}
|
|
|
|
int FileClose(void)
|
|
{
|
|
return (int)f_close(&File[0]);
|
|
}
|
|
|
|
/*---------------------------------------------------------*/
|
|
/* User provided RTC function for FatFs module */
|
|
/*---------------------------------------------------------*/
|
|
/* This is a real time clock service to be called back */
|
|
/* from FatFs module. */
|
|
|
|
#if !_FS_NORTC && !_FS_READONLY
|
|
//Access time
|
|
//User defined function to give a current time to fatfs module */
|
|
//31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
|
|
//15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
|
|
DWORD get_fattime (void)
|
|
{
|
|
/* Pack date and time into a DWORD variable */
|
|
return ((DWORD)(GetTimeYear() - 1980) << 25)
|
|
| ((DWORD)GetTimeMonth() << 21)
|
|
| ((DWORD)GetTimeDate() << 16)
|
|
| ((DWORD)GetTimeHour() << 11)
|
|
| ((DWORD)GetTimeMinute() << 5)
|
|
| ((DWORD)GetTimeSec() >> 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* Monitor */
|
|
/*--------------------------------------------------------------------------*/
|
|
void put_rc (FRESULT rc)
|
|
{
|
|
#ifdef CONSOLE_DEBUG
|
|
const char *str =
|
|
"OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
|
|
"INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0"
|
|
"INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
|
|
"LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0";
|
|
BYTE i;
|
|
|
|
for (i = 0; i != (BYTE)rc && *str; i++) {
|
|
while (*str++) ;
|
|
}
|
|
printf("rc=%u FR_%s\r\n", (UINT)rc, str);
|
|
#endif /* CONSOLE_DEBUG */
|
|
}
|
|
|
|
#ifdef CONSOLE_DEBUG
|
|
|
|
static
|
|
FRESULT scan_files (
|
|
char* path /* Pointer to the path name working buffer */
|
|
)
|
|
{
|
|
DIR dirs;
|
|
FRESULT res;
|
|
BYTE i;
|
|
char *fn;
|
|
|
|
if ((res = f_opendir(&dirs, path)) == FR_OK)
|
|
{
|
|
i = strlen(path);
|
|
while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0])
|
|
{
|
|
if (_FS_RPATH && Finfo.fname[0] == '.') continue;
|
|
|
|
fn = Finfo.fname;
|
|
|
|
if (Finfo.fattrib & AM_DIR)
|
|
{
|
|
AccDirs++;
|
|
*(path+i) = '/'; strcpy(path+i+1, fn);
|
|
res = scan_files(path);
|
|
*(path+i) = '\0';
|
|
if (res != FR_OK) break;
|
|
}
|
|
else
|
|
{
|
|
/* printf("%s/%s\r\n", path, fn); */
|
|
AccFiles++;
|
|
AccSize += Finfo.fsize;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static
|
|
const char HelpMsg[] =
|
|
"[Disk contorls]\r\n"
|
|
" di <pd#> - Initialize disk\r\n"
|
|
" dd [<pd#> <lba>] - Dump a secrtor\r\n"
|
|
" ds <pd#> - Show disk status\r\n"
|
|
"[Buffer controls]\r\n"
|
|
" bd <ofs> - Dump working buffer\r\n"
|
|
" be <ofs> [<data>] ... - Edit working buffer\r\n"
|
|
" br <pd#> <lba> [<count>] - Read disk into working buffer\r\n"
|
|
" bw <pd#> <lba> [<count>] - Write working buffer into disk\r\n"
|
|
" bf <val> - Fill working buffer\r\n"
|
|
"[File system controls]\r\n"
|
|
" fi <ld#> [<mount>]- Force initialized the volume\r\n"
|
|
" fs [<path>] - Show volume status\r\n"
|
|
" fl [<path>] - Show a directory\r\n"
|
|
" fo <mode> <file> - Open a file\r\n"
|
|
" fc - Close the file\r\n"
|
|
" fe <ofs> - Move fp in normal seek\r\n"
|
|
" fd <len> - Read and dump the file\r\n"
|
|
" fr <len> - Read the file\r\n"
|
|
" fw <len> <val> - Write to the file\r\n"
|
|
" fn <org.name> <new.name> - Rename an object\r\n"
|
|
" fu <name> - Unlink an object\r\n"
|
|
" fv - Truncate the file at current fp\r\n"
|
|
" fk <name> - Create a directory\r\n"
|
|
" fa <atrr> <mask> <object name> - Change attribute of an object\r\n"
|
|
" ft <year> <month> <day> <hour> <min> <sec> <name> - Change timestamp of an object\r\n"
|
|
" fx <src.file> <dst.file> - Copy a file\r\n"
|
|
" fg <path> - Change current directory\r\n"
|
|
" fq - Show current directory\r\n"
|
|
" fb <name> - Set volume label\r\n"
|
|
" fm <ld#> <rule> <csize> - Create file system\r\n"
|
|
" fz [<len>] - Change/Show R/W length for fr/fw/fx command\r\n"
|
|
"[Misc commands]\r\n"
|
|
" md[b|h|w] <addr> [<count>] - Dump memory\r\n"
|
|
" mf <addr> <value> <count> - Fill memory\r\n"
|
|
" me[b|h|w] <addr> [<value> ...] - Edit memory\r\n"
|
|
" t [<year> <mon> <mday> <hour> <min> <sec>] - Set/Show RTC\r\n"
|
|
"\r\n";
|
|
|
|
void ff_process(void)
|
|
{
|
|
char *ptr, *ptr2;
|
|
long p1, p2, p3;
|
|
BYTE res, b, drv = 0;
|
|
// UINT s1, s2, cnt, blen = sizeof Buff;
|
|
UINT s1, s2, cnt, blen = FBUFF_MAX;
|
|
static const BYTE ft[] = {0, 12, 16, 32};
|
|
// static const char days[] = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
|
|
DWORD ofs = 0, sect = 0, blk[2];
|
|
FATFS *fs;
|
|
|
|
printf("\r\nFile system monitor\r\n");
|
|
printf(_USE_LFN ? "LFN Enabled" : "LFN Disabled");
|
|
printf(", Code page: %u\r\n", _CODE_PAGE);
|
|
|
|
/* Initiazlize RTC */
|
|
printf("Current time is %u/%u/%u %2u:%02u:%02u.\r\n",
|
|
GetTimeYear(),
|
|
GetTimeMonth(),
|
|
GetTimeDate(),
|
|
GetTimeHour(),
|
|
GetTimeMinute(),
|
|
GetTimeSec()
|
|
);
|
|
|
|
fBuff = mymalloc(blen);
|
|
cLine = mymalloc(CLINE_MAX);
|
|
|
|
if ((fBuff == NULL)||(cLine == NULL))
|
|
{
|
|
printf("FATFS MEM Error. \r\n");
|
|
return;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
if (f_getcwd(cLine, CLINE_MAX) == FR_OK)
|
|
printf("%s>", cLine);
|
|
else
|
|
printf(">");
|
|
|
|
xgets(cLine, CLINE_MAX);
|
|
|
|
ptr = cLine;
|
|
switch (*ptr++)
|
|
{
|
|
case 'q':
|
|
myfree(fBuff);
|
|
myfree(cLine);
|
|
return;
|
|
case '?' : /* Show Command List */
|
|
printf(HelpMsg);
|
|
xputs(HelpMsg);
|
|
break;
|
|
case 'l':
|
|
switch (*ptr++)
|
|
{
|
|
case 's':
|
|
while (*ptr == ' ') ptr++;
|
|
res = f_opendir(&Dir, ptr);
|
|
if (res) { put_rc((FRESULT)res); break; }
|
|
p1 = s1 = s2 = 0;
|
|
|
|
for(;;)
|
|
{
|
|
res = f_readdir(&Dir, &Finfo);
|
|
if ((res != FR_OK) || !Finfo.fname[0]) break;
|
|
if (Finfo.fattrib & AM_DIR)
|
|
{
|
|
s2++;
|
|
}
|
|
else
|
|
{
|
|
s1++; p1 += Finfo.fsize;
|
|
}
|
|
printf("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %-12s %s\r\n",
|
|
(Finfo.fattrib & AM_DIR) ? 'D' : '-',
|
|
(Finfo.fattrib & AM_RDO) ? 'R' : '-',
|
|
(Finfo.fattrib & AM_HID) ? 'H' : '-',
|
|
(Finfo.fattrib & AM_SYS) ? 'S' : '-',
|
|
(Finfo.fattrib & AM_ARC) ? 'A' : '-',
|
|
(Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31,
|
|
(Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
|
|
Finfo.fsize, Finfo.fname,
|
|
"");
|
|
}
|
|
printf("%c%c", Dir.dir[0], Dir.dir[1]);
|
|
printf("%4u File(s),%10lu bytes total\r\n%4u Dir(s)", s1, p1, s2);
|
|
res = f_getfree(ptr, (DWORD*)&p1, &fs);
|
|
if (res == FR_OK)
|
|
printf(", %10lu bytes free\r\n", p1 * fs->csize * 512);
|
|
else
|
|
put_rc((FRESULT)res);
|
|
break;
|
|
}
|
|
break;
|
|
case 'c':
|
|
switch (*ptr++)
|
|
{
|
|
case 'd':
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_chdir(ptr));
|
|
break;
|
|
}
|
|
break;
|
|
case 'm' : /* Memory dump/fill/edit */
|
|
switch (*ptr++)
|
|
{
|
|
case 'd' : /* md[b|h|w] <address> [<count>] - Dump memory */
|
|
switch (*ptr++)
|
|
{
|
|
case 'w': p3 = DW_LONG; break;
|
|
case 'h': p3 = DW_SHORT; break;
|
|
default: p3 = DW_CHAR;
|
|
}
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
if (!xatoi(&ptr, &p2)) p2 = 128 / p3;
|
|
for (ptr = (char*)p1; p2 >= 16 / p3; ptr += 16, p2 -= 16 / p3)
|
|
put_dump(ptr, (DWORD)ptr, 16 / p3, p3);
|
|
if (p2) put_dump((BYTE*)ptr, (UINT)ptr, p2, p3);
|
|
break;
|
|
case 'f' : /* mf <address> <value> <count> - Fill memory */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
|
|
while (p3--)
|
|
{
|
|
*(BYTE*)p1 = (BYTE)p2;
|
|
p1++;
|
|
}
|
|
break;
|
|
case 'e' : /* me[b|h|w] <address> [<value> ...] - Edit memory */
|
|
switch (*ptr++)
|
|
{ /* Get data width */
|
|
case 'w': p3 = DW_LONG; break;
|
|
case 'h': p3 = DW_SHORT; break;
|
|
default: p3 = DW_CHAR;
|
|
}
|
|
if (!xatoi(&ptr, &p1)) break; /* Get start address */
|
|
if (xatoi(&ptr, &p2))
|
|
{ /* 2nd parameter is given (direct mode) */
|
|
do
|
|
{
|
|
switch (p3)
|
|
{
|
|
case DW_LONG: *(DWORD*)p1 = (DWORD)p2; break;
|
|
case DW_SHORT: *(WORD*)p1 = (WORD)p2; break;
|
|
default: *(BYTE*)p1 = (BYTE)p2;
|
|
}
|
|
p1 += p3;
|
|
} while (xatoi(&ptr, &p2)); /* Get next value */
|
|
break;
|
|
}
|
|
for (;;)
|
|
{ /* 2nd parameter is not given (interactive mode) */
|
|
switch (p3)
|
|
{
|
|
case DW_LONG: printf("%08X 0x%08X-", (uint32_t)p1, (uint32_t)*(DWORD*)p1); break;
|
|
case DW_SHORT: printf("%08X 0x%04X-", (uint32_t)p1, (uint32_t)*(WORD*)p1); break;
|
|
default: printf("%08X 0x%02X-", (uint32_t)p1, *(BYTE*)p1);
|
|
}
|
|
ptr = cLine; xgets(ptr, sizeof cLine);
|
|
if (*ptr == '.') break;
|
|
if ((BYTE)*ptr >= ' ')
|
|
{
|
|
if (!xatoi(&ptr, &p2)) continue;
|
|
switch (p3)
|
|
{
|
|
case DW_LONG: *(DWORD*)p1 = (DWORD)p2; break;
|
|
case DW_SHORT: *(WORD*)p1 = (WORD)p2; break;
|
|
default: *(BYTE*)p1 = (BYTE)p2;
|
|
}
|
|
}
|
|
p1 += p3;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 'd' : /* Disk I/O layer controls */
|
|
switch (*ptr++)
|
|
{
|
|
case 'd' : /* dd [<pd#> <sect>] - Dump secrtor */
|
|
if (!xatoi(&ptr, &p1))
|
|
{
|
|
p1 = drv; p2 = sect;
|
|
}
|
|
else
|
|
{
|
|
if (!xatoi(&ptr, &p2)) break;
|
|
}
|
|
drv = (BYTE)p1; sect = p2;
|
|
res = disk_read(drv, fBuff, sect, 1);
|
|
if (res) { printf("rc=%d\r\n", (WORD)res); break; }
|
|
printf("PD#:%u LBA:%lu\r\n", drv, sect++);
|
|
for (ptr=(char*)fBuff, ofs = 0; ofs < 0x200; ptr += 16, ofs += 16)
|
|
put_dump((BYTE*)ptr, ofs, 16, DW_CHAR);
|
|
break;
|
|
case 'i' : /* di <pd#> - Initialize disk */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
printf("rc=%d\r\n", (WORD)disk_initialize((BYTE)p1));
|
|
break;
|
|
case 's' : /* ds <pd#> - Show disk status */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
if (disk_ioctl((BYTE)p1, GET_SECTOR_COUNT, &p2) == RES_OK)
|
|
{ printf("Drive size: %lu sectors\r\n", p2); }
|
|
if (disk_ioctl((BYTE)p1, GET_BLOCK_SIZE, &p2) == RES_OK)
|
|
{ printf("Block size: %lu sectors\r\n", p2); }
|
|
if (disk_ioctl((BYTE)p1, MMC_GET_TYPE, &b) == RES_OK)
|
|
{ printf("Media type: %u\r\n", b); }
|
|
if (disk_ioctl((BYTE)p1, MMC_GET_CSD, fBuff) == RES_OK)
|
|
{ printf("CSD:\r\n"); put_dump(fBuff, 0, 16, DW_CHAR); }
|
|
if (disk_ioctl((BYTE)p1, MMC_GET_CID, fBuff) == RES_OK)
|
|
{ printf("CID:\r\n"); put_dump(fBuff, 0, 16, DW_CHAR); }
|
|
if (disk_ioctl((BYTE)p1, MMC_GET_OCR, fBuff) == RES_OK)
|
|
{ printf("OCR:\r\n"); put_dump(fBuff, 0, 4, DW_CHAR); }
|
|
if (disk_ioctl((BYTE)p1, MMC_GET_SDSTAT, fBuff) == RES_OK)
|
|
{
|
|
printf("SD Status:\r\n");
|
|
for (s1 = 0; s1 < 64; s1 += 16) put_dump(fBuff + s1, s1, 16, DW_CHAR);
|
|
}
|
|
break;
|
|
case 'c' : /* Disk ioctl */
|
|
switch (*ptr++)
|
|
{
|
|
case 's' : /* dcs <pd#> - CTRL_SYNC */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
printf("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_SYNC, 0));
|
|
break;
|
|
case 'e' : /* dce <pd#> <s.lba> <e.lba> - CTRL_TRIM */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, (long*)&blk[0]) || !xatoi(&ptr, (long*)&blk[1])) break;
|
|
printf("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_TRIM, blk));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 'b' : /* Buffer controls */
|
|
switch (*ptr++)
|
|
{
|
|
case 'd' : /* bd <ofs> - Dump R/W buffer */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
for (ptr=(char*)&fBuff[p1], ofs = p1, cnt = 32; cnt; cnt--, ptr+=16, ofs+=16)
|
|
put_dump((BYTE*)ptr, ofs, 16, DW_CHAR);
|
|
break;
|
|
case 'e' : /* be <ofs> [<data>] ... - Edit R/W buffer */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
if (xatoi(&ptr, &p2))
|
|
{
|
|
do
|
|
{
|
|
fBuff[p1++] = (BYTE)p2;
|
|
} while (xatoi(&ptr, &p2));
|
|
break;
|
|
}
|
|
for (;;)
|
|
{
|
|
printf("%04X %02X-", (WORD)(p1), (WORD)fBuff[p1]);
|
|
xgets(cLine, sizeof cLine);
|
|
ptr = cLine;
|
|
if (*ptr == '.') break;
|
|
if (*ptr < ' ') { p1++; continue; }
|
|
if (xatoi(&ptr, &p2))
|
|
fBuff[p1++] = (BYTE)p2;
|
|
else
|
|
printf("???\r\n");
|
|
}
|
|
break;
|
|
case 'r' : /* br <pd#> <lba> [<num>] - Read disk into R/W buffer */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
|
|
if (!xatoi(&ptr, &p3)) p3 = 1;
|
|
printf("rc=%u\r\n", (WORD)disk_read((BYTE)p1, fBuff, p2, p3));
|
|
break;
|
|
case 'w' : /* bw <pd#> <lba> [<num>] - Write R/W buffer into disk */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
|
|
if (!xatoi(&ptr, &p3)) p3 = 1;
|
|
printf("rc=%u\r\n", (WORD)disk_write((BYTE)p1, fBuff, p2, p3));
|
|
break;
|
|
case 'f' : /* bf <val> - Fill working buffer */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
memset(fBuff, (BYTE)p1, FBUFF_MAX);
|
|
break;
|
|
#ifdef BOOT_UPDATE
|
|
case 'u':
|
|
BootUpdateProcess();
|
|
break;
|
|
case 'z':
|
|
BootSectorCompare();
|
|
break;
|
|
#endif // #ifdef BOOT_UPDATE
|
|
}
|
|
break;
|
|
case 'f' : /* FatFS API controls */
|
|
switch (*ptr++)
|
|
{
|
|
#if _FS_RPATH && _VOLUMES >= 2
|
|
case 'f':
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_chdrive(ptr));
|
|
break;
|
|
#endif
|
|
case 'i' : /* fi [<opt>]- Initialize logical drive */
|
|
if (!xatoi(&ptr, &p2)) p2 = 0;
|
|
// f_mount(fs[1],"1:",1);
|
|
put_rc(f_mount(&FatFs, "1:", (BYTE)p2));
|
|
break;
|
|
case 's' : /* fs [<path>] - Show volume status */
|
|
while (*ptr == ' ') ptr++;
|
|
res = f_getfree(ptr, (DWORD*)&p1, &fs);
|
|
if (res) { put_rc((FRESULT)res); break; }
|
|
printf("FAT type = FAT%u\r\nBytes/Cluster = %lu\r\nNumber of FATs = %u\r\n"
|
|
"Root DIR entries = %u\r\nSectors/FAT = %lu\r\nNumber of clusters = %lu\r\n"
|
|
"Volume start (lba) = %lu\r\nFAT start (lba) = %lu\r\nDIR start (lba,clustor) = %lu\r\nData start (lba) = %lu\r\n\r\n",
|
|
ft[fs->fs_type & 3], (DWORD)fs->csize * 512, fs->n_fats,
|
|
fs->n_rootdir, fs->fsize, (DWORD)fs->n_fatent - 2,
|
|
fs->volbase, fs->fatbase, fs->dirbase, fs->database);
|
|
#if _USE_LABEL
|
|
res = f_getlabel(ptr, (char*)fBuff, (DWORD*)&p2);
|
|
if (res) { put_rc((FRESULT)res); break; }
|
|
fBuff[0] ? printf("Volume name is %s\r\n", (char *)fBuff) : printf("No volume label\r\n");
|
|
// printf(fBuff[0] ? "Volume name is %s\r\n" : "No volume label\r\n", (char *)fBuff);
|
|
printf("Volume S/N is %04X-%04X\r\n", (uint32_t)((DWORD)p2 >> 16), (uint32_t)((DWORD)p2 & 0xFFFF));
|
|
#endif
|
|
AccSize = AccFiles = AccDirs = 0;
|
|
printf("...");
|
|
res = scan_files(ptr);
|
|
if (res) { put_rc((FRESULT)res); break; }
|
|
printf("\r%u files, %lu bytes.\r\n%u folders.\r\n"
|
|
"%lu KiB total disk space.\r\n%lu KiB available.\r\n",
|
|
AccFiles, AccSize, AccDirs,
|
|
(fs->n_fatent - 2) * (fs->csize / 2), (DWORD)p1 * (fs->csize / 2)
|
|
);
|
|
break;
|
|
case 'l' : /* fl [<path>] - Directory listing */
|
|
while (*ptr == ' ') ptr++;
|
|
res = f_opendir(&Dir, ptr);
|
|
if (res) { put_rc((FRESULT)res); break; }
|
|
p1 = s1 = s2 = 0;
|
|
for(;;)
|
|
{
|
|
res = f_readdir(&Dir, &Finfo);
|
|
if ((res != FR_OK) || !Finfo.fname[0]) break;
|
|
if (Finfo.fattrib & AM_DIR) {
|
|
s2++;
|
|
} else {
|
|
s1++; p1 += Finfo.fsize;
|
|
}
|
|
printf("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %-12s %s\r\n",
|
|
(Finfo.fattrib & AM_DIR) ? 'D' : '-',
|
|
(Finfo.fattrib & AM_RDO) ? 'R' : '-',
|
|
(Finfo.fattrib & AM_HID) ? 'H' : '-',
|
|
(Finfo.fattrib & AM_SYS) ? 'S' : '-',
|
|
(Finfo.fattrib & AM_ARC) ? 'A' : '-',
|
|
(Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31,
|
|
(Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
|
|
Finfo.fsize, Finfo.fname,
|
|
"");
|
|
}
|
|
printf("%c%c", Dir.dir[0], Dir.dir[1]);
|
|
printf("%4u File(s),%10lu bytes total\r\n%4u Dir(s)", s1, p1, s2);
|
|
res = f_getfree(ptr, (DWORD*)&p1, &fs);
|
|
if (res == FR_OK)
|
|
printf(", %10lu bytes free\r\n", p1 * fs->csize * 512);
|
|
else
|
|
put_rc((FRESULT)res);
|
|
break;
|
|
case 'o' : /* fo <mode> <file> - Open a file */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_open(&File[0], ptr, (BYTE)p1));
|
|
break;
|
|
case 'c' : /* fc - Close a file */
|
|
put_rc(f_close(&File[0]));
|
|
break;
|
|
case 'e' : /* fe - Seek file pointer */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
res = f_lseek(&File[0], p1);
|
|
put_rc((FRESULT)res);
|
|
if (res == FR_OK)
|
|
printf("fptr=%lu(0x%lX)\r\n", File[0].fptr, File[0].fptr);
|
|
break;
|
|
case 'd' : /* fd <len> - read and dump file from current fp */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
ofs = File[0].fptr;
|
|
while (p1)
|
|
{
|
|
if ((UINT)p1 >= 16) { cnt = 16; p1 -= 16; }
|
|
else { cnt = p1; p1 = 0; }
|
|
res = f_read(&File[0], fBuff, cnt, &cnt);
|
|
if (res != FR_OK) { put_rc((FRESULT)res); break; }
|
|
if (!cnt) break;
|
|
put_dump(fBuff, ofs, cnt, DW_CHAR);
|
|
ofs += 16;
|
|
}
|
|
break;
|
|
case 'r' : /* fr <len> - read file */
|
|
if (!xatoi(&ptr, &p1)) break;
|
|
p2 = 0;
|
|
Timer = 0;
|
|
while (p1)
|
|
{
|
|
if ((UINT)p1 >= blen) {
|
|
cnt = blen; p1 -= blen;
|
|
} else {
|
|
cnt = p1; p1 = 0;
|
|
}
|
|
res = f_read(&File[0], fBuff, cnt, &s2);
|
|
if (res != FR_OK) { put_rc((FRESULT)res); break; }
|
|
p2 += s2;
|
|
if (cnt != s2) break;
|
|
}
|
|
printf("%lu bytes read with %lu kB/sec.\r\n", p2, Timer ? (p2 / Timer) : 0);
|
|
break;
|
|
case 'w' : /* fw <len> <val> - write file */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
|
|
memset(fBuff, (BYTE)p2, blen);
|
|
p2 = 0;
|
|
Timer = 0;
|
|
while (p1)
|
|
{
|
|
if ((UINT)p1 >= blen) {
|
|
cnt = blen; p1 -= blen;
|
|
} else {
|
|
cnt = p1; p1 = 0;
|
|
}
|
|
res = f_write(&File[0], fBuff, cnt, &s2);
|
|
if (res != FR_OK) { put_rc((FRESULT)res); break; }
|
|
p2 += s2;
|
|
if (cnt != s2) break;
|
|
}
|
|
printf("%lu bytes written with %lu kB/sec.\r\n", p2, Timer ? (p2 / Timer) : 0);
|
|
break;
|
|
case 'n' : /* fn <org.name> <new.name> - Change name of an object */
|
|
while (*ptr == ' ') ptr++;
|
|
ptr2 = strchr(ptr, ' ');
|
|
if (!ptr2) break;
|
|
*ptr2++ = 0;
|
|
while (*ptr2 == ' ') ptr2++;
|
|
put_rc(f_rename(ptr, ptr2));
|
|
break;
|
|
case 'u' : /* fu <name> - Unlink an object */
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_unlink(ptr));
|
|
break;
|
|
case 'v' : /* fv - Truncate file */
|
|
put_rc(f_truncate(&File[0]));
|
|
break;
|
|
case 'k' : /* fk <name> - Create a directory */
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_mkdir(ptr));
|
|
break;
|
|
case 'a' : /* fa <atrr> <mask> <name> - Change attribute of an object */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_chmod(ptr, p1, p2));
|
|
break;
|
|
case 't' : /* ft <year> <month> <day> <hour> <min> <sec> <name> - Change timestamp of an object */
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
|
|
Finfo.fdate = ((p1 - 1980) << 9) | ((p2 & 15) << 5) | (p3 & 31);
|
|
if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
|
|
Finfo.ftime = ((p1 & 31) << 11) | ((p2 & 63) << 5) | ((p3 >> 1) & 31);
|
|
put_rc(f_utime(ptr, &Finfo));
|
|
break;
|
|
case 'x' : /* fx <src.name> <dst.name> - Copy a file */
|
|
while (*ptr == ' ') ptr++;
|
|
ptr2 = strchr(ptr, ' ');
|
|
if (!ptr2) break;
|
|
*ptr2++ = 0;
|
|
while (*ptr2 == ' ') ptr2++;
|
|
printf("Opening \"%s\"", ptr);
|
|
res = f_open(&File[0], ptr, FA_OPEN_EXISTING | FA_READ);
|
|
printf("\r\n");
|
|
if (res) {
|
|
put_rc((FRESULT)res);
|
|
break;
|
|
}
|
|
printf("Creating \"%s\"", ptr2);
|
|
res = f_open(&File[1], ptr2, FA_CREATE_ALWAYS | FA_WRITE);
|
|
printf("\r\n");
|
|
if (res) {
|
|
put_rc((FRESULT)res);
|
|
f_close(&File[0]);
|
|
break;
|
|
}
|
|
printf("Copying file...");
|
|
Timer = 0;
|
|
p1 = 0;
|
|
for (;;)
|
|
{
|
|
res = f_read(&File[0], fBuff, blen, &s1);
|
|
if (res || s1 == 0) break; /* error or eof */
|
|
res = f_write(&File[1], fBuff, s1, &s2);
|
|
p1 += s2;
|
|
if (res || s2 < s1) break; /* error or disk full */
|
|
}
|
|
printf("\r\n%lu bytes copied with %lu kB/sec.\r\n", p1, p1 / Timer);
|
|
f_close(&File[0]);
|
|
f_close(&File[1]);
|
|
break;
|
|
#if _FS_RPATH
|
|
case 'g' : /* fg <path> - Change current directory */
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_chdir(ptr));
|
|
break;
|
|
#if _FS_RPATH >= 2
|
|
case 'q' : /* fq - Show current dir path */
|
|
res = f_getcwd(cLine, sizeof cLine);
|
|
if (res)
|
|
put_rc((FRESULT)res);
|
|
else
|
|
printf("%s\r\n", cLine);
|
|
break;
|
|
#endif
|
|
#endif
|
|
#if _USE_LABEL
|
|
case 'b' : /* fb <name> - Set volume label */
|
|
while (*ptr == ' ') ptr++;
|
|
put_rc(f_setlabel(ptr));
|
|
break;
|
|
#endif /* _USE_LABEL */
|
|
#if _USE_MKFS
|
|
case 'm' : /* fm <rule> <csize> - Create file system */
|
|
if (!xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
|
|
printf("The volume will be formatted. Are you sure? (Y/n)=");
|
|
xgets(cLine, sizeof cLine);
|
|
if (cLine[0] == 'Y')
|
|
put_rc(f_mkfs("0:", (BYTE)p2, (WORD)p3, work_space, 1024));
|
|
break;
|
|
#endif /* _USE_MKFS */
|
|
case 'z' : /* fz [<size>] - Change/Show R/W length for fr/fw/fx command */
|
|
if (xatoi(&ptr, &p1) && p1 >= 1 && p1 <= (long)sizeof fBuff)
|
|
blen = p1;
|
|
printf("blen=%u\r\n", blen);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // #ifdef CONSOLE_DEBUG
|
|
|
|
/* Pointer to the file name */
|
|
FRESULT FileCreate(const TCHAR *path)
|
|
{
|
|
FRESULT rc = FR_LOCKED;
|
|
FIL pFile; /* File objects */
|
|
UINT wlen;
|
|
|
|
if (ReqUseFatfs())
|
|
{
|
|
rc = f_open(&pFile, path, FA_WRITE);
|
|
|
|
if (rc == FR_NO_FILE)
|
|
{
|
|
rc = f_open(&pFile, path, FA_CREATE_NEW | FA_WRITE);
|
|
if (rc == FR_OK)
|
|
// rc = f_write(&pFile, path, strlen(path), &wlen);
|
|
rc = f_close(&pFile);
|
|
}
|
|
else if (rc == FR_OK)
|
|
{
|
|
rc = f_truncate(&pFile);
|
|
rc = f_write(&pFile, path, strlen(path), &wlen);
|
|
f_close(&pFile);
|
|
}
|
|
leaveFatfs();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
FRESULT FileCheck(const TCHAR *path)
|
|
{
|
|
FRESULT rc = FR_LOCKED;
|
|
FIL pFile; /* File objects */
|
|
|
|
if (ReqUseFatfs())
|
|
{
|
|
rc = f_open(&pFile, path, FA_READ);
|
|
|
|
if (rc == FR_OK)
|
|
{
|
|
f_close(&pFile);
|
|
}
|
|
leaveFatfs();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* Pointer to the file name */
|
|
FRESULT FileWrite(const TCHAR *path, BYTE *data, DWORD offset, DWORD size)
|
|
{
|
|
FRESULT rc = FR_LOCKED;
|
|
UINT wlen;
|
|
FIL pFile; /* File objects */
|
|
|
|
if (ReqUseFatfs())
|
|
{
|
|
rc = f_open(&pFile, path, FA_WRITE);
|
|
|
|
if (rc == FR_OK)
|
|
{
|
|
if (offset == 0xffffffff)
|
|
rc = f_lseek(&pFile, f_size(&pFile));
|
|
else
|
|
rc = f_lseek(&pFile, offset);
|
|
rc = f_write(&pFile, data, size, &wlen);
|
|
f_close(&pFile);
|
|
}
|
|
leaveFatfs();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* Pointer to the file name */
|
|
FRESULT FileRead(const TCHAR *path, BYTE *data, DWORD offset, DWORD size, UINT *rlen)
|
|
{
|
|
FRESULT rc = FR_LOCKED;
|
|
FIL pFile; /* File objects */
|
|
|
|
if (ReqUseFatfs())
|
|
{
|
|
rc = f_open(&pFile, path, FA_READ);
|
|
|
|
if (rc == FR_OK)
|
|
{
|
|
f_lseek(&pFile, offset);
|
|
f_read(&pFile, data, size, rlen);
|
|
f_close(&pFile);
|
|
}
|
|
leaveFatfs();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
FRESULT GetFileSize(const TCHAR *path, UINT *size)
|
|
{
|
|
FRESULT rc = FR_LOCKED;
|
|
FIL pFile;
|
|
|
|
if (ReqUseFatfs()) {
|
|
rc = f_open(&pFile, path, FA_READ);
|
|
|
|
if (rc == FR_OK)
|
|
{
|
|
*size = pFile.obj.objsize;
|
|
f_close(&pFile);
|
|
}
|
|
leaveFatfs();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
FRESULT DirCreate(const TCHAR *path)
|
|
{
|
|
FRESULT rc = FR_LOCKED;
|
|
|
|
if (ReqUseFatfs()) {
|
|
rc = f_mkdir(path);
|
|
leaveFatfs();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/
|