ebus: Switch to a 10ms ticker
[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 10ms ticker interrupt service routine
166    with the current clock value given in 10 millisecond increments
167    from 0..999. */
168 void
169 ticker_bottom (unsigned int clock)
170 {
171   if (!(clock % 100))
172     {
173       one_second_event = 1;
174       wakeup_main = 1;
175     }
176
177   if (!key_s2_event && read_key_s2 ())
178     {
179       key_s2_event = 1;
180       wakeup_main = 1;
181     }
182
183   if (!key_s3_event && read_key_s3 ())
184     {
185       key_s3_event = 1;
186       wakeup_main = 1;
187     }
188
189   if (motor_action_delay && !--motor_action_delay)
190     {
191       motor_action_event = 1;
192       wakeup_main = 1;
193     }
194
195   if (sensor_action_delay && !--sensor_action_delay)
196     {
197       sensor_action_event = 1;
198       wakeup_main = 1;
199     }
200 }
201
202
203 static void
204 send_dbgmsg (const char *string)
205 {
206   byte msg[16];
207
208   if (config.debug_flags)
209     {
210       msg[0] = PROTOCOL_EBUS_DBGMSG;
211       msg[1] = config.nodeid_hi;
212       msg[2] = config.nodeid_lo;
213       memset (msg+3, 0, 13);
214       strncpy (msg+3, string, 13);
215       csma_send_message (msg, 16);
216     }
217 }
218
219
220 /* static void */
221 /* send_dbgmsg_fmt (const char *format, ...) */
222 /* { */
223 /*   va_list arg_ptr; */
224 /*   char buffer[16]; */
225
226 /*   va_start (arg_ptr, format); */
227 /*   vsnprintf (buffer, 16, format, arg_ptr); */
228 /*   va_end (arg_ptr); */
229 /*   send_dbgmsg (buffer); */
230 /* } */
231
232
233 /* Trigger a new motor action.  */
234 static void
235 trigger_action (enum action_values action)
236 {
237   static enum action_values last_action;
238
239  again:
240   switch (action)
241     {
242     case action_none: motor_state = motor_state_pre_off;  break;
243     case action_up:   motor_state = motor_state_pre_up;   break;
244     case action_down: motor_state = motor_state_pre_down; break;
245
246     case action_up_key:
247       action = last_action == action_up? action_none : action_up;
248       goto again;
249     case action_down_key:
250       action = last_action == action_down? action_none : action_down;
251       goto again;
252
253     default:
254       return;/* Avoid setting a new delay for unknown states.  */
255     }
256
257   last_action = action;
258
259   /* Now force a new transaction using the ticker interrupt.  We set
260      the delay to 10 ms so that the motor_action_event will be
261      triggered within the next 10 milliseconds.  There is no need to
262      disable interrupts; the worst what could happen is a double
263      triggered action and that action is anyway a motor off.  Using
264      this indirect method avoids a race between motor_action_delay and
265      motor_action_event.  */
266   motor_action_delay = 1;
267 }
268
269
270 /* The main state machine for the shutter motors.  The return value is
271    delay to be taken before the next call to this function.  */
272 static uint16_t
273 motor_action (void)
274 {
275   uint16_t newdelay;
276
277   /* Perform the state transitions.  */
278   do
279     {
280       newdelay = 0;
281       switch (motor_state)
282         {
283         case motor_state_off:
284           break;
285
286         case motor_state_pre_off:
287           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
288           newdelay = MILLISEC (200);
289           motor_state = motor_state_pre_off2;
290           break;
291         case motor_state_pre_off2:
292           MOTOR_down &= ~_BV(MOTOR_down_BIT);/* Switch direction relay off. */
293           newdelay = MILLISEC (200);
294           motor_state = motor_state_pre_off3;
295           break;
296         case motor_state_pre_off3:
297           LED_Collision &= ~_BV (LED_Collision_BIT); /* Clear LED.  */
298           /* Make sure the motor flags are cleared in the state info.  */
299           shutter_state &= 0b00111111;
300           motor_state = motor_state_off;
301           break;
302
303         case motor_state_pre_up:
304           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
305           newdelay = MILLISEC (200);
306           motor_state = motor_state_pre_up2;
307           break;
308         case motor_state_pre_up2:
309           MOTOR_down &= ~_BV(MOTOR_down_BIT);/* Switch direction relay off. */
310           newdelay = MILLISEC (200);
311           motor_state = motor_state_up;
312           break;
313         case motor_state_up:
314           MOTOR_on |= _BV(MOTOR_on_BIT);     /* Switch motor on. */
315           shutter_state = 0b11000000;
316           /*                |!------- Direction set to up
317            *                +-------- Motor running.        */
318           newdelay = MILLISEC (25000);
319           motor_state = motor_state_up_ready;
320           break;
321         case motor_state_up_ready:
322           shutter_state = 0b00100000;
323           /*                  | !~~!- Value: 0 = 0% closed
324            *                  +------ State in bits 3..0 is valid.  */
325           motor_state = motor_state_pre_off;
326           break;
327
328         case motor_state_pre_down:
329           MOTOR_on &= ~_BV(MOTOR_on_BIT);    /* Switch motor off. */
330           newdelay = MILLISEC (200);
331           motor_state = motor_state_pre_down2;
332           break;
333         case motor_state_pre_down2:
334           MOTOR_down |= _BV(MOTOR_down_BIT); /* Switch direction relay on. */
335           newdelay = MILLISEC (200);
336           motor_state = motor_state_down;
337           break;
338         case motor_state_down:
339           MOTOR_on |= _BV(MOTOR_on_BIT);     /* Switch motor on. */
340           shutter_state = 0b10000000;
341           /*                |!------- Direction set to down
342            *                +-------- Motor running.        */
343           newdelay = MILLISEC (25000);
344           motor_state = motor_state_down_ready;
345           break;
346         case motor_state_down_ready:
347           shutter_state = 0b00101111;
348           /*                  | !~~!--- Value: 15 = 100% closed
349            *                  +-------- State in bits 3..0 is valid.  */
350           motor_state = motor_state_pre_off;
351           break;
352         }
353     }
354   while (!newdelay && motor_state != motor_state_off);
355
356   return newdelay;
357 }
358
359
360 /* Process scheduled actions.  TIME is the current time.  If
361    FORCED_TLOW is not 0 the scheduler will run the last action between
362    FORCED_TLOW and TIME regardless on whether it has already been run.
363    This feature is required to cope with a changed system time:
364    Consider the shutter shall be closed at 19:00, the current system
365    time is 18:59 and the system time is updated to 19:10 - without
366    that feature the closing at 19:00 would get lost.  */
367 static void
368 process_schedule (uint16_t time, uint16_t forced_tlow)
369 {
370   uint16_t tlow, thigh, t, tfound;
371   byte i;
372
373   if (!time_has_been_set)
374     return; /* Don't schedule while running without a valid clock.  */
375
376   if (schedule_last_tfound > time || forced_tlow)
377     schedule_last_tfound = 0;  /* Time wrapped to the next week or forced
378                                   schedule action.  */
379
380   /* We look up to 5 minutes back into the past to cope with lost events.  */
381   time /= 6;
382   time *= 6;
383   tlow = forced_tlow? forced_tlow : time;
384   if (tlow >= 5 * 6)
385     tlow -= 5 * 6;
386   else
387     tlow = 0;
388   if (schedule_last_tfound && schedule_last_tfound > tlow)
389     tlow = schedule_last_tfound;
390   thigh = time + 5;
391
392   /* send_dbgmsg_fmt ("time=%u", time); */
393   /* send_dbgmsg_fmt ("lst=%u", schedule_last_tfound); */
394   /* send_dbgmsg_fmt ("low=%u", tlow); */
395   /* send_dbgmsg_fmt ("hig=%u", thigh); */
396
397   /* Walk the schedule and find the last entry. */
398   for (tfound=0, i=0; i < DIM (ee_data.u.shutterctl.schedule); i++)
399     {
400       t = eeprom_read_word (&ee_data.u.shutterctl.schedule[i]);
401       if (!t)
402         break;
403       if (t > tlow && t <= thigh)
404         tfound = t;
405     }
406   if (tfound)
407     {
408       schedule_last_tfound = tfound;
409       /* send_dbgmsg_fmt ("fnd=%u", ((tfound/6)*6)); */
410       tfound %= 6;
411       /* send_dbgmsg_fmt ("act=%u", tfound); */
412       if (tfound == SCHEDULE_ACTION_UP)
413         {
414           send_dbgmsg ("sch-act up");
415           trigger_action (action_up);
416         }
417       else if (tfound == SCHEDULE_ACTION_DOWN)
418         {
419           send_dbgmsg ("sch-act dn");
420           trigger_action (action_down);
421         }
422
423     }
424 }
425
426
427 /* Process a shutter command.  */
428 static void
429 process_shutter_cmd (byte *msg)
430 {
431   uint16_t val16;
432   byte err = 0;
433
434   switch (msg[6])
435     {
436     case P_H61_SHUTTER_QUERY:
437       {
438         msg[1] = msg[3];
439         msg[2] = msg[4];
440         msg[3] = config.nodeid_hi;
441         msg[4] = config.nodeid_lo;
442         msg[5] |= P_BUSCTL_RESPMASK;
443
444         msg[7] = 0; /* No error.  */
445         msg[8] = shutter_state;
446         memset (msg+9, 0, 7);
447         csma_send_message (msg, MSGSIZE);
448       }
449       break;
450
451     case P_H61_SHUTTER_DRIVE:
452       {
453         if (msg[7] > 1 /* Only all shutters or shutter 1 are allowed.  */
454             || msg[9] || msg[10] || msg[11] || msg[12] || msg[13]
455             || msg[14] || msg[15] /* Reserved bytes are not zero.  */
456             || (msg[8] & 0x10)    /* Reserved bit is set.  */
457             || (msg[8] & 0x20)    /* Not yet supported.  */ )
458           err = 1;
459         else if ((msg[8] & 0xc0) == 0xc0)
460           {
461             send_dbgmsg ("bus-act up");
462             trigger_action (action_up);
463           }
464         else if ((msg[8] & 0xc0) == 0x80)
465           {
466             send_dbgmsg ("bus-act dn");
467             trigger_action (action_down);
468           }
469         else
470           err = 1;
471
472         msg[1] = msg[3];
473         msg[2] = msg[4];
474         msg[3] = config.nodeid_hi;
475         msg[4] = config.nodeid_lo;
476         msg[5] |= P_BUSCTL_RESPMASK;
477         msg[7] = err;
478         msg[8] = shutter_state;
479         memset (msg+9, 0, 7);
480         csma_send_message (msg, MSGSIZE);
481       }
482       break;
483
484     case P_H61_SHUTTER_QRY_TIMINGS:
485       break;
486
487     case P_H61_SHUTTER_UPD_TIMINGS:
488       break;
489
490     case P_H61_SHUTTER_QRY_SCHEDULE:
491       {
492         byte i;
493
494         msg[1] = msg[3];
495         msg[2] = msg[4];
496         msg[3] = config.nodeid_hi;
497         msg[4] = config.nodeid_lo;
498         msg[5] |= P_BUSCTL_RESPMASK;
499         msg[7] = 0; /* We only have a global schedule for now.  */
500         msg[8] = 0; /* No error.  */
501         for (i=0; i < DIM (ee_data.u.shutterctl.schedule); i++)
502           {
503             val16 = eeprom_read_word (&ee_data.u.shutterctl.schedule[i]);
504             switch ((val16 % 6))
505               {
506               case SCHEDULE_ACTION_UP:   msg[13] = 0b11000000; break;
507               case SCHEDULE_ACTION_DOWN: msg[13] = 0b10000000; break;
508               default: msg[13] = 0;  break; /* Undefined.  */
509               }
510             val16 /= 6;
511             val16 *= 6;
512             msg[9] = DIM (ee_data.u.shutterctl.schedule);
513             msg[10] = i;
514             msg[11] = val16 >> 8;
515             msg[12] = val16;
516             /* msg[13] already set.  */
517             msg[14] = 0;
518             msg[15] = 0;
519             csma_send_message (msg, MSGSIZE);
520           }
521       }
522       break;
523
524     case P_H61_SHUTTER_UPD_SCHEDULE:
525       if (msg[8] || msg[14] || msg[15] || msg[9] != 1
526           || msg[10] >= DIM (ee_data.u.shutterctl.schedule))
527         {
528           /* Bad message or eeprom reset  */
529           if (msg[7] == 0xf0 && msg[9] == 16 && msg[10] == 0xf0
530               && msg[11] == 0xf0 && msg[12] == 0xf0 && msg[13] == 0xf0)
531             {
532               init_eeprom (1);
533             }
534         }
535       else
536         {
537           /* Get time and round down to the full minute.  */
538           val16 = (msg[11] << 8) | msg[12];
539           val16 /= 6;
540           val16 *= 6;
541           /* Include the action.  Note that SCHEDULE_ACTION_NOP is the
542              default.  */
543           if (msg[13] == 0b11000000)
544             val16 += SCHEDULE_ACTION_UP;
545           else if (msg[13] == 0b10000000)
546             val16 += SCHEDULE_ACTION_DOWN;
547
548           eeprom_write_word (&ee_data.u.shutterctl.schedule[msg[10]], val16);
549         }
550       break;
551
552     default:
553       break;
554     }
555 }
556
557
558
559 /* Process a sensor command.  */
560 static void
561 process_sensor_cmd (byte *msg)
562 {
563   switch (msg[6])
564     {
565     case P_H61_SENSOR_TEMPERATURE:
566       if (sensor_ctrl.active)
567         {
568           /* A second client request, if it is a different one switch
569              to broadcast mode.  */
570           if (msg[3] != sensor_ctrl.addr_hi || msg[4] != sensor_ctrl.addr_lo)
571             {
572               sensor_ctrl.addr_hi = 0xff;
573               sensor_ctrl.addr_lo = 0xff;
574             }
575         }
576       else
577         {
578           sensor_ctrl.active = 5;    /* Number of tries.  */
579           sensor_ctrl.addr_hi = msg[3];
580           sensor_ctrl.addr_lo = msg[4];
581
582           /* Trigger the read out machinery.  */
583           onewire_enable ();
584           onewire_write_byte (0xcc); /* Skip ROM.  */
585           onewire_write_byte (0x44); /* Convert T.  */
586           /* Now we need to wait at least 750ms to read the value from
587              the scratchpad.  */
588           sensor_action_delay = MILLISEC (900);
589           sensor_action_event = 0;
590       }
591       break;
592
593     default:
594       break;
595     }
596 }
597
598
599 /* Try to read the result from the sensor and send it back.  This
600    function shall be called at least 750ms after the first conversion
601    message.  */
602 static void
603 send_sensor_result (void)
604 {
605   byte i, crc;
606   int16_t t;
607   byte msg[16]; /* Used to read the scratchpad and to build the message.  */
608
609   if (!sensor_ctrl.active)
610     return;
611
612   onewire_enable ();         /* Reset */
613   onewire_write_byte (0xcc); /* Skip ROM.  */
614   onewire_write_byte (0xbe); /* Read scratchpad.  */
615   for (i=0; i < 9; i++)
616     msg[i] = onewire_read_byte ();
617
618   crc = 0;
619   for (i=0; i < 8; i++)
620     crc = _crc_ibutton_update (crc, msg[i]);
621
622   if (msg[8] == crc)
623     {
624       t = (msg[1] << 8) | msg[0];
625       t = (t*100 - 25 + ((16 - msg[6])*100 / 16)) / 20;
626     }
627   else
628     {
629       t = 0x7fff;  /* Read error */
630     }
631
632   if (t != 0x7fff || !--sensor_ctrl.active)
633     {
634       /* Success or read error with the counter at zero.  */
635       msg[0] = PROTOCOL_EBUS_H61;
636       msg[1] = sensor_ctrl.addr_hi;
637       msg[2] = sensor_ctrl.addr_lo;
638       msg[3] = config.nodeid_hi;
639       msg[4] = config.nodeid_lo;
640       msg[5] = (P_H61_SENSOR | P_H61_RESPMASK);
641       msg[6] = P_H61_SENSOR_TEMPERATURE;
642       msg[7] = (1 << 4 | 1); /* Group 1 of 1.  */
643       msg[8] = (t >> 8); /* Sensor no. 0.  */
644       msg[9] = t;
645       msg[10] = 0x80; /* No sensor no. 1.  */
646       msg[11] = 0;
647       msg[12] = 0x80; /* No sensor no. 2.  */
648       msg[13] = 0;
649       msg[14] = 0x80; /* No sensor no. 3.  */
650       msg[15] = 0;
651       csma_send_message (msg, MSGSIZE);
652
653       sensor_ctrl.active = 0;  /* Ready. */
654       onewire_disable ();
655     }
656   else
657     {
658       send_dbgmsg ("sens #4");
659       /* Better issue the read command again.  */
660       onewire_enable ();         /* Reset.     */
661       onewire_write_byte (0xcc); /* Skip ROM.  */
662       onewire_write_byte (0x44); /* Convert T. */
663       /* Try again ...  */
664       sensor_action_delay = MILLISEC (1100);
665       sensor_action_event = 0;
666     }
667 }
668
669
670
671 /* A new message has been received and we must now parse the message
672    quickly and see what to do.  We need to return as soon as possible,
673    so that the caller may re-enable the receiver.  */
674 static void
675 process_ebus_h61 (byte *msg)
676 {
677   char is_response = !!(msg[5] & P_H61_RESPMASK);
678
679   if (!(msg[1] == config.nodeid_hi && msg[2] == config.nodeid_lo))
680     return; /* Not addressed to us.  */
681
682   switch ((msg[5] & ~P_H61_RESPMASK))
683     {
684     case P_H61_SHUTTER:
685       if (!is_response)
686         process_shutter_cmd (msg);
687       break;
688
689     case P_H61_SENSOR:
690       if (!is_response)
691         process_sensor_cmd (msg);
692       break;
693
694     default:
695       break;
696     }
697 }
698
699
700 /* Process busctl messages.  */
701 static void
702 process_ebus_busctl (byte *msg)
703 {
704   uint16_t val16;
705   byte     val8;
706   char is_response = !!(msg[5] & P_BUSCTL_RESPMASK);
707
708   if (is_response)
709     return;  /* Nothing to do.  */
710   else if (msg[3] == 0xff || msg[4] == 0xff || msg[4] == 0)
711     return ; /* Bad sender address.  */
712   else if (msg[1] == config.nodeid_hi && msg[2] == config.nodeid_lo)
713     ; /* Directed to us.  */
714   else if ((msg[1] == config.nodeid_hi || msg[1] == 0xff) && msg[2] == 0xff)
715     ; /* Broadcast. */
716   else
717     return; /* Not addressed to us.  */
718
719   switch ((msg[5] & ~P_BUSCTL_RESPMASK))
720     {
721     case P_BUSCTL_TIME:
722       {
723         uint16_t t;
724
725         t = get_current_time ();
726         val16 = (msg[7] << 8) | msg[8];
727         val8  = (msg[6] & 0x02)? msg[9] : 0;
728         set_current_fulltime (val16, val8);
729         if (val16 > t)
730           process_schedule (val16, t);
731       }
732       break;
733
734     case P_BUSCTL_QRY_TIME:
735       msg[1] = msg[3];
736       msg[2] = msg[4];
737       msg[3] = config.nodeid_hi;
738       msg[4] = config.nodeid_lo;
739       msg[5] |= P_BUSCTL_RESPMASK;
740       msg[6] = 0; /* fixme: return an error for unknown shutter numbers.  */
741       val16 = get_current_fulltime (&val8);
742       msg[7] = val16 >> 8;
743       msg[8] = val16;
744       msg[9] = val8;
745       memset (msg+10, 0, 6);
746       csma_send_message (msg, MSGSIZE);
747       break;
748
749     case P_BUSCTL_QRY_VERSION:
750       msg[1] = msg[3];
751       msg[2] = msg[4];
752       msg[3] = config.nodeid_hi;
753       msg[4] = config.nodeid_lo;
754       msg[5] |= P_BUSCTL_RESPMASK;
755       msg[6] = eeprom_read_byte (&ee_data.nodetype);
756       msg[7] = 0;
757       memcpy_P (msg+8, PSTR (GIT_REVISION), 7);
758       msg[15] = 0;
759       csma_send_message (msg, MSGSIZE);
760       break;
761
762       /* FIXME: Better move this into hardware.c */
763     /* case P_BUSCTL_QRY_NAME: */
764     /*   msg[1] = msg[3]; */
765     /*   msg[2] = msg[4]; */
766     /*   msg[3] = config.nodeid_hi; */
767     /*   msg[4] = config.nodeid_lo; */
768     /*   msg[5] |= P_BUSCTL_RESPMASK; */
769     /*   msg[6] = eeprom_read_byte (&ee_data.nodetype); */
770     /*   msg[7] = 0; */
771     /*   eeprom_read_block (msg+8, config */
772     /*   memcpy_P (msg+8, PSTR (GIT_REVISION), 7); */
773     /*   msg[15] = 0; */
774     /*   csma_send_message (msg, MSGSIZE); */
775     /*   break; */
776
777     case P_BUSCTL_SET_DEBUG:
778       set_debug_flags (msg[6]);
779       break;
780
781     case P_BUSCTL_QRY_DEBUG:
782       msg[1] = msg[3];
783       msg[2] = msg[4];
784       msg[3] = config.nodeid_hi;
785       msg[4] = config.nodeid_lo;
786       msg[5] |= P_BUSCTL_RESPMASK;
787       msg[6] = config.debug_flags;
788       msg[7] = config.reset_flags;
789       memset (msg+8, 0, 8);
790       csma_send_message (msg, MSGSIZE);
791       break;
792
793     default:
794       break;
795     }
796 }
797
798
799
800 /* Init our eeprom data if needed. */
801 static void
802 init_eeprom (byte force)
803 {
804   uint16_t uptime, downtime;
805   byte i;
806
807   if (force || !eeprom_read_word (&ee_data.u.shutterctl.schedule[0]))
808     {
809       /* The schedule is empty - set up reasonable values for every
810          day of the week.  */
811       uptime = (7 * 60 + 30) * 6 + SCHEDULE_ACTION_UP;
812       downtime = (18 * 60 + 15) * 6 + SCHEDULE_ACTION_DOWN;
813       for (i=0; i < 7*2 && i < DIM (ee_data.u.shutterctl.schedule); i++)
814         {
815           if (i==6*2) /* Pull up on Sundays one hour later.  */
816             uptime += 60 * 6;
817           eeprom_write_word (&ee_data.u.shutterctl.schedule[i], uptime);
818           i++;
819           eeprom_write_word (&ee_data.u.shutterctl.schedule[i], downtime);
820           uptime += 24 * 60 * 6;
821           downtime += 24 * 60 * 6;
822         }
823       for (; i < DIM (ee_data.u.shutterctl.schedule); i++)
824         eeprom_write_word (&ee_data.u.shutterctl.schedule[i], 0);
825     }
826 }
827
828
829 /*
830     Entry point
831  */
832 int
833 main (void)
834 {
835   static int ten_seconds_counter;
836   byte *msg;
837
838   hardware_setup (NODETYPE_SHUTTER);
839   init_eeprom (0);
840
841   /* Port C configuration changes.  Configure motor ports for output
842      and switch them off. */
843   PORTC &= ~(_BV(MOTOR_down_BIT) | _BV(MOTOR_on_BIT));
844   DDRC  |= _BV(MOTOR_down_BIT) | _BV(MOTOR_on_BIT);
845
846   csma_setup ();
847   onewire_setup ();
848
849   sei (); /* Enable interrupts.  */
850
851   for (;;)
852     {
853       set_sleep_mode (SLEEP_MODE_IDLE);
854       while (!wakeup_main)
855         {
856           cli();
857           if (!wakeup_main)
858             {
859               sleep_enable ();
860               sei ();
861               sleep_cpu ();
862               sleep_disable ();
863             }
864           sei ();
865         }
866       wakeup_main = 0;
867
868       if (key_s2_event)
869         {
870           send_dbgmsg ("key-act down");
871           trigger_action (action_down_key);
872           key_s2_event = key_s3_event = 0;
873         }
874
875       if (key_s3_event)
876         {
877           send_dbgmsg ("key-act up");
878           trigger_action (action_up_key);
879           key_s3_event = 0;
880         }
881
882       if (motor_action_event)
883         {
884           motor_action_event = 0;
885           motor_action_delay = motor_action ();
886         }
887
888       if (sensor_action_event)
889         {
890           sensor_action_event = 0;
891           send_sensor_result ();
892         }
893
894       if (one_second_event)
895         {
896           one_second_event = 0;
897
898           /*
899              Code to run once a second.
900            */
901
902           /* Blink the activity LED if the motor is not in off state.  */
903           if (motor_state != motor_state_off)
904             {
905               if ((LED_Collision & _BV(LED_Collision_BIT)))
906                 LED_Collision &= ~_BV (LED_Collision_BIT);
907               else
908                 LED_Collision |= _BV(LED_Collision_BIT);
909             }
910
911
912           if (++ten_seconds_counter == 10)
913             {
914               /*
915                  Code to run once every 10 seconds.
916                */
917               uint16_t t;
918
919               ten_seconds_counter = 0;
920               t = get_current_time ();
921               if (!(t % 6))
922                 {
923                   /* Code to run every minute.  */
924                   process_schedule (t, 0);
925                 }
926             }
927         }
928
929
930       msg = csma_get_message ();
931       if (msg)
932         {
933           /* Process the message.  */
934           switch (msg[0])
935             {
936             case PROTOCOL_EBUS_BUSCTL:
937               process_ebus_busctl (msg);
938               break;
939             case PROTOCOL_EBUS_H61:
940               process_ebus_h61 (msg);
941               break;
942             default:
943               /* Ignore all other protocols.  */
944               break;
945             }
946           /* Re-enable the receiver.  */
947           csma_message_done ();
948         }
949     }
950
951 }