#include <avr/pgmspace.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Streaming.h>
#include <EEPROM.h>
#include "RTClib.h"
#include <Time.h>
#include <TimeLib.h>
const uint8_t days_in_month [12] PROGMEM = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
const int chipSelect = 10;
const char string_0[] PROGMEM = "1=0-Falling 1-Rising 2-Both";
const char string_1[] PROGMEM = "2=Scan Intervall";
const char string_2[] PROGMEM = "3=0-Date+time,1-Timestamp,2-Timestamp+Millis,3-Systemmillis,4-Systemmillis+TimeDiff";
const char string_3[] PROGMEM = "4=Output 0-Serial 1-SD 2-Both";
const char string_4[] PROGMEM = "5=Minimal Signal Duration in Ms";
const char string_5[] PROGMEM = "6=Debounce in Ms";
const char string_6[] PROGMEM = "7=Activate Channel 1=On 0=Off";
const char string_7[] PROGMEM = "8=change Channel (1-4)";
const char string_8[] PROGMEM = "9=Save!";
const char string_9[] PROGMEM = "10=Set RTC unixtime UTC!";
const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9};
int configs[40] = {1, 5, 2, 0, 50, 10, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
RTC_DS3231 RTC;
String filename = "";
void setup() {
loadconfigs();
Serial.begin(115200);
if (! RTC.begin())
{}
setSyncProvider(syncProvider);
setSyncInterval(1000);
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
return;
}
filename += String(now() / 60 / 60);
filename += ".csv";
}
#define SECONDS_FROM_1970_TO_2000 946684800
int pins[4] = {2, 3, 4, 5};
char buffer2[100];
String inputString = "";
boolean stringComplete = false;
int channel = 1;
boolean menuactive = false;
int menuchoice = 0;
int choicevalue = 0;
int laststate[4] = {HIGH, HIGH, HIGH, HIGH};
int state[4] = {HIGH, HIGH, HIGH, HIGH};
void loop() {
if (!menuactive)
intervallset();
serialmenu();
}
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
if (!menuactive)
{
inputString += inChar;
if (inChar == '\n') {
stringComplete = true;
}
} else
{
if (isDigit(inChar)) {
inputString += (char)inChar;
}
if (inChar == '\n') {
stringComplete = true;
}
}
}
}
void menu() {
Serial.print(hour());
Serial.print(":");
Serial.print(minute());
Serial.print(":");
Serial.print(second());
Serial.print("-");
Serial.print(day());
Serial.print(".");
Serial.print(month());
Serial.print(".");
Serial.println(year());
Serial.print("Aktiver Kanal: ");
Serial.println(channel);
for (int i = 0; i <= 9; i++)
{ int test = ((channel - 1) * 10) + i;
int tempwert = configs[((((channel - 1) * 10) + i))];
if (tempwert != -1)
Serial.print(tempwert);
spaces(String(tempwert).length());
strcpy_P(buffer2, (char*)pgm_read_word(&(string_table[i])));
Serial.println(buffer2);
delay( 100 );
}
}
void serialmenu() {
if (stringComplete)
if (!menuactive && inputString == "menu\n")
{
menuactive = true;
stringComplete = false;
inputString = "";
menu();
} else if (menuactive && menuchoice == 0)
{
menuchoice = inputString.toInt();
strcpy_P(buffer2, (PGM_P)pgm_read_word(&(string_table[menuchoice - 1])));
Serial.println(buffer2);
Serial.println("Neuen Wert eingeben!");
stringComplete = false;
inputString = "";
} else if (menuactive && menuchoice == 8)
{
choicevalue = inputString.toInt();
if (choicevalue < 4) {
channel = choicevalue;
} else
{
Serial.println("Falsche Eingabe");
}
stringComplete = false;
inputString = "";
menuchoice = 0;
menu();
} else if (menuactive && menuchoice == 9)
{
saveconfigs((channel - 1));
menuchoice = 0;
menuactive = false;
stringComplete = false;
inputString = "";
menu();
} else if (menuactive && menuchoice == 10)
{
static time_t tLast;
time_t t = inputString.toInt() + 3600;
RTC.adjust(t);
stringComplete = false;
inputString = "";
menuchoice = 0;
menuactive = false;
menu();
}
else if (menuactive && menuchoice != 0)
{
choicevalue = inputString.toInt();
configs[((channel - 1) * 10) + (menuchoice - 1)] = choicevalue;
stringComplete = false;
inputString = "";
menuchoice = 0;
menu();
}
}
void spaces(int sizechars) {
for (int z = 8; z != sizechars; z--)
{
Serial.print(" ");
}
}
boolean debouncing[4] = {false, false, false, false};
boolean mininterval[4] = {true, true, true, true};
unsigned long lastintervallmillis[4] = {millis(), millis(), millis(), millis()};
unsigned long changestate[4] = {millis(), millis(), millis(), millis()};
unsigned long lastdebounce[4] = {millis(), millis(), millis(), millis()};
unsigned long lastminpulse[4] = {millis(), millis(), millis(), millis()};
void intervallset() {
unsigned long tempmillis = millis();
for (int i = 0; i <= 3; i++) {
if (tempmillis >= lastintervallmillis[i] + configs[(i * 10) + 1] && configs[(i * 10) + 6] == 1)
{
lastintervallmillis[i] = tempmillis;
int tempstate = digitalRead(pins[i]);
if (tempstate != laststate[i])
{
debouncing[i] = true;
lastminpulse[i] = true;
laststate[i] = tempstate;
changestate[i] = tempmillis;
mininterval[i] = true;
}
if (debouncing[i]) {
if (tempmillis >= changestate[i] + configs[((i * 10) + 5)] && debouncing[i])
{ debouncing[i] = false;
mininterval[i] = false;
}
}
if (tempmillis >= changestate[i] + configs[((i * 10) + 5)] + configs[((i * 10) + 4)] && !debouncing[i] && !mininterval[i])
{
state[i] = laststate[i];
debouncing[i] = false;
lastminpulse[i] = false;
mininterval[i] = true;
int Flanke = configs[(i * 10)];
if (Flanke == 2)
{
Flanke = tempstate;
}
if (state[i] == Flanke) {
if (configs[((i * 10) + 3)] == 0 || configs[((i * 10) + 3)] == 2)
{
Serial.println( createlogtext(state[i], i, now(), millis()));
}
if (configs[((i * 10) + 3)] == 1 || configs[((i * 10) + 3)] == 2) {
File dataFile = SD.open(filename, FILE_WRITE);
if (dataFile) {
dataFile.println( createlogtext(state[i], i, now(), millis() % 1000));
dataFile.close();
}
}
}
}
}
}
}
uint32_t get_unixtime(tmElements_t t)
{
uint8_t i;
uint16_t d;
int16_t y;
uint32_t rv;
int tmpYear = t.Year + 1970;
if (tmpYear >= 2000) {
y = tmpYear - 2000;
} else {
return 0;
}
d = t.Day - 1;
for (i = 1; i < (int)t.Month; i++) {
d += pgm_read_byte(days_in_month + i - 1);
}
if ((int)t.Month > 2 && y % 4 == 0) {
d++;
}
d += (365 * y + (y + 3) / 4);
rv = ((d * 24UL + (int)t.Hour) * 60 + (int)t.Minute) * 60 + (int)t.Second + SECONDS_FROM_1970_TO_2000;
return rv;
}
void printDateTime(time_t t)
{
printDate(t);
Serial << ' ';
printTime(t);
}
void printTime(time_t t)
{
printI00(hour(t), ':');
printI00(minute(t), ':');
printI00(second(t), ' ');
}
void printDate(time_t t)
{
printI00(day(t), 0);
Serial << monthShortStr(month(t)) << _DEC(year(t));
}
void printI00(int val, char delim)
{
if (val < 10) Serial << '0';
Serial << _DEC(val);
if (delim > 0) Serial << delim;
return;
}
void saveconfigs(int channel) {
for (int i = channel * 10; i <= channel * 10 + 10; i++)
eepromWriteInt(i * 2, configs[i]);
}
void loadconfigs() {
for (int i = 0; i <= 39; i++)
configs[i] = eepromReadInt(i * 2);
}
void eepromWriteInt(int adr, int wert) {
byte low, high;
low = wert & 0xFF;
high = (wert >> 8) & 0xFF;
EEPROM.write(adr, low);
EEPROM.write(adr + 1, high);
return;
}
int eepromReadInt(int adr) {
byte low, high;
low = EEPROM.read(adr);
high = EEPROM.read(adr + 1);
return low + ((high << 8) & 0xFF00);
}
unsigned long laststatemillis1[4];
unsigned long laststatemillis0[4];
String createlogtext(int state, int channel, unsigned long newunixtime, unsigned long newmillis) {
String tempstring = "'";
int checkconfig = configs[(channel * 10) + 2];
switch (checkconfig) {
case 0:
tempstring += day();
tempstring += ".";
tempstring += month();
tempstring += ".";
tempstring += year();
tempstring += "-";
tempstring += hour();
tempstring += ":";
tempstring += minute();
tempstring += ":";
tempstring += second();
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += channel;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += state;
tempstring += "'";
return tempstring;
break;
case 1:
tempstring += newunixtime;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += channel;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += state;
tempstring += "'";
return tempstring;
case 2:
tempstring += newunixtime;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += newmillis;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += channel;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += state;
tempstring += "'";
return tempstring;
break;
case 3:
tempstring += newmillis;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += channel;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += state;
tempstring += "'";
return tempstring;
break;
case 4:
tempstring += newmillis;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += channel;
tempstring += "'";
tempstring += ",";
tempstring += "'";
tempstring += state;
tempstring += "'";
tempstring += ",";
tempstring += "'";
if (state == 0) {
tempstring += newmillis - laststatemillis0[channel];
laststatemillis0[channel] = newmillis;
} else {
tempstring += newmillis - laststatemillis1[channel];
laststatemillis1[channel] = newmillis;
}
tempstring += "'";
return tempstring;
break;
}
}
time_t syncProvider()
{
return RTC.now().unixtime();
}