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