blob: b4ce9bedbe3ece749fc317647bc3a9b153410d87 [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
9#include <base/files/file_util.h>
10#include <base/logging.h>
Harvey Yang9260b662019-08-12 15:48:03 +080011#include <base/strings/stringprintf.h>
Enrico Granata60a818d2019-05-09 09:56:09 -070012
Harvey Yang6698c862019-09-16 17:24:38 +080013#include "libmems/common_types.h"
Enrico Granata51cdb942019-06-18 16:40:17 -070014#include "libmems/iio_channel_impl.h"
15#include "libmems/iio_context_impl.h"
16#include "libmems/iio_device_impl.h"
Harvey Yang9260b662019-08-12 15:48:03 +080017#include "libmems/iio_device_trigger_impl.h"
Enrico Granata60a818d2019-05-09 09:56:09 -070018
Harvey Yangc0d19d82019-07-01 12:17:34 +080019#define ERROR_BUFFER_SIZE 256
20
Enrico Granata51cdb942019-06-18 16:40:17 -070021namespace libmems {
Enrico Granata60a818d2019-05-09 09:56:09 -070022
Harvey Yang75452e82019-10-02 16:57:01 +080023namespace {
24
Harvey Yang75452e82019-10-02 16:57:01 +080025constexpr int kNumSamples = 1;
26
27}; // namespace
28
Harvey Yang98ff1b32020-10-28 14:45:35 +080029// static
Harvey Yang9260b662019-08-12 15:48:03 +080030base::Optional<int> IioDeviceImpl::GetIdFromString(const char* id_str) {
31 return IioDevice::GetIdAfterPrefix(id_str, kDeviceIdPrefix);
32}
33
Harvey Yang98ff1b32020-10-28 14:45:35 +080034// static
Harvey Yang9260b662019-08-12 15:48:03 +080035std::string IioDeviceImpl::GetStringFromId(int id) {
36 return base::StringPrintf("%s%d", kDeviceIdPrefix, id);
37}
38
Enrico Granata60a818d2019-05-09 09:56:09 -070039IioDeviceImpl::IioDeviceImpl(IioContextImpl* ctx, iio_device* dev)
Harvey Yangc0d19d82019-07-01 12:17:34 +080040 : IioDevice(),
41 context_(ctx),
42 device_(dev),
Harvey Yang75452e82019-10-02 16:57:01 +080043 buffer_(nullptr, IioBufferDeleter) {
Enrico Granata60a818d2019-05-09 09:56:09 -070044 CHECK(context_);
45 CHECK(device_);
Harvey Yang5e6cb702020-01-15 10:57:44 +080046
Harvey Yang705e40f2020-11-19 15:42:44 +080047 log_prefix_ = base::StringPrintf("Device with id: %d and name: %s. ", GetId(),
48 (GetName() ? GetName() : "null"));
49
Harvey Yang9f48d812020-06-30 16:24:30 +080050 uint32_t chn_count = iio_device_get_channels_count(device_);
51 channels_.resize(chn_count);
52
53 for (uint32_t i = 0; i < chn_count; ++i) {
54 iio_channel* channel = iio_device_get_channel(device_, i);
55 if (channel == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +080056 LOG(WARNING) << log_prefix_ << "Unable to get " << i << "th channel";
Harvey Yang9f48d812020-06-30 16:24:30 +080057 continue;
58 }
59
Harvey Yang705e40f2020-11-19 15:42:44 +080060 channels_[i].chn = std::make_unique<IioChannelImpl>(
61 channel, GetId(), GetName() ? GetName() : "null");
Harvey Yang9f48d812020-06-30 16:24:30 +080062 channels_[i].chn_id = channels_[i].chn->GetId();
63 }
Enrico Granata60a818d2019-05-09 09:56:09 -070064}
65
66IioContext* IioDeviceImpl::GetContext() const {
67 return context_;
68}
69
70const char* IioDeviceImpl::GetName() const {
71 return iio_device_get_name(device_);
72}
73
Harvey Yang9260b662019-08-12 15:48:03 +080074int IioDeviceImpl::GetId() const {
75 const char* id_str = iio_device_get_id(device_);
76
77 auto id = GetIdFromString(id_str);
78 DCHECK(id.has_value());
79 return id.value();
Enrico Granata60a818d2019-05-09 09:56:09 -070080}
81
82base::FilePath IioDeviceImpl::GetPath() const {
Harvey Yang9260b662019-08-12 15:48:03 +080083 std::string id_str = GetStringFromId(GetId());
Harvey Yang36779e92020-08-26 10:46:15 +080084 auto path = base::FilePath(kSysDevString).Append(id_str);
Enrico Granata60a818d2019-05-09 09:56:09 -070085 CHECK(base::DirectoryExists(path));
86 return path;
87}
88
89base::Optional<std::string> IioDeviceImpl::ReadStringAttribute(
90 const std::string& name) const {
Harvey Yang9260b662019-08-12 15:48:03 +080091 char data[kReadAttrBufferSize] = {0};
Enrico Granata60a818d2019-05-09 09:56:09 -070092 ssize_t len = iio_device_attr_read(device_, name.c_str(), data, sizeof(data));
93 if (len < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +080094 LOG(WARNING) << log_prefix_ << "Attempting to read string attribute "
95 << name << " failed: " << len;
Enrico Granata60a818d2019-05-09 09:56:09 -070096 return base::nullopt;
97 }
98 return std::string(data, len);
99}
100
101base::Optional<int64_t> IioDeviceImpl::ReadNumberAttribute(
102 const std::string& name) const {
103 long long val = 0; // NOLINT(runtime/int)
104 int error = iio_device_attr_read_longlong(device_, name.c_str(), &val);
105 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800106 LOG(WARNING) << log_prefix_ << "Attempting to read number attribute "
107 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700108 return base::nullopt;
109 }
110 return val;
111}
112
Enrico Granatad2e57f42019-07-31 10:46:03 -0700113base::Optional<double> IioDeviceImpl::ReadDoubleAttribute(
114 const std::string& name) const {
115 double val = 0;
116 int error = iio_device_attr_read_double(device_, name.c_str(), &val);
117 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800118 LOG(WARNING) << log_prefix_ << "Attempting to read double attribute "
119 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700120 return base::nullopt;
121 }
122 return val;
123}
124
Enrico Granata60a818d2019-05-09 09:56:09 -0700125bool IioDeviceImpl::WriteStringAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800126 const std::string& value) {
127 int error = iio_device_attr_write_raw(device_, name.c_str(), value.data(),
128 value.size());
129 if (error < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800130 LOG(WARNING) << log_prefix_ << "Attempting to write string attribute "
131 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700132 return false;
133 }
134 return true;
135}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700136
Enrico Granata60a818d2019-05-09 09:56:09 -0700137bool IioDeviceImpl::WriteNumberAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800138 int64_t value) {
139 int error = iio_device_attr_write_longlong(device_, name.c_str(), value);
Enrico Granata60a818d2019-05-09 09:56:09 -0700140 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800141 LOG(WARNING) << log_prefix_ << "Attempting to write number attribute "
142 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700143 return false;
144 }
145 return true;
146}
147
Harvey Yang9260b662019-08-12 15:48:03 +0800148bool IioDeviceImpl::WriteDoubleAttribute(const std::string& name,
149 double value) {
150 int error = iio_device_attr_write_double(device_, name.c_str(), value);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700151 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800152 LOG(WARNING) << log_prefix_ << "Attempting to write double attribute "
153 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700154 return false;
155 }
156 return true;
157}
158
Harvey Yangcbfe75e2021-01-21 09:35:25 +0800159bool IioDeviceImpl::HasFifo() const {
160 return iio_device_find_buffer_attr(device_, kHWFifoWatermarkMaxAttr);
161}
162
Enrico Granata60a818d2019-05-09 09:56:09 -0700163iio_device* IioDeviceImpl::GetUnderlyingIioDevice() const {
164 return device_;
165}
166
167bool IioDeviceImpl::SetTrigger(IioDevice* trigger_device) {
Gwendal Grignou66393e22019-11-20 16:46:22 -0800168 // Reset the old - if any - and then add the new trigger.
169 int error = iio_device_set_trigger(device_, NULL);
170 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800171 LOG(WARNING) << log_prefix_ << "Unable to clean trigger, error: " << error;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800172 return false;
173 }
174 if (trigger_device == nullptr)
175 return true;
176
Harvey Yang9260b662019-08-12 15:48:03 +0800177 const iio_device* impl_device = nullptr;
178 int id = trigger_device->GetId();
179 if (id == -2) {
180 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
181 kIioSysfsTrigger);
182 } else {
183 std::string id_str = IioDeviceTriggerImpl::GetStringFromId(id);
184 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
185 id_str.c_str());
186 }
Enrico Granata60a818d2019-05-09 09:56:09 -0700187 if (!impl_device) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800188 LOG(WARNING) << log_prefix_ << "Unable to find device " << id
189 << " in the current context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700190 return false;
191 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800192
193 error = iio_device_set_trigger(device_, impl_device);
194 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800195 LOG(WARNING) << log_prefix_ << "Unable to set trigger to be device "
196 << trigger_device->GetId() << ", error: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700197 return false;
198 }
199 return true;
200}
201
202IioDevice* IioDeviceImpl::GetTrigger() {
203 const iio_device* trigger;
204 int error = iio_device_get_trigger(device_, &trigger);
Harvey Yang74a18762020-12-30 11:09:13 +0800205 if (error)
Enrico Granata60a818d2019-05-09 09:56:09 -0700206 return nullptr;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800207
208 if (trigger == nullptr)
209 return nullptr;
210
Harvey Yang9260b662019-08-12 15:48:03 +0800211 const char* id_str = iio_device_get_id(trigger);
212 auto id = IioDeviceTriggerImpl::GetIdFromString(id_str);
213
214 IioDevice* trigger_device = nullptr;
215 if (id.has_value())
216 trigger_device = GetContext()->GetTriggerById(id.value());
217
Enrico Granata60a818d2019-05-09 09:56:09 -0700218 if (trigger_device == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800219 LOG(WARNING) << log_prefix_ << "Has trigger device " << id_str
220 << ", which cannot be found in this context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700221 }
Harvey Yang9260b662019-08-12 15:48:03 +0800222
Enrico Granata60a818d2019-05-09 09:56:09 -0700223 return trigger_device;
224}
225
Harvey Yangc0d19d82019-07-01 12:17:34 +0800226base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
227 ssize_t sample_size = iio_device_get_sample_size(device_);
228 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800229 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800230 iio_strerror(errno, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800231 LOG(WARNING) << log_prefix_ << "Unable to get sample size: " << errMsg;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800232 return base::nullopt;
233 }
234
235 return static_cast<size_t>(sample_size);
236}
237
Enrico Granata60a818d2019-05-09 09:56:09 -0700238bool IioDeviceImpl::EnableBuffer(size_t count) {
239 if (!WriteNumberAttribute("buffer/length", count))
240 return false;
241 if (!WriteNumberAttribute("buffer/enable", 1))
242 return false;
243
244 return true;
245}
246
247bool IioDeviceImpl::DisableBuffer() {
248 return WriteNumberAttribute("buffer/enable", 0);
249}
250
251bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
252 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
253 if (enabled && count)
254 *count = ReadNumberAttribute("buffer/length").value_or(0);
255
256 return enabled;
257}
258
Harvey Yangdf365182021-01-16 23:43:45 +0800259bool IioDeviceImpl::CreateBuffer() {
260 if (buffer_)
261 return false;
262
263 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
264
265 if (!buffer_) {
266 char errMsg[kErrorBufferSize];
267 iio_strerror(errno, errMsg, sizeof(errMsg));
268 LOG(ERROR) << log_prefix_ << "Unable to allocate buffer: " << errMsg;
269 return false;
270 }
271
272 return true;
273}
274
Harvey Yange8b301b2020-05-19 14:43:03 +0800275base::Optional<int32_t> IioDeviceImpl::GetBufferFd() {
Harvey Yangdf365182021-01-16 23:43:45 +0800276 if (!buffer_)
Harvey Yange8b301b2020-05-19 14:43:03 +0800277 return base::nullopt;
278
279 int32_t fd = iio_buffer_get_poll_fd(buffer_.get());
280 if (fd < 0) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800281 LOG(ERROR) << log_prefix_ << "Failed to get poll fd: " << fd;
Harvey Yange8b301b2020-05-19 14:43:03 +0800282 return base::nullopt;
283 }
284
285 return fd;
286}
287
Harvey Yang34c54d52020-05-20 13:34:20 +0800288base::Optional<IioDevice::IioSample> IioDeviceImpl::ReadSample() {
Harvey Yangdf365182021-01-16 23:43:45 +0800289 if (!buffer_)
Harvey Yang34c54d52020-05-20 13:34:20 +0800290 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800291
292 ssize_t ret = iio_buffer_refill(buffer_.get());
293 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800294 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800295 iio_strerror(-ret, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800296 LOG(ERROR) << log_prefix_ << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800297
Harvey Yang34c54d52020-05-20 13:34:20 +0800298 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800299 }
300
301 const auto buf_step = iio_buffer_step(buffer_.get());
302 size_t sample_size = GetSampleSize().value_or(0);
303
304 // There is something wrong when refilling the buffer.
305 if (buf_step != sample_size) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800306 LOG(ERROR) << log_prefix_
307 << "sample_size doesn't match in refill: " << buf_step
Harvey Yangc0d19d82019-07-01 12:17:34 +0800308 << ", sample_size: " << sample_size;
309
Harvey Yang34c54d52020-05-20 13:34:20 +0800310 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800311 }
312
313 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800314
Harvey Yang34c54d52020-05-20 13:34:20 +0800315 return DeserializeSample(start);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800316}
317
Harvey Yangdf365182021-01-16 23:43:45 +0800318void IioDeviceImpl::FreeBuffer() {
319 buffer_.reset();
320}
321
Harvey Yangc0d19d82019-07-01 12:17:34 +0800322// static
323void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
324 iio_buffer_cancel(buffer);
325 iio_buffer_destroy(buffer);
326}
327
Harvey Yang34c54d52020-05-20 13:34:20 +0800328IioDevice::IioSample IioDeviceImpl::DeserializeSample(const uint8_t* src) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800329 IioSample sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800330 int64_t pos = 0;
331
Harvey Yang9f48d812020-06-30 16:24:30 +0800332 auto channels = GetAllChannels();
333 for (int32_t i = 0; i < channels.size(); ++i) {
334 IioChannelImpl* chn = dynamic_cast<IioChannelImpl*>(channels[i]);
Harvey Yang34c54d52020-05-20 13:34:20 +0800335 if (!chn->IsEnabled())
336 continue;
337
338 size_t len = chn->Length().value_or(0);
339 if (len == 0)
340 continue;
341 len /= CHAR_BIT;
342
343 size_t space_in_block = sizeof(int64_t) - (pos % sizeof(int64_t));
344 if (len > space_in_block) {
345 pos += space_in_block;
346 }
347
348 base::Optional<int64_t> value = chn->Convert(src + pos);
349 pos += len;
350
351 if (value.has_value())
Harvey Yang9f48d812020-06-30 16:24:30 +0800352 sample[i] = value.value();
Harvey Yang34c54d52020-05-20 13:34:20 +0800353 }
354
Harvey Yang9f48d812020-06-30 16:24:30 +0800355 return sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800356}
357
Enrico Granata51cdb942019-06-18 16:40:17 -0700358} // namespace libmems