Merge branch 'vendor/XZ' into HEAD
[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  * $FreeBSD: src/libexec/xtend/packet.c,v 1.8 1999/08/28 00:10:30 peter Exp $
32  * $DragonFly: src/libexec/xtend/packet.c,v 1.2 2003/06/17 04:27:08 dillon Exp $
33  */
34
35 #include <stdio.h>
36 #include <sys/time.h>
37 #include "xtend.h"
38 #include "xten.h"
39
40 char *X10housenames[] = {
41   "A", "B", "C", "D", "E", "F", "G", "H",
42   "I", "J", "K", "L", "M", "N", "O", "P",
43   NULL
44 };
45
46 char *X10cmdnames[] = {
47   "1", "2", "3", "4", "5", "6", "7", "8",
48   "9", "10", "11", "12", "13", "14", "15", "16",
49   "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
50   "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
51   "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
52   NULL
53 };
54
55 /*
56  * Log a packet and update device status accordingly
57  */
58
59 void
60 logpacket(p)
61 unsigned char *p;
62 {
63   fprintf(Log, "%s:  %s %s ", thedate(),
64           X10housenames[p[1]], X10cmdnames[p[2]]);
65   if(p[0] & TW_RCV_LOCAL) fprintf(Log, "(loc,");
66   else fprintf(Log, "(rem,");
67   if(p[0] & TW_RCV_ERROR) fprintf(Log, "err)");
68   else fprintf(Log, " ok)");
69   fprintf(Log, "\n");
70 }
71
72 /*
73  * Process a received packet p, updating device status information both
74  * in core and on disk.
75  */
76
77 void
78 processpacket(p)
79 unsigned char *p;
80 {
81   int i, j, h, k;
82   STATUS *s;
83
84   /*
85    * If the packet had the error flag set, there is no other useful info.
86    */
87   if(p[0] & TW_RCV_ERROR) return;
88   /*
89    * First update in-core status information for the device.
90    */
91   h = p[1]; k = p[2];
92   if(k < 16) {  /* We received a unit code, to select a particular device */
93     s = &Status[h][k];
94     s->selected = SELECTED;
95     s->lastchange = time(NULL);
96     s->changed = 1;
97   } else {  /* We received a key code, to execute some function */
98     /*
99      * Change in status depends on the key code received
100      */
101     if(k == DIM) {
102       /*
103        * We can't really track DIM/BRIGHT properly the way things are right
104        * now.  The TW523 reports the first, fourth, seventh, etc. Dim packet.
105        * We don't really have any way to tell when gaps occur, to cancel
106        * selection.  For now, we'll assume that successive sequences of
107        * Dim/Bright commands are never transmitted without some other
108        * intervening command, and we make a good guess about how many units of
109        * dim/bright are represented by each packet actually reported by the
110        * TW523.
111        */
112       for(i = 0; i < 16; i++) {
113         s = &Status[h][i];
114         switch(s->selected) {
115         case SELECTED:  /* Selected, but not being dimmed or brightened */
116           if(s->onoff == 0) {
117             s->onoff = 1;
118             s->brightness = 15;
119           }
120           s->brightness -= 2;
121           if(s->brightness < 0) s->brightness = 0;
122           s->selected = DIMMING;
123           s->lastchange = time(NULL);
124           s->changed = 1;
125           break;
126         case DIMMING:  /* Selected and being dimmed */
127           s->brightness -=3;
128           if(s->brightness < 0) s->brightness = 0;
129           s->lastchange = time(NULL);
130           s->changed = 1;
131           break;
132         case BRIGHTENING:  /* Selected and being brightened (an error) */
133           s->selected = IDLE;
134           s->lastchange = time(NULL);
135           s->changed = 1;
136           break;
137         default:
138           break;
139         }
140       }
141     } else if(k == BRIGHT) {
142       /*
143        * Same problem here...
144        */
145       for(i = 0; i < 16; i++) {
146         s = &Status[h][i];
147         switch(s->selected) {
148         case SELECTED:  /* Selected, but not being dimmed or brightened */
149           if(s->onoff == 0) {
150             s->onoff = 1;
151             s->brightness = 15;
152           }
153           s->brightness += 2;
154           if(s->brightness > 15) s->brightness = 15;
155           s->selected = BRIGHTENING;
156           s->lastchange = time(NULL);
157           s->changed = 1;
158           break;
159         case DIMMING:  /* Selected and being dimmed (an error) */
160           s->selected = IDLE;
161           s->lastchange = time(NULL);
162           s->changed = 1;
163           break;
164         case BRIGHTENING:  /* Selected and being brightened */
165           s->brightness +=3;
166           if(s->brightness > 15) s->brightness = 15;
167           s->lastchange = time(NULL);
168           s->changed = 1;
169           break;
170         default:
171           break;
172         }
173       }
174     } else {  /* Other key codes besides Bright and Dim */
175       /*
176        * We cancel brightening and dimming on ALL units on ALL house codes,
177        * because the arrival of a different packet indicates a gap that
178        * terminates any prior sequence of brightening and dimming
179        */
180       for(j = 0; j < 16; j++) {
181         for(i = 0; i < 16; i++) {
182           s = &Status[j][i];
183           if(s->selected == BRIGHTENING || s->selected == DIMMING) {
184             s->selected = IDLE;
185             s->lastchange = time(NULL);
186             s->changed = 1;
187           }
188         }
189       }
190       switch(k) {
191       case ALLUNITSOFF:
192         for(i = 0; i < 16; i++) {
193           s = &Status[h][i];
194           s->onoff = 0;
195           s->selected = IDLE;
196           s->brightness = 0;
197           s->lastchange = time(NULL);
198           s->changed = 1;
199         }
200         break;
201       case ALLLIGHTSON:
202         /* Does AllLightsOn cancel selectedness of non-lights? */
203         for(i = 0; i < 16; i++) {
204           s = &Status[h][i];
205           if(s->devcap & ISLIGHT) {
206             s->onoff = 1;
207             s->selected = IDLE;
208             s->brightness = 15;
209             s->lastchange = time(NULL);
210             s->changed = 1;
211           }
212         }
213         break;
214       case UNITON:
215         for(i = 0; i < 16; i++) {
216           s = &Status[h][i];
217           if(s->selected == SELECTED) {
218             s->onoff = 1;
219             s->selected = IDLE;
220             s->brightness = 15;
221             s->lastchange = time(NULL);
222             s->changed = 1;
223           }
224         }
225         break;
226       case UNITOFF:
227         for(i = 0; i < 16; i++) {
228           s = &Status[h][i];
229           if(s->selected == SELECTED) {
230             s->onoff = 0;
231             s->selected = IDLE;
232             s->lastchange = time(NULL);
233             s->changed = 1;
234           }
235         }
236         break;
237       case ALLLIGHTSOFF:
238         /* Does AllLightsOff cancel selectedness of non-lights? */
239         for(i = 0; i < 16; i++) {
240           s = &Status[h][i];
241           if(s->devcap & ISLIGHT) {
242             s->onoff = 0;
243             s->selected = IDLE;
244             s->lastchange = time(NULL);
245             s->changed = 1;
246           }
247         }
248         break;
249       case EXTENDEDCODE:
250         break;
251       case HAILREQUEST:
252         for(i = 0; i < 16; i++) {
253           s = &Status[h][i];
254           if(s->selected == SELECTED) {
255             s->selected = HAILED;
256             s->lastchange = time(NULL);
257             s->changed = 1;
258           }
259         }
260         break;
261       case HAILACKNOWLEDGE:
262         /* Do these commands cancel selection of devices not affected? */
263         for(i = 0; i < 16; i++) {
264           s = &Status[h][i];
265           if(s->selected == HAILED) {
266             s->selected = IDLE;
267             s->lastchange = time(NULL);
268             s->changed = 1;
269           }
270         }
271         break;
272       case PRESETDIM0:
273       case PRESETDIM1:
274         /* I don't really understand these */
275         for(i = 0; i < 16; i++) {
276           s = &Status[h][i];
277           if(s->selected == SELECTED) {
278             s->selected = IDLE;
279             s->lastchange = time(NULL);
280             s->changed = 1;
281           }
282         }
283         break;
284       case EXTENDEDDATA:
285         /* Who knows?  The TW523 can't receive these anyway. */
286         break;
287       case STATUSON:
288         for(i = 0; i < 16; i++) {
289           s = &Status[h][i];
290           if(s->selected == REQUESTED) {
291             s->onoff = 1;
292             s->selected = IDLE;
293             s->lastchange = time(NULL);
294             s->changed = 1;
295           }
296         }
297         break;
298       case STATUSOFF:
299         for(i = 0; i < 16; i++) {
300           if(s->selected == REQUESTED) {
301             s = &Status[h][i];
302             s->onoff = 0;
303             s->selected = IDLE;
304             s->brightness = 0;
305             s->lastchange = time(NULL);
306             s->changed = 1;
307           }
308         }
309       case STATUSREQUEST:
310         for(i = 0; i < 16; i++) {
311           s = &Status[h][i];
312           if(s->selected) {
313             s->selected = REQUESTED;
314             s->lastchange = time(NULL);
315             s->changed = 1;
316           }
317         }
318         break;
319       }
320     }
321   }
322 }