Client.hpp
Go to the documentation of this file.
1 #ifndef CLIENT_HPP
2 #define CLIENT_HPP
3 
4 #include <asio.hpp>
5 #include <condition_variable>
6 #include <functional>
7 #include <map>
8 #include <mutex>
9 #include <string>
10 #include <thread>
11 #include "ByteVector.hpp"
12 #include "FirmwareVariants.hpp"
13 #include "Message.hpp"
14 #include "Subscription.hpp"
15 
16 namespace msp {
17 namespace client {
18 
19 typedef asio::buffers_iterator<asio::streambuf::const_buffers_type> iterator;
20 
22 
24  OK, // no errors
25  FAIL_ID, // message ID is unknown
26  FAIL_CRC // wrong CRC
27 };
28 
33 };
34 
35 class Client {
36 public:
43  Client();
44 
48  ~Client();
49 
55  void setLoggingLevel(const LoggingLevel& level);
56 
62  bool setVersion(const int& ver);
63 
68  int getVersion() const;
69 
74  void setVariant(const FirmwareVariant& v);
75 
80  FirmwareVariant getVariant() const;
81 
86  bool start(const std::string& device, const size_t baudrate = 115200);
87 
92  bool stop();
93 
98  bool isConnected() const;
99 
111  bool sendMessage(msp::Message& message, const double& timeout = 0);
112 
117  bool sendMessageNoWait(const msp::Message& message);
118 
128  template <typename T, typename C,
129  class = typename std::enable_if<
130  std::is_base_of<msp::Message, T>::value>::type>
131  std::shared_ptr<SubscriptionBase> subscribe(void (C::*callback)(const T&),
132  C* context, const double& tp) {
133  return subscribe<T>(std::bind(callback, context, std::placeholders::_1),
134  tp);
135  }
136 
146  template <typename T, class = typename std::enable_if<
147  std::is_base_of<msp::Message, T>::value>::type>
148  std::shared_ptr<SubscriptionBase> subscribe(
149  const std::function<void(const T&)>& recv_callback, const double& tp) {
150  // validate the period
151  if(!(tp >= 0.0)) throw std::runtime_error("Period must be positive!");
152 
153  // get the id of the message in question
154  const msp::ID id = T(fw_variant).id();
155  if(log_level_ >= INFO)
156  std::cout << "SUBSCRIBING TO " << id << std::endl;
157 
158  // generate the callback for sending messages
159  std::function<bool(const Message&)> send_callback =
160  std::bind(&Client::sendMessageNoWait, this, std::placeholders::_1);
161 
162  // create a shared pointer to a new Subscription and set all properties
163  auto subscription = std::make_shared<Subscription<T>>(
164  recv_callback, send_callback, std::make_unique<T>(fw_variant), tp);
165 
166  // gonna modify the subscription map, so lock the mutex
167  std::lock_guard<std::mutex> lock(mutex_subscriptions);
168 
169  // delete old subscription
170  if(subscriptions.count(id)) subscriptions.erase(id);
171 
172  // move the new subscription into the subscription map
173  subscriptions.emplace(id, std::move(subscription));
174  return subscriptions[id];
175  }
176 
182  bool hasSubscription(const msp::ID& id) const {
183  return (subscriptions.count(id) == 1);
184  }
185 
191  std::shared_ptr<SubscriptionBase> getSubscription(const msp::ID& id) {
192  return subscriptions.at(id);
193  }
194 
202  void processOneMessage(const asio::error_code& ec,
203  const std::size_t& bytes_transferred);
204 
212  bool sendData(const msp::ID id, const ByteVector& data = ByteVector(0));
213 
221  bool sendData(const msp::ID id, const ByteVectorUptr&& data) {
222  if(!data) return sendData(id);
223  return sendData(id, *data);
224  }
225 
226 protected:
231  bool connectPort(const std::string& device, const size_t baudrate = 115200);
232 
237  bool disconnectPort();
238 
243  bool startReadThread();
244 
249  bool stopReadThread();
250 
255  bool startSubscriptions();
256 
261  bool stopSubscriptions();
262 
267  uint8_t extractChar();
268 
276  std::pair<iterator, bool> messageReady(iterator begin, iterator end) const;
277 
284  ReceivedMessage processOneMessageV1();
285 
292  ReceivedMessage processOneMessageV2();
293 
301  ByteVector packMessageV1(const msp::ID id,
302  const ByteVector& data = ByteVector(0)) const;
303 
310  uint8_t crcV1(const uint8_t id, const ByteVector& data) const;
311 
319  ByteVector packMessageV2(const msp::ID id,
320  const ByteVector& data = ByteVector(0)) const;
321 
328  uint8_t crcV2(uint8_t crc, const ByteVector& data) const;
329 
336  uint8_t crcV2(uint8_t crc, const uint8_t& b) const;
337 
338 protected:
339  asio::io_service io;
340  asio::serial_port port;
341  asio::streambuf buffer;
342 
343  // read thread management
344  std::thread thread;
345  std::atomic_flag running_ = ATOMIC_FLAG_INIT;
346 
347  // thread safety and synchronization
348  std::condition_variable cv_response;
349  std::mutex cv_response_mtx;
350  std::mutex mutex_response;
351  std::mutex mutex_buffer;
352  std::mutex mutex_send;
353 
354  // holder for received data
355  std::unique_ptr<ReceivedMessage> request_received;
356 
357  // subscription management
359  std::map<msp::ID, std::shared_ptr<SubscriptionBase>> subscriptions;
360 
361  // debugging
363 
364  // reference values
365  int msp_ver_;
367 };
368 
369 } // namespace client
370 } // namespace msp
371 
372 #endif // CLIENT_HPP
std::mutex mutex_buffer
Definition: Client.hpp:351
std::condition_variable cv_response
Definition: Client.hpp:348
bool sendMessageNoWait(const msp::Message &message)
Send a message, but do not wait for any response.
Definition: Client.cpp:173
std::mutex mutex_response
Definition: Client.hpp:350
bool sendData(const msp::ID id, const ByteVectorUptr &&data)
Send an ID and payload to the flight controller.
Definition: Client.hpp:221
std::mutex mutex_subscriptions
Definition: Client.hpp:358
asio::io_service io
! io service
Definition: Client.hpp:339
ID
Definition: msp_msg.hpp:30
std::unique_ptr< ReceivedMessage > request_received
Definition: Client.hpp:355
FirmwareVariant
Enum of firmware variants.
std::shared_ptr< SubscriptionBase > getSubscription(const msp::ID &id)
Get pointer to subscription.
Definition: Client.hpp:191
std::unique_ptr< ByteVector > ByteVectorUptr
Definition: ByteVector.hpp:465
std::map< msp::ID, std::shared_ptr< SubscriptionBase > > subscriptions
Definition: Client.hpp:359
asio::buffers_iterator< asio::streambuf::const_buffers_type > iterator
Definition: Client.hpp:19
std::mutex cv_response_mtx
Definition: Client.hpp:349
std::shared_ptr< SubscriptionBase > subscribe(void(C::*callback)(const T &), C *context, const double &tp)
Register callback function that is called when a message of matching ID is received.
Definition: Client.hpp:131
asio::serial_port port
! port for serial device
Definition: Client.hpp:340
bool hasSubscription(const msp::ID &id) const
Check if message ID already has a subscription.
Definition: Client.hpp:182
LoggingLevel log_level_
Definition: Client.hpp:362
std::shared_ptr< SubscriptionBase > subscribe(const std::function< void(const T &)> &recv_callback, const double &tp)
Register callback function that is called when a message of matching ID is received. Replaces the previous callback of the same ID.
Definition: Client.hpp:148
FirmwareVariant fw_variant
Definition: Client.hpp:366
std::thread thread
Definition: Client.hpp:344
std::mutex mutex_send
Definition: Client.hpp:352
asio::streambuf buffer
Definition: Client.hpp:341


msp
Author(s): Christian Rauch
autogenerated on Tue Oct 6 2020 03:38:57