37#include <wx/tokenzr.h>
40#if defined(__linux__) && !defined(__ANDROID__)
45#include <sys/socket.h>
50#include "androidUTIL.h"
56#include "libgui/text_ctrl_w_help.h"
75#if wxCHECK_VERSION(3, 2, 0)
76#define _(s) wxGetTranslation(wxASCII_STR(s)).ToStdString()
78#define _(s) wxGetTranslation((s)).ToStdString()
81static const std::string kAddressDefaultHelp =
82 _(
"Enter IP address or hostname");
83static const std::string kAddressUdpHelp =
84 _(
"IP address or hostname, often 255.255.255.255");
85static const std::string kAddressMcastHelp =
86 _(
"Group address, usually 224.0.2.0 - 224.0.255.255");
87static const std::string kTcpDevice = _(
"Device using TCP");
88static const std::string kUdpReceive = _(
"Device sending UDP");
89static const std::string kUdpOutput = _(
"UDP send");
90static const std::string kGpsdDevice = _(
"Gpsd server");
91static const std::string kSignalkDevice = _(
"SignalK server");
92static const std::string kTcpClient = _(
"TCP client");
93static const std::string kUdpSend = _(
"Device(s) receiving UDP");
94static const std::string kGpsdClient = _(
"Gpsd client");
95static const std::string kSignalkClient = _(
"SignalK client");
96static const std::string kTcpServer = _(
"TCP Server");
97static const std::string kUdpInput = _(
"UDP Receive");
98static const std::string kMulticastServer = _(
"UDP Multicast Receive and Send");
99static const std::string kMulticastClient = _(
"UDP Multicast Send");
101static const std::vector<std::string> kBasicNetViews = {
102 kTcpDevice, kUdpReceive, kUdpSend, kGpsdDevice, kSignalkDevice};
104static const std::vector<std::string> kAdvancedNetViews = {
106 kTcpClient, kUdpInput, kUdpOutput, kGpsdClient,
107 kSignalkClient, kTcpServer, kMulticastClient, kMulticastServer};
109static wxString StringArrayToString(
const wxArrayString& arr) {
110 wxString ret = wxEmptyString;
111 for (
size_t i = 0; i < arr.Count(); i++) {
112 if (i > 0) ret.Append(
",");
119#if defined(__linux__) && !defined(__ANDROID__)
121std::vector<std::string> can_if_candidates;
122static int print_intf(
const struct intf_entry* entry,
void* arg) {
123 std::string iface = entry->intf_name;
124 if (entry->intf_type == 1 && iface.find(
"can") != std::string::npos) {
125 can_if_candidates.push_back(entry->intf_name);
131static bool IsAddressMultiCast(
const wxString& ip) {
132 wxArrayString bytes = wxSplit(ip,
'.');
133 if (bytes.size() != 4) {
136 unsigned long ipNum = (wxAtoi(bytes[0]) << 24) + (wxAtoi(bytes[1]) << 16) +
137 (wxAtoi(bytes[2]) << 8) + wxAtoi(bytes[3]);
138 unsigned long multicastStart = (224 << 24);
139 unsigned long multicastEnd = (239 << 24) + (255 << 16) + (255 << 8) + 255;
140 return ipNum >= multicastStart && ipNum <= multicastEnd;
143static bool IsAddressListener(
const std::string& address) {
144 return address.empty() || address ==
"0.0.0.0";
148static std::string GetChoiceSelection(
const wxChoice* choice) {
149 int selected = choice->GetSelection();
150 return choice->GetString(selected).ToStdString();
159 bool is_server = IsAddressListener(cp->network_address.ToStdString());
160 if (IsAddressMultiCast(cp->network_address))
161 return is_server ? kMulticastServer : kMulticastClient;
162 switch (cp->net_protocol) {
163 case NetworkProtocol::GPSD:
165 case NetworkProtocol::SIGNALK:
166 return kSignalkDevice;
167 case NetworkProtocol::UDP:
168 return is_server ? kUdpReceive : kUdpSend;
169 case NetworkProtocol::TCP:
170 return is_server ? kTcpServer : kTcpDevice;
172 wxLogWarning(
"Cannot deduce connection params view type");
178static wxArrayString GetAvailableSocketCANInterfaces() {
181#if defined(__linux__) && !defined(__ANDROID__)
182 can_if_candidates.clear();
184 if ((intf = intf_open()) ==
nullptr) {
185 wxLogWarning(
"Error opening interface list");
189 if (intf_loop(intf, print_intf,
nullptr) < 0) {
190 wxLogWarning(
"Error looping over interface list");
194 for (
const auto& iface : can_if_candidates) {
195 int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
201 struct ifreq if_request = {{0}};
202 strcpy(if_request.ifr_name, iface.c_str());
203 if (ioctl(sock, SIOCGIFINDEX, &if_request) < 0) {
208 struct sockaddr_can can_address = {0};
209 can_address.can_family = AF_CAN;
210 can_address.can_ifindex = if_request.ifr_ifindex;
211 if (ioctl(sock, SIOCGIFFLAGS, &if_request) < 0) {
214 if (if_request.ifr_flags & IFF_UP) {
224static void LoadSerialPorts(wxComboBox* box) {
228 [[nodiscard]]
static std::string GetKey(
const std::string& s) {
229 if (s.find(
"->") == std::string::npos)
return s;
234 bool operator()(
const std::string& lhs,
const std::string& rhs)
const {
235 return GetKey(lhs) < GetKey(rhs);
239 std::set<std::string, PortSorter> sorted_ports(port_sorter);
241 for (
size_t i = 0; i < ports->GetCount(); i++)
242 sorted_ports.insert((*ports)[i].ToStdString());
244 auto value = box->GetValue();
246 for (
auto& p : sorted_ports) box->Append(p);
247 if (!value.empty()) box->SetValue(value);
251 if (ctrl.
IsPristine() || ctrl.GetValue().empty()) {
252 auto dlg = wxMessageDialog(parent, _(
"Required field port is missing"),
253 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
259 port = std::stoi(ctrl.GetValue().ToStdString());
260 }
catch (std::logic_error&) {
261 auto dlg = wxMessageDialog(parent, _(
"Invalid port number"),
262 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
267 static const std::string kMsg =
268 _(R
"(Port numbers smaller than 1024 are reserved for use by the
269operating system and should normally not be used by OpenCPN)");
270 auto dlg = wxMessageDialog(parent, kMsg, _(
"OpenCPN warning"),
271 wxOK | wxICON_WARNING);
279 if (ctrl.
IsPristine() || ctrl.GetValue().empty()) {
280 auto dlg = wxMessageDialog(parent, _(
"Required field address is missing"),
281 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
290bool CheckIoDirections(wxWindow* parent,
const wxCheckBox* input,
291 const wxCheckBox* output) {
292 if (input->GetValue() || output->GetValue())
return true;
295 wxMessageDialog(parent, _(
"Either input or output must be checked"),
296 _(
"OpenCPN error"), wxOK | wxICON_ERROR);
302static void SetupProtocolChoice(wxChoice* choice) {
304 choice->Append(
"NMEA 0183");
305 choice->Append(
"NMEA 2000");
306 choice->SetSelection(0);
314ConnectionEditDialog::ConnectionEditDialog()
317ConnectionEditDialog::ConnectionEditDialog(
321 : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), 0,
323 m_scroll_win_connections(nullptr),
324 m_on_edit_click(std::move(_on_edit_click)),
325 m_selected_conn_params(nullptr),
326 m_cp_original(nullptr),
327 m_is_conn_saved(false),
329 m_is_nmea_params_shown(false),
332 m_conn_enabled(false),
333 m_accept_radiobtn(nullptr),
335 m_advanced_chkbox(nullptr),
336 m_aps_magnetic_chkbox(nullptr),
337 m_auth_token_tctrl(nullptr),
338 m_auth_token_text(nullptr),
339 m_baud_rate_choice(nullptr),
340 m_bt_data_sources_choice(nullptr),
341 m_bt_last_result_count(0),
342 m_bt_no_change_counter(0),
343 m_bt_pairs_text(nullptr),
345 m_bt_scan_timer(nullptr),
346 m_can_props_sizer(nullptr),
347 m_can_source_choice(nullptr),
348 m_can_source_text(nullptr),
349 m_collapse_box(nullptr),
350 m_connection_props_sizer(nullptr),
351 m_connections_sizer(nullptr),
352 m_conn_edit_statbox(nullptr),
353 m_dlg_buttons_apply_btn(nullptr),
354 m_dlg_buttons_cancel_btn(nullptr),
355 m_dlg_buttons_ok_btn(nullptr),
356 m_dlg_cancel_btn(nullptr),
357 m_dlg_ok_btn(nullptr),
358 m_filter_cog_sog_chkbox(nullptr),
359 m_filter_sec_tctrl(nullptr),
360 m_filter_sec_text(nullptr),
361 m_furuno_gp3x_chkbox(nullptr),
362 m_garmin_host_chkbox(nullptr),
363 m_garmin_upload_host_chkbox(nullptr),
364 m_ignore_radiobtn(nullptr),
365 m_in_filter_sizer(nullptr),
366 m_input_chkbox(nullptr),
367 m_input_stc_list_btn(nullptr),
368 m_input_stc_tctrl(nullptr),
369 m_net_address_tctrl(nullptr),
370 m_net_addr_text(nullptr),
371 m_net_comment_tctrl(nullptr),
372 m_net_comment_text(nullptr),
373 m_net_data_protocol_choice(nullptr),
374 m_net_data_protocol_text(nullptr),
375 m_net_expert_box_text(nullptr),
376 m_net_expert_chkbox(nullptr),
377 m_net_port_tctrl(nullptr),
378 m_net_port_text(nullptr),
379 m_net_props_sizer(nullptr),
380 m_net_view_choice(nullptr),
381 m_net_type_choice_text(nullptr),
382 m_o_accept_radiobtn(nullptr),
383 m_o_ignore_radiobtn(nullptr),
384 m_out_filter_sizer(nullptr),
385 m_output_chkbox(nullptr),
386 m_output_stc_list_btn(nullptr),
387 m_output_stc_tctrl(nullptr),
389 m_port_combo(nullptr),
390 m_precision_choice(nullptr),
391 m_precision_text(nullptr),
392 m_priority_choice(nullptr),
393 m_priority_dialog_btn(nullptr),
394 m_remove_btn(nullptr),
395 m_scan_bt_btn(nullptr),
396 m_ser_baudrate_text(nullptr),
397 m_ser_comment_text(nullptr),
398 m_serial_comment_tctrl(nullptr),
399 m_serial_protocol_choice(nullptr),
400 m_ser_port_text(nullptr),
401 m_ser_props_sizer(nullptr),
402 m_ser_protocol_text(nullptr),
403 m_sizer_box_btn(nullptr),
404 m_sk_check_discover_chkbox(nullptr),
405 m_sk_discover_btn(nullptr),
406 m_sk_server_status_text(nullptr),
407 m_std_dialog_btn_sizer(nullptr),
408 m_talker_id_text(nullptr),
409 m_type_can_radiobtn(nullptr),
410 m_type_internal_bt_radiobtn(nullptr),
411 m_type_internal_gps_radiobtn(nullptr),
412 m_type_net_radiobtn(nullptr),
413 m_type_serial_radiobtn(nullptr) {
417ConnectionEditDialog::~ConnectionEditDialog() =
default;
419void ConnectionEditDialog::AddOKCancelButtons() {
421 if (!m_std_dialog_btn_sizer) {
422 m_std_dialog_btn_sizer =
new wxStdDialogButtonSizer();
423 m_dlg_ok_btn =
new wxButton(
this, wxID_OK);
424 m_dlg_cancel_btn =
new wxButton(
this, wxID_CANCEL, _(
"Cancel"));
425 m_std_dialog_btn_sizer->AddButton(m_dlg_ok_btn);
426 m_std_dialog_btn_sizer->AddButton(m_dlg_cancel_btn);
427 m_std_dialog_btn_sizer->Realize();
428 GetSizer()->Add(m_std_dialog_btn_sizer, 0, wxALL | wxEXPAND, 5);
429 m_std_dialog_btn_sizer->Show(
true);
432 if (!m_std_dialog_btn_sizer) {
433 m_std_dialog_btn_sizer =
new wxStdDialogButtonSizer();
434 m_dlg_ok_btn =
new wxButton(
this, wxID_OK);
435 m_dlg_cancel_btn =
new wxButton(
this, wxID_CANCEL, _(
"Cancel"));
436 m_std_dialog_btn_sizer->AddSpacer(wxWindow::GetCharWidth());
437 m_std_dialog_btn_sizer->Add(m_dlg_ok_btn, 0, wxALL, 5);
438 m_std_dialog_btn_sizer->Add(m_dlg_cancel_btn, 0, wxALL, 5);
439 GetSizer()->Add(m_std_dialog_btn_sizer, 0, wxALL | wxEXPAND, 5);
443 m_dlg_ok_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
444 [&](wxCommandEvent& ev) { OnOKClick(); });
445 m_dlg_cancel_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
446 [&](wxCommandEvent& ev) { OnCancelClick(); });
448void ConnectionEditDialog::InitiateNewConnection() {
449 m_net_view_choice->Clear();
450 for (
const auto& view : kBasicNetViews) m_net_view_choice->Append(view);
451 m_net_view_choice->SetSelection(0);
452 m_net_expert_chkbox->SetValue(
false);
453 m_net_comment_tctrl->Hide();
454 m_net_comment_text->Hide();
457 m_net_address_tctrl->Show();
458 m_net_address_tctrl->Enable();
460 if (addr_ctrl) addr_ctrl->
SetHelp(kAddressDefaultHelp);
461 m_net_addr_text->Show();
462 SetupProtocolChoice(m_net_data_protocol_choice);
463 m_output_chkbox->SetValue(
false);
464 m_input_chkbox->SetValue(
true);
468 int selection = m_net_view_choice->GetSelection();
469 if (selection == wxNOT_FOUND)
return;
470 std::string view = GetChoiceSelection(m_net_view_choice);
471 ConfigureControlsForView(view);
472 OnExpertModeChange();
475void ConnectionEditDialog::ConfigureControlsForView(
const std::string& view) {
476 if (!m_type_net_radiobtn->GetValue())
return;
477 auto found = std::find(kBasicNetViews.begin(), kBasicNetViews.end(), view);
478 int selection = m_net_view_choice->GetSelection();
479 assert(selection != wxNOT_FOUND);
480 m_net_expert_chkbox->SetValue(found == kBasicNetViews.end());
481 m_net_address_tctrl->Enable();
482 auto net_addr_w_help =
dynamic_cast<TextCtrlWithHelp*
>(m_net_address_tctrl);
483 assert(net_addr_w_help);
485 assert(net_port_w_help);
486 m_net_addr_text->SetLabel(_(
"Server address"));
487 m_output_chkbox->Disable();
488 m_input_chkbox->Disable();
489 m_net_addr_text->Show();
490 m_net_address_tctrl->Show();
491 auto port = m_net_port_tctrl->GetValue();
492 if (port == kDefaultGpsdPort || port == kDefaultSignalkPort || port.empty())
493 net_port_w_help->RestoreHelp();
494 if (m_net_data_protocol_choice->GetCount() != 2)
495 SetupProtocolChoice(m_net_data_protocol_choice);
496 if (view == kTcpDevice || view == kTcpClient) {
497 m_net_addr_text->Show();
498 m_net_address_tctrl->Show();
499 if (m_net_address_tctrl->GetValue() ==
"0.0.0.0")
500 net_addr_w_help->RestoreHelp();
501 if (net_addr_w_help->IsPristine())
502 net_addr_w_help->SetHelp(kAddressDefaultHelp);
503 if (net_port_w_help->IsPristine())
504 net_port_w_help->SetHelp(_(
"Port number (1025 - 65535, often 10110)"));
505 m_input_chkbox->Enable();
506 m_output_chkbox->Enable();
507 }
else if (view == kUdpReceive || view == kUdpInput) {
508 m_net_addr_text->Hide();
509 m_net_address_tctrl->ChangeValue(
"0.0.0.0");
510 m_net_address_tctrl->Disable();
511 m_net_address_tctrl->Hide();
512 if (net_addr_w_help->IsPristine())
513 net_addr_w_help->SetHelp(kAddressDefaultHelp);
514 if (net_port_w_help->IsPristine())
515 net_port_w_help->SetHelp(_(
"Port number (1025 - 65535, often 10110)"));
516 m_input_chkbox->SetValue(
true);
517 m_output_chkbox->SetValue(
false);
518 }
else if (view == kUdpSend || view == kUdpOutput) {
519 if (m_net_address_tctrl->GetValue() ==
"0.0.0.0")
520 net_addr_w_help->RestoreHelp();
521 if (net_addr_w_help->IsPristine())
522 net_addr_w_help->SetHelp(kAddressUdpHelp);
523 m_input_chkbox->SetValue(
false);
524 m_output_chkbox->SetValue(
true);
525 }
else if (view == kGpsdClient || view == kGpsdDevice) {
526 m_net_data_protocol_choice->Clear();
527 m_net_data_protocol_choice->Append(
"gpsd");
528 m_net_data_protocol_choice->SetSelection(0);
529 m_net_data_protocol_choice->Disable();
530 if (m_net_address_tctrl->GetValue() ==
"0.0.0.0")
531 net_addr_w_help->RestoreHelp();
532 if (net_addr_w_help->IsPristine())
533 net_addr_w_help->SetHelp(kAddressDefaultHelp);
534 if (net_port_w_help->IsPristine())
535 net_port_w_help->ChangeValue(kDefaultGpsdPort);
536 m_output_chkbox->SetValue(
false);
537 m_input_chkbox->SetValue(
true);
538 }
else if (view == kSignalkClient || view == kSignalkDevice) {
539 m_net_data_protocol_choice->Clear();
540 m_net_data_protocol_choice->Append(
"SignalK");
541 m_net_data_protocol_choice->SetSelection(0);
542 m_net_data_protocol_choice->Disable();
543 if (m_net_address_tctrl->GetValue() ==
"0.0.0.0")
544 net_addr_w_help->RestoreHelp();
545 if (net_addr_w_help->IsPristine())
546 net_addr_w_help->SetHelp(kAddressDefaultHelp);
547 if (net_port_w_help->IsPristine())
548 net_port_w_help->ChangeValue(kDefaultSignalkPort);
549 m_input_chkbox->SetValue(
true);
550 m_output_chkbox->SetValue(
false);
551 }
else if (view == kTcpServer) {
552 m_net_addr_text->SetLabel(_(
"Interface"));
553 m_net_address_tctrl->ChangeValue(
"0.0.0.0");
554 m_net_address_tctrl->Disable();
555 m_output_chkbox->Enable();
556 m_input_chkbox->Enable();
557 }
else if (view == kMulticastClient || view == kMulticastServer) {
558 if (net_addr_w_help->GetValue().empty()) net_addr_w_help->RestoreHelp();
559 m_net_addr_text->SetLabel(_(
"Multicast group"));
560 if (net_port_w_help->IsPristine())
561 net_port_w_help->SetHelp(_(
"Port number, usually 49152 - 65535"));
562 if (net_addr_w_help->IsPristine())
563 net_addr_w_help->SetHelp(kAddressMcastHelp);
564 if (view == kMulticastClient) {
565 m_input_chkbox->SetValue(
false);
566 m_output_chkbox->SetValue(
true);
568 m_input_chkbox->SetValue(
true);
569 m_output_chkbox->Enable();
572 wxLogError(
"Illegal view: %s", view.c_str());
573 assert(
false &&
"Illegal view");
579 if (!m_type_net_radiobtn->GetValue())
return;
580 if (m_garmin_host_chkbox) m_garmin_host_chkbox->Hide();
581 if (m_garmin_upload_host_chkbox) m_garmin_upload_host_chkbox->Hide();
582 const std::string view = GetChoiceSelection(m_net_view_choice);
583 bool show_auth = view == kSignalkDevice || view == kSignalkClient;
584 m_auth_token_tctrl->Show(show_auth && m_advanced);
585 m_auth_token_text->Show(show_auth && m_advanced);
586 bool show_apb_precision = m_output_chkbox->IsChecked();
587 m_precision_text->Show(show_apb_precision && m_advanced);
588 m_precision_choice->Show(show_apb_precision && m_advanced);
592void ConnectionEditDialog::Init() {
598 m_bt_scan_timer.SetOwner(
this, ID_BT_SCANTIMER);
600 wxSize displaySize = wxGetDisplaySize();
604 auto* mainSizer =
new wxBoxSizer(wxVERTICAL);
607 wxFont* dFont = GetOCPNScaledFont_PlugIn(_(
"Dialog"));
608 double font_size = dFont->GetPointSize() * 17 / 16;
609 wxFont* bFont = wxTheFontList->FindOrCreateFont(
610 static_cast<int>(font_size), dFont->GetFamily(), dFont->GetStyle(),
614 m_conn_edit_statbox =
615 new wxStaticBox(
this, wxID_ANY, _(
"Edit Selected Connection"));
616 m_conn_edit_statbox->SetFont(*bFont);
618 m_connection_props_sizer =
619 new wxStaticBoxSizer(m_conn_edit_statbox, wxVERTICAL);
620 GetSizer()->Add(m_connection_props_sizer, 1, wxALL | wxEXPAND, 5);
622 wxBoxSizer* bSizer15;
623 bSizer15 =
new wxBoxSizer(wxHORIZONTAL);
625 m_connection_props_sizer->Add(bSizer15, 0, wxTOP | wxEXPAND, 5);
627 m_type_serial_radiobtn =
628 new wxRadioButton(
this, wxID_ANY, _(
"Serial"), wxDefaultPosition,
629 wxDefaultSize, wxRB_GROUP);
630 m_type_serial_radiobtn->SetValue(
true);
631 bSizer15->Add(m_type_serial_radiobtn, 0, wxALL, 5);
633 m_type_net_radiobtn =
new wxRadioButton(
this, wxID_ANY, _(
"Network"),
634 wxDefaultPosition, wxDefaultSize, 0);
635 bSizer15->Add(m_type_net_radiobtn, 0, wxALL, 5);
637 m_type_can_radiobtn =
new wxRadioButton(
this, wxID_ANY,
"socketCAN",
638 wxDefaultPosition, wxDefaultSize, 0);
639#if defined(__linux__) && !defined(__ANDROID__) && !defined(__WXOSX__)
640 bSizer15->Add(m_type_can_radiobtn, 0, wxALL, 5);
642 m_type_can_radiobtn->Hide();
645 auto* bSizer15a =
new wxBoxSizer(wxHORIZONTAL);
646 m_connection_props_sizer->Add(bSizer15a, 0, wxEXPAND, 5);
648 if (OCPNPlatform::hasInternalGPS()) {
649 m_type_internal_gps_radiobtn =
new wxRadioButton(
650 this, wxID_ANY, _(
"Built-in GPS"), wxDefaultPosition, wxDefaultSize, 0);
651 bSizer15a->Add(m_type_internal_gps_radiobtn, 0, wxALL, 5);
653 m_type_internal_gps_radiobtn =
nullptr;
656 if (OCPNPlatform::hasInternalBT()) {
657 m_type_internal_bt_radiobtn =
658 new wxRadioButton(
this, wxID_ANY, _(
"Built-in Bluetooth SPP"),
659 wxDefaultPosition, wxDefaultSize, 0);
660 bSizer15a->Add(m_type_internal_bt_radiobtn, 0, wxALL, 5);
662 m_scan_bt_btn =
new wxButton(
this, wxID_ANY, _(
"BT Scan") +
" ",
663 wxDefaultPosition, wxDefaultSize);
664 m_scan_bt_btn->Hide();
666 m_connection_props_sizer->Add(m_scan_bt_btn, 0, wxALL, 25);
669 new wxStaticText(
this, wxID_ANY, _(
"Bluetooth Data Sources"),
670 wxDefaultPosition, wxDefaultSize, 0);
671 m_bt_pairs_text->Wrap(-1);
672 m_bt_pairs_text->Hide();
673 m_connection_props_sizer->Add(m_bt_pairs_text, 0, wxALL, 5);
678 int ref_size = this->GetCharWidth();
679 m_bt_data_sources_choice =
680 new wxChoice(
this, wxID_ANY, wxDefaultPosition,
681 wxSize(40 * ref_size, 2 * ref_size), mt);
682 m_bt_data_sources_choice->SetSelection(0);
683 m_bt_data_sources_choice->Hide();
684 m_connection_props_sizer->Add(m_bt_data_sources_choice, 1, wxEXPAND | wxTOP,
688 m_type_internal_bt_radiobtn =
nullptr;
691 m_net_props_sizer =
new wxFlexGridSizer(0, 2, 0, 0);
693 m_connection_props_sizer->Add(m_net_props_sizer, 0, wxEXPAND, 5);
696 if (displaySize.x < displaySize.y) {
697 wxBoxSizer* bSizer16a;
698 bSizer16a =
new wxBoxSizer(wxHORIZONTAL);
699 m_net_props_sizer->AddSpacer(1);
700 m_net_props_sizer->Add(bSizer16a, 1, wxEXPAND, 5);
701 m_net_props_sizer->AddSpacer(1);
702 m_net_props_sizer->AddSpacer(1);
704 m_net_expert_box_text =
new wxStaticText(
this, wxID_ANY, _(
"Expert mode"));
705 m_net_props_sizer->Add(m_net_expert_box_text, 0, wxALL, 5);
706 m_net_expert_chkbox =
new wxCheckBox(
this, wxID_ANY,
"");
707 m_net_props_sizer->Add(m_net_expert_chkbox, 0, wxALL, 5);
708 m_net_expert_chkbox->Bind(
709 wxEVT_CHECKBOX, [&](
const wxCommandEvent&) { OnExpertModeChange(); });
711 m_net_type_choice_text =
712 new wxStaticText(
this, wxID_ANY, _(
"Connection type"));
713 m_net_props_sizer->Add(m_net_type_choice_text, 0, wxALL, 5);
714 m_net_view_choice =
new wxChoice(
this, wxID_ANY);
715 m_net_view_choice->Append(kBasicNetViews[0]);
716 m_net_view_choice->SetSelection(0);
717 m_net_view_choice->Bind(wxEVT_CHOICE,
719 m_net_props_sizer->Add(m_net_view_choice, 0, wxTOP, 5);
720 m_net_data_protocol_text =
721 new wxStaticText(
this, wxID_ANY, _(
"Data Protocol"));
722 m_net_data_protocol_text->Wrap(-1);
723 m_net_props_sizer->Add(m_net_data_protocol_text, 0, wxALL, 5);
725 m_net_data_protocol_choice =
new wxChoice(
this, wxID_ANY);
726 SetupProtocolChoice(m_net_data_protocol_choice);
727 m_net_props_sizer->Add(m_net_data_protocol_choice, 1, wxTOP, 5);
728 m_net_props_sizer->AddSpacer(1);
729 m_net_props_sizer->AddSpacer(1);
731 m_net_addr_text =
new wxStaticText(
this, wxID_ANY, _(
"Address"));
732 m_net_addr_text->Wrap(-1);
733 int column1width = 15 * GetCharWidth();
734 m_net_addr_text->SetMinSize(wxSize(column1width, -1));
735 m_net_props_sizer->Add(m_net_addr_text, 0, wxALL, 5);
737 int column2width = 60 * GetCharWidth();
738 m_net_address_tctrl->SetMaxSize(wxSize(column2width, -1));
739 m_net_address_tctrl->SetMinSize(wxSize(column2width, -1));
740 m_net_address_tctrl->Bind(wxEVT_KILL_FOCUS,
741 [&](wxFocusEvent& ev) { OnAddressChange(ev); });
743 m_net_props_sizer->Add(m_net_address_tctrl, 0, wxEXPAND | wxTOP, 5);
744 m_net_props_sizer->AddSpacer(1);
745 m_net_props_sizer->AddSpacer(1);
747 m_net_port_text =
new wxStaticText(
this, wxID_ANY, _(
"Data Port"));
748 m_net_port_text->Wrap(-1);
749 m_net_props_sizer->Add(m_net_port_text, 0, wxALL, 5);
752 m_net_port_tctrl->SetMaxSize(wxSize(column2width, -1));
753 m_net_port_tctrl->SetMinSize(wxSize(column2width, -1));
754 m_net_props_sizer->Add(m_net_port_tctrl, 1, wxEXPAND | wxTOP, 5);
755 m_net_port_tctrl->SetMaxSize(wxSize(column2width, -1));
756 m_net_port_tctrl->SetMinSize(wxSize(column2width, -1));
758 m_net_comment_text =
new wxStaticText(
this, wxID_ANY, _(
"User Comment"));
759 m_net_comment_text->Wrap(-1);
760 m_net_comment_text->SetMinSize({column1width, -1});
761 m_net_props_sizer->Add(m_net_comment_text, 0, wxALL, 5);
762 m_net_comment_text->Hide();
764 m_net_comment_tctrl =
new wxTextCtrl(
this, wxID_ANY);
765 m_net_comment_tctrl->SetMaxSize({column2width, -1});
766 m_net_comment_tctrl->SetMinSize({column2width, -1});
767 m_net_props_sizer->Add(m_net_comment_tctrl, 1, wxEXPAND | wxTOP, 5);
768 m_net_comment_tctrl->Hide();
770 m_net_props_sizer->AddSpacer(1);
771 m_net_props_sizer->AddSpacer(1);
773 m_can_props_sizer =
new wxGridSizer(0, 1, 0, 0);
774 wxFlexGridSizer* fgSizer1C;
775 fgSizer1C =
new wxFlexGridSizer(0, 2, 0, 0);
777 m_can_source_text =
new wxStaticText(
this, wxID_ANY, _(
"socketCAN Source"),
778 wxDefaultPosition, wxDefaultSize, 0);
779 m_can_source_text->Wrap(-1);
780 m_can_source_text->SetMinSize(wxSize(column1width, -1));
781 fgSizer1C->Add(m_can_source_text, 0, wxALL, 5);
783 wxArrayString choices = GetAvailableSocketCANInterfaces();
784 m_can_source_choice =
785 new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
787 m_can_source_choice->SetSelection(0);
788 m_can_source_choice->Enable(!choices.empty());
789 m_can_source_choice->SetMaxSize(wxSize(column2width, -1));
790 m_can_source_choice->SetMinSize(wxSize(column2width, -1));
791 fgSizer1C->Add(m_can_source_choice, 1, wxEXPAND | wxTOP, 5);
793 m_can_props_sizer->Add(fgSizer1C, 0, wxEXPAND, 5);
795 m_connection_props_sizer->Add(m_can_props_sizer, 0, wxEXPAND, 5);
797 m_ser_props_sizer =
new wxGridSizer(0, 1, 0, 0);
798 m_connection_props_sizer->Add(m_ser_props_sizer, 0, wxEXPAND, 5);
800 wxFlexGridSizer* fgSizer1;
801 fgSizer1 =
new wxFlexGridSizer(0, 4, 0, 0);
802 fgSizer1->SetFlexibleDirection(wxBOTH);
803 fgSizer1->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
806 new wxStaticText(
this, wxID_ANY, _(
"Data port"), wxDefaultPosition,
807 wxDefaultSize, wxST_ELLIPSIZE_END);
808 m_ser_port_text->SetMinSize(wxSize(column1width, -1));
809 m_ser_port_text->Wrap(-1);
811 fgSizer1->Add(m_ser_port_text, 0, wxALL, 5);
814 new wxComboBox(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
815 wxDefaultSize, 0,
nullptr, 0);
817 m_port_combo->SetMaxSize(wxSize(column2width, -1));
818 m_port_combo->SetMinSize(wxSize(column2width, -1));
820 fgSizer1->Add(m_port_combo, 0, wxEXPAND | wxTOP, 5);
822 m_ser_baudrate_text =
new wxStaticText(
this, wxID_ANY, _(
"Baudrate"),
823 wxDefaultPosition, wxDefaultSize, 0);
824 m_ser_baudrate_text->Wrap(-1);
825 fgSizer1->AddSpacer(1);
826 fgSizer1->AddSpacer(1);
827 fgSizer1->Add(m_ser_baudrate_text, 0, wxALL, 5);
829 wxString m_choiceBaudRateChoices[] = {
830 _(
"150"), _(
"300"), _(
"600"), _(
"1200"), _(
"2400"),
831 _(
"4800"), _(
"9600"), _(
"19200"), _(
"38400"), _(
"57600"),
832 _(
"115200"), _(
"230400"), _(
"460800"), _(
"921600")};
833 int m_choiceBaudRateNChoices =
834 sizeof(m_choiceBaudRateChoices) /
sizeof(wxString);
836 new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
837 m_choiceBaudRateNChoices, m_choiceBaudRateChoices, 0);
841 m_baud_rate_choice->SetSelection(0);
843 fgSizer1->Add(m_baud_rate_choice, 1, wxEXPAND | wxTOP, 5);
844 fgSizer1->AddSpacer(1);
845 fgSizer1->AddSpacer(1);
847 m_ser_protocol_text =
new wxStaticText(
this, wxID_ANY, _(
"Protocol"));
848 m_ser_protocol_text->Wrap(-1);
849 fgSizer1->Add(m_ser_protocol_text, 0, wxALL, 5);
851 wxString m_choiceSerialProtocolChoices[] = {_(
"NMEA 0183"), _(
"NMEA 2000")};
852 int m_choiceSerialProtocolNChoices =
853 sizeof(m_choiceSerialProtocolChoices) /
sizeof(wxString);
854 m_serial_protocol_choice =
new wxChoice(
855 this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
856 m_choiceSerialProtocolNChoices, m_choiceSerialProtocolChoices, 0);
860 m_serial_protocol_choice->SetSelection(0);
861 m_serial_protocol_choice->Enable(
true);
862 fgSizer1->Add(m_serial_protocol_choice, 1, wxEXPAND | wxTOP, 5);
864 m_ser_props_sizer->Add(fgSizer1, 0, wxEXPAND, 5);
868 auto* commentSizer =
new wxFlexGridSizer(0, 2, 0, 0);
872 m_ser_comment_text =
new wxStaticText(
this, wxID_ANY, _(
"User Comment"));
873 m_ser_comment_text->Wrap(-1);
874 m_ser_comment_text->SetMinSize(wxSize(column1width, -1));
875 commentSizer->Add(m_ser_comment_text, 0, wxALL, 5);
877 m_serial_comment_tctrl =
new wxTextCtrl(
this, wxID_ANY);
878 m_serial_comment_tctrl->SetMaxSize(wxSize(column2width, -1));
879 m_serial_comment_tctrl->SetMinSize(wxSize(column2width, -1));
881 commentSizer->Add(m_serial_comment_tctrl, 1, wxTOP, 5);
883 m_connection_props_sizer->Add(commentSizer, 0, wxALL, 5);
885 wxFlexGridSizer* fgSizer5;
886 fgSizer5 =
new wxFlexGridSizer(0, 2, 0, 0);
887 fgSizer5->SetFlexibleDirection(wxBOTH);
888 fgSizer5->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
889 m_connection_props_sizer->Add(fgSizer5, 0, wxEXPAND, 5);
892 new wxCheckBox(
this, wxID_ANY, _(
"Receive Input on this Port"));
893 fgSizer5->Add(m_input_chkbox, 0, wxALL, 2);
894 fgSizer5->AddSpacer(1);
897 new wxCheckBox(
this, wxID_ANY,
898 wxString::Format(
"%s (%s)", _(
"Output on this port"),
899 _(
"as autopilot or NMEA repeater")));
900 fgSizer5->Add(m_output_chkbox, 0, wxALL, 2);
901 fgSizer5->AddSpacer(1);
905 auto flags = wxSizerFlags().Border();
906 m_collapse_box =
new wxBoxSizer(wxHORIZONTAL);
908 m_collapse_box->Add(
new wxStaticText(
this, wxID_ANY, _(
"Advanced: ")), flags);
911 [&](
bool collapsed) { OnCollapsedToggle(collapsed); }),
913 fgSizer5->Add(m_collapse_box, wxSizerFlags());
914 fgSizer5->Add(
new wxStaticText(
this, wxID_ANY,
""));
916#ifndef USE_GARMINHOST
917 m_cbGarminHost->Hide();
920 m_auth_token_text =
new wxStaticText(
this, wxID_ANY, _(
"Auth Token"));
921 m_auth_token_text->SetMinSize(wxSize(column1width, -1));
922 m_auth_token_text->Wrap(-1);
923 m_auth_token_text->SetMinSize(wxSize(column1width, -1));
924 fgSizer5->Add(m_auth_token_text, 0, wxALL, 5);
925 m_auth_token_text->Hide();
927 m_auth_token_tctrl =
new wxTextCtrl(
this, wxID_ANY,
"");
928 m_auth_token_tctrl->SetMinSize(wxSize(column2width, -1));
929 fgSizer5->Add(m_auth_token_tctrl, 1, wxEXPAND | wxTOP, 5);
930 m_auth_token_tctrl->SetValue(
"orvar");
931 m_auth_token_tctrl->Hide();
933 fgSizer5->AddSpacer(1);
934 fgSizer5->Add(
new wxStaticText(
this, wxID_ANY,
""), 0, wxALL, 2);
937 new wxStaticText(
this, wxID_ANY, _(
"APB bearing precision"));
938 m_precision_text->Wrap(-1);
939 m_precision_text->SetMinSize(wxSize(column1width, -1));
940 fgSizer5->Add(m_precision_text, 0, wxALL, 2);
941 m_precision_text->Hide();
943 wxString m_choicePrecisionChoices[] = {_(
"x"), _(
"x.x"), _(
"x.xx"),
944 _(
"x.xxx"), _(
"x.xxxx")};
945 int m_choicePrecisionNChoices =
946 sizeof(m_choicePrecisionChoices) /
sizeof(wxString);
948 new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
949 m_choicePrecisionNChoices, m_choicePrecisionChoices, 0);
953 m_precision_choice->SetSelection(g_NMEAAPBPrecision);
954 fgSizer5->Add(m_precision_choice, 0, wxALL, 2);
955 m_precision_choice->Hide();
956 OnExpertModeChange();
958 m_garmin_host_chkbox =
959 new wxCheckBox(
this, wxID_ANY, _(
"Use Garmin (GRMN) mode for input"));
960 m_garmin_host_chkbox->SetValue(
false);
961 fgSizer5->Add(m_garmin_host_chkbox, 0, wxALL, 2);
962 fgSizer5->AddSpacer(1);
965 m_sk_check_discover_chkbox =
966 new wxCheckBox(
this, wxID_ANY, _(
"Automatic server discovery"));
967 m_sk_check_discover_chkbox->SetValue(
true);
968 m_sk_check_discover_chkbox->SetToolTip(
969 _(
"If checked, signal K server will be discovered automatically"));
971 fgSizer5->Add(m_sk_check_discover_chkbox, 0, wxALL, 2);
974 m_sk_discover_btn =
new wxButton(
this, wxID_ANY, _(
"Discover now..."));
975 m_sk_discover_btn->Hide();
976 fgSizer5->Add(m_sk_discover_btn, 0, wxALL, 2);
979 m_sk_server_status_text =
new wxStaticText(
this, wxID_ANY,
"");
980 fgSizer5->Add(m_sk_server_status_text, 0, wxALL, 2);
982 m_in_filter_sizer =
new wxStaticBoxSizer(
983 new wxStaticBox(
this, wxID_ANY, _(
"Input filtering")), wxVERTICAL);
984 m_connection_props_sizer->Add(m_in_filter_sizer,
985 wxSizerFlags().Expand().Border());
988 bSizer9 =
new wxBoxSizer(wxHORIZONTAL);
991 new wxRadioButton(
this, wxID_ANY, _(
"Accept only sentences"));
992 bSizer9->Add(m_accept_radiobtn, 0, wxALL, 5);
994 m_ignore_radiobtn =
new wxRadioButton(
this, wxID_ANY, _(
"Ignore sentences"));
995 bSizer9->Add(m_ignore_radiobtn, 0, wxALL, 5);
997 m_in_filter_sizer->Add(bSizer9, 0, wxEXPAND, 5);
999 wxBoxSizer* bSizer11;
1000 bSizer11 =
new wxBoxSizer(wxHORIZONTAL);
1001 m_in_filter_sizer->Add(bSizer11, 0, wxEXPAND, 5);
1004 new wxTextCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1005 wxDefaultSize, wxTE_READONLY);
1006 bSizer11->Add(m_input_stc_tctrl, 1, wxALL | wxEXPAND, 5);
1008 m_input_stc_list_btn =
new wxButton(
this, wxID_ANY,
"...", wxDefaultPosition,
1009 wxDefaultSize, wxBU_EXACTFIT);
1010 bSizer11->Add(m_input_stc_list_btn, 0, wxALL, 5);
1012 bSizer11->AddSpacer(GetCharWidth() * 5);
1014 m_out_filter_sizer =
new wxStaticBoxSizer(
1015 new wxStaticBox(
this, wxID_ANY, _(
"Output filtering")), wxVERTICAL);
1016 m_connection_props_sizer->Add(m_out_filter_sizer, 0, wxEXPAND, 5);
1018 wxBoxSizer* bSizer10;
1019 bSizer10 =
new wxBoxSizer(wxHORIZONTAL);
1021 m_o_accept_radiobtn =
1022 new wxRadioButton(
this, wxID_ANY, _(
"Transmit sentences"),
1023 wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
1024 bSizer10->Add(m_o_accept_radiobtn, 0, wxALL, 5);
1026 m_o_ignore_radiobtn =
new wxRadioButton(
this, wxID_ANY, _(
"Drop sentences"),
1027 wxDefaultPosition, wxDefaultSize, 0);
1028 bSizer10->Add(m_o_ignore_radiobtn, 0, wxALL, 5);
1030 m_out_filter_sizer->Add(bSizer10, 0, wxEXPAND, 5);
1032 wxBoxSizer* bSizer12;
1033 bSizer12 =
new wxBoxSizer(wxHORIZONTAL);
1034 m_out_filter_sizer->Add(bSizer12, 0, wxEXPAND, 5);
1036 m_output_stc_tctrl =
1037 new wxTextCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1038 wxDefaultSize, wxTE_READONLY);
1039 bSizer12->Add(m_output_stc_tctrl, 1, wxALL | wxEXPAND, 5);
1041 m_output_stc_list_btn =
new wxButton(
this, wxID_ANY,
"...", wxDefaultPosition,
1042 wxDefaultSize, wxBU_EXACTFIT);
1043 bSizer12->Add(m_output_stc_list_btn, 0, wxALL, 5);
1045 bSizer12->AddSpacer(GetCharWidth() * 5);
1047 m_connection_props_sizer->AddSpacer(20);
1051 SetInitialSettings();
1055 ShowNMEACommon(
true);
1056 ShowNMEASerial(
true);
1060 m_is_conn_saved =
true;
1062 GetSizer()->Fit(
this);
1064 m_new_device_listener.Init(
1065 SystemEvents::GetInstance().evt_dev_change,
1066 [&](
ObservedEvt&) { LoadSerialPorts(m_port_combo); });
1069void ConnectionEditDialog::OnAddressChange(wxFocusEvent& ev) {
1070 int selection = m_net_view_choice->GetSelection();
1071 if (selection != wxNOT_FOUND) {
1072 std::string type = m_net_view_choice->GetString(selection).ToStdString();
1073 if (type == kMulticastClient || type == kMulticastServer) {
1074 auto address = m_net_address_tctrl->GetValue().ToStdString();
1075 if (!IsAddressMultiCast(address)) {
1076 auto dlg = wxMessageDialog(
this, _(
"Illegal multicast address"),
1077 _(
"OpenCPN warning"), wxOK | wxICON_WARNING);
1085void ConnectionEditDialog::OnExpertModeChange() {
1086 bool advanced = m_net_expert_chkbox->GetValue();
1087 int view = m_net_view_choice->GetSelection();
1088 m_net_view_choice->Clear();
1090 for (
const auto& choice : kAdvancedNetViews)
1091 m_net_view_choice->Append(choice);
1092 m_net_type_choice_text->SetLabel(_(
"Connection type"));
1093 if (m_net_comment_text) m_net_comment_text->Show();
1094 if (m_net_comment_tctrl) m_net_comment_tctrl->Show();
1096 if (view != wxNOT_FOUND) {
1097 if (
static_cast<size_t>(view) >= kBasicNetViews.size()) view = 0;
1099 for (
const auto& choice : kBasicNetViews) m_net_view_choice->Append(choice);
1100 m_net_type_choice_text->SetLabel(_(
"Connect to"));
1101 if (m_net_comment_text) m_net_comment_text->Hide();
1102 if (m_net_comment_tctrl) m_net_comment_tctrl->Hide();
1104 m_net_view_choice->SetSelection(view);
1105 auto view_str = m_net_view_choice->GetStringSelection().ToStdString();
1106 if (!view_str.empty()) ConfigureControlsForView(view_str);
1110void ConnectionEditDialog::OnCancelClick() {
1111 m_on_edit_click(
nullptr,
false,
false);
1114void ConnectionEditDialog::OnOKClick() {
1115 if (m_cp_original) {
1116 int selection = m_net_view_choice->GetSelection();
1117 if (selection != wxNOT_FOUND) {
1118 std::string selected =
1119 m_net_view_choice->GetString(selection).ToStdString();
1123 if (m_net_address_tctrl->IsEnabled() &&
1124 m_net_address_tctrl->IsShownOnScreen()) {
1126 if (net_address) ok = CheckAddress(
this, *net_address);
1128 if (m_net_port_tctrl->IsEnabled() && m_net_port_tctrl->IsShownOnScreen()) {
1130 if (net_port) ok = ok && CheckPort(
this, *net_port);
1132 ok = ok && CheckIoDirections(
this, m_output_chkbox, m_input_chkbox);
1133 if (ok) m_on_edit_click(m_cp_original, m_new_mode,
true);
1136void ConnectionEditDialog::SetInitialSettings() {
1137 LoadSerialPorts(m_port_combo);
1144void ConnectionEditDialog::SetSelectedConnectionPanel(
1149 if (m_selected_conn_params && m_selected_conn_params->options_panel)
1150 m_selected_conn_params->options_panel->SetSelected(
false);
1153 m_selected_conn_params = panel->m_pConnectionParams;
1154 panel->SetSelected(
true);
1155 SetConnectionParams(m_selected_conn_params);
1156 m_remove_btn->Enable();
1157 m_remove_btn->Show();
1158 m_add_btn->Disable();
1159 m_conn_edit_statbox->SetLabel(_(
"Edit Connection"));
1162 m_selected_conn_params =
nullptr;
1163 m_remove_btn->Disable();
1164 m_add_btn->Enable();
1166 m_conn_edit_statbox->SetLabel(
"");
1176void ConnectionEditDialog::SetPropsLabel(
const wxString& label) {
1177 m_conn_edit_statbox->SetLabel(label);
1184 conn->is_setup =
false;
1185 m_conn_enabled = conn->is_enabled;
1189void ConnectionEditDialog::OnValChange(wxCommandEvent& event) {
event.Skip(); }
1191void ConnectionEditDialog::OnScanBtClick(wxCommandEvent& event) {
1195 m_bt_no_change_counter = 0;
1196 m_bt_last_result_count = 0;
1198 Bind(wxEVT_TIMER, &ConnectionEditDialog::OnBtScanTimer,
this,
1200 m_bt_scan_timer.Start(1000, wxTIMER_CONTINUOUS);
1201 g_Platform->startBluetoothScan();
1203 if (m_scan_bt_btn) {
1204 m_scan_bt_btn->SetLabel(_(
"Stop Scan"));
1209void ConnectionEditDialog::OnBtScanTimer(wxTimerEvent& event) {
1210 if (m_bt_scanning) {
1213 m_bt_scan_results = g_Platform->getBluetoothScanResults();
1215 m_bt_data_sources_choice->Clear();
1216 m_bt_data_sources_choice->Append(m_bt_scan_results[0]);
1219 while ((i + 1) < m_bt_scan_results.GetCount()) {
1220 wxString item1 = m_bt_scan_results[i] +
";";
1221 wxString item2 = m_bt_scan_results.Item(i + 1);
1222 m_bt_data_sources_choice->Append(item1 + item2);
1227 if (m_bt_scan_results.GetCount() > 1) {
1228 m_bt_data_sources_choice->SetSelection(1);
1233 if (m_bt_no_change_counter > 5) StopBtScan();
1235 if ((
int)m_bt_scan_results.GetCount() == m_bt_last_result_count)
1236 m_bt_no_change_counter++;
1238 m_bt_no_change_counter = 0;
1240 m_bt_last_result_count =
static_cast<int>(m_bt_scan_results.GetCount());
1243 if (m_bt_scanning >= 15) {
1250void ConnectionEditDialog::StopBtScan() {
1251 m_bt_scan_timer.Stop();
1253 g_Platform->stopBluetoothScan();
1257 if (m_scan_bt_btn) {
1258 m_scan_bt_btn->SetLabel(_(
"BT Scan"));
1259 m_scan_bt_btn->Enable();
1263void ConnectionEditDialog::OnConnValChange(wxCommandEvent& event) {
1264 m_is_conn_saved =
false;
1268void ConnectionEditDialog::OnTypeSerialSelected(wxCommandEvent& event) {
1269 OnConnValChange(event);
1270 SetNMEAFormToSerial();
1273void ConnectionEditDialog::OnTypeNetSelected(wxCommandEvent& event) {
1274 OnConnValChange(event);
1278void ConnectionEditDialog::OnTypeCANSelected(wxCommandEvent& event) {
1279 OnConnValChange(event);
1283void ConnectionEditDialog::OnTypeGPSSelected(wxCommandEvent& event) {
1284 OnConnValChange(event);
1288void ConnectionEditDialog::OnTypeBTSelected(wxCommandEvent& event) {
1289 OnConnValChange(event);
1293void ConnectionEditDialog::OnUploadFormatChange(wxCommandEvent& event) {
1294 if (event.GetEventObject() == m_garmin_upload_host_chkbox &&
1296 m_furuno_gp3x_chkbox->SetValue(
false);
1297 else if (event.GetEventObject() == m_furuno_gp3x_chkbox && event.IsChecked())
1298 m_garmin_upload_host_chkbox->SetValue(
false);
1300 OnConnValChange(event);
1304void ConnectionEditDialog::ShowTypeCommon(
bool visible) {
1305 m_type_serial_radiobtn->Show(visible);
1306 m_type_net_radiobtn->Show(visible);
1307#if defined(__linux__) && !defined(__ANDROID__) && !defined(__WXOSX__)
1308 m_type_can_radiobtn->Show(visible);
1310 if (m_type_internal_gps_radiobtn) m_type_internal_gps_radiobtn->Show(visible);
1311 if (m_type_internal_bt_radiobtn) m_type_internal_bt_radiobtn->Show(visible);
1314void ConnectionEditDialog::ShowNMEACommon(
bool visible) {
1315 bool advanced = m_advanced;
1316 m_input_chkbox->Show(visible);
1317 m_output_chkbox->Show(visible);
1319 m_out_filter_sizer->SetDimension(0, 0, 0, 0);
1320 m_in_filter_sizer->SetDimension(0, 0, 0, 0);
1321 m_connection_props_sizer->SetDimension(0, 0, 0, 0);
1322 m_conn_edit_statbox->SetLabel(
"");
1325 m_sk_check_discover_chkbox->Hide();
1326 m_sk_discover_btn->Hide();
1328 const bool bin_enable = (m_input_chkbox->IsChecked() && advanced);
1329 ShowInFilter(visible && bin_enable);
1330 const bool bout_enable = (m_output_chkbox->IsChecked() && advanced);
1331 ShowOutFilter(visible && bout_enable);
1333 m_is_nmea_params_shown = visible;
1336void ConnectionEditDialog::ShowNMEANet(
bool visible) {
1337 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1339 m_net_addr_text->Show(visible);
1340 m_net_address_tctrl->Show(visible);
1341 m_net_data_protocol_text->Show(visible);
1342 m_net_port_text->Show(visible);
1343 m_net_data_protocol_choice->Show(visible);
1344 m_net_port_tctrl->Show(visible);
1345 m_net_expert_chkbox->Show(visible);
1346 if (m_net_expert_chkbox->GetValue()) {
1347 m_net_comment_text->Show(visible);
1348 m_net_comment_tctrl->Show(visible);
1350 m_net_expert_box_text->Show(visible);
1351 m_net_type_choice_text->Show(visible);
1352 m_net_view_choice->Show(visible);
1353 m_garmin_host_chkbox->Hide();
1357void ConnectionEditDialog::ShowNMEASerial(
bool visible) {
1358 bool advanced = m_advanced;
1359 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1361 m_ser_baudrate_text->Show(visible);
1362 m_baud_rate_choice->Show(visible);
1363 m_ser_port_text->Show(visible);
1364 m_port_combo->Show(visible);
1365 m_ser_protocol_text->Show(visible);
1366 m_serial_protocol_choice->Show(visible);
1367 m_garmin_host_chkbox->Show(visible && advanced);
1368 m_ser_comment_text->Show(visible);
1369 m_serial_comment_tctrl->Show(visible);
1370 m_net_comment_text->Hide();
1371 m_net_comment_tctrl->Hide();
1374void ConnectionEditDialog::ShowNMEAGPS(
bool visible) {
1375 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1377 m_sk_check_discover_chkbox->Hide();
1378 m_sk_discover_btn->Hide();
1379 m_output_chkbox->Hide();
1382void ConnectionEditDialog::ShowNMEACAN(
bool visible) {
1383 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1384 m_can_source_text->Show(visible);
1385 m_can_source_choice->Show(visible);
1386 if (visible && m_dlg_ok_btn && m_can_source_choice->IsEmpty())
1387 m_dlg_ok_btn->Enable(
false);
1390void ConnectionEditDialog::ShowNMEABT(
bool visible) {
1391 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1394 if (m_scan_bt_btn) m_scan_bt_btn->Show();
1395 if (m_bt_pairs_text) m_bt_pairs_text->Show();
1396 if (m_bt_data_sources_choice) {
1397 if (m_bt_data_sources_choice->GetCount() > 1)
1398 m_bt_data_sources_choice->SetSelection(1);
1399 m_bt_data_sources_choice->Show();
1402 if (m_scan_bt_btn) m_scan_bt_btn->Hide();
1403 if (m_bt_pairs_text) m_bt_pairs_text->Hide();
1404 if (m_bt_data_sources_choice) m_bt_data_sources_choice->Hide();
1406 m_sk_check_discover_chkbox->Hide();
1407 m_sk_check_discover_chkbox->Hide();
1408 m_sk_discover_btn->Hide();
1409 m_output_stc_tctrl->Show(visible);
1410 m_output_stc_list_btn->Show(visible);
1411 m_output_chkbox->Show(visible);
1414void ConnectionEditDialog::SetNMEAFormToSerial() {
1415 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1417 ShowNMEACommon(
true);
1421 ShowNMEASerial(
true);
1423 SetDSFormRWStates();
1427void ConnectionEditDialog::SetNMEAFormToNet() {
1428 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1430 ShowNMEACommon(
true);
1434 ShowNMEASerial(
false);
1436 SetDSFormRWStates();
1441void ConnectionEditDialog::SetNMEAFormToCAN() {
1442 if (m_dlg_ok_btn) m_dlg_ok_btn->Enable();
1444 ShowNMEACommon(
false);
1448 ShowNMEASerial(
false);
1450 m_in_filter_sizer->Show(
false);
1451 m_out_filter_sizer->Show(
false);
1452 SetDSFormRWStates();
1457void ConnectionEditDialog::SetNMEAFormToGPS() {
1458 ShowNMEACommon(
true);
1462 ShowNMEASerial(
false);
1467 SetDSFormRWStates();
1471void ConnectionEditDialog::SetNMEAFormToBT() {
1472 ShowNMEACommon(
true);
1476 ShowNMEASerial(
false);
1481 SetDSFormRWStates();
1485void ConnectionEditDialog::ClearNMEAForm() {
1486 ShowNMEACommon(
false);
1490 ShowNMEASerial(
false);
1501void ConnectionEditDialog::SetDSFormOptionVizStates() {
1502 bool advanced = m_advanced;
1503 m_collapse_box->ShowItems(
true);
1504 m_input_chkbox->Show();
1505 m_output_chkbox->Show();
1507 ShowInFilter(advanced);
1508 ShowOutFilter(advanced);
1512 m_sk_server_status_text->Show(advanced);
1514 if (m_type_serial_radiobtn->GetValue()) {
1515 m_sk_check_discover_chkbox->Hide();
1516 m_sk_discover_btn->Hide();
1517 m_sk_server_status_text->Hide();
1518 bool n0183ctlenabled =
1519 (DataProtocol)m_serial_protocol_choice->GetSelection() ==
1520 DataProtocol::PROTO_NMEA0183;
1521 bool n2kctlenabled =
1522 (DataProtocol)m_serial_protocol_choice->GetSelection() ==
1523 DataProtocol::PROTO_NMEA2000;
1524 if (!n0183ctlenabled) {
1525 if (n2kctlenabled) {
1526 m_input_chkbox->Show();
1527 m_output_chkbox->Show();
1529 m_input_chkbox->Hide();
1530 m_output_chkbox->Hide();
1532 ShowOutFilter(
false);
1533 ShowInFilter(
false);
1534 m_net_data_protocol_text->Hide();
1535 m_net_data_protocol_choice->Hide();
1536 m_net_expert_chkbox->Hide();
1537 m_net_type_choice_text->Hide();
1538 m_net_view_choice->Hide();
1539 m_net_expert_chkbox->Hide();
1540 m_net_type_choice_text->Hide();
1541 m_net_expert_box_text->Hide();
1542 m_net_view_choice->Hide();
1544 m_input_chkbox->Show();
1545 m_input_chkbox->Enable();
1547 ShowInFilter(m_input_chkbox->IsChecked() && advanced);
1548 ShowOutFilter(m_output_chkbox->IsChecked() && advanced);
1550 m_garmin_host_chkbox->Show(m_input_chkbox->IsChecked() && advanced);
1554 if (m_type_internal_gps_radiobtn &&
1555 m_type_internal_gps_radiobtn->GetValue()) {
1556 m_sk_check_discover_chkbox->Hide();
1557 m_sk_discover_btn->Hide();
1558 m_sk_server_status_text->Hide();
1559 m_output_chkbox->Hide();
1560 m_input_chkbox->Hide();
1561 ShowOutFilter(
false);
1562 ShowInFilter(
false);
1563 m_garmin_host_chkbox->Hide();
1564 m_collapse_box->ShowItems(
false);
1567 if (m_type_internal_bt_radiobtn && m_type_internal_bt_radiobtn->GetValue()) {
1568 m_sk_check_discover_chkbox->Hide();
1569 m_sk_discover_btn->Hide();
1570 m_sk_server_status_text->Hide();
1572 ShowInFilter(m_input_chkbox->IsChecked() && advanced);
1573 ShowOutFilter(m_output_chkbox->IsChecked() && advanced);
1576 if (m_type_can_radiobtn->GetValue()) {
1577 m_sk_check_discover_chkbox->Hide();
1578 m_sk_discover_btn->Hide();
1579 m_sk_server_status_text->Hide();
1580 m_garmin_host_chkbox->Hide();
1581 m_input_chkbox->Hide();
1582 m_output_chkbox->Hide();
1584 ShowInFilter(
false);
1585 ShowOutFilter(
false);
1587 m_net_data_protocol_text->Hide();
1588 m_net_data_protocol_choice->Hide();
1589 m_net_expert_chkbox->Hide();
1590 m_net_type_choice_text->Hide();
1591 m_net_expert_box_text->Hide();
1592 m_net_view_choice->Hide();
1593 m_collapse_box->Show(
false);
1596 if (m_type_net_radiobtn->GetValue()) {
1597 if ((DataProtocol)m_net_data_protocol_choice->GetSelection() ==
1598 DataProtocol::PROTO_NMEA2000) {
1599 ShowInFilter(
false);
1600 ShowOutFilter(
false);
1602 if ((DataProtocol)m_net_data_protocol_choice->GetSelection() ==
1603 DataProtocol::PROTO_NMEA0183) {
1604 ShowInFilter(m_input_chkbox->IsChecked() && advanced);
1605 ShowOutFilter(m_output_chkbox->IsChecked() && advanced);
1614void ConnectionEditDialog::SetDSFormRWStates() {
1615 if (m_type_serial_radiobtn->GetValue()) {
1616 m_input_chkbox->Enable(
true);
1617 m_output_chkbox->Enable(
true);
1619 ShowOutFilter(m_output_chkbox->IsChecked());
1621 m_o_accept_radiobtn->Enable(
true);
1622 m_o_ignore_radiobtn->Enable(
true);
1623 m_output_stc_list_btn->Enable(
true);
1625 SetDSFormOptionVizStates();
1628void ConnectionEditDialog::ShowInFilter(
bool bshow) {
1629 m_in_filter_sizer->GetStaticBox()->Show(bshow);
1630 m_accept_radiobtn->Show(bshow);
1631 m_ignore_radiobtn->Show(bshow);
1632 m_input_stc_tctrl->Show(bshow);
1633 m_input_stc_list_btn->Show(bshow);
1636void ConnectionEditDialog::ShowOutFilter(
bool bshow) {
1637 m_out_filter_sizer->GetStaticBox()->Show(bshow);
1638 m_o_accept_radiobtn->Show(bshow);
1639 m_o_ignore_radiobtn->Show(bshow);
1640 m_output_stc_tctrl->Show(bshow);
1641 m_output_stc_list_btn->Show(bshow);
1646 SetConnectionParams(cp);
1650 if (cp->type == NETWORK && cp->direction == PortDirection::kInput) {
1653 auto& address = cp->network_address;
1654 if (address ==
"127.0.0.1" || address ==
"localhost") address =
"0.0.0.0";
1656 const std::string view = NetViewByConnection(cp);
1657 auto found = std::find(kBasicNetViews.begin(), kBasicNetViews.end(), view);
1658 m_net_expert_chkbox->SetValue(found == kBasicNetViews.end());
1659 m_net_view_choice->Clear();
1660 if (found == kBasicNetViews.end())
1661 for (
const auto& v : kAdvancedNetViews) m_net_view_choice->Append(v);
1663 for (
const auto& v : kBasicNetViews) m_net_view_choice->Append(v);
1664 std::vector<std::string> all_views = kBasicNetViews;
1665 for (
const auto& v : kAdvancedNetViews) all_views.push_back(v);
1666 found = std::find(all_views.begin(), all_views.end(), view);
1667 if (found != all_views.end()) {
1668 int select_ix = m_net_view_choice->FindString(*found);
1669 if (select_ix != wxNOT_FOUND) m_net_view_choice->SetSelection(select_ix);
1671 if (wxNOT_FOUND == m_port_combo->FindString(cp->serial_port))
1672 m_port_combo->Append(cp->serial_port);
1674 m_port_combo->Select(m_port_combo->FindString(cp->serial_port));
1676 m_garmin_host_chkbox->SetValue(cp->is_garmin);
1677 m_sk_check_discover_chkbox->SetValue(cp->auto_sk_discover);
1678 if (view == kUdpReceive || view == kUdpInput) {
1679 m_input_chkbox->SetValue(
true);
1680 m_input_chkbox->Disable();
1681 m_output_chkbox->SetValue(
false);
1682 m_output_chkbox->Disable();
1684 m_input_chkbox->SetValue(cp->direction != PortDirection::kOutput);
1685 m_output_chkbox->SetValue(cp->direction != PortDirection::kInput);
1688 if (cp->input_sentence_list_type == WHITELIST)
1689 m_accept_radiobtn->SetValue(
true);
1691 m_ignore_radiobtn->SetValue(
true);
1692 if (cp->output_sentence_list_type == WHITELIST)
1693 m_o_accept_radiobtn->SetValue(
true);
1695 m_o_ignore_radiobtn->SetValue(
true);
1696 m_input_stc_tctrl->SetValue(StringArrayToString(cp->input_sentence_list));
1697 m_output_stc_tctrl->SetValue(StringArrayToString(cp->output_sentence_list));
1698 m_baud_rate_choice->Select(
1699 m_baud_rate_choice->FindString(wxString::Format(
"%d", cp->baudrate)));
1700 m_serial_protocol_choice->Select(cp->data_protocol);
1702 if (net_address) m_net_address_tctrl->ChangeValue(cp->network_address);
1704 m_net_data_protocol_choice->Select(cp->data_protocol);
1706 if (cp->network_port == 0)
1707 m_net_port_tctrl->ChangeValue(
"");
1709 m_net_port_tctrl->ChangeValue(std::to_string(cp->network_port));
1711 if (cp->type == SERIAL) {
1712 m_type_serial_radiobtn->SetValue(
true);
1713 SetNMEAFormToSerial();
1714 SetNMEAFormForSerialProtocol();
1715 }
else if (cp->type == NETWORK) {
1716 m_type_net_radiobtn->SetValue(
true);
1718 }
else if (cp->type == SOCKETCAN) {
1719 m_type_can_radiobtn->SetValue(
true);
1721 }
else if (cp->type == INTERNAL_GPS) {
1722 if (m_type_internal_gps_radiobtn)
1723 m_type_internal_gps_radiobtn->SetValue(
true);
1725 }
else if (cp->type == INTERNAL_BT) {
1726 if (m_type_internal_bt_radiobtn)
1727 m_type_internal_bt_radiobtn->SetValue(
true);
1731 wxString bts = cp->network_address +
";" + cp->serial_port;
1732 m_bt_data_sources_choice->Clear();
1733 m_bt_data_sources_choice->Append(bts);
1734 m_bt_data_sources_choice->SetSelection(0);
1739 if (cp->type == SERIAL) {
1740 m_serial_comment_tctrl->SetValue(cp->user_comment);
1741 }
else if (cp->type == NETWORK) {
1742 m_net_comment_tctrl->SetValue(cp->user_comment);
1743 ConfigureControlsForView(view);
1744 OnExpertModeChange();
1747 m_auth_token_tctrl->SetValue(cp->auth_token);
1749 m_conn_enabled = cp->is_enabled;
1752 m_is_conn_saved =
true;
1755void ConnectionEditDialog::SetDefaultConnectionParams() {
1756 if (m_port_combo && !m_port_combo->IsListEmpty()) {
1757 m_port_combo->Select(0);
1758 m_port_combo->SetValue(wxEmptyString);
1760 m_garmin_host_chkbox->SetValue(
false);
1761 m_input_chkbox->SetValue(
true);
1762 m_output_chkbox->SetValue(
false);
1763 m_accept_radiobtn->SetValue(
true);
1764 m_o_accept_radiobtn->SetValue(
true);
1765 m_input_stc_tctrl->SetValue(wxEmptyString);
1766 m_output_stc_tctrl->SetValue(wxEmptyString);
1767 m_baud_rate_choice->Select(m_baud_rate_choice->FindString(
"4800"));
1770 m_net_comment_tctrl->SetValue(wxEmptyString);
1771 m_serial_comment_tctrl->SetValue(wxEmptyString);
1772 m_auth_token_tctrl->SetValue(wxEmptyString);
1777 bool bserial =
true;
1787 if (m_type_internal_gps_radiobtn) {
1788 m_type_internal_gps_radiobtn->SetValue(
true);
1791 m_type_net_radiobtn->SetValue(
true);
1795 m_type_serial_radiobtn->SetValue(bserial);
1796 m_type_net_radiobtn->SetValue(!bserial);
1797 bserial ? SetNMEAFormToSerial() : SetNMEAFormToNet();
1798 m_type_can_radiobtn->SetValue(
false);
1801 m_conn_enabled =
true;
1804 m_is_conn_saved =
false;
1807void ConnectionEditDialog::LayoutDialog() {
1808 m_net_props_sizer->Layout();
1809 m_ser_props_sizer->Layout();
1812 GetSizer()->Layout();
1815void ConnectionEditDialog::UpdateSourceList(
bool bResort) {
1818 if (panel) panel->Update(cp);
1821 m_scroll_win_connections->Layout();
1824void ConnectionEditDialog::OnSelectDatasource(wxListEvent& event) {
1826 m_remove_btn->Enable();
1827 m_remove_btn->Show();
1831void ConnectionEditDialog::OnDiscoverButton(wxCommandEvent& event) {
1835 std::string serviceIdent =
1836 std::string(
"_signalk-ws._tcp.local.");
1838 g_Platform->ShowBusySpinner();
1840 if (SignalKDataStream::DiscoverSKServer(serviceIdent, ip, port,
1843 m_tNetAddress->SetValue(ip);
1844 m_tNetPort->SetValue(wxString::Format(
"%i", port));
1845 UpdateDiscoverStatus(_(
"Signal K server available."));
1847 UpdateDiscoverStatus(_(
"Signal K server not found."));
1849 g_Platform->HideBusySpinner();
1854void ConnectionEditDialog::UpdateDiscoverStatus(
const wxString& stat) {
1855 m_sk_server_status_text->SetLabel(stat);
1858void ConnectionEditDialog::OnBtnIStcs(wxCommandEvent& event) {
1859 const ListType type = m_accept_radiobtn->GetValue() ? WHITELIST : BLACKLIST;
1860 const wxArrayString list =
1861 wxStringTokenize(m_input_stc_tctrl->GetValue(),
",");
1864 if (dlg.ShowModal() == wxID_OK)
1865 m_input_stc_tctrl->SetValue(dlg.GetSentences());
1868void ConnectionEditDialog::OnBtnOStcs(wxCommandEvent& event) {
1869 const ListType type = m_o_accept_radiobtn->GetValue() ? WHITELIST : BLACKLIST;
1870 const wxArrayString list =
1871 wxStringTokenize(m_output_stc_tctrl->GetValue(),
",");
1874 if (dlg.ShowModal() == wxID_OK)
1875 m_output_stc_tctrl->SetValue(dlg.GetSentences());
1878void ConnectionEditDialog::OnNetProtocolSelected(wxCommandEvent& event) {
1879 SetDSFormRWStates();
1881 OnConnValChange(event);
1884void ConnectionEditDialog::OnRbAcceptInput(wxCommandEvent& event) {
1885 OnConnValChange(event);
1887void ConnectionEditDialog::OnRbIgnoreInput(wxCommandEvent& event) {
1888 OnConnValChange(event);
1891void ConnectionEditDialog::OnRbOutput(wxCommandEvent& event) {
1892 OnConnValChange(event);
1895void ConnectionEditDialog::OnCbInput(wxCommandEvent& event) {
1896 const bool checked = m_input_chkbox->IsChecked();
1897 ShowInFilter(checked);
1898 SetDSFormRWStates();
1900 OnConnValChange(event);
1903void ConnectionEditDialog::OnCbOutput(wxCommandEvent& event) {
1904 OnConnValChange(event);
1905 const bool is_output_enabled = m_output_chkbox->IsChecked();
1906 ShowOutFilter(is_output_enabled);
1908 int selection = m_net_view_choice->GetSelection();
1910 if (selection != wxNOT_FOUND)
1911 view = m_net_view_choice->GetString(selection).ToStdString();
1912 if (view == kUdpInput || view == kMulticastServer) {
1913 if (is_output_enabled) {
1915 NetworkProtocol proto = UDP;
1917 if (cp->net_protocol == proto &&
1918 cp->network_port == wxAtoi(m_net_port_tctrl->GetValue()) &&
1919 cp->direction == PortDirection::kInput) {
1922 if (cp->is_enabled) {
1924 _(
"There is an enabled UDP input connection that uses the "
1927 << _(
"Please apply a filter on both connections to avoid a "
1932 _(
"There is a disabled UDP Input connection that uses the "
1935 << _(
"If you enable that input please apply a filter on both "
1936 "connections to avoid a feedback loop.");
1939 << _(
"Or consider using a different data port for one of them");
1941 OCPNMessageBox(
this, mes, _(
"OpenCPN Warning"),
1942 wxOK | wxICON_EXCLAMATION, 60);
1944 OCPNMessageBox(
this, mes, _(
"OpenCPN info"),
1945 wxOK | wxICON_INFORMATION, 60);
1951 if (view == kUdpReceive || view == kUdpInput) {
1952 m_net_address_tctrl->Hide();
1953 m_net_address_tctrl->Disable();
1954 m_net_addr_text->Hide();
1955 m_net_addr_text->Disable();
1957 SetDSFormRWStates();
1962void ConnectionEditDialog::OnCollapsedToggle(
bool collapsed) {
1963 m_advanced = !collapsed;
1964 if (m_type_net_radiobtn->GetValue())
1965 SetNMEAFormForNetProtocol();
1967 SetNMEAFormForSerialProtocol();
1972void ConnectionEditDialog::OnCbAdvanced(wxCommandEvent& event) {
1973 if (m_type_net_radiobtn->GetValue())
1974 SetNMEAFormForNetProtocol();
1976 SetNMEAFormForSerialProtocol();
1980void ConnectionEditDialog::SetNMEAFormForSerialProtocol() {
1981 bool n0183ctlenabled =
1982 (DataProtocol)m_serial_protocol_choice->GetSelection() ==
1983 DataProtocol::PROTO_NMEA0183;
1984 bool advanced = m_advanced;
1985 ShowNMEACommon(n0183ctlenabled && advanced);
1986 m_garmin_host_chkbox->Show(n0183ctlenabled && advanced);
1988 SetDSFormRWStates();
1992void ConnectionEditDialog::SetNMEAFormForNetProtocol() {
1993 bool n0183ctlenabled =
1994 (DataProtocol)m_net_data_protocol_choice->GetSelection() ==
1995 DataProtocol::PROTO_NMEA0183;
1996 bool advanced = m_advanced;
1997 ShowNMEACommon(n0183ctlenabled && advanced);
1998 m_garmin_host_chkbox->Show(n0183ctlenabled && advanced);
2000 SetDSFormRWStates();
2004void ConnectionEditDialog::OnProtocolChoice(wxCommandEvent& event) {
2005 if (m_type_net_radiobtn->GetValue())
2006 SetNMEAFormForNetProtocol();
2008 SetNMEAFormForSerialProtocol();
2009 OnConnValChange(event);
2014 UpdateConnectionParamsFromControls(pConnectionParams);
2015 return pConnectionParams;
2020 pConnectionParams->is_valid =
true;
2021 int selection = m_net_view_choice->GetSelection();
2022 if (selection != wxNOT_FOUND) {
2023 std::string s = m_net_view_choice->GetString(selection).ToStdString();
2025 if (m_type_serial_radiobtn->GetValue())
2026 pConnectionParams->type = SERIAL;
2027 else if (m_type_net_radiobtn->GetValue())
2028 pConnectionParams->type = NETWORK;
2029 else if (m_type_internal_gps_radiobtn &&
2030 m_type_internal_gps_radiobtn->GetValue())
2031 pConnectionParams->type = INTERNAL_GPS;
2032 else if (m_type_internal_bt_radiobtn &&
2033 m_type_internal_bt_radiobtn->GetValue())
2034 pConnectionParams->type = INTERNAL_BT;
2035 else if (m_type_can_radiobtn && m_type_can_radiobtn->GetValue())
2036 pConnectionParams->type = SOCKETCAN;
2038 if (m_type_net_radiobtn->GetValue()) {
2040 pConnectionParams->last_network_address =
2041 pConnectionParams->network_address;
2042 pConnectionParams->last_network_port = pConnectionParams->network_port;
2043 pConnectionParams->last_net_protocol = pConnectionParams->net_protocol;
2044 pConnectionParams->last_data_protocol = pConnectionParams->data_protocol;
2046 pConnectionParams->network_address =
2047 m_net_address_tctrl->GetValue().Trim(
false).Trim(
true);
2048 pConnectionParams->network_port =
2049 wxAtoi(m_net_port_tctrl->GetValue().Trim(
false).Trim(
true));
2050 int net_select = m_net_view_choice->GetSelection();
2051 std::string net_type;
2052 if (net_select != wxNOT_FOUND)
2053 net_type = m_net_view_choice->GetString(net_select).ToStdString();
2054 if (net_type == kTcpClient || net_type == kTcpServer ||
2055 net_type == kTcpDevice) {
2056 pConnectionParams->net_protocol = TCP;
2057 pConnectionParams->data_protocol =
2058 static_cast<DataProtocol
>(m_net_data_protocol_choice->GetSelection());
2059 }
else if (net_type == kUdpSend || net_type == kUdpInput ||
2060 net_type == kUdpReceive || net_type == kMulticastClient ||
2061 net_type == kMulticastServer) {
2062 pConnectionParams->net_protocol = UDP;
2063 pConnectionParams->data_protocol =
2064 static_cast<DataProtocol
>(m_net_data_protocol_choice->GetSelection());
2065 }
else if (net_type == kGpsdClient || net_type == kGpsdDevice) {
2066 pConnectionParams->net_protocol = GPSD;
2067 }
else if (net_type == kSignalkClient || net_type == kSignalkDevice) {
2068 pConnectionParams->net_protocol = SIGNALK;
2070 pConnectionParams->net_protocol = PROTO_UNDEFINED;
2073 if (m_type_serial_radiobtn->GetValue())
2074 pConnectionParams->data_protocol =
2075 (DataProtocol)m_serial_protocol_choice->GetSelection();
2076 else if (m_type_net_radiobtn->GetValue())
2077 pConnectionParams->data_protocol =
2078 (DataProtocol)m_net_data_protocol_choice->GetSelection();
2080 pConnectionParams->baudrate =
2081 wxAtoi(m_baud_rate_choice->GetStringSelection());
2082 pConnectionParams->checksum_check =
true;
2083 pConnectionParams->auto_sk_discover = m_sk_check_discover_chkbox->GetValue();
2084 pConnectionParams->is_garmin = m_garmin_host_chkbox->GetValue();
2085 pConnectionParams->input_sentence_list =
2086 wxStringTokenize(m_input_stc_tctrl->GetValue(),
",");
2087 if (m_accept_radiobtn->GetValue())
2088 pConnectionParams->input_sentence_list_type = WHITELIST;
2090 pConnectionParams->input_sentence_list_type = BLACKLIST;
2091 if (m_input_chkbox->GetValue()) {
2092 if (m_output_chkbox->GetValue()) {
2093 pConnectionParams->direction = PortDirection::kInOut;
2095 pConnectionParams->direction = PortDirection::kInput;
2098 pConnectionParams->direction = PortDirection::kOutput;
2100 pConnectionParams->output_sentence_list =
2101 wxStringTokenize(m_output_stc_tctrl->GetValue(),
",");
2102 if (m_o_accept_radiobtn->GetValue())
2103 pConnectionParams->output_sentence_list_type = WHITELIST;
2105 pConnectionParams->output_sentence_list_type = BLACKLIST;
2106 pConnectionParams->serial_port = m_port_combo->GetValue().BeforeFirst(
' ');
2107#if defined(__linux__) && !defined(__ANDROID__)
2108 if (pConnectionParams->type == SERIAL)
2112 if (m_type_can_radiobtn && m_type_can_radiobtn->GetValue())
2113 pConnectionParams->data_protocol = PROTO_NMEA2000;
2115 pConnectionParams->is_enabled = m_conn_enabled;
2116 pConnectionParams->is_setup =
false;
2118 if (pConnectionParams->type == INTERNAL_GPS) {
2119 pConnectionParams->network_address =
"";
2120 pConnectionParams->network_port = 0;
2121 pConnectionParams->net_protocol = PROTO_UNDEFINED;
2122 pConnectionParams->baudrate = 0;
2123 pConnectionParams->serial_port =
"Internal GPS";
2126 if (pConnectionParams->type == INTERNAL_BT) {
2127 wxString parms = m_bt_data_sources_choice->GetStringSelection();
2128 wxStringTokenizer tkz(parms,
";");
2129 wxString name = tkz.GetNextToken();
2130 wxString mac = tkz.GetNextToken();
2132 pConnectionParams->network_address = name;
2133 pConnectionParams->serial_port = mac;
2134 pConnectionParams->network_port = 0;
2135 pConnectionParams->net_protocol = PROTO_UNDEFINED;
2136 pConnectionParams->baudrate = 0;
2140 if (pConnectionParams->type == SOCKETCAN) {
2141 pConnectionParams->network_address =
"";
2142 pConnectionParams->network_port = 0;
2143 pConnectionParams->net_protocol = PROTO_UNDEFINED;
2144 pConnectionParams->baudrate = 0;
2145 pConnectionParams->socket_can_port =
2146 m_can_source_choice->GetString(m_can_source_choice->GetSelection());
2148 if (pConnectionParams->type == SERIAL) {
2149 pConnectionParams->user_comment = m_serial_comment_tctrl->GetValue();
2150 }
else if (pConnectionParams->type == NETWORK) {
2151 pConnectionParams->user_comment = m_net_comment_tctrl->GetValue();
2153 pConnectionParams->auth_token = m_auth_token_tctrl->GetValue();
2155 return pConnectionParams;
2158void ConnectionEditDialog::OnPriorityDialog(wxCommandEvent& event) {
2163void ConnectionEditDialog::ConnectControls() {
2165 m_type_serial_radiobtn->Connect(
2166 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2167 wxCommandEventHandler(ConnectionEditDialog::OnTypeSerialSelected),
2169 m_type_net_radiobtn->Connect(
2170 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2171 wxCommandEventHandler(ConnectionEditDialog::OnTypeNetSelected),
nullptr,
2173 m_type_can_radiobtn->Connect(
2174 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2175 wxCommandEventHandler(ConnectionEditDialog::OnTypeCANSelected),
nullptr,
2177 if (m_type_internal_gps_radiobtn)
2178 m_type_internal_gps_radiobtn->Connect(
2179 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2180 wxCommandEventHandler(ConnectionEditDialog::OnTypeGPSSelected),
nullptr,
2182 if (m_type_internal_bt_radiobtn)
2183 m_type_internal_bt_radiobtn->Connect(
2184 wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2185 wxCommandEventHandler(ConnectionEditDialog::OnTypeBTSelected),
nullptr,
2188 m_net_data_protocol_choice->Connect(
2189 wxEVT_COMMAND_CHOICE_SELECTED,
2190 wxCommandEventHandler(ConnectionEditDialog::OnProtocolChoice),
nullptr,
2192 m_serial_protocol_choice->Connect(
2193 wxEVT_COMMAND_CHOICE_SELECTED,
2194 wxCommandEventHandler(ConnectionEditDialog::OnProtocolChoice),
nullptr,
2198 m_input_chkbox->Connect(
2199 wxEVT_COMMAND_CHECKBOX_CLICKED,
2200 wxCommandEventHandler(ConnectionEditDialog::OnCbInput),
nullptr,
this);
2201 m_output_chkbox->Connect(
2202 wxEVT_COMMAND_CHECKBOX_CLICKED,
2203 wxCommandEventHandler(ConnectionEditDialog::OnCbOutput),
nullptr,
this);
2206 m_scan_bt_btn->Connect(
2207 wxEVT_COMMAND_BUTTON_CLICKED,
2208 wxCommandEventHandler(ConnectionEditDialog::OnScanBtClick),
nullptr,
2211 m_input_stc_list_btn->Connect(
2212 wxEVT_COMMAND_BUTTON_CLICKED,
2213 wxCommandEventHandler(ConnectionEditDialog::OnBtnIStcs),
nullptr,
this);
2216 m_output_stc_list_btn->Connect(
2217 wxEVT_COMMAND_BUTTON_CLICKED,
2218 wxCommandEventHandler(ConnectionEditDialog::OnBtnOStcs),
nullptr,
this);
2221SentenceListDlg::SentenceListDlg(wxWindow* parent, FilterDirection dir,
2222 ListType type,
const wxArrayString& list)
2223 : wxDialog(parent, wxID_ANY, _(
"Sentence Filter"), wxDefaultPosition,
2227 m_sentences(NMEA0183().GetRecognizedArray()) {
2229 auto* mainSizer =
new wxBoxSizer(wxVERTICAL);
2230 auto* secondSizer =
new wxBoxSizer(wxHORIZONTAL);
2231 auto* pclbBox =
new wxStaticBox(
this, wxID_ANY, GetBoxLabel());
2232 auto* stcSizer =
new wxStaticBoxSizer(pclbBox, wxVERTICAL);
2233 m_sentences_clb =
new wxCheckListBox(
this, wxID_ANY, wxDefaultPosition,
2234 wxDefaultSize, m_sentences);
2235 auto* btnEntrySizer =
new wxBoxSizer(wxVERTICAL);
2236 auto* btnCheckAll =
new wxButton(
this, wxID_ANY, _(
"Select All"));
2237 auto* btnClearAll =
new wxButton(
this, wxID_ANY, _(
"Clear All"));
2238 auto* btnAdd =
new wxButton(
this, wxID_ANY, _(
"Add"));
2239 m_del_btn =
new wxButton(
this, wxID_ANY, _(
"Delete"));
2240 m_del_btn->Disable();
2241 auto* btnSizer =
new wxStdDialogButtonSizer();
2242 auto* btnOK =
new wxButton(
this, wxID_OK);
2243 auto* btnCancel =
new wxButton(
this, wxID_CANCEL, _(
"Cancel"));
2245 secondSizer->Add(stcSizer, 1, wxALL | wxEXPAND, 5);
2246 stcSizer->Add(m_sentences_clb, 1, wxALL | wxEXPAND, 5);
2247 btnEntrySizer->Add(btnCheckAll, 0, wxALL, 5);
2248 btnEntrySizer->Add(btnClearAll, 0, wxALL, 5);
2249 btnEntrySizer->AddSpacer(1);
2250 btnEntrySizer->Add(btnAdd, 0, wxALL, 5);
2251 btnEntrySizer->Add(m_del_btn, 0, wxALL, 5);
2252 secondSizer->Add(btnEntrySizer, 0, wxALL | wxEXPAND, 5);
2253 mainSizer->Add(secondSizer, 1, wxEXPAND, 5);
2254 btnSizer->AddButton(btnOK);
2255 btnSizer->AddButton(btnCancel);
2256 btnSizer->Realize();
2257 mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
2259 SetSizer(mainSizer);
2260 mainSizer->SetSizeHints(
this);
2263 btnAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2264 wxCommandEventHandler(SentenceListDlg::OnAddClick),
nullptr,
2266 m_del_btn->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2267 wxCommandEventHandler(SentenceListDlg::OnDeleteClick),
2269 m_sentences_clb->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
2270 wxCommandEventHandler(SentenceListDlg::OnCLBSelect),
2272 btnCheckAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2273 wxCommandEventHandler(SentenceListDlg::OnCheckAllClick),
2275 btnClearAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2276 wxCommandEventHandler(SentenceListDlg::OnClearAllClick),
2281wxString SentenceListDlg::GetBoxLabel()
const {
2282 if (m_dir == FILTER_OUTPUT)
2283 return m_type == WHITELIST ? _(
"Transmit sentences") : _(
"Drop sentences");
2285 return m_type == WHITELIST ? _(
"Accept only sentences")
2286 : _(
"Ignore sentences");
2289void SentenceListDlg::Populate(
const wxArrayString& list) {
2290 if (m_dir == FILTER_OUTPUT) {
2292 m_sentences.Add(g_TalkerIdText + wxString(
"RMB"));
2293 m_sentences.Add(g_TalkerIdText + wxString(
"RMC"));
2294 m_sentences.Add(g_TalkerIdText + wxString(
"APB"));
2295 m_sentences.Add(g_TalkerIdText + wxString(
"XTE"));
2297 m_sentences.Add(
"AIVDM");
2298 m_sentences.Add(
"AIVDO");
2299 m_sentences.Add(
"FRPOS");
2300 m_sentences.Add(g_TalkerIdText);
2301 m_sentences.Add(
"CD");
2303 m_sentences_clb->Clear();
2304 m_sentences_clb->InsertItems(m_sentences, 0);
2306 wxArrayString new_strings;
2307 if (list.Count() == 0) {
2308 for (
size_t i = 0; i < m_sentences_clb->GetCount(); ++i)
2309 m_sentences_clb->Check(i, m_type == WHITELIST);
2311 for (
size_t i = 0; i < list.Count(); ++i) {
2312 int item = m_sentences_clb->FindString(list[i]);
2313 if (item != wxNOT_FOUND)
2314 m_sentences_clb->Check(item);
2316 new_strings.Add(list[i]);
2318 if (new_strings.GetCount()) {
2319 m_sentences_clb->InsertItems(new_strings, m_sentences_clb->GetCount());
2320 for (
size_t i = 0; i < new_strings.GetCount(); ++i) {
2321 int item = m_sentences_clb->FindString(new_strings[i]);
2322 if (item != wxNOT_FOUND) m_sentences_clb->Check(item);
2328wxString SentenceListDlg::GetSentences() {
2329 wxArrayString retString;
2330 for (
size_t i = 0; i < m_sentences_clb->GetCount(); i++) {
2331 if (m_sentences_clb->IsChecked(i))
2332 retString.Add(m_sentences_clb->GetString(i));
2334 return StringArrayToString(retString);
2337void SentenceListDlg::OnCLBSelect(wxCommandEvent& e) {
2340 m_del_btn->Enable(m_sentences.Index(e.GetString()) == wxNOT_FOUND);
2343void SentenceListDlg::OnAddClick(wxCommandEvent& event) {
2345 androidDisableRotation();
2348 wxTextEntryDialog textdlg(
2350 _(
"Enter the NMEA sentence (2, 3 or 5 characters)\n or a valid REGEX "
2351 "expression (6 characters or longer)"),
2352 _(
"Enter the NMEA sentence"));
2354 textdlg.SetTextValidator(wxFILTER_ASCII);
2355 int result = textdlg.ShowModal();
2358 androidEnableRotation();
2361 if (result == wxID_CANCEL)
return;
2362 wxString stc = textdlg.GetValue();
2364 if (stc.Length() == 2 || stc.Length() == 3 || stc.Length() == 5) {
2365 m_sentences_clb->Append(stc);
2366 m_sentences_clb->Check(m_sentences_clb->FindString(stc));
2368 }
else if (stc.Length() < 2) {
2371 _(
"An NMEA sentence is generally 3 characters long (like RMC, GGA etc.)\n \
2372 It can also have a two letter prefix identifying the source, or TALKER, of the message.\n \
2373 The whole sentences then looks like GPGGA or AITXT.\n \
2374 You may filter out all the sentences with certain TALKER prefix (like GP, AI etc.).\n \
2375 The filter also accepts Regular Expressions (REGEX) with 6 or more characters. \n\n"),
2384 m_sentences_clb->Append(stc);
2385 m_sentences_clb->Check(m_sentences_clb->FindString(stc));
2388 OCPNMessageBox(
this, _(
"REGEX syntax error: \n") + stc,
2395void SentenceListDlg::OnDeleteClick(wxCommandEvent& event) {
2396 m_sentences_clb->Delete(m_sentences_clb->GetSelection());
2399void SentenceListDlg::OnClearAllClick(wxCommandEvent& event) {
2400 for (
size_t i = 0; i < m_sentences_clb->GetCount(); i++)
2401 m_sentences_clb->Check(i,
false);
2404void SentenceListDlg::OnCheckAllClick(wxCommandEvent& event) {
2405 for (
size_t i = 0; i < m_sentences_clb->GetCount(); i++)
2406 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.
Connection data container close to a POD struct.
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.
std::vector< ConnectionParams * > & TheConnectionParams()
Return global list of connections.
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.