ebus: Add command to read the reset flags.
[wk-misc.git] / ebus / shutter.c
1 /* shutter.c - Elektor Bus node to control a shutter
2  * Copyright (C) 2011 g10 Code GmbH
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /* This node is used to control the shutter in a living room.  The
19    shutter is operator by a motor with two coils and limit switches
20    connected to a solid state relays which is controlled by this node.
21    A future version of this controller will also support some sensor
22    to allow pulling down the shutter only to some percentage.  In any
23    case the limit switches of the motor control the endpoints.  The
24    control logic takes down the relays after the time required to pull
25    the shutters up or down plus some extra time.  The S2 and S3
26    switches are used for manually controlling the shutter.  They are
27    interlocked and operate in a toggle on/off way.  The hardware
28    itself is also interlocked so that it is not possible to drive both
29    motors at the same time.
30
31    The used relays are FINDER 34.51.7.012.0010 which feature a high
32    sensitive coil (~18mA) and are able to switch 6A (the datasheet
33    even exlicitly allows motors of up to 185W).  The first relay is
34    used for direction selection with NC connected to the pull-up motor
35    and NO to the pull-down motor.  Our control logic makes sure that
36    this relay is not switched under load.  The second one connects its
37    NO to the first relay and a snubber circuit is used to protect its
38    contacts.  They are both connected to the 12V rail and flyback
39    diodes are used for each.  Two BC547 are used to drive them.
40
41    Historical note: A first version of the shutter rig and this
42    software used two (not interlocked) solid state relays made up from
43    S202S02 opto-triacs along with snubbers and varistors to cope with
44    the voltage peaks induced by the other motor.  However the spikes
45    were obviously too high and after some weeks the triacs bricked
46    themself.  A second try using S202S01s had the same effect.  Better
47    save your money and use mechanical relays.
48  */
49
50 #include "hardware.h"
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <avr/io.h>
56 #include <avr/interrupt.h>
57 #include <avr/sleep.h>
58 #include <avr/eeprom.h>
59 #include <util/crc16.h>  /* For _crc_ibutton_update.  */
60
61 #include "ebus.h"
62 #include "proto-busctl.h"
63 #include "proto-h61.h"
64
65
66 #define MOTOR_on       (PORTC)  /* Switch motor on.  */
67 #define MOTOR_on_BIT   (PC2)
68 #define MOTOR_down     (PORTC)  /* Switch direction relay to down.  */
69 #define MOTOR_down_BIT (PC3)
70
71
72 #define SCHEDULE_ACTION_NOP   0 /* No operation.  */
73 #define SCHEDULE_ACTION_UP    1 /* Minute + 10s := pull up  */
74 #define SCHEDULE_ACTION_DOWN  5 /* Minute + 50s := pull down  */
75
76
77 /* Allowed action values.  Note that the hardware interlocks both
78    motors.  However to avoid switch the direction under load we first
79    set the direction, wait a moment and then switch the motor on.  */
80 enum __attribute__ ((packed)) action_values {
81   action_none = 0,
82   action_up,
83   action_down,
84   action_up_key,
85   action_down_key
86 };
87
88 enum __attribute__ ((packed)) motor_state_values {
89   motor_state_off = 0,
90   motor_state_pre_off,
91   motor_state_pre_off2,
92   motor_state_pre_off3,
93   motor_state_pre_up,
94   motor_state_pre_up2,
95   motor_state_up,
96   motor_state_up_ready,
97   motor_state_pre_down,
98   motor_state_pre_down2,
99   motor_state_down,
100   motor_state_down_ready
101 };
102
103
104 \f
105 /*
106    Communication between ISR and main loop.
107  */
108
109 /* Event flag triggered (surprise) every second.  */
110 static volatile byte one_second_event;
111
112 /* Event flag trigger by key S2.  */
113 static volatile byte key_s2_event;
114
115 /* Event flag trigger by key S3.  */
116 static volatile byte key_s3_event;
117
118 /* The motor action delay counter and its event flag.  */
119 static volatile uint16_t motor_action_delay;
120 static volatile uint16_t motor_action_event;
121
122 /* Sensor action delay counter and its event flag.  */
123 static volatile uint16_t sensor_action_delay;
124 static volatile byte sensor_action_event;
125
126
127 \f
128 /*
129    Global state of the main loop.
130  */
131
132 /* Remember the last action time.  */
133 static uint16_t schedule_last_tfound;
134
135 /* The current state of the motor state machine.  */
136 static enum motor_state_values motor_state;
137
138 /* The shutter state byte.  This is directly used for the
139    QueryShutterState response message.  */
140 static byte shutter_state;
141
142 /* A structure to control the sensor actions.  This is not used by an
143    ISR thus no need for volatile.  */
144 static struct
145 {
146   /* If set a sensor read out has been requested.  The value gives the
147      number of read out tries left.  If it is down to zero an error
148      message will be returned.  */
149   byte active;
150   /* The address to send the response to.  If a second client requests
151      a readout, we won't record the address but broadcast th
152      result.  */
153   byte addr_hi;
154   byte addr_lo;
155 } sensor_ctrl;
156
157
158 \f
159 /* Local prototypes.  */
160 static void init_eeprom (byte force);
161
162
163
164 \f
165 /* This code is called by the 1ms ticker interrupt service routine
166    with the current clock value given in milliseconds from 0..9999. */
167 void
168 ticker_bottom (unsigned int clock)
169 {
170   if (!(clock % 1000))
171     {
172       one_second_event = 1;
173       wakeup_main = 1;
174     }
175
176   if (!key_s2_event && read_key_s2 ())
177     {
178       key_s2_event = 1;
179       wakeup_main = 1;
180     }
181
182   if (!key_s3_event && read_key_s3 ())
183     {
184       key_s3_event = 1;
185       wakeup_main = 1;
186     }
187
188   if (motor_action_delay && !--motor_action_delay)
189     {
190       motor_action_event = 1;
191       wakeup_main = 1;
192     }
193
194   if (sensor_action_delay && !--sensor_action_delay)
195     {
196       sensor_action_event = 1;
197       wakeup_main = 1;
198     }
199 }
200
201
202 static void
203 send_dbgmsg (const char *string)
204 {
205   byte msg[16];
206
207   if (config.debug_flags)
208     {
209       msg[0] = PROTOCOL_EBUS_DBGMSG;
210       msg[1] = config.nodeid_hi;
211       msg[2] = config.nodeid_lo;
212       memset (msg+3, 0, 13);
213       strncpy (msg+3, string, 13);
214       csma_send_message (msg, 16);
215     }
216 }
217
218
219 /* static void */
220 /* send_dbgmsg_fmt (const char *format, ...) */
221 /* { */
222 /*   va_list arg_ptr; */
223 /*   char buffer[16]; */
224
225 /*   va_start (arg_ptr, format); */
226 /*   vsnprintf (buffer, 16, format, arg_ptr); */
227 /*   va_end (arg_ptr); */
228 /*   send_dbgmsg (buffer); */
229 /* } */
230
231
232 /* Trigger a new motor action.  */
233 static void
234 trigger_action (enum action_values action)
235 {
236   static enum action_values last_action;
237
238  again:
239   switch (action)
240     {
241     case action_none: motor_state = motor_state_pre_off;  break;
242     case action_up:   motor_state = motor_state_pre_up;   break;
243     case action_down: motor_state = motor_state_pre_down; break;
244
245     case action_up_key:
246       action = last_action == action_up? action_none : action_up;
247       goto again;
248     case action_down_key:
249       action = last_action == action_down? action_none : action_down;
250       goto again;
251
252     default:
253       return;/* Avoid setting a new delay for unknown states.  */
254     }
255
256   last_action = action;
257
258   /* Now force a new transaction using the ticker interrupt.  We set
259      the delay to 1 ms so that the motor_action_event will be
260      triggered within the next millisecond.  There is no need to
261      disable interrupts; the worst what could happen is a double
262      triggered action and that action is anyway a motor off.  Using
263      this indirect method avoids a race between motor_action_delay and
264      motor_action_event.  */
265   motor_action_delay = 1;
266 }
267
268
269 /* The main state machine for the shutter motors.  The return value is
270    delay to be taken before the next call to this function.  */
271 static uint16_t
272 motor_action (void)
273 {
274   uint16_t newdelay;
275
276   /* Perform the state transitions.  */
277   do
278     {
279       newdelay = 0;
280       switch (motor_state)
281         {
282         case motor_state_off:
283           break;
284
285         case motor_state_pre_off:
286           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
287           newdelay = 200; /*ms*/
288           motor_state = motor_state_pre_off2;
289           break;
290         case motor_state_pre_off2:
291           MOTOR_down &= ~_BV(MOTOR_down_BIT);/* Switch direction relay off. */
292           newdelay = 200; /*ms*/
293           motor_state = motor_state_pre_off3;
294           break;
295         case motor_state_pre_off3:
296           LED_Collision &= ~_BV (LED_Collision_BIT); /* Clear LED.  */
297           /* Make sure the motor flags are cleared in the state info.  */
298           shutter_state &= 0b00111111;
299           motor_state = motor_state_off;
300           break;
301
302         case motor_state_pre_up:
303           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
304           newdelay = 200; /*ms*/
305           motor_state = motor_state_pre_up2;
306           break;
307         case motor_state_pre_up2:
308           MOTOR_down &= ~_BV(MOTOR_down_BIT);/* Switch direction relay off. */
309           newdelay = 200; /*ms*/
310           motor_state = motor_state_up;
311           break;
312         case motor_state_up:
313           MOTOR_on |= _BV(MOTOR_on_BIT);     /* Switch motor on. */
314           shutter_state = 0b11000000;
315           /*                |!------- Direction set to up
316            *                +-------- Motor running.        */
317           newdelay = 25000; /*ms*/
318           motor_state = motor_state_up_ready;
319           break;
320         case motor_state_up_ready:
321           shutter_state = 0b00100000;
322           /*                  | !~~!- Value: 0 = 0% closed
323            *                  +------ State in bits 3..0 is valid.  */
324           motor_state = motor_state_pre_off;
325           break;
326
327         case motor_state_pre_down:
328           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
329           newdelay = 200; /*ms*/
330           motor_state = motor_state_pre_down2;
331           break;
332         case motor_state_pre_down2:
333           MOTOR_down |= _BV(MOTOR_down_BIT); /* Switch direction relay on. */
334           newdelay = 200; /*ms*/
335           motor_state = motor_state_down;
336           break;
337         case motor_state_down:
338           MOTOR_on |= _BV(MOTOR_on_BIT);     /* Switch motor on. */
339           shutter_state = 0b10000000;
340           /*                |!------- Direction set to down
341            *                +-------- Motor running.        */
342           newdelay = 25000; /*ms*/
343           motor_state = motor_state_down_ready;
344           break;
345         case motor_state_down_ready:
346           shutter_state = 0b00101111;
347           /*                  | !~~!--- Value: 15 = 100% closed
348            *                  +-------- State in bits 3..0 is valid.  */
349           motor_state = motor_state_pre_off;
350           break;
351         }
352     }
353   while (!newdelay && motor_state != motor_state_off);
354
355   return newdelay;
356 }
357
358
359 /* Process scheduled actions.  TIME is the current time.  If
360    FORCED_TLOW is not 0 the scheduler will run the last action between
361    FORCED_TLOW and TIME regardless on whether it has already been run.
362    This feature is required to cope with a changed system time:
363    Consider the shutter shall be closed at 19:00, the current system
364    time is 18:59 and the system time is updated to 19:10 - without
365    that feature the closing at 19:00 would get lost.  */
366 static void
367 process_schedule (uint16_t time, uint16_t forced_tlow)
368 {
369   uint16_t tlow, thigh, t, tfound;
370   byte i;
371
372   if (!time_has_been_set)
373     return; /* Don't schedule while running without a valid clock.  */
374
375   if (schedule_last_tfound > time || forced_tlow)
376     schedule_last_tfound = 0;  /* Time wrapped to the next week or forced
377                                   schedule action.  */
378
379   /* We look up to 5 minutes back into the past to cope with lost events.  */
380   time /= 6;
381   time *= 6;
382   tlow = forced_tlow? forced_tlow : time;
383   if (tlow >= 5 * 6)
384     tlow -= 5 * 6;
385   else
386     tlow = 0;
387   if (schedule_last_tfound && schedule_last_tfound > tlow)
388     tlow = schedule_last_tfound;
389   thigh = time + 5;
390
391   /* send_dbgmsg_fmt ("time=%u", time); */
392   /* send_dbgmsg_fmt ("lst=%u", schedule_last_tfound); */
393   /* send_dbgmsg_fmt ("low=%u", tlow); */
394   /* send_dbgmsg_fmt ("hig=%u", thigh); */
395
396   /* Walk the schedule and find the last entry. */
397   for (tfound=0, i=0; i < DIM (ee_data.u.shutterctl.schedule); i++)
398     {
399       t = eeprom_read_word (&ee_data.u.shutterctl.schedule[i]);
400       if (!t)
401         break;
402       if (t > tlow && t <= thigh)
403         tfound = t;
404     }
405   if (tfound)
406     {
407       schedule_last_tfound = tfound;
408       /* send_dbgmsg_fmt ("fnd=%u", ((tfound/6)*6)); */
409       tfound %= 6;
410       /* send_dbgmsg_fmt ("act=%u", tfound); */
411       if (tfound == SCHEDULE_ACTION_UP)
412         {
413           send_dbgmsg ("sch-act up");
414           trigger_action (action_up);
415         }
416       else if (tfound == SCHEDULE_ACTION_DOWN)
417         {
418           send_dbgmsg ("sch-act dn");
419           trigger_action (action_down);
420         }
421
422     }
423 }
424
425
426 /* Process a shutter command.  */
427 static void
428 process_shutter_cmd (byte *msg)
429 {
430   uint16_t val16;
431   byte err = 0;
432
433   switch (msg[6])
434     {
435     case P_H61_SHUTTER_QUERY:
436       {
437         msg[1] = msg[3];
438         msg[2] = msg[4];
439         msg[3] = config.nodeid_hi;
440         msg[4] = config.nodeid_lo;
441         msg[5] |= P_BUSCTL_RESPMASK;
442
443         msg[7] = 0; /* No error.  */
444         msg[8] = shutter_state;
445         memset (msg+9, 0, 7);
446         csma_send_message (msg, MSGSIZE);
447       }
448       break;
449
450     case P_H61_SHUTTER_DRIVE:
451       {
452         if (msg[7] > 1 /* Only all shutters or shutter 1 are allowed.  */
453             || msg[9] || msg[10] || msg[11] || msg[12] || msg[13]
454             || msg[14] || msg[15] /* Reserved bytes are not zero.  */
455             || (msg[8] & 0x10)    /* Reserved bit is set.  */
456             || (msg[8] & 0x20)    /* Not yet supported.  */ )
457           err = 1;
458         else if ((msg[8] & 0xc0) == 0xc0)
459           {
460             send_dbgmsg ("bus-act up");
461             trigger_action (action_up);
462           }
463         else if ((msg[8] & 0xc0) == 0x80)
464           {
465             send_dbgmsg ("bus-act dn");
466             trigger_action (action_down);
467           }
468         else
469           err = 1;
470
471         msg[1] = msg[3];
472         msg[2] = msg[4];
473         msg[3] = config.nodeid_hi;
474         msg[4] = config.nodeid_lo;
475         msg[5] |= P_BUSCTL_RESPMASK;
476         msg[7] = err;
477         msg[8] = shutter_state;
478         memset (msg+9, 0, 7);
479         csma_send_message (msg, MSGSIZE);
480       }
481       break;
482
483     case P_H61_SHUTTER_QRY_TIMINGS:
484       break;
485
486     case P_H61_SHUTTER_UPD_TIMINGS:
487       break;
488
489     case P_H61_SHUTTER_QRY_SCHEDULE:
490       {
491         byte i;
492
493         msg[1] = msg[3];
494         msg[2] = msg[4];
495         msg[3] = config.nodeid_hi;
496         msg[4] = config.nodeid_lo;
497         msg[5] |= P_BUSCTL_RESPMASK;
498         msg[7] = 0; /* We only have a global schedule for now.  */
499         msg[8] = 0; /* No error.  */
500         for (i=0; i < DIM (ee_data.u.shutterctl.schedule); i++)
501           {
502             val16 = eeprom_read_word (&ee_data.u.shutterctl.schedule[i]);
503             switch ((val16 % 6))
504               {
505               case SCHEDULE_ACTION_UP:   msg[13] = 0b11000000; break;
506               case SCHEDULE_ACTION_DOWN: msg[13] = 0b10000000; break;
507               default: msg[13] = 0;  break; /* Undefined.  */
508               }
509             val16 /= 6;
510             val16 *= 6;
511             msg[9] = DIM (ee_data.u.shutterctl.schedule);
512             msg[10] = i;
513             msg[11] = val16 >> 8;
514             msg[12] = val16;
515             /* msg[13] already set.  */
516             msg[14] = 0;
517             msg[15] = 0;
518             csma_send_message (msg, MSGSIZE);
519           }
520       }
521       break;
522
523     case P_H61_SHUTTER_UPD_SCHEDULE:
524       if (msg[8] || msg[14] || msg[15] || msg[9] != 1
525           || msg[10] >= DIM (ee_data.u.shutterctl.schedule))
526         {
527           /* Bad message or eeprom reset  */
528           if (msg[7] == 0xf0 && msg[9] == 16 && msg[10] == 0xf0
529               && msg[11] == 0xf0 && msg[12] == 0xf0 && msg[13] == 0xf0)
530             {
531               init_eeprom (1);
532             }
533         }
534       else
535         {
536           /* Get time and round down to the full minute.  */
537           val16 = (msg[11] << 8) | msg[12];
538           val16 /= 6;
539           val16 *= 6;
540           /* Include the action.  Note that SCHEDULE_ACTION_NOP is the
541              default.  */
542           if (msg[13] == 0b11000000)
543             val16 += SCHEDULE_ACTION_UP;
544           else if (msg[13] == 0b10000000)
545             val16 += SCHEDULE_ACTION_DOWN;
546
547           eeprom_write_word (&ee_data.u.shutterctl.schedule[msg[10]], val16);
548         }
549       break;
550
551     default:
552       break;
553     }
554 }
555
556
557
558 /* Process a sensor command.  */
559 static void
560 process_sensor_cmd (byte *msg)
561 {
562   switch (msg[6])
563     {
564     case P_H61_SENSOR_TEMPERATURE:
565       if (sensor_ctrl.active)
566         {
567           /* A second client request, if it is a different one switch
568              to broadcast mode.  */
569           if (msg[3] != sensor_ctrl.addr_hi || msg[4] != sensor_ctrl.addr_lo)
570             {
571               sensor_ctrl.addr_hi = 0xff;
572               sensor_ctrl.addr_lo = 0xff;
573             }
574         }
575       else
576         {
577           sensor_ctrl.active = 5;    /* Number of tries.  */
578           sensor_ctrl.addr_hi = msg[3];
579           sensor_ctrl.addr_lo = msg[4];
580
581           /* Trigger the read out machinery.  */
582           onewire_enable ();
583           onewire_write_byte (0xcc); /* Skip ROM.  */
584           onewire_write_byte (0x44); /* Convert T.  */
585           /* Now we need to wait at least 750ms to read the value from
586              the scratchpad.  */
587           sensor_action_delay = 900; /* ms */
588           sensor_action_event = 0;
589       }
590       break;
591
592     default:
593       break;
594     }
595 }
596
597
598 /* Try to read the result from the sensor and send it back.  This
599    function shall be called at least 750ms after the first conversion
600    message.  */
601 static void
602 send_sensor_result (void)
603 {
604   byte i, crc;
605   int16_t t;
606   byte msg[16]; /* Used to read the scratchpad and to build the message.  */
607
608   if (!sensor_ctrl.active)
609     return;
610
611   onewire_enable ();         /* Reset */
612   onewire_write_byte (0xcc); /* Skip ROM.  */
613   onewire_write_byte (0xbe); /* Read scratchpad.  */
614   for (i=0; i < 9; i++)
615     msg[i] = onewire_read_byte ();
616
617   crc = 0;
618   for (i=0; i < 8; i++)
619     crc = _crc_ibutton_update (crc, msg[i]);
620
621   if (msg[8] == crc)
622     {
623       t = (msg[1] << 8) | msg[0];
624       t = (t*100 - 25 + ((16 - msg[6])*100 / 16)) / 20;
625     }
626   else
627     {
628       t = 0x7fff;  /* Read error */
629     }
630
631   if (t != 0x7fff || !--sensor_ctrl.active)
632     {
633       /* Success or read error with the counter at zero.  */
634       msg[0] = PROTOCOL_EBUS_H61;
635       msg[1] = sensor_ctrl.addr_hi;
636       msg[2] = sensor_ctrl.addr_lo;
637       msg[3] = config.nodeid_hi;
638       msg[4] = config.nodeid_lo;
639       msg[5] = (P_H61_SENSOR | P_H61_RESPMASK);
640       msg[6] = P_H61_SENSOR_TEMPERATURE;
641       msg[7] = (1 << 4 | 1); /* Group 1 of 1.  */
642       msg[8] = (t >> 8); /* Sensor no. 0.  */
643       msg[9] = t;
644       msg[10] = 0x80; /* No sensor no. 1.  */
645       msg[11] = 0;
646       msg[12] = 0x80; /* No sensor no. 2.  */
647       msg[13] = 0;
648       msg[14] = 0x80; /* No sensor no. 3.  */
649       msg[15] = 0;
650       csma_send_message (msg, MSGSIZE);
651
652       sensor_ctrl.active = 0;  /* Ready. */
653       onewire_disable ();
654     }
655   else
656     {
657       send_dbgmsg ("sens #4");
658       /* Better issue the read command again.  */
659       onewire_enable ();         /* Reset.     */
660       onewire_write_byte (0xcc); /* Skip ROM.  */
661       onewire_write_byte (0x44); /* Convert T. */
662       /* Try again ...  */
663       sensor_action_delay = 1100; /*ms*/
664       sensor_action_event = 0;
665     }
666 }
667
668
669
670 /* A new message has been received and we must now parse the message
671    quickly and see what to do.  We need to return as soon as possible,
672    so that the caller may re-enable the receiver.  */
673 static void
674 process_ebus_h61 (byte *msg)
675 {
676   char is_response = !!(msg[5] & P_H61_RESPMASK);
677
678   if (!(msg[1] == config.nodeid_hi && msg[2] == config.nodeid_lo))
679     return; /* Not addressed to us.  */
680
681   switch ((msg[5] & ~P_H61_RESPMASK))
682     {
683     case P_H61_SHUTTER:
684       if (!is_response)
685         process_shutter_cmd (msg);
686       break;
687
688     case P_H61_SENSOR:
689       if (!is_response)
690         process_sensor_cmd (msg);
691       break;
692
693     default:
694       break;
695     }
696 }
697
698
699 /* Process busctl messages.  */
700 static void
701 process_ebus_busctl (byte *msg)
702 {
703   uint16_t val16;
704   byte     val8;
705   char is_response = !!(msg[5] & P_BUSCTL_RESPMASK);
706
707   if (is_response)
708     return;  /* Nothing to do.  */
709   else if (msg[3] == 0xff || msg[4] == 0xff || msg[4] == 0)
710     return ; /* Bad sender address.  */
711   else if (msg[1] == config.nodeid_hi && msg[2] == config.nodeid_lo)
712     ; /* Directed to us.  */
713   else if ((msg[1] == config.nodeid_hi || msg[1] == 0xff) && msg[2] == 0xff)
714     ; /* Broadcast. */
715   else
716     return; /* Not addressed to us.  */
717
718   switch ((msg[5] & ~P_BUSCTL_RESPMASK))
719     {
720     case P_BUSCTL_TIME:
721       {
722         uint16_t t;
723
724         t = get_current_time ();
725         val16 = (msg[7] << 8) | msg[8];
726         val8  = (msg[6] & 0x02)? msg[9] : 0;
727         set_current_fulltime (val16, val8);
728         if (val16 > t)
729           process_schedule (val16, t);
730       }
731       break;
732
733     case P_BUSCTL_QRY_TIME:
734       msg[1] = msg[3];
735       msg[2] = msg[4];
736       msg[3] = config.nodeid_hi;
737       msg[4] = config.nodeid_lo;
738       msg[5] |= P_BUSCTL_RESPMASK;
739       msg[6] = 0; /* fixme: return an error for unknown shutter numbers.  */
740       val16 = get_current_fulltime (&val8);
741       msg[7] = val16 >> 8;
742       msg[8] = val16;
743       msg[9] = val8;
744       memset (msg+10, 0, 6);
745       csma_send_message (msg, MSGSIZE);
746       break;
747
748     case P_BUSCTL_QRY_VERSION:
749       msg[1] = msg[3];
750       msg[2] = msg[4];
751       msg[3] = config.nodeid_hi;
752       msg[4] = config.nodeid_lo;
753       msg[5] |= P_BUSCTL_RESPMASK;
754       msg[6] = eeprom_read_byte (&ee_data.nodetype);
755       msg[7] = 0;
756       memcpy_P (msg+8, PSTR (GIT_REVISION), 7);
757       msg[15] = 0;
758       csma_send_message (msg, MSGSIZE);
759       break;
760
761       /* FIXME: Better move this into hardware.c */
762     /* case P_BUSCTL_QRY_NAME: */
763     /*   msg[1] = msg[3]; */
764     /*   msg[2] = msg[4]; */
765     /*   msg[3] = config.nodeid_hi; */
766     /*   msg[4] = config.nodeid_lo; */
767     /*   msg[5] |= P_BUSCTL_RESPMASK; */
768     /*   msg[6] = eeprom_read_byte (&ee_data.nodetype); */
769     /*   msg[7] = 0; */
770     /*   eeprom_read_block (msg+8, config */
771     /*   memcpy_P (msg+8, PSTR (GIT_REVISION), 7); */
772     /*   msg[15] = 0; */
773     /*   csma_send_message (msg, MSGSIZE); */
774     /*   break; */
775
776     case P_BUSCTL_SET_DEBUG:
777       set_debug_flags (msg[6]);
778       break;
779
780     case P_BUSCTL_QRY_DEBUG:
781       msg[1] = msg[3];
782       msg[2] = msg[4];
783       msg[3] = config.nodeid_hi;
784       msg[4] = config.nodeid_lo;
785       msg[5] |= P_BUSCTL_RESPMASK;
786       msg[6] = config.debug_flags;
787       msg[7] = config.reset_flags;
788       memset (msg+8, 0, 8);
789       csma_send_message (msg, MSGSIZE);
790       break;
791
792     default:
793       break;
794     }
795 }
796
797
798
799 /* Init our eeprom data if needed. */
800 static void
801 init_eeprom (byte force)
802 {
803   uint16_t uptime, downtime;
804   byte i;
805
806   if (force || !eeprom_read_word (&ee_data.u.shutterctl.schedule[0]))
807     {
808       /* The schedule is empty - set up reasonable values for every
809          day of the week.  */
810       uptime = (7 * 60 + 30) * 6 + SCHEDULE_ACTION_UP;
811       downtime = (18 * 60 + 15) * 6 + SCHEDULE_ACTION_DOWN;
812       for (i=0; i < 7*2 && i < DIM (ee_data.u.shutterctl.schedule); i++)
813         {
814           if (i==6*2) /* Pull up on Sundays one hour later.  */
815             uptime += 60 * 6;
816           eeprom_write_word (&ee_data.u.shutterctl.schedule[i], uptime);
817           i++;
818           eeprom_write_word (&ee_data.u.shutterctl.schedule[i], downtime);
819           uptime += 24 * 60 * 6;
820           downtime += 24 * 60 * 6;
821         }
822       for (; i < DIM (ee_data.u.shutterctl.schedule); i++)
823         eeprom_write_word (&ee_data.u.shutterctl.schedule[i], 0);
824     }
825 }
826
827
828 /*
829     Entry point
830  */
831 int
832 main (void)
833 {
834   static int ten_seconds_counter;
835   byte *msg;
836
837   hardware_setup (NODETYPE_SHUTTER);
838   init_eeprom (0);
839
840   /* Port C configuration changes.  Configure motor ports for output
841      and switch them off. */
842   PORTC &= ~(_BV(MOTOR_down_BIT) | _BV(MOTOR_on_BIT));
843   DDRC  |= _BV(MOTOR_down_BIT) | _BV(MOTOR_on_BIT);
844
845   csma_setup ();
846   onewire_setup ();
847
848   sei (); /* Enable interrupts.  */
849
850   for (;;)
851     {
852       set_sleep_mode (SLEEP_MODE_IDLE);
853       while (!wakeup_main)
854         {
855           cli();
856           if (!wakeup_main)
857             {
858               sleep_enable ();
859               sei ();
860               sleep_cpu ();
861               sleep_disable ();
862             }
863           sei ();
864         }
865       wakeup_main = 0;
866
867       if (key_s2_event)
868         {
869           send_dbgmsg ("key-act down");
870           trigger_action (action_down_key);
871           key_s2_event = key_s3_event = 0;
872         }
873
874       if (key_s3_event)
875         {
876           send_dbgmsg ("key-act up");
877           trigger_action (action_up_key);
878           key_s3_event = 0;
879         }
880
881       if (motor_action_event)
882         {
883           motor_action_event = 0;
884           motor_action_delay = motor_action ();
885         }
886
887       if (sensor_action_event)
888         {
889           sensor_action_event = 0;
890           send_sensor_result ();
891         }
892
893       if (one_second_event)
894         {
895           one_second_event = 0;
896
897           /*
898              Code to run once a second.
899            */
900
901           /* Blink the activity LED if the motor is not in off state.  */
902           if (motor_state != motor_state_off)
903             {
904               if ((LED_Collision & _BV(LED_Collision_BIT)))
905                 LED_Collision &= ~_BV (LED_Collision_BIT);
906               else
907                 LED_Collision |= _BV(LED_Collision_BIT);
908             }
909
910
911           if (++ten_seconds_counter == 10)
912             {
913               /*
914                  Code to run once every 10 seconds.
915                */
916               uint16_t t;
917
918               ten_seconds_counter = 0;
919               t = get_current_time ();
920               if (!(t % 6))
921                 {
922                   /* Code to run every minute.  */
923                   process_schedule (t, 0);
924                 }
925             }
926         }
927
928
929       msg = csma_get_message ();
930       if (msg)
931         {
932           /* Process the message.  */
933           switch (msg[0])
934             {
935             case PROTOCOL_EBUS_BUSCTL:
936               process_ebus_busctl (msg);
937               break;
938             case PROTOCOL_EBUS_H61:
939               process_ebus_h61 (msg);
940               break;
941             default:
942               /* Ignore all other protocols.  */
943               break;
944             }
945           /* Re-enable the receiver.  */
946           csma_message_done ();
947         }
948     }
949
950 }