34 #include <wx/msw/winundef.h>
38 #include <wx/wxprec.h>
44 #include <wx/tokenzr.h>
45 #include <wx/datetime.h>
52 #include <arpa/inet.h>
53 #include <netinet/tcp.h>
57 #include <wx/socket.h>
59 #include <wx/memory.h>
60 #include <wx/chartype.h>
62 #include <wx/sckaddr.h>
64 #include "model/comm_drv_n0183_net.h"
65 #include "model/comm_navmsg_bus.h"
66 #include "model/garmin_protocol_mgr.h"
67 #include "model/idents.h"
68 #include "model/sys_events.h"
70 #include "observable.h"
72 #define N_DOG_TIMEOUT 8
75 bool CheckSumCheck(
const std::string& sentence) {
76 size_t check_start = sentence.find(
'*');
77 if (check_start == wxString::npos || check_start > sentence.size() - 3)
80 std::string check_str = sentence.substr(check_start + 1, 2);
81 unsigned long checksum = strtol(check_str.c_str(), 0, 16);
82 if (checksum == 0L && check_str !=
"00")
return false;
84 unsigned char calculated_checksum = 0;
85 for (std::string::const_iterator i = sentence.begin() + 1;
86 i != sentence.end() && *i !=
'*'; ++i)
87 calculated_checksum ^=
static_cast<unsigned char>(*i);
89 return calculated_checksum == checksum;
95 void SetMrqAddr(
unsigned int addr) {
96 m_mrq.imr_multiaddr.s_addr = addr;
97 m_mrq.imr_interface.s_addr = INADDR_ANY;
109 : wxEvent(
id, commandType){};
113 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
116 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
119 wxEvent* Clone()
const {
121 newevent->m_payload = this->m_payload;
126 std::shared_ptr<std::vector<unsigned char>> m_payload;
134 EVT_TIMER(TIMER_SOCKET, CommDriverN0183Net::OnTimerSocket)
136 EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN0183Net::OnServerSocketEvent)
137 EVT_TIMER(TIMER_SOCKET + 1, CommDriverN0183Net::OnSocketReadWatchdogTimer)
147 m_listener(listener),
148 m_net_port(wxString::Format("%i", params->NetworkPort)),
149 m_net_protocol(params->NetProtocol),
152 m_socket_server(NULL),
153 m_is_multicast(false),
155 m_portstring(params->GetDSPort()),
156 m_io_select(params->IOSelect),
157 m_connection_type(params->Type),
161 m_addr.Hostname(params->NetworkAddress);
162 m_addr.Service(params->NetworkPort);
164 m_socket_timer.SetOwner(
this, TIMER_SOCKET);
165 m_socketread_watchdog_timer.SetOwner(
this, TIMER_SOCKET + 1);
166 this->attributes[
"netAddress"] = params->NetworkAddress.ToStdString();
168 sprintf(port_char,
"%d", params->NetworkPort);
169 this->attributes[
"netPort"] = std::string(port_char);
170 this->attributes[
"userComment"] = params->UserComment.ToStdString();
171 dsPortType iosel = params->IOSelect;
172 std::string s_iosel = std::string(
"IN");
173 if (iosel == DS_TYPE_INPUT_OUTPUT) {s_iosel =
"OUT";}
174 else if (iosel == DS_TYPE_INPUT_OUTPUT) {s_iosel =
"IN/OUT";}
175 this->attributes[
"ioDirection"] = s_iosel;
178 Bind(wxEVT_COMMDRIVER_N0183_NET, &CommDriverN0183Net::handle_N0183_MSG,
this);
183 resume_listener.Init(SystemEvents::GetInstance().evt_resume,
188 CommDriverN0183Net::~CommDriverN0183Net() {
189 delete m_mrq_container;
194 auto p =
event.GetPayload();
195 std::vector<unsigned char>* payload = p.get();
198 std::string full_sentence = std::string(payload->begin(), payload->end());
200 if ((full_sentence[0] ==
'$') || (full_sentence[0] ==
'!')) {
201 std::string identifier;
203 identifier = full_sentence.substr(1, 5);
207 auto msg = std::make_shared<const Nmea0183Msg>(identifier, full_sentence,
209 auto msg_all = std::make_shared<const Nmea0183Msg>(*msg,
"ALL");
211 if (m_params.SentencePassesFilter(full_sentence, FILTER_INPUT))
212 m_listener.
Notify(std::move(msg));
213 m_listener.
Notify(std::move(msg_all));
217 void CommDriverN0183Net::Open(
void) {
219 #if wxCHECK_VERSION(3, 0, 0)
221 ((
struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
224 ((
struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
227 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
230 switch (m_net_protocol) {
236 OpenNetworkTCP(addr);
240 OpenNetworkUDP(addr);
249 void CommDriverN0183Net::OpenNetworkUDP(
unsigned int addr) {
250 if (GetPortType() != DS_TYPE_OUTPUT) {
253 wxIPV4address conn_addr;
254 conn_addr.Service(GetNetPort());
255 conn_addr.AnyAddress();
257 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
260 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
262 m_mrq_container->SetMrqAddr(addr);
263 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP,
264 &m_mrq_container->m_mrq,
265 sizeof(m_mrq_container->m_mrq));
268 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
270 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
272 GetSock()->Notify(TRUE);
273 GetSock()->SetTimeout(1);
277 if (GetPortType() != DS_TYPE_INPUT) {
278 wxIPV4address tconn_addr;
279 tconn_addr.Service(0);
280 tconn_addr.AnyAddress();
282 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
287 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(_T(
"255")))) {
288 int broadcastEnable = 1;
289 bool bam = GetTSock()->SetOption(
290 SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
sizeof(broadcastEnable));
295 SetConnectTime(wxDateTime::Now());
298 void CommDriverN0183Net::OpenNetworkTCP(
unsigned int addr) {
299 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
300 wxLogMessage(wxString::Format(_T(
"Opening TCP Server %d"), isServer));
303 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
305 SetSock(
new wxSocketClient());
309 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
310 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
311 GetSockServer()->Notify(TRUE);
312 GetSockServer()->SetTimeout(1);
314 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
315 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
316 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
317 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
318 GetSock()->SetNotify(notify_flags);
319 GetSock()->Notify(TRUE);
320 GetSock()->SetTimeout(1);
322 SetBrxConnectEvent(
false);
323 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
327 SetConnectTime(wxDateTime::Now());
330 void CommDriverN0183Net::OpenNetworkGPSD() {
331 SetSock(
new wxSocketClient());
332 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
333 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
335 GetSock()->Notify(TRUE);
336 GetSock()->SetTimeout(1);
338 wxSocketClient* tcp_socket =
static_cast<wxSocketClient*
>(GetSock());
339 tcp_socket->Connect(GetAddr(), FALSE);
340 SetBrxConnectEvent(
false);
343 void CommDriverN0183Net::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
346 if (m_dog_value <= 0) {
347 if (GetParams().NoDataReconnect) {
349 if (GetProtocol() == TCP) {
350 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
354 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT - 2, 2);
355 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.",
357 GetSocketTimer()->Start(n_reconnect_delay * 1000, wxTIMER_ONE_SHOT);
360 GetSocketThreadWatchdogTimer()->Stop();
366 void CommDriverN0183Net::OnTimerSocket() {
368 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
370 if (tcp_socket->IsDisconnected()) {
371 wxLogDebug(
" Attempting reconnection...");
372 SetBrxConnectEvent(
false);
374 GetSocketThreadWatchdogTimer()->Stop();
375 tcp_socket->Connect(GetAddr(), FALSE);
378 int n_reconnect_delay = N_DOG_TIMEOUT;
379 GetSocketTimer()->Start(n_reconnect_delay * 1000,
385 void CommDriverN0183Net::HandleResume() {
388 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
390 GetSocketThreadWatchdogTimer()->Stop();
395 int n_reconnect_delay = wxMax(N_DOG_TIMEOUT-2, 2);
396 wxLogMessage(wxString::Format(
" Reconnection scheduled in %d seconds.", n_reconnect_delay));
398 GetSocketTimer()->Start(n_reconnect_delay * 1000,
403 bool CommDriverN0183Net::SendMessage(std::shared_ptr<const NavMsg> msg,
404 std::shared_ptr<const NavAddr> addr) {
405 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
406 return SendSentenceNetwork(msg_0183->payload.c_str());
411 #define RD_BUF_SIZE \
415 switch (event.GetSocketEvent()) {
431 std::vector<char> data(RD_BUF_SIZE + 1);
432 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
433 if (!event.GetSocket()->Error()) {
434 size_t count =
event.GetSocket()->LastCount();
438 m_sock_buffer += (&data.front());
443 m_sock_buffer.append(&data.front(), count);
452 size_t nmea_end = m_sock_buffer.find_first_of(
460 if (m_sock_buffer[nmea_end] !=
'*') nmea_tail = -1;
462 if (nmea_end < m_sock_buffer.size() - nmea_tail) {
469 std::string nmea_line = m_sock_buffer.substr(0, nmea_end);
476 if (nmea_end > m_sock_buffer.size())
477 m_sock_buffer.clear();
479 m_sock_buffer = m_sock_buffer.substr(nmea_end);
481 size_t nmea_start = nmea_line.find_last_of(
485 if (nmea_start != wxString::npos) {
486 nmea_line = nmea_line.substr(nmea_start);
488 if (ChecksumOK(nmea_line)) {
490 if (nmea_line.size()) {
492 auto buffer = std::make_shared<std::vector<unsigned char>>();
493 std::vector<unsigned char>* vec = buffer.get();
494 std::copy(nmea_line.begin(), nmea_line.end(),
495 std::back_inserter(*vec));
497 Nevent.SetPayload(buffer);
498 AddPendingEvent(Nevent);
508 if (m_sock_buffer.size() > RD_BUF_SIZE)
510 m_sock_buffer.substr(m_sock_buffer.size() - RD_BUF_SIZE);
512 m_dog_value = N_DOG_TIMEOUT;
516 case wxSOCKET_LOST: {
517 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
518 if (GetBrxConnectEvent())
519 wxLogMessage(wxString::Format(
520 _T(
"NetworkDataStream connection lost: %s"), GetPort().c_str()));
521 if (GetSockServer()) {
522 GetSock()->Destroy();
526 wxDateTime now = wxDateTime::Now();
527 wxTimeSpan since_connect(
529 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
531 int retry_time = 5000;
537 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
540 GetSocketThreadWatchdogTimer()->Stop();
541 GetSocketTimer()->Start(
542 retry_time, wxTIMER_ONE_SHOT);
547 case wxSOCKET_CONNECTION: {
548 if (GetProtocol() == GPSD) {
552 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
553 GetSock()->Write(cmd, strlen(cmd));
554 }
else if (GetProtocol() == TCP) {
555 wxLogMessage(wxString::Format(
556 _T(
"TCP NetworkDataStream connection established: %s"),
559 m_dog_value = N_DOG_TIMEOUT;
560 if (GetPortType() != DS_TYPE_OUTPUT) {
562 if (GetParams().NoDataReconnect)
563 GetSocketThreadWatchdogTimer()->Start(1000);
566 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
567 (void)SetOutputSocketOptions(GetSock());
568 GetSocketTimer()->Stop();
569 SetBrxConnectEvent(
true);
572 SetConnectTime(wxDateTime::Now());
581 void CommDriverN0183Net::OnServerSocketEvent(wxSocketEvent& event) {
582 switch (event.GetSocketEvent()) {
583 case wxSOCKET_CONNECTION: {
584 SetSock(GetSockServer()->Accept(
false));
587 GetSock()->SetTimeout(2);
589 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
590 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
591 if (GetPortType() != DS_TYPE_INPUT) {
592 notify_flags |= wxSOCKET_OUTPUT_FLAG;
593 (void)SetOutputSocketOptions(GetSock());
595 if (GetPortType() != DS_TYPE_OUTPUT)
596 notify_flags |= wxSOCKET_INPUT_FLAG;
597 GetSock()->SetNotify(notify_flags);
598 GetSock()->Notify(
true);
609 bool CommDriverN0183Net::SendSentenceNetwork(
const wxString& payload) {
616 wxDatagramSocket* udp_socket;
617 switch (GetProtocol()) {
619 if (GetSock() && GetSock()->IsOk()) {
620 GetSock()->Write(payload.mb_str(), strlen(payload.mb_str()));
621 if (GetSock()->Error()) {
622 if (GetSockServer()) {
623 GetSock()->Destroy();
626 wxSocketClient* tcp_socket =
627 dynamic_cast<wxSocketClient*
>(GetSock());
628 if (tcp_socket) tcp_socket->Close();
629 if (!GetSocketTimer()->IsRunning())
630 GetSocketTimer()->Start(
631 5000, wxTIMER_ONE_SHOT);
632 GetSocketThreadWatchdogTimer()->Stop();
641 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
642 if (udp_socket && udp_socket->IsOk()) {
643 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
644 if (udp_socket->Error()) ret =
false;
658 void CommDriverN0183Net::Close() {
659 wxLogMessage(wxString::Format(_T(
"Closing NMEA NetworkDataStream %s"),
660 GetNetPort().c_str()));
664 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
665 sizeof(m_mrq_container->m_mrq));
666 m_sock->Notify(FALSE);
671 m_tsock->Notify(FALSE);
675 if (m_socket_server) {
676 m_socket_server->Notify(FALSE);
677 m_socket_server->Destroy();
680 m_socket_timer.Stop();
681 m_socketread_watchdog_timer.Stop();
684 bool CommDriverN0183Net::SetOutputSocketOptions(wxSocketBase* tsock) {
693 int nagleDisable = 1;
694 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
695 sizeof(nagleDisable));
701 unsigned long outbuf_size = 1024;
702 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
703 sizeof(outbuf_size)) &&
707 bool CommDriverN0183Net::ChecksumOK(
const std::string& sentence) {
708 if (!m_bchecksumCheck)
return true;
710 return CheckSumCheck(sentence);
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.
Where messages are sent to or received from.
Adds a std::shared<void> element to wxCommandEvent.
wxDEFINE_EVENT(REST_IO_EVT, ObservedEvt)
Event from IO thread to main.