blob: c15a9831868138234651209e69f3c5d7cc307ac8 [file] [log] [blame]
Enrico Granata60a818d2019-05-09 09:56:09 -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
5#include <memory>
6#include <string>
Harvey Yangc0d19d82019-07-01 12:17:34 +08007#include <vector>
Enrico Granata60a818d2019-05-09 09:56:09 -07008
Qijiang Fan713061e2021-03-08 15:45:12 +09009#include <base/check.h>
Enrico Granata60a818d2019-05-09 09:56:09 -070010#include <base/files/file_util.h>
11#include <base/logging.h>
Harvey Yang9260b662019-08-12 15:48:03 +080012#include <base/strings/stringprintf.h>
Enrico Granata60a818d2019-05-09 09:56:09 -070013
Harvey Yang6698c862019-09-16 17:24:38 +080014#include "libmems/common_types.h"
Enrico Granata51cdb942019-06-18 16:40:17 -070015#include "libmems/iio_channel_impl.h"
16#include "libmems/iio_context_impl.h"
17#include "libmems/iio_device_impl.h"
Harvey Yang9260b662019-08-12 15:48:03 +080018#include "libmems/iio_device_trigger_impl.h"
Enrico Granata60a818d2019-05-09 09:56:09 -070019
Harvey Yangc0d19d82019-07-01 12:17:34 +080020#define ERROR_BUFFER_SIZE 256
21
Enrico Granata51cdb942019-06-18 16:40:17 -070022namespace libmems {
Enrico Granata60a818d2019-05-09 09:56:09 -070023
Harvey Yang75452e82019-10-02 16:57:01 +080024namespace {
25
Harvey Yang75452e82019-10-02 16:57:01 +080026constexpr int kNumSamples = 1;
Gwendal Grignou887ea812021-02-10 12:58:36 -080027constexpr char kHWFifoWatermarkMaxAttr[] = "hwfifo_watermark_max";
Harvey Yang75452e82019-10-02 16:57:01 +080028
29}; // namespace
30
Harvey Yang98ff1b32020-10-28 14:45:35 +080031// static
Harvey Yang9260b662019-08-12 15:48:03 +080032base::Optional<int> IioDeviceImpl::GetIdFromString(const char* id_str) {
33 return IioDevice::GetIdAfterPrefix(id_str, kDeviceIdPrefix);
34}
35
Harvey Yang98ff1b32020-10-28 14:45:35 +080036// static
Harvey Yang9260b662019-08-12 15:48:03 +080037std::string IioDeviceImpl::GetStringFromId(int id) {
38 return base::StringPrintf("%s%d", kDeviceIdPrefix, id);
39}
40
Enrico Granata60a818d2019-05-09 09:56:09 -070041IioDeviceImpl::IioDeviceImpl(IioContextImpl* ctx, iio_device* dev)
Harvey Yangc0d19d82019-07-01 12:17:34 +080042 : IioDevice(),
43 context_(ctx),
44 device_(dev),
Harvey Yang75452e82019-10-02 16:57:01 +080045 buffer_(nullptr, IioBufferDeleter) {
Enrico Granata60a818d2019-05-09 09:56:09 -070046 CHECK(context_);
47 CHECK(device_);
Harvey Yang5e6cb702020-01-15 10:57:44 +080048
Harvey Yang705e40f2020-11-19 15:42:44 +080049 log_prefix_ = base::StringPrintf("Device with id: %d and name: %s. ", GetId(),
50 (GetName() ? GetName() : "null"));
51
Harvey Yang9f48d812020-06-30 16:24:30 +080052 uint32_t chn_count = iio_device_get_channels_count(device_);
53 channels_.resize(chn_count);
54
55 for (uint32_t i = 0; i < chn_count; ++i) {
56 iio_channel* channel = iio_device_get_channel(device_, i);
57 if (channel == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +080058 LOG(WARNING) << log_prefix_ << "Unable to get " << i << "th channel";
Harvey Yang9f48d812020-06-30 16:24:30 +080059 continue;
60 }
61
Harvey Yang705e40f2020-11-19 15:42:44 +080062 channels_[i].chn = std::make_unique<IioChannelImpl>(
63 channel, GetId(), GetName() ? GetName() : "null");
Harvey Yang9f48d812020-06-30 16:24:30 +080064 channels_[i].chn_id = channels_[i].chn->GetId();
65 }
Enrico Granata60a818d2019-05-09 09:56:09 -070066}
67
68IioContext* IioDeviceImpl::GetContext() const {
69 return context_;
70}
71
72const char* IioDeviceImpl::GetName() const {
73 return iio_device_get_name(device_);
74}
75
Harvey Yang9260b662019-08-12 15:48:03 +080076int IioDeviceImpl::GetId() const {
77 const char* id_str = iio_device_get_id(device_);
78
79 auto id = GetIdFromString(id_str);
80 DCHECK(id.has_value());
81 return id.value();
Enrico Granata60a818d2019-05-09 09:56:09 -070082}
83
84base::FilePath IioDeviceImpl::GetPath() const {
Harvey Yang9260b662019-08-12 15:48:03 +080085 std::string id_str = GetStringFromId(GetId());
Harvey Yang36779e92020-08-26 10:46:15 +080086 auto path = base::FilePath(kSysDevString).Append(id_str);
Enrico Granata60a818d2019-05-09 09:56:09 -070087 CHECK(base::DirectoryExists(path));
88 return path;
89}
90
91base::Optional<std::string> IioDeviceImpl::ReadStringAttribute(
92 const std::string& name) const {
Harvey Yang9260b662019-08-12 15:48:03 +080093 char data[kReadAttrBufferSize] = {0};
Enrico Granata60a818d2019-05-09 09:56:09 -070094 ssize_t len = iio_device_attr_read(device_, name.c_str(), data, sizeof(data));
95 if (len < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +080096 LOG(WARNING) << log_prefix_ << "Attempting to read string attribute "
97 << name << " failed: " << len;
Enrico Granata60a818d2019-05-09 09:56:09 -070098 return base::nullopt;
99 }
100 return std::string(data, len);
101}
102
103base::Optional<int64_t> IioDeviceImpl::ReadNumberAttribute(
104 const std::string& name) const {
105 long long val = 0; // NOLINT(runtime/int)
106 int error = iio_device_attr_read_longlong(device_, name.c_str(), &val);
107 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800108 LOG(WARNING) << log_prefix_ << "Attempting to read number attribute "
109 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700110 return base::nullopt;
111 }
112 return val;
113}
114
Enrico Granatad2e57f42019-07-31 10:46:03 -0700115base::Optional<double> IioDeviceImpl::ReadDoubleAttribute(
116 const std::string& name) const {
117 double val = 0;
118 int error = iio_device_attr_read_double(device_, name.c_str(), &val);
119 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800120 LOG(WARNING) << log_prefix_ << "Attempting to read double attribute "
121 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700122 return base::nullopt;
123 }
124 return val;
125}
126
Enrico Granata60a818d2019-05-09 09:56:09 -0700127bool IioDeviceImpl::WriteStringAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800128 const std::string& value) {
129 int error = iio_device_attr_write_raw(device_, name.c_str(), value.data(),
130 value.size());
131 if (error < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800132 LOG(WARNING) << log_prefix_ << "Attempting to write string attribute "
133 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700134 return false;
135 }
136 return true;
137}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700138
Enrico Granata60a818d2019-05-09 09:56:09 -0700139bool IioDeviceImpl::WriteNumberAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800140 int64_t value) {
141 int error = iio_device_attr_write_longlong(device_, name.c_str(), value);
Enrico Granata60a818d2019-05-09 09:56:09 -0700142 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800143 LOG(WARNING) << log_prefix_ << "Attempting to write number attribute "
144 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700145 return false;
146 }
147 return true;
148}
149
Harvey Yang9260b662019-08-12 15:48:03 +0800150bool IioDeviceImpl::WriteDoubleAttribute(const std::string& name,
151 double value) {
152 int error = iio_device_attr_write_double(device_, name.c_str(), value);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700153 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800154 LOG(WARNING) << log_prefix_ << "Attempting to write double attribute "
155 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700156 return false;
157 }
158 return true;
159}
160
Harvey Yangcbfe75e2021-01-21 09:35:25 +0800161bool IioDeviceImpl::HasFifo() const {
162 return iio_device_find_buffer_attr(device_, kHWFifoWatermarkMaxAttr);
163}
164
Enrico Granata60a818d2019-05-09 09:56:09 -0700165iio_device* IioDeviceImpl::GetUnderlyingIioDevice() const {
166 return device_;
167}
168
169bool IioDeviceImpl::SetTrigger(IioDevice* trigger_device) {
Gwendal Grignou66393e22019-11-20 16:46:22 -0800170 // Reset the old - if any - and then add the new trigger.
171 int error = iio_device_set_trigger(device_, NULL);
172 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800173 LOG(WARNING) << log_prefix_ << "Unable to clean trigger, error: " << error;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800174 return false;
175 }
176 if (trigger_device == nullptr)
177 return true;
178
Harvey Yang9260b662019-08-12 15:48:03 +0800179 const iio_device* impl_device = nullptr;
180 int id = trigger_device->GetId();
181 if (id == -2) {
182 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
183 kIioSysfsTrigger);
184 } else {
185 std::string id_str = IioDeviceTriggerImpl::GetStringFromId(id);
186 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
187 id_str.c_str());
188 }
Enrico Granata60a818d2019-05-09 09:56:09 -0700189 if (!impl_device) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800190 LOG(WARNING) << log_prefix_ << "Unable to find device " << id
191 << " in the current context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700192 return false;
193 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800194
195 error = iio_device_set_trigger(device_, impl_device);
196 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800197 LOG(WARNING) << log_prefix_ << "Unable to set trigger to be device "
198 << trigger_device->GetId() << ", error: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700199 return false;
200 }
201 return true;
202}
203
204IioDevice* IioDeviceImpl::GetTrigger() {
205 const iio_device* trigger;
206 int error = iio_device_get_trigger(device_, &trigger);
Harvey Yang74a18762020-12-30 11:09:13 +0800207 if (error)
Enrico Granata60a818d2019-05-09 09:56:09 -0700208 return nullptr;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800209
210 if (trigger == nullptr)
211 return nullptr;
212
Harvey Yang9260b662019-08-12 15:48:03 +0800213 const char* id_str = iio_device_get_id(trigger);
214 auto id = IioDeviceTriggerImpl::GetIdFromString(id_str);
215
216 IioDevice* trigger_device = nullptr;
217 if (id.has_value())
218 trigger_device = GetContext()->GetTriggerById(id.value());
219
Enrico Granata60a818d2019-05-09 09:56:09 -0700220 if (trigger_device == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800221 LOG(WARNING) << log_prefix_ << "Has trigger device " << id_str
222 << ", which cannot be found in this context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700223 }
Harvey Yang9260b662019-08-12 15:48:03 +0800224
Enrico Granata60a818d2019-05-09 09:56:09 -0700225 return trigger_device;
226}
227
Harvey Yangee5a26d2021-03-23 17:19:27 +0800228IioDevice* IioDeviceImpl::GetHrtimer() {
229 if (hrtimer_)
230 return hrtimer_;
231
232 auto triggers = context_->GetTriggersByName(
233 base::StringPrintf(kHrtimerNameFormatString, GetId()));
234 if (triggers.empty())
235 return nullptr;
236
237 if (triggers.size() > 1) {
238 LOG(WARNING) << log_prefix_ << triggers.size()
239 << " hrtimers existing for this device";
240 }
241
242 hrtimer_ = triggers.front();
243 return hrtimer_;
244}
245
Harvey Yangc0d19d82019-07-01 12:17:34 +0800246base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
247 ssize_t sample_size = iio_device_get_sample_size(device_);
248 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800249 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800250 iio_strerror(errno, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800251 LOG(WARNING) << log_prefix_ << "Unable to get sample size: " << errMsg;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800252 return base::nullopt;
253 }
254
255 return static_cast<size_t>(sample_size);
256}
257
Enrico Granata60a818d2019-05-09 09:56:09 -0700258bool IioDeviceImpl::EnableBuffer(size_t count) {
259 if (!WriteNumberAttribute("buffer/length", count))
260 return false;
261 if (!WriteNumberAttribute("buffer/enable", 1))
262 return false;
263
264 return true;
265}
266
267bool IioDeviceImpl::DisableBuffer() {
268 return WriteNumberAttribute("buffer/enable", 0);
269}
270
271bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
272 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
273 if (enabled && count)
274 *count = ReadNumberAttribute("buffer/length").value_or(0);
275
276 return enabled;
277}
278
Harvey Yangdf365182021-01-16 23:43:45 +0800279bool IioDeviceImpl::CreateBuffer() {
280 if (buffer_)
281 return false;
282
283 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
284
285 if (!buffer_) {
286 char errMsg[kErrorBufferSize];
287 iio_strerror(errno, errMsg, sizeof(errMsg));
288 LOG(ERROR) << log_prefix_ << "Unable to allocate buffer: " << errMsg;
289 return false;
290 }
291
292 return true;
293}
294
Harvey Yange8b301b2020-05-19 14:43:03 +0800295base::Optional<int32_t> IioDeviceImpl::GetBufferFd() {
Harvey Yangdf365182021-01-16 23:43:45 +0800296 if (!buffer_)
Harvey Yange8b301b2020-05-19 14:43:03 +0800297 return base::nullopt;
298
299 int32_t fd = iio_buffer_get_poll_fd(buffer_.get());
300 if (fd < 0) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800301 LOG(ERROR) << log_prefix_ << "Failed to get poll fd: " << fd;
Harvey Yange8b301b2020-05-19 14:43:03 +0800302 return base::nullopt;
303 }
304
305 return fd;
306}
307
Harvey Yang34c54d52020-05-20 13:34:20 +0800308base::Optional<IioDevice::IioSample> IioDeviceImpl::ReadSample() {
Harvey Yangdf365182021-01-16 23:43:45 +0800309 if (!buffer_)
Harvey Yang34c54d52020-05-20 13:34:20 +0800310 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800311
312 ssize_t ret = iio_buffer_refill(buffer_.get());
313 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800314 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800315 iio_strerror(-ret, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800316 LOG(ERROR) << log_prefix_ << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800317
Harvey Yang34c54d52020-05-20 13:34:20 +0800318 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800319 }
320
321 const auto buf_step = iio_buffer_step(buffer_.get());
322 size_t sample_size = GetSampleSize().value_or(0);
323
324 // There is something wrong when refilling the buffer.
325 if (buf_step != sample_size) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800326 LOG(ERROR) << log_prefix_
327 << "sample_size doesn't match in refill: " << buf_step
Harvey Yangc0d19d82019-07-01 12:17:34 +0800328 << ", sample_size: " << sample_size;
329
Harvey Yang34c54d52020-05-20 13:34:20 +0800330 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800331 }
332
333 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800334
Harvey Yang34c54d52020-05-20 13:34:20 +0800335 return DeserializeSample(start);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800336}
337
Harvey Yangdf365182021-01-16 23:43:45 +0800338void IioDeviceImpl::FreeBuffer() {
339 buffer_.reset();
340}
341
Harvey Yangc0d19d82019-07-01 12:17:34 +0800342// static
343void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
344 iio_buffer_cancel(buffer);
345 iio_buffer_destroy(buffer);
346}
347
Harvey Yang34c54d52020-05-20 13:34:20 +0800348IioDevice::IioSample IioDeviceImpl::DeserializeSample(const uint8_t* src) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800349 IioSample sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800350 int64_t pos = 0;
351
Harvey Yang9f48d812020-06-30 16:24:30 +0800352 auto channels = GetAllChannels();
353 for (int32_t i = 0; i < channels.size(); ++i) {
354 IioChannelImpl* chn = dynamic_cast<IioChannelImpl*>(channels[i]);
Harvey Yang34c54d52020-05-20 13:34:20 +0800355 if (!chn->IsEnabled())
356 continue;
357
358 size_t len = chn->Length().value_or(0);
359 if (len == 0)
360 continue;
361 len /= CHAR_BIT;
362
363 size_t space_in_block = sizeof(int64_t) - (pos % sizeof(int64_t));
364 if (len > space_in_block) {
365 pos += space_in_block;
366 }
367
368 base::Optional<int64_t> value = chn->Convert(src + pos);
369 pos += len;
370
371 if (value.has_value())
Harvey Yang9f48d812020-06-30 16:24:30 +0800372 sample[i] = value.value();
Harvey Yang34c54d52020-05-20 13:34:20 +0800373 }
374
Harvey Yang9f48d812020-06-30 16:24:30 +0800375 return sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800376}
377
Enrico Granata51cdb942019-06-18 16:40:17 -0700378} // namespace libmems