Add time parser and command to update the shutter schedule
authorWerner Koch <wk@gnupg.org>
Sun, 27 Nov 2011 15:42:48 +0000 (16:42 +0100)
committerWerner Koch <wk@gnupg.org>
Sun, 27 Nov 2011 15:42:48 +0000 (16:42 +0100)
Also added a feature to enable the shutter schedule only after the wall
time has been set.  This avoids unwanted shutter actions after a power
failure.

13 files changed:
ebus/Makefile
ebus/ebus.h
ebus/hardware.c
ebus/hardware.h
ebus/housectl.c
ebus/housed.c
ebus/hsd-misc.c [new file with mode: 0644]
ebus/hsd-misc.h
ebus/hsd-time.c
ebus/hsd-time.h
ebus/proto-h61.h
ebus/shutter.c
ebus/testnode.c

index eabd0be..15f53a0 100644 (file)
@@ -22,18 +22,20 @@ CFLAGS = -Wall -Wno-pointer-sign -mmcu=$(MCU) -g -Os
 LIBS =
 
 HOSTCC = gcc
-HOSTCFLAGS = -Wall -Wno-pointer-sign -g -O2
+HOSTCFLAGS = -D_GNU_SOURCE -Wall -Wno-pointer-sign -g -O0
 
 sources = ebus.h hardware.c hardware.h protocol.h csma.c \
          ebusdump.c testnode.c shutter.c proto-busctl.h proto-h61.h \
          proto-dbgmsg.h onewire.c i2c.c i2c-lcd.c \
-         housed.c housectl.c hsd-misc.h hsd-time.c hsd-time.h
+         housed.c housectl.c \
+         hsd-misc.c hsd-misc.h \
+          hsd-time.c hsd-time.h
 
 all: housed housectl testnode.hex shutter.hex doorbell.hex
 
 common_node_obj = hardware.o csma.o onewire.o
 
-common_hsd_obj = hsd-time.o
+common_hsd_obj = hsd-misc.o hsd-time.o
 
 .PHONY: FORCE
 
@@ -64,7 +66,8 @@ onewire.o: hardware.h ebus.h
 i2c.o: hardware.h ebus.h
 i2c-lcd.o: hardware.h ebus.h
 
-hsd-time.o: hsd-time.h hsd-misc.h
+hsd-misc.o: hsd-misc.c hsd-misc.h
+hsd-time.o: hsd-time.c hsd-time.h hsd-misc.h
 ebusctl.o: hsd-time.h hsd-misc.h
 
 testnode.elf : testnode.o $(common_node_obj)
@@ -80,6 +83,8 @@ doorbell.elf : doorbell.o $(common_node_obj) i2c.o i2c-lcd.o
 %.hex : %.elf
        $(OBJCOPY) -O ihex -j .text -j .data  $< $@
 
+$(common_hsd_obj):
+       $(HOSTCC) $(HOSTCFLAGS) -o $@ -c $*.c
 
 housed : housed.c protocol.h proto-busctl.h proto-h61.h
        $(HOSTCC) $(HOSTCFLAGS) -o $@ housed.c
index a1417ae..49af5ce 100644 (file)
@@ -42,6 +42,9 @@ struct
 /* Set to one (e.g. the timer int) to wakeup the main loop.  */
 volatile char wakeup_main;
 
+/* We need a flag indicating whether the time has been set.  */
+byte time_has_been_set;
+
 
 /*-- hardware.c --*/
 void hardware_setup (byte nodetype);
index 5ea26c3..3214805 100644 (file)
@@ -122,6 +122,7 @@ set_current_fulltime (uint16_t tim, byte deci)
   current_time = tim;
   current_clock = deci * 100;
   sei ();
+  time_has_been_set = 1;
 }
 
 
index ed74647..b33e0a0 100644 (file)
@@ -75,6 +75,10 @@ struct __attribute__ ((packed)) ee_data_s
            minute + 50 := pull-down
       */
       uint16_t schedule[16];
+      /* If the next variable is 1 a shutter status message will be
+         sent at the end of an action.  If it is 0 none is sent.
+         Other values are reserved for future extensions.  */
+      uint8_t  notify;
     } shutterctl;
 
     struct __attribute__ ((packed))
index a073011..d195e8d 100644 (file)
@@ -496,6 +496,81 @@ cmd_drive_shutter (FILE *fp, const char *subcmd)
 
 
 static void
+cmd_set_shutter_schedule (FILE *fp, char const *args)
+{
+  int slot;
+  uint16_t t;
+  char *endp;
+  byte msg[16];
+  unsigned int crc;
+  int idx;
+
+  msg[0] = PROTOCOL_EBUS_H61;
+  msg[1] = 0x10;
+  msg[2] = 0x05;
+  msg[3] = 0x01;
+  msg[4] = 0x01;
+  msg[5] = P_H61_SHUTTER;
+  msg[6] = P_H61_SHUTTER_UPD_SCHEDULE;
+  msg[7] = 0;
+  msg[8] = 0;
+  msg[9] = 1;
+
+  for (; *args && ascii_isspace (*args); args++)
+    ;
+
+  slot = strtol (args, &endp, 10);
+  if (!digitp (args) || slot < 0 || slot > 15)
+    {
+      err ("invalid slot number %d - must be 0..15", slot);
+      return;
+    }
+  args = endp;
+
+  msg[10] = slot;
+
+  if (!ascii_isspace (*args))
+    {
+      err ("time spec missing");
+      return;
+    }
+  t = timestr_to_ebustime (args, &endp);
+  if (t == INVALID_TIME)
+    {
+      err ("invalid time given - expecting WEEKDAY HH:MM");
+      return;
+    }
+  for (args = endp; *args && ascii_isspace (*args); args++)
+    ;
+
+  msg[11] = t >> 8;
+  msg[12] = t;
+
+  if (!strcmp (args, "up"))
+    msg[13] = 0xc0;
+  else if (!strcmp (args, "down"))
+    msg[13] = 0x80;
+  else if (!strcmp (args, "none"))
+    msg[13] = 0;
+  else
+    {
+      err ("invalid action given - must be \"up\", \"down\" or \"none\"");
+      return;
+    }
+
+  msg[14] = 0;
+  msg[15] = 0;
+  crc = compute_crc (msg, 16);
+  send_byte_raw (fp, FRAMESYNCBYTE);
+  for (idx=0; idx < 16; idx++)
+    send_byte (fp, msg[idx]);
+  send_byte (fp, crc >> 8);
+  send_byte (fp, crc);
+  fflush (fp);
+}
+
+
+static void
 cmd_reset_shutter_eeprom (FILE *fp)
 {
   byte msg[16];
@@ -530,6 +605,40 @@ cmd_reset_shutter_eeprom (FILE *fp)
 
 
 
+static void
+cmd_sensor_temperature (FILE *fp)
+{
+  byte msg[16];
+  unsigned int crc;
+  int idx;
+
+  msg[0] = PROTOCOL_EBUS_H61;
+  msg[1] = 0x10;
+  msg[2] = 0x05;
+  msg[3] = 0x01;
+  msg[4] = 0x01;
+  msg[5] = P_H61_SENSOR;
+  msg[6] = P_H61_SENSOR_TEMPERATURE;
+  msg[7] = 0; /* Get all.  */
+  msg[8] = 0;
+  msg[9] = 0;
+  msg[10] = 0;
+  msg[11] = 0;
+  msg[12] = 0;
+  msg[13] = 0;
+  msg[14] = 0;
+  msg[15] = 0;
+  crc = compute_crc (msg, 16);
+
+  send_byte_raw (fp, FRAMESYNCBYTE);
+  for (idx=0; idx < 16; idx++)
+    send_byte (fp, msg[idx]);
+  send_byte (fp, crc >> 8);
+  send_byte (fp, crc);
+  fflush (fp);
+}
+
+
 
 static void
 show_usage (const char *errtext)
@@ -556,7 +665,8 @@ main (int argc, char **argv )
 {
   int last_argc = -1;
   FILE *fp;
-  const char *cmd, *cmdarg1;
+  const char *cmd;
+  char *cmdargs;
 
   if (argc)
     {
@@ -620,7 +730,23 @@ main (int argc, char **argv )
 
   fp = open_line (*argv);
   cmd = argv[1];
-  cmdarg1 = argc < 3? "": argv[2];
+  if (argc < 3)
+    cmdargs = xstrdup ("");
+  else
+    {
+      int n,i;
+
+      for (n=0, i=2; i < argc; i++)
+        n += strlen (argv[i]) + 1;
+      cmdargs = xmalloc (n);
+      strcpy (cmdargs, argv[2]);
+      for (i=3; i < argc; i++)
+        {
+          strcat (cmdargs, " ");
+          strcat (cmdargs, argv[i]);
+        }
+    }
+
   if (!strcmp (cmd, "help"))
     {
       fputs ("help                     This help\n"
@@ -629,9 +755,10 @@ main (int argc, char **argv )
              "query-version\n"
              "query-shutter-state\n"
              "query-shutter-schedule\n"
-             "set-shutter-schedule SLOT TIMESPEC\n"
+             "set-shutter-schedule SLOTNO TIMESPEC up|down\n"
              "reset-shutter-eeprom\n"
              "drive-shutter up|down\n"
+             "sensor-temperature\n"
              ,stdout);
     }
   else  if (!strcmp (cmd, "broadcast-time"))
@@ -645,14 +772,17 @@ main (int argc, char **argv )
   else if (!strcmp (cmd, "query-shutter-schedule"))
     cmd_query_shutter_schedule (fp);
   else if (!strcmp (cmd, "set-shutter-schedule"))
-    cmd_set_shutter_schedule (fp);
+    cmd_set_shutter_schedule (fp, cmdargs);
   else if (!strcmp (cmd, "reset-shutter-eeprom"))
     cmd_reset_shutter_eeprom (fp);
   else if (!strcmp (cmd, "drive-shutter"))
-    cmd_drive_shutter (fp, cmdarg1);
+    cmd_drive_shutter (fp, cmdargs);
+  else if (!strcmp (cmd, "sensor-temperature"))
+    cmd_sensor_temperature (fp);
   else
     err ("invalid command `%s'", cmd);
 
+  free (cmdargs);
 
   fclose (fp);
   return any_error? 1:0;
index 648114f..31818dd 100644 (file)
@@ -262,7 +262,15 @@ logmsg_time (unsigned int value, unsigned int decile)
   sec = (value % 6) * 10;
   sec += decile/10;
 
-  logmsg_fmt ("%ud%02u:%02u:%02u.%u", day, hour, min, sec, decile%10);
+  logmsg_fmt ("%s %02u:%02u:%02u.%u",
+              day == 0? "Mon" :
+              day == 1? "Tue" :
+              day == 2? "Wed" :
+              day == 3? "Thu" :
+              day == 4? "Fri" :
+              day == 5? "Sat" :
+              day == 6? "Sun" : "[?]",
+              hour, min, sec, decile%10);
 }
 
 
@@ -359,19 +367,46 @@ process_ebus_busctl (byte *msg, size_t msglen)
 
 
 static void
-p_h61_adcread_cmd (byte *msg, size_t msglen)
+p_h61_sensor_cmd (byte *msg, size_t msglen)
 {
-  logmsg_fmt ("[not_yet_supported]");
+  switch (msg[6])
+    {
+    case P_H61_SENSOR_TEMPERATURE:
+      logmsg_fmt ("Temperature(%u)", msg[7]);
+      break;
+    default:
+      logmsg_fmt ("Type_%u", msg[6]);
+      break;
+    }
 }
 
+
 static void
-p_h61_adcread_rsp (byte *msg, size_t msglen)
+p_h61_sensor_rsp (byte *msg, size_t msglen)
 {
-  logmsg_fmt ("sensor_%d: %u (%02x%02x)",
-              msg[6],
-              (msg[7] << 8 | msg[8]),
-              msg[7], msg[8]);
+  int i;
+  unsigned short val;
+
+  switch (msg[6])
+    {
+    case P_H61_SENSOR_TEMPERATURE:
+      logmsg_fmt ("Temperature: Group %u[%u]", (msg[7]&0x0f), (msg[7]>>4));
+      for (i=8; i < 16; i += 2)
+        {
+          val = ((msg[i] << 8) | msg[i+1]);
+          if (val == 0x8000)
+            logmsg_fmt ("      -");
+          else if (val == 0x7fff)
+            logmsg_fmt ("  *err*");
+          else
+            logmsg_fmt (" %6.1f", val/10.0);
+        }
+      break;
 
+    default:
+      logmsg_fmt ("Type_%u", msg[6]);
+      break;
+    }
 }
 
 
@@ -432,14 +467,6 @@ process_ebus_h61 (byte *msg, size_t msglen)
 
   switch ((msg[5] & ~P_H61_RESPMASK))
     {
-    case P_H61_ADCREAD:
-      logmsg_fmt ("%s:AdcRead", is_response?"Rsp":"Cmd");
-      if (is_response)
-        p_h61_adcread_rsp (msg, msglen);
-      else
-        p_h61_adcread_cmd (msg, msglen);
-       break;
-
     case P_H61_SHUTTER:
       logmsg_fmt ("%s:Shutter", is_response?"Rsp":"Cmd");
       if (is_response)
@@ -448,6 +475,14 @@ process_ebus_h61 (byte *msg, size_t msglen)
         p_h61_shutter_cmd (msg, msglen);
        break;
 
+    case P_H61_SENSOR:
+      logmsg_fmt ("%s:Sensor", is_response?"Rsp":"Cmd");
+      if (is_response)
+        p_h61_sensor_rsp (msg, msglen);
+      else
+        p_h61_sensor_cmd (msg, msglen);
+       break;
+
     default:
       logmsg_fmt ("%s:%02x", is_response?"Rsp":"Cmd", msg[5]);
       break;
diff --git a/ebus/hsd-misc.c b/ebus/hsd-misc.c
new file mode 100644 (file)
index 0000000..d16d823
--- /dev/null
@@ -0,0 +1,98 @@
+/* hsd-misc.c - Miscellaneous functions for housed and housectl
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007,
+ *               2008, 2009, 2010  Free Software Foundation, Inc.
+ * Copyright (C) 2011 Werner Koch (dd9jn)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Some code has been taken from the jnlib part og gnupg.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hsd-misc.h"
+
+static void
+out_of_core (char const *string)
+{
+  fprintf (stderr, "out of core in %s\n", string);
+  exit (2);
+}
+
+
+void *
+xmalloc (size_t n)
+{
+  void *p = malloc (n);
+  if (!p)
+    out_of_core ("xmalloc");
+  return p;
+}
+
+void *
+xstrdup (char const *string)
+{
+  char *p;
+
+  p = malloc (strlen (string)+1);
+  if (!p)
+    out_of_core ("xstrdup");
+  strcpy (p, string);
+  return p;
+}
+
+
+int
+ascii_strcasecmp (char const *a, char const *b)
+{
+  if (a == b)
+    return 0;
+
+  for (; *a && *b; a++, b++)
+    {
+      if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
+        break;
+    }
+  return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+}
+
+
+int
+ascii_strncasecmp (char const *a, char const *b, size_t n)
+{
+  unsigned char const *p1 = (unsigned char const *)a;
+  unsigned char const *p2 = (unsigned char const *)b;
+  unsigned char c1, c2;
+
+  if (p1 == p2 || !n )
+    return 0;
+
+  do
+    {
+      c1 = ascii_tolower (*p1);
+      c2 = ascii_tolower (*p2);
+
+      if ( !--n || c1 == '\0')
+       break;
+
+      ++p1;
+      ++p2;
+    }
+  while (c1 == c2);
+
+  return c1 - c2;
+}
index a7ab484..9583464 100644 (file)
 #ifndef HSD_MISC_H
 #define HSD_MISC_H
 
+
+void *xmalloc (size_t n);
+void *xstrdup (char const *string);
+
 static inline int
 ascii_isspace (int a)
 {
@@ -31,6 +35,39 @@ ascii_isspace (int a)
     }
 }
 
+static inline int
+ascii_isupper (int c)
+{
+  return c >= 'A' && c <= 'Z';
+}
+
+static inline int
+ascii_islower (int c)
+{
+  return c >= 'a' && c <= 'z';
+}
+
+static inline int
+ascii_toupper (int c)
+{
+  if (c >= 'a' && c <= 'z')
+    c &= ~0x20;
+  return c;
+}
+
+static inline int
+ascii_tolower (int c)
+{
+  if (c >= 'A' && c <= 'Z')
+    c |= 0x20;
+  return c;
+}
+
+
+int ascii_strcasecmp (char const *a, char const *b);
+int ascii_strncasecmp (char const *a, char const *b, size_t n);
+
+
 /*-- Macros to replace ctype ones to avoid locale problems. --*/
 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
@@ -48,4 +85,7 @@ ascii_isspace (int a)
 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
 #define xtoi_4(p)   ((xtoi_2(p) * 256) + xtoi_2((p)+2))
 
+/* Helper macros.  */
+#define DIM(v)              (sizeof(v)/sizeof((v)[0]))
+
 #endif /*HSD_MISC_H*/
index 7d17acb..bd98190 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <stdint.h>
-#include <errno.h>
-#include <time.h>
 
+#include "hsd-misc.h"
 #include "hsd-time.h"
 
+
 /* Take a time string and convert it into an ebus style time.  Ebus
    time is the number of 10 second intervals since Monday 0:00 local
    time. (uint16_t)(-1) is returned on error.
 
    Supported formats are:
 
-     hh:mm:sx    - Hour, minute and 10 seconds on Monday
-     w hh:mm:sx  - Ditto with weekday specified
-     ndhh:mm:sx  - Ditto with weekday give as Monday (0) to  Sunday (6)
+     hh:mm[:sx]    - Hour, minute and 10 seconds on Monday
+     w hh:mm[:sx]  - Ditto with weekday specified
+     ndhh:mm[:sx]  - Ditto with weekday give as Monday (0) to  Sunday (6)
 
    with
 
           in any capitalization.
  */
 uint16_t
-timestr_to_ebustime (const char *string)
+timestr_to_ebustime (char const *string, char **r_endp)
 {
+  int i, n;
+  int weekday = 0;
+  int hour = 0;
+  int minute = 0;
+  int second = 0;
+  char const *s;
+  char *endp;
+
+  if (!string)
+    return INVALID_TIME;
+
+  for (; *string && ascii_isspace (*string); string++)
+    ;
+
+  if (*string >= '0' && *string <= '6' && string[1] == 'd')
+    {
+      weekday = *string - '0';
+      string += 2;
+    }
+  else if ((*string >= 'a' && *string < 'z')
+           || (*string >= 'A' && *string < 'Z'))
+    {
+      static struct { char no; char const * const name; } tbl[] = {
+        { 0, "mo" }, { 0, "mon" }, { 0, "monday" },
+        { 1, "tu" }, { 1, "tue" }, { 1, "tuesday" },
+        { 2, "we" }, { 2, "wed" }, { 2, "wednesday" },
+        { 3, "th" }, { 3, "thu" }, { 3, "thursday" },
+        { 4, "fr" }, { 4, "fri" }, { 4, "friday" },
+        { 5, "sa" }, { 5, "sat" }, { 5, "saturday" },
+        { 6, "su" }, { 6, "sun" }, { 6, "sunday" }};
 
+      for (s=string+1; *s; s++)
+        if (ascii_isspace (*s))
+          break;
+      n = s - string;
+      for (i=0; i < DIM (tbl); i++)
+        if (strlen (tbl[i].name) == n
+            && !ascii_strncasecmp (string, tbl[i].name, n))
+          break;
+      if (!(i < DIM (tbl)))
+        return INVALID_TIME;
+      weekday = tbl[i].no;
+      for (; *s && ascii_isspace (*s); s++)
+        ;
+      string = s;
+    }
 
+  if (!digitp (string))
+    return INVALID_TIME;
+  hour = strtol (string, &endp, 10);
+  if (hour < 0 || hour > 23 || *endp != ':')
+    return INVALID_TIME;
+  string = endp + 1;
+  minute = strtol (string, &endp, 10);
+  if (!digitp (string) || !digitp (string+1) || minute < 0 || minute > 59)
+    return INVALID_TIME;
+  if (*endp == ':')
+    {
+      string = endp + 1;
+      second = strtol (string, &endp, 10);
+      /* Note: We don't care about leap seconds.  */
+      if (!digitp (string) || !digitp (string+1) || second < 0 || second > 59)
+        return INVALID_TIME;
+    }
 
+  if (!*endp)
+    string = endp;
+  else if (ascii_isspace (*endp))
+    string = endp + 1;
+  else
+    return INVALID_TIME;
 
+  if (r_endp)
+    *r_endp = (char *)string;
+
+  return (weekday * 24 * 60 * 6
+          + hour * 60 * 6
+          + minute * 6
+          + second / 10);
 }
+
+
+
+char *
+ebustime_to_timestr (uint16_t ebustime)
+{
+  unsigned int day, hour, min, sec;
+  char *result;
+
+  if (ebustime == INVALID_TIME)
+    {
+      if (asprintf (&result, "[invalid time]") == -1)
+        result = NULL;
+    }
+  else
+    {
+      day = (ebustime/6/60/24);
+      hour= (ebustime/6/60 % 24);
+      min = (ebustime/6 % 60);
+      sec = (ebustime % 6) * 10;
+
+      if (asprintf (&result, "%s %u:%02u:%02u",
+                    day == 0? "Mon" :
+                    day == 1? "Tue" :
+                    day == 2? "Wed" :
+                    day == 3? "Thu" :
+                    day == 4? "Fri" :
+                    day == 5? "Sat" :
+                    day == 6? "Sun" : "[?]",
+                    hour, min, sec) == -1)
+        result = NULL;
+    }
+  return result;
+}
+
index 12489bd..aca6758 100644 (file)
 #ifndef HSD_TIME_H
 #define HSD_TIME_H
 
-uint16_t timestr_to_ebustime (const char *string);
+
+#define INVALID_TIME ((uint16_t)(-1))
+
+uint16_t timestr_to_ebustime (const char *string, char **endp);
+char * ebustime_to_timestr (uint16_t ebustime);
 
 
 #endif /*HSD_TIME_H*/
index fa60881..f8a0cf2 100644 (file)
    There is no response message.  It is suggested to use Query Shutter
    State to check that the settings are correct.
 
+* 0x20 := Read sensors
+
+  byte 6 - Sensor type
+
+** 0x20, 0x01 Read temperature sensors
+
+  byte 7     - Sensor group to read (0 to read all).
+  byte 8..15 - reserved (must be 0)
+
+  A sensor group consist of 4 sensors.
+
+*** Response message
+
+  byte 7     - bit 7..4 := Number of available sensor groups
+               bit 3..0 := This Sensor group (1 to 15).
+  byte 8,9   - Sensor 0
+  byte 10,11 - Sensor 1
+  byte 12,13 - Sensor 2
+  byte 14,15 - Sensor 3
+
+  The values of the temperature sensors are signed 16 bit integer
+  values returning the temperature in decigrades.  There are two
+  special values:
+    0x8000 (-32678) := No sensor found
+    0x7fff (32767)  := Error reading value.
+
+  Note that it may take some time to read the sensor, thus the client
+  should not expect that the host will answer immediately.
+
 */
 
 #include "protocol.h"
 
 #define P_H61_RESPMASK 0x80  /* The response mask for the commands.  */
 #define P_H61_SHUTTER  0x10  /* ShutterControl.  */
-#define P_H61_ADCREAD  0x21  /* Read analog sensor.  */
+#define P_H61_SENSOR   0x20  /* Read sensor.  */
 
 
 /* Subcommands of P_H61_SHUTTER.  */
 #define P_H61_SHUTTER_QRY_SCHEDULE 0x04
 #define P_H61_SHUTTER_UPD_SCHEDULE 0x05
 
+/* Subcommands of P_H61_SENSOR.  */
+#define P_H61_SENSOR_TEMPERATURE   0x01
+
 
 
 #endif /*PROTO_H61_H*/
index 041b1ef..80f0b3f 100644 (file)
@@ -290,6 +290,9 @@ process_schedule (uint16_t time, uint16_t forced_tlow)
   uint16_t tlow, thigh, t, tfound;
   byte i;
 
+  if (!time_has_been_set)
+    return; /* Don't schedule while running without a valid clock.  */
+
   if (schedule_last_tfound > time || forced_tlow)
     schedule_last_tfound = 0;  /* Time wrapped to the next week or forced
                                   schedule action.  */
@@ -393,15 +396,7 @@ process_shutter_cmd (byte *msg)
 
     case P_H61_SHUTTER_QRY_SCHEDULE:
       {
-        byte n, i;
-
-        for (i=0; i < DIM (ee_data.u.shutterctl.schedule); i++)
-          {
-            val16 = eeprom_read_word (&ee_data.u.shutterctl.schedule[i]);
-            if (!val16)
-              break;
-          }
-        n = i;
+        byte i;
 
         msg[1] = msg[3];
         msg[2] = msg[4];
@@ -410,7 +405,7 @@ process_shutter_cmd (byte *msg)
         msg[5] |= P_BUSCTL_RESPMASK;
         msg[7] = 0; /* We only have a global schedule for now.  */
         msg[8] = 0; /* No error.  */
-        for (i=0; i < n; i++)
+        for (i=0; i < DIM (ee_data.u.shutterctl.schedule); i++)
           {
             val16 = eeprom_read_word (&ee_data.u.shutterctl.schedule[i]);
             switch ((val16 % 6))
@@ -421,7 +416,7 @@ process_shutter_cmd (byte *msg)
               }
             val16 /= 6;
             val16 *= 6;
-            msg[9] = n;
+            msg[9] = DIM (ee_data.u.shutterctl.schedule);
             msg[10] = i;
             msg[11] = val16 >> 8;
             msg[12] = val16;
@@ -467,6 +462,43 @@ process_shutter_cmd (byte *msg)
 }
 
 
+
+/* Process a sensor command.  */
+static void
+process_sensor_cmd (byte *msg)
+{
+  uint16_t val16;
+  byte err = 0;
+
+  switch (msg[6])
+    {
+    case P_H61_SENSOR_TEMPERATURE:
+      {
+        msg[1] = msg[3];
+        msg[2] = msg[4];
+        msg[3] = config.nodeid_hi;
+        msg[4] = config.nodeid_lo;
+        msg[5] |= P_BUSCTL_RESPMASK;
+        msg[7] = (1 << 4 | 1); /* Group 1 of 1.  */
+        msg[8] = 0;
+        msg[9] = 0;
+        msg[10] = 0x80; /* No sensor.  */
+        msg[11] = 0;
+        msg[12] = 0x80;
+        msg[13] = 0;
+        msg[14] = 0x80;
+        msg[15] = 0;
+        memset (msg+10, 0, 6);
+        csma_send_message (msg, MSGSIZE);
+      }
+      break;
+
+    default:
+      break;
+    }
+}
+
+
 /* A new message has been received and we must now parse the message
    quickly and see what to do.  We need to return as soon as possible,
    so that the caller may re-enable the receiver.  */
@@ -485,6 +517,11 @@ process_ebus_h61 (byte *msg)
         process_shutter_cmd (msg);
       break;
 
+    case P_H61_SENSOR:
+      if (!is_response)
+        process_sensor_cmd (msg);
+      break;
+
     default:
       break;
     }
@@ -583,6 +620,8 @@ init_eeprom (byte force)
           uptime += 24 * 60 * 6;
           downtime += 24 * 60 * 6;
         }
+      for (; i < DIM (ee_data.u.shutterctl.schedule); i++)
+        eeprom_write_word (&ee_data.u.shutterctl.schedule[i], 0);
     }
 }
 
index dcd44b8..cee7b7e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include <avr/sleep.h>