blob: 92e2df1d5db4bf4f69e1d5d1d50f8872b367f7b0 [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>
11
Enrico Granata51cdb942019-06-18 16:40:17 -070012#include "libmems/iio_channel_impl.h"
13#include "libmems/iio_context_impl.h"
14#include "libmems/iio_device_impl.h"
Enrico Granata60a818d2019-05-09 09:56:09 -070015
Harvey Yangc0d19d82019-07-01 12:17:34 +080016#define ERROR_BUFFER_SIZE 256
17
Enrico Granata51cdb942019-06-18 16:40:17 -070018namespace libmems {
Enrico Granata60a818d2019-05-09 09:56:09 -070019
Harvey Yang75452e82019-10-02 16:57:01 +080020namespace {
21
22constexpr int kErrorBufferSize = 256;
23constexpr int kNumSamples = 1;
24
25}; // namespace
26
Enrico Granata60a818d2019-05-09 09:56:09 -070027IioDeviceImpl::IioDeviceImpl(IioContextImpl* ctx, iio_device* dev)
Harvey Yangc0d19d82019-07-01 12:17:34 +080028 : IioDevice(),
29 context_(ctx),
30 device_(dev),
Harvey Yang75452e82019-10-02 16:57:01 +080031 buffer_(nullptr, IioBufferDeleter) {
Enrico Granata60a818d2019-05-09 09:56:09 -070032 CHECK(context_);
33 CHECK(device_);
34}
35
36IioContext* IioDeviceImpl::GetContext() const {
37 return context_;
38}
39
40const char* IioDeviceImpl::GetName() const {
41 return iio_device_get_name(device_);
42}
43
44const char* IioDeviceImpl::GetId() const {
45 return iio_device_get_id(device_);
46}
47
48base::FilePath IioDeviceImpl::GetPath() const {
49 auto path = base::FilePath("/sys/bus/iio/devices").Append(GetId());
50 CHECK(base::DirectoryExists(path));
51 return path;
52}
53
54base::Optional<std::string> IioDeviceImpl::ReadStringAttribute(
55 const std::string& name) const {
56 char data[1024] = {0};
57 ssize_t len = iio_device_attr_read(device_, name.c_str(), data, sizeof(data));
58 if (len < 0) {
59 LOG(WARNING) << "Attempting to read attribute " << name
60 << " failed: " << len;
61 return base::nullopt;
62 }
63 return std::string(data, len);
64}
65
66base::Optional<int64_t> IioDeviceImpl::ReadNumberAttribute(
67 const std::string& name) const {
68 long long val = 0; // NOLINT(runtime/int)
69 int error = iio_device_attr_read_longlong(device_, name.c_str(), &val);
70 if (error) {
71 LOG(WARNING) << "Attempting to read attribute " << name
72 << " failed: " << error;
73 return base::nullopt;
74 }
75 return val;
76}
77
Enrico Granatad2e57f42019-07-31 10:46:03 -070078base::Optional<double> IioDeviceImpl::ReadDoubleAttribute(
79 const std::string& name) const {
80 double val = 0;
81 int error = iio_device_attr_read_double(device_, name.c_str(), &val);
82 if (error) {
83 LOG(WARNING) << "Attempting to read attribute " << name
84 << " failed: " << error;
85 return base::nullopt;
86 }
87 return val;
88}
89
Enrico Granata60a818d2019-05-09 09:56:09 -070090bool IioDeviceImpl::WriteStringAttribute(const std::string& name,
91 const std::string& val) {
92 int error =
93 iio_device_attr_write_raw(device_, name.c_str(), val.data(), val.size());
94 if (error) {
95 LOG(WARNING) << "Attempting to write attribute " << name
96 << " failed: " << error;
97 return false;
98 }
99 return true;
100}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700101
Enrico Granata60a818d2019-05-09 09:56:09 -0700102bool IioDeviceImpl::WriteNumberAttribute(const std::string& name,
103 int64_t val) {
104 int error = iio_device_attr_write_longlong(device_, name.c_str(), val);
105 if (error) {
106 LOG(WARNING) << "Attempting to write attribute " << name
107 << " failed: " << error;
108 return false;
109 }
110 return true;
111}
112
Enrico Granatad2e57f42019-07-31 10:46:03 -0700113bool IioDeviceImpl::WriteDoubleAttribute(const std::string& name, double val) {
114 int error = iio_device_attr_write_double(device_, name.c_str(), val);
115 if (error) {
116 LOG(WARNING) << "Attempting to write attribute " << name
117 << " failed: " << error;
118 return false;
119 }
120 return true;
121}
122
Enrico Granata60a818d2019-05-09 09:56:09 -0700123iio_device* IioDeviceImpl::GetUnderlyingIioDevice() const {
124 return device_;
125}
126
127bool IioDeviceImpl::SetTrigger(IioDevice* trigger_device) {
Gwendal Grignou66393e22019-11-20 16:46:22 -0800128 // Reset the old - if any - and then add the new trigger.
129 int error = iio_device_set_trigger(device_, NULL);
130 if (error) {
131 LOG(WARNING) << "Unable to clean triiger of device " << GetId()
132 << ", error: " << error;
133 return false;
134 }
135 if (trigger_device == nullptr)
136 return true;
137
Enrico Granata60a818d2019-05-09 09:56:09 -0700138 auto impl_device = trigger_device->GetUnderlyingIioDevice();
139 if (!impl_device) {
140 LOG(WARNING) << "cannot find device " << trigger_device->GetId()
141 << " in the current context";
142 return false;
143 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800144
145 error = iio_device_set_trigger(device_, impl_device);
146 if (error) {
Enrico Granata60a818d2019-05-09 09:56:09 -0700147 LOG(WARNING) << "Unable to set trigger for device " << GetId()
148 << " to be device " << trigger_device->GetId()
Gwendal Grignou66393e22019-11-20 16:46:22 -0800149 << ", error: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700150 return false;
151 }
152 return true;
153}
154
155IioDevice* IioDeviceImpl::GetTrigger() {
156 const iio_device* trigger;
157 int error = iio_device_get_trigger(device_, &trigger);
158 if (error) {
159 LOG(WARNING) << "Unable to get trigger for device " << GetId();
160 return nullptr;
161 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800162
163 if (trigger == nullptr)
164 return nullptr;
165
Enrico Granata60a818d2019-05-09 09:56:09 -0700166 const char* trigger_id = iio_device_get_id(trigger);
167 auto trigger_device = GetContext()->GetDevice(trigger_id);
168 if (trigger_device == nullptr) {
169 LOG(WARNING) << GetId() << " has trigger device " << trigger_id
170 << "which cannot be found in this context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700171 }
172 return trigger_device;
173}
174
175IioChannel* IioDeviceImpl::GetChannel(const std::string& name) {
176 auto k = channels_.find(name);
177 if (k != channels_.end())
178 return k->second.get();
179 iio_channel* channel = iio_device_find_channel(device_, name.c_str(), true);
180 if (channel == nullptr)
181 channel = iio_device_find_channel(device_, name.c_str(), false);
182 if (channel == nullptr)
183 return nullptr;
184 channels_.emplace(name, std::make_unique<IioChannelImpl>(channel));
185 return channels_[name].get();
186}
187
Harvey Yangc0d19d82019-07-01 12:17:34 +0800188base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
189 ssize_t sample_size = iio_device_get_sample_size(device_);
190 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800191 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800192 iio_strerror(errno, errMsg, sizeof(errMsg));
193 LOG(WARNING) << "Unable to get sample size: " << errMsg;
194 return base::nullopt;
195 }
196
197 return static_cast<size_t>(sample_size);
198}
199
Enrico Granata60a818d2019-05-09 09:56:09 -0700200bool IioDeviceImpl::EnableBuffer(size_t count) {
201 if (!WriteNumberAttribute("buffer/length", count))
202 return false;
203 if (!WriteNumberAttribute("buffer/enable", 1))
204 return false;
205
206 return true;
207}
208
209bool IioDeviceImpl::DisableBuffer() {
210 return WriteNumberAttribute("buffer/enable", 0);
211}
212
213bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
214 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
215 if (enabled && count)
216 *count = ReadNumberAttribute("buffer/length").value_or(0);
217
218 return enabled;
219}
220
Harvey Yang75452e82019-10-02 16:57:01 +0800221bool IioDeviceImpl::ReadEvent(std::vector<uint8_t>* event) {
222 if (!CreateBuffer())
Harvey Yangc0d19d82019-07-01 12:17:34 +0800223 return false;
224
Harvey Yang75452e82019-10-02 16:57:01 +0800225 event->clear();
Harvey Yangc0d19d82019-07-01 12:17:34 +0800226
227 ssize_t ret = iio_buffer_refill(buffer_.get());
228 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800229 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800230 iio_strerror(-ret, errMsg, sizeof(errMsg));
231 LOG(ERROR) << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800232 buffer_.reset();
Harvey Yangae53dc82019-07-25 18:11:20 +0800233
Harvey Yangc0d19d82019-07-01 12:17:34 +0800234 return false;
235 }
236
237 const auto buf_step = iio_buffer_step(buffer_.get());
238 size_t sample_size = GetSampleSize().value_or(0);
239
240 // There is something wrong when refilling the buffer.
241 if (buf_step != sample_size) {
242 LOG(ERROR) << "sample_size doesn't match in refill: " << buf_step
243 << ", sample_size: " << sample_size;
Harvey Yangae53dc82019-07-25 18:11:20 +0800244 buffer_.reset();
Harvey Yangc0d19d82019-07-01 12:17:34 +0800245
246 return false;
247 }
248
249 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
250 size_t len = reinterpret_cast<intptr_t>(iio_buffer_end(buffer_.get())) -
251 reinterpret_cast<intptr_t>(start);
252
Harvey Yang75452e82019-10-02 16:57:01 +0800253 event->reserve(len);
254 event->insert(event->begin(), start, start + len);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800255
256 return true;
257}
258
259// static
260void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
261 iio_buffer_cancel(buffer);
262 iio_buffer_destroy(buffer);
263}
264
Harvey Yang75452e82019-10-02 16:57:01 +0800265bool IioDeviceImpl::CreateBuffer() {
266 if (buffer_ &&
Harvey Yangc0d19d82019-07-01 12:17:34 +0800267 iio_device_get_sample_size(device_) == iio_buffer_step(buffer_.get()))
268 return true;
269
Harvey Yangc0d19d82019-07-01 12:17:34 +0800270 buffer_.reset();
Harvey Yang75452e82019-10-02 16:57:01 +0800271 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800272
273 if (!buffer_) {
Harvey Yang75452e82019-10-02 16:57:01 +0800274 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800275 iio_strerror(errno, errMsg, sizeof(errMsg));
276 LOG(ERROR) << "Unable to allocate buffer: " << errMsg;
277 return false;
278 }
279
280 return true;
281}
282
Enrico Granata51cdb942019-06-18 16:40:17 -0700283} // namespace libmems