/*----------------------------------------------------------------------------+ | | | X10 Module Attributes for HEYU | | Copyright 2004-2007 Charles W. Sullivan | | All Rights Reserved | | | | | | This software is licensed free of charge for non-commercial distribution | | and for personal and internal business use only. Inclusion of this | | software or any part thereof in a commercial product is prohibited | | without the prior written permission of the author. You may copy, use, | | and distribute this software subject to the following restrictions: | | | | 1) You may not charge money for it. | | 2) You may not remove or alter this license, copyright notice, or the | | included disclaimers. | | 3) You may not claim you wrote it. | | 4) If you make improvements (or other changes), you are requested | | to send them to the Heyu maintainer so there's a focal point for | | distributing improved versions. | | | | As used herein, HEYU is a trademark of Daniel B. Suthers. | | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc. | | SwitchLinc and LampLinc are trademarks of Smarthome, Inc. | | The author is not affiliated with any of these entities. | | | | Charles W. Sullivan | | Co-author and Maintainer | | Greensboro, North Carolina | | Email ID: cwsulliv01 | | Email domain: -at- heyu -dot- org | | | | Disclaimers: | | THERE IS NO ASSURANCE THAT THIS SOFTWARE IS FREE OF DEFECTS AND IT MUST | | NOT BE USED IN ANY SITUATION WHERE THERE IS ANY CHANCE THAT ITS | | PERFORMANCE OR FAILURE TO PERFORM AS EXPECTED COULD RESULT IN LOSS OF | | LIFE, INJURY TO PERSONS OR PROPERTY, FINANCIAL LOSS, OR LEGAL LIABILITY. | | | | TO THE EXTENT ALLOWED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED "AS IS",| | WITH NO EXPRESS OR IMPLIED WARRANTY, INCLUDING, BUT NOT LIMITED TO, THE | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.| | | | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL THE AUTHOR BE LIABLE | | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL | | DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THIS SOFTWARE EVEN IF | | THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | | | +----------------------------------------------------------------------------*/ #include #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD) #include #else #include #endif #include #include "process.h" /* Standard module attribute/response definitions for cflags */ /* Basic function codes 0-6 (maintain this order) */ #define UNOFF 0x00000001 /* All Units Off */ #define LION 0x00000002 /* All Lights ON */ #define MON 0x00000004 /* Simple module ON */ #define MOFF 0x00000008 /* Simple module OFF */ #define DIM 0x00000010 /* Dim 1-22 */ #define BRI 0x00000020 /* Bright 1-22 */ #define LIOFF 0x00000040 /* All Lights OFF */ /* Other attributes */ #define ALLON 0x00000080 /* All Units On */ #define STDX10 0x00000100 /* Standard X10 */ #define PRESET 0x00000200 /* Preset 1-32 */ #define BRIB4DIM 0x00000400 /* If OFF, full Brightness before dimming */ #define STAREQ 0x00000800 /* Responds to Status Request */ #define STAON 0x00001000 /* Sends StatusOn ack */ #define STAOFF 0x00002000 /* Sends StatusOff ack */ #define LIONFULL 0x00004000 /* All Lights ON -> Full brightness */ #define ONFULL 0x00008000 /* ON -> Full (or option) brightness */ #define ONFULLOFF 0x00010000 /* ON -> Full brightness if Off */ #define RESUME 0x00020000 /* ON resumes previous level */ #define RESUMEDIM 0x00040000 /* Dim/Bright first resumes previous level */ #define LIONUNAD 0x00080000 /* AllLightsOn unaddresses the module */ #define LIOFFUNAD 0x00100000 /* AllLightsOff unaddresses the module */ #define TARG 0x00200000 /* Is a target instead of a module */ #define EXC16 0x00400000 /* Last unit turns On (all others turn off) */ #define EXC8 0x00800000 /* Last unit turns On (others in group of 8 turn off) */ #define EXC4 0x01000000 /* Last unit turns On and others in group of 4 turn off) */ #define VDATA 0x02000000 /* Virtual data repository */ /* NOTE: Attributes STDX10, PRESET, and EXT3SW/EXT3DIM are */ /* mutually incompatible. */ /* Extended code module attributes for xflags */ /* (Group reference characteristic types are mutually incompatible.) */ #define XNON 0 #define X3SW 0x00000001 /* Extended codes Type 3 (switch only) */ #define X3DIM 0x00000002 /* Extended codes Type 3 with preset dim 0-63 */ #define X0SH 0x00000004 /* Extended code Type 0 shutter control */ #define X3GEXEC 0x00000008 /* Supports Extended Group Exec command */ #define X3GRC1 0x00000010 /* Group reference characteristic Type 1 (LM14A, AM14A) */ #define X3GRC2 0x00000020 /* Group reference characteristic Type 2 (LM465-1) */ #define X3GRC3 0x00000040 /* Group reference characteristic Type 3 (WS467-1) */ #define X3GRC4 0x00000080 /* Group reference characteristic Type 4 */ #define X3GOFF 0x00000100 /* Extended Group Off */ #define X3GOFFEX 0x00000200 /* Extended Group Off acts like Group Exec */ #define X3GBD 0x00000400 /* Extended Group Bright/Dim */ #define X3GBDFULL 0x00000800 /* Ext Grp Bri/Dim resumes, or brightens full if prev at level 0 */ #define X3STAT 0x00001000 /* Extended code status, i.e., 2-way */ /* Virtual model attributes for vflags */ #define VNON 0 #define VSTD 0x00000001 /* X10 Standard */ #define VENT 0x00000002 /* X10 Entertainment */ #define VSEC 0x00000004 /* X10 Security */ /* Module max dim levels */ #define MXL0 0 #define MXLS 210 /* Standard X10 modules 0-210 */ #define MXLP 31 /* Preset modules 0-31 (zero-base) */ #define MXLE 62 /* Extended code Type 3 dimmer modules 0-62 */ #define MXLEA 63 /* Extended code Type 3 appliance modules 0,63 */ #define MXLS0 25 /* Extended code Type 0 shutters 0-25 */ #define MXLV 255 /* Virtual modules 0-255 */ /* Standard module type attributes for cflags . To add a new module type, */ /* "OR" together its attributes here and add an entry in the modules */ /* table below. (Keep the table uncluttered, for future additions.) */ #define NOMATT 0 #define BASIC (UNOFF | MON | MOFF | ALLON) #define STDAM (BASIC | STDX10) #define STDLM (STDAM | DIM | BRI | BRIB4DIM | LION | ONFULLOFF) #define STDWS (STDLM | LIOFF) #define AMS (STDAM | STAON | STAOFF | STAREQ) #define LMS (STDLM | STAON | STAOFF | STAREQ) #define SIREN (STDAM | LION ) #define REM2 (STDX10 | TARG | MON | MOFF) #define REM3 (STDX10 | TARG | MOFF | BRI | DIM) #define REM4 (STDX10 | TARG | MON | MOFF | BRI | DIM) #define REM6 (STDX10 | TARG | MON | MOFF | BRI | DIM | LION | UNOFF) #define LM15A (STDAM | LION | LIONFULL | LIOFF | LIONUNAD | LIOFFUNAD) #define XPS3 (STDAM | LION | LIONFULL | LIOFF) #define XPD3 (STDLM | LIOFF) #define PR511 (STDAM | STAON | STAOFF | STAREQ | LION | LIONFULL | LIOFF) #define AM14A (BASIC | ALLON | STAON | STAOFF | STAREQ) #define LM14A (AM14A | DIM | BRI | LION | LIOFF | RESUME | RESUMEDIM | LIOFFUNAD) #define SL1AM (BASIC) #define SL2AM (SL1AM | STAREQ) #define SL1LM (BASIC | PRESET | DIM | BRI | LION | LIOFF | ONFULL) #define SL2LM (SL1LM | STAREQ) #define LL1LM (BASIC | PRESET | DIM | BRI | LION | LIOFF | LIONFULL | ONFULL) #define LL2LM (LL1LM | STAREQ) #define AMEXC16 (STDAM | EXC16) #define AMEXC8 (STDAM | EXC8 ) #define AMEXC4 (STDAM | EXC4 ) #define CAMEXC4 (STDX10 | EXC4 | MON | MOFF) #define VIRT4 (TARG | MON | MOFF | BRI | DIM) #define SHUT0 (MON | MOFF | RESUME) #define VIRTUAL (TARG | VDATA) #define PALMPAD (TARG | MON | MOFF | BRI | DIM) #define KEYCHAIN (TARG | MON | MOFF) #define ONLYON (TARG | MON) #define ONLYOFF (TARG | MOFF) #define LM_1 (BASIC | DIM | BRI | LION | LIOFF | RESUMEDIM | LIOFFUNAD) #define WS_1 (BASIC | DIM | BRI | LION | RESUME) /* Extended module type attributes for xflags */ #define XAM14A (X3SW | X3GEXEC | X3GRC1 | X3GOFFEX | X3STAT) #define XLM14A (X3SW | X3GEXEC | X3DIM | X3GRC1 | X3GOFFEX | X3STAT) #define XLM_1 (X3SW | X3GEXEC | X3DIM | X3GRC2 | X3GOFF | X3GBD | X3GBDFULL) #define XWS_1 (X3SW | X3GEXEC | X3DIM | X3GRC3 | X3GOFFEX) #define XSHUT0 (X0SH) /* Module option functions */ int opt_onlevel(), opt_sremote(), opt_sensor(), opt_ds90(), opt_ur81a(), opt_ux17a(), opt_guru(), opt_aux(); /* Decoder functions for security and entertainment modules */ int fn_ds10a(), fn_ds90(), fn_ms10a(), fn_sh624(), fn_kr10a(), fn_ur81a(), fn_guru(); struct modules_st { char *label; /* Case insensitive */ int maxlevel; unsigned long vflags; /* Virtual attributes */ unsigned long cflags; /* Standard attributes */ unsigned long xflags; /* Extended code attributes */ int (*addopt_func)(); int (*xlate_func)(); } modules[] = { {"NONE", MXLS, VNON, NOMATT, 0, NULL, NULL }, /* Has no attributes */ {"StdAM", MXLS, VNON, STDAM, 0, NULL, NULL }, /* Standard X10 1-way Appliance Module */ {"AM", MXLS, VNON, STDAM, 0, NULL, NULL }, /* Standard X10 1-way Appliance Module */ {"AM486", MXLS, VNON, STDAM, 0, NULL, NULL }, /* Standard X10 1-way Appliance Module */ {"AMS", MXLS, VNON, AMS, 0, NULL, NULL }, /* 2-way Appliance Module */ {"RR501", MXLS, VNON, AMS, 0, NULL, NULL }, /* X10 Transceiver/Switch */ {"StdLM", MXLS, VNON, STDLM, 0, NULL, NULL }, /* Standard X10 1-way Lamp Module */ {"LM", MXLS, VNON, STDLM, 0, NULL, NULL }, /* Standard X10 1-way Lamp Module */ {"LM465", MXLS, VNON, STDLM, 0, NULL, NULL }, /* Standard X10 1-way Lamp Module */ {"LM465-1", MXLE, VNON, LM_1, XLM_1, NULL, NULL }, /* Redesigned (2007) X10 1-way Lamp Module */ {"LM-1", MXLE, VNON, LM_1, XLM_1, NULL, NULL }, /* Redesigned (2007) X10 1-way Lamp Module */ {"PLM03", MXLS, VNON, STDLM, 0, NULL, NULL }, /* Standard X10 1-way Lamp Module */ {"StdWS", MXLS, VNON, STDWS, 0, NULL, NULL }, /* Standard X10 1-way Lamp Wall Switch */ {"WS", MXLS, VNON, STDWS, 0, NULL, NULL }, /* Standard X10 1-way Lamp Wall Switch */ {"WS467", MXLS, VNON, STDWS, 0, NULL, NULL }, /* Standard X10 1-way Lamp Wall Switch */ {"WS467-1", MXLE, VNON, WS_1, XWS_1, NULL, NULL }, /* Redesigned (2007) X10 1-way Lamp Wall Switch */ {"WS-1", MXLE, VNON, WS_1, XWS_1, NULL, NULL }, /* Redesigned (2007) X10 1-way Lamp Wall Switch */ {"XPD3", MXLS, VNON, XPD3, 0, NULL, NULL }, /* X10 Pro 1-way Lamp Wall Switch */ {"XPS3", MXLS, VNON, XPS3, 0, NULL, NULL }, /* X10 Pro 1-way non-dimming Wall Switch */ {"LM15A", MXLS, VNON, LM15A, 0, NULL, NULL }, /* X10 LM15A Socket Rocket */ {"LMS", MXLS, VNON, LMS, 0, NULL, NULL }, /* 2-way Lamp Module */ {"PR511", MXLS, VNON, PR511, 0, NULL, NULL }, /* X10 2-way Motion Sensor floodlight */ {"AM14A", MXLEA, VNON, AM14A, XAM14A, NULL, NULL }, /* X10 2-way Appliance Module, 2-pin (AM14A) */ {"AM15A", MXLEA, VNON, AM14A, XAM14A, NULL, NULL }, /* X10 2-way Appliance Module, 3-pin (AM15A) */ {"PAM22", MXLEA, VNON, AM14A, XAM14A, NULL, NULL }, /* X10 2-way Appliance Module, 3-pin (AM15A) */ {"LM14A", MXLE, VNON, LM14A, XLM14A, NULL, NULL }, /* X10 2-way Lamp Module (LM14A) */ {"PLM21", MXLE, VNON, LM14A, XLM14A, NULL, NULL }, /* X10 2-way Lamp Module (LM14A) */ {"SL1AM", MXLP, VNON, SL1AM, 0, NULL, NULL }, /* SwitchLinc 1-way Switch */ {"SL2AM", MXLP, VNON, SL2AM, 0, NULL, NULL }, /* SwitchLinc 2-way Switch */ {"SL1LM", MXLP, VNON, SL1LM, 0, opt_onlevel, NULL }, /* SwitchLinc 1-way Lamp Module */ {"SL2LM", MXLP, VNON, SL2LM, 0, opt_onlevel, NULL }, /* SwitchLinc 2-way Lamp Module */ {"SL2380W", MXLP, VNON, SL2LM, 0, opt_onlevel, NULL }, /* SwitchLinc 2380W Dimmer */ {"LL1LM", MXLP, VNON, LL1LM, 0, opt_onlevel, NULL }, /* LampLinc 1-way Dimmer */ {"LL2LM", MXLP, VNON, LL2LM, 0, opt_onlevel, NULL }, /* LampLink 2-way Dimmer */ {"LL2000STW", MXLP, VNON, LL2LM, 0, opt_onlevel, NULL }, /* LampLinc 2000STW Dimmer */ {"REMOTE2", MXLS, VNON, REM2, 0, NULL, NULL }, /* Remote transmitter, 2 function */ {"REMOTE3", MXLS, VNON, REM3, 0, NULL, NULL }, /* Remote transmitter, 3 function */ {"REMOTE4", MXLS, VNON, REM4, 0, NULL, NULL }, /* Remote transmitter, 4 function */ {"REMOTE6", MXLS, VNON, REM6, 0, NULL, NULL }, /* Remote transmitter, 6 function */ {"REMOTEP", MXLP, VNON, PRESET, 0, NULL, NULL }, /* Remote transmitter, Preset 1-32 only */ {"AMEXC", MXLS, VNON, AMEXC16, 0, NULL, NULL }, /* AM with exclusive-16 addressing */ {"AMEXC16", MXLS, VNON, AMEXC16, 0, NULL, NULL }, /* AM with exclusive addressing */ {"AMEXC8", MXLS, VNON, AMEXC8, 0, NULL, NULL }, /* AM with exclusive-8 addressing */ {"RAIN8", MXLS, VNON, AMEXC8, 0, NULL, NULL }, /* WGL Rain8 irrigation controller */ {"AMEXC4", MXLS, VNON, AMEXC4, 0, NULL, NULL }, /* AM with exclusive-4 addressing */ {"XM10A", MXLS, VNON, CAMEXC4, 0, NULL, NULL }, /* X10 camera power supply */ {"XM13A", MXLS, VNON, CAMEXC4, 0, NULL, NULL }, /* X10 camera power supply */ {"XM14A", MXLS, VNON, CAMEXC4, 0, NULL, NULL }, /* X10 pan/tilt power supply */ {"VIRT4", MXLV, VSTD, VIRT4, 0, opt_onlevel, NULL }, /* Virtual module, 4 function */ {"VDATA", MXLV, VSTD, VIRTUAL, 0, NULL, NULL }, /* Virtual module data */ #ifdef HASEXT0 {"SHUTTER", MXLS0, VNON, SHUT0, XSHUT0, NULL, NULL }, /* Extended code Type 0 shutter */ {"SW10", MXLS0, VNON, SHUT0, XSHUT0, NULL, NULL }, /* Marmitek SW10 shutter control */ #endif {"DS10A", MXLV, VSEC, VIRTUAL, 0, opt_sensor, fn_ds10a }, {"DS90", MXLV, VSEC, VIRTUAL, 0, opt_ds90, fn_ds90 }, {"MS10A", MXLV, VSEC, VIRTUAL, 0, opt_sensor, fn_ms10a }, {"SH624", MXLV, VSEC, VIRTUAL, 0, opt_sremote, fn_sh624 }, {"KR10A", MXLV, VSEC, VIRTUAL, 0, opt_sremote, fn_kr10a }, {"UR81A", MXLV, VENT, VIRTUAL, 0, opt_ur81a, fn_ur81a }, {"UX17A", MXLV, VENT, VIRTUAL, 0, opt_ux17a, NULL }, {"GURU", MXLV, VENT, VIRTUAL, 0, opt_guru, fn_guru }, {"PALMPAD", MXLS, VSTD, PALMPAD, 0, opt_aux, NULL}, {"HR12A", MXLS, VSTD, PALMPAD, 0, opt_aux, NULL}, {"KEYCHAIN", MXLS, VSTD, KEYCHAIN, 0, opt_aux, NULL}, {"KC624", MXLS, VSTD, KEYCHAIN, 0, opt_aux, NULL}, {"ONLYON", MXLS, VSTD, ONLYON, 0, opt_aux, NULL}, {"ONLYOFF", MXLS, VSTD, ONLYOFF, 0, opt_aux, NULL}, }; static int ntypes = (sizeof(modules)/sizeof(struct modules_st)); unsigned int modmask[NumModMasks][16]; unsigned int vmodmask[NumModMasks][16]; unsigned char maxdimlevel[16][16]; unsigned char ondimlevel[16][16]; extern CONFIG config; extern CONFIG *configp; /*-------------------------------------------------------+ | Return a pointer to a module xlate_func() | +-------------------------------------------------------*/ int (*module_xlate_func(int index))() { return modules[index].xlate_func; } /*-------------------------------------------------------+ | Return the index in the module table for the argument | | name, or -1 if not found | | The comparison is case insensitive | +-------------------------------------------------------*/ int lookup_module_type ( char *modelname ) { char buffer[NAME_LEN + 1], label[NAME_LEN + 1]; int j; strncpy2(buffer, modelname, sizeof(buffer) - 1); strupper(buffer); for ( j = 0; j < ntypes; j++ ) { strncpy2(label, modules[j].label, sizeof(label) - 1); strupper(label); if ( strcmp(buffer, label) == 0 ) return j; } return -1; } /*-------------------------------------------------------+ | Pass back through the argument list the flags and | | maxlevel values for module index 'module_type' | +-------------------------------------------------------*/ void module_attributes ( int module_type, unsigned long *vflags, unsigned long *cflags, unsigned long *xflags, int *maxlevel ) { if ( module_type >= 0 ) { *vflags = modules[module_type].vflags; *cflags = modules[module_type].cflags; *xflags = modules[module_type].xflags; *maxlevel = modules[module_type].maxlevel; } else { *vflags = 0; *cflags = 0; *xflags = 0; *maxlevel = 0; } return; } /*-------------------------------------------------------+ | Called by add_alias() to add options specified on the | | ALIAS line in the config file. | +-------------------------------------------------------*/ int add_module_options ( ALIAS *aliasp, int aliasindex, char **tokens, int ntokens ) { int type; type = aliasp[aliasindex].modtype; if ( modules[type].addopt_func == NULL ) { if ( ntokens > 0 ) { store_error_message("Unsupported parameter"); return 1; } return 0; } return modules[type].addopt_func(aliasp, aliasindex, tokens, &ntokens); } /*-------------------------------------------------------+ | Display options specified for an ALIAS. | +-------------------------------------------------------*/ char *display_module_options (int aliasindex ) { static char buffer[128]; ALIAS *aliasp; long int optflags; int j; aliasp = configp->aliasp; if ( !aliasp ) return ""; if ( !(optflags = aliasp[aliasindex].optflags) ) return ""; buffer[0] = '\0'; if ( optflags & MOPT_RESUME ) sprintf(buffer, "ONLEVEL RESUME"); else if ( optflags & MOPT_ONFULL && aliasp[aliasindex].flags & PRESET) sprintf(buffer, "ONLEVEL %d", aliasp[aliasindex].onlevel + 1); else if ( optflags & MOPT_ONFULL ) sprintf(buffer, "ONLEVEL %d", aliasp[aliasindex].onlevel); if ( optflags & MOPT_SECURITY || optflags & MOPT_ENTERTAIN ) { buffer[0] = '\0'; for ( j = 0; j < aliasp[aliasindex].nident; j++ ) sprintf(buffer + strlen(buffer), "0x%02x ", aliasp[aliasindex].ident[j]); } if ( optflags & MOPT_MAIN ) sprintf(buffer + strlen(buffer), "%s ", "MAIN"); if ( optflags & MOPT_AUX ) sprintf(buffer + strlen(buffer), "%s ", "AUX"); if ( optflags & MOPT_TRANSCEIVE ) sprintf(buffer + strlen(buffer), "%s ", "TRANSCEIVE"); if ( optflags & MOPT_RFFORWARD ) sprintf(buffer + strlen(buffer), "%s ", "RFFORWARD"); if ( optflags & MOPT_RFIGNORE ) sprintf(buffer + strlen(buffer), "%s ", "RFIGNORE"); if ( optflags & MOPT_REVERSE ) sprintf(buffer + strlen(buffer), "%s ", "REVERSE"); return buffer; } /*-------------------------------------------------------+ | Return a pointer to the module name corresponding to | | the argument module_type. | +-------------------------------------------------------*/ char *lookup_module_name ( int module_type ) { if ( module_type >= 0 && module_type < ntypes ) return modules[module_type].label; return ""; } /*-------------------------------------------------------+ | Create the state filter determined by characteristics | | of each module defined in the config file. | +-------------------------------------------------------*/ void set_module_masks ( ALIAS *aliasp ) { int j, ucode; unsigned char hcode, maxlevel, onlevel; unsigned int bitmap, vflags, cflags, xflags; unsigned int defined[16]; if ( configp->module_types == NO ) { for ( j = 0; j < NumModMasks; j++ ) { for ( hcode = 0; hcode < 16; hcode++ ) modmask[j][hcode] = 0xffff; } return; } /* Default for undefined modules */ vflags = modules[configp->default_module].vflags; cflags = modules[configp->default_module].cflags; xflags = modules[configp->default_module].xflags; maxlevel = modules[configp->default_module].maxlevel; /* Record housecode|units with defined module type */ for ( j = 0; j < 16; j++ ) { defined[j] = 0; } j = 0; while ( aliasp && aliasp[j].line_no > 0 ) { if ( aliasp[j].modtype >= 0 ) { /* Module is defined */ hcode = hc2code(aliasp[j].housecode); defined[hcode] |= aliasp[j].unitbmap; } j++; } /* Initialize to zero */ for ( j = 0; j < NumModMasks; j++ ) { for ( hcode = 0; hcode < 16; hcode++ ) modmask[j][hcode] = 0; } for ( j = 0; j < NumVmodMasks; j++ ) { for ( hcode = 0; hcode < 16; hcode++ ) vmodmask[j][hcode] = 0; } /* Set the characteristic of undefined modules */ for ( hcode = 0; hcode < 16; hcode++ ) { bitmap = ~defined[hcode]; /* Mark units which respond */ if ( cflags & UNOFF ) modmask[AllOffMask][hcode] = bitmap; if ( cflags & LION ) modmask[LightsOnMask][hcode] = bitmap; if ( cflags & MON ) modmask[OnMask][hcode] = bitmap; if ( cflags & MOFF ) modmask[OffMask][hcode] = bitmap; if ( cflags & DIM ) modmask[DimMask][hcode] = bitmap; if ( cflags & BRI ) modmask[BriMask][hcode] = bitmap; if ( cflags & LIOFF ) modmask[LightsOffMask][hcode] = bitmap; if ( cflags & BRIB4DIM ) modmask[BriDimMask][hcode] = bitmap; if ( cflags & STDX10 ) modmask[StdMask][hcode] = bitmap; if ( cflags & PRESET ) modmask[PresetMask][hcode] = bitmap; if ( cflags & STAREQ ) modmask[StatusMask][hcode] = bitmap; if ( cflags & STAON ) modmask[StatusOnMask][hcode] = bitmap; if ( cflags & STAOFF ) modmask[StatusOffMask][hcode] = bitmap; if ( cflags & LIONFULL ) modmask[LightsOnFullMask][hcode] = bitmap; if ( cflags & ONFULL ) modmask[OnFullMask][hcode] = bitmap; if ( cflags & ONFULLOFF ) modmask[OnFullOffMask][hcode] = bitmap; if ( cflags & ALLON ) modmask[AllOnMask][hcode] = bitmap; if ( cflags & RESUME ) modmask[ResumeMask][hcode] = bitmap; if ( cflags & TARG ) modmask[TargMask][hcode] = bitmap; if ( cflags & EXC16 ) modmask[Exc16Mask][hcode] = bitmap; if ( cflags & EXC8 ) modmask[Exc8Mask][hcode] = bitmap; if ( cflags & EXC4 ) modmask[Exc4Mask][hcode] = bitmap; if ( cflags & VDATA ) modmask[VdataMask][hcode] = bitmap; if ( cflags & RESUMEDIM ) modmask[ResumeDimMask][hcode] = bitmap; if ( cflags & LIONUNAD ) modmask[LightsOnUnaddrMask][hcode] = bitmap; if ( cflags & LIOFFUNAD ) modmask[LightsOffUnaddrMask][hcode] = bitmap; if ( xflags & X0SH ) modmask[Ext0Mask][hcode] = bitmap; if ( xflags & X3SW ) { modmask[Ext3Mask][hcode] = bitmap; modmask[AllOnMask][hcode] = bitmap; } if ( xflags & X3DIM ) modmask[Ext3DimMask][hcode] = bitmap; if ( xflags & X3GEXEC ) modmask[Ext3GrpExecMask][hcode] = bitmap; if ( xflags & X3GRC1 ) modmask[Ext3GrpRelT1Mask][hcode] = bitmap; if ( xflags & X3GRC2 ) modmask[Ext3GrpRelT2Mask][hcode] = bitmap; if ( xflags & X3GRC3 ) modmask[Ext3GrpRelT3Mask][hcode] = bitmap; if ( xflags & X3GRC4 ) modmask[Ext3GrpRelT4Mask][hcode] = bitmap; if ( xflags & X3GOFF ) modmask[Ext3GrpOffMask][hcode] = bitmap; if ( xflags & X3GOFFEX ) modmask[Ext3GrpOffExecMask][hcode] = bitmap; if ( xflags & X3GBD ) modmask[Ext3GrpBriDimMask][hcode] = bitmap; if ( xflags & X3GBDFULL ) modmask[Ext3GrpBriDimFullMask][hcode] = bitmap; if ( xflags & X3STAT ) modmask[Ext3StatusMask][hcode] = bitmap; if ( vflags & VSTD ) vmodmask[VstdMask][hcode] = bitmap; if ( vflags & VENT ) vmodmask[VentMask][hcode] = bitmap; if ( vflags & VSEC ) vmodmask[VsecMask][hcode] = bitmap; /* Set max and on dim levels for each unit */ for ( ucode = 0; ucode < 16; ucode++ ) { if ( bitmap & (1 << ucode) ) { maxdimlevel[hcode][ucode] = maxlevel; ondimlevel[hcode][ucode] = maxlevel; } } } /* Now fill in the characteristics of defined modules */ j = 0; while ( aliasp && aliasp[j].line_no > 0 ) { if ( aliasp[j].modtype < 0 ) { /* Module is undefined */ j++; continue; } hcode = hc2code(aliasp[j].housecode); bitmap = aliasp[j].unitbmap; cflags = aliasp[j].flags; vflags = aliasp[j].vflags; xflags = aliasp[j].xflags; maxlevel = aliasp[j].maxlevel; onlevel = aliasp[j].onlevel; /* Mark units which respond */ if ( cflags & UNOFF ) modmask[AllOffMask][hcode] |= bitmap; if ( cflags & LION ) modmask[LightsOnMask][hcode] |= bitmap; if ( cflags & MON ) modmask[OnMask][hcode] |= bitmap; if ( cflags & MOFF ) modmask[OffMask][hcode] |= bitmap; if ( cflags & DIM ) modmask[DimMask][hcode] |= bitmap; if ( cflags & BRI ) modmask[BriMask][hcode] |= bitmap; if ( cflags & LIOFF ) modmask[LightsOffMask][hcode] |= bitmap; if ( cflags & BRIB4DIM ) modmask[BriDimMask][hcode] |= bitmap; if ( cflags & STDX10 ) modmask[StdMask][hcode] |= bitmap; if ( cflags & PRESET ) modmask[PresetMask][hcode] |= bitmap; if ( cflags & STAREQ ) modmask[StatusMask][hcode] |= bitmap; if ( cflags & STAON ) modmask[StatusOnMask][hcode] |= bitmap; if ( cflags & STAOFF ) modmask[StatusOffMask][hcode] |= bitmap; if ( cflags & LIONFULL ) modmask[LightsOnFullMask][hcode] |= bitmap; if ( cflags & ONFULL ) modmask[OnFullMask][hcode] |= bitmap; if ( cflags & ONFULLOFF ) modmask[OnFullOffMask][hcode] |= bitmap; if ( cflags & ALLON ) modmask[AllOnMask][hcode] |= bitmap; if ( cflags & RESUME ) modmask[ResumeMask][hcode] |= bitmap; if ( cflags & TARG ) modmask[TargMask][hcode] |= bitmap; if ( cflags & EXC16 ) modmask[Exc16Mask][hcode] |= bitmap; if ( cflags & EXC8 ) modmask[Exc8Mask][hcode] |= bitmap; if ( cflags & EXC4 ) modmask[Exc4Mask][hcode] |= bitmap; if ( cflags & VDATA ) modmask[VdataMask][hcode] |= bitmap; if ( cflags & RESUMEDIM ) modmask[ResumeDimMask][hcode] |= bitmap; if ( cflags & LIONUNAD ) modmask[LightsOnUnaddrMask][hcode] |= bitmap; if ( cflags & LIOFFUNAD ) modmask[LightsOffUnaddrMask][hcode] |= bitmap; if ( xflags & X0SH ) modmask[Ext0Mask][hcode] |= bitmap; if ( xflags & X3SW ) { modmask[Ext3Mask][hcode] |= bitmap; modmask[AllOnMask][hcode] |= bitmap; } if ( xflags & X3DIM ) modmask[Ext3DimMask][hcode] |= bitmap; if ( xflags & X3GEXEC ) modmask[Ext3GrpExecMask][hcode] |= bitmap; if ( xflags & X3GRC1 ) modmask[Ext3GrpRelT1Mask][hcode] |= bitmap; if ( xflags & X3GRC2 ) modmask[Ext3GrpRelT2Mask][hcode] |= bitmap; if ( xflags & X3GRC3 ) modmask[Ext3GrpRelT3Mask][hcode] |= bitmap; if ( xflags & X3GRC4 ) modmask[Ext3GrpRelT4Mask][hcode] |= bitmap; if ( xflags & X3GOFF ) modmask[Ext3GrpOffMask][hcode] |= bitmap; if ( xflags & X3GOFFEX ) modmask[Ext3GrpOffExecMask][hcode] |= bitmap; if ( xflags & X3GBD ) modmask[Ext3GrpBriDimMask][hcode] |= bitmap; if ( xflags & X3GBDFULL ) modmask[Ext3GrpBriDimFullMask][hcode] |= bitmap; if ( xflags & X3STAT ) modmask[Ext3StatusMask][hcode] |= bitmap; if ( vflags & VSTD ) vmodmask[VstdMask][hcode] |= bitmap; if ( vflags & VENT ) vmodmask[VentMask][hcode] |= bitmap; if ( vflags & VSEC ) vmodmask[VsecMask][hcode] |= bitmap; /* Set max and on dim levels for each unit */ for ( ucode = 0; ucode < 16; ucode++ ) { if ( bitmap & (1 << ucode) ) { maxdimlevel[hcode][ucode] = maxlevel; ondimlevel[hcode][ucode] = onlevel; } } j++; } return; } /*-------------------------------------------------------+ | Display a table indicating the module attributes | | (either defined or defaults) for each unit | +-------------------------------------------------------*/ void show_module_mask ( unsigned char hcode ) { char *chr = ".*x"; int lw = 13; unsigned int exclusive; printf("Module Attributes\n"); printf("%*s %c\n", lw + 13, "Housecode", code2hc(hcode)); printf("%*s 1..4...8.......16\n", lw, "Unit:"); printf("%*s (%s) %s\n", lw, "On", bmap2asc(modmask[OnMask][hcode], chr), "Supports On command"); printf("%*s (%s) %s\n", lw, "Off", bmap2asc(modmask[OffMask][hcode], chr), "Supports Off command"); printf("%*s (%s) %s\n", lw, "Dim", bmap2asc(modmask[DimMask][hcode], chr), "Supports Dim (1-22) commands"); printf("%*s (%s) %s\n", lw, "Bright", bmap2asc(modmask[BriMask][hcode], chr), "Supports Bright (1-22) commands"); printf("%*s (%s) %s\n", lw, "BrightB4Dim", bmap2asc(modmask[BriDimMask][hcode], chr), "Brightens to 100% before Dim/Bright if Off"); printf("%*s (%s) %s\n", lw, "ResumeB4Dim", bmap2asc(modmask[ResumeDimMask][hcode], chr), "Resumes prev. level before Dim/Bright if Off"); printf("%*s (%s) %s\n", lw, "LightsOn", bmap2asc(modmask[LightsOnMask][hcode], chr), "Supports LightsOn (AllLightsOn) command"); printf("%*s (%s) %s\n", lw, "LightsOnFull", bmap2asc(modmask[LightsOnFullMask][hcode], chr), "LightsOn command always brightens to 100%"); printf("%*s (%s) %s\n", lw, "OnFullIfOff", bmap2asc(modmask[OnFullOffMask][hcode], chr), "LightsOn brightens to 100% only if Off"); exclusive = modmask[Exc16Mask][hcode] | modmask[Exc8Mask][hcode] | modmask[Exc4Mask][hcode]; printf("%*s (%s) %s\n", lw, "ExclusiveOn", bmap2asc(exclusive, chr), "Last unit turns On, other units in group Off"); printf("%*s (%s) %s\n", lw, "LightsOff", bmap2asc(modmask[LightsOffMask][hcode], chr), "Supports LightsOff command"); printf("%*s (%s) %s\n", lw, "LiOnUnAddr", bmap2asc(modmask[LightsOnUnaddrMask][hcode], chr), "Unaddressed by LightsOn command"); printf("%*s (%s) %s\n", lw, "LiOffUnAddr", bmap2asc(modmask[LightsOffUnaddrMask][hcode], chr), "Unaddressed by LightsOff command"); printf("%*s (%s) %s\n", lw, "AllOff", bmap2asc(modmask[AllOffMask][hcode], chr), "Supports AllOff (AllUnitsOff) command"); printf("%*s (%s) %s\n", lw, "StatusReq", bmap2asc(modmask[StatusMask][hcode], chr), "Supports StatusReq command"); printf("%*s (%s) %s\n", lw, "StatusOn", bmap2asc(modmask[StatusOnMask][hcode], chr), "Sends only StatusOn in response to StatusReq"); printf("%*s (%s) %s\n", lw, "StatusOff", bmap2asc(modmask[StatusOffMask][hcode], chr), "Sends only StatusOff in response to StatusReq"); printf("%*s (%s) %s\n", lw, "Preset", bmap2asc(modmask[PresetMask][hcode], chr), "Supports Preset (1-32) commands"); printf("%*s (%s) %s\n", lw, "LevelFixed", bmap2asc(modmask[OnFullMask][hcode], chr), "On command sets to fixed brightness level"); printf("%*s (%s) %s\n", lw, "LevelResume", bmap2asc(modmask[ResumeMask][hcode], chr), "On command resumes previous brightness level"); printf("%*s (%s) %s\n", lw, "ExtSwitch", bmap2asc(modmask[Ext3Mask][hcode], chr), "Supports Extended code switch commands"); printf("%*s (%s) %s\n", lw, "ExtDimmer", bmap2asc(modmask[Ext3DimMask][hcode], chr), "Supports Extended code dimmer (0-63) commands"); printf("%*s (%s) %s\n", lw, "ExtStatus", bmap2asc(modmask[Ext3StatusMask][hcode], chr), "Supports Extended code StatusReq commands"); printf("%*s (%s) %s\n", lw, "ExtGrpExec", bmap2asc(modmask[Ext3GrpExecMask][hcode], chr), "Supports Extended code Group Execute"); printf("%*s (%s) %s\n", lw, "ExtGrpOff", bmap2asc2(modmask[Ext3GrpOffMask][hcode], modmask[Ext3GrpOffExecMask][hcode], chr), "Supports Extended code Group Off (x = bug)"); printf("%*s (%s) %s\n", lw, "ExtGrpBrDim", bmap2asc(modmask[Ext3GrpBriDimMask][hcode], chr), "Supports Extended code Group Bright/Dim"); printf("%*s (%s) %s\n", lw, "ExtShutter", bmap2asc(modmask[Ext0Mask][hcode], chr), "Supports Extended code shutter (0-25) commands"); printf("%*s (%s) %s\n", lw, "Virtual", bmap2asc(modmask[VdataMask][hcode], chr), "Virtual Data module"); printf("\n"); return; } /*---------------------------------------------------------------------+ | Count the RF options (There should be no more than one) | +---------------------------------------------------------------------*/ int count_rf_options ( ALIAS *aliasp, int aliasindex ) { int count = 0; count += (aliasp[aliasindex].optflags & MOPT_TRANSCEIVE) ? 1 : 0; count += (aliasp[aliasindex].optflags & MOPT_RFFORWARD) ? 1 : 0; count += (aliasp[aliasindex].optflags & MOPT_RFIGNORE) ? 1 : 0; return count; } /*---------------------------------------------------------------------+ | Set REVERSE, MAIN, and AUX module options | +---------------------------------------------------------------------*/ int sensor_options ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens) { int j, k, count = 0; char *tmptok; for ( j = 0; j < *ntokens; j++ ) { strupper(tokens[j]); if ( strcmp(tokens[j], "REVERSE") == 0 ) { aliasp[aliasindex].optflags |= MOPT_REVERSE; *tokens[j] = '\0'; count++; } else if ( strcmp(tokens[j], "RFIGNORE") == 0 ) { aliasp[aliasindex].optflags |= MOPT_RFIGNORE; *tokens[j] = '\0'; count++; } else if ( strcmp(tokens[j], "MAIN") == 0 ) { aliasp[aliasindex].optflags |= MOPT_MAIN; *tokens[j] = '\0'; count++; } else if ( strcmp(tokens[j], "AUX") == 0 ) { aliasp[aliasindex].optflags |= MOPT_AUX; *tokens[j] = '\0'; count++; } } /* Compact to remove "gaps" where tokens were nulled out */ for ( j = 0; j < *ntokens; j++ ) { if ( *tokens[j] == '\0' ) { for ( k = j + 1; k < *ntokens; k++ ) { if ( *tokens[k] != '\0' ) { tmptok = tokens[j]; tokens[j] = tokens[k]; tokens[k] = tmptok; *tmptok = '\0'; break; } } } } *ntokens -= count; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the identity of | | the X-10 UX17A transceiver to the module. | +-------------------------------------------------------*/ int opt_ux17a ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { if ( *ntokens > 0 ) { store_error_message("This module takes no parameters."); return 1; } /* First byte of UX17A codeword is either 0x82 or 0x83 */ aliasp[aliasindex].nident = 2; aliasp[aliasindex].ident[0] = 0x82; aliasp[aliasindex].ident[1] = 0x83; /* This is an entertainment remote transmitter */ aliasp[aliasindex].vtype = RF_ENT; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the identity of | | the X-10 UR81A remote to the module. | +-------------------------------------------------------*/ int opt_ur81a ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { if ( *ntokens > 0 ) { store_error_message("This module takes no parameters."); return 1; } /* First byte of UR81A codeword is always 0xEE */ aliasp[aliasindex].nident = 1; aliasp[aliasindex].ident[0] = 0xEE; /* This is an entertainment remote transmitter */ aliasp[aliasindex].vtype = RF_ENT; aliasp[aliasindex].optflags |= MOPT_ENTERTAIN; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the IDs for a | | generic entertainment remote. Valid ID bytes for an | | entertainment remote have bit 2 (1-8) set. | +-------------------------------------------------------*/ int opt_guru ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { char *sp; long ident; int j; /* Tokens are IDs */ if ( *ntokens < 1 ) { store_error_message("At least one entertainment ID is needed."); return 1; } if ( *ntokens > NIDENT ) { store_error_message("Too many parameters on line."); return 1; } for ( j = 0; j < *ntokens; j++ ) { ident = strtol(tokens[j], &sp, 16); if ( *sp == '\0' && ident >= 0 && ident <= 0xff && (ident & 0x02) ) { aliasp[aliasindex].ident[j] = (unsigned char)ident; } else { store_error_message("Invalid hexadecimal entertainment ID parameter"); return 1; } } aliasp[aliasindex].nident = j; /* This is an entertainment RF transmitter */ aliasp[aliasindex].vtype = RF_ENT; aliasp[aliasindex].optflags |= MOPT_ENTERTAIN; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the RF security | | ID from the ALIAS line in the config file. | +-------------------------------------------------------*/ int opt_sremote ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { char *sp; long ident; int j; /* First token is security ID */ if ( *ntokens < 1 ) { store_error_message("Module security ID is needed."); return 1; } if ( *ntokens > NIDENT ) { store_error_message("Too many parameters on line."); return 1; } for ( j = 0; j < *ntokens; j++ ) { ident = strtol(tokens[j], &sp, 16); if ( *sp == '\0' && ident >= 0 && ident <= 0xff ) { aliasp[aliasindex].ident[j] = (unsigned char)ident; } else { store_error_message("Invalid hexadecimal security ID parameter"); return 1; } } aliasp[aliasindex].nident = j; /* This is a security RF transmitter */ aliasp[aliasindex].vtype = RF_SEC; aliasp[aliasindex].optflags |= MOPT_SECURITY; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the RF security | | sensor options from the ALIAS line in the config file.| +-------------------------------------------------------*/ int opt_sensor ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { sensor_options(aliasp, aliasindex, tokens, ntokens); if ( opt_sremote(aliasp, aliasindex, tokens, ntokens) != 0 ) return 1; if ( aliasp[aliasindex].nident > 1 ) { store_error_message("Only one security ID is supported"); return 1; } if ( aliasp[aliasindex].optflags & (MOPT_MAIN | MOPT_AUX) ) { store_error_message("Unsupported module option MAIN or AUX"); return 1; } /* This is a sensor with periodic "alive" signals */ aliasp[aliasindex].optflags |= MOPT_SENSOR; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the RF security | | sensor options from the ALIAS line in the config file.| +-------------------------------------------------------*/ int opt_ds90 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { int check_ds90_ids( unsigned char * ); unsigned char comp_ds90_id( unsigned char, int ); sensor_options(aliasp, aliasindex, tokens, ntokens); if ( opt_sremote(aliasp, aliasindex, tokens, ntokens) != 0 ) return 1; if ( (aliasp[aliasindex].optflags & MOPT_MAIN) && (aliasp[aliasindex].optflags & MOPT_AUX) ) { store_error_message("Module options MAIN and AUX are incompatible"); return 1; } if ( aliasp[aliasindex].nident > 2 ) { store_error_message("Too many security IDs for DS90"); return 1; } else if ( aliasp[aliasindex].nident == 2 ) { /* Check main and aux ID and reverse order if necessary */ if ( check_ds90_ids(aliasp[aliasindex].ident) != 0 ) { store_error_message("DS90 security IDs are incompatible"); return 1; } } else if ( aliasp[aliasindex].optflags & MOPT_MAIN ) { aliasp[aliasindex].ident[1] = comp_ds90_id(aliasp[aliasindex].ident[0], COMPUTE_AUX); aliasp[aliasindex].nident = 2; } else if ( aliasp[aliasindex].optflags & MOPT_AUX ) { aliasp[aliasindex].ident[1] = aliasp[aliasindex].ident[0]; aliasp[aliasindex].ident[0] = comp_ds90_id(aliasp[aliasindex].ident[1], COMPUTE_MAIN); aliasp[aliasindex].nident = 2; } /* This is a sensor with periodic "alive" signals */ aliasp[aliasindex].optflags |= MOPT_SENSOR; return 0; } /*-------------------------------------------------------+ | Called by add_module_options() to add the RESUME or | | ONFULL options from the ALIAS line in the | | config file. | +-------------------------------------------------------*/ int opt_onlevel ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens ) { int j, type, val, maxval, valoffset; char *sp; type = aliasp[aliasindex].modtype; maxval = modules[type].maxlevel; valoffset = (modules[type].cflags & PRESET) ? 1 : 0; for ( j = 0; j < *ntokens; j++ ) strupper(tokens[j]); j = 0; while ( *ntokens > 0 ) { if ( !strcmp(tokens[j], "ONLEVEL") ) { if ( *ntokens > 1 && (!strcmp(tokens[j + 1], "RESUME") || !strcmp(tokens[j + 1], "0")) ) { aliasp[aliasindex].flags |= RESUME; aliasp[aliasindex].flags &= ~ONFULL; aliasp[aliasindex].optflags |= MOPT_RESUME; aliasp[aliasindex].optflags &= ~MOPT_ONFULL; aliasp[aliasindex].onlevel = maxval; j += 2; *ntokens -= 2; } else if ( *ntokens > 1 && (val = strtol(tokens[j + 1], &sp, 10)) && *sp == '\0' && val > 0 && val <= (maxval + valoffset) ) { aliasp[aliasindex].flags &= ~RESUME; aliasp[aliasindex].flags |= ONFULL; aliasp[aliasindex].optflags &= ~MOPT_RESUME; aliasp[aliasindex].optflags |= MOPT_ONFULL; aliasp[aliasindex].onlevel = val - valoffset; j += 2; *ntokens -= 2; } else if ( *ntokens > 1 ) { store_error_message("Invalid ONLEVEL parameter"); return 1; } else { store_error_message("Missing ONLEVEL parameter"); return 1; } } else { store_error_message("Module option not recognized"); return 1; } } return 0; } /*---------------------------------------------------------------------+ | Set TRANSCEIVE, RFFORWARD, or RFIGNORE module options | +---------------------------------------------------------------------*/ int opt_aux ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens) { int j, k, count = 0; char *tmptok; for ( j = 0; j < *ntokens; j++ ) { strupper(tokens[j]); if ( strcmp(tokens[j], "TRANSCEIVE") == 0 ) { aliasp[aliasindex].optflags |= MOPT_TRANSCEIVE; *tokens[j] = '\0'; count++; } else if ( strcmp(tokens[j], "RFFORWARD") == 0 ) { aliasp[aliasindex].optflags |= MOPT_RFFORWARD; *tokens[j] = '\0'; count++; } else if ( strcmp(tokens[j], "RFIGNORE") == 0 ) { aliasp[aliasindex].optflags |= MOPT_RFIGNORE; *tokens[j] = '\0'; count++; } else { store_error_message("Unknown RF option parameter."); return 1; } } if ( count == 0 ) { store_error_message("RF option TRANSCEIVE, RFFORWARD, or RFIGNORE required."); return 1; } else if ( count > 1 ) { store_error_message("Conflicting RF options."); return 1; } /* Compact to remove "gaps" where tokens were nulled out */ for ( j = 0; j < *ntokens; j++ ) { if ( *tokens[j] == '\0' ) { for ( k = j + 1; k < *ntokens; k++ ) { if ( *tokens[k] != '\0' ) { tmptok = tokens[j]; tokens[j] = tokens[k]; tokens[k] = tmptok; *tmptok = '\0'; break; } } } } *ntokens -= count; return 0; } /*---------------------------------------------------------------------+ | Process received vdata for DS10A Door/Window Sensor | +---------------------------------------------------------------------*/ int fn_ds10a ( struct xlate_vdata_st *xlate_vdata ) { unsigned int vdata; int polarity; vdata = xlate_vdata->vdata; polarity = (xlate_vdata->optflags & MOPT_REVERSE) ? 0 : 1; xlate_vdata->vflags = 0; if ( vdata & ~(0x85u) ) { xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } if ( vdata & 0x80 ) { xlate_vdata->func = polarity ? ClearFunc : AlertFunc; xlate_vdata->trig = polarity ? ClearTrig : AlertTrig; } else { xlate_vdata->func = polarity ? AlertFunc : ClearFunc; xlate_vdata->trig = polarity ? AlertTrig : ClearTrig; } xlate_vdata->vflags |= (vdata & 0x04) ? SEC_MIN : SEC_MAX; xlate_vdata->vflags |= (vdata & 0x01) ? SEC_LOBAT : 0; return 0; } /*---------------------------------------------------------------------+ | Process received vdata for DS90 Door/Window Sensor | +---------------------------------------------------------------------*/ int fn_ds90 ( struct xlate_vdata_st *xlate_vdata ) { unsigned int vdata; int polarity; vdata = xlate_vdata->vdata; polarity = (xlate_vdata->optflags & MOPT_REVERSE) ? 0 : 1; if ( vdata & ~(0xc5u) ) { xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } if ( (xlate_vdata->optflags & MOPT_MAIN) && (xlate_vdata->ident == xlate_vdata->identp[1]) ) { /* MAIN specified and signal on AUX, ignore */ return 1; } if ( (xlate_vdata->optflags & MOPT_AUX) && (xlate_vdata->ident == xlate_vdata->identp[0]) ) { /* AUX specified and signal on MAIN, ignore */ return 1; } if ( !(xlate_vdata->optflags & (MOPT_MAIN | MOPT_AUX)) && (xlate_vdata->nident == 2) ) { /* Neither specified - add appropriate flag */ xlate_vdata->vflags |= (xlate_vdata->ident == xlate_vdata->identp[0]) ? SEC_MAIN : SEC_AUX ; } if ( vdata & 0x40 ) { xlate_vdata->func = TamperFunc; xlate_vdata->trig = TamperTrig; xlate_vdata->vflags |= SEC_TAMPER; } else if ( vdata & 0x80 ) { xlate_vdata->func = polarity ? ClearFunc : AlertFunc; xlate_vdata->trig = polarity ? ClearTrig : AlertTrig; } else { xlate_vdata->func = polarity ? AlertFunc : ClearFunc; xlate_vdata->trig = polarity ? AlertTrig : ClearTrig; } xlate_vdata->vflags |= (vdata & 0x04) ? SEC_MIN : SEC_MAX; xlate_vdata->vflags |= (vdata & 0x01) ? SEC_LOBAT : 0; return 0; } /*---------------------------------------------------------------------+ | Process received vdata for MS10A Security Motion Sensor | +---------------------------------------------------------------------*/ int fn_ms10a ( struct xlate_vdata_st *xlate_vdata ) { unsigned int vdata; vdata = xlate_vdata->vdata; xlate_vdata->vflags = 0; if ( (vdata & 0x0cu) != 0x0cu || vdata & ~(0x8du) ) { xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } xlate_vdata->vflags |= (vdata & 0x01u) ? SEC_LOBAT : 0; if ( vdata & 0x80u ) { xlate_vdata->func = ClearFunc; xlate_vdata->trig = ClearTrig; } else { xlate_vdata->func = AlertFunc; xlate_vdata->trig = AlertTrig; } return 0; } /*---------------------------------------------------------------------+ | Process received vdata for SH624 Security Remote Control | +---------------------------------------------------------------------*/ int fn_sh624 ( struct xlate_vdata_st *xlate_vdata ) { unsigned int vdata; vdata = xlate_vdata->vdata; xlate_vdata->vflags = 0; if ( !(vdata & 0x02) || (vdata & 0x11) ) { xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } if ( vdata & 0x20 ) { xlate_vdata->func = PanicFunc; xlate_vdata->trig = PanicTrig; } else if ( vdata & 0x40 ) { if ( vdata & 0x80 ) { xlate_vdata->func = SecLightsOffFunc; xlate_vdata->trig = SecLightsOffTrig; } else { xlate_vdata->func = SecLightsOnFunc; xlate_vdata->trig = SecLightsOnTrig; } } else { if ( vdata & 0x80 ) { xlate_vdata->func = DisarmFunc; xlate_vdata->trig = DisarmTrig; } else { xlate_vdata->func = ArmFunc; xlate_vdata->trig = ArmTrig; xlate_vdata->vflags |= ((vdata & 0x08) ? SEC_HOME : SEC_AWAY); xlate_vdata->vflags |= ((vdata & 0x04) ? SEC_MIN : SEC_MAX); } } return 0; } /*---------------------------------------------------------------------+ | Process received vdata for KR10A Security Keychain Remote Control | +---------------------------------------------------------------------*/ int fn_kr10a ( struct xlate_vdata_st *xlate_vdata ) { unsigned int vdata; vdata = xlate_vdata->vdata; xlate_vdata->vflags = 0; if ( (vdata & 0x0f) != 0x06 || (vdata & 0x11) ) { xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } if ( vdata & 0x20 ) { xlate_vdata->func = PanicFunc; xlate_vdata->trig = PanicTrig; } else if ( vdata & 0x40 ) { if ( vdata & 0x80 ) { xlate_vdata->func = SecLightsOffFunc; xlate_vdata->trig = SecLightsOffTrig; } else { xlate_vdata->func = SecLightsOnFunc; xlate_vdata->trig = SecLightsOnTrig; } } else { if ( vdata & 0x80 ) { xlate_vdata->func = DisarmFunc; xlate_vdata->trig = DisarmTrig; } else { xlate_vdata->func = ArmFunc; xlate_vdata->trig = ArmTrig; xlate_vdata->vflags |= (SEC_MIN | SEC_AWAY); } } return 0; } /*---------------------------------------------------------------------+ | Process received vdata for UR81A Entertainment Remote Control | +---------------------------------------------------------------------*/ int fn_ur81a ( struct xlate_vdata_st *xlate_vdata ) { xlate_vdata->vflags = 0; xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } /*---------------------------------------------------------------------+ | Process received vdata for General Universal Remote Unit (GURU) | +---------------------------------------------------------------------*/ int fn_guru ( struct xlate_vdata_st *xlate_vdata ) { xlate_vdata->vflags = 0; xlate_vdata->func = VdataFunc; xlate_vdata->trig = VdataTrig; return 0; } /*---------------------------------------------------------------------+ | Check the order of DS90 IDs. After bit reversals, the aux ID must | | be the primary ID + 1. Reverse the order if necessary. | | Return 0 if OK or 1 if the IDs don't have a valid relationship. | +---------------------------------------------------------------------*/ int check_ds90_ids( unsigned char *identp ) { unsigned char mainid, auxid; mainid = rev_byte_bits(identp[0]); auxid = rev_byte_bits(identp[1]); if ( auxid == ((mainid + 1) & 0xffu) ) { /* Order is OK */ return 0; } else if ( mainid == ((auxid + 1) & 0xffu) ) { /* Reverse the order */ identp[0] = rev_byte_bits(auxid); identp[1] = rev_byte_bits(mainid); return 0; } /* Invalid relationship */ return 1; } /*---------------------------------------------------------------------+ | Determine the companion ID for a DS90 ID. If func = COMPUTE_AUX, | | find the aux ID for the argument main ID; otherwise find the main | | ID for the argument aux ID. | +---------------------------------------------------------------------*/ unsigned char comp_ds90_id ( unsigned char ident, int func ) { unsigned char newid; ident = rev_byte_bits(ident); if ( func == COMPUTE_AUX ) { /* Get aux corresponding to main */ newid = rev_byte_bits((ident + 1) & 0xffu); } else { /* Get main corresponding to aux */ newid = rev_byte_bits((ident - 1) & 0xffu); } return newid; }