blob: 00c3c2e2ea5077713a2bf91e05e74a26d22b0082 [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
Harvey Yang98ff1b32020-10-28 14:45:35 +080027constexpr base::TimeDelta kDefaultPeriodForObsoleteSamples =
28 base::TimeDelta::FromMilliseconds(10.0);
29
Harvey Yang75452e82019-10-02 16:57:01 +080030}; // namespace
31
Harvey Yang98ff1b32020-10-28 14:45:35 +080032// static
Harvey Yang9260b662019-08-12 15:48:03 +080033base::Optional<int> IioDeviceImpl::GetIdFromString(const char* id_str) {
34 return IioDevice::GetIdAfterPrefix(id_str, kDeviceIdPrefix);
35}
36
Harvey Yang98ff1b32020-10-28 14:45:35 +080037// static
Harvey Yang9260b662019-08-12 15:48:03 +080038std::string IioDeviceImpl::GetStringFromId(int id) {
39 return base::StringPrintf("%s%d", kDeviceIdPrefix, id);
40}
41
Enrico Granata60a818d2019-05-09 09:56:09 -070042IioDeviceImpl::IioDeviceImpl(IioContextImpl* ctx, iio_device* dev)
Harvey Yangc0d19d82019-07-01 12:17:34 +080043 : IioDevice(),
44 context_(ctx),
45 device_(dev),
Harvey Yang75452e82019-10-02 16:57:01 +080046 buffer_(nullptr, IioBufferDeleter) {
Enrico Granata60a818d2019-05-09 09:56:09 -070047 CHECK(context_);
48 CHECK(device_);
Harvey Yang5e6cb702020-01-15 10:57:44 +080049
Harvey Yang705e40f2020-11-19 15:42:44 +080050 log_prefix_ = base::StringPrintf("Device with id: %d and name: %s. ", GetId(),
51 (GetName() ? GetName() : "null"));
52
Harvey Yang9f48d812020-06-30 16:24:30 +080053 uint32_t chn_count = iio_device_get_channels_count(device_);
54 channels_.resize(chn_count);
55
56 for (uint32_t i = 0; i < chn_count; ++i) {
57 iio_channel* channel = iio_device_get_channel(device_, i);
58 if (channel == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +080059 LOG(WARNING) << log_prefix_ << "Unable to get " << i << "th channel";
Harvey Yang9f48d812020-06-30 16:24:30 +080060 continue;
61 }
62
Harvey Yang705e40f2020-11-19 15:42:44 +080063 channels_[i].chn = std::make_unique<IioChannelImpl>(
64 channel, GetId(), GetName() ? GetName() : "null");
Harvey Yang9f48d812020-06-30 16:24:30 +080065 channels_[i].chn_id = channels_[i].chn->GetId();
66 }
Enrico Granata60a818d2019-05-09 09:56:09 -070067}
68
69IioContext* IioDeviceImpl::GetContext() const {
70 return context_;
71}
72
73const char* IioDeviceImpl::GetName() const {
74 return iio_device_get_name(device_);
75}
76
Harvey Yang9260b662019-08-12 15:48:03 +080077int IioDeviceImpl::GetId() const {
78 const char* id_str = iio_device_get_id(device_);
79
80 auto id = GetIdFromString(id_str);
81 DCHECK(id.has_value());
82 return id.value();
Enrico Granata60a818d2019-05-09 09:56:09 -070083}
84
85base::FilePath IioDeviceImpl::GetPath() const {
Harvey Yang9260b662019-08-12 15:48:03 +080086 std::string id_str = GetStringFromId(GetId());
Harvey Yang36779e92020-08-26 10:46:15 +080087 auto path = base::FilePath(kSysDevString).Append(id_str);
Enrico Granata60a818d2019-05-09 09:56:09 -070088 CHECK(base::DirectoryExists(path));
89 return path;
90}
91
92base::Optional<std::string> IioDeviceImpl::ReadStringAttribute(
93 const std::string& name) const {
Harvey Yang9260b662019-08-12 15:48:03 +080094 char data[kReadAttrBufferSize] = {0};
Enrico Granata60a818d2019-05-09 09:56:09 -070095 ssize_t len = iio_device_attr_read(device_, name.c_str(), data, sizeof(data));
96 if (len < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +080097 LOG(WARNING) << log_prefix_ << "Attempting to read string attribute "
98 << name << " failed: " << len;
Enrico Granata60a818d2019-05-09 09:56:09 -070099 return base::nullopt;
100 }
101 return std::string(data, len);
102}
103
104base::Optional<int64_t> IioDeviceImpl::ReadNumberAttribute(
105 const std::string& name) const {
106 long long val = 0; // NOLINT(runtime/int)
107 int error = iio_device_attr_read_longlong(device_, name.c_str(), &val);
108 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800109 LOG(WARNING) << log_prefix_ << "Attempting to read number attribute "
110 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700111 return base::nullopt;
112 }
113 return val;
114}
115
Enrico Granatad2e57f42019-07-31 10:46:03 -0700116base::Optional<double> IioDeviceImpl::ReadDoubleAttribute(
117 const std::string& name) const {
118 double val = 0;
119 int error = iio_device_attr_read_double(device_, name.c_str(), &val);
120 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800121 LOG(WARNING) << log_prefix_ << "Attempting to read double attribute "
122 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700123 return base::nullopt;
124 }
125 return val;
126}
127
Enrico Granata60a818d2019-05-09 09:56:09 -0700128bool IioDeviceImpl::WriteStringAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800129 const std::string& value) {
130 int error = iio_device_attr_write_raw(device_, name.c_str(), value.data(),
131 value.size());
132 if (error < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800133 LOG(WARNING) << log_prefix_ << "Attempting to write string attribute "
134 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700135 return false;
136 }
137 return true;
138}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700139
Enrico Granata60a818d2019-05-09 09:56:09 -0700140bool IioDeviceImpl::WriteNumberAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800141 int64_t value) {
142 int error = iio_device_attr_write_longlong(device_, name.c_str(), value);
Enrico Granata60a818d2019-05-09 09:56:09 -0700143 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800144 LOG(WARNING) << log_prefix_ << "Attempting to write number attribute "
145 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700146 return false;
147 }
148 return true;
149}
150
Harvey Yang9260b662019-08-12 15:48:03 +0800151bool IioDeviceImpl::WriteDoubleAttribute(const std::string& name,
152 double value) {
153 int error = iio_device_attr_write_double(device_, name.c_str(), value);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700154 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800155 LOG(WARNING) << log_prefix_ << "Attempting to write double attribute "
156 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700157 return false;
158 }
159 return true;
160}
161
Enrico Granata60a818d2019-05-09 09:56:09 -0700162iio_device* IioDeviceImpl::GetUnderlyingIioDevice() const {
163 return device_;
164}
165
166bool IioDeviceImpl::SetTrigger(IioDevice* trigger_device) {
Gwendal Grignou66393e22019-11-20 16:46:22 -0800167 // Reset the old - if any - and then add the new trigger.
168 int error = iio_device_set_trigger(device_, NULL);
169 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800170 LOG(WARNING) << log_prefix_ << "Unable to clean trigger, error: " << error;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800171 return false;
172 }
173 if (trigger_device == nullptr)
174 return true;
175
Harvey Yang9260b662019-08-12 15:48:03 +0800176 const iio_device* impl_device = nullptr;
177 int id = trigger_device->GetId();
178 if (id == -2) {
179 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
180 kIioSysfsTrigger);
181 } else {
182 std::string id_str = IioDeviceTriggerImpl::GetStringFromId(id);
183 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
184 id_str.c_str());
185 }
Enrico Granata60a818d2019-05-09 09:56:09 -0700186 if (!impl_device) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800187 LOG(WARNING) << log_prefix_ << "Unable to find device " << id
188 << " in the current context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700189 return false;
190 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800191
192 error = iio_device_set_trigger(device_, impl_device);
193 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800194 LOG(WARNING) << log_prefix_ << "Unable to set trigger to be device "
195 << trigger_device->GetId() << ", error: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700196 return false;
197 }
198 return true;
199}
200
201IioDevice* IioDeviceImpl::GetTrigger() {
202 const iio_device* trigger;
203 int error = iio_device_get_trigger(device_, &trigger);
Harvey Yang74a18762020-12-30 11:09:13 +0800204 if (error)
Enrico Granata60a818d2019-05-09 09:56:09 -0700205 return nullptr;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800206
207 if (trigger == nullptr)
208 return nullptr;
209
Harvey Yang9260b662019-08-12 15:48:03 +0800210 const char* id_str = iio_device_get_id(trigger);
211 auto id = IioDeviceTriggerImpl::GetIdFromString(id_str);
212
213 IioDevice* trigger_device = nullptr;
214 if (id.has_value())
215 trigger_device = GetContext()->GetTriggerById(id.value());
216
Enrico Granata60a818d2019-05-09 09:56:09 -0700217 if (trigger_device == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800218 LOG(WARNING) << log_prefix_ << "Has trigger device " << id_str
219 << ", which cannot be found in this context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700220 }
Harvey Yang9260b662019-08-12 15:48:03 +0800221
Enrico Granata60a818d2019-05-09 09:56:09 -0700222 return trigger_device;
223}
224
Harvey Yangc0d19d82019-07-01 12:17:34 +0800225base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
226 ssize_t sample_size = iio_device_get_sample_size(device_);
227 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800228 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800229 iio_strerror(errno, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800230 LOG(WARNING) << log_prefix_ << "Unable to get sample size: " << errMsg;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800231 return base::nullopt;
232 }
233
234 return static_cast<size_t>(sample_size);
235}
236
Enrico Granata60a818d2019-05-09 09:56:09 -0700237bool IioDeviceImpl::EnableBuffer(size_t count) {
238 if (!WriteNumberAttribute("buffer/length", count))
239 return false;
240 if (!WriteNumberAttribute("buffer/enable", 1))
241 return false;
242
243 return true;
244}
245
246bool IioDeviceImpl::DisableBuffer() {
247 return WriteNumberAttribute("buffer/enable", 0);
248}
249
250bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
251 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
252 if (enabled && count)
253 *count = ReadNumberAttribute("buffer/length").value_or(0);
254
255 return enabled;
256}
257
Harvey Yange8b301b2020-05-19 14:43:03 +0800258base::Optional<int32_t> IioDeviceImpl::GetBufferFd() {
259 if (!CreateBuffer())
260 return base::nullopt;
261
262 int32_t fd = iio_buffer_get_poll_fd(buffer_.get());
263 if (fd < 0) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800264 LOG(ERROR) << log_prefix_ << "Failed to get poll fd: " << fd;
Harvey Yange8b301b2020-05-19 14:43:03 +0800265 return base::nullopt;
266 }
267
268 return fd;
269}
270
Harvey Yang34c54d52020-05-20 13:34:20 +0800271base::Optional<IioDevice::IioSample> IioDeviceImpl::ReadSample() {
Harvey Yang75452e82019-10-02 16:57:01 +0800272 if (!CreateBuffer())
Harvey Yang34c54d52020-05-20 13:34:20 +0800273 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800274
275 ssize_t ret = iio_buffer_refill(buffer_.get());
276 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800277 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800278 iio_strerror(-ret, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800279 LOG(ERROR) << log_prefix_ << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800280 buffer_.reset();
Harvey Yangae53dc82019-07-25 18:11:20 +0800281
Harvey Yang34c54d52020-05-20 13:34:20 +0800282 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800283 }
284
285 const auto buf_step = iio_buffer_step(buffer_.get());
286 size_t sample_size = GetSampleSize().value_or(0);
287
288 // There is something wrong when refilling the buffer.
289 if (buf_step != sample_size) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800290 LOG(ERROR) << log_prefix_
291 << "sample_size doesn't match in refill: " << buf_step
Harvey Yangc0d19d82019-07-01 12:17:34 +0800292 << ", sample_size: " << sample_size;
Harvey Yangae53dc82019-07-25 18:11:20 +0800293 buffer_.reset();
Harvey Yangc0d19d82019-07-01 12:17:34 +0800294
Harvey Yang34c54d52020-05-20 13:34:20 +0800295 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800296 }
297
298 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800299
Harvey Yang34c54d52020-05-20 13:34:20 +0800300 return DeserializeSample(start);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800301}
302
Harvey Yang98ff1b32020-10-28 14:45:35 +0800303base::TimeDelta IioDeviceImpl::GetPeriodForObsoleteSamplesInMilliseconds() {
304 double min_freq, max_freq;
305 if (!GetMinMaxFrequency(&min_freq, &max_freq) || max_freq <= 0.0)
306 return kDefaultPeriodForObsoleteSamples;
307
308 return base::TimeDelta::FromMilliseconds(1.0 / max_freq);
309}
310
Harvey Yangc0d19d82019-07-01 12:17:34 +0800311// static
312void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
313 iio_buffer_cancel(buffer);
314 iio_buffer_destroy(buffer);
315}
316
Harvey Yang75452e82019-10-02 16:57:01 +0800317bool IioDeviceImpl::CreateBuffer() {
318 if (buffer_ &&
Harvey Yangc0d19d82019-07-01 12:17:34 +0800319 iio_device_get_sample_size(device_) == iio_buffer_step(buffer_.get()))
320 return true;
321
Harvey Yangc0d19d82019-07-01 12:17:34 +0800322 buffer_.reset();
Harvey Yang75452e82019-10-02 16:57:01 +0800323 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800324
325 if (!buffer_) {
Harvey Yang75452e82019-10-02 16:57:01 +0800326 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800327 iio_strerror(errno, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800328 LOG(ERROR) << log_prefix_ << "Unable to allocate buffer: " << errMsg;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800329 return false;
330 }
331
332 return true;
333}
334
Harvey Yang34c54d52020-05-20 13:34:20 +0800335IioDevice::IioSample IioDeviceImpl::DeserializeSample(const uint8_t* src) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800336 IioSample sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800337 int64_t pos = 0;
338
Harvey Yang9f48d812020-06-30 16:24:30 +0800339 auto channels = GetAllChannels();
340 for (int32_t i = 0; i < channels.size(); ++i) {
341 IioChannelImpl* chn = dynamic_cast<IioChannelImpl*>(channels[i]);
Harvey Yang34c54d52020-05-20 13:34:20 +0800342 if (!chn->IsEnabled())
343 continue;
344
345 size_t len = chn->Length().value_or(0);
346 if (len == 0)
347 continue;
348 len /= CHAR_BIT;
349
350 size_t space_in_block = sizeof(int64_t) - (pos % sizeof(int64_t));
351 if (len > space_in_block) {
352 pos += space_in_block;
353 }
354
355 base::Optional<int64_t> value = chn->Convert(src + pos);
356 pos += len;
357
358 if (value.has_value())
Harvey Yang9f48d812020-06-30 16:24:30 +0800359 sample[i] = value.value();
Harvey Yang34c54d52020-05-20 13:34:20 +0800360 }
361
Harvey Yang9f48d812020-06-30 16:24:30 +0800362 return sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800363}
364
Enrico Granata51cdb942019-06-18 16:40:17 -0700365} // namespace libmems