MMEx with SPI Slave to allow legacy devices to communicate with modern media such as USB, SD cards, the internet and all of the mbed\'s other interfaces
Dependencies: NetServices MSCUsbHost mbed TMP102 SDFileSystem
ffuncs.cpp
- Committer:
- DeMein
- Date:
- 2011-02-27
- Revision:
- 0:67a55a82ce06
File content as of revision 0:67a55a82ce06:
/* MMEx for MBED - File I/O Command processing * Copyright (c) 2011 MK * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** \file ffuncs.cpp \brief Commands starting with F for File I/O */ #include "ffuncs.h" FILE *fp1; SDFileSystem sd(p5, p6, p7, p8, fs_sd); MSCFileSystem msc(fs_usb); LocalFileSystem local(fs_local); // directory handles FATFS_DIR dj; DIR *d; char odirectory = NULL; // keeps track of which directory was opened fhandle handles[10]; /** initialize file handles on startup * */ void init_handles() { // initialize the file handles for (int i = 0; i < 10; i++) { // handles[i].filename = NULL; // handles[i].medium = NULL; // handles[i].fsp = NULL; // handles[i].direct = NULL; // handles[i].filemode = NULL; // handles[i].fullpath = NULL; handles[i].fp = NULL; // we only use this to test } } /** main entry for parsing F-commands * */ void parse_F() { err_num = noerror; DBG_msg("parse_F", inbuf); wipesp(inbuf); // first remove space from string if (inbuf[1] != NULL) { switch (inbuf[1]) { case fmount : do_fmount(); // mount storage medium break; case funmount : do_funmount(); // unmount storage medium break; case ffopen : do_ffopen(); // open file break; case ffread : do_ffread(); // read from file break; case ffwrite : do_ffwrite(); // write to file break; case ffclose : do_ffclose(); // close file break; case ffseek : do_ffseek(); // seek to file position break; case fflush : do_fflush(); // flush file break; case fdir : do_fdir(); // get first directory entry break; case fndir : do_fndir(); // get next directory entry break; case fftell : do_fftell(); // get next directory entry break; case ffsize : do_ffsize(); // get next directory entry break; default : do_fdefault(); // command not recognized break; } } else { do_fdefault(); // command not recognized } } /** mount storage device * * syntax: FM[medium]<CR> * \n [medium]: U, S, L */ void do_fmount() { int rslt = 0; DBG_msg("do_fmount", inbuf); if (inbuf[2] != NULL) { switch (inbuf[2]) { case f_sdcard : DBG_msg("do_fmount", "SD, 1st init"); rslt = sd.disk_initialize(); //initialize file system DBG_msg("do_fmount", "SD, 2nd init"); rslt = sd.disk_initialize(); //initialize file system break; case f_local : // mount local flash, nothing really to do, it is always there break; case f_usb : rslt = msc.disk_initialize(); // enumerate USB device break; default : do_fdefault(); // command not recognized break; } } else { do_fdefault(); } if (rslt != noerror) { // could not mount SD or USB device DBG_int("device not mounted", rslt); send_error(err_not_mounted); } } /** unmount storage device * * syntax: FU[medium]<CR> * \n [medium]: U, S, L */ void do_funmount() { // unmount storage device int rslt = 0; DBG_msg("do_funmount", inbuf); if (inbuf[2] != NULL) { switch (inbuf[2]) { case f_sdcard : rslt = sd.disk_sync(); break; case f_local : // sync not needed, class does not have this functions break; case f_usb : rslt = msc.disk_sync(); // enumerate USB device break; default : do_fdefault(); // command not recognized break; } } else { DBG_msg("do_funmount", "argument error"); do_fdefault(); } if (rslt != noerror) { // could not mount SD or USB device // will never see this message DBG_int("device not unmounted", rslt); send_error(err_not_mounted); } } /** open file on storage device * * syntax: FO [handle] [mode] [medium] [name] * \n [handle]: 0..9 * \n [mode] : R, W, A * \n [medium]: U, S, L * \n [name] : filename in 8.3 format * \n anything after FO may be replaced by a Parameter when %n is present */ void do_ffopen() { int han = 0; // variable for handle int i = 0; int pos = 0; int pnum = 0; unsigned char c; char * cstr; wipesp(inbuf); DBG_msg("do_ffopen", inbuf); // check for a % sign in inbuf pos = 2; while ((inbuf[pos] != NULL) && (inbuf[pos] != c_percent)) pos++; if ((inbuf[pos] != NULL) && ((pnum = getpnum(inbuf[pos + 1])) >= 0)) { // found and valid parameter, now insert cstr = new char [param[pnum].size() + 1]; strcpy (cstr, param[pnum].c_str()); DBG_msg("param", cstr); DBG_int("pos", pos); remchar(inbuf, pos, 2); // remove %n, works better for insert DBG_msg("do_ffopen", inbuf); insertstr(inbuf, cstr, pos); // insert DBG_msg("do_ffopen", inbuf); delete[] cstr; } // check the arguments c = inbuf[2]; // [handle] if ((c != NULL) && (c >= '0') && (c <= '9')) { // [handle] in range han = c - '0'; } else { do_fdefault(); return; // terminate this function } if (handles[han].fp != NULL) { // file handle in use! DBG_msg("do_ffopen", "file handle in use"); send_error(err_handle_used); return; } c = inbuf[4]; // [medium] if (c != NULL) { switch (c) { case f_sdcard : handles[han].medium = f_sdcard; strcpy(handles[han].fsp, fsp_sd); break; case f_local : handles[han].medium = f_local; strcpy(handles[han].fsp, fsp_local); break; case f_usb : handles[han].medium = f_usb; strcpy(handles[han].fsp, fsp_usb); break; default : do_fdefault(); // command not recognized break; } } else { do_fdefault(); return; // terminate this function } c = inbuf[3]; // get filemode if (c != NULL) { switch (c) { case 'W' : handles[han].filemode = f_modew; break; case 'R' : handles[han].filemode = f_moder; break; case 'A' : handles[han].filemode = f_modea; break; default : do_fdefault(); // command not recognized break; } } else { do_fdefault(); return; // terminate this function } // now get filename i = 0; while ((inbuf[i + 5] != NULL) && (i <= 13)) { // will not check until end of name, take max 12 chars handles[han].filename[i] = inbuf[i + 5]; i++; handles[han].filename[i] = NULL; // guarantee null terminated string } // create full pathname strcpy(handles[han].fullpath, handles[han].fsp); strcat(handles[han].fullpath, handles[han].filename); char tmp[5]; sprintf(tmp,"%c", handles[han].filemode); DBG_msg("filename:", handles[han].filename); DBG_msg("path :", handles[han].fullpath); DBG_int("handle# :", han); DBG_chr("mode :", handles[han].filemode); DBG_chr("medium :", handles[han].medium); // now open file handles[han].fp = fopen(handles[han].fullpath,tmp); if (handles[han].fp != NULL) { DBG_msg("do_ffopen", "file opened"); } else { DBG_msg("do_ffopen", "file NOT opened"); send_error(err_filenotopen); } } /** read file contents * * syntax: FR [handle] [value] * \n [handle]: 0..9 * \n [value] : number of byte to read * \n when [value]=0 or omitted will read until <EOF>, * reading can be interrupted by sending >F or >I */ void do_ffread() { long int numbytes = 0; long int count = 0; int i, m; int han; bool go = true; bool stopread = false; DBG_msg("do_ffread", inbuf); rx_max = 0; tx_max = 0; int c = inbuf[2]; // [handle] if ((c != NULL) && (c >= '0') && (c <= '9')) { // [handle] in range han = c - '0'; } else { do_fdefault(); return; // exit with error } DBG_int("handle :", han); if (handles[han].fp == NULL) { // file handle not in use! DBG_msg("do_ffread", "no valid file handle"); send_error(err_no_handle); return; } count = 0; // next chars on the commandline is the number of bytes to read if (inbuf[3] == NULL) { // no value on the command line numbytes = 0; } else { // now process line for (i = 3; ((inbuf[i] >='0') && (inbuf[i] <= '9')); i++ ) { numbytes = 10 * numbytes + (inbuf[i] - '0'); } } DBG_int("do_ffread bytes:", numbytes); // now ready to really do the read // must monitor input buffer to check if we need to stop! while (go) { m = mldl.rx_use(); if (m > rx_max) rx_max = m; m = mldl.tx_use(); if (m > tx_max) tx_max = m; c = getc(handles[han].fp); // read one byte // remove comment below to list all bytes read DBG_chr("do_ffread: ", c); if (c == EOF) { // EOF found, send <EOF> sequence mldl.tx_add(c_escape); mldl.tx_add(c_eof); DBG_int("do_ffread: EOF at byte ", count); } else { // no problem, just send data mldl.tx_addp(c); count++; // increase counter } // now check if we have to stop? if (!mldl.rx_empty()) { stopread = (mldl.rxx_read(data_mode) < 0); // intentional stop of read } go = !((c == EOF) || (count == numbytes) || stopread); } // in case the complete file is read, now wait until buffer is emptied while (!stopread && !mldl.tx_empty()) { // keep checking for EOF if (!mldl.rx_empty()) { stopread = (mldl.rxx_read(data_mode) < 0); } } if (stopread) { DBG_msg("do_ffread", "forced stop read received"); mldl.flush_tx(); // empty transmit buffer } DBG_int("do_ffread: end read at byte ", count); DBG_int("rx_max", rx_max); DBG_int("tx_max", tx_max); } /** write to file * * syntax: FW [handle] * \n [handle]: 0..9 * \ wait for prompt, then send data to be written. * End writing by sending >F */ void do_ffwrite() { int han, m; bool go = true; int count = 0; DBG_msg("do_ffwrite", inbuf); int c = inbuf[2]; // [handle] if ((c != NULL) && (c >= '0') && (c <= '9')) { // [handle] in range han = c - '0'; } else { do_fdefault(); return; // check how to exit with error } DBG_int("handle :", han); if (handles[han].fp == NULL) { // file handle not in use! DBG_msg("do_ffwrite", "no valid file handle"); send_error(err_no_handle); return; } send_prompt(); // now send a prompt and we are ready to go while (go) { // as long as we can continue m = mldl.rx_use(); if (m > rx_max) rx_max = m; m = mldl.tx_use(); if (m > tx_max) tx_max = m; c = mldl.rxx_read(data_mode); // get data if ((c == -1) || (c == -2)) go = false; // <EOF> or interrupt if (go) { // remove comment below to list all bytes written DBG_chr("fwrite", c); count++; fputc(c, handles[han].fp); } else { DBG_int("fwrite: ", c); } } DBG_int("fwrite written", count); DBG_int("rx_max", rx_max); DBG_int("tx_max", tx_max); } /** close file * * syntax: FC [handle] * \n [handle]: 0..9 */ void do_ffclose() { int han = 0; int rslt = 0; DBG_msg("do_ffclose", inbuf); char c = inbuf[2]; // file handle should be here if ((c != NULL) && (c >= '0') && (c <= '9')) { // [handle] in range han = c - '0'; } else { do_fdefault(); return; // check how to exit with error } if (handles[han].fp == NULL) { // file handle not in use! DBG_msg("do_ffclose", "no valid file handle"); send_error(err_no_handle); return; } rslt = fclose(handles[han].fp); handles[han].fp = NULL; DBG_int("do_ffclose result", rslt); } /** seek to file position * * syntax: FS [handle] [value] * \n [handle]: 0..9 * \n [value] : new position * \n if [value] is ommitted, will assume 0, * will always seek relative to the start of the file */ void do_ffseek() { DBG_msg("do_ffseek", inbuf); long int position = 0; // max value is 2147483647 int i; int han; int c = inbuf[2]; // [handle] if ((c != NULL) && (c >= '0') && (c <= '9')) { // [handle] in range han = c - '0'; } else { do_fdefault(); return; // check how to exit with error } DBG_int("handle :", han); if (handles[han].fp == NULL) { // file handle not in use! DBG_msg("do_ffseek", "no valid file handle"); send_error(err_no_handle); return; } // next chars on the commandline is the number of bytes to read if (inbuf[3] == NULL) { // no value on the command line position = 0; } else { // now process line for (i = 3; ((inbuf[i] >='0') && (inbuf[i] <= '9')); i++ ) { position = 10 * position + (inbuf[i] - '0'); } } if (fseek(handles[han].fp, position, SEEK_SET) < 0) { // error in fseek send_error(err_seek); return; } } /** flush file * * syntax: FF [handle] * \n [handle]: 0..9 * \n fflush is not implemented in the file systems */ void do_fflush() { DBG_msg("do_fflush", inbuf); } /** open directory and list first entry * * syntax: FD [medium] * \n [medium]: U, S, L * \n returns the first directory item, * subdirectories are not yet supported, * if the listing is empty >F is returned */ void do_fdir() { FILINFO finfo; FRESULT res ; struct dirent *p; char tmp[25]; DBG_msg("do_ffdir", inbuf); if (inbuf[2] != NULL) { switch (inbuf[2]) { case f_sdcard : res = f_opendir(&dj, "0:/"); odirectory = f_sdcard; break; case f_local : d = opendir(rt_local); odirectory = f_local; break; case f_usb : res = f_opendir(&dj, "1:/"); odirectory = f_usb; break; default : do_fdefault(); // command not recognized break; } } else { do_fdefault(); return; } if (odirectory == f_local) { // get listing from local flash if (d != NULL) { if ((p = readdir(d)) != NULL) { sprintf(tmp,"%s", p->d_name); DBG_msg("do_ffdir", tmp); upstring(tmp); mldl.tx_string(tmp); } else { DBG_msg("do_ffdir", "Last directory entry"); mldl.tx_add(c_escape); // send <EOF> sequence mldl.tx_add(c_eof); } } else { // could not open directory DBG_msg("do_ffdir", "Could not open directory"); send_error(err_directory); } } else { // get listing from USB or SD card /* File attribute bits for directory entry */ // #define AM_RDO 0x01 /* Read only */ // #define AM_HID 0x02 /* Hidden */ // #define AM_SYS 0x04 /* System */ // #define AM_VOL 0x08 /* Volume label */ // #define AM_LFN 0x0F /* LFN entry */ // #define AM_DIR 0x10 /* Directory */ // #define AM_ARC 0x20 /* Archive */ if (res == FR_OK) { res = f_readdir(&dj, &finfo); if ((res == FR_OK) && finfo.fname[0] != 0) { if ((finfo.fattrib & AM_DIR) == AM_DIR) { // file is a directory entry sprintf(tmp,"./%s %d", finfo.fname, finfo.fsize); } else { sprintf(tmp,"%s %d", finfo.fname, finfo.fsize); } DBG_msg("ffdir", tmp); upstring(tmp); mldl.tx_string(tmp); } else { DBG_msg("do_ffdir", "Last directory entry"); mldl.tx_add(c_escape); // send <EOF> sequence mldl.tx_add(c_eof); } } else { // could not open directory DBG_msg("do_ffdir", "Could not open directory"); send_error(err_directory); } } } /** lists the next directory item * * syntax: FN [medium] * \n [medium]: U, S, L * returns the next directory item, must be preceded by a FD call. * Subdirectories are not yet supported, * after the last item >F is returned */ void do_fndir() { FILINFO finfo; FRESULT res ; struct dirent *p; char tmp[25]; DBG_msg("do_fndir", inbuf); if (odirectory == f_local) { // get listing from local flash if (d != NULL) { if ((p = readdir(d)) != NULL) { sprintf(tmp,"%s", p->d_name); DBG_msg("ffdir", tmp); upstring(tmp); mldl.tx_string(tmp); } else { DBG_msg("ffdir", "Last directory entry"); mldl.tx_add(c_escape); // send <EOF> sequence mldl.tx_add(c_eof); } } } else { // get listing from USB or SD card res = f_readdir(&dj, &finfo); if ((res == FR_OK) && finfo.fname[0] != 0) { if ((finfo.fattrib & AM_DIR) == AM_DIR) { // file is a directory entry sprintf(tmp,"./%s %d", finfo.fname, finfo.fsize); } else { sprintf(tmp,"%s %d", finfo.fname, finfo.fsize); } DBG_msg("do_fndir", tmp); upstring(tmp); mldl.tx_string(tmp); } else { DBG_msg("do_fndir", "Last directory entry"); mldl.tx_add(c_escape); // send <EOF> sequence mldl.tx_add(c_eof); } } } /** returns the value of the current file pointer * * syntax: FT [handle] * \n [handle]: 0..9 * returns the value of the file pointer for the open file with the * given handle. */ void do_fftell() { int han = 0; int rslt = 0; char tmp[25]; DBG_msg("do_ftell", inbuf); char c = inbuf[2]; // file handle should be here if ((c != NULL) && (c >= '0') && (c <= '9')) { // [handle] in range han = c - '0'; } else { do_fdefault(); return; // check how to exit with error } if (handles[han].fp == NULL) { // file handle not in use! DBG_msg("do_ffclose", "no valid file handle"); send_error(err_no_handle); return; } rslt = ftell(handles[han].fp); sprintf(tmp,"%d", rslt); mldl.tx_string(tmp); DBG_int("do_ftell result", rslt); } /** returns the size of a file * * syntax: FZ [medium] [name] * \n [medium]: S, L or U * \n [name]: valid 8.3 filename * \n argument may contain %n for replacement by the Parameter n * returns the size of a file. This function will open and close the file! */ void do_ffsize() { int i = 0; int pos = 0; int pnum = 0; int size = 0; char filename[20]; char fullpath[50]; char tmp[25]; unsigned char c; char * cstr; wipesp(inbuf); DBG_msg("do_fsize", inbuf); // check for a % sign in inbuf pos = 2; while ((inbuf[pos] != NULL) && (inbuf[pos] != c_percent)) pos++; if ((inbuf[pos] != NULL) && ((pnum = getpnum(inbuf[pos + 1])) >= 0)) { // found and valid parameter, now insert cstr = new char [param[pnum].size() + 1]; strcpy (cstr, param[pnum].c_str()); DBG_msg("param", cstr); DBG_int("pos", pos); remchar(inbuf, pos, 2); // remove %n, works better for insert DBG_msg("do_fsize", inbuf); insertstr(inbuf, cstr, pos); // insert DBG_msg("do_fsize", inbuf); delete[] cstr; } c = inbuf[2]; // [medium] if (c != NULL) { switch (c) { case f_sdcard : strcpy(fullpath, fsp_sd); break; case f_local : strcpy(fullpath, fsp_local); break; case f_usb : strcpy(fullpath, fsp_usb); break; default : do_fdefault(); // command not recognized break; } } else { do_fdefault(); return; // terminate this function } // now get filename i = 0; while ((inbuf[i + 3] != NULL) && (i <= 13)) { // will not check until end of name, take max 13 chars filename[i] = inbuf[i + 3]; i++; filename[i] = NULL; // ensure null terminated string } // create full pathname strcat(fullpath, filename); DBG_msg("filename", fullpath); // now open file FILE *fp = fopen(fullpath, "r"); if (fp != NULL) { DBG_msg("do_fsize", "file opened"); } else { DBG_msg("do_fsize", "file NOT opened"); send_error(err_filenotopen); return; // and get out } fseek(fp, 0L, SEEK_END); // seek to end size = ftell(fp); // get size fclose(fp); // close file sprintf(tmp,"%d", size); mldl.tx_string(tmp); DBG_int("do_fsize result", size); } /** send error message, command not recognized, */ void do_fdefault() { // get version string DBG_msg("do_fdefault", "unsupported command"); send_error(err_novalidcommand); }