1 // ----------------------------------------------------------------------------
2 // configuration.cxx
3 //
4 // Copyright (C) 2006-2010
5 // Dave Freese, W1HKJ
6 // Copyright (C) 2007-2008
7 // Leigh L. Klotz, Jr., WA5ZNU
8 // Copyright (C) 2007-2010
9 // Stelios Bounanos, M0GLD
10 // Copyright (C) 2013
11 // Remi Chateauneu, F4ECW
12 //
13 // This file is part of fldigi.
14 //
15 // Fldigi is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
19 //
20 // Fldigi is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU General Public License for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
27 // ----------------------------------------------------------------------------
28
29 #include <config.h>
30
31 #include "configuration.h"
32 #include "confdialog.h"
33 #include "xmlreader.h"
34 #include "soundconf.h"
35 #include "fl_digi.h"
36 #include "main.h"
37 #include "gettext.h"
38 #include "nls.h"
39 #include "icons.h"
40 #include "rigsupport.h"
41 #include "contest.h"
42
43 #if USE_HAMLIB
44 #include "hamlib.h"
45 #include "rigclass.h"
46 #endif
47
48 #include "rigio.h"
49 #include "rigxml.h"
50 #include "nanoIO.h"
51 #include "debug.h"
52
53 #include <FL/Fl_Tooltip.H>
54
55 #include <unistd.h>
56 #include <iostream>
57 #include <fstream>
58 #include <map>
59 #include <sstream>
60
61 #ifdef __linux__
62 # include <dirent.h>
63 # include <limits.h>
64 # include <errno.h>
65 # include <glob.h>
66 #endif
67 #ifdef __APPLE__
68 # include <glob.h>
69 #endif
70 #ifndef __CYGWIN__
71 # include <sys/stat.h>
72 #else
73 # include <fcntl.h>
74 #endif
75
76 // this tests depends on a modified FL/filename.H in the Fltk-1.3.0
77 // change
78 //# if defined(WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
79 // to
80 //# if defined(WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WOE32__)
81
82 #include <dirent.h>
83
84 using namespace std;
85
86
87 const char *szBaudRates[] = {
88 "",
89 "300","600","1200","2400",
90 "4800","9600","19200","38400",
91 "57600","115200","230400","460800"};
92
93 const char *szBands[] = {
94 "",
95 "1830", "3580", "7030", "7070", "10138",
96 "14070", "18100", "21070", "21080", "24920", "28070", "28120", 0};
97
operator <<(ostream & out,const RGB & rgb)98 ostream& operator<<(ostream& out, const RGB& rgb)
99 {
100 return out << (int)rgb.R << ' ' << (int)rgb.G << ' ' << (int)rgb.B;
101 }
operator >>(istream & in,RGB & rgb)102 istream& operator>>(istream& in, RGB& rgb)
103 {
104 int i;
105 in >> i; rgb.R = i;
106 in >> i; rgb.G = i;
107 in >> i; rgb.B = i;
108 return in;
109
110 }
operator <<(ostream & out,const RGBI & rgbi)111 ostream& operator<<(ostream& out, const RGBI& rgbi)
112 {
113 return out << (int)rgbi.R << ' ' << (int)rgbi.G << ' ' << (int)rgbi.B;
114 }
operator >>(istream & in,RGBI & rgbi)115 istream& operator>>(istream& in, RGBI& rgbi)
116 {
117 int i;
118 in >> i; rgbi.R = i;
119 in >> i; rgbi.G = i;
120 in >> i; rgbi.B = i;
121 return in;
122 }
123
124 // This allows to put tag elements into containers
125 class tag_base
126 {
127 public:
tag_base(const char * t,const char * d="")128 tag_base(const char* t, const char* d = "") : tag(t), doc(d) { }
129 virtual void write(ostream& out) const = 0;
130 virtual void read(const char* data) = 0;
~tag_base()131 virtual ~tag_base() { }
132 const char* tag;
133 const char* doc;
134 };
135
136 // This will handle every type that has << and >> stream operators
137 template <typename T>
138 class tag_elem : public tag_base
139 {
140 public:
tag_elem(const char * t,const char * d,T & v)141 tag_elem(const char* t, const char* d, T& v) : tag_base(t, d), var(v) { }
write(ostream & out) const142 void write(ostream& out) const
143 {
144 out << "<!-- " << doc << " -->\n"
145 << '<' << tag << '>' << var << "</" << tag << ">\n\n";
146 }
read(const char * data)147 void read(const char* data)
148 {
149 istringstream iss(data);
150 iss >> var;
151 }
152 T& var;
153 };
154
155 // Instantiate an explicit tag_elem<T> for types that require unusual handling.
156
157 // Special handling for strings
158 template <>
159 class tag_elem<string> : public tag_base
160 {
161 public:
tag_elem(const char * t,const char * d,string & s)162 tag_elem(const char* t, const char* d, string& s) : tag_base(t, d), str(s) { }
write(ostream & out) const163 void write(ostream& out) const
164 {
165 string s = str;
166 string s2 = doc;
167
168 string::size_type i = s.find('&');
169 while (i != string::npos) {
170 s.replace(i, 1, "&");
171 i = s.find('&', i + 1);
172 }
173 while ((i = s.find('<')) != string::npos)
174 s.replace(i, 1, "<");
175 while ((i = s.find('>')) != string::npos)
176 s.replace(i, 1, ">");
177 while ((i = s.find('"')) != string::npos)
178 s.replace(i, 1, """);
179 while ((i = s.find('\'')) != string::npos)
180 s.replace(i, 1, "'");
181
182 i = s2.find('&');
183 while (i != string::npos) {
184 s2.replace(i, 1, "&");
185 i = s2.find('&', i + 1);
186 }
187 while ((i = s2.find('<')) != string::npos)
188 s2.replace(i, 1, "<");
189 while ((i = s2.find('>')) != string::npos)
190 s2.replace(i, 1, ">");
191 while ((i = s2.find('"')) != string::npos)
192 s2.replace(i, 1, """);
193 while ((i = s2.find('\'')) != string::npos)
194 s2.replace(i, 1, "'");
195
196 out << "<!-- " << s2 << " -->\n"
197 << '<' << tag << '>' << s << "</" << tag << ">\n\n";
198 }
read(const char * data)199 void read(const char* data) { str = data; }
200 string& str;
201 };
202
203 // Special handling for mode bitsets
204 template <>
205 class tag_elem<mode_set_t> : public tag_base
206 {
207 public:
tag_elem(const char * t,const char * d,mode_set_t & m)208 tag_elem(const char* t, const char* d, mode_set_t& m) : tag_base(t, d), modes(m) { }
write(ostream & out) const209 void write(ostream& out) const
210 {
211 out << "<!-- " << doc << " -->\n" << '<' << tag << '>';
212 for (size_t i = 0; i < modes.size(); i++) {
213 if (!modes.test(i))
214 out << mode_info[i].name << ',';
215 }
216 out << ",</" << tag << ">\n\n";
217 }
read(const char * data)218 void read(const char* data)
219 {
220 string sdata = data, smode, tstmode;
221 modes.set();
222 size_t p = sdata.find(",");
223 while ((p != string::npos) && (p != 0)) {
224 smode = sdata.substr(0, p);
225
226 for (size_t i = 0; i < modes.size(); i++) {
227 tstmode = mode_info[i].name;
228 if (smode == tstmode) {
229 modes.set(i,0);
230 break;
231 }
232 }
233 sdata.erase(0, p+1);
234 p = sdata.find(",");
235 }
236 }
237 mode_set_t& modes;
238 };
239
240 // By redefining the ELEM_ macro, we can control what the CONFIG_LIST macro
241 // will expand to, and accomplish several things:
242 // 1) Declare "struct configuration". See ELEM_DECLARE_CONFIGURATION
243 // in configuration.h.
244 // 2) Define progdefaults, the configuration struct that is initialised with
245 // fldigi's default options
246 #define ELEM_PROGDEFAULTS(type_, var_, tag_, doc_, ...) __VA_ARGS__,
247 // 3) Define an array of tag element pointers
248 #define ELEM_TAG_ARRAY(type_, var_, tag_, doc_, ...) \
249 (*tag_ ? new tag_elem<type_>(tag_, "type: " #type_ "; default: " #__VA_ARGS__ "\n" doc_, \
250 progdefaults.var_) : 0),
251
252 // First define the default config
253 #undef ELEM_
254 #define ELEM_ ELEM_PROGDEFAULTS
255 configuration progdefaults = { CONFIG_LIST };
256
257
writeDefaultsXML()258 void configuration::writeDefaultsXML()
259 {
260 string deffname(HomeDir);
261 deffname.append("fldigi_def.xml");
262
263 string deffname_backup(deffname);
264 deffname_backup.append("-old");
265 remove(deffname_backup.c_str());
266 rename(deffname.c_str(), deffname_backup.c_str());
267
268 ofstream f(deffname.c_str());
269 if (!f) {
270 LOG_ERROR("Could not write %s", deffname.c_str());
271 return;
272 }
273
274 // create an array
275 #undef ELEM_
276 #define ELEM_ ELEM_TAG_ARRAY
277 tag_base* tag_list[] = { CONFIG_LIST };
278
279 // write all variables with non-empty tags to f
280 f << "<FLDIGI_DEFS>\n\n";
281 for (size_t i = 0; i < sizeof(tag_list)/sizeof(*tag_list); i++) {
282 if (tag_list[i]) {
283 tag_list[i]->write(f);
284 delete tag_list[i];
285 }
286 }
287 f << "</FLDIGI_DEFS>\n";
288 f.close();
289 }
290
log_excluded_modes(void)291 static void log_excluded_modes(void)
292 {
293 return;
294 struct {
295 mode_set_t* modes;
296 const char* msgstr;
297 } excluded[] = {
298 { &progdefaults.rsid_rx_modes, "RSID (rx)" },
299 { &progdefaults.rsid_tx_modes, "RSID (tx)" },
300 { &progdefaults.cwid_modes, "CWID" },
301 { &progdefaults.videoid_modes, "VIDEOID" }
302 };
303 string buf;
304 for (size_t i = 0; i < sizeof(excluded)/sizeof(*excluded); i++) {
305 size_t n = excluded[i].modes->size();
306 if (excluded[i].modes->count() == n)
307 continue;
308 buf.erase();
309 for (size_t j = 0; j < n; j++) {
310 if (!excluded[i].modes->test(j)) {
311 if (!buf.empty())
312 buf += ' ';
313 buf += mode_info[j].sname;
314 }
315 }
316 LOG(debug::QUIET_LEVEL, debug::LOG_OTHER, "%-10s: %s", excluded[i].msgstr, buf.c_str());
317 }
318 }
319
readDefaultsXML()320 bool configuration::readDefaultsXML()
321 {
322 // Decode all RSID modes
323 rsid_rx_modes.set();
324 // Don't transmit RSID or VideoID for CW, PSK31, RTTY
325 rsid_tx_modes.set().reset(MODE_CW).reset(MODE_PSK31).reset(MODE_RTTY);
326 videoid_modes = rsid_tx_modes;
327 // Don't transmit CWID for CW
328 cwid_modes.set().reset(MODE_CW);
329 // Show all op modes
330 visible_modes.set();
331
332 string deffname = HomeDir;
333 deffname.append("fldigi_def.xml");
334 ifstream f(deffname.c_str());
335 if (!f)
336 return false;
337
338 string xmlbuf;
339
340 f.seekg(0, ios::end);
341 xmlbuf.reserve(f.tellg()); // reserve some space to avoid reallocations
342 f.seekg(0, ios::beg);
343
344 char line[2048];
345 while (f.getline(line, sizeof(line)))
346 xmlbuf.append(line).append("\n");
347 f.close();
348
349 IrrXMLReader* xml = createIrrXMLReader(new IIrrXMLStringReader(xmlbuf));
350 if (!xml)
351 return false;
352
353 // create a TAG_NAME -> ELEMENT map
354 typedef map<string, tag_base*> tag_map_t;
355 tag_map_t tag_map;
356
357 tag_base* tag_list[] = { CONFIG_LIST };
358 for (size_t i = 0; i < sizeof(tag_list)/sizeof(*tag_list); i++)
359 if (tag_list[i])
360 tag_map[tag_list[i]->tag] = tag_list[i];
361
362 // parse the xml buffer
363 tag_map_t::const_iterator i = tag_map.end();
364 while(xml->read()) {
365 switch(xml->getNodeType()) {
366 case EXN_TEXT:
367 case EXN_CDATA:
368 if (i != tag_map.end()) // do we know about this tag?
369 i->second->read(xml->getNodeData());
370 break;
371 case EXN_ELEMENT_END:
372 i = tag_map.end(); // ignore the next EXN_CDATA
373 break;
374 case EXN_ELEMENT:
375 i = tag_map.find(xml->getNodeName());
376 break;
377 case EXN_NONE: case EXN_COMMENT: case EXN_UNKNOWN:
378 break;
379 }
380 }
381
382 delete xml;
383 // delete the tag objects
384 for (size_t i = 0; i < sizeof(tag_list)/sizeof(*tag_list); i++)
385 delete tag_list[i];
386
387 log_excluded_modes();
388
389 return true;
390 }
391
loadDefaults()392 void configuration::loadDefaults()
393 {
394 // RTTY
395 selShift->index(rtty_shift);
396 if (progdefaults.rtty_shift == selShift->lsize() - 1) {
397 selCustomShift->activate();
398 selCustomShift->value(rtty_custom_shift);
399 } else
400 selCustomShift->deactivate();
401 selBaud->index(rtty_baud);
402 selBits->index(rtty_bits);
403 selParity->index(rtty_parity);
404 // chkMsbFirst->value(rtty_msbfirst);
405 selStopBits->index(rtty_stop);
406 btnCRCRLF->value(rtty_crcrlf);
407 btnAUTOCRLF->value(rtty_autocrlf);
408 cntrAUTOCRLF->value(rtty_autocount);
409 chkPseudoFSK->value(PseudoFSK);
410 chkUOSrx->value(UOSrx);
411 chkUOStx->value(UOStx);
412
413 i_listbox_rtty_afc_speed->index(rtty_afcspeed);
414 btnPreferXhairScope->value(PreferXhairScope);
415
416 // OLIVIA
417 i_listbox_olivia_tones->index(oliviatones);
418 i_listbox_olivia_bandwidth->index(oliviabw);
419 cntOlivia_smargin->value(oliviasmargin);
420 cntOlivia_sinteg->value(oliviasinteg);
421 btnOlivia_8bit->value(olivia8bit);
422
423 // CONTESTIA
424 i_listbox_contestia_tones->index(contestiatones);
425 i_listbox_contestia_bandwidth->index(contestiabw);
426 cntContestia_smargin->value(contestiasmargin);
427 cntContestia_sinteg->value(contestiasinteg);
428 btnContestia_8bit->value(contestia8bit);
429
430 chkDominoEX_FEC->value(DOMINOEX_FEC);
431
432 Fl_Tooltip::enable(tooltips);
433
434 // contest settings for state qso parties
435 adjust_for_contest(0);
436
437 UI_select();
438 set_log_colors();
439 clear_log_fields();
440 clearQSO();
441 }
442
saveDefaults()443 void configuration::saveDefaults()
444 {
445 ENSURE_THREAD(FLMAIN_TID);
446
447 memcpy(&cfgpal0, &palette[0], sizeof(cfgpal0));
448 memcpy(&cfgpal1, &palette[1], sizeof(cfgpal1));
449 memcpy(&cfgpal2, &palette[2], sizeof(cfgpal2));
450 memcpy(&cfgpal3, &palette[3], sizeof(cfgpal3));
451 memcpy(&cfgpal4, &palette[4], sizeof(cfgpal4));
452 memcpy(&cfgpal5, &palette[5], sizeof(cfgpal5));
453 memcpy(&cfgpal6, &palette[6], sizeof(cfgpal6));
454 memcpy(&cfgpal7, &palette[7], sizeof(cfgpal7));
455 memcpy(&cfgpal8, &palette[8], sizeof(cfgpal8));
456
457 RxFontName = Fl::get_font_name(RxFontnbr);
458 TxFontName = Fl::get_font_name(TxFontnbr);
459
460 WaterfallFontName = Fl::get_font_name(WaterfallFontnbr);
461
462 ViewerFontName = Fl::get_font_name(ViewerFontnbr);
463
464 FreqControlFontName = Fl::get_font_name(FreqControlFontnbr);
465
466 MacroEditFontName = Fl::get_font_name(MacroEditFontnbr);
467 MacroBtnFontName = Fl::get_font_name(MacroBtnFontnbr);
468
469 DXC_textname = Fl::get_font_name(DXC_textfont);
470 DXfontname = Fl::get_font_name(DXfontnbr);
471
472 LOGGINGfontname = Fl::get_font_name(LOGGINGtextfont);
473 LOGBOOKtextname = Fl::get_font_name(LOGBOOKtextfont);
474
475
476 #if ENABLE_NLS && defined(__WOE32__)
477 set_ui_lang(listbox_language->index());
478 #endif
479
480 writeDefaultsXML();
481 changed = false;
482 }
483
484 #if USE_HAMLIB
fill_hamlib_menu(const char * rigname)485 static int fill_hamlib_menu(const char* rigname)
486 {
487 cboHamlibRig->add(rigname);
488 return 1;
489 }
490 #endif
491
setDefaults()492 int configuration::setDefaults()
493 {
494 ENSURE_THREAD(FLMAIN_TID);
495
496 #if USE_HAMLIB
497 hamlib_get_rigs();
498 hamlib_get_rig_str(fill_hamlib_menu);
499 if (HamRigModel == 0 && !HamRigName.empty()) { // compatibility with < 3.04
500 HamRigModel = hamlib_get_rig_model_compat(HamRigName.c_str());
501 LOG_VERBOSE("Found rig model %d for \"%s\"", HamRigModel, HamRigName.c_str());
502 }
503 #endif
504
505 inpMyCallsign->value(myCall.c_str());
506 inpMyName->value(myName.c_str());
507 inpMyQth->value(myQth.c_str());
508 inpMyLocator->value(myLocator.c_str());
509 inpMyAntenna->value(myAntenna.c_str());
510 UseLeadingZeros = btnUseLeadingZeros->value();
511 ContestStart = (int)nbrContestStart->value();
512 ContestDigits = (int)nbrContestDigits->value();
513
514 txtSecondary->value(secText.c_str());
515
516 txtTHORSecondary->value(THORsecText.c_str());
517 valTHOR_BW->value(THOR_BW);
518 valTHOR_FILTER->value(THOR_FILTER);
519 valTHOR_PATHS->value(THOR_PATHS);
520 valThorCWI->value(ThorCWI);
521 valTHOR_PREAMBLE->value(THOR_PREAMBLE);
522 valTHOR_SOFTSYMBOLS->value(THOR_SOFTSYMBOLS);
523 valTHOR_SOFTBITS->value(THOR_SOFTBITS);
524
525 valDominoEX_BW->value(DOMINOEX_BW);
526 valDominoEX_FILTER->value(DOMINOEX_FILTER);
527 chkDominoEX_FEC->value(DOMINOEX_FEC);
528 valDominoEX_PATHS->value(DOMINOEX_PATHS);
529 valDomCWI->value(DomCWI);
530
531 btnRigCatCMDptt->value(RigCatCMDptt);
532 btnTTYptt->value(TTYptt);
533 btnUsePPortPTT->value(progdefaults.UsePPortPTT);
534 btnUseUHrouterPTT->value(progdefaults.UseUHrouterPTT);
535
536 btn_use_cmedia_PTT->value(progdefaults.cmedia_ptt);
537
538 #if USE_HAMLIB
539 listbox_sideband->add(_("Rig mode"));
540 listbox_sideband->add(_("Always LSB"));
541 listbox_sideband->add(_("Always USB"));
542 listbox_sideband->index(HamlibSideband);
543 btnHamlibCMDptt->value(HamlibCMDptt);
544 inpRIGdev->show();
545 listbox_baudrate->show();
546 cboHamlibRig->show();
547 cboHamlibRig->value(HamRigName.c_str());
548 #else
549 tab_tree->remove(tab_tree->find_item(_("Rig Control/Hamlib")));
550 #endif
551 btnRTSptt->value(RTSptt);
552 btnDTRptt->value(DTRptt);
553 btnRTSplusV->value(RTSplus);
554 btnDTRplusV->value(DTRplus);
555
556 inpTTYdev->value(PTTdev.c_str());
557
558 chkUSEHAMLIB->value(0);
559 chkUSERIGCAT->value(0);
560 if (chkUSEHAMLIBis) chkUSEHAMLIB->value(1);
561 if (chkUSERIGCATis) chkUSERIGCAT->value(1);
562
563 if (!XmlRigFilename.empty()) readRigXML();
564
565 inpRIGdev->value(HamRigDevice.c_str());
566 listbox_baudrate->index(HamRigBaudrate);
567
568 inpXmlRigDevice->value(XmlRigDevice.c_str());
569 listbox_xml_rig_baudrate->index(XmlRigBaudrate);
570
571 select_nanoIO_CommPort->value(nanoIO_serial_port_name.c_str());
572 select_nanoCW_CommPort->value(nanoIO_serial_port_name.c_str());
573 select_CW_KEYLINE_CommPort->value(CW_KEYLINE_serial_port_name.c_str());
574
575 select_USN_FSK_port->value(Nav_FSK_port.c_str());
576 select_Nav_config_port->value(Nav_config_port.c_str());
577
578 valCWsweetspot->value(CWsweetspot);
579 valRTTYsweetspot->value(RTTYsweetspot);
580 valPSKsweetspot->value(PSKsweetspot);
581 btnWaterfallHistoryDefault->value(WaterfallHistoryDefault);
582 btnWaterfallQSY->value(WaterfallQSY);
583
584 inpWaterfallClickText->input_type(FL_MULTILINE_INPUT);
585 inpWaterfallClickText->value(WaterfallClickText.c_str());
586 if (!WaterfallClickInsert)
587 inpWaterfallClickText->deactivate();
588
589 for (size_t i = 0;
590 i < sizeof(waterfall::wf_wheel_action)/sizeof(*waterfall::wf_wheel_action); i++)
591 listboxWaterfallWheelAction->add(waterfall::wf_wheel_action[i]);
592 listboxWaterfallWheelAction->index(WaterfallWheelAction);
593
594 btnStartAtSweetSpot->value(StartAtSweetSpot);
595 btnPSKmailSweetSpot->value(PSKmailSweetSpot);
596 cntSearchRange->value(SearchRange);
597 cntServerOffset->value(ServerOffset);
598 cntACQsn->value(ACQsn);
599
600 btnCursorBWcolor->color(
601 fl_rgb_color(cursorLineRGBI.R, cursorLineRGBI.G, cursorLineRGBI.B) );
602 btnCursorCenterLineColor->color(
603 fl_rgb_color(cursorCenterRGBI.R, cursorCenterRGBI.G, cursorCenterRGBI.B) );
604 btnBwTracksColor->color(
605 fl_rgb_color(bwTrackRGBI.R, bwTrackRGBI.G, bwTrackRGBI.B) );
606
607 sldrCWxmtWPM->value(CWspeed);
608 cntCWdefWPM->value(defCWspeed);
609 sldrCWbandwidth->value(CWbandwidth);
610 btnCWrcvTrack->value(CWtrack);
611 cntCWrange->value(CWrange);
612 cntCWlowerlimit->value(CWlowerlimit);
613 cntCWupperlimit->value(CWupperlimit);
614 cntCWlowerlimit->maximum(CWupperlimit - 20);
615 cntCWupperlimit->minimum(CWlowerlimit + 20);
616 cntCWrisetime->value(CWrisetime);
617 cntCWdash2dot->value(CWdash2dot);
618 i_listboxQSKshape->index(QSKshape);
619 sldrCWxmtWPM->minimum(CWlowerlimit);
620 sldrCWxmtWPM->maximum(CWupperlimit);
621 btnQSK->value(QSK);
622 cntPreTiming->value(CWpre);
623 cntPostTiming->value(CWpost);
624 btnCWID->value(CWid);
625
626 listboxHellFont->index(feldfontnbr);
627 btnFeldHellIdle->value(HellXmtIdle);
628
629 btnTxRSID->value(TransmitRSid);
630 btnRSID->value(rsid);
631 chkRSidWideSearch->value(rsidWideSearch);
632 chkSlowCpu->value(slowcpu);
633
634 Fl_Button* qrzb = btnQRZXMLnotavailable;
635 Fl_Button* qrzb2 = btnQRZWEBnotavailable;
636 switch (QRZXML) {
637 case QRZCD:
638 qrzb = btnQRZcdrom;
639 break;
640 case QRZNET:
641 qrzb = btnQRZsub;
642 break;
643 case HAMCALLNET:
644 qrzb = btnHamcall;
645 break;
646 case CALLOOK:
647 qrzb = btnCALLOOK;
648 break;
649 case HAMQTH:
650 qrzb = btnHamQTH;
651 break;
652 case QRZXMLNONE:
653 default :
654 break;
655 }
656 switch (QRZWEB) {
657 case QRZHTML:
658 qrzb2 = btnQRZonline;
659 break;
660 case HAMCALLHTML:
661 qrzb2 = btnHAMCALLonline;
662 break;
663 case HAMQTHHTML:
664 qrzb2 = btnHamQTHonline;
665 break;
666 case QRZWEBNONE:
667 default :
668 break;
669 }
670
671 set_qrzxml_buttons(qrzb);
672 set_qrzweb_buttons(qrzb2);
673
674 txtQRZpathname->value(QRZpathname.c_str());
675
676 btnsendid->value(sendid);
677 btnsendvideotext->value(sendtextid);
678 chkID_SMALL->value(ID_SMALL);
679
680 wf->setPrefilter(wfPreFilter);
681 btnWFaveraging->value(WFaveraging);
682
683 memcpy(&palette[0], &cfgpal0, sizeof(palette[0]));
684 memcpy(&palette[1], &cfgpal1, sizeof(palette[1]));
685 memcpy(&palette[2], &cfgpal2, sizeof(palette[2]));
686 memcpy(&palette[3], &cfgpal3, sizeof(palette[3]));
687 memcpy(&palette[4], &cfgpal4, sizeof(palette[4]));
688 memcpy(&palette[5], &cfgpal5, sizeof(palette[5]));
689 memcpy(&palette[6], &cfgpal6, sizeof(palette[6]));
690 memcpy(&palette[7], &cfgpal7, sizeof(palette[7]));
691 memcpy(&palette[8], &cfgpal8, sizeof(palette[8]));
692
693 wf->setcolors();
694 setColorButtons();
695
696 #if !HAVE_UHROUTER
697 btnUseUHrouterPTT->hide();
698 #endif
699
700 #if !HAVE_PARPORT
701 btnUsePPortPTT->hide();
702 #endif
703
704 #if ENABLE_NLS && defined(__WOE32__)
705 ostringstream ss;
706 for (lang_def_t* p = ui_langs; p->lang; p++) {
707 ss.str("");
708 ss << p->native_name;
709 listbox_language->add(ss.str().c_str());
710 }
711 listbox_language->index(get_ui_lang());
712 listbox_language->show();
713 #else
714 listbox_language->hide();
715 #endif
716
717 return 1;
718 }
719
resetDefaults(void)720 void configuration::resetDefaults(void)
721 {
722 if (!fl_choice2(_("\
723 Reset all options to their default values?\n\n\
724 Reset options will take effect at the next start\n\
725 Files: fldigi_def.xml and fldigi.prefs will be deleted!\n"), _("OK"), _("Cancel"), NULL) &&
726 Fl::event_key() != FL_Escape) {
727 if (!fl_choice2(_("Confirm RESET"), _("Yes"), _("No"), NULL) &&
728 Fl::event_key() != FL_Escape) {
729 reset();
730 atexit(reset);
731 }
732 }
733 }
734
reset(void)735 void configuration::reset(void)
736 {
737 remove(string(HomeDir).append("fldigi_def.xml").c_str());
738 remove(string(HomeDir).append("fldigi.prefs").c_str());
739 }
740
741 #include "rigio.h"
742
initInterface()743 void configuration::initInterface()
744 {
745 ENSURE_THREAD(FLMAIN_TID);
746
747 // close down any possible rig interface threads
748 #if USE_HAMLIB
749 hamlib_close();
750 // MilliSleep(100);
751 #endif
752 rigCAT_close();
753 // MilliSleep(100);
754
755 RigCatCMDptt = btnRigCatCMDptt->value();
756 TTYptt = btnTTYptt->value();
757
758 RTSptt = btnRTSptt->value();
759 DTRptt = btnDTRptt->value();
760 RTSplus = btnRTSplusV->value();
761 DTRplus = btnDTRplusV->value();
762
763 PTTdev = inpTTYdev->value();
764
765 #if USE_HAMLIB
766 chkUSEHAMLIBis = chkUSEHAMLIB->value();
767 HamlibCMDptt = btnHamlibCMDptt->value();
768 #endif
769 chkUSERIGCATis = chkUSERIGCAT->value();
770
771 #if USE_HAMLIB
772 if (*cboHamlibRig->value() == '\0') // no selection at start up
773 cboHamlibRig->index(hamlib_get_index(HamRigModel));
774 else
775 HamRigModel = hamlib_get_rig_model(cboHamlibRig->index());
776 HamRigDevice = inpRIGdev->value();
777 HamRigBaudrate = listbox_baudrate->index();
778 #else
779 cboHamlibRig->hide();
780 inpRIGdev->hide();
781 listbox_baudrate->hide();
782 #endif
783
784 if (connected_to_flrig) {
785 LOG_INFO("%s", "using flrig xcvr control");
786 wf->setQSY(1);
787 } else if (chkUSERIGCATis) { // start the rigCAT thread
788 if (rigCAT_init()) {
789 LOG_INFO("%s", "using rigCAT xcvr control");
790 wf->USB(true);
791 wf->setQSY(1);
792 rigCAT_get_pwrlevel();
793 } else {
794 LOG_INFO("%s", "defaulting to no xcvr control");
795 noCAT_init();
796 wf->USB(true);
797 wf->setQSY(0);
798 chkUSERIGCATis = false;
799 }
800 #if USE_HAMLIB
801 } else if (chkUSEHAMLIBis) { // start the hamlib thread
802 if (hamlib_init(HamlibCMDptt)) {
803 LOG_INFO("%s", "using HAMLIB xcvr control");
804 btnInitHAMLIB->deactivate();
805 wf->USB(true);
806 wf->setQSY(1);
807 } else {
808 LOG_INFO("%s", "defaulting to no xcvr control");
809 noCAT_init();
810 wf->USB(true);
811 wf->setQSY(0);
812 }
813 #endif
814 } else {
815 LOG_INFO("%s", "No xcvr control selected");
816 noCAT_init();
817 wf->USB(true);
818 wf->setQSY(0);
819 }
820 build_frequencies2_list();
821
822 if (HamlibCMDptt && chkUSEHAMLIBis)
823 push2talk->reset(PTT::PTT_HAMLIB);
824 else if ((RigCatCMDptt || RigCatRTSptt || RigCatDTRptt) && chkUSERIGCATis)
825 push2talk->reset(PTT::PTT_RIGCAT);
826 else if (TTYptt)
827 push2talk->reset(PTT::PTT_TTY);
828 else if (UsePPortPTT)
829 push2talk->reset(PTT::PTT_PARPORT);
830 else if (UseUHrouterPTT)
831 push2talk->reset(PTT::PTT_UHROUTER);
832 else if (cmedia_ptt)
833 push2talk->reset(PTT::PTT_CMEDIA);
834 else if (gpio_ptt)
835 push2talk->reset(PTT::PTT_GPIO);
836 else
837 push2talk->reset(PTT::PTT_NONE);
838
839 wf->setRefLevel();
840 wf->setAmpSpan();
841 cntLowFreqCutoff->value(LowFreqCutoff);
842 }
843
strBaudRate()844 const char* configuration::strBaudRate()
845 {
846 return (szBaudRates[HamRigBaudrate + 1]);
847 }
848
nBaudRate(const char * szBR)849 int configuration::nBaudRate(const char *szBR)
850 {
851 for (size_t i = 1; i < sizeof(szBaudRates); i++)
852 if (strcmp(szBaudRates[i], szBR) == 0)
853 return i - 1;
854 return 0;
855 }
856
BaudRate(size_t n)857 int configuration::BaudRate(size_t n)
858 {
859 if (n > sizeof(szBaudRates) + 1) return 1200;
860 return (atoi(szBaudRates[n + 1]));
861 }
862
863 #ifdef __WOE32__
open_serial(const char * dev)864 static bool open_serial(const char* dev)
865 {
866 bool ret = false;
867 #ifdef __CYGWIN__
868 int fd = fl_open(dev, O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC);
869 if (fd != -1) {
870 close(fd);
871 ret = true;
872 }
873 #elif defined(__MINGW32__)
874 HANDLE fd = CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
875 if (fd != INVALID_HANDLE_VALUE) {
876 CloseHandle(fd);
877 ret = true;
878 }
879 #endif
880 return ret;
881 }
882 #endif // __WOE32__
883
testCommPorts()884 void configuration::testCommPorts()
885 {
886 inpTTYdev->clear();
887 inpRIGdev->clear();
888 inpXmlRigDevice->clear();
889 #ifndef PATH_MAX
890 # define PATH_MAX 1024
891 #endif
892 #ifndef __WOE32__
893 struct stat st;
894 #endif
895
896 #ifndef __APPLE__
897 char ttyname[PATH_MAX + 1];
898 #endif
899
900 const char* tty_fmt[] = {
901 #if defined(__linux__)
902 "/dev/ttyS%u",
903 "/dev/ttyUSB%u",
904 "/dev/usb/ttyUSB%u",
905 "/dev/ttyACM%u",
906 "/dev/usb/ttyACM%u",
907 "/dev/rfcomm%u",
908 "/opt/vttyS%u"
909 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
910 "/dev/tty%2.2u"
911 #elif defined(__CYGWIN__)
912 "/dev/ttyS%u"
913 #elif defined(__MINGW32__)
914 "//./COM%u"
915 #elif defined(__APPLE__)
916 "/dev/cu.*",
917 "/dev/tty.*"
918 #endif
919 };
920
921 #if defined(__WOE32__)
922 # define TTY_MAX 255
923 #elif defined(__OpenBSD__) || defined(__NetBSD__)
924 # define TTY_MAX 4
925 #else
926 # define TTY_MAX 8
927 #endif
928
929 #ifdef __linux__
930 glob_t gbuf;
931 glob("/dev/serial/by-id/*", 0, NULL, &gbuf);
932 for (size_t j = 0; j < gbuf.gl_pathc; j++) {
933 if ( !(stat(gbuf.gl_pathv[j], &st) == 0 && S_ISCHR(st.st_mode)) ||
934 strstr(gbuf.gl_pathv[j], "modem") )
935 continue;
936 LOG_INFO("Found serial port %s", gbuf.gl_pathv[j]);
937 inpTTYdev->add(gbuf.gl_pathv[j]);
938 # if USE_HAMLIB
939 inpRIGdev->add(gbuf.gl_pathv[j]);
940 # endif
941 inpXmlRigDevice->add(gbuf.gl_pathv[j]);
942
943 select_nanoIO_CommPort->add(gbuf.gl_pathv[j]);
944 select_nanoCW_CommPort->add(gbuf.gl_pathv[j]);
945 select_CW_KEYLINE_CommPort->add(gbuf.gl_pathv[j]);
946
947 select_USN_FSK_port->add(gbuf.gl_pathv[j]);
948 select_Nav_config_port->add(gbuf.gl_pathv[j]);
949
950 select_WK_CommPort->add(gbuf.gl_pathv[j]);
951 select_WKFSK_CommPort->add(gbuf.gl_pathv[j]);
952 }
953 globfree(&gbuf);
954 #endif
955
956 for (size_t i = 0; i < sizeof(tty_fmt)/sizeof(*tty_fmt); i++) {
957 #ifndef __APPLE__
958 for (unsigned j = 0; j < TTY_MAX; j++) {
959 snprintf(ttyname, sizeof(ttyname), tty_fmt[i], j);
960 # ifndef __WOE32__
961 if ( !(stat(ttyname, &st) == 0 && S_ISCHR(st.st_mode)) )
962 continue;
963 # else // __WOE32__
964 LOG_DEBUG("Testing serial port %s", ttyname);
965 if (!open_serial(ttyname))
966 continue;
967 # ifdef __CYGWIN__
968 snprintf(ttyname, sizeof(ttyname), "COM%u", j+1);
969 # else
970 snprintf(ttyname, sizeof(ttyname), "COM%u", j);
971 # endif
972 # endif // __WOE32__
973
974 LOG_VERBOSE("Found serial port %s", ttyname);
975 inpTTYdev->add(ttyname);
976 # if USE_HAMLIB
977 inpRIGdev->add(ttyname);
978 # endif
979 inpXmlRigDevice->add(ttyname);
980
981 select_nanoIO_CommPort->add(ttyname);
982 select_nanoCW_CommPort->add(ttyname);
983 select_CW_KEYLINE_CommPort->add(ttyname);
984
985 select_USN_FSK_port->add(ttyname);
986 select_Nav_config_port->add(ttyname);
987
988 select_WK_CommPort->add(ttyname);
989 select_WKFSK_CommPort->add(ttyname);
990 }
991 #else // __APPLE__
992 glob_t gbuf;
993 glob(tty_fmt[i], 0, NULL, &gbuf);
994 for (size_t j = 0; j < gbuf.gl_pathc; j++) {
995 int ret1 = !stat(gbuf.gl_pathv[j], &st);
996 int ret2 = S_ISCHR(st.st_mode);
997 if (ret1) {
998 LOG_INFO("Serial port %s", gbuf.gl_pathv[j]);
999 LOG_INFO(" device mode: %X", st.st_mode);
1000 LOG_INFO(" char device? %s", ret2 ? "Y" : "N");
1001 } else
1002 LOG_INFO("%s does not return stat query", gbuf.gl_pathv[j]);
1003
1004 if ( (ret1 && ret2 ) || strstr(gbuf.gl_pathv[j], "modem") )
1005 inpTTYdev->add(gbuf.gl_pathv[j]);
1006 else
1007 continue;
1008 # if USE_HAMLIB
1009 inpRIGdev->add(gbuf.gl_pathv[j]);
1010 # endif
1011 inpXmlRigDevice->add(gbuf.gl_pathv[j]);
1012
1013 select_nanoIO_CommPort->add(gbuf.gl_pathv[j]);
1014 select_nanoCW_CommPort->add(gbuf.gl_pathv[j]);
1015 select_CW_KEYLINE_CommPort->add(gbuf.gl_pathv[j]);
1016
1017 select_USN_FSK_port->add(gbuf.gl_pathv[j]);
1018 select_Nav_config_port->add(gbuf.gl_pathv[j]);
1019
1020 select_WK_CommPort->add(gbuf.gl_pathv[j]);
1021 select_WKFSK_CommPort->add(gbuf.gl_pathv[j]);
1022 }
1023 globfree(&gbuf);
1024 #endif // __APPLE__
1025 }
1026
1027 #if HAVE_UHROUTER
1028 if (stat(UHROUTER_FIFO_PREFIX "Read", &st) != -1 && S_ISFIFO(st.st_mode) &&
1029 stat(UHROUTER_FIFO_PREFIX "Write", &st) != -1 && S_ISFIFO(st.st_mode))
1030 inpTTYdev->add(UHROUTER_FIFO_PREFIX);
1031 #endif // HAVE_UHROUTER
1032 }
1033
font_number(const char * name)1034 Fl_Font font_number(const char* name)
1035 {
1036 int n = (int)Fl::set_fonts(0);
1037 for (int i = 0; i < n; i++) {
1038 if (strcmp(Fl::get_font_name((Fl_Font)i), name) == 0)
1039 return (Fl_Font)i;
1040 }
1041 return FL_HELVETICA;
1042 }
1043
initFonts(void)1044 void configuration::initFonts(void)
1045 {
1046 RxFontnbr =
1047 TxFontnbr =
1048 WaterfallFontnbr =
1049 ViewerFontnbr =
1050 FreqControlFontnbr =
1051 MacroBtnFontnbr =
1052 MacroEditFontnbr =
1053
1054 DXC_textfont =
1055 DXfontnbr =
1056
1057 LOGGINGtextfont =
1058 LOGBOOKtextfont =
1059
1060 FL_HELVETICA;
1061
1062 if (!RxFontName.empty())
1063 RxFontnbr = font_number(RxFontName.c_str());
1064 if (!TxFontName.empty())
1065 TxFontnbr = font_number(TxFontName.c_str());
1066 if (!WaterfallFontName.empty())
1067 WaterfallFontnbr = font_number(WaterfallFontName.c_str());
1068 if (!ViewerFontName.empty())
1069 ViewerFontnbr = font_number(ViewerFontName.c_str());
1070 if (!FreqControlFontName.empty())
1071 FreqControlFontnbr = font_number(FreqControlFontName.c_str());
1072
1073 if (!MacroEditFontName.empty())
1074 MacroEditFontnbr = font_number(MacroEditFontName.c_str());
1075 if (!MacroBtnFontName.empty())
1076 MacroBtnFontnbr = font_number(MacroBtnFontName.c_str());
1077
1078 if (!DXC_textname.empty())
1079 DXC_textfont = font_number(DXC_textname.c_str());
1080 if (!DXfontname.empty())
1081 DXfontnbr = font_number(DXfontname.c_str());
1082
1083 if (!LOGGINGfontname.empty())
1084 LOGGINGtextfont = font_number(LOGGINGfontname.c_str());
1085 if (!LOGBOOKtextname.empty())
1086 LOGBOOKtextfont = font_number(LOGBOOKtextname.c_str());
1087 }
1088