blob: c48587fcb4371cff14438ea5aff0f87c76e1c2b7 [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;
Harvey Yang9f48d812020-06-30 16:24:30 +0800128 for (const auto& channel_data : channels_)
129 channels.push_back(channel_data.chn);
Harvey Yangb0c30962019-09-17 15:00:25 +0800130
131 return channels;
132}
133
Harvey Yang9f48d812020-06-30 16:24:30 +0800134IioChannel* FakeIioDevice::GetChannel(int32_t index) {
135 if (index < 0 || index >= channels_.size())
Enrico Granata51cdb942019-06-18 16:40:17 -0700136 return nullptr;
Harvey Yang9f48d812020-06-30 16:24:30 +0800137
138 return channels_[index].chn;
139}
140
141IioChannel* FakeIioDevice::GetChannel(const std::string& id) {
142 for (size_t i = 0; i < channels_.size(); ++i) {
143 if (id == channels_[i].chn_id)
144 return channels_[i].chn;
145 }
146
147 return nullptr;
Enrico Granata51cdb942019-06-18 16:40:17 -0700148}
149
Enrico Granata9bb17522019-06-28 17:22:42 -0700150bool FakeIioDevice::EnableBuffer(size_t n) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700151 buffer_length_ = n;
152 buffer_enabled_ = true;
153 return true;
154}
Enrico Granata9bb17522019-06-28 17:22:42 -0700155bool FakeIioDevice::DisableBuffer() {
Enrico Granata51cdb942019-06-18 16:40:17 -0700156 buffer_enabled_ = false;
157 return true;
158}
Enrico Granata9bb17522019-06-28 17:22:42 -0700159bool FakeIioDevice::IsBufferEnabled(size_t* n) const {
Enrico Granata51cdb942019-06-18 16:40:17 -0700160 if (n && buffer_enabled_)
161 *n = buffer_length_;
162 return buffer_enabled_;
163}
164
Harvey Yang3dfaed62020-05-19 17:29:02 +0800165base::Optional<int32_t> FakeIioDevice::GetBufferFd() {
166 if (disabled_fd_)
167 return base::nullopt;
168
169 if (!CreateBuffer())
170 return base::nullopt;
171
172 return sample_fd_.get();
173}
174base::Optional<IioDevice::IioSample> FakeIioDevice::ReadSample() {
Harvey Yange5e98a82020-06-01 17:31:41 +0800175 if (is_paused_ || disabled_fd_)
Harvey Yang3dfaed62020-05-19 17:29:02 +0800176 return base::nullopt;
177
178 if (!failed_read_queue_.empty()) {
179 CHECK_GE(failed_read_queue_.top(), sample_index_);
180 if (failed_read_queue_.top() == sample_index_) {
181 failed_read_queue_.pop();
182 return base::nullopt;
183 }
184 }
185
186 if (!CreateBuffer())
187 return base::nullopt;
188
189 if (!ReadByte())
190 return base::nullopt;
191
192 base::Optional<double> freq_opt = ReadDoubleAttribute(kSamplingFrequencyAttr);
193 if (!freq_opt.has_value()) {
194 LOG(ERROR) << "sampling_frequency not set";
195 return base::nullopt;
196 }
197 double frequency = freq_opt.value();
198 if (frequency <= 0.0) {
199 LOG(ERROR) << "Invalid frequency: " << frequency;
200 return base::nullopt;
201 }
202
203 IioDevice::IioSample sample;
Harvey Yang9f48d812020-06-30 16:24:30 +0800204 for (int32_t i = 0; i < channels_.size(); ++i) {
205 auto value = channels_[i].chn->GetData(sample_index_);
Harvey Yang3dfaed62020-05-19 17:29:02 +0800206 if (!value.has_value()) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800207 LOG(ERROR) << "Channel: " << channels_[i].chn_id << " has no sample";
Harvey Yang3dfaed62020-05-19 17:29:02 +0800208 return base::nullopt;
209 }
210
Harvey Yang9f48d812020-06-30 16:24:30 +0800211 sample[i] = value.value();
Harvey Yang3dfaed62020-05-19 17:29:02 +0800212 }
213
214 sample_index_ += 1;
215
216 if (sample_index_ < base::size(kFakeAccelSamples)) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800217 if (pause_index_.has_value() && sample_index_ == pause_index_.value())
218 SetPause();
219 else if (!WriteByte())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800220 return base::nullopt;
221 }
222
223 return sample;
224}
225
226void FakeIioDevice::DisableFd() {
227 disabled_fd_ = true;
228 if (readable_fd_)
229 CHECK(ReadByte());
230}
231
232void FakeIioDevice::AddFailedReadAtKthSample(int k) {
233 CHECK_GE(k, sample_index_);
234
235 failed_read_queue_.push(k);
236}
237
Harvey Yange5e98a82020-06-01 17:31:41 +0800238void FakeIioDevice::SetPauseCallbackAtKthSamples(
239 int k, base::OnceCallback<void()> callback) {
240 CHECK_GE(k, sample_index_);
241 CHECK_LE(k, base::size(kFakeAccelSamples));
242 CHECK(!pause_index_.has_value()); // pause callback hasn't been set
243
244 pause_index_ = k;
245 pause_callback_ = std::move(callback);
246
247 if (pause_index_.value() != sample_index_)
248 return;
249
250 SetPause();
251}
252
253void FakeIioDevice::ResumeReadingSamples() {
254 CHECK(is_paused_);
255
256 is_paused_ = false;
257 if (sample_fd_.is_valid() && !readable_fd_)
258 CHECK(WriteByte());
259}
260
Harvey Yang3dfaed62020-05-19 17:29:02 +0800261bool FakeIioDevice::CreateBuffer() {
262 CHECK(!disabled_fd_);
263
264 if (sample_fd_.is_valid())
265 return true;
266
267 int fd = eventfd(0, 0);
268 CHECK_GE(fd, 0);
269 sample_fd_.reset(fd);
270
Harvey Yange5e98a82020-06-01 17:31:41 +0800271 if (sample_index_ >= base::size(kFakeAccelSamples) || is_paused_)
Harvey Yang3dfaed62020-05-19 17:29:02 +0800272 return true;
273
274 if (!WriteByte()) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800275 ClosePipe();
Harvey Yang3dfaed62020-05-19 17:29:02 +0800276 return false;
277 }
278
279 return true;
280}
281
282bool FakeIioDevice::WriteByte() {
283 if (!sample_fd_.is_valid())
284 return false;
285
286 CHECK(!readable_fd_);
287 uint64_t val = 1;
288 CHECK_EQ(write(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
289 readable_fd_ = true;
290
291 return true;
292}
293
294bool FakeIioDevice::ReadByte() {
295 if (!sample_fd_.is_valid())
296 return false;
297
298 CHECK(readable_fd_);
299 int64_t val = 1;
300 CHECK_EQ(read(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
301 readable_fd_ = false;
302
303 return true;
304}
305
Harvey Yange5e98a82020-06-01 17:31:41 +0800306void FakeIioDevice::ClosePipe() {
Harvey Yang3dfaed62020-05-19 17:29:02 +0800307 sample_fd_.reset();
308}
309
Harvey Yange5e98a82020-06-01 17:31:41 +0800310void FakeIioDevice::SetPause() {
311 is_paused_ = true;
312 pause_index_.reset();
313 std::move(pause_callback_).Run();
314 if (readable_fd_)
315 CHECK(ReadByte());
316}
317
Enrico Granata9bb17522019-06-28 17:22:42 -0700318void FakeIioContext::AddDevice(FakeIioDevice* device) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700319 CHECK(device);
Enrico Granata51cdb942019-06-18 16:40:17 -0700320 devices_.emplace(device->GetId(), device);
321}
322
Harvey Yang9260b662019-08-12 15:48:03 +0800323void FakeIioContext::AddTrigger(FakeIioDevice* trigger) {
324 CHECK(trigger);
325 triggers_.emplace(trigger->GetId(), trigger);
326}
327
328std::vector<IioDevice*> FakeIioContext::GetDevicesByName(
329 const std::string& name) {
330 return GetFakeByName(name, devices_);
331}
332
333IioDevice* FakeIioContext::GetDeviceById(int id) {
334 return GetFakeById(id, devices_);
335}
336
337std::vector<IioDevice*> FakeIioContext::GetAllDevices() {
338 return GetFakeAll(devices_);
339}
340
341std::vector<IioDevice*> FakeIioContext::GetTriggersByName(
342 const std::string& name) {
343 return GetFakeByName(name, triggers_);
344}
345
346IioDevice* FakeIioContext::GetTriggerById(int id) {
347 return GetFakeById(id, triggers_);
348}
349
350std::vector<IioDevice*> FakeIioContext::GetAllTriggers() {
351 return GetFakeAll(triggers_);
352}
353
354IioDevice* FakeIioContext::GetFakeById(
355 int id, const std::map<int, FakeIioDevice*>& devices_map) {
356 auto k = devices_map.find(id);
357 return (k == devices_map.end()) ? nullptr : k->second;
358}
359
360std::vector<IioDevice*> FakeIioContext::GetFakeByName(
361 const std::string& name, const std::map<int, FakeIioDevice*>& devices_map) {
362 std::vector<IioDevice*> devices;
363 for (auto const& it : devices_map) {
364 if (name.compare(it.second->GetName()) == 0)
365 devices.push_back(it.second);
366 }
367
368 return devices;
369}
370
371std::vector<IioDevice*> FakeIioContext::GetFakeAll(
372 const std::map<int, FakeIioDevice*>& devices_map) {
373 std::vector<IioDevice*> devices;
374 for (auto const& it : devices_map)
375 devices.push_back(it.second);
376
377 return devices;
Enrico Granata51cdb942019-06-18 16:40:17 -0700378}
379
Enrico Granata9bb17522019-06-28 17:22:42 -0700380} // namespace fakes
Enrico Granata51cdb942019-06-18 16:40:17 -0700381} // namespace libmems