Skip to content

Commit a822338

Browse files
committed
Now compiles under Arduino v1.6.x. A large number of changes. See CHANGELOG
Significant changes to reduce RAM footprint. Updated to most recent SdFatlib-beta.
1 parent d063f6a commit a822338

File tree

116 files changed

+22502
-10170
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+22502
-10170
lines changed

CHANGELOG.md

Lines changed: 526 additions & 0 deletions
Large diffs are not rendered by default.

OpenLog-Attached-To-FTDI-Basic.jpg

148 KB
Loading

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ License Information
1111

1212
The hardware design and firmware are released under [Creative Commons Share-alike 3.0](http://creativecommons.org/licenses/by-sa/3.0/).
1313
The FAT16/FAT32 firmware was originally designed by Roland Riegel and is released under [GPL v2](http://www.gnu.org/licenses/gpl-2.0.html).
14+
15+
Feel free to use, distribute, and sell varients of OpenLog. All we ask is that you include attribution of 'Based on OpenLog by SparkFun'.
16+
1417
OpenLog v2.0 and above uses sdfatlib written by Bill Greiman and is released under [GPL v3](http://www.gnu.org/licenses/gpl-3.0.html).
18+
1519
The OpenLog firmware was created by SparkFun Electronics, and is open source so please feel free to do anything you want with it;
1620
you buy me a beer if you use this and we meet someday ([Beerware license](http://en.wikipedia.org/wiki/Beerware)).
1721

@@ -24,10 +28,11 @@ Repository Contents
2428
* **/Fritzing** - Fritzing image showing the connections between the OpenLog and an FTDI Basic
2529
* **/Hardware** - Hardware design files for the OpenLog PCB. These files were designed in Eagle CAD.
2630

27-
2831
Version History
2932
---------------
3033

34+
For a full view of changes please see the [changelog].
35+
3136
OpenLog v1 is stable but only supports FAT16 and up to 2GB.
3237

3338
OpenLog v2 is a bit buggy but supports FAT32 and SD cards up to 16GB.
@@ -55,4 +60,5 @@ OpenLog v3 is stable, supports FAT32 cards up to 64GB and supports higher record
5560
* **v3.0** Migration to Arduino v1.0 and better recording speed at 115200bps and 57600bps.
5661
* **v3.1** Better handling of recording during power loss.
5762
* **v3.2** Freed up RAM for larger RX ring buffer. Added support for wildcards and ability to ignore emergency override.
58-
* **v3.3** Added ability to ignore escape character checking and corrected incremental log naming.
63+
* **v3.3** Added ability to ignore escape character checking and corrected incremental log naming.
64+
* **v4.0** Re-worked to be compatible with Arduino v1.6.x. Freed RAM to increase RX buffer size.

firmware/OpenLog_v3/OpenLog_v3.ino renamed to firmware/OpenLog/OpenLog.ino

Lines changed: 426 additions & 714 deletions
Large diffs are not rendered by default.

firmware/OpenLog_v3_Light/OpenLog_v3_Light.ino renamed to firmware/OpenLog_Light/OpenLog_Light.ino

Lines changed: 65 additions & 188 deletions
Large diffs are not rendered by default.
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
12-3-09
3+
Nathan Seidle
4+
SparkFun Electronics 2012
5+
6+
OpenLog hardware and firmware are released under the Creative Commons Share Alike v3.0 license.
7+
http://creativecommons.org/licenses/by-sa/3.0/
8+
Feel free to use, distribute, and sell varients of OpenLog. All we ask is that you include attribution of 'Based on OpenLog by SparkFun'.
9+
10+
OpenLog is based on the work of Bill Greiman and sdfatlib: https://github.com/greiman/SdFat-beta
11+
12+
This version has the command line interface and config file stripped out in order to simplify the overall
13+
program and increase the receive buffer (RAM).
14+
15+
The only option is the interface baud rate and it has to be set in code, compiled, and loaded onto OpenLog. To
16+
see how to do this please refer to https://github.com/sparkfun/OpenLog/wiki/Flashing-Firmware
17+
18+
This version
19+
20+
*/
21+
22+
#define __PROG_TYPES_COMPAT__ //Needed to get SerialPort.h to work in 1.6x
23+
24+
#include <SPI.h>
25+
#include <SdFat.h> //We do not use the built-in SD.h file because it calls Serial.print
26+
#include <EEPROM.h>
27+
#include <FreeStack.h> //Allows us to print the available stack/RAM size
28+
29+
#include <avr/sleep.h> //Needed for sleep_mode
30+
#include <avr/power.h> //Needed for powering down perihperals such as the ADC/TWI and Timers
31+
32+
#include <SerialPort.h>
33+
// port 0, 256 byte RX buffer, 0 byte TX buffer
34+
SerialPort<0, 1024, 0> NewSerial;
35+
36+
37+
//Debug turns on (1) or off (0) a bunch of verbose debug statements. Normally use (0)
38+
//#define DEBUG 1
39+
#define DEBUG 0
40+
41+
#define SD_CHIP_SELECT 10 //On OpenLog this is pin 10
42+
43+
//Internal EEPROM locations for the user settings
44+
#define LOCATION_FILE_NUMBER_LSB 0x03
45+
#define LOCATION_FILE_NUMBER_MSB 0x04
46+
47+
//STAT1 is a general LED and indicates serial traffic
48+
const byte statled1 = 5; //This is the normal status LED
49+
const byte statled2 = 13; //This is the SPI LED, indicating SD traffic
50+
51+
//Blinking LED error codes
52+
#define ERROR_SD_INIT 3
53+
#define ERROR_NEW_BAUD 5
54+
#define ERROR_CARD_INIT 6
55+
#define ERROR_VOLUME_INIT 7
56+
#define ERROR_ROOT_INIT 8
57+
#define ERROR_FILE_OPEN 9
58+
59+
SdFat sd;
60+
Sd2Card card;
61+
62+
long setting_uart_speed = 115200;
63+
64+
//Handle errors by printing the error type and blinking LEDs in certain way
65+
//The function will never exit - it loops forever inside blink_error
66+
void systemError(byte error_type)
67+
{
68+
NewSerial.print(F("Error "));
69+
switch (error_type)
70+
{
71+
case ERROR_CARD_INIT:
72+
NewSerial.print(F("card.init"));
73+
blink_error(ERROR_SD_INIT);
74+
break;
75+
case ERROR_VOLUME_INIT:
76+
NewSerial.print(F("volume.init"));
77+
blink_error(ERROR_SD_INIT);
78+
break;
79+
case ERROR_ROOT_INIT:
80+
NewSerial.print(F("root.init"));
81+
blink_error(ERROR_SD_INIT);
82+
break;
83+
case ERROR_FILE_OPEN:
84+
NewSerial.print(F("file.open"));
85+
blink_error(ERROR_SD_INIT);
86+
break;
87+
}
88+
}
89+
90+
void setup(void)
91+
{
92+
pinMode(statled1, OUTPUT);
93+
94+
//Power down various bits of hardware to lower power usage
95+
set_sleep_mode(SLEEP_MODE_IDLE);
96+
sleep_enable();
97+
98+
//Shut off TWI, Timer2, Timer1, ADC
99+
ADCSRA &= ~(1 << ADEN); //Disable ADC
100+
ACSR = (1 << ACD); //Disable the analog comparator
101+
DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins
102+
DIDR1 = (1 << AIN1D) | (1 << AIN0D); //Disable digital input buffer on AIN1/0
103+
104+
power_twi_disable();
105+
power_timer1_disable();
106+
power_timer2_disable();
107+
power_adc_disable();
108+
109+
//Setup UART
110+
NewSerial.begin(setting_uart_speed);
111+
NewSerial.print(F("1"));
112+
113+
//Setup SD & FAT
114+
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) systemError(ERROR_CARD_INIT);
115+
116+
NewSerial.print(F("2"));
117+
118+
#if DEBUG
119+
NewSerial.print(F("FreeStack: "));
120+
NewSerial.println(FreeStack());
121+
#endif
122+
123+
}
124+
125+
void loop(void)
126+
{
127+
append_file(newlog()); //Append the file name that newlog() returns
128+
}
129+
130+
//Log to a new file everytime the system boots
131+
//Checks the spots in EEPROM for the next available LOG# file name
132+
//Updates EEPROM and then appends to the new log file.
133+
//Limited to 65535 files but this should not always be the case.
134+
char* newlog(void)
135+
{
136+
byte msb, lsb;
137+
uint16_t new_file_number;
138+
139+
SdFile newFile; //This will contain the file for SD writing
140+
141+
//Combine two 8-bit EEPROM spots into one 16-bit number
142+
lsb = EEPROM.read(LOCATION_FILE_NUMBER_LSB);
143+
msb = EEPROM.read(LOCATION_FILE_NUMBER_MSB);
144+
145+
new_file_number = msb;
146+
new_file_number = new_file_number << 8;
147+
new_file_number |= lsb;
148+
149+
//If both EEPROM spots are 255 (0xFF), that means they are un-initialized (first time OpenLog has been turned on)
150+
//Let's init them both to 0
151+
if ((lsb == 255) && (msb == 255))
152+
{
153+
new_file_number = 0; //By default, unit will start at file number zero
154+
EEPROM.write(LOCATION_FILE_NUMBER_LSB, 0x00);
155+
EEPROM.write(LOCATION_FILE_NUMBER_MSB, 0x00);
156+
}
157+
158+
//The above code looks like it will forever loop if we ever create 65535 logs
159+
//Let's quit if we ever get to 65534
160+
//65534 logs is quite possible if you have a system with lots of power on/off cycles
161+
if (new_file_number == 65534)
162+
{
163+
//Gracefully drop out to command prompt with some error
164+
NewSerial.print(F("!Too many logs:1!"));
165+
return (0); //Bail!
166+
}
167+
168+
//If we made it this far, everything looks good - let's start testing to see if our file number is the next available
169+
170+
//Search for next available log spot
171+
static char new_file_name[13];
172+
while(1)
173+
{
174+
sprintf_P(new_file_name, PSTR("LOG%05d.TXT"), new_file_number); //Splice the new file number into this file name
175+
176+
//If we are able to create this file, then it didn't exist, we're good, break
177+
if (newFile.open(new_file_name, O_CREAT | O_EXCL | O_WRITE) == true) break;
178+
179+
//If file exists, see if empty. If so, use it.
180+
if (newFile.open(new_file_name, O_READ))
181+
{
182+
if (newFile.fileSize() == 0)
183+
{
184+
newFile.close(); // Close this existing file we just opened.
185+
return (new_file_name); // Use existing empty file.
186+
}
187+
newFile.close(); // Close this existing file we just opened.
188+
}
189+
190+
//Try the next number
191+
new_file_number++;
192+
if (new_file_number > 65533) //There is a max of 65534 logs
193+
{
194+
NewSerial.print(F("!Too many logs:2!"));
195+
return (0); //Bail!
196+
}
197+
}
198+
199+
new_file_number++; //Increment so the next power up uses the next file #
200+
201+
//Record new_file number to EEPROM
202+
lsb = (byte)(new_file_number & 0x00FF);
203+
msb = (byte)((new_file_number & 0xFF00) >> 8);
204+
205+
EEPROM.write(LOCATION_FILE_NUMBER_LSB, lsb); // LSB
206+
207+
if (EEPROM.read(LOCATION_FILE_NUMBER_MSB) != msb)
208+
EEPROM.write(LOCATION_FILE_NUMBER_MSB, msb); // MSB
209+
210+
#if DEBUG
211+
NewSerial.print(F("\nCreated new file: "));
212+
NewSerial.println(new_file_name);
213+
#endif
214+
215+
return (new_file_name);
216+
}
217+
218+
//This is the most important function of the device. These loops have been tweaked as much as possible.
219+
//Modifying this loop may negatively affect how well the device can record at high baud rates.
220+
//Appends a stream of serial data to a given file
221+
//Assumes the currentDirectory variable has been set before entering the routine
222+
//Does not exit until Ctrl+z (ASCII 26) is received
223+
//Returns 0 on error
224+
//Returns 1 on success
225+
byte append_file(char* file_name)
226+
{
227+
SdFile workingFile;
228+
229+
// O_CREAT - create the file if it does not exist
230+
// O_APPEND - seek to the end of the file prior to each write
231+
// O_WRITE - open for write
232+
if (!workingFile.open(file_name, O_CREAT | O_APPEND | O_WRITE)) systemError(ERROR_FILE_OPEN);
233+
234+
if (workingFile.fileSize() == 0) {
235+
//This is a trick to make sure first cluster is allocated - found in Bill's example/beta code
236+
workingFile.rewind();
237+
workingFile.sync();
238+
}
239+
240+
const int LOCAL_BUFF_SIZE = 128; //This is the 2nd buffer. It pulls from the larger Serial buffer as quickly as possible.
241+
242+
byte buff[LOCAL_BUFF_SIZE];
243+
244+
const unsigned int MAX_IDLE_TIME_MSEC = 500; //The number of milliseconds of inactivity before unit goes to sleep
245+
246+
#if DEBUG
247+
NewSerial.print(F("FreeStack: "));
248+
NewSerial.println(FreeStack());
249+
#endif
250+
251+
NewSerial.print(F("<")); //give a different prompt to indicate no echoing
252+
digitalWrite(statled1, HIGH); //Turn on indicator LED
253+
254+
unsigned long lastSyncTime = millis(); //Keeps track of the last time the file was synced
255+
256+
//Start recording incoming characters
257+
while (1)
258+
{
259+
byte charsToRecord = NewSerial.read(buff, sizeof(buff));
260+
if (charsToRecord > 0)
261+
{
262+
toggleLED(statled1); //Toggle the STAT1 LED each time we record the buffer
263+
264+
workingFile.write(buff, charsToRecord);
265+
}
266+
267+
//No characters recevied?
268+
else if ( (unsigned long)(millis() - lastSyncTime) > MAX_IDLE_TIME_MSEC) //If we haven't received any characters in 2s, goto sleep
269+
{
270+
workingFile.sync(); //Sync the card before we go to sleep
271+
272+
digitalWrite(statled1, LOW); //Turn off stat LED to save power
273+
274+
power_timer0_disable(); //Shut down peripherals we don't need
275+
power_spi_disable();
276+
sleep_mode(); //Stop everything and go to sleep. Wake up if serial character received
277+
278+
power_spi_enable(); //After wake up, power up peripherals
279+
power_timer0_enable();
280+
281+
lastSyncTime = millis(); //Reset the last sync time to now
282+
}
283+
}
284+
285+
return (1); //We should never get here!
286+
}
287+
288+
//The following are system functions needed for basic operation
289+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
290+
291+
//Blinks the status LEDs to indicate a type of error
292+
void blink_error(byte ERROR_TYPE) {
293+
while (1) {
294+
for (int x = 0 ; x < ERROR_TYPE ; x++) {
295+
digitalWrite(statled1, HIGH);
296+
delay(200);
297+
digitalWrite(statled1, LOW);
298+
delay(200);
299+
}
300+
301+
delay(2000);
302+
}
303+
}
304+
305+
//Given a pin, it will toggle it from high to low or vice versa
306+
void toggleLED(byte pinNumber)
307+
{
308+
if (digitalRead(pinNumber)) digitalWrite(pinNumber, LOW);
309+
else digitalWrite(pinNumber, HIGH);
310+
}
311+
312+
//End core system functions
313+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
314+
315+
//A rudimentary way to convert a string to a long 32 bit integer
316+
//Used by the read command, in command shell and baud from the system menu
317+
uint32_t strtolong(const char* str)
318+
{
319+
uint32_t l = 0;
320+
while (*str >= '0' && *str <= '9')
321+
l = l * 10 + (*str++ - '0');
322+
323+
return l;
324+
}

0 commit comments

Comments
 (0)