OpenCPN Partial API docs
comm_drv_n0183_android_bt.cpp
1 /***************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose: Implement comm_drv_n0183_android_bt.h -- Nmea 0183 driver.
5  * Author: David Register, Alec Leamas
6  *
7  ***************************************************************************
8  * Copyright (C) 2023 by David Register, Alec Leamas *
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License *
21  * along with this program; if not, write to the *
22  * Free Software Foundation, Inc., *
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24  **************************************************************************/
25 
26 // For compilers that support precompilation, includes "wx.h".
27 #include <wx/wxprec.h>
28 
29 #ifndef WX_PRECOMP
30 #include <wx/wx.h>
31 #endif // precompiled headers
32 
33 #include <mutex> // std::mutex
34 #include <queue> // std::queue
35 #include <vector>
36 
37 #include <wx/event.h>
38 #include <wx/log.h>
39 #include <wx/string.h>
40 #include <wx/utils.h>
41 
42 #include "config.h"
43 #include "model/comm_drv_n0183_android_bt.h"
44 #include "model/comm_navmsg_bus.h"
45 #include "model/comm_drv_registry.h"
46 
47 #ifdef __ANDROID__
48 #include "androidUTIL.h"
49 #endif
50 
51 typedef enum DS_ENUM_BUFFER_STATE {
52  DS_RX_BUFFER_EMPTY,
53  DS_RX_BUFFER_FULL
54 } _DS_ENUM_BUFFER_STATE;
55 
56 class CommDriverN0183AndroidBT; // fwd
57 
58 #define MAX_OUT_QUEUE_MESSAGE_LENGTH 100
59 
60 template <typename T>
62 public:
63  size_t size() {
64  std::lock_guard<std::mutex> lock(m_mutex);
65  return m_queque.size();
66  }
67 
68  bool empty() {
69  std::lock_guard<std::mutex> lock(m_mutex);
70  return m_queque.empty();
71  }
72 
73  const T& front() {
74  std::lock_guard<std::mutex> lock(m_mutex);
75  return m_queque.front();
76  }
77 
78  void push(const T& value) {
79  std::lock_guard<std::mutex> lock(m_mutex);
80  m_queque.push(value);
81  }
82 
83  void pop() {
84  std::lock_guard<std::mutex> lock(m_mutex);
85  m_queque.pop();
86  }
87 
88 private:
89  std::queue<T> m_queque;
90  mutable std::mutex m_mutex;
91 };
92 
93 #define OUT_QUEUE_LENGTH 20
94 #define MAX_OUT_QUEUE_MESSAGE_LENGTH 100
95 
96 wxDEFINE_EVENT(wxEVT_COMMDRIVER_N0183_ANDROID_BT, CommDriverN0183AndroidBTEvent);
97 
98 CommDriverN0183AndroidBTEvent::CommDriverN0183AndroidBTEvent( wxEventType commandType, int id = 0)
99  : wxEvent(id, commandType){};
100 
101 CommDriverN0183AndroidBTEvent::~CommDriverN0183AndroidBTEvent(){};
102 
103 void CommDriverN0183AndroidBTEvent::SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
104  m_payload = data;
105 }
106 std::shared_ptr<std::vector<unsigned char>> CommDriverN0183AndroidBTEvent::GetPayload() { return m_payload; }
107 
108  // required for sending with wxPostEvent()
109 wxEvent* CommDriverN0183AndroidBTEvent::Clone() const {
112  newevent->m_payload = this->m_payload;
113  return newevent;
114 };
115 
116 
117 template <class T>
119 public:
120  explicit circular_buffer(size_t size)
121  : buf_(std::unique_ptr<T[]>(new T[size])), max_size_(size) {}
122 
123  void reset();
124  size_t capacity() const;
125  size_t size() const;
126 
127  bool empty() const {
128  // if head and tail are equal, we are empty
129  return (!full_ && (head_ == tail_));
130  }
131 
132  bool full() const {
133  // If tail is ahead the head by 1, we are full
134  return full_;
135  }
136 
137  void put(T item) {
138  std::lock_guard<std::mutex> lock(mutex_);
139  buf_[head_] = item;
140  if (full_) tail_ = (tail_ + 1) % max_size_;
141 
142  head_ = (head_ + 1) % max_size_;
143 
144  full_ = head_ == tail_;
145  }
146 
147  T get() {
148  std::lock_guard<std::mutex> lock(mutex_);
149 
150  if (empty()) return T();
151 
152  // Read data and advance the tail (we now have a free space)
153  auto val = buf_[tail_];
154  full_ = false;
155  tail_ = (tail_ + 1) % max_size_;
156 
157  return val;
158  }
159 
160 private:
161  std::mutex mutex_;
162  std::unique_ptr<T[]> buf_;
163  size_t head_ = 0;
164  size_t tail_ = 0;
165  const size_t max_size_;
166  bool full_ = 0;
167 };
168 
169 CommDriverN0183AndroidBT::CommDriverN0183AndroidBT(const ConnectionParams* params,
170  DriverListener& listener)
171  : CommDriverN0183(NavAddr::Bus::N0183,
172  ((ConnectionParams*)params)->GetStrippedDSPort()),
173  m_bok(false),
174  m_portstring(params->GetDSPort()),
175  m_params(*params),
176  m_listener(listener) {
177  //m_BaudRate = wxString::Format("%i", params->Baudrate), SetSecThreadInActive();
178  this->attributes["commPort"] = params->Port.ToStdString();
179  this->attributes["userComment"] = params->UserComment.ToStdString();
180  dsPortType iosel = params->IOSelect;
181  std::string s_iosel = std::string("IN");
182  if (iosel == DS_TYPE_INPUT_OUTPUT) {s_iosel = "OUT";}
183  else if (iosel == DS_TYPE_INPUT_OUTPUT) {s_iosel = "IN/OUT";}
184  this->attributes["ioDirection"] = s_iosel;
185 
186  // Prepare the wxEventHandler to accept events from the actual hardware thread
187  Bind(wxEVT_COMMDRIVER_N0183_ANDROID_BT, &CommDriverN0183AndroidBT::handle_N0183_MSG,
188  this);
189 
190  Open();
191 }
192 
193 CommDriverN0183AndroidBT::~CommDriverN0183AndroidBT() { Close(); }
194 
195 bool CommDriverN0183AndroidBT::Open() {
196  wxString comx;
197  comx = m_params.GetDSPort().AfterFirst(':'); // strip "Serial:"
198 
199  wxString port_uc = m_params.GetDSPort().Upper();
200 
201  androidStartBT( this, port_uc );
202  return true;
203 }
204 
205 void CommDriverN0183AndroidBT::Close() {
206  wxLogMessage(
207  wxString::Format(_T("Closing NMEA BT Driver %s"), m_portstring.c_str()));
208 
209  androidStopBT();
210 
211  Unbind(wxEVT_COMMDRIVER_N0183_ANDROID_BT, &CommDriverN0183AndroidBT::handle_N0183_MSG,
212  this);
213 }
214 
215 
217  CommDriverRegistry::GetInstance().Activate(shared_from_this());
218 }
219 
220 bool CommDriverN0183AndroidBT::SendMessage(std::shared_ptr<const NavMsg> msg,
221  std::shared_ptr<const NavAddr> addr) {
222 
223  auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
224  wxString sentence(msg_0183->payload.c_str());
225 
226  wxString payload = sentence;
227  if( !sentence.EndsWith(_T("\r\n")) )
228  payload += _T("\r\n");
229 
230  androidSendBTMessage(payload);
231  return true;
232 }
233 
234 
235 
236 void CommDriverN0183AndroidBT::handle_N0183_MSG(
238  auto p = event.GetPayload();
239  std::vector<unsigned char>* payload = p.get();
240 
241  // Extract the NMEA0183 sentence
242  std::string full_sentence = std::string(payload->begin(), payload->end());
243 
244  if ((full_sentence[0] == '$') || (full_sentence[0] == '!')) { // Sanity check
245  std::string identifier;
246  // We notify based on full message, including the Talker ID
247  identifier = full_sentence.substr(1, 5);
248 
249  // notify message listener and also "ALL" N0183 messages, to support plugin
250  // API using original talker id
251  auto msg = std::make_shared<const Nmea0183Msg>(identifier, full_sentence,
252  GetAddress());
253  auto msg_all = std::make_shared<const Nmea0183Msg>(*msg, "ALL");
254 
255  if (m_params.SentencePassesFilter(full_sentence, FILTER_INPUT))
256  m_listener.Notify(std::move(msg));
257 
258  m_listener.Notify(std::move(msg_all));
259  }
260 }
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...
Definition: comm_driver.h:47
virtual void Notify(std::shared_ptr< const NavMsg > message)=0
Handle a received message.
Where messages are sent to or received from.
Definition: comm_navmsg.h:133
wxDEFINE_EVENT(REST_IO_EVT, ObservedEvt)
Event from IO thread to main.