Files
airplane-data-logger/USBDrive_Airplane_Data_Logger/USBDrive_Airplane_Data_Logger.ino
T
2022-07-05 14:11:31 -07:00

381 lines
9.3 KiB
Arduino

/*
Airplane Data Logging for Dynon EFIS-D10A, Dynon EMS-D10, Garmin GNS430W
(c) 2022 Ken Staton
issue: hot insert drive not always starting. don't worry about remove and re-insert.
issue: clock sync.
how long does backup battery last??
use GPS time for RTC sync when drifts more than 20 seconds
measured data rates
G: GPS Rx1 115 bytes/sec message end: '\x003'
F: EFIS Rx2 3300 bytes/sec message end: '\n'
E: EMS Rx3 480 bytes/sec message end: '\n'
*/
#define DEBUG false // USB serial debug printing
// setup will BLOCK until USB serial starts
#define UTCm7 (7*60*60) // your timezone relative to UTC in seconds
// end of message characters
#define GPS_EOM '\x003'
#define EFIS_EOM '\n'
#define EMS_EOM '\n'
#include <USBHost_t36.h>
#include <TimeLib.h>
// Setup USBHost_t36 and as many HUB ports as needed.
USBHost myusb;
// Instances for the number of hubs
USBHub hub1(myusb);
// Instances for the number of USB drives you are using.
USBDrive myDrive1(myusb);
// Instances for accessing the files on each drive
USBFilesystem myFiles1(myusb);
// Timer events
IntervalTimer myTimer;
// vvv GLOBALS vvv
File myFile;
volatile bool tick = false;
bool LED_ON = false;
// https://www.pjrc.com/teensy/td_uart.html
// these buffers are used by the UART interrupt
#define Serial1RxBufferSIZE 1024 // 10 seconds
char Serial1RxBuffer[Serial1RxBufferSIZE]; // global scope or static char. power of 2.
#define Serial2RxBufferSIZE 8192 // 2 seconds
char Serial2RxBuffer[Serial2RxBufferSIZE]; // global scope or static char. power of 2.
#define Serial3RxBufferSIZE 1024 // 2 seconds
char Serial3RxBuffer[Serial3RxBufferSIZE]; // global scope or static char. power of 2.
// ^^^ end GLOBAL ^^^
void TimerISR() { // callback for myTimer
tick = true; // only sets global
}
void setup()
{
int i;
char fname[16];
myTimer.begin(TimerISR, 1000000); // period in microseconds = 1 sec
setSyncProvider(getTeensy3Time);
setSyncInterval(300); // default is 5 min. this call should force a sync
if (DEBUG) {
Serial.begin(115200);
while (!Serial) {
; // wait for Arduino Serial Monitor to connect.
}
}
if (DEBUG) RTCDisplay();
// Serial1 Rx @ Tx (0), Tx @ Tx (1)
Serial1.begin(9600); // MUST match Garmin
Serial1.addMemoryForRead(Serial1RxBuffer, Serial1RxBufferSIZE);
// Serial2 Rx @ Rx1 (16), Tx @ Tx1 (17)
Serial2.begin(115200); // MUST match Dynon EFIS
Serial2.addMemoryForRead(Serial2RxBuffer, Serial2RxBufferSIZE);
// Serial3 Rx @ A1 (15), Tx @ A0 (14)
Serial3.begin(115200); // MUST match Dynon EMS
Serial3.addMemoryForRead(Serial3RxBuffer, Serial3RxBufferSIZE);
SdFile::dateTimeCallback(dateTime);
myusb.begin();
// .begin(USBDrive) is a temporary feature, future USBFilesystem will begin automatically
if (DEBUG) Serial.println("\nInitializing USB drive 1...");
if (!myFiles1.begin(&myDrive1)) {
if (DEBUG) Serial.print("initialization failed with code: ");
if (DEBUG) myFiles1.printError(Serial);
return; // setup() is done!
}
if (DEBUG) Serial.printf(F(" connected: %d\n"), myDrive1.msDriveInfo.connected);
if (DEBUG) Serial.printf(F(" initialized: %d\n"), myDrive1.msDriveInfo.initialized);
if (DEBUG) Serial.printf(F(" fs started: %d\n"), myDrive1.filesystemsStarted());
if (DEBUG) Serial.printf("Find next file number...\n");
i=next_file_number(); /* global access to myFiles1 */
sprintf(fname,"Log%04d.txt",i);
if (DEBUG) Serial.printf("Testing for file %s\n",fname);
myFile = myFiles1.open(fname, FILE_WRITE);
// see https://github.com/wwatson4506/UsbMscFat/blob/UsbMscFat-FS_DATES/examples/ReadWriteUSB/ReadWriteUSB.ino
if (myFile) {
if (DEBUG) Serial.printf("Writing to %s...\n",fname);
myFile.println("Log Started "); // first line
} else {
// if the file didn't open, print an error:
if (DEBUG) Serial.printf("error opening %s \n",fname);
}
if (DEBUG) RTCDisplay();
if (DEBUG) Serial.printf("t.s = %f\n", getdatetime());
if (DEBUG) Serial.println("init done...");
} // end of setup()
int next_file_number() { /* global access to myFiles1 */
// returns the first unused file number
char fname[16];
bool fileexists = true; // assume true
int i=0; // always start at 0
do {
sprintf(fname,"Log%04d.txt",i);
//Serial.printf("%s",fname);
if (myFiles1.exists(fname) == 0) {
fileexists=false;
} else {
i++;
}
} while (fileexists == true);
return(i);
}
void RTCDisplay() {
// display the time
Serial.print(year());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.println();
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
void toggleLED() {
if (LED_ON) {
digitalWrite(LED_BUILTIN, LOW);
LED_ON = false;
} else { /* LED_OFF */
digitalWrite(LED_BUILTIN, HIGH);
LED_ON = true;
}
}
void halt(int hz) {
int t_ms;
float period;
period = 1.0/hz;
t_ms = period * 1000/2;
//if (DEBUG) Serial.printf("blink period %d\n",t_ms);
// LED_BUILTIN interferes with I2C !!
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
while (true) {
toggleLED();
delay(t_ms);
}
}
// read about time https://www.pjrc.com/teensy/td_libs_Time.html
// /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/Time/TimeLib.h
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
/*
* User provided date time callback function.
* See SdFile::dateTimeCallback() for usage.
*/
void dateTime(uint16_t* date, uint16_t* time) {
// User gets date and time from GPS or real-time
// clock in real callback function
time_t now();
// return date using FAT_DATE macro to format fields via parameter pointer
*date = FAT_DATE(year(), month(), day());
// return time using FAT_TIME macro to format fields via parameter pointer
*time = FAT_TIME(hour(), minute(), second());
}
time_t getdatetime(){
// gets time from GPS
// returns time_t with nanoseconds as a float
time_t t;
TimeElements tm;
t = 0;
return(t);
}
// loop is called repeatedly
// static vars to persist between calls
void loop(void) {
int i;
static int t=0;
char fname[16];
// these buffers are used for message processing
static char GPSRx[Serial1RxBufferSIZE];
static char EFISRx[Serial2RxBufferSIZE];
static char EMSRx[Serial3RxBufferSIZE];
static int msg1 = 0;
static int msg2 = 0;
static int msg3 = 0;
static int i1 = 0;
static int i2 = 0;
static int i3 = 0;
static bool MSG_OVFL = false;
// process until end of message or overflow
if (Serial1.available()) {
GPSRx[i1]=Serial1.read();
//Serial.print(GPSRx[i1]);
if (GPSRx[i1] == GPS_EOM) msg1 = i1;
i1++;
if (i1 == Serial1RxBufferSIZE - 1) {
MSG_OVFL = true;
msg1 = i1;
} else GPSRx[i1]=NULL;
}
// process until end of message or overflow
if (Serial2.available()) {
EFISRx[i2]=Serial2.read();
//Serial.print(EFISRx[i2]);
if (EFISRx[i2] == EFIS_EOM) msg2 = i2;
i2++;
if (i2 == Serial2RxBufferSIZE - 1) {
MSG_OVFL = true;
msg2 = i2;
} else EFISRx[i2]=NULL;
}
// process until end of message or overflow
if (Serial3.available()) {
EMSRx[i3]=Serial3.read();
//Serial.print(EMSRx[i3]);
if (EMSRx[i3] == EMS_EOM) msg3 = i3;
i3++;
if (i3 == Serial3RxBufferSIZE - 1) {
MSG_OVFL = true;
msg3 = i3;
} else EMSRx[i3]=NULL;
}
if (myFile) {
if (msg1>0) {
myFile.print("G:");
myFile.write(GPSRx,msg1);
msg1=0;
i1=0;
if (MSG_OVFL) {
myFile.println("G: OVERFLOW!");
MSG_OVFL = false;
}
}
if (msg2>0) {
myFile.print("F:");
myFile.write(EFISRx,msg2);
msg2=0;
i2=0;
if (MSG_OVFL) {
myFile.println("F: OVERFLOW!");
MSG_OVFL = false;
}
}
if (msg3>0) {
myFile.print("E:");
myFile.write(EMSRx,msg3);
msg3=0;
i3=0;
if (MSG_OVFL) {
myFile.println("E: OVERFLOW!");
MSG_OVFL = false;
}
}
}
if (tick) {
tick = false;
toggleLED();
if (myFile) {
if (t>4) {
myFile.flush(); // flush every 5 seconds
t=0;
}
t=t+1;
}
if (!myFile) { /* open a new file */
myDrive1.begin();
myDrive1.startFilesystems();
if (DEBUG) Serial.print("try opening new file...\n");
if (DEBUG) Serial.println("\nInitializing USB drive 1...");
if (DEBUG) Serial.printf(F(" connected: %d\n"), myDrive1.msDriveInfo.connected);
if (DEBUG) Serial.printf(F(" initialized: %d\n"), myDrive1.msDriveInfo.initialized);
if (DEBUG) Serial.printf(F(" fs start: %d\n"), myDrive1.filesystemsStarted());
if (!myFiles1.begin(&myDrive1)) {
if (DEBUG) Serial.print("initialization failed with code: ");
if (DEBUG) myFiles1.printError(Serial);
} else {
i=next_file_number(); /* global access to myFiles1 */
sprintf(fname,"Log%04d.txt",i);
myFile = myFiles1.open(fname, FILE_WRITE);
myFile.println("Log Started "); // first line
}
} /* open new file */
} /* tick */
}