blob: 18ce6bf4181e9d04da9d7a7b73f69057476c7fd5 [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
Qijiang Fan713061e2021-03-08 15:45:12 +09009#include <base/check.h>
10#include <base/check_op.h>
Harvey Yang3dfaed62020-05-19 17:29:02 +080011#include <base/files/file_util.h>
Enrico Granata51cdb942019-06-18 16:40:17 -070012#include <base/logging.h>
Harvey Yang3dfaed62020-05-19 17:29:02 +080013#include "base/posix/eintr_wrapper.h"
14#include <base/stl_util.h>
Enrico Granata51cdb942019-06-18 16:40:17 -070015
Harvey Yang9260b662019-08-12 15:48:03 +080016#include "libmems/common_types.h"
17
Enrico Granata51cdb942019-06-18 16:40:17 -070018namespace libmems {
Enrico Granata9bb17522019-06-28 17:22:42 -070019namespace fakes {
Enrico Granata51cdb942019-06-18 16:40:17 -070020
Enrico Granata9bb17522019-06-28 17:22:42 -070021FakeIioChannel::FakeIioChannel(const std::string& id, bool enabled)
Enrico Granata51cdb942019-06-18 16:40:17 -070022 : id_(id), enabled_(enabled) {}
23
Harvey Yang2c08cf72020-09-24 12:36:23 +080024void FakeIioChannel::SetEnabled(bool en) {
Enrico Granata51cdb942019-06-18 16:40:17 -070025 enabled_ = en;
Harvey Yang2c08cf72020-09-24 12:36:23 +080026}
27
28bool FakeIioChannel::SetScanElementsEnabled(bool en) {
29 scan_elements_enabled_ = en;
Enrico Granata51cdb942019-06-18 16:40:17 -070030 return true;
31}
32
Harvey Yangf0a0b232020-08-29 10:20:31 +080033template <typename T>
34base::Optional<T> FakeReadAttributes(const std::string& name,
35 std::map<std::string, T> attributes) {
Gwendal Grignou197d5162019-11-20 16:46:02 -080036 auto k = attributes.find(name);
37 if (k == attributes.end())
Enrico Granata064a25c2019-07-15 15:48:03 -070038 return base::nullopt;
39 return k->second;
40}
Gwendal Grignou197d5162019-11-20 16:46:02 -080041
42base::Optional<std::string> FakeIioChannel::ReadStringAttribute(
43 const std::string& name) const {
44 return FakeReadAttributes<>(name, text_attributes_);
45}
Enrico Granata064a25c2019-07-15 15:48:03 -070046base::Optional<int64_t> FakeIioChannel::ReadNumberAttribute(
47 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -080048 return FakeReadAttributes<>(name, numeric_attributes_);
Enrico Granata064a25c2019-07-15 15:48:03 -070049}
Harvey Yang9903fc22020-03-16 14:22:53 +080050base::Optional<double> FakeIioChannel::ReadDoubleAttribute(
51 const std::string& name) const {
52 return FakeReadAttributes<>(name, double_attributes_);
Enrico Granata064a25c2019-07-15 15:48:03 -070053}
Harvey Yang9903fc22020-03-16 14:22:53 +080054
55bool FakeIioChannel::WriteStringAttribute(const std::string& name,
56 const std::string& value) {
57 text_attributes_[name] = value;
58 return true;
59}
60bool FakeIioChannel::WriteNumberAttribute(const std::string& name,
61 int64_t value) {
Enrico Granata064a25c2019-07-15 15:48:03 -070062 numeric_attributes_[name] = value;
Harvey Yang9903fc22020-03-16 14:22:53 +080063 return true;
64}
65bool FakeIioChannel::WriteDoubleAttribute(const std::string& name,
66 double value) {
67 double_attributes_[name] = value;
68 return true;
Enrico Granata064a25c2019-07-15 15:48:03 -070069}
70
Harvey Yang3dfaed62020-05-19 17:29:02 +080071base::Optional<int64_t> FakeIioChannel::GetData(int index) {
72 if (!enabled_ || index < 0 || index >= base::size(kFakeAccelSamples))
73 return base::nullopt;
74
75 auto raw = ReadNumberAttribute(kRawAttr);
76 if (raw.has_value())
77 return raw;
78
79 for (int i = 0; i < base::size(kFakeAccelChns); ++i) {
80 if (id_.compare(kFakeAccelChns[i]) == 0)
81 return kFakeAccelSamples[index][i];
82 }
83
84 return base::nullopt;
85}
86
Enrico Granata9bb17522019-06-28 17:22:42 -070087FakeIioDevice::FakeIioDevice(FakeIioContext* ctx,
Enrico Granata51cdb942019-06-18 16:40:17 -070088 const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +080089 int id)
Enrico Granata51cdb942019-06-18 16:40:17 -070090 : IioDevice(), context_(ctx), name_(name), id_(id) {}
91
Harvey Yang9260b662019-08-12 15:48:03 +080092base::FilePath FakeIioDevice::GetPath() const {
93 std::string id_str(kDeviceIdPrefix);
94 id_str.append(std::to_string(GetId()));
Harvey Yang36779e92020-08-26 10:46:15 +080095 return base::FilePath(kSysDevString).Append(id_str);
Harvey Yang9260b662019-08-12 15:48:03 +080096}
97
Enrico Granata9bb17522019-06-28 17:22:42 -070098base::Optional<std::string> FakeIioDevice::ReadStringAttribute(
Enrico Granata51cdb942019-06-18 16:40:17 -070099 const std::string& name) const {
Harvey Yangd2c3c942020-12-21 14:52:32 +0800100 if (name.compare(kDeviceName) == 0)
101 return name_;
Gwendal Grignou197d5162019-11-20 16:46:02 -0800102 return FakeReadAttributes<>(name, text_attributes_);
Enrico Granata51cdb942019-06-18 16:40:17 -0700103}
Enrico Granata9bb17522019-06-28 17:22:42 -0700104base::Optional<int64_t> FakeIioDevice::ReadNumberAttribute(
Enrico Granata51cdb942019-06-18 16:40:17 -0700105 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -0800106 return FakeReadAttributes<>(name, numeric_attributes_);
Enrico Granata51cdb942019-06-18 16:40:17 -0700107}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700108base::Optional<double> FakeIioDevice::ReadDoubleAttribute(
109 const std::string& name) const {
Gwendal Grignou197d5162019-11-20 16:46:02 -0800110 return FakeReadAttributes<>(name, double_attributes_);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700111}
Enrico Granata51cdb942019-06-18 16:40:17 -0700112
Enrico Granata9bb17522019-06-28 17:22:42 -0700113bool FakeIioDevice::WriteStringAttribute(const std::string& name,
Enrico Granata51cdb942019-06-18 16:40:17 -0700114 const std::string& value) {
115 text_attributes_[name] = value;
116 return true;
117}
Enrico Granata9bb17522019-06-28 17:22:42 -0700118bool FakeIioDevice::WriteNumberAttribute(const std::string& name,
Enrico Granata51cdb942019-06-18 16:40:17 -0700119 int64_t value) {
120 numeric_attributes_[name] = value;
121 return true;
122}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700123bool FakeIioDevice::WriteDoubleAttribute(const std::string& name,
124 double value) {
125 double_attributes_[name] = value;
126 return true;
127}
Enrico Granata51cdb942019-06-18 16:40:17 -0700128
Enrico Granata9bb17522019-06-28 17:22:42 -0700129bool FakeIioDevice::SetTrigger(IioDevice* trigger) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700130 trigger_ = trigger;
131 return true;
132}
133
Enrico Granata9bb17522019-06-28 17:22:42 -0700134bool FakeIioDevice::EnableBuffer(size_t n) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700135 buffer_length_ = n;
136 buffer_enabled_ = true;
137 return true;
138}
Enrico Granata9bb17522019-06-28 17:22:42 -0700139bool FakeIioDevice::DisableBuffer() {
Enrico Granata51cdb942019-06-18 16:40:17 -0700140 buffer_enabled_ = false;
141 return true;
142}
Enrico Granata9bb17522019-06-28 17:22:42 -0700143bool FakeIioDevice::IsBufferEnabled(size_t* n) const {
Enrico Granata51cdb942019-06-18 16:40:17 -0700144 if (n && buffer_enabled_)
145 *n = buffer_length_;
146 return buffer_enabled_;
147}
148
Harvey Yangdf365182021-01-16 23:43:45 +0800149bool FakeIioDevice::CreateBuffer() {
150 if (disabled_fd_ || sample_fd_.is_valid())
151 return false;
Harvey Yang3dfaed62020-05-19 17:29:02 +0800152
Harvey Yangdf365182021-01-16 23:43:45 +0800153 int fd = eventfd(0, 0);
154 CHECK_GE(fd, 0);
155 sample_fd_.reset(fd);
156
157 if (sample_index_ >= base::size(kFakeAccelSamples) || is_paused_)
158 return true;
159
160 if (!WriteByte()) {
161 ClosePipe();
162 return false;
163 }
164
165 return true;
166}
167
168base::Optional<int32_t> FakeIioDevice::GetBufferFd() {
169 if (disabled_fd_ || !sample_fd_.is_valid())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800170 return base::nullopt;
171
172 return sample_fd_.get();
173}
Harvey Yangdf365182021-01-16 23:43:45 +0800174
Harvey Yang3dfaed62020-05-19 17:29:02 +0800175base::Optional<IioDevice::IioSample> FakeIioDevice::ReadSample() {
Harvey Yangdf365182021-01-16 23:43:45 +0800176 if (is_paused_ || disabled_fd_ || !sample_fd_.is_valid())
Harvey Yang3dfaed62020-05-19 17:29:02 +0800177 return base::nullopt;
178
179 if (!failed_read_queue_.empty()) {
180 CHECK_GE(failed_read_queue_.top(), sample_index_);
181 if (failed_read_queue_.top() == sample_index_) {
182 failed_read_queue_.pop();
183 return base::nullopt;
184 }
185 }
186
Harvey Yang3dfaed62020-05-19 17:29:02 +0800187 if (!ReadByte())
188 return base::nullopt;
189
190 base::Optional<double> freq_opt = ReadDoubleAttribute(kSamplingFrequencyAttr);
191 if (!freq_opt.has_value()) {
192 LOG(ERROR) << "sampling_frequency not set";
193 return base::nullopt;
194 }
195 double frequency = freq_opt.value();
196 if (frequency <= 0.0) {
197 LOG(ERROR) << "Invalid frequency: " << frequency;
198 return base::nullopt;
199 }
200
201 IioDevice::IioSample sample;
Gwendal Grignoua1446472020-06-30 18:00:05 -0700202 auto channels = GetAllChannels();
203 for (int32_t i = 0; i < channels.size(); ++i) {
204 FakeIioChannel* chn = dynamic_cast<FakeIioChannel*>(channels[i]);
205 auto value = 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
Harvey Yangdf365182021-01-16 23:43:45 +0800226void FakeIioDevice::FreeBuffer() {
227 ClosePipe();
228}
229
Harvey Yang3dfaed62020-05-19 17:29:02 +0800230void FakeIioDevice::DisableFd() {
231 disabled_fd_ = true;
232 if (readable_fd_)
233 CHECK(ReadByte());
234}
235
236void FakeIioDevice::AddFailedReadAtKthSample(int k) {
237 CHECK_GE(k, sample_index_);
238
239 failed_read_queue_.push(k);
240}
241
Harvey Yange5e98a82020-06-01 17:31:41 +0800242void FakeIioDevice::SetPauseCallbackAtKthSamples(
243 int k, base::OnceCallback<void()> callback) {
244 CHECK_GE(k, sample_index_);
245 CHECK_LE(k, base::size(kFakeAccelSamples));
246 CHECK(!pause_index_.has_value()); // pause callback hasn't been set
247
248 pause_index_ = k;
249 pause_callback_ = std::move(callback);
250
251 if (pause_index_.value() != sample_index_)
252 return;
253
254 SetPause();
255}
256
257void FakeIioDevice::ResumeReadingSamples() {
258 CHECK(is_paused_);
259
260 is_paused_ = false;
261 if (sample_fd_.is_valid() && !readable_fd_)
262 CHECK(WriteByte());
263}
264
Harvey Yang3dfaed62020-05-19 17:29:02 +0800265bool FakeIioDevice::WriteByte() {
266 if (!sample_fd_.is_valid())
267 return false;
268
269 CHECK(!readable_fd_);
270 uint64_t val = 1;
271 CHECK_EQ(write(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
272 readable_fd_ = true;
273
274 return true;
275}
276
277bool FakeIioDevice::ReadByte() {
278 if (!sample_fd_.is_valid())
279 return false;
280
281 CHECK(readable_fd_);
282 int64_t val = 1;
283 CHECK_EQ(read(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
284 readable_fd_ = false;
285
286 return true;
287}
288
Harvey Yange5e98a82020-06-01 17:31:41 +0800289void FakeIioDevice::ClosePipe() {
Harvey Yang3dfaed62020-05-19 17:29:02 +0800290 sample_fd_.reset();
291}
292
Harvey Yange5e98a82020-06-01 17:31:41 +0800293void FakeIioDevice::SetPause() {
294 is_paused_ = true;
295 pause_index_.reset();
296 std::move(pause_callback_).Run();
297 if (readable_fd_)
298 CHECK(ReadByte());
299}
300
Gwendal Grignoua1446472020-06-30 18:00:05 -0700301void FakeIioContext::AddDevice(std::unique_ptr<FakeIioDevice> device) {
302 CHECK(device.get());
303 devices_.emplace(device->GetId(), std::move(device));
Enrico Granata51cdb942019-06-18 16:40:17 -0700304}
305
Gwendal Grignoua1446472020-06-30 18:00:05 -0700306void FakeIioContext::AddTrigger(std::unique_ptr<FakeIioDevice> trigger) {
307 CHECK(trigger.get());
308 triggers_.emplace(trigger->GetId(), std::move(trigger));
Harvey Yang9260b662019-08-12 15:48:03 +0800309}
310
311std::vector<IioDevice*> FakeIioContext::GetDevicesByName(
312 const std::string& name) {
313 return GetFakeByName(name, devices_);
314}
315
316IioDevice* FakeIioContext::GetDeviceById(int id) {
317 return GetFakeById(id, devices_);
318}
319
320std::vector<IioDevice*> FakeIioContext::GetAllDevices() {
321 return GetFakeAll(devices_);
322}
323
324std::vector<IioDevice*> FakeIioContext::GetTriggersByName(
325 const std::string& name) {
326 return GetFakeByName(name, triggers_);
327}
328
329IioDevice* FakeIioContext::GetTriggerById(int id) {
330 return GetFakeById(id, triggers_);
331}
332
333std::vector<IioDevice*> FakeIioContext::GetAllTriggers() {
334 return GetFakeAll(triggers_);
335}
336
337IioDevice* FakeIioContext::GetFakeById(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700338 int id, const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800339 auto k = devices_map.find(id);
Gwendal Grignoua1446472020-06-30 18:00:05 -0700340 return (k == devices_map.end()) ? nullptr : k->second.get();
Harvey Yang9260b662019-08-12 15:48:03 +0800341}
342
343std::vector<IioDevice*> FakeIioContext::GetFakeByName(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700344 const std::string& name,
345 const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800346 std::vector<IioDevice*> devices;
347 for (auto const& it : devices_map) {
348 if (name.compare(it.second->GetName()) == 0)
Gwendal Grignoua1446472020-06-30 18:00:05 -0700349 devices.push_back(it.second.get());
Harvey Yang9260b662019-08-12 15:48:03 +0800350 }
351
352 return devices;
353}
354
355std::vector<IioDevice*> FakeIioContext::GetFakeAll(
Gwendal Grignoua1446472020-06-30 18:00:05 -0700356 const std::map<int, std::unique_ptr<FakeIioDevice>>& devices_map) {
Harvey Yang9260b662019-08-12 15:48:03 +0800357 std::vector<IioDevice*> devices;
358 for (auto const& it : devices_map)
Gwendal Grignoua1446472020-06-30 18:00:05 -0700359 devices.push_back(it.second.get());
Harvey Yang9260b662019-08-12 15:48:03 +0800360
361 return devices;
Enrico Granata51cdb942019-06-18 16:40:17 -0700362}
363
Enrico Granata9bb17522019-06-28 17:22:42 -0700364} // namespace fakes
Enrico Granata51cdb942019-06-18 16:40:17 -0700365} // namespace libmems