1 // =====================================================================
2 //
3 // n3fjp_logger.cxx
4 //
5 // interface to multiple n3fjp tcpip logbook services
6 //
7 // Copyright (C) 2016
8 // Dave Freese, W1HKJ
9 // Dave Anderson, KA3PMW
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 <sstream>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <time.h>
33 #include <cmath>
34 #include <cstring>
35 #include <vector>
36 #include <list>
37 #include <stdlib.h>
38 #include <time.h>
39
40 #include <FL/Fl_Text_Display.H>
41 #include <FL/Fl_Text_Buffer.H>
42
43 #include "threads.h"
44 #include "socket.h"
45
46 #include "rigsupport.h"
47 #include "modem.h"
48 #include "trx.h"
49 #include "fl_digi.h"
50 #include "configuration.h"
51 #include "main.h"
52 #include "waterfall.h"
53 #include "macros.h"
54 #include "qrunner.h"
55 #include "debug.h"
56 #include "status.h"
57 #include "icons.h"
58 #include "logsupport.h"
59 #include "n3fjp_logger.h"
60 #include "confdialog.h"
61 #include "rigsupport.h"
62 #include "contest.h"
63 #include "timeops.h"
64
65 LOG_FILE_SOURCE(debug::LOG_N3FJP);
66
67 using namespace std;
68
69 static void send_log_data();
70
71 //======================================================================
72 // Socket N3FJP i/o used on all platforms
73 //======================================================================
74
75 pthread_t n3fjp_thread;
76 pthread_t n3fjp_rx_socket_thread;
77 Socket *n3fjp_socket = 0;
78
79 pthread_mutex_t n3fjp_mutex = PTHREAD_MUTEX_INITIALIZER;
80 pthread_mutex_t send_this_mutex = PTHREAD_MUTEX_INITIALIZER;
81 pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER;
82 pthread_mutex_t n3fjp_socket_mutex = PTHREAD_MUTEX_INITIALIZER;
83
84 static string send_this = "";
85 static string pathname;
86 static stringstream result;
87
88 bool n3fjp_connected = false;
89 bool n3fjp_enabled = false;
90 bool n3fjp_exit = false;
91
92 string n3fjp_ip_address = "";
93 string n3fjp_ip_port = "";
94
95 string n3fjp_rxbuffer;
96 string connected_to;
97
98 enum {UNKNOWN, N3FJP, FLDIGI};
99
100 bool n3fjp_bool_add_record = false;
101 int n3fjp_has_xcvr_control = UNKNOWN;
102
103 string tracked_freq = "";
104 int tracked_mode = -1;
105
106 enum {
107 FJP_NONE,
108 FJP_ACL, // Amateur Contact Log
109 FJP_FD, // ARRL Field Day
110 FJP_WFD, // ARRL Winter Field Day
111 FJP_KD, // ARRL Kids Day
112 FJP_ARR, // ARRL Rookie Roundup
113 FJP_RTTY, // ARRL Rtty
114 FJP_ASCR, // ARRL School Club Roundup
115 FJP_JOTA, // ARRL Jamboree On The Air
116 FJP_AICW, // ARRL International DX (CW)
117 FJP_SS, // ARRL November Sweepstakes
118 FJP_CQ_WPX, // CQ WPX
119 FJP_CQWWRTTY, // CQWW Rtty
120 FJP_CQWWDX, // CQWW DX
121 FJP_IARI, // Italian ARI International DX
122 FJP_NAQP, // North American QSO Party
123 FJP_NAS, // North American Sprint
124 FJP_1010, // Ten Ten
125 FJP_AIDX, // Africa All Mode
126 FJP_VHF, // VHF
127 FJP_WAE, // Worked All Europe
128 FJP_MDQP, // MD QSOP record format
129 FJP_7QP, // 7QP record format
130 FJP_NEQP, // New England QSO party record format
131 FJP_QP1, // QSO party record format 1 / 7QP contest
132 FJP_QP2, // QSO party record format 2
133 FJP_QP3, // QSO party record format 3
134 FJP_QP4, // QSO party record format 4
135 FJP_QP5, // QSO party record format 5
136 FJP_QP6 // QSO party record format 6
137 };
138
139 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
140 //
141 // "7QP", "B", "B", "B", "", "I", "", "", "SSCCC"
142 // "New Eng", "B", "B", "B", "", "I", "", "", "CCCSS"
143 // "MD SQP" "", "B", "B", "", "", "", "B", ""
144 // "QSOP 1" "B", "B", "B", "", "I", "", "", ""
145 // "QSOP 2" "B", "B", "B", "", "B", "", "", ""
146 // "QSOP 3" "", "B", "B", "B", "I", "", "", ""
147 // "QSOP 4" "", "B", "B", "", "I", "B", "", ""
148 // "QSOP 5" "B", "B", "B", "", "", "", "", ""
149 // "QSOP 6" "B", "B", "B", "", "I", "", "", ""
150
151 struct N3FJP_LOGGER {
152 const char *program;
153 int contest;
154 bool in_state;
155 } n3fjp_logger[] = {
156 {"No Contest", FJP_NONE, false},
157 {"Amateur Contact Log", FJP_ACL, false},
158 {"Africa All-Mode International", FJP_AIDX, false},
159 {"ARRL Field Day", FJP_FD, false},
160 {"Winter FD", FJP_WFD, false},
161 {"ARRL International DX", FJP_AICW, false},
162 {"Jamboree on the Air", FJP_JOTA, false},
163 {"ARRL Kids Day", FJP_KD, false},
164 {"ARRL Rookie Roundup", FJP_ARR, false},
165 {"ARRL RTTY Roundup", FJP_RTTY, false},
166 {"School Club Roundup", FJP_ASCR, false},
167 {"ARRL November Sweepstakes", FJP_SS, false},
168 {"BARTG RTTY Contest", FJP_NONE, false},
169 {"CQ WPX Contest Log", FJP_CQ_WPX, false},
170 {"CQ WW DX Contest Log", FJP_CQWWDX, false},
171 {"CQ WW DX RTTY Contest Log", FJP_CQWWRTTY, false},
172 {"Italian A.R.I. International DX", FJP_IARI, false},
173 {"NAQP", FJP_NAQP, false},
174 {"NA Sprint", FJP_NAS, false},
175 {"Ten Ten", FJP_1010, false},
176 {"VHF", FJP_VHF, false},
177 {"Worked All Europe", FJP_WAE, false},
178
179 {"Alabama QSO Party Contest Log", FJP_QP1, true},
180 {"ALQP Contest Log (Out of State)", FJP_QP1, false},
181 {"Arkansas QSO Party Contest Log", FJP_QP1, true},
182 {"ARQP Contest Log (Out of State)", FJP_QP1, false},
183 {"British Columbia QSO Party Contest Log", FJP_QP1, true},
184 {"BCQP Contest Log (Out of Province)", FJP_QP1, false},
185 {"Florida QSO Party Contest Log", FJP_QP1, true},
186 {"FLQP Contest Log (Out of State)", FJP_QP1, false},
187 {"Georgia QSO Party Contest Log", FJP_QP1, true},
188 {"GAQP Contest Log (Out of State)", FJP_QP1, false},
189 {"Hawaii QSO Party Contest Log", FJP_QP1, true},
190 {"HIQP Contest Log (Out of State)", FJP_QP1, false},
191 {"Iowa QSO Party Contest Log", FJP_QP1, true},
192 {"IAQP Contest Log (Out of State)", FJP_QP1, false},
193 {"Idaho QSO Party Contest Log", FJP_QP1, true},
194 {"IDQP Contest Log (Out of State)", FJP_QP1, false},
195 {"Illinois QSO Party Contest Log", FJP_QP1, true},
196 {"ILQP Contest Log (Out of State)", FJP_QP1, false},
197 {"Indiana QSO Party Contest Log", FJP_QP1, true},
198 {"INQP Contest Log (Out of State)", FJP_QP1, false},
199 {"Kansas QSO Party Contest Log", FJP_QP1, true},
200 {"KSQP Contest Log (Out of State)", FJP_QP1, false},
201 {"Kentucky QSO Party Contest Log", FJP_QP1, true},
202 {"KYQP Contest Log (Out of State)", FJP_QP1, false},
203 {"Louisiana QSO Party Contest Log", FJP_QP1, true},
204 {"LAQP Contest Log (Out of State)", FJP_QP1, false},
205 {"Missouri QSO Party Contest Log", FJP_QP1, true},
206 {"MOQP Contest Log (Out of State)", FJP_QP1, false},
207 {"Mississippi QSO Party Contest Log", FJP_QP1, true},
208 {"MSQP Contest Log (Out of State)", FJP_QP1, false},
209 {"North Dakota QSO Party Contest Log", FJP_QP1, true},
210 {"NDQP Contest Log (Out of State)", FJP_QP1, false},
211 {"New Jersey QSO Party Contest Log", FJP_QP1, true},
212 {"NJQP Contest Log (Out of State)", FJP_QP1, false},
213
214 {"Montana QSO Party Contest Log", FJP_QP2, true},
215 {"MTQP Contest Log (Out of State)", FJP_QP2, false},
216 {"Nebraska QSO Party Contest Log", FJP_QP2, true},
217 {"NEQP Contest Log (Out of State)", FJP_QP2, false},
218 {"New York QSO Party Contest Log", FJP_QP2, true},
219 {"NYQP Contest Log (Out of State)", FJP_QP2, false},
220 {"Ohio QSO Party Contest Log", FJP_QP2, true},
221 {"OHQP Contest Log (Out of State)", FJP_QP2, false},
222 {"Oklahoma QSO Party Contest Log", FJP_QP2, true},
223 {"OKQP Contest Log (Out of State)", FJP_QP2, false},
224 {"Ontario QSO Party Contest Log", FJP_QP2, true},
225 {"ONQP Contest Log (Out of Province)", FJP_QP2, false},
226 {"South Dakota QSO Party Contest Log", FJP_QP2, true},
227 {"SDQP Contest Log (Out of State)", FJP_QP2, false},
228 {"Tennessee QSO Party Contest Log", FJP_QP2, true},
229 {"TNQP Contest Log (Out of State)", FJP_QP2, false},
230 {"Texas QSO Party Contest Log", FJP_QP2, true},
231 {"TXQP Contest Log (Out of State)", FJP_QP2, false},
232 {"Vermont QSO Party Contest Log", FJP_QP2, true},
233 {"VTQP Contest Log (Out of State)", FJP_QP2, false},
234 {"Washington Salmon Run QSO Party Contest Log", FJP_QP2, true},
235 {"WAQP Contest Log (Out of State)", FJP_QP2, false},
236 {"Maine QSO Party Contest Log", FJP_QP2, true},
237 {"MEQP Contest Log (Out of State)", FJP_QP2, false},
238
239 {"Arizona QSO Party Contest Log", FJP_QP3, true},
240 {"AZQP Contest Log (Out of State)", FJP_QP3, false},
241 {"California QSO Party Contest Log", FJP_QP3, true},
242 {"CAQP Contest Log (Out of State)", FJP_QP3, false},
243 {"Michigan QSO Party Contest Log", FJP_QP3, true},
244 {"MIQP Contest Log (Out of State)", FJP_QP3, false},
245 {"Pennsylvania QSO Party Contest Log", FJP_QP3, true},
246 {"PAQP Contest Log (Out of State)", FJP_QP3, false},
247 {"Virginia QSO Party Contest Log", FJP_QP3, true},
248 {"VAQP Contest Log (Out of State)", FJP_QP3, false},
249
250 {"Colorado QSO Party Contest Log", FJP_QP4, true},
251 {"COQP Contest Log (Out of State)", FJP_QP4, false},
252 {"Maryland QSO Party Contest Log", FJP_MDQP, true},
253 {"MDQP Contest Log (Out of State)", FJP_MDQP, false},
254
255 {"Minnesota QSO Party Contest Log", FJP_QP4, true},
256 {"MNQP Contest Log (Out of State)", FJP_QP4, false},
257 {"New Mexico QSO Party Contest Log", FJP_QP4, true},
258 {"NMQP Contest Log (Out of State)", FJP_QP4, false},
259 {"North Carolina QSO Party Contest Log", FJP_QP6, true},
260 {"NCQP Contest Log (Out of State)", FJP_QP6, false},
261
262 {"South Carolina QSO Party Contest Log", FJP_QP5, true},
263 {"SCQP Contest Log (Out of State)", FJP_QP5, false},
264 {"West Virginia QSO Party Contest Log", FJP_QP5, true},
265 {"WVQP Contest Log (Out of State)", FJP_QP5, false},
266 {"Wisconsin QSO Party Contest Log", FJP_QP6, true},
267 {"WIQP Contest Log (Out of State)", FJP_QP6, false},
268
269 {"7QP QSO Party Contest Log", FJP_7QP, true},
270 {"7QP Contest Log (Out of Region)", FJP_7QP, false},
271
272 {"New England QSO Party Contest Log", FJP_NEQP, true},
273 {"NEQP Contest Log (Out of Region)", FJP_NEQP, false}
274 };
275
276 int n3fjp_contest = FJP_NONE;
277 bool n3fjp_in_state = false;
278
279 int n3fjp_wait = 0;
280
281 void adjust_freq(string s);
282 void n3fjp_parse_response(string s);
283 void n3fjp_disp_report(string s, string fm = "", bool tofile = true);
284 void n3fjp_send(string cmd, bool tofile = true);
285 void n3fjp_rcv(string &rx, bool tofile = true);
286 void n3fjp_send_freq_mode();
287 void n3fjp_clear_record();
288 void n3fjp_getfields();
289 void n3fjp_get_record(string call);
290 static string ParseField(string &record, string fieldtag);
291 static string ParseTextField(string &record, string fieldtag);
292 static string ucasestr(string s);
293 static void n3fjp_parse_data_stream(string buffer);
294 static void n3fjp_parse_calltab_event(string buffer);
295 string fmt_date(string date);
296 string fmt_time(string time);
297 string field_rec(string fld, string val);
298 static string n3fjp_tstmode();
299 static string n3fjp_opmode();
300 static string n3fjp_opband();
301 static string n3fjp_freq();
302 static void send_control(const string ctl, string val);
303 static void send_action(const string action);
304 static void send_command(const string command, string val="");
305 static void send_data();
306 static void send_data_norig();
307 void get_n3fjp_frequency();
308 void do_n3fjp_add_record_entries();
309 void n3fjp_set_freq(long f);
310 void n3fjp_set_ptt(int on);
311 void n3fjp_add_record(cQsoRec &record);
312 void n3fjp_parse_response(string tempbuff);
313 void n3fjp_rcv_data();
314 static bool connect_to_n3fjp_server();
315 void n3fjp_start();
316 void n3fjp_disconnect(bool clearlog = false);
317 void *n3fjp_loop(void *args);
318 void n3fjp_init(void);
319 void n3fjp_close(void);
320
321 //======================================================================
322 //
323 //======================================================================
strip(std::string s)324 static std::string strip(std::string s)
325 {
326 while (s.length() && (s[0] <= ' ')) s.erase(0,1);
327 while (s.length() && (s[s.length()-1] <= ' ')) s.erase(s.length()-1, 1);
328 return s;
329 }
330
331 //======================================================================
332 //
333 //======================================================================
334
adjust_freq(string sfreq)335 void adjust_freq(string sfreq)
336 {
337 long freq;
338 size_t pp = sfreq.find(".");
339 if (pp == string::npos) return;
340
341 while ((sfreq.length() - pp) < 7) sfreq.append("0");
342 sfreq.erase(pp,1);
343 freq = atol(sfreq.c_str());
344
345 if (freq == 0) return;
346
347 wf->rfcarrier(freq);
348 wf->movetocenter();
349 show_frequency(freq);
350
351 return;
352
353 if (progdefaults.N3FJP_sweet_spot) {
354 int afreq;
355 if (active_modem->get_mode() == MODE_CW) {
356 afreq = progdefaults.CWsweetspot;
357 }
358 else if (active_modem->get_mode() == MODE_RTTY) {
359 afreq = progdefaults.RTTYsweetspot;
360 }
361 else if (active_modem->get_mode() < MODE_SSB)
362 afreq = progdefaults.PSKsweetspot;
363 else {
364 wf->rfcarrier(freq);
365 wf->movetocenter();
366 show_frequency(freq);
367 return;
368 }
369 freq -= (wf->USB() ? afreq : -afreq);
370 wf->rfcarrier(freq);
371 wf->movetocenter();
372 show_frequency(freq);
373 return;
374 }
375 wf->rfcarrier(freq);
376 wf->movetocenter();
377 show_frequency(freq);
378 }
379
380 //======================================================================
381 //
382 //======================================================================
383 static notify_dialog *alert_window = 0;
set_connect_box()384 void set_connect_box()
385 {
386 if (!alert_window) alert_window = new notify_dialog;
387 box_n3fjp_connected->color(
388 n3fjp_connected ? FL_DARK_GREEN : FL_BACKGROUND2_COLOR);
389 box_n3fjp_connected->redraw();
390 if (n3fjp_connected) {
391 alert_window->notify(_("Connected to N3FJP logger"), 1.0);
392 REQ(show_notifier, alert_window);
393 REQ(update_main_title);
394 }
395 else {
396 progdefaults.CONTESTnotes = "";
397 listbox_contest->index(0);
398 listbox_QP_contests->index(0);
399 inp_contest_notes->value(progdefaults.CONTESTnotes.c_str());
400 }
401
402 }
403
n3fjp_print(string s)404 void n3fjp_print(string s)
405 {
406 if (bEXITING) return;
407
408 FILE *n3fjplog = fl_fopen(pathname.c_str(), "a");
409
410 time_t t = time(NULL);
411 struct tm stm;
412 (void)localtime_r(&t, &stm);
413 char sztime[12];
414 memset(sztime, 0, 11);
415 snprintf(sztime, sizeof(sztime), "[%02d:%02d:%02d] ", stm.tm_hour, stm.tm_min, stm.tm_sec);
416
417 s.insert(0, sztime);
418
419 if (n3fjplog) {
420 if (s[s.length()-1]!='\n')
421 fprintf(n3fjplog, "%s\n", s.c_str());
422 else
423 fprintf(n3fjplog, "%s", s.c_str());
424 fclose(n3fjplog);
425 }
426
427 LOG_VERBOSE("%s", s.c_str());
428 }
429
n3fjp_show(std::string s)430 void n3fjp_show(std::string s)
431 {
432 txt_N3FJP_data->insert(s.c_str());
433 txt_N3FJP_data->redraw();
434 }
435
n3fjp_disp_report(string s,string fm,bool tofile)436 void n3fjp_disp_report(string s, string fm, bool tofile)
437 {
438 guard_lock report_lock(&report_mutex);
439
440 if (s.empty()) return;
441
442 string report = fm.append("\n").append(s);
443
444 size_t p;
445 p = report.find("\r\n");
446 while (p != string::npos) {
447 report.replace(p,2,"<crlf>\n");
448 p = report.find("\r\n");
449 }
450 p = report.find("</CMD><CMD>");
451 while (p != string::npos) {
452 report.replace(p, 11, "</CMD>\n<CMD>");
453 p = report.find("</CMD><CMD>");
454 }
455
456 if (progdefaults.enable_N3FJP_log) REQ(n3fjp_show, report);
457
458 if (tofile) n3fjp_print(report);
459
460 }
461
462
n3fjp_send(string cmd,bool tofile)463 void n3fjp_send(string cmd, bool tofile)
464 {
465 guard_lock send_lock(&n3fjp_socket_mutex);
466 if (!n3fjp_socket) {
467 n3fjp_print("Socket not present");
468 return;
469 }
470 try {
471 if (cmd.empty()) return;
472 n3fjp_disp_report(cmd, "SEND:", tofile);
473 cmd.append("\r\n");
474 n3fjp_socket->send(cmd);
475
476 } catch (const SocketException& e) {
477 result.str("");
478 result << "n3fjp_send()::failed " << e.error() << " " << e.what();
479 n3fjp_print(result.str());
480 throw e;
481 } catch (...) { throw; }
482 }
483
n3fjp_rcv(string & rx,bool tofile)484 void n3fjp_rcv(string &rx, bool tofile)
485 {
486 guard_lock read_lock(&n3fjp_socket_mutex);
487 if (!n3fjp_socket) return;
488 try {
489 if (!n3fjp_socket->recv(rx))
490 rx.clear();
491 if (rx.empty()) return;
492 n3fjp_disp_report(rx, "RCVD:", tofile);
493 } catch (const SocketException& e) {
494 result.str("");
495 result << "n3fjp_rcv()::failed " << e.error() << " " << e.what();
496 n3fjp_print(result.str());
497 throw e;
498 } catch (...) { throw; }
499 }
500
n3fjp_send_freq_mode()501 void n3fjp_send_freq_mode()
502 {
503 if (!active_modem) return;
504
505 string cmd;
506 char szfreq[20];
507 double freq = atof(inpFreq->value()) / 1e3;
508 snprintf(szfreq, sizeof(szfreq), "%f", freq);
509
510 if (active_modem->get_mode() != tracked_mode ||
511 tracked_freq != szfreq) {
512 tracked_mode = active_modem->get_mode();
513 tracked_freq = szfreq;
514 cmd = "<CMD><SENDRIGPOLL><FREQ>";
515 cmd.append(tracked_freq);
516 cmd.append("</FREQ><MODE>");
517 cmd.append( mode_info[tracked_mode].adif_name );
518 cmd.append("</MODE></CMD>");
519 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
520 }
521 }
522
523 //======================================================================
524 //
525 //======================================================================
526
527 static cQsoRec rec;
528
n3fjp_sendRSTS(std::string s)529 static void n3fjp_sendRSTS(std::string s)
530 {
531 if (s.empty()) return;
532 try {
533 send_control("RSTS", s);
534 } catch (...) { throw; }
535 }
536
n3fjp_sendRSTR(std::string s)537 static void n3fjp_sendRSTR(std::string s)
538 {
539 if (s.empty()) return;
540 try {
541 send_control("RSTR", s);
542 } catch (...) { throw; }
543 }
544
send_call(std::string s)545 void send_call(std::string s)
546 {
547 try {
548 send_control("CALL", s.c_str());
549 } catch (const SocketException& e) {
550 result.str("");
551 result << "send_call()::failed " << e.error() << " " << e.what();
552 n3fjp_print(result.str());
553 throw e;
554 } catch (...) { throw; }
555 }
556
send_freq(std::string s)557 void send_freq(std::string s)
558 {
559 try {
560 send_control("FREQUENCY", s);
561 } catch (const SocketException& e) {
562 result.str("");
563 result << "send_freq()::failed " << e.error() << " " << e.what();
564 n3fjp_print(result.str());
565 throw e;
566 } catch (...) { throw; }
567 }
568
send_band(std::string s)569 void send_band(std::string s)
570 {
571 try {
572 send_control("BAND", s);
573 } catch (const SocketException& e) {
574 result.str("");
575 result << "send_band()::failed " << e.error() << " " << e.what();
576 n3fjp_print(result.str());
577 throw e;
578 } catch (...) { throw; }
579 }
580
send_mode(std::string s)581 void send_mode(std::string s)
582 {
583 try {
584 send_control("MODE", s);
585 } catch (const SocketException& e) {
586 result.str("");
587 result << "send_mode()::failed " << e.error() << " " << e.what();
588 n3fjp_print(result.str());
589 throw e;
590 } catch (...) { throw; }
591 }
592
send_state(std::string s)593 void send_state(std::string s)
594 {
595 try {
596 send_control("STATE", s);
597 } catch (const SocketException& e) {
598 result.str("");
599 result << "send_state()::failed " << e.error() << " " << e.what();
600 n3fjp_print(result.str());
601 throw e;
602 } catch (...) { throw; }
603 }
604
send_county(std::string s)605 void send_county(std::string s)
606 {
607 try {
608 send_control("COUNTYR", s);
609 } catch (const SocketException& e) {
610 result.str("");
611 result << "send_county()::failed " << e.error() << " " << e.what();
612 n3fjp_print(result.str());
613 throw e;
614 } catch (...) { throw; }
615 }
616
send_spcnum(std::string s)617 void send_spcnum(std::string s)
618 {
619 try {
620 send_control("SPCNUM", s);
621 } catch (const SocketException& e) {
622 result.str("");
623 result << "send_spcnum()::failed " << e.error() << " " << e.what();
624 n3fjp_print(result.str());
625 throw e;
626 } catch (...) { throw; }
627 }
628
send_name(std::string s)629 void send_name(std::string s)
630 {
631 try {
632 send_control("NAMER", s);
633 } catch (const SocketException& e) {
634 result.str("");
635 result << "send_name()::failed " << e.error() << " " << e.what();
636 n3fjp_print(result.str());
637 throw e;
638 } catch (...) { throw; }
639 }
640
641 //======================================================================
642 //
643 //======================================================================
644
n3fjp_clear_record()645 void n3fjp_clear_record()
646 {
647 if(!n3fjp_socket) return;
648 if (!n3fjp_connected) return;
649
650 string cmd = "<CMD><ACTION><VALUE>CLEAR</VALUE></CMD>";
651 try {
652 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
653 n3fjp_wait = 100;
654 } catch (const SocketException& e) {
655 result.str("");
656 result << "Error: " << e.error() << ", " << e.what();
657 n3fjp_print(result.str());
658 } catch (...) { throw; }
659 }
660
661 //======================================================================
662 //
663 //======================================================================
664 bool n3fjp_calltab = false;
665
n3fjp_getfields()666 void n3fjp_getfields()
667 {
668 string cmd ="<CMD><ALLFIELDSWITHVALUES></CMD>";
669 try {
670 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
671 n3fjp_wait = 100;
672 } catch (const SocketException& e) {
673 result.str("");
674 result << "Error: " << e.error() << ", " << e.what();
675 n3fjp_print(result.str());
676 n3fjp_calltab = false;
677 } catch (...) { throw; }
678 }
679
n3fjp_get_record(string call)680 void n3fjp_get_record(string call)
681 {
682 if(!n3fjp_socket) return;
683 if (!n3fjp_connected) return;
684
685 if (!n3fjp_calltab) return;
686
687 string cmd0, cmd1, cmd2;
688
689 cmd0.assign("<CMD><ACTION><VALUE>CLEAR</VALUE></CMD>");
690
691 cmd1.assign("<CMD><UPDATE><CONTROL>TXTENTRYCALL</CONTROL><VALUE>");
692 cmd1.append(call).append("</VALUE></CMD>");
693
694 cmd2.assign("<CMD><ACTION><VALUE>CALLTAB</VALUE></CMD>");
695
696 try {
697 n3fjp_send(cmd0, progdefaults.enable_N3FJP_log);
698 n3fjp_send(cmd1, progdefaults.enable_N3FJP_log);
699
700 n3fjp_send(cmd2, progdefaults.enable_N3FJP_log);
701 n3fjp_calltab = false;
702
703 n3fjp_wait = 100;
704
705 } catch (const SocketException& e) {
706 result.str("");
707 result << "Error: " << e.error() << ", " << e.what();
708 n3fjp_print(result.str());
709 n3fjp_calltab = false;
710 } catch (...) { throw; }
711 }
712
713 //======================================================================
714 // parse string containing value, e.g.
715 // <FREQ>14.01310</FREQ>
716 //======================================================================
ParseField(string & record,string fieldtag)717 static string ParseField(string &record, string fieldtag)
718 {
719 string fld_tag_start, fld_tag_end;
720 fld_tag_start.assign("<").append(fieldtag).append(">");
721 fld_tag_end.assign("</").append(fieldtag).append(">");
722 size_t p1 = record.find(fld_tag_start);
723 if (p1 == string::npos) return "";
724 p1 += fld_tag_start.length();
725
726 size_t p2 = record.find(fld_tag_end, p1);
727 if (p2 == string::npos) return "";
728 return record.substr(p1, p2 - p1);
729 }
730
731 //======================================================================
732 // parse string containing text entry values, e.g.
733 // <CONTROL>TXTENTRYCOUNTYR</CONTROL><VALUE>Saint Louis City</VALUE></CMD>
734 //======================================================================
ParseTextField(string & record,string fieldtag)735 static string ParseTextField(string &record, string fieldtag)
736 {
737 string fld_tag_start;
738 fld_tag_start.assign("<CONTROL>TXTENTRY").append(fieldtag).append("</CONTROL>");
739 size_t p1 = record.find(fld_tag_start);
740 if (p1 == string::npos) return "";
741 size_t p2 = record.find("<VALUE>", p1);
742 if (p2 == string::npos) return "";
743 p2 += strlen("<VALUE>");
744 size_t p3 = record.find("</VALUE>", p2);
745 if (p3 == string::npos) return "";
746 return record.substr(p2, p3 - p2);
747 }
748
749 //======================================================================
750 // parse value contents
751 // <VALUE>valuestring</VALUE>
752 //======================================================================
ParseValueField(string field,string & record)753 static string ParseValueField(string field, string &record)
754 {
755 string start = "<";
756 start.append(field).append("><VALUE>");
757 string endvalue = "</VALUE>";
758 size_t p1 = record.find(start);
759 size_t p2 = record.find(endvalue, p1);
760 if ((p1 == string::npos) || (p2 == string::npos) ||
761 (p2 < p1) ) return "";
762 p1 += start.length();
763 return record.substr(p1, p2 - p1);
764 }
765
ucasestr(string s)766 static string ucasestr(string s)
767 {
768 for (size_t n = 0; n < s.length(); n++) s[n] = toupper(s[n]);
769 return s;
770 }
771
772 //======================================================================
773 //
774 //======================================================================
n3fjp_parse_data_stream(string buffer)775 static void n3fjp_parse_data_stream(string buffer)
776 {
777 string field;
778 field = ParseTextField(buffer, "NAMER");
779 if (!field.empty() && ucasestr(field) != ucasestr(inpName->value())) {
780 for (size_t n = 1; n < field.length(); n++) field[n] = tolower(field[n]);
781 }
782
783 field = ParseTextField(buffer, "COUNTYR");
784 if (!field.empty() && field != inpCounty->value() &&
785 n3fjp_contest != FJP_NEQP &&
786 n3fjp_contest != FJP_7QP)
787
788 field = ParseTextField(buffer, "STATE");
789 if (!field.empty() && field != inpState->value() &&
790 n3fjp_contest != FJP_NEQP &&
791 n3fjp_contest != FJP_7QP)
792
793 field = ParseTextField(buffer, "COUNTRYWORKED");
794 if (!field.empty() && field != cboCountry->value())
795
796 field = ParseTextField(buffer, "GRID");
797 if (!field.empty() && field != inpLoc->value())
798
799 field = ParseTextField(buffer, "FREQUENCY");
800 if (!field.empty()) adjust_freq(field);
801
802 field = ParseTextField(buffer, "CQZONE");
803 if (!field.empty() && field != inp_CQzone->value())
804
805 // comments field does not contain \n delimiters
806 // substitute \n for each '-'
807 field = ParseTextField(buffer, "COMMENTS");
808 if (!field.empty()) {
809 size_t p = field.find(" - ");
810 while (p != string::npos) {
811 field.replace(p, 3, "\n");
812 p = field.find(" - ");
813 }
814 }
815 }
816
817 //======================================================================
818 //<CMD><CALLTABEVENT>
819 // <CALL>ON6NB/P</CALL>
820 // <BAND>40</BAND>
821 // <MODE>SSB</MODE>
822 // <MODETEST>PH</MODETEST>
823 // <COUNTRY>Belgium</COUNTRY>
824 //</CMD>
825 //======================================================================
n3fjp_parse_calltab_event(string buffer)826 static void n3fjp_parse_calltab_event(string buffer)
827 {
828 // inpCall->value(ParseField(buffer, "CALL").c_str());
829 cboCountry->value(ParseField(buffer, "COUNTRY").c_str());
830 n3fjp_getfields();
831 }
832
833 //======================================================================
834 //
835 //======================================================================
fmt_date(string date)836 string fmt_date(string date)
837 {
838 if (date.length() > 6) date.insert(6,"/");
839 if (date.length() > 4) date.insert(4,"/");
840 return date;
841 }
842
fmt_time(string time)843 string fmt_time(string time)
844 {
845 if (time.length() > 4) time.insert(4,":");
846 if (time.length() > 2) time.insert(2,":");
847 return time;
848 }
849
field_rec(string fld,string val)850 string field_rec(string fld, string val)
851 {
852 string s;
853 s.assign("<").append(fld).append(">");
854 s.append(val);
855 s.append("</").append(fld).append(">");
856 return s;
857 }
858
n3fjp_tstmode()859 static string n3fjp_tstmode()
860 {
861 if (!active_modem)
862 return "PH";
863
864 if (active_modem->get_mode() == MODE_CW)
865 return "CW";
866
867 if (active_modem->get_mode() == MODE_SSB)
868 return "PH";
869
870 if (active_modem->get_mode() < MODE_SSB)
871 return mode_info[active_modem->get_mode()].adif_name;
872
873 return "";
874 }
875
n3fjp_opmode()876 static string n3fjp_opmode()
877 {
878 if (!active_modem)
879 return "PH";
880
881 if (active_modem->get_mode() == MODE_CW)
882 return "CW";
883
884 if (active_modem->get_mode() == MODE_SSB)
885 return "PH";
886
887 if (active_modem->get_mode() < MODE_SSB)
888 return mode_info[active_modem->get_mode()].adif_name;
889
890 return "";
891 }
892
n3fjp_opband()893 static string n3fjp_opband()
894 {
895 if (!active_modem) return "";
896
897 float freq = qsoFreqDisp->value();
898 freq /= 1e6;
899
900 if (freq >= 1.8 && freq < 3.5) return "160";
901 if (freq >= 3.5 && freq < 5.3) return "80";
902 if (freq >= 5.3 && freq < 5.5) return "60";
903 if (freq >= 7.0 && freq < 7.5) return "40";
904 if (freq >= 14.0 && freq < 18.0) return "20";
905 if (freq >= 18.0 && freq < 21.0) return "17";
906 if (freq >= 21.0 && freq < 24.0) return "15";
907 if (freq >= 24.0 && freq < 28.0) return "12";
908 if (freq >= 28.0 && freq < 50.0) return "10";
909 if (freq >= 50.0 && freq < 70.0) return "6";
910 if (freq >= 144.0 && freq < 222.0) return "2";
911 if (freq >= 222.0 && freq < 420.0) return "222";
912 if (freq >= 420.0 && freq < 444.0) return "440";
913 return "";
914 }
915
n3fjp_freq()916 static string n3fjp_freq()
917 {
918 if (!active_modem) return "";
919 float freq = qsoFreqDisp->value();
920 if (progdefaults.N3FJP_modem_carrier) {
921 if (ModeIsLSB(mode_info[active_modem->get_mode()].adif_name)) {
922 freq -= active_modem->get_txfreq();
923 if (active_modem->get_mode() == MODE_RTTY)
924 freq -= progdefaults.rtty_shift / 2;
925 } else {
926 freq += active_modem->get_txfreq();
927 if (active_modem->get_mode() == MODE_RTTY)
928 freq += progdefaults.rtty_shift / 2;
929 }
930 }
931 freq /= 1e6;
932 char szfreq[20];
933 snprintf(szfreq, sizeof(szfreq), "%f", freq);
934 return szfreq;
935 }
936
send_control(const string ctl,string val)937 static void send_control(const string ctl, string val)
938 {
939 string cmd;
940 cmd.assign("<CMD><UPDATE><CONTROL>TXTENTRY").append(ctl);
941 cmd.append("</CONTROL><VALUE>");
942 cmd.append(val);
943 cmd.append("</VALUE></CMD>");
944 try {
945 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
946 n3fjp_wait = 100;
947 } catch (...) { throw; }
948 }
949
send_action(const string action)950 static void send_action(const string action)
951 {
952 string cmd;
953 cmd.assign("<CMD><ACTION><VALUE>");
954 cmd.append(action);
955 cmd.append("</VALUE></CMD>");
956 try {
957 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
958 n3fjp_wait = 200;//100;
959 } catch (...) { throw; }
960 }
961
send_command(const string command,string val)962 static void send_command(const string command, string val)
963 {
964 string cmd;
965 cmd.assign("<CMD><").append(command).append(">");
966 if (!val.empty())
967 cmd.append("<VALUE>").append(val).append("</VALUE>");
968 cmd.append("</CMD>");
969 try {
970 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
971 // MilliSleep(5);
972 n3fjp_wait = 100;
973 } catch (...) { throw; }
974 }
975
n3fjp_send_NONE()976 static void n3fjp_send_NONE()
977 {
978 try {
979 send_control("DATE", fmt_date(rec.getField(QSO_DATE)));
980 send_control("TIMEON", fmt_time(rec.getField(TIME_ON)));
981 send_control("TIMEOFF", fmt_time(rec.getField(TIME_OFF)));
982
983 send_name(strip(rec.getField(NAME)));
984 send_control("COMMENTS", strip(rec.getField(NOTES)));
985 send_control("POWER", strip(rec.getField(TX_PWR)));
986 send_state(rec.getField(STATE));
987 send_control("GRID", strip(rec.getField(GRIDSQUARE)));
988 send_control("QTHGROUP", strip(rec.getField(QTH)));
989 send_county(rec.getField(CNTY));
990 send_control("COUNTRYWORKED", rec.getField(COUNTRY));
991 } catch (...) { throw; }
992 }
993
994 // ARRL Field Day
n3fjp_send_FD()995 static void n3fjp_send_FD()
996 {
997 try {
998 send_control("MODETST", n3fjp_tstmode());
999 send_control("CLASS", strip(ucasestr(rec.getField(CLASS))));
1000 send_control("SECTION", strip(ucasestr(rec.getField(ARRL_SECT))));
1001 } catch (...) { throw; }
1002 }
1003
1004 // Winter Field Day
n3fjp_send_WFD()1005 static void n3fjp_send_WFD()
1006 {
1007 try {
1008 send_control("MODETST", n3fjp_tstmode());
1009 send_control("CLASS", strip(ucasestr(rec.getField(CLASS))));
1010 send_control("SECTION", strip(ucasestr(rec.getField(ARRL_SECT))));
1011 } catch (...) { throw; }
1012 }
1013
1014 // Kids Day
n3fjp_send_KD()1015 static void n3fjp_send_KD()
1016 {
1017 try {
1018 send_name(rec.getField(NAME));
1019
1020 send_control("AGE", rec.getField(AGE));
1021
1022 std::string stprc = strip(ucasestr(rec.getField(STATE)));
1023 if (stprc.empty())
1024 stprc = strip(ucasestr(rec.getField(VE_PROV)));
1025 if (stprc.empty())
1026 stprc = strip(rec.getField(COUNTRY));
1027 send_spcnum(stprc);
1028
1029 send_control("COMMENTS", strip(rec.getField(XCHG1)));
1030 } catch (...) { throw; }
1031 }
1032
1033 // ARRL Rookie Roundup
n3fjp_send_ARR()1034 static void n3fjp_send_ARR()
1035 {
1036 try {
1037 send_name(rec.getField(NAME));
1038 send_control("CHECK", rec.getField(CHECK));
1039 if (rec.getField(XCHG1)[0])
1040 send_spcnum(strip(ucasestr(rec.getField(XCHG1))));
1041 else
1042 send_spcnum(strip(ucasestr(rec.getField(COUNTRY))));
1043 } catch (...) { throw; }
1044 }
1045
1046 // ARRL RTTY
n3fjp_send_RTTY()1047 static void n3fjp_send_RTTY()
1048 {
1049 try {
1050 if (rec.getField(SRX)[0])
1051 send_spcnum(strip(rec.getField(SRX)));
1052 else if (rec.getField(STATE)[0])
1053 send_spcnum(strip(ucasestr(rec.getField(STATE))));
1054 else if (rec.getField(VE_PROV)[0])
1055 send_spcnum(strip(ucasestr(rec.getField(VE_PROV))));
1056 send_control("COUNTRYWORKED", rec.getField(COUNTRY));
1057 } catch (...) { throw; }
1058 }
1059
1060 // ARRL School Club Roundup
n3fjp_send_ASCR()1061 static void n3fjp_send_ASCR()
1062 {
1063 try {
1064 send_name(strip(rec.getField(NAME)));
1065 send_control("CLASS", ucasestr(rec.getField(CLASS)));
1066 send_spcnum(ucasestr(rec.getField(XCHG1)));
1067 } catch (...) { throw; }
1068 }
1069
1070 // ARRL Jamboree On The Air
n3fjp_send_JOTA()1071 static void n3fjp_send_JOTA()
1072 {
1073 try {
1074 send_name(rec.getField(SCOUTR)); // received scout name
1075 send_control("NAMES", rec.getField(SCOUTS)); // sent scout name
1076 send_control("CHECK", rec.getField(TROOPR)); // received troop number
1077 send_control("TROOPS", rec.getField(TROOPS)); // sent troop number
1078 if (state_test(rec.getField(STATE)))
1079 send_spcnum(ucasestr(rec.getField(STATE)));
1080 else if (province_test(rec.getField(VE_PROV)))
1081 send_spcnum(ucasestr(rec.getField(VE_PROV)));
1082 else
1083 send_spcnum(rec.getField(COUNTRY)); // St / Pr / Cntry
1084 send_control("COMMENTS", rec.getField(NOTES));
1085 } catch (...) { throw; }
1086 }
1087
1088 // CQ WPX
n3fjp_send_WPX()1089 static void n3fjp_send_WPX()
1090 {
1091 try {
1092 send_call(rec.getField(CALL));
1093 send_freq(n3fjp_freq());
1094 send_band(n3fjp_opband());
1095 send_mode(n3fjp_opmode());
1096
1097 send_control("COUNTRYWORKED", rec.getField(COUNTRY));
1098 send_control("SERIALNOR", strip(rec.getField(SRX)));
1099 } catch (...) { throw; }
1100 }
1101
1102 // Italian ARI International DX
n3fjp_send_IARI()1103 static void n3fjp_send_IARI()
1104 {
1105 try {
1106 if (rec.getField(SRX)[0])
1107 send_spcnum(rec.getField(SRX));
1108 else
1109 send_spcnum(ucasestr(rec.getField(XCHG1)));
1110 // send_control("COUNTRYWORKED", rec.getField(COUNTRY));
1111 } catch (...) { throw; }
1112 }
1113
1114 // North American Sprint
n3fjp_send_NAS()1115 static void n3fjp_send_NAS()
1116 {
1117 try {
1118 send_name(rec.getField(NAME));
1119 send_control("SERIALNOR", strip(rec.getField(SRX)));
1120 send_spcnum(strip(ucasestr(rec.getField(XCHG1))));
1121 } catch (...) { throw; }
1122 }
1123
1124 // CQ World Wide RTTY
n3fjp_send_CQWWRTTY()1125 static void n3fjp_send_CQWWRTTY()
1126 {
1127 try {
1128 send_control("CQZONE", strip(rec.getField(CQZ)));
1129 send_state(rec.getField(STATE));
1130 send_control("COUNTRYWORKED", strip(rec.getField(COUNTRY)));
1131 } catch (...) { throw; }
1132 }
1133
1134 // CQ World Wide DX
n3fjp_send_CQWWDX()1135 static void n3fjp_send_CQWWDX()
1136 {
1137 try {
1138 send_control("CQZONE", strip(rec.getField(CQZ)));
1139 send_control("COUNTRYWORKED", strip(rec.getField(COUNTRY)));
1140 } catch (...) { throw; }
1141 }
1142
1143 // Sweepstakes
n3fjp_send_SS()1144 static void n3fjp_send_SS()
1145 {
1146 try {
1147 send_control("SERIALNOR", strip(rec.getField(SS_SERNO)));
1148 send_control("PRECEDENCE", strip(rec.getField(SS_PREC)));
1149 send_control("CHECK", strip(rec.getField(SS_CHK)));
1150 send_control("SECTION", strip(rec.getField(SS_SEC)));
1151 } catch (...) { throw; }
1152 }
1153
1154 // North American QSO Party
n3fjp_send_NAQP()1155 static void n3fjp_send_NAQP()
1156 {
1157 try {
1158 send_name(rec.getField(NAME));
1159 if (strlen(rec.getField(XCHG1)) > 0)
1160 send_spcnum(ucasestr(rec.getField(XCHG1)));
1161 } catch (...) { throw; }
1162 }
1163
1164 // Ten Ten
n3fjp_send_1010()1165 static void n3fjp_send_1010()
1166 {
1167 try {
1168 send_name(rec.getField(NAME));
1169 send_control("1010", rec.getField(TEN_TEN));
1170 if (strlen(rec.getField(XCHG1)) > 0)
1171 send_spcnum(ucasestr(rec.getField(XCHG1)));
1172 } catch (...) { throw; }
1173 }
1174
1175 // Africa International DX
n3fjp_send_AIDX()1176 static void n3fjp_send_AIDX()
1177 {
1178 try {
1179 send_control("SERIALNOR", strip(rec.getField(SRX)));
1180 send_control("COUNTRYWORKED", rec.getField(COUNTRY));
1181 } catch (...) { throw; }
1182 }
1183
1184 // ARRL International DX (CW)
n3fjp_send_AICW()1185 static void n3fjp_send_AICW()
1186 {
1187 try {
1188 send_spcnum(rec.getField(XCHG1));
1189 send_control("COUNTRYWORKED", rec.getField(COUNTRY));
1190 } catch (...) { throw; }
1191 }
1192
n3fjp_send_GENERIC()1193 static void n3fjp_send_GENERIC()
1194 {
1195 try {
1196 send_control("SERIALNOR", strip(rec.getField(SRX)));
1197 send_spcnum(strip(ucasestr(rec.getField(XCHG1))));
1198 } catch (...) { throw; }
1199 }
1200
n3fjp_send_VHF()1201 static void n3fjp_send_VHF()
1202 {
1203 try {
1204 std::string grid = strip(rec.getField(GRIDSQUARE));
1205 if (grid.length() > 4) grid.erase(4);
1206 send_control("GRID", grid);
1207 } catch (...) { throw; }
1208 }
1209
n3fjp_send_WAE()1210 static void n3fjp_send_WAE()
1211 {
1212 try {
1213 send_control("SERIALNOR", strip(rec.getField(SRX)));
1214 send_control("COUNTRYWORKED", rec.getField(COUNTRY));
1215 } catch (...) { throw; }
1216 }
1217
1218 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1219 // "MD SQP" "", "B", "B", "", "", "", "B", ""
1220
n3fjp_send_MDQSP()1221 static void n3fjp_send_MDQSP()
1222 {
1223 try {
1224
1225 if (rec.getField(XCHG1)[0])
1226 send_control("CATEGORY", ucasestr(strip(rec.getField(XCHG1))));
1227 send_county(strip(rec.getField(CNTY)));
1228
1229 if (n3fjp_in_state) {
1230 send_county(ucasestr(strip(rec.getField(CNTY))));
1231 if (rec.getField(STATE)[0])
1232 send_spcnum(rec.getField(STATE));
1233 else if (rec.getField(VE_PROV)[0])
1234 send_spcnum(rec.getField(VE_PROV));
1235 else if (rec.getField(COUNTRY)[0])
1236 send_spcnum(rec.getField(COUNTRY));
1237 }
1238 } catch (...) { throw; }
1239 }
1240
1241 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1242 // "New Eng", "B", "B", "B", "", "I", "", "", "CCCSS"
1243
1244 // MA, NH, VT, MA, CT, RI
n3fjp_send_NEQP()1245 static void n3fjp_send_NEQP()
1246 {
1247 try {
1248 if (rec.getField(CNTY)[0])
1249 send_county(rec.getField(CNTY));
1250
1251 if (rec.getField(STATE)[0])
1252 send_spcnum(rec.getField(STATE));
1253 else if (rec.getField(COUNTRY)[0])
1254 send_spcnum(rec.getField(COUNTRY));
1255 } catch (...) { throw; }
1256 }
1257
1258 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1259 // "7QP", "B", "B", "B", "", "I", "", "", "SSCCC"
1260 // AZ ID OR MT NV WA WY
n3fjp_send_7QP()1261 static void n3fjp_send_7QP()
1262 {
1263 static string st7QP = "AZ ID OR MT NV WA WY UT";
1264 try {
1265 std::string st = rec.getField(STATE);
1266 std::string cnty = rec.getField(CNTY);
1267
1268 if (cnty.length() == 5) {
1269 if (st7QP.find(cnty.substr(0,2)) != std::string::npos)
1270 st = cnty.substr(0,2);
1271 }
1272
1273 send_spcnum(st);
1274 send_county(cnty);
1275
1276 if (progdefaults.SQSOinstate && !st.empty()) { // in region
1277 if (st7QP.find(st) != std::string::npos) {
1278 if (!cnty.empty()) send_county(cnty);
1279 send_spcnum(st);
1280 } else
1281 send_spcnum(st);
1282 } else { // out of region
1283 if (!st.empty() && st7QP.find(st) != std::string::npos) {
1284 if (!cnty.empty()) send_county(cnty);
1285 send_spcnum(st);
1286 }
1287 }
1288
1289 } catch (...) { throw; }
1290 }
1291
1292 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1293 // "QSOP 1" "B", "B", "B", "", "I", "", "", ""
1294 //AL, AR, FL, GA, HI, IA, ID, IL, KS, KY, LA, MO, MI, ND, NJ, BC, 7QP
n3fjp_send_QP1()1295 static void n3fjp_send_QP1()
1296 {
1297 try {
1298 std::string st = rec.getField(STATE);
1299 if (st.empty()) st = QSOparties.qso_parties[progdefaults.SQSOcontest].state;
1300 if (rec.getField(STATE)[0])
1301 send_spcnum(rec.getField(STATE));
1302 else if (rec.getField(VE_PROV)[0])
1303 send_spcnum(rec.getField(VE_PROV));
1304 else if (rec.getField(COUNTRY)[0])
1305 send_spcnum(rec.getField(COUNTRY));
1306 if (rec.getField(CNTY)[0]) {
1307 if (st == "BC") { // British Columbia
1308 Cstates cs;
1309 send_county(cs.cnty_short(st, rec.getField(CNTY)));
1310 } else
1311 send_county(rec.getField(CNTY));
1312 }
1313 } catch (...) { throw; }
1314 }
1315
1316 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1317 // "QSOP 2" "B", "B", "B", "", "B", "", "", ""
1318
1319 // MT, NE, NY, OH, OK, ON, SK, TN, TX, VT, WA, ME
n3fjp_send_QP2()1320 static void n3fjp_send_QP2()
1321 {
1322 try {
1323 if (rec.getField(STATE)[0])
1324 send_spcnum(rec.getField(STATE));
1325 else if (rec.getField(VE_PROV)[0])
1326 send_spcnum(rec.getField(VE_PROV));
1327 else if (rec.getField(COUNTRY)[0])
1328 send_spcnum(rec.getField(COUNTRY));
1329 if (rec.getField(CNTY)[0])
1330 send_county(rec.getField(CNTY));
1331 } catch (...) { throw; }
1332 }
1333
1334 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1335 // "QSOP 3" "", "B", "B", "B", "I", "", "", ""
1336
1337 // AZ, CA, MI, PA, VI
n3fjp_send_QP3()1338 static void n3fjp_send_QP3()
1339 {
1340 try {
1341 if (n3fjp_in_state) { // in state log
1342 if (rec.getField(STATE)[0]) {
1343 send_spcnum(rec.getField(STATE));
1344 // string county = states.county(rec.getField(STATE), rec.getField(CNTY));
1345 // if (!county.empty())
1346 if (rec.getField(CNTY)[0])
1347 send_county(rec.getField(CNTY));
1348 }
1349 else if (rec.getField(VE_PROV)[0])
1350 send_spcnum(rec.getField(VE_PROV));
1351 else if (rec.getField(COUNTRY)[0])
1352 send_spcnum(rec.getField(COUNTRY));
1353 } else { // out of state log
1354 std::string county = rec.getField(CNTY);
1355 if (!county.empty())
1356 // {
1357 send_county(county);
1358 // } else
1359 // send_county(rec.getField(CNTY)); // may be ARRL section
1360 }
1361 send_control("SERIALNOR", strip(rec.getField(SRX)));
1362 } catch (...) { throw; }
1363 }
1364
1365 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1366 // "QSOP 4" "", "B", "B", "", "I", "B", "", ""
1367
1368 // CO, MN, NM
n3fjp_send_QP4()1369 static void n3fjp_send_QP4()
1370 {
1371 try {
1372 // RST sent/rcvd not required, but will be accepted by logger
1373 if (n3fjp_in_state) {
1374 if (rec.getField(STATE)[0])
1375 send_spcnum(rec.getField(STATE));
1376 else if (rec.getField(VE_PROV)[0])
1377 send_spcnum(rec.getField(VE_PROV));
1378 else if (rec.getField(COUNTRY)[0])
1379 send_spcnum(rec.getField(COUNTRY));
1380 if (rec.getField(NAME)[0])
1381 send_name(rec.getField(NAME));
1382 if (rec.getField(CNTY)[0])
1383 send_county(rec.getField(CNTY));
1384 } else {
1385 // std::string st = QSOparties.qso_parties[progdefaults.SQSOcontest].state;
1386 // send_county(states.county(st, rec.getField(CNTY)));
1387 send_county(rec.getField(CNTY));
1388 if (rec.getField(NAME)[0])
1389 send_name(rec.getField(NAME));
1390 }
1391 } catch (...) { throw; }
1392 }
1393
1394 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1395 // "QSOP 5" "B", "I", "B", "", "", "", "", ""
1396
1397 // SC, WV
n3fjp_send_QP5()1398 static void n3fjp_send_QP5()
1399 {
1400 try {
1401 if (n3fjp_in_state) {
1402 if (rec.getField(STATE)[0])
1403 send_spcnum(rec.getField(STATE));
1404 else if (rec.getField(VE_PROV)[0])
1405 send_spcnum(rec.getField(VE_PROV));
1406 else if (rec.getField(COUNTRY)[0])
1407 send_spcnum(rec.getField(COUNTRY));
1408 send_county(rec.getField(CNTY));
1409 } else {
1410 send_county(rec.getField(CNTY));
1411 }
1412 } catch (...) { throw; }
1413 }
1414
1415 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1416 // "QSOP 6" "B", "B", "B", "", "I", "", "", ""
1417
1418 // NC, WI
n3fjp_send_QP6()1419 static void n3fjp_send_QP6()
1420 {
1421 try {
1422 if (n3fjp_in_state) {
1423 if (rec.getField(STATE)[0])
1424 send_spcnum(rec.getField(STATE));
1425 else if (rec.getField(VE_PROV)[0])
1426 send_spcnum(rec.getField(VE_PROV));
1427 else if (rec.getField(COUNTRY)[0])
1428 send_spcnum(rec.getField(COUNTRY));
1429 if (rec.getField(CNTY)[0])
1430 send_county(rec.getField(CNTY));
1431 } else {
1432 // send_county(states.county(rec.getField(STATE), rec.getField(CNTY)));
1433 send_county(rec.getField(CNTY));
1434 }
1435 } catch (...) { throw; }
1436 }
1437
1438 // check fields for duplicates
1439
1440 // ARRL Field Day
n3fjp_check_FD()1441 static void n3fjp_check_FD()
1442 {
1443 try {
1444 send_control("MODETST", n3fjp_tstmode());
1445 send_control("CLASS", inpClass->value());
1446 send_control("SECTION", inpSection->value());
1447 } catch (...) { throw; }
1448 return;
1449 }
1450
1451 // Winter Field Day
n3fjp_check_WFD()1452 static void n3fjp_check_WFD()
1453 {
1454 try {
1455 send_control("MODETST", n3fjp_tstmode());
1456 send_control("CLASS", inpClass->value());
1457 send_control("SECTION", inpSection->value());
1458 } catch (...) { throw; }
1459 return;
1460 }
1461
1462 // Kids Day
n3fjp_check_KD()1463 static void n3fjp_check_KD()
1464 {
1465 try {
1466 send_name(inpName->value());
1467 send_control("AGE", inp_KD_age->value());
1468 send_spcnum(ucasestr(inpQTH->value()));
1469 send_control("COMMENTS", inpXchgIn->value());
1470 } catch (...) { throw; }
1471 return;
1472 }
1473
1474 // ARRL Rookie Roundup
n3fjp_check_ARR()1475 static void n3fjp_check_ARR()
1476 {
1477 try {
1478 send_name(inpName->value());
1479 send_control("CHECK", inp_ARR_check->value());
1480 if (inpXchgIn->value()[0])
1481 send_spcnum(ucasestr(inpXchgIn->value()));
1482 else
1483 send_spcnum(ucasestr(cboCountry->value()));
1484 } catch (...) { throw; }
1485 return;
1486 }
1487
1488 // ARRL RTTY
n3fjp_check_RTTY()1489 static void n3fjp_check_RTTY()
1490 {
1491 try {
1492 if (inpSerNo->value()[0])
1493 send_spcnum(inpSerNo->value());
1494 else if (inpState->value()[0])
1495 send_spcnum(ucasestr(inpState->value()));
1496 else if (inpVEprov->value()[0])
1497 send_spcnum(ucasestr(ucasestr(inpVEprov->value())));
1498 send_control("COUNTRYWORKED", cboCountry->value());
1499 } catch (...) { throw; }
1500 return;
1501 }
1502
1503 // ARRL School Club Roundup
n3fjp_check_ASCR()1504 static void n3fjp_check_ASCR()
1505 {
1506 try {
1507 send_name(inpName->value());
1508 send_spcnum(inpXchgIn->value());
1509 send_control("CLASS", ucasestr(inpClass->value()));
1510 } catch (...) { throw; }
1511 return;
1512 }
1513
1514 // ARRL Jamboree On The Air
n3fjp_check_JOTA()1515 static void n3fjp_check_JOTA()
1516 {
1517 try {
1518 send_name(inpName->value());
1519
1520 send_control("CHECK", rec.getField(TROOPR)); // received troop number
1521 send_control("TROOPS", inp_JOTA_troop->value()); // sent troop number
1522 if (state_test(inpState->value()))
1523 send_spcnum(inpState->value());
1524 else if (province_test(inpVEprov->value()))
1525 send_spcnum(inpVEprov->value());
1526 else
1527 send_spcnum(ucasestr(cboCountry->value())); // St / Pr / Cntry
1528 send_control("CHECK", inp_JOTA_troop->value());
1529 } catch (...) { throw; }
1530 return;
1531 }
1532
1533 // CQ WPX
n3fjp_check_WPX()1534 static void n3fjp_check_WPX()
1535 {
1536 try {
1537 send_control("COUNTRYWORKED", cboCountry->value());
1538 send_control("SERIALNOR", inpSerNo->value());
1539 // send_control("CHECK", inpXchgIn->value());
1540 } catch (...) { throw; }
1541 return;
1542 }
1543
1544 // Italian ARI International DX
n3fjp_check_IARI()1545 static void n3fjp_check_IARI()
1546 {
1547 try {
1548 if (inpSerNo->value()[0])
1549 send_spcnum(inpSerNo->value());
1550 else
1551 send_spcnum(inpXchgIn->value());
1552 // send_control("COUNTRYWORKED", cboCountry->value());
1553 } catch (...) { throw; }
1554 return;
1555 }
1556
1557 // North American Sprint
n3fjp_check_NAS()1558 static void n3fjp_check_NAS()
1559 {
1560 try {
1561 send_name(inpName->value());
1562 send_control("SERIALNOR", inpSerNo->value());
1563 send_spcnum(inpXchgIn->value());
1564 } catch (...) { throw; }
1565 return;
1566 }
1567
1568 // CQ World Wide RTTY
n3fjp_check_CQWWRTTY()1569 static void n3fjp_check_CQWWRTTY()
1570 {
1571 try {
1572 send_control("CQZONE", inp_CQzone->value());
1573 send_state(inpState->value());
1574 send_control("COUNTRYWORKED", cboCountry->value());
1575 } catch (...) { throw; }
1576 return;
1577 }
1578
1579 // CQ World Wide DX
n3fjp_check_CQWWDX()1580 static void n3fjp_check_CQWWDX()
1581 {
1582 try {
1583 send_control("CQZONE", inp_CQzone->value());
1584 send_control("COUNTRYWORKED", cboCountry->value());
1585 } catch (...) { throw; }
1586 return;
1587 }
1588
1589 // Sweepstakes
n3fjp_check_SS()1590 static void n3fjp_check_SS()
1591 {
1592 try {
1593 send_control("SERIALNOR", inpSerNo->value());
1594 send_control("PRECEDENCE", inp_SS_Precedence->value());
1595 send_control("CHECK", inp_SS_Check->value());
1596 send_control("SECTION", inp_SS_Section->value());
1597 } catch (...) { throw; }
1598 return;
1599 }
1600
1601 // North American QSO Party
n3fjp_check_NAQP()1602 static void n3fjp_check_NAQP()
1603 {
1604 try {
1605 send_name(inpName->value());
1606 send_spcnum(inpXchgIn->value());
1607 } catch (...) { throw; }
1608 return;
1609 }
1610
1611 // Ten Ten
n3fjp_check_1010()1612 static void n3fjp_check_1010()
1613 {
1614 try {
1615 send_name(inpName->value());
1616 send_control("1010", inp_1010_nr->value());
1617 send_spcnum(inpXchgIn->value());
1618 } catch (...) { throw; }
1619 return;
1620 }
1621
1622 // Africa International DX
n3fjp_check_AIDX()1623 static void n3fjp_check_AIDX()
1624 {
1625 try {
1626 send_control("SERIALNOR", inpSerNo->value());
1627 send_control("COUNTRYWORKED", cboCountry->value());
1628 } catch (...) { throw; }
1629 return;
1630 }
1631
1632 // ARRL International DX (CW)
n3fjp_check_AICW()1633 static void n3fjp_check_AICW()
1634 {
1635 try {
1636 send_spcnum(inpSPCnum->value());
1637 send_control("COUNTRYWORKED", cboCountry->value());
1638 } catch (...) { throw; }
1639 return;
1640 }
1641
n3fjp_check_GENERIC()1642 static void n3fjp_check_GENERIC()
1643 {
1644 try {
1645 send_control("SERIALNOR", inpSerNo->value());
1646 send_spcnum(ucasestr(inpXchgIn->value()));
1647 } catch (...) { throw; }
1648 return;
1649 }
1650
n3fjp_check_VHF()1651 static void n3fjp_check_VHF()
1652 {
1653 try {
1654 std::string grid = inpLoc->value();
1655 if (grid.length() > 4) grid.erase(4);
1656 send_control("GRID", grid);
1657 } catch (...) { throw; }
1658 return;
1659 }
1660
n3fjp_check_WAE()1661 static void n3fjp_check_WAE()
1662 {
1663 try {
1664 send_control("SERIALNOR", inpSerNo->value());
1665 send_control("COUNTRYWORKED", cboCountry->value());
1666 } catch (...) { throw; }
1667 return;
1668 }
1669
1670 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1671 // "MD SQP" "", "B", "B", "", "", "", "B", ""
1672
n3fjp_check_MDQSP()1673 static void n3fjp_check_MDQSP()
1674 {
1675 try {
1676 send_county(inpCounty->value());
1677
1678 if (inpSQSO_category->value()[0])
1679 send_control("CATEGORY", inpSQSO_category->value());
1680
1681 if (n3fjp_in_state) {
1682 if (inpState->value()[0])
1683 send_spcnum(inpState->value());
1684 else if (inpVEprov->value()[0])
1685 send_spcnum(inpVEprov->value());
1686 else if (cboCountry->value()[0])
1687 send_spcnum(cboCountry->value());
1688 }
1689
1690 } catch (...) { throw; }
1691 return;
1692 }
1693
1694 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1695 // "New Eng", "B", "B", "B", "", "I", "", "", "CCCSS"
1696
1697 // MA, NH, VT, MA, CT, RI
n3fjp_check_NEQP()1698 static void n3fjp_check_NEQP()
1699 {
1700 static std::string stNEQP = "CT MA ME NH RI VT";
1701 try {
1702 std::string st = inpState->value();
1703 std::string cnty = inpCounty->value();
1704
1705 if (cnty.length() == 5) {
1706 if (stNEQP.find(cnty.substr(cnty.length() - 3, 2)) != std::string::npos)
1707 st = cnty.substr(cnty.length() - 3, 2);
1708 }
1709
1710 if (progdefaults.SQSOinstate && !st.empty()) { // in region
1711 if (stNEQP.find(st) != std::string::npos) {
1712 if(!cnty.empty()) send_county(cnty);
1713 send_spcnum(st);
1714 } else
1715 send_spcnum(st);
1716 } else { // out of region
1717 if (!st.empty() && stNEQP.find(st) != std::string::npos) {
1718 if (!cnty.empty()) send_county(cnty);
1719 send_spcnum(st);
1720 }
1721 }
1722 } catch (...) { throw; }
1723
1724 return;
1725 }
1726
1727 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1728 // "7QP", "B", "B", "B", "", "I", "", "", "SSCCC"
1729 // AZ ID OR MT NV WA WY
n3fjp_check_7QP()1730 static void n3fjp_check_7QP()
1731 {
1732 try {
1733 static string st7QP = "AZ ID OR MT NV WA WY UT";
1734 std::string st = inpState->value();
1735 std::string cnty = inpCounty->value();
1736
1737 if (cnty.length() == 5 && !inpState->value()[0]) {
1738 if (st7QP.find(cnty.substr(0,2)) != std::string::npos)
1739 st = cnty.substr(0,2);
1740 }
1741
1742 if (progdefaults.SQSOinstate && !st.empty()) { // in region
1743 if (st7QP.find(st) != std::string::npos) {
1744 if (!cnty.empty()) send_county(cnty);
1745 send_spcnum(st);
1746 } else
1747 send_spcnum(st);
1748 } else { // out of region
1749 if (!st.empty() && st7QP.find(st) != std::string::npos) {
1750 if (!cnty.empty()) send_county(cnty);
1751 send_spcnum(st);
1752 }
1753 }
1754
1755 } catch (...) { throw; }
1756
1757 return;
1758 }
1759
1760 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1761 // "QSOP 1" "B", "B", "B", "", "I", "", "", ""
1762 //AL, AR, FL, GA, HI, IA, ID, IL, IN, KS, KY, LA, MO, MI, ND, NJ, BC, 7QP
n3fjp_check_QP1()1763 static void n3fjp_check_QP1()
1764 {
1765 try {
1766 std::string st = inpState->value();
1767 std::string cntry = cboCountry->value();
1768 if (st.empty())
1769 st = QSOparties.qso_parties[progdefaults.SQSOcontest].state;
1770
1771 if (inpState->value()[0])
1772 send_spcnum(inpState->value());
1773 if (inpVEprov->value()[0])
1774 send_spcnum(inpVEprov->value());
1775 if (!cntry.empty() && cntry != "USA")
1776 send_spcnum(cboCountry->value());
1777
1778 if (inpCounty->value()[0]) {
1779 if (st == "BC" ) { // British Columbia
1780 Cstates cs;
1781 send_county(cs.cnty_short("BC", inpCounty->value()));
1782 } else
1783 send_county(inpCounty->value());
1784 }
1785 } catch (...) { throw; }
1786
1787 return;
1788 }
1789
1790 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1791 // "QSOP 2" "B", "B", "B", "", "B", "", "", ""
1792
1793 // MT, NE, NY, OH, OK, ON, SK, TN, TX, VT, WA, ME
n3fjp_check_QP2()1794 static void n3fjp_check_QP2()
1795 {
1796 try {
1797 if (inpState->value()[0])
1798 send_spcnum(inpState->value());
1799 else if (inpVEprov->value()[0])
1800 send_spcnum(inpVEprov->value());
1801 else if (cboCountry->value()[0])
1802 send_spcnum(cboCountry->value());
1803 if (inpCounty->value()[0])
1804 send_county(inpCounty->value());
1805 } catch (...) { throw; }
1806
1807 return;
1808 }
1809
1810 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1811 // "QSOP 3" "", "B", "B", "B", "I", "", "", ""
1812
1813 // AZ, CA, MI, PA, VI
n3fjp_check_QP3()1814 static void n3fjp_check_QP3()
1815 {
1816 try {
1817 if (n3fjp_in_state) {
1818 if (inpState->value()[0]) {
1819 send_spcnum(inpState->value());
1820 // string county = states.county(inpState->value(), inpCounty->value());
1821 // if (!county.empty())
1822 // send_county(county);
1823 }
1824 if (inpCounty->value()[0])
1825 send_county(inpCounty->value());
1826 if (inpVEprov->value()[0])
1827 send_spcnum(inpVEprov->value());
1828 if (cboCountry->value()[0] && (strcmp(cboCountry->value(), "USA") != 0))
1829 send_spcnum(cboCountry->value());
1830 } else {
1831 // std::string stsh = states.state_short(inpState->value());
1832 // std::string county = states.county(stsh, inpCounty->value());
1833 // if (!county.empty()) {
1834 // send_county(county);
1835 // } else
1836 if (inpCounty->value()[0])
1837 send_county(inpCounty->value());
1838 }
1839 send_control("SERIALNOR", inpSerNo->value());
1840 } catch (...) { throw; }
1841
1842 return;
1843 }
1844
1845 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1846 // "QSOP 4" "", "B", "B", "", "I", "B", "", ""
1847
1848 // CO, MN, NM
1849 /*
1850 N3FJP's Colorado QSO Party Contest Log
1851 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYSPCNUM</CONTROL><VALUE></VALUE></CMD>
1852 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYNAMER</CONTROL><VALUE></VALUE></CMD>
1853 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYCOUNTYR</CONTROL><VALUE></VALUE></CMD>
1854 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYCALL</CONTROL><VALUE></VALUE></CMD>
1855 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>LBLDIALOGUE</CONTROL><VALUE>Ready to begin!<crlf>
1856 */
n3fjp_check_QP4()1857 static void n3fjp_check_QP4()
1858 {
1859 try {
1860 if (n3fjp_in_state) {
1861 std::string cntry = cboCountry->value();
1862 if (inpState->value()[0])
1863 send_spcnum(inpState->value());
1864 else if (inpVEprov->value()[0])
1865 send_spcnum(inpVEprov->value());
1866 else if (!cntry.empty() && cntry != "USA")
1867 send_county(inpCounty->value());
1868 if (inpCounty->value()[0])
1869 send_county(inpCounty->value());
1870 if (inpName->value()[0])
1871 send_name(inpName->value());
1872 } else {
1873 std::string st = QSOparties.qso_parties[progdefaults.SQSOcontest].state;
1874 // send_county(states.county(st, inpCounty->value()));
1875 send_county(inpCounty->value());
1876 if (inpName->value()[0])
1877 send_name(inpName->value());
1878 }
1879 } catch (...) { throw; }
1880
1881 return;
1882 }
1883
1884 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1885 // "QSOP 5" "B", "I", "B", "", "", "", "", ""
1886
1887 // SC, WV
n3fjp_check_QP5()1888 static void n3fjp_check_QP5()
1889 {
1890 try {
1891 if (n3fjp_in_state) {
1892 if (inpState->value()[0])
1893 send_spcnum(inpState->value());
1894 else if (inpVEprov->value()[0])
1895 send_spcnum(inpVEprov->value());
1896 else if (cboCountry->value()[0])
1897 send_spcnum(cboCountry->value());
1898 if (inpCounty->value()[0])
1899 send_county(inpCounty->value());
1900 }else {
1901 send_county(inpCounty->value());
1902 }
1903 } catch (...) { throw; }
1904
1905 return;
1906 }
1907
1908 // "QSO Party","rRST","rST","rCNTY","rSER","rXCHG","rNAM","rCAT","STCTY"
1909 // "QSOP 6" "B", "B", "B", "", "I", "", "", ""
1910
1911 // NC, WI
n3fjp_check_QP6()1912 static void n3fjp_check_QP6()
1913 {
1914 try {
1915 if (n3fjp_in_state) {
1916 if (inpCounty->value()[0])
1917 send_county(inpCounty->value());
1918 if (inpState->value()[0])
1919 send_spcnum(inpState->value());
1920 else if (inpVEprov->value()[0])
1921 send_spcnum(inpVEprov->value());
1922 else if (cboCountry->value()[0])
1923 send_spcnum(cboCountry->value());
1924 } else {
1925 // send_county(states.county(inpState->value(), inpCounty->value()));
1926 send_county(inpCounty->value());
1927 }
1928 } catch (...) { throw; }
1929 return;
1930 }
1931
check_log_data()1932 static void check_log_data()
1933 {
1934 try{
1935 switch (n3fjp_contest) {
1936 case FJP_FD:
1937 n3fjp_check_FD();
1938 break;
1939 case FJP_WFD:
1940 n3fjp_check_WFD();
1941 break;
1942 case FJP_KD:
1943 n3fjp_check_KD();
1944 break;
1945 case FJP_ARR:
1946 n3fjp_check_ARR();
1947 break;
1948 case FJP_RTTY:
1949 n3fjp_check_RTTY();
1950 break;
1951 case FJP_ASCR:
1952 n3fjp_check_ASCR();
1953 break;
1954 case FJP_JOTA:
1955 n3fjp_check_JOTA();
1956 break;
1957 case FJP_CQ_WPX:
1958 n3fjp_check_WPX();
1959 break;
1960 case FJP_IARI:
1961 n3fjp_check_IARI();
1962 break;
1963 case FJP_NAS:
1964 n3fjp_check_NAS();
1965 break;
1966 case FJP_CQWWRTTY:
1967 n3fjp_check_CQWWRTTY();
1968 break;
1969 case FJP_CQWWDX:
1970 n3fjp_check_CQWWDX();
1971 break;
1972 case FJP_SS:
1973 n3fjp_check_SS();
1974 break;
1975 case FJP_NAQP:
1976 n3fjp_check_NAQP();
1977 break;
1978 case FJP_1010:
1979 n3fjp_check_1010();
1980 break;
1981 case FJP_AIDX:
1982 n3fjp_check_AIDX();
1983 break;
1984 case FJP_AICW:
1985 n3fjp_check_AICW();
1986 break;
1987 case FJP_VHF:
1988 n3fjp_check_VHF();
1989 break;
1990 case FJP_WAE:
1991 n3fjp_check_WAE();
1992 break;
1993 case FJP_MDQP:
1994 n3fjp_check_MDQSP();
1995 break;
1996 case FJP_7QP:
1997 n3fjp_check_7QP();
1998 break;
1999 case FJP_NEQP:
2000 n3fjp_check_NEQP();
2001 break;
2002 case FJP_QP1:
2003 n3fjp_check_QP1();
2004 break;
2005 case FJP_QP2:
2006 n3fjp_check_QP2();
2007 break;
2008 case FJP_QP3:
2009 n3fjp_check_QP3();
2010 break;
2011 case FJP_QP4:
2012 n3fjp_check_QP4();
2013 break;
2014 case FJP_QP5:
2015 n3fjp_check_QP5();
2016 break;
2017 case FJP_QP6:
2018 n3fjp_check_QP6();
2019 break;
2020 case FJP_ACL:
2021 case FJP_NONE:
2022 default:
2023 n3fjp_check_GENERIC();
2024 }
2025 } catch (...) { throw; }
2026 }
2027
n3fjp_dupcheck()2028 int n3fjp_dupcheck()
2029 {
2030 guard_lock rx_lock(&n3fjp_mutex);
2031
2032 string chkcall = inpCall->value();
2033
2034 if (chkcall.length() < 3) return false;
2035 if ((chkcall.length() == 3) && isdigit(chkcall[2])) return false;
2036
2037 string cmd;
2038
2039 try {
2040 send_call(chkcall);
2041 send_band(strip(n3fjp_opband()));
2042 send_mode(n3fjp_tstmode());
2043 n3fjp_sendRSTS(inpRstOut->value());
2044 n3fjp_sendRSTR(inpRstIn->value());
2045 check_log_data();
2046
2047 send_action("CALLTAB");
2048 } catch (...) { throw; }
2049 return 0;
2050 }
2051
send_log_data()2052 static void send_log_data()
2053 {
2054 send_call(rec.getField(CALL));
2055 send_band(strip(n3fjp_opband()));
2056 send_freq(n3fjp_freq());
2057 send_mode(n3fjp_opmode());
2058 n3fjp_sendRSTS(rec.getField(RST_SENT));
2059 n3fjp_sendRSTR(rec.getField(RST_RCVD));
2060
2061 try {
2062 switch (n3fjp_contest) {
2063 case FJP_NONE:
2064 n3fjp_send_NONE();
2065 break;
2066 case FJP_FD:
2067 n3fjp_send_FD();
2068 break;
2069 case FJP_WFD:
2070 n3fjp_send_WFD();
2071 break;
2072 case FJP_KD:
2073 n3fjp_send_KD();
2074 break;
2075 case FJP_ARR:
2076 n3fjp_send_ARR();
2077 break;
2078 case FJP_RTTY:
2079 n3fjp_send_RTTY();
2080 break;
2081 case FJP_ASCR:
2082 n3fjp_send_ASCR();
2083 break;
2084 case FJP_JOTA:
2085 n3fjp_send_JOTA();
2086 break;
2087 case FJP_CQ_WPX:
2088 n3fjp_send_WPX();
2089 break;
2090 case FJP_IARI:
2091 n3fjp_send_IARI();
2092 break;
2093 case FJP_NAS:
2094 n3fjp_send_NAS();
2095 break;
2096 case FJP_CQWWRTTY:
2097 n3fjp_send_CQWWRTTY();
2098 break;
2099 case FJP_CQWWDX:
2100 n3fjp_send_CQWWDX();
2101 break;
2102 case FJP_SS:
2103 n3fjp_send_SS();
2104 break;
2105 case FJP_NAQP:
2106 n3fjp_send_NAQP();
2107 break;
2108 case FJP_1010:
2109 n3fjp_send_1010();
2110 break;
2111 case FJP_AIDX:
2112 n3fjp_send_AIDX();
2113 break;
2114 case FJP_AICW:
2115 n3fjp_send_AICW();
2116 break;
2117 case FJP_VHF:
2118 n3fjp_send_VHF();
2119 break;
2120 case FJP_WAE:
2121 n3fjp_send_WAE();
2122 break;
2123 case FJP_MDQP:
2124 n3fjp_send_MDQSP();
2125 break;
2126 case FJP_7QP:
2127 n3fjp_send_7QP();
2128 break;
2129 case FJP_NEQP:
2130 n3fjp_send_NEQP();
2131 break;
2132 case FJP_QP1:
2133 n3fjp_send_QP1();
2134 break;
2135 case FJP_QP2:
2136 n3fjp_send_QP2();
2137 break;
2138 case FJP_QP3:
2139 n3fjp_send_QP3();
2140 break;
2141 case FJP_QP4:
2142 n3fjp_send_QP4();
2143 break;
2144 case FJP_QP5:
2145 n3fjp_send_QP5();
2146 break;
2147 case FJP_QP6:
2148 n3fjp_send_QP6();
2149 break;
2150 case FJP_ACL:
2151 n3fjp_send_NONE();
2152 break;
2153 default:
2154 n3fjp_send_GENERIC();
2155 break;
2156 }
2157 send_command("NEXTSERIALNUMBER");
2158 } catch (...) { throw; }
2159 }
2160
enter_log_data()2161 static void enter_log_data()
2162 {
2163 try {
2164 send_log_data();
2165 send_action("ENTER");
2166 // if (n3fjp_contest != FJP_SS) {
2167 // string other = "XCVR:";
2168 // char szfreq[6];
2169 // snprintf(szfreq, sizeof(szfreq), "%d", (int)active_modem->get_txfreq());
2170 // other.append(ModeIsLSB(rec.getField(ADIF_MODE)) ? "LSB" : "USB");
2171 // other.append(" MODE:");
2172 // other.append(strip(rec.getField(ADIF_MODE)));
2173 // other.append(" WF:");
2174 // other.append(szfreq);
2175 // send_control("OTHER8", other);
2176 // }
2177
2178 } catch (...) { throw; }
2179 }
2180
send_data()2181 static void send_data()
2182 {
2183 try {
2184
2185 send_command("IGNORERIGPOLLS", "TRUE");
2186
2187 send_call(rec.getField(CALL));
2188 send_freq(n3fjp_freq());
2189 send_band(n3fjp_opband());
2190 send_mode(n3fjp_opmode());
2191
2192 enter_log_data();
2193
2194 send_command("IGNORERIGPOLLS", "FALSE");
2195
2196 } catch (...) { throw; }
2197 }
2198
send_data_norig()2199 static void send_data_norig()
2200 {
2201 try {
2202 string cmd;
2203
2204 send_call(rec.getField(CALL));
2205 cmd = "<CMD><CHANGEBM>";
2206 cmd.append("<BAND>").append(n3fjp_opband()).append("</BAND>");
2207 cmd.append("<MODE>").append(n3fjp_opmode()).append("</MODE>");
2208 cmd.append("</CMD>");
2209 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
2210
2211 enter_log_data();
2212
2213 } catch (...) { throw; }
2214 }
2215
get_n3fjp_frequency()2216 void get_n3fjp_frequency()
2217 {
2218 try {
2219 send_command("READBMF");
2220 } catch (...) { throw; }
2221 }
2222
do_n3fjp_add_record_entries()2223 void do_n3fjp_add_record_entries()
2224 {
2225 if(!n3fjp_socket) return;
2226 if (!n3fjp_connected) return;
2227
2228 string cmd, response, val;
2229
2230 try {
2231 if (n3fjp_has_xcvr_control == N3FJP)
2232 send_data();
2233 else
2234 send_data_norig();
2235
2236 } catch (const SocketException& e) {
2237 result.str("");
2238 result << "Error: " << e.error() << ", " << e.what();
2239 n3fjp_print(result.str());
2240 throw e;
2241 }
2242 n3fjp_bool_add_record = false;
2243 }
2244
n3fjp_set_freq(long f)2245 void n3fjp_set_freq(long f)
2246 {
2247 char szfreq[20];
2248 snprintf(szfreq, sizeof(szfreq), "%ld", f);
2249 string freq = szfreq;
2250 while (freq.length() < 7) freq.insert(0, "0");
2251 freq.insert(freq.length() - 6, ".");
2252
2253 string cmd;
2254
2255 cmd.assign("<CMD><CHANGEFREQ><VALUE>");
2256 cmd.append(freq);
2257 cmd.append("</VALUE><SUPPRESSMODEDEFAULT>TRUE</SUPPRESSMODEDEFAULT></CMD>");
2258
2259 { guard_lock send_lock(&send_this_mutex);
2260 send_this = cmd;
2261 }
2262 }
2263
n3fjp_set_ptt(int on)2264 void n3fjp_set_ptt(int on)
2265 {
2266 if (n3fjp_has_xcvr_control != N3FJP) return;
2267
2268 string cmd = "<CMD>";
2269 if (on) {
2270 if (progdefaults.enable_N3FJP_RIGTX)
2271 cmd.append("<RIGTX>");
2272 else
2273 cmd.append("<CWCOMPORTKEYDOWN>");
2274 } else {
2275 if (progdefaults.enable_N3FJP_RIGTX)
2276 cmd.append("<RIGRX>");
2277 else
2278 cmd.append("<CWCOMPORTKEYUP>");
2279 }
2280 cmd.append("</CMD>");
2281
2282 { guard_lock send_lock(&send_this_mutex);
2283 send_this = cmd;
2284 }
2285 }
2286
n3fjp_add_record(cQsoRec & record)2287 void n3fjp_add_record(cQsoRec &record)
2288 {
2289 if (!n3fjp_connected) return;
2290 rec = record;
2291 n3fjp_bool_add_record = true;
2292 }
2293
2294 std::string n3fjp_serno = "";
2295
n3fjp_parse_next_serial(string buff)2296 void n3fjp_parse_next_serial(string buff)
2297 {
2298 n3fjp_serno = ParseValueField("NEXTSERIALNUMBERRESPONSE", buff);
2299 updateOutSerNo();
2300 }
2301
2302 //======================================================================
2303 //
2304 //======================================================================
n3fjp_parse_response(string tempbuff)2305 void n3fjp_parse_response(string tempbuff)
2306 {
2307 if (tempbuff.empty()) return;
2308 size_t p1 = string::npos, p2 = string::npos;
2309
2310 if (tempbuff.find("RIGRESPONSE") != string::npos) {
2311 size_t p0 = tempbuff.find("<RIG>");
2312 if (p0 != string::npos) {
2313 p0 += strlen("<RIG>");
2314 string rigname = tempbuff.substr(p0);
2315 p0 = rigname.find("</RIG>");
2316 if (p0 != string::npos) {
2317 rigname.erase(p0);
2318 if (rigname != "None" && rigname != "Client API") {
2319 n3fjp_has_xcvr_control = N3FJP;
2320 send_command("READBMF");
2321 } else
2322 n3fjp_has_xcvr_control = FLDIGI;
2323 }
2324 }
2325 }
2326
2327 if (n3fjp_has_xcvr_control == N3FJP) {
2328 if ((p1 = tempbuff.find("<CHANGEFREQ><VALUE>")) != string::npos) {
2329 p1 += strlen("<CHANGEFREQ><VALUE>");
2330 p2 = tempbuff.find("</VALUE>", p1);
2331 if (p2 == string::npos) return;
2332 string sfreq = tempbuff.substr(p1, p2 - p1);
2333 REQ(adjust_freq, sfreq);
2334 } else if (tempbuff.find("<READBMFRESPONSE>") != string::npos) {
2335 string sfreq = ParseField(tempbuff, "FREQ");
2336 REQ(adjust_freq, sfreq);
2337 }
2338 }
2339
2340 if (tempbuff.find("<CALLTABEVENT>") != string::npos) {
2341 n3fjp_rxbuffer = tempbuff;
2342 REQ(n3fjp_parse_calltab_event, tempbuff);
2343 }
2344
2345 if (tempbuff.find("ALLFIELDSWVRESPONSE") != string::npos) {
2346 REQ(n3fjp_parse_data_stream, tempbuff);
2347 }
2348 if (tempbuff.find("<ENTEREVENT>") != string::npos) {
2349 send_command("NEXTSERIALNUMBER");
2350 }
2351 if (tempbuff.find("<NEXTSERIALNUMBERRESPONSE>") != string::npos) {
2352 REQ(n3fjp_parse_next_serial, tempbuff);
2353 }
2354
2355 if (tempbuff.find("CALLTABDUPEEVENT") != string::npos &&
2356 tempbuff.find("Duplicate") != string::npos) {
2357 if (tempbuff.find("Possible") != string::npos)
2358 REQ(show_dup, (void*)2);
2359 else
2360 REQ(show_dup, (void*)1);
2361 }
2362 }
2363
2364 //======================================================================
2365 //
2366 //======================================================================
n3fjp_rcv_data()2367 void n3fjp_rcv_data()
2368 {
2369 string tempbuff = "";
2370 try {
2371 n3fjp_rcv(tempbuff, progdefaults.enable_N3FJP_log);
2372 n3fjp_parse_response(tempbuff);
2373 } catch (const SocketException& e) {
2374 result.str("");
2375 result << "n3fjp_rcv_data()::failed " << e.error() << " " << e.what();
2376 n3fjp_print(result.str());
2377 throw e;
2378 } catch (...) { throw; }
2379 }
2380
2381 static int logger_nbr = 0;
2382
match(std::string s1,std::string s2)2383 inline bool match(std::string s1, std::string s2)
2384 {
2385 return (s1.find(s2) != std::string::npos ||
2386 s2.find(s1) != std::string::npos);
2387 }
2388
select_fldigi_logging()2389 static void select_fldigi_logging()
2390 {
2391 // check for specific contest
2392 size_t n = 0;
2393 std::string logger = n3fjp_logger[logger_nbr].program;
2394
2395 n3fjp_print(std::string("logger: ").append(logger));
2396
2397 if (logger == "Amateur Contact Log") {
2398 listbox_contest->index(0);
2399 progdefaults.logging = 0;
2400 UI_select();
2401 return;
2402 }
2403
2404 if ((n = logger.find("Jamboree") != std::string::npos)) {
2405 logger.insert(0, "ARRL ");
2406 }
2407 if (logger.find("CQ WW DX RTTY") != std::string::npos)
2408 logger = "WW DX RTTY";
2409
2410 progdefaults.CONTESTnotes = "";
2411
2412 for (int n = 2; !contests[n].name.empty(); n++) {
2413 if (match(contests[n].name, logger)) {
2414 progdefaults.logging = n;
2415 listbox_contest->index(n);
2416 listbox_QP_contests->index(0);
2417 UI_select();
2418 progdefaults.CONTESTnotes = contests[progdefaults.logging].notes;
2419 inp_contest_notes->value(progdefaults.CONTESTnotes.c_str());
2420 n3fjp_print(std::string("found: ").append(contests[n].name));
2421 return;
2422 }
2423 }
2424 n3fjp_print(std::string("Check for SQSO: ").append(logger));
2425
2426 if ((n = logger.find("QP Contest Log")) != std::string::npos) {
2427 logger.erase(n + 2, 12);
2428 progdefaults.logging = LOG_SQSO;
2429 listbox_contest->index(progdefaults.logging);
2430 n3fjp_print(std::string("Out of state SQSO log: ").append(logger));
2431 }
2432 else if ((n = logger.find(" QSO Party Contest Log")) != std::string::npos) {
2433 logger.erase(n + 10);
2434 progdefaults.logging = LOG_SQSO;
2435 listbox_contest->index(progdefaults.logging);
2436 n3fjp_print(std::string("In state SQSO log: ").append(logger));
2437 }
2438
2439 for (n = 1; QSOparties.qso_parties[n].contest[0]; n++) {
2440 if (logger == QSOparties.qso_parties[n].contest) {
2441 n3fjp_print(std::string("QSOparty: ").append(QSOparties.qso_parties[n].contest));
2442 progdefaults.SQSOcontest = n;
2443 listbox_QP_contests->index(progdefaults.SQSOcontest - 1);
2444 inp_contest_notes->value(progdefaults.CONTESTnotes.c_str());
2445 progdefaults.CONTESTnotes = QSOparties.qso_parties[progdefaults.SQSOcontest].notes;
2446 adjust_for_contest(0);
2447 }
2448 }
2449 inp_contest_notes->value(progdefaults.CONTESTnotes.c_str());
2450
2451 UI_select();
2452 clearQSO();
2453 return;
2454 }
2455
fldigi_no_contest()2456 static void fldigi_no_contest()
2457 {
2458 progdefaults.SQSOcontest = 0;//1;
2459 progdefaults.logging = 0;
2460 adjust_for_contest(0);
2461 UI_select();
2462 set_log_colors();
2463 clearQSO();
2464 listbox_contest->index(0);
2465 }
2466
2467 static int connect_tries = 0;
2468
connect_to_n3fjp_server()2469 static bool connect_to_n3fjp_server()
2470 {
2471 try {
2472 n3fjp_serno.clear();
2473
2474 if (!n3fjp_connected)
2475 n3fjp_socket->connect();
2476
2477 if (!n3fjp_socket->is_connected()) {
2478 MilliSleep(200);
2479 n3fjp_socket->connect();
2480 if (!n3fjp_socket->is_connected()) {
2481 if (!connect_tries--) {
2482 result.str("");
2483 result << "Cannot connect to server: " << n3fjp_socket->fd();
2484 n3fjp_print(result.str());
2485 connect_tries = 20;
2486 }
2487 return false;
2488 }
2489 result.str("");
2490 result << "connected to n3fjp server: " << n3fjp_socket->fd();
2491 n3fjp_print(result.str());
2492 connect_tries = 0;
2493 }
2494
2495 string buffer;
2496
2497 string cmd = "<CMD><PROGRAM></CMD>";
2498 n3fjp_send(cmd, true);
2499
2500 buffer.clear();
2501 size_t n;
2502 for (n = 0; n < 10; n++) {
2503 n3fjp_rcv(buffer, true);
2504 if (!buffer.empty()) break;
2505 }
2506 if (buffer.empty()) {
2507 n3fjp_print("N3FJP logger not responding");
2508 return false;
2509 }
2510
2511 string info = ParseField(buffer, "PGM");
2512 connected_to = info;
2513
2514 n3fjp_contest = FJP_NONE;
2515
2516 n = info.find("N3FJP's ");
2517 if (n != std::string::npos) info.erase(n, 8);
2518
2519 if (info.find("Winter") != std::string::npos)
2520 info = "Winter FD";
2521
2522 n3fjp_print(std::string("Info: ").append(info));
2523
2524 for (n = 0; n < sizeof(n3fjp_logger) / sizeof(*n3fjp_logger); n++) {
2525 if (info.find(n3fjp_logger[n].program) == 0) {
2526 n3fjp_contest = n3fjp_logger[n].contest;
2527 n3fjp_in_state = n3fjp_logger[n].in_state;
2528 logger_nbr = n;
2529 REQ(select_fldigi_logging);
2530 break;
2531 }
2532 }
2533 if (n == sizeof(n3fjp_logger) / sizeof(*n3fjp_logger)) {
2534 n3fjp_print(string(info).append(" not supported by fldigi"));
2535 return false;
2536 }
2537 else
2538 n3fjp_print(std::string("Connected to: ").append(n3fjp_logger[n].program));
2539
2540 send_command("NEXTSERIALNUMBER");
2541
2542 info.insert(0, "Connected to ");
2543
2544 string ver = ParseField(buffer, "VER");
2545 info.append(", Ver ").append(ver);
2546
2547 n3fjp_connected = true;
2548 REQ(set_connect_box);
2549
2550 cmd = " <CMD><VISIBLEFIELDS></CMD>";
2551 n3fjp_send(cmd, true);
2552
2553 buffer.clear();
2554 n3fjp_rcv(buffer, true);
2555
2556 cmd = "<CMD><CALLTABENTEREVENTS><VALUE>TRUE</VALUE></CMD>";
2557 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
2558
2559 cmd = "<CMD><READOFFSETENABLED></CMD>";
2560 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
2561
2562 cmd = "<CMD><READOFFSET></CMD>";
2563 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
2564
2565 cmd = "<CMD><READMODEDEFAULTSUPPRESS></CMD>";
2566 n3fjp_send(cmd, progdefaults.enable_N3FJP_log);
2567
2568 cmd = "RIGENABLED";
2569 send_command(cmd);
2570
2571 } catch (const SocketException& e) {
2572 result.str("");
2573 result << e.what() << "(" << e.error() << ")";
2574 n3fjp_print(result.str());
2575 connected_to.clear();
2576 LOG_ERROR("%s", result.str().c_str());
2577 } catch (...) {
2578 n3fjp_print("Caught unknown error");
2579 LOG_ERROR("%s", "Caught unknown error");
2580 connected_to.clear();
2581 }
2582 return true;
2583 }
2584
2585 //======================================================================
2586 //
2587 //======================================================================
2588
n3fjp_start()2589 void n3fjp_start()
2590 {
2591 n3fjp_ip_address = progdefaults.N3FJP_address;
2592 n3fjp_ip_port = progdefaults.N3FJP_port;
2593
2594 try {
2595 if (n3fjp_socket) delete n3fjp_socket;
2596
2597 n3fjp_socket = new Socket(
2598 Address( n3fjp_ip_address.c_str(),
2599 n3fjp_ip_port.c_str(),
2600 "tcp") );
2601 if (!n3fjp_socket) return;
2602
2603 n3fjp_socket->set_timeout(0.20);//0.05);
2604 n3fjp_socket->set_nonblocking(true);
2605
2606 result.str("");
2607 result << "Client socket " << n3fjp_socket->fd();
2608 n3fjp_print(result.str());
2609 }
2610 catch (const SocketException& e) {
2611 result.str("");
2612 result << e.what() << "(" << e.error() << ")";
2613 n3fjp_print(result.str());
2614 LOG_ERROR("%s", result.str().c_str() );
2615 delete n3fjp_socket;
2616 n3fjp_socket = 0;
2617 n3fjp_connected = false;
2618 REQ(set_connect_box);
2619 n3fjp_has_xcvr_control = UNKNOWN;
2620 } catch (...) {
2621 n3fjp_print("Caught unknown error");
2622 n3fjp_print(result.str());
2623 LOG_ERROR("%s", result.str().c_str() );
2624 delete n3fjp_socket;
2625 n3fjp_socket = 0;
2626 n3fjp_connected = false;
2627 REQ(set_connect_box);
2628 n3fjp_has_xcvr_control = UNKNOWN;
2629 }
2630 }
2631
2632 //======================================================================
2633 // Disconnect from N3FJP tcpip server
2634 //======================================================================
n3fjp_disconnect(bool clearlog)2635 void n3fjp_disconnect(bool clearlog)
2636 {
2637 if (n3fjp_socket) {
2638 n3fjp_send("", false);//progdefaults.enable_N3FJP_log);
2639 delete n3fjp_socket;
2640 n3fjp_socket = 0;
2641 }
2642 n3fjp_connected = false;
2643 n3fjp_has_xcvr_control = UNKNOWN;
2644 n3fjp_serno.clear();
2645 connected_to.clear();
2646 REQ(set_connect_box);
2647 if (clearlog) REQ(fldigi_no_contest);
2648 n3fjp_print("Disconnected");
2649
2650 }
2651
2652 //======================================================================
2653 // Thread loop
2654 //======================================================================
2655
n3fjp_loop(void * args)2656 void *n3fjp_loop(void *args)
2657 {
2658 SET_THREAD_ID(N3FJP_TID);
2659
2660 int loopcount = 9;
2661 int n3fjp_looptime = 100; // initially 0.1 second delay to connect
2662 while(1) {
2663 if (n3fjp_exit) break;
2664
2665 MilliSleep(10);
2666 if (n3fjp_wait) n3fjp_wait -= 10;
2667 if (n3fjp_looptime) n3fjp_looptime -= 10;
2668
2669 if (n3fjp_wait > 0) continue;
2670
2671 if (n3fjp_looptime > 0) continue;
2672
2673 n3fjp_looptime = 250; // r/w to N3FJP logger every 1/4 second
2674
2675 loopcount = (loopcount + 1) % 10;
2676 if (progdefaults.connect_to_n3fjp) {
2677 if (!n3fjp_socket || (n3fjp_socket->fd() == -1))
2678 n3fjp_start();
2679
2680 else {
2681 if ((n3fjp_ip_address != progdefaults.N3FJP_address) ||
2682 (n3fjp_ip_port != progdefaults.N3FJP_port) ) {
2683 n3fjp_disconnect(true);
2684 n3fjp_start();
2685 }
2686
2687 if (!n3fjp_connected) {
2688 if (loopcount == 0)
2689 if (!connect_to_n3fjp_server())
2690 n3fjp_disconnect(false);
2691 } else try { // insure connection still up (2.5 second interval)
2692 if (loopcount == 0) {
2693 guard_lock send_lock(&send_this_mutex);
2694 std::string buffer;
2695 string cmd = "<CMD><PROGRAM></CMD>";
2696 n3fjp_send(cmd, false);
2697 size_t n;
2698 for (n = 0; n < 10; n++) {
2699 n3fjp_rcv(buffer, false);
2700 if (!buffer.empty()) break;
2701 }
2702 if (buffer.empty()) {
2703 n3fjp_print(std::string("Lost server connection to ").append(connected_to));
2704 n3fjp_disconnect(true);
2705 continue;
2706 }
2707 }
2708 if (n3fjp_has_xcvr_control == FLDIGI)
2709 n3fjp_send_freq_mode();
2710 if (!send_this.empty()) {
2711 guard_lock send_lock(&send_this_mutex);
2712 n3fjp_send(send_this, progdefaults.enable_N3FJP_log);
2713 send_this.clear();
2714 } else if (n3fjp_bool_add_record)
2715 do_n3fjp_add_record_entries();
2716 else {
2717 guard_lock rx_lock(&n3fjp_mutex);
2718 n3fjp_rcv_data();
2719 }
2720 } catch (const SocketException& e) {
2721 result.str("");
2722 result << "Error: " << e.error() << ", " << e.what();
2723 n3fjp_print(result.str());
2724 n3fjp_disconnect(true);
2725 } catch (...) {
2726 n3fjp_print("Caught unknown error");
2727 n3fjp_disconnect(true);
2728 }
2729 }
2730 } else if (n3fjp_connected)
2731 n3fjp_disconnect(true);
2732 }
2733 // exit the n3fjp thread
2734 SET_THREAD_CANCEL();
2735 return NULL;
2736 }
2737
2738 //======================================================================
2739 //
2740 //======================================================================
2741
n3fjp_init(void)2742 void n3fjp_init(void)
2743 {
2744 n3fjp_enabled = false;
2745 n3fjp_exit = false;
2746
2747 if (pthread_create(&n3fjp_thread, NULL, n3fjp_loop, NULL) < 0) {
2748 LOG_ERROR("pthread_create failed");
2749 return;
2750 }
2751
2752 LOG_INFO("N3FJP logger thread started");
2753
2754 pathname = DebugDir;
2755 pathname.append("n3fjp_data_stream.txt");
2756 rotate_log(pathname);
2757 FILE *n3fjplog = fl_fopen(pathname.c_str(), "w");
2758 fprintf(n3fjplog, "N3FJP / fldigi tcpip log\n\n");
2759 fclose(n3fjplog);
2760
2761 n3fjp_enabled = true;
2762 }
2763
2764 //======================================================================
2765 //
2766 //======================================================================
n3fjp_close(void)2767 void n3fjp_close(void)
2768 {
2769 if (!n3fjp_enabled) return;
2770
2771 guard_lock close_lock(&n3fjp_socket_mutex);
2772
2773 n3fjp_exit = true;
2774 CANCEL_THREAD(n3fjp_thread);
2775 pthread_join(n3fjp_thread, NULL);
2776 n3fjp_enabled = false;
2777
2778 LOG_INFO("%s", "N3FJP logger thread terminated. ");
2779
2780 if(n3fjp_socket) {
2781 delete n3fjp_socket;
2782 n3fjp_socket = 0;
2783 }
2784
2785 }
2786
2787 /*
2788 FLDIGI log fields
2789
2790 FREQ QSO frequency in Mhz
2791 CALL contacted stations CALLSIGN
2792 MODE QSO mode
2793 NAME contacted operators NAME
2794 QSO_DATE QSO date
2795 QSO_DATE_OFF QSO date OFF, according to ADIF 2.2.6
2796 TIME_OFF HHMM or HHMMSS in UTC
2797 TIME_ON HHMM or HHMMSS in UTC
2798 QTH contacted stations city
2799 RST_RCVD received signal report
2800 RST_SENT sent signal report
2801 STATE contacted stations STATE
2802 VE_PROV 2 letter abbreviation for Canadian Province
2803 NOTES QSO notes
2804
2805 QSLRDATE QSL received date
2806 QSLSDATE QSL sent date
2807
2808 EQSLRDATE EQSL received date
2809 EQSLSDATE EQSL sent date
2810
2811 LOTWRDATE EQSL received date
2812 LOTWSDATE EQSL sent date
2813
2814 GRIDSQUARE contacted stations Maidenhead Grid Square
2815 BAND QSO band
2816 CNTY secondary political subdivision, ie: county
2817 COUNTRY contacted stations DXCC entity name
2818 CQZ contacted stations CQ Zone
2819 DXCC contacted stations Country Code
2820 QSL_VIA contacted stations QSL manager
2821 IOTA Islands on the air
2822 ITUZ ITU zone
2823 CONT contacted stations continent
2824
2825 SRX received serial number for a contest QSO
2826 STX QSO transmitted serial number
2827
2828 XCHG1 contest exchange received
2829 MYXCHG contest exchange sent
2830
2831 CLASS Field Day class received
2832 ARRL_SECT Field Day section received
2833
2834 TX_PWR power transmitted by this station
2835
2836 OP_CALL Callsign of person logging the QSO
2837 STA_CALL Callsign of transmitting station
2838 MY_GRID Xmt station locator
2839 MY_CITY Xmt station city
2840
2841 SS_SEC CW sweepstakes section
2842 SS_SERNO CW sweepstakes serial number received
2843 SS_PREC CW sweepstakes precedence
2844 SS_CHK CW sweepstakes check
2845
2846 AGE contacted operators age in years
2847 TEN_TEN contacted stations ten ten #
2848 CHECK contacted stations contest identifier
2849
2850 |-------------------------------------------------------------|
2851 | N3FJP field | FLDIGI LOG FIELD |
2852 |--------------------------------|----------------------------|
2853 | txtEntry1010 | rec.getField(TEN_TEN) |
2854 | txtEntryCall | rec.getField(CALL) |
2855 | txtEntryCheck (Rookie Roundup) | rec.getField(CHECK) |
2856 | txtEntryCheck (1010 ??) ) | rec.getField(CHECK) |
2857 | txtEntryClass | rec.getField(CLASS) |
2858 | txtEntryCountyR | rec.getField(CNTY) |
2859 | txtEntryGrid | rec.getField(GRIDSQUARE) |
2860 | txtEntryNameR | rec.getField(NAME) |
2861 | txtEntryRSTR | rec.getField(RST_RCVD) |
2862 | txtEntryRSTS | rec.getField(RST_SENT) |
2863 | txtEntrySection | rec.getField(ARRL_SECT) |
2864 | txtEntrySection | rec.getField(SS_SEC) |
2865 | txtEntrySerialNoT | rec.getField(STX) |
2866 | txtEntrySerialNoR | rec.getField(SRX) |
2867 | txtEntrySpcNum | rec.getField(XCHG1) |
2868 | txtEntryState | rec.getField(STATE) |
2869 | txtEntryState | rec.getField(VE_PROV) ?? |
2870 |-------------------------------------------------------------|
2871
2872 Use this command to query N3FJP logger to find which fields are visible
2873 for any given program.
2874
2875 <CMD><VISIBLEFIELDS></CMD>
2876 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYCOUNTYR</CONTROL><VALUE></VALUE></CMD>
2877 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYSTATE</CONTROL><VALUE></VALUE></CMD>
2878 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYCOUNTRYWORKED</CONTROL><VALUE></VALUE></CMD>
2879 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYMODE</CONTROL><VALUE></VALUE></CMD>
2880 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYBAND</CONTROL><VALUE></VALUE></CMD>
2881 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYDATE</CONTROL><VALUE></VALUE></CMD>
2882 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYTIMEOFF</CONTROL><VALUE></VALUE></CMD>
2883 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYTIMEON</CONTROL><VALUE></VALUE></CMD>
2884 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYRSTS</CONTROL><VALUE></VALUE></CMD>
2885 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYRSTR</CONTROL><VALUE></VALUE></CMD>
2886 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYPOWER</CONTROL><VALUE></VALUE></CMD>
2887 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYOTHER1</CONTROL><VALUE></VALUE></CMD>
2888 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYNAMER</CONTROL><VALUE></VALUE></CMD>
2889 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYFREQUENCY</CONTROL><VALUE></VALUE></CMD>
2890 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYCOMMENTS</CONTROL><VALUE></VALUE></CMD>
2891 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>TXTENTRYCALL</CONTROL><VALUE></VALUE></CMD>
2892 <CMD><VISIBLEFIELDSRESPONSE><CONTROL>LBLDIALOGUE</CONTROL><VALUE>Ready to begin!</VALUE></CMD>
2893
2894 Africa All Mode: RST / Serial Received
2895 ARRL Field Day: Class / Section
2896 ARRL Kids Day: Name / Age / SPCNum
2897 ARRL Rookie Roundup: Name / Check / SPCNum
2898 ARRL RTTY: RST / SPCNum
2899 ARRL School Club Roundup: RST / Class / SPCNum / Name (optional)
2900 CQ WPX: RST / Serial Received
2901 CQ WW RTTY: RST / CQ Zone (autofilled from call) / State (or Province)
2902 Italian ARI International DX: RST / SPCNum
2903 Jamboree On The Air (lots of unrequired fields)
2904 NCJ North American QSO Party: Name / SPCNum
2905 NCJ North American Sprint: Serial Received / Name / SPCNum
2906 State QSO Parties, varies:
2907 Name
2908 State
2909 County
2910 Serial Received
2911 Section
2912 SPCNum
2913 Ten Ten: Name / SPCNum / 1010 number
2914 VHF: Grid / RST
2915 Worked All Europe: RST / Serial Received (QTCs not coded in API)
2916 Winter Field Day: Category (use class, just like ARRL Field Day) / Section
2917
2918 */
2919