37#include <wx/msw/winundef.h>
47#include <wx/tokenzr.h>
48#include <wx/datetime.h>
58#include <netinet/tcp.h>
65#include <wx/chartype.h>
67#include <wx/sckaddr.h>
69#include "model/comm_drv_n2k_net.h"
71#include "model/idents.h"
74#define N_DOG_TIMEOUT 8
76using namespace std::literals::chrono_literals;
78static const int kNotFound = -1;
83 void SetMrqAddr(
unsigned int addr) {
84 m_mrq.imr_multiaddr.s_addr = addr;
85 m_mrq.imr_interface.s_addr = INADDR_ANY;
91circular_buffer::circular_buffer(
size_t size)
92 : buf_(std::unique_ptr<unsigned char[]>(new unsigned char[size])),
104bool circular_buffer::empty()
const {
106 return (!full_ && (head_ == tail_));
109bool circular_buffer::full()
const {
114void circular_buffer::put(
unsigned char item) {
115 std::lock_guard<std::mutex> lock(mutex_);
117 if (full_) tail_ = (tail_ + 1) % max_size_;
119 head_ = (head_ + 1) % max_size_;
121 full_ = head_ == tail_;
124unsigned char circular_buffer::get() {
125 std::lock_guard<std::mutex> lock(mutex_);
127 if (empty())
return 0;
130 auto val = buf_[tail_];
132 tail_ = (tail_ + 1) % max_size_;
139 : priority(
'\0'), source(
'\0'), destination(
'\0'), pgn(-1) {};
149 : wxEvent(
id, commandType) {};
153 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
156 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
159 wxEvent* Clone()
const {
161 newevent->m_payload = this->m_payload;
166 std::shared_ptr<std::vector<unsigned char>> m_payload;
169static uint64_t PayloadToName(
const std::vector<unsigned char> payload) {
171 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
179#define TIMER_SOCKET_N2KNET 7339
182EVT_TIMER(TIMER_SOCKET_N2KNET, CommDriverN2KNet::OnTimerSocket)
184EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN2KNet::OnServerSocketEvent)
185EVT_TIMER(TIMER_SOCKET_N2KNET + 1, CommDriverN2KNet::OnSocketReadWatchdogTimer)
194 m_listener(listener),
195 m_stats_timer(*this, 2s),
196 m_net_port(wxString::Format("%i", params->NetworkPort)),
197 m_net_protocol(params->NetProtocol),
200 m_socket_server(NULL),
201 m_is_multicast(false),
203 m_portstring(params->GetDSPort()),
204 m_io_select(params->IOSelect),
205 m_connection_type(params->Type),
207 m_TX_available(false) {
208 m_addr.Hostname(params->NetworkAddress);
209 m_addr.Service(params->NetworkPort);
211 m_driver_stats.driver_bus = NavAddr::Bus::N2000;
212 m_driver_stats.driver_iface = params->GetStrippedDSPort();
214 m_socket_timer.SetOwner(
this, TIMER_SOCKET_N2KNET);
215 m_socketread_watchdog_timer.SetOwner(
this, TIMER_SOCKET_N2KNET + 1);
216 this->attributes[
"netAddress"] = params->NetworkAddress.ToStdString();
218 sprintf(port_char,
"%d", params->NetworkPort);
219 this->attributes[
"netPort"] = std::string(port_char);
220 this->attributes[
"userComment"] = params->UserComment.ToStdString();
221 this->attributes[
"ioDirection"] = DsPortTypeToString(params->IOSelect);
224 Bind(wxEVT_COMMDRIVER_N2K_NET, &CommDriverN2KNet::handle_N2K_MSG,
this);
226 m_prodinfo_timer.Connect(
227 wxEVT_TIMER, wxTimerEventHandler(CommDriverN2KNet::OnProdInfoTimer), NULL,
235 rx_buffer =
new unsigned char[RX_BUFFER_SIZE_NET + 1];
240 m_n2k_format = N2KFormat_YD_RAW;
243 resume_listener.Init(SystemEvents::GetInstance().evt_resume,
249CommDriverN2KNet::~CommDriverN2KNet() {
250 delete m_mrq_container;
258 std::string Model_ID;
262std::unordered_map<uint8_t, product_info> prod_info_map;
264bool CommDriverN2KNet::HandleMgntMsg(uint64_t pgn,
265 std::vector<unsigned char>& payload) {
267 auto name = PayloadToName(payload);
269 std::make_shared<const Nmea2000Msg>(pgn, payload, GetAddress(name));
271 bool b_handled =
false;
274 uint8_t src_addr = payload.at(7);
275 if (src_addr == 75)
return false;
277 pr_info.Model_ID = std::string((
char*)&payload.data()[17], 32);
278 pr_info.RT_flag = m_TX_flag;
280 prod_info_map[src_addr] = pr_info;
285 uint8_t src_addr = payload.at(7);
295void CommDriverN2KNet::OnProdInfoTimer(wxTimerEvent& ev) {
297 bool b_found =
false;
298 for (
const auto& [key, value] : prod_info_map) {
299 auto prod_info = value;
300 if (prod_info.Model_ID.find(
"YDEN") != std::string::npos) {
305 if (prod_info.RT_flag ==
'T') b_found =
true;
310 if (b_found) m_TX_available =
true;
311 prod_info_map.clear();
315 auto p =
event.GetPayload();
316 std::vector<unsigned char>* payload = p.get();
320 unsigned char* c = (
unsigned char*)&pgn;
321 *c++ = payload->at(3);
322 *c++ = payload->at(4);
323 *c++ = payload->at(5);
327 auto name = PayloadToName(*payload);
329 std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
330 m_driver_stats.
rx_count += payload->size();
331 m_listener.
Notify(std::move(msg));
334void CommDriverN2KNet::Open(
void) {
336#if wxCHECK_VERSION(3, 0, 0)
338 ((
struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
341 ((
struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
344 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
347 switch (m_net_protocol) {
349 OpenNetworkTCP(addr);
353 OpenNetworkUDP(addr);
362void CommDriverN2KNet::OpenNetworkUDP(
unsigned int addr) {
363 if (GetPortType() != DS_TYPE_OUTPUT) {
366 wxIPV4address conn_addr;
367 conn_addr.Service(GetNetPort());
368 conn_addr.AnyAddress();
370 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
373 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
375 m_mrq_container->SetMrqAddr(addr);
376 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP,
377 &m_mrq_container->m_mrq,
378 sizeof(m_mrq_container->m_mrq));
381 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
383 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
385 GetSock()->Notify(TRUE);
386 GetSock()->SetTimeout(1);
387 m_driver_stats.available =
true;
391 if (GetPortType() != DS_TYPE_INPUT) {
392 wxIPV4address tconn_addr;
393 tconn_addr.Service(0);
394 tconn_addr.AnyAddress();
396 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
401 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(_T(
"255")))) {
402 int broadcastEnable = 1;
403 bool bam = GetTSock()->SetOption(
404 SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
sizeof(broadcastEnable));
406 m_driver_stats.available =
true;
410 SetConnectTime(wxDateTime::Now());
413void CommDriverN2KNet::OpenNetworkTCP(
unsigned int addr) {
414 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
415 wxLogMessage(wxString::Format(_T(
"Opening TCP Server %d"), isServer));
418 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
420 SetSock(
new wxSocketClient());
424 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
425 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
426 GetSockServer()->Notify(TRUE);
427 GetSockServer()->SetTimeout(1);
429 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
430 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
431 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
432 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
433 GetSock()->SetNotify(notify_flags);
434 GetSock()->Notify(TRUE);
435 GetSock()->SetTimeout(1);
437 SetBrxConnectEvent(
false);
438 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
442 SetConnectTime(wxDateTime::Now());
445void CommDriverN2KNet::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
448 if (m_dog_value <= 0) {
449 if (GetParams().NoDataReconnect) {
451 if (GetProtocol() == TCP) {
452 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
453 if (tcp_socket) tcp_socket->Close();
455 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
456 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
458 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
461 GetSocketThreadWatchdogTimer()->Stop();
467void CommDriverN2KNet::OnTimerSocket() {
469 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
471 if (tcp_socket->IsDisconnected()) {
472 wxLogDebug(
" Attempting reconnection...");
473 SetBrxConnectEvent(
false);
475 GetSocketThreadWatchdogTimer()->Stop();
476 tcp_socket->Connect(GetAddr(), FALSE);
479 int n_reconnect_delay = N_DOG_TIMEOUT;
480 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
485void CommDriverN2KNet::HandleResume() {
487 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
489 GetSocketThreadWatchdogTimer()->Stop();
494 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
495 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
498 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
502bool CommDriverN2KNet::SendMessage(std::shared_ptr<const NavMsg> msg,
503 std::shared_ptr<const NavAddr> addr) {
504 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
505 auto dest_addr_n2k = std::static_pointer_cast<const NavAddr2000>(addr);
506 return SendN2KNetwork(msg_n2k, dest_addr_n2k);
509std::vector<unsigned char> CommDriverN2KNet::PrepareLogPayload(
510 std::shared_ptr<const Nmea2000Msg>& msg,
511 std::shared_ptr<const NavAddr2000> addr) {
512 std::vector<unsigned char> data;
513 data.push_back(0x94);
514 data.push_back(0x13);
515 data.push_back(msg->priority);
516 data.push_back(msg->PGN.pgn & 0xFF);
517 data.push_back((msg->PGN.pgn >> 8) & 0xFF);
518 data.push_back((msg->PGN.pgn >> 16) & 0xFF);
519 data.push_back(addr->address);
520 data.push_back(addr->address);
521 for (
size_t n = 0; n < msg->payload.size(); n++)
522 data.push_back(msg->payload[n]);
523 data.push_back(0x55);
527std::vector<unsigned char> CommDriverN2KNet::PushCompleteMsg(
528 const CanHeader header,
int position,
const can_frame frame) {
529 std::vector<unsigned char> data;
530 data.push_back(0x93);
531 data.push_back(0x13);
532 data.push_back(header.priority);
533 data.push_back(header.pgn & 0xFF);
534 data.push_back((header.pgn >> 8) & 0xFF);
535 data.push_back((header.pgn >> 16) & 0xFF);
536 data.push_back(header.destination);
537 data.push_back(header.source);
538 data.push_back(0xFF);
539 data.push_back(0xFF);
540 data.push_back(0xFF);
541 data.push_back(0xFF);
542 data.push_back(CAN_MAX_DLEN);
543 for (
size_t n = 0; n < CAN_MAX_DLEN; n++) data.push_back(frame.data[n]);
544 data.push_back(0x55);
548std::vector<unsigned char> CommDriverN2KNet::PushFastMsgFragment(
550 std::vector<unsigned char> data;
551 data.push_back(0x93);
552 data.push_back(fast_messages->entries[position].expected_length + 11);
553 data.push_back(header.priority);
554 data.push_back(header.pgn & 0xFF);
555 data.push_back((header.pgn >> 8) & 0xFF);
556 data.push_back((header.pgn >> 16) & 0xFF);
557 data.push_back(header.destination);
558 data.push_back(header.source);
559 data.push_back(0xFF);
560 data.push_back(0xFF);
561 data.push_back(0xFF);
562 data.push_back(0xFF);
563 data.push_back(fast_messages->entries[position].expected_length);
564 for (
size_t n = 0; n < fast_messages->entries[position].expected_length; n++)
565 data.push_back(fast_messages->entries[position].data[n]);
566 data.push_back(0x55);
567 fast_messages->
Remove(position);
577void CommDriverN2KNet::HandleCanFrameInput(can_frame frame) {
584 if (position == kNotFound) {
591 if ((frame.data[0] & 0x1F) == 0) {
593 ready = fast_messages->
InsertEntry(header, frame.data, position);
598 ready = fast_messages->
AppendEntry(header, frame.data, position);
602 std::vector<unsigned char> vec;
605 vec = PushFastMsgFragment(header, position);
608 vec = PushCompleteMsg(header, position, frame);
612 if (HandleMgntMsg(header.pgn, vec))
return;
616 auto payload = std::make_shared<std::vector<uint8_t>>(vec);
617 Nevent.SetPayload(payload);
618 AddPendingEvent(Nevent);
622bool isASCII(std::vector<unsigned char> packet) {
623 for (
unsigned char c : packet) {
624 if (!isascii(c))
return false;
629N2K_Format CommDriverN2KNet::DetectFormat(std::vector<unsigned char> packet) {
634 if (isASCII(packet)) {
635 std::string payload = std::string(packet.begin(), packet.end());
636 if (payload.find(
"$PCDIN") != std::string::npos) {
637 return N2KFormat_SeaSmart;
638 }
else if (payload.find(
"$MXPGN") != std::string::npos) {
642 return N2KFormat_MiniPlex;
643 }
else if (std::find(packet.begin(), packet.end(),
':') != packet.end()) {
644 return N2KFormat_Actisense_RAW_ASCII;
646 return N2KFormat_Actisense_N2K_ASCII;
649 if (packet[2] == 0x95)
650 return N2KFormat_Actisense_RAW;
651 else if (packet[2] == 0xd0)
652 return N2KFormat_Actisense_N2K;
653 else if (packet[2] == 0x93)
654 return N2KFormat_Actisense_NGT;
656 return N2KFormat_Undefined;
659bool CommDriverN2KNet::ProcessActisense_N2K(std::vector<unsigned char> packet) {
662 std::vector<unsigned char> data;
664 bool bGotESC =
false;
665 bool bGotSOT =
false;
667 while (!m_circle->empty()) {
668 uint8_t next_byte = m_circle->get();
672 if (next_byte == ESCAPE) {
673 data.push_back(next_byte);
675 }
else if (next_byte == ENDOFTEXT) {
679 unsigned int msg_length =
680 (uint32_t)data[1] + ((uint32_t)data[2] << 8);
683 if (msg_length == data.size() - 1) {
684 uint8_t destination = data[3];
685 uint8_t source = data[4];
687 uint8_t dprp = data[7];
690 uint8_t rAndDP = dprp & 3;
693 uint8_t pduFormat = data[6];
694 uint32_t pgn = (rAndDP << 16) + (pduFormat << 8);
700 std::vector<uint8_t> o_payload;
701 o_payload.push_back(0x93);
702 o_payload.push_back(0x13);
703 o_payload.push_back(priority);
704 o_payload.push_back(pgn & 0xFF);
705 o_payload.push_back((pgn >> 8) & 0xFF);
706 o_payload.push_back((pgn >> 16) & 0xFF);
707 o_payload.push_back(destination);
708 o_payload.push_back(source);
709 o_payload.push_back(0xFF);
710 o_payload.push_back(0xFF);
711 o_payload.push_back(0xFF);
712 o_payload.push_back(0xFF);
713 o_payload.push_back(data.size());
716 for (
size_t n = 13; n < data.size() - 1; n++)
717 o_payload.push_back(data[n]);
719 o_payload.push_back(0x55);
724 std::make_shared<std::vector<uint8_t>>(o_payload);
725 Nevent.SetPayload(n2k_payload);
726 AddPendingEvent(Nevent);
733 }
else if (next_byte == STARTOFTEXT) {
742 bGotESC = (next_byte == ESCAPE);
745 data.push_back(next_byte);
751 if (STARTOFTEXT == next_byte) {
757 bGotESC = (next_byte == ESCAPE);
762 data.push_back(next_byte);
771bool CommDriverN2KNet::ProcessActisense_RAW(std::vector<unsigned char> packet) {
776 std::vector<unsigned char> data;
778 bool bGotESC =
false;
779 bool bGotSOT =
false;
781 while (!m_circle->empty()) {
782 uint8_t next_byte = m_circle->get();
786 if (next_byte == ESCAPE) {
787 data.push_back(next_byte);
789 }
else if (next_byte == ENDOFTEXT) {
794 if (data.size() >= 8) {
795 size_t dLen = data[1];
797 if (dLen + 3 == data.size()) {
799 memcpy(&frame.can_id, &data.data()[4], 4);
802 memcpy(&frame.data, &data.data()[8], 8);
804 HandleCanFrameInput(frame);
812 }
else if (next_byte == STARTOFTEXT) {
821 bGotESC = (next_byte == ESCAPE);
824 data.push_back(next_byte);
830 if (STARTOFTEXT == next_byte) {
836 bGotESC = (next_byte == ESCAPE);
841 data.push_back(next_byte);
850bool CommDriverN2KNet::ProcessActisense_NGT(std::vector<unsigned char> packet) {
851 std::vector<unsigned char> data;
853 bool bGotESC =
false;
854 bool bGotSOT =
false;
856 while (!m_circle->empty()) {
857 uint8_t next_byte = m_circle->get();
861 if (next_byte == ESCAPE) {
862 data.push_back(next_byte);
864 }
else if (next_byte == ENDOFTEXT) {
867 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(data);
868 Nevent.SetPayload(n2k_payload);
869 AddPendingEvent(Nevent);
875 }
else if (next_byte == STARTOFTEXT) {
884 bGotESC = (next_byte == ESCAPE);
887 data.push_back(next_byte);
893 if (STARTOFTEXT == next_byte) {
899 bGotESC = (next_byte == ESCAPE);
904 data.push_back(next_byte);
913bool CommDriverN2KNet::ProcessActisense_ASCII_RAW(
914 std::vector<unsigned char> packet) {
917 while (!m_circle->empty()) {
918 char b = m_circle->get();
919 if ((b != 0x0a) && (b != 0x0d)) {
927 wxString ss(m_sentence.c_str());
929 wxStringTokenizer tkz(ss,
" ");
932 wxString token = tkz.GetNextToken();
934 token = tkz.GetNextToken();
936 m_TX_flag = token[0];
939 token = tkz.GetNextToken();
941 token.ToLong(&canID, 16);
942 frame.can_id = canID;
945 unsigned char bytes[8];
947 for (
unsigned int i = 0; i < 8; i++) {
948 if (tkz.HasMoreTokens()) {
949 token = tkz.GetNextToken();
951 token.ToLong(&tui, 16);
952 bytes[i] = (uint8_t)tui;
955 memcpy(&frame.data, bytes, 8);
956 HandleCanFrameInput(frame);
962bool CommDriverN2KNet::ProcessActisense_ASCII_N2K(
963 std::vector<unsigned char> packet) {
965 std::string sentence;
967 while (!m_circle->empty()) {
968 char b = m_circle->get();
969 if ((b != 0x0a) && (b != 0x0d)) {
977 wxString ss(sentence.c_str());
978 wxStringTokenizer tkz(ss,
" ");
982 wxString time_header = tkz.GetNextToken();
984 wxString sprio_addr = tkz.GetNextToken();
986 sprio_addr.ToLong(&prio_addr, 16);
987 uint8_t priority = (uint8_t)prio_addr & 0X0F;
988 uint8_t destination = (uint8_t)(prio_addr >> 4) & 0X0FF;
989 uint8_t source = (uint8_t)(prio_addr >> 12) & 0X0FF;
992 wxString sPGN = tkz.GetNextToken();
994 sPGN.ToULong(&PGN, 16);
998 wxString sdata = tkz.GetNextToken();
999 std::vector<uint8_t> data;
1000 for (
size_t i = 0; i < sdata.Length(); i += 2) {
1002 wxString stui = sdata.Mid(i, 2);
1003 stui.ToLong(&dv, 16);
1004 data.push_back((uint8_t)dv);
1008 std::vector<uint8_t> o_payload;
1009 o_payload.push_back(0x93);
1010 o_payload.push_back(0x13);
1011 o_payload.push_back(priority);
1012 o_payload.push_back(PGN & 0xFF);
1013 o_payload.push_back((PGN >> 8) & 0xFF);
1014 o_payload.push_back((PGN >> 16) & 0xFF);
1015 o_payload.push_back(destination);
1016 o_payload.push_back(source);
1017 o_payload.push_back(0xFF);
1018 o_payload.push_back(0xFF);
1019 o_payload.push_back(0xFF);
1020 o_payload.push_back(0xFF);
1021 o_payload.push_back(data.size());
1022 for (
size_t n = 0; n < data.size(); n++) o_payload.push_back(data[n]);
1023 o_payload.push_back(0x55);
1025 if (HandleMgntMsg(PGN, o_payload))
return false;
1029 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
1030 Nevent.SetPayload(n2k_payload);
1031 AddPendingEvent(Nevent);
1037bool CommDriverN2KNet::ProcessSeaSmart(std::vector<unsigned char> packet) {
1038 while (!m_circle->empty()) {
1039 char b = m_circle->get();
1040 if ((b != 0x0a) && (b != 0x0d)) {
1048 wxString ss(m_sentence.c_str());
1050 wxStringTokenizer tkz(ss,
",");
1053 wxString token = tkz.GetNextToken();
1056 token = tkz.GetNextToken();
1058 token.ToULong(&PGN, 16);
1060 token = tkz.GetNextToken();
1061 unsigned long timestamp;
1062 token.ToULong(×tamp, 16);
1064 token = tkz.GetNextToken();
1065 unsigned long source;
1066 token.ToULong(&source, 16);
1068 token = tkz.GetNextToken();
1070 wxStringTokenizer datatkz(token,
"*");
1071 wxString data = datatkz.GetNextToken();
1074 std::vector<uint8_t> o_payload;
1075 o_payload.push_back(0x93);
1076 o_payload.push_back(0x13);
1077 o_payload.push_back(3);
1078 o_payload.push_back(PGN & 0xFF);
1079 o_payload.push_back((PGN >> 8) & 0xFF);
1080 o_payload.push_back((PGN >> 16) & 0xFF);
1081 o_payload.push_back(0xFF);
1082 o_payload.push_back((uint8_t)source);
1083 o_payload.push_back(timestamp & 0xFF);
1084 o_payload.push_back((timestamp >> 8) & 0xFF);
1085 o_payload.push_back((timestamp >> 16) & 0xFF);
1086 o_payload.push_back((timestamp >> 24) & 0xFF);
1087 o_payload.push_back((uint8_t)data.Length() / 2);
1088 for (
size_t i = 0; i < data.Length(); i += 2) {
1090 wxString sbyte = data.Mid(i, 2);
1091 sbyte.ToULong(&dv, 16);
1092 o_payload.push_back((uint8_t)dv);
1094 o_payload.push_back(0x55);
1096 if (HandleMgntMsg(PGN, o_payload))
return false;
1100 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
1101 Nevent.SetPayload(n2k_payload);
1102 AddPendingEvent(Nevent);
1108bool CommDriverN2KNet::ProcessMiniPlex(std::vector<unsigned char> packet) {
1203 while (!m_circle->empty()) {
1204 char b = m_circle->get();
1205 if ((b != 0x0a) && (b != 0x0d)) {
1213 wxString ss(m_sentence.c_str());
1215 wxStringTokenizer tkz(ss,
",");
1218 wxString token = tkz.GetNextToken();
1221 token = tkz.GetNextToken();
1223 token.ToULong(&PGN, 16);
1225 token = tkz.GetNextToken();
1227 token.ToULong(&attr, 16);
1229 bool send_bit = (attr >> 15) != 0;
1231 uint8_t priority = (attr >> 12) & 0x07;
1234 uint8_t dlc = (attr >> 8) & 0x0F;
1237 uint8_t address = attr & 0xFF;
1239 token = tkz.GetNextToken();
1241 wxStringTokenizer datatkz(token,
"*");
1242 wxString data = datatkz.GetNextToken();
1250 memset(&frame.data, 0, 8);
1251 for (
size_t i = 0; i < data.Length(); i += 2) {
1253 wxString sbyte = data.Mid(data.Length() - i - 2, 2);
1254 sbyte.ToULong(&dv, 16);
1255 frame.data[i / 2] = ((uint8_t)dv);
1257 frame.can_id = (uint32_t)BuildCanID(priority, address, 0xFF, PGN);
1258 HandleCanFrameInput(frame);
1265#define RD_BUF_SIZE 4096
1268 switch (event.GetSocketEvent()) {
1269 case wxSOCKET_INPUT: {
1283 std::vector<unsigned char> data(RD_BUF_SIZE + 1);
1285 uint8_t next_byte = 0;
1287 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
1288 if (!event.GetSocket()->Error()) {
1289 m_driver_stats.available =
true;
1290 size_t count =
event.GetSocket()->LastCount();
1303 for (
int i = 0; i < newdata; i++) {
1304 m_circle->put(data[i]);
1309 m_n2k_format = DetectFormat(data);
1311 switch (m_n2k_format) {
1312 case N2KFormat_Actisense_RAW_ASCII:
1313 ProcessActisense_ASCII_RAW(data);
1315 case N2KFormat_YD_RAW:
1316 ProcessActisense_ASCII_RAW(data);
1318 case N2KFormat_Actisense_N2K_ASCII:
1319 ProcessActisense_ASCII_N2K(data);
1321 case N2KFormat_Actisense_N2K:
1322 ProcessActisense_N2K(data);
1324 case N2KFormat_Actisense_RAW:
1325 ProcessActisense_RAW(data);
1327 case N2KFormat_Actisense_NGT:
1328 ProcessActisense_NGT(data);
1330 case N2KFormat_SeaSmart:
1331 ProcessSeaSmart(data);
1333 case N2KFormat_MiniPlex:
1334 ProcessMiniPlex(data);
1336 case N2KFormat_Undefined:
1343 m_dog_value = N_DOG_TIMEOUT;
1347 case wxSOCKET_LOST: {
1348 m_driver_stats.available =
false;
1349 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
1350 if (GetBrxConnectEvent())
1351 wxLogMessage(wxString::Format(
1352 _T(
"NetworkDataStream connection lost: %s"), GetPort().c_str()));
1353 if (GetSockServer()) {
1354 GetSock()->Destroy();
1358 wxDateTime now = wxDateTime::Now();
1359 wxTimeSpan since_connect(
1361 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
1363 int retry_time = 5000;
1369 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
1372 GetSocketThreadWatchdogTimer()->Stop();
1373 GetSocketTimer()->Start(
1374 retry_time, wxTIMER_ONE_SHOT);
1379 case wxSOCKET_CONNECTION: {
1380 m_driver_stats.available =
true;
1381 if (GetProtocol() == GPSD) {
1385 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
1386 GetSock()->Write(cmd, strlen(cmd));
1387 }
else if (GetProtocol() == TCP) {
1388 wxLogMessage(wxString::Format(
1389 _T(
"TCP NetworkDataStream connection established: %s"),
1390 GetPort().c_str()));
1391 m_dog_value = N_DOG_TIMEOUT;
1392 if (GetPortType() != DS_TYPE_OUTPUT) {
1394 if (GetParams().NoDataReconnect)
1395 GetSocketThreadWatchdogTimer()->Start(1000);
1397 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
1398 (void)SetOutputSocketOptions(GetSock());
1399 GetSocketTimer()->Stop();
1400 SetBrxConnectEvent(
true);
1403 SetConnectTime(wxDateTime::Now());
1412void CommDriverN2KNet::OnServerSocketEvent(wxSocketEvent& event) {
1413 switch (event.GetSocketEvent()) {
1414 case wxSOCKET_CONNECTION: {
1415 m_driver_stats.available =
true;
1416 SetSock(GetSockServer()->Accept(
false));
1419 GetSock()->SetTimeout(2);
1421 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
1422 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
1423 if (GetPortType() != DS_TYPE_INPUT) {
1424 notify_flags |= wxSOCKET_OUTPUT_FLAG;
1425 (void)SetOutputSocketOptions(GetSock());
1427 if (GetPortType() != DS_TYPE_OUTPUT)
1428 notify_flags |= wxSOCKET_INPUT_FLAG;
1429 GetSock()->SetNotify(notify_flags);
1430 GetSock()->Notify(
true);
1441std::vector<unsigned char> MakeSimpleOutMsg(
1442 int data_format,
int pgn, std::vector<unsigned char>& payload) {
1443 std::vector<unsigned char> out_vec;
1445 switch (data_format) {
1446 case N2KFormat_YD_RAW:
1447 case N2KFormat_Actisense_RAW_ASCII: {
1449 unsigned can_id = BuildCanID(6, 0xff, 0xff, pgn);
1450 std::stringstream ss;
1451 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1452 for (
unsigned char s : ss.str()) out_vec.push_back(s);
1453 out_vec.push_back(
' ');
1458 for (
unsigned char d : payload) {
1459 snprintf(tv, 4,
"%02X ", d);
1462 for (
unsigned char s : sspl) out_vec.push_back(s);
1466 out_vec.push_back(0x0d);
1467 out_vec.push_back(0x0a);
1470 case N2KFormat_Actisense_N2K_ASCII: {
1472 wxDateTime now = wxDateTime::Now();
1473 wxString stime = now.Format(
"%H%M%S");
1475 std::string sstime = stime.ToStdString();
1476 out_vec.push_back(
'A');
1477 for (
unsigned char s : sstime) out_vec.push_back(s);
1481 sdp.Printf(
"%02X%02X%1X ",
1483 (
unsigned char)0xFF, 0x6);
1484 std::string ssdp = sdp.ToStdString();
1485 for (
unsigned char s : ssdp) out_vec.push_back(s);
1489 spgn.Printf(
"%05X ", pgn);
1490 std::string sspgn = spgn.ToStdString();
1491 for (
unsigned char s : sspgn) out_vec.push_back(s);
1496 for (
unsigned char d : payload) {
1497 snprintf(tv, 3,
"%02X", d);
1500 for (
unsigned char s : sspl) out_vec.push_back(s);
1503 out_vec.push_back(0x0d);
1504 out_vec.push_back(0x0a);
1507 case N2KFormat_MiniPlex: {
1508 out_vec.push_back(
'$');
1509 out_vec.push_back(
'M');
1510 out_vec.push_back(
'X');
1511 out_vec.push_back(
'P');
1512 out_vec.push_back(
'G');
1513 out_vec.push_back(
'N');
1514 out_vec.push_back(
',');
1517 spgn.Printf(
"%06X,", pgn);
1518 std::string sspgn = spgn.ToStdString();
1519 for (
unsigned char c : sspgn) {
1520 out_vec.push_back(c);
1526 attr |= ((uint16_t)0x06) << 12;
1527 attr |= ((uint16_t)payload.size()) << 8;
1528 attr |= (uint16_t)0xFF;
1532 sattr.Printf(
"%04X,", attr);
1533 std::string ssattr = sattr.ToStdString();
1534 for (
unsigned char c : ssattr) {
1535 out_vec.push_back(c);
1539 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1540 snprintf(tv, 3,
"%02X", *rit);
1541 out_vec.push_back(tv[0]);
1542 out_vec.push_back(tv[1]);
1546 for (
auto ci = ++out_vec.begin(); ci != out_vec.end(); ci++) {
1549 out_vec.push_back(
'*');
1550 snprintf(tv, 3,
"%02X", crc);
1551 out_vec.push_back(tv[0]);
1552 out_vec.push_back(tv[1]);
1555 out_vec.push_back(0x0d);
1556 out_vec.push_back(0x0a);
1567std::vector<std::vector<unsigned char>> CommDriverN2KNet::GetTxVector(
1568 const std::shared_ptr<const Nmea2000Msg>& msg,
1569 std::shared_ptr<const NavAddr2000> dest_addr) {
1570 std::vector<std::vector<unsigned char>> tx_vector;
1573 switch (m_n2k_format) {
1574 case N2KFormat_YD_RAW:
1576 case N2KFormat_Actisense_RAW_ASCII: {
1578 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() <= 8) {
1580 std::vector<unsigned char> header_vec;
1581 std::vector<unsigned char> out_vec;
1586 unsigned long can_id =
1587 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 for (
unsigned char s : header_vec) out_vec.push_back(s);
1599 for (
unsigned int k = 0; k < msg->payload.size(); k++) {
1601 snprintf(tb, 4,
"%02X ", msg->payload.data()[k]);
1604 for (
unsigned char s : ssdata) out_vec.push_back(s);
1607 out_vec.push_back(0x0d);
1608 out_vec.push_back(0x0a);
1610 tx_vector.push_back(out_vec);
1612 std::vector<unsigned char> header_vec;
1613 std::vector<unsigned char> out_vec;
1618 wxDateTime now = wxDateTime::Now();
1619 wxString stime = now.Format(
"%H:%M:%S");
1621 std::string sstime = stime.ToStdString();
1622 for (
unsigned char s : sstime) header_vec.push_back(s);
1625 header_vec.push_back(
'T');
1626 header_vec.push_back(
' ');
1632 unsigned long can_id =
1633 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1634 std::stringstream ss;
1635 ss << std::setfill(
'0') << std::setw(8) << std::hex << can_id;
1636 for (
unsigned char s : ss.str()) header_vec.push_back(s);
1637 header_vec.push_back(
' ');
1640 int payload_size = msg->payload.size();
1641 unsigned char temp[8];
1644 (payload_size > 6 ? (payload_size - 6 - 1) / 7 + 1 + 1 : 1);
1646 for (
int i = 0; i < nframes && result; i++) {
1647 temp[0] = i | m_order;
1649 temp[1] = msg->payload.size();
1651 for (
int j = 2; j < 8; j++) {
1652 temp[j] = msg->payload.data()[cur];
1658 for (; j < 8 && cur < payload_size; j++) {
1659 temp[j] = msg->payload.data()[cur];
1662 for (; j < 8; j++) {
1670 for (
unsigned char s : header_vec) out_vec.push_back(s);
1674 for (
unsigned int k = 0; k < 8; k++) {
1676 snprintf(tb, 4,
"%02X ", temp[k]);
1679 for (
unsigned char s : ssdata) out_vec.push_back(s);
1682 out_vec.push_back(0x0d);
1683 out_vec.push_back(0x0a);
1685 tx_vector.push_back(out_vec);
1689 case N2KFormat_Actisense_N2K_ASCII: {
1706 std::vector<unsigned char> ovec;
1709 wxDateTime now = wxDateTime::Now();
1710 wxString stime = now.Format(
"%H%M%S");
1712 std::string sstime = stime.ToStdString();
1713 ovec.push_back(
'A');
1714 for (
unsigned char s : sstime) ovec.push_back(s);
1718 sdp.Printf(
"%02X%02X%1X ",
1720 (
unsigned char)dest_addr->address,
1721 (
unsigned char)msg->priority);
1722 std::string ssdp = sdp.ToStdString();
1723 for (
unsigned char s : ssdp) ovec.push_back(s);
1727 spgn.Printf(
"%05X ", (
int)msg->PGN.pgn);
1728 std::string sspgn = spgn.ToStdString();
1729 for (
unsigned char s : sspgn) ovec.push_back(s);
1734 for (
unsigned char d : msg->payload) {
1735 snprintf(tv, 3,
"%02X", d);
1738 for (
unsigned char s : sspl) ovec.push_back(s);
1741 ovec.push_back(0x0d);
1742 ovec.push_back(0x0a);
1745 tx_vector.push_back(ovec);
1749 case N2KFormat_MiniPlex: {
1750 std::vector<unsigned char> ovec;
1751 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1756 (msg->payload.size() > 6 ? (msg->payload.size() - 6 - 1) / 7 + 1 + 1
1758 for (
size_t i = 0; i < nframes; i++) {
1759 ovec.push_back(
'$');
1760 ovec.push_back(
'M');
1761 ovec.push_back(
'X');
1762 ovec.push_back(
'P');
1763 ovec.push_back(
'G');
1764 ovec.push_back(
'N');
1765 ovec.push_back(
',');
1768 spgn.Printf(
"%06X,", (
int)msg->PGN.pgn);
1769 std::string sspgn = spgn.ToStdString();
1770 for (
unsigned char c : sspgn) {
1776 if (i == nframes - 1) {
1777 len = msg->payload.size() + 1 - 6 - (nframes - 2) * 7;
1779 attr |= ((uint16_t)((uint8_t)msg->priority & 0x07)) << 12;
1780 attr |= ((uint16_t)len) << 8;
1781 attr |= (uint16_t)dest_addr->address;
1785 sattr.Printf(
"%04X,", attr);
1786 std::string ssattr = sattr.ToStdString();
1787 for (
unsigned char c : ssattr) {
1792 uint8_t databytes = i == 0 ? len - 2 : len - 1;
1793 std::vector<unsigned char> payload;
1794 for (uint8_t j = 0; j < databytes; j++) {
1795 payload.push_back(msg->payload[cur]);
1798 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1799 snprintf(tv, 3,
"%02X", *rit);
1800 ovec.push_back(tv[0]);
1801 ovec.push_back(tv[1]);
1804 snprintf(tv, 3,
"%02X", (uint8_t)msg->payload.size());
1805 ovec.push_back(tv[0]);
1806 ovec.push_back(tv[1]);
1809 snprintf(tv, 3,
"%02X", (uint8_t)i | m_order);
1810 ovec.push_back(tv[0]);
1811 ovec.push_back(tv[1]);
1815 for (
auto ci = ++ovec.begin(); ci != ovec.end(); ci++) {
1818 ovec.push_back(
'*');
1819 snprintf(tv, 3,
"%02X", crc);
1820 ovec.push_back(tv[0]);
1821 ovec.push_back(tv[1]);
1824 ovec.push_back(0x0d);
1825 ovec.push_back(0x0a);
1831 tx_vector.push_back(ovec);
1838 case N2KFormat_Actisense_N2K:
1840 case N2KFormat_Actisense_RAW:
1842 case N2KFormat_Actisense_NGT:
1844 case N2KFormat_SeaSmart:
1855bool CommDriverN2KNet::PrepareForTX() {
1865 bool b_found =
false;
1872 if (m_n2k_format == N2KFormat_Actisense_N2K_ASCII)
return true;
1879 if (m_n2k_format == N2KFormat_MiniPlex)
return true;
1884 if (m_n2k_format == N2KFormat_SeaSmart)
return false;
1897 std::vector<unsigned char> payload;
1898 payload.push_back(0x14);
1899 payload.push_back(0xF0);
1900 payload.push_back(0x01);
1902 std::vector<std::vector<unsigned char>> out_data;
1903 std::vector<unsigned char> msg_vec =
1904 MakeSimpleOutMsg(N2KFormat_YD_RAW, 59904, payload);
1905 out_data.push_back(msg_vec);
1906 SendSentenceNetwork(out_data);
1909 m_prodinfo_timer.Start(200,
true);
1916bool CommDriverN2KNet::SendN2KNetwork(std::shared_ptr<const Nmea2000Msg>& msg,
1917 std::shared_ptr<const NavAddr2000> addr) {
1920 std::vector<std::vector<unsigned char>> out_data = GetTxVector(msg, addr);
1921 SendSentenceNetwork(out_data);
1922 m_driver_stats.
tx_count += msg->payload.size();
1925 std::vector<unsigned char> msg_payload = PrepareLogPayload(msg, addr);
1927 std::make_shared<const Nmea2000Msg>(msg->PGN.pgn, msg_payload, addr);
1928 auto msg_all = std::make_shared<const Nmea2000Msg>(1, msg_payload, addr);
1931 m_listener.
Notify(std::move(msg_one));
1932 m_listener.
Notify(std::move(msg_all));
1937bool CommDriverN2KNet::SendSentenceNetwork(
1938 std::vector<std::vector<unsigned char>> payload) {
1945 wxDatagramSocket* udp_socket;
1946 switch (GetProtocol()) {
1948 for (std::vector<unsigned char>& v : payload) {
1949 if (GetSock() && GetSock()->IsOk()) {
1950 m_driver_stats.available =
true;
1952 GetSock()->Write(v.data(), v.size());
1953 m_dog_value = N_DOG_TIMEOUT;
1954 if (GetSock()->Error()) {
1955 if (GetSockServer()) {
1956 GetSock()->Destroy();
1959 wxSocketClient* tcp_socket =
1960 dynamic_cast<wxSocketClient*
>(GetSock());
1961 if (tcp_socket) tcp_socket->Close();
1962 if (!GetSocketTimer()->IsRunning())
1963 GetSocketTimer()->Start(
1964 5000, wxTIMER_ONE_SHOT);
1965 GetSocketThreadWatchdogTimer()->Stop();
1971 m_driver_stats.available =
false;
1978 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
1979 if (udp_socket && udp_socket->IsOk()) {
1980 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
1981 if (udp_socket->Error()) ret =
false;
1996void CommDriverN2KNet::Close() {
1997 wxLogMessage(wxString::Format(_T(
"Closing NMEA NetworkDataStream %s"),
1998 GetNetPort().c_str()));
1999 m_stats_timer.Stop();
2003 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
2004 sizeof(m_mrq_container->m_mrq));
2005 m_sock->Notify(FALSE);
2007 m_driver_stats.available =
false;
2011 m_tsock->Notify(FALSE);
2015 if (m_socket_server) {
2016 m_socket_server->Notify(FALSE);
2017 m_socket_server->Destroy();
2020 m_socket_timer.Stop();
2021 m_socketread_watchdog_timer.Stop();
2024bool CommDriverN2KNet::SetOutputSocketOptions(wxSocketBase* tsock) {
2033 int nagleDisable = 1;
2034 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
2035 sizeof(nagleDisable));
2041 unsigned long outbuf_size = 1024;
2042 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
2043 sizeof(outbuf_size)) &&
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.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
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.