-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpackaging.h
More file actions
173 lines (142 loc) · 5.71 KB
/
packaging.h
File metadata and controls
173 lines (142 loc) · 5.71 KB
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
#pragma once
#include "protocol.h"
#include "flags.h"
#include <deque>
namespace CS {
constexpr size_t max_path_len = 128;
constexpr size_t max_requests = 50;
class PackagedWired;
class Requester {
const size_t m_offset = 0;
public:
Requester() = default;
Requester(const char* req_buf) { memcpy(get_as_data(), req_buf, get_as_data_len()); }
Requester(const size_t off) : m_offset(off) {}
Requester(const int off) : m_offset(static_cast<size_t>(off)) {}
size_t get_offset() const { return m_offset; }
char* get_as_data() { return (char*)this; }
const char* get_as_data() const { return (char*)this; }
size_t get_as_data_len() const { return sizeof(*this); }
};
struct Command {
enum class vtype : uint8_t { INVALID, TD, TF, TI, TU, REQUEST = std::numeric_limits<uint8_t>::max() };
union _ {
double d;
float f;
int64_t i;
uint64_t u;
_() : d(0.0) {}
_(double _d) : d(_d) {}
_(float _f) : f(_f) {}
_(int64_t _i) : i(_i) {}
_(uint64_t _u) : u(_u) {}
void operator=(double _d) { d = _d; }
void operator=(float _f) { f = _f; }
void operator=(int64_t _i) { i = _i; }
void operator=(uint64_t _u) { u = _u; }
operator double() const { return d; }
operator float() const { return f; }
operator int64_t() const { return i; }
operator uint64_t() const { return u; }
};
private:
char m_path[max_path_len]{};
_ m_val{0.0f};
vtype m_type = vtype::INVALID;
void _set_val(double _d) { m_val = _d; m_type = vtype::TD; }
void _set_val(float _f) { m_val = _f; m_type = vtype::TF; }
void _set_val(int64_t _i) { m_val = _i; m_type = vtype::TI; }
void _set_val(uint64_t _u) { m_val = _u; m_type = vtype::TU; }
public:
// as invalid
Command() = default;
Command(Command&& o) { memcpy(get_as_data(), o.get_as_data(), get_as_data_len()); }
Command(const Command& o) { memcpy(get_as_data(), o.get_as_data(), get_as_data_len()); }
void operator=(Command&& o) { memcpy(get_as_data(), o.get_as_data(), get_as_data_len()); }
void operator=(const Command& o) { memcpy(get_as_data(), o.get_as_data(), get_as_data_len()); }
template<typename T>
Command(const char* path, const T& value)
{
const auto len = strlen(path);
memcpy(m_path, path, (len + 1) > max_path_len ? max_path_len : len + 1);
_set_val(value);
}
template<typename T>
T get_val() const { return (T)m_val;}
const char* get_path() const { return m_path; }
vtype get_type() const { return m_type; }
bool valid() const {
return
m_type == vtype::TD ||
m_type == vtype::TF ||
m_type == vtype::TI ||
m_type == vtype::TU ||
m_type == vtype::REQUEST;
}
char* get_as_data() { return (char*)this; }
const char* get_as_data() const { return (char*)this; }
size_t get_as_data_len() const { return sizeof(*this); }
};
class PackagedWired : public Wired {
public:
PackagedWired(const config& cfg) : Wired(cfg) {}
Command master_do(device_id to, const Requester& req) {
CS_LOGF("PackagedWired master_do about to request %zu from %hu\n", req.get_offset(), (uint16_t)d2u(to));
Command cmd;
this->Wired::master_do(to,
req.get_as_data(), static_cast<uint8_t>(req.get_as_data_len()),
cmd.get_as_data(), static_cast<uint8_t>(cmd.get_as_data_len())
);
return cmd; // if master_do fails, cmd will be invalid anyway. No need to check.
}
std::deque<Command> master_request_all(device_id to)
{
std::deque<Command> cmds;
for(size_t p = 0; p < max_requests; ++p)
{
Requester req(p);
Command cmd = master_do(to, req);
if (!cmd.valid()) break;
cmds.push_back(cmd);
}
return cmds;
}
std::deque<Command> master_smart_request_all(device_id to, FlagWrapper& fw, bool& answered)
{
std::deque<Command> cmds;
const auto autofill_rest = [&]{
for(size_t p = 1; p < max_requests; ++p)
{
Requester req(p);
Command cmd = master_do(to, req);
if (!cmd.valid()) break;
cmds.push_back(cmd);
}
};
Requester req(0);
Command cmd = master_do(to, req);
if (!cmd.valid()) {
answered = false;
return cmds;
}
answered = true;
// if, supports
if (strcmp("#FLAGS", cmd.get_path()) == 0 && cmd.get_type() == Command::vtype::TU)
{
fw = FlagWrapper(cmd.get_val<uint64_t>());
if (fw & device_flags::HAS_NEW_DATA) {
autofill_rest(); // only autofill if has new data
}
// it should not care about errors here.
}
else { // no support
cmds.push_back(cmd);
autofill_rest();
}
return cmds;
}
void slave_reply_from_callback(const Command& cmd) {
this->Wired::slave_reply_from_callback(cmd.get_as_data(), cmd.get_as_data_len());
}
};
}