52static unsigned char NGT_STARTUP_SEQ[] = {
58static std::vector<unsigned char> BufferToActisenseFormat(tN2kMsg& msg);
64 std::lock_guard<std::mutex> lock(m_mutex);
65 return m_queque.size();
69 std::lock_guard<std::mutex> lock(m_mutex);
70 return m_queque.empty();
74 std::lock_guard<std::mutex> lock(m_mutex);
75 return m_queque.front();
78 void push(
const T& value) {
79 std::lock_guard<std::mutex> lock(m_mutex);
84 std::lock_guard<std::mutex> lock(m_mutex);
89 std::queue<T> m_queque;
90 mutable std::mutex m_mutex;
97 : buf_(std::unique_ptr<T[]>(new T[size])), max_size_(size) {}
100 size_t capacity()
const;
105 return (!full_ && (head_ == tail_));
114 std::lock_guard<std::mutex> lock(mutex_);
116 if (full_) tail_ = (tail_ + 1) % max_size_;
118 head_ = (head_ + 1) % max_size_;
120 full_ = head_ == tail_;
124 std::lock_guard<std::mutex> lock(mutex_);
126 if (empty())
return T();
129 auto val = buf_[tail_];
131 tail_ = (tail_ + 1) % max_size_;
138 std::unique_ptr<T[]> buf_;
141 const size_t max_size_;
150 const wxString& PortName,
151 const wxString& strBaudRate);
155 bool SetOutMsg(
const std::vector<unsigned char>& load);
163 void ThreadMessage(
const wxString& msg);
164 bool OpenComPortPhysical(
const wxString& com_name,
int baud_rate);
165 void CloseComPortPhysical();
166 size_t WriteComPortPhysical(std::vector<unsigned char> msg);
167 size_t WriteComPortPhysical(
unsigned char* msg,
size_t length);
168 void SetGatewayOperationMode();
172 wxString m_FullPortName;
174 unsigned char* put_ptr;
175 unsigned char* tak_ptr;
177 unsigned char* rx_buffer;
184 mutable std::mutex m_stats_mutex;
186 HANDLE m_hSerialComm;
197 : wxEvent(
id, commandType) {};
201 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
204 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
207 wxEvent* Clone()
const {
209 newevent->m_payload = this->m_payload;
214 std::shared_ptr<std::vector<unsigned char>> m_payload;
226 m_Thread_run_flag(-1),
229 m_portstring(params->GetDSPort()),
230 m_pSecondary_Thread(NULL),
231 m_listener(listener),
232 m_stats_timer(*this, 2s),
234 m_BaudRate = wxString::Format(
"%i", params->Baudrate), SetSecThreadInActive();
235 m_manufacturers_code = 0;
236 m_got_mfg_code =
false;
237 this->attributes[
"canAddress"] = std::string(
"-1");
238 this->attributes[
"userComment"] = params->UserComment.ToStdString();
242 Bind(wxEVT_COMMDRIVER_N2K_SERIAL, &CommDriverN2KSerial::handle_N2K_SERIAL_RAW,
246 m_driver_stats.driver_bus = NavAddr::Bus::N2000;
247 m_driver_stats.driver_iface = m_params.GetStrippedDSPort();
248 m_driver_stats.available =
false;
256 SendMgmtMsg(NGT_STARTUP_SEQ,
sizeof(NGT_STARTUP_SEQ), 0x11, 0, NULL);
259CommDriverN2KSerial::~CommDriverN2KSerial() { Close(); }
262 if (m_closing)
return m_driver_stats;
265 if (m_pSecondary_Thread)
266 return m_pSecondary_Thread->GetStats();
269 return m_driver_stats;
272bool CommDriverN2KSerial::Open() {
274 comx = m_params.GetDSPort().AfterFirst(
':');
277 comx.BeforeFirst(
' ');
283 GetSecondaryThread()->Run();
289void CommDriverN2KSerial::Close() {
290 wxLogMessage(wxString::Format(
"Closing N2K Driver %s", m_portstring.c_str()));
292 m_stats_timer.Stop();
296 if (m_pSecondary_Thread) {
297 if (m_bsec_thread_active)
299 wxLogMessage(
"Stopping Secondary Thread");
301 m_Thread_run_flag = 0;
303 while ((m_Thread_run_flag >= 0) && (tsec--)) wxSleep(1);
306 if (m_Thread_run_flag < 0)
307 msg.Printf(
"Stopped in %d sec.", 10 - tsec);
309 msg.Printf(
"Not Stopped after 10 sec.");
313 m_pSecondary_Thread = NULL;
314 m_bsec_thread_active =
false;
317static uint64_t PayloadToName(
const std::vector<unsigned char> payload) {
319 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
323bool CommDriverN2KSerial::SendMessage(std::shared_ptr<const NavMsg> msg,
324 std::shared_ptr<const NavAddr> addr) {
325 if (m_closing)
return false;
329 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
330 std::vector<uint8_t> load = msg_n2k->payload;
332 uint64_t _pgn = msg_n2k->PGN.pgn;
333 auto destination_address = std::static_pointer_cast<const NavAddr2000>(addr);
337 N2kMsg.Priority = msg_n2k->priority;
338 if (destination_address) N2kMsg.Destination = destination_address->address;
340 for (
size_t i = 0; i < load.size(); i++) N2kMsg.AddByte(load.at(i));
342 const std::vector<uint8_t> acti_pkg = BufferToActisenseFormat(N2kMsg);
345 std::vector<unsigned char> msg_payload;
346 for (
size_t i = 2; i < acti_pkg.size() - 2; i++)
347 msg_payload.push_back(acti_pkg[i]);
348 auto name = PayloadToName(load);
350 std::make_shared<const Nmea2000Msg>(1, msg_payload, GetAddress(name));
352 std::make_shared<const Nmea2000Msg>(_pgn, msg_payload, GetAddress(name));
355 m_listener.
Notify(std::move(msg_internal));
356 m_listener.
Notify(std::move(msg_all));
358 if (GetSecondaryThread()) {
359 if (IsSecThreadActive()) {
362 if (GetSecondaryThread()->SetOutMsg(acti_pkg))
375void CommDriverN2KSerial::ProcessManagementPacket(
376 std::vector<unsigned char>* payload) {
377 if (payload->at(2) != 0xF2) {
384 switch (payload->at(2)) {
396 if (payload->at(3) == 0x02) {
397 std::string device_common_name;
398 for (
unsigned int i = 0; i < 32; i++) {
399 device_common_name += payload->at(i + 14);
401 device_common_name +=
'\0';
402 m_device_common_name = device_common_name;
408 unsigned char name[8];
409 for (
unsigned int i = 0; i < 8; i++) name[i] = payload->at(i + 15);
411 memcpy((
void*)&NAME, name, 8);
413 int* f1 = (
int*)&NAME;
415 m_manufacturers_code = f1d >> 21;
424void CommDriverN2KSerial::handle_N2K_SERIAL_RAW(
426 auto p =
event.GetPayload();
428 std::vector<unsigned char>* payload = p.get();
430 if (payload->at(0) == 0xA0) {
431 ProcessManagementPacket(payload);
436 if (m_params.IOSelect != DS_TYPE_OUTPUT) {
439 unsigned char* c = (
unsigned char*)&pgn;
440 *c++ = payload->at(3);
441 *c++ = payload->at(4);
442 *c++ = payload->at(5);
444 auto name = PayloadToName(*payload);
446 std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
448 m_listener.
Notify(std::move(msg));
452int CommDriverN2KSerial::GetMfgCode() {
453 unsigned char request_name[] = {0x42};
454 int ni = SendMgmtMsg(request_name,
sizeof(request_name), 0x41, 2000,
457 m_got_mfg_code =
true;
461int CommDriverN2KSerial::SendMgmtMsg(
unsigned char*
string,
size_t string_size,
462 unsigned char cmd_code,
int timeout_msec,
463 bool* response_flag) {
468 std::vector<unsigned char> msg;
470 msg.push_back(ESCAPE);
471 msg.push_back(STARTOFTEXT);
474 msg.push_back(string_size);
475 byteSum += string_size;
477 for (
unsigned int i = 0; i < string_size; i++) {
478 if (
string[i] == ESCAPE) msg.push_back(
string[i]);
479 msg.push_back(
string[i]);
480 byteSum +=
string[i];
485 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
486 msg.push_back(CheckSum);
488 msg.push_back(ESCAPE);
489 msg.push_back(ENDOFTEXT);
493 if (response_flag) *response_flag =
false;
497 bool not_done =
true;
500 if (GetSecondaryThread() && IsSecThreadActive()) {
503 if (GetSecondaryThread()->SetOutMsg(msg)) {
512 if (ntry_outer-- <= 0) not_done =
false;
516 if (!bsent)
return 1;
520 int timeout = timeout_msec;
521 while (timeout > 0) {
525 if (*response_flag) {
545int CommDriverN2KSerial::SetTXPGN(
int pgn) {
547 unsigned char request_enable[] = {0x47, 0x00, 0x00, 0x00,
548 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF};
551 unsigned char* c = (
unsigned char*)&pgn;
552 request_enable[1] = c[0];
553 request_enable[2] = c[1];
554 request_enable[3] = c[2];
556 int aa = SendMgmtMsg(request_enable,
sizeof(request_enable), 0x47, 2000,
561 unsigned char request_commit[] = {0x01};
562 int bb = SendMgmtMsg(request_commit,
sizeof(request_commit), 0x01, 2000,
566 unsigned char request_activate[] = {0x4B};
567 int cc = SendMgmtMsg(request_activate,
sizeof(request_activate), 0x4B, 2000,
572void CommDriverN2KSerial::AddTxPGN(
int pgn) {
573 auto it = std::find(pgn_tx_list.begin(), pgn_tx_list.end(), pgn);
574 if (it != pgn_tx_list.end())
578 pgn_tx_list.push_back(pgn);
610#define DS_RX_BUFFER_SIZE 4096
612CommDriverN2KSerialThread::CommDriverN2KSerialThread(
614 const wxString& strBaudRate) {
615 m_pParentDriver = Launcher;
617 m_PortName = PortName;
618 m_FullPortName =
"Serial:" + PortName;
627 if (strBaudRate.ToLong(&lbaud)) m_baud = (int)lbaud;
629 std::lock_guard lock(m_stats_mutex);
630 m_driver_stats.driver_bus = NavAddr::Bus::N2000;
631 m_driver_stats.driver_iface = m_pParentDriver->m_params.GetStrippedDSPort();
632 m_driver_stats.available =
false;
638CommDriverN2KSerialThread::~CommDriverN2KSerialThread() {
delete[] rx_buffer; }
640void CommDriverN2KSerialThread::OnExit() {}
642DriverStats CommDriverN2KSerialThread::GetStats()
const {
643 std::lock_guard lock(m_stats_mutex);
644 return m_driver_stats;
647bool CommDriverN2KSerialThread::OpenComPortPhysical(
const wxString& com_name,
650 m_serial.
setPort(com_name.ToStdString());
654 }
catch (std::exception&) {
661void CommDriverN2KSerialThread::CloseComPortPhysical() {
664 }
catch (std::exception&) {
668 std::lock_guard lock(m_stats_mutex);
669 m_driver_stats.available =
false;
672void CommDriverN2KSerialThread::SetGatewayOperationMode() {
676 unsigned char config_string[] = {0x10, 0x02, 0xA1, 0x03, 0x11,
677 0x02, 0x00, 0x49, 0x10, 0x03};
681 WriteComPortPhysical(config_string, 10);
684void CommDriverN2KSerialThread::ThreadMessage(
const wxString& msg) {
691size_t CommDriverN2KSerialThread::WriteComPortPhysical(
692 std::vector<unsigned char> msg) {
693 return WriteComPortPhysical(msg.data(), msg.size());
696size_t CommDriverN2KSerialThread::WriteComPortPhysical(
unsigned char* msg,
698 if (!m_serial.
isOpen())
return 0;
700 size_t status = m_serial.
write((uint8_t*)msg, length);
703 }
catch (std::exception& e) {
704 DEBUG_LOG <<
"Unhandled Exception while writing to serial port: "
710bool CommDriverN2KSerialThread::SetOutMsg(
711 const std::vector<unsigned char>& msg) {
712 if (out_que.size() < OUT_QUEUE_LENGTH) {
720void* CommDriverN2KSerialThread::Entry() {
721 bool not_done =
true;
722 bool nl_found =
false;
729 if (!OpenComPortPhysical(m_PortName, m_baud)) {
730 wxString msg(
"NMEA input device open failed: ");
731 msg.Append(m_PortName);
733 std::lock_guard lock(m_stats_mutex);
734 m_driver_stats.available =
false;
743 std::lock_guard lock(m_stats_mutex);
744 m_driver_stats.available =
true;
745 SetGatewayOperationMode();
748 m_pParentDriver->SetSecThreadActive();
751 static size_t retries = 0;
754 bool bGotESC =
false;
755 bool bGotSOT =
false;
757 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
758 if (TestDestroy()) not_done =
false;
760 uint8_t next_byte = 0;
764 newdata = m_serial.
read(rdata, 1000);
765 }
catch (std::exception& e) {
767 std::lock_guard lock(m_stats_mutex);
770 if (10 < retries++) {
774 CloseComPortPhysical();
782 wxMilliSleep(250 * retries);
783 CloseComPortPhysical();
784 if (OpenComPortPhysical(m_PortName, m_baud)) {
785 SetGatewayOperationMode();
786 std::lock_guard lock(m_stats_mutex);
787 m_driver_stats.available =
true;
789 }
else if (retries < 10) {
790 std::lock_guard lock(m_stats_mutex);
791 m_driver_stats.available =
false;
797 std::lock_guard lock(m_stats_mutex);
800 for (
int i = 0; i < newdata; i++) {
801 circle.put(rdata[i]);
805 while (!circle.empty()) {
807 uint8_t next_byte = circle.get();
811 if (ESCAPE == next_byte) {
812 rx_buffer[ib++] = next_byte;
817 if (bGotESC && (ENDOFTEXT == next_byte)) {
821 auto buffer = std::make_shared<std::vector<unsigned char>>(
822 rx_buffer, rx_buffer + ib);
823 std::vector<unsigned char>* vec = buffer.get();
839 Nevent.SetPayload(buffer);
840 m_pParentDriver->AddPendingEvent(Nevent);
843 bGotESC = (next_byte == ESCAPE);
846 rx_buffer[ib++] = next_byte;
852 if (STARTOFTEXT == next_byte) {
858 bGotESC = (next_byte == ESCAPE);
863 rx_buffer[ib++] = next_byte;
871 bool b_qdata = !out_que.empty();
875 std::vector<unsigned char> qmsg = out_que.front();
878 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
883 CloseComPortPhysical();
886 b_qdata = !out_que.empty();
893 CloseComPortPhysical();
894 m_pParentDriver->SetSecThreadInActive();
895 m_pParentDriver->m_Thread_run_flag = -1;
897 std::lock_guard lock(m_stats_mutex);
898 m_driver_stats.available =
false;
904void* CommDriverN2KSerialThread::Entry() {
905 bool not_done =
true;
906 bool nl_found =
false;
911 if (!OpenComPortPhysical(m_PortName, m_baud)) {
912 wxString msg(
"NMEA input device open failed: ");
913 msg.Append(m_PortName);
915 std::lock_guard lock(m_stats_mutex);
916 m_driver_stats.available =
false;
924 SetGatewayOperationMode();
925 std::lock_guard lock(m_stats_mutex);
926 m_driver_stats.available =
true;
929 m_pParentDriver->SetSecThreadActive();
932 static size_t retries = 0;
935 bool bGotESC =
false;
936 bool bGotSOT =
false;
938 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
939 if (TestDestroy()) not_done =
false;
941 uint8_t next_byte = 0;
947 newdata = m_serial.
read(rdata, 200);
948 }
catch (std::exception& e) {
950 if (10 < retries++) {
954 CloseComPortPhysical();
962 wxMilliSleep(250 * retries);
963 CloseComPortPhysical();
964 if (OpenComPortPhysical(m_PortName, m_baud)) {
965 std::lock_guard lock(m_stats_mutex);
966 m_driver_stats.available =
true;
967 SetGatewayOperationMode();
969 }
else if (retries < 10)
974 for (
int i = 0; i < newdata; i++) {
975 circle.put(rdata[i]);
979 while (!circle.empty()) {
980 uint8_t next_byte = circle.get();
985 if (ESCAPE == next_byte) {
986 *put_ptr++ = next_byte;
990 }
else if (ENDOFTEXT == next_byte) {
994 auto buffer = std::make_shared<std::vector<unsigned char>>();
995 std::vector<unsigned char>* vec = buffer.get();
1000 while ((tptr != put_ptr)) {
1001 vec->push_back(*tptr++);
1014 Nevent.SetPayload(buffer);
1015 m_pParentDriver->AddPendingEvent(Nevent);
1016 std::lock_guard lock(m_stats_mutex);
1017 m_driver_stats.
rx_count += vec->size();
1018 }
else if (next_byte == STARTOFTEXT) {
1019 put_ptr = rx_buffer;
1022 put_ptr = rx_buffer;
1028 bGotESC = (next_byte == ESCAPE);
1031 *put_ptr++ = next_byte;
1033 put_ptr = rx_buffer;
1039 if (STARTOFTEXT == next_byte) {
1045 bGotESC = (next_byte == ESCAPE);
1050 *put_ptr++ = next_byte;
1052 put_ptr = rx_buffer;
1060 bool b_qdata = !out_que.empty();
1064 std::vector<unsigned char> qmsg = out_que.front();
1067 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
1072 CloseComPortPhysical();
1074 std::lock_guard lock(m_stats_mutex);
1075 m_driver_stats.
tx_count += qmsg.size();
1077 b_qdata = !out_que.empty();
1082 CloseComPortPhysical();
1083 m_pParentDriver->SetSecThreadInActive();
1084 m_pParentDriver->m_Thread_run_flag = -1;
1097#define MaxActisenseMsgBuf 400
1098#define MsgTypeN2kTX 0x94
1100void AddByteEscapedToBuf(
unsigned char byteToAdd, uint8_t& idx,
1101 unsigned char* buf,
int& byteSum);
1103static std::vector<unsigned char> BufferToActisenseFormat(tN2kMsg& msg) {
1104 unsigned long _PGN = msg.PGN;
1108 unsigned char ActisenseMsgBuf[MaxActisenseMsgBuf];
1110 ActisenseMsgBuf[msgIdx++] = ESCAPE;
1111 ActisenseMsgBuf[msgIdx++] = STARTOFTEXT;
1112 AddByteEscapedToBuf(MsgTypeN2kTX, msgIdx, ActisenseMsgBuf, byteSum);
1113 AddByteEscapedToBuf(msg.DataLen + 6, msgIdx, ActisenseMsgBuf,
1116 AddByteEscapedToBuf(msg.Priority, msgIdx, ActisenseMsgBuf, byteSum);
1117 AddByteEscapedToBuf(_PGN & 0xff, msgIdx, ActisenseMsgBuf, byteSum);
1119 AddByteEscapedToBuf(_PGN & 0xff, msgIdx, ActisenseMsgBuf, byteSum);
1121 AddByteEscapedToBuf(_PGN & 0xff, msgIdx, ActisenseMsgBuf, byteSum);
1122 AddByteEscapedToBuf(msg.Destination, msgIdx, ActisenseMsgBuf, byteSum);
1127 AddByteEscapedToBuf(msg.Source,msgIdx,ActisenseMsgBuf,byteSum);
1130 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1131 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1132 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1133 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum);
1137 AddByteEscapedToBuf(msg.DataLen, msgIdx, ActisenseMsgBuf, byteSum);
1139 for (
int i = 0; i < msg.DataLen; i++)
1140 AddByteEscapedToBuf(msg.Data[i], msgIdx, ActisenseMsgBuf, byteSum);
1143 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
1144 ActisenseMsgBuf[msgIdx++] = CheckSum;
1145 if (CheckSum == ESCAPE) ActisenseMsgBuf[msgIdx++] = CheckSum;
1147 ActisenseMsgBuf[msgIdx++] = ESCAPE;
1148 ActisenseMsgBuf[msgIdx++] = ENDOFTEXT;
1150 std::vector<unsigned char> rv;
1151 for (
unsigned int i = 0; i < msgIdx; i++) rv.push_back(ActisenseMsgBuf[i]);
DriverStats GetDriverStats() const override
Get the Driver Statistics.
Interface for handling incoming messages.
virtual void Notify(std::shared_ptr< const NavMsg > message)=0
Handle a received message.
Class that provides a portable serial port interface.
size_t read(uint8_t *buffer, size_t size)
Read a given amount of bytes from the serial port into a given buffer.
void setPort(const std::string &port)
Sets the serial port identifier.
size_t write(const uint8_t *data, size_t size)
Write a string to the serial port.
void setBaudrate(uint32_t baudrate)
Sets the baudrate for the serial port.
void close()
Closes the serial port.
void setTimeout(Timeout &timeout)
Sets the timeout for reads and writes using the Timeout struct.
void flushOutput()
Flush only the output buffer.
void open()
Opens the serial port as long as the port is set and the port isn't already open.
bool isOpen() const
Gets the open status of the serial port.
#define DS_RX_BUFFER_SIZE
This thread manages reading the N2K data stream provided by some N2K gateways from the declared seria...
Driver registration container, a singleton.
Communication statistics infrastructure.
Raw messages layer, supports sending and recieving navmsg messages.
std::string DsPortTypeToString(dsPortType type)
Return textual representation for use in driver ioDirection attribute.
Enhanced logging interface on top of wx/log.h.
Driver statistics report.
unsigned tx_count
Number of bytes sent since program start.
unsigned rx_count
Number of bytes received since program start.
unsigned error_count
Number of detected errors since program start.