34#include <wx/msw/winundef.h>
44#include <wx/tokenzr.h>
45#include <wx/datetime.h>
55#include <netinet/tcp.h>
62#include <wx/chartype.h>
64#include <wx/sckaddr.h>
66#include "model/comm_drv_n2k_net.h"
68#include "model/idents.h"
71#define N_DOG_TIMEOUT 8
73static const int kNotFound = -1;
78 void SetMrqAddr(
unsigned int addr) {
79 m_mrq.imr_multiaddr.s_addr = addr;
80 m_mrq.imr_interface.s_addr = INADDR_ANY;
86circular_buffer::circular_buffer(
size_t size)
87 : buf_(std::unique_ptr<unsigned char[]>(new unsigned char[size])),
99bool circular_buffer::empty()
const {
101 return (!full_ && (head_ == tail_));
104bool circular_buffer::full()
const {
109void 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_;
119unsigned 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) {};
144 : wxEvent(
id, commandType) {};
148 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
151 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
154 wxEvent* Clone()
const {
156 newevent->m_payload = this->m_payload;
161 std::shared_ptr<std::vector<unsigned char>> m_payload;
164static uint64_t PayloadToName(
const std::vector<unsigned char> payload) {
166 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
174#define TIMER_SOCKET_N2KNET 7339
177EVT_TIMER(TIMER_SOCKET_N2KNET, CommDriverN2KNet::OnTimerSocket)
179EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN2KNet::OnServerSocketEvent)
180EVT_TIMER(TIMER_SOCKET_N2KNET + 1, CommDriverN2KNet::OnSocketReadWatchdogTimer)
189 m_listener(listener),
190 m_net_port(wxString::Format("%i", params->NetworkPort)),
191 m_net_protocol(params->NetProtocol),
194 m_socket_server(NULL),
195 m_is_multicast(false),
197 m_portstring(params->GetDSPort()),
198 m_io_select(params->IOSelect),
199 m_connection_type(params->Type),
203 m_addr.Hostname(params->NetworkAddress);
204 m_addr.Service(params->NetworkPort);
206 m_socket_timer.SetOwner(
this, TIMER_SOCKET_N2KNET);
207 m_socketread_watchdog_timer.SetOwner(
this, TIMER_SOCKET_N2KNET + 1);
208 this->attributes[
"netAddress"] = params->NetworkAddress.ToStdString();
210 sprintf(port_char,
"%d", params->NetworkPort);
211 this->attributes[
"netPort"] = std::string(port_char);
212 this->attributes[
"userComment"] = params->UserComment.ToStdString();
213 this->attributes[
"ioDirection"] = std::string(
"IN/OUT");
216 Bind(wxEVT_COMMDRIVER_N2K_NET, &CommDriverN2KNet::handle_N2K_MSG,
this);
223 rx_buffer =
new unsigned char[RX_BUFFER_SIZE_NET + 1];
228 m_n2k_format = N2KFormat_YD_RAW;
231 resume_listener.Init(SystemEvents::GetInstance().evt_resume,
237CommDriverN2KNet::~CommDriverN2KNet() {
238 delete m_mrq_container;
246 std::string Model_ID;
250std::unordered_map<uint8_t, product_info> prod_info_map;
252bool CommDriverN2KNet::HandleMgntMsg(uint64_t pgn,
253 std::vector<unsigned char>& payload) {
255 auto name = PayloadToName(payload);
257 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);
299 std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
301 std::make_shared<const Nmea2000Msg>(1, *payload, GetAddress(name));
303 m_listener.
Notify(std::move(msg));
304 m_listener.
Notify(std::move(msg_all));
307void CommDriverN2KNet::Open(
void) {
309#if wxCHECK_VERSION(3, 0, 0)
311 ((
struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
314 ((
struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
317 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
320 switch (m_net_protocol) {
322 OpenNetworkTCP(addr);
326 OpenNetworkUDP(addr);
335void CommDriverN2KNet::OpenNetworkUDP(
unsigned int addr) {
336 if (GetPortType() != DS_TYPE_OUTPUT) {
339 wxIPV4address conn_addr;
340 conn_addr.Service(GetNetPort());
341 conn_addr.AnyAddress();
343 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
346 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
348 m_mrq_container->SetMrqAddr(addr);
349 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP,
350 &m_mrq_container->m_mrq,
351 sizeof(m_mrq_container->m_mrq));
354 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
356 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
358 GetSock()->Notify(TRUE);
359 GetSock()->SetTimeout(1);
363 if (GetPortType() != DS_TYPE_INPUT) {
364 wxIPV4address tconn_addr;
365 tconn_addr.Service(0);
366 tconn_addr.AnyAddress();
368 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
373 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(_T(
"255")))) {
374 int broadcastEnable = 1;
375 bool bam = GetTSock()->SetOption(
376 SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
sizeof(broadcastEnable));
381 SetConnectTime(wxDateTime::Now());
384void CommDriverN2KNet::OpenNetworkTCP(
unsigned int addr) {
385 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
386 wxLogMessage(wxString::Format(_T(
"Opening TCP Server %d"), isServer));
389 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
391 SetSock(
new wxSocketClient());
395 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
396 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
397 GetSockServer()->Notify(TRUE);
398 GetSockServer()->SetTimeout(1);
400 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
401 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
402 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
403 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
404 GetSock()->SetNotify(notify_flags);
405 GetSock()->Notify(TRUE);
406 GetSock()->SetTimeout(1);
408 SetBrxConnectEvent(
false);
409 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
413 SetConnectTime(wxDateTime::Now());
416void CommDriverN2KNet::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
419 if (m_dog_value <= 0) {
420 if (GetParams().NoDataReconnect) {
422 if (GetProtocol() == TCP) {
423 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
424 if (tcp_socket) tcp_socket->Close();
426 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
427 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
429 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
432 GetSocketThreadWatchdogTimer()->Stop();
438void CommDriverN2KNet::OnTimerSocket() {
440 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
442 if (tcp_socket->IsDisconnected()) {
443 wxLogDebug(
" Attempting reconnection...");
444 SetBrxConnectEvent(
false);
446 GetSocketThreadWatchdogTimer()->Stop();
447 tcp_socket->Connect(GetAddr(), FALSE);
450 int n_reconnect_delay = N_DOG_TIMEOUT;
451 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
456void CommDriverN2KNet::HandleResume() {
458 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
460 GetSocketThreadWatchdogTimer()->Stop();
465 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
466 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
469 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
473bool CommDriverN2KNet::SendMessage(std::shared_ptr<const NavMsg> msg,
474 std::shared_ptr<const NavAddr> addr) {
475 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
476 auto dest_addr_n2k = std::static_pointer_cast<const NavAddr2000>(addr);
477 return SendN2KNetwork(msg_n2k, dest_addr_n2k);
480std::vector<unsigned char> CommDriverN2KNet::PushCompleteMsg(
481 const CanHeader header,
int position,
const can_frame frame) {
482 std::vector<unsigned char> data;
483 data.push_back(0x93);
484 data.push_back(0x13);
485 data.push_back(header.priority);
486 data.push_back(header.pgn & 0xFF);
487 data.push_back((header.pgn >> 8) & 0xFF);
488 data.push_back((header.pgn >> 16) & 0xFF);
489 data.push_back(header.destination);
490 data.push_back(header.source);
491 data.push_back(0xFF);
492 data.push_back(0xFF);
493 data.push_back(0xFF);
494 data.push_back(0xFF);
495 data.push_back(CAN_MAX_DLEN);
496 for (
size_t n = 0; n < CAN_MAX_DLEN; n++) data.push_back(frame.data[n]);
497 data.push_back(0x55);
501std::vector<unsigned char> CommDriverN2KNet::PushFastMsgFragment(
503 std::vector<unsigned char> data;
504 data.push_back(0x93);
505 data.push_back(fast_messages->entries[position].expected_length + 11);
506 data.push_back(header.priority);
507 data.push_back(header.pgn & 0xFF);
508 data.push_back((header.pgn >> 8) & 0xFF);
509 data.push_back((header.pgn >> 16) & 0xFF);
510 data.push_back(header.destination);
511 data.push_back(header.source);
512 data.push_back(0xFF);
513 data.push_back(0xFF);
514 data.push_back(0xFF);
515 data.push_back(0xFF);
516 data.push_back(fast_messages->entries[position].expected_length);
517 for (
size_t n = 0; n < fast_messages->entries[position].expected_length; n++)
518 data.push_back(fast_messages->entries[position].data[n]);
519 data.push_back(0x55);
520 fast_messages->
Remove(position);
530void CommDriverN2KNet::HandleCanFrameInput(can_frame frame) {
537 if (position == kNotFound) {
544 if ((frame.data[0] & 0x1F) == 0) {
546 ready = fast_messages->
InsertEntry(header, frame.data, position);
551 ready = fast_messages->
AppendEntry(header, frame.data, position);
555 std::vector<unsigned char> vec;
558 vec = PushFastMsgFragment(header, position);
561 vec = PushCompleteMsg(header, position, frame);
565 if (HandleMgntMsg(header.pgn, vec))
return;
569 auto payload = std::make_shared<std::vector<uint8_t>>(vec);
570 Nevent.SetPayload(payload);
571 AddPendingEvent(Nevent);
575bool isASCII(std::vector<unsigned char> packet) {
576 for (
unsigned char c : packet) {
577 if (!isascii(c))
return false;
582N2K_Format CommDriverN2KNet::DetectFormat(std::vector<unsigned char> packet) {
587 if (isASCII(packet)) {
588 std::string payload = std::string(packet.begin(), packet.end());
589 if (payload.find(
"$PCDIN") != std::string::npos) {
590 return N2KFormat_SeaSmart;
591 }
else if (payload.find(
"$MXPGN") != std::string::npos) {
595 return N2KFormat_MiniPlex;
596 }
else if (std::find(packet.begin(), packet.end(),
':') != packet.end()) {
597 return N2KFormat_Actisense_RAW_ASCII;
599 return N2KFormat_Actisense_N2K_ASCII;
602 if (packet[2] == 0x95)
603 return N2KFormat_Actisense_RAW;
604 else if (packet[2] == 0xd0)
605 return N2KFormat_Actisense_N2K;
606 else if (packet[2] == 0x93)
607 return N2KFormat_Actisense_NGT;
609 return N2KFormat_Undefined;
612bool CommDriverN2KNet::ProcessActisense_N2K(std::vector<unsigned char> packet) {
615 std::vector<unsigned char> data;
617 bool bGotESC =
false;
618 bool bGotSOT =
false;
620 while (!m_circle->empty()) {
621 uint8_t next_byte = m_circle->get();
625 if (next_byte == ESCAPE) {
626 data.push_back(next_byte);
628 }
else if (next_byte == ENDOFTEXT) {
632 unsigned int msg_length =
633 (uint32_t)data[1] + ((uint32_t)data[2] << 8);
636 if (msg_length == data.size() - 1) {
637 uint8_t destination = data[3];
638 uint8_t source = data[4];
640 uint8_t dprp = data[7];
643 uint8_t rAndDP = dprp & 3;
646 uint8_t pduFormat = data[6];
647 uint32_t pgn = (rAndDP << 16) + (pduFormat << 8);
653 std::vector<uint8_t> o_payload;
654 o_payload.push_back(0x93);
655 o_payload.push_back(0x13);
656 o_payload.push_back(priority);
657 o_payload.push_back(pgn & 0xFF);
658 o_payload.push_back((pgn >> 8) & 0xFF);
659 o_payload.push_back((pgn >> 16) & 0xFF);
660 o_payload.push_back(destination);
661 o_payload.push_back(source);
662 o_payload.push_back(0xFF);
663 o_payload.push_back(0xFF);
664 o_payload.push_back(0xFF);
665 o_payload.push_back(0xFF);
666 o_payload.push_back(data.size());
669 for (
size_t n = 13; n < data.size() - 1; n++)
670 o_payload.push_back(data[n]);
672 o_payload.push_back(0x55);
677 std::make_shared<std::vector<uint8_t>>(o_payload);
678 Nevent.SetPayload(n2k_payload);
679 AddPendingEvent(Nevent);
686 }
else if (next_byte == STARTOFTEXT) {
695 bGotESC = (next_byte == ESCAPE);
698 data.push_back(next_byte);
704 if (STARTOFTEXT == next_byte) {
710 bGotESC = (next_byte == ESCAPE);
715 data.push_back(next_byte);
724bool CommDriverN2KNet::ProcessActisense_RAW(std::vector<unsigned char> packet) {
729 std::vector<unsigned char> data;
731 bool bGotESC =
false;
732 bool bGotSOT =
false;
734 while (!m_circle->empty()) {
735 uint8_t next_byte = m_circle->get();
739 if (next_byte == ESCAPE) {
740 data.push_back(next_byte);
742 }
else if (next_byte == ENDOFTEXT) {
747 if (data.size() >= 8) {
748 size_t dLen = data[1];
750 if (dLen + 3 == data.size()) {
752 memcpy(&frame.can_id, &data.data()[4], 4);
755 memcpy(&frame.data, &data.data()[8], 8);
757 HandleCanFrameInput(frame);
765 }
else if (next_byte == STARTOFTEXT) {
774 bGotESC = (next_byte == ESCAPE);
777 data.push_back(next_byte);
783 if (STARTOFTEXT == next_byte) {
789 bGotESC = (next_byte == ESCAPE);
794 data.push_back(next_byte);
803bool CommDriverN2KNet::ProcessActisense_NGT(std::vector<unsigned char> packet) {
804 std::vector<unsigned char> data;
806 bool bGotESC =
false;
807 bool bGotSOT =
false;
809 while (!m_circle->empty()) {
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 std::vector<unsigned char> packet) {
870 while (!m_circle->empty()) {
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 std::vector<unsigned char> packet) {
918 std::string sentence;
920 while (!m_circle->empty()) {
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(std::vector<unsigned char> packet) {
991 while (!m_circle->empty()) {
992 char b = m_circle->get();
993 if ((b != 0x0a) && (b != 0x0d)) {
1001 wxString ss(m_sentence.c_str());
1003 wxStringTokenizer tkz(ss,
",");
1006 wxString token = tkz.GetNextToken();
1009 token = tkz.GetNextToken();
1011 token.ToULong(&PGN, 16);
1013 token = tkz.GetNextToken();
1014 unsigned long timestamp;
1015 token.ToULong(×tamp, 16);
1017 token = tkz.GetNextToken();
1018 unsigned long source;
1019 token.ToULong(&source, 16);
1021 token = tkz.GetNextToken();
1023 wxStringTokenizer datatkz(token,
"*");
1024 wxString data = datatkz.GetNextToken();
1027 std::vector<uint8_t> o_payload;
1028 o_payload.push_back(0x93);
1029 o_payload.push_back(0x13);
1030 o_payload.push_back(3);
1031 o_payload.push_back(PGN & 0xFF);
1032 o_payload.push_back((PGN >> 8) & 0xFF);
1033 o_payload.push_back((PGN >> 16) & 0xFF);
1034 o_payload.push_back(0xFF);
1035 o_payload.push_back((uint8_t)source);
1036 o_payload.push_back(timestamp & 0xFF);
1037 o_payload.push_back((timestamp >> 8) & 0xFF);
1038 o_payload.push_back((timestamp >> 16) & 0xFF);
1039 o_payload.push_back((timestamp >> 24) & 0xFF);
1040 o_payload.push_back((uint8_t)data.Length() / 2);
1041 for (
size_t i = 0; i < data.Length(); i += 2) {
1043 wxString sbyte = data.Mid(i, 2);
1044 sbyte.ToULong(&dv, 16);
1045 o_payload.push_back((uint8_t)dv);
1047 o_payload.push_back(0x55);
1049 if (HandleMgntMsg(PGN, o_payload))
return false;
1053 auto n2k_payload = std::make_shared<std::vector<uint8_t>>(o_payload);
1054 Nevent.SetPayload(n2k_payload);
1055 AddPendingEvent(Nevent);
1061bool CommDriverN2KNet::ProcessMiniPlex(std::vector<unsigned char> packet) {
1156 while (!m_circle->empty()) {
1157 char b = m_circle->get();
1158 if ((b != 0x0a) && (b != 0x0d)) {
1166 wxString ss(m_sentence.c_str());
1168 wxStringTokenizer tkz(ss,
",");
1171 wxString token = tkz.GetNextToken();
1174 token = tkz.GetNextToken();
1176 token.ToULong(&PGN, 16);
1178 token = tkz.GetNextToken();
1180 token.ToULong(&attr, 16);
1182 bool send_bit = (attr >> 15) != 0;
1184 uint8_t priority = (attr >> 12) & 0x07;
1187 uint8_t dlc = (attr >> 8) & 0x0F;
1190 uint8_t address = attr & 0xFF;
1192 token = tkz.GetNextToken();
1194 wxStringTokenizer datatkz(token,
"*");
1195 wxString data = datatkz.GetNextToken();
1203 memset(&frame.data, 0, 8);
1204 for (
size_t i = 0; i < data.Length(); i += 2) {
1206 wxString sbyte = data.Mid(data.Length() - i - 2, 2);
1207 sbyte.ToULong(&dv, 16);
1208 frame.data[i / 2] = ((uint8_t)dv);
1210 frame.can_id = (uint32_t)BuildCanID(priority, address, 0xFF, PGN);
1211 HandleCanFrameInput(frame);
1218#define RD_BUF_SIZE 4096
1221 switch (event.GetSocketEvent()) {
1222 case wxSOCKET_INPUT: {
1236 std::vector<unsigned char> data(RD_BUF_SIZE + 1);
1238 uint8_t next_byte = 0;
1240 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
1241 if (!event.GetSocket()->Error()) {
1242 size_t count =
event.GetSocket()->LastCount();
1255 for (
int i = 0; i < newdata; i++) {
1256 m_circle->put(data[i]);
1261 m_n2k_format = DetectFormat(data);
1263 switch (m_n2k_format) {
1264 case N2KFormat_Actisense_RAW_ASCII:
1265 ProcessActisense_ASCII_RAW(data);
1267 case N2KFormat_YD_RAW:
1268 ProcessActisense_ASCII_RAW(data);
1270 case N2KFormat_Actisense_N2K_ASCII:
1271 ProcessActisense_ASCII_N2K(data);
1273 case N2KFormat_Actisense_N2K:
1274 ProcessActisense_N2K(data);
1276 case N2KFormat_Actisense_RAW:
1277 ProcessActisense_RAW(data);
1279 case N2KFormat_Actisense_NGT:
1280 ProcessActisense_NGT(data);
1282 case N2KFormat_SeaSmart:
1283 ProcessSeaSmart(data);
1285 case N2KFormat_MiniPlex:
1286 ProcessMiniPlex(data);
1288 case N2KFormat_Undefined:
1295 m_dog_value = N_DOG_TIMEOUT;
1299 case wxSOCKET_LOST: {
1300 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
1301 if (GetBrxConnectEvent())
1302 wxLogMessage(wxString::Format(
1303 _T(
"NetworkDataStream connection lost: %s"), GetPort().c_str()));
1304 if (GetSockServer()) {
1305 GetSock()->Destroy();
1309 wxDateTime now = wxDateTime::Now();
1310 wxTimeSpan since_connect(
1312 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
1314 int retry_time = 5000;
1320 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
1323 GetSocketThreadWatchdogTimer()->Stop();
1324 GetSocketTimer()->Start(
1325 retry_time, wxTIMER_ONE_SHOT);
1330 case wxSOCKET_CONNECTION: {
1331 if (GetProtocol() == GPSD) {
1335 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
1336 GetSock()->Write(cmd, strlen(cmd));
1337 }
else if (GetProtocol() == TCP) {
1338 wxLogMessage(wxString::Format(
1339 _T(
"TCP NetworkDataStream connection established: %s"),
1340 GetPort().c_str()));
1341 m_dog_value = N_DOG_TIMEOUT;
1342 if (GetPortType() != DS_TYPE_OUTPUT) {
1344 if (GetParams().NoDataReconnect)
1345 GetSocketThreadWatchdogTimer()->Start(1000);
1347 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
1348 (void)SetOutputSocketOptions(GetSock());
1349 GetSocketTimer()->Stop();
1350 SetBrxConnectEvent(
true);
1353 SetConnectTime(wxDateTime::Now());
1362void CommDriverN2KNet::OnServerSocketEvent(wxSocketEvent& event) {
1363 switch (event.GetSocketEvent()) {
1364 case wxSOCKET_CONNECTION: {
1365 SetSock(GetSockServer()->Accept(
false));
1368 GetSock()->SetTimeout(2);
1370 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
1371 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
1372 if (GetPortType() != DS_TYPE_INPUT) {
1373 notify_flags |= wxSOCKET_OUTPUT_FLAG;
1374 (void)SetOutputSocketOptions(GetSock());
1376 if (GetPortType() != DS_TYPE_OUTPUT)
1377 notify_flags |= wxSOCKET_INPUT_FLAG;
1378 GetSock()->SetNotify(notify_flags);
1379 GetSock()->Notify(
true);
1390std::vector<unsigned char> MakeSimpleOutMsg(
1391 int data_format,
int pgn, std::vector<unsigned char>& payload) {
1392 std::vector<unsigned char> out_vec;
1394 switch (data_format) {
1395 case N2KFormat_YD_RAW:
1396 case N2KFormat_Actisense_RAW_ASCII: {
1398 unsigned can_id = BuildCanID(6, 0xff, 0xff, pgn);
1400 scan_id.Printf(
"%08X", can_id);
1401 std::string sscan_id = scan_id.ToStdString();
1402 for (
unsigned char s : sscan_id) out_vec.push_back(s);
1403 out_vec.push_back(
' ');
1408 for (
unsigned char d : payload) {
1409 snprintf(tv, 4,
"%02X ", d);
1412 for (
unsigned char s : sspl) out_vec.push_back(s);
1415 out_vec.push_back(0x0d);
1416 out_vec.push_back(0x0a);
1419 case N2KFormat_Actisense_N2K_ASCII: {
1421 wxDateTime now = wxDateTime::Now();
1422 wxString stime = now.Format(
"%H%M%S");
1424 std::string sstime = stime.ToStdString();
1425 out_vec.push_back(
'A');
1426 for (
unsigned char s : sstime) out_vec.push_back(s);
1430 sdp.Printf(
"%02X%02X%1X ",
1432 (
unsigned char)0xFF, 0x6);
1433 std::string ssdp = sdp.ToStdString();
1434 for (
unsigned char s : ssdp) out_vec.push_back(s);
1438 spgn.Printf(
"%05X ", pgn);
1439 std::string sspgn = spgn.ToStdString();
1440 for (
unsigned char s : sspgn) out_vec.push_back(s);
1445 for (
unsigned char d : payload) {
1446 snprintf(tv, 3,
"%02X", d);
1449 for (
unsigned char s : sspl) out_vec.push_back(s);
1452 out_vec.push_back(0x0d);
1453 out_vec.push_back(0x0a);
1456 case N2KFormat_MiniPlex: {
1457 out_vec.push_back(
'$');
1458 out_vec.push_back(
'M');
1459 out_vec.push_back(
'X');
1460 out_vec.push_back(
'P');
1461 out_vec.push_back(
'G');
1462 out_vec.push_back(
'N');
1463 out_vec.push_back(
',');
1466 spgn.Printf(
"%06X,", pgn);
1467 std::string sspgn = spgn.ToStdString();
1468 for (
unsigned char c : sspgn) {
1469 out_vec.push_back(c);
1475 attr |= ((uint16_t)0x06) << 12;
1476 attr |= ((uint16_t)payload.size()) << 8;
1477 attr |= (uint16_t)0xFF;
1481 sattr.Printf(
"%04X,", attr);
1482 std::string ssattr = sattr.ToStdString();
1483 for (
unsigned char c : ssattr) {
1484 out_vec.push_back(c);
1488 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1489 snprintf(tv, 3,
"%02X", *rit);
1490 out_vec.push_back(tv[0]);
1491 out_vec.push_back(tv[1]);
1495 for (
auto ci = ++out_vec.begin(); ci != out_vec.end(); ci++) {
1498 out_vec.push_back(
'*');
1499 snprintf(tv, 3,
"%02X", crc);
1500 out_vec.push_back(tv[0]);
1501 out_vec.push_back(tv[1]);
1504 out_vec.push_back(0x0d);
1505 out_vec.push_back(0x0a);
1516std::vector<std::vector<unsigned char>> CommDriverN2KNet::GetTxVector(
1517 const std::shared_ptr<const Nmea2000Msg>& msg,
1518 std::shared_ptr<const NavAddr2000> dest_addr) {
1519 std::vector<std::vector<unsigned char>> tx_vector;
1522 switch (m_n2k_format) {
1523 case N2KFormat_YD_RAW:
1525 case N2KFormat_Actisense_RAW_ASCII: {
1527 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1530 std::vector<unsigned char> header_vec;
1531 std::vector<unsigned char> out_vec;
1536 wxDateTime now = wxDateTime::Now();
1537 wxString stime = now.Format(
"%H:%M:%S");
1539 std::string sstime = stime.ToStdString();
1540 for (
unsigned char s : sstime) header_vec.push_back(s);
1543 header_vec.push_back(
'T');
1544 header_vec.push_back(
' ');
1550 unsigned long can_id =
1551 BuildCanID(msg->priority, 0, dest_addr->address, msg->PGN.pgn);
1553 scan_id.Printf(
"%08X", can_id);
1554 std::string sscan_id = scan_id.ToStdString();
1555 for (
unsigned char s : sscan_id) header_vec.push_back(s);
1556 header_vec.push_back(
' ');
1559 int payload_size = msg->payload.size();
1560 unsigned char temp[8];
1563 (payload_size > 6 ? (payload_size - 6 - 1) / 7 + 1 + 1 : 1);
1565 for (
int i = 0; i < nframes && result; i++) {
1566 temp[0] = i | m_order;
1568 temp[1] = msg->payload.size();
1570 for (
int j = 2; j < 8; j++) {
1571 temp[j] = msg->payload.data()[cur];
1577 for (; j < 8 && cur < payload_size; j++) {
1578 temp[j] = msg->payload.data()[cur];
1581 for (; j < 8; j++) {
1589 for (
unsigned char s : header_vec) out_vec.push_back(s);
1593 for (
unsigned int k = 0; k < 8; k++) {
1595 snprintf(tb, 4,
"%02X ", temp[k]);
1598 for (
unsigned char s : ssdata) out_vec.push_back(s);
1601 out_vec.push_back(0x0d);
1602 out_vec.push_back(0x0a);
1607 tx_vector.push_back(out_vec);
1611 case N2KFormat_Actisense_N2K_ASCII: {
1628 std::vector<unsigned char> ovec;
1631 wxDateTime now = wxDateTime::Now();
1632 wxString stime = now.Format(
"%H%M%S");
1634 std::string sstime = stime.ToStdString();
1635 ovec.push_back(
'A');
1636 for (
unsigned char s : sstime) ovec.push_back(s);
1640 sdp.Printf(
"%02X%02X%1X ",
1642 (
unsigned char)dest_addr->address,
1643 (
unsigned char)msg->priority);
1644 std::string ssdp = sdp.ToStdString();
1645 for (
unsigned char s : ssdp) ovec.push_back(s);
1649 spgn.Printf(
"%05X ", (
int)msg->PGN.pgn);
1650 std::string sspgn = spgn.ToStdString();
1651 for (
unsigned char s : sspgn) ovec.push_back(s);
1656 for (
unsigned char d : msg->payload) {
1657 snprintf(tv, 3,
"%02X", d);
1660 for (
unsigned char s : sspl) ovec.push_back(s);
1663 ovec.push_back(0x0d);
1664 ovec.push_back(0x0a);
1667 tx_vector.push_back(ovec);
1671 case N2KFormat_MiniPlex: {
1672 std::vector<unsigned char> ovec;
1673 if (!IsFastMessagePGN(msg->PGN.pgn) && msg->payload.size() < 8) {
1678 (msg->payload.size() > 6 ? (msg->payload.size() - 6 - 1) / 7 + 1 + 1
1680 for (
size_t i = 0; i < nframes; i++) {
1681 ovec.push_back(
'$');
1682 ovec.push_back(
'M');
1683 ovec.push_back(
'X');
1684 ovec.push_back(
'P');
1685 ovec.push_back(
'G');
1686 ovec.push_back(
'N');
1687 ovec.push_back(
',');
1690 spgn.Printf(
"%06X,", (
int)msg->PGN.pgn);
1691 std::string sspgn = spgn.ToStdString();
1692 for (
unsigned char c : sspgn) {
1698 if (i == nframes - 1) {
1699 len = msg->payload.size() + 1 - 6 - (nframes - 2) * 7;
1701 attr |= ((uint16_t)((uint8_t)msg->priority & 0x07)) << 12;
1702 attr |= ((uint16_t)len) << 8;
1703 attr |= (uint16_t)dest_addr->address;
1707 sattr.Printf(
"%04X,", attr);
1708 std::string ssattr = sattr.ToStdString();
1709 for (
unsigned char c : ssattr) {
1714 uint8_t databytes = i == 0 ? len - 2 : len - 1;
1715 std::vector<unsigned char> payload;
1716 for (uint8_t j = 0; j < databytes; j++) {
1717 payload.push_back(msg->payload[cur]);
1720 for (
auto rit = payload.rbegin(); rit != payload.rend(); ++rit) {
1721 snprintf(tv, 3,
"%02X", *rit);
1722 ovec.push_back(tv[0]);
1723 ovec.push_back(tv[1]);
1726 snprintf(tv, 3,
"%02X", (uint8_t)msg->payload.size());
1727 ovec.push_back(tv[0]);
1728 ovec.push_back(tv[1]);
1731 snprintf(tv, 3,
"%02X", (uint8_t)i | m_order);
1732 ovec.push_back(tv[0]);
1733 ovec.push_back(tv[1]);
1737 for (
auto ci = ++ovec.begin(); ci != ovec.end(); ci++) {
1740 ovec.push_back(
'*');
1741 snprintf(tv, 3,
"%02X", crc);
1742 ovec.push_back(tv[0]);
1743 ovec.push_back(tv[1]);
1746 ovec.push_back(0x0d);
1747 ovec.push_back(0x0a);
1753 tx_vector.push_back(ovec);
1760 case N2KFormat_Actisense_N2K:
1762 case N2KFormat_Actisense_RAW:
1764 case N2KFormat_Actisense_NGT:
1766 case N2KFormat_SeaSmart:
1777bool CommDriverN2KNet::PrepareForTX() {
1787 bool b_found =
false;
1794 if (m_n2k_format == N2KFormat_Actisense_N2K_ASCII)
return true;
1801 if (m_n2k_format == N2KFormat_MiniPlex)
return true;
1806 if (m_n2k_format == N2KFormat_SeaSmart)
return false;
1814 prod_info_map.clear();
1817 std::vector<unsigned char> payload;
1818 payload.push_back(0x14);
1819 payload.push_back(0xF0);
1820 payload.push_back(0x01);
1822 std::vector<std::vector<unsigned char>> out_data;
1823 std::vector<unsigned char> msg_vec =
1824 MakeSimpleOutMsg(N2KFormat_YD_RAW, 59904, payload);
1825 out_data.push_back(msg_vec);
1826 SendSentenceNetwork(out_data);
1833 for (
const auto& [key, value] : prod_info_map) {
1834 auto prod_info = value;
1835 if (prod_info.Model_ID.find(
"YDEN") != std::string::npos) {
1840 if (prod_info.RT_flag ==
'T') b_found =
true;
1845 if (b_found)
return true;
1851bool CommDriverN2KNet::SendN2KNetwork(std::shared_ptr<const Nmea2000Msg>& msg,
1852 std::shared_ptr<const NavAddr2000> addr) {
1855 std::vector<std::vector<unsigned char>> out_data = GetTxVector(msg, addr);
1856 SendSentenceNetwork(out_data);
1860bool CommDriverN2KNet::SendSentenceNetwork(
1861 std::vector<std::vector<unsigned char>> payload) {
1868 wxDatagramSocket* udp_socket;
1869 switch (GetProtocol()) {
1871 for (std::vector<unsigned char>& v : payload) {
1872 if (GetSock() && GetSock()->IsOk()) {
1874 GetSock()->Write(v.data(), v.size());
1875 if (GetSock()->Error()) {
1876 if (GetSockServer()) {
1877 GetSock()->Destroy();
1880 wxSocketClient* tcp_socket =
1881 dynamic_cast<wxSocketClient*
>(GetSock());
1882 if (tcp_socket) tcp_socket->Close();
1883 if (!GetSocketTimer()->IsRunning())
1884 GetSocketTimer()->Start(
1885 5000, wxTIMER_ONE_SHOT);
1886 GetSocketThreadWatchdogTimer()->Stop();
1897 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
1898 if (udp_socket && udp_socket->IsOk()) {
1899 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
1900 if (udp_socket->Error()) ret =
false;
1915void CommDriverN2KNet::Close() {
1916 wxLogMessage(wxString::Format(_T(
"Closing NMEA NetworkDataStream %s"),
1917 GetNetPort().c_str()));
1921 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
1922 sizeof(m_mrq_container->m_mrq));
1923 m_sock->Notify(FALSE);
1928 m_tsock->Notify(FALSE);
1932 if (m_socket_server) {
1933 m_socket_server->Notify(FALSE);
1934 m_socket_server->Destroy();
1937 m_socket_timer.Stop();
1938 m_socketread_watchdog_timer.Stop();
1941bool CommDriverN2KNet::SetOutputSocketOptions(wxSocketBase* tsock) {
1950 int nagleDisable = 1;
1951 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
1952 sizeof(nagleDisable));
1958 unsigned long outbuf_size = 1024;
1959 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
1960 sizeof(outbuf_size)) &&
void OnSocketEvent(wxSocketEvent &event)
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.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
Suspend/resume and new devices events exchange point.