1 
2 
3 /*----------------------------------------------------------------------------+
4  |                                                                            |
5  |                  X10 Module Attributes for HEYU                            |
6  |             Copyright 2004-2008 Charles W. Sullivan                        |
7  |                                                                            |
8  |                                                                            |
9  | As used herein, HEYU is a trademark of Daniel B. Suthers.                  |
10  | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc.               |
11  | SwitchLinc and LampLinc are trademarks of Smarthome, Inc.                  |
12  | The author is not affiliated with any of these entities.                   |
13  |                                                                            |
14  | Charles W. Sullivan                                                        |
15  | Co-author and Maintainer                                                   |
16  | Greensboro, North Carolina                                                 |
17  | Email ID: cwsulliv01                                                       |
18  | Email domain: -at- heyu -dot- org                                          |
19  |                                                                            |
20  +----------------------------------------------------------------------------*/
21 
22 /*
23  *   This program is free software: you can redistribute it and/or modify
24  *   it under the terms of the GNU General Public License as published by
25  *   the Free Software Foundation, either version 3 of the License, or
26  *   (at your option) any later version.
27  *
28  *   This program is distributed in the hope that it will be useful,
29  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
30  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  *   GNU General Public License for more details.
32  *
33  *   You should have received a copy of the GNU General Public License
34  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
35  */
36 
37 #include <stdio.h>
38 #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD)
39 #include <string.h>
40 #else
41 #include <strings.h>
42 #endif
43 #include <stdlib.h>
44 #include <ctype.h>
45 #include "process.h"
46 #include "oregon.h"
47 
48 /* Standard module attribute/response definitions for cflags */
49 /* Basic function codes 0-6 (maintain this order) */
50 #define  UNOFF     0x00000001     /* All Units Off */
51 #define  LION      0x00000002     /* All Lights ON */
52 #define  MON       0x00000004     /* Simple module ON */
53 #define  MOFF      0x00000008     /* Simple module OFF */
54 #define  DIM       0x00000010     /* Dim 1-22 */
55 #define  BRI       0x00000020     /* Bright 1-22 */
56 #define  LIOFF     0x00000040     /* All Lights OFF */
57 /* Other attributes */
58 #define  ALLON     0x00000080     /* All Units On */
59 #define  STDX10    0x00000100     /* Standard X10 */
60 #define  PRESET    0x00000200     /* Preset 1-32 */
61 #define  BRIB4DIM  0x00000400     /* If OFF, full Brightness before dimming */
62 #define  STAREQ    0x00000800     /* Responds to Status Request */
63 #define  STAON     0x00001000     /* Sends StatusOn ack */
64 #define  STAOFF    0x00002000     /* Sends StatusOff ack */
65 #define  LIONFULL  0x00004000     /* All Lights ON -> Full brightness */
66 #define  ONFULL    0x00008000     /* ON -> Full (or option) brightness */
67 #define  ONFULLOFF 0x00010000     /* ON -> Full brightness if Off */
68 #define  RESUME    0x00020000     /* ON resumes previous level */
69 #define  RESUMEDIM 0x00040000     /* Dim/Bright first resumes previous level */
70 #define  LIONUNAD  0x00080000     /* AllLightsOn unaddresses the module */
71 #define  LIOFFUNAD 0x00100000     /* AllLightsOff unaddresses the module */
72 #define  TARG      0x00200000     /* Is a target instead of a module */
73 #define  EXC16     0x00400000     /* Last unit turns On (all others turn off) */
74 #define  EXC8      0x00800000     /* Last unit turns On (others in group of 8 turn off) */
75 #define  EXC4      0x01000000     /* Last unit turns On and others in group of 4 turn off) */
76 #define  VDATA     0x02000000     /* Virtual data repository */
77 #define  PLCSENSOR 0x04000000     /* PLC Sensor */
78 #define  ADDRESSED 0x08000000     /* Has standard address */
79 #define  PHYS      0x10000000     /* Is a physical module */
80 #define  ONOFFUNAD 0x20000000     /* On or Off unaddresses the module (ACT bug) */
81 
82 /* NOTE: Attributes STDX10, PRESET, and EXT3SW/EXT3DIM are */
83 /* mutually incompatible.                                  */
84 
85 /* Extended code module attributes for xflags */
86 /* (Group reference characteristic types are mutually incompatible.) */
87 #define  XNON      0
88 #define  X3SW      0x00000001     /* Extended codes Type 3 (switch only) */
89 #define  X3DIM     0x00000002     /* Extended codes Type 3 with preset dim 0-63 */
90 #define  X0SH      0x00000004     /* Extended code Type 0 shutter control */
91 #define  X3GEXEC   0x00000008     /* Supports Extended Group Exec command */
92 #define  X3GRC1    0x00000010     /* Group reference characteristic Type 1 (LM14A, AM14A) */
93 #define  X3GRC2    0x00000020     /* Group reference characteristic Type 2 (LM465-1) */
94 #define  X3GRC3    0x00000040     /* Group reference characteristic Type 3 (WS467-1) */
95 #define  X3GRC4    0x00000080     /* Group reference characteristic Type 4 */
96 #define  X3GOFF    0x00000100     /* Extended Group Off */
97 #define  X3GOFFEX  0x00000200     /* Extended Group Off acts like Group Exec */
98 #define  X3GBD     0x00000400     /* Extended Group Bright/Dim */
99 #define  X3GBDFULL 0x00000800     /* Ext Grp Bri/Dim resumes, or brightens full if prev at level 0 */
100 #define  X3STAT    0x00001000     /* Extended code status, i.e., 2-way */
101 #define  X3GREM    0x00002000     /* Extended Group Remove works */
102 #define  X0PRESET  0x00004000     /* Extended code Type 0 shutter preset */
103 
104 /* Virtual model attributes for vflags */
105 #define  VNON   0
106 #define  VSTD   0x00000001   /* X10 Standard */
107 #define  VENT   0x00000002   /* X10 Entertainment */
108 #define  VSEC   0x00000004   /* X10 Security */
109 #define  VRFXS  0x00000008   /* RFX Sensor */
110 #define  VRFXM  0x00000010   /* RFX Meter */
111 #define  VDMX   0x00000020   /* Digimax */
112 #define  VORE   0x00000040   /* Oregon */
113 #define  VKAKU  0x00000080   /* KAKU */
114 
115 /* KaKu model attributes for kflags */
116 #define  KOFF     0x00000001   /* Off */
117 #define  KON      0x00000002   /* On */
118 #define  KGOFF    0x00000004   /* Group Off */
119 #define  KGON     0x00000008   /* Group On */
120 #define  KPRE     0x00000010   /* Preset */
121 #define  KGPRE    0x00000020   /* Group Preset */
122 #define  KRESUME  0x00000040   /* Resume */
123 #define  KPHYS    0x00000080   /* Physical module */
124 
125 /* Module max dim levels */
126 #define  MXL0        0
127 #define  MXLS      210         /* Standard X10 modules 0-210 */
128 #define  MXLP       31         /* Preset modules 0-31 (zero-base) */
129 #define  MXLE       62         /* Extended code Type 3 dimmer modules 0-62 */
130 #define  MXLEA      63         /* Extended code Type 3 appliance modules 0,63 */
131 #define  MXLS0      25         /* Extended code Type 0 shutters 0-25 */
132 #define  MXLV      255         /* Virtual modules 0-255 */
133 #define  MXLK       15         /* KAKU modules 0-15 */
134 
135 /* Standard module type attributes for cflags .  To add a new module type,  */
136 /* "OR" together its attributes here and add an entry in the modules */
137 /* table below. (Keep the table uncluttered, for future additions.) */
138 #define  NOMATT      0
139 #define  BASIC       (UNOFF | MON | MOFF | ALLON | ADDRESSED | PHYS)
140 #define  ACTBASIC    (STDX10 | MON | MOFF | ALLON | ADDRESSED | PHYS | STAON | STAOFF | STAREQ)
141 #define  ACTBUG      (ACTBASIC | ONOFFUNAD)
142 
143 #define  STDAM       (BASIC | STDX10)
144 #define  STDLM       (STDAM | DIM | BRI | BRIB4DIM | LION | ONFULLOFF)
145 #define  STDWS       (STDLM | LIOFF)
146 #define  AMS         (STDAM | STAON | STAOFF | STAREQ)
147 #define  LMS         (STDLM | STAON | STAOFF | STAREQ)
148 #define  SIREN       (STDAM | LION )
149 #define  REM2        (STDX10 | TARG | MON | MOFF)
150 #define  REM3        (STDX10 | TARG | MOFF | BRI | DIM)
151 #define  REM4        (STDX10 | TARG | MON | MOFF | BRI | DIM)
152 #define  REM6        (STDX10 | TARG | MON | MOFF | BRI | DIM | LION | UNOFF)
153 
154 #define  LM15A       (STDAM | LION | LIONFULL | LIOFF | LIONUNAD | LIOFFUNAD)
155 #define  XPS3        (STDAM | LION | LIONFULL | LIOFF)
156 #define  XPD3        (STDLM | LIOFF)
157 
158 #define  PR511       (STDAM | STAON | STAOFF | STAREQ | LION | LIONFULL | LIOFF)
159 
160 #define  AM14A       (BASIC | ALLON | STAON | STAOFF | STAREQ)
161 #define  LM14A       (AM14A | DIM | BRI | LION | LIOFF | RESUME | RESUMEDIM | LIOFFUNAD)
162 
163 #define  SL1AM       (BASIC)
164 #define  SL2AM       (SL1AM | STAREQ)
165 
166 #define  SL1LM       (BASIC | PRESET | DIM | BRI | LION | LIOFF | ONFULL)
167 #define  SL2LM       (SL1LM | STAREQ)
168 
169 #define  LL1LM       (BASIC | PRESET | DIM | BRI | LION | LIOFF | LIONFULL | ONFULL)
170 #define  LL2LM       (LL1LM | STAREQ)
171 #define  AMEXC16     (STDAM | EXC16)
172 #define  AMEXC8      (STDAM | EXC8 )
173 #define  AMEXC4      (STDAM | EXC4 )
174 #define  CAMEXC4     (STDX10 | EXC4 | MON | MOFF | ADDRESSED | PHYS)
175 #define  VIRT4       (TARG | MON | MOFF | BRI | DIM)
176 #define  SHUT0       (MON | MOFF | RESUME | PHYS)
177 #define  VIRTUAL     (TARG | VDATA)
178 #define  PALMPAD     (TARG | MON | MOFF | BRI | DIM)
179 #define  KEYCHAIN    (TARG | MON | MOFF)
180 #define  ONLYON      (TARG | MON)
181 #define  ONLYOFF     (TARG | MOFF)
182 #define  PLCSEN      (TARG | MON | MOFF | ADDRESSED | PLCSENSOR)
183 #define  MOTION      (TARG | MON | MOFF)
184 
185 #define  LM_1        (BASIC | DIM | BRI | LION | LIOFF | RESUMEDIM | LIOFFUNAD)
186 #define  WS_1        (BASIC | DIM | BRI | LION | RESUME)
187 
188 /* Extended module type attributes for xflags */
189 
190 #define XAM14A        (X3SW | X3GEXEC | X3GRC1 | X3GOFFEX | X3STAT | X3GREM)
191 #define XLM14A        (X3SW | X3GEXEC | X3DIM | X3GRC1 | X3GOFFEX | X3STAT | X3GREM)
192 #define XLM_1         (X3SW | X3GEXEC | X3DIM | X3GRC2 | X3GOFF | X3GBD | X3GBDFULL)
193 #define XWS_1         (X3SW | X3GEXEC | X3DIM | X3GRC3 | X3GOFFEX | X3GREM)
194 #define XSHUT0        (X0SH)
195 
196 /* KaKu module type attributes */
197 #define KAM           (KOFF | KON | KGOFF | KGON)
198 #define KLM           (KAM | KPRE | KGPRE | KRESUME)
199 
200 /* Module option functions */
201 int opt_onlevel(), opt_sremote(), opt_kremote(), opt_sensor(), opt_svsensor(), opt_ds90(), opt_sd90(),
202 opt_ur81a(), opt_ux17a(), opt_guru(), opt_aux(), opt_rfxsensor(), opt_rfxold(), opt_act(), opt_defer(),
203 opt_rfxtemp(),
204 opt_rfxpulse(), opt_rfxcount(), opt_rfxpower(), opt_rfxwater(), opt_rfxgas(),
205 opt_sd10(), opt_plcsensor(), opt_gb10(), opt_jam(), opt_digimax(),
206 opt_oreTH1(), opt_oreTH2(), opt_oreTH3(), opt_oreTH4(), opt_oreTH5(), opt_oreTH6(),
207 opt_oreTemp1(), opt_oreTemp2(), opt_oreTemp3(), opt_oreTHB1(), opt_oreTHB2(), opt_oreWeight1(),
208 opt_oreTemu(), opt_oreTHemu(), opt_oreTHBemu(), opt_x10std(), opt_oreignore(), opt_elsElec1(),
209 opt_bmb_sd18(),
210 opt_secignore(), opt_visonic(),
211 opt_oreWind1(), opt_oreWind2(), opt_oreWind3(),
212 opt_oreRain1(), opt_oreRain2(), opt_oreRain3(),
213 opt_oreUV1(), opt_oreUV2(), opt_kaku(), opt_owlElec2(), opt_owlElec2new(), opt_owlElec2rev();
214 
215 /* Decoder functions for modules */
216 int fn_ds10a(), fn_ds90(), fn_ms10a(), fn_sh624(), fn_kr10a(), fn_ur81a(),
217 fn_guru(), fn_rfxsensor(),
218 fn_rfxpulse(), fn_rfxcount(), fn_rfxpower(), fn_rfxwater(), fn_rfxgas(),
219 fn_sd10(), fn_sd90(), fn_ms90(), fn_ds18(), fn_gb10(), fn_svdata(), fn_jam(),
220 fn_kr15a(), fn_kr18(), fn_dm10(), fn_bmb_sd18(), fn_visonic();
221 
222 extern int ore_maxmin_temp ( ALIAS *, int, char **, int * );
223 extern int ore_maxmin_rh ( ALIAS *, int, char **, int * );
224 extern int ore_maxmin_bp ( ALIAS *, int, char **, int * );
225 extern double celsius2temp ( double, char, double);
226 int sensor_timeout ( ALIAS *, int, char **, int * );
227 
228 
229 
230 struct modules_st {
231   char           *label;  /* Case insensitive */
232   int            maxlevel;
233   unsigned long  vflags;  /* Virtual attributes */
234   unsigned long  cflags;  /* Standard attributes */
235   unsigned long  xflags;  /* Extended code attributes */
236   int (*addopt_func)();
237   int (*xlate_func)();
238 } modules[] = {
239   {"NONE",        MXLS, VNON, NOMATT,     0, NULL, NULL  },  /* Has no attributes */
240   {"StdAM",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
241   {"AM",          MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
242   {"AM486",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
243   {"AM12",        MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Marmitek Standard X10 1-way Appliance Module */
244   {"PAM01",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
245   {"AM466",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
246   {"PAM02",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
247   {"SR227",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
248   {"PA011",       MXLS, VNON, STDAM,      0, NULL, NULL  },  /* Standard X10 1-way Appliance Module */
249   {"AMS",         MXLS, VNON, AMS,        0, opt_defer, NULL  },  /* 2-way Appliance Module */
250   {"RAIN8II",     MXLS, VNON, AMS,        0, opt_defer, NULL  },  /* Rain8II 2-way Irrigation Module */
251   {"RR501",       MXLS, VNON, AMS,        0, NULL, NULL  },  /* X10 Transceiver/Switch */
252   {"PAT01",       MXLS, VNON, AMS,        0, NULL, NULL  },  /* X10 Transceiver/Switch */
253   {"ACTAMS",      MXLS, VNON, ACTBASIC,   0, opt_act, NULL}, /* ACT programmable appliance module */
254   {"RS114",       MXLS, VNON, ACTBASIC,   0, opt_act, NULL}, /* ACT programmable appliance module */
255   {"ACTAMSBUG",   MXLS, VNON, ACTBUG,     0, opt_act, NULL}, /* ACT as above with On/Off unaddress bug */
256   {"RF234",       MXLS, VNON, ACTBUG,     0, opt_act, NULL}, /* ACT as above with On/Off unaddress bug */
257   {"StdLM",       MXLS, VNON, STDLM,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Module */
258   {"LM",          MXLS, VNON, STDLM,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Module */
259   {"LM465",       MXLS, VNON, STDLM,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Module */
260   {"LM12",        MXLS, VNON, STDLM,      0, NULL, NULL  },  /* Marmitek X10 1-way Lamp Module */
261   {"LM465-1",     MXLE, VNON, LM_1,   XLM_1, NULL, NULL  },  /* Redesigned (2007) X10 1-way Lamp Module */
262   {"LM-1",        MXLE, VNON, LM_1,   XLM_1, NULL, NULL  },  /* Redesigned (2007) X10 1-way Lamp Module */
263   {"PLM03",       MXLS, VNON, STDLM,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Module */
264   {"PLM01",       MXLS, VNON, STDLM,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Module */
265   {"StdWS",       MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Wall Switch */
266   {"WS",          MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Wall Switch */
267   {"WS467",       MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Wall Switch */
268   {"LW10U",       MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Marmitek Standard X10 1-way Lamp Wall Switch */
269   {"PLW01",       MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Wall Switch */
270   {"WS477",       MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Standard X10 3-way Lamp Wall Switch */
271   {"PLW02",       MXLS, VNON, STDWS,      0, NULL, NULL  },  /* Standard X10 1-way Lamp Wall Switch */
272   {"WS467-1",     MXLE, VNON,  WS_1,  XWS_1, NULL, NULL  },  /* Redesigned (2007) X10 1-way Lamp Wall Switch */
273   {"WS-1",        MXLE, VNON,  WS_1,  XWS_1, NULL, NULL  },  /* Redesigned (2007) X10 1-way Lamp Wall Switch */
274   {"WS12A",       MXLS, VNON, XPD3,       0, NULL, NULL  },  /* X10 1-way Lamp Wall Switch */
275   {"XPD3",        MXLS, VNON, XPD3,       0, NULL, NULL  },  /* X10 Pro 1-way Lamp Wall Switch */
276   {"WS13A",       MXLS, VNON, XPS3,       0, NULL, NULL  },  /* X10 1-way non-dimming Wall Switch */
277   {"XPS3",        MXLS, VNON, XPS3,       0, NULL, NULL  },  /* X10 Pro 1-way non-dimming Wall Switch */
278   {"LM15A",       MXLS, VNON, LM15A,      0, NULL, NULL  },  /* X10 LM15A Socket Rocket */
279   {"LM15",        MXLS, VNON, LM15A,      0, NULL, NULL  },  /* Marmitek Socket Rocket */
280   {"PSM04",       MXLS, VNON, LM15A,      0, NULL, NULL  },  /* X10 Pro Socket Rocket */
281   {"LMS",         MXLS, VNON, LMS,        0, NULL, NULL  },  /* 2-way Lamp Module */
282   {"PR511",       MXLS, VNON, PR511,      0, NULL, NULL  },  /* X10 2-way Motion Sensor floodlight */
283   {"PHS01",       MXLS, VNON, PR511,      0, NULL, NULL  },  /* X10 Pro 2-way Motion Sensor floodlight */
284   {"AM14A",       MXLEA, VNON, AM14A, XAM14A, NULL, NULL  },  /* X10 2-way Appliance Module, 2-pin (AM14A) */
285   {"PAM21",       MXLEA, VNON, AM14A, XAM14A, NULL, NULL  },  /* X10 2-way Appliance Module, 2-pin (AM14A) */
286   {"AM15A",       MXLEA, VNON, AM14A, XAM14A, NULL, NULL  },  /* X10 2-way Appliance Module, 3-pin (AM15A) */
287   {"PAM22",       MXLEA, VNON, AM14A, XAM14A, NULL, NULL  },  /* X10 2-way Appliance Module, 3-pin (AM15A) */
288   {"LM14A",       MXLE, VNON, LM14A, XLM14A, NULL, NULL  },  /* X10 2-way Lamp Module (LM14A) */
289   {"PLM21",       MXLE, VNON, LM14A, XLM14A, NULL, NULL  },  /* X10 2-way Lamp Module (LM14A) */
290   {"SL1AM",       MXLP, VNON, SL1AM,      0, NULL, NULL  },  /* SwitchLinc 1-way Switch */
291   {"SL2AM",       MXLP, VNON, SL2AM,      0, NULL, NULL  },  /* SwitchLinc 2-way Switch */
292   {"SL1LM",       MXLP, VNON, SL1LM,      0, opt_onlevel, NULL  },  /* SwitchLinc 1-way Lamp Module */
293   {"SL2LM",       MXLP, VNON, SL2LM,      0, opt_onlevel, NULL  },  /* SwitchLinc 2-way Lamp Module */
294   {"SL2380W",     MXLP, VNON, SL2LM,      0, opt_onlevel, NULL  },  /* SwitchLinc 2380W Dimmer */
295   {"LL1LM",       MXLP, VNON, LL1LM,      0, opt_onlevel, NULL  },  /* LampLinc 1-way Dimmer */
296   {"LL2LM",       MXLP, VNON, LL2LM,      0, opt_onlevel, NULL  },  /* LampLink 2-way Dimmer */
297   {"LL2000STW",   MXLP, VNON, LL2LM,      0, opt_onlevel, NULL  },  /* LampLinc 2000STW Dimmer */
298   {"REMOTE2",     MXLS, VNON, REM2,       0, NULL, NULL  },  /* Remote transmitter, 2 function */
299   {"REMOTE3",     MXLS, VNON, REM3,       0, NULL, NULL  },  /* Remote transmitter, 3 function */
300   {"REMOTE4",     MXLS, VNON, REM4,       0, NULL, NULL  },  /* Remote transmitter, 4 function */
301   {"REMOTE6",     MXLS, VNON, REM6,       0, NULL, NULL  },  /* Remote transmitter, 6 function */
302   {"REMOTEP",     MXLP, VNON, PRESET,     0, NULL, NULL  },  /* Remote transmitter, Preset 1-32 only */
303   {"AMEXC",       MXLS, VNON, AMEXC16,    0, NULL, NULL  },  /* AM with exclusive-16 addressing */
304   {"AMEXC16",     MXLS, VNON, AMEXC16,    0, NULL, NULL  },  /* AM with exclusive addressing */
305   {"AMEXC8",      MXLS, VNON, AMEXC8,     0, NULL, NULL  },  /* AM with exclusive-8 addressing */
306   {"RAIN8",       MXLS, VNON, AMEXC8,     0, NULL, NULL  },  /* WGL Rain8 irrigation controller */
307   {"AMEXC4",      MXLS, VNON, AMEXC4,     0, NULL, NULL  },  /* AM with exclusive-4 addressing */
308   {"XM10A",       MXLS, VNON, CAMEXC4,    0, NULL, NULL  },  /* X10 camera power supply */
309   {"XM13A",       MXLS, VNON, CAMEXC4,    0, NULL, NULL  },  /* X10 camera power supply */
310   {"XM14A",       MXLS, VNON, CAMEXC4,    0, NULL, NULL  },  /* X10 pan/tilt power supply */
311   {"VIRT4",       MXLV, VSTD, VIRT4,      0, opt_onlevel, NULL  },  /* Virtual module, 4 function */
312   {"VDATA",       MXLV, VSTD, VIRTUAL,    0, NULL, NULL  },  /* Virtual module data */
313   {"PLCSENSOR",   MXLS, VSTD, PLCSEN,     0, opt_plcsensor, NULL  },  /* PLC Sensor target */
314 #ifdef HASEXT0
315   {"SHUTTER",     MXLS0, VNON, SHUT0, XSHUT0, NULL, NULL  },  /* Extended code Type 0 shutter */
316   {"SW10",        MXLS0, VNON, SHUT0, XSHUT0, NULL, NULL  },  /* Marmitek SW10 shutter control */
317 #endif
318 
319   {"DS10A",       MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ds10a }, /* X-10 USA D/W sensor */
320   {"DS10",        MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ds10a }, /* Marmitek D/W sensor */
321   {"DS10E",       MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ds10a }, /* Marmitek D/W sensor */
322   {"PDS01",       MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ds10a }, /* X10 Pro D/W sensor */
323   {"DS18",        MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ds18 }, /* ElekHomica D/W sensor, old? */
324   {"DS90",        MXLV, VSEC, VIRTUAL,    0, opt_ds90, fn_ds90 },   /* Marmitek D/W sensor */
325   {"DS18-1",      MXLV, VSEC, VIRTUAL,    0, opt_ds90, fn_ds90 },   /* ElekHomica D/W sensor */
326 
327   {"MS10A",       MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ms10a },
328   {"MS90",        MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ms90 }, /* Marmitek Motion sensor */
329   {"MS18E",       MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ms90 }, /* BMB Home Solutions Motion sensor */
330   {"SD10",        MXLV, VSEC, VIRTUAL,    0, opt_sd10, fn_sd10 },
331   {"BMB-SD18",    MXLV, VSEC, VIRTUAL,    0, opt_bmb_sd18, fn_bmb_sd18}, /* BMB Smoke Detector */
332   {"EH-CWSD10",   MXLV, VSEC, VIRTUAL,    0, opt_sd10, fn_sd10 }, /* ElekHomica Smoke detector */
333   {"EH-WD210",    MXLV, VSEC, VIRTUAL,    0, opt_sd10, fn_sd10 }, /* ElekHomica Water detector */
334   {"GB10",        MXLV, VSEC, VIRTUAL,    0, opt_gb10, fn_gb10 }, /* Marmitek Glass Break detector */
335   {"DM10",        MXLV, VSEC, VIRTUAL,    0, opt_gb10, fn_dm10 }, /* Marmitek DM10 Motion/Dawn/Dusk sensor */
336   {"SD90",        MXLV, VSEC, VIRTUAL,    0, opt_sd90, fn_sd90 }, /* Marmitek Smoke detector */
337   {"PMS01",       MXLV, VSEC, VIRTUAL,    0, opt_sensor, fn_ms10a },
338   {"SH624",       MXLV, VSEC, VIRTUAL,    0, opt_sremote, fn_sh624 }, /* Full size remotes */
339   {"PSR01",       MXLV, VSEC, VIRTUAL,    0, opt_sremote, fn_sh624 },
340   {"KR18",        MXLV, VSEC, VIRTUAL,    0, opt_kremote, fn_kr18 }, /* Keyfob remotes */
341   {"KR18E",       MXLV, VSEC, VIRTUAL,    0, opt_kremote, fn_kr18 },
342   {"KR10A",       MXLV, VSEC, VIRTUAL,    0, opt_kremote, fn_kr10a },
343   {"KR21",        MXLV, VSEC, VIRTUAL,    0, opt_kremote, fn_kr10a },
344   {"PKR02",       MXLV, VSEC, VIRTUAL,    0, opt_kremote, fn_kr10a },
345   {"KR15A",       MXLV, VSEC, VIRTUAL,    0, opt_sremote, fn_kr15a }, /* Big Red Button */
346   {"SVDATA",      MXLV, VSEC, VIRTUAL,    0, opt_sremote, fn_svdata }, /* Generic security remote */
347   {"SSVDATA",     MXLV, VSEC, VIRTUAL,    0, opt_svsensor, fn_svdata }, /* Generic security sensor */
348   {"SEC_IGNORE",  MXLV, VSEC, VIRTUAL,    0, opt_secignore, NULL },
349   {"UR81A",       MXLV, VENT, VIRTUAL,    0, opt_ur81a, fn_ur81a },
350   {"UR51A",       MXLV, VENT, VIRTUAL,    0, opt_ur81a, fn_ur81a },
351   {"UX17A",       MXLV, VENT, VIRTUAL,    0, opt_ux17a, NULL },
352   {"UX23A",       MXLV, VENT, VIRTUAL,    0, opt_ux17a, NULL },
353   {"GURU",        MXLV, VENT, VIRTUAL,    0, opt_guru, fn_guru },
354   {"PALMPAD",     MXLS, VSTD, PALMPAD,    0, opt_aux, NULL},
355   {"KR19A",       MXLS, VSTD, PALMPAD,    0, opt_aux, NULL},
356   {"KR22",        MXLS, VSTD, PALMPAD,    0, opt_aux, NULL},
357   {"KEYCHAIN",    MXLS, VSTD, KEYCHAIN,   0, opt_aux, NULL},
358   {"ONLYON",      MXLS, VSTD, ONLYON,     0, opt_aux, NULL},
359   {"ONLYOFF",     MXLS, VSTD, ONLYOFF,    0, opt_aux, NULL},
360   {"MS12",        MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
361   {"MS12A",       MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
362   {"MS13",        MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
363   {"MS13A",       MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
364   {"MS14",        MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
365   {"MS14A",       MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
366   {"MS16",        MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
367   {"MS16A",       MXLS, VSTD, MOTION,     0, opt_x10std, NULL},
368 
369 #ifdef HASORE
370   {"ORE_TH1",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH1, NULL},
371   {"THGR122NX",   MXLV, VORE,  VIRTUAL,   0, opt_oreTH1, NULL},
372   {"THGN123N",    MXLV, VORE,  VIRTUAL,   0, opt_oreTH1, NULL},
373   {"THGR228N",    MXLV, VORE,  VIRTUAL,   0, opt_oreTH1, NULL},
374   {"ORE_TH2",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH2, NULL},
375   {"THGN800",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH2, NULL},
376   {"THGR800",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH2, NULL},
377   {"THGR810",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH2, NULL},
378   {"ORE_TH3",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH3, NULL},
379   {"RTGN318",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH3, NULL},
380   {"RTGR328N",    MXLV, VORE,  VIRTUAL,   0, opt_oreTH3, NULL},
381   {"ORE_TH4",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH4, NULL},
382   {"ORE_TH5",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH5, NULL},
383   {"ORE_TH6",     MXLV, VORE,  VIRTUAL,   0, opt_oreTH6, NULL},
384   {"THGR918N",    MXLV, VORE,  VIRTUAL,   0, opt_oreTH6, NULL},
385   {"ORE_T1",      MXLV, VORE,  VIRTUAL,   0, opt_oreTemp1, NULL},
386   {"THR138",      MXLV, VORE,  VIRTUAL,   0, opt_oreTemp1, NULL},
387   {"ORE_T2",      MXLV, VORE,  VIRTUAL,   0, opt_oreTemp2, NULL},
388   {"THRN122N",    MXLV, VORE,  VIRTUAL,   0, opt_oreTemp2, NULL},
389   {"THN122N",     MXLV, VORE,  VIRTUAL,   0, opt_oreTemp2, NULL},
390   {"THN132N",     MXLV, VORE,  VIRTUAL,   0, opt_oreTemp2, NULL},
391   {"ORE_T3",      MXLV, VORE,  VIRTUAL,   0, opt_oreTemp3, NULL},
392   {"ORE_THB1",    MXLV, VORE,  VIRTUAL,   0, opt_oreTHB1, NULL},
393   {"BTHR918",     MXLV, VORE,  VIRTUAL,   0, opt_oreTHB1, NULL},
394   {"ORE_THB2",    MXLV, VORE,  VIRTUAL,   0, opt_oreTHB2, NULL},
395   {"BTHR968",     MXLV, VORE,  VIRTUAL,   0, opt_oreTHB2, NULL},
396   {"BTHR918N",    MXLV, VORE,  VIRTUAL,   0, opt_oreTHB2, NULL},
397   {"ORE_WGT1",    MXLV, VORE,  VIRTUAL,   0, opt_oreWeight1, NULL},
398   {"BWR102",      MXLV, VORE,  VIRTUAL,   0, opt_oreWeight1, NULL},
399   {"ORE_TEMU",    MXLV, VORE,  VIRTUAL,   0, opt_oreTemu,   NULL},  /* Dummy */
400   {"ORE_THEMU",   MXLV, VORE,  VIRTUAL,   0, opt_oreTHemu,  NULL},  /* Dummy */
401   {"ORE_THBEMU",  MXLV, VORE,  VIRTUAL,   0, opt_oreTHBemu, NULL},  /* Dummy */
402   {"ORE_IGNORE",  MXLV, VORE,  VIRTUAL,   0, opt_oreignore, NULL},
403   {"ORE_WIND1",   MXLV, VORE,  VIRTUAL,   0, opt_oreWind1, NULL},
404   {"ORE_WIND2",   MXLV, VORE,  VIRTUAL,   0, opt_oreWind2, NULL},
405   {"WGR800",      MXLV, VORE,  VIRTUAL,   0, opt_oreWind2, NULL},
406   {"ORE_WIND3",   MXLV, VORE,  VIRTUAL,   0, opt_oreWind3, NULL},
407   {"WGR918N",     MXLV, VORE,  VIRTUAL,   0, opt_oreWind3, NULL},
408   {"ORE_RAIN1",   MXLV, VORE,  VIRTUAL,   0, opt_oreRain1, NULL},
409   {"PCR918N",     MXLV, VORE,  VIRTUAL,   0, opt_oreRain1, NULL},
410   {"ORE_RAIN2",   MXLV, VORE,  VIRTUAL,   0, opt_oreRain2, NULL},
411   {"PCR800",      MXLV, VORE,  VIRTUAL,   0, opt_oreRain2, NULL},
412   {"ORE_RAIN3",   MXLV, VORE,  VIRTUAL,   0, opt_oreRain3, NULL},
413   {"ELS_CM113",   MXLV, VORE,  VIRTUAL,   0, opt_elsElec1, NULL},
414   {"ELS_ELEC1",   MXLV, VORE,  VIRTUAL,   0, opt_elsElec1, NULL},
415   {"ORE_ELS",     MXLV, VORE,  VIRTUAL,   0, opt_elsElec1, NULL},
416   {"ORE_UV1",     MXLV, VORE,  VIRTUAL,   0, opt_oreUV1, NULL},
417   {"ORE_UV2",     MXLV, VORE,  VIRTUAL,   0, opt_oreUV2, NULL},
418   {"OWL_ELEC2",   MXLV, VORE,  VIRTUAL,   0, opt_owlElec2new, NULL},
419 #endif /* HASORE */
420 
421 #ifdef HASRFXS
422   {"RFXSENSOR",   MXLV, VRFXS, VIRTUAL,   0, opt_rfxsensor, fn_rfxsensor},
423 #endif /* HASRFXS */
424 
425 #ifdef HASRFXM
426   {"RFXCOUNT",    MXLV, VRFXM, VIRTUAL,   0, opt_rfxcount, fn_rfxcount},
427   {"RFXPOWER",    MXLV, VRFXM, VIRTUAL,   0, opt_rfxpower, fn_rfxpower},
428   {"RFXWATER",    MXLV, VRFXM, VIRTUAL,   0, opt_rfxwater, fn_rfxwater},
429   {"RFXGAS",      MXLV, VRFXM, VIRTUAL,   0, opt_rfxgas, fn_rfxgas},
430   {"RFXPULSE",    MXLV, VRFXM, VIRTUAL,   0, opt_rfxpulse, fn_rfxpulse},
431 #endif /* HASRFXM */
432 
433 #ifdef HASDMX
434   {"DIGIMAX",     MXLV, VDMX,  VIRTUAL,   0, opt_digimax, NULL},
435 #endif /* HASDMX */
436 
437 #ifdef HASKAKU
438   {"KAKU_S",      MXLK, VKAKU, KAM,       0, opt_kaku, NULL},
439   {"KAKU_P",      MXLK, VKAKU, KLM,       0, opt_kaku, NULL},
440 #endif /* HASKAKU */
441 
442   {"VISGEN",     MXLV, VSEC, VIRTUAL,    0, opt_visonic, fn_visonic }, /* Generic Visonic */
443 
444 };
445 static int ntypes = (sizeof(modules)/sizeof(struct modules_st));
446 
447 unsigned int modmask[NumModMasks][16];
448 unsigned int vmodmask[NumVmodMasks][16];
449 unsigned int kmodmask[NumKmodMasks][16];
450 unsigned char maxdimlevel[16][16];
451 unsigned char ondimlevel[16][16];
452 
453 extern CONFIG config;
454 extern CONFIG *configp;
455 
456 
457 /*-------------------------------------------------------+
458  | Return a pointer to a module xlate_func()             |
459  +-------------------------------------------------------*/
module_xlate_func(int index)460 int (*module_xlate_func(int index))()
461 {
462    return modules[index].xlate_func;
463 }
464 
465 /*-------------------------------------------------------+
466  | Return the index in the module table for the argument |
467  | name, or -1 if not found                              |
468  | The comparison is case insensitive                    |
469  +-------------------------------------------------------*/
lookup_module_type(char * modelname)470 int lookup_module_type ( char *modelname )
471 {
472    char buffer[NAME_LEN + 1], label[NAME_LEN + 1];
473    int  j;
474 
475    strncpy2(buffer, modelname, sizeof(buffer) - 1);
476    strupper(buffer);
477 
478    for ( j = 0; j < ntypes; j++ ) {
479       strncpy2(label, modules[j].label, sizeof(label) - 1);
480       strupper(label);
481       if ( strcmp(buffer, label) == 0 )
482          return j;
483    }
484 
485    return -1;
486 }
487 
488 /*-------------------------------------------------------+
489  | Pass back through the argument list the flags and     |
490  | maxlevel values for module index 'module_type'        |
491  +-------------------------------------------------------*/
module_attributes(int module_type,unsigned long * vflags,unsigned long * cflags,unsigned long * xflags,unsigned long * kflags,int * maxlevel)492 void module_attributes ( int module_type,
493       unsigned long *vflags, unsigned long *cflags,
494       unsigned long *xflags, unsigned long *kflags, int *maxlevel )
495 {
496    if ( module_type >= 0 ) {
497       *vflags = modules[module_type].vflags;
498       *cflags = modules[module_type].cflags;
499       if ( *vflags & VKAKU ) {
500          *kflags = *cflags;
501          *cflags = 0;
502       }
503       else {
504          *kflags = 0;
505       }
506       *xflags = modules[module_type].xflags;
507       *maxlevel = modules[module_type].maxlevel;
508    }
509    else {
510       *vflags = 0;
511       *cflags = 0;
512       *xflags = 0;
513       *kflags = 0;
514       *maxlevel = 0;
515    }
516    return;
517 }
518 
519 /*-------------------------------------------------------+
520  | Called by add_alias() to add options specified on the |
521  | ALIAS line in the config file.                        |
522  +-------------------------------------------------------*/
add_module_options(ALIAS * aliasp,int aliasindex,char ** tokens,int ntokens)523 int add_module_options ( ALIAS *aliasp, int aliasindex,
524                                char **tokens, int ntokens )
525 {
526    int type;
527 
528    type = aliasp[aliasindex].modtype;
529 
530    if ( modules[type].addopt_func == NULL ) {
531       if ( ntokens > 0 ) {
532          store_error_message("No parameters are supported for this module type.");
533          return 1;
534       }
535       return 0;
536    }
537 
538    return modules[type].addopt_func(aliasp, aliasindex, tokens, &ntokens);
539 }
540 
541 
542 /*-------------------------------------------------------+
543  | Display options specified for an ALIAS.               |
544  +-------------------------------------------------------*/
display_module_options(int aliasindex)545 char *display_module_options (int aliasindex )
546 {
547    static   char buffer[128];
548    ALIAS    *aliasp;
549    long int optflags, optflags2;
550    int      j, k;
551    int      rh;
552    double   tempc, bp;
553    char     keystr[4], grpstr[4];
554    long     secs;
555 
556    aliasp = configp->aliasp;
557 
558    if ( !aliasp )
559       return "";
560 
561 
562    optflags  = aliasp[aliasindex].optflags;
563    optflags2 = aliasp[aliasindex].optflags2;
564 
565    buffer[0] = '\0';
566 
567    if ( optflags & MOPT_RESUME )
568       sprintf(buffer, "ONLEVEL RESUME");
569    else if ( optflags & MOPT_ONFULL && aliasp[aliasindex].flags & PRESET)
570       sprintf(buffer, "ONLEVEL %d", aliasp[aliasindex].onlevel + 1);
571    else if ( optflags & MOPT_ONFULL )
572       sprintf(buffer, "ONLEVEL %d", aliasp[aliasindex].onlevel);
573 
574    if ( optflags & MOPT_SECURITY || optflags & MOPT_ENTERTAIN ) {
575       buffer[0] = '\0';
576       for ( j = 0; j < aliasp[aliasindex].nident; j++ )
577          sprintf(buffer + strlen(buffer), "0x%02lx ", aliasp[aliasindex].ident[j]);
578    }
579 
580    if ( optflags & MOPT_MAIN ) strcat(buffer, "MAIN ");
581    if ( optflags & MOPT_AUX )  strcat(buffer, "AUX ");
582 
583    if ( optflags & MOPT_TRANSCEIVE ) strcat(buffer, "TRANSCEIVE ");
584    if ( optflags & MOPT_RFFORWARD )  strcat(buffer, "RFFORWARD ");
585    if ( optflags & MOPT_RFIGNORE )   strcat(buffer, "RFIGNORE ");
586    if ( optflags & MOPT_REVERSE )    strcat(buffer, "REVERSE ");
587 
588    if ( optflags2 & MOPT2_DUMMY )    strcat(buffer, "DUMMY ");
589 
590    if ( optflags & MOPT_RFXSENSOR ) {
591       sprintf(buffer + strlen(buffer), "0x%02lx ", aliasp[aliasindex].ident[0]);
592       strcat(buffer, "T");
593       if ( optflags & MOPT_RFXRH )       strcat(buffer, "H ");
594       else if ( optflags & MOPT_RFXBP )  strcat(buffer, "B ");
595       else if ( optflags & MOPT_RFXVAD ) strcat(buffer, "V ");
596       else if ( optflags & MOPT_RFXPOT ) strcat(buffer, "P ");
597       else if ( optflags & MOPT_RFXT2 )  strcat(buffer, "T ");
598       else strcat(buffer, " ");
599    }
600 
601    if ( optflags & MOPT_RFXMETER ) {
602       sprintf(buffer + strlen(buffer), "0x%02lx ", aliasp[aliasindex].ident[0]);
603    }
604 
605    if ( optflags & MOPT_KAKU ) {
606       for ( j = 0; j < aliasp[aliasindex].nident; j++ ) {
607          *keystr = '\0';
608          for ( k = 0; k < 16; k++ ) {
609             if ( aliasp[aliasindex].kaku_keymap[j] & (1 << k) ) {
610                sprintf(keystr, "%d", k + 1);
611                break;
612             }
613          }
614          *grpstr = '\0';
615          for ( k = 0; k < 16; k++ ) {
616             if ( aliasp[aliasindex].kaku_grpmap[j] & (1 << k) ) {
617                sprintf(grpstr, "%c", k + 'A');
618                break;
619             }
620          }
621 
622          sprintf(buffer + strlen(buffer), "0x%07lx %s%s ",
623            aliasp[aliasindex].ident[j], keystr, grpstr);
624       }
625    }
626 
627    if ( optflags2 & MOPT2_TMIN ) {
628       tempc = (double)aliasp[aliasindex].tmin / 10.0;
629       sprintf(buffer + strlen(buffer), "TMIN "FMT_ORET"%c ",
630         celsius2temp(tempc, configp->ore_tscale, 0.0), configp->ore_tscale );
631    }
632    if ( optflags2 & MOPT2_TMAX ) {
633       tempc = (double)aliasp[aliasindex].tmax / 10.0;
634       sprintf(buffer + strlen(buffer), "TMAX "FMT_ORET"%c ",
635         celsius2temp(tempc, configp->ore_tscale, 0.0), configp->ore_tscale );
636    }
637    if ( optflags2 & MOPT2_RHMIN ) {
638       rh = aliasp[aliasindex].rhmin;
639       sprintf(buffer + strlen(buffer), "RHMIN %d%% ", rh);
640    }
641    if ( optflags2 & MOPT2_RHMAX ) {
642       rh = aliasp[aliasindex].rhmax;
643       sprintf(buffer + strlen(buffer), "RHMAX %d%% ", rh);
644    }
645    if ( optflags2 & MOPT2_BPMIN ) {
646       bp = (double)aliasp[aliasindex].bpmin;
647       sprintf(buffer + strlen(buffer), "BPMIN "FMT_OREBP"%s ",
648         (bp * configp->ore_bpscale) + configp->ore_bpoffset, configp->ore_bpunits );
649    }
650    if ( optflags2 & MOPT2_BPMAX ) {
651       bp = (double)aliasp[aliasindex].bpmax;
652       sprintf(buffer + strlen(buffer), "BPMAX "FMT_OREBP"%s ",
653         (bp * configp->ore_bpscale) + configp->ore_bpoffset, configp->ore_bpunits );
654    }
655 
656    if ( optflags2 & MOPT2_SWHOME ) {
657       strcat(buffer + strlen(buffer), "SWHOME ");
658    }
659    if ( optflags2 & MOPT2_SWMAX ) {
660       strcat(buffer + strlen(buffer), "SWMAX ");
661    }
662    if ( optflags2 & MOPT2_DUMMY ) {
663       strcat(buffer + strlen(buffer), "DUMMY ");
664    }
665 
666    /* Inactive timeout */
667    if ( optflags2 & MOPT2_IATO ) {
668       secs = aliasp[aliasindex].hb_timeout;
669       sprintf(buffer + strlen(buffer), "IATO %ld:%02ld:%02ld ", (secs / 3600L), (secs % 3600L) / 60L, (secs % 60));
670    }
671 
672    /* ACT module options */
673    if ( optflags2 & MOPT2_AUF ) {
674       sprintf(buffer + strlen(buffer), "AUF ");
675    }
676    if ( optflags2 & MOPT2_ALO ) {
677       sprintf(buffer + strlen(buffer), "ALO ");
678    }
679    if ( optflags2 & MOPT2_ALF ) {
680       sprintf(buffer + strlen(buffer), "ALF ");
681    }
682 
683    /* Defer update for 2-way modules with auto status response */
684    if ( optflags2 & MOPT2_DEFER ) {
685       sprintf(buffer + strlen(buffer), "DEFER ");
686    }
687 
688    return buffer;
689 }
690 
691 
692 /*-------------------------------------------------------+
693  | Return a pointer to the module name corresponding to  |
694  | the argument module_type.                             |
695  +-------------------------------------------------------*/
lookup_module_name(int module_type)696 char *lookup_module_name ( int module_type )
697 {
698 
699    if ( module_type >= 0 && module_type < ntypes )
700       return modules[module_type].label;
701 
702    return "";
703 }
704 
705 /*-------------------------------------------------------+
706  | Create the state filter determined by characteristics |
707  | of each module defined in the config file.            |
708  +-------------------------------------------------------*/
set_module_masks(ALIAS * aliasp)709 void set_module_masks ( ALIAS *aliasp )
710 {
711    int j, ucode;
712    unsigned char hcode, maxlevel, onlevel;
713    unsigned int  bitmap, vflags, cflags, xflags, kflags;
714    unsigned int  defined[16];
715 
716    if ( configp->module_types == NO ) {
717       for ( j = 0; j < NumModMasks; j++ ) {
718          for ( hcode = 0; hcode < 16; hcode++ )
719             modmask[j][hcode] = 0xffff;
720       }
721       return;
722    }
723 
724    /* Default for undefined modules */
725    vflags = modules[configp->default_module].vflags;
726    cflags = modules[configp->default_module].cflags;
727    if ( vflags & VKAKU ) {
728       kflags = cflags;
729       cflags = 0;
730    }
731    else {
732       kflags = 0;
733    }
734    xflags = modules[configp->default_module].xflags;
735    maxlevel = modules[configp->default_module].maxlevel;
736 
737    /* Record housecode|units with defined module type */
738    for ( j = 0; j < 16; j++ ) {
739       defined[j] = 0;
740    }
741    j = 0;
742    while ( aliasp && aliasp[j].line_no > 0 ) {
743       if ( aliasp[j].modtype >= 0 ) {
744          /* Module is defined */
745          hcode = hc2code(aliasp[j].housecode);
746          defined[hcode] |= aliasp[j].unitbmap;
747       }
748       j++;
749    }
750 
751    /* Initialize to zero */
752    for ( j = 0; j < NumModMasks; j++ ) {
753       for ( hcode = 0; hcode < 16; hcode++ )
754          modmask[j][hcode] = 0;
755    }
756    for ( j = 0; j < NumVmodMasks; j++ ) {
757       for ( hcode = 0; hcode < 16; hcode++ )
758          vmodmask[j][hcode] = 0;
759    }
760    for ( j = 0; j < NumKmodMasks; j++ ) {
761       for ( hcode = 0; hcode < 16; hcode++ )
762          kmodmask[j][hcode] = 0;
763    }
764 
765    /* Set the characteristic of undefined modules */
766    for ( hcode = 0; hcode < 16; hcode++ ) {
767       bitmap = ~defined[hcode];
768 
769       /* Mark units which respond */
770       if ( cflags & ADDRESSED )
771          modmask[AddrMask][hcode] = bitmap;
772       if ( cflags & PHYS )
773          modmask[PhysMask][hcode] = bitmap;
774       if ( cflags & UNOFF )
775          modmask[AllOffMask][hcode] = bitmap;
776       if ( cflags & LION )
777          modmask[LightsOnMask][hcode] = bitmap;
778       if ( cflags & MON )
779          modmask[OnMask][hcode] = bitmap;
780       if ( cflags & MOFF )
781          modmask[OffMask][hcode] = bitmap;
782       if ( cflags & DIM )
783          modmask[DimMask][hcode] = bitmap;
784       if ( cflags & BRI )
785          modmask[BriMask][hcode] = bitmap;
786       if ( cflags & LIOFF )
787          modmask[LightsOffMask][hcode] = bitmap;
788       if ( cflags & BRIB4DIM )
789          modmask[BriDimMask][hcode] = bitmap;
790       if ( cflags & STDX10 )
791          modmask[StdMask][hcode] = bitmap;
792       if ( cflags & PRESET )
793          modmask[PresetMask][hcode] = bitmap;
794       if ( cflags & STAREQ )
795          modmask[StatusMask][hcode] = bitmap;
796       if ( cflags & STAON )
797          modmask[StatusOnMask][hcode] = bitmap;
798       if ( cflags & STAOFF )
799          modmask[StatusOffMask][hcode] = bitmap;
800       if ( cflags & LIONFULL )
801          modmask[LightsOnFullMask][hcode] = bitmap;
802       if ( cflags & ONFULL )
803          modmask[OnFullMask][hcode] = bitmap;
804       if ( cflags & ONFULLOFF )
805          modmask[OnFullOffMask][hcode] = bitmap;
806       if ( cflags & ALLON )
807          modmask[AllOnMask][hcode] = bitmap;
808       if ( cflags & RESUME )
809          modmask[ResumeMask][hcode] = bitmap;
810       if ( cflags & TARG )
811          modmask[TargMask][hcode] = bitmap;
812       if ( cflags & EXC16 )
813          modmask[Exc16Mask][hcode] = bitmap;
814       if ( cflags & EXC8 )
815          modmask[Exc8Mask][hcode] = bitmap;
816       if ( cflags & EXC4 )
817          modmask[Exc4Mask][hcode] = bitmap;
818       if ( cflags & VDATA || vflags & VKAKU )
819          modmask[VdataMask][hcode] = bitmap;
820       if ( cflags & RESUMEDIM )
821          modmask[ResumeDimMask][hcode] = bitmap;
822       if ( cflags & LIONUNAD )
823          modmask[LightsOnUnaddrMask][hcode] = bitmap;
824       if ( cflags & LIOFFUNAD )
825          modmask[LightsOffUnaddrMask][hcode] = bitmap;
826       if ( cflags & PLCSENSOR )
827          modmask[PlcSensorMask][hcode] = bitmap;
828       if ( cflags & ONOFFUNAD )
829          modmask[OnOffUnaddrMask][hcode] = bitmap;
830 
831       if ( xflags & X0SH )
832          modmask[Ext0Mask][hcode] = bitmap;
833 
834       if ( xflags & X3SW ) {
835          modmask[Ext3Mask][hcode] = bitmap;
836          modmask[AllOnMask][hcode] = bitmap;
837       }
838       if ( xflags & X3DIM )
839          modmask[Ext3DimMask][hcode] = bitmap;
840       if ( xflags & X3GEXEC )
841          modmask[Ext3GrpExecMask][hcode] = bitmap;
842       if ( xflags & X3GRC1 )
843          modmask[Ext3GrpRelT1Mask][hcode] = bitmap;
844       if ( xflags & X3GRC2 )
845          modmask[Ext3GrpRelT2Mask][hcode] = bitmap;
846       if ( xflags & X3GRC3 )
847          modmask[Ext3GrpRelT3Mask][hcode] = bitmap;
848       if ( xflags & X3GRC4 )
849          modmask[Ext3GrpRelT4Mask][hcode] = bitmap;
850       if ( xflags & X3GOFF )
851          modmask[Ext3GrpOffMask][hcode] = bitmap;
852       if ( xflags & X3GOFFEX )
853          modmask[Ext3GrpOffExecMask][hcode] = bitmap;
854       if ( xflags & X3GBD )
855          modmask[Ext3GrpBriDimMask][hcode] = bitmap;
856       if ( xflags & X3GBDFULL )
857          modmask[Ext3GrpBriDimFullMask][hcode] = bitmap;
858       if ( xflags & X3STAT )
859          modmask[Ext3StatusMask][hcode] = bitmap;
860       if ( xflags & X3GREM )
861          modmask[Ext3GrpRemMask][hcode] = bitmap;
862 
863       if ( vflags & VSTD )
864          vmodmask[VstdMask][hcode] = bitmap;
865       if ( vflags & VENT )
866          vmodmask[VentMask][hcode] = bitmap;
867       if ( vflags & VSEC )
868          vmodmask[VsecMask][hcode] = bitmap;
869       if ( vflags & VRFXS )
870          vmodmask[VrfxsMask][hcode] = bitmap;
871       if ( vflags & VRFXM )
872          vmodmask[VrfxmMask][hcode] = bitmap;
873       if ( vflags & VDMX )
874          vmodmask[VdmxMask][hcode] = bitmap;
875       if ( vflags & VORE )
876          vmodmask[VoreMask][hcode] = bitmap;
877       if ( vflags & VKAKU )
878          vmodmask[VkakuMask][hcode] = bitmap;
879 
880       if ( kflags & KON )
881          kmodmask[KonMask][hcode] = bitmap;
882       if ( kflags & KOFF )
883          kmodmask[KoffMask][hcode] = bitmap;
884       if ( kflags & KGON )
885          kmodmask[KGonMask][hcode] = bitmap;
886       if ( kflags & KGOFF )
887          kmodmask[KGoffMask][hcode] = bitmap;
888       if ( kflags & KPRE )
889          kmodmask[KpreMask][hcode] = bitmap;
890       if ( kflags & KGPRE )
891          kmodmask[KGpreMask][hcode] = bitmap;
892       if ( kflags & KRESUME )
893          kmodmask[KresumeMask][hcode] = bitmap;
894       if ( kflags & KPHYS )
895          kmodmask[KPhysMask][hcode] = bitmap;
896 
897       if ( !vflags || (vflags & VSTD) )
898          vmodmask[VtstampMask][hcode] = bitmap;
899 
900       /* Set max and on dim levels for each unit */
901       for ( ucode = 0; ucode < 16; ucode++ ) {
902          if ( bitmap & (1 << ucode) ) {
903             maxdimlevel[hcode][ucode] = maxlevel;
904             ondimlevel[hcode][ucode] = maxlevel;
905          }
906       }
907    }
908 
909    /* Now fill in the characteristics of defined modules */
910    j = 0;
911    while ( aliasp && aliasp[j].line_no > 0 ) {
912       if ( aliasp[j].modtype < 0 ) {
913          /* Module is undefined */
914          j++;
915          continue;
916       }
917       hcode  = hc2code(aliasp[j].housecode);
918       bitmap = aliasp[j].unitbmap;
919       cflags = aliasp[j].flags;
920       vflags = aliasp[j].vflags;
921       xflags = aliasp[j].xflags;
922       kflags = aliasp[j].kflags;
923       maxlevel = aliasp[j].maxlevel;
924       onlevel = aliasp[j].onlevel;
925 
926       /* Mark units which respond */
927       if ( cflags & ADDRESSED )
928          modmask[AddrMask][hcode] |= bitmap;
929       if ( cflags & PHYS )
930          modmask[PhysMask][hcode] |= bitmap;
931       if ( cflags & UNOFF )
932          modmask[AllOffMask][hcode] |= bitmap;
933       if ( cflags & LION )
934          modmask[LightsOnMask][hcode] |= bitmap;
935       if ( cflags & MON )
936          modmask[OnMask][hcode] |= bitmap;
937       if ( cflags & MOFF )
938          modmask[OffMask][hcode] |= bitmap;
939       if ( cflags & DIM )
940          modmask[DimMask][hcode] |= bitmap;
941       if ( cflags & BRI )
942          modmask[BriMask][hcode] |= bitmap;
943       if ( cflags & LIOFF )
944          modmask[LightsOffMask][hcode] |= bitmap;
945       if ( cflags & BRIB4DIM )
946          modmask[BriDimMask][hcode] |= bitmap;
947       if ( cflags & STDX10 )
948          modmask[StdMask][hcode] |= bitmap;
949       if ( cflags & PRESET )
950          modmask[PresetMask][hcode] |= bitmap;
951       if ( cflags & STAREQ )
952          modmask[StatusMask][hcode] |= bitmap;
953       if ( cflags & STAON )
954          modmask[StatusOnMask][hcode] |= bitmap;
955       if ( cflags & STAOFF )
956          modmask[StatusOffMask][hcode] |= bitmap;
957       if ( cflags & LIONFULL )
958          modmask[LightsOnFullMask][hcode] |= bitmap;
959       if ( cflags & ONFULL )
960          modmask[OnFullMask][hcode] |= bitmap;
961       if ( cflags & ONFULLOFF )
962          modmask[OnFullOffMask][hcode] |= bitmap;
963       if ( cflags & ALLON )
964          modmask[AllOnMask][hcode] |= bitmap;
965       if ( cflags & RESUME )
966          modmask[ResumeMask][hcode] |= bitmap;
967       if ( cflags & TARG )
968          modmask[TargMask][hcode] |= bitmap;
969       if ( cflags & EXC16 )
970          modmask[Exc16Mask][hcode] |= bitmap;
971       if ( cflags & EXC8 )
972          modmask[Exc8Mask][hcode] |= bitmap;
973       if ( cflags & EXC4 )
974          modmask[Exc4Mask][hcode] |= bitmap;
975       if ( cflags & VDATA || vflags & VKAKU )
976          modmask[VdataMask][hcode] |= bitmap;
977       if ( cflags & RESUMEDIM )
978          modmask[ResumeDimMask][hcode] |= bitmap;
979       if ( cflags & LIONUNAD )
980          modmask[LightsOnUnaddrMask][hcode] |= bitmap;
981       if ( cflags & LIOFFUNAD )
982          modmask[LightsOffUnaddrMask][hcode] |= bitmap;
983       if ( cflags & PLCSENSOR )
984          modmask[PlcSensorMask][hcode] |= bitmap;
985       if ( cflags & ONOFFUNAD )
986          modmask[OnOffUnaddrMask][hcode] |= bitmap;
987 
988       if ( xflags & X0SH )
989          modmask[Ext0Mask][hcode] |= bitmap;
990 
991       if ( xflags & X3SW ) {
992          modmask[Ext3Mask][hcode] |= bitmap;
993          modmask[AllOnMask][hcode] |= bitmap;
994       }
995       if ( xflags & X3DIM )
996          modmask[Ext3DimMask][hcode] |= bitmap;
997       if ( xflags & X3GEXEC )
998          modmask[Ext3GrpExecMask][hcode] |= bitmap;
999       if ( xflags & X3GRC1 )
1000          modmask[Ext3GrpRelT1Mask][hcode] |= bitmap;
1001       if ( xflags & X3GRC2 )
1002          modmask[Ext3GrpRelT2Mask][hcode] |= bitmap;
1003       if ( xflags & X3GRC3 )
1004          modmask[Ext3GrpRelT3Mask][hcode] |= bitmap;
1005       if ( xflags & X3GRC4 )
1006          modmask[Ext3GrpRelT4Mask][hcode] |= bitmap;
1007       if ( xflags & X3GOFF )
1008          modmask[Ext3GrpOffMask][hcode] |= bitmap;
1009       if ( xflags & X3GOFFEX )
1010          modmask[Ext3GrpOffExecMask][hcode] |= bitmap;
1011       if ( xflags & X3GBD )
1012          modmask[Ext3GrpBriDimMask][hcode] |= bitmap;
1013       if ( xflags & X3GBDFULL )
1014          modmask[Ext3GrpBriDimFullMask][hcode] |= bitmap;
1015       if ( xflags & X3STAT )
1016          modmask[Ext3StatusMask][hcode] |= bitmap;
1017       if ( xflags & X3GREM )
1018          modmask[Ext3GrpRemMask][hcode] |= bitmap;
1019 
1020       if ( kflags & KON )
1021          kmodmask[KonMask][hcode] |= bitmap;
1022       if ( kflags & KOFF )
1023          kmodmask[KoffMask][hcode] |= bitmap;
1024       if ( kflags & KGON )
1025          kmodmask[KGonMask][hcode] |= bitmap;
1026       if ( kflags & KGOFF )
1027          kmodmask[KGoffMask][hcode] |= bitmap;
1028       if ( kflags & KPRE )
1029          kmodmask[KpreMask][hcode] |= bitmap;
1030       if ( kflags & KGPRE )
1031          kmodmask[KGpreMask][hcode] |= bitmap;
1032       if ( kflags & KRESUME )
1033          kmodmask[KresumeMask][hcode] |= bitmap;
1034       if ( kflags & KPHYS )
1035          kmodmask[KPhysMask][hcode] |= bitmap;
1036 
1037       if ( vflags & VSTD )
1038          vmodmask[VstdMask][hcode] |= bitmap;
1039       if ( vflags & VENT )
1040          vmodmask[VentMask][hcode] |= bitmap;
1041       if ( vflags & VSEC )
1042          vmodmask[VsecMask][hcode] |= bitmap;
1043       if ( vflags & VRFXS )
1044          vmodmask[VrfxsMask][hcode] |= bitmap;
1045       if ( vflags & VRFXM )
1046          vmodmask[VrfxmMask][hcode] |= bitmap;
1047       if ( vflags & VDMX )
1048          vmodmask[VdmxMask][hcode] |= bitmap;
1049       if ( vflags & VORE )
1050          vmodmask[VoreMask][hcode] |= bitmap;
1051       if ( vflags & VKAKU )
1052          vmodmask[VkakuMask][hcode] |= bitmap;
1053       if ( !vflags || (vflags & VSTD) )
1054          vmodmask[VtstampMask][hcode] |= bitmap;
1055 
1056       /* ACT module options */
1057       if ( aliasp[j].optflags2 & MOPT2_AUF )
1058          modmask[AllOffMask][hcode] |= bitmap;
1059       if ( aliasp[j].optflags2 & MOPT2_ALO ) {
1060          modmask[LightsOnMask][hcode] |= bitmap;
1061          modmask[OnFullMask][hcode] |= bitmap;
1062       }
1063       if ( aliasp[j].optflags2 & MOPT2_ALF )
1064          modmask[LightsOffMask][hcode] |= bitmap;
1065 
1066       if ( aliasp[j].optflags2 & MOPT2_DEFER )
1067          modmask[DeferMask][hcode] |= bitmap;
1068 
1069 
1070       /* Set max and on dim levels for each unit */
1071       for ( ucode = 0; ucode < 16; ucode++ ) {
1072          if ( bitmap & (1 << ucode) ) {
1073             maxdimlevel[hcode][ucode] = maxlevel;
1074             ondimlevel[hcode][ucode] = onlevel;
1075          }
1076       }
1077 
1078       j++;
1079    }
1080 
1081    return;
1082 }
1083 
1084 
1085 /*-------------------------------------------------------+
1086  | Display a table indicating the module attributes      |
1087  | (either defined or defaults) for each unit            |
1088  +-------------------------------------------------------*/
show_module_mask(unsigned char hcode)1089 void show_module_mask ( unsigned char hcode )
1090 {
1091    char hc, *chr = ".*x", *chr2 = ".*?";
1092    int  j, lw = 13;
1093    unsigned int exclusive, heartbeat = 0, lobat = 0, lobatunkn = 0;
1094    ALIAS *aliasp;
1095 
1096    aliasp = configp->aliasp;
1097 
1098    hc = code2hc(hcode);
1099 
1100    j = 0;
1101    while ( aliasp && aliasp[j].line_no > 0 ) {
1102      if ( aliasp[j].housecode == hc && (aliasp[j].optflags & MOPT_HEARTBEAT) ) {
1103         heartbeat |= aliasp[j].unitbmap;
1104      }
1105      if ( aliasp[j].housecode == hc && (aliasp[j].optflags & MOPT_LOBAT) ) {
1106         lobat |= aliasp[j].unitbmap;
1107      }
1108      if ( aliasp[j].housecode == hc && (aliasp[j].optflags & MOPT_LOBATUNKN) ) {
1109         lobatunkn |= aliasp[j].unitbmap;
1110      }
1111      j++;
1112    }
1113 
1114 
1115    printf("Module Attributes\n");
1116    printf("%*s %c\n", lw + 13, "Housecode", hc);
1117    printf("%*s  1..4...8.......16\n", lw, "Unit:");
1118    printf("%*s (%s)  %s\n", lw, "On", bmap2asc(modmask[OnMask][hcode], chr),
1119       "Supports On command");
1120    printf("%*s (%s)  %s\n", lw, "Off", bmap2asc(modmask[OffMask][hcode], chr),
1121       "Supports Off command");
1122    printf("%*s (%s)  %s\n", lw, "Dim", bmap2asc(modmask[DimMask][hcode], chr),
1123       "Supports Dim (1-22) commands");
1124    printf("%*s (%s)  %s\n", lw, "Bright", bmap2asc(modmask[BriMask][hcode], chr),
1125       "Supports Bright (1-22) commands");
1126    printf("%*s (%s)  %s\n", lw, "BrightB4Dim", bmap2asc(modmask[BriDimMask][hcode], chr),
1127       "Brightens to 100% before Dim/Bright if Off");
1128    printf("%*s (%s)  %s\n", lw, "ResumeB4Dim", bmap2asc(modmask[ResumeDimMask][hcode], chr),
1129       "Resumes prev. level before Dim/Bright if Off");
1130    printf("%*s (%s)  %s\n", lw, "LightsOn", bmap2asc(modmask[LightsOnMask][hcode], chr),
1131       "Supports LightsOn (AllLightsOn) command");
1132    printf("%*s (%s)  %s\n", lw, "LightsOnFull", bmap2asc(modmask[LightsOnFullMask][hcode], chr),
1133       "LightsOn command always brightens to 100%");
1134    printf("%*s (%s)  %s\n", lw, "OnFullIfOff", bmap2asc(modmask[OnFullOffMask][hcode], chr),
1135       "LightsOn brightens to 100% only if Off");
1136    exclusive = modmask[Exc16Mask][hcode] | modmask[Exc8Mask][hcode] | modmask[Exc4Mask][hcode];
1137    printf("%*s (%s)  %s\n", lw, "ExclusiveOn", bmap2asc(exclusive, chr),
1138       "Last unit turns On, other units in group Off");
1139    printf("%*s (%s)  %s\n", lw, "LightsOff", bmap2asc(modmask[LightsOffMask][hcode], chr),
1140       "Supports LightsOff command");
1141    printf("%*s (%s)  %s\n", lw, "LiOnUnAddr", bmap2asc(modmask[LightsOnUnaddrMask][hcode], chr),
1142       "Unaddressed by LightsOn command");
1143    printf("%*s (%s)  %s\n", lw, "LiOffUnAddr", bmap2asc(modmask[LightsOffUnaddrMask][hcode], chr),
1144       "Unaddressed by LightsOff command");
1145 
1146    printf("%*s (%s)  %s\n", lw, "OnOffUnAddr", bmap2asc(modmask[OnOffUnaddrMask][hcode], chr),
1147       "Unaddressed by On or Off command");
1148 
1149    printf("%*s (%s)  %s\n", lw, "AllOff", bmap2asc(modmask[AllOffMask][hcode], chr),
1150       "Supports AllOff (AllUnitsOff) command");
1151    printf("%*s (%s)  %s\n", lw, "StatusReq", bmap2asc(modmask[StatusMask][hcode], chr),
1152       "Supports StatusReq command");
1153    printf("%*s (%s)  %s\n", lw, "StatusOn", bmap2asc(modmask[StatusOnMask][hcode], chr),
1154       "Sends StatusOn in response to StatusReq");
1155    printf("%*s (%s)  %s\n", lw, "StatusOff", bmap2asc(modmask[StatusOffMask][hcode], chr),
1156       "Sends StatusOff in response to StatusReq");
1157    printf("%*s (%s)  %s\n", lw, "StatusDefer", bmap2asc(modmask[DeferMask][hcode], chr),
1158       "Defer update until StatusOn/Off response");
1159    printf("%*s (%s)  %s\n", lw, "Preset", bmap2asc(modmask[PresetMask][hcode], chr),
1160       "Supports Preset (1-32) commands");
1161    printf("%*s (%s)  %s\n", lw, "LevelFixed", bmap2asc(modmask[OnFullMask][hcode], chr),
1162       "On command sets to fixed brightness level");
1163    printf("%*s (%s)  %s\n", lw, "LevelResume", bmap2asc(modmask[ResumeMask][hcode], chr),
1164       "On command resumes previous brightness level");
1165    printf("%*s (%s)  %s\n", lw, "ExtSwitch", bmap2asc(modmask[Ext3Mask][hcode], chr),
1166       "Supports Extended code switch commands");
1167    printf("%*s (%s)  %s\n", lw, "ExtDimmer", bmap2asc(modmask[Ext3DimMask][hcode], chr),
1168       "Supports Extended code dimmer (0-63) commands");
1169    printf("%*s (%s)  %s\n", lw, "ExtStatus", bmap2asc(modmask[Ext3StatusMask][hcode], chr),
1170       "Supports Extended code StatusReq commands");
1171    printf("%*s (%s)  %s\n", lw, "ExtGrpExec", bmap2asc(modmask[Ext3GrpExecMask][hcode], chr),
1172       "Supports Extended code Group Execute");
1173    printf("%*s (%s)  %s\n", lw, "ExtGrpOff",
1174        bmap2asc2(modmask[Ext3GrpOffMask][hcode], modmask[Ext3GrpOffExecMask][hcode], chr),
1175       "Supports Extended code Group Off (x = bug)");
1176    printf("%*s (%s)  %s\n", lw, "ExtGrpBrDim", bmap2asc(modmask[Ext3GrpBriDimMask][hcode], chr),
1177       "Supports Extended code Group Bright/Dim");
1178    printf("%*s (%s)  %s\n", lw, "ExtGrpRem", bmap2asc(modmask[Ext3GrpRemMask][hcode], chr),
1179       "Supports Extended code Group Remove");
1180    printf("%*s (%s)  %s\n", lw, "ExtShutter", bmap2asc(modmask[Ext0Mask][hcode], chr),
1181       "Supports Extended code shutter (0-25) commands");
1182    printf("%*s (%s)  %s\n", lw, "PhysMod", bmap2asc((modmask[PhysMask][hcode] | kmodmask[KPhysMask][hcode]), chr),
1183       "Physical receiver module");
1184    printf("%*s (%s)  %s\n", lw, "Virtual", bmap2asc(modmask[VdataMask][hcode], chr),
1185       "Virtual Data module");
1186    printf("%*s (%s)  %s\n", lw, "PLCSensor", bmap2asc(modmask[PlcSensorMask][hcode], chr),
1187       "Sensor transmits X10 power line signals");
1188    printf("%*s (%s)  %s\n", lw, "Security", bmap2asc(vmodmask[VsecMask][hcode], chr),
1189       "X10 Security RF data");
1190 #ifdef HASRFXS
1191    printf("%*s (%s)  %s\n", lw, "RFXSensor", bmap2asc(vmodmask[VrfxsMask][hcode], chr),
1192       "RFXSensor RF data");
1193 #endif
1194 #ifdef HASRFXM
1195    printf("%*s (%s)  %s\n", lw, "RFXMeter", bmap2asc(vmodmask[VrfxmMask][hcode], chr),
1196       "RFXMeter RF data");
1197 #endif
1198 #ifdef HASDMX
1199    printf("%*s (%s)  %s\n", lw, "Digimax", bmap2asc(vmodmask[VdmxMask][hcode], chr),
1200       "Digimax RF data");
1201 #endif
1202 #ifdef HASORE
1203    printf("%*s (%s)  %s\n", lw, "Oregon", bmap2asc(vmodmask[VoreMask][hcode], chr),
1204       "Oregon RF data");
1205 #endif
1206    printf("%*s (%s)  %s\n", lw, "KaKu/HE", bmap2asc(vmodmask[VkakuMask][hcode], chr),
1207       "Supports KaKu/HomeEasy RF commands");
1208 
1209    printf("%*s (%s)  %s\n", lw, "Heartbeat", bmap2asc(heartbeat, chr),
1210       "Sensor transmits periodic heartbeat signal");
1211    printf("%*s (%s)  %s\n", lw, "LoBat",
1212        bmap2asc2(lobat, lobatunkn, chr2),
1213       "Sensor transmits low battery indication");
1214 
1215    printf("\n");
1216 
1217    return;
1218 }
1219 
1220 /*---------------------------------------------------------------------+
1221  | Count the RF options (There should be no more than one)             |
1222  +---------------------------------------------------------------------*/
count_rf_options(ALIAS * aliasp,int aliasindex)1223 int count_rf_options ( ALIAS *aliasp, int aliasindex )
1224 {
1225    int count = 0;
1226 
1227    count += (aliasp[aliasindex].optflags & MOPT_TRANSCEIVE) ? 1 : 0;
1228    count += (aliasp[aliasindex].optflags & MOPT_RFFORWARD)  ? 1 : 0;
1229    count += (aliasp[aliasindex].optflags & MOPT_RFIGNORE)   ? 1 : 0;
1230 
1231    return count;
1232 }
1233 
1234 /*---------------------------------------------------------------------+
1235  | Set DUMMY option for security remotes (keyfob)                      |
1236  +---------------------------------------------------------------------*/
remote_options(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1237 int remote_options ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1238 {
1239    int  j, k, count = 0;
1240    char *tmptok;
1241    unsigned long flags = 0;
1242 
1243    for ( j = 0; j < *ntokens; j++ ) {
1244       strupper(tokens[j]);
1245       if ( strcmp(tokens[j], "DUMMY") == 0 ) {
1246          aliasp[aliasindex].optflags2 |= MOPT2_DUMMY;
1247          *tokens[j] = '\0';
1248          count++;
1249       }
1250       else if ( strcmp(tokens[j], "SWMAX") == 0 ) {
1251          flags |= SEC_MAX;
1252          aliasp[aliasindex].optflags2 |= MOPT2_SWMAX;
1253          *tokens[j] = '\0';
1254          count++;
1255       }
1256       else if ( strcmp(tokens[j], "SWHOME") == 0 ) {
1257          flags |= SEC_HOME;
1258          aliasp[aliasindex].optflags2 |= MOPT2_SWHOME;
1259          *tokens[j] = '\0';
1260          count++;
1261       }
1262       else if ( strcmp(tokens[j], "SWMIN") == 0 ) {
1263          flags |= SEC_MIN;
1264          aliasp[aliasindex].optflags2 &= ~MOPT2_SWMAX;
1265          *tokens[j] = '\0';
1266          count++;
1267       }
1268       else if ( strcmp(tokens[j], "SWAWAY") == 0 ) {
1269          flags |= SEC_AWAY;
1270          aliasp[aliasindex].optflags2 &= ~MOPT2_SWHOME;
1271          *tokens[j] = '\0';
1272          count++;
1273       }
1274    }
1275 
1276    if ( flags && (aliasp[aliasindex].optflags2 & MOPT2_DUMMY) ) {
1277       store_error_message("Parameter DUMMY incompatible with SWxxx parameters.");
1278       return 1;
1279    }
1280    if ( (flags & SEC_HOME) && (flags & SEC_AWAY) ) {
1281       store_error_message("Conflicting parameters SWHOME, SWAWAY.");
1282       return 1;
1283    }
1284    if ( (flags & SEC_MAX) && (flags & SEC_MIN) ) {
1285       store_error_message("Conflicting parameters SWMAX, SWMIN.");
1286       return 1;
1287    }
1288 
1289 
1290    if ( count == 0 )
1291       return 0;
1292 
1293    /* Compact to remove "gaps" where tokens were nulled out */
1294 
1295    for ( j = 0; j < *ntokens; j++ ) {
1296       if ( *tokens[j] == '\0' ) {
1297          for ( k = j + 1; k < *ntokens; k++ ) {
1298             if ( *tokens[k] != '\0' ) {
1299                tmptok = tokens[j];
1300                tokens[j] = tokens[k];
1301                tokens[k] = tmptok;
1302                *tmptok = '\0';
1303                break;
1304             }
1305          }
1306       }
1307    }
1308 
1309    *ntokens -= count;
1310 
1311    return 0;
1312 }
1313 
1314 /*---------------------------------------------------------------------+
1315  | Set REVERSE, MAIN, and AUX module options                           |
1316  +---------------------------------------------------------------------*/
sensor_options(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1317 int sensor_options ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1318 {
1319    int  j, k, count = 0;
1320    char *tmptok;
1321 
1322    for ( j = 0; j < *ntokens; j++ ) {
1323       strupper(tokens[j]);
1324       if ( strcmp(tokens[j], "REVERSE") == 0 ) {
1325          aliasp[aliasindex].optflags |= MOPT_REVERSE;
1326          *tokens[j] = '\0';
1327          count++;
1328       }
1329       else if ( strcmp(tokens[j], "RFIGNORE") == 0 ) {
1330          aliasp[aliasindex].optflags |= MOPT_RFIGNORE;
1331          *tokens[j] = '\0';
1332          count++;
1333       }
1334       else if ( strcmp(tokens[j], "MAIN") == 0 ) {
1335          aliasp[aliasindex].optflags |= MOPT_MAIN;
1336          *tokens[j] = '\0';
1337          count++;
1338       }
1339       else if ( strcmp(tokens[j], "AUX") == 0 ) {
1340          aliasp[aliasindex].optflags |= MOPT_AUX;
1341          *tokens[j] = '\0';
1342          count++;
1343       }
1344    }
1345 
1346    /* Compact to remove "gaps" where tokens were nulled out */
1347 
1348    for ( j = 0; j < *ntokens; j++ ) {
1349       if ( *tokens[j] == '\0' ) {
1350          for ( k = j + 1; k < *ntokens; k++ ) {
1351             if ( *tokens[k] != '\0' ) {
1352                tmptok = tokens[j];
1353                tokens[j] = tokens[k];
1354                tokens[k] = tmptok;
1355                *tmptok = '\0';
1356                break;
1357             }
1358          }
1359       }
1360    }
1361 
1362    *ntokens -= count;
1363 
1364    return 0;
1365 }
1366 
1367 /*---------------------------------------------------------------------+
1368  | Options for PLC Sensor                                              |
1369  +---------------------------------------------------------------------*/
opt_plcsensor(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1370 int opt_plcsensor ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1371 {
1372 
1373    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
1374       return 1;
1375 
1376    aliasp[aliasindex].vtype = 0;
1377    aliasp[aliasindex].optflags |= (MOPT_PLCSENSOR | MOPT_HEARTBEAT);
1378    return 0;
1379 }
1380 
1381 /*---------------------------------------------------------------------+
1382  | Options for second sensor in RFXSensor modules                      |
1383  +---------------------------------------------------------------------*/
opt_rfxsensor(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1384 int opt_rfxsensor ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1385 {
1386    long ident;
1387    unsigned char rfxid /*, delta */;
1388    char *sp;
1389 
1390    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
1391       return 1;
1392 
1393    if ( *ntokens < 2 ) {
1394       store_error_message("This module requires more parameters.");
1395       return 1;
1396    }
1397 
1398    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
1399       store_error_message("Multiple unit alias is invalid for sensors.");
1400       return 1;
1401    }
1402 
1403    ident = strtol(tokens[0], &sp, 16);
1404    if ( *sp == '\0' && ident >= 0 && ident <= 0xff ) {
1405       aliasp[aliasindex].ident[0] = (unsigned short)ident;
1406    }
1407    else {
1408       store_error_message("Invalid hexadecimal RFXSensor base address parameter");
1409       return 1;
1410    }
1411 
1412    rfxid = aliasp[aliasindex].ident[0];
1413 
1414    if ( (rfxid % 4) != 0 ) {
1415       store_error_message("RFXSensor base address must be a multiple of 0x04");
1416       return 1;
1417    }
1418 
1419    /* Add IDs for secondary and Supply Voltage sensors. */
1420    aliasp[aliasindex].ident[1] = aliasp[aliasindex].ident[0] + 1;
1421    aliasp[aliasindex].ident[2] = aliasp[aliasindex].ident[0] + 2;
1422    aliasp[aliasindex].nident = 3;
1423 
1424    aliasp[aliasindex].optflags |= MOPT_RFXVS;
1425 
1426    strupper(tokens[1]);
1427    if ( strcmp(tokens[1], "TH") == 0 ) {
1428       /* Temperature and Humidity */
1429       aliasp[aliasindex].optflags |= MOPT_RFXRH;
1430    }
1431    else if ( strcmp(tokens[1], "TB") == 0 ) {
1432       /* Temperature and Barometric Pressure */
1433       aliasp[aliasindex].optflags |= MOPT_RFXBP;
1434    }
1435    else if ( strcmp(tokens[1], "TV") == 0 ) {
1436       /* Temperature and Voltage */
1437       aliasp[aliasindex].optflags |= MOPT_RFXVAD;
1438    }
1439    else if ( strcmp(tokens[1], "TP") == 0 ) {
1440       /* Potentiometer */
1441       aliasp[aliasindex].optflags |= MOPT_RFXPOT;
1442    }
1443    else if ( strcmp(tokens[1], "TT") == 0 ) {
1444       /* Two Temperature probes */
1445       aliasp[aliasindex].optflags |= MOPT_RFXT2;
1446    }
1447    else if ( strcmp(tokens[1], "T") == 0 ) {
1448       /* Single Temperature probe */
1449       aliasp[aliasindex].optflags &= ~MOPT_RFXVS;
1450    }
1451    else {
1452       store_error_message("Invalid RFXSensor function.");
1453       return 1;
1454    }
1455 
1456    /* This is a sensor with periodic "heartbeat" signals */
1457    aliasp[aliasindex].vtype = RF_XSENSOR;
1458    aliasp[aliasindex].optflags |= (MOPT_RFXSENSOR | MOPT_HEARTBEAT | MOPT_LOBAT);
1459 
1460    return 0;
1461 }
1462 
1463 /*---------------------------------------------------------------------+
1464  | Options for RFXMeter modules                                        |
1465  +---------------------------------------------------------------------*/
opt_rfxmeter(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1466 int opt_rfxmeter ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1467 {
1468    long ident;
1469    char *sp;
1470 
1471    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
1472       return 1;
1473 
1474    if ( *ntokens < 1 ) {
1475       store_error_message("This module requires one ID parameter.");
1476       return 1;
1477    }
1478    else if ( *ntokens > 1 ) {
1479       store_error_message("This module accepts only one ID parameter.");
1480       return 1;
1481    }
1482 
1483    ident = strtol(tokens[0], &sp, 16);
1484    if ( *sp == '\0' && ident >= 0 && ident <= 0xff ) {
1485       aliasp[aliasindex].ident[0] = (unsigned short)ident;
1486    }
1487    else {
1488       store_error_message("Invalid hexadecimal RFXMeter ID parameter");
1489       return 1;
1490    }
1491    aliasp[aliasindex].nident = 1;
1492 
1493    aliasp[aliasindex].vtype = RF_XMETER;
1494    aliasp[aliasindex].optflags |= ((MOPT_SENSOR | MOPT_HEARTBEAT) & ~MOPT_LOBAT);
1495 
1496    return 0;
1497 }
1498 
1499 /*---------------------------------------------------------------------+
1500  | Options for RFXMeter Pulse modules                                  |
1501  +---------------------------------------------------------------------*/
opt_rfxpulse(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1502 int opt_rfxpulse ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1503 {
1504    if ( opt_rfxmeter(aliasp, aliasindex, tokens, ntokens) != 0 )
1505       return 1;
1506 
1507    aliasp[aliasindex].optflags |= (MOPT_RFXPULSE | MOPT_RFXCOUNT | MOPT_HEARTBEAT);
1508    return 0;
1509 }
1510 
1511 /*---------------------------------------------------------------------+
1512  | Options for RFXMeter Counter modules                                |
1513  +---------------------------------------------------------------------*/
opt_rfxcount(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1514 int opt_rfxcount ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1515 {
1516    if ( opt_rfxmeter(aliasp, aliasindex, tokens, ntokens) != 0 )
1517       return 1;
1518 
1519    aliasp[aliasindex].optflags |= (MOPT_RFXCOUNT | MOPT_HEARTBEAT);
1520    return 0;
1521 }
1522 
1523 /*---------------------------------------------------------------------+
1524  | Options for RFXMeter Power modules                                  |
1525  +---------------------------------------------------------------------*/
opt_rfxpower(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1526 int opt_rfxpower ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1527 {
1528    if ( opt_rfxmeter(aliasp, aliasindex, tokens, ntokens) != 0 )
1529       return 1;
1530 
1531    aliasp[aliasindex].optflags |= (MOPT_RFXPOWER | MOPT_RFXCOUNT | MOPT_HEARTBEAT);
1532    return 0;
1533 }
1534 
1535 /*---------------------------------------------------------------------+
1536  | Options for RFXMeter Water meter modules                            |
1537  +---------------------------------------------------------------------*/
opt_rfxwater(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1538 int opt_rfxwater ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1539 {
1540    if ( opt_rfxmeter(aliasp, aliasindex, tokens, ntokens) != 0 )
1541       return 1;
1542 
1543    aliasp[aliasindex].optflags |= (MOPT_RFXWATER | MOPT_RFXCOUNT | MOPT_HEARTBEAT);
1544    return 0;
1545 }
1546 
1547 /*---------------------------------------------------------------------+
1548  | Options for RFXMeter Gas meter modules                              |
1549  +---------------------------------------------------------------------*/
opt_rfxgas(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1550 int opt_rfxgas ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
1551 {
1552    if ( opt_rfxmeter(aliasp, aliasindex, tokens, ntokens) != 0 )
1553       return 1;
1554 
1555    aliasp[aliasindex].optflags |= (MOPT_RFXGAS | MOPT_RFXCOUNT | MOPT_HEARTBEAT);
1556    return 0;
1557 }
1558 
1559 /*---------------------------------------------------------------------+
1560  | Options for Digimax 210                                             |
1561  +---------------------------------------------------------------------*/
opt_digimax(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1562 int opt_digimax ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1563 {
1564    long ident;
1565    char *sp;
1566 
1567    if ( *ntokens < 1 ) {
1568       store_error_message("This module requires an ID parameter");
1569       return 1;
1570    }
1571 
1572    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
1573       store_error_message("Multiple unit alias is invalid for sensors.");
1574       return 1;
1575    }
1576 
1577    ident = strtol(tokens[0], &sp, 16);
1578    if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
1579       aliasp[aliasindex].ident[0] = (unsigned short)ident;
1580       aliasp[aliasindex].nident = 1;
1581    }
1582    else {
1583       store_error_message("Invalid hexadecimal Digimax address parameter");
1584       return 1;
1585    }
1586 
1587    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
1588       return 1;
1589 
1590    aliasp[aliasindex].vtype = RF_DIGIMAX;
1591    aliasp[aliasindex].storage_units = 1;
1592 
1593    aliasp[aliasindex].optflags = (MOPT_SECURITY | MOPT_SENSOR | MOPT_HEARTBEAT);
1594 
1595    return 0;
1596 }
1597 
1598 /*---------------------------------------------------------------------+
1599  | Options for ACT modules.                                            |
1600  +---------------------------------------------------------------------*/
opt_act(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1601 int opt_act ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1602 {
1603    int j;
1604    char message[80];
1605 
1606    for ( j = 0; j < *ntokens; j++ ) {
1607       strupper(tokens[j]);
1608       if ( strcmp(tokens[j], "AUF") == 0 )
1609          aliasp[aliasindex].optflags2 |= MOPT2_AUF;
1610       else if ( strcmp(tokens[j], "ALO") == 0 )
1611          aliasp[aliasindex].optflags2 |= MOPT2_ALO;
1612       else if ( strcmp(tokens[j], "ALF") == 0 )
1613          aliasp[aliasindex].optflags2 |= MOPT2_ALF;
1614       else {
1615          sprintf(message, "Invalid module option '%s'", tokens[j]);
1616          store_error_message(message);
1617          return 1;
1618       }
1619    }
1620 
1621    return 0;
1622 }
1623 
1624 /*---------------------------------------------------------------------+
1625  | Option for 2-way modules with automatic StatusOn/Off response       |
1626  +---------------------------------------------------------------------*/
opt_defer(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1627 int opt_defer ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1628 {
1629    int j;
1630    char message[80];
1631 
1632    for ( j = 0; j < *ntokens; j++ ) {
1633       strupper(tokens[j]);
1634       if ( strcmp(tokens[j], "DEFER") == 0 )
1635          aliasp[aliasindex].optflags2 |= MOPT2_DEFER;
1636       else {
1637          sprintf(message, "Invalid module option '%s'", tokens[j]);
1638          store_error_message(message);
1639          return 1;
1640       }
1641    }
1642 
1643    return 0;
1644 }
1645 
1646 
1647 #ifdef HASORE
1648 /*---------------------------------------------------------------------+
1649  | General options for Oregon sensors                                  |
1650  +---------------------------------------------------------------------*/
opt_oregon(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1651 int opt_oregon ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1652 {
1653    long ident;
1654    char *sp;
1655 
1656    if ( ore_maxmin_temp(aliasp, aliasindex, tokens, ntokens) != 0 )
1657       return 1;
1658    if ( ore_maxmin_rh(aliasp, aliasindex, tokens, ntokens) != 0 )
1659       return 1;
1660    if ( ore_maxmin_bp(aliasp, aliasindex, tokens, ntokens) != 0 )
1661       return 1;
1662    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
1663       return 1;
1664 
1665    if ( *ntokens != 1 ) {
1666       store_error_message("Unknown parameters");
1667       return 1;
1668    }
1669 
1670    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
1671       store_error_message("Multiple unit alias is invalid for sensors.");
1672       return 1;
1673    }
1674 
1675    ident = strtol(tokens[0], &sp, 16);
1676    if ( *sp == '\0' && ident >= 0 && ident <= 0xfff ) {
1677       aliasp[aliasindex].ident[0] = (unsigned short)ident;
1678       aliasp[aliasindex].nident = 1;
1679    }
1680    else {
1681       store_error_message("Invalid hexadecimal Oregon address parameter");
1682       return 1;
1683    }
1684 
1685    aliasp[aliasindex].vtype = RF_OREGON;
1686 
1687    aliasp[aliasindex].optflags = (MOPT_SECURITY | MOPT_SENSOR | MOPT_HEARTBEAT | MOPT_LOBAT);
1688 
1689    return 0;
1690 }
1691 
1692 /*---------------------------------------------------------------------+
1693  | General options for Oregon sensors                                  |
1694  +---------------------------------------------------------------------*/
opt_ore_dummy(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1695 int opt_ore_dummy ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1696 {
1697 
1698    if ( ore_maxmin_temp(aliasp, aliasindex, tokens, ntokens) != 0 )
1699       return 1;
1700    if ( ore_maxmin_rh(aliasp, aliasindex, tokens, ntokens) != 0 )
1701       return 1;
1702    if ( ore_maxmin_bp(aliasp, aliasindex, tokens, ntokens) != 0 )
1703       return 1;
1704    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
1705       return 1;
1706 
1707 
1708    if ( *ntokens != 0 ) {
1709       store_error_message("Unknown parameters");
1710       return 1;
1711    }
1712 
1713    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
1714       store_error_message("Multiple unit alias is invalid for sensors.");
1715       return 1;
1716    }
1717 
1718    aliasp[aliasindex].nident = 0;
1719 
1720    aliasp[aliasindex].vtype = RF_OREGON;
1721 
1722    aliasp[aliasindex].optflags = (MOPT_SECURITY | MOPT_SENSOR | MOPT_HEARTBEAT);
1723 
1724    return 0;
1725 }
1726 
1727 /*---------------------------------------------------------------------+
1728  | Options for Oregon Temp1 sensors                                    |
1729  +---------------------------------------------------------------------*/
opt_oreTemp1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1730 int opt_oreTemp1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1731 {
1732    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1733       return 1;
1734 
1735    aliasp[aliasindex].subtype = OreTemp1;
1736    aliasp[aliasindex].nvar = 1;
1737    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1738    aliasp[aliasindex].funclist[0] = OreTempFunc;
1739 
1740    return 0;
1741 }
1742 
1743 /*---------------------------------------------------------------------+
1744  | Options for Oregon Temp2 sensors                                    |
1745  +---------------------------------------------------------------------*/
opt_oreTemp2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1746 int opt_oreTemp2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1747 {
1748    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1749       return 1;
1750 
1751    aliasp[aliasindex].subtype = OreTemp2;
1752    aliasp[aliasindex].nvar = 1;
1753    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1754    aliasp[aliasindex].funclist[0] = OreTempFunc;
1755 
1756    return 0;
1757 }
1758 
1759 /*---------------------------------------------------------------------+
1760  | Options for Oregon Temp3 sensors                                    |
1761  +---------------------------------------------------------------------*/
opt_oreTemp3(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1762 int opt_oreTemp3 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1763 {
1764    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1765       return 1;
1766 
1767    aliasp[aliasindex].subtype = OreTemp3;
1768    aliasp[aliasindex].nvar = 1;
1769    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1770    aliasp[aliasindex].funclist[0] = OreTempFunc;
1771 
1772    return 0;
1773 }
1774 
1775 /*---------------------------------------------------------------------+
1776  | Options for Oregon TH1 sensors                                      |
1777  +---------------------------------------------------------------------*/
opt_oreTH1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1778 int opt_oreTH1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1779 {
1780    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1781       return 1;
1782 
1783    aliasp[aliasindex].subtype = OreTH1;
1784    aliasp[aliasindex].nvar = 2;
1785    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1786    aliasp[aliasindex].funclist[0] = OreTempFunc;
1787    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1788 
1789    return 0;
1790 }
1791 
1792 /*---------------------------------------------------------------------+
1793  | Options for Oregon TH2 sensors                                      |
1794  +---------------------------------------------------------------------*/
opt_oreTH2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1795 int opt_oreTH2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1796 {
1797    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1798       return 1;
1799 
1800    aliasp[aliasindex].subtype = OreTH2;
1801    aliasp[aliasindex].nvar = 2;
1802    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1803    aliasp[aliasindex].funclist[0] = OreTempFunc;
1804    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1805 
1806    return 0;
1807 }
1808 
1809 /*---------------------------------------------------------------------+
1810  | Options for Oregon TH3 sensors                                      |
1811  +---------------------------------------------------------------------*/
opt_oreTH3(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1812 int opt_oreTH3 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1813 {
1814    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1815       return 1;
1816 
1817    aliasp[aliasindex].subtype = OreTH3;
1818    aliasp[aliasindex].nvar = 2;
1819    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1820    aliasp[aliasindex].funclist[0] = OreTempFunc;
1821    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1822 
1823    return 0;
1824 }
1825 
1826 /*---------------------------------------------------------------------+
1827  | Options for Oregon TH4 sensors                                      |
1828  +---------------------------------------------------------------------*/
opt_oreTH4(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1829 int opt_oreTH4 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1830 {
1831    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1832       return 1;
1833 
1834    aliasp[aliasindex].subtype = OreTH4;
1835    aliasp[aliasindex].nvar = 2;
1836    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1837    aliasp[aliasindex].funclist[0] = OreTempFunc;
1838    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1839 
1840    return 0;
1841 }
1842 
1843 /*---------------------------------------------------------------------+
1844  | Options for Oregon TH5 sensors                                      |
1845  +---------------------------------------------------------------------*/
opt_oreTH5(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1846 int opt_oreTH5 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1847 {
1848    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1849       return 1;
1850 
1851    aliasp[aliasindex].subtype = OreTH5;
1852    aliasp[aliasindex].nvar = 2;
1853    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1854    aliasp[aliasindex].funclist[0] = OreTempFunc;
1855    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1856 
1857    return 0;
1858 }
1859 
1860 /*---------------------------------------------------------------------+
1861  | Options for Oregon TH6 sensors                                      |
1862  +---------------------------------------------------------------------*/
opt_oreTH6(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1863 int opt_oreTH6 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1864 {
1865    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1866       return 1;
1867 
1868    aliasp[aliasindex].subtype = OreTH6;
1869    aliasp[aliasindex].nvar = 2;
1870    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1871    aliasp[aliasindex].funclist[0] = OreTempFunc;
1872    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1873 
1874    return 0;
1875 }
1876 
1877 /*---------------------------------------------------------------------+
1878  | Options for Oregon THB1 sensors                                     |
1879  +---------------------------------------------------------------------*/
opt_oreTHB1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1880 int opt_oreTHB1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1881 {
1882    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1883       return 1;
1884 
1885    aliasp[aliasindex].subtype = OreTHB1;
1886    aliasp[aliasindex].nvar = 3;
1887    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1888    aliasp[aliasindex].funclist[0] = OreTempFunc;
1889    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1890    aliasp[aliasindex].funclist[2] = OreBaroFunc;
1891 
1892    return 0;
1893 }
1894 
1895 /*---------------------------------------------------------------------+
1896  | Options for Oregon THB2 sensors                                     |
1897  +---------------------------------------------------------------------*/
opt_oreTHB2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1898 int opt_oreTHB2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1899 {
1900    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1901       return 1;
1902 
1903    aliasp[aliasindex].subtype = OreTHB2;
1904    aliasp[aliasindex].nvar = 3;
1905    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1906    aliasp[aliasindex].funclist[0] = OreTempFunc;
1907    aliasp[aliasindex].funclist[1] = OreHumidFunc;
1908    aliasp[aliasindex].funclist[2] = OreBaroFunc;
1909 
1910    return 0;
1911 }
1912 
1913 /*---------------------------------------------------------------------+
1914  | Options for Oregon Wind1 sensors                                    |
1915  +---------------------------------------------------------------------*/
opt_oreWind1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1916 int opt_oreWind1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1917 {
1918    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1919       return 1;
1920 
1921    aliasp[aliasindex].subtype = OreWind1;
1922    aliasp[aliasindex].nvar = 3;
1923    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1924    aliasp[aliasindex].funclist[0] = OreWindAvSpFunc;
1925    aliasp[aliasindex].funclist[1] = OreWindSpFunc;
1926    aliasp[aliasindex].funclist[2] = OreWindDirFunc;
1927 
1928    return 0;
1929 }
1930 
1931 /*---------------------------------------------------------------------+
1932  | Options for Oregon Wind2 sensors                                    |
1933  +---------------------------------------------------------------------*/
opt_oreWind2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1934 int opt_oreWind2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1935 {
1936    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1937       return 1;
1938 
1939    aliasp[aliasindex].subtype = OreWind2;
1940    aliasp[aliasindex].nvar = 3;
1941    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1942    aliasp[aliasindex].funclist[0] = OreWindAvSpFunc;
1943    aliasp[aliasindex].funclist[1] = OreWindSpFunc;
1944    aliasp[aliasindex].funclist[2] = OreWindDirFunc;
1945 
1946    return 0;
1947 }
1948 
1949 /*---------------------------------------------------------------------+
1950  | Options for Oregon Wind3 sensors                                    |
1951  +---------------------------------------------------------------------*/
opt_oreWind3(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1952 int opt_oreWind3 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1953 {
1954    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1955       return 1;
1956 
1957    aliasp[aliasindex].subtype = OreWind3;
1958    aliasp[aliasindex].nvar = 3;
1959    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
1960    aliasp[aliasindex].funclist[0] = OreWindAvSpFunc;
1961    aliasp[aliasindex].funclist[1] = OreWindSpFunc;
1962    aliasp[aliasindex].funclist[2] = OreWindDirFunc;
1963 
1964    return 0;
1965 }
1966 
1967 /*---------------------------------------------------------------------+
1968  | Options for Oregon Rain1 sensors                                    |
1969  +---------------------------------------------------------------------*/
opt_oreRain1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1970 int opt_oreRain1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1971 {
1972    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1973       return 1;
1974 
1975    aliasp[aliasindex].subtype = OreRain1;
1976    aliasp[aliasindex].nvar = 2;
1977    /* Need extra storage locations for 32 bit data */
1978    aliasp[aliasindex].storage_units = 4 * aliasp[aliasindex].nvar;
1979    aliasp[aliasindex].funclist[0] = OreRainRateFunc;
1980    aliasp[aliasindex].funclist[1] = OreRainTotFunc;
1981    /* Override the default storage offsets */
1982    aliasp[aliasindex].statusoffset[0] = 0;
1983    aliasp[aliasindex].statusoffset[1] = 4;
1984 
1985    return 0;
1986 }
1987 
1988 /*---------------------------------------------------------------------+
1989  | Options for Oregon Rain2 sensors                                    |
1990  +---------------------------------------------------------------------*/
opt_oreRain2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)1991 int opt_oreRain2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
1992 {
1993    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
1994       return 1;
1995 
1996    aliasp[aliasindex].subtype = OreRain2;
1997    aliasp[aliasindex].nvar = 2;
1998    /* Need extra storage locations for 32 bit data */
1999    aliasp[aliasindex].storage_units = 4 * aliasp[aliasindex].nvar;
2000    aliasp[aliasindex].funclist[0] = OreRainRateFunc;
2001    aliasp[aliasindex].funclist[1] = OreRainTotFunc;
2002    /* Override the default storage offsets */
2003    aliasp[aliasindex].statusoffset[0] = 0;
2004    aliasp[aliasindex].statusoffset[1] = 4;
2005 
2006    return 0;
2007 }
2008 
2009 /*---------------------------------------------------------------------+
2010  | Options for Oregon Rain3 sensors                                    |
2011  +---------------------------------------------------------------------*/
opt_oreRain3(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2012 int opt_oreRain3 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2013 {
2014    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2015       return 1;
2016 
2017    aliasp[aliasindex].subtype = OreRain3;
2018    aliasp[aliasindex].nvar = 2;
2019    /* Need extra storage locations for 32 bit data */
2020    aliasp[aliasindex].storage_units = 4 * aliasp[aliasindex].nvar;
2021    aliasp[aliasindex].funclist[0] = OreRainRateFunc;
2022    aliasp[aliasindex].funclist[1] = OreRainTotFunc;
2023    /* Override the default storage offsets */
2024    aliasp[aliasindex].statusoffset[0] = 0;
2025    aliasp[aliasindex].statusoffset[1] = 4;
2026 
2027    return 0;
2028 }
2029 
2030 /*---------------------------------------------------------------------+
2031  | Options for Electrisave sensors                                     |
2032  +---------------------------------------------------------------------*/
opt_elsElec1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2033 int opt_elsElec1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2034 {
2035    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2036       return 1;
2037 
2038    aliasp[aliasindex].vtype = RF_ELECSAVE;
2039    aliasp[aliasindex].subtype = OreElec1;
2040    aliasp[aliasindex].nvar = 1;
2041    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2042    aliasp[aliasindex].funclist[0] = ElsCurrFunc;
2043 
2044    return 0;
2045 }
2046 
2047 /*---------------------------------------------------------------------+
2048  | Options for OWL CM119 sensors                                       |
2049  +---------------------------------------------------------------------*/
opt_owlElec2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2050 int opt_owlElec2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2051 {
2052    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2053       return 1;
2054 
2055    /* OWL needs 2 storage locations for power and 3 storage locations */
2056    /* for energy - all times 2 for last unchanged values also.        */
2057 
2058    aliasp[aliasindex].vtype = RF_OWL;
2059    aliasp[aliasindex].subtype = OreElec2;
2060    aliasp[aliasindex].nvar = 2;
2061    aliasp[aliasindex].storage_units = 10;
2062    aliasp[aliasindex].funclist[0] = OwlPowerFunc;
2063    aliasp[aliasindex].funclist[1] = OwlEnergyFunc;
2064    /* Override the default storage offsets */
2065    aliasp[aliasindex].statusoffset[0] = 0;
2066    aliasp[aliasindex].statusoffset[1] = 2;
2067 
2068    aliasp[aliasindex].optflags &= ~MOPT_LOBAT;
2069    aliasp[aliasindex].optflags |= MOPT_LOBATUNKN;
2070 
2071    return 0;
2072 }
2073 
2074 /*---------------------------------------------------------------------+
2075  | Options for OWL CM119 sensors                                       |
2076  +---------------------------------------------------------------------*/
opt_owlElec2new(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2077 int opt_owlElec2new ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2078 {
2079    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2080       return 1;
2081 
2082    /* OWL needs 2 storage locations for power and 3 storage locations */
2083    /* for energy - all times 2 for last unchanged values also.        */
2084 
2085    aliasp[aliasindex].vtype = RF_OWL;
2086    aliasp[aliasindex].subtype = OreElec2;
2087    aliasp[aliasindex].nvar = 2;
2088    aliasp[aliasindex].storage_units = 10;
2089    aliasp[aliasindex].funclist[0] = OwlPowerFunc;
2090    aliasp[aliasindex].funclist[1] = OwlEnergyFunc;
2091    /* Override the default storage offsets */
2092    aliasp[aliasindex].statusoffset[0] = 0;
2093    aliasp[aliasindex].statusoffset[1] = 4;
2094 
2095    aliasp[aliasindex].optflags &= ~MOPT_LOBAT;
2096    aliasp[aliasindex].optflags |= MOPT_LOBATUNKN;
2097 
2098    return 0;
2099 }
2100 
2101 /*---------------------------------------------------------------------+
2102  | Options for OWL CM119 sensors                                       |
2103  +---------------------------------------------------------------------*/
opt_owlElec2rev(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2104 int opt_owlElec2rev ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2105 {
2106    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2107       return 1;
2108 
2109    /* OWL needs 2 storage locations for power and 3 storage locations */
2110    /* for energy - all times 2 for last unchanged values also.        */
2111 
2112    aliasp[aliasindex].vtype = RF_OWL;
2113    aliasp[aliasindex].subtype = OreElec2;
2114    aliasp[aliasindex].nvar = 2;
2115    aliasp[aliasindex].storage_units = 10;
2116    aliasp[aliasindex].funclist[0] = OwlEnergyFunc;
2117    aliasp[aliasindex].funclist[1] = OwlPowerFunc;
2118    /* Override the default storage offsets */
2119    aliasp[aliasindex].statusoffset[0] = 4;
2120    aliasp[aliasindex].statusoffset[1] = 0;
2121 
2122    aliasp[aliasindex].optflags &= ~MOPT_LOBAT;
2123    aliasp[aliasindex].optflags |= MOPT_LOBATUNKN;
2124 
2125    return 0;
2126 }
2127 
2128 /*---------------------------------------------------------------------+
2129  | Options for Oregon UV1 sensors                                      |
2130  +---------------------------------------------------------------------*/
opt_oreUV1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2131 int opt_oreUV1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2132 {
2133    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2134       return 1;
2135 
2136    aliasp[aliasindex].subtype = OreUV1;
2137    aliasp[aliasindex].nvar = 1;
2138    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2139    aliasp[aliasindex].funclist[0] = OreUVFunc;
2140 
2141    return 0;
2142 }
2143 
2144 /*---------------------------------------------------------------------+
2145  | Options for Oregon UV2 sensors                                      |
2146  +---------------------------------------------------------------------*/
opt_oreUV2(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2147 int opt_oreUV2 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2148 {
2149    if ( opt_oregon(aliasp, aliasindex, tokens, ntokens) != 0 )
2150       return 1;
2151 
2152    aliasp[aliasindex].subtype = OreUV2;
2153    aliasp[aliasindex].nvar = 1;
2154    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2155    aliasp[aliasindex].funclist[0] = OreUVFunc;
2156 
2157    return 0;
2158 }
2159 
2160 /*---------------------------------------------------------------------+
2161  | Options for Oregon WEIGHT1 sensors                                  |
2162  +---------------------------------------------------------------------*/
opt_oreWeight1(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2163 int opt_oreWeight1 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2164 {
2165    long ident;
2166    char *sp;
2167 
2168    if ( *ntokens != 1 ) {
2169       store_error_message("Unknown parameters");
2170       return 1;
2171    }
2172 
2173    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
2174       store_error_message("Multiple unit alias is invalid for sensors.");
2175       return 1;
2176    }
2177 
2178    ident = strtol(tokens[0], &sp, 16);
2179    if ( *sp == '\0' && ident >= 0 && ident <= 0xfff ) {
2180       aliasp[aliasindex].ident[0] = (unsigned short)ident;
2181       aliasp[aliasindex].nident = 1;
2182    }
2183    else {
2184       store_error_message("Invalid hexadecimal Oregon address parameter");
2185       return 1;
2186    }
2187 
2188    aliasp[aliasindex].vtype = RF_OREGON;
2189    aliasp[aliasindex].subtype = OreWeight1;
2190    aliasp[aliasindex].optflags = (MOPT_SECURITY | MOPT_SENSOR);
2191    aliasp[aliasindex].nvar = 1;
2192    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2193    aliasp[aliasindex].funclist[0] = OreWeightFunc;
2194 
2195    return 0;
2196 }
2197 
2198 /*---------------------------------------------------------------------+
2199  | Options for Oregon Dummy Temp sensors                                |
2200  +---------------------------------------------------------------------*/
opt_oreTemu(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2201 int opt_oreTemu ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2202 {
2203    if ( opt_ore_dummy(aliasp, aliasindex, tokens, ntokens) != 0 )
2204       return 1;
2205 
2206    aliasp[aliasindex].subtype = OreTemu;
2207    aliasp[aliasindex].nvar = 1;
2208    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2209    aliasp[aliasindex].funclist[0] = OreTempFunc;
2210 
2211    return 0;
2212 }
2213 
2214 /*---------------------------------------------------------------------+
2215  | Options for Oregon Dummy Temp/Humidity sensors                      |
2216  +---------------------------------------------------------------------*/
opt_oreTHemu(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2217 int opt_oreTHemu ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2218 {
2219    if ( opt_ore_dummy(aliasp, aliasindex, tokens, ntokens) != 0 )
2220       return 1;
2221 
2222    aliasp[aliasindex].subtype = OreTHemu;
2223    aliasp[aliasindex].nvar = 2;
2224    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2225    aliasp[aliasindex].funclist[0] = OreTempFunc;
2226    aliasp[aliasindex].funclist[1] = OreHumidFunc;
2227 
2228    return 0;
2229 }
2230 
2231 /*---------------------------------------------------------------------+
2232  | Options for Oregon Dummy THB sensors                                |
2233  +---------------------------------------------------------------------*/
opt_oreTHBemu(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2234 int opt_oreTHBemu ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2235 {
2236    if ( opt_ore_dummy(aliasp, aliasindex, tokens, ntokens) != 0 )
2237       return 1;
2238 
2239    aliasp[aliasindex].subtype = OreTHBemu;
2240    aliasp[aliasindex].nvar = 3;
2241    aliasp[aliasindex].storage_units = 2 * aliasp[aliasindex].nvar;
2242    aliasp[aliasindex].funclist[0] = OreTempFunc;
2243    aliasp[aliasindex].funclist[1] = OreHumidFunc;
2244    aliasp[aliasindex].funclist[2] = OreBaroFunc;
2245 
2246    return 0;
2247 }
2248 
2249 /*-------------------------------------------------------+
2250  | Called for Oregon sensor IDs which are to be ignored  |
2251  +-------------------------------------------------------*/
opt_oreignore(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2252 int opt_oreignore ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2253 {
2254    char   *sp;
2255    long   ident;
2256    int    j;
2257 
2258    /* First token is security ID */
2259    if ( *ntokens < 1 ) {
2260       store_error_message("Module ID(s) needed.");
2261       return 1;
2262    }
2263    if ( *ntokens > NIDENT ) {
2264       store_error_message("Too many parameters on line.");
2265       return 1;
2266    }
2267 
2268    for ( j = 0; j < *ntokens; j++ ) {
2269       ident = strtol(tokens[j], &sp, 16);
2270       if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {  /* Was 0xaff ??? */
2271          aliasp[aliasindex].ident[j] = (unsigned short)ident;
2272       }
2273       else {
2274          store_error_message("Invalid hexadecimal ID parameter");
2275          return 1;
2276       }
2277    }
2278    aliasp[aliasindex].nident = j;
2279 
2280    /* This is a security RF transmitter */
2281    aliasp[aliasindex].vtype = RF_OREGON;
2282    aliasp[aliasindex].optflags = (MOPT_SECURITY | MOPT_RFIGNORE);
2283 
2284    return 0;
2285 }
2286 
2287 #endif
2288 
2289 /*--------------------------------------------------------+
2290  | Called for Security sensor IDs which are to be ignored |
2291  +--------------------------------------------------------*/
opt_secignore(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2292 int opt_secignore ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2293 {
2294    char   *sp;
2295    long   ident;
2296    int    j;
2297 
2298    /* First token is security ID */
2299    if ( *ntokens < 1 ) {
2300       store_error_message("Module ID(s) needed.");
2301       return 1;
2302    }
2303    if ( *ntokens > NIDENT ) {
2304       store_error_message("Too many parameters on line.");
2305       return 1;
2306    }
2307 
2308    for ( j = 0; j < *ntokens; j++ ) {
2309       ident = strtol(tokens[j], &sp, 16);
2310       if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
2311          aliasp[aliasindex].ident[j] = (unsigned short)ident;
2312       }
2313       else {
2314          store_error_message("Invalid hexadecimal ID parameter");
2315          return 1;
2316       }
2317    }
2318    aliasp[aliasindex].nident = j;
2319 
2320    /* This is a security RF transmitter */
2321    aliasp[aliasindex].vtype = RF_SEC;
2322    aliasp[aliasindex].optflags = (MOPT_SECURITY | MOPT_RFIGNORE);
2323 
2324    return 0;
2325 }
2326 
2327 /*-------------------------------------------------------+
2328  | Called by add_module_options() to add the identity of |
2329  | the X-10 UX17A transceiver to the module.             |
2330  +-------------------------------------------------------*/
opt_ux17a(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2331 int opt_ux17a ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2332 {
2333 
2334    if ( *ntokens > 0 ) {
2335       store_error_message("This module takes no parameters.");
2336       return 1;
2337    }
2338 
2339    /* First byte of UX17A codeword is either 0x82 or 0x83 */
2340    aliasp[aliasindex].nident = 2;
2341    aliasp[aliasindex].ident[0] = 0x82;
2342    aliasp[aliasindex].ident[1] = 0x83;
2343 
2344    /* This is an entertainment remote transmitter */
2345    aliasp[aliasindex].vtype = RF_ENT;
2346 
2347    return 0;
2348 }
2349 
2350 /*-------------------------------------------------------+
2351  | Called by add_module_options() to add the identity of |
2352  | the X-10 UR81A remote to the module.                  |
2353  +-------------------------------------------------------*/
opt_ur81a(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2354 int opt_ur81a ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2355 {
2356 
2357    if ( *ntokens > 0 ) {
2358       store_error_message("This module takes no parameters.");
2359       return 1;
2360    }
2361 
2362    /* First byte of UR81A codeword is always 0xEE */
2363    aliasp[aliasindex].nident = 1;
2364    aliasp[aliasindex].ident[0] = 0xEE;
2365 
2366    /* This is an entertainment remote transmitter */
2367    aliasp[aliasindex].vtype = RF_ENT;
2368 
2369    return 0;
2370 }
2371 
2372 /*-------------------------------------------------------+
2373  | Called by add_module_options() to add the IDs for a   |
2374  | generic entertainment remote.  Valid ID bytes for an  |
2375  | entertainment remote have bit 2 (1-8) set.            |
2376  +-------------------------------------------------------*/
opt_guru(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2377 int opt_guru ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2378 {
2379    char   *sp;
2380    long   ident;
2381    int    j;
2382 
2383    /* Tokens are IDs */
2384    if ( *ntokens < 1 ) {
2385       store_error_message("At least one entertainment ID is needed.");
2386       return 1;
2387    }
2388    if ( *ntokens > NIDENT ) {
2389       store_error_message("Too many parameters on line.");
2390       return 1;
2391    }
2392 
2393    for ( j = 0; j < *ntokens; j++ ) {
2394       ident = strtol(tokens[j], &sp, 16);
2395       if ( *sp == '\0' && ident >= 0 && ident <= 0xff && (ident & 0x02) ) {
2396          aliasp[aliasindex].ident[j] = (unsigned short)ident;
2397       }
2398       else {
2399          store_error_message("Invalid hexadecimal entertainment ID parameter");
2400          return 1;
2401       }
2402    }
2403    aliasp[aliasindex].nident = j;
2404 
2405    /* This is an entertainment RF transmitter */
2406    aliasp[aliasindex].vtype = RF_ENT;
2407    aliasp[aliasindex].optflags |= MOPT_ENTERTAIN;
2408 
2409    return 0;
2410 }
2411 
2412 
2413 
2414 
2415 /*-------------------------------------------------------+
2416  | For security remotes with Arm/Disarm buttons          |
2417  | Called by add_module_options() to add the RF security |
2418  | ID from the ALIAS line in the config file.            |
2419  +-------------------------------------------------------*/
opt_kremote(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2420 int opt_kremote ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2421 {
2422    char   *sp;
2423    long   ident;
2424    int    j;
2425 
2426    if ( remote_options(aliasp, aliasindex, tokens, ntokens) != 0 )
2427       return 1;
2428 
2429    /* First token is security ID */
2430    if ( *ntokens < 1 ) {
2431       store_error_message("Module ID is needed.");
2432       return 1;
2433    }
2434    if ( *ntokens > NIDENT ) {
2435       store_error_message("Too many parameters on line.");
2436       return 1;
2437    }
2438 
2439    for ( j = 0; j < *ntokens; j++ ) {
2440       ident = strtol(tokens[j], &sp, 16);
2441       if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
2442          aliasp[aliasindex].ident[j] = (unsigned short)ident;
2443       }
2444       else {
2445          store_error_message("Invalid hexadecimal ID parameter");
2446          return 1;
2447       }
2448    }
2449    aliasp[aliasindex].nident = j;
2450 
2451    /* This is a security RF transmitter */
2452    aliasp[aliasindex].vtype = RF_SEC;
2453    aliasp[aliasindex].optflags |= MOPT_SECURITY;
2454 
2455    return 0;
2456 }
2457 
2458 /*-------------------------------------------------------+
2459  | Called by add_module_options() to add the RF security |
2460  | ID from the ALIAS line in the config file.            |
2461  +-------------------------------------------------------*/
opt_sremote(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2462 int opt_sremote ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2463 {
2464    char   *sp;
2465    long   ident;
2466    int    j;
2467 
2468    /* First token is security ID */
2469    if ( *ntokens < 1 ) {
2470       store_error_message("Module ID is needed.");
2471       return 1;
2472    }
2473    if ( *ntokens > NIDENT ) {
2474       store_error_message("Too many parameters on line.");
2475       return 1;
2476    }
2477 
2478    for ( j = 0; j < *ntokens; j++ ) {
2479       ident = strtol(tokens[j], &sp, 16);
2480       if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
2481          aliasp[aliasindex].ident[j] = (unsigned short)ident;
2482       }
2483       else {
2484          store_error_message("Invalid hexadecimal ID parameter");
2485          return 1;
2486       }
2487    }
2488    aliasp[aliasindex].nident = j;
2489 
2490    /* This is a security RF transmitter */
2491    aliasp[aliasindex].vtype = RF_SEC;
2492    aliasp[aliasindex].optflags |= MOPT_SECURITY;
2493 
2494    return 0;
2495 }
2496 
2497 /*-------------------------------------------------------+
2498  | Like opt_sremote by also identified as a sensor       |
2499  +-------------------------------------------------------*/
opt_svsensor(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2500 int opt_svsensor ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2501 {
2502    if ( opt_sensor(aliasp, aliasindex, tokens, ntokens) != 0 )
2503       return 1;
2504 
2505    if ( aliasp[aliasindex].optflags & MOPT_REVERSE ) {
2506       store_error_message("Unsupported module option REVERSE");
2507       return 1;
2508    }
2509 
2510    aliasp[aliasindex].optflags &= ~(MOPT_HEARTBEAT | MOPT_LOBAT);
2511 
2512    return 0;
2513 }
2514 
opt_visonic(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2515 int opt_visonic ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2516 {
2517    char   *sp;
2518    long   ident;
2519    int    j;
2520 
2521    /* First token is security ID */
2522    if ( *ntokens < 1 ) {
2523       store_error_message("Module ID is needed.");
2524       return 1;
2525    }
2526    if ( *ntokens > NIDENT ) {
2527       store_error_message("Too many parameters on line.");
2528       return 1;
2529    }
2530 
2531    for ( j = 0; j < *ntokens; j++ ) {
2532       ident = strtol(tokens[j], &sp, 16);
2533       if ( *sp == '\0' && ident >= 0 && ident <= 0xffffff ) {
2534          aliasp[aliasindex].ident[j] = ident;
2535       }
2536       else {
2537          store_error_message("Invalid hexadecimal ID parameter");
2538          return 1;
2539       }
2540    }
2541    aliasp[aliasindex].nident = j;
2542 
2543    /* This is a security RF transmitter */
2544    aliasp[aliasindex].vtype = RF_VISONIC;
2545    aliasp[aliasindex].optflags |= MOPT_SECURITY;
2546 
2547    return 0;
2548 }
2549 
2550 /*-------------------------------------------------------+
2551  | Called by add_module_options() to add the RF security |
2552  | sensor options from the ALIAS line in the config file.|
2553  +-------------------------------------------------------*/
opt_sensor(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2554 int opt_sensor ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2555 {
2556    sensor_options(aliasp, aliasindex, tokens, ntokens);
2557 
2558    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
2559       return 1;
2560 
2561    if ( opt_sremote(aliasp, aliasindex, tokens, ntokens) != 0 )
2562       return 1;
2563 
2564    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
2565       store_error_message("Multiple unit alias is invalid for sensors.");
2566       return 1;
2567    }
2568 
2569    if ( aliasp[aliasindex].nident > 1 ) {
2570       store_error_message("Only one security ID is supported");
2571       return 1;
2572    }
2573 
2574    if ( aliasp[aliasindex].optflags & (MOPT_MAIN | MOPT_AUX) ) {
2575       store_error_message("Unsupported module option MAIN or AUX");
2576       return 1;
2577    }
2578 
2579    /* This is a sensor with periodic "heartbeat" signals and low battery flag */
2580    aliasp[aliasindex].optflags |= (MOPT_SENSOR | MOPT_HEARTBEAT | MOPT_LOBAT);
2581 
2582    return 0;
2583 }
2584 
2585 /*-------------------------------------------------------+
2586  | Called by add_module_options() to add the SD90 Smoke  |
2587  | Detector IDs from the ALIAS line in the config file.  |
2588  +-------------------------------------------------------*/
opt_sd90(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2589 int opt_sd90 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2590 {
2591    unsigned short id0, id1;
2592    unsigned long  optflags = 0;
2593 
2594    sensor_options(aliasp, aliasindex, tokens, ntokens);
2595 
2596    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
2597       return 1;
2598 
2599    if ( opt_sremote(aliasp, aliasindex, tokens, ntokens) != 0 )
2600       return 1;
2601 
2602    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
2603       store_error_message("Multiple unit alias is invalid.");
2604       return 1;
2605    }
2606 
2607    if ( aliasp[aliasindex].nident == 2 ) {
2608       id0 = aliasp[aliasindex].ident[0] & 0x00F0;
2609       id1 = aliasp[aliasindex].ident[1] & 0x00F0;
2610       if ( (id0 == 0xC0 && id1 == 0xD0) ||
2611            (id0 == 0xD0 && id1 == 0xC0)    ) {
2612          optflags = (MOPT_SENSOR | MOPT_HEARTBEAT | MOPT_LOBAT);
2613       }
2614       else {
2615          store_error_message("Invalid ID value for the SD90");
2616          return 1;
2617       }
2618    }
2619    else if ( aliasp[aliasindex].nident == 1 ) {
2620       id0 = aliasp[aliasindex].ident[0] & 0x00F0;
2621       if ( id0 == 0xD0 ) {
2622          /* Sensor ID */
2623          optflags = (MOPT_SENSOR | MOPT_HEARTBEAT | MOPT_LOBAT);
2624       }
2625       else if ( id0 == 0xC0 ) {
2626          /* Emergency ID */
2627          optflags = 0;
2628       }
2629       else {
2630          store_error_message("Invalid ID value for the SD90");
2631          return 1;
2632       }
2633    }
2634    else {
2635       store_error_message("SD90 module type requires one or two IDs");
2636       return 1;
2637    }
2638 
2639    if ( aliasp[aliasindex].optflags & (MOPT_MAIN | MOPT_AUX | MOPT_REVERSE) ) {
2640       store_error_message("Unsupported module option");
2641       return 1;
2642    }
2643 
2644    /* This is a sensor */
2645    aliasp[aliasindex].optflags |= /* MOPT_SENSOR | */ optflags;
2646 
2647    return 0;
2648 }
2649 
2650 /*-------------------------------------------------------+
2651  | Called by add_module_options() for the Marmitek SD10  |
2652  | Smoke Detector which has no "heartbeat".              |
2653  +-------------------------------------------------------*/
opt_sd10(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2654 int opt_sd10 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2655 {
2656    char   *sp;
2657    long   ident;
2658 
2659    /* Token is security ID */
2660    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
2661       store_error_message("Multiple unit alias is invalid for sensors.");
2662       return 1;
2663    }
2664 
2665    if ( *ntokens < 1 ) {
2666       store_error_message("Module ID is needed.");
2667       return 1;
2668    }
2669    else if ( *ntokens > 1 ) {
2670       store_error_message("Only one security ID is supported.");
2671       return 1;
2672    }
2673 
2674    ident = strtol(tokens[0], &sp, 16);
2675    if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
2676       aliasp[aliasindex].ident[0] = (unsigned short)ident;
2677    }
2678    else {
2679       store_error_message("Invalid hexadecimal ID parameter");
2680       return 1;
2681    }
2682 
2683    aliasp[aliasindex].nident = 1;
2684 
2685    /* This is a security RF transmitter */
2686    aliasp[aliasindex].vtype = RF_SEC;
2687    aliasp[aliasindex].optflags |= MOPT_SECURITY;
2688 
2689    return 0;
2690 }
2691 
2692 /*-------------------------------------------------------+
2693  | Called by add_module_options() for the BMB-SD18       |
2694  | Smoke Detector                                        |
2695  +-------------------------------------------------------*/
opt_bmb_sd18(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2696 int opt_bmb_sd18 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2697 {
2698    char   *sp;
2699    long   ident;
2700 
2701    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
2702       return 1;
2703 
2704    /* Token is security ID */
2705    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
2706       store_error_message("Multiple unit alias is invalid for sensors.");
2707       return 1;
2708    }
2709 
2710    if ( *ntokens < 1 ) {
2711       store_error_message("Module ID is needed.");
2712       return 1;
2713    }
2714    else if ( *ntokens > 1 ) {
2715       store_error_message("Only one security ID is supported.");
2716       return 1;
2717    }
2718 
2719    ident = strtol(tokens[0], &sp, 16);
2720    if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
2721       aliasp[aliasindex].ident[0] = (unsigned short)ident;
2722    }
2723    else {
2724       store_error_message("Invalid hexadecimal ID parameter");
2725       return 1;
2726    }
2727 
2728    aliasp[aliasindex].nident = 1;
2729 
2730    /* This is a security RF transmitter */
2731    aliasp[aliasindex].vtype = RF_SEC;
2732    aliasp[aliasindex].optflags |= (MOPT_SENSOR | MOPT_SECURITY | MOPT_HEARTBEAT | MOPT_LOBAT);
2733 
2734    return 0;
2735 }
2736 
2737 /*-------------------------------------------------------+
2738  | Called by add_module_options() for the Marmitek GB10  |
2739  | Glass Break sensor.                                   |
2740  +-------------------------------------------------------*/
opt_gb10(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2741 int opt_gb10 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2742 {
2743    char   *sp;
2744    long   ident;
2745 
2746    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
2747       return 1;
2748 
2749    /* Token is security ID */
2750    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
2751       store_error_message("Multiple unit alias is invalid for sensors.");
2752       return 1;
2753    }
2754 
2755    if ( *ntokens < 1 ) {
2756       store_error_message("Module ID is needed.");
2757       return 1;
2758    }
2759    else if ( *ntokens > 1 ) {
2760       store_error_message("Only one security ID is supported");
2761       return 1;
2762    }
2763 
2764    ident = strtol(tokens[0], &sp, 16);
2765    if ( *sp == '\0' && ident >= 0 && ident <= 0xffff ) {
2766       aliasp[aliasindex].ident[0] = (unsigned short)ident;
2767    }
2768    else {
2769       store_error_message("Invalid hexadecimal ID parameter");
2770       return 1;
2771    }
2772 
2773    aliasp[aliasindex].nident = 1;
2774 
2775    /* This is a security RF transmitter */
2776    aliasp[aliasindex].vtype = RF_SEC;
2777    aliasp[aliasindex].optflags |= ((MOPT_SENSOR | MOPT_SECURITY | MOPT_HEARTBEAT) & ~MOPT_LOBAT);
2778 
2779    return 0;
2780 }
2781 
2782 /*-------------------------------------------------------+
2783  | Called by add_module_options() for Standard X10       |
2784  | sensors, e.g., MS12,13,14,16 motion detectors.        |
2785  +-------------------------------------------------------*/
opt_x10std(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2786 int opt_x10std ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2787 {
2788 
2789    aliasp[aliasindex].optflags = 0;
2790 
2791    opt_aux(aliasp, aliasindex, tokens, ntokens);
2792 
2793 #if 0
2794    aliasp[aliasindex].optflags = 0;
2795 
2796    for ( j = 0; j < *ntokens; j++ ) {
2797       strupper(tokens[j]);
2798       if ( strcmp(tokens[j], "TRANSCEIVE") == 0 ) {
2799          aliasp[aliasindex].optflags |= MOPT_TRANSCEIVE;
2800          *tokens[j] = '\0';
2801          count++;
2802       }
2803       else if ( strcmp(tokens[j], "RFFORWARD") == 0 ) {
2804          aliasp[aliasindex].optflags |= MOPT_RFFORWARD;
2805          *tokens[j] = '\0';
2806          count++;
2807       }
2808       else if ( strcmp(tokens[j], "RFIGNORE") == 0 ) {
2809          aliasp[aliasindex].optflags |= MOPT_RFIGNORE;
2810          *tokens[j] = '\0';
2811          count++;
2812       }
2813       else {
2814          store_error_message("Unknown RF option parameter.");
2815          return 1;
2816       }
2817    }
2818 
2819    if ( count > 1 ) {
2820       store_error_message("Conflicting RF options.");
2821       return 1;
2822    }
2823 
2824    /* Compact to remove "gaps" where tokens were nulled out */
2825 
2826    for ( j = 0; j < *ntokens; j++ ) {
2827       if ( *tokens[j] == '\0' ) {
2828          for ( k = j + 1; k < *ntokens; k++ ) {
2829             if ( *tokens[k] != '\0' ) {
2830                tmptok = tokens[j];
2831                tokens[j] = tokens[k];
2832                tokens[k] = tmptok;
2833                *tmptok = '\0';
2834                break;
2835             }
2836          }
2837       }
2838    }
2839 
2840    *ntokens -= count;
2841 #endif
2842 
2843    aliasp[aliasindex].nident = 0;
2844 
2845    /* This is a Standard X10 RF sensor transmitter */
2846    aliasp[aliasindex].vtype = RF_STD;
2847    aliasp[aliasindex].optflags |= MOPT_SENSOR;
2848 
2849    return 0;
2850 }
2851 
2852 /*-------------------------------------------------------+
2853  | Called by add_module_options() to add the RFXTemp     |
2854  | ID from the ALIAS line in the config file.            |
2855  +-------------------------------------------------------*/
opt_rfxtemp(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2856 int opt_rfxtemp ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2857 {
2858    sensor_options(aliasp, aliasindex, tokens, ntokens);
2859 
2860    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
2861       return 1;
2862 
2863    if ( opt_sremote(aliasp, aliasindex, tokens, ntokens) != 0 )
2864       return 1;
2865 
2866    if ( aliasp[aliasindex].nident > 1 ) {
2867       store_error_message("Only one RFXTemp ID is supported");
2868       return 1;
2869    }
2870 
2871    /* This is a sensor with periodic "heartbeat" signals */
2872    aliasp[aliasindex].vtype = RF_XSENSOR;
2873    aliasp[aliasindex].optflags |= (MOPT_RFXSENSOR | MOPT_HEARTBEAT | MOPT_LOBAT);
2874 
2875    return 0;
2876 }
2877 
2878 /*-------------------------------------------------------+
2879  | Called by add_module_options() to add the RF security |
2880  | sensor options from the ALIAS line in the config file.|
2881  +-------------------------------------------------------*/
opt_ds90(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2882 int opt_ds90 ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2883 {
2884    int check_ds90_ids( unsigned /*short*/ long * );
2885    unsigned short comp_ds90_id( unsigned short, int );
2886 
2887    sensor_options(aliasp, aliasindex, tokens, ntokens);
2888 
2889    if ( sensor_timeout(aliasp, aliasindex, tokens, ntokens) != 0 )
2890       return 1;
2891 
2892    if ( opt_sremote(aliasp, aliasindex, tokens, ntokens) != 0 )
2893       return 1;
2894 
2895    if ( (aliasp[aliasindex].optflags & MOPT_MAIN) &&
2896         (aliasp[aliasindex].optflags & MOPT_AUX)     ) {
2897       store_error_message("Module options MAIN and AUX are incompatible");
2898       return 1;
2899    }
2900 
2901    if ( aliasp[aliasindex].nident > 2 ) {
2902       store_error_message("Too many security IDs for DS90");
2903       return 1;
2904    }
2905    else if ( aliasp[aliasindex].nident == 2 ) {
2906       /* Check main and aux ID and reverse order if necessary */
2907       if ( check_ds90_ids(aliasp[aliasindex].ident) != 0 ) {
2908          store_error_message("DS90 security IDs are incompatible");
2909          return 1;
2910       }
2911    }
2912    else if ( aliasp[aliasindex].optflags & MOPT_MAIN ) {
2913       aliasp[aliasindex].ident[1] =
2914             comp_ds90_id(aliasp[aliasindex].ident[0], COMPUTE_AUX);
2915       aliasp[aliasindex].nident = 2;
2916    }
2917    else if ( aliasp[aliasindex].optflags & MOPT_AUX ) {
2918       aliasp[aliasindex].ident[1] = aliasp[aliasindex].ident[0];
2919       aliasp[aliasindex].ident[0] =
2920             comp_ds90_id(aliasp[aliasindex].ident[1], COMPUTE_MAIN);
2921       aliasp[aliasindex].nident = 2;
2922    }
2923 
2924    /* This is a sensor with periodic "heartbeat" signals */
2925    aliasp[aliasindex].optflags |= (MOPT_SENSOR | MOPT_SECURITY | MOPT_HEARTBEAT | MOPT_LOBATUNKN);
2926 
2927    return 0;
2928 }
2929 
2930 
2931 /*-------------------------------------------------------+
2932  | Called by add_module_options() to add the RESUME or   |
2933  | ONFULL <level> options from the ALIAS line in the     |
2934  | config file.                                          |
2935  +-------------------------------------------------------*/
opt_onlevel(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2936 int opt_onlevel ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
2937 {
2938    int    j, type, val, maxval, valoffset;
2939    char   *sp;
2940 
2941    type = aliasp[aliasindex].modtype;
2942    maxval = modules[type].maxlevel;
2943    valoffset = (modules[type].cflags & PRESET) ? 1 : 0;
2944 
2945    for ( j = 0; j < *ntokens; j++ )
2946       strupper(tokens[j]);
2947 
2948    j = 0;
2949    while ( *ntokens > 0 ) {
2950       if ( !strcmp(tokens[j], "ONLEVEL") ) {
2951          if ( *ntokens > 1 &&
2952               (!strcmp(tokens[j + 1], "RESUME") ||
2953                !strcmp(tokens[j + 1], "0"))        ) {
2954             aliasp[aliasindex].flags |= RESUME;
2955             aliasp[aliasindex].flags &= ~ONFULL;
2956             aliasp[aliasindex].optflags |= MOPT_RESUME;
2957             aliasp[aliasindex].optflags &= ~MOPT_ONFULL;
2958             aliasp[aliasindex].onlevel = maxval;
2959             j += 2;
2960             *ntokens -= 2;
2961          }
2962          else if ( *ntokens > 1 &&
2963                  (val = strtol(tokens[j + 1], &sp, 10)) &&
2964                  *sp == '\0' && val > 0 &&
2965                   val <= (maxval + valoffset) ) {
2966             aliasp[aliasindex].flags &= ~RESUME;
2967             aliasp[aliasindex].flags |= ONFULL;
2968             aliasp[aliasindex].optflags &= ~MOPT_RESUME;
2969             aliasp[aliasindex].optflags |= MOPT_ONFULL;
2970             aliasp[aliasindex].onlevel = val - valoffset;
2971             j += 2;
2972             *ntokens -= 2;
2973          }
2974          else if ( *ntokens > 1 ) {
2975             store_error_message("Invalid ONLEVEL parameter");
2976             return 1;
2977          }
2978          else {
2979             store_error_message("Missing ONLEVEL parameter");
2980             return 1;
2981          }
2982       }
2983       else {
2984          store_error_message("Module option not recognized");
2985          return 1;
2986       }
2987    }
2988    return 0;
2989 }
2990 
2991 
2992 /*---------------------------------------------------------------------+
2993  | Set TRANSCEIVE, RFFORWARD, or RFIGNORE module options               |
2994  +---------------------------------------------------------------------*/
opt_aux(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)2995 int opt_aux ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens)
2996 {
2997    int  j, k, count = 0;
2998    char *tmptok;
2999 
3000    for ( j = 0; j < *ntokens; j++ ) {
3001       strupper(tokens[j]);
3002       if ( strcmp(tokens[j], "TRANSCEIVE") == 0 ) {
3003          aliasp[aliasindex].optflags |= MOPT_TRANSCEIVE;
3004          *tokens[j] = '\0';
3005          count++;
3006       }
3007       else if ( strcmp(tokens[j], "RFFORWARD") == 0 ) {
3008          aliasp[aliasindex].optflags |= MOPT_RFFORWARD;
3009          *tokens[j] = '\0';
3010          count++;
3011       }
3012       else if ( strcmp(tokens[j], "RFIGNORE") == 0 ) {
3013          aliasp[aliasindex].optflags |= MOPT_RFIGNORE;
3014          *tokens[j] = '\0';
3015          count++;
3016       }
3017       else {
3018          store_error_message("Unknown RF option parameter.");
3019          return 1;
3020       }
3021    }
3022 
3023    if ( count == 0 ) {
3024       store_error_message("RF option TRANSCEIVE, RFFORWARD, or RFIGNORE required.");
3025       return 1;
3026    }
3027    else if ( count > 1 ) {
3028       store_error_message("Conflicting RF options.");
3029       return 1;
3030    }
3031 
3032    /* Compact to remove "gaps" where tokens were nulled out */
3033 
3034    for ( j = 0; j < *ntokens; j++ ) {
3035       if ( *tokens[j] == '\0' ) {
3036          for ( k = j + 1; k < *ntokens; k++ ) {
3037             if ( *tokens[k] != '\0' ) {
3038                tmptok = tokens[j];
3039                tokens[j] = tokens[k];
3040                tokens[k] = tmptok;
3041                *tmptok = '\0';
3042                break;
3043             }
3044          }
3045       }
3046    }
3047 
3048    *ntokens -= count;
3049 
3050    return 0;
3051 }
3052 
3053 /*-------------------------------------------------------+
3054  | Called by add_module_options() to add the identity of |
3055  | a jamming signal from a (older) RFXCOM receiver       |
3056  +-------------------------------------------------------*/
opt_jam(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)3057 int opt_jam ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
3058 {
3059 
3060    if ( *ntokens > 0 ) {
3061       store_error_message("This module takes no parameters.");
3062       return 1;
3063    }
3064 
3065    /* ID is either 0xFF (master) or 0x00 (slave) */
3066    aliasp[aliasindex].nident = 2;
3067    aliasp[aliasindex].ident[0] = 0xFF;
3068    aliasp[aliasindex].ident[1] = 0x00;
3069 
3070    /* This is a security remote transmitter */
3071    aliasp[aliasindex].vtype = RF_SEC;
3072 
3073    return 0;
3074 }
3075 
3076 
3077 /*---------------------------------------------------------------------+
3078  | Process received vdata for GB10 Glass Break Sensor                  |
3079  +---------------------------------------------------------------------*/
fn_gb10(struct xlate_vdata_st * xlate_vdata)3080 int fn_gb10 ( struct xlate_vdata_st *xlate_vdata )
3081 {
3082   unsigned int vdata;
3083 
3084   vdata = xlate_vdata->vdata;
3085 
3086   if ( vdata & ~(0xF4u) ) {
3087      /* Unknown code */
3088      xlate_vdata->func = VdataFunc;
3089      xlate_vdata->trig = VdataTrig;
3090      xlate_vdata->vflags = 0;
3091      return 0;
3092   }
3093 
3094   if ( vdata == 0xF0u ) {
3095      xlate_vdata->func = DuskFunc;
3096      xlate_vdata->trig = DuskTrig;
3097   }
3098   else if ( vdata & 0x80u ) {
3099      xlate_vdata->func = ClearFunc;
3100      xlate_vdata->trig = ClearTrig;
3101   }
3102   else {
3103      xlate_vdata->func = AlertFunc;
3104      xlate_vdata->trig = AlertTrig;
3105   }
3106 
3107 #if 0
3108   xlate_vdata->vflags = (vdata & 0x01u) ? SEC_LOBAT : 0;
3109 #endif  /* May be needed */
3110 
3111   return 0;
3112 }
3113 
3114 
3115 /*---------------------------------------------------------------------+
3116  | Process received vdata for (Euro) DM10 Motion/Dusk/Dawn sensor      |
3117  +---------------------------------------------------------------------*/
fn_dm10(struct xlate_vdata_st * xlate_vdata)3118 int fn_dm10 ( struct xlate_vdata_st *xlate_vdata )
3119 {
3120   unsigned int vdata;
3121 
3122   vdata = xlate_vdata->vdata;
3123 
3124   if ( vdata == 0xE0u ) {
3125      xlate_vdata->func = AlertFunc;
3126      xlate_vdata->trig = AlertTrig;
3127   }
3128   else if ( vdata == 0xF0 ) {
3129      xlate_vdata->func = DuskFunc;
3130      xlate_vdata->trig = DuskTrig;
3131   }
3132   else if ( vdata == 0xF8 ) {
3133      xlate_vdata->func = DawnFunc;
3134      xlate_vdata->trig = DawnTrig;
3135   }
3136   else {
3137      /* Unknown code */
3138      xlate_vdata->func = VdataFunc;
3139      xlate_vdata->trig = VdataTrig;
3140   }
3141 
3142   xlate_vdata->vflags = 0;
3143 
3144 #if 0
3145   xlate_vdata->vflags = (vdata & 0x01u) ? SEC_LOBAT : 0;
3146 #endif  /* May be needed */
3147 
3148   return 0;
3149 }
3150 
3151 
3152 /*---------------------------------------------------------------------+
3153  | Process received vdata for DS10A Door/Window Sensor                 |
3154  +---------------------------------------------------------------------*/
fn_ds10a(struct xlate_vdata_st * xlate_vdata)3155 int fn_ds10a ( struct xlate_vdata_st *xlate_vdata )
3156 {
3157   unsigned int vdata;
3158   int          polarity;
3159 
3160   vdata = xlate_vdata->vdata;
3161   polarity = (xlate_vdata->optflags & MOPT_REVERSE) ? 0 : 1;
3162 
3163   xlate_vdata->vflags = 0;
3164 
3165 #if 0
3166   if ( vdata == 0xffu ) {
3167      xlate_vdata->func = InactiveFunc;
3168      xlate_vdata->trig = InactiveTrig;
3169      return 0;
3170   }
3171 #endif
3172 
3173   if ( vdata & ~(0x85u) ) {
3174      xlate_vdata->func = VdataFunc;
3175      xlate_vdata->trig = VdataTrig;
3176      return 0;
3177   }
3178 
3179   if ( vdata & 0x80u ) {
3180      xlate_vdata->func = polarity ? ClearFunc : AlertFunc;
3181      xlate_vdata->trig = polarity ? ClearTrig : AlertTrig;
3182   }
3183   else {
3184      xlate_vdata->func = polarity ? AlertFunc : ClearFunc;
3185      xlate_vdata->trig = polarity ? AlertTrig : ClearTrig;
3186   }
3187 
3188   if ( xlate_vdata->func == AlertFunc )
3189      xlate_vdata->vflags |= SEC_FAULT;
3190 
3191   xlate_vdata->vflags |= (vdata & 0x04u) ? SEC_MIN : SEC_MAX;
3192   xlate_vdata->vflags |= (vdata & 0x01u) ? SEC_LOBAT : 0;
3193 
3194   return 0;
3195 }
3196 
3197 /*---------------------------------------------------------------------+
3198  | Process received vdata for ElekHomica DS18 Door/Window Sensor       |
3199  +---------------------------------------------------------------------*/
fn_ds18(struct xlate_vdata_st * xlate_vdata)3200 int fn_ds18 ( struct xlate_vdata_st *xlate_vdata )
3201 {
3202   unsigned int vdata;
3203   int          polarity;
3204 
3205   vdata = xlate_vdata->vdata;
3206   polarity = (xlate_vdata->optflags & MOPT_REVERSE) ? 0 : 1;
3207 
3208   xlate_vdata->vflags = 0;
3209 
3210   if ( vdata & ~(0x85u) ) {
3211      xlate_vdata->func = VdataFunc;
3212      xlate_vdata->trig = VdataTrig;
3213      return 0;
3214   }
3215 
3216   if ( vdata & 0x80 ) {
3217      xlate_vdata->func = polarity ? ClearFunc : AlertFunc;
3218      xlate_vdata->trig = polarity ? ClearTrig : AlertTrig;
3219   }
3220   else {
3221      xlate_vdata->func = polarity ? AlertFunc : ClearFunc;
3222      xlate_vdata->trig = polarity ? AlertTrig : ClearTrig;
3223   }
3224 
3225   if ( xlate_vdata->func == AlertFunc )
3226      xlate_vdata->vflags |= SEC_FAULT;
3227 
3228   xlate_vdata->vflags |= (vdata & 0x04) ? SEC_MIN : SEC_MAX;
3229   xlate_vdata->vflags |= (vdata & 0x01) ? SEC_LOBAT : 0;
3230 
3231   return 0;
3232 }
3233 
3234 /*---------------------------------------------------------------------+
3235  | Process received vdata for DS90 Door/Window Sensor                  |
3236  +---------------------------------------------------------------------*/
fn_ds90(struct xlate_vdata_st * xlate_vdata)3237 int fn_ds90 ( struct xlate_vdata_st *xlate_vdata )
3238 {
3239   unsigned int   vdata;
3240   int            polarity;
3241 //  unsigned short mask;
3242   unsigned long  mask;
3243 
3244   vdata = xlate_vdata->vdata;
3245   polarity = (xlate_vdata->optflags & MOPT_REVERSE) ? 0 : 1;
3246 
3247   mask = configp->securid_mask;
3248 
3249   xlate_vdata->func = VdataFunc;
3250   xlate_vdata->trig = VdataTrig;
3251 
3252   if ( vdata & ~(0xc5u) ) {
3253      xlate_vdata->func = VdataFunc;
3254      xlate_vdata->trig = VdataTrig;
3255      return 0;
3256   }
3257 
3258   if ( (xlate_vdata->optflags & MOPT_MAIN) &&
3259        ((xlate_vdata->ident & mask) == (xlate_vdata->identp[1] & mask)) ) {
3260      /* MAIN specified and signal on AUX, ignore */
3261      return 1;
3262   }
3263   if ( (xlate_vdata->optflags & MOPT_AUX) &&
3264        ((xlate_vdata->ident & mask) == (xlate_vdata->identp[0] & mask)) ) {
3265      /* AUX specified and signal on MAIN, ignore */
3266      return 1;
3267   }
3268 
3269 
3270 #if 0
3271   if ( !(xlate_vdata->optflags & (MOPT_MAIN | MOPT_AUX))  &&
3272         (xlate_vdata->nident == 2) ) {
3273      /* Neither specified - add appropriate flag */
3274      xlate_vdata->vflags |=
3275          ((xlate_vdata->ident & mask) == (xlate_vdata->identp[0] & mask)) ? SEC_MAIN : SEC_AUX ;
3276   }
3277 #endif
3278 
3279 
3280    if ( xlate_vdata->nident == 2 ) {
3281       if ( !(xlate_vdata->optflags & (MOPT_MAIN | MOPT_AUX)) ) {
3282          xlate_vdata->vflags |=
3283            ((xlate_vdata->ident & mask) == (xlate_vdata->identp[0] & mask)) ? SEC_MAIN : SEC_AUX ;
3284       }
3285       else if ( xlate_vdata->optflags & MOPT_MAIN ) {
3286          xlate_vdata->vflags |= SEC_MAIN;
3287       }
3288       else {
3289          xlate_vdata->vflags |= SEC_AUX;
3290       }
3291    }
3292 
3293 
3294   if ( vdata & 0x40 ) {
3295      xlate_vdata->func = TamperFunc;
3296      xlate_vdata->trig = TamperTrig;
3297 //     xlate_vdata->vflags |= SEC_TAMPER;
3298   }
3299   else if ( vdata & 0x80 ) {
3300      xlate_vdata->func = polarity ? ClearFunc : AlertFunc;
3301      xlate_vdata->trig = polarity ? ClearTrig : AlertTrig;
3302   }
3303   else {
3304      xlate_vdata->func = polarity ? AlertFunc : ClearFunc;
3305      xlate_vdata->trig = polarity ? AlertTrig : ClearTrig;
3306   }
3307 
3308   if ( xlate_vdata->func == AlertFunc )
3309      xlate_vdata->vflags |= SEC_FAULT;
3310 
3311   xlate_vdata->vflags |= (vdata & 0x04) ? SEC_MIN : SEC_MAX;
3312   xlate_vdata->vflags |= (vdata & 0x01) ? SEC_LOBAT : 0;
3313 
3314   return 0;
3315 }
3316 
3317 /*---------------------------------------------------------------------+
3318  | Process received vdata for SD10 Security Smoke Detector             |
3319  +---------------------------------------------------------------------*/
fn_sd10(struct xlate_vdata_st * xlate_vdata)3320 int fn_sd10 ( struct xlate_vdata_st *xlate_vdata )
3321 {
3322 
3323   unsigned int vdata;
3324 
3325   vdata = xlate_vdata->vdata;
3326 
3327   xlate_vdata->vflags = 0;
3328 
3329   if ( vdata == 0x26u ) {
3330      xlate_vdata->func = AlertFunc;
3331      xlate_vdata->trig = AlertTrig;
3332   }
3333   else {
3334      xlate_vdata->func = VdataFunc;
3335      xlate_vdata->trig = VdataTrig;
3336   }
3337 
3338   return 0;
3339 }
3340 
3341 /*---------------------------------------------------------------------+
3342  | Process received vdata for BMB-SD18 SD10 Security Smoke Detector    |
3343  +---------------------------------------------------------------------*/
fn_bmb_sd18(struct xlate_vdata_st * xlate_vdata)3344 int fn_bmb_sd18 ( struct xlate_vdata_st *xlate_vdata )
3345 {
3346 
3347    unsigned int vdata;
3348 
3349    vdata = xlate_vdata->vdata;
3350 
3351    xlate_vdata->vflags = 0;
3352 
3353    xlate_vdata->vflags |= (vdata & 0x01) ? SEC_LOBAT : 0;
3354 
3355    switch ( vdata & ~(0x01u) ) {
3356       case 0x26u : /* "R" switch position */
3357          xlate_vdata->func = AlertFunc;
3358          xlate_vdata->trig = AlertTrig;
3359          break;
3360       case 0x66u : /* "R" switch position */
3361          xlate_vdata->func = ClearFunc;
3362          xlate_vdata->trig = ClearTrig;
3363          break;
3364       case 0x04u : /* "S" switch position */
3365          xlate_vdata->func = AlertFunc;
3366          xlate_vdata->trig = AlertTrig;
3367          break;
3368       case 0x80u : /* "S" switch position */
3369          xlate_vdata->func = ClearFunc;
3370          xlate_vdata->trig = ClearTrig;
3371          break;
3372       case 0x44u : /* Heartbeat, either "R" or "S" switch position */
3373          xlate_vdata->func = ClearFunc;
3374          xlate_vdata->trig = ClearTrig;
3375          break;
3376       default : /* Undefined codes */
3377          xlate_vdata->func = VdataFunc;
3378          xlate_vdata->trig = VdataTrig;
3379          break;
3380    }
3381 
3382    return 0;
3383 }
3384 
3385 /*---------------------------------------------------------------------+
3386  | Process received vdata for KR15A "Big Red Button"                   |
3387  +---------------------------------------------------------------------*/
fn_kr15a(struct xlate_vdata_st * xlate_vdata)3388 int fn_kr15a ( struct xlate_vdata_st *xlate_vdata )
3389 {
3390 
3391   unsigned int vdata;
3392 
3393   vdata = xlate_vdata->vdata;
3394 
3395   xlate_vdata->vflags = 0;
3396 
3397   if ( vdata == 0x03u ) {
3398      xlate_vdata->func = PanicFunc;
3399      xlate_vdata->trig = PanicTrig;
3400   }
3401   else {
3402      xlate_vdata->func = VdataFunc;
3403      xlate_vdata->trig = VdataTrig;
3404   }
3405 
3406   return 0;
3407 }
3408 
3409 /*---------------------------------------------------------------------+
3410  | Process received vdata for generic X10 security remote              |
3411  +---------------------------------------------------------------------*/
fn_svdata(struct xlate_vdata_st * xlate_vdata)3412 int fn_svdata ( struct xlate_vdata_st *xlate_vdata )
3413 {
3414 
3415   xlate_vdata->vflags = 0;
3416   xlate_vdata->func = VdataFunc;
3417   xlate_vdata->trig = VdataTrig;
3418 
3419   return 0;
3420 }
3421 
3422 /*---------------------------------------------------------------------+
3423  | Process received vdata for SD90 Security Smoke Detector             |
3424  +---------------------------------------------------------------------*/
fn_sd90(struct xlate_vdata_st * xlate_vdata)3425 int fn_sd90 ( struct xlate_vdata_st *xlate_vdata )
3426 {
3427 
3428   unsigned int vdata;
3429 
3430   vdata = xlate_vdata->vdata;
3431 
3432   xlate_vdata->vflags = 0;
3433 
3434 
3435   if ( vdata != 0x26u && vdata != 0x27u && (vdata & ~0x85u) ) {
3436      xlate_vdata->func = VdataFunc;
3437      xlate_vdata->trig = VdataTrig;
3438      return 0;
3439   }
3440 
3441   xlate_vdata->vflags |= (vdata & 0x01u) ? SEC_LOBAT : 0;
3442 
3443   if ( (vdata & 0x26u) == 0x26u ) {
3444      xlate_vdata->func = TestFunc;
3445      xlate_vdata->trig = TestTrig;
3446   }
3447   else if ( (vdata & 0x84u) == 0x84u ) {
3448      xlate_vdata->func = ClearFunc;
3449      xlate_vdata->trig = ClearTrig;
3450   }
3451   else {
3452      xlate_vdata->func = AlertFunc;
3453      xlate_vdata->trig = AlertTrig;
3454   }
3455 
3456   return 0;
3457 }
3458 
3459 /*---------------------------------------------------------------------+
3460  | Process received vdata for MS90 Security Motion Sensor              |
3461  +---------------------------------------------------------------------*/
fn_ms90(struct xlate_vdata_st * xlate_vdata)3462 int fn_ms90 ( struct xlate_vdata_st *xlate_vdata )
3463 {
3464 
3465   unsigned int vdata;
3466 
3467   vdata = xlate_vdata->vdata;
3468 
3469   xlate_vdata->vflags = 0;
3470 
3471 
3472   if ( (vdata & 0x0Cu) != 0x0Cu || vdata & ~(0xCDu) ) {
3473      xlate_vdata->func = VdataFunc;
3474      xlate_vdata->trig = VdataTrig;
3475      return 0;
3476   }
3477 
3478   xlate_vdata->vflags |= (vdata & 0x01u) ? SEC_LOBAT : 0;
3479 //  xlate_vdata->vflags |= (vdata & 0x40u) ? SEC_TAMPER : 0;
3480 
3481   if ( vdata & 0x40u ) {
3482      xlate_vdata->func = TamperFunc;
3483      xlate_vdata->trig = TamperTrig;
3484   }
3485   else if ( vdata & 0x80u ) {
3486      xlate_vdata->func = ClearFunc;
3487      xlate_vdata->trig = ClearTrig;
3488   }
3489   else {
3490      xlate_vdata->func = AlertFunc;
3491      xlate_vdata->trig = AlertTrig;
3492   }
3493 
3494   return 0;
3495 }
3496 
3497 /*---------------------------------------------------------------------+
3498  | Process received vdata for MS10A Security Motion Sensor             |
3499  +---------------------------------------------------------------------*/
fn_ms10a(struct xlate_vdata_st * xlate_vdata)3500 int fn_ms10a ( struct xlate_vdata_st *xlate_vdata )
3501 {
3502 
3503   unsigned int vdata;
3504 
3505   vdata = xlate_vdata->vdata;
3506 
3507   xlate_vdata->vflags = 0;
3508 
3509 
3510   if ( (vdata & 0x0cu) != 0x0cu || vdata & ~(0x8du) ) {
3511      xlate_vdata->func = VdataFunc;
3512      xlate_vdata->trig = VdataTrig;
3513      return 0;
3514   }
3515 
3516   xlate_vdata->vflags |= (vdata & 0x01u) ? SEC_LOBAT : 0;
3517 
3518   if ( vdata & 0x80u ) {
3519      xlate_vdata->func = ClearFunc;
3520      xlate_vdata->trig = ClearTrig;
3521   }
3522   else {
3523      xlate_vdata->func = AlertFunc;
3524      xlate_vdata->trig = AlertTrig;
3525   }
3526 
3527   return 0;
3528 }
3529 
3530 /*---------------------------------------------------------------------+
3531  | Process received vdata for SH624 Security Remote Control            |
3532  +---------------------------------------------------------------------*/
fn_sh624(struct xlate_vdata_st * xlate_vdata)3533 int fn_sh624 ( struct xlate_vdata_st *xlate_vdata )
3534 {
3535 
3536   unsigned int vdata;
3537 
3538   vdata = xlate_vdata->vdata;
3539 
3540   xlate_vdata->vflags = 0;
3541 
3542 
3543    if ( !(vdata & 0x02) || (vdata & 0x11) ) {
3544       xlate_vdata->func = VdataFunc;
3545       xlate_vdata->trig = VdataTrig;
3546       return 0;
3547    }
3548 
3549    if ( vdata & 0x20 ) {
3550       xlate_vdata->func = PanicFunc;
3551       xlate_vdata->trig = PanicTrig;
3552    }
3553    else if ( vdata & 0x40 ) {
3554       if ( vdata & 0x80 ) {
3555          xlate_vdata->func = SecLightsOffFunc;
3556          xlate_vdata->trig = SecLightsOffTrig;
3557       }
3558       else {
3559          xlate_vdata->func = SecLightsOnFunc;
3560          xlate_vdata->trig = SecLightsOnTrig;
3561       }
3562    }
3563    else {
3564       if ( vdata & 0x80 ) {
3565          xlate_vdata->func = DisarmFunc;
3566          xlate_vdata->trig = DisarmTrig;
3567       }
3568       else {
3569          xlate_vdata->func = ArmFunc;
3570          xlate_vdata->trig = ArmTrig;
3571          xlate_vdata->vflags |= ((vdata & 0x08) ? SEC_HOME : SEC_AWAY);
3572          xlate_vdata->vflags |= ((vdata & 0x04) ? SEC_MIN : SEC_MAX);
3573       }
3574    }
3575    return 0;
3576 }
3577 
3578 /*---------------------------------------------------------------------+
3579  | Process received vdata for KR10A Security Keychain Remote Control   |
3580  +---------------------------------------------------------------------*/
fn_kr10a(struct xlate_vdata_st * xlate_vdata)3581 int fn_kr10a ( struct xlate_vdata_st *xlate_vdata )
3582 {
3583 
3584   unsigned int vdata;
3585 
3586   vdata = xlate_vdata->vdata;
3587 
3588   xlate_vdata->vflags = 0;
3589 
3590 
3591    if ( (vdata & 0x0f) != 0x06 || (vdata & 0x11) ) {
3592       xlate_vdata->func = VdataFunc;
3593       xlate_vdata->trig = VdataTrig;
3594       return 0;
3595    }
3596 
3597    if ( vdata & 0x20 ) {
3598       xlate_vdata->func = PanicFunc;
3599       xlate_vdata->trig = PanicTrig;
3600    }
3601    else if ( vdata & 0x40 ) {
3602       if ( vdata & 0x80 ) {
3603          xlate_vdata->func = SecLightsOffFunc;
3604          xlate_vdata->trig = SecLightsOffTrig;
3605       }
3606       else {
3607          xlate_vdata->func = SecLightsOnFunc;
3608          xlate_vdata->trig = SecLightsOnTrig;
3609       }
3610    }
3611    else {
3612       if ( vdata & 0x80 ) {
3613          if ( xlate_vdata->optflags2 & MOPT2_DUMMY ) {
3614             xlate_vdata->func = ClearFunc;
3615             xlate_vdata->trig = ClearTrig;
3616          }
3617          else {
3618             xlate_vdata->func = DisarmFunc;
3619             xlate_vdata->trig = DisarmTrig;
3620          }
3621       }
3622       else {
3623          if ( xlate_vdata->optflags2 & MOPT2_DUMMY ) {
3624             xlate_vdata->func = AlertFunc;
3625             xlate_vdata->trig = AlertTrig;
3626          }
3627          else {
3628             xlate_vdata->func = ArmFunc;
3629             xlate_vdata->trig = ArmTrig;
3630             xlate_vdata->vflags |= (xlate_vdata->optflags2 & MOPT2_SWHOME) ? SEC_HOME : SEC_AWAY;
3631             xlate_vdata->vflags |= (xlate_vdata->optflags2 & MOPT2_SWMAX) ? SEC_MAX : SEC_MIN;
3632          }
3633       }
3634    }
3635    return 0;
3636 }
3637 
3638 /*---------------------------------------------------------------------+
3639  | Process received vdata for Marmitek KR18 Security Keychain Remote   |
3640  +---------------------------------------------------------------------*/
fn_kr18(struct xlate_vdata_st * xlate_vdata)3641 int fn_kr18 ( struct xlate_vdata_st *xlate_vdata )
3642 {
3643    xlate_vdata->vflags = 0;
3644 
3645    switch ( xlate_vdata-> vdata ) {
3646       case 0x26 :
3647          xlate_vdata->func = PanicFunc;
3648          xlate_vdata->trig = PanicTrig;
3649          break;
3650       case 0x06 :
3651          if ( xlate_vdata->optflags2 & MOPT2_DUMMY ) {
3652             xlate_vdata->func = AlertFunc;
3653             xlate_vdata->trig = AlertTrig;
3654          }
3655          else {
3656             xlate_vdata->func = ArmFunc;
3657             xlate_vdata->trig = ArmTrig;
3658             xlate_vdata->vflags |= (xlate_vdata->optflags2 & MOPT2_SWHOME) ? SEC_HOME : SEC_AWAY;
3659             xlate_vdata->vflags |= (xlate_vdata->optflags2 & MOPT2_SWMAX) ? SEC_MAX : SEC_MIN;
3660          }
3661          break;
3662       case 0x86 :
3663          if ( xlate_vdata->optflags2 & MOPT2_DUMMY ) {
3664             xlate_vdata->func = ClearFunc;
3665             xlate_vdata->trig = ClearTrig;
3666          }
3667          else {
3668             xlate_vdata->func = DisarmFunc;
3669             xlate_vdata->trig = DisarmTrig;
3670          }
3671          break;
3672       case 0x42 :
3673          xlate_vdata->func = AkeyOnFunc;
3674          xlate_vdata->trig = AkeyOnTrig;
3675          break;
3676       case 0xC2 :
3677          xlate_vdata->func = AkeyOffFunc;
3678          xlate_vdata->trig = AkeyOffTrig;
3679          break;
3680       case 0x46 :
3681          xlate_vdata->func = BkeyOnFunc;
3682          xlate_vdata->trig = BkeyOnTrig;
3683          break;
3684       case 0xC6 :
3685          xlate_vdata->func = BkeyOffFunc;
3686          xlate_vdata->trig = BkeyOffTrig;
3687          break;
3688       default :
3689          xlate_vdata->func = VdataFunc;
3690          xlate_vdata->trig = VdataTrig;
3691          break;
3692    }
3693    return 0;
3694 }
3695 
3696 /*---------------------------------------------------------------------+
3697  | Process received vdata for UR81A Entertainment Remote Control       |
3698  +---------------------------------------------------------------------*/
fn_ur81a(struct xlate_vdata_st * xlate_vdata)3699 int fn_ur81a ( struct xlate_vdata_st *xlate_vdata )
3700 {
3701 
3702    xlate_vdata->vflags = 0;
3703    xlate_vdata->func = VdataFunc;
3704    xlate_vdata->trig = VdataTrig;
3705 
3706    return 0;
3707 }
3708 
3709 /*---------------------------------------------------------------------+
3710  | Process received vdata for General Universal Remote Unit (GURU)     |
3711  +---------------------------------------------------------------------*/
fn_guru(struct xlate_vdata_st * xlate_vdata)3712 int fn_guru ( struct xlate_vdata_st *xlate_vdata )
3713 {
3714 
3715    xlate_vdata->vflags = 0;
3716    xlate_vdata->func = VdataFunc;
3717    xlate_vdata->trig = VdataTrig;
3718 
3719    return 0;
3720 }
3721 
3722 /*---------------------------------------------------------------------+
3723  | Process received vdata for RFXSensor                                |
3724  +---------------------------------------------------------------------*/
fn_rfxsensor(struct xlate_vdata_st * xlate_vdata)3725 int fn_rfxsensor ( struct xlate_vdata_st *xlate_vdata )
3726 {
3727 
3728    if ( (xlate_vdata->lobyte) & 0x10u && xlate_vdata->hibyte != 0x02u ) {
3729       xlate_vdata->func = RFXOtherFunc;
3730       xlate_vdata->trig = RFXOtherTrig;
3731       return 0;
3732    }
3733 
3734    switch ( xlate_vdata->ident % 0x04u ) {
3735       case 0 :
3736          xlate_vdata->func = RFXTempFunc;
3737          xlate_vdata->trig = RFXTempTrig;
3738          break;
3739       case 1 :
3740          if ( xlate_vdata->optflags & MOPT_RFXRH ) {
3741             xlate_vdata->func = RFXHumidFunc;
3742             xlate_vdata->trig = RFXHumidTrig;
3743          }
3744          else if ( xlate_vdata->optflags & MOPT_RFXBP ) {
3745             xlate_vdata->func = RFXPressFunc;
3746             xlate_vdata->trig = RFXPressTrig;
3747          }
3748          else if ( xlate_vdata->optflags & MOPT_RFXPOT ) {
3749             xlate_vdata->func = RFXPotFunc;
3750             xlate_vdata->trig = RFXPotTrig;
3751          }
3752          else {
3753             xlate_vdata->func = RFXVadFunc;
3754             xlate_vdata->trig = RFXVadTrig;
3755          }
3756          break;
3757       case 2 :
3758          if ( xlate_vdata->lobyte & 0x10u ) {
3759             xlate_vdata->func = RFXLoBatFunc;
3760             xlate_vdata->trig = RFXLoBatTrig;
3761          }
3762          else {
3763             xlate_vdata->func = RFXVsFunc;
3764             xlate_vdata->trig = RFXVsTrig;
3765          }
3766          break;
3767       default :
3768          break;
3769    }
3770 
3771    return 0;
3772 }
3773 
3774 /*---------------------------------------------------------------------+
3775  | Process received vdata for RFXMeter Pulse                           |
3776  +---------------------------------------------------------------------*/
fn_rfxpulse(struct xlate_vdata_st * xlate_vdata)3777 int fn_rfxpulse ( struct xlate_vdata_st *xlate_vdata )
3778 {
3779    xlate_vdata->vflags = 0;
3780    xlate_vdata->func = RFXPulseFunc;
3781    xlate_vdata->trig = RFXPulseTrig;
3782 
3783    return 0;
3784 }
3785 
3786 /*---------------------------------------------------------------------+
3787  | Process received vdata for RFXMeter Counter                         |
3788  +---------------------------------------------------------------------*/
fn_rfxcount(struct xlate_vdata_st * xlate_vdata)3789 int fn_rfxcount ( struct xlate_vdata_st *xlate_vdata )
3790 {
3791    xlate_vdata->vflags = 0;
3792    xlate_vdata->func = RFXCountFunc;
3793    xlate_vdata->trig = RFXCountTrig;
3794 
3795    return 0;
3796 }
3797 
3798 /*---------------------------------------------------------------------+
3799  | Process received vdata for RFXMeter Power                           |
3800  +---------------------------------------------------------------------*/
fn_rfxpower(struct xlate_vdata_st * xlate_vdata)3801 int fn_rfxpower ( struct xlate_vdata_st *xlate_vdata )
3802 {
3803    xlate_vdata->vflags = 0;
3804    xlate_vdata->func = RFXPowerFunc;
3805    xlate_vdata->trig = RFXPowerTrig;
3806 
3807    return 0;
3808 }
3809 
3810 /*---------------------------------------------------------------------+
3811  | Process received vdata for RFXMeter Water                           |
3812  +---------------------------------------------------------------------*/
fn_rfxwater(struct xlate_vdata_st * xlate_vdata)3813 int fn_rfxwater ( struct xlate_vdata_st *xlate_vdata )
3814 {
3815    xlate_vdata->vflags = 0;
3816    xlate_vdata->func = RFXWaterFunc;
3817    xlate_vdata->trig = RFXWaterTrig;
3818 
3819    return 0;
3820 }
3821 
3822 /*---------------------------------------------------------------------+
3823  | Process received vdata for RFXMeter Pulse                           |
3824  +---------------------------------------------------------------------*/
fn_rfxgas(struct xlate_vdata_st * xlate_vdata)3825 int fn_rfxgas ( struct xlate_vdata_st *xlate_vdata )
3826 {
3827    xlate_vdata->vflags = 0;
3828    xlate_vdata->func = RFXGasFunc;
3829    xlate_vdata->trig = RFXGasTrig;
3830 
3831    return 0;
3832 }
3833 
fn_visonic(struct xlate_vdata_st * xlate_vdata)3834 int fn_visonic ( struct xlate_vdata_st *xlate_vdata )
3835 {
3836 
3837    xlate_vdata->func = VdataFunc;
3838    xlate_vdata->trig = VdataTrig;
3839    xlate_vdata->vflags = 0;
3840 
3841    return 0;
3842 }
3843 
3844 /*---------------------------------------------------------------------+
3845  | Check the compatibility and order of DS90 IDs.  After bit reversal, |
3846  | each byte of the aux ID must be the corresponding byte of the       |
3847  | primary ID + 1.                                                     |
3848  | Reverse the order if necessary to get compatibility.                |
3849  | Return 0 if OK or 1 if the IDs don't have a valid relationship.     |
3850  +---------------------------------------------------------------------*/
check_ds90_ids(unsigned long * identp)3851 int check_ds90_ids( unsigned /*short*/ long *identp )
3852 {
3853    unsigned short mid, mid1, midlo, midhi, mask, temp;
3854    unsigned short aid, aid1, aidlo, aidhi;
3855 
3856    mask = (identp[0] > 0xffu || identp[1] > 0xffu) ? 0xffffu : 0x00ffu;
3857 
3858    midlo = rev_byte_bits( identp[0] & 0x00ffu);
3859    midhi = rev_byte_bits((identp[0] & 0xff00u & mask) >> 8) << 8;
3860    aidlo = rev_byte_bits( identp[1] & 0x00ffu);
3861    aidhi = rev_byte_bits((identp[1] & 0xff00u & mask) >> 8) << 8;
3862 
3863    mid = midhi | midlo;
3864    aid = aidhi | aidlo;
3865 
3866    mid1 = (((midhi + 0x0100u) & 0xff00u) | ((midlo + 0x0001u) & 0x00ffu)) & mask;
3867    aid1 = (((aidhi + 0x0100u) & 0xff00u) | ((aidlo + 0x0001u) & 0x00ffu)) & mask;
3868 
3869    if ( aid == mid1 ) {
3870       /* Order is OK */
3871       return 0;
3872    }
3873 
3874    if ( aid1 == mid ) {
3875       /* Reverse the order */
3876       temp = identp[0];
3877       identp[0] = identp[1];
3878       identp[1] = temp;
3879       return 0;
3880    }
3881 
3882    /* Invalid relationship */
3883    return 1;
3884 }
3885 
3886 /*---------------------------------------------------------------------+
3887  | Determine the companion ID for a DS90 ID.  If func = COMPUTE_AUX,   |
3888  | find the aux ID for the argument main ID; otherwise find the main   |
3889  | ID for the argument aux ID.                                         |
3890  +---------------------------------------------------------------------*/
comp_ds90_id(unsigned short ident,int func)3891 unsigned short comp_ds90_id ( unsigned short ident, int func )
3892 {
3893    unsigned short mask, newid;
3894    unsigned char  idlo, idhi, id1lo, id1hi;
3895 
3896    mask = (ident > 0xffu) ? 0xffffu : 0x00ffu;
3897 
3898    idlo = rev_byte_bits(ident & 0x00ffu);
3899    idhi = rev_byte_bits((ident & 0xff00u & mask) >> 8);
3900 
3901    ident = rev_byte_bits(ident & 0xffu);
3902 
3903    if ( func == COMPUTE_AUX ) {
3904       /* Get aux corresponding to main */
3905       id1hi = ((idhi + 0x0001u) & 0x00ffu) & (mask >> 8);
3906       id1lo = ((idlo + 0x0001u) & 0x00ffu);
3907    }
3908    else {
3909       /* Get main corresponding to aux */
3910       id1hi = ((idhi - 0x0001u) & 0x00ffu) & (mask >> 8);
3911       id1lo = ((idlo - 0x0001u) & 0x00ffu);
3912    }
3913    newid = (rev_byte_bits(id1hi) << 8) | rev_byte_bits(id1lo);
3914    return newid;
3915 }
3916 
3917 
cmp_modules(const void * m1,const void * m2)3918 int cmp_modules ( const void *m1, const void *m2 )
3919 {
3920    struct modules_st *one, *two;
3921 
3922    one = (struct modules_st *)m1; two = (struct modules_st *)m2;
3923 
3924    return strcmp(one->label, two->label);
3925 }
3926 
c_modlist(int argc,char * argv[])3927 int c_modlist ( int argc, char *argv[] )
3928 {
3929    int j;
3930    qsort(modules, ntypes, sizeof(struct modules_st), cmp_modules);
3931 
3932    for ( j = 0; j < ntypes; j++ )
3933       printf("%s\n", modules[j].label);
3934    printf("\n");
3935 
3936    return 0;
3937 }
3938 
3939 
3940 /*---------------------------------------------------------------------+
3941  | Get a temperature parameter from the tokenized ALIAS directive for  |
3942  | a sensor.                                                           |
3943  +---------------------------------------------------------------------*/
temp_parm(char ** tokens,int * ntokens,char * tparmname,char * tscale,int * tflag,double * tvalue)3944 int temp_parm ( char **tokens, int *ntokens, char *tparmname, char *tscale,
3945                                              int *tflag, double *tvalue )
3946 {
3947    char msg[80];
3948    int  j, k, count = 0;
3949    char *sp, *tmptok;
3950 
3951    *tflag = 0;
3952 
3953    j = 0;
3954    while ( j < *ntokens ) {
3955       strupper(tokens[j]);
3956       if ( strcmp(tokens[j], tparmname) == 0 ) {
3957          *tokens[j] = '\0';
3958          j++;
3959          if ( j >= *ntokens ) {
3960             sprintf(msg, "Missing %s value.", tparmname);
3961             store_error_message(msg);
3962             return 1;
3963          }
3964          strupper(tokens[j]);
3965          *tvalue = strtod(tokens[j], &sp);
3966          if ( strchr("CFKR", *sp) && strchr(" \t\n\r", *(sp + 1)) ) {
3967             *tscale = *sp;
3968          }
3969          else if ( !strchr(" \t\n\r", *sp) ) {
3970             sprintf(msg, "Invalid %s value or scale.", tparmname);
3971             store_error_message(msg);
3972             return 1;
3973          }
3974          *tokens[j] = '\0';
3975          *tflag = 1;
3976          count += 2;
3977       }
3978       j++;
3979    }
3980 
3981    if ( count == 0 )
3982       return 0;
3983 
3984    /* Compact to remove "gaps" where tokens were nulled out */
3985 
3986    for ( j = 0; j < *ntokens; j++ ) {
3987       if ( *tokens[j] == '\0' ) {
3988          for ( k = j + 1; k < *ntokens; k++ ) {
3989             if ( *tokens[k] != '\0' ) {
3990                tmptok = tokens[j];
3991                tokens[j] = tokens[k];
3992                tokens[k] = tmptok;
3993                *tmptok = '\0';
3994                break;
3995             }
3996          }
3997       }
3998    }
3999    *ntokens -= count;
4000 
4001    return 0;
4002 }
4003 
4004 /*---------------------------------------------------------------------+
4005  | Get a relative humidity parameter from the tokenized ALIAS          |
4006  | directive for a sensor.                                             |
4007  +---------------------------------------------------------------------*/
rh_parm(char ** tokens,int * ntokens,char * rhparmname,char * rhscale,int * rhflag,double * rhvalue)4008 int rh_parm ( char **tokens, int *ntokens, char *rhparmname, char *rhscale,
4009                                              int *rhflag, double *rhvalue )
4010 {
4011    char msg[80];
4012    int  j, k, count = 0;
4013    char *sp, *tmptok;
4014 
4015    *rhflag = 0;
4016 
4017    j = 0;
4018    while ( j < *ntokens ) {
4019       strupper(tokens[j]);
4020       if ( strcmp(tokens[j], rhparmname) == 0 ) {
4021          *tokens[j] = '\0';
4022          j++;
4023          if ( j >= *ntokens ) {
4024             sprintf(msg, "Missing %s value.", rhparmname);
4025             store_error_message(msg);
4026             return 1;
4027          }
4028          strupper(tokens[j]);
4029          *rhvalue = strtod(tokens[j], &sp);
4030          *rhscale = '%';
4031          if ( !strchr(" %\t\n\r", *sp) ) {
4032             sprintf(msg, "Invalid %s value.", rhparmname);
4033             store_error_message(msg);
4034             return 1;
4035          }
4036          *tokens[j] = '\0';
4037          *rhflag = 1;
4038          count += 2;
4039       }
4040       j++;
4041    }
4042 
4043    if ( count == 0 )
4044       return 0;
4045 
4046    /* Compact to remove "gaps" where tokens were nulled out */
4047 
4048    for ( j = 0; j < *ntokens; j++ ) {
4049       if ( *tokens[j] == '\0' ) {
4050          for ( k = j + 1; k < *ntokens; k++ ) {
4051             if ( *tokens[k] != '\0' ) {
4052                tmptok = tokens[j];
4053                tokens[j] = tokens[k];
4054                tokens[k] = tmptok;
4055                *tmptok = '\0';
4056                break;
4057             }
4058          }
4059       }
4060    }
4061    *ntokens -= count;
4062 
4063    return 0;
4064 }
4065 
4066 /*---------------------------------------------------------------------+
4067  | Get a barometric pressure parameter from the tokenized ALIAS        |
4068  | directive for a sensor.                                             |
4069  +---------------------------------------------------------------------*/
bp_parm(char ** tokens,int * ntokens,char * bpparmname,char * bpunits,int * bpflag,double * bpvalue)4070 int bp_parm ( char **tokens, int *ntokens, char *bpparmname, char *bpunits,
4071                                              int *bpflag, double *bpvalue )
4072 {
4073    char msg[80];
4074    int  j, k, count = 0;
4075    char *sp, *tmptok;
4076 
4077    *bpflag = 0;
4078 
4079    j = 0;
4080    while ( j < *ntokens ) {
4081       strupper(tokens[j]);
4082       if ( strcmp(tokens[j], bpparmname) == 0 ) {
4083          *tokens[j] = '\0';
4084          j++;
4085          if ( j >= *ntokens ) {
4086             sprintf(msg, "Missing %s value.", bpparmname);
4087             store_error_message(msg);
4088             return 1;
4089          }
4090          strupper(tokens[j]);
4091          *bpvalue = strtod(tokens[j], &sp);
4092          if ( strchr(" \t\n\r", *sp) )
4093             *bpunits = '\0';
4094          else
4095             strncpy(bpunits, sp, NAME_LEN);
4096 
4097          *tokens[j] = '\0';
4098          *bpflag = 1;
4099          count += 2;
4100       }
4101       j++;
4102    }
4103 
4104    if ( count == 0 )
4105       return 0;
4106 
4107    /* Compact to remove "gaps" where tokens were nulled out */
4108 
4109    for ( j = 0; j < *ntokens; j++ ) {
4110       if ( *tokens[j] == '\0' ) {
4111          for ( k = j + 1; k < *ntokens; k++ ) {
4112             if ( *tokens[k] != '\0' ) {
4113                tmptok = tokens[j];
4114                tokens[j] = tokens[k];
4115                tokens[k] = tmptok;
4116                *tmptok = '\0';
4117                break;
4118             }
4119          }
4120       }
4121    }
4122    *ntokens -= count;
4123 
4124    return 0;
4125 }
4126 
4127 /*---------------------------------------------------------------------+
4128  | Get inactive_timeout parameter from the tokenized ALIAS directive   |
4129  | for a sensor.                                                       |
4130  +---------------------------------------------------------------------*/
timeout_parm(char ** tokens,int * ntokens,char * parmname,int * toflag,long * timeout)4131 int timeout_parm ( char **tokens, int *ntokens, char *parmname,
4132                                              int *toflag, long *timeout )
4133 {
4134    char msg[80];
4135    int  j, k, count = 0;
4136    char *totok;
4137 
4138    *toflag = 0;
4139 
4140    j = 0;
4141    while ( j < *ntokens ) {
4142       strupper(tokens[j]);
4143       if ( strcmp(tokens[j], parmname) == 0 ) {
4144          *tokens[j] = '\0';
4145          j++;
4146          if ( j >= *ntokens ) {
4147             sprintf(msg, "Missing %s hh:mm:ss value.", parmname);
4148             store_error_message(msg);
4149             return 1;
4150          }
4151          if ( (*timeout = parse_hhmmss(tokens[j], 3)) < 0 || *timeout > 86400L ) {
4152             sprintf(msg, "Invalid %s timeout '%s'.", parmname, tokens[j]);
4153             store_error_message(msg);
4154             return 1;
4155          }
4156 
4157          *tokens[j] = '\0';
4158          *toflag = 1;
4159          count += 2;
4160       }
4161       j++;
4162    }
4163 
4164    if ( count == 0 )
4165       return 0;
4166 
4167    /* Compact to remove "gaps" where tokens were nulled out */
4168 
4169    for ( j = 0; j < *ntokens; j++ ) {
4170       if ( *tokens[j] == '\0' ) {
4171          for ( k = j + 1; k < *ntokens; k++ ) {
4172             if ( *tokens[k] != '\0' ) {
4173                totok = tokens[j];
4174                tokens[j] = tokens[k];
4175                tokens[k] = totok;
4176                *totok = '\0';
4177                break;
4178             }
4179          }
4180       }
4181    }
4182    *ntokens -= count;
4183 
4184    return 0;
4185 }
4186 
4187 
sensor_timeout(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)4188 int sensor_timeout ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
4189 {
4190    long timeout;
4191    int  toflag;
4192 
4193    int timeout_parm ( char **, int *, char *, int *, long * );
4194 
4195    if ( timeout_parm(tokens, ntokens, "IATO", &toflag, &timeout) != 0 )
4196       return 1;
4197 
4198    if ( toflag ) {
4199       aliasp[aliasindex].optflags2 |= MOPT2_IATO;
4200       aliasp[aliasindex].hb_timeout = timeout;
4201    }
4202 
4203    return 0;
4204 }
4205 
4206 
4207 
4208 /*-------------------------------------------------------+
4209  | Called by add_module_options() to add the KAKU        |
4210  | sensor options from the ALIAS line in the config file.|
4211  +-------------------------------------------------------*/
opt_kaku_orig(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)4212 int opt_kaku_orig ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
4213 {
4214    long ident;
4215    int  key, grp;
4216    char *sp;
4217 
4218    if ( *ntokens < 2 || *ntokens > 3 ) {
4219       store_error_message("Unknown parameters");
4220       return 1;
4221    }
4222 
4223    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
4224       store_error_message("Multiple unit alias is invalid for sensors.");
4225       return 1;
4226    }
4227 
4228    ident = strtol(tokens[0], &sp, 16);
4229    if ( *sp == '\0' && ident >= 0 ) {
4230       aliasp[aliasindex].ident[0] = ident;
4231       aliasp[aliasindex].nident = 1;
4232    }
4233    else {
4234       store_error_message("Invalid hexadecimal KAKU ID parameter");
4235       return 1;
4236    }
4237 
4238    key = strtol(tokens[1], &sp, 10);
4239    if ( *sp == '\0' && key > 0 && key <= 16 ) {
4240       aliasp[aliasindex].kaku_keymap[0] = 1 << (key - 1);
4241    }
4242    else {
4243       store_error_message("Invalid KAKU key parameter");
4244       return 1;
4245    }
4246 
4247    if ( *ntokens == 3 ) {
4248       grp = toupper((int)((unsigned char)(*tokens[2])));
4249       if ( strlen(tokens[2]) == 1 && grp >= 'A' && grp <= 'P' ) {
4250          aliasp[aliasindex].kaku_grpmap[0] = 1 << (grp - 'A');
4251       }
4252       else {
4253          store_error_message("Invalid KAKU group parameter");
4254          return 1;
4255       }
4256    }
4257 
4258    aliasp[aliasindex].vtype = RF_KAKU;
4259 
4260    aliasp[aliasindex].optflags = MOPT_KAKU;
4261 
4262    return 0;
4263 }
4264 
4265 /*-------------------------------------------------------+
4266  | Called by add_module_options() to add the KAKU        |
4267  | sensor options from the ALIAS line in the config file.|
4268  +-------------------------------------------------------*/
opt_kaku(ALIAS * aliasp,int aliasindex,char ** tokens,int * ntokens)4269 int opt_kaku ( ALIAS *aliasp, int aliasindex, char **tokens, int *ntokens )
4270 {
4271    long ident;
4272    int  nident, key, grp;
4273    int  j;
4274    char *sp;
4275 
4276    if ( *ntokens < 2 ) {
4277       store_error_message("Too few parameters");
4278       return 1;
4279    }
4280    else if ( *ntokens > 12 ) {
4281       store_error_message("Too many parameters");
4282       return 1;
4283    }
4284    else if ( ((*ntokens) % 2) != 0 ) {
4285       store_error_message("Parameter syntax: <ID> <Key|Grp> [<ID> <Key|Grp> [...]]");
4286       return 1;
4287    }
4288 
4289 
4290    if ( single_bmap_unit(aliasp[aliasindex].unitbmap) == 0xff ) {
4291       store_error_message("Multiple unit alias is invalid for sensors.");
4292       return 1;
4293    }
4294 
4295    nident = 0;
4296    for ( j = 0; j < *ntokens; j += 2 ) {
4297       ident = strtol(tokens[j], &sp, 16);
4298       if ( strchr(" \t", *sp) && ident >= 0 ) {
4299          aliasp[aliasindex].ident[nident] = ident;
4300       }
4301       else {
4302          store_error_message("Invalid hexadecimal KAKU ID parameter");
4303          return 1;
4304       }
4305 
4306       if ( isdigit((int)((unsigned char)(*tokens[j+1]))) ) {
4307          key = strtol(tokens[j+1], &sp, 10);
4308          if ( key > 0 && key <= 16 ) {
4309             aliasp[aliasindex].kaku_keymap[nident] = 1 << (key - 1);
4310          }
4311          else {
4312             store_error_message("Invalid KAKU key parameter");
4313             return 1;
4314          }
4315 
4316          if ( strchr(" \t\r\n", *sp) ) {
4317             nident++;
4318             continue;
4319          }
4320 
4321          strupper(sp);
4322          if ( strlen(sp) == 1 && *sp >= 'A' && *sp <= 'P' ) {
4323             aliasp[aliasindex].kaku_grpmap[nident] = 1 << (*sp - 'A');
4324          }
4325          else {
4326             store_error_message("Invalid KAKU group parameter");
4327             return 1;
4328          }
4329       }
4330       else {
4331          strupper(tokens[j+1]);
4332          grp = *tokens[j+1];
4333          if ( strlen(tokens[j+1]) == 1 && grp >= 'A' && grp <= 'P' ) {
4334             aliasp[aliasindex].kaku_grpmap[nident] = 1 << (grp - 'A');
4335          }
4336          else {
4337             store_error_message("Invalid KAKU group parameter");
4338             return 1;
4339          }
4340       }
4341 
4342       nident++;
4343    }
4344 
4345    aliasp[aliasindex].nident = nident;
4346 
4347 
4348    aliasp[aliasindex].vtype = RF_KAKU;
4349 
4350    aliasp[aliasindex].optflags = MOPT_KAKU;
4351 
4352    return 0;
4353 }
4354