1 /*----------------------------------------------------------------------------+
2  |                                                                            |
3  |              State and Script functions for HEYU                           |
4  |            Copyright 2004-2010 Charles W. Sullivan                         |
5  |                                                                            |
6  |                                                                            |
7  | As used herein, HEYU is a trademark of Daniel B. Suthers.                  |
8  | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc.               |
9  | The author is not affiliated with either entity.                           |
10  |                                                                            |
11  | Charles W. Sullivan                                                        |
12  | Co-author and Maintainer                                                   |
13  | Greensboro, North Carolina                                                 |
14  | Email ID: cwsulliv01                                                       |
15  | Email domain: -at- heyu -dot- org                                          |
16  |                                                                            |
17  +----------------------------------------------------------------------------*/
18 
19 /*
20  *   This program is free software: you can redistribute it and/or modify
21  *   it under the terms of the GNU General Public License as published by
22  *   the Free Software Foundation, either version 3 of the License, or
23  *   (at your option) any later version.
24  *
25  *   This program is distributed in the hope that it will be useful,
26  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
27  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  *   GNU General Public License for more details.
29  *
30  *   You should have received a copy of the GNU General Public License
31  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
32  *
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <ctype.h>
39 #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD)
40 #include <string.h>
41 #else
42 #include <strings.h>
43 #endif
44 #include <errno.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <syslog.h>
48 #include <sys/time.h>
49 
50 #ifdef POSIX
51 #define EXEC_POSIX
52 #endif
53 
54 #ifdef EXEC_POSIX
55 #include <sys/wait.h>
56 #endif
57 
58 #include <signal.h>
59 #include <time.h>
60 #include "x10.h"
61 #include "process.h"
62 #include "sun.h"
63 #include "x10state.h"
64 #include "rfxcom.h"
65 #include "digimax.h"
66 #include "oregon.h"
67 #include "local.h"
68 #include "version.h"
69 
70 #ifdef pid_t
71 #define PID_T pid_t
72 #else
73 #define PID_T long
74 #endif
75 
76 
77 extern CONFIG config;
78 extern CONFIG *configp;
79 
80 extern char *funclabel[];
81 extern int tty, sptty, verbose;
82 extern int i_am_monitor, i_am_state, i_am_relay, i_am_rfxmeter;
83 extern int heyu_parent;
84 extern FILE *fdsout, *fdserr;
85 
86 extern char *heyu_tzname[2];
87 extern char *datstrf( void );
88 extern void datstrf2( char * );
89 
90 extern char heyu_script[];
91 extern char statefile[];
92 extern char enginelockfile[];
93 extern char heyu_config[PATH_LEN + 1];
94 
95 #define PROMSIZE 1024
96 static unsigned char image[PROMSIZE + 10];
97 
98 extern unsigned int modmask[NumModMasks][16];
99 extern unsigned int vmodmask[NumVmodMasks][16];
100 extern unsigned int kmodmask[NumKmodMasks][16];
101 extern unsigned char maxdimlevel[16][16];
102 extern unsigned char ondimlevel[16][16];
103 
104 extern char *wday_name[7];
105 extern char *month_name[12];
106 
107 struct x10global_st x10global;
108 x10hcode_t *x10state = x10global.x10hcode;
109 
110 #define SpecPLC  0x00000001   /* Specific PLC */
111 #define GenPLC   0x00000002   /* Generic PLC */
112 #define SpecSec  0x00000004   /* Specific Security */
113 #define SpecRFX  0x00000008   /* Specific RFXSensor */
114 #define SpecDMX  0x00000010   /* Specific Digimax */
115 #define SpecOre  0x00000020   /* Specific Oregon */
116 #define SpecKaku 0x00000040   /* Specific Kaku */
117 #define AnyFlag  0x80000000   /* All of any above group */
118 
119 #define AnyPLC   (AnyFlag | SpecPLC)
120 #define AnySec   (AnyFlag | SpecSec)
121 #define AnyRFX   (AnyFlag | SpecRFX)
122 #define AnyDMX   (AnyFlag | SpecDMX)
123 #define AnyFunc  (AnyFlag | SpecPLC)
124 #define AnyOre   (AnyFlag | SpecOre)
125 #define AnyKaku  (AnyFlag | SpecKaku)
126 
127 /* General commands which can launch a script */
128 /* (Maximum of 32 distinct xxxTrig entries in */
129 /* each table, to fit into an unsigned long   */
130 /* integer bitmap.)                           */
131 
132 static struct trig_type_st {
133    char          *label;
134    unsigned long  flags;
135    int           signal;
136 } trig_type[] = {
137   {"anyplc",       AnyPLC,  0},
138   {"on",           SpecPLC, OnTrig},
139   {"off",          SpecPLC, OffTrig},
140   {"dim",          SpecPLC, DimTrig},
141   {"bright",       SpecPLC, BriTrig},
142   {"lightson",     SpecPLC, LightsOnTrig},
143   {"lightsoff",    SpecPLC, LightsOffTrig},
144   {"allon",        SpecPLC, AllOnTrig},
145   {"alloff",       SpecPLC, AllOffTrig},
146   {"statuson",     SpecPLC, StatusOnTrig},
147   {"status_on",    SpecPLC, StatusOnTrig},
148   {"statusoff",    SpecPLC, StatusOffTrig},
149   {"status_off",   SpecPLC, StatusOffTrig},
150   {"status",       SpecPLC, StatusReqTrig},
151   {"statusreq",    SpecPLC, StatusReqTrig},
152   {"status_req",   SpecPLC, StatusReqTrig},
153   {"preset",       SpecPLC, PresetTrig},
154   {"extended",     SpecPLC, ExtendedTrig},
155   {"xpup",         SpecPLC, ExtPowerUpTrig},
156   {"xpowerup",     SpecPLC, ExtPowerUpTrig},
157   {"hail",         SpecPLC, HailReqTrig},
158   {"hail_ack",     SpecPLC, HailAckTrig},
159   {"data_xfer",    SpecPLC, DataXferTrig},
160   {"vdata",        (SpecPLC|SpecSec), VdataTrig},
161   {"vdatam",       (SpecPLC|SpecSec), VdataMTrig},
162   {"gon",          GenPLC,  OnTrig},
163   {"goff",         GenPLC,  OffTrig},
164   {"gdim",         GenPLC,  DimTrig},
165 };
166 #define NTRIGTYPES (sizeof(trig_type)/sizeof(struct trig_type_st))
167 
168 static struct trig_type_st sec_trig_type[] = {
169   {"anysec",       AnySec,  0},
170   {"panic",        SpecSec, PanicTrig},
171   {"arm",          SpecSec, ArmTrig},
172   {"disarm",       SpecSec, DisarmTrig},
173   {"alert",        SpecSec, AlertTrig},
174   {"clear",        SpecSec, ClearTrig},
175   {"sectamper",    SpecSec, TamperTrig},
176   {"test",         SpecSec, TestTrig},
177   {"slightson",    SpecSec, SecLightsOnTrig},
178   {"slightsoff",   SpecSec, SecLightsOffTrig},
179   {"sdusk",        SpecSec, DuskTrig},
180   {"sdawn",        SpecSec, DawnTrig},
181   {"akeyon",       SpecSec, AkeyOnTrig},
182   {"akeyoff",      SpecSec, AkeyOffTrig},
183   {"bkeyon",       SpecSec, BkeyOnTrig},
184   {"bkeyoff",      SpecSec, BkeyOffTrig},
185   {"vdata",        SpecSec, VdataTrig},
186   {"vdatam",       SpecSec, VdataMTrig},
187   {"inactive",     SpecSec, InactiveTrig},
188 };
189 #define NSECTRIGTYPES (sizeof(sec_trig_type)/sizeof(struct trig_type_st))
190 
191 
192 static struct trig_type_st rfx_trig_type[] = {
193   {"anyrfx",       AnyRFX,  0},
194   {"anydmx",       AnyDMX,  0},
195   {"dmxtemp",      SpecDMX, DmxTempTrig},
196   {"dmxon",        SpecDMX, DmxOnTrig},
197   {"dmxoff",       SpecDMX, DmxOffTrig},
198   {"dmxsetpoint",  SpecDMX, DmxSetPtTrig},
199   {"rfxtemp",      SpecRFX, RFXTempTrig},
200   {"rfxtemp2",     SpecRFX, RFXTemp2Trig},
201   {"rfxrh",        SpecRFX, RFXHumidTrig},
202   {"rfxbp",        SpecRFX, RFXPressTrig},
203   {"rfxlobat",     SpecRFX, RFXLoBatTrig},
204   {"rfxvad",       SpecRFX, RFXVadTrig},
205   {"rfxpot",       SpecRFX, RFXPotTrig},
206   {"rfxvs",        SpecRFX, RFXVsTrig},
207   {"rfxother",     SpecRFX, RFXOtherTrig},
208   {"rfxpulse",     SpecRFX, RFXPulseTrig},
209   {"rfxpower",     SpecRFX, RFXPowerTrig},
210   {"rfxwater",     SpecRFX, RFXWaterTrig},
211   {"rfxgas",       SpecRFX, RFXGasTrig},
212   {"rfxcount",     SpecRFX, RFXCountTrig},
213 };
214 #define NRFXTRIGTYPES (sizeof(rfx_trig_type)/sizeof(struct trig_type_st))
215 
216 
217 static struct trig_type_st ore_trig_type[] = {
218   {"anyore",       AnyOre,  0},
219   {"oretemp",      SpecOre, OreTempTrig},
220   {"orerh",        SpecOre, OreHumidTrig},
221   {"orebp",        SpecOre, OreBaroTrig},
222   {"orewgt",       SpecOre, OreWeightTrig},
223   {"elscurr",      SpecOre, ElsCurrTrig},
224   {"orewindsp",    SpecOre, OreWindSpTrig},
225   {"orewindavsp",  SpecOre, OreWindAvSpTrig},
226   {"orewinddir",   SpecOre, OreWindDirTrig},
227   {"oreraintot",   SpecOre, OreRainTotTrig},
228   {"orerainrate",  SpecOre, OreRainRateTrig},
229   {"oreuv",        SpecOre, OreUVTrig},
230   {"owlpower",     SpecOre, OwlPowerTrig},
231   {"owlenergy",    SpecOre, OwlEnergyTrig},
232 };
233 #define NORETRIGTYPES (sizeof(ore_trig_type)/sizeof(struct trig_type_st))
234 
235 static struct trig_type_st kaku_trig_type[] = {
236   {"anykaku",      AnyKaku,  0},
237   {"koff",         SpecKaku, KakuOffTrig},
238   {"kon",          SpecKaku, KakuOnTrig},
239   {"kgrpoff",      SpecKaku, KakuGrpOffTrig},
240   {"kgrpon",       SpecKaku, KakuGrpOnTrig},
241   {"kpreset",      SpecKaku, KakuPreTrig},
242   {"kgrppreset",   SpecKaku, KakuGrpPreTrig},
243 };
244 #define NKAKUTRIGTYPES (sizeof(kaku_trig_type)/sizeof(struct trig_type_st))
245 
246 
247 /* Functions included in the 'generic' group */
248 #define GENFUNCMAP ((1 << OnTrig) | (1 << OffTrig) | (1 << DimTrig))
249 
250 
251 void arm_delay_complete ( int );
252 void timer_timeout ( int );
253 
254 typedef struct {
255    char    timername[NAME_LEN];
256    void    (*elapsed_func)(int);
257 } COUNTDOWN;
258 
259 COUNTDOWN countdown_timer[NUM_USER_TIMERS + 1];
260 
261 #define ArmDelayTimer  0
262 
setup_countdown_timers(void)263 void setup_countdown_timers ( void )
264 {
265    int j;
266 
267 //   x10global.timer_count[ArmDelayTimer] = 0;
268    strcpy(countdown_timer[ArmDelayTimer].timername, "armtimer");
269    countdown_timer[ArmDelayTimer].elapsed_func = arm_delay_complete;
270 
271    for ( j = 1; j <= NUM_USER_TIMERS; j++ ) {
272 //      x10global.timer_count[j] = 0;
273       sprintf(countdown_timer[j].timername, "timer%d", j);
274       countdown_timer[j].elapsed_func = timer_timeout;
275    }
276 
277    return;
278 }
279 
280 struct stflags_st {
281    char *label;
282    int  length;
283    int  state;
284    int  not;
285    int  andstate;
286    int  andnot;
287 } stflags[] = {
288   {"on:",            3, OnState,        0, NullState,   1},
289   {"noton:",         6, OnState,        1, NullState,   1},
290   {"off:",           4, OnState,        1, NullState,   1},
291   {"notoff:",        7, OnState,        0, NullState,   1},
292   {"dim:",           4, DimState,       0, NullState,   1},
293   {"notdim:",        7, DimState,       1, NullState,   1},
294   {"alert:",         6, AlertState,     0, NullState,   1},
295   {"notalert:",      9, AlertState,     1, NullState,   1},
296   {"clear:",         6, ClearState,     0, NullState,   1},
297   {"notclear:",      9, ClearState,     1, NullState,   1},
298   {"auxalert:",      9, AuxAlertState,  0, NullState,   1},
299   {"notauxalert:",  12, AuxAlertState,  1, NullState,   1},
300   {"auxclear:",      9, AuxClearState,  0, NullState,   1},
301   {"notauxclear:",  12, AuxClearState,  1, NullState,   1},
302   {"active:",        7, ActiveState,    0, NullState,   1},
303   {"notactive:",    10, ActiveState,    1, NullState,   1},
304   {"inactive:",      9, InactiveState,  0, NullState,   1},
305   {"notinactive:",  12, InactiveState,  1, NullState,   1},
306   {"valid:",         6, ValidState,     0, NullState,   1},
307   {"notvalid:",      9, ValidState,     1, NullState,   1},
308   {"addr:",          5, AddrState,      0, NullState,   1},
309   {"notaddr:",       8, AddrState,      1, NullState,   1},
310   {"tamper:",        7, TamperState,    0, NullState,   1},
311   {"nottamper:",    10, TamperState,    1, NullState,   1},
312   {"chg:",           4, ChgState,       0, NullState,   1},
313   {"notchg:",        7, ChgState,       1, NullState,   1},
314 //  {"activechg:",    10, ActiveChgState, 0, NullState,   1},
315 //  {"notactivechg:", 13, ActiveChgState, 1, NullState,   1},
316 //  {"modchg:",        7, ModChgState,    0, NullState,   1},
317 //  {"notmodchg:",    10, ModChgState,    1, NullState,   1},
318 };
319 int num_stflags = sizeof(stflags) / sizeof(struct stflags_st);
320 
321 
322 struct virtflags_st {
323    char          *label;
324    int           length;
325    unsigned long vflag;
326    int           not;
327 } virtflags[] = {
328   {"lobat:",        6, SEC_LOBAT,      0},
329   {"notlobat:",     9, SEC_LOBAT,      1},
330   {"rollover:",     9, RFX_ROLLOVER,   0},
331   {"notrollover:", 12, RFX_ROLLOVER,   1},
332   {"swmin:",        6, SEC_MIN,        0},
333   {"notswmin:",     9, SEC_MIN,        1},
334   {"swmax:",        6, SEC_MAX,        0},
335   {"notswmax:",     9, SEC_MAX,        1},
336   {"tmin:",         5, ORE_TMIN,       0},
337   {"nottmin:",      8, ORE_TMIN,       1},
338   {"tmax:",         5, ORE_TMAX,       0},
339   {"nottmax:",      8, ORE_TMAX,       1},
340   {"rhmin:",        6, ORE_RHMIN,      0},
341   {"notrhmin:",     9, ORE_RHMIN,      1},
342   {"rhmax:",        6, ORE_RHMAX,      0},
343   {"notrhmax:",     9, ORE_RHMAX,      1},
344   {"bpmin:",        6, ORE_BPMIN,      0},
345   {"notbpmin:",     9, ORE_BPMIN,      1},
346   {"bpmax:",        6, ORE_BPMAX,      0},
347   {"notbpmax:",     9, ORE_BPMAX,      1},
348   {"main:",         5, SEC_MAIN,       0},
349   {"notmain:",      8, SEC_MAIN,       1},
350   {"aux:",          4, SEC_AUX,        0},
351   {"notaux:",       7, SEC_AUX,        1},
352   {"init:",         5, DMX_INIT,       0},
353   {"notinit:",      8, DMX_INIT,       1},
354   {"heat:",         5, DMX_HEAT,       0},
355   {"notheat:",      8, DMX_HEAT,       1},
356   {"set:",          4, DMX_SET,        0},
357   {"notset:",       7, DMX_SET,        1},
358 //  {"dmxtemp:",      8, DMX_TEMP,       0},
359 //  {"notdmxtemp:",  11, DMX_TEMP,       1},
360 };
361 int num_virtflags = sizeof(virtflags) / sizeof(struct virtflags_st);
362 
363 
364 /* Heartbeat sensor countdowns and alias indexes */
365 struct {
366    int alias_index;
367    long countdown;
368 } heartbeat_sensor[MAX_SEC_SENSORS];
369 int num_heartbeat_sensors = 0;
370 
371 /* Heyu environment masks */
372 static struct {
373    char          *query;
374    unsigned long  mask;
375 } heyumaskval[] = {
376    {"whatLevel",   HEYUMAP_LEVEL},
377    {"isAppl",      HEYUMAP_APPL },
378    {"isSpend",     HEYUMAP_SPEND},
379    {"isOff",       HEYUMAP_OFF  },
380    {"isAddr",      HEYUMAP_ADDR },
381    {"isChg",       HEYUMAP_CHG  },
382    {"isDim",       HEYUMAP_DIM  },
383    {"isValid",     HEYUMAP_SIGNAL },
384    {"isClear",     HEYUMAP_CLEAR},
385    {"isAlert",     HEYUMAP_ALERT},
386    {"isAuxClear",  HEYUMAP_AUXCLEAR},
387    {"isAuxAlert",  HEYUMAP_AUXALERT},
388    {"isSdawn",     HEYUMAP_AUXCLEAR},
389    {"isSdusk",     HEYUMAP_AUXALERT},
390    {"isActive",    HEYUMAP_ACTIVE},
391    {"isInactive",  HEYUMAP_INACTIVE},
392 //   {"isModChg",    HEYUMAP_MODCHG},
393    {"isOn",        HEYUMAP_ON   },
394    { NULL,         0            },
395 };
396 
397 /* Heyu environment masks for Security, RFX, Oregon flags */
398 static struct {
399    char           *query;
400    unsigned long  mask;
401 } heyusecmaskval[] = {
402    {"isLoBat",    FLAGMAP_LOBAT    },
403    {"isRollover", FLAGMAP_ROLLOVER },
404    {"isSwMin",    FLAGMAP_SWMIN    },
405    {"isSwMax",    FLAGMAP_SWMAX    },
406    {"isMain",     FLAGMAP_MAIN     },
407    {"isAux",      FLAGMAP_AUX      },
408    {"isTamper",   FLAGMAP_TAMPER   },
409    {"isTmin",     FLAGMAP_TMIN     },
410    {"isTmax",     FLAGMAP_TMAX     },
411    {"isRHmin",    FLAGMAP_RHMIN    },
412    {"isRHmax",    FLAGMAP_RHMAX    },
413    {"isBPmin",    FLAGMAP_BPMIN    },
414    {"isBPmax",    FLAGMAP_BPMAX    },
415    {"isInit",     FLAGMAP_DMXINIT  },
416    {"isSet",      FLAGMAP_DMXSET   },
417    {"isHeat",     FLAGMAP_DMXHEAT  },
418 //   {"isDmxTemp",  FLAGMAP_DMXTEMP  },
419    { NULL,        0                },
420 };
421 
422 /* Xtend environment masks */
423 static struct {
424    char           *query;
425    unsigned long  mask;
426 } xtendmaskval[] = {
427    {"isAppl",    XTMAP_APPL },
428    {"isAddr",    XTMAP_ADDR },
429    {"isOn",      XTMAP_ON   },
430    { NULL,       0          },
431 };
432 
433 /*----------------------------------------------------------------------------+
434  | Update the activity timer countdown for a sensor with a heartbeat.         |
435  +----------------------------------------------------------------------------*/
update_activity_timeout(ALIAS * aliasp,int index)436 void update_activity_timeout ( ALIAS *aliasp, int index )
437 {
438    if ( index >= 0 && aliasp[index].optflags & MOPT_HEARTBEAT &&
439         aliasp[index].hb_index >= 0 ) {
440       heartbeat_sensor[aliasp[index].hb_index].countdown = aliasp[index].hb_timeout;
441    }
442    return;
443 }
444 
445 /*---------------------------------------------------------------------+
446  | Update the Active, Inactive, and ActiveChg states                   |
447  +---------------------------------------------------------------------*/
update_activity_states(unsigned char hcode,unsigned int bitmap,unsigned char mode)448 int update_activity_states ( unsigned char hcode, unsigned int bitmap, unsigned char mode )
449 {
450    unsigned int prevstate, newstate, changed;
451 
452    prevstate = x10state[hcode].state[InactiveState];
453 
454    if ( mode == S_INACTIVE ) {
455       newstate = prevstate | bitmap;
456    }
457    else {
458       newstate = prevstate & ~bitmap;
459    }
460    x10state[hcode].state[InactiveState] = newstate;
461    x10state[hcode].state[ActiveState] = ~newstate & x10state[hcode].state[ValidState];
462 
463    changed = prevstate ^ newstate;
464 
465    x10state[hcode].state[ActiveChgState] =
466        (x10state[hcode].state[ActiveChgState] & ~bitmap) | changed;
467 
468    return 0;
469 }
470 
471 /*---------------------------------------------------------------------+
472  | Return 1 if the sensor module type specified in an alias at the     |
473  | argument address has a heartbeat, otherwise 0.                      |
474  +---------------------------------------------------------------------*/
has_heartbeat(unsigned char hcode,unsigned int bitmap)475 int has_heartbeat ( unsigned char hcode, unsigned int bitmap )
476 {
477    ALIAS *aliasp;
478    int   index, j = 0;
479 
480    if ( !(aliasp = configp->aliasp) )
481       return 0;
482 
483    j = 0;
484    while ( (index = lookup_alias_mult(hcode, bitmap, &j) >= 0) ) {
485       if ( aliasp[index].optflags & MOPT_HEARTBEAT )
486          return 1;
487    }
488 
489    return 0;
490 }
491 
492 /*----------------------------------------------------------------------------+
493  | Converts programmed dim level (1-22) to dims (0-210).                      |
494  | This is just an approximation as the number of dims actually transmitted   |
495  | by the interface varies, apparently at random, but actually depending on   |
496  | whether beginning on rising or falling zero crossing of AC waveform.       |
497  +----------------------------------------------------------------------------*/
level2dims(unsigned char level,char ** prefix,char ** suffix)498 unsigned char level2dims ( unsigned char level, char **prefix, char **suffix )
499 {
500    unsigned int dims, base;
501 
502    /* The value of 'base' appears to vary randomly, being either 2 or 3  */
503    /* with approximately equal likelyhood.  The value 4 has occasionally */
504    /* been observed.  We use 2 here.                                     */
505    base = 2;
506    dims = (level > 0) ? base + 11 * (level - 1) : base + 11 ;
507    if ( dims > 210 ) {
508       *prefix = "";
509       *suffix = "+";
510    }
511    else {
512       *prefix = "~";
513       *suffix = "";
514    }
515    dims = min(210, dims);
516 
517    return (unsigned char)dims;
518 }
519 
520 /*----------------------------------------------------------------------------+
521  | Converts dims level (0-210) to (int) percent of full ON voltage.           |
522  | Linearized from measured data on an X10 LM465 (1-way) Lamp Module          |
523  | controlling a 100 Watt lamp.                                               |
524  +----------------------------------------------------------------------------*/
dims2pct(unsigned char level)525 int dims2pct ( unsigned char level )
526 {
527    long int pct;
528 
529    pct = (level > 32u) ? 90 * (level - 33u) / 177 + 10 :
530          (level > 1u)  ?  8 * (level -  2u) / 31  +  2 : 0 ;
531 
532    return (int)pct;
533 }
534 
535 /*----------------------------------------------------------------------------+
536  | Converts type 0 (shutter) level (0-25) to (int) percent of full Open.      |
537  | This is just a linear translation.                                         |
538  +----------------------------------------------------------------------------*/
ext0level2pct(unsigned int level)539 int ext0level2pct ( unsigned int level )
540 {
541    return 100 * (int)level /25;
542 }
543 
544 #define MEASURED_DATA
545 #ifdef MEASURED_DATA
546 /*----------------------------------------------------------------------------+
547  | Converts old-style preset level (zero-based, 0-31) to (int) percent of     |
548  | full ON voltage.                                                           |
549  | This is based on measurement of output voltage for a LampLinc 2000STW      |
550  | (2-way) dimmer module controlling a 100 Watt lamp.                         |
551  +----------------------------------------------------------------------------*/
presetlevel2pct(unsigned char level)552 int presetlevel2pct ( unsigned char level )
553 {
554    static unsigned char table[32] = {
555        0, 18, 21, 23, 27, 28, 31, 34, 36, 39, 42, 45, 48, 51, 54, 57,
556       60, 63, 67, 70, 73, 76, 79, 82, 85, 87, 90, 92, 95, 97, 99, 100
557    };
558 
559    return (int)table[min(31u, level)];
560 }
561 
562 /*----------------------------------------------------------------------------+
563  | Converts extended preset level (0-63) to (int) percent of full ON voltage. |
564  | (This is based on measurement of output voltage for a LM14A module         |
565  | controlling a 100 Watt lamp.)                                              |
566  +----------------------------------------------------------------------------*/
ext3level2pct(unsigned char level)567 int ext3level2pct ( unsigned char level )
568 {
569    static unsigned char table[64] = {
570        0, 12, 13, 15, 15, 17, 18, 20, 21, 22,
571       23, 25, 26, 28, 29, 31, 32, 34, 35, 37,
572       38, 40, 41, 43, 44, 46, 48, 50, 51, 53,
573       54, 56, 58, 60, 61, 63, 64, 66, 67, 69,
574       71, 73, 74, 76, 77, 79, 80, 82, 83, 85,
575       86, 88, 88, 90, 91, 92, 93, 95, 96, 97,
576       98, 99, 100, 100
577    };
578 
579    return (int)table[min(63u, level)];
580 }
581 
582 #else
583 /*----------------------------------------------------------------------------+
584  | Converts (old) preset level (0-31) to (int) percent of full ON voltage.    |
585  | This is just a linear translation.                                         |
586  +----------------------------------------------------------------------------*/
presetlevel2pct(unsigned char level)587 int presetlevel2pct ( unsigned char level )
588 {
589    return 100 * (int)level / 31;
590 }
591 
592 /*----------------------------------------------------------------------------+
593  | Converts extended preset level (0-63) to (int) percent of full ON voltage. |
594  | (This is linearized from actual data - max deviation about 4% of full On). |
595  +----------------------------------------------------------------------------*/
ext3level2pct(unsigned char level)596 int ext3level2pct ( unsigned char level )
597 {
598    level = min(62, level);
599    return (level > 0) ? 12 + 88 * ((int)level - 1) / 61 : 0;
600 }
601 #endif /* Measured vs Linearized data */
602 
603 /*----------------------------------------------------------------------------+
604  | Convert percent ON voltage to nearest above extended preset level (0-63)   |
605  +----------------------------------------------------------------------------*/
pct2ext3level(int percent)606 unsigned char pct2ext3level ( int percent )
607 {
608    unsigned char level;
609 
610    if ( percent <= 0 )   return 0u;
611    if ( percent > 100 )  return 63u;
612 
613    for ( level = 0u; level < 63u; level++ ) {
614       if ( ext3level2pct(level) >= percent )
615          return level;
616    }
617 
618    return 63u;
619 }
620 
621 /*----------------------------------------------------------------------------+
622  | Convert percent ON voltage to nearest above old style preset level (0-31)  |
623  +----------------------------------------------------------------------------*/
pct2presetlevel(int percent)624 unsigned char pct2presetlevel ( int percent )
625 {
626    unsigned char level;
627 
628    if ( percent <= 0 )   return 0u;
629    if ( percent >= 100 ) return 31u;
630 
631    for ( level = 0u; level < 32u; level++ ) {
632       if ( presetlevel2pct(level) >= percent )
633          return level;
634    }
635 
636    return 31u;
637 }
638 
639 /*----------------------------------------------------------------------------+
640  | Convert percent of ON voltage to nearest above dims level (0-210)          |
641  +----------------------------------------------------------------------------*/
pct2dims(int percent)642 unsigned char pct2dims ( int percent )
643 {
644    unsigned char dims;
645 
646    if ( percent <= 0 )  return 0;
647    if ( percent > 100 ) return 210;
648 
649    for ( dims = 0u; dims < 211u; dims++ ) {
650       if ( dims2pct(dims) >= percent )
651          return dims;
652    }
653 
654    return 210;
655 }
656 
657 /*----------------------------------------------------------------------------+
658  | Convert dims (0-210) to nearest CM11A bright/dim level (0-0x31)            |
659  +----------------------------------------------------------------------------*/
dims2level(unsigned char dims)660 unsigned char dims2level ( unsigned char dims )
661 {
662    if ( dims == 0 ) return 0u;
663    if ( dims >= 210 ) return 20u;
664 
665    dims = max(0, (int)dims - 2);
666 
667    return min(31u, (1 + (dims / 11u)));
668 }
669 
670 
671 /*----------------------------------------------------------------------------+
672  | Return the name of the function for the argument trigger signal            |
673  +----------------------------------------------------------------------------*/
lookup_function(int signal)674 char *lookup_function ( int signal )
675 {
676    int j;
677 
678    for ( j = 0; j < (int)NTRIGTYPES; j++ ) {
679       if ( trig_type[j].signal == signal )
680          return trig_type[j].label;
681    }
682    return "";
683 }
684 
685 /*----------------------------------------------------------------------------+
686  | Compare launcher flags (security, common, counter-zero) with state tables. |
687  | Return 1 if not matched, 0 otherwise.                                      |
688  +----------------------------------------------------------------------------*/
is_unmatched_flags(LAUNCHER * launcherpp)689 int is_unmatched_flags ( LAUNCHER *launcherpp )
690 {
691    int           k, m;
692    unsigned char hcode, ucode;
693    unsigned int  bitmap;
694 
695    if ( (launcherpp->sflags & x10global.sflags) != launcherpp->sflags ||
696         (launcherpp->notsflags & ~x10global.sflags) != launcherpp->notsflags ) {
697       return 1;
698    }
699 
700    for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
701       if ( (launcherpp->flags[k] & x10global.flags[k]) != launcherpp->flags[k] ||
702            (launcherpp->notflags[k] & ~x10global.flags[k]) != launcherpp->notflags[k] ) {
703          return 1;
704       }
705    }
706 
707    for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
708       if ( (launcherpp->czflags[k] & x10global.czflags[k]) != launcherpp->czflags[k] ||
709            (launcherpp->notczflags[k] & ~x10global.czflags[k]) != launcherpp->notczflags[k] ) {
710          return 1;
711       }
712    }
713 
714    for ( k = 0; k < NUM_TIMER_BANKS; k++ ) {
715       if ( (launcherpp->tzflags[k] & x10global.tzflags[k]) != launcherpp->tzflags[k] ||
716            (launcherpp->nottzflags[k] & ~x10global.tzflags[k]) != launcherpp->nottzflags[k] ) {
717          return 1;
718       }
719    }
720 
721    for ( k = 0; k < launcherpp->num_stflags; k++ ) {
722       m = launcherpp->stlist[k].stindex;
723       hcode = launcherpp->stlist[k].hcode;
724       bitmap = launcherpp->stlist[k].bmap;
725       if ( stflags[m].not ) {
726          if ( (x10state[hcode].state[stflags[m].state] & bitmap) != 0 )
727             return 1;
728       }
729       else {
730          if ( (x10state[hcode].state[stflags[m].state] & bitmap) != bitmap )
731             return 1;
732       }
733       if ( stflags[m].andnot ) {
734          if ( (x10state[hcode].state[stflags[m].andstate] & bitmap) != 0 )
735             return 1;
736       }
737       else {
738          if ( (x10state[hcode].state[stflags[m].andstate] & bitmap) != bitmap )
739             return 1;
740       }
741    }
742 
743    for ( k = 0; k < launcherpp->num_virtflags; k++ ) {
744       m = launcherpp->virtlist[k].vfindex;
745       hcode = launcherpp->virtlist[k].hcode;
746       ucode = launcherpp->virtlist[k].ucode;
747       if ( virtflags[m].not ) {
748          if ( (x10state[hcode].vflags[ucode] & virtflags[m].vflag) != 0 )
749             return 1;
750       }
751       else {
752          if ( (x10state[hcode].vflags[ucode] & virtflags[m].vflag) == 0 )
753             return 1;
754       }
755    }
756 
757    return 0;
758 }
759 
760 /*----------------------------------------------------------------------------+
761  | Initialize the state structure elements for (X10 encoded) hcode            |
762  +----------------------------------------------------------------------------*/
x10state_init_old(unsigned char hcode)763 void x10state_init_old ( unsigned char hcode )
764 {
765    void reset_security_sensor_timeout ( unsigned char, unsigned int );
766 
767    ALIAS *aliasp;
768    int   j, k;
769    int   ucode, group;
770    char  hc;
771 
772    hc = code2hc(hcode);
773 
774    x10state[hcode].lastunit = 0;
775    x10state[hcode].lastcmd = 0xff;
776    x10state[hcode].reset = 0;
777    x10state[hcode].addressed = 0;
778    x10state[hcode].sticky = 0;
779    x10state[hcode].exclusive = 0;
780    x10state[hcode].vaddress = 0;
781    x10state[hcode].squelch = 0;
782    x10state[hcode].lastactive = 0;
783    x10state[hcode].xconfigmode = 0;
784    for ( j = 0; j < NumStates; j++ )
785       x10state[hcode].state[j] = 0;
786    x10state[hcode].launched = 0;
787 //   x10state[hcode].statusflags = 0;
788    x10state[hcode].rfxlobat = 0;
789    x10state[hcode].longdata = 0;
790    x10global.longdata_flags &= ~(1 << hcode);
791    x10state[hcode].rcstemp = 0;
792    x10global.rcstemp_flags &= ~(1 << hcode);
793    for ( ucode = 0; ucode < 16; ucode++ ) {
794       x10state[hcode].dimlevel[ucode] = 0;
795       x10state[hcode].memlevel[ucode] = maxdimlevel[hcode][ucode];
796       x10state[hcode].vident[ucode] = 0;
797       x10state[hcode].timestamp[ucode] = 0;  /* Init timestamp */
798       x10state[hcode].vflags[ucode] = 0;
799       x10state[hcode].rfxmeter[ucode] = 0;
800       x10state[hcode].grpmember[ucode] = 0;
801       for ( group = 0; group < 4; group++ ) {
802          x10state[hcode].grpaddr[ucode] = 0;
803          x10state[hcode].grplevel[ucode][group] = 0;
804       }
805    }
806 
807    if ( (aliasp = configp->aliasp) == NULL )
808       return;
809 
810    j = 0;
811    while ( aliasp[j].line_no > 0 ) {
812       if ( aliasp[j].housecode == hc ) {
813          for ( k = 0; k < aliasp[j].storage_units; k++ ) {
814             x10global.data_storage[aliasp[j].storage_index + k] = 0;
815          }
816       }
817       j++;
818    }
819 
820    reset_security_sensor_timeout(hcode, 0xffffu );
821 
822    return;
823 }
824 
825 /*----------------------------------------------------------------------------+
826  | Initialize the state structure elements for (X10 encoded) hcode            |
827  +----------------------------------------------------------------------------*/
x10state_init(unsigned char hcode,unsigned int bitmap)828 void x10state_init ( unsigned char hcode, unsigned int bitmap )
829 {
830    void reset_security_sensor_timeout ( unsigned char, unsigned int );
831 
832    ALIAS *aliasp;
833    int   j, k;
834    int   ucode, group;
835    char  hc;
836    unsigned int globtamper = 0;
837 
838    hc = code2hc(hcode);
839 
840    bitmap &= 0xffffu;
841    if ( bitmap == 0 )
842       bitmap = 0xffffu;
843 
844    if ( bitmap == 0xffffu ) {
845       x10state[hcode].reset = 0;
846       x10state[hcode].lastunit = 0;
847       x10state[hcode].lastcmd = 0xffu;
848       x10state[hcode].xconfigmode = 0;
849       x10state[hcode].longdata = 0;
850       x10global.longdata_flags &= ~(1 << hcode);
851       x10state[hcode].rcstemp = 0;
852       x10global.rcstemp_flags &= ~(1 << hcode);
853    }
854 
855    x10state[hcode].addressed &= ~bitmap;
856    x10state[hcode].exclusive &= ~bitmap;
857    x10state[hcode].sticky &= ~bitmap;
858    x10state[hcode].vaddress &= ~bitmap;
859    x10state[hcode].squelch &= ~bitmap;
860    x10state[hcode].lastactive &= ~bitmap;
861    x10state[hcode].launched &= ~bitmap;
862    x10state[hcode].rfxlobat &= ~bitmap;
863    for ( j = 0; j < NumStates; j++ ) {
864       x10state[hcode].state[j] &= ~bitmap;
865    }
866 
867    for ( ucode = 0; ucode < 16; ucode++ ) {
868       if ( bitmap & (1 << ucode) ) {
869          x10state[hcode].dimlevel[ucode] = 0;
870          x10state[hcode].memlevel[ucode] = maxdimlevel[hcode][ucode];
871          x10state[hcode].vident[ucode] = 0;
872          x10state[hcode].timestamp[ucode] = 0;  /* Init timestamp */
873          x10state[hcode].vflags[ucode] = 0;
874          x10state[hcode].rfxmeter[ucode] = 0;
875          x10state[hcode].grpmember[ucode] = 0;
876          for ( group = 0; group < 4; group++ ) {
877             x10state[hcode].grpaddr[ucode] = 0;
878             x10state[hcode].grplevel[ucode][group] = 0;
879          }
880       }
881    }
882 
883    aliasp = configp->aliasp;
884 
885    j = 0;
886    while ( aliasp && aliasp[j].line_no > 0 ) {
887       if ( aliasp[j].housecode == hc && (bitmap & aliasp[j].unitbmap) != 0 ) {
888          for ( k = 0; k < aliasp[j].storage_units; k++ ) {
889             x10global.data_storage[aliasp[j].storage_index + k] = 0;
890          }
891       }
892       j++;
893    }
894 
895    reset_security_sensor_timeout(hcode, bitmap);
896 
897    globtamper = 0;
898    for ( j = 0; j < 16; j++ ) {
899       globtamper |= x10state[j].state[TamperState];
900    }
901    if ( (globtamper & 0xffffu) == 0 ) {
902       x10global.sflags &= ~GLOBSEC_TAMPER;
903    }
904 
905    write_x10state_file();
906 
907    return;
908 }
909 
910 /*----------------------------------------------------------------------------+
911  | Initialize the state structure for all housecodes and global data except   |
912  | security flags and countdown timer counts.                                 |
913  +----------------------------------------------------------------------------*/
x10state_init_all(void)914 void x10state_init_all ( void )
915 {
916    int hcode, j, k;
917 
918    for ( hcode = 0; hcode < 16; hcode++ )
919       x10state_init(hcode, 0xffff);
920 
921    x10global.longvdata = 0;
922    x10global.longvdata2 = 0;
923    x10global.longvdata3 = 0;
924    x10global.sigcount = 0;
925    x10global.interval = 0;
926    x10global.lastvtype = 0;
927    x10global.lasthc = 0xff;
928    x10global.lastaddr = 0;
929    x10global.utc0_macrostamp = 0;
930    x10global.hailstate = 0;
931    x10global.sflags &=
932       (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING | GLOBSEC_TAMPER);
933    x10global.vflags = 0;
934    update_global_nightdark_flags(time(NULL));
935 
936    if ( x10global.timer_count[ArmDelayTimer] > 0 ) {
937       x10global.timer_count[ArmDelayTimer] = 0;
938       x10global.sflags &= ~(GLOBSEC_PENDING);
939       x10global.sflags |= GLOBSEC_ARMED;
940    }
941 
942    for ( j = 1; j <= NUM_USER_TIMERS; j++ ) {
943       x10global.timer_count[j] = 0;
944    }
945    for ( j = 0; j < NUM_TIMER_BANKS; j++ ) {
946       x10global.tzflags[j] = ~(0UL);
947    }
948 
949 
950    for ( j = 0; j < 8; j++ ) {
951       x10global.rfxflags[j] = 0;
952       for ( k = 0; k < 3; k++ ) {
953          x10global.rfxdata[j][k] = 0;
954       }
955    }
956    for ( j = 0; j < NUM_FLAG_BANKS; j++ ) {
957       x10global.flags[j] = 0;
958    }
959    for ( j = 0; j < (32 * NUM_COUNTER_BANKS); j++ ) {
960       x10global.counter[j] = 0;
961    }
962    for ( j = 0; j < NUM_COUNTER_BANKS; j++ )
963       x10global.czflags[j] = ~(0);
964 
965    for ( j = 0; j < MAXDATASTORAGE; j++ )
966       x10global.data_storage[j] = 0;
967 
968    write_x10state_file();
969 
970    return;
971 }
972 
973 /*----------------------------------------------------------------------------+
974  | Initialize the cumulative address table for all housecodes.                |
975  +----------------------------------------------------------------------------*/
x10state_init_others(void)976 void x10state_init_others ( void )
977 {
978    int hcode;
979 
980    for ( hcode = 0; hcode < 16; hcode++ )
981       x10state[hcode].sticky = 0;
982 
983    return;
984 }
985 
986 /*---------------------------------------------------------------------+
987  | Convert Celsius temperature to scaled temperature.                  |
988  +---------------------------------------------------------------------*/
celsius2temp(double tempc,char tscale,double toffset)989 double celsius2temp ( double tempc, char tscale, double toffset )
990 {
991 
992    double temperature;
993 
994    switch ( tscale ) {
995       case 'F' :
996          /* Fahrenheit */
997          temperature = 1.8 * tempc + 32.0;
998          break;
999       case 'R' :
1000          /* Rankine */
1001          temperature = 1.8 * tempc + 32.0 + 459.67;
1002          break;
1003       case 'K' :
1004          /* Kelvin */
1005          temperature = tempc + 273.15;
1006          break;
1007       default :
1008          /* Celsius */
1009          temperature = tempc;
1010          break;
1011    }
1012    temperature += toffset;
1013 
1014    return temperature;
1015 }
1016 
1017 /*---------------------------------------------------------------------+
1018  | Convert scaled temperature to Celsius.                              |
1019  +---------------------------------------------------------------------*/
temp2celsius(double temperature,char tscale,double toffset)1020 double temp2celsius ( double temperature, char tscale, double toffset )
1021 {
1022 
1023    double tempc;
1024 
1025    temperature -= toffset;
1026 
1027    switch ( tscale ) {
1028       case 'F' :
1029          /* Input is Fahrenheit */
1030          tempc = (temperature - 32.0) / 1.8;
1031          break;
1032       case 'R' :
1033          /* Input is Rankine */
1034          tempc = (temperature - 32.0 - 459.67) / 1.8;
1035          break;
1036       case 'K' :
1037          /* Input is Kelvin */
1038          tempc = temperature - 273.15;
1039          break;
1040       default :
1041          /* Input is Celsius */
1042          tempc = temperature;
1043          break;
1044    }
1045 
1046    return tempc;
1047 }
1048 
1049 /*----------------------------------------------------------------------------+
1050  | Elapsed time string from last timestamp in hours:minutes:seconds           |
1051  +----------------------------------------------------------------------------*/
intvstrfunc(char * intvstr,long * intv,time_t timenow,time_t timeprev)1052 void intvstrfunc ( char *intvstr, long *intv, time_t timenow, time_t timeprev )
1053 {
1054    unsigned long intvu, hours, minutes, seconds;
1055 
1056    if ( timeprev == 0 || timenow < timeprev ) {
1057       sprintf(intvstr, "----");
1058       *intv = -1;
1059       return;
1060    }
1061 
1062    intvu = (unsigned long)(timenow - timeprev);
1063    *intv = intvu;
1064    hours = intvu / 3600u;
1065    intvu = intvu % 3600u;
1066    minutes = intvu / 60u;
1067    seconds = intvu % 60u;
1068 
1069    sprintf(intvstr, "%lu:%02lu:%02lu", hours, minutes, seconds );
1070 
1071    return;
1072 }
1073 
1074 /*---------------------------------------------------------------------+
1075  | Initialize the arm delay timer with the countdown time in seconds.  |
1076  +---------------------------------------------------------------------*/
set_arm_delay_timer_countdown(long seconds)1077 void set_arm_delay_timer_countdown ( long seconds )
1078 {
1079    x10global.timer_count[ArmDelayTimer] = seconds;
1080 
1081    return;
1082 }
1083 
1084 /*----------------------------------------------------------------------------+
1085  | Set the security flags represented by the argument (which has been shifted |
1086  | to fit into the size of the argument).                                     |
1087  | With this version, an Armed or Pending state cannot be changed unless      |
1088  | first Disarmed.                                                            |
1089  +----------------------------------------------------------------------------*/
set_globsec_flags_strict(unsigned char sflags)1090 int set_globsec_flags_strict ( unsigned char sflags )
1091 {
1092    unsigned long lflags;
1093    int           retcode = 1;
1094 
1095    lflags = ((unsigned long)sflags << GLOBSEC_SHIFT) &
1096                 (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1097 
1098    if ( lflags == 0 ) {
1099       /* Disarm */
1100       x10global.sflags &= ~(GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1101       set_arm_delay_timer_countdown(0);
1102       x10global.timer_count[ArmDelayTimer] = 0;
1103       retcode = 0;
1104    }
1105    else if ( !(x10global.sflags & (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING)) ) {
1106       /* Arm */
1107       x10global.sflags |= lflags;
1108       if ( x10global.sflags & GLOBSEC_PENDING ) {
1109          set_arm_delay_timer_countdown(config.arm_max_delay);
1110          if ( (x10global.timer_count[ArmDelayTimer] = config.arm_max_delay) == 0 ) {
1111             x10global.sflags |= GLOBSEC_ARMED;
1112             x10global.sflags &= ~GLOBSEC_PENDING;
1113          }
1114       }
1115       retcode = 0;
1116    }
1117 
1118    return retcode;
1119 }
1120 
1121 
1122 /*----------------------------------------------------------------------------+
1123  | Set the security flags represented by the argument (which has been shifted |
1124  | to fit into the size of the argument).                                     |
1125  | Allowed changes:                                                           |
1126  |    Disarmed --> Armed or Pending                                           |
1127  |    Armed    --> Disarmed                                                   |
1128  |    Pending  --> Armed or Disarmed                                          |
1129  |    Home    <--> Away                                                       |
1130  +----------------------------------------------------------------------------*/
set_globsec_flags_medium(unsigned char sflags)1131 int set_globsec_flags_medium ( unsigned char sflags )
1132 {
1133    unsigned long lflags, gflags;
1134 
1135    lflags = ((unsigned long)sflags << GLOBSEC_SHIFT) &
1136                        (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1137    gflags = x10global.sflags & (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1138 
1139    if ( lflags == gflags ) {
1140       return 0;
1141    }
1142 
1143    if ( lflags == 0 ) {
1144       /* Disarm */
1145       x10global.sflags &= ~(GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1146       set_arm_delay_timer_countdown(0);
1147       x10global.timer_count[ArmDelayTimer] = 0;
1148       return 0;
1149    }
1150 
1151    if ( gflags == 0 ) {
1152       /* Arm or Pending */
1153       x10global.sflags |= lflags;
1154       if ( x10global.sflags & GLOBSEC_PENDING ) {
1155          set_arm_delay_timer_countdown(config.arm_max_delay);
1156          if ( (x10global.timer_count[ArmDelayTimer] = config.arm_max_delay) == 0 ) {
1157             x10global.sflags |= GLOBSEC_ARMED;
1158             x10global.sflags &= ~GLOBSEC_PENDING;
1159          }
1160       }
1161       return 0;
1162    }
1163 
1164    if ( lflags & GLOBSEC_ARMED ||
1165         (gflags & GLOBSEC_ARMED && lflags & GLOBSEC_PENDING) ) {
1166       /* Arm */
1167       x10global.sflags &= ~GLOBSEC_PENDING;
1168       x10global.sflags |= GLOBSEC_ARMED;
1169       set_arm_delay_timer_countdown(0);
1170       x10global.timer_count[ArmDelayTimer] = 0;
1171       if ( (lflags & GLOBSEC_HOME) != (gflags & GLOBSEC_HOME) ) {
1172          /* Reverse Home or Away */
1173          x10global.sflags &= ~GLOBSEC_HOME;
1174          x10global.sflags |= (lflags & GLOBSEC_HOME);
1175       }
1176       return 0;
1177    }
1178 
1179    return 1;
1180 }
1181 
1182 
1183 /*----------------------------------------------------------------------------+
1184  | Set the security flags represented by the argument (which has been shifted |
1185  | to fit into the size of the argument).                                     |
1186  | Allowed transitions:  Any                                                  |
1187  +----------------------------------------------------------------------------*/
set_globsec_flags_loose(unsigned char sflags)1188 int set_globsec_flags_loose ( unsigned char sflags )
1189 {
1190    x10global.sflags &= ~(GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1191 
1192    x10global.sflags |= ((unsigned long)sflags << GLOBSEC_SHIFT) &
1193                                (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING);
1194 
1195    if ( x10global.sflags & GLOBSEC_PENDING ) {
1196       set_arm_delay_timer_countdown(config.arm_max_delay);
1197       if ( (x10global.timer_count[ArmDelayTimer] = config.arm_max_delay) == 0 ) {
1198          x10global.sflags |= GLOBSEC_ARMED;
1199          x10global.sflags &= ~GLOBSEC_PENDING;
1200       }
1201    }
1202    else {
1203       set_arm_delay_timer_countdown(0);
1204       x10global.timer_count[ArmDelayTimer] = 0;
1205    }
1206 
1207    return 0;
1208 }
1209 
set_globsec_flags(unsigned char sflags)1210 int set_globsec_flags ( unsigned char sflags )
1211 {
1212    return
1213      (config.arm_logic == ArmLogicStrict) ? set_globsec_flags_strict(sflags) :
1214      (config.arm_logic == ArmLogicMedium) ? set_globsec_flags_medium(sflags) :
1215      (config.arm_logic == ArmLogicLoose)  ? set_globsec_flags_loose(sflags)  : 0;
1216 }
1217 
set_seclights_flag(unsigned char sflags)1218 int set_seclights_flag ( unsigned char sflags )
1219 {
1220    if ( sflags )
1221       x10global.sflags |= GLOBSEC_SLIGHTS;
1222    else
1223       x10global.sflags &= ~GLOBSEC_SLIGHTS;
1224    return 0;
1225 }
1226 
set_tamper_flag(unsigned char sflags)1227 int set_tamper_flag ( unsigned char sflags )
1228 {
1229    if ( sflags )
1230       x10global.sflags |= GLOBSEC_TAMPER;
1231    else
1232       x10global.sflags &= ~GLOBSEC_TAMPER;
1233    return 0;
1234 }
1235 
1236 /*----------------------------------------------------------------------------+
1237  | Display the Armed/Disarmed state of the system - c_show2()                 |
1238  +----------------------------------------------------------------------------*/
show_armed_status(void)1239 void show_armed_status ( void )
1240 {
1241    char *tflag;
1242 
1243    tflag = (x10global.sflags & GLOBSEC_TAMPER) ? "*TAMPER*, " : "";
1244 
1245    if ( x10global.sflags & GLOBSEC_PENDING ) {
1246       printf("%sSystem will be Armed %s in %ld seconds\n", tflag,
1247           ((x10global.sflags & GLOBSEC_HOME) ? "Home" : "Away"),
1248           x10global.timer_count[ArmDelayTimer]);
1249    }
1250    else if ( (x10global.sflags & GLOBSEC_ARMED) == 0 ) {
1251       printf("%sSystem is Disarmed\n", tflag);
1252    }
1253    else {
1254       printf("%sSystem is Armed %s\n", tflag,
1255          ((x10global.sflags & GLOBSEC_HOME) ? "Home" : "Away") );
1256    }
1257 
1258    return;
1259 }
1260 
1261 
1262 /*----------------------------------------------------------------------------+
1263  | Display the Armed/Disarmed state of the system (poll.c)                    |
1264  +----------------------------------------------------------------------------*/
display_armed_status(void)1265 char *display_armed_status ( void )
1266 {
1267    static char outbuf[120];
1268 
1269    if ( x10global.sflags & GLOBSEC_PENDING ) {
1270       sprintf(outbuf, "%sSystem will be Armed %s in %ld seconds.",
1271           ((x10global.sflags & GLOBSEC_TAMPER) ? "*TAMPER*, " : ""),
1272           ((x10global.sflags & GLOBSEC_HOME) ? "Home" : "Away"),
1273           x10global.timer_count[ArmDelayTimer]);
1274       return outbuf;
1275    }
1276 
1277    *outbuf = '\0';
1278 
1279    if ( x10global.sflags & GLOBSEC_TAMPER )
1280       strcat(outbuf, "*TAMPER*, ");
1281 
1282    if ( (x10global.sflags & GLOBSEC_ARMED) == 0 ) {
1283       strcat(outbuf, "System is Disarmed");
1284    }
1285    else {
1286       strcat(outbuf, "System is Armed ");
1287       strcat(outbuf, ((x10global.sflags & GLOBSEC_HOME) ? "Home" : "Away"));
1288    }
1289 
1290    return outbuf;
1291 }
1292 
1293 
1294 /*----------------------------------------------------------------------------+
1295  | Send a powerfail message to the heyu monitor/state engine                  |
1296  +----------------------------------------------------------------------------*/
send_pfail_msg(int spptty,unsigned char command,unsigned char parm)1297 void send_pfail_msg ( int spptty, unsigned char command, unsigned char parm )
1298 {
1299    static unsigned char template[7] = {
1300      0xff,0xff,0xff,3,ST_COMMAND,0,0};
1301 
1302    int ignoret;
1303 
1304    template[5] = command;
1305    template[6] = parm;
1306 
1307    ignoret = write(spptty, template, 7);
1308    return;
1309 }
1310 
1311 
1312 /*----------------------------------------------------------------------------+
1313  | Internal @vdata and @vdatam commands                                       |
1314  +----------------------------------------------------------------------------*/
engine_internal_vdata(unsigned char hcode,unsigned char ucode,unsigned char vdata,unsigned char vtype)1315 void engine_internal_vdata ( unsigned char hcode, unsigned char ucode,
1316                              unsigned char vdata, unsigned char vtype )
1317 {
1318    unsigned int bitmap, changestate, startupstate;
1319    char         hc;
1320    unsigned char func;
1321 
1322    bitmap = 1 << ucode;
1323    hc = code2hc(hcode);
1324 
1325 //   x10state[hcode].state[ChgState] = 0;
1326    changestate = 0;
1327    if ( vtype == RF_VDATAM ) {
1328       func = VdataMFunc;
1329       if ( vdata != x10state[hcode].memlevel[ucode] )
1330 //         x10state[hcode].state[ChgState] |= bitmap;
1331          changestate |= bitmap;
1332       x10state[hcode].memlevel[ucode] = vdata;
1333    }
1334    else {
1335       func = VdataFunc;
1336       if ( vdata != x10state[hcode].dimlevel[ucode] )
1337 //         x10state[hcode].state[ChgState] |= bitmap;
1338          changestate |= bitmap;
1339       x10state[hcode].dimlevel[ucode] = vdata;
1340    }
1341    x10state[hcode].lastcmd = func;
1342    x10state[hcode].vaddress = bitmap;
1343    x10state[hcode].lastunit = code2unit(ucode);
1344    x10state[hcode].vident[ucode] = 0;
1345    x10state[hcode].vflags[ucode] = 0;
1346    x10state[hcode].timestamp[ucode] = time(NULL);
1347 //   x10state[hcode].state[ValidState] |= (1 << ucode);
1348    x10global.lasthc = hcode;
1349    x10global.lastaddr = 0;
1350 
1351    startupstate = ~x10state[hcode].state[ValidState] & bitmap;
1352    x10state[hcode].state[ValidState] |= bitmap;
1353 
1354 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~bitmap) | changestate;
1355    x10state[hcode].state[ModChgState] = changestate;
1356    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
1357       (x10state[hcode].state[ActiveChgState] & bitmap) |
1358       (startupstate & ~modmask[PhysMask][hcode]);
1359 
1360    if ( i_am_state ) {
1361       fprintf(fdsout, "%s syst func %12s : hu %c%-2d vdata 0x%02x (%s)\n",
1362          datstrf(), funclabel[func], hc, code2unit(ucode), vdata, lookup_label(hc, bitmap));
1363    }
1364 
1365    return;
1366 }
1367 
1368 #if 0
1369 /*----------------------------------------------------------------------------+
1370  | Internal @vdata command                                                    |
1371  +----------------------------------------------------------------------------*/
1372 void engine_internal_vdata_old ( unsigned char hcode, unsigned char ucode, unsigned char vdata )
1373 {
1374    unsigned int bitmap;
1375    char         hc;
1376 
1377    bitmap = 1 << ucode;
1378    hc = code2hc(hcode);
1379 
1380    x10state[hcode].vaddress = bitmap;
1381    x10state[hcode].lastcmd = VdataFunc;
1382    x10state[hcode].lastunit = code2unit(ucode);
1383    x10state[hcode].vident[ucode] = 0;
1384    x10state[hcode].vflags[ucode] = 0;
1385    x10state[hcode].timestamp[ucode] = time(NULL);
1386    x10state[hcode].state[ValidState] |= (1 << ucode);
1387    x10state[hcode].state[ChgState] = 0;
1388    x10global.lasthc = hcode;
1389    x10global.lastaddr = 0;
1390    if ( vdata != x10state[hcode].dimlevel[ucode] )
1391       x10state[hcode].state[ChgState] |= bitmap;
1392    x10state[hcode].dimlevel[ucode] = vdata;
1393    if ( i_am_state ) {
1394       fprintf(fdsout, "%s syst func %12s : hu %c%-2d vdata 0x%02x (%s)\n",
1395          datstrf(), funclabel[VdataFunc], hc, code2unit(ucode), vdata, lookup_label(hc, bitmap));
1396    }
1397 
1398    return;
1399 }
1400 #endif
1401 
1402 /*----------------------------------------------------------------------------+
1403  | Send command line launch request to the Heyu state engine                  |
1404  | Mode 0x00 - Check all launchers for script                                 |
1405  | Mode 0x01 - Check only specified launcher for script                       |
1406  | Mode 0x80 - Exec mode (flags only)                                         |
1407  +----------------------------------------------------------------------------*/
send_launch_request(unsigned char mode,int scriptnum,int launchernum)1408 void send_launch_request ( unsigned char mode, int scriptnum, int launchernum )
1409 {
1410    static unsigned char template[11] = {
1411     0xff, 0xff, 0xff, 7, ST_COMMAND, ST_SCRIPT, 0, 0,0, 0,0};
1412 
1413    int ignoret;
1414 
1415    template[6] = mode;
1416    template[7] = scriptnum & 0x00ff;
1417    template[8] = (scriptnum & 0xff00) >> 8;
1418    template[9] = launchernum & 0x00ff;
1419    template[10] = (launchernum & 0xff00) >> 8;
1420 
1421    ignoret = write(sptty, template, sizeof(template));
1422    return;
1423 }
1424 
1425 /*----------------------------------------------------------------------------+
1426  | Send a binary buffer to the monitor/logfile for display                    |
1427  +----------------------------------------------------------------------------*/
send_showbuffer(unsigned char * buffer,unsigned char bufflen)1428 void send_showbuffer ( unsigned char *buffer, unsigned char bufflen )
1429 {
1430    unsigned char outbuff[80];
1431    int ignoret;
1432    static unsigned char template[7] = {
1433      0xff, 0xff, 0xff, 0, ST_COMMAND, ST_SHOWBUFFER, 0};
1434 
1435    template[6] = bufflen;
1436    template[3] = bufflen + 3;
1437    memcpy(outbuff, template, sizeof(template));
1438    memcpy(outbuff + sizeof(template), buffer, bufflen);
1439 
1440    ignoret = write(sptty, outbuff, sizeof(template) + bufflen);
1441 
1442    return;
1443 }
1444 
1445 /*----------------------------------------------------------------------------+
1446  | Debugging tool - Displey a binary buffer in the monitor/logfile            |
1447  | buff[0] is length, buff + 1 = data                                         |
1448  +----------------------------------------------------------------------------*/
display_binbuffer(unsigned char * buff)1449 char *display_binbuffer ( unsigned char *buff )
1450 {
1451    int j;
1452    static char outbuff[120];
1453 
1454    strcpy(outbuff, "Buffer =");
1455    for ( j = 0; j < buff[0]; j++ ) {
1456       sprintf(outbuff + strlen(outbuff), " %02x", buff[1 + j]);
1457    }
1458 
1459    return outbuff;
1460 }
1461 
1462 
1463 /*----------------------------------------------------------------------------+
1464  | Send virtual data to the heyu monitor/state engine                         |
1465  +----------------------------------------------------------------------------*/
send_virtual_data(unsigned char address,unsigned char vdata,unsigned char vtype,unsigned char vidlo,unsigned char vidhi,unsigned char byte2,unsigned char byte3)1466 void send_virtual_data ( unsigned char address, unsigned char vdata,
1467      unsigned char vtype, unsigned char vidlo, unsigned char vidhi, unsigned char byte2, unsigned char byte3 )
1468 {
1469    static unsigned char template[20] = {
1470     0xff,0xff,0xff,3,ST_COMMAND,ST_SOURCE,0,
1471     0xff,0xff,0xff,9,ST_COMMAND,ST_VDATA,0,0,0,0,0,0,0};
1472 
1473    int ignoret;
1474 
1475    template[6] = (unsigned char)heyu_parent;
1476 
1477    template[13] = address;
1478    template[14] = vdata;
1479    template[15] = vtype;
1480    template[16] = vidlo;
1481    template[17] = vidhi;
1482    template[18] = byte2;
1483    template[19] = byte3;
1484 
1485    ignoret = write(sptty, template, sizeof(template));
1486    return;
1487 }
1488 
1489 /*----------------------------------------------------------------------------+
1490  | Send a state command to the heyu monitor/state engine                      |
1491  +----------------------------------------------------------------------------*/
send_sptty_x10state_command(int spptty,unsigned char command,unsigned char parm)1492 void send_sptty_x10state_command ( int spptty, unsigned char command, unsigned char parm )
1493 {
1494    static unsigned char template[7] = {
1495     0xff,0xff,0xff,3,ST_COMMAND,0,0};
1496 
1497    int ignoret = 0;
1498 
1499    template[5] = command;
1500    template[6] = parm;
1501 
1502    ignoret = write(spptty, template, sizeof(template));
1503 
1504    return;
1505 }
1506 
1507 
1508 /*----------------------------------------------------------------------------+
1509  | Send a state command to the heyu monitor/state engine                      |
1510  +----------------------------------------------------------------------------*/
send_x10state_command(unsigned char command,unsigned char parm)1511 void send_x10state_command ( unsigned char command, unsigned char parm )
1512 {
1513    extern int sptty;
1514 
1515    send_sptty_x10state_command(sptty, command, parm);
1516 
1517    return;
1518 }
1519 
1520 /*----------------------------------------------------------------------------+
1521  | Send an initstate command to the heyu monitor/state engine                 |
1522  +----------------------------------------------------------------------------*/
send_initstate_command(unsigned char hcode,unsigned int bitmap)1523 void send_initstate_command ( unsigned char hcode, unsigned int bitmap )
1524 {
1525    extern int sptty;
1526    static unsigned char template[9] = {
1527     0xff, 0xff, 0xff, 5, ST_COMMAND, ST_INIT, 0, 0,0};
1528    int ignoret = 0;
1529 
1530    template[6] = hcode;
1531    template[7] = bitmap & 0x00ff;
1532    template[8] = (bitmap & 0xff00) >> 8;
1533 
1534    ignoret = write(sptty, template, sizeof(template));
1535 
1536    return;
1537 }
1538 
1539 /*----------------------------------------------------------------------------+
1540  | Translate an X10-encoded bitmap to a linear unit bitmap, i.e., where       |
1541  | unit 1 = 1, unit 2 = 2, unit 3 = 4, unit 4 = 8, etc.                       |
1542  +----------------------------------------------------------------------------*/
x10map2linmap(unsigned int x10map)1543 unsigned int x10map2linmap ( unsigned int x10map )
1544 {
1545    int j;
1546    unsigned int mask, linmap;
1547    static unsigned char bitshift[] =
1548       {12,4,2,10,14,6,0,8,13,5,3,11,15,7,1,9};
1549 
1550    mask = 1;
1551    linmap = 0;
1552    for ( j = 0; j < 16; j++ ) {
1553      if ( x10map & mask )
1554         linmap |= (1 << bitshift[j]);
1555      mask <<= 1;
1556    }
1557    return linmap;
1558 }
1559 
1560 /*----------------------------------------------------------------------------+
1561  | Display a text message in the heyu monitor/state engine logfile            |
1562  | Maximum length 80 characters.                                              |
1563  +----------------------------------------------------------------------------*/
display_x10state_message(char * message)1564 int display_x10state_message ( char *message )
1565 {
1566    extern int    sptty;
1567    int           size;
1568    unsigned char buf[88];
1569 
1570    int   ignoret;
1571 
1572    static unsigned char template[7] = {
1573      0xff,0xff,0xff,0,ST_COMMAND,ST_MSG,0};
1574 
1575    if ( (size = strlen(message)) > (int)(sizeof(buf) - 8) ) {
1576       fprintf(stderr,
1577         "Log message exceeds %d characters\n", (int)(sizeof(buf) - 8));
1578       return 1;
1579    }
1580 
1581    memcpy(buf, template, sizeof(template));
1582    memcpy(buf + sizeof(template), message, size + 1);
1583 
1584    buf[6] = size + 1;
1585    buf[3] = size + 1 + 3;
1586 
1587    ignoret = write(sptty, buf, size + 8);
1588 
1589    return 0;
1590 }
1591 
1592 /*----------------------------------------------------------------------------+
1593  | Display a text message in the heyu monitor/state engine logfile            |
1594  | Maximum length 80 characters.                                              |
1595  +----------------------------------------------------------------------------*/
c_logmsg(int argc,char * argv[])1596 int c_logmsg ( int argc, char *argv[] )
1597 {
1598    if ( argc < 3 ) {
1599       fprintf(stderr, "%s - Too few arguments\n", argv[1]);
1600       return 1;
1601    }
1602    else if ( argc > 3 ) {
1603       fprintf(stderr, "%s - Too many arguments\n", argv[1]);
1604       return 1;
1605    }
1606 
1607    return display_x10state_message(argv[2]);
1608 }
1609 
1610 /*----------------------------------------------------------------------------+
1611  | Display the raw data in argument buff + 4 as hex bytes.                    |
1612  | buff[2] has the type code, buff[3] has the length of the data.             |
1613  | (This function is used in poll.c to display a Raw or Noise packet from     |
1614  | heyu_aux in the log file and/or monitor.)                                  |
1615  | Maximum length 120 characters.                                             |
1616  +----------------------------------------------------------------------------*/
display_variable_aux_data(unsigned char * buff)1617 char *display_variable_aux_data ( unsigned char *buff )
1618 {
1619    static char outbuf[120];
1620    int         j;
1621 
1622    if ( buff[2] == RF_NOISEVL ) {
1623       sprintf(outbuf, "func %12s : Data (hex)", "RFnoise");
1624    }
1625    else if ( buff[2] == RF_RAWVL ) {
1626       sprintf(outbuf, "func %12s : Data (hex)", "RFrawdata");
1627    }
1628    else {
1629       sprintf(outbuf, "func %12s : Data (hex)", "RFunknown");
1630    }
1631 
1632    for ( j = 0; j < buff[3]; j++ ) {
1633       snprintf(outbuf + strlen(outbuf), sizeof(outbuf) - strlen(outbuf) - 1,
1634               " %02x", buff[j + 4]);
1635    }
1636 
1637    return outbuf;
1638 }
1639 
1640 
1641 
1642 
1643 
1644 /*----------------------------------------------------------------------------+
1645  | Send an arbitrary state message to the engine.  The first parameter must   |
1646  | be the ST_XXX value (in hex), then followed by the hex bytes to be sent.   |
1647  +----------------------------------------------------------------------------*/
c_sendarbst(int argc,char * argv[])1648 int c_sendarbst ( int argc, char *argv[] )
1649 {
1650    unsigned char buf[80];
1651    long hex;
1652    int j;
1653    char *sp;
1654 
1655    int ignoret;
1656 
1657    if ( argc < 4 ) {
1658       fprintf(stderr, "%s - Too few arguments\n", argv[1]);
1659       return 1;
1660    }
1661 
1662    hex = strtol(argv[2], &sp, 16);
1663    if ( !strchr(" /r/n", *sp) || hex < 0 || hex > 0xff ) {
1664       fprintf(stderr, "Invalid ST_xxxx value '%s'\n", argv[2]);
1665       return 1;
1666    }
1667 
1668    buf[0] = 0xff; buf[1] = 0xff; buf[2] = 0xff;
1669    buf[3] = argc - 1;
1670    buf[4] = ST_COMMAND;
1671    buf[5] = (unsigned char)hex;
1672 
1673    for ( j = 3; j < argc; j++ ) {
1674       hex = strtol(argv[j], &sp, 16);
1675       if ( !strchr(" /r/n", *sp) || hex < 0 || hex > 0xff ) {
1676          fprintf(stderr, "Invalid hex byte value '%s'\n", argv[j]);
1677          return 1;
1678       }
1679       buf[j + 3] = (unsigned char)hex;
1680    }
1681 
1682    ignoret = write(sptty, buf, argc + 3);
1683 
1684    return 0;
1685 }
1686 
1687 /*----------------------------------------------------------------------------+
1688  | Check the dims table to determine the onstate and dimstate of modules on   |
1689  | argument housecode, returning X10 bitmaps back through the argument list.  |
1690  +----------------------------------------------------------------------------*/
get_states(unsigned char hcode,unsigned int * onstate,unsigned int * dimstate)1691 void get_states ( unsigned char hcode, unsigned int *onstate, unsigned int *dimstate )
1692 {
1693    int           ucode;
1694    unsigned char level;
1695    unsigned int  mask, offstate, ex3mask, premask, stdmask, ex0mask, kakumask, vdatamask;
1696 
1697    ex3mask  = modmask[Ext3Mask][hcode];
1698    premask  = modmask[PresetMask][hcode];
1699    stdmask  = modmask[StdMask][hcode];
1700    ex0mask  = modmask[Ext0Mask][hcode];
1701    vdatamask = modmask[VdataMask][hcode];
1702    kakumask = kmodmask[KpreMask][hcode] | kmodmask[KGpreMask][hcode];
1703 
1704    offstate = 0;
1705    *dimstate = 0;
1706    for ( ucode = 0; ucode < 16; ucode++ ) {
1707       mask = (1 << ucode);
1708       level = x10state[hcode].dimlevel[ucode];
1709       if ( level == 0 )
1710          offstate |= mask;
1711       else if ( (mask & ex3mask  && level < 62)  ||
1712                 (mask & ex0mask  && level < 25)  ||
1713                 (mask & premask  && level < 31)  ||
1714                 (mask & stdmask  && level < 210) ||
1715                 (mask & kakumask && level < 15)  ) {
1716          *dimstate |= mask;
1717       }
1718       else if ( !(mask & (ex3mask | ex0mask | premask | stdmask | kakumask)) &&
1719 		      level < ondimlevel[hcode][ucode] )
1720 	 *dimstate |= mask;
1721    }
1722    *onstate = ~offstate & ~vdatamask;
1723    *dimstate &= ~vdatamask;
1724 
1725    return;
1726 }
1727 
1728 /*----------------------------------------------------------------------------+
1729  | Determine the dimstate of modules on argument housecode, returning an X10  |
1730  | bitmap of units which are dimmed.                                          |
1731  +----------------------------------------------------------------------------*/
get_dimstate(unsigned char hcode)1732 unsigned int get_dimstate ( unsigned char hcode )
1733 {
1734    int ucode;
1735    unsigned int bitmap, mask, dimstate = 0;
1736 
1737    /* Check Extended Preset Type 3 Dim Units */
1738    bitmap = modmask[Ext3DimMask][hcode];
1739    if ( bitmap ) {
1740       mask = 1;
1741       for ( ucode = 0; ucode < 16; ucode++ ) {
1742          if ( bitmap & mask &&
1743               x10state[hcode].dimlevel[ucode] > 0 &&
1744               x10state[hcode].dimlevel[ucode] < 62  ) {
1745             dimstate |= mask;
1746          }
1747          mask = mask << 1;
1748       }
1749    }
1750 
1751    /* Check Extended Preset Type 0 Dim Units */
1752    bitmap = modmask[Ext0Mask][hcode];
1753    if ( bitmap ) {
1754       mask = 1;
1755       for ( ucode = 0; ucode < 16; ucode++ ) {
1756          if ( bitmap & mask &&
1757               x10state[hcode].dimlevel[ucode] > 0 &&
1758               x10state[hcode].dimlevel[ucode] < 25  ) {
1759             dimstate |= mask;
1760          }
1761          mask = mask << 1;
1762       }
1763    }
1764 
1765    /* Check Preset Units */
1766    bitmap = modmask[PresetMask][hcode];
1767    if ( bitmap ) {
1768       mask = 1;
1769       for ( ucode = 0; ucode < 16; ucode++ ) {
1770          if ( bitmap & mask &&
1771               x10state[hcode].dimlevel[ucode] > 0 &&
1772               x10state[hcode].dimlevel[ucode] < 31  ) {
1773             dimstate |= mask;
1774          }
1775          mask = mask << 1;
1776       }
1777    }
1778 
1779    /* Check KAKU Units */
1780    bitmap = kmodmask[KpreMask][hcode] | kmodmask[KGpreMask][hcode];
1781    if ( bitmap ) {
1782       mask = 1;
1783       for ( ucode = 0; ucode < 16; ucode++ ) {
1784          if ( bitmap & mask &&
1785               x10state[hcode].dimlevel[ucode] > 0 &&
1786               x10state[hcode].dimlevel[ucode] < 15  ) {
1787             dimstate |= mask;
1788          }
1789          mask = mask << 1;
1790       }
1791    }
1792 
1793    /* Check Standard Non-Preset Units */
1794    bitmap = (modmask[DimMask][hcode] | modmask[BriMask][hcode]) &
1795             ~modmask[Ext3DimMask][hcode] & ~modmask[PresetMask][hcode];
1796    if ( bitmap ) {
1797       mask = 1;
1798       for ( ucode = 0; ucode < 16; ucode++ ) {
1799          if ( bitmap & mask &&
1800               x10state[hcode].dimlevel[ucode] > 0 &&
1801               x10state[hcode].dimlevel[ucode] < 210  ) {
1802             dimstate |= mask;
1803          }
1804          mask = mask << 1;
1805       }
1806    }
1807 
1808    return dimstate;
1809 }
1810 
1811 
1812 /*----------------------------------------------------------------------------+
1813  | Copy current dimlevel > 0 (0 is the same as OFF) to memlevel for bitmap    |
1814  | units.
1815  | This is only valid for units which support the preset or extended preset   |
1816  | commands.                                                                  |
1817  +----------------------------------------------------------------------------*/
save_dimlevel(unsigned char hcode,unsigned int bitmap)1818 void save_dimlevel ( unsigned char hcode, unsigned int bitmap )
1819 {
1820    int ucode;
1821    int level;
1822    unsigned int mask = 1;
1823 
1824    for ( ucode = 0; ucode < 16; ucode++ ) {
1825       if ( bitmap & mask ) {
1826          level = x10state[hcode].dimlevel[ucode];
1827          if ( level > 0 )
1828            x10state[hcode].memlevel[ucode] = level;
1829       }
1830       mask = mask << 1;
1831    }
1832    return;
1833 }
1834 
1835 /*----------------------------------------------------------------------------+
1836  | Restore current dimlevel from memlevel for bitmap units                    |
1837  | This is only valid for units which support the preset or extended preset   |
1838  | commands.                                                                  |
1839  +----------------------------------------------------------------------------*/
restore_dimlevel(unsigned char hcode,unsigned int bitmap)1840 void restore_dimlevel ( unsigned char hcode, unsigned int bitmap )
1841 {
1842    int ucode;
1843    int level;
1844    unsigned int mask = 1;
1845 
1846    for ( ucode = 0; ucode < 16; ucode++ ) {
1847       if ( bitmap & mask ) {
1848          level = x10state[hcode].memlevel[ucode];
1849          x10state[hcode].dimlevel[ucode] = level;
1850       }
1851       mask = mask << 1;
1852    }
1853    return;
1854 }
1855 
1856 
1857 /*----------------------------------------------------------------------------+
1858  | Set a specific raw dimlevel 0-255 (limited to native level range).         |
1859  +----------------------------------------------------------------------------*/
set_raw_level(int rawlevel,unsigned char hcode,unsigned int bitmap)1860 void set_raw_level ( int rawlevel, unsigned char hcode, unsigned int bitmap )
1861 {
1862    int ucode;
1863    unsigned int mask = 1;
1864    unsigned char level;
1865 
1866    for ( ucode = 0; ucode < 16; ucode++ ) {
1867       if ( bitmap & mask ) {
1868          level = max(0, rawlevel);
1869          level = min(level, maxdimlevel[hcode][ucode]);
1870          x10state[hcode].dimlevel[ucode] = level;
1871       }
1872       mask = mask << 1;
1873    }
1874    return;
1875 }
1876 
1877 /*----------------------------------------------------------------------------+
1878  | Set a specific dimlevel.                                                   |
1879  +----------------------------------------------------------------------------*/
set_dimlevel(int level,unsigned char hcode,unsigned int bitmap)1880 void set_dimlevel ( int level , unsigned char hcode, unsigned int bitmap )
1881 {
1882    int ucode;
1883    unsigned int mask = 1;
1884 
1885    for ( ucode = 0; ucode < 16; ucode++ ) {
1886       if ( bitmap & mask ) {
1887          x10state[hcode].dimlevel[ucode] = level;
1888       }
1889       mask = mask << 1;
1890    }
1891    return;
1892 }
1893 
1894 /*----------------------------------------------------------------------------+
1895  | Set a specific memlevel.                                                   |
1896  +----------------------------------------------------------------------------*/
set_memlevel(int level,unsigned char hcode,unsigned int bitmap)1897 void set_memlevel ( int level , unsigned char hcode, unsigned int bitmap )
1898 {
1899    int ucode;
1900    unsigned int mask = 1;
1901 
1902    for ( ucode = 0; ucode < 16; ucode++ ) {
1903       if ( bitmap & mask ) {
1904          x10state[hcode].memlevel[ucode] = level;
1905       }
1906       mask = mask << 1;
1907    }
1908    return;
1909 }
1910 
1911 /*----------------------------------------------------------------------------+
1912  | Set the ident for virtual modules                                          |
1913  +----------------------------------------------------------------------------*/
set_ident(unsigned short vident,unsigned char hcode,unsigned int bitmap)1914 void set_ident ( unsigned short vident , unsigned char hcode, unsigned int bitmap )
1915 {
1916    int ucode;
1917    unsigned int mask = 1;
1918 
1919    for ( ucode = 0; ucode < 16; ucode++ ) {
1920       if ( bitmap & mask ) {
1921          x10state[hcode].vident[ucode] = vident;
1922       }
1923       mask = mask << 1;
1924    }
1925    return;
1926 }
1927 
1928 
1929 /*----------------------------------------------------------------------------+
1930  | Set dimlevels to '0n' level.                                               |
1931  +----------------------------------------------------------------------------*/
set_max_level(unsigned char hcode,unsigned int bitmap)1932 void set_max_level ( unsigned char hcode, unsigned int bitmap )
1933 {
1934    int           ucode;
1935 
1936    if ( !bitmap )
1937       return;
1938 
1939    for ( ucode = 0; ucode < 16; ucode++ ) {
1940       if ( bitmap & (1 << ucode) ) {
1941          x10state[hcode].dimlevel[ucode] = maxdimlevel[hcode][ucode];
1942       }
1943    }
1944 
1945    return;
1946 }
1947 
1948 /*----------------------------------------------------------------------------+
1949  | Set memlevels to '0n' level.                                               |
1950  +----------------------------------------------------------------------------*/
set_max_memlevel(unsigned char hcode,unsigned int bitmap)1951 void set_max_memlevel ( unsigned char hcode, unsigned int bitmap )
1952 {
1953    int           ucode;
1954 
1955    if ( !bitmap )
1956       return;
1957 
1958    for ( ucode = 0; ucode < 16; ucode++ ) {
1959       if ( bitmap & (1 << ucode) ) {
1960          x10state[hcode].memlevel[ucode] = maxdimlevel[hcode][ucode];
1961       }
1962    }
1963 
1964    return;
1965 }
1966 
1967 /*----------------------------------------------------------------------------+
1968  | Set dimlevels to '0n' level.                                               |
1969  +----------------------------------------------------------------------------*/
set_on_level(unsigned char hcode,unsigned int bitmap)1970 void set_on_level ( unsigned char hcode, unsigned int bitmap )
1971 {
1972    int           ucode;
1973 
1974    if ( !bitmap )
1975       return;
1976 
1977    for ( ucode = 0; ucode < 16; ucode++ ) {
1978       if ( bitmap & (1 << ucode) ) {
1979          x10state[hcode].dimlevel[ucode] = ondimlevel[hcode][ucode];
1980       }
1981    }
1982 
1983    return;
1984 }
1985 
1986 /*----------------------------------------------------------------------------+
1987  | Set a specific dimlevel no higher than that stored in memlevel.            |
1988  +----------------------------------------------------------------------------*/
set_limit_dimlevel(int level,unsigned char hcode,unsigned int bitmap)1989 void set_limit_dimlevel ( int level , unsigned char hcode, unsigned int bitmap )
1990 {
1991    int ucode;
1992    unsigned int mask = 1;
1993 
1994    for ( ucode = 0; ucode < 16; ucode++ ) {
1995       if ( bitmap & mask ) {
1996          x10state[hcode].dimlevel[ucode] =
1997             min(level, (int)x10state[hcode].memlevel[ucode]);
1998       }
1999       mask = mask << 1;
2000    }
2001    return;
2002 }
2003 
2004 /*----------------------------------------------------------------------------+
2005  | Update the stored dimlevel by the amount of the argument level 0-210,      |
2006  | positive for brightens, negative for dims.                                 |
2007  +----------------------------------------------------------------------------*/
update_dimlevel(int level,unsigned char hcode,unsigned int bitmap)2008 void update_dimlevel ( int level , unsigned char hcode, unsigned int bitmap )
2009 {
2010    int          ucode, newlevel, abslev, table, delta;
2011    unsigned int active, mask;
2012 
2013    /* Table used in conversion of dims to change in ext3 preset level */
2014    /* Table[0] is used for Base-2 dims, table[1] for others */
2015    static int ext3table[2][17] = {
2016       {0, 5, 9, 14, 18, 22, 27, 31, 36, 40, 44, 49, 53, 58, 61, 62, 62},
2017       {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 62},
2018    };
2019 
2020    /* Table used in conversion of dims to change in old-style Preset level */
2021    /* Table [0] is brights from level 0, [1] is dims from level 31.        */
2022    static int presettable[2][15] = {
2023       {1, 1, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 29, 30, 32},
2024       {1, 1, 4, 7, 9, 12, 15, 17, 20, 22, 25, 28, 30, 32, 32},
2025    };
2026 
2027    if ( !bitmap )
2028       return;
2029 
2030    /* Standard Dimmable Units */
2031    active = bitmap & (modmask[DimMask][hcode] | modmask[BriMask][hcode]) &
2032                      modmask[StdMask][hcode] ;
2033    if ( active ) {
2034       mask = 1;
2035       for ( ucode = 0; ucode < 16; ucode++ ) {
2036          if ( active & mask ) {
2037             newlevel = level + x10state[hcode].dimlevel[ucode];
2038             newlevel = min(210, newlevel);
2039             newlevel = max(newlevel, (mask & modmask[TargMask][hcode]) ? 0 : 3);
2040             x10state[hcode].dimlevel[ucode] = newlevel;
2041          }
2042          mask = mask << 1;
2043       }
2044    }
2045 
2046    /* Ext3 Units */
2047    active = bitmap & modmask[Ext3Mask][hcode];
2048    if ( active ) {
2049       abslev = abs(level);
2050       table = (abslev % 11 == 2) ? 0 : 1;
2051       delta = ext3table[table][min(abslev/11, 16)];
2052       delta = (level < 0) ? -delta : delta;
2053       mask = 1;
2054       for ( ucode = 0; ucode < 16; ucode++ ) {
2055          if ( active & mask ) {
2056             newlevel = delta + x10state[hcode].dimlevel[ucode];
2057             newlevel = min(62, max(1, newlevel));
2058             x10state[hcode].dimlevel[ucode] = newlevel;
2059          }
2060          mask = mask << 1;
2061       }
2062    }
2063 
2064    /* Ext0 (Shutter) Units */
2065    active = bitmap & modmask[Ext0Mask][hcode];
2066    if ( active ) {
2067       delta = level * 25 / 210 ;
2068       mask = 1;
2069       for ( ucode = 0; ucode < 16; ucode++ ) {
2070          if ( active & mask ) {
2071             newlevel = delta + x10state[hcode].dimlevel[ucode];
2072             newlevel = min(25, max(0, newlevel));
2073             x10state[hcode].dimlevel[ucode] = newlevel;
2074          }
2075          mask = mask << 1;
2076       }
2077    }
2078 
2079    /* Preset1/Preset2 Units, zero-base levels 0-31 */
2080    active = bitmap & modmask[PresetMask][hcode];
2081    if ( active ) {
2082       abslev = abs(level);
2083       delta = (level > 0) ? presettable[0][min(abslev/11, 14)] :
2084                            -presettable[1][min(abslev/11, 14)];
2085       mask = 1;
2086       for ( ucode = 0; ucode < 16; ucode++ ) {
2087          if ( active & mask ) {
2088             newlevel = delta + x10state[hcode].dimlevel[ucode];
2089             newlevel = min(31, max(0, newlevel));
2090             x10state[hcode].dimlevel[ucode] = newlevel;
2091          }
2092          mask = mask << 1;
2093       }
2094    }
2095 
2096    /* Virtual units */
2097    active = bitmap & (modmask[DimMask][hcode] | modmask[BriMask][hcode]) &
2098       ~(modmask[StdMask][hcode] | modmask[Ext3Mask][hcode] | modmask[PresetMask][hcode] | modmask[Ext0Mask][hcode]);
2099    if ( active ) {
2100       mask = 1;
2101       for ( ucode = 0; ucode < 16; ucode++ ) {
2102          if ( active & mask ) {
2103             newlevel = level + x10state[hcode].dimlevel[ucode];
2104             newlevel = min((int)ondimlevel[hcode][ucode], newlevel);
2105             newlevel = max(newlevel, 0);
2106             x10state[hcode].dimlevel[ucode] = newlevel;
2107          }
2108          mask = mask << 1;
2109       }
2110    }
2111 
2112    return;
2113 }
2114 
2115 
2116 /*----------------------------------------------------------------------------+
2117  | Update the sticky address state of housecode|units                         |
2118  | Addressing is cumulative until cleared by an initstate command.            |
2119  +----------------------------------------------------------------------------*/
x10state_update_sticky_addr(unsigned char addrbyte)2120 void x10state_update_sticky_addr ( unsigned char addrbyte )
2121 {
2122    unsigned char hcode, ucode;
2123    unsigned int  bitmap;
2124 
2125    hcode = (addrbyte & 0xf0u) >> 4;
2126    ucode = addrbyte & 0x0fu;
2127    bitmap = 1 << ucode;
2128 
2129    x10state[hcode].sticky |= bitmap;
2130 
2131    return;
2132 }
2133 
2134 /*----------------------------------------------------------------------------+
2135  | Update the RCS temperature storage                                         |
2136  | Argument 'level' is 0-31                                                   |
2137  +----------------------------------------------------------------------------*/
update_rcs_data(unsigned char hcode,int lastunit,unsigned char level)2138 void update_rcs_data ( unsigned char hcode, int lastunit, unsigned char level )
2139 {
2140    if ( (configp->rcs_temperature & (1 << hcode)) && lastunit > 10 ) {
2141       x10state[hcode].rcstemp = -60L + (long)level + 32L * (long)(lastunit - 11);
2142       x10global.rcstemp_flags |= (1 << hcode);
2143    }
2144    return;
2145 }
2146 
2147 /*----------------------------------------------------------------------------+
2148  | Update the flag states by engine.                                                    |
2149  +----------------------------------------------------------------------------*/
engine_update_flags(unsigned char bank,unsigned long flagmap,unsigned char mode)2150 void engine_update_flags ( unsigned char bank, unsigned long flagmap, unsigned char mode )
2151 {
2152    if ( mode == SETFLAG )
2153       x10global.flags[bank] |= flagmap; /*###*/
2154    else
2155       x10global.flags[bank] &= ~flagmap; /*###*/
2156 
2157    return;
2158 }
2159 
2160 /*----------------------------------------------------------------------------+
2161  | Update the flag states.                                                    |
2162  +----------------------------------------------------------------------------*/
update_flags_32(unsigned char * buf)2163 void update_flags_32 ( unsigned char *buf )
2164 {
2165    unsigned long flagmap;
2166 
2167    /* buf[3] = flag bank */
2168    flagmap = ((unsigned long)buf[4] << 24) |
2169              ((unsigned long)buf[5] << 16) |
2170              ((unsigned long)buf[6] << 8)  |
2171               (unsigned long)buf[7];
2172 
2173    engine_update_flags(buf[3], flagmap, buf[2]);
2174 
2175    return;
2176 }
2177 
2178 /*----------------------------------------------------------------------------+
2179  | Update the flag states.                                                    |
2180  +----------------------------------------------------------------------------*/
update_flags(unsigned char * buf)2181 void update_flags ( unsigned char *buf )
2182 {
2183    unsigned long flagmap;
2184 
2185    flagmap = (unsigned long)((buf[3] << 8) | buf[4]);
2186 
2187    engine_update_flags(0, flagmap, buf[2]);
2188 
2189    return;
2190 }
2191 
2192 
2193 /*----------------------------------------------------------------------------+
2194  | Update the mask for units with an exclusive attribute.                     |
2195  +----------------------------------------------------------------------------*/
update_exclusive_mask(unsigned char hcode,unsigned int bitmap,unsigned int * mask)2196 void update_exclusive_mask ( unsigned char hcode,
2197                                         unsigned int bitmap, unsigned int *mask )
2198 {
2199    unsigned int others;
2200 
2201    if ( (others = modmask[Exc4Mask][hcode] & ~bitmap) != 0 ) {
2202       *mask |= ( bitmap & 0x4444u ) ? others & 0x4444u :
2203                ( bitmap & 0x2222u ) ? others & 0x2222u :
2204                ( bitmap & 0x8888u ) ? others & 0x8888u :
2205                ( bitmap & 0x1111u ) ? others & 0x1111u : 0;
2206    }
2207    if ( (others = modmask[Exc8Mask][hcode] & ~bitmap) != 0 ) {
2208       *mask |= ( bitmap & 0x6666u ) ? others & 0x6666u :
2209                ( bitmap & 0x9999u ) ? others & 0x9999u : 0;
2210    }
2211 
2212    *mask |= modmask[Exc16Mask][hcode] & ~bitmap;
2213 
2214    return;
2215 }
2216 
2217 /*----------------------------------------------------------------------------+
2218  | Update the addressed/unaddresssed state of housecode|units                 |
2219  | Addressing is cumulative until reset by an intervening function code with  |
2220  | the same housecode.                                                        |
2221  | An alloff (all_units_off) function unaddresses all units on that housecode.|
2222  +----------------------------------------------------------------------------*/
x10state_update_addr(unsigned char addrbyte,int * launchp)2223 void x10state_update_addr ( unsigned char addrbyte, int *launchp )
2224 {
2225    unsigned char   hcode, ucode;
2226    unsigned int    bitmap, launched;
2227    int             j;
2228    LAUNCHER        *launcherp;
2229    extern unsigned int signal_source;
2230 
2231    launcherp = configp->launcherp;
2232 
2233    hcode = (addrbyte & 0xf0u) >> 4;
2234    ucode = addrbyte & 0x0f;
2235    bitmap = 1 << ucode;
2236 
2237    x10state[hcode].lastunit = code2unit(ucode);
2238 
2239    x10global.lasthc = hcode;
2240 
2241    if ( signal_source & RCVA ) {
2242       x10state[hcode].vaddress = bitmap;
2243    }
2244    else {
2245       x10global.lastaddr = bitmap;
2246 
2247       if ( x10state[hcode].reset ) {
2248          x10state[hcode].addressed = bitmap /* & modmask[AddrMask][hcode] */;
2249          x10state[hcode].reset = 0;
2250          x10state[hcode].exclusive = 0;
2251       }
2252       else {
2253          x10state[hcode].addressed |= bitmap /* & modmask[AddrMask][hcode] */;
2254       }
2255 
2256       update_exclusive_mask(hcode, bitmap, &x10state[hcode].exclusive);
2257 
2258       x10state[hcode].addressed &= ~x10state[hcode].exclusive;
2259 
2260       if ( bitmap & modmask[PlcSensorMask][hcode] && signal_source & RCVI && configp->hide_unchanged == YES ) {
2261          x10state[hcode].squelch = bitmap;
2262       }
2263       x10state[hcode].state[AddrState] = x10state[hcode].addressed;
2264    }
2265 
2266    *launchp = -1;
2267 
2268    if ( configp->script_mode & HEYU_HELPER )
2269       return;
2270 
2271    launched = 0;
2272    j = 0;
2273    while ( launcherp && launcherp[j].line_no > 0 ) {
2274       if ( launcherp[j].type != L_ADDRESS ||
2275            launcherp[j].hcode != hcode ||
2276            is_unmatched_flags(&launcherp[j])  ) {
2277          j++;
2278 	 continue;
2279       }
2280       if ( launcherp[j].bmaptrig & bitmap &&
2281            launcherp[j].source & signal_source ) {
2282          *launchp = j;
2283          launcherp[j].matched = YES;
2284          launcherp[j].actfunc = 0;
2285          launcherp[j].genfunc = 0;
2286          launcherp[j].xfunc = 0;
2287          launcherp[j].level = 0;
2288          launcherp[j].bmaplaunch = bitmap;
2289          launcherp[j].actsource = signal_source;
2290          launched |= bitmap;
2291          if ( launcherp[j].scanmode & FM_BREAK )
2292             break;
2293       }
2294       j++;
2295    }
2296    x10state[hcode].launched = launched;
2297 
2298    return;
2299 }
2300 
2301 #if 0
2302 /*----------------------------------------------------------------------------+
2303  | Update the addressed/unaddresssed state of housecode|units                 |
2304  | Addressing is cumulative until reset by an intervening function code with  |
2305  | the same housecode.                                                        |
2306  | An alloff (all_units_off) function unaddresses all units on that housecode.|
2307  +----------------------------------------------------------------------------*/
2308 void x10state_update_addr ( unsigned char addrbyte, int *launchp )
2309 {
2310    unsigned char   hcode, ucode;
2311    unsigned int    bitmap, launched;
2312    int             j;
2313    LAUNCHER        *launcherp;
2314    extern unsigned int signal_source;
2315 
2316    launcherp = configp->launcherp;
2317 
2318    hcode = (addrbyte & 0xf0u) >> 4;
2319    ucode = addrbyte & 0x0f;
2320    bitmap = 1 << ucode;
2321 
2322    x10state[hcode].lastunit = code2unit(ucode);
2323 
2324    x10global.lasthc = hcode;
2325 
2326    if ( signal_source & RCVA ) {
2327       x10state[hcode].vaddress = bitmap;
2328    }
2329    else {
2330       x10global.lastaddr = bitmap;
2331 
2332       if ( x10state[hcode].reset ) {
2333          x10state[hcode].addressed = bitmap;
2334          x10state[hcode].reset = 0;
2335          x10state[hcode].exclusive = 0;
2336       }
2337       else {
2338          x10state[hcode].addressed |= bitmap;
2339       }
2340 
2341       update_exclusive_mask(hcode, bitmap, &x10state[hcode].exclusive);
2342 
2343       x10state[hcode].addressed &= ~x10state[hcode].exclusive;
2344 
2345       if ( bitmap & modmask[PlcSensorMask][hcode] && signal_source & RCVI && configp->hide_unchanged == YES ) {
2346          x10state[hcode].squelch = bitmap;
2347       }
2348       x10state[hcode].state[AddrState] = x10state[hcode].addressed;
2349    }
2350 
2351    *launchp = -1;
2352 
2353    if ( configp->script_mode & HEYU_HELPER )
2354       return;
2355 
2356    launched = 0;
2357    j = 0;
2358    while ( launcherp && launcherp[j].line_no > 0 ) {
2359       if ( launcherp[j].type != L_ADDRESS ||
2360            launcherp[j].hcode != hcode ||
2361            is_unmatched_flags(&launcherp[j])  ) {
2362          j++;
2363 	 continue;
2364       }
2365       if ( launcherp[j].bmaptrig & bitmap &&
2366            launcherp[j].source & signal_source ) {
2367          *launchp = j;
2368          launcherp[j].matched = YES;
2369          launcherp[j].actfunc = 0;
2370          launcherp[j].genfunc = 0;
2371          launcherp[j].xfunc = 0;
2372          launcherp[j].level = 0;
2373          launcherp[j].bmaplaunch = bitmap;
2374          launcherp[j].actsource = signal_source;
2375          launched |= bitmap;
2376          if ( launcherp[j].scanmode & FM_BREAK )
2377             break;
2378       }
2379       j++;
2380    }
2381    x10state[hcode].launched = launched;
2382 
2383    return;
2384 }
2385 #endif
2386 
2387 /*----------------------------------------------------------------------------+
2388  | Update the x10state structure per the contents of the argument 'buf'       |
2389  | buf[0] is the housecode|function byte, buf[1] is the dim level 1-210 for   |
2390  | dims and brights.  (This routine handles just the standard X10 functions - |
2391  | Type 3 Extended code functions are handled separately.)                    |
2392  |                                                                            |
2393  | If the user has defined the type of module, e.g. lamp module, for a        |
2394  | specific housecode|unit address, the change of state for that address      |
2395  | is filtered by the supported features of that type of module, e.g. a dim   |
2396  | signal will be ignored for appliance modules.                              |
2397  |                                                                            |
2398  | The received signal and state are tested to see if any of the conditions   |
2399  | exist for triggering the launching of an external script, and if so, the   |
2400  | index of the launcher is passed back through argument 'launchp',           |
2401  | otherwise -1 is passed back.                                               |
2402  +----------------------------------------------------------------------------*/
x10state_update_func(unsigned char * buf,int * launchp)2403 void x10state_update_func ( unsigned char *buf, int *launchp )
2404 {
2405    unsigned char hcode, func, level, rawdim, lasthc;
2406    unsigned char actfunc, genfunc;
2407    unsigned int  lastaddr, addressed;
2408    unsigned int  trigaddr, active = 0, mask, trigactive, inactive;
2409    unsigned int  resumask, fullmask, fulloffmask, applmask, bbdimask, ext3dimask, lofmask, ext0mask;
2410    unsigned int  lubmap, exclusmask;
2411    unsigned int  bmaplaunch, launched;
2412    unsigned int  onstate, dimstate, changestate, startupstate;
2413    unsigned long afuncmap, gfuncmap;
2414    int           j, dims;
2415    LAUNCHER      *launcherp;
2416    extern unsigned int signal_source;
2417    int update_plcsensor_timeout ( unsigned char, unsigned int );
2418 
2419    launcherp = configp->launcherp;
2420 
2421    *launchp = -1;
2422 
2423    if ( !(i_am_state || i_am_monitor) )
2424       return;
2425 
2426    func = buf[0] & 0x0fu;
2427    hcode = (buf[0] & 0xf0u) >> 4;
2428    genfunc = actfunc = func;
2429    rawdim = 0;
2430 
2431    x10state[hcode].reset = 1;
2432 
2433    lasthc = x10global.lasthc;
2434 
2435    /* Preset1/Preset2 functions take special handling */
2436    if ( func == 10 || func == 11 ) {
2437       level = hcode;
2438       hcode = x10global.lasthc;
2439       x10global.lasthc = level;
2440       /* Use zero-base level (0-31) here */
2441       level = rev_low_nybble(level) + 16 * (func - 10);
2442    }
2443    else {
2444       x10global.lasthc = hcode;
2445       level = 0;
2446    }
2447 
2448    if ( hcode == lasthc && x10global.lastaddr )
2449       lastaddr = x10global.lastaddr;
2450    else
2451       lastaddr = 0xffff;
2452 
2453    x10global.lastaddr = 0;
2454 
2455    gfuncmap = 0;
2456    mask = 0;
2457    lubmap = 1 << unit2code(x10state[hcode].lastunit);
2458 //   x10state[hcode].state[ChgState] = 0;
2459    changestate = 0;
2460    x10state[hcode].launched = 0;
2461 
2462    addressed = (signal_source & RCVA) ?
2463             x10state[hcode].vaddress : x10state[hcode].addressed;
2464 
2465    trigaddr = addressed;
2466 
2467    switch ( func ) {
2468       case  0 :  /* AllOff */
2469          /* state = OffState; */
2470          afuncmap = (1 << AllOffTrig);
2471          gfuncmap = (1 << OffTrig);
2472          genfunc = OffFunc;
2473          mask = modmask[AllOffMask][hcode];
2474          trigaddr = 0xffff;
2475          lastaddr = 0xffff;
2476          onstate = x10state[hcode].state[OnState];
2477          active = modmask[AllOffMask][hcode];
2478          resumask = (modmask[ResumeMask][hcode] | modmask[ResumeDimMask][hcode]) & modmask[Ext3DimMask][hcode];
2479          lofmask = modmask[PresetMask][hcode] &
2480                    modmask[LightsOnFullMask][hcode] &
2481                    x10state[hcode].state[LightsOnState];
2482          save_dimlevel(hcode, active & resumask & ~lofmask);
2483          set_dimlevel(0, hcode, active);
2484          get_states(hcode, &onstate, &dimstate);
2485 //         x10state[hcode].state[ChgState] = active &
2486          changestate = active &
2487            ((x10state[hcode].state[OnState] ^ onstate) |
2488             (x10state[hcode].state[DimState] ^ dimstate));
2489          if ( signal_source & RCVA )
2490             x10state[hcode].vaddress &= ~(modmask[AllOffMask][hcode] | modmask[VdataMask][hcode]);
2491          else
2492             x10state[hcode].addressed &= ~(modmask[AllOffMask][hcode] | modmask[VdataMask][hcode]);
2493          x10state[hcode].state[OnState] = onstate;
2494          x10state[hcode].state[DimState] = dimstate;
2495          x10state[hcode].state[LightsOnState] &= ~active;
2496          break;
2497       case  1 :  /* LightsOn */
2498          /* state = OnState; */
2499          afuncmap = (1 << LightsOnTrig);
2500          gfuncmap = (1 << OnTrig);
2501          genfunc = OnFunc;
2502          mask = modmask[LightsOnMask][hcode];
2503          trigaddr = 0xffff;
2504          lastaddr = 0xffff;
2505          resumask = modmask[ResumeMask][hcode];
2506          fullmask = modmask[LightsOnFullMask][hcode];
2507          onstate = x10state[hcode].state[OnState];
2508          active = modmask[LightsOnMask][hcode];
2509          /* Units which resume saved brightness */
2510          restore_dimlevel(hcode, active & resumask);
2511          /* Units which go to 'On' level */
2512          set_on_level(hcode, active & ~resumask & ~fullmask & modmask[OnFullMask][hcode]);
2513          /* Units which go to full brightness */
2514          set_max_level(hcode, active &
2515            (fullmask | (~onstate & modmask[OnFullOffMask][hcode]) | modmask[TargMask][hcode]));
2516          get_states(hcode, &onstate, &dimstate);
2517 //         x10state[hcode].state[ChgState] = active &
2518          changestate = active &
2519            ((x10state[hcode].state[OnState] ^ onstate) |
2520             (x10state[hcode].state[DimState] ^ dimstate));
2521          if ( signal_source & RCVA ) {
2522             x10state[hcode].vaddress &=
2523                ~(modmask[LightsOnUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2524 	 }
2525          else {
2526             x10state[hcode].addressed &=
2527                ~(modmask[LightsOnUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2528 	 }
2529          x10state[hcode].state[OnState] = onstate;
2530          x10state[hcode].state[DimState] = dimstate;
2531          x10state[hcode].state[LightsOnState] |= active;
2532          break;
2533       case  2 :  /* On */
2534          /* state = OnState; */
2535          afuncmap = gfuncmap = (1 << OnTrig);
2536          if ( addressed == 0xffff ) {
2537             afuncmap = (1 << AllOnTrig);
2538          }
2539          mask = modmask[OnMask][hcode];
2540          onstate = x10state[hcode].state[OnState];
2541          resumask = modmask[ResumeMask][hcode];
2542          fullmask = modmask[OnFullMask][hcode];
2543          fulloffmask = modmask[OnFullOffMask][hcode];
2544          applmask = ~(modmask[DimMask][hcode] | modmask[BriMask][hcode]);
2545          exclusmask = x10state[hcode].exclusive;
2546          active = addressed & modmask[OnMask][hcode] & ~modmask[DeferMask][hcode];
2547          /* Resume-enabled units will go to saved brightness */
2548          restore_dimlevel(hcode, active & resumask);
2549          /* Modules which go to 'On' brightness */
2550          set_on_level(hcode, active & ~resumask & (~onstate | modmask[TargMask][hcode]));
2551 	 /* Exclusive modules which turn Off */
2552          set_dimlevel(0, hcode, exclusmask);
2553          save_dimlevel(hcode, active & resumask);
2554          get_states(hcode, &onstate, &dimstate);
2555 //         x10state[hcode].state[ChgState] =  /* active & */
2556          changestate = active &
2557            ((x10state[hcode].state[OnState] ^ onstate) |
2558             (x10state[hcode].state[DimState] ^ dimstate));
2559 
2560          if ( signal_source & RCVA ) {
2561             x10state[hcode].vaddress &=
2562                ~(modmask[OnOffUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2563 	 }
2564          else {
2565             x10state[hcode].addressed &=
2566                ~(modmask[OnOffUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2567 	 }
2568 
2569          x10state[hcode].state[OnState] = onstate;
2570          x10state[hcode].state[DimState] = dimstate;
2571          x10state[hcode].state[LightsOnState] &= ~active;
2572          if ( x10state[hcode].xconfigmode & 0x02u ) {
2573             x10state[hcode].state[SpendState] |= (active & modmask[Ext3StatusMask][hcode]);
2574          }
2575 
2576          break;
2577       case  3 :  /* Off */
2578          /* state = OffState; */
2579          afuncmap = gfuncmap = (1 << OffTrig);
2580          mask = modmask[OffMask][hcode];
2581          onstate = x10state[hcode].state[OnState];
2582          active = addressed & modmask[OffMask][hcode] & ~modmask[DeferMask][hcode];
2583          resumask = modmask[ResumeMask][hcode] | modmask[ResumeDimMask][hcode];
2584          ext0mask = modmask[ResumeMask][hcode];
2585          lofmask = modmask[PresetMask][hcode] &
2586                    modmask[LightsOnFullMask][hcode] &
2587                    x10state[hcode].state[LightsOnState];
2588          save_dimlevel(hcode, active & resumask & ~lofmask & ~ext0mask);
2589          set_dimlevel(0, hcode, active);
2590          get_states(hcode, &onstate, &dimstate);
2591 //         x10state[hcode].state[ChgState] = active &
2592          changestate = active &
2593            ((x10state[hcode].state[OnState] ^ onstate) |
2594             (x10state[hcode].state[DimState] ^ dimstate));
2595 
2596          if ( signal_source & RCVA ) {
2597             x10state[hcode].vaddress &=
2598                ~(modmask[OnOffUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2599 	 }
2600          else {
2601             x10state[hcode].addressed &=
2602                ~(modmask[OnOffUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2603 	 }
2604 
2605          x10state[hcode].state[OnState]  = onstate;
2606          x10state[hcode].state[DimState] = dimstate;
2607          x10state[hcode].state[LightsOnState] &= ~active;
2608          if ( x10state[hcode].xconfigmode & 0x02u ) {
2609             x10state[hcode].state[SpendState] |= (active & modmask[Ext3StatusMask][hcode]);
2610          }
2611          break;
2612       case  4 :  /* Dim */
2613          /* state = DimState; */
2614          afuncmap = gfuncmap = (1 << DimTrig);
2615          genfunc = DimFunc;
2616          mask = modmask[DimMask][hcode];
2617          onstate = x10state[hcode].state[OnState];
2618 	 rawdim = buf[1];
2619          dims = -(int)rawdim;
2620          active = addressed & modmask[DimMask][hcode];
2621          bbdimask = modmask[BriDimMask][hcode];
2622          resumask = modmask[ResumeDimMask][hcode];
2623          ext3dimask = modmask[Ext3DimMask][hcode];
2624          inactive = ext3dimask & ~(bbdimask | resumask) & ~onstate;
2625          /* Off resume-enabled units will first go to saved brightness */
2626          restore_dimlevel(hcode, active & resumask & ~onstate & ext3dimask);
2627          /* Modules which first go to full brightness if Off */
2628          set_max_level(hcode, active & bbdimask & ~onstate);
2629          update_dimlevel(dims, hcode, active & ~inactive);
2630          lofmask = modmask[PresetMask][hcode] &
2631                    modmask[LightsOnFullMask][hcode] &
2632                    x10state[hcode].state[LightsOnState];
2633          save_dimlevel(hcode, active & resumask & ~lofmask);
2634          get_states(hcode, &onstate, &dimstate);
2635 //         x10state[hcode].state[ChgState] = active &
2636          changestate = active &
2637            ((x10state[hcode].state[OnState] ^ onstate) |
2638             (x10state[hcode].state[DimState] ^ dimstate));
2639          x10state[hcode].state[OnState]  = onstate;
2640          x10state[hcode].state[DimState] = dimstate;
2641          x10state[hcode].state[LightsOnState] &= ~active;
2642          if ( x10state[hcode].xconfigmode & 0x02u ) {
2643             x10state[hcode].state[SpendState] |= (active & modmask[Ext3StatusMask][hcode]);
2644          }
2645          break;
2646       case  5 :  /* Bright */
2647          /* state = DimState; */
2648          afuncmap = (1 << BriTrig);
2649          gfuncmap = (1 << DimTrig);
2650          genfunc = DimFunc;
2651          mask = modmask[BriMask][hcode];
2652 	 rawdim = buf[1];
2653          dims = (int)rawdim;
2654          active = addressed & modmask[BriMask][hcode];
2655          onstate = x10state[hcode].state[OnState];
2656          bbdimask = modmask[BriDimMask][hcode];
2657          resumask = modmask[ResumeDimMask][hcode];
2658          ext3dimask = modmask[Ext3DimMask][hcode];
2659          inactive = ext3dimask & ~(bbdimask | resumask) & ~onstate;
2660          /* Off, resume-enabled units will first go to saved brightness */
2661          restore_dimlevel(hcode, active & resumask & ~onstate);
2662          /* Modules which first go to full brightness if Off */
2663          set_max_level(hcode, active & bbdimask & ~onstate);
2664          update_dimlevel(dims, hcode, active & ~inactive);
2665          lofmask = modmask[PresetMask][hcode] &
2666                    modmask[LightsOnFullMask][hcode] &
2667                    x10state[hcode].state[LightsOnState];
2668          save_dimlevel(hcode, active & resumask & ~lofmask);
2669          get_states(hcode, &onstate, &dimstate);
2670 //         x10state[hcode].state[ChgState] = active &
2671          changestate = active &
2672            ((x10state[hcode].state[OnState] ^ onstate) |
2673             (x10state[hcode].state[DimState] ^ dimstate));
2674          x10state[hcode].state[OnState]  = onstate;
2675          x10state[hcode].state[DimState] = dimstate;
2676          x10state[hcode].state[LightsOnState] &= ~active;
2677          if ( x10state[hcode].xconfigmode & 0x02u ) {
2678             x10state[hcode].state[SpendState] |= (active & modmask[Ext3StatusMask][hcode]);
2679          }
2680          break;
2681       case  6 : /* LightsOff */
2682          /* state = OffState; */
2683          afuncmap = (1 << LightsOffTrig);
2684          gfuncmap = (1 << OffTrig);
2685          genfunc = OffFunc;
2686          mask = modmask[LightsOffMask][hcode];
2687          trigaddr = 0xffff;
2688          lastaddr = 0xffff;
2689          onstate = x10state[hcode].state[OnState];
2690          active = modmask[LightsOffMask][hcode];
2691          resumask = modmask[ResumeMask][hcode] | modmask[ResumeDimMask][hcode];
2692          lofmask = modmask[PresetMask][hcode] &
2693                    modmask[LightsOnFullMask][hcode] &
2694                    x10state[hcode].state[LightsOnState];
2695          save_dimlevel(hcode, active & resumask & ~lofmask);
2696          set_dimlevel(0, hcode, active);
2697          get_states(hcode, &onstate, &dimstate);
2698 //         x10state[hcode].state[ChgState] = active &
2699          changestate = active &
2700            ((x10state[hcode].state[OnState] ^ onstate) |
2701             (x10state[hcode].state[DimState] ^ dimstate));
2702          if ( signal_source & RCVA ) {
2703             x10state[hcode].vaddress &=
2704                ~(modmask[LightsOffUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2705 	 }
2706          else {
2707             x10state[hcode].addressed &=
2708                ~(modmask[LightsOffUnaddrMask][hcode] | modmask[VdataMask][hcode]);
2709 	 }
2710          x10state[hcode].state[OnState]  = onstate;
2711          x10state[hcode].state[DimState] = dimstate;
2712          x10state[hcode].state[LightsOnState] &= ~active;
2713          break;
2714       case 10 :  /* Preset1 */
2715       case 11 :  /* Preset2 */
2716          if ( hcode == 0xff ) {
2717             /* Housecode unknown - can't do anything */
2718             return;
2719          }
2720          if ( signal_source & RCVI ) {
2721             update_rcs_data(hcode, x10state[hcode].lastunit, level);
2722          }
2723          onstate = x10state[hcode].state[OnState];
2724          dimstate = x10state[hcode].state[DimState];
2725          mask = modmask[PresetMask][hcode];
2726          active = addressed & modmask[PresetMask][hcode];
2727          resumask = modmask[ResumeMask][hcode];
2728          afuncmap = (1 << PresetTrig);
2729          if ( level == 0 ) {
2730             /* Lowest level => Off */
2731             /* state = OffState; */
2732             gfuncmap = (1 << OffTrig);
2733             genfunc = OffFunc;
2734             save_dimlevel(hcode, active & resumask);
2735             set_dimlevel(0, hcode, active);
2736             get_states(hcode, &onstate, &dimstate);
2737 //            x10state[hcode].state[ChgState] = active &
2738             changestate = active &
2739               ((x10state[hcode].state[OnState] ^ onstate) |
2740                (x10state[hcode].state[DimState] ^ dimstate));
2741             x10state[hcode].state[OnState]  = onstate;
2742             x10state[hcode].state[DimState] = dimstate;
2743          }
2744          else if ( level == 31 ) {
2745             /* Highest level => On */
2746             /* state = OnState; */
2747             gfuncmap = (1 << OnTrig);
2748             genfunc = OnFunc;
2749             set_dimlevel(31, hcode, active);
2750             save_dimlevel(hcode, active & resumask);
2751             get_states(hcode, &onstate, &dimstate);
2752 //            x10state[hcode].state[ChgState] = active &
2753             changestate = active &
2754               ((x10state[hcode].state[OnState] ^ onstate) |
2755                (x10state[hcode].state[DimState] ^ dimstate));
2756             x10state[hcode].state[OnState]  = onstate;
2757             x10state[hcode].state[DimState] = dimstate;
2758          }
2759          else {
2760             /* Intermediate level => Dim */
2761             /* state = DimState; */
2762             gfuncmap = (1 << DimTrig);
2763             genfunc = DimFunc;
2764             set_dimlevel(level, hcode, active);
2765             save_dimlevel(hcode, active & resumask);
2766             get_states(hcode, &onstate, &dimstate);
2767 //            x10state[hcode].state[ChgState] = active &
2768             changestate = active &
2769               ((x10state[hcode].state[OnState] ^ onstate) |
2770                (x10state[hcode].state[DimState] ^ dimstate));
2771             x10state[hcode].state[OnState]  = onstate;
2772             x10state[hcode].state[DimState] = dimstate;
2773          }
2774          x10state[hcode].state[LightsOnState] &= ~active;
2775 
2776          /* Preset modules unaddress themselves after receiving a preset function */
2777          /* (otherwise they'd be affected by the next non-Preset function on the  */
2778          /* same housecode), but not if they've _sent_ the preset in response to  */
2779          /* a status request.                                                     */
2780          if ( !(x10state[hcode].lastcmd == StatusReqFunc && signal_source & RCVI) )
2781             x10state[hcode].addressed &= ~active;
2782 
2783          break;
2784       case 13 :  /* Status On - limited to the last received unit address */
2785          /* state = OnState; */
2786          afuncmap = (1 << StatusOnTrig);
2787          if ( !(signal_source & RCVI) ) {
2788             active = 0;
2789             break;
2790          }
2791          mask = modmask[StatusOnMask][hcode];
2792 //         active = addressed & modmask[StatusOnMask][hcode];
2793          active = addressed & modmask[StatusOnMask][hcode] & lubmap;
2794          onstate = x10state[hcode].state[OnState];
2795          set_on_level(hcode, active & ~onstate);
2796          get_states(hcode, &onstate, &dimstate);
2797 //         x10state[hcode].state[ChgState] = active &
2798          changestate = active &
2799            ((x10state[hcode].state[OnState] ^ onstate) |
2800             (x10state[hcode].state[DimState] ^ dimstate));
2801          x10state[hcode].state[OnState]  = onstate;
2802          x10state[hcode].state[DimState] = dimstate;
2803          x10state[hcode].state[LightsOnState] &= ~active;
2804 //         x10state[hcode].state[SpendState] &= ~addressed;
2805          x10state[hcode].state[SpendState] &= ~active;
2806          break;
2807       case 14 :  /* Status Off - limited to the last received unit address */
2808          /* state = OffState; */
2809          afuncmap = (1 << StatusOffTrig);
2810          gfuncmap = 0;
2811          if ( !(signal_source & RCVI) ) {
2812             active = 0;
2813             break;
2814          }
2815          mask = modmask[StatusOffMask][hcode];
2816 //         active = addressed & modmask[StatusOffMask][hcode];
2817          active = addressed & modmask[StatusOffMask][hcode] & lubmap;
2818          onstate = x10state[hcode].state[OnState];
2819          dimstate = x10state[hcode].state[DimState];
2820          x10state[hcode].state[OnState]  &= ~active;
2821          x10state[hcode].state[DimState] &= ~active;
2822          set_dimlevel(0, hcode, active);
2823 //         x10state[hcode].state[ChgState] = active &
2824          changestate = active &
2825            ((x10state[hcode].state[OnState] ^ onstate) |
2826             (x10state[hcode].state[DimState] ^ dimstate));
2827          x10state[hcode].state[LightsOnState] &= ~active;
2828 //         x10state[hcode].state[SpendState] &= ~addressed;
2829          x10state[hcode].state[SpendState] &= ~active;
2830          break;
2831       case 15 : /* StatusReq */
2832          afuncmap = (1 << StatusReqTrig);
2833          active = addressed & modmask[StatusMask][hcode];
2834          x10state[hcode].state[SpendState] |= addressed;
2835          break;
2836       case 8 :  /* HailReq */
2837          if ( (signal_source & RCVI) == 0 )
2838             x10global.hailstate = 0;
2839          afuncmap = (1 << HailReqTrig);
2840          active = 0;
2841          break;
2842       case 9 :  /* Hail Ack */
2843          if ( signal_source & RCVI )
2844             x10global.hailstate |= (1 << hcode);
2845          afuncmap = (1 << HailAckTrig);
2846          active = 0;
2847          break;
2848       case 12 : /* Data Xfer */
2849          afuncmap = (1 << DataXferTrig);
2850          active = 0;
2851          break;
2852       default :
2853          /* state = OffState; */
2854          afuncmap = 0;
2855          mask = 0;
2856          trigaddr = 0;
2857          active = 0;
2858          break;
2859    }
2860 
2861    x10state[hcode].lastcmd = func;
2862 
2863    for ( j = 0; j < 16; j++ ) {
2864       if ( (addressed & vmodmask[VtstampMask][hcode]) & (1 << j) ) {
2865          x10state[hcode].timestamp[j] = time(NULL);
2866       }
2867    }
2868 
2869    startupstate = ~x10state[hcode].state[ValidState] & active;
2870    x10state[hcode].state[ValidState] |= active;
2871 
2872    if ( signal_source & RCVI && lubmap & modmask[PlcSensorMask][hcode] ) {
2873       update_plcsensor_timeout(hcode, lubmap);
2874       update_activity_states(hcode, lubmap, S_ACTIVE);
2875    }
2876 
2877 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
2878    x10state[hcode].state[ModChgState] = changestate;
2879 
2880    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
2881       (x10state[hcode].state[ActiveChgState] & active) |
2882       (startupstate & ~modmask[PhysMask][hcode]);
2883 
2884    changestate = x10state[hcode].state[ChgState];
2885 
2886    if ( signal_source & RCVI ) {
2887       x10state[hcode].lastactive = active;
2888    }
2889 
2890    if ( i_am_state )
2891       write_x10state_file();
2892 
2893    /* Heyuhelper, if applicable */
2894    if ( signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
2895       launch_heyuhelper(hcode, trigaddr, func);
2896       return;
2897    }
2898 
2899    bmaplaunch = 0;
2900    launched = 0;
2901    j = 0;
2902    while ( launcherp && launcherp[j].line_no > 0 ) {
2903       if ( launcherp[j].type != L_NORMAL ||
2904            launcherp[j].hcode != hcode ||
2905            is_unmatched_flags(&launcherp[j]) ||
2906            launcherp[j].vflags || launcherp[j].notvflags ||
2907            !(launcherp[j].bmaptrigemu & lastaddr) ) {
2908          j++;
2909 	 continue;
2910       }
2911 
2912       if ( (launcherp[j].afuncmap & afuncmap || launcherp[j].gfuncmap & gfuncmap)  &&
2913            launcherp[j].source & signal_source ) {
2914          trigactive = trigaddr & (mask | launcherp[j].signal);
2915 
2916          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
2917 #if 0
2918                    (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ||
2919 #endif
2920                    (changestate | ~launcherp[j].chgtrig)) ||
2921                    (launcherp[j].unitstar && !trigaddr) ) {
2922             *launchp = j;
2923             launcherp[j].matched = YES;
2924             launcherp[j].bmaplaunch = bmaplaunch;
2925             launcherp[j].actfunc = func;
2926             launcherp[j].genfunc = genfunc;
2927 	    launcherp[j].level = level + 1;  /* preset 1-32 */
2928 	    launcherp[j].rawdim = rawdim;
2929             launcherp[j].actsource = signal_source;
2930             launched |= bmaplaunch;
2931             if ( launcherp[j].scanmode & FM_BREAK )
2932                break;
2933          }
2934       }
2935       j++;
2936    }
2937    x10state[hcode].launched = launched;
2938 
2939    return;
2940 }
2941 
2942 /*----------------------------------------------------------------------------+
2943  | Update the x10state structure per the contents of the argument 'buf'       |
2944  | for type 3 extended codes.  'buf' will always contain 4 bytes.             |
2945  | Supported Type/Functions are limited to 0x31, 0x33, 0x34, and 0x38.        |
2946  |                                                                            |
2947  | If the user has defined the type of module, e.g. lamp module, for a        |
2948  | specific housecode|unit address, the change of state for that address      |
2949  | is filtered by the supported features of that type of module, e.g. an      |
2950  | extended preset dim signal will be ignored for appliance modules.          |
2951  |                                                                            |
2952  | The received signal and state are tested to see if any of the conditions   |
2953  | exist for triggering the launching of an external script, and if so, the   |
2954  | index of the launcher is passed back through argument 'launchp',           |
2955  | otherwise -1 is passed back.                                               |
2956  +----------------------------------------------------------------------------*/
x10state_update_ext3func(unsigned char * buf,int * launchp)2957 void x10state_update_ext3func ( unsigned char *buf, int *launchp )
2958 {
2959    unsigned char hcode, func, xfunc, xdata, ucode, subunit, level, grpbmap, group, subgroup;
2960    unsigned char grplevel;
2961    int      oldlevel, memlevel;
2962    unsigned char actfunc, genfunc;
2963    unsigned int  bitmap, trigaddr, mask, grpmask, active = 0, trigactive, switchmask;
2964    unsigned int  onstate, dimstate, changestate, startupstate;
2965    unsigned int  bmaplaunch, launched;
2966    unsigned long afuncmap, gfuncmap;
2967    int           j;
2968    LAUNCHER      *launcherp;
2969    extern unsigned int signal_source;
2970 
2971    launcherp = configp->launcherp;
2972 
2973    *launchp = -1;
2974 
2975    if ( !(i_am_state || i_am_monitor) )
2976       return;
2977 
2978    func = buf[0] & 0x0f;
2979    if ( func != 7 )
2980       return;
2981    actfunc = genfunc = func;
2982    afuncmap = gfuncmap = (1 << ExtendedTrig);
2983 
2984    hcode = (buf[0] & 0xf0u) >> 4;
2985    ucode = buf[1] & 0x0fu;
2986 
2987    subunit = (buf[1] & 0xf0u) >> 4;
2988    /* Subunit states are not supported */
2989    if ( subunit > 0 )
2990       return;
2991 
2992    xdata = buf[2];
2993    level = xdata & 0x3f;
2994    xfunc = buf[3];
2995    bitmap = 1 << ucode;
2996    trigaddr = bitmap;
2997 
2998    x10state[hcode].lastcmd = func;
2999 //   x10state[hcode].state[ChgState] = 0;
3000    changestate = 0;
3001    x10state[hcode].lastunit = code2unit(ucode);
3002    x10global.lasthc = hcode;
3003 
3004    x10state[hcode].reset = 1;
3005 
3006    x10global.lastaddr = 0;
3007 
3008    onstate = x10state[hcode].state[OnState];
3009    dimstate = x10state[hcode].state[DimState];
3010    switchmask = modmask[Ext3Mask][hcode] & ~modmask[Ext3DimMask][hcode];
3011 
3012    switch ( xfunc ) {
3013       case 0x30 :  /* Include in group at current level */
3014          mask = 0;
3015          gfuncmap = 0;
3016          genfunc = 0;
3017          if ( (bitmap & modmask[Ext3GrpExecMask][hcode]) == 0 )
3018             break;
3019          group = (xdata & 0xc0u) >> 6;
3020          x10state[hcode].grpmember[ucode] |= (1 << group);
3021 
3022          grplevel = x10state[hcode].dimlevel[ucode];
3023          x10state[hcode].grplevel[ucode][group] = grplevel;
3024 
3025          if ( xdata & 0x20u ) {
3026             subgroup = xdata & 0x0fu;
3027             if ( grplevel == 63 && (modmask[Ext3DimMask][hcode] & bitmap) )
3028                x10state[hcode].grplevel[ucode][group] = 62;
3029 
3030             if ( modmask[Ext3GrpRelT1Mask][hcode] & bitmap ) {
3031                /* LM14A - All groups changed to subgroup */
3032                x10state[hcode].grpaddr[ucode] = subgroup | 0x80u;
3033                x10state[hcode].grpmember[ucode] &= ~(0x80u);
3034             }
3035             else if ( modmask[Ext3GrpRelT2Mask][hcode] & bitmap ) {
3036                /* LM465-1 change to a different subgroup removes other groups */
3037                if ( x10state[hcode].grpaddr[ucode] != (subgroup | 0x80u) ) {
3038                   x10state[hcode].grpmember[ucode] &= (1 << group);
3039                }
3040                x10state[hcode].grpaddr[ucode] = subgroup | 0x80u;
3041                x10state[hcode].grpmember[ucode] &= ~(0x80u);
3042             }
3043             else if ( modmask[Ext3GrpRelT3Mask][hcode] & bitmap ) {
3044                /* WS467-1 is in both absolute and relative groups */
3045                x10state[hcode].grpaddr[ucode] = subgroup | 0x80u;
3046                x10state[hcode].grpmember[ucode] |= 0x80u;
3047             }
3048          }
3049          else {
3050             x10state[hcode].grpaddr[ucode] = 0;
3051          }
3052          break;
3053       case 0x31 :  /* Ext Preset */
3054          if ( level > 0 && (switchmask & bitmap) ) {
3055             gfuncmap = (1 << OnTrig);
3056             genfunc = OnFunc;
3057             mask = modmask[Ext3Mask][hcode];
3058             active = bitmap & mask;
3059 //            x10state[hcode].state[ChgState] = ~x10state[hcode].state[OnState] & active;
3060             changestate = ~x10state[hcode].state[OnState] & active;
3061             x10state[hcode].state[OnState] |= active;
3062             x10state[hcode].state[DimState] &= active;
3063             set_dimlevel(63, hcode, active);
3064             save_dimlevel(hcode, active);
3065          }
3066          else if ( level >= 62 ) {
3067             /* Full On is level 62 or 63 */
3068             gfuncmap = (1 << OnTrig);
3069             genfunc = OnFunc; /* On function */
3070             mask = modmask[Ext3DimMask][hcode];
3071             active = bitmap & mask;
3072 //            x10state[hcode].state[ChgState] =
3073             changestate =
3074                (~x10state[hcode].state[OnState] | x10state[hcode].state[DimState]) & active;
3075             x10state[hcode].state[OnState] |= active;
3076             x10state[hcode].state[DimState] &= ~active;
3077             set_dimlevel(62, hcode, active);
3078             save_dimlevel(hcode, active);
3079          }
3080          else if ( level == 0 ) {
3081             /* Level 0 is Off */
3082             gfuncmap = (1 << OffTrig);
3083             genfunc = OffFunc;
3084             mask = modmask[Ext3Mask][hcode];
3085             active = bitmap & mask;
3086 //            x10state[hcode].state[ChgState] =
3087             changestate =
3088               (x10state[hcode].state[OnState] | x10state[hcode].state[DimState]) & active;
3089             x10state[hcode].state[OnState] &= ~active;
3090             x10state[hcode].state[DimState] &= ~active;
3091             save_dimlevel(hcode, active);
3092             set_dimlevel(0, hcode, active);
3093          }
3094          else {
3095             /* state = DimState; */
3096             gfuncmap = (1 << DimTrig);
3097             genfunc = DimFunc;
3098             mask = modmask[Ext3DimMask][hcode];
3099             active = bitmap & mask;
3100 //            x10state[hcode].state[ChgState] = active &
3101             changestate = active &
3102               ~x10state[hcode].state[DimState];
3103             x10state[hcode].state[OnState] |= active;
3104             x10state[hcode].state[DimState] |= active;
3105             set_dimlevel(level, hcode, active);
3106             save_dimlevel(hcode, active);
3107          }
3108          if ( x10state[hcode].xconfigmode & 0x01u ) {
3109             x10state[hcode].state[SpendState] |= (bitmap & modmask[Ext3StatusMask][hcode]);
3110          }
3111          break;
3112       case 0x32 : /* Include in Group at specified level */
3113          mask = 0;
3114          gfuncmap = 0;
3115          genfunc = 0;
3116          group = (xdata & 0xc0u) >> 6;
3117          grplevel = xdata & 0x3fu;
3118          if ( grplevel > 0 && (switchmask & bitmap) ) {
3119             grplevel = 63;
3120          }
3121          x10state[hcode].grpmember[ucode] |= (1 << group);
3122          x10state[hcode].grplevel[ucode][group] = grplevel;
3123          x10state[hcode].grpaddr[ucode] = 0;
3124          break;
3125       case 0x33 : /* Ext AllOn */
3126          gfuncmap = (1 << OnTrig);
3127          genfunc = OnFunc;
3128          mask = modmask[Ext3Mask][hcode];
3129          trigaddr = 0xffff;
3130          active = modmask[Ext3Mask][hcode];
3131 //         x10state[hcode].state[ChgState] = active &
3132          changestate = active &
3133             (~x10state[hcode].state[OnState] | x10state[hcode].state[DimState]);
3134          x10state[hcode].state[OnState] |= active;
3135          x10state[hcode].state[DimState] &= ~active;
3136          /* Ext AllOn sets full brightness regardless of previous dim level */
3137          set_dimlevel(62, hcode, active);
3138          save_dimlevel(hcode, active);
3139          break;
3140       case 0x34 : /* Ext AllOff */
3141          gfuncmap = (1 << OffTrig);
3142          genfunc = OffFunc;
3143          mask = modmask[Ext3Mask][hcode];
3144          trigaddr = 0xffff;
3145          active = modmask[Ext3Mask][hcode];
3146 //         x10state[hcode].state[ChgState] = active &
3147          changestate = active &
3148             (x10state[hcode].state[OnState] | x10state[hcode].state[DimState]);
3149          x10state[hcode].state[OnState] &= ~active;
3150          x10state[hcode].state[DimState] &= ~active;
3151          /* Does not set the module "memory" level to 0 */
3152          save_dimlevel(hcode, active & modmask[Ext3DimMask][hcode]);
3153          set_dimlevel(0, hcode, active);
3154          break;
3155       case 0x35 : /* Remove Housecode|Unit from groups */
3156          mask = 0;
3157          gfuncmap = 0;
3158          genfunc = 0;
3159          grpbmap = xdata & 0x0fu;
3160          if ( (xdata & 0xf0u ) == 0 ) {
3161             if ( modmask[Ext3GrpRemMask][hcode] & (1 << ucode) )
3162                x10state[hcode].grpmember[ucode] &= ~grpbmap;
3163          }
3164          else {
3165             for ( j = 0; j < 16; j++ ) {
3166                if ( modmask[Ext3GrpRemMask][hcode] & (1 << j) )
3167                   x10state[hcode].grpmember[j] &= ~grpbmap;
3168             }
3169          }
3170          break;
3171       case 0x3c : /* Group Bright/Dim (one level) */
3172       case 0x36 : /* Execute Group function */
3173          mask = 0;
3174          gfuncmap = 0;
3175          genfunc = 0;
3176          trigaddr = 0;
3177          group = (xdata & 0xc0u) >> 6;
3178          grpmask = 1 << group;
3179          if ( (xdata & 0x20u) )
3180             subgroup = (xdata & 0x0fu) | 0x80;
3181          else
3182             subgroup = 0;
3183 
3184          for ( j = 0; j < 16; j++ ) {
3185             bitmap = 1 << j;
3186             if ( (x10state[hcode].grpmember[j] & grpmask) == 0 ||
3187                  (modmask[Ext3GrpExecMask][hcode] & bitmap) == 0 ||
3188                   (x10state[hcode].grpaddr[j] != subgroup &&
3189                   (x10state[hcode].grpmember[j] & 0x80u) == 0) ) {
3190                continue;
3191             }
3192             ucode = j;
3193             bitmap = 1 << ucode;
3194             trigaddr |= bitmap;
3195 
3196             if ( xfunc == 0x3c ) {
3197                if ( (modmask[Ext3GrpBriDimMask][hcode] & bitmap) == 0 ) {
3198                   continue;
3199                }
3200                oldlevel = x10state[hcode].dimlevel[ucode];
3201                memlevel = x10state[hcode].memlevel[ucode];
3202                if ( (modmask[Ext3GrpBriDimFullMask][hcode] & bitmap) != 0 ) {
3203                   if ( oldlevel == 0 )
3204                      oldlevel = memlevel;
3205                }
3206                if ( xdata & 0x10u )
3207                   grplevel = min(63, oldlevel + 1);
3208                else
3209                   grplevel = max(1, oldlevel - 1);
3210             }
3211             else {
3212                if ( (xdata & 0x10u) && (modmask[Ext3GrpOffMask][hcode] & bitmap) )
3213                   grplevel = 0;
3214                else if ( (xdata & 0x10u) && (modmask[Ext3GrpOffExecMask][hcode] & bitmap) )
3215                   grplevel = x10state[hcode].grplevel[ucode][group];
3216                else
3217                   grplevel = x10state[hcode].grplevel[ucode][group];
3218             }
3219 
3220             if ( grplevel > 0 && (bitmap & switchmask) ) {
3221                gfuncmap |= (1 << OnTrig);
3222                genfunc = OnFunc;
3223                mask = modmask[Ext3Mask][hcode];
3224                active = bitmap & mask;
3225 //               x10state[hcode].state[ChgState] &= ~active;
3226 //               x10state[hcode].state[ChgState] |= ~x10state[hcode].state[OnState] & active;
3227                changestate = active & ~x10state[hcode].state[OnState];
3228                x10state[hcode].state[OnState] |= active;
3229                x10state[hcode].state[DimState] &= ~active;
3230                set_dimlevel(63, hcode, active);
3231                save_dimlevel(hcode, active);
3232             }
3233             else if ( grplevel >= 62 ) {
3234                /* Full On is level 62 or 63 */
3235                gfuncmap |= (1 << OnTrig);
3236                genfunc = OnFunc; /* On function */
3237                mask = modmask[Ext3DimMask][hcode];
3238                active = bitmap & mask;
3239 //               x10state[hcode].state[ChgState] &= ~active;
3240 //               x10state[hcode].state[ChgState] |=
3241                changestate =
3242                   (~x10state[hcode].state[OnState] | x10state[hcode].state[DimState]) & active;
3243                x10state[hcode].state[OnState] |= active;
3244                x10state[hcode].state[DimState] &= ~active;
3245                set_dimlevel(62, hcode, active);
3246                save_dimlevel(hcode, active);
3247             }
3248             else if ( grplevel == 0 ) {
3249                /* Level 0 is Off */
3250                gfuncmap |= (1 << OffTrig);
3251                genfunc = OffFunc;
3252                mask = modmask[Ext3Mask][hcode];
3253                active = bitmap & mask;
3254 //               x10state[hcode].state[ChgState] &= ~active;
3255 //               x10state[hcode].state[ChgState] |=
3256                changestate =
3257                  (x10state[hcode].state[OnState] | x10state[hcode].state[DimState]) & active;
3258                x10state[hcode].state[OnState] &= ~active;
3259                x10state[hcode].state[DimState] &= ~active;
3260                save_dimlevel(hcode, active);
3261                set_dimlevel(0, hcode, active);
3262             }
3263             else {
3264                /* state = DimState; */
3265                gfuncmap |= (1 << DimTrig);
3266                genfunc = DimFunc;
3267                mask = modmask[Ext3DimMask][hcode];
3268                active = bitmap & mask;
3269 //               x10state[hcode].state[ChgState] &= ~active;
3270 //               x10state[hcode].state[ChgState] |= active &
3271                changestate = active &
3272                  ~x10state[hcode].state[DimState];
3273                x10state[hcode].state[OnState] |= active;
3274                x10state[hcode].state[DimState] |= active;
3275                set_dimlevel(grplevel, hcode, active);
3276                save_dimlevel(hcode, active);
3277             }
3278          }
3279          break;
3280       case 0x37 : /* Ext Status Req */
3281          gfuncmap = 0;
3282          genfunc = 0;
3283          mask = modmask[Ext3Mask][hcode];
3284          active = bitmap & mask;
3285          if ( (xdata & 0x30u) == 0x10u ) {
3286             /* Extended PowerUp signal from module */
3287             afuncmap = (1 << ExtPowerUpTrig);
3288          }
3289          else {
3290             x10state[hcode].state[SpendState] |= bitmap;
3291          }
3292          break;
3293       case 0x38 : /* Ext Status Ack */
3294          gfuncmap = 0;
3295          if ( level > 0 && (switchmask & bitmap) ) {
3296             gfuncmap = (1 << OnTrig);
3297             genfunc = OnFunc;
3298             mask = modmask[Ext3Mask][hcode];
3299             active = bitmap & mask;
3300 //            x10state[hcode].state[ChgState] = ~x10state[hcode].state[OnState] & active;
3301             changestate = ~x10state[hcode].state[OnState] & active;
3302             x10state[hcode].state[OnState] |= active;
3303             x10state[hcode].state[DimState] &= ~active;
3304             set_dimlevel(63, hcode, active);
3305             x10state[hcode].state[SpendState] &= ~bitmap;
3306          }
3307          else if ( level >= 62 ) {
3308             gfuncmap = (1 << OnTrig);
3309             genfunc = OnFunc;
3310             mask = modmask[Ext3DimMask][hcode];
3311             active = bitmap & mask;
3312 //            x10state[hcode].state[ChgState] = ~x10state[hcode].state[OnState] & active;
3313             changestate = ~x10state[hcode].state[OnState] & active;
3314             x10state[hcode].state[OnState] |= active;
3315             x10state[hcode].state[DimState] &= ~active;
3316             set_dimlevel(62, hcode, active);
3317             save_dimlevel(hcode, active);
3318             x10state[hcode].state[SpendState] &= ~bitmap;
3319          }
3320          else if ( level == 0 ) {
3321             /* This does not reflect the module's level  */
3322             /* "memory", only it's current status as OFF */
3323             gfuncmap = (1 << OffTrig);
3324             genfunc = OffFunc;
3325             mask = modmask[Ext3Mask][hcode];
3326             active = bitmap & mask;
3327 //            x10state[hcode].state[ChgState] = x10state[hcode].state[OnState] & active;
3328             changestate = x10state[hcode].state[OnState] & active;
3329             x10state[hcode].state[OnState] &= ~active;
3330             x10state[hcode].state[DimState] &= ~active;
3331             /* This may be inaccurate, depending on module's history */
3332             save_dimlevel(hcode, active & modmask[Ext3DimMask][hcode]);
3333             set_dimlevel(0, hcode, active);
3334             x10state[hcode].state[SpendState] &= ~bitmap;
3335          }
3336          else {
3337             /* state = DimState; */
3338             mask = modmask[Ext3DimMask][hcode];
3339             gfuncmap = (1 << DimTrig);
3340             genfunc = DimFunc;
3341             active = bitmap & mask;
3342 //            x10state[hcode].state[ChgState] = ~x10state[hcode].state[DimState] & active;
3343             changestate = ~x10state[hcode].state[DimState] & active;
3344             x10state[hcode].state[OnState] |= active;
3345             x10state[hcode].state[DimState] |= active;
3346             set_dimlevel(level, hcode, active);
3347             save_dimlevel(hcode, active);
3348             x10state[hcode].state[SpendState] &= ~bitmap;
3349          }
3350          break;
3351       case 0x39 : /* Extended Group Status Ack */
3352          mask = modmask[Ext3Mask][hcode];
3353          active = mask & bitmap;
3354          if ( active ) {
3355             x10state[hcode].state[SpendState] &= ~bitmap;
3356          }
3357 //         x10state[hcode].state[ChgState] &= ~bitmap;
3358          changestate = 0;
3359          mask = 0;
3360          gfuncmap = 0;
3361          genfunc = 0;
3362          break;
3363       case 0x3a : /* Extended Group Status Nack */
3364          mask = modmask[Ext3Mask][hcode];
3365          active = mask & bitmap;
3366          if ( active ) {
3367             x10state[hcode].state[SpendState] &= ~bitmap;
3368          }
3369 //         x10state[hcode].state[ChgState] &= ~bitmap;
3370          changestate = 0;
3371          mask = 0;
3372          gfuncmap = 0;
3373          genfunc = 0;
3374          break;
3375       case 0x3b : /* Configure modules */
3376          mask = 0;
3377          gfuncmap = 0;
3378          genfunc = 0;
3379          x10state[hcode].xconfigmode = xdata & 0x03;
3380          break;
3381       default :
3382          /* state = OffState; */
3383          mask = 0;
3384          gfuncmap = 0;
3385          genfunc = 0;
3386          break;
3387    }
3388 
3389    if ( signal_source & RCVI )
3390       x10state[hcode].lastactive = 0;
3391 
3392    startupstate = ~x10state[hcode].state[ValidState] & active;
3393    x10state[hcode].state[ValidState] |= bitmap;
3394 
3395 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
3396    x10state[hcode].state[ModChgState] = changestate;
3397 
3398    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
3399       (x10state[hcode].state[ActiveChgState] & bitmap) |
3400       (startupstate & ~modmask[PhysMask][hcode]);
3401 
3402    changestate = x10state[hcode].state[ChgState];
3403 
3404    if ( bitmap & vmodmask[VtstampMask][hcode] ) {
3405       x10state[hcode].timestamp[ucode] = time(NULL);
3406    }
3407 
3408    if ( i_am_state )
3409       write_x10state_file();
3410 
3411    /* Heyuhelper, if applicable */
3412    if ( i_am_state != 0 && signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
3413       launch_heyuhelper(hcode, trigaddr, func);
3414       return;
3415    }
3416 
3417    bmaplaunch = 0;
3418    launched = 0;
3419    j = 0;
3420    while ( launcherp && launcherp[j].line_no > 0 ) {
3421       if ( launcherp[j].type != L_NORMAL ||
3422            launcherp[j].hcode != hcode ||
3423            is_unmatched_flags(&launcherp[j])  ) {
3424          j++;
3425 	 continue;
3426       }
3427       if ( (launcherp[j].afuncmap & afuncmap || launcherp[j].gfuncmap & gfuncmap) &&
3428            launcherp[j].source & signal_source ) {
3429          trigactive = trigaddr & (mask | launcherp[j].signal);
3430          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
3431 //                   (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ) {
3432                    (changestate | ~launcherp[j].chgtrig)) ) {
3433             *launchp = j;
3434             launcherp[j].matched = YES;
3435             launcherp[j].actfunc = actfunc;
3436             launcherp[j].genfunc = genfunc;
3437 	    launcherp[j].xfunc = xfunc;
3438 	    launcherp[j].level = level;
3439             launcherp[j].bmaplaunch = bmaplaunch;
3440             launcherp[j].actsource = signal_source;
3441             launched |= bmaplaunch;
3442             if ( launcherp[j].scanmode & FM_BREAK )
3443                break;
3444          }
3445       }
3446       j++;
3447    }
3448    x10state[hcode].launched = launched;
3449 
3450    return;
3451 }
3452 
3453 #ifdef HASEXT0
3454 /*----------------------------------------------------------------------------+
3455  | Update the x10state structure per the contents of the argument 'buf'       |
3456  | for type 0 extended codes.  'buf' will always contain 4 bytes.             |
3457  | Supported Type/Functions are limited to 0x01, 0x02, 0x03, 0x04, 0x0B       |
3458  |                                                                            |
3459  | If the user has defined the type of module, e.g. lamp module, for a        |
3460  | specific housecode|unit address, the change of state for that address      |
3461  | is filtered by the supported features of that type of module, e.g. an      |
3462  | extended preset dim signal will be ignored for appliance modules.          |
3463  |                                                                            |
3464  | The received signal and state are tested to see if any of the conditions   |
3465  | exist for triggering the launching of an external script, and if so, the   |
3466  | index of the launcher is passed back through argument 'launchp',           |
3467  | otherwise -1 is passed back.                                               |
3468  +----------------------------------------------------------------------------*/
x10state_update_ext0func(unsigned char * buf,int * launchp)3469 void x10state_update_ext0func ( unsigned char *buf, int *launchp )
3470 {
3471    unsigned char hcode, func, xfunc, ucode, subunit, level, limit;
3472    unsigned char actfunc, genfunc;
3473    unsigned int  bitmap, trigaddr, mask, active = 0, trigactive;
3474    unsigned int  onstate, dimstate, changestate, startupstate;
3475    unsigned int  bmaplaunch, launched;
3476    unsigned long afuncmap, gfuncmap;
3477    int           j;
3478    LAUNCHER      *launcherp;
3479    extern unsigned int signal_source;
3480 
3481    launcherp = configp->launcherp;
3482 
3483    *launchp = -1;
3484 
3485    if ( !(i_am_state || i_am_monitor) )
3486       return;
3487 
3488    func = buf[0] & 0x0f;
3489    if ( func != 7 )
3490       return;
3491    actfunc = genfunc = func;
3492    afuncmap = (1 << ExtendedTrig);
3493 
3494    hcode = (buf[0] & 0xf0u) >> 4;
3495    ucode = buf[1] & 0x0fu;
3496 
3497    subunit = (buf[1] & 0xf0u) >> 4;
3498    /* Subunit states are not supported */
3499    if ( subunit > 0 )
3500       return;
3501 
3502    level = buf[2] & 0x1f;
3503    limit = 25;
3504    xfunc = buf[3];
3505    bitmap = 1 << ucode;
3506    trigaddr = bitmap;
3507 
3508    x10state[hcode].lastcmd = func;
3509 //   x10state[hcode].state[ChgState] = 0;
3510    changestate = 0;
3511    x10state[hcode].lastunit = code2unit(ucode);
3512    x10global.lasthc = hcode;
3513 
3514    x10state[hcode].reset = 1;
3515 
3516    x10global.lastaddr = 0;
3517 
3518    onstate = x10state[hcode].state[OnState];
3519    dimstate = x10state[hcode].state[DimState];
3520 
3521    switch ( xfunc ) {
3522       case 0x01 :  /* Open, observe limit */
3523       case 0x03 :  /* Open, disregard and disable limit */
3524          mask = modmask[Ext0Mask][hcode];
3525          active = bitmap & mask;
3526          if ( level >= 25 ) {
3527             /* Full Open is level 25 */
3528             level = 25;
3529             gfuncmap = (1 << OnTrig);
3530             genfunc = OnFunc; /* On function */
3531          }
3532          else if ( level == 0 ) {
3533             /* Level 0 is Off */
3534             gfuncmap = (1 << OffTrig);
3535             genfunc = OffFunc;
3536          }
3537          else {
3538             /* state = DimState; */
3539             gfuncmap = (1 << DimTrig);
3540             genfunc = DimFunc;
3541          }
3542 
3543          if ( xfunc == 0x01 )
3544             set_limit_dimlevel(level, hcode, active);
3545          else {
3546             set_dimlevel(level, hcode, active);
3547             set_max_memlevel(hcode, active);
3548          }
3549 
3550          get_states(hcode, &onstate, &dimstate);
3551 //         x10state[hcode].state[ChgState] = active &
3552          changestate = active &
3553            ((x10state[hcode].state[OnState] ^ onstate) |
3554             (x10state[hcode].state[DimState] ^ dimstate));
3555          x10state[hcode].state[OnState]  = onstate;
3556          x10state[hcode].state[DimState] = dimstate;
3557 
3558          break;
3559 
3560       case 0x02 :  /* Set limit and open to that limit */
3561          level = min(level, 25);
3562          gfuncmap = 0;
3563          genfunc = 0;
3564          mask = modmask[Ext0Mask][hcode];
3565          active = bitmap & mask;
3566          get_states(hcode, &onstate, &dimstate);
3567          changestate = active &
3568            ((x10state[hcode].state[OnState] ^ onstate) |
3569             (x10state[hcode].state[DimState] ^ dimstate));
3570          set_memlevel(level, hcode, active);
3571          restore_dimlevel(hcode, active);
3572          break;
3573 
3574       case 0x04 :  /* Open all shutters, disable limit */
3575          gfuncmap = (1 << OnTrig);
3576          genfunc = OnFunc;
3577          mask = modmask[Ext0Mask][hcode];
3578          trigaddr = 0xffff;
3579          active = modmask[Ext0Mask][hcode];
3580 //         x10state[hcode].state[ChgState] = active &
3581          changestate = active &
3582             (~x10state[hcode].state[OnState] | x10state[hcode].state[DimState]);
3583          x10state[hcode].state[OnState] |= active;
3584          x10state[hcode].state[DimState] &= ~active;
3585          set_max_memlevel(hcode, active);
3586          break;
3587 
3588       case 0x0B :  /* Close all shutters */
3589          gfuncmap = (1 << OffTrig);
3590          genfunc = OffFunc;
3591          mask = modmask[Ext0Mask][hcode];
3592          trigaddr = 0xffff;
3593          active = modmask[Ext0Mask][hcode];
3594 //         x10state[hcode].state[ChgState] = active &
3595          changestate = active &
3596             (x10state[hcode].state[OnState] | x10state[hcode].state[DimState]);
3597          x10state[hcode].state[OnState] &= ~active;
3598          x10state[hcode].state[DimState] &= ~active;
3599          set_dimlevel(0, hcode, active);
3600          break;
3601 
3602       default :
3603          /* state = OffState; */
3604          mask = 0;
3605          active = 0;
3606          gfuncmap = 0;
3607          genfunc = 0;
3608          break;
3609    }
3610 
3611    startupstate = ~x10state[hcode].state[ValidState] & active;
3612    x10state[hcode].state[ValidState] |= active;
3613 
3614 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
3615    x10state[hcode].state[ModChgState] = changestate;
3616 
3617    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
3618       (x10state[hcode].state[ActiveChgState] & active) |
3619       (startupstate & ~modmask[PhysMask][hcode]);
3620 
3621    changestate = x10state[hcode].state[ChgState];
3622 
3623    if ( bitmap & vmodmask[VtstampMask][hcode] ) {
3624       x10state[hcode].timestamp[ucode] = time(NULL);
3625    }
3626 
3627    if ( signal_source & RCVI )
3628       x10state[hcode].lastactive = 0;
3629 
3630    if ( i_am_state )
3631       write_x10state_file();
3632 
3633    /* Heyuhelper, if applicable */
3634    if ( signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
3635       launch_heyuhelper(hcode, trigaddr, func);
3636       return;
3637    }
3638 
3639    bmaplaunch = 0;
3640    launched = 0;
3641    j = 0;
3642    while ( launcherp && launcherp[j].line_no > 0 ) {
3643       if ( launcherp[j].type != L_NORMAL ||
3644            launcherp[j].hcode != hcode ||
3645            is_unmatched_flags(&launcherp[j])  ) {
3646          j++;
3647 	 continue;
3648       }
3649       if ( (launcherp[j].afuncmap & afuncmap || launcherp[j].gfuncmap & gfuncmap) &&
3650            launcherp[j].source & signal_source ) {
3651          trigactive = trigaddr & (mask | launcherp[j].signal);
3652          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
3653 //                   (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ) {
3654                    (changestate | ~launcherp[j].chgtrig)) ) {
3655             *launchp = j;
3656             launcherp[j].matched = YES;
3657             launcherp[j].actfunc = actfunc;
3658             launcherp[j].genfunc = genfunc;
3659 	    launcherp[j].xfunc = xfunc;
3660 	    launcherp[j].level = level;
3661             launcherp[j].bmaplaunch = bmaplaunch;
3662             launcherp[j].actsource = signal_source;
3663             launched |= bmaplaunch;
3664             if ( launcherp[j].scanmode & FM_BREAK )
3665                break;
3666          }
3667       }
3668       j++;
3669    }
3670    x10state[hcode].launched = launched;
3671 
3672    return;
3673 }
3674 
3675 #else
3676 
3677 /*----------------------------------------------------------------------------+
3678  | Dummy stub.                                                                |
3679  +----------------------------------------------------------------------------*/
x10state_update_ext0func(unsigned char * buf,int * launchp)3680 void x10state_update_ext0func ( unsigned char *buf, int *launchp )
3681 {
3682    *launchp = -1;
3683    return;
3684 }
3685 
3686 #endif  /* End of HASEXT0 block */
3687 
3688 /*----------------------------------------------------------------------------+
3689  | Handler for extended code type/function which are otherwise undefined.     |
3690  |                                                                            |
3691  | The received signal and state are tested to see if any of the conditions   |
3692  | exist for triggering the launching of an external script, and if so, the   |
3693  | index of the launcher is passed back through argument 'launchp',           |
3694  | otherwise -1 is passed back.                                               |
3695  +----------------------------------------------------------------------------*/
x10state_update_extotherfunc(unsigned char * buf,int * launchp)3696 void x10state_update_extotherfunc ( unsigned char *buf, int *launchp )
3697 {
3698    unsigned char hcode, func, xfunc, ucode, subunit, level;
3699    unsigned char actfunc, genfunc;
3700    unsigned int  bitmap, trigaddr, mask, trigactive, active;
3701    unsigned int  changestate, startupstate;
3702    unsigned int  bmaplaunch, launched;
3703    unsigned long afuncmap, gfuncmap;
3704    int           j;
3705    LAUNCHER      *launcherp;
3706    extern unsigned int signal_source;
3707 
3708    launcherp = configp->launcherp;
3709 
3710    *launchp = -1;
3711 
3712    if ( !(i_am_state || i_am_monitor) )
3713       return;
3714 
3715    func = buf[0] & 0x0f;
3716    if ( func != 7 )
3717       return;
3718    actfunc = genfunc = func;
3719    afuncmap = (1 << ExtendedTrig);
3720 
3721    hcode = (buf[0] & 0xf0u) >> 4;
3722    ucode = buf[1] & 0x0fu;
3723 
3724    subunit = (buf[1] & 0xf0u) >> 4;
3725    /* Subunit states are not supported */
3726    if ( subunit > 0 )
3727       return;
3728 
3729    level = buf[2];
3730    xfunc = buf[3];
3731    bitmap = 1 << ucode;
3732    trigaddr = bitmap;
3733 
3734    x10state[hcode].lastcmd = func;
3735 //   x10state[hcode].state[ChgState] = 0;
3736    changestate = 0;
3737    x10state[hcode].lastunit = code2unit(ucode);
3738    x10global.lasthc = hcode;
3739 
3740    x10state[hcode].reset = 1;
3741 
3742    x10global.lastaddr = 0;
3743 
3744    mask = 0;
3745    gfuncmap = 0;
3746    genfunc = 0;
3747    active = bitmap;
3748 
3749    startupstate = ~x10state[hcode].state[ValidState] & active;
3750    x10state[hcode].state[ValidState] |= active;
3751 
3752 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
3753    x10state[hcode].state[ModChgState] = changestate;
3754 
3755    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
3756       (x10state[hcode].state[ActiveChgState] & active) |
3757       (startupstate & ~modmask[PhysMask][hcode]);
3758 
3759    changestate = x10state[hcode].state[ChgState];
3760 
3761    if ( bitmap & vmodmask[VtstampMask][hcode] ) {
3762       x10state[hcode].timestamp[ucode] = time(NULL);
3763    }
3764 
3765    if ( signal_source & RCVI )
3766       x10state[hcode].lastactive = 0;
3767 
3768    if ( i_am_state )
3769       write_x10state_file();
3770 
3771    /* Heyuhelper, if applicable */
3772    if ( signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
3773       launch_heyuhelper(hcode, trigaddr, func);
3774       return;
3775    }
3776 
3777    bmaplaunch = 0;
3778    launched = 0;
3779    j = 0;
3780    while ( launcherp && launcherp[j].line_no > 0 ) {
3781       if ( launcherp[j].type != L_NORMAL ||
3782            launcherp[j].hcode != hcode ||
3783            is_unmatched_flags(&launcherp[j])  ) {
3784          j++;
3785 	 continue;
3786       }
3787       if ( (launcherp[j].afuncmap & afuncmap || launcherp[j].gfuncmap & gfuncmap) &&
3788            launcherp[j].source & signal_source ) {
3789          trigactive = trigaddr & (mask | launcherp[j].signal);
3790          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
3791 //                   (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ) {
3792                    (changestate | ~launcherp[j].chgtrig)) ) {
3793             *launchp = j;
3794             launcherp[j].matched = YES;
3795             launcherp[j].actfunc = actfunc;
3796             launcherp[j].genfunc = genfunc;
3797 	    launcherp[j].xfunc = xfunc;
3798 	    launcherp[j].level = level;
3799             launcherp[j].bmaplaunch = bmaplaunch;
3800             launcherp[j].actsource = signal_source;
3801             launched |= bmaplaunch;
3802             if ( launcherp[j].scanmode & FM_BREAK )
3803                break;
3804          }
3805       }
3806       j++;
3807    }
3808    x10state[hcode].launched = launched;
3809 
3810    return;
3811 }
3812 
3813 /*----------------------------------------------------------------------------+
3814  | Update the x10state structure per the contents of the argument 'buf'       |
3815  | for virtual modules.  'buf' will contains 6 bytes.  The first is the       |
3816  | standard hcode|ucode byte, the second is the data 0x00-0xff, the third is  |
3817  | the virtual type, the fourth is the module ID byte.                        |
3818  |                                                                            |
3819  | Only modules with attribute VIRTUAL will be updated.                       |
3820  |                                                                            |
3821  | The received signal and state are tested to see if any of the conditions   |
3822  | exist for triggering the launching of an external script, and if so, the   |
3823  | index of the launcher is passed back through argument 'launchp',           |
3824  | otherwise -1 is passed back.                                               |
3825  +----------------------------------------------------------------------------*/
x10state_update_virtual(unsigned char * buf,int len,int * launchp)3826 int x10state_update_virtual ( unsigned char *buf, int len, int *launchp )
3827 {
3828    unsigned char  hcode, func, xfunc, ucode, vdata, vtype, hibyte, lobyte;
3829 //   unsigned short ident, idmask;
3830    unsigned long  ident, idmask;
3831    unsigned char  actfunc, genfunc;
3832    unsigned int   bitmap, trigaddr, mask, active, trigactive;
3833    unsigned int   changestate, startupstate;
3834    unsigned int   bmaplaunch, launched;
3835    unsigned long  afuncmap = 0, gfuncmap = 0, sfuncmap = 0;
3836    unsigned long  sflags, vflags;
3837    struct xlate_vdata_st xlate_vdata;
3838    int            j, index, trig;
3839    char           hc;
3840    LAUNCHER       *launcherp;
3841    ALIAS          *aliasp;
3842    extern unsigned int signal_source;
3843 
3844    launcherp = configp->launcherp;
3845 
3846    *launchp = -1;
3847 
3848    aliasp = config.aliasp;
3849 
3850    genfunc = 0;
3851    gfuncmap = 0;
3852    vflags = 0;
3853 
3854    hcode  = (buf[0] & 0xf0u) >> 4;
3855    ucode  = buf[0] & 0x0fu;
3856    vdata  = buf[1];
3857    vtype  = buf[2];
3858    ident  = buf[3] | (buf[4] << 8);
3859    hibyte = buf[5];
3860    lobyte = buf[6];
3861 
3862    if ( vtype == RF_VDATAM ) {
3863       func = VdataMFunc;
3864       trig = VdataMTrig;
3865    }
3866    else {
3867       func = VdataFunc;
3868       trig = VdataTrig;
3869    }
3870 
3871    bitmap = 1 << ucode;
3872    hc = code2hc(hcode);
3873 
3874    idmask = (vtype == RF_SEC) ? configp->securid_mask : 0xffffu;
3875 
3876    index = alias_rev_index(hc, bitmap, vtype, (ident & idmask));
3877 
3878    /* Run the decoding function for the module type, if any */
3879    if ( index >= 0 &&
3880         aliasp[index].modtype >= 0 && aliasp[index].xlate_func != NULL ) {
3881       xlate_vdata.vdata = vdata;
3882       xlate_vdata.hibyte = hibyte;
3883       xlate_vdata.lobyte = lobyte;
3884       xlate_vdata.hcode = hcode;
3885       xlate_vdata.ucode = ucode;
3886       xlate_vdata.ident = ident & idmask;
3887       xlate_vdata.nident = aliasp[index].nident;
3888       xlate_vdata.identp = aliasp[index].ident;
3889       xlate_vdata.optflags = aliasp[index].optflags;
3890       xlate_vdata.optflags2 = aliasp[index].optflags2;
3891       /* Tamper flag is sticky */
3892       xlate_vdata.vflags = x10state[hcode].vflags[ucode] & SEC_TAMPER;
3893 
3894       /* Run the translation function */
3895       if ( aliasp[index].xlate_func(&xlate_vdata) != 0 )
3896          return 1;
3897       func = xlate_vdata.func;
3898       xfunc = xlate_vdata.xfunc;
3899       vflags = xlate_vdata.vflags;
3900       trig = xlate_vdata.trig;
3901    }
3902 
3903    x10state[hcode].vaddress = bitmap;
3904    x10state[hcode].lastcmd = func;
3905    x10state[hcode].lastunit = code2unit(ucode);
3906    x10state[hcode].vident[ucode] = ident & idmask;
3907    x10state[hcode].vflags[ucode] = vflags;
3908    x10state[hcode].timestamp[ucode] = time(NULL);
3909 //   x10state[hcode].state[ValidState] |= (1 << ucode);
3910 //   x10state[hcode].state[ChgState] = 0;
3911    changestate = 0;
3912    x10global.lasthc = hcode;
3913    x10global.lastaddr = 0;
3914 
3915    if ( vflags & SEC_LOBAT ) {
3916       x10state[hcode].state[LoBatState] |= bitmap;
3917    }
3918    else {
3919       x10state[hcode].state[LoBatState] &= ~bitmap;
3920    }
3921 
3922    if ( (vflags & SEC_AUX) || (func == VdataMFunc) ) {
3923       /* Special for DS90 and other dual signal devices, or vdatam command */
3924       if ( vdata != x10state[hcode].memlevel[ucode] ) {
3925 //         x10state[hcode].state[ChgState] |= bitmap;
3926          changestate |= bitmap;
3927          x10state[hcode].memlevel[ucode] = vdata;
3928       }
3929    }
3930    else {
3931       if ( vdata != x10state[hcode].dimlevel[ucode] ) {
3932 //         x10state[hcode].state[ChgState] |= bitmap;
3933          changestate |= bitmap;
3934          x10state[hcode].dimlevel[ucode] = vdata;
3935       }
3936    }
3937 
3938 #if 0
3939    if ( vtype == RF_SEC ) {
3940       if ( vflags & SEC_MIN ) {
3941          x10state[hcode].state[SwMinState] |= bitmap;
3942          x10state[hcode].state[SwMaxState] &= ~bitmap;
3943       }
3944       else if ( vflags & SEC_MAX ) {
3945          x10state[hcode].state[SwMaxState] |= bitmap;
3946          x10state[hcode].state[SwMinState] &= ~bitmap;
3947       }
3948    }
3949 #endif
3950 
3951    if ( func == AlertFunc ) {
3952       if ( vflags & SEC_AUX ) {
3953          x10state[hcode].state[AuxAlertState] |= bitmap;
3954          x10state[hcode].state[AuxClearState] &= ~bitmap;
3955       }
3956       else {
3957          x10state[hcode].state[AlertState] |= bitmap;
3958          x10state[hcode].state[ClearState] &= ~bitmap;
3959       }
3960    }
3961    else if ( func == ClearFunc ) {
3962       if ( vflags & SEC_AUX ) {
3963          x10state[hcode].state[AuxAlertState] &= ~bitmap;
3964          x10state[hcode].state[AuxClearState] |= bitmap;
3965       }
3966       else {
3967          x10state[hcode].state[AlertState] &= ~bitmap;
3968          x10state[hcode].state[ClearState] |= bitmap;
3969       }
3970    }
3971    else if ( func == DuskFunc ) {
3972       x10state[hcode].state[AuxAlertState] |= bitmap;
3973       x10state[hcode].state[AuxClearState] &= ~bitmap;
3974    }
3975    else if ( func == DawnFunc ) {
3976       x10state[hcode].state[AuxAlertState] &= ~bitmap;
3977       x10state[hcode].state[AuxClearState] |= bitmap;
3978    }
3979 
3980    if ( func == DisarmFunc ) {
3981       set_globsec_flags(0);
3982    }
3983    else if ( func == ArmFunc ) {
3984       if ( configp->arm_remote == AUTOMATIC || !(signal_source & RCVA) ) {
3985          sflags = (vflags & SEC_HOME) ? GLOBSEC_HOME : 0;
3986          sflags |= ((vflags & SEC_MIN) || config.arm_max_delay == 0) ? GLOBSEC_ARMED : GLOBSEC_PENDING;
3987          set_globsec_flags(sflags >> GLOBSEC_SHIFT);
3988       }
3989    }
3990    else if ( func == SecLightsOnFunc )
3991       set_seclights_flag(1);
3992    else if ( func == SecLightsOffFunc )
3993       set_seclights_flag(0);
3994 
3995    if ( func == TamperFunc ) {
3996       set_tamper_flag(1);
3997       x10state[hcode].vflags[ucode] |= SEC_TAMPER;
3998       x10state[hcode].state[TamperState] |= (1 << ucode);
3999    }
4000 
4001 
4002    actfunc = func;
4003    trigaddr = bitmap;
4004    if ( vtype == RF_SEC )
4005       sfuncmap = (1 << trig);
4006    else
4007       afuncmap = (1 << trig);
4008 
4009    mask = modmask[VdataMask][hcode];
4010    active = bitmap & mask;
4011 
4012    startupstate = ~x10state[hcode].state[ValidState] & active;
4013    x10state[hcode].state[ValidState] |= active;
4014 
4015    update_activity_timeout(aliasp, index);
4016    update_activity_states(hcode, active, S_ACTIVE);
4017 
4018 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
4019    x10state[hcode].state[ModChgState] = changestate;
4020 
4021    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
4022       (x10state[hcode].state[ActiveChgState] & active) |
4023       (startupstate & ~modmask[PhysMask][hcode]);
4024 
4025    changestate = x10state[hcode].state[ChgState];
4026 
4027 
4028    if ( signal_source & RCVI )
4029       x10state[hcode].lastactive = 0;
4030 
4031    if ( i_am_state )
4032       write_x10state_file();
4033 
4034    /* Heyuhelper, if applicable */
4035    if ( i_am_state && signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
4036       launch_heyuhelper(hcode, trigaddr, func);
4037       return 0;
4038    }
4039 
4040    bmaplaunch = 0;
4041    launched = 0;
4042    j = 0;
4043    while ( launcherp && launcherp[j].line_no > 0 ) {
4044       if ( launcherp[j].type != L_NORMAL ||
4045            launcherp[j].hcode != hcode ||
4046            is_unmatched_flags(&launcherp[j]) ||
4047            (launcherp[j].vflags & x10state[hcode].vflags[ucode]) != launcherp[j].vflags ||
4048 	   (launcherp[j].notvflags & ~x10state[hcode].vflags[ucode]) != launcherp[j].notvflags ) {
4049          j++;
4050 	 continue;
4051       }
4052 
4053       if ( (launcherp[j].afuncmap & afuncmap || launcherp[j].gfuncmap & gfuncmap || launcherp[j].sfuncmap & sfuncmap) &&
4054            launcherp[j].source & signal_source ) {
4055          trigactive = trigaddr & (mask | launcherp[j].signal);
4056          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
4057 #if 0
4058                    (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ||
4059 #endif
4060                    (changestate | ~launcherp[j].chgtrig)) ||
4061                    (launcherp[j].unitstar && !trigaddr)) {
4062             *launchp = j;
4063             launcherp[j].matched = YES;
4064             launcherp[j].actfunc = actfunc;
4065             launcherp[j].genfunc = genfunc;
4066 	    launcherp[j].xfunc = 0;
4067 	    launcherp[j].level = vdata;
4068             launcherp[j].bmaplaunch = bmaplaunch;
4069             launcherp[j].actsource = signal_source;
4070             launched |= bmaplaunch;
4071             if ( launcherp[j].scanmode & FM_BREAK )
4072                break;
4073          }
4074       }
4075       j++;
4076    }
4077 
4078    x10state[hcode].launched = launched;
4079 
4080    return 0;
4081 }
4082 
4083 /*----------------------------------------------------------------------------+
4084  | Handle the special case of type RF_DUSK sensors.                           |
4085  +----------------------------------------------------------------------------*/
x10state_update_duskdawn(unsigned char * buf,int len,int * launchp)4086 int x10state_update_duskdawn ( unsigned char *buf, int len, int *launchp )
4087 {
4088    unsigned char  hcode, ucode, func, vdata;
4089    unsigned char  actfunc, genfunc;
4090    unsigned int   bitmap, trigaddr, mask, active, trigactive, vflags;
4091    unsigned int   bmaplaunch, launched;
4092    unsigned int   changestate, startupstate;
4093    unsigned long  afuncmap, gfuncmap;
4094    int            j, trig;
4095    char           hc;
4096    LAUNCHER       *launcherp;
4097    extern unsigned int signal_source;
4098 
4099    launcherp = configp->launcherp;
4100 
4101    *launchp = -1;
4102 
4103    genfunc = 0;
4104    gfuncmap = 0;
4105    vflags = 0;
4106    hcode  = (buf[0] & 0xf0u) >> 4;
4107    ucode = buf[0] & 0x0fu;
4108    vdata  = buf[1];
4109 
4110    bitmap = (1 << ucode);
4111    hc = code2hc(hcode);
4112 
4113    changestate = (x10state[hcode].dimlevel[ucode] == vdata) ? 0 : bitmap;
4114 
4115    if ( vdata == 0xf0u ) {
4116       func = DuskFunc;
4117       trig = DuskTrig;
4118    }
4119    else if ( vdata == 0xf8u ) {
4120       func = DawnFunc;
4121       trig = DawnTrig;
4122    }
4123    else if ( vdata == 0xe0u ) {
4124       func = AlertFunc;
4125       trig = AlertTrig;
4126    }
4127    else {
4128       func = VdataFunc;
4129       trig = VdataTrig;
4130    }
4131 
4132 
4133    x10state[hcode].vaddress = 0;
4134    x10state[hcode].lastcmd = func;
4135 //   x10state[hcode].state[ChgState] = 0;
4136    x10global.lasthc = hcode;
4137    x10global.lastaddr = 0;
4138 
4139    actfunc = func;
4140    afuncmap = (1 << trig);
4141    trigaddr = bitmap;
4142    mask = 0;
4143 
4144    active = bitmap;
4145 
4146    startupstate = ~x10state[hcode].state[ValidState] & active;
4147    x10state[hcode].state[ValidState] |= active;
4148 
4149 //   x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
4150    x10state[hcode].state[ModChgState] = changestate;
4151 
4152    x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
4153       (x10state[hcode].state[ActiveChgState] & active) |
4154       (startupstate & ~modmask[PhysMask][hcode]);
4155 
4156    changestate = x10state[hcode].state[ChgState];
4157 
4158    if ( i_am_state )
4159       write_x10state_file();
4160 
4161    /* Heyuhelper, if applicable */
4162    if ( i_am_state && signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
4163       launch_heyuhelper(hcode, trigaddr, func);
4164       return 0;
4165    }
4166 
4167    bmaplaunch = 0;
4168    launched = 0;
4169    j = 0;
4170    while ( launcherp && launcherp[j].line_no > 0 ) {
4171       if ( launcherp[j].type != L_NORMAL ||
4172            launcherp[j].hcode != hcode ||
4173            is_unmatched_flags(&launcherp[j])  ) {
4174          j++;
4175 	 continue;
4176       }
4177 
4178       if ( (launcherp[j].afuncmap & afuncmap || launcherp[j].gfuncmap & gfuncmap) &&
4179            launcherp[j].source & signal_source ) {
4180          trigactive = trigaddr & (mask | launcherp[j].signal);
4181          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
4182 //                   (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ||
4183                    (changestate | ~launcherp[j].chgtrig)) ||
4184                    (launcherp[j].unitstar && !trigaddr)) {
4185             *launchp = j;
4186             launcherp[j].matched = YES;
4187             launcherp[j].actfunc = actfunc;
4188             launcherp[j].genfunc = genfunc;
4189 	    launcherp[j].xfunc = 0;
4190 	    launcherp[j].level = vdata;
4191             launcherp[j].bmaplaunch = bmaplaunch;
4192             launcherp[j].actsource = signal_source;
4193             launched |= bmaplaunch;
4194             if ( launcherp[j].scanmode & FM_BREAK )
4195                break;
4196          }
4197       }
4198       j++;
4199    }
4200 
4201    x10state[hcode].launched = launched;
4202 
4203    return 0;
4204 }
4205 
4206 /*---------------------------------------------------------------------+
4207  | Execute all hourly scripts                                          |
4208  +---------------------------------------------------------------------*/
launch_hourly_scripts(void)4209 int launch_hourly_scripts ( void )
4210 {
4211    LAUNCHER      *launcherp;
4212    int           j, launchp = -1;
4213    int           exec_script ( LAUNCHER * );
4214    mode_t        oldumask;
4215 
4216    if ( (launcherp = configp->launcherp) == NULL ||
4217         (configp->script_mode & HEYU_HELPER)  )
4218       return -1;
4219 
4220    if ( !i_am_state )
4221       return -1;
4222 
4223    /* Redirect output to the Heyu log file */
4224    oldumask = umask((mode_t)configp->log_umask);
4225    fdsout = freopen(configp->logfile, "a", stdout);
4226    fdserr = freopen(configp->logfile, "a", stderr);
4227    umask(oldumask);
4228 
4229    j = 0;
4230    while ( launcherp[j].line_no > 0 ) {
4231       if ( (launcherp[j].type != L_HOURLY) ||
4232            is_unmatched_flags(&launcherp[j])  ) {
4233          j++;
4234          continue;
4235       }
4236       launcherp[j].matched = YES;
4237       launchp = j;
4238 
4239       if ( launcherp[j].scanmode & FM_BREAK )
4240          break;
4241       j++;
4242    }
4243 
4244    return launch_scripts(&launchp);
4245 
4246    return 0;
4247 }
4248 
4249 /*---------------------------------------------------------------------+
4250  | Launch -rfflood scripts which match the launch conditions.          |
4251  +---------------------------------------------------------------------*/
find_rfflood_scripts(void)4252 int find_rfflood_scripts ( void )
4253 {
4254    LAUNCHER      *launcherp;
4255    int           j, launchp = -1;
4256 
4257    if ( (launcherp = configp->launcherp) == NULL ||
4258         (configp->script_mode & HEYU_HELPER)  )
4259       return -1;
4260 
4261    if ( !i_am_state )
4262       return -1;
4263 
4264    j = 0;
4265    while ( launcherp[j].line_no > 0 ) {
4266       if ( (launcherp[j].type != L_RFFLOOD) ||
4267            is_unmatched_flags(&launcherp[j])  ) {
4268          j++;
4269          continue;
4270       }
4271       launcherp[j].matched = YES;
4272       launchp = j;
4273       if ( launcherp[j].scanmode == FM_BREAK )
4274          break;
4275       j++;
4276    }
4277    return launchp;
4278 }
4279 
4280 /*---------------------------------------------------------------------+
4281  | Launch -rfxjam scripts which match the launch conditions.           |
4282  +---------------------------------------------------------------------*/
find_rfxjam_scripts(void)4283 int find_rfxjam_scripts ( void )
4284 {
4285    LAUNCHER      *launcherp;
4286    int           j, launchp = -1;
4287 
4288    if ( (launcherp = configp->launcherp) == NULL ||
4289         (configp->script_mode & HEYU_HELPER)  )
4290       return -1;
4291 
4292    if ( !i_am_state )
4293       return -1;
4294 
4295    j = 0;
4296    while ( launcherp[j].line_no > 0 ) {
4297       if ( (launcherp[j].type != L_RFXJAM) ||
4298            is_unmatched_flags(&launcherp[j])  ||
4299            (launcherp[j].vflags & x10global.vflags) != launcherp[j].vflags     ||
4300            (launcherp[j].notvflags & ~x10global.vflags) != launcherp[j].notvflags ) {
4301          j++;
4302          continue;
4303       }
4304       launcherp[j].matched = YES;
4305       launchp = j;
4306       if ( launcherp[j].scanmode == FM_BREAK )
4307          break;
4308       j++;
4309    }
4310    return launchp;
4311 }
4312 
4313 /*---------------------------------------------------------------------+
4314  | Launch -lockup scripts which match the launch conditions.           |
4315  +---------------------------------------------------------------------*/
find_lockup_scripts(void)4316 int find_lockup_scripts(void)
4317 {
4318    LAUNCHER      *launcherp;
4319    int           j, launchp = -1;
4320 
4321    if ( (launcherp = configp->launcherp) == NULL ||
4322         (configp->script_mode & HEYU_HELPER)  )
4323       return -1;
4324 
4325    if ( !i_am_state )
4326       return -1;
4327 
4328    j = 0;
4329    while ( launcherp[j].line_no > 0 ) {
4330       if ( (launcherp[j].type != L_LOCKUP) ||
4331             is_unmatched_flags(&launcherp[j])  ) {
4332          j++;
4333          continue;
4334       }
4335       launcherp[j].matched = YES;
4336       launchp = j;
4337       if ( launcherp[j].scanmode & FM_BREAK )
4338          break;
4339       j++;
4340    }
4341    return launchp;
4342 }
4343 
4344 /*---------------------------------------------------------------------+
4345  | Launch powerfail scripts which match the launch conditions          |
4346  +---------------------------------------------------------------------*/
find_powerfail_scripts(unsigned char bootflag)4347 int find_powerfail_scripts ( unsigned char bootflag )
4348 {
4349    LAUNCHER      *launcherp;
4350    int           j, launchp = -1;
4351 
4352    if ( (launcherp = configp->launcherp) == NULL ||
4353         (configp->script_mode & HEYU_HELPER)  )
4354       return -1;
4355 
4356    if ( !i_am_state )
4357       return -1;
4358 
4359    j = 0;
4360    while ( launcherp[j].line_no > 0 ) {
4361       if ( (launcherp[j].type != L_POWERFAIL) ||
4362             is_unmatched_flags(&launcherp[j])  ||
4363            (launcherp[j].bootflag & bootflag) != launcherp[j].bootflag ) {
4364          j++;
4365          continue;
4366       }
4367       launcherp[j].matched = YES;
4368       launchp = j;
4369       if ( launcherp[j].scanmode & FM_BREAK )
4370          break;
4371       j++;
4372    }
4373 
4374    return launchp;
4375 }
4376 
4377 /*---------------------------------------------------------------------+
4378  | Display the detailed state of each unit on the argument X10-encoded |
4379  | housecode, i.e., Addressed, On, Dimmed, Changed.                    |
4380  +---------------------------------------------------------------------*/
x10state_show(unsigned char hcode)4381 void x10state_show ( unsigned char hcode )
4382 {
4383    char lasthc;
4384    unsigned char lastcmd;
4385    unsigned int lastunitbmap;
4386    char minibuf[32];
4387    char *chrs = ".*";
4388    int  lw = 13;
4389    char *bmap2asc2 ( unsigned int, unsigned int, char * );
4390 
4391    lastcmd = x10state[hcode].lastcmd;
4392    if ( lastcmd == 0xff )
4393       sprintf(minibuf, "_none_");
4394    else
4395       sprintf(minibuf, "%s", funclabel[lastcmd]);
4396 
4397    lastunitbmap = (x10state[hcode].lastunit > 0) ?
4398        (1 << unit2code(x10state[hcode].lastunit)) : 0;
4399 
4400    lasthc = (x10global.lasthc == 0xff) ? '_' : code2hc(x10global.lasthc);
4401 
4402    printf("%*s %c\n", lw + 13, "Housecode", code2hc(hcode));
4403    printf("%*s  1..4...8.......16\n", lw, "Unit:");
4404    printf("%*s (%s)\n", lw,    "LastUnit", bmap2asc(lastunitbmap, ".u"));
4405    printf("%*s (%s)\n", lw,   "Addressed", bmap2asc2(x10state[hcode].vaddress,
4406                                                       x10state[hcode].addressed, ".va"));
4407    printf("%*s (%s)\n", lw,          "On", bmap2asc(x10state[hcode].state[OnState], chrs));
4408    printf("%*s (%s)\n", lw,      "Dimmed", bmap2asc(x10state[hcode].state[DimState], ".x"));
4409    printf("%*s (%s)\n", lw,     "Changed", bmap2asc(x10state[hcode].state[ChgState], ".c"));
4410    printf("%*s (%s)\n", lw,    "Launched", bmap2asc(x10state[hcode].launched, chrs));
4411    printf("Last function this housecode: %s\n", minibuf);
4412    printf("Last Housecode = %c\n", lasthc);
4413    printf("\n");
4414    fflush(stdout);
4415    return;
4416 }
4417 
4418 /*---------------------------------------------------------------------+
4419  | Return a 16 character ASCII string displaying in ascending order    |
4420  | an X10 unit bitmap, i.e., char[0] -> unit 1, char[15] -> unit 16.   |
4421  | The argument chrs is a three-character string, the 1st character of |
4422  | represents 'unset' units and the 2nd character the 'set' bits in    |
4423  | bitmap1.  The 3rd character will overwrite the 2nd character for  ` |
4424  | set bits in bitmap2                                                 |
4425  +---------------------------------------------------------------------*/
bmap2asc2(unsigned int bitmap1,unsigned int bitmap2,char * chrs)4426 char *bmap2asc2 ( unsigned int bitmap1, unsigned int bitmap2, char *chrs )
4427 {
4428    int j;
4429    static char outbuf[17];
4430 
4431    for ( j = 0; j < 16; j++ ) {
4432       if ( bitmap1 & (1 << j) )
4433          outbuf[code2unit(j) - 1] = chrs[1];
4434       else
4435          outbuf[code2unit(j) - 1] = chrs[0];
4436    }
4437    for ( j = 0; j < 16; j++ ) {
4438       if ( bitmap2 & (1 << j) )
4439          outbuf[code2unit(j) - 1] = chrs[2];
4440    }
4441    outbuf[16] = '\0';
4442    return outbuf;
4443 }
4444 
4445 /*---------------------------------------------------------------------+
4446  | Return a 16 character ASCII string displaying in ascending order    |
4447  | a 16-bit linear bitmap.                                             |
4448  | The argument chrs is a three-character string, the 1st character of |
4449  | represents 'unset' units and the 2nd character the 'set' bits in    |
4450  | bitmap1.  The 3rd character will overwrite the 2nd character for  ` |
4451  | set bits in bitmap2                                                 |
4452  +---------------------------------------------------------------------*/
linmap2asc2(unsigned int bitmap1,unsigned int bitmap2,char * chrs)4453 char *linmap2asc2 ( unsigned int bitmap1, unsigned int bitmap2, char *chrs )
4454 {
4455    int j;
4456    static char outbuf[17];
4457 
4458    for ( j = 0; j < 16; j++ ) {
4459       if ( bitmap1 & (1 << j) )
4460          outbuf[j] = chrs[1];
4461       else
4462          outbuf[j] = chrs[0];
4463    }
4464    for ( j = 0; j < 16; j++ ) {
4465       if ( bitmap2 & (1 << j) )
4466          outbuf[j] = chrs[2];
4467    }
4468    outbuf[16] = '\0';
4469    return outbuf;
4470 }
4471 
4472 /*---------------------------------------------------------------------+
4473  | Return a 16 character ASCII string displaying a state bitmap for    |
4474  | the unit corresponding to the index in the array, i.e. char[0] =    |
4475  | unit 1; char[1] = unit 2; etc.                                      |
4476  | The bits in each bitmap have the following meanings:                |
4477  |   Bit 0 : Addressed                                                 |
4478  |   Bit 1 : Changed                                                   |
4479  |   Bit 2 : Dimmed                                                    |
4480  |   Bit 3 : On                                                        |
4481  | The arguments are the unit bitmaps indicating On, Dimmed, Changed,  |
4482  | and Addressed, respectively.                                        |
4483  +---------------------------------------------------------------------*/
bmap2statestr(unsigned int onmap,unsigned int dimmap,unsigned int chgmap,unsigned int addrmap)4484 char *bmap2statestr ( unsigned int onmap, unsigned int dimmap,
4485 	                     unsigned int chgmap, unsigned int addrmap )
4486 {
4487   int j;
4488   int val;
4489   unsigned int bmap;
4490   static char outbuf[17];
4491   char hexdigit[] = "0123456789abcdef";
4492 
4493   for ( j = 0; j < 16; j++ )  {
4494      val = 0;
4495      bmap = 1 << j;
4496      val += (   onmap & bmap ) ? 8 : 0;
4497      val += (  dimmap & bmap ) ? 4 : 0;
4498      val += (  chgmap & bmap ) ? 2 : 0;
4499      val += ( addrmap & bmap ) ? 1 : 0;
4500      outbuf[code2unit(j) - 1] = hexdigit[val];
4501   }
4502   outbuf[16] = '\0';
4503   return outbuf;
4504 }
4505 
4506 
4507 /*---------------------------------------------------------------------+
4508  | Create list of SCRIPT options for launcher.                         |
4509  +---------------------------------------------------------------------*/
script_option_list(LAUNCHER * launcherp,int index,char * list)4510 int script_option_list ( LAUNCHER *launcherp, int index, char *list )
4511 {
4512    SCRIPT   *scriptp;
4513    unsigned char option;
4514 
4515    scriptp = configp->scriptp;
4516 
4517    option = scriptp[launcherp[index].scriptnum].script_option;
4518 
4519    *list = '\0';
4520 
4521    if ( !option )
4522       return 0;
4523 
4524    if ( option & SCRIPT_XTEND )
4525       strcat(list + strlen(list), "-xtend ");
4526    if ( option & SCRIPT_RAWLEVEL )
4527       strcat(list + strlen(list), "-rawlevel ");
4528    if ( option & SCRIPT_NOENV )
4529       strcat(list + strlen(list), "-noenv ");
4530    if ( option & SCRIPT_QQUIET )
4531       strcat(list + strlen(list), "-qquiet ");
4532    if ( option & SCRIPT_QUIET )
4533       strcat(list + strlen(list), "-quiet ");
4534 
4535    return 1;
4536 }
4537 
4538 
4539 
4540 /*---------------------------------------------------------------------+
4541  | Display launcher flags for specific launcher                        |
4542  +---------------------------------------------------------------------*/
display_launcher_flags(LAUNCHER * launcherp,int index)4543 void display_launcher_flags ( LAUNCHER *launcherp, int index )
4544 {
4545    unsigned long bitmap1, bitmap2, bitmap3, bitmap4, /*bitmap5, bitmap6,*/ mask;
4546    unsigned int  bmap;
4547    unsigned char hcode;
4548    int           j, k;
4549 
4550    bitmap1 = launcherp[index].sflags;
4551    bitmap2 = launcherp[index].notsflags;
4552    bitmap3 = launcherp[index].vflags;
4553    bitmap4 = launcherp[index].notvflags;
4554 //   bitmap5 = launcherp[index].czflags;
4555 //   bitmap6 = launcherp[index].notczflags;
4556 
4557    /* Display state flags */
4558 
4559    for ( j = 0; j < launcherp[index].num_stflags; j++ ) {
4560       k = launcherp[index].stlist[j].stindex;
4561       hcode = launcherp[index].stlist[j].hcode;
4562       bmap = launcherp[index].stlist[j].bmap;
4563       printf("%s%c%s ", stflags[k].label, code2hc(hcode), bmap2units(bmap));
4564    }
4565 
4566 
4567    if ( launcherp[index].bootflag & R_ATSTART )
4568       printf("boot ");
4569    else if ( launcherp[index].bootflag & R_NOTATSTART )
4570       printf("notboot ");
4571 
4572    if ( bitmap3 & SEC_MIN         ) printf("swmin ");
4573    if ( bitmap3 & SEC_MAX         ) printf("swmax ");
4574    if ( bitmap3 & SEC_HOME        ) printf("swhome ");
4575    if ( bitmap3 & SEC_AWAY        ) printf("swaway ");
4576    if ( bitmap3 & SEC_LOBAT       ) printf("lobat ");
4577    if ( launcherp[index].notvflags & SEC_LOBAT )
4578       printf("notlobat ");
4579    if ( bitmap3 & RFX_JAM         ) printf("started ");
4580    if ( bitmap4 & RFX_JAM         ) printf("ended ");
4581    if ( bitmap3 & SEC_MAIN        ) printf("main ");
4582    if ( bitmap3 & SEC_AUX         ) printf("aux ");
4583    if ( bitmap3 & RFX_ROLLOVER    ) printf("rollover ");
4584    if ( bitmap3 & ORE_TMIN        ) printf("tmin ");
4585    if ( bitmap3 & ORE_TMAX        ) printf("tmax ");
4586    if ( bitmap3 & ORE_RHMIN       ) printf("rhmin ");
4587    if ( bitmap3 & ORE_RHMAX       ) printf("rhmax ");
4588    if ( bitmap3 & ORE_BPMIN       ) printf("bpmin ");
4589    if ( bitmap3 & ORE_BPMAX       ) printf("bpmax ");
4590 
4591    if ( bitmap3 & DMX_SET         ) printf("set ");
4592    if ( bitmap4 & DMX_SET         ) printf("notset ");
4593    if ( bitmap3 & DMX_HEAT        ) printf("heat ");
4594    if ( bitmap4 & DMX_HEAT        ) printf("cool ");
4595    if ( bitmap3 & DMX_INIT        ) printf("init ");
4596    if ( bitmap4 & DMX_INIT        ) printf("notinit ");
4597    if ( bitmap3 & DMX_TEMP        ) printf("temp ");
4598    if ( bitmap4 & DMX_TEMP        ) printf("nottemp ");
4599 
4600    if ( bitmap1 & NIGHT_FLAG      ) printf("night ");
4601    if ( bitmap2 & NIGHT_FLAG      ) printf("notnight ");
4602    if ( bitmap1 & DARK_FLAG       ) printf("dark ");
4603    if ( bitmap2 & DARK_FLAG       ) printf("notdark ");
4604    if ( bitmap1 & GLOBSEC_TAMPER  ) printf("tamper ");
4605    if ( bitmap1 & GLOBSEC_FLOOD   ) printf("started ");
4606    if ( bitmap2 & GLOBSEC_FLOOD   ) printf("ended ");
4607    if ( bitmap1 & GLOBSEC_ARMED   ) printf("armed ");
4608    if ( bitmap1 & GLOBSEC_PENDING ) printf("armpending ");
4609    if ((bitmap2 & GLOBSEC_ARMED) &&
4610        (bitmap2 & GLOBSEC_PENDING)) printf("disarmed ");
4611    else if
4612       ( bitmap2 & GLOBSEC_ARMED   ) printf("notarmed ");
4613    if ( bitmap1 & GLOBSEC_HOME    ) printf("home ");
4614    if ( bitmap2 & GLOBSEC_HOME    ) printf("away ");
4615 
4616    for ( j = 0; j < NUM_FLAG_BANKS; j++ ) {
4617       bitmap1 = launcherp[index].flags[j];
4618       bitmap2 = launcherp[index].notflags[j];
4619       mask = 1;
4620       for ( k = 0; k < 32; k++ ) {
4621          if ( bitmap1 & mask ) printf("flag%d ", (32 * j) + k + 1);
4622          if ( bitmap2 & mask ) printf("notflag%d ", (32 * j) + k + 1);
4623          mask = mask << 1;
4624       }
4625    }
4626 
4627    for ( j = 0; j < NUM_COUNTER_BANKS; j++ ) {
4628       bitmap1 = launcherp[index].czflags[j];
4629       bitmap2 = launcherp[index].notczflags[j];
4630       mask = 1;
4631       for ( k = 0; k < 32; k++ ) {
4632          if ( bitmap1 & mask ) printf("czflag%d ", (32 * j) + k + 1);
4633          if ( bitmap2 & mask ) printf("notczflag%d ", (32 * j) + k + 1);
4634          mask = mask << 1;
4635       }
4636    }
4637 
4638    for ( j = 0; j < NUM_TIMER_BANKS; j++ ) {
4639       bitmap1 = launcherp[index].tzflags[j];
4640       bitmap2 = launcherp[index].nottzflags[j];
4641       mask = 1;
4642       for ( k = 0; k < 32; k++ ) {
4643          if ( bitmap1 & mask ) printf("tzflag%d ", (32 * j) + k + 1);
4644          if ( bitmap2 & mask ) printf("nottzflag%d ", (32 * j) + k + 1);
4645          mask = mask << 1;
4646       }
4647    }
4648 
4649    return;
4650 }
4651 
4652 /*---------------------------------------------------------------------+
4653  | Display launcher sources for specific launcher                      |
4654  +---------------------------------------------------------------------*/
display_launcher_sources(LAUNCHER * launcherp,int index)4655 void display_launcher_sources ( LAUNCHER *launcherp, int index )
4656 {
4657    unsigned int source;
4658 
4659    source = launcherp[index].source;
4660 
4661    if ( source & RCVI )  printf("rcvi ");
4662    if ( source & RCVT )  printf("rcvt ");
4663    if ( source & SNDC )  printf("sndc ");
4664    if ( source & SNDM )  printf("sndm ");
4665    if ( source & SNDS )  printf("snds ");
4666    if ( source & SNDT )  printf("sndt ");
4667    if ( source & SNDP )  printf("sndp ");
4668    if ( source & SNDA )  printf("snda ");
4669    if ( source & RCVA )  printf("rcva ");
4670    if ( source & XMTF )  printf("xmtf ");
4671 
4672    return;
4673 }
4674 
4675 /*---------------------------------------------------------------------+
4676  | Display all script -sensorfail launch conditions.                   |
4677  +---------------------------------------------------------------------*/
show_sensorfail_launcher(void)4678 void show_sensorfail_launcher ( void )
4679 {
4680    int           j, lw = 13;
4681    LAUNCHER      *launcherp;
4682    char          list[80];
4683    char          *flowstr;
4684 
4685    if ( (launcherp = configp->launcherp) == NULL ) {
4686       return;
4687    }
4688 
4689    j = 0;
4690    while ( launcherp[j].line_no > 0 ) {
4691       if ( launcherp[j].type == L_SENSORFAIL ) {
4692          printf("\n");
4693          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4694                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4695          sprintf(list, "-sensorfail %s", flowstr);
4696          printf("%*s: %-20s", lw, "Launch Mode", list);
4697 
4698          printf("%s: ", "Flags");
4699          display_launcher_flags(launcherp, j);
4700 
4701          printf("\n");
4702          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4703             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4704             printf("%*s: %-18s\n", lw, "Script label", list);
4705          }
4706          else {
4707             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4708          }
4709 
4710          if ( script_option_list(launcherp, j, list) > 0 )
4711             printf("%*s: %s\n", lw, "Script opt", list);
4712 
4713          printf("%*s: %s\n", lw, "Command Line",
4714 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
4715 
4716       }
4717       j++;
4718    }
4719    return;
4720 }
4721 
4722 /*---------------------------------------------------------------------+
4723  | Display all script -timout launch conditions.                       |
4724  +---------------------------------------------------------------------*/
show_timeout_launcher(void)4725 void show_timeout_launcher ( void )
4726 {
4727    int           j, lw = 13;
4728    LAUNCHER      *launcherp;
4729    char          list[80];
4730    char          *flowstr;
4731 
4732    if ( (launcherp = configp->launcherp) == NULL ) {
4733       return;
4734    }
4735 
4736    j = 0;
4737    while ( launcherp[j].line_no > 0 ) {
4738       if ( launcherp[j].type == L_TIMEOUT ) {
4739          printf("\n");
4740          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4741                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4742          sprintf(list, "-timeout %s", flowstr);
4743          printf("%*s: %-20s", lw, "Launch Mode", list);
4744 
4745          if ( launcherp[j].timer == 0 )
4746             printf("%s: armdelay ", "Flags");
4747          else
4748             printf("%s: timer%-2d ", "Flags", launcherp[j].timer);
4749 
4750          display_launcher_flags(launcherp, j);
4751 
4752          printf("\n");
4753          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4754             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4755             printf("%*s: %-18s\n", lw, "Script label", list);
4756          }
4757          else {
4758             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4759          }
4760 
4761          if ( script_option_list(launcherp, j, list) > 0 )
4762             printf("%*s: %s\n", lw, "Script opt", list);
4763 
4764          printf("%*s: %s\n", lw, "Command Line",
4765 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
4766 
4767       }
4768       j++;
4769    }
4770    return;
4771 }
4772 
4773 /*---------------------------------------------------------------------+
4774  | Display all script -rfflood launch conditions.                      |
4775  +---------------------------------------------------------------------*/
show_rfflood_launcher(void)4776 void show_rfflood_launcher ( void )
4777 {
4778    int           j, lw = 13;
4779    LAUNCHER      *launcherp;
4780    char          list[80];
4781    char          *flowstr;
4782 
4783    if ( (launcherp = configp->launcherp) == NULL ) {
4784       return;
4785    }
4786 
4787    j = 0;
4788    while ( launcherp[j].line_no > 0 ) {
4789       if ( launcherp[j].type == L_RFFLOOD ) {
4790          printf("\n");
4791          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4792                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4793          sprintf(list, "-rfflood %s", flowstr);
4794          printf("%*s: %-20s", lw, "Launch Mode", list);
4795 
4796          printf("%s: ", "Flags");
4797          display_launcher_flags(launcherp, j);
4798          printf("\n");
4799 
4800          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4801             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4802             printf("%*s: %-18s\n", lw, "Script label", list);
4803          }
4804          else {
4805             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4806          }
4807 
4808          if ( script_option_list(launcherp, j, list) > 0 )
4809             printf("%*s: %s\n", lw, "Script opt", list);
4810 
4811          printf("%*s: %s\n", lw, "Command Line",
4812 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
4813 
4814       }
4815       j++;
4816    }
4817    return;
4818 }
4819 
4820 /*---------------------------------------------------------------------+
4821  | Display all script -rfxjam launch conditions.                       |
4822  +---------------------------------------------------------------------*/
show_rfxjam_launcher(void)4823 void show_rfxjam_launcher ( void )
4824 {
4825    int           j, lw = 13;
4826    LAUNCHER      *launcherp;
4827    char          list[80];
4828    char          *flowstr;
4829 
4830    if ( (launcherp = configp->launcherp) == NULL ) {
4831       return;
4832    }
4833 
4834    j = 0;
4835    while ( launcherp[j].line_no > 0 ) {
4836       if ( launcherp[j].type == L_RFXJAM ) {
4837          printf("\n");
4838          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4839                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4840          sprintf(list, "-rfxjam %s", flowstr);
4841          printf("%*s: %-20s", lw, "Launch Mode", list);
4842 
4843          printf("%s: ", "Flags");
4844          display_launcher_flags(launcherp, j);
4845          printf("\n");
4846 
4847          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4848             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4849             printf("%*s: %-18s\n", lw, "Script label", list);
4850          }
4851          else {
4852             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4853          }
4854 
4855          if ( script_option_list(launcherp, j, list) > 0 )
4856             printf("%*s: %s\n", lw, "Script opt", list);
4857 
4858          printf("%*s: %s\n", lw, "Command Line",
4859 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
4860 
4861       }
4862       j++;
4863    }
4864    return;
4865 }
4866 
4867 /*---------------------------------------------------------------------+
4868  | Display all script -powerfail launch conditions.                    |
4869  +---------------------------------------------------------------------*/
show_powerfail_launcher(void)4870 void show_powerfail_launcher ( void )
4871 {
4872    int           j, lw = 13;
4873    LAUNCHER      *launcherp;
4874    char          list[80];
4875    char          *flowstr;
4876 
4877    if ( (launcherp = configp->launcherp) == NULL ) {
4878       return;
4879    }
4880 
4881    j = 0;
4882    while ( launcherp[j].line_no > 0 ) {
4883       if ( launcherp[j].type == L_POWERFAIL ) {
4884          printf("\n");
4885          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4886                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4887          sprintf(list, "-powerfail %s", flowstr);
4888          printf("%*s: %-20s", lw, "Launch Mode", list);
4889 
4890          printf("%s: ", "Flags");
4891          display_launcher_flags(launcherp, j);
4892          printf("\n");
4893 
4894          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4895             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4896             printf("%*s: %-18s\n", lw, "Script label", list);
4897          }
4898          else {
4899             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4900          }
4901 
4902          if ( script_option_list(launcherp, j, list) > 0 )
4903             printf("%*s: %s\n", lw, "Script opt", list);
4904 
4905          printf("%*s: %s\n", lw, "Command Line",
4906 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
4907 
4908       }
4909       j++;
4910    }
4911    return;
4912 }
4913 
4914 /*---------------------------------------------------------------------+
4915  | Display all script -exec launch conditions.                         |
4916  +---------------------------------------------------------------------*/
show_exec_launcher(void)4917 void show_exec_launcher ( void )
4918 {
4919    int           j, lw = 13;
4920    LAUNCHER      *launcherp;
4921    char          list[80];
4922    char          *flowstr;
4923 
4924    if ( (launcherp = configp->launcherp) == NULL ) {
4925       return;
4926    }
4927 
4928    j = 0;
4929    while ( launcherp[j].line_no > 0 ) {
4930       if ( launcherp[j].type == L_EXEC ) {
4931          printf("\n");
4932          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4933                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4934          sprintf(list, "-exec %s", flowstr);
4935          printf("%*s: %-20s", lw, "Launch Mode", list);
4936 
4937          printf("%s: ", "Flags");
4938          display_launcher_flags(launcherp, j);
4939          printf("\n");
4940 
4941          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4942             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4943             printf("%*s: %-18s\n", lw, "Script label", list);
4944          }
4945          else {
4946             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4947          }
4948 
4949          if ( script_option_list(launcherp, j, list) > 0 )
4950             printf("%*s: %s\n", lw, "Script opt", list);
4951 
4952          printf("%*s: %s\n", lw, "Command Line",
4953 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
4954 
4955       }
4956       j++;
4957    }
4958    return;
4959 }
4960 
4961 /*---------------------------------------------------------------------+
4962  | Display all script -hourly launch conditions.                       |
4963  +---------------------------------------------------------------------*/
show_hourly_launcher(void)4964 void show_hourly_launcher ( void )
4965 {
4966    int           j, lw = 13;
4967    LAUNCHER      *launcherp;
4968    char          list[80];
4969    char          *flowstr;
4970 
4971    if ( (launcherp = configp->launcherp) == NULL ) {
4972       return;
4973    }
4974 
4975    j = 0;
4976    while ( launcherp[j].line_no > 0 ) {
4977       if ( launcherp[j].type == L_HOURLY ) {
4978          printf("\n");
4979          flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
4980                    (launcherp[j].scanmode & FM_BREAK) ? "break" : "continue";
4981          sprintf(list, "-hourly %s", flowstr);
4982          printf("%*s: %-20s", lw, "Launch Mode", list);
4983 
4984          printf("%s: ", "Flags");
4985          display_launcher_flags(launcherp, j);
4986          printf("\n");
4987 
4988          if ( configp->scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
4989             sprintf(list, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
4990             printf("%*s: %-18s\n", lw, "Script label", list);
4991          }
4992          else {
4993             printf("%*s: %-18s\n", lw, "Script label", launcherp[j].label);
4994          }
4995 
4996          if ( script_option_list(launcherp, j, list) > 0 )
4997             printf("%*s: %s\n", lw, "Script opt", list);
4998 
4999          printf("%*s: %s\n", lw, "Command Line",
5000 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
5001 
5002       }
5003       j++;
5004    }
5005    return;
5006 }
5007 
5008 /*---------------------------------------------------------------------+
5009  | Display all script launch conditions for argument housecode.        |
5010  +---------------------------------------------------------------------*/
show_launcher(unsigned char hcode)5011 void show_launcher ( unsigned char hcode )
5012 {
5013    unsigned int  signal, bmaptrig, chgtrig;
5014    unsigned long funcmap, afuncmap, gfuncmap, xfuncmap;
5015    unsigned long sfuncmap, ofuncmap, kfuncmap;
5016    unsigned int  bmaptrigemu;
5017    unsigned int  source;
5018    int           j, lw = 13;
5019    LAUNCHER      *launcherp;
5020    SCRIPT        *scriptp;
5021    char          minibuf[64];
5022    char          *flowstr;
5023 
5024    if ( (launcherp = configp->launcherp) == NULL ||
5025         (scriptp   = configp->scriptp  ) == NULL    ) {
5026       return;
5027    }
5028 
5029    j = 0;
5030    while ( launcherp[j].line_no > 0 ) {
5031       if ( launcherp[j].hcode != hcode ||
5032            launcherp[j].type == L_POWERFAIL ||
5033            launcherp[j].type == L_SENSORFAIL ||
5034            launcherp[j].type == L_RFFLOOD ||
5035            launcherp[j].type == L_RFXJAM  ||
5036            launcherp[j].type == L_TIMEOUT ||
5037            launcherp[j].type == L_EXEC    ||
5038            launcherp[j].type == L_HOURLY    ) {
5039          j++;
5040          continue;
5041       }
5042       signal = launcherp[j].signal;
5043       afuncmap = launcherp[j].afuncmap;
5044       gfuncmap = launcherp[j].gfuncmap;
5045       xfuncmap = launcherp[j].xfuncmap;
5046       sfuncmap = launcherp[j].sfuncmap;
5047       ofuncmap = launcherp[j].ofuncmap;
5048       kfuncmap = launcherp[j].kfuncmap;
5049       funcmap = gfuncmap | afuncmap;
5050       bmaptrig = launcherp[j].bmaptrig;
5051       chgtrig = launcherp[j].chgtrig;
5052       source = launcherp[j].source;
5053       bmaptrigemu = launcherp[j].bmaptrigemu;
5054 
5055       printf("\n");
5056       if ( launcherp[j].unitstar ) {
5057          sprintf(minibuf, "%c*", code2hc(launcherp[j].hcode));
5058          printf("%*s: %-27s", lw, "Address", minibuf);
5059       }
5060       else {
5061          sprintf(minibuf, "%c%s", code2hc(launcherp[j].hcode), bmap2units(bmaptrig));
5062          printf("%*s: %-27s", lw, "Address", minibuf);
5063       }
5064 
5065       printf("%s: ", "Functions");
5066       if ( gfuncmap & (1 << OnTrig) ) {
5067          printf("%s ", "gon");
5068          funcmap &= ~((1 << OnTrig) | (1 << LightsOnTrig) | (1 << AllOnTrig));
5069       }
5070       if ( gfuncmap & (1 << OffTrig) ) {
5071          printf("%s ", "goff");
5072          funcmap &= ~((1 << OffTrig) | (1 << LightsOffTrig) | (1 << AllOffTrig));
5073       }
5074       if ( gfuncmap & (1 << DimTrig) ) {
5075          printf("%s ", "gdim");
5076          funcmap &= ~((1 << DimTrig) | (1 << BriTrig));
5077       }
5078       if ( funcmap & (1 << OnTrig) ) printf("%s ", "on");
5079       if ( funcmap & (1 << OffTrig) ) printf("%s ", "off");
5080       if ( funcmap & (1 << DimTrig) ) printf("%s ", "dim");
5081       if ( funcmap & (1 << BriTrig) ) printf("%s ", "bright");
5082       if ( funcmap & (1 << LightsOnTrig) ) printf("%s ", "lightson");
5083       if ( funcmap & (1 << LightsOffTrig) ) printf("%s ","lightsoff");
5084       if ( funcmap & (1 << AllOnTrig) ) printf("%s ", "allon");
5085       if ( funcmap & (1 << AllOffTrig) ) printf("%s ", "alloff");
5086       if ( funcmap & (1 << PresetTrig) ) printf("%s ", "preset");
5087       if ( funcmap & (1 << ExtendedTrig) ) printf("%s ", "extended");
5088       if ( funcmap & (1 << StatusReqTrig) ) printf("%s ", "status");
5089       if ( funcmap & (1 << StatusOnTrig) ) printf("%s ", "status_on");
5090       if ( funcmap & (1 << StatusOffTrig) ) printf("%s ", "status_off");
5091       if ( funcmap & (1 << HailReqTrig) ) printf("%s ", "hail");
5092       if ( funcmap & (1 << HailAckTrig) ) printf("%s ", "hail_ack");
5093       if ( funcmap & (1 << DataXferTrig) ) printf("%s ", "data_xfer");
5094       if ( funcmap & (1 << ExtPowerUpTrig) ) printf("%s ", "xpowerup");
5095       if ( funcmap & (1 << VdataTrig) ) printf("%s ", "vdata");
5096 
5097       if ( sfuncmap & (1 << PanicTrig) ) printf("%s ", "panic");
5098       if ( sfuncmap & (1 << ArmTrig) ) printf("%s ", "arm");
5099       if ( sfuncmap & (1 << DisarmTrig) ) printf("%s ", "disarm");
5100       if ( sfuncmap & (1 << AlertTrig) ) printf("%s ", "alert");
5101       if ( sfuncmap & (1 << ClearTrig) ) printf("%s ", "clear");
5102       if ( sfuncmap & (1 << TamperTrig) ) printf("%s ", "sectamper");
5103       if ( sfuncmap & (1 << TestTrig)  ) printf("%s ", "test");
5104       if ( sfuncmap & (1 << SecLightsOnTrig) ) printf("%s ", "slightson");
5105       if ( sfuncmap & (1 << SecLightsOffTrig) ) printf("%s ", "slightsoff");
5106       if ( sfuncmap & (1 << AkeyOnTrig) ) printf("%s ", "akeyon");
5107       if ( sfuncmap & (1 << AkeyOffTrig) ) printf("%s ", "akeyoff");
5108       if ( sfuncmap & (1 << BkeyOnTrig) ) printf("%s ", "bkeyon");
5109       if ( sfuncmap & (1 << BkeyOffTrig) ) printf("%s ", "bkeyoff");
5110       if ( sfuncmap & (1 << DawnTrig) ) printf("%s ", "sdawn");
5111       if ( sfuncmap & (1 << DuskTrig) ) printf("%s ", "sdusk");
5112       if ( sfuncmap & (1 << InactiveTrig) ) printf("%s ", "inactive");
5113 
5114       if ( xfuncmap & (1 << RFXTempTrig) )  printf("%s ", "rfxtemp");
5115       if ( xfuncmap & (1 << RFXTemp2Trig) ) printf("%s ", "rfxtemp2");
5116       if ( xfuncmap & (1 << RFXHumidTrig) ) printf("%s ", "rfxrh");
5117       if ( xfuncmap & (1 << RFXPressTrig) ) printf("%s ", "rfxbp");
5118       if ( xfuncmap & (1 << RFXLoBatTrig) ) printf("%s ", "rfxlobat");
5119       if ( xfuncmap & (1 << RFXVsTrig) )    printf("%s ", "rfxvs");
5120       if ( xfuncmap & (1 << RFXVadTrig) )   printf("%s ", "rfxvad");
5121       if ( xfuncmap & (1 << RFXOtherTrig) ) printf("%s ", "rfxother");
5122       if ( xfuncmap & (1 << RFXPulseTrig) ) printf("%s ", "rfxpulse");
5123       if ( xfuncmap & (1 << RFXCountTrig) ) printf("%s ", "rfxcount");
5124       if ( xfuncmap & (1 << RFXPowerTrig) ) printf("%s ", "rfxpower");
5125       if ( xfuncmap & (1 << RFXWaterTrig) ) printf("%s ", "rfxwater");
5126       if ( xfuncmap & (1 << RFXGasTrig) )   printf("%s ", "rfxgas");
5127       if ( xfuncmap & (1 << DmxTempTrig) )  printf("%s ", "dmxtemp");
5128       if ( xfuncmap & (1 << DmxOnTrig) )    printf("%s ", "dmxon");
5129       if ( xfuncmap & (1 << DmxOffTrig) )   printf("%s ", "dmxoff");
5130       if ( xfuncmap & (1 << DmxSetPtTrig) )  printf("%s ", "dmxsetpoint");
5131 
5132       if ( ofuncmap & (1 << OreTempTrig) )  printf("%s ", "oretemp");
5133       if ( ofuncmap & (1 << OreHumidTrig) )  printf("%s ", "orerh");
5134       if ( ofuncmap & (1 << OreBaroTrig) )  printf("%s ", "orebp");
5135       if ( ofuncmap & (1 << OreWeightTrig) )  printf("%s ", "orewgt");
5136       if ( ofuncmap & (1 << OreWindSpTrig) ) printf("%s ", "orewindsp");
5137       if ( ofuncmap & (1 << OreWindAvSpTrig) ) printf("%s ", "orewindavsp");
5138       if ( ofuncmap & (1 << OreWindSpTrig) ) printf("%s ", "orewindsp");
5139       if ( ofuncmap & (1 << OreRainRateTrig) ) printf("%s ", "orerain");
5140       if ( ofuncmap & (1 << OreRainTotTrig) ) printf("%s ", "oreraintot");
5141       if ( ofuncmap & (1 << OwlPowerTrig) ) printf("%s ", "owlpower");
5142       if ( ofuncmap & (1 << OwlEnergyTrig) ) printf("%s ", "owlenergy");
5143       if ( ofuncmap & (1 << ElsCurrTrig) ) printf("%s ", "elscurr");
5144 
5145 
5146       if ( kfuncmap & (1 << KakuOnTrig) ) printf("%s ", "kon");
5147       if ( kfuncmap & (1 << KakuOffTrig) ) printf("%s ", "koff");
5148       if ( kfuncmap & (1 << KakuGrpOnTrig) ) printf("%s ", "kgrpon");
5149       if ( kfuncmap & (1 << KakuGrpOffTrig) ) printf("%s ", "kgrpoff");
5150       if ( kfuncmap & (1 << KakuPreTrig) ) printf("%s ", "kpreset");
5151       if ( kfuncmap & (1 << KakuGrpPreTrig) ) printf("%s ", "kgrppreset");
5152 
5153       printf("\n");
5154 
5155       printf("%*s: ", lw, "Launch Mode");
5156       flowstr = (configp->scanmode == launcherp[j].scanmode) ? "" :
5157                 (launcherp[j].scanmode & FM_BREAK) ? "break " : "continue ";
5158       if ( launcherp[j].type == L_ADDRESS )
5159          sprintf(minibuf, "%s", "address");
5160       else
5161          sprintf(minibuf, "%s%s%s%s", (chgtrig ? "changed " : ""),
5162 	   ((bmaptrig & signal) ? "signal " : "module "),
5163 	   ((launcherp[j].trigemuflag) ? "trigemu " : ""), flowstr );
5164       printf("%-31s", minibuf);
5165 
5166       printf("%s: ", "Flags");
5167       display_launcher_flags(launcherp, j);
5168       printf("\n");
5169 
5170       if ( scriptp[launcherp[j].scriptnum].num_launchers > 1 ) {
5171          sprintf(minibuf, "%s [%d]", launcherp[j].label, launcherp[j].launchernum);
5172          printf("%*s: %-29s", lw, "Script label", minibuf);
5173       }
5174       else {
5175          printf("%*s: %-29s", lw, "Script label", launcherp[j].label);
5176       }
5177 
5178       printf("%s: ", "Sources");
5179       if ( source & RCVI )  printf("rcvi ");
5180       if ( source & RCVT )  printf("rcvt ");
5181       if ( source & SNDC )  printf("sndc ");
5182       if ( source & SNDM )  printf("sndm ");
5183       if ( source & SNDS )  printf("snds ");
5184       if ( source & SNDT )  printf("sndt ");
5185       if ( source & SNDP )  printf("sndp ");
5186       if ( source & SNDA )  printf("snda ");
5187       if ( source & RCVA )  printf("rcva ");
5188       if ( source & XMTF )  printf("xmtf ");
5189       printf("\n");
5190 
5191       if ( script_option_list(launcherp, j, minibuf) > 0 )
5192          printf("%*s: %s\n", lw, "Script opt", minibuf);
5193 
5194       printf("%*s: %s\n", lw, "Command Line",
5195 		  configp->scriptp[launcherp[j].scriptnum].cmdline);
5196 
5197       j++;
5198    }
5199 
5200    return;
5201 }
5202 
5203 
show_all_launchers(void)5204 void show_all_launchers ( void )
5205 {
5206    static int hcode_table[16] =
5207         {6, 14, 2, 10, 1, 9, 5, 13, 7, 15, 3, 11, 0, 8, 4, 12};
5208    int j;
5209 
5210    if ( configp->launcherp == NULL ) {
5211       return;
5212    }
5213 
5214    for ( j = 0; j < 16; j++ )
5215       show_launcher(hcode_table[j]);
5216 
5217    show_powerfail_launcher();
5218    show_sensorfail_launcher();
5219    show_rfflood_launcher();
5220    show_rfxjam_launcher();
5221    show_timeout_launcher();
5222    show_exec_launcher();
5223    show_hourly_launcher();
5224 
5225    return;
5226 }
5227 
5228 /*---------------------------------------------------------------------+
5229  | Display the sticky address state for all housecodes and units.      |
5230  +---------------------------------------------------------------------*/
show_sticky_addr(void)5231 void show_sticky_addr ( void )
5232 {
5233    unsigned char hcode;
5234    char          hc;
5235    int           j, unit;
5236    char          outbuf[17];
5237    char          label[16];
5238    char          *chrs = "*.";
5239    int           lw = 13;
5240 
5241    printf("Cumulative received addresses\n");
5242    printf("%*s  1..4...8.......16\n", lw, "Unit:");
5243    for ( hc = 'A'; hc <= 'P'; hc++ ) {
5244       hcode = hc2code(hc);
5245 
5246       for ( j = 0; j < 16; j++ ) {
5247          unit = code2unit(j) - 1;
5248          if ( x10state[hcode].sticky & (1 << j) ) {
5249             outbuf[unit] = chrs[0];
5250          }
5251          else
5252             outbuf[unit] = chrs[1];
5253       }
5254       sprintf(label, "Housecode %c", hc);
5255       outbuf[16] = '\0';
5256       printf("%*s (%s)\n", lw, label, outbuf);
5257    }
5258    return;
5259 }
5260 
5261 /*---------------------------------------------------------------------+
5262  | Display the On/Off/Dimmed state for all housecodes and units.       |
5263  +---------------------------------------------------------------------*/
show_housemap(void)5264 void show_housemap ( void )
5265 {
5266    unsigned char hcode;
5267    char          hc;
5268    int           j, unit;
5269    char          outbuf[17];
5270    char          label[16];
5271    char          *chrs = "*x.";
5272    int           lw = 13;
5273 
5274    printf("%*s %s\n", lw, "", "* = On  x = Dimmed");
5275    printf("%*s  1..4...8.......16\n", lw, "Unit:");
5276    for ( hc = 'A'; hc <= 'P'; hc++ ) {
5277       hcode = hc2code(hc);
5278 
5279       for ( j = 0; j < 16; j++ ) {
5280          unit = code2unit(j) - 1;
5281          if ( x10state[hcode].state[DimState] & (1 << j) ) {
5282             outbuf[unit] = chrs[1];
5283          }
5284          else if ( x10state[hcode].state[OnState] & (1 << j) ) {
5285             outbuf[unit] = chrs[0];
5286          }
5287          else
5288             outbuf[unit] = chrs[2];
5289       }
5290       sprintf(label, "Housecode %c", hc);
5291       outbuf[16] = '\0';
5292       printf("%*s (%s)\n", lw, label, outbuf);
5293    }
5294    return;
5295 }
5296 
5297 /*---------------------------------------------------------------------+
5298  | Display the flag states, including night and dark flags             |
5299  +---------------------------------------------------------------------*/
show_flags_old(void)5300 void show_flags_old ( void )
5301 {
5302    int           j, lw = 13;
5303    char          *chrs = "01-";
5304    char          outbuf[64];
5305    int           offset = 0;
5306 
5307    for ( j = 0; j < (int)sizeof(outbuf); j++ )
5308       outbuf[j] = ' ';
5309 
5310    printf("%*s %s\n\n", lw, "Flag states", "0 = Clear  1 = Set");
5311    printf("%*s  1..4...8.......16    night dark\n", lw, "Flag:");
5312 
5313    outbuf[offset++] = '(';
5314 
5315    for ( j = 0; j < 16; j++ ) {
5316       if ( x10global.flags[0] & (1 << j) )
5317          outbuf[offset] = chrs[1];
5318       else
5319          outbuf[offset] = chrs[0];
5320       offset++;
5321    }
5322    outbuf[offset++] = ')';
5323    for ( j = 16; j < 18; j++ ) {
5324       offset += 6;
5325       if ( x10global.sflags & (1 << j) )
5326          outbuf[offset] = x10global.dawndusk_enable ? chrs[1] : chrs[2];
5327       else
5328          outbuf[offset] = x10global.dawndusk_enable ? chrs[0] : chrs[2];
5329    }
5330 
5331    outbuf[++offset] = '\0';
5332 
5333    printf("%*s %s\n\n", lw, "", outbuf);
5334 
5335    offset = 0;
5336    printf("%*s  1..4...8.......16\n", lw, "CzFlag:");
5337    outbuf[offset++] = '(';
5338 
5339    for ( j = 0; j < 16; j++ ) {
5340       if ( x10global.czflags[0] & (1 << j) )
5341          outbuf[offset] = chrs[1];
5342       else
5343          outbuf[offset] = chrs[0];
5344       offset++;
5345    }
5346    outbuf[offset++] = ')';
5347    outbuf[++offset] = '\0';
5348 
5349    printf("%*s %s\n\n", lw, "", outbuf);
5350 
5351    return;
5352 }
5353 
5354 
5355 /*---------------------------------------------------------------------+
5356  | Display the flag states, including night and dark flags             |
5357  +---------------------------------------------------------------------*/
show_geoflags(void)5358 void show_geoflags ( void )
5359 {
5360    int           j, lw = 13;
5361    char          *chrs = "01-";
5362    char          outbuf[64];
5363    int           offset = 0;
5364 
5365    for ( j = 0; j < (int)sizeof(outbuf); j++ )
5366       outbuf[j] = ' ';
5367 
5368    printf("%*s %s\n\n", lw, "Flag states", "0 = Clear  1 = Set");
5369    printf("%*s  1..4...8.......16    night dark\n", lw, "Flag:");
5370 
5371    outbuf[offset++] = '(';
5372 
5373    for ( j = 0; j < 16; j++ ) {
5374 #if 0
5375       if ( x10global.sflags & (1 << j) )
5376 #endif
5377       if ( x10global.flags[0] & (1 << j) )
5378          outbuf[offset] = chrs[1];
5379       else
5380          outbuf[offset] = chrs[0];
5381       offset++;
5382    }
5383    outbuf[offset++] = ')';
5384    for ( j = 16; j < 18; j++ ) {
5385       offset += 6;
5386       if ( x10global.sflags & (1 << j) )
5387          outbuf[offset] = x10global.dawndusk_enable ? chrs[1] : chrs[2];
5388       else
5389          outbuf[offset] = x10global.dawndusk_enable ? chrs[0] : chrs[2];
5390    }
5391 
5392    outbuf[++offset] = '\0';
5393 
5394    printf("%*s %s\n\n", lw, "", outbuf);
5395 
5396    return;
5397 }
5398 
5399 /*---------------------------------------------------------------------+
5400  | Display the flag/czflag/tzflag states, plus night and dark flags    |
5401  +---------------------------------------------------------------------*/
5402 #define INDENT 12
5403 #define FLAGS_GROUP 4
5404 
show_long_flags(void)5405 void show_long_flags ( void )
5406 {
5407    int j, k;
5408    unsigned long mask;
5409    char *chrs = "01-";
5410 
5411    for ( j = 0; j < NUM_FLAG_BANKS; j++ ) {
5412       if ( (32 * NUM_FLAG_BANKS) >= 100 ) {
5413          printf("\n%*s", INDENT, " ");
5414          for ( k = 0; k < 32; k += FLAGS_GROUP )
5415             printf("%-*d", FLAGS_GROUP + 1, (j * 32 + 1 + k) / 100);
5416       }
5417       printf("\n%*s", INDENT, " ");
5418       for ( k = 0; k < 32; k += FLAGS_GROUP )
5419          printf("%-*d", FLAGS_GROUP + 1, ((j * 32 + 1 + k) % 100) / 10);
5420       printf("\n     Flag:  ");
5421       for ( k = 0; k < 32; k += FLAGS_GROUP )
5422          printf("%-*d", FLAGS_GROUP + 1, (j * 32 + 1 + k) % 10);
5423       if ( j == 0 )
5424          printf("    night   dark");
5425       printf("\n%*s(", INDENT - 1, " ");
5426 
5427       mask = 1;
5428       for ( k = 0; k < 32; k++ ) {
5429          if ( !(k % FLAGS_GROUP) && k > 0 )
5430             printf(" ");
5431          printf("%c", ((x10global.flags[j] & mask) ? chrs[1] : chrs[0]) );
5432          mask <<= 1;
5433       }
5434       printf(")");
5435 
5436       if ( j == 0 && x10global.dawndusk_enable ) {
5437          printf("      %c", ((x10global.sflags & NIGHT_FLAG) ? chrs[1] : chrs[0]) );
5438          printf("       %c", ((x10global.sflags & DARK_FLAG) ? chrs[1] : chrs[0]) );
5439       }
5440       else if ( j == 0 )
5441          printf("      -       -");
5442 
5443       printf("\n");
5444 
5445    }
5446    for ( j = 0; j < NUM_COUNTER_BANKS; j++ ) {
5447       if ( (32 * NUM_COUNTER_BANKS) >= 100 ) {
5448          printf("\n%*s", INDENT, " ");
5449          for ( k = 0; k < 32; k += FLAGS_GROUP )
5450             printf("%-*d", FLAGS_GROUP + 1, (j * 32 + 1 + k) / 100);
5451       }
5452       printf("\n%*s", INDENT, " ");
5453       for ( k = 0; k < 32; k += FLAGS_GROUP )
5454          printf("%-*d", FLAGS_GROUP + 1, ((j * 32 + 1 + k) % 100) / 10);
5455       printf("\n   CzFlag:  ");
5456       for ( k = 0; k < 32; k += FLAGS_GROUP )
5457          printf("%-*d", FLAGS_GROUP + 1, (j * 32 + 1 + k) % 10);
5458       printf("\n%*s(", INDENT - 1, " ");
5459 
5460       mask = 1;
5461       for ( k = 0; k < 32; k++ ) {
5462          if ( !(k % FLAGS_GROUP) && k > 0 )
5463             printf(" ");
5464          printf("%c", ((x10global.czflags[j] & mask) ? chrs[1] : chrs[0]) );
5465          mask <<= 1;
5466       }
5467       printf(")\n");
5468    }
5469    printf("\n");
5470 
5471    for ( j = 0; j < NUM_TIMER_BANKS; j++ ) {
5472       if ( (32 * NUM_TIMER_BANKS) >= 100 ) {
5473          printf("\n%*s", INDENT, " ");
5474          for ( k = 0; k < 32; k += FLAGS_GROUP )
5475             printf("%-*d", FLAGS_GROUP + 1, (j * 32 + 1 + k) / 100);
5476       }
5477       printf("\n%*s", INDENT, " ");
5478       for ( k = 0; k < 32; k += FLAGS_GROUP )
5479          printf("%-*d", FLAGS_GROUP + 1, ((j * 32 + 1 + k) % 100) / 10);
5480       printf("\n   TzFlag:  ");
5481       for ( k = 0; k < 32; k += FLAGS_GROUP )
5482          printf("%-*d", FLAGS_GROUP + 1, (j * 32 + 1 + k) % 10);
5483       printf("\n%*s(", INDENT - 1, " ");
5484 
5485       mask = 1UL;
5486       for ( k = 0; k < 32; k++ ) {
5487          if ( !(k % FLAGS_GROUP) && k > 0 )
5488             printf(" ");
5489          printf("%c", ((x10global.tzflags[j] & mask) ? chrs[1] : chrs[0]) );
5490          mask <<= 1;
5491       }
5492       printf(")\n");
5493    }
5494    printf("\n");
5495 
5496    return;
5497 }
5498 
5499 
5500 /*---------------------------------------------------------------------+
5501  | Function to delete the X10state file.                               |
5502  +---------------------------------------------------------------------*/
remove_x10state_file(void)5503 void remove_x10state_file ( void )
5504 {
5505    int   code;
5506 
5507    code = remove( statefile ) ;
5508    if ( code != 0 && errno != 2 ) {
5509       (void)fprintf(stderr,
5510          "WARNING: Unable to delete X10 State File %s - errno = %d\n",
5511           statefile, errno);
5512    }
5513    return;
5514 }
5515 
5516 /*---------------------------------------------------------------------+
5517  | Function to write the x10state structure to the X10state file.      |
5518  +---------------------------------------------------------------------*/
write_x10state_file(void)5519 void write_x10state_file ( void )
5520 {
5521    FILE *fd;
5522 
5523    if ( !i_am_state )
5524       return;
5525 
5526    if ( verbose )
5527       fprintf(stderr, "Writing state file\n");
5528 
5529    if ( !(fd = fopen(statefile, "w")) ) {
5530       fprintf(stderr, "Unable to open X10 State File '%s' for writing.\n",
5531          statefile);
5532       exit(1);
5533    }
5534 
5535    x10global.filestamp = time(NULL);
5536    if ( fwrite((void *)(&x10global), 1, (sizeof(x10global)), fd) != sizeof(x10global) ) {
5537       fprintf(stderr, "Unable to write X10 State File.\n");
5538    }
5539 
5540    fclose(fd);
5541    return;
5542 }
5543 
5544 /*---------------------------------------------------------------------+
5545  | Get the last-modified time of the x10state file.                    |
5546  +---------------------------------------------------------------------*/
modtime_x10state_file(void)5547 long int modtime_x10state_file ( void )
5548 {
5549    struct stat statbuf;
5550    int retcode;
5551 
5552    retcode = stat(statefile, &statbuf);
5553 
5554    if ( retcode == 0 )
5555       return statbuf.st_mtime;
5556 
5557    return (long)retcode;
5558 }
5559 
5560 /*---------------------------------------------------------------------+
5561  | Verify that the state engine is running by checking for its lock    |
5562  | file.                                                               |
5563  +---------------------------------------------------------------------*/
check_for_engine(void)5564 int check_for_engine ( void )
5565 {
5566    struct stat statbuf;
5567    int retcode;
5568 
5569    retcode = stat(enginelockfile, &statbuf);
5570 
5571    return retcode;
5572 }
5573 
5574 /*---------------------------------------------------------------------+
5575  | Function to read the x10state file and store the contents in the    |
5576  | x10state structure.                                                 |
5577  +---------------------------------------------------------------------*/
read_x10state_file(void)5578 int read_x10state_file (void )
5579 {
5580    FILE *fd = NULL;  /* Keep some compilers happy; ditto with nread */
5581    int  j, nread = 0;
5582    unsigned char inbuffer[sizeof(x10global) + 8];
5583 
5584    for ( j = 0; j < 3; j++ ) {
5585       if ( (fd = fopen(statefile, "r")) == NULL ) {
5586          millisleep(100);
5587          continue;
5588       }
5589       nread = fread((void *)inbuffer, 1, (sizeof(x10global) + 1), fd );
5590       fclose(fd);
5591       if ( nread == (sizeof(x10global)) ) {
5592          memcpy((void *)(&x10global), inbuffer, nread);
5593          break;
5594       }
5595       millisleep(100);
5596    }
5597 
5598    if ( nread != (sizeof(x10global)) ) {
5599       return 2;
5600    }
5601    return 0;
5602 }
5603 #if 0
5604 /*---------------------------------------------------------------------+
5605  | Function to read the x10state file and store the contents in the    |
5606  | x10state structure.                                                 |
5607  +---------------------------------------------------------------------*/
5608 int read_x10state_file (void )
5609 {
5610    FILE *fd = NULL;  /* Keep some compilers happy; ditto with nread */
5611    int  j, nread = 0;
5612    unsigned char inbuffer[sizeof(x10global) + 8];
5613 
5614    for ( j = 0; j < 3; j++ ) {
5615       if ( (fd = fopen(statefile, "r")) )
5616          break;
5617       millisleep(100);
5618    }
5619 
5620    if ( !fd ) {
5621       return 1;
5622    }
5623 
5624    for ( j = 0; j < 3; j++ ) {
5625       nread = fread((void *)inbuffer, 1, (sizeof(x10global) + 1), fd );
5626       if ( nread == (sizeof(x10global)) ) {
5627          memcpy((void *)(&x10global), inbuffer, nread);
5628          break;
5629       }
5630       rewind(fd);
5631       millisleep(100);
5632    }
5633 
5634    if ( nread != (sizeof(x10global)) ) {
5635       return 2;
5636    }
5637    fclose(fd);
5638    return 0;
5639 }
5640 #endif
5641 
5642 /*---------------------------------------------------------------------+
5643  | Send command to heyu_engine process to write the x10 state file,    |
5644  | then read it and store in the state structure.                      |
5645  +---------------------------------------------------------------------*/
fetch_x10state(void)5646 int fetch_x10state ( void )
5647 {
5648    struct stat statbuf;
5649    int         j, retcode;
5650    time_t      now;
5651    int         retries = 20;
5652 
5653    if ( check_for_engine() != 0 ) {
5654       fprintf(stderr, "State engine is not running.\n");
5655       return 1;
5656    }
5657 
5658    now = time(NULL);
5659    send_x10state_command(ST_WRITE, 0);
5660    for ( j = 0; j < retries; j++ ) {
5661       if ( (retcode = stat(statefile, &statbuf)) == 0 &&
5662            read_x10state_file() == 0  &&
5663            x10global.filestamp >= now ) {
5664          break;
5665       }
5666       millisleep(100);
5667    }
5668    if ( j >= retries ) {
5669       fprintf(stderr, "Unable to read current x10state - is state engine running?\n");
5670       return 1;
5671    }
5672 
5673    return 0;
5674 }
5675 
5676 
5677 /*---------------------------------------------------------------------+
5678  | Send command to heyu_engine process to write the x10 state file,    |
5679  | then read it and store in the state structure.                      |
5680  +---------------------------------------------------------------------*/
fetch_x10state_old(void)5681 int fetch_x10state_old ( void )
5682 {
5683    struct stat statbuf;
5684    int         j, retcode;
5685    time_t      now;
5686    int         retries = 50;
5687 
5688    if ( check_for_engine() != 0 ) {
5689       fprintf(stderr, "State engine is not running.\n");
5690       return 1;
5691    }
5692 
5693    time(&now);
5694    send_x10state_command(ST_WRITE, 0);
5695    for ( j = 0; j < retries; j++ ) {
5696       if ( (retcode = stat(statefile, &statbuf)) == 0 &&
5697            statbuf.st_mtime >= now ) {
5698          if ( read_x10state_file() == 0 )
5699             break;
5700       }
5701       millisleep(100);
5702    }
5703    if ( j >= retries ) {
5704       fprintf(stderr, "Unable to read current x10state - is state engine running?\n");
5705       return 1;
5706    }
5707 
5708    return 0;
5709 }
5710 
5711 /*---------------------------------------------------------------------+
5712  | Identify the type of data read from the spoolfile which was written |
5713  | there by heyu, i.e., excluding data received from the interface.    |
5714  +---------------------------------------------------------------------*/
identify_sent(unsigned char * buf,int len,unsigned char * chksum)5715 int identify_sent ( unsigned char *buf, int len, unsigned char *chksum )
5716 {
5717    int type;
5718 
5719    *chksum = checksum(buf, len);
5720 
5721    if ( buf[0] == 0 && len == 1 )
5722       type = SENT_WRMI;  /* WRMI */
5723    else if ( buf[0] == 0x04 && len == 2 )
5724       type = SENT_ADDR;  /* Address */
5725    else if ( (buf[0] & 0x07) == 0x06 && len == 2 )
5726       type = SENT_FUNC;  /* Standard Function */
5727    else if ( buf[0] == 0x07 && len == 5 )
5728       type = SENT_EXTFUNC;  /* Extended function */
5729    else if ( buf[0] == ST_COMMAND && buf[1] == ST_XMITRF && len == 6 )
5730       type = SENT_RF; /* CM17A command */
5731    else if ( buf[0] == ST_COMMAND && buf[1] == ST_MSG &&
5732              len == (buf[2] + 3) )
5733       type = SENT_MESSAGE; /* Display message */
5734    else if ( buf[0] == ST_COMMAND && buf[1] == ST_VDATA && len == 9 )
5735       type = SENT_VDATA; /* Virtual data */
5736    else if ( buf[0] == ST_COMMAND && buf[1] == ST_LONGVDATA )
5737       type = SENT_LONGVDATA; /* Virtual data */
5738    else if ( buf[0] == ST_COMMAND && buf[1] == ST_GENLONG )
5739       type = SENT_GENLONG;
5740    else if ( buf[0] == ST_COMMAND && buf[1] == ST_FLAGS && len == 5 )
5741       type = SENT_FLAGS;  /* Update flag states */
5742    else if ( buf[0] == ST_COMMAND && buf[1] == ST_FLAGS32 && len == 8 )
5743       type = SENT_FLAGS32;  /* Update flag states */
5744    else if ( buf[0] == ST_COMMAND && buf[1] == ST_COUNTER /* && len == 7 */)
5745       type = SENT_COUNTER;  /* Set, Increment, or Decrement counter */
5746    else if ( buf[0] == ST_COMMAND && buf[1] == ST_CLRSTATUS && len == 5 )
5747       type = SENT_CLRSTATUS; /* Clear status flags */
5748    else if ( buf[0] == ST_COMMAND && buf[1] == ST_PFAIL && len == 3 )
5749       type = SENT_PFAIL;  /* Relay reports a powerfail update */
5750    else if ( buf[0] == ST_COMMAND && buf[1] == ST_RFFLOOD && len == 3 )
5751       type = SENT_RFFLOOD; /* Aux reports an RF Flood */
5752    else if ( buf[0] == ST_COMMAND && buf[1] == ST_LOCKUP && len == 3 )
5753       type = SENT_LOCKUP; /* Relay reports a CM11A lockup condition */
5754    else if ( buf[0] == ST_COMMAND && buf[1] == ST_RFXTYPE && len == 4 )
5755       type = SENT_RFXTYPE; /* An RFXSerial initialization packet */
5756    else if ( buf[0] == ST_COMMAND && buf[1] == ST_RFXSERIAL && len == 10 )
5757       type = SENT_RFXSERIAL; /* An RFXSerial initialization packet */
5758    else if ( buf[0] == ST_COMMAND && buf[1] == ST_SHOWBUFFER )
5759       type = SENT_SHOWBUFFER; /* Display a binary buffer */
5760    else if ( buf[0] == ST_COMMAND && buf[1] == ST_VARIABLE_LEN ) {
5761       if ( buf[2] == RF_KAKU )
5762          type = SENT_KAKU; /* KaKu signal */
5763       else if ( buf[2] == RF_VISONIC )
5764          type = SENT_VISONIC;  /* Visonic signal */
5765       else
5766          type = SENT_RFVARIABLE; /* An RFXSerial raw or noise packet */
5767    }
5768    else if ( buf[0] == ST_COMMAND && len == 3 )
5769       type = SENT_STCMD;  /* Monitor/state control command */
5770    else if ( buf[0] == 0x0C && len == 2 && buf[1] == 0x56 )
5771       type = SENT_ADDR;  /* Address of G1 with 5a fix */
5772    else if ( buf[0] == 0x0F && len == 5 && *chksum == 0x62 )
5773       type = SENT_EXTFUNC;  /* Extended function with 5a fix */
5774    else if ( buf[0] == ST_COMMAND && buf[1] == ST_SETTIMER && len == 8 )
5775       type = SENT_SETTIMER; /* Set a countdown timer */
5776    else if ( buf[0] == ST_COMMAND && buf[1] == ST_ORE_EMU )
5777       type = SENT_ORE_EMU;  /* Oregon emulation */
5778    else if ( buf[0] == ST_COMMAND && buf[1] == ST_SCRIPT /*&& len == 7*/ )
5779       type = SENT_SCRIPT; /* heyu launch command */
5780    else if ( buf[0] == ST_COMMAND && buf[1] == ST_INIT && len == 5 )
5781       type = SENT_INITSTATE; /* Initstate command */
5782    else
5783       type = SENT_OTHER;  /* Other, i.e., info, setclock, upload, etc. */
5784 
5785    return type;
5786 }
5787 
5788 
create_flagslist(unsigned char vtype,unsigned long vflags,char * flagslist)5789 void create_flagslist ( unsigned char vtype, unsigned long vflags, char *flagslist )
5790 {
5791 
5792    if ( vtype == RF_SEC ) {
5793       if ( vflags & SEC_TAMPER )
5794          strcat(flagslist, "Tamper ");
5795       if ( vflags & SEC_MAIN )
5796          strcat(flagslist, "Main ");
5797       if ( vflags & SEC_AUX )
5798          strcat(flagslist, "Aux ");
5799       if ( vflags & SEC_HOME )
5800          strcat(flagslist, "swHome ");
5801       if ( vflags & SEC_AWAY )
5802          strcat(flagslist, "swAway ");
5803       if ( vflags & SEC_MIN )
5804          strcat(flagslist, "swMin ");
5805       if ( vflags & SEC_MAX )
5806          strcat(flagslist, "swMax ");
5807       if ( vflags & SEC_LOBAT )
5808          strcat(flagslist, "LoBat ");
5809    }
5810    if ( vtype == RF_OREGON ) {
5811       if ( vflags & ORE_TMIN )
5812          strcat(flagslist, "TmiN ");
5813       if ( vflags & ORE_TMAX )
5814          strcat(flagslist, "TmaX ");
5815       if ( vflags & ORE_RHMIN )
5816          strcat(flagslist, "RHmiN ");
5817       if ( vflags & ORE_RHMAX )
5818          strcat(flagslist, "RHmaX ");
5819       if ( vflags & ORE_BPMIN )
5820          strcat(flagslist, "BPmiN ");
5821       if ( vflags & ORE_BPMAX )
5822          strcat(flagslist, "BPmaX ");
5823       if ( vflags & SEC_LOBAT )
5824          strcat(flagslist, "LoBat ");
5825       if ( vflags & RFX_ROLLOVER )
5826          strcat(flagslist, "rollover ");
5827    }
5828    if ( vtype == RF_ELECSAVE || vtype == RF_OWL ) {
5829       if ( vflags & SEC_LOBAT )
5830          strcat(flagslist, "LoBat ");
5831       if ( vflags & RFX_ROLLOVER )
5832          strcat(flagslist, "rollover ");
5833    }
5834    if ( vtype == RF_DIGIMAX ) {
5835       if ( vflags & DMX_INIT )
5836          strcat(flagslist, "Init ");
5837       if ( vflags & DMX_SET )
5838          strcat(flagslist, "Set ");
5839       else
5840          strcat(flagslist, "NotSet ");
5841       if ( vflags & DMX_HEAT )
5842          strcat(flagslist, "Heat ");
5843       else
5844          strcat(flagslist, "Cool ");
5845    }
5846 
5847    return;
5848 }
5849 
5850 /*---------------------------------------------------------------------+
5851  | Interpret Virtual data string, update the state, and test whether   |
5852  | any launch condition is satisfied.                                  |
5853  | buffer references:                                                  |
5854  |  ST_COMMAND, ST_VDATA, addr, vdata, vtype, vident, videnthi, hibyte, lobyte   |
5855  +---------------------------------------------------------------------*/
translate_virtual(unsigned char * buf,int len,unsigned char * sunchanged,int * launchp)5856 char *translate_virtual ( unsigned char *buf, int len, unsigned char *sunchanged, int *launchp )
5857 {
5858    static char outbuf[120];
5859    static char intvstr[32];
5860    long intv;
5861    char flagslist[80];
5862    char vdatabuf[32];
5863    char hc;
5864    int  j, k, found, index = -1;
5865    unsigned char hcode, ucode, unit, func, vdata, vtype, /*vident,*/ byte2, byte3;
5866 //   unsigned short vident, idmask;
5867    unsigned long vident, idmask;
5868    unsigned int bitmap;
5869    unsigned long vflags = 0;
5870    /* unsigned long flood; */
5871    ALIAS *aliasp;
5872    static char *typename[] = {"Std", "Ent", "Sec", "RFXSensor", "RFXMeter", "Dusk", "Visonic", "Noise"};
5873 
5874 #ifdef HASRFXS
5875    char *marker = "";
5876    char valbuf[60];
5877    int  stype;
5878    unsigned int inmap, outmap;
5879    double temperature, vsup, var2, advolt;
5880    extern int x10state_update_rfxsensor ( unsigned char *, int, int * );
5881 #endif
5882    *launchp = -1;
5883    *sunchanged = 0;
5884    flagslist[0] = '\0';
5885 
5886    aliasp = config.aliasp;
5887 
5888    vdata  = buf[3];
5889    vtype  = buf[4];
5890 //   vident = buf[5] | (buf[6] << 8);
5891    byte2  = buf[7];
5892    byte3  = buf[8];
5893    func   = VdataFunc;
5894 
5895 if ( vtype == RF_VISONIC ) {
5896    vident = buf[5] | (buf[6] << 8) | (buf[7] << 16);
5897 }
5898 else {
5899    vident = buf[5] | (buf[6] << 8);
5900 }
5901 
5902    x10global.longvdata = 0;
5903    x10global.lastvtype = vtype;
5904 
5905    if ( vtype == RF_STD || vtype == RF_VDATAM ) {
5906       hcode = (buf[2] & 0xf0u) >> 4;
5907       hc = code2hc(hcode);
5908       ucode = buf[2] & 0x0fu;
5909       bitmap = (1 << ucode);
5910       unit = code2unit(ucode);
5911       vdata = buf[3];
5912       func = (vtype == RF_VDATAM) ? VdataMFunc : VdataFunc;
5913       if ( x10state_update_virtual(buf + 2, len - 2, launchp) != 0 )
5914          return "";
5915       sprintf(outbuf, "func %12s : hu %c%-2d vdata 0x%02x (%s)",
5916          funclabel[func], hc, unit, vdata, lookup_label(hc, (1 << ucode)));
5917       return outbuf;
5918    }
5919 
5920    if ( vtype == RF_DUSK || vtype == RF_SECX ) {
5921       *vdatabuf = '\0';
5922       hcode = (buf[2] & 0xf0u) >> 4;
5923       hc = code2hc(hcode);
5924       ucode = buf[2] & 0x0fu;
5925       bitmap = 1 << ucode;
5926       unit = code2unit(ucode);
5927       if ( vdata == 0xf0u )
5928          func = DuskFunc;
5929       else if ( vdata == 0xf8u )
5930          func = DawnFunc;
5931       else if ( vdata == 0xe0u )
5932          func = AlertFunc;
5933       else {
5934          func = VdataFunc;
5935          sprintf(vdatabuf, "vdata 0x%02x ", vdata);
5936       }
5937       if ( x10state_update_duskdawn(buf + 2, len -2, launchp) != 0 )
5938          return "";
5939       sprintf(outbuf, "func %12s : hu %c%d %s(%s)", funclabel[func], hc, unit, vdatabuf, lookup_label(hc, bitmap));
5940       return outbuf;
5941    }
5942 
5943    if ( vtype == RF_FLOOD ) {
5944       if ( vdata & SEC_FLOOD )
5945          x10global.sflags |= GLOBSEC_FLOOD;
5946       else
5947          x10global.sflags &= ~GLOBSEC_FLOOD;
5948       sprintf(outbuf, "           RF Flood : %s", ((vdata & SEC_FLOOD) ? "Started" : "Ended"));
5949       *launchp = find_rfflood_scripts();
5950       return outbuf;
5951    }
5952 
5953    if ( vtype == RF_XJAM ) {
5954       if ( vdata == 0xe0u ) {
5955          x10global.vflags |= RFX_JAM;
5956          x10global.sflags |= GLOBSEC_RFXJAM;
5957       }
5958       else {
5959          x10global.vflags &= ~RFX_JAM;
5960          x10global.sflags &= ~GLOBSEC_RFXJAM;
5961       }
5962       if ( vident == 0xffu ) {
5963          x10global.vflags |= SEC_MAIN;
5964          x10global.vflags &= ~SEC_AUX;
5965       }
5966       else {
5967          x10global.vflags &= ~SEC_MAIN;
5968          x10global.vflags |= SEC_AUX;
5969       }
5970       sprintf(outbuf, "         RF Jamming : %s %s",
5971        ((vdata == 0xe0u) ? "Started" : "Ended"),
5972        ((vident == 0xffu) ? "Main" : "Aux") );
5973       *launchp = find_rfxjam_scripts();
5974       return outbuf;
5975    }
5976 
5977    if ( vtype == RF_XJAM32 ) {
5978       if ( vident == 0x07u ) {
5979          x10global.vflags |= RFX_JAM;
5980          x10global.sflags |= GLOBSEC_RFXJAM;
5981       }
5982       else {
5983          x10global.vflags &= ~RFX_JAM;
5984          x10global.sflags &= ~GLOBSEC_RFXJAM;
5985       }
5986       if ( vdata == 0xffu ) {
5987          x10global.vflags |= SEC_MAIN;
5988          x10global.vflags &= ~SEC_AUX;
5989       }
5990       else {
5991          x10global.vflags &= ~SEC_MAIN;
5992          x10global.vflags |= SEC_AUX;
5993       }
5994       sprintf(outbuf, "         RF Jamming : %s %s",
5995        ((vident == 0x07u) ? "Started" : "Ended"),
5996        ((vdata == 0xffu) ? "Main" : "Aux") );
5997       *launchp = find_rfxjam_scripts();
5998       return outbuf;
5999    }
6000 
6001 //   if ( vtype == RF_SEC || vtype == RF_ENT ) {
6002    if ( vtype == RF_SEC || vtype == RF_ENT || vtype == RF_VISONIC ) {
6003       idmask = (vtype == RF_SEC) ? configp->securid_mask : 0xffffu;
6004       hcode = ucode = 0;
6005       found = 0;
6006       j = 0;
6007       /* Look up the alias, if any */
6008       while ( !found && aliasp && aliasp[j].line_no > 0 ) {
6009          if ( aliasp[j].vtype == vtype &&
6010               (bitmap = aliasp[j].unitbmap) > 0 &&
6011               (ucode = single_bmap_unit(bitmap)) != 0xff ) {
6012             for ( k = 0; k < aliasp[j].nident; k++ ) {
6013                if ( (aliasp[j].ident[k] & idmask) == (vident & idmask) ) {
6014                   index = j;
6015                   found = 1;
6016                   break;
6017                }
6018             }
6019          }
6020          j++;
6021       }
6022 
6023       if ( !found || !aliasp ) {
6024          sprintf(outbuf, "func %12s : Type %s ID 0x%02lX Data 0x%02X",
6025            "RFdata", typename[vtype], vident, vdata);
6026          return outbuf;
6027       }
6028 
6029       x10global.longvdata = (vident << 8) | vdata;
6030 
6031       hc = aliasp[index].housecode;
6032       hcode = hc2code(hc);
6033       unit = code2unit(ucode);
6034 
6035       /* Save interval since last transmission */
6036       intvstrfunc(intvstr, &intv, time(NULL), x10state[hcode].timestamp[ucode]);
6037       x10global.interval = intv;
6038 
6039 #if 0
6040       /* Update activity timeout for security sensors with heartbeat */
6041       update_activity_timeout(aliasp, index);
6042       update_activity_states(hcode, (1 << ucode), S_ACTIVE);
6043 #endif
6044 
6045       /* Add address to buf and update the state */
6046       buf[2] = (hcode & 0x0fu) << 4 | (ucode & 0x0fu);
6047       if ( x10state_update_virtual(buf + 2, len - 2, launchp) != 0 )
6048          return "";
6049 
6050       func = x10state[hcode].lastcmd;
6051       vflags = x10state[hcode].vflags[ucode];
6052       create_flagslist(vtype, vflags, flagslist);
6053 
6054       if ( vtype == RF_SEC ) {
6055          if ( func == VdataFunc ) {
6056             sprintf(outbuf, "func %12s : hu %c%-2d vdata 0x%02x %s (%s)",
6057               funclabel[func], hc, unit, vdata, flagslist, aliasp[index].label);
6058          }
6059          else {
6060             sprintf(outbuf, "func %12s : hu %c%-2d %s (%s)",
6061                 funclabel[func], hc, unit, flagslist, aliasp[index].label);
6062          }
6063 
6064          if ( (aliasp[index].optflags & MOPT_HEARTBEAT) &&
6065               (x10state[hcode].state[ChgState] & (1 << ucode)) == 0 ) {
6066             *sunchanged = 1;
6067          }
6068 
6069          if ( configp->display_sensor_intv == YES && (aliasp[index].optflags & MOPT_HEARTBEAT) ) {
6070             snprintf(outbuf + strlen(outbuf), sizeof(outbuf), " Intv %s ", intvstr);
6071          }
6072 
6073          if ( configp->show_change == YES ) {
6074             if ( x10state[hcode].state[ChgState] & (1 << ucode) ) {
6075                strcat(outbuf, " Chg");
6076             }
6077             else {
6078                strcat(outbuf, " UnChg");
6079             }
6080          }
6081       }
6082       else if ( vtype == RF_ENT && aliasp[index].nident == 1 ) {
6083          sprintf(outbuf, "func %12s : hu %c%-2d vdata 0x%02X (%s)",
6084            funclabel[func], hc, unit, vdata, aliasp[index].label);
6085       }
6086       else if ( vtype == RF_ENT ) {
6087          sprintf(outbuf, "func %12s : hu %c%-2d lvdata 0x%04lX (%s)",
6088            funclabel[func], hc, unit, x10global.longvdata, aliasp[index].label);
6089       }
6090       else {
6091          sprintf(outbuf, "func %12s : hu %c%-2d vdata 0x%02X (%s)",
6092            funclabel[func], hc, unit, vdata, aliasp[index].label);
6093       }
6094    }
6095 #ifdef HASRFXS
6096    else if ( vtype == RF_XSENSOR ) {
6097       hcode = ucode = 0;
6098       found = 0;
6099       j = 0;
6100       /* Look up the alias, if any */
6101       while ( !found && aliasp && aliasp[j].line_no > 0 ) {
6102          if ( aliasp[j].vtype == vtype &&
6103               (bitmap = aliasp[j].unitbmap) > 0 &&
6104               (ucode = single_bmap_unit(bitmap)) != 0xff ) {
6105             for ( k = 0; k < aliasp[j].nident; k++ ) {
6106                if ( aliasp[j].ident[k] == vident ) {
6107                   index = j;
6108                   found = 1;
6109                   break;
6110                }
6111             }
6112          }
6113          j++;
6114       }
6115 
6116       if ( !found || !aliasp ) {
6117          marker = ((vident % 4) == 0) ? "*" : " ";
6118          sprintf(outbuf, "func %12s : Type %s ID 0x%02lX%s Data 0x%02X%02X",
6119            "RFdata", typename[vtype], vident, marker, byte2, byte3);
6120          return outbuf;
6121       }
6122 
6123       x10global.longvdata = (byte2 << 8) | byte3;
6124 
6125       hc = aliasp[index].housecode;
6126       hcode = hc2code(hc);
6127       unit = code2unit(ucode);
6128 
6129       /* Save interval since last transmission */
6130       intvstrfunc(intvstr, &intv, time(NULL), x10state[hcode].timestamp[ucode]);
6131 
6132 #if 0
6133       /* Update activity timeout for sensor */
6134       update_activity_timeout(aliasp, index);
6135       update_activity_states(hcode, (1 << ucode), S_ACTIVE);
6136 #endif
6137 
6138       /* Add address to buf and update the state */
6139       buf[2] = (hcode & 0x0fu) << 4 | (ucode & 0x0fu);
6140       if ( x10state_update_rfxsensor(buf + 2, len - 2, launchp) != 0 )
6141          return "";
6142 
6143       func = x10state[hcode].lastcmd;
6144       vflags = x10state[hcode].vflags[ucode];
6145       create_flagslist(vtype, vflags, flagslist);
6146 
6147 #if 0
6148       activechange = (configp->active_change == YES) ? x10state[hcode].state[ActiveChgState] : 0;
6149 
6150       /* Indicate whether no change in state for Sensor module */
6151       if ( (aliasp[index].optflags & MOPT_RFXSENSOR) &&
6152            ((x10state[hcode].state[ChgState] | activechange) & (1 << ucode)) == 0 ) {
6153          *sunchanged = 1;
6154       }
6155 #endif
6156       if ( (x10state[hcode].state[ChgState] & (1 << ucode)) == 0 )
6157          *sunchanged = 1;
6158 
6159       stype = vident % 4;
6160 
6161       if ( x10global.longvdata & 0x10u ) {
6162          if ( stype == RFX_S && byte2 == 0x02u ) {
6163             sprintf(outbuf, "func %12s : hu %c%-2d Low Battery (%s)",
6164                funclabel[func], hc, unit, aliasp[index].label);
6165          }
6166          else if ( byte2 & 0x80u ) {
6167             sprintf(outbuf, "func %12s : hu %c%-2d ID %02lX Error 0x%02X (%s)",
6168                funclabel[func], hc, unit, vident, byte2, aliasp[index].label);
6169          }
6170          else {
6171             sprintf(outbuf, "func %12s : hu %c%-2d ID %02lX Code 0x%02X (%s)",
6172                funclabel[func], hc, unit, vident, byte2, aliasp[index].label);
6173          }
6174          return outbuf;
6175       }
6176 
6177       decode_rfxsensor_data(aliasp, index, &inmap, &outmap, &temperature, &vsup, &advolt, &var2);
6178 
6179       if ( stype == RFX_T ) {
6180          sprintf(valbuf, FMT_RFXT, temperature);
6181          sprintf(outbuf, "func %12s : hu %c%-2d Temp %s%c (%s)",
6182             funclabel[func], hc, unit, valbuf, configp->rfx_tscale, aliasp[index].label);
6183       }
6184       else if ( stype == RFX_S ) {
6185          sprintf(outbuf, "func %12s : hu %c%-2d Vs %.2fV (%s)",
6186             funclabel[func], hc, unit, vsup, aliasp[index].label);
6187       }
6188       else if ( stype == RFX_H ) {
6189          if ( inmap & RFXO_H ) {
6190             if ( outmap & RFXO_H ) {
6191                sprintf(valbuf, FMT_RFXRH, var2);
6192                sprintf(outbuf, "func %12s : hu %c%-2d RH %s%% (%s)",
6193                   funclabel[func], hc, unit, valbuf, aliasp[index].label);
6194             }
6195             else {
6196                sprintf(outbuf, "func %12s : hu %c%-2d RH n/a (%s)",
6197                   funclabel[func], hc, unit, aliasp[index].label);
6198             }
6199          }
6200          else if ( inmap & RFXO_B ) {
6201             if ( outmap & RFXO_B ) {
6202                sprintf(valbuf, FMT_RFXBP, var2);
6203                sprintf(outbuf, "func %12s : hu %c%-2d BP %s %s (%s)",
6204                   funclabel[func], hc, unit, valbuf, configp->rfx_bpunits, aliasp[index].label);
6205             }
6206             else {
6207                sprintf(outbuf, "func %12s : hu %c%-2d BP n/a %s (%s)",
6208                   funclabel[func], hc, unit, configp->rfx_bpunits, aliasp[index].label);
6209             }
6210          }
6211          else if ( inmap & RFXO_P ) {
6212             if ( outmap & RFXO_P ) {
6213                sprintf(outbuf, "func %12s : hu %c%-2d Pot %.2f%% (%s)",
6214                   funclabel[func], hc, unit, var2, aliasp[index].label);
6215             }
6216             else {
6217                sprintf(outbuf, "func %12s : hu %c%-2d Pot n/a (%s)",
6218                   funclabel[func], hc, unit, aliasp[index].label);
6219             }
6220          }
6221          else if ( inmap & RFXO_V ) {
6222             sprintf(valbuf, FMT_RFXVAD, var2);
6223             sprintf(outbuf, "func %12s : hu %c%-2d Vad %s %s (%s)",
6224                funclabel[func], hc, unit, valbuf, configp->rfx_vadunits, aliasp[index].label);
6225          }
6226          else if ( inmap & RFXO_T2 ) {
6227             sprintf(valbuf, FMT_RFXT, temperature);
6228             sprintf(outbuf, "func %12s : hu %c%-2d Temp2 %s%c (%s)",
6229                funclabel[func], hc, unit, valbuf, configp->rfx_tscale, aliasp[index].label);
6230          }
6231          else {
6232             sprintf(outbuf, "func %12s : hu %c%-2d Vadi %.2fV (%s)",
6233                funclabel[func], hc, unit, advolt, aliasp[index].label);
6234          }
6235       }
6236 
6237       if ( configp->display_sensor_intv == YES && (aliasp[index].optflags & MOPT_HEARTBEAT) ) {
6238          snprintf(outbuf + strlen(outbuf), sizeof(outbuf), " Intv %s ", intvstr);
6239       }
6240       if ( configp->show_change == YES ) {
6241          snprintf(outbuf + strlen(outbuf), sizeof(outbuf), "%s", (*sunchanged ? " UnChg" : " Chg"));
6242       }
6243    }
6244 #endif /* HASRFXS */
6245    else if ( vtype == RF_RAWW800 ) {
6246       x10global.longvdata = (buf[3] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
6247       sprintf(outbuf, "func %12s : Data (hex) %02X %02X %02X %02X",
6248          "RFrawdata", buf[3], buf[5], buf[7], buf[8]);
6249    }
6250    else if ( vtype == RF_NOISEW800 ) {
6251       x10global.longvdata = (buf[3] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
6252       sprintf(outbuf, "func %12s : Data (hex) %02X %02X %02X %02X",
6253          "RFnoise", buf[3], buf[5], buf[7], buf[8]);
6254    }
6255    else if ( vtype == RF_RAWMR26 ) {
6256       x10global.longvdata = (buf[2] << 8) | buf[3];
6257       sprintf(outbuf, "func %12s : Data (hex) %02X %02X %02X %02X %02X",
6258          "RFrawdata", buf[2], buf[3], buf[5], buf[7], buf[8]);
6259    }
6260    else if ( vtype == RF_NOISEMR26 ) {
6261       x10global.longvdata = (buf[2] << 8) | buf[3];
6262       sprintf(outbuf, "func %12s : Data (hex) %02X %02X %02X %02X %02X",
6263          "RFnoise", buf[2], buf[3], buf[5], buf[7], buf[8]);
6264    }
6265    else {
6266       x10global.longvdata = (buf[3] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
6267       sprintf(outbuf, "func %12s : Type 0x%02x Data (hex) %02x %02x %02x %02x",
6268          "RFdata", vtype, buf[3], buf[5], buf[6], buf[7]);
6269    }
6270 
6271    return outbuf;
6272 }
6273 
6274 /*---------------------------------------------------------------------+
6275  | Interpret Virtual data string, update the state, and test whether   |
6276  | any launch condition is satisfied.                                  |
6277  | buffer references:                                                  |
6278  |  ST_COMMAND, ST_LONGVDATA, vtype, seq, vidhi, vidlo, nbytes, bytes 1-N   |
6279  +---------------------------------------------------------------------*/
translate_long_virtual(unsigned char * buf,unsigned char * sunchanged,int * launchp)6280 char *translate_long_virtual ( unsigned char *buf, unsigned char *sunchanged, int *launchp )
6281 {
6282    extern char *translate_rfxmeter ( unsigned char *, unsigned char *, int * );
6283    extern char *translate_digimax ( unsigned char *, unsigned char *, int * );
6284 
6285    if ( buf[2] == RF_XMETER )
6286       return translate_rfxmeter(buf, sunchanged, launchp);
6287    else if ( buf[2] == RF_DIGIMAX )
6288       return translate_digimax(buf, sunchanged, launchp);
6289 
6290    return "";
6291 }
6292 
6293 /*----------------------------------------------------------------------------+
6294  | Translate general aux data.                                                |
6295  | Buffer reference: ST_COMMAND, ST_GENLONG, plus:                            |
6296  |  vtype, subtype, vidhi, vidlo, seq, buflen, buffer                         |
6297  |   [2]     [3]     [4]    [5]   [6]    [7]    [8+]                          |
6298  +----------------------------------------------------------------------------*/
translate_gen_longdata(unsigned char * buff,unsigned char * sunchanged,int * launchp)6299 char *translate_gen_longdata ( unsigned char *buff, unsigned char *sunchanged, int *launchp )
6300 {
6301    if ( buff[2] == RF_OREGON || buff[2] == RF_ELECSAVE || buff[2] == RF_OWL ) {
6302       return translate_oregon(buff, sunchanged, launchp);
6303    }
6304    return "";
6305 }
6306 
6307 
6308 /*---------------------------------------------------------------------+
6309  | Interpret byte string sent to CM11A, update the state, and test     |
6310  | whether any launch condition is satisfied.                          |
6311  +---------------------------------------------------------------------*/
translate_sent(unsigned char * buf,int len,int * launchp)6312 char *translate_sent ( unsigned char *buf, int len, int *launchp )
6313 {
6314    static char outbuf[120];
6315    char hc;
6316    unsigned char hcode, func, level, unit, subunit, chksum;
6317    unsigned char xgroup, xfunc, xsubfunc, xtype, xdata;
6318    unsigned char newbuf[2];
6319    unsigned int bmap, memloc;
6320    int dims;
6321    double ddims;
6322    char *prefix, *suffix;
6323 
6324    *launchp = -1;
6325 
6326    chksum = checksum(buf, len);
6327 
6328    if ( buf[0] == 0 && len == 1 ) {
6329       return "";
6330    }
6331    else if ( (buf[0] == 0x04 && len == 2) ||
6332 	     (buf[0] == 0x0C && len == 2 && buf[1] == 0x56 ) ) {
6333       /* Address */
6334       hcode = (buf[1] & 0xf0u) >> 4;
6335       hc = code2hc(hcode);
6336       unit = code2unit(buf[1] & 0x0fu);
6337       bmap = 1 << (buf[1] & 0x0fu);
6338       x10state_update_addr(buf[1], launchp);
6339       sprintf(outbuf, "addr unit     %3d : hu %c%-2d (%s)",
6340          unit, hc, unit, lookup_label(hc, bmap));
6341       return outbuf;
6342    }
6343    else if ( (buf[0] & 0x07) == 0x06 && len == 2 ) {
6344       /* Standard function */
6345       level = (buf[0] & 0xf8u) >> 3;
6346       dims = level2dims(level, &prefix, &suffix);
6347       ddims = 100. * (double)dims / 210.;
6348       hcode = (buf[1] & 0xf0u) >> 4;
6349       hc = code2hc(hcode);
6350       func = buf[1] & 0x0f;
6351       if ( level > 0 && func != 4 && func != 5 ) {
6352          sprintf(outbuf, "Unknown transmission: %02x %02x", buf[0], buf[1]);
6353          return outbuf;
6354       }
6355       newbuf[0] = buf[1];
6356       newbuf[1] = dims;
6357 
6358       x10state_update_func(newbuf, launchp);
6359 
6360       switch ( func ) {
6361          case 4 :  /* Dim */
6362             sprintf(outbuf,
6363 		 "func %12s : hc %c dim %%%02.0f [%s%d%s]",
6364                funclabel[func], hc, ddims, prefix, dims, suffix);
6365             return outbuf;
6366          case 5 :  /* Bright */
6367             sprintf(outbuf,
6368 	         "func %12s : hc %c bright %%%02.0f [%s%d%s]",
6369                funclabel[func], hc, ddims, prefix, dims, suffix);
6370             return outbuf;
6371          case 10 : /* Preset level */
6372          case 11 : /* Preset level */
6373             level = rev_low_nybble(hcode) + 1;
6374             level += (func == 11) ? 16 : 0;
6375             sprintf(outbuf, "func %12s : level %d", funclabel[func], level);
6376             return outbuf;
6377          default:
6378             sprintf(outbuf, "func %12s : hc %c", funclabel[func], hc);
6379       }
6380    }
6381    else if ( (buf[0] == 0x07 && len == 5) ||
6382 	     (buf[0] == 0x0F && len == 5 && chksum == 0x62) ) {
6383       /* Extended code function */
6384       char stmp[16];
6385       if ( (buf[1] & 0x0fu) != 0x07 ) {
6386          sprintf(outbuf, "Unknown transmission: %02x %02x %02x %02x %02x",
6387              buf[0], buf[1], buf[2], buf[3], buf[4]);
6388          return outbuf;
6389       }
6390       hcode = (buf[1] & 0xf0u) >> 4;
6391       hc = code2hc(hcode);
6392       unit = code2unit(buf[2] & 0x0fu);
6393       subunit = (buf[2] & 0xf0u) >> 4;
6394       bmap = 1 << (buf[2] & 0x0fu);
6395       xfunc = buf[4];
6396       xtype = (xfunc & 0xf0u) >> 4;
6397       xdata = buf[3];
6398 
6399       if ( xtype == 3 ) {
6400          x10state_update_ext3func(buf + 1, launchp);
6401       }
6402 #ifdef HASEXT0
6403       else if ( xtype == 0 ) {
6404          x10state_update_ext0func(buf + 1, launchp);
6405       }
6406 #endif
6407       else {
6408          x10state_update_extotherfunc(buf + 1, launchp);
6409       }
6410 
6411       stmp[0] = '\0';
6412 
6413       if ( xfunc == 0x30 ) {
6414          if ( (xdata & 0x30u) == 0x20 )
6415             sprintf(outbuf, "func      xGrpAdd : hu %c%-2d%s group %d.%-2d (%s)",
6416                hc, unit, stmp, (xdata >> 6), (xdata & 0x0fu) + 1, lookup_label(hc, bmap));
6417          else
6418             sprintf(outbuf, "func      xGrpAdd : hu %c%-2d%s group %d (%s)",
6419                hc, unit, stmp, (xdata >> 6), lookup_label(hc, bmap));
6420       }
6421       else if ( xfunc == 0x31 ) {
6422          if ( xdata & 0xc0u ) {
6423             sprintf(outbuf, "func      xPreset : hu %c%-2d%s level %d ramp %d (%s)",
6424                hc, unit, stmp, xdata & 0x3fu, (xdata & 0xc0u) >> 6, lookup_label(hc, bmap));
6425          }
6426          else {
6427             sprintf(outbuf, "func      xPreset : hu %c%-2d%s level %d (%s)",
6428                hc, unit, stmp, xdata, lookup_label(hc, bmap));
6429          }
6430       }
6431       else if ( xfunc == 0x32 )
6432          sprintf(outbuf, "func   xGrpAddLvl : hu %c%-2d%s group %d level %d (%s)",
6433             hc, unit, stmp, ((xdata & 0xc0) >> 6), (xdata & 0x3f), lookup_label(hc, bmap));
6434       else if ( xfunc == 0x33 )
6435          sprintf(outbuf, "func       xAllOn : hc %c", hc);
6436       else if ( xfunc == 0x34 )
6437          sprintf(outbuf, "func      xAllOff : hc %c", hc);
6438       else if ( xfunc == 0x35 ) {
6439          if ( (xdata & 0x30) == 0 ) {
6440             sprintf(outbuf, "func      xGrpRem : hu %c%-2d%s group(s) %s (%s)",
6441                hc, unit, stmp, linmap2list(xdata & 0x0f), lookup_label(hc, bmap));
6442          }
6443          else {
6444             sprintf(outbuf, "func   xGrpRemAll : hc %c group(s) %s",
6445                hc, linmap2list(xdata & 0x0f));
6446          }
6447       }
6448       else if ( xfunc == 0x36 ) {
6449          xsubfunc = (xdata & 0x30u) >> 4;
6450          xgroup = (xdata & 0xc0u) >> 6;
6451          if ( xsubfunc == 0 )
6452             sprintf(outbuf, "func     xGrpExec : hc %c group %d",
6453                hc, xgroup);
6454          else if ( xsubfunc == 2 )
6455             sprintf(outbuf, "func     xGrpExec : hc %c group %d.%-2d",
6456                hc, xgroup, (xdata & 0x0fu) + 1);
6457          else if ( xsubfunc == 1 )
6458             sprintf(outbuf, "func      xGrpOff : hc %c group %d",
6459                hc, xgroup);
6460          else
6461             sprintf(outbuf, "func      xGrpOff : hc %c group %d.%-2d",
6462                hc, xgroup, (xdata & 0x0fu) + 1);
6463 
6464       }
6465       else if ( xfunc == 0x37 ) {
6466          xsubfunc = (xdata & 0x30u) >> 4;
6467          xgroup = (xdata & 0xc0u) >> 6;
6468          if ( xsubfunc == 0 )
6469             sprintf(outbuf, "func   xStatusReq : hu %c%-2d%s (%s)",
6470                hc, unit, stmp, lookup_label(hc, bmap));
6471          else if ( xsubfunc == 1 )
6472             sprintf(outbuf, "func     xPowerUp : hu %c%-2d%s (%s)",
6473                 hc, unit, stmp, lookup_label(hc, bmap));
6474          else if ( xsubfunc == 2 )
6475             sprintf(outbuf, "func   xGrpStatus : hu %c%-2d%s group %d (%s)",
6476                 hc, unit, stmp, (xdata & 0xc0) >> 6, lookup_label(hc, bmap));
6477          else
6478             sprintf(outbuf, "func   xGrpStatus : hu %c%-2d%s group %d.%-2d (%s)",
6479                hc, unit, stmp, xgroup, (xdata & 0x0fu) + 1, lookup_label(hc, bmap));
6480       }
6481       else if ( xfunc == 0x38 ) {
6482          if ( xdata & 0x40 )
6483             sprintf(outbuf, "func   xStatusAck : hu %c%-2d%s Switch %-3s %s (%s)",
6484                hc, unit, stmp, ((xdata & 0x3f) ? "On " : "Off"),
6485                ((xdata & 0x80) ? "LoadOK" : "NoLoad"),
6486                lookup_label(hc, bmap));
6487          else
6488             sprintf(outbuf, "func   xStatusAck : hu %c%-2d%s Lamp level %d, %s (%s)",
6489                hc, unit, stmp, xdata & 0x3f,
6490                ((xdata & 0x80) ? "BulbOK" : "NoBulb"),
6491                lookup_label(hc, bmap));
6492       }
6493       else if ( xfunc == 0x3b ) {
6494            sprintf(outbuf, "func      xConfig : hc %c mode=%d",
6495               hc, xdata);
6496       }
6497       else if ( xfunc == 0x3C ) {
6498          /* Unsupported by X-10 modules */
6499          xsubfunc = (xdata & 0x30u) >> 4;
6500          xgroup = (xdata & 0xc0u) >> 6;
6501          if ( xsubfunc == 0 )
6502             sprintf(outbuf, "func      xGrpDim : hc %c group %d",
6503                hc, xgroup);
6504          else if ( xsubfunc == 2 )
6505             sprintf(outbuf, "func      xGrpDim : hc %c group %d.%-2d",
6506                hc, xgroup, (xdata & 0x0fu) + 1);
6507          else if ( xsubfunc == 1 )
6508             sprintf(outbuf, "func   xGrpBright : hc %c group %d",
6509                hc, xgroup);
6510          else
6511             sprintf(outbuf, "func   xGrpBright : hc %c group %d.%-2d",
6512                hc, xgroup, (xdata & 0x0fu) + 1);
6513 
6514       }
6515 
6516 #ifdef HASEXT0
6517       else if ( xfunc == 0x01 ) {
6518            sprintf(outbuf, "func    shOpenLim : hu %c%-2d%s level %d (%s)",
6519               hc, unit, stmp, xdata & 0x1f, lookup_label(hc, bmap));
6520       }
6521       else if ( xfunc == 0x03 ) {
6522            sprintf(outbuf, "func       shOpen : hu %c%-2d%s level %d (%s)",
6523               hc, unit, stmp, xdata & 0x1f, lookup_label(hc, bmap));
6524       }
6525       else if ( xfunc == 0x02 ) {
6526            sprintf(outbuf, "func     shSetLim : hu %c%-2d%s level %d (%s)",
6527               hc, unit, stmp, xdata & 0x1f, lookup_label(hc, bmap));
6528       }
6529       else if ( xfunc == 0x04 ) {
6530            sprintf(outbuf, "func    shOpenAll : hc %c", hc);
6531       }
6532       else if ( xfunc == 0x0B ) {
6533            sprintf(outbuf, "func   shCloseAll : hc %c", hc);
6534       }
6535 #endif  /* HASEXT0 block */
6536 
6537       else if ( xfunc == 0xff )
6538             sprintf(outbuf, "func      ExtCode : Incomplete xcode in buffer.");
6539       else {
6540             sprintf(outbuf, "func     xFunc %02x : hu %c%-2d%s data=0x%02x (%s)",
6541             xfunc, hc, unit, stmp, xdata, lookup_label(hc, bmap));
6542       }
6543 
6544       return outbuf;
6545    }
6546    else if ( buf[0] == 0xfb && len == 19 ) {
6547       chksum = checksum(buf + 1, len - 1);
6548       memloc = (buf[1] << 8) + buf[2];
6549       sprintf(outbuf, "Upload to EEPROM location %03x, checksum = %02x",
6550           memloc, chksum);
6551       return outbuf;
6552    }
6553    else if ( buf[0] == 0x8b && len == 1 ) {
6554       sprintf(outbuf, "Request CM11A info");
6555       return outbuf;
6556    }
6557    else if ( buf[0] == 0x9b && len == 7 ) {
6558       sprintf(outbuf, "Update CM11A info");
6559       return outbuf;
6560    }
6561    else if ( buf[0] == 0xeb && len == 1 ) {
6562       *outbuf = '\0';
6563 /*
6564       sprintf(outbuf, "Enable serial ring signal");
6565 */
6566       return outbuf;
6567    }
6568    else if ( buf[0] == 0xdb && len == 1 ) {
6569       *outbuf = '\0';
6570 /*
6571       sprintf(outbuf, "Disable serial ring signal");
6572 */
6573       return outbuf;
6574    }
6575    else if ( buf[0] == ST_COMMAND && len == 3 ) {
6576       sprintf(outbuf, "State command");
6577       return outbuf;
6578    }
6579    else if ( buf[0] == 0xfb && len == 43 && configp->device_type & DEV_CM10A ) {
6580       sprintf(outbuf, "Initialize CM10A");
6581       return outbuf;
6582    }
6583    else {
6584       sprintf(outbuf, "Unknown transmission: %d bytes, 1st byte = %02x",
6585          len, buf[0]);
6586    }
6587    return outbuf;
6588 }
6589 
6590 
6591 /*---------------------------------------------------------------------+
6592  | Interpret bytes sent to CM17A                                       |
6593  +---------------------------------------------------------------------*/
translate_rf_sent(unsigned char * buf,int * launchp)6594 char *translate_rf_sent ( unsigned char *buf, int *launchp )
6595 {
6596    extern void xlate_rf( unsigned char, char **, unsigned int, char *,
6597                                                int *, unsigned char * );
6598 
6599    static char   outbuf[80];
6600    char verb[16];
6601    unsigned char type, bursts, nosw, addr;
6602    char          hc;
6603    unsigned int  rfword, dimlevel;
6604    char          *fname, *vp, *nsw;
6605    int           unit;
6606    unsigned char updatebuf[8];
6607    int           launchaddr, launchfunc;
6608    extern unsigned int signal_source;
6609 
6610    type = buf[2];
6611    rfword = buf[3] << 8 | buf[4];
6612    bursts = buf[5];
6613    xlate_rf( type, &fname, rfword, &hc, &unit, &nosw );
6614 
6615 
6616    if ( configp->disp_rf_xmit == VERBOSE ) {
6617       sprintf(verb, " [%02x %02x %d]", buf[3], buf[4], buf[5]);
6618       vp = verb;
6619    }
6620    else {
6621       vp = "";
6622    }
6623 
6624    nsw = ( nosw && (type == 0 || unit == 1 || unit == 9) ) ? " NoSw" : "";
6625 
6626    if ( type == 9 )
6627       sprintf(outbuf, "RF           fArb : bytes 0x%02X 0x%02X count %d%s",
6628 		      buf[3], buf[4], buf[5], vp);
6629    else if ( type == 10 )
6630       sprintf(outbuf, "RF           fArw : word 0x%04X count %d%s",
6631 		      ((buf[3] << 8) | buf[4]), buf[5], vp);
6632    else if ( type == 11 )
6633       sprintf(outbuf, "RF           fLux : word 0x%04X count %d%s",
6634 		      ((buf[3] << 8) | buf[4]), buf[5], vp);
6635    else if ( type == 2 || type == 3 )
6636       sprintf(outbuf, "RF   %12s : hu %c%-2d%s%s", fname, hc, unit, nsw, vp);
6637    else if ( type == 4 || type == 5 )
6638       sprintf(outbuf, "RF   %12s : hc %c count %d%s", fname, hc, bursts, vp);
6639    else
6640       sprintf(outbuf, "RF   %12s : hc %c%s%s", fname, hc, nsw, vp);
6641 
6642    *launchp = launchaddr = launchfunc = -1;
6643 
6644    if ( configp->process_xmit == YES ) {
6645       signal_source = XMTF;
6646       if ( type == 2 || type == 3 ) {
6647          addr = (hc2code(hc) << 4) | unit2code(unit);
6648          x10state_update_addr(addr, &launchaddr);
6649       }
6650       if ( type < 7 ) {
6651          updatebuf[0] = (hc2code(hc) << 4) | (type & 0x0f);
6652          dimlevel = min((210 * bursts) / 32, 210);
6653          updatebuf[1] = (unsigned char)dimlevel;
6654          x10state_update_func(updatebuf, &launchfunc);
6655       }
6656       *launchp = (launchfunc < 0) ? launchaddr : launchfunc;
6657    }
6658 
6659    return outbuf;
6660 }
6661 
6662 
6663 /*---------------------------------------------------------------------+
6664  | Interpret byte string sent to CM11A.                                |
6665  +---------------------------------------------------------------------*/
translate_other(unsigned char * buf,int len,unsigned char * chksum)6666 char *translate_other ( unsigned char *buf, int len, unsigned char *chksum )
6667 {
6668    static char outbuf[80];
6669    unsigned int memloc;
6670 
6671    if ( buf[0] == 0 && len == 1 ) {
6672       return "";
6673    }
6674    else if ( buf[0] == 0xfb && len == 19 ) {
6675       *chksum = checksum(buf + 1, len - 1);
6676       memloc = (buf[1] << 8) + buf[2];
6677       sprintf(outbuf, "Upload to EEPROM location %03x, checksum = %02x",
6678           memloc, *chksum);
6679       return outbuf;
6680    }
6681    else if ( buf[0] == 0x8b && len == 1 ) {
6682       sprintf(outbuf, "Request CM11A info");
6683       return outbuf;
6684    }
6685    else if ( buf[0] == 0x9b && len == 7 ) {
6686       sprintf(outbuf, "Update CM11A info");
6687       return outbuf;
6688    }
6689    else if ( buf[0] == 0xeb && len == 1 ) {
6690       *outbuf = '\0';
6691 /*
6692       sprintf(outbuf, "Enable serial ring signal");
6693 */
6694       return outbuf;
6695    }
6696    else if ( buf[0] == 0xdb && len == 1 ) {
6697       *outbuf = '\0';
6698 /*
6699       sprintf(outbuf, "Disable serial ring signal");
6700 */
6701       return outbuf;
6702    }
6703    else if ( buf[0] == ST_COMMAND && len == 3 ) {
6704       sprintf(outbuf, "State command");
6705       return outbuf;
6706    }
6707    else if ( buf[0] == 0xfb && len == 43 && configp->device_type & DEV_CM10A ) {
6708       sprintf(outbuf, "Initialize CM10A");
6709       return outbuf;
6710    }
6711    else {
6712       sprintf(outbuf, "Unknown transmission: %d bytes, 1st byte = %02x",
6713          len, buf[0]);
6714    }
6715    return outbuf;
6716 }
6717 
6718 /*---------------------------------------------------------------------+
6719  | Create argument list string for heyuhelper.                         |
6720  | If argument big = 0, a token for only the last unit is included,    |
6721  | otherwise tokens are include for each unit in the launcher bitmap.  |
6722  +---------------------------------------------------------------------*/
helper_string(LAUNCHER * launcherp,int big)6723 char *helper_string ( LAUNCHER *launcherp, int big )
6724 {
6725    int           ucode;
6726    unsigned int  bitmap, mask;
6727    unsigned char actfunc;
6728    char          hc;
6729    char          buffer[256];
6730    char          minibuf[32];
6731    char          *dup;
6732 
6733    bitmap = launcherp->bmaplaunch;
6734    actfunc = launcherp->actfunc;
6735    hc = tolower((int)code2hc(launcherp->hcode));
6736 
6737    strncpy2(buffer, ((big) ? "bighelper=" : "helper="), sizeof(buffer) - 1);
6738    for ( ucode = 15; ucode >= 0; ucode-- ) {
6739       mask = 1 << ucode;
6740       if ( bitmap & mask ) {
6741          sprintf(minibuf, "%c%d%s ",
6742             hc, code2unit(ucode), funclabel[actfunc]);
6743          strncat(buffer, minibuf, sizeof(buffer) - 1 - strlen(buffer));
6744          if ( !big )
6745             break;
6746       }
6747    }
6748    if ( (dup = strdup(buffer)) == NULL ) {
6749       fprintf(stderr, "Out of memory in helper_string()\n");
6750       exit(1);
6751    }
6752    return dup;
6753 }
6754 
6755 
6756 /*---------------------------------------------------------------------+
6757  | Return the heyu state in the same bitmap format as is put into the  |
6758  | environment when a script is launched.                              |
6759  +---------------------------------------------------------------------*/
get_heyu_state(unsigned char hcode,unsigned char ucode,int mode)6760 unsigned long get_heyu_state ( unsigned char hcode, unsigned char ucode, int mode )
6761 {
6762    unsigned int  bitmap;
6763    unsigned long value;
6764    int           level;
6765 
6766    bitmap = (1 << ucode);
6767 
6768    if ( mode == PCTMODE ) {
6769       /* Start with the dim level (0-100) */
6770       level = x10state[hcode].dimlevel[ucode];
6771       if ( modmask[Ext3Mask][hcode] & bitmap )
6772          value = ext3level2pct(level);
6773       else if ( modmask[Ext0Mask][hcode] & bitmap )
6774          value = ext0level2pct(level);
6775       else if ( modmask[PresetMask][hcode] & bitmap )
6776          value = presetlevel2pct(level);
6777       else if ( modmask[StdMask][hcode] & bitmap )
6778          value = dims2pct(level);
6779       else if ( vmodmask[VkakuMask][hcode] & bitmap )
6780          value = 100 * level / 15;
6781       else
6782          value = 100 * level / ondimlevel[hcode][ucode];
6783    }
6784    else {
6785       /* Start with the raw dim level */
6786       level = x10state[hcode].dimlevel[ucode];
6787       if ( modmask[PresetMask][hcode] & bitmap )
6788          value = level + 1;
6789       else
6790          value = level;
6791    }
6792 
6793    /* Add the state bits */
6794    if ( bitmap & ~(modmask[DimMask][hcode] | modmask[BriMask][hcode]) )
6795       value |= HEYUMAP_APPL;
6796    if ( bitmap & x10state[hcode].state[SpendState] )
6797       value |= HEYUMAP_SPEND;
6798    if ( bitmap & ~x10state[hcode].state[OnState] )
6799       value |= HEYUMAP_OFF;
6800    if ( bitmap & x10state[hcode].addressed )
6801       value |= HEYUMAP_ADDR;
6802    if ( bitmap & x10state[hcode].state[ChgState] )
6803       value |= HEYUMAP_CHG;
6804    if ( bitmap & x10state[hcode].state[DimState] )
6805       value |= HEYUMAP_DIM;
6806    if ( bitmap & x10state[hcode].state[ValidState] )
6807       value |= HEYUMAP_SIGNAL;
6808 //   if ( bitmap & ~x10state[hcode].state[AlertState] & x10state[hcode].state[ValidState] & vmodmask[VsecMask][hcode])
6809    if ( bitmap & x10state[hcode].state[ClearState] )
6810       value |= HEYUMAP_CLEAR;
6811    if ( bitmap & x10state[hcode].state[AlertState] )
6812       value |= HEYUMAP_ALERT;
6813 //   if ( bitmap & ~x10state[hcode].state[AuxAlertState] & x10state[hcode].state[ValidState] & vmodmask[VsecMask][hcode])
6814    if ( bitmap & x10state[hcode].state[AuxClearState] )
6815       value |= HEYUMAP_AUXCLEAR;
6816    if ( bitmap & x10state[hcode].state[AuxAlertState] )
6817       value |= HEYUMAP_AUXALERT;
6818    if ( bitmap & x10state[hcode].state[ActiveState] )
6819       value |= HEYUMAP_ACTIVE;
6820    if ( bitmap & x10state[hcode].state[InactiveState] )
6821       value |= HEYUMAP_INACTIVE;
6822    if ( bitmap & x10state[hcode].state[ModChgState] )
6823       value |= HEYUMAP_MODCHG;
6824    if ( bitmap & x10state[hcode].state[OnState] )
6825       value |= HEYUMAP_ON;
6826 
6827 
6828    return value;
6829 }
6830 
6831 #if 0
6832 /*---------------------------------------------------------------------+
6833  | Return the heyu state in the same bitmap format as is put into the  |
6834  | environment when a script is launched with "-rawlevel" option.      |
6835  +---------------------------------------------------------------------*/
6836 unsigned long get_heyu_rawstate_old ( unsigned char hcode, unsigned char ucode )
6837 {
6838    unsigned int  bitmap;
6839    unsigned long value;
6840    int           level;
6841 
6842    bitmap = (1 << ucode);
6843 
6844    /* Start with the raw dim level */
6845    level = x10state[hcode].dimlevel[ucode];
6846    if ( modmask[PresetMask][hcode] & bitmap )
6847       value = level + 1;
6848    else
6849       value = level;
6850 
6851    /* Add the state bits */
6852    if ( bitmap & ~(modmask[DimMask][hcode] | modmask[BriMask][hcode]) )
6853       value |= HEYUMAP_APPL;
6854    if ( bitmap & x10state[hcode].state[SpendState] )
6855       value |= HEYUMAP_SPEND;
6856    if ( bitmap & ~x10state[hcode].state[OnState] )
6857       value |= HEYUMAP_OFF;
6858    if ( bitmap & x10state[hcode].addressed )
6859       value |= HEYUMAP_ADDR;
6860    if ( bitmap & x10state[hcode].state[ChgState] )
6861       value |= HEYUMAP_CHG;
6862    if ( bitmap & x10state[hcode].state[DimState] )
6863       value |= HEYUMAP_DIM;
6864    if ( bitmap & x10state[hcode].state[ValidState] )
6865       value |= HEYUMAP_SIGNAL;
6866    if ( bitmap & x10state[hcode].state[ActiveState] )
6867       value |= HEYUMAP_ACTIVE;
6868    if ( bitmap & x10state[hcode].state[InactiveState] )
6869       value |= HEYUMAP_INACTIVE;
6870    if ( bitmap & x10state[hcode].state[ActiveChgState] )
6871       value |= HEYUMAP_ACTIVECHG;
6872    if ( bitmap & x10state[hcode].state[OnState] )
6873       value |= HEYUMAP_ON;
6874 
6875    return value;
6876 }
6877 #endif
6878 
get_secflag_state(unsigned char hcode,unsigned char ucode)6879 unsigned long get_secflag_state ( unsigned char hcode, unsigned char ucode)
6880 {
6881    unsigned long flagvalue;
6882    unsigned int  bitmap;
6883 
6884    bitmap = 1 << ucode;
6885 
6886    flagvalue = 0;
6887 
6888    if ( x10state[hcode].state[LoBatState] & bitmap ) flagvalue |= FLAGMAP_LOBAT;
6889    if ( x10state[hcode].vflags[ucode] & RFX_ROLLOVER ) flagvalue |= FLAGMAP_ROLLOVER;
6890 //   if ( x10state[hcode].state[SwMinState] & bitmap ) flagvalue |= FLAGMAP_SWMIN;
6891 //   if ( x10state[hcode].state[SwMaxState] & bitmap ) flagvalue |= FLAGMAP_SWMAX;
6892    if ( x10state[hcode].vflags[ucode] & SEC_MIN    ) flagvalue |= FLAGMAP_SWMIN;
6893    if ( x10state[hcode].vflags[ucode] & SEC_MAX    ) flagvalue |= FLAGMAP_SWMAX;
6894    if ( x10state[hcode].vflags[ucode] & SEC_MAIN   ) flagvalue |= FLAGMAP_MAIN;
6895    if ( x10state[hcode].vflags[ucode] & SEC_AUX    ) flagvalue |= FLAGMAP_AUX;
6896    if ( x10state[hcode].state[TamperState] & bitmap ) flagvalue |= FLAGMAP_TAMPER;
6897 
6898    return flagvalue;
6899 }
6900 
get_rfxflag_state(unsigned char hcode,unsigned char ucode)6901 unsigned long get_rfxflag_state ( unsigned char hcode, unsigned char ucode)
6902 {
6903    unsigned long flagvalue;
6904    unsigned int  bitmap;
6905 
6906    bitmap = 1 << ucode;
6907 
6908    flagvalue = 0;
6909 
6910    if ( x10state[hcode].state[LoBatState] & bitmap ) flagvalue |= FLAGMAP_LOBAT;
6911    if ( x10state[hcode].vflags[ucode] & RFX_ROLLOVER ) flagvalue |= FLAGMAP_ROLLOVER;
6912    if ( x10state[hcode].vflags[ucode] & ORE_TMIN ) flagvalue |= FLAGMAP_TMIN;
6913    if ( x10state[hcode].vflags[ucode] & ORE_TMAX ) flagvalue |= FLAGMAP_TMAX;
6914    if ( x10state[hcode].vflags[ucode] & ORE_RHMIN ) flagvalue |= FLAGMAP_RHMIN;
6915    if ( x10state[hcode].vflags[ucode] & ORE_RHMAX ) flagvalue |= FLAGMAP_RHMAX;
6916    if ( x10state[hcode].vflags[ucode] & ORE_BPMIN ) flagvalue |= FLAGMAP_BPMIN;
6917    if ( x10state[hcode].vflags[ucode] & ORE_BPMAX ) flagvalue |= FLAGMAP_BPMAX;
6918 
6919    return flagvalue;
6920 }
6921 
get_oreflag_state(unsigned char hcode,unsigned char ucode)6922 unsigned long get_oreflag_state ( unsigned char hcode, unsigned char ucode)
6923 {
6924    unsigned long flagvalue;
6925    unsigned int  bitmap;
6926 
6927    bitmap = 1 << ucode;
6928 
6929    flagvalue = 0;
6930 
6931    if ( x10state[hcode].state[LoBatState] & bitmap ) flagvalue |= FLAGMAP_LOBAT;
6932    if ( x10state[hcode].vflags[ucode] & RFX_ROLLOVER ) flagvalue |= FLAGMAP_ROLLOVER;
6933    if ( x10state[hcode].vflags[ucode] & ORE_TMIN ) flagvalue |= FLAGMAP_TMIN;
6934    if ( x10state[hcode].vflags[ucode] & ORE_TMAX ) flagvalue |= FLAGMAP_TMAX;
6935    if ( x10state[hcode].vflags[ucode] & ORE_RHMIN ) flagvalue |= FLAGMAP_RHMIN;
6936    if ( x10state[hcode].vflags[ucode] & ORE_RHMAX ) flagvalue |= FLAGMAP_RHMAX;
6937    if ( x10state[hcode].vflags[ucode] & ORE_BPMIN ) flagvalue |= FLAGMAP_BPMIN;
6938    if ( x10state[hcode].vflags[ucode] & ORE_BPMAX ) flagvalue |= FLAGMAP_BPMAX;
6939 
6940    return flagvalue;
6941 }
6942 
get_dmxflag_state(unsigned char hcode,unsigned char ucode)6943 unsigned long get_dmxflag_state ( unsigned char hcode, unsigned char ucode)
6944 {
6945    unsigned long flagvalue;
6946    unsigned int  bitmap;
6947 
6948    bitmap = 1 << ucode;
6949 
6950    flagvalue = 0;
6951 
6952    if ( x10state[hcode].state[LoBatState] & bitmap ) flagvalue |= FLAGMAP_LOBAT;
6953    if ( x10state[hcode].vflags[ucode] & DMX_SET ) flagvalue |= FLAGMAP_DMXSET;
6954    if ( x10state[hcode].vflags[ucode] & DMX_HEAT ) flagvalue |= FLAGMAP_DMXHEAT;
6955    if ( x10state[hcode].vflags[ucode] & DMX_INIT ) flagvalue |= FLAGMAP_DMXINIT;
6956    if ( x10state[hcode].vflags[ucode] & DMX_TEMP ) flagvalue |= FLAGMAP_DMXTEMP;
6957 
6958    return flagvalue;
6959 }
6960 
get_vflag_state(unsigned char hcode,unsigned char ucode)6961 unsigned long get_vflag_state ( unsigned char hcode, unsigned char ucode )
6962 {
6963    return get_secflag_state(hcode, ucode) |
6964           get_rfxflag_state(hcode, ucode) |
6965           get_oreflag_state(hcode, ucode) |
6966           get_dmxflag_state(hcode, ucode)   ;
6967 }
6968 
6969 
6970 /*---------------------------------------------------------------------+
6971  | Return the xtend state in the same bitmap format as is put into the |
6972  | environment when a script is launched.                              |
6973  +---------------------------------------------------------------------*/
get_xtend_state(unsigned char hcode,unsigned char ucode)6974 unsigned long get_xtend_state ( unsigned char hcode, unsigned char ucode )
6975 {
6976    unsigned int  bitmap;
6977    unsigned long value;
6978 
6979    bitmap = (1 << ucode);
6980 
6981    value = 0;
6982 
6983    /* Add the state bits */
6984    if ( bitmap & ~(modmask[DimMask][hcode] | modmask[BriMask][hcode]) )
6985       value |= XTMAP_APPL;
6986    if ( bitmap & x10state[hcode].addressed )
6987       value |= XTMAP_ADDR;
6988    if ( bitmap & x10state[hcode].state[OnState] )
6989       value |= XTMAP_ON;
6990 
6991    return value;
6992 }
6993 
6994 /*---------------------------------------------------------------------+
6995  | Allocate memory for argument envstr.                                |
6996  +---------------------------------------------------------------------*/
add_envptr(char * envstr)6997 char *add_envptr ( char *envstr )
6998 {
6999    char *dup;
7000    char *out_of_memory = "add_envptr() : Out of memory\n";
7001 
7002 
7003    if ( (dup = strdup(envstr)) == NULL ) {
7004       fprintf(stderr, "%s", out_of_memory);
7005       exit(1);
7006    }
7007    return dup;
7008 }
7009 
7010 /*---------------------------------------------------------------------+
7011  | Create a minimal environment for the -noenv option                  |
7012  +---------------------------------------------------------------------*/
create_noenv_environment(LAUNCHER * launcherp,unsigned char daemon)7013 char **create_noenv_environment ( LAUNCHER *launcherp, unsigned char daemon )
7014 {
7015 
7016    extern char   **environ;
7017 
7018    int           j, size, newsize;
7019    char          **envp, **ep;
7020    char          minibuf[512];
7021    static int    sizchrptr = sizeof(char *);
7022 
7023 
7024    if ( daemon == D_RELAY || (launcherp && launcherp->type == L_POWERFAIL) )
7025       putenv("HEYU_PARENT=RELAY");
7026    else
7027       putenv("HEYU_PARENT=ENGINE");
7028 
7029    /* Get length of original environment */
7030    size = 0;
7031    while ( environ[size] != NULL )
7032       size++;
7033 
7034    newsize = size + 50;
7035 
7036    if ( (envp = calloc(newsize, sizchrptr)) == NULL ) {
7037       fprintf(stderr, "create_noenv__environment() : out_of_memory\n");
7038       exit(1);
7039    }
7040 
7041    ep = envp;
7042 
7043    *ep++ = add_envptr("IAMNOENV=1");
7044 
7045    /* Put config file pathname in environment for child processes */
7046    sprintf(minibuf, "X10CONFIG=%s", pathspec(heyu_config));
7047    *ep++ = add_envptr(minibuf);
7048 
7049 
7050    /* Append the user's original environment */
7051    for ( j = 0; j < size; j++ ) {
7052       *ep++ = add_envptr(environ[j]);
7053    }
7054 
7055    /* Add NULL terminator */
7056    *ep++ = NULL;
7057 
7058    return envp;
7059 }
7060 
7061 /*---------------------------------------------------------------------+
7062  | Create the environment for heyu scripts.                            |
7063  +---------------------------------------------------------------------*/
create_heyu_environment(LAUNCHER * launcherp,unsigned char option)7064 char **create_heyu_environment( LAUNCHER *launcherp, unsigned char option)
7065 {
7066    extern char   **environ;
7067 
7068    int           j, k, size, newsize, aliasindex;
7069    unsigned char hcode, ucode, lucode, actfunc /*, vtype*/;
7070    char          **envp, **ep, *pathptr, *newpathptr;
7071    char          hc;
7072    unsigned int  bitmap /*, addressed, onstate, appliance*/;
7073    unsigned long value, /*flagvalue, allflagvalue,*/ vflags;
7074 //   unsigned int  dimstate, chgstate, modchgstate, spendstate;
7075    unsigned int  actsource;
7076    char          *srcname;
7077    long int      dawn, dusk, systime;
7078    int           expire;
7079    char          *aliaslabel;
7080    char          minibuf[512];
7081    static int    sizchrptr = sizeof(char *);
7082    time_t        now;
7083    struct tm     *tms;
7084    extern unsigned char bootflag;
7085    extern int    alias_vtype_count ( unsigned char );
7086    ALIAS         *aliasp;
7087 
7088    unsigned long longvdata;
7089    int           unit;
7090 
7091 #ifdef HASDMX
7092    int           tempc, settempc;
7093    unsigned char status, oostatus;
7094 #endif /* HASDMX */
7095 
7096 
7097 #if (defined(HASRFXS) || defined(HASRFXM))
7098    char          valbuf[80];
7099 #endif
7100 
7101 #ifdef HASRFXS
7102    unsigned int  inmap, outmap;
7103    double        temp, vsup, vad, var2;
7104 #endif /* HASRFXS */
7105 
7106 #ifdef HASRFXM
7107    unsigned long rfxdata;
7108    extern int    npowerpanels;
7109    extern int    powerpanel_query(unsigned char, unsigned long *);
7110 #endif /* HASRFXM */
7111 
7112 #ifdef HASORE
7113    int    otempc;
7114    double otemp;
7115    int    obaro;
7116    double odbaro;
7117    int    cweight;
7118    double weight;
7119    int    channel;
7120    int    blevel;
7121    int    fcast;
7122    int    deciamps;
7123    int    dwind;
7124    double dblwind;
7125    unsigned long rain;
7126    double dblrain;
7127    extern char *forecast_txt( int );
7128    int    uvfactor;
7129    double dblpower, dblenergy;
7130 #endif /* HASORE */
7131 
7132 #if 0
7133 static struct {
7134    char          *query;
7135    unsigned long  mask;
7136 } heyumaskval[] = {
7137    {"whatLevel",   HEYUMAP_LEVEL},
7138    {"isAppl",      HEYUMAP_APPL },
7139    {"isSpend",     HEYUMAP_SPEND},
7140    {"isOff",       HEYUMAP_OFF  },
7141    {"isAddr",      HEYUMAP_ADDR },
7142    {"isChg",       HEYUMAP_CHG  },
7143    {"isDim",       HEYUMAP_DIM  },
7144    {"isValid",     HEYUMAP_SIGNAL },
7145    {"isClear",     HEYUMAP_CLEAR},
7146    {"isAlert",     HEYUMAP_ALERT},
7147    {"isAuxClear",  HEYUMAP_AUXCLEAR},
7148    {"isAuxAlert",  HEYUMAP_AUXALERT},
7149    {"isActive",    HEYUMAP_ACTIVE},
7150    {"isInactive",  HEYUMAP_INACTIVE},
7151    {"isModChg",    HEYUMAP_MODCHG},
7152    {"isOn",        HEYUMAP_ON   },
7153    { NULL,        0            },
7154 };
7155 
7156 static struct {
7157    char           *query;
7158    unsigned long  mask;
7159 } heyusecmaskval[] = {
7160    {"isLoBat",    FLAGMAP_LOBAT    },
7161    {"isRollover", FLAGMAP_ROLLOVER },
7162    {"isSwMin",    FLAGMAP_SWMIN    },
7163    {"isSwMax",    FLAGMAP_SWMAX    },
7164    {"isMain",     FLAGMAP_MAIN     },
7165    {"isAux",      FLAGMAP_AUX      },
7166    {"isTamper",   FLAGMAP_TAMPER   },
7167    {"isTmin",     FLAGMAP_TMIN     },
7168    {"isTmax",     FLAGMAP_TMAX     },
7169    {"isRHmin",    FLAGMAP_RHMIN    },
7170    {"isRHmax",    FLAGMAP_RHMAX    },
7171    {"isBPmin",    FLAGMAP_BPMIN    },
7172    {"isBPmax",    FLAGMAP_BPMAX    },
7173    {"isDmxSet",   FLAGMAP_DMXSET   },
7174    {"isDmxHeat",  FLAGMAP_DMXHEAT  },
7175    {"isDmxTemp",  FLAGMAP_DMXTEMP  },
7176    { NULL,        0                },
7177 };
7178 #endif  /* Reference */
7179 
7180    aliasp = configp->aliasp;
7181    unit = 0;
7182 
7183    longvdata = x10global.longvdata;
7184 
7185    if ( launcherp->type != L_POWERFAIL )
7186       putenv("HEYU_PARENT=ENGINE");
7187    else
7188       putenv("HEYU_PARENT=RELAY");
7189 
7190    /* Get length of original environment */
7191    size = 0;
7192    while ( environ[size] != NULL )
7193       size++;
7194 
7195    newsize = size + 16 + 77 + alias_count() +
7196          256 +                       /* States */
7197          256 +                       /* vFlag states */
7198          32 * NUM_FLAG_BANKS +       /* Common flags */
7199          64 * NUM_COUNTER_BANKS +    /* Counters and counter-zero flags */
7200          64 * NUM_TIMER_BANKS + 1 +  /* Timers and timer-zero flags */
7201          6 * alias_vtype_count(RF_XSENSOR) +
7202          4 * alias_vtype_count(RF_XMETER) +
7203         14 * alias_vtype_count(RF_DIGIMAX) +
7204         36 * alias_vtype_count(RF_OREGON) +
7205         12 * alias_vtype_count(RF_ELECSAVE) +
7206         14 * alias_vtype_count(RF_OWL) +
7207          2 * alias_vtype_count(RF_SEC);
7208 
7209    if ( (envp = calloc(newsize, sizchrptr)) == NULL ) {
7210       fprintf(stderr, "create_heyu_environment() : out of memory\n");
7211       exit(1);
7212    }
7213 
7214    ep = envp;
7215 
7216    *ep++ = add_envptr("IAMHEYU=1");
7217 
7218    /* Put config file pathname in environment for child processes */
7219    sprintf(minibuf, "X10CONFIG=%s", pathspec(heyu_config));
7220    *ep++ = add_envptr(minibuf);
7221 
7222    /* Add version and release date */
7223    sprintf(minibuf, "HEYU_VERSION=%s", VERSION);
7224    *ep++ = add_envptr(minibuf);
7225    sprintf(minibuf, "HEYU_RELEASE_DATE=%s", RELEASE_DATE);
7226    *ep++ = add_envptr(minibuf);
7227 
7228    /* Prefix and/or Append to PATH if requested */
7229    if ( (*configp->launchpath_prefix || *configp->launchpath_append) && (pathptr = getenv("PATH")) ) {
7230       /* Old PATH might be very large - malloc space */
7231       newpathptr = malloc(8 + strlen(pathptr) + strlen(configp->launchpath_prefix) + strlen(configp->launchpath_append));
7232       if ( newpathptr ) {
7233          strcpy(newpathptr, "PATH=");
7234          if ( *configp->launchpath_prefix ) {
7235             strcat(newpathptr, configp->launchpath_prefix);
7236             strcat(newpathptr, ":");
7237          }
7238          strcat(newpathptr, pathptr);
7239          if ( *configp->launchpath_append ) {
7240             strcat(newpathptr, ":");
7241             strcat(newpathptr, configp->launchpath_append);
7242          }
7243          putenv(newpathptr);
7244       }
7245    }
7246 
7247    /* Create the various masks */
7248    j = 0;
7249    while ( heyumaskval[j].query ) {
7250       sprintf(minibuf, "%s=%lu", heyumaskval[j].query, heyumaskval[j].mask);
7251       *ep++ = add_envptr(minibuf);
7252       j++;
7253    }
7254 
7255    j = 0;
7256    while ( heyusecmaskval[j].query ) {
7257       sprintf(minibuf, "%s=%lu", heyusecmaskval[j].query, heyusecmaskval[j].mask);
7258       *ep++ = add_envptr(minibuf);
7259       j++;
7260    }
7261 
7262    hcode = launcherp->hcode;
7263    actfunc = launcherp->actfunc;
7264    actsource = launcherp->actsource;
7265 
7266    /* Variables for scripts launched by a "normal" launcher, */
7267    /* i.e., not a powerfail or address launcher.             */
7268    if ( launcherp->type == L_NORMAL ) {
7269       /* Put in the variables 'helper' and 'bighelper' */
7270       /* with arguments for heyuhelper                 */
7271       *ep++ = helper_string(launcherp, 0);
7272       *ep++ = helper_string(launcherp, 1);
7273 
7274    }
7275 
7276    /* Variables for scripts launched by normal or address launchers */
7277    if ( launcherp->type == L_NORMAL ||
7278         launcherp->type == L_ADDRESS       ) {
7279 
7280       if ( launcherp->type == L_NORMAL ) {
7281          sprintf(minibuf, "X10_Function=%s", funclabel[actfunc]);
7282 	 *ep++ = add_envptr(minibuf);
7283          sprintf(minibuf, "X10_function=%s", funclabel[actfunc]);
7284 	 strlower(minibuf + 1);
7285 	 *ep++ = add_envptr(minibuf);
7286       }
7287       else {
7288          sprintf(minibuf, "X10_Function=none");
7289          *ep++ = add_envptr(minibuf);
7290       }
7291 
7292       sprintf(minibuf, "X10_Housecode=%c", code2hc(hcode));
7293       *ep++ = add_envptr(minibuf);
7294 
7295       sprintf(minibuf, "X10_Linmap=%u", x10map2linmap(launcherp->bmaplaunch));
7296       *ep++ = add_envptr(minibuf);
7297 
7298       sprintf(minibuf, "X10_LastUnit=%d", x10state[hcode].lastunit);
7299       *ep++ = add_envptr(minibuf);
7300 
7301       if ( launcherp->bmaplaunch != 0 ) {
7302 
7303          lucode = 0xff;
7304          if ( x10state[hcode].lastunit > 0 ) {
7305             lucode = unit2code(x10state[hcode].lastunit);
7306             sprintf(minibuf, "X10_LastUnitAlias=%s", lookup_label(code2hc(hcode), lucode) );
7307          }
7308 
7309          if ( lucode <= 0x0f && (launcherp->bmaplaunch & (1 << lucode)) ) {
7310             ucode = lucode;
7311          }
7312          else {
7313             for ( ucode = 0; ucode < 16; ucode++ ) {
7314                if ( launcherp->bmaplaunch & (1 << ucode) )
7315                   break;
7316             }
7317          }
7318 
7319          sprintf(minibuf, "X10_Unit=%d", code2unit(ucode));
7320          *ep++ = add_envptr(minibuf);
7321 
7322          sprintf(minibuf, "X10_UnitAlias=%s", lookup_label(code2hc(hcode), (1 << ucode)) );
7323          *ep++ = add_envptr(minibuf);
7324 
7325          sprintf(minibuf, "X10_Timestamp=%ld", (unsigned long)x10state[hcode].timestamp[ucode]);
7326          *ep++ = add_envptr(minibuf);
7327 
7328          sprintf(minibuf, "X10_Vident=%lu", x10state[hcode].vident[ucode]);
7329          *ep++ = add_envptr(minibuf);
7330 
7331          /* Security functions local switch flags */
7332          if ( actfunc == ArmFunc ) {
7333             sprintf(minibuf, "X10_swHome=%d", ((x10state[hcode].vflags[ucode] & SEC_HOME) ? 1 : 0) );
7334             *ep++ = add_envptr(minibuf);
7335             sprintf(minibuf, "X10_swAway=%d", ((x10state[hcode].vflags[ucode] & SEC_AWAY) ? 1 : 0) );
7336             *ep++ = add_envptr(minibuf);
7337          }
7338          if ( actfunc == ArmFunc || actfunc == AlertFunc || actfunc == ClearFunc ) {
7339             sprintf(minibuf, "X10_swMin=%d", ((x10state[hcode].vflags[ucode] & SEC_MIN) ? 1 : 0) );
7340             *ep++ = add_envptr(minibuf);
7341             sprintf(minibuf, "X10_swMax=%d", ((x10state[hcode].vflags[ucode] & SEC_MAX) ? 1 : 0) );
7342             *ep++ = add_envptr(minibuf);
7343          }
7344 
7345          if ( actfunc == AlertFunc || actfunc == ClearFunc ) {
7346             sprintf(minibuf, "X10_LoBat=%d", ((x10state[hcode].vflags[ucode] & SEC_LOBAT) ? 1 : 0) );
7347             *ep++ = add_envptr(minibuf);
7348          }
7349          if ( actfunc == RFXLoBatFunc ) {
7350             *ep++ = add_envptr("X10_LoBat=1");
7351          }
7352 
7353          if ( actfunc == RFXPowerFunc || actfunc == RFXWaterFunc ||
7354               actfunc == RFXGasFunc || actfunc == RFXPulseFunc || actfunc == RFXCountFunc ||
7355               actfunc == OreRainTotFunc ) {
7356             sprintf(minibuf, "X10_rollover=%d", ((x10state[hcode].vflags[ucode] & RFX_ROLLOVER) ? 1 : 0) );
7357             *ep++ = add_envptr(minibuf);
7358          }
7359 
7360 #ifdef HASDMX
7361          if ( actfunc == DmxSetPtFunc ) {
7362             longvdata = x10global.longvdata;
7363             settempc = (int)((longvdata & TSETPMASK) >> TSETPSHIFT);
7364             sprintf(minibuf, "X10_dmxSetpoint=%d", settempc);
7365             *ep++ = add_envptr(minibuf);
7366          }
7367          if ( actfunc == DmxTempFunc ) {
7368             longvdata = x10global.longvdata;
7369             tempc = (int)((longvdata & TCURRMASK) >> TCURRSHIFT);
7370             tempc = (tempc & 0x80) ? (0x80 - tempc) : tempc;
7371             sprintf(minibuf, "X10_dmxTemp=%d", tempc);
7372             *ep++ = add_envptr(minibuf);
7373          }
7374          if ( actfunc == DmxOnFunc || actfunc == DmxOffFunc ) {
7375             longvdata = x10global.longvdata;
7376             sprintf(minibuf, "X10_dmxHeat=%d", ((longvdata & HEATMASK) ? 0 : 1));
7377             *ep++ = add_envptr(minibuf);
7378          }
7379          if ( actfunc == DmxSetPtFunc || actfunc == DmxTempFunc ||
7380               actfunc == DmxOnFunc || actfunc == DmxOffFunc ) {
7381             longvdata = x10global.longvdata;
7382             status = (unsigned char)((longvdata & STATMASK) >> STATSHIFT);
7383             sprintf(minibuf, "X10_dmxHeat=%d", ((longvdata & HEATMASK) ? 0 : 1));
7384             *ep++ = add_envptr(minibuf);
7385             sprintf(minibuf, "X10_dmxInit=%d", ((status == 3) ? 1 : 0));
7386             *ep++ = add_envptr(minibuf);
7387             sprintf(minibuf, "X10_dmxSet=%d", ((status > 0) ? 1 : 0));
7388             *ep++ = add_envptr(minibuf);
7389             oostatus = (longvdata & ONOFFMASK) >> ONOFFSHIFT;
7390             if ( oostatus > 0 ) {
7391                oostatus = (oostatus == 1) ? 1 : 0;
7392                if ( (longvdata & HEATMASK) && (DMXCOOLSWAP == YES) )
7393                   oostatus = (oostatus + 1) % 2;
7394                sprintf(minibuf, "X10_dmxStatus=%d", oostatus);
7395                *ep++ = add_envptr(minibuf);
7396             }
7397          }
7398 
7399 #endif /* HASDMX */
7400       }
7401 
7402 #ifdef HASORE
7403       if ( actfunc == OreTempFunc || actfunc == OreHumidFunc || actfunc == OreBaroFunc ||
7404            actfunc == OreWeightFunc || actfunc == ElsCurrFunc ||
7405            actfunc == OreWindSpFunc || actfunc == OreWindAvSpFunc || actfunc == OreWindDirFunc ||
7406            actfunc == OreRainRateFunc || actfunc == OreRainTotFunc ||
7407            actfunc == OwlPowerFunc || actfunc == OwlEnergyFunc ) {
7408          longvdata = x10global.longvdata;
7409          if ( (channel = (int)((longvdata & ORE_CHANMSK) >> ORE_CHANSHFT)) > 0 ) {
7410             sprintf(minibuf, "X10_oreCh=%d", channel);
7411             *ep++ = add_envptr(minibuf);
7412          }
7413          if ( longvdata & ORE_BATLVL ) {
7414             blevel = (longvdata & ORE_BATMSK) >> ORE_BATSHFT;
7415             sprintf(minibuf, "X10_oreBatLvl=%d", blevel * 10);
7416             *ep++ = add_envptr(minibuf);
7417          }
7418          if ( x10global.interval >= 0 ) {
7419             sprintf(minibuf, "X10_oreIntv=%ld", x10global.interval);
7420             *ep++ = add_envptr(minibuf);
7421          }
7422          sprintf(minibuf, "X10_oreLoBat=%d", ((longvdata & ORE_LOBAT) ? 1 : 0));
7423          *ep++ = add_envptr(minibuf);
7424       }
7425 
7426       if ( actfunc == OreTempFunc ) {
7427          longvdata = x10global.longvdata;
7428          otempc = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
7429          if ( (longvdata & ORE_NEGTEMP) )
7430             otempc = -otempc;
7431          otemp = celsius2temp((double)otempc / 10.0, configp->ore_tscale, configp->ore_toffset);
7432          sprintf(minibuf, "X10_oreTemp="FMT_ORET, otemp);
7433          *ep++ = add_envptr(minibuf);
7434       }
7435       else if ( actfunc == OreHumidFunc ) {
7436          longvdata = x10global.longvdata;
7437          sprintf(minibuf, "X10_oreRH=%d", (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT));
7438          *ep++ = add_envptr(minibuf);
7439       }
7440       else if ( actfunc == OreBaroFunc ) {
7441          longvdata = x10global.longvdata;
7442          obaro = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7443          odbaro = (double)obaro * configp->ore_bpscale + configp->ore_bpoffset;
7444          sprintf(minibuf, "X10_oreBP="FMT_OREBP, odbaro);
7445          *ep++ = add_envptr(minibuf);
7446          if ( (fcast = (longvdata & ORE_FCAST) >> ORE_FCASTSHFT) > 0 ) {
7447             sprintf(minibuf, "X10_oreForecast=%s", forecast_txt(fcast));
7448             *ep++ = add_envptr(minibuf);
7449          }
7450       }
7451       else if ( actfunc == OreWeightFunc ) {
7452          longvdata = x10global.longvdata;
7453          cweight = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7454          weight = (double)cweight / 10.0 * configp->ore_wgtscale;
7455          sprintf(minibuf, "X10_oreWgt="FMT_OREWGT, weight);
7456          *ep++ = add_envptr(minibuf);
7457       }
7458       else if ( actfunc == ElsCurrFunc ) {
7459          longvdata = x10global.longvdata;
7460          deciamps = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7461          sprintf(minibuf, "X10_elsCurr=%.1f", (double)deciamps / 10.0);
7462          *ep++ = add_envptr(minibuf);
7463          sprintf(minibuf, "X10_elsSigCount=%u", x10global.sigcount);
7464          *ep++ = add_envptr(minibuf);
7465          sprintf(minibuf, "X10_elsPwr=%.0f", configp->els_voltage * (double)deciamps / 10.0);
7466          *ep++ = add_envptr(minibuf);
7467       }
7468       else if ( actfunc == OreWindSpFunc ) {
7469          longvdata = x10global.longvdata;
7470          dwind = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7471          dblwind = (double)dwind / 10.0 * configp->ore_windscale;
7472          sprintf(minibuf, "X10_oreWindSp="FMT_OREWSP, dblwind);
7473          *ep++ = add_envptr(minibuf);
7474       }
7475       else if ( actfunc == OreWindAvSpFunc ) {
7476          longvdata = x10global.longvdata;
7477          dwind = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7478          dblwind = (double)dwind / 10.0 * configp->ore_windscale;
7479          sprintf(minibuf, "X10_oreWindAvSp="FMT_OREWSP, dblwind);
7480          *ep++ = add_envptr(minibuf);
7481       }
7482       else if ( actfunc == OreWindDirFunc ) {
7483          longvdata = x10global.longvdata;
7484          dwind = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7485          dwind = (dwind + configp->ore_windsensordir + 3600) % 3600;
7486          dblwind = (double)dwind / 10.0;
7487          sprintf(minibuf, "X10_oreWindDir="FMT_OREWDIR, dblwind);
7488          *ep++ = add_envptr(minibuf);
7489       }
7490       else if ( actfunc == OreRainRateFunc ) {
7491          longvdata = x10global.longvdata2;
7492          rain = (longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
7493          dblrain = (double)rain / 1000.0 * configp->ore_rainratescale;
7494          sprintf(minibuf, "X10_oreRainRate="FMT_ORERRATE, dblrain);
7495          *ep++ = add_envptr(minibuf);
7496       }
7497       else if ( actfunc == OreRainTotFunc ) {
7498          rain = x10global.longvdata2;
7499          dblrain = (double)rain / 1000.0 * configp->ore_raintotscale;
7500          sprintf(minibuf, "X10_oreRainTot="FMT_ORERTOT, dblrain);
7501          *ep++ = add_envptr(minibuf);
7502       }
7503       else if ( actfunc == OreUVFunc ) {
7504          longvdata = x10global.longvdata;
7505          uvfactor = (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT);
7506          sprintf(minibuf, "X10_oreUV=%d", uvfactor);
7507          *ep++ = add_envptr(minibuf);
7508       }
7509       else if ( actfunc == OwlPowerFunc ) {
7510          dblpower = (double)x10global.longvdata2;
7511          dblpower = dblpower / 1000.0 * OWLPSC * configp->owl_calib_power * (configp->owl_voltage / OWLVREF);
7512          sprintf(minibuf, "X10_owlPower=%.3f", dblpower);
7513          *ep++ = add_envptr(minibuf);
7514          sprintf(minibuf, "X10_owlPowerCount=%lu", x10global.longvdata2);
7515          *ep++ = add_envptr(minibuf);
7516          sprintf(minibuf, "X10_owlSigCount=%u", x10global.sigcount);
7517          *ep++ = add_envptr(minibuf);
7518       }
7519       else if ( actfunc == OwlEnergyFunc ) {
7520          dblenergy = hilo2dbl(x10global.longvdata3, x10global.longvdata2);
7521          dblenergy = dblenergy / 10000.0 * OWLESC * configp->owl_calib_energy * (configp->owl_voltage / OWLVREF);
7522          sprintf(minibuf, "X10_owlEnergy=%.4f", dblenergy);
7523          *ep++ = add_envptr(minibuf);
7524 #ifdef HASULL
7525          sprintf(minibuf, "X10_owlEnergyCount=%lld",
7526             (unsigned long long)x10global.longvdata3 << 32 | (unsigned long long)x10global.longvdata2);
7527 #else
7528          sprintf(minibuf, "X10_owlEnergyCount=0x%lx%08lx", x10global.longvdata3, x10global.longvdata2);
7529 #endif
7530          *ep++ = add_envptr(minibuf);
7531          sprintf(minibuf, "X10_owlSigCount=%u", x10global.sigcount);
7532          *ep++ = add_envptr(minibuf);
7533       }
7534 
7535 
7536 #endif /* HASORE */
7537 
7538       if ( actfunc == DimFunc || actfunc == BrightFunc ) {
7539          sprintf(minibuf, "X10_RawVal=%d", launcherp->rawdim);
7540          *ep++ = add_envptr(minibuf);
7541          sprintf(minibuf, "X10_RawLevel=%d",
7542 	      (launcherp->rawdim - 2) / 11 + 1);
7543          *ep++ = add_envptr(minibuf);
7544          if ( actfunc == 4 ) {
7545             sprintf(minibuf, "X10_DimVal=%d", launcherp->rawdim);
7546             *ep++ = add_envptr(minibuf);
7547             sprintf(minibuf, "X10_BrightVal=-%d", launcherp->rawdim);
7548             *ep++ = add_envptr(minibuf);
7549          }
7550          else {
7551             sprintf(minibuf, "X10_DimVal=-%d", launcherp->rawdim);
7552             *ep++ = add_envptr(minibuf);
7553             sprintf(minibuf, "X10_BrightVal=%d", launcherp->rawdim);
7554             *ep++ = add_envptr(minibuf);
7555          }
7556       }
7557       else if ( actfunc == Preset1Func || actfunc == Preset2Func ) {
7558          sprintf(minibuf, "X10_PresetLevel=%d", launcherp->level);
7559          *ep++ = add_envptr(minibuf);
7560       }
7561       else if ( actfunc == ExtendedFunc ) {
7562          sprintf(minibuf, "X10_Xfunc=%d", launcherp->xfunc);
7563          *ep++ = add_envptr(minibuf);
7564 
7565          sprintf(minibuf, "X10_xFunc=%d", launcherp->xfunc);
7566          *ep++ = add_envptr(minibuf);
7567 
7568          sprintf(minibuf, "X10_Xdata=%d", launcherp->level);
7569          *ep++ = add_envptr(minibuf);
7570       }
7571       else if ( actfunc == VdataFunc ) {
7572          sprintf(minibuf, "X10_Vdata=%d", launcherp->level);
7573          *ep++ = add_envptr(minibuf);
7574 
7575          sprintf(minibuf, "X10_vData=%d", launcherp->level);
7576          *ep++ = add_envptr(minibuf);
7577 
7578          sprintf(minibuf, "X10_Lvdata=%ld", x10global.longvdata);
7579          *ep++ = add_envptr(minibuf);
7580          sprintf(minibuf, "X10_lvData=%ld", x10global.longvdata);
7581          *ep++ = add_envptr(minibuf);
7582       }
7583 
7584       srcname =
7585          (actsource & RCVI) ? "RCVI" :
7586          (actsource & RCVA) ? "RCVA" :
7587          (actsource & SNDC) ? "SNDC" :
7588          (actsource & SNDM) ? "SNDM" :
7589          (actsource & SNDS) ? "SNDS" :
7590          (actsource & SNDA) ? "SNDA" :
7591          (actsource & SNDT) ? "SNDT" :
7592          (actsource & RCVT) ? "RCVT" :
7593          (actsource & SNDP) ? "SNDP" :
7594          (actsource & XMTF) ? "XMTF" : "";
7595 
7596       if ( *srcname ) {
7597          sprintf(minibuf, "X10_Source=%s", srcname);
7598          *ep++ = add_envptr(minibuf);
7599       }
7600    }
7601 
7602    if ( launcherp->type == L_POWERFAIL ) {
7603       sprintf(minibuf, "X10_Boot=%d", ((bootflag & R_ATSTART) ? 1 : 0) );
7604       *ep++ = add_envptr(minibuf);
7605    }
7606    else if ( launcherp->type == L_TIMEOUT ) {
7607       sprintf(minibuf, "X10_Timer=%d", launcherp->timer);
7608       *ep++ = add_envptr(minibuf);
7609    }
7610    else if ( launcherp->type == L_SENSORFAIL && config.aliasp != NULL ) {
7611       aliasindex = launcherp->sensor;
7612       sprintf(minibuf, "X10_Sensor=%c%s", config.aliasp[aliasindex].housecode,
7613          bmap2units(config.aliasp[aliasindex].unitbmap));
7614       *ep++ = add_envptr(minibuf);
7615    }
7616 
7617    /* The following are valid for all launchers */
7618 
7619    /* Put in the common flag variables */
7620    for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
7621       for ( j = 0; j < 32; j++ ) {
7622          sprintf(minibuf, "X10_Flag%d=%d", (32 * k) + j+1, ((x10global.flags[k] & (1UL << j)) ? 1 : 0) );
7623          *ep++ = add_envptr(minibuf);
7624       }
7625    }
7626 
7627    /* Put in the counters and counter-zero flags */
7628    for ( j = 0; j < (32 * NUM_COUNTER_BANKS); j++ ) {
7629       sprintf(minibuf, "X10_Counter%d=%d", j+1, x10global.counter[j]);
7630       *ep++ = add_envptr(minibuf);
7631       sprintf(minibuf, "X10_CzFlag%d=%d", j + 1, ((x10global.czflags[j / 32] & (1UL << (j % 32)) ? 1 : 0)) );
7632       *ep++ = add_envptr(minibuf);
7633    }
7634 
7635    /* Put in the countdown timers */
7636    /* Timer 0 is the arm-pending timer */
7637    sprintf(minibuf, "X10_ArmPendingTimer=%ld", x10global.timer_count[0]);
7638    *ep++ = add_envptr(minibuf);
7639 
7640    /* The rest are the user-settable timers and timer-zero flags */
7641    for ( j = 1; j <= NUM_USER_TIMERS; j++ ) {
7642       sprintf(minibuf, "X10_Timer%d=%ld", j, x10global.timer_count[j]);
7643       *ep++ = add_envptr(minibuf);
7644       sprintf(minibuf, "X10_TzFlag%d=%d", j, ((x10global.tzflags[(j - 1) / 32] & (1UL << ((j - 1) % 32)) ? 1 : 0)) );
7645       *ep++ = add_envptr(minibuf);
7646    }
7647 
7648    /* Global Security flags */
7649    sprintf(minibuf, "X10_Tamper=%d", ((x10global.sflags & GLOBSEC_TAMPER) ? 1 : 0) );
7650    *ep++ = add_envptr(minibuf);
7651    sprintf(minibuf, "X10_Armed=%d", ((x10global.sflags & GLOBSEC_ARMED) ? 1 : 0) );
7652    *ep++ = add_envptr(minibuf);
7653    sprintf(minibuf, "X10_ArmPending=%d", ((x10global.sflags & GLOBSEC_PENDING) ? 1 : 0) );
7654    *ep++ = add_envptr(minibuf);
7655    sprintf(minibuf, "X10_Disarmed=%d", ( !(x10global.sflags & GLOBSEC_ARMED) ? 1 : 0) );
7656    *ep++ = add_envptr(minibuf);
7657    sprintf(minibuf, "X10_Home=%d", ((x10global.sflags & GLOBSEC_HOME) ? 1 : 0) );
7658    *ep++ = add_envptr(minibuf);
7659    sprintf(minibuf, "X10_Away=%d",
7660        (((x10global.sflags & GLOBSEC_ARMED) && !(x10global.sflags & GLOBSEC_HOME)) ? 1 : 0) );
7661    *ep++ = add_envptr(minibuf);
7662    sprintf(minibuf, "X10_SecLights=%d", ((x10global.sflags & GLOBSEC_SLIGHTS) ? 1 : 0) );
7663    *ep++ = add_envptr(minibuf);
7664 
7665    /* Put in the variables X10_DawnTime, X10_DuskTime, and X10_SysTime */
7666    if ( dawndusk_today(&dawn, &dusk) == 0 ) {
7667       sprintf(minibuf, "%s=%ld", "X10_DawnTime", dawn);
7668       *ep++ = add_envptr(minibuf);
7669       sprintf(minibuf, "%s=%ld", "X10_DuskTime", dusk);
7670       *ep++ = add_envptr(minibuf);
7671    }
7672 
7673    /* Add Clock/Calendar variables */
7674 
7675    time(&now);
7676    tms = localtime(&now);
7677 
7678    systime = 3600L * (long)tms->tm_hour + 60L * (long)tms->tm_min + (long)tms->tm_sec;
7679    sprintf(minibuf, "%s=%ld", "X10_SysTime", systime);
7680    *ep++ = add_envptr(minibuf);
7681 
7682    sprintf(minibuf, "%s=%d", "X10_Year", tms->tm_year + 1900);
7683    *ep++ = add_envptr(minibuf);
7684 
7685    sprintf(minibuf, "%s=%d", "X10_Month", tms->tm_mon + 1);
7686    *ep++ = add_envptr(minibuf);
7687 
7688    sprintf(minibuf, "%s=%s", "X10_MonthName", month_name[tms->tm_mon]);
7689    *ep++ = add_envptr(minibuf);
7690 
7691    sprintf(minibuf, "%s=%d", "X10_Day", tms->tm_mday);
7692    *ep++ = add_envptr(minibuf);
7693 
7694    sprintf(minibuf, "%s=%d", "X10_WeekDay", tms->tm_wday);
7695    *ep++ = add_envptr(minibuf);
7696 
7697    sprintf(minibuf, "%s=%s", "X10_WeekDayName", wday_name[tms->tm_wday]);
7698    *ep++ = add_envptr(minibuf);
7699 
7700    sprintf(minibuf, "%s=%d", "X10_Hour", tms->tm_hour);
7701    *ep++ = add_envptr(minibuf);
7702 
7703    sprintf(minibuf, "%s=%d", "X10_Minute", tms->tm_min);
7704    *ep++ = add_envptr(minibuf);
7705 
7706    sprintf(minibuf, "%s=%d", "X10_Second", tms->tm_sec);
7707    *ep++ = add_envptr(minibuf);
7708 
7709    sprintf(minibuf, "%s=%d", "X10_isDST", ((tms->tm_isdst > 0) ? 1 : 0));
7710    *ep++ = add_envptr(minibuf);
7711 
7712    sprintf(minibuf, "%s=%ld", "X10_GMT", (unsigned long)now);
7713    *ep++ = add_envptr(minibuf);
7714 
7715    sprintf(minibuf, "%s=", "X10_DateString");
7716    gendate(minibuf + strlen(minibuf), time(NULL), YES, YES);
7717    strtrim(minibuf);
7718    *ep++ = add_envptr(minibuf);
7719 
7720    if ( x10global.dawndusk_enable ) {
7721       /* Logical variable is true between dusk and dawn */
7722       sprintf(minibuf, "%s=%d",
7723         "X10_isNightTime", ((x10global.sflags & NIGHT_FLAG) ? 1 : 0));
7724       *ep++ = add_envptr(minibuf);
7725 
7726       /* Logical variable is true in the interval after Dusk */
7727       /* and before Dawn by the number of minutes defined by */
7728       /* the config directive ISDARK_OFFSET                  */
7729       sprintf(minibuf, "%s=%d",
7730         "X10_isDarkTime", ((x10global.sflags & DARK_FLAG) ? 1 : 0));
7731       *ep++ = add_envptr(minibuf);
7732    }
7733 
7734    /* Add upload expiration status and time */
7735    expire = get_upload_expire();
7736 
7737    sprintf(minibuf, "%s=%d", "X10_Expire", expire);
7738    *ep++ = add_envptr(minibuf);
7739 
7740 
7741    /* Add bitmap for each Housecode|Unit */
7742    for ( hcode = 0; hcode < 16; hcode++ ) {
7743       hc = code2hc(hcode);
7744 #if 0
7745       addressed = x10state[hcode].addressed;
7746       onstate = x10state[hcode].state[OnState];
7747       dimstate = x10state[hcode].state[DimState];
7748       chgstate = x10state[hcode].state[ChgState];
7749       modchgstate = x10state[hcode].state[ModChgState];
7750       spendstate = x10state[hcode].state[SpendState];
7751       appliance = ~(modmask[DimMask][hcode] | modmask[BriMask][hcode]);
7752 #endif
7753 
7754       /* Add stored long data in unit 0 variable, e.g., X10_A0=nnnn */
7755       if ( x10global.longdata_flags & (unsigned long)(1 << hcode) ) {
7756          sprintf(minibuf, "X10_%c0=%ld", hc, x10state[hcode].longdata);
7757          *ep++ = add_envptr(minibuf);
7758       }
7759 
7760       /* Add RCS temperature if thus configured and valid */
7761       if ( (configp->rcs_temperature & (1 << hcode)) &&
7762            (x10global.rcstemp_flags & (unsigned long)(1 << hcode)) ) {
7763          sprintf(minibuf, "X10_%c0_Temp=%d", hc, x10state[hcode].rcstemp);
7764          *ep++ = add_envptr(minibuf);
7765       }
7766 
7767       for ( ucode = 0; ucode < 16; ucode++ ) {
7768          bitmap = 1 << ucode;
7769          if ( option & SCRIPT_RAWLEVEL )
7770             value = get_heyu_state(hcode, ucode, RAWMODE);
7771          else
7772             value = get_heyu_state(hcode, ucode, PCTMODE);
7773          /* Add standard variable, e.g., X10_A9=nnnn */
7774          sprintf(minibuf, "X10_%c%d=%lu", hc, code2unit(ucode), value);
7775          *ep++ = add_envptr(minibuf);
7776 
7777 
7778          /* Add 'alias' variable, e.g., x10_porch_light=nnnn */
7779          j = 0;
7780          while ( (aliasindex = lookup_alias_mult(hc, bitmap, &j)) >= 0 ) {
7781             sprintf(minibuf, "%s_%s=%lu",
7782                 configp->env_alias_prefix, aliasp[aliasindex].label, value);
7783             *ep++ = add_envptr(minibuf);
7784 
7785 #if 0
7786             vtype = aliasp[aliasindex].vtype;
7787             allflagvalue = 0;
7788             if ( vtype == RF_SEC || (aliasp[aliasindex].optflags & MOPT_PLCSENSOR) > 0 ) {
7789                vflags = x10state[hcode].vflags[ucode];
7790                flagvalue = get_secflag_state(hcode, ucode);
7791                allflagvalue |= flagvalue;
7792                sprintf(minibuf, "X10_%c%d_secFlags=%lu",
7793                   hc, code2unit(ucode), flagvalue);
7794                *ep++ = add_envptr(minibuf);
7795                sprintf(minibuf, "%s_%s_secFlags=%lu",
7796                   configp->env_alias_prefix, aliasp[aliasindex].label, flagvalue);
7797                *ep++ = add_envptr(minibuf);
7798             }
7799             else if ( vtype == RF_XSENSOR || vtype == RF_XMETER ) {
7800                vflags = x10state[hcode].vflags[ucode];
7801                flagvalue = get_rfxflag_state(hcode, ucode);
7802                allflagvalue |= flagvalue;
7803                sprintf(minibuf, "X10_%c%d_rfxFlags=%lu",
7804                   hc, code2unit(ucode), flagvalue);
7805                *ep++ = add_envptr(minibuf);
7806                sprintf(minibuf, "%s_%s_rfxFlags=%lu",
7807                   configp->env_alias_prefix, aliasp[aliasindex].label, flagvalue);
7808                *ep++ = add_envptr(minibuf);
7809             }
7810             else if ( vtype == RF_OREGON || vtype == RF_ELECSAVE || vtype == RF_OWL ) {
7811                vflags = x10state[hcode].vflags[ucode];
7812                flagvalue = get_oreflag_state(hcode, ucode);
7813                allflagvalue |= flagvalue;
7814                sprintf(minibuf, "X10_%c%d_oreFlags=%lu",
7815                   hc, code2unit(ucode), flagvalue);
7816                *ep++ = add_envptr(minibuf);
7817                sprintf(minibuf, "%s_%s_oreFlags=%lu",
7818                   configp->env_alias_prefix, aliasp[aliasindex].label, flagvalue);
7819                *ep++ = add_envptr(minibuf);
7820             }
7821             else if ( vtype == RF_DIGIMAX ) {
7822                vflags = x10state[hcode].vflags[ucode];
7823                flagvalue = get_dmxflag_state(hcode, ucode);
7824                allflagvalue |= flagvalue;
7825                sprintf(minibuf, "X10_%c%d_dmxFlags=%lu",
7826                   hc, code2unit(ucode), flagvalue);
7827                *ep++ = add_envptr(minibuf);
7828                sprintf(minibuf, "%s_%s_dmxFlags=%lu",
7829                   configp->env_alias_prefix, aliasp[aliasindex].label, flagvalue);
7830                *ep++ = add_envptr(minibuf);
7831             }
7832 #endif
7833             vflags = get_vflag_state(hcode, ucode);
7834             sprintf(minibuf, "X10_%c%d_vFlags=%lu",
7835                hc, code2unit(ucode), vflags);
7836             *ep++ = add_envptr(minibuf);
7837             sprintf(minibuf, "%s_%s_vFlags=%lu",
7838                configp->env_alias_prefix, aliasp[aliasindex].label, vflags);
7839             *ep++ = add_envptr(minibuf);
7840          }
7841       }
7842 
7843       /* Add long data for unit 0 aliases */
7844       j = 0;
7845       while ( (aliaslabel = lookup_label_mult(hc, 0, &j)) != NULL ) {
7846          if ( x10global.longdata_flags & (unsigned long)(1 << hcode) ) {
7847             sprintf(minibuf, "%s_%s=%ld",
7848                configp->env_alias_prefix, aliaslabel, x10state[hcode].longdata);
7849             *ep++ = add_envptr(minibuf);
7850          }
7851          if ( x10global.rcstemp_flags & (1 << hcode) ) {
7852             sprintf(minibuf, "%s_%s_Temp=%d",
7853                configp->env_alias_prefix, aliaslabel, x10state[hcode].rcstemp);
7854             *ep++ = add_envptr(minibuf);
7855          }
7856       }
7857    }
7858 
7859 #ifdef HASRFXM
7860 
7861    /* Add RFXMeter data if any */
7862    aliasp = configp->aliasp;
7863    j = 0;
7864    while ( aliasp && aliasp[j].line_no > 0 ) {
7865       if ( aliasp[j].vtype != RF_XMETER ) {
7866          j++;
7867          continue;
7868       }
7869       ucode = single_bmap_unit((aliasp[j].unitbmap));
7870       unit = code2unit(ucode);
7871       hc = aliasp[j].housecode;
7872       hcode = hc2code(hc);
7873 
7874       rfxdata = x10state[hcode].rfxmeter[ucode];
7875       if ( (rfxdata & 1) == 0 ) {
7876          j++;
7877          continue;
7878       }
7879       rfxdata = rfxdata >> 8;
7880 
7881       aliaslabel = aliasp[j].label;
7882 
7883       if ( (aliasp[j].optflags & MOPT_RFXPOWER) && *(configp->rfx_powerunits) ) {
7884          sprintf(valbuf, FMT_RFXPOWER, (double)rfxdata * configp->rfx_powerscale);
7885          sprintf(minibuf, "X10_%c%d_Power=%s", hc, unit, valbuf);
7886          *ep++ = add_envptr(minibuf);
7887          sprintf(minibuf, "%s_%s_Power=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7888          *ep++ = add_envptr(minibuf);
7889       }
7890       else if ( (aliasp[j].optflags & MOPT_RFXWATER) && *(configp->rfx_waterunits) ) {
7891          sprintf(valbuf, FMT_RFXWATER, (double)rfxdata * configp->rfx_waterscale);
7892          sprintf(minibuf, "X10_%c%d_Water=%s", hc, unit, valbuf);
7893          *ep++ = add_envptr(minibuf);
7894          sprintf(minibuf, "%s_%s_Water=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7895          *ep++ = add_envptr(minibuf);
7896       }
7897       else if ( (aliasp[j].optflags & MOPT_RFXGAS) && *(configp->rfx_gasunits) ) {
7898          sprintf(valbuf, FMT_RFXGAS, (double)rfxdata * configp->rfx_gasscale);
7899          sprintf(minibuf, "X10_%c%d_Gas=%s", hc, unit, valbuf);
7900          *ep++ = add_envptr(minibuf);
7901          sprintf(minibuf, "%s_%s_Gas=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7902          *ep++ = add_envptr(minibuf);
7903       }
7904       else if ( (aliasp[j].optflags & MOPT_RFXPULSE) && *(configp->rfx_pulseunits) ) {
7905          sprintf(valbuf, FMT_RFXPULSE, (double)rfxdata * configp->rfx_pulsescale);
7906          sprintf(minibuf, "X10_%c%d_Pulse=%s", hc, unit, valbuf);
7907          *ep++ = add_envptr(minibuf);
7908          sprintf(minibuf, "%s_%s_Pulse=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7909          *ep++ = add_envptr(minibuf);
7910       }
7911 
7912       sprintf(minibuf, "X10_%c%d_Count=%ld", hc, unit, rfxdata);
7913       *ep++ = add_envptr(minibuf);
7914       sprintf(minibuf, "%s_%s_Count=%ld", configp->env_alias_prefix, aliaslabel, rfxdata);
7915       *ep++ = add_envptr(minibuf);
7916 
7917       j++;
7918    }
7919 
7920    /* Power panel totals */
7921    for ( j = 0; j < npowerpanels; j++ ) {
7922       if ( powerpanel_query((unsigned char)j, &rfxdata) == 0 ) {
7923          sprintf(valbuf, FMT_RFXPOWER, (double)rfxdata * configp->rfx_powerscale);
7924          sprintf(minibuf, "X10_Panel_%d=%s", j, valbuf);
7925          *ep++ = add_envptr(minibuf);
7926       }
7927    }
7928 
7929 #endif /* HASRFXM */
7930 
7931 #ifdef HASRFXS
7932    /* Add RFXSensor data if any */
7933    aliasp = configp->aliasp;
7934    j = 0;
7935    while ( aliasp && aliasp[j].line_no > 0 ) {
7936       if ( aliasp[j].vtype != RF_XSENSOR ) {
7937          j++;
7938          continue;
7939       }
7940 
7941       unit = code2unit(single_bmap_unit((aliasp[j].unitbmap)));
7942       hc = aliasp[j].housecode;
7943       aliaslabel = aliasp[j].label;
7944 
7945       decode_rfxsensor_data(aliasp, j, &inmap, &outmap, &temp, &vsup, &vad, &var2);
7946 
7947       if ( outmap & RFXO_T ) {
7948          sprintf(valbuf, FMT_RFXT, temp);
7949          sprintf(minibuf, "X10_%c%d_Temp=%s", hc, unit, valbuf);
7950          *ep++ = add_envptr(minibuf);
7951          sprintf(minibuf, "%s_%s_Temp=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7952          *ep++ = add_envptr(minibuf);
7953       }
7954       if ( outmap & RFXO_S ) {
7955          sprintf(minibuf, "X10_%c%d_Vs=%.2f", hc, unit, vsup);
7956          *ep++ = add_envptr(minibuf);
7957          sprintf(minibuf, "%s_%s_Vs=%.2f", configp->env_alias_prefix, aliaslabel, vsup);
7958          *ep++ = add_envptr(minibuf);
7959       }
7960 //      if ( outmap & RFXO_V ) {
7961       if ( outmap & (RFXO_V | RFXO_H | RFXO_B | RFXO_P) ) {
7962          sprintf(minibuf, "X10_%c%d_Vadi=%.2f", hc, unit, vad);
7963          *ep++ = add_envptr(minibuf);
7964          sprintf(minibuf, "%s_%s_Vadi=%.2f", configp->env_alias_prefix, aliaslabel, vad);
7965          *ep++ = add_envptr(minibuf);
7966       }
7967 
7968       if ( outmap & RFXO_H ) {
7969          sprintf(valbuf, FMT_RFXRH, var2);
7970          sprintf(minibuf, "X10_%c%d_RH=%s", hc, unit, valbuf);
7971          *ep++ = add_envptr(minibuf);
7972          sprintf(minibuf, "%s_%s_RH=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7973          *ep++ = add_envptr(minibuf);
7974       }
7975       else if ( outmap & RFXO_B ) {
7976          sprintf(valbuf, FMT_RFXBP, var2);
7977          sprintf(minibuf, "X10_%c%d_BP=%s", hc, unit, valbuf);
7978          *ep++ = add_envptr(minibuf);
7979          sprintf(minibuf, "%s_%s_BP=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7980          *ep++ = add_envptr(minibuf);
7981       }
7982       else if ( outmap & RFXO_P ) {
7983          sprintf(minibuf, "X10_%c%d_Pot=%.2f", hc, unit, var2);
7984          *ep++ = add_envptr(minibuf);
7985          sprintf(minibuf, "%s_%s_Pot=%.2f", configp->env_alias_prefix, aliaslabel, var2);
7986          *ep++ = add_envptr(minibuf);
7987       }
7988       else if ( outmap & RFXO_T2 ) {
7989          sprintf(valbuf, FMT_RFXT, temp);
7990          sprintf(minibuf, "X10_%c%d_Temp2=%s", hc, unit, valbuf);
7991          *ep++ = add_envptr(minibuf);
7992          sprintf(minibuf, "%s_%s_Temp2=%s", configp->env_alias_prefix, aliaslabel, valbuf);
7993          *ep++ = add_envptr(minibuf);
7994       }
7995       else if ( outmap & inmap & RFXO_V ) {
7996          sprintf(valbuf, FMT_RFXVAD, var2);
7997          sprintf(minibuf, "X10_%c%d_Vad=%s", hc, unit, valbuf);
7998          *ep++ = add_envptr(minibuf);
7999          sprintf(minibuf, "%s_%s_Vad=%s", configp->env_alias_prefix, aliaslabel, valbuf);
8000          *ep++ = add_envptr(minibuf);
8001       }
8002 
8003       j++;
8004    }
8005 #endif /* HASRFXS */
8006 
8007 #ifdef HASDMX
8008    /* Add Digimax data if any */
8009    aliasp = configp->aliasp;
8010    j = 0;
8011    while ( aliasp && aliasp[j].line_no > 0 ) {
8012       int loc;
8013       if ( aliasp[j].vtype != RF_DIGIMAX ) {
8014          j++;
8015          continue;
8016       }
8017       unit = code2unit(single_bmap_unit((aliasp[j].unitbmap)));
8018       hc = aliasp[j].housecode;
8019       aliaslabel = aliasp[j].label;
8020       loc = aliasp[j].storage_index;
8021       if ( (longvdata = x10global.data_storage[loc]) == 0 ) {
8022          j++;
8023          continue;
8024       }
8025 
8026       status = (longvdata & STATMASK) >> STATSHIFT;
8027 
8028       tempc = (longvdata & TCURRMASK) >> TCURRSHIFT;
8029       tempc = (tempc & 0x80) ? 0x80 - tempc : tempc;
8030       sprintf(minibuf, "X10_%c%d_dmxTemp=%d", hc, unit, tempc);
8031       *ep++ = add_envptr(minibuf);
8032       sprintf(minibuf, "%s_%s_dmxTemp=%d",
8033           configp->env_alias_prefix, aliaslabel, tempc);
8034       *ep++ = add_envptr(minibuf);
8035 
8036       if ( longvdata & SETPFLAG ) {
8037          settempc = (longvdata & TSETPMASK) >> TSETPSHIFT;
8038          sprintf(minibuf, "X10_%c%d_dmxSetpoint=%d", hc, unit, settempc);
8039          *ep++ = add_envptr(minibuf);
8040          sprintf(minibuf, "%s_%s_dmxSetpoint=%d",
8041              configp->env_alias_prefix, aliaslabel, settempc);
8042          *ep++ = add_envptr(minibuf);
8043       }
8044 
8045       sprintf(minibuf, "X10_%c%d_dmxSet=%d", hc, unit, ((longvdata & SETPFLAG) ? 1 : 0));
8046       *ep++ = add_envptr(minibuf);
8047       sprintf(minibuf, "%s_%s_dmxSet=%d",
8048           configp->env_alias_prefix, aliaslabel, ((longvdata & SETPFLAG) ? 1 : 0));
8049       *ep++ = add_envptr(minibuf);
8050 
8051       oostatus = (longvdata & ONOFFMASK) >> ONOFFSHIFT;
8052       if ( oostatus > 0 ) {
8053          oostatus = (oostatus == 1) ? 1 : 0;
8054          if ( (longvdata & HEATMASK) && (DMXCOOLSWAP == YES) )
8055             oostatus = (oostatus + 1) % 2;
8056          sprintf(minibuf, "X10_%c%d_dmxStatus=%d", hc, unit, oostatus);
8057          *ep++ = add_envptr(minibuf);
8058          sprintf(minibuf, "%s_%s_dmxStatus=%d",
8059              configp->env_alias_prefix, aliaslabel, oostatus);
8060          *ep++ = add_envptr(minibuf);
8061       }
8062 
8063       sprintf(minibuf, "X10_%c%d_dmxInit=%d", hc, unit, ((status == 3) ? 1 : 0));
8064       *ep++ = add_envptr(minibuf);
8065       sprintf(minibuf, "%s_%s_dmxInit=%d",
8066           configp->env_alias_prefix, aliaslabel, ((status == 3) ? 1 : 0));
8067       *ep++ = add_envptr(minibuf);
8068 
8069       sprintf(minibuf, "X10_%c%d_dmxHeat=%d", hc, unit, ((longvdata & HEATMASK) ? 0 : 1));
8070       *ep++ = add_envptr(minibuf);
8071       sprintf(minibuf, "%s_%s_dmxHeat=%d",
8072           configp->env_alias_prefix, aliaslabel, ((longvdata & HEATMASK) ? 0 : 1));
8073       *ep++ = add_envptr(minibuf);
8074 
8075       j++;
8076    }
8077 #endif /* HASDMX */
8078 
8079 #ifdef HASORE
8080    /* Add Oregon data if any */
8081    aliasp = configp->aliasp;
8082    aliasindex = 0;
8083    while ( aliasp && aliasp[aliasindex].line_no > 0 ) {
8084       int k, loc, func;
8085       if ( aliasp[aliasindex].vtype != RF_OREGON    &&
8086            aliasp[aliasindex].vtype != RF_ELECSAVE  &&
8087            aliasp[aliasindex].vtype != RF_OWL           ) {
8088          aliasindex++;
8089          continue;
8090       }
8091 
8092       unit = code2unit(single_bmap_unit((aliasp[aliasindex].unitbmap)));
8093       hc = aliasp[aliasindex].housecode;
8094       aliaslabel = aliasp[aliasindex].label;
8095       for ( k = 0; k < aliasp[aliasindex].nvar; k++ ) {
8096          func = aliasp[aliasindex].funclist[k];
8097          loc = aliasp[aliasindex].storage_index + aliasp[aliasindex].statusoffset[k];
8098          if ( (longvdata = x10global.data_storage[loc]) == 0 )
8099             break;
8100 
8101          if ( (k == 0) && (channel = (int)((longvdata & ORE_CHANMSK) >> ORE_CHANSHFT)) > 0 ) {
8102             sprintf(minibuf, "X10_%c%d_oreCh=%d", hc, unit, channel);
8103             *ep++ = add_envptr(minibuf);
8104             sprintf(minibuf, "%s_%s_oreCh=%d",
8105                  configp->env_alias_prefix, aliaslabel, channel);
8106             *ep++ = add_envptr(minibuf);
8107          }
8108          if ( (k == 0) && (longvdata & ORE_BATLVL) ) {
8109             blevel = (int)((longvdata & ORE_BATMSK) >> ORE_BATSHFT);
8110             sprintf(minibuf, "X10_%c%d_oreBatLvl=%d", hc, unit, blevel * 10);
8111             *ep++ = add_envptr(minibuf);
8112             sprintf(minibuf, "%s_%s_oreBatLvl=%d",
8113                  configp->env_alias_prefix, aliaslabel, blevel * 10);
8114             *ep++ = add_envptr(minibuf);
8115          }
8116          if ( k == 0 ) {
8117             sprintf(minibuf, "X10_%c%d_oreLoBat=%d", hc, unit, ((longvdata & ORE_LOBAT) ? 1 : 0));
8118             *ep++ = add_envptr(minibuf);
8119             sprintf(minibuf, "%s_%s_oreLoBat=%d",
8120                  configp->env_alias_prefix, aliaslabel, ((longvdata & ORE_LOBAT) ? 1 : 0));
8121             *ep++ = add_envptr(minibuf);
8122          }
8123 
8124          switch ( func ) {
8125             case OreTempFunc :
8126                otempc = (longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8127                if ( longvdata & ORE_NEGTEMP )
8128                   otempc = -otempc;
8129                otemp = celsius2temp((double)otempc / 10.0, configp->ore_tscale, configp->ore_toffset);
8130                sprintf(minibuf, "X10_%c%d_oreTemp="FMT_ORET, hc, unit, otemp);
8131                *ep++ = add_envptr(minibuf);
8132                sprintf(minibuf, "%s_%s_oreTemp="FMT_ORET,
8133                    configp->env_alias_prefix, aliaslabel, otemp);
8134                *ep++ = add_envptr(minibuf);
8135                break;
8136 
8137             case OreHumidFunc :
8138                sprintf(minibuf, "X10_%c%d_oreRH=%d", hc, unit, (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT));
8139                *ep++ = add_envptr(minibuf);
8140                sprintf(minibuf, "%s_%s_oreRH=%d", configp->env_alias_prefix, aliaslabel,
8141                      (int)((longvdata & ORE_DATAMSK) >> ORE_DATASHFT));
8142                *ep++ = add_envptr(minibuf);
8143                break;
8144 
8145             case OreBaroFunc :
8146                obaro = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8147                odbaro = (double)obaro * configp->ore_bpscale + configp->ore_bpoffset;
8148                sprintf(minibuf, "X10_%c%d_oreBP="FMT_OREBP, hc, unit, odbaro);
8149                *ep++ = add_envptr(minibuf);
8150                sprintf(minibuf, "%s_%s_oreBP="FMT_OREBP, configp->env_alias_prefix, aliaslabel, odbaro);
8151                *ep++ = add_envptr(minibuf);
8152                if ( (fcast = (longvdata & ORE_FCAST) >> ORE_FCASTSHFT) > 0 ) {
8153                   sprintf(minibuf, "X10_%c%d_oreForecast=%s", hc, unit, forecast_txt(fcast));
8154                   *ep++ = add_envptr(minibuf);
8155                   sprintf(minibuf, "%s_%s_oreForecast=%s",configp->env_alias_prefix, aliaslabel, forecast_txt(fcast));
8156                   *ep++ = add_envptr(minibuf);
8157                }
8158                break;
8159 
8160             case OreWeightFunc :
8161                cweight = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8162                weight = (double)cweight / 10.0 * configp->ore_wgtscale;
8163                sprintf(minibuf, "X10_%c%d_oreWgt="FMT_OREWGT, hc, unit, weight);
8164                *ep++ = add_envptr(minibuf);
8165                sprintf(minibuf, "%s_%s_oreWgt="FMT_OREWGT, configp->env_alias_prefix, aliaslabel, weight);
8166                *ep++ = add_envptr(minibuf);
8167                break;
8168 
8169             case ElsCurrFunc :
8170                if ( (channel = (int)((longvdata & ORE_CHANMSK) >> ORE_CHANSHFT)) > 0 ) {
8171                   sprintf(minibuf, "X10_%c%d_elsCh=%d", hc, unit, channel);
8172                   *ep++ = add_envptr(minibuf);
8173                   sprintf(minibuf, "%s_%s_elsCh=%d",
8174                        configp->env_alias_prefix, aliaslabel, channel);
8175                   *ep++ = add_envptr(minibuf);
8176                }
8177                deciamps = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8178                sprintf(minibuf, "X10_%c%d_elsCurr=%.1f", hc, unit, (double)deciamps / 10.0);
8179                *ep++ = add_envptr(minibuf);
8180                sprintf(minibuf, "%s_%s_elsCurr=%.1f", configp->env_alias_prefix, aliaslabel,
8181                  (double)deciamps / 10.0);
8182                *ep++ = add_envptr(minibuf);
8183                sprintf(minibuf, "X10_%c%d_elsPwr=%.0f", hc, unit,
8184                   configp->els_voltage * (double)deciamps / 10.0);
8185                *ep++ = add_envptr(minibuf);
8186                sprintf(minibuf, "%s_%s_elsPwr=%.0f", configp->env_alias_prefix, aliaslabel,
8187                   configp->els_voltage * (double)deciamps / 10.0);
8188                *ep++ = add_envptr(minibuf);
8189 
8190 
8191                sprintf(minibuf, "X10_%c%d_elsLoBat=%d", hc, unit, ((longvdata & ORE_LOBAT) ? 1 : 0));
8192                *ep++ = add_envptr(minibuf);
8193                sprintf(minibuf, "%s_%s_elsLoBat=%d",
8194                     configp->env_alias_prefix, aliaslabel, ((longvdata & ORE_LOBAT) ? 1 : 0));
8195                *ep++ = add_envptr(minibuf);
8196                break;
8197 
8198             case OreWindSpFunc :
8199                dwind = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8200                dblwind = (double)dwind / 10.0 * configp->ore_windscale;
8201                sprintf(minibuf, "X10_%c%d_oreWindSp="FMT_OREWSP, hc, unit, dblwind);
8202                *ep++ = add_envptr(minibuf);
8203                sprintf(minibuf, "%s_%s_oreWindSp="FMT_OREWSP, configp->env_alias_prefix, aliaslabel, dblwind);
8204                *ep++ = add_envptr(minibuf);
8205 
8206                break;
8207 
8208             case OreWindAvSpFunc :
8209                dwind = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8210                dblwind = (double)dwind / 10.0 * configp->ore_windscale;
8211                sprintf(minibuf, "X10_%c%d_oreWindAvSp="FMT_OREWSP, hc, unit, dblwind);
8212                *ep++ = add_envptr(minibuf);
8213                sprintf(minibuf, "%s_%s_oreWindAvSp="FMT_OREWSP, configp->env_alias_prefix, aliaslabel, dblwind);
8214                *ep++ = add_envptr(minibuf);
8215                break;
8216 
8217             case OreWindDirFunc :
8218                dwind = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8219                dwind = (dwind + configp->ore_windsensordir + 3600) % 3600;
8220                dblwind = (double)dwind / 10.0;
8221                sprintf(minibuf, "X10_%c%d_oreWindDir=%.1f", hc, unit, dblwind);
8222                *ep++ = add_envptr(minibuf);
8223                sprintf(minibuf, "%s_%s_oreWindDir=%.1f", configp->env_alias_prefix, aliaslabel, dblwind);
8224                *ep++ = add_envptr(minibuf);
8225                break;
8226 
8227             case OreRainRateFunc :
8228                /* 32 bit rainfall rate is stored in an adjoining location */
8229                rain = x10global.data_storage[loc + 1];
8230                dblrain = (double)rain / 1000.0 * configp->ore_rainratescale;
8231                sprintf(minibuf, "X10_%c%d_oreRainRate="FMT_ORERRATE, hc, unit, dblrain);
8232                *ep++ = add_envptr(minibuf);
8233                sprintf(minibuf, "%s_%s_oreRainRate="FMT_ORERRATE, configp->env_alias_prefix, aliaslabel, dblrain);
8234                *ep++ = add_envptr(minibuf);
8235                break;
8236 
8237             case OreRainTotFunc :
8238                /* 32 bit total rainfall is stored in an adjoining location */
8239                rain = x10global.data_storage[loc + 1];
8240                dblrain = (double)rain / 1000.0 * configp->ore_raintotscale;
8241                sprintf(minibuf, "X10_%c%d_oreRainTot="FMT_ORERTOT, hc, unit, dblrain);
8242                *ep++ = add_envptr(minibuf);
8243                sprintf(minibuf, "%s_%s_oreRainTot="FMT_ORERTOT, configp->env_alias_prefix, aliaslabel, dblrain);
8244                *ep++ = add_envptr(minibuf);
8245                break;
8246 
8247             case OreUVFunc :
8248                uvfactor = (int)(longvdata & ORE_DATAMSK) >> ORE_DATASHFT;
8249                sprintf(minibuf, "X10_%c%d_oreUV=%d", hc, unit, uvfactor);
8250                *ep++ = add_envptr(minibuf);
8251                sprintf(minibuf, "%s_%s_oreUV=%d", configp->env_alias_prefix, aliaslabel, uvfactor);
8252                *ep++ = add_envptr(minibuf);
8253                break;
8254 
8255             case OwlPowerFunc :
8256                dblpower = (double)x10global.data_storage[loc + 1];
8257                dblpower = dblpower / 1000.0 * OWLPSC * configp->owl_calib_power * (configp->owl_voltage / OWLVREF);
8258                sprintf(minibuf, "X10_%c%d_owlPower=%.3f", hc, unit, dblpower);
8259                *ep++ = add_envptr(minibuf);
8260                sprintf(minibuf, "%s_%s_owlPower=%.3f", configp->env_alias_prefix, aliaslabel, dblpower);
8261                *ep++ = add_envptr(minibuf);
8262                sprintf(minibuf, "X10_%c%d_owlPowerCount=%ld", hc, unit, x10global.data_storage[loc + 1]);
8263                *ep++ = add_envptr(minibuf);
8264                break;
8265 
8266             case OwlEnergyFunc :
8267                dblenergy = hilo2dbl(x10global.data_storage[loc + 2], x10global.data_storage[loc + 1]);
8268                dblenergy = dblenergy / 10000.0 * OWLESC * configp->owl_calib_energy * (configp->owl_voltage / OWLVREF);
8269                sprintf(minibuf, "X10_%c%d_owlEnergy=%.4f", hc, unit, dblenergy);
8270                *ep++ = add_envptr(minibuf);
8271                sprintf(minibuf, "%s_%s_owlEnergy=%.4f", configp->env_alias_prefix, aliaslabel, dblenergy);
8272                *ep++ = add_envptr(minibuf);
8273 #ifdef HASULL
8274                sprintf(minibuf, "X10_%c%d_owlEnergyCount=%llu", hc, unit,
8275                   (unsigned long long)x10global.data_storage[loc + 2] << 32 | (unsigned long long)x10global.data_storage[loc + 1]);
8276 #else
8277                sprintf(minibuf, "X10_%c%d_owlEnergyCount=0x%lx%08lx", hc, unit,
8278                   x10global.data_storage[loc + 2], x10global.data_storage[loc + 2]);
8279 #endif
8280                *ep++ = add_envptr(minibuf);
8281 
8282                break;
8283 
8284             default :
8285                break;
8286          }
8287       }
8288       aliasindex++;
8289    }
8290 #endif /* HASORE */
8291 
8292    /* Append the user's original environment */
8293    for ( j = 0; j < size; j++ ) {
8294       *ep++ = add_envptr(environ[j]);
8295    }
8296 
8297    /* Add NULL terminator */
8298    *ep++ = NULL;
8299 
8300    /* Make sure we haven't exceeded allocated size */
8301    if ( (int)(ep - envp) > newsize ) {
8302       fprintf(stderr, "Internal error in create_heyu_environment()\n");
8303       fprintf(stderr, "Allocated = %d, actual = %d\n",
8304            newsize, (int)(ep - envp));
8305       exit(1);
8306    }
8307 
8308    return envp;
8309 }
8310 
8311 
8312 /*---------------------------------------------------------------------+
8313  | Create an environment compatible with Xtend scripts.                |
8314  +---------------------------------------------------------------------*/
create_xtend_environment(LAUNCHER * launcherp)8315 char **create_xtend_environment( LAUNCHER *launcherp )
8316 {
8317 
8318    extern char   **environ;
8319 
8320    int           j, size, newsize;
8321    unsigned char hcode, ucode;
8322    char          **envp, **ep;
8323    char          hc;
8324    unsigned int  value, bitmap, addressed, onstate, appliance;
8325    char          minibuf[512];
8326    static int    sizchrptr = sizeof(char *);
8327 
8328 #if 0
8329    static struct {
8330       char *query;
8331       int  mask;
8332    } xtendmaskval[] = {
8333       {"isAppl",    XTMAP_APPL },
8334       {"isAddr",    XTMAP_ADDR },
8335       {"isOn",      XTMAP_ON   },
8336       { NULL,       0          },
8337    };
8338 #endif  /* Reference */
8339 
8340 
8341    if ( launcherp->type == L_NORMAL )
8342       putenv("HEYU_PARENT=ENGINE");
8343    else
8344       putenv("HEYU_PARENT=RELAY");
8345 
8346    /* Get length of original environment */
8347    size = 0;
8348    while ( environ[size] != NULL )
8349       size++;
8350 
8351    newsize = size + 256 + 50;
8352 
8353    if ( (envp = calloc(newsize, sizchrptr)) == NULL ) {
8354       fprintf(stderr, "create_xtend_environment() : out_of_memory\n");
8355       exit(1);
8356    }
8357 
8358    ep = envp;
8359 
8360    *ep++ = add_envptr("IAMXTEND=1");
8361 
8362    /* Put config file pathname in environment for child processes */
8363    sprintf(minibuf, "X10CONFIG=%s", pathspec(heyu_config));
8364    *ep++ = add_envptr(minibuf);
8365 
8366    /* Create the various masks */
8367    j = 0;
8368    while ( xtendmaskval[j].query ) {
8369       sprintf(minibuf, "%s=%lu", xtendmaskval[j].query, xtendmaskval[j].mask);
8370       *ep++ = add_envptr(minibuf);
8371       j++;
8372    }
8373 
8374    for ( hcode = 0; hcode < 16; hcode++ ) {
8375       hc = code2hc(hcode);
8376       addressed = x10state[hcode].addressed;
8377       onstate = x10state[hcode].state[OnState];
8378       appliance = ~(modmask[DimMask][hcode] | modmask[BriMask][hcode]);
8379       for ( ucode = 0; ucode < 16; ucode++ ) {
8380          bitmap = 1 << ucode;
8381          value = 0;
8382 
8383          /* Add the state bits */
8384          if ( appliance & bitmap )
8385             value |= XTMAP_APPL;
8386          if ( addressed & bitmap )
8387             value |= XTMAP_ADDR;
8388          if ( onstate & bitmap )
8389             value |= XTMAP_ON;
8390 
8391          sprintf(minibuf, "X10_%c%d=%d", hc, code2unit(ucode), value);
8392          *ep++ = add_envptr(minibuf);
8393       }
8394    }
8395 
8396    /* Append the user's original environment */
8397    for ( j = 0; j < size; j++ ) {
8398       *ep++ = add_envptr(environ[j]);
8399    }
8400 
8401    /* Add NULL terminator */
8402    *ep++ = NULL;
8403 
8404    return envp;
8405 }
8406 
free_environment(char ** envp)8407 void free_environment ( char **envp )
8408 {
8409    int j = 0;
8410 
8411    if ( !envp )
8412       return;
8413 
8414    while ( envp[j] != NULL ) {
8415       free(envp[j]);
8416       j++;
8417    }
8418 
8419    free(envp);
8420    return;
8421 }
8422 
8423 /*---------------------------------------------------------------------+
8424  | For debugging.                                                      |
8425  +---------------------------------------------------------------------*/
display_environment(char ** envp)8426 void display_environment ( char **envp )
8427 {
8428    int j = 0;
8429 
8430    while ( envp[j] != NULL ) {
8431       printf("%s\n", envp[j]);
8432       j++;
8433    }
8434 }
8435 
8436 /*---------------------------------------------------------------------+
8437  | Execute internal engine precomands at beginning of cmdline.         |
8438  | On return, cmdptr points to remainder of command line.              |
8439  | Return codes:                                                       |
8440  |  0  if normal return.                                               |
8441  | -1  if remainder of command line is to be skipped, e.g., for        |
8442  |     @decskpz or @decskpnz commands.                                 |
8443  |  1  if error.                                                       |
8444  +---------------------------------------------------------------------*/
exec_internal_precommands(char * cmdline,char ** cmdptr)8445 int exec_internal_precommands ( char *cmdline, char **cmdptr )
8446 {
8447    int  tokc, retcode = 0;
8448    char **tokv;
8449    char *bufp;
8450    int  direct_command ( int, char **, int );
8451    char command[80];
8452 
8453    *cmdptr = bufp = cmdline;
8454    while ( 1 ) {
8455       get_token(command, &bufp, ";", sizeof(command) - 1);
8456       strtrim(command);
8457       if ( *command != '@' )
8458          break;
8459       tokenize(command, " \t\r\n", &tokc, &tokv);
8460       retcode = direct_command(tokc, tokv, CMD_INT);
8461       if ( *bufp == ';' )
8462          bufp++;
8463       *cmdptr = bufp;
8464       free(tokv);
8465       if ( retcode != 0 )
8466          break;
8467    }
8468    return retcode;
8469 }
8470 
8471 #ifdef EXEC_POSIX
8472 /*---------------------------------------------------------------------+
8473  | Execute a general script by the state engine - POSIX                |
8474  +---------------------------------------------------------------------*/
exec_script(LAUNCHER * launcherp)8475 int exec_script ( LAUNCHER *launcherp )
8476 {
8477 
8478    int      retcode, scriptnum, /*lindex,*/ status, precode;
8479    PID_T    pid;
8480    unsigned char option;
8481    char     *cmdline, *label, *cmdptr;
8482    char     **envp;
8483    char     *argv[4];
8484    char     *shell;
8485 
8486    if ( !i_am_state || configp->script_ctrl == DISABLE )
8487       return 0;
8488 
8489    scriptnum = launcherp->scriptnum;
8490 
8491    cmdline = configp->scriptp[scriptnum].cmdline;
8492    option = configp->scriptp[scriptnum].script_option;
8493    label = configp->scriptp[scriptnum].label;
8494    shell = configp->script_shell;
8495 
8496    if ( !(option & SCRIPT_QQUIET) ) {
8497       if ( option & SCRIPT_QUIET )
8498          fprintf(stdout, "%s Launching '%s': <quiet>\n", datstrf(), label);
8499       else
8500          fprintf(stdout, "%s Launching '%s': %s\n", datstrf(), label, cmdline);
8501       fflush(stdout);
8502    }
8503 
8504    precode = exec_internal_precommands(cmdline, &cmdptr);
8505 
8506    write_x10state_file();
8507 
8508    if ( precode > 0 ) {
8509       fprintf(stderr, "%s\n", error_message());
8510       fflush(stderr);
8511       return 1;
8512    }
8513    else if ( precode < 0 || *cmdptr == '\0' ) {
8514       return 0;
8515    }
8516 
8517    argv[0] = shell;
8518    argv[1] = "-c";
8519    argv[2] = cmdptr;
8520    argv[3] = NULL;
8521 
8522    retcode = fork();
8523 
8524    if ( retcode == -1 ) {
8525       fprintf(stderr, "Unable to fork() for launching script.\n");
8526       fflush(stderr);
8527       return 1;
8528    }
8529 
8530    if ( retcode == 0 ) {
8531       /* In child process */
8532       if ( (pid = fork()) > (PID_T)0 ) {
8533 	 /* Child dies; grandchild inherited by init */
8534          _exit(0);
8535       }
8536       else if ( pid < (PID_T)0 ) {
8537          fprintf(stderr, "Failed to double fork() for launching script.\n");
8538 	 fflush(stderr);
8539 	 _exit(1);
8540       }
8541       else {
8542          if ( option & SCRIPT_NOENV )
8543             envp = create_noenv_environment(launcherp, D_ENGINE);
8544          else if ( option & SCRIPT_XTEND )
8545             envp = create_xtend_environment(launcherp);
8546          else
8547             envp = create_heyu_environment(launcherp, option);
8548          execve(shell, argv, envp);
8549          perror("Execution of script has failed");
8550          exit(1);
8551       }
8552    }
8553 
8554    /* Wait for child process */
8555    while ( waitpid(retcode, &status, 0) < (PID_T)0 && errno == EINTR )
8556       ;
8557    if (WEXITSTATUS(status) != 0 ) {
8558      fprintf(stderr, "Unable to double fork() for launching script.\n");
8559      return 1;
8560    }
8561 
8562    return 0;
8563 }
8564 
8565 /*---------------------------------------------------------------------+
8566  | Launch a power-fail script by the heyu relay - POSIX                |
8567  +---------------------------------------------------------------------*/
relay_powerfail_script(void)8568 int relay_powerfail_script ( void )
8569 {
8570    int      status;
8571    PID_T    pid, retpid;
8572    char     **envp;
8573    char     *argv[4];
8574 
8575    if ( configp->script_ctrl == DISABLE )
8576       return 0;
8577 
8578    if ( !configp->pfail_script )
8579       return 0;
8580 
8581    argv[0] = configp->script_shell;
8582    argv[1] = "-c";
8583    argv[2] = configp->pfail_script;
8584    argv[3] = NULL;
8585 
8586    retpid = fork();
8587 
8588    if ( retpid == (PID_T)(-1) ) {
8589       syslog(LOG_ERR,"Unable to fork() in relay_powerfail_script().\n");
8590       return 1;
8591    }
8592 
8593    if ( retpid == (PID_T)0 ) {
8594       /* In child process */
8595       if ( (pid = fork()) > (PID_T)0 ) {
8596 	 /* Child dies; grandchild inherited by init */
8597          _exit(0);
8598       }
8599       else if ( pid < (PID_T)0 ) {
8600          syslog(LOG_ERR,"Failed to double fork() in relay_powerfail_script().");
8601 	 _exit(1);
8602       }
8603       else {
8604          envp = create_noenv_environment(NULL, D_RELAY);
8605          execve(configp->script_shell, argv, envp);
8606          perror("Execution of relay_powerfail_script() has failed");
8607          exit(1);
8608       }
8609    }
8610 
8611    /* Wait for child process */
8612    while ( waitpid(retpid, &status, 0) < (PID_T)0 && errno == EINTR )
8613       ;
8614    if (WEXITSTATUS(status) != 0 ) {
8615       syslog(LOG_ERR,"waitpid failed in relay_powerfail_script().");
8616       return 1;
8617    }
8618 
8619    return 0;
8620 }
8621 
8622 /*---------------------------------------------------------------------+
8623  | Start the state engine from main() - POSIX                          |
8624  +---------------------------------------------------------------------*/
start_engine_main(void)8625 int start_engine_main ( void )
8626 {
8627    int         status;
8628    PID_T       pid, retpid;
8629    char        **envp;
8630    char        *argv[4];
8631    extern char heyuprogname[PATH_LEN + 1 + 10];
8632 
8633    strncat(heyuprogname, " engine", sizeof(heyuprogname) - 1 - strlen(heyuprogname));
8634 
8635    argv[0] = configp->script_shell;
8636    argv[1] = "-c";
8637    argv[2] = heyuprogname;
8638    argv[3] = NULL;
8639 
8640    retpid = fork();
8641 
8642    if ( retpid == (PID_T)(-1) ) {
8643       syslog(LOG_ERR,"Unable to fork() in start_engine_main().\n");
8644       return 1;
8645    }
8646 
8647    if ( retpid == (PID_T)0 ) {
8648       /* In child process */
8649       if ( (pid = fork()) > (PID_T)0 ) {
8650 	 /* Child dies; grandchild inherited by init */
8651          _exit(0);
8652       }
8653       else if ( pid < (PID_T)0 ) {
8654          syslog(LOG_ERR,"Failed to double fork() in start_engine_main().");
8655 	 _exit(1);
8656       }
8657       else {
8658          envp = create_noenv_environment(NULL, D_RELAY);
8659          execve(configp->script_shell, argv, envp);
8660          perror("Execution of start_engine_main() has failed");
8661          exit(1);
8662       }
8663    }
8664 
8665    /* Wait for child process */
8666    while ( waitpid(retpid, &status, 0) < (PID_T)0 && errno == EINTR )
8667       ;
8668    if (WEXITSTATUS(status) != 0 ) {
8669       syslog(LOG_ERR,"waitpid failed in start_engine_main().");
8670       return 1;
8671    }
8672 
8673    return 0;
8674 }
8675 
8676 /*---------------------------------------------------------------------+
8677  | Launch heyuhelper - POSIX                                           |
8678  +---------------------------------------------------------------------*/
launch_heyuhelper(unsigned char hcode,unsigned int bitmap,unsigned char actfunc)8679 int launch_heyuhelper ( unsigned char hcode, unsigned int bitmap,
8680                                                 unsigned char actfunc )
8681 {
8682    int           status;
8683    PID_T         pid, retpid;
8684    char          *argv[4];
8685    char          *shell;
8686    char          **envp;
8687    char          hc;
8688    char          cmdline[128];
8689 
8690    if ( configp->script_ctrl == DISABLE )
8691       return 0;
8692 
8693    write_x10state_file();
8694 
8695    hc = tolower((int)code2hc(hcode));
8696 
8697    sprintf(cmdline, "heyuhelper %c%d%s",
8698 	hc, x10state[hcode].lastunit, funclabel[actfunc]);
8699 
8700    shell = configp->script_shell;
8701 
8702    argv[0] = shell;
8703    argv[1] = "-c";
8704    argv[2] = cmdline;
8705    argv[3] = 0;
8706 
8707    retpid = fork();
8708 
8709    if ( retpid == (PID_T)(-1) ) {
8710       fprintf(stderr, "Unable to fork() for launching heyuhelper.\n");
8711       return 1;
8712    }
8713 
8714    if ( retpid == (PID_T)0 ) {
8715       /* In child process */
8716       if ( (pid = fork()) > (PID_T)0 ) {
8717 	 /* Child dies; grandchild inherited by init */
8718          _exit(0);
8719       }
8720       else if ( pid < (PID_T)0 ) {
8721 	 fprintf(stderr, "Unable to fork() 2nd gen for launching heyuhelper.\n");
8722 	 fflush(stderr);
8723 	 _exit(1);
8724       }
8725       else {
8726 	 envp = create_noenv_environment(NULL, D_ENGINE);
8727          execve(shell, argv, envp);
8728          /* Silently exit if failure */
8729          exit(1);
8730       }
8731    }
8732 
8733    /* wait for child process */
8734    while ( waitpid(retpid, &status, 0) < (PID_T)0 && errno == EINTR )
8735       ;
8736    if (WEXITSTATUS(status) != 0 ) {
8737      fprintf(stderr, "Unable to double fork() for launching heyuhelper.\n");
8738      return 1;
8739    }
8740 
8741    return 0;
8742 }
8743 
8744 
8745 #else
8746 /*---------------------------------------------------------------------+
8747  | Execute a general script by the state engine - non-POSIX            |
8748  +---------------------------------------------------------------------*/
exec_script(LAUNCHER * launcherp)8749 int exec_script ( LAUNCHER *launcherp )
8750 {
8751 
8752    int      scriptnum, /*lindex,*/ precode;
8753    PID_T    retpid;
8754    unsigned char option;
8755    char     *cmdline, *label, *cmdptr;
8756    char     **envp;
8757    char     *argv[4];
8758    char     *shell;
8759 
8760    if ( !i_am_state || configp->script_ctrl == DISABLE )
8761       return 0;
8762 
8763    signal(SIGCHLD, SIG_IGN);
8764 
8765    scriptnum = launcherp->scriptnum;
8766    cmdline = configp->scriptp[scriptnum].cmdline;
8767    option = configp->scriptp[scriptnum].script_option;
8768    label = configp->scriptp[scriptnum].label;
8769    shell = configp->script_shell;
8770 
8771    if ( !(option & SCRIPT_QQUIET) ) {
8772       if ( option & SCRIPT_QUIET )
8773          fprintf(stdout, "%s Launching '%s': <quiet>\n", datstrf(), label);
8774       else
8775          fprintf(stdout, "%s Launching '%s': %s\n", datstrf(), label, cmdline);
8776       fflush(stdout);
8777    }
8778 
8779    precode = exec_internal_precommands(cmdline, &cmdptr);
8780 
8781    write_x10state_file();
8782 
8783    if ( precode > 0 ) {
8784       fprintf(stderr, "%s\n", error_message());
8785       fflush(stderr);
8786       return 1;
8787    }
8788    else if ( precode < 0 || *cmdptr == '\0' ) {
8789       return 0;
8790    }
8791 
8792    argv[0] = shell;
8793    argv[1] = "-c";
8794    argv[2] = cmdptr;
8795    argv[3] = 0;
8796 
8797    retpid = fork();
8798 
8799    if ( retpid == (PID_T)(-1) ) {
8800       fprintf(stderr, "Unable to fork() for launching script.\n");
8801       return 1;
8802    }
8803 
8804    if ( retpid == (PID_T)0 ) {
8805       /* In child process */
8806       if ( option & SCRIPT_NOENV )
8807          envp = create_noenv_environment(launcherp, D_ENGINE);
8808       else if ( option & SCRIPT_XTEND )
8809          envp = create_xtend_environment(launcherp);
8810       else
8811          envp = create_heyu_environment(launcherp, option);
8812       execve(shell, argv, envp);
8813       perror("Execution of script has failed");
8814       exit(1);
8815    }
8816 
8817    return 0;
8818 }
8819 
8820 
8821 /*---------------------------------------------------------------------+
8822  | Launch a power-fail script by the heyu relay - non-POSIX            |
8823  +---------------------------------------------------------------------*/
relay_powerfail_script(void)8824 int relay_powerfail_script ( void )
8825 {
8826    PID_T    retpid;
8827    char     **envp;
8828    char     *argv[4];
8829 
8830    if ( configp->script_ctrl == DISABLE )
8831       return 0;
8832 
8833    if ( !configp->pfail_script )
8834       return 0;
8835 
8836    signal(SIGCHLD, SIG_IGN);
8837 
8838    argv[0] = configp->script_shell;
8839    argv[1] = "-c";
8840    argv[2] = configp->pfail_script;
8841    argv[3] = 0;
8842 
8843    retpid = fork();
8844 
8845    if ( retpid == (PID_T)(-1) ) {
8846       fprintf(stderr, "Unable to fork() in relay_powerfail_script().\n");
8847       return 1;
8848    }
8849 
8850    if ( retpid == (PID_T)0 ) {
8851       /* In child process */
8852       envp = create_noenv_environment(NULL, D_RELAY);
8853       execve(configp->script_shell, argv, envp);
8854       perror("Execution of relay_powerfail_script() has failed");
8855       exit(1);
8856    }
8857 
8858    return 0;
8859 }
8860 
8861 /*---------------------------------------------------------------------+
8862  | Start the state engine from main() - non-POSIX                      |
8863  +---------------------------------------------------------------------*/
start_engine_main(void)8864 int start_engine_main ( void )
8865 {
8866    int         j;
8867    PID_T       retpid;
8868    char        **envp;
8869    char        *argv[4];
8870    extern char heyuprogname[PATH_LEN + 1 + 10];
8871 
8872    strncat(heyuprogname, " engine", sizeof(heyuprogname) - 1 - strlen(heyuprogname));
8873 
8874    signal(SIGCHLD, SIG_IGN);
8875 
8876    argv[0] = configp->script_shell;
8877    argv[1] = "-c";
8878    argv[2] = heyuprogname;
8879    argv[3] = 0;
8880 
8881    retpid = fork();
8882 
8883    if ( retpid == (PID_T)(-1) ) {
8884       fprintf(stderr, "Unable to fork() in start_engine_main().\n");
8885       return 1;
8886    }
8887 
8888    if ( retpid == (PID_T)0 ) {
8889       /* In child process */
8890       envp = create_noenv_environment(NULL, D_RELAY);
8891       execve(configp->script_shell, argv, envp);
8892       perror("Execution of start_engine_main() has failed");
8893       exit(1);
8894    }
8895 
8896    /* Wait until engine is ready to go */
8897    for ( j = 0; j < 20; j++ ) {
8898       if ( check_for_engine() == 0 )
8899          break;
8900       millisleep(100);
8901    }
8902 
8903    return 0;
8904 }
8905 
8906 /*---------------------------------------------------------------------+
8907  | Launch heyuhelper - non-POSIX.                                      |
8908  +---------------------------------------------------------------------*/
launch_heyuhelper(unsigned char hcode,unsigned int bitmap,unsigned char actfunc)8909 int launch_heyuhelper ( unsigned char hcode, unsigned int bitmap,
8910                                                 unsigned char actfunc )
8911 {
8912 
8913    PID_T         retpid;
8914    char          *argv[4];
8915    char          *shell;
8916    char          **envp;
8917    char          hc;
8918    char          cmdline[128];
8919 
8920    if ( configp->script_ctrl == DISABLE )
8921       return 0;
8922 
8923    signal(SIGCHLD, SIG_IGN);
8924 
8925    write_x10state_file();
8926 
8927    hc = tolower(code2hc(hcode));
8928 
8929    sprintf(cmdline, "heyuhelper %c%d%s",
8930 	hc, x10state[hcode].lastunit, funclabel[actfunc]);
8931 
8932    shell = configp->script_shell;
8933 
8934    argv[0] = shell;
8935    argv[1] = "-c";
8936    argv[2] = cmdline;
8937    argv[3] = NULL;
8938 
8939    retpid = fork();
8940 
8941    if ( retpid == (PID_T)(-1) ) {
8942       fprintf(stderr, "Unable to fork() for launching heyuhelper.\n");
8943       return 1;
8944    }
8945 
8946    if ( retpid == (PID_T)0 ) {
8947       /* In child process */
8948       envp = create_noenv_environment(NULL, D_ENGINE);
8949       execve(shell, argv, envp);
8950       /* Silently exit if failure */
8951       exit(1);
8952    }
8953 
8954    return 0;
8955 }
8956 
8957 #endif  /* End of ifdef EXEC_POSIX / else block */
8958 
8959 
8960 /*---------------------------------------------------------------------+
8961  | Launch the script identified in LAUNCHER at index launchp           |
8962  +---------------------------------------------------------------------*/
launch_script_old(int * launchp)8963 int launch_script_old ( int *launchp )
8964 {
8965    LAUNCHER *launcherp;
8966 
8967    launcherp = &configp->launcherp[*launchp];
8968    *launchp = -1;
8969 
8970    return exec_script(launcherp);
8971 }
8972 
8973 /*---------------------------------------------------------------------+
8974  | Launch the script identified in LAUNCHER at index launchp           |
8975  +---------------------------------------------------------------------*/
launch_scripts(int * launchp)8976 int launch_scripts ( int *launchp )
8977 {
8978    LAUNCHER *launcherp;
8979    int      j, retcode = 0;
8980 
8981    if ( !i_am_state || !(launcherp = configp->launcherp) )
8982       return 0;
8983 
8984    j = 0;
8985    while ( launcherp[j].line_no > 0 ) {
8986       if ( launcherp[j].matched == YES ) {
8987          launcherp[j].matched = NO;
8988          *launchp = -1;
8989          retcode |= exec_script(&launcherp[j]);
8990       }
8991       j++;
8992    }
8993 
8994    return retcode;
8995 }
8996 
8997 /*---------------------------------------------------------------------+
8998  | Display state information in a variety of formats (primarily for    |
8999  | use in scripts) in response to command line requests.               |
9000  +---------------------------------------------------------------------*/
c_x10state(int argc,char * argv[])9001 int c_x10state ( int argc, char *argv[] )
9002 {
9003    extern void show_module_mask ( unsigned char );
9004 
9005    char          hc;
9006    long          delta;
9007    unsigned char hcode, ucode, unit, check;
9008    unsigned char level;
9009    unsigned int  state, bitmap, aflags;
9010    unsigned long vident, value;
9011    int           j;
9012    char          *query;
9013 
9014    argv++;
9015    argc--;
9016 
9017    check = check_for_engine();
9018 
9019    if ( strcmp(argv[0], "enginestate") == 0 ) {
9020       printf("%d\n", (check ? 0 : 1));
9021       return 0;
9022    }
9023 
9024    if ( check != 0 ) {
9025       fprintf(stderr, "State engine is not running.\n");
9026       return 1;
9027    }
9028 
9029    if ( argc < 1 ) {
9030       fprintf(stderr, "Too few arguments\n");
9031       return 1;
9032    }
9033 
9034    get_configuration(CONFIG_INIT);
9035 
9036 
9037    if ( strcmp(argv[0], "initstateold") == 0 ) {
9038       /* Initialize the state structure to 0 */
9039       if ( argc == 1 ) {
9040          send_x10state_command( ST_INIT_ALL, 0 );
9041          return 0;
9042       }
9043       else {
9044          aflags = parse_addr(argv[1], &hc, &bitmap);
9045          if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || (aflags & A_DUMMY) ) {
9046             fprintf(stderr, "Invalid argument %s\n", argv[1]);
9047             return 1;
9048          }
9049          if ( bitmap )
9050             fprintf(stderr, "Unit code ignored\n");
9051 
9052          send_x10state_command( ST_INIT, hc2code(hc) );
9053       }
9054       return 0;
9055    }
9056 
9057    if ( strcmp(argv[0], "initstate") == 0 ) {
9058       /* Initialize the state structure to 0 */
9059       if ( argc == 1 ) {
9060          send_x10state_command( ST_INIT_ALL, 0 );
9061          return 0;
9062       }
9063       else {
9064          aflags = parse_addr(argv[1], &hc, &bitmap);
9065          if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || (aflags & A_DUMMY) ) {
9066             fprintf(stderr, "Invalid argument %s\n", argv[1]);
9067             return 1;
9068          }
9069          send_initstate_command(hc2code(hc), bitmap);
9070       }
9071       return 0;
9072    }
9073 
9074    if ( strcmp(argv[0], "initothers") == 0 ) {
9075       /* Initialize the cumulative address table to 0 */
9076       send_x10state_command( ST_INIT_OTHERS, 0 );
9077       return 0;
9078    }
9079 
9080    if ( strcmp(argv[0], "fetchstate") == 0 ) {
9081       return fetch_x10state();
9082    }
9083    else {
9084       if ( read_x10state_file() != 0 ) {
9085          fprintf(stderr, "Unable to read state file.\n");
9086          return 1;
9087       }
9088    }
9089 
9090    if ( strcmp(argv[0], "onstate")     == 0 ||
9091         strcmp(argv[0], "offstate")    == 0 ||
9092         strcmp(argv[0], "dimstate")    == 0 ||
9093         strcmp(argv[0], "fullonstate") == 0 ||
9094         strcmp(argv[0], "chgstate")    == 0 ||
9095         strcmp(argv[0], "addrstate")   == 0 ||
9096         strcmp(argv[0], "alertstate")  == 0 ||
9097         strcmp(argv[0], "clearstate")  == 0 ||
9098         strcmp(argv[0], "auxalertstate")  == 0 ||
9099         strcmp(argv[0], "auxclearstate") == 0 ||
9100         strcmp(argv[0], "lobatstate") == 0 ||
9101         strcmp(argv[0], "inactivestate") == 0 ||
9102         strcmp(argv[0], "activestate")   == 0 ||
9103         strcmp(argv[0], "activechgstate") == 0  ||
9104         strcmp(argv[0], "tamperstate") == 0 ||
9105 //        strcmp(argv[0], "swminstate") == 0 ||
9106 //        strcmp(argv[0], "swmaxstate") == 0 ||
9107         strcmp(argv[0], "modchgstate") == 0 ||
9108         strcmp(argv[0], "validstate") == 0 ) {
9109 
9110       if ( argc < 2 ) {
9111          fprintf(stderr, "%s: Housecode[Unit] needed\n", argv[0]);
9112          return 1;
9113       }
9114 
9115       aflags = parse_addr(argv[1], &hc, &bitmap) ;
9116       if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || (aflags & A_DUMMY) ) {
9117          fprintf(stderr, "%s: Invalid Housecode|Unit '%s'\n", argv[0], argv[1]);
9118          return 1;
9119       }
9120       if ( aflags & A_MULT && config.state_ctrl == SC_SINGLE ) {
9121          fprintf(stderr, "%s: Only a single unit code is acceptable\n", argv[0]);
9122          return 1;
9123       }
9124 
9125       if ( aflags & A_MINUS )
9126          bitmap = 0;
9127       if ( aflags & A_PLUS && bitmap == 0 )
9128 	 bitmap = 1;
9129       if ( bitmap == 0 )
9130          bitmap = 0xffff;
9131 
9132       hcode = hc2code(hc);
9133 
9134       if ( configp->state_format == NEW ) {
9135          if ( strcmp(argv[0], "onstate") == 0 )
9136 	    state = x10state[hcode].state[OnState] & bitmap;
9137 	 else if ( strcmp(argv[0], "offstate") == 0 )
9138 	    state = ~x10state[hcode].state[OnState] & bitmap;
9139 	 else if ( strcmp(argv[0], "dimstate") == 0 )
9140 	    state = x10state[hcode].state[DimState] & bitmap;
9141 	 else if ( strcmp(argv[0], "fullonstate") == 0 )
9142 	    state = (~x10state[hcode].state[DimState] & x10state[hcode].state[OnState]) & bitmap;
9143 	 else if ( strcmp(argv[0], "chgstate") == 0 )
9144             state = x10state[hcode].state[ChgState] & bitmap;
9145 	 else if ( strcmp(argv[0], "modchgstate") == 0 )
9146             state = x10state[hcode].state[ModChgState] & bitmap;
9147          else if ( strcmp(argv[0], "alertstate") == 0 )
9148             state = x10state[hcode].state[AlertState] & bitmap;
9149 	 else if ( strcmp(argv[0], "clearstate") == 0 )
9150             state = x10state[hcode].state[ClearState] & bitmap;
9151          else if ( strcmp(argv[0], "auxalertstate") == 0 )
9152             state = x10state[hcode].state[AuxAlertState] & bitmap;
9153 	 else if ( strcmp(argv[0], "auxclearstate") == 0 )
9154             state = x10state[hcode].state[AuxClearState] & bitmap;
9155          else if ( strcmp(argv[0], "validstate") == 0 )
9156             state = x10state[hcode].state[ValidState] & bitmap;
9157 	 else if ( strcmp(argv[0], "addrstate") == 0 ) {
9158             if ( configp->autofetch == YES && fetch_x10state() != 0 )
9159 	       return 1;
9160 	    state = x10state[hcode].addressed & bitmap;
9161 	 }
9162          else if ( strcmp(argv[0], "lobatstate") == 0 ) {
9163             state = x10state[hcode].state[LoBatState] & bitmap;
9164          }
9165          else if ( strcmp(argv[0], "tamperstate") == 0 ) {
9166             state = x10state[hcode].state[TamperState] & bitmap;
9167          }
9168 #if 0
9169          else if ( strcmp(argv[0], "swminstate") == 0 ) {
9170             state = x10state[hcode].state[SwMinState] & bitmap;
9171          }
9172          else if ( strcmp(argv[0], "swmaxstate") == 0 ) {
9173             state = x10state[hcode].state[SwMaxState] & bitmap;
9174          }
9175 #endif
9176          else if ( strcmp(argv[0], "inactivestate") == 0 ) {
9177             fetch_x10state();
9178             state = x10state[hcode].state[InactiveState] & bitmap;
9179          }
9180          else if ( strcmp(argv[0], "activestate") == 0 ) {
9181             fetch_x10state();
9182             state = x10state[hcode].state[ActiveState] & bitmap;
9183          }
9184          else if ( strcmp(argv[0], "activechgstate") == 0 ) {
9185             fetch_x10state();
9186             state = x10state[hcode].state[ActiveChgState] & bitmap;
9187          }
9188 	 else {
9189 	    state = 0;
9190          }
9191 
9192 	 if ( bitmap == 0xffff || config.state_ctrl == SC_BITMAP )
9193             printf("%d\n", x10map2linmap(state));
9194          else
9195             printf("%d\n", ((state & bitmap) ? 1 : 0) );
9196 
9197 	 return 0;
9198       }
9199 
9200       if ( configp->state_format == OLD ) {
9201 	 /* heyuhelper format */
9202          if ( !bitmap ) {
9203             fprintf(stderr, "%s: No unit specified in '%s'\n", argv[0], argv[1]);
9204             return 1;
9205          }
9206 
9207          hc = tolower((int)hc);
9208          ucode = single_bmap_unit(bitmap);
9209          unit = code2unit(ucode);
9210 
9211          if ( strcmp(argv[0], "onstate") == 0 ) {
9212             if ( x10state[hcode].state[OnState] & bitmap )
9213                printf("%c%dOn\n", hc, unit);
9214             else
9215                printf("%c%dOff\n", hc, unit);
9216          }
9217          else if ( strcmp(argv[0], "dimstate") == 0 ) {
9218             if ( x10state[hcode].state[DimState] & bitmap )
9219                printf("%c%dDim\n", hc, unit);
9220             else if ( x10state[hcode].state[OnState] & bitmap )
9221                printf("%c%dOn\n", hc, unit);
9222             else
9223                printf("%c%dOff\n", hc, unit);
9224          }
9225          else if ( strcmp(argv[0], "chgstate") == 0 ) {
9226             if ( x10state[hcode].state[ChgState] & bitmap )
9227                printf("%c%dChg\n", hc, unit);
9228             else
9229                printf("%c%dUnchg\n", hc, unit);
9230          }
9231          else if ( strcmp(argv[0], "modchgstate") == 0 ) {
9232             if ( x10state[hcode].state[ModChgState] & bitmap )
9233                printf("%c%dChg\n", hc, unit);
9234             else
9235                printf("%c%dUnchg\n", hc, unit);
9236          }
9237          else if ( strcmp(argv[0], "addrstate") == 0 ) {
9238             if ( configp->autofetch == YES && fetch_x10state() != 0 )
9239                return 1;
9240             if ( x10state[hcode].addressed & bitmap )
9241                printf("%c%dAddr\n", hc, unit);
9242             else
9243                printf("%c%dUnaddr\n", hc, unit);
9244          }
9245 	 return 0;
9246       }
9247    }
9248 
9249 
9250    if ( strcmp(argv[0], "dimlevel")    == 0 ||
9251         strcmp(argv[0], "rawlevel")    == 0 ||
9252         strcmp(argv[0], "memlevel")    == 0 ||
9253         strcmp(argv[0], "rawmemlevel") == 0 ||
9254         strcmp(argv[0], "rcstemp")     == 0 ||
9255         strcmp(argv[0], "vident")      == 0 ||
9256         strcmp(argv[0], "sincelast")   == 0 ||
9257         strcmp(argv[0], "heyu_state")  == 0 ||
9258         strcmp(argv[0], "heyu_rawstate")  == 0 ||
9259         strcmp(argv[0], "heyu_vflagstate") == 0 ||
9260         strcmp(argv[0], "secflag_state") == 0 ||
9261         strcmp(argv[0], "rfxflag_state") == 0 ||
9262         strcmp(argv[0], "oreflag_state") == 0 ||
9263         strcmp(argv[0], "dmxflag_state") == 0 ||
9264         strcmp(argv[0], "verbose_rawstate") == 0 ||
9265         strcmp(argv[0], "xtend_state") == 0   ) {
9266 
9267       if ( argc < 2 ) {
9268          if ( strcmp(argv[0], "rcstemp") == 0 )
9269             fprintf(stderr, "%s: Housecode needed\n", argv[0]);
9270          else
9271             fprintf(stderr, "%s: Housecode|Unit needed\n", argv[0]);
9272          return 1;
9273       }
9274 
9275       aflags = parse_addr(argv[1], &hc, &bitmap) ;
9276       if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || (aflags & A_DUMMY) ) {
9277          fprintf(stderr, "%s: Invalid Housecode|Unit '%s'\n", argv[0], argv[1]);
9278          return 1;
9279       }
9280       if ( aflags & A_MULT ) {
9281          fprintf(stderr, "%s: Only a single unit code is acceptable\n", argv[0]);
9282          return 1;
9283       }
9284 
9285       if ( aflags & A_MINUS )
9286          bitmap = 0;
9287       if ( aflags & A_PLUS && bitmap == 0 )
9288 	 bitmap = 1;
9289 
9290       hcode = hc2code(hc);
9291 
9292       if ( strcmp(argv[0], "rcstemp") == 0 ) {
9293          if ( (configp->rcs_temperature & (1 << hcode)) == 0 ) {
9294             fprintf(stderr,
9295                "This housecode is not configured in the RCS_DECODE directive.\n");
9296             return 1;
9297          }
9298          else if ( x10global.rcstemp_flags & (unsigned long)(1 << hcode) ) {
9299             printf("%d\n", x10state[hcode].rcstemp);
9300             return 0;
9301          }
9302          else {
9303             fprintf(stderr, "No temperature data has been stored.\n");
9304             return 1;
9305          }
9306       }
9307 
9308       if ( !bitmap ) {
9309          if ( strcmp(argv[0], "rawlevel") == 0 ) {
9310             if ( x10global.longdata_flags & (unsigned long)(1 << hcode) ) {
9311                printf("%ld\n", x10state[hcode].longdata);
9312                return 0;
9313             }
9314             else {
9315                fprintf(stderr, "No valid data has been stored.\n");
9316                return 1;
9317             }
9318          }
9319          else {
9320             fprintf(stderr, "%s: No unit specified in '%s'\n", argv[0], argv[1]);
9321             return 1;
9322          }
9323       }
9324 
9325       hc = tolower((int)hc);
9326       ucode = single_bmap_unit(bitmap);
9327       unit = code2unit(ucode);
9328       if ( strcmp(argv[0], "dimlevel") == 0 ) {
9329          /* Level as a percentage of full On */
9330          level = x10state[hcode].dimlevel[ucode];
9331          if ( modmask[Ext3Mask][hcode] & bitmap )
9332             printf("%d\n", ext3level2pct(level));
9333          else if ( modmask[PresetMask][hcode] & bitmap )
9334             printf("%d\n", presetlevel2pct(level));
9335          else if ( modmask[StdMask][hcode] & bitmap )
9336             printf("%d\n", dims2pct(level));
9337 	 else if ( modmask[Ext0Mask][hcode] & bitmap )
9338             printf("%d\n", ext0level2pct(level));
9339          else if ( vmodmask[VkakuMask][hcode] & bitmap )
9340             printf("%d\n", (int)(100 * level) / 15);
9341          else {
9342             printf("%d\n", (int)(100 * level) / ondimlevel[hcode][ucode]);
9343          }
9344       }
9345       else if ( strcmp(argv[0], "memlevel") == 0 ) {
9346          /* Memory level as a percentage of full On */
9347          level = x10state[hcode].memlevel[ucode];
9348          if ( modmask[Ext3Mask][hcode] & bitmap )
9349             printf("%d\n", ext3level2pct(level));
9350          else if ( modmask[PresetMask][hcode] & bitmap )
9351             printf("%d\n", presetlevel2pct(level));
9352          else if ( modmask[StdMask][hcode] & bitmap )
9353             printf("%d\n", dims2pct(level));
9354 	 else if ( modmask[Ext0Mask][hcode] & bitmap )
9355             printf("%d\n", ext0level2pct(level));
9356          else if ( vmodmask[VkakuMask][hcode] & bitmap )
9357             printf("%d\n", (int)(100 * level) / 15);
9358          else {
9359             printf("%d\n", (int)(100 * level) / ondimlevel[hcode][ucode]);
9360          }
9361       }
9362       else if ( strcmp(argv[0], "rawlevel") == 0 ) {
9363          /* Native module level */
9364          level = x10state[hcode].dimlevel[ucode];
9365          if ( modmask[PresetMask][hcode] & bitmap )
9366             printf("%d\n", level + 1);
9367          else {
9368             printf("%d\n", level);
9369          }
9370       }
9371       else if ( strcmp(argv[0], "rawmemlevel") == 0 ) {
9372          /* Native module memory level */
9373          level = x10state[hcode].memlevel[ucode];
9374          if ( modmask[PresetMask][hcode] & bitmap )
9375             printf("%d\n", level + 1);
9376          else {
9377             printf("%d\n", level);
9378          }
9379       }
9380       else if ( strcmp(argv[0], "vident") == 0 ) {
9381          /* Virtual ident */
9382          vident = x10state[hcode].vident[ucode];
9383          printf("0x%02lX\n", vident);
9384       }
9385       else if ( strcmp(argv[0], "sincelast") == 0 ) {
9386          /* Seconds since last signal */
9387          delta = (long)(time(NULL) - x10state[hcode].timestamp[ucode]);
9388          if ( x10state[hcode].timestamp[ucode] == 0 ||
9389               delta < 0 || delta > (365L * 86400L) ) {
9390             printf("-1\n");
9391          }
9392          else {
9393             printf("%ld\n", delta) ;
9394          }
9395       }
9396       else if ( strcmp(argv[0], "heyu_state") == 0 ) {
9397          /* Heyu script bitmap format */
9398          if ( configp->autofetch == YES && fetch_x10state() != 0 )
9399             return 1;
9400          printf("%lu\n", get_heyu_state(hcode, ucode, PCTMODE));
9401       }
9402       else if ( strcmp(argv[0], "heyu_rawstate") == 0 ) {
9403          /* Heyu script bitmap format, but with native levels */
9404          if ( configp->autofetch == YES && fetch_x10state() != 0 )
9405             return 1;
9406          printf("%lu\n", get_heyu_state(hcode, ucode, RAWMODE));
9407       }
9408       else if ( strcmp(argv[0], "xtend_state") == 0 ) {
9409          /* Xtend script bitmap format */
9410          if ( configp->autofetch == YES && fetch_x10state() != 0 )
9411             return 1;
9412          printf("%lu\n", get_xtend_state(hcode, ucode));
9413       }
9414       else if ( strcmp(argv[0], "heyu_vflagstate") == 0 ) {
9415          /* All vflags */
9416          printf("%lu\n", get_vflag_state(hcode, ucode));
9417       }
9418 #if 0
9419       else if ( strcmp(argv[0], "secflag_state") == 0 ) {
9420          /* Security flags */
9421          printf("%lu\n", get_secflag_state(hcode, ucode));
9422       }
9423       else if ( strcmp(argv[0], "rfxflag_state") == 0 ) {
9424          /* Security flags */
9425          printf("%lu\n", get_rfxflag_state(hcode, ucode));
9426       }
9427       else if ( strcmp(argv[0], "oreflag_state") == 0 ) {
9428          /* Security flags */
9429          printf("%lu\n", get_oreflag_state(hcode, ucode));
9430       }
9431       else if ( strcmp(argv[0], "dmxflag_state") == 0 ) {
9432          /* Security flags */
9433          printf("%lu\n", get_dmxflag_state(hcode, ucode));
9434       }
9435 #endif
9436       else if ( strcmp(argv[0], "verbose_rawstate") == 0 ) {
9437          fetch_x10state();
9438          value = get_heyu_state(hcode, ucode, RAWMODE);
9439          printf("$X10_%c%d = %lu\n", code2hc(hcode), code2unit(ucode), value);
9440          printf("   %-11s 0x%02lx\n", heyumaskval[0].query, value & heyumaskval[0].mask);
9441          j = 1;
9442          while ( (query = heyumaskval[j].query) ) {
9443             printf("   %-11s %d\n", query, ((value & heyumaskval[j].mask) ? 1 : 0) );
9444             j++;
9445          }
9446 
9447          value = get_vflag_state(hcode, ucode);
9448          printf("\n$X10_%c%d_heyu_vflagstate = %lu\n", code2hc(hcode), code2unit(ucode), value);
9449          j = 0;
9450          while ( (query = heyusecmaskval[j].query) ) {
9451             printf("   %-11s %d\n", query, ((value & heyusecmaskval[j].mask) ? 1 : 0) );
9452             j++;
9453          }
9454       }
9455 
9456       return 0;
9457    }
9458 
9459    if ( strcmp(argv[0], "statestr") == 0 ) {
9460       if ( argc > 1 ) {
9461          aflags = parse_addr(argv[1], &hc, &bitmap) ;
9462          if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || (aflags & A_DUMMY) ) {
9463             fprintf(stderr, "%s: Invalid Housecode in '%s'\n", argv[0], argv[1]);
9464             return 1;
9465          }
9466 
9467 	 if ( aflags & A_MINUS )
9468             bitmap = 0;
9469 	 if ( aflags & A_PLUS && bitmap == 0 )
9470 	    bitmap = 1;
9471 
9472          if ( bitmap ) {
9473             fprintf(stderr, "%s: Units in '%s' ignored\n", argv[0], argv[1]);
9474          }
9475 
9476 	 if ( configp->autofetch == YES && fetch_x10state() != 0 )
9477             return 1;
9478 
9479          hcode = hc2code(hc);
9480          hc = toupper((int)hc);
9481 
9482          printf("%s\n",
9483 	      bmap2statestr(x10state[hcode].state[OnState],
9484                             x10state[hcode].state[DimState],
9485 	                    x10state[hcode].state[ChgState],
9486 	                    x10state[hcode].addressed) );
9487 
9488          return 0;
9489       }
9490       fprintf(stderr, "%s: Housecode needed\n", argv[0]);
9491       return 1;
9492    }
9493 
9494 
9495    fprintf(stderr, "State command '%s' not recognized\n", argv[0]);
9496    return 1;
9497 }
9498 
9499 /*---------------------------------------------------------------------+
9500  | Display a table showing the dimlevels of every Housecode|Unit,      |
9501  | expressed as a (integer) percentage of full On brightness.          |
9502  +---------------------------------------------------------------------*/
show_all_dimlevels(void)9503 void show_all_dimlevels ( void )
9504 {
9505    char hc;
9506    int  unit;
9507    unsigned char hcode, ucode, level;
9508    unsigned int mask;
9509 
9510    printf("%20sPercent of Full Brightness\n", "");
9511    printf("  Unit:");
9512    for ( unit = 1; unit <= 16; unit++ )
9513       printf("%3d ", unit);
9514    printf("\n");
9515    printf("Hcode  ");
9516    for ( unit = 1; unit <= 16; unit++ )
9517       printf(" -- ");
9518    printf("\n");
9519 
9520    for ( hc = 'A'; hc <= 'P'; hc++ ) {
9521       printf("  %c    ", hc);
9522       hcode = hc2code(hc);
9523       for ( unit = 1; unit <= 16; unit++ ) {
9524          ucode = unit2code(unit);
9525          mask = 1 << ucode;
9526          level = x10state[hcode].dimlevel[ucode];
9527          if ( modmask[Ext3Mask][hcode] & mask )
9528             printf("%3d ", ext3level2pct(level));
9529          else if ( modmask[PresetMask][hcode] & mask )
9530             printf("%3d ", presetlevel2pct(level));
9531          else if ( modmask[StdMask][hcode] & mask )
9532             printf("%3d ", dims2pct(level));
9533          else if ( modmask[Ext0Mask][hcode] & mask )
9534             printf("%3d ", ext0level2pct(level));
9535 	 else {
9536 	    printf("%3d ", (int)(100 * level) / ondimlevel[hcode][ucode]);
9537          }
9538       }
9539       printf("\n");
9540    }
9541 
9542    return;
9543 }
9544 
9545 /*---------------------------------------------------------------------+
9546  | Display a table showing the dimlevel of each Housecode|Unit in the  |
9547  | native form for the module at the address, i.e., 0-210 for standard |
9548  | modules, 1-32 for Preset modules, and 0-63 for Extended modules.    |
9549  | Preset and Extended levels are prefixed respectively by 'p' and 'e'.|
9550  +---------------------------------------------------------------------*/
show_all_dimlevels_raw(void)9551 void show_all_dimlevels_raw ( void )
9552 {
9553    char hc;
9554    int  unit;
9555    unsigned char hcode, ucode, level;
9556    unsigned int mask;
9557    char buffer[16];
9558 
9559    printf("Raw Levels:\n (p: Preset 1-32, e: Ext 0-63, s: Shutter 0-25, v: Virt 00-ff, else 0-210)\n");
9560    printf("  Unit:");
9561    for ( unit = 1; unit <= 16; unit++ )
9562       printf("%3d ", unit);
9563    printf("\n");
9564    printf("Hcode  ");
9565    for ( unit = 1; unit <= 16; unit++ )
9566       printf(" -- ");
9567    printf("\n");
9568 
9569    for ( hc = 'A'; hc <= 'P'; hc++ ) {
9570       printf("  %c    ", hc);
9571       hcode = hc2code(hc);
9572       for ( unit = 1; unit <= 16; unit++ ) {
9573          ucode = unit2code(unit);
9574          mask = 1 << ucode;
9575          level = x10state[hcode].dimlevel[ucode];
9576          if ( modmask[Ext3Mask][hcode] & mask )
9577             sprintf(buffer, "e%d", level);
9578          else if ( modmask[PresetMask][hcode] & mask )
9579             sprintf(buffer, "p%d", level + 1);
9580          else if ( modmask[StdMask][hcode] & mask )
9581             sprintf(buffer, "%d", level);
9582          else if ( modmask[Ext0Mask][hcode] & mask )
9583             sprintf(buffer, "s%d", level);
9584          else if ( modmask[VdataMask][hcode] & mask )
9585             sprintf(buffer, "v%02x", level);
9586 	 else
9587 	    sprintf(buffer, "%d", level);
9588          printf("%3s ", buffer);
9589       }
9590       printf("\n");
9591    }
9592 
9593    return;
9594 }
9595 
9596 
9597 /*---------------------------------------------------------------------+
9598  | Return the index to a new LAUNCHER in the array of same.            |
9599  +---------------------------------------------------------------------*/
launcher_index(LAUNCHER ** launcherpp)9600 int launcher_index ( LAUNCHER **launcherpp )
9601 {
9602    static int    size, maxsize;
9603    static int    sizlauncher = sizeof(LAUNCHER);
9604    int           j, k, index, blksize = 5;
9605 
9606    /* Allocate initial block if not already done */
9607    if ( *launcherpp == NULL ) {
9608       *launcherpp = calloc(blksize, sizlauncher );
9609       if ( *launcherpp == NULL ) {
9610          (void) fprintf(stderr, "Unable to allocate memory for Launcher.\n");
9611          exit(1);
9612       }
9613       maxsize = blksize;
9614       size = 0;
9615       for ( j = 0; j < maxsize; j++ ) {
9616          (*launcherpp)[j].type = L_NORMAL;
9617          (*launcherpp)[j].matched = NO;
9618          (*launcherpp)[j].scanmode = 0;
9619          (*launcherpp)[j].line_no = -1 ;
9620          (*launcherpp)[j].scriptnum = -1;
9621          (*launcherpp)[j].label[0] = '\0';
9622          (*launcherpp)[j].bmaptrig = 0;
9623          (*launcherpp)[j].chgtrig = 0;
9624          for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
9625             (*launcherpp)[j].flags[k] = 0;
9626             (*launcherpp)[j].notflags[k] = 0;
9627          }
9628          (*launcherpp)[j].sflags = 0;
9629          (*launcherpp)[j].notsflags = 0;
9630          (*launcherpp)[j].vflags = 0;
9631          (*launcherpp)[j].notvflags = 0;
9632          for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
9633             (*launcherpp)[j].czflags[k] = 0;
9634             (*launcherpp)[j].notczflags[k] = 0;
9635          }
9636          for ( k = 0; k < NUM_TIMER_BANKS; k++ ) {
9637             (*launcherpp)[j].tzflags[k] = 0;
9638             (*launcherpp)[j].nottzflags[k] = 0;
9639          }
9640          (*launcherpp)[j].bootflag = 0;
9641          (*launcherpp)[j].trigemuflag = 0;
9642          (*launcherpp)[j].unitstar = 0;
9643          (*launcherpp)[j].timer = 0;
9644          (*launcherpp)[j].sensor = 0;
9645          (*launcherpp)[j].afuncmap = 0;
9646          (*launcherpp)[j].gfuncmap = 0;
9647          (*launcherpp)[j].xfuncmap = 0;
9648          (*launcherpp)[j].sfuncmap = 0;
9649          (*launcherpp)[j].ofuncmap = 0;
9650          (*launcherpp)[j].kfuncmap = 0;
9651          (*launcherpp)[j].signal = 0;
9652          (*launcherpp)[j].module = 0;
9653          (*launcherpp)[j].source = 0;
9654          (*launcherpp)[j].nosource = 0;
9655          (*launcherpp)[j].oksofar = 0;
9656          (*launcherpp)[j].actsource = 0;
9657          (*launcherpp)[j].num_stflags = 0;
9658       }
9659    }
9660 
9661    /* Check to see if there's an available location          */
9662    /* If not, increase the size of the memory allocation.    */
9663    /* (Always leave room for a final termination indicator.) */
9664    if ( size == (maxsize - 1) ) {
9665       maxsize += blksize ;
9666       *launcherpp = realloc(*launcherpp, maxsize * sizlauncher );
9667       if ( *launcherpp == NULL ) {
9668          (void) fprintf(stderr, "Unable to increase size of Launcher list.\n");
9669          exit(1);
9670       }
9671 
9672       /* Initialize the new memory allocation */
9673       for ( j = size; j < maxsize; j++ ) {
9674          (*launcherpp)[j].type = L_NORMAL;
9675          (*launcherpp)[j].matched = NO;
9676          (*launcherpp)[j].scanmode = 0;
9677          (*launcherpp)[j].line_no = -1 ;
9678          (*launcherpp)[j].scriptnum = -1;
9679          (*launcherpp)[j].label[0] = '\0';
9680          (*launcherpp)[j].bmaptrig = 0;
9681          (*launcherpp)[j].chgtrig = 0;
9682          for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
9683             (*launcherpp)[j].flags[k] = 0;
9684             (*launcherpp)[j].notflags[k] = 0;
9685          }
9686          (*launcherpp)[j].sflags = 0;
9687          (*launcherpp)[j].notsflags = 0;
9688          (*launcherpp)[j].vflags = 0;
9689          (*launcherpp)[j].notvflags = 0;
9690          for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
9691             (*launcherpp)[j].czflags[k] = 0;
9692             (*launcherpp)[j].notczflags[k] = 0;
9693          }
9694          for ( k = 0; k < NUM_TIMER_BANKS; k++ ) {
9695             (*launcherpp)[j].tzflags[k] = 0;
9696             (*launcherpp)[j].nottzflags[k] = 0;
9697          }
9698          (*launcherpp)[j].bootflag = 0;
9699          (*launcherpp)[j].trigemuflag = 0;
9700          (*launcherpp)[j].unitstar = 0;
9701          (*launcherpp)[j].timer = 0;
9702          (*launcherpp)[j].sensor = 0;
9703          (*launcherpp)[j].afuncmap = 0;
9704          (*launcherpp)[j].gfuncmap = 0;
9705          (*launcherpp)[j].xfuncmap = 0;
9706          (*launcherpp)[j].sfuncmap = 0;
9707          (*launcherpp)[j].ofuncmap = 0;
9708          (*launcherpp)[j].kfuncmap = 0;
9709          (*launcherpp)[j].signal = 0;
9710          (*launcherpp)[j].module = 0;
9711          (*launcherpp)[j].source = 0;
9712          (*launcherpp)[j].nosource = 0;
9713          (*launcherpp)[j].oksofar = 0;
9714          (*launcherpp)[j].actsource = 0;
9715          (*launcherpp)[j].num_stflags = 0;
9716       }
9717    }
9718 
9719    index = size;
9720    size += 1;
9721    return index;
9722 }
9723 
9724 /*---------------------------------------------------------------------+
9725  | Parse a launch condition for common flags, security flags, czflags, |
9726  | and scanmode and load into the LAUNCHER.                            |
9727  +---------------------------------------------------------------------*/
get_global_flags(LAUNCHER * launcherp,int tokc,char ** tokv)9728 int get_global_flags( LAUNCHER *launcherp, int tokc, char **tokv )
9729 {
9730    int           k, m, flag;
9731    char          *sp;
9732    char          errmsg[128];
9733    char          tbuf[32];
9734    unsigned int  aflags, bitmap;
9735    char          hc;
9736 
9737    launcherp->sflags = launcherp->notsflags = launcherp->scanmode = 0;
9738    launcherp->num_stflags = launcherp->num_virtflags = 0;
9739 
9740    for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
9741       launcherp->flags[k] = 0;
9742       launcherp->notflags[k] = 0;
9743    }
9744    for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
9745       launcherp->czflags[k] = 0;
9746       launcherp->notczflags[k] = 0;
9747    }
9748 
9749    for ( k = 0; k < NUM_TIMER_BANKS; k++ ) {
9750       launcherp->tzflags[k] = 0;
9751       launcherp->nottzflags[k] = 0;
9752    }
9753 
9754    launcherp->num_stflags = 0;
9755 
9756    /* Scan tokens for flags */
9757    for ( k = 1; k < tokc; k++ ) {
9758       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
9759       strlower(tbuf);
9760 
9761       /* Search for state flags */
9762       if ( strchr(tbuf, ':') ) {
9763          for ( m = 0; m < num_stflags; m++ ) {
9764             if ( strncmp(tbuf, stflags[m].label, stflags[m].length) == 0 ) {
9765                aflags = parse_addr(tokv[k] + stflags[m].length, &hc, &bitmap);
9766                if ( (aflags & (A_VALID | A_HCODE | A_BMAP | A_PLUS | A_MINUS)) != (A_VALID | A_HCODE | A_BMAP) ) {
9767                   sprintf(errmsg, "Invalid state flag housecode|unit '%s'", tokv[k] + stflags[m].length);
9768                   store_error_message(errmsg);
9769                   return -1;
9770                }
9771                if ( aflags & A_MULT ) {
9772                   sprintf(errmsg, "'%s' Only a single unit code is acceptable", tokv[k] + stflags[m].length);
9773                   store_error_message(errmsg);
9774                   return 1;
9775                }
9776 
9777                if ( launcherp->num_stflags >= 32 ) {
9778                   store_error_message("Too many state flags - 32 max.");
9779                   return -1;
9780                }
9781                launcherp->stlist[launcherp->num_stflags].stindex = m;
9782                launcherp->stlist[launcherp->num_stflags].hcode = hc2code(hc);
9783                launcherp->stlist[launcherp->num_stflags].bmap = bitmap;
9784                launcherp->num_stflags++;
9785 
9786                *tokv[k] = '\0';
9787                break;
9788             }
9789          }
9790 
9791          if ( !(*tokv[k]) )
9792             continue;
9793 
9794          for ( m = 0; m < num_virtflags; m++ ) {
9795             if ( strncmp(tbuf, virtflags[m].label, virtflags[m].length) == 0 ) {
9796                aflags = parse_addr(tokv[k] + virtflags[m].length, &hc, &bitmap);
9797                if ( (aflags & (A_VALID | A_HCODE | A_BMAP | A_PLUS | A_MINUS)) != (A_VALID | A_HCODE | A_BMAP) ) {
9798                   sprintf(errmsg, "Invalid state flag housecode|unit '%s'", tokv[k] + virtflags[m].length);
9799                   store_error_message(errmsg);
9800                   return -1;
9801                }
9802                if ( aflags & A_MULT ) {
9803                   sprintf(errmsg, "'%s' Only a single unit code is acceptable", tokv[k] + virtflags[m].length);
9804                   store_error_message(errmsg);
9805                   return 1;
9806                }
9807 
9808                if ( launcherp->num_virtflags >= 32 ) {
9809                   store_error_message("Too many state flags - 32 max.");
9810                   return -1;
9811                }
9812                launcherp->virtlist[launcherp->num_virtflags].vfindex = m;
9813                launcherp->virtlist[launcherp->num_virtflags].hcode = hc2code(hc);
9814                launcherp->virtlist[launcherp->num_virtflags].ucode = single_bmap_unit(bitmap);
9815                launcherp->num_virtflags++;
9816 
9817                *tokv[k] = '\0';
9818                break;
9819             }
9820          }
9821       }
9822 
9823       if ( !(*tokv[k]) )
9824          continue;
9825 
9826       /* Search for other flags and keywords */
9827       if ( strncmp("flag", tbuf, 4) == 0 ) {
9828          flag = (int)strtol(tbuf + 4, &sp, 10);
9829          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_FLAG_BANKS) ) {
9830             sprintf(errmsg, "Invalid flag launch parameter '%s'", tokv[k]);
9831             store_error_message(errmsg);
9832             return -1;
9833          }
9834          launcherp->flags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
9835          *tokv[k] = '\0';
9836       }
9837       else if ( strncmp("notflag", tbuf, 7) == 0 ) {
9838          flag = (int)strtol(tbuf + 7, &sp, 10);
9839          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_FLAG_BANKS) ) {
9840             sprintf(errmsg, "Invalid notflag launch parameter '%s'", tokv[k]);
9841             store_error_message(errmsg);
9842             return -1;
9843          }
9844          launcherp->notflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
9845          *tokv[k] = '\0';
9846       }
9847 
9848       else if ( strncmp("czflag", tbuf, 6) == 0 ) {
9849          flag = (int)strtol(tbuf + 6, &sp, 10);
9850          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_COUNTER_BANKS)) {
9851             sprintf(errmsg, "Invalid czflag launch parameter '%s'", tokv[k]);
9852             store_error_message(errmsg);
9853             return -1;
9854          }
9855          launcherp->czflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
9856          *tokv[k] = '\0';
9857       }
9858       else if ( strncmp("notczflag", tbuf, 9) == 0 ) {
9859          flag = (int)strtol(tbuf + 9, &sp, 10);
9860          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_COUNTER_BANKS)) {
9861             sprintf(errmsg, "Invalid notczflag launch parameter '%s'", tokv[k]);
9862             store_error_message(errmsg);
9863             return -1;
9864          }
9865          launcherp->notczflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
9866          *tokv[k] = '\0';
9867       }
9868 
9869       else if ( strncmp("tzflag", tbuf, 6) == 0 ) {
9870          flag = (int)strtol(tbuf + 6, &sp, 10);
9871          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_TIMER_BANKS)) {
9872             sprintf(errmsg, "Invalid tzflag launch parameter '%s'", tokv[k]);
9873             store_error_message(errmsg);
9874             return -1;
9875          }
9876          launcherp->tzflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
9877          *tokv[k] = '\0';
9878       }
9879       else if ( strncmp("nottzflag", tbuf, 9) == 0 ) {
9880          flag = (int)strtol(tbuf + 9, &sp, 10);
9881          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_TIMER_BANKS)) {
9882             sprintf(errmsg, "Invalid nottzflag launch parameter '%s'", tokv[k]);
9883             store_error_message(errmsg);
9884             return -1;
9885          }
9886          launcherp->nottzflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
9887          *tokv[k] = '\0';
9888       }
9889 
9890       else if ( strcmp("night", tbuf) == 0 ) {
9891          launcherp->sflags |= NIGHT_FLAG;
9892          *tokv[k] = '\0';
9893       }
9894       else if ( strcmp("notnight", tbuf) == 0 ) {
9895          launcherp->notsflags |= NIGHT_FLAG;
9896          *tokv[k] = '\0';
9897       }
9898       else if ( strcmp("dark", tbuf) == 0 ) {
9899          launcherp->sflags |= DARK_FLAG;
9900          *tokv[k] = '\0';
9901       }
9902       else if ( strcmp("notdark", tbuf) == 0 ) {
9903          launcherp->notsflags |= DARK_FLAG;
9904          *tokv[k] = '\0';
9905       }
9906       else if ( strcmp("tamper", tbuf) == 0 ) {
9907          launcherp->sflags |= GLOBSEC_TAMPER;
9908          *tokv[k] = '\0';
9909       }
9910       else if ( strcmp("nottamper", tbuf) == 0 ) {
9911          launcherp->notsflags |= GLOBSEC_TAMPER;
9912          *tokv[k] = '\0';
9913       }
9914       else if ( strcmp("armed", tbuf) == 0 ) {
9915          launcherp->sflags |= GLOBSEC_ARMED;
9916          *tokv[k] = '\0';
9917       }
9918       else if ( strcmp("notarmed", tbuf) == 0 ) {
9919          launcherp->notsflags |= GLOBSEC_ARMED;
9920          *tokv[k] = '\0';
9921       }
9922       else if ( strcmp("disarmed", tbuf) == 0 ) {
9923          launcherp->notsflags |= (GLOBSEC_ARMED | GLOBSEC_PENDING);
9924          *tokv[k] = '\0';
9925       }
9926       else if ( strcmp("notdisarmed", tbuf) == 0 ) {
9927          launcherp->sflags |= (GLOBSEC_ARMED | GLOBSEC_PENDING);
9928          *tokv[k] = '\0';
9929       }
9930       else if ( strcmp("armpending", tbuf) == 0 ) {
9931          launcherp->sflags |= GLOBSEC_PENDING;
9932          *tokv[k] = '\0';
9933       }
9934       else if ( strcmp("notarmpending", tbuf) == 0 ) {
9935          launcherp->notsflags |= GLOBSEC_PENDING;
9936          *tokv[k] = '\0';
9937       }
9938       else if ( strcmp("home", tbuf) == 0 ) {
9939          launcherp->sflags |= GLOBSEC_HOME;
9940          *tokv[k] = '\0';
9941       }
9942       else if ( strcmp("away", tbuf) == 0 ) {
9943          launcherp->notsflags |= GLOBSEC_HOME;
9944          *tokv[k] = '\0';
9945       }
9946       else if ( strcmp("continue", tbuf) == 0 ) {
9947          launcherp->scanmode |= FM_CONTINUE;
9948          *tokv[k] = '\0';
9949       }
9950       else if ( strcmp("break", tbuf) == 0 ) {
9951          launcherp->scanmode |= FM_BREAK;
9952          *tokv[k] = '\0';
9953       }
9954    }
9955 
9956    /* home and away flags require armed or armpending - default to armed */
9957    if ( ((launcherp->sflags | launcherp->notsflags) & GLOBSEC_HOME) &&
9958         !(launcherp->sflags & (GLOBSEC_ARMED | GLOBSEC_PENDING)) ) {
9959       launcherp->sflags |= GLOBSEC_ARMED;
9960    }
9961 
9962 
9963    for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
9964       if ( launcherp->flags[k] & launcherp->notflags[k] ) {
9965          store_error_message("Conflicting common flag/notflag in launch conditions.");
9966          return -1;
9967       }
9968    }
9969 
9970    for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
9971       if ( launcherp->czflags[k] & launcherp->notczflags[k] ) {
9972          store_error_message("Conflicting czflag/notczflag in launch conditions.");
9973          return -1;
9974       }
9975    }
9976 
9977    for ( k = 0; k < NUM_TIMER_BANKS; k++ ) {
9978       if ( launcherp->tzflags[k] & launcherp->nottzflags[k] ) {
9979          store_error_message("Conflicting tzflag/nottzflag in launch conditions.");
9980          return -1;
9981       }
9982    }
9983 
9984    if ( launcherp->sflags & launcherp->notsflags ) {
9985       store_error_message("Conflicting global flag/notflag in launch conditions.");
9986       return -1;
9987    }
9988 
9989    if ( launcherp->scanmode == (FM_CONTINUE | FM_BREAK) ) {
9990       store_error_message("Conflicting continue/break in launch conditions.");
9991       return -1;
9992    }
9993 
9994    return 0;
9995 }
9996 
9997 /*---------------------------------------------------------------------+
9998  | Parse a launch condition for common, security, and czflags and      |
9999  | return the flagmaps via the argument list.                          |
10000  +---------------------------------------------------------------------*/
get_global_flags_old(unsigned long * cflags,unsigned long * notcflags,unsigned long * sflags,unsigned long * notsflags,unsigned long * czflags,unsigned long * notczflags,unsigned char * scanmode,int tokc,char ** tokv)10001 int get_global_flags_old ( unsigned long *cflags, unsigned long *notcflags,
10002                        unsigned long *sflags, unsigned long *notsflags,
10003                        unsigned long *czflags, unsigned long *notczflags,
10004                        unsigned char *scanmode, int tokc, char **tokv )
10005 {
10006    int           k, flag;
10007    char          *sp;
10008    char          errmsg[128];
10009    char          tbuf[32];
10010 
10011    *sflags = *notsflags = *scanmode = 0;
10012 
10013    for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
10014       cflags[k] = 0;
10015       notcflags[k] = 0;
10016    }
10017 
10018    for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
10019       czflags[k] = 0;
10020       notczflags[k] = 0;
10021    }
10022 
10023    /* Scan the remainder of the tokens for keywords */
10024    for ( k = 1; k < tokc; k++ ) {
10025       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10026       strlower(tbuf);
10027 
10028       if ( strncmp("flag", tbuf, 4) == 0 ) {
10029          flag = (int)strtol(tbuf + 4, &sp, 10);
10030          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_FLAG_BANKS) ) {
10031             sprintf(errmsg, "Invalid flag launch parameter '%s'", tokv[k]);
10032             store_error_message(errmsg);
10033             return -1;
10034          }
10035          cflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
10036          *tokv[k] = '\0';
10037       }
10038       else if ( strncmp("notflag", tbuf, 7) == 0 ) {
10039          flag = (int)strtol(tbuf + 7, &sp, 10);
10040          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_FLAG_BANKS) ) {
10041             sprintf(errmsg, "Invalid notflag launch parameter '%s'", tokv[k]);
10042             store_error_message(errmsg);
10043             return -1;
10044          }
10045          notcflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
10046          *tokv[k] = '\0';
10047       }
10048 
10049       else if ( strncmp("czflag", tbuf, 6) == 0 ) {
10050          flag = (int)strtol(tbuf + 6, &sp, 10);
10051          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_COUNTER_BANKS)) {
10052             sprintf(errmsg, "Invalid cxflag launch parameter '%s'", tokv[k]);
10053             store_error_message(errmsg);
10054             return -1;
10055          }
10056          czflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
10057          *tokv[k] = '\0';
10058       }
10059       else if ( strncmp("notczflag", tbuf, 9) == 0 ) {
10060          flag = (int)strtol(tbuf + 9, &sp, 10);
10061          if ( !strchr(" /t/n", *sp) || flag < 1 || flag > (32 * NUM_COUNTER_BANKS)) {
10062             sprintf(errmsg, "Invalid notczflag launch parameter '%s'", tokv[k]);
10063             store_error_message(errmsg);
10064             return -1;
10065          }
10066          notczflags[(flag - 1) / 32] |= 1UL << ((flag - 1) % 32);
10067          *tokv[k] = '\0';
10068       }
10069 
10070       else if ( strcmp("night", tbuf) == 0 ) {
10071          *sflags |= NIGHT_FLAG;
10072          *tokv[k] = '\0';
10073       }
10074       else if ( strcmp("notnight", tbuf) == 0 ) {
10075          *notsflags |= NIGHT_FLAG;
10076          *tokv[k] = '\0';
10077       }
10078       else if ( strcmp("dark", tbuf) == 0 ) {
10079          *sflags |= DARK_FLAG;
10080          *tokv[k] = '\0';
10081       }
10082       else if ( strcmp("notdark", tbuf) == 0 ) {
10083          *notsflags |= DARK_FLAG;
10084          *tokv[k] = '\0';
10085       }
10086       else if ( strcmp("tamper", tbuf) == 0 ) {
10087          *sflags |= GLOBSEC_TAMPER;
10088          *tokv[k] = '\0';
10089       }
10090       else if ( strcmp("nottamper", tbuf) == 0 ) {
10091          *notsflags |= GLOBSEC_TAMPER;
10092          *tokv[k] = '\0';
10093       }
10094       else if ( strcmp("armed", tbuf) == 0 ) {
10095          *sflags |= GLOBSEC_ARMED;
10096          *tokv[k] = '\0';
10097       }
10098       else if ( strcmp("notarmed", tbuf) == 0 ) {
10099          *notsflags |= GLOBSEC_ARMED;
10100          *tokv[k] = '\0';
10101       }
10102       else if ( strcmp("disarmed", tbuf) == 0 ) {
10103          *notsflags |= (GLOBSEC_ARMED | GLOBSEC_PENDING);
10104          *tokv[k] = '\0';
10105       }
10106       else if ( strcmp("notdisarmed", tbuf) == 0 ) {
10107          *sflags |= (GLOBSEC_ARMED | GLOBSEC_PENDING);
10108          *tokv[k] = '\0';
10109       }
10110       else if ( strcmp("armpending", tbuf) == 0 ) {
10111          *sflags |= GLOBSEC_PENDING;
10112          *tokv[k] = '\0';
10113       }
10114       else if ( strcmp("notarmpending", tbuf) == 0 ) {
10115          *notsflags |= GLOBSEC_PENDING;
10116          *tokv[k] = '\0';
10117       }
10118       else if ( strcmp("home", tbuf) == 0 ) {
10119          *sflags |= GLOBSEC_HOME;
10120          *tokv[k] = '\0';
10121       }
10122       else if ( strcmp("away", tbuf) == 0 ) {
10123          *notsflags |= GLOBSEC_HOME;
10124          *tokv[k] = '\0';
10125       }
10126       else if ( strcmp("continue", tbuf) == 0 ) {
10127          *scanmode |= FM_CONTINUE;
10128          *tokv[k] = '\0';
10129       }
10130       else if ( strcmp("break", tbuf) == 0 ) {
10131          *scanmode |= FM_BREAK;
10132          *tokv[k] = '\0';
10133       }
10134    }
10135 
10136    /* home and away flags require armed or armpending - default to armed */
10137    if ( ((*sflags | *notsflags) & GLOBSEC_HOME) &&
10138         !(*sflags & (GLOBSEC_ARMED | GLOBSEC_PENDING)) ) {
10139       *sflags |= GLOBSEC_ARMED;
10140    }
10141 
10142 
10143    for ( k = 0; k < NUM_FLAG_BANKS; k++ ) {
10144       if ( cflags[k] & notcflags[k] ) {
10145          store_error_message("Conflicting common flag/notflag in launch conditions.");
10146          return -1;
10147       }
10148    }
10149 
10150    for ( k = 0; k < NUM_COUNTER_BANKS; k++ ) {
10151       if ( czflags[k] & notczflags[k] ) {
10152          store_error_message("Conflicting czflag/notczflag in launch conditions.");
10153          return -1;
10154       }
10155    }
10156 
10157    if ( *sflags & *notsflags ) {
10158       store_error_message("Conflicting global flag/notflag in launch conditions.");
10159       return -1;
10160    }
10161    if ( *scanmode == (FM_CONTINUE | FM_BREAK) ) {
10162       store_error_message("Conflicting continue/break in launch conditions.");
10163       return -1;
10164    }
10165 
10166    return 0;
10167 }
10168 
10169 /*---------------------------------------------------------------------+
10170  | Create an exec launcher, i.e., the script is launched only from the |
10171  | command line with the 'heyu launch' command.                        |
10172  | Return 0 if successful, or -1 if error.                             |
10173  +---------------------------------------------------------------------*/
create_exec_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10174 int create_exec_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10175 {
10176    int j;
10177    char errmsg[128];
10178 
10179    launcherp->type = L_EXEC;
10180 
10181    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10182       return -1;
10183    }
10184 
10185    for ( j = 1; j < tokc; j++ ) {
10186       if ( *tokv[j] != '\0' ) {
10187         sprintf(errmsg, "Launch parameter '%s' is invalid for -exec script", tokv[j]);
10188         store_error_message(errmsg);
10189         return -1;
10190       }
10191    }
10192 
10193    launcherp->oksofar = 1;
10194 
10195    return 0;
10196 }
10197 
10198 /*---------------------------------------------------------------------+
10199  | Create an -hourly launcher, triggered once every hour on the hour.  |
10200  | Return 0 if successful, or -1 if error.                             |
10201  +---------------------------------------------------------------------*/
create_hourly_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10202 int create_hourly_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10203 {
10204    int j;
10205    char errmsg[128];
10206 
10207    launcherp->type = L_HOURLY;
10208 
10209    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10210       return -1;
10211    }
10212 
10213    for ( j = 1; j < tokc; j++ ) {
10214       if ( *tokv[j] != '\0' ) {
10215         sprintf(errmsg, "Launch parameter '%s' is invalid for -hourly script", tokv[j]);
10216         store_error_message(errmsg);
10217         return -1;
10218       }
10219    }
10220 
10221    launcherp->oksofar = 1;
10222 
10223    return 0;
10224 }
10225 
10226 /*---------------------------------------------------------------------+
10227  | Create a sensorfail launcher, i.e., triggered when any security     |
10228  | security sensor inactive countdown reaches zero.                    |
10229  | Return 0 if successful, or -1 if error.                             |
10230  +---------------------------------------------------------------------*/
create_sensorfail_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10231 int create_sensorfail_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10232 {
10233    int           k;
10234    char          errmsg[128];
10235 
10236    launcherp->type = L_SENSORFAIL;
10237 
10238    launcherp->bmaptrigemu = 0xffff;
10239 
10240    /* Scan tokens for Global flags */
10241    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10242       return -1;
10243    }
10244 
10245    for ( k = 1; k < tokc; k++ ) {
10246       if ( *tokv[k] != '\0' ) {
10247         sprintf(errmsg, "Launch parameter '%s' is invalid for -sensorfail script", tokv[k]);
10248         store_error_message(errmsg);
10249         return -1;
10250       }
10251    }
10252 
10253    launcherp->oksofar = 1;
10254 
10255    return 0;
10256 
10257 }
10258 
10259 
10260 /*---------------------------------------------------------------------+
10261  | Create a timeout launcher, i.e., triggered when the specified timer |
10262  | (1-16) countdown reaches zero.                                      |
10263  | Return 0 if successful, or -1 if error.                             |
10264  +---------------------------------------------------------------------*/
create_timeout_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10265 int create_timeout_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10266 {
10267    int           k, timer, tcount = 0;
10268    char          *sp;
10269    char          errmsg[128];
10270    char          tbuf[32];
10271 
10272    launcherp->type = L_TIMEOUT;
10273 
10274    launcherp->bmaptrigemu = 0xffff;
10275 
10276    /* Scan tokens for Global flags */
10277    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10278       return -1;
10279    }
10280 
10281    /* Scan the remainder of the tokens for timer flags */
10282    for ( k = 1; k < tokc; k++ ) {
10283       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10284       strlower(tbuf);
10285 
10286       if ( strncmp("timer", tbuf, 5) == 0 ) {
10287          timer = (int)strtol(tbuf + 5, &sp, 10);
10288          if ( !strchr(" /t/n", *sp) || timer < 1 || timer > NUM_USER_TIMERS ) {
10289             sprintf(errmsg, "Invalid timer launch parameter '%s'", tokv[k]);
10290             store_error_message(errmsg);
10291             return -1;
10292          }
10293          launcherp->timer = timer;
10294          tcount++;
10295          *tokv[k] = '\0';
10296       }
10297       else if ( strcmp("armdelay", tbuf) == 0 ) {
10298          launcherp->timer = 0;
10299          tcount++;
10300          *tokv[k] = '\0';
10301       }
10302    }
10303 
10304    for ( k = 1; k < tokc; k++ ) {
10305       if ( *tokv[k] != '\0' ) {
10306         sprintf(errmsg, "Launch parameter '%s' is invalid for -timer script", tokv[k]);
10307         store_error_message(errmsg);
10308         return -1;
10309       }
10310    }
10311 
10312    if ( tcount == 0 ) {
10313       store_error_message("No timer (armtimer or timer1 ... timer32) has been specified.");
10314       return -1;
10315    }
10316    else if ( tcount > 1 ) {
10317       store_error_message("Only one timer (armtimer or timer1 ... timer32) may be specified.");
10318       return -1;
10319    }
10320 
10321    launcherp->oksofar = 1;
10322 
10323    return 0;
10324 }
10325 
10326 
10327 /*---------------------------------------------------------------------+
10328  | Create an RF Flood launcher, i.e., triggered when heyu_aux detects  |
10329  | an unbroken flood of RF signals.                                    |
10330  | Return 0 if successful, or -1 if error.                             |
10331  +---------------------------------------------------------------------*/
create_rfflood_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10332 int create_rfflood_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10333 {
10334    int           k;
10335    char          errmsg[128];
10336    char          tbuf[32];
10337 
10338    launcherp->type = L_RFFLOOD;
10339 
10340    launcherp->bmaptrigemu = 0xffff;
10341 
10342    /* Scan tokens for Global flags */
10343    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10344       return -1;
10345    }
10346 
10347    /* Scan the remainder of the tokens for specific flags */
10348    for ( k = 1; k < tokc; k++ ) {
10349       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10350       strlower(tbuf);
10351 
10352       if ( strcmp("started", tbuf) == 0 ) {
10353          launcherp->sflags |= GLOBSEC_FLOOD;
10354          *tokv[k] = '\0';
10355       }
10356       else if ( strcmp("ended", tbuf) == 0 ) {
10357          launcherp->notsflags |= GLOBSEC_FLOOD;
10358          *tokv[k] = '\0';
10359       }
10360       else {
10361          sprintf(errmsg, "Launch parameter '%s' is invalid for -rfflood launcher", tokv[k]);
10362          store_error_message(errmsg);
10363          return -1;
10364       }
10365    }
10366 
10367 
10368    launcherp->oksofar = 1;
10369 
10370    return 0;
10371 }
10372 
10373 /*---------------------------------------------------------------------+
10374  | Create an -rfjamming launcher, i.e., triggered when heyu_aux        |
10375  | receives an RF Jamming signal from an (older) RFXCOM receiver.      |
10376  | Return 0 if successful, or -1 if error.                             |
10377  +---------------------------------------------------------------------*/
create_rfxjam_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10378 int create_rfxjam_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10379 {
10380    int           k;
10381    char          errmsg[128];
10382    char          tbuf[32];
10383 
10384    launcherp->type = L_RFXJAM;
10385 
10386    launcherp->bmaptrigemu = 0xffff;
10387 
10388    /* Scan tokens for Global flags */
10389    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10390       return -1;
10391    }
10392 
10393    /* Scan the remainder of the tokens for specific flags */
10394    for ( k = 1; k < tokc; k++ ) {
10395       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10396       strlower(tbuf);
10397 
10398       if ( strcmp("started", tbuf) == 0 ) {
10399          launcherp->sflags |= GLOBSEC_FLOOD;
10400          *tokv[k] = '\0';
10401       }
10402       else if ( strcmp("ended", tbuf) == 0 ) {
10403          launcherp->notsflags |= GLOBSEC_FLOOD;
10404          *tokv[k] = '\0';
10405       }
10406       else if ( strcmp("main", tbuf) == 0 ) {
10407          launcherp->vflags |= SEC_MAIN;
10408          *tokv[k] = '\0';
10409       }
10410       else if ( strcmp("aux", tbuf) == 0 ) {
10411          launcherp->vflags |= SEC_AUX;
10412          *tokv[k] = '\0';
10413       }
10414       else {
10415          sprintf(errmsg, "Launch parameter '%s' is invalid for -rfxjam launcher", tokv[k]);
10416          store_error_message(errmsg);
10417          return -1;
10418       }
10419    }
10420 
10421 
10422    launcherp->oksofar = 1;
10423 
10424    return 0;
10425 }
10426 
10427 /*---------------------------------------------------------------------+
10428  | Create a lockup launcher, i.e., triggered when heyu_relay says the  |
10429  | CM11A appears to be locked up.                                      |
10430  | Return 0 if successful, or -1 if error.                             |
10431  +---------------------------------------------------------------------*/
create_lockup_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10432 int create_lockup_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10433 {
10434    int           k;
10435    char          errmsg[128];
10436    char          tbuf[32];
10437 
10438    launcherp->type = L_LOCKUP;
10439 
10440    launcherp->bmaptrigemu = 0xffff;
10441 
10442    /* Scan tokens for Global flags */
10443    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10444       return -1;
10445    }
10446 
10447    /* Scan the remainder of the tokens for specific flags */
10448    for ( k = 1; k < tokc; k++ ) {
10449       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10450       strlower(tbuf);
10451 
10452       if ( strcmp("started", tbuf) == 0 ) {
10453          launcherp->sflags |= GLOBSEC_FLOOD;
10454          *tokv[k] = '\0';
10455       }
10456       else if ( strcmp("ended", tbuf) == 0 ) {
10457          launcherp->notsflags |= GLOBSEC_FLOOD;
10458          *tokv[k] = '\0';
10459       }
10460       else if ( strcmp("boot", tbuf) == 0 ) {
10461          launcherp->bootflag |= R_ATSTART;
10462       }
10463       else if ( strcmp("notboot", tbuf) == 0 ) {
10464          launcherp->bootflag |= R_NOTATSTART;
10465       }
10466       else {
10467          sprintf(errmsg, "Launch parameter '%s' is invalid for -lockup launcher", tokv[k]);
10468          store_error_message(errmsg);
10469          return -1;
10470       }
10471    }
10472 
10473    if ( launcherp->bootflag == (R_ATSTART | R_NOTATSTART) ) {
10474       store_error_message("Conflicting boot/notboot in launch conditions.");
10475       return -1;
10476    }
10477 
10478 
10479    launcherp->oksofar = 1;
10480 
10481    return 0;
10482 }
10483 
10484 /*---------------------------------------------------------------------+
10485  | Create a powerfail launcher, i.e., triggered when the CM11A polls   |
10486  | for a time update.  Return 0 if successful, or -1 if error.         |
10487  +---------------------------------------------------------------------*/
create_powerfail_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10488 int create_powerfail_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10489 {
10490    int           k;
10491    char          errmsg[128];
10492    char          tbuf[32];
10493 
10494    launcherp->type = L_POWERFAIL;
10495 
10496    launcherp->bmaptrigemu = 0xffff;
10497 
10498    /* Scan tokens for Global flags */
10499    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10500       return -1;
10501    }
10502 
10503    /* Scan the remainder of the tokens for specific flags */
10504    for ( k = 1; k < tokc; k++ ) {
10505       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10506       strlower(tbuf);
10507 
10508       if ( strcmp("boot", tbuf) == 0 ) {
10509          launcherp->bootflag |= R_ATSTART;
10510       }
10511       else if ( strcmp("notboot", tbuf) == 0 ) {
10512          launcherp->bootflag |= R_NOTATSTART;
10513       }
10514       else {
10515          sprintf(errmsg, "Launch parameter '%s' is invalid for -powerfail launcher", tokv[k]);
10516          store_error_message(errmsg);
10517          return -1;
10518       }
10519    }
10520 
10521    if ( launcherp->bootflag == (R_ATSTART | R_NOTATSTART) ) {
10522       store_error_message("Conflicting boot/notboot in launch conditions.");
10523       return -1;
10524    }
10525 
10526    launcherp->oksofar = 1;
10527 
10528    return 0;
10529 }
10530 
10531 /*---------------------------------------------------------------------+
10532  | Create a normal launcher, i.e., triggered with a standard X10       |
10533  | signal.  Return 0 if successful, or -1 if error.                    |
10534  +---------------------------------------------------------------------*/
create_normal_launcher(LAUNCHER * launcherp,int tokc,char ** tokv)10535 int create_normal_launcher ( LAUNCHER *launcherp, int tokc, char **tokv )
10536 {
10537    int           k, m, mm, mask, flag, found_func;
10538    char          hc;
10539    char          errmsg[128];
10540    unsigned char hcode, change;
10541    unsigned char actual, generic, signal, module, address;
10542    unsigned int  aflags, source, nosource;
10543    unsigned int  bitmap;
10544    char          tbuf[32];
10545 
10546 //   int get_global_flags ( LAUNCHER *, int, char ** );
10547    change = 0; module = 0; signal = 0; source = 0; nosource = 0;
10548    actual = 0; generic = 0; address = 0;
10549 
10550    launcherp->type = L_NORMAL;
10551    launcherp->bmaptrigemu = 0xffff;
10552 
10553    aflags = parse_addr(tokv[0], &hc, &bitmap);
10554    if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || !bitmap ) {
10555       sprintf(errmsg, "Invalid Housecode|Units '%s' in Launcher.", tokv[0]);
10556       store_error_message(errmsg);
10557       return -1;
10558    }
10559    if ( aflags & A_STAR ) {
10560       launcherp->unitstar = 1;
10561    }
10562 
10563    hcode = hc2code(hc);
10564    launcherp->hcode = hc2code(hc);
10565    launcherp->bmaptrig = bitmap;
10566 
10567    /* Scan tokens for Global flags */
10568    if ( get_global_flags(launcherp, tokc, tokv) != 0 ) {
10569       return -1;
10570    }
10571 
10572    /* Scan the remainder of the tokens for specific flags and keywords */
10573    for ( k = 1; k < tokc; k++ ) {
10574       strncpy2(tbuf, tokv[k], (sizeof(tbuf)));
10575       strlower(tbuf);
10576       if ( strcmp("address", tbuf) == 0 ) {
10577          address = 1;
10578          *tokv[k] = '\0';
10579       }
10580       else if ( strcmp("changed", tbuf) == 0 ) {
10581          change = 1;
10582          *tokv[k] = '\0';
10583       }
10584       else if ( strcmp("module", tbuf) == 0 ) {
10585          module = 1;
10586          *tokv[k] = '\0';
10587       }
10588       else if ( strcmp("signal", tbuf) == 0 ) {
10589          signal = 1;
10590          *tokv[k] = '\0';
10591       }
10592       else if ( strcmp("nosrc", tbuf) == 0 ) {
10593          source |= LSNONE;
10594          *tokv[k] = '\0';
10595       }
10596       else if ( strcmp("anysrc", tbuf) == 0 ) {
10597          source |= LSALL;
10598          *tokv[k] = '\0';
10599       }
10600       else if ( strcmp("sndc", tbuf) == 0 ) {
10601          source |= SNDC;
10602          *tokv[k] = '\0';
10603       }
10604       else if ( strcmp("snds", tbuf) == 0 ) {
10605          source |= SNDS;
10606          *tokv[k] = '\0';
10607       }
10608       else if ( strcmp("sndm", tbuf) == 0 ) {
10609          source |= SNDM;
10610          *tokv[k] = '\0';
10611       }
10612       else if ( strcmp("snda", tbuf) == 0 ) {
10613          source |= SNDA;
10614          *tokv[k] = '\0';
10615       }
10616       else if ( strcmp("sndt", tbuf) == 0 ) {
10617          source |= SNDT;
10618          *tokv[k] = '\0';
10619       }
10620       else if ( strcmp("rcvi", tbuf) == 0 ) {
10621          source |= RCVI;
10622          *tokv[k] = '\0';
10623       }
10624       else if ( strcmp("rcvt", tbuf) == 0 ) {
10625          source |= RCVT;
10626          *tokv[k] = '\0';
10627       }
10628       else if ( strcmp("sndp", tbuf) == 0 ) {
10629          source |= SNDP;
10630          *tokv[k] = '\0';
10631       }
10632       else if ( strcmp("snda", tbuf) == 0 ) {
10633          source |= SNDA;
10634          *tokv[k] = '\0';
10635       }
10636       else if ( strcmp("rcva", tbuf) == 0 ) {
10637          source |= RCVA;
10638          *tokv[k] = '\0';
10639       }
10640       else if ( strcmp("xmtf", tbuf) == 0 ) {
10641          source |= XMTF;
10642          *tokv[k] = '\0';
10643       }
10644 
10645       else if ( strcmp("nosndc", tbuf) == 0 ) {
10646          nosource |= SNDC;
10647          *tokv[k] = '\0';
10648       }
10649       else if ( strcmp("nosnds", tbuf) == 0 ) {
10650          nosource |= SNDS;
10651          *tokv[k] = '\0';
10652       }
10653       else if ( strcmp("nosndm", tbuf) == 0 ) {
10654          nosource |= SNDM;
10655          *tokv[k] = '\0';
10656       }
10657       else if ( strcmp("nosnda", tbuf) == 0 ) {
10658          nosource |= SNDA;
10659          *tokv[k] = '\0';
10660       }
10661       else if ( strcmp("nosndt", tbuf) == 0 ) {
10662          nosource |= SNDT;
10663          *tokv[k] = '\0';
10664       }
10665       else if ( strcmp("norcvi", tbuf) == 0 ) {
10666          nosource |= RCVI;
10667          *tokv[k] = '\0';
10668       }
10669       else if ( strcmp("norcvt", tbuf) == 0 ) {
10670          nosource |= RCVT;
10671          *tokv[k] = '\0';
10672       }
10673       else if ( strcmp("nosndp", tbuf) == 0 ) {
10674          nosource |= SNDP;
10675          *tokv[k] = '\0';
10676       }
10677       else if ( strcmp("nosnda", tbuf) == 0 ) {
10678          nosource |= SNDA;
10679          *tokv[k] = '\0';
10680       }
10681       else if ( strcmp("norcva", tbuf) == 0 ) {
10682          nosource |= RCVA;
10683          *tokv[k] = '\0';
10684       }
10685       else if ( strcmp("noxmtf", tbuf) == 0 ) {
10686          nosource |= XMTF;
10687          *tokv[k] = '\0';
10688       }
10689       else if ( strcmp("trigemu", tbuf) == 0 ) {
10690          launcherp->trigemuflag = 1;
10691 	 launcherp->bmaptrigemu = bitmap;
10692 	 *tokv[k] = '\0';
10693       }
10694 
10695       else if ( strcmp("swmin", tbuf) == 0 ) {
10696          /* For the command itself */
10697          launcherp->vflags |= SEC_MIN;
10698          *tokv[k] = '\0';
10699       }
10700       else if ( strcmp("swmax", tbuf) == 0 ) {
10701          /* For the command itself */
10702          launcherp->vflags |= SEC_MAX;
10703          *tokv[k] = '\0';
10704       }
10705       else if ( strcmp("swhome", tbuf) == 0 ) {
10706          launcherp->vflags |= SEC_HOME;
10707          *tokv[k] = '\0';
10708       }
10709       else if ( strcmp("swaway", tbuf) == 0 ) {
10710          launcherp->vflags |= SEC_AWAY;
10711          *tokv[k] = '\0';
10712       }
10713       else if ( strcmp("lobat", tbuf) == 0 ) {
10714          launcherp->vflags |= SEC_LOBAT;
10715          *tokv[k] = '\0';
10716       }
10717       else if ( strcmp("notlobat", tbuf) == 0 ) {
10718          launcherp->notvflags |= SEC_LOBAT;
10719          *tokv[k] = '\0';
10720       }
10721       else if ( strcmp("main", tbuf) == 0 ) {
10722          /* For the command itself */
10723          launcherp->vflags |= SEC_MAIN;
10724          *tokv[k] = '\0';
10725       }
10726       else if ( strcmp("aux", tbuf) == 0 ) {
10727          /* For the command itself */
10728          launcherp->vflags |= SEC_AUX;
10729          *tokv[k] = '\0';
10730       }
10731       else if ( strcmp("rollover", tbuf) == 0 ) {
10732          /* RFXMeter or Oregon Rain sensor count rollover */
10733          launcherp->vflags |= RFX_ROLLOVER;
10734          *tokv[k] = '\0';
10735       }
10736 
10737 #ifdef HASDMX
10738       else if ( strcmp("heat", tbuf) == 0 || strcmp("notcool", tbuf) == 0 ) {
10739          /* Digimax */
10740          launcherp->vflags |= DMX_HEAT;
10741          *tokv[k] = '\0';
10742       }
10743       else if ( strcmp("cool", tbuf) == 0 || strcmp("notheat", tbuf) == 0 ) {
10744          /* Digimax */
10745          launcherp->notvflags |= DMX_HEAT;
10746          *tokv[k] = '\0';
10747       }
10748       else if ( strcmp("set", tbuf) == 0 ) {
10749          /* Digimax */
10750          launcherp->vflags |= DMX_SET;
10751          *tokv[k] = '\0';
10752       }
10753       else if ( strcmp("notset", tbuf) == 0 ) {
10754          /* Digimax */
10755          launcherp->notvflags |= DMX_SET;
10756          *tokv[k] = '\0';
10757       }
10758       else if ( strcmp("init", tbuf) == 0 ) {
10759          /* Digimax */
10760          launcherp->vflags |= DMX_INIT;
10761          *tokv[k] = '\0';
10762       }
10763       else if ( strcmp("notinit", tbuf) == 0 ) {
10764          /* Digimax */
10765          launcherp->notvflags |= DMX_INIT;
10766          *tokv[k] = '\0';
10767       }
10768       else if ( strcmp("temp", tbuf) == 0 ) {
10769          /* Digimax */
10770          launcherp->vflags |= DMX_TEMP;
10771          *tokv[k] = '\0';
10772       }
10773       else if ( strcmp("nottemp", tbuf) == 0 ) {
10774          /* Digimax */
10775          launcherp->notvflags |= DMX_TEMP;
10776          *tokv[k] = '\0';
10777       }
10778 #endif  /* HASDMX */
10779 
10780 #ifdef  HASORE
10781       else if ( strcmp("tmin", tbuf) == 0 ) {
10782          /* Oregon Temperature */
10783          launcherp->vflags |= ORE_TMIN;
10784          *tokv[k] = '\0';
10785       }
10786       else if ( strcmp("tmax", tbuf) == 0 ) {
10787          /* Oregon Temperature */
10788          launcherp->vflags |= ORE_TMAX;
10789          *tokv[k] = '\0';
10790       }
10791       else if ( strcmp("rhmin", tbuf) == 0 ) {
10792          /* Oregon Relative Humidity */
10793          launcherp->vflags |= ORE_RHMIN;
10794          *tokv[k] = '\0';
10795       }
10796       else if ( strcmp("rhmax", tbuf) == 0 ) {
10797          /* Oregon Relative Humidity */
10798          launcherp->vflags |= ORE_RHMAX;
10799          *tokv[k] = '\0';
10800       }
10801 
10802       else if ( strcmp("bpmin", tbuf) == 0 ) {
10803          /* Oregon Barometric Pressure */
10804          launcherp->vflags |= ORE_BPMIN;
10805          *tokv[k] = '\0';
10806       }
10807       else if ( strcmp("bpmax", tbuf) == 0 ) {
10808          /* Oregon Barometric Pressure */
10809          launcherp->vflags |= ORE_BPMAX;
10810          *tokv[k] = '\0';
10811       }
10812 #endif   /* HASORE */
10813 
10814    }
10815 
10816    for ( k = 1; k < tokc; k++ ) {
10817       if ( *tokv[k] == '\0' )
10818          continue;
10819       if ( strcmp(tokv[k], "anyfunc") == 0 ) {
10820          launcherp->afuncmap = ~(0);
10821          launcherp->sfuncmap = ~(0);
10822          launcherp->xfuncmap = ~(0);
10823          launcherp->ofuncmap = ~(0);
10824          launcherp->kfuncmap = ~(0);
10825          found_func = 1;
10826          continue;
10827       }
10828 
10829       found_func = 0;
10830 
10831       for ( m = 0; m < (int)NTRIGTYPES; m++ ) {
10832          if ( strcmp(trig_type[m].label, tokv[k]) == 0 ) {
10833             if ( trig_type[m].flags & AnyFlag ) {
10834                mask = trig_type[m].flags & ~AnyFlag;
10835                for ( mm = 0; mm < (int)NTRIGTYPES; mm++ ) {
10836                   if ( (flag = trig_type[mm].flags) & AnyFlag )
10837                      continue;
10838                   launcherp->afuncmap |= (mask & flag) ? (1 << trig_type[mm].signal) : 0;
10839                }
10840             }
10841             else if ( trig_type[m].flags & GenPLC ) {
10842                launcherp->gfuncmap |= (1 << trig_type[m].signal);
10843             }
10844             else if ( trig_type[m].flags & SpecSec ) {
10845                /* vdata can be sent from the command line or received as a security signal */
10846                launcherp->afuncmap |= (1 << trig_type[m].signal);
10847                launcherp->sfuncmap |= (1 << trig_type[m].signal);
10848             }
10849             else {
10850                launcherp->afuncmap |= (1 << trig_type[m].signal);
10851             }
10852             found_func = 1;
10853             break;
10854          }
10855       }
10856       if ( found_func )
10857          continue;
10858 
10859       for ( m = 0; m < (int)NSECTRIGTYPES; m++ ) {
10860          if ( strcmp(sec_trig_type[m].label, tokv[k]) == 0 ) {
10861             if ( sec_trig_type[m].flags & AnyFlag ) {
10862                mask = sec_trig_type[m].flags & ~AnyFlag;
10863                for ( mm = 0; mm < (int)NSECTRIGTYPES; mm++ ) {
10864                   if ( (flag = sec_trig_type[mm].flags) & AnyFlag )
10865                      continue;
10866                   launcherp->sfuncmap |= (mask & flag) ? (1 << sec_trig_type[mm].signal) : 0;
10867                }
10868             }
10869             else {
10870                launcherp->sfuncmap |= (1 << sec_trig_type[m].signal);
10871             }
10872             found_func = 1;
10873             break;
10874          }
10875       }
10876       if ( found_func )
10877          continue;
10878 
10879       for ( m = 0; m < (int)NORETRIGTYPES; m++ ) {
10880          if ( strcmp(ore_trig_type[m].label, tokv[k]) == 0 ) {
10881             if ( ore_trig_type[m].flags & AnyFlag ) {
10882                mask = ore_trig_type[m].flags & ~AnyFlag;
10883                for ( mm = 0; mm < (int)NORETRIGTYPES; mm++ ) {
10884                   if ( (flag = ore_trig_type[mm].flags) & AnyFlag )
10885                      continue;
10886                   launcherp->ofuncmap |= (mask & flag) ? (1 << ore_trig_type[mm].signal) : 0;
10887                }
10888             }
10889             else {
10890                launcherp->ofuncmap |= (1 << ore_trig_type[m].signal);
10891             }
10892             found_func = 1;
10893             break;
10894          }
10895       }
10896       if ( found_func )
10897          continue;
10898 
10899       for ( m = 0; m < (int)NKAKUTRIGTYPES; m++ ) {
10900          if ( strcmp(kaku_trig_type[m].label, tokv[k]) == 0 ) {
10901             if ( kaku_trig_type[m].flags & AnyFlag ) {
10902                mask = kaku_trig_type[m].flags & ~AnyFlag;
10903                for ( mm = 0; mm < (int)NKAKUTRIGTYPES; mm++ ) {
10904                   if ( (flag = kaku_trig_type[mm].flags) & AnyFlag )
10905                      continue;
10906                   launcherp->kfuncmap |= (mask & flag) ? (1 << kaku_trig_type[mm].signal) : 0;
10907                }
10908             }
10909             else {
10910                launcherp->kfuncmap |= (1 << kaku_trig_type[m].signal);
10911             }
10912             found_func = 1;
10913             break;
10914          }
10915       }
10916       if ( found_func )
10917          continue;
10918 
10919       for ( m = 0; m < (int)NRFXTRIGTYPES; m++ ) {
10920          if ( strcmp(rfx_trig_type[m].label, tokv[k]) == 0 ) {
10921             if ( rfx_trig_type[m].flags & AnyFlag ) {
10922                mask = rfx_trig_type[m].flags & ~AnyFlag;
10923                for ( mm = 0; mm < (int)NRFXTRIGTYPES; mm++ ) {
10924                   if ( (flag = rfx_trig_type[mm].flags) & AnyFlag )
10925                      continue;
10926                   launcherp->xfuncmap |= (mask & flag) ? (1 << rfx_trig_type[mm].signal) : 0;
10927                }
10928             }
10929             else {
10930                launcherp->xfuncmap |= (1 << rfx_trig_type[m].signal);
10931             }
10932             found_func = 1;
10933             break;
10934          }
10935       }
10936 
10937       if ( !found_func ) {
10938          sprintf(errmsg, "Invalid launch parameter '%s'", tokv[k]);
10939          store_error_message(errmsg);
10940          return -1;
10941       }
10942    }
10943 
10944    if ( launcherp->gfuncmap == 0 && launcherp->afuncmap == 0 &&
10945         launcherp->xfuncmap == 0 && launcherp->sfuncmap == 0 &&
10946         launcherp->ofuncmap == 0 && launcherp->kfuncmap == 0 &&
10947         address == 0 && change == 0 ) {
10948       store_error_message("No launch function has been specified.");
10949       return -1;
10950    }
10951 
10952    if ( address && (launcherp->gfuncmap || launcherp->afuncmap ||
10953        launcherp->xfuncmap || launcherp->sfuncmap || launcherp->ofuncmap  || launcherp->kfuncmap) ) {
10954       store_error_message("Keyword 'address' is incompatible with any functions.");
10955       return -1;
10956    }
10957    else if ( address && (change || module) ) {
10958       store_error_message("Keywords 'changed' and 'module' are invalid in an address launcher.");
10959       return -1;
10960    }
10961    else if ( address ) {
10962       launcherp->type = L_ADDRESS;
10963    }
10964    else {}
10965 
10966    if ( change && signal ) {
10967       store_error_message("Keywords change and signal are incompatible.");
10968       return -1;
10969    }
10970    if ( module && signal ) {
10971       store_error_message("Keywords module and signal are incompatible.");
10972       return -1;
10973    }
10974    if ( change ) {
10975       launcherp->chgtrig = launcherp->bmaptrig;
10976       module = 1;
10977       signal = 0;
10978    }
10979    else
10980       launcherp->chgtrig = 0;
10981 
10982    if ( module ) {
10983       launcherp->module = bitmap;
10984       launcherp->signal = 0;
10985    }
10986    else if ( signal ) {
10987       launcherp->module = 0;
10988       launcherp->signal = bitmap;
10989    }
10990    else {
10991       launcherp->module = 0;
10992       launcherp->signal = 0;
10993    }
10994 
10995    launcherp->source = source;
10996    launcherp->nosource = nosource;
10997 
10998    launcherp->oksofar = 1;
10999 
11000    return 0;
11001 }
11002 
11003 
11004 /*---------------------------------------------------------------------+
11005  | Create individual launchers with argument label from the sets of    |
11006  | launch conditions in argument tail.  Return 0 if successful, or -1  |
11007  | if error.                                                           |
11008  +---------------------------------------------------------------------*/
create_launchers(LAUNCHER ** launcherpp,char * label,int line_no,char * tail)11009 int create_launchers ( LAUNCHER **launcherpp, char *label, int line_no, char *tail )
11010 {
11011 
11012    int           j, index, retcode = 0;
11013    int           argc, tokc;
11014    char          **argv, **tokv;
11015    char          *sp;
11016    char          errmsg[128];
11017    LAUNCHER      *launcherp;
11018 
11019    sp = tail;
11020 
11021    /* Tokenize the line into individual sets of launch conditions */
11022    tokenize( sp, ";", &argc, &argv );
11023 
11024    if ( argc == 0 ) {
11025        store_error_message("No launch parameters specified");
11026        free(argv);
11027        return -1;
11028    }
11029 
11030    for ( j = 0; j < argc; j++ ) {
11031       /* Tokenize each set of launch conditions */
11032       tokenize(argv[j], " \t", &tokc, &tokv);
11033       if ( tokc < 1 ) {
11034          sprintf(errmsg, "No launch parameters specified for %s", tokv[0]);
11035          store_error_message(errmsg);
11036          free(tokv);
11037          free(argv);
11038          return -1;
11039       }
11040 
11041       index = launcher_index(launcherpp);
11042 
11043       (*launcherpp)[index].line_no = line_no;
11044       strncpy2((*launcherpp)[index].label, label, NAME_LEN);
11045 
11046       launcherp = &(*launcherpp)[index];
11047 
11048       if ( strcmp(tokv[0], "-powerfail") == 0 )
11049          retcode = create_powerfail_launcher(launcherp, tokc, tokv);
11050       else if ( strcmp(tokv[0], "-rfflood") == 0 )
11051          retcode = create_rfflood_launcher(launcherp, tokc, tokv);
11052       else if ( strcmp(tokv[0], "-timeout") == 0 )
11053          retcode = create_timeout_launcher(launcherp, tokc, tokv);
11054       else if ( strcmp(tokv[0], "-sensorfail") == 0 )
11055          retcode = create_sensorfail_launcher(launcherp, tokc, tokv);
11056       else if ( strcmp(tokv[0], "-lockup") == 0 )
11057          retcode = create_lockup_launcher(launcherp, tokc, tokv);
11058       else if ( strcmp(tokv[0], "-rfjamming") == 0 )
11059          retcode = create_rfxjam_launcher(launcherp, tokc, tokv);
11060       else if ( strcmp(tokv[0], "-exec") == 0 )
11061          retcode = create_exec_launcher(launcherp, tokc, tokv);
11062       else if ( strcmp(tokv[0], "-hourly") == 0 )
11063          retcode = create_hourly_launcher(launcherp, tokc, tokv);
11064       else {
11065          retcode = create_normal_launcher(launcherp, tokc, tokv);
11066       }
11067 
11068       free(tokv);
11069 
11070       if ( retcode != 0 )
11071          break;
11072    }
11073 
11074    free(argv);
11075 
11076    return retcode;
11077 }
11078 
11079 
11080 /*---------------------------------------------------------------------+
11081  | Add a launcher to the array of LAUNCHER structures for each set     |
11082  | of launch conditions in argument tail.  Return 0 if successful.     |
11083  +---------------------------------------------------------------------*/
add_launchers(LAUNCHER ** launcherpp,int line_no,char * tail)11084 int add_launchers ( LAUNCHER **launcherpp, int line_no, char *tail )
11085 {
11086 
11087    char          label[51];
11088    char          errmsg[128];
11089    char          *sp;
11090 
11091    sp = tail;
11092 
11093    /* The first token is the script label */
11094    if ( *get_token(label, &sp, " \t", 50) == '\0' || *sp == '\0' ) {
11095       store_error_message("Too few items on line.");
11096       return -1;
11097    }
11098    if ( (int)strlen(label) > NAME_LEN ) {
11099       sprintf(errmsg, "Label '%s' too long (max %d characters)", label, NAME_LEN);
11100       store_error_message(errmsg);
11101       return -1;
11102    }
11103 
11104    strtrim(sp);
11105    if ( *sp == '\0' ) {
11106       store_error_message("Too few items on line.");
11107       return -1;
11108    }
11109 
11110    return create_launchers(launcherpp, label, line_no, sp);
11111 }
11112 
11113 
11114 /*---------------------------------------------------------------------+
11115  | Make the appropriate changes/additions/error checks for launchers   |
11116  | once all the config file information has been stored.               |
11117  +---------------------------------------------------------------------*/
finalize_launchers(void)11118 int finalize_launchers ( void )
11119 {
11120    unsigned char mode, matched;
11121    int           j, k, noloc, lnum, errors = 0;
11122    LAUNCHER      *launcherp;
11123    SCRIPT        *scriptp;
11124 
11125    mode = configp->launch_mode ;
11126    launcherp = configp->launcherp;
11127    scriptp = configp->scriptp;
11128    noloc = (configp->loc_flag == (LONGITUDE | LATITUDE)) ? 0 : 1;
11129 
11130    if ( !launcherp && !scriptp )
11131       return 0;
11132    else if ( launcherp && !scriptp ) {
11133       fprintf(stderr, "Config File: No SCRIPTs defined for LAUNCHERs");
11134       return 1;
11135    }
11136    else if ( !launcherp && scriptp ) {
11137       fprintf(stderr, "Config File: No LAUNCHERs defined for SCRIPTs");
11138       return 1;
11139    }
11140 
11141    errors = 0;
11142 
11143    /* Check for duplicate script labels */
11144    k = 0;
11145    while ( scriptp[k].line_no > 0 ) {
11146       j = k + 1;
11147       while ( scriptp[j].line_no > 0 ) {
11148          if ( strcmp(scriptp[j].label, scriptp[k].label) == 0 ) {
11149             fprintf(stderr, "Config Line %02d: Script label '%s' duplicates line %d\n",
11150                scriptp[j].line_no, scriptp[j].label, scriptp[k].line_no);
11151             errors++;
11152          }
11153          j++;
11154       }
11155       k++;
11156    }
11157 
11158 
11159    /* Match up scripts and launchers */
11160    k = 0;
11161    while ( scriptp[k].line_no > 0 ) {
11162       j = 0;
11163       matched = 0;
11164       lnum = 0;
11165       scriptp[k].num_launchers = 0;
11166       while ( launcherp[j].line_no > 0 ) {
11167          if ( strcmp(launcherp[j].label, scriptp[k].label) == 0 ) {
11168             matched = 1;
11169             launcherp[j].scriptnum = k;
11170             launcherp[j].launchernum = lnum++;
11171             scriptp[k].num_launchers += 1;
11172          }
11173          j++;
11174       }
11175       if ( !matched ) {
11176          fprintf(stderr, "Config Line %02d: No LAUNCHER for SCRIPT with label '%s'\n",
11177                  scriptp[k].line_no, scriptp[k].label);
11178          errors++;
11179       }
11180       k++;
11181    }
11182 
11183    j = 0;
11184    while ( launcherp[j].line_no > 0 ) {
11185       /* Skip known bad launchers */
11186       if ( !(launcherp[j].oksofar) ) {
11187          j++;
11188          continue;
11189       }
11190 
11191       if ( launcherp[j].scriptnum < 0 ) {
11192          fprintf(stderr, "Config Line %02d: No SCRIPT with label '%s' found\n",
11193                     launcherp[j].line_no, launcherp[j].label);
11194          errors++;
11195       }
11196 
11197       if ( noloc &&
11198            ((launcherp[j].sflags | launcherp[j].notsflags) & (NIGHT_FLAG | DARK_FLAG)) ) {
11199          fprintf(stderr,
11200              "Config Line %02d: Flags night/notnight/dark/notdark require LONGITUDE and LATITUDE\n",
11201                  launcherp[j].line_no);
11202          errors++;
11203       }
11204 
11205       if ( launcherp[j].scanmode == 0 ) {
11206          launcherp[j].scanmode = configp->scanmode;
11207       }
11208 
11209       if ( configp->inactive_handling == NEW && launcherp[j].type == L_SENSORFAIL ) {
11210          fprintf(stderr, "Config Line %02d: Sensorfail script ignored.", launcherp[j].line_no);
11211       }
11212 
11213       if ( launcherp[j].type != L_NORMAL && launcherp[j].type != L_ADDRESS ) {
11214          j++;
11215          continue;
11216       }
11217 
11218       /* Consolidate signal sources */
11219       if ( launcherp[j].source & LSNONE )
11220          launcherp[j].source &= ~(launcherp[j].nosource | LSNONE);
11221       else
11222          launcherp[j].source =
11223            (configp->launch_source | launcherp[j].source) & ~launcherp[j].nosource;
11224 
11225       if ( !launcherp[j].source ) {
11226          fprintf(stderr,
11227             "Config Line %02d: No sources (e.g., RCVI) for LAUNCHER with label '%s'\n",
11228                     launcherp[j].line_no, launcherp[j].label);
11229          errors++;
11230       }
11231 
11232       if ( launcherp[j].signal )
11233          launcherp[j].signal = launcherp[j].bmaptrig;
11234       else if ( launcherp[j].module )
11235          launcherp[j].signal = 0;
11236       else if ( mode == TMODE_SIGNAL )
11237          launcherp[j].signal = launcherp[j].bmaptrig;
11238       else
11239          launcherp[j].signal = 0;
11240 
11241 
11242       /* Fix up 'changed' function if no other function specified */
11243       if ( launcherp[j].chgtrig != 0 ) {
11244          if ( (launcherp[j].afuncmap | launcherp[j].gfuncmap | launcherp[j].sfuncmap |
11245                launcherp[j].xfuncmap | launcherp[j].ofuncmap | launcherp[j].kfuncmap) == 0 ) {
11246 #if 0
11247          if ( launcherp[j].afuncmap == 0 && launcherp[j].gfuncmap == 0 &&
11248               launcherp[j].xfuncmap == 0 && launcherp[j].ofuncmap == 0 &&
11249               launcherp[j].sfuncmap == 0 && launcherp[j].kfuncmap == 0 ) {
11250 #endif
11251             launcherp[j].afuncmap = ~(0);
11252             launcherp[j].gfuncmap = ~(0);
11253             launcherp[j].sfuncmap = ~(0);
11254             launcherp[j].xfuncmap = ~(0);
11255             launcherp[j].ofuncmap = ~(0);
11256             launcherp[j].kfuncmap = ~(0);
11257          }
11258       }
11259 
11260       j++;
11261    }
11262 
11263    return errors;
11264 }
11265 
11266 
11267 /*---------------------------------------------------------------------+
11268  | Add a script to the array of SCRIPT structures and return           |
11269  | the index of the new member.                                        |
11270  +---------------------------------------------------------------------*/
11271 int add_script ( SCRIPT **scriptpp, LAUNCHER **launcherpp, int line_no, char *tail )
11272 {
11273    static int size, maxsize;
11274    static int sizscript = sizeof(SCRIPT);
11275    int        blksize = 5;
11276    int        j, index;
11277    char       *sp, *dup;
11278    unsigned char opts;
11279    char       token[51];
11280    char       errmsg[128];
11281    char       *separator = "::";
11282 
11283    /* Allocate memory for script structure */
11284 
11285    /* Allocate initial block if not already done */
11286    if ( *scriptpp == NULL ) {
11287       *scriptpp = calloc(blksize, sizscript );
11288       if ( *scriptpp == NULL ) {
11289          (void) fprintf(stderr, "Unable to allocate memory for Script.\n");
11290          exit(1);
11291       }
11292       maxsize = blksize;
11293       size = 0;
11294       for ( j = 0; j < maxsize; j++ ) {
11295          (*scriptpp)[j].line_no = -1 ;
11296          (*scriptpp)[j].label[0] = '\0';
11297          (*scriptpp)[j].script_option = 0;
11298          (*scriptpp)[j].cmdline = NULL;
11299       }
11300    }
11301 
11302    /* Check to see if there's an available location          */
11303    /* If not, increase the size of the memory allocation.    */
11304    /* (Always leave room for a final termination indicator.) */
11305    if ( size == (maxsize - 1) ) {
11306       maxsize += blksize ;
11307       *scriptpp = realloc(*scriptpp, maxsize * sizscript );
11308       if ( *scriptpp == NULL ) {
11309          (void) fprintf(stderr, "Unable to increase size of Script list.\n");
11310          exit(1);
11311       }
11312 
11313       /* Initialize the new memory allocation */
11314       for ( j = size; j < maxsize; j++ ) {
11315          (*scriptpp)[j].line_no = -1 ;
11316          (*scriptpp)[j].label[0] = '\0';
11317          (*scriptpp)[j].script_option = 0;
11318          (*scriptpp)[j].cmdline = NULL;
11319       }
11320    }
11321 
11322    index = size;
11323    size += 1;
11324 
11325    /* Now add the new script information */
11326 
11327    sp = tail;
11328 
11329    (*scriptpp)[index].line_no = line_no;
11330 
11331    /* Locate substring separating the launcher from the command line */
11332    if ( (sp = strstr(tail, separator)) == NULL ) {
11333       sprintf(errmsg, "Invalid SCRIPT format - no '%s' separator\n", separator);
11334       store_error_message(errmsg);
11335       return -1;
11336    }
11337 
11338    *sp = '\0';
11339     sp += strlen(separator);
11340 
11341    strtrim(sp);
11342    if ( *sp == '\0' ) {
11343       store_error_message("Missing script command line\n");
11344       return -1;
11345    }
11346 
11347 #if 0
11348    while ( *sp == '-' ) {
11349       /* Look for -xtend option */
11350       if ( strncmp(sp, "-x", 2) == 0 ) {
11351          (*scriptpp)[index].script_option |= SCRIPT_XTEND;
11352          /* Bypass the token */
11353          get_token(token, &sp, " \t", 50);
11354          strtrim(sp);
11355          continue;
11356       }
11357 
11358       /* Look for -noenv option */
11359       if ( strncmp(sp, "-n", 2) == 0 ) {
11360          (*scriptpp)[index].script_option |= SCRIPT_NOENV;
11361          /* Bypass the token */
11362          get_token(token, &sp, " \t", 50);
11363          strtrim(sp);
11364          continue;
11365       }
11366 
11367       /* Look for -rawlevel option */
11368       if ( strncmp(sp, "-r", 2) == 0 ) {
11369          (*scriptpp)[index].script_option |= SCRIPT_RAWLEVEL;
11370          /* Bypass the token */
11371          get_token(token, &sp, " \t", 50);
11372          strtrim(sp);
11373          continue;
11374       }
11375 
11376       /* Look for -qquiet or -quiet option */
11377       if ( strncmp(sp, "-qq", 3) == 0 ) {
11378          (*scriptpp)[index].script_option |= SCRIPT_QQUIET;
11379          /* Bypass the token */
11380          get_token(token, &sp, " \t", 50);
11381          strtrim(sp);
11382          continue;
11383       }
11384 
11385       if ( strncmp(sp, "-q", 2) == 0 ) {
11386          (*scriptpp)[index].script_option |= SCRIPT_QUIET;
11387          /* Bypass the token */
11388          get_token(token, &sp, " \t", 50);
11389          strtrim(sp);
11390          continue;
11391       }
11392 
11393       get_token(token, &sp, " \t", 50);
11394       strtrim(sp);
11395       sprintf(errmsg, "Invalid script option '%s'\n", token);
11396       store_error_message(errmsg);
11397       return -1;
11398    }
11399 
11400    opts = (*scriptpp)[index].script_option;
11401    if ( (opts & SCRIPT_NOENV && opts & (SCRIPT_XTEND | SCRIPT_RAWLEVEL)) ||
11402         (opts & SCRIPT_QUIET && opts & SCRIPT_QQUIET)  ||
11403         (opts & SCRIPT_XTEND && opts & SCRIPT_RAWLEVEL)  ) {
11404       store_error_message("Invalid combination of script options\n");
11405       return -1;
11406    }
11407 #endif
11408 
11409    opts = 0;
11410    while ( *sp == '-' ) {
11411       if ( strncmp(sp, "-qq", 3) == 0 ) {
11412          opts |= SCRIPT_QQUIET;
11413       }
11414       else if ( strncmp(sp, "-q", 2) == 0 ) {
11415          opts |= SCRIPT_QUIET;
11416       }
11417       else if ( strncmp(sp, "-r", 2) == 0 ) {
11418          opts |= SCRIPT_RAWLEVEL;
11419       }
11420       else if ( strncmp(sp, "-n", 2) == 0 ) {
11421          opts |= SCRIPT_NOENV;
11422       }
11423       else if ( strncmp(sp, "-x", 2) == 0 ) {
11424          opts |= SCRIPT_XTEND;
11425       }
11426       else {
11427          get_token(token, &sp, " \t", 50);
11428          sprintf(errmsg, "Invalid script option '%s'\n", token);
11429          store_error_message(errmsg);
11430          return -1;
11431       }
11432       /* Bypass the token */
11433       get_token(token, &sp, " \t", 50);
11434       strtrim(sp);
11435    }
11436 
11437    if ( (opts & SCRIPT_NOENV && opts & (SCRIPT_XTEND | SCRIPT_RAWLEVEL)) ||
11438         (opts & SCRIPT_QUIET && opts & SCRIPT_QQUIET)  ||
11439         (opts & SCRIPT_XTEND && opts & SCRIPT_RAWLEVEL)  ) {
11440       store_error_message("Invalid combination of script options\n");
11441       return -1;
11442    }
11443    (*scriptpp)[index].script_option = opts;
11444 
11445    if ( *sp == '\0' ) {
11446       store_error_message("Missing script command line\n");
11447       return -1;
11448    }
11449 
11450    if ( (dup = strdup(sp)) == NULL ) {
11451       fprintf(stderr, "Unable to allocate memory for script command line.\n");
11452       exit(1);
11453    }
11454    (*scriptpp)[index].cmdline = dup;
11455 
11456    sp = tail;
11457 
11458    /* Does script have a label? */
11459    get_token(token, &sp, " \t", 50);
11460    if ( strcmp(token, "-l") == 0 ) {
11461       /* Yes */
11462       get_token(token, &sp, " \t", 50);
11463       strncpy2((*scriptpp)[index].label, token, NAME_LEN);
11464    }
11465    else {
11466       /* No - create default label */
11467       sprintf((*scriptpp)[index].label, "Script_%02d", line_no);
11468       sp = tail;
11469    }
11470 
11471    strtrim(sp);
11472 
11473    /* Add launchers if specified here, otherwise assume user will */
11474    /* add them as a separate config item.                         */
11475    if ( *sp != '\0' ) {
11476       if ( create_launchers(launcherpp, (*scriptpp)[index].label, line_no, sp) < 0 )
11477          return -1;
11478    }
11479 
11480    return index;
11481 }
11482 
11483 /*---------------------------------------------------------------------+
11484  | Load the x10image file and pass back its checksum in the argument.  |
11485  | Return 1 if OK, 0 otherwise.                                        |
11486  +---------------------------------------------------------------------*/
11487 int load_image ( int *chksump )
11488 {
11489 
11490    FILE *fd;
11491 
11492    if ( !(fd = fopen(pathspec(IMAGE_FILE), "r")) ) {
11493       return 0;
11494    }
11495 
11496    if ( fread((void *)image, 1, PROMSIZE + 2, fd) != PROMSIZE ) {
11497       fclose(fd);
11498       return 0;
11499    }
11500    fclose(fd);
11501 
11502    if ( (*chksump = image_chksum(image)) == -1 )
11503       return 0;
11504 
11505    return 1;
11506 }
11507 
11508 
11509 /*---------------------------------------------------------------------+
11510  | Load the x10image file and compare it's checksum with the argument. |
11511  | Return 1 if OK, 0 otherwise.                                        |
11512  +---------------------------------------------------------------------*/
11513 int loadcheck_image ( int chksum )
11514 {
11515 
11516    FILE *fd;
11517    int  sum;
11518 
11519    if ( !(fd = fopen(pathspec(IMAGE_FILE), "r")) ) {
11520       return 0;
11521    }
11522 
11523    if ( fread((void *)image, 1, PROMSIZE + 2, fd) != PROMSIZE ) {
11524       fclose(fd);
11525       return 0;
11526    }
11527    fclose(fd);
11528 
11529    sum = image_chksum(image);
11530    if ( sum != chksum || sum == -1 )
11531       return 0;
11532 
11533    return 1;
11534 }
11535 
11536 /*---------------------------------------------------------------------+
11537  | Return a pointer to the (static) image.                             |
11538  +---------------------------------------------------------------------*/
11539 unsigned char *image_ptr ( void )
11540 {
11541    return image;
11542 }
11543 
11544 /*---------------------------------------------------------------------+
11545  | Scan the cm11a memory image to locate the trigger having argument   |
11546  | tag which resulted in execution of the macro at macaddr.  Pass back |
11547  | the housecode|unit and housecode|function bytes through the         |
11548  | argument list.  Return the tag (1-6) of the matching trigger, or 0  |
11549  | if no match or if the tag is 7 (indicating anything more than 6).   |
11550  +---------------------------------------------------------------------*/
11551 int find_trigger ( unsigned char *image, unsigned int macaddr,
11552     unsigned char tag, unsigned char *hcu, unsigned char *hcf,
11553     unsigned char *fwver )
11554 {
11555    unsigned char func, count, *sp;
11556    unsigned int  addr;
11557 
11558    if ( tag > 6 )
11559       return 0;
11560 
11561    count = 0;
11562 
11563    /* Start of trigger table */
11564    addr = ((image[0] << 8) | image[1]) & 0x3ff;
11565    sp = image + addr;
11566 
11567    /* Future:                                          */
11568    /* Heyu stores CM11A firmware version in a byte     */
11569    /* between the timer table terminator 0xff and the  */
11570    /* start of the trigger table.                      */
11571    *fwver = *(sp - 1);
11572 
11573    while ( sp < (image + PROMSIZE - 2) ) {
11574       if ( *sp == 0xff && *(sp+1) == 0xff )
11575          break;
11576       addr = (((*(sp+1)) << 8) | *(sp+2)) & 0x7ff;
11577       if ( addr == macaddr && ++count == tag ) {
11578          *hcu = *sp;
11579          func = (*(sp+1) & 0x80 ) ? 2 : 3;
11580          *hcf = (*hcu & 0xf0u) | func;
11581          return count;
11582       }
11583       sp += 3;
11584    }
11585 
11586    return 0;
11587 }
11588 
11589 /*---------------------------------------------------------------------+
11590  | Display the trigger with argument tag which executed the macro at   |
11591  | macaddr.  Also update the system state and launch a script if so    |
11592  | programmed.                                                         |
11593  +---------------------------------------------------------------------*/
11594 void display_trigger( char *statstr, unsigned int macaddr, unsigned char tag )
11595 {
11596    unsigned char hcu, hcf, fwver, buf[4];
11597    int           launchp;
11598    int           count;
11599 
11600    count = find_trigger(image, macaddr, tag, &hcu, &hcf, &fwver);
11601 
11602    /* Just return if macro delay > 0 */
11603    if ( image[macaddr] > 0 )
11604       return;
11605 
11606    if ( count > 0 ) {
11607       buf[0] = 0x04;
11608       buf[1] = hcu;
11609       fprintf(fdsout, "%s rcvt %s\n", statstr, translate_sent(buf, 2, &launchp));
11610       buf[0] = 0x06;
11611       buf[1] = hcf;
11612       fprintf(fdsout, "%s rcvt %s\n", statstr, translate_sent(buf, 2, &launchp));
11613       if ( launchp >= 0 )
11614          launch_scripts(&launchp);
11615    }
11616    else {
11617       fprintf(fdsout, "%s rcvt Undetermined trigger\n", statstr);
11618    }
11619 
11620    return;
11621 }
11622 
11623 /*---------------------------------------------------------------------+
11624  |  Perform multiple functions when a macro is executed:               |
11625  |     Display individual addresses/functions in monitor               |
11626  |     Update x10status for each address/function                      |
11627  |     If trigger conditions are met, launch the user's script.        |
11628  |                                                                     |
11629  |  Argument 'type' is TRIGGER_EXEC or TIMER_EXEC                      |
11630  +---------------------------------------------------------------------*/
11631 int expand_macro( char *statstr, unsigned int macaddr, int type )
11632 {
11633    int           nelem, j;
11634    unsigned char hcode, ucode, level, len;
11635    unsigned int  bitmap, mask;
11636    unsigned char buf[8];
11637    unsigned char *elemp;
11638    int           launchp;
11639    char          *pfix;
11640 
11641    static unsigned char cmdlen[16] = {
11642       3,3,3,3,4,4,3,6,3,3,3,3,3,3,3,3
11643    };
11644 
11645    if ( type == TRIGGER_EXEC )
11646       pfix = "sndt";
11647    else
11648       pfix = "sndm";
11649 
11650    nelem = image[macaddr + 1];
11651    elemp = image + macaddr + 2;
11652 
11653    for ( j = 0; j < nelem; j++ ) {
11654       hcode = (elemp[0] & 0xf0u) >> 4;
11655       len = cmdlen[elemp[0] & 0x0f];
11656 
11657       bitmap = (elemp[1] << 8) | elemp[2];
11658 
11659       /* Display addresses */
11660       mask = 1;
11661       for ( ucode = 0; ucode < 16; ucode++ ) {
11662          if ( bitmap & mask ) {
11663             buf[0] = 0x04;
11664             buf[1] = (hcode << 4) | ucode ;
11665             fprintf(fdsout, "%s %s %s\n", statstr, pfix, translate_sent(buf, 2, &launchp));
11666          }
11667          mask = mask << 1;
11668       }
11669 
11670       if ( len == 3 ) {
11671          /* Basic command */
11672          buf[0] = 0x06;
11673          buf[1] = elemp[0];
11674          fprintf(fdsout, "%s %s %s\n", statstr, pfix, translate_sent(buf, 2, &launchp));
11675          if ( launchp >= 0 )
11676             launch_scripts(&launchp);
11677       }
11678       else if ( len == 4 ) {
11679          /* Dim or Bright command */
11680          level = elemp[3] & 0x1f;
11681          if ( elemp[3] & 0x80 ) {
11682             /* Brighten bit is set */
11683             buf[0] = (22 << 3) | 0x06;
11684             buf[1] = (hcode << 4) | 5;
11685             fprintf(fdsout, "%s %s %s\n", statstr, pfix, translate_sent(buf, 2, &launchp));
11686             if ( launchp >= 0 )
11687                launch_scripts(&launchp);
11688          }
11689          buf[0] = (level << 3) | 0x06;
11690          buf[1] = elemp[0];
11691          fprintf(fdsout, "%s %s %s\n", statstr, pfix, translate_sent(buf, 2, &launchp));
11692          if ( launchp >= 0 )
11693             launch_scripts(&launchp);
11694       }
11695       else {
11696          /* Extended command */
11697          buf[0] = 0x07;
11698          buf[1] = elemp[0];
11699          buf[2] = elemp[3];
11700          buf[3] = elemp[4];
11701          buf[4] = elemp[5];
11702          fprintf(fdsout, "%s %s %s\n", statstr, pfix, translate_sent(buf, 5, &launchp));
11703          if ( launchp >= 0 )
11704             launch_scripts(&launchp);
11705       }
11706       elemp += len;
11707    }
11708    return 1;
11709 }
11710 
11711 /*---------------------------------------------------------------------+
11712  | Write a lock file for the state engine.  Return 1 if one already    |
11713  | exists or can't be written; 0 otherwise.                            |
11714  +---------------------------------------------------------------------*/
11715 int lock_state_engine ( PID_T pid )
11716 {
11717    FILE *fdlock;
11718    int  acc;
11719 
11720    if ( (acc = access(enginelockfile, F_OK)) == 0 ) {
11721       /* File exists - assume state engine is running */
11722       printf("Heyu state engine is already running.\n");
11723       return 1;
11724    }
11725 
11726    if ( (fdlock = fopen(enginelockfile, "w")) == NULL ) {
11727       fprintf(stderr, "Unable to lock heyu state engine.");
11728       return 1;
11729    }
11730 
11731    fprintf(fdlock, "%ld\n", (long)pid);
11732    fclose(fdlock);
11733 
11734    return 0;
11735 }
11736 
11737 /*---------------------------------------------------------------------+
11738  | Unlink the lock file for the state engine.                          |
11739  +---------------------------------------------------------------------*/
11740 int unlock_state_engine ( void )
11741 {
11742    int retcode;
11743 
11744    retcode = unlink(enginelockfile);
11745 
11746    if ( retcode == 0 || errno == ENOENT )
11747       return 0;
11748 
11749    return retcode;
11750 }
11751 
11752 /*---------------------------------------------------------------------+
11753  | Return 1 if a lock file exists for the state engine, 0 otherwise.   |
11754  +---------------------------------------------------------------------*/
11755 int checklock_state_engine ( void )
11756 {
11757    int  acc;
11758 
11759    if ( (acc = access(enginelockfile, F_OK)) == 0 ) {
11760       return 1;
11761    }
11762    return 0;
11763 }
11764 
11765 /*---------------------------------------------------------------------+
11766  | Tell the state engine daemon to shut itself down and wait for it to |
11767  | unlink the lock file.  This will fail if called by heyu on a        |
11768  | different channel (serial_port) since the spool file is different.  |
11769  | Return 0 if successful or non-zero otherwise.                       |
11770  +---------------------------------------------------------------------*/
11771 int stop_state_engine ( void )
11772 {
11773    int  j, k, retcode = 1;
11774 
11775    if ( (retcode = checklock_state_engine()) != 0 ) {
11776       for ( j = 0; j < 3; j++ ) {
11777          send_x10state_command(ST_EXIT, 0);
11778          for ( k = 0; k < 10; k++ ) {
11779             millisleep(100);
11780             if ( (retcode = checklock_state_engine()) == 0 )
11781                return 0;
11782          }
11783       }
11784    }
11785 
11786    /* Orphan lockfile? */
11787    retcode = unlock_state_engine();
11788 
11789    return retcode;
11790 }
11791 
11792 
11793 #ifdef EXEC_POSIX
11794 
11795 /*---------------------------------------------------------------------+
11796  | Start the state engine process - POSIX style.                       |
11797  +---------------------------------------------------------------------*/
11798 int c_start_engine ( int argc, char *argv[] )
11799 {
11800    extern int    c_engine(int, char **);
11801 
11802    int           status;
11803    char          *dup;
11804    char          tmpfile[PATH_LEN + 1 + 10];
11805    PID_T         pid, retpid;
11806    extern        char *argptr;
11807 
11808    if ( check_for_engine() == 0 ) {
11809       fprintf(stderr,"heyu_engine is running - use 'heyu restart' to reconfigure\n");
11810       return 1;
11811    }
11812 
11813    retpid = fork();
11814 
11815    if ( retpid == (PID_T)(-1) ) {
11816       fprintf(stderr, "Unable to fork() for starting state engine.\n");
11817       fflush(stderr);
11818       return 1;
11819    }
11820 
11821    if ( retpid == (PID_T)0 ) {
11822       /* In child process */
11823       if ( (pid = fork()) > (PID_T)0 ) {
11824          /* Child dies; grandchild inherited by init */
11825          _exit(0);
11826       }
11827       else if ( pid < (PID_T)0 ) {
11828          fprintf(stderr, "Failed to double fork() for state engine.\n");
11829          fflush(stderr);
11830          _exit(1);
11831       }
11832       else {
11833          /* Put config path into environment for any scripts calling heyu */
11834          sprintf(tmpfile, "X10CONFIG=%s", pathspec(heyu_config));
11835          if ( (dup = strdup(tmpfile)) == NULL || putenv(dup) == -1 ) {
11836             fprintf(stderr, "Memory allocation error in c_start_engine()\n");
11837             exit(1);
11838          }
11839 
11840          strcpy(argptr, "heyu_engine");
11841 
11842          close(0);
11843 
11844          pid = setsid();
11845          if ( pid < (PID_T)0 ) {
11846             fprintf(stderr, "Unable to setsid() for state engine.\n");
11847             exit(1);
11848          }
11849 
11850          i_am_state = 1;
11851          i_am_relay = 0;
11852          heyu_parent = D_CMDLINE;
11853          if ( read_x10state_file() != 0 )
11854             x10state_init_all();
11855          lock_state_engine(pid);
11856          c_engine(argc, argv);
11857          return 0;
11858       }
11859    }
11860 
11861    /* Wait for child process to die */
11862    while ( waitpid(retpid, &status, 0) < (PID_T)0 && errno == EINTR )
11863       ;
11864    if (WEXITSTATUS(status) != 0 ) {
11865      fprintf(stderr, "Unable to double fork() for starting engine.\n");
11866      return 1;
11867    }
11868 
11869    return 0;
11870 }
11871 
11872 #else
11873 
11874 /*---------------------------------------------------------------------+
11875  | Start the state engine process - non-POSIX                          |
11876  +---------------------------------------------------------------------*/
11877 int c_start_engine ( int argc, char *argv[] )
11878 {
11879    extern int    c_engine(int, char **);
11880 
11881    char          *dup;
11882    char          tmpfile[PATH_LEN + 1 + 10];
11883    PID_T         pid, retpid;
11884    extern        char *argptr;
11885 
11886 
11887    if ( check_for_engine() == 0 ) {
11888       fprintf(stderr,"heyu_engine is running - use 'heyu restart' to reconfigure\n");
11889       return 1;
11890    }
11891 
11892    signal(SIGCHLD, SIG_IGN);
11893 
11894    retpid = fork();
11895 
11896    if ( retpid == (PID_T)(-1) ) {
11897       fprintf(stderr, "Unable to fork() for starting state engine.\n");
11898       return 1;
11899    }
11900 
11901    if ( retpid == (PID_T)0 ) {
11902       /* Put config path into environment for any scripts calling heyu */
11903       sprintf(tmpfile, "X10CONFIG=%s", pathspec(heyu_config));
11904       if ( (dup = strdup(tmpfile)) == NULL || putenv(dup) == -1 ) {
11905          fprintf(stderr, "Memory allocation error in c_start_engine()\n");
11906          exit(1);
11907       }
11908 
11909       strcpy(argptr, "heyu_engine");
11910 
11911       close(0);
11912       close(1);
11913       close(2);
11914 
11915       pid = setsid();
11916       if ( pid < (PID_T)0 ) {
11917          fprintf(stderr, "Failure in setsid() for starting state engine.\n");
11918          exit(1);
11919       }
11920       i_am_state = 1;
11921       i_am_relay = 0;
11922       heyu_parent = D_CMDLINE;
11923       if ( read_x10state_file() != 0 )
11924          x10state_init_all();
11925       lock_state_engine(pid);
11926       c_engine(argc, argv);
11927       return 0;
11928    }
11929 
11930    return 0;
11931 }
11932 
11933 #endif  /* End of ifdef EXEC_POSIX / else block */
11934 
11935 /*----------------------------------------------------------------------------+
11936  | Instruct state engine to update the flags.  Argument mode is SETFLAG or    |
11937  | CLRFLAG                                                                    |
11938  +----------------------------------------------------------------------------*/
11939 int send_long_flag_update ( unsigned char bank, unsigned long flagmap, unsigned char mode )
11940 {
11941    extern int sptty;
11942 
11943    int ignoret;
11944 
11945    static unsigned char template[12] = {
11946     0xff,0xff,0xff,8,ST_COMMAND,ST_FLAGS32,0,0, 0,0,0,0};
11947 
11948    template[6] = mode;
11949    template[7] = bank;
11950    template[8] = (flagmap & 0xff000000) >> 24;
11951    template[9] = (flagmap & 0x00ff0000) >> 16;
11952    template[10] = (flagmap & 0x0000ff00) >> 8;
11953    template[11] = flagmap & 0x000000ff;
11954 
11955    ignoret = write(sptty, template, sizeof(template));
11956 
11957    return 0;
11958 }
11959 
11960 /*----------------------------------------------------------------------------+
11961  | Instruct state engine to update the flags.  Argument mode is SETFLAG or    |
11962  | CLRFLAG                                                                    |
11963  +----------------------------------------------------------------------------*/
11964 int send_flag_update ( unsigned int flagmap, unsigned char mode )
11965 {
11966    extern int sptty;
11967 
11968    int ignoret;
11969 
11970    static unsigned char template[9] = {
11971     0xff,0xff,0xff,5,ST_COMMAND,ST_FLAGS,0,0,0};
11972 
11973    template[6] = mode;
11974    template[7] = (flagmap & 0xff00) >> 8;
11975    template[8] = flagmap & 0xff;
11976 
11977    ignoret = write(sptty, template, sizeof(template));
11978 
11979    return 0;
11980 }
11981 
11982 
11983 /*----------------------------------------------------------------------------+
11984  | Instruct state engine to clear the status flags for hcode and bitmap       |
11985  +----------------------------------------------------------------------------*/
11986 int send_clear_statusflags ( unsigned char hcode, unsigned int bitmap )
11987 {
11988    extern int sptty;
11989 
11990    int ignoret;
11991 
11992    static unsigned char template[9] = {
11993      0xff,0xff,0xff,5,ST_COMMAND,ST_CLRSTATUS,0,0,0};
11994 
11995    template[6] = hcode;
11996    template[7] = (bitmap & 0xff00) >> 8;
11997    template[8] = bitmap & 0xff;
11998 
11999    ignoret = write(sptty, template, sizeof(template));
12000    return 0;
12001 }
12002 
12003 
12004 void clear_statusflags ( unsigned char hcode, unsigned int bitmap )
12005 {
12006 //   x10state[hcode].statusflags &= ~bitmap;
12007    x10state[hcode].state[SpendState] &= ~bitmap;
12008 
12009    return;
12010 }
12011 
12012 /*---------------------------------------------------------------------+
12013  | Return states of Night and/or Dark flags.                           |
12014  |  'nightstate' or 'darkstate' return Boolean.                        |
12015  |  'sunstate' returns bitmap where night = 1, dark = 2                |
12016  +---------------------------------------------------------------------*/
12017 int c_sunstate ( int argc, char *argv[] )
12018 {
12019    unsigned int  flagmap;
12020 
12021    if ( check_for_engine() != 0 ) {
12022       fprintf(stderr, "State engine is not running.\n");
12023       return 1;
12024    }
12025 
12026    if ( argc > 2 ) {
12027       fprintf(stderr, "%s: Too many parameters.\n", argv[1]);
12028       return 1;
12029    }
12030 
12031    if ( read_x10state_file() != 0 ) {
12032       fprintf(stderr, "Unable to read state file.\n");
12033       return 1;
12034    }
12035 
12036    if ( !x10global.dawndusk_enable ) {
12037       fprintf(stderr, "LATITUDE and/or LONGITUDE have not been defined.\n");
12038       return 1;
12039    }
12040 
12041    if ( strcmp(argv[1], "nightstate") == 0 ) {
12042       printf("%d\n", ((x10global.sflags & NIGHT_FLAG) ? 1 : 0));
12043    }
12044    else if ( strcmp(argv[1], "darkstate") == 0 ) {
12045       printf("%d\n", ((x10global.sflags & DARK_FLAG) ? 1 : 0));
12046    }
12047    else if ( strcmp(argv[1], "sunstate") == 0 ) {
12048       flagmap = (x10global.sflags & NIGHT_FLAG) ? 1 : 0;
12049       flagmap |= (x10global.sflags & DARK_FLAG) ? 2 : 0;
12050       printf("%d\n", flagmap);
12051    }
12052 
12053    return 0;
12054 }
12055 
12056 /*---------------------------------------------------------------------+
12057  | Read counter                                                        |
12058  +---------------------------------------------------------------------*/
12059 int c_counter ( int argc, char *argv[] )
12060 {
12061    int           index;
12062    char          *sp;
12063 
12064    if ( check_for_engine() != 0 ) {
12065       fprintf(stderr, "State engine is not running.\n");
12066       return 1;
12067    }
12068 
12069    if ( argc < 3 ) {
12070       fprintf(stderr, "%s: Too few parameters.\n", argv[1]);
12071       return 1;
12072    }
12073    else if ( argc > 3 ) {
12074       fprintf(stderr, "%s: Too many parameters.\n", argv[1]);
12075       return 1;
12076    }
12077 
12078    if ( strcmp(argv[1], "counter") == 0 )  {
12079       index = (int)strtol(argv[2], &sp, 10);
12080       if ( !strchr(" /t/n", *sp) || index < 1 || index > 32 * NUM_COUNTER_BANKS ) {
12081          fprintf(stderr, "Invalid counter number.\n");
12082          return 1;
12083       }
12084       if ( read_x10state_file() != 0 ) {
12085          fprintf(stderr, "Unable to read state file.\n");
12086          return 1;
12087       }
12088       printf("%d\n", x10global.counter[index - 1]);
12089    }
12090 
12091    return 0;
12092 }
12093 
12094 /*---------------------------------------------------------------------+
12095  | Flag reading and setting commands.                                  |
12096  +---------------------------------------------------------------------*/
12097 int c_flagstate ( int argc, char *argv[] )
12098 {
12099    unsigned long flagmap;
12100    int           flag;
12101    char          *sp;
12102 
12103    if ( check_for_engine() != 0 ) {
12104       fprintf(stderr, "State engine is not running.\n");
12105       return 1;
12106    }
12107 
12108    if ( argc < 3 ) {
12109       fprintf(stderr, "%s: Too few parameters.\n", argv[1]);
12110       return 1;
12111    }
12112    else if ( argc > 3 ) {
12113       fprintf(stderr, "%s: Too many parameters.\n", argv[1]);
12114       return 1;
12115    }
12116 
12117    if ( strcmp(argv[1], "flagstate") == 0 )  {
12118       flag = (int)strtol(argv[2], &sp, 10);
12119       if ( !strchr(" /t/n", *sp) || flag < 1 || flag > 32 * NUM_FLAG_BANKS ) {
12120          fprintf(stderr, "Invalid flag number.\n");
12121          return 1;
12122       }
12123       if ( read_x10state_file() != 0 ) {
12124          fprintf(stderr, "Unable to read state file.\n");
12125          return 1;
12126       }
12127       flagmap = (1 << ((flag - 1) % 32)) & x10global.flags[(flag - 1) / 32]; /*###*/
12128       printf("%d\n", ((flagmap) ? 1 : 0));
12129 
12130       return 0;
12131    }
12132 
12133    clear_error_message();
12134 
12135    flagmap = flags2longmap(argv[2]);
12136 
12137    if ( *error_message() ) {
12138       /* Display error from error handler */
12139       fprintf(stderr, "%s: %s\n", argv[1], error_message());
12140       return 1;
12141    }
12142 
12143    if ( strncmp(argv[1], "setflag", 7)   == 0 )
12144       send_long_flag_update(0, flagmap, SETFLAG);
12145    else if ( strncmp(argv[1], "clrflag", 7) == 0 )
12146       send_long_flag_update(0, flagmap, CLRFLAG);
12147 
12148    return 0;
12149 }
12150 
12151 /*---------------------------------------------------------------------+
12152  | Status flag query.  (A status flag for Hu is set when a status_req  |
12153  | is sent or received and cleared when a status_on or status_off is   |
12154  | sent or received.                                                   |
12155  +---------------------------------------------------------------------*/
12156 int c_status_state ( int argc, char *argv[] )
12157 {
12158    unsigned int  aflags, bitmap, flagstate;
12159    char          hc;
12160 
12161    if ( check_for_engine() != 0 ) {
12162       fprintf(stderr, "%s: State engine is not running.\n", argv[1]);
12163       return 1;
12164    }
12165 
12166    if ( argc < 3 ) {
12167       fprintf(stderr, "%s: Too few parameters.\n", argv[1]);
12168       return 1;
12169    }
12170    else if ( argc > 3 ) {
12171       fprintf(stderr, "%s: Too many parameters.\n", argv[1]);
12172       return 1;
12173    }
12174 
12175    aflags = parse_addr(argv[2], &hc, &bitmap) ;
12176    if ( !(aflags & A_VALID) || !(aflags & A_HCODE) || (aflags & A_DUMMY) ) {
12177       fprintf(stderr, "%s: Invalid Housecode|Unit '%s'\n", argv[1], argv[2]);
12178       return 1;
12179    }
12180    if ( aflags & A_MULT ) {
12181       fprintf(stderr, "%s: Only a single unit code is acceptable\n", argv[1]);
12182       return 1;
12183    }
12184 
12185    if ( read_x10state_file() != 0 ) {
12186       fprintf(stderr, "%s: Unable to read state file.\n", argv[1]);
12187       return 1;
12188    }
12189 
12190    if ( aflags & A_MINUS )
12191       bitmap = 0;
12192    if ( aflags & A_PLUS && bitmap == 0 )
12193       bitmap = 1;
12194 
12195    flagstate = x10state[hc2code(hc)].state[SpendState];
12196 //   flagstate = x10state[hc2code(hc)].statusflags;
12197 
12198    if ( bitmap )
12199       printf("%d\n", ((flagstate & bitmap) ? 1 : 0) );
12200    else
12201       printf("%d\n", x10map2linmap(flagstate));
12202 
12203    return 0;
12204 }
12205 
12206 /*---------------------------------------------------------------------+
12207  | Display timestamp for a module address                              |
12208  +---------------------------------------------------------------------*/
12209 int show_signal_timestamp ( char *address )
12210 {
12211    unsigned int  aflags, bitmap;
12212    unsigned char ucode;
12213    char          hc;
12214    time_t        timestamp;
12215    struct tm     *tmp;
12216    extern char   *heyu_tzname[2];
12217    extern void   fix_tznames ( void );
12218 
12219    aflags = parse_addr(address, &hc, &bitmap);
12220 
12221    if ( !(aflags & A_VALID) || (aflags & A_MULT) || bitmap == 0 ) {
12222       fprintf(stderr, "Invalid Hu address parameter.\n");
12223       return 1;
12224    }
12225    ucode = single_bmap_unit(bitmap);
12226 
12227    timestamp = x10state[hc2code(hc)].timestamp[ucode];
12228 
12229    if ( timestamp == 0 ) {
12230       printf("No signal has been recorded for this address.\n");
12231       return 0;
12232    }
12233 
12234    fix_tznames();
12235 
12236    tmp = localtime(&timestamp);
12237    printf("%c%d: %s  %02d:%02d:%02d  %s %02d %d %s\n",
12238      hc, code2unit(ucode), wday_name[tmp->tm_wday],
12239      tmp->tm_hour, tmp->tm_min, tmp->tm_sec, month_name[tmp->tm_mon],
12240      tmp->tm_mday, tmp->tm_year + 1900, heyu_tzname[tmp->tm_isdst]);
12241 
12242    return 0;
12243 }
12244 
12245 /*---------------------------------------------------------------------+
12246  | Initialize a countdown timer with the countdown time in seconds.    |
12247  +---------------------------------------------------------------------*/
12248 void set_user_timer_countdown ( int timer_nbr, long seconds )
12249 {
12250    if ( timer_nbr < 0 || timer_nbr > NUM_USER_TIMERS )
12251       return;
12252 
12253    x10global.timer_count[timer_nbr] = seconds;
12254 
12255    if ( seconds == 0 )
12256       x10global.tzflags[(timer_nbr - 1) / 32] |= (1UL << ((timer_nbr - 1) % 32));
12257    else
12258       x10global.tzflags[(timer_nbr - 1) / 32] &= ~(1UL << ((timer_nbr - 1) % 32));
12259 
12260    return;
12261 }
12262 
12263 /*---------------------------------------------------------------------+
12264  | Reset all user timers 1 through NUM_USER_TIMERS                     |
12265  +---------------------------------------------------------------------*/
12266 void reset_user_timers ( void )
12267 {
12268    int j;
12269 
12270    for ( j = 1; j <= NUM_USER_TIMERS; j++ )
12271       x10global.timer_count[j] = 0;
12272 
12273    for ( j = 0; j < NUM_TIMER_BANKS; j++ )
12274       x10global.tzflags[j] = ~(0UL);
12275 
12276    return;
12277 }
12278 
12279 /*---------------------------------------------------------------------+
12280  | Display @settimer setting                                           |
12281  +---------------------------------------------------------------------*/
12282 void display_settimer_setting ( int timer, long timeout )
12283 {
12284    if ( timeout < 120 )
12285       fprintf(fdsout, "%s Countdown timer %d set to %ld seconds\n", datstrf(), timer, timeout);
12286    else
12287       fprintf(fdsout, "%s Countdown timer %d set to %ld:%02ld:%02ld\n", datstrf(),
12288          timer, timeout / 3600L, (timeout % 3600L) / 60L, timeout % 3600L % 60L);
12289    fflush(fdsout);
12290    return;
12291 }
12292 
12293 
12294 /*---------------------------------------------------------------------+
12295  | Translate settimer message and set the timer countdown              |
12296  +---------------------------------------------------------------------*/
12297 char *translate_settimer_message( unsigned char *buffer )
12298 {
12299    unsigned long timeout = 0;
12300    int           j, timer;
12301    static char   message[64];
12302 
12303    timer = buffer[2] | (buffer[3] << 8);
12304    for ( j = 0; j < 4; j++ )
12305       timeout |= (unsigned long)(buffer[j + 4] << (8 * j));
12306 
12307    set_user_timer_countdown(timer, (long)timeout);
12308 
12309    if ( timeout < 120 )
12310       sprintf(message, "Countdown timer %d set to %ld seconds", timer, timeout);
12311    else
12312       sprintf(message, "Countdown timer %d set to %ld:%02ld:%02ld",
12313          timer, timeout / 3600L, (timeout % 3600L) / 60L, timeout % 3600L % 60L);
12314 
12315    return message;
12316 }
12317 
12318 
12319 /*---------------------------------------------------------------------+
12320  | Send settimer message to State Engine.                              |
12321  +---------------------------------------------------------------------*/
12322 void send_settimer_msg( unsigned short timer, long timeout )
12323 {
12324    int  j;
12325 
12326    int ignoret;
12327 
12328    static unsigned char template[12] =
12329      {0xff, 0xff, 0xff, 8, ST_COMMAND, ST_SETTIMER, 0,0, 0,0,0,0};
12330 
12331    template[6] = timer & 0x00ff;
12332    template[7] = (timer & 0xff00) >> 8;
12333    for ( j = 0; j < 4; j++ ) {
12334       template[j + 8] = (unsigned char)(timeout & 0xff);
12335       timeout >>= 8;
12336    }
12337    ignoret = write(sptty, (char *)template, sizeof(template));
12338    return;
12339 }
12340 
12341 /*---------------------------------------------------------------------+
12342  | Display security flags as bitmap:                                   |
12343  |   0=disarmed, 1=armed, 2=home, 4=armpending, 8 = tamper             |
12344  +---------------------------------------------------------------------*/
12345 int c_armedstate( int argc, char *argv[] )
12346 {
12347    long globsec;
12348 
12349    if ( check_for_engine() != 0 ) {
12350       fprintf(stderr, "Engine is not running\n");
12351       return 1;
12352    }
12353 
12354    fetch_x10state();
12355 
12356    globsec = x10global.sflags & (GLOBSEC_ARMED | GLOBSEC_HOME | GLOBSEC_PENDING | GLOBSEC_TAMPER);
12357 
12358    printf("%ld\n", (globsec >> GLOBSEC_SHIFT));
12359 
12360    return 0;
12361 }
12362 
12363 /*---------------------------------------------------------------------+
12364  | Display security Armed, Disarmed, Pending, Home, Away               |
12365  +---------------------------------------------------------------------*/
12366 int c_armed_status( int argc, char *argv[] )
12367 {
12368    if ( check_for_engine() != 0 ) {
12369       fprintf(stderr, "Engine is not running\n");
12370       return 1;
12371    }
12372 
12373    fetch_x10state();
12374 
12375    printf("%s\n", display_armed_status());
12376    return 0;
12377 }
12378 
12379 /*---------------------------------------------------------------------+
12380  | Create general date or date/time string.                            |
12381  +---------------------------------------------------------------------*/
12382 void gendate ( char *datestr, time_t timestamp, unsigned char showyear, unsigned char showtime )
12383 {
12384    struct tm *tmp;
12385    char   sep;
12386 
12387    tmp = localtime(&timestamp);
12388 
12389    sep = configp->date_separator;
12390    *datestr = '\0';
12391 
12392    if ( configp->date_format == YMD_ORDER ) {
12393       /* [yyyy/]mm/dd */
12394       if ( showyear == YES) {
12395          sprintf(datestr, "%d%c", tmp->tm_year + 1900, sep);
12396       }
12397       sprintf(datestr + strlen(datestr), "%02d%c%02d",
12398          tmp->tm_mon + 1, sep, tmp->tm_mday);
12399    }
12400    else if ( configp->date_format == MDY_ORDER ) {
12401       /* mm/dd[/yyyy] */
12402       sprintf(datestr, "%02d%c%02d",
12403          tmp->tm_mon + 1, sep, tmp->tm_mday);
12404       if ( showyear == YES) {
12405          sprintf(datestr + strlen(datestr), "%c%d", sep, tmp->tm_year + 1900);
12406       }
12407    }
12408    else if ( configp->date_format == DMY_ORDER ) {
12409       /* dd/mm/yyyy */
12410       sprintf(datestr, "%02d%c%02d", tmp->tm_mday, sep, tmp->tm_mon + 1);
12411       if ( showyear == YES ) {
12412          sprintf(datestr + strlen(datestr), "%c%d", sep, tmp->tm_year + 1900);
12413       }
12414    }
12415 
12416    if ( showtime == YES )
12417       sprintf(datestr + strlen(datestr), " %02d:%02d:%02d",
12418           tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
12419 
12420    return;
12421 }
12422 
12423 /*---------------------------------------------------------------------+
12424  | Date display in seconds from epoch.                                 |
12425  +---------------------------------------------------------------------*/
12426 void datstrf_epoch ( char *buffer )
12427 {
12428    struct timeval tvstruct;
12429    struct timeval *tv = &tvstruct;
12430 
12431    gettimeofday(tv, NULL);
12432 
12433    sprintf(buffer, "%ld.%03ld ",
12434        (unsigned long)tv->tv_sec, (unsigned long)tv->tv_usec/1000);
12435 
12436    return;
12437 }
12438 
12439 /*---------------------------------------------------------------------+
12440  | Date display with optional subdirectory for monitor and log file.   |
12441  +---------------------------------------------------------------------*/
12442 char *datstrf ( void )
12443 {
12444    extern struct opt_st *optptr;
12445    static char buffer[40];
12446 
12447    if ( configp->logdate_unix == YES )
12448       datstrf_epoch(buffer);
12449    else {
12450       gendate(buffer, time(NULL), configp->logdate_year, YES);
12451       strcat(buffer, " ");
12452    }
12453 
12454    if ( configp->disp_subdir == YES ) {
12455       if ( optptr->dispsub[0] != '\0' )
12456          strcat(buffer, optptr->dispsub);
12457       else
12458          strcat(buffer, " ");
12459    }
12460 
12461    return buffer;
12462 }
12463 
12464 /*---------------------------------------------------------------------+
12465  | Launch -timeout scripts for timer number                            |
12466  +---------------------------------------------------------------------*/
12467 int launch_timeout_scripts ( int timer )
12468 {
12469    LAUNCHER *launcherp;
12470    int      j, launchp = -1;
12471 
12472    if ( !i_am_state || !(launcherp = configp->launcherp) )
12473       return 0;
12474 
12475    j = 0;
12476    while ( launcherp[j].line_no > 0 ) {
12477       if ( (launcherp[j].type != L_TIMEOUT) ||
12478            (launcherp[j].timer != timer) ||
12479            is_unmatched_flags(&launcherp[j])  ) {
12480          j++;
12481          continue;
12482       }
12483       launcherp[j].matched = YES;
12484       launchp = j;
12485       if ( launcherp[j].scanmode & FM_BREAK )
12486          break;
12487       j++;
12488   }
12489 
12490   return launch_scripts(&launchp);
12491 
12492 }
12493 
12494 
12495 /*---------------------------------------------------------------------+
12496  | Timeout processing - called by countdown function.                  |
12497  +---------------------------------------------------------------------*/
12498 void timer_timeout ( int timer )
12499 {
12500 
12501    if ( i_am_state || i_am_monitor ) {
12502       fprintf(fdsout, "%s Timeout, %s\n", datstrf(), countdown_timer[timer].timername);
12503       fflush(fdsout);
12504    }
12505    if ( i_am_state ) {
12506       write_x10state_file();
12507       launch_timeout_scripts(timer);
12508    }
12509 
12510    return;
12511 }
12512 
12513 /*---------------------------------------------------------------------+
12514  | Raise Armed flag - called by countdown function.                    |
12515  +---------------------------------------------------------------------*/
12516 void arm_delay_complete ( int armtimer )
12517 {
12518 
12519    x10global.sflags |= GLOBSEC_ARMED;
12520    x10global.sflags &= ~GLOBSEC_PENDING;
12521 
12522    if ( i_am_state || i_am_monitor ) {
12523       fprintf(fdsout, "%s %s\n", datstrf(), display_armed_status());
12524       fflush(fdsout);
12525    }
12526    if ( i_am_state ) {
12527       write_x10state_file();
12528       launch_timeout_scripts(armtimer);
12529    }
12530 
12531    return;
12532 }
12533 
12534 /*---------------------------------------------------------------------+
12535  | Execute sensorfail scripts                                          |
12536  +---------------------------------------------------------------------*/
12537 int launch_sensorfail_scripts ( int index )
12538 {
12539    LAUNCHER *launcherp;
12540    int      j, launchp = -1;
12541 
12542    if ( !i_am_state || !(launcherp = configp->launcherp) )
12543       return 0;
12544 
12545    j = 0;
12546    while ( launcherp[j].line_no > 0 ) {
12547       if ( (launcherp[j].type != L_SENSORFAIL) ||
12548            is_unmatched_flags(&launcherp[j])  ) {
12549          j++;
12550          continue;
12551       }
12552       launcherp[j].matched = YES;
12553       launcherp[j].sensor = index;
12554       launchp = j;
12555       if ( launcherp[j].scanmode & FM_BREAK )
12556          break;
12557       j++;
12558   }
12559 
12560   return launch_scripts(&launchp);
12561 
12562 }
12563 
12564 /*---------------------------------------------------------------------+
12565  | Launch inactive sensor script - called by countdown function.       |
12566  +---------------------------------------------------------------------*/
12567 void sensor_elapsed_func_old ( int index )
12568 {
12569    ALIAS *aliasp;
12570 
12571    aliasp = configp->aliasp;
12572 
12573    if ( i_am_state || i_am_monitor ) {
12574       fprintf(fdsout, "%s Inactive sensor %c%s (%s)\n", datstrf(),
12575          aliasp[index].housecode, bmap2units(aliasp[index].unitbmap),
12576          aliasp[index].label);
12577       fflush(fdsout);
12578    }
12579    if ( i_am_state ) {
12580       write_x10state_file();
12581       launch_sensorfail_scripts(index);
12582    }
12583 
12584    return;
12585 }
12586 
12587 /*---------------------------------------------------------------------+
12588  | Launch inactive sensor script - called by countdown function.       |
12589  +---------------------------------------------------------------------*/
12590 void sensor_elapsed_func ( int index )
12591 {
12592    unsigned char  hcode, func, ucode, vdata;
12593    unsigned char  actfunc, genfunc;
12594    unsigned int   bitmap, trigaddr, mask, active, trigactive;
12595    unsigned int   changestate, startupstate;
12596    unsigned int   bmaplaunch, launched;
12597    unsigned long  afuncmap = 0, gfuncmap = 0, sfuncmap = 0;
12598    int            j, trig, hide = 0, launchp = -1;
12599    char           hc;
12600    LAUNCHER       *launcherp;
12601    ALIAS          *aliasp;
12602    unsigned int   source;
12603    char           *srcname;
12604 
12605    aliasp = configp->aliasp;
12606    launcherp = configp->launcherp;
12607 
12608    hc = aliasp[index].housecode;
12609    bitmap = aliasp[index].unitbmap;
12610 
12611    hcode = hc2code(hc);
12612    ucode = single_bmap_unit(bitmap);
12613 
12614    func = InactiveFunc;
12615    trig = InactiveTrig;
12616    vdata = 0;
12617 
12618    actfunc = func;
12619    genfunc = 0;
12620    afuncmap = gfuncmap = 0;
12621 
12622    active = bitmap;
12623 
12624    startupstate = ~x10state[hcode].state[ValidState] & active;
12625 
12626 //   x10state[hcode].dimlevel[ucode] = 0xffu;
12627    changestate = x10state[hcode].state[ActiveChgState] & active;
12628    x10state[hcode].state[ChgState] = (x10state[hcode].state[ChgState] & ~active) | changestate;
12629    changestate = x10state[hcode].state[ChgState];
12630 
12631    hide = (configp->hide_unchanged_inactive == YES && (changestate & active) == 0) ? 1 : 0;
12632 
12633 
12634    if ( aliasp[index].optflags & MOPT_PLCSENSOR ) {
12635        mask = modmask[PlcSensorMask][hcode];
12636        source = RCVI;
12637        srcname = "rcvi";
12638    }
12639    else {
12640        mask = modmask[VdataMask][hcode];
12641        source = RCVA;
12642        srcname = "rcva";
12643    }
12644 
12645    sfuncmap = (1 << trig);
12646 
12647    trigaddr = bitmap;
12648 
12649    bmaplaunch = 0;
12650    launched = 0;
12651    j = 0;
12652    while ( launcherp && launcherp[j].line_no > 0 ) {
12653       if ( launcherp[j].type != L_NORMAL ||
12654            launcherp[j].hcode != hcode ||
12655            is_unmatched_flags(&launcherp[j])  ) {
12656          j++;
12657 	 continue;
12658       }
12659 
12660       if ( launcherp[j].sfuncmap & sfuncmap  &&
12661            launcherp[j].source & source ) {
12662          trigactive = trigaddr & (mask | launcherp[j].signal);
12663          if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
12664               (changestate | ~launcherp[j].chgtrig)) ||
12665               (launcherp[j].unitstar && !trigaddr)) {
12666             launchp = j;
12667             launcherp[j].matched = YES;
12668             launcherp[j].actfunc = actfunc;
12669             launcherp[j].genfunc = genfunc;
12670 	    launcherp[j].xfunc = 0;
12671 	    launcherp[j].level = vdata;
12672             launcherp[j].bmaplaunch = bmaplaunch;
12673             launcherp[j].actsource = source;
12674             launched |= bmaplaunch;
12675             if ( launcherp[j].scanmode & FM_BREAK )
12676                break;
12677          }
12678       }
12679       j++;
12680    }
12681 
12682    x10state[hcode].launched = launched;
12683 
12684    if ( (i_am_state || i_am_monitor) &&  (hide == 0 || launchp >= 0) )  {
12685       fprintf(fdsout, "%s %4s func %12s : hu %c%s  (%s)\n", datstrf(),
12686          srcname, funclabel[func], hc, bmap2units(bitmap), aliasp[index].label);
12687       fflush(fdsout);
12688    }
12689 
12690    if ( i_am_state ) {
12691       write_x10state_file();
12692    }
12693 
12694    if ( launchp >= 0 )
12695       launch_scripts(&launchp);
12696 
12697    return;
12698 }
12699 
12700 
12701 /*---------------------------------------------------------------------+
12702  | Display state of security, RFX, Oregon sensors                      |
12703  +---------------------------------------------------------------------*/
12704 int show_security_sensors ( void )
12705 {
12706    ALIAS         *aliasp;
12707    char          hc;
12708    int           j, unit, count = 0, maxmod = 0, maxlabel = 0;
12709    int           is_rfx;
12710    unsigned char hcode, ucode;
12711    unsigned int  bitmap, active, inactive;
12712    time_t        timestamp;
12713    char          *batstatus;
12714    char          datestr[40];
12715 
12716    if ( !(aliasp = config.aliasp) )
12717       return 0;
12718 
12719    if ( fetch_x10state() != 0 )
12720       return 1;
12721 
12722    /* Get maximum lengths of module name and alias label */
12723    j = 0;
12724    while ( aliasp[j].line_no > 0 ) {
12725       if ( (aliasp[j].optflags & (MOPT_SENSOR | MOPT_RFXSENSOR | MOPT_RFXMETER | MOPT_PLCSENSOR)) != 0 ) {
12726          count++;
12727          maxlabel = max(maxlabel, (int)strlen(aliasp[j].label));
12728          maxmod = max(maxmod, (int)strlen(lookup_module_name(aliasp[j].modtype)) );
12729       }
12730       j++;
12731    }
12732 
12733    if ( count == 0 ) {
12734       printf("No security sensors have been defined.\n");
12735       return 0;
12736    }
12737 
12738    j = 0;
12739    while ( aliasp[j].line_no > 0 ) {
12740       if ( (aliasp[j].optflags & (MOPT_SENSOR | MOPT_RFXSENSOR | MOPT_RFXMETER | MOPT_PLCSENSOR)) == 0 ) {
12741          j++;
12742          continue;
12743       }
12744 
12745       hc = aliasp[j].housecode;
12746       hcode = hc2code(hc);
12747       is_rfx = (aliasp[j].optflags & MOPT_RFXSENSOR) ? 1 : 0;
12748       for ( unit = 1; unit <= 16; unit++ ) {
12749          ucode = unit2code(unit);
12750          bitmap = aliasp[j].unitbmap & (1 << ucode);
12751          if ( bitmap ) {
12752             timestamp = x10state[hcode].timestamp[ucode];
12753             inactive = x10state[hcode].state[InactiveState] & bitmap;
12754 //            active = ~inactive & x10state[hcode].state[ValidState] & bitmap;
12755             active = x10state[hcode].state[ActiveState] & bitmap;
12756 
12757             batstatus = ((aliasp[j].optflags & MOPT_LOBAT) == 0) ? "n/a," :
12758               (timestamp == 0) ? "---," :
12759               ( (is_rfx && (x10state[hcode].rfxlobat & (1 << ucode))) ||
12760                 (x10state[hcode].vflags[ucode] & SEC_LOBAT) ) ? "LOW," : "OK,";
12761 
12762             printf("%c%-2d %-*s  %-*s  %sbattery %-4s ", hc, unit,
12763               maxmod, lookup_module_name(aliasp[j].modtype),
12764               maxlabel, aliasp[j].label,
12765               ((x10state[hcode].vflags[ucode] & SEC_TAMPER) ? "*TAMPER*, " : ""),
12766               batstatus);
12767 
12768 
12769             if ( aliasp[j].optflags & MOPT_HEARTBEAT ) {
12770                if ( !(active | inactive) )
12771                   printf("active ---, tstamp ---\n");
12772                else if ( active ) {
12773                   gendate(datestr, timestamp, NO, YES);
12774                   printf("active YES, tstamp %s\n", datestr);
12775                }
12776                else if ( timestamp == 0 ) {
12777                   printf("active NO,  tstamp ---\n");
12778                }
12779                else {
12780                   gendate(datestr, timestamp, NO, YES);
12781                   printf("active NO,  tstamp %s\n", datestr);
12782                }
12783             }
12784             else {
12785                if ( timestamp == 0 ) {
12786                   printf("active n/a, tstamp ---\n");
12787                }
12788                else {
12789                   gendate(datestr, timestamp, NO, YES);
12790                   printf("active n/a, tstamp %s\n", datestr);
12791                }
12792             }
12793 
12794          }
12795       }
12796       j++;
12797    }
12798    return 0;
12799 }
12800 
12801 /*---------------------------------------------------------------------+
12802  | Display state of security, RFX, Oregon sensors                      |
12803  +---------------------------------------------------------------------*/
12804 int show_security_sensors_old ( void )
12805 {
12806    ALIAS         *aliasp;
12807    char          hc;
12808    int           j, unit, count = 0, maxmod = 0, maxlabel = 0;
12809    int           is_rfx;
12810    unsigned char hcode, ucode;
12811    unsigned int  bitmap;
12812    time_t        timenow, timestamp;
12813    long          elapsed;
12814    char          *batstatus;
12815    char          datestr[40];
12816 
12817    if ( !(aliasp = config.aliasp) )
12818       return 0;
12819 
12820    /* Get maximum lengths of module name and alias label */
12821    j = 0;
12822    while ( aliasp[j].line_no > 0 ) {
12823       if ( (aliasp[j].optflags & (MOPT_SENSOR | MOPT_RFXSENSOR | MOPT_RFXMETER | MOPT_PLCSENSOR)) != 0 ) {
12824          count++;
12825          maxlabel = max(maxlabel, (int)strlen(aliasp[j].label));
12826          maxmod = max(maxmod, (int)strlen(lookup_module_name(aliasp[j].modtype)) );
12827       }
12828       j++;
12829    }
12830 
12831    if ( count == 0 ) {
12832       printf("No security sensors have been defined.\n");
12833       return 0;
12834    }
12835 
12836    j = 0;
12837    while ( aliasp[j].line_no > 0 ) {
12838       if ( (aliasp[j].optflags & (MOPT_SENSOR | MOPT_RFXSENSOR | MOPT_RFXMETER | MOPT_PLCSENSOR)) == 0 ) {
12839          j++;
12840          continue;
12841       }
12842 
12843       hc = aliasp[j].housecode;
12844       hcode = hc2code(hc);
12845       bitmap = aliasp[j].unitbmap;
12846       timenow = time(NULL);
12847       is_rfx = (aliasp[j].optflags & MOPT_RFXSENSOR) ? 1 : 0;
12848       for ( unit = 1; unit <= 16; unit++ ) {
12849          ucode = unit2code(unit);
12850          if ( bitmap & (1 << ucode) ) {
12851             timestamp = x10state[hcode].timestamp[ucode];
12852             elapsed = (long)(timenow - timestamp);
12853 
12854             batstatus = ((aliasp[j].optflags & MOPT_LOBAT) == 0) ? "n/a," :
12855               (timestamp == 0) ? "---," :
12856               ( (is_rfx && (x10state[hcode].rfxlobat & (1 << ucode))) ||
12857                 (x10state[hcode].vflags[ucode] & SEC_LOBAT) ) ? "LOW," : "OK,";
12858 
12859             printf("%c%-2d %-*s  %-*s  %sbattery %-4s ", hc, unit,
12860               maxmod, lookup_module_name(aliasp[j].modtype),
12861               maxlabel, aliasp[j].label,
12862               ((x10state[hcode].vflags[ucode] & SEC_TAMPER) ? "*TAMPER*, " : ""),
12863               batstatus);
12864 
12865 
12866             if ( aliasp[j].optflags & MOPT_HEARTBEAT ) {
12867                if ( timestamp == 0 )
12868                   printf("active ---, tstamp ---\n");
12869                else if ( elapsed < config.inactive_timeout ) {
12870                   gendate(datestr, timestamp, NO, YES);
12871                   printf("active YES, tstamp %s\n", datestr);
12872                }
12873                else {
12874                   gendate(datestr, timestamp, NO, YES);
12875                   printf("active NO,  tstamp %s\n", datestr);
12876                }
12877             }
12878             else {
12879                if ( timestamp == 0 ) {
12880                   printf("active n/a, tstamp ---\n");
12881                }
12882                else {
12883                   gendate(datestr, timestamp, NO, YES);
12884                   printf("active n/a, tstamp %s\n", datestr);
12885                }
12886             }
12887 
12888          }
12889       }
12890       j++;
12891    }
12892    return 0;
12893 }
12894 
12895 /*---------------------------------------------------------------------+
12896  | Check all modules defined by their module_type in an alias as a     |
12897  | security sensor.  OR the results from all security sensors.         |
12898  | Display a bitmap with 0 = OK, 1 = low battery, 2 = inactive         |
12899  | Display an error message if the heyu_engine is not running.         |
12900  +---------------------------------------------------------------------*/
12901 int c_sensorfault ( int argc, char *argv[] )
12902 {
12903    ALIAS         *aliasp;
12904    int           j, count = 0;
12905    unsigned char hcode, ucode, status = 0;
12906    unsigned int  bitmap;
12907 
12908    if ( check_for_engine() != 0 ) {
12909       fprintf(stderr, "State engine is not running.\n");
12910       return 1;
12911    }
12912 
12913    if ( argc > 2 ) {
12914       fprintf(stderr, "This command takes no parameters.\n");
12915       return 1;
12916    }
12917 
12918    fetch_x10state();
12919 
12920    aliasp = config.aliasp;
12921 
12922    j = 0;
12923    while ( aliasp && aliasp[j].line_no > 0 ) {
12924       if ( (aliasp[j].optflags & (MOPT_HEARTBEAT | MOPT_LOBAT)) == 0 ) {
12925          j++;
12926          continue;
12927       }
12928       hcode = hc2code(aliasp[j].housecode);
12929       bitmap = aliasp[j].unitbmap;
12930       for ( ucode = 0; ucode < 16; ucode++ ) {
12931          if ( bitmap & (1 << ucode) ) {
12932             count++;
12933             if ( x10state[hcode].state[InactiveState] & (1 << ucode) )
12934                status |= 2;
12935 #if 0
12936             if ( x10state[hcode].vflags[ucode] & SEC_LOBAT )
12937                status |= 1;
12938             if ( x10state[hcode].vflags[ucode] & SEC_TAMPER )
12939                status |= 8;
12940 #endif
12941             if ( x10state[hcode].state[LoBatState] & (1 << ucode) )
12942                status |= 1;
12943          }
12944       }
12945       j++;
12946    }
12947    if ( x10global.sflags & GLOBSEC_TAMPER )
12948       status |= 8;
12949 
12950    printf("%d\n", status);
12951 
12952    return 0;
12953 }
12954 
12955 #if 0
12956 /*---------------------------------------------------------------------+
12957  | Update the Active, Inactive, and ActiveChg states                   |
12958  +---------------------------------------------------------------------*/
12959 int update_activity_states ( unsigned char hcode, unsigned int bitmap, unsigned char mode )
12960 {
12961    unsigned int prevstate, newstate, changed;
12962 
12963    prevstate = x10state[hcode].state[InactiveState];
12964 
12965    if ( mode == S_INACTIVE ) {
12966       newstate = prevstate | bitmap;
12967    }
12968    else {
12969       newstate = prevstate & ~bitmap;
12970    }
12971    x10state[hcode].state[InactiveState] = newstate;
12972    x10state[hcode].state[ActiveState] = ~newstate & x10state[hcode].state[ValidState];
12973 
12974    changed = prevstate ^ newstate;
12975 
12976    x10state[hcode].state[ActiveChgState] =
12977        (x10state[hcode].state[ActiveChgState] & ~bitmap) | changed;
12978 
12979    return 0;
12980 }
12981 #endif
12982 
12983 /*---------------------------------------------------------------------+
12984  | Reset ValidState for all modules                                    |
12985  +---------------------------------------------------------------------*/
12986 void invalidate_all_signals ( void )
12987 {
12988    unsigned char hcode;
12989 
12990    for ( hcode = 0; hcode < 16; hcode++ )
12991       x10state[hcode].state[ValidState] = 0;
12992 
12993    return;
12994 }
12995 
12996 
12997 /*---------------------------------------------------------------------+
12998  | Reset ValidState for virtual modules                                |
12999  +---------------------------------------------------------------------*/
13000 void invalidate_virtual_signals ( void )
13001 {
13002    unsigned char hcode;
13003 
13004    for ( hcode = 0; hcode < 16; hcode++ )
13005       x10state[hcode].state[ValidState] &= ~modmask[VdataMask][hcode];
13006 
13007    return;
13008 }
13009 
13010 
13011 /*---------------------------------------------------------------------+
13012  | Reset the heartbeat_sensors countdown array for argument modules    |
13013  +---------------------------------------------------------------------*/
13014 void reset_security_sensor_timeout ( unsigned char hcode, unsigned int bitmap )
13015 {
13016    ALIAS *aliasp;
13017    unsigned int activebmap;
13018    int j, index;
13019 
13020    if ( !(aliasp = configp->aliasp) )
13021       return;
13022 
13023    for ( j = 0; j < num_heartbeat_sensors; j++ ) {
13024       index = heartbeat_sensor[j].alias_index;
13025       activebmap = aliasp[index].unitbmap & bitmap;
13026       if ( hc2code(aliasp[index].housecode) == hcode && activebmap != 0 ) {
13027          heartbeat_sensor[j].countdown = aliasp[heartbeat_sensor[j].alias_index].hb_timeout;
13028          update_activity_states(hcode, activebmap, S_ACTIVE);
13029       }
13030    }
13031    return;
13032 }
13033 
13034 /*---------------------------------------------------------------------+
13035  | Initialize the heartbeat_sensors countdown array.                   |
13036  +---------------------------------------------------------------------*/
13037 int initialize_security_sensor_timeout ( CONFIG *configp )
13038 {
13039    ALIAS         *aliasp;
13040    int           j;
13041    unsigned char hcode, ucode;
13042    time_t        now;
13043 
13044    if ( !(aliasp = configp->aliasp) )
13045       return 0;
13046 
13047    time(&now);
13048 
13049    num_heartbeat_sensors = 0;
13050    j = 0;
13051    while ( aliasp[j].line_no > 0 && num_heartbeat_sensors < MAX_SEC_SENSORS ) {
13052       hcode = hc2code(aliasp[j].housecode);
13053       ucode = single_bmap_unit(aliasp[j].unitbmap);
13054       if ( ucode < 0x10u &&
13055            (aliasp[j].optflags & MOPT_HEARTBEAT) &&
13056           !(aliasp[j].optflags & MOPT_RFIGNORE) ) {
13057          heartbeat_sensor[num_heartbeat_sensors].countdown = aliasp[j].hb_timeout;
13058 
13059          if ( (x10state[hcode].timestamp[ucode] != 0) &&
13060               (now - x10state[hcode].timestamp[ucode]) > aliasp[j].hb_timeout ) {
13061             update_activity_states(hcode, (1 << ucode), S_INACTIVE);
13062          }
13063          else {
13064             update_activity_states(hcode, (1 << ucode), S_ACTIVE);
13065          }
13066 
13067          aliasp[j].hb_index = num_heartbeat_sensors;
13068          heartbeat_sensor[num_heartbeat_sensors++].alias_index = j;
13069       }
13070       j++;
13071    }
13072 
13073    return num_heartbeat_sensors;
13074 }
13075 
13076 /*---------------------------------------------------------------------+
13077  | Initialize timestamps                                               |
13078  +---------------------------------------------------------------------*/
13079 void initialize_timestamps ( void )
13080 {
13081    int hcode, ucode;
13082 
13083    for ( hcode = 0; hcode < 16; hcode++ ) {
13084       for ( ucode = 0; ucode < 16; ucode++ ) {
13085         x10state[hcode].timestamp[ucode] = 0;
13086       }
13087    }
13088    return ;
13089 }
13090 
13091 /*---------------------------------------------------------------------+
13092  | Clear global and module tamper flags                                |
13093  +---------------------------------------------------------------------*/
13094 int clear_tamper_flags ( void )
13095 {
13096    unsigned char hcode, ucode;
13097 
13098    for ( hcode = 0; hcode < 16; hcode++ ) {
13099       for ( ucode = 0; ucode < 16; ucode++ ) {
13100          x10state[hcode].vflags[ucode] &= ~SEC_TAMPER;
13101       }
13102       x10state[hcode].state[TamperState] = 0;
13103    }
13104 
13105    x10global.sflags &= ~GLOBSEC_TAMPER;
13106 
13107    return 0;
13108 }
13109 
13110 /*---------------------------------------------------------------------+
13111  | Load UTC0 times of today's Dawn and Dusk into global structure.     |
13112  | Called at heyu_engine startup or restart, and at Midnight, STD Time |
13113  +---------------------------------------------------------------------*/
13114 int set_global_dawndusk ( time_t utc0 )
13115 {
13116 
13117    if ( x10global.dawndusk_enable == 0 ) {
13118       x10global.utc0_dawn = x10global.utc0_dusk = 0;
13119       return 0;
13120    }
13121 
13122    local_dawndusk(utc0, &x10global.utc0_dawn, &x10global.utc0_dusk);
13123 
13124    return 0;
13125 }
13126 
13127 /*---------------------------------------------------------------------+
13128  | Called at startup and again once every minute to update the 'night' |
13129  | and 'dark' global flags.                                            |
13130  +---------------------------------------------------------------------*/
13131 int update_global_nightdark_flags ( time_t utc0 )
13132 {
13133    time_t         dawndark, duskdark;
13134    unsigned long  oldflags;
13135 
13136    if ( x10global.dawndusk_enable == 0 ) {
13137       x10global.sflags &= ~(NIGHT_FLAG | DARK_FLAG);
13138       return 0;
13139    }
13140 
13141    oldflags = x10global.sflags;
13142 
13143    if ( x10global.utc0_dawn <= x10global.utc0_dusk ) {
13144       if ( utc0 < x10global.utc0_dawn || utc0 >= x10global.utc0_dusk )
13145          x10global.sflags |= NIGHT_FLAG;
13146       else
13147          x10global.sflags &= ~NIGHT_FLAG;
13148    }
13149    else {
13150       if ( utc0 >= x10global.utc0_dawn || utc0 < x10global.utc0_dusk )
13151          x10global.sflags &= ~NIGHT_FLAG;
13152       else
13153          x10global.sflags |= NIGHT_FLAG;
13154    }
13155 
13156 
13157    dawndark = x10global.utc0_dawn - (time_t)60 * (time_t)x10global.isdark_offset;
13158    duskdark = x10global.utc0_dusk + (time_t)60 * (time_t)x10global.isdark_offset;
13159 
13160    if ( dawndark <= duskdark ) {
13161       if ( utc0 < dawndark || utc0 >= duskdark )
13162          x10global.sflags |= DARK_FLAG;
13163       else
13164          x10global.sflags &= ~DARK_FLAG;
13165    }
13166    else {
13167       if ( utc0 >= dawndark || utc0 < duskdark )
13168          x10global.sflags &= ~DARK_FLAG;
13169       else
13170          x10global.sflags |= DARK_FLAG;
13171    }
13172 
13173    if ( i_am_state && ((oldflags ^ x10global.sflags) & (NIGHT_FLAG | DARK_FLAG)) )
13174       write_x10state_file();
13175 
13176    return 0;
13177 }
13178 
13179 /*---------------------------------------------------------------------+
13180  | Display global Dawn and Dusk in Civil Time                          |
13181  +---------------------------------------------------------------------*/
13182 char *display_global_dawndusk ( void )
13183 {
13184    static char buffer[64];
13185    struct tm *tmp;
13186 
13187    tmp = localtime(&x10global.utc0_dawn);
13188    sprintf(buffer, "dawn = %02d:%02d, ", tmp->tm_hour, tmp->tm_min);
13189    tmp = localtime(&x10global.utc0_dusk);
13190    sprintf(buffer + strlen(buffer), "dusk = %02d:%02d\n", tmp->tm_hour, tmp->tm_min);
13191    return buffer;
13192 }
13193 
13194 /*---------------------------------------------------------------------+
13195  | Pass back the times of dawn and dusk expressed as seconds after     |
13196  | midnight civil (wall clock) time.                                   |
13197  +---------------------------------------------------------------------*/
13198 int dawndusk_today ( long *dawn, long *dusk )
13199 {
13200    struct tm *tmp;
13201 
13202    if ( x10global.dawndusk_enable == 0 )
13203       return -1;
13204 
13205    tmp = localtime(&x10global.utc0_dawn);
13206    *dawn = 3600L * (long)tmp->tm_hour + 60L * (long)tmp->tm_min + (long)tmp->tm_sec;
13207 
13208    tmp = localtime(&x10global.utc0_dusk);
13209    *dusk = 3600L * (long)tmp->tm_hour + 60L * (long)tmp->tm_min + (long)tmp->tm_sec;
13210 
13211    return 0;
13212 }
13213 
13214 /*---------------------------------------------------------------------+
13215  | Print remaining countdown times for active timers, i.e., with       |
13216  | non-zero countdown times.                                           |
13217  +---------------------------------------------------------------------*/
13218 int show_global_timers ( void )
13219 {
13220    int  j;
13221    long count;
13222 
13223    for ( j = 1; j <= NUM_USER_TIMERS; j++ ) {
13224       if ( (count = x10global.timer_count[j]) > 0 )
13225          printf("Timer %2d  %ld:%02ld:%02ld\n", j, count/3600L, (count % 3600L)/60L, count % 60);
13226    }
13227    return 0;
13228 }
13229 
13230 /*---------------------------------------------------------------------+
13231  | Print global Dawn and Dusk times for today.                         |
13232  +---------------------------------------------------------------------*/
13233 int show_state_dawndusk ( void )
13234 {
13235    struct tm   *tmp;
13236    extern char *heyu_tzname[2];
13237    extern void fix_tznames ( void );
13238    long        lutc0;
13239    time_t      midnight;
13240 
13241    static char   *sunmodelabel[] = {"Sunrise/Sunset", "Civil Twilight",
13242         "Nautical Twilight", "Astronomical Twilight", "Sun angle offset = %d'", };
13243 
13244    if ( configp->loc_flag != (LONGITUDE | LATITUDE) ||
13245         x10global.dawndusk_enable == 0 ) {
13246       fprintf(stderr, "LONGITUDE and LATITUDE must be specified in config file.\n");
13247       return -1;
13248    }
13249 
13250    fix_tznames();
13251 
13252    lutc0 = (long)time(NULL);
13253    midnight = (time_t)(lutc0 - ((lutc0 - configp->tzone) % 86400L));
13254 
13255    if ( x10global.utc0_dawn < midnight || x10global.utc0_dawn >= (midnight + (time_t)86400) ||
13256         x10global.utc0_dusk < midnight || x10global.utc0_dusk >= (midnight + (time_t)86400)   ) {
13257       fprintf(stderr, "Internal error: Dawn/Dusk times are for the wrong date.\n");
13258       return -1;
13259    }
13260 
13261    tmp = localtime(&x10global.utc0_dawn);
13262    printf("Dawn = %02d:%02d %s", tmp->tm_hour, tmp->tm_min, heyu_tzname[tmp->tm_isdst]);
13263 
13264    tmp = localtime(&x10global.utc0_dusk);
13265    printf("  Dusk = %02d:%02d %s  ", tmp->tm_hour,  tmp->tm_min, heyu_tzname[tmp->tm_isdst]);
13266    printf(sunmodelabel[configp->sunmode], configp->sunmode_offset);
13267    printf("\n");
13268 
13269    return 0;
13270 }
13271 
13272 /*---------------------------------------------------------------------+
13273  | Compute the UTC0 time for 24:00:00 Std Time tonight, i.e., 00:00:00 |
13274  | tomorrow, from the current UTC0 time and configured timezone.       |
13275  +---------------------------------------------------------------------*/
13276 void set_global_tomorrow ( time_t utc0 )
13277 {
13278    long lutc0;
13279 
13280    lutc0 = (long)utc0;
13281 
13282    x10global.utc0_tomorrow =
13283         (time_t)(lutc0 - ((lutc0 - configp->tzone) % 86400L) + 86400L);
13284    return;
13285 }
13286 
13287 /*---------------------------------------------------------------------+
13288  | Return 1 if argument utc0 has reached or exceeded utc0 for 00:00:00 |
13289  | hours tomorrow; otherwise return 0.                                 |
13290  +---------------------------------------------------------------------*/
13291 int is_tomorrow ( time_t utc0 )
13292 {
13293    return (utc0 >= x10global.utc0_tomorrow) ? 1 : 0;
13294 }
13295 
13296 /*---------------------------------------------------------------------+
13297  | Called at heyu_engine startup and at a restart                      |
13298  +---------------------------------------------------------------------*/
13299 int engine_local_setup ( int mode )
13300 {
13301    int check4poll(int, int);
13302    void create_rfxmeter_panels( void );
13303    int  clear_data_storage( void );
13304    time_t tnow;
13305    mode_t oldumask;
13306 
13307    /* Redirect output from engine to the Heyu log file */
13308 //   if ( i_am_state ) {
13309       oldumask = umask((mode_t)configp->log_umask);
13310       fdsout = freopen(configp->logfile, "a", stdout);
13311       fdserr = freopen(configp->logfile, "a", stderr);
13312       umask(oldumask);
13313 //   }
13314 //   else {
13315 //      fdsout = stdout;
13316 //      fdserr = stderr;
13317 //   }
13318 
13319    tnow = time(NULL);
13320    x10global.dawndusk_enable = (configp->loc_flag == (LONGITUDE | LATITUDE)) ? 1 : 0;
13321    x10global.isdark_offset = configp->isdark_offset;
13322    set_global_dawndusk(tnow);
13323    update_global_nightdark_flags(tnow);
13324    set_global_tomorrow(tnow);
13325 
13326    clear_data_storage();
13327 
13328    if ( mode == E_START ) {
13329       invalidate_all_signals();
13330       reset_user_timers();
13331    }
13332 
13333    initialize_security_sensor_timeout(configp);
13334 
13335    if ( i_am_state )
13336       write_x10state_file();
13337 
13338    return 0;
13339 }
13340 
13341 /*---------------------------------------------------------------------+
13342  | Called at heyu_engine startup and at a restart                      |
13343  +---------------------------------------------------------------------*/
13344 int engine_local_setup_old ( void )
13345 {
13346    int check4poll(int, int);
13347    void create_rfxmeter_panels( void );
13348    int  clear_data_storage( void );
13349    time_t tnow;
13350    mode_t oldumask;
13351 
13352    /* Redirect output to the Heyu log file */
13353    oldumask = umask((mode_t)configp->log_umask);
13354    fdsout = freopen(configp->logfile, "a", stdout);
13355    fdserr = freopen(configp->logfile, "a", stderr);
13356    umask(oldumask);
13357 
13358    tnow = time(NULL);
13359    x10global.dawndusk_enable = (configp->loc_flag == (LONGITUDE | LATITUDE)) ? 1 : 0;
13360    x10global.isdark_offset = configp->isdark_offset;
13361    set_global_dawndusk(tnow);
13362    update_global_nightdark_flags(tnow);
13363    set_global_tomorrow(tnow);
13364 
13365    clear_data_storage();
13366    invalidate_all_signals();
13367    reset_user_timers();
13368 
13369    initialize_security_sensor_timeout(configp);
13370 
13371    write_x10state_file();
13372 
13373    return 0;
13374 }
13375 
13376 /*---------------------------------------------------------------------+
13377  | Called at midnight, standard time                                   |
13378  +---------------------------------------------------------------------*/
13379 void midnight_tick ( time_t utc0 )
13380 {
13381    set_global_dawndusk(utc0);
13382 
13383    return;
13384 }
13385 
13386 /*---------------------------------------------------------------------+
13387  | Called once per hour                                                |
13388  +---------------------------------------------------------------------*/
13389 void hour_tick ( time_t utc0 )
13390 {
13391    launch_hourly_scripts();
13392    return;
13393 }
13394 
13395 /*---------------------------------------------------------------------+
13396  | Called once per minute                                              |
13397  +---------------------------------------------------------------------*/
13398 void minute_tick ( time_t utc0 )
13399 {
13400 
13401    update_global_nightdark_flags(utc0);
13402 
13403    /* Sanity - in case user has reset system time */
13404    set_global_tomorrow(utc0);
13405 
13406    return;
13407 }
13408 
13409 /*---------------------------------------------------------------------+
13410  | Called approximately once per second to actuate timer countdown.    |
13411  | (The time delta is included in case a tick is missed.)              |
13412  +---------------------------------------------------------------------*/
13413 void second_tick ( time_t utc0, long delta )
13414 {
13415    ALIAS         *aliasp;
13416    int           j, index;
13417    unsigned char hcode;
13418 
13419    /* Countdown Arm-pending and user timers */
13420    for ( j = 0; j <= NUM_USER_TIMERS; j++ ) {
13421       if ( x10global.timer_count[j] > 0 &&
13422            (x10global.timer_count[j] -= delta) <= 0 ) {
13423          x10global.timer_count[j] = 0;
13424          if ( j > 0 )
13425             x10global.tzflags[(j - 1) / 32] |= (1UL << ((j - 1) % 32));
13426 
13427          countdown_timer[j].elapsed_func(j);
13428       }
13429    }
13430 
13431    /* Countdown sensor heartbeat timers */
13432    if ( (aliasp = configp->aliasp) != NULL ) {
13433       for ( j = 0; j < num_heartbeat_sensors; j++ ) {
13434          index = heartbeat_sensor[j].alias_index;
13435          hcode = hc2code(aliasp[index].housecode);
13436          if ( heartbeat_sensor[j].countdown > 0 &&
13437               (heartbeat_sensor[j].countdown -= delta) <= 0 ) {
13438             heartbeat_sensor[j].countdown = aliasp[index].hb_timeout;
13439             update_activity_states(hcode, aliasp[index].unitbmap, S_INACTIVE);
13440             if ( configp->inactive_handling == OLD )
13441                sensor_elapsed_func_old(index);
13442             else
13443                sensor_elapsed_func(index);
13444          }
13445       }
13446    }
13447 
13448    return;
13449 }
13450 
13451 /*---------------------------------------------------------------------+
13452  | Display a table of Extended Code groups and levels for housecode    |
13453  +---------------------------------------------------------------------*/
13454 void show_extended_groups ( unsigned char hcode )
13455 {
13456    unsigned char ucode, grpmask, grel;
13457    unsigned int  bitmap, mask, relmask;
13458    int           unit, group, found;
13459    char          outbuf[80];
13460    char          minbuf[16];
13461 
13462    printf("Group levels (0-63) for Housecode %c\n", code2hc(hcode));
13463 
13464    printf("  Unit:");
13465    for ( unit = 1; unit <= 16; unit++ )
13466       printf("%3d", unit);
13467    printf("\nGroup  ");
13468    for ( unit = 1; unit <= 16; unit++ )
13469       printf(" --");
13470    printf("\n");
13471 
13472    mask = modmask[Ext3GrpExecMask][hcode];
13473    relmask = modmask[Ext3GrpRelMask][hcode];
13474 
13475    for ( group = 0; group < 4; group++ ) {
13476       grpmask = 1 << group;
13477       sprintf(outbuf, "  %d    ", group);
13478       /* Display the absolute group */
13479       for ( unit = 1; unit <= 16; unit++ ) {
13480          ucode = unit2code(unit);
13481          bitmap = 1 << ucode;
13482          if ( mask & bitmap ) {
13483             if ( (x10state[hcode].grpmember[ucode] & grpmask) &&
13484                  ((x10state[hcode].grpaddr[ucode] & 0x80u) == 0 ||
13485                   (x10state[hcode].grpmember[ucode] & 0x80u) != 0) ) {
13486                sprintf(minbuf, "%3d", x10state[hcode].grplevel[ucode][group]);
13487             }
13488             else {
13489                sprintf(minbuf, "  -");
13490             }
13491          }
13492          else {
13493             sprintf(minbuf, "  .");
13494          }
13495          strcat(outbuf, minbuf);
13496       }
13497       printf("%s\n", outbuf);
13498 
13499       /* Scan for relative groups and display if any */
13500       for ( grel = 0x80u; grel < 0x8fu; grel++ ) {
13501          sprintf(outbuf, "  %d.%-2d ", group, (grel & 0x7fu) + 1);
13502          found = 0;
13503          for ( unit = 1; unit <= 16; unit++ ) {
13504             ucode = unit2code(unit);
13505             bitmap = 1 << ucode;
13506             if ( mask & bitmap ) {
13507                if ( (x10state[hcode].grpmember[ucode] & grpmask) &&
13508                      x10state[hcode].grpaddr[ucode] == grel ) {
13509                   found = 1;
13510                   sprintf(minbuf, "%3d", x10state[hcode].grplevel[ucode][group]);
13511                }
13512                else {
13513                   sprintf(minbuf, "  -");
13514                }
13515             }
13516             else {
13517                sprintf(minbuf, "  .");
13518             }
13519             strcat(outbuf, minbuf);
13520          }
13521          if ( found ) {
13522             printf("%s\n", outbuf);
13523          }
13524       }
13525    }
13526 
13527    printf("\n");
13528 
13529    return;
13530 }
13531 
13532 /*---------------------------------------------------------------------+
13533  | Copy xmodule information from x10state table to argument arrays.    |
13534  +---------------------------------------------------------------------*/
13535 int copy_xmodule_info ( unsigned char hcode, unsigned char grpmember[],
13536                    unsigned char grpaddr[], unsigned char grplevel[][4],
13537                    unsigned char *xconfigmode )
13538 {
13539    int ucode, group;
13540 
13541    for ( ucode = 0; ucode < 16; ucode++ ) {
13542       grpmember[ucode] = x10state[hcode].grpmember[ucode];
13543       grpaddr[ucode] = x10state[hcode].grpaddr[ucode];
13544       for ( group = 0; group < 4; group++ )
13545          grplevel[ucode][group] = x10state[hcode].grplevel[ucode][group];
13546    }
13547 
13548    *xconfigmode = x10state[hcode].xconfigmode;
13549 
13550    return 0;
13551 }
13552 
13553 /*---------------------------------------------------------------------+
13554  | Search the array of ALIAS structures for an alias having the        |
13555  | argument housecode, bitmap and vtype.  Return the alias index if    |
13556  | found, otherwise -1.                                                |
13557  +---------------------------------------------------------------------*/
13558 int alias_lookup_index ( char hc, unsigned int bitmap, unsigned char vtype )
13559 {
13560    ALIAS *aliasp;
13561    int   j;
13562 
13563    aliasp = configp->aliasp;
13564    hc = toupper((int)hc);
13565 
13566    j = 0;
13567    while ( aliasp && aliasp[j].line_no > 0 ) {
13568       if ( hc == aliasp[j].housecode &&
13569            bitmap == aliasp[j].unitbmap &&
13570            vtype == aliasp[j].vtype ) {
13571          return j;
13572       }
13573       j++;
13574    }
13575    return -1;
13576 }
13577 
13578 /*---------------------------------------------------------------------+
13579  | Used to update the record of the last timed macro execution.        |
13580  +---------------------------------------------------------------------*/
13581 void set_macro_timestamp ( time_t now )
13582 {
13583    x10global.utc0_macrostamp = now;
13584    return;
13585 }
13586 
13587 /*---------------------------------------------------------------------+
13588  | Retrieve the record of the last timed macro execution.              |
13589  +---------------------------------------------------------------------*/
13590 time_t get_macro_timestamp ( void )
13591 {
13592    return x10global.utc0_macrostamp;
13593 }
13594 
13595 
13596 /*---------------------------------------------------------------------+
13597  | Set, Increment, or Decrement internal counter and flags.            |
13598  +---------------------------------------------------------------------*/
13599 int set_counter ( int index, unsigned short count, unsigned char mode )
13600 {
13601    int retcode = 0;
13602 
13603    if ( mode == CNT_DEC ) {
13604       /* Decrement counter by 1 */
13605       if ( x10global.counter[index - 1] > 0 )
13606          x10global.counter[index - 1] -= 1;
13607    }
13608    else if ( mode == CNT_DSKPZ ) {
13609       /* Decrement counter by 1 and Skip if Zero */
13610       if ( x10global.counter[index - 1] > 0 )
13611          x10global.counter[index - 1] -= 1;
13612       if ( x10global.counter[index - 1] == 0 )
13613          retcode = -1;
13614    }
13615    else if ( mode == CNT_DSKPNZ ) {
13616       /* Decrement counter by 1 and Skip if Not Zero */
13617       if ( x10global.counter[index - 1] > 0 )
13618          x10global.counter[index - 1] -= 1;
13619       if ( x10global.counter[index - 1] > 0 )
13620          retcode = -1;
13621    }
13622    else if ( mode == CNT_DSKPNZIZ ) {
13623       /* Decrement counter by 1 and Skip if Not Zero */
13624       /* (or if counter is 0 to start with).         */
13625       if ( x10global.counter[index - 1] > 0 ) {
13626          x10global.counter[index - 1] -= 1;
13627          if ( x10global.counter[index - 1] > 0 )
13628             retcode = -1;
13629       }
13630       else {
13631          retcode = -1;
13632       }
13633    }
13634    else if ( mode == CNT_INC ) {
13635       /* Increment counter by 1 */
13636       if ( x10global.counter[index - 1] < 0xffff )
13637          x10global.counter[index - 1] += 1;
13638    }
13639    else {
13640       /* Set counter value */
13641       x10global.counter[index - 1] = count;
13642    }
13643 
13644    /* Set or reset counter = zero flag */
13645    if ( x10global.counter[index - 1] == 0 )
13646       x10global.czflags[(index - 1) / 32] |= (unsigned long)(1 << ((index - 1) % 32));
13647    else
13648       x10global.czflags[(index - 1) / 32] &= ~(unsigned long)(1 << ((index - 1) % 32));
13649 
13650    return retcode;
13651 }
13652 
13653 char *translate_counter_action ( unsigned char *buf )
13654 {
13655    int index, count, mode;
13656    static char outbuf[80];
13657 
13658    index = buf[2] | (buf[3] << 8);
13659    count = buf[4] | (buf[5] << 8);
13660    mode  = buf[6];
13661 
13662    sprintf(outbuf, "Counter %d %s to %d", index,
13663       ((mode == CNT_INC) ? "incremented" :
13664        (mode == CNT_DEC) ? "decremented" : "set"), x10global.counter[index - 1]);
13665 
13666    return outbuf;
13667 }
13668 
13669 /*----------------------------------------------------------------------------+
13670  | Send a setcounter message to the heyu monitor/state engine                 |
13671  +----------------------------------------------------------------------------*/
13672 void send_setcounter_msg ( int index, unsigned short count, unsigned char mode )
13673 {
13674    extern int sptty;
13675 
13676    int ignoret;
13677 
13678    static unsigned char template[11] = {
13679      0xff,0xff,0xff,7,ST_COMMAND,ST_COUNTER,0,0, 0,0, 0};
13680 
13681    template[6] = index & 0x00ff;
13682    template[7] = (index & 0xff00) >> 8;
13683    template[8] = count & 0x00ff;
13684    template[9] = (count & 0xff00) >> 8;
13685    template[10] = mode;
13686 
13687    ignoret = write(sptty, template, sizeof(template));
13688    return;
13689 }
13690 
13691 /*----------------------------------------------------------------------------+
13692  | Update the timeout for a PLC Sensor                                        |
13693  +----------------------------------------------------------------------------*/
13694 int update_plcsensor_timeout ( unsigned char hcode, unsigned int bitmap )
13695 {
13696    ALIAS *aliasp;
13697    int   j;
13698    char  hc;
13699 
13700    if ( !(aliasp = configp->aliasp) )
13701       return 0;
13702 
13703    hc = code2hc(hcode);
13704    j = 0;
13705    while ( aliasp[j].line_no > 0 ) {
13706       if ( aliasp[j].housecode == hc && aliasp[j].unitbmap == bitmap ) {
13707          update_activity_timeout(aliasp, j);
13708          update_activity_states(hcode, bitmap, S_ACTIVE);
13709          break;
13710       }
13711       j++;
13712    }
13713    return 0;
13714 }
13715 
13716 
13717 /*---------------------------------------------------------------------+
13718  | Set contents of all data in x10global.data_storage[] array to zero  |
13719  +---------------------------------------------------------------------*/
13720 int clear_data_storage ( void )
13721 {
13722    int j;
13723 
13724    for ( j = 0; j < MAXDATASTORAGE; j++ )
13725       x10global.data_storage[j] = 0;
13726 
13727    return 0;
13728 }
13729 
13730 
13731 /*---------------------------------------------------------------------+
13732  | Assign data storage location in x10global.data_storage array for    |
13733  | sensors requiring it.                                               |
13734  +---------------------------------------------------------------------*/
13735 int assign_data_storage ( void )
13736 {
13737    ALIAS         *aliasp;
13738    int           j, index;
13739    char          errmsg[80];
13740 
13741    if ( !(aliasp = configp->aliasp) )
13742       return 0;
13743 
13744    index = 0;
13745    j = 0;
13746    while ( aliasp[j].line_no > 0 ) {
13747       if ( aliasp[j].storage_units == 0 ) {
13748          j++;
13749          continue;
13750       }
13751       if ( index < MAXDATASTORAGE ) {
13752          aliasp[j].storage_index = index;
13753          index += aliasp[j].storage_units;
13754       }
13755       else {
13756          sprintf(errmsg, "Data storage limit exceeded.");
13757          store_error_message(errmsg);
13758          return 1;
13759       }
13760       j++;
13761    }
13762    for ( j = 0; j < index; j++ )
13763       x10global.data_storage[j] = 0;
13764 
13765    return 0;
13766 }
13767 
13768 int c_doit ( int argc, char *argv[] )
13769 {
13770    return 0;
13771 }
13772 
13773 /*---------------------------------------------------------------------+
13774  | Launch a script from the command line.                              |
13775  +---------------------------------------------------------------------*/
13776 int c_launch ( int argc, char *argv[] )
13777 {
13778    LAUNCHER *launcherp;
13779    SCRIPT   *scriptp;
13780    int      j, nl, scriptnum, launchernum;
13781    char     *sp, *scriptlabel;
13782    unsigned char eflag, mode = 0;
13783 
13784 
13785    if ( argc < 3 ) {
13786       printf("Usage: %s %s [-L<n>] [-e] <script_label>\n", argv[0], argv[1]);
13787       printf("  -L<n>  Test only launcher <n> launch conditions\n");
13788       printf("  -e     Test only flags in launch conditions\n");
13789       return 0;
13790    }
13791 
13792    if ( !(launcherp = configp->launcherp) ||
13793         !(scriptp   = configp->scriptp)      ) {
13794       fprintf(stderr, "No scripts are configured.\n");
13795       return 1;
13796    }
13797 
13798    scriptlabel = "";
13799 
13800    launchernum = -1;
13801    eflag = 0;
13802    for ( j = 2; j < argc; j++ ) {
13803       if ( *argv[j] != '-' ) {
13804          scriptlabel = argv[j];
13805          if ( j != (argc - 1) ) {
13806             fprintf(stderr, "Usage: %s %s [-e] [-L<n>] <script_label>\n", argv[0], argv[1]);
13807             return 1;
13808          }
13809          break;
13810       }
13811       else if ( strcmp(argv[j], "-e") == 0 ) {
13812          eflag = 0x80;
13813       }
13814       else if ( strncmp(argv[j], "-L", 2) == 0 ) {
13815          launchernum = -1;
13816          sp = " ";
13817          if ( strlen(argv[j]) > 2 ) {
13818             launchernum = strtol((argv[j] + 2), &sp, 10);
13819          }
13820          if ( *sp || launchernum < 0) {
13821             fprintf(stderr, "Invalid (or missing) launcher number in '%s'\n", argv[j]);
13822             return 1;
13823          }
13824          mode = 1;
13825       }
13826       else {
13827          fprintf(stderr, "Unknown switch '%s'\n", argv[j]);
13828          return 1;
13829       }
13830    }
13831 
13832    j = 0; scriptnum = -1;
13833    while ( launcherp[j].line_no > 0 ) {
13834       if ( strcmp(launcherp[j].label, scriptlabel) == 0 ) {
13835          nl = scriptp[launcherp[j].scriptnum].num_launchers;
13836          if ( launchernum > (nl - 1) ) {
13837             fprintf(stderr, "Launcher number %d outside range 0-%d\n", launchernum, (nl - 1));
13838             return 1;
13839          }
13840          scriptnum = launcherp[j].scriptnum;
13841          break;
13842       }
13843       j++;
13844    }
13845 
13846    if ( scriptnum < 0 ) {
13847       fprintf(stderr, "Script '%s' not found.\n", argv[2]);
13848       return 1;
13849    }
13850 
13851    mode |= eflag;
13852 
13853    send_launch_request(mode, scriptnum, ((launchernum >= 0) ? launchernum : 0));
13854 
13855    return 0;
13856 }
13857 
13858 
13859 /*---------------------------------------------------------------------+
13860  | Test launch conditions against global flags and against the states  |
13861  | Addressed/On/Off/Dim/Changed of the HU addresses (where applicable) |
13862  | If eflag > 0, test only against global flags.                       |
13863  | Return 1 if successful, 0 otherwise.                                |
13864  +---------------------------------------------------------------------*/
13865 int test_launcher ( LAUNCHER *launcherp, unsigned char eflag )
13866 {
13867    unsigned int bitmap, funcmap, chgmask, active;
13868    unsigned char hcode;
13869 
13870    hcode = launcherp->hcode;
13871    if ( launcherp->unitstar )
13872       bitmap = 0xffff;
13873    else
13874       bitmap = launcherp->bmaptrig;
13875 
13876    if ( is_unmatched_flags(launcherp) )
13877       return 0;
13878 
13879    if ( eflag || (launcherp->type & ~(L_NORMAL | L_ADDRESS)) ) {
13880       launcherp->type = L_EXEC;
13881       launcherp->bmaplaunch = 0;
13882       launcherp->actfunc = InvalidFunc;
13883       launcherp->actsource = SNDC;
13884       return 1;
13885    }
13886 
13887    if ( launcherp->type == L_ADDRESS ) {
13888       if ( (active = bitmap & x10state[hcode].addressed) ) {
13889          launcherp->bmaplaunch = active;
13890          launcherp->actsource = SNDC;
13891          return 1;
13892       }
13893       else {
13894          return 0;
13895       }
13896    }
13897 
13898    if ( launcherp->type != L_NORMAL ) {
13899       return 0;
13900    }
13901 
13902    if ( launcherp->chgtrig > 0 )
13903       chgmask = x10state[hcode].state[ChgState];
13904    else
13905       chgmask = 0xffff;
13906 
13907    funcmap = launcherp->afuncmap | launcherp->gfuncmap;
13908    if ( funcmap & (1 << OnTrig)  &&
13909         bitmap &  x10state[hcode].state[OnState] &&
13910         bitmap & chgmask ) {
13911       launcherp->bmaplaunch = bitmap & x10state[hcode].state[OnState];
13912       launcherp->actfunc = OnFunc;
13913    }
13914    else if ( funcmap & (1 << OffTrig) &&
13915         bitmap & ~x10state[hcode].state[OnState] &&
13916         bitmap & chgmask ) {
13917       launcherp->bmaplaunch = bitmap & ~x10state[hcode].state[OnState];
13918       launcherp->actfunc = OffFunc;
13919    }
13920    else if ( funcmap & (1 << DimTrig) &&
13921         bitmap & x10state[hcode].state[DimState] &&
13922         bitmap & chgmask ) {
13923       launcherp->bmaplaunch = bitmap & x10state[hcode].state[DimState];
13924       launcherp->actfunc = DimFunc;
13925    }
13926    else {
13927       return 0;
13928    }
13929 
13930    launcherp->actsource = SNDC;
13931 
13932    return 1;
13933 }
13934 
13935 /*---------------------------------------------------------------------+
13936  | Select launcher(s) to be tested.  Test each one in turn and execute |
13937  | the script for the first one which passes.  (Since the launcher is  |
13938  | modified by the test, we first make a local copy to work with so as |
13939  | not to change the original.)                                        |
13940  | The buffer will have been sent to heyu_engine with the function     |
13941  | send_launch_request()                                               |
13942  +---------------------------------------------------------------------*/
13943 int launch_script_cmd ( unsigned char *buffer )
13944 {
13945    LAUNCHER *launcherpp, *launcherp;
13946    LAUNCHER launchercopy;
13947    unsigned char mode, eflag, save_ctrl;
13948    int j, scriptnum, launchernum, retcode;
13949 
13950    mode = buffer[2] & 0x7f;
13951    eflag = buffer[2] & 0x80;
13952    scriptnum = buffer[3] | (buffer[4] << 8);
13953    launchernum = buffer[5] | (buffer[6] << 8);
13954 
13955    if ( configp->scriptp == NULL || configp->launcherp == NULL ) {
13956       return 1;
13957    }
13958 
13959 
13960    launcherpp = configp->launcherp;
13961 
13962    if ( mode == 0 ) {
13963       /* Check all launchers for the script */
13964       j = 0;
13965       while ( launcherpp[j].line_no > 0 ) {
13966          if ( launcherpp[j].scriptnum == scriptnum ) {
13967             memcpy(&launchercopy, &launcherpp[j], sizeof(LAUNCHER));
13968             launcherp = &launchercopy;
13969             if ( test_launcher(launcherp, eflag) == 1 ) {
13970                save_ctrl = configp->script_ctrl;
13971                configp->script_ctrl = ENABLE;
13972                retcode = exec_script(launcherp);
13973                configp->script_ctrl = save_ctrl;
13974                return retcode;
13975             }
13976          }
13977          j++;
13978       }
13979    }
13980    else {
13981       /* Check only the specified launcher number for the script */
13982       j = 0;
13983       while ( launcherpp[j].line_no > 0 ) {
13984          if ( launcherpp[j].scriptnum == scriptnum &&
13985               launcherpp[j].launchernum == launchernum ) {
13986             memcpy(&launchercopy, &launcherpp[j], sizeof(LAUNCHER));
13987             launcherp = &launchercopy;
13988             if ( test_launcher(launcherp, eflag) == 1 ) {
13989                save_ctrl = configp->script_ctrl;
13990                configp->script_ctrl = ENABLE;
13991                retcode = exec_script(launcherp);
13992                configp->script_ctrl = save_ctrl;
13993                return retcode;
13994             }
13995             else {
13996                return 0;
13997             }
13998          }
13999          j++;
14000       }
14001    }
14002    return 0;
14003 }
14004 
14005 /*---------------------------------------------------------------------+
14006  | Display warnings for security zones in fault, i.e., Door/Window     |
14007  | sensors in Alert status.                                            |
14008  +---------------------------------------------------------------------*/
14009 int warn_zone_faults ( FILE *fp, char *datestr )
14010 {
14011    ALIAS *aliasp;
14012    int   j, retcode = 0;
14013    char  hc;
14014    unsigned char hcode, ucode;
14015 
14016    if ( !(aliasp = configp->aliasp) )
14017       return 0;
14018 
14019    j = 0;
14020    while ( aliasp[j].line_no > 0 ) {
14021       if ( !(aliasp[j].vtype == RF_SEC) || (ucode = single_bmap_unit(aliasp[j].unitbmap)) == 0xff ) {
14022          j++;
14023          continue;
14024       }
14025       hc = aliasp[j].housecode;
14026       hcode = hc2code(hc);
14027       if ( x10state[hcode].vflags[ucode] & SEC_FAULT ) {
14028          fprintf(fp, "%s *** Warning: %c%d (%s) is in Alert mode.\n", datestr, hc, code2unit(ucode), aliasp[j].label);
14029          retcode = 1;
14030       }
14031       j++;
14032    }
14033    return retcode;
14034 }
14035 
14036 /*---------------------------------------------------------------------+
14037  | Display stored data for X10 Security sensors                        |
14038  +---------------------------------------------------------------------*/
14039 int show_x10_security ( void )
14040 {
14041 
14042    ALIAS          *aliasp;
14043    char           hc;
14044    int            unit, index, count = 0, maxlabel = 0, maxmod = 0;
14045    unsigned char  hcode, ucode;
14046    unsigned long  vflags;
14047 
14048    struct xlate_vdata_st xlate_vdata;
14049 
14050    if ( !(aliasp = configp->aliasp) )
14051       return 0;
14052 
14053    /* Get maximum lengths of module name and alias label */
14054    index = 0;
14055    while ( aliasp[index].line_no > 0 ) {
14056       if ( aliasp[index].vtype == RF_SEC && (aliasp[index].optflags & MOPT_SENSOR) ) {
14057          count++;
14058          maxlabel = max(maxlabel, (int)strlen(aliasp[index].label));
14059          maxmod = max(maxmod, (int)strlen(lookup_module_name(aliasp[index].modtype)) );
14060       }
14061       index++;
14062    }
14063 
14064    if ( count == 0 )
14065       return 0;
14066 
14067    index = 0;
14068    while ( aliasp[index].line_no > 0 ) {
14069       if ( aliasp[index].vtype != RF_SEC || !(aliasp[index].optflags & MOPT_SENSOR) ) {
14070          index++;
14071          continue;
14072       }
14073 
14074       ucode = single_bmap_unit(aliasp[index].unitbmap);
14075       unit = code2unit(ucode);
14076       hc = aliasp[index].housecode;
14077       hcode = hc2code(hc);
14078 
14079       if ( x10state[hcode].vflags[ucode] & SEC_AUX ) {
14080          xlate_vdata.vdata = x10state[hcode].memlevel[ucode];
14081       }
14082       else {
14083          xlate_vdata.vdata = x10state[hcode].dimlevel[ucode];
14084       }
14085       xlate_vdata.optflags = aliasp[index].optflags;
14086       xlate_vdata.optflags2 = aliasp[index].optflags2;
14087       xlate_vdata.ident = 0;
14088       xlate_vdata.identp = aliasp[index].ident;
14089       xlate_vdata.nident = aliasp[index].nident;
14090       xlate_vdata.vflags = x10state[hcode].vflags[ucode];
14091 
14092       if ( aliasp[index].xlate_func(&xlate_vdata) != 0 ) {
14093          fprintf(stderr, "Show function error.\n");
14094          fflush(stderr);
14095          return 1;
14096       }
14097 
14098       vflags = xlate_vdata.vflags;
14099 
14100       printf("%c%-2d %-*s %-*s ", hc, unit,
14101           maxmod, lookup_module_name(aliasp[index].modtype),
14102           maxlabel, aliasp[index].label);
14103 
14104       if ( x10state[hcode].timestamp[ucode] == 0 ) {
14105          printf("----\n");
14106          index++;
14107          continue;
14108       }
14109 
14110       printf("%s ", funclabel[xlate_vdata.func]);
14111 
14112       if ( vflags & SEC_MAX )
14113          printf("swMax ");
14114       else if ( vflags & SEC_MIN )
14115          printf("swMin ");
14116 
14117       if ( vflags & SEC_MAIN )
14118          printf("Main ");
14119       else if ( vflags & SEC_AUX )
14120          printf("Aux");
14121 
14122       if ( vflags & SEC_LOBAT )
14123          printf("LoBat ");
14124       printf("\n");
14125 
14126       index++;
14127    }
14128 
14129    return 0;
14130 }
14131 
14132 void display_env_masks ( void )
14133 {
14134    int j;
14135 
14136    printf("\nMasks for Heyu environment\n");
14137    printf("variables X10_Hu and x10_<Hu_alias>\n");
14138    j = 0;
14139    while ( heyumaskval[j].query ) {
14140 //      printf("  $%-10s  0x%08lx  %7lu\n", heyumaskval[j].query, heyumaskval[j].mask, heyumaskval[j].mask);
14141       printf("  $%s\n", heyumaskval[j].query);
14142       j++;
14143    }
14144 
14145    printf("\nMasks for Heyu environment\n");
14146    printf("variables X10_Hu_vFlags and x10_<Hu_alias>_vFlags\n");
14147    j = 0;
14148    while ( heyusecmaskval[j].query ) {
14149 //      printf("  $%-10s  0x%08lx  %7lu\n", heyusecmaskval[j].query, heyusecmaskval[j].mask, heyusecmaskval[j].mask);
14150       printf("  $%s\n", heyusecmaskval[j].query);
14151       j++;
14152    }
14153 
14154    printf("\nMasks for Xtend environment\n");
14155    printf("variables X10_Hu and x10_<Hu_alias>\n");
14156    j = 0;
14157    while ( xtendmaskval[j].query ) {
14158 //      printf("  $%-10s  0x%08lx  %7lu\n", xtendmaskval[j].query, xtendmaskval[j].mask, xtendmaskval[j].mask);
14159       printf("  $%s\n", xtendmaskval[j].query);
14160       j++;
14161    }
14162    printf("\n");
14163 
14164    return;
14165 }
14166 
14167 /*---------------------------------------------------------------------+
14168  | Return the index of an alias having the argument housecode and      |
14169  | unit bitmap, and having a configured module type.                   |
14170  +---------------------------------------------------------------------*/
14171 int locate_alias_module_index ( char housecode, unsigned int unitbmap )
14172 {
14173    ALIAS *aliasp;
14174    int   index;
14175 
14176    if ( !(aliasp = configp->aliasp) )
14177       return -1;
14178 
14179    index = 0;
14180    while ( aliasp[index].line_no > 0 ) {
14181       if ( aliasp[index].housecode == housecode &&
14182            aliasp[index].unitbmap == unitbmap &&
14183            aliasp[index].modtype >= 0 ) {
14184          return index;
14185       }
14186       index++;
14187    }
14188    return -1;
14189 }
14190 
14191 static struct func_type_st {
14192    char          *label;
14193    int           func;
14194 } sec_func_type[] = {
14195   {"panic",        PanicFunc},
14196   {"arm",          ArmFunc},
14197   {"disarm",       DisarmFunc},
14198   {"alert",        AlertFunc},
14199   {"clear",        ClearFunc},
14200   {"test",         TestFunc},
14201   {"sectamper",    TamperFunc},
14202   {"slightson",    SecLightsOnFunc},
14203   {"slightsoff",   SecLightsOffFunc},
14204   {"sdusk",        DuskFunc},
14205   {"sdawn",        DawnFunc},
14206   {"akeyon",       AkeyOnFunc},
14207   {"akeyoff",      AkeyOffFunc},
14208   {"bkeyon",       BkeyOnFunc},
14209   {"bkeyoff",      BkeyOffFunc},
14210   {"inactive",     InactiveFunc},
14211   {"",             0}
14212 };
14213 
14214 static struct local_flags_st {
14215   char *label;
14216   unsigned long flag;
14217 } local_flags[] = {
14218   {"lobat",   SEC_LOBAT},
14219   {"swhome",  SEC_HOME},
14220   {"swaway",  SEC_AWAY},
14221   {"swmin",   SEC_MIN},
14222   {"swmax",   SEC_MAX},
14223   {"main",    SEC_MAIN},
14224   {"aux",     SEC_AUX},
14225   {"",        0}
14226 };
14227 
14228 /*---------------------------------------------------------------------+
14229  | Emulate an X10 Security transmission from the command line.         |
14230  +---------------------------------------------------------------------*/
14231 int c_sec_emu ( int argc, char *argv[] )
14232 {
14233    ALIAS        *aliasp;
14234    char         hc;
14235    unsigned int bitmap;
14236    int          j, k, index, found;
14237    int          func;
14238    unsigned char vdata;
14239    unsigned long ident;
14240    unsigned long vflags;
14241    unsigned int  aflags;
14242    struct xlate_vdata_st xlate_vdata;
14243 
14244    if ( argc < 4 ) {
14245       fprintf(stderr, "Too few parameters.\n");
14246       return 1;
14247    }
14248 
14249    aflags = parse_addr(argv[2], &hc, &bitmap);
14250 
14251    if ( !(aflags & A_VALID) || (aflags & (A_PLUS | A_MINUS | A_MULT)) || bitmap == 0) {
14252       fprintf(stderr, "Invalid Housecode|unit parameter '%s'.\n", argv[2]);
14253       return 1;
14254    }
14255 
14256    index = locate_alias_module_index(hc, bitmap);
14257 
14258    aliasp = configp->aliasp;
14259 
14260    if ( index < 0 || !aliasp ||
14261         aliasp[index].vtype != RF_SEC ||
14262         aliasp[index].xlate_func == NULL ) {
14263       fprintf(stderr, "Security device not found at Hu address.\n");
14264       return 1;
14265    }
14266 
14267    j = 0; found = 0;
14268    while ( *sec_func_type[j].label ) {
14269       if ( strcmp(argv[3], sec_func_type[j].label) == 0 ) {
14270          func = sec_func_type[j].func;
14271          found = 1;
14272          break;
14273       }
14274       j++;
14275    }
14276    if ( !found ) {
14277       fprintf(stderr, "Invalid security function '%s'.\n", argv[3]);
14278       return 1;
14279    }
14280 
14281    vflags = 0;
14282    for ( k = 4; k < argc; k++ ) {
14283       strlower(argv[k]);
14284       j = 0; found = 0;
14285       while ( *local_flags[j].label ) {
14286          if ( strcmp(argv[k], local_flags[j].label) == 0 ) {
14287             vflags |= local_flags[j].flag;
14288             found = 1;
14289             break;
14290          }
14291          j++;
14292       }
14293       if ( !found ) {
14294          fprintf(stderr, "Invalid flag '%s'.\n", argv[k]);
14295          return 1;
14296       }
14297    }
14298 
14299 
14300    xlate_vdata.optflags = aliasp[index].optflags & ~(MOPT_MAIN | MOPT_AUX);
14301    xlate_vdata.optflags2 = aliasp[index].optflags2;
14302    xlate_vdata.nident = aliasp[index].nident;
14303    xlate_vdata.identp = aliasp[index].ident;
14304 
14305    if ( (vflags & SEC_AUX) && (aliasp[index].nident > 1) )
14306       xlate_vdata.ident = xlate_vdata.identp[1] = ident = aliasp[index].ident[1];
14307    else
14308       xlate_vdata.ident = xlate_vdata.identp[0] = ident = aliasp[index].ident[0];
14309 
14310    found = 0; vdata = 0xff;
14311    for ( j = 0; j <= 0xff; j++ ) {
14312       xlate_vdata.vdata = j;
14313       xlate_vdata.vflags = 0;
14314       if ( aliasp[index].xlate_func(&xlate_vdata) != 0 ) {
14315          fprintf(stderr, "Function error.\n");
14316          return 1;
14317       }
14318       if ( func == xlate_vdata.func && vflags == (xlate_vdata.vflags & ~SEC_FAULT) ) {
14319          vdata = j;
14320          found = 1;
14321          break;
14322       }
14323    }
14324    if ( !found ) {
14325       fprintf(stderr, "Function and/or Flag mismatch for module type %s.\n",
14326          lookup_module_name(aliasp[index].modtype));
14327       return 1;
14328    }
14329 
14330    send_virtual_cmd_data(0, vdata, RF_SEC, (ident & 0xffu), ((ident & 0xff00u) >> 8), 0, 0);
14331 
14332    return 0;
14333 }
14334 
14335 /*---------------------------------------------------------------------+
14336  | Parse the flags list and return a long bitmap, with bit 0 = flag 1, |
14337  | bit 1 = flag 2, etc.                                                |
14338  +---------------------------------------------------------------------*/
14339 int flaglist2banks ( unsigned long *flagbank, int banks, char *str )
14340 {
14341 
14342    char           buffer[256];
14343    char           errmsg[80];
14344    char           *tail, *sp;
14345    int            flagmax = 32 * banks;
14346 
14347    unsigned char  flist[32 * banks];
14348    int            j, ustart, flag;
14349 
14350 
14351    for ( j = 0; j < 32 * banks; j++ )
14352       flist[j] = 0;
14353 
14354    for ( j = 0; j < banks; j++ )
14355       flagbank[j] = 0;
14356 
14357    ustart = 0; tail = str;
14358    while ( *(get_token(buffer, &tail, "-,", 255)) ) {
14359       flag = (int)strtol(buffer, &sp, 10);
14360       if ( *sp ) {
14361          sprintf(errmsg, "Invalid char '%c' in flags list.", *sp);
14362          store_error_message(errmsg);
14363          return 1;
14364       }
14365       if ( flag < 1 || flag > flagmax ) {
14366          sprintf(errmsg, "Flag number %d outside range 1-%d.", flag, flagmax);
14367          store_error_message(errmsg);
14368          return 1;
14369       }
14370 
14371       if ( *tail == ',' || *tail == '\0' ) {
14372          if ( ustart ) {
14373             for ( j = ustart; j <= flag; j++ )
14374                flist[j-1] = 1;
14375             ustart = 0;
14376             continue;
14377          }
14378          else {
14379             flist[flag-1] = 1;
14380             continue;
14381          }
14382       }
14383       else {
14384          ustart = flag;
14385       }
14386    }
14387 
14388    for ( j = 0; j < (int)sizeof(flist); j++ ) {
14389       if ( flist[j] )
14390         flagbank[j / 32] |= 1UL << (j % 32);
14391    }
14392 
14393    return 0;
14394 }
14395 
14396 /*---------------------------------------------------------------------+
14397  | Display list of state flags.  Omit display of "not" flags.          |
14398  +---------------------------------------------------------------------*/
14399 int c_stateflaglist ( int argc, char *argv[] )
14400 {
14401    int j;
14402    char buffer[32];
14403 
14404    printf("Hu = Housecode|single_unit or Alias label.\n");
14405    printf("Prefix a flag with \"not\" to negate it.\n");
14406 
14407    for ( j = 0; j < num_stflags; j++ ) {
14408       if ( strncmp(stflags[j].label, "not", 3) == 0 )
14409          continue;
14410       strncpy2(buffer, stflags[j].label, stflags[j].length);
14411       strcat(buffer, "Hu");
14412       printf("%s\n", buffer);
14413    }
14414    for ( j = 0; j < num_virtflags; j++ ) {
14415       if ( strncmp(virtflags[j].label, "not", 3) == 0 )
14416          continue;
14417       strncpy2(buffer, virtflags[j].label, virtflags[j].length);
14418       strcat(buffer, "Hu");
14419       printf("%s\n", buffer);
14420    }
14421    return 0;
14422 }
14423 
14424 int c_masklist ( int argc, char *argv[] )
14425 {
14426    display_env_masks();
14427    return 0;
14428 }
14429 
14430 int get_env_funcmask ( int index, char **query, int *mask )
14431 {
14432    if ( !heyumaskval[index].query )
14433       return -1;
14434 
14435    *query = heyumaskval[index].query;
14436    *mask = heyumaskval[index].mask;
14437 
14438    return 0;
14439 }
14440 
14441 int get_env_flagmask ( int index, char **query, int *mask )
14442 {
14443    if ( !heyusecmaskval[index].query )
14444       return -1;
14445 
14446    *query = heyusecmaskval[index].query;
14447    *mask = heyusecmaskval[index].mask;
14448 
14449    return 0;
14450 }
14451 
14452 
14453 
14454