/*
T4.1 Take readings from UART (from ESP32C3) in text and save to SD card and show on screen.
Modified to detect SD Card present, or NOT.
SoftwareId: S.0004.0004.002
SoftwareId: S.0004.0004.003 Added MTP support
*/
#define softwareId "S.0004.0004.003 - Added MTP support"
#include <SD.h>
#include <timelib.h>
#include <MTP_Teensy.h>
#define numTargets 4
#define CS_SD BUILTIN_SDCARD // Works on T_3.6 and T_4.1
#define ledPin 13
const uint32_t identifier = 57767959;
union identifierUnion {
uint32_t Identifier;
char identTxt[sizeof(uint32_t)];
};
identifierUnion identMatch;
struct msgType {
uint32_t ident;
uint8_t id;
uint16_t temp;
uint16_t humidity;
};
struct uniMsgType {
union {
msgType d;
char txt[sizeof(msgType)];
};
};
uniMsgType recvMsg;
const uint8_t maxArr = numTargets;
typedef struct msgArrType {
msgType data[maxArr];
bool gotData[maxArr];
uint8_t hour;
uint8_t min;
} msgArrType;
msgArrType recvMsgArr;
File dataFile;
String GenerateDateStr(char c) {
String s = "";
int n = day();
if (n < 10) s.concat( "0");
s.concat(n);
s.concat('/');
n = month();
if (n < 10) s.concat("0");
s.concat(n);
s.concat('/');
n = year();
if (n < 10) s.concat("0");
s.concat(n);
if (c != 0x0) s.concat(c);
return s;
}
String GenerateTimeStr(bool andSeconds, char c ) {
String s = "";
int n = hour();
if (n < 10) s.concat("0");
s.concat(n);
s.concat(':');
n = minute();
if (n < 10) s.concat("0");
s.concat(n);
if (andSeconds) {
s.concat(':');
n = second();
if (n < 10) s.concat("0");
s.concat(n);
}
if (c != 0x0) s.concat(c);
return s;
}
time_t getTeensy3Time(){
return Teensy3Clock.get();
}
void send(const msgType* msg)
{
Serial1.write((const char*)msg, sizeof(msgType)); // 2 bytes.
}
bool receive(uniMsgType* msg)
{
return (Serial1.readBytes((char*)msg, sizeof(uniMsgType)) == sizeof(uniMsgType));
}
//String t = "";
bool sdSetup = true;
void setup()
{
identMatch.Identifier = identifier;
setSyncProvider(getTeensy3Time);
Serial.begin(115200);
while (!Serial && millis() < 5000);
Serial1.begin(115200);
Serial.print("SoftwareId: "); Serial.println(softwareId);
Serial.print("Initializing SD card...");
pinMode(ledPin, OUTPUT);
// see if the card is present and can be initialized:
if (SD.begin(CS_SD)) {
MTP.addFilesystem(SD, "SD Card");
Serial.println("card initialized.");
}
else {
Serial.println("Card failed, or not present");
sdSetup = false;
// No SD card, so don't do anything more - stay stuck here
}
if (timeStatus() != timeSet) {
Serial.println("Unable to sync with the RTC");
} else Serial.println("RTC has set the system time");
// mandatory to begin the MTP session.
MTP.begin();
Serial.println(GenerateDateStr(0x0));
}
void PrintDec(uint8_t n) {
if (n < 10) Serial.print("0");
Serial.print(n);
};
void PrintN(uint16_t n) {
uint16_t q;
Serial.print(n / 100);
Serial.print(".");
q = n % 100;
PrintDec(q);
}
void PrintNN(uint16_t n) {
uint16_t q;
dataFile.print(n / 100);
dataFile.print(".");
q = n % 100;
if (q < 10) dataFile.print("0");
dataFile.print(q);
}
void PrintData() {
String where;
uint8_t n;
uint8_t p;
n = 0;
PrintDec(recvMsgArr.hour);
Serial.print(":");
PrintDec(recvMsgArr.min);
Serial.print(" ");
while (n < maxArr) {
p = recvMsgArr.data[n].id - 1;
if (recvMsgArr.gotData[n]) {
switch (p) {
case 0:
where = "GBrm:";
break;
case 1:
where = "Lnge:";
break;
case 2:
where = "BBrm:";
break;
case 3:
where = "CBrm:";
break;
}
Serial.print(where);
PrintN(recvMsgArr.data[n].temp);
recvMsgArr.data[n].temp = 0;
Serial.print(" ");
PrintN(recvMsgArr.data[n].humidity); recvMsgArr.data[n].humidity = 0;
Serial.print(" ");
}
else Serial.print("----------------- ");
recvMsgArr.gotData[n] = false;
n = n + 1;
}
Serial.println();
}
String tim;
String date;
uint8_t lastMin = 99;
uint8_t currMin = 98;
uint8_t p;
// Add the main program code into the continuous loop() function
void loop()
{
MTP.loop(); //This is mandatory to be placed in the loop code.
while (Serial1.available() >= (int)sizeof(msgType)) {
digitalWrite(ledPin, HIGH);
if (receive(&recvMsg)) {
if (recvMsg.d.ident == identifier) {
currMin = minute();
if (currMin != lastMin) {
if (lastMin != 99) {
PrintData();
}
lastMin = currMin;
}
p = recvMsg.d.id - 1; // Serial.print(p); Serial.println(" ");
recvMsgArr.data[p] = recvMsg.d;
recvMsgArr.gotData[p] = true;
recvMsgArr.hour = hour();
recvMsgArr.min = minute();
//Serial.print("sdSetup:"); Serial.print(sdSetup); Serial.print(" SD.mediaPresent:"); Serial.print(SD.mediaPresent());
if (sdSetup && SD.mediaPresent()) {
dataFile = SD.open("datalog.csv", FILE_WRITE);
//Serial.print(" dataFile:"); Serial.println(dataFile);
// if the file is available, write to it:
if (dataFile) {
for (int q = 0; q < (recvMsg.d.id-1) * 5; q++) {
dataFile.print(',');
}
date = GenerateDateStr(' ');
tim = GenerateTimeStr(true, ',');
dataFile.print(date);
dataFile.print(tim);
dataFile.print(recvMsg.d.id); dataFile.print(",");
PrintNN(recvMsg.d.temp); dataFile.print(",");
PrintNN(recvMsg.d.humidity); dataFile.println();
dataFile.close();
}
else Serial.println("error opening datalog.csv");
}
else Serial.println("No SD Card (Media) present");
}
else {
Serial.println("Bad data, getting back into synch");
for (uint n = 0; n < sizeof(msgType); n++) {
Serial.print(recvMsg.txt[n]);
}
bool insynch = false;
elapsedMillis outOfSynchTime;
while (!insynch && outOfSynchTime < 5000) { // after 5 seconds of no serial1 data should be back in synch
while (Serial1.available() && (Serial1.peek() != identMatch.identTxt[0])) {
Serial.print((char)Serial1.read());
outOfSynchTime = 0;
}
if (Serial1.available()) insynch = (Serial1.peek() == identMatch.identTxt[0]);
}
Serial.println("Back in synch");
}
} else Serial.println("Unable to Receive Data");
digitalWrite(ledPin, LOW);
}
delay(1);
}