40#include <wx/msw/winundef.h>
46#include <netinet/tcp.h>
54#include <wx/tokenzr.h>
55#include <wx/datetime.h>
60#include <wx/chartype.h>
61#include <wx/sckaddr.h>
68#define N_DOG_TIMEOUT 8
70using namespace std::literals::chrono_literals;
72static const int kNotFound = -1;
77 void SetMrqAddr(
unsigned int addr) {
78 m_mrq.imr_multiaddr.s_addr = addr;
79 m_mrq.imr_interface.s_addr = INADDR_ANY;
85 : priority(
'\0'), source(
'\0'), destination(
'\0'), pgn(-1) {};
92class CommDriverN2KNetEvent :
public wxEvent {
94 CommDriverN2KNetEvent(wxEventType commandType = wxEVT_NULL,
int id = 0)
95 : wxEvent(
id, commandType) {};
96 ~CommDriverN2KNetEvent()
override =
default;
99 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
102 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
105 [[nodiscard]] wxEvent* Clone()
const override {
106 auto* newevent =
new CommDriverN2KNetEvent(*
this);
107 newevent->m_payload = this->m_payload;
112 std::shared_ptr<std::vector<unsigned char>> m_payload;
115static uint64_t PayloadToName(
const std::vector<unsigned char>& payload) {
117 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
125#define TIMER_SOCKET_N2KNET 7339
128EVT_TIMER(TIMER_SOCKET_N2KNET, CommDriverN2KNet::OnTimerSocket)
130EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN2KNet::OnServerSocketEvent)
131EVT_TIMER(TIMER_SOCKET_N2KNET + 1, CommDriverN2KNet::OnSocketReadWatchdogTimer)
140 m_listener(listener),
141 m_stats_timer(*this, 2s),
142 m_net_port(wxString::Format(
"%i", params->network_port)),
143 m_net_protocol(params->net_protocol),
146 m_socket_server(
nullptr),
147 m_is_multicast(false),
149 m_portstring(params->GetDSPort()),
150 m_direction(params->direction),
151 m_connection_type(params->type),
153 m_circle(RX_BUFFER_SIZE_NET),
154 m_TX_available(false),
156 m_addr.Hostname(params->network_address);
157 m_addr.Service(params->network_port);
159 m_driver_stats.driver_bus = NavAddr::Bus::N2000;
160 m_driver_stats.driver_iface = params->GetStrippedDSPort();
162 m_socket_timer.SetOwner(
this, TIMER_SOCKET_N2KNET);
163 m_socketread_watchdog_timer.SetOwner(
this, TIMER_SOCKET_N2KNET + 1);
164 this->attributes[
"netAddress"] = params->network_address.ToStdString();
166 sprintf(port_char,
"%d", params->network_port);
167 this->attributes[
"netPort"] = std::string(port_char);
168 this->attributes[
"userComment"] = params->user_comment.ToStdString();
172 Bind(wxEVT_COMMDRIVER_N2K_NET, &CommDriverN2KNet::handle_N2K_MSG,
this);
174 m_prodinfo_timer.Connect(
175 wxEVT_TIMER, wxTimerEventHandler(CommDriverN2KNet::OnProdInfoTimer),
182 rx_buffer =
new unsigned char[RX_BUFFER_SIZE_NET + 1];
186 m_n2k_format = N2KFormat_YD_RAW;
189 resume_listener.Init(SystemEvents::GetInstance().evt_resume,
195CommDriverN2KNet::~CommDriverN2KNet() {
196 delete m_mrq_container;
203 std::string Model_ID;
207std::unordered_map<uint8_t, product_info> prod_info_map;
209bool CommDriverN2KNet::HandleMgntMsg(
210 uint64_t pgn,
const std::vector<unsigned char>& payload) {
212 auto name = PayloadToName(payload);
214 std::make_shared<const Nmea2000Msg>(pgn, payload, GetAddress(name));
216 bool b_handled =
false;
219 uint8_t src_addr = payload.at(7);
220 if (src_addr == 75)
return false;
222 pr_info.Model_ID = std::string((
char*)&payload.data()[17], 32);
223 pr_info.RT_flag = m_TX_flag;
225 prod_info_map[src_addr] = pr_info;
230 uint8_t src_addr = payload.at(7);
240void CommDriverN2KNet::OnProdInfoTimer(wxTimerEvent& ev) {
242 bool b_found =
false;
243 for (
const auto& [key, value] : prod_info_map) {
244 auto prod_info = value;
245 if (prod_info.Model_ID.find(
"YDEN") != std::string::npos) {
250 if (prod_info.RT_flag ==
'T') b_found =
true;
255 if (b_found) m_TX_available =
true;
256 prod_info_map.clear();
260 auto p =
event.GetPayload();
261 std::vector<unsigned char>* payload = p.get();
265 auto* c = (
unsigned char*)&pgn;
266 *c++ = payload->at(3);
267 *c++ = payload->at(4);
268 *c++ = payload->at(5);
272 auto name = PayloadToName(*payload);
274 std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
275 m_driver_stats.rx_count += payload->size();
276 m_listener.Notify(std::move(msg));
279void CommDriverN2KNet::Open() {
281#if wxCHECK_VERSION(3, 0, 0)
283 ((
struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
286 ((
struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
289 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
292 switch (m_net_protocol) {
294 OpenNetworkTCP(addr);
298 OpenNetworkUDP(addr);
307void CommDriverN2KNet::OpenNetworkUDP(
unsigned int addr) {
308 if (m_params.direction != PortDirection::kOutput &&
309 m_params.direction != PortDirection::kUpload) {
312 wxIPV4address conn_addr;
313 conn_addr.Service(GetNetPort());
314 conn_addr.AnyAddress();
316 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
319 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
321 m_mrq_container->SetMrqAddr(addr);
322 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP,
323 &m_mrq_container->m_mrq,
324 sizeof(m_mrq_container->m_mrq));
327 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
329 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
331 GetSock()->Notify(TRUE);
332 GetSock()->SetTimeout(1);
333 m_driver_stats.available =
true;
337 if (GetPortDirection() != PortDirection::kInput) {
338 wxIPV4address tconn_addr;
339 tconn_addr.Service(0);
340 tconn_addr.AnyAddress();
342 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
347 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(
"255"))) {
348 int broadcastEnable = 1;
349 GetTSock()->SetOption(SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
350 sizeof(broadcastEnable));
352 m_driver_stats.available =
true;
356 SetConnectTime(wxDateTime::Now());
359void CommDriverN2KNet::OpenNetworkTCP(
unsigned int addr) {
360 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
361 wxLogMessage(wxString::Format(
"Opening TCP Server %d", isServer));
364 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
366 SetSock(
new wxSocketClient());
370 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
371 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
372 GetSockServer()->Notify(TRUE);
373 GetSockServer()->SetTimeout(1);
375 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
376 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
377 if (GetPortDirection() != PortDirection::kInput)
378 notify_flags |= wxSOCKET_OUTPUT_FLAG;
379 if (GetPortDirection() != PortDirection::kOutput)
380 notify_flags |= wxSOCKET_INPUT_FLAG;
381 GetSock()->SetNotify(notify_flags);
382 GetSock()->Notify(TRUE);
383 GetSock()->SetTimeout(1);
385 SetBrxConnectEvent(
false);
386 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
390 SetConnectTime(wxDateTime::Now());
391 m_driver_stats.available = GetSock() && GetSock()->IsOk();
394void CommDriverN2KNet::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
397 if (m_dog_value <= 0) {
398 if (GetParams().no_data_reconnect) {
400 if (GetProtocol() == TCP) {
401 auto* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
402 if (tcp_socket) tcp_socket->Close();
404 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
405 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
407 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
410 GetSocketThreadWatchdogTimer()->Stop();
416void CommDriverN2KNet::OnTimerSocket() {
418 auto* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
420 if (tcp_socket->IsDisconnected()) {
421 wxLogDebug(
" Attempting reconnection...");
422 SetBrxConnectEvent(
false);
424 GetSocketThreadWatchdogTimer()->Stop();
425 tcp_socket->Connect(GetAddr(), FALSE);
428 int n_reconnect_delay = N_DOG_TIMEOUT;
429 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
431 m_driver_stats.available =
true;
436void CommDriverN2KNet::HandleResume() {
438 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
440 GetSocketThreadWatchdogTimer()->Stop();
445 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
446 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
449 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
453bool CommDriverN2KNet::SendMessage(std::shared_ptr<const NavMsg> msg,
454 std::shared_ptr<const NavAddr> addr) {
455 if (!msg)
return false;
456 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
457 auto dest_addr_n2k = std::static_pointer_cast<const NavAddr2000>(addr);
458 return SendN2KNetwork(msg_n2k, dest_addr_n2k);
461std::vector<unsigned char> CommDriverN2KNet::PrepareLogPayload(
462 const std::shared_ptr<const Nmea2000Msg>& msg,
463 const std::shared_ptr<const NavAddr2000>& addr) {
464 std::vector<unsigned char> data;
465 data.push_back(0x94);
466 data.push_back(0x13);
467 data.push_back(msg->priority);
468 data.push_back(msg->PGN.pgn & 0xFF);
469 data.push_back((msg->PGN.pgn >> 8) & 0xFF);
470 data.push_back((msg->PGN.pgn >> 16) & 0xFF);
471 data.push_back(addr->address);
472 data.push_back(addr->address);
473 for (
size_t n = 0; n < msg->payload.size(); n++)
474 data.push_back(msg->payload[n]);
475 data.push_back(0x55);
479std::vector<unsigned char> CommDriverN2KNet::PushCompleteMsg(
480 const CanHeader& header,
int position,
const can_frame& frame) {
481 std::vector<unsigned char> data;
482 data.push_back(0x93);
483 data.push_back(0x13);
484 data.push_back(header.priority);
485 data.push_back(header.pgn & 0xFF);
486 data.push_back((header.pgn >> 8) & 0xFF);
487 data.push_back((header.pgn >> 16) & 0xFF);
488 data.push_back(header.destination);
489 data.push_back(header.source);
490 data.push_back(0xFF);
491 data.push_back(0xFF);
492 data.push_back(0xFF);
493 data.push_back(0xFF);
494 data.push_back(CAN_MAX_DLEN);
495 for (
size_t n = 0; n < CAN_MAX_DLEN; n++) data.push_back(frame.data[n]);
496 data.push_back(0x55);
500std::vector<unsigned char> CommDriverN2KNet::PushFastMsgFragment(
502 std::vector<unsigned char> data;
503 data.push_back(0x93);
504 data.push_back(fast_messages->entries[position].expected_length + 11);
505 data.push_back(header.priority);
506 data.push_back(header.pgn & 0xFF);
507 data.push_back((header.pgn >> 8) & 0xFF);
508 data.push_back((header.pgn >> 16) & 0xFF);
509 data.push_back(header.destination);
510 data.push_back(header.source);
511 data.push_back(0xFF);
512 data.push_back(0xFF);
513 data.push_back(0xFF);
514 data.push_back(0xFF);
515 data.push_back(fast_messages->entries[position].expected_length);
516 for (
size_t n = 0; n < fast_messages->entries[position].expected_length; n++)
517 data.push_back(fast_messages->entries[position].data[n]);
518 data.push_back(0x55);
519 fast_messages->Remove(position);
529void CommDriverN2KNet::HandleCanFrameInput(
const can_frame& frame) {
533 CanHeader header(frame);
535 position = fast_messages->FindMatchingEntry(header, frame.data[0]);
536 if (position == kNotFound) {
543 if ((frame.data[0] & 0x1F) == 0) {
544 position = fast_messages->AddNewEntry();
545 ready = fast_messages->InsertEntry(header, frame.data, position);
550 ready = fast_messages->AppendEntry(header, frame.data, position);
554 std::vector<unsigned char> vec;
557 vec = PushFastMsgFragment(header, position);
560 vec = PushCompleteMsg(header, position, frame);
564 if (HandleMgntMsg(header.pgn, vec))
return;
567 CommDriverN2KNetEvent Nevent(wxEVT_COMMDRIVER_N2K_NET, 0);
568 auto payload = std::make_shared<std::vector<uint8_t>>(vec);
569 Nevent.SetPayload(payload);
570 AddPendingEvent(Nevent);
574static bool isASCII(
const std::vector<unsigned char>& packet) {
575 for (
unsigned char c : packet) {
576 if (!isascii(c))
return false;
581N2K_Format CommDriverN2KNet::DetectFormat(
582 const std::vector<unsigned char>& packet) {
587 if (isASCII(packet)) {
588 std::string payload = std::string(packet.begin(), packet.end());
589 if (payload.find(
"$PCDIN") != std::string::npos) {
590 return N2KFormat_SeaSmart;
591 }
else if (payload.find(
"$MXPGN") != std::string::npos) {
595 return N2KFormat_MiniPlex;
596 }
else if (std::find(packet.begin(), packet.end(),
':') != packet.end()) {
597 return N2KFormat_Actisense_RAW_ASCII;
599 return N2KFormat_Actisense_N2K_ASCII;
602 if (packet[2] == 0x95)
603 return N2KFormat_Actisense_RAW;
604 else if (packet[2] == 0xd0)
605 return N2KFormat_Actisense_N2K;
606 else if (packet[2] == 0x93)
607 return N2KFormat_Actisense_NGT;
609 return N2KFormat_Undefined;
612bool CommDriverN2KNet::ProcessActisense_N2K(
613 const std::vector<unsigned char>& packet) {
616 std::vector<unsigned char> data;
618 bool bGotESC =
false;
619 bool bGotSOT =
false;
621 while (!m_circle.IsEmpty()) {
622 uint8_t next_byte = m_circle.Get();
626 if (next_byte == ESCAPE) {
627 data.push_back(next_byte);
629 }
else if (next_byte == ENDOFTEXT) {
633 unsigned int msg_length =
634 (uint32_t)data[1] + ((uint32_t)data[2] << 8);
637 if (msg_length == data.size() - 1) {
638 uint8_t destination = data[3];
639 uint8_t source = data[4];
641 uint8_t dprp = data[7];
644 uint8_t rAndDP = dprp & 3;
647 uint8_t pduFormat = data[6];
648 uint32_t pgn = (rAndDP << 16) + (pduFormat << 8);
654 std::vector<uint8_t> o_payload;
655 o_payload.push_back(0x93);
656 o_payload.push_back(0x13);
657 o_payload.push_back(priority);
658 o_payload.push_back(pgn & 0xFF);
659 o_payload.push_back((pgn >> 8) & 0xFF);
660 o_payload.push_back((pgn >> 16) & 0xFF);
661 o_payload.push_back(destination);
662 o_payload.push_back(source);
663 o_payload.push_back(0xFF);
664 o_payload.push_back(0xFF);
665 o_payload.push_back(0xFF);
666 o_payload.push_back(0xFF);
667 o_payload.push_back(data.size());
670 for (
size_t n = 13; n < data.size() - 1; n++)
671 o_payload.push_back(data[n]);
673 o_payload.push_back(0x55);
676 CommDriverN2KNetEvent Nevent(wxEVT_COMMDRIVER_N2K_NET, 0);
678 std::make_shared<std::vector<uint8_t>>(o_payload);
679 Nevent.SetPayload(n2k_payload);
680 AddPendingEvent(Nevent);
687 }
else if (next_byte == STARTOFTEXT) {
696 bGotESC = (next_byte == ESCAPE);
699 data.push_back(next_byte);
705 if (STARTOFTEXT == next_byte) {
711 bGotESC = (next_byte == ESCAPE);
716 data.push_back(next_byte);
725bool CommDriverN2KNet::ProcessActisense_RAW(
726 const std::vector<unsigned char>& packet) {
731 std::vector<unsigned char> data;
733 bool bGotESC =
false;
734 bool bGotSOT =
false;
736 while (!m_circle.IsEmpty()) {
737 uint8_t next_byte = m_circle.Get();
741 if (next_byte == ESCAPE) {
742 data.push_back(next_byte);
744 }
else if (next_byte == ENDOFTEXT) {
749 if (data.size() >= 8) {
750 size_t dLen = data[1];
752 if (dLen + 3 == data.size()) {
754 memcpy(&frame.can_id, &data.data()[4], 4);
757 memcpy(&frame.data, &data.data()[8], 8);
759 HandleCanFrameInput(frame);
767 }
else if (next_byte == STARTOFTEXT) {
776 bGotESC = (next_byte == ESCAPE);
779 data.push_back(next_byte);
785 if (STARTOFTEXT == next_byte) {
791 bGotESC = (next_byte == ESCAPE);
796 data.push_back(next_byte);
805bool CommDriverN2KNet::ProcessActisense_NGT(
806 const std::vector<unsigned char>& packet) {
807 std::vector<unsigned char> data;
809 bool bGotESC =
false;
810 bool bGotSOT =
false;
812 while (!m_circle.IsEmpty()) {
813 uint8_t next_byte = m_circle.Get();
817 if (next_byte == ESCAPE) {
818 data.push_back(next_byte);
820 }
else if (next_byte == ENDOFTEXT) {
822 CommDriverN2KNetEvent Nevent(wxEVT_COMMDRIVER_N2K_NET, 0);
823 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(data);
824 Nevent.SetPayload(n2k_payload);
825 AddPendingEvent(Nevent);
831 }
else if (next_byte == STARTOFTEXT) {
840 bGotESC = (next_byte == ESCAPE);
843 data.push_back(next_byte);
849 if (STARTOFTEXT == next_byte) {
855 bGotESC = (next_byte == ESCAPE);
860 data.push_back(next_byte);
869bool CommDriverN2KNet::ProcessActisense_ASCII_RAW(
870 const std::vector<unsigned char>& packet) {
873 while (!m_circle.IsEmpty()) {
874 char b = m_circle.Get();
875 if ((b != 0x0a) && (b != 0x0d)) {
883 wxString ss(m_sentence.c_str());
885 wxStringTokenizer tkz(ss,
" ");
888 wxString token = tkz.GetNextToken();
890 token = tkz.GetNextToken();
892 m_TX_flag = token[0];
895 token = tkz.GetNextToken();
897 token.ToLong(&canID, 16);
898 frame.can_id = canID;
901 unsigned char bytes[8];
903 for (
unsigned int i = 0; i < 8; i++) {
904 if (tkz.HasMoreTokens()) {
905 token = tkz.GetNextToken();
907 token.ToLong(&tui, 16);
908 bytes[i] = (uint8_t)tui;
911 memcpy(&frame.data, bytes, 8);
912 HandleCanFrameInput(frame);
918bool CommDriverN2KNet::ProcessActisense_ASCII_N2K(
919 const std::vector<unsigned char>& packet) {
921 std::string sentence;
923 while (!m_circle.IsEmpty()) {
924 char b = m_circle.Get();
925 if ((b != 0x0a) && (b != 0x0d)) {
933 wxString ss(sentence.c_str());
934 wxStringTokenizer tkz(ss,
" ");
938 wxString time_header = tkz.GetNextToken();
940 wxString sprio_addr = tkz.GetNextToken();
942 sprio_addr.ToLong(&prio_addr, 16);
943 uint8_t priority = (uint8_t)prio_addr & 0X0F;
944 uint8_t destination = (uint8_t)(prio_addr >> 4) & 0X0FF;
945 uint8_t source = (uint8_t)(prio_addr >> 12) & 0X0FF;
948 wxString sPGN = tkz.GetNextToken();
950 sPGN.ToULong(&PGN, 16);
954 wxString sdata = tkz.GetNextToken();
955 std::vector<uint8_t> data;
956 for (
size_t i = 0; i < sdata.Length(); i += 2) {
958 wxString stui = sdata.Mid(i, 2);
959 stui.ToLong(&dv, 16);
960 data.push_back((uint8_t)dv);
964 std::vector<uint8_t> o_payload;
965 o_payload.push_back(0x93);
966 o_payload.push_back(0x13);
967 o_payload.push_back(priority);
968 o_payload.push_back(PGN & 0xFF);
969 o_payload.push_back((PGN >> 8) & 0xFF);
970 o_payload.push_back((PGN >> 16) & 0xFF);
971 o_payload.push_back(destination);
972 o_payload.push_back(source);
973 o_payload.push_back(0xFF);
974 o_payload.push_back(0xFF);
975 o_payload.push_back(0xFF);
976 o_payload.push_back(0xFF);
977 o_payload.push_back(data.size());
978 for (
size_t n = 0; n < data.size(); n++) o_payload.push_back(data[n]);
979 o_payload.push_back(0x55);
981 if (HandleMgntMsg(PGN, o_payload))
return false;
984 CommDriverN2KNetEvent Nevent(wxEVT_COMMDRIVER_N2K_NET, 0);
985 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
986 Nevent.SetPayload(n2k_payload);
987 AddPendingEvent(Nevent);
993bool CommDriverN2KNet::ProcessSeaSmart(
994 const std::vector<unsigned char>& packet) {
995 while (!m_circle.IsEmpty()) {
996 char b = m_circle.Get();
997 if ((b != 0x0a) && (b != 0x0d)) {
1005 wxString ss(m_sentence.c_str());
1007 wxStringTokenizer tkz(ss,
",");
1010 wxString token = tkz.GetNextToken();
1013 token = tkz.GetNextToken();
1015 token.ToULong(&PGN, 16);
1017 token = tkz.GetNextToken();
1018 unsigned long timestamp;
1019 token.ToULong(×tamp, 16);
1021 token = tkz.GetNextToken();
1022 unsigned long source;
1023 token.ToULong(&source, 16);
1025 token = tkz.GetNextToken();
1027 wxStringTokenizer datatkz(token,
"*");
1028 wxString data = datatkz.GetNextToken();
1031 std::vector<uint8_t> o_payload;
1032 o_payload.push_back(0x93);
1033 o_payload.push_back(0x13);
1034 o_payload.push_back(3);
1035 o_payload.push_back(PGN & 0xFF);
1036 o_payload.push_back((PGN >> 8) & 0xFF);
1037 o_payload.push_back((PGN >> 16) & 0xFF);
1038 o_payload.push_back(0xFF);
1039 o_payload.push_back((uint8_t)source);
1040 o_payload.push_back(timestamp & 0xFF);
1041 o_payload.push_back((timestamp >> 8) & 0xFF);
1042 o_payload.push_back((timestamp >> 16) & 0xFF);
1043 o_payload.push_back((timestamp >> 24) & 0xFF);
1044 o_payload.push_back((uint8_t)data.Length() / 2);
1045 for (
size_t i = 0; i < data.Length(); i += 2) {
1047 wxString sbyte = data.Mid(i, 2);
1048 sbyte.ToULong(&dv, 16);
1049 o_payload.push_back((uint8_t)dv);
1051 o_payload.push_back(0x55);
1053 if (HandleMgntMsg(PGN, o_payload))
return false;
1056 CommDriverN2KNetEvent Nevent(wxEVT_COMMDRIVER_N2K_NET, 0);
1057 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
1058 Nevent.SetPayload(n2k_payload);
1059 AddPendingEvent(Nevent);
1065bool CommDriverN2KNet::ProcessMiniPlex(
1066 const std::vector<unsigned char>& packet) {
1161 while (!m_circle.IsEmpty()) {
1162 char b = m_circle.Get();
1163 if ((b != 0x0a) && (b != 0x0d)) {
1171 wxString ss(m_sentence.c_str());
1173 wxStringTokenizer tkz(ss,
",");
1176 wxString token = tkz.GetNextToken();
1179 token = tkz.GetNextToken();
1181 token.ToULong(&PGN, 16);
1183 token = tkz.GetNextToken();
1185 token.ToULong(&attr, 16);
1187 bool send_bit = (attr >> 15) != 0;
1189 uint8_t priority = (attr >> 12) & 0x07;
1192 uint8_t dlc = (attr >> 8) & 0x0F;
1195 uint8_t address = attr & 0xFF;
1197 token = tkz.GetNextToken();
1199 wxStringTokenizer datatkz(token,
"*");
1200 wxString data = datatkz.GetNextToken();
1208 memset(&frame.data, 0, 8);
1209 for (
size_t i = 0; i < data.Length(); i += 2) {
1211 wxString sbyte = data.Mid(data.Length() - i - 2, 2);
1212 sbyte.ToULong(&dv, 16);
1213 frame.data[i / 2] = ((uint8_t)dv);
1215 frame.can_id = (uint32_t)BuildCanID(priority, address, 0xFF, PGN);
1216 HandleCanFrameInput(frame);
1223#define RD_BUF_SIZE 4096
1226 switch (event.GetSocketEvent()) {
1227 case wxSOCKET_INPUT: {
1241 std::vector<unsigned char> data(RD_BUF_SIZE + 1);
1243 uint8_t next_byte = 0;
1245 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
1246 if (!event.GetSocket()->Error()) {
1247 m_driver_stats.available =
true;
1248 size_t count =
event.GetSocket()->LastCount();
1261 for (
int i = 0; i < newdata; i++) {
1262 if (!m_circle.IsFull()) m_circle.Put(data[i]);
1267 m_detect_count = (m_detect_count + 1) % 10;
1268 if (m_detect_count <= 0) m_n2k_format = DetectFormat(data);
1270 switch (m_n2k_format) {
1271 case N2KFormat_Actisense_RAW_ASCII:
1272 ProcessActisense_ASCII_RAW(data);
1274 case N2KFormat_YD_RAW:
1275 ProcessActisense_ASCII_RAW(data);
1277 case N2KFormat_Actisense_N2K_ASCII:
1278 ProcessActisense_ASCII_N2K(data);
1280 case N2KFormat_Actisense_N2K:
1281 ProcessActisense_N2K(data);
1283 case N2KFormat_Actisense_RAW:
1284 ProcessActisense_RAW(data);
1286 case N2KFormat_Actisense_NGT:
1287 ProcessActisense_NGT(data);
1289 case N2KFormat_SeaSmart:
1290 ProcessSeaSmart(data);
1292 case N2KFormat_MiniPlex:
1293 ProcessMiniPlex(data);
1295 case N2KFormat_Undefined:
1302 m_dog_value = N_DOG_TIMEOUT;
1306 case wxSOCKET_LOST: {
1307 m_driver_stats.available = GetSock() && GetSock()->IsOk();
1308 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
1309 if (GetBrxConnectEvent())
1310 wxLogMessage(wxString::Format(
"NetworkDataStream connection lost: %s",
1311 GetPort().c_str()));
1312 if (GetSockServer()) {
1313 GetSock()->Destroy();
1317 wxDateTime now = wxDateTime::Now();
1318 wxTimeSpan since_connect(
1320 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
1322 int retry_time = 5000;
1328 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
1331 GetSocketThreadWatchdogTimer()->Stop();
1332 GetSocketTimer()->Start(
1333 retry_time, wxTIMER_ONE_SHOT);
1338 case wxSOCKET_CONNECTION: {
1339 m_driver_stats.available =
true;
1340 if (GetProtocol() == GPSD) {
1344 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
1345 GetSock()->Write(cmd, strlen(cmd));
1346 }
else if (GetProtocol() == TCP) {
1348 wxString::Format(
"TCP NetworkDataStream connection established: %s",
1349 GetPort().c_str()));
1350 m_dog_value = N_DOG_TIMEOUT;
1351 if (GetPortDirection() != PortDirection::kOutput) {
1353 if (GetParams().no_data_reconnect)
1354 GetSocketThreadWatchdogTimer()->Start(1000);
1356 if (GetPortDirection() != PortDirection::kInput && GetSock()->IsOk())
1357 (void)SetOutputSocketOptions(GetSock());
1358 GetSocketTimer()->Stop();
1359 SetBrxConnectEvent(
true);
1362 SetConnectTime(wxDateTime::Now());
1371void CommDriverN2KNet::OnServerSocketEvent(wxSocketEvent& event) {
1372 switch (event.GetSocketEvent()) {
1373 case wxSOCKET_CONNECTION: {
1374 m_driver_stats.available =
true;
1375 SetSock(GetSockServer()->Accept(
false));
1378 GetSock()->SetTimeout(2);
1380 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
1381 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
1382 if (GetPortDirection() != PortDirection::kInput) {
1383 notify_flags |= wxSOCKET_OUTPUT_FLAG;
1384 (void)SetOutputSocketOptions(GetSock());
1386 if (GetPortDirection() != PortDirection::kOutput)
1387 notify_flags |= wxSOCKET_INPUT_FLAG;
1388 GetSock()->SetNotify(notify_flags);
1389 GetSock()->Notify(
true);
1400std::vector<unsigned char> MakeSimpleOutMsg(
1401 int data_format,
int pgn, std::vector<unsigned char>& payload) {
1402 std::vector<unsigned char> out_vec;
1404 switch (data_format) {
1405 case N2KFormat_YD_RAW:
1406 case N2KFormat_Actisense_RAW_ASCII: {
1408 unsigned can_id = BuildCanID(6, 0xff, 0xff, pgn);
1409 std::stringstream ss;
1410 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1411 for (
unsigned char s : ss.str()) out_vec.push_back(s);
1412 out_vec.push_back(
' ');
1417 for (
unsigned char d : payload) {
1418 snprintf(tv, 4,
"%02X ", d);
1421 for (
unsigned char s : sspl) out_vec.push_back(s);
1425 out_vec.push_back(0x0d);
1426 out_vec.push_back(0x0a);
1429 case N2KFormat_Actisense_N2K_ASCII: {
1431 wxDateTime now = wxDateTime::Now();
1432 wxString stime = now.Format(
"%H%M%S");
1434 std::string sstime = stime.ToStdString();
1435 out_vec.push_back(
'A');
1436 for (
unsigned char s : sstime) out_vec.push_back(s);
1440 sdp.Printf(
"%02X%02X%1X ",
1442 (
unsigned char)0xFF, 0x6);
1443 std::string ssdp = sdp.ToStdString();
1444 for (
unsigned char s : ssdp) out_vec.push_back(s);
1448 spgn.Printf(
"%05X ", pgn);
1449 std::string sspgn = spgn.ToStdString();
1450 for (
unsigned char s : sspgn) out_vec.push_back(s);
1455 for (
unsigned char d : payload) {
1456 snprintf(tv, 3,
"%02X", d);
1459 for (
unsigned char s : sspl) out_vec.push_back(s);
1462 out_vec.push_back(0x0d);
1463 out_vec.push_back(0x0a);
1466 case N2KFormat_MiniPlex: {
1467 out_vec.push_back(
'$');
1468 out_vec.push_back(
'M');
1469 out_vec.push_back(
'X');
1470 out_vec.push_back(
'P');
1471 out_vec.push_back(
'G');
1472 out_vec.push_back(
'N');
1473 out_vec.push_back(
',');
1476 spgn.Printf(
"%06X,", pgn);
1477 std::string sspgn = spgn.ToStdString();
1478 for (
unsigned char c : sspgn) {
1479 out_vec.push_back(c);
1484 attr |= ((uint16_t)0x06) << 12;
1485 attr |= ((uint16_t)payload.size()) << 8;
1486 attr |= (uint16_t)0xFF;
1490 sattr.Printf(
"%04X,", attr);
1491 std::string ssattr = sattr.ToStdString();
1492 for (
unsigned char c : ssattr) {
1493 out_vec.push_back(c);
1497 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1498 snprintf(tv, 3,
"%02X", *rit);
1499 out_vec.push_back(tv[0]);
1500 out_vec.push_back(tv[1]);
1504 for (
auto ci = ++out_vec.begin(); ci != out_vec.end(); ci++) {
1507 out_vec.push_back(
'*');
1508 snprintf(tv, 3,
"%02X", crc);
1509 out_vec.push_back(tv[0]);
1510 out_vec.push_back(tv[1]);
1513 out_vec.push_back(0x0d);
1514 out_vec.push_back(0x0a);
1525std::vector<std::vector<unsigned char>> CommDriverN2KNet::GetTxVector(
1526 const std::shared_ptr<const Nmea2000Msg>& msg,
1527 const std::shared_ptr<const NavAddr2000>& dest_addr) {
1528 std::vector<std::vector<unsigned char>> tx_vector;
1531 switch (m_n2k_format) {
1532 case N2KFormat_YD_RAW:
1534 case N2KFormat_Actisense_RAW_ASCII: {
1536 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() <= 8) {
1538 std::vector<unsigned char> header_vec;
1539 std::vector<unsigned char> out_vec;
1544 unsigned long can_id =
1545 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1547 std::stringstream ss;
1548 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1549 for (
unsigned char s : ss.str()) header_vec.push_back(s);
1550 header_vec.push_back(
' ');
1553 for (
unsigned char s : header_vec) out_vec.push_back(s);
1557 for (
unsigned int k = 0; k < msg->payload.size(); k++) {
1559 snprintf(tb, 4,
"%02X ", msg->payload.data()[k]);
1562 for (
unsigned char s : ssdata) out_vec.push_back(s);
1565 out_vec.push_back(0x0d);
1566 out_vec.push_back(0x0a);
1568 tx_vector.push_back(out_vec);
1570 std::vector<unsigned char> header_vec;
1571 std::vector<unsigned char> out_vec;
1576 wxDateTime now = wxDateTime::Now();
1577 wxString stime = now.Format(
"%H:%M:%S");
1579 std::string sstime = stime.ToStdString();
1580 for (
unsigned char s : sstime) header_vec.push_back(s);
1583 header_vec.push_back(
'T');
1584 header_vec.push_back(
' ');
1590 unsigned long can_id =
1591 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1592 std::stringstream ss;
1593 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1594 for (
unsigned char s : ss.str()) header_vec.push_back(s);
1595 header_vec.push_back(
' ');
1598 int payload_size = msg->payload.size();
1599 unsigned char temp[8];
1602 (payload_size > 6 ? (payload_size - 6 - 1) / 7 + 1 + 1 : 1);
1604 for (
int i = 0; i < nframes && result; i++) {
1605 temp[0] = i | m_order;
1607 temp[1] = msg->payload.size();
1609 for (
int j = 2; j < 8; j++) {
1610 temp[j] = msg->payload.data()[cur];
1616 for (; j < 8 && cur < payload_size; j++) {
1617 temp[j] = msg->payload.data()[cur];
1620 for (; j < 8; j++) {
1628 for (
unsigned char s : header_vec) out_vec.push_back(s);
1632 for (
unsigned int k = 0; k < 8; k++) {
1634 snprintf(tb, 4,
"%02X ", temp[k]);
1637 for (
unsigned char s : ssdata) out_vec.push_back(s);
1640 out_vec.push_back(0x0d);
1641 out_vec.push_back(0x0a);
1643 tx_vector.push_back(out_vec);
1647 case N2KFormat_Actisense_N2K_ASCII: {
1664 std::vector<unsigned char> ovec;
1667 wxDateTime now = wxDateTime::Now();
1668 wxString stime = now.Format(
"%H%M%S");
1670 std::string sstime = stime.ToStdString();
1671 ovec.push_back(
'A');
1672 for (
unsigned char s : sstime) ovec.push_back(s);
1676 sdp.Printf(
"%02X%02X%1X ",
1678 (
unsigned char)dest_addr->address,
1679 (
unsigned char)msg->priority);
1680 std::string ssdp = sdp.ToStdString();
1681 for (
unsigned char s : ssdp) ovec.push_back(s);
1685 spgn.Printf(
"%05X ", (
int)msg->PGN.pgn);
1686 std::string sspgn = spgn.ToStdString();
1687 for (
unsigned char s : sspgn) ovec.push_back(s);
1692 for (
unsigned char d : msg->payload) {
1693 snprintf(tv, 3,
"%02X", d);
1696 for (
unsigned char s : sspl) ovec.push_back(s);
1699 ovec.push_back(0x0d);
1700 ovec.push_back(0x0a);
1703 tx_vector.push_back(ovec);
1707 case N2KFormat_MiniPlex: {
1708 std::vector<unsigned char> ovec;
1709 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1714 (msg->payload.size() > 6 ? (msg->payload.size() - 6 - 1) / 7 + 1 + 1
1716 for (
size_t i = 0; i < nframes; i++) {
1717 ovec.push_back(
'$');
1718 ovec.push_back(
'M');
1719 ovec.push_back(
'X');
1720 ovec.push_back(
'P');
1721 ovec.push_back(
'G');
1722 ovec.push_back(
'N');
1723 ovec.push_back(
',');
1726 spgn.Printf(
"%06X,", (
int)msg->PGN.pgn);
1727 std::string sspgn = spgn.ToStdString();
1728 for (
unsigned char c : sspgn) {
1734 if (i == nframes - 1) {
1739 attr |= ((uint16_t)((uint8_t)msg->priority & 0x07)) << 12;
1740 attr |= ((uint16_t)len) << 8;
1741 attr |= (uint16_t)dest_addr->address;
1745 sattr.Printf(
"%04X,", attr);
1746 std::string ssattr = sattr.ToStdString();
1747 for (
unsigned char c : ssattr) {
1752 uint8_t databytes = i == 0 ? len - 2 : len - 1;
1753 std::vector<unsigned char> payload;
1754 for (uint8_t j = 0; j < databytes; j++) {
1755 payload.push_back(msg->payload[cur]);
1760 int psize = payload.size();
1761 while ((i > 0) && (psize < 7)) {
1762 ovec.push_back(
'F');
1763 ovec.push_back(
'F');
1768 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1769 snprintf(tv, 3,
"%02X", *rit);
1770 ovec.push_back(tv[0]);
1771 ovec.push_back(tv[1]);
1774 snprintf(tv, 3,
"%02X", (uint8_t)msg->payload.size());
1775 ovec.push_back(tv[0]);
1776 ovec.push_back(tv[1]);
1779 snprintf(tv, 3,
"%02X", (uint8_t)i | m_order);
1780 ovec.push_back(tv[0]);
1781 ovec.push_back(tv[1]);
1785 for (
auto ci = ++ovec.begin(); ci != ovec.end(); ci++) {
1788 ovec.push_back(
'*');
1789 snprintf(tv, 3,
"%02X", crc);
1790 ovec.push_back(tv[0]);
1791 ovec.push_back(tv[1]);
1794 ovec.push_back(0x0d);
1795 ovec.push_back(0x0a);
1801 tx_vector.push_back(ovec);
1807 case N2KFormat_Actisense_N2K:
1808 case N2KFormat_Actisense_RAW:
1809 case N2KFormat_Actisense_NGT:
1810 case N2KFormat_SeaSmart:
1816 m_order = (m_order + 0x20) & 0xE0;
1821bool CommDriverN2KNet::PrepareForTX() {
1836 if (m_n2k_format == N2KFormat_Actisense_N2K_ASCII)
return true;
1843 if (m_n2k_format == N2KFormat_MiniPlex)
return true;
1848 if (m_n2k_format == N2KFormat_SeaSmart)
return false;
1861 std::vector<unsigned char> payload;
1862 payload.push_back(0x14);
1863 payload.push_back(0xF0);
1864 payload.push_back(0x01);
1866 std::vector<std::vector<unsigned char>> out_data;
1867 std::vector<unsigned char> msg_vec =
1868 MakeSimpleOutMsg(N2KFormat_YD_RAW, 59904, payload);
1869 out_data.push_back(msg_vec);
1870 SendSentenceNetwork(out_data);
1873 m_prodinfo_timer.Start(200,
true);
1880bool CommDriverN2KNet::SendN2KNetwork(
1881 const std::shared_ptr<const Nmea2000Msg>& msg,
1882 const std::shared_ptr<const NavAddr2000>& addr) {
1885 std::vector<std::vector<unsigned char>> out_data = GetTxVector(msg, addr);
1886 SendSentenceNetwork(out_data);
1887 m_driver_stats.tx_count += msg->payload.size();
1890 std::vector<unsigned char> msg_payload = PrepareLogPayload(msg, addr);
1892 std::make_shared<const Nmea2000Msg>(msg->PGN.pgn, msg_payload, addr));
1897bool CommDriverN2KNet::SendSentenceNetwork(
1898 const std::vector<std::vector<unsigned char>>& payload) {
1905 wxDatagramSocket* udp_socket;
1906 switch (GetProtocol()) {
1908 for (
const std::vector<unsigned char>& v : payload) {
1909 if (GetSock() && GetSock()->IsOk()) {
1910 m_driver_stats.available =
true;
1912 GetSock()->Write(v.data(), v.size());
1913 m_dog_value = N_DOG_TIMEOUT;
1914 if (GetSock()->Error()) {
1915 if (GetSockServer()) {
1916 GetSock()->Destroy();
1919 auto* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
1920 if (tcp_socket) tcp_socket->Close();
1921 if (!GetSocketTimer()->IsRunning())
1922 GetSocketTimer()->Start(
1923 5000, wxTIMER_ONE_SHOT);
1924 GetSocketThreadWatchdogTimer()->Stop();
1930 m_driver_stats.available =
false;
1937 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
1938 if (udp_socket && udp_socket->IsOk()) {
1939 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
1940 if (udp_socket->Error()) ret =
false;
1955void CommDriverN2KNet::Close() {
1956 wxLogMessage(wxString::Format(
"Closing NMEA NetworkDataStream %s",
1957 GetNetPort().c_str()));
1958 m_stats_timer.Stop();
1962 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
1963 sizeof(m_mrq_container->m_mrq));
1964 m_sock->Notify(FALSE);
1966 m_driver_stats.available =
false;
1970 m_tsock->Notify(FALSE);
1974 if (m_socket_server) {
1975 m_socket_server->Notify(FALSE);
1976 m_socket_server->Destroy();
1979 m_socket_timer.Stop();
1980 m_socketread_watchdog_timer.Stop();
1983bool CommDriverN2KNet::SetOutputSocketOptions(wxSocketBase* tsock) {
1992 int nagleDisable = 1;
1993 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
1994 sizeof(nagleDisable));
2000 unsigned long outbuf_size = 1024;
2001 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
2002 sizeof(outbuf_size)) &&
void OnSocketEvent(wxSocketEvent &event)
Connection data container close to a POD struct.
Interface for handling incoming messages.
Track fast message fragments eventually forming complete messages.
Custom event class for OpenCPN's notification system.
Nmea2000 IP network driver.
Raw messages layer, supports sending and recieving navmsg messages.
std::string PortDirectionToString(PortDirection pd)
Return textual representation for use in driver ioDirection attribute.
GUI constant definitions.
Suspend/resume and new devices events exchange point.