blob: 69e02ea2d405ff0ed464fedbc78b8e2b70b37173 [file] [log] [blame]
Enrico Granata51cdb942019-06-18 16:40:17 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Enrico Granata9bb17522019-06-28 17:22:42 -07005#include "libmems/test_fakes.h"
Enrico Granata51cdb942019-06-18 16:40:17 -07006
Harvey Yang3dfaed62020-05-19 17:29:02 +08007#include <sys/eventfd.h>
8
9#include <base/files/file_util.h>
Enrico Granata51cdb942019-06-18 16:40:17 -070010#include <base/logging.h>
Harvey Yang3dfaed62020-05-19 17:29:02 +080011#include "base/posix/eintr_wrapper.h"
12#include <base/stl_util.h>
Enrico Granata51cdb942019-06-18 16:40:17 -070013
Harvey Yang9260b662019-08-12 15:48:03 +080014#include "libmems/common_types.h"
15
Enrico Granata51cdb942019-06-18 16:40:17 -070016namespace libmems {
Enrico Granata9bb17522019-06-28 17:22:42 -070017namespace fakes {
Enrico Granata51cdb942019-06-18 16:40:17 -070018
Enrico Granata9bb17522019-06-28 17:22:42 -070019FakeIioChannel::FakeIioChannel(const std::string& id, bool enabled)
Enrico Granata51cdb942019-06-18 16:40:17 -070020 : id_(id), enabled_(enabled) {}
21
Enrico Granata9bb17522019-06-28 17:22:42 -070022bool FakeIioChannel::SetEnabled(bool en) {
Enrico Granata51cdb942019-06-18 16:40:17 -070023 enabled_ = en;
24 return true;
25}
26
Gwendal Grignou197d5162019-11-20 16:46:02 -080027template <typename T> base::Optional<T> FakeReadAttributes(
28 const std::string& name,
29 std::map<std::string, T> attributes) {
30 auto k = attributes.find(name);
31 if (k == attributes.end())
Enrico Granata064a25c2019-07-15 15:48:03 -070032 return base::nullopt;
33 return k->second;
34}
Gwendal Grignou197d5162019-11-20 16:46:02 -080035
36base::Optional<std::string> FakeIioChannel::ReadStringAttribute(
37 const std::string& name) const {
38 return FakeReadAttributes<>(name, text_attributes_);
39}
Enrico Granata064a25c2019-07-15 15:48:03 -070040base::Optional<int64_t> FakeIioChannel::ReadNumberAttribute(
41 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -080042 return FakeReadAttributes<>(name, numeric_attributes_);
Enrico Granata064a25c2019-07-15 15:48:03 -070043}
Harvey Yang9903fc22020-03-16 14:22:53 +080044base::Optional<double> FakeIioChannel::ReadDoubleAttribute(
45 const std::string& name) const {
46 return FakeReadAttributes<>(name, double_attributes_);
Enrico Granata064a25c2019-07-15 15:48:03 -070047}
Harvey Yang9903fc22020-03-16 14:22:53 +080048
49bool FakeIioChannel::WriteStringAttribute(const std::string& name,
50 const std::string& value) {
51 text_attributes_[name] = value;
52 return true;
53}
54bool FakeIioChannel::WriteNumberAttribute(const std::string& name,
55 int64_t value) {
Enrico Granata064a25c2019-07-15 15:48:03 -070056 numeric_attributes_[name] = value;
Harvey Yang9903fc22020-03-16 14:22:53 +080057 return true;
58}
59bool FakeIioChannel::WriteDoubleAttribute(const std::string& name,
60 double value) {
61 double_attributes_[name] = value;
62 return true;
Enrico Granata064a25c2019-07-15 15:48:03 -070063}
64
Harvey Yang3dfaed62020-05-19 17:29:02 +080065base::Optional<int64_t> FakeIioChannel::GetData(int index) {
66 if (!enabled_ || index < 0 || index >= base::size(kFakeAccelSamples))
67 return base::nullopt;
68
69 auto raw = ReadNumberAttribute(kRawAttr);
70 if (raw.has_value())
71 return raw;
72
73 for (int i = 0; i < base::size(kFakeAccelChns); ++i) {
74 if (id_.compare(kFakeAccelChns[i]) == 0)
75 return kFakeAccelSamples[index][i];
76 }
77
78 return base::nullopt;
79}
80
Enrico Granata9bb17522019-06-28 17:22:42 -070081FakeIioDevice::FakeIioDevice(FakeIioContext* ctx,
Enrico Granata51cdb942019-06-18 16:40:17 -070082 const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +080083 int id)
Enrico Granata51cdb942019-06-18 16:40:17 -070084 : IioDevice(), context_(ctx), name_(name), id_(id) {}
85
Harvey Yang9260b662019-08-12 15:48:03 +080086base::FilePath FakeIioDevice::GetPath() const {
87 std::string id_str(kDeviceIdPrefix);
88 id_str.append(std::to_string(GetId()));
89 return base::FilePath("/sys/bus/iio/devices").Append(id_str);
90}
91
Enrico Granata9bb17522019-06-28 17:22:42 -070092base::Optional<std::string> FakeIioDevice::ReadStringAttribute(
Enrico Granata51cdb942019-06-18 16:40:17 -070093 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -080094 return FakeReadAttributes<>(name, text_attributes_);
Enrico Granata51cdb942019-06-18 16:40:17 -070095}
Enrico Granata9bb17522019-06-28 17:22:42 -070096base::Optional<int64_t> FakeIioDevice::ReadNumberAttribute(
Enrico Granata51cdb942019-06-18 16:40:17 -070097 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -080098 return FakeReadAttributes<>(name, numeric_attributes_);
Enrico Granata51cdb942019-06-18 16:40:17 -070099}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700100base::Optional<double> FakeIioDevice::ReadDoubleAttribute(
101 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -0800102 return FakeReadAttributes<>(name, double_attributes_);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700103}
Enrico Granata51cdb942019-06-18 16:40:17 -0700104
Enrico Granata9bb17522019-06-28 17:22:42 -0700105bool FakeIioDevice::WriteStringAttribute(const std::string& name,
Enrico Granata51cdb942019-06-18 16:40:17 -0700106 const std::string& value) {
107 text_attributes_[name] = value;
108 return true;
109}
Enrico Granata9bb17522019-06-28 17:22:42 -0700110bool FakeIioDevice::WriteNumberAttribute(const std::string& name,
Enrico Granata51cdb942019-06-18 16:40:17 -0700111 int64_t value) {
112 numeric_attributes_[name] = value;
113 return true;
114}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700115bool FakeIioDevice::WriteDoubleAttribute(const std::string& name,
116 double value) {
117 double_attributes_[name] = value;
118 return true;
119}
Enrico Granata51cdb942019-06-18 16:40:17 -0700120
Enrico Granata9bb17522019-06-28 17:22:42 -0700121bool FakeIioDevice::SetTrigger(IioDevice* trigger) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700122 trigger_ = trigger;
123 return true;
124}
125
Harvey Yangb0c30962019-09-17 15:00:25 +0800126std::vector<IioChannel*> FakeIioDevice::GetAllChannels() {
127 std::vector<IioChannel*> channels;
128 for (auto channel : channels_)
129 channels.push_back(channel.second);
130
131 return channels;
132}
133
Enrico Granata9bb17522019-06-28 17:22:42 -0700134IioChannel* FakeIioDevice::GetChannel(const std::string& id) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700135 auto k = channels_.find(id);
136 if (k == channels_.end())
137 return nullptr;
138 return k->second;
139}
140
Enrico Granata9bb17522019-06-28 17:22:42 -0700141bool FakeIioDevice::EnableBuffer(size_t n) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700142 buffer_length_ = n;
143 buffer_enabled_ = true;
144 return true;
145}
Enrico Granata9bb17522019-06-28 17:22:42 -0700146bool FakeIioDevice::DisableBuffer() {
Enrico Granata51cdb942019-06-18 16:40:17 -0700147 buffer_enabled_ = false;
148 return true;
149}
Enrico Granata9bb17522019-06-28 17:22:42 -0700150bool FakeIioDevice::IsBufferEnabled(size_t* n) const {
Enrico Granata51cdb942019-06-18 16:40:17 -0700151 if (n && buffer_enabled_)
152 *n = buffer_length_;
153 return buffer_enabled_;
154}
155
Harvey Yang3dfaed62020-05-19 17:29:02 +0800156base::Optional<int32_t> FakeIioDevice::GetBufferFd() {
157 if (disabled_fd_)
158 return base::nullopt;
159
160 if (!CreateBuffer())
161 return base::nullopt;
162
163 return sample_fd_.get();
164}
165base::Optional<IioDevice::IioSample> FakeIioDevice::ReadSample() {
Harvey Yange5e98a82020-06-01 17:31:41 +0800166 if (is_paused_ || disabled_fd_)
Harvey Yang3dfaed62020-05-19 17:29:02 +0800167 return base::nullopt;
168
169 if (!failed_read_queue_.empty()) {
170 CHECK_GE(failed_read_queue_.top(), sample_index_);
171 if (failed_read_queue_.top() == sample_index_) {
172 failed_read_queue_.pop();
173 return base::nullopt;
174 }
175 }
176
177 if (!CreateBuffer())
178 return base::nullopt;
179
180 if (!ReadByte())
181 return base::nullopt;
182
183 base::Optional<double> freq_opt = ReadDoubleAttribute(kSamplingFrequencyAttr);
184 if (!freq_opt.has_value()) {
185 LOG(ERROR) << "sampling_frequency not set";
186 return base::nullopt;
187 }
188 double frequency = freq_opt.value();
189 if (frequency <= 0.0) {
190 LOG(ERROR) << "Invalid frequency: " << frequency;
191 return base::nullopt;
192 }
193
194 IioDevice::IioSample sample;
195 for (auto channel : channels_) {
196 auto value = channel.second->GetData(sample_index_);
197 if (!value.has_value()) {
198 LOG(ERROR) << "Channel: " << channel.second->GetId() << " has no sample";
199 return base::nullopt;
200 }
201
202 sample[channel.second->GetId()] = value.value();
203 }
204
205 sample_index_ += 1;
206
207 if (sample_index_ < base::size(kFakeAccelSamples)) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800208 if (pause_index_.has_value() && sample_index_ == pause_index_.value())
209 SetPause();
210 else if (!WriteByte())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800211 return base::nullopt;
212 }
213
214 return sample;
215}
216
217void FakeIioDevice::DisableFd() {
218 disabled_fd_ = true;
219 if (readable_fd_)
220 CHECK(ReadByte());
221}
222
223void FakeIioDevice::AddFailedReadAtKthSample(int k) {
224 CHECK_GE(k, sample_index_);
225
226 failed_read_queue_.push(k);
227}
228
Harvey Yange5e98a82020-06-01 17:31:41 +0800229void FakeIioDevice::SetPauseCallbackAtKthSamples(
230 int k, base::OnceCallback<void()> callback) {
231 CHECK_GE(k, sample_index_);
232 CHECK_LE(k, base::size(kFakeAccelSamples));
233 CHECK(!pause_index_.has_value()); // pause callback hasn't been set
234
235 pause_index_ = k;
236 pause_callback_ = std::move(callback);
237
238 if (pause_index_.value() != sample_index_)
239 return;
240
241 SetPause();
242}
243
244void FakeIioDevice::ResumeReadingSamples() {
245 CHECK(is_paused_);
246
247 is_paused_ = false;
248 if (sample_fd_.is_valid() && !readable_fd_)
249 CHECK(WriteByte());
250}
251
Harvey Yang3dfaed62020-05-19 17:29:02 +0800252bool FakeIioDevice::CreateBuffer() {
253 CHECK(!disabled_fd_);
254
255 if (sample_fd_.is_valid())
256 return true;
257
258 int fd = eventfd(0, 0);
259 CHECK_GE(fd, 0);
260 sample_fd_.reset(fd);
261
Harvey Yange5e98a82020-06-01 17:31:41 +0800262 if (sample_index_ >= base::size(kFakeAccelSamples) || is_paused_)
Harvey Yang3dfaed62020-05-19 17:29:02 +0800263 return true;
264
265 if (!WriteByte()) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800266 ClosePipe();
Harvey Yang3dfaed62020-05-19 17:29:02 +0800267 return false;
268 }
269
270 return true;
271}
272
273bool FakeIioDevice::WriteByte() {
274 if (!sample_fd_.is_valid())
275 return false;
276
277 CHECK(!readable_fd_);
278 uint64_t val = 1;
279 CHECK_EQ(write(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
280 readable_fd_ = true;
281
282 return true;
283}
284
285bool FakeIioDevice::ReadByte() {
286 if (!sample_fd_.is_valid())
287 return false;
288
289 CHECK(readable_fd_);
290 int64_t val = 1;
291 CHECK_EQ(read(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
292 readable_fd_ = false;
293
294 return true;
295}
296
Harvey Yange5e98a82020-06-01 17:31:41 +0800297void FakeIioDevice::ClosePipe() {
Harvey Yang3dfaed62020-05-19 17:29:02 +0800298 sample_fd_.reset();
299}
300
Harvey Yange5e98a82020-06-01 17:31:41 +0800301void FakeIioDevice::SetPause() {
302 is_paused_ = true;
303 pause_index_.reset();
304 std::move(pause_callback_).Run();
305 if (readable_fd_)
306 CHECK(ReadByte());
307}
308
Enrico Granata9bb17522019-06-28 17:22:42 -0700309void FakeIioContext::AddDevice(FakeIioDevice* device) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700310 CHECK(device);
Enrico Granata51cdb942019-06-18 16:40:17 -0700311 devices_.emplace(device->GetId(), device);
312}
313
Harvey Yang9260b662019-08-12 15:48:03 +0800314void FakeIioContext::AddTrigger(FakeIioDevice* trigger) {
315 CHECK(trigger);
316 triggers_.emplace(trigger->GetId(), trigger);
317}
318
319std::vector<IioDevice*> FakeIioContext::GetDevicesByName(
320 const std::string& name) {
321 return GetFakeByName(name, devices_);
322}
323
324IioDevice* FakeIioContext::GetDeviceById(int id) {
325 return GetFakeById(id, devices_);
326}
327
328std::vector<IioDevice*> FakeIioContext::GetAllDevices() {
329 return GetFakeAll(devices_);
330}
331
332std::vector<IioDevice*> FakeIioContext::GetTriggersByName(
333 const std::string& name) {
334 return GetFakeByName(name, triggers_);
335}
336
337IioDevice* FakeIioContext::GetTriggerById(int id) {
338 return GetFakeById(id, triggers_);
339}
340
341std::vector<IioDevice*> FakeIioContext::GetAllTriggers() {
342 return GetFakeAll(triggers_);
343}
344
345IioDevice* FakeIioContext::GetFakeById(
346 int id, const std::map<int, FakeIioDevice*>& devices_map) {
347 auto k = devices_map.find(id);
348 return (k == devices_map.end()) ? nullptr : k->second;
349}
350
351std::vector<IioDevice*> FakeIioContext::GetFakeByName(
352 const std::string& name, const std::map<int, FakeIioDevice*>& devices_map) {
353 std::vector<IioDevice*> devices;
354 for (auto const& it : devices_map) {
355 if (name.compare(it.second->GetName()) == 0)
356 devices.push_back(it.second);
357 }
358
359 return devices;
360}
361
362std::vector<IioDevice*> FakeIioContext::GetFakeAll(
363 const std::map<int, FakeIioDevice*>& devices_map) {
364 std::vector<IioDevice*> devices;
365 for (auto const& it : devices_map)
366 devices.push_back(it.second);
367
368 return devices;
Enrico Granata51cdb942019-06-18 16:40:17 -0700369}
370
Enrico Granata9bb17522019-06-28 17:22:42 -0700371} // namespace fakes
Enrico Granata51cdb942019-06-18 16:40:17 -0700372} // namespace libmems