#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <TimeLib.h>
int hour_old;
int current_time[3];
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
#include "SD.h"
#include <MTP_Teensy.h>
SDClass sd;
#define CS_SD BUILTIN_SDCARD
#define SPI_SPEED SD_SCK_MHZ(16) // adjust to sd card
File myFile, dataFile;
int iRecord = 0;
int line = 0;
#define BUFFER_SIZE_INDEX 128
uint8_t write_buffer[BUFFER_SIZE_INDEX];
#define buffer_mult 16
uint8_t buffer_temp[buffer_mult*BUFFER_SIZE_INDEX];
int bytesRead;
int record_count = 0;
bool write_data = false;
uint32_t diskSize;
#include <LittleFS.h>
LittleFS_Program lfsProg; // Used to create FS on the Flash memory of the chip
FS *myfs = &lfsProg; // current default FS...
static const uint32_t file_system_size = 1024 * 1024 * 1;
void setup() {
while (!Serial && millis() < 5000) {}
if (CrashReport) {
Serial.print(CrashReport);
}
delay(2000);
MTP.begin();
// Lets add the Program memory version:
// checks that the LittFS program has started with the disk size specified
if (lfsProg.begin(file_system_size)) {
MTP.addFilesystem(lfsProg, "Program");
} else {
Serial.println("Error starting Program Flash storage");
}
// Lets add SD Card
if (sd.begin(CS_SD)) {
MTP.addFilesystem(sd, "SD");
}
Serial.println(F("BME680/Prog/SD Logger test"));
// set the Time library to use Teensy 3.0's RTC to keep time
setSyncProvider(getTeensy3Time);
hour_old = hour();
delay(100);
if (timeStatus()!= timeSet) {
Serial.println("Unable to sync with the RTC");
} else {
Serial.println("RTC has set the system time");
}
if (!bme.begin()) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
while (1);
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
if ( Serial.available() ) {
uint8_t command = Serial.read();
int ch = Serial.read();
while (ch == ' ') ch = Serial.read();
switch (command) {
case 't':
{
if (Serial.available()) {
time_t t = processSyncMessage();
if (t != 0) {
Teensy3Clock.set(t); // set the RTC
setTime(t);
}
}
}
break;
case 's':
{
Serial.println("\nLogging Data!!!");
write_data = true; // sets flag to continue to write data until new command is received
// opens a file or creates a file if not present, FILE_WRITE will append data to
// to the file created.
dataFile = myfs->open("datalog.txt", FILE_WRITE_BEGIN);
digitalClockDisplay();
hour_old = minute();
logData();
}
break;
case 'x': stopLogging(); break;
case 'd': dumpLog(); break;
case 'c': copyProg2SD(); break;
case '\r':
case '\n':
case 'h': menu(); break;
}
while (Serial.read() != -1) ; // remove rest of characters.
} else {
MTP.loop();
}
if (write_data) {
logData();
//delay(500);
}
}
/* **************************************************
* BME Functions
****************************************************/
void logData()
{
String dataString = "";
//Serial.printf("Minute: %d, Old: %d\n", minute(), hour_old);
if((minute()-hour_old) == 1 || minute() == 0) {
hour_old = minute();
digitalClockDisplay();
if (! bme.performReading()) {
Serial.println("Failed to perform reading :(");
//myfs.printf("%f, %f, %f, %f, %f\n", 0, 0, 0, 0 );
dataString = String(hour()) + ", " + String(minute()) + ", " + String(second()) +", " ;
dataString += String(day()) + ", " + String(month()) + ", " + String(year());
dataString += ", 0, 0, 0, 0, 0";
dataFile.println(dataString);
record_count += 1;
Serial.printf("Record Count: %d\n", record_count);
return;
}
//myfs.printf("%f, %f, %f, %f, %f\n", bme.temperature,bme.pressure / 100.0, bme.humidity,bme.gas_resistance / 1000.0, bme.readAltitude(SEALEVELPRESSURE_HPA));
dataString = String(hour()) + ", " + String(minute()) + ", " + String(second()) +", " ;
dataString += String(day()) + ", " + String(month()) + ", " + String(year());
dataString += ", ";
dataString += String(bme.temperature) + ", ";
dataString += String(bme.pressure / 100.0) + ", ";
dataString += String(bme.humidity) + ", ";
dataString += String(bme.gas_resistance / 1000.0) + ", ";
dataString += String(bme.readAltitude(SEALEVELPRESSURE_HPA));
dataFile.println(dataString);
record_count += 1;
Serial.printf("Record Count: %d\n", record_count);
}
//if(record_count == 10) stopLogging();
checkLogging();
}
void stopLogging()
{
Serial.println("\nStopped Logging Data!!!");
write_data = false;
// Closes the data file.
dataFile.close();
Serial.printf("Records written = %d\n", record_count);
//MTP.send_DeviceResetEvent();
}
/* **************************************************
* RTC Functions
****************************************************/
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
/* code to process time sync messages from the serial port */
#define TIME_HEADER "T" // Header tag for serial time sync message
unsigned long processSyncMessage() {
unsigned long pctime = 0L;
const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013
if(Serial.find(TIME_HEADER)) {
pctime = Serial.parseInt();
return pctime;
if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
pctime = 0L; // return 0 to indicate that the time is not valid
}
}
return pctime;
}
void digitalClockDisplay() {
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
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 menu()
{
Serial.println();
Serial.println("Menu Options:");
Serial.println("\ts - Start Logging data (Restarting logger will append records to existing log)");
Serial.println("\tx - Stop Logging data");
Serial.println("\td - Dump Log");
Serial.println("\tc - Copy datafile to SD Card");
Serial.println("\th - Menu");
Serial.println();
}
uint8_t copyProg2SD()
{
// open the file on SD Card.
Serial.println("Copy File on Flash to SD Card");
dataFile = myfs->open("datalog.txt", FILE_READ);
//open file on flash
myFile = sd.open("LITF.txt", FILE_WRITE_BEGIN);
if(!dataFile || !myFile) return 0;
//dataFile.truncate();
if (dataFile) {
Serial.println("Files Writing");
while (dataFile.available()) {
memset(write_buffer, 0, sizeof(write_buffer));
memset(buffer_temp, 0, sizeof(buffer_temp));
uint16_t byteCount = 0;
for(uint8_t i=0; i < buffer_mult; i++) {
bytesRead = dataFile.read(write_buffer, line? BUFFER_SIZE_INDEX : BUFFER_SIZE_INDEX-12);
if(bytesRead > 0) {
for(int j = 0; j < (line? BUFFER_SIZE_INDEX : BUFFER_SIZE_INDEX-12); j++) {
buffer_temp[byteCount+j] = write_buffer[j];
}
}
byteCount += (line? BUFFER_SIZE_INDEX : BUFFER_SIZE_INDEX-12);
line += 1;
}
myFile.write((void *)buffer_temp, byteCount);
iRecord += 1;
Serial.printf("Record Number: %d, BytesWritten: %d\n", iRecord, byteCount);
if(bytesRead < 0) break;
} // if the file isn't open, pop up an error:
}
myFile.close();
dataFile.close();
Serial.println("Files Closed");
//MTP.send_DeviceResetEvent();
return 1;
}
void dumpLog()
{
Serial.println("\nDumping Log!!!");
// open the file.
dataFile = myfs->open("datalog.txt");
// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}
bool itsMidnight = false;
#define DEBUG_LOOP_MIDNIGHT_TIME
void checkLogging()
{
if (second() == 0) // Seconds = zero.
{
if (minute() == 0) // Minutes = zero.
{
if (hour() == 17) // Hours = zero, It is Midnight 00:00:00.
{
itsMidnight = true; // The clock has just struck midnight.
#if defined(DEBUG_LOOP_MIDNIGHT_TIME)
Serial.println(F("\nMain Loop - Now stopping the logging of data and moving the Environmental data file to SD Card..."));
#endif
//stopLoggingDataToRamDisk(); // This stops the logging and closes the existing data file.
stopLogging();
//if(!copyDataFileFromRAMDiskToSDCard(FileNameChars, SDDataDirectory, FileNameChars)) // This moves the data file to the SD Card, the source file name and destination file name are the same.
if(!copyProg2SD())
{
#if defined(DEBUG_LOOP_MIDNIGHT_TIME )
Serial.println(F("Error - Copying data file to SD Card from RAMDISK...\n"));
#endif
}
else
{
#if defined(DEBUG_LOOP_MIDNIGHT_TIME )
Serial.println(F("Copying data file to SD Card from RAMDISK was successful...\n"));
#endif
}
#if defined(DEBUG_LOOP_MIDNIGHT_TIME )
Serial.println(F("Now creating a new Environmental data file in QSPI-RAM...\n"));
#endif
if(!createNewDataFileAndStartLogging()) // This creates the new data file and begins logging again.
{
#if defined(DEBUG_LOOP_MIDNIGHT_TIME )
Serial.println(F("Error - Creating new data file to log data...\n"));
#endif
}
else
{
MTP.send_DeviceResetEvent(); // Make sure the MTP system updates the new file name and file copied to the SD Card.
#if defined(DEBUG_LOOP_MIDNIGHT_TIME )
Serial.println(F("Creating new data file was successful...\n"));
#endif
}
//insideDailyHighTemp = sensorState.Temperature; // Set inside Daily High Temp to ambient at midnight.
//insideDailyLowTemp = sensorState.Temperature; // Set inside Daily Low Temp to ambient at midnight.
//outsideDailyHighTemp = WeatherDataStruct.Temperature; // Set outside Daily High Temp to ambient at midnight.
//outsideDailyLowTemp = WeatherDataStruct.Temperature; // Set outside Daily Low Temp to ambient at midnight.
}
}
}
}
uint8_t createNewDataFileAndStartLogging()
{
myfs->remove("datalog.txt");
return 1;
}