34#include <wx/msw/winundef.h>
44#include <wx/tokenzr.h>
45#include <wx/datetime.h>
53#include <netinet/tcp.h>
60#include <wx/chartype.h>
62#include <wx/sckaddr.h>
64#include "garmin_protocol_mgr.h"
66#include "comm_drv_n0183_net.h"
67#include "comm_navmsg_bus.h"
70#define N_DOG_TIMEOUT 5
73bool CheckSumCheck(
const std::string &sentence) {
74 size_t check_start = sentence.find(
'*');
75 if (check_start == wxString::npos || check_start > sentence.size() - 3)
78 std::string check_str = sentence.substr(check_start + 1, 2);
79 unsigned long checksum = strtol(check_str.c_str(), 0, 16);
80 if (checksum == 0L && check_str !=
"00")
return false;
82 unsigned char calculated_checksum = 0;
83 for (std::string::const_iterator i = sentence.begin() + 1;
84 i != sentence.end() && *i !=
'*'; ++i)
85 calculated_checksum ^=
static_cast<unsigned char>(*i);
87 return calculated_checksum == checksum;
94 void SetMrqAddr(
unsigned int addr) {
95 m_mrq.imr_multiaddr.s_addr = addr;
96 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;
134EVT_TIMER(TIMER_SOCKET, CommDriverN0183Net::OnTimerSocket)
135EVT_SOCKET(DS_SOCKET_ID, CommDriverN0183Net::OnSocketEvent)
136EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN0183Net::OnServerSocketEvent)
137EVT_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);
168 Bind(wxEVT_COMMDRIVER_N0183_NET, &CommDriverN0183Net::handle_N0183_MSG,
this);
175CommDriverN0183Net::~CommDriverN0183Net() {
176 delete m_mrq_container;
181 auto p =
event.GetPayload();
182 std::vector<unsigned char>* payload = p.get();
185 std::string full_sentence = std::string(payload->begin(), payload->end());
187 if ((full_sentence[0] ==
'$') || (full_sentence[0] ==
'!')) {
188 std::string identifier;
190 identifier = full_sentence.substr(1, 5);
194 auto msg = std::make_shared<const Nmea0183Msg>(identifier, full_sentence,
196 auto msg_all = std::make_shared<const Nmea0183Msg>(*msg,
"ALL");
198 if (m_params.SentencePassesFilter(full_sentence, FILTER_INPUT))
199 m_listener.
Notify(std::move(msg));
200 m_listener.
Notify(std::move(msg_all));
204void CommDriverN0183Net::Open(
void) {
206#if wxCHECK_VERSION(3, 0, 0)
208 ((
struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
211 ((
struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
214 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
217 switch (m_net_protocol) {
223 OpenNetworkTCP(addr);
227 OpenNetworkUDP(addr);
236void CommDriverN0183Net::OpenNetworkUDP(
unsigned int addr) {
237 if (GetPortType() != DS_TYPE_OUTPUT) {
240 wxIPV4address conn_addr;
241 conn_addr.Service(GetNetPort());
242 conn_addr.AnyAddress();
244 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
247 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
249 m_mrq_container->SetMrqAddr(addr);
250 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &m_mrq_container->m_mrq,
251 sizeof(m_mrq_container->m_mrq));
254 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
256 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
258 GetSock()->Notify(TRUE);
259 GetSock()->SetTimeout(1);
263 if (GetPortType() != DS_TYPE_INPUT) {
264 wxIPV4address tconn_addr;
265 tconn_addr.Service(0);
266 tconn_addr.AnyAddress();
268 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
273 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(_T(
"255")))) {
274 int broadcastEnable = 1;
275 bool bam = GetTSock()->SetOption(
276 SOL_SOCKET, SO_BROADCAST, &broadcastEnable,
sizeof(broadcastEnable));
281 SetConnectTime(wxDateTime::Now());
284void CommDriverN0183Net::OpenNetworkTCP(
unsigned int addr) {
285 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
286 wxLogMessage(wxString::Format(_T(
"Opening TCP Server %d"), isServer));
289 SetSockServer(
new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
291 SetSock(
new wxSocketClient());
295 GetSockServer()->SetEventHandler(*
this, DS_SERVERSOCKET_ID);
296 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
297 GetSockServer()->Notify(TRUE);
298 GetSockServer()->SetTimeout(1);
300 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
301 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
302 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
303 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
304 GetSock()->SetNotify(notify_flags);
305 GetSock()->Notify(TRUE);
306 GetSock()->SetTimeout(1);
308 SetBrxConnectEvent(
false);
309 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT);
313 SetConnectTime(wxDateTime::Now());
316void CommDriverN0183Net::OpenNetworkGPSD() {
317 SetSock(
new wxSocketClient());
318 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
319 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
321 GetSock()->Notify(TRUE);
322 GetSock()->SetTimeout(1);
324 wxSocketClient* tcp_socket =
static_cast<wxSocketClient*
>(GetSock());
325 tcp_socket->Connect(GetAddr(), FALSE);
326 SetBrxConnectEvent(
false);
329void CommDriverN0183Net::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
331 if (m_dog_value <= 0) {
333 wxString::Format(_T(
" TCP NetworkDataStream watchdog timeout: %s"),
336 if (GetProtocol() == TCP) {
337 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
341 GetSocketTimer()->Start(5000, wxTIMER_ONE_SHOT);
342 GetSocketThreadWatchdogTimer()->Stop();
347void CommDriverN0183Net::OnTimerSocket(wxTimerEvent& event) {
349 wxSocketClient* tcp_socket =
dynamic_cast<wxSocketClient*
>(GetSock());
351 if (tcp_socket->IsDisconnected()) {
352 SetBrxConnectEvent(
false);
353 tcp_socket->Connect(GetAddr(), FALSE);
354 GetSocketTimer()->Start(5000,
360bool CommDriverN0183Net::SendMessage(std::shared_ptr<const NavMsg> msg,
361 std::shared_ptr<const NavAddr> addr) {
362 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
363 return SendSentenceNetwork(msg_0183->payload.c_str());
367void CommDriverN0183Net::OnSocketEvent(wxSocketEvent& event) {
373 switch (event.GetSocketEvent()) {
389 std::vector<char> data(RD_BUF_SIZE + 1);
390 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
391 if (!event.GetSocket()->Error()) {
392 size_t count =
event.GetSocket()->LastCount();
396 m_sock_buffer += (&data.front());
401 m_sock_buffer.append(&data.front(), count);
410 size_t nmea_end = m_sock_buffer.find_first_of(
418 if (m_sock_buffer[nmea_end] !=
'*') nmea_tail = -1;
420 if (nmea_end < m_sock_buffer.size() - nmea_tail) {
427 std::string nmea_line = m_sock_buffer.substr(0, nmea_end);
435 if (nmea_end > m_sock_buffer.size())
436 m_sock_buffer.clear();
438 m_sock_buffer = m_sock_buffer.substr(nmea_end);
440 size_t nmea_start = nmea_line.find_last_of(
444 if (nmea_start != wxString::npos) {
445 nmea_line = nmea_line.substr(nmea_start);
447 if (ChecksumOK(nmea_line)) {
449 if (nmea_line.size()) {
451 auto buffer = std::make_shared<std::vector<unsigned char>>();
452 std::vector<unsigned char>* vec = buffer.get();
453 std::copy(nmea_line.begin(), nmea_line.end(),
454 std::back_inserter(*vec));
456 Nevent.SetPayload(buffer);
457 AddPendingEvent(Nevent);
467 if (m_sock_buffer.size() > RD_BUF_SIZE)
469 m_sock_buffer.substr(m_sock_buffer.size() - RD_BUF_SIZE);
471 m_dog_value = N_DOG_TIMEOUT;
475 case wxSOCKET_LOST: {
476 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
477 if (GetBrxConnectEvent())
478 wxLogMessage(wxString::Format(
479 _T(
"NetworkDataStream connection lost: %s"), GetPort().c_str()));
480 if (GetSockServer()) {
481 GetSock()->Destroy();
485 wxDateTime now = wxDateTime::Now();
486 wxTimeSpan since_connect(
488 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
490 int retry_time = 5000;
496 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
499 GetSocketThreadWatchdogTimer()->Stop();
500 GetSocketTimer()->Start(
501 retry_time, wxTIMER_ONE_SHOT);
506 case wxSOCKET_CONNECTION: {
507 if (GetProtocol() == GPSD) {
511 char cmd[] =
"?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
512 GetSock()->Write(cmd, strlen(cmd));
513 }
else if (GetProtocol() == TCP) {
514 wxLogMessage(wxString::Format(
515 _T(
"TCP NetworkDataStream connection established: %s"),
517 m_dog_value = N_DOG_TIMEOUT;
518 if (GetPortType() != DS_TYPE_OUTPUT)
519 GetSocketThreadWatchdogTimer()->Start(1000);
520 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
521 (void)SetOutputSocketOptions(GetSock());
522 GetSocketTimer()->Stop();
523 SetBrxConnectEvent(
true);
526 SetConnectTime(wxDateTime::Now());
535void CommDriverN0183Net::OnServerSocketEvent(wxSocketEvent& event) {
536 switch (event.GetSocketEvent()) {
537 case wxSOCKET_CONNECTION: {
538 SetSock(GetSockServer()->Accept(
false));
541 GetSock()->SetTimeout(2);
543 GetSock()->SetEventHandler(*
this, DS_SOCKET_ID);
544 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
545 if (GetPortType() != DS_TYPE_INPUT) {
546 notify_flags |= wxSOCKET_OUTPUT_FLAG;
547 (void)SetOutputSocketOptions(GetSock());
549 if (GetPortType() != DS_TYPE_OUTPUT)
550 notify_flags |= wxSOCKET_INPUT_FLAG;
551 GetSock()->SetNotify(notify_flags);
552 GetSock()->Notify(
true);
563bool CommDriverN0183Net::SendSentenceNetwork(
const wxString& payload) {
570 wxDatagramSocket* udp_socket;
571 switch (GetProtocol()) {
573 if (GetSock() && GetSock()->IsOk()) {
574 GetSock()->Write(payload.mb_str(), strlen(payload.mb_str()));
575 if (GetSock()->Error()) {
576 if (GetSockServer()) {
577 GetSock()->Destroy();
580 wxSocketClient* tcp_socket =
581 dynamic_cast<wxSocketClient*
>(GetSock());
582 if (tcp_socket) tcp_socket->Close();
583 if (!GetSocketTimer()->IsRunning())
584 GetSocketTimer()->Start(
585 5000, wxTIMER_ONE_SHOT);
586 GetSocketThreadWatchdogTimer()->Stop();
595 udp_socket =
dynamic_cast<wxDatagramSocket*
>(GetTSock());
596 if (udp_socket && udp_socket->IsOk()) {
597 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
598 if (udp_socket->Error()) ret =
false;
612void CommDriverN0183Net::Close() {
613 wxLogMessage(wxString::Format(_T(
"Closing NMEA NetworkDataStream %s"),
614 GetNetPort().c_str()));
618 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
619 sizeof(m_mrq_container->m_mrq));
620 m_sock->Notify(FALSE);
625 m_tsock->Notify(FALSE);
629 if (m_socket_server) {
630 m_socket_server->Notify(FALSE);
631 m_socket_server->Destroy();
634 m_socket_timer.Stop();
635 m_socketread_watchdog_timer.Stop();
638bool CommDriverN0183Net::SetOutputSocketOptions(wxSocketBase* tsock) {
647 int nagleDisable = 1;
648 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
649 sizeof(nagleDisable));
655 unsigned long outbuf_size = 1024;
656 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
657 sizeof(outbuf_size)) &&
661bool CommDriverN0183Net::ChecksumOK(
const std::string& sentence) {
662 if (!m_bchecksumCheck)
return true;
664 return CheckSumCheck(sentence);
Internal wxEvent worker thread – main driver.
Driver for NMEA0183 over TCP/IP.
Abstract NMEA0183 drivers common parts.
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.