27 #include <wx/wxprec.h>
39 #include "model/comm_drv_n2k_serial.h"
40 #include "model/comm_navmsg_bus.h"
41 #include "model/comm_drv_registry.h"
42 #include "model/logger.h"
45 std::vector<unsigned char> BufferToActisenseFormat( tN2kMsg &msg);
51 std::lock_guard<std::mutex> lock(m_mutex);
52 return m_queque.size();
56 std::lock_guard<std::mutex> lock(m_mutex);
57 return m_queque.empty();
61 std::lock_guard<std::mutex> lock(m_mutex);
62 return m_queque.front();
65 void push(
const T& value) {
66 std::lock_guard<std::mutex> lock(m_mutex);
71 std::lock_guard<std::mutex> lock(m_mutex);
76 std::queue<T> m_queque;
77 mutable std::mutex m_mutex;
84 : buf_(std::unique_ptr<T[]>(new T[size])), max_size_(size) {}
87 size_t capacity()
const;
92 return (!full_ && (head_ == tail_));
101 std::lock_guard<std::mutex> lock(mutex_);
103 if (full_) tail_ = (tail_ + 1) % max_size_;
105 head_ = (head_ + 1) % max_size_;
107 full_ = head_ == tail_;
111 std::lock_guard<std::mutex> lock(mutex_);
113 if (empty())
return T();
116 auto val = buf_[tail_];
118 tail_ = (tail_ + 1) % max_size_;
125 std::unique_ptr<T[]> buf_;
128 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;
183 : wxEvent(
id, commandType){};
187 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
190 std::shared_ptr<std::vector<unsigned char>> GetPayload() {
return m_payload; }
193 wxEvent* Clone()
const {
195 newevent->m_payload = this->m_payload;
200 std::shared_ptr<std::vector<unsigned char>> m_payload;
212 m_Thread_run_flag(-1),
214 m_portstring(params->GetDSPort()),
215 m_pSecondary_Thread(NULL),
217 m_listener(listener) {
218 m_BaudRate = wxString::Format(
"%i", params->Baudrate), SetSecThreadInActive();
219 m_manufacturers_code = 0;
220 m_got_mfg_code =
false;
221 this->attributes[
"canAddress"] = std::string(
"-1");
222 this->attributes[
"userComment"] = params->UserComment.ToStdString();
223 this->attributes[
"ioDirection"] = std::string(
"IN/OUT");
226 Bind(wxEVT_COMMDRIVER_N2K_SERIAL, &CommDriverN2KSerial::handle_N2K_SERIAL_RAW,
241 N2kMsg.SetPGN(126993L);
244 N2kMsg.Destination = 133;
245 N2kMsg.Add2ByteUInt((uint16_t)(2000));
248 N2kMsg.AddByte(0xff);
249 N2kMsg.Add4ByteUInt(0xffffffff);
251 const std::vector<unsigned char> mv = BufferToActisenseFormat(N2kMsg);
253 size_t len = mv.size();
255 wxString comx = m_params.GetDSPort().AfterFirst(
':');
256 std::string
interface = comx.ToStdString();
259 auto source_address = std::make_shared<NavAddr2000>(interface, source_name);
260 auto dest_address = std::make_shared<NavAddr2000>(interface, N2kMsg.Destination);
262 auto message_to_send = std::make_shared<Nmea2000Msg>(126993L,
263 mv, source_address, 3);
265 for(
size_t i=0; i< mv.size(); i++){
266 printf(
"%02X ", mv.at(i));
273 SendMessage(message_to_send, dest_address);
281 CommDriverN2KSerial::~CommDriverN2KSerial() {
285 bool CommDriverN2KSerial::Open() {
287 comx = m_params.GetDSPort().AfterFirst(
':');
290 comx.BeforeFirst(
' ');
296 GetSecondaryThread()->Run();
302 void CommDriverN2KSerial::Close() {
304 wxString::Format(_T(
"Closing N2K Driver %s"), m_portstring.c_str()));
307 if (m_pSecondary_Thread) {
308 if (m_bsec_thread_active)
310 wxLogMessage(_T(
"Stopping Secondary Thread"));
312 m_Thread_run_flag = 0;
314 while ((m_Thread_run_flag >= 0) && (tsec--)) wxSleep(1);
317 if (m_Thread_run_flag < 0)
318 msg.Printf(_T(
"Stopped in %d sec."), 10 - tsec);
320 msg.Printf(_T(
"Not Stopped after 10 sec."));
324 m_pSecondary_Thread = NULL;
325 m_bsec_thread_active =
false;
330 CommDriverRegistry::GetInstance().
Activate(shared_from_this());
334 bool CommDriverN2KSerial::SendMessage(std::shared_ptr<const NavMsg> msg,
335 std::shared_ptr<const NavAddr> addr) {
338 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
339 std::vector<uint8_t> load = msg_n2k->payload;
341 uint64_t _pgn = msg_n2k->PGN.pgn;
342 auto destination_address = std::static_pointer_cast<const NavAddr2000>(addr);
346 N2kMsg.Priority = msg_n2k->priority;
347 if (destination_address)
348 N2kMsg.Destination = destination_address->address;
350 for (
size_t i=0 ; i < load.size(); i++)
351 N2kMsg.AddByte(load.at(i));
353 const std::vector<uint8_t> mv = BufferToActisenseFormat(N2kMsg);
361 if( GetSecondaryThread() ) {
362 if( IsSecThreadActive() )
366 if( GetSecondaryThread()->SetOutMsg(mv))
380 void CommDriverN2KSerial::ProcessManagementPacket(std::vector<unsigned char> *payload) {
382 if (payload->at(2) != 0xF2) {
389 switch (payload->at(2)){
401 if (payload->at(3) == 0x02) {
402 std::string device_common_name;
403 for (
unsigned int i = 0; i < 32; i++) {
404 device_common_name += payload->at(i + 14);
406 device_common_name +=
'\0';
407 m_device_common_name = device_common_name;
413 unsigned char name[8];
414 for (
unsigned int i = 0; i < 8; i++)
415 name[i] = payload->at(i + 15);
417 memcpy( (
void *)&NAME, name, 8);
419 int *f1 = (
int *)&NAME;
421 m_manufacturers_code = f1d >> 21;
432 static uint64_t PayloadToName(
const std::vector<unsigned char> payload) {
434 memcpy(&name,
reinterpret_cast<const void*
>(payload.data()),
sizeof(name));
439 void CommDriverN2KSerial::handle_N2K_SERIAL_RAW(
441 auto p =
event.GetPayload();
443 std::vector<unsigned char>* payload = p.get();
445 if (payload->at(0) == 0xA0) {
446 ProcessManagementPacket(payload);
452 unsigned char* c = (
unsigned char*)&pgn;
453 *c++ = payload->at(3);
454 *c++ = payload->at(4);
455 *c++ = payload->at(5);
459 auto name = PayloadToName(*payload);
460 auto msg = std::make_shared<const Nmea2000Msg>(pgn, *payload, GetAddress(name));
461 auto msg_all = std::make_shared<const Nmea2000Msg>(1, *payload, GetAddress(name));
463 m_listener.
Notify(std::move(msg));
464 m_listener.
Notify(std::move(msg_all));
467 size_t packetLength = (size_t)payload->at(1);
468 size_t vector_length = payload->size();
473 printf(
"Payload Length: %ld\n", vector_length);
475 printf(
"PGN: %ld\n", pgn);
477 for(
size_t i=0; i< vector_length ; i++){
478 printf(
"%02X ", payload->at(i));
485 int CommDriverN2KSerial::GetMfgCode(){
486 unsigned char request_name[] = { 0x42};
487 int ni = SendMgmtMsg( request_name,
sizeof(request_name), 0x41, 2000, &m_bmg42_resp);
490 m_got_mfg_code =
true;
494 int CommDriverN2KSerial::SendMgmtMsg(
unsigned char *
string,
size_t string_size,
495 unsigned char cmd_code,
496 int timeout_msec,
bool *response_flag) {
501 std::vector <unsigned char> msg;
503 msg.push_back(ESCAPE);
504 msg.push_back(STARTOFTEXT);
507 msg.push_back(string_size);
508 byteSum += string_size;
510 for (
unsigned int i=0; i < string_size; i++){
511 if (
string[i] == ESCAPE)
512 msg.push_back(
string[i]);
513 msg.push_back(
string[i]);
514 byteSum +=
string[i];
519 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
520 msg.push_back(CheckSum);
522 msg.push_back(ESCAPE);
523 msg.push_back(ENDOFTEXT);
528 *response_flag =
false;
532 bool not_done =
true;
535 if( GetSecondaryThread() && IsSecThreadActive() ) {
538 if( GetSecondaryThread()->SetOutMsg( msg )){
549 if (ntry_outer-- <= 0)
559 int timeout = timeout_msec;
560 while (timeout > 0) {
592 static unsigned char NGT_STARTUP_SEQ[] = {
598 int CommDriverN2KSerial::SetTXPGN(
int pgn) {
606 SendMgmtMsg( NGT_STARTUP_SEQ,
sizeof(NGT_STARTUP_SEQ), 0x11, 0, NULL);
611 unsigned char request_enable[] = { 0x47,
614 0xFF, 0xFF, 0xFF, 0xFF};
617 unsigned char* c = (
unsigned char*)&pgn;
618 request_enable[1] = c[0];
619 request_enable[2] = c[1];
620 request_enable[3] = c[2];
622 int aa = SendMgmtMsg( request_enable,
sizeof(request_enable), 0x47, 2000, &m_bmg47_resp);
627 unsigned char request_commit[] = { 0x01 };
628 int bb = SendMgmtMsg( request_commit,
sizeof(request_commit), 0x01, 2000, &m_bmg01_resp);
634 unsigned char request_activate[] = { 0x4B };
635 int cc = SendMgmtMsg( request_activate,
sizeof(request_activate), 0x4B, 2000, &m_bmg4B_resp);
672 #define DS_RX_BUFFER_SIZE 4096
674 CommDriverN2KSerialThread::CommDriverN2KSerialThread(
676 const wxString& strBaudRate) {
677 m_pParentDriver = Launcher;
679 m_PortName = PortName;
680 m_FullPortName = _T(
"Serial:") + PortName;
682 rx_buffer =
new unsigned char[DS_RX_BUFFER_SIZE + 1];
689 if (strBaudRate.ToLong(&lbaud)) m_baud = (int)lbaud;
694 CommDriverN2KSerialThread::~CommDriverN2KSerialThread(
void) {
698 void CommDriverN2KSerialThread::OnExit(
void) {}
700 bool CommDriverN2KSerialThread::OpenComPortPhysical(
const wxString& com_name,
703 m_serial.setPort(com_name.ToStdString());
704 m_serial.setBaudrate(baud_rate);
706 m_serial.setTimeout(250, 250, 0, 250, 0);
707 }
catch (std::exception&) {
711 return m_serial.isOpen();
714 void CommDriverN2KSerialThread::CloseComPortPhysical() {
717 }
catch (std::exception&) {
723 void CommDriverN2KSerialThread::SetGatewayOperationMode(
void) {
728 unsigned char config_string[] = { 0x10, 0x02, 0xA1, 0x03, 0x11,
729 0x02, 0x00, 0x49, 0x10, 0x03};
732 WriteComPortPhysical(config_string, 10);
737 void CommDriverN2KSerialThread::ThreadMessage(
const wxString& msg) {
744 size_t CommDriverN2KSerialThread::WriteComPortPhysical(std::vector<unsigned char> msg) {
745 if (m_serial.isOpen()) {
749 for (
size_t i = 0; i < msg.size(); i++) printf(
"%02X ", msg[i]);
753 status = m_serial.write((uint8_t*)msg.data(), msg.size());
754 }
catch (std::exception& e) {
755 WARNING_LOG <<
"Unhandled Exception while writing to serial port: "
765 size_t CommDriverN2KSerialThread::WriteComPortPhysical(
unsigned char *msg,
size_t length) {
766 if (m_serial.isOpen()) {
769 status = m_serial.write((uint8_t*)msg, length);
770 }
catch (std::exception&) {
781 bool CommDriverN2KSerialThread::SetOutMsg(
const std::vector<unsigned char> &msg)
783 if(out_que.size() < OUT_QUEUE_LENGTH){
791 void* CommDriverN2KSerialThread::Entry() {
792 bool not_done =
true;
793 bool nl_found =
false;
800 if (!OpenComPortPhysical(m_PortName, m_baud)) {
801 wxString msg(_T(
"NMEA input device open failed: "));
802 msg.Append(m_PortName);
812 SetGatewayOperationMode();
816 m_pParentDriver->SetSecThreadActive();
819 static size_t retries = 0;
822 bool bGotESC =
false;
823 bool bGotSOT =
false;
825 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
826 if (TestDestroy()) not_done =
false;
828 uint8_t next_byte = 0;
830 if (m_serial.isOpen()) {
832 newdata = m_serial.read(rdata, 1000);
833 }
catch (std::exception& e) {
835 if (10 < retries++) {
839 CloseComPortPhysical();
847 wxMilliSleep(250 * retries);
848 CloseComPortPhysical();
849 if (OpenComPortPhysical(m_PortName, m_baud)){
850 SetGatewayOperationMode();
853 else if (retries < 10)
858 for (
int i = 0; i < newdata; i++) {
859 circle.put(rdata[i]);
863 while (!circle.empty()) {
864 if (ib >= DS_RX_BUFFER_SIZE)
866 uint8_t next_byte = circle.get();
870 if (ESCAPE == next_byte) {
871 rx_buffer[ib++] = next_byte;
876 if (bGotESC && (ENDOFTEXT == next_byte)) {
880 auto buffer = std::make_shared<std::vector<unsigned char>>(rx_buffer, rx_buffer + ib);
881 std::vector<unsigned char>* vec = buffer.get();
897 Nevent.SetPayload(buffer);
898 m_pParentDriver->AddPendingEvent(Nevent);
902 bGotESC = (next_byte == ESCAPE);
905 rx_buffer[ib++] = next_byte;
911 if (STARTOFTEXT == next_byte) {
917 bGotESC = (next_byte == ESCAPE);
922 rx_buffer[ib++] = next_byte;
930 bool b_qdata = !out_que.empty();
934 std::vector<unsigned char> qmsg = out_que.front();
937 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
942 CloseComPortPhysical();
945 b_qdata = !out_que.empty();
952 CloseComPortPhysical();
953 m_pParentDriver->SetSecThreadInActive();
954 m_pParentDriver->m_Thread_run_flag = -1;
960 void* CommDriverN2KSerialThread::Entry() {
961 bool not_done =
true;
962 bool nl_found =
false;
967 if (!OpenComPortPhysical(m_PortName, m_baud)) {
968 wxString msg(_T(
"NMEA input device open failed: "));
969 msg.Append(m_PortName);
978 SetGatewayOperationMode();
981 m_pParentDriver->SetSecThreadActive();
984 static size_t retries = 0;
987 bool bGotESC =
false;
988 bool bGotSOT =
false;
990 while ((not_done) && (m_pParentDriver->m_Thread_run_flag > 0)) {
991 if (TestDestroy()) not_done =
false;
993 uint8_t next_byte = 0;
997 if (m_serial.isOpen()) {
999 newdata = m_serial.read(rdata, 200);
1000 }
catch (std::exception& e) {
1002 if (10 < retries++) {
1006 CloseComPortPhysical();
1014 wxMilliSleep(250 * retries);
1015 CloseComPortPhysical();
1016 if (OpenComPortPhysical(m_PortName, m_baud)){
1017 SetGatewayOperationMode();
1020 else if (retries < 10)
1025 for (
int i = 0; i < newdata; i++) {
1026 circle.put(rdata[i]);
1030 while (!circle.empty()) {
1031 uint8_t next_byte = circle.get();
1036 if (ESCAPE == next_byte) {
1037 *put_ptr++ = next_byte;
1038 if ((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE)
1039 put_ptr = rx_buffer;
1041 }
else if ( ENDOFTEXT == next_byte ) {
1045 auto buffer = std::make_shared<std::vector<unsigned char>>();
1046 std::vector<unsigned char>* vec = buffer.get();
1048 unsigned char* tptr;
1051 while ((tptr != put_ptr)) {
1052 vec->push_back(*tptr++);
1053 if ((tptr - rx_buffer) > DS_RX_BUFFER_SIZE) tptr = rx_buffer;
1065 Nevent.SetPayload(buffer);
1066 m_pParentDriver->AddPendingEvent(Nevent);
1067 }
else if (next_byte == STARTOFTEXT) {
1068 put_ptr = rx_buffer;
1071 put_ptr = rx_buffer;
1077 bGotESC = (next_byte == ESCAPE);
1080 *put_ptr++ = next_byte;
1081 if ((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE)
1082 put_ptr = rx_buffer;
1088 if (STARTOFTEXT == next_byte) {
1094 bGotESC = (next_byte == ESCAPE);
1099 *put_ptr++ = next_byte;
1100 if ((put_ptr - rx_buffer) > DS_RX_BUFFER_SIZE)
1101 put_ptr = rx_buffer;
1109 bool b_qdata = !out_que.empty();
1113 std::vector<unsigned char> qmsg = out_que.front();
1116 if (
static_cast<size_t>(-1) == WriteComPortPhysical(qmsg) &&
1121 CloseComPortPhysical();
1124 b_qdata = !out_que.empty();
1129 CloseComPortPhysical();
1130 m_pParentDriver->SetSecThreadInActive();
1131 m_pParentDriver->m_Thread_run_flag = -1;
1144 #define MaxActisenseMsgBuf 400
1145 #define MsgTypeN2kTX 0x94
1147 void AddByteEscapedToBuf(
unsigned char byteToAdd, uint8_t &idx,
unsigned char *buf,
int &byteSum);
1149 std::vector<unsigned char> BufferToActisenseFormat( tN2kMsg &msg){
1150 unsigned long _PGN=msg.PGN;
1154 unsigned char ActisenseMsgBuf[MaxActisenseMsgBuf];
1157 ActisenseMsgBuf[msgIdx++]=ESCAPE;
1158 ActisenseMsgBuf[msgIdx++]=STARTOFTEXT;
1159 AddByteEscapedToBuf(MsgTypeN2kTX,msgIdx,ActisenseMsgBuf,byteSum);
1160 AddByteEscapedToBuf(msg.DataLen+6,msgIdx,ActisenseMsgBuf,byteSum);
1162 AddByteEscapedToBuf(msg.Priority,msgIdx,ActisenseMsgBuf,byteSum);
1163 AddByteEscapedToBuf(_PGN & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _PGN>>=8;
1164 AddByteEscapedToBuf(_PGN & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _PGN>>=8;
1165 AddByteEscapedToBuf(_PGN & 0xff,msgIdx,ActisenseMsgBuf,byteSum);
1166 AddByteEscapedToBuf(msg.Destination,msgIdx,ActisenseMsgBuf,byteSum);
1171 AddByteEscapedToBuf(msg.Source,msgIdx,ActisenseMsgBuf,byteSum);
1174 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1175 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1176 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum); _MsgTime>>=8;
1177 AddByteEscapedToBuf(_MsgTime & 0xff,msgIdx,ActisenseMsgBuf,byteSum);
1181 AddByteEscapedToBuf(msg.DataLen,msgIdx,ActisenseMsgBuf,byteSum);
1183 for (
int i = 0; i < msg.DataLen; i++)
1184 AddByteEscapedToBuf(msg.Data[i],msgIdx,ActisenseMsgBuf,byteSum);
1187 CheckSum = (uint8_t)((byteSum == 0) ? 0 : (256 - byteSum));
1188 ActisenseMsgBuf[msgIdx++]=CheckSum;
1189 if (CheckSum==ESCAPE) ActisenseMsgBuf[msgIdx++]=CheckSum;
1191 ActisenseMsgBuf[msgIdx++] = ESCAPE;
1192 ActisenseMsgBuf[msgIdx++] = ENDOFTEXT;
1194 std::vector<unsigned char> rv;
1195 for (
unsigned int i=0 ; i < msgIdx; i++)
1196 rv.push_back(ActisenseMsgBuf[i]);
void Activate() override
Register driver and possibly do other post-ctor steps.
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.
wxDEFINE_EVENT(REST_IO_EVT, ObservedEvt)
Event from IO thread to main.
N2k uses CAN which defines the basic properties of messages.