SapFlow Probe
A low-cost HRM probe for measuring a tree's water consumption
schedule.cpp
Go to the documentation of this file.
1 #include "schedule.h"
2 
4 
5 void alarmISR() {
6  // Reset the alarm.
7  rtc_ds.armAlarm(1, false);
8 
9  // Disable this interrupt
10  detachInterrupt(digitalPinToInterrupt(ALARM_PIN));
11 }
12 
13 void feather_sleep( void ){MARK();
14  // Wait for the alarm to clear
15  while(!digitalRead(ALARM_PIN)){
16  pinMode(ALARM_PIN, INPUT_PULLUP);
17  Serial.print("Waiting on alarm pin...");
18  delay(10);
19  }MARK();
20  // Disable SPI to save power
21  pinMode(SPI_SCK, INPUT);
22  pinMode(SPI_MOSI, INPUT);
23  pinMode(SD_CS, INPUT);
24  // Turn off power rails
25  digitalWrite(EN_3v3, HIGH);
26  digitalWrite(EN_5v, LOW);
27  digitalWrite(STATUS_LED, LOW);MARK();
28  Serial.println("Sleeping");
30 #if 1
31  // Prep for sleep
32  Serial.end();
33  USBDevice.detach();
34  // Low-level so we can wake from sleep
35  // We have to call this twice - maybe a synchronization issue?
36  attachInterrupt(digitalPinToInterrupt(ALARM_PIN), alarmISR, LOW);
37  attachInterrupt(digitalPinToInterrupt(ALARM_PIN), alarmISR, LOW);
38  // Sleep
39  LowPower.standby();
40 
41  // Prep to resume
42  USBDevice.attach();
43  Serial.begin(115200);
44 #else
45  // Pretend to sleep, so the serial terminal doesn't exit
46  // This draws a lot of power, so don't do this in production
47  while(digitalRead(ALARM_PIN));
48 #endif
49  // Resume the watchdog
53  MARK();
54  // Enable the power rails
55  digitalWrite(STATUS_LED, HIGH);
56  digitalWrite(EN_3v3, LOW);
57  digitalWrite(EN_5v, HIGH);
58  // Start the SD card again
59  pinMode(SPI_SCK, OUTPUT);
60  pinMode(SPI_MOSI, OUTPUT);
61  pinMode(SD_CS, OUTPUT);MARK();
62  sd.begin(SD_CS, SD_SCK_MHZ(1));MARK();
63 }
64 
65 // Sleep until the time is a round multiple of the minute inteval.
66 // Produces unexpected bevahior for non-factors of 60 (7, 8, 9, 11, etc)
67 void sleep_cycle( int interval ){MARK();
68  Serial.print("Sleeping until nearest multiple of ");
69  Serial.print(interval);
70  Serial.println(" minutes");MARK();
71  DateTime t = rtc_ds.now();MARK();
72  t = t + TimeSpan( interval * 60 );MARK();
73  uint8_t minutes = interval*(t.minute()/interval);MARK();
74  rtc_ds.setAlarm(ALM2_MATCH_MINUTES, minutes, 0, 0);MARK();
75  Serial.print("Alarm set to ");MARK();
76  t = rtc_ds.getAlarm(2);MARK();
77  Serial.println(t.text());MARK();
78  feather_sleep();MARK();
79 }
80 
81 int schedule(struct pt *pt)
82 {
83  PT_BEGIN(pt);
84  Serial.print("Initializing schedule thread... ");
85  // RTC Timer settings here
86  if (! rtc_ds.begin()) {
87  Serial.println("Couldn't find RTC");
88  }
89  // If this is a new RTC, set the time
90  if (rtc_ds.lostPower()) {
91  Serial.println("RTC lost power, lets set the time!");
92  // Set the RTC to the date & time this sketch was compiled
93  rtc_ds.adjust(DateTime(F(__DATE__), F(__TIME__)));
94  }
95  Serial.println("Done");
96  // This is the main schedule for the program
97  while (1)
98  {
99  Serial.print("Awoke at ");MARK();
100  Serial.println(rtc_ds.now().text());MARK();
101  PT_WAIT_THREAD(pt, baseline());MARK(); //<Measure the baseline temp
102  digitalWrite(HEATER, HIGH);MARK(); //< Turn on the heater
103  Serial.print("Heater On at ");MARK();
104  Serial.println(rtc_ds.now().text());MARK();
105  PT_TIMER_DELAY(pt,6000);MARK(); //< Heater is on for 6 seconds
106  digitalWrite(HEATER, LOW);MARK(); //< Turn off the heater
107  Serial.print("Heater Off at ");MARK();
108  Serial.println(rtc_ds.now().text());MARK();
109  PT_TIMER_DELAY(pt,100);MARK(); //< Wait for heat to propagate
110  Serial.println("Temperature probably reached plateau");MARK();
111  PT_WAIT_THREAD(pt, delta());MARK(); //<Calculate the sapflow
112  Serial.println("Finished logging");MARK();
113  sleep_cycle(5); MARK(); //<Sleep until the next multiple of 5 minutes
114  sleep = false;
115  }
116  PT_END(pt);
117 }
EN_5v
@ EN_5v
Control pin for 5v Power rail. Output, Active-high.
Definition: pinout.h:13
STATUS_LED
@ STATUS_LED
Built-in LED on feather. Active-high.
Definition: pinout.h:17
schedule.h
sleep_cycle
void sleep_cycle(int interval)
Sleep function for periodic sleeping.
Definition: schedule.cpp:67
EN_3v3
@ EN_3v3
Control pin for 3.3V power rail. Output, Active-low.
Definition: pinout.h:12
rtc_ds
static RTC_DS3231 rtc_ds
Instance of our real-time clock.
Definition: schedule.h:11
SPI_MOSI
@ SPI_MOSI
SPI data pin. Output.
Definition: pinout.h:21
alarmISR
void alarmISR()
Interrupt handler for RTC alarm.
Definition: schedule.cpp:5
feather_sleep
void feather_sleep(void)
Maximizes power savings during sleep.
Definition: schedule.cpp:13
FunctionMarker::print
void print(void)
Prints the most recently recorded value.
Definition: debug.cpp:42
FunctionMarker::resume
void resume(void)
Re-enable the watchdog. You should do this right after waking from sleep.
Definition: debug.cpp:37
baseline
int baseline(struct pt *pt)
Calculates baseline temperature.
Definition: measure.cpp:65
FunctionMarker::pause
void pause(void)
Pause the watchdog. You'll want to do this before sleeping.
Definition: debug.cpp:33
sd
static SdFat sd
File system object.
Definition: sd_log.h:14
HEATER
@ HEATER
Control pin for heater switch. Output, Active-high.
Definition: pinout.h:15
MARK
#define MARK()
This macro records the line number and function name.
Definition: debug.h:72
halt_location
static class FunctionMarker halt_location
Singleton of our debug class.
Definition: debug.h:64
delta
int delta(struct pt *pt)
Calculates temperature delta and sapflow.
Definition: measure.cpp:91
FunctionMarker::read
bool read(void)
Read the recorded value from flash.
Definition: debug.cpp:58
schedule
int schedule(struct pt *pt)
Controls general measurement schedule.
Definition: schedule.cpp:81
sleep
static bool sleep
Global flag to prep for sleep.
Definition: schedule.h:13
SPI_SCK
@ SPI_SCK
SPI clock pin. Output.
Definition: pinout.h:20
ALARM_PIN
@ ALARM_PIN
Interrupt pin from RTC. Pull-up, Active-low.
Definition: pinout.h:16
SD_CS
@ SD_CS
SPI chip select for SD card. Output, Active-low.
Definition: pinout.h:14