1 /*----------------------------------------------------------------------------+
2  |                                                                            |
3  |                    Enhanced HEYU Functionality                             |
4  |                                                                            |
5  |         Enhancements copyright 2004-2008 Charles W. Sullivan               |
6  |                                                                            |
7  | Changes for use with CM11A copyright 1996, 1997 Daniel B. Suthers,         |
8  | Pleasanton Ca, 94588 USA                                                   |
9  |                                                                            |
10  | Copyright 1986 by Larry Campbell, 73 Concord Street, Maynard MA 01754 USA  |
11  | (maynard!campbell).                                                        |
12  |                                                                            |
13  | John Chmielewski (tesla!jlc until 9/1/86, then rogue!jlc) assisted         |
14  | by doing the System V port and adding some nice features.  Thanks!         |
15  |                                                                            |
16  |                                                                            |
17  | As used herein, HEYU is a trademark of Daniel B. Suthers.                  |
18  | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc.               |
19  | The author is not affiliated with either entity.                           |
20  |                                                                            |
21  | Charles W. Sullivan                                                        |
22  | Co-author and Maintainer                                                   |
23  | Greensboro, North Carolina                                                 |
24  | Email ID: cwsulliv01                                                       |
25  | Email domain: -at- heyu -dot- org                                          |
26  |                                                                            |
27  +----------------------------------------------------------------------------*/
28 
29 /*
30  *   This program is free software: you can redistribute it and/or modify
31  *   it under the terms of the GNU General Public License as published by
32  *   the Free Software Foundation, either version 3 of the License, or
33  *   (at your option) any later version.
34  *
35  *   This program is distributed in the hope that it will be useful,
36  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *   GNU General Public License for more details.
39  *
40  *   You should have received a copy of the GNU General Public License
41  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
42  *
43  */
44 
45 #include <stdio.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <ctype.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD)
53 #include <string.h>
54 #else
55 #include <strings.h>
56 #endif
57 #include <time.h>
58 #include <signal.h>
59 #include "x10.h"
60 #include <syslog.h>
61 #include "process.h"
62 #include "x10state.h"
63 #include "oregon.h"
64 
65 #ifdef __GLIBC__
66 /* msf - added for glibc/rh 5.0 */
67 #include <sys/types.h>
68 #endif
69 
70 extern int sptty;
71 
72 extern CONFIG config;
73 extern CONFIG *configp;
74 
75 extern struct x10global_st x10global;
76 extern x10hcode_t *x10state;
77 
78 extern int i_am_monitor, i_am_state, i_am_rfxmeter;
79 extern int verbose;
80 
81 extern int xread(int, unsigned char *, int, int);
82 
83 extern int is_ring ( void );
84 extern int reread_config ( void );
85 
86 unsigned char bootflag = R_NOTATSTART;
87 
88 /*----------------------------------------------------------------------------+
89  | Determine the maximum number of bytes for a received function available in |
90  | the buffer.  Arguments lenbyte and fmapbyte are the first two bytes from   |
91  | the buffer, representing the length of the buffer and a bitmapped function |
92  | indicator.  The return value is determined by the lesser the length of the |
93  | buffer or the distance to the next indicated function from the function    |
94  | indicator byte.                                                            |
95  +----------------------------------------------------------------------------*/
max_funclen(unsigned char lenbyte,unsigned char fmapbyte,int pos)96 int max_funclen ( unsigned char lenbyte, unsigned char fmapbyte, int pos )
97 {
98    int k, maxlen;
99 
100    if ( !(fmapbyte & (1 << pos)) || lenbyte > 9 )
101       return 0;
102 
103    maxlen = 1;
104    for ( k = pos + 1; k < (int)(lenbyte - 1); k++ ) {
105       if ( !(fmapbyte & (1 << k)) )
106          maxlen++;
107       else
108          break;
109    }
110    return maxlen;
111 }
112 
113 
114 /*
115  *  The CM11A sends data back to the computer whenever it sees a command
116  *  come in over the AC buss.  This should (theoretically) allow the compuer
117  *  to track the status of all modules.  Upon startup, this program should
118  *  check for a poll before anything else.
119  *
120  *  Check for a poll (0x5a) from the CM11A, If we get one within a
121  *  second, we should send 0xc3 to tell it that we are ready to read
122  *  it's output.
123  *
124  *  If the showdata flag is set, we print.  Otherwise we just eat the output.
125  */
126 
127 
128 extern char *datstrf(void);
129 unsigned int signal_source;
130 extern FILE *fdsout;
131 extern FILE *fdserr;
132 extern FILE *fprfxo;
133 extern FILE *fprfxe;
134 
check4poll(int showdata,int timeout)135 int check4poll( int showdata, int timeout )
136 {
137     static int lastunit;
138     static char lasthc = '_';
139     int temperat, fdata;
140     int n, i, j;
141     int to_read;
142     char hc;
143     unsigned char predim, xcmd, xtype, xdata, subunit;
144     int unit;
145     int macro_report;
146     char *func;
147     int funcbits;
148     static int wasflag = 0;
149     unsigned char buf[128];
150     char outbuf[256];
151     unsigned char snochange;
152     extern char *b2s();
153     off_t f_offset;
154     unsigned int mac_addr, bitmap;
155     extern void acknowledge_hail();
156     extern int special_func;
157     extern int display_expanded_macro();
158     int ichksum;
159     int identify_sent(unsigned char *, int, unsigned char *);
160     char *translate_other(unsigned char *, int, unsigned char *);
161     extern char *translate_sent(unsigned char *, int, int *);
162     extern char *translate_rf_sent(unsigned char *, int *);
163 #if 0
164     extern int find_powerfail_launcher( unsigned char );
165     extern int find_rfflood_launcher( void );
166     extern int find_lockup_launcher( void );
167 #endif
168     extern int find_powerfail_scripts ( unsigned char );
169     extern int find_rfflood_scripts ( void );
170     extern int find_lockup_scripts ( void );
171 
172     extern int set_globsec_flags( unsigned char );
173     extern char *display_armed_status ( void );
174     extern int clear_tamper_flags ( void );
175     extern int engine_local_setup ( int );
176     extern char *translate_rfxtype_message ( unsigned char * );
177     extern char *translate_rfxsensor_ident ( unsigned char * );
178     extern char *display_variable_aux_data ( unsigned char * );
179     extern int set_counter ( int, unsigned short, unsigned char );
180     extern char *translate_counter_action ( unsigned char * );
181     extern char *translate_kaku ( unsigned char *, unsigned char *, int * );
182     extern char *translate_visonic ( unsigned char *, unsigned char *, int * );
183     extern char *display_binbuffer ( unsigned char * );
184     int launch_script_cmd ( unsigned char * );
185     int launchp = -1;
186     char maclabel[MACRO_LEN + 1];
187     int macfound;
188     unsigned int squelch;
189     unsigned char hcode;
190 
191     static int chksum_alert = -1;
192     extern char *funclabel[18];
193     static unsigned char newbuf[8], hexaddr = 0;
194     static char *send_prefix = "sndc";
195     static unsigned char waitflag = 0;
196 
197     int sent_type;
198     unsigned char tag;
199     int maxlen;
200     unsigned char level;
201     static unsigned char defer_dim;
202     char minibuf[32];
203     char *transp;
204     mode_t oldumask;
205     char *sp;
206 
207 
208 
209     static char *rcs_status[] = {
210        "System_mode = OFF", "System_mode = HEAT", "System_mode = COOL", "System_mode = AUTO",
211        "Fan = ON", "Fan = OFF", "Setback = ON", "Setback = OFF", "Temp Change", "Setpoint Change",
212        "Outside Temp", "Heat Setpoint", "Cooling Setpoint",
213     };
214     static unsigned int source_type[] = {SNDC, SNDS, SNDP, SNDA, RCVA};
215     static char *source_name[] = {"sndc", "snds", "sndp", "snda", "rcva"};
216 
217     if ( i_am_state ) {
218        /* Redirect output to the Heyu log file */
219        oldumask = umask((mode_t)configp->log_umask);
220        fdsout = freopen(configp->logfile, "a", stdout);
221        fdserr = freopen(configp->logfile, "a", stderr);
222        umask(oldumask);
223     }
224 
225     /* Note: When invoked as the normal 'heyu monitor' (i_am_monitor), */
226     /* fdsout and fdserr will have been set to stdout and stderr.      */
227     /* But when invoked as 'heyu monitor rfxmeter' (i_am_rfxmeter),    */
228     /* they will have been redirected to /dev/null so the only output  */
229     /* to that xterm will be RFXMeter data via file pointer fprfxo.    */
230 
231     unit = -1;
232     hc = '\0';
233     func =  "" ;
234 
235     if ( timeout == 0 )	 {	/* only do a read if there is data */
236 	if( sptty < 0 ) {
237 	    return 0;
238         }
239         f_offset = lseek(sptty, 0, SEEK_CUR);
240 	if ( f_offset == lseek(sptty, 0, SEEK_END) ) {
241 	    return 0;
242         }
243 	lseek(sptty, f_offset, SEEK_SET);
244 	timeout = 1;
245     }
246 
247 
248     n = xread(sptty, buf, 1, timeout);
249     if ( n != 0 ) {
250 	/* Three 0xff bytes in a row indicate that I sent a transmission to
251 	 * the CM11, I.E a command.  The byte following the 3 0xFF bytes
252 	 * indicates how long the sent command was.  We need to suck these
253 	 * off the stack if we are monitoring.
254 	 */
255 	while ( buf[0] == 0xff )  {  /* CM11A may be responding to a transmission  */
256 	    if ( ++wasflag == 3 ) {
257 		wasflag = 0;
258 		n = xread(sptty, buf, 1, timeout);	/* length of xmit */
259 		if( n != 1 ) {
260 		     return(0);
261                 }
262                 if ( buf[0] == 0xff && chksum_alert == 0xff ) {
263 		   /*
264 		    * We have received four 0xff bytes in a row,
265 		    * looks like the first one was the checksum expected,
266 		    * so drop one of them and loop one more time.
267 		    */
268 		   chksum_alert = -1;
269 		   wasflag = 2;
270 		   continue;
271 		}
272 		n = buf[0];
273 
274                 if ( n < 127 ) {
275 		   unsigned char chksum;
276 
277                    n = xread(sptty, buf, n, timeout);
278 
279                    /* Identify the type of sent command from the leading */
280                    /* byte and the length of the buffer.                 */
281                    sent_type = identify_sent(buf, n, &chksum);
282 
283                    if ( sent_type == SENT_STCMD ) {
284                       /* A command for the monitor/state process */
285 		      if ( buf[1] == ST_SOURCE ) {
286                          signal_source = source_type[buf[2]];
287                          send_prefix = source_name[buf[2]];
288 		      }
289                       else if ( buf[1] == ST_TESTPOINT && i_am_monitor ) {
290                          fprintf(fdsout, "%s Testpoint %d\n", datstrf(), buf[2]);
291                       }
292                       else if ( buf[1] == ST_LAUNCH && i_am_state ) {
293                          configp->script_ctrl = buf[2];
294                          fprintf(fdsout, "%s Scripts %s\n", datstrf(), (buf[2] == ENABLE ? "enabled" : "disabled"));
295                       }
296                       else if ( buf[1] == ST_INIT_ALL && i_am_state ) {
297                          x10state_init_all();
298                          write_x10state_file();
299                       }
300                       else if ( buf[1] == ST_INIT && i_am_state ) {
301                          x10state_init_old(buf[2]);
302                          write_x10state_file();
303                       }
304                       else if ( buf[1] == ST_INIT_OTHERS && i_am_state ) {
305                          x10state_init_others();
306                          write_x10state_file();
307                       }
308                       else if ( buf[1] == ST_WRITE && i_am_state ) {
309                          write_x10state_file();
310                       }
311                       else if ( buf[1] == ST_EXIT && i_am_state ) {
312                          write_x10state_file();
313                          unlock_state_engine();
314                          exit(0);
315                       }
316                       else if ( buf[1] == ST_RESETRF && (i_am_state || i_am_monitor) ) {
317 			 fprintf(fdsout, "%s Reset CM17A\n", datstrf());
318                       }
319 		      else if ( buf[1] == ST_BUSYWAIT && (i_am_state || i_am_monitor) ) {
320 			 waitflag = buf[2];
321                          if ( configp->auto_wait == 0 ) {
322 			    if ( waitflag > 0 )
323 			       fprintf(fdsout, "%s Wait macro completion.\n", datstrf());
324 			    else
325 			       fprintf(fdsout, "%s Wait timeout.\n", datstrf());
326                          }
327 		      }
328                       else if ( buf[1] == ST_CHKSUM ) {
329                          chksum_alert = buf[2];
330                       }
331                       else if ( buf[1] == ST_REWIND ) {
332                          for ( j = 0; j < 10; j++ ) {
333                             if ( lseek(sptty, (off_t)0, SEEK_END) <= (off_t)(SPOOLFILE_ABSMIN/2) )
334                                break;
335                             sleep(1);
336                          }
337                          fprintf(fdsout, "%s Spoolfile exceeded max size and was rewound.\n", datstrf());
338                       }
339                       else if ( buf[1] == ST_SHOWBYTE && (i_am_state || i_am_monitor) ) {
340                          fprintf(fdsout, "%s Byte value = 0x%02x\n", datstrf(), buf[2]);
341                       }
342                       else if ( buf[1] == ST_RESTART && (i_am_state || i_am_monitor || i_am_rfxmeter) ) {
343                          reread_config();
344                          if ( i_am_state ) {
345                             syslog(LOG_ERR, "engine reconfiguration-\n");
346                             engine_local_setup(E_RESTART);
347                             fprintf(fdsout, "%s Engine reconfiguration\n", datstrf());
348                             fflush(fdsout);
349 //                            syslog(LOG_ERR, "engine reconfiguration-\n");
350                          }
351                          else if ( i_am_rfxmeter ) {
352                             fprintf(fprfxo, "RFXMeter monitor reconfiguration\n");
353                             fflush(fprfxo);
354                          }
355                          else {
356                             fprintf(fdsout, "%s Monitor reconfiguration\n", datstrf());
357                             fflush(fdsout);
358                          }
359                       }
360                       else if ( buf[1] == ST_SECFLAGS && (i_am_state || i_am_monitor)) {
361                          if ( buf[2] != 0 ) {
362                             warn_zone_faults(fdsout, datstrf());
363                          }
364                          set_globsec_flags(buf[2]);
365                          write_x10state_file();
366                          fprintf(fdsout, "%s %s\n", datstrf(), display_armed_status());
367                          fflush(fdsout);
368                       }
369                       else if ( buf[1] == ST_CLRTIMERS && (i_am_state || i_am_monitor)) {
370                          reset_user_timers();
371                          write_x10state_file();
372                          fprintf(fdsout, "%s Reset timers 1-16\n", datstrf());
373                          fflush(fdsout);
374                       }
375                       else if ( buf[1] == ST_CLRTAMPER && (i_am_state || i_am_monitor)) {
376                          clear_tamper_flags();
377                          write_x10state_file();
378                          fprintf(fdsout, "%s Clear tamper flags\n", datstrf());
379                          fflush(fdsout);
380                       }
381                    }
382                    else if ( sent_type == SENT_WRMI ) {
383                       /* WRMI - Ignore */
384                    }
385                    else if ( sent_type == SENT_ADDR ) {
386                       /* An address */
387                       if ( *(transp = translate_sent(buf, n, &launchp)) )
388                          fprintf(fdsout, "%s %s %s\n", datstrf(), send_prefix, transp);
389                       if (signal_source != RCVA)
390                          chksum_alert = chksum;
391                       if ( launchp >= 0 && i_am_state) {
392                          launch_scripts(&launchp);
393                       }
394                    }
395                    else if ( sent_type == SENT_FUNC ) {
396                       /* Standard function */
397                       if ( *(transp = translate_sent(buf, n, &launchp)) )
398                          fprintf(fdsout, "%s %s %s\n", datstrf(), send_prefix, transp);
399                       if (signal_source != RCVA)
400                          chksum_alert = chksum;
401                       if ( launchp >= 0 && i_am_state) {
402                          launch_scripts(&launchp);
403                       }
404                    }
405                    else if ( sent_type == SENT_EXTFUNC ) {
406                       /* Extended function */
407                       if ( *(transp = translate_sent(buf, n, &launchp)) )
408                          fprintf(fdsout,"%s %s %s\n", datstrf(), send_prefix, transp);
409 		      chksum_alert = chksum;
410                       if ( launchp >= 0 && i_am_state) {
411                          launch_scripts(&launchp);
412                       }
413                    }
414                    else if ( sent_type == SENT_RF ) {
415                       /* CM17A command */
416                       fprintf(fdsout,"%s %s %s\n", datstrf(), "xmtf", translate_rf_sent(buf, &launchp));
417                       if ( launchp >= 0 && i_am_state ) {
418                          launch_scripts(&launchp);
419                       }
420                    }
421                    else if ( sent_type == SENT_FLAGS && i_am_state ) {
422                       update_flags(buf);
423                       write_x10state_file();
424                    }
425                    else if ( sent_type == SENT_FLAGS32 && i_am_state ) {
426                       update_flags_32(buf);
427                       write_x10state_file();
428                    }
429                    else if ( sent_type == SENT_VDATA ) {
430                       strcpy(outbuf, translate_virtual(buf, 9 /*8*/, &snochange, &launchp));
431                       if ( *outbuf && !(snochange && config.hide_unchanged == YES && launchp < 0) )
432                          fprintf(fdsout,"%s %s %s\n", datstrf(), send_prefix, outbuf);
433                       if ( i_am_state && launchp >= 0 ) {
434                          launch_scripts(&launchp);
435                       }
436                    }
437                    else if ( sent_type == SENT_GENLONG ) {
438                       strcpy(outbuf, translate_gen_longdata(buf, &snochange, &launchp));
439                       if ( *outbuf && !(snochange && config.hide_unchanged == YES && launchp < 0) )
440                          fprintf(fdsout,"%s %s %s\n", datstrf(), send_prefix, outbuf);
441                       if ( i_am_state && launchp >= 0 ) {
442                          launch_scripts(&launchp);
443                       }
444                    }
445                    else if ( sent_type == SENT_ORE_EMU ) {
446                       strcpy(outbuf, translate_ore_emu(buf, &snochange, &launchp));
447                       if ( *outbuf && !(snochange && config.hide_unchanged == YES && launchp < 0) )
448                          fprintf(fdsout,"%s %s %s\n", datstrf(), send_prefix, outbuf);
449                       if ( i_am_state && launchp >= 0 ) {
450                          launch_scripts(&launchp);
451                       }
452                    }
453                    else if ( sent_type == SENT_KAKU ) {
454                       strcpy(outbuf, translate_kaku(buf, &snochange, &launchp));
455                       if ( *outbuf && !(snochange && config.hide_unchanged == YES && launchp < 0) )
456                          fprintf(fdsout,"%s", outbuf);
457                       if ( i_am_state && launchp >= 0 ) {
458                          launch_scripts(&launchp);
459                       }
460                    }
461                    else if ( sent_type == SENT_VISONIC ) {
462                       strcpy(outbuf, translate_visonic(buf, &snochange, &launchp));
463                       if ( *outbuf && !(snochange && config.hide_unchanged == YES && launchp < 0) )
464                          fprintf(fdsout,"%s", outbuf);
465                       if ( i_am_state && launchp >= 0 ) {
466                          launch_scripts(&launchp);
467                       }
468                    }
469                    else if ( sent_type == SENT_LONGVDATA ) {
470                       if ( i_am_rfxmeter ) {
471                          /* This and only this data gets sent to the special */
472                          /* 'heyu monitor rfxmeter' window */
473                          strcpy(outbuf, translate_long_virtual(buf, &snochange, &launchp) );
474                          if ( (sp = strchr(outbuf, '\n')) != NULL )
475                             *sp = '\0';
476                          fprintf(fprfxo, "%s\n", outbuf);
477                          fflush(fprfxo);
478                       }
479                       else {
480                          /* This and all other data are not sent to the rfxmeter window */
481                          strcpy(outbuf, translate_long_virtual(buf, &snochange, &launchp) );
482                          if ( *outbuf && !(snochange && config.hide_unchanged == YES && launchp < 0) ) {
483                             if ( (sp = strchr(outbuf, '\n')) != NULL ) {
484                                *sp = '\0';
485                                fprintf(fdsout,"%s %s %s\n", datstrf(), send_prefix, outbuf);
486                                fprintf(fdsout,"%s %s\n", datstrf(), sp + 1);
487                             }
488                             else {
489                                fprintf(fdsout,"%s %s %s\n", datstrf(), send_prefix, outbuf);
490                             }
491                          }
492                          if ( i_am_state && launchp >= 0 ) {
493                             launch_scripts(&launchp);
494                          }
495                       }
496                    }
497                    else if ( sent_type == SENT_COUNTER && (i_am_state || i_am_monitor)) {
498                       set_counter(buf[2] | (buf[3] << 8), buf[4] | (buf[5] << 8), buf[6]);
499                       write_x10state_file();
500                       fprintf(fdsout, "%s %s\n", datstrf(), translate_counter_action(buf));
501                       fflush(fdsout);
502                    }
503                    else if ( sent_type == SENT_CLRSTATUS && i_am_state ) {
504                       clear_statusflags(buf[2], (buf[3] << 8 | buf[4]));
505                       write_x10state_file();
506                    }
507 		   else if ( sent_type == SENT_MESSAGE && (i_am_monitor || i_am_state) ) {
508 		      fprintf(fdsout, "%s %s\n", datstrf(), buf + 3);
509 	           }
510                    else if ( sent_type == SENT_PFAIL && (i_am_state || i_am_monitor) ) {
511                       bootflag = buf[2];
512                       if ( bootflag & R_ATSTART )
513                          fprintf(fdsout, "%s Powerfail signal received at startup.\n", datstrf());
514                       else
515                          fprintf(fdsout, "%s Powerfail signal received.\n", datstrf());
516                       if ( i_am_state && (launchp = find_powerfail_scripts(bootflag)) >= 0 )
517                          launch_scripts(&launchp);
518                    }
519                    else if ( sent_type == SENT_RFFLOOD && (i_am_state || i_am_monitor) ) {
520                       fprintf(fdsout, "%s RF_Flood signal received.\n", datstrf());
521                       if ( i_am_state && (launchp = find_rfflood_scripts()) >= 0 )
522                          launch_scripts(&launchp);
523                    }
524                    else if ( sent_type == SENT_LOCKUP && (i_am_state || i_am_monitor) ) {
525                       fprintf(fdsout, "%s Interface lockup signal received, reason %02x.\n", datstrf(), buf[2]);
526                       if ( i_am_state && (launchp = find_lockup_scripts()) >= 0 )
527                          launch_scripts(&launchp);
528                    }
529                    else if ( sent_type == SENT_SETTIMER && (i_am_state || i_am_monitor) ) {
530                       fprintf(fdsout, "%s %s\n", datstrf(), translate_settimer_message(buf));
531 //                      if ( i_am_state )
532 //                         write_x10state_file();
533                    }
534                    else if ( sent_type == SENT_RFXTYPE && (i_am_state || i_am_monitor) ) {
535                       fprintf(fdsout, "%s %s %s\n", datstrf(), send_prefix, translate_rfxtype_message(buf));
536                    }
537                    else if ( sent_type == SENT_RFXSERIAL && (i_am_state || i_am_monitor) ) {
538                       fprintf(fdsout, "%s %s %s\n", datstrf(), send_prefix, translate_rfxsensor_ident(buf));
539                    }
540                    else if ( sent_type == SENT_RFVARIABLE && (i_am_state || i_am_monitor) ) {
541                       fprintf(fdsout, "%s %s %s\n", datstrf(), send_prefix, display_variable_aux_data(buf));
542                    }
543                    else if ( sent_type == SENT_SCRIPT && (i_am_state) ) {
544                        launch_script_cmd(buf);
545                    }
546                    else if ( sent_type == SENT_INITSTATE && (i_am_state) ) {
547                         x10state_init(buf[2], buf[3] | (buf[4] << 8));
548                    }
549                    else if ( sent_type == SENT_SHOWBUFFER && i_am_monitor ) {
550                       fprintf(fdsout, "%s %s\n", datstrf(), display_binbuffer(buf + 2));
551                    }
552                    else if ( sent_type == SENT_OTHER ) {
553                       /* Other command */
554                       if ( *(transp = translate_other(buf, n, &chksum)) )
555                          fprintf(fdsout, "%s %s\n", datstrf(), transp);
556 		      chksum_alert = chksum;
557                       launchp = -1;
558                    }
559 
560                 }
561                 else {
562                    n = xread(sptty, buf, n - 127, timeout);
563                 }
564 
565 	        fflush(fdsout);
566 	        return(0);
567 	    }
568 	    else
569 		n = xread(sptty, buf, 1, timeout);
570 
571 	    if( n != 1 ) {
572 	        return(0);
573             }
574 
575 	}   /* end of while */
576 
577 
578 	/* print out the saved 0xff from the buffer */
579 	if ( buf[0] != 0xff && wasflag > 0 )  {
580 	    if (chksum_alert == 0xff) {
581 	    	/* a single 0xff was apparently a checksum */
582 		chksum_alert = -1;
583 		wasflag--;
584 	    }
585 	    n = buf[0];
586 	    for(i = 0; i < wasflag;i++)
587 		buf[i] = 0xff;
588 	    buf[i] = n;
589 	    n = wasflag + 1;
590 	    wasflag = 0;
591 	}
592 
593         if ( buf[0] == chksum_alert ) {
594 	    /* this is the checksum expected, just drop it */
595             chksum_alert = -1;
596 	    return 0;
597         }
598 
599 	if (chksum_alert >= 0) {
600 	    /*
601 	     * Instead of the checksum expected, we've received something else.
602 	     * Don't expect that checksum to appear any longer. Either the
603 	     * interface didn't respond with a checksum, busy with an incomming
604 	     * transmission or a macro, or we are completely out of sync.
605 	     */
606 	    chksum_alert = -1;
607 	}
608 
609 	macro_report = 0;
610         if ( buf[0] == 0x5a )  {
611             /* CM11A has polling info for me */
612 	    /* The xread is executed a second time on failure because the
613 	       dim commands may be tieing up the CM11.
614 	    */
615 	    n = xread(sptty, buf, 1, 2);  /* get the buffer size */
616 	    if ( n == 0)
617 		n = xread(sptty, buf, 1, 2);  /* get the buffer size */
618 
619 	    if ( n > 0 )  {
620                 /* We have a byte count */
621 	        to_read = buf[0];	/* number of bytes to read */
622 		if ( to_read == 0x5a ) {
623                     /* Darn.  Another polling indicator */
624 		    timeout = 2;
625 		    return ( check4poll(showdata, timeout) );
626 		}
627 		else if ( to_read == 0x5b )  { /* Macro report coming in */
628 		    to_read = 2;
629 		    macro_report = 1;
630 		}
631 
632 		if ( to_read > (int)sizeof(buf) ) {
633 		    if( verbose )
634 			fprintf(fdserr, "Polling read size exceeds buffer");
635 		    return(-1);
636 		}
637 
638 		n = xread(sptty, buf, to_read , timeout);
639 		if ( n != to_read ) {
640 		    fprintf(fdsout, "Poll only got %d of %d bytes\n",
641 		            n, to_read);
642 		    fflush(fdsout);
643 		    return 0;
644 		}
645 
646                 if ( showdata > 0 && (verbose != 0) )
647 		    fprintf(fdsout, "I received a poll %d bytes long.\n", n);
648 
649 		if ( macro_report == 1 )  { /* CM11A is reporting a macro execution.*/
650 		    if ( showdata ) {
651                        mac_addr = ((buf[0] & 0x07u) << 8) + buf[1];
652                        /* Get macro label (or "Unknown") and saved image checksum */
653                        macfound = lookup_macro(mac_addr, maclabel, &ichksum);
654 
655                        if ( buf[0] & 0x70u )  {
656                           /* Macro was executed by a Trigger */
657                           if ( macfound == 1 && ichksum != -1 && loadcheck_image(ichksum) ) {
658 
659                              /* Determine and display the inferred trigger. */
660                              /* Launch a script if warranted.               */
661                              signal_source = RCVT;
662                              tag = (buf[0] & 0x70u) >> 4;
663                              display_trigger(datstrf(), mac_addr, tag);
664 
665                              /* Announce the execution of the macro */
666                              fprintf(fdsout, "%s Trigger executed macro : %s, address 0x%03x\n",
667                                    datstrf(), maclabel, mac_addr);
668 
669                              /* Decipher and display macro elements from image file. */
670                              /* Launch script(s) when warranted.                     */
671                              signal_source = SNDT;
672                              expand_macro(datstrf(), mac_addr, TRIGGER_EXEC);
673                           }
674                           else {
675                              fprintf(fdsout, "%s Trigger executed macro : %s, address 0x%03x\n",
676                                     datstrf(), maclabel, mac_addr);
677                           }
678                        }
679                        else {
680                           /* Macro was executed by a Timer */
681                           set_macro_timestamp(time(NULL));
682                           if ( macfound == 1 && ichksum != -1 && loadcheck_image(ichksum) ) {
683                              fprintf(fdsout, "%s Timer executed macro   : %s, address 0x%03x\n",
684                                        datstrf(), maclabel, mac_addr);
685                              /* Decipher and display macro elements from image file. */
686                              /* Launch script(s) when warranted.                     */
687                              signal_source = SNDM;
688                              expand_macro(datstrf(), mac_addr, TIMER_EXEC);
689                           }
690                           else {
691                              fprintf(fdsout, "%s Timer executed macro   : %s, address 0x%03x\n",
692                                        datstrf(), maclabel, mac_addr);
693                           }
694                        }
695 		    }
696 		}
697 		else {
698                     signal_source = RCVI;
699 #if 0
700                     if ( showdata ) {
701                         for ( i = 1; i < to_read; i++)
702                             fprintf(fdsout, " %02x", buf[i]);
703                         fprintf(fdsout, "\n");
704                     }
705 #endif
706 
707 
708 		    for ( i = 1; i < to_read; i++) {
709                         xcmd = xdata = subunit = predim = level = 0;
710 
711 			if ( defer_dim &&
712                             ( (funcbits = (newbuf[0] & 0x0Fu)) == DIM || funcbits == BRIGHT) ) {
713                             /* Finish handling a deferred Dim or Bright function */
714                             newbuf[1] = buf[i];
715                             signal_source = RCVI;
716                             x10state_update_func(newbuf, &launchp);
717                             hc = code2hc((newbuf[0] & 0xF0u) >> 4);
718                             level = buf[i];
719                             defer_dim = 0;
720                             newbuf[0] = 0;
721 			    if( showdata ) {
722                                fprintf(fdsout, "%s rcvi func %12s : hc %c %s %%%02.0f [%d]\n",
723                                   datstrf(), funclabel[funcbits], hc,
724                                   ((funcbits == DIM) ? "dim" : "bright"),
725                                   100.*(float)level/210., level);
726                             }
727 			}
728 			else if ( (buf[0] & (0x01 << (i-1))) != 0) {
729                             /* A function has been received */
730                             signal_source = RCVI;
731 
732                             /* Determine the maximum number of bytes    */
733                             /* available in the buffer for the function */
734                             maxlen = max_funclen(to_read, buf[0], (i-1));
735 
736 			    hc = code2hc( ((buf[i] & 0xF0u) >> 4) );
737 			    funcbits = buf[i] & 0x0Fu;
738                             func = funclabel[buf[i] & 0x0Fu];
739 
740 			    if ( funcbits == DIM || funcbits == BRIGHT ) {
741                                if ( maxlen > 1 ) {
742                                   /* We have the dim level - handle it here */
743                                   x10state_update_func(buf + i, &launchp);
744                                   level = buf[i+1];
745                                   defer_dim = 0;
746                                   i++;
747                                }
748 			       else {
749                                   /* Otherwise, defer until we've got the dim level */
750                                   newbuf[0] = buf[i];
751                                   defer_dim = 1;
752                                }
753                             }
754 			    else if ( funcbits == PRESET1 || funcbits == PRESET2)  {
755 			        func = "Preset";
756                                 x10state_update_func(buf + i, &launchp);
757 
758                                 predim = rev_low_nybble((buf[i] & 0xF0u) >> 4) + 1;
759 
760 			        if ( funcbits == PRESET2 )
761 			           predim += 16;
762 
763                                 fdata = predim;
764 			    }
765                             else if ( funcbits == EXTCODE )  {
766                                 if ( maxlen >= 4 )  {
767                                     /* Buffer looks OK. (Sometimes it gets  */
768                                     /* garbled when ext code functions are  */
769                                     /* received by a firmware 1 interface.) */
770                                     unit = code2unit(buf[i+1] & 0x0fu);
771 				    subunit = (buf[i+1] & 0xf0u) >> 4;
772                                     bitmap = 1 << (buf[i+1] & 0x0fu);
773                                     xdata = buf[i+2];
774                                     xcmd = buf[i+3];
775                                     xtype = (xcmd & 0xf0u) >> 4;
776                                     if ( xtype == 3 ) {
777                                        x10state_update_ext3func(buf + i, &launchp);
778                                     }
779 #ifdef HASEXT0
780                                     else if ( xtype == 0 ) {
781                                        x10state_update_ext0func(buf + i, &launchp);
782                                     }
783 #endif
784                                     else {
785                                        x10state_update_extotherfunc(buf + i, &launchp);
786                                     }
787                                     i += 3;
788                                 }
789                                 else  {
790                                     /* Garbled buffer - dump it */
791                                     unit = 0;
792                                     bitmap = 0;
793                                     xdata = 0;
794                                     xcmd = 0xff;
795                                     i = to_read;
796                                 }
797                             }
798                             else {
799                                 x10state_update_func(buf + i, &launchp);
800                             }
801 
802 
803 			    if ( showdata )  {
804 
805                                 hcode = hc2code(hc);
806                                 squelch = x10state[hcode].squelch;
807                                 if ( squelch != 0 && (x10state[hcode].lastactive & squelch) == 0 ) {
808                                    fprintf(fdsout, "%s rcvi addr unit     %3d : hu %c%-2d (%s)\n",
809                                       datstrf(), code2unit(single_bmap_unit(squelch)),
810                                       hc, code2unit(single_bmap_unit(squelch)), lookup_label(hc, squelch) );
811                                    x10state[hcode].squelch = squelch = 0;
812                                 }
813                                 else if ( squelch != 0 && ((squelch & x10state[hcode].state[ChgState]) || launchp >= 0) ) {
814                                    fprintf(fdsout, "%s rcvi addr unit     %3d : hu %c%-2d (%s)\n",
815                                       datstrf(), code2unit(single_bmap_unit(squelch)),
816                                       hc, code2unit(single_bmap_unit(squelch)), lookup_label(hc, squelch) );
817                                    x10state[hcode].squelch = squelch = 0;
818                                 }
819 
820 
821 
822 				if ( (funcbits == DIM || funcbits == BRIGHT) && squelch == 0 ) {
823                                     if ( !defer_dim )
824                                         fprintf(fdsout, "%s rcvi func %12s : hc %c %s %%%02.0f [%d]\n",
825                                            datstrf(), funclabel[funcbits], toupper((int)hc),
826                                            ((funcbits == DIM) ? "dim" : "bright"),
827                                            100.*(float)level/210., level);
828                                 }
829 				else if ( (funcbits == PRESET1 || funcbits == PRESET2) && squelch == 0 ) {
830 				    fprintf(fdsout, "%s rcvi func %12s : level %d\n",
831 					    datstrf(), func, predim);
832                                     if ( i_am_monitor &&
833                                          configp->rcs_temperature & (1 << hc2code(lasthc)) ) {
834                                        /* Special funcs for RCS compatible thermometers */
835                                        if ( lastunit > 10 )  {
836                                           temperat = -60 + (predim - 1) + 32 * (lastunit - 11);
837 					  sprintf(minibuf, "Temperature = %d", temperat);
838                                           fprintf(fdsout, "%s %-22s : hu %c0  (%s)\n",
839                                             datstrf(), minibuf, toupper((int)lasthc), lookup_label(lasthc, 0));
840                                        }
841                                        else if ( lastunit == 6 && predim < sizeof(rcs_status) / sizeof(*rcs_status) + 1 ) {
842                                           fprintf(fdsout, "%s %-22s : hu %c0  (%s)\n",
843                                             datstrf(), rcs_status[predim - 1], toupper((int)lasthc),
844                                                                    lookup_label(lasthc, 0));
845                                        }
846                                     }
847 				}
848                                 else if ( funcbits == EXTCODE && squelch == 0 )  {
849 			            char tmp[10], stmp[16];
850 			            sprintf(tmp, "%d", unit);
851                                     bitmap = 1 << unit2code(unit);
852 				    if ( subunit == 0 )
853 				       stmp[0] = '\0';
854 				    else
855 				       sprintf(stmp, " subunit %02d", subunit);
856 
857                                     if ( xcmd == 0x31 ) {
858                                        if ( xdata & 0xc0u ) {
859                                           fprintf(fdsout,
860                                             "%s rcvi func      xPreset : hu %c%-2d%s level %d ramp %d (%s)\n",
861                                             datstrf(), hc, unit, stmp, xdata & 0x3f, (xdata & 0xc0) >> 6,
862                                             lookup_label(hc, bitmap));
863                                        }
864                                        else {
865                                           fprintf(fdsout,
866                                             "%s rcvi func      xPreset : hu %c%-2d%s level %d (%s)\n",
867                                             datstrf(), hc, unit, stmp, xdata, lookup_label(hc, bitmap));
868                                        }
869                                     }
870 				    else if ( xcmd == 0x3b )
871                                        fprintf(fdsout, "%s rcvi func      xConfig : hc %c mode=%d\n",
872                                            datstrf(), hc, xdata);
873                                     else if ( xcmd == 0x33 )
874                                        fprintf(fdsout, "%s rcvi func       xAllOn : hc %c\n",
875                                            datstrf(), hc);
876                                     else if ( xcmd == 0x34 )
877                                        fprintf(fdsout, "%s rcvi func      xAllOff : hc %c\n",
878                                            datstrf(), hc);
879                                     else if ( xcmd == 0x37 ) {
880                                        if ( (xdata & 0x30u) == 0 ) {
881                                           fprintf(fdsout, "%s rcvi func   xStatusReq : hu %c%-2d%s (%s)\n",
882                                               datstrf(), hc, unit, stmp, lookup_label(hc, bitmap));
883                                        }
884                                        else if ( (xdata & 0x30u) == 0x10 ) {
885                                           fprintf(fdsout, "%s rcvi func     xPowerUp : hu %c%-2d%s (%s)\n",
886                                               datstrf(), hc, unit, stmp, lookup_label(hc, bitmap));
887                                        }
888                                        else if ( (xdata & 0x30u) == 0x20 ) {
889                                           fprintf(fdsout, "%s rcvi func   xGrpStatus : hu %c%-2d%s group %d (%s)\n",
890                                               datstrf(), hc, unit, stmp, (xdata & 0xc0u) >> 6, lookup_label(hc, bitmap));
891                                        }
892                                        else {
893                                           fprintf(fdsout, "%s rcvi func   xGrpStatus : hu %c%-2d%s group %d.%-2d (%s)\n",
894                                               datstrf(), hc, unit, stmp, (xdata & 0xc0u) >> 6, (xdata & 0x0fu) + 1, lookup_label(hc, bitmap));
895                                        }
896                                     }
897                                     else if ( xcmd == 0x38 ) {
898                                        if ( xdata & 0x40u )
899                                            fprintf(fdsout, "%s rcvi func   xStatusAck : hu %c%-2d%s Switch %-3s %s (%s)\n",
900                                                datstrf(), hc, unit, stmp, ((xdata & 0x3fu) ? "On " : "Off"),
901                                                ((xdata & 0x80u) ? "LoadOK" : "NoLoad"),
902                                                lookup_label(hc, bitmap));
903                                        else
904                                            fprintf(fdsout, "%s rcvi func   xStatusAck : hu %c%-2d%s Lamp level %d, %s (%s)\n",
905                                                datstrf(), hc, unit, stmp, xdata & 0x3fu,
906                                                ((xdata & 0x80u) ? "BulbOK" : "NoBulb"),
907                                                lookup_label(hc, bitmap));
908                                     }
909                                     else if ( xcmd == 0x30 ) {
910                                        if ( (xdata & 0x20u) == 0 ) {
911                                           fprintf(fdsout, "%s rcvi func      xGrpAdd : hu %c%-2d%s group %d (%s)\n",
912                                              datstrf(), hc, unit, stmp, (xdata & 0xc0u) >> 6, lookup_label(hc, bitmap));
913 
914                                        }
915                                        else {
916                                           fprintf(fdsout, "%s rcvi func      xGrpAdd : hu %c%-2d%s group %d.%-2d (%s)\n",
917                                              datstrf(), hc, unit, stmp, (xdata & 0xc0u) >> 6, (xdata & 0x0fu) + 1, lookup_label(hc, bitmap));
918                                        }
919                                     }
920                                     else if ( xcmd == 0x32 ) {
921                                        fprintf(fdsout, "%s rcvi func   xGrpAddLvl : hu %c%-2d%s group %d level %d (%s)\n",
922                                           datstrf(), hc, unit, stmp, (xdata & 0xc0u) >> 6, xdata & 0x3fu, lookup_label(hc, bitmap));
923                                     }
924                                     else if ( xcmd == 0x35 ) {
925                                        if ( (xdata & 0x30) == 0 ) {
926                                           fprintf(fdsout, "%s rcvi func      xGrpRem : hu %c%-2d%s group(s) %s (%s)\n",
927                                              datstrf(), hc, unit, stmp, linmap2list(xdata & 0x0f), lookup_label(hc, bitmap));
928                                        }
929                                        else {
930                                           fprintf(fdsout, "%s rcvi func   xGrpRemAll : hc %c group(s) %s\n",
931                                              datstrf(), hc, linmap2list(xdata & 0x0f));
932 
933                                        }
934                                     }
935                                     else if ( xcmd == 0x36 ) {
936                                        if ( (xdata & 0x30u) == 0 ) {
937                                           fprintf(fdsout, "%s rcvi func     xGrpExec : hc %c group %d\n",
938                                              datstrf(), hc, (xdata & 0xc0u) >> 6);
939                                        }
940                                        else if ( (xdata & 0x30u) == 0x20u ) {
941                                           fprintf(fdsout, "%s rcvi func     xGrpExec : hc %c group %d.%-2d\n",
942                                              datstrf(), hc, (xdata & 0xc0u) >> 6, (xdata & 0x0fu) + 1);
943                                        }
944                                        else if ( (xdata & 0x30u) == 0x10u ) {
945                                           fprintf(fdsout, "%s rcvi func      xGrpOff : hc %c group %d\n",
946                                              datstrf(), hc, (xdata & 0xc0u) >> 6);
947                                        }
948                                        else {
949                                           fprintf(fdsout, "%s rcvi func      xGrpOff : hc %c group %d.%-2d\n",
950                                              datstrf(), hc, (xdata & 0xc0u) >> 6, (xdata & 0x0fu) + 1);
951                                        }
952                                     }
953                                     else if ( xcmd == 0x39 ) {
954                                        fprintf(fdsout, "%s rcvi func      xGrpAck : hu %c%-2d%s group %d level %d (%s)\n",
955                                           datstrf(), hc, unit, stmp, (xdata & 0xc0) >> 6, xdata & 0x3fu, lookup_label(hc, bitmap));
956                                     }
957                                     else if ( xcmd == 0x3A ) {
958                                        fprintf(fdsout, "%s rcvi func     xGrpNack : hu %c%-2d%s group %d (%s)\n",
959                                           datstrf(), hc, unit, stmp, (xdata & 0xc0) >> 6, lookup_label(hc, bitmap));
960                                     }
961                                     else if ( xcmd == 0x3C ) {
962                                        if ( (xdata & 0x30u) == 0 ) {
963                                           fprintf(fdsout, "%s rcvi func      xGrpDim : hc %c group %d\n",
964                                              datstrf(), hc, (xdata & 0xc0u) >> 6);
965                                        }
966                                        else if ( (xdata & 0x30u) == 0x10 ) {
967                                           fprintf(fdsout, "%s rcvi func   xGrpBright : hc %c group %d\n",
968                                              datstrf(), hc, (xdata & 0xc0u) >> 6);
969                                        }
970                                        else if ( (xdata & 0x30u) == 0x20 ) {
971                                           fprintf(fdsout, "%s rcvi func      xGrpDim : hc %c group %d.%-2d\n",
972                                              datstrf(), hc, (xdata & 0xc0u) >> 6, (xdata & 0x0fu) + 1);
973                                        }
974                                        else {
975                                           fprintf(fdsout, "%s rcvi func   xGrpBright : hc %c group %d.%-2d\n",
976                                              datstrf(), hc, (xdata & 0xc0u) >> 6, (xdata & 0x0fu) + 1);
977                                        }
978 
979                                     }
980                                     else if ( xcmd == 0x01 )
981                                        fprintf(fdsout, "%s rcvi func    shOpenLim : hu %c%-2d%s level %d (%s)\n",
982                                            datstrf(), hc, unit, stmp, xdata, lookup_label(hc, bitmap));
983 				    else if ( xcmd == 0x03 )
984                                        fprintf(fdsout, "%s rcvi func       shOpen : hu %c%-2d%s level %d (%s)\n",
985                                            datstrf(), hc, unit, stmp, xdata, lookup_label(hc, bitmap));
986 				    else if ( xcmd == 0x02 )
987                                        fprintf(fdsout, "%s rcvi func     shSetLim : hu %c%-2d%s level %d (%s)\n",
988                                            datstrf(), hc, unit, stmp, xdata, lookup_label(hc, bitmap));
989                                     else if ( xcmd == 0x04 )
990                                        fprintf(fdsout, "%s rcvi func    shOpenAll : hc %c\n",
991                                            datstrf(), hc);
992                                     else if ( xcmd == 0x0B )
993                                        fprintf(fdsout, "%s rcvi func   shCloseAll : hc %c\n",
994                                            datstrf(), hc);
995 
996                                     else if ( xcmd == 0xff )
997                                        fprintf(fdsout, "%s rcvi func      ExtCode : Incomplete xcode in buffer.\n",
998                                                datstrf());
999                                     else  {
1000                                        fprintf(fdsout, "%s rcvi func     xFunc %02x : hu %c%-2d%s data=0x%02x (%s)\n",
1001                                            datstrf(), xcmd, hc, unit, stmp, xdata, lookup_label(hc, bitmap));
1002                                     }
1003                                 }
1004                                 else {
1005                                    hcode = hc2code(hc);
1006                                    squelch = x10state[hcode].squelch;
1007                                    if ( squelch == 0 ) {
1008                                       fprintf(fdsout, "%s rcvi func %12s : hc %c\n",
1009 					 datstrf(), func, hc);
1010                                    }
1011 
1012                                    if ( funcbits == 8 && i_am_state && configp->ack_hails == YES ) {
1013                                       acknowledge_hail();
1014                                    }
1015 				}
1016                                 x10state[hcode].squelch = 0;
1017 
1018 			    }
1019 
1020                             if ( special_func > 0 ) {
1021                                if( (funcbits == PRESET1 || funcbits == PRESET2) ) {
1022                                   if ( lastunit > 10 ) {
1023                                      temperat = -60 + (predim - 1) + 32 * (lastunit - 11);
1024                                      fprintf(fdsout, "%s Temperature = %-3d   : hu %c0  (%s)\n",
1025                                           datstrf(), temperat, lasthc, lookup_label(lasthc, 0));
1026                                   }
1027                                   else if ( lastunit == 6 && predim < 9 ) {
1028                                      fprintf(fdsout, "%s %s : hu %c0  (%s)\n",
1029                                          datstrf(), rcs_status[predim - 1], toupper((int)lasthc),
1030                                                                    lookup_label(lasthc, 0));
1031                                   }
1032                                }
1033                             }
1034                         }
1035 			else {
1036                             /* an address byte was received */
1037                             signal_source = RCVI;
1038 			    hcode = (buf[i] & 0xF0u) >> 4;
1039                             hc = code2hc(hcode);
1040 			    unit = code2unit( buf[i] & 0x0Fu) ;
1041 	                    hexaddr = buf[i];
1042                             bitmap = 1 << (buf[i] & 0x0fu);
1043                             lasthc = hc;
1044                             lastunit = unit;
1045                             x10state_update_addr(buf[i], &launchp);
1046 			    x10state_update_sticky_addr(buf[i]);
1047 
1048 
1049                             if ( showdata ) {
1050                                squelch = x10state[hcode].squelch;
1051                                if ( squelch == 0 ) {
1052                                   fprintf(fdsout, "%s rcvi addr unit     %3d : hu %c%-2d (%s)\n",
1053 				     datstrf(), unit, hc, unit, lookup_label(hc, bitmap) );
1054                                }
1055                                else if ( squelch != 0  && squelch != bitmap ) {
1056                                   /* Different address - display deferred squelch address and cancel it */
1057                                   x10state[hcode].squelch = 0;
1058                                   fprintf(fdsout, "%s rcvi addr unit     %3d : hu %c%-2d (%s)\n",
1059                                       datstrf(), code2unit(single_bmap_unit(squelch)), hc, code2unit(single_bmap_unit(squelch)), lookup_label(hc, squelch) );
1060                                   fprintf(fdsout, "%s rcvi addr unit     %3d : hu %c%-2d (%s)\n",
1061 				      datstrf(), unit, hc, unit, lookup_label(hc, bitmap) );
1062                                }
1063                             }
1064 			}
1065 
1066 			fflush(fdsout);
1067 
1068                         if ( launchp >= 0 && i_am_state) {
1069                             launch_scripts(&launchp);
1070                         }
1071 		    }
1072 		    fflush(fdsout);
1073 		}
1074 	    }
1075 	    else {
1076 		if (verbose)
1077                    fprintf(fdsout, "%s Bytes received = %d; the interface didn't answer a getinfo response.\n", datstrf(), n);
1078                 else
1079                    fprintf(fdsout, "%s The interface didn't answer a getinfo response.\n", datstrf());
1080 	    }
1081 	}
1082         else if ( buf[0] == 0xa5 && showdata )  {
1083             /* Device experienced an AC power interruption */
1084             if ( configp->device_type & DEV_CM10A )
1085                fprintf(fdsout, "%s CM10A experienced an AC power interruption. %s",
1086                     datstrf(), "It requested a restart.\n");
1087             else
1088 	       fprintf(fdsout, "%s CM11A experienced an AC power interruption. %s",
1089 	            datstrf(), "It requested a time update.\n");
1090 	}
1091 	else if ( buf[0] == 0x5b ) {
1092            /* The CM11A is reporting a macro execution */
1093 	   to_read = 2;
1094 	   n = xread(sptty, buf, to_read, timeout);
1095 	   if ( showdata ) {
1096               mac_addr = ((buf[0] & 0x07u) << 8) + buf[1];
1097               /* Get macro label (or "Unknown") and saved image checksum */
1098               macfound = lookup_macro(mac_addr, maclabel, &ichksum);
1099 
1100               if ( buf[0] & 0x70u ) {
1101                  /* The macro was executed by a Trigger */
1102                  if ( macfound == 1 && ichksum != -1 && loadcheck_image(ichksum) ) {
1103 
1104                     /* Determine and display the inferred trigger. */
1105                     /* Launch script if warranted.                 */
1106                     tag = (buf[0] & 0x70u) >> 4;
1107                     signal_source = RCVT;
1108                     display_trigger(datstrf(), mac_addr, tag);
1109 
1110                     /* Announce the execution of the macro */
1111                     fprintf(fdsout, "%s Trigger executed macro : %s, address 0x%03x\n",
1112                                        datstrf(), maclabel, mac_addr);
1113 
1114                     /* Decipher and display macro elements from image file. */
1115                     /* Launch script(s) if warranted.                       */
1116                     signal_source = SNDT;
1117                     expand_macro(datstrf(), mac_addr, TRIGGER_EXEC);
1118                  }
1119                  else {
1120                     fprintf(fdsout, "%s Trigger executed macro : %s, address 0x%03x\n",
1121                                        datstrf(), maclabel, mac_addr);
1122                  }
1123               }
1124               else  {
1125                  /* The macro was executed by a Timer */
1126                  if ( macfound == 1 && ichksum != -1 && loadcheck_image(ichksum) ) {
1127 
1128                     /* Announce the execution of the macro */
1129                     fprintf(fdsout, "%s Timer executed macro   : %s, address 0x%03x\n",
1130                                  datstrf(), maclabel, mac_addr);
1131 
1132                     /* Decipher and display macro elements from image file */
1133                     /* and launch script(s) if warranted.                  */
1134                     signal_source = SNDM;
1135                     expand_macro(datstrf(), mac_addr, TIMER_EXEC);
1136                  }
1137                  else {
1138                     fprintf(fdsout, "%s Timer executed macro   : %s, address 0x%03x\n",
1139                                        datstrf(), maclabel, mac_addr);
1140                  }
1141               }
1142            }
1143 	}
1144 	else if ( buf[0] == ((configp->ring_ctrl == DISABLE) ? 0xdb : 0xeb) && waitflag ) {
1145 	   waitflag = 0;
1146 	}
1147 	else if ( !(buf[0] == 0x55 && n == 1) )  {
1148             /* There's some sort of timing problem with the 0x55 ("ready to  */
1149             /* receive") signal from the interface after a long bright/dim   */
1150             /* or extended command is sent.  Ignore it, but alert to other   */
1151             /* unknown values.                                               */
1152 	    fprintf(fdsout,
1153 	        "%s Poll received unknown value (%d bytes), leading byte = %0x\n",
1154 		datstrf(), n, buf[0]);
1155         }
1156 
1157         fflush(fdsout);
1158     }
1159     return 0;
1160 }
1161 
1162