summaryrefslogtreecommitdiffstats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp347
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);
+ }
+}