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(×tamp);
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(×tamp);
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