1 /*----------------------------------------------------------------------------+
2  |                                                                            |
3  |            HEYU Support for External Power Line Sync                       |
4  |             Copyright 2005,2006 Charles W. Sullivan                        |
5  |                                                                            |
6  |                                                                            |
7  | As used herein, HEYU is a trademark of Daniel B. Suthers.                  |
8  | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc.               |
9  | The author is not affiliated with either entity.                           |
10  |                                                                            |
11  | Charles W. Sullivan                                                        |
12  | Co-author and Maintainer                                                   |
13  | Greensboro, North Carolina                                                 |
14  | Email ID: cwsulliv01                                                       |
15  | Email domain: -at- heyu -dot- org                                          |
16  |                                                                            |
17  +----------------------------------------------------------------------------*/
18 
19 /*
20  *   This program is free software: you can redistribute it and/or modify
21  *   it under the terms of the GNU General Public License as published by
22  *   the Free Software Foundation, either version 3 of the License, or
23  *   (at your option) any later version.
24  *
25  *   This program is distributed in the hope that it will be useful,
26  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
27  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  *   GNU General Public License for more details.
29  *
30  *   You should have received a copy of the GNU General Public License
31  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
32  *
33  */
34 
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <ctype.h>
39 #if 0
40 #include "x10.h"
41 #include "process.h"
42 #endif
43 
44 #ifdef        SCO
45 #define _SVID3 /* required for correct termio handling */
46 #undef  _IBCS2 /* conflicts with SVID3  */
47 #endif
48 
49 #include <time.h>
50 #include <unistd.h>
51 #include <signal.h>
52 
53 #ifdef LINUX
54 #include <asm/ioctls.h>
55 #   ifdef OLDLINUX
56 #include <linux/serial_reg.h>
57 #   endif
58 #include <linux/serial.h>
59 #include <sys/ioctl.h>
60 #include <unistd.h>
61 #include <syslog.h>
62 #else
63 #    if (defined(POSIX) || defined(FREEBSD) || defined(OPENBSD))
64 #include <sys/ttycom.h>
65 #    else
66 #         ifdef SCO
67 #include <sys/ttycom.h>
68 #         else
69 #              ifdef DARWIN
70 #include <sys/ttycom.h>
71 #              else
72 #include <sys/ttycom.h>
73 #              endif
74 #         endif
75 #    endif
76 #endif
77 
78 #if (defined(OSF) || defined(DARWIN) || defined(NETBSD))
79 #include <sys/ioctl.h>
80 #endif
81 
82 #ifdef HASSELECT
83 #include <sys/time.h>
84 #include <sys/types.h>
85 #endif
86 
87 #include "x10.h"
88 #include "process.h"
89 
90 #ifdef pid_t
91 #define PID_T pid_t
92 #else
93 #define PID_T long
94 #endif
95 
96 extern int verbose;
97 extern int sptty;
98 extern int tty;
99 extern int ttylock(), munlock();
100 extern PID_T lockpid( char * );
101 extern int i_am_relay;
102 
103 extern CONFIG config;
104 extern CONFIG *configp;
105 
106 static volatile unsigned long trigger_loopcount;
107 static volatile unsigned long countdown;
108 static volatile int dummy = 1;
109 
110 /*----------------------------------------------------------------------------+
111  | Millisecond timer using timing loop.                                       |
112  +----------------------------------------------------------------------------*/
msec_timer(unsigned long loopcount)113 static void msec_timer ( unsigned long loopcount )
114 {
115    countdown = loopcount;
116    while (dummy && countdown--);
117    return;
118 }
119 
120 
121 /*---------------------------------------------------------------+
122  | Optional wait for external sync trigger for dims/brights.     |
123  | A one millisec timing loop must be configured and additional  |
124  | hardware is required as follows:                              |
125  |                                                               |
126  | The output of a 4 to 8 VAC (RMS) transformer connected from   |
127  | the Carrier Detect to Signal Ground pins of the serial port   |
128  | (DB9 pins 1 and 5 respectively) allows Heyu to distinguish    |
129  | between the positive and negative half-cycles of the AC power |
130  | line and trigger the command to begin exclusively on either   |
131  | the rising or falling zero crossing, depending on the         |
132  | relative phase of the voltages on the CD pin and the AC line. |
133  +---------------------------------------------------------------*/
wait_external_trigger(int mode)134 int wait_external_trigger ( int mode )
135 {
136    int j, status, retcode, jmax = 20;
137 
138    if ( mode == NO_SYNC )
139       return 0;
140 
141    if ( configp->timer_loopcount == 0 ) {
142       fprintf(stderr, "No timing loop has been configured - trigger ignored.\n");
143       return 1;
144    }
145 
146    /* Timing loopcount for 1 millisecond */
147    trigger_loopcount = configp->timer_loopcount / 1000L;
148 
149    if ( mode == RISE_SYNC ) {
150       /* Rising zero-crossing triggering */
151       /* Wait until the Carrier Detect line becomes active */
152       for ( j = 0; j < jmax; j++ ) {
153          retcode = ioctl(tty, TIOCMGET, &status);
154          if ( status & TIOCM_CD )
155             break;
156          msec_timer(trigger_loopcount);
157       }
158       if ( j >= jmax ) {
159          fprintf(stderr, "No trigger detected.\n");
160          return 1;
161       }
162 
163       /* Now wait until it just becomes inactive */
164       for ( j = 0; j < jmax; j++ ) {
165          retcode = ioctl(tty, TIOCMGET, &status);
166          if ( !(status & TIOCM_CD) )
167             break;
168          msec_timer(trigger_loopcount);
169       }
170    }
171    else {
172       /* Falling zero-crossing triggering */
173       /* Wait until the Carrier Detect line becomes inactive */
174       for ( j = 0; j < jmax; j++ ) {
175          retcode = ioctl(tty, TIOCMGET, &status);
176          if ( !(status & TIOCM_CD) )
177             break;
178          msec_timer(trigger_loopcount);
179       }
180       /* Now wait until it just becomes active */
181       for ( j = 0; j < jmax; j++ ) {
182          retcode = ioctl(tty, TIOCMGET, &status);
183          if ( status & TIOCM_CD )
184             break;
185          msec_timer(trigger_loopcount);
186       }
187       if ( j >= jmax ) {
188          fprintf(stderr, "No trigger detected.\n");
189          return 1;
190       }
191    }
192 
193    /* Wait an additional few milliconds to make   */
194    /* sure we're out of the zero crossing region  */
195    msec_timer(2 * trigger_loopcount);
196 
197    return 0;
198 }
199 
200