/*- * Copyright (c) 1992, 1993, 1995 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. * * $FreeBSD: src/libexec/xtend/packet.c,v 1.8 1999/08/28 00:10:30 peter Exp $ * $DragonFly: src/libexec/xtend/packet.c,v 1.2 2003/06/17 04:27:08 dillon Exp $ */ #include #include #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 */ void 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. */ void 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; } } } }