blob: f222ae85f771beeb68d83165b2121c2362e57063 [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;
Gwendal Grignou887ea812021-02-10 12:58:36 -080026constexpr char kHWFifoWatermarkMaxAttr[] = "hwfifo_watermark_max";
Harvey Yang75452e82019-10-02 16:57:01 +080027
28}; // namespace
29
Harvey Yang98ff1b32020-10-28 14:45:35 +080030// static
Harvey Yang9260b662019-08-12 15:48:03 +080031base::Optional<int> IioDeviceImpl::GetIdFromString(const char* id_str) {
32 return IioDevice::GetIdAfterPrefix(id_str, kDeviceIdPrefix);
33}
34
Harvey Yang98ff1b32020-10-28 14:45:35 +080035// static
Harvey Yang9260b662019-08-12 15:48:03 +080036std::string IioDeviceImpl::GetStringFromId(int id) {
37 return base::StringPrintf("%s%d", kDeviceIdPrefix, id);
38}
39
Enrico Granata60a818d2019-05-09 09:56:09 -070040IioDeviceImpl::IioDeviceImpl(IioContextImpl* ctx, iio_device* dev)
Harvey Yangc0d19d82019-07-01 12:17:34 +080041 : IioDevice(),
42 context_(ctx),
43 device_(dev),
Harvey Yang75452e82019-10-02 16:57:01 +080044 buffer_(nullptr, IioBufferDeleter) {
Enrico Granata60a818d2019-05-09 09:56:09 -070045 CHECK(context_);
46 CHECK(device_);
Harvey Yang5e6cb702020-01-15 10:57:44 +080047
Harvey Yang705e40f2020-11-19 15:42:44 +080048 log_prefix_ = base::StringPrintf("Device with id: %d and name: %s. ", GetId(),
49 (GetName() ? GetName() : "null"));
50
Harvey Yang9f48d812020-06-30 16:24:30 +080051 uint32_t chn_count = iio_device_get_channels_count(device_);
52 channels_.resize(chn_count);
53
54 for (uint32_t i = 0; i < chn_count; ++i) {
55 iio_channel* channel = iio_device_get_channel(device_, i);
56 if (channel == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +080057 LOG(WARNING) << log_prefix_ << "Unable to get " << i << "th channel";
Harvey Yang9f48d812020-06-30 16:24:30 +080058 continue;
59 }
60
Harvey Yang705e40f2020-11-19 15:42:44 +080061 channels_[i].chn = std::make_unique<IioChannelImpl>(
62 channel, GetId(), GetName() ? GetName() : "null");
Harvey Yang9f48d812020-06-30 16:24:30 +080063 channels_[i].chn_id = channels_[i].chn->GetId();
64 }
Enrico Granata60a818d2019-05-09 09:56:09 -070065}
66
67IioContext* IioDeviceImpl::GetContext() const {
68 return context_;
69}
70
71const char* IioDeviceImpl::GetName() const {
72 return iio_device_get_name(device_);
73}
74
Harvey Yang9260b662019-08-12 15:48:03 +080075int IioDeviceImpl::GetId() const {
76 const char* id_str = iio_device_get_id(device_);
77
78 auto id = GetIdFromString(id_str);
79 DCHECK(id.has_value());
80 return id.value();
Enrico Granata60a818d2019-05-09 09:56:09 -070081}
82
83base::FilePath IioDeviceImpl::GetPath() const {
Harvey Yang9260b662019-08-12 15:48:03 +080084 std::string id_str = GetStringFromId(GetId());
Harvey Yang36779e92020-08-26 10:46:15 +080085 auto path = base::FilePath(kSysDevString).Append(id_str);
Enrico Granata60a818d2019-05-09 09:56:09 -070086 CHECK(base::DirectoryExists(path));
87 return path;
88}
89
90base::Optional<std::string> IioDeviceImpl::ReadStringAttribute(
91 const std::string& name) const {
Harvey Yang9260b662019-08-12 15:48:03 +080092 char data[kReadAttrBufferSize] = {0};
Enrico Granata60a818d2019-05-09 09:56:09 -070093 ssize_t len = iio_device_attr_read(device_, name.c_str(), data, sizeof(data));
94 if (len < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +080095 LOG(WARNING) << log_prefix_ << "Attempting to read string attribute "
96 << name << " failed: " << len;
Enrico Granata60a818d2019-05-09 09:56:09 -070097 return base::nullopt;
98 }
99 return std::string(data, len);
100}
101
102base::Optional<int64_t> IioDeviceImpl::ReadNumberAttribute(
103 const std::string& name) const {
104 long long val = 0; // NOLINT(runtime/int)
105 int error = iio_device_attr_read_longlong(device_, name.c_str(), &val);
106 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800107 LOG(WARNING) << log_prefix_ << "Attempting to read number attribute "
108 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700109 return base::nullopt;
110 }
111 return val;
112}
113
Enrico Granatad2e57f42019-07-31 10:46:03 -0700114base::Optional<double> IioDeviceImpl::ReadDoubleAttribute(
115 const std::string& name) const {
116 double val = 0;
117 int error = iio_device_attr_read_double(device_, name.c_str(), &val);
118 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800119 LOG(WARNING) << log_prefix_ << "Attempting to read double attribute "
120 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700121 return base::nullopt;
122 }
123 return val;
124}
125
Enrico Granata60a818d2019-05-09 09:56:09 -0700126bool IioDeviceImpl::WriteStringAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800127 const std::string& value) {
128 int error = iio_device_attr_write_raw(device_, name.c_str(), value.data(),
129 value.size());
130 if (error < 0) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800131 LOG(WARNING) << log_prefix_ << "Attempting to write string attribute "
132 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700133 return false;
134 }
135 return true;
136}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700137
Enrico Granata60a818d2019-05-09 09:56:09 -0700138bool IioDeviceImpl::WriteNumberAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800139 int64_t value) {
140 int error = iio_device_attr_write_longlong(device_, name.c_str(), value);
Enrico Granata60a818d2019-05-09 09:56:09 -0700141 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800142 LOG(WARNING) << log_prefix_ << "Attempting to write number attribute "
143 << name << " failed: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700144 return false;
145 }
146 return true;
147}
148
Harvey Yang9260b662019-08-12 15:48:03 +0800149bool IioDeviceImpl::WriteDoubleAttribute(const std::string& name,
150 double value) {
151 int error = iio_device_attr_write_double(device_, name.c_str(), value);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700152 if (error) {
Harvey Yang3b87b1d2020-12-04 15:38:20 +0800153 LOG(WARNING) << log_prefix_ << "Attempting to write double attribute "
154 << name << " failed: " << error;
Enrico Granatad2e57f42019-07-31 10:46:03 -0700155 return false;
156 }
157 return true;
158}
159
Harvey Yangcbfe75e2021-01-21 09:35:25 +0800160bool IioDeviceImpl::HasFifo() const {
161 return iio_device_find_buffer_attr(device_, kHWFifoWatermarkMaxAttr);
162}
163
Enrico Granata60a818d2019-05-09 09:56:09 -0700164iio_device* IioDeviceImpl::GetUnderlyingIioDevice() const {
165 return device_;
166}
167
168bool IioDeviceImpl::SetTrigger(IioDevice* trigger_device) {
Gwendal Grignou66393e22019-11-20 16:46:22 -0800169 // Reset the old - if any - and then add the new trigger.
170 int error = iio_device_set_trigger(device_, NULL);
171 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800172 LOG(WARNING) << log_prefix_ << "Unable to clean trigger, error: " << error;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800173 return false;
174 }
175 if (trigger_device == nullptr)
176 return true;
177
Harvey Yang9260b662019-08-12 15:48:03 +0800178 const iio_device* impl_device = nullptr;
179 int id = trigger_device->GetId();
180 if (id == -2) {
181 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
182 kIioSysfsTrigger);
183 } else {
184 std::string id_str = IioDeviceTriggerImpl::GetStringFromId(id);
185 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
186 id_str.c_str());
187 }
Enrico Granata60a818d2019-05-09 09:56:09 -0700188 if (!impl_device) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800189 LOG(WARNING) << log_prefix_ << "Unable to find device " << id
190 << " in the current context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700191 return false;
192 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800193
194 error = iio_device_set_trigger(device_, impl_device);
195 if (error) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800196 LOG(WARNING) << log_prefix_ << "Unable to set trigger to be device "
197 << trigger_device->GetId() << ", error: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700198 return false;
199 }
200 return true;
201}
202
203IioDevice* IioDeviceImpl::GetTrigger() {
204 const iio_device* trigger;
205 int error = iio_device_get_trigger(device_, &trigger);
Harvey Yang74a18762020-12-30 11:09:13 +0800206 if (error)
Enrico Granata60a818d2019-05-09 09:56:09 -0700207 return nullptr;
Gwendal Grignou66393e22019-11-20 16:46:22 -0800208
209 if (trigger == nullptr)
210 return nullptr;
211
Harvey Yang9260b662019-08-12 15:48:03 +0800212 const char* id_str = iio_device_get_id(trigger);
213 auto id = IioDeviceTriggerImpl::GetIdFromString(id_str);
214
215 IioDevice* trigger_device = nullptr;
216 if (id.has_value())
217 trigger_device = GetContext()->GetTriggerById(id.value());
218
Enrico Granata60a818d2019-05-09 09:56:09 -0700219 if (trigger_device == nullptr) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800220 LOG(WARNING) << log_prefix_ << "Has trigger device " << id_str
221 << ", which cannot be found in this context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700222 }
Harvey Yang9260b662019-08-12 15:48:03 +0800223
Enrico Granata60a818d2019-05-09 09:56:09 -0700224 return trigger_device;
225}
226
Harvey Yangc0d19d82019-07-01 12:17:34 +0800227base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
228 ssize_t sample_size = iio_device_get_sample_size(device_);
229 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800230 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800231 iio_strerror(errno, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800232 LOG(WARNING) << log_prefix_ << "Unable to get sample size: " << errMsg;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800233 return base::nullopt;
234 }
235
236 return static_cast<size_t>(sample_size);
237}
238
Enrico Granata60a818d2019-05-09 09:56:09 -0700239bool IioDeviceImpl::EnableBuffer(size_t count) {
240 if (!WriteNumberAttribute("buffer/length", count))
241 return false;
242 if (!WriteNumberAttribute("buffer/enable", 1))
243 return false;
244
245 return true;
246}
247
248bool IioDeviceImpl::DisableBuffer() {
249 return WriteNumberAttribute("buffer/enable", 0);
250}
251
252bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
253 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
254 if (enabled && count)
255 *count = ReadNumberAttribute("buffer/length").value_or(0);
256
257 return enabled;
258}
259
Harvey Yangdf365182021-01-16 23:43:45 +0800260bool IioDeviceImpl::CreateBuffer() {
261 if (buffer_)
262 return false;
263
264 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
265
266 if (!buffer_) {
267 char errMsg[kErrorBufferSize];
268 iio_strerror(errno, errMsg, sizeof(errMsg));
269 LOG(ERROR) << log_prefix_ << "Unable to allocate buffer: " << errMsg;
270 return false;
271 }
272
273 return true;
274}
275
Harvey Yange8b301b2020-05-19 14:43:03 +0800276base::Optional<int32_t> IioDeviceImpl::GetBufferFd() {
Harvey Yangdf365182021-01-16 23:43:45 +0800277 if (!buffer_)
Harvey Yange8b301b2020-05-19 14:43:03 +0800278 return base::nullopt;
279
280 int32_t fd = iio_buffer_get_poll_fd(buffer_.get());
281 if (fd < 0) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800282 LOG(ERROR) << log_prefix_ << "Failed to get poll fd: " << fd;
Harvey Yange8b301b2020-05-19 14:43:03 +0800283 return base::nullopt;
284 }
285
286 return fd;
287}
288
Harvey Yang34c54d52020-05-20 13:34:20 +0800289base::Optional<IioDevice::IioSample> IioDeviceImpl::ReadSample() {
Harvey Yangdf365182021-01-16 23:43:45 +0800290 if (!buffer_)
Harvey Yang34c54d52020-05-20 13:34:20 +0800291 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800292
293 ssize_t ret = iio_buffer_refill(buffer_.get());
294 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800295 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800296 iio_strerror(-ret, errMsg, sizeof(errMsg));
Harvey Yang705e40f2020-11-19 15:42:44 +0800297 LOG(ERROR) << log_prefix_ << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800298
Harvey Yang34c54d52020-05-20 13:34:20 +0800299 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800300 }
301
302 const auto buf_step = iio_buffer_step(buffer_.get());
303 size_t sample_size = GetSampleSize().value_or(0);
304
305 // There is something wrong when refilling the buffer.
306 if (buf_step != sample_size) {
Harvey Yang705e40f2020-11-19 15:42:44 +0800307 LOG(ERROR) << log_prefix_
308 << "sample_size doesn't match in refill: " << buf_step
Harvey Yangc0d19d82019-07-01 12:17:34 +0800309 << ", sample_size: " << sample_size;
310
Harvey Yang34c54d52020-05-20 13:34:20 +0800311 return base::nullopt;
Harvey Yangc0d19d82019-07-01 12:17:34 +0800312 }
313
314 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800315
Harvey Yang34c54d52020-05-20 13:34:20 +0800316 return DeserializeSample(start);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800317}
318
Harvey Yangdf365182021-01-16 23:43:45 +0800319void IioDeviceImpl::FreeBuffer() {
320 buffer_.reset();
321}
322
Harvey Yangc0d19d82019-07-01 12:17:34 +0800323// static
324void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
325 iio_buffer_cancel(buffer);
326 iio_buffer_destroy(buffer);
327}
328
Harvey Yang34c54d52020-05-20 13:34:20 +0800329IioDevice::IioSample IioDeviceImpl::DeserializeSample(const uint8_t* src) {
Harvey Yang9f48d812020-06-30 16:24:30 +0800330 IioSample sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800331 int64_t pos = 0;
332
Harvey Yang9f48d812020-06-30 16:24:30 +0800333 auto channels = GetAllChannels();
334 for (int32_t i = 0; i < channels.size(); ++i) {
335 IioChannelImpl* chn = dynamic_cast<IioChannelImpl*>(channels[i]);
Harvey Yang34c54d52020-05-20 13:34:20 +0800336 if (!chn->IsEnabled())
337 continue;
338
339 size_t len = chn->Length().value_or(0);
340 if (len == 0)
341 continue;
342 len /= CHAR_BIT;
343
344 size_t space_in_block = sizeof(int64_t) - (pos % sizeof(int64_t));
345 if (len > space_in_block) {
346 pos += space_in_block;
347 }
348
349 base::Optional<int64_t> value = chn->Convert(src + pos);
350 pos += len;
351
352 if (value.has_value())
Harvey Yang9f48d812020-06-30 16:24:30 +0800353 sample[i] = value.value();
Harvey Yang34c54d52020-05-20 13:34:20 +0800354 }
355
Harvey Yang9f48d812020-06-30 16:24:30 +0800356 return sample;
Harvey Yang34c54d52020-05-20 13:34:20 +0800357}
358
Enrico Granata51cdb942019-06-18 16:40:17 -0700359} // namespace libmems