blob: 4a606eeb8994d537089a717f4ab3c57f7c6ad81e [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
Harvey Yang2c08cf72020-09-24 12:36:23 +080022void FakeIioChannel::SetEnabled(bool en) {
Enrico Granata51cdb942019-06-18 16:40:17 -070023 enabled_ = en;
Harvey Yang2c08cf72020-09-24 12:36:23 +080024}
25
26bool FakeIioChannel::SetScanElementsEnabled(bool en) {
27 scan_elements_enabled_ = en;
Enrico Granata51cdb942019-06-18 16:40:17 -070028 return true;
29}
30
Harvey Yangf0a0b232020-08-29 10:20:31 +080031template <typename T>
32base::Optional<T> FakeReadAttributes(const std::string& name,
33 std::map<std::string, T> attributes) {
Gwendal Grignou197d5162019-11-20 16:46:02 -080034 auto k = attributes.find(name);
35 if (k == attributes.end())
Enrico Granata064a25c2019-07-15 15:48:03 -070036 return base::nullopt;
37 return k->second;
38}
Gwendal Grignou197d5162019-11-20 16:46:02 -080039
40base::Optional<std::string> FakeIioChannel::ReadStringAttribute(
41 const std::string& name) const {
42 return FakeReadAttributes<>(name, text_attributes_);
43}
Enrico Granata064a25c2019-07-15 15:48:03 -070044base::Optional<int64_t> FakeIioChannel::ReadNumberAttribute(
45 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -080046 return FakeReadAttributes<>(name, numeric_attributes_);
Enrico Granata064a25c2019-07-15 15:48:03 -070047}
Harvey Yang9903fc22020-03-16 14:22:53 +080048base::Optional<double> FakeIioChannel::ReadDoubleAttribute(
49 const std::string& name) const {
50 return FakeReadAttributes<>(name, double_attributes_);
Enrico Granata064a25c2019-07-15 15:48:03 -070051}
Harvey Yang9903fc22020-03-16 14:22:53 +080052
53bool FakeIioChannel::WriteStringAttribute(const std::string& name,
54 const std::string& value) {
55 text_attributes_[name] = value;
56 return true;
57}
58bool FakeIioChannel::WriteNumberAttribute(const std::string& name,
59 int64_t value) {
Enrico Granata064a25c2019-07-15 15:48:03 -070060 numeric_attributes_[name] = value;
Harvey Yang9903fc22020-03-16 14:22:53 +080061 return true;
62}
63bool FakeIioChannel::WriteDoubleAttribute(const std::string& name,
64 double value) {
65 double_attributes_[name] = value;
66 return true;
Enrico Granata064a25c2019-07-15 15:48:03 -070067}
68
Harvey Yang3dfaed62020-05-19 17:29:02 +080069base::Optional<int64_t> FakeIioChannel::GetData(int index) {
70 if (!enabled_ || index < 0 || index >= base::size(kFakeAccelSamples))
71 return base::nullopt;
72
73 auto raw = ReadNumberAttribute(kRawAttr);
74 if (raw.has_value())
75 return raw;
76
77 for (int i = 0; i < base::size(kFakeAccelChns); ++i) {
78 if (id_.compare(kFakeAccelChns[i]) == 0)
79 return kFakeAccelSamples[index][i];
80 }
81
82 return base::nullopt;
83}
84
Enrico Granata9bb17522019-06-28 17:22:42 -070085FakeIioDevice::FakeIioDevice(FakeIioContext* ctx,
Enrico Granata51cdb942019-06-18 16:40:17 -070086 const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +080087 int id)
Enrico Granata51cdb942019-06-18 16:40:17 -070088 : IioDevice(), context_(ctx), name_(name), id_(id) {}
89
Harvey Yang9260b662019-08-12 15:48:03 +080090base::FilePath FakeIioDevice::GetPath() const {
91 std::string id_str(kDeviceIdPrefix);
92 id_str.append(std::to_string(GetId()));
Harvey Yang36779e92020-08-26 10:46:15 +080093 return base::FilePath(kSysDevString).Append(id_str);
Harvey Yang9260b662019-08-12 15:48:03 +080094}
95
Enrico Granata9bb17522019-06-28 17:22:42 -070096base::Optional<std::string> FakeIioDevice::ReadStringAttribute(
Enrico Granata51cdb942019-06-18 16:40:17 -070097 const std::string& name) const {
Harvey Yangd2c3c942020-12-21 14:52:32 +080098 if (name.compare(kDeviceName) == 0)
99 return name_;
Gwendal Grignou197d5162019-11-20 16:46:02 -0800100 return FakeReadAttributes<>(name, text_attributes_);
Enrico Granata51cdb942019-06-18 16:40:17 -0700101}
Enrico Granata9bb17522019-06-28 17:22:42 -0700102base::Optional<int64_t> FakeIioDevice::ReadNumberAttribute(
Enrico Granata51cdb942019-06-18 16:40:17 -0700103 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -0800104 return FakeReadAttributes<>(name, numeric_attributes_);
Enrico Granata51cdb942019-06-18 16:40:17 -0700105}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700106base::Optional<double> FakeIioDevice::ReadDoubleAttribute(
107 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -0800108 return FakeReadAttributes<>(name, double_attributes_);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700109}
Enrico Granata51cdb942019-06-18 16:40:17 -0700110
Enrico Granata9bb17522019-06-28 17:22:42 -0700111bool FakeIioDevice::WriteStringAttribute(const std::string& name,
Enrico Granata51cdb942019-06-18 16:40:17 -0700112 const std::string& value) {
113 text_attributes_[name] = value;
114 return true;
115}
Enrico Granata9bb17522019-06-28 17:22:42 -0700116bool FakeIioDevice::WriteNumberAttribute(const std::string& name,
Enrico Granata51cdb942019-06-18 16:40:17 -0700117 int64_t value) {
118 numeric_attributes_[name] = value;
119 return true;
120}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700121bool FakeIioDevice::WriteDoubleAttribute(const std::string& name,
122 double value) {
123 double_attributes_[name] = value;
124 return true;
125}
Enrico Granata51cdb942019-06-18 16:40:17 -0700126
Enrico Granata9bb17522019-06-28 17:22:42 -0700127bool FakeIioDevice::SetTrigger(IioDevice* trigger) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700128 trigger_ = trigger;
129 return true;
130}
131
Enrico Granata9bb17522019-06-28 17:22:42 -0700132bool FakeIioDevice::EnableBuffer(size_t n) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700133 buffer_length_ = n;
134 buffer_enabled_ = true;
135 return true;
136}
Enrico Granata9bb17522019-06-28 17:22:42 -0700137bool FakeIioDevice::DisableBuffer() {
Enrico Granata51cdb942019-06-18 16:40:17 -0700138 buffer_enabled_ = false;
139 return true;
140}
Enrico Granata9bb17522019-06-28 17:22:42 -0700141bool FakeIioDevice::IsBufferEnabled(size_t* n) const {
Enrico Granata51cdb942019-06-18 16:40:17 -0700142 if (n && buffer_enabled_)
143 *n = buffer_length_;
144 return buffer_enabled_;
145}
146
Harvey Yangdf365182021-01-16 23:43:45 +0800147bool FakeIioDevice::CreateBuffer() {
148 if (disabled_fd_ || sample_fd_.is_valid())
149 return false;
Harvey Yang3dfaed62020-05-19 17:29:02 +0800150
Harvey Yangdf365182021-01-16 23:43:45 +0800151 int fd = eventfd(0, 0);
152 CHECK_GE(fd, 0);
153 sample_fd_.reset(fd);
154
155 if (sample_index_ >= base::size(kFakeAccelSamples) || is_paused_)
156 return true;
157
158 if (!WriteByte()) {
159 ClosePipe();
160 return false;
161 }
162
163 return true;
164}
165
166base::Optional<int32_t> FakeIioDevice::GetBufferFd() {
167 if (disabled_fd_ || !sample_fd_.is_valid())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800168 return base::nullopt;
169
170 return sample_fd_.get();
171}
Harvey Yangdf365182021-01-16 23:43:45 +0800172
Harvey Yang3dfaed62020-05-19 17:29:02 +0800173base::Optional<IioDevice::IioSample> FakeIioDevice::ReadSample() {
Harvey Yangdf365182021-01-16 23:43:45 +0800174 if (is_paused_ || disabled_fd_ || !sample_fd_.is_valid())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800175 return base::nullopt;
176
177 if (!failed_read_queue_.empty()) {
178 CHECK_GE(failed_read_queue_.top(), sample_index_);
179 if (failed_read_queue_.top() == sample_index_) {
180 failed_read_queue_.pop();
181 return base::nullopt;
182 }
183 }
184
Harvey Yang3dfaed62020-05-19 17:29:02 +0800185 if (!ReadByte())
186 return base::nullopt;
187
188 base::Optional<double> freq_opt = ReadDoubleAttribute(kSamplingFrequencyAttr);
189 if (!freq_opt.has_value()) {
190 LOG(ERROR) << "sampling_frequency not set";
191 return base::nullopt;
192 }
193 double frequency = freq_opt.value();
194 if (frequency <= 0.0) {
195 LOG(ERROR) << "Invalid frequency: " << frequency;
196 return base::nullopt;
197 }
198
199 IioDevice::IioSample sample;
Gwendal Grignoua1446472020-06-30 18:00:05 -0700200 auto channels = GetAllChannels();
201 for (int32_t i = 0; i < channels.size(); ++i) {
202 FakeIioChannel* chn = dynamic_cast<FakeIioChannel*>(channels[i]);
203 auto value = chn->GetData(sample_index_);
Harvey Yang3dfaed62020-05-19 17:29:02 +0800204 if (!value.has_value()) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800205 LOG(ERROR) << "Channel: " << channels_[i].chn_id << " has no sample";
Harvey Yang3dfaed62020-05-19 17:29:02 +0800206 return base::nullopt;
207 }
208
Harvey Yang9f48d812020-06-30 16:24:30 +0800209 sample[i] = value.value();
Harvey Yang3dfaed62020-05-19 17:29:02 +0800210 }
211
212 sample_index_ += 1;
213
214 if (sample_index_ < base::size(kFakeAccelSamples)) {
Harvey Yange5e98a82020-06-01 17:31:41 +0800215 if (pause_index_.has_value() && sample_index_ == pause_index_.value())
216 SetPause();
217 else if (!WriteByte())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800218 return base::nullopt;
219 }
220
221 return sample;
222}
223
Harvey Yangdf365182021-01-16 23:43:45 +0800224void FakeIioDevice::FreeBuffer() {
225 ClosePipe();
226}
227
Harvey Yang3dfaed62020-05-19 17:29:02 +0800228void FakeIioDevice::DisableFd() {
229 disabled_fd_ = true;
230 if (readable_fd_)
231 CHECK(ReadByte());
232}
233
234void FakeIioDevice::AddFailedReadAtKthSample(int k) {
235 CHECK_GE(k, sample_index_);
236
237 failed_read_queue_.push(k);
238}
239
Harvey Yange5e98a82020-06-01 17:31:41 +0800240void FakeIioDevice::SetPauseCallbackAtKthSamples(
241 int k, base::OnceCallback<void()> callback) {
242 CHECK_GE(k, sample_index_);
243 CHECK_LE(k, base::size(kFakeAccelSamples));
244 CHECK(!pause_index_.has_value()); // pause callback hasn't been set
245
246 pause_index_ = k;
247 pause_callback_ = std::move(callback);
248
249 if (pause_index_.value() != sample_index_)
250 return;
251
252 SetPause();
253}
254
255void FakeIioDevice::ResumeReadingSamples() {
256 CHECK(is_paused_);
257
258 is_paused_ = false;
259 if (sample_fd_.is_valid() && !readable_fd_)
260 CHECK(WriteByte());
261}
262
Harvey Yang3dfaed62020-05-19 17:29:02 +0800263bool FakeIioDevice::WriteByte() {
264 if (!sample_fd_.is_valid())
265 return false;
266
267 CHECK(!readable_fd_);
268 uint64_t val = 1;
269 CHECK_EQ(write(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
270 readable_fd_ = true;
271
272 return true;
273}
274
275bool FakeIioDevice::ReadByte() {
276 if (!sample_fd_.is_valid())
277 return false;
278
279 CHECK(readable_fd_);
280 int64_t val = 1;
281 CHECK_EQ(read(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
282 readable_fd_ = false;
283
284 return true;
285}
286
Harvey Yange5e98a82020-06-01 17:31:41 +0800287void FakeIioDevice::ClosePipe() {
Harvey Yang3dfaed62020-05-19 17:29:02 +0800288 sample_fd_.reset();
289}
290
Harvey Yange5e98a82020-06-01 17:31:41 +0800291void FakeIioDevice::SetPause() {
292 is_paused_ = true;
293 pause_index_.reset();
294 std::move(pause_callback_).Run();
295 if (readable_fd_)
296 CHECK(ReadByte());
297}
298
Gwendal Grignoua1446472020-06-30 18:00:05 -0700299void FakeIioContext::AddDevice(std::unique_ptr<FakeIioDevice> device) {
300 CHECK(device.get());
301 devices_.emplace(device->GetId(), std::move(device));
Enrico Granata51cdb942019-06-18 16:40:17 -0700302}
303
Gwendal Grignoua1446472020-06-30 18:00:05 -0700304void FakeIioContext::AddTrigger(std::unique_ptr<FakeIioDevice> trigger) {
305 CHECK(trigger.get());
306 triggers_.emplace(trigger->GetId(), std::move(trigger));
Harvey Yang9260b662019-08-12 15:48:03 +0800307}
308
309std::vector<IioDevice*> FakeIioContext::GetDevicesByName(
310 const std::string& name) {
311 return GetFakeByName(name, devices_);
312}
313
314IioDevice* FakeIioContext::GetDeviceById(int id) {
315 return GetFakeById(id, devices_);
316}
317
318std::vector<IioDevice*> FakeIioContext::GetAllDevices() {
319 return GetFakeAll(devices_);
320}
321
322std::vector<IioDevice*> FakeIioContext::GetTriggersByName(
323 const std::string& name) {
324 return GetFakeByName(name, triggers_);
325}
326
327IioDevice* FakeIioContext::GetTriggerById(int id) {
328 return GetFakeById(id, triggers_);
329}
330
331std::vector<IioDevice*> FakeIioContext::GetAllTriggers() {
332 return GetFakeAll(triggers_);
333}
334
335IioDevice* FakeIioContext::GetFakeById(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700336 int id, const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800337 auto k = devices_map.find(id);
Gwendal Grignoua1446472020-06-30 18:00:05 -0700338 return (k == devices_map.end()) ? nullptr : k->second.get();
Harvey Yang9260b662019-08-12 15:48:03 +0800339}
340
341std::vector<IioDevice*> FakeIioContext::GetFakeByName(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700342 const std::string& name,
343 const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800344 std::vector<IioDevice*> devices;
345 for (auto const& it : devices_map) {
346 if (name.compare(it.second->GetName()) == 0)
Gwendal Grignoua1446472020-06-30 18:00:05 -0700347 devices.push_back(it.second.get());
Harvey Yang9260b662019-08-12 15:48:03 +0800348 }
349
350 return devices;
351}
352
353std::vector<IioDevice*> FakeIioContext::GetFakeAll(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700354 const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800355 std::vector<IioDevice*> devices;
356 for (auto const& it : devices_map)
Gwendal Grignoua1446472020-06-30 18:00:05 -0700357 devices.push_back(it.second.get());
Harvey Yang9260b662019-08-12 15:48:03 +0800358
359 return devices;
Enrico Granata51cdb942019-06-18 16:40:17 -0700360}
361
Enrico Granata9bb17522019-06-28 17:22:42 -0700362} // namespace fakes
Enrico Granata51cdb942019-06-18 16:40:17 -0700363} // namespace libmems