37#include <wx/tokenzr.h>
40#if defined(__linux__) && !defined(__ANDROID__)
45#include <sys/socket.h>
50#include "androidUTIL.h"
56#include "text_ctrl_w_help.h"
74#if wxCHECK_VERSION(3, 2, 0)
75#define _(s) wxGetTranslation(wxASCII_STR(s)).ToStdString()
77#define _(s) wxGetTranslation((s)).ToStdString()
80static const std::string kAddressDefaultHelp =
81 _(
"Enter IP address or hostname");
82static const std::string kAddressUdpHelp =
83 _(
"IP address or hostname, often 255.255.255.255");
84static const std::string kAddressMcastHelp =
85 _(
"Group address, usually 224.0.2.0 - 224.0.255.255");
86static const std::string kTcpDevice = _(
"Device using TCP");
87static const std::string kUdpReceive = _(
"Device sending UDP");
88static const std::string kUdpOutput = _(
"UDP send");
89static const std::string kGpsdDevice = _(
"Gpsd server");
90static const std::string kSignalkDevice = _(
"SignalK server");
91static const std::string kTcpClient = _(
"TCP client");
92static const std::string kUdpSend = _(
"Devices receiving UDP");
93static const std::string kGpsdClient = _(
"Gpsd client");
94static const std::string kSignalkClient = _(
"SignalK client");
95static const std::string kTcpServer = _(
"TCP Server");
96static const std::string kUdpInput = _(
"UDP Receive");
97static const std::string kMulticastServer = _(
"UDP Multicast Receive and Send");
98static const std::string kMulticastClient = _(
"UDP Multicast Send");
100static const std::vector<std::string> kBasicNetViews = {
101 kTcpDevice, kUdpReceive, kUdpSend, kGpsdDevice, kSignalkDevice};
103static const std::vector<std::string> kAdvancedNetViews = {
105 kTcpClient, kUdpInput, kUdpOutput, kGpsdClient,
106 kSignalkClient, kTcpServer, kMulticastClient, kMulticastServer};
108static wxString StringArrayToString(
const wxArrayString& arr) {
109 wxString ret = wxEmptyString;
110 for (
size_t i = 0; i < arr.Count(); i++) {
111 if (i > 0) ret.Append(
",");
118#if defined(__linux__) && !defined(__ANDROID__)
120std::vector<std::string> can_if_candidates;
121static int print_intf(
const struct intf_entry* entry,
void* arg) {
122 std::string iface = entry->intf_name;
123 if (entry->intf_type == 1 && iface.find(
"can") != std::string::npos) {
124 can_if_candidates.push_back(entry->intf_name);
130static bool IsAddressMultiCast(
const wxString& ip) {
131 wxArrayString bytes = wxSplit(ip,
'.');
132 if (bytes.size() != 4) {
135 unsigned long ipNum = (wxAtoi(bytes[0]) << 24) + (wxAtoi(bytes[1]) << 16) +
136 (wxAtoi(bytes[2]) << 8) + wxAtoi(bytes[3]);
137 unsigned long multicastStart = (224 << 24);
138 unsigned long multicastEnd = (239 << 24) + (255 << 16) + (255 << 8) + 255;
139 return ipNum >= multicastStart && ipNum <= multicastEnd;
142static bool IsAddressListener(
const std::string& address) {
143 return address.empty() || address ==
"0.0.0.0";
147static std::string GetChoiceSelection(
const wxChoice* choice) {
148 int selected = choice->GetSelection();
149 return choice->GetString(selected).ToStdString();
158 bool is_server = IsAddressListener(cp->NetworkAddress.ToStdString());
159 if (IsAddressMultiCast(cp->NetworkAddress))
160 return is_server ? kMulticastServer : kMulticastClient;
161 switch (cp->NetProtocol) {
162 case NetworkProtocol::GPSD:
164 case NetworkProtocol::SIGNALK:
165 return kSignalkDevice;
166 case NetworkProtocol::UDP:
167 return is_server ? kUdpReceive : kUdpSend;
168 case NetworkProtocol::TCP:
169 return is_server ? kTcpServer : kTcpDevice;
171 wxLogWarning(
"Cannot deduce connection params view type");
177static wxArrayString GetAvailableSocketCANInterfaces() {
180#if defined(__linux__) && !defined(__ANDROID__)
181 can_if_candidates.clear();
183 if ((intf = intf_open()) ==
nullptr) {
184 wxLogWarning(
"Error opening interface list");
188 if (intf_loop(intf, print_intf,
nullptr) < 0) {
189 wxLogWarning(
"Error looping over interface list");
193 for (
const auto& iface : can_if_candidates) {
194 int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
200 struct ifreq if_request = {{0}};
201 strcpy(if_request.ifr_name, iface.c_str());
202 if (ioctl(sock, SIOCGIFINDEX, &if_request) < 0) {
207 struct sockaddr_can can_address = {0};
208 can_address.can_family = AF_CAN;
209 can_address.can_ifindex = if_request.ifr_ifindex;
210 if (ioctl(sock, SIOCGIFFLAGS, &if_request) < 0) {
213 if (if_request.ifr_flags & IFF_UP) {
223static void LoadSerialPorts(wxComboBox* box) {
227 [[nodiscard]]
static std::string GetKey(
const std::string& s) {
228 if (s.find(
"->") == std::string::npos)
return s;
233 bool operator()(
const std::string& lhs,
const std::string& rhs)
const {
234 return GetKey(lhs) < GetKey(rhs);
238 std::set<std::string, PortSorter> sorted_ports(port_sorter);
240 for (
size_t i = 0; i < ports->GetCount(); i++)
241 sorted_ports.insert((*ports)[i].ToStdString());
243 auto value = box->GetValue();
245 for (
auto& p : sorted_ports) box->Append(p);
246 if (!value.empty()) box->SetValue(value);
250 if (ctrl.
IsPristine() || ctrl.GetValue().empty()) {
251 auto dlg = wxMessageDialog(parent, _(
"Required field port is missing"),
252 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
258 port = std::stoi(ctrl.GetValue().ToStdString());
259 }
catch (std::logic_error&) {
260 auto dlg = wxMessageDialog(parent, _(
"Invalid port number"),
261 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
266 static const std::string kMsg =
267 _(R
"(Port numbers smaller than 1024 are reserved for use by the
268operating system and should normally not be used by OpenCPN)");
269 auto dlg = wxMessageDialog(parent, kMsg, _(
"OpenCPN warning"),
270 wxOK | wxICON_WARNING);
278 if (ctrl.
IsPristine() || ctrl.GetValue().empty()) {
279 auto dlg = wxMessageDialog(parent, _(
"Required field address is missing"),
280 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
290static void SetupProtocolChoice(wxChoice* choice) {
292 choice->Append(
"NMEA 0183");
293 choice->Append(
"NMEA 2000");
294 choice->SetSelection(0);
302ConnectionEditDialog::ConnectionEditDialog()
305ConnectionEditDialog::ConnectionEditDialog(
309 : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), 0,
311 m_scroll_win_connections(nullptr),
312 m_on_edit_click(std::move(_on_edit_click)),
313 m_selected_conn_params(nullptr),
314 m_cp_original(nullptr),
315 m_is_conn_saved(false),
317 m_is_nmea_params_shown(false),
320 m_conn_enabled(false),
321 m_accept_radiobtn(nullptr),
323 m_advanced_chkbox(nullptr),
324 m_aps_magnetic_chkbox(nullptr),
325 m_auth_token_tctrl(nullptr),
326 m_auth_token_text(nullptr),
327 m_baud_rate_choice(nullptr),
328 m_bt_data_sources_choice(nullptr),
329 m_bt_last_result_count(0),
330 m_bt_no_change_counter(0),
331 m_bt_pairs_text(nullptr),
333 m_bt_scan_timer(nullptr),
334 m_can_props_sizer(nullptr),
335 m_can_source_choice(nullptr),
336 m_can_source_text(nullptr),
337 m_collapse_box(nullptr),
338 m_connection_props_sizer(nullptr),
339 m_connections_sizer(nullptr),
340 m_conn_edit_statbox(nullptr),
341 m_dlg_buttons_apply_btn(nullptr),
342 m_dlg_buttons_cancel_btn(nullptr),
343 m_dlg_buttons_ok_btn(nullptr),
344 m_dlg_cancel_btn(nullptr),
345 m_dlg_ok_btn(nullptr),
346 m_filter_cog_sog_chkbox(nullptr),
347 m_filter_sec_tctrl(nullptr),
348 m_filter_sec_text(nullptr),
349 m_furuno_gp3x_chkbox(nullptr),
350 m_garmin_host_chkbox(nullptr),
351 m_garmin_upload_host_chkbox(nullptr),
352 m_ignore_radiobtn(nullptr),
353 m_in_filter_sizer(nullptr),
354 m_input_chkbox(nullptr),
355 m_input_stc_list_btn(nullptr),
356 m_input_stc_tctrl(nullptr),
357 m_net_address_tctrl(nullptr),
358 m_net_addr_text(nullptr),
359 m_net_comment_tctrl(nullptr),
360 m_net_comment_text(nullptr),
361 m_net_data_protocol_choice(nullptr),
362 m_net_data_protocol_text(nullptr),
363 m_net_expert_box_text(nullptr),
364 m_net_expert_chkbox(nullptr),
365 m_net_port_tctrl(nullptr),
366 m_net_port_text(nullptr),
367 m_net_props_sizer(nullptr),
368 m_net_view_choice(nullptr),
369 m_net_type_choice_text(nullptr),
370 m_o_accept_radiobtn(nullptr),
371 m_o_ignore_radiobtn(nullptr),
372 m_out_filter_sizer(nullptr),
373 m_output_chkbox(nullptr),
374 m_output_stc_list_btn(nullptr),
375 m_output_stc_tctrl(nullptr),
377 m_port_combo(nullptr),
378 m_precision_choice(nullptr),
379 m_precision_text(nullptr),
380 m_priority_choice(nullptr),
381 m_priority_dialog_btn(nullptr),
382 m_remove_btn(nullptr),
383 m_scan_bt_btn(nullptr),
384 m_ser_baudrate_text(nullptr),
385 m_ser_comment_text(nullptr),
386 m_serial_comment_tctrl(nullptr),
387 m_serial_protocol_choice(nullptr),
388 m_ser_port_text(nullptr),
389 m_ser_props_sizer(nullptr),
390 m_ser_protocol_text(nullptr),
391 m_sizer_box_btn(nullptr),
392 m_sk_check_discover_chkbox(nullptr),
393 m_sk_discover_btn(nullptr),
394 m_sk_server_status_text(nullptr),
395 m_std_dialog_btn_sizer(nullptr),
396 m_talker_id_text(nullptr),
397 m_type_can_radiobtn(nullptr),
398 m_type_internal_bt_radiobtn(nullptr),
399 m_type_internal_gps_radiobtn(nullptr),
400 m_type_net_radiobtn(nullptr),
401 m_type_serial_radiobtn(nullptr) {
405ConnectionEditDialog::~ConnectionEditDialog() =
default;
407void ConnectionEditDialog::AddOKCancelButtons() {
409 if (!m_std_dialog_btn_sizer) {
410 m_std_dialog_btn_sizer =
new wxStdDialogButtonSizer();
411 m_dlg_ok_btn =
new wxButton(
this, wxID_OK);
412 m_dlg_cancel_btn =
new wxButton(
this, wxID_CANCEL, _(
"Cancel"));
413 m_std_dialog_btn_sizer->AddButton(m_dlg_ok_btn);
414 m_std_dialog_btn_sizer->AddButton(m_dlg_cancel_btn);
415 m_std_dialog_btn_sizer->Realize();
416 GetSizer()->Add(m_std_dialog_btn_sizer, 0, wxALL | wxEXPAND, 5);
417 m_std_dialog_btn_sizer->Show(
true);
420 if (!m_std_dialog_btn_sizer) {
421 m_std_dialog_btn_sizer =
new wxStdDialogButtonSizer();
422 m_dlg_ok_btn =
new wxButton(
this, wxID_OK);
423 m_dlg_cancel_btn =
new wxButton(
this, wxID_CANCEL, _(
"Cancel"));
424 m_std_dialog_btn_sizer->AddSpacer(wxWindow::GetCharWidth());
425 m_std_dialog_btn_sizer->Add(m_dlg_ok_btn, 0, wxALL, 5);
426 m_std_dialog_btn_sizer->Add(m_dlg_cancel_btn, 0, wxALL, 5);
427 GetSizer()->Add(m_std_dialog_btn_sizer, 0, wxALL | wxEXPAND, 5);
431 m_dlg_ok_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
432 [&](wxCommandEvent& ev) { OnOKClick(); });
433 m_dlg_cancel_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
434 [&](wxCommandEvent& ev) { OnCancelClick(); });
436void ConnectionEditDialog::InitiateNewConnection() {
437 m_net_view_choice->Clear();
438 for (
const auto& view : kBasicNetViews) m_net_view_choice->Append(view);
439 m_net_view_choice->SetSelection(0);
440 m_net_expert_chkbox->SetValue(
false);
441 m_net_comment_tctrl->Hide();
442 m_net_comment_text->Hide();
446 if (addr_ctrl) addr_ctrl->
SetHelp(kAddressDefaultHelp);
447 SetupProtocolChoice(m_net_data_protocol_choice);
451 int selection = m_net_view_choice->GetSelection();
452 if (selection == wxNOT_FOUND)
return;
453 std::string view = GetChoiceSelection(m_net_view_choice);
454 ConfigureControlsForView(view);
455 OnExpertModeChange();
458void ConnectionEditDialog::ConfigureControlsForView(
const std::string& view) {
459 if (!m_type_net_radiobtn->GetValue())
return;
460 auto found = std::find(kBasicNetViews.begin(), kBasicNetViews.end(), view);
461 int selection = m_net_view_choice->GetSelection();
462 assert(selection != wxNOT_FOUND);
463 m_net_expert_chkbox->SetValue(found == kBasicNetViews.end());
464 m_net_address_tctrl->Enable();
465 auto net_addr_w_help =
dynamic_cast<TextCtrlWithHelp*
>(m_net_address_tctrl);
466 assert(net_addr_w_help);
468 assert(net_port_w_help);
469 m_net_addr_text->SetLabel(_(
"Server address"));
470 m_output_chkbox->Disable();
471 m_input_chkbox->Disable();
472 m_net_addr_text->Show();
473 m_net_address_tctrl->Show();
474 auto port = m_net_port_tctrl->GetValue();
475 if (port == kDefaultGpsdPort || port == kDefaultSignalkPort || port.empty())
476 net_port_w_help->RestoreHelp();
477 if (view == kTcpDevice || view == kTcpClient) {
478 m_input_chkbox->SetValue(
true);
479 m_output_chkbox->SetValue(
false);
480 m_net_addr_text->Show();
481 m_net_address_tctrl->Show();
482 m_input_chkbox->Enable();
483 m_output_chkbox->Enable();
484 }
else if (view == kUdpReceive || view == kUdpInput) {
485 m_net_addr_text->Hide();
486 m_net_address_tctrl->ChangeValue(
"0.0.0.0");
487 m_net_address_tctrl->Disable();
488 m_net_address_tctrl->Hide();
489 m_input_chkbox->SetValue(
true);
490 m_output_chkbox->SetValue(
false);
491 }
else if (view == kGpsdClient || view == kGpsdDevice) {
492 m_net_data_protocol_choice->Clear();
493 m_net_data_protocol_choice->Append(
"gpsd");
494 m_net_data_protocol_choice->SetSelection(0);
495 m_net_data_protocol_choice->Disable();
496 m_output_chkbox->SetValue(
false);
497 m_input_chkbox->SetValue(
true);
498 if (net_port_w_help->IsPristine())
499 net_port_w_help->ChangeValue(kDefaultGpsdPort);
500 }
else if (view == kSignalkClient || view == kSignalkDevice) {
501 m_net_data_protocol_choice->Clear();
502 m_net_data_protocol_choice->Append(
"SignalK");
503 m_net_data_protocol_choice->SetSelection(0);
504 m_net_data_protocol_choice->Disable();
505 m_input_chkbox->SetValue(
true);
506 m_output_chkbox->SetValue(
false);
507 if (net_port_w_help->IsPristine())
508 net_port_w_help->ChangeValue(kDefaultSignalkPort);
509 }
else if (view == kTcpServer) {
510 m_net_addr_text->SetLabel(_(
"Interface"));
511 m_net_address_tctrl->ChangeValue(
"0.0.0.0");
512 m_net_address_tctrl->Disable();
513 m_input_chkbox->SetValue(
true);
514 m_output_chkbox->Enable();
515 m_input_chkbox->Enable();
516 }
else if (view == kMulticastClient || view == kMulticastServer) {
517 if (m_net_view_choice->GetCount() != 2)
518 SetupProtocolChoice(m_net_data_protocol_choice);
519 if (net_addr_w_help->GetValue().empty()) net_addr_w_help->RestoreHelp();
520 m_net_addr_text->SetLabel(_(
"Multicast group"));
521 if (net_port_w_help->IsPristine())
522 net_port_w_help->SetHelp(
"Port number, usually 49152..65535");
525 if (view == kMulticastClient || view == kUdpSend || view == kUdpOutput) {
526 m_input_chkbox->SetValue(
false);
527 m_output_chkbox->SetValue(
true);
528 }
else if (view == kMulticastServer) {
529 m_input_chkbox->SetValue(
true);
530 m_output_chkbox->SetValue(
false);
531 m_output_chkbox->Enable();
532 m_input_chkbox->Disable();
535 if (view == kTcpClient || view == kTcpDevice || view == kUdpInput ||
536 view == kUdpReceive) {
537 if (net_port_w_help->IsPristine())
538 net_port_w_help->SetHelp(_(
"Port number (1025..65535, often 10110)"));
540 if (view != kGpsdClient && view != kGpsdDevice && view != kSignalkClient &&
541 view != kSignalkDevice) {
542 if (m_net_view_choice->GetCount() != 2)
543 SetupProtocolChoice(m_net_data_protocol_choice);
545 if (view != kTcpServer && view != kUdpReceive && view != kUdpInput &&
546 view != kMulticastServer) {
547 if (m_net_address_tctrl->GetValue() ==
"0.0.0.0")
548 net_addr_w_help->RestoreHelp();
550 if (net_addr_w_help->IsPristine()) {
551 if (view == kUdpSend)
552 net_addr_w_help->SetHelp(kAddressUdpHelp);
553 else if (view == kMulticastClient || view == kMulticastServer)
554 net_addr_w_help->SetHelp(kAddressMcastHelp);
556 net_addr_w_help->SetHelp(kAddressDefaultHelp);
562 if (!m_type_net_radiobtn->GetValue())
return;
563 if (m_garmin_host_chkbox) m_garmin_host_chkbox->Hide();
564 if (m_garmin_upload_host_chkbox) m_garmin_upload_host_chkbox->Hide();
565 const std::string view = GetChoiceSelection(m_net_view_choice);
566 bool show_auth = view == kSignalkDevice || view == kSignalkClient;
567 m_auth_token_tctrl->Show(show_auth && m_advanced);
568 m_auth_token_text->Show(show_auth && m_advanced);
569 bool show_apb_precision = m_output_chkbox->IsChecked();
570 m_precision_text->Show(show_apb_precision && m_advanced);
571 m_precision_choice->Show(show_apb_precision && m_advanced);
575void ConnectionEditDialog::Init() {
581 m_bt_scan_timer.SetOwner(
this, ID_BT_SCANTIMER);
583 wxSize displaySize = wxGetDisplaySize();
587 auto* mainSizer =
new wxBoxSizer(wxVERTICAL);
590 wxFont* dFont = GetOCPNScaledFont_PlugIn(_(
"Dialog"));
591 double font_size = dFont->GetPointSize() * 17 / 16;
592 wxFont* bFont = wxTheFontList->FindOrCreateFont(
593 static_cast<int>(font_size), dFont->GetFamily(), dFont->GetStyle(),
597 m_conn_edit_statbox =
598 new wxStaticBox(
this, wxID_ANY, _(
"Edit Selected Connection"));
599 m_conn_edit_statbox->SetFont(*bFont);
601 m_connection_props_sizer =
602 new wxStaticBoxSizer(m_conn_edit_statbox, wxVERTICAL);
603 GetSizer()->Add(m_connection_props_sizer, 1, wxALL | wxEXPAND, 5);
605 wxBoxSizer* bSizer15;
606 bSizer15 =
new wxBoxSizer(wxHORIZONTAL);
608 m_connection_props_sizer->Add(bSizer15, 0, wxTOP | wxEXPAND, 5);
610 m_type_serial_radiobtn =
611 new wxRadioButton(
this, wxID_ANY, _(
"Serial"), wxDefaultPosition,
612 wxDefaultSize, wxRB_GROUP);
613 m_type_serial_radiobtn->SetValue(
true);
614 bSizer15->Add(m_type_serial_radiobtn, 0, wxALL, 5);
616 m_type_net_radiobtn =
new wxRadioButton(
this, wxID_ANY, _(
"Network"),
617 wxDefaultPosition, wxDefaultSize, 0);
618 bSizer15->Add(m_type_net_radiobtn, 0, wxALL, 5);
620 m_type_can_radiobtn =
new wxRadioButton(
this, wxID_ANY,
"socketCAN",
621 wxDefaultPosition, wxDefaultSize, 0);
622#if defined(__linux__) && !defined(__ANDROID__) && !defined(__WXOSX__)
623 bSizer15->Add(m_type_can_radiobtn, 0, wxALL, 5);
625 m_type_can_radiobtn->Hide();
628 auto* bSizer15a =
new wxBoxSizer(wxHORIZONTAL);
629 m_connection_props_sizer->Add(bSizer15a, 0, wxEXPAND, 5);
631 if (OCPNPlatform::hasInternalGPS()) {
632 m_type_internal_gps_radiobtn =
new wxRadioButton(
633 this, wxID_ANY, _(
"Built-in GPS"), wxDefaultPosition, wxDefaultSize, 0);
634 bSizer15a->Add(m_type_internal_gps_radiobtn, 0, wxALL, 5);
636 m_type_internal_gps_radiobtn =
nullptr;
639 if (OCPNPlatform::hasInternalBT()) {
640 m_type_internal_bt_radiobtn =
641 new wxRadioButton(
this, wxID_ANY, _(
"Built-in Bluetooth SPP"),
642 wxDefaultPosition, wxDefaultSize, 0);
643 bSizer15a->Add(m_type_internal_bt_radiobtn, 0, wxALL, 5);
645 m_scan_bt_btn =
new wxButton(
this, wxID_ANY, _(
"BT Scan") +
" ",
646 wxDefaultPosition, wxDefaultSize);
647 m_scan_bt_btn->Hide();
649 m_connection_props_sizer->Add(m_scan_bt_btn, 0, wxALL, 25);
652 new wxStaticText(
this, wxID_ANY, _(
"Bluetooth Data Sources"),
653 wxDefaultPosition, wxDefaultSize, 0);
654 m_bt_pairs_text->Wrap(-1);
655 m_bt_pairs_text->Hide();
656 m_connection_props_sizer->Add(m_bt_pairs_text, 0, wxALL, 5);
661 int ref_size = this->GetCharWidth();
662 m_bt_data_sources_choice =
663 new wxChoice(
this, wxID_ANY, wxDefaultPosition,
664 wxSize(40 * ref_size, 2 * ref_size), mt);
665 m_bt_data_sources_choice->SetSelection(0);
666 m_bt_data_sources_choice->Hide();
667 m_connection_props_sizer->Add(m_bt_data_sources_choice, 1, wxEXPAND | wxTOP,
671 m_type_internal_bt_radiobtn =
nullptr;
674 m_net_props_sizer =
new wxFlexGridSizer(0, 2, 0, 0);
676 m_connection_props_sizer->Add(m_net_props_sizer, 0, wxEXPAND, 5);
679 if (displaySize.x < displaySize.y) {
680 wxBoxSizer* bSizer16a;
681 bSizer16a =
new wxBoxSizer(wxHORIZONTAL);
682 m_net_props_sizer->AddSpacer(1);
683 m_net_props_sizer->Add(bSizer16a, 1, wxEXPAND, 5);
684 m_net_props_sizer->AddSpacer(1);
685 m_net_props_sizer->AddSpacer(1);
687 m_net_expert_box_text =
new wxStaticText(
this, wxID_ANY, _(
"Expert mode"));
688 m_net_props_sizer->Add(m_net_expert_box_text, 0, wxALL, 5);
689 m_net_expert_chkbox =
new wxCheckBox(
this, wxID_ANY,
"");
690 m_net_props_sizer->Add(m_net_expert_chkbox, 0, wxALL, 5);
691 m_net_expert_chkbox->Bind(
692 wxEVT_CHECKBOX, [&](
const wxCommandEvent&) { OnExpertModeChange(); });
694 m_net_type_choice_text =
695 new wxStaticText(
this, wxID_ANY, _(
"Connection type"));
696 m_net_props_sizer->Add(m_net_type_choice_text, 0, wxALL, 5);
697 m_net_view_choice =
new wxChoice(
this, wxID_ANY);
698 m_net_view_choice->Append(kBasicNetViews[0]);
699 m_net_view_choice->SetSelection(0);
700 m_net_view_choice->Bind(wxEVT_CHOICE,
702 m_net_props_sizer->Add(m_net_view_choice, 0, wxTOP, 5);
703 m_net_data_protocol_text =
704 new wxStaticText(
this, wxID_ANY, _(
"Data Protocol"));
705 m_net_data_protocol_text->Wrap(-1);
706 m_net_props_sizer->Add(m_net_data_protocol_text, 0, wxALL, 5);
708 m_net_data_protocol_choice =
new wxChoice(
this, wxID_ANY);
709 SetupProtocolChoice(m_net_data_protocol_choice);
710 m_net_props_sizer->Add(m_net_data_protocol_choice, 1, wxTOP, 5);
711 m_net_props_sizer->AddSpacer(1);
712 m_net_props_sizer->AddSpacer(1);
714 m_net_addr_text =
new wxStaticText(
this, wxID_ANY, _(
"Address"));
715 m_net_addr_text->Wrap(-1);
716 int column1width = 15 * GetCharWidth();
717 m_net_addr_text->SetMinSize(wxSize(column1width, -1));
718 m_net_props_sizer->Add(m_net_addr_text, 0, wxALL, 5);
720 int column2width = 60 * GetCharWidth();
721 m_net_address_tctrl->SetMaxSize(wxSize(column2width, -1));
722 m_net_address_tctrl->SetMinSize(wxSize(column2width, -1));
723 m_net_address_tctrl->Bind(wxEVT_KILL_FOCUS,
724 [&](wxFocusEvent& ev) { OnAddressChange(ev); });
726 m_net_props_sizer->Add(m_net_address_tctrl, 0, wxEXPAND | wxTOP, 5);
727 m_net_props_sizer->AddSpacer(1);
728 m_net_props_sizer->AddSpacer(1);
730 m_net_port_text =
new wxStaticText(
this, wxID_ANY, _(
"Data Port"));
731 m_net_port_text->Wrap(-1);
732 m_net_props_sizer->Add(m_net_port_text, 0, wxALL, 5);
735 m_net_port_tctrl->SetMaxSize(wxSize(column2width, -1));
736 m_net_port_tctrl->SetMinSize(wxSize(column2width, -1));
737 m_net_props_sizer->Add(m_net_port_tctrl, 1, wxEXPAND | wxTOP, 5);
738 m_net_port_tctrl->SetMaxSize(wxSize(column2width, -1));
739 m_net_port_tctrl->SetMinSize(wxSize(column2width, -1));
741 m_net_comment_text =
new wxStaticText(
this, wxID_ANY, _(
"User Comment"));
742 m_net_comment_text->Wrap(-1);
743 m_net_comment_text->SetMinSize({column1width, -1});
744 m_net_props_sizer->Add(m_net_comment_text, 0, wxALL, 5);
745 m_net_comment_text->Hide();
747 m_net_comment_tctrl =
new wxTextCtrl(
this, wxID_ANY);
748 m_net_comment_tctrl->SetMaxSize({column2width, -1});
749 m_net_comment_tctrl->SetMinSize({column2width, -1});
750 m_net_props_sizer->Add(m_net_comment_tctrl, 1, wxEXPAND | wxTOP, 5);
751 m_net_comment_tctrl->Hide();
753 m_net_props_sizer->AddSpacer(1);
754 m_net_props_sizer->AddSpacer(1);
756 m_can_props_sizer =
new wxGridSizer(0, 1, 0, 0);
757 wxFlexGridSizer* fgSizer1C;
758 fgSizer1C =
new wxFlexGridSizer(0, 2, 0, 0);
760 m_can_source_text =
new wxStaticText(
this, wxID_ANY, _(
"socketCAN Source"),
761 wxDefaultPosition, wxDefaultSize, 0);
762 m_can_source_text->Wrap(-1);
763 m_can_source_text->SetMinSize(wxSize(column1width, -1));
764 fgSizer1C->Add(m_can_source_text, 0, wxALL, 5);
766 wxArrayString choices = GetAvailableSocketCANInterfaces();
767 m_can_source_choice =
768 new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
770 m_can_source_choice->SetSelection(0);
771 m_can_source_choice->Enable(!choices.empty());
772 m_can_source_choice->SetMaxSize(wxSize(column2width, -1));
773 m_can_source_choice->SetMinSize(wxSize(column2width, -1));
774 fgSizer1C->Add(m_can_source_choice, 1, wxEXPAND | wxTOP, 5);
776 m_can_props_sizer->Add(fgSizer1C, 0, wxEXPAND, 5);
778 m_connection_props_sizer->Add(m_can_props_sizer, 0, wxEXPAND, 5);
780 m_ser_props_sizer =
new wxGridSizer(0, 1, 0, 0);
781 m_connection_props_sizer->Add(m_ser_props_sizer, 0, wxEXPAND, 5);
783 wxFlexGridSizer* fgSizer1;
784 fgSizer1 =
new wxFlexGridSizer(0, 4, 0, 0);
785 fgSizer1->SetFlexibleDirection(wxBOTH);
786 fgSizer1->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
789 new wxStaticText(
this, wxID_ANY, _(
"Data port"), wxDefaultPosition,
790 wxDefaultSize, wxST_ELLIPSIZE_END);
791 m_ser_port_text->SetMinSize(wxSize(column1width, -1));
792 m_ser_port_text->Wrap(-1);
794 fgSizer1->Add(m_ser_port_text, 0, wxALL, 5);
797 new wxComboBox(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
798 wxDefaultSize, 0,
nullptr, 0);
800 m_port_combo->SetMaxSize(wxSize(column2width, -1));
801 m_port_combo->SetMinSize(wxSize(column2width, -1));
803 fgSizer1->Add(m_port_combo, 0, wxEXPAND | wxTOP, 5);
805 m_ser_baudrate_text =
new wxStaticText(
this, wxID_ANY, _(
"Baudrate"),
806 wxDefaultPosition, wxDefaultSize, 0);
807 m_ser_baudrate_text->Wrap(-1);
808 fgSizer1->AddSpacer(1);
809 fgSizer1->AddSpacer(1);
810 fgSizer1->Add(m_ser_baudrate_text, 0, wxALL, 5);
812 wxString m_choiceBaudRateChoices[] = {
813 _(
"150"), _(
"300"), _(
"600"), _(
"1200"), _(
"2400"),
814 _(
"4800"), _(
"9600"), _(
"19200"), _(
"38400"), _(
"57600"),
815 _(
"115200"), _(
"230400"), _(
"460800"), _(
"921600")};
816 int m_choiceBaudRateNChoices =
817 sizeof(m_choiceBaudRateChoices) /
sizeof(wxString);
819 new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
820 m_choiceBaudRateNChoices, m_choiceBaudRateChoices, 0);
824 m_baud_rate_choice->SetSelection(0);
826 fgSizer1->Add(m_baud_rate_choice, 1, wxEXPAND | wxTOP, 5);
827 fgSizer1->AddSpacer(1);
828 fgSizer1->AddSpacer(1);
830 m_ser_protocol_text =
new wxStaticText(
this, wxID_ANY, _(
"Protocol"));
831 m_ser_protocol_text->Wrap(-1);
832 fgSizer1->Add(m_ser_protocol_text, 0, wxALL, 5);
834 wxString m_choiceSerialProtocolChoices[] = {_(
"NMEA 0183"), _(
"NMEA 2000")};
835 int m_choiceSerialProtocolNChoices =
836 sizeof(m_choiceSerialProtocolChoices) /
sizeof(wxString);
837 m_serial_protocol_choice =
new wxChoice(
838 this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
839 m_choiceSerialProtocolNChoices, m_choiceSerialProtocolChoices, 0);
843 m_serial_protocol_choice->SetSelection(0);
844 m_serial_protocol_choice->Enable(
true);
845 fgSizer1->Add(m_serial_protocol_choice, 1, wxEXPAND | wxTOP, 5);
847 m_ser_props_sizer->Add(fgSizer1, 0, wxEXPAND, 5);
851 auto* commentSizer =
new wxFlexGridSizer(0, 2, 0, 0);
855 m_ser_comment_text =
new wxStaticText(
this, wxID_ANY, _(
"User Comment"));
856 m_ser_comment_text->Wrap(-1);
857 m_ser_comment_text->SetMinSize(wxSize(column1width, -1));
858 commentSizer->Add(m_ser_comment_text, 0, wxALL, 5);
860 m_serial_comment_tctrl =
new wxTextCtrl(
this, wxID_ANY);
861 m_serial_comment_tctrl->SetMaxSize(wxSize(column2width, -1));
862 m_serial_comment_tctrl->SetMinSize(wxSize(column2width, -1));
864 commentSizer->Add(m_serial_comment_tctrl, 1, wxTOP, 5);
866 m_connection_props_sizer->Add(commentSizer, 0, wxALL, 5);
868 wxFlexGridSizer* fgSizer5;
869 fgSizer5 =
new wxFlexGridSizer(0, 2, 0, 0);
870 fgSizer5->SetFlexibleDirection(wxBOTH);
871 fgSizer5->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
872 m_connection_props_sizer->Add(fgSizer5, 0, wxEXPAND, 5);
875 new wxCheckBox(
this, wxID_ANY, _(
"Receive Input on this Port"));
876 fgSizer5->Add(m_input_chkbox, 0, wxALL, 2);
877 fgSizer5->AddSpacer(1);
880 new wxCheckBox(
this, wxID_ANY,
881 wxString::Format(
"%s (%s)", _(
"Output on this port"),
882 _(
"as autopilot or NMEA repeater")));
883 fgSizer5->Add(m_output_chkbox, 0, wxALL, 2);
884 fgSizer5->AddSpacer(1);
888 auto flags = wxSizerFlags().Border();
889 m_collapse_box =
new wxBoxSizer(wxHORIZONTAL);
891 m_collapse_box->Add(
new wxStaticText(
this, wxID_ANY, _(
"Advanced: ")), flags);
894 [&](
bool collapsed) { OnCollapsedToggle(collapsed); }),
896 fgSizer5->Add(m_collapse_box, wxSizerFlags());
897 fgSizer5->Add(
new wxStaticText(
this, wxID_ANY,
""));
899#ifndef USE_GARMINHOST
900 m_cbGarminHost->Hide();
903 m_auth_token_text =
new wxStaticText(
this, wxID_ANY, _(
"Auth Token"));
904 m_auth_token_text->SetMinSize(wxSize(column1width, -1));
905 m_auth_token_text->Wrap(-1);
906 m_auth_token_text->SetMinSize(wxSize(column1width, -1));
907 fgSizer5->Add(m_auth_token_text, 0, wxALL, 5);
908 m_auth_token_text->Hide();
910 m_auth_token_tctrl =
new wxTextCtrl(
this, wxID_ANY,
"");
911 m_auth_token_tctrl->SetMinSize(wxSize(column2width, -1));
912 fgSizer5->Add(m_auth_token_tctrl, 1, wxEXPAND | wxTOP, 5);
913 m_auth_token_tctrl->SetValue(
"orvar");
914 m_auth_token_tctrl->Hide();
916 fgSizer5->AddSpacer(1);
917 fgSizer5->Add(
new wxStaticText(
this, wxID_ANY,
""), 0, wxALL, 2);
920 new wxStaticText(
this, wxID_ANY, _(
"APB bearing precision"));
921 m_precision_text->Wrap(-1);
922 m_precision_text->SetMinSize(wxSize(column1width, -1));
923 fgSizer5->Add(m_precision_text, 0, wxALL, 2);
924 m_precision_text->Hide();
926 wxString m_choicePrecisionChoices[] = {_(
"x"), _(
"x.x"), _(
"x.xx"),
927 _(
"x.xxx"), _(
"x.xxxx")};
928 int m_choicePrecisionNChoices =
929 sizeof(m_choicePrecisionChoices) /
sizeof(wxString);
931 new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
932 m_choicePrecisionNChoices, m_choicePrecisionChoices, 0);
936 m_precision_choice->SetSelection(g_NMEAAPBPrecision);
937 fgSizer5->Add(m_precision_choice, 0, wxALL, 2);
938 m_precision_choice->Hide();
939 OnExpertModeChange();
941 m_garmin_host_chkbox =
942 new wxCheckBox(
this, wxID_ANY, _(
"Use Garmin (GRMN) mode for input"));
943 m_garmin_host_chkbox->SetValue(
false);
944 fgSizer5->Add(m_garmin_host_chkbox, 0, wxALL, 2);
945 fgSizer5->AddSpacer(1);
948 m_sk_check_discover_chkbox =
949 new wxCheckBox(
this, wxID_ANY, _(
"Automatic server discovery"));
950 m_sk_check_discover_chkbox->SetValue(
true);
951 m_sk_check_discover_chkbox->SetToolTip(
952 _(
"If checked, signal K server will be discovered automatically"));
954 fgSizer5->Add(m_sk_check_discover_chkbox, 0, wxALL, 2);
957 m_sk_discover_btn =
new wxButton(
this, wxID_ANY, _(
"Discover now..."));
958 m_sk_discover_btn->Hide();
959 fgSizer5->Add(m_sk_discover_btn, 0, wxALL, 2);
962 m_sk_server_status_text =
new wxStaticText(
this, wxID_ANY,
"");
963 fgSizer5->Add(m_sk_server_status_text, 0, wxALL, 2);
965 m_in_filter_sizer =
new wxStaticBoxSizer(
966 new wxStaticBox(
this, wxID_ANY, _(
"Input filtering")), wxVERTICAL);
967 m_connection_props_sizer->Add(m_in_filter_sizer,
968 wxSizerFlags().Expand().Border());
971 bSizer9 =
new wxBoxSizer(wxHORIZONTAL);
974 new wxRadioButton(
this, wxID_ANY, _(
"Accept only sentences"));
975 bSizer9->Add(m_accept_radiobtn, 0, wxALL, 5);
977 m_ignore_radiobtn =
new wxRadioButton(
this, wxID_ANY, _(
"Ignore sentences"));
978 bSizer9->Add(m_ignore_radiobtn, 0, wxALL, 5);
980 m_in_filter_sizer->Add(bSizer9, 0, wxEXPAND, 5);
982 wxBoxSizer* bSizer11;
983 bSizer11 =
new wxBoxSizer(wxHORIZONTAL);
984 m_in_filter_sizer->Add(bSizer11, 0, wxEXPAND, 5);
987 new wxTextCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
988 wxDefaultSize, wxTE_READONLY);
989 bSizer11->Add(m_input_stc_tctrl, 1, wxALL | wxEXPAND, 5);
991 m_input_stc_list_btn =
new wxButton(
this, wxID_ANY,
"...", wxDefaultPosition,
992 wxDefaultSize, wxBU_EXACTFIT);
993 bSizer11->Add(m_input_stc_list_btn, 0, wxALL, 5);
995 bSizer11->AddSpacer(GetCharWidth() * 5);
997 m_out_filter_sizer =
new wxStaticBoxSizer(
998 new wxStaticBox(
this, wxID_ANY, _(
"Output filtering")), wxVERTICAL);
999 m_connection_props_sizer->Add(m_out_filter_sizer, 0, wxEXPAND, 5);
1001 wxBoxSizer* bSizer10;
1002 bSizer10 =
new wxBoxSizer(wxHORIZONTAL);
1004 m_o_accept_radiobtn =
1005 new wxRadioButton(
this, wxID_ANY, _(
"Transmit sentences"),
1006 wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
1007 bSizer10->Add(m_o_accept_radiobtn, 0, wxALL, 5);
1009 m_o_ignore_radiobtn =
new wxRadioButton(
this, wxID_ANY, _(
"Drop sentences"),
1010 wxDefaultPosition, wxDefaultSize, 0);
1011 bSizer10->Add(m_o_ignore_radiobtn, 0, wxALL, 5);
1013 m_out_filter_sizer->Add(bSizer10, 0, wxEXPAND, 5);
1015 wxBoxSizer* bSizer12;
1016 bSizer12 =
new wxBoxSizer(wxHORIZONTAL);
1017 m_out_filter_sizer->Add(bSizer12, 0, wxEXPAND, 5);
1019 m_output_stc_tctrl =
1020 new wxTextCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1021 wxDefaultSize, wxTE_READONLY);
1022 bSizer12->Add(m_output_stc_tctrl, 1, wxALL | wxEXPAND, 5);
1024 m_output_stc_list_btn =
new wxButton(
this, wxID_ANY,
"...", wxDefaultPosition,
1025 wxDefaultSize, wxBU_EXACTFIT);
1026 bSizer12->Add(m_output_stc_list_btn, 0, wxALL, 5);
1028 bSizer12->AddSpacer(GetCharWidth() * 5);
1030 m_connection_props_sizer->AddSpacer(20);
1034 SetInitialSettings();
1038 ShowNMEACommon(
true);
1039 ShowNMEASerial(
true);
1043 m_is_conn_saved =
true;
1045 GetSizer()->Fit(
this);
1047 m_new_device_listener.Init(
1048 SystemEvents::GetInstance().evt_dev_change,
1049 [&](
ObservedEvt&) { LoadSerialPorts(m_port_combo); });
1052void ConnectionEditDialog::OnAddressChange(wxFocusEvent& ev) {
1053 int selection = m_net_view_choice->GetSelection();
1054 if (selection != wxNOT_FOUND) {
1055 std::string type = m_net_view_choice->GetString(selection).ToStdString();
1056 if (type == kMulticastClient || type == kMulticastServer) {
1057 auto address = m_net_address_tctrl->GetValue().ToStdString();
1058 if (!IsAddressMultiCast(address)) {
1059 auto dlg = wxMessageDialog(
this, _(
"Illegal multicast address"),
1060 _(
"OpenCPN warning"), wxOK | wxICON_WARNING);
1068void ConnectionEditDialog::OnExpertModeChange() {
1069 bool advanced = m_net_expert_chkbox->GetValue();
1070 int view = m_net_view_choice->GetSelection();
1071 m_net_view_choice->Clear();
1073 for (
const auto& choice : kAdvancedNetViews)
1074 m_net_view_choice->Append(choice);
1075 m_net_type_choice_text->SetLabel(_(
"Connection type"));
1076 if (m_net_comment_text) m_net_comment_text->Show();
1077 if (m_net_comment_tctrl) m_net_comment_tctrl->Show();
1079 if (view != wxNOT_FOUND) {
1080 if (
static_cast<size_t>(view) >= kBasicNetViews.size()) view = 0;
1082 for (
const auto& choice : kBasicNetViews) m_net_view_choice->Append(choice);
1083 m_net_type_choice_text->SetLabel(_(
"Connect to"));
1084 if (m_net_comment_text) m_net_comment_text->Hide();
1085 if (m_net_comment_tctrl) m_net_comment_tctrl->Hide();
1087 m_net_view_choice->SetSelection(view);
1088 auto view_str = m_net_view_choice->GetStringSelection().ToStdString();
1089 if (!view_str.empty()) ConfigureControlsForView(view_str);
1093void ConnectionEditDialog::OnCancelClick() {
1094 m_on_edit_click(
nullptr,
false,
false);
1097void ConnectionEditDialog::OnOKClick() {
1098 if (m_cp_original) {
1099 int selection = m_net_view_choice->GetSelection();
1100 if (selection != wxNOT_FOUND) {
1101 std::string selected =
1102 m_net_view_choice->GetString(selection).ToStdString();
1106 if (m_net_address_tctrl->IsEnabled() &&
1107 m_net_address_tctrl->IsShownOnScreen()) {
1109 if (net_address) ok = CheckAddress(
this, *net_address);
1111 if (m_net_port_tctrl->IsEnabled() && m_net_port_tctrl->IsShownOnScreen()) {
1113 if (net_port) ok = ok && CheckPort(
this, *net_port);
1115 if (ok) m_on_edit_click(m_cp_original, m_new_mode,
true);
1118void ConnectionEditDialog::SetInitialSettings() {
1119 LoadSerialPorts(m_port_combo);
1126void ConnectionEditDialog::SetSelectedConnectionPanel(
1131 if (m_selected_conn_params && m_selected_conn_params->m_optionsPanel)
1132 m_selected_conn_params->m_optionsPanel->SetSelected(
false);
1135 m_selected_conn_params = panel->m_pConnectionParams;
1136 panel->SetSelected(
true);
1137 SetConnectionParams(m_selected_conn_params);
1138 m_remove_btn->Enable();
1139 m_remove_btn->Show();
1140 m_add_btn->Disable();
1141 m_conn_edit_statbox->SetLabel(_(
"Edit Selected Connection"));
1144 m_selected_conn_params =
nullptr;
1145 m_remove_btn->Disable();
1146 m_add_btn->Enable();
1148 m_conn_edit_statbox->SetLabel(
"");
1158void ConnectionEditDialog::SetPropsLabel(
const wxString& label) {
1159 m_conn_edit_statbox->SetLabel(label);
1166 conn->b_IsSetup =
false;
1167 m_conn_enabled = conn->bEnabled;
1171void ConnectionEditDialog::OnValChange(wxCommandEvent& event) {
event.Skip(); }
1173void ConnectionEditDialog::OnScanBtClick(wxCommandEvent& event) {
1177 m_bt_no_change_counter = 0;
1178 m_bt_last_result_count = 0;
1180 Bind(wxEVT_TIMER, &ConnectionEditDialog::OnBtScanTimer,
this,
1182 m_bt_scan_timer.Start(1000, wxTIMER_CONTINUOUS);
1183 g_Platform->startBluetoothScan();
1185 if (m_scan_bt_btn) {
1186 m_scan_bt_btn->SetLabel(_(
"Stop Scan"));
1191void ConnectionEditDialog::OnBtScanTimer(wxTimerEvent& event) {
1192 if (m_bt_scanning) {
1195 m_bt_scan_results = g_Platform->getBluetoothScanResults();
1197 m_bt_data_sources_choice->Clear();
1198 m_bt_data_sources_choice->Append(m_bt_scan_results[0]);
1201 while ((i + 1) < m_bt_scan_results.GetCount()) {
1202 wxString item1 = m_bt_scan_results[i] +
";";
1203 wxString item2 = m_bt_scan_results.Item(i + 1);
1204 m_bt_data_sources_choice->Append(item1 + item2);
1209 if (m_bt_scan_results.GetCount() > 1) {
1210 m_bt_data_sources_choice->SetSelection(1);
1215 if (m_bt_no_change_counter > 5) StopBtScan();
1217 if ((
int)m_bt_scan_results.GetCount() == m_bt_last_result_count)
1218 m_bt_no_change_counter++;
1220 m_bt_no_change_counter = 0;
1222 m_bt_last_result_count =
static_cast<int>(m_bt_scan_results.GetCount());
1225 if (m_bt_scanning >= 15) {
1232void ConnectionEditDialog::StopBtScan() {
1233 m_bt_scan_timer.Stop();
1235 g_Platform->stopBluetoothScan();
1239 if (m_scan_bt_btn) {
1240 m_scan_bt_btn->SetLabel(_(
"BT Scan"));
1241 m_scan_bt_btn->Enable();
1245void ConnectionEditDialog::OnConnValChange(wxCommandEvent& event) {
1246 m_is_conn_saved =
false;
1250void ConnectionEditDialog::OnTypeSerialSelected(wxCommandEvent& event) {
1251 OnConnValChange(event);
1252 SetNMEAFormToSerial();
1255void ConnectionEditDialog::OnTypeNetSelected(wxCommandEvent& event) {
1256 OnConnValChange(event);
1260void ConnectionEditDialog::OnTypeCANSelected(wxCommandEvent& event) {
1261 OnConnValChange(event);
1265void ConnectionEditDialog::OnTypeGPSSelected(wxCommandEvent& event) {
1266 OnConnValChange(event);
1270void ConnectionEditDialog::OnTypeBTSelected(wxCommandEvent& event) {
1271 OnConnValChange(event);
1275void ConnectionEditDialog::OnUploadFormatChange(wxCommandEvent& event) {
1276 if (event.GetEventObject() == m_garmin_upload_host_chkbox &&
1278 m_furuno_gp3x_chkbox->SetValue(
false);
1279 else if (event.GetEventObject() == m_furuno_gp3x_chkbox && event.IsChecked())
1280 m_garmin_upload_host_chkbox->SetValue(
false);
1282 OnConnValChange(event);
1286void ConnectionEditDialog::ShowTypeCommon(
bool visible) {
1287 m_type_serial_radiobtn->Show(visible);
1288 m_type_net_radiobtn->Show(visible);
1289#if defined(__linux__) && !defined(__ANDROID__) && !defined(__WXOSX__)
1290 m_type_can_radiobtn->Show(visible);
1292 if (m_type_internal_gps_radiobtn) m_type_internal_gps_radiobtn->Show(visible);
1293 if (m_type_internal_bt_radiobtn) m_type_internal_bt_radiobtn->Show(visible);
1296void ConnectionEditDialog::ShowNMEACommon(
bool visible) {
1297 bool advanced = m_advanced;
1298 m_input_chkbox->Show(visible);
1299 m_output_chkbox->Show(visible);
1301 m_out_filter_sizer->SetDimension(0, 0, 0, 0);
1302 m_in_filter_sizer->SetDimension(0, 0, 0, 0);
1303 m_connection_props_sizer->SetDimension(0, 0, 0, 0);
1304 m_conn_edit_statbox->SetLabel(
"");
1307 m_sk_check_discover_chkbox->Hide();
1308 m_sk_discover_btn->Hide();
1310 const bool bin_enable = (m_input_chkbox->IsChecked() && advanced);
1311 ShowInFilter(visible && bin_enable);
1312 const bool bout_enable = (m_output_chkbox->IsChecked() && advanced);
1313 ShowOutFilter(visible && bout_enable);
1315 m_is_nmea_params_shown = visible;
1318void ConnectionEditDialog::ShowNMEANet(
bool visible) {
1319 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1321 m_net_addr_text->Show(visible);
1322 m_net_address_tctrl->Show(visible);
1323 m_net_data_protocol_text->Show(visible);
1324 m_net_port_text->Show(visible);
1325 m_net_data_protocol_choice->Show(visible);
1326 m_net_port_tctrl->Show(visible);
1327 m_net_expert_chkbox->Show(visible);
1328 if (m_net_expert_chkbox->GetValue()) {
1329 m_net_comment_text->Show(visible);
1330 m_net_comment_tctrl->Show(visible);
1332 m_net_expert_box_text->Show(visible);
1333 m_net_type_choice_text->Show(visible);
1334 m_net_view_choice->Show(visible);
1335 m_garmin_host_chkbox->Hide();
1339void ConnectionEditDialog::ShowNMEASerial(
bool visible) {
1340 bool advanced = m_advanced;
1341 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1343 m_ser_baudrate_text->Show(visible);
1344 m_baud_rate_choice->Show(visible);
1345 m_ser_port_text->Show(visible);
1346 m_port_combo->Show(visible);
1347 m_ser_protocol_text->Show(visible);
1348 m_serial_protocol_choice->Show(visible);
1349 m_garmin_host_chkbox->Show(visible && advanced);
1350 m_ser_comment_text->Show(visible);
1351 m_serial_comment_tctrl->Show(visible);
1354void ConnectionEditDialog::ShowNMEAGPS(
bool visible) {
1355 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1357 m_sk_check_discover_chkbox->Hide();
1358 m_sk_discover_btn->Hide();
1359 m_output_chkbox->Hide();
1362void ConnectionEditDialog::ShowNMEACAN(
bool visible) {
1363 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1364 m_can_source_text->Show(visible);
1365 m_can_source_choice->Show(visible);
1366 if (visible && m_dlg_ok_btn && m_can_source_choice->IsEmpty())
1367 m_dlg_ok_btn->Enable(
false);
1370void ConnectionEditDialog::ShowNMEABT(
bool visible) {
1371 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1374 if (m_scan_bt_btn) m_scan_bt_btn->Show();
1375 if (m_bt_pairs_text) m_bt_pairs_text->Show();
1376 if (m_bt_data_sources_choice) {
1377 if (m_bt_data_sources_choice->GetCount() > 1)
1378 m_bt_data_sources_choice->SetSelection(1);
1379 m_bt_data_sources_choice->Show();
1382 if (m_scan_bt_btn) m_scan_bt_btn->Hide();
1383 if (m_bt_pairs_text) m_bt_pairs_text->Hide();
1384 if (m_bt_data_sources_choice) m_bt_data_sources_choice->Hide();
1386 m_sk_check_discover_chkbox->Hide();
1387 m_sk_check_discover_chkbox->Hide();
1388 m_sk_discover_btn->Hide();
1389 m_output_stc_tctrl->Show(visible);
1390 m_output_stc_list_btn->Show(visible);
1391 m_output_chkbox->Show(visible);
1394void ConnectionEditDialog::SetNMEAFormToSerial() {
1395 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1397 ShowNMEACommon(
true);
1401 ShowNMEASerial(
true);
1403 SetDSFormRWStates();
1407void ConnectionEditDialog::SetNMEAFormToNet() {
1408 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1410 ShowNMEACommon(
true);
1414 ShowNMEASerial(
false);
1416 SetDSFormRWStates();
1421void ConnectionEditDialog::SetNMEAFormToCAN() {
1422 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1424 ShowNMEACommon(
false);
1428 ShowNMEASerial(
false);
1430 m_in_filter_sizer->Show(
false);
1431 m_out_filter_sizer->Show(
false);
1432 SetDSFormRWStates();
1437void ConnectionEditDialog::SetNMEAFormToGPS() {
1438 ShowNMEACommon(
true);
1442 ShowNMEASerial(
false);
1447 SetDSFormRWStates();
1451void ConnectionEditDialog::SetNMEAFormToBT() {
1452 ShowNMEACommon(
true);
1456 ShowNMEASerial(
false);
1461 SetDSFormRWStates();
1465void ConnectionEditDialog::ClearNMEAForm() {
1466 ShowNMEACommon(
false);
1470 ShowNMEASerial(
false);
1481void ConnectionEditDialog::SetDSFormOptionVizStates() {
1482 bool advanced = m_advanced;
1483 m_collapse_box->ShowItems(
true);
1484 m_input_chkbox->Show();
1485 m_output_chkbox->Show();
1487 ShowInFilter(advanced);
1488 ShowOutFilter(advanced);
1492 m_sk_server_status_text->Show(advanced);
1494 if (m_type_serial_radiobtn->GetValue()) {
1495 m_sk_check_discover_chkbox->Hide();
1496 m_sk_discover_btn->Hide();
1497 m_sk_server_status_text->Hide();
1498 bool n0183ctlenabled =
1499 (DataProtocol)m_serial_protocol_choice->GetSelection() ==
1500 DataProtocol::PROTO_NMEA0183;
1501 bool n2kctlenabled =
1502 (DataProtocol)m_serial_protocol_choice->GetSelection() ==
1503 DataProtocol::PROTO_NMEA2000;
1504 if (!n0183ctlenabled) {
1505 if (n2kctlenabled) {
1506 m_input_chkbox->Show();
1507 m_output_chkbox->Show();
1509 m_input_chkbox->Hide();
1510 m_output_chkbox->Hide();
1512 ShowOutFilter(
false);
1513 ShowInFilter(
false);
1514 m_net_data_protocol_text->Hide();
1515 m_net_data_protocol_choice->Hide();
1516 m_net_expert_chkbox->Hide();
1517 m_net_type_choice_text->Hide();
1518 m_net_view_choice->Hide();
1519 m_net_expert_chkbox->Hide();
1520 m_net_type_choice_text->Hide();
1521 m_net_expert_box_text->Hide();
1522 m_net_view_choice->Hide();
1524 m_input_chkbox->Show();
1525 m_input_chkbox->Enable();
1527 ShowInFilter(m_input_chkbox->IsChecked() && advanced);
1528 ShowOutFilter(m_output_chkbox->IsChecked() && advanced);
1530 m_garmin_host_chkbox->Show(m_input_chkbox->IsChecked() && advanced);
1534 if (m_type_internal_gps_radiobtn &&
1535 m_type_internal_gps_radiobtn->GetValue()) {
1536 m_sk_check_discover_chkbox->Hide();
1537 m_sk_discover_btn->Hide();
1538 m_sk_server_status_text->Hide();
1539 m_output_chkbox->Hide();
1540 m_input_chkbox->Hide();
1541 ShowOutFilter(
false);
1542 ShowInFilter(
false);
1543 m_garmin_host_chkbox->Hide();
1544 m_collapse_box->ShowItems(
false);
1547 if (m_type_internal_bt_radiobtn && m_type_internal_bt_radiobtn->GetValue()) {
1548 m_sk_check_discover_chkbox->Hide();
1549 m_sk_discover_btn->Hide();
1550 m_sk_server_status_text->Hide();
1552 ShowInFilter(m_input_chkbox->IsChecked() && advanced);
1553 ShowOutFilter(m_output_chkbox->IsChecked() && advanced);
1556 if (m_type_can_radiobtn->GetValue()) {
1557 m_sk_check_discover_chkbox->Hide();
1558 m_sk_discover_btn->Hide();
1559 m_sk_server_status_text->Hide();
1560 m_garmin_host_chkbox->Hide();
1561 m_input_chkbox->Hide();
1562 m_output_chkbox->Hide();
1564 ShowInFilter(
false);
1565 ShowOutFilter(
false);
1567 m_net_data_protocol_text->Hide();
1568 m_net_data_protocol_choice->Hide();
1569 m_net_expert_chkbox->Hide();
1570 m_net_type_choice_text->Hide();
1571 m_net_expert_box_text->Hide();
1572 m_net_view_choice->Hide();
1573 m_collapse_box->Show(
false);
1576 if (m_type_net_radiobtn->GetValue()) {
1577 if ((DataProtocol)m_net_data_protocol_choice->GetSelection() ==
1578 DataProtocol::PROTO_NMEA2000) {
1579 ShowInFilter(
false);
1580 ShowOutFilter(
false);
1582 if ((DataProtocol)m_net_data_protocol_choice->GetSelection() ==
1583 DataProtocol::PROTO_NMEA0183) {
1584 ShowInFilter(m_input_chkbox->IsChecked() && advanced);
1585 ShowOutFilter(m_output_chkbox->IsChecked() && advanced);
1594void ConnectionEditDialog::SetDSFormRWStates() {
1595 if (m_type_serial_radiobtn->GetValue()) {
1596 m_input_chkbox->Enable(
true);
1597 m_output_chkbox->Enable(
true);
1599 ShowOutFilter(m_output_chkbox->IsChecked());
1601 m_o_accept_radiobtn->Enable(
true);
1602 m_o_ignore_radiobtn->Enable(
true);
1603 m_output_stc_list_btn->Enable(
true);
1605 SetDSFormOptionVizStates();
1608void ConnectionEditDialog::ShowInFilter(
bool bshow) {
1609 m_in_filter_sizer->GetStaticBox()->Show(bshow);
1610 m_accept_radiobtn->Show(bshow);
1611 m_ignore_radiobtn->Show(bshow);
1612 m_input_stc_tctrl->Show(bshow);
1613 m_input_stc_list_btn->Show(bshow);
1616void ConnectionEditDialog::ShowOutFilter(
bool bshow) {
1617 m_out_filter_sizer->GetStaticBox()->Show(bshow);
1618 m_o_accept_radiobtn->Show(bshow);
1619 m_o_ignore_radiobtn->Show(bshow);
1620 m_output_stc_tctrl->Show(bshow);
1621 m_output_stc_list_btn->Show(bshow);
1626 SetConnectionParams(cp);
1630 const std::string view = NetViewByConnection(cp);
1631 auto found = std::find(kBasicNetViews.begin(), kBasicNetViews.end(), view);
1632 m_net_expert_chkbox->SetValue(found == kBasicNetViews.end());
1633 m_net_view_choice->Clear();
1634 if (found == kBasicNetViews.end())
1635 for (
const auto& v : kAdvancedNetViews) m_net_view_choice->Append(v);
1637 for (
const auto& v : kBasicNetViews) m_net_view_choice->Append(v);
1638 std::vector<std::string> all_views = kBasicNetViews;
1639 for (
const auto& v : kAdvancedNetViews) all_views.push_back(v);
1640 found = std::find(all_views.begin(), all_views.end(), view);
1641 if (found != all_views.end()) {
1642 int select_ix = m_net_view_choice->FindString(*found);
1643 if (select_ix != wxNOT_FOUND) m_net_view_choice->SetSelection(select_ix);
1645 if (wxNOT_FOUND == m_port_combo->FindString(cp->Port))
1646 m_port_combo->Append(cp->Port);
1648 m_port_combo->Select(m_port_combo->FindString(cp->Port));
1650 m_garmin_host_chkbox->SetValue(cp->Garmin);
1651 m_sk_check_discover_chkbox->SetValue(cp->AutoSKDiscover);
1652 if (view == kUdpReceive || view == kUdpInput) {
1653 m_input_chkbox->SetValue(
true);
1654 m_input_chkbox->Disable();
1655 m_output_chkbox->SetValue(
false);
1656 m_output_chkbox->Disable();
1658 m_input_chkbox->SetValue(cp->IOSelect != DS_TYPE_OUTPUT);
1659 m_output_chkbox->SetValue(cp->IOSelect != DS_TYPE_INPUT);
1662 if (cp->InputSentenceListType == WHITELIST)
1663 m_accept_radiobtn->SetValue(
true);
1665 m_ignore_radiobtn->SetValue(
true);
1666 if (cp->OutputSentenceListType == WHITELIST)
1667 m_o_accept_radiobtn->SetValue(
true);
1669 m_o_ignore_radiobtn->SetValue(
true);
1670 m_input_stc_tctrl->SetValue(StringArrayToString(cp->InputSentenceList));
1671 m_output_stc_tctrl->SetValue(StringArrayToString(cp->OutputSentenceList));
1672 m_baud_rate_choice->Select(
1673 m_baud_rate_choice->FindString(wxString::Format(
"%d", cp->Baudrate)));
1674 m_serial_protocol_choice->Select(cp->Protocol);
1676 if (net_address) m_net_address_tctrl->ChangeValue(cp->NetworkAddress);
1678 m_net_data_protocol_choice->Select(cp->Protocol);
1680 if (cp->NetworkPort == 0)
1681 m_net_port_tctrl->ChangeValue(
"");
1683 m_net_port_tctrl->ChangeValue(std::to_string(cp->NetworkPort));
1685 if (cp->Type == SERIAL) {
1686 m_type_serial_radiobtn->SetValue(
true);
1687 SetNMEAFormToSerial();
1688 SetNMEAFormForSerialProtocol();
1689 }
else if (cp->Type == NETWORK) {
1690 m_type_net_radiobtn->SetValue(
true);
1692 }
else if (cp->Type == SOCKETCAN) {
1693 m_type_can_radiobtn->SetValue(
true);
1695 }
else if (cp->Type == INTERNAL_GPS) {
1696 if (m_type_internal_gps_radiobtn)
1697 m_type_internal_gps_radiobtn->SetValue(
true);
1699 }
else if (cp->Type == INTERNAL_BT) {
1700 if (m_type_internal_bt_radiobtn)
1701 m_type_internal_bt_radiobtn->SetValue(
true);
1705 wxString bts = cp->NetworkAddress +
";" + cp->GetPortStr();
1706 m_bt_data_sources_choice->Clear();
1707 m_bt_data_sources_choice->Append(bts);
1708 m_bt_data_sources_choice->SetSelection(0);
1713 if (cp->Type == SERIAL) {
1714 m_serial_comment_tctrl->SetValue(cp->UserComment);
1715 }
else if (cp->Type == NETWORK) {
1716 m_net_comment_tctrl->SetValue(cp->UserComment);
1717 ConfigureControlsForView(view);
1718 OnExpertModeChange();
1721 m_auth_token_tctrl->SetValue(cp->AuthToken);
1723 m_conn_enabled = cp->bEnabled;
1726 m_is_conn_saved =
true;
1729void ConnectionEditDialog::SetDefaultConnectionParams() {
1730 if (m_port_combo && !m_port_combo->IsListEmpty()) {
1731 m_port_combo->Select(0);
1732 m_port_combo->SetValue(wxEmptyString);
1734 m_garmin_host_chkbox->SetValue(
false);
1735 m_input_chkbox->SetValue(
true);
1736 m_output_chkbox->SetValue(
false);
1737 m_accept_radiobtn->SetValue(
true);
1738 m_o_accept_radiobtn->SetValue(
true);
1739 m_input_stc_tctrl->SetValue(wxEmptyString);
1740 m_output_stc_tctrl->SetValue(wxEmptyString);
1741 m_baud_rate_choice->Select(m_baud_rate_choice->FindString(
"4800"));
1744 m_net_comment_tctrl->SetValue(wxEmptyString);
1745 m_serial_comment_tctrl->SetValue(wxEmptyString);
1746 m_auth_token_tctrl->SetValue(wxEmptyString);
1751 bool bserial =
true;
1761 if (m_type_internal_gps_radiobtn) {
1762 m_type_internal_gps_radiobtn->SetValue(
true);
1765 m_type_net_radiobtn->SetValue(
true);
1769 m_type_serial_radiobtn->SetValue(bserial);
1770 m_type_net_radiobtn->SetValue(!bserial);
1771 bserial ? SetNMEAFormToSerial() : SetNMEAFormToNet();
1772 m_type_can_radiobtn->SetValue(
false);
1775 m_conn_enabled =
true;
1778 m_is_conn_saved =
false;
1781void ConnectionEditDialog::LayoutDialog() {
1782 m_net_props_sizer->Layout();
1783 m_ser_props_sizer->Layout();
1786 GetSizer()->Layout();
1789void ConnectionEditDialog::UpdateSourceList(
bool bResort) {
1790 for (
auto* cp : TheConnectionParams()) {
1792 if (panel) panel->Update(cp);
1795 m_scroll_win_connections->Layout();
1798void ConnectionEditDialog::OnSelectDatasource(wxListEvent& event) {
1799 SetConnectionParams(TheConnectionParams()[event.GetData()]);
1800 m_remove_btn->Enable();
1801 m_remove_btn->Show();
1805void ConnectionEditDialog::OnDiscoverButton(wxCommandEvent& event) {
1809 std::string serviceIdent =
1810 std::string(
"_signalk-ws._tcp.local.");
1812 g_Platform->ShowBusySpinner();
1814 if (SignalKDataStream::DiscoverSKServer(serviceIdent, ip, port,
1817 m_tNetAddress->SetValue(ip);
1818 m_tNetPort->SetValue(wxString::Format(
"%i", port));
1819 UpdateDiscoverStatus(_(
"Signal K server available."));
1821 UpdateDiscoverStatus(_(
"Signal K server not found."));
1823 g_Platform->HideBusySpinner();
1828void ConnectionEditDialog::UpdateDiscoverStatus(
const wxString& stat) {
1829 m_sk_server_status_text->SetLabel(stat);
1832void ConnectionEditDialog::OnBtnIStcs(wxCommandEvent& event) {
1833 const ListType type = m_accept_radiobtn->GetValue() ? WHITELIST : BLACKLIST;
1834 const wxArrayString list =
1835 wxStringTokenize(m_input_stc_tctrl->GetValue(),
",");
1838 if (dlg.ShowModal() == wxID_OK)
1839 m_input_stc_tctrl->SetValue(dlg.GetSentences());
1842void ConnectionEditDialog::OnBtnOStcs(wxCommandEvent& event) {
1843 const ListType type = m_o_accept_radiobtn->GetValue() ? WHITELIST : BLACKLIST;
1844 const wxArrayString list =
1845 wxStringTokenize(m_output_stc_tctrl->GetValue(),
",");
1848 if (dlg.ShowModal() == wxID_OK)
1849 m_output_stc_tctrl->SetValue(dlg.GetSentences());
1852void ConnectionEditDialog::OnNetProtocolSelected(wxCommandEvent& event) {
1853 SetDSFormRWStates();
1855 OnConnValChange(event);
1858void ConnectionEditDialog::OnRbAcceptInput(wxCommandEvent& event) {
1859 OnConnValChange(event);
1861void ConnectionEditDialog::OnRbIgnoreInput(wxCommandEvent& event) {
1862 OnConnValChange(event);
1865void ConnectionEditDialog::OnRbOutput(wxCommandEvent& event) {
1866 OnConnValChange(event);
1869void ConnectionEditDialog::OnCbInput(wxCommandEvent& event) {
1870 const bool checked = m_input_chkbox->IsChecked();
1871 ShowInFilter(checked);
1872 SetDSFormRWStates();
1874 OnConnValChange(event);
1877void ConnectionEditDialog::OnCbOutput(wxCommandEvent& event) {
1878 OnConnValChange(event);
1879 const bool is_output_enabled = m_output_chkbox->IsChecked();
1880 ShowOutFilter(is_output_enabled);
1882 int selection = m_net_view_choice->GetSelection();
1884 if (selection != wxNOT_FOUND)
1885 view = m_net_view_choice->GetString(selection).ToStdString();
1886 if (view == kUdpInput || view == kMulticastServer) {
1887 if (is_output_enabled) {
1889 NetworkProtocol proto = UDP;
1890 for (
auto* cp : TheConnectionParams()) {
1891 if (cp->NetProtocol == proto &&
1892 cp->NetworkPort == wxAtoi(m_net_port_tctrl->GetValue()) &&
1893 cp->IOSelect == DS_TYPE_INPUT) {
1898 _(
"There is an enabled UDP input connection that uses the "
1901 << _(
"Please apply a filter on both connections to avoid a "
1906 _(
"There is a disabled UDP Input connection that uses the "
1909 << _(
"If you enable that input please apply a filter on both "
1910 "connections to avoid a feedback loop.");
1913 << _(
"Or consider using a different data port for one of them");
1915 OCPNMessageBox(
this, mes, _(
"OpenCPN Warning"),
1916 wxOK | wxICON_EXCLAMATION, 60);
1918 OCPNMessageBox(
this, mes, _(
"OpenCPN info"),
1919 wxOK | wxICON_INFORMATION, 60);
1925 if (view == kUdpReceive || view == kUdpInput) {
1926 m_net_address_tctrl->Hide();
1927 m_net_address_tctrl->Disable();
1928 m_net_addr_text->Hide();
1929 m_net_addr_text->Disable();
1931 SetDSFormRWStates();
1936void ConnectionEditDialog::OnCollapsedToggle(
bool collapsed) {
1937 m_advanced = !collapsed;
1938 if (m_type_net_radiobtn->GetValue())
1939 SetNMEAFormForNetProtocol();
1941 SetNMEAFormForSerialProtocol();
1946void ConnectionEditDialog::OnCbAdvanced(wxCommandEvent& event) {
1947 if (m_type_net_radiobtn->GetValue())
1948 SetNMEAFormForNetProtocol();
1950 SetNMEAFormForSerialProtocol();
1954void ConnectionEditDialog::SetNMEAFormForSerialProtocol() {
1955 bool n0183ctlenabled =
1956 (DataProtocol)m_serial_protocol_choice->GetSelection() ==
1957 DataProtocol::PROTO_NMEA0183;
1958 bool advanced = m_advanced;
1959 ShowNMEACommon(n0183ctlenabled && advanced);
1960 m_garmin_host_chkbox->Show(n0183ctlenabled && advanced);
1962 SetDSFormRWStates();
1966void ConnectionEditDialog::SetNMEAFormForNetProtocol() {
1967 bool n0183ctlenabled =
1968 (DataProtocol)m_net_data_protocol_choice->GetSelection() ==
1969 DataProtocol::PROTO_NMEA0183;
1970 bool advanced = m_advanced;
1971 ShowNMEACommon(n0183ctlenabled && advanced);
1972 m_garmin_host_chkbox->Show(n0183ctlenabled && advanced);
1974 SetDSFormRWStates();
1978void ConnectionEditDialog::OnProtocolChoice(wxCommandEvent& event) {
1979 if (m_type_net_radiobtn->GetValue())
1980 SetNMEAFormForNetProtocol();
1982 SetNMEAFormForSerialProtocol();
1983 OnConnValChange(event);
1988 UpdateConnectionParamsFromControls(pConnectionParams);
1989 return pConnectionParams;
1994 pConnectionParams->Valid =
true;
1995 int selection = m_net_view_choice->GetSelection();
1996 if (selection != wxNOT_FOUND) {
1997 std::string s = m_net_view_choice->GetString(selection).ToStdString();
1999 if (m_type_serial_radiobtn->GetValue())
2000 pConnectionParams->Type = SERIAL;
2001 else if (m_type_net_radiobtn->GetValue())
2002 pConnectionParams->Type = NETWORK;
2003 else if (m_type_internal_gps_radiobtn &&
2004 m_type_internal_gps_radiobtn->GetValue())
2005 pConnectionParams->Type = INTERNAL_GPS;
2006 else if (m_type_internal_bt_radiobtn &&
2007 m_type_internal_bt_radiobtn->GetValue())
2008 pConnectionParams->Type = INTERNAL_BT;
2009 else if (m_type_can_radiobtn && m_type_can_radiobtn->GetValue())
2010 pConnectionParams->Type = SOCKETCAN;
2012 if (m_type_net_radiobtn->GetValue()) {
2014 pConnectionParams->LastNetworkAddress = pConnectionParams->NetworkAddress;
2015 pConnectionParams->LastNetworkPort = pConnectionParams->NetworkPort;
2016 pConnectionParams->LastNetProtocol = pConnectionParams->NetProtocol;
2017 pConnectionParams->LastDataProtocol = pConnectionParams->Protocol;
2019 pConnectionParams->NetworkAddress =
2020 m_net_address_tctrl->GetValue().Trim(
false).Trim(
true);
2021 pConnectionParams->NetworkPort =
2022 wxAtoi(m_net_port_tctrl->GetValue().Trim(
false).Trim(
true));
2023 int net_select = m_net_view_choice->GetSelection();
2024 std::string net_type;
2025 if (net_select != wxNOT_FOUND)
2026 net_type = m_net_view_choice->GetString(net_select).ToStdString();
2027 if (net_type == kTcpClient || net_type == kTcpServer ||
2028 net_type == kTcpDevice) {
2029 pConnectionParams->NetProtocol = TCP;
2030 pConnectionParams->Protocol =
2031 static_cast<DataProtocol
>(m_net_data_protocol_choice->GetSelection());
2032 }
else if (net_type == kUdpSend || net_type == kUdpInput ||
2033 net_type == kUdpReceive || net_type == kMulticastClient ||
2034 net_type == kMulticastServer) {
2035 pConnectionParams->NetProtocol = UDP;
2036 pConnectionParams->Protocol =
2037 static_cast<DataProtocol
>(m_net_data_protocol_choice->GetSelection());
2038 }
else if (net_type == kGpsdClient || net_type == kGpsdDevice) {
2039 pConnectionParams->NetProtocol = GPSD;
2040 }
else if (net_type == kSignalkClient || net_type == kSignalkDevice) {
2041 pConnectionParams->NetProtocol = SIGNALK;
2043 pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2045 pConnectionParams->is_server =
2046 net_type == kTcpServer || net_type == kUdpInput ||
2047 net_type == kUdpReceive || net_type == kMulticastServer;
2049 if (m_type_serial_radiobtn->GetValue())
2050 pConnectionParams->Protocol =
2051 (DataProtocol)m_serial_protocol_choice->GetSelection();
2052 else if (m_type_net_radiobtn->GetValue())
2053 pConnectionParams->Protocol =
2054 (DataProtocol)m_net_data_protocol_choice->GetSelection();
2056 pConnectionParams->Baudrate =
2057 wxAtoi(m_baud_rate_choice->GetStringSelection());
2058 pConnectionParams->ChecksumCheck =
true;
2059 pConnectionParams->AutoSKDiscover = m_sk_check_discover_chkbox->GetValue();
2060 pConnectionParams->Garmin = m_garmin_host_chkbox->GetValue();
2061 pConnectionParams->InputSentenceList =
2062 wxStringTokenize(m_input_stc_tctrl->GetValue(),
",");
2063 if (m_accept_radiobtn->GetValue())
2064 pConnectionParams->InputSentenceListType = WHITELIST;
2066 pConnectionParams->InputSentenceListType = BLACKLIST;
2067 if (m_input_chkbox->GetValue()) {
2068 if (m_output_chkbox->GetValue()) {
2069 pConnectionParams->IOSelect = DS_TYPE_INPUT_OUTPUT;
2071 pConnectionParams->IOSelect = DS_TYPE_INPUT;
2074 pConnectionParams->IOSelect = DS_TYPE_OUTPUT;
2076 pConnectionParams->OutputSentenceList =
2077 wxStringTokenize(m_output_stc_tctrl->GetValue(),
",");
2078 if (m_o_accept_radiobtn->GetValue())
2079 pConnectionParams->OutputSentenceListType = WHITELIST;
2081 pConnectionParams->OutputSentenceListType = BLACKLIST;
2082 pConnectionParams->Port = m_port_combo->GetValue().BeforeFirst(
' ');
2083#if defined(__linux__) && !defined(__ANDROID__)
2084 if (pConnectionParams->Type == SERIAL)
2088 if (m_type_can_radiobtn && m_type_can_radiobtn->GetValue())
2089 pConnectionParams->Protocol = PROTO_NMEA2000;
2091 pConnectionParams->bEnabled = m_conn_enabled;
2092 pConnectionParams->b_IsSetup =
false;
2094 if (pConnectionParams->Type == INTERNAL_GPS) {
2095 pConnectionParams->NetworkAddress =
"";
2096 pConnectionParams->NetworkPort = 0;
2097 pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2098 pConnectionParams->Baudrate = 0;
2099 pConnectionParams->Port =
"Internal GPS";
2102 if (pConnectionParams->Type == INTERNAL_BT) {
2103 wxString parms = m_bt_data_sources_choice->GetStringSelection();
2104 wxStringTokenizer tkz(parms,
";");
2105 wxString name = tkz.GetNextToken();
2106 wxString mac = tkz.GetNextToken();
2108 pConnectionParams->NetworkAddress = name;
2109 pConnectionParams->Port = mac;
2110 pConnectionParams->NetworkPort = 0;
2111 pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2112 pConnectionParams->Baudrate = 0;
2116 if (pConnectionParams->Type == SOCKETCAN) {
2117 pConnectionParams->NetworkAddress =
"";
2118 pConnectionParams->NetworkPort = 0;
2119 pConnectionParams->NetProtocol = PROTO_UNDEFINED;
2120 pConnectionParams->Baudrate = 0;
2121 pConnectionParams->socketCAN_port =
2122 m_can_source_choice->GetString(m_can_source_choice->GetSelection());
2124 if (pConnectionParams->Type == SERIAL) {
2125 pConnectionParams->UserComment = m_serial_comment_tctrl->GetValue();
2126 }
else if (pConnectionParams->Type == NETWORK) {
2127 pConnectionParams->UserComment = m_net_comment_tctrl->GetValue();
2129 pConnectionParams->AuthToken = m_auth_token_tctrl->GetValue();
2131 return pConnectionParams;
2134void ConnectionEditDialog::OnPriorityDialog(wxCommandEvent& event) {
2139void ConnectionEditDialog::ConnectControls() {
2141 m_type_serial_radiobtn->Connect(
2142 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2143 wxCommandEventHandler(ConnectionEditDialog::OnTypeSerialSelected),
2145 m_type_net_radiobtn->Connect(
2146 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2147 wxCommandEventHandler(ConnectionEditDialog::OnTypeNetSelected),
nullptr,
2149 m_type_can_radiobtn->Connect(
2150 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2151 wxCommandEventHandler(ConnectionEditDialog::OnTypeCANSelected),
nullptr,
2153 if (m_type_internal_gps_radiobtn)
2154 m_type_internal_gps_radiobtn->Connect(
2155 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2156 wxCommandEventHandler(ConnectionEditDialog::OnTypeGPSSelected),
nullptr,
2158 if (m_type_internal_bt_radiobtn)
2159 m_type_internal_bt_radiobtn->Connect(
2160 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2161 wxCommandEventHandler(ConnectionEditDialog::OnTypeBTSelected),
nullptr,
2164 m_net_data_protocol_choice->Connect(
2165 wxEVT_COMMAND_CHOICE_SELECTED,
2166 wxCommandEventHandler(ConnectionEditDialog::OnProtocolChoice),
nullptr,
2168 m_serial_protocol_choice->Connect(
2169 wxEVT_COMMAND_CHOICE_SELECTED,
2170 wxCommandEventHandler(ConnectionEditDialog::OnProtocolChoice),
nullptr,
2174 m_input_chkbox->Connect(
2175 wxEVT_COMMAND_CHECKBOX_CLICKED,
2176 wxCommandEventHandler(ConnectionEditDialog::OnCbInput),
nullptr,
this);
2177 m_output_chkbox->Connect(
2178 wxEVT_COMMAND_CHECKBOX_CLICKED,
2179 wxCommandEventHandler(ConnectionEditDialog::OnCbOutput),
nullptr,
this);
2182 m_scan_bt_btn->Connect(
2183 wxEVT_COMMAND_BUTTON_CLICKED,
2184 wxCommandEventHandler(ConnectionEditDialog::OnScanBtClick),
nullptr,
2187 m_input_stc_list_btn->Connect(
2188 wxEVT_COMMAND_BUTTON_CLICKED,
2189 wxCommandEventHandler(ConnectionEditDialog::OnBtnIStcs),
nullptr,
this);
2192 m_output_stc_list_btn->Connect(
2193 wxEVT_COMMAND_BUTTON_CLICKED,
2194 wxCommandEventHandler(ConnectionEditDialog::OnBtnOStcs),
nullptr,
this);
2197SentenceListDlg::SentenceListDlg(wxWindow* parent, FilterDirection dir,
2198 ListType type,
const wxArrayString& list)
2199 : wxDialog(parent, wxID_ANY, _(
"Sentence Filter"), wxDefaultPosition,
2203 m_sentences(NMEA0183().GetRecognizedArray()) {
2205 auto* mainSizer =
new wxBoxSizer(wxVERTICAL);
2206 auto* secondSizer =
new wxBoxSizer(wxHORIZONTAL);
2207 auto* pclbBox =
new wxStaticBox(
this, wxID_ANY, GetBoxLabel());
2208 auto* stcSizer =
new wxStaticBoxSizer(pclbBox, wxVERTICAL);
2209 m_sentences_clb =
new wxCheckListBox(
this, wxID_ANY, wxDefaultPosition,
2210 wxDefaultSize, m_sentences);
2211 auto* btnEntrySizer =
new wxBoxSizer(wxVERTICAL);
2212 auto* btnCheckAll =
new wxButton(
this, wxID_ANY, _(
"Select All"));
2213 auto* btnClearAll =
new wxButton(
this, wxID_ANY, _(
"Clear All"));
2214 auto* btnAdd =
new wxButton(
this, wxID_ANY, _(
"Add"));
2215 m_del_btn =
new wxButton(
this, wxID_ANY, _(
"Delete"));
2216 m_del_btn->Disable();
2217 auto* btnSizer =
new wxStdDialogButtonSizer();
2218 auto* btnOK =
new wxButton(
this, wxID_OK);
2219 auto* btnCancel =
new wxButton(
this, wxID_CANCEL, _(
"Cancel"));
2221 secondSizer->Add(stcSizer, 1, wxALL | wxEXPAND, 5);
2222 stcSizer->Add(m_sentences_clb, 1, wxALL | wxEXPAND, 5);
2223 btnEntrySizer->Add(btnCheckAll, 0, wxALL, 5);
2224 btnEntrySizer->Add(btnClearAll, 0, wxALL, 5);
2225 btnEntrySizer->AddSpacer(1);
2226 btnEntrySizer->Add(btnAdd, 0, wxALL, 5);
2227 btnEntrySizer->Add(m_del_btn, 0, wxALL, 5);
2228 secondSizer->Add(btnEntrySizer, 0, wxALL | wxEXPAND, 5);
2229 mainSizer->Add(secondSizer, 1, wxEXPAND, 5);
2230 btnSizer->AddButton(btnOK);
2231 btnSizer->AddButton(btnCancel);
2232 btnSizer->Realize();
2233 mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
2235 SetSizer(mainSizer);
2236 mainSizer->SetSizeHints(
this);
2239 btnAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2240 wxCommandEventHandler(SentenceListDlg::OnAddClick),
nullptr,
2242 m_del_btn->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2243 wxCommandEventHandler(SentenceListDlg::OnDeleteClick),
2245 m_sentences_clb->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
2246 wxCommandEventHandler(SentenceListDlg::OnCLBSelect),
2248 btnCheckAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2249 wxCommandEventHandler(SentenceListDlg::OnCheckAllClick),
2251 btnClearAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2252 wxCommandEventHandler(SentenceListDlg::OnClearAllClick),
2257wxString SentenceListDlg::GetBoxLabel()
const {
2258 if (m_dir == FILTER_OUTPUT)
2259 return m_type == WHITELIST ? _(
"Transmit sentences") : _(
"Drop sentences");
2261 return m_type == WHITELIST ? _(
"Accept only sentences")
2262 : _(
"Ignore sentences");
2265void SentenceListDlg::Populate(
const wxArrayString& list) {
2266 if (m_dir == FILTER_OUTPUT) {
2268 m_sentences.Add(g_TalkerIdText + wxString(
"RMB"));
2269 m_sentences.Add(g_TalkerIdText + wxString(
"RMC"));
2270 m_sentences.Add(g_TalkerIdText + wxString(
"APB"));
2271 m_sentences.Add(g_TalkerIdText + wxString(
"XTE"));
2273 m_sentences.Add(
"AIVDM");
2274 m_sentences.Add(
"AIVDO");
2275 m_sentences.Add(
"FRPOS");
2276 m_sentences.Add(g_TalkerIdText);
2277 m_sentences.Add(
"CD");
2279 m_sentences_clb->Clear();
2280 m_sentences_clb->InsertItems(m_sentences, 0);
2282 wxArrayString new_strings;
2283 if (list.Count() == 0) {
2284 for (
size_t i = 0; i < m_sentences_clb->GetCount(); ++i)
2285 m_sentences_clb->Check(i, m_type == WHITELIST);
2287 for (
size_t i = 0; i < list.Count(); ++i) {
2288 int item = m_sentences_clb->FindString(list[i]);
2289 if (item != wxNOT_FOUND)
2290 m_sentences_clb->Check(item);
2292 new_strings.Add(list[i]);
2294 if (new_strings.GetCount()) {
2295 m_sentences_clb->InsertItems(new_strings, m_sentences_clb->GetCount());
2296 for (
size_t i = 0; i < new_strings.GetCount(); ++i) {
2297 int item = m_sentences_clb->FindString(new_strings[i]);
2298 if (item != wxNOT_FOUND) m_sentences_clb->Check(item);
2304wxString SentenceListDlg::GetSentences() {
2305 wxArrayString retString;
2306 for (
size_t i = 0; i < m_sentences_clb->GetCount(); i++) {
2307 if (m_sentences_clb->IsChecked(i))
2308 retString.Add(m_sentences_clb->GetString(i));
2310 return StringArrayToString(retString);
2313void SentenceListDlg::OnCLBSelect(wxCommandEvent& e) {
2316 m_del_btn->Enable(m_sentences.Index(e.GetString()) == wxNOT_FOUND);
2319void SentenceListDlg::OnAddClick(wxCommandEvent& event) {
2321 androidDisableRotation();
2324 wxTextEntryDialog textdlg(
2326 _(
"Enter the NMEA sentence (2, 3 or 5 characters)\n or a valid REGEX "
2327 "expression (6 characters or longer)"),
2328 _(
"Enter the NMEA sentence"));
2330 textdlg.SetTextValidator(wxFILTER_ASCII);
2331 int result = textdlg.ShowModal();
2334 androidEnableRotation();
2337 if (result == wxID_CANCEL)
return;
2338 wxString stc = textdlg.GetValue();
2340 if (stc.Length() == 2 || stc.Length() == 3 || stc.Length() == 5) {
2341 m_sentences_clb->Append(stc);
2342 m_sentences_clb->Check(m_sentences_clb->FindString(stc));
2344 }
else if (stc.Length() < 2) {
2347 _(
"An NMEA sentence is generally 3 characters long (like RMC, GGA etc.)\n \
2348 It can also have a two letter prefix identifying the source, or TALKER, of the message.\n \
2349 The whole sentences then looks like GPGGA or AITXT.\n \
2350 You may filter out all the sentences with certain TALKER prefix (like GP, AI etc.).\n \
2351 The filter also accepts Regular Expressions (REGEX) with 6 or more characters. \n\n"),
2360 m_sentences_clb->Append(stc);
2361 m_sentences_clb->Check(m_sentences_clb->FindString(stc));
2364 OCPNMessageBox(
this, _(
"REGEX syntax error: \n") + stc,
2371void SentenceListDlg::OnDeleteClick(wxCommandEvent& event) {
2372 m_sentences_clb->Delete(m_sentences_clb->GetSelection());
2375void SentenceListDlg::OnClearAllClick(wxCommandEvent& event) {
2376 for (
size_t i = 0; i < m_sentences_clb->GetCount(); i++)
2377 m_sentences_clb->Check(i,
false);
2380void SentenceListDlg::OnCheckAllClick(wxCommandEvent& event) {
2381 for (
size_t i = 0; i < m_sentences_clb->GetCount(); i++)
2382 m_sentences_clb->Check(i,
true);
Dialog for editing connection parameters.
void OnConnectionTypeChange()
Initiate a network connection view with new data.
void RefreshAdvancedDetails()
Refresh visible states in a network connection view.
ConnectionParams * GetParamsFromControls()
Return parameters instance populated from UI elements owned by caller.
Panel for displaying and editing connection parameters.
Simple panel showing either an "expand" or "collapse" icon, state switches when clicked.
Custom event class for OpenCPN's notification system.
A wxTextCtrl with an initial italics help text, removed when user starts typing.
void SetHelp(const std::string &help_text)
Set help text, enter pristine state.
void RestoreHelp()
Restore help text to initial value, enter pristine state.
bool IsPristine() const
Return true if user has not entered anything.
Communication drivers factory and support.
Global variables stored in configuration file.
Panel for editing a connection.
Dialog and support code for editing a connection.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
General purpose GUI support.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
std::string trim(std::string s)
Strip possibly trailing and/or leading space characters in s.
PlugIn Object Definition/API.
Miscellaneous utilities, many of which string related.
Input priorities management dialog.
Serial ports support, notably enumeration.
wxArrayString * EnumerateSerialPorts(void)
Enumerate all serial ports.
Suspend/resume and new devices events exchange point.
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.