OpenCPN Partial API docs
connection_edit.cpp
1 /******************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose:
5  * Author: David Register
6  *
7  ***************************************************************************
8  * Copyright (C) 2022 by David S. Register *
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License *
21  * along with this program; if not, write to the *
22  * Free Software Foundation, Inc., *
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24  ***************************************************************************
25  *
26  *
27  */
28 
29 #include <set>
30 
31 #include <wx/wxprec.h>
32 
33 #ifndef WX_PRECOMP
34 #include <wx/wx.h>
35 #endif // precompiled headers
36 
37 #include "config.h"
38 
39 #include <wx/tokenzr.h>
40 #include <wx/regex.h>
41 
42 #if defined(__linux__) && !defined(__ANDROID__)
43 #include <linux/can.h>
44 #include <linux/can/raw.h>
45 #include <net/if.h>
46 #include <serial/serial.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include "dnet.h"
50 #endif
51 
52 #ifdef __ANDROID__
53 #include "androidUTIL.h"
54 #include "qdebug.h"
55 #endif
56 
57 #include "model/comm_drv_factory.h"
58 #include "model/config_vars.h"
59 #include "model/ocpn_utils.h"
60 #include "model/ser_ports.h"
61 #include "model/sys_events.h"
62 
63 #include "connection_edit.h"
64 #include "conn_params_panel.h"
65 #include "gui_lib.h"
66 #include "nmea0183.h"
67 #include "NMEALogWindow.h"
68 #include "OCPNPlatform.h"
69 #include "ocpn_plugin.h" // FIXME for GetOCPNScaledFont_PlugIn
70 #include "options.h"
71 #include "priority_gui.h"
72 #include "udev_rule_mgr.h"
73 
74 extern bool g_bfilter_cogsog;
75 extern int g_COGFilterSec;
76 extern int g_SOGFilterSec;
77 
78 extern OCPNPlatform* g_Platform;
79 
80 static wxString StringArrayToString(const wxArrayString& arr) {
81  wxString ret = wxEmptyString;
82  for (size_t i = 0; i < arr.Count(); i++) {
83  if (i > 0) ret.Append(",");
84  ret.Append(arr[i]);
85  }
86  return ret;
87 }
88 
89 // Check available SocketCAN interfaces
90 
91 #if defined(__linux__) && !defined(__ANDROID__)
92 static intf_t* intf;
93 std::vector<std::string> can_if_candidates;
94 static int print_intf(const struct intf_entry* entry, void* arg) {
95  std::string iface = entry->intf_name;
96  if (entry->intf_type == 1 && iface.find("can") != std::string::npos) {
97  can_if_candidates.push_back(entry->intf_name);
98  }
99  return 0;
100 }
101 #endif
102 
103 static wxArrayString GetAvailableSocketCANInterfaces() {
104  wxArrayString rv;
105 
106 #if defined(__linux__) && !defined(__ANDROID__)
107  struct intf_entry* entry;
108 
109  can_if_candidates.clear();
110 
111  if ((intf = intf_open()) == NULL) {
112  wxLogWarning("Error opening interface list");
113  }
114 
115  if (intf_loop(intf, print_intf, NULL) < 0) {
116  wxLogWarning("Error looping over interface list");
117  }
118  intf_close(intf);
119 
120  for (const auto& iface : can_if_candidates) {
121  int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
122  if (sock < 0) {
123  continue;
124  }
125 
126  // Get the interface index
127  struct ifreq if_request;
128  strcpy(if_request.ifr_name, iface.c_str());
129  if (ioctl(sock, SIOCGIFINDEX, &if_request) < 0) {
130  continue;
131  }
132 
133  // Check if interface is UP
134  struct sockaddr_can can_address;
135  can_address.can_family = AF_CAN;
136  can_address.can_ifindex = if_request.ifr_ifindex;
137  if (ioctl(sock, SIOCGIFFLAGS, &if_request) < 0) {
138  continue;
139  }
140  if (if_request.ifr_flags & IFF_UP) {
141  rv.Add(iface);
142  } else {
143  continue;
144  }
145  }
146 #endif
147  return rv;
148 }
149 
150 static void LoadSerialPorts(wxComboBox* box) {
152  class PortSorter {
153  private:
154  std::string GetKey(const std::string& s) const {
155  if (s.find("->") == std::string::npos) return s;
156  return ocpn::trim(ocpn::split(s, "->")[1]) + " link";
157  }
158 
159  public:
160  bool operator()(const std::string& lhs, const std::string& rhs) const {
161  return GetKey(lhs) < GetKey(rhs);
162  }
163  } port_sorter;
164 
165  std::set<std::string, PortSorter> sorted_ports(port_sorter);
166  std::unique_ptr<wxArrayString> ports(EnumerateSerialPorts());
167  for (size_t i = 0; i < ports->GetCount(); i++)
168  sorted_ports.insert((*ports)[i].ToStdString());
169 
170  box->Clear();
171  for (auto& p : sorted_ports) box->Append(p);
172 }
173 
174 //------------------------------------------------------------------------------
175 // ConnectionEditDialog Implementation
176 //------------------------------------------------------------------------------
177 
178 // BEGIN_EVENT_TABLE(ConnectionEditDialog, wxDialog)
179 // EVT_TIMER(ID_BT_SCANTIMER, ConnectionEditDialog::onBTScanTimer)
180 // END_EVENT_TABLE()
181 
182 // Define constructors
183 ConnectionEditDialog::ConnectionEditDialog() {}
184 
185 ConnectionEditDialog::ConnectionEditDialog(options* parent,
186  ConnectionsDialog* client)
187  : wxDialog(parent, wxID_ANY, _("Connection Edit"), wxDefaultPosition,
188  wxSize(280, 420)) {
189  m_parent = parent;
190 
191  Init();
192 }
193 
194 ConnectionEditDialog::~ConnectionEditDialog() {}
195 
196 void ConnectionEditDialog::SetInitialSettings(void) {
197  LoadSerialPorts(m_comboPort);
198 }
199 
200 void ConnectionEditDialog::Init() {
201  MORE = "<span foreground=\'blue\'>";
202  MORE += _("More");
203  MORE += "...</span>";
204  LESS = "<span foreground=\'blue\'>";
205  LESS += _("Less");
206  LESS += "...</span>";
207 
208  // For small displays, skip the "More" text.
209  // if (g_Platform->getDisplaySize().x < 80 * GetCharWidth()) MORE = "";
210 
211  // Setup some inital values
212  m_buttonScanBT = 0;
213  m_stBTPairs = 0;
214  m_choiceBTDataSources = 0;
215 
216  m_BTScanTimer.SetOwner(this, ID_BT_SCANTIMER);
217  m_BTscanning = 0;
218 
219  // Create the UI
220 
221  wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
222 
223  wxBoxSizer* boxSizer02 = new wxBoxSizer(wxVERTICAL);
224  mainSizer->Add(boxSizer02, 1, wxEXPAND | wxALL, 2);
225 
226  m_scrolledwin =
227  new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1),
228  wxTAB_TRAVERSAL | wxVSCROLL);
229  m_scrolledwin->SetScrollRate(0, 5);
230  boxSizer02->Add(m_scrolledwin, 1, wxALL | wxEXPAND, 3);
231 
232  auto boxSizerSWin = new wxBoxSizer(wxVERTICAL);
233  m_scrolledwin->SetSizer(boxSizerSWin);
234 
235  wxStdDialogButtonSizer* btnSizer = new wxStdDialogButtonSizer();
236  wxButton* btnOK = new wxButton(this, wxID_OK);
237  wxButton* btnCancel = new wxButton(this, wxID_CANCEL, _("Cancel"));
238  btnSizer->AddButton(btnOK);
239  btnSizer->AddButton(btnCancel);
240  btnSizer->Realize();
241  mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
242 
243  SetSizer(mainSizer);
244 
245  int group_item_spacing = 2;
246 
247  wxFont* dFont = GetOCPNScaledFont_PlugIn(_("Dialog"));
248  double font_size = dFont->GetPointSize() * 17 / 16;
249  wxFont* bFont = wxTheFontList->FindOrCreateFont(
250  font_size, dFont->GetFamily(), dFont->GetStyle(), wxFONTWEIGHT_BOLD);
251  //
252  // m_stEditCon = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Edit Selected
253  // Connection")); m_stEditCon->SetFont(*bFont); bSizer19->Add(m_stEditCon,
254  // 0, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL, 5);
255  //
256 
257  // Connections Properties
258  m_sbConnEdit =
259  new wxStaticBox(m_scrolledwin, wxID_ANY, _("Edit Selected Connection"));
260  m_sbConnEdit->SetFont(*bFont);
261 
262  sbSizerConnectionProps = new wxStaticBoxSizer(m_sbConnEdit, wxVERTICAL);
263  m_scrolledwin->GetSizer()->Add(sbSizerConnectionProps, 1, wxALL | wxEXPAND,
264  5);
265 
266  wxBoxSizer* bSizer15;
267  bSizer15 = new wxBoxSizer(wxHORIZONTAL);
268 
269  sbSizerConnectionProps->Add(bSizer15, 0, wxTOP | wxEXPAND, 5);
270  // bSizer4->Add(bSizerOuterContainer, 1, wxEXPAND, 5);
271 
272  m_rbTypeSerial =
273  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Serial"), wxDefaultPosition,
274  wxDefaultSize, wxRB_GROUP);
275  m_rbTypeSerial->SetValue(TRUE);
276  bSizer15->Add(m_rbTypeSerial, 0, wxALL, 5);
277 
278  m_rbTypeNet = new wxRadioButton(m_scrolledwin, wxID_ANY, _("Network"),
279  wxDefaultPosition, wxDefaultSize, 0);
280  bSizer15->Add(m_rbTypeNet, 0, wxALL, 5);
281 
282  m_rbTypeCAN = new wxRadioButton(m_scrolledwin, wxID_ANY, "socketCAN",
283  wxDefaultPosition, wxDefaultSize, 0);
284 #if defined(__linux__) && !defined(__ANDROID__) && !defined(__WXOSX__)
285  bSizer15->Add(m_rbTypeCAN, 0, wxALL, 5);
286 #else
287  m_rbTypeCAN->Hide();
288 #endif
289 
290  if (OCPNPlatform::hasInternalGPS()) {
291  m_rbTypeInternalGPS =
292  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Built-in GPS"),
293  wxDefaultPosition, wxDefaultSize, 0);
294  bSizer15->Add(m_rbTypeInternalGPS, 0, wxALL, 5);
295  } else
296  m_rbTypeInternalGPS = NULL;
297 
298  // has built-in Bluetooth
299  if (OCPNPlatform::hasInternalBT()) {
300  m_rbTypeInternalBT =
301  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Built-in Bluetooth SPP"),
302  wxDefaultPosition, wxDefaultSize, 0);
303  bSizer15->Add(m_rbTypeInternalBT, 0, wxALL, 5);
304 
305  m_buttonScanBT = new wxButton(m_scrolledwin, wxID_ANY, _("BT Scan"),
306  wxDefaultPosition, wxDefaultSize);
307  m_buttonScanBT->Hide();
308 
309  // wxBoxSizer* bSizer15a = new wxBoxSizer(wxHORIZONTAL);
310  // sbSizerConnectionProps->Add(bSizer15a, 0, wxEXPAND, 5);
311 
312  sbSizerConnectionProps->Add(m_buttonScanBT, 0, wxALL, 5);
313 
314  m_stBTPairs =
315  new wxStaticText(m_scrolledwin, wxID_ANY, _("Bluetooth Data Sources"),
316  wxDefaultPosition, wxDefaultSize, 0);
317  m_stBTPairs->Wrap(-1);
318  m_stBTPairs->Hide();
319  sbSizerConnectionProps->Add(m_stBTPairs, 0, wxALL, 5);
320 
321  wxArrayString mt;
322  mt.Add("unscanned");
323 
324  int ref_size = m_scrolledwin->GetCharWidth();
325  m_choiceBTDataSources =
326  new wxChoice(m_scrolledwin, wxID_ANY, wxDefaultPosition,
327  wxSize(40 * ref_size, 2 * ref_size), mt);
328  // m_choiceBTDataSources->Bind(wxEVT_MOUSEWHEEL,
329  // &ConnectionEditDialog::OnWheelChoice, this);
330  m_choiceBTDataSources->SetSelection(0);
331  m_choiceBTDataSources->Hide();
332  sbSizerConnectionProps->Add(m_choiceBTDataSources, 1, wxEXPAND | wxTOP, 5);
333 
334  } else
335  m_rbTypeInternalBT = NULL;
336 
337  gSizerNetProps = new wxFlexGridSizer(0, 4, 0, 0);
338 
339  sbSizerConnectionProps->Add(gSizerNetProps, 0, wxEXPAND, 5);
340 
341  m_stNetProto =
342  new wxStaticText(m_scrolledwin, wxID_ANY, _("Network Protocol"),
343  wxDefaultPosition, wxDefaultSize, 0);
344  m_stNetProto->Wrap(-1);
345  gSizerNetProps->Add(m_stNetProto, 0, wxALL, 5);
346 
347  wxBoxSizer* bSizer16;
348  bSizer16 = new wxBoxSizer(wxHORIZONTAL);
349 
350  m_rbNetProtoTCP =
351  new wxRadioButton(m_scrolledwin, wxID_ANY, _("TCP"), wxDefaultPosition,
352  wxDefaultSize, wxRB_GROUP);
353  m_rbNetProtoTCP->Enable(TRUE);
354  m_rbNetProtoTCP->SetValue(TRUE);
355 
356  bSizer16->Add(m_rbNetProtoTCP, 0, wxALL, 5);
357 
358  m_rbNetProtoUDP = new wxRadioButton(m_scrolledwin, wxID_ANY, _("UDP"),
359  wxDefaultPosition, wxDefaultSize, 0);
360  m_rbNetProtoUDP->Enable(TRUE);
361 
362  bSizer16->Add(m_rbNetProtoUDP, 0, wxALL, 5);
363 
364  m_rbNetProtoGPSD = new wxRadioButton(m_scrolledwin, wxID_ANY, _("GPSD"),
365  wxDefaultPosition, wxDefaultSize, 0);
366  m_rbNetProtoGPSD->Enable(TRUE);
367  bSizer16->Add(m_rbNetProtoGPSD, 0, wxALL, 5);
368 
369  m_rbNetProtoSignalK =
370  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Signal K"),
371  wxDefaultPosition, wxDefaultSize, 0);
372  m_rbNetProtoSignalK->Enable(TRUE);
373  bSizer16->Add(m_rbNetProtoSignalK, 0, wxALL, 5);
374 
375  gSizerNetProps->Add(bSizer16, 1, wxEXPAND, 5);
376  gSizerNetProps->AddSpacer(1);
377  gSizerNetProps->AddSpacer(1);
378 
379  m_stNetDataProtocol =
380  new wxStaticText(m_scrolledwin, wxID_ANY, _("Data Protocol"),
381  wxDefaultPosition, wxDefaultSize, 0);
382  m_stNetDataProtocol->Wrap(-1);
383 
384  gSizerNetProps->Add(m_stNetDataProtocol, 0, wxALL, 5);
385 
386  wxString m_choiceNetProtocolChoices[] = {_("NMEA 0183"), _("NMEA 2000")};
387  int m_choiceNetProtocolNChoices =
388  sizeof(m_choiceNetProtocolChoices) / sizeof(wxString);
389  m_choiceNetDataProtocol =
390  new wxChoice(m_scrolledwin, wxID_ANY, wxDefaultPosition, wxDefaultSize,
391  m_choiceNetProtocolNChoices, m_choiceNetProtocolChoices, 0);
392  // m_choiceNetDataProtocol->Bind(wxEVT_MOUSEWHEEL,
393  // &ConnectionEditDialog::OnWheelChoice, this);
394  m_choiceNetDataProtocol->SetSelection(0);
395  m_choiceNetDataProtocol->Enable(TRUE);
396 
397  gSizerNetProps->Add(m_choiceNetDataProtocol, 1, wxEXPAND | wxTOP, 5);
398  gSizerNetProps->AddSpacer(1);
399  gSizerNetProps->AddSpacer(1);
400 
401  m_stNetAddr = new wxStaticText(m_scrolledwin, wxID_ANY, _("Address"),
402  wxDefaultPosition, wxDefaultSize, 0);
403  m_stNetAddr->Wrap(-1);
404  int column1width = 16 * m_stNetProto->GetCharWidth();
405  m_stNetAddr->SetMinSize(wxSize(column1width, -1));
406  gSizerNetProps->Add(m_stNetAddr, 0, wxALL, 5);
407 
408  m_tNetAddress = new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString,
409  wxDefaultPosition, wxDefaultSize, 0);
410  int column2width = 40 * m_scrolledwin->GetCharWidth();
411  m_tNetAddress->SetMaxSize(wxSize(column2width, -1));
412  m_tNetAddress->SetMinSize(wxSize(column2width, -1));
413 
414  gSizerNetProps->Add(m_tNetAddress, 0, wxEXPAND | wxTOP, 5);
415  gSizerNetProps->AddSpacer(1);
416  gSizerNetProps->AddSpacer(1);
417 
418  m_stNetPort = new wxStaticText(m_scrolledwin, wxID_ANY, _("DataPort"),
419  wxDefaultPosition, wxDefaultSize, 0);
420  m_stNetPort->Wrap(-1);
421  gSizerNetProps->Add(m_stNetPort, 0, wxALL, 5);
422 
423  m_tNetPort = new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString,
424  wxDefaultPosition, wxDefaultSize, 0);
425  gSizerNetProps->Add(m_tNetPort, 1, wxEXPAND | wxTOP, 5);
426  gSizerNetProps->AddSpacer(1);
427  gSizerNetProps->AddSpacer(1);
428 
429  gSizerCanProps = new wxGridSizer(0, 1, 0, 0);
430 
431  wxFlexGridSizer* fgSizer1C;
432  fgSizer1C = new wxFlexGridSizer(0, 2, 0, 0);
433  // fgSizer1C->SetFlexibleDirection(wxBOTH);
434  // fgSizer1C->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
435 
436  m_stCANSource =
437  new wxStaticText(m_scrolledwin, wxID_ANY, _("socketCAN Source"),
438  wxDefaultPosition, wxDefaultSize, 0);
439  m_stCANSource->Wrap(-1);
440  m_stCANSource->SetMinSize(wxSize(column1width, -1));
441  fgSizer1C->Add(m_stCANSource, 0, wxALL, 5);
442 
443  wxArrayString choices = GetAvailableSocketCANInterfaces();
444  m_choiceCANSource = new wxChoice(m_scrolledwin, wxID_ANY, wxDefaultPosition,
445  wxDefaultSize, choices);
446 
447  m_choiceCANSource->SetSelection(0);
448  m_choiceCANSource->Enable(TRUE);
449  m_choiceCANSource->SetMaxSize(wxSize(column2width, -1));
450  m_choiceCANSource->SetMinSize(wxSize(column2width, -1));
451  fgSizer1C->Add(m_choiceCANSource, 1, wxEXPAND | wxTOP, 5);
452 
453  gSizerCanProps->Add(fgSizer1C, 0, wxEXPAND, 5);
454 
455  sbSizerConnectionProps->Add(gSizerCanProps, 0, wxEXPAND, 5);
456 
457  gSizerSerProps = new wxGridSizer(0, 1, 0, 0);
458  sbSizerConnectionProps->Add(gSizerSerProps, 0, wxEXPAND, 5);
459 
460  wxFlexGridSizer* fgSizer1;
461  fgSizer1 = new wxFlexGridSizer(0, 4, 0, 0);
462  fgSizer1->SetFlexibleDirection(wxBOTH);
463  fgSizer1->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
464 
465  m_stSerPort =
466  new wxStaticText(m_scrolledwin, wxID_ANY, _("Data port"),
467  wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
468  m_stSerPort->SetMinSize(wxSize(column1width, -1));
469  m_stSerPort->Wrap(-1);
470 
471  fgSizer1->Add(m_stSerPort, 0, wxALL, 5);
472 
473  m_comboPort = new wxComboBox(m_scrolledwin, wxID_ANY, wxEmptyString,
474  wxDefaultPosition, wxDefaultSize, 0, NULL, 0);
475 
476  m_comboPort->SetMaxSize(wxSize(column2width, -1));
477  m_comboPort->SetMinSize(wxSize(column2width, -1));
478 
479  fgSizer1->Add(m_comboPort, 0, wxEXPAND | wxTOP, 5);
480 
481  m_stSerBaudrate = new wxStaticText(m_scrolledwin, wxID_ANY, _("Baudrate"),
482  wxDefaultPosition, wxDefaultSize, 0);
483  m_stSerBaudrate->Wrap(-1);
484  fgSizer1->AddSpacer(1);
485  fgSizer1->AddSpacer(1);
486  fgSizer1->Add(m_stSerBaudrate, 0, wxALL, 5);
487 
488  wxString m_choiceBaudRateChoices[] = {
489  _("150"), _("300"), _("600"), _("1200"), _("2400"),
490  _("4800"), _("9600"), _("19200"), _("38400"), _("57600"),
491  _("115200"), _("230400"), _("460800"), _("921600")};
492  int m_choiceBaudRateNChoices =
493  sizeof(m_choiceBaudRateChoices) / sizeof(wxString);
494  m_choiceBaudRate =
495  new wxChoice(m_scrolledwin, wxID_ANY, wxDefaultPosition, wxDefaultSize,
496  m_choiceBaudRateNChoices, m_choiceBaudRateChoices, 0);
497  // m_choiceBaudRate->Bind(wxEVT_MOUSEWHEEL,
498  // &ConnectionEditDialog::OnWheelChoice, this);
499 
500  m_choiceBaudRate->SetSelection(0);
501 
502  fgSizer1->Add(m_choiceBaudRate, 1, wxEXPAND | wxTOP, 5);
503  fgSizer1->AddSpacer(1);
504  fgSizer1->AddSpacer(1);
505 
506  m_stSerProtocol = new wxStaticText(m_scrolledwin, wxID_ANY, _("Protocol"),
507  wxDefaultPosition, wxDefaultSize, 0);
508  m_stSerProtocol->Wrap(-1);
509  fgSizer1->Add(m_stSerProtocol, 0, wxALL, 5);
510 
511  wxString m_choiceSerialProtocolChoices[] = {_("NMEA 0183"), _("NMEA 2000")};
512  int m_choiceSerialProtocolNChoices =
513  sizeof(m_choiceSerialProtocolChoices) / sizeof(wxString);
514  m_choiceSerialProtocol = new wxChoice(
515  m_scrolledwin, wxID_ANY, wxDefaultPosition, wxDefaultSize,
516  m_choiceSerialProtocolNChoices, m_choiceSerialProtocolChoices, 0);
517  // m_choiceSerialProtocol->Bind(wxEVT_MOUSEWHEEL,
518  // &ConnectionEditDialog::OnWheelChoice, this);
519 
520  m_choiceSerialProtocol->SetSelection(0);
521  m_choiceSerialProtocol->Enable(TRUE);
522  fgSizer1->Add(m_choiceSerialProtocol, 1, wxEXPAND | wxTOP, 5);
523 
524  gSizerSerProps->Add(fgSizer1, 0, wxEXPAND, 5);
525 
526  // User Comments
527 
528  wxFlexGridSizer* commentSizer = new wxFlexGridSizer(0, 2, 0, 0);
529  // sbSizerConnectionProps->Add(commentSizer, 0, wxEXPAND, 5);
530 
531  // Net User Comments
532  m_stNetComment = new wxStaticText(m_scrolledwin, wxID_ANY, _("User Comment"),
533  wxDefaultPosition, wxDefaultSize, 0);
534  m_stNetComment->Wrap(-1);
535  m_stNetComment->SetMinSize(wxSize(column1width, -1));
536  commentSizer->Add(m_stNetComment, 0, wxALL, 5);
537 
538  m_tNetComment = new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString,
539  wxDefaultPosition, wxDefaultSize, 0);
540  m_tNetComment->SetMaxSize(wxSize(column2width, -1));
541  m_tNetComment->SetMinSize(wxSize(column2width, -1));
542 
543  commentSizer->Add(m_tNetComment, 1, wxEXPAND | wxTOP, 5);
544 
545  // Serial User Comments
546  m_stSerialComment =
547  new wxStaticText(m_scrolledwin, wxID_ANY, _("User Comment"),
548  wxDefaultPosition, wxDefaultSize, 0);
549  m_stSerialComment->Wrap(-1);
550  m_stSerialComment->SetMinSize(wxSize(column1width, -1));
551  commentSizer->Add(m_stSerialComment, 0, wxALL, 5);
552 
553  m_tSerialComment = new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString,
554  wxDefaultPosition, wxDefaultSize, 0);
555  m_tSerialComment->SetMaxSize(wxSize(column2width, -1));
556  m_tSerialComment->SetMinSize(wxSize(column2width, -1));
557 
558  commentSizer->Add(m_tSerialComment, 1, wxTOP, 5);
559 
560  m_stPriority = new wxStaticText(m_scrolledwin, wxID_ANY, _("List position"),
561  wxDefaultPosition, wxDefaultSize, 0);
562  m_stPriority->Wrap(-1);
563  commentSizer->Add(m_stPriority, 0, wxALL, 5);
564 
565  wxString m_choicePriorityChoices[] = {_("0"), _("1"), _("2"), _("3"), _("4"),
566  _("5"), _("6"), _("7"), _("8"), _("9")};
567  int m_choicePriorityNChoices =
568  sizeof(m_choicePriorityChoices) / sizeof(wxString);
569  m_choicePriority =
570  new wxChoice(m_scrolledwin, wxID_ANY, wxDefaultPosition,
571  wxSize(8 * m_parent->GetCharWidth(), -1),
572  m_choicePriorityNChoices, m_choicePriorityChoices, 0);
573  // m_choicePriority->Bind(wxEVT_MOUSEWHEEL, &ConnectionsDialog::OnWheelChoice,
574  // this);
575 
576  m_choicePriority->SetSelection(9);
577  commentSizer->Add(m_choicePriority, 0, wxEXPAND | wxTOP, 5);
578 
579  sbSizerConnectionProps->Add(commentSizer, 0, wxEXPAND, 5);
580 
581  wxFlexGridSizer* fgSizer5;
582  fgSizer5 = new wxFlexGridSizer(0, 2, 0, 0);
583  fgSizer5->SetFlexibleDirection(wxBOTH);
584  fgSizer5->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
585  sbSizerConnectionProps->Add(fgSizer5, 0, wxEXPAND, 5);
586 
587  m_cbInput =
588  new wxCheckBox(m_scrolledwin, wxID_ANY, _("Receive Input on this Port"),
589  wxDefaultPosition, wxDefaultSize, 0);
590  fgSizer5->Add(m_cbInput, 0, wxALL, 2);
591  fgSizer5->AddSpacer(1);
592 
593  m_cbOutput =
594  new wxCheckBox(m_scrolledwin, wxID_ANY,
595  wxString::Format("%s (%s)", _("Output on this port"),
596  _("as autopilot or NMEA repeater")),
597  wxDefaultPosition, wxDefaultSize, 0);
598  fgSizer5->Add(m_cbOutput, 0, wxALL, 2);
599  fgSizer5->AddSpacer(1);
600 
601  // Authentication token
602 
603  m_stAuthToken = new wxStaticText(m_scrolledwin, wxID_ANY, _("Auth Token"),
604  wxDefaultPosition, wxDefaultSize, 0);
605  m_stAuthToken->SetMinSize(wxSize(column1width, -1));
606  m_stAuthToken->Wrap(-1);
607  fgSizer5->Add(m_stAuthToken, 0, wxALL, 5);
608  m_stAuthToken->Hide();
609 
610  m_tAuthToken = new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString,
611  wxDefaultPosition, wxDefaultSize, 0);
612  m_tAuthToken->SetMinSize(wxSize(column2width, -1));
613  fgSizer5->Add(m_tAuthToken, 1, wxEXPAND | wxTOP, 5);
614 
615  m_tAuthToken->Hide();
616 
617  m_cbCheckCRC = new wxCheckBox(m_scrolledwin, wxID_ANY, _("Control checksum"),
618  wxDefaultPosition, wxDefaultSize, 0);
619  m_cbCheckCRC->SetValue(TRUE);
620  m_cbCheckCRC->SetToolTip(
621  _("If checked, only the sentences with a valid checksum are passed "
622  "through"));
623  fgSizer5->Add(m_cbCheckCRC, 0, wxALL, 2);
624  fgSizer5->AddSpacer(1);
625 
626  m_cbGarminHost = new wxCheckBox(m_scrolledwin, wxID_ANY,
627  _("Use Garmin (GRMN) mode for input"),
628  wxDefaultPosition, wxDefaultSize, 0);
629  m_cbGarminHost->SetValue(FALSE);
630  fgSizer5->Add(m_cbGarminHost, 0, wxALL, 2);
631  fgSizer5->AddSpacer(1);
632 
633 #ifndef USE_GARMINHOST
634  m_cbGarminHost->Hide();
635 #endif
636 
637  m_cbMultiCast = new wxCheckBox(m_scrolledwin, wxID_ANY, _(" UDP Multicast"),
638  wxDefaultPosition, wxDefaultSize, 0);
639  m_cbMultiCast->SetValue(FALSE);
640  // m_cbMultiCast->SetToolTip(_("Advanced Use Only. Enable UDP Multicast."));
641 
642  fgSizer5->Add(m_cbMultiCast, 0, wxALL, 2);
643  fgSizer5->AddSpacer(1);
644 
645  m_stPrecision =
646  new wxStaticText(m_scrolledwin, wxID_ANY, _("APB bearing precision"),
647  wxDefaultPosition, wxDefaultSize, 0);
648 
649  m_stPrecision->Wrap(-1);
650  fgSizer5->Add(m_stPrecision, 0, wxALL, 2);
651 
652  wxString m_choicePrecisionChoices[] = {_("x"), _("x.x"), _("x.xx"),
653  _("x.xxx"), _("x.xxxx")};
654  int m_choicePrecisionNChoices =
655  sizeof(m_choicePrecisionChoices) / sizeof(wxString);
656  m_choicePrecision =
657  new wxChoice(m_scrolledwin, wxID_ANY, wxDefaultPosition, wxDefaultSize,
658  m_choicePrecisionNChoices, m_choicePrecisionChoices, 0);
659  // m_choicePrecision->Bind(wxEVT_MOUSEWHEEL,
660  // &ConnectionEditDialog::OnWheelChoice, this);
661 
662  m_choicePrecision->SetSelection(g_NMEAAPBPrecision);
663  fgSizer5->Add(m_choicePrecision, 0, wxALL, 2);
664 
665  // signalK discovery enable
666  m_cbCheckSKDiscover =
667  new wxCheckBox(m_scrolledwin, wxID_ANY, _("Automatic server discovery"),
668  wxDefaultPosition, wxDefaultSize, 0);
669  m_cbCheckSKDiscover->SetValue(TRUE);
670  m_cbCheckSKDiscover->SetToolTip(
671  _("If checked, signal K server will be discovered automatically"));
672 
673  fgSizer5->Add(m_cbCheckSKDiscover, 0, wxALL, 2);
674 
675  // signal K "Discover now" button
676  m_ButtonSKDiscover =
677  new wxButton(m_scrolledwin, wxID_ANY, _("Discover now..."),
678  wxDefaultPosition, wxDefaultSize, 0);
679  m_ButtonSKDiscover->Hide();
680  fgSizer5->Add(m_ButtonSKDiscover, 0, wxALL, 2);
681 
682  // signalK Server Status
683  m_StaticTextSKServerStatus = new wxStaticText(
684  m_scrolledwin, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0);
685  fgSizer5->Add(m_StaticTextSKServerStatus, 0, wxALL, 2);
686 
687  sbSizerInFilter = new wxStaticBoxSizer(
688  new wxStaticBox(m_scrolledwin, wxID_ANY, _("Input filtering")),
689  wxVERTICAL);
690  sbSizerConnectionProps->Add(sbSizerInFilter,
691  wxSizerFlags().Expand().Border());
692 
693  wxBoxSizer* bSizer9;
694  bSizer9 = new wxBoxSizer(wxHORIZONTAL);
695 
696  m_rbIAccept =
697  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Accept only sentences"),
698  wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
699  bSizer9->Add(m_rbIAccept, 0, wxALL, 5);
700 
701  m_rbIIgnore =
702  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Ignore sentences"),
703  wxDefaultPosition, wxDefaultSize, 0);
704  bSizer9->Add(m_rbIIgnore, 0, wxALL, 5);
705 
706  sbSizerInFilter->Add(bSizer9, 0, wxEXPAND, 5);
707 
708  wxBoxSizer* bSizer11;
709  bSizer11 = new wxBoxSizer(wxHORIZONTAL);
710  sbSizerInFilter->Add(bSizer11, 0, wxEXPAND, 5);
711 
712  m_tcInputStc =
713  new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString, wxDefaultPosition,
714  wxDefaultSize, wxTE_READONLY);
715  bSizer11->Add(m_tcInputStc, 1, wxALL | wxEXPAND, 5);
716 
717  m_btnInputStcList =
718  new wxButton(m_scrolledwin, wxID_ANY, "...", wxDefaultPosition,
719  wxDefaultSize, wxBU_EXACTFIT);
720  bSizer11->Add(m_btnInputStcList, 0, wxALL, 5);
721 
722  bSizer11->AddSpacer(GetCharWidth() * 5);
723 
724  sbSizerOutFilter = new wxStaticBoxSizer(
725  new wxStaticBox(m_scrolledwin, wxID_ANY, _("Output filtering")),
726  wxVERTICAL);
727  sbSizerConnectionProps->Add(sbSizerOutFilter, 0, wxEXPAND, 5);
728 
729  wxBoxSizer* bSizer10;
730  bSizer10 = new wxBoxSizer(wxHORIZONTAL);
731 
732  m_rbOAccept =
733  new wxRadioButton(m_scrolledwin, wxID_ANY, _("Transmit sentences"),
734  wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
735  bSizer10->Add(m_rbOAccept, 0, wxALL, 5);
736 
737  m_rbOIgnore = new wxRadioButton(m_scrolledwin, wxID_ANY, _("Drop sentences"),
738  wxDefaultPosition, wxDefaultSize, 0);
739  bSizer10->Add(m_rbOIgnore, 0, wxALL, 5);
740 
741  sbSizerOutFilter->Add(bSizer10, 0, wxEXPAND, 5);
742 
743  wxBoxSizer* bSizer12;
744  bSizer12 = new wxBoxSizer(wxHORIZONTAL);
745  sbSizerOutFilter->Add(bSizer12, 0, wxEXPAND, 5);
746 
747  m_tcOutputStc =
748  new wxTextCtrl(m_scrolledwin, wxID_ANY, wxEmptyString, wxDefaultPosition,
749  wxDefaultSize, wxTE_READONLY);
750  bSizer12->Add(m_tcOutputStc, 1, wxALL | wxEXPAND, 5);
751 
752  m_btnOutputStcList =
753  new wxButton(m_scrolledwin, wxID_ANY, "...", wxDefaultPosition,
754  wxDefaultSize, wxBU_EXACTFIT);
755  bSizer12->Add(m_btnOutputStcList, 0, wxALL, 5);
756 
757  bSizer12->AddSpacer(GetCharWidth() * 5);
758 
759  sbSizerConnectionProps->AddSpacer(20);
760 
761  m_more = new wxStaticText(m_scrolledwin, wxID_ANY, "4 chars",
762  wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
763  m_more->SetLabelMarkup(MORE);
764  sbSizerConnectionProps->Add(m_more, wxSizerFlags().Border());
765 
766  ConnectControls();
767 
768  SetInitialSettings();
769 
770  ShowTypeCommon();
771 
772  ShowNMEACommon(true);
773  ShowNMEASerial(true);
774  ShowNMEANet(false);
775  ShowNMEACAN(false);
776  connectionsaved = TRUE;
777 
778  GetSizer()->Fit(m_scrolledwin);
779 
780  new_device_listener.Init(SystemEvents::GetInstance().evt_dev_change,
781  [&](ObservedEvt&) { LoadSerialPorts(m_comboPort); });
782 }
783 
784 // void ConnectionEditDialog::OnWheelChoice(wxMouseEvent& event) {
785 // return;
786 // }
787 
788 void ConnectionEditDialog::SetSelectedConnectionPanel(
789  ConnectionParamsPanel* panel) {
790  // Only one panel can be selected at any time
791  // Clear any selections
792 
793  if (mSelectedConnection && mSelectedConnection->m_optionsPanel)
794  mSelectedConnection->m_optionsPanel->SetSelected(false);
795 
796  if (panel) {
797  mSelectedConnection = panel->m_pConnectionParams;
798  panel->SetSelected(true);
799  SetConnectionParams(mSelectedConnection);
800  m_buttonRemove->Enable();
801  m_buttonRemove->Show();
802  m_buttonAdd->Disable();
803  m_sbConnEdit->SetLabel(_("Edit Selected Connection"));
804 
805  } else {
806  mSelectedConnection = NULL;
807  m_buttonRemove->Disable();
808  m_buttonAdd->Enable();
809  m_buttonAdd->Show();
810  m_sbConnEdit->SetLabel("");
811  ClearNMEAForm();
812  }
813 
814  // Scroll the panel to allow the user to see more of the NMEA parameter
815  // settings area
816  // wxPoint buttonPosition = m_buttonAdd->GetPosition();
817  // this->Scroll(-1, buttonPosition.y / m_parent->GetScrollRate());
818 }
819 
820 void ConnectionEditDialog::SetPropsLabel(wxString label) {
821  m_sbConnEdit->SetLabel(label);
822 }
823 
824 void ConnectionEditDialog::EnableConnection(ConnectionParams* conn,
825  bool value) {
826  if (conn) {
827  conn->bEnabled = value;
828  conn->b_IsSetup = FALSE; // trigger a rebuild/takedown of the connection
829  m_connection_enabled = conn->bEnabled;
830  }
831 }
832 
833 #if 1
834 void ConnectionEditDialog::OnValChange(wxCommandEvent& event) { event.Skip(); }
835 
836 void ConnectionEditDialog::OnScanBTClick(wxCommandEvent& event) {
837  if (m_BTscanning)
838  StopBTScan();
839  else {
840  m_btNoChangeCounter = 0;
841  m_btlastResultCount = 0;
842 
843  m_BTScanTimer.Start(1000, wxTIMER_CONTINUOUS);
844  g_Platform->startBluetoothScan();
845  m_BTscanning = 1;
846  if (m_buttonScanBT) {
847  m_buttonScanBT->SetLabel(_("Stop Scan"));
848  }
849  }
850 }
851 
852 void ConnectionEditDialog::onBTScanTimer(wxTimerEvent& event) {
853  if (m_BTscanning) {
854  m_BTscanning++;
855 
856  m_BTscan_results = g_Platform->getBluetoothScanResults();
857 
858  m_choiceBTDataSources->Clear();
859  m_choiceBTDataSources->Append(m_BTscan_results[0]); // scan status
860 
861  unsigned int i = 1;
862  while ((i + 1) < m_BTscan_results.GetCount()) {
863  wxString item1 = m_BTscan_results[i] + ";";
864  wxString item2 = m_BTscan_results.Item(i + 1);
865  m_choiceBTDataSources->Append(item1 + item2);
866 
867  i += 2;
868  }
869 
870  if (m_BTscan_results.GetCount() > 1) {
871  m_choiceBTDataSources->SetSelection(1);
872  }
873 
874  // Watch for changes. When no changes occur after n seconds, stop the scan
875  if (m_btNoChangeCounter > 5) StopBTScan();
876 
877  if ((int)m_BTscan_results.GetCount() == m_btlastResultCount)
878  m_btNoChangeCounter++;
879  else
880  m_btNoChangeCounter = 0;
881 
882  m_btlastResultCount = m_BTscan_results.GetCount();
883 
884  // Absolute fallback
885  if (m_BTscanning >= 15) {
886  StopBTScan();
887  }
888  } else {
889  }
890  return;
891 }
892 
893 void ConnectionEditDialog::StopBTScan(void) {
894  m_BTScanTimer.Stop();
895 
896  g_Platform->stopBluetoothScan();
897 
898  m_BTscanning = 0;
899 
900  if (m_buttonScanBT) {
901  m_buttonScanBT->SetLabel(_("BT Scan"));
902  m_buttonScanBT->Enable();
903  }
904 }
905 
906 void ConnectionEditDialog::OnConnValChange(wxCommandEvent& event) {
907  connectionsaved = FALSE;
908  event.Skip();
909 }
910 
911 void ConnectionEditDialog::OnTypeSerialSelected(wxCommandEvent& event) {
912  OnConnValChange(event);
913  SetNMEAFormToSerial();
914 }
915 
916 void ConnectionEditDialog::OnTypeNetSelected(wxCommandEvent& event) {
917  OnConnValChange(event);
918  SetNMEAFormToNet();
919 }
920 
921 void ConnectionEditDialog::OnTypeCANSelected(wxCommandEvent& event) {
922  OnConnValChange(event);
923  SetNMEAFormToCAN();
924 }
925 
926 void ConnectionEditDialog::OnTypeGPSSelected(wxCommandEvent& event) {
927  OnConnValChange(event);
928  SetNMEAFormToGPS();
929 }
930 
931 void ConnectionEditDialog::OnTypeBTSelected(wxCommandEvent& event) {
932  OnConnValChange(event);
933  SetNMEAFormToBT();
934 }
935 
936 void ConnectionEditDialog::OnUploadFormatChange(wxCommandEvent& event) {
937  if (event.GetEventObject() == m_cbGarminUploadHost && event.IsChecked())
938  m_cbFurunoGP3X->SetValue(FALSE);
939  else if (event.GetEventObject() == m_cbFurunoGP3X && event.IsChecked())
940  m_cbGarminUploadHost->SetValue(FALSE);
941 
942  OnConnValChange(event);
943  event.Skip();
944 }
945 #endif
946 
947 void ConnectionEditDialog::ShowTypeCommon(bool visible) {
948  m_rbTypeSerial->Show(visible);
949  m_rbTypeNet->Show(visible);
950 #if defined(__linux__) && !defined(__ANDROID__) && !defined(__WXOSX__)
951  m_rbTypeCAN->Show(visible);
952 #endif
953  if (m_rbTypeInternalGPS) m_rbTypeInternalGPS->Show(visible);
954  if (m_rbTypeInternalBT) m_rbTypeInternalBT->Show(visible);
955 }
956 
957 void ConnectionEditDialog::ShowNMEACommon(bool visible) {
958  bool advanced = m_advanced;
959  m_cbInput->Show(visible);
960  m_cbOutput->Show(visible);
961  m_stPrecision->Show(visible && advanced);
962  m_choicePrecision->Show(visible && advanced);
963  m_stPrecision->Show(visible && advanced);
964  m_cbCheckCRC->Show(visible && advanced);
965  m_stAuthToken->Show(visible && advanced);
966  m_tAuthToken->Show(visible && advanced);
967  if (visible) {
968  const bool bout_enable = (m_cbOutput->IsChecked() && advanced);
969  m_stPrecision->Enable(bout_enable);
970  m_choicePrecision->Enable(bout_enable);
971  } else {
972  sbSizerOutFilter->SetDimension(0, 0, 0, 0);
973  sbSizerInFilter->SetDimension(0, 0, 0, 0);
974  sbSizerConnectionProps->SetDimension(0, 0, 0, 0);
975  m_sbConnEdit->SetLabel("");
976  }
977 
978  m_cbCheckSKDiscover->Hide(); // Provisional
979  m_ButtonSKDiscover->Hide();
980 
981  const bool bin_enable = (m_cbInput->IsChecked() && advanced);
982  ShowInFilter(visible && bin_enable);
983  const bool bout_enable = (m_cbOutput->IsChecked() && advanced);
984  ShowOutFilter(visible && bout_enable);
985 
986  m_bNMEAParams_shown = visible;
987 }
988 
989 void ConnectionEditDialog::ShowNMEANet(bool visible) {
990  bool advanced = m_advanced;
991  m_stNetAddr->Show(visible);
992  m_tNetAddress->Show(visible);
993  m_stNetDataProtocol->Show(visible);
994  m_stNetPort->Show(visible);
995  m_choiceNetDataProtocol->Show(visible);
996  m_tNetPort->Show(visible);
997  m_stNetProto->Show(visible);
998  m_rbNetProtoSignalK->Show(visible);
999  m_rbNetProtoGPSD->Show(visible);
1000  m_rbNetProtoTCP->Show(visible);
1001  m_rbNetProtoUDP->Show(visible);
1002  m_stNetComment->Show(visible);
1003  m_tNetComment->Show(visible);
1004  m_stAuthToken->Show(visible);
1005  m_tAuthToken->Show(visible);
1006  m_cbGarminHost->Hide();
1007 }
1008 
1009 void ConnectionEditDialog::ShowNMEASerial(bool visible) {
1010  bool advanced = m_advanced;
1011  m_stSerBaudrate->Show(visible);
1012  m_choiceBaudRate->Show(visible);
1013  m_stSerPort->Show(visible);
1014  m_comboPort->Show(visible);
1015  m_stSerProtocol->Show(visible);
1016  m_choiceSerialProtocol->Show(visible);
1017  m_cbGarminHost->Show(visible && advanced);
1018  m_stSerialComment->Show(visible);
1019  m_tSerialComment->Show(visible);
1020 }
1021 
1022 void ConnectionEditDialog::ShowNMEAGPS(bool visible) {
1023  m_cbCheckSKDiscover->Hide();
1024  m_ButtonSKDiscover->Hide();
1025  m_stAuthToken->Hide();
1026  m_tAuthToken->Hide();
1027  m_cbOutput->Hide();
1028 }
1029 
1030 void ConnectionEditDialog::ShowNMEACAN(bool visible) {
1031  m_stCANSource->Show(visible);
1032  m_choiceCANSource->Show(visible);
1033 }
1034 
1035 void ConnectionEditDialog::ShowNMEABT(bool visible) {
1036  if (visible) {
1037  if (m_buttonScanBT) m_buttonScanBT->Show();
1038  if (m_stBTPairs) m_stBTPairs->Show();
1039  if (m_choiceBTDataSources) {
1040  if (m_choiceBTDataSources->GetCount() > 1)
1041  m_choiceBTDataSources->SetSelection(1);
1042  m_choiceBTDataSources->Show();
1043  }
1044  } else {
1045  if (m_buttonScanBT) m_buttonScanBT->Hide();
1046  if (m_stBTPairs) m_stBTPairs->Hide();
1047  if (m_choiceBTDataSources) m_choiceBTDataSources->Hide();
1048  }
1049  m_cbCheckSKDiscover->Hide();
1050  m_stAuthToken->Hide();
1051  m_tAuthToken->Hide();
1052  m_cbCheckSKDiscover->Hide(); // Provisional
1053  m_ButtonSKDiscover->Hide();
1054  m_tcOutputStc->Show(visible);
1055  m_btnOutputStcList->Show(visible);
1056  m_cbOutput->Show(visible);
1057 }
1058 
1059 void ConnectionEditDialog::SetNMEAFormToSerial(void) {
1060  bool advanced = m_advanced;
1061  ShowNMEACommon(TRUE);
1062  ShowNMEANet(FALSE);
1063  ShowNMEAGPS(FALSE);
1064  ShowNMEABT(FALSE);
1065  ShowNMEASerial(TRUE);
1066  ShowNMEACAN(FALSE);
1067  SetDSFormRWStates();
1068  LayoutDialog();
1069 }
1070 
1071 void ConnectionEditDialog::SetNMEAFormToNet(void) {
1072  bool advanced = m_advanced;
1073  ShowNMEACommon(TRUE);
1074  ShowNMEANet(TRUE);
1075  ShowNMEAGPS(FALSE);
1076  ShowNMEABT(FALSE);
1077  ShowNMEASerial(FALSE);
1078  ShowNMEACAN(FALSE);
1079  SetUDPNetAddressVisiblity();
1080  SetDSFormRWStates();
1081 
1082  LayoutDialog();
1083 }
1084 
1085 void ConnectionEditDialog::SetNMEAFormToCAN(void) {
1086  bool advanced = m_advanced;
1087  ShowNMEACommon(FALSE);
1088  ShowNMEANet(FALSE);
1089  ShowNMEAGPS(FALSE);
1090  ShowNMEABT(FALSE);
1091  ShowNMEASerial(FALSE);
1092  ShowNMEACAN(TRUE);
1093  sbSizerInFilter->Show(false);
1094  sbSizerOutFilter->Show(false);
1095  SetDSFormRWStates();
1096 
1097  LayoutDialog();
1098 }
1099 
1100 void ConnectionEditDialog::SetNMEAFormToGPS(void) {
1101  ShowNMEACommon(TRUE);
1102  ShowNMEANet(FALSE);
1103  ShowNMEAGPS(TRUE);
1104  ShowNMEABT(FALSE);
1105  ShowNMEASerial(FALSE);
1106  ShowNMEACAN(FALSE);
1107 
1108  // m_container->FitInside();
1109  // Fit();
1110  SetDSFormRWStates();
1111  LayoutDialog();
1112 }
1113 
1114 void ConnectionEditDialog::SetNMEAFormToBT(void) {
1115  m_rbNetProtoUDP->SetValue(true);
1116  ShowNMEACommon(TRUE);
1117  ShowNMEANet(FALSE);
1118  ShowNMEAGPS(FALSE);
1119  ShowNMEABT(TRUE);
1120  ShowNMEASerial(FALSE);
1121  ShowNMEACAN(FALSE);
1122 
1123  // m_container->FitInside();
1124  // Fit();
1125  SetDSFormRWStates();
1126  LayoutDialog();
1127 }
1128 
1129 void ConnectionEditDialog::ClearNMEAForm(void) {
1130  ShowNMEACommon(FALSE);
1131  ShowNMEANet(FALSE);
1132  ShowNMEAGPS(FALSE);
1133  ShowNMEABT(FALSE);
1134  ShowNMEASerial(FALSE);
1135  ShowNMEACAN(FALSE);
1136 
1137  // m_container->FitInside();
1138  // Fit();
1139 }
1140 
1141 void ConnectionEditDialog::SetDSFormOptionVizStates(void) {
1142  bool advanced = m_advanced;
1143  m_more->Show(true);
1144  m_cbInput->Show();
1145  m_cbOutput->Show();
1146  m_cbCheckCRC->Show(advanced);
1147  m_stPrecision->Show(true);
1148  m_choicePrecision->Show(true);
1149 
1150  ShowInFilter(advanced);
1151  ShowOutFilter(advanced);
1152  // Discovery hidden until it works.
1153  // m_cbCheckSKDiscover->Show();
1154  m_stAuthToken->Show(advanced);
1155  m_tAuthToken->Show(advanced);
1156  // m_ButtonSKDiscover->Show();
1157  m_StaticTextSKServerStatus->Show(advanced);
1158 
1159  if (m_rbTypeSerial->GetValue()) {
1160  m_cbMultiCast->Hide();
1161  m_cbCheckSKDiscover->Hide();
1162  m_stAuthToken->Hide();
1163  m_tAuthToken->Hide();
1164  m_ButtonSKDiscover->Hide();
1165  m_StaticTextSKServerStatus->Hide();
1166  bool n0183ctlenabled =
1167  (DataProtocol)m_choiceSerialProtocol->GetSelection() ==
1168  DataProtocol::PROTO_NMEA0183;
1169  if (!n0183ctlenabled) {
1170  m_cbInput->Hide();
1171  m_cbOutput->Hide();
1172  ShowOutFilter(false);
1173  ShowInFilter(false);
1174  m_stPrecision->Hide();
1175  m_choicePrecision->Hide();
1176  m_cbCheckCRC->Hide();
1177  m_stNetDataProtocol->Hide();
1178  m_choiceNetDataProtocol->Hide();
1179  } else {
1180  m_cbInput->Show();
1181  m_cbInput->Enable();
1182 
1183  ShowInFilter(m_cbInput->IsChecked() && advanced);
1184  ShowOutFilter(m_cbOutput->IsChecked() && advanced);
1185 
1186  m_stPrecision->Show(m_cbOutput->IsChecked() && advanced);
1187  m_choicePrecision->Show(m_cbOutput->IsChecked() && advanced);
1188 
1189  m_cbGarminHost->Show(m_cbInput->IsChecked() && advanced);
1190  }
1191  }
1192 
1193  if (m_rbTypeInternalGPS && m_rbTypeInternalGPS->GetValue()) {
1194  m_cbMultiCast->Hide();
1195  m_cbCheckSKDiscover->Hide();
1196  m_stAuthToken->Hide();
1197  m_tAuthToken->Hide();
1198  m_ButtonSKDiscover->Hide();
1199  m_StaticTextSKServerStatus->Hide();
1200  m_cbOutput->Hide();
1201  m_cbInput->Hide();
1202  ShowOutFilter(false);
1203  ShowInFilter(false);
1204  m_stPrecision->Hide();
1205  m_choicePrecision->Hide();
1206  m_cbCheckCRC->Hide();
1207  m_cbGarminHost->Hide();
1208  m_more->Hide();
1209  }
1210 
1211  if (m_rbTypeInternalBT && m_rbTypeInternalBT->GetValue()) {
1212  m_cbMultiCast->Hide();
1213  m_cbCheckSKDiscover->Hide();
1214  m_stAuthToken->Hide();
1215  m_tAuthToken->Hide();
1216  m_ButtonSKDiscover->Hide();
1217  m_StaticTextSKServerStatus->Hide();
1218 
1219  ShowInFilter(m_cbInput->IsChecked() && advanced);
1220  ShowOutFilter(m_cbOutput->IsChecked() && advanced);
1221 
1222  m_stPrecision->Show(m_cbOutput->IsChecked() && advanced);
1223  m_choicePrecision->Show(m_cbOutput->IsChecked() && advanced);
1224  }
1225 
1226  if (m_rbTypeCAN->GetValue()) {
1227  m_cbMultiCast->Hide();
1228  m_cbCheckSKDiscover->Hide();
1229  m_stAuthToken->Hide();
1230  m_tAuthToken->Hide();
1231  m_ButtonSKDiscover->Hide();
1232  m_StaticTextSKServerStatus->Hide();
1233  m_cbGarminHost->Hide();
1234  m_cbInput->Hide();
1235  m_cbOutput->Hide();
1236 
1237  ShowInFilter(false);
1238  ShowOutFilter(false);
1239 
1240  m_stPrecision->Hide();
1241  m_choicePrecision->Hide();
1242  m_cbCheckCRC->Hide();
1243 
1244  m_stNetDataProtocol->Hide();
1245  m_choiceNetDataProtocol->Hide();
1246  m_more->Hide();
1247  }
1248 
1249  if (m_rbTypeNet->GetValue()) {
1250  if (m_rbNetProtoGPSD->GetValue()) {
1251  m_cbMultiCast->Hide();
1252  m_cbCheckSKDiscover->Hide();
1253  m_cbInput->Hide();
1254  m_cbOutput->Hide();
1255  ShowInFilter(false);
1256  ShowOutFilter(false);
1257  m_cbCheckCRC->Hide();
1258  m_stPrecision->Hide();
1259  m_choicePrecision->Hide();
1260  m_ButtonSKDiscover->Hide();
1261  m_StaticTextSKServerStatus->Hide();
1262  m_stAuthToken->Hide();
1263  m_tAuthToken->Hide();
1264  m_stNetDataProtocol->Hide();
1265  m_choiceNetDataProtocol->Hide();
1266  m_cbGarminHost->Hide();
1267  m_more->Hide();
1268 
1269  } else if (m_rbNetProtoSignalK->GetValue()) {
1270  m_cbMultiCast->Hide();
1271  m_cbInput->Hide();
1272  m_cbOutput->Hide();
1273  ShowInFilter(false);
1274  ShowOutFilter(false);
1275  m_cbCheckCRC->Hide();
1276  m_stPrecision->Hide();
1277  m_choicePrecision->Hide();
1278  m_stNetDataProtocol->Hide();
1279  m_choiceNetDataProtocol->Hide();
1280  m_cbGarminHost->Hide();
1281 
1282  } else { // tcp or udp
1283  m_stAuthToken->Hide();
1284  m_tAuthToken->Hide();
1285  m_cbCheckSKDiscover->Hide();
1286  m_ButtonSKDiscover->Hide();
1287  m_StaticTextSKServerStatus->Hide();
1288  m_stNetDataProtocol->Show();
1289  m_choiceNetDataProtocol->Show();
1290  m_cbGarminHost->Hide();
1291 
1292  // if (m_rbNetProtoUDP->GetValue()) m_cbMultiCast->Show(advanced);
1293 
1294  if ((DataProtocol)m_choiceNetDataProtocol->GetSelection() ==
1295  DataProtocol::PROTO_NMEA2000) {
1296  m_cbCheckCRC->Hide();
1297  m_stPrecision->Hide();
1298  m_choicePrecision->Hide();
1299 
1300  ShowInFilter(false);
1301  ShowOutFilter(false);
1302  if (m_rbNetProtoTCP->GetValue()) m_more->Hide();
1303  }
1304  if ((DataProtocol)m_choiceNetDataProtocol->GetSelection() ==
1305  DataProtocol::PROTO_NMEA0183) {
1306  m_stPrecision->Show(advanced);
1307  m_choicePrecision->Show(advanced);
1308  m_stPrecision->Enable(m_cbOutput->IsChecked() && advanced);
1309  m_choicePrecision->Enable(m_cbOutput->IsChecked() && advanced);
1310 
1311  ShowInFilter(m_cbInput->IsChecked() && advanced);
1312  ShowOutFilter(m_cbOutput->IsChecked() && advanced);
1313  }
1314  }
1315  }
1316 }
1317 
1318 void ConnectionEditDialog::SetDSFormRWStates(void) {
1319  if (m_rbTypeSerial->GetValue()) {
1320  m_cbInput->Enable(FALSE);
1321  m_cbOutput->Enable(TRUE);
1322  ShowInFilter();
1323  ShowOutFilter(m_cbOutput->IsChecked());
1324  } else if (m_rbNetProtoGPSD->GetValue()) {
1325  if (m_tNetPort->GetValue() == wxEmptyString)
1326  m_tNetPort->SetValue(DEFAULT_GPSD_PORT);
1327  m_cbInput->SetValue(TRUE);
1328  m_cbInput->Enable(FALSE);
1329  // m_cbOutput->SetValue(FALSE);
1330  m_cbOutput->Enable(FALSE);
1331  m_rbOAccept->Enable(FALSE);
1332  m_rbOIgnore->Enable(FALSE);
1333  m_btnOutputStcList->Enable(FALSE);
1334  } else if (m_rbNetProtoSignalK->GetValue()) {
1335  if (m_tNetPort->GetValue() == wxEmptyString)
1336  m_tNetPort->SetValue(DEFAULT_SIGNALK_PORT);
1337  m_cbInput->SetValue(TRUE);
1338  m_cbInput->Enable(FALSE);
1339  // m_cbOutput->SetValue(FALSE);
1340  m_cbOutput->Enable(FALSE);
1341  m_rbOAccept->Enable(FALSE);
1342  m_rbOIgnore->Enable(FALSE);
1343  UpdateDiscoverStatus(wxEmptyString);
1344  } else {
1345  if (m_tNetPort->GetValue() == wxEmptyString) {
1346  if (m_rbNetProtoTCP->GetValue()) {
1347  m_tNetPort->SetValue(DEFAULT_TCP_PORT);
1348  } else {
1349  m_tNetPort->SetValue(DEFAULT_UDP_PORT);
1350  }
1351  }
1352  m_cbInput->Enable(TRUE);
1353  m_cbOutput->Enable(TRUE);
1354  m_rbOAccept->Enable(TRUE);
1355  m_rbOIgnore->Enable(TRUE);
1356  m_btnOutputStcList->Enable(TRUE);
1357  }
1358 
1359  SetDSFormOptionVizStates();
1360  // m_container->FitInside();
1361 }
1362 
1363 void ConnectionEditDialog::ShowInFilter(bool bshow) {
1364  sbSizerInFilter->GetStaticBox()->Show(bshow);
1365  m_rbIAccept->Show(bshow);
1366  m_rbIIgnore->Show(bshow);
1367  m_tcInputStc->Show(bshow);
1368  m_btnInputStcList->Show(bshow);
1369 }
1370 
1371 void ConnectionEditDialog::ShowOutFilter(bool bshow) {
1372  sbSizerOutFilter->GetStaticBox()->Show(bshow);
1373  m_rbOAccept->Show(bshow);
1374  m_rbOIgnore->Show(bshow);
1375  m_tcOutputStc->Show(bshow);
1376  m_btnOutputStcList->Show(bshow);
1377 }
1378 
1379 void ConnectionEditDialog::PreloadControls(ConnectionParams* cp) {
1380  SetConnectionParams(cp);
1381 }
1382 
1383 void ConnectionEditDialog::SetConnectionParams(ConnectionParams* cp) {
1384  if (wxNOT_FOUND == m_comboPort->FindString(cp->Port))
1385  m_comboPort->Append(cp->Port);
1386 
1387  m_comboPort->Select(m_comboPort->FindString(cp->Port));
1388 
1389  m_cbCheckCRC->SetValue(cp->ChecksumCheck);
1390  m_cbGarminHost->SetValue(cp->Garmin);
1391  m_cbInput->SetValue(cp->IOSelect != DS_TYPE_OUTPUT);
1392  m_cbOutput->SetValue(cp->IOSelect != DS_TYPE_INPUT);
1393  m_cbCheckSKDiscover->SetValue(cp->AutoSKDiscover);
1394 
1395  if (cp->InputSentenceListType == WHITELIST)
1396  m_rbIAccept->SetValue(TRUE);
1397  else
1398  m_rbIIgnore->SetValue(TRUE);
1399  if (cp->OutputSentenceListType == WHITELIST)
1400  m_rbOAccept->SetValue(TRUE);
1401  else
1402  m_rbOIgnore->SetValue(TRUE);
1403  m_tcInputStc->SetValue(StringArrayToString(cp->InputSentenceList));
1404  m_tcOutputStc->SetValue(StringArrayToString(cp->OutputSentenceList));
1405  m_choiceBaudRate->Select(
1406  m_choiceBaudRate->FindString(wxString::Format("%d", cp->Baudrate)));
1407  m_choiceSerialProtocol->Select(cp->Protocol); // TODO
1408  m_choicePriority->Select(
1409  m_choicePriority->FindString(wxString::Format("%d", cp->Priority)));
1410  m_tNetAddress->SetValue(cp->NetworkAddress);
1411 
1412  m_choiceNetDataProtocol->Select(cp->Protocol); // TODO
1413 
1414  m_cbMultiCast->SetValue(IsAddressMultiCast(m_tNetAddress->GetValue()));
1415 
1416  if (cp->NetworkPort == 0)
1417  m_tNetPort->SetValue(wxEmptyString);
1418  else
1419  m_tNetPort->SetValue(wxString::Format(wxT("%i"), cp->NetworkPort));
1420 
1421  if (cp->NetProtocol == TCP)
1422  m_rbNetProtoTCP->SetValue(TRUE);
1423  else if (cp->NetProtocol == UDP)
1424  m_rbNetProtoUDP->SetValue(TRUE);
1425  else if (cp->NetProtocol == GPSD)
1426  m_rbNetProtoGPSD->SetValue(TRUE);
1427  else if (cp->NetProtocol == SIGNALK)
1428  m_rbNetProtoSignalK->SetValue(TRUE);
1429  else
1430  m_rbNetProtoGPSD->SetValue(TRUE);
1431 
1432  if (cp->Type == SERIAL) {
1433  m_rbTypeSerial->SetValue(TRUE);
1434  SetNMEAFormToSerial();
1435  SetNMEAFormForSerialProtocol();
1436  } else if (cp->Type == NETWORK) {
1437  m_rbTypeNet->SetValue(TRUE);
1438  SetNMEAFormToNet();
1439  } else if (cp->Type == SOCKETCAN) {
1440  m_rbTypeCAN->SetValue(TRUE);
1441  SetNMEAFormToCAN();
1442 
1443  } else if (cp->Type == INTERNAL_GPS) {
1444  if (m_rbTypeInternalGPS) m_rbTypeInternalGPS->SetValue(TRUE);
1445  SetNMEAFormToGPS();
1446  } else if (cp->Type == INTERNAL_BT) {
1447  if (m_rbTypeInternalBT) m_rbTypeInternalBT->SetValue(TRUE);
1448  SetNMEAFormToBT();
1449 
1450  // Preset the source selector
1451  wxString bts = cp->NetworkAddress + ";" + cp->GetPortStr();
1452  m_choiceBTDataSources->Clear();
1453  m_choiceBTDataSources->Append(bts);
1454  m_choiceBTDataSources->SetSelection(0);
1455  } else
1456  ClearNMEAForm();
1457 
1458  if (cp->Type == SERIAL)
1459  m_tSerialComment->SetValue(cp->UserComment);
1460  else if (cp->Type == NETWORK)
1461  m_tNetComment->SetValue(cp->UserComment);
1462 
1463  m_tAuthToken->SetValue(cp->AuthToken);
1464 
1465  m_connection_enabled = cp->bEnabled;
1466 
1467  // Reset touch flag
1468  connectionsaved = true;
1469 }
1470 
1471 void ConnectionEditDialog::SetUDPNetAddressVisiblity(void) {
1472  if (m_rbNetProtoUDP->GetValue() && !m_cbMultiCast->IsChecked() &&
1473  !m_cbOutput->IsChecked()) {
1474  // m_stNetAddr->Show(FALSE);
1475  // m_tNetAddress->Show(FALSE);
1476  m_tNetAddress->Enable(TRUE);
1477  } else {
1478  m_stNetAddr->Show(TRUE);
1479  m_tNetAddress->Show(TRUE);
1480  m_tNetAddress->Enable(TRUE);
1481  }
1482  if (!m_rbNetProtoUDP->GetValue()) {
1483  m_stNetAddr->Show(TRUE);
1484  m_tNetAddress->Show(TRUE);
1485  m_tNetAddress->Enable(TRUE);
1486  }
1487  if (m_rbNetProtoUDP->GetValue() && m_advanced) {
1488  // m_cbMultiCast->Show();
1489  } else
1490  m_cbMultiCast->Hide();
1491 }
1492 
1493 void ConnectionEditDialog::SetDefaultConnectionParams(void) {
1494  if (m_comboPort && !m_comboPort->IsListEmpty()) {
1495  m_comboPort->Select(0);
1496  m_comboPort->SetValue(wxEmptyString); // These two broke it
1497  }
1498  m_cbCheckCRC->SetValue(TRUE);
1499  m_cbGarminHost->SetValue(FALSE);
1500  m_cbInput->SetValue(TRUE);
1501  m_cbOutput->SetValue(FALSE);
1502  m_rbIAccept->SetValue(TRUE);
1503  m_rbOAccept->SetValue(TRUE);
1504  m_tcInputStc->SetValue(wxEmptyString);
1505  m_tcOutputStc->SetValue(wxEmptyString);
1506  m_choiceBaudRate->Select(m_choiceBaudRate->FindString("4800"));
1507  // m_choiceSerialProtocol->Select( cp->Protocol ); // TODO
1508  m_choicePriority->Select(m_choicePriority->FindString("1"));
1509 
1510  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1511 
1512  m_tNetComment->SetValue(wxEmptyString);
1513  m_tSerialComment->SetValue(wxEmptyString);
1514  m_tAuthToken->SetValue(wxEmptyString);
1515 
1516  bool bserial = TRUE;
1517 #ifdef __WXGTK__
1518  bserial = FALSE;
1519 #endif
1520 
1521 #ifdef __WXOSX__
1522  bserial = FALSE;
1523 #endif
1524 
1525 #ifdef __ANDROID__
1526  if (m_rbTypeInternalGPS) {
1527  m_rbTypeInternalGPS->SetValue(true);
1528  SetNMEAFormToGPS();
1529  } else {
1530  m_rbTypeNet->SetValue(true);
1531  SetNMEAFormToNet();
1532  }
1533 
1534 #else
1535  m_rbTypeSerial->SetValue(bserial);
1536  m_rbTypeNet->SetValue(!bserial);
1537  bserial ? SetNMEAFormToSerial() : SetNMEAFormToNet();
1538  m_rbTypeCAN->SetValue(FALSE);
1539 #endif
1540 
1541  m_connection_enabled = TRUE;
1542 
1543  // Reset touch flag
1544  connectionsaved = false;
1545 }
1546 
1547 bool ConnectionEditDialog::SortSourceList(void) {
1548  if (TheConnectionParams()->Count() < 2) return false;
1549 
1550  std::vector<int> ivec;
1551  for (size_t i = 0; i < TheConnectionParams()->Count(); i++) ivec.push_back(i);
1552 
1553  bool did_sort = false;
1554  bool did_swap = true;
1555  while (did_swap) {
1556  did_swap = false;
1557  for (size_t j = 1; j < ivec.size(); j++) {
1558  ConnectionParams* c1 = TheConnectionParams()->Item(ivec[j]);
1559  ConnectionParams* c2 = TheConnectionParams()->Item(ivec[j - 1]);
1560 
1561  if (c1->Priority > c2->Priority) {
1562  int t = ivec[j - 1];
1563  ivec[j - 1] = ivec[j];
1564  ivec[j] = t;
1565  did_swap = true;
1566  did_sort = true;
1567  }
1568  }
1569  }
1570 
1571  // if(did_sort)
1572  {
1573  boxSizerConnections = new wxBoxSizer(wxVERTICAL);
1574  m_scrollWinConnections->SetSizer(boxSizerConnections);
1575 
1576  for (size_t i = 0; i < ivec.size(); i++) {
1577  ConnectionParamsPanel* pPanel =
1578  TheConnectionParams()->Item(ivec[i])->m_optionsPanel;
1579  boxSizerConnections->Add(pPanel, 0, wxEXPAND | wxALL, 0);
1580  }
1581  }
1582 
1583  return did_sort;
1584 }
1585 
1586 void ConnectionEditDialog::LayoutDialog() {
1587  gSizerNetProps->Layout();
1588  gSizerSerProps->Layout();
1589  m_scrolledwin->Layout();
1590  m_scrolledwin->Fit();
1591  GetSizer()->Layout();
1592 }
1593 
1594 void ConnectionEditDialog::UpdateSourceList(bool bResort) {
1595  for (size_t i = 0; i < TheConnectionParams()->Count(); i++) {
1596  ConnectionParams* cp = TheConnectionParams()->Item(i);
1597  ConnectionParamsPanel* panel = cp->m_optionsPanel;
1598  if (panel) panel->Update(TheConnectionParams()->Item(i));
1599  }
1600 
1601  if (bResort) {
1602  SortSourceList();
1603  }
1604 
1605  m_scrollWinConnections->Layout();
1606 }
1607 
1608 void ConnectionEditDialog::OnSelectDatasource(wxListEvent& event) {
1609  SetConnectionParams(TheConnectionParams()->Item(event.GetData()));
1610  m_buttonRemove->Enable();
1611  m_buttonRemove->Show();
1612  event.Skip();
1613 }
1614 
1615 void ConnectionEditDialog::OnDiscoverButton(wxCommandEvent& event) {
1616 #if 0 // FIXME (dave)
1617  wxString ip;
1618  int port;
1619  std::string serviceIdent =
1620  std::string("_signalk-ws._tcp.local."); // Works for node.js server
1621 
1622  g_Platform->ShowBusySpinner();
1623 
1624  if (SignalKDataStream::DiscoverSKServer(serviceIdent, ip, port,
1625  1)) // 1 second scan
1626  {
1627  m_tNetAddress->SetValue(ip);
1628  m_tNetPort->SetValue(wxString::Format(wxT("%i"), port));
1629  UpdateDiscoverStatus(_("Signal K server available."));
1630  } else {
1631  UpdateDiscoverStatus(_("Signal K server not found."));
1632  }
1633  g_Platform->HideBusySpinner();
1634 #endif
1635  event.Skip();
1636 }
1637 
1638 void ConnectionEditDialog::UpdateDiscoverStatus(wxString stat) {
1639  m_StaticTextSKServerStatus->SetLabel(stat);
1640 }
1641 
1642 void ConnectionEditDialog::OnBtnIStcs(wxCommandEvent& event) {
1643  const ListType type = m_rbIAccept->GetValue() ? WHITELIST : BLACKLIST;
1644  const wxArrayString list = wxStringTokenize(m_tcInputStc->GetValue(), ",");
1645  SentenceListDlg dlg(m_parent, FILTER_INPUT, type, list);
1646 
1647  if (dlg.ShowModal() == wxID_OK) m_tcInputStc->SetValue(dlg.GetSentences());
1648 }
1649 
1650 void ConnectionEditDialog::OnBtnOStcs(wxCommandEvent& event) {
1651  const ListType type = m_rbOAccept->GetValue() ? WHITELIST : BLACKLIST;
1652  const wxArrayString list = wxStringTokenize(m_tcOutputStc->GetValue(), ",");
1653  SentenceListDlg dlg(m_parent, FILTER_OUTPUT, type, list);
1654 
1655  if (dlg.ShowModal() == wxID_OK) m_tcOutputStc->SetValue(dlg.GetSentences());
1656 }
1657 
1658 void ConnectionEditDialog::OnNetProtocolSelected(wxCommandEvent& event) {
1659  if (m_rbNetProtoGPSD->GetValue()) {
1660  if (IsDefaultPort(m_tNetPort->GetValue())) {
1661  m_tNetPort->SetValue(DEFAULT_GPSD_PORT);
1662  }
1663  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1664  } else if (m_rbNetProtoUDP->GetValue()) {
1665  if (IsDefaultPort(m_tNetPort->GetValue())) {
1666  m_tNetPort->SetValue(DEFAULT_UDP_PORT);
1667  }
1668  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1669  if (m_cbInput->GetValue() && !m_cbMultiCast->GetValue() &&
1670  m_rbNetProtoUDP->GetValue())
1671  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1672  else if (m_cbOutput->GetValue() && !m_cbMultiCast->GetValue())
1673  m_tNetPort->SetValue(DEFAULT_UDP_OUT_ADDRESS);
1674 
1675  if (m_cbInput->GetValue() && m_cbOutput->GetValue())
1676  m_cbOutput->SetValue(false);
1677 
1678  } else if (m_rbNetProtoSignalK->GetValue()) {
1679  if (IsDefaultPort(m_tNetPort->GetValue())) {
1680  m_tNetPort->SetValue(DEFAULT_SIGNALK_PORT);
1681  }
1682  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1683  } else if (m_rbNetProtoTCP->GetValue()) {
1684  if (IsDefaultPort(m_tNetPort->GetValue())) {
1685  m_tNetPort->SetValue(DEFAULT_TCP_PORT);
1686  }
1687  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1688  }
1689 
1690  SetUDPNetAddressVisiblity();
1691  SetDSFormRWStates();
1692  LayoutDialog();
1693  OnConnValChange(event);
1694 }
1695 
1696 void ConnectionEditDialog::OnRbAcceptInput(wxCommandEvent& event) {
1697  OnConnValChange(event);
1698 }
1699 void ConnectionEditDialog::OnRbIgnoreInput(wxCommandEvent& event) {
1700  OnConnValChange(event);
1701 }
1702 
1703 void ConnectionEditDialog::OnRbOutput(wxCommandEvent& event) {
1704  OnConnValChange(event);
1705 }
1706 
1707 void ConnectionEditDialog::OnCbInput(wxCommandEvent& event) {
1708  const bool checked = m_cbInput->IsChecked();
1709  ShowInFilter(checked);
1710  if (checked && m_rbNetProtoUDP->GetValue() && m_rbTypeNet->GetValue()) {
1711  m_cbOutput->SetValue(FALSE);
1712 
1713  if (!m_cbMultiCast->GetValue()) m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS);
1714  }
1715  SetDSFormRWStates();
1716  LayoutDialog();
1717  if (m_rbTypeNet->GetValue()) SetUDPNetAddressVisiblity();
1718  OnConnValChange(event);
1719 }
1720 
1721 void ConnectionEditDialog::OnCbOutput(wxCommandEvent& event) {
1722  OnConnValChange(event);
1723  const bool checked = m_cbOutput->IsChecked();
1724  m_stPrecision->Enable(checked);
1725  m_choicePrecision->Enable(checked);
1726  ShowOutFilter(checked);
1727 
1728  if (!m_cbMultiCast->IsChecked() && m_rbNetProtoUDP->GetValue()) {
1729  if (checked) {
1730  m_tNetAddress->SetValue(
1731  DEFAULT_UDP_OUT_ADDRESS); // IP address for output
1732  // Check for an UDP input connection on the same port
1733  NetworkProtocol proto = UDP;
1734  for (size_t i = 0; i < TheConnectionParams()->Count(); i++) {
1735  ConnectionParams* cp = TheConnectionParams()->Item(i);
1736  if (cp->NetProtocol == proto &&
1737  cp->NetworkPort == wxAtoi(m_tNetPort->GetValue()) &&
1738  cp->IOSelect == DS_TYPE_INPUT) {
1739  // More: View the filter handler
1740  m_advanced = true;
1741  m_more->SetLabelMarkup(m_advanced ? LESS : MORE);
1742  SetNMEAFormForNetProtocol();
1743  LayoutDialog();
1744 
1745  wxString mes;
1746  bool warn = false;
1747  if (cp->bEnabled) {
1748  mes = _("There is an enabled UDP input connection that uses the "
1749  "same data port.");
1750  mes << "\n"
1751  << _("Please apply a filter on both connections to avoid a "
1752  "feedback loop.");
1753  warn = true;
1754  }
1755  else {
1756  mes = _("There is a disabled UDP Input connection that uses the "
1757  "same Dataport.");
1758  mes
1759  << "\n"
1760  << _("If you enable that input please apply a filter on both "
1761  "connections to avoid a feedback loop.");
1762  }
1763  mes << "\n"
1764  << _("Or consider using a different data port for one of them");
1765  if (warn)
1766  OCPNMessageBox(this, mes, _("OpenCPN Warning"),
1767  wxOK | wxICON_EXCLAMATION, 60);
1768  else
1769  OCPNMessageBox(this, mes, _("OpenCPN info"),
1770  wxOK | wxICON_INFORMATION, 60);
1771  break;
1772  }
1773  }
1774  } else {
1775  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS); // IP address for input
1776  }
1777  }
1778 
1779  if (checked && m_rbNetProtoUDP->GetValue()) {
1780  m_cbInput->SetValue(FALSE);
1781  }
1782 
1783  if (m_rbTypeNet->GetValue()) SetUDPNetAddressVisiblity();
1784  SetDSFormRWStates();
1785  LayoutDialog();
1786 }
1787 
1788 void ConnectionEditDialog::OnCbMultiCast(wxCommandEvent& event) {
1789  const bool checked = m_cbMultiCast->IsChecked();
1790  if (checked) {
1791  if (!IsAddressMultiCast(m_tNetAddress->GetValue())) {
1792  m_tNetAddress->SetValue("224.0.2.21");
1793  }
1794  } else if (m_cbOutput->IsChecked()) {
1795  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS); // IP address for output
1796  } else {
1797  m_tNetAddress->SetValue(DEFAULT_IP_ADDRESS); // IP address for input
1798  }
1799 
1800  SetUDPNetAddressVisiblity();
1801  LayoutDialog();
1802 }
1803 
1804 void ConnectionEditDialog::OnClickMore(wxMouseEvent& event) {
1805  // m_cbAdvanced->SetValue(!m_cbAdvanced->IsChecked());
1806  m_advanced = !m_advanced;
1807  m_more->SetLabelMarkup(m_advanced ? LESS : MORE);
1808  if (m_rbTypeNet->GetValue())
1809  SetNMEAFormForNetProtocol();
1810  else
1811  SetNMEAFormForSerialProtocol();
1812  LayoutDialog();
1813 }
1814 
1815 void ConnectionEditDialog::OnCbAdvanced(wxCommandEvent& event) {
1816  if (m_rbTypeNet->GetValue())
1817  SetNMEAFormForNetProtocol();
1818  else
1819  SetNMEAFormForSerialProtocol();
1820  LayoutDialog();
1821 }
1822 
1823 void ConnectionEditDialog::OnShowGpsWindowCheckboxClick(wxCommandEvent& event) {
1824  if (!m_cbNMEADebug->GetValue()) {
1825  NMEALogWindow::GetInstance().DestroyWindow();
1826  } else {
1827  NMEALogWindow::GetInstance().Create((wxWindow*)(m_parent->pParent), 35);
1828 
1829  // Try to ensure that the log window is a least a little bit visible
1830  wxRect logRect(NMEALogWindow::GetInstance().GetPosX(),
1831  NMEALogWindow::GetInstance().GetPosY(),
1832  NMEALogWindow::GetInstance().GetSizeW(),
1833  NMEALogWindow::GetInstance().GetSizeH());
1834 
1835 #if 0
1836  if (m_container->GetRect().Contains(logRect)) {
1837  NMEALogWindow::Get().SetPos(
1838  m_container->GetRect().x / 2,
1839  (m_container->GetRect().y +
1840  (m_container->GetRect().height - logRect.height) / 2));
1841  NMEALogWindow::Get().Move();
1842  }
1843 #endif
1844  m_parent->Raise();
1845  }
1846 }
1847 void ConnectionEditDialog::SetNMEAFormForSerialProtocol() {
1848  bool n0183ctlenabled = (DataProtocol)m_choiceSerialProtocol->GetSelection() ==
1849  DataProtocol::PROTO_NMEA0183;
1850  bool advanced = m_advanced;
1851  ShowNMEACommon(n0183ctlenabled && advanced);
1852  m_cbGarminHost->Show(n0183ctlenabled && advanced);
1853  m_stPriority->Show(true);
1854  m_choicePriority->Show(true);
1855 
1856  SetDSFormRWStates();
1857  LayoutDialog();
1858 }
1859 
1860 void ConnectionEditDialog::SetNMEAFormForNetProtocol() {
1861  bool n0183ctlenabled =
1862  (DataProtocol)m_choiceNetDataProtocol->GetSelection() ==
1863  DataProtocol::PROTO_NMEA0183;
1864  bool advanced = m_advanced;
1865  ShowNMEACommon(n0183ctlenabled && advanced);
1866  m_cbGarminHost->Show(n0183ctlenabled && advanced);
1867  m_stPriority->Show(true);
1868  m_choicePriority->Show(true);
1869 
1870  SetDSFormRWStates();
1871 
1872  LayoutDialog();
1873 }
1874 
1875 void ConnectionEditDialog::OnProtocolChoice(wxCommandEvent& event) {
1876  if (m_rbTypeNet->GetValue())
1877  SetNMEAFormForNetProtocol();
1878  else
1879  SetNMEAFormForSerialProtocol();
1880 
1881  OnConnValChange(event);
1882 }
1883 
1884 void ConnectionEditDialog::ApplySettings() {
1885 #if 0
1886  g_bfilter_cogsog = m_cbFilterSogCog->GetValue();
1887 
1888  long filter_val = 1;
1889  m_tFilterSec->GetValue().ToLong(&filter_val);
1890  g_COGFilterSec =
1891  wxMin(static_cast<int>(filter_val),
1892  60 /*MAX_COGSOG_FILTER_SECONDS*/); // FIXME (dave) should be
1893  g_COGFilterSec = wxMax(g_COGFilterSec, 1);
1894  g_SOGFilterSec = g_COGFilterSec;
1895 
1896  g_bMagneticAPB = m_cbAPBMagnetic->GetValue();
1897  g_NMEAAPBPrecision = m_choicePrecision->GetCurrentSelection();
1898 
1899  // NMEA Source
1900  // If the stream selected exists, capture some of its existing parameters
1901  // to facility identification and allow stop and restart of the stream
1902  wxString lastAddr;
1903  int lastPort = 0;
1904  NetworkProtocol lastNetProtocol = PROTO_UNDEFINED;
1905  DataProtocol lastDataProtocol = PROTO_NMEA0183;
1906 
1907  if (mSelectedConnection) {
1908  ConnectionParams* cpo = mSelectedConnection;
1909  lastAddr = cpo->NetworkAddress;
1910  lastPort = cpo->NetworkPort;
1911  lastNetProtocol = cpo->NetProtocol;
1912  lastDataProtocol = cpo->Protocol;
1913  }
1914 
1915  if (!connectionsaved) {
1916  size_t nCurrentPanelCount = TheConnectionParams()->GetCount();
1917  ConnectionParams* cp = NULL;
1918  int old_priority = -1;
1919  {
1920  if (mSelectedConnection) {
1921  cp = mSelectedConnection;
1922  old_priority = cp->Priority;
1923  UpdateConnectionParamsFromControls(cp);
1924  cp->b_IsSetup = false;
1925  // cp->bEnabled = false;
1926  // if (cp->m_optionsPanel)
1927  // cp->m_optionsPanel->SetEnableCheckbox(false);
1928 
1929  // delete TheConnectionParams()->Item(itemIndex)->m_optionsPanel;
1930  // old_priority = TheConnectionParams()->Item(itemIndex)->Priority;
1931  // TheConnectionParams()->RemoveAt(itemIndex);
1932  // TheConnectionParams()->Insert(cp, itemIndex);
1933  // mSelectedConnection = cp;
1934  // cp->m_optionsPanel->SetSelected( true );
1935  } else {
1936  cp = CreateConnectionParamsFromSelectedItem();
1937  if (cp) TheConnectionParams()->Add(cp);
1938  }
1939 
1940  // Record the previous parameters, if any
1941  if (cp) {
1942  cp->LastNetProtocol = lastNetProtocol;
1943  cp->LastNetworkAddress = lastAddr;
1944  cp->LastNetworkPort = lastPort;
1945  cp->LastDataProtocol = lastDataProtocol;
1946  }
1947 
1948  if (TheConnectionParams()->GetCount() != nCurrentPanelCount)
1949  FillSourceList();
1950  else if (old_priority >= 0) {
1951  if (old_priority != cp->Priority) // need resort
1952  UpdateSourceList(true);
1953  else
1954  UpdateSourceList(false);
1955  }
1956 
1957  connectionsaved = TRUE;
1958  }
1959  // else {
1960  // ::wxEndBusyCursor();
1961  // if (m_bNMEAParams_shown) event.SetInt(wxID_STOP);
1962  // }
1963 
1964  SetSelectedConnectionPanel(nullptr);
1965  }
1966 
1967  // Recreate datastreams that are new, or have been edited
1968  for (size_t i = 0; i < TheConnectionParams()->Count(); i++) {
1969  ConnectionParams* cp = TheConnectionParams()->Item(i);
1970 
1971  if (cp->b_IsSetup) continue;
1972 
1973  // Connection is new, or edited, or disabled
1974 
1975  // Terminate and remove any existing driver, if present in registry
1976  StopAndRemoveCommDriver(cp->GetStrippedDSPort(), cp->GetCommProtocol());
1977 
1978  // Stop and remove "previous" port, in case other params have changed.
1979  StopAndRemoveCommDriver(cp->GetLastDSPort(), cp->GetLastCommProtocol());
1980 
1981  // Internal BlueTooth driver stacks commonly need a time delay to purge
1982  // their buffers, etc. before restating with new parameters...
1983  if (cp->Type == INTERNAL_BT) wxSleep(1);
1984 
1985  // Connection has been disabled
1986  if (!cp->bEnabled) continue;
1987 
1988  // Make any new or re-enabled drivers
1989  MakeCommDriver(cp);
1990  cp->b_IsSetup = TRUE;
1991  }
1992 
1993  g_bGarminHostUpload = m_cbGarminUploadHost->GetValue();
1994  g_GPS_Ident =
1995  m_cbFurunoGP3X->GetValue() ? "FurunoGP3X" : "Generic";
1996 #endif
1997 }
1998 
2000 ConnectionEditDialog::CreateConnectionParamsFromSelectedItem() {
2001 #if 0
2002  // FIXME (dave) How could this happen?
2003  // if (!m_bNMEAParams_shown) return NULL;
2004 
2005  // Special encoding for deleted connection
2006  if (m_rbTypeSerial->GetValue() && m_comboPort->GetValue() == "Deleted")
2007  return NULL;
2008 
2009  // We check some values here for consistency.
2010  // If necessary, set defaults so user will see some result, however wrong...
2011 
2012  // DataStreams should be Input, Output, or Both
2013  if (!(m_cbInput->GetValue() || m_cbOutput->GetValue())) {
2014  m_cbInput->SetValue(true);
2015  }
2016 
2017  if (m_rbTypeSerial->GetValue() && m_comboPort->GetValue() == wxEmptyString) {
2018  m_comboPort->Select(0);
2019  }
2020  // TCP, GPSD and UDP require port field to be set.
2021  // TCP clients, GPSD and UDP output sockets require an address
2022  else if (m_rbTypeNet->GetValue()) {
2023  if (wxAtoi(m_tNetPort->GetValue()) == 0) {
2024  m_tNetPort->SetValue("10110"); // reset to default
2025  }
2026  if (m_tNetAddress->GetValue() == wxEmptyString) {
2027  m_tNetAddress->SetValue("0.0.0.0");
2028  }
2029  } else if (m_rbTypeCAN->GetValue()) {
2030  }
2031 
2032  ConnectionParams* pConnectionParams = new ConnectionParams();
2033 
2034  UpdateConnectionParamsFromSelectedItem(pConnectionParams);
2035 
2037  m_scrollWinConnections, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2038  pConnectionParams, this);
2039  pPanel->SetSelected(false);
2040  boxSizerConnections->Add(pPanel, 0, wxEXPAND | wxALL, 0);
2041  pConnectionParams->m_optionsPanel = pPanel;
2042 
2043  return pConnectionParams;
2044 #endif
2045  return NULL;
2046 }
2047 
2048 ConnectionParams* ConnectionEditDialog::GetParamsFromControls() {
2049  ConnectionParams* pConnectionParams = new ConnectionParams();
2050  UpdateConnectionParamsFromControls(pConnectionParams);
2051  return pConnectionParams;
2052 }
2053 
2054 ConnectionParams* ConnectionEditDialog::UpdateConnectionParamsFromControls(
2055  ConnectionParams* pConnectionParams) {
2056  pConnectionParams->Valid = TRUE;
2057  if (m_rbTypeSerial->GetValue())
2058  pConnectionParams->Type = SERIAL;
2059  else if (m_rbTypeNet->GetValue())
2060  pConnectionParams->Type = NETWORK;
2061  else if (m_rbTypeInternalGPS && m_rbTypeInternalGPS->GetValue())
2062  pConnectionParams->Type = INTERNAL_GPS;
2063  else if (m_rbTypeInternalBT && m_rbTypeInternalBT->GetValue())
2064  pConnectionParams->Type = INTERNAL_BT;
2065  else if (m_rbTypeCAN && m_rbTypeCAN->GetValue())
2066  pConnectionParams->Type = SOCKETCAN;
2067 
2068  if (m_rbTypeNet->GetValue()) {
2069  // Save the existing addr/port to allow closing of existing port
2070  pConnectionParams->LastNetworkAddress = pConnectionParams->NetworkAddress;
2071  pConnectionParams->LastNetworkPort = pConnectionParams->NetworkPort;
2072  pConnectionParams->LastNetProtocol = pConnectionParams->NetProtocol;
2073  pConnectionParams->LastDataProtocol = pConnectionParams->Protocol;
2074 
2075  pConnectionParams->NetworkAddress =
2076  m_tNetAddress->GetValue().Trim(false).Trim(true);
2077  pConnectionParams->NetworkPort =
2078  wxAtoi(m_tNetPort->GetValue().Trim(false).Trim(true));
2079  if (m_rbNetProtoTCP->GetValue()) {
2080  pConnectionParams->NetProtocol = TCP;
2081  pConnectionParams->Protocol =
2082  (DataProtocol)m_choiceNetDataProtocol->GetSelection();
2083  } else if (m_rbNetProtoUDP->GetValue()) {
2084  pConnectionParams->NetProtocol = UDP;
2085  pConnectionParams->Protocol =
2086  (DataProtocol)m_choiceNetDataProtocol->GetSelection();
2087  } else if (m_rbNetProtoGPSD->GetValue())
2088  pConnectionParams->NetProtocol = GPSD;
2089  else if (m_rbNetProtoSignalK->GetValue())
2090  pConnectionParams->NetProtocol = SIGNALK;
2091  else
2092  pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2093  }
2094 
2095  if (m_rbTypeSerial->GetValue())
2096  pConnectionParams->Protocol =
2097  (DataProtocol)m_choiceSerialProtocol->GetSelection();
2098  else if (m_rbTypeNet->GetValue())
2099  pConnectionParams->Protocol =
2100  (DataProtocol)m_choiceNetDataProtocol->GetSelection();
2101 
2102  pConnectionParams->Baudrate = wxAtoi(m_choiceBaudRate->GetStringSelection());
2103  pConnectionParams->Priority = wxAtoi(m_choicePriority->GetStringSelection());
2104  pConnectionParams->ChecksumCheck = m_cbCheckCRC->GetValue();
2105  pConnectionParams->AutoSKDiscover = m_cbCheckSKDiscover->GetValue();
2106  pConnectionParams->Garmin = m_cbGarminHost->GetValue();
2107  pConnectionParams->InputSentenceList =
2108  wxStringTokenize(m_tcInputStc->GetValue(), ",");
2109  if (m_rbIAccept->GetValue())
2110  pConnectionParams->InputSentenceListType = WHITELIST;
2111  else
2112  pConnectionParams->InputSentenceListType = BLACKLIST;
2113  if (m_cbInput->GetValue()) {
2114  if (m_cbOutput->GetValue()) {
2115  pConnectionParams->IOSelect = DS_TYPE_INPUT_OUTPUT;
2116  } else {
2117  pConnectionParams->IOSelect = DS_TYPE_INPUT;
2118  }
2119  } else
2120  pConnectionParams->IOSelect = DS_TYPE_OUTPUT;
2121 
2122  pConnectionParams->OutputSentenceList =
2123  wxStringTokenize(m_tcOutputStc->GetValue(), ",");
2124  if (m_rbOAccept->GetValue())
2125  pConnectionParams->OutputSentenceListType = WHITELIST;
2126  else
2127  pConnectionParams->OutputSentenceListType = BLACKLIST;
2128  pConnectionParams->Port = m_comboPort->GetValue().BeforeFirst(' ');
2129 #if defined(__linux__) && !defined(__ANDROID__)
2130  if (pConnectionParams->Type == SERIAL)
2131  CheckSerialAccess(m_parent, pConnectionParams->Port.ToStdString());
2132 #endif
2133 
2134  if (m_rbTypeCAN && m_rbTypeCAN->GetValue())
2135  pConnectionParams->Protocol = PROTO_NMEA2000;
2136 
2137  pConnectionParams->bEnabled = m_connection_enabled;
2138  pConnectionParams->b_IsSetup = FALSE;
2139 
2140  if (pConnectionParams->Type == INTERNAL_GPS) {
2141  pConnectionParams->NetworkAddress = "";
2142  pConnectionParams->NetworkPort = 0;
2143  pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2144  pConnectionParams->Baudrate = 0;
2145  }
2146 
2147  if (pConnectionParams->Type == INTERNAL_BT) {
2148  wxString parms = m_choiceBTDataSources->GetStringSelection();
2149  wxStringTokenizer tkz(parms, ";");
2150  wxString name = tkz.GetNextToken();
2151  wxString mac = tkz.GetNextToken();
2152 
2153  pConnectionParams->NetworkAddress = name;
2154  pConnectionParams->Port = mac;
2155  pConnectionParams->NetworkPort = 0;
2156  pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2157  pConnectionParams->Baudrate = 0;
2158  // pConnectionParams->SetAuxParameterStr(m_choiceBTDataSources->GetStringSelection());
2159  }
2160 
2161  if (pConnectionParams->Type == SOCKETCAN) {
2162  pConnectionParams->NetworkAddress = "";
2163  pConnectionParams->NetworkPort = 0;
2164  pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2165  pConnectionParams->Baudrate = 0;
2166  pConnectionParams->socketCAN_port =
2167  m_choiceCANSource->GetString(m_choiceCANSource->GetSelection());
2168  }
2169 
2170  if (pConnectionParams->Type == SERIAL) {
2171  pConnectionParams->UserComment = m_tSerialComment->GetValue();
2172  } else if (pConnectionParams->Type == NETWORK) {
2173  pConnectionParams->UserComment = m_tNetComment->GetValue();
2174  }
2175  pConnectionParams->AuthToken = m_tAuthToken->GetValue();
2176 
2177  return pConnectionParams;
2178 }
2179 
2180 void ConnectionEditDialog::OnPriorityDialog(wxCommandEvent& event) {
2181  PriorityDlg* pdlg = new PriorityDlg(m_parent);
2182  pdlg->ShowModal();
2183  delete pdlg;
2184 }
2185 void ConnectionEditDialog::ConnectControls() {
2186  // Connect controls
2187  m_rbTypeSerial->Connect(
2188  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2189  wxCommandEventHandler(ConnectionEditDialog::OnTypeSerialSelected), NULL,
2190  this);
2191  m_rbTypeNet->Connect(
2192  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2193  wxCommandEventHandler(ConnectionEditDialog::OnTypeNetSelected), NULL,
2194  this);
2195 
2196  m_rbTypeCAN->Connect(
2197  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2198  wxCommandEventHandler(ConnectionEditDialog::OnTypeCANSelected), NULL,
2199  this);
2200 
2201  if (m_rbTypeInternalGPS)
2202  m_rbTypeInternalGPS->Connect(
2203  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2204  wxCommandEventHandler(ConnectionEditDialog::OnTypeGPSSelected), NULL,
2205  this);
2206  if (m_rbTypeInternalBT)
2207  m_rbTypeInternalBT->Connect(
2208  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2209  wxCommandEventHandler(ConnectionEditDialog::OnTypeBTSelected), NULL,
2210  this);
2211 
2212  // Network connection
2213  m_rbNetProtoTCP->Connect(
2214  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2215  wxCommandEventHandler(ConnectionEditDialog::OnNetProtocolSelected), NULL,
2216  this);
2217  m_rbNetProtoUDP->Connect(
2218  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2219  wxCommandEventHandler(ConnectionEditDialog::OnNetProtocolSelected), NULL,
2220  this);
2221  m_rbNetProtoGPSD->Connect(
2222  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2223  wxCommandEventHandler(ConnectionEditDialog::OnNetProtocolSelected), NULL,
2224  this);
2225  m_rbNetProtoSignalK->Connect(
2226  wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2227  wxCommandEventHandler(ConnectionEditDialog::OnNetProtocolSelected), NULL,
2228  this);
2229  m_choiceNetDataProtocol->Connect(
2230  wxEVT_COMMAND_CHOICE_SELECTED,
2231  wxCommandEventHandler(ConnectionEditDialog::OnProtocolChoice), NULL,
2232  this);
2233  m_choiceSerialProtocol->Connect(
2234  wxEVT_COMMAND_CHOICE_SELECTED,
2235  wxCommandEventHandler(ConnectionEditDialog::OnProtocolChoice), NULL,
2236  this);
2237  m_cbMultiCast->Connect(
2238  wxEVT_COMMAND_CHECKBOX_CLICKED,
2239  wxCommandEventHandler(ConnectionEditDialog::OnCbMultiCast), NULL, this);
2240  // m_cbAdvanced->Connect(
2241  // wxEVT_COMMAND_CHECKBOX_CLICKED,
2242  // wxCommandEventHandler(ConnectionEditDialog::OnCbAdvanced), NULL, this);
2243  m_more->Bind(wxEVT_LEFT_DOWN, &ConnectionEditDialog::OnClickMore, this);
2244 
2245  // input/output control
2246  m_cbInput->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2247  wxCommandEventHandler(ConnectionEditDialog::OnCbInput),
2248  NULL, this);
2249  m_cbOutput->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2250  wxCommandEventHandler(ConnectionEditDialog::OnCbOutput),
2251  NULL, this);
2252 
2253  // Input filtering
2254  // m_rbIAccept->Connect(
2255  // wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2256  // wxCommandEventHandler(ConnectionEditDialog::OnRbAcceptInput), NULL,
2257  // this);
2258  // m_rbIIgnore->Connect(
2259  // wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2260  // wxCommandEventHandler(ConnectionEditDialog::OnRbIgnoreInput), NULL,
2261  // this);
2262  // m_tcInputStc->Connect(
2263  // wxEVT_COMMAND_TEXT_UPDATED,
2264  // wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL,
2265  // this);
2266  m_btnInputStcList->Connect(
2267  wxEVT_COMMAND_BUTTON_CLICKED,
2268  wxCommandEventHandler(ConnectionEditDialog::OnBtnIStcs), NULL, this);
2269 
2270  // output filtering
2271  m_btnOutputStcList->Connect(
2272  wxEVT_COMMAND_BUTTON_CLICKED,
2273  wxCommandEventHandler(ConnectionEditDialog::OnBtnOStcs), NULL, this);
2274 
2275 #if 0
2276  m_tNetAddress->Connect(
2277  wxEVT_COMMAND_TEXT_UPDATED,
2278  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2279  m_tNetPort->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2280  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange),
2281  NULL, this);
2282  m_comboPort->Connect(
2283  wxEVT_COMMAND_COMBOBOX_SELECTED,
2284  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2285  m_comboPort->Connect(
2286  wxEVT_COMMAND_TEXT_UPDATED,
2287  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2288  m_choiceBaudRate->Connect(
2289  wxEVT_COMMAND_CHOICE_SELECTED,
2290  wxCommandEventHandler(ConnectionEditDialog::OnBaudrateChoice), NULL, this);
2291  m_choicePriority->Connect(
2292  wxEVT_COMMAND_CHOICE_SELECTED,
2293  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2294  m_choiceCANSource->Connect(
2295  wxEVT_COMMAND_CHOICE_SELECTED,
2296  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2297  m_cbCheckCRC->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2298  wxCommandEventHandler(ConnectionEditDialog::OnCrcCheck),
2299  NULL, this);
2300  m_cbGarminHost->Connect(
2301  wxEVT_COMMAND_CHECKBOX_CLICKED,
2302  wxCommandEventHandler(ConnectionEditDialog::OnUploadFormatChange), NULL,
2303  this);
2304  m_cbGarminUploadHost->Connect(
2305  wxEVT_COMMAND_CHECKBOX_CLICKED,
2306  wxCommandEventHandler(ConnectionEditDialog::OnUploadFormatChange), NULL,
2307  this);
2308  m_cbFurunoGP3X->Connect(
2309  wxEVT_COMMAND_CHECKBOX_CLICKED,
2310  wxCommandEventHandler(ConnectionEditDialog::OnUploadFormatChange), NULL,
2311  this);
2312  m_cbCheckSKDiscover->Connect(
2313  wxEVT_COMMAND_CHECKBOX_CLICKED,
2314  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2315  m_ButtonSKDiscover->Connect(
2316  wxEVT_COMMAND_BUTTON_CLICKED,
2317  wxCommandEventHandler(ConnectionEditDialog::OnDiscoverButton), NULL, this);
2318 
2319  m_rbOAccept->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2320  wxCommandEventHandler(ConnectionEditDialog::OnRbOutput),
2321  NULL, this);
2322  m_rbOIgnore->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2323  wxCommandEventHandler(ConnectionEditDialog::OnRbOutput),
2324  NULL, this);
2325  m_tcOutputStc->Connect(
2326  wxEVT_COMMAND_TEXT_UPDATED,
2327  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2328  m_cbCheckCRC->Connect(
2329  wxEVT_COMMAND_CHECKBOX_CLICKED,
2330  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2331 
2332  m_cbNMEADebug->Connect(
2333  wxEVT_COMMAND_CHECKBOX_CLICKED,
2334  wxCommandEventHandler(ConnectionEditDialog::OnShowGpsWindowCheckboxClick),
2335  NULL, this);
2336  m_cbFilterSogCog->Connect(
2337  wxEVT_COMMAND_CHECKBOX_CLICKED,
2338  wxCommandEventHandler(ConnectionEditDialog::OnValChange), NULL, this);
2339  m_tFilterSec->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2340  wxCommandEventHandler(ConnectionEditDialog::OnValChange),
2341  NULL, this);
2342  m_cbAPBMagnetic->Connect(
2343  wxEVT_COMMAND_CHECKBOX_CLICKED,
2344  wxCommandEventHandler(ConnectionEditDialog::OnValChange), NULL, this);
2345 
2346  m_ButtonPriorityDialog->Connect(
2347  wxEVT_COMMAND_BUTTON_CLICKED,
2348  wxCommandEventHandler(ConnectionEditDialog::OnPriorityDialog), NULL, this);
2349 
2350  m_tNetComment->Connect(
2351  wxEVT_COMMAND_TEXT_UPDATED,
2352  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2353  m_tSerialComment->Connect(
2354  wxEVT_COMMAND_TEXT_UPDATED,
2355  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2356  m_tAuthToken->Connect(
2357  wxEVT_COMMAND_TEXT_UPDATED,
2358  wxCommandEventHandler(ConnectionEditDialog::OnConnValChange), NULL, this);
2359 
2360  if (m_buttonScanBT)
2361  m_buttonScanBT->Connect(
2362  wxEVT_COMMAND_BUTTON_CLICKED,
2363  wxCommandEventHandler(ConnectionEditDialog::OnScanBTClick), NULL, this);
2364 #endif
2365 }
2366 
2367 bool ConnectionEditDialog::IsAddressMultiCast(wxString ip) {
2368  wxArrayString bytes = wxSplit(ip, '.');
2369  if (bytes.size() != 4) {
2370  return false;
2371  }
2372  unsigned long ipNum = (wxAtoi(bytes[0]) << 24) + (wxAtoi(bytes[1]) << 16) +
2373  (wxAtoi(bytes[2]) << 8) + wxAtoi(bytes[3]);
2374  unsigned long multicastStart = (224 << 24);
2375  unsigned long multicastEnd = (239 << 24) + (255 << 16) + (255 << 8) + 255;
2376  return ipNum >= multicastStart && ipNum <= multicastEnd;
2377 }
2378 
2379 bool ConnectionEditDialog::IsDefaultPort(wxString address) {
2380  return (address == DEFAULT_TCP_PORT) || (address == DEFAULT_UDP_PORT) ||
2381  (address == DEFAULT_SIGNALK_PORT) || (address == DEFAULT_GPSD_PORT);
2382 }
2383 
2384 bool ConnectionEditDialog::IsAddressBroadcast(wxString ip) {
2385  wxArrayString bytes = wxSplit(ip, '.');
2386  if (bytes.size() != 4) {
2387  std::cerr << "Invalid IP format." << std::endl;
2388  return false;
2389  }
2390  return wxAtoi(bytes[3]) == 255;
2391 }
2392 
2393 SentenceListDlg::SentenceListDlg(wxWindow* parent, FilterDirection dir,
2394  ListType type, const wxArrayString& list)
2395  : wxDialog(parent, wxID_ANY, _("Sentence Filter"), wxDefaultPosition,
2396  wxSize(280, 420)),
2397  m_type(type),
2398  m_dir(dir),
2399  m_sentences(NMEA0183().GetRecognizedArray()) {
2400  m_sentences.Sort();
2401  wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
2402  wxBoxSizer* secondSizer = new wxBoxSizer(wxHORIZONTAL);
2403  wxStaticBox* pclbBox = new wxStaticBox(this, wxID_ANY, GetBoxLabel());
2404  wxStaticBoxSizer* stcSizer = new wxStaticBoxSizer(pclbBox, wxVERTICAL);
2405  m_clbSentences = new wxCheckListBox(this, wxID_ANY, wxDefaultPosition,
2406  wxDefaultSize, m_sentences);
2407  wxBoxSizer* btnEntrySizer = new wxBoxSizer(wxVERTICAL);
2408  wxButton* btnCheckAll = new wxButton(this, wxID_ANY, _("Select All"));
2409  wxButton* btnClearAll = new wxButton(this, wxID_ANY, _("Clear All"));
2410  wxButton* btnAdd = new wxButton(this, wxID_ANY, _("Add"));
2411  m_btnDel = new wxButton(this, wxID_ANY, _("Delete"));
2412  m_btnDel->Disable();
2413  wxStdDialogButtonSizer* btnSizer = new wxStdDialogButtonSizer();
2414  wxButton* btnOK = new wxButton(this, wxID_OK);
2415  wxButton* btnCancel = new wxButton(this, wxID_CANCEL, _("Cancel"));
2416 
2417  secondSizer->Add(stcSizer, 1, wxALL | wxEXPAND, 5);
2418  stcSizer->Add(m_clbSentences, 1, wxALL | wxEXPAND, 5);
2419  btnEntrySizer->Add(btnCheckAll, 0, wxALL, 5);
2420  btnEntrySizer->Add(btnClearAll, 0, wxALL, 5);
2421  btnEntrySizer->AddSpacer(1);
2422  btnEntrySizer->Add(btnAdd, 0, wxALL, 5);
2423  btnEntrySizer->Add(m_btnDel, 0, wxALL, 5);
2424  secondSizer->Add(btnEntrySizer, 0, wxALL | wxEXPAND, 5);
2425  mainSizer->Add(secondSizer, 1, wxEXPAND, 5);
2426  btnSizer->AddButton(btnOK);
2427  btnSizer->AddButton(btnCancel);
2428  btnSizer->Realize();
2429  mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
2430 
2431  SetSizer(mainSizer);
2432  mainSizer->SetSizeHints(this);
2433  Centre();
2434 
2435  // Connect Events
2436  btnAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2437  wxCommandEventHandler(SentenceListDlg::OnAddClick), NULL,
2438  this);
2439  m_btnDel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2440  wxCommandEventHandler(SentenceListDlg::OnDeleteClick), NULL,
2441  this);
2442  m_clbSentences->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
2443  wxCommandEventHandler(SentenceListDlg::OnCLBSelect),
2444  NULL, this);
2445  btnCheckAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2446  wxCommandEventHandler(SentenceListDlg::OnCheckAllClick),
2447  NULL, this);
2448  btnClearAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2449  wxCommandEventHandler(SentenceListDlg::OnClearAllClick),
2450  NULL, this);
2451 
2452  Populate(list);
2453 }
2454 
2455 wxString SentenceListDlg::GetBoxLabel(void) const {
2456  if (m_dir == FILTER_OUTPUT)
2457  return m_type == WHITELIST ? _("Transmit sentences") : _("Drop sentences");
2458  else
2459  return m_type == WHITELIST ? _("Accept only sentences")
2460  : _("Ignore sentences");
2461 }
2462 
2463 void SentenceListDlg::Populate(const wxArrayString& list) {
2464  if (m_dir == FILTER_OUTPUT) {
2465  wxString s;
2466  m_sentences.Add(g_TalkerIdText + wxString("RMB"));
2467  m_sentences.Add(g_TalkerIdText + wxString("RMC"));
2468  m_sentences.Add(g_TalkerIdText + wxString("APB"));
2469  m_sentences.Add(g_TalkerIdText + wxString("XTE"));
2470  }
2471  m_sentences.Add("AIVDM");
2472  m_sentences.Add("AIVDO");
2473  m_sentences.Add("FRPOS");
2474  m_sentences.Add(g_TalkerIdText);
2475  m_sentences.Add("CD");
2476  m_sentences.Sort();
2477  m_clbSentences->Clear();
2478  m_clbSentences->InsertItems(m_sentences, 0);
2479 
2480  wxArrayString new_strings;
2481 
2482  if (list.Count() == 0) {
2483  for (size_t i = 0; i < m_clbSentences->GetCount(); ++i)
2484  m_clbSentences->Check(i, m_type == WHITELIST);
2485  } else {
2486  for (size_t i = 0; i < list.Count(); ++i) {
2487  int item = m_clbSentences->FindString(list[i]);
2488  if (item != wxNOT_FOUND)
2489  m_clbSentences->Check(item);
2490  else
2491  new_strings.Add(list[i]);
2492  }
2493  if (new_strings.GetCount()) {
2494  m_clbSentences->InsertItems(new_strings, m_clbSentences->GetCount());
2495  for (size_t i = 0; i < new_strings.GetCount(); ++i) {
2496  int item = m_clbSentences->FindString(new_strings[i]);
2497  if (item != wxNOT_FOUND) m_clbSentences->Check(item);
2498  }
2499  }
2500  }
2501 }
2502 
2503 wxString SentenceListDlg::GetSentences(void) {
2504  wxArrayString retString;
2505  for (size_t i = 0; i < m_clbSentences->GetCount(); i++) {
2506  if (m_clbSentences->IsChecked(i))
2507  retString.Add(m_clbSentences->GetString(i));
2508  }
2509  return StringArrayToString(retString);
2510 }
2511 
2512 void SentenceListDlg::OnCLBSelect(wxCommandEvent& e) {
2513  // Only activate the "Delete" button if the selection is not in the standard
2514  // list
2515  m_btnDel->Enable(m_sentences.Index(e.GetString()) == wxNOT_FOUND);
2516 }
2517 
2518 void SentenceListDlg::OnAddClick(wxCommandEvent& event) {
2519 #ifdef __ANDROID__
2520  androidDisableRotation();
2521 #endif
2522 
2523  wxTextEntryDialog textdlg(
2524  this,
2525  _("Enter the NMEA sentence (2, 3 or 5 characters)\n or a valid REGEX "
2526  "expression (6 characters or longer)"),
2527  _("Enter the NMEA sentence"));
2528 
2529  textdlg.SetTextValidator(wxFILTER_ASCII);
2530  int result = textdlg.ShowModal();
2531 
2532 #ifdef __ANDROID__
2533  androidEnableRotation();
2534 #endif
2535 
2536  if (result == wxID_CANCEL) return;
2537  wxString stc = textdlg.GetValue();
2538 
2539  if (stc.Length() == 2 || stc.Length() == 3 || stc.Length() == 5) {
2540  m_clbSentences->Append(stc);
2541  m_clbSentences->Check(m_clbSentences->FindString(stc));
2542  return;
2543  } else if (stc.Length() < 2) {
2544  OCPNMessageBox(
2545  this,
2546  _("An NMEA sentence is generally 3 characters long (like RMC, GGA etc.)\n \
2547  It can also have a two letter prefix identifying the source, or TALKER, of the message.\n \
2548  The whole sentences then looks like GPGGA or AITXT.\n \
2549  You may filter out all the sentences with certain TALKER prefix (like GP, AI etc.).\n \
2550  The filter also accepts Regular Expressions (REGEX) with 6 or more characters. \n\n"),
2551  _("OpenCPN Info"));
2552  return;
2553  }
2554 
2555  else {
2556  // Verify that a longer text entry is a valid RegEx
2557  wxRegEx r(stc);
2558  if (r.IsValid()) {
2559  m_clbSentences->Append(stc);
2560  m_clbSentences->Check(m_clbSentences->FindString(stc));
2561  return;
2562  } else {
2563  OCPNMessageBox(this, _("REGEX syntax error: \n") + stc,
2564  _("OpenCPN Info"));
2565  return;
2566  }
2567  }
2568 }
2569 
2570 void SentenceListDlg::OnDeleteClick(wxCommandEvent& event) {
2571  m_clbSentences->Delete(m_clbSentences->GetSelection());
2572 }
2573 
2574 void SentenceListDlg::OnClearAllClick(wxCommandEvent& event) {
2575  for (size_t i = 0; i < m_clbSentences->GetCount(); i++)
2576  m_clbSentences->Check(i, FALSE);
2577 }
2578 
2579 void SentenceListDlg::OnCheckAllClick(wxCommandEvent& event) {
2580  for (size_t i = 0; i < m_clbSentences->GetCount(); i++)
2581  m_clbSentences->Check(i, TRUE);
2582 }
void Init(const KeyProvider &kp, std::function< void(ObservedEvt &ev)> action)
Initiate an object yet not listening.
Definition: observable.h:227
Adds a std::shared<void> element to wxCommandEvent.
Definition: ocpn_plugin.h:1652
General purpose GUI support.
bool CheckSerialAccess(wxWindow *parent, const std::string device)
Run checks and possible dialogs to ensure device is accessible.
Access checks for comm devices and dongle.