blob: c1cf3a3217d5297f62070afd75f3ad0e21136c59 [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
Enrico Granata9bb17522019-06-28 17:22:42 -0700126bool FakeIioDevice::EnableBuffer(size_t n) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700127 buffer_length_ = n;
128 buffer_enabled_ = true;
129 return true;
130}
Enrico Granata9bb17522019-06-28 17:22:42 -0700131bool FakeIioDevice::DisableBuffer() {
Enrico Granata51cdb942019-06-18 16:40:17 -0700132 buffer_enabled_ = false;
133 return true;
134}
Enrico Granata9bb17522019-06-28 17:22:42 -0700135bool FakeIioDevice::IsBufferEnabled(size_t* n) const {
Enrico Granata51cdb942019-06-18 16:40:17 -0700136 if (n && buffer_enabled_)
137 *n = buffer_length_;
138 return buffer_enabled_;
139}
140
Harvey Yang3dfaed62020-05-19 17:29:02 +0800141base::Optional<int32_t> FakeIioDevice::GetBufferFd() {
142 if (disabled_fd_)
143 return base::nullopt;
144
145 if (!CreateBuffer())
146 return base::nullopt;
147
148 return sample_fd_.get();
149}
150base::Optional<IioDevice::IioSample> FakeIioDevice::ReadSample() {
Harvey Yange5e98a82020-06-01 17:31:41 +0800151 if (is_paused_ || disabled_fd_)
Harvey Yang3dfaed62020-05-19 17:29:02 +0800152 return base::nullopt;
153
154 if (!failed_read_queue_.empty()) {
155 CHECK_GE(failed_read_queue_.top(), sample_index_);
156 if (failed_read_queue_.top() == sample_index_) {
157 failed_read_queue_.pop();
158 return base::nullopt;
159 }
160 }
161
162 if (!CreateBuffer())
163 return base::nullopt;
164
165 if (!ReadByte())
166 return base::nullopt;
167
168 base::Optional<double> freq_opt = ReadDoubleAttribute(kSamplingFrequencyAttr);
169 if (!freq_opt.has_value()) {
170 LOG(ERROR) << "sampling_frequency not set";
171 return base::nullopt;
172 }
173 double frequency = freq_opt.value();
174 if (frequency <= 0.0) {
175 LOG(ERROR) << "Invalid frequency: " << frequency;
176 return base::nullopt;
177 }
178
179 IioDevice::IioSample sample;
Gwendal Grignoua1446472020-06-30 18:00:05 -0700180 auto channels = GetAllChannels();
181 for (int32_t i = 0; i < channels.size(); ++i) {
182 FakeIioChannel* chn = dynamic_cast<FakeIioChannel*>(channels[i]);
183 auto value = chn->GetData(sample_index_);
Harvey Yang3dfaed62020-05-19 17:29:02 +0800184 if (!value.has_value()) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800185 LOG(ERROR) << "Channel: " << channels_[i].chn_id << " has no sample";
Harvey Yang3dfaed62020-05-19 17:29:02 +0800186 return base::nullopt;
187 }
188
Harvey Yang9f48d812020-06-30 16:24:30 +0800189 sample[i] = value.value();
Harvey Yang3dfaed62020-05-19 17:29:02 +0800190 }
191
192 sample_index_ += 1;
193
194 if (sample_index_ < base::size(kFakeAccelSamples)) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800195 if (pause_index_.has_value() && sample_index_ == pause_index_.value())
196 SetPause();
197 else if (!WriteByte())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800198 return base::nullopt;
199 }
200
201 return sample;
202}
203
204void FakeIioDevice::DisableFd() {
205 disabled_fd_ = true;
206 if (readable_fd_)
207 CHECK(ReadByte());
208}
209
210void FakeIioDevice::AddFailedReadAtKthSample(int k) {
211 CHECK_GE(k, sample_index_);
212
213 failed_read_queue_.push(k);
214}
215
Harvey Yange5e98a82020-06-01 17:31:41 +0800216void FakeIioDevice::SetPauseCallbackAtKthSamples(
217 int k, base::OnceCallback<void()> callback) {
218 CHECK_GE(k, sample_index_);
219 CHECK_LE(k, base::size(kFakeAccelSamples));
220 CHECK(!pause_index_.has_value()); // pause callback hasn't been set
221
222 pause_index_ = k;
223 pause_callback_ = std::move(callback);
224
225 if (pause_index_.value() != sample_index_)
226 return;
227
228 SetPause();
229}
230
231void FakeIioDevice::ResumeReadingSamples() {
232 CHECK(is_paused_);
233
234 is_paused_ = false;
235 if (sample_fd_.is_valid() && !readable_fd_)
236 CHECK(WriteByte());
237}
238
Harvey Yang3dfaed62020-05-19 17:29:02 +0800239bool FakeIioDevice::CreateBuffer() {
240 CHECK(!disabled_fd_);
241
242 if (sample_fd_.is_valid())
243 return true;
244
245 int fd = eventfd(0, 0);
246 CHECK_GE(fd, 0);
247 sample_fd_.reset(fd);
248
Harvey Yange5e98a82020-06-01 17:31:41 +0800249 if (sample_index_ >= base::size(kFakeAccelSamples) || is_paused_)
Harvey Yang3dfaed62020-05-19 17:29:02 +0800250 return true;
251
252 if (!WriteByte()) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800253 ClosePipe();
Harvey Yang3dfaed62020-05-19 17:29:02 +0800254 return false;
255 }
256
257 return true;
258}
259
260bool FakeIioDevice::WriteByte() {
261 if (!sample_fd_.is_valid())
262 return false;
263
264 CHECK(!readable_fd_);
265 uint64_t val = 1;
266 CHECK_EQ(write(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
267 readable_fd_ = true;
268
269 return true;
270}
271
272bool FakeIioDevice::ReadByte() {
273 if (!sample_fd_.is_valid())
274 return false;
275
276 CHECK(readable_fd_);
277 int64_t val = 1;
278 CHECK_EQ(read(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
279 readable_fd_ = false;
280
281 return true;
282}
283
Harvey Yange5e98a82020-06-01 17:31:41 +0800284void FakeIioDevice::ClosePipe() {
Harvey Yang3dfaed62020-05-19 17:29:02 +0800285 sample_fd_.reset();
286}
287
Harvey Yange5e98a82020-06-01 17:31:41 +0800288void FakeIioDevice::SetPause() {
289 is_paused_ = true;
290 pause_index_.reset();
291 std::move(pause_callback_).Run();
292 if (readable_fd_)
293 CHECK(ReadByte());
294}
295
Gwendal Grignoua1446472020-06-30 18:00:05 -0700296void FakeIioContext::AddDevice(std::unique_ptr<FakeIioDevice> device) {
297 CHECK(device.get());
298 devices_.emplace(device->GetId(), std::move(device));
Enrico Granata51cdb942019-06-18 16:40:17 -0700299}
300
Gwendal Grignoua1446472020-06-30 18:00:05 -0700301void FakeIioContext::AddTrigger(std::unique_ptr<FakeIioDevice> trigger) {
302 CHECK(trigger.get());
303 triggers_.emplace(trigger->GetId(), std::move(trigger));
Harvey Yang9260b662019-08-12 15:48:03 +0800304}
305
306std::vector<IioDevice*> FakeIioContext::GetDevicesByName(
307 const std::string& name) {
308 return GetFakeByName(name, devices_);
309}
310
311IioDevice* FakeIioContext::GetDeviceById(int id) {
312 return GetFakeById(id, devices_);
313}
314
315std::vector<IioDevice*> FakeIioContext::GetAllDevices() {
316 return GetFakeAll(devices_);
317}
318
319std::vector<IioDevice*> FakeIioContext::GetTriggersByName(
320 const std::string& name) {
321 return GetFakeByName(name, triggers_);
322}
323
324IioDevice* FakeIioContext::GetTriggerById(int id) {
325 return GetFakeById(id, triggers_);
326}
327
328std::vector<IioDevice*> FakeIioContext::GetAllTriggers() {
329 return GetFakeAll(triggers_);
330}
331
332IioDevice* FakeIioContext::GetFakeById(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700333 int id, const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800334 auto k = devices_map.find(id);
Gwendal Grignoua1446472020-06-30 18:00:05 -0700335 return (k == devices_map.end()) ? nullptr : k->second.get();
Harvey Yang9260b662019-08-12 15:48:03 +0800336}
337
338std::vector<IioDevice*> FakeIioContext::GetFakeByName(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700339 const std::string& name,
340 const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800341 std::vector<IioDevice*> devices;
342 for (auto const& it : devices_map) {
343 if (name.compare(it.second->GetName()) == 0)
Gwendal Grignoua1446472020-06-30 18:00:05 -0700344 devices.push_back(it.second.get());
Harvey Yang9260b662019-08-12 15:48:03 +0800345 }
346
347 return devices;
348}
349
350std::vector<IioDevice*> FakeIioContext::GetFakeAll(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700351 const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800352 std::vector<IioDevice*> devices;
353 for (auto const& it : devices_map)
Gwendal Grignoua1446472020-06-30 18:00:05 -0700354 devices.push_back(it.second.get());
Harvey Yang9260b662019-08-12 15:48:03 +0800355
356 return devices;
Enrico Granata51cdb942019-06-18 16:40:17 -0700357}
358
Enrico Granata9bb17522019-06-28 17:22:42 -0700359} // namespace fakes
Enrico Granata51cdb942019-06-18 16:40:17 -0700360} // namespace libmems