OpenCPN Partial API docs
comm_drv_n0183_android_int.cpp
1 /***************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose: Implement comm_drv_n0183_android_int.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>
34 #include <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_int.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 CommDriverN0183AndroidInt; // fwd
57 
58 #define MAX_OUT_QUEUE_MESSAGE_LENGTH 100
59 
60 template <typename T>
61 class n0183_atomic_queue {
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_INT, CommDriverN0183AndroidIntEvent);
97 
98 CommDriverN0183AndroidIntEvent::CommDriverN0183AndroidIntEvent( wxEventType commandType, int id = 0)
99  : wxEvent(id, commandType){};
100 
101 CommDriverN0183AndroidIntEvent::~CommDriverN0183AndroidIntEvent(){};
102 
103 void CommDriverN0183AndroidIntEvent::SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
104  m_payload = data;
105 }
106 std::shared_ptr<std::vector<unsigned char>> CommDriverN0183AndroidIntEvent::GetPayload() { return m_payload; }
107 
108  // required for sending with wxPostEvent()
109 wxEvent* CommDriverN0183AndroidIntEvent::Clone() const {
112  newevent->m_payload = this->m_payload;
113  return newevent;
114 };
115 
116 
117 template <class T>
118 class circular_buffer {
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 CommDriverN0183AndroidInt::CommDriverN0183AndroidInt(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  this->attributes["commPort"] = params->Port.ToStdString();
178  this->attributes["userComment"] = params->UserComment.ToStdString();
179  dsPortType iosel = params->IOSelect;
180  std::string s_iosel = std::string("IN");
181  if (iosel == DS_TYPE_INPUT_OUTPUT) {s_iosel = "OUT";}
182  else if (iosel == DS_TYPE_INPUT_OUTPUT) {s_iosel = "IN/OUT";}
183  this->attributes["ioDirection"] = s_iosel;
184 
185  // Prepare the wxEventHandler to accept events from the actual hardware thread
186  Bind(wxEVT_COMMDRIVER_N0183_ANDROID_INT, &CommDriverN0183AndroidInt::handle_N0183_MSG,
187  this);
188 
189  Open();
190 }
191 
192 CommDriverN0183AndroidInt::~CommDriverN0183AndroidInt() { Close(); }
193 
194 bool CommDriverN0183AndroidInt::Open() {
195  androidStartGPS( this );
196  return true;
197 }
198 
199 void CommDriverN0183AndroidInt::Close() {
200  wxLogMessage(
201  wxString::Format(_T("Closing NMEA Driver %s"), m_portstring.c_str()));
202 
203  androidStopGPS();
204 
205  Unbind(wxEVT_COMMDRIVER_N0183_ANDROID_INT, &CommDriverN0183AndroidInt::handle_N0183_MSG,
206  this);
207 
208 }
209 
210 
212  CommDriverRegistry::GetInstance().Activate(shared_from_this());
213 }
214 
215 bool CommDriverN0183AndroidInt::SendMessage(std::shared_ptr<const NavMsg> msg,
216  std::shared_ptr<const NavAddr> addr) {
217  return false;
218 }
219 
220 
221 
222 void CommDriverN0183AndroidInt::handle_N0183_MSG(
224  auto p = event.GetPayload();
225  std::vector<unsigned char>* payload = p.get();
226 
227  // Extract the NMEA0183 sentence
228  std::string full_sentence = std::string(payload->begin(), payload->end());
229 
230  if ((full_sentence[0] == '$') || (full_sentence[0] == '!')) { // Sanity check
231  std::string identifier;
232  // We notify based on full message, including the Talker ID
233  identifier = full_sentence.substr(1, 5);
234 
235  // notify message listener and also "ALL" N0183 messages, to support plugin
236  // API using original talker id
237  auto msg = std::make_shared<const Nmea0183Msg>(identifier, full_sentence,
238  GetAddress());
239  auto msg_all = std::make_shared<const Nmea0183Msg>(*msg, "ALL");
240 
241  if (m_params.SentencePassesFilter(full_sentence, FILTER_INPUT))
242  m_listener.Notify(std::move(msg));
243 
244  m_listener.Notify(std::move(msg_all));
245  }
246 }
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.