1 // =====================================================================
2 //
3 // TOD_clock.cxx
4 //
5 // interface to tcpip application fdserver.tcl
6 //   fdserver is a multiple client tcpip server
7 //
8 // Copyright (C) 2016
9 //		Dave Freese, W1HKJ
10 //
11 // This file is part of fldigi.
12 //
13 // Fldigi is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // Fldigi is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
25 // =====================================================================
26 
27 #include <iostream>
28 #include <cmath>
29 #include <cstring>
30 #include <vector>
31 #include <list>
32 #include <stdlib.h>
33 
34 #include <FL/Fl_Text_Display.H>
35 #include <FL/Fl_Text_Buffer.H>
36 
37 #include "fl_digi.h"
38 #include "rigsupport.h"
39 #include "modem.h"
40 #include "trx.h"
41 #include "configuration.h"
42 #include "main.h"
43 #include "waterfall.h"
44 #include "macros.h"
45 #include "qrunner.h"
46 #include "debug.h"
47 #include "status.h"
48 #include "icons.h"
49 
50 #include "logsupport.h"
51 #include "fd_logger.h"
52 #include "fd_view.h"
53 
54 #include "confdialog.h"
55 
56 #include "timeops.h"
57 #include "nanoIO.h"
58 
59 LOG_FILE_SOURCE(debug::LOG_FD);
60 
61 using namespace std;
62 
63 static pthread_t TOD_thread;
64 static pthread_mutex_t TX_mutex     = PTHREAD_MUTEX_INITIALIZER;
65 static pthread_mutex_t time_mutex   = PTHREAD_MUTEX_INITIALIZER;
66 
67 static char ztbuf[20] = "20120602 123000";
68 static char ltbuf[20] = "20120602 123000";
69 
70 static struct timeval tx_start_val;
71 static struct timeval tx_last_val;
72 static struct timeval now_val;
73 
74 extern void xmtrcv_cb(Fl_Widget *, void *);
75 
76 static int tx_timeout = 0;
77 
78 static int macro_time = -1;
79 
kill_tx(void *)80 void kill_tx(void *)
81 {
82 	wf->xmtrcv->value(0);
83 	xmtrcv_cb(wf->xmtrcv, 0);
84 	fl_alert2("TX timeout expired!\nAre you awake?");
85 }
86 
service_deadman()87 void service_deadman()
88 {
89 	guard_lock txlock(&TX_mutex);
90 	if (!tx_timeout) return;
91 	if (--tx_timeout == 0) {
92 		Fl::awake(kill_tx);
93 	}
94 }
95 
start_deadman()96 void start_deadman()
97 {
98 	guard_lock txlock(&TX_mutex);
99 	tx_timeout = 60 * progdefaults.tx_timeout;
100 }
101 
stop_deadman()102 void stop_deadman()
103 {
104 	guard_lock txlock(&TX_mutex);
105 	tx_timeout = 0;
106 }
107 
start_macro_time()108 void start_macro_time()
109 {
110 	macro_time = 0;
111 }
112 
stop_macro_time()113 int stop_macro_time()
114 {
115 	return macro_time;
116 }
117 
tmval(void)118 const timeval tmval(void)
119 {
120 	struct timeval t1;
121 	{
122 		guard_lock lk(&time_mutex);
123 		gettimeofday(&t1, NULL);
124 	}
125 	return t1;
126 }
127 
zusec(void)128 const double zusec(void)
129 {
130 	struct timeval t1;
131 	{
132 		guard_lock lk(&time_mutex);
133 		gettimeofday(&t1, NULL);
134 	}
135 	double usecs = t1.tv_sec * 1000000L;
136 	usecs += t1.tv_usec;
137 	return usecs;
138 }
139 
zmsec(void)140 const unsigned long zmsec(void)
141 {
142 	struct timeval t1;
143 	{
144 		guard_lock lk(&time_mutex);
145 		gettimeofday(&t1, NULL);
146 	}
147 	unsigned long msecs = t1.tv_sec * 1000000L;
148 	msecs += t1.tv_usec;
149 	msecs /= 1000L;
150 	return msecs;
151 }
152 
zdate(void)153 const char* zdate(void)
154 {
155 	return ztbuf;
156 }
157 
ztime(void)158 const char* ztime(void)
159 {
160 	return ztbuf + 9;
161 }
162 
ldate(void)163 const char* ldate(void)
164 {
165 	return ltbuf;
166 }
167 
ltime(void)168 const char *ltime(void)
169 {
170 	return ltbuf + 9;
171 }
172 
zshowtime(void)173 const char* zshowtime(void) {
174 	static char s[5];
175 	strncpy(s, &ztbuf[9], 4);
176 	s[4] = 0;
177 	return (const char *)s;
178 }
179 
180 static char tx_time[20];
181 
182 static bool TOD_exit = false;
183 static bool TOD_enabled = false;
184 
185 static bool   tx_timer_active = false;
186 
show_tx_timer()187 void show_tx_timer()
188 {
189 	if (!tx_timer) return;
190 	if (progdefaults.show_tx_timer && tx_timer_active) {
191 		snprintf(tx_time, sizeof(tx_time),"%02d:%02d",
192 			(int)((now_val.tv_sec - tx_start_val.tv_sec)/60),
193 			(int)((now_val.tv_sec - tx_start_val.tv_sec) % 60 ));
194 		tx_timer->color(FL_DARK_RED);
195 		tx_timer->labelcolor(FL_YELLOW);
196 		tx_timer->label(tx_time);
197 		tx_timer->redraw_label();
198 		tx_timer->redraw();
199 	} else {
200 		tx_timer->color(FL_BACKGROUND_COLOR);
201 		tx_timer->labelcolor(FL_BACKGROUND_COLOR);
202 		tx_timer->redraw_label();
203 		tx_timer->redraw();
204 	}
205 }
206 
start_tx_timer()207 void start_tx_timer()
208 {
209 	tx_last_val = tx_start_val = now_val;
210 	tx_timer_active = true;
211 	REQ(show_tx_timer);
212 }
213 
stop_tx_timer()214 void stop_tx_timer()
215 {
216 	if (!tx_timer) return;
217 	tx_timer_active = false;
218 }
219 
update_tx_timer()220 void update_tx_timer()
221 {
222 	if (tx_last_val.tv_sec == now_val.tv_sec) return;
223 	tx_last_val = now_val;
224 	show_tx_timer();
225 	service_deadman();
226 	macro_time++;
227 }
228 
229 //void ztimer(void *)
show_ztimer()230 static void show_ztimer()
231 {
232 	if (!inpTimeOff1) return;
233 
234 	update_tx_timer();
235 
236 	inpTimeOff1->value(zshowtime());
237 	inpTimeOff2->value(zshowtime());
238 	inpTimeOff3->value(zshowtime());
239 	inpTimeOff1->redraw();
240 	inpTimeOff2->redraw();
241 	inpTimeOff3->redraw();
242 
243 }
244 
ztimer()245 static void ztimer()
246 {
247 	struct tm ztm, ltm;
248 	time_t t_temp;
249 
250 	t_temp=(time_t)now_val.tv_sec;
251 	gmtime_r(&t_temp, &ztm);
252 	if (!strftime(ztbuf, sizeof(ztbuf), "%Y%m%d %H%M%S", &ztm))
253 		memset(ztbuf, 0, sizeof(ztbuf));
254 	else
255 		ztbuf[8] = '\0';
256 
257 	localtime_r(&t_temp, &ltm);
258 	if (!strftime(ltbuf, sizeof(ltbuf), "%Y%m%d %H%M%S", &ltm))
259 		memset(ltbuf, 0, sizeof(ltbuf));
260 	else
261 		ltbuf[8] = '\0';
262 
263 	REQ(show_ztimer);
264 }
265 
266 //======================================================================
267 // TOD Thread loop
268 //======================================================================
TOD_loop(void * args)269 void *TOD_loop(void *args)
270 {
271 	SET_THREAD_ID(TOD_TID);
272 #define LOOP  250
273 	int cnt = 0;
274 	while(1) {
275 
276 		if (TOD_exit) break;
277 
278 		if (++cnt == 4) {
279 			guard_lock tmlock(&time_mutex);
280 			gettimeofday(&now_val, NULL);
281 			ztimer();
282 			cnt = 0;
283 		}
284 		REQ(nanoIO_read_pot);
285 		MilliSleep(LOOP);
286 	}
287 
288 // exit the TOD thread
289 	SET_THREAD_CANCEL();
290 	return NULL;
291 }
292 
293 //======================================================================
294 //
295 //======================================================================
TOD_init(void)296 void TOD_init(void)
297 {
298 	TOD_exit = false;
299 
300 	if (pthread_create(&TOD_thread, NULL, TOD_loop, NULL) < 0) {
301 		LOG_ERROR("%s", "pthread_create failed");
302 		return;
303 	}
304 
305 	LOG_INFO("%s", "Time Of Day thread started");
306 
307 	TOD_enabled = true;
308 }
309 
310 //======================================================================
311 //
312 //======================================================================
TOD_close(void)313 void TOD_close(void)
314 {
315 	if (!TOD_enabled) return;
316 
317 	TOD_exit = true;
318 	pthread_join(TOD_thread, NULL);
319 	TOD_enabled = false;
320 
321 	LOG_INFO("%s", "Time Of Day thread terminated. ");
322 
323 }
324 
325