blob: 8bd92f2f00c49b96f0f5f8dd4da20dd54401ab35 [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) {
128 auto impl_device = trigger_device->GetUnderlyingIioDevice();
129 if (!impl_device) {
130 LOG(WARNING) << "cannot find device " << trigger_device->GetId()
131 << " in the current context";
132 return false;
133 }
134 int ok = iio_device_set_trigger(device_, impl_device);
135 if (ok) {
136 LOG(WARNING) << "Unable to set trigger for device " << GetId()
137 << " to be device " << trigger_device->GetId()
138 << ", error: " << ok;
139 return false;
140 }
141 return true;
142}
143
144IioDevice* IioDeviceImpl::GetTrigger() {
145 const iio_device* trigger;
146 int error = iio_device_get_trigger(device_, &trigger);
147 if (error) {
148 LOG(WARNING) << "Unable to get trigger for device " << GetId();
149 return nullptr;
150 }
151 const char* trigger_id = iio_device_get_id(trigger);
152 auto trigger_device = GetContext()->GetDevice(trigger_id);
153 if (trigger_device == nullptr) {
154 LOG(WARNING) << GetId() << " has trigger device " << trigger_id
155 << "which cannot be found in this context";
156 return nullptr;
157 }
158 return trigger_device;
159}
160
161IioChannel* IioDeviceImpl::GetChannel(const std::string& name) {
162 auto k = channels_.find(name);
163 if (k != channels_.end())
164 return k->second.get();
165 iio_channel* channel = iio_device_find_channel(device_, name.c_str(), true);
166 if (channel == nullptr)
167 channel = iio_device_find_channel(device_, name.c_str(), false);
168 if (channel == nullptr)
169 return nullptr;
170 channels_.emplace(name, std::make_unique<IioChannelImpl>(channel));
171 return channels_[name].get();
172}
173
Harvey Yangc0d19d82019-07-01 12:17:34 +0800174base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
175 ssize_t sample_size = iio_device_get_sample_size(device_);
176 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800177 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800178 iio_strerror(errno, errMsg, sizeof(errMsg));
179 LOG(WARNING) << "Unable to get sample size: " << errMsg;
180 return base::nullopt;
181 }
182
183 return static_cast<size_t>(sample_size);
184}
185
Enrico Granata60a818d2019-05-09 09:56:09 -0700186bool IioDeviceImpl::EnableBuffer(size_t count) {
187 if (!WriteNumberAttribute("buffer/length", count))
188 return false;
189 if (!WriteNumberAttribute("buffer/enable", 1))
190 return false;
191
192 return true;
193}
194
195bool IioDeviceImpl::DisableBuffer() {
196 return WriteNumberAttribute("buffer/enable", 0);
197}
198
199bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
200 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
201 if (enabled && count)
202 *count = ReadNumberAttribute("buffer/length").value_or(0);
203
204 return enabled;
205}
206
Harvey Yang75452e82019-10-02 16:57:01 +0800207bool IioDeviceImpl::ReadEvent(std::vector<uint8_t>* event) {
208 if (!CreateBuffer())
Harvey Yangc0d19d82019-07-01 12:17:34 +0800209 return false;
210
Harvey Yang75452e82019-10-02 16:57:01 +0800211 event->clear();
Harvey Yangc0d19d82019-07-01 12:17:34 +0800212
213 ssize_t ret = iio_buffer_refill(buffer_.get());
214 if (ret < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800215 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800216 iio_strerror(-ret, errMsg, sizeof(errMsg));
217 LOG(ERROR) << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800218 buffer_.reset();
Harvey Yangae53dc82019-07-25 18:11:20 +0800219
Harvey Yangc0d19d82019-07-01 12:17:34 +0800220 return false;
221 }
222
223 const auto buf_step = iio_buffer_step(buffer_.get());
224 size_t sample_size = GetSampleSize().value_or(0);
225
226 // There is something wrong when refilling the buffer.
227 if (buf_step != sample_size) {
228 LOG(ERROR) << "sample_size doesn't match in refill: " << buf_step
229 << ", sample_size: " << sample_size;
Harvey Yangae53dc82019-07-25 18:11:20 +0800230 buffer_.reset();
Harvey Yangc0d19d82019-07-01 12:17:34 +0800231
232 return false;
233 }
234
235 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
236 size_t len = reinterpret_cast<intptr_t>(iio_buffer_end(buffer_.get())) -
237 reinterpret_cast<intptr_t>(start);
238
Harvey Yang75452e82019-10-02 16:57:01 +0800239 event->reserve(len);
240 event->insert(event->begin(), start, start + len);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800241
242 return true;
243}
244
245// static
246void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
247 iio_buffer_cancel(buffer);
248 iio_buffer_destroy(buffer);
249}
250
Harvey Yang75452e82019-10-02 16:57:01 +0800251bool IioDeviceImpl::CreateBuffer() {
252 if (buffer_ &&
Harvey Yangc0d19d82019-07-01 12:17:34 +0800253 iio_device_get_sample_size(device_) == iio_buffer_step(buffer_.get()))
254 return true;
255
Harvey Yangc0d19d82019-07-01 12:17:34 +0800256 buffer_.reset();
Harvey Yang75452e82019-10-02 16:57:01 +0800257 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800258
259 if (!buffer_) {
Harvey Yang75452e82019-10-02 16:57:01 +0800260 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800261 iio_strerror(errno, errMsg, sizeof(errMsg));
262 LOG(ERROR) << "Unable to allocate buffer: " << errMsg;
263 return false;
264 }
265
266 return true;
267}
268
Enrico Granata51cdb942019-06-18 16:40:17 -0700269} // namespace libmems