OpenCPN Partial API docs
Loading...
Searching...
No Matches
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"
46
47#ifdef __ANDROID__
48#include "androidUTIL.h"
49#endif
50
51typedef enum DS_ENUM_BUFFER_STATE {
52 DS_RX_BUFFER_EMPTY,
53 DS_RX_BUFFER_FULL
54} _DS_ENUM_BUFFER_STATE;
55
56class CommDriverN0183AndroidBT; // fwd
57
58#define MAX_OUT_QUEUE_MESSAGE_LENGTH 100
59
60template <typename T>
62public:
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
88private:
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
96wxDEFINE_EVENT(wxEVT_COMMDRIVER_N0183_ANDROID_BT,
98
99CommDriverN0183AndroidBTEvent::CommDriverN0183AndroidBTEvent(
100 wxEventType commandType, int id = 0)
101 : wxEvent(id, commandType) {};
102
103CommDriverN0183AndroidBTEvent::~CommDriverN0183AndroidBTEvent() {};
104
105void CommDriverN0183AndroidBTEvent::SetPayload(
106 std::shared_ptr<std::vector<unsigned char>> data) {
107 m_payload = data;
108}
109std::shared_ptr<std::vector<unsigned char>>
110CommDriverN0183AndroidBTEvent::GetPayload() {
111 return m_payload;
112}
113
114// required for sending with wxPostEvent()
115wxEvent* CommDriverN0183AndroidBTEvent::Clone() const {
118 newevent->m_payload = this->m_payload;
119 return newevent;
120};
121
122template <class T>
124public:
125 explicit circular_buffer(size_t size)
126 : buf_(std::unique_ptr<T[]>(new T[size])), max_size_(size) {}
127
128 void reset();
129 size_t capacity() const;
130 size_t size() const;
131
132 bool empty() const {
133 // if head and tail are equal, we are empty
134 return (!full_ && (head_ == tail_));
135 }
136
137 bool full() const {
138 // If tail is ahead the head by 1, we are full
139 return full_;
140 }
141
142 void put(T item) {
143 std::lock_guard<std::mutex> lock(mutex_);
144 buf_[head_] = item;
145 if (full_) tail_ = (tail_ + 1) % max_size_;
146
147 head_ = (head_ + 1) % max_size_;
148
149 full_ = head_ == tail_;
150 }
151
152 T get() {
153 std::lock_guard<std::mutex> lock(mutex_);
154
155 if (empty()) return T();
156
157 // Read data and advance the tail (we now have a free space)
158 auto val = buf_[tail_];
159 full_ = false;
160 tail_ = (tail_ + 1) % max_size_;
161
162 return val;
163 }
164
165private:
166 std::mutex mutex_;
167 std::unique_ptr<T[]> buf_;
168 size_t head_ = 0;
169 size_t tail_ = 0;
170 const size_t max_size_;
171 bool full_ = 0;
172};
173
174CommDriverN0183AndroidBT::CommDriverN0183AndroidBT(
175 const ConnectionParams* params, DriverListener& listener)
176 : CommDriverN0183(NavAddr::Bus::N0183, params->GetStrippedDSPort()),
177 m_bok(false),
178 m_portstring(params->GetDSPort()),
179 m_params(*params),
180 m_listener(listener) {
181 // m_BaudRate = wxString::Format("%i", params->Baudrate),
182 // SetSecThreadInActive();
183 this->attributes["commPort"] = params->Port.ToStdString();
184 this->attributes["userComment"] = params->UserComment.ToStdString();
185 this->attributes["ioDirection"] = DsPortTypeToString(params->IOSelect);
186
187 // Prepare the wxEventHandler to accept events from the actual hardware thread
188 Bind(wxEVT_COMMDRIVER_N0183_ANDROID_BT,
189 &CommDriverN0183AndroidBT::handle_N0183_MSG, this);
190
191 Open();
192}
193
194CommDriverN0183AndroidBT::~CommDriverN0183AndroidBT() { Close(); }
195
196bool CommDriverN0183AndroidBT::Open() {
197 wxString comx;
198 comx = m_params.GetDSPort().AfterFirst(':'); // strip "Serial:"
199
200 wxString port_uc = m_params.GetDSPort().Upper();
201
202 androidStartBT(this, port_uc);
203 return true;
204}
205
206void CommDriverN0183AndroidBT::Close() {
207 wxLogMessage(
208 wxString::Format(_T("Closing NMEA BT Driver %s"), m_portstring.c_str()));
209
210 androidStopBT();
211
212 Unbind(wxEVT_COMMDRIVER_N0183_ANDROID_BT,
213 &CommDriverN0183AndroidBT::handle_N0183_MSG, this);
214}
215
216bool CommDriverN0183AndroidBT::SendMessage(
217 std::shared_ptr<const NavMsg> msg, std::shared_ptr<const NavAddr> addr) {
218 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
219 wxString sentence(msg_0183->payload.c_str());
220
221 wxString payload = sentence;
222 if (!sentence.EndsWith(_T("\r\n"))) payload += _T("\r\n");
223
224 androidSendBTMessage(payload);
225 return true;
226}
227
228void CommDriverN0183AndroidBT::handle_N0183_MSG(
230 auto p = event.GetPayload();
231 std::vector<unsigned char>* payload = p.get();
232
233 // Extract the NMEA0183 sentence
234 std::string full_sentence = std::string(payload->begin(), payload->end());
235
236 if ((full_sentence[0] == '$') || (full_sentence[0] == '!')) { // Sanity check
237 std::string identifier;
238 // We notify based on full message, including the Talker ID
239 identifier = full_sentence.substr(1, 5);
240
241 // notify message listener and also "ALL" N0183 messages, to support plugin
242 // API using original talker id
243 auto msg = std::make_shared<const Nmea0183Msg>(identifier, full_sentence,
244 GetAddress());
245 auto msg_all = std::make_shared<const Nmea0183Msg>(*msg, "ALL");
246
247 if (m_params.SentencePassesFilter(full_sentence, FILTER_INPUT))
248 m_listener.Notify(std::move(msg));
249
250 m_listener.Notify(std::move(msg_all));
251 }
252}
NMEA0183 drivers common part.
Interface implemented by transport layer and possible other parties like test code which should handl...
Definition comm_driver.h:48
virtual void Notify(std::shared_ptr< const NavMsg > message)=0
Handle a received message.
Where messages are sent to or received from.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.