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;
326 if (!msg)
return false;
330 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
331 std::vector<uint8_t> load = msg_n2k->payload;
333 uint64_t _pgn = msg_n2k->PGN.pgn;
334 auto destination_address = std::static_pointer_cast<const NavAddr2000>(addr);
338 N2kMsg.Priority = msg_n2k->priority;
339 if (destination_address) N2kMsg.Destination = destination_address->address;
341 for (
size_t i = 0; i < load.size(); i++) N2kMsg.AddByte(load.at(i));
343 const std::vector<uint8_t> acti_pkg = BufferToActisenseFormat(N2kMsg);
346 std::vector<unsigned char> msg_payload;
347 for (
size_t i = 2; i < acti_pkg.size() - 2; i++)
348 msg_payload.push_back(acti_pkg[i]);
349 auto name = PayloadToName(load);
351 std::make_shared<const Nmea2000Msg>(_pgn, msg_payload, GetAddress(name)));
353 if (GetSecondaryThread()) {
354 if (IsSecThreadActive()) {
357 if (GetSecondaryThread()->SetOutMsg(acti_pkg))
370void CommDriverN2KSerial::ProcessManagementPacket(
371 std::vector<unsigned char>* payload) {
372 if (payload->at(2) != 0xF2) {
379 switch (payload->at(2)) {
391 if (payload->at(3) == 0x02) {
392 std::string device_common_name;
393 for (
unsigned int i = 0; i < 32; i++) {
394 device_common_name += payload->at(i + 14);
396 device_common_name +=
'\0';
397 m_device_common_name = device_common_name;
403 unsigned char name[8];
404 for (
unsigned int i = 0; i < 8; i++) name[i] = payload->at(i + 15);
406 memcpy((
void*)&NAME, name, 8);
408 int* f1 = (
int*)&NAME;
410 m_manufacturers_code = f1d >> 21;
419void CommDriverN2KSerial::handle_N2K_SERIAL_RAW(
421 auto p =
event.GetPayload();
423 std::vector<unsigned char>* payload = p.get();
425 if (payload->at(0) == 0xA0) {
426 ProcessManagementPacket(payload);
431 if (m_params.IOSelect != DS_TYPE_OUTPUT) {
434 unsigned char* c = (
unsigned char*)&pgn;
435 *c++ = payload->at(3);
436 *c++ = payload->at(4);
437 *c++ = payload->at(5);
439 auto name = PayloadToName(*payload);
441 std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
443 m_listener.
Notify(std::move(msg));
447int CommDriverN2KSerial::GetMfgCode() {
448 unsigned char request_name[] = {0x42};
449 int ni = SendMgmtMsg(request_name,
sizeof(request_name), 0x41, 2000,
452 m_got_mfg_code =
true;
456int CommDriverN2KSerial::SendMgmtMsg(
unsigned char*
string,
size_t string_size,
457 unsigned char cmd_code,
int timeout_msec,
458 bool* response_flag) {
463 std::vector<unsigned char> msg;
465 msg.push_back(ESCAPE);
466 msg.push_back(STARTOFTEXT);
469 msg.push_back(string_size);
470 byteSum += string_size;
472 for (
unsigned int i = 0; i < string_size; i++) {
473 if (
string[i] == ESCAPE) msg.push_back(
string[i]);
474 msg.push_back(
string[i]);
475 byteSum +=
string[i];
480 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
481 msg.push_back(CheckSum);
483 msg.push_back(ESCAPE);
484 msg.push_back(ENDOFTEXT);
488 if (response_flag) *response_flag =
false;
492 bool not_done =
true;
495 if (GetSecondaryThread() && IsSecThreadActive()) {
498 if (GetSecondaryThread()->SetOutMsg(msg)) {
507 if (ntry_outer-- <= 0) not_done =
false;
511 if (!bsent)
return 1;
515 int timeout = timeout_msec;
516 while (timeout > 0) {
520 if (*response_flag) {
540int CommDriverN2KSerial::SetTXPGN(
int pgn) {
542 unsigned char request_enable[] = {0x47, 0x00, 0x00, 0x00,
543 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF};
546 unsigned char* c = (
unsigned char*)&pgn;
547 request_enable[1] = c[0];
548 request_enable[2] = c[1];
549 request_enable[3] = c[2];
551 int aa = SendMgmtMsg(request_enable,
sizeof(request_enable), 0x47, 2000,
556 unsigned char request_commit[] = {0x01};
557 int bb = SendMgmtMsg(request_commit,
sizeof(request_commit), 0x01, 2000,
561 unsigned char request_activate[] = {0x4B};
562 int cc = SendMgmtMsg(request_activate,
sizeof(request_activate), 0x4B, 2000,
567void CommDriverN2KSerial::AddTxPGN(
int pgn) {
568 auto it = std::find(pgn_tx_list.begin(), pgn_tx_list.end(), pgn);
569 if (it != pgn_tx_list.end())
573 pgn_tx_list.push_back(pgn);
605#define DS_RX_BUFFER_SIZE 4096
607CommDriverN2KSerialThread::CommDriverN2KSerialThread(
609 const wxString& strBaudRate) {
610 m_pParentDriver = Launcher;
612 m_PortName = PortName;
613 m_FullPortName =
"Serial:" + PortName;
622 if (strBaudRate.ToLong(&lbaud)) m_baud = (int)lbaud;
624 std::lock_guard lock(m_stats_mutex);
625 m_driver_stats.driver_bus = NavAddr::Bus::N2000;
626 m_driver_stats.driver_iface = m_pParentDriver->m_params.GetStrippedDSPort();
627 m_driver_stats.available =
false;
633CommDriverN2KSerialThread::~CommDriverN2KSerialThread() {
delete[] rx_buffer; }
635void CommDriverN2KSerialThread::OnExit() {}
637DriverStats CommDriverN2KSerialThread::GetStats()
const {
638 std::lock_guard lock(m_stats_mutex);
639 return m_driver_stats;
642bool CommDriverN2KSerialThread::OpenComPortPhysical(
const wxString& com_name,
645 m_serial.
setPort(com_name.ToStdString());
649 }
catch (std::exception&) {
656void CommDriverN2KSerialThread::CloseComPortPhysical() {
659 }
catch (std::exception&) {
663 std::lock_guard lock(m_stats_mutex);
664 m_driver_stats.available =
false;
667void CommDriverN2KSerialThread::SetGatewayOperationMode() {
671 unsigned char config_string[] = {0x10, 0x02, 0xA1, 0x03, 0x11,
672 0x02, 0x00, 0x49, 0x10, 0x03};
676 WriteComPortPhysical(config_string, 10);
679void CommDriverN2KSerialThread::ThreadMessage(
const wxString& msg) {
686size_t CommDriverN2KSerialThread::WriteComPortPhysical(
687 std::vector<unsigned char> msg) {
688 return WriteComPortPhysical(msg.data(), msg.size());
691size_t CommDriverN2KSerialThread::WriteComPortPhysical(
unsigned char* msg,
693 if (!m_serial.
isOpen())
return 0;
695 size_t status = m_serial.
write((uint8_t*)msg, length);
698 }
catch (std::exception& e) {
699 DEBUG_LOG <<
"Unhandled Exception while writing to serial port: "
705bool CommDriverN2KSerialThread::SetOutMsg(
706 const std::vector<unsigned char>& msg) {
707 if (out_que.size() < OUT_QUEUE_LENGTH) {
715void* CommDriverN2KSerialThread::Entry() {
716 bool not_done =
true;
717 bool nl_found =
false;
724 if (!OpenComPortPhysical(m_PortName, m_baud)) {
725 wxString msg(
"NMEA input device open failed: ");
726 msg.Append(m_PortName);
728 std::lock_guard lock(m_stats_mutex);
729 m_driver_stats.available =
false;
738 std::lock_guard lock(m_stats_mutex);
739 m_driver_stats.available =
true;
740 SetGatewayOperationMode();
743 m_pParentDriver->SetSecThreadActive();
746 static size_t retries = 0;
749 bool bGotESC =
false;
750 bool bGotSOT =
false;
752 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
753 if (TestDestroy()) not_done =
false;
755 uint8_t next_byte = 0;
759 newdata = m_serial.
read(rdata, 1000);
760 }
catch (std::exception& e) {
762 std::lock_guard lock(m_stats_mutex);
765 if (10 < retries++) {
769 CloseComPortPhysical();
777 wxMilliSleep(250 * retries);
778 CloseComPortPhysical();
779 if (OpenComPortPhysical(m_PortName, m_baud)) {
780 SetGatewayOperationMode();
781 std::lock_guard lock(m_stats_mutex);
782 m_driver_stats.available =
true;
784 }
else if (retries < 10) {
785 std::lock_guard lock(m_stats_mutex);
786 m_driver_stats.available =
false;
792 std::lock_guard lock(m_stats_mutex);
795 for (
int i = 0; i < newdata; i++) {
796 circle.put(rdata[i]);
800 while (!circle.empty()) {
802 uint8_t next_byte = circle.get();
806 if (ESCAPE == next_byte) {
807 rx_buffer[ib++] = next_byte;
812 if (bGotESC && (ENDOFTEXT == next_byte)) {
816 auto buffer = std::make_shared<std::vector<unsigned char>>(
817 rx_buffer, rx_buffer + ib);
818 std::vector<unsigned char>* vec = buffer.get();
834 Nevent.SetPayload(buffer);
835 m_pParentDriver->AddPendingEvent(Nevent);
838 bGotESC = (next_byte == ESCAPE);
841 rx_buffer[ib++] = next_byte;
847 if (STARTOFTEXT == next_byte) {
853 bGotESC = (next_byte == ESCAPE);
858 rx_buffer[ib++] = next_byte;
866 bool b_qdata = !out_que.empty();
870 std::vector<unsigned char> qmsg = out_que.front();
873 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
878 CloseComPortPhysical();
881 b_qdata = !out_que.empty();
888 CloseComPortPhysical();
889 m_pParentDriver->SetSecThreadInActive();
890 m_pParentDriver->m_Thread_run_flag = -1;
892 std::lock_guard lock(m_stats_mutex);
893 m_driver_stats.available =
false;
899void* CommDriverN2KSerialThread::Entry() {
900 bool not_done =
true;
901 bool nl_found =
false;
906 if (!OpenComPortPhysical(m_PortName, m_baud)) {
907 wxString msg(
"NMEA input device open failed: ");
908 msg.Append(m_PortName);
910 std::lock_guard lock(m_stats_mutex);
911 m_driver_stats.available =
false;
919 SetGatewayOperationMode();
920 std::lock_guard lock(m_stats_mutex);
921 m_driver_stats.available =
true;
924 m_pParentDriver->SetSecThreadActive();
927 static size_t retries = 0;
930 bool bGotESC =
false;
931 bool bGotSOT =
false;
933 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
934 if (TestDestroy()) not_done =
false;
936 uint8_t next_byte = 0;
942 newdata = m_serial.
read(rdata, 200);
943 }
catch (std::exception& e) {
945 if (10 < retries++) {
949 CloseComPortPhysical();
957 wxMilliSleep(250 * retries);
958 CloseComPortPhysical();
959 if (OpenComPortPhysical(m_PortName, m_baud)) {
960 std::lock_guard lock(m_stats_mutex);
961 m_driver_stats.available =
true;
962 SetGatewayOperationMode();
964 }
else if (retries < 10)
969 for (
int i = 0; i < newdata; i++) {
970 circle.put(rdata[i]);
974 while (!circle.empty()) {
975 uint8_t next_byte = circle.get();
980 if (ESCAPE == next_byte) {
981 *put_ptr++ = next_byte;
985 }
else if (ENDOFTEXT == next_byte) {
989 auto buffer = std::make_shared<std::vector<unsigned char>>();
990 std::vector<unsigned char>* vec = buffer.get();
995 while ((tptr != put_ptr)) {
996 vec->push_back(*tptr++);
1009 Nevent.SetPayload(buffer);
1010 m_pParentDriver->AddPendingEvent(Nevent);
1011 std::lock_guard lock(m_stats_mutex);
1012 m_driver_stats.
rx_count += vec->size();
1013 }
else if (next_byte == STARTOFTEXT) {
1014 put_ptr = rx_buffer;
1017 put_ptr = rx_buffer;
1023 bGotESC = (next_byte == ESCAPE);
1026 *put_ptr++ = next_byte;
1028 put_ptr = rx_buffer;
1034 if (STARTOFTEXT == next_byte) {
1040 bGotESC = (next_byte == ESCAPE);
1045 *put_ptr++ = next_byte;
1047 put_ptr = rx_buffer;
1055 bool b_qdata = !out_que.empty();
1059 std::vector<unsigned char> qmsg = out_que.front();
1062 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
1067 CloseComPortPhysical();
1069 std::lock_guard lock(m_stats_mutex);
1070 m_driver_stats.
tx_count += qmsg.size();
1072 b_qdata = !out_que.empty();
1077 CloseComPortPhysical();
1078 m_pParentDriver->SetSecThreadInActive();
1079 m_pParentDriver->m_Thread_run_flag = -1;
1092#define MaxActisenseMsgBuf 400
1093#define MsgTypeN2kTX 0x94
1095void AddByteEscapedToBuf(
unsigned char byteToAdd, uint8_t& idx,
1096 unsigned char* buf,
int& byteSum);
1098static std::vector<unsigned char> BufferToActisenseFormat(tN2kMsg& msg) {
1099 unsigned long _PGN = msg.PGN;
1103 unsigned char ActisenseMsgBuf[MaxActisenseMsgBuf];
1105 ActisenseMsgBuf[msgIdx++] = ESCAPE;
1106 ActisenseMsgBuf[msgIdx++] = STARTOFTEXT;
1107 AddByteEscapedToBuf(MsgTypeN2kTX, msgIdx, ActisenseMsgBuf, byteSum);
1108 AddByteEscapedToBuf(msg.DataLen + 6, msgIdx, ActisenseMsgBuf,
1111 AddByteEscapedToBuf(msg.Priority, msgIdx, ActisenseMsgBuf, byteSum);
1112 AddByteEscapedToBuf(_PGN & 0xff, msgIdx, ActisenseMsgBuf, byteSum);
1114 AddByteEscapedToBuf(_PGN & 0xff, msgIdx, ActisenseMsgBuf, byteSum);
1116 AddByteEscapedToBuf(_PGN & 0xff, msgIdx, ActisenseMsgBuf, byteSum);
1117 AddByteEscapedToBuf(msg.Destination, msgIdx, ActisenseMsgBuf, byteSum);
1122 AddByteEscapedToBuf(msg.Source,msgIdx,ActisenseMsgBuf,byteSum);
1125 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1126 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1127 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1128 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum);
1132 AddByteEscapedToBuf(msg.DataLen, msgIdx, ActisenseMsgBuf, byteSum);
1134 for (
int i = 0; i < msg.DataLen; i++)
1135 AddByteEscapedToBuf(msg.Data[i], msgIdx, ActisenseMsgBuf, byteSum);
1138 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
1139 ActisenseMsgBuf[msgIdx++] = CheckSum;
1140 if (CheckSum == ESCAPE) ActisenseMsgBuf[msgIdx++] = CheckSum;
1142 ActisenseMsgBuf[msgIdx++] = ESCAPE;
1143 ActisenseMsgBuf[msgIdx++] = ENDOFTEXT;
1145 std::vector<unsigned char> rv;
1146 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.