blob: 64f60c8c6e288e440b95d26bf9924d61dd30e31f [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 Yangc0d19d82019-07-01 12:17:34 +0800228base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
229 ssize_t sample_size = iio_device_get_sample_size(device_);
230 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800231 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800232 iio_strerror(errno, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800233 LOG(WARNING) << log_prefix_ << "Unable to get sample size: " << errMsg;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800234 return base::nullopt;
235 }
236
237 return static_cast<size_t>(sample_size);
238}
239
Enrico Granata60a818d2019-05-09 09:56:09 -0700240bool IioDeviceImpl::EnableBuffer(size_t count) {
241 if (!WriteNumberAttribute("buffer/length", count))
242 return false;
243 if (!WriteNumberAttribute("buffer/enable", 1))
244 return false;
245
246 return true;
247}
248
249bool IioDeviceImpl::DisableBuffer() {
250 return WriteNumberAttribute("buffer/enable", 0);
251}
252
253bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
254 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
255 if (enabled && count)
256 *count = ReadNumberAttribute("buffer/length").value_or(0);
257
258 return enabled;
259}
260
Harvey Yangdf365182021-01-16 23:43:45 +0800261bool IioDeviceImpl::CreateBuffer() {
262 if (buffer_)
263 return false;
264
265 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
266
267 if (!buffer_) {
268 char errMsg[kErrorBufferSize];
269 iio_strerror(errno, errMsg, sizeof(errMsg));
270 LOG(ERROR) << log_prefix_ << "Unable to allocate buffer: " << errMsg;
271 return false;
272 }
273
274 return true;
275}
276
Harvey Yange8b301b2020-05-19 14:43:03 +0800277base::Optional<int32_t> IioDeviceImpl::GetBufferFd() {
Harvey Yangdf365182021-01-16 23:43:45 +0800278 if (!buffer_)
Harvey Yange8b301b2020-05-19 14:43:03 +0800279 return base::nullopt;
280
281 int32_t fd = iio_buffer_get_poll_fd(buffer_.get());
282 if (fd < 0) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800283 LOG(ERROR) << log_prefix_ << "Failed to get poll fd: " << fd;
Harvey Yange8b301b2020-05-19 14:43:03 +0800284 return base::nullopt;
285 }
286
287 return fd;
288}
289
Harvey Yang34c54d52020-05-20 13:34:20 +0800290base::Optional<IioDevice::IioSample> IioDeviceImpl::ReadSample() {
Harvey Yangdf365182021-01-16 23:43:45 +0800291 if (!buffer_)
Harvey Yang34c54d52020-05-20 13:34:20 +0800292 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800293
294 ssize_t ret = iio_buffer_refill(buffer_.get());
295 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800296 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800297 iio_strerror(-ret, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800298 LOG(ERROR) << log_prefix_ << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800299
Harvey Yang34c54d52020-05-20 13:34:20 +0800300 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800301 }
302
303 const auto buf_step = iio_buffer_step(buffer_.get());
304 size_t sample_size = GetSampleSize().value_or(0);
305
306 // There is something wrong when refilling the buffer.
307 if (buf_step != sample_size) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800308 LOG(ERROR) << log_prefix_
309 << "sample_size doesn't match in refill: " << buf_step
Harvey Yangc0d19d82019-07-01 12:17:34 +0800310 << ", sample_size: " << sample_size;
311
Harvey Yang34c54d52020-05-20 13:34:20 +0800312 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800313 }
314
315 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800316
Harvey Yang34c54d52020-05-20 13:34:20 +0800317 return DeserializeSample(start);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800318}
319
Harvey Yangdf365182021-01-16 23:43:45 +0800320void IioDeviceImpl::FreeBuffer() {
321 buffer_.reset();
322}
323
Harvey Yangc0d19d82019-07-01 12:17:34 +0800324// static
325void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
326 iio_buffer_cancel(buffer);
327 iio_buffer_destroy(buffer);
328}
329
Harvey Yang34c54d52020-05-20 13:34:20 +0800330IioDevice::IioSample IioDeviceImpl::DeserializeSample(const uint8_t* src) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800331 IioSample sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800332 int64_t pos = 0;
333
Harvey Yang9f48d812020-06-30 16:24:30 +0800334 auto channels = GetAllChannels();
335 for (int32_t i = 0; i < channels.size(); ++i) {
336 IioChannelImpl* chn = dynamic_cast<IioChannelImpl*>(channels[i]);
Harvey Yang34c54d52020-05-20 13:34:20 +0800337 if (!chn->IsEnabled())
338 continue;
339
340 size_t len = chn->Length().value_or(0);
341 if (len == 0)
342 continue;
343 len /= CHAR_BIT;
344
345 size_t space_in_block = sizeof(int64_t) - (pos % sizeof(int64_t));
346 if (len > space_in_block) {
347 pos += space_in_block;
348 }
349
350 base::Optional<int64_t> value = chn->Convert(src + pos);
351 pos += len;
352
353 if (value.has_value())
Harvey Yang9f48d812020-06-30 16:24:30 +0800354 sample[i] = value.value();
Harvey Yang34c54d52020-05-20 13:34:20 +0800355 }
356
Harvey Yang9f48d812020-06-30 16:24:30 +0800357 return sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800358}
359
Enrico Granata51cdb942019-06-18 16:40:17 -0700360} // namespace libmems