1
2 /*----------------------------------------------------------------------------+
3 | |
4 | RFXSensor and RFXMeter Support for HEYU |
5 | Copyright 2008 Charles W. Sullivan |
6 | |
7 | |
8 | As used herein, HEYU is a trademark of Daniel B. Suthers. |
9 | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc. |
10 | The author is not affiliated with either entity. |
11 | |
12 | Charles W. Sullivan |
13 | Co-author and Maintainer |
14 | Greensboro, North Carolina |
15 | Email ID: cwsulliv01 |
16 | Email domain: -at- heyu -dot- org |
17 | |
18 +----------------------------------------------------------------------------*/
19
20 /*
21 * This program is free software: you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation, either version 3 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33 *
34 */
35
36
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <syslog.h>
42 #include <ctype.h>
43 #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD)
44 #include <string.h>
45 #else
46 #include <strings.h>
47 #endif
48
49 #include "x10.h"
50 #include "process.h"
51 #include "x10state.h"
52 #include "rfxcom.h"
53
54 extern int sptty;
55 extern int i_am_state, i_am_aux, i_am_relay, i_am_rfxmeter;
56 extern char *funclabel[];
57 extern void create_flagslist ( unsigned char, unsigned long, char * );
58
59 extern CONFIG config;
60 extern CONFIG *configp;
61
62 extern struct x10global_st x10global;
63 extern x10hcode_t *x10state;
64
65 extern unsigned int modmask[NumModMasks][16];
66 extern int lock_for_write(), munlock();
67 extern void update_activity_timeout ( ALIAS *, int );
68
69 /*---------------------------------------------------------------------+
70 | Send the RFXSensor initialization type message to the spool file. |
71 +---------------------------------------------------------------------*/
send_rfxtype_message(char rfxtype,unsigned char code)72 int send_rfxtype_message ( char rfxtype, unsigned char code )
73 {
74 extern int sptty;
75 char writefilename[PATH_LEN + 1];
76
77 int ignoret;
78
79 static unsigned char template[15] = {
80 0xff,0xff,0xff,3,ST_COMMAND,ST_SOURCE,D_AUXRCV,
81 0xff, 0xff, 0xff, 4, ST_COMMAND, ST_RFXTYPE, 0, 0
82 };
83
84 sprintf(writefilename, "%s%s", WRITEFILE, configp->suffix);
85
86 if ( lock_for_write() < 0 ) {
87 syslog(LOG_ERR, "aux unable to lock writefile\n");
88 return 1;
89 }
90
91 template[13] = (rfxtype == 'X') ? (unsigned char)'1' : (unsigned char)rfxtype;
92 template[14] = code;
93
94 ignoret = write(sptty, (char *)template, sizeof(template));
95
96 munlock(writefilename);
97
98 return 0;
99 }
100
101 /*---------------------------------------------------------------------+
102 | Translate the RFXSensor initialization type message. |
103 +---------------------------------------------------------------------*/
translate_rfxtype_message(unsigned char * buf)104 char *translate_rfxtype_message( unsigned char *buf )
105 {
106 static char outbuf[80];
107
108 #ifdef HASRFXS
109 sprintf(outbuf, "RFXSensorXmitter : Type %c, version %d, sample_mode %s",
110 (char)buf[2], buf[3] & 0x7fu, (buf[3] & 0x80u ? "slow" : "fast"));
111 #else
112 sprintf(outbuf, "RFXSensorXmitter : Heyu support not configured.");
113 #endif
114
115 return outbuf;
116 }
117
118
119 /*---------------------------------------------------------------------+
120 | Send the RFXSensor initialization serial message to the spool file. |
121 +---------------------------------------------------------------------*/
send_rfxsensor_ident(unsigned short sensor,unsigned char * serial)122 int send_rfxsensor_ident ( unsigned short sensor, unsigned char *serial )
123 {
124 extern int sptty;
125
126 int ignoret;
127
128 static unsigned char template[14] = {
129 0xff, 0xff, 0xff, 10, ST_COMMAND, ST_RFXSERIAL,
130 0, 0, 0, 0, 0, 0, 0, 0
131 };
132
133 template[6] = (sensor >> 8) & 0xffu;
134 template[7] = sensor & 0xffu;
135 memcpy (template + 8, serial, 6);
136 ignoret = write(sptty, (char *)template, sizeof(template));
137
138 return 0;
139 }
140
141 /*---------------------------------------------------------------------+
142 | | Translate the RFXSensor initialization serial message. |
143 +---------------------------------------------------------------------*/
translate_rfxsensor_ident(unsigned char * buf)144 char *translate_rfxsensor_ident ( unsigned char *buf )
145 {
146 static char outbuf[80];
147 #ifdef HASRFXS
148 unsigned char addr;
149 unsigned char chip;
150 unsigned long serial = 0;
151 int j;
152
153 addr = buf[2];
154 chip = buf[3];
155
156 for ( j = 0; j < 6; j++ ) {
157 serial |= (unsigned long)(buf[j + 4] << (8 * j));
158 }
159
160 sprintf(outbuf, "RFXSensorInit : ID 0x%02X, chip %s, serial_no %lu",
161 addr, ((chip == 0x26) ? "DS2438" : (chip == 0x28) ? "DS18B20" : "???"), serial );
162 #else
163 sprintf(outbuf, "RFXSensorInit : Heyu support not configured.");
164 #endif /* HASRFXS */
165
166 return outbuf;
167 }
168
169
170 #ifdef HASRFXS
171 /*---------------------------------------------------------------------+
172 | Convert RFXSensor temperature short word to scaled double |
173 | temperature. |
174 +---------------------------------------------------------------------*/
rfxdata2temp(unsigned short tdata,double * tempc,double * temperature)175 void rfxdata2temp ( unsigned short tdata, double *tempc, double *temperature)
176 {
177 tdata &= 0xffe0u;
178 if ( tdata & 0x8000u ) {
179 /* Negative temperature */
180 tdata = (~tdata + 1) & 0xffffu;
181 *tempc = -(double)tdata / 256.0;
182 }
183 else {
184 *tempc = (double)tdata / 256.0;
185 }
186
187 switch ( configp->rfx_tscale ) {
188 case 'F' :
189 /* Fahrenheit */
190 *temperature = 1.8 * (*tempc) + 32.0;
191 break;
192 case 'R' :
193 /* Rankine */
194 *temperature = 1.8 * (*tempc) + 32.0 + 459.67;
195 break;
196 case 'K' :
197 /* Kelvin */
198 *temperature = *tempc + 273.15;
199 break;
200 default :
201 /* Celsius */
202 *temperature = *tempc;
203 break;
204 }
205 *temperature += configp->rfx_toffset;
206
207 return;
208 }
209
210 /*---------------------------------------------------------------------+
211 | Convert RFXSensor a/d voltage to scaled double voltage. |
212 +---------------------------------------------------------------------*/
rfxdata2volt(unsigned short vdata,double * vad,double * voltage)213 void rfxdata2volt ( unsigned short vdata, double *vad, double *voltage )
214 {
215 *vad = 0.010 * (double)((vdata & 0xffe0u) >> 5);
216 *voltage = (*vad * configp->rfx_vadscale) + configp->rfx_vadoffset;
217 return;
218 }
219
220 /*---------------------------------------------------------------------+
221 | Convert RFXSensor a/d voltage hdata to double relative humidity. |
222 | The temperature and supply voltage are required for the calculation.|
223 +---------------------------------------------------------------------*/
rfxdata2humi(unsigned short hdata,unsigned short vdata,unsigned short tdata,double * vad,double * rhum)224 void rfxdata2humi ( unsigned short hdata, unsigned short vdata,
225 unsigned short tdata, double *vad, double *rhum )
226 {
227 double tempc, supvolt;
228
229 tdata &= 0xffe0u;
230 if ( tdata & 0x8000u ) {
231 /* Negative temperature */
232 tdata = (~tdata + 1) & 0xffffu;
233 tempc = -(double)tdata / 256.0;
234 }
235 else {
236 tempc = (double)tdata / 256.0;
237 }
238
239 supvolt = 0.010 * (double)((vdata & 0xffe0u) >> 5);
240 *vad = 0.010 * (double)((hdata & 0xffe0u) >> 5);
241 *rhum = (((*vad/supvolt) - 0.16) / 0.0062)/(1.0546 - 0.00216 * tempc);
242 return;
243 }
244
245 /*---------------------------------------------------------------------+
246 | Convert RFXSensor a/d voltage hdata to scaled double barometric |
247 | pressure value. The supply voltage is required for the calculation.|
248 +---------------------------------------------------------------------*/
rfxdata2press(unsigned short hdata,unsigned short vdata,double * vad,double * bpr)249 void rfxdata2press ( unsigned short hdata, unsigned short vdata,
250 double *vad, double *bpr )
251 {
252 double supvolt;
253
254 supvolt = 0.010 * (double)((vdata & 0xffe0u) >> 5);
255 *vad = 0.010 * (double)((hdata & 0xffe0u) >> 5);
256 *bpr = ((*vad/supvolt) + 0.095) / 0.0009;
257 *bpr *= configp->rfx_bpscale;
258 *bpr += configp->rfx_bpoffset;
259 return;
260 }
261
262 /*---------------------------------------------------------------------+
263 | Convert RFXSensor a/d voltage hdata to potentiometer percent value. |
264 | The supply voltage is required for the calculation. |
265 +---------------------------------------------------------------------*/
rfxdata2pot(unsigned short hdata,unsigned short vdata,double * vad,double * pot)266 void rfxdata2pot ( unsigned short hdata, unsigned short vdata, double *vad, double *pot )
267 {
268 double supvolt;
269
270 supvolt = 0.010 * (double)((vdata & 0xffe0u) >> 5);
271 *vad = 0.010 * (double)((hdata & 0xffe0u) >> 5);
272 *pot = 100.0 * (*vad/supvolt);
273 return;
274 }
275
276 #endif /* HASRFXS */
277
278 /*---------------------------------------------------------------------+
279 | Retrieve raw RFXSensor data |
280 +---------------------------------------------------------------------*/
raw_rfxsensor_data(ALIAS * aliasp,int index,unsigned short * tdata,unsigned short * vdata,unsigned short * hdata)281 int raw_rfxsensor_data ( ALIAS *aliasp, int index, unsigned short *tdata,
282 unsigned short *vdata, unsigned short *hdata )
283 {
284 #ifdef HASRFXS
285 unsigned char ident, /* delta, */base, offset /*, offbase */;
286
287 if ( aliasp[index].vtype != RF_XSENSOR ) {
288 return 1;
289 }
290
291 ident = aliasp[index].ident[0];
292 base = ident / 0x20;
293 offset = 0x04 * ((ident % 0x20) / 0x04);
294
295 *tdata = x10global.rfxdata[base][offset + RFX_T];
296 *hdata = x10global.rfxdata[base][offset + RFX_H];
297 *vdata = x10global.rfxdata[base][offset + RFX_S];
298 #else
299 *tdata = *hdata = *vdata = 0; /* Keep some compilers happy */
300 #endif /* HASRFXS */
301
302 return 0;
303 }
304
305
306 /*---------------------------------------------------------------------+
307 | Decode RFXSensor data for transmitter mapped to ALIAS |
308 +---------------------------------------------------------------------*/
decode_rfxsensor_data(ALIAS * aliasp,int index,unsigned int * inmap,unsigned int * outmap,double * tempp,double * vsupp,double * vadp,double * var2p)309 int decode_rfxsensor_data ( ALIAS *aliasp, int index, unsigned int *inmap,
310 unsigned int *outmap, double *tempp, double *vsupp, double *vadp, double *var2p )
311 {
312 #ifdef HASRFXS
313 unsigned short tdata, hdata, vdata;
314 unsigned char ident, /* delta, */ base, offset, /* offbase, */flags, tflag, vflag, hflag;
315 unsigned char hcode, ucode;
316 double tempc, voltage;
317
318 *inmap = *outmap = 0;
319
320 if ( aliasp[index].vtype != RF_XSENSOR ) {
321 return 1;
322 }
323
324 hcode = hc2code(aliasp[index].housecode);
325 ucode = single_bmap_unit(aliasp[index].unitbmap);
326
327 ident = aliasp[index].ident[0];
328 base = ident / 0x20;
329 offset = 0x04 * ((ident % 0x20) / 0x04);
330
331 flags = (unsigned char)(x10global.rfxflags[base] >> offset) & 0x0fu;
332 tflag = (flags >> RFX_T) & 0x01;
333 hflag = (flags >> RFX_H) & 0x01;
334 vflag = (flags >> RFX_S) & 0x01;
335
336 tdata = x10global.rfxdata[base][offset + RFX_T];
337 hdata = x10global.rfxdata[base][offset + RFX_H];
338 vdata = x10global.rfxdata[base][offset + RFX_S];
339
340
341 *inmap |= RFXO_T;
342 if ( aliasp[index].optflags & MOPT_RFXVS )
343 *inmap |= (RFXO_S | RFXO_LO);
344
345 if ( tflag ) {
346 rfxdata2temp(tdata, &tempc, tempp);
347 *outmap |= RFXO_T;
348 }
349
350 if ( hflag ) {
351 rfxdata2volt(hdata, vadp, var2p);
352 *outmap |= RFXO_VI;
353 }
354
355 if ( vflag ) {
356 rfxdata2volt(vdata, vsupp, &voltage);
357 *outmap |= RFXO_S;
358 }
359
360 if ( aliasp[index].optflags & MOPT_RFXRH ) {
361 *inmap |= (RFXO_H | RFXO_VI);
362 if ( tflag && vflag && hflag ) {
363 rfxdata2humi(hdata, vdata, tdata, vadp, var2p);
364 *outmap |= RFXO_H;
365 }
366 }
367 else if ( aliasp[index].optflags & MOPT_RFXBP ) {
368 *inmap |= (RFXO_B | RFXO_VI);
369 if ( vflag && hflag ) {
370 rfxdata2press(hdata, vdata, vadp, var2p);
371 *outmap |= RFXO_B;
372 }
373 }
374 else if ( aliasp[index].optflags & MOPT_RFXVAD ) {
375 *inmap |= (RFXO_V | RFXO_VI);
376 if ( hflag ) {
377 rfxdata2volt(hdata, vadp, var2p);
378 *outmap |= RFXO_V;
379 }
380 }
381 else if ( aliasp[index].optflags & MOPT_RFXPOT ) {
382 *inmap |= (RFXO_P | RFXO_VI);
383 if ( hflag && vflag ) {
384 rfxdata2pot(hdata, vdata, vadp, var2p);
385 *outmap |= RFXO_P;
386 }
387 }
388 else if ( aliasp[index].optflags & MOPT_RFXT2 ) {
389 *inmap |= RFXO_T2;
390 if ( hflag ) {
391 rfxdata2temp(hdata, &tempc, var2p);
392 *outmap |= RFXO_T2;
393 }
394 }
395
396 if ( x10state[hcode].rfxlobat & (1 << ucode) )
397 *outmap |= (*inmap & RFXO_LO);
398
399 #else
400 *inmap = *outmap = 0;
401 *tempp = *vsupp = *vadp = *var2p = 0.0;
402 #endif /* HASRFXS */
403 return 0;
404 }
405
406 #if (defined(HASRFXS) || defined(HASRFXM))
407 /*---------------------------------------------------------------------+
408 | Display a RFXSensor or RFXMeter data value stored in the x10state |
409 | structure. |
410 +---------------------------------------------------------------------*/
c_rfxcmds(int argc,char * argv[])411 int c_rfxcmds ( int argc, char *argv[] )
412 {
413
414 ALIAS *aliasp;
415 unsigned char hcode, ucode, offset, type;
416 unsigned int inmap, outmap, fmap;
417 double temp, vsup, vad, var2;
418 unsigned long aflags, optflag;
419 unsigned long rfxmeter;
420 char hc;
421 unsigned int bitmap;
422 int j, unit, index, panelid;
423 char *display, *sp;
424 unsigned short data, tdata = 0, vdata = 0, hdata = 0;
425 char obuf[60];
426 #ifdef HASRFXM
427 int retcode;
428 #endif
429
430 int read_x10state_file ( void );
431 int powerpanel_query ( unsigned char, unsigned long * );
432
433 static struct {
434 char *rfxcmd;
435 char *display;
436 unsigned char offset;
437 unsigned char panelok;
438 unsigned int fmap;
439 unsigned char type;
440 unsigned long optflag;
441 } cmdlist[] = {
442 {"rfxtemp", "Temp", 0, 0, RFXO_T, RF_XSENSOR, 0 },
443 {"rfxrh", "RH", 1, 0, RFXO_H, RF_XSENSOR, 0 },
444 {"rfxbp", "BP", 1, 0, RFXO_B, RF_XSENSOR, 0 },
445 {"rfxpot", "Pot", 1, 0, RFXO_P, RF_XSENSOR, 0 },
446 {"rfxvs", "Vs", 2, 0, RFXO_S, RF_XSENSOR, 0 },
447 {"rfxvad", "Vad", 1, 0, RFXO_V, RF_XSENSOR, 0 },
448 {"rfxvadi", "Vadi", 1, 0, RFXO_VI, RF_XSENSOR, 0 },
449 {"rfxtemp2", "Temp2", 1, 0, RFXO_T2, RF_XSENSOR, 0 },
450 {"rfxlobat", "LoBat", 2, 0, RFXO_LO, RF_XSENSOR, 0 },
451 {"rfxpower", "Power", 0, 0, 0, RF_XMETER, MOPT_RFXPOWER },
452 {"rfxwater", "Water", 0, 0, 0, RF_XMETER, MOPT_RFXWATER },
453 {"rfxgas", "Gas", 0, 0, 0, RF_XMETER, MOPT_RFXGAS },
454 {"rfxpulse", "Pulse", 0, 0, 0, RF_XMETER, MOPT_RFXPULSE },
455 {"rfxcount", "Counter", 0, 0, 0, RF_XMETER, MOPT_RFXCOUNT },
456 {"rfxpanel", "Panel", 0, 1, 0, RF_XMETER, MOPT_RFXPOWER },
457 {NULL, NULL, 0, 0, 0, 0, 0}
458 };
459
460 if ( argc < 3 && (strcmp(argv[1], "rfxpanel") != 0) ) {
461 fprintf(stderr, "Usage: %s %s Hu\n", argv[0], argv[1]);
462 return 1;
463 }
464
465 if ( check_for_engine() != 0 ) {
466 fprintf(stderr, "State engine is not running.\n");
467 return 1;
468 }
469 if ( read_x10state_file() != 0 ) {
470 fprintf(stderr, "Unable to read state file.\n");
471 return 1;
472 }
473
474 if ( (aliasp = configp->aliasp) == NULL )
475 return 1;
476
477 j = 0;
478 while ( cmdlist[j].rfxcmd != NULL ) {
479 if ( strcmp(argv[1], cmdlist[j].rfxcmd) == 0 )
480 break;
481 j++;
482 }
483 if ( cmdlist[j].rfxcmd == NULL ) {
484 fprintf(stderr, "Invalid command '%s'\n", argv[1]);
485 return 1;
486 }
487 fmap = cmdlist[j].fmap;
488 display = cmdlist[j].display;
489 offset = cmdlist[j].offset;
490 type = cmdlist[j].type;
491 optflag = cmdlist[j].optflag;
492
493 if ( cmdlist[j].panelok ) {
494 if ( argc > 2 ) {
495 panelid = (int)strtol(argv[2], &sp, 10);
496 }
497 else {
498 panelid = 0;
499 sp = " ";
500 }
501 #ifdef HASRFXM
502 if ( strchr(" \t\r\n", *sp) == NULL || panelid < 0 || panelid >= 0xff ) {
503 fprintf(stderr, "Invalid power panel number '%s'\n", argv[2]);
504 return 1;
505 }
506 if ( (retcode = powerpanel_query((unsigned char)panelid, &rfxmeter)) == 0 ) {
507 printf(FMT_RFXPOWER"\n", (double)(rfxmeter) * configp->rfx_powerscale);
508 }
509 else if ( retcode == 1 ) {
510 fprintf(stderr, "Power panel %d does not exist.\n", panelid);
511 return 1;
512 }
513 else if ( retcode == 2 ) {
514 fprintf(stderr, "Power panel %d data not ready.\n", panelid);
515 return 1;
516 }
517 #endif /* HASRFXM */
518 return 0;
519 }
520
521 aflags = parse_addr(argv[2], &hc, &bitmap);
522 if ( !(aflags & A_VALID) || aflags & (A_DUMMY | A_PLUS | A_MINUS) || bitmap == 0 ) {
523 fprintf(stderr, "Invalid Hu address '%s'\n", argv[2]);
524 return 1;
525 }
526 if ( aflags & A_MULT ) {
527 fprintf(stderr, "Only a single unit address is valid.\n");
528 return 1;
529 }
530 hcode = hc2code(hc);
531 ucode = single_bmap_unit(bitmap);
532 unit = code2unit(ucode);
533
534 if ( (index = alias_lookup_index(hc, bitmap, type)) < 0 ) {
535 fprintf(stderr, "Address is not configured as an %s\n",
536 ((type == RF_XSENSOR) ? "RFXSensor" : "RFXMeter") );
537 return 1;
538 }
539
540
541 if ( type == RF_XMETER ) {
542 if ( (optflag & aliasp[index].optflags) == 0 ) {
543 fprintf(stderr, "Address is not configured as an RFX%s meter.\n", display);
544 return 1;
545 }
546 if ( (rfxmeter = x10state[hcode].rfxmeter[ucode]) == 0 ) {
547 printf("Not ready\n");
548 return 1;
549 }
550
551 if ( optflag & MOPT_RFXPOWER ) {
552 printf(FMT_RFXPOWER"\n", (double)(rfxmeter >> 8) * configp->rfx_powerscale);
553 }
554 else if ( (optflag & MOPT_RFXWATER) && *(configp->rfx_waterunits) ) {
555 printf(FMT_RFXWATER"\n", (double)(rfxmeter >> 8) * configp->rfx_waterscale);
556 }
557 else if ( (optflag & MOPT_RFXGAS) && *(configp->rfx_gasunits) ) {
558 printf(FMT_RFXGAS"\n", (double)(rfxmeter >> 8) * configp->rfx_gasscale);
559 }
560 else if ( (optflag & MOPT_RFXPULSE) && *(configp->rfx_pulseunits) ) {
561 printf(FMT_RFXPULSE"\n", (double)(rfxmeter >> 8) * configp->rfx_pulsescale);
562 }
563 else if ( optflag & MOPT_RFXCOUNT ) {
564 printf("%ld\n", (rfxmeter >> 8));
565 }
566 else {
567 printf("%ld\n", (rfxmeter >> 8));
568 }
569 return 0;
570 }
571
572 /* Remainder is for RFXSensors */
573
574 if ( argc > 3 && toupper((int)((unsigned char)(*argv[3]))) == 'R' ) {
575 /* Just display raw stored data and exit */
576 raw_rfxsensor_data(aliasp,index, &tdata, &vdata, &hdata);
577 data = (offset == 0) ? tdata :
578 (offset == 1) ? hdata :
579 (offset == 2) ? vdata : 0xffff ;
580 printf("0x%04x\n", data);
581 return 0;
582 }
583
584 decode_rfxsensor_data(aliasp, index, &inmap, &outmap, &temp, &vsup, &vad, &var2);
585
586 if ( !(inmap & fmap) ) {
587 fprintf(stderr, "%s is not supported by this sensor.\n", display);
588 return 1;
589 }
590 if ( fmap != RFXO_LO && !(outmap & fmap) ) {
591 printf("Data not ready\n");
592 return 1;
593 }
594
595 switch ( fmap ) {
596 case RFXO_T :
597 sprintf(obuf, FMT_RFXT, temp);
598 printf("%s\n", obuf);
599 break;
600 case RFXO_H :
601 sprintf(obuf, FMT_RFXRH, var2);
602 printf("%s\n", obuf);
603 break;
604 case RFXO_B :
605 sprintf(obuf, FMT_RFXBP, var2);
606 printf("%s\n", obuf);
607 break;
608 case RFXO_V :
609 sprintf(obuf, FMT_RFXVAD, var2);
610 printf("%s\n", obuf);
611 break;
612 case RFXO_P :
613 printf("%.2f\n", var2);
614 break;
615 case RFXO_S :
616 printf("%.2f\n", vsup);
617 break;
618 case RFXO_T2 :
619 sprintf(obuf, FMT_RFXT, var2);
620 printf("%s\n", obuf);
621 break;
622 case RFXO_LO :
623 printf("%d\n", ((outmap & RFXO_LO) ? 1 : 0) );
624 break;
625 case RFXO_VI :
626 printf("%.2f\n", vad);
627 break;
628 default :
629 fprintf(stderr, "Internal error c_rfxcmds()\n");
630 return 1;
631 }
632
633 return 0;
634 }
635 #endif /* HASRFXS || HASRFXM */
636
637 #ifdef HASRFXM
638 /*---------------------------------------------------------------------+
639 | Display stored data for all RFXMeters |
640 +---------------------------------------------------------------------*/
show_rfxmeters(void)641 int show_rfxmeters ( void )
642 {
643 ALIAS *aliasp;
644 char hc;
645 int unit, index, count = 0, maxlabel = 0;
646 unsigned char hcode, ucode;
647 unsigned long rfxmeter;
648 int read_x10state_file ( void );
649
650 if ( !(aliasp = configp->aliasp) )
651 return 0;
652
653 /* Get maximum lengths of module name and alias label */
654 index = 0;
655 while ( aliasp[index].line_no > 0 ) {
656 if ( aliasp[index].vtype == RF_XMETER ) {
657 count++;
658 maxlabel = max(maxlabel, (int)strlen(aliasp[index].label));
659 }
660 index++;
661 }
662
663 if ( count == 0 )
664 return 0;
665
666 index = 0;
667 while ( aliasp[index].line_no > 0 ) {
668 if ( aliasp[index].vtype != RF_XMETER ) {
669 index++;
670 continue;
671 }
672 hc = aliasp[index].housecode;
673 hcode = hc2code(hc);
674 ucode = single_bmap_unit(aliasp[index].unitbmap);
675 unit = code2unit(ucode);
676
677 printf("%c%-2d %-*s", hc, unit, maxlabel, aliasp[index].label);
678
679 rfxmeter = x10state[hcode].rfxmeter[ucode];
680
681 if ( aliasp[index].optflags & MOPT_RFXPOWER ) {
682 if ( rfxmeter != 0 ) {
683 printf(" Power "FMT_RFXPOWER" %s, Counter %ld\n",
684 (double)(rfxmeter >> 8) * configp->rfx_powerscale,
685 configp->rfx_powerunits, (rfxmeter >> 8));
686 }
687 else {
688 printf(" Power ---- , Counter ----\n");
689 }
690 }
691 else if ( aliasp[index].optflags & MOPT_RFXWATER ) {
692 if ( rfxmeter != 0 ) {
693 if ( *(configp->rfx_waterunits) ) {
694 printf(" Water "FMT_RFXWATER" %s, Counter %ld\n",
695 (double)(rfxmeter >> 8) * configp->rfx_waterscale,
696 configp->rfx_waterunits, (rfxmeter >> 8));
697 }
698 else {
699 printf(" Water ---- , Counter %ld\n", (rfxmeter >> 8));
700 }
701 }
702 else {
703 printf(" Water ---- , Counter ----\n");
704 }
705 }
706 else if ( aliasp[index].optflags & MOPT_RFXGAS ) {
707 if ( rfxmeter != 0 ) {
708 if ( *(configp->rfx_gasunits) ) {
709 printf(" Gas "FMT_RFXGAS" %s, Counter %ld\n",
710 (double)(rfxmeter >> 8) * configp->rfx_gasscale,
711 configp->rfx_gasunits, (rfxmeter >> 8));
712 }
713 else {
714 printf(" Gas ---- , Counter %ld\n", (rfxmeter >> 8));
715 }
716 }
717 else {
718 printf(" Gas ---- , Counter ----\n");
719 }
720 }
721 else if ( aliasp[index].optflags & MOPT_RFXPULSE ) {
722 if ( rfxmeter != 0 ) {
723 if ( *(configp->rfx_pulseunits) ) {
724 printf(" Pulse "FMT_RFXPULSE" %s, Counter %ld\n",
725 (double)(rfxmeter >> 8) * configp->rfx_pulsescale,
726 configp->rfx_pulseunits, (rfxmeter >> 8));
727 }
728 else {
729 printf(" Pulse ---- , Counter %ld\n", (rfxmeter >> 8));
730 }
731 }
732 else {
733 printf(" Pulse ---- , Counter ----\n");
734 }
735 }
736 else if ( aliasp[index].optflags & MOPT_RFXCOUNT ) {
737 if ( rfxmeter != 0 ) {
738 printf(" Counter %ld\n", (rfxmeter >> 8));
739 }
740 else {
741 printf(" Counter ----\n");
742 }
743 }
744 index++;
745 }
746 return 0;
747 }
748
749 #endif /* HASRFXM */
750
751 #ifdef HASRFXS
752 /*---------------------------------------------------------------------+
753 | Display stored data for all RFXSensors |
754 +---------------------------------------------------------------------*/
show_rfxsensors(void)755 int show_rfxsensors ( void )
756 {
757 ALIAS *aliasp;
758 char hc;
759 int unit, index, count = 0, maxlabel = 0;
760 unsigned int inmap, outmap;
761 double temp, vsup, vad, var2;
762 char valbuf[80];
763 int read_x10state_file ( void );
764
765 if ( !(aliasp = configp->aliasp) )
766 return 0;
767
768 /* Get maximum lengths of module name and alias label */
769 index = 0;
770 while ( aliasp[index].line_no > 0 ) {
771 if ( aliasp[index].vtype == RF_XSENSOR ) {
772 count++;
773 maxlabel = max(maxlabel, (int)strlen(aliasp[index].label));
774 }
775 index++;
776 }
777
778 if ( count == 0 )
779 return 0;
780
781 index = 0;
782 while ( aliasp[index].line_no > 0 ) {
783 if ( aliasp[index].vtype != RF_XSENSOR ) {
784 index++;
785 continue;
786 }
787 unit = code2unit(single_bmap_unit(aliasp[index].unitbmap));
788 hc = aliasp[index].housecode;
789
790 printf("%c%-2d %-*s", hc, unit, maxlabel, aliasp[index].label);
791
792 decode_rfxsensor_data(aliasp, index, &inmap, &outmap, &temp, &vsup, &vad, &var2);
793
794 if ( outmap & RFXO_T ) {
795 sprintf(valbuf, FMT_RFXT, temp);
796 printf(" Temp %s%c", valbuf, configp->rfx_tscale);
797 }
798 else {
799 printf(" Temp ----%c", configp->rfx_tscale);
800 }
801
802 if ( outmap & RFXO_S ) {
803 printf(" Vs %.2fV", vsup);
804 }
805 else if ( inmap & RFXO_S ) {
806 printf(" Vs ----V");
807 }
808 else {
809 printf("\n");
810 index++;
811 continue;
812 }
813
814 if ( outmap & RFXO_H ) {
815 printf(" RH %.2f%%", var2);
816 }
817 else if ( inmap & RFXO_H ) {
818 printf(" RH ----%%");
819 }
820 else if ( outmap & RFXO_B ) {
821 sprintf(valbuf, FMT_RFXBP, var2);
822 printf(" BP %s %s", valbuf, configp->rfx_bpunits);
823 }
824 else if ( inmap & RFXO_B) {
825 printf(" BP ---- %s", configp->rfx_bpunits);
826 }
827 else if ( outmap & RFXO_V ) {
828 sprintf(valbuf, FMT_RFXVAD, var2);
829 printf(" Vad %s %s", valbuf, configp->rfx_vadunits);
830 }
831 else if ( inmap & RFXO_V ) {
832 printf(" Vad ---- %s", configp->rfx_vadunits);
833 }
834 else if ( outmap & RFXO_P ) {
835 printf(" Pot %.2f%%", var2);
836 }
837 else if ( inmap & RFXO_P ) {
838 printf(" Pot ---- %%");
839 }
840 else if ( outmap & RFXO_T2 ) {
841 sprintf(valbuf, FMT_RFXT, var2);
842 printf(" Temp2 %s%c", valbuf, configp->rfx_tscale);
843 }
844 else if ( inmap & RFXO_T2 ) {
845 printf(" Temp2 ----%c", configp->rfx_tscale);
846 }
847
848 printf("\n");
849
850 index++;
851 }
852
853 return 0;
854 }
855
856
857 /*----------------------------------------------------------------------------+
858 | Update the x10state structure per the contents of the argument 'buf' |
859 | for RFXSensor modules. 'buf' contains 6 bytes. The first is the |
860 | standard hcode|ucode byte, the second is the data 0x00-0xff, the third is |
861 | the virtual type, the fourth is the module ID byte, the fifth and sixth |
862 | are the high and low significant raw data bytes. |
863 | |
864 | Only modules of type RF_XSENSOR will be updated. |
865 | |
866 | The received signal and state are tested to see if any of the conditions |
867 | exist for triggering the launching of an external script, and if so, the |
868 | index of the launcher is passed back through argument 'launchp', |
869 | otherwise -1 is passed back. |
870 +----------------------------------------------------------------------------*/
x10state_update_rfxsensor(unsigned char * buf,int len,int * launchp)871 int x10state_update_rfxsensor ( unsigned char *buf, int len, int *launchp )
872 {
873 unsigned char hcode, func, xfunc, ucode, vdata, vtype, hibyte, lobyte;
874 unsigned char actfunc, genfunc, xactfunc;
875 unsigned int bitmap, trigaddr, mask, active, trigactive;
876 unsigned int changestate, startupstate;
877 unsigned long vflags;
878 unsigned int bmaplaunch, launched;
879 unsigned long afuncmap, gfuncmap, xfuncmap;
880 // unsigned short ident;
881 unsigned long ident;
882 struct xlate_vdata_st xlate_vdata;
883 int j, index, trig, base, offset /*, divisor */;
884 char hc;
885 LAUNCHER *launcherp;
886 ALIAS *aliasp;
887 extern unsigned int signal_source;
888 unsigned short rfxdata;
889
890 launcherp = configp->launcherp;
891
892 *launchp = -1;
893
894 aliasp = config.aliasp;
895
896 genfunc = 0;
897 gfuncmap = 0;
898 func = xfunc = VdataFunc;
899 trig = VdataTrig;
900 vflags = 0;
901
902 hcode = (buf[0] & 0xf0u) >> 4;
903 ucode = buf[0] & 0x0fu;
904 vdata = buf[1];
905 vtype = buf[2];
906 ident = buf[3] | (buf[4] << 8);
907 hibyte = buf[5];
908 lobyte = buf[6];
909
910 bitmap = 1 << ucode;
911 hc = code2hc(hcode);
912
913 /* Run the decoding function for the module type, if any */
914 if ( (index = alias_rev_index(hc, bitmap, vtype, ident)) >= 0 &&
915 aliasp[index].modtype >= 0 && aliasp[index].xlate_func != NULL ) {
916 xlate_vdata.vdata = vdata;
917 xlate_vdata.hibyte = hibyte;
918 xlate_vdata.lobyte = lobyte;
919 xlate_vdata.hcode = hcode;
920 xlate_vdata.ucode = ucode;
921 xlate_vdata.ident = ident;
922 xlate_vdata.nident = aliasp[index].nident;
923 xlate_vdata.identp = aliasp[index].ident;
924 xlate_vdata.optflags = aliasp[index].optflags;
925 /* Tamper flag is sticky */
926 xlate_vdata.vflags = x10state[hcode].vflags[ucode] & SEC_TAMPER;
927 if ( aliasp[index].xlate_func(&xlate_vdata) != 0 )
928 return 1;
929 func = xlate_vdata.func;
930 vflags = xlate_vdata.vflags;
931 trig = xlate_vdata.trig;
932 }
933
934 x10state[hcode].vaddress = bitmap;
935 x10state[hcode].lastcmd = func;
936 x10state[hcode].lastunit = code2unit(ucode);
937 x10state[hcode].vident[ucode] = ident;
938 x10state[hcode].vflags[ucode] = vflags;
939 x10state[hcode].timestamp[ucode] = time(NULL);
940 // x10state[hcode].state[ValidState] |= (1 << ucode);
941 // x10state[hcode].state[ChgState] = 0;
942 x10global.lasthc = hcode;
943 x10global.lastaddr = 0;
944 changestate = 0;
945
946 if ( vflags & SEC_LOBAT ) {
947 x10state[hcode].state[LoBatState] |= (1 << ucode);
948 }
949 else {
950 x10state[hcode].state[LoBatState] &= ~(1 << ucode);
951 }
952
953 if ( vdata != x10state[hcode].dimlevel[ucode] ) {
954 // x10state[hcode].state[ChgState] |= bitmap;
955 changestate |= bitmap;
956 x10state[hcode].dimlevel[ucode] = vdata;
957 }
958
959 base = ident / 0x20;
960 offset = ident % 0x20;
961 rfxdata = (hibyte << 8) | lobyte;
962
963 if ( (lobyte & 0x10u) == 0 ) {
964 if ( x10global.rfxdata[base][offset] != rfxdata ) {
965 // x10state[hcode].state[ChgState] |= (1 << ucode);
966 changestate |= (1 << ucode);
967 x10global.rfxdata[base][offset] = rfxdata;
968 }
969 else {
970 // x10state[hcode].state[ChgState] &= ~(1 << ucode);
971 changestate = 0;
972 }
973 x10global.rfxflags[base] |= (1 << offset);
974 if ( (offset % 4) == 2 ) {
975 x10state[hcode].rfxlobat &= ~(1 << ucode);
976 }
977 }
978 else if ( (offset % 4) == 2 && hibyte == 0x02 ) {
979 x10state[hcode].rfxlobat |= (1 << ucode);
980 }
981
982 actfunc = 0;
983 afuncmap = 0;
984 xactfunc = func;
985 xfuncmap = (1 << trig);
986 trigaddr = bitmap;
987
988 mask = modmask[VdataMask][hcode];
989 active = bitmap & mask;
990
991 startupstate = ~x10state[hcode].state[ValidState] & active;
992 x10state[hcode].state[ValidState] |= active;
993
994 update_activity_timeout(aliasp, index);
995 update_activity_states(hcode, active, S_ACTIVE);
996
997
998 // x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
999 x10state[hcode].state[ModChgState] = changestate;
1000
1001 x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
1002 (x10state[hcode].state[ActiveChgState] & active) |
1003 (startupstate & ~modmask[PhysMask][hcode]);
1004
1005 changestate = x10state[hcode].state[ChgState];
1006
1007 if ( i_am_state )
1008 write_x10state_file();
1009
1010 /* Heyuhelper, if applicable */
1011 if ( i_am_state && signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
1012 launch_heyuhelper(hcode, trigaddr, func);
1013 return 0;
1014 }
1015
1016 bmaplaunch = 0;
1017 launched = 0;
1018 j = 0;
1019 while ( launcherp && launcherp[j].line_no > 0 ) {
1020
1021 if ( launcherp[j].type != L_NORMAL ||
1022 launcherp[j].hcode != hcode ||
1023 is_unmatched_flags(&launcherp[j]) ) {
1024 j++;
1025 continue;
1026 }
1027
1028 if ( launcherp[j].xfuncmap & xfuncmap &&
1029 launcherp[j].source & signal_source ) {
1030 trigactive = trigaddr & (mask | launcherp[j].signal);
1031 if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
1032 (changestate | ~launcherp[j].chgtrig)) ||
1033 (launcherp[j].unitstar && !trigaddr)) {
1034 *launchp = j;
1035 launcherp[j].matched = YES;
1036 launcherp[j].actfunc = xactfunc;
1037 launcherp[j].genfunc = 0;
1038 launcherp[j].xfunc = xactfunc;
1039 launcherp[j].level = vdata;
1040 launcherp[j].bmaplaunch = bmaplaunch;
1041 launcherp[j].actsource = signal_source;
1042 launched |= bmaplaunch;
1043 if ( launcherp[j].scanmode & FM_BREAK )
1044 break;
1045 }
1046 }
1047 j++;
1048 }
1049
1050 x10state[hcode].launched = launched;
1051
1052 return 0;
1053 }
1054 #endif /* HASRFXS */
1055
1056 #ifdef HASRFXM
1057 /*----------------------------------------------------------------------------+
1058 | Form the unsigned long RFXMeter word for storage and further processing |
1059 | from the last 4 bytes of the data received by the RFXCOMVL receiver |
1060 | (which have a somewhat unusual arrangement). |
1061 | The "parity" nybble is replaced by 0x1 for use as a flag. |
1062 | The pulse count will be the return value >> 8 |
1063 +----------------------------------------------------------------------------*/
rfxmeter_word(unsigned char byte0,unsigned char byte1,unsigned char byte2,unsigned char byte3)1064 unsigned long rfxmeter_word( unsigned char byte0, unsigned char byte1,
1065 unsigned char byte2, unsigned char byte3 )
1066 {
1067 return (byte2 << 24) | (byte0 << 16) | (byte1 << 8) | (byte3 & 0xf0) | 1;
1068 }
1069
1070 /*----------------------------------------------------------------------------+
1071 | Update the x10state structure per the contents of the argument 'buf' |
1072 | for RFXMeter modules. 'buf' contains 8 bytes. The first is the |
1073 | standard hcode|ucode byte, the second is the data 0x00-0xff, the third is |
1074 | the virtual type, the fourth is the module ID byte, the fifth through |
1075 | eighth are the high through low significant raw data bytes. |
1076 | |
1077 | Only modules of type RF_XMETER will be updated. |
1078 | |
1079 | The received signal and state are tested to see if any of the conditions |
1080 | exist for triggering the launching of an external script, and if so, the |
1081 | index of the launcher is passed back through argument 'launchp', |
1082 | otherwise -1 is passed back. |
1083 | Buffer reference: vtype, seq, id_high, id_low, nbytes, bytes 1-N
1084 +----------------------------------------------------------------------------*/
x10state_update_rfxmeter(unsigned char addr,unsigned char * buf,unsigned char * sunchanged,int * launchp)1085 int x10state_update_rfxmeter ( unsigned char addr, unsigned char *buf, unsigned char *sunchanged, int *launchp )
1086 {
1087 unsigned char hcode, func, xfunc, ucode, vdata, /*ident,*/ vtype, hibyte, lobyte;
1088 // unsigned short ident;
1089 unsigned long ident;
1090 unsigned char actfunc, genfunc, xactfunc;
1091 unsigned int bitmap, trigaddr, mask, active, trigactive, vflags;
1092 unsigned int changestate, startupstate;
1093 unsigned int bmaplaunch, launched;
1094 unsigned long afuncmap, gfuncmap, xfuncmap;
1095 struct xlate_vdata_st xlate_vdata;
1096 int j, index, trig;
1097 char hc;
1098 LAUNCHER *launcherp;
1099 ALIAS *aliasp;
1100 extern unsigned int signal_source;
1101 unsigned long rfxmeter;
1102 unsigned char rfxcode;
1103 unsigned char *vdatap;
1104
1105 launcherp = configp->launcherp;
1106
1107 *launchp = -1;
1108 *sunchanged = 0;
1109
1110 aliasp = config.aliasp;
1111
1112 genfunc = 0;
1113 gfuncmap = 0;
1114 func = xfunc = VdataFunc;
1115 trig = VdataTrig;
1116 vflags = 0;
1117
1118 hcode = (addr & 0xf0u) >> 4;
1119 ucode = addr & 0x0fu;
1120 vtype = buf[0];
1121 // ident = (unsigned short)buf[3];
1122 ident = buf[3];
1123 vdatap = buf + 7;
1124 vdata = 0;
1125
1126 hibyte = buf[5];
1127 lobyte = buf[6];
1128
1129 bitmap = 1 << ucode;
1130 hc = code2hc(hcode);
1131
1132 /* Run the decoding function for the module type, if any */
1133 if ( (index = alias_rev_index(hc, bitmap, vtype, ident)) >= 0 &&
1134 aliasp[index].modtype >= 0 && aliasp[index].xlate_func != NULL ) {
1135 xlate_vdata.vdata = vdata;
1136 xlate_vdata.hibyte = hibyte;
1137 xlate_vdata.lobyte = lobyte;
1138 xlate_vdata.hcode = hcode;
1139 xlate_vdata.ucode = ucode;
1140 xlate_vdata.ident = ident;
1141 xlate_vdata.nident = aliasp[index].nident;
1142 xlate_vdata.identp = aliasp[index].ident;
1143 xlate_vdata.optflags = aliasp[index].optflags;
1144 /* Tamper flag is sticky */
1145 xlate_vdata.vflags = x10state[hcode].vflags[ucode] & SEC_TAMPER;
1146 if ( aliasp[index].xlate_func(&xlate_vdata) != 0 )
1147 return 1;
1148
1149 func = xlate_vdata.func;
1150 vflags = xlate_vdata.vflags;
1151 trig = xlate_vdata.trig;
1152 }
1153
1154 x10state[hcode].vaddress = bitmap;
1155 x10state[hcode].lastcmd = func;
1156 x10state[hcode].lastunit = code2unit(ucode);
1157 x10state[hcode].vident[ucode] = ident;
1158 x10state[hcode].vflags[ucode] = vflags;
1159 x10state[hcode].timestamp[ucode] = time(NULL);
1160 // x10state[hcode].state[ValidState] |= (1 << ucode);
1161 // x10state[hcode].state[ChgState] = 0;
1162 x10global.lasthc = hcode;
1163 x10global.lastaddr = 0;
1164 changestate = 0;
1165
1166 if ( vflags & SEC_LOBAT ) {
1167 x10state[hcode].state[LoBatState] |= (1 << ucode);
1168 }
1169 else {
1170 x10state[hcode].state[LoBatState] &= ~(1 << ucode);
1171 }
1172
1173 rfxmeter = rfxmeter_word(vdatap[0], vdatap[1], vdatap[2], vdatap[3]);
1174
1175 rfxcode = rfxmeter & 0xf0;
1176
1177 /* Replace the superfluous parity field (lowest nybble) by 1 as a flag */
1178 rfxmeter = (rfxmeter & 0xfffffff0) | 0x01;
1179
1180 if ( rfxcode == 0 ) {
1181 if ( rfxmeter != x10state[hcode].rfxmeter[ucode] ) {
1182 // x10state[hcode].state[ChgState] |= bitmap;
1183 changestate |= bitmap;
1184 }
1185 else {
1186 // x10state[hcode].state[ChgState] &= ~bitmap;
1187 changestate &= ~bitmap;
1188 }
1189
1190 if ( (rfxmeter & 0xFFFFFF00) < (x10state[hcode].rfxmeter[ucode] & 0xFFFFFF00) ) {
1191 x10state[hcode].vflags[ucode] |= RFX_ROLLOVER;
1192 // changestate |= bitmap;
1193 }
1194 x10state[hcode].rfxmeter[ucode] = rfxmeter;
1195 }
1196 else {
1197 return 0;
1198 }
1199
1200 actfunc = 0;
1201 afuncmap = 0;
1202 xactfunc = func;
1203 xfuncmap = (1 << trig);
1204 trigaddr = bitmap;
1205
1206 mask = modmask[VdataMask][hcode];
1207 active = bitmap & mask;
1208
1209 startupstate = ~x10state[hcode].state[ValidState] & active;
1210 x10state[hcode].state[ValidState] |= active;
1211
1212 update_activity_timeout(aliasp, index);
1213 update_activity_states(hcode, active, S_ACTIVE);
1214
1215 // x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
1216 x10state[hcode].state[ModChgState] = changestate;
1217
1218 x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
1219 (x10state[hcode].state[ActiveChgState] & active) |
1220 (startupstate & ~modmask[PhysMask][hcode]);
1221
1222 changestate = x10state[hcode].state[ChgState];
1223
1224 *sunchanged = (changestate & active) ? 0 : 1;
1225
1226 if ( i_am_state )
1227 write_x10state_file();
1228
1229 /* Heyuhelper, if applicable */
1230 if ( i_am_state && signal_source & RCVI && configp->script_mode & HEYU_HELPER ) {
1231 launch_heyuhelper(hcode, trigaddr, func);
1232 return 0;
1233 }
1234
1235 bmaplaunch = 0;
1236 launched = 0;
1237 j = 0;
1238 while ( launcherp && launcherp[j].line_no > 0 ) {
1239 if ( launcherp[j].type != L_NORMAL ||
1240 launcherp[j].hcode != hcode ||
1241 is_unmatched_flags(&launcherp[j]) ||
1242 (launcherp[j].vflags & x10state[hcode].vflags[ucode]) != launcherp[j].vflags ||
1243 (launcherp[j].notvflags & ~x10state[hcode].vflags[ucode]) != launcherp[j].notvflags ) {
1244 j++;
1245 continue;
1246 }
1247
1248 if ( launcherp[j].xfuncmap & xfuncmap &&
1249 launcherp[j].source & signal_source ) {
1250 trigactive = trigaddr & (mask | launcherp[j].signal);
1251 if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
1252 (changestate | ~launcherp[j].chgtrig)) ||
1253 (launcherp[j].unitstar && !trigaddr)) {
1254 *launchp = j;
1255 launcherp[j].matched = YES;
1256 launcherp[j].actfunc = xactfunc;
1257 launcherp[j].genfunc = 0;
1258 launcherp[j].xfunc = xactfunc;
1259 launcherp[j].level = vdata;
1260 launcherp[j].bmaplaunch = bmaplaunch;
1261 launcherp[j].actsource = signal_source;
1262 launched |= bmaplaunch;
1263 if ( launcherp[j].scanmode & FM_BREAK )
1264 break;
1265 }
1266 }
1267 j++;
1268 }
1269
1270 x10state[hcode].launched = launched;
1271
1272 return 0;
1273 }
1274
1275 /*----------------------------------------------------------------------------+
1276 | Translate RFXMeter messages for codes other than 0 |
1277 | Reference: RFXCOM RFreceiver program. |
1278 +----------------------------------------------------------------------------*/
translate_rfxmeter_code(unsigned short vident,unsigned long rfxdata)1279 char *translate_rfxmeter_code ( unsigned short vident, unsigned long rfxdata )
1280 {
1281 unsigned char code, subcode, intv;
1282
1283 static char outbuf[80];
1284 unsigned char recbuf[6];
1285 double calib, dmeasured;
1286 unsigned long measured;
1287
1288 /* Reconstruct original bytes (excluding ident bytes) */
1289 recbuf[0] = recbuf[1] = 0;
1290 recbuf[2] = (rfxdata & 0xFF0000) >> 16;
1291 recbuf[3] = (rfxdata & 0xFF00) >> 8;
1292 recbuf[4] = (rfxdata & 0xFF000000) >> 24;
1293 recbuf[5] = rfxdata & 0xFF;
1294
1295 code = recbuf[5] & 0xF0;
1296 outbuf[0] = '\0';
1297
1298 switch ( code ) {
1299 case 0x00 :
1300 sprintf(outbuf, "RFXMeter ID %02X, Counter %ld", vident, (rfxdata >> 8));
1301 break;
1302 case 0x10 :
1303 intv = recbuf[2];
1304 sprintf(outbuf, "Interval %s ",
1305 ((intv == 0x01) ? "30 sec" :
1306 (intv == 0x02) ? "1 min" :
1307 (intv == 0x04) ? "6 min" :
1308 (intv == 0x08) ? "12 min" :
1309 (intv == 0x10) ? "15 min" :
1310 (intv == 0x20) ? "30 min" :
1311 (intv == 0x40) ? "45 min" :
1312 (intv == 0x80) ? "60 min" : "???"));
1313 break;
1314 case 0x20 :
1315 switch ( recbuf[4] & 0xC0 ) {
1316 case 0x00 :
1317 sprintf(outbuf, "Input-0 ");
1318 break;
1319 case 0x40 :
1320 sprintf(outbuf, "Input-1 ");
1321 break;
1322 case 0x80 :
1323 sprintf(outbuf, "Input-2 ");
1324 break;
1325 default :
1326 sprintf(outbuf, "Unknown input ");
1327 break;
1328 }
1329 dmeasured = (double)(((recbuf[4] & 0x3F) << 16) | (recbuf[2] << 8) | recbuf[3]) / 1000.;
1330 sprintf(outbuf + strlen(outbuf), "Calibration: %.3f msec", dmeasured);
1331 if ( dmeasured != 0 ) {
1332 #if 0
1333 calib = 1.0 / ( (16. * dmeasured) / (3600000. / 100.) );
1334 sprintf(outbuf + strlen(outbuf), "RFXPower= %.3f kW ", calib);
1335 #endif /* Old RFXPower module */
1336
1337 calib = 1.0 / ( (16. * dmeasured) / (3600000. / 62.5) );
1338 sprintf(outbuf + strlen(outbuf), ", RFXPwr= %.3f kW", calib);
1339 #if 0
1340 calib *= 1.917;
1341 sprintf(outbuf + strlen(outbuf), "|%.3f kW", calib);
1342 #endif /* Old RFXPOWER module */
1343
1344 }
1345 break;
1346 case 0x30 :
1347 sprintf(outbuf, "New address ID %02X set", vident);
1348 break;
1349 case 0x40 :
1350 subcode = recbuf[4] & 0xC0;
1351 sprintf(outbuf, "Push MODE button to skip resetting %s counter to 0",
1352 ((subcode == 0x00) ? "Input-0" :
1353 (subcode == 0x40) ? "Input-1" :
1354 (subcode == 0x80) ? "Input-2" : "Error"));
1355 break;
1356 case 0x50 :
1357 measured = ((recbuf[2] >> 4) * 100000) + ((recbuf[2] & 0xF) * 10000) +
1358 ((recbuf[3] >> 4) * 1000) + ((recbuf[3] & 0xF) * 100) +
1359 ((recbuf[4] >> 4) * 10) + (recbuf[4] & 0xF);
1360 sprintf(outbuf, "Push MODE button to increment 1st digit of counter %05ld", measured);
1361 break;
1362 case 0x60 :
1363 measured = ((recbuf[2] >> 4) * 100000) + ((recbuf[2] & 0xF) * 10000) +
1364 ((recbuf[3] >> 4) * 1000) + ((recbuf[3] & 0xF) * 100) +
1365 ((recbuf[4] >> 4) * 10) + (recbuf[4] & 0xF);
1366 sprintf(outbuf, "Push MODE button to increment 2nd digit of counter %05ld", measured);
1367 break;
1368 case 0x70 :
1369 measured = ((recbuf[2] >> 4) * 100000) + ((recbuf[2] & 0xF) * 10000) +
1370 ((recbuf[3] >> 4) * 1000) + ((recbuf[3] & 0xF) * 100) +
1371 ((recbuf[4] >> 4) * 10) + (recbuf[4] & 0xF);
1372 sprintf(outbuf, "Push MODE button to increment 3rd digit of counter %05ld", measured);
1373 break;
1374 case 0x80 :
1375 measured = ((recbuf[2] >> 4) * 100000) + ((recbuf[2] & 0xF) * 10000) +
1376 ((recbuf[3] >> 4) * 1000) + ((recbuf[3] & 0xF) * 100) +
1377 ((recbuf[4] >> 4) * 10) + (recbuf[4] & 0xF);
1378 sprintf(outbuf, "Push MODE button to increment 4th digit of counter %05ld", measured);
1379 break;
1380 case 0x90 :
1381 measured = ((recbuf[2] >> 4) * 100000) + ((recbuf[2] & 0xF) * 10000) +
1382 ((recbuf[3] >> 4) * 1000) + ((recbuf[3] & 0xF) * 100) +
1383 ((recbuf[4] >> 4) * 10) + (recbuf[4] & 0xF);
1384 sprintf(outbuf, "Push MODE button to increment 5th digit of counter %05ld", measured);
1385 break;
1386 case 0xA0 :
1387 measured = ((recbuf[2] >> 4) * 100000) + ((recbuf[2] & 0xF) * 10000) +
1388 ((recbuf[3] >> 4) * 1000) + ((recbuf[3] & 0xF) * 100) +
1389 ((recbuf[4] >> 4) * 10) + (recbuf[4] & 0xF);
1390 sprintf(outbuf, "Push MODE button to increment 6th digit of counter %05ld", measured);
1391 break;
1392 case 0xB0 :
1393 subcode = recbuf[4];
1394 sprintf(outbuf, "Counter for %s has been reset to zero",
1395 ((subcode == 0x00) ? "Input-0" :
1396 (subcode == 0x40) ? "Input-1" :
1397 (subcode == 0x80) ? "Input-2" : "???"));
1398 break;
1399 case 0xC0 :
1400 sprintf(outbuf, "Push MODE button to skip SET INTERVAL RATE");
1401 break;
1402 case 0xD0 :
1403 subcode = recbuf[4] & 0xC0;
1404 sprintf(outbuf, "Push MODE button to skip CALIBRATION of %s",
1405 ((subcode == 0x00) ? "Input-0" :
1406 (subcode == 0x40) ? "Input-1" :
1407 (subcode == 0x80) ? "Input-2" : "???"));
1408 break;
1409 case 0xE0 :
1410 sprintf(outbuf, "Push MODE button to skip SET ADDRESS");
1411 break;
1412 case 0xF0 :
1413 sprintf(outbuf, "%s ",
1414 ((recbuf[2] < 0x40) ? "RFXPower " :
1415 (recbuf[2] < 0x80) ? "RFXWater " :
1416 (recbuf[2] < 0xC0) ? "RFXGas " : "RFXMeter "));
1417 sprintf(outbuf + strlen(outbuf), "firmware 0x%02X, ", recbuf[2]);
1418 intv = recbuf[3];
1419 sprintf(outbuf + strlen(outbuf), "Interval %s ",
1420 ((intv == 0x01) ? "30 sec" :
1421 (intv == 0x02) ? "1 min" :
1422 (intv == 0x04) ? "6 min" :
1423 (intv == 0x08) ? "12 min" :
1424 (intv == 0x10) ? "15 min" :
1425 (intv == 0x20) ? "30 min" :
1426 (intv == 0x40) ? "45 min" :
1427 (intv == 0x80) ? "60 min" : "???"));
1428 break;
1429 default :
1430 sprintf(outbuf, "Invalid RFXMeter message code %02X", code);
1431 break;
1432 }
1433
1434 return outbuf;
1435 }
1436
1437 #define MAX_PANEL_PHASES 3
1438
1439 static struct phaselist_st {
1440 unsigned char panel;
1441 unsigned char size;
1442 unsigned char ident;
1443 unsigned char hcode;
1444 unsigned char ucode;
1445 } phaselist[80 /* MAX_RFX_SENSORS */];
1446 static int nphases;
1447
1448 int npowerpanels;
1449
1450 /*----------------------------------------------------------------------------+
1451 | Comparison function for qsort(). |
1452 +----------------------------------------------------------------------------*/
cmp_phase_ids(const void * phase1,const void * phase2)1453 int cmp_phase_ids( const void *phase1, const void *phase2 )
1454 {
1455 struct phaselist_st *one = (struct phaselist_st *)phase1;
1456 struct phaselist_st *two = (struct phaselist_st *)phase2;
1457
1458 return (two->ident < one->ident) ? -1 :
1459 (two->ident > one->ident) ? 1 : 0;
1460 }
1461
1462 /*----------------------------------------------------------------------------+
1463 | Create a table of RFXPower addresses grouped in "power panels" of two or |
1464 | three phases of a multiphase AC power system. |
1465 +----------------------------------------------------------------------------*/
create_rfxpower_panels(void)1466 void create_rfxpower_panels ( void )
1467 {
1468 ALIAS *aliasp;
1469 int j, k;
1470 unsigned char identprev, size, panelid;
1471
1472 npowerpanels = 0;
1473 nphases = 0;
1474
1475 if ( (aliasp = configp->aliasp) == NULL ) {
1476 return;
1477 }
1478
1479 j = 0;
1480 nphases = 1;
1481 while ( aliasp[j].line_no > 0 && nphases < (int)(sizeof(phaselist)/sizeof(struct phaselist_st)) ) {
1482 if ( aliasp[j].optflags & MOPT_RFXPOWER ) {
1483 phaselist[nphases].panel = 0xff;
1484 phaselist[nphases].size = 1;
1485 phaselist[nphases].hcode = hc2code(aliasp[j].housecode);
1486 phaselist[nphases].ucode = single_bmap_unit(aliasp[j].unitbmap);
1487 phaselist[nphases++].ident = aliasp[j].ident[0];
1488 }
1489 j++;
1490 }
1491
1492 if ( nphases == 1 ) {
1493 nphases = 0;
1494 return;
1495 }
1496
1497 /* Sort phaselist in descending order of idents */
1498 qsort(phaselist + 1, nphases - 1, sizeof(struct phaselist_st), cmp_phase_ids);
1499
1500 phaselist[0].ident = phaselist[1].ident;
1501 phaselist[0].size = phaselist[1].size;
1502
1503 /* Create groups of phases which have consecutive IDs */
1504 identprev = phaselist[nphases - 1].ident;
1505 j = nphases - 1;
1506 while ( j > 0 ) {
1507 k = j - 1;
1508 while ( k >= 0 ) {
1509 if ( phaselist[k].ident == (identprev + 1) && phaselist[j].size < MAX_PANEL_PHASES) {
1510 ++phaselist[j].size;
1511 identprev = phaselist[k].ident;
1512 k--;
1513 }
1514 else {
1515 identprev = phaselist[k].ident;
1516 j = k;
1517 break;
1518 }
1519 }
1520 }
1521
1522 nphases--;
1523 memmove(phaselist, phaselist + 1, nphases * sizeof(struct phaselist_st) );
1524
1525 for ( j = 0; j < nphases; j++ ) {
1526 if ( (size = phaselist[j].size) > 1 ) {
1527 phaselist[j - size + 1].size = size;
1528 phaselist[j].size = 1;
1529 }
1530 }
1531
1532
1533 /* Assign an ID to each panel */
1534 panelid = 0;
1535 npowerpanels = 0;
1536 for ( j = nphases - 1; j >= 0; j-- ) {
1537 if ( phaselist[j].size > 1 )
1538 phaselist[j].panel = panelid++;
1539 }
1540 npowerpanels = panelid;
1541
1542 return;
1543 }
1544
1545 /*----------------------------------------------------------------------------+
1546 | Pass back the power panel ID and total power usage for RFXPower sensors |
1547 | in multiphase AC power systems when the argument ident corresponds to the |
1548 | highest ident in a panel group and return 0. Otherwise return 1. |
1549 +----------------------------------------------------------------------------*/
powerpanel_total(unsigned char ident,int * panelid,unsigned long * rfxpower)1550 int powerpanel_total ( unsigned char ident, int *panelid, unsigned long *rfxpower )
1551 {
1552 int j, k;
1553 unsigned long rfxmeter;
1554
1555 for ( j = 0; j < nphases; j++ ) {
1556 if ( phaselist[j].ident == ident ) {
1557 if ( phaselist[j].size < 2 )
1558 return 1;
1559 *panelid = phaselist[j].panel;
1560 *rfxpower = 0;
1561 for ( k = 0; k < phaselist[j].size; k++ ) {
1562 rfxmeter = x10state[phaselist[j + k].hcode].rfxmeter[phaselist[j + k].ucode];
1563 if ( rfxmeter & 0x01 )
1564 *rfxpower += (rfxmeter >> 8);
1565 else
1566 return 2;
1567 }
1568 break;
1569 }
1570 }
1571 return 0;
1572 }
1573
1574 /*----------------------------------------------------------------------------+
1575 | Pass back the total multiphase power usage for power panel 'panelid'. |
1576 | Return 1 if valid panelid does not exist, or 0 otherwise. |
1577 +----------------------------------------------------------------------------*/
powerpanel_query(unsigned char panelid,unsigned long * rfxpower)1578 int powerpanel_query ( unsigned char panelid, unsigned long *rfxpower )
1579 {
1580 int j, k;
1581 unsigned long rfxmeter;
1582
1583 *rfxpower = 0;
1584
1585 if ( nphases == 0 || panelid == 0xff ) {
1586 return 1;
1587 }
1588
1589 for ( j = 0; j < nphases; j++ ) {
1590 if ( phaselist[j].panel == panelid ) {
1591 for ( k = 0; k < phaselist[j].size; k++ ) {
1592 rfxmeter = x10state[phaselist[j + k].hcode].rfxmeter[phaselist[j + k].ucode];
1593 if ( rfxmeter & 0x01 )
1594 *rfxpower += (rfxmeter >> 8);
1595 else
1596 return 2;
1597 }
1598 return 0;
1599 }
1600 }
1601 return 1;
1602 }
1603
1604 #endif /* HASRFXM */
1605
1606 /*------------------------------------------------------------------------+
1607 | Interpret Virtual data string, update the state, and test whether |
1608 | any launch condition is satisfied. |
1609 | buffer references: |
1610 | ST_COMMAND, ST_LONGVDATA, vtype, seq, vidhi, vidlo, nbytes, bytes 1-N |
1611 +------------------------------------------------------------------------*/
translate_rfxmeter(unsigned char * buf,unsigned char * sunchanged,int * launchp)1612 char *translate_rfxmeter ( unsigned char *buf, unsigned char *sunchanged, int *launchp )
1613 {
1614 static char outbuf[160];
1615 #ifdef HASRFXM
1616 char flagslist[80];
1617 ALIAS *aliasp;
1618 unsigned char func, *vdatap, vtype, seq;
1619 unsigned short vident;
1620
1621 static char *typename[] = {"Std", "Ent", "Sec", "RFXSensor", "RFXMeter", "?", "??", "???", "????", "Digimax", "Noise", "Noise2"};
1622 char hc;
1623 int j, k, found, index = -1, panelid;
1624 unsigned char hcode, ucode, addr, rfxcode, unit;
1625 unsigned int bitmap, vflags = 0;
1626 unsigned char *inbuf;
1627 unsigned long counter, longvdata, rfxpower;
1628 double rfxmeterdbl;
1629 char *roll;
1630 extern int x10state_update_rfxmeter ( unsigned char, unsigned char *, unsigned char *, int * );
1631 extern unsigned long rfxmeter_word ( unsigned char, unsigned char,
1632 unsigned char, unsigned char );
1633 char *translate_rfxmeter_code ( unsigned short, unsigned long );
1634 int powerpanel_total ( unsigned char, int *, unsigned long * );
1635 extern int rfxmeter_checksum ( unsigned char * );
1636
1637 *launchp = -1;
1638 *sunchanged = 0;
1639 flagslist[0] = '\0';
1640 *outbuf = '\0';
1641
1642 aliasp = config.aliasp;
1643
1644 inbuf = buf + 7; /* Original data including two ID bytes */
1645 vtype = buf[2];
1646 seq = buf[3];
1647 vident = (buf[4] << 8) | buf[5];
1648 vdatap = buf + 9;
1649 func = VdataFunc;
1650
1651 x10global.longvdata = 0;
1652 x10global.lastvtype = vtype;
1653
1654 if ( vtype == RF_XMETER ) {
1655 /* Re-verify RFXMeter checksum in case of spoolfile corruption */
1656 if ( rfxmeter_checksum(inbuf) != 0 ) {
1657 sprintf(outbuf, " Error : Corrupted RFXM buffer: 0x%02X%02X%02X%02X%02X%02X",
1658 inbuf[0], inbuf[1], inbuf[2], inbuf[3], inbuf[4], inbuf[5]);
1659 *sunchanged = 0;
1660 *launchp = -1;
1661 return outbuf;
1662 };
1663
1664 if ( i_am_rfxmeter ) {
1665 longvdata = rfxmeter_word(vdatap[0], vdatap[1], vdatap[2], vdatap[3]);
1666 return translate_rfxmeter_code ( vident, longvdata );
1667 }
1668
1669 hcode = ucode = 0;
1670 found = 0;
1671 j = 0;
1672 /* Look up the alias, if any */
1673 while ( !found && aliasp && aliasp[j].line_no > 0 ) {
1674 if ( aliasp[j].vtype == vtype &&
1675 (bitmap = aliasp[j].unitbmap) > 0 &&
1676 (ucode = single_bmap_unit(bitmap)) != 0xff ) {
1677 for ( k = 0; k < aliasp[j].nident; k++ ) {
1678 if ( aliasp[j].ident[k] == vident ) {
1679 index = j;
1680 found = 1;
1681 break;
1682 }
1683 }
1684 }
1685 j++;
1686 }
1687
1688 if ( !found || !aliasp ) {
1689 sprintf(outbuf, "func %12s : Type %s ID 0x%02X Data 0x%02X%02X%02X%02X",
1690 "RFdata", typename[vtype], vident, vdatap[0], vdatap[1], vdatap[2], vdatap[3]);
1691 return outbuf;
1692 }
1693
1694 x10global.longvdata = rfxmeter_word(vdatap[0], vdatap[1], vdatap[2], vdatap[3]);
1695
1696 hc = aliasp[index].housecode;
1697 hcode = hc2code(hc);
1698 unit = code2unit(ucode);
1699
1700 /* Add address and update the state */
1701 addr = (hcode & 0x0fu) << 4 | (ucode & 0x0fu);
1702 if ( x10state_update_rfxmeter(addr, buf + 2, sunchanged, launchp) != 0 )
1703 return "";
1704
1705 func = x10state[hcode].lastcmd;
1706 vflags = x10state[hcode].vflags[ucode];
1707 create_flagslist(vtype, vflags, flagslist);
1708
1709 roll = (vflags & RFX_ROLLOVER) ? "rollover " : "";
1710
1711 rfxcode = vdatap[3] >> 4;
1712
1713 if ( rfxcode == 0 ) {
1714 counter = x10global.longvdata >> 8;
1715 if ( func == RFXPowerFunc && *(configp->rfx_powerunits) ) {
1716 rfxmeterdbl = (double)counter * configp->rfx_powerscale;
1717 sprintf(outbuf, "func %12s : hu %c%-2d Meter "FMT_RFXPOWER" %s %s(%s)",
1718 funclabel[func], hc, unit, rfxmeterdbl, configp->rfx_powerunits, roll, aliasp[index].label);
1719 if ( powerpanel_total(vident, &panelid, &rfxpower) == 0 ) {
1720 rfxmeterdbl = (double)rfxpower * configp->rfx_powerscale;
1721 sprintf(outbuf + strlen(outbuf),
1722 "\nPanel %d total = "FMT_RFXPOWER" %s", panelid, rfxmeterdbl, configp->rfx_powerunits);
1723 }
1724 }
1725 else if ( func == RFXWaterFunc && *(configp->rfx_waterunits) ) {
1726 rfxmeterdbl = (double)counter * configp->rfx_waterscale;
1727 sprintf(outbuf, "func %12s : hu %c%-2d Meter "FMT_RFXWATER" %s %s(%s)",
1728 funclabel[func], hc, unit, rfxmeterdbl, configp->rfx_waterunits, roll, aliasp[index].label);
1729 }
1730 else if ( func == RFXGasFunc && *(configp->rfx_gasunits) ) {
1731 rfxmeterdbl = (double)counter * configp->rfx_gasscale;
1732 sprintf(outbuf, "func %12s : hu %c%-2d Meter "FMT_RFXGAS" %s %s(%s)",
1733 funclabel[func], hc, unit, rfxmeterdbl, configp->rfx_gasunits, roll, aliasp[index].label);
1734 }
1735 else if ( func == RFXPulseFunc && *(configp->rfx_pulseunits) ) {
1736 rfxmeterdbl = (double)counter * configp->rfx_pulsescale;
1737 sprintf(outbuf, "func %12s : hu %c%-2d Meter "FMT_RFXPULSE" %s %s(%s)",
1738 funclabel[func], hc, unit, rfxmeterdbl, configp->rfx_pulseunits, roll, aliasp[index].label);
1739 }
1740 else {
1741 sprintf(outbuf, "func %12s : hu %c%-2d Counter %ld %s(%s)",
1742 funclabel[func], hc, unit, counter, roll, aliasp[index].label);
1743 }
1744 }
1745 else if ( configp->rfx_inline == YES ) {
1746 longvdata = rfxmeter_word(vdatap[0], vdatap[1], vdatap[2], vdatap[3]);
1747 sprintf(outbuf, "func %12s : hu %c%-2d Code: 0x%02X %s",
1748 funclabel[func], hc, unit, rfxcode, translate_rfxmeter_code(vident, longvdata));
1749 }
1750 else {
1751 sprintf(outbuf, "func %12s : hu %c%-2d Code: 0x%02X (%s)",
1752 funclabel[func], hc, unit, rfxcode, aliasp[index].label);
1753 }
1754 }
1755 else {
1756 sprintf(outbuf, "func %12s : Type 0x%02x Data (hex) %02x %02x %02x %02x",
1757 "RFdata", vtype, vdatap[0], vdatap[1], vdatap[2], vdatap[3]);
1758 }
1759 #endif /* HASRFXM */
1760
1761 return outbuf;
1762 }
1763
1764 struct x10list_st {
1765 unsigned char hcode;
1766 unsigned int bitmap;
1767 };
1768
1769
1770 /*----------------------------------------------------------------------------+
1771 | Compress X10 list by combining bitmaps for the same housecodes, keeping |
1772 | housecodes in the same order as they appear in the original list. |
1773 +----------------------------------------------------------------------------*/
compress_x10list(struct x10list_st * x10list,int * listsize)1774 int compress_x10list ( struct x10list_st *x10list, int *listsize )
1775 {
1776 #ifdef HASKAKU
1777 struct x10list_st duplist[256];
1778 int j, k, newsize;
1779 unsigned char hcode;
1780
1781 memcpy(duplist, x10list, (*listsize) * sizeof(struct x10list_st));
1782
1783 newsize = 0;
1784 for ( j = 0; j < (*listsize); j++ ) {
1785 if ( !duplist[j].bitmap )
1786 continue;
1787 x10list[newsize].hcode = hcode = duplist[j].hcode;
1788 x10list[newsize].bitmap = duplist[j].bitmap;
1789 for ( k = j + 1; k < (*listsize); k++ ) {
1790 if ( duplist[k].hcode == hcode ) {
1791 x10list[newsize].bitmap |= duplist[k].bitmap;
1792 duplist[k].bitmap = 0;
1793 }
1794 }
1795 newsize++;
1796 }
1797 *listsize = newsize;
1798 #endif /* HASKAKU */
1799
1800 return 0;
1801 }
1802
1803
1804 /*----------------------------------------------------------------------------+
1805 | Translate KaKu RF data |
1806 | Buffer reference: ST_COMMAND, ST_VARIABLE_LEN, plus: |
1807 | vtype, buflen, buffer |
1808 | [2] [3] [4+] |
1809 +----------------------------------------------------------------------------*/
translate_kaku(unsigned char * xbuf,unsigned char * sunchanged,int * launchp)1810 char *translate_kaku ( unsigned char *xbuf, unsigned char *sunchanged, int *launchp )
1811 {
1812
1813 #ifdef HASKAKU
1814 static char outbuf[2048];
1815 extern unsigned int signal_source;
1816 extern unsigned int kmodmask[NumKmodMasks][16];
1817 extern void get_states ( unsigned char, unsigned int *, unsigned int * );
1818 extern unsigned int get_dimstate ( unsigned char );
1819 extern void save_dimlevel ( unsigned char, unsigned int );
1820 extern void restore_dimlevel ( unsigned char, unsigned int );
1821 extern void set_dimlevel ( int, unsigned char, unsigned int );
1822 extern void set_on_level ( unsigned char, unsigned int );
1823 extern char *datstrf ( void );
1824 extern char *lookup_label ( char, unsigned int );
1825
1826 struct x10list_st x10list[256];
1827
1828 ALIAS *aliasp;
1829 LAUNCHER *launcherp;
1830 unsigned long kaddr;
1831 unsigned char *buf;
1832 unsigned char keynum;
1833 char hc = 'Z';
1834 unsigned char hcode, ucode, trig;
1835 unsigned int bitmap, afuncmap;
1836 unsigned long kfuncmap;
1837 unsigned int onstate, dimstate, active, mask, resumask, trigaddr, trigactive;
1838 unsigned int changestate, startupstate;
1839 unsigned int launched, bmaplaunch;
1840 char *ulabel;
1841 char uval[4];
1842 unsigned char cmd, cmd2;
1843 unsigned char level = 0, breaker;
1844 int j, k, n, nx10, unit;
1845 int index;
1846 int nbits, func, actfunc, kactfunc;
1847 char funcparmstr[16];
1848 char *sublabel;
1849
1850 /* Kaku functions 0x00 to 0x11 */
1851 static int ksfunc[] = {KakuOffFunc, KakuOnFunc, KakuGrpOffFunc, KakuGrpOnFunc};
1852 // static int kstrig[] = {KakuOffTrig, KakuOnTrig, KakuGrpOffTrig, KakuGrpOnTrig};
1853 static int kpfunc[] = {KakuPreFunc, KakuUnkPreFunc, KakuGrpPreFunc, KakuUnkPreFunc};
1854 // static int kptrig[] = {KakuPreTrig, KakuUnkPreTrig, KakuGrpPreTrig, KakuUnkPreTrig};
1855
1856 *sunchanged = 0;
1857 *launchp = -1;
1858 *outbuf = '\0';
1859 breaker = 0;
1860 changestate = 0;
1861
1862
1863 nbits = xbuf[4] & 0x7F;
1864 buf = xbuf + 5;
1865 sublabel = (nbits == 34) ? "KAKU_S" :
1866 (nbits == 36) ? "KAKU_D" : "KAKU_?";
1867
1868 kaddr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] & 0xc0);
1869 kaddr = kaddr >> 6;
1870
1871 cmd = (buf[3] & 0x30) >> 4;
1872 keynum = (buf[3] & 0x0f);
1873
1874 index = 0;
1875 *outbuf = '\0';
1876
1877 aliasp = config.aliasp;
1878
1879 /* Create a list of Hu mapped to this signal */
1880
1881 nx10 = 0;
1882 if ( cmd & 0x02 ) {
1883 /* Group command */
1884 while ( aliasp && aliasp[index].line_no > 0 ) {
1885 if ( aliasp[index].vtype == RF_KAKU ) {
1886 for ( j = 0; j < aliasp[index].nident; j++ ) {
1887 if ( aliasp[index].ident[j] == kaddr &&
1888 aliasp[index].kaku_grpmap[j] & (1 << keynum) ) {
1889 x10list[nx10].hcode = hc2code(aliasp[index].housecode);
1890 x10list[nx10++].bitmap = aliasp[index].unitbmap;
1891 }
1892 }
1893 }
1894 index++;
1895 }
1896 }
1897 else {
1898 /* Unit key command */
1899 while ( aliasp && aliasp[index].line_no > 0 ) {
1900 if ( aliasp[index].vtype == RF_KAKU ) {
1901 for ( j = 0; j < aliasp[index].nident; j++ ) {
1902 if ( aliasp[index].ident[j] == kaddr &&
1903 aliasp[index].kaku_keymap[j] & (1 << keynum) ) {
1904 x10list[nx10].hcode = hc2code(aliasp[index].housecode);
1905 x10list[nx10++].bitmap = aliasp[index].unitbmap;
1906 }
1907 }
1908 }
1909 index++;
1910 }
1911 }
1912
1913
1914 if ( !nx10 ) {
1915 /* Display "Key" for kOn/kOff or "Grp" for kGrpOn/kGrpOff */
1916 if ( cmd & 0x02 ) {
1917 /* Group command */
1918 ulabel = "Grp";
1919 sprintf(uval, "%c", 'A' + keynum);
1920 }
1921 else {
1922 /* Unit command */
1923 ulabel = "Key";
1924 sprintf(uval, "%d", keynum + 1);
1925 }
1926
1927 if ( nbits == 34 ) {
1928 cmd2 = (buf[4] & 0xc0) >> 6;
1929 func = ksfunc[cmd];
1930 sprintf(outbuf, "%s rcva func %12s : Type KAKU_S ID 0x%07lx Cmd %s %s %s [Cmd2 0x%02x]\n",
1931 datstrf(), "RFdata", kaddr, funclabel[func], ulabel, uval, cmd2);
1932 }
1933 else if ( nbits == 38 ) {
1934 level = (buf[4] & 0xf0) >> 4;
1935 cmd2 = (buf[4] & 0x0c) >> 2;
1936 func = kpfunc[cmd];
1937 sprintf(outbuf, "%s rcva func %12s : Type KAKU_P ID 0x%07lx Cmd %s %s %s Level %d [Cmd2 0x%02x]\n",
1938 datstrf(), "RFdata", kaddr, funclabel[func], ulabel, uval, level, cmd2);
1939 }
1940 else {
1941 sprintf(outbuf, "%s rcva Unknown KAKU\n", datstrf());
1942 }
1943 return outbuf;
1944 }
1945
1946 /* Built a combined HU bitmap for each housecode */
1947 compress_x10list(x10list, &nx10);
1948
1949 actfunc = func = (nbits == 34) ? ksfunc[cmd] : kpfunc[cmd];
1950
1951 for ( n = 0; n < nx10; n++ ) {
1952 hcode = x10list[n].hcode;
1953 bitmap = x10list[n].bitmap;
1954 hc = code2hc(hcode);
1955
1956 switch ( func ) {
1957 case KakuOnFunc :
1958 mask = kmodmask[KonMask][hcode];
1959 trig = KakuOnTrig;
1960 level = 15;
1961 sprintf(funcparmstr, "key %d", keynum + 1);
1962 break;
1963 case KakuOffFunc :
1964 mask = kmodmask[KoffMask][hcode];
1965 trig = KakuOffTrig;
1966 sprintf(funcparmstr, "key %d", keynum + 1);
1967 level = 0;
1968 break;
1969 case KakuGrpOnFunc :
1970 mask = kmodmask[KGonMask][hcode];
1971 trig = KakuGrpOnTrig;
1972 sprintf(funcparmstr, "grp %c", keynum + 'A');
1973 level = 15;
1974 break;
1975 case KakuGrpOffFunc :
1976 mask = kmodmask[KGoffMask][hcode];
1977 trig = KakuGrpOffTrig;
1978 sprintf(funcparmstr, "grp %c", keynum + 'A');
1979 level = 0;
1980 break;
1981 case KakuPreFunc :
1982 mask = kmodmask[KpreMask][hcode];
1983 level = (buf[4] & 0xf0) >> 4;
1984 trig = KakuPreTrig;
1985 sprintf(funcparmstr, "key %d level %d", keynum + 1, level);
1986 break;
1987 case KakuGrpPreFunc :
1988 mask = kmodmask[KGpreMask][hcode];
1989 level = (buf[4] & 0xf0) >> 4;
1990 trig = KakuGrpPreTrig;
1991 sprintf(funcparmstr, "grp %c level %d", keynum + 'A', level);
1992 break;
1993 default :
1994 mask = 0;
1995 trig = KakuUnkPreTrig;
1996 sprintf(funcparmstr, "key %d", keynum + 1);
1997 level = 0;
1998 break;
1999 }
2000
2001 active = 0;
2002
2003 switch ( func ) {
2004 case KakuOffFunc :
2005 case KakuGrpOffFunc :
2006 active = bitmap & mask;
2007 onstate = x10state[hcode].state[OnState];
2008 save_dimlevel(hcode, active & kmodmask[KresumeMask][hcode]);
2009 set_dimlevel(0, hcode, active);
2010 get_states(hcode, &onstate, &dimstate);
2011 // x10state[hcode].state[ChgState] = active &
2012 changestate = active &
2013 ((x10state[hcode].state[OnState] ^ onstate) |
2014 (x10state[hcode].state[DimState] ^ dimstate));
2015 x10state[hcode].state[OnState] = onstate;
2016 x10state[hcode].state[DimState] = dimstate;
2017 x10state[hcode].state[LightsOnState] &= ~active;
2018 break;
2019
2020 case KakuOnFunc :
2021 case KakuGrpOnFunc :
2022 active = bitmap & mask;
2023 onstate = x10state[hcode].state[OnState];
2024 resumask = kmodmask[KresumeMask][hcode];
2025 /* Resume-enabled units will go to saved brightness */
2026 restore_dimlevel(hcode, active & resumask);
2027 /* Modules which go to 'On' brightness */
2028 set_on_level(hcode, active & ~resumask & ~onstate);
2029 save_dimlevel(hcode, active & resumask);
2030 get_states(hcode, &onstate, &dimstate);
2031 // x10state[hcode].state[ChgState] = /* active & */
2032 changestate = active &
2033 ((x10state[hcode].state[OnState] ^ onstate) |
2034 (x10state[hcode].state[DimState] ^ dimstate));
2035
2036 x10state[hcode].state[OnState] = onstate;
2037 x10state[hcode].state[DimState] = dimstate;
2038 x10state[hcode].state[LightsOnState] &= ~active;
2039 break;
2040
2041 case KakuPreFunc :
2042 case KakuGrpPreFunc :
2043 active = bitmap & mask;
2044 onstate = x10state[hcode].state[OnState];
2045 set_dimlevel(level, hcode, active);
2046 get_states(hcode, &onstate, &dimstate);
2047 // x10state[hcode].state[ChgState] = active &
2048 changestate = active &
2049 ((x10state[hcode].state[OnState] ^ onstate) |
2050 (x10state[hcode].state[DimState] ^ dimstate));
2051 x10state[hcode].state[OnState] = onstate;
2052 x10state[hcode].state[DimState] = dimstate;
2053 x10state[hcode].state[LightsOnState] &= ~active;
2054 break;
2055
2056 default :
2057 active = 0;
2058 break;
2059 }
2060
2061 ucode = 0xff;
2062
2063 startupstate = ~x10state[hcode].state[ValidState] & active;
2064 x10state[hcode].state[ValidState] |= active;
2065
2066 // x10state[hcode].state[ModChgState] = (x10state[hcode].state[ModChgState] & ~active) | changestate;
2067 x10state[hcode].state[ModChgState] = changestate;
2068
2069 x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] |
2070 (x10state[hcode].state[ActiveChgState] & active) |
2071 (startupstate & ~kmodmask[KPhysMask][hcode]);
2072
2073 changestate = x10state[hcode].state[ChgState];
2074
2075 for ( k = 0; k < 16; k++ ) {
2076 if ( bitmap & (1 << k) ) {
2077 ucode = k;
2078 x10state[hcode].vident[ucode] = kaddr;
2079 x10state[hcode].vflags[ucode] = 0;
2080 x10state[hcode].timestamp[ucode] = time(NULL);
2081 x10state[hcode].state[ValidState] |= (1 << ucode);
2082 }
2083 }
2084
2085 unit = code2unit(ucode);
2086 x10state[hcode].vaddress = bitmap;
2087 x10state[hcode].lastcmd = func;
2088 x10state[hcode].lastunit = unit;
2089 x10global.lasthc = hcode;
2090 x10global.lastaddr = 0;
2091
2092 actfunc = 0;
2093 afuncmap = 0;
2094 kactfunc = func;
2095 kfuncmap = (1 << trig);
2096 trigaddr = active;
2097
2098 launcherp = config.launcherp;
2099
2100 bmaplaunch = launched = 0;
2101 j = 0;
2102 while ( launcherp && !breaker && launcherp[j].line_no > 0 ) {
2103 if ( launcherp[j].type != L_NORMAL ||
2104 launcherp[j].hcode != hcode ||
2105 is_unmatched_flags(&launcherp[j]) ||
2106 (launcherp[j].vflags & x10state[hcode].vflags[ucode]) != launcherp[j].vflags ||
2107 (launcherp[j].notvflags & ~x10state[hcode].vflags[ucode]) != launcherp[j].notvflags ) {
2108 j++;
2109 continue;
2110 }
2111
2112 if ( launcherp[j].kfuncmap & kfuncmap &&
2113 launcherp[j].source & signal_source ) {
2114 trigactive = trigaddr & (mask | launcherp[j].signal);
2115 if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) &
2116 // (x10state[hcode].state[ChgState] | ~launcherp[j].chgtrig)) ||
2117 (changestate | ~launcherp[j].chgtrig)) ||
2118 (launcherp[j].unitstar && !trigaddr)) {
2119 launcherp[j].matched = YES;
2120 *launchp = j;
2121 launched |= bmaplaunch;
2122 launcherp[j].actfunc = kactfunc;
2123 launcherp[j].genfunc = 0;
2124 launcherp[j].xfunc = kactfunc;
2125 launcherp[j].level = x10state[hcode].dimlevel[ucode];
2126 launcherp[j].bmaplaunch = bmaplaunch;
2127 launcherp[j].actsource = signal_source;
2128 if ( launcherp[j].scanmode & FM_BREAK ) {
2129 breaker = 1;
2130 break;
2131 }
2132 }
2133 }
2134 j++;
2135 }
2136
2137 x10state[hcode].launched = launched;
2138
2139 for ( ucode = 0; ucode < 16; ucode++ ) {
2140 if ( bitmap & (1 << ucode) ) {
2141 unit = code2unit(ucode);
2142 sprintf(outbuf + strlen(outbuf), "%s rcva %12s : hu %c%d (%s)\n",
2143 datstrf(), "kAddress", hc, unit, lookup_label(hc, (1 << ucode)) );
2144 }
2145 }
2146 }
2147
2148 sprintf(outbuf + strlen(outbuf), "%s rcva func %12s : %s\n",
2149 datstrf(), funclabel[func], funcparmstr);
2150
2151 if ( i_am_state )
2152 write_x10state_file();
2153
2154 return outbuf;
2155
2156 #else
2157 return "";
2158
2159 #endif /* HASKAKU */
2160
2161
2162 }
2163
2164 /*----------------------------------------------------------------------------+
2165 | Translate Visonic RF data |
2166 | Buffer reference: ST_COMMAND, ST_VARIABLE_LEN, plus: |
2167 | vtype, buflen, buffer |
2168 | [2] [3] [4+] |
2169 +----------------------------------------------------------------------------*/
translate_visonic(unsigned char * xbuf,unsigned char * sunchanged,int * launchp)2170 char *translate_visonic ( unsigned char *xbuf, unsigned char *sunchanged, int *launchp )
2171 {
2172 static char outbuf[120];
2173 unsigned int ident;
2174 unsigned char data;
2175 unsigned char *buf;
2176
2177 extern char *datstrf ( void );
2178
2179 buf = xbuf + 5;
2180 ident = (buf[4] << 16) | (buf[1] << 8) | buf[0];
2181 data = buf[2];
2182
2183 sprintf(outbuf, "%s rcva func %12s : Type VISONIC ID 0x%06x Data 0x%02x\n",
2184 datstrf(), "RFdata", ident, data);
2185
2186 *sunchanged = 0;
2187 *launchp = -1;
2188
2189 return outbuf;
2190 }
2191
2192
2193
2194