/* 12-3-09 Nathan Seidle SparkFun Electronics© 2010 spark at sparkfun.com OpenLog hardware and firmware are released under the Creative Commons Share Alike v3.0 license. http://creativecommons.org/licenses/by-sa/3.0/ Feel free to use, distribute, and sell varients of OpenLog. All we ask is that you include attribution of 'Based on OpenLog by SparkFun'. OpenLog is based on the work of Bill Greiman and sdfatlib: http://code.google.com/p/sdfatlib/ OpenLog is a simple serial logger based on the ATmega328 running at 16MHz. The ATmega328 should be able to talk to high capacity (larger than 2GB) SD cards. The whole purpose of this logger was to create a logger that just powered up and worked. OpenLog ships with standard 57600bps serial bootloader running at 16MHz so you can load new firmware with a simple serial connection. This makes it compatible with Arduino if needed. OpenLog automatically works with 512MB, 1GB, 2GB, 4GB, 8GB, and 16GB microSD cards. We recommend FAT16 for 2GB and smaller cards. We recommend FAT32 for 4GB and larger cards. OpenLog runs at 9600bps by default. This is configurable to 2400, 4800, 9600, 19200, 57600, and 115200bps. You can alter all settings including baud rate and escape characters by editing config.txt found on OpenLog. Type '?' to get a list of supported commands. During power up, you will see '12<'. '1' indicates the serial connection is established. '2' indicates the SD card has been successfully initialized. '<' indicates OpenLog is ready to receive serial characters. Recording constant 115200bps datastreams are supported. Throw it everything you've got! To acheive this maximum record rate, please use the SD card formatter from : http://www.sdcard.org/consumers/formatter/. The fewer files on the card, the faster OpenLog is able to begin logging. 200 files is ok. 2GB worth of music and pictures is not. To a lower dir, use 'cd ..' instead of 'cd..'. Only standard 8.3 file names are supported. "12345678.123" is acceptable. "123456789.123" is not. All file names are pushed to upper case. "NewLog.txt" will become "NEWLOG.TXT". Type 'set' to enter baud rate configuration menu. Select the baud rate and press enter. You will then see a message 'Going to 9600bps...' or some such message. You will need to power down OpenLog, change your system UART settings to match the new OpenLog baud rate and then power OpenLog back up. If you get OpenLog stuck into an unknown baudrate, there is a safety mechanism built-in. Tie the RX pin to ground and power up OpenLog. You should see the LEDs blink back and forth for 2 seconds, then blink in unison. Now power down OpenLog and remove the RX/GND jumper. OpenLog is now reset to 9600bps. Please note: The preloaded STK500 serial bootloader is 2k, and begins at 0x7800 (30,720). If the code is larger than 30,719 bytes, you will get verification errors during serial bootloading. STAT1 LED is sitting on PD5 (Arduino D5) - toggles when character is received STAT2 LED is sitting on PB5 (Arduino D13) - toggles when SPI writes happen LED Flashing errors @ 2Hz: No SD card - 3 blinks Baud rate change (requires power cycle) - 4 blinks OpenLog regularly shuts down to conserve power. If after 1.5 seconds no characters are received, OpenLog will record any unsaved characters and go to sleep. OpenLog will automatically wake up and continue logging the instand a new character is received. If power is lost during normal operation, OpenLog should lose a maximum of the RX_BUFF / 2. This is currently a max of 350 characters. It's actually quite hard to get into this scenario and is rare with normal operation. 8mA idle 18mA actively writing Input voltage on VCC can be 3.3 to 12V. Input voltage on RX-I pin must not exceed 6V. Output voltage on TX-O pin will not be greater than 3.3V. This may cause problems with some systems - for example if your attached microcontroller requires 4V minimum for serial communication (this is rare). OpenLog has progressed significantly over the past year. Please see Changes.txt or GitHub for a full change log. v2.21 ringp fork brought in. Wildcard remove and list commands now work. Remove directory now works! Change directory up/down the tree works again. 28440 bytes used of 30720. ringp brought back many great commands! Thanks ringp! rm LOG*.* works ls *.TXT works cd .. works again ls now correctly shows directories first and files following the directories. To remove a directory, you have to navigate into that directory. For example: >cd TEMP (you are now in TEMP directory) >rm -f TEMP (you are now removing TEMP, and you will be pushed back down one level of the tree) >ls (shows files and directories where TEMP directory used to be, but TEMP directory should be gone) ringp added new commands: efcount: gives the number of files in the current directory. Example: "efcount" returns "count|3". There are 3 files in the current directory. efinfo : gives info about the file in . Example: "efinfo 2" reports "LOG00588.TXT|45". File number 2 is named LOG00588.TXT and is 45 bytes in size. verbose <"on"|"off">: sets whether command errors are verbose (long winded) or just the "!" character. Example: "verbose off" sets verbose off. Then if a command like "blah" is received, then only "!>" is seen from the command line interface. This makes it easier for embedded systems to recognize there was an error. This setting is not recorded to EEPROM. v2.3 Migrated to v10.10.10 of sdfatlib. Moved to inline RX interrupt and buffer. Improved the ability to receive a constant stream at 57600bps. 27334 bytes out of 30720. Remember - we had to completely butcher HardwareSerial.cpp so a normal Arduino installation will not work. C:\arduino-xxxx\hardware\arduino\cores\arduino\HardwareSerial.cpp I removed the receive interupt handler from HardwareSerial.cpp so that we can deal directly with USART_RX_vect in the main code. This allows us to return to the way OpenLog used to operate - by having one buffer split in half. Once one half fills, it is recorded to SD while the other half fills up. This dramatically decreases the time spent in function calls and SD recording, which leads to many fewer characters dropped. The change log at the top of the main code got so large I've moved it to a version controlled "Changes.txt" file. By making all these changes, I have broken many things. Ringp - I could use your help here. I apologize for stomping on so much of your work. I was not good enough to figure out how to re-link from the old function calls to the new sdfatlib setup. Backspace is broken - ringp, I saw this fix in one of your commits, but looking at the code, I don't see how it is supposed to work. Either way, we still get 0x08 when trying to backspace. New sdfatlib doesn't have SdFat.cpp so fileInfo doesn't work. These function calls are marked with //Error I have chosen to dis-allow deprecated functions: #define ALLOW_DEPRECATED_FUNCTIONS 0 This forced some trivial changes to the SD write and new file creation function calls. I believe we've successfully migrated to the new version of sdfatlib. In the command_shell / read_line function : It may be better to pull directly from the UART buffer and use the RX interrupt. For now, we brute force it. Because of all these changes, I need to re-test power consumption. For now, I'm confident it's low enough. Testing with 512 buffer array size 1GB @ 57600 - dropped very little out of 3 tests 1GB @ 115200 - dropped very little out of 2 tests 8GB @ 57600 - Formatted using the sd formater (32k byte allocation size). Dropped nothing. 8GB @ 115200 - dropped very little, dropped none 16GB w/ Lots of files @ 57600 - Drops the first part of the file because of start up delay? 16GB w/ Lots of files @ 115200 1024 array size (and 800) does not run Testing with 700 buffer array size 1GB @ 57600 - 110300 out of 111000 bytes, 110300/111000, 1GB @ 115200 - 111000/111000!, 109600/111000 8GB @ 57600 - 109000/111000, 111000/111000!, 8GB @ 115200 - 111000/111000!, 111000/111000!, 16GB w/ Lots of files @ 57600 - 85120/111000, 85120/111000 16GB w/ Lots of files @ 115200 - 56420 (but once it got going, log looks good). 56420. I am seeing long delays on cards with lots of files. In the above tests, the 16GB test card is a good example. It has 2GB worth of random files in a sub directory. After OpenLog boots, goes to '12<'. After I send ~500 characters OpenLog freezes for a couple seconds, then returns to normal, very fast, operation. During that down time, I believe sdfatlib is searching for an open cluster. The odd thing is that after the cluster is established (after the initial down time) OpenLog performs excellently. I am hoping to create a faux file or pre-write and save to the file or some how get this allocation done before we report the '12<' indicating we are ready. That way, if a card does fill up, as long as the host system is checking for '<', it doesn't matter how long it takes sdfatlib to find the next free cluster. You can see that we drop 700 bytes at a time. That's a bit odd - I'd expect to drop half or 350 at a time. What happens if we shrink the array size to say 256? To be expected, this is bad - way more instances of dropped characters. Added blink for each test to the OpenLog_Test sketch so we can see as the test progresses. http://www.sdcard.org/consumers/formatter/ is the site for SD card formatting. It looks like this program takes a guess at the correct block size. This could help a lot in the future. v2.4 Merged ringp updates. Commands cd, rm, ls work again! New "rm -rf" command to remove directory and its files. 29028 bytes of 30720 (yikes). Thanks ringp! Great work. Remember - we had to completely butcher HardwareSerial.cpp so a normal Arduino installation will not work. C:\arduino-xxxx\hardware\arduino\cores\arduino\HardwareSerial.cpp I've added the modified HardwareSerial.cpp to the Testing at 57600 1GB: 110490/111000, 110490/111000 8GB: 111000/111000, 111000/111000, 111000/111000 16GB: 83890/111000, 84908/111000 The 16GB card with tons of files continue to have problems but the other cards (FAT and FAT32) are acceptable. Whenever possible, use a clean, empty, freshly formatted card. "rm -rf mydirectory" to remove a directory and all its files Windows 7 stores the Arduino hex file is an aweful place. Something like: C:\Users\Main\AppData\Local\Temp\build3390340147786739225.tmp\OpenLog_v2.cpp.hex Added HardwareSerial.cpp and a readme to the main trunk. Added OpenLog_v2.cpp.hex to the main trunk. v2.41 Power loss bug fixed. Adding support for 38400bps for testing with SparkFum 9DOF IMU logging. 29124 bytes of 30720 (yikes) Found a bug in the append_file routine. If the unit is actively logging, file.writes are flying by quickly. But if OpenLog loses power, none of the data is recorded because there is no file.sync. Data would only get recorded if the unit went idle or if user entered escape command. This has since been fixed with two file.sync() commands. v2.5 Improved 'read' command. Added 'reset' command. 28782 bytes of 30720 (yikes) Modified the read command so that we can print extended ASCII characters. The function was also failing to print any value over 127 (limited to signed 8 bits - boo). Thank you wilafau! You proposed excellent, easy fixes. Added raw command during print operation. This allows for non-visible and extended ASCII characters to be printed correctly, if need be. Issuing 'reset' command causes OpenLog to reset and re-read the config file. This is important if you want to change the config file then restart. Removed some of the extraneous prints from the help menu to save on space. v2.51 Improved command prompt parsing (now ignores '\n') We now ignore the \n character when parsing characters from the command prompt. This makes it easier to create code on a microcontroller that correctly controls OpenLog. Previously, println or sprintf commands were adding a \n to the end of the string that would confuse OpenLog. One way around this if you have previous versions is this sprintf(buff, "new blah.txt\r"); Serial.print(buff); //No println, use \r in string instead Also - added a CommandTest sketch to demonstrate how you can control OpenLog from a microcontroller / automate the command prompt */ #include "SdFat.h" #include "SdFatUtil.h" // use functions to print strings from flash memory #include #include //Needed for strcmp_P - string compare in program space #include //Needed for isdigit #include //Needed for sleep_mode #include //Needed for powering down perihperals such as the ADC/TWI and Timers //#include //Needed for the reset command - uses watch dog timer to reset IC //Debug turns on (1) or off (0) a bunch of verbose debug statements. Normally use (0) //#define DEBUG 1 #define DEBUG 0 //Boot time testing is used to see how long it takes to go from power on to ready to receive characters //The problem with this is that millis() is not running while the bootloader is timing out... //Current testing shows that time to boot is around 74ms from a hardware reset and 217ms from a power cycle //#define BOOTTIME_TESTING 1 #define BOOTTIME_TESTING 0 //The bigger the receive buffer, the less likely we are to drop characters at high speed. However, the ATmega has a limited amount of //RAM. This debug mode allows us to view available RAM at various stages of the program //#define RAM_TESTING 1 //On #define RAM_TESTING 0 //Off #define sbi(port, port_pin) ((port) |= (uint8_t)(1 << port_pin)) #define cbi(port, port_pin) ((port) &= (uint8_t)~(1 << port_pin)) //#define RX_BUFF_SIZE 1024 //This larger buffer size does work but may not work in full OpenLog bells and whistles //#define RX_BUFF_SIZE 800 //Bad //#define RX_BUFF_SIZE 700 //Works #define RX_BUFF_SIZE 512 //#define RX_BUFF_SIZE 256 //Drops lots char rxBuffer[RX_BUFF_SIZE]; int rxSpot; //#define Reset_AVR() wdt_enable(WDTO_1S); while(1) {} //Correct way of resetting the ATmega, but doesn't work with Arduino pre-Optiboot bootloader void(* Reset_AVR) (void) = 0; //Dirty way of resetting the ATmega, but it works for now //The very important receive interrupt handler SIGNAL(USART_RX_vect) { rxBuffer[rxSpot++] = UDR0; if(rxSpot == RX_BUFF_SIZE) rxSpot = 0; } char general_buffer[30]; // The folder track depth is used by "cd .." and "pwd" // This looks like an ugly hack but the sdfatlib is not // supporting going back to previous folder yet. // The current handling of "cd .." should be removed when // it's available in the sdfat library. #define FOLDER_TRACK_DEPTH 15 char folderTree[FOLDER_TRACK_DEPTH][12]; #define CFG_FILENAME "config.txt" //EEPROM locations for the various user settings #define LOCATION_BAUD_SETTING 0x01 #define LOCATION_SYSTEM_SETTING 0x02 #define LOCATION_FILE_NUMBER_LSB 0x03 #define LOCATION_FILE_NUMBER_MSB 0x04 #define LOCATION_ESCAPE_CHAR 0x05 #define LOCATION_MAX_ESCAPE_CHAR 0x06 #define BAUD_2400 0 #define BAUD_9600 1 #define BAUD_57600 2 #define BAUD_115200 3 #define BAUD_4800 4 #define BAUD_19200 5 #define BAUD_38400 6 #define MODE_NEWLOG 0 #define MODE_SEQLOG 1 #define MODE_COMMAND 2 // The number of command line arguments // Increase to support more arguments but be aware of the // memory restrictions // command #define MAX_COUNT_COMMAND_LINE_ARGS 5 #define FALSE -1 #define TRUE 0 //STAT1 is a general LED and indicates serial traffic #define STAT1 5 //On PORTD #define STAT1_PORT PORTD #define STAT2 5 //On PORTB #define STAT2_PORT PORTB int statled1 = 5; //This is the normal status LED int statled2 = 13; //This is the SPI LED, indicating SD traffic //Blinking LED error codes #define ERROR_SD_INIT 3 #define ERROR_NEW_BAUD 5 #if !DEBUG // Using OpenLog in an embedded environment // only if not in debug mode. The reason for this // is that we are out of space if the simple embedded is // included #define INCLUDE_SIMPLE_EMBEDDED #endif #define ECHO 0x01 #define EXTENDED_INFO 0x02 #ifdef INCLUDE_SIMPLE_EMBEDDED #define EMBEDDED_END_MARKER 0x08 #endif Sd2Card card; SdVolume volume; SdFile currentDirectory; SdFile file; byte setting_uart_speed; //This is the baud rate that the system runs at, default is 9600 byte setting_system_mode; //This is the mode the system runs in, default is MODE_NEWLOG byte setting_escape_character; //This is the ASCII character we look for to break logging, default is ctrl+z byte setting_max_escape_character; //Number of escape chars before break logging, default is 3 #if BOOTTIME_TESTING unsigned long boottime; //Used to keep track of how long it takes to boot #endif //Used for wild card delete and search struct command_arg { char* arg; //Points to first character in command line argument uint8_t arg_length; // Length of command line argument }; static struct command_arg cmd_arg[MAX_COUNT_COMMAND_LINE_ARGS]; uint8_t feedback_mode = (ECHO | EXTENDED_INFO); #define MIN(a,b) ((a)<(b))?(a):(b) // store error strings in flash to save RAM #define error(s) error_P(PSTR(s)) void error_P(const char *str) { PgmPrint("error: "); SerialPrintln_P(str); if (card.errorCode()) { PgmPrint("SD error: "); Serial.print(card.errorCode(), HEX); Serial.print(','); Serial.println(card.errorData(), HEX); } while(1); } void setup(void) { pinMode(statled1, OUTPUT); //Power down various bits of hardware to lower power usage set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); //Shut off TWI, Timer2, Timer1, ADC power_twi_disable(); power_timer1_disable(); power_timer2_disable(); power_adc_disable(); check_emergency_reset(); //Look to see if the RX pin is being pulled low read_system_settings(); //Load all system settings from EEPROM //Setup UART if(setting_uart_speed == BAUD_2400) Serial.begin(2400); if(setting_uart_speed == BAUD_4800) Serial.begin(4800); if(setting_uart_speed == BAUD_9600) Serial.begin(9600); if(setting_uart_speed == BAUD_19200) Serial.begin(19200); if(setting_uart_speed == BAUD_38400) Serial.begin(38400); if(setting_uart_speed == BAUD_57600) Serial.begin(57600); if(setting_uart_speed == BAUD_115200) Serial.begin(115200); Serial.print("1"); #if RAM_TESTING PgmPrint("Free RAM start: "); Serial.println(FreeRam()); #endif //Setup SD & FAT if (!card.init(SPI_FULL_SPEED)) { PgmPrint("error card.init"); blink_error(ERROR_SD_INIT); } // initialize the SD card if (!volume.init(&card)) { PgmPrint("error volume.init"); blink_error(ERROR_SD_INIT); } // initialize a FAT volume if (!currentDirectory.openRoot(&volume)) { PgmPrint("error openRoot"); blink_error(ERROR_SD_INIT); } // open the root directory Serial.print("2"); #if RAM_TESTING PgmPrint("Free RAM post SD init: "); Serial.println(FreeRam()); #endif //Search for a config file and load any settings found. This will over-ride previous EEPROM settings if found. read_config_file(); memset(folderTree, 0, sizeof(folderTree)); } void loop(void) { //If we are in new log mode, find a new file name to write to if(setting_system_mode == MODE_NEWLOG) newlog(); //If we are in sequential log mode, determine if seqlog.txt has been created or not, and then open it for logging if(setting_system_mode == MODE_SEQLOG) seqlog(); //Once either one of these modes exits, go to normal command mode, which is called by returning to main() command_shell(); while(1); //We should never get this far } int8_t getNextFolderTreeIndex() { int8_t i; for (i = 0; i < FOLDER_TRACK_DEPTH; i++) if (strlen(folderTree[i]) == 0) return i; if (i >= FOLDER_TRACK_DEPTH) i = -1; return i; } //Log to a new file everytime the system boots //Checks the spots in EEPROM for the next available LOG# file name //Updates EEPROM and then appends to the new log file. //Limited to 65535 files but this should not always be the case. void newlog(void) { uint8_t msb, lsb; uint16_t new_file_number; //Combine two 8-bit EEPROM spots into one 16-bit number lsb = EEPROM.read(LOCATION_FILE_NUMBER_LSB); msb = EEPROM.read(LOCATION_FILE_NUMBER_MSB); new_file_number = msb; new_file_number = new_file_number << 8; new_file_number |= lsb; //If both EEPROM spots are 255 (0xFF), that means they are un-initialized (first time OpenLog has been turned on) //Let's init them both to 0 if((lsb == 255) && (msb == 255)) { new_file_number = 0; //By default, unit will start at file number zero EEPROM.write(LOCATION_FILE_NUMBER_LSB, 0x00); EEPROM.write(LOCATION_FILE_NUMBER_MSB, 0x00); } //The above code looks like it will forever loop if we ever create 65535 logs //Let's quit if we ever get to 65534 //65534 logs is quite possible if you have a system with lots of power on/off cycles if(new_file_number == 65534) { //Gracefully drop out to command prompt with some error PgmPrint("!Too many logs:1!"); return; //Bail! } //If we made it this far, everything looks good - let's start testing to see if our file number is the next available //Search for next available log spot char new_file_name[] = "LOG00000.TXT"; while(1) { new_file_number++; if(new_file_number > 65533) //There is a max of 65534 logs { PgmPrint("!Too many logs:2!"); return; } sprintf(new_file_name, "LOG%05d.TXT", new_file_number); //Splice the new file number into this file name //Try to open file, if fail (file doesn't exist), then break if (file.open(¤tDirectory, new_file_name, O_CREAT | O_EXCL | O_WRITE)) break; } file.close(); //Close this new file we just opened //file.writeError = false; // clear any write errors //Record new_file number to EEPROM lsb = (uint8_t)(new_file_number & 0x00FF); msb = (uint8_t)((new_file_number & 0xFF00) >> 8); EEPROM.write(LOCATION_FILE_NUMBER_LSB, lsb); // LSB if (EEPROM.read(LOCATION_FILE_NUMBER_MSB) != msb) EEPROM.write(LOCATION_FILE_NUMBER_MSB, msb); // MSB #if DEBUG PgmPrint("\nCreated new file: "); Serial.println(new_file_name); #endif //Begin writing to file append_file(new_file_name); } //Log to the same file every time the system boots, sequentially //Checks to see if the file SEQLOG.txt is available //If not, create it //If yes, append to it //Return 0 on error //Return anything else on sucess void seqlog(void) { char seq_file_name[13] = "SEQLOG00.TXT"; //Try to create sequential file if (!file.open(¤tDirectory, seq_file_name, O_CREAT | O_WRITE)) { PgmPrint("Error creating SEQLOG\n"); return; } file.close(); //Close this new file we just opened append_file(seq_file_name); } //Appends a stream of serial data to a given file //Assumes the currentDirectory variable has been set before entering the routine //We use the RX interrupt and a circular buffer of 1024 bytes so that we can capture a full stream of //data even at 115200bps //Does not exit until Ctrl+z (ASCII 26) is received //Returns 0 on error //Returns 1 on success uint8_t append_file(char* file_name) { int checkedSpot; char escape_chars_received = 0; // O_CREAT - create the file if it does not exist // O_APPEND - seek to the end of the file prior to each write // O_WRITE - open for write if (!file.open(¤tDirectory, file_name, O_CREAT | O_APPEND | O_WRITE)) { if ((feedback_mode & EXTENDED_INFO) > 0) error("open1"); } #if DEBUG PgmPrintln("File open"); PgmPrintln("Recording"); #endif #ifdef INCLUDE_SIMPLE_EMBEDDED if ((feedback_mode & EMBEDDED_END_MARKER) > 0) Serial.print((char)0x1A); // Ctrl+Z ends the data and marks the start of result #endif Serial.print('<'); //give a different prompt to indicate no echoing digitalWrite(statled1, HIGH); //Turn on indicator LED //Clear out the serial buffer rxSpot = 0; checkedSpot = 0; //Start UART buffered interrupts UCSR0B |= (1< 1200){ //If we haven't seen a character for about 3 seconds, then record the buffer, sync the SD, and shutdown timeout_counter = 0; if(checkedSpot != 0 && checkedSpot != (RX_BUFF_SIZE/2)) //There is stuff in buffer to record before we go to sleep { if(checkedSpot < (RX_BUFF_SIZE/2)) { file.write(rxBuffer, checkedSpot); //Record first half the buffer } else { //checked_spot > (BUFF_LEN/2) file.write(rxBuffer + (RX_BUFF_SIZE/2), checkedSpot - (RX_BUFF_SIZE/2)); //Record second half the buffer } // rxSpot may have moved while we , copy unsigned spot = checkedSpot > RX_BUFF_SIZE/2 ? RX_BUFF_SIZE/2 : 0; unsigned sp = spot; // start of new buffer cli(); while(checkedSpot != rxSpot) { rxBuffer[spot++] = rxBuffer[checkedSpot++]; //Error - We are not checking for escape characters in here if( checkedSpot >= RX_BUFF_SIZE ) checkedSpot = 0; } rxSpot = spot; // set insertion to end of copy checkedSpot = sp; // reset checked to beginning of copy sei(); file.sync(); //Push these new file.writes to the SD card } //Now power down until new characters to arrive while(checkedSpot == rxSpot){ digitalWrite(STAT1, LOW); //Turn off stat LED to save power sleep_mode(); //Stop everything and go to sleep. Wake up if serial character received } } delay(1); //Hang out for a ms } //Scan for escape character if(rxBuffer[checkedSpot] == setting_escape_character){ #if DEBUG Serial.print("!"); #endif if(++escape_chars_received == setting_max_escape_character){ //Disable interrupt and we're done! cli(); UCSR0B &= ~(1< (RX_BUFF_SIZE/2) { file.write(rxBuffer + (RX_BUFF_SIZE/2), checkedSpot - (RX_BUFF_SIZE/2)); //Record second half the buffer } file.sync(); file.close(); //Done recording, close out the file digitalWrite(statled1, LOW); //Turn off indicator LED #if DEBUG PgmPrintln("Done!"); #endif PgmPrint("~"); //Indicate a successful record return(1); //Success! } uint8_t gotoDir(char *dir) { SdFile subDirectory; uint8_t tmp_var = 0; //Goto parent directory //@NOTE: This is a fix to make this work. Should be replaced with //proper handling. Limitation: FOLDER_TRACK_DEPTH subfolders if (strncmp_P(dir, PSTR(".."), 2) == 0) { tmp_var = 1; //close file system currentDirectory.close(); // open the root directory if (!currentDirectory.openRoot(&volume)) error("openRoot"); int8_t index = getNextFolderTreeIndex() - 1; if (index >= 0) { for (int8_t iTemp = 0; iTemp < index; iTemp++) { if (!(tmp_var = subDirectory.open(¤tDirectory, folderTree[iTemp], O_READ))) break; currentDirectory = subDirectory; //Point to new directory subDirectory.close(); } memset(folderTree[index], 0, 11); } if (((feedback_mode & EXTENDED_INFO) > 0) && (tmp_var == 0)) { PgmPrint("cannot cd to parent directory: "); Serial.println(dir); } } else { if (!(tmp_var = subDirectory.open(¤tDirectory, dir, O_READ))) { if ((feedback_mode & EXTENDED_INFO) > 0) { PgmPrint("directory not found: "); Serial.println(dir); } } else { currentDirectory = subDirectory; //Point to new directory int8_t index = getNextFolderTreeIndex(); if (index >= 0) strncpy(folderTree[index], dir, 11); } } return tmp_var; } void command_shell(void) { //Serial.begin causes the receive interrupt to turn on //This is bad for command_shell that relies on non-interrupt driven line reads cli(); UCSR0B &= ~(1< 0) Serial.print((char)0x1A); // Ctrl+Z ends the data and marks the start of result if (command_succedded == 0) Serial.print('!'); #endif Serial.print('>'); //read command char* command = buffer; if(read_line(command, sizeof(buffer)) < 1) { #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif continue; } #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 0; #endif //Argument 1: The actual command char* command_arg = get_cmd_arg(0); //execute command if(strcmp_P(command_arg, PSTR("init")) == 0) { if ((feedback_mode & EXTENDED_INFO) > 0) PgmPrintln("Closing down file system"); //close file system currentDirectory.close(); // open the root directory if (!currentDirectory.openRoot(&volume)) error("openRoot"); memset(folderTree, 0, sizeof(folderTree)); if ((feedback_mode & EXTENDED_INFO) > 0) PgmPrintln("File system initialized"); #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif } else if(strcmp_P(command_arg, PSTR("?")) == 0) { //Print available commands print_menu(); #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif } else if(strcmp_P(command_arg, PSTR("help")) == 0) { //Print available commands print_menu(); #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif } else if(strcmp_P(command_arg, PSTR("baud")) == 0) { //Go into baud select menu baud_menu(); #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif } else if(strcmp_P(command_arg, PSTR("set")) == 0) { //Go into system setting menu system_menu(); #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif } #if DEBUG else if(strcmp_P(command_arg, PSTR("create")) == 0) { //Test for creating the maximum number of files that a directory can hold //create_lots_of_files(); } #endif else if(strcmp_P(command_arg, PSTR("ls")) == 0) { if ((feedback_mode & EXTENDED_INFO) > 0) { PgmPrint("Volume is FAT"); Serial.println(volume.fatType(), DEC); } currentDirectory.ls(LS_SIZE, 0, &wildcmp, get_cmd_arg(1)); #ifdef INCLUDE_SIMPLE_EMBEDDED command_succedded = 1; #endif } else if(strncmp_P(command_arg, PSTR("md"), 2) == 0) { //Argument 2: Directory name command_arg = get_cmd_arg(1); if(command_arg == 0) continue; SdFile newDirectory; if (!newDirectory.makeDir(¤tDirectory, command_arg)) { if ((feedback_mode & EXTENDED_INFO) > 0) { PgmPrintln("error creating directory: "); Serial.println(command_arg); } } #ifdef INCLUDE_SIMPLE_EMBEDDED else { command_succedded = 1; } #endif } //NOTE on using "rm