Initial import from FreeBSD RELENG_4:
[dragonfly.git] / libexec / xtend / packet.c
1 /*-
2  * Copyright (c) 1992, 1993, 1995 Eugene W. Stark
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Eugene W. Stark.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifndef lint
33 static const char rcsid[] =
34   "$FreeBSD: src/libexec/xtend/packet.c,v 1.8 1999/08/28 00:10:30 peter Exp $";
35 #endif /* not lint */
36
37 #include <stdio.h>
38 #include <sys/time.h>
39 #include "xtend.h"
40 #include "xten.h"
41
42 char *X10housenames[] = {
43   "A", "B", "C", "D", "E", "F", "G", "H",
44   "I", "J", "K", "L", "M", "N", "O", "P",
45   NULL
46 };
47
48 char *X10cmdnames[] = {
49   "1", "2", "3", "4", "5", "6", "7", "8",
50   "9", "10", "11", "12", "13", "14", "15", "16",
51   "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
52   "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
53   "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
54   NULL
55 };
56
57 /*
58  * Log a packet and update device status accordingly
59  */
60
61 void
62 logpacket(p)
63 unsigned char *p;
64 {
65   fprintf(Log, "%s:  %s %s ", thedate(),
66           X10housenames[p[1]], X10cmdnames[p[2]]);
67   if(p[0] & TW_RCV_LOCAL) fprintf(Log, "(loc,");
68   else fprintf(Log, "(rem,");
69   if(p[0] & TW_RCV_ERROR) fprintf(Log, "err)");
70   else fprintf(Log, " ok)");
71   fprintf(Log, "\n");
72 }
73
74 /*
75  * Process a received packet p, updating device status information both
76  * in core and on disk.
77  */
78
79 void
80 processpacket(p)
81 unsigned char *p;
82 {
83   int i, j, h, k;
84   STATUS *s;
85
86   /*
87    * If the packet had the error flag set, there is no other useful info.
88    */
89   if(p[0] & TW_RCV_ERROR) return;
90   /*
91    * First update in-core status information for the device.
92    */
93   h = p[1]; k = p[2];
94   if(k < 16) {  /* We received a unit code, to select a particular device */
95     s = &Status[h][k];
96     s->selected = SELECTED;
97     s->lastchange = time(NULL);
98     s->changed = 1;
99   } else {  /* We received a key code, to execute some function */
100     /*
101      * Change in status depends on the key code received
102      */
103     if(k == DIM) {
104       /*
105        * We can't really track DIM/BRIGHT properly the way things are right
106        * now.  The TW523 reports the first, fourth, seventh, etc. Dim packet.
107        * We don't really have any way to tell when gaps occur, to cancel
108        * selection.  For now, we'll assume that successive sequences of
109        * Dim/Bright commands are never transmitted without some other
110        * intervening command, and we make a good guess about how many units of
111        * dim/bright are represented by each packet actually reported by the
112        * TW523.
113        */
114       for(i = 0; i < 16; i++) {
115         s = &Status[h][i];
116         switch(s->selected) {
117         case SELECTED:  /* Selected, but not being dimmed or brightened */
118           if(s->onoff == 0) {
119             s->onoff = 1;
120             s->brightness = 15;
121           }
122           s->brightness -= 2;
123           if(s->brightness < 0) s->brightness = 0;
124           s->selected = DIMMING;
125           s->lastchange = time(NULL);
126           s->changed = 1;
127           break;
128         case DIMMING:  /* Selected and being dimmed */
129           s->brightness -=3;
130           if(s->brightness < 0) s->brightness = 0;
131           s->lastchange = time(NULL);
132           s->changed = 1;
133           break;
134         case BRIGHTENING:  /* Selected and being brightened (an error) */
135           s->selected = IDLE;
136           s->lastchange = time(NULL);
137           s->changed = 1;
138           break;
139         default:
140           break;
141         }
142       }
143     } else if(k == BRIGHT) {
144       /*
145        * Same problem here...
146        */
147       for(i = 0; i < 16; i++) {
148         s = &Status[h][i];
149         switch(s->selected) {
150         case SELECTED:  /* Selected, but not being dimmed or brightened */
151           if(s->onoff == 0) {
152             s->onoff = 1;
153             s->brightness = 15;
154           }
155           s->brightness += 2;
156           if(s->brightness > 15) s->brightness = 15;
157           s->selected = BRIGHTENING;
158           s->lastchange = time(NULL);
159           s->changed = 1;
160           break;
161         case DIMMING:  /* Selected and being dimmed (an error) */
162           s->selected = IDLE;
163           s->lastchange = time(NULL);
164           s->changed = 1;
165           break;
166         case BRIGHTENING:  /* Selected and being brightened */
167           s->brightness +=3;
168           if(s->brightness > 15) s->brightness = 15;
169           s->lastchange = time(NULL);
170           s->changed = 1;
171           break;
172         default:
173           break;
174         }
175       }
176     } else {  /* Other key codes besides Bright and Dim */
177       /*
178        * We cancel brightening and dimming on ALL units on ALL house codes,
179        * because the arrival of a different packet indicates a gap that
180        * terminates any prior sequence of brightening and dimming
181        */
182       for(j = 0; j < 16; j++) {
183         for(i = 0; i < 16; i++) {
184           s = &Status[j][i];
185           if(s->selected == BRIGHTENING || s->selected == DIMMING) {
186             s->selected = IDLE;
187             s->lastchange = time(NULL);
188             s->changed = 1;
189           }
190         }
191       }
192       switch(k) {
193       case ALLUNITSOFF:
194         for(i = 0; i < 16; i++) {
195           s = &Status[h][i];
196           s->onoff = 0;
197           s->selected = IDLE;
198           s->brightness = 0;
199           s->lastchange = time(NULL);
200           s->changed = 1;
201         }
202         break;
203       case ALLLIGHTSON:
204         /* Does AllLightsOn cancel selectedness of non-lights? */
205         for(i = 0; i < 16; i++) {
206           s = &Status[h][i];
207           if(s->devcap & ISLIGHT) {
208             s->onoff = 1;
209             s->selected = IDLE;
210             s->brightness = 15;
211             s->lastchange = time(NULL);
212             s->changed = 1;
213           }
214         }
215         break;
216       case UNITON:
217         for(i = 0; i < 16; i++) {
218           s = &Status[h][i];
219           if(s->selected == SELECTED) {
220             s->onoff = 1;
221             s->selected = IDLE;
222             s->brightness = 15;
223             s->lastchange = time(NULL);
224             s->changed = 1;
225           }
226         }
227         break;
228       case UNITOFF:
229         for(i = 0; i < 16; i++) {
230           s = &Status[h][i];
231           if(s->selected == SELECTED) {
232             s->onoff = 0;
233             s->selected = IDLE;
234             s->lastchange = time(NULL);
235             s->changed = 1;
236           }
237         }
238         break;
239       case ALLLIGHTSOFF:
240         /* Does AllLightsOff cancel selectedness of non-lights? */
241         for(i = 0; i < 16; i++) {
242           s = &Status[h][i];
243           if(s->devcap & ISLIGHT) {
244             s->onoff = 0;
245             s->selected = IDLE;
246             s->lastchange = time(NULL);
247             s->changed = 1;
248           }
249         }
250         break;
251       case EXTENDEDCODE:
252         break;
253       case HAILREQUEST:
254         for(i = 0; i < 16; i++) {
255           s = &Status[h][i];
256           if(s->selected == SELECTED) {
257             s->selected = HAILED;
258             s->lastchange = time(NULL);
259             s->changed = 1;
260           }
261         }
262         break;
263       case HAILACKNOWLEDGE:
264         /* Do these commands cancel selection of devices not affected? */
265         for(i = 0; i < 16; i++) {
266           s = &Status[h][i];
267           if(s->selected == HAILED) {
268             s->selected = IDLE;
269             s->lastchange = time(NULL);
270             s->changed = 1;
271           }
272         }
273         break;
274       case PRESETDIM0:
275       case PRESETDIM1:
276         /* I don't really understand these */
277         for(i = 0; i < 16; i++) {
278           s = &Status[h][i];
279           if(s->selected == SELECTED) {
280             s->selected = IDLE;
281             s->lastchange = time(NULL);
282             s->changed = 1;
283           }
284         }
285         break;
286       case EXTENDEDDATA:
287         /* Who knows?  The TW523 can't receive these anyway. */
288         break;
289       case STATUSON:
290         for(i = 0; i < 16; i++) {
291           s = &Status[h][i];
292           if(s->selected == REQUESTED) {
293             s->onoff = 1;
294             s->selected = IDLE;
295             s->lastchange = time(NULL);
296             s->changed = 1;
297           }
298         }
299         break;
300       case STATUSOFF:
301         for(i = 0; i < 16; i++) {
302           if(s->selected == REQUESTED) {
303             s = &Status[h][i];
304             s->onoff = 0;
305             s->selected = IDLE;
306             s->brightness = 0;
307             s->lastchange = time(NULL);
308             s->changed = 1;
309           }
310         }
311       case STATUSREQUEST:
312         for(i = 0; i < 16; i++) {
313           s = &Status[h][i];
314           if(s->selected) {
315             s->selected = REQUESTED;
316             s->lastchange = time(NULL);
317             s->changed = 1;
318           }
319         }
320         break;
321       }
322     }
323   }
324 }