diff options
Diffstat (limited to 'libexec/xtend/packet.c')
-rw-r--r-- | libexec/xtend/packet.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/libexec/xtend/packet.c b/libexec/xtend/packet.c new file mode 100644 index 0000000..bc75fcb --- /dev/null +++ b/libexec/xtend/packet.c @@ -0,0 +1,317 @@ +/*- + * Copyright (c) 1992, 1993 Eugene W. Stark + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eugene W. Stark. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <sys/time.h> +#include "xtend.h" +#include "xten.h" + +char *X10housenames[] = { + "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", + NULL +}; + +char *X10cmdnames[] = { + "1", "2", "3", "4", "5", "6", "7", "8", + "9", "10", "11", "12", "13", "14", "15", "16", + "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff", + "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1", + "ExtendedData", "StatusOn", "StatusOff", "StatusRequest", + NULL +}; + +/* + * Log a packet and update device status accordingly + */ + +logpacket(p) +unsigned char *p; +{ + fprintf(Log, "%s: %s %s ", thedate(), + X10housenames[p[1]], X10cmdnames[p[2]]); + if(p[0] & TW_RCV_LOCAL) fprintf(Log, "(loc,"); + else fprintf(Log, "(rem,"); + if(p[0] & TW_RCV_ERROR) fprintf(Log, "err)"); + else fprintf(Log, " ok)"); + fprintf(Log, "\n"); +} + +/* + * Process a received packet p, updating device status information both + * in core and on disk. + */ + +processpacket(p) +unsigned char *p; +{ + int i, j, h, k; + STATUS *s; + + /* + * If the packet had the error flag set, there is no other useful info. + */ + if(p[0] & TW_RCV_ERROR) return; + /* + * First update in-core status information for the device. + */ + h = p[1]; k = p[2]; + if(k < 16) { /* We received a unit code, to select a particular device */ + s = &Status[h][k]; + s->selected = SELECTED; + s->lastchange = time(NULL); + s->changed = 1; + } else { /* We received a key code, to execute some function */ + /* + * Change in status depends on the key code received + */ + if(k == DIM) { + /* + * We can't really track DIM/BRIGHT properly the way things are right + * now. The TW523 reports the first, fourth, seventh, etc. Dim packet. + * We don't really have any way to tell when gaps occur, to cancel + * selection. For now, we'll assume that successive sequences of + * Dim/Bright commands are never transmitted without some other + * intervening command, and we make a good guess about how many units of + * dim/bright are represented by each packet actually reported by the + * TW523. + */ + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + switch(s->selected) { + case SELECTED: /* Selected, but not being dimmed or brightened */ + if(s->onoff == 0) { + s->onoff = 1; + s->brightness = 15; + } + s->brightness -= 2; + if(s->brightness < 0) s->brightness = 0; + s->selected = DIMMING; + s->lastchange = time(NULL); + s->changed = 1; + break; + case DIMMING: /* Selected and being dimmed */ + s->brightness -=3; + if(s->brightness < 0) s->brightness = 0; + s->lastchange = time(NULL); + s->changed = 1; + break; + case BRIGHTENING: /* Selected and being brightened (an error) */ + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + break; + default: + break; + } + } + } else if(k == BRIGHT) { + /* + * Same problem here... + */ + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + switch(s->selected) { + case SELECTED: /* Selected, but not being dimmed or brightened */ + if(s->onoff == 0) { + s->onoff = 1; + s->brightness = 15; + } + s->brightness += 2; + if(s->brightness > 15) s->brightness = 15; + s->selected = BRIGHTENING; + s->lastchange = time(NULL); + s->changed = 1; + break; + case DIMMING: /* Selected and being dimmed (an error) */ + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + break; + case BRIGHTENING: /* Selected and being brightened */ + s->brightness +=3; + if(s->brightness > 15) s->brightness = 15; + s->lastchange = time(NULL); + s->changed = 1; + break; + default: + break; + } + } + } else { /* Other key codes besides Bright and Dim */ + /* + * We cancel brightening and dimming on ALL units on ALL house codes, + * because the arrival of a different packet indicates a gap that + * terminates any prior sequence of brightening and dimming + */ + for(j = 0; j < 16; j++) { + for(i = 0; i < 16; i++) { + s = &Status[j][i]; + if(s->selected == BRIGHTENING || s->selected == DIMMING) { + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + } + } + } + switch(k) { + case ALLUNITSOFF: + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + s->onoff = 0; + s->selected = IDLE; + s->brightness = 0; + s->lastchange = time(NULL); + s->changed = 1; + } + break; + case ALLLIGHTSON: + /* Does AllLightsOn cancel selectedness of non-lights? */ + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->devcap & ISLIGHT) { + s->onoff = 1; + s->selected = IDLE; + s->brightness = 15; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case UNITON: + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected == SELECTED) { + s->onoff = 1; + s->selected = IDLE; + s->brightness = 15; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case UNITOFF: + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected == SELECTED) { + s->onoff = 0; + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case ALLLIGHTSOFF: + /* Does AllLightsOff cancel selectedness of non-lights? */ + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->devcap & ISLIGHT) { + s->onoff = 0; + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case EXTENDEDCODE: + break; + case HAILREQUEST: + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected == SELECTED) { + s->selected = HAILED; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case HAILACKNOWLEDGE: + /* Do these commands cancel selection of devices not affected? */ + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected == HAILED) { + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case PRESETDIM0: + case PRESETDIM1: + /* I don't really understand these */ + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected == SELECTED) { + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case EXTENDEDDATA: + /* Who knows? The TW523 can't receive these anyway. */ + break; + case STATUSON: + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected == REQUESTED) { + s->onoff = 1; + s->selected = IDLE; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + case STATUSOFF: + for(i = 0; i < 16; i++) { + if(s->selected == REQUESTED) { + s = &Status[h][i]; + s->onoff = 0; + s->selected = IDLE; + s->brightness = 0; + s->lastchange = time(NULL); + s->changed = 1; + } + } + case STATUSREQUEST: + for(i = 0; i < 16; i++) { + s = &Status[h][i]; + if(s->selected) { + s->selected = REQUESTED; + s->lastchange = time(NULL); + s->changed = 1; + } + } + break; + } + } + } +} |