forked from dimitry-ishenko-cpp/firmata
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.hpp
184 lines (140 loc) · 5.45 KB
/
client.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017 Dimitry Ishenko
// Contact: dimitry (dot) ishenko (at) (gee) mail (dot) com
//
// Distributed under the GNU GPL license. See the LICENSE.md file for details.
////////////////////////////////////////////////////////////////////////////////
#ifndef FIRMATA_CLIENT_HPP
#define FIRMATA_CLIENT_HPP
////////////////////////////////////////////////////////////////////////////////
#include "firmata/call_chain.hpp"
#include "firmata/io_base.hpp"
#include "firmata/pins.hpp"
#include "firmata/types.hpp"
#include <algorithm>
#include <array>
#include <bitset>
#include <chrono>
#include <string>
#include <stdexcept>
#include <utility>
////////////////////////////////////////////////////////////////////////////////
namespace firmata
{
////////////////////////////////////////////////////////////////////////////////
struct timeout_error : public std::runtime_error { using std::runtime_error::runtime_error; };
namespace literals { enum dont_reset_t { dont_reset }; }
using namespace literals;
////////////////////////////////////////////////////////////////////////////////
class client
{
public:
////////////////////
client() = default;
explicit client(io_base& io) : client(&io, false) { }
client(io_base& io, dont_reset_t) : client(&io, true) { }
~client() noexcept;
client(const client&) = delete;
client(client&& rhs) noexcept { swap(rhs); }
client& operator=(const client&) = delete;
client& operator=(client&& rhs) noexcept { swap(rhs); return *this; }
void swap(client&) noexcept;
////////////////////
bool valid() const noexcept { return io_; }
explicit operator bool() const noexcept { return valid(); }
////////////////////
// protocol version
auto const& protocol() const noexcept { return protocol_; }
// firmware name & version
auto const& firmware() const noexcept { return firmware_; }
// reset host
void reset();
// set new read timeout
template<typename Rep, typename Period>
static void timeout(const std::chrono::duration<Rep, Period>&);
static void timeout(const sec& time) noexcept { time_ = time; }
// current read timeout
static auto const& timeout() noexcept { return time_; }
////////////////////
// send string to host
void string(const std::string& s);
// last string received from host
auto const& string() const noexcept { return string_; }
using string_call = call<void(const std::string&)>;
// install string changed callback
cid on_string_changed(string_call fn) { return chain_.insert(std::move(fn)); }
// remove callback
bool remove_call(cid id) { return chain_.erase(id); }
////////////////////
// get all pins (for use in range-based "for" loops)
firmata::pins& pins() noexcept { return pins_; }
firmata::pins const& pins() const noexcept { return pins_; }
// get pin
firmata::pin& pin(pos n) { return pins_.get(n); }
firmata::pin const& pin(pos n) const { return pins_.get(n); }
// get analog pin
firmata::pin& pin(analog n) { return pins_.get(analog_in, n); }
firmata::pin const& pin(analog n) const { return pins_.get(analog_in, n); }
// get pin that supports certain mode
firmata::pin& pin(mode m, pos n) { return pins_.get(m, n); }
firmata::pin const& pin(mode m, pos n) const { return pins_.get(m, n); }
////////////////////
// print out host info (for debugging only)
void info();
private:
////////////////////
client(io_base*, bool dont_reset);
io_base* io_ = nullptr;
cid id_;
firmata::protocol protocol_ { 0, 0 };
firmata::firmware firmware_ { 0, 0 };
firmata::pins pins_;
firmata::pin::delegate delegate_;
std::string string_;
call_chain<string_call> chain_;
static sec time_;
////////////////////
// enable/disable reporting for a digital pin
void report_digital(pos, bool);
// enable/disable reporting for an analog pin
void report_analog(pos, bool);
// set digital pin value
void digital_value(pos, bool);
// set analog pin value
void analog_value(pos, int);
// set pin mode
void pin_mode(pos, mode);
// reset host
void reset_();
// query protocol version
void query_version();
// query firmware name & version
void query_firmware();
// query capability (pins, modes and reses)
void query_capability();
// query analog pin mapping
void query_analog_mapping();
// query current pin state
void query_state();
// enable reporting for all inputs
// and disable for all outputs
void set_report();
// read messages from host
void async_read(msg_id, const payload&);
////////////////////
// ports that are currently being monitored
std::array<std::bitset<8>, port_count> ports_;
// wait for specific message
payload wait_until(msg_id);
};
////////////////////////////////////////////////////////////////////////////////
template<typename Rep, typename Period>
inline void
client::timeout(const std::chrono::duration<Rep, Period>& time)
{ timeout(std::chrono::duration_cast<sec>(time)); }
////////////////////////////////////////////////////////////////////////////////
inline void swap(client& lhs, client& rhs) noexcept { lhs.swap(rhs); }
////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
#endif