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) {};
95 : wxEvent(
id, commandType) {};
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 {
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) {
536 if (position == kNotFound) {
543 if ((frame.data[0] & 0x1F) == 0) {
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;
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;
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);
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;
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;
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) {
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) {
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;
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;
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) {
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;
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) {
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)) &&
bool IsEmpty() const noexcept
Return true if buffer is empty.
T Get()
Get item from buff; throw BufferError if empty.
void Put(const T &item)
Add item to buffer; throw BufferError if full.
bool IsFull() const noexcept
Return true if buffer is full.
void OnSocketEvent(wxSocketEvent &event)
Connection data container close to a POD struct.
Interface for handling incoming messages.
virtual void Notify(std::shared_ptr< const NavMsg > message)=0
Handle a received message.
Track fast message fragments eventually forming complete messages.
int AddNewEntry(void)
Allocate a new, fresh entry and return index to it.
void Remove(int pos)
Remove entry at pos.
bool AppendEntry(const CanHeader hdr, const unsigned char *data, int index)
Append fragment to existing multipart message.
int FindMatchingEntry(const CanHeader header, const unsigned char sid)
Setter.
bool InsertEntry(const CanHeader header, const unsigned char *data, int index)
Insert a new entry, first part of a multipart message.
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.
unsigned tx_count
Number of bytes sent since program start.
unsigned rx_count
Number of bytes received since program start.
Suspend/resume and new devices events exchange point.