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->NetworkPort)),
143 m_net_protocol(params->NetProtocol),
146 m_socket_server(
nullptr),
147 m_is_multicast(false),
149 m_portstring(params->GetDSPort()),
150 m_io_select(params->IOSelect),
151 m_connection_type(params->Type),
153 m_circle(RX_BUFFER_SIZE_NET),
154 m_TX_available(false),
156 m_addr.Hostname(params->NetworkAddress);
157 m_addr.Service(params->NetworkPort);
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->NetworkAddress.ToStdString();
166 sprintf(port_char,
"%d", params->NetworkPort);
167 this->attributes[
"netPort"] = std::string(port_char);
168 this->attributes[
"userComment"] = params->UserComment.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.is_server) {
311 wxIPV4address conn_addr;
312 conn_addr.Service(GetNetPort());
313 conn_addr.AnyAddress();
315 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
318 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
320 m_mrq_container->SetMrqAddr(addr);
321 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP,
322 &m_mrq_container->m_mrq,
323 sizeof(m_mrq_container->m_mrq));
326 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
328 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
330 GetSock()->Notify(TRUE);
331 GetSock()->SetTimeout(1);
332 m_driver_stats.available =
true;
336 if (GetPortType() != DS_TYPE_INPUT) {
337 wxIPV4address tconn_addr;
338 tconn_addr.Service(0);
339 tconn_addr.AnyAddress();
341 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
346 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(
"255"))) {
347 int broadcastEnable = 1;
348 GetTSock()->SetOption(SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
349 sizeof(broadcastEnable));
351 m_driver_stats.available =
true;
355 SetConnectTime(wxDateTime::Now());
358void CommDriverN2KNet::OpenNetworkTCP(
unsigned int addr) {
359 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
360 wxLogMessage(wxString::Format(
"Opening TCP Server %d", isServer));
363 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
365 SetSock(
new wxSocketClient());
369 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
370 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
371 GetSockServer()->Notify(TRUE);
372 GetSockServer()->SetTimeout(1);
374 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
375 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
376 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
377 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
378 GetSock()->SetNotify(notify_flags);
379 GetSock()->Notify(TRUE);
380 GetSock()->SetTimeout(1);
382 SetBrxConnectEvent(
false);
383 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
387 SetConnectTime(wxDateTime::Now());
388 m_driver_stats.available = GetSock()->IsOk();
391void CommDriverN2KNet::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
394 if (m_dog_value <= 0) {
395 if (GetParams().NoDataReconnect) {
397 if (GetProtocol() == TCP) {
398 auto* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
399 if (tcp_socket) tcp_socket->Close();
401 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
402 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
404 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
407 GetSocketThreadWatchdogTimer()->Stop();
413void CommDriverN2KNet::OnTimerSocket() {
415 auto* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
417 if (tcp_socket->IsDisconnected()) {
418 wxLogDebug(
" Attempting reconnection...");
419 SetBrxConnectEvent(
false);
421 GetSocketThreadWatchdogTimer()->Stop();
422 tcp_socket->Connect(GetAddr(), FALSE);
425 int n_reconnect_delay = N_DOG_TIMEOUT;
426 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
428 m_driver_stats.available =
true;
433void CommDriverN2KNet::HandleResume() {
435 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
437 GetSocketThreadWatchdogTimer()->Stop();
442 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
443 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
446 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
450bool CommDriverN2KNet::SendMessage(std::shared_ptr<const NavMsg> msg,
451 std::shared_ptr<const NavAddr> addr) {
452 if (!msg)
return false;
453 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
454 auto dest_addr_n2k = std::static_pointer_cast<const NavAddr2000>(addr);
455 return SendN2KNetwork(msg_n2k, dest_addr_n2k);
458std::vector<unsigned char> CommDriverN2KNet::PrepareLogPayload(
459 const std::shared_ptr<const Nmea2000Msg>& msg,
460 const std::shared_ptr<const NavAddr2000>& addr) {
461 std::vector<unsigned char> data;
462 data.push_back(0x94);
463 data.push_back(0x13);
464 data.push_back(msg->priority);
465 data.push_back(msg->PGN.pgn & 0xFF);
466 data.push_back((msg->PGN.pgn >> 8) & 0xFF);
467 data.push_back((msg->PGN.pgn >> 16) & 0xFF);
468 data.push_back(addr->address);
469 data.push_back(addr->address);
470 for (
size_t n = 0; n < msg->payload.size(); n++)
471 data.push_back(msg->payload[n]);
472 data.push_back(0x55);
476std::vector<unsigned char> CommDriverN2KNet::PushCompleteMsg(
477 const CanHeader& header,
int position,
const can_frame& frame) {
478 std::vector<unsigned char> data;
479 data.push_back(0x93);
480 data.push_back(0x13);
481 data.push_back(header.priority);
482 data.push_back(header.pgn & 0xFF);
483 data.push_back((header.pgn >> 8) & 0xFF);
484 data.push_back((header.pgn >> 16) & 0xFF);
485 data.push_back(header.destination);
486 data.push_back(header.source);
487 data.push_back(0xFF);
488 data.push_back(0xFF);
489 data.push_back(0xFF);
490 data.push_back(0xFF);
491 data.push_back(CAN_MAX_DLEN);
492 for (
size_t n = 0; n < CAN_MAX_DLEN; n++) data.push_back(frame.data[n]);
493 data.push_back(0x55);
497std::vector<unsigned char> CommDriverN2KNet::PushFastMsgFragment(
499 std::vector<unsigned char> data;
500 data.push_back(0x93);
501 data.push_back(fast_messages->entries[position].expected_length + 11);
502 data.push_back(header.priority);
503 data.push_back(header.pgn & 0xFF);
504 data.push_back((header.pgn >> 8) & 0xFF);
505 data.push_back((header.pgn >> 16) & 0xFF);
506 data.push_back(header.destination);
507 data.push_back(header.source);
508 data.push_back(0xFF);
509 data.push_back(0xFF);
510 data.push_back(0xFF);
511 data.push_back(0xFF);
512 data.push_back(fast_messages->entries[position].expected_length);
513 for (
size_t n = 0; n < fast_messages->entries[position].expected_length; n++)
514 data.push_back(fast_messages->entries[position].data[n]);
515 data.push_back(0x55);
516 fast_messages->
Remove(position);
526void CommDriverN2KNet::HandleCanFrameInput(
const can_frame& frame) {
533 if (position == kNotFound) {
540 if ((frame.data[0] & 0x1F) == 0) {
542 ready = fast_messages->
InsertEntry(header, frame.data, position);
547 ready = fast_messages->
AppendEntry(header, frame.data, position);
551 std::vector<unsigned char> vec;
554 vec = PushFastMsgFragment(header, position);
557 vec = PushCompleteMsg(header, position, frame);
561 if (HandleMgntMsg(header.pgn, vec))
return;
565 auto payload = std::make_shared<std::vector<uint8_t>>(vec);
566 Nevent.SetPayload(payload);
567 AddPendingEvent(Nevent);
571static bool isASCII(
const std::vector<unsigned char>& packet) {
572 for (
unsigned char c : packet) {
573 if (!isascii(c))
return false;
578N2K_Format CommDriverN2KNet::DetectFormat(
579 const std::vector<unsigned char>& packet) {
584 if (isASCII(packet)) {
585 std::string payload = std::string(packet.begin(), packet.end());
586 if (payload.find(
"$PCDIN") != std::string::npos) {
587 return N2KFormat_SeaSmart;
588 }
else if (payload.find(
"$MXPGN") != std::string::npos) {
592 return N2KFormat_MiniPlex;
593 }
else if (std::find(packet.begin(), packet.end(),
':') != packet.end()) {
594 return N2KFormat_Actisense_RAW_ASCII;
596 return N2KFormat_Actisense_N2K_ASCII;
599 if (packet[2] == 0x95)
600 return N2KFormat_Actisense_RAW;
601 else if (packet[2] == 0xd0)
602 return N2KFormat_Actisense_N2K;
603 else if (packet[2] == 0x93)
604 return N2KFormat_Actisense_NGT;
606 return N2KFormat_Undefined;
609bool CommDriverN2KNet::ProcessActisense_N2K(
610 const std::vector<unsigned char>& packet) {
613 std::vector<unsigned char> data;
615 bool bGotESC =
false;
616 bool bGotSOT =
false;
619 uint8_t next_byte = m_circle.
Get();
623 if (next_byte == ESCAPE) {
624 data.push_back(next_byte);
626 }
else if (next_byte == ENDOFTEXT) {
630 unsigned int msg_length =
631 (uint32_t)data[1] + ((uint32_t)data[2] << 8);
634 if (msg_length == data.size() - 1) {
635 uint8_t destination = data[3];
636 uint8_t source = data[4];
638 uint8_t dprp = data[7];
641 uint8_t rAndDP = dprp & 3;
644 uint8_t pduFormat = data[6];
645 uint32_t pgn = (rAndDP << 16) + (pduFormat << 8);
651 std::vector<uint8_t> o_payload;
652 o_payload.push_back(0x93);
653 o_payload.push_back(0x13);
654 o_payload.push_back(priority);
655 o_payload.push_back(pgn & 0xFF);
656 o_payload.push_back((pgn >> 8) & 0xFF);
657 o_payload.push_back((pgn >> 16) & 0xFF);
658 o_payload.push_back(destination);
659 o_payload.push_back(source);
660 o_payload.push_back(0xFF);
661 o_payload.push_back(0xFF);
662 o_payload.push_back(0xFF);
663 o_payload.push_back(0xFF);
664 o_payload.push_back(data.size());
667 for (
size_t n = 13; n < data.size() - 1; n++)
668 o_payload.push_back(data[n]);
670 o_payload.push_back(0x55);
675 std::make_shared<std::vector<uint8_t>>(o_payload);
676 Nevent.SetPayload(n2k_payload);
677 AddPendingEvent(Nevent);
684 }
else if (next_byte == STARTOFTEXT) {
693 bGotESC = (next_byte == ESCAPE);
696 data.push_back(next_byte);
702 if (STARTOFTEXT == next_byte) {
708 bGotESC = (next_byte == ESCAPE);
713 data.push_back(next_byte);
722bool CommDriverN2KNet::ProcessActisense_RAW(
723 const std::vector<unsigned char>& packet) {
728 std::vector<unsigned char> data;
730 bool bGotESC =
false;
731 bool bGotSOT =
false;
734 uint8_t next_byte = m_circle.
Get();
738 if (next_byte == ESCAPE) {
739 data.push_back(next_byte);
741 }
else if (next_byte == ENDOFTEXT) {
746 if (data.size() >= 8) {
747 size_t dLen = data[1];
749 if (dLen + 3 == data.size()) {
751 memcpy(&frame.can_id, &data.data()[4], 4);
754 memcpy(&frame.data, &data.data()[8], 8);
756 HandleCanFrameInput(frame);
764 }
else if (next_byte == STARTOFTEXT) {
773 bGotESC = (next_byte == ESCAPE);
776 data.push_back(next_byte);
782 if (STARTOFTEXT == next_byte) {
788 bGotESC = (next_byte == ESCAPE);
793 data.push_back(next_byte);
802bool CommDriverN2KNet::ProcessActisense_NGT(
803 const std::vector<unsigned char>& packet) {
804 std::vector<unsigned char> data;
806 bool bGotESC =
false;
807 bool bGotSOT =
false;
810 uint8_t next_byte = m_circle.
Get();
814 if (next_byte == ESCAPE) {
815 data.push_back(next_byte);
817 }
else if (next_byte == ENDOFTEXT) {
820 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(data);
821 Nevent.SetPayload(n2k_payload);
822 AddPendingEvent(Nevent);
828 }
else if (next_byte == STARTOFTEXT) {
837 bGotESC = (next_byte == ESCAPE);
840 data.push_back(next_byte);
846 if (STARTOFTEXT == next_byte) {
852 bGotESC = (next_byte == ESCAPE);
857 data.push_back(next_byte);
866bool CommDriverN2KNet::ProcessActisense_ASCII_RAW(
867 const std::vector<unsigned char>& packet) {
871 char b = m_circle.
Get();
872 if ((b != 0x0a) && (b != 0x0d)) {
880 wxString ss(m_sentence.c_str());
882 wxStringTokenizer tkz(ss,
" ");
885 wxString token = tkz.GetNextToken();
887 token = tkz.GetNextToken();
889 m_TX_flag = token[0];
892 token = tkz.GetNextToken();
894 token.ToLong(&canID, 16);
895 frame.can_id = canID;
898 unsigned char bytes[8];
900 for (
unsigned int i = 0; i < 8; i++) {
901 if (tkz.HasMoreTokens()) {
902 token = tkz.GetNextToken();
904 token.ToLong(&tui, 16);
905 bytes[i] = (uint8_t)tui;
908 memcpy(&frame.data, bytes, 8);
909 HandleCanFrameInput(frame);
915bool CommDriverN2KNet::ProcessActisense_ASCII_N2K(
916 const std::vector<unsigned char>& packet) {
918 std::string sentence;
921 char b = m_circle.
Get();
922 if ((b != 0x0a) && (b != 0x0d)) {
930 wxString ss(sentence.c_str());
931 wxStringTokenizer tkz(ss,
" ");
935 wxString time_header = tkz.GetNextToken();
937 wxString sprio_addr = tkz.GetNextToken();
939 sprio_addr.ToLong(&prio_addr, 16);
940 uint8_t priority = (uint8_t)prio_addr & 0X0F;
941 uint8_t destination = (uint8_t)(prio_addr >> 4) & 0X0FF;
942 uint8_t source = (uint8_t)(prio_addr >> 12) & 0X0FF;
945 wxString sPGN = tkz.GetNextToken();
947 sPGN.ToULong(&PGN, 16);
951 wxString sdata = tkz.GetNextToken();
952 std::vector<uint8_t> data;
953 for (
size_t i = 0; i < sdata.Length(); i += 2) {
955 wxString stui = sdata.Mid(i, 2);
956 stui.ToLong(&dv, 16);
957 data.push_back((uint8_t)dv);
961 std::vector<uint8_t> o_payload;
962 o_payload.push_back(0x93);
963 o_payload.push_back(0x13);
964 o_payload.push_back(priority);
965 o_payload.push_back(PGN & 0xFF);
966 o_payload.push_back((PGN >> 8) & 0xFF);
967 o_payload.push_back((PGN >> 16) & 0xFF);
968 o_payload.push_back(destination);
969 o_payload.push_back(source);
970 o_payload.push_back(0xFF);
971 o_payload.push_back(0xFF);
972 o_payload.push_back(0xFF);
973 o_payload.push_back(0xFF);
974 o_payload.push_back(data.size());
975 for (
size_t n = 0; n < data.size(); n++) o_payload.push_back(data[n]);
976 o_payload.push_back(0x55);
978 if (HandleMgntMsg(PGN, o_payload))
return false;
982 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
983 Nevent.SetPayload(n2k_payload);
984 AddPendingEvent(Nevent);
990bool CommDriverN2KNet::ProcessSeaSmart(
991 const std::vector<unsigned char>& packet) {
993 char b = m_circle.
Get();
994 if ((b != 0x0a) && (b != 0x0d)) {
1002 wxString ss(m_sentence.c_str());
1004 wxStringTokenizer tkz(ss,
",");
1007 wxString token = tkz.GetNextToken();
1010 token = tkz.GetNextToken();
1012 token.ToULong(&PGN, 16);
1014 token = tkz.GetNextToken();
1015 unsigned long timestamp;
1016 token.ToULong(×tamp, 16);
1018 token = tkz.GetNextToken();
1019 unsigned long source;
1020 token.ToULong(&source, 16);
1022 token = tkz.GetNextToken();
1024 wxStringTokenizer datatkz(token,
"*");
1025 wxString data = datatkz.GetNextToken();
1028 std::vector<uint8_t> o_payload;
1029 o_payload.push_back(0x93);
1030 o_payload.push_back(0x13);
1031 o_payload.push_back(3);
1032 o_payload.push_back(PGN & 0xFF);
1033 o_payload.push_back((PGN >> 8) & 0xFF);
1034 o_payload.push_back((PGN >> 16) & 0xFF);
1035 o_payload.push_back(0xFF);
1036 o_payload.push_back((uint8_t)source);
1037 o_payload.push_back(timestamp & 0xFF);
1038 o_payload.push_back((timestamp >> 8) & 0xFF);
1039 o_payload.push_back((timestamp >> 16) & 0xFF);
1040 o_payload.push_back((timestamp >> 24) & 0xFF);
1041 o_payload.push_back((uint8_t)data.Length() / 2);
1042 for (
size_t i = 0; i < data.Length(); i += 2) {
1044 wxString sbyte = data.Mid(i, 2);
1045 sbyte.ToULong(&dv, 16);
1046 o_payload.push_back((uint8_t)dv);
1048 o_payload.push_back(0x55);
1050 if (HandleMgntMsg(PGN, o_payload))
return false;
1054 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
1055 Nevent.SetPayload(n2k_payload);
1056 AddPendingEvent(Nevent);
1062bool CommDriverN2KNet::ProcessMiniPlex(
1063 const std::vector<unsigned char>& packet) {
1159 char b = m_circle.
Get();
1160 if ((b != 0x0a) && (b != 0x0d)) {
1168 wxString ss(m_sentence.c_str());
1170 wxStringTokenizer tkz(ss,
",");
1173 wxString token = tkz.GetNextToken();
1176 token = tkz.GetNextToken();
1178 token.ToULong(&PGN, 16);
1180 token = tkz.GetNextToken();
1182 token.ToULong(&attr, 16);
1184 bool send_bit = (attr >> 15) != 0;
1186 uint8_t priority = (attr >> 12) & 0x07;
1189 uint8_t dlc = (attr >> 8) & 0x0F;
1192 uint8_t address = attr & 0xFF;
1194 token = tkz.GetNextToken();
1196 wxStringTokenizer datatkz(token,
"*");
1197 wxString data = datatkz.GetNextToken();
1205 memset(&frame.data, 0, 8);
1206 for (
size_t i = 0; i < data.Length(); i += 2) {
1208 wxString sbyte = data.Mid(data.Length() - i - 2, 2);
1209 sbyte.ToULong(&dv, 16);
1210 frame.data[i / 2] = ((uint8_t)dv);
1212 frame.can_id = (uint32_t)BuildCanID(priority, address, 0xFF, PGN);
1213 HandleCanFrameInput(frame);
1220#define RD_BUF_SIZE 4096
1223 switch (event.GetSocketEvent()) {
1224 case wxSOCKET_INPUT: {
1238 std::vector<unsigned char> data(RD_BUF_SIZE + 1);
1240 uint8_t next_byte = 0;
1242 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
1243 if (!event.GetSocket()->Error()) {
1244 m_driver_stats.available =
true;
1245 size_t count =
event.GetSocket()->LastCount();
1258 for (
int i = 0; i < newdata; i++) {
1259 if (!m_circle.
IsFull()) m_circle.
Put(data[i]);
1264 m_detect_count = (m_detect_count + 1) % 10;
1265 if (m_detect_count <= 0) m_n2k_format = DetectFormat(data);
1267 switch (m_n2k_format) {
1268 case N2KFormat_Actisense_RAW_ASCII:
1269 ProcessActisense_ASCII_RAW(data);
1271 case N2KFormat_YD_RAW:
1272 ProcessActisense_ASCII_RAW(data);
1274 case N2KFormat_Actisense_N2K_ASCII:
1275 ProcessActisense_ASCII_N2K(data);
1277 case N2KFormat_Actisense_N2K:
1278 ProcessActisense_N2K(data);
1280 case N2KFormat_Actisense_RAW:
1281 ProcessActisense_RAW(data);
1283 case N2KFormat_Actisense_NGT:
1284 ProcessActisense_NGT(data);
1286 case N2KFormat_SeaSmart:
1287 ProcessSeaSmart(data);
1289 case N2KFormat_MiniPlex:
1290 ProcessMiniPlex(data);
1292 case N2KFormat_Undefined:
1299 m_dog_value = N_DOG_TIMEOUT;
1303 case wxSOCKET_LOST: {
1304 m_driver_stats.available = GetSock()->IsOk();
1305 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
1306 if (GetBrxConnectEvent())
1307 wxLogMessage(wxString::Format(
"NetworkDataStream connection lost: %s",
1308 GetPort().c_str()));
1309 if (GetSockServer()) {
1310 GetSock()->Destroy();
1314 wxDateTime now = wxDateTime::Now();
1315 wxTimeSpan since_connect(
1317 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
1319 int retry_time = 5000;
1325 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
1328 GetSocketThreadWatchdogTimer()->Stop();
1329 GetSocketTimer()->Start(
1330 retry_time, wxTIMER_ONE_SHOT);
1335 case wxSOCKET_CONNECTION: {
1336 m_driver_stats.available =
true;
1337 if (GetProtocol() == GPSD) {
1341 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
1342 GetSock()->Write(cmd, strlen(cmd));
1343 }
else if (GetProtocol() == TCP) {
1345 wxString::Format(
"TCP NetworkDataStream connection established: %s",
1346 GetPort().c_str()));
1347 m_dog_value = N_DOG_TIMEOUT;
1348 if (GetPortType() != DS_TYPE_OUTPUT) {
1350 if (GetParams().NoDataReconnect)
1351 GetSocketThreadWatchdogTimer()->Start(1000);
1353 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
1354 (void)SetOutputSocketOptions(GetSock());
1355 GetSocketTimer()->Stop();
1356 SetBrxConnectEvent(
true);
1359 SetConnectTime(wxDateTime::Now());
1368void CommDriverN2KNet::OnServerSocketEvent(wxSocketEvent& event) {
1369 switch (event.GetSocketEvent()) {
1370 case wxSOCKET_CONNECTION: {
1371 m_driver_stats.available =
true;
1372 SetSock(GetSockServer()->Accept(
false));
1375 GetSock()->SetTimeout(2);
1377 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
1378 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
1379 if (GetPortType() != DS_TYPE_INPUT) {
1380 notify_flags |= wxSOCKET_OUTPUT_FLAG;
1381 (void)SetOutputSocketOptions(GetSock());
1383 if (GetPortType() != DS_TYPE_OUTPUT)
1384 notify_flags |= wxSOCKET_INPUT_FLAG;
1385 GetSock()->SetNotify(notify_flags);
1386 GetSock()->Notify(
true);
1397std::vector<unsigned char> MakeSimpleOutMsg(
1398 int data_format,
int pgn, std::vector<unsigned char>& payload) {
1399 std::vector<unsigned char> out_vec;
1401 switch (data_format) {
1402 case N2KFormat_YD_RAW:
1403 case N2KFormat_Actisense_RAW_ASCII: {
1405 unsigned can_id = BuildCanID(6, 0xff, 0xff, pgn);
1406 std::stringstream ss;
1407 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1408 for (
unsigned char s : ss.str()) out_vec.push_back(s);
1409 out_vec.push_back(
' ');
1414 for (
unsigned char d : payload) {
1415 snprintf(tv, 4,
"%02X ", d);
1418 for (
unsigned char s : sspl) out_vec.push_back(s);
1422 out_vec.push_back(0x0d);
1423 out_vec.push_back(0x0a);
1426 case N2KFormat_Actisense_N2K_ASCII: {
1428 wxDateTime now = wxDateTime::Now();
1429 wxString stime = now.Format(
"%H%M%S");
1431 std::string sstime = stime.ToStdString();
1432 out_vec.push_back(
'A');
1433 for (
unsigned char s : sstime) out_vec.push_back(s);
1437 sdp.Printf(
"%02X%02X%1X ",
1439 (
unsigned char)0xFF, 0x6);
1440 std::string ssdp = sdp.ToStdString();
1441 for (
unsigned char s : ssdp) out_vec.push_back(s);
1445 spgn.Printf(
"%05X ", pgn);
1446 std::string sspgn = spgn.ToStdString();
1447 for (
unsigned char s : sspgn) out_vec.push_back(s);
1452 for (
unsigned char d : payload) {
1453 snprintf(tv, 3,
"%02X", d);
1456 for (
unsigned char s : sspl) out_vec.push_back(s);
1459 out_vec.push_back(0x0d);
1460 out_vec.push_back(0x0a);
1463 case N2KFormat_MiniPlex: {
1464 out_vec.push_back(
'$');
1465 out_vec.push_back(
'M');
1466 out_vec.push_back(
'X');
1467 out_vec.push_back(
'P');
1468 out_vec.push_back(
'G');
1469 out_vec.push_back(
'N');
1470 out_vec.push_back(
',');
1473 spgn.Printf(
"%06X,", pgn);
1474 std::string sspgn = spgn.ToStdString();
1475 for (
unsigned char c : sspgn) {
1476 out_vec.push_back(c);
1481 attr |= ((uint16_t)0x06) << 12;
1482 attr |= ((uint16_t)payload.size()) << 8;
1483 attr |= (uint16_t)0xFF;
1487 sattr.Printf(
"%04X,", attr);
1488 std::string ssattr = sattr.ToStdString();
1489 for (
unsigned char c : ssattr) {
1490 out_vec.push_back(c);
1494 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1495 snprintf(tv, 3,
"%02X", *rit);
1496 out_vec.push_back(tv[0]);
1497 out_vec.push_back(tv[1]);
1501 for (
auto ci = ++out_vec.begin(); ci != out_vec.end(); ci++) {
1504 out_vec.push_back(
'*');
1505 snprintf(tv, 3,
"%02X", crc);
1506 out_vec.push_back(tv[0]);
1507 out_vec.push_back(tv[1]);
1510 out_vec.push_back(0x0d);
1511 out_vec.push_back(0x0a);
1522std::vector<std::vector<unsigned char>> CommDriverN2KNet::GetTxVector(
1523 const std::shared_ptr<const Nmea2000Msg>& msg,
1524 const std::shared_ptr<const NavAddr2000>& dest_addr) {
1525 std::vector<std::vector<unsigned char>> tx_vector;
1528 switch (m_n2k_format) {
1529 case N2KFormat_YD_RAW:
1531 case N2KFormat_Actisense_RAW_ASCII: {
1533 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() <= 8) {
1535 std::vector<unsigned char> header_vec;
1536 std::vector<unsigned char> out_vec;
1541 unsigned long can_id =
1542 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1544 std::stringstream ss;
1545 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1546 for (
unsigned char s : ss.str()) header_vec.push_back(s);
1547 header_vec.push_back(
' ');
1550 for (
unsigned char s : header_vec) out_vec.push_back(s);
1554 for (
unsigned int k = 0; k < msg->payload.size(); k++) {
1556 snprintf(tb, 4,
"%02X ", msg->payload.data()[k]);
1559 for (
unsigned char s : ssdata) out_vec.push_back(s);
1562 out_vec.push_back(0x0d);
1563 out_vec.push_back(0x0a);
1565 tx_vector.push_back(out_vec);
1567 std::vector<unsigned char> header_vec;
1568 std::vector<unsigned char> out_vec;
1573 wxDateTime now = wxDateTime::Now();
1574 wxString stime = now.Format(
"%H:%M:%S");
1576 std::string sstime = stime.ToStdString();
1577 for (
unsigned char s : sstime) header_vec.push_back(s);
1580 header_vec.push_back(
'T');
1581 header_vec.push_back(
' ');
1587 unsigned long can_id =
1588 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1589 std::stringstream ss;
1590 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1591 for (
unsigned char s : ss.str()) header_vec.push_back(s);
1592 header_vec.push_back(
' ');
1595 int payload_size = msg->payload.size();
1596 unsigned char temp[8];
1599 (payload_size > 6 ? (payload_size - 6 - 1) / 7 + 1 + 1 : 1);
1601 for (
int i = 0; i < nframes && result; i++) {
1602 temp[0] = i | m_order;
1604 temp[1] = msg->payload.size();
1606 for (
int j = 2; j < 8; j++) {
1607 temp[j] = msg->payload.data()[cur];
1613 for (; j < 8 && cur < payload_size; j++) {
1614 temp[j] = msg->payload.data()[cur];
1617 for (; j < 8; j++) {
1625 for (
unsigned char s : header_vec) out_vec.push_back(s);
1629 for (
unsigned int k = 0; k < 8; k++) {
1631 snprintf(tb, 4,
"%02X ", temp[k]);
1634 for (
unsigned char s : ssdata) out_vec.push_back(s);
1637 out_vec.push_back(0x0d);
1638 out_vec.push_back(0x0a);
1640 tx_vector.push_back(out_vec);
1644 case N2KFormat_Actisense_N2K_ASCII: {
1661 std::vector<unsigned char> ovec;
1664 wxDateTime now = wxDateTime::Now();
1665 wxString stime = now.Format(
"%H%M%S");
1667 std::string sstime = stime.ToStdString();
1668 ovec.push_back(
'A');
1669 for (
unsigned char s : sstime) ovec.push_back(s);
1673 sdp.Printf(
"%02X%02X%1X ",
1675 (
unsigned char)dest_addr->address,
1676 (
unsigned char)msg->priority);
1677 std::string ssdp = sdp.ToStdString();
1678 for (
unsigned char s : ssdp) ovec.push_back(s);
1682 spgn.Printf(
"%05X ", (
int)msg->PGN.pgn);
1683 std::string sspgn = spgn.ToStdString();
1684 for (
unsigned char s : sspgn) ovec.push_back(s);
1689 for (
unsigned char d : msg->payload) {
1690 snprintf(tv, 3,
"%02X", d);
1693 for (
unsigned char s : sspl) ovec.push_back(s);
1696 ovec.push_back(0x0d);
1697 ovec.push_back(0x0a);
1700 tx_vector.push_back(ovec);
1704 case N2KFormat_MiniPlex: {
1705 std::vector<unsigned char> ovec;
1706 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1711 (msg->payload.size() > 6 ? (msg->payload.size() - 6 - 1) / 7 + 1 + 1
1713 for (
size_t i = 0; i < nframes; i++) {
1714 ovec.push_back(
'$');
1715 ovec.push_back(
'M');
1716 ovec.push_back(
'X');
1717 ovec.push_back(
'P');
1718 ovec.push_back(
'G');
1719 ovec.push_back(
'N');
1720 ovec.push_back(
',');
1723 spgn.Printf(
"%06X,", (
int)msg->PGN.pgn);
1724 std::string sspgn = spgn.ToStdString();
1725 for (
unsigned char c : sspgn) {
1731 if (i == nframes - 1) {
1736 attr |= ((uint16_t)((uint8_t)msg->priority & 0x07)) << 12;
1737 attr |= ((uint16_t)len) << 8;
1738 attr |= (uint16_t)dest_addr->address;
1742 sattr.Printf(
"%04X,", attr);
1743 std::string ssattr = sattr.ToStdString();
1744 for (
unsigned char c : ssattr) {
1749 uint8_t databytes = i == 0 ? len - 2 : len - 1;
1750 std::vector<unsigned char> payload;
1751 for (uint8_t j = 0; j < databytes; j++) {
1752 payload.push_back(msg->payload[cur]);
1757 int psize = payload.size();
1758 while ((i > 0) && (psize < 7)) {
1759 ovec.push_back(
'F');
1760 ovec.push_back(
'F');
1765 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1766 snprintf(tv, 3,
"%02X", *rit);
1767 ovec.push_back(tv[0]);
1768 ovec.push_back(tv[1]);
1771 snprintf(tv, 3,
"%02X", (uint8_t)msg->payload.size());
1772 ovec.push_back(tv[0]);
1773 ovec.push_back(tv[1]);
1776 snprintf(tv, 3,
"%02X", (uint8_t)i | m_order);
1777 ovec.push_back(tv[0]);
1778 ovec.push_back(tv[1]);
1782 for (
auto ci = ++ovec.begin(); ci != ovec.end(); ci++) {
1785 ovec.push_back(
'*');
1786 snprintf(tv, 3,
"%02X", crc);
1787 ovec.push_back(tv[0]);
1788 ovec.push_back(tv[1]);
1791 ovec.push_back(0x0d);
1792 ovec.push_back(0x0a);
1798 tx_vector.push_back(ovec);
1804 case N2KFormat_Actisense_N2K:
1805 case N2KFormat_Actisense_RAW:
1806 case N2KFormat_Actisense_NGT:
1807 case N2KFormat_SeaSmart:
1813 m_order = (m_order + 0x20) & 0xE0;
1818bool CommDriverN2KNet::PrepareForTX() {
1833 if (m_n2k_format == N2KFormat_Actisense_N2K_ASCII)
return true;
1840 if (m_n2k_format == N2KFormat_MiniPlex)
return true;
1845 if (m_n2k_format == N2KFormat_SeaSmart)
return false;
1858 std::vector<unsigned char> payload;
1859 payload.push_back(0x14);
1860 payload.push_back(0xF0);
1861 payload.push_back(0x01);
1863 std::vector<std::vector<unsigned char>> out_data;
1864 std::vector<unsigned char> msg_vec =
1865 MakeSimpleOutMsg(N2KFormat_YD_RAW, 59904, payload);
1866 out_data.push_back(msg_vec);
1867 SendSentenceNetwork(out_data);
1870 m_prodinfo_timer.Start(200,
true);
1877bool CommDriverN2KNet::SendN2KNetwork(
1878 const std::shared_ptr<const Nmea2000Msg>& msg,
1879 const std::shared_ptr<const NavAddr2000>& addr) {
1882 std::vector<std::vector<unsigned char>> out_data = GetTxVector(msg, addr);
1883 SendSentenceNetwork(out_data);
1884 m_driver_stats.
tx_count += msg->payload.size();
1887 std::vector<unsigned char> msg_payload = PrepareLogPayload(msg, addr);
1889 std::make_shared<const Nmea2000Msg>(msg->PGN.pgn, msg_payload, addr));
1894bool CommDriverN2KNet::SendSentenceNetwork(
1895 const std::vector<std::vector<unsigned char>>& payload) {
1902 wxDatagramSocket* udp_socket;
1903 switch (GetProtocol()) {
1905 for (
const std::vector<unsigned char>& v : payload) {
1906 if (GetSock() && GetSock()->IsOk()) {
1907 m_driver_stats.available =
true;
1909 GetSock()->Write(v.data(), v.size());
1910 m_dog_value = N_DOG_TIMEOUT;
1911 if (GetSock()->Error()) {
1912 if (GetSockServer()) {
1913 GetSock()->Destroy();
1916 auto* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
1917 if (tcp_socket) tcp_socket->Close();
1918 if (!GetSocketTimer()->IsRunning())
1919 GetSocketTimer()->Start(
1920 5000, wxTIMER_ONE_SHOT);
1921 GetSocketThreadWatchdogTimer()->Stop();
1927 m_driver_stats.available =
false;
1934 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
1935 if (udp_socket && udp_socket->IsOk()) {
1936 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
1937 if (udp_socket->Error()) ret =
false;
1952void CommDriverN2KNet::Close() {
1953 wxLogMessage(wxString::Format(
"Closing NMEA NetworkDataStream %s",
1954 GetNetPort().c_str()));
1955 m_stats_timer.Stop();
1959 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
1960 sizeof(m_mrq_container->m_mrq));
1961 m_sock->Notify(FALSE);
1963 m_driver_stats.available =
false;
1967 m_tsock->Notify(FALSE);
1971 if (m_socket_server) {
1972 m_socket_server->Notify(FALSE);
1973 m_socket_server->Destroy();
1976 m_socket_timer.Stop();
1977 m_socketread_watchdog_timer.Stop();
1980bool CommDriverN2KNet::SetOutputSocketOptions(wxSocketBase* tsock) {
1989 int nagleDisable = 1;
1990 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
1991 sizeof(nagleDisable));
1997 unsigned long outbuf_size = 1024;
1998 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
1999 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)
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 DsPortTypeToString(dsPortType type)
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.