mirror of
https://github.com/elua/elua.git
synced 2025-01-08 20:56:17 +08:00
Added WOFS + other stuff
This should really be more than one commit, but I wrote everything in one shot and I don't feel like arranging the changes logically into different commits. So, these are the changes: - added WOFS (Write Once File System). This is a writeable file system that exists in the MCU's internal Flash memory and allows files to be written, but only once, in a single shot. More details to follow. - the platform interface has a new MCU flash access interface. - added WOFS "reference implementations" for two CPUs: LM3S8962 and STM32F103RE. They are easily extendable to other CPUs in the same platform and can be taken as a model for other platforms. - the ROMFS file layout in memory was slightly changed. - the simulator (src/platform/sim) got a new function (lseek). - shell: now each shell command receives its arguments in a C-main-style (argc, argv) pair. This was originally Marcelo's idea and it finally made it to the master (although this particular implementation is mine), after I got fed up with all the argument parsing in the shell functions. - new shell command: wofmt ("formats" a WOFS, effectively clearing it). - a couple of small fixes in the shell code
This commit is contained in:
parent
a378b8943e
commit
e9a24cac11
@ -315,7 +315,16 @@ u32 platform_eth_get_elapsed_time();
|
||||
void platform_usb_cdc_send( u8 data );
|
||||
int platform_usb_cdc_recv( s32 timeout );
|
||||
|
||||
// *****************************************************************************
|
||||
// Internal flash erase/write functions
|
||||
// Currently used by WOFS
|
||||
|
||||
u32 platform_flash_get_first_free_block_address( u32 *psect );
|
||||
u32 platform_flash_get_sector_of_address( u32 addr );
|
||||
u32 platform_flash_write( const void *from, u32 toaddr, u32 size );
|
||||
u32 platform_s_flash_write( const void *from, u32 toaddr, u32 size );
|
||||
u32 platform_flash_get_num_sectors();
|
||||
int platform_flash_erase_sector( u32 sector_id );
|
||||
|
||||
// *****************************************************************************
|
||||
// Allocator support
|
||||
|
46
inc/romfs.h
46
inc/romfs.h
@ -8,10 +8,20 @@
|
||||
|
||||
/*******************************************************************************
|
||||
The Read-Only "filesystem" resides in a contiguous zone of memory, with the
|
||||
following structure, repeated for each file:
|
||||
following structure (repeated for each file):
|
||||
|
||||
Filename: ASCIIZ, max length is DM_MAX_FNAME_LENGTH defined here, empty if last file
|
||||
File size: (4 bytes)
|
||||
Filename: ASCIIZ, max length is DM_MAX_FNAME_LENGTH, first byte is 0xFF if last file
|
||||
File size: (4 bytes), aligned to ROMFS_ALIGN bytes
|
||||
File data: (file size bytes)
|
||||
|
||||
The WOFS (Write Once File System) uses much of the ROMFS functions, thuss it is
|
||||
also implemented in romfs.c. It resides in a contiguous zone of memory, with a
|
||||
structure that is quite similar with ROMFS' structure (repeated for each file):
|
||||
|
||||
Filename: ASCIIZ, max length is DM_MAX_FNAME_LENGTH, first byte is 0xFF if last file.
|
||||
WOFS filenames always begin at an address which is a multiple of ROMFS_ALIGN.
|
||||
File deleted flag: (WOFS_DEL_FIELD_SIZE bytes), aligned to ROMFS_ALIGN bytes
|
||||
File size: (4 bytes), aligned to ROMFS_ALIGN bytes
|
||||
File data: (file size bytes)
|
||||
|
||||
*******************************************************************************/
|
||||
@ -22,9 +32,9 @@ enum
|
||||
FS_FILE_OK
|
||||
};
|
||||
|
||||
// This is the function used to read a byte at the given address from the file
|
||||
// system
|
||||
typedef u8 ( *p_read_fs_byte )( u32 );
|
||||
// ROMFS/WOFS functions
|
||||
typedef u32 ( *p_fs_read )( void *to, u32 fromaddr, u32 size, const void *pdata );
|
||||
typedef u32 ( *p_fs_write )( const void *from, u32 toaddr, u32 size, const void *pdata );
|
||||
|
||||
// File flags
|
||||
#define ROMFS_FILE_FLAG_READ 0x01
|
||||
@ -40,19 +50,33 @@ typedef struct
|
||||
u8 flags;
|
||||
} FD;
|
||||
|
||||
// WOFS constants
|
||||
// The miminum size we need in order to create another file
|
||||
// This size will be added to the size of the filename when creating a new file
|
||||
// to ensure that there's enough space left on the device
|
||||
// This comes from the size of the file length field (4) + the maximum number of
|
||||
// bytes needed to align this field (3) + a single 0xFF byte which marks the end
|
||||
// of the filesystem (1) + the maximum number of bytes needed to align the contents
|
||||
// of a file (3)
|
||||
#define WOFS_MIN_NEEDED_SIZE 11
|
||||
|
||||
// Filesystem flags
|
||||
#define ROMFS_FS_FLAG_DIRECT 0x01
|
||||
#define ROMFS_FS_FLAG_WO 0x02
|
||||
#define ROMFS_FS_FLAG_DIRECT 0x01 // direct mode (the file is mapped in a memory area directly accesible by the CPU)
|
||||
#define ROMFS_FS_FLAG_WO 0x02 // this FS is actually a WO (Write-Once) FS
|
||||
|
||||
// File system descriptor
|
||||
typedef struct
|
||||
{
|
||||
u8 *pbase;
|
||||
u8 flags;
|
||||
u8 *pbase; // pointer to FS base in memory (only for ROMFS_FS_FLAG_DIRECT)
|
||||
u8 flags; // flags (see above)
|
||||
p_fs_read readf; // pointer to read function (for non-direct mode FS)
|
||||
p_fs_write writef; // pointer to write function (only for ROMFS_FS_FLAG_WO)
|
||||
u32 max_size; // maximum size of the FS (in bytes)
|
||||
} FSDATA;
|
||||
|
||||
|
||||
// FS functions
|
||||
int romfs_init();
|
||||
int wofs_format();
|
||||
|
||||
#endif
|
||||
|
||||
|
11
mkfs.py
11
mkfs.py
@ -117,21 +117,20 @@ def mkfs( dirname, outname, flist, mode, compcmd ):
|
||||
size_lh = ( len( filedata ) >> 8 ) & 0xFF
|
||||
size_hl = ( len( filedata ) >> 16 ) & 0xFF
|
||||
size_hh = ( len( filedata ) >> 24 ) & 0xFF
|
||||
# Round to a multiple of 4
|
||||
while _bytecnt & ( alignment - 1 ) != 0:
|
||||
_add_data( 0, outfile )
|
||||
# Write size
|
||||
_add_data( size_ll, outfile )
|
||||
_add_data( size_lh, outfile )
|
||||
_add_data( size_hl, outfile )
|
||||
_add_data( size_hh, outfile )
|
||||
# Round to a multiple of 4
|
||||
actual = len( filedata )
|
||||
while _bytecnt & ( alignment - 1 ) != 0:
|
||||
_add_data( 0, outfile )
|
||||
actual = actual + 1
|
||||
# Then write the rest of the file
|
||||
for c in filedata:
|
||||
_add_data( ord( c ), outfile )
|
||||
|
||||
# Report
|
||||
print "Encoded file %s (%d bytes real size, %d bytes after rounding, %d bytes total)" % ( fname, len( filedata ), actual, _fcnt )
|
||||
print "Encoded file %s (%d bytes real size, %d bytes encoded size)" % ( fname, len( filedata ), _fcnt )
|
||||
|
||||
# All done, write the final "0xFF" (terminator)
|
||||
_add_data( 0xFF, outfile, False )
|
||||
|
119
src/common.c
119
src/common.c
@ -440,6 +440,125 @@ void cmn_int_handler( elua_int_id id, elua_int_resnum resnum )
|
||||
|
||||
#endif // #ifdef BUILD_INT_HANDLERS
|
||||
|
||||
// ****************************************************************************
|
||||
// Internal flash support functions (currently used only by WOFS)
|
||||
|
||||
#ifdef BUILD_WOFS
|
||||
|
||||
// This symbol must be exported by the linker command file and must reflect the
|
||||
// TOTAL size of flash used by the eLua image (not only the code and constants,
|
||||
// but also .data and whatever else ends up in the eLua image). WOFS will start
|
||||
// at the next usable (aligned to a flash sector boundary) address after
|
||||
// flash_used_size.
|
||||
extern char flash_used_size[];
|
||||
|
||||
// Helper function: find the flash sector in which an address resides
|
||||
// Return the sector number, as well as the start and end address of the sector
|
||||
static u32 flashh_find_sector( u32 address, u32 *pstart, u32 *pend )
|
||||
{
|
||||
address -= INTERNAL_FLASH_START_ADDRESS;
|
||||
#ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
// All the sectors in the flash have the same size, so just align the address
|
||||
u32 sect_id = address / INTERNAL_FLASH_SECTOR_SIZE;
|
||||
|
||||
if( pstart )
|
||||
*pstart = sect_id * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS;
|
||||
if( pend )
|
||||
*pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS - 1;
|
||||
return sect_id;
|
||||
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
// The flash has blocks of different size
|
||||
// Their size is decribed in the INTERNAL_FLASH_SECTOR_ARRAY macro
|
||||
const u16 flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
|
||||
u32 total = 0, i = 0;
|
||||
|
||||
while( ( total <= address ) && ( i < sizeof( flash_sect_size ) / sizeof( u16 ) ) )
|
||||
total += flash_sect_size[ i ++ ];
|
||||
if( pstart )
|
||||
*pstart = ( total - flash_sect_size[ i - 1 ] ) + INTERNAL_FLASH_START_ADDRESS;
|
||||
if( pend )
|
||||
*pend = total + INTERNAL_FLASH_START_ADDRESS - 1;
|
||||
return i - 1;
|
||||
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
}
|
||||
|
||||
u32 platform_flash_get_sector_of_address( u32 addr )
|
||||
{
|
||||
return flashh_find_sector( addr, NULL, NULL );
|
||||
}
|
||||
|
||||
u32 platform_flash_get_num_sectors()
|
||||
{
|
||||
#ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
return INTERNAL_FLASH_SIZE / INTERNAL_FLASH_SECTOR_SIZE;
|
||||
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
const u16 flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
|
||||
|
||||
return sizeof( flash_sect_size ) / sizeof( u16 );
|
||||
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
}
|
||||
|
||||
u32 platform_flash_get_first_free_block_address( u32 *psect )
|
||||
{
|
||||
// Round the total used flash size to the closest flash block address
|
||||
u32 temp, sect;
|
||||
|
||||
sect = flashh_find_sector( ( u32 )flash_used_size + INTERNAL_FLASH_START_ADDRESS - 1, NULL, &temp );
|
||||
if( psect )
|
||||
*psect = sect + 1;
|
||||
return temp + 1;
|
||||
}
|
||||
|
||||
u32 platform_flash_write( const void *from, u32 toaddr, u32 size )
|
||||
{
|
||||
#ifndef INTERNAL_FLASH_WRITE_BLK_SIZE
|
||||
return platform_s_flash_write( from, toaddr, size );
|
||||
#else // #ifindef INTERNAL_FLASH_WRITE_BLK_SIZE
|
||||
u32 temp, rest, ssize = size;
|
||||
unsigned i;
|
||||
char tmpdata[ INTERNAL_FLASH_WRITE_BLK_SIZE ];
|
||||
const u8 *pfrom = ( const u8* )from;
|
||||
const u32 blksize = INTERNAL_FLASH_WRITE_BLK_SIZE;
|
||||
const u32 blkmask = INTERNAL_FLASH_WRITE_BLK_SIZE - 1;
|
||||
|
||||
// Align the start
|
||||
if( toaddr & blkmask )
|
||||
{
|
||||
rest = toaddr & blkmask;
|
||||
temp = toaddr & ~blkmask; // this is the actual aligned address
|
||||
memcpy( tmpdata, ( const void* )temp, blksize );
|
||||
for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ )
|
||||
tmpdata[ i ] = *pfrom;
|
||||
platform_s_flash_write( tmpdata, temp, blksize );
|
||||
if( size == 0 )
|
||||
return ssize;
|
||||
toaddr = temp + blksize;
|
||||
}
|
||||
// The start address is now a multiple of blksize
|
||||
// Compute how many bytes we can write as multiples of blksize
|
||||
rest = size & blkmask;
|
||||
temp = size & ~blkmask;
|
||||
// Program the blocks now
|
||||
if( temp )
|
||||
{
|
||||
platform_s_flash_write( pfrom, toaddr, temp );
|
||||
toaddr += temp;
|
||||
pfrom += temp;
|
||||
}
|
||||
// And the final part of a block if needed
|
||||
if( rest )
|
||||
{
|
||||
memcpy( tmpdata, ( const void* )toaddr, blksize );
|
||||
for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ )
|
||||
tmpdata[ i ] = *pfrom;
|
||||
platform_s_flash_write( tmpdata, toaddr, blksize );
|
||||
}
|
||||
return ssize;
|
||||
#endif // #ifndef INTERNAL_FLASH_WRITE_BLK_SIZE
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_WOFS
|
||||
|
||||
// ****************************************************************************
|
||||
// Misc support
|
||||
|
||||
|
@ -38,7 +38,7 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} >sram
|
||||
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab*)
|
||||
@ -51,6 +51,8 @@ SECTIONS
|
||||
} >sram
|
||||
__exidx_end = .;
|
||||
|
||||
PROVIDE( flash_used_size = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.extab) + SIZEOF(.ARM.exidx) );
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
_bss = .;
|
||||
*(.bss .bss.*)
|
||||
|
@ -151,6 +151,8 @@ int platform_init()
|
||||
MAP_IntMasterEnable();
|
||||
#endif
|
||||
|
||||
MAP_FlashUsecSet( SysCtlClockGet() );
|
||||
|
||||
// All done
|
||||
return PLATFORM_OK;
|
||||
}
|
||||
@ -1308,6 +1310,19 @@ ControlHandler(void *pvCBData, unsigned long ulEvent, unsigned long ulMsgValue,
|
||||
|
||||
#endif // BUILD_USB_CDC
|
||||
|
||||
// ****************************************************************************
|
||||
// Flash access functions
|
||||
|
||||
u32 platform_s_flash_write( const void *from, u32 toaddr, u32 size )
|
||||
{
|
||||
return MAP_FlashProgram( ( unsigned long * )from, toaddr, size );
|
||||
}
|
||||
|
||||
int platform_flash_erase_sector( u32 sector_id )
|
||||
{
|
||||
return FlashErase( sector_id * INTERNAL_FLASH_SECTOR_SIZE ) == 0 ? PLATFORM_OK : PLATFORM_ERR;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Platform specific modules go here
|
||||
|
||||
|
@ -267,6 +267,15 @@
|
||||
#define SRAM_SIZE ( 0x10000 )
|
||||
#endif
|
||||
|
||||
// Flash data (only for LM3S8962 for now)
|
||||
#ifdef ELUA_CPU_LM3S8962
|
||||
#define INTERNAL_FLASH_SIZE ( 256 * 1024 )
|
||||
#define INTERNAL_FLASH_WRITE_BLK_SIZE 4
|
||||
#define INTERNAL_FLASH_SECTOR_SIZE 1024
|
||||
#define INTERNAL_FLASH_START_ADDRESS 0
|
||||
#define BUILD_WOFS
|
||||
#endif // #ifdef ELUA_CPU_LM3S8962
|
||||
|
||||
// Allocator data: define your free memory zones here in two arrays
|
||||
// (start address and end address)
|
||||
#define MEM_START_ADDRESS { ( void* )end }
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define __NR_open 5
|
||||
#define __NR_close 6
|
||||
#define __NR_gettimeofday 78
|
||||
#define __NR_lseek 19
|
||||
|
||||
int host_errno = 0;
|
||||
|
||||
@ -70,4 +71,5 @@ _syscall6(void *,mmap2, void *,addr, size_t, length, int, prot, int, flags, int,
|
||||
_syscall1(void, exit, int, status);
|
||||
_syscall1(int, close, int, status);
|
||||
_syscall2(int, gettimeofday, struct timeval*, tv, struct timezone*, tz);
|
||||
_syscall3(long, lseek, int, fd, long, offset, int, whence );
|
||||
|
||||
|
@ -13,6 +13,7 @@ ssize_t host_read( int fd, void * buf, size_t count );
|
||||
ssize_t host_write( int fd, const void * buf, size_t count );
|
||||
int host_open( const char *name, int flags, mode_t mode );
|
||||
int host_close( int fd );
|
||||
long host_lseek( int fd, long pos, int whence );
|
||||
|
||||
#define PROT_READ 0x1 /* Page can be read. */
|
||||
#define PROT_WRITE 0x2 /* Page can be written. */
|
||||
|
@ -32,6 +32,9 @@ int hostif_write( int fd, const void *buf, unsigned count );
|
||||
// Close
|
||||
int hostif_close( int fd );
|
||||
|
||||
// Seek
|
||||
long hostif_lseek( int fd, long pos, int whence );
|
||||
|
||||
// Get time
|
||||
s64 hostif_gettime();
|
||||
|
||||
|
@ -65,6 +65,11 @@ int hostif_close( int fd )
|
||||
return host_close( fd );
|
||||
}
|
||||
|
||||
long hostif_lseek( int fd, long pos, int whence )
|
||||
{
|
||||
return host_lseek( fd, pos, whence );
|
||||
}
|
||||
|
||||
s64 hostif_gettime()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
@ -93,6 +93,9 @@ int platform_init()
|
||||
/* Capture error */
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Flash initialization (for WOFS)
|
||||
FLASH_Unlock();
|
||||
|
||||
cmn_platform_init();
|
||||
|
||||
@ -1277,6 +1280,33 @@ int platform_adc_start_sequence( )
|
||||
|
||||
#endif // ifdef BUILD_ADC
|
||||
|
||||
// ****************************************************************************
|
||||
// Flash access functions
|
||||
|
||||
u32 platform_s_flash_write( const void *from, u32 toaddr, u32 size )
|
||||
{
|
||||
u32 ssize = 0;
|
||||
const u16 *psrc = ( const u16* )from;
|
||||
FLASH_Status flstat;
|
||||
|
||||
while( ssize < size )
|
||||
{
|
||||
if( ( flstat = FLASH_ProgramHalfWord( toaddr, *psrc ++ ) ) != FLASH_COMPLETE )
|
||||
{
|
||||
printf( "ERROR in platform_s_flash_write: stat=%d at %08X\n", ( int )flstat, toaddr );
|
||||
break;
|
||||
}
|
||||
toaddr += 2;
|
||||
ssize += 2;
|
||||
}
|
||||
return ssize;
|
||||
}
|
||||
|
||||
int platform_flash_erase_sector( u32 sector_id )
|
||||
{
|
||||
return FLASH_ErasePage( sector_id * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS ) == FLASH_COMPLETE ? PLATFORM_OK : PLATFORM_ERR;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Platform specific modules go here
|
||||
|
||||
|
@ -172,6 +172,14 @@ u32 platform_s_cpu_get_frequency();
|
||||
#define MEM_START_ADDRESS { ( void* )end }
|
||||
#define MEM_END_ADDRESS { ( void* )( SRAM_BASE + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
|
||||
|
||||
// Flash data (only for STM32F103RE for now)
|
||||
#ifdef ELUA_CPU_STM32F103RE
|
||||
#define INTERNAL_FLASH_SIZE ( 512 * 1024 )
|
||||
#define INTERNAL_FLASH_SECTOR_SIZE 2048
|
||||
#define INTERNAL_FLASH_START_ADDRESS 0x08000000
|
||||
#define BUILD_WOFS
|
||||
#endif // #ifdef ELUA_CPU_STM32F103RE
|
||||
|
||||
// Interrupt queue size
|
||||
#define PLATFORM_INT_QUEUE_LOG_SIZE 5
|
||||
|
||||
|
@ -51,6 +51,8 @@ SECTIONS
|
||||
*(.ARM.exidx*)
|
||||
} >sram
|
||||
__exidx_end = .;
|
||||
|
||||
PROVIDE( flash_used_size = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.extab) + SIZEOF(.ARM.exidx) );
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
|
391
src/romfs.c
391
src/romfs.c
@ -7,75 +7,129 @@
|
||||
#include "romfiles.h"
|
||||
#include <stdio.h>
|
||||
#include "ioctl.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "platform.h"
|
||||
#ifdef ELUA_SIMULATOR
|
||||
#include "hostif.h"
|
||||
#endif
|
||||
#include "platform_conf.h"
|
||||
#ifdef BUILD_ROMFS
|
||||
#if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )
|
||||
|
||||
#define ROMFS_MAX_FDS 4
|
||||
#define TOTAL_MAX_FDS 8
|
||||
// DO NOT CHANGE THE ROMFS ALIGNMENT.
|
||||
// UNLESS YOU _LIKE_ TO WATCH THE WORLD BURN.
|
||||
#define ROMFS_ALIGN 4
|
||||
|
||||
#define fsmin( x , y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )
|
||||
|
||||
static FD romfs_fd_table[ ROMFS_MAX_FDS ];
|
||||
static FD fd_table[ TOTAL_MAX_FDS ];
|
||||
static int romfs_num_fd;
|
||||
#ifdef ELUA_CPU_LINUX
|
||||
static int wofs_sim_fd;
|
||||
#define WOFS_FNAME "/tmp/wofs.dat"
|
||||
#define WOFS_SIZE (256 * 1024)
|
||||
#endif
|
||||
|
||||
#define WOFS_END_MARKER_CHAR 0xFF
|
||||
#define WOFS_DEL_FIELD_SIZE ( ROMFS_ALIGN )
|
||||
#define WOFS_FILE_DELETED 0xAA
|
||||
|
||||
// Length of the 'file size' field for both ROMFS/WOFS
|
||||
#define ROMFS_SIZE_LEN 4
|
||||
|
||||
static int romfs_find_empty_fd()
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < ROMFS_MAX_FDS; i ++ )
|
||||
if( romfs_fd_table[ i ].baseaddr == 0xFFFFFFFF &&
|
||||
romfs_fd_table[ i ].offset == 0xFFFFFFFF &&
|
||||
romfs_fd_table[ i ].size == 0xFFFFFFFF )
|
||||
for( i = 0; i < TOTAL_MAX_FDS; i ++ )
|
||||
if( fd_table[ i ].baseaddr == 0xFFFFFFFF &&
|
||||
fd_table[ i ].offset == 0xFFFFFFFF &&
|
||||
fd_table[ i ].size == 0xFFFFFFFF )
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void romfs_close_fd( int fd )
|
||||
{
|
||||
memset( romfs_fd_table + fd, 0xFF, sizeof( FD ) );
|
||||
romfs_fd_table[ fd ].flags = 0;
|
||||
memset( fd_table + fd, 0xFF, sizeof( FD ) );
|
||||
fd_table[ fd ].flags = 0;
|
||||
}
|
||||
|
||||
// Helper function: read a byte from the FS
|
||||
static u8 romfsh_read8( u32 addr, const FSDATA *pfs )
|
||||
{
|
||||
u8 temp;
|
||||
if( pfs->flags & ROMFS_FS_FLAG_DIRECT )
|
||||
return pfs->pbase[ addr ];
|
||||
pfs->readf( &temp, addr, 1, pfs );
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Helper function: return 1 if PFS reffers to a WOFS, 0 otherwise
|
||||
static int romfsh_is_wofs( const FSDATA* pfs )
|
||||
{
|
||||
return ( pfs->flags & ROMFS_FS_FLAG_WO ) != 0;
|
||||
}
|
||||
|
||||
// Open the given file, returning one of FS_FILE_NOT_FOUND, FS_FILE_ALREADY_OPENED
|
||||
// or FS_FILE_OK
|
||||
static u8 romfs_open_file( const char* fname, u8 *pbase, FD* pfd )
|
||||
static u8 romfs_open_file( const char* fname, FD* pfd, FSDATA *pfs, u32 *plast, u32 *pnameaddr )
|
||||
{
|
||||
u32 i, j;
|
||||
u32 i, j, n;
|
||||
char fsname[ DM_MAX_FNAME_LENGTH + 1 ];
|
||||
u32 fsize;
|
||||
int is_deleted;
|
||||
|
||||
// Look for the file
|
||||
i = 0;
|
||||
while( 1 )
|
||||
{
|
||||
if( pbase[ i ] == 0xFF )
|
||||
if( romfsh_read8( i, pfs ) == WOFS_END_MARKER_CHAR )
|
||||
{
|
||||
*plast = i;
|
||||
return FS_FILE_NOT_FOUND;
|
||||
}
|
||||
// Read file name
|
||||
n = i;
|
||||
for( j = 0; j < DM_MAX_FNAME_LENGTH; j ++ )
|
||||
{
|
||||
fsname[ j ] = pbase[ i + j ];
|
||||
fsname[ j ] = romfsh_read8( i + j, pfs );
|
||||
if( fsname[ j ] == 0 )
|
||||
break;
|
||||
}
|
||||
// ' i + j' now points at the '0' byte
|
||||
j = i + j + 1;
|
||||
// And read the size
|
||||
fsize = pbase[ j ] + ( pbase[ j + 1 ] << 8 );
|
||||
fsize += ( pbase[ j + 2 ] << 16 ) + ( pbase[ j + 3 ] << 24 );
|
||||
j += 4;
|
||||
// Round to a multiple of ROMFS_ALIGN
|
||||
j = ( j + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
|
||||
if( !strncasecmp( fname, fsname, DM_MAX_FNAME_LENGTH ) )
|
||||
// WOFS has an additional WOFS_DEL_FIELD_SIZE bytes before the size as an indication for "file deleted"
|
||||
if( romfsh_is_wofs( pfs ) )
|
||||
{
|
||||
is_deleted = romfsh_read8( j, pfs ) == WOFS_FILE_DELETED;
|
||||
j += WOFS_DEL_FIELD_SIZE;
|
||||
}
|
||||
else
|
||||
is_deleted = 0;
|
||||
// And read the size
|
||||
fsize = romfsh_read8( j, pfs ) + ( romfsh_read8( j + 1, pfs ) << 8 );
|
||||
fsize += ( romfsh_read8( j + 2, pfs ) << 16 ) + ( romfsh_read8( j + 3, pfs ) << 24 );
|
||||
j += ROMFS_SIZE_LEN;
|
||||
if( !strncasecmp( fname, fsname, DM_MAX_FNAME_LENGTH ) && !is_deleted )
|
||||
{
|
||||
// Found the file
|
||||
pfd->baseaddr = j;
|
||||
pfd->offset = 0;
|
||||
pfd->size = fsize;
|
||||
if( pnameaddr )
|
||||
*pnameaddr = n;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
// Move to next file
|
||||
i = j + fsize;
|
||||
// On WOFS, all file names must begin at a multiple of ROMFS_ALIGN
|
||||
if( romfsh_is_wofs( pfs ) )
|
||||
i = ( i + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
|
||||
}
|
||||
*plast = 0;
|
||||
return FS_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
@ -84,25 +138,115 @@ static int romfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
FD tempfs;
|
||||
int i;
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
|
||||
if( romfs_num_fd == ROMFS_MAX_FDS )
|
||||
int must_create = 0;
|
||||
int exists;
|
||||
u8 lflags = ROMFS_FILE_FLAG_READ;
|
||||
u32 firstfree, nameaddr;
|
||||
|
||||
if( romfs_num_fd == TOTAL_MAX_FDS )
|
||||
{
|
||||
r->_errno = ENFILE;
|
||||
return -1;
|
||||
}
|
||||
if( romfs_open_file( path, pfsdata->pbase, &tempfs ) != FS_FILE_OK )
|
||||
// Does the file exist?
|
||||
exists = romfs_open_file( path, &tempfs, pfsdata, &firstfree, &nameaddr ) == FS_FILE_OK;
|
||||
// Now interpret "flags" to set file flags and to check if we should create the file
|
||||
if( flags & O_CREAT )
|
||||
{
|
||||
r->_errno = ENOENT;
|
||||
// If O_CREAT is specified with O_EXCL and the file already exists, return with error
|
||||
if( ( flags & O_EXCL ) && exists )
|
||||
{
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
// Otherwise create the file if it does not exist
|
||||
must_create = !exists;
|
||||
}
|
||||
if( ( flags & O_TRUNC ) && ( flags & ( O_WRONLY | O_RDWR ) ) && exists )
|
||||
{
|
||||
// The file exists, but it must be truncated
|
||||
// In the case of WOFS, this effectively means "create a new file"
|
||||
must_create = 1;
|
||||
}
|
||||
// ROMFS can't create files
|
||||
if( must_create && ( ( pfsdata->flags & ROMFS_FS_FLAG_WO ) == 0 ) )
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
// Decode access mode
|
||||
if( flags & O_WRONLY )
|
||||
lflags = ROMFS_FILE_FLAG_WRITE;
|
||||
else if( flags & O_RDWR )
|
||||
lflags = ROMFS_FILE_FLAG_READ | ROMFS_FILE_FLAG_WRITE;
|
||||
if( flags & O_APPEND )
|
||||
lflags |= ROMFS_FILE_FLAG_APPEND;
|
||||
// If a write access is requested when the file must NOT be created, this
|
||||
// is an error
|
||||
if( ( lflags & ( ROMFS_FILE_FLAG_WRITE | ROMFS_FILE_FLAG_APPEND ) ) && !must_create )
|
||||
{
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
// Do we need to create the file ?
|
||||
if( must_create )
|
||||
{
|
||||
if( exists )
|
||||
{
|
||||
// Invalidate the file first by changing WOFS_DEL_FIELD_SIZE bytes before
|
||||
// the file length to WOFS_FILE_DELETED
|
||||
u8 tempb[] = { WOFS_FILE_DELETED, 0xFF, 0xFF, 0xFF };
|
||||
pfsdata->writef( tempb, tempfs.baseaddr - ROMFS_SIZE_LEN - WOFS_DEL_FIELD_SIZE, WOFS_DEL_FIELD_SIZE, pfsdata );
|
||||
}
|
||||
// Find the last available position by asking romfs_open_file to look for a file
|
||||
// with an invalid name
|
||||
romfs_open_file( "\1", &tempfs, pfsdata, &firstfree, NULL );
|
||||
// Is there enough space on the FS for another file?
|
||||
if( pfsdata->max_size - firstfree + 1 < strlen( path ) + 1 + WOFS_MIN_NEEDED_SIZE + WOFS_DEL_FIELD_SIZE )
|
||||
{
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
// Write the name of the file
|
||||
pfsdata->writef( path, firstfree, strlen( path ) + 1, pfsdata );
|
||||
firstfree += strlen( path ) + 1; // skip over the name
|
||||
// Align to a multiple of ROMFS_ALIGN
|
||||
firstfree = ( firstfree + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
|
||||
firstfree += ROMFS_SIZE_LEN + WOFS_DEL_FIELD_SIZE; // skip over the size and the deleted flags area
|
||||
tempfs.baseaddr = firstfree;
|
||||
tempfs.offset = tempfs.size = 0;
|
||||
}
|
||||
else // File must exist (and was found in the previous 'romfs_open_file' call)
|
||||
{
|
||||
if( !exists )
|
||||
{
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Find a free FD and copy the descriptor information
|
||||
tempfs.flags = lflags;
|
||||
i = romfs_find_empty_fd();
|
||||
memcpy( romfs_fd_table + i, &tempfs, sizeof( FD ) );
|
||||
memcpy( fd_table + i, &tempfs, sizeof( FD ) );
|
||||
romfs_num_fd ++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int romfs_close_r( struct _reent *r, int fd, void *pdata )
|
||||
{
|
||||
FD* pfd = fd_table + fd;
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
u8 temp[ ROMFS_SIZE_LEN ];
|
||||
|
||||
if( pfd->flags & ( ROMFS_FILE_FLAG_WRITE | ROMFS_FILE_FLAG_APPEND ) )
|
||||
{
|
||||
// Write back the size
|
||||
temp[ 0 ] = pfd->size & 0xFF;
|
||||
temp[ 1 ] = ( pfd->size >> 8 ) & 0xFF;
|
||||
temp[ 2 ] = ( pfd->size >> 16 ) & 0xFF;
|
||||
temp[ 3 ] = ( pfd->size >> 24 ) & 0xFF;
|
||||
pfsdata->writef( temp, pfd->baseaddr - ROMFS_SIZE_LEN, ROMFS_SIZE_LEN, pfsdata );
|
||||
}
|
||||
romfs_close_fd( fd );
|
||||
romfs_num_fd --;
|
||||
return 0;
|
||||
@ -110,17 +254,44 @@ static int romfs_close_r( struct _reent *r, int fd, void *pdata )
|
||||
|
||||
static _ssize_t romfs_write_r( struct _reent *r, int fd, const void* ptr, size_t len, void *pdata )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
FD* pfd = fd_table + fd;
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
|
||||
if( ( pfd->flags & ( ROMFS_FILE_FLAG_WRITE | ROMFS_FILE_FLAG_APPEND ) ) == 0 )
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
// Append mode: set the file pointer to the end
|
||||
if( pfd->flags & ROMFS_FILE_FLAG_APPEND )
|
||||
pfd->offset = pfd->size;
|
||||
// Only write at the end of the file!
|
||||
if( pfd->offset != pfd->size )
|
||||
return 0;
|
||||
// Check if we have enough space left on the device. Always keep 1 byte for the final 0xFF
|
||||
if( pfd->baseaddr + pfd->size + len > pfsdata->max_size - 1 )
|
||||
len = pfsdata->max_size - ( pfd->baseaddr + pfd->size ) - 1;
|
||||
pfsdata->writef( ptr, pfd->offset + pfd->baseaddr, len, pfsdata );
|
||||
pfd->offset += len;
|
||||
pfd->size += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static _ssize_t romfs_read_r( struct _reent *r, int fd, void* ptr, size_t len, void *pdata )
|
||||
{
|
||||
FD* pfd = romfs_fd_table + fd;
|
||||
FD* pfd = fd_table + fd;
|
||||
long actlen = fsmin( len, pfd->size - pfd->offset );
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
|
||||
memcpy( ptr, pfsdata->pbase + pfd->offset + pfd->baseaddr, actlen );
|
||||
|
||||
if( ( pfd->flags & ROMFS_FILE_FLAG_READ ) == 0 )
|
||||
{
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if( pfsdata->flags & ROMFS_FS_FLAG_DIRECT )
|
||||
memcpy( ptr, pfsdata->pbase + pfd->offset + pfd->baseaddr, actlen );
|
||||
else
|
||||
actlen = pfsdata->readf( ptr, pfd->offset + pfd->baseaddr, actlen, pfsdata );
|
||||
pfd->offset += actlen;
|
||||
return actlen;
|
||||
}
|
||||
@ -128,7 +299,7 @@ static _ssize_t romfs_read_r( struct _reent *r, int fd, void* ptr, size_t len, v
|
||||
// lseek
|
||||
static off_t romfs_lseek_r( struct _reent *r, int fd, off_t off, int whence, void *pdata )
|
||||
{
|
||||
FD* pfd = romfs_fd_table + fd;
|
||||
FD* pfd = fd_table + fd;
|
||||
u32 newpos = 0;
|
||||
|
||||
switch( whence )
|
||||
@ -175,20 +346,36 @@ static struct dm_dirent* romfs_readdir_r( struct _reent *r, void *d, void *pdata
|
||||
{
|
||||
u32 off = *( u32* )d;
|
||||
struct dm_dirent *pent = &dm_shared_dirent;
|
||||
unsigned j = 0;
|
||||
unsigned j;
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
u8 *pbase = pfsdata->pbase;
|
||||
int is_deleted;
|
||||
|
||||
if( pbase[ off ] == 0xFF )
|
||||
return NULL;
|
||||
while( ( dm_shared_fname[ j ++ ] = pbase[ off ++ ] ) != '\0' );
|
||||
pent->fname = dm_shared_fname;
|
||||
pent->fsize = pbase[ off ] + ( pbase[ off + 1 ] << 8 );
|
||||
pent->fsize += ( pbase[ off + 2 ] << 16 ) + ( pbase[ off + 3 ] << 24 );
|
||||
pent->ftime = 0;
|
||||
off += 4;
|
||||
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
|
||||
*( u32* )d = off + pent->fsize;
|
||||
while( 1 )
|
||||
{
|
||||
if( romfsh_read8( off, pfsdata ) == WOFS_END_MARKER_CHAR )
|
||||
return NULL;
|
||||
j = 0;
|
||||
while( ( dm_shared_fname[ j ++ ] = romfsh_read8( off ++, pfsdata ) ) != '\0' );
|
||||
pent->fname = dm_shared_fname;
|
||||
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
|
||||
if( romfsh_is_wofs( pfsdata ) )
|
||||
{
|
||||
is_deleted = romfsh_read8( off, pfsdata ) == WOFS_FILE_DELETED;
|
||||
off += WOFS_DEL_FIELD_SIZE;
|
||||
}
|
||||
else
|
||||
is_deleted = 0;
|
||||
pent->fsize = romfsh_read8( off, pfsdata ) + ( romfsh_read8( off + 1, pfsdata ) << 8 );
|
||||
pent->fsize += ( romfsh_read8( off + 2, pfsdata ) << 16 ) + ( romfsh_read8( off + 3, pfsdata ) << 24 );
|
||||
pent->ftime = 0;
|
||||
off += ROMFS_SIZE_LEN;
|
||||
off += pent->fsize;
|
||||
if( romfsh_is_wofs( pfsdata ) )
|
||||
off = ( off + ROMFS_ALIGN - 1 ) & ~( ROMFS_ALIGN - 1 );
|
||||
if( !is_deleted )
|
||||
break;
|
||||
}
|
||||
*( u32* )d = off;
|
||||
return pent;
|
||||
}
|
||||
|
||||
@ -202,7 +389,7 @@ static int romfs_closedir_r( struct _reent *r, void *d, void *pdata )
|
||||
// getaddr
|
||||
static const char* romfs_getaddr_r( struct _reent *r, int fd, void *pdata )
|
||||
{
|
||||
FD* pfd = romfs_fd_table + fd;
|
||||
FD* pfd = fd_table + fd;
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
|
||||
if( pfsdata->flags & ROMFS_FS_FLAG_DIRECT )
|
||||
@ -211,7 +398,10 @@ static const char* romfs_getaddr_r( struct _reent *r, int fd, void *pdata )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Our ROMFS device descriptor structure
|
||||
// These functions apply to both ROMFS and WOFS
|
||||
|
||||
static const DM_DEVICE romfs_device =
|
||||
{
|
||||
romfs_open_r, // open
|
||||
@ -225,31 +415,130 @@ static const DM_DEVICE romfs_device =
|
||||
romfs_getaddr_r, // getaddr
|
||||
};
|
||||
|
||||
// ROMFS descriptor
|
||||
// ****************************************************************************
|
||||
// ROMFS instance descriptor
|
||||
|
||||
static const FSDATA romfs_fsdata =
|
||||
{
|
||||
( u8* )romfiles_fs,
|
||||
ROMFS_FS_FLAG_DIRECT
|
||||
ROMFS_FS_FLAG_DIRECT,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof( romfiles_fs )
|
||||
};
|
||||
|
||||
// ****************************************************************************
|
||||
// WOFS functions and instance descriptor for the simulator (testing)
|
||||
|
||||
#if defined( ELUA_CPU_LINUX ) && defined( BUILD_WOFS )
|
||||
static u32 sim_wofs_read( void *to, u32 fromaddr, u32 size, const void *pdata )
|
||||
{
|
||||
hostif_lseek( wofs_sim_fd, ( long )fromaddr, SEEK_SET );
|
||||
return hostif_read( wofs_sim_fd, to, size );
|
||||
}
|
||||
|
||||
static u32 sim_wofs_write( const void *from, u32 toaddr, u32 size, const void *pdata )
|
||||
{
|
||||
hostif_lseek( wofs_sim_fd, ( long )toaddr, SEEK_SET );
|
||||
return hostif_write( wofs_sim_fd, from, size );
|
||||
}
|
||||
|
||||
static const FSDATA wofs_sim_fsdata =
|
||||
{
|
||||
NULL,
|
||||
ROMFS_FS_FLAG_WO,
|
||||
sim_wofs_read,
|
||||
sim_wofs_write,
|
||||
WOFS_SIZE
|
||||
};
|
||||
#endif // #ifdef ELUA_CPU_LINUX
|
||||
|
||||
// ****************************************************************************
|
||||
// WOFS functions and instance descriptor for real hardware
|
||||
|
||||
#if defined( BUILD_WOFS )
|
||||
static u32 sim_wofs_write( const void *from, u32 toaddr, u32 size, const void *pdata )
|
||||
{
|
||||
const FSDATA *pfsdata = ( const FSDATA* )pdata;
|
||||
|
||||
toaddr += ( u32 )pfsdata->pbase;
|
||||
return platform_flash_write( from, toaddr, size );
|
||||
}
|
||||
|
||||
// This must NOT be a const!
|
||||
static FSDATA wofs_fsdata =
|
||||
{
|
||||
NULL,
|
||||
ROMFS_FS_FLAG_WO | ROMFS_FS_FLAG_DIRECT,
|
||||
NULL,
|
||||
sim_wofs_write,
|
||||
0
|
||||
};
|
||||
|
||||
// WOFS formatting function
|
||||
// Returns 1 if OK, 0 for error
|
||||
int wofs_format()
|
||||
{
|
||||
u32 sect_first, sect_last;
|
||||
FD tempfd;
|
||||
|
||||
platform_flash_get_first_free_block_address( §_first );
|
||||
// Get the first free address in WOFS. We use this address to compute the last block that we need to
|
||||
// erase, instead of simply erasing everything from sect_first to the last Flash page.
|
||||
romfs_open_file( "\1", &tempfd, &wofs_fsdata, §_last, NULL );
|
||||
sect_last = platform_flash_get_sector_of_address( sect_last + ( u32 )wofs_fsdata.pbase );
|
||||
while( sect_first <= sect_last )
|
||||
if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_WOFS
|
||||
|
||||
// Initialize both ROMFS and WOFS as needed
|
||||
int romfs_init()
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for( i = 0; i < ROMFS_MAX_FDS; i ++ )
|
||||
for( i = 0; i < TOTAL_MAX_FDS; i ++ )
|
||||
{
|
||||
memset( romfs_fd_table + i, 0xFF, sizeof( FD ) );
|
||||
romfs_fd_table[ i ].flags = 0;
|
||||
memset( fd_table + i, 0xFF, sizeof( FD ) );
|
||||
fd_table[ i ].flags = 0;
|
||||
}
|
||||
return dm_register( "/rom", ( void* )&romfs_fsdata, &romfs_device );
|
||||
#if defined( ELUA_CPU_LINUX ) && defined( BUILD_WOFS )
|
||||
// Initialize and register WOFS for the simulator
|
||||
wofs_sim_fd = hostif_open( WOFS_FNAME, 2, 0666 ); // try to open directly first
|
||||
if( -1 == wofs_sim_fd )
|
||||
{
|
||||
wofs_sim_fd = hostif_open( WOFS_FNAME, 66, 0666) ; // 66 == O_RDWR | O_CREAT
|
||||
u8 temp = WOFS_END_MARKER_CHAR;
|
||||
for( i = 0; i < WOFS_SIZE; i ++ )
|
||||
hostif_write( wofs_sim_fd, &temp, 1 );
|
||||
printf( "SIM_WOFS: creating WOFS file\n" );
|
||||
hostif_close( wofs_sim_fd );
|
||||
wofs_sim_fd = hostif_open( WOFS_FNAME, 2, 0666 );
|
||||
}
|
||||
dm_register( "/wo", ( void* )&wofs_sim_fsdata, &romfs_device );
|
||||
#endif // #if defined( ELUA_CPU_LINUX ) && defined( BUILD_WOFS )
|
||||
#ifdef BUILD_WOFS
|
||||
// Get the start address and size of WOFS and register it
|
||||
wofs_fsdata.pbase = ( u8* )platform_flash_get_first_free_block_address( NULL );
|
||||
wofs_fsdata.max_size = INTERNAL_FLASH_SIZE - ( ( u32 )wofs_fsdata.pbase - INTERNAL_FLASH_START_ADDRESS );
|
||||
dm_register( "/wo", &wofs_fsdata, &romfs_device );
|
||||
#endif // ifdef BUILD_WOFS
|
||||
#ifdef BUILD_ROMFS
|
||||
// Register the ROM filesystem
|
||||
dm_register( "/rom", ( void* )&romfs_fsdata, &romfs_device );
|
||||
#endif // #ifdef BUILD_ROMFS
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_ROMFS
|
||||
#else // #if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )
|
||||
|
||||
int romfs_init()
|
||||
{
|
||||
return dm_register( NULL, NULL, NULL );
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_ROMFS
|
||||
#endif // #if defined( BUILD_ROMFS ) || defined( BUILD_WOFS )
|
||||
|
||||
|
297
src/shell.c
297
src/shell.c
@ -15,6 +15,9 @@
|
||||
#include "remotefs.h"
|
||||
#include "eluarpc.h"
|
||||
#include "linenoise.h"
|
||||
#include "term.h"
|
||||
#include "romfs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined( USE_GIT_REVISION )
|
||||
#include "git_version.h"
|
||||
@ -27,6 +30,7 @@
|
||||
|
||||
// Shell alternate ' ' char
|
||||
#define SHELL_ALT_SPACE '\x07'
|
||||
#define SHELL_MAX_ARGS 10
|
||||
|
||||
// EOF is different in UART mode and TCP/IP mode
|
||||
#ifdef BUILD_CON_GENERIC
|
||||
@ -36,7 +40,7 @@
|
||||
#endif
|
||||
|
||||
// Shell command handler function
|
||||
typedef void( *p_shell_handler )( char* args );
|
||||
typedef void( *p_shell_handler )( int argc, char **argv );
|
||||
|
||||
// Command/handler pair structure
|
||||
typedef struct
|
||||
@ -52,81 +56,47 @@ static char* shell_prog;
|
||||
// Shell functions
|
||||
|
||||
// 'help' handler
|
||||
static void shell_help( char* args )
|
||||
static void shell_help( int argc, char **argv )
|
||||
{
|
||||
args = args;
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
printf( "Shell commands:\n" );
|
||||
printf( " exit - exit from this shell\n" );
|
||||
printf( " help - print this help\n" );
|
||||
printf( " ls or dir - lists filesystems files and sizes\n" );
|
||||
printf( " cat or type - lists file contents\n" );
|
||||
printf( " lua [args] - run Lua with the given arguments\n" );
|
||||
printf( " recv [path] - receive a file via XMODEM, if there is a path, save"
|
||||
" there, otherwise run it.");
|
||||
printf( " recv [path] - receive a file via XMODEM. If path is given save it there, otherwise run it.\n");
|
||||
printf( " cp <src> <dst> - copy source file 'src' to 'dst'\n" );
|
||||
printf( " wofmt - format the internal WOFS\n" );
|
||||
printf( " ver - print eLua version\n" );
|
||||
}
|
||||
|
||||
// 'lua' handler
|
||||
static void shell_lua( char* args )
|
||||
static void shell_lua( int argc, char **argv )
|
||||
{
|
||||
int nargs = 0;
|
||||
char* lua_argv[ SHELL_MAX_LUA_ARGS + 2 ];
|
||||
char *p, *prev, *temp;
|
||||
|
||||
lua_argv[ 0 ] = "lua";
|
||||
// Process "args" if needed
|
||||
if( *args )
|
||||
{
|
||||
prev = args;
|
||||
p = strchr( args, ' ' );
|
||||
while( p )
|
||||
{
|
||||
if( nargs == SHELL_MAX_LUA_ARGS )
|
||||
{
|
||||
printf( "Too many arguments to 'lua' (maxim %d)\n", SHELL_MAX_LUA_ARGS );
|
||||
return;
|
||||
}
|
||||
*p = 0;
|
||||
lua_argv[ nargs + 1 ] = temp = prev;
|
||||
nargs ++;
|
||||
prev = p + 1;
|
||||
p = strchr( p + 1, ' ' );
|
||||
// If the argument is quoted, remove the quotes and transform the 'alternate chars' back to space
|
||||
if( *temp == '\'' || *temp == '"' )
|
||||
{
|
||||
temp ++;
|
||||
lua_argv[ nargs ] = temp;
|
||||
while( *temp )
|
||||
{
|
||||
if( *temp == SHELL_ALT_SPACE )
|
||||
*temp = ' ';
|
||||
temp ++;
|
||||
}
|
||||
*( temp - 1 ) = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_argv[ nargs + 1 ] = NULL;
|
||||
printf( "Press " SHELL_EOF_STRING " to exit Lua\n" );
|
||||
lua_main( nargs + 1, lua_argv );
|
||||
lua_main( argc, argv );
|
||||
clearerr( stdin );
|
||||
}
|
||||
|
||||
// 'recv' handler
|
||||
static void shell_recv( char* args )
|
||||
static void shell_recv( int argc, char **argv )
|
||||
{
|
||||
args = args;
|
||||
|
||||
#ifndef BUILD_XMODEM
|
||||
printf( "XMODEM support not compiled, unable to recv\n" );
|
||||
return;
|
||||
#else // #ifndef BUILD_XMODEM
|
||||
|
||||
char *p;
|
||||
long actsize;
|
||||
lua_State* L;
|
||||
|
||||
if( argc > 2 )
|
||||
{
|
||||
printf( "Usage: recv [path]\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ( shell_prog = malloc( XMODEM_INITIAL_BUFFER_SIZE ) ) == NULL )
|
||||
{
|
||||
printf( "Unable to allocate memory\n" );
|
||||
@ -151,23 +121,21 @@ static void shell_recv( char* args )
|
||||
printf( "done, got %u bytes\n", ( unsigned )( p - shell_prog ) );
|
||||
|
||||
// we've received an argument, try saving it to a file
|
||||
if( strcmp( args, "") != 0 )
|
||||
if( argc == 2 )
|
||||
{
|
||||
if( strchr( args, ' ' ) )
|
||||
*strchr( args, ' ' ) = '\0';
|
||||
FILE *foutput = fopen( args, "w" );
|
||||
FILE *foutput = fopen( argv[ 1 ], "w" );
|
||||
size_t file_sz = p - shell_prog;
|
||||
if( foutput == NULL )
|
||||
{
|
||||
printf( "unable to open file %s\n", args);
|
||||
printf( "unable to open file %s\n", argv[ 1 ] );
|
||||
free( shell_prog );
|
||||
shell_prog = NULL;
|
||||
return;
|
||||
}
|
||||
if( fwrite( shell_prog, sizeof( char ), file_sz, foutput ) == file_sz )
|
||||
printf( "received and saved as %s\n", args );
|
||||
printf( "received and saved as %s\n", argv[ 1 ] );
|
||||
else
|
||||
printf( "disk full, unable to save file %s\n", args );
|
||||
printf( "unable to save file %s (no space left on target?)\n", argv[ 1 ] );
|
||||
fclose( foutput );
|
||||
}
|
||||
else // no arg, running the file with lua.
|
||||
@ -193,15 +161,16 @@ static void shell_recv( char* args )
|
||||
}
|
||||
|
||||
// 'ver' handler
|
||||
static void shell_ver( char* args )
|
||||
static void shell_ver( int argc, char **argv )
|
||||
{
|
||||
args = args;
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
printf( "eLua version %s\n", ELUA_STR_VERSION );
|
||||
printf( "For more information visit www.eluaproject.net and wiki.eluaproject.net\n" );
|
||||
}
|
||||
|
||||
// 'ls' and 'dir' handler
|
||||
static void shell_ls( char* args )
|
||||
static void shell_ls( int argc, char **argv )
|
||||
{
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
unsigned dev, i;
|
||||
@ -209,6 +178,8 @@ static void shell_ls( char* args )
|
||||
struct dm_dirent *ent;
|
||||
u32 total;
|
||||
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
// Iterate through all devices, looking for the ones that can do "opendir"
|
||||
for( dev = 0; dev < dm_get_num_devices(); dev ++ )
|
||||
{
|
||||
@ -236,35 +207,32 @@ static void shell_ls( char* args )
|
||||
}
|
||||
|
||||
// 'cat' and 'type' handler
|
||||
static void shell_cat( char *args )
|
||||
static void shell_cat( int argc, char **argv )
|
||||
{
|
||||
FILE *fp;
|
||||
int c;
|
||||
char *p;
|
||||
unsigned i;
|
||||
|
||||
// *args has an appended space. Replace it with the string terminator.
|
||||
// *(strchr( args, ' ' )) = 0;
|
||||
if ( *args )
|
||||
while ( *args )
|
||||
if( argc < 2 )
|
||||
{
|
||||
printf( "Usage: cat (or type) <filename1> [<filename2> ...]\n" );
|
||||
return;
|
||||
}
|
||||
for( i = 1; i < argc; i ++ )
|
||||
{
|
||||
if( ( fp = fopen( argv[ i ] , "rb" ) ) != NULL )
|
||||
{
|
||||
p = strchr( args, ' ' );
|
||||
*p = 0;
|
||||
if( ( fp = fopen( args , "rb" ) ) != NULL )
|
||||
c = fgetc( fp );
|
||||
while( c != EOF )
|
||||
{
|
||||
printf("%c", (char) c );
|
||||
c = fgetc( fp );
|
||||
while( c != EOF )
|
||||
{
|
||||
printf("%c", (char) c );
|
||||
c = fgetc( fp );
|
||||
}
|
||||
fclose ( fp );
|
||||
}
|
||||
else
|
||||
printf( "File %s not found\n", args );
|
||||
args = p + 1;
|
||||
}
|
||||
else
|
||||
printf( "Usage: cat (or type) <filename1> [<filename2> ...]\n" );
|
||||
fclose ( fp );
|
||||
}
|
||||
else
|
||||
printf( "Unable to open '%s'\n", argv[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
// 'copy' handler
|
||||
@ -273,60 +241,49 @@ static void shell_cat( char *args )
|
||||
#else
|
||||
#define SHELL_COPY_BUFSIZE 256
|
||||
#endif
|
||||
static void shell_cp( char *args )
|
||||
static void shell_cp( int argc, char **argv )
|
||||
{
|
||||
char *p1 = NULL, *p2 = NULL;
|
||||
FILE *fps = NULL, *fpd = NULL;
|
||||
void *buf = NULL;
|
||||
size_t datalen, datawrote, total = 0;
|
||||
|
||||
if( *args )
|
||||
if( argc != 3 )
|
||||
{
|
||||
p1 = strchr( args, ' ' );
|
||||
if( p1 )
|
||||
printf( "Usage: cp <source> <destination>\n" );
|
||||
return;
|
||||
}
|
||||
if( ( fps = fopen( argv[ 1 ], "rb" ) ) == NULL )
|
||||
printf( "Unable to open %s for reading\n", argv[ 1 ] );
|
||||
else
|
||||
{
|
||||
if( ( fpd = fopen( argv[ 2 ], "wb" ) ) == NULL )
|
||||
printf( "Unable to open %s for writing\n", argv[ 2 ] );
|
||||
else
|
||||
{
|
||||
*p1 = 0;
|
||||
p2 = strchr( p1 + 1, ' ' );
|
||||
if( p2 )
|
||||
// Alloc memory
|
||||
if( ( buf = malloc( SHELL_COPY_BUFSIZE ) ) == NULL )
|
||||
printf( "Not enough memory\n" );
|
||||
else
|
||||
{
|
||||
*p2 = 0;
|
||||
// First file is at args, second one at p1 + 1
|
||||
if( ( fps = fopen( args, "rb" ) ) == NULL )
|
||||
printf( "Unable to open %s for reading\n", args );
|
||||
else
|
||||
// Do the actual copy
|
||||
while( 1 )
|
||||
{
|
||||
if( ( fpd = fopen( p1 + 1, "wb" ) ) == NULL )
|
||||
printf( "Unable to open %s for writing\n", p1 + 1 );
|
||||
else
|
||||
datalen = fread( buf, 1, SHELL_COPY_BUFSIZE, fps );
|
||||
datawrote = fwrite( buf, 1, datalen, fpd );
|
||||
if( datawrote < datalen )
|
||||
{
|
||||
// Alloc memory
|
||||
if( ( buf = malloc( SHELL_COPY_BUFSIZE ) ) == NULL )
|
||||
printf( "Not enough memory\n" );
|
||||
else
|
||||
{
|
||||
// Do the actual copy
|
||||
while( 1 )
|
||||
{
|
||||
datalen = fread( buf, 1, SHELL_COPY_BUFSIZE, fps );
|
||||
datawrote = fwrite( buf, 1, datalen, fpd );
|
||||
if( datawrote < datalen )
|
||||
{
|
||||
printf( "Copy error (no space left on target?)\n" );
|
||||
break;
|
||||
}
|
||||
total += datalen;
|
||||
if( datalen < SHELL_COPY_BUFSIZE )
|
||||
break;
|
||||
}
|
||||
printf( "%u bytes copied\n", ( unsigned int )total );
|
||||
}
|
||||
printf( "Copy error (no space left on target?)\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
total += datalen;
|
||||
if( datalen < SHELL_COPY_BUFSIZE )
|
||||
break;
|
||||
}
|
||||
fflush( fpd );
|
||||
printf( "%u bytes copied\n", ( unsigned int )total );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !p1 || !p2 )
|
||||
printf( "Syntax error.\n" );
|
||||
if( fps )
|
||||
fclose( fps );
|
||||
if( fpd )
|
||||
@ -335,6 +292,37 @@ static void shell_cp( char *args )
|
||||
free( buf );
|
||||
}
|
||||
|
||||
// 'wofmt' handler
|
||||
static void shell_wofmt( int argc, char **argv )
|
||||
{
|
||||
#ifndef BUILD_WOFS
|
||||
printf( "WOFS not enabled.\n" );
|
||||
#else // #ifndef BUILD_WOFS
|
||||
int c;
|
||||
|
||||
printf( "Formatting the internal WOFS will DESTROY ALL THE FILES FROM WOFS.\n" );
|
||||
while( 1 )
|
||||
{
|
||||
printf( "Are you sure you want to continue? [y/n] " );
|
||||
c = term_getch( TERM_INPUT_WAIT );
|
||||
printf( "%c\n", isprint( c ) ? c : ' ' );
|
||||
c = tolower( c );
|
||||
if( c == 'n' )
|
||||
return;
|
||||
else if( c == 'y' )
|
||||
break;
|
||||
}
|
||||
printf( "Formatting ... " );
|
||||
if( !wofs_format() )
|
||||
{
|
||||
printf( "\ni*** ERROR ***: unable to erase the internal flash. WOFS might be compromised.\n" );
|
||||
printf( "It is advised to re-flash the eLua image.\n" );
|
||||
}
|
||||
else
|
||||
printf( " done.\n" );
|
||||
#endif // #ifndef BUILD_WOFS
|
||||
}
|
||||
|
||||
// Insert shell commands here
|
||||
static const SHELL_COMMAND shell_commands[] =
|
||||
{
|
||||
@ -348,6 +336,7 @@ static const SHELL_COMMAND shell_commands[] =
|
||||
{ "cat", shell_cat },
|
||||
{ "type", shell_cat },
|
||||
{ "cp", shell_cp },
|
||||
{ "wofmt", shell_wofmt },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
@ -359,11 +348,13 @@ void shell_start()
|
||||
const SHELL_COMMAND* pcmd;
|
||||
int i, inside_quotes;
|
||||
char quote_char;
|
||||
int argc;
|
||||
char *argv[ SHELL_MAX_ARGS ];
|
||||
|
||||
printf( SHELL_WELCOMEMSG, ELUA_STR_VERSION );
|
||||
while( 1 )
|
||||
{
|
||||
while( linenoise_getline( LINENOISE_ID_SHELL, cmd, SHELL_MAXSIZE, SHELL_PROMPT ) == -1 )
|
||||
while( linenoise_getline( LINENOISE_ID_SHELL, cmd, SHELL_MAXSIZE - 1, SHELL_PROMPT ) == -1 )
|
||||
{
|
||||
printf( "\n" );
|
||||
clearerr( stdin );
|
||||
@ -374,11 +365,11 @@ void shell_start()
|
||||
if( cmd[ strlen( cmd ) - 1 ] != '\n' )
|
||||
strcat( cmd, "\n" );
|
||||
|
||||
// Change '\r' and '\n' chars to ' ' to ease processing
|
||||
// Change '\r', '\n' and '\t' chars to ' ' to ease processing
|
||||
p = cmd;
|
||||
while( *p )
|
||||
{
|
||||
if( *p == '\r' || *p == '\n' )
|
||||
if( *p == '\r' || *p == '\n' || *p == '\t' )
|
||||
*p = ' ';
|
||||
p ++;
|
||||
}
|
||||
@ -421,19 +412,57 @@ void shell_start()
|
||||
memmove( temp, temp + 1, strlen( temp ) );
|
||||
p = strchr( p + 1, ' ' );
|
||||
}
|
||||
if( strlen( cmd ) == 1 )
|
||||
if( !strcmp( cmd, " " ) )
|
||||
continue;
|
||||
|
||||
// Look for the first ' ' to separate the command from its args
|
||||
temp = cmd;
|
||||
if( *temp == ' ' )
|
||||
temp ++;
|
||||
if( ( p = strchr( temp, ' ' ) ) == NULL )
|
||||
// Skip over the initial space char if it exists
|
||||
p = cmd;
|
||||
if( *p == ' ' )
|
||||
p ++;
|
||||
|
||||
// Add a final space if it does not exist
|
||||
if( p[ strlen( p ) - 1 ] != ' ' )
|
||||
strcat( p, " " );
|
||||
|
||||
// Compute argc/argv
|
||||
for( argc = 0; argc < SHELL_MAX_ARGS; argc ++ )
|
||||
argv[ argc ] = NULL;
|
||||
argc = 0;
|
||||
while( ( temp = strchr( p, ' ' ) ) != NULL )
|
||||
{
|
||||
printf( SHELL_ERRMSG );
|
||||
continue;
|
||||
*temp = 0;
|
||||
if( argc == SHELL_MAX_ARGS )
|
||||
{
|
||||
printf( "Error: too many arguments\n" );
|
||||
argc = -1;
|
||||
break;
|
||||
}
|
||||
argv[ argc ++ ] = p;
|
||||
p = temp + 1;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
if( argc == -1 )
|
||||
continue;
|
||||
|
||||
// Additional argument processing happens here
|
||||
for( i = 0; i < argc; i ++ )
|
||||
{
|
||||
p = argv[ i ];
|
||||
// Put back spaces if needed
|
||||
for( inside_quotes = 0; inside_quotes < strlen( argv[ i ] ); inside_quotes ++ )
|
||||
{
|
||||
if( p[ inside_quotes ] == SHELL_ALT_SPACE )
|
||||
argv[ i ][ inside_quotes ] = ' ';
|
||||
}
|
||||
// Remove quotes
|
||||
if( ( p[ 0 ] == '\'' || p [ 0 ] == '"' ) && ( p[ 0 ] == p[ strlen( p ) - 1 ] ) )
|
||||
{
|
||||
argv[ i ] = p + 1;
|
||||
p[ strlen( p ) - 1 ] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Match user command with shell's commands
|
||||
i = 0;
|
||||
while( 1 )
|
||||
{
|
||||
@ -443,11 +472,11 @@ void shell_start()
|
||||
printf( SHELL_ERRMSG );
|
||||
break;
|
||||
}
|
||||
if( !strcasecmp( pcmd->cmd, temp ) )
|
||||
if( !strcasecmp( pcmd->cmd, argv[ 0 ] ) )
|
||||
{
|
||||
// Special case: the "exit" command has a NULL handler
|
||||
if( pcmd->handler_func )
|
||||
pcmd->handler_func( p + 1 );
|
||||
pcmd->handler_func( argc, argv );
|
||||
break;
|
||||
}
|
||||
i ++;
|
||||
|
@ -123,22 +123,21 @@ function mkfs( dirname, outname, flist, mode, compcmd )
|
||||
end
|
||||
_add_data( 0, outfile ) -- ASCIIZ
|
||||
local plen = string.pack( "<i", #filedata )
|
||||
-- Round to a multiple of 'alignment'
|
||||
while _bytecnt % alignment ~= 0 do
|
||||
_add_data( 0, outfile )
|
||||
end
|
||||
-- Write size
|
||||
_add_data( plen:byte( 1 ), outfile )
|
||||
_add_data( plen:byte( 2 ), outfile )
|
||||
_add_data( plen:byte( 3 ), outfile )
|
||||
_add_data( plen:byte( 4 ), outfile )
|
||||
-- Round to a multiple of 'alignment'
|
||||
local actual = #filedata
|
||||
while _bytecnt % alignment ~= 0 do
|
||||
_add_data( 0, outfile )
|
||||
actual = actual + 1
|
||||
end
|
||||
-- Then write the rest of the file
|
||||
-- Then write the rest of the file
|
||||
for i = 1, #filedata do
|
||||
_add_data( filedata:byte( i ), outfile )
|
||||
end
|
||||
-- Report
|
||||
print( sf( "Encoded file %s (%d bytes real size, %d bytes after rounding, %d bytes total)", fname, #filedata, actual, _fcnt ) )
|
||||
print( sf( "Encoded file %s (%d bytes real size, %d bytes encoded size)", fname, #filedata, _fcnt ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user