OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_drv_n0183_android_bt.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2023 by David Register *
3 * Copyright (C) 2023 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
26#include <mutex> // std::mutex
27#include <queue> // std::queue
28#include <vector>
29
30// For compilers that support precompilation, includes "wx.h".
31#include <wx/wxprec.h>
32#ifndef WX_PRECOMP
33#include <wx/wx.h>
34#endif
35
36#include <wx/event.h>
37#include <wx/log.h>
38#include <wx/string.h>
39#include <wx/utils.h>
40
41#include "config.h"
45
46#ifdef __ANDROID__
47#include "androidUTIL.h"
48#endif
49
50using namespace std::literals::chrono_literals;
51
52typedef enum DS_ENUM_BUFFER_STATE {
53 DS_RX_BUFFER_EMPTY,
54 DS_RX_BUFFER_FULL
55} _DS_ENUM_BUFFER_STATE;
56
57class CommDriverN0183AndroidBT; // forward
58
59#define MAX_OUT_QUEUE_MESSAGE_LENGTH 100
60
61template <typename T>
63public:
64 size_t size() {
65 std::lock_guard<std::mutex> lock(m_mutex);
66 return m_queque.size();
67 }
68
69 bool empty() {
70 std::lock_guard<std::mutex> lock(m_mutex);
71 return m_queque.empty();
72 }
73
74 const T& front() {
75 std::lock_guard<std::mutex> lock(m_mutex);
76 return m_queque.front();
77 }
78
79 void push(const T& value) {
80 std::lock_guard<std::mutex> lock(m_mutex);
81 m_queque.push(value);
82 }
83
84 void pop() {
85 std::lock_guard<std::mutex> lock(m_mutex);
86 m_queque.pop();
87 }
88
89private:
90 std::queue<T> m_queque;
91 mutable std::mutex m_mutex;
92};
93
94#define OUT_QUEUE_LENGTH 20
95#define MAX_OUT_QUEUE_MESSAGE_LENGTH 100
96
97wxDEFINE_EVENT(wxEVT_COMMDRIVER_N0183_ANDROID_BT,
99
100CommDriverN0183AndroidBTEvent::CommDriverN0183AndroidBTEvent(
101 wxEventType commandType, int id = 0)
102 : wxEvent(id, commandType) {};
103
104CommDriverN0183AndroidBTEvent::~CommDriverN0183AndroidBTEvent() {};
105
106void CommDriverN0183AndroidBTEvent::SetPayload(
107 std::shared_ptr<std::vector<unsigned char>> data) {
108 m_payload = data;
109}
110std::shared_ptr<std::vector<unsigned char>>
111CommDriverN0183AndroidBTEvent::GetPayload() {
112 return m_payload;
113}
114
115// required for sending with wxPostEvent()
116wxEvent* CommDriverN0183AndroidBTEvent::Clone() const {
119 newevent->m_payload = this->m_payload;
120 return newevent;
121};
122
123template <class T>
125public:
126 explicit circular_buffer(size_t size)
127 : buf_(std::unique_ptr<T[]>(new T[size])), max_size_(size) {}
128
129 void reset();
130 size_t capacity() const;
131 size_t size() const;
132
133 bool empty() const {
134 // if head and tail are equal, we are empty
135 return (!full_ && (head_ == tail_));
136 }
137
138 bool full() const {
139 // If tail is ahead the head by 1, we are full
140 return full_;
141 }
142
143 void put(T item) {
144 std::lock_guard<std::mutex> lock(mutex_);
145 buf_[head_] = item;
146 if (full_) tail_ = (tail_ + 1) % max_size_;
147
148 head_ = (head_ + 1) % max_size_;
149
150 full_ = head_ == tail_;
151 }
152
153 T get() {
154 std::lock_guard<std::mutex> lock(mutex_);
155
156 if (empty()) return T();
157
158 // Read data and advance the tail (we now have a free space)
159 auto val = buf_[tail_];
160 full_ = false;
161 tail_ = (tail_ + 1) % max_size_;
162
163 return val;
164 }
165
166private:
167 std::mutex mutex_;
168 std::unique_ptr<T[]> buf_;
169 size_t head_ = 0;
170 size_t tail_ = 0;
171 const size_t max_size_;
172 bool full_ = 0;
173};
174
175CommDriverN0183AndroidBT::CommDriverN0183AndroidBT(
176 const ConnectionParams* params, DriverListener& listener)
177 : CommDriverN0183(NavAddr::Bus::N0183, params->GetStrippedDSPort()),
178 m_bok(false),
179 m_portstring(params->GetDSPort()),
180 m_params(*params),
181 m_listener(listener),
182 m_stats_timer(*this, 2s) {
183 this->attributes["commPort"] = params->Port.ToStdString();
184 this->attributes["userComment"] = params->UserComment.ToStdString();
185 this->attributes["ioDirection"] = DsPortTypeToString(params->IOSelect);
186 m_driver_stats.driver_bus = NavAddr::Bus::N0183;
187 m_driver_stats.driver_iface = params->GetStrippedDSPort();
188
189 // Prepare the wxEventHandler to accept events from the actual hardware thread
190 Bind(wxEVT_COMMDRIVER_N0183_ANDROID_BT,
191 &CommDriverN0183AndroidBT::handle_N0183_MSG, this);
192
193 Open();
194}
195
196CommDriverN0183AndroidBT::~CommDriverN0183AndroidBT() { Close(); }
197
198bool CommDriverN0183AndroidBT::Open() {
199 wxString comx;
200 comx = m_params.GetDSPort().AfterFirst(':'); // strip "Serial:"
201
202 wxString port_uc = m_params.GetDSPort().Upper();
203
204 androidStartBT(this, port_uc);
205 m_driver_stats.available = true;
206
207 return true;
208}
209
210void CommDriverN0183AndroidBT::Close() {
211 wxLogMessage(
212 wxString::Format("Closing NMEA BT Driver %s", m_portstring.c_str()));
213 m_stats_timer.Stop();
214
215 androidStopBT();
216 m_driver_stats.available = false;
217
218 Unbind(wxEVT_COMMDRIVER_N0183_ANDROID_BT,
219 &CommDriverN0183AndroidBT::handle_N0183_MSG, this);
220}
221
222bool CommDriverN0183AndroidBT::SendMessage(
223 std::shared_ptr<const NavMsg> msg, std::shared_ptr<const NavAddr> addr) {
224 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
225 wxString sentence(msg_0183->payload.c_str());
226 m_driver_stats.tx_count += sentence.Length();
227
228 wxString payload = sentence;
229 if (!sentence.EndsWith("\r\n")) payload += "\r\n";
230
231 androidSendBTMessage(payload);
232 return true;
233}
234
235void CommDriverN0183AndroidBT::handle_N0183_MSG(
237 auto p = event.GetPayload();
238 std::vector<unsigned char>* payload = p.get();
239 m_driver_stats.rx_count += payload->size();
240 SendToListener({payload->begin(), payload->end()}, m_listener, m_params);
241}
NMEA0183 basic parsing common parts:
void SendToListener(const std::string &payload, DriverListener &listener, const ConnectionParams &params)
Wrap argument string in NavMsg pointer, forward to listener.
Interface for handling incoming messages.
Definition comm_driver.h:50
Where messages are sent to or received from.
Android nmea0183 internal bluetooth driver.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
std::string DsPortTypeToString(dsPortType type)
Return textual representation for use in driver ioDirection attribute.
unsigned tx_count
Number of bytes sent since program start.
unsigned rx_count
Number of bytes received since program start.