39#include "comm_drv_n2k_serial.h"
40#include "comm_navmsg_bus.h"
41#include "comm_drv_registry.h"
44std::vector<unsigned char> BufferToActisenseFormat( tN2kMsg &msg);
50 std::lock_guard<std::mutex> lock(m_mutex);
51 return m_queque.size();
55 std::lock_guard<std::mutex> lock(m_mutex);
56 return m_queque.empty();
60 std::lock_guard<std::mutex> lock(m_mutex);
61 return m_queque.front();
64 void push(
const T& value) {
65 std::lock_guard<std::mutex> lock(m_mutex);
70 std::lock_guard<std::mutex> lock(m_mutex);
75 std::queue<T> m_queque;
76 mutable std::mutex m_mutex;
83 : buf_(std::unique_ptr<T[]>(new T[size])), max_size_(size) {}
86 size_t capacity()
const;
91 return (!full_ && (head_ == tail_));
100 std::lock_guard<std::mutex> lock(mutex_);
102 if (full_) tail_ = (tail_ + 1) % max_size_;
104 head_ = (head_ + 1) % max_size_;
106 full_ = head_ == tail_;
110 std::lock_guard<std::mutex> lock(mutex_);
112 if (empty())
return T();
115 auto val = buf_[tail_];
117 tail_ = (tail_ + 1) % max_size_;
124 std::unique_ptr<T[]> buf_;
127 const size_t max_size_;
138 const wxString& PortName,
139 const wxString& strBaudRate);
143 bool SetOutMsg(
const std::vector<unsigned char> &load);
148 serial::Serial m_serial;
150 void ThreadMessage(
const wxString& msg);
151 bool OpenComPortPhysical(
const wxString& com_name,
int baud_rate);
152 void CloseComPortPhysical();
153 size_t WriteComPortPhysical(std::vector<unsigned char> msg);
154 size_t WriteComPortPhysical(
unsigned char *msg,
size_t length);
155 void SetGatewayOperationMode(
void);
159 wxString m_FullPortName;
161 unsigned char* put_ptr;
162 unsigned char* tak_ptr;
164 unsigned char* rx_buffer;
172 HANDLE m_hSerialComm;
184 : wxEvent(
id, commandType){};
188 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
191 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
194 wxEvent* Clone()
const {
196 newevent->m_payload = this->m_payload;
201 std::shared_ptr<std::vector<unsigned char>> m_payload;
213 m_Thread_run_flag(-1),
215 m_portstring(params->GetDSPort()),
216 m_pSecondary_Thread(NULL),
218 m_listener(listener) {
219 m_BaudRate = wxString::Format(
"%i", params->Baudrate), SetSecThreadInActive();
220 m_manufacturers_code = 0;
221 m_got_mfg_code =
false;
224 Bind(wxEVT_COMMDRIVER_N2K_SERIAL, &CommDriverN2KSerial::handle_N2K_SERIAL_RAW,
236 N2kMsg.SetPGN(126993L);
239 N2kMsg.Add2ByteUInt((uint16_t)(2000));
242 N2kMsg.AddByte(0xff);
243 N2kMsg.Add4ByteUInt(0xffffffff);
245 const std::vector<unsigned char> mv = BufferToActisenseFormat(N2kMsg);
247 size_t len = mv.size();
249 wxString comx = m_params.GetDSPort().AfterFirst(
':');
250 std::string
interface = comx.ToStdString();
253 auto source_address = std::make_shared<NavAddr2000>(interface, source_name);
254 auto dest_address = std::make_shared<NavAddr2000>(interface, N2kMsg.Destination);
256 auto message_to_send = std::make_shared<Nmea2000Msg>(source_name, mv, source_address);
258 for(
size_t i=0; i< mv.size(); i++){
259 printf(
"%02X ", mv.at(i));
271CommDriverN2KSerial::~CommDriverN2KSerial() {
275bool CommDriverN2KSerial::Open() {
277 comx = m_params.GetDSPort().AfterFirst(
':');
280 comx.BeforeFirst(
' ');
285 GetSecondaryThread()->Run();
290void CommDriverN2KSerial::Close() {
292 wxString::Format(_T(
"Closing N2K Driver %s"), m_portstring.c_str()));
295 if (m_pSecondary_Thread) {
296 if (m_bsec_thread_active)
298 wxLogMessage(_T(
"Stopping Secondary Thread"));
300 m_Thread_run_flag = 0;
302 while ((m_Thread_run_flag >= 0) && (tsec--)) wxSleep(1);
305 if (m_Thread_run_flag < 0)
306 msg.Printf(_T(
"Stopped in %d sec."), 10 - tsec);
308 msg.Printf(_T(
"Not Stopped after 10 sec."));
312 m_pSecondary_Thread = NULL;
313 m_bsec_thread_active =
false;
318 CommDriverRegistry::GetInstance().
Activate(shared_from_this());
322bool CommDriverN2KSerial::SendMessage(std::shared_ptr<const NavMsg> msg,
323 std::shared_ptr<const NavAddr> addr) {
325 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
326 std::vector<uint8_t> load = msg_n2k->payload;
328 uint64_t _pgn = msg_n2k->PGN.pgn;
334 for (
size_t i=0 ; i < load.size(); i++)
335 N2kMsg.AddByte(load.at(i));
337 const std::vector<uint8_t> mv = BufferToActisenseFormat(N2kMsg);
344 if( GetSecondaryThread() ) {
345 if( IsSecThreadActive() )
349 if( GetSecondaryThread()->SetOutMsg( mv ))
362void CommDriverN2KSerial::ProcessManagementPacket(std::vector<unsigned char> *payload) {
364 if (payload->at(2) != 0xF2) {
366 for (
unsigned int i = 0; i < payload->size(); i++)
367 printf(
"%02X ", payload->at(i));
371 switch (payload->at(2)){
383 if (payload->at(3) == 0x02) {
384 std::string device_common_name;
385 for (
unsigned int i = 0; i < 32; i++) {
386 device_common_name += payload->at(i + 14);
388 device_common_name +=
'\0';
389 m_device_common_name = device_common_name;
395 unsigned char name[8];
396 for (
unsigned int i = 0; i < 8; i++)
397 name[i] = payload->at(i + 15);
399 memcpy( (
void *)&NAME, name, 8);
401 int *f1 = (
int *)&NAME;
403 m_manufacturers_code = f1d >> 21;
414static uint64_t PayloadToName(
const std::vector<unsigned char> payload) {
416 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
421void CommDriverN2KSerial::handle_N2K_SERIAL_RAW(
423 auto p =
event.GetPayload();
425 std::vector<unsigned char>* payload = p.get();
427 if (payload->at(0) == 0xA0) {
428 ProcessManagementPacket(payload);
434 unsigned char* c = (
unsigned char*)&pgn;
435 *c++ = payload->at(3);
436 *c++ = payload->at(4);
437 *c++ = payload->at(5);
441 auto name = PayloadToName(*payload);
442 auto msg = std::make_unique<const Nmea2000Msg>(pgn, *payload,
444 m_listener.
Notify(std::move(msg));
447 size_t packetLength = (size_t)payload->at(1);
448 size_t vector_length = payload->size();
453 printf(
"Payload Length: %ld\n", vector_length);
455 printf(
"PGN: %ld\n", pgn);
457 for(
size_t i=0; i< vector_length ; i++){
458 printf(
"%02X ", payload->at(i));
465int CommDriverN2KSerial::SendMgmtMsg(
unsigned char *
string,
size_t string_size,
466 unsigned char cmd_code,
467 int timeout_msec,
bool *response_flag) {
471 std::vector <unsigned char> msg;
473 msg.push_back(ESCAPE);
474 msg.push_back(STARTOFTEXT);
477 msg.push_back(string_size);
478 byteSum += string_size;
480 for (
unsigned int i=0; i < string_size; i++){
481 if (
string[i] == ESCAPE)
482 msg.push_back(
string[i]);
483 msg.push_back(
string[i]);
484 byteSum +=
string[i];
489 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
490 msg.push_back(CheckSum);
492 msg.push_back(ESCAPE);
493 msg.push_back(ENDOFTEXT);
497 *response_flag =
false;
500 if( GetSecondaryThread() ) {
501 if( IsSecThreadActive() ) {
504 if( GetSecondaryThread()->SetOutMsg( msg )){
517 int timeout = timeout_msec;
519 while (timeout > 0) {
539int CommDriverN2KSerial::SetTXPGN(
int pgn) {
546 if (m_got_mfg_code) {
547 if (m_manufacturers_code != 273)
551 unsigned char request_name[] = { 0x42};
552 int ni = SendMgmtMsg( request_name,
sizeof(request_name), 0x41, 2000, &m_bmg42_resp);
555 m_got_mfg_code =
true;
556 if (m_manufacturers_code != 273)
561 unsigned char request_enable[] = { 0x47,
564 0xFF, 0xFF, 0xFF, 0xFF};
567 unsigned char* c = (
unsigned char*)&pgn;
568 request_enable[1] = c[0];
569 request_enable[2] = c[1];
570 request_enable[3] = c[2];
572 int aa = SendMgmtMsg( request_enable,
sizeof(request_enable), 0x47, 2000, &m_bmg47_resp);
577 unsigned char request_commit[] = { 0x01 };
578 int bb = SendMgmtMsg( request_commit,
sizeof(request_commit), 0x01, 2000, &m_bmg01_resp);
584 unsigned char request_activate[] = { 0x4B };
585 int cc = SendMgmtMsg( request_activate,
sizeof(request_activate), 0x4B, 2000, &m_bmg4B_resp);
622#define DS_RX_BUFFER_SIZE 4096
624CommDriverN2KSerialThread::CommDriverN2KSerialThread(
626 const wxString& strBaudRate) {
627 m_pParentDriver = Launcher;
629 m_PortName = PortName;
630 m_FullPortName = _T(
"Serial:") + PortName;
632 rx_buffer =
new unsigned char[DS_RX_BUFFER_SIZE + 1];
639 if (strBaudRate.ToLong(&lbaud)) m_baud = (int)lbaud;
644CommDriverN2KSerialThread::~CommDriverN2KSerialThread(
void) {
648void CommDriverN2KSerialThread::OnExit(
void) {}
650bool CommDriverN2KSerialThread::OpenComPortPhysical(
const wxString& com_name,
653 m_serial.setPort(com_name.ToStdString());
654 m_serial.setBaudrate(baud_rate);
656 m_serial.setTimeout(250, 250, 0, 250, 0);
657 }
catch (std::exception& e) {
661 return m_serial.isOpen();
664void CommDriverN2KSerialThread::CloseComPortPhysical() {
667 }
catch (std::exception& e) {
673void CommDriverN2KSerialThread::SetGatewayOperationMode(
void) {
678 unsigned char config_string[] = { 0x10, 0x02, 0xA1, 0x03, 0x11,
679 0x02, 0x00, 0x49, 0x10, 0x03};
682 WriteComPortPhysical(config_string, 10);
687void CommDriverN2KSerialThread::ThreadMessage(
const wxString& msg) {
694size_t CommDriverN2KSerialThread::WriteComPortPhysical(std::vector<unsigned char> msg) {
695 if (m_serial.isOpen()) {
699 for (
size_t i = 0; i < msg.size(); i++)
700 printf(
"%02X ", msg.at(i));
703 status = m_serial.write((uint8_t*)msg.data(), msg.size());
704 }
catch (std::exception& e) {
705 std::cerr <<
"Unhandled Exception while writing to serial port: " <<
706 e.what() << std::endl;
715size_t CommDriverN2KSerialThread::WriteComPortPhysical(
unsigned char *msg,
size_t length) {
716 if (m_serial.isOpen()) {
719 status = m_serial.write((uint8_t*)msg, length);
720 }
catch (std::exception& e) {
731bool CommDriverN2KSerialThread::SetOutMsg(
const std::vector<unsigned char> &msg)
733 if(out_que.size() < OUT_QUEUE_LENGTH){
741void* CommDriverN2KSerialThread::Entry() {
742 bool not_done =
true;
743 bool nl_found =
false;
750 if (!OpenComPortPhysical(m_PortName, m_baud)) {
751 wxString msg(_T(
"NMEA input device open failed: "));
752 msg.Append(m_PortName);
762 SetGatewayOperationMode();
766 m_pParentDriver->SetSecThreadActive();
769 static size_t retries = 0;
772 bool bGotESC =
false;
773 bool bGotSOT =
false;
775 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
776 if (TestDestroy()) not_done =
false;
778 uint8_t next_byte = 0;
780 if (m_serial.isOpen()) {
782 newdata = m_serial.read(rdata, 1000);
783 }
catch (std::exception& e) {
785 if (10 < retries++) {
789 CloseComPortPhysical();
797 wxMilliSleep(250 * retries);
798 CloseComPortPhysical();
799 if (OpenComPortPhysical(m_PortName, m_baud)){
800 SetGatewayOperationMode();
803 else if (retries < 10)
808 for (
int i = 0; i < newdata; i++) {
809 circle.put(rdata[i]);
813 while (!circle.empty()) {
814 if (ib >= DS_RX_BUFFER_SIZE)
816 uint8_t next_byte = circle.get();
820 if (ESCAPE == next_byte) {
821 rx_buffer[ib++] = next_byte;
826 if (bGotESC && (ENDOFTEXT == next_byte)) {
830 auto buffer = std::make_shared<std::vector<unsigned char>>(rx_buffer, rx_buffer + ib);
831 std::vector<unsigned char>* vec = buffer.get();
847 Nevent.SetPayload(buffer);
848 m_pParentDriver->AddPendingEvent(Nevent);
852 bGotESC = (next_byte == ESCAPE);
855 rx_buffer[ib++] = next_byte;
861 if (STARTOFTEXT == next_byte) {
867 bGotESC = (next_byte == ESCAPE);
872 rx_buffer[ib++] = next_byte;
880 bool b_qdata = !out_que.empty();
884 std::vector<unsigned char> qmsg = out_que.front();
887 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
892 CloseComPortPhysical();
895 b_qdata = !out_que.empty();
902 CloseComPortPhysical();
903 m_pParentDriver->SetSecThreadInActive();
904 m_pParentDriver->m_Thread_run_flag = -1;
910void* CommDriverN2KSerialThread::Entry() {
911 bool not_done =
true;
912 bool nl_found =
false;
917 if (!OpenComPortPhysical(m_PortName, m_baud)) {
918 wxString msg(_T(
"NMEA input device open failed: "));
919 msg.Append(m_PortName);
928 SetGatewayOperationMode();
931 m_pParentDriver->SetSecThreadActive();
934 static size_t retries = 0;
937 bool bGotESC =
false;
938 bool bGotSOT =
false;
940 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
941 if (TestDestroy()) not_done =
false;
943 uint8_t next_byte = 0;
947 if (m_serial.isOpen()) {
949 newdata = m_serial.read(rdata, 200);
950 }
catch (std::exception& e) {
952 if (10 < retries++) {
956 CloseComPortPhysical();
964 wxMilliSleep(250 * retries);
965 CloseComPortPhysical();
966 if (OpenComPortPhysical(m_PortName, m_baud)){
967 SetGatewayOperationMode();
970 else if (retries < 10)
975 for (
int i = 0; i < newdata; i++) {
976 circle.put(rdata[i]);
980 while (!circle.empty()) {
981 uint8_t next_byte = circle.get();
986 if (ESCAPE == next_byte) {
987 *put_ptr++ = next_byte;
988 if ((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE)
994 if (bGotESC && (ENDOFTEXT == next_byte)) {
998 auto buffer = std::make_shared<std::vector<unsigned char>>();
999 std::vector<unsigned char>* vec = buffer.get();
1001 unsigned char* tptr;
1004 while ((tptr != put_ptr)) {
1005 vec->push_back(*tptr++);
1006 if ((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer;
1018 Nevent.SetPayload(buffer);
1019 m_pParentDriver->AddPendingEvent(Nevent);
1022 bGotESC = (next_byte == ESCAPE);
1025 *put_ptr++ = next_byte;
1026 if ((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE)
1027 put_ptr = rx_buffer;
1033 if (STARTOFTEXT == next_byte) {
1039 bGotESC = (next_byte == ESCAPE);
1044 *put_ptr++ = next_byte;
1045 if ((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE)
1046 put_ptr = rx_buffer;
1055 bool b_qdata = !out_que.empty();
1059 char *qmsg = out_que.front();
1062 char msg[MAX_OUT_QUEUE_MESSAGE_LENGTH];
1063 strncpy(msg, qmsg, MAX_OUT_QUEUE_MESSAGE_LENGTH - 1);
1066 if (
static_cast<size_t>(-1) == WriteComPortPhysical(msg) &&
1071 CloseComPortPhysical();
1074 b_qdata = !out_que.empty();
1081 CloseComPortPhysical();
1082 m_pParentDriver->SetSecThreadInActive();
1083 m_pParentDriver->m_Thread_run_flag = -1;
1096#define MaxActisenseMsgBuf 400
1097#define MsgTypeN2kTX 0x94
1099void AddByteEscapedToBuf(
unsigned char byteToAdd, uint8_t &idx,
unsigned char *buf,
int &byteSum);
1101std::vector<unsigned char> BufferToActisenseFormat( tN2kMsg &msg){
1102 unsigned long _PGN=msg.PGN;
1106 unsigned char ActisenseMsgBuf[MaxActisenseMsgBuf];
1109 ActisenseMsgBuf[msgIdx++]=ESCAPE;
1110 ActisenseMsgBuf[msgIdx++]=STARTOFTEXT;
1111 AddByteEscapedToBuf(MsgTypeN2kTX,msgIdx,ActisenseMsgBuf,byteSum);
1112 AddByteEscapedToBuf(msg.DataLen+6,msgIdx,ActisenseMsgBuf,byteSum);
1113 AddByteEscapedToBuf(msg.Priority,msgIdx,ActisenseMsgBuf,byteSum);
1114 AddByteEscapedToBuf(_PGN & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _PGN>>=8;
1115 AddByteEscapedToBuf(_PGN & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _PGN>>=8;
1116 AddByteEscapedToBuf(_PGN & 0xff,msgIdx,ActisenseMsgBuf,byteSum);
1117 AddByteEscapedToBuf(msg.Destination,msgIdx,ActisenseMsgBuf,byteSum);
1128 AddByteEscapedToBuf(msg.DataLen,msgIdx,ActisenseMsgBuf,byteSum);
1131 for (
int i = 0; i < msg.DataLen; i++)
1132 AddByteEscapedToBuf(msg.Data[i],msgIdx,ActisenseMsgBuf,byteSum);
1135 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
1136 ActisenseMsgBuf[msgIdx++]=CheckSum;
1137 if (CheckSum==ESCAPE) ActisenseMsgBuf[msgIdx++]=CheckSum;
1139 ActisenseMsgBuf[msgIdx++] = ESCAPE;
1140 ActisenseMsgBuf[msgIdx++] = ENDOFTEXT;
1142 std::vector<unsigned char> rv;
1143 for (
unsigned int i=0 ; i < msgIdx; i++)
1144 rv.push_back(ActisenseMsgBuf[i]);
Internal event worker thread -> main driver.
Driver for NMEA200 messages over serial connections.
void Activate() override
Register driver and possibly do other post-ctor steps.
Abstract driver interface for NMEA2000 messages.
void Activate(DriverPtr driver)
Add driver to list of active drivers.
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.
N2k uses CAN which defines the basic properties of messages.