blob: ecb5b94395a7436d3cd84dbddd3c8541c2db3e89 [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() {
166 if (disabled_fd_)
167 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)) {
208 if (!WriteByte())
209 return base::nullopt;
210 }
211
212 return sample;
213}
214
215void FakeIioDevice::DisableFd() {
216 disabled_fd_ = true;
217 if (readable_fd_)
218 CHECK(ReadByte());
219}
220
221void FakeIioDevice::AddFailedReadAtKthSample(int k) {
222 CHECK_GE(k, sample_index_);
223
224 failed_read_queue_.push(k);
225}
226
227bool FakeIioDevice::CreateBuffer() {
228 CHECK(!disabled_fd_);
229
230 if (sample_fd_.is_valid())
231 return true;
232
233 int fd = eventfd(0, 0);
234 CHECK_GE(fd, 0);
235 sample_fd_.reset(fd);
236
237 if (sample_index_ >= base::size(kFakeAccelSamples))
238 return true;
239
240 if (!WriteByte()) {
241 ClosePipes();
242 return false;
243 }
244
245 return true;
246}
247
248bool FakeIioDevice::WriteByte() {
249 if (!sample_fd_.is_valid())
250 return false;
251
252 CHECK(!readable_fd_);
253 uint64_t val = 1;
254 CHECK_EQ(write(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
255 readable_fd_ = true;
256
257 return true;
258}
259
260bool FakeIioDevice::ReadByte() {
261 if (!sample_fd_.is_valid())
262 return false;
263
264 CHECK(readable_fd_);
265 int64_t val = 1;
266 CHECK_EQ(read(sample_fd_.get(), &val, sizeof(uint64_t)), sizeof(uint64_t));
267 readable_fd_ = false;
268
269 return true;
270}
271
272void FakeIioDevice::ClosePipes() {
273 sample_fd_.reset();
274}
275
Enrico Granata9bb17522019-06-28 17:22:42 -0700276void FakeIioContext::AddDevice(FakeIioDevice* device) {
Enrico Granata51cdb942019-06-18 16:40:17 -0700277 CHECK(device);
Enrico Granata51cdb942019-06-18 16:40:17 -0700278 devices_.emplace(device->GetId(), device);
279}
280
Harvey Yang9260b662019-08-12 15:48:03 +0800281void FakeIioContext::AddTrigger(FakeIioDevice* trigger) {
282 CHECK(trigger);
283 triggers_.emplace(trigger->GetId(), trigger);
284}
285
286std::vector<IioDevice*> FakeIioContext::GetDevicesByName(
287 const std::string& name) {
288 return GetFakeByName(name, devices_);
289}
290
291IioDevice* FakeIioContext::GetDeviceById(int id) {
292 return GetFakeById(id, devices_);
293}
294
295std::vector<IioDevice*> FakeIioContext::GetAllDevices() {
296 return GetFakeAll(devices_);
297}
298
299std::vector<IioDevice*> FakeIioContext::GetTriggersByName(
300 const std::string& name) {
301 return GetFakeByName(name, triggers_);
302}
303
304IioDevice* FakeIioContext::GetTriggerById(int id) {
305 return GetFakeById(id, triggers_);
306}
307
308std::vector<IioDevice*> FakeIioContext::GetAllTriggers() {
309 return GetFakeAll(triggers_);
310}
311
312IioDevice* FakeIioContext::GetFakeById(
313 int id, const std::map<int, FakeIioDevice*>& devices_map) {
314 auto k = devices_map.find(id);
315 return (k == devices_map.end()) ? nullptr : k->second;
316}
317
318std::vector<IioDevice*> FakeIioContext::GetFakeByName(
319 const std::string& name, const std::map<int, FakeIioDevice*>& devices_map) {
320 std::vector<IioDevice*> devices;
321 for (auto const& it : devices_map) {
322 if (name.compare(it.second->GetName()) == 0)
323 devices.push_back(it.second);
324 }
325
326 return devices;
327}
328
329std::vector<IioDevice*> FakeIioContext::GetFakeAll(
330 const std::map<int, FakeIioDevice*>& devices_map) {
331 std::vector<IioDevice*> devices;
332 for (auto const& it : devices_map)
333 devices.push_back(it.second);
334
335 return devices;
Enrico Granata51cdb942019-06-18 16:40:17 -0700336}
337
Enrico Granata9bb17522019-06-28 17:22:42 -0700338} // namespace fakes
Enrico Granata51cdb942019-06-18 16:40:17 -0700339} // namespace libmems