1 // =====================================================================
2 //
3 // maclogger.cxx
4 //
5 // receive log data from maclogger udp broadcast message
6 //
7 // Copyright (C) 2016
8 // Dave Freese, W1HKJ
9 //
10 // This file is part of fldigi.
11 //
12 // Fldigi is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Fldigi is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
24 // =====================================================================
25
26 #include <iostream>
27 #include <cmath>
28 #include <cstring>
29 #include <vector>
30 #include <list>
31 #include <stdlib.h>
32
33 #include <FL/Fl_Text_Display.H>
34 #include <FL/Fl_Text_Buffer.H>
35
36 #include "rigsupport.h"
37 #include "modem.h"
38 #include "trx.h"
39 #include "fl_digi.h"
40 #include "configuration.h"
41 #include "main.h"
42 #include "waterfall.h"
43 #include "macros.h"
44 #include "qrunner.h"
45 #include "debug.h"
46 #include "status.h"
47 #include "icons.h"
48
49 #include "maclogger.h"
50
51 #include "confdialog.h"
52
53 LOG_FILE_SOURCE(debug::LOG_MACLOGGER);
54
55 using namespace std;
56
57 //======================================================================
58 // Socket MACLOGGER i/o used on all platforms
59 //======================================================================
60
61 pthread_t maclogger_thread;
62 pthread_t maclogger_rx_socket_thread;
63 pthread_mutex_t mclg_str_mutex = PTHREAD_MUTEX_INITIALIZER;
64 Socket *maclogger_socket = 0;
65
66 bool maclogger_enabled = false;
67 bool maclogger_exit = false;
68
69 string maclogger_ip_address= "";;
70 string maclogger_ip_port= "";;
71
72 string mclg_str = "";
73 int mclg_rxhz;
74 int mclg_txhz;
75 string mclg_band;
76 string mclg_mode;
77 string mclg_power;
78 string mclg_call;
79 string mclg_dxccnum;
80 string mclg_dxccstr;
81 string mclg_city;
82 string mclg_state;
83 string mclg_firstname;
84 string mclg_lastname;
85 string mclg_comment;
86 string mclg_bearing;
87 string mclg_longpath;
88 string mclg_distance;
89
90 //======================================================================
91 // MacLogger UDP string parsing
92 //======================================================================
93
get_str(string s)94 static string get_str(string s)
95 {
96 size_t p = s.find(":");
97 if (p == string::npos) return "";
98 s.erase(0, p+1);
99 p = s.find(",");
100 if (p == string::npos) p = s.find("]");
101 if (p == string::npos) return "";
102 string s2 = s.substr(0, p);
103 if (s2 == "(null)") return "";
104 return s2;
105 }
106
get_freq(string s)107 static int get_freq(string s)
108 {
109 string s2 = get_str(s);
110 size_t dpt = s2.find(".");
111 if (dpt == string::npos) return 0;
112 string sf = s2.substr(0, dpt);
113 string sm = s2.substr(dpt+1);
114 while(sm.length() < 6) sm.append("0");
115 sf.append(sm);
116 int fr = sf[0] - '0';
117 for (size_t n = 1; n < sf.length(); n++) {
118 fr *= 10;
119 fr += (sf[n] - '0');
120 }
121 //std::cout << "string: " << sf << ", int freq: " << fr << std::endl;
122 return fr;
123 }
124
maclogger_set_qsy()125 void maclogger_set_qsy()
126 {
127 long hz = mclg_rxhz;
128 if (hz <= 0 || !progdefaults.maclogger_spot_rx) hz = mclg_txhz;
129 if (hz <= 0) return;
130 sendFreq(hz);
131 wf->rfcarrier(hz);
132 wf->movetocenter();
133 show_frequency(hz);
134 }
135
maclogger_set_call()136 void maclogger_set_call()
137 {
138 inpCall->value(mclg_call.c_str());
139 inpCall->do_callback();
140 }
141
maclogger_set_name()142 void maclogger_set_name()
143 {
144 inpName->value(mclg_firstname.c_str());
145 inpName->do_callback();
146 }
147
maclogger_set_mode()148 void maclogger_set_mode()
149 {
150 // inpMode->value(mclg_mode.c_str());
151 // inpMode->do_callback();
152 }
153
maclogger_set_qth()154 void maclogger_set_qth()
155 {
156 inpQth->value(mclg_city.c_str());
157 inpQth->do_callback();
158 }
159
maclogger_set_state()160 void maclogger_set_state()
161 {
162 inpState->value(mclg_state.c_str());
163 inpState->do_callback();
164 }
165
maclogger_disp_report(const char * s)166 void maclogger_disp_report(const char * s)
167 {
168 txt_UDP_data->insert(s);
169 txt_UDP_data->redraw();
170 }
171
show_mac_strings()172 void show_mac_strings()
173 {
174 SET_THREAD_ID(MACLOGGER_TID);
175
176 if (mclg_txhz > 0) REQ(maclogger_set_qsy);
177 else if (mclg_rxhz > 0) REQ(maclogger_set_qsy);
178 if (!mclg_mode.empty()) REQ(maclogger_set_mode);
179 if (!mclg_call.empty()) REQ(maclogger_set_call);
180 if (!mclg_city.empty()) REQ(maclogger_set_qth);
181 if (!mclg_state.empty()) REQ(maclogger_set_state);
182 if (!mclg_firstname.empty()) REQ(maclogger_set_name);
183
184 // if (!mclg_power.empty())
185 // if (!mclg_band.empty())
186 // if (!mclg_lastname.empty())
187 // if (!mclg_comment.empty())
188 // if (!mclg_bearing.empty())
189 // if (!mclg_longpath.empty())
190 // if (!mclg_distance.empty())
191 // if (!mclg_dxccnum.empty())
192 // if (!mclg_dxccstr.empty())
193
194 }
195
parse_report(string str)196 void parse_report(string str)
197 {
198 size_t p;
199 mclg_rxhz = 0;
200 mclg_txhz = 0;
201 mclg_band.clear();
202 mclg_mode.clear();
203 mclg_power.clear();
204 mclg_call.clear();
205 mclg_dxccnum.clear();
206 mclg_dxccstr.clear();
207 mclg_city.clear();
208 mclg_state.clear();
209 mclg_firstname.clear();
210 mclg_lastname.clear();
211 mclg_comment.clear();
212 mclg_bearing.clear();
213 mclg_longpath.clear();
214 mclg_distance.clear();
215
216 if ((p = str.find("RxMHz:")) != string::npos)
217 mclg_rxhz = get_freq(str.substr(p));
218 if ((p = str.find("TxMHz:")) != string::npos)
219 mclg_txhz = get_freq(str.substr(p));
220 if ((p = str.find("Mode:")) != string::npos)
221 mclg_mode = get_str(str.substr(p));
222 if ((p = str.find("Call:")) != string::npos)
223 mclg_call = get_str(str.substr(p));
224 if ((p = str.find("city:")) != string::npos)
225 mclg_city = get_str(str.substr(p));
226 if ((p = str.find("state:")) != string::npos)
227 mclg_state = get_str(str.substr(p));
228 if ((p = str.find("first_name:")) != string::npos)
229 mclg_firstname = get_str(str.substr(p));
230
231 // if ((p = mclg_str.find("dxcc_num:")) != string::npos)
232 // mclg_dxccnum = get_str(mclg_str.substr(p));
233 // if ((p = mclg_str.find("dxcc_string:")) != string::npos)
234 // mclg_dxccstr = get_str(mclg_str.substr(p));
235 // if ((p = mclg_str.find("Power:")) != string::npos)
236 // mclg_power = get_str(mclg_str.substr(p));
237 // if ((p = mclg_str.find("Band:")) != string::npos)
238 // mclg_band = get_str(mclg_str.substr(p));
239 // if ((p = mclg_str.find("last_name:")) != string::npos)
240 // mclg_lastname = get_str(mclg_str.substr(p));
241 // if ((p = mclg_str.find("Comment:")) != string::npos)
242 // mclg_comment = get_str(mclg_str.substr(p));
243 // if ((p = mclg_str.find("Bearing:")) != string::npos)
244 // mclg_bearing = get_str(mclg_str.substr(p));
245 // if ((p = mclg_str.find("LongPath:")) != string::npos)
246 // mclg_longpath = get_str(mclg_str.substr(p));
247 // if ((p = mclg_str.find("Distance:")) != string::npos)
248 // mclg_distance = get_str(mclg_str.substr(p));
249
250 show_mac_strings();
251 }
252
parse_maclog()253 void parse_maclog()
254 {
255 size_t p1, p2;
256 string str;
257 static string srep;
258 while (!mclg_str.empty()) {
259 p1 = mclg_str.find("[");
260 if (p1 == string::npos) return;
261 if (p1 != 0) mclg_str.erase(0, p1);
262 p2 = mclg_str.find("]");
263 if (p2 == string::npos) return;
264
265 str = mclg_str.substr(0, p2 + 1);
266 srep = str;
267 srep.append("\n");
268 REQ(maclogger_disp_report, srep.c_str());
269
270 if (progdefaults.enable_maclogger_log) {
271 std::string pathname = TempDir;
272 pathname.append("maclogger_udp_strings.txt");
273 FILE *maclog = fl_fopen(pathname.c_str(), "a");
274 fprintf(maclog, "%s", srep.c_str());
275 fclose(maclog);
276 }
277
278 if ((progdefaults.capture_maclogger_radio &&
279 mclg_str.find("[Radio Report:") != std::string::npos) ||
280 (progdefaults.capture_maclogger_spot_tune &&
281 mclg_str.find("[SpotTune:") != std::string::npos) ||
282 (progdefaults.capture_maclogger_spot_report &&
283 mclg_str.find("[Spot Report:") != std::string::npos) ||
284 (progdefaults.capture_maclogger_log &&
285 mclg_str.find("[Log Report:") != std::string::npos) ||
286 (progdefaults.capture_maclogger_lookup &&
287 mclg_str.find("[Lookup Report") != std::string::npos) )
288 parse_report(str);
289
290 mclg_str.erase(0, p2 + 1);
291
292 MilliSleep(100);
293 }
294 }
295
296 //======================================================================
297 // uncomment to use UDP test strings
298 //
299 // #define TESTSTRINGS 1
300 //
301 //======================================================================
302
303 #ifdef TESTSTRINGS
304 string tstring[6] = {
305 "[Radio Report:RxMHz:24.96400, TxMHz:24.96400, Band:12M, Mode:USB, Power:5]",
306 "[SpotTune:RxMHz:3.5095, TxMHz:3.549525, Band:10M, Mode:USB]",
307 "[Log Report: Call:N2BJ, RxMHz:21.08580, TxMHz:21.08580, Band:15M, Mode:FSK, Power:5, dxcc_num:291, dxcc_string:United States, city:NEW LENOX, state:IL, first_name:Barry, last_name:COHEN]",
308 "[Spot Report: RxMHz:3.50300, TxMHz:3.50300, Band:80M, Mode:CW, Call:EP6T, dxcc_string:Iran, Comment:UP , TNX CARLO , GL]",
309 "[Rotor Report: Bearing:304.7, LongPath:0, Distance:0.0]",
310 "[Lookup Report:Call:YC8RBI, RxMHz:21.32500, Band:15M, Mode:USB, dxcc_num:327, dxcc_string:Indonesia, Bearing:328.1, city:SANGIHE ISLAND NORTH SULAWESI, state:(null), first_name:RICHARD, last_name:BYL ( ICHA )]"
311 };
312 int tnbr = 0;
313 #endif
314
get_maclogger_udp()315 void get_maclogger_udp()
316 {
317 #ifdef TESTSTRINGS
318 if (tnbr == 0) {
319 for (int n = 0; n < 6; n++) {
320 mclg_str = tstring[n];
321 parse_maclog();
322 }
323 tnbr = 1;
324 }
325 #else
326 if(!maclogger_socket) return;
327 if (!progdefaults.connect_to_maclogger) return;
328
329 char buffer[MACLOGGER_BUFFER_SIZE];
330 size_t count = 0;
331
332 memset(buffer, 0, sizeof(buffer));
333
334 try {
335 count = maclogger_socket->recvFrom(
336 (void *) buffer,
337 sizeof(buffer) - 1);
338 } catch (...) {
339 LOG_WARN("MAC_logger socket error");
340 count = 0;
341 }
342
343 if (count) {
344 mclg_str.append(buffer, count);
345 parse_maclog();
346 }
347 #endif
348 }
349
350 //======================================================================
351 //
352 //======================================================================
maclogger_loop(void * args)353 void *maclogger_loop(void *args)
354 {
355 SET_THREAD_ID(MACLOGGER_TID);
356
357 LOG_INFO("%s", "MAC_logger loop started. ");
358
359 while(1) {
360 for (int i = 0; i < 100; i++) {
361 MilliSleep(10);
362 if (maclogger_exit) break;
363 }
364 if (maclogger_exit) break;
365 get_maclogger_udp();
366 }
367 // exit the maclogger thread
368 SET_THREAD_CANCEL();
369 return NULL;
370 }
371
372 //======================================================================
373 //
374 //======================================================================
maclogger_start(void)375 bool maclogger_start(void)
376 {
377 maclogger_ip_address = "255.255.255.255";
378 maclogger_ip_port = "9932";
379
380 try {
381 maclogger_socket = new Socket(
382 Address( maclogger_ip_address.c_str(),
383 maclogger_ip_port.c_str(),
384 "udp") );
385 maclogger_socket->set_autoclose(true);
386 maclogger_socket->set_nonblocking(false);
387 maclogger_socket->bindUDP();
388 }
389 catch (const SocketException& e) {
390 LOG_ERROR(
391 "Could not resolve %s: %s",
392 maclogger_ip_address.c_str(),
393 e.what() );
394 return false;
395 }
396
397 return true;
398 }
399
400 //======================================================================
401 //
402 //======================================================================
maclogger_init(void)403 void maclogger_init(void)
404 {
405 maclogger_enabled = false;
406 maclogger_exit = false;
407
408 #ifndef TESTSTRINGS
409 if(!maclogger_start()) return;
410 LOG_INFO("%s", "UDP Init - OK");
411 #endif
412
413 if (pthread_create(&maclogger_thread, NULL, maclogger_loop, NULL) < 0) {
414 LOG_ERROR("MACLOGGER maclogger_thread: pthread_create failed");
415 return;
416 }
417
418 LOG_INFO("MACLOGGER thread started");
419
420 maclogger_enabled = true;
421 }
422
423 //======================================================================
424 //
425 //======================================================================
maclogger_close(void)426 void maclogger_close(void)
427 {
428 if (!maclogger_enabled) return;
429
430 if(maclogger_socket) {
431 maclogger_socket->shut_down();
432 maclogger_socket->close();
433 }
434
435 maclogger_exit = true;
436 pthread_join(maclogger_thread, NULL);
437
438 LOG_INFO("%s", "MAC_logger loop terminated. ");
439
440 maclogger_enabled = false;
441 #ifdef TESTSTRINGS
442 tnbr = 0;
443 #endif
444 }
445
446