34 #include <wx/msw/winundef.h>
38 #include <wx/wxprec.h>
44 #include <wx/tokenzr.h>
45 #include <wx/datetime.h>
51 #include "model/sys_events.h"
54 #include <arpa/inet.h>
55 #include <netinet/tcp.h>
59 #include <wx/socket.h>
61 #include <wx/memory.h>
62 #include <wx/chartype.h>
64 #include <wx/sckaddr.h>
67 #include "model/comm_drv_n2k_net.h"
68 #include "model/comm_navmsg_bus.h"
69 #include "model/idents.h"
70 #include "model/comm_drv_registry.h"
72 #define N_DOG_TIMEOUT 8
74 static const int kNotFound = -1;
79 void SetMrqAddr(
unsigned int addr) {
80 m_mrq.imr_multiaddr.s_addr = addr;
81 m_mrq.imr_interface.s_addr = INADDR_ANY;
87 circular_buffer::circular_buffer(
size_t size)
88 : buf_(std::unique_ptr<unsigned char[]>(new unsigned char[size])), max_size_(size) {}
99 bool circular_buffer::empty()
const {
101 return (!full_ && (head_ == tail_));
104 bool circular_buffer::full()
const {
109 void circular_buffer::put(
unsigned char item) {
110 std::lock_guard<std::mutex> lock(mutex_);
112 if (full_) tail_ = (tail_ + 1) % max_size_;
114 head_ = (head_ + 1) % max_size_;
116 full_ = head_ == tail_;
119 unsigned char circular_buffer::get() {
120 std::lock_guard<std::mutex> lock(mutex_);
122 if (empty())
return 0;
125 auto val = buf_[tail_];
127 tail_ = (tail_ + 1) % max_size_;
134 : priority(
'\0'), source(
'\0'), destination(
'\0'), pgn(-1) {};
146 : wxEvent(
id, commandType){};
150 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
153 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
156 wxEvent* Clone()
const {
158 newevent->m_payload = this->m_payload;
163 std::shared_ptr<std::vector<unsigned char>> m_payload;
166 static uint64_t PayloadToName(
const std::vector<unsigned char> payload) {
168 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
176 #define TIMER_SOCKET_N2KNET 7339
179 EVT_TIMER(TIMER_SOCKET_N2KNET, CommDriverN2KNet::OnTimerSocket)
181 EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN2KNet::OnServerSocketEvent)
182 EVT_TIMER(TIMER_SOCKET_N2KNET + 1, CommDriverN2KNet::OnSocketReadWatchdogTimer)
191 m_listener(listener),
192 m_net_port(wxString::Format("%i", params->NetworkPort)),
193 m_net_protocol(params->NetProtocol),
196 m_socket_server(NULL),
197 m_is_multicast(false),
199 m_portstring(params->GetDSPort()),
200 m_io_select(params->IOSelect),
201 m_connection_type(params->Type),
205 m_addr.Hostname(params->NetworkAddress);
206 m_addr.Service(params->NetworkPort);
208 m_socket_timer.SetOwner(
this, TIMER_SOCKET_N2KNET);
209 m_socketread_watchdog_timer.SetOwner(
this, TIMER_SOCKET_N2KNET + 1);
210 this->attributes[
"netAddress"] = params->NetworkAddress.ToStdString();
212 sprintf(port_char,
"%d",params->NetworkPort);
213 this->attributes[
"netPort"] = std::string(port_char);
214 this->attributes[
"userComment"] = params->UserComment.ToStdString();
215 this->attributes[
"ioDirection"] = std::string(
"IN/OUT");
218 Bind(wxEVT_COMMDRIVER_N2K_NET, &CommDriverN2KNet::handle_N2K_MSG,
this);
225 rx_buffer =
new unsigned char[RX_BUFFER_SIZE_NET + 1];
230 m_n2k_format = N2KFormat_YD_RAW;
233 resume_listener.Init(SystemEvents::GetInstance().evt_resume,
239 CommDriverN2KNet::~CommDriverN2KNet() {
240 delete m_mrq_container;
248 std::string Model_ID;
252 std::unordered_map<uint8_t, product_info> prod_info_map;
254 bool CommDriverN2KNet::HandleMgntMsg(uint64_t pgn, std::vector<unsigned char> &payload){
256 auto name = PayloadToName(payload);
257 auto msg = std::make_shared<const Nmea2000Msg>(pgn, payload, GetAddress(name));
259 bool b_handled =
false;
262 uint8_t src_addr = payload.at(7);
263 if(src_addr == 75)
return false;
265 pr_info.Model_ID = std::string((
char *) &payload.data()[17], 32);
266 pr_info.RT_flag = m_TX_flag;
268 prod_info_map[src_addr] = pr_info;
273 uint8_t src_addr = payload.at(7);
285 auto p =
event.GetPayload();
286 std::vector<unsigned char>* payload = p.get();
290 unsigned char* c = (
unsigned char*)&pgn;
291 *c++ = payload->at(3);
292 *c++ = payload->at(4);
293 *c++ = payload->at(5);
297 auto name = PayloadToName(*payload);
298 auto msg = std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
299 auto msg_all = std::make_shared<const Nmea2000Msg>(1, *payload, GetAddress(name));
301 m_listener.
Notify(std::move(msg));
302 m_listener.
Notify(std::move(msg_all));
306 CommDriverRegistry::GetInstance().
Activate(shared_from_this());
310 void CommDriverN2KNet::Open(
void) {
312 #if wxCHECK_VERSION(3, 0, 0)
314 ((
struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
317 ((
struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
320 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
323 switch (m_net_protocol) {
325 OpenNetworkTCP(addr);
329 OpenNetworkUDP(addr);
338 void CommDriverN2KNet::OpenNetworkUDP(
unsigned int addr) {
339 if (GetPortType() != DS_TYPE_OUTPUT) {
342 wxIPV4address conn_addr;
343 conn_addr.Service(GetNetPort());
344 conn_addr.AnyAddress();
346 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
349 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
351 m_mrq_container->SetMrqAddr(addr);
352 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &m_mrq_container->m_mrq,
353 sizeof(m_mrq_container->m_mrq));
356 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
358 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
360 GetSock()->Notify(TRUE);
361 GetSock()->SetTimeout(1);
365 if (GetPortType() != DS_TYPE_INPUT) {
366 wxIPV4address tconn_addr;
367 tconn_addr.Service(0);
368 tconn_addr.AnyAddress();
370 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
375 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(_T(
"255")))) {
376 int broadcastEnable = 1;
377 bool bam = GetTSock()->SetOption(
378 SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
sizeof(broadcastEnable));
383 SetConnectTime(wxDateTime::Now());
386 void CommDriverN2KNet::OpenNetworkTCP(
unsigned int addr) {
387 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
388 wxLogMessage(wxString::Format(_T(
"Opening TCP Server %d"), isServer));
391 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
393 SetSock(
new wxSocketClient());
397 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
398 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
399 GetSockServer()->Notify(TRUE);
400 GetSockServer()->SetTimeout(1);
402 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
403 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
404 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
405 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
406 GetSock()->SetNotify(notify_flags);
407 GetSock()->Notify(TRUE);
408 GetSock()->SetTimeout(1);
410 SetBrxConnectEvent(
false);
411 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
415 SetConnectTime(wxDateTime::Now());
419 void CommDriverN2KNet::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
422 if (m_dog_value <= 0) {
423 if (GetParams().NoDataReconnect) {
425 if (GetProtocol() == TCP) {
426 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
430 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
431 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
433 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
436 GetSocketThreadWatchdogTimer()->Stop();
442 void CommDriverN2KNet::OnTimerSocket() {
444 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
446 if (tcp_socket->IsDisconnected()) {
447 wxLogDebug(
" Attempting reconnection...");
448 SetBrxConnectEvent(
false);
450 GetSocketThreadWatchdogTimer()->Stop();
451 tcp_socket->Connect(GetAddr(), FALSE);
454 int n_reconnect_delay = N_DOG_TIMEOUT;
455 GetSocketTimer()->Start(n_reconnect_delay * 1000,
462 void CommDriverN2KNet::HandleResume() {
465 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
467 GetSocketThreadWatchdogTimer()->Stop();
472 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT-2, 2);
473 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.", n_reconnect_delay));
475 GetSocketTimer()->Start(n_reconnect_delay * 1000,
480 bool CommDriverN2KNet::SendMessage(std::shared_ptr<const NavMsg> msg,
481 std::shared_ptr<const NavAddr> addr) {
482 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
483 auto dest_addr_n2k = std::static_pointer_cast<const NavAddr2000>(addr);
484 return SendN2KNetwork(msg_n2k, dest_addr_n2k);
487 std::vector<unsigned char> CommDriverN2KNet::PushCompleteMsg(
const CanHeader header,
489 const can_frame frame) {
490 std::vector<unsigned char> data;
491 data.push_back(0x93);
492 data.push_back(0x13);
493 data.push_back(header.priority);
494 data.push_back(header.pgn & 0xFF);
495 data.push_back((header.pgn >> 8) & 0xFF);
496 data.push_back((header.pgn >> 16) & 0xFF);
497 data.push_back(header.destination);
498 data.push_back(header.source);
499 data.push_back(0xFF);
500 data.push_back(0xFF);
501 data.push_back(0xFF);
502 data.push_back(0xFF);
503 data.push_back(CAN_MAX_DLEN);
504 for (
size_t n = 0; n < CAN_MAX_DLEN; n++) data.push_back(frame.data[n]);
505 data.push_back(0x55);
509 std::vector<unsigned char> CommDriverN2KNet::PushFastMsgFragment(
const CanHeader& header,
511 std::vector<unsigned char> data;
512 data.push_back(0x93);
513 data.push_back(fast_messages->entries[position].expected_length + 11);
514 data.push_back(header.priority);
515 data.push_back(header.pgn & 0xFF);
516 data.push_back((header.pgn >> 8) & 0xFF);
517 data.push_back((header.pgn >> 16) & 0xFF);
518 data.push_back(header.destination);
519 data.push_back(header.source);
520 data.push_back(0xFF);
521 data.push_back(0xFF);
522 data.push_back(0xFF);
523 data.push_back(0xFF);
524 data.push_back(fast_messages->entries[position].expected_length);
525 for (
size_t n = 0; n < fast_messages->entries[position].expected_length; n++)
526 data.push_back(fast_messages->entries[position].data[n]);
527 data.push_back(0x55);
528 fast_messages->
Remove(position);
538 void CommDriverN2KNet::HandleCanFrameInput(can_frame frame) {
545 if (position == kNotFound) {
552 if ((frame.data[0] & 0x1F) == 0) {
554 ready = fast_messages->
InsertEntry(header, frame.data, position);
560 ready = fast_messages->
AppendEntry(header, frame.data, position);
564 std::vector<unsigned char> vec;
567 vec = PushFastMsgFragment(header, position);
570 vec = PushCompleteMsg(header, position, frame);
574 if (HandleMgntMsg( header.pgn, vec))
580 auto payload = std::make_shared<std::vector<uint8_t> >(vec);
581 Nevent.SetPayload(payload);
582 AddPendingEvent(Nevent);
587 bool isASCII(std::vector<unsigned char> packet) {
588 for (
unsigned char c : packet) {
589 if (!isascii(c))
return false;
594 N2K_Format CommDriverN2KNet::DetectFormat(std::vector<unsigned char> packet) {
600 if (isASCII(packet)) {
601 std::string payload = std::string(packet.begin(), packet.end());
602 if (payload.find(
"$PCDIN") != std::string::npos) {
603 return N2KFormat_SeaSmart;
604 }
else if (payload.find(
"$MXPGN") != std::string::npos) {
607 return N2KFormat_MiniPlex;
608 }
else if (std::find(packet.begin(), packet.end(),
':') != packet.end()) {
609 return N2KFormat_Actisense_RAW_ASCII;
611 return N2KFormat_Actisense_N2K_ASCII;
615 if (packet[2] == 0x95)
616 return N2KFormat_Actisense_RAW;
617 else if (packet[2] == 0xd0)
618 return N2KFormat_Actisense_N2K;
619 else if (packet[2] == 0x93)
620 return N2KFormat_Actisense_NGT;
622 return N2KFormat_Undefined;
625 bool CommDriverN2KNet::ProcessActisense_N2K(std::vector<unsigned char> packet) {
629 std::vector<unsigned char> data;
631 bool bGotESC =
false;
632 bool bGotSOT =
false;
634 while (!m_circle->empty()) {
635 uint8_t next_byte = m_circle->get();
639 if ( next_byte == ESCAPE ) {
640 data.push_back(next_byte);
642 }
else if ( next_byte == ENDOFTEXT ) {
645 unsigned int msg_length = (uint32_t)data[1] + ((uint32_t)data[2]<<8);
648 if (msg_length == data.size()-1) {
649 uint8_t destination = data[3];
650 uint8_t source = data[4];
652 uint8_t dprp = data[7];
653 uint8_t priority = (dprp >> 2) & 7;
654 uint8_t rAndDP = dprp & 3;
657 uint8_t pduFormat = data[6];
658 uint32_t pgn = (rAndDP << 16) + (pduFormat << 8);
664 std::vector<uint8_t> o_payload;
665 o_payload.push_back(0x93);
666 o_payload.push_back(0x13);
667 o_payload.push_back(priority);
668 o_payload.push_back(pgn & 0xFF);
669 o_payload.push_back((pgn >> 8) & 0xFF);
670 o_payload.push_back((pgn >> 16) & 0xFF);
671 o_payload.push_back(destination);
672 o_payload.push_back(source);
673 o_payload.push_back(0xFF);
674 o_payload.push_back(0xFF);
675 o_payload.push_back(0xFF);
676 o_payload.push_back(0xFF);
677 o_payload.push_back(data.size());
680 for (
size_t n = 13; n < data.size() - 1; n++)
681 o_payload.push_back(data[n]);
683 o_payload.push_back(0x55);
687 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
688 Nevent.SetPayload(n2k_payload);
689 AddPendingEvent(Nevent);
696 }
else if (next_byte == STARTOFTEXT) {
705 bGotESC = (next_byte == ESCAPE);
708 data.push_back(next_byte);
714 if (STARTOFTEXT == next_byte) {
720 bGotESC = (next_byte == ESCAPE);
725 data.push_back(next_byte);
734 bool CommDriverN2KNet::ProcessActisense_RAW(std::vector<unsigned char> packet) {
739 std::vector<unsigned char> data;
741 bool bGotESC =
false;
742 bool bGotSOT =
false;
744 while (!m_circle->empty()) {
745 uint8_t next_byte = m_circle->get();
749 if ( next_byte == ESCAPE ) {
750 data.push_back(next_byte);
752 }
else if ( next_byte == ENDOFTEXT ) {
757 if (data.size() >= 8) {
758 size_t dLen = data[1];
760 if (dLen+3 == data.size()) {
763 memcpy(&frame.can_id, &data.data()[4], 4);
766 memcpy(&frame.data, &data.data()[8], 8);
768 HandleCanFrameInput(frame);
776 }
else if (next_byte == STARTOFTEXT) {
785 bGotESC = (next_byte == ESCAPE);
788 data.push_back(next_byte);
794 if (STARTOFTEXT == next_byte) {
800 bGotESC = (next_byte == ESCAPE);
805 data.push_back(next_byte);
814 bool CommDriverN2KNet::ProcessActisense_NGT(std::vector<unsigned char> packet) {
815 std::vector<unsigned char> data;
817 bool bGotESC =
false;
818 bool bGotSOT =
false;
820 while (!m_circle->empty()) {
821 uint8_t next_byte = m_circle->get();
825 if ( next_byte == ESCAPE ) {
826 data.push_back(next_byte);
828 }
else if ( next_byte == ENDOFTEXT ) {
831 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(data);
832 Nevent.SetPayload(n2k_payload);
833 AddPendingEvent(Nevent);
839 }
else if (next_byte == STARTOFTEXT) {
848 bGotESC = (next_byte == ESCAPE);
851 data.push_back(next_byte);
857 if (STARTOFTEXT == next_byte) {
863 bGotESC = (next_byte == ESCAPE);
868 data.push_back(next_byte);
877 bool CommDriverN2KNet::ProcessActisense_ASCII_RAW(std::vector<unsigned char> packet) {
880 while (!m_circle->empty()) {
881 char b = m_circle->get();
882 if ((b != 0x0a) && (b != 0x0d)) {
890 wxString ss(m_sentence.c_str());
892 wxStringTokenizer tkz(ss,
" ");
895 wxString token = tkz.GetNextToken();
897 token = tkz.GetNextToken();
899 m_TX_flag = token[0];
902 token = tkz.GetNextToken();
904 token.ToLong(&canID, 16);
905 frame.can_id = canID;
908 unsigned char bytes[8];
910 for (
unsigned int i = 0; i < 8; i++) {
911 if (tkz.HasMoreTokens()) {
912 token = tkz.GetNextToken();
914 token.ToLong(&tui, 16);
915 bytes[i] = (uint8_t)tui;
918 memcpy(&frame.data, bytes, 8);
919 HandleCanFrameInput(frame);
925 bool CommDriverN2KNet::ProcessActisense_ASCII_N2K(std::vector<unsigned char> packet) {
927 std::string sentence;
929 while (!m_circle->empty()) {
930 char b = m_circle->get();
931 if ((b != 0x0a) && (b != 0x0d)) {
939 wxString ss(sentence.c_str());
940 wxStringTokenizer tkz(ss,
" ");
944 wxString time_header = tkz.GetNextToken();
946 wxString sprio_addr = tkz.GetNextToken();
948 sprio_addr.ToLong(&prio_addr, 16);
949 uint8_t priority = (uint8_t)prio_addr & 0X0F;
950 uint8_t destination = (uint8_t)(prio_addr >> 4) & 0X0FF;
951 uint8_t source = (uint8_t)(prio_addr >> 12) & 0X0FF;
955 wxString sPGN = tkz.GetNextToken();
957 sPGN.ToULong(&PGN, 16);
961 wxString sdata = tkz.GetNextToken();
962 std::vector<uint8_t> data;
963 for (
size_t i = 0; i < sdata.Length(); i += 2) {
965 wxString stui = sdata.Mid(i, 2);
966 stui.ToLong(&dv, 16);
967 data.push_back((uint8_t)dv);
971 std::vector<uint8_t> o_payload;
972 o_payload.push_back(0x93);
973 o_payload.push_back(0x13);
974 o_payload.push_back(priority);
975 o_payload.push_back(PGN & 0xFF);
976 o_payload.push_back((PGN >> 8) & 0xFF);
977 o_payload.push_back((PGN >> 16) & 0xFF);
978 o_payload.push_back(destination);
979 o_payload.push_back(source);
980 o_payload.push_back(0xFF);
981 o_payload.push_back(0xFF);
982 o_payload.push_back(0xFF);
983 o_payload.push_back(0xFF);
984 o_payload.push_back(data.size());
985 for (
size_t n = 0; n < data.size(); n++) o_payload.push_back(data[n]);
986 o_payload.push_back(0x55);
988 if (HandleMgntMsg(PGN, o_payload))
993 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
994 Nevent.SetPayload(n2k_payload);
995 AddPendingEvent(Nevent);
1001 bool CommDriverN2KNet::ProcessSeaSmart(std::vector<unsigned char> packet) {
1002 while (!m_circle->empty()) {
1003 char b = m_circle->get();
1004 if ((b != 0x0a) && (b != 0x0d)) {
1012 wxString ss(m_sentence.c_str());
1014 wxStringTokenizer tkz(ss,
",");
1017 wxString token = tkz.GetNextToken();
1020 token = tkz.GetNextToken();
1022 token.ToULong(&PGN, 16);
1024 token = tkz.GetNextToken();
1025 unsigned long timestamp;
1026 token.ToULong(×tamp, 16);
1028 token = tkz.GetNextToken();
1029 unsigned long source;
1030 token.ToULong(&source, 16);
1032 token = tkz.GetNextToken();
1034 wxStringTokenizer datatkz(token,
"*");
1035 wxString data = datatkz.GetNextToken();
1038 std::vector<uint8_t> o_payload;
1039 o_payload.push_back(0x93);
1040 o_payload.push_back(0x13);
1041 o_payload.push_back(3);
1042 o_payload.push_back(PGN & 0xFF);
1043 o_payload.push_back((PGN >> 8) & 0xFF);
1044 o_payload.push_back((PGN >> 16) & 0xFF);
1045 o_payload.push_back(0xFF);
1046 o_payload.push_back((uint8_t)source);
1047 o_payload.push_back(timestamp & 0xFF);
1048 o_payload.push_back((timestamp >> 8) & 0xFF);
1049 o_payload.push_back((timestamp >> 16) & 0xFF);
1050 o_payload.push_back((timestamp >> 24) & 0xFF);
1051 o_payload.push_back((uint8_t)data.Length()/2);
1052 for (
size_t i = 0; i < data.Length(); i += 2) {
1054 wxString sbyte = data.Mid(i, 2);
1055 sbyte.ToULong(&dv, 16);
1056 o_payload.push_back((uint8_t)dv);
1058 o_payload.push_back(0x55);
1060 if (HandleMgntMsg(PGN, o_payload))
1065 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
1066 Nevent.SetPayload(n2k_payload);
1067 AddPendingEvent(Nevent);
1073 bool CommDriverN2KNet::ProcessMiniPlex(std::vector<unsigned char> packet) {
1165 while (!m_circle->empty()) {
1166 char b = m_circle->get();
1167 if ((b != 0x0a) && (b != 0x0d)) {
1175 wxString ss(m_sentence.c_str());
1177 wxStringTokenizer tkz(ss,
",");
1180 wxString token = tkz.GetNextToken();
1183 token = tkz.GetNextToken();
1185 token.ToULong(&PGN, 16);
1187 token = tkz.GetNextToken();
1189 token.ToULong(&attr, 16);
1191 bool send_bit = (attr >> 15) != 0;
1193 uint8_t priority = (attr >> 12) & 0x07;
1196 uint8_t dlc = (attr >> 8) & 0x0F;
1199 uint8_t address = attr & 0xFF;
1201 token = tkz.GetNextToken();
1203 wxStringTokenizer datatkz(token,
"*");
1204 wxString data = datatkz.GetNextToken();
1206 if (data.Length() > 16) {
1211 memset(&frame.data, 0, 8);
1212 for (
size_t i = 0; i < data.Length(); i += 2) {
1214 wxString sbyte = data.Mid(data.Length() - i - 2, 2);
1215 sbyte.ToULong(&dv, 16);
1216 frame.data[i/2] = ((uint8_t)dv);
1218 frame.can_id = (uint32_t)BuildCanID(priority, address, 0xFF, PGN);
1219 HandleCanFrameInput(frame);
1226 #define RD_BUF_SIZE \
1230 switch (event.GetSocketEvent()) {
1231 case wxSOCKET_INPUT: {
1245 std::vector<unsigned char> data(RD_BUF_SIZE + 1);
1247 uint8_t next_byte = 0;
1249 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
1250 if (!event.GetSocket()->Error()) {
1251 size_t count =
event.GetSocket()->LastCount();
1264 for (
int i = 0; i < newdata; i++) {
1265 m_circle->put(data[i]);
1270 m_n2k_format = DetectFormat(data);
1272 switch (m_n2k_format) {
1273 case N2KFormat_Actisense_RAW_ASCII:
1274 ProcessActisense_ASCII_RAW(data);
1276 case N2KFormat_YD_RAW:
1277 ProcessActisense_ASCII_RAW(data);
1279 case N2KFormat_Actisense_N2K_ASCII:
1280 ProcessActisense_ASCII_N2K(data);
1282 case N2KFormat_Actisense_N2K:
1283 ProcessActisense_N2K(data);
1285 case N2KFormat_Actisense_RAW:
1286 ProcessActisense_RAW(data);
1288 case N2KFormat_Actisense_NGT:
1289 ProcessActisense_NGT(data);
1291 case N2KFormat_SeaSmart:
1292 ProcessSeaSmart(data);
1294 case N2KFormat_MiniPlex:
1295 ProcessMiniPlex(data);
1297 case N2KFormat_Undefined:
1304 m_dog_value = N_DOG_TIMEOUT;
1308 case wxSOCKET_LOST: {
1309 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
1310 if (GetBrxConnectEvent())
1311 wxLogMessage(wxString::Format(
1312 _T(
"NetworkDataStream connection lost: %s"), GetPort().c_str()));
1313 if (GetSockServer()) {
1314 GetSock()->Destroy();
1318 wxDateTime now = wxDateTime::Now();
1319 wxTimeSpan since_connect(
1321 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
1323 int retry_time = 5000;
1329 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
1332 GetSocketThreadWatchdogTimer()->Stop();
1333 GetSocketTimer()->Start(
1334 retry_time, wxTIMER_ONE_SHOT);
1339 case wxSOCKET_CONNECTION: {
1340 if (GetProtocol() == GPSD) {
1344 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
1345 GetSock()->Write(cmd, strlen(cmd));
1346 }
else if (GetProtocol() == TCP) {
1347 wxLogMessage(wxString::Format(
1348 _T(
"TCP NetworkDataStream connection established: %s"),
1349 GetPort().c_str()));
1350 m_dog_value = N_DOG_TIMEOUT;
1351 if (GetPortType() != DS_TYPE_OUTPUT) {
1353 if (GetParams().NoDataReconnect)
1354 GetSocketThreadWatchdogTimer()->Start(1000);
1356 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
1357 (void)SetOutputSocketOptions(GetSock());
1358 GetSocketTimer()->Stop();
1359 SetBrxConnectEvent(
true);
1362 SetConnectTime(wxDateTime::Now());
1371 void CommDriverN2KNet::OnServerSocketEvent(wxSocketEvent& event) {
1372 switch (event.GetSocketEvent()) {
1373 case wxSOCKET_CONNECTION: {
1374 SetSock(GetSockServer()->Accept(
false));
1377 GetSock()->SetTimeout(2);
1379 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
1380 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
1381 if (GetPortType() != DS_TYPE_INPUT) {
1382 notify_flags |= wxSOCKET_OUTPUT_FLAG;
1383 (void)SetOutputSocketOptions(GetSock());
1385 if (GetPortType() != DS_TYPE_OUTPUT)
1386 notify_flags |= wxSOCKET_INPUT_FLAG;
1387 GetSock()->SetNotify(notify_flags);
1388 GetSock()->Notify(
true);
1399 std::vector<unsigned char> MakeSimpleOutMsg(
1400 int data_format,
int pgn, std::vector<unsigned char>& payload) {
1401 std::vector<unsigned char> out_vec;
1403 switch (data_format) {
1404 case N2KFormat_YD_RAW:
1405 case N2KFormat_Actisense_RAW_ASCII: {
1407 unsigned can_id = BuildCanID(6, 0xff, 0xff, pgn);
1409 scan_id.Printf(
"%08X", can_id);
1410 std::string sscan_id = scan_id.ToStdString();
1411 for (
unsigned char s : sscan_id) 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);
1424 out_vec.push_back(0x0d);
1425 out_vec.push_back(0x0a);
1428 case N2KFormat_Actisense_N2K_ASCII: {
1430 wxDateTime now = wxDateTime::Now();
1431 wxString stime = now.Format(
"%H%M%S");
1433 std::string sstime = stime.ToStdString();
1434 out_vec.push_back(
'A');
1435 for (
unsigned char s : sstime) out_vec.push_back(s);
1439 sdp.Printf(
"%02X%02X%1X ",
1441 (
unsigned char)0xFF, 0x6);
1442 std::string ssdp = sdp.ToStdString();
1443 for (
unsigned char s : ssdp) out_vec.push_back(s);
1447 spgn.Printf(
"%05X ", pgn);
1448 std::string sspgn = spgn.ToStdString();
1449 for (
unsigned char s : sspgn) out_vec.push_back(s);
1454 for (
unsigned char d : payload) {
1455 snprintf(tv, 3,
"%02X", d);
1458 for (
unsigned char s : sspl) out_vec.push_back(s);
1461 out_vec.push_back(0x0d);
1462 out_vec.push_back(0x0a);
1465 case N2KFormat_MiniPlex: {
1466 out_vec.push_back(
'$');
1467 out_vec.push_back(
'M');
1468 out_vec.push_back(
'X');
1469 out_vec.push_back(
'P');
1470 out_vec.push_back(
'G');
1471 out_vec.push_back(
'N');
1472 out_vec.push_back(
',');
1475 spgn.Printf(
"%06X,", pgn);
1476 std::string sspgn = spgn.ToStdString();
1477 for (
unsigned char c : sspgn) {
1478 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);
1524 std::vector<std::vector<unsigned char>> CommDriverN2KNet::GetTxVector(
const std::shared_ptr<const Nmea2000Msg> &msg,
1525 std::shared_ptr<const NavAddr2000> dest_addr) {
1526 std::vector<std::vector<unsigned char>> tx_vector;
1529 switch(m_n2k_format) {
1530 case N2KFormat_YD_RAW:
1532 case N2KFormat_Actisense_RAW_ASCII: {
1534 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1537 std::vector<unsigned char> header_vec;
1538 std::vector<unsigned char> out_vec;
1543 wxDateTime now = wxDateTime::Now();
1544 wxString stime = now.Format(
"%H:%M:%S");
1546 std::string sstime = stime.ToStdString();
1547 for (
unsigned char s : sstime) header_vec.push_back(s);
1550 header_vec.push_back(
'T');
1551 header_vec.push_back(
' ');
1557 unsigned long can_id =
1558 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1560 scan_id.Printf(
"%08X", can_id);
1561 std::string sscan_id = scan_id.ToStdString();
1562 for (
unsigned char s : sscan_id) header_vec.push_back(s);
1563 header_vec.push_back(
' ');
1566 int payload_size = msg->payload.size();
1567 unsigned char temp[8];
1570 (payload_size > 6 ? (payload_size - 6 - 1) / 7 + 1 + 1 : 1);
1572 for (
int i = 0; i < nframes && result; i++) {
1573 temp[0] = i | m_order;
1575 temp[1] = msg->payload.size();
1577 for (
int j = 2; j < 8; j++) {
1578 temp[j] = msg->payload.data()[cur];
1584 for (; j < 8 && cur < payload_size; j++) {
1585 temp[j] = msg->payload.data()[cur];
1588 for (; j < 8; j++) {
1596 for (
unsigned char s : header_vec) out_vec.push_back(s);
1600 for (
unsigned int k = 0; k < 8; k++) {
1602 snprintf(tb, 4,
"%02X ", temp[k]);
1605 for (
unsigned char s : ssdata) out_vec.push_back(s);
1608 out_vec.push_back(0x0d);
1609 out_vec.push_back(0x0a);
1614 tx_vector.push_back(out_vec);
1619 case N2KFormat_Actisense_N2K_ASCII: {
1634 std::vector<unsigned char> ovec;
1637 wxDateTime now = wxDateTime::Now();
1638 wxString stime = now.Format(
"%H%M%S");
1640 std::string sstime = stime.ToStdString();
1641 ovec.push_back(
'A');
1642 for (
unsigned char s : sstime) ovec.push_back(s);
1646 sdp.Printf(
"%02X%02X%1X ",
1648 (
unsigned char)dest_addr->address,
1649 (
unsigned char)msg->priority);
1650 std::string ssdp = sdp.ToStdString();
1651 for (
unsigned char s : ssdp) ovec.push_back(s);
1655 spgn.Printf(
"%05X ", (
int)msg->PGN.pgn);
1656 std::string sspgn = spgn.ToStdString();
1657 for (
unsigned char s : sspgn) ovec.push_back(s);
1662 for (
unsigned char d : msg->payload){
1663 snprintf(tv, 3,
"%02X", d);
1666 for (
unsigned char s : sspl) ovec.push_back(s);
1669 ovec.push_back(0x0d);
1670 ovec.push_back(0x0a);
1673 tx_vector.push_back(ovec);
1677 case N2KFormat_MiniPlex: {
1678 std::vector<unsigned char> ovec;
1679 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1683 size_t nframes = (msg->payload.size() > 6 ? (msg->payload.size() - 6 - 1) / 7 + 1 + 1 : 1);
1684 for (
size_t i = 0; i < nframes; i++) {
1685 ovec.push_back(
'$');
1686 ovec.push_back(
'M');
1687 ovec.push_back(
'X');
1688 ovec.push_back(
'P');
1689 ovec.push_back(
'G');
1690 ovec.push_back(
'N');
1691 ovec.push_back(
',');
1694 spgn.Printf(
"%06X,", (
int)msg->PGN.pgn);
1695 std::string sspgn = spgn.ToStdString();
1696 for (
unsigned char c : sspgn) {
1702 if (i == nframes - 1) {
1703 len = msg->payload.size() + 1 - 6 - (nframes - 2) * 7;
1705 attr |= ((uint16_t)((uint8_t)msg->priority & 0x07)) << 12;
1706 attr |= ((uint16_t)len) << 8;
1707 attr |= (uint16_t)dest_addr->address;
1711 sattr.Printf(
"%04X,", attr);
1712 std::string ssattr = sattr.ToStdString();
1713 for (
unsigned char c : ssattr) {
1718 uint8_t databytes = i == 0 ? len - 2 : len - 1;
1719 std::vector<unsigned char> payload;
1720 for (uint8_t j = 0; j < databytes; j++) {
1721 payload.push_back(msg->payload[cur]);
1724 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1725 snprintf(tv, 3,
"%02X", *rit);
1726 ovec.push_back(tv[0]);
1727 ovec.push_back(tv[1]);
1730 snprintf(tv, 3,
"%02X", (uint8_t)msg->payload.size());
1731 ovec.push_back(tv[0]);
1732 ovec.push_back(tv[1]);
1735 snprintf(tv, 3,
"%02X", (uint8_t)i | m_order);
1736 ovec.push_back(tv[0]);
1737 ovec.push_back(tv[1]);
1741 for (
auto ci = ++ovec.begin(); ci != ovec.end(); ci++) {
1744 ovec.push_back(
'*');
1745 snprintf(tv, 3,
"%02X", crc);
1746 ovec.push_back(tv[0]);
1747 ovec.push_back(tv[1]);
1750 ovec.push_back(0x0d);
1751 ovec.push_back(0x0a);
1756 tx_vector.push_back(ovec);
1763 case N2KFormat_Actisense_N2K:
1765 case N2KFormat_Actisense_RAW:
1767 case N2KFormat_Actisense_NGT:
1769 case N2KFormat_SeaSmart:
1780 bool CommDriverN2KNet::PrepareForTX() {
1791 bool b_found =
false;
1798 if (m_n2k_format == N2KFormat_Actisense_N2K_ASCII)
1806 if (m_n2k_format == N2KFormat_MiniPlex)
1813 if (m_n2k_format == N2KFormat_SeaSmart)
1822 prod_info_map.clear();
1825 std::vector<unsigned char> payload;
1826 payload.push_back(0x14);
1827 payload.push_back(0xF0);
1828 payload.push_back(0x01);
1830 std::vector<std::vector<unsigned char>> out_data;
1831 std::vector<unsigned char> msg_vec = MakeSimpleOutMsg( N2KFormat_YD_RAW, 59904, payload);
1832 out_data.push_back(msg_vec);
1833 SendSentenceNetwork(out_data);
1840 for (
const auto& [key, value] : prod_info_map){
1841 auto prod_info = value;
1842 if (prod_info.Model_ID.find(
"YDEN") != std::string::npos) {
1847 if (prod_info.RT_flag ==
'T')
1863 bool CommDriverN2KNet::SendN2KNetwork(std::shared_ptr<const Nmea2000Msg> &msg,
1864 std::shared_ptr<const NavAddr2000> addr) {
1867 std::vector<std::vector<unsigned char>> out_data = GetTxVector(msg, addr);
1868 SendSentenceNetwork(out_data);
1873 bool CommDriverN2KNet::SendSentenceNetwork(std::vector<std::vector<unsigned char>> payload) {
1880 wxDatagramSocket* udp_socket;
1881 switch (GetProtocol()) {
1883 for (std::vector<unsigned char> &v : payload ) {
1884 if (GetSock() && GetSock()->IsOk()) {
1886 GetSock()->Write(v.data(), v.size());
1887 if (GetSock()->Error()) {
1888 if (GetSockServer()) {
1889 GetSock()->Destroy();
1892 wxSocketClient* tcp_socket =
1893 dynamic_cast<wxSocketClient*
>(GetSock());
1894 if (tcp_socket) tcp_socket->Close();
1895 if (!GetSocketTimer()->IsRunning())
1896 GetSocketTimer()->Start(
1897 5000, wxTIMER_ONE_SHOT);
1898 GetSocketThreadWatchdogTimer()->Stop();
1909 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
1910 if (udp_socket && udp_socket->IsOk()) {
1911 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
1912 if (udp_socket->Error()) ret =
false;
1927 void CommDriverN2KNet::Close() {
1928 wxLogMessage(wxString::Format(_T(
"Closing NMEA NetworkDataStream %s"),
1929 GetNetPort().c_str()));
1933 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
1934 sizeof(m_mrq_container->m_mrq));
1935 m_sock->Notify(FALSE);
1940 m_tsock->Notify(FALSE);
1944 if (m_socket_server) {
1945 m_socket_server->Notify(FALSE);
1946 m_socket_server->Destroy();
1949 m_socket_timer.Stop();
1950 m_socketread_watchdog_timer.Stop();
1953 bool CommDriverN2KNet::SetOutputSocketOptions(wxSocketBase* tsock) {
1962 int nagleDisable = 1;
1963 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
1964 sizeof(nagleDisable));
1970 unsigned long outbuf_size = 1024;
1971 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
1972 sizeof(outbuf_size)) &&
void OnSocketEvent(wxSocketEvent &event)
void Activate() override
Register driver and possibly do other post-ctor steps.
void Activate(DriverPtr driver)
Add driver to list of active drivers.
Interface implemented by transport layer and possible other parties like test code which should handl...
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.
Adds a std::shared<void> element to wxCommandEvent.
wxDEFINE_EVENT(REST_IO_EVT, ObservedEvt)
Event from IO thread to main.