diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8058f46 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,347 @@ +// simple data logger +// +// using Arduino Leonardo and an Adafruit Logger Shield +// +// uses Adafruit's RTClib +// +// Based on https://github.com/cnvogelg/ardu/blob/master/datalog/datalog/datalog.ino + +#include <Arduino.h> +#include <Wire.h> +#include <SD.h> +#include <RTClib.h> +#include <DallasTemperature.h> +#include <stdlib.h> + +#include "Bounce.h" + +// Pin setup +const int ledGreenPin = 8; +const int ledRedPin = 4; +const int buttonPin = 6; +const int oneWirePin = 7; +const int chipSelect = 10; + +#define DEBOUNCE 10 +#define BUFSIZE 32 + +// ----- GLOBALS ----- +RTC_DS1307 RTC; +OneWire oneWire(oneWirePin); +DallasTemperature sensors(&oneWire); + +uint16_t delta = 10; // measurement delta in seconds +uint32_t next_ts; + +static uint16_t year; +static uint8_t month, day, hour, minute, second; + +Bounce logToggleButton; + +File file; + +// offsets: 0123456789012 +byte name[] = "yymmdd_x.log"; + +// ----- FUNCTIONS ----- +static void led(int pin, int on) +{ + digitalWrite(pin, on ? HIGH : LOW); +} + +// fatal error - blink led and wait for reset +static void fail() { + while(1) { + led(ledRedPin, 1); + delay(200); + led(ledRedPin, 0); + delay(200); + } +} + +static int sd_init() +{ + pinMode(chipSelect, OUTPUT); + //if (!SD.begin(chipSelect)) { + if (!SD.begin(10,11,12,13)) { + Serial.println("SD init failed"); + fail(); + } +} + +static void rtc_init() +{ + Wire.begin(); + RTC.begin(); + + if (! RTC.isrunning()) { + Serial.println("RTC is NOT running!"); + } + + // get value for first measurement + next_ts = RTC.now().unixtime(); +} + +static uint16_t parse_dec(byte *buf, byte num) +{ + uint16_t val = 0; + for(byte i=0;i<num;i++) { + val = val * 10; + if ((buf[i] >= '0')&&(buf[i] <= '9')) { + byte v = buf[i] - '0'; + val += v; + } else { + return 0xffff; + } + } + return val; +} + +static void to_dec(uint16_t val, byte *buf, byte num) +{ + byte *ptr = buf + num - 1; + for(byte i=0;i<num;i++) { + byte r = val % 10; + val = val / 10; + *(ptr--) = '0' + r; + } +} + +static void store_name() +{ + DateTime now = RTC.now(); + to_dec(now.year(),name,2); + to_dec(now.month(),name+2,2); + to_dec(now.day(),name+4,2); +} + +static byte log_find_name() +{ + store_name(); + for(int i=0;i<26;i++) { + name[7] = 'a' + i; + if (!SD.exists((char *)name)) { + return 1; + } + } + return 0; +} + +static byte log_open() +{ + // log already open! + if (file) { + return 1; + } + // try to find name + if (!log_find_name()) { + return 2; + } + file = SD.open((char *)name, FILE_WRITE); + if (!file) { + return 3; + } + + Serial.print("O: "); + Serial.println((char *)name); + return 0; +} + +static byte log_close() +{ + // log is not open! + if (!file) { + return 1; + } + file.close(); + + Serial.print("C: "); + Serial.println((char *)name); + return 0; +} + +static void store_byte_val(byte v, byte cmd) +{ + switch (cmd) { + case 'm': month = v; break; + case 'd': day = v; break; + case 'H': hour = v; break; + case 'M': minute = v; break; + case 'S': second = v; break; + } +} + +static void store_word_val(uint16_t v, byte cmd) +{ + switch (cmd) { + case 'y': year = v; break; + case 'D': delta = v; break; + } +} + +static void adjust_clock() +{ + DateTime set(year,month,day,hour,minute,second); + RTC.adjust(set); + + // check new time + uint32_t ts = RTC.now().unixtime(); + + // update next time + next_ts = ts + delta; +} + +static void print_time() +{ + DateTime now = RTC.now(); + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(' '); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); +} + +const byte ERR_CMD = 9; +const byte ERR_SYNTAX = 8; +const byte OK = 0; + +static byte handle_command(char *buf, int len) +{ + uint16_t v; + switch (buf[0]) { + case 'y': // set year + case 'D': // set delta + if (len==5) { + v = parse_dec((byte*) buf+1,4); + if (v==0xffff) { + return ERR_SYNTAX; + } + Serial.write(buf[0]); + Serial.println(v); + store_word_val(v,buf[0]); + } else { + return ERR_SYNTAX; + } + break; + case 'm': // set month + case 'd': // set day + case 'H': // set HOUR + case 'M': // set MINUTE + case 'S': // set SECOND + if (len==3) { + v = parse_dec((byte*) buf+1,2); + if (v==0xffff) { + return ERR_SYNTAX; + } + Serial.write(buf[0]); + Serial.println(v); + store_byte_val((byte)v,buf[0]); + } else { + return ERR_SYNTAX; + } + break; + case 'a': // adjust clock + adjust_clock(); + break; + case 'o': // open log + return log_open(); + case 'c': // close log + return log_close(); + case 'r': // read clock + print_time(); + break; + default: + return ERR_CMD; + } + return OK; +} + +static void serial_in() +{ + // read serial + if (Serial.available()) { + char buf[BUFSIZE]; + int len = Serial.readBytesUntil('\n', buf, sizeof(buf)); + byte err = handle_command(buf, len); + if (err == 0) { + Serial.println("OK"); + } else { + Serial.print("ERR"); + Serial.print(err); + Serial.println(); + } + } +} + +static void handle_button(void) +{ + if (file) { + log_close(); + } else { + log_open(); + } +} + +// ----- MAIN ----- +void setup () { + Serial.begin(9600); + + //while (!Serial) { + //; // wait for serial port to connect. Needed for Leonardo only + //} + + Serial.println("Starting up"); + + pinMode(buttonPin, INPUT_PULLUP); + logToggleButton = Bounce(buttonPin, DEBOUNCE); + + pinMode(ledRedPin, OUTPUT); + pinMode(ledGreenPin, OUTPUT); + + rtc_init(); + sd_init(); +} + +void loop () { + led(ledRedPin, file ? 1 : 0); + + serial_in(); + + logToggleButton.update(); + if (logToggleButton.fallingEdge()) { + handle_button(); + } + + uint32_t ts = RTC.now().unixtime(); + + if (ts >= next_ts) { + led(ledGreenPin, 1); + next_ts += delta; + // do measurement + sensors.requestTemperatures(); + float t = sensors.getTempCByIndex(0); + char temp[BUFSIZE]; + + // format: <timestamp> t:1=<temp> + String line = ""; + line += ts; + + line += " t:1="; + dtostrf(t, 5, 2, temp); + line += temp; + + Serial.println(line); + if (file) { + file.println(line); + file.flush(); + } + led(ledGreenPin, 0); + } +} |