inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2271424"
- inkscape:cx="233.1688"
+ inkscape:cx="66.928924"
inkscape:cy="743.6865"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
x="46.571613"
y="108.98867"
style="stroke-width:0.26458332px">parameters</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="50.883797"
+ y="76.000443"
+ id="text5120"><tspan
+ sodipodi:role="line"
+ id="tspan5118"
+ x="50.883797"
+ y="76.000443"
+ style="stroke-width:0.26458332px">run_sequence()</tspan></text>
</g>
</svg>
-bin_PROGRAMS = wakeup pwm curtain lightcontrol read_serial
+bin_PROGRAMS = wakeup pwm curtain lightswitch lightcontrol read_serial
sbin_SCRIPTS = startpwm
-wakeup_SOURCES = wakeup.cpp event.cpp
+wakeup_SOURCES = wakeup.cpp event.cpp logging.cpp
pwm_SOURCES = pwm.c
curtain_SOURCES = curtain.c
+lightswitch_SOURCES = lightswitch.c
lightcontrol_SOURCES = lightcontrol.cpp logging.cpp
sunrise_SOURCES = sunrise.cpp
{
return String("no command");
}
-//virtual void execute() = 0;
+
+ virtual int execute() = 0;
};
cmd += parameters;
return cmd;
}
+
+ virtual int execute()
+ {
+ String cmd("lightcontrol ");
+ cmd += parameters;
+ return system(cmd);
+ }
};
class Sleepstep : public Action
cmd += parameters;
return cmd;
}
+
+ virtual int execute()
+ {
+ String cmd("sleep ");
+ cmd += parameters;
+ return system(cmd);
+ }
};
#include "event.h"
+#include "logging.h"
+
+extern logstream Log;
void Event::FromXML(xml_element x)
{
}
}
+void Event::run_sequence()
+{
+ std::list<Action *>::iterator cmd;
+
+ for (cmd = sequence.begin(); cmd != sequence.end(); cmd++)
+ {
+ Log << "Executing " + (*cmd)->command_line();
+ (*cmd)->execute();
+ }
+}
+
UTC Event::next_occurance(UTC after)
{
UTC next;
String ToXML(void);
void add_action(String command);
+ void run_sequence();
UTC next_occurance(UTC after);
};
--- /dev/null
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <getopt.h>
+
+#define PAGE_SIZE (4*1024)
+#define BLOCK_SIZE (4*1024)
+
+/* Direct access to GPIO hardware */
+
+// Access from ARM Running Linux
+// For Raspberry Pi 2 and Pi 3, change BCM2708_PERI_BASE to 0x3F000000 for the code to work.
+
+//#define BCM2708_PERI_BASE 0x20000000
+#define BCM2708_PERI_BASE 0x3F000000
+#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
+
+
+// I/O access
+volatile unsigned *gpio;
+
+
+// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
+#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
+
+#define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH
+
+#define GPIO_PULL *(gpio+37) // Pull up/pull down
+#define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
+
+void setup_io();
+
+
+
+/* GPIO pin assignments */
+
+#define SWITCH_IN 2
+
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct timespec interval;
+
+ interval.tv_sec = 2;
+ interval.tv_nsec = 0;
+
+ // Set up gpi pointer for direct register access
+ setup_io();
+
+ // Initialize the IO pins.
+ INP_GPIO(SWITCH_IN);
+
+ // Scan the arguments.
+
+ while (1)
+ {
+ printf("%d", GET_GPIO(SWITCH_IN));
+ nanosleep(&interval, NULL);
+ }
+
+ return 0;
+}
+
+//
+// Set up a memory regions to access GPIO
+//
+void setup_io()
+{
+ void *gpio_map;
+ int mem_fd;
+
+ /* open /dev/mem */
+ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
+ {
+ printf("can't open /dev/mem \n");
+ exit(-1);
+ }
+
+ /* mmap GPIO */
+ gpio_map = mmap(
+ NULL, //Any adddress in our space will do
+ BLOCK_SIZE, //Map length
+ PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
+ MAP_SHARED, //Shared with other processes
+ mem_fd, //File to map
+ GPIO_BASE //Offset to GPIO peripheral
+ );
+
+ close(mem_fd); //No need to keep mem_fd open after mmap
+
+ if (gpio_map == MAP_FAILED)
+ {
+ printf("mmap error %d, errno = %d\n", gpio_map, errno);//errno also set!
+ exit(-1);
+ }
+
+ // Always use volatile pointer!
+ gpio = (volatile unsigned *)gpio_map;
+
+
+} // setup_io
#include <fstream>
#include <String.h>
-class logstream : public std::ofstream
+class logstream
{
std::ofstream destination;
public:
+ logstream()
+ {
+ }
+
logstream(const char * filename)
{
destination.open(filename, std::ios_base::app);
}
+ void open(const char * filename)
+ {
+ destination.open(filename, std::ios_base::app);
+ }
+
logstream & operator << (const char *msg);
logstream & operator << (const String &msg);
};
--- /dev/null
+<?xml version='1.0'?>
+<wakeup version='0.0.1'>
+ <logging>
+ <method>file</method>
+ <destination>.</destination>
+ <level>0</level>
+ </logging>
+ <alarms>
+ <filename>wakeup_alarms.xml</filename>
+ </alarms>
+</wakeup>
+
+#include <signal.h>
+
+#include <configuration.h>
+#include <Tachyon.h>
+
+#include "logging.h"
#include "event.h"
+// Global objects
+
+configuration Config;
+logstream Log;
+Tachyon Timebase;
+
+std::list<Event> calculate_occurances(std::list<Event> alarms)
+{
+ std::list<Event> future_alarms;
+ std::list<Event>::iterator alarm;
+
+ for (alarm = alarms.begin(); alarm != alarms.end(); alarm++)
+ {
+ UTC next_time;
+
+ next_time = alarm->next_occurance(Now());
+ //DEBUG
+ std::cout << "Next alarm after will be " << next_time << ".\n";
+ if ( next_time != UTC(date(0,0,0), hour(0)))
+ {
+ future_alarms.push_back(*alarm);
+ }
+ }
+
+ return future_alarms;
+}
+
+// Reload the configuration and list of events.
+
+void reload()
+{
+ Config.read("wakeup");
+}
+
+// Signal handler for SIGHUP: reload the configuration,
+// event list and recalculate the next event.
+
+void sighup_handler(int sig)
+{
+ std::cout << "Caught signal " << sig << "\n";
+}
+
int main()
{
+ String logdir;
+ String alarms_file;
+
+ reload();
+
+ signal(SIGHUP, sighup_handler);
+
+ logdir = Config.find_parameter("logging", "destination");
+ if (logdir == "")
+ {
+ logdir = "."; // default to current dir
+ }
+ Log.open(logdir + "/wakeup.log");
+
+ std::ofstream runfile("wakeup.run");
+ runfile << Timebase.name() << "\n";
+ runfile.close();
+
+ Log << "wakeup started";
+
std::list<Event> set_alarms;
+ std::list<Event> pending_alarms;
+
+ alarms_file = Config.find_parameter("alarms", "filename");
+ set_alarms = read_alarms(alarms_file);
+ pending_alarms = calculate_occurances(set_alarms);
+ // DEBUG
+ std::cout << alarms_to_XML(pending_alarms);
+
+ // Find the next alarm
+
+ Event next_alarm;
+ std::list<Event>::iterator alarm;
- set_alarms = read_alarms("wakeup_alarms.xml");
+ alarm = pending_alarms.begin();
+ next_alarm = *alarm;
+ while (alarm != pending_alarms.end())
+ {
+ if (alarm->next_occurance(Now()) < next_alarm.next_occurance(Now()))
+ {
+ next_alarm = *alarm;
+ }
+ alarm++;
+ }
+ // DEBUG
+ std::cout << "Sleep until " << next_alarm.next_occurance(Now()) << "\n";
+ Timebase.nanosleep(3000);
- std::cout << alarms_to_XML(set_alarms);
+ std::cout << "wakeup exitting.\n";
+ remove("wakeup.run");
}
--- /dev/null
+<?xml version='1.0'?>
+<wakeup>
+ <event id='recurr-workdays'>
+ <start>2020-04-02 06:00</start>
+ <recurrance>
+ <pattern>weekdays</pattern>
+ <number>1,2,3,4,5</number>
+ </recurrance>
+ <action>lightcontrol -r 100 -f 200</action>
+ <action>lightcontrol -g 100 -f 200</action>
+ <action>lightcontrol -w 100 -f 200</action>
+ </event>
+</wakeup>
AM_CPPFLAGS = -I../src
LDADD = -lTachyon -lACL
-check_PROGRAMS = wakeup_load_events sunrise_test event_recurrance
+check_PROGRAMS = wakeup_load_events sunrise_test event_recurrance event_run_sequence
-wakeup_load_events_SOURCES = wakeup_load_events.cpp ../src/event.cpp
-event_recurrance_SOURCES = event_recurrance.cpp ../src/event.cpp
+wakeup_load_events_SOURCES = wakeup_load_events.cpp ../src/event.cpp ../src/logging.cpp
+event_recurrance_SOURCES = event_recurrance.cpp ../src/event.cpp ../src/logging.cpp
+event_run_sequence_SOURCES = event_run_sequence.cpp ../src/event.cpp ../src/logging.cpp
sunrise_test_SOURCES = sunrise_test.cpp ../src/sunrise.cpp
#include "event.h"
#include "assert.h"
+#include "logging.h"
+
+logstream Log;
int main()
{
UTC time_expected;
UTC next_time;
+ Log.open("event_recurrance.log2");
+
set_alarms = read_alarms("wakeup-02.xml");
// The first alarm at 2020-03-22 06:00 does not recurr
--- /dev/null
+#include "event.h"
+#include "assert.h"
+#include "logging.h"
+
+logstream Log;
+
+int main()
+{
+ String PATH;
+
+ std::list<Event> set_alarms;
+ std::list<Event>::iterator alarm;
+ UTC time_to_check;
+ UTC time_expected;
+ UTC next_time;
+
+ Log.open("event_run_sequence.log2");
+
+ // Make sure we execute in our own directory
+
+ PATH = getenv("PATH");
+ PATH = "PATH=../src:" + PATH;
+ putenv(PATH);
+
+ set_alarms = read_alarms("wakeup-03.xml");
+
+ // The first alarm at 2020-03-22 06:00 has a sequence of 3 actions
+
+ alarm = set_alarms.begin();
+
+ // Time of the alarm is irrelevant, just run the sequence
+ alarm->run_sequence();
+
+}
sleep 1
read TACHYON_NAME <lightcontrol.run
-tachyon -a 10 $TACHYON_NAME
+#tachyon -a 4.0 $TACHYON_NAME
while [ -f lightcontrol.run ]
do
--- /dev/null
+<?xml version='1.0'?>
+<wakeup>
+ <event id='non-recurring'>
+ <start>2020-03-22 06:00</start>
+ <action>lightcontrol -r 100 -f 20</action>
+ <action>sleep 30</action>
+ <action>lightcontrol -r 0</action>
+ </event>
+
+</wakeup>
--- /dev/null
+<?xml version='1.0'?>
+<wakeup version='0.0.1'>
+ <logging>
+ <method>file</method>
+ <destination>.</destination>
+ <level>0</level>
+ </logging>
+ <alarms>
+ <filename>wakeup_alarms.xml</filename>
+ </alarms>
+</wakeup>
+
--- /dev/null
+<?xml version='1.0'?>
+<wakeup>
+ <event id='recurr-workdays'>
+ <start>2020-04-02 06:00</start>
+ <recurrance>
+ <pattern>weekdays</pattern>
+ <number>1,2,3,4,5</number>
+ </recurrance>
+ <action>lightcontrol -r 100 -f 200</action>
+ <action>lightcontrol -g 100 -f 200</action>
+ <action>lightcontrol -w 100 -f 200</action>
+ </event>
+</wakeup>
#include "event.h"
+#include "logging.h"
+
+logstream Log;
int main()
{
+ Log.open("wakeup_load_events.log2");
+
std::list<Event> set_alarms;
set_alarms = read_alarms("wakeup-01.xml");