New utility housectl.
authorWerner Koch <wk@gnupg.org>
Mon, 24 Oct 2011 19:13:17 +0000 (21:13 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 24 Oct 2011 19:13:17 +0000 (21:13 +0200)
ebus/Makefile [new file with mode: 0644]
ebus/housectl.c [new file with mode: 0644]
ebus/housed.c
ebus/shutter.c

diff --git a/ebus/Makefile b/ebus/Makefile
new file mode 100644 (file)
index 0000000..65825e2
--- /dev/null
@@ -0,0 +1,83 @@
+# Makefile - The CSMA Elektor Bus
+# Copyright (C) 2011 g10 Code GmbH
+#
+# 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/>.
+#
+
+MCU=atmega88
+CC = avr-gcc
+OBJCOPY = avr-objcopy
+CFLAGS = -Wall -Wno-pointer-sign -mmcu=$(MCU) -g -Os
+LIBS =
+
+HOSTCC = gcc
+HOSTCFLAGS = -Wall -Wno-pointer-sign -g -O2
+
+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
+
+all: housed housectl testnode.hex shutter.hex doorbell.hex
+
+common_node_obj = hardware.o csma.o onewire.o
+
+.PHONY: FORCE
+
+FORCE:
+
+revision.h: FORCE Makefile
+       @set -e; \
+        if [ "x$$(git status -uno --porcelain)" = x ]; then \
+          git branch -v --no-color 2>/dev/null \
+          | awk '/^\* / {printf "#define GIT_REVISION \"%s\"\n",$$3}' \
+          > revision.h.tmp;\
+       else \
+         echo '#define GIT_REVISION "unknown"' > revision.h.tmp ;\
+       fi;\
+       if [ ! -f $@ ]; then \
+            mv -f revision.h.tmp $@ ;\
+       elif ! cmp revision.h.tmp $@; then \
+            mv -f revision.h.tmp $@ ;\
+        fi
+
+ebus.h : revision.h
+
+hardware.o : hardware.h ebus.h protocol.h
+csma.o : ebus.h protocol.h
+testnode.o : hardware.h ebus.h protocol.h
+shutter.o : ebus.h protocol.h proto-h61.h proto-busctl.h
+onewire.o: hardware.h ebus.h
+i2c.o: hardware.h ebus.h
+i2c-lcd.o: hardware.h ebus.h
+
+testnode.elf : testnode.o $(common_node_obj)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+shutter.elf : shutter.o $(common_node_obj)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+doorbell.elf : doorbell.o $(common_node_obj) i2c.o i2c-lcd.o
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+
+%.hex : %.elf
+       $(OBJCOPY) -O ihex -j .text -j .data  $< $@
+
+
+housed : housed.c protocol.h proto-busctl.h proto-h61.h
+       $(HOSTCC) $(HOSTCFLAGS) -o $@ housed.c
+
+housectl : housectl.c protocol.h proto-busctl.h proto-h61.h
+       $(HOSTCC) $(HOSTCFLAGS) -o $@ housectl.c
diff --git a/ebus/housectl.c b/ebus/housectl.c
new file mode 100644 (file)
index 0000000..1262f2f
--- /dev/null
@@ -0,0 +1,653 @@
+/* housectl.c - A house control utility
+ * 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/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <stdint.h>
+#include <errno.h>
+#include <time.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "protocol.h"
+#include "proto-busctl.h"
+#include "proto-h61.h"
+
+
+#define PGM           "housectl"
+#define PGM_VERSION   "0.0"
+#define PGM_BUGREPORT "wk@gnupg.org"
+
+typedef unsigned char byte;
+
+/* Option flags. */
+static int verbose;
+static int debug;
+static int line_speed = 19200;
+
+/* Error counter.  */
+static int any_error;
+
+
+/* Print diagnostic message and exit with failure. */
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  fflush (stdout);
+  fprintf (stderr, "%s: ", PGM);
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  putc ('\n', stderr);
+
+  exit (1);
+}
+
+
+/* Print diagnostic message. */
+static void
+err (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  any_error = 1;
+
+  fflush (stdout);
+  fprintf (stderr, "%s: ", PGM);
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  putc ('\n', stderr);
+}
+
+
+/* Print a info message message. */
+static void
+inf (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  if (verbose)
+    {
+      fprintf (stderr, "%s: ", PGM);
+
+      va_start (arg_ptr, format);
+      vfprintf (stderr, format, arg_ptr);
+      va_end (arg_ptr);
+      putc ('\n', stderr);
+    }
+}
+
+
+static void
+dump_mcbits (int fd)
+{
+  int mcbits;
+
+  if (ioctl (fd, TIOCMGET, &mcbits))
+    err ("TIOCMGET failed: %s\n", strerror (errno));
+  else
+    inf ("mc: %3s %3s %3s %3s %3s %3s %3s %3s %3s",
+         (mcbits & TIOCM_LE )? "LE":"",
+         (mcbits & TIOCM_DTR)? "DTR":"",
+         (mcbits & TIOCM_DSR)? "DSR":"",
+         (mcbits & TIOCM_CAR)? "DCD":"",
+         (mcbits & TIOCM_RNG)? "RI":"",
+         (mcbits & TIOCM_RTS)? "RTS":"",
+         (mcbits & TIOCM_CTS)? "CTS":"",
+         (mcbits & TIOCM_ST )? "TX2":"",
+         (mcbits & TIOCM_SR )? "RX2":"");
+}
+
+
+static FILE *
+open_line (const char *fname)
+{
+  FILE *fp;
+  int fd;
+  struct termios term;
+  speed_t speed;
+
+  switch (line_speed)
+    {
+    case 300   : speed = B300   ; break;
+    case 600   : speed = B600   ; break;
+    case 1200  : speed = B1200  ; break;
+    case 2400  : speed = B2400  ; break;
+    case 4800  : speed = B4800  ; break;
+    case 9600  : speed = B9600  ; break;
+    case 19200 : speed = B19200 ; break;
+    case 38400 : speed = B38400 ; break;
+    case 57600 : speed = B57600 ; break;
+    case 115200: speed = B115200; break;
+    default:
+      die ("unsupported line speed %d given", line_speed);
+    }
+
+  fp = fopen (fname, "r+");
+  if (!fp || (fd = fileno (fp)) == -1)
+    die ("can't open `%s': %s", fname, strerror (errno));
+
+  if (tcgetattr (fd, &term))
+    die ("tcgetattr(%d) failed: %s", fd, strerror (errno));
+
+  term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+                    | INLCR | IGNCR | ICRNL | IXON);
+  term.c_oflag &= ~OPOST;
+  term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+  term.c_cflag &= ~(CSIZE | PARENB);
+  term.c_cflag |= CS8;
+
+  if (cfsetospeed (&term, speed) || cfsetispeed (&term, speed))
+    die ("setting terminal speed to %d failed: %s",
+         line_speed, strerror (errno));
+
+  if (tcsetattr (fd, TCSANOW, &term ) )
+    die ("tcsetattr(%d) failed: %s", fd, strerror (errno));
+
+  inf ("connected to '%s' at %dbps", fname, line_speed);
+  dump_mcbits (fd);
+  /* { */
+  /*   int mcbits; */
+
+  /*   for (;;) */
+  /*     { */
+  /*       mcbits = TIOCM_RTS; */
+  /*       if (ioctl (fd, TIOCMBIC, &mcbits)) */
+  /*         err ("TIOCMBIC(RTS) failed: %s\n", strerror (errno)); */
+  /*       mcbits = TIOCM_RTS; */
+  /*       if (ioctl (fd, TIOCMBIS, &mcbits)) */
+  /*         err ("TIOCMBIS(RTS) failed: %s\n", strerror (errno)); */
+  /*     } */
+  /* } */
+  /* dump_mcbits (fd); */
+
+  return fp;
+}
+
+
+static uint16_t
+crc_ccitt_update (uint16_t crc, uint8_t data)
+{
+  data ^= (crc & 0xff);
+  data ^= data << 4;
+
+  return ((((uint16_t)data << 8) | ((crc >> 8)& 0xff)) ^ (uint8_t)(data >> 4)
+          ^ ((uint16_t)data << 3));
+}
+
+
+/* Compute the CRC for MSG.  MSG must be of MSGLEN.  The CRC used is
+   possible not the optimal CRC for our message length.  However on
+   the AVR we have a convenient inline function for it.  */
+static uint16_t
+compute_crc (const unsigned char *msg, size_t msglen)
+{
+  int idx;
+  uint16_t crc = 0xffff;
+
+  for (idx=0; idx < msglen; idx++)
+    crc = crc_ccitt_update (crc, msg[idx]);
+
+  return crc;
+}
+
+
+/* Return the current ebus time for broadcasting.  The time is defined
+   as number of 10 second periods passed since Monday 0:00.  */
+static unsigned int
+mk_ebus_time (unsigned int *r_decile, unsigned int *r_dst)
+{
+  struct tm *tp;
+  time_t atime = time (NULL);
+  unsigned int result;
+
+  /* Get the local time and convert it to a Monday...Sunday week.  */
+  /* Fixme: We can't return fractions of a second.  Need to use
+     clock_gettime or wait for the full second.  */
+  tp = localtime (&atime);
+  if (!tp->tm_wday)
+    tp->tm_wday = 6;
+  else
+    tp->tm_wday--;
+
+  result = (tp->tm_wday * 24 * 60 * 6
+            + tp->tm_hour * 60 * 6
+            + tp->tm_min * 6 + tp->tm_sec/10);
+  if (r_decile)
+    *r_decile = (tp->tm_sec % 10) * 10;
+  if (r_dst)
+    *r_dst = !!tp->tm_isdst;
+  return result;
+}
+
+
+
+\f
+/* Send out the raw byte C.  */
+static void
+send_byte_raw (FILE *fp, byte c)
+{
+  putc (c, fp);
+}
+
+
+/* Send byte C with byte stuffing.  */
+static void
+send_byte (FILE *fp, byte c)
+{
+  if (c == FRAMESYNCBYTE || c == FRAMEESCBYTE)
+    {
+      send_byte_raw (fp, FRAMEESCBYTE);
+      send_byte_raw (fp, (c ^ FRAMEESCMASK));
+    }
+  else
+    send_byte_raw (fp, c);
+}
+
+
+static void
+cmd_query_time (FILE *fp)
+{
+  byte msg[16];
+  unsigned int crc;
+  int idx;
+
+  msg[0] = PROTOCOL_EBUS_BUSCTL;
+  msg[1] = 0xff;
+  msg[2] = 0xff;
+  msg[3] = 0x01;
+  msg[4] = 0x01;
+  msg[5] = P_BUSCTL_QRY_TIME;
+  memset (msg+6, 0, 10);
+  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_query_version (FILE *fp)
+{
+  byte msg[16];
+  unsigned int crc;
+  int idx;
+
+  msg[0] = PROTOCOL_EBUS_BUSCTL;
+  msg[1] = 0xff;
+  msg[2] = 0xff;
+  msg[3] = 0x01;
+  msg[4] = 0x01;
+  msg[5] = P_BUSCTL_QRY_VERSION;
+  memset (msg+6, 0, 10);
+  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_query_shutter_schedule (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_SHUTTER;
+  msg[6] = P_H61_SHUTTER_QRY_SCHEDULE;
+  msg[7] = 1;
+  memset (msg+8, 0, 8);
+  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_broadcast_time (FILE *fp)
+{
+  byte msg[16];
+  unsigned int crc;
+  int idx;
+  unsigned int tim, dec, dst;
+
+  tim = mk_ebus_time (&dec, &dst);
+  msg[0] = PROTOCOL_EBUS_BUSCTL;
+  msg[1] = 0xff;
+  msg[2] = 0xff;
+  msg[3] = 0x01;
+  msg[4] = 0x01;
+  msg[5] = P_BUSCTL_TIME;
+  msg[6] = 0x03;  /* Decile given, exact time */
+  if (dst)
+    msg[6] |= 0x04;
+  msg[7] = tim >> 8;
+  msg[8] = tim;
+  msg[9] = dec;
+  memset (msg+10, 0, 6);
+  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 */
+/* footest_4 (FILE *fp) */
+/* { */
+/*   byte msg[16]; */
+/*   unsigned int crc; */
+/*   int idx; */
+/*   unsigned char   item = 2; */
+/*   unsigned int     tim = 3 * 60 * 6; */
+/*   unsigned char action = 0x80; */
+
+/*   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; */
+/*   msg[10] = item; */
+/*   msg[11] = tim >> 8; */
+/*   msg[12] = tim; */
+/*   msg[13] = action; */
+/*   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_query_shutter_state (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_SHUTTER;
+  msg[6] = P_H61_SHUTTER_QUERY;
+  msg[7] = 0;
+  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
+cmd_drive_shutter (FILE *fp, const char *subcmd)
+{
+  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_DRIVE;
+  msg[7] = 0;
+
+  if (!strcmp (subcmd, "up"))
+    msg[8] = 0xc0;
+  else if (!strcmp (subcmd, "down"))
+    msg[8] = 0x80;
+  else
+    {
+      err ("invalid sub-command.  Use \"up\" or \"down\"");
+      return;
+    }
+  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
+cmd_reset_shutter_eeprom (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_SHUTTER;
+  msg[6] = P_H61_SHUTTER_UPD_SCHEDULE;
+  msg[7] = 0xf0;
+  msg[8] = 0;
+  msg[9] = 16;
+  msg[10] = 0xf0;
+  msg[11] = 0xf0;
+  msg[12] = 0xf0;
+  msg[13] = 0xf0;
+  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)
+{
+  if (errtext)
+    {
+      err ("command line error: %s\n", errtext);
+      exit (1);
+    }
+  fputs ("Usage: " PGM " DEVICE COMMAND\n"
+         "Send message to housed\n\n"
+         "  --speed N      Use given speed\n"
+         "  --verbose      Enable extra informational output\n"
+         "  --debug        Enable additional debug output\n"
+         "  --help         Display this help and exit\n\n"
+         "Report bugs to " PGM_BUGREPORT ".\n",
+         stdout);
+  exit (0);
+}
+
+
+int
+main (int argc, char **argv )
+{
+  int last_argc = -1;
+  FILE *fp;
+  const char *cmd, *cmdarg1;
+
+  if (argc)
+    {
+      argc--; argv++;
+    }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--version"))
+        {
+          fputs (PGM " " PGM_VERSION "\n", stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          show_usage (NULL);
+        }
+      else if (!strcmp (*argv, "--speed"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              line_speed = atoi (*argv);
+              argc--; argv++;
+            }
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose = debug = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--node"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              line_speed = atoi (*argv);
+              argc--; argv++;
+            }
+          else
+            show_usage ("argument missing");
+        }
+      else if (!strncmp (*argv, "--", 2))
+        show_usage ("invalid option");
+    }
+
+  if (argc < 2)
+    show_usage ("device or command missing");
+
+  setvbuf (stdout, NULL, _IOLBF, 0);
+
+  fp = open_line (*argv);
+  cmd = argv[1];
+  cmdarg1 = argc < 3? "": argv[2];
+  if (!strcmp (cmd, "help"))
+    {
+      fputs ("help                     This help\n"
+             "broadcast-time\n"
+             "query-time\n"
+             "query-version\n"
+             "query-shutter-state\n"
+             "query-shutter-schedule\n"
+             "reset-shutter-eeprom\n"
+             "drive-shutter up|down\n"
+             ,stdout);
+    }
+  else  if (!strcmp (cmd, "broadcast-time"))
+    cmd_broadcast_time (fp);
+  else if (!strcmp (cmd, "query-time"))
+    cmd_query_time (fp);
+  else if (!strcmp (cmd, "query-version"))
+    cmd_query_version (fp);
+  else if (!strcmp (cmd, "query-shutter-state"))
+    cmd_query_shutter_state (fp);
+  else if (!strcmp (cmd, "query-shutter-schedule"))
+    cmd_query_shutter_schedule (fp);
+  else if (!strcmp (cmd, "reset-shutter-eeprom"))
+    cmd_reset_shutter_eeprom (fp);
+  else if (!strcmp (cmd, "drive-shutter"))
+    cmd_drive_shutter (fp, cmdarg1);
+  else
+    err ("invalid command `%s'", cmd);
+
+
+  fclose (fp);
+  return any_error? 1:0;
+}
index b45ecff..648114f 100644 (file)
@@ -266,36 +266,6 @@ logmsg_time (unsigned int value, unsigned int decile)
 }
 
 
-/* Return the current ebus time for broadcasting.  The time is defined
-   as number of 10 second periods passed since Monday 0:00.  */
-static unsigned int
-mk_ebus_time (unsigned int *r_decile, unsigned int *r_dst)
-{
-  struct tm *tp;
-  time_t atime = time (NULL);
-  unsigned int result;
-
-  /* Get the local time and convert it to a Monday...Sunday week.  */
-  /* Fixme: We can't return fractions of a second.  Need to use
-     clock_gettime or wait for the full second.  */
-  tp = localtime (&atime);
-  if (!tp->tm_wday)
-    tp->tm_wday = 6;
-  else
-    tp->tm_wday--;
-
-  result = (tp->tm_wday * 24 * 60 * 6
-            + tp->tm_hour * 60 * 6
-            + tp->tm_min * 6 + tp->tm_sec/10);
-  if (r_decile)
-    *r_decile = (tp->tm_sec % 10) * 10;
-  if (r_dst)
-    *r_dst = !!tp->tm_isdst;
-  return result;
-}
-
-
-
 
 \f
 /* Process test messages.  */
@@ -341,6 +311,14 @@ p_busctl_time (byte *msg, size_t msglen, int have_decile)
 }
 
 
+static void
+p_busctl_version (byte *msg, size_t msglen)
+{
+  logmsg_fmt ("nodetype=%u rev=\"%.7s\"%s", msg[6], msg+8,
+              (msg[7] || msg[15])? "[reserved octets are not 0]":"");
+}
+
+
 /* Process busctl messages.  */
 static void
 process_ebus_busctl (byte *msg, size_t msglen)
@@ -366,6 +344,12 @@ process_ebus_busctl (byte *msg, size_t msglen)
         p_busctl_time (msg, msglen, 1);
       break;
 
+    case P_BUSCTL_QRY_VERSION:
+      logmsg_fmt ("%s:QueryVersion", is_response?"Rsp":"Cmd");
+      if (is_response)
+        p_busctl_version (msg, msglen);
+      break;
+
     default:
       logmsg_fmt ("%s:%02x", is_response?"Rsp":"Cmd", msg[5]);
       break;
@@ -415,6 +399,16 @@ p_h61_shutter_rsp (byte *msg, size_t msglen)
 {
   switch (msg[6])
     {
+    case P_H61_SHUTTER_QUERY:
+      logmsg_fmt ("QryState: err=%d state=%02x",
+                  msg[7], msg[8]);
+      if ((msg[8] & 0xc0) == 0xc0)
+        logmsg_fmt (" upwards");
+      if ((msg[8] & 0xc0) == 0x80)
+        logmsg_fmt (" downwards");
+      if ((msg[8] & 0x20))
+        logmsg_fmt (" %d%% closed", (msg[8] & 0x0f)*100/15);
+      break;
     case P_H61_SHUTTER_QRY_SCHEDULE:
       logmsg_fmt ("QrySchedule(%u): %u[%u] action 0x%02x ",
                   msg[7], msg[10], msg[9], msg[13]);
@@ -550,179 +544,6 @@ process (FILE *fp)
     }
 }
 
-/* Send out the raw byte C.  */
-static void
-send_byte_raw (FILE *fp, byte c)
-{
-  putc (c, fp);
-}
-
-
-/* Send byte C with byte stuffing.  */
-static void
-send_byte (FILE *fp, byte c)
-{
-  if (c == FRAMESYNCBYTE || c == FRAMEESCBYTE)
-    {
-      send_byte_raw (fp, FRAMEESCBYTE);
-      send_byte_raw (fp, (c ^ FRAMEESCMASK));
-    }
-  else
-    send_byte_raw (fp, c);
-}
-
-static void
-footest_1 (FILE *fp)
-{
-  byte msg[16];
-  unsigned int crc;
-  int idx;
-
-  msg[0] = PROTOCOL_EBUS_BUSCTL;
-  msg[1] = 0xff;
-  msg[2] = 0xff;
-  msg[3] = 0x01;
-  msg[4] = 0x01;
-  msg[5] = P_BUSCTL_QRY_TIME;
-  memset (msg+6, 0, 10);
-  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
-footest_2 (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_SHUTTER;
-  msg[6] = P_H61_SHUTTER_QRY_SCHEDULE;
-  msg[7] = 1;
-  memset (msg+8, 0, 8);
-  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
-footest_3 (FILE *fp)
-{
-  byte msg[16];
-  unsigned int crc;
-  int idx;
-  unsigned int tim, dec, dst;
-
-  tim = mk_ebus_time (&dec, &dst);
-  msg[0] = PROTOCOL_EBUS_BUSCTL;
-  msg[1] = 0xff;
-  msg[2] = 0xff;
-  msg[3] = 0x01;
-  msg[4] = 0x01;
-  msg[5] = P_BUSCTL_TIME;
-  msg[6] = 0x03;  /* Decile given, exact time */
-  if (dst)
-    msg[6] |= 0x04;
-  msg[7] = tim >> 8;
-  msg[8] = tim;
-  msg[9] = dec;
-  memset (msg+10, 0, 6);
-  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
-footest_4 (FILE *fp)
-{
-  byte msg[16];
-  unsigned int crc;
-  int idx;
-  unsigned char   item = 2;
-  unsigned int     tim = 3 * 60 * 6;
-  unsigned char action = 0x80;
-
-  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;
-  msg[10] = item;
-  msg[11] = tim >> 8;
-  msg[12] = tim;
-  msg[13] = action;
-  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
-send_reset_shutter_eeprom (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_SHUTTER;
-  msg[6] = P_H61_SHUTTER_UPD_SCHEDULE;
-  msg[7] = 0xf0;
-  msg[8] = 0;
-  msg[9] = 16;
-  msg[10] = 0xf0;
-  msg[11] = 0xf0;
-  msg[12] = 0xf0;
-  msg[13] = 0xf0;
-  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 int
@@ -744,7 +565,6 @@ int
 main (int argc, char **argv )
 {
   int last_argc = -1;
-  int testmode = 0;
   FILE *fp;
 
   if (argc)
@@ -787,15 +607,6 @@ main (int argc, char **argv )
           verbose = debug = 1;
           argc--; argv++;
         }
-      else if (!strcmp (*argv, "--test"))
-        {
-          argc--; argv++;
-          if (argc)
-            {
-              testmode = atoi (*argv);
-              argc--; argv++;
-            }
-        }
       else if (!strncmp (*argv, "--", 2))
         show_usage (1);
     }
@@ -806,15 +617,7 @@ main (int argc, char **argv )
   setvbuf (stdout, NULL, _IOLBF, 0);
 
   fp = open_line (*argv);
-  switch (testmode)
-    {
-    case 1: footest_1 (fp); break;
-    case 2: footest_2 (fp); break;
-    case 3: footest_3 (fp); break;
-    case 4: footest_4 (fp); break;
-    case 5: send_reset_shutter_eeprom (fp); break;
-    default: process (fp); break;
-    }
+  process (fp);
   fclose (fp);
 
   return any_error? 1:0;
index 4aee6a6..d546886 100644 (file)
@@ -216,7 +216,6 @@ ticker_bottom (unsigned int clock)
           /*                  | !~~!- Value: 0 = 0% closed
            *                  +------ State in bits 3..0 is valid.  */
           goto label_pre_off;
-          break;
 
         case motor_state_pre_down:
           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
@@ -235,12 +234,12 @@ ticker_bottom (unsigned int clock)
            *                +-------- Motor running.        */
           action_delay = 25000; /*ms*/
           state = motor_state_down_ready;
+          break;
         case motor_state_down_ready:
           shutter_state = 0b00101111;
           /*                  | !~~!--- Value: 15 = 100% closed
            *                  +-------- State in bits 3..0 is valid.  */
           goto label_pre_off;
-          break;
         }
     }
 
@@ -541,6 +540,19 @@ process_ebus_busctl (byte *msg)
       csma_send_message (msg, MSGSIZE);
       break;
 
+    case P_BUSCTL_QRY_VERSION:
+      msg[1] = msg[3];
+      msg[2] = msg[4];
+      msg[3] = config.nodeid_hi;
+      msg[4] = config.nodeid_lo;
+      msg[5] |= P_BUSCTL_RESPMASK;
+      msg[6] = eeprom_read_byte (&ee_data.nodetype);
+      msg[7] = 0;
+      memcpy_P (msg+8, PSTR (GIT_REVISION), 7);
+      msg[15] = 0;
+      csma_send_message (msg, MSGSIZE);
+      break;
+
     default:
       break;
     }