2025-06-18 15:30:14 +08:00

5503 lines
196 KiB
C

/***********************************************************************************************************************
PicoMite MMBasic
FileIO.c
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
Copyright (c) 2021, <COPYRIGHT HOLDERS> All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed
on the console at startup (additional copyright messages may be added).
4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed
by the <copyright holder>.
5. Neither the name of the <copyright holder> nor the names of its contributors may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDERS> AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDERS> BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
************************************************************************************************************************/
/**
* @file FileIO.c
* @author Geoff Graham, Peter Mather
* @brief Source for file handling MMBasic commands and functions
*/
/**
* @cond
* The following section will be excluded from the documentation.
*/
#include "MMBasic_Includes.h"
#include "Hardware_Includes.h"
#include "ff.h"
#include "diskio.h"
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/irq.h"
#include "hardware/gpio.h"
#include "pico/binary_info.h"
#include "hardware/structs/watchdog.h"
#include "hardware/watchdog.h"
#include "hardware/pll.h"
#include "hardware/clocks.h"
#include "hardware/structs/pll.h"
#include "hardware/structs/clocks.h"
#include "sys/stat.h"
#include "picojpeg.h"
#include "hardware/sync.h"
#ifdef PICOMITE
#include "pico/multicore.h"
extern mutex_t frameBufferMutex;
#endif
#ifdef rp2350
#include "hardware/structs/qmi.h"
#endif
extern const uint8_t *flash_target_contents;
extern const uint8_t *flash_option_contents;
extern const uint8_t *SavedVarsFlash;
extern const uint8_t *flash_progmemory;
//LIBRARY
extern const uint8_t *flash_libgmemory;
extern void routinechecks(void);
extern bool mergedread;
extern int TraceOn;
struct option_s __attribute__ ((aligned (256))) Option;
int dirflags;
int GPSfnbr = 0;
int lfs_FileFnbr=0;
int FatFSFileSystem=0; //Assume we are using flash file system
#ifdef rp2350
static uint32_t m1_rfmt;
static uint32_t m1_timing;
static uint32_t m0_rfmt;
static uint32_t m0_timing;
int MemLoadProgram(unsigned char *fname, unsigned char *ram);
#endif
// 8*8*4 bytes * 3 = 768
int16_t *gCoeffBuf;
// 8*8*4 bytes * 3 = 768
uint8_t *gMCUBufR;
uint8_t *gMCUBufG;
uint8_t *gMCUBufB;
// 256 bytes
int16_t *gQuant0;
int16_t *gQuant1;
uint8_t *gHuffVal2;
uint8_t *gHuffVal3;
uint8_t *gInBuf;
#define BLOCK_SIZE 4096
char FlashReadBuffer[256];
char FlashProgBuffer[256];
char FlashLookBuffer[256];
int fs_flash_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
int fs_flash_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
int fs_flash_erase(const struct lfs_config *cfg, lfs_block_t block);
int fs_flash_sync(const struct lfs_config *c);
struct lfs_config pico_lfs_cfg = {
// block device operations
.read = fs_flash_read,
.prog = fs_flash_prog,
.erase = fs_flash_erase,
.sync = fs_flash_sync,
// block device configuration
.read_size = 1,
.prog_size = 256,
.block_size = BLOCK_SIZE,
.block_count = 0,
.block_cycles=500,
.cache_size=256,
.lookahead_size = 256,
.read_buffer = (void *)FlashReadBuffer,
.prog_buffer = (void *)FlashProgBuffer,
.lookahead_buffer = (void *)FlashLookBuffer,
};
volatile union u_flash
{
uint64_t i64[32];
uint8_t i8[256];
uint32_t i32[64];
} MemWord;
volatile int mi8p = 0;
volatile uint32_t realflashpointer;
int FlashLoad = 0;
unsigned char *CFunctionFlash = NULL;
unsigned char *CFunctionLibrary = NULL;
#define SDbufferSize 512
static char *SDbuffer[MAXOPENFILES + 1] = {NULL};
int buffpointer[MAXOPENFILES + 1] = {0};
static uint32_t lastfptr[MAXOPENFILES + 1] = {[0 ... MAXOPENFILES] = -1};
uint8_t fmode[MAXOPENFILES + 1] = {0};
static unsigned int bw[MAXOPENFILES + 1] = {[0 ... MAXOPENFILES] = -1};
unsigned char filesource[MAXOPENFILES + 1] = {0};
char filepath[2][FF_MAX_LFN]={
"A:/",
"B:/"
};
char fullpathname[2][FF_MAX_LFN];
char fullfilepathname[FF_MAX_LFN];
extern BYTE BMP_bDecode(int x, int y, int fnbr);
#define RoundUp(a) (((a) + (sizeof(int) - 1)) & (~(sizeof(int) - 1))) // round up to the nearest integer size [position 27:9]
int resolve_path(char *path, char *result, char *pos);
void getfullpath(char *p, char *q);
void getfullfilepath(char *p, char *q);
void fullpath(char *q);
int FatFSFileSystemSave=0;
#define overlap (VRes % (FontTable[gui_font >> 4][1] * (gui_font & 0b1111)) ? 0 : 1)
#ifdef rp2350
typedef struct sa_dlist {
char from[32];
char to[32];
} a_dlist;
a_dlist *dlist;
int nDefines;
int LineCount=0;
#endif
/******************************************************************************************
Text for the file related error messages reported by MMBasic
******************************************************************************************/
const char* const FErrorMsg[] = {"",
"A hard error occurred in the low level disk I/O layer",
"Assertion failed",
"SD Card not found",
"Could not find the file",
"Could not find the path",
"The path name format is invalid",
"FAccess denied due to prohibited access or directory full",
"Access denied due to prohibited access",
"The file/directory object is invalid",
"The physical drive is write protected",
"The logical drive number is invalid",
"The volume has no work area",
"There is no valid FAT volume",
"The f_mkfs() aborted due to any problem",
"Could not get a grant to access the volume within defined period",
"The operation is rejected according to the file sharing policy",
"LFN working buffer could not be allocated",
"Number of open files > FF_FS_LOCK",
"Given parameter is invalid",
"SD card not present"};
const char* const LFSErrorMsg[]= {
"",
"",
"Could not find the file",
"Could not find the path",
"",
"Error during device operation",
"",
"",
"",
"Bad file number",
"",
"",
"No more memory available",
"",
"",
"",
"",
"Entry already exists",
"",
"",
"Entry is not a dir",
"Entry is a dir",
"Invalid parameter",
"",
"",
"",
"",
"File too large",
"No space left on device",
"",
"",
"",
"",
"",
"",
"",
"File name too long",
"",
"",
"Dir is not empty",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"No data/attr available",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Corrupted"
};
extern BYTE MDD_SDSPI_CardDetectState(void);
extern void InitReservedIO(void);
int ForceFileClose(int fnbr);
int FSerror;
FATFS FatFs;
union uFileTable FileTable[MAXOPENFILES + 1];
volatile BYTE SDCardStat = STA_NOINIT | STA_NODISK;
int OptionFileErrorAbort = true;
volatile uint32_t irqs;
#ifdef rp2350
static void save_psram_settings(void) {
// We're about to invalidate the XIP cache, clean it first to commit any dirty writes to PSRAM
uint8_t *maintenance_ptr = (uint8_t *)XIP_MAINTENANCE_BASE;
for (int i = 1; i < 16 * 1024; i += 8) {
maintenance_ptr[i] = 0;
}
m1_timing = qmi_hw->m[1].timing;
m1_rfmt = qmi_hw->m[1].rfmt;
m0_timing = qmi_hw->m[0].timing;
m0_rfmt = qmi_hw->m[0].rfmt;
}
static void restore_psram_settings(void) {
qmi_hw->m[1].timing = m1_timing;
qmi_hw->m[1].rfmt = m1_rfmt;
qmi_hw->m[0].timing = m0_timing;
qmi_hw->m[0].rfmt = m0_rfmt;
}
#endif
void disable_interrupts_pico(void)
{
#ifdef rp2350
save_psram_settings();
#endif
irqs=save_and_disable_interrupts();
}
void enable_interrupts_pico(void)
{
#ifdef rp2350
restore_psram_settings();
#endif
restore_interrupts(irqs);
SecondsTimer+=(time_us_64()/1000 - mSecTimer);
mSecTimer=time_us_64()/1000;
irqs=0;
}
void ErrorThrow(int e, int type)
{
FatFSFileSystem = FatFSFileSystemSave;
MMerrno = e;
FSerror = e;
if(type==FATFSFILE)strcpy(MMErrMsg, (char *)FErrorMsg[e]);
if(type==FLASHFILE)strcpy(MMErrMsg, (char *)LFSErrorMsg[-e]);
if (e == 1)
{
BYTE s;
s = SDCardStat;
s |= (STA_NODISK | STA_NOINIT);
SDCardStat = s;
memset(&FatFs, 0, sizeof(FatFs));
}
if (e && OptionFileErrorAbort)
error(MMErrMsg);
return;
}
void ResetFlashStorage(int umount){
int boot_count=0;
if(umount)lfs_unmount(&lfs);
FSerror=lfs_format(&lfs, &pico_lfs_cfg);ErrorCheck(0);
FSerror=lfs_mount(&lfs, &pico_lfs_cfg); ErrorCheck(0);
int fnbr = FindFreeFileNbr();
BasicFileOpen("bootcount",fnbr,FA_WRITE | FA_OPEN_APPEND | FA_READ);
FSerror=lfs_file_read(&lfs, FileTable[fnbr].lfsptr, &boot_count, sizeof(boot_count));
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
boot_count+=1;
FSerror=lfs_file_rewind(&lfs, FileTable[fnbr].lfsptr);
ErrorCheck(fnbr);
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, &boot_count, sizeof(boot_count));
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
FileClose(fnbr);
}
int __not_in_flash_func(fs_flash_read)(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size)
{
assert(off % cfg->read_size == 0);
assert(size % cfg->read_size == 0);
assert(block < cfg->block_count);
uint32_t addr = XIP_BASE + RoundUpK4(TOP_OF_SYSTEM_FLASH) + (Option.modbuff ? 1024*Option.modbuffsize : 0) + block*4096 + off;
memcpy(buffer,(char *)addr,size);
return 0;
}
int __not_in_flash_func(fs_flash_prog)(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size)
{
assert(off % cfg->prog_size == 0);
assert(size % cfg->prog_size == 0);
assert(block < cfg->block_count);
uint32_t addr = RoundUpK4(TOP_OF_SYSTEM_FLASH) + (Option.modbuff ? 1024*Option.modbuffsize : 0) + block*4096 + off;
disable_interrupts_pico();
flash_range_program(addr, buffer, size);
enable_interrupts_pico();
return 0;
}
int __not_in_flash_func(fs_flash_erase)(const struct lfs_config *cfg, lfs_block_t block){
assert(block < cfg->block_count);
uint32_t block_addr = RoundUpK4(TOP_OF_SYSTEM_FLASH) + (Option.modbuff ? 1024*Option.modbuffsize : 0) + block*4096;
disable_interrupts_pico();
flash_range_erase(block_addr, BLOCK_SIZE);
enable_interrupts_pico();
return 0;
}
int __not_in_flash_func(fs_flash_sync)(const struct lfs_config *c)
{
return 0;
}
/* @endcond */
void MIPS16 cmd_disk(void){
char *p=(char *)getCstring(cmdline);
char *b=GetTempMemory(STRINGSIZE);
for(int i=0;i<strlen(p);i++)b[i]=toupper(p[i]);
if(strcmp(b, "A:/FORMAT")==0) {
FatFSFileSystem = FatFSFileSystemSave = 0;
ResetFlashStorage(1);
return;
}
if(strcmp(b, "A:")==0) { FatFSFileSystem = FatFSFileSystemSave = 0; return; }
if(strcmp(b, "B:")==0) {
if(!(Option.SD_CS || Option.CombinedCS))error("B: drive not enabled");
FatFSFileSystem = FatFSFileSystemSave = 1;
return;
}
error((char *)"Syntax");
}
#if defined(rp2350) && !defined(PICOMITEWEB)
extern unsigned int mmap[HEAP_MEMORY_SIZE/ PAGESIZE / PAGESPERWORD];
extern unsigned int psmap[7*1024*1024/ PAGESIZE / PAGESPERWORD];
void MIPS16 cmd_psram(void)
{
if(!PSRAMsize)error("PSRAM not enabled");
unsigned char *p;
if ((p = checkstring(cmdline, (unsigned char *)"ERASE ALL")))
{
memset((void *)PSRAMblock, 0, PSRAMblocksize);
}
else if ((p = checkstring(cmdline, (unsigned char *)"ERASE")))
{
int i = getint(p, 1, MAXRAMSLOTS);
uint8_t *j = (uint8_t *)PSRAMblock + ((i - 1) * MAX_PROG_SIZE);
memset(j,0,MAX_PROG_SIZE);
}
else if ((p = checkstring(cmdline, (unsigned char *)"OVERWRITE")))
{
int i = getint(p, 1, MAXRAMSLOTS);
uint8_t *j = (uint8_t *)PSRAMblock + ((i - 1) * MAX_PROG_SIZE);
memset(j,0,MAX_PROG_SIZE);
uint8_t *q = ProgMemory;
memcpy(j,q,MAX_PROG_SIZE);
}
else if ((p = checkstring(cmdline, (unsigned char *)"LIST")))
{
int j, i, k;
int *pp;
getargs(&p, 3, (unsigned char *)",");
if (argc)
{
int i = getint(argv[0], 1, MAXRAMSLOTS);
ProgMemory = (uint8_t *)PSRAMblock + ((i - 1) * MAX_PROG_SIZE);
if(Option.DISPLAY_CONSOLE && (SPIREAD || Option.NoScroll)){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;}
if (argc == 1)
ListProgram(ProgMemory, false);
else if (argc == 3 && checkstring(argv[2], (unsigned char *)"ALL"))
{
ListProgram(ProgMemory, true);
}
else
error("Syntax");
ProgMemory = (unsigned char *)flash_progmemory;
}
else
{
int n=MAXRAMSLOTS;
for (i = 1; i <= n; i++)
{
k = 0;
j = MAX_PROG_SIZE >> 2;
pp = (int *)(PSRAMblock + ((i - 1) * MAX_PROG_SIZE));
while (j--)
if (*pp++ != 0x0)
{
char buff[STRINGSIZE] = {0};
MMPrintString(" RAM Slot ");
PInt(i);
MMPrintString(" in use");
pp--;
if ((unsigned char)*pp == T_NEWLINE)
{
char *p=(char *)pp;
MMPrintString(": \"");
buff[0]='\'';buff[1]='#';
while(buff[0]=='\'' && buff[1]=='#')p=(char *)llist((unsigned char *)buff, (unsigned char *)p);
MMPrintString(buff);
MMPrintString("\"\r\n");
}
else
MMPrintString("\r\n");
k = 1;
break;
}
if (k == 0)
{
MMPrintString(" RAM Slot ");
PInt(i);
MMPrintString(" available\r\n");
}
}
}
}
else if ((p = checkstring(cmdline, (unsigned char *)"FILE LOAD")))
{
int overwrite=0;
getargs(&p,5,(unsigned char *)",");
if(!(argc==3 || argc==5))error("Syntax");
int i = getint(argv[0], 1, MAXRAMSLOTS);
if(argc==5){
if(checkstring(argv[4],(unsigned char *)"O") || checkstring(argv[4],(unsigned char *)"OVERWRITE"))overwrite=1;
else error("Syntax");
}
uint8_t *c = (uint8_t *)(PSRAMblock + ((i - 1) * MAX_PROG_SIZE));
if (*c != 0x0 && overwrite==0) error("Already programmed");
memset(c,0xFF,MAX_PROG_SIZE);
ClearTempMemory();
SaveContext();
MemLoadProgram(argv[2],c);
RestoreContext(false);
}
else if ((p = checkstring(cmdline, (unsigned char *)"SAVE")))
{
int i = getint(p, 1, MAXRAMSLOTS);
uint8_t *c = (uint8_t *)(PSRAMblock + ((i - 1) * MAX_PROG_SIZE));
if (*c != 0x0)
error("Already programmed");
uint8_t *q = ProgMemory;
memcpy(c,q,MAX_PROG_SIZE);
}
else if ((p = checkstring(cmdline, (unsigned char *)"LOAD")))
{
if (CurrentLinePtr)
error("Invalid in program");
int j = (Option.PROG_FLASH_SIZE >> 2), i = getint(p, 1, MAXRAMSLOTS);
disable_interrupts_pico();
flash_range_erase(PROGSTART, MAX_PROG_SIZE);
enable_interrupts_pico();
j = (MAX_PROG_SIZE >> 2);
uSec(250000);
int *pp = (int *)flash_progmemory;
while (j--)
if (*pp++ != 0xFFFFFFFF)
{
error("Erase error");
}
disable_interrupts_pico();
uint8_t *q = (uint8_t *)(PSRAMblock + ((i - 1) * MAX_PROG_SIZE));
uint8_t *writebuff = GetTempMemory(4096);
if (*q == 0xFF)
{
enable_interrupts_pico();
FlashWriteInit(PROGRAM_FLASH);
flash_range_erase(realflashpointer, MAX_PROG_SIZE);
FlashWriteByte(0);
FlashWriteByte(0);
FlashWriteByte(0); // terminate the program in flash
FlashWriteClose();
error("Flash slot empty");
}
for (int k = 0; k < MAX_PROG_SIZE; k += 4096)
{
for (int j = 0; j < 4096; j++)
writebuff[j] = *q++;
flash_range_program((PROGSTART + k), writebuff, 4096);
}
enable_interrupts_pico();
FlashLoad = 0;
}
else if ((p = checkstring(cmdline, (unsigned char *)"CHAIN")))
{
if (!CurrentLinePtr)
error("Invalid at command prompt");
int i = getint(p, 0, MAXRAMSLOTS);
if(i) ProgMemory = (unsigned char *)(PSRAMblock + ((i - 1) * MAX_PROG_SIZE));
else ProgMemory = (unsigned char *)(flash_target_contents + MAXFLASHSLOTS * MAX_PROG_SIZE);
FlashLoad = i;
PrepareProgram(true);
nextstmt = (unsigned char *)ProgMemory;
}
else if ((p = checkstring(cmdline, (unsigned char *)"RUN")))
{
int i = getint(p, 0, MAXRAMSLOTS);
if(i) ProgMemory = (unsigned char *)(uint8_t *)PSRAMblock + ((i - 1) * MAX_PROG_SIZE);
else ProgMemory = (unsigned char *)(flash_target_contents + MAXFLASHSLOTS * MAX_PROG_SIZE);
ClearRuntime(true);
FlashLoad = i;
PrepareProgram(true);
// Create a global constant MM.CMDLINE$ containing the empty string.
// (void) findvar((unsigned char *)"MM.CMDLINE$", V_FIND | V_DIM_VAR | T_CONST);
if(Option.LIBRARY_FLASH_SIZE == MAX_PROG_SIZE) ExecuteProgram(LibMemory); // run anything that might be in the library
nextstmt = (unsigned char *)ProgMemory;
}
else
error("Syntax");
}
#endif
void MIPS16 cmd_flash(void)
{
unsigned char *p;
if ((p = checkstring(cmdline, (unsigned char *)"ERASE ALL")))
{
if (CurrentLinePtr)
error("Invalid in program");
// uint32_t j = FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE;
int k=MAXFLASHSLOTS;
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE )
k--;
uSec(250000);
disable_interrupts_pico();
for (int i = 0; i < k; i++)
{
uint32_t j = FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + (i * MAX_PROG_SIZE);
flash_range_erase(j, MAX_PROG_SIZE);
}
enable_interrupts_pico();
}
else if ((p = checkstring(cmdline, (unsigned char *)"ERASE")))
{
if (CurrentLinePtr)
error("Invalid in program");
int i = getint(p, 1, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
uint32_t j = FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + ((i - 1) * MAX_PROG_SIZE);
uSec(250000);
disable_interrupts_pico();
flash_range_erase(j, MAX_PROG_SIZE);
enable_interrupts_pico();
}
else if ((p = checkstring(cmdline, (unsigned char *)"OVERWRITE")))
{
if (CurrentLinePtr)
error("Invalid in program");
int i = getint(p, 1, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
uint32_t j = FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + ((i - 1) * MAX_PROG_SIZE);
uSec(250000);
disable_interrupts_pico();
flash_range_erase(j, MAX_PROG_SIZE);
enable_interrupts_pico();
j = (MAX_PROG_SIZE >> 2);
uSec(250000);
int *pp = (int *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
while (j--)
if (*pp++ != 0xFFFFFFFF)
{
error("Erase error");
}
disable_interrupts_pico();
uint8_t *q = ProgMemory;
uint8_t *writebuff = GetTempMemory(4096);
for (int k = 0; k < MAX_PROG_SIZE; k += 4096)
{
for (int j = 0; j < 4096; j++)
writebuff[j] = *q++;
flash_range_program(FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + ((i - 1) * MAX_PROG_SIZE + k), writebuff, 4096);
}
enable_interrupts_pico();
}
else if ((p = checkstring(cmdline, (unsigned char *)"LIST")))
{
int j, i, k;
int *pp;
getargs(&p, 3, (unsigned char *)",");
if (argc)
{
int i = getint(argv[0], 1, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
ProgMemory = (unsigned char *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
if(Option.DISPLAY_CONSOLE && (SPIREAD || Option.NoScroll)){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;}
if (argc == 1)
ListProgram(ProgMemory, false);
else if (argc == 3 && checkstring(argv[2], (unsigned char *)"ALL"))
{
ListProgram(ProgMemory, true);
}
else
error("Syntax");
ProgMemory = (unsigned char *)flash_progmemory;
}
else
{
int n=MAXFLASHSLOTS;
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE )
n--;
for (i = 1; i <= n; i++)
{
k = 0;
j = MAX_PROG_SIZE >> 2;
pp = (int *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
while (j--)
if (*pp++ != 0xFFFFFFFF)
{
char buff[STRINGSIZE] = {0};
MMPrintString(" Slot ");
PInt(i);
MMPrintString(" in use");
pp--;
if ((unsigned char)*pp == T_NEWLINE)
{
char *p=(char *)pp;
MMPrintString(": \"");
buff[0]='\'';buff[1]='#';
while(buff[0]=='\'' && buff[1]=='#')p=(char *)llist((unsigned char *)buff, (unsigned char *)p);
MMPrintString(buff);
MMPrintString("\"\r\n");
}
else
MMPrintString("\r\n");
k = 1;
break;
}
if (k == 0)
{
MMPrintString(" Slot ");
PInt(i);
MMPrintString(" available\r\n");
}
}
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE ){
MMPrintString(" Slot ");
PInt(MAXFLASHSLOTS);
MMPrintString(" in use: Library\r\n");
}
}
}
else if ((p = checkstring(cmdline, (unsigned char *)"MODBUFF LOAD")))
{
int fsize;
getargs(&p,1,(unsigned char *)",");
if(!(argc==1))error("Syntax");
int fnbr = FindFreeFileNbr();
if (!InitSDCard()) return;
char *pp = (char *)getFstring(argv[0]);
if (!BasicFileOpen((char *)pp, fnbr, FA_READ)) return;
if(filesource[fnbr]!=FLASHFILE) fsize = f_size(FileTable[fnbr].fptr);
else fsize = lfs_file_size(&lfs,FileTable[fnbr].lfsptr);
if(RoundUpK4(fsize)>1024*Option.modbuffsize)error("File too large for modbuffer");
char *r = GetTempMemory(256);
uint32_t j = RoundUpK4(TOP_OF_SYSTEM_FLASH);
disable_interrupts_pico();
flash_range_erase(j, RoundUpK4(fsize));
enable_interrupts_pico();
while(!FileEOF(fnbr)) {
memset(r,0,256) ;
for(int i=0;i<256;i++) {
if(FileEOF(fnbr))break;
r[i] = FileGetChar(fnbr);
}
disable_interrupts_pico();
flash_range_program(j, (uint8_t *)r, 256);
enable_interrupts_pico();
routinechecks();
j+=256;
}
FileClose(fnbr);
FlashWriteClose();
}
else if ((p = checkstring(cmdline, (unsigned char *)"DISK LOAD")))
{
int fsize,overwrite=0;
getargs(&p,5,(unsigned char *)",");
if(!(argc==3 || argc==5))error("Syntax");
int i = getint(argv[0], 1, MAXFLASHSLOTS);
if(argc==5){
if(checkstring(argv[4],(unsigned char *)"O") || checkstring(argv[4],(unsigned char *)"OVERWRITE"))overwrite=1;
else error("Syntax");
}
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
uint32_t *c = (uint32_t *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
if (*c != 0xFFFFFFFF && overwrite==0) error("Already programmed");
int fnbr = FindFreeFileNbr();
if (!InitSDCard()) return;
char *pp = (char *)getFstring(argv[2]);
if (!BasicFileOpen((char *)pp, fnbr, FA_READ)) return;
if(filesource[fnbr]!=FLASHFILE) fsize = f_size(FileTable[fnbr].fptr);
else fsize = lfs_file_size(&lfs,FileTable[fnbr].lfsptr);
if(fsize>MAX_PROG_SIZE)error("File size % cannot exceed %",fsize,MAX_PROG_SIZE);
FlashWriteInit(i);
flash_range_erase(realflashpointer, MAX_PROG_SIZE);
int j=MAX_PROG_SIZE/4;
int *ppp=(int *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
while(j--)if(*ppp++ != 0xFFFFFFFF){
enable_interrupts_pico();
error("Flash erase problem");
}
for(int k = 0; k < fsize; k++){ // write to the flash byte by byte
FlashWriteByte(FileGetChar(fnbr));
}
FileClose(fnbr);
FlashWriteClose();
}
else if ((p = checkstring(cmdline, (unsigned char *)"SAVE")))
{
if (CurrentLinePtr)
error("Invalid in program");
int i = getint(p, 1, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
uint32_t *c = (uint32_t *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
if (*c != 0xFFFFFFFF)
error("Already programmed");
;
uint32_t j = FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + ((i - 1) * MAX_PROG_SIZE);
uSec(250000);
disable_interrupts_pico();
flash_range_erase(j, MAX_PROG_SIZE);
enable_interrupts_pico();
j = (MAX_PROG_SIZE >> 2);
uSec(250000);
int *pp = (int *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
while (j--)
if (*pp++ != 0xFFFFFFFF)
{
error("Erase error");
}
disable_interrupts_pico();
uint8_t *q = (uint8_t *)ProgMemory;
uint8_t *writebuff = (uint8_t *)GetTempMemory(4096);
for (int k = 0; k < MAX_PROG_SIZE; k += 4096)
{
for (int j = 0; j < 4096; j++)
writebuff[j] = *q++;
flash_range_program(FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + ((i - 1) * MAX_PROG_SIZE + k), (uint8_t *)writebuff, 4096);
}
enable_interrupts_pico();
}
else if ((p = checkstring(cmdline, (unsigned char *)"LOAD")))
{
if (CurrentLinePtr)
error("Invalid in program");
int j = (Option.PROG_FLASH_SIZE >> 2), i = getint(p, 1, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
disable_interrupts_pico();
flash_range_erase(PROGSTART, MAX_PROG_SIZE);
enable_interrupts_pico();
j = (MAX_PROG_SIZE >> 2);
uSec(250000);
int *pp = (int *)flash_progmemory;
while (j--)
if (*pp++ != 0xFFFFFFFF)
{
error("Erase error");
}
disable_interrupts_pico();
uint8_t *q = (uint8_t *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
uint8_t *writebuff = GetTempMemory(4096);
if (*q == 0xFF)
{
enable_interrupts_pico();
FlashWriteInit(PROGRAM_FLASH);
flash_range_erase(realflashpointer, MAX_PROG_SIZE);
FlashWriteByte(0);
FlashWriteByte(0);
FlashWriteByte(0); // terminate the program in flash
FlashWriteClose();
error("Flash slot empty");
}
for (int k = 0; k < MAX_PROG_SIZE; k += 4096)
{
for (int j = 0; j < 4096; j++)
writebuff[j] = *q++;
flash_range_program((PROGSTART + k), writebuff, 4096);
}
enable_interrupts_pico();
FlashLoad = 0;
}
else if ((p = checkstring(cmdline, (unsigned char *)"CHAIN")))
{
if (!CurrentLinePtr)
error("Invalid at command prompt");
int i = getint(p, 0, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
if(i) ProgMemory = (unsigned char *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
else ProgMemory = (unsigned char *)(flash_target_contents + MAXFLASHSLOTS * MAX_PROG_SIZE);
FlashLoad = i;
PrepareProgram(true);
nextstmt = (unsigned char *)ProgMemory;
}
else if ((p = checkstring(cmdline, (unsigned char *)"RUN")))
{
int i = getint(p, 0, MAXFLASHSLOTS);
if(Option.LIBRARY_FLASH_SIZE==MAX_PROG_SIZE && i==MAXFLASHSLOTS) error("Library is using Slot % ",MAXFLASHSLOTS);
if(i) ProgMemory = (unsigned char *)(flash_target_contents + (i - 1) * MAX_PROG_SIZE);
else ProgMemory = (unsigned char *)(flash_target_contents + MAXFLASHSLOTS * MAX_PROG_SIZE);
ClearRuntime(true);
FlashLoad = i;
PrepareProgram(true);
// Create a global constant MM.CMDLINE$ containing the empty string.
// (void) findvar((unsigned char *)"MM.CMDLINE$", V_FIND | V_DIM_VAR | T_CONST);
if(Option.LIBRARY_FLASH_SIZE == MAX_PROG_SIZE) ExecuteProgram(LibMemory); // run anything that might be in the library
nextstmt = (unsigned char *)ProgMemory;
}
else
error("Syntax");
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
void ErrorCheck(int fnbr)
{ // checks for an error, if fnbr is specified frees up the filehandle before sending error
int e;
e = (int)FSerror;
if (fnbr != 0 && e != 0)
ForceFileClose(fnbr);
if (e >= 1 && e <= 19)
ErrorThrow(e, FATFSFILE);
if (e<0 && e>=-84)
ErrorThrow(e, FLASHFILE);
return;
}
char *GetCWD(void)
{
char *b;
b = GetTempMemory(STRINGSIZE);
if(FatFSFileSystem){
if (!InitSDCard())
return b;
FSerror = f_getcwd(b, STRINGSIZE);
ErrorCheck(0);
return &b[1];
} else {
fullpath("");
strcpy(b,"A:");
strcat(b,fullpathname[FatFSFileSystem]);
return b;
}
}
/* @endcond */
void cmd_LoadImage(unsigned char *p)
{
int fnbr;
int xOrigin, yOrigin;
// get the command line arguments
getargs(&p, 5, (unsigned char *)","); // this MUST be the first executable line in the function
if (argc == 0)
error("Argument count");
if (!InitSDCard())
return;
p = getFstring(argv[0]); // get the file name
xOrigin = yOrigin = 0;
if (argc >= 3)
xOrigin = getinteger(argv[2]); // get the x origin (optional) argument
if (argc == 5)
yOrigin = getinteger(argv[4]); // get the y origin (optional) argument
// open the file
if (strchr((char *)p, '.') == NULL)
strcat((char *)p, ".bmp");
fnbr = FindFreeFileNbr();
if (!BasicFileOpen((char *)p, fnbr, FA_READ))
return;
BMP_bDecode(xOrigin, yOrigin, fnbr);
FileClose(fnbr);
if (Option.Refresh)
Display_Refresh();
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
static uint g_nInFileSize;
static uint g_nInFileOfs;
static int jpgfnbr;
unsigned char pjpeg_need_bytes_callback(unsigned char *pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data)
{
uint n, n_read;
// pCallback_data;
n = min(g_nInFileSize - g_nInFileOfs, buf_size);
if(filesource[jpgfnbr]!=FLASHFILE) f_read(FileTable[jpgfnbr].fptr, pBuf, n, &n_read);
else n_read=lfs_file_read(&lfs, FileTable[jpgfnbr].lfsptr, pBuf, n);
if (n != n_read)
return PJPG_STREAM_READ_ERROR;
*pBytes_actually_read = (unsigned char)(n);
g_nInFileOfs += n;
return 0;
}
/* @endcond */
void cmd_LoadJPGImage(unsigned char *p)
{
pjpeg_image_info_t image_info;
int mcu_x = 0;
int mcu_y = 0;
uint row_pitch;
uint8_t status;
gCoeffBuf = (int16_t *)GetTempMemory(8 * 8 * sizeof(int16_t));
gMCUBufR = (uint8_t *)GetTempMemory(256);
gMCUBufG = (uint8_t *)GetTempMemory(256);
gMCUBufB = (uint8_t *)GetTempMemory(256);
gQuant0 = (int16_t *)GetTempMemory(8 * 8 * sizeof(int16_t));
gQuant1 = (int16_t *)GetTempMemory(8 * 8 * sizeof(int16_t));
gHuffVal2 = (uint8_t *)GetTempMemory(256);
gHuffVal3 = (uint8_t *)GetTempMemory(256);
gInBuf = (uint8_t *)GetTempMemory(PJPG_MAX_IN_BUF_SIZE);
g_nInFileSize = g_nInFileOfs = 0;
// uint decoded_width, decoded_height;
int xOrigin, yOrigin;
// get the command line arguments
getargs(&p, 5, (unsigned char *)","); // this MUST be the first executable line in the function
if (argc == 0)
error("Argument count");
if (!InitSDCard())
return;
p = getFstring(argv[0]); // get the file name
xOrigin = yOrigin = 0;
if (argc >= 3)
xOrigin = getint(argv[2], 0, HRes - 1); // get the x origin (optional) argument
if (argc == 5)
yOrigin = getint(argv[4], 0, VRes - 1); // get the y origin (optional) argument
// open the file
if (strchr((char *)p, '.') == NULL)
strcat((char *)p, ".jpg");
jpgfnbr = FindFreeFileNbr();
if (!BasicFileOpen((char *)p, jpgfnbr, FA_READ))
return;
if(filesource[jpgfnbr]!=FLASHFILE) g_nInFileSize = f_size(FileTable[jpgfnbr].fptr);
else g_nInFileSize = lfs_file_size(&lfs,FileTable[jpgfnbr].lfsptr);
status = pjpeg_decode_init(&image_info, pjpeg_need_bytes_callback, NULL, 0);
if (status)
{
if (status == PJPG_UNSUPPORTED_MODE)
{
FileClose(jpgfnbr);
error("Progressive JPEG files are not supported");
}
FileClose(jpgfnbr);
error("pjpeg_decode_init() failed with status %", status);
}
// decoded_width = image_info.m_width;
// decoded_height = image_info.m_height;
row_pitch = image_info.m_MCUWidth * image_info.m_comps;
unsigned char *imageblock = GetTempMemory(image_info.m_MCUHeight * image_info.m_MCUWidth * image_info.m_comps);
for (;;)
{
uint8_t *pDst_row = imageblock;
int y, x;
status = pjpeg_decode_mcu();
if (status)
{
if (status != PJPG_NO_MORE_BLOCKS)
{
FileClose(jpgfnbr);
error("pjpeg_decode_mcu() failed with status %", status);
}
break;
}
if (mcu_y >= image_info.m_MCUSPerCol)
{
FileClose(jpgfnbr);
return;
}
/* for(int i=0;i<image_info.m_MCUHeight*image_info.m_MCUWidth ;i++){
imageblock[i*3+2]=image_info.m_pMCUBufR[i];
imageblock[i*3+1]=image_info.m_pMCUBufG[i];
imageblock[i*3]=image_info.m_pMCUBufB[i];
}*/
// pDst_row = pImage + (mcu_y * image_info.m_MCUHeight) * row_pitch + (mcu_x * image_info.m_MCUWidth * image_info.m_comps);
for (y = 0; y < image_info.m_MCUHeight; y += 8)
{
const int by_limit = min(8, image_info.m_height - (mcu_y * image_info.m_MCUHeight + y));
for (x = 0; x < image_info.m_MCUWidth; x += 8)
{
uint8_t *pDst_block = pDst_row + x * image_info.m_comps;
// Compute source byte offset of the block in the decoder's MCU buffer.
uint src_ofs = (x * 8U) + (y * 16U);
const uint8_t *pSrcR = image_info.m_pMCUBufR + src_ofs;
const uint8_t *pSrcG = image_info.m_pMCUBufG + src_ofs;
const uint8_t *pSrcB = image_info.m_pMCUBufB + src_ofs;
const int bx_limit = min(8, image_info.m_width - (mcu_x * image_info.m_MCUWidth + x));
{
int bx, by;
for (by = 0; by < by_limit; by++)
{
uint8_t *pDst = pDst_block;
for (bx = 0; bx < bx_limit; bx++)
{
pDst[2] = *pSrcR++;
pDst[1] = *pSrcG++;
pDst[0] = *pSrcB++;
pDst += 3;
}
pSrcR += (8 - bx_limit);
pSrcG += (8 - bx_limit);
pSrcB += (8 - bx_limit);
pDst_block += row_pitch;
}
}
}
pDst_row += (row_pitch * 8);
}
x = mcu_x * image_info.m_MCUWidth + xOrigin;
y = mcu_y * image_info.m_MCUHeight + yOrigin;
if (y < VRes && x < HRes)
{
int yend = min(VRes - 1, y + image_info.m_MCUHeight - 1);
int xend = min(HRes - 1, x + image_info.m_MCUWidth - 1);
if (xend < x + image_info.m_MCUWidth - 1)
{
// need to get rid of some pixels to remove artifacts
xend = HRes - 1;
unsigned char *s = imageblock;
unsigned char *d = imageblock;
for (int yp = 0; yp < image_info.m_MCUHeight; yp++)
{
for (int xp = 0; xp < image_info.m_MCUWidth; xp++)
{
if (xp < xend - x + 1)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
else
{
s += 3;
}
}
}
}
if(yend>=yOrigin+image_info.m_height)yend=yOrigin+image_info.m_height-1;
if(xend>=xOrigin+image_info.m_width){
for(int yi=y;yi<yend;yi++){
uint8_t *ipoint=imageblock+3*image_info.m_MCUWidth*(yi-y);
DrawBuffer(x, yi, xOrigin+image_info.m_width-1, yi, ipoint);
}
} else DrawBuffer(x, y, xend, yend, imageblock);
}
if (y >= VRes)
{ // nothing useful left to process
FileClose(jpgfnbr);
if (Option.Refresh)
Display_Refresh();
return;
}
mcu_x++;
if (mcu_x == image_info.m_MCUSPerRow)
{
mcu_x = 0;
mcu_y++;
}
}
FileClose(jpgfnbr);
#ifdef USBKEYBOARD
clearrepeat();
#endif
if (Option.Refresh)
Display_Refresh();
}
// search for a volume label, directory or file
// s$ = DIR$(fspec, DIR|FILE|ALL) will return the first entry
// s$ = DIR$() will return the next
// If s$ is empty then no (more) files found
void fun_dir(void)
{
static DIR djd;
static FILINFO fnod;
static char pp[FF_MAX_LFN];
static char path[FF_MAX_LFN];
static int FSsave;
static lfs_dir_t lfs_dir_dir;
struct lfs_info lfs_info_dir;
unsigned char *p;
getargs(&ep, 3, (unsigned char *)",");
if (argc != 0)
dirflags = -1;
if (!(argc <= 3))
error("Syntax");
if (argc == 3)
{
if (checkstring(argv[2], (unsigned char *)"DIR"))
dirflags = AM_DIR;
else if (checkstring(argv[2], (unsigned char *)"FILE"))
dirflags = -1;
else if (checkstring(argv[2], (unsigned char *)"ALL"))
dirflags = 0;
else
error("Invalid flag specification");
}
if (argc != 0)
{
memset(pp,0,FF_MAX_LFN);
memset(path,0,FF_MAX_LFN);
memset(&djd, 0, sizeof(DIR));
memset(&fnod, 0, sizeof(FILINFO));
// this must be the first call eg: DIR$("*.*", FILE)
p = getFstring(argv[0]);
char fullfilename[FF_MAX_LFN]={0};
getfullfilename((char *)p,(char *)fullfilename);
FSsave=FatFSFileSystem;
int i = strlen(fullfilename) - 1;
while (i > 1 && !(fullfilename[i] == '/')) i--;
if(i>1){
memcpy(path,fullfilename,i);
strcpy(pp,&fullfilename[i+1]);
} else {
strcpy(pp,&fullfilename[1]);
}
if(!(*pp))*pp='*';
if(!(*path))*path='/';
djd.pat = pp;
if (!InitSDCard())
return; // setup the SD card
if(FSsave==1)FSerror = f_opendir(&djd, path);
else FSerror=lfs_dir_open(&lfs, &lfs_dir_dir, path);
ErrorCheck(0);
}
if (SDCardStat & STA_NOINIT && FSsave==1)
{
f_closedir(&djd);
error("SD card not found");
}
if (dirflags == AM_DIR)
{
for (;;)
{
if(FSsave==1){
FSerror = f_readdir(&djd, &fnod); // Get a directory item
if (FSerror != FR_OK || !fnod.fname[0])
break; // Terminate if any error or end of directory
if (pattern_matching(pp, fnod.fname, 0, 0) && (fnod.fattrib & AM_DIR) && !(fnod.fattrib & AM_SYS))
break; // Test for the file name
} else {
FSerror=lfs_dir_read(&lfs, &lfs_dir_dir, &lfs_info_dir);
strcpy(fnod.fname,lfs_info_dir.name);
if(FSerror==0)
break;
if (lfs_info_dir.type==LFS_TYPE_DIR && pattern_matching(pp, lfs_info_dir.name, 0, 0) && !(strcmp(lfs_info_dir.name,".")==0 || strcmp(lfs_info_dir.name,"..")==0 )){
break;
}
}
}
}
else if (dirflags == -1)
{
for (;;)
{
if(FSsave==1){
FSerror = f_readdir(&djd, &fnod); // Get a directory item
if (FSerror != FR_OK || !fnod.fname[0])
break; // Terminate if any error or end of directory
if (pattern_matching(pp, fnod.fname, 0, 0) && !(fnod.fattrib & AM_DIR) && !(fnod.fattrib & AM_SYS))
break; // Test for the file name
} else {
FSerror=lfs_dir_read(&lfs, &lfs_dir_dir, &lfs_info_dir);
strcpy(fnod.fname,lfs_info_dir.name);
if(FSerror==0)
break;
if (lfs_info_dir.type==LFS_TYPE_REG && pattern_matching(pp, lfs_info_dir.name, 0, 0)){
break;
}
}
}
}
else
{
for (;;)
{
if(FSsave==1){
FSerror = f_readdir(&djd, &fnod); // Get a directory item
if (FSerror != FR_OK || !fnod.fname[0])
break; // Terminate if any error or end of directory
if (pattern_matching(pp, fnod.fname, 0, 0) && !(fnod.fattrib & AM_SYS))
break; // Test for the file name
} else {
FSerror=lfs_dir_read(&lfs, &lfs_dir_dir, &lfs_info_dir);
strcpy(fnod.fname,lfs_info_dir.name);
if(FSerror==0)
break;
if (lfs_info_dir.type & (LFS_TYPE_REG | LFS_TYPE_DIR) && pattern_matching(pp, lfs_info_dir.name, 0, 0) && !(strcmp(lfs_info_dir.name,".")==0 || strcmp(lfs_info_dir.name,"..")==0 )){
break;
}
}
}
}
if (FSerror != FR_OK || !fnod.fname[0]){
if(FSsave==1)f_closedir(&djd);
else lfs_dir_close(&lfs, &lfs_dir_dir);
}
sret = GetTempMemory(STRINGSIZE); // this will last for the life of the command
strcpy((char *)sret, fnod.fname);
CtoM(sret); // convert to a MMBasic style string
FatFSFileSystem=FatFSFileSystemSave;
targ = T_STR;
}
void MIPS16 cmd_mkdir(void)
{
char *p;
int i;
char q[FF_MAX_LFN]={0};
p = (char *)getFstring(cmdline); // get the directory name and convert to a standard C string
if(drivecheck(p,&i)!=FatFSFileSystem+1) error("Only valid on current drive");
getfullpath(p,q);
if(FatFSFileSystem){
if (!InitSDCard())
return;
FSerror = f_mkdir(q);
ErrorCheck(0);
} else {
FSerror=lfs_mkdir(&lfs, q);
ErrorCheck(0);
}
}
void MIPS16 cmd_rmdir(void)
{
char *p;
int i;
char q[FF_MAX_LFN]={0};
p = (char *)getFstring(cmdline); // get the directory name and convert to a standard C string
if(drivecheck(p,&i)!=FatFSFileSystem+1) error("Only valid on current drive");
getfullpath(p,q);
if(FatFSFileSystem){
if (!InitSDCard())
return;
FSerror = f_unlink(q);
ErrorCheck(0);
} else {
FSerror=lfs_remove(&lfs, q);
ErrorCheck(0);
}
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
void chdir(char *p){
int i;
char rp[STRINGSIZE],oldfilepath[STRINGSIZE];
if(drivecheck(p,&i)!=FatFSFileSystem+1) error("Only valid on current drive");
if(strcmp(p,".")==0)return; //nothing to do
if(strlen(p)==0)return;//nothing to do
strcpy(oldfilepath,filepath[FatFSFileSystem]); //save the path in case the change of directory fails
if(p[1]==':'){ //modify the requested path so that if the disk is specified the pathname is absolute and starts with /
if(p[2]=='/')p+=2;
else {
p[1]='/';
p++;
}
}
if (*p=='/'){ //absolute path specified
strcpy(rp,FatFSFileSystem==0? "A:":"B:");
strcat(rp,p);
} else { // relative path specified
strcpy(rp,filepath[FatFSFileSystem]); //copy the current pathname
if(rp[strlen(rp)-1]!='/') strcat(rp,"/"); //make sure the previous pathname ends in slash, will only be the case at root
strcat(rp,p); //append the new pathname
}
strcpy(filepath[FatFSFileSystem],rp); //set the new pathname
resolve_path(filepath[FatFSFileSystem],rp,rp); //resolve to single absolute path
if(strcmp(rp,"A:")==0 || strcmp(rp,"B:")==0 )strcat(rp,"/"); //if root append the slash
strcpy(filepath[FatFSFileSystem],rp); //store this back to the filepath variable
if(!InitSDCard()) { //If no disk restore the old path and return
strcpy(filepath[FatFSFileSystem],oldfilepath);
return;
}
// MMPrintString(filepath[FatFSFileSystem]);
if(FatFSFileSystem)FSerror = f_chdir(&filepath[FatFSFileSystem][2]); //finally change directory always using an absolute pathname
else {
if(filepath[FatFSFileSystem][3]==0)FSerror=lfs_dir_open(&lfs, &lfs_dir, "/");
else FSerror=lfs_dir_open(&lfs, &lfs_dir, &filepath[FatFSFileSystem][3]);
if(!FSerror)lfs_dir_close(&lfs, &lfs_dir);
}
if(FSerror==-2)FSerror=-3;
if(FSerror)strcpy(filepath[FatFSFileSystem],oldfilepath); //if it didn't work restore the original path
ErrorCheck(0); // error if the pathname was invalid
}
/* @endcond */
void cmd_chdir(void){
char *p;
p = (char *)getFstring(cmdline); // get the directory name and convert to a standard C string
chdir(p);
}
void fun_cwd(void)
{
sret = CtoM((unsigned char *)GetCWD());
targ = T_STR;
}
void MIPS16 cmd_kill(void)
{
char q[FF_MAX_LFN]={0};
getargs(&cmdline,3,(unsigned char *)",");
char *tp = (char *)getFstring(argv[0]);
if(strchr(tp,'*') || strchr(tp,'?')){
// char *fromfile;
char fromdir[FF_MAX_LFN]={0};
int fromfilesystem;
char *in=GetTempMemory(STRINGSIZE);
int localsave=FatFSFileSystem;
int all=0;
int waste=0, t=FatFSFileSystem+1;
t = drivecheck(tp,&waste);
tp+=waste;
tp[0]='"';
FatFSFileSystem=t-1;
int i;
// int fcnt, sortorder = 0;
char pp[FF_MAX_LFN] = {0};
char q[FF_MAX_LFN] = {0};
DIR djd;
FILINFO fnod;
memset((void *)&djd, 0, sizeof(DIR));
memset((void *)&fnod, 0, sizeof(FILINFO));
char *p = (char *)getFstring(argv[0]);
i = strlen(p) - 1;
while (i > 0 && !(p[i] == '/'))
i--;
if (i > 0)
{
memcpy(q, p, i);
if (q[1] == ':')
q[0] = '0';
i++;
}
strcpy(pp, &p[i]);
if ((pp[0] == '/') && i == 0)
{
strcpy(q, &pp[1]);
strcpy(pp, q);
strcpy(q, "0:/");
}
if (pp[0] == 0)
strcpy(pp, "*");
if (CurrentLinePtr)
error("Invalid in a program");
FatFSFileSystem=t-1;
if (!InitSDCard())
error((char *)FErrorMsg[20]); // setup the SD card
FatFSFileSystem=t-1;
fullpath(q);
if(!(ExistsDir(fullpathname[FatFSFileSystem],fromdir,&fromfilesystem))){
FatFSFileSystem=localsave;
error("$ not a directory",fromdir);
}
if(argc==3 && checkstring(argv[2],(unsigned char *)"ALL")){
all=1;
MMPrintString("Deleting ");MMPrintString(pp);MMPrintString(" from ");
MMPrintString(fromfilesystem==1 ? "B:" : "A:"); MMPrintString(fromdir);
MMPrintString("\r\nAre you sure ? (Y/N) ");
while(1){
i=toupper(MMInkey());
if(i=='Y' || i=='N')putConsole(i,1);
if(i=='Y')break;
if(i=='N'){
PRet();
FatFSFileSystem=localsave;
return;
}
}
PRet();
}
if(fromfilesystem==0) FSerror=lfs_dir_open(&lfs, &lfs_dir, fromdir);
else FSerror = f_findfirst(&djd, &fnod, fromdir, pp);
ErrorCheck(0);
if(fromfilesystem){
while (FSerror == FR_OK && fnod.fname[0])
{
if (!(fnod.fattrib & (AM_SYS | AM_HID | AM_DIR)))
{
// add a prefix to each line so that directories will sort ahead of files
// and concatenate the filename found
MMPrintString("Deleting ");
MMPrintString(fnod.fname);
if(!all) {
MMPrintString(" ? (Y/N) ");
while(1){
i=toupper(MMInkey());
if(i=='Y' || i=='N'){
putConsole(i,1);
break;
}
}
}
PRet();
if(i=='Y' || all){
strcpy(in,fromdir);
if(in[strlen(in)-1]!='/')strcat(in,"/");
strcat(in,fnod.fname);
FSerror = f_unlink(in);
ErrorCheck(0);
}
}
FSerror = f_findnext(&djd, &fnod);
}
} else {
while(1){
int found=0;
FSerror=lfs_dir_read(&lfs, &lfs_dir, &lfs_info);
if(FSerror==0)break;
if(FSerror<0)ErrorCheck(0);
if (lfs_info.type==LFS_TYPE_DIR && pattern_matching(pp, lfs_info.name, 0, 0))
{
continue;
}
else if (lfs_info.type==LFS_TYPE_REG && pattern_matching(pp, lfs_info.name, 0, 0))
{
found=1;
}
if(found){
// and concatenate the filename found
MMPrintString("Deleting ");
MMPrintString(lfs_info.name);
if(!all){
MMPrintString(" ? (Y/N) ");
while(1){
i=toupper(MMInkey());
if(i=='Y' || i=='N'){
putConsole(i,1);
break;
}
}
}
PRet();
if(i=='Y' || all){
strcpy(in,fromdir);
if(in[strlen(in)-1]!='/')strcat(in,"/");
strcat(in,lfs_info.name);
FSerror=lfs_remove(&lfs, in); ErrorCheck(0);
}
}
}
}
if(fromfilesystem) f_closedir(&djd);
else lfs_dir_close(&lfs, &lfs_dir);
FatFSFileSystem=FatFSFileSystemSave;
} else {
// int localsave=FatFSFileSystem;
int waste=0, t=FatFSFileSystem+1;
t = drivecheck(tp,&waste);
tp+=waste;
FatFSFileSystem=t-1;
getfullfilepath(tp,q);
if(!FatFSFileSystem){
FSerror=lfs_remove(&lfs, q); ErrorCheck(0);
} else {
if (!InitSDCard()) return;
FSerror = f_unlink(q);
ErrorCheck(0);
}
FatFSFileSystem=FatFSFileSystemSave;
}
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
void positionfile(int fnbr, int idx){
char *buff;
if(filesource[fnbr]==FLASHFILE){
// if(idx>FileTable[fnbr].lfsptr->ctz.size)idx=FileTable[fnbr].lfsptr->ctz.size;
FSerror = lfs_file_seek(&lfs, FileTable[fnbr].lfsptr, idx, LFS_SEEK_SET);
if(FSerror<0)ErrorCheck(fnbr);
} else {
if (fmode[fnbr] & FA_WRITE)
{
FSerror = f_lseek(FileTable[fnbr].fptr, idx);
ErrorCheck(fnbr);
}
else
{
buff = SDbuffer[fnbr];
FSerror = f_lseek(FileTable[fnbr].fptr, idx - (idx % 512));
ErrorCheck(fnbr);
FSerror = f_read(FileTable[fnbr].fptr, buff, SDbufferSize, &bw[fnbr]);
ErrorCheck(fnbr);
buffpointer[fnbr] = idx % 512;
lastfptr[fnbr] = (uint32_t)FileTable[fnbr].fptr;
}
}
}
/* @endcond */
void cmd_seek(void)
{
int fnbr, idx;
getargs(&cmdline, 5, (unsigned char *)",");
if (argc != 3)
error("Syntax");
if (*argv[0] == '#')
argv[0]++;
fnbr = getinteger(argv[0]);
if (fnbr < 1 || fnbr > MAXOPENFILES || FileTable[fnbr].com <= MAXCOMPORTS)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number #% is not open", fnbr);
if (!InitSDCard())
return;
idx = getint(argv[2], 1, 0x7FFFFFFF) - 1;
if (idx < 0)
idx = 0;
positionfile(fnbr, idx);
}
void MIPS16 cmd_name(void)
{
char *old, *new, ss[2];
int i;
ss[0] = tokenAS; // this will be used to split up the argument line
ss[1] = 0;
char qold[FF_MAX_LFN]={0};
char qnew[FF_MAX_LFN]={0};
getargs(&cmdline, 3, (unsigned char *)ss); // getargs macro must be the first executable stmt in a block
if(argc != 3) error("Syntax");
old = (char *)getFstring(argv[0]); // get the old name
if(drivecheck(old,&i)!=FatFSFileSystem+1) error("Only valid on current drive");
getfullfilepath(old,qold);
new = (char *)getFstring(argv[2]); // get the new name
if(drivecheck(new,&i)!=FatFSFileSystem+1) error("Only valid on current drive");
getfullfilepath(new,qnew);
if(!FatFSFileSystem){
// start a new block
FSerror = lfs_rename(&lfs, qold, qnew);
ErrorCheck(0);
} else { // start a new block
if (!InitSDCard()) return;
FSerror = f_rename(qold, qnew);
ErrorCheck(0);
}
}
extern uint64_t __uninitialized_ram(_persistent);
void MIPS16 cmd_save(void)
{
int fnbr;
unsigned char *pp, *flinebuf, *outbuf, *p; // get the file name and change to the directory
int maxH = VRes;
int maxW = HRes;
if (!InitSDCard()) return;
fnbr = FindFreeFileNbr();
if((p=checkstring(cmdline, (unsigned char *)"PERSISTENT"))){
_persistent=getinteger(p);
return;
}
if ((p = checkstring(cmdline, (unsigned char *)"CONTEXT")) != NULL){
SaveContext();
if(checkstring(p, (unsigned char *)"CLEAR"))ClearVars(0,false);
return;
}
if ((p = checkstring(cmdline, (unsigned char *)"COMPRESSED IMAGE")) != NULL){
if(!(ReadBuffer==ReadBuffer16 || ReadBuffer==ReadBuffer2))error("Invalid for this display");
unsigned int nbr;
int i, x, y, w, h, filesize;
union colourmap
{
char rgbbytes[4];
unsigned int rgb;
} c;
unsigned char fcolour;
unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 0x76, 0, 0, 0};
unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0,
2,0,0,0,0,0,0,0,0x13,0xb,0,0,0x13,0xb,0,0,
16,0,0,0,16,0,0,0
};
unsigned char bmpcolourpallette[16*4]={
0,0,0,0,
0,0,255,0,
0,64,0,0,
0,64,255,0,
0,128,0,0,
0,128,255,0,
0,255,0,0,
0,255,255,0,
255,0,0,0,
255,0,255,0,
255,64,0,0,
255,64,255,0,
255,128,0,0,
255,128,255,0,
255,255,0,0,
255,255,255,0
};
// unsigned char bmppad[3] = {0, 0, 0};
getargs(&p, 9, (unsigned char *)",");
if (!InitSDCard())
return;
if ((void *)ReadBuffer == (void *)DisplayNotSet)
error("SAVE IMAGE not available on this display");
pp = getFstring(argv[0]);
if (argc != 1 && argc != 9)
error("Syntax");
if (strchr((char *)pp, '.') == NULL)
strcat((char *)pp, ".bmp");
if (!BasicFileOpen((char *)pp, fnbr, FA_WRITE | FA_CREATE_ALWAYS))
return;
if (argc == 1)
{
x = 0;
y = 0;
h = maxH;
w = maxW;
}
else
{
x = getint(argv[2], 0, maxW - 1);
y = getint(argv[4], 0, maxH - 1);
w = getint(argv[6], 1, maxW - x);
h = getint(argv[8], 1, maxH - y);
}
if(w & 1)error("Width must be a multiple of 2 for compressed image save");
filesize = 54 + 16* 4 + w * h / 2;
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
bmpinfoheader[4] = (unsigned char)(w);
bmpinfoheader[5] = (unsigned char)(w >> 8);
bmpinfoheader[6] = (unsigned char)(w >> 16);
bmpinfoheader[7] = (unsigned char)(w >> 24);
bmpinfoheader[8] = (unsigned char)(h);
bmpinfoheader[9] = (unsigned char)(h >> 8);
bmpinfoheader[10] = (unsigned char)(h >> 16);
bmpinfoheader[11] = (unsigned char)(h >> 24);
bmpinfoheader[20] = (unsigned char)(h*w/2);
bmpinfoheader[21] = (unsigned char)((h*w/2) >> 8);
bmpinfoheader[22] = (unsigned char)((h*w/2) >> 16);
bmpinfoheader[23] = (unsigned char)((h*w/2) >> 24);
if(filesource[fnbr]==FATFSFILE) {
f_write(FileTable[fnbr].fptr, bmpfileheader, 14, &nbr);
f_write(FileTable[fnbr].fptr, bmpinfoheader, 40, &nbr);
f_write(FileTable[fnbr].fptr, bmpcolourpallette, 64, &nbr);
} else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpfileheader, 14);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpinfoheader, 40);
if(FSerror>0)FSerror=0;
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpcolourpallette, 64);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
flinebuf = GetTempMemory(maxW * 4);
outbuf=GetTempMemory(maxW/2);
char *foutbuf=GetTempMemory(maxW);
#ifdef PICOMITEVGA
mergedread=1;
#endif
for (i = y + h - 1; i >= y; i--)
{
ReadBuffer(x, i, x + w - 1, i, flinebuf);
p=flinebuf;
pp=outbuf;
for(int k=0;k<w;k++){
c.rgbbytes[2]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[0]=*p++;
fcolour = RGB121(c.rgb);
if(k & 1){
*pp |=fcolour;
pp++;
} else {
*pp = fcolour<<4;
}
}
unsigned char *ppp=(unsigned char *)foutbuf;
unsigned char *q=outbuf;
int count=0;
int k=w;
while(k){
ppp[0]=2;ppp[1]=*q++;
count+=2;
k-=2;
while(*q==ppp[1] && ppp[0]<254 && k){
ppp[0]+=2;
q++;
k-=2;
}
ppp+=2;
}
*ppp++=0;*ppp++=0;count+=2;
if(filesource[fnbr]==FATFSFILE) f_write(FileTable[fnbr].fptr, foutbuf, count, &nbr);
else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, foutbuf, count);
}
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
#ifdef PICOMITEVGA
mergedread=0;
#endif
foutbuf[0]=0;foutbuf[1]=1;
if(filesource[fnbr]==FATFSFILE) f_write(FileTable[fnbr].fptr, foutbuf, 2, &nbr);
else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, foutbuf, 2);
}
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
FileClose(fnbr);
return;
}
if ((p = checkstring(cmdline, (unsigned char *)"IMAGE")) != NULL)
{
if(ReadBuffer==ReadBuffer16 || ReadBuffer==ReadBuffer2){
unsigned int nbr;
int i, x, y, w, h, filesize;
union colourmap
{
char rgbbytes[4];
unsigned int rgb;
} c;
unsigned char fcolour;
unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 0x76, 0, 0, 0};
unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0,
0,0,0,0,0,0,0,0,0x13,0xb,0,0,0x13,0xb,0,0,
16,0,0,0,16,0,0,0
};
unsigned char bmpcolourpallette[16*4]={
0,0,0,0,
0,0,255,0,
0,64,0,0,
0,64,255,0,
0,128,0,0,
0,128,255,0,
0,255,0,0,
0,255,255,0,
255,0,0,0,
255,0,255,0,
255,64,0,0,
255,64,255,0,
255,128,0,0,
255,128,255,0,
255,255,0,0,
255,255,255,0
};
unsigned char bmppad[3] = {0, 0, 0};
getargs(&p, 9, (unsigned char *)",");
if (!InitSDCard())
return;
if ((void *)ReadBuffer == (void *)DisplayNotSet)
error("SAVE IMAGE not available on this display");
pp = getFstring(argv[0]);
if (argc != 1 && argc != 9)
error("Syntax");
if (strchr((char *)pp, '.') == NULL)
strcat((char *)pp, ".bmp");
if (!BasicFileOpen((char *)pp, fnbr, FA_WRITE | FA_CREATE_ALWAYS))
return;
if (argc == 1)
{
x = 0;
y = 0;
h = maxH;
w = maxW;
}
else
{
x = getint(argv[2], 0, maxW - 1);
y = getint(argv[4], 0, maxH - 1);
w = getint(argv[6], 1, maxW - x);
h = getint(argv[8], 1, maxH - y);
}
filesize = 54 + 16* 4 + w * h / 2;
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
bmpinfoheader[4] = (unsigned char)(w);
bmpinfoheader[5] = (unsigned char)(w >> 8);
bmpinfoheader[6] = (unsigned char)(w >> 16);
bmpinfoheader[7] = (unsigned char)(w >> 24);
bmpinfoheader[8] = (unsigned char)(h);
bmpinfoheader[9] = (unsigned char)(h >> 8);
bmpinfoheader[10] = (unsigned char)(h >> 16);
bmpinfoheader[11] = (unsigned char)(h >> 24);
bmpinfoheader[20] = (unsigned char)(h*w/2);
bmpinfoheader[21] = (unsigned char)((h*w/2) >> 8);
bmpinfoheader[22] = (unsigned char)((h*w/2) >> 16);
bmpinfoheader[23] = (unsigned char)((h*w/2) >> 24);
if(filesource[fnbr]==FATFSFILE) {
f_write(FileTable[fnbr].fptr, bmpfileheader, 14, &nbr);
f_write(FileTable[fnbr].fptr, bmpinfoheader, 40, &nbr);
f_write(FileTable[fnbr].fptr, bmpcolourpallette, 64, &nbr);
} else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpfileheader, 14);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpinfoheader, 40);
if(FSerror>0)FSerror=0;
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpcolourpallette, 64);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
flinebuf = GetTempMemory(maxW * 4);
outbuf=GetTempMemory(maxW/2);
#ifdef PICOMITEVGA
mergedread=1;
#endif
for (i = y + h - 1; i >= y; i--)
{
ReadBuffer(x, i, x + w - 1, i, flinebuf);
p=flinebuf;
pp=outbuf;
for(int k=0;k<w;k++){
c.rgbbytes[2]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[0]=*p++;
fcolour = RGB121(c.rgb);
if(k & 1){
*pp |=(fcolour);
pp++;
} else {
*pp = fcolour<<4;
}
}
if(filesource[fnbr]==FATFSFILE) f_write(FileTable[fnbr].fptr, outbuf, w / 2, &nbr);
else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, outbuf, w /2);
}
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
if ((w / 2) % 4 != 0){
if(filesource[fnbr]==FATFSFILE)f_write(FileTable[fnbr].fptr, bmppad, 4 - ((w / 2 ) % 4), &nbr);
else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmppad, 4 - ((w / 2 ) % 4));
}
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
}
#ifdef PICOMITEVGA
mergedread=0;
#endif
FileClose(fnbr);
return;
}
unsigned int nbr;
int i, x, y, w, h, filesize;
unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0};
unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0};
unsigned char bmppad[3] = {0, 0, 0};
getargs(&p, 9, (unsigned char *)",");
if (!InitSDCard())
return;
if ((void *)ReadBuffer == (void *)DisplayNotSet)
error("SAVE IMAGE not available on this display");
pp = getFstring(argv[0]);
if (argc != 1 && argc != 9)
error("Syntax");
if (strchr((char *)pp, '.') == NULL)
strcat((char *)pp, ".bmp");
if (!BasicFileOpen((char *)pp, fnbr, FA_WRITE | FA_CREATE_ALWAYS))
return;
if (argc == 1)
{
x = 0;
y = 0;
h = maxH;
w = maxW;
}
else
{
x = getint(argv[2], 0, maxW - 1);
y = getint(argv[4], 0, maxH - 1);
w = getint(argv[6], 1, maxW - x);
h = getint(argv[8], 1, maxH - y);
}
filesize = 54 + 3 * w * h;
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
bmpinfoheader[4] = (unsigned char)(w);
bmpinfoheader[5] = (unsigned char)(w >> 8);
bmpinfoheader[6] = (unsigned char)(w >> 16);
bmpinfoheader[7] = (unsigned char)(w >> 24);
bmpinfoheader[8] = (unsigned char)(h);
bmpinfoheader[9] = (unsigned char)(h >> 8);
bmpinfoheader[10] = (unsigned char)(h >> 16);
bmpinfoheader[11] = (unsigned char)(h >> 24);
if(filesource[fnbr]==FATFSFILE) {
f_write(FileTable[fnbr].fptr, bmpfileheader, 14, &nbr);
f_write(FileTable[fnbr].fptr, bmpinfoheader, 40, &nbr);
} else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpfileheader, 14);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmpinfoheader, 40);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
flinebuf = GetTempMemory(maxW * 4);
for (i = y + h - 1; i >= y; i--)
{
ReadBuffer(x, i, x + w - 1, i, flinebuf);
if(filesource[fnbr]==FATFSFILE) f_write(FileTable[fnbr].fptr, flinebuf, w * 3, &nbr);
else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, flinebuf, w * 3);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
if ((w * 3) % 4 != 0){
if(filesource[fnbr]==FATFSFILE)f_write(FileTable[fnbr].fptr, bmppad, 4 - ((w * 3) % 4), &nbr);
else {
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, bmppad, 4 - ((w * 3) % 4));
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
}
}
}
FileClose(fnbr);
return;
}
else
{
unsigned char b[STRINGSIZE];
p = getFstring(cmdline); // get the file name and change to the directory
if (strchr((char *)p, '.') == NULL)
strcat((char *)p, ".bas");
if (!BasicFileOpen((char *)p, fnbr, FA_WRITE | FA_CREATE_ALWAYS))
return;
p = ProgMemory;
int lineno=0;
while (!(*p == 0 || *p == 0xff))
{ // this is a safety precaution
p = llist(b, p); // expand the line
pp = b;
if(!(b[0]=='\'' && b[1]=='#' && lineno==0)){
lineno++;
while (*pp) FilePutChar(*pp++, fnbr); // write the line to the SD card
FilePutChar('\r', fnbr);
FilePutChar('\n', fnbr); // terminate the line
if (p[0] == 0 && p[1] == 0) break; // end of the listing ?
}
}
FileClose(fnbr);
}
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
#ifdef rp2350
#define loadbuffsize EDIT_BUFFER_SIZE-sizeof(a_dlist)*MAXDEFINES-4096
int cmpstr(char *s1,char *s2)
{
unsigned char *p1 = (unsigned char *) s1;
unsigned char *p2 = (unsigned char *) s2;
unsigned char c1, c2;
if (p1 == p2)
return 0;
do
{
c1 = tolower (*p1++);
c2 = tolower (*p2++);
if (c1 == '\0') return 0;
}
while (c1 == c2);
return c1 - c2;
}
int massage(char *buff){
int i=nDefines;
while(i--){
char *p=dlist[i].from;
while(*p){
*p=toupper(*p);
p++;
}
p=dlist[i].to;
while(*p){
*p=toupper(*p);
p++;
}
STR_REPLACE(buff,dlist[i].from,dlist[i].to,0);
}
STR_REPLACE(buff,"=<","<=",0);
STR_REPLACE(buff,"=>",">=",0);
STR_REPLACE(buff," ,",",",0);
STR_REPLACE(buff,", ",",",0);
STR_REPLACE(buff," *","*",0);
STR_REPLACE(buff,"* ","*",0);
STR_REPLACE(buff,"- ","-",0);
STR_REPLACE(buff," /","/",0);
STR_REPLACE(buff,"/ ","/",0);
STR_REPLACE(buff,"= ","=",0);
STR_REPLACE(buff,"+ ","+",0);
STR_REPLACE(buff," )",")",0);
STR_REPLACE(buff,") ",")",0);
STR_REPLACE(buff,"( ","(",0);
STR_REPLACE(buff,"> ",">",0);
STR_REPLACE(buff,"< ","<",0);
STR_REPLACE(buff," '","'",0);
return strlen(buff);
}
void importfile(char *pp, char *tp, char **p, uint32_t buf, int convertdebug, bool message){
int fnbr;
char buff[256];
char qq[FF_MAX_LFN] = {0};
int importlines=0;
int ignore=0;
char *fname, *sbuff, *op, *ip;
int c, slen, data;
fnbr = FindFreeFileNbr();
char *q;
if((q=strchr((char *)tp,34)) == 0) error("Syntax");
q++;
if((q=strchr(q,34)) == 0) error("Syntax");
fname = (char *)getFstring((unsigned char *)tp);
fnbr = FindFreeFileNbr();
if (strchr((char *)fname, '.') == NULL) strcat((char *)fname, ".INC");
q=&fname[strlen(fname)-4];
if(strcasecmp(q,".inc")!=0)error("must be a .inc file");
if(!(fname[1]==':' && (fname[0] == 'A' || fname[0]=='a' || fname[0] == 'B' || fname[0]=='b'))) {strcpy(qq,pp);strcat(qq,fname);}
else strcpy(qq,fname);
if(message){MMPrintString("Importing ");MMPrintString(qq);PRet();}
if (!BasicFileOpen(qq, fnbr, FA_READ)) return;
**p='\'';
*p+=1;
**p='#';
*p+=1;
strcpy(*p,qq);
*p+=strlen(qq);
**p='\r';
*p+=1;
**p='\n';
*p+=1;
while(!FileEOF(fnbr)) {
int toggle=0, len=0;// while waiting for the end of file
sbuff=buff;
if(((uint32_t)*p - buf) >= loadbuffsize) {
FreeMemorySafe((void **)&buf);
FreeMemorySafe((void **)&dlist);
error("Not enough memory");
}
memset(buff,0,256);
MMgetline(fnbr, (char *)buff); // get the input line
data=0;
importlines++;
LineCount++;
routinechecks();
len=strlen(buff);
toggle=0;
for(c=0;c<strlen(buff);c++){
if(buff[c] == TAB) buff[c] = ' ';
}
while(*sbuff==' '){
sbuff++;
len--;
}
if(ignore && sbuff[0]!='#')*sbuff='\'';
if(strncasecmp(sbuff,"rem ",4)==0 || (len==3 && strncasecmp(sbuff,"rem",3)==0 )){
sbuff+=2;
*sbuff='\'';
continue;
}
if(strncasecmp(sbuff,"data ",5)==0)data=1;
slen=len;
op=sbuff;
ip=sbuff;
while(*ip){
if(*ip==34){
if(toggle==0)toggle=1;
else toggle=0;
}
if(!toggle && (*ip==' ' || *ip==':')){
*op++=*ip++; //copy the first space
while(*ip==' '){
ip++;
len--;
}
}
else *op++=*ip++;
}
slen=len;
if(!(toupper(sbuff[0])=='R' && toupper(sbuff[1])=='U' && toupper(sbuff[2])=='N' && (strlen(sbuff)==3 || sbuff[3]==' '))){
toggle=0;
for(c=0;c<slen;c++){
if(!(toggle || data))sbuff[c]=toupper(sbuff[c]);
if(sbuff[c]==34){
if(toggle==0)toggle=1;
else toggle=0;
}
}
}
toggle=0;
for(c=0;c<slen;c++){
if(sbuff[c]==34){
if(toggle==0)toggle=1;
else toggle=0;
}
if(!toggle && sbuff[c]==39 && len==slen){
len=c;//get rid of comments
break;
}
}
if(sbuff[0]=='#'){
unsigned char *tp=checkstring((unsigned char *)&sbuff[1], (unsigned char *)"DEFINE");
if(tp){
getargs(&tp,3,(unsigned char *)",");
if(nDefines>=MAXDEFINES){
FreeMemorySafe((void *)&buf);
FreeMemorySafe((void *)&dlist);
error("Too many #DEFINE statements");
}
strcpy(dlist[nDefines].from,(char *)getCstring(argv[0]));
strcpy(dlist[nDefines].to,(char *)getCstring(argv[2]));
nDefines++;
ClearTempMemory();
} else {
if(cmpstr("COMMENT END",&sbuff[1])==0)ignore=0;
if(cmpstr("COMMENT START",&sbuff[1])==0)ignore=1;
if(cmpstr("MMDEBUG ON",&sbuff[1])==0)convertdebug=0;
if(cmpstr("MMDEBUG OFF",&sbuff[1])==0)convertdebug=1;
if(cmpstr("INCLUDE ",&sbuff[1])==0){
FreeMemorySafe((void **)&buf);
FreeMemorySafe((void **)&dlist);
error("Can't import from an import");
}
}
} else {
if(toggle)sbuff[len++]=34;
sbuff[len++]=39;
sbuff[len]=0;
len=massage(sbuff); //can't risk crushing lines with a quote in them
if((sbuff[0]!=39) || (sbuff[0]==39 && sbuff[1]==39)){
memcpy(*p,sbuff,len);
*p+=len;
**p='\n';
*p+=1;
}
}
}
FileClose(fnbr);
return ;
}
// load a file into program memory
int FileLoadCMM2Program(char *fname, bool message) {
int fnbr;
char *p,*op, *ip, *buf, *sbuff, buff[STRINGSIZE];
char pp[FF_MAX_LFN] = {0};
int c;
int convertdebug=1;
int ignore=0;
nDefines=0;
LineCount=0;
int importlines=0, data;
if (!InitSDCard()) return false;
ClearProgram(true); // clear any leftovers from the previous program
fnbr = FindFreeFileNbr();
p = (char *)getFstring((unsigned char *)fname);
if (strchr((char *)p, '.') == NULL) strcat((char *)p, ".bas");
char q[FF_MAX_LFN]={0};
FatFSFileSystemSave=FatFSFileSystem;
getfullfilename(p,q);
int CurrentFileSystem=FatFSFileSystem;
FatFSFileSystem=FatFSFileSystemSave;
strcpy(pp,CurrentFileSystem? "B:":"A:");
strcat(pp,fullpathname[FatFSFileSystem]);
strcat(pp,"/");
chdir(pp);
if (!BasicFileOpen(p, fnbr, FA_READ)) return false;
p = buf = GetMemory(loadbuffsize);
*p++='\'';
*p++='#';
strcpy(p,CurrentFileSystem? "B:":"A:");
p+=2;
strcpy(p,q);
p+=strlen(q);
*p++='\r';
*p++='\n';
dlist=GetMemory(sizeof(a_dlist)*MAXDEFINES);
while(!FileEOF(fnbr)) { // while waiting for the end of file
int toggle=0, len=0, slen;// while waiting for the end of file
sbuff=buff;
if((p - buf) >= loadbuffsize) {
FreeMemorySafe((void **)&buf);
FreeMemorySafe((void **)&dlist);
error("Not enough memory");
}
memset(buff,0,256);
MMgetline(fnbr, (char *)buff); // get the input line
data=0;
importlines++;
LineCount++;
routinechecks();
len=strlen(buff);
toggle=0;
for(c=0;c<strlen(buff);c++){
if(buff[c] == TAB) buff[c] = ' ';
}
while(sbuff[0]==' '){ //strip leading spaces
sbuff++;
len--;
}
if(ignore && sbuff[0]!='#')*sbuff='\'';
if(strncasecmp(sbuff,"rem ",4)==0 || (len==3 && strncasecmp(sbuff,"rem",3)==0 )){
sbuff+=2;
*sbuff='\'';
continue;
}
if(strncasecmp(sbuff,"mmdebug ",7)==0 && convertdebug==1){
sbuff+=6;
*sbuff='\'';
continue;
}
if(strncasecmp(sbuff,"data ",5)==0)data=1;
slen=len;
op=sbuff;
ip=sbuff;
while(*ip){
if(*ip==34){
if(toggle==0)toggle=1;
else toggle=0;
}
if(!toggle && (*ip==' ' || *ip==':')){
*op++=*ip++; //copy the first space
while(*ip==' '){
ip++;
len--;
}
} else *op++=*ip++;
}
slen=len;
if(sbuff[0]=='#'){
unsigned char *tp=checkstring((unsigned char *)&sbuff[1], (unsigned char *)"DEFINE");
if(tp){
getargs(&tp,3,(unsigned char *)",");
if(nDefines>=MAXDEFINES){
FreeMemorySafe((void *)&buf);
FreeMemorySafe((void *)&dlist);
error("Too many #DEFINE statements");
}
strcpy(dlist[nDefines].from,(char *)getCstring(argv[0]));
strcpy(dlist[nDefines].to,(char *)getCstring(argv[2]));
nDefines++;
} else {
if(cmpstr("COMMENT END",&sbuff[1])==0)ignore=0;
if(cmpstr("COMMENT START",&sbuff[1])==0)ignore=1;
if(cmpstr("MMDEBUG ON",&sbuff[1])==0)convertdebug=0;
if(cmpstr("MMDEBUG OFF",&sbuff[1])==0)convertdebug=1;
if(cmpstr("INCLUDE",&sbuff[1])==0){
importfile(pp, &sbuff[8],&p, (uint32_t)buf, convertdebug, message);
ClearTempMemory();
}
}
} else {
if(!(toupper(sbuff[0])=='R' && toupper(sbuff[1])=='U' && toupper(sbuff[2])=='N' && (strlen(sbuff)==3 || sbuff[3]==' '))){
toggle=0;
for(c=0;c<slen;c++){
if(!(toggle || data))sbuff[c]=toupper(sbuff[c]);
if(sbuff[c]==34){
if(toggle==0)toggle=1;
else toggle=0;
}
}
}
toggle=0;
for(c=0;c<slen;c++){
if(sbuff[c]==34){
if(toggle==0)toggle=1;
else toggle=0;
}
if(!toggle && sbuff[c]==39 && len==slen){
len=c;//get rid of comments
break;
}
}
if(toggle)sbuff[len++]=34;
sbuff[len++]=39;
sbuff[len]=0;
len=massage(sbuff); //can't risk crushing lines with a quote in them
if((sbuff[0]!=39) || (sbuff[0]==39 && sbuff[1]==39)){
memcpy(p,sbuff,len);
p+=len;
*p++='\n';
}
}
}
*p = 0; // terminate the string in RAM
FileClose(fnbr);
unsigned char continuation=Option.continuation;
SaveProgramToFlash((unsigned char *)buf, false);
Option.continuation= continuation;
FreeMemorySafe((void **)&buf);
FreeMemorySafe((void **)&dlist);
return true;
}
#endif
// load a file into program memory
int FileLoadProgram(unsigned char *fname, bool chain)
{
int fnbr;
char *p, *buf;
int c,oldfont=gui_font;
if (!InitSDCard()) return false;
// ClearProgram(true); // clear any leftovers from the previous program
initFonts();
m_alloc(chain? M_LIMITED :M_PROG); // init the variables for program memory
if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf)FreeMemorySafe((void **)&WriteBuf);
ClearRuntime(chain? false : true);
// ProgMemory[0] = ProgMemory[1] = ProgMemory[3] = ProgMemory[4] = 0;
PSize = 0;
StartEditPoint = NULL;
StartEditChar= 0;
ProgramChanged = false;
TraceOn = false;
SetFont(oldfont);
PromptFont=oldfont;
fnbr = FindFreeFileNbr();
p = (char *)getFstring(fname);
if (strchr((char *)p, '.') == NULL) strcat((char *)p, ".bas");
char q[FF_MAX_LFN]={0};
FatFSFileSystemSave=FatFSFileSystem;
getfullfilename(p,q);
int CurrentFileSystem=FatFSFileSystem;
FatFSFileSystem=FatFSFileSystemSave;
if (!BasicFileOpen(p, fnbr, FA_READ)) return false;
p = buf = GetTempMemory(EDIT_BUFFER_SIZE-2048); // get all the memory while leaving space for the couple of buffers defined and the file handle
*p++='\'';
*p++='#';
strcpy(p,CurrentFileSystem? "B:":"A:");
p+=2;
strcpy(p,q);
p+=strlen(q);
*p++='\r';
*p++='\n';
while (!FileEOF(fnbr))
{ // while waiting for the end of file
if ((p - buf) >= EDIT_BUFFER_SIZE - 2048 - 512)
error("Not enough memory");
c = FileGetChar(fnbr) & 0x7f;
if (isprint(c) || c == '\r' || c == '\n' || c == TAB)
{
if (c == TAB)
c = ' ';
*p++ = c; // get the input into RAM
}
}
*p = 0; // terminate the string in RAM
FileClose(fnbr);
ClearSavedVars(); // clear any saved variables
SaveProgramToFlash((unsigned char *)buf, false);
return true;
}
#ifdef rp2350
volatile uint32_t realmempointer;
void MemWriteBlock(void){
int i;
uint32_t address=realmempointer-32;
if(address % 32)error("Memory write address");
memcpy((char *)address,(char*)&MemWord.i64[0],32);
for(i=0;i<8;i++)MemWord.i32[i]=0xFFFFFFFF;
}
void MemWriteByte(unsigned char b) {
realmempointer++;
MemWord.i8[mi8p]=b;
mi8p++;
mi8p %= 32;
if(mi8p==0){
MemWriteBlock();
}
}
void MemWriteWord(unsigned int i) {
MemWriteByte(i & 0xFF);
MemWriteByte((i>>8) & 0xFF);
MemWriteByte((i>>16) & 0xFF);
MemWriteByte((i>>24) & 0xFF);
}
void MemWriteAlign(void) {
while(mi8p != 0) {
MemWriteByte(0x0);
}
MemWriteWord(0xFFFFFFFF);
}
void MemWriteClose(void){
while(mi8p != 0) {
MemWriteByte(0xff);
}
}
void MIPS16 SaveProgramToRAM(unsigned char *pm, int msg, uint8_t *ram) {
unsigned char *p, fontnbr, prevchar = 0, buf[STRINGSIZE];
unsigned short endtoken, tkn;
int nbr, i, n, SaveSizeAddr;
multi=false;
uint32_t storedupdates[MAXCFUNCTION], updatecount=0, realmemsave;
initFonts();
#ifdef USBKEYBOARD
clearrepeat();
#endif
memcpy(buf, tknbuf, STRINGSIZE); // save the token buffer because we are going to use it
memset(ram,0xFF,MAX_PROG_SIZE);
realmempointer=(volatile uint32_t)ram;
nbr = 0;
// this is used to count the number of bytes written to ram
while(*pm) {
p = inpbuf;
while(!(*pm == 0 || *pm == '\r' || (*pm == '\n' && prevchar != '\r'))) {
if(*pm == TAB) {
do {*p++ = ' ';
if((p - inpbuf) >= MAXSTRLEN) goto exiterror;
} while((p - inpbuf) % 2);
} else {
if(isprint((uint8_t)*pm)) {
*p++ = *pm;
if((p - inpbuf) >= MAXSTRLEN) goto exiterror;
}
}
prevchar = *pm++;
}
if(*pm) prevchar = *pm++; // step over the end of line char but not the terminating zero
*p = 0; // terminate the string in inpbuf
if(*inpbuf == 0 && (*pm == 0 || (!isprint((uint8_t)*pm) && pm[1] == 0))) break; // don't save a trailing newline
tokenise(false); // turn into executable code
p = tknbuf;
while(!(p[0] == 0 && p[1] == 0)) {
MemWriteByte(*p++); nbr++;
if(((uint32_t)realmempointer - (uint32_t)ram) >= MAX_PROG_SIZE - 5) goto exiterror;
}
MemWriteByte(0); nbr++; // terminate that line in flash
}
MemWriteByte(0);
MemWriteAlign(); // this will flush the buffer and step the flash write pointer to the next word boundary
// now we must scan the program looking for CFUNCTION/CSUB/DEFINEFONT statements, extract their data and program it into the flash used by CFUNCTIONs
// programs are terminated with two zero bytes and one or more bytes of 0xff. The CFunction area starts immediately after that.
// the format of a CFunction/CSub/Font in flash is:
// Unsigned Int - Address of the CFunction/CSub in program memory (points to the token representing the "CFunction" keyword) or NULL if it is a font
// Unsigned Int - The length of the CFunction/CSub/Font in bytes including the Offset (see below)
// Unsigned Int - The Offset (in words) to the main() function (ie, the entry point to the CFunction/CSub). Omitted in a font.
// word1..wordN - The CFunction/CSub/Font code
// The next CFunction/CSub/Font starts immediately following the last word of the previous CFunction/CSub/Font
int firsthex=1;
realmemsave= realmempointer;
p = (unsigned char *)ram ; // start scanning program memory
while(*p != 0xff) {
nbr++;
if(*p == 0) p++; // if it is at the end of an element skip the zero marker
if(*p == 0) break; // end of the program
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // step over the line number
skipspace(p);
if(*p == T_LABEL) {
p += p[1] + 2; // skip over the label
skipspace(p); // and any following spaces
}
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
if(tkn == cmdCSUB || tkn == GetCommandValue((unsigned char *)"DefineFont")) { // found a CFUNCTION, CSUB or DEFINEFONT token
if(tkn == GetCommandValue((unsigned char *)"DefineFont")) {
endtoken = GetCommandValue((unsigned char *)"End DefineFont");
p+=2; // step over the token
skipspace(p);
if(*p == '#') p++;
fontnbr = getint(p, 1, FONT_TABLE_SIZE);
// font 6 has some special characters, some of which depend on font 1
if(fontnbr == 1 || fontnbr == 6 || fontnbr == 7) {
error("Cannot redefine fonts 1, 6 or 7");
}
realmempointer+=4;
skipelement(p); // go to the end of the command
p--;
} else {
endtoken = GetCommandValue((unsigned char *)"End CSub");
realmempointer+=4;
fontnbr = 0;
firsthex=0;
p++;
}
SaveSizeAddr = realmempointer; // save where we are so that we can write the CFun size in here
realmempointer+=4;
p++;
skipspace(p);
if(!fontnbr) { //process CSub
if(!isnamestart((uint8_t)*p)){
error("Function name");
}
do { p++; } while(isnamechar((uint8_t)*p));
skipspace(p);
if(!(isxdigit((uint8_t)p[0]) && isxdigit((uint8_t)p[1]) && isxdigit((uint8_t)p[2]))) {
skipelement(p);
p++;
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over a line number
}
}
do {
while(*p && *p != '\'') {
skipspace(p);
n = 0;
for(i = 0; i < 8; i++) {
if(!isxdigit((uint8_t)*p)) {
error("Invalid hex word");
}
if(((uint32_t)realmempointer - (uint32_t)ram) >= MAX_PROG_SIZE - 5) goto exiterror;
n = n << 4;
if(*p <= '9')
n |= (*p - '0');
else
n |= (toupper(*p) - 'A' + 10);
p++;
}
realmempointer+=4;
skipspace(p);
if(firsthex){
firsthex=0;
if(((n>>16) & 0xff) < 0x20){
error("Can't define non-printing characters");
}
}
}
// we are at the end of a embedded code line
while(*p) p++; // make sure that we move to the end of the line
p++; // step to the start of the next line
if(*p == 0) {
error("Missing END declaration");
}
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over the line number
skipspace(p);
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
} while(tkn != endtoken);
storedupdates[updatecount++]=realmempointer - SaveSizeAddr - 4;
}
while(*p) p++; // look for the zero marking the start of the next element
}
realmempointer = realmemsave ;
updatecount=0;
p = (unsigned char *)ram; // start scanning program memory
while(*p != 0xff) {
nbr++;
if(*p == 0) p++; // if it is at the end of an element skip the zero marker
if(*p == 0) break; // end of the program
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // step over the line number
skipspace(p);
if(*p == T_LABEL) {
p += p[1] + 2; // skip over the label
skipspace(p); // and any following spaces
}
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
if(tkn == cmdCSUB || tkn == GetCommandValue((unsigned char *)"DefineFont")) { // found a CFUNCTION, CSUB or DEFINEFONT token
if(tkn == GetCommandValue((unsigned char *)"DefineFont")) { // found a CFUNCTION, CSUB or DEFINEFONT token
endtoken = GetCommandValue((unsigned char *)"End DefineFont");
p+=2; // step over the token
skipspace(p);
if(*p == '#') p++;
fontnbr = getint(p, 1, FONT_TABLE_SIZE);
// font 6 has some special characters, some of which depend on font 1
if(fontnbr == 1 || fontnbr == 6 || fontnbr == 7) {
error("Cannot redefine fonts 1, 6, or 7");
}
//FlashWriteWord(fontnbr - 1); // a low number (< FONT_TABLE_SIZE) marks the entry as a font
// B31 = 1 now marks entry as font.
MemWriteByte(fontnbr - 1);
MemWriteByte(0x00);
MemWriteByte(0x00);
MemWriteByte(0x80);
skipelement(p); // go to the end of the command
p--;
} else {
endtoken = GetCommandValue((unsigned char *)"End CSub");
MemWriteWord((unsigned int)(p-ram)); // if a CFunction/CSub save a relative pointer to the declaration
fontnbr = 0;
p++;
}
SaveSizeAddr = realmempointer; // save where we are so that we can write the CFun size in here
MemWriteWord(storedupdates[updatecount++]); // leave this blank so that we can later do the write
p++;
skipspace(p);
if(!fontnbr) {
if(!isnamestart((uint8_t)*p)) {
error("Function name");
}
do { p++; } while(isnamechar(*p));
skipspace(p);
if(!(isxdigit(p[0]) && isxdigit(p[1]) && isxdigit(p[2]))) {
skipelement(p);
p++;
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over a line number
}
}
do {
while(*p && *p != '\'') {
skipspace(p);
n = 0;
for(i = 0; i < 8; i++) {
if(!isxdigit(*p)) {
error("Invalid hex word");
}
if(((uint32_t)realmempointer - (uint32_t)ram) >= MAX_PROG_SIZE - 5) goto exiterror;
n = n << 4;
if(*p <= '9')
n |= (*p - '0');
else
n |= (toupper(*p) - 'A' + 10);
p++;
}
MemWriteWord(n);
skipspace(p);
}
// we are at the end of a embedded code line
while(*p) p++; // make sure that we move to the end of the line
p++; // step to the start of the next line
if(*p == 0) {
error("Missing END declaration");
}
if(*p == T_NEWLINE) {
CurrentLinePtr = p;
p++; // skip the newline token
}
if(*p == T_LINENBR) p += 3; // skip over a line number
skipspace(p);
tkn=p[0] & 0x7f;
tkn |= ((unsigned short)(p[1] & 0x7f)<<7);
} while(tkn != endtoken);
}
while(*p) p++; // look for the zero marking the start of the next element
}
MemWriteWord(0xffffffff); // make sure that the end of the CFunctions is terminated with an erased word
MemWriteClose(); // this will flush the buffer and step the flash write pointer to the next word boundary
if(msg) { // if requested by the caller, print an informative message
if(MMCharPos > 1) MMPrintString("\r\n"); // message should be on a new line
MMPrintString("Saved ");
IntToStr((char *)tknbuf, nbr + 3, 10);
MMPrintString((char *)tknbuf);
MMPrintString(" bytes\r\n");
}
memcpy(tknbuf, buf, STRINGSIZE); // restore the token buffer in case there are other commands in it
// initConsole();
#ifdef USBKEYBOARD
clearrepeat();
#endif
return;
// we only get here in an error situation while writing the program to flash
exiterror:
MemWriteByte(0); MemWriteByte(0); MemWriteByte(0); // terminate the program in flash
MemWriteClose();
error("Not enough memory");
}
int MemLoadProgram(unsigned char *fname, unsigned char *ram)
{
int fnbr;
char *p, *buf;
int c,oldfont=gui_font;
if (!InitSDCard()) return false;
initFonts();
m_alloc(M_LIMITED); // init the variables for program memory
if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf)FreeMemorySafe((void **)&WriteBuf);
ClearRuntime(false);
PSize = 0;
StartEditPoint = NULL;
StartEditChar= 0;
ProgramChanged = false;
TraceOn = false;
SetFont(oldfont);
PromptFont=oldfont;
fnbr = FindFreeFileNbr();
p = (char *)getFstring(fname);
if (strchr((char *)p, '.') == NULL) strcat((char *)p, ".bas");
char q[FF_MAX_LFN]={0};
FatFSFileSystemSave=FatFSFileSystem;
getfullfilename(p,q);
int CurrentFileSystem=FatFSFileSystem;
FatFSFileSystem=FatFSFileSystemSave;
if (!BasicFileOpen(p, fnbr, FA_READ)) return false;
p = buf = GetTempMemory(EDIT_BUFFER_SIZE-2048); // get all the memory while leaving space for the couple of buffers defined and the file handle
*p++='\'';
*p++='#';
strcpy(p,CurrentFileSystem? "B:":"A:");
p+=2;
strcpy(p,q);
p+=strlen(q);
*p++='\r';
*p++='\n';
while (!FileEOF(fnbr))
{ // while waiting for the end of file
if ((p - buf) >= EDIT_BUFFER_SIZE - 2048 - 512)
error("Not enough memory");
c = FileGetChar(fnbr) & 0x7f;
if (isprint(c) || c == '\r' || c == '\n' || c == TAB)
{
if (c == TAB)
c = ' ';
*p++ = c; // get the input into RAM
}
}
*p = 0; // terminate the string in RAM
FileClose(fnbr);
ClearSavedVars(); // clear any saved variables
SaveProgramToRAM((unsigned char *)buf, false, ram);
return true;
}
void MIPS16 loadCMM2(unsigned char *p, bool autorun, bool message)
{
getargs(&p, 1, (unsigned char *)",");
if (!(argc & 1) || argc == 0)
error("Syntax");
if (CurrentLinePtr != NULL && !autorun)
error("Invalid in a program");
if (!FileLoadCMM2Program((char *)argv[0], message))
return;
FlashLoad = 0;
if (autorun)
{
if (*ProgMemory != 0x01)
return; // no program to run
ClearRuntime(true);
WatchdogSet = false;
PrepareProgram(true);
IgnorePIN = false;
if(Option.LIBRARY_FLASH_SIZE == MAX_PROG_SIZE) ExecuteProgram(ProgMemory - Option.LIBRARY_FLASH_SIZE); // run anything that might be in the library
nextstmt = ProgMemory;
}
return;
}
/* @endcond */
void MIPS16 cmd_loadCMM2(void){
bool autorun=false;
getargs(&cmdline,3,(unsigned char *)",");
if (argc == 3)
{
if (toupper(*argv[2]) == 'R')
autorun = true;
else
error("Syntax");
}
else if (CurrentLinePtr != NULL)
error("Invalid in a program");
loadCMM2(argv[0],autorun,true);
}
#endif
#ifdef rp2350
void LoadPNG(unsigned char *p) {
// int fnbr;
int xOrigin, yOrigin,w,h, transparent=0, cutoff=20;
int maxW=HRes;
int maxH=VRes;
upng_t* upng;
// get the command line arguments
getargs(&p, 9, (unsigned char *)","); // this MUST be the first executable line in the function
if(argc == 0) error("Argument count");
if(!InitSDCard()) return;
unsigned char *q = getFstring(argv[0]); // get the file name
xOrigin = yOrigin = 0;
if(argc >= 3 && *argv[2]) xOrigin = getinteger(argv[2]); // get the x origin (optional) argument
if(argc >= 5 && *argv[4]){
yOrigin = getinteger(argv[4]); // get the y origin (optional) argument
}
if(argc >= 7 && *argv[6])transparent=getint(argv[6],-1,15);
if(transparent!=-1)transparent=RGB121map[transparent];
if(argc==9)cutoff=getint(argv[8],1,254);
if(strchr((char *)q, '.') == NULL) strcat((char *)q, ".png");
upng = upng_new_from_file((char *)q);
routinechecks();
upng_header(upng);
w=upng_get_width(upng);
h= upng_get_height(upng);
if(w+xOrigin >maxW || h+yOrigin >maxH){
upng_free(upng);
error("Image too large");
}
if(!(upng_get_format(upng)==3)){
upng_free(upng);
error("Invalid format, must be RGBA8888");
}
routinechecks();
upng_decode(upng);
unsigned char *rr;
routinechecks();
rr=(unsigned char *)upng_get_buffer(upng);
unsigned char *pp=rr;
unsigned char *ppp=rr;
char d[3];
if(transparent==-1){
unsigned char *buff = GetTempMemory(w*h*3);
ReadBuffer(xOrigin, yOrigin, xOrigin+w-1, yOrigin+h-1,buff);
for(int i=0;i<w*h;i++){
d[0]=rr[2];
d[1]=rr[1];
d[2]=rr[0];
if(rr[3]>cutoff){
pp[0]=d[0];
pp[1]=d[1];
pp[2]=d[2];
} else {
pp[0]=buff[0];
pp[1]=buff[1];
pp[2]=buff[2];
}
pp+=3;
rr+=4;
buff+=3;
}
DrawBuffer(xOrigin, yOrigin, xOrigin+w-1, yOrigin+h-1,ppp);
} else {
for(int i=0;i<w*h;i++){
d[0]=rr[2];
d[1]=rr[1];
d[2]=rr[0];
if(rr[3]>cutoff){
pp[0]=d[0];
pp[1]=d[1];
pp[2]=d[2];
} else {
pp[0]=(transparent & 0xFF0000)>>16;
pp[1]=(transparent & 0xFF00)>>8;
pp[2]=(transparent & 0xFF);
}
pp+=3;
rr+=4;
}
DrawBuffer(xOrigin, yOrigin, xOrigin+w-1, yOrigin+h-1,ppp);
}
upng_free(upng);
#ifdef USBKEYBOARD
clearrepeat();
#endif
}
#endif
void MIPS16 cmd_load(void)
{
int oldfont=PromptFont;
int autorun = false;
unsigned char *p;
p = checkstring(cmdline, (unsigned char *)"CONTEXT");
if (p)
{
if(checkstring(p, (unsigned char *)"KEEP"))RestoreContext(true);
else RestoreContext(false);
return;
}
p = checkstring(cmdline, (unsigned char *)"IMAGE");
if (p)
{
cmd_LoadImage(p);
return;
}
p = checkstring(cmdline, (unsigned char *)"JPG");
if (p)
{
cmd_LoadJPGImage(p);
return;
}
#ifdef rp2350
p = checkstring(cmdline, (unsigned char *)"PNG");
if (p)
{
LoadPNG(p);
return;
}
#endif
getargs(&cmdline, 3, (unsigned char *)",");
CloseAudio(1);
if (!(argc & 1) || argc == 0)
error("Syntax");
if (argc == 3)
{
if (toupper(*argv[2]) == 'R')
autorun = true;
else
error("Syntax");
} else if (CurrentLinePtr != NULL) error("Invalid in a program");
if (!FileLoadProgram(argv[0], false)){
SetFont(oldfont);
PromptFont=oldfont;
return;
}
FlashLoad = 0;
if (autorun) {
if (*ProgMemory != 0x01)
return; // no program to run
ClearRuntime(true);
WatchdogSet = false;
PrepareProgram(true);
IgnorePIN = false;
if(Option.LIBRARY_FLASH_SIZE == MAX_PROG_SIZE) ExecuteProgram(ProgMemory - Option.LIBRARY_FLASH_SIZE); // run anything that might be in the library
nextstmt = ProgMemory;
}
SetFont(oldfont);
PromptFont=oldfont;
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
char __not_in_flash_func(FileGetChar)(int fnbr)
{
char ch;
if(filesource[fnbr]==FLASHFILE){
FSerror=lfs_file_read(&lfs, FileTable[fnbr].lfsptr, &ch, 1);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
return ch;
} else {
char *buff = SDbuffer[fnbr];
if (!InitSDCard())
return 0;
if (fmode[fnbr] & FA_WRITE)
{
FSerror = f_read(FileTable[fnbr].fptr, &ch, 1, &bw[fnbr]);
ErrorCheck(fnbr);
}
else
{
if (!(lastfptr[fnbr] == (uint32_t)FileTable[fnbr].fptr && buffpointer[fnbr] < SDbufferSize))
{
FSerror = f_read(FileTable[fnbr].fptr, buff, SDbufferSize, &bw[fnbr]);
ErrorCheck(fnbr);
buffpointer[fnbr] = 0;
lastfptr[fnbr] = (uint32_t)FileTable[fnbr].fptr;
}
ch = buff[buffpointer[fnbr]];
buffpointer[fnbr]++;
}
diskchecktimer = DISKCHECKRATE;
return ch;
}
}
char __not_in_flash_func(FilePutChar)(char c, int fnbr)
{
if(filesource[fnbr]==FLASHFILE){
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, &c, 1);
if(FSerror!=1)FSerror=-5;
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
return c;
} else {
static char t;
unsigned int bw;
t = c;
if (!InitSDCard())
return 0;
FSerror = f_write(FileTable[fnbr].fptr, &t, 1, &bw);
lastfptr[fnbr] = -1; // invalidate the read file buffer
ErrorCheck(fnbr);
diskchecktimer = DISKCHECKRATE;
return t;
}
}
int FileEOF(int fnbr)
{
int i;
if(filesource[fnbr]==FATFSFILE){
if (!InitSDCard())
return 0;
if (buffpointer[fnbr] <= bw[fnbr] - 1 && !(fmode[fnbr] & FA_WRITE))
i = 0;
else
{
i = f_eof(FileTable[fnbr].fptr);
}
} else {
i = (lfs_file_tell(&lfs,FileTable[fnbr].lfsptr)==lfs_file_size(&lfs,FileTable[fnbr].lfsptr));
}
return i;
}
// send a character to a file or the console
// if fnbr == 0 then send the char to the console
// otherwise the COM port or file opened as #fnbr
unsigned char MMfputc(unsigned char c, int fnbr)
{
if (fnbr == 0)
return MMputchar(c, 1); // accessing the console
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
if (FileTable[fnbr].com > MAXCOMPORTS)
return FilePutChar(c, fnbr);
else
return SerialPutchar(FileTable[fnbr].com, c); // send the char to the serial port
}
int MMfgetc(int fnbr)
{
int ch;
if (fnbr == 0)
return MMgetchar(); // accessing the console
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
if (FileTable[fnbr].com > MAXCOMPORTS)
ch = FileGetChar(fnbr);
else
ch = SerialGetchar(FileTable[fnbr].com); // get the char from the serial port
return ch;
}
int MMfeof(int fnbr)
{
if (fnbr == 0)
return (kbhitConsole() == 0); // accessing the console
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
if (FileTable[fnbr].com > MAXCOMPORTS)
return FileEOF(fnbr);
else
return SerialRxStatus(FileTable[fnbr].com) == 0;
}
// close the file and free up the file handle
// it will generate an error if needed
void FileClose(int fnbr)
{
int type=ForceFileClose(fnbr);
ErrorThrow(FSerror, type);
}
// close the file and free up the file handle
// it will NOT generate an error
int ForceFileClose(int fnbr)
{
FatFSFileSystem = FatFSFileSystemSave;
int type=NONEFILE;
if (fnbr && FileTable[fnbr].fptr != NULL && filesource[fnbr]==FATFSFILE)
{
FSerror = f_close(FileTable[fnbr].fptr);
FreeMemory((void *)FileTable[fnbr].fptr);
FreeMemory((void *)SDbuffer[fnbr]);
FileTable[fnbr].fptr = NULL;
type=FATFSFILE;
} else {
if(FileTable[fnbr].lfsptr != NULL){
FSerror = lfs_file_close(&lfs, FileTable[fnbr].lfsptr);
FreeMemory((void *)FileTable[fnbr].lfsptr);
FileTable[fnbr].lfsptr = NULL;
}
type=FLASHFILE;
}
buffpointer[fnbr] = 0;
lastfptr[fnbr] = -1;
bw[fnbr] = -1;
fmode[fnbr] = 0;
filesource[fnbr] = NONEFILE;
return type;
}
// finds the first available free file number. Throws an error if no free file numbers
int FindFreeFileNbr(void)
{
int i;
for (i = MAXOPENFILES; i >= 1; i--)
if (FileTable[i].com == 0)
return i;
error("Too many files open");
return 0;
}
void MIPS16 CloseAllFiles(void)
{
int i;
closeallsprites();
#ifndef PICOMITEWEB
closeall3d();
#endif
closeframebuffer('A');
for (i = 1; i <= MAXOPENFILES; i++)
{
if (FileTable[i].com != 0)
{
if (FileTable[i].com > MAXCOMPORTS)
{
ForceFileClose(i);
}
else
SerialClose(FileTable[i].com);
FileTable[i].com = 0;
}
}
}
void FilePutStr(int count, char *c, int fnbr)
{
if(filesource[fnbr]==FLASHFILE){
// int err;
FSerror=lfs_file_write(&lfs, FileTable[fnbr].lfsptr, c, count);
if(FSerror!=count)FSerror=-5;
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr);
} else {
unsigned int bw;
InitSDCard();
FSerror = f_write(FileTable[fnbr].fptr, c, count, &bw);
ErrorCheck(fnbr);
diskchecktimer = DISKCHECKRATE;
}
}
// output a string to a file
// the string must be a MMBasic string
void MMfputs(unsigned char *p, int filenbr)
{
int i;
i = *p++;
if (FileTable[filenbr].com > MAXCOMPORTS)
{
FilePutStr(i, (char *)p, filenbr);
}
else
{
while (i--)
MMfputc(*p++, filenbr);
}
}
// this is invoked as a command (ie, date$ = "6/7/2010")
// search through the line looking for the equals sign and step over it,
// evaluate the rest of the command, split it up and save in the system counters
int InitSDCard(void)
{
if(!FatFSFileSystem) return 1;
int i;
ErrorThrow(0,NONEFILE); // reset mm.errno to zero
if (((IsInvalidPin(Option.SD_CS) && !Option.CombinedCS) || (IsInvalidPin(Option.SYSTEM_MOSI) && IsInvalidPin(Option.SD_MOSI_PIN)) || (IsInvalidPin(Option.SYSTEM_MISO) && IsInvalidPin(Option.SD_MISO_PIN)) || (IsInvalidPin(Option.SYSTEM_CLK) && IsInvalidPin(Option.SD_CLK_PIN))))
error("SDcard not configured");
if (!(SDCardStat & STA_NOINIT))
return 1; // if the card is present and has been initialised we have nothing to do
for (i = 0; i < MAXOPENFILES; i++)
if (FileTable[i].com > MAXCOMPORTS)
if (FileTable[i].fptr != NULL)
ForceFileClose(i);
i = f_mount(&FatFs, "", 1);
if (i)
{
FatFSFileSystem=0;
ErrorThrow(i,FATFSFILE);
return false;
}
return 2;
}
void getfullfilename(char *fname, char *q){
int waste=0, t=FatFSFileSystem+1;
if(*cmdline){
t = drivecheck(fname,&waste);
fname+=waste;
}
FatFSFileSystem=t-1;
char pp[FF_MAX_LFN] = {0};
char *p=fname;
int i;
i=strlen(p)-1;
while(i>0 && !(p[i]=='/'))i--;
if(i>0){
memcpy(q,p,i);
if(q[1]==':')q[0]='0';
i++;
}
strcpy(pp,&p[i]);
if((pp[0]=='/') && i==0){
strcpy(q,&pp[1]);
strcpy(pp,q);
strcpy(q,"0:/");
}
fullpath(q);
// MMPrintString("Was: ");MMPrintString(fname);PRet();
// MMPrintString("Path: ");MMPrintString(filepath[FatFSFileSystem]);PRet();
// MMPrintString("File: ");MMPrintString(pp);PRet();
strcpy(q,fullpathname[FatFSFileSystem]);
if(fullpathname[FatFSFileSystem][strlen(fullpathname[FatFSFileSystem])-1]!='/')strcat(q,"/");
strcat(q,pp);
// MMPrintString("Full: ");MMPrintString(q);PRet();
}
// this performs the basic duties of opening a file, all file opens in MMBasic should use this
// it will open the file, set the FileTable[] entry and populate the file descriptor
// it returns with true if successful or false if an error
int BasicFileOpen(char *fname, int fnbr, int mode)
{
if (fnbr < 1 || fnbr > MAXOPENFILES) error("File number");
if (FileTable[fnbr].com != 0) error("File number already open");
char q[FF_MAX_LFN]={0};
getfullfilename(fname,q);
if(FatFSFileSystem){
if (!InitSDCard())
return false;
// if we are writing check the write protect pin (negative pin number means that low = write protect)
FileTable[fnbr].fptr = GetMemory(sizeof(FIL)); // allocate the file descriptor
SDbuffer[fnbr] = GetMemory(SDbufferSize);
FSerror = f_open(FileTable[fnbr].fptr, q, mode); // open it
ErrorCheck(fnbr);
filesource[fnbr] = FATFSFILE;
buffpointer[fnbr] = 0;
lastfptr[fnbr] = -1;
bw[fnbr] = -1;
fmode[fnbr] = mode;
} else {
int lfsmode=0;
if(mode == FA_READ)lfsmode=LFS_O_RDONLY;
else if(mode==(FA_WRITE | FA_CREATE_ALWAYS))lfsmode=LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC;
else if(mode==(FA_WRITE | FA_OPEN_APPEND)) lfsmode = LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND;
else if(mode==(FA_WRITE | FA_OPEN_APPEND | FA_READ))lfsmode =LFS_O_RDWR | LFS_O_CREAT;
else error("Internal error");
FileTable[fnbr].lfsptr = GetMemory(sizeof(lfs_file_t)); // allocate the file descriptor
if(mode!=LFS_O_RDONLY && ExistsFile(q))lfs_removeattr(&lfs, q, 'A');
FSerror=lfs_file_open(&lfs, FileTable[fnbr].lfsptr, q, lfsmode);
if(mode!=LFS_O_RDONLY){
int dt=get_fattime();
FSerror=lfs_setattr(&lfs, q, 'A', &dt, 4);
ErrorCheck(0);
if(mode != (FA_WRITE | FA_CREATE_ALWAYS))lfs_file_seek(&lfs, FileTable[fnbr].lfsptr, lfs_file_size(&lfs,FileTable[fnbr].lfsptr), LFS_SEEK_SET);
lfs_file_sync(&lfs, FileTable[fnbr].lfsptr);
}
ErrorCheck(fnbr);
filesource[fnbr] = FLASHFILE;
}
#ifdef USBKEYBOARD
clearrepeat();
#endif
if (FSerror)
{
ForceFileClose(fnbr);
return false;
}
else {
FatFSFileSystem=FatFSFileSystemSave;
return true;
}
}
#define MAXFILES 1000
typedef struct ss_flist
{
char fn[FF_MAX_LFN];
int fs; // file size
int fd; // file date
int ft; // file time
} s_flist;
int strcicmp(char const *a, char const *b)
{
for (;; a++, b++)
{
int d = tolower(*a) - tolower(*b);
if (d != 0 || !*a)
return d;
}
}
void B2A(unsigned char *fromfile, unsigned char *tofile){
char buff[512];
unsigned int nbr = 0;
int fnbr1, fnbr2;
fnbr1 = FindFreeFileNbr();
FatFSFileSystem=1; //set to SD
BasicFileOpen((char *)fromfile, fnbr1, FA_READ);
fnbr2 = FindFreeFileNbr();
FatFSFileSystem=0; //set to flash
if (!BasicFileOpen((char *)tofile, fnbr2, FA_WRITE | FA_CREATE_ALWAYS))
{
FileClose(fnbr1);
}
while (!f_eof(FileTable[fnbr1].fptr))
{
FSerror = f_read(FileTable[fnbr1].fptr, buff, 512, &nbr);
ErrorCheck(fnbr1);
FSerror=lfs_file_write(&lfs, FileTable[fnbr2].lfsptr, buff, nbr);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr2);
}
FileClose(fnbr1);
FileClose(fnbr2);
FatFSFileSystem=FatFSFileSystemSave;
}
void A2B(unsigned char *fromfile, unsigned char *tofile){
char buff[512];
unsigned int nbr = 0, bw;
int fnbr1, fnbr2;
FatFSFileSystem=0; //set to flash
fnbr1 = FindFreeFileNbr();
BasicFileOpen((char *)fromfile, fnbr1, FA_READ);
fnbr2 = FindFreeFileNbr();
FatFSFileSystem=1; //set to SD
if (!BasicFileOpen((char *)tofile, fnbr2, FA_WRITE | FA_CREATE_ALWAYS))
{
FileClose(fnbr1);
}
while (!(lfs_file_tell(&lfs,FileTable[fnbr1].lfsptr)==lfs_file_size(&lfs,FileTable[fnbr1].lfsptr)))
{
nbr=lfs_file_read(&lfs, FileTable[fnbr1].lfsptr, buff, 512);
if(nbr<0)FSerror=nbr;
ErrorCheck(fnbr1);
FSerror = f_write(FileTable[fnbr2].fptr, buff, nbr, &bw);
ErrorCheck(fnbr2);
}
FileClose(fnbr1);
FileClose(fnbr2);
FatFSFileSystem=FatFSFileSystemSave;
}
void B2B(unsigned char *fromfile, unsigned char *tofile){
char buff[512];
unsigned int nbr = 0, bw;
int fnbr1, fnbr2;
fnbr1 = FindFreeFileNbr();
FatFSFileSystem=1; //set to SD
BasicFileOpen((char *)fromfile, fnbr1, FA_READ);
FatFSFileSystem=1; //set to SD
fnbr2 = FindFreeFileNbr();
if (!BasicFileOpen((char *)tofile, fnbr2, FA_WRITE | FA_CREATE_ALWAYS))
{
FileClose(fnbr1);
}
while (!f_eof(FileTable[fnbr1].fptr))
{
FSerror = f_read(FileTable[fnbr1].fptr, buff, 512, &nbr);
ErrorCheck(fnbr1);
FSerror = f_write(FileTable[fnbr2].fptr, buff, nbr, &bw);
ErrorCheck(fnbr2);
}
FileClose(fnbr1);
FileClose(fnbr2);
FatFSFileSystem=FatFSFileSystemSave;
}
void A2A(unsigned char *fromfile, unsigned char *tofile){
char buff[512];
unsigned int nbr = 0;
int fnbr1, fnbr2;
fnbr1 = FindFreeFileNbr();
FatFSFileSystem=0; //set to FLASH
BasicFileOpen((char *)fromfile, fnbr1, FA_READ);
fnbr2 = FindFreeFileNbr();
FatFSFileSystem=0; //set to FLASH
if (!BasicFileOpen((char *)tofile, fnbr2, FA_WRITE | FA_CREATE_ALWAYS))
{
FileClose(fnbr1);
}
while (!(lfs_file_tell(&lfs,FileTable[fnbr1].lfsptr)==lfs_file_size(&lfs,FileTable[fnbr1].lfsptr)))
{
nbr=lfs_file_read(&lfs, FileTable[fnbr1].lfsptr, buff, 512);
if(nbr<0)FSerror=nbr;
ErrorCheck(fnbr1);
FSerror=lfs_file_write(&lfs, FileTable[fnbr2].lfsptr, buff, nbr);
if(FSerror>0)FSerror=0;
ErrorCheck(fnbr2);
}
FileClose(fnbr1);
FileClose(fnbr2);
FatFSFileSystem=FatFSFileSystemSave;
}
int drivecheck(char *p, int *waste){
*waste=0;
if(strlen(p)==2){
if(!(p[1]==':')) return FatFSFileSystem+1;
if(*p=='a' || *p=='A') {
*waste=2;
return FLASHFILE;
} else if(*p=='b' || *p=='B') {
*waste=2;
return FATFSFILE;
} else error("Invalid disk");
return FatFSFileSystem+1;
} else {
if(!(p[1]==':' && (p[2]=='/'))) return FatFSFileSystem+1;
if(*p=='a' || *p=='A') {
*waste=2;
return FLASHFILE;
} else if(*p=='b' || *p=='B') {
*waste=2;
return FATFSFILE;
} else error("Invalid disk");
return FatFSFileSystem+1;
}
}
/* @endcond */
void MIPS16 cmd_copy(void)
{
unsigned char *p=GetTempMemory(STRINGSIZE);
memcpy(p,cmdline,STRINGSIZE);
char ss[2]; // this will be used to split up the argument line
unsigned char *fromfile, *tofile;
ss[0] = tokenTO;
ss[1] = 0;
int waste;
unsigned char *tp = checkstring(cmdline, (unsigned char *)"B2A");
if(tp){
getargs(&tp, 3, (unsigned char *)ss);
if (argc != 3) error("Syntax");
fromfile = getFstring(argv[0]);
tofile = getFstring(argv[2]);
B2A(fromfile,tofile);
return;
}
tp = checkstring(cmdline, (unsigned char *)"A2B");
if(tp){
getargs(&tp, 3, (unsigned char *)ss);
if (argc != 3) error("Syntax");
fromfile = getFstring(argv[0]);
tofile = getFstring(argv[2]);
A2B(fromfile,tofile);
return;
}
tp = checkstring(cmdline, (unsigned char *)"A2A");
if(tp){
getargs(&tp, 3, (unsigned char *)ss);
if (argc != 3) error("Syntax");
fromfile = getFstring(argv[0]);
tofile = getFstring(argv[2]);
A2A(fromfile,tofile);
return;
}
tp = checkstring(cmdline, (unsigned char *)"B2B");
if(tp){
getargs(&tp, 3, (unsigned char *)ss);
if (argc != 3) error("Syntax");
fromfile = getFstring(argv[0]);
tofile = getFstring(argv[2]);
B2B(fromfile,tofile);
return;
}
getargs(&p, 3, (unsigned char *)ss);
if (argc != 3) error("Syntax");
fromfile = getFstring(argv[0]);
tofile = getFstring(argv[2]);
int tofilesystem;
char todir[FF_MAX_LFN]={0};
int fromfilesystem;
char fromdir[FF_MAX_LFN]={0};
if(strchr((char *)fromfile,'*') || strchr((char *)fromfile,'?')){ //wildcard in the source so bulk copy
unsigned char *in=GetTempMemory(STRINGSIZE);
unsigned char *out=GetTempMemory(STRINGSIZE);
// MMPrintString("Bulk copying\r\n");
int localsave=FatFSFileSystem;
if(!(ExistsDir((char *)tofile, todir, &tofilesystem))){
FatFSFileSystem=localsave;
error("$ not a directory",tofile);
}
int waste=0, t=FatFSFileSystem+1;
t = drivecheck((char *)getFstring(argv[0]),&waste);
argv[0]+=waste;
*argv[0]='"';
FatFSFileSystem=t-1;
int i;
// uint32_t currentdate;
char *p;
// char ts[FF_MAX_LFN] = {0};
char pp[FF_MAX_LFN] = {0};
char q[FF_MAX_LFN] = {0};
DIR djd;
FILINFO fnod;
memset(&djd, 0, sizeof(DIR));
memset(&fnod, 0, sizeof(FILINFO));
p = (char *)getFstring(argv[0]);
i = strlen(p) - 1;
while (i > 0 && !(p[i] == '/'))
i--;
if (i > 0)
{
memcpy(q, p, i);
if (q[1] == ':')
q[0] = '0';
i++;
}
strcpy(pp, &p[i]);
if ((pp[0] == '/') && i == 0)
{
strcpy(q, &pp[1]);
strcpy(pp, q);
strcpy(q, "0:/");
}
if (pp[0] == 0)
strcpy(pp, "*");
if (CurrentLinePtr)
error("Invalid in a program");
FatFSFileSystem=t-1;
if (!InitSDCard())
error((char *)FErrorMsg[20]); // setup the SD card
FatFSFileSystem=t-1;
fullpath(q);
if(!(ExistsDir(fullpathname[FatFSFileSystem],fromdir,&fromfilesystem))){
FatFSFileSystem=localsave;
error("$ not a directory",fromdir);
}
// MMPrintString(fromdir);putConsole(':',0);MMPrintString(todir);PRet();
// PInt(fromfilesystem);PIntComma(tofilesystem);PRet();
if(fromfilesystem==tofilesystem && strcmp(fromdir,todir)==0){
FatFSFileSystem=localsave;
error("Source and destination are the same");
}
if(fromfilesystem==0) FSerror=lfs_dir_open(&lfs, &lfs_dir, fromdir);
else FSerror = f_findfirst(&djd, &fnod, fromdir, pp);
ErrorCheck(0);
if(fromfilesystem){
while (FSerror == FR_OK && fnod.fname[0])
{
if (!(fnod.fattrib & (AM_SYS | AM_HID | AM_DIR)))
{
// add a prefix to each line so that directories will sort ahead of files
// currentsize = fnod.fsize;
// and concatenate the filename found
MMPrintString("Copying ");
MMPrintString(fnod.fname);PRet();
strcpy((char *)in,fromdir);
strcpy((char *)out,todir);
if(in[strlen((char *)in)-1]!='/')strcat((char *)in,"/");
if(out[strlen((char *)out)-1]!='/')strcat((char *)out,"/");
strcat((char *)out,fnod.fname);
strcat((char *)in,fnod.fname);
if(fromfilesystem==1 && tofilesystem==1)B2B(in,out);
else if(fromfilesystem==0 && tofilesystem==0)A2A(in,out);
else if(fromfilesystem==1 && tofilesystem==0)B2A(in,out);
else if(fromfilesystem==0 && tofilesystem==1)A2B(in,out);
}
FSerror = f_findnext(&djd, &fnod);
}
} else {
while(1){
int found=0;
FSerror=lfs_dir_read(&lfs, &lfs_dir, &lfs_info);
if(FSerror==0)break;
if(FSerror<0)ErrorCheck(0);
if (lfs_info.type==LFS_TYPE_DIR && pattern_matching(pp, lfs_info.name, 0, 0))
{
continue;
}
else if (lfs_info.type==LFS_TYPE_REG && pattern_matching(pp, lfs_info.name, 0, 0))
{
found=1;
}
if(found){
// currentsize = lfs_info.size;
// and concatenate the filename found
MMPrintString("Copying ");
MMPrintString(lfs_info.name);PRet();
strcpy((char *)in,fromdir);
strcpy((char *)out,todir);
if(in[strlen((char *)in)-1]!='/')strcat((char *)in,"/");
if(out[strlen((char *)out)-1]!='/')strcat((char *)out,"/");
strcat((char *)out,lfs_info.name);
strcat((char *)in,lfs_info.name);
if(fromfilesystem==1 && tofilesystem==1)B2B(in,out);
else if(fromfilesystem==0 && tofilesystem==0)A2A(in,out);
else if(fromfilesystem==1 && tofilesystem==0)B2A(in,out);
else if(fromfilesystem==0 && tofilesystem==1)A2B(in,out);
}
}
}
if(fromfilesystem) f_closedir(&djd);
else lfs_dir_close(&lfs, &lfs_dir);
FatFSFileSystem=FatFSFileSystemSave;
return;
}
if(drivecheck((char *)fromfile, &waste)==FLASHFILE && drivecheck((char *)tofile, &waste)==FLASHFILE){
A2A(fromfile,tofile);
return;
}
if(drivecheck((char *)fromfile, &waste)==FATFSFILE && drivecheck((char *)tofile, &waste)==FATFSFILE){
B2B(fromfile,tofile);
return;
}
if(drivecheck((char *)fromfile, &waste)==FLASHFILE && drivecheck((char *)tofile, &waste)==FATFSFILE){
A2B(fromfile,tofile);
return;
}
if(drivecheck((char *)fromfile, &waste)==FATFSFILE && drivecheck((char *)tofile, &waste)==FLASHFILE){
B2A(fromfile,tofile);
return;
}
FatFSFileSystem=FatFSFileSystemSave;
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
int resolve_path(char *path, char *result, char *pos)
{
if (*path == '/')
{
*result = '/';
pos = result + 1;
path++;
}
*pos = 0;
if (!*path)
return 0;
while (1)
{
char *slash;
struct stat st;
st.st_mode = 0;
slash = *path ? strchr(path, '/') : NULL;
if (slash)
*slash = 0;
if (!path[0] || (path[0] == '.' &&
(!path[1] || (path[1] == '.' && !path[2]))))
{
pos--;
if (pos != result && path[0] && path[1])
while (*--pos != '/')
;
}
else
{
strcpy(pos, path);
// if (lstat(result,&st) < 0) return -1;
if (S_ISLNK(st.st_mode))
{
char buf[PATH_MAX];
// if (readlink(result,buf,sizeof(buf)) < 0) return -1;
*pos = 0;
if (slash)
{
*slash = '/';
strcat(buf, slash);
}
strcpy(path, buf);
if (*path == '/')
result[1] = 0;
pos = strchr(result, 0);
continue;
}
pos = strchr(result, 0);
}
if (slash)
{
*pos++ = '/';
path = slash + 1;
}
*pos = 0;
if (!slash)
break;
}
return 0;
}
void fullpath(char *q)
{
char *p = GetMemory(STRINGSIZE);
char *rp = GetMemory(STRINGSIZE);
char *fp=p;
char *frp=rp;
// int i;
strcpy(p, q);
memset(fullpathname[FatFSFileSystem], 0, sizeof(fullpathname[FatFSFileSystem]));
strcpy(fullpathname[FatFSFileSystem], filepath[FatFSFileSystem]);
if (strcmp(p, ".") == 0 || strlen(p) == 0)
{
memmove(fullpathname[FatFSFileSystem], &fullpathname[FatFSFileSystem][2], strlen(fullpathname[FatFSFileSystem]));
// MMPrintString("Now: ");MMPrintString(fullpathname);PRet();
FreeMemory((unsigned char *)fp);
FreeMemory((unsigned char *)frp);
return; // nothing to do
}
if (p[1] == ':')
{ // modify the requested path so that if the disk is specified the pathname is absolute and starts with /
if (p[2] == '/')
p += 2;
else
{
p[1] = '/';
p++;
}
}
if (*p == '/')
{ // absolute path specified
strcpy(rp, FatFSFileSystem==0?"A:":"B:");
strcat(rp, p);
}
else
{ // relative path specified
strcpy(rp, fullpathname[FatFSFileSystem]); // copy the current pathname
if (rp[strlen(rp) - 1] != '/')
strcat(rp, "/"); // make sure the previous pathname ends in slash, will only be the case at root
strcat(rp, p); // append the new pathname
}
strcpy(fullpathname[FatFSFileSystem], rp); // set the new pathname
resolve_path(fullpathname[FatFSFileSystem], rp, rp); // resolve to single absolute path
if (strcmp(rp, "A:") == 0 || strcmp(rp, "0:") == 0 || strcmp(rp, "B:") == 0)
strcat(rp, "/"); // if root append the slash
strcpy(fullpathname[FatFSFileSystem], rp); // store this back to the filepath variable
memmove(fullpathname[FatFSFileSystem], &fullpathname[FatFSFileSystem][2], strlen(fullpathname[FatFSFileSystem]));
// MMPrintString("Now: ");MMPrintString(fullpathname[FatFSFileSystem]);PRet();
FreeMemory((unsigned char *)fp);
FreeMemory((unsigned char *)frp);
}
void getfullpath(char *p, char *q){
// int j;
strcpy(q,p);
if(q[1]==':')q[0]='0';
fullpath(q);
strcpy(q,fullpathname[FatFSFileSystem]);
}
void getfullfilepath(char *p, char *q){
int i;
char pp[FF_MAX_LFN] = {0};
i=strlen(p)-1;
while(i>0 && !(p[i]=='/'))i--;
if(i>0){
memcpy(q,p,i);
if(q[1]==':')q[0]='0';
i++;
}
strcpy(pp,&p[i]);
if((pp[0]=='/') && i==0){
strcpy(q,&pp[1]);
strcpy(pp,q);
strcpy(q,"0:/");
}
fullpath(q);
strcpy(q,fullpathname[FatFSFileSystem]);
if(q[strlen(q)-1]!='/')strcat(q,"/");
strcat(q,pp);
}
/* @endcond */
void MIPS16 cmd_files(void)
{
// if(CurrentLinePtr) error("Invalid in a program");
int waste=0, t=FatFSFileSystem+1;
unsigned char cmdbuffer[STRINGSIZE]={0};
unsigned char *cmdbuf=cmdbuffer;
strcpy((char *)cmdbuf,(char *)cmdline);
if(*cmdbuf){
t = drivecheck((char *)getFstring(cmdline),&waste);
cmdbuf+=waste;
*cmdbuf='"';
}
int oldfont=PromptFont;
if(!CurrentLinePtr){
ClearVars(0,true);
ClearRuntime(true);
}
SetFont(oldfont);
int i, c, dirs, currentsize;
static int ListCnt=2;
uint32_t currentdate;
char *p, extension[8];
int fcnt, sortorder = 0;
char ts[FF_MAX_LFN] = {0};
char pp[FF_MAX_LFN] = {0};
char q[FF_MAX_LFN] = {0};
static s_flist *flist = NULL;
char outbuff[STRINGSIZE]={0};
DIR djd;
FILINFO fnod;
memset(&djd, 0, sizeof(DIR));
memset(&fnod, 0, sizeof(FILINFO));
fcnt = 0;
if (*cmdbuf)
{
getargs(&cmdbuf, 3, (unsigned char *)",");
if (!(argc == 1 || argc == 3))
error("Syntax");
p = (char *)getFstring(argv[0]);
i = strlen(p) - 1;
while (i > 0 && !(p[i] == '/'))
i--;
if (i > 0)
{
memcpy(q, p, i);
if (q[1] == ':')
q[0] = '0';
i++;
}
strcpy(pp, &p[i]);
if ((pp[0] == '/') && i == 0)
{
strcpy(q, &pp[1]);
strcpy(pp, q);
strcpy(q, "0:/");
}
if (argc == 3)
{
if (checkstring(argv[2], (unsigned char *)"NAME"))
sortorder = 0;
else if (checkstring(argv[2], (unsigned char *)"TIME"))
sortorder = 1;
else if (checkstring(argv[2], (unsigned char *)"SIZE"))
sortorder = 2;
else if (checkstring(argv[2], (unsigned char *)"TYPE"))
sortorder = 3;
else
error("Syntax");
}
}
if(CurrentLinePtr){
CloseAudio(1);
SaveContext();
ClearVars(0,false);
InitHeap(false);
}
if (pp[0] == 0)
strcpy(pp, "*");
FatFSFileSystem=t-1;
if (!InitSDCard())
error((char *)FErrorMsg[20]); // setup the SD card
FatFSFileSystem=t-1;
fullpath(q);
if(Option.DISPLAY_CONSOLE){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;}
putConsole('A'+FatFSFileSystem,0);
putConsole(':',1);
MMPrintString(fullpathname[FatFSFileSystem]);PRet();
if(FatFSFileSystem==0) FSerror=lfs_dir_open(&lfs, &lfs_dir, fullpathname[FatFSFileSystem]);
else FSerror = f_findfirst(&djd, &fnod, fullpathname[FatFSFileSystem], pp);
ErrorCheck(0);
flist = GetMemory(sizeof(s_flist) * MAXFILES);
// add the file to the list, search for the next and keep looping until no more files
if(FatFSFileSystem){
while (FSerror == FR_OK && fnod.fname[0])
{
#ifdef PICOMITEWEB
ProcessWeb(1);
#endif
if (fcnt >= MAXFILES)
{
FreeMemorySafe((void **)&flist);
f_closedir(&djd);
error("Too many files to list");
}
if (!(fnod.fattrib & (AM_SYS | AM_HID)))
{
// add a prefix to each line so that directories will sort ahead of files
if (fnod.fattrib & AM_DIR)
{
ts[0] = 'D';
currentdate = 0xFFFFFFFF;
fnod.fdate = 0xFFFF;
fnod.ftime = 0xFFFF;
memset(extension, '+', sizeof(extension));
extension[sizeof(extension) - 1] = 0;
}
else
{
ts[0] = 'F';
currentdate = (fnod.fdate << 16) | fnod.ftime;
if (fnod.fname[strlen(fnod.fname) - 1] == '.')
strcpy(extension, &fnod.fname[strlen(fnod.fname) - 1]);
else if (fnod.fname[strlen(fnod.fname) - 2] == '.')
strcpy(extension, &fnod.fname[strlen(fnod.fname) - 2]);
else if (fnod.fname[strlen(fnod.fname) - 3] == '.')
strcpy(extension, &fnod.fname[strlen(fnod.fname) - 3]);
else if (fnod.fname[strlen(fnod.fname) - 4] == '.')
strcpy(extension, &fnod.fname[strlen(fnod.fname) - 4]);
else if (fnod.fname[strlen(fnod.fname) - 5] == '.')
strcpy(extension, &fnod.fname[strlen(fnod.fname) - 5]);
else
{
memset(extension, '.', sizeof(extension));
extension[sizeof(extension) - 1] = 0;
}
}
currentsize = fnod.fsize;
// and concatenate the filename found
strcpy(&ts[1], fnod.fname);
// sort the file name into place in the array
if (sortorder == 0)
{
for (i = fcnt; i > 0; i--)
{
if (strcicmp((flist[i - 1].fn), (ts)) > 0)
flist[i] = flist[i - 1];
else
break;
}
}
else if (sortorder == 2)
{
for (i = fcnt; i > 0; i--)
{
if ((flist[i - 1].fs) > currentsize)
flist[i] = flist[i - 1];
else
break;
}
}
else if (sortorder == 3)
{
for (i = fcnt; i > 0; i--)
{
char e2[8];
if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 1] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 1]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 2] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 2]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 3] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 3]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 4] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 4]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 5] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 5]);
else
{
if (flist[i - 1].fn[0] == 'D')
{
memset(e2, '+', sizeof(e2));
e2[sizeof(e2) - 1] = 0;
}
else
{
memset(e2, '.', sizeof(e2));
e2[sizeof(e2) - 1] = 0;
}
}
if (strcicmp((e2), (extension)) > 0)
flist[i] = flist[i - 1];
else
break;
}
}
else
{
for (i = fcnt; i > 0; i--)
{
if (((flist[i - 1].fd << 16) | flist[i - 1].ft) < currentdate)
flist[i] = flist[i - 1];
else
break;
}
}
strcpy(flist[i].fn, ts);
flist[i].fs = fnod.fsize;
flist[i].fd = fnod.fdate;
flist[i].ft = fnod.ftime;
fcnt++;
}
FSerror = f_findnext(&djd, &fnod);
}
} else {
while(1){
#ifdef PICOMITEWEB
ProcessWeb(1);
#endif
int found=0;
FSerror=lfs_dir_read(&lfs, &lfs_dir, &lfs_info);
if(FSerror==0)break;
// if(!lfs_info.type){
// FSerror=lfs_dir_close(&lfs, &lfs_dir); ErrorCheck(0);
// break;
// }
if(FSerror<0)ErrorCheck(0);
if (lfs_info.type==LFS_TYPE_DIR && pattern_matching(pp, lfs_info.name, 0, 0))
{
ts[0] = 'D';
currentdate = 0xFFFFFFFF;
memset(extension, '+', sizeof(extension));
fnod.fdate = 0xFFFF;
fnod.ftime = 0xFFFF;
extension[sizeof(extension) - 1] = 0;
found=1;
}
else if (lfs_info.type==LFS_TYPE_REG && pattern_matching(pp, lfs_info.name, 0, 0))
{
ts[0] = 'F';
if (lfs_info.name[strlen(lfs_info.name) - 1] == '.')
strcpy(extension, &lfs_info.name[strlen(lfs_info.name) - 1]);
else if (lfs_info.name[strlen(lfs_info.name) - 2] == '.')
strcpy(extension, &lfs_info.name[strlen(lfs_info.name) - 2]);
else if (lfs_info.name[strlen(lfs_info.name) - 3] == '.')
strcpy(extension, &lfs_info.name[strlen(lfs_info.name) - 3]);
else if (lfs_info.name[strlen(lfs_info.name) - 4] == '.')
strcpy(extension, &lfs_info.name[strlen(lfs_info.name) - 4]);
else if (lfs_info.name[strlen(lfs_info.name) - 5] == '.')
strcpy(extension, &lfs_info.name[strlen(lfs_info.name) - 5]);
else
{
memset(extension, '.', sizeof(extension));
extension[sizeof(extension) - 1] = 0;
}
found=1;
}
if(found){
currentsize = lfs_info.size;
// and concatenate the filename found
strcpy(&ts[1], lfs_info.name);
int dt;
char fullfilename[STRINGSIZE];
strcpy(fullfilename,fullpathname[FatFSFileSystem]);
strcat(fullfilename,"/");
strcat(fullfilename,lfs_info.name);
FSerror=lfs_getattr(&lfs, fullfilename, 'A', &dt, 4);
if(FSerror!=4){
fnod.fdate=0;
fnod.ftime=0;
} else {
WORD *p=(WORD *)&dt;
fnod.fdate=(WORD)p[1];
fnod.ftime=(WORD)p[0];
}
currentdate = (fnod.fdate << 16) | fnod.ftime;
// sort the file name into place in the array
if (sortorder == 0)
{
for (i = fcnt; i > 0; i--)
{
if (strcicmp((flist[i - 1].fn), (ts)) > 0)
flist[i] = flist[i - 1];
else
break;
}
}
else if (sortorder == 2)
{
for (i = fcnt; i > 0; i--)
{
if ((flist[i - 1].fs) > currentsize)
flist[i] = flist[i - 1];
else
break;
}
}
else if (sortorder == 3)
{
for (i = fcnt; i > 0; i--)
{
char e2[8];
if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 1] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 1]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 2] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 2]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 3] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 3]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 4] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 4]);
else if (flist[i - 1].fn[strlen(flist[i - 1].fn) - 5] == '.')
strcpy(e2, &flist[i - 1].fn[strlen(flist[i - 1].fn) - 5]);
else
{
if (flist[i - 1].fn[0] == 'D')
{
memset(e2, '+', sizeof(e2));
e2[sizeof(e2) - 1] = 0;
}
else
{
memset(e2, '.', sizeof(e2));
e2[sizeof(e2) - 1] = 0;
}
}
if (strcicmp((e2), (extension)) > 0)
flist[i] = flist[i - 1];
else
break;
}
}
else
{
for (i = fcnt; i > 0; i--)
{
if (((flist[i - 1].fd << 16) | flist[i - 1].ft) < currentdate)
flist[i] = flist[i - 1];
else
break;
}
}
strcpy(flist[i].fn, ts);
flist[i].fs = lfs_info.size;
flist[i].fd = fnod.fdate;
flist[i].ft = fnod.ftime;
fcnt++;
}
}
}
// list the files with a pause every screen full
ListCnt = 3;
unsigned char noscroll=Option.NoScroll;
if((void *)ReadBuffer!=(void *)DisplayNotSet && Option.DISPLAY_CONSOLE)Option.NoScroll=0;
for (i = dirs = 0; i < fcnt; i++)
{
memset(outbuff,0,sizeof(outbuff));
#ifdef PICOMITEWEB
ProcessWeb(1);
#endif
if (flist[i].fn[0] == 'D')
{
dirs++;
strcpy(outbuff," <DIR> ");
// MMPrintString(" <DIR> ");
}
else
{
IntToStrPad(ts, (flist[i].ft >> 11) & 0x1F, '0', 2, 10);
ts[2] = ':';
IntToStrPad(ts + 3, (flist[i].ft >> 5) & 0x3F, '0', 2, 10);
ts[5] = ' ';
IntToStrPad(ts + 6, flist[i].fd & 0x1F, '0', 2, 10);
ts[8] = '-';
IntToStrPad(ts + 9, (flist[i].fd >> 5) & 0xF, '0', 2, 10);
ts[11] = '-';
IntToStr(ts + 12, ((flist[i].fd >> 9) & 0x7F) + 1980, 10);
ts[16] = ' ';
IntToStrPad(ts + 17, flist[i].fs, ' ', 10, 10);
strcpy(outbuff,ts);
strcat(outbuff," ");
}
strcat(outbuff,flist[i].fn + 1);
char *pp=outbuff;
while(*pp) {
if(MMCharPos >= Option.Width) ListNewLine(&ListCnt, 1);
MMputchar(*pp++,0);
}
fflush(stdout);
ListNewLine(&ListCnt, 1);
// check if it is more than a screen full
if (ListCnt >= Option.Height-overlap && i < fcnt)
{
unsigned char noscroll=Option.NoScroll;
if((void *)ReadBuffer!=(void *)DisplayNotSet && Option.DISPLAY_CONSOLE)Option.NoScroll=0;
#ifdef USBKEYBOARD
clearrepeat();
#endif
MMPrintString("PRESS ANY KEY ...");
Option.NoScroll=noscroll;
do
{
ShowCursor(1);
#ifdef PICOMITEWEB
ProcessWeb(1);
#endif
routinechecks();
if (MMAbort)
{
FreeMemorySafe((void **)&flist);
if(FatFSFileSystem) f_closedir(&djd);
else lfs_dir_close(&lfs, &lfs_dir);
WDTimer = 0; // turn off the watchdog timer
memset(inpbuf, 0, STRINGSIZE);
ShowCursor(false);
FatFSFileSystem=FatFSFileSystemSave;
PromptFont=oldfont;
if(CurrentLinePtr)RestoreContext(false);
MMAbort=false;
return;
// longjmp(mark, 1);
}
c = -1;
if (ConsoleRxBufHead != ConsoleRxBufTail)
{ // if the queue has something in it
c = ConsoleRxBuf[ConsoleRxBufTail];
ConsoleRxBufTail = (ConsoleRxBufTail + 1) % CONSOLE_RX_BUF_SIZE; // advance the head of the queue
}
} while (c == -1);
ShowCursor(0);
MMPrintString("\r \r");
if(Option.DISPLAY_CONSOLE){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;}
ListCnt = 2;
}
}
// display the summary
IntToStr(ts, dirs, 10);
MMPrintString(ts);
MMPrintString(" director");
MMPrintString(dirs == 1 ? "y, " : "ies, ");
IntToStr(ts, fcnt - dirs, 10);
MMPrintString(ts);
MMPrintString(" file");
MMPrintString((fcnt - dirs) == 1 ? "" : "s");
FreeMemorySafe((void **)&flist);
if(FatFSFileSystem) f_closedir(&djd);
else {
lfs_dir_close(&lfs, &lfs_dir);
IntToStr(ts, Option.FlashSize-(Option.modbuff ? 1024*Option.modbuffsize : 0)-RoundUpK4(TOP_OF_SYSTEM_FLASH)-lfs_fs_size(&lfs)*4096,10);
MMPrintString(", ");
MMPrintString(ts);
MMPrintString(" bytes free");
}
MMPrintString("\r\n");
memset(inpbuf, 0, STRINGSIZE);
FatFSFileSystem=FatFSFileSystemSave;
Option.NoScroll=noscroll;
PromptFont=oldfont;
if(CurrentLinePtr)RestoreContext(false);
return;
// longjmp(mark, 1);
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
// remove unnecessary text
void CrunchData(unsigned char **p, int c)
{
static unsigned char inquotes, lastch, incomment;
if (c == '\n')
c = '\r'; // CR is the end of line terminator
if (c == 0 || c == '\r')
{
inquotes = false;
incomment = false; // newline so reset our flags
if (c)
{
if (lastch == '\r')
return; // remove two newlines in a row (ie, empty lines)
*((*p)++) = '\r';
}
lastch = '\r';
return;
}
if (incomment)
return; // discard comments
if (c == ' ' && lastch == '\r')
return; // trim all spaces at the start of the line
if (c == '"')
inquotes = !inquotes;
if (inquotes)
{
*((*p)++) = c; // copy everything within quotes
return;
}
if (c == '\'')
{ // skip everything following a comment
incomment = true;
return;
}
if (c == ' ' && (lastch == ' ' || lastch == ','))
{
lastch = ' ';
return; // remove more than one space or a space after a comma
}
*((*p)++) = lastch = c;
}
/* @endcond */
int check_line_length(const char *text ,int *linein) {
int current_length = 0;
int max_length = 0;
const char *ptr = text;
int line=0;
while (*ptr) {
if (*ptr == '\r') {
line++;
// If this line exceeds the max, update
if (current_length > max_length) {
max_length = current_length;
*linein=line;
}
current_length = 0; // Reset for a new line
} else {
// Increase length for this segment of the line
current_length++;
}
ptr++;
}
// Final check in case the last line was the longest
if (current_length > max_length) {
max_length = current_length;
}
return max_length;
}
void cmd_autosave(void)
{
unsigned char *buf, *p;
int c, prevc = 0, crunch = false;
int count = 0;
uint64_t timeout;
if (CurrentLinePtr)error("Invalid in a program");
char *tp=(char *)checkstring(cmdline,(unsigned char *)"APPEND");
if(tp){
ClearVars(0,true);
CloseAudio(1);
CloseAllFiles();
ClearExternalIO(); // this MUST come before InitHeap(true)
#ifdef PICOMITEWEB
if(TCPstate){
for(int i=0;i<MaxPcb;i++)FreeMemory(TCPstate->buffer_recv[i]);
}
#endif
p = buf = GetTempMemory(EDIT_BUFFER_SIZE);
char * fromp = (char *)ProgMemory;
p = buf;
while(*fromp != 0xff) {
if(*fromp == T_NEWLINE) {
fromp = (char *)llist((unsigned char *)p, (unsigned char *)fromp); // otherwise expand the line
p += strlen((char *)p);
*p++ = '\n'; *p = 0;
}
// finally, is it the end of the program?
if(fromp[0] == 0 || fromp[0] == 0xff) break;
}
goto readin;
}
if (*cmdline)
{
if (toupper(*cmdline) == 'C')
crunch = true;
else
error("Syntax");
}
ClearProgram(false); // clear any leftovers from the previous program
p = buf = GetTempMemory(EDIT_BUFFER_SIZE);
CrunchData(&p, 0); // initialise the crunch data subroutine
readin:;
while ((c = MMInkey()) != 0x1a && c != F1 && c != F2)
{ // while waiting for the end of text char
if (c == -1 && count && time_us_64() - timeout > 100000)
{
fflush(stdout);
count = 0;
}
if (p == buf && c == '\n')
continue; // throw away an initial line feed which can follow the command
if ((p - buf) >= EDIT_BUFFER_SIZE)
error("Not enough memory");
if (isprint(c) || c == '\r' || c == '\n' || c == TAB)
{
if (c == TAB)
c = ' ';
if (crunch)
CrunchData(&p, c); // insert into RAM after throwing away comments. etc
else
*p++ = c; // insert the input into RAM
{
if (!(c == '\n' && prevc == '\r'))
{
MMputchar(c, 0);
count++;
timeout = time_us_64();
} // and echo it
if (c == '\r')
{
MMputchar('\n', 1);
count = 0;
}
}
prevc = c;
}
}
fflush(stdout);
*p = 0; // terminate the string in RAM
while (getConsole() != -1)
; // clear any rubbish in the input
// ClearSavedVars(); // clear any saved variables
SaveProgramToFlash(buf, true);
ClearSavedVars(); // clear any saved variables
ClearTempMemory();
#ifdef PICOMITEWEB
if(TCPstate){
for(int i=0;i<MaxPcb;i++)TCPstate->buffer_recv[i]=GetMemory(TCP_READ_BUFFER_SIZE);
}
#endif
if (c == F2)
{
ClearVars(0,true);
strcpy((char *)inpbuf, "RUN\r\n");
multi=false;
tokenise(true); // turn into executable code
ExecuteProgram(tknbuf); // execute the line straight away
}
}
/*
void cmd_autosave(void)
{
unsigned char *buf, *p;
int c, prevc = 0, crunch = false;
int count = 0;
uint64_t timeout;
if (CurrentLinePtr)error("Invalid in a program");
if(!checkstring(cmdline,(unsigned char *)"APPEND")){
FlashLoad=0;
uSec(250000);
FlashWriteInit(PROGRAM_FLASH);
flash_range_erase(realflashpointer, MAX_PROG_SIZE);
FlashWriteByte(0); FlashWriteByte(0); FlashWriteByte(0); // terminate the program in flash
FlashWriteClose();
if (*cmdline)
{
if (toupper(*cmdline) == 'C')
crunch = true;
else
error("Syntax");
}
CrunchData(&p, 0); // initialise the crunch data subroutine
}
ClearVars(0,true);
CloseAudio(1);
CloseAllFiles();
ClearExternalIO(); // this MUST come before InitHeap(true)
#ifdef PICOMITEWEB
if(TCPstate){
for(int i=0;i<MaxPcb;i++)FreeMemory(TCPstate->buffer_recv[i]);
}
#endif
p = buf = GetTempMemory(EDIT_BUFFER_SIZE-2048);
char * fromp = (char *)ProgMemory;
if(*fromp){
p = buf;
while(*fromp != 0xff) {
if(*fromp == T_NEWLINE) {
fromp = (char *)llist((unsigned char *)p, (unsigned char *)fromp); // otherwise expand the line
p += strlen((char *)p);
*p++ = '\n'; *p = 0;
}
// finally, is it the end of the program?
if(fromp[0] == 0 || fromp[0] == 0xff) break;
}
}
while ((c = MMInkey()) != 0x1a && c != F1 && c != F2)
{ // while waiting for the end of text char
if (c == -1 && count && time_us_64() - timeout > 100000)
{
fflush(stdout);
count = 0;
}
if (p == buf && c == '\n')
continue; // throw away an initial line feed which can follow the command
if ((p - buf) >= EDIT_BUFFER_SIZE-2048)
error("Not enough memory");
if (isprint(c) || c == '\r' || c == '\n' || c == TAB)
{
if (c == TAB)
c = ' ';
if (crunch)
CrunchData(&p, c); // insert into RAM after throwing away comments. etc
else
*p++ = c; // insert the input into RAM
{
if (!(c == '\n' && prevc == '\r'))
{
MMputchar(c, 0);
count++;
timeout = time_us_64();
} // and echo it
if (c == '\r')
{
MMputchar('\n', 1);
count = 0;
}
}
prevc = c;
}
}
fflush(stdout);
*p = 0; // terminate the string in RAM
while (getConsole() != -1)
; // clear any rubbish in the input
// ClearSavedVars(); // clear any saved variables
int j,i=0;
j=check_line_length((char *)buf,&i);
if(j>255)error("line % is % characters long, maximum is 255",i,j);
SaveProgramToFlash(buf, true);
ClearSavedVars(); // clear any saved variables
ClearTempMemory();
#ifdef PICOMITEWEB
if(TCPstate){
for(int i=0;i<MaxPcb;i++)TCPstate->buffer_recv[i]=GetMemory(TCP_READ_BUFFER_SIZE);
}
#endif
if (c == F2)
{
ClearVars(0,true);
strcpy((char *)inpbuf, "RUN\r\n");
multi=false;
tokenise(true); // turn into executable code
ExecuteProgram(tknbuf); // execute the line straight away
}
// }
}*/
/*
* @cond
* The following section will be excluded from the documentation.
*/
void FileOpen(char *fname, char *fmode, char *ffnbr)
{
int fnbr;
BYTE mode = 0;
if (str_equal((const unsigned char *)fmode, (const unsigned char *)"OUTPUT"))
mode = FA_WRITE | FA_CREATE_ALWAYS;
else if (str_equal((const unsigned char *)fmode, (const unsigned char *)"APPEND"))
mode = FA_WRITE | FA_OPEN_APPEND;
else if (str_equal((const unsigned char *)fmode, (const unsigned char *)"INPUT"))
mode = FA_READ;
else if (str_equal((const unsigned char *)fmode, (const unsigned char *)"RANDOM"))
mode = FA_WRITE | FA_OPEN_APPEND | FA_READ;
else
error("File access mode");
if (*ffnbr == '#')
ffnbr++;
fnbr = getinteger((unsigned char *)ffnbr);
BasicFileOpen(fname, fnbr, mode);
}
/* @endcond */
void cmd_open(void)
{
int fnbr;
char *fname;
char ss[4]; // this will be used to split up the argument line
ss[0] = tokenAS;
ss[1] = tokenFOR;
ss[2] = ',';
ss[3] = 0;
{ // start a new block
getargs(&cmdline, 7, (unsigned char *)ss); // getargs macro must be the first executable stmt in a block
if (!(argc == 3 || argc == 5 || argc == 7))
error("Syntax");
fname = (char *)getFstring(argv[0]);
// check that it is a serial port that we are opening
if (argc == 5 && !(mem_equal((unsigned char *)fname, (unsigned char *)"COM1:", 5) || mem_equal((unsigned char *)fname, (unsigned char *)"COM2:", 5)))
{
FileOpen(fname, (char *)argv[2], (char *)argv[4]);
diskchecktimer = DISKCHECKRATE;
return;
}
if (!(mem_equal((unsigned char *)fname, (unsigned char *)"COM1:", 5) || mem_equal((unsigned char *)fname, (unsigned char *)"COM2:", 5)))
error("Invalid COM port");
if ((*argv[2] == 'G') || (*argv[2] == 'g'))
{
MMFLOAT timeadjust = 0.0;
argv[2]++;
if (!((*argv[2] == 'P') || (*argv[2] == 'p')))
error("Syntax");
argv[2]++;
if (!((*argv[2] == 'S') || (*argv[2] == 's')))
error("Syntax");
if (argc >= 5)
timeadjust = getnumber(argv[4]);
if (timeadjust < -12.0 || timeadjust > 14.0)
error("Invalid Time Offset");
gpsmonitor = 0;
if (argc == 7)
gpsmonitor = getint(argv[6], 0, 1);
GPSadjust = (int)(timeadjust * 3600.0);
// check that it is a serial port that we are opening
SerialOpen((unsigned char *)fname);
fnbr = FindFreeFileNbr();
GPSfnbr = fnbr;
FileTable[fnbr].com = fname[3] - '0';
if (mem_equal((unsigned char *)fname, (unsigned char *)"COM1:", 5))
GPSchannel = 1;
if (mem_equal((unsigned char *)fname, (unsigned char *)"COM2:", 5))
GPSchannel = 2;
gpsbuf = gpsbuf1;
gpscurrent = 0;
gpscount = 0;
}
else
{
if (*argv[2] == '#')
argv[2]++;
fnbr = getint(argv[2], 1, MAXOPENFILES);
if (FileTable[fnbr].com != 0)
error("Already open");
SerialOpen((unsigned char *)fname);
FileTable[fnbr].com = fname[3] - '0';
}
}
}
void fun_inputstr(void)
{
int i, nbr, fnbr;
getargs(&ep, 3, (unsigned char *)",");
if (argc != 3)
error("Syntax");
sret = GetTempMemory(STRINGSIZE); // this will last for the life of the command
nbr = getint(argv[0], 1, MAXSTRLEN);
if (*argv[2] == '#')
argv[2]++;
fnbr = getinteger(argv[2]);
if (fnbr == 0)
{ // accessing the console
for (i = 1; i <= nbr && kbhitConsole(); i++)
sret[i] = getConsole(); // get the char from the console input buffer and save in our returned string
}
else
{
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
targ = T_STR;
if (FileTable[fnbr].com > MAXCOMPORTS)
{
for (i = 1; i <= nbr && !MMfeof(fnbr); i++)
sret[i] = FileGetChar(fnbr); // get the char from the SD card and save in our returned string
*sret = i - 1; // update the length of the string
return; // all done so skip the rest
}
for (i = 1; i <= nbr && SerialRxStatus(FileTable[fnbr].com); i++)
sret[i] = SerialGetchar(FileTable[fnbr].com); // get the char from the serial input buffer and save in our returned string
}
*sret = i - 1;
}
void fun_eof(void)
{
int fnbr;
getargs(&ep, 1, (unsigned char *)",");
if (argc == 0)
error("Syntax");
if (*argv[0] == '#')
argv[0]++;
fnbr = getinteger(argv[0]);
iret = MMfeof(fnbr);
targ = T_INT;
}
void cmd_flush(void)
{
int fnbr;
getargs(&cmdline, 1, (unsigned char *)",");
if (*argv[0] == '#')
argv[0]++;
fnbr = getinteger(argv[0]);
if (fnbr == 0) // accessing the console
return;
else
{
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
if (FileTable[fnbr].com > MAXCOMPORTS )
{
if(filesource[fnbr]==FATFSFILE)f_sync(FileTable[fnbr].fptr);
else lfs_file_sync(&lfs, FileTable[fnbr].lfsptr);
}
else
{
while (SerialTxStatus(FileTable[fnbr].com))
{
}
}
}
}
#define RoundUptoBlock(a) ((((uint64_t)a) + (uint64_t)(511)) & (uint64_t)(~(511)))// round up to the nearest whole integer
void fun_loc(void)
{
int fnbr;
getargs(&ep, 1, (unsigned char *)",");
if (argc == 0)
error("Syntax");
if (*argv[0] == '#')
argv[0]++;
fnbr = getinteger(argv[0]);
if (fnbr == 0) // accessing the console
iret = kbhitConsole();
else
{
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
if (FileTable[fnbr].com > MAXCOMPORTS)
{
if(filesource[fnbr]==FLASHFILE)iret = lfs_file_tell(&lfs,FileTable[fnbr].lfsptr) + 1;
else {
// iret = (*(FileTable[fnbr].fptr)).fptr + 1;
if(fmode[fnbr] & FA_WRITE){
iret = (*(FileTable[fnbr].fptr)).fptr + 1;
} else {
iret = (RoundUptoBlock((*(FileTable[fnbr].fptr)).fptr) -511 + buffpointer[fnbr]);
if(iret<0)iret+=512;
}
}
}
else
iret = SerialRxStatus(FileTable[fnbr].com);
}
targ = T_INT;
}
void fun_lof(void)
{
int fnbr;
getargs(&ep, 1, (unsigned char *)",");
if (argc == 0)
error("Syntax");
if (*argv[0] == '#')
argv[0]++;
fnbr = getinteger(argv[0]);
if (fnbr == 0) // accessing the console
iret = 0;
else
{
if (fnbr < 1 || fnbr > MAXOPENFILES)
error("File number");
if (FileTable[fnbr].com == 0)
error("File number is not open");
if (FileTable[fnbr].com > MAXCOMPORTS)
{
if(filesource[fnbr]==FATFSFILE){
f_sync(FileTable[fnbr].fptr);
iret = f_size(FileTable[fnbr].fptr);
} else {
lfs_file_sync(&lfs, FileTable[fnbr].lfsptr);
iret = FileTable[fnbr].lfsptr->ctz.size;
}
}
else
iret = (TX_BUFFER_SIZE - SerialTxStatus(FileTable[fnbr].com));
}
targ = T_INT;
}
void cmd_close(void)
{
int i, fnbr;
getargs(&cmdline, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block
if ((argc & 0x01) == 0)
error("Syntax");
for (i = 0; i < argc; i += 2)
{
if ((*argv[i] == 'G') || (*argv[i] == 'g'))
{
argv[i]++;
if (!((*argv[i] == 'P') || (*argv[i] == 'p')))
error("Syntax");
argv[i]++;
if (!((*argv[i] == 'S') || (*argv[i] == 's')))
error("Syntax");
if (!GPSfnbr)
error("Not open");
SerialClose(FileTable[GPSfnbr].com);
FileTable[GPSfnbr].com = 0;
GPSfnbr = 0;
GPSchannel = 0;
GPSlatitude = 0;
GPSlongitude = 0;
GPSspeed = 0;
GPSvalid = 0;
GPStime[1] = '0';
GPStime[2] = '0';
GPStime[4] = '0';
GPStime[5] = '0';
GPStime[7] = '0';
GPStime[8] = '0';
GPSdate[1] = '0';
GPSdate[2] = '0';
GPSdate[4] = '0';
GPSdate[5] = '0';
GPSdate[9] = '0';
GPSdate[10] = '0';
GPStrack = 0;
GPSdop = 0;
GPSsatellites = 0;
GPSaltitude = 0;
GPSfix = 0;
GPSadjust = 0;
gpsmonitor = 0;
}
else
{
if (*argv[i] == '#')
argv[i]++;
fnbr = getint(argv[i], 1, MAXOPENFILES);
if (FileTable[fnbr].com == 0)
error("File number is not open");
while (SerialTxStatus(FileTable[fnbr].com) && !MMAbort)
; // wait for anything in the buffer to be transmitted
if (FileTable[fnbr].com > MAXCOMPORTS)
{
FileClose(fnbr);
diskchecktimer = DISKCHECKRATE;
}
else
SerialClose(FileTable[fnbr].com);
FileTable[fnbr].com = 0;
}
}
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
void CheckSDCard(void)
{
if (!(SDCardStat & STA_NOINIT))
{ // the card is supposed to be initialised - lets check
char buff[4];
if (disk_ioctl(0, MMC_GET_OCR, buff) != RES_OK)
{
BYTE s;
s = SDCardStat;
s |= (STA_NODISK | STA_NOINIT);
SDCardStat = s;
ShowCursor(false);
if(!CurrentLinePtr)MMPrintString("Warning: SDcard Removed\r\n> ");
FatFSFileSystem=0;
}
}
diskchecktimer = DISKCHECKRATE;
}
void LoadOptions(void)
{
int i = sizeof(struct option_s);
unsigned char *pp = (unsigned char *)flash_option_contents;
unsigned char *qq = (unsigned char *)&Option;
while (i--) *qq++ = *pp++;
RGB121map[0] = BLACK;
RGB121map[1] = BLUE;
RGB121map[2] = MYRTLE;
RGB121map[3] = COBALT;
RGB121map[4] = MIDGREEN;
RGB121map[5] = CERULEAN;
RGB121map[6] = GREEN;
RGB121map[7] = CYAN;
RGB121map[8] = RED;
RGB121map[9] = MAGENTA;
RGB121map[10] = RUST;
RGB121map[11] = FUCHSIA;
RGB121map[12] = BROWN;
RGB121map[13] = LILAC;
RGB121map[14] = YELLOW;
RGB121map[15] = WHITE;
#ifdef PICOCALC
Option.DISPLAY_TYPE = ST7796SP;
Option.SYSTEM_CLK = 14;
Option.SYSTEM_MOSI = 15;
Option.SYSTEM_MISO = 16;
Option.DISPLAY_BL = 0; //stm32 control the backlight
Option.LCD_CD = 19;
Option.LCD_CS = 17;
Option.LCD_Reset = 20;
Option.DISPLAY_ORIENTATION = PORTRAIT;
Option.DISPLAY_CONSOLE = 1;
Option.SerialConsole = 1;
Option.SerialTX = 1;
Option.SerialRX = 2;
Option.CombinedCS = 0;
Option.SD_CS = 22;
Option.SD_CLK_PIN = 24;
Option.SD_MOSI_PIN = 25;
Option.SD_MISO_PIN = 21;
Option.TOUCH_CS = 0;
Option.TOUCH_IRQ = 0;
Option.DefaultFC = GREEN;
Option.AUDIO_L = 31;
Option.AUDIO_R = 32;
Option.AUDIO_SLICE=5;
Option.AUDIO_CLK_PIN=0;
Option.AUDIO_MOSI_PIN = 0;
Option.AUDIO_DCS_PIN = 0;
Option.AUDIO_DREQ_PIN = 0;
Option.AUDIO_RESET_PIN = 0;
Option.KeyboardConfig =CONFIG_I2C;
Option.SYSTEM_I2C_SDA = 9;
Option.SYSTEM_I2C_SCL = 10;
Option.SYSTEM_I2C_SLOW=1; //10khz for picocalc
Option.DefaultFont = 0x01;
Option.BGR = 1;
Option.BackLightLevel = 20; //default 20,sync with i2c keyboard
Option.ColourCode = 1;
strcpy((char *)Option.platform,"PicoCalc");
#endif
}
void ResetOptions(bool startup)
{
if(!startup){
disable_sd();
disable_audio();
disable_systemi2c();
disable_systemspi();
}
memset((void *)&Option, 0, sizeof(struct option_s));
Option.Magic = MagicKey;
Option.Height = SCREENHEIGHT;
Option.Width = SCREENWIDTH;
Option.Tab = 2;
Option.DefaultFont = 0x01;
Option.DefaultBrightness = 100;
Option.Baudrate = CONSOLE_BAUDRATE;
Option.PROG_FLASH_SIZE=MAX_PROG_SIZE;
Option.ColourCode=0x01;
#ifdef PICOMITEVGA
Option.DISPLAY_CONSOLE = 1;
Option.DISPLAY_TYPE = SCREENMODE1;
// Option.VGAFC = 0xFFFF;
Option.X_TILE=80;
Option.Y_TILE=40;
Option.CPU_Speed = Freq252P;
#ifdef USBKEYBOARD
#ifdef HDMI
Option.HDMIclock=2;
Option.HDMId0=0;
Option.HDMId1=6;
Option.HDMId2=4;
#endif
Option.USBKeyboard = CONFIG_US;
Option.RepeatStart=600;
Option.RepeatRate=150;
Option.SerialConsole = 2;
Option.SerialTX = 11;
Option.SerialRX = 12;
Option.capslock=0;
Option.numlock=1;
Option.ColourCode=1;
#else
#ifdef HDMI
Option.HDMIclock=2;
Option.HDMId0=0;
Option.HDMId1=6;
Option.HDMId2=4;
#else
Option.VGA_HSYNC=21;
Option.VGA_BLUE=24;
#endif
Option.KEYBOARD_CLOCK=KEYBOARDCLOCK;
Option.KEYBOARD_DATA=KEYBOARDDATA;
Option.KeyboardConfig = CONFIG_US;
#endif
#else
Option.CPU_Speed=FreqDefault;
#ifdef USBKEYBOARD
Option.USBKeyboard = CONFIG_US;
Option.RepeatStart=600;
Option.RepeatRate=150;
Option.SerialConsole = 2;
Option.SerialTX = 11;
Option.SerialRX = 12;
Option.capslock=0;
Option.numlock=1;
Option.ColourCode=1;
#else
Option.KeyboardConfig = NO_KEYBOARD;
Option.SSD_RESET = -1;
#endif
#endif
#ifdef PICOMITEWEB
Option.ServerResponceTime=5000;
#endif
Option.AUDIO_SLICE = 99;
Option.SDspeed = 12;
Option.DISPLAY_ORIENTATION = DISPLAY_LANDSCAPE;
Option.DefaultFont = 0x01;
Option.DefaultFC = WHITE;
Option.DefaultBC = BLACK;
Option.LCDVOP = 0xB1;
Option.INT1pin = 9;
Option.INT2pin = 10;
Option.INT3pin = 11;
Option.INT4pin = 12;
#ifndef PICOMITEVGA
Option.TOUCH_XSCALE=1.0f;
Option.TOUCH_YSCALE=1.0f;
#endif
Option.DefaultBrightness = 100;
Option.numlock = 1;
Option.repeat = 0b101100;
Option.VGA_HSYNC=21;
Option.VGA_BLUE=24;
uint8_t txbuf[4] = {0x9f};
uint8_t rxbuf[4] = {0};
Option.heartbeatpin = 43;
#ifdef rp2350
if(!rp2350a){
Option.NoHeartbeat=1;
Option.AllPins=1;
}
#endif
disable_interrupts_pico();
flash_do_cmd(txbuf, rxbuf, 4);
Option.FlashSize= 1 << rxbuf[3];
enable_interrupts_pico();
SaveOptions();
uSec(250000);
}
void ResetAllFlash(void)
{
ResetOptions(true);
ClearSavedVars();
disable_interrupts_pico();
for (int i = 0; i < MAXFLASHSLOTS + 1; i++)
{
uint32_t j = FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE + SAVEDVARS_FLASH_SIZE + (i * MAX_PROG_SIZE);
flash_range_erase(j, MAX_PROG_SIZE);
}
enable_interrupts_pico();
FlashWriteInit(PROGRAM_FLASH);
flash_range_erase(realflashpointer, MAX_PROG_SIZE);
FlashWriteByte(0);
FlashWriteByte(0);
FlashWriteByte(0); // terminate the program in flash
FlashWriteClose();
}
void FlashWriteInit(int region)
{
for (int i = 0; i < 64; i++)
MemWord.i32[i] = 0xFFFFFFFF;
mi8p = 0;
if (region == PROGRAM_FLASH)
realflashpointer = (uint32_t)PROGSTART;
else if (region == SAVED_VARS_FLASH)
realflashpointer = (uint32_t)(FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE);
else if (region == LIBRARY_FLASH)
realflashpointer = (uint32_t)(PROGSTART - MAX_PROG_SIZE); //i.e the last slot
else
realflashpointer = (uint32_t)PROGSTART - MAX_PROG_SIZE*(MAXFLASHSLOTS-region+1);
disable_interrupts_pico();
}
void FlashWriteBlock(void)
{
int i;
uint32_t address = realflashpointer - 256;
// if(address % 32)error("Memory write address");
flash_range_program((const uint32_t)address, (const uint8_t *)&MemWord.i64[0], 256);
for (i = 0; i < 64; i++)
MemWord.i32[i] = 0xFFFFFFFF;
}
void FlashWriteByte(unsigned char b)
{
realflashpointer++;
MemWord.i8[mi8p] = b;
mi8p++;
mi8p %= 256;
if (mi8p == 0)
{
FlashWriteBlock();
}
}
void FlashWriteWord(unsigned int i)
{
FlashWriteByte(i & 0xFF);
FlashWriteByte((i >> 8) & 0xFF);
FlashWriteByte((i >> 16) & 0xFF);
FlashWriteByte((i >> 24) & 0xFF);
}
// Set the pointer to a specific address
void FlashSetAddress(int address) {
realflashpointer=(uint32_t)PROGSTART+address;
}
void FlashWriteAlignWord(void)
{
while ((mi8p %4) != 0)
{
FlashWriteByte(0x0);
}
FlashWriteWord(0xFFFFFFFF);
}
void FlashWriteAlign(void)
{
while (mi8p != 0)
{
FlashWriteByte(0x0);
}
FlashWriteWord(0xFFFFFFFF);
}
void FlashWriteClose(void)
{
while (mi8p != 0)
{
FlashWriteByte(0xff);
}
enable_interrupts_pico();
}
/* @endcond */
/*******************************************************************************************************************
The variables are stored in a reserved flash area (which in total is 2K).
The first few bytes are used for the options. So we must save the options in RAM before we erase, then write the
options back. The variables saved by this command are then written to flash starting just after the options.
********************************************************************************************************************/
void MIPS16 cmd_var(void)
{
unsigned char *p, *buf, *bufp, *varp, *vdata, lastc;
int i, j, nbr = 1, nbr2 = 1, array, type, SaveDefaultType;
int VarList[MAX_ARG_COUNT];
unsigned char *VarDataList[MAX_ARG_COUNT];
if ((p = checkstring(cmdline, (unsigned char *)"CLEAR")))
{
checkend(p);
ClearSavedVars();
return;
}
if ((p = checkstring(cmdline, (unsigned char *)"RESTORE")))
{
char b[MAXVARLEN + 3];
checkend(p);
// SavedVarsFlash = (char*)FLASH_SAVED_VAR_ADDR; // point to where the variables were saved
if (*SavedVarsFlash == 0xFF)
return; // zero in this location means that nothing has ever been saved
SaveDefaultType = DefaultType; // save the default type
bufp = (unsigned char *)SavedVarsFlash; // point to where the variables were saved
while (*bufp != 0xff)
{ // 0xff is the end of the variable list
type = *bufp++; // get the variable type
array = type & 0x80;
type &= 0x7f; // set array to true if it is an array
DefaultType = TypeMask(type); // and set the default type to this
if (array)
{
strcpy(b, (const char *)bufp);
strcat(b, "()");
vdata = findvar((unsigned char *)b, type | V_EMPTY_OK | V_NOFIND_ERR); // find an array
}
else
vdata = findvar(bufp, type | V_FIND); // find or create a non arrayed variable
if (TypeMask(g_vartbl[g_VarIndex].type) != TypeMask(type))
error("$ type conflict", bufp);
if (g_vartbl[g_VarIndex].type & T_CONST)
error("$ is a constant", bufp);
bufp += strlen((char *)bufp) + 1; // step over the name and the terminating zero byte
if (array)
{ // an array has the data size in the next two bytes
nbr = *bufp++;
nbr |= (*bufp++) << 8;
nbr |= (*bufp++) << 16;
nbr |= (*bufp++) << 24;
nbr2 = 1;
for (j = 0; g_vartbl[g_VarIndex].dims[j] != 0 && j < MAXDIM; j++)
nbr2 *= (g_vartbl[g_VarIndex].dims[j] + 1 - g_OptionBase);
if (type & T_STR)
nbr2 *= g_vartbl[g_VarIndex].size + 1;
if (type & T_NBR)
nbr2 *= sizeof(MMFLOAT);
if (type & T_INT)
nbr2 *= sizeof(long long int);
if (nbr2 != nbr)
error("Array size");
}
else
{
if (type & T_STR)
nbr = *bufp + 1;
if (type & T_NBR)
nbr = sizeof(MMFLOAT);
if (type & T_INT)
nbr = sizeof(long long int);
}
while (nbr--)
*vdata++ = *bufp++; // copy the data
}
DefaultType = SaveDefaultType;
return;
}
if ((p = checkstring(cmdline, (unsigned char *)"SAVE")))
{
getargs(&p, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block
if (argc && (argc & 0x01) == 0)
error("Invalid syntax");
// befor we start, run through the arguments checking for errors
// before we start, run through the arguments checking for errors
for (i = 0; i < argc; i += 2)
{
checkend(skipvar(argv[i], false));
VarDataList[i / 2] = findvar(argv[i], V_NOFIND_ERR | V_EMPTY_OK);
VarList[i / 2] = g_VarIndex;
if ((g_vartbl[g_VarIndex].type & (T_CONST | T_PTR)) || g_vartbl[g_VarIndex].level != 0)
error("Invalid variable");
p = &argv[i][strlen((char *)argv[i]) - 1]; // pointer to the last char
if (*p == ')')
{ // strip off any empty brackets which indicate an array
p--;
if (*p == ' ')
p--;
if (*p == '(')
*p = 0;
else
error("Invalid variable");
}
}
// load the current variable save table into RAM
// while doing this skip any variables that are in the argument list for this save
bufp = buf = GetTempMemory(SAVEDVARS_FLASH_SIZE); // build the saved variable table in RAM
// SavedVarsFlash = (char*)FLASH_SAVED_VAR_ADDR; // point to where the variables were saved
varp = (unsigned char *)SavedVarsFlash; // point to where the variables were saved
while (*varp != 0 && *varp != 0xff)
{ // 0xff is the end of the variable list, SavedVarsFlash[4] = 0 means that the flash has never been written to
type = *varp++; // get the variable type
array = type & 0x80;
type &= 0x7f; // set array to true if it is an array
vdata = varp; // save a pointer to the name
while (*varp)
varp++; // skip the name
varp++; // and the terminating zero byte
if (array)
{ // an array has the data size in the next two bytes
nbr = (varp[0] | (varp[1] << 8) | (varp[2] << 16) | (varp[3] << 24)) + 4;
}
else
{
if (type & T_STR)
nbr = *varp + 1;
if (type & T_NBR)
nbr = sizeof(MMFLOAT);
if (type & T_INT)
nbr = sizeof(long long int);
}
for (i = 0; i < argc; i += 2)
{ // scan the argument list
p = &argv[i][strlen((char *)argv[i]) - 1]; // pointer to the last char
lastc = *p; // get the last char
if (lastc <= '%')
*p = 0; // remove the type suffix for the compare
if (strncasecmp((char *)vdata, (char *)argv[i], MAXVARLEN) == 0)
{ // does the entry have the same name?
while (nbr--)
varp++; // found matching variable, skip over the entry in flash (ie, do not copy to RAM)
i = 9999; // force the termination of the for loop
}
*p = lastc; // restore the type suffix
}
// finished scanning the argument list, did we find a matching variable?
// if not, copy this entry to RAM
if (i < 9999)
{
*bufp++ = type | array;
while (*vdata)
*bufp++ = *vdata++; // copy the name
*bufp++ = *vdata++; // and the terminating zero byte
while (nbr--)
*bufp++ = *varp++; // copy the data
}
}
// initialise for writing to the flash
ClearSavedVars();
FlashWriteInit(SAVED_VARS_FLASH);
// now write the variables in RAM recovered from the var save list
while (buf < bufp)
{
FlashWriteByte(*buf++);
}
// now save the variables listed in this invocation of VAR SAVE
for (i = 0; i < argc; i += 2)
{
g_VarIndex = VarList[i / 2]; // previously saved index to the variable
vdata = VarDataList[i / 2]; // pointer to the variable's data
type = TypeMask(g_vartbl[g_VarIndex].type); // get the variable's type
type |= (g_vartbl[g_VarIndex].type & T_IMPLIED); // set the implied flag
array = (g_vartbl[g_VarIndex].dims[0] != 0);
nbr = 1; // number of elements to save
if (array)
{ // if this is an array calculate the number of elements
for (j = 0; g_vartbl[g_VarIndex].dims[j] != 0 && j < MAXDIM; j++)
nbr *= (g_vartbl[g_VarIndex].dims[j] + 1 - g_OptionBase);
type |= 0x80; // an array has the top bit set
}
if (type & T_STR)
{
if (array)
nbr *= (g_vartbl[g_VarIndex].size + 1);
else
nbr = *vdata + 1; // for a simple string variable just save the string
}
if (type & T_NBR)
nbr *= sizeof(MMFLOAT);
if (type & T_INT)
nbr *= sizeof(long long int);
if ((uint32_t)realflashpointer + XIP_BASE - (uint32_t)SavedVarsFlash + 36 + nbr > SAVEDVARS_FLASH_SIZE)
{
FlashWriteClose();
error("Not enough memory");
}
FlashWriteByte(type); // save its type
for (j = 0, p = g_vartbl[g_VarIndex].name; *p && j < MAXVARLEN; p++, j++)
FlashWriteByte(*p); // save the name
FlashWriteByte(0); // terminate the name
if (array)
{ // if it is an array save the number of data bytes
FlashWriteByte(nbr);
FlashWriteByte(nbr >> 8);
FlashWriteByte(nbr >> 16);
FlashWriteByte(nbr >> 24);
}
while (nbr--)
FlashWriteByte(*vdata++); // write the data
}
FlashWriteClose();
return;
}
error("Unknown command");
}
/*
* @cond
* The following section will be excluded from the documentation.
*/
void ClearSavedVars(void)
{
uSec(250000);
disable_interrupts_pico();
flash_range_erase(FLASH_TARGET_OFFSET + FLASH_ERASE_SIZE, SAVEDVARS_FLASH_SIZE);
enable_interrupts_pico();
uSec(10000);
}
void SaveOptions(void)
{
uint8_t buf[FLASH_ERASE_SIZE];
// load flash content to buf
memcpy(buf, (const void*)(XIP_BASE + FLASH_TARGET_OFFSET), FLASH_ERASE_SIZE);
// overwrite the options
memcpy(buf, (const uint8_t *)&Option, sizeof(struct option_s));
uSec(100000);
disable_interrupts_pico();
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_ERASE_SIZE);
enable_interrupts_pico();
uSec(10000);
disable_interrupts_pico();
// save flash block back
flash_range_program(FLASH_TARGET_OFFSET, buf, FLASH_ERASE_SIZE);
enable_interrupts_pico();
}
/* @endcond */