Add cron functionality

ico
Ralf Schlatterbeck 2016-02-26 17:30:16 +01:00
parent c6165a3bcf
commit 6b40e88ecb
7 changed files with 866 additions and 15 deletions

View File

@ -1 +1,2 @@
time_src = time.c resource_gmtime.c resource_timestamp.c resource_timezone.c
time_src = time.c resource_gmtime.c resource_timestamp.c \
resource_timezone.c resource_crontab.c cron.c

118
apps/time/bitstring.h Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Vixie.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)bitstring.h 5.2 (Berkeley) 4/4/90
*/
typedef unsigned char bitstr_t;
/* internal macros */
/* byte of the bitstring bit is in */
#define _bit_byte(bit) \
((bit) >> 3)
/* mask for the bit within its byte */
#define _bit_mask(bit) \
(1 << ((bit)&0x7))
/* external macros */
/* bytes in a bitstring of nbits bits */
#define bitstr_size(nbits) \
((((nbits) - 1) >> 3) + 1)
/* allocate a bitstring on the stack */
#define bit_decl(name, nbits) \
(name)[bitstr_size(nbits)]
/* is bit N of bitstring name set? */
#define bit_test(name, bit) \
((name)[_bit_byte(bit)] & _bit_mask(bit))
/* set bit N of bitstring name */
#define bit_set(name, bit) \
(name)[_bit_byte(bit)] |= _bit_mask(bit)
/* clear bit N of bitstring name */
#define bit_clear(name, bit) \
(name)[_bit_byte(bit)] &= ~_bit_mask(bit)
/* clear bits start ... stop in bitstring */
#define bit_nclear(name, start, stop) { \
register bitstr_t *_name = name; \
register int _start = start, _stop = stop; \
register int _startbyte = _bit_byte(_start); \
register int _stopbyte = _bit_byte(_stop); \
if (_startbyte == _stopbyte) { \
_name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
(0xff << ((_stop&0x7) + 1))); \
} else { \
_name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
while (++_startbyte < _stopbyte) \
_name[_startbyte] = 0; \
_name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
} \
}
/* set bits start ... stop in bitstring */
#define bit_nset(name, start, stop) { \
register bitstr_t *_name = name; \
register int _start = start, _stop = stop; \
register int _startbyte = _bit_byte(_start); \
register int _stopbyte = _bit_byte(_stop); \
if (_startbyte == _stopbyte) { \
_name[_startbyte] |= ((0xff << (_start&0x7)) & \
(0xff >> (7 - (_stop&0x7)))); \
} else { \
_name[_startbyte] |= 0xff << ((_start)&0x7); \
while (++_startbyte < _stopbyte) \
_name[_startbyte] = 0xff; \
_name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
} \
}
/* find first bit clear in name */
#define bit_ffc(name, nbits, value) { \
register bitstr_t *_name = name; \
register int _byte, _nbits = nbits; \
register int _stopbyte = _bit_byte(_nbits), _value = -1; \
for (_byte = 0; _byte <= _stopbyte; ++_byte) \
if (_name[_byte] != 0xff) { \
_value = _byte << 3; \
for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
++_value, _stopbyte >>= 1); \
break; \
} \
*(value) = _value; \
}
/* find first bit set in name */
#define bit_ffs(name, nbits, value) { \
register bitstr_t *_name = name; \
register int _byte, _nbits = nbits; \
register int _stopbyte = _bit_byte(_nbits), _value = -1; \
for (_byte = 0; _byte <= _stopbyte; ++_byte) \
if (_name[_byte]) { \
_value = _byte << 3; \
for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
++_value, _stopbyte >>= 1); \
break; \
} \
*(value) = _value; \
}

488
apps/time/cron.c Normal file
View File

@ -0,0 +1,488 @@
/**
* \file
* cron: Cron-like functionality
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
* \brief cron-like command scheduler
*
* Inspired by vixie's cron by Paul Vixie which is
* Copyright 1988,1990,1993,1994 by Paul Vixie
*
* Distribute freely, except: don't remove my name from the source or
* documentation (don't take credit for my work), mark your changes (don't
* get me blamed for your possible bugs), don't alter or remove this
* notice. May be sold if buildable source is provided to buyer. No
* warrantee of any kind, express or implied, is included with this
* software; use at your own risk, responsibility for damages (if any) to
* anyone resulting from the use of this software rests entirely with the
* user.
*
* Changes to make this work on a microcontroller by Ralf Schlatterbeck
* In fact this is mostly a rewrite but keeps central algorithms and
* some data structures of the original.
* The syntax is simplified, we don't support the @ notation (e.g.
* @hourly) and named entities (e.g. weekday names instead of numbers).
* Furthermore we can't send email and don't support environment
* variables. The called commands are functions registered via a
* registration mechanism before runtime.
* Copyright 2016 Ralf Schlatterbeck, distribute with the conditions
* given above.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include "contiki.h"
#include "cron.h"
#include "time.h"
#undef DEBUG
static struct cron_entry cron_entries [MAX_CRON_ENTRIES];
static struct cron_cmd cron_commands [MAX_CRON_COMMANDS];
static size_t cron_registered_entries = 0;
static size_t cron_registered_commands = 0;
static struct cron_entry *entry_freelist = NULL;
static struct cron_entry *entry_list = NULL;
typedef int64_t minute_t;
static time_t start_time;
static minute_t cron_clock_time;
/* Register a new cron command
* A command consists of a name (which must be unique, uniqueness is not
* enforced currently as registrations are done once at initialization
* time), a function to be called and a parameter.
*/
int cron_register_command
(const char *name, void (*function)(void *), void * parameter)
{
if (cron_registered_commands >= MAX_CRON_COMMANDS) {
return -1;
}
cron_commands [cron_registered_commands].name = name;
cron_commands [cron_registered_commands].function = function;
cron_commands [cron_registered_commands].parameter = parameter;
cron_registered_commands++;
return 0;
}
/*
* Allocate a new crontab entry.
* This allocates from the freelist and returns NULL if no more entries
* are available.
* Implementation note: If cron_registered_entries is 0 we first
* initialize the entry_freelist and the entry_list.
*/
struct cron_entry *allocate_cron_entry (void)
{
size_t n;
struct cron_entry *e;
if (cron_registered_entries == 0) {
entry_list = NULL;
entry_freelist = &cron_entries [0];
for (n=0; n < (MAX_CRON_ENTRIES - 1); n++) {
cron_entries [n].next = &cron_entries [n+1];
}
cron_entries [MAX_CRON_ENTRIES - 1].next = NULL;
}
if (cron_registered_entries >= MAX_CRON_ENTRIES) {
return NULL;
}
e = entry_freelist;
entry_freelist = e->next;
e->next = entry_list;
entry_list = e;
cron_registered_entries++;
return e;
}
void free_cron_entry (struct cron_entry *obsolete)
{
struct cron_entry *e;
assert (cron_registered_entries);
if (entry_list == obsolete) {
entry_list = obsolete->next;
obsolete->next = entry_freelist;
entry_freelist = obsolete;
cron_registered_entries--;
return;
}
for (e=entry_list; e; e=e->next) {
if (e->next == obsolete) {
e->next = obsolete->next;
obsolete->next = entry_freelist;
entry_freelist = obsolete;
cron_registered_entries--;
break;
}
}
assert (e != NULL);
}
struct cron_entry *get_cron_entry (size_t idx)
{
if (idx >= MAX_CRON_ENTRIES) {
return NULL;
}
return &cron_entries [idx];
}
/* Set the number in bits, return 0 on success -1 on error */
static int set_element (bitstr_t *bits, int low, int high, int n)
{
if (n < low || n > high) {
return -1;
}
bit_set (bits, (n - low));
return 0;
}
static const char *get_number (int *np, int high, const char *s)
{
char *endptr;
long l = strtol (s, &endptr, 10);
if (endptr == s || errno == ERANGE || l > high) {
return NULL;
}
*np = l;
return endptr;
}
static const char *get_range (bitstr_t *bits, int low, int high, const char *s)
{
int i;
int n1, n2, n3;
if (*s == '*') {
/* '*' means "first-last" but can be modified by /step */
n1 = low;
n2 = high;
if (*++s == '\0') {
return NULL;
}
} else {
s = get_number (&n1, high, s);
if (s == NULL || *s == '\0') {
return NULL;
}
if (*s != '-') {
if (set_element (bits, low, high, n1) < 0) {
return NULL;
}
return s;
} else {
if (*++s == '\0') {
return NULL;
}
s = get_number (&n2, high, s);
if (*s == '\0') {
return NULL;
}
}
}
if (*s == '/') {
if (*++s == '\0') {
return NULL;
}
s = get_number (&n3, high, s);
if (*s == '\0') {
return NULL;
}
} else {
n3 = 1;
}
/* Explicit check for sane values */
if (n1 < low || n1 > high || n2 < low || n2 > high) {
return NULL;
}
for (i=n1; i<=n2; i+=n3) {
if (set_element (bits, low, high, i) < 0) {
return NULL;
}
}
return s;
}
static const char *get_list (bitstr_t *bits, int low, int high, const char *s)
{
int done = 0;
bit_nclear (bits, 0, (high - low + 1));
while (!done) {
s = get_range (bits, low, high, s);
if (NULL == s) {
return NULL;
}
if (*s == ',') {
s++;
} else {
done = 1;
}
}
/* Skip white space */
while (s && isspace (*s)) {
s++;
}
return s;
}
/*
* Parse a single crontab entry on a single line.
* We get the line via CoAP.
* Returns 0 if parsed successfully, -1 on error.
* On error the err pointer is set to the error message.
*/
int parse_crontab_line
(const char *line, struct cron_entry *e, const char **err)
{
size_t n;
const char *s = line;
size_t cmd_len = 0;
e->flags &= ~VALID;
if (*s == '*') {
e->flags |= MIN_STAR;
}
s = get_list (e->minute, FIRST_MINUTE, LAST_MINUTE, s);
if (NULL == s || *s == '\0') {
*err = "minute";
return -1;
}
if (*s == '*') {
e->flags |= HR_STAR;
}
s = get_list (e->hour, FIRST_HOUR, LAST_HOUR, s);
if (NULL == s || *s == '\0') {
*err = "hour";
return -1;
}
if (*s == '*') {
e->flags |= DOM_STAR;
}
s = get_list (e->dom, FIRST_DOM, LAST_DOM, s);
if (NULL == s || *s == '\0') {
*err = "dom";
return -1;
}
s = get_list (e->month, FIRST_MONTH, LAST_MONTH, s);
if (NULL == s || *s == '\0') {
*err = "month";
return -1;
}
if (*s == '*') {
e->flags |= DOW_STAR;
}
s = get_list (e->dow, FIRST_DOW, LAST_DOW, s);
if (NULL == s || *s == '\0') {
*err = "dow";
return -1;
}
/* Make sundays equivalent */
if (bit_test (e->dow, 0) || bit_test (e->dow, 7)) {
bit_set (e->dow, 0);
bit_set (e->dow, 7);
}
/* strip whitespace at *end* of command
* by getting length without whitespace
*/
for (n=0; s [n]; n++) {
if (!isspace (s [n])) {
cmd_len = n + 1;
}
}
for (n=0; n<cron_registered_commands; n++) {
if ( cmd_len == strlen (cron_commands [n].name)
&& !strncmp (cron_commands [n].name, s, cmd_len)
)
{
e->cmd = &cron_commands [n];
break;
}
}
if (n == cron_registered_commands) {
*err = "command";
return -1;
}
e->flags |= VALID;
return 0;
}
static void set_time (void)
{
struct tm *tm;
struct timeval tv;
gettimeofday (&tv, NULL);
start_time = tv.tv_sec;
tm = localtime (&start_time);
/* We adjust the time to GMT so we can catch DST changes */
cron_clock_time = (start_time + tm->tm_gmtoff) / (time_t)SECONDS_PER_MINUTE;
}
static void find_jobs (minute_t vtime, int do_wild, int do_nonwild)
{
time_t virtual_second = vtime * SECONDS_PER_MINUTE;
struct tm *tm = gmtime (&virtual_second);
int minute, hour, dom, month, dow;
struct cron_entry *e;
/* make 0-based values out of these so we can use them as indicies */
minute = tm->tm_min -FIRST_MINUTE;
hour = tm->tm_hour -FIRST_HOUR;
dom = tm->tm_mday -FIRST_DOM;
month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
dow = tm->tm_wday -FIRST_DOW;
#ifdef DEBUG
printf ("%d %d %d %d %d\n", minute, hour, dom, month, dow);
#endif
/* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
* first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
* on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
* is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
* like many bizarre things, it's the standard.
*/
for (e = entry_list; e; e = e->next) {
#ifdef DEBUG
if (e->flags & VALID) {
printf ("Checking entry %s\n", e->cmd->name);
}
printf ("valid: %d\n", (e->flags & VALID));
printf ("minute: %d\n", (bit_test (e->minute, minute)));
printf ("hour: %d\n", (bit_test (e->hour, hour)));
printf ("month %d\n", (bit_test (e->month, month)));
printf ("dom* %d\n", (e->flags & DOM_STAR));
printf ("dow* %d\n", (e->flags & DOW_STAR));
printf ("dow %d\n", (bit_test (e->dow, dow)));
printf ("dom %d\n", (bit_test (e->dom, dom)));
printf ("min* %d\n", (e->flags & MIN_STAR));
printf ("hr* %d\n", (e->flags & HR_STAR));
printf ("nonwild %d\n", (do_nonwild));
#endif
if ( (e->flags & VALID)
&& bit_test (e->minute, minute)
&& bit_test (e->hour, hour)
&& bit_test (e->month, month)
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
? (bit_test (e->dow, dow) && bit_test (e->dom, dom))
: (bit_test (e->dow, dow) || bit_test (e->dom, dom))
)
)
{
if ( (do_nonwild && !(e->flags & (MIN_STAR | HR_STAR)))
|| (do_wild && (e->flags & (MIN_STAR | HR_STAR)))
)
{
printf ("Cron: calling \"%s\"\n", e->cmd->name);
e->cmd->function (e->cmd->parameter);
}
}
}
}
/*
* The cron callback function must be run regularly, at least once per
* minute.
* Implementation:
* Clocks are in minutes since the epoch (time() / 60).
* virtual_time is the time it *would* be if we are called promptly and
* nobody ever changed the clock. It is monotonically increasing...
* unless a timejump happens.
* time_running is the time we were last called. We determine
* initialization by checking time_running for -1.
* cron_clock_time is the current time for this run.
*/
void cron (void)
{
static minute_t time_running = -1;
static minute_t virtual_time = -1;
minute_t time_diff;
/*
* ... calculate how the current time differs from
* our virtual clock. Classify the change into one
* of 4 cases
*/
set_time ();
if (time_running == cron_clock_time) {
#ifdef DEBUG
printf ("time not reached\n");
#endif
return;
}
time_running = cron_clock_time;
time_diff = time_running - virtual_time;
#ifdef DEBUG
printf ("time_diff: %ld\n", (long)time_diff);
#endif
/* shortcut for the most common case */
if (time_diff == 1) {
virtual_time = time_running;
find_jobs (virtual_time, 1, 1);
} else {
int wakeup_kind = -1;
if (time_diff > -(3*MINUTE_COUNT)) {
wakeup_kind = 0;
}
if (time_diff > 0) {
wakeup_kind = 1;
}
if (time_diff > 5) {
wakeup_kind = 2;
}
if (time_diff > (3*MINUTE_COUNT)) {
wakeup_kind = 3;
}
#ifdef DEBUG
printf ("wakeup_kind: %d\n", wakeup_kind);
#endif
switch (wakeup_kind) {
/* time_diff is a small positive number (wokeup late)
* run jobs for each virtual minute until caught up.
*/
case 1:
do {
virtual_time++;
find_jobs (virtual_time, 1, 1);
} while (virtual_time < time_running);
break;
/* time_diff is a medium-sized positive number, for example
* because we went to DST. Run wildcard jobs once, then run any
* fixed-time jobs that would otherwise be skipped. If we use up
* our minute (possible, if there are a lot of jobs to run) go
* around the loop again so that wildcard jobs have a chance to
* run, and we do our housekeeping.
*/
case 2:
/* run wildcard jobs for current minute */
find_jobs (time_running, 1, 0);
/* run fixed-time jobs for each minute missed */
do {
virtual_time++;
find_jobs (virtual_time, 0, 1);
set_time ();
} while ( virtual_time < time_running
&& cron_clock_time == time_running
);
break;
/* time_diff is a small or medium-sized negative num, eg.
* because of DST ending. Just run the wildcard jobs. The
* fixed-time jobs probably have already run, and should not be
* repeated. virtual_time does not change until we are caught up.
*/
case 0:
find_jobs (time_running, 1, 0);
break;
/* Other: time has changed a *lot*, jump virtual time, and run
* everything
*/
default:
virtual_time = time_running;
find_jobs (time_running, 1, 1);
break;
}
}
}

91
apps/time/cron.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Definitions for cron
* Inspired by vixie's cron by Paul Vixie which is
* Copyright 1988,1990,1993,1994 by Paul Vixie
*
* Distribute freely, except: don't remove my name from the source or
* documentation (don't take credit for my work), mark your changes (don't
* get me blamed for your possible bugs), don't alter or remove this
* notice. May be sold if buildable source is provided to buyer. No
* warrantee of any kind, express or implied, is included with this
* software; use at your own risk, responsibility for damages (if any) to
* anyone resulting from the use of this software rests entirely with the
* user.
* Changes to make this work on a microcontroller by Ralf Schlatterbeck
* In fact this is mostly a rewrite but keeps central algorithms of the
* original.
* Copyright 2016 Ralf Schlatterbeck, distribute with the conditions
* given above.
*/
#ifndef _cron_h_
#define _cron_h_
#include "bitstring.h"
#define SECONDS_PER_MINUTE 60
#define FIRST_MINUTE 0
#define LAST_MINUTE 59
#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
#define FIRST_HOUR 0
#define LAST_HOUR 23
#define HOUR_COUNT (LAST_HOUR - FIRST_HOUR + 1)
#define FIRST_DOM 1
#define LAST_DOM 31
#define DOM_COUNT (LAST_DOM - FIRST_DOM + 1)
#define FIRST_MONTH 1
#define LAST_MONTH 12
#define MONTH_COUNT (LAST_MONTH - FIRST_MONTH + 1)
/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
#define FIRST_DOW 0
#define LAST_DOW 7
#define DOW_COUNT (LAST_DOW - FIRST_DOW + 1)
#ifndef MAX_CRON_ENTRIES
#define MAX_CRON_ENTRIES 5
#endif
#ifndef MAX_CRON_COMMANDS
#define MAX_CRON_COMMANDS 5
#endif
struct cron_cmd {
const char *name;
void (*function)(void *);
void *parameter;
};
struct cron_entry {
struct cron_entry *next;
struct cron_cmd *cmd;
bitstr_t bit_decl(minute, MINUTE_COUNT);
bitstr_t bit_decl(hour, HOUR_COUNT);
bitstr_t bit_decl(dom, DOM_COUNT);
bitstr_t bit_decl(month, MONTH_COUNT);
bitstr_t bit_decl(dow, DOW_COUNT);
int flags;
#define DOM_STAR 0x01
#define DOW_STAR 0x02
#define WHEN_REBOOT 0x04
#define MIN_STAR 0x08
#define HR_STAR 0x10
#define VALID 0x20
};
extern int parse_crontab_line
(const char *line, struct cron_entry *e, const char **err);
extern int cron_register_command
(const char *name, void (*function)(void *), void * parameter);
extern struct cron_entry *allocate_cron_entry (void);
extern struct cron_entry *get_cron_entry (size_t idx);
extern void free_cron_entry (struct cron_entry *e);
extern void cron (void);
#endif /* _cron_h_ */

View File

@ -0,0 +1,118 @@
/**
* \file
* Resource for crontab entry
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
* \brief get/put crontab entry
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "time_resource.h"
#include "jsonparse.h"
#include "er-coap.h"
#include "generic_resource.h"
#include "cron.h"
static size_t get_index_from_uri (const char *uri)
{
const char *s;
char *endptr;
size_t idx;
if (uri == NULL) {
return MAX_CRON_ENTRIES;
}
if (NULL == (s = strrchr (uri, '/'))) {
return MAX_CRON_ENTRIES;
}
idx = strtoul (s+1, &endptr, 10);
if (s == endptr || *endptr != '\0') {
return MAX_CRON_ENTRIES;
}
return idx;
}
int crontab_from_string (const char *name, const char *uri, const char *s)
{
const char *err;
int res;
size_t idx = get_index_from_uri (uri);
if (idx >= MAX_CRON_ENTRIES) {
return -1;
}
res = parse_crontab_line (s, get_cron_entry (idx), &err);
if (res < 0) {
printf ("Error parsing: %s\n", err);
return -1;
}
return 0;
}
size_t
crontab_to_string (const char *name, const char *uri, char *buf, size_t bsize)
{
/* FIXME: For now we only return "valid" or "invalid" until someone
* comes up with a clever algorithm to reconstruct a crontab string
* from the cron_entry struct.
*/
size_t idx = get_index_from_uri (uri);
struct cron_entry *e;
if (idx >= MAX_CRON_ENTRIES) {
return MAX_GET_STRING_LENGTH;
}
e = get_cron_entry (idx);
if (e->flags & VALID) {
return snprintf (buf, bsize, "valid");
}
return snprintf (buf, bsize, "invalid");
}
GENERIC_RESOURCE
( crontab
, crontab-entry
, s
, 1
, crontab_from_string
, crontab_to_string
);
/* Allocate all cron entries and the necessary resources */
void activate_cron_resources (void)
{
size_t n;
for (n=0; n<MAX_CRON_ENTRIES; n++) {
resource_t *res;
char *buf;
size_t len;
struct cron_entry *e;
char name [15];
/* Need to copy the resource because resource->url holds the path
* under which we activate it using rest_activate_resource
*/
if (NULL == (res = malloc (sizeof (*res)))) {
printf ("Error malloc\n");
break;
}
memcpy (res, &res_crontab, sizeof (*res));
e = allocate_cron_entry ();
assert (!(e->flags & VALID));
len = snprintf (name, sizeof (name), "crontab/%u", n);
name [sizeof (name) -1] = '\0';
assert (len < 15);
if (NULL == (buf = malloc (len + 1))) {
printf ("Error malloc\n");
break;
}
strcpy (buf, name);
rest_activate_resource (res, buf);
}
}
/*
* VI settings, see coding style
* ex:ts=8:et:sw=2
*/

View File

@ -16,13 +16,17 @@
#ifndef time_resource_h
#define time_resource_h
#include <assert.h>
#include "contiki.h"
#include "rest-engine.h"
extern resource_t res_timestamp;
extern resource_t res_timezone;
extern resource_t res_crontab;
extern resource_t res_localtime;
extern resource_t res_utc;
extern void activate_cron_resources (void);
#endif // time_resource_h
/** @} */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011, Matthias Kovatsch and other contributors.
* Copyright (C) 2016, Ralf Schlatterbeck and other contributors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -44,8 +44,10 @@
#include "contiki-net.h"
#include "er-coap-engine.h"
#include "time.h"
#include "cron.h"
#include "time_resource.h"
#include "jsonparse.h"
#include "Arduino.h"
#if PLATFORM_HAS_BUTTON
#include "dev/button-sensor.h"
@ -82,7 +84,7 @@ extern resource_t res_radio;
//******************************************************************************/
void
hw_init()
hw_init ()
{
#if defined (PLATFORM_HAS_LEDS)
leds_off(LEDS_RED);
@ -93,8 +95,22 @@ PROCESS(rest_server_example, "Erbium Example Server");
AUTOSTART_PROCESSES(&rest_server_example, &sensors_process);
#define LED_PIN 4
#define LOOP_INTERVAL (30 * CLOCK_SECOND)
/*
* Set led to on or off, we abuse the given pointer to simply carry the
* on/off flag.
*/
void led_set (void *onoff)
{
int status = (int)onoff;
digitalWrite (LED_PIN, (status ? 0 : 1));
}
PROCESS_THREAD(rest_server_example, ev, data)
{
static struct etimer loop_periodic_timer;
PROCESS_BEGIN();
PRINTF("Starting Erbium Example Server\n");
@ -112,32 +128,47 @@ PROCESS_THREAD(rest_server_example, ev, data)
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE)
set_global_address();
configure_routing();
set_global_address ();
configure_routing ();
#endif
/* Initialize the OSD Hardware. */
hw_init();
hw_init ();
/* Initialize the REST engine. */
rest_init_engine();
rest_init_engine ();
/* Activate the application-specific resources. */
rest_activate_resource(&res_leds, "s/leds");
rest_activate_resource (&res_leds, "s/leds");
#if defined (PLATFORM_HAS_BATTERY) && REST_RES_BATTERY
SENSORS_ACTIVATE(battery_sensor);
rest_activate_resource(&res_battery, "s/battery");
rest_activate_resource (&res_battery, "s/battery");
#endif
rest_activate_resource(&res_timestamp, "clock/timestamp");
rest_activate_resource(&res_timezone, "clock/timezone");
rest_activate_resource(&res_localtime, "clock/localtime");
rest_activate_resource(&res_utc, "clock/utc");
rest_activate_resource (&res_timestamp, "clock/timestamp");
rest_activate_resource (&res_timezone, "clock/timezone");
rest_activate_resource (&res_localtime, "clock/localtime");
rest_activate_resource (&res_utc, "clock/utc");
/* Define application-specific events here. */
while(1) {
/* Register callback function(s) */
cron_register_command ("led_on", led_set, (void *)1);
cron_register_command ("led_off", led_set, (void *)0);
/* Allocate all cron entries and the necessary resources */
activate_cron_resources ();
/* Define application-specific events here.
* We need to call cron every 30 seconds or so (at least once a
* minute)
*/
etimer_set (&loop_periodic_timer, LOOP_INTERVAL);
while (1) {
PROCESS_WAIT_EVENT();
if (etimer_expired (&loop_periodic_timer)) {
cron ();
etimer_reset (&loop_periodic_timer);
}
} /* while (1) */
PROCESS_END();