blob: 4dffa72673fd195185fa520b336954b1719f52f1 [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 Yang9260b662019-08-12 15:48:03 +080029base::Optional<int> IioDeviceImpl::GetIdFromString(const char* id_str) {
30 return IioDevice::GetIdAfterPrefix(id_str, kDeviceIdPrefix);
31}
32
33std::string IioDeviceImpl::GetStringFromId(int id) {
34 return base::StringPrintf("%s%d", kDeviceIdPrefix, id);
35}
36
Enrico Granata60a818d2019-05-09 09:56:09 -070037IioDeviceImpl::IioDeviceImpl(IioContextImpl* ctx, iio_device* dev)
Harvey Yangc0d19d82019-07-01 12:17:34 +080038 : IioDevice(),
39 context_(ctx),
40 device_(dev),
Harvey Yang75452e82019-10-02 16:57:01 +080041 buffer_(nullptr, IioBufferDeleter) {
Enrico Granata60a818d2019-05-09 09:56:09 -070042 CHECK(context_);
43 CHECK(device_);
44}
45
46IioContext* IioDeviceImpl::GetContext() const {
47 return context_;
48}
49
50const char* IioDeviceImpl::GetName() const {
51 return iio_device_get_name(device_);
52}
53
Harvey Yang9260b662019-08-12 15:48:03 +080054int IioDeviceImpl::GetId() const {
55 const char* id_str = iio_device_get_id(device_);
56
57 auto id = GetIdFromString(id_str);
58 DCHECK(id.has_value());
59 return id.value();
Enrico Granata60a818d2019-05-09 09:56:09 -070060}
61
62base::FilePath IioDeviceImpl::GetPath() const {
Harvey Yang9260b662019-08-12 15:48:03 +080063 std::string id_str = GetStringFromId(GetId());
64 auto path = base::FilePath("/sys/bus/iio/devices").Append(id_str);
Enrico Granata60a818d2019-05-09 09:56:09 -070065 CHECK(base::DirectoryExists(path));
66 return path;
67}
68
69base::Optional<std::string> IioDeviceImpl::ReadStringAttribute(
70 const std::string& name) const {
Harvey Yang9260b662019-08-12 15:48:03 +080071 char data[kReadAttrBufferSize] = {0};
Enrico Granata60a818d2019-05-09 09:56:09 -070072 ssize_t len = iio_device_attr_read(device_, name.c_str(), data, sizeof(data));
73 if (len < 0) {
74 LOG(WARNING) << "Attempting to read attribute " << name
75 << " failed: " << len;
76 return base::nullopt;
77 }
78 return std::string(data, len);
79}
80
81base::Optional<int64_t> IioDeviceImpl::ReadNumberAttribute(
82 const std::string& name) const {
83 long long val = 0; // NOLINT(runtime/int)
84 int error = iio_device_attr_read_longlong(device_, name.c_str(), &val);
85 if (error) {
86 LOG(WARNING) << "Attempting to read attribute " << name
87 << " failed: " << error;
88 return base::nullopt;
89 }
90 return val;
91}
92
Enrico Granatad2e57f42019-07-31 10:46:03 -070093base::Optional<double> IioDeviceImpl::ReadDoubleAttribute(
94 const std::string& name) const {
95 double val = 0;
96 int error = iio_device_attr_read_double(device_, name.c_str(), &val);
97 if (error) {
98 LOG(WARNING) << "Attempting to read attribute " << name
99 << " failed: " << error;
100 return base::nullopt;
101 }
102 return val;
103}
104
Enrico Granata60a818d2019-05-09 09:56:09 -0700105bool IioDeviceImpl::WriteStringAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800106 const std::string& value) {
107 int error = iio_device_attr_write_raw(device_, name.c_str(), value.data(),
108 value.size());
109 if (error < 0) {
Enrico Granata60a818d2019-05-09 09:56:09 -0700110 LOG(WARNING) << "Attempting to write attribute " << name
111 << " failed: " << error;
112 return false;
113 }
114 return true;
115}
Enrico Granatad2e57f42019-07-31 10:46:03 -0700116
Enrico Granata60a818d2019-05-09 09:56:09 -0700117bool IioDeviceImpl::WriteNumberAttribute(const std::string& name,
Harvey Yang9260b662019-08-12 15:48:03 +0800118 int64_t value) {
119 int error = iio_device_attr_write_longlong(device_, name.c_str(), value);
Enrico Granata60a818d2019-05-09 09:56:09 -0700120 if (error) {
121 LOG(WARNING) << "Attempting to write attribute " << name
122 << " failed: " << error;
123 return false;
124 }
125 return true;
126}
127
Harvey Yang9260b662019-08-12 15:48:03 +0800128bool IioDeviceImpl::WriteDoubleAttribute(const std::string& name,
129 double value) {
130 int error = iio_device_attr_write_double(device_, name.c_str(), value);
Enrico Granatad2e57f42019-07-31 10:46:03 -0700131 if (error) {
132 LOG(WARNING) << "Attempting to write attribute " << name
133 << " failed: " << error;
134 return false;
135 }
136 return true;
137}
138
Enrico Granata60a818d2019-05-09 09:56:09 -0700139iio_device* IioDeviceImpl::GetUnderlyingIioDevice() const {
140 return device_;
141}
142
143bool IioDeviceImpl::SetTrigger(IioDevice* trigger_device) {
Gwendal Grignou66393e22019-11-20 16:46:22 -0800144 // Reset the old - if any - and then add the new trigger.
145 int error = iio_device_set_trigger(device_, NULL);
146 if (error) {
Harvey Yang9260b662019-08-12 15:48:03 +0800147 LOG(WARNING) << "Unable to clean trigger of device " << GetId()
Gwendal Grignou66393e22019-11-20 16:46:22 -0800148 << ", error: " << error;
149 return false;
150 }
151 if (trigger_device == nullptr)
152 return true;
153
Harvey Yang9260b662019-08-12 15:48:03 +0800154 const iio_device* impl_device = nullptr;
155 int id = trigger_device->GetId();
156 if (id == -2) {
157 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
158 kIioSysfsTrigger);
159 } else {
160 std::string id_str = IioDeviceTriggerImpl::GetStringFromId(id);
161 impl_device = iio_context_find_device(GetContext()->GetCurrentContext(),
162 id_str.c_str());
163 }
Enrico Granata60a818d2019-05-09 09:56:09 -0700164 if (!impl_device) {
Harvey Yang9260b662019-08-12 15:48:03 +0800165 LOG(WARNING) << "cannot find device " << id << " in the current context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700166 return false;
167 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800168
169 error = iio_device_set_trigger(device_, impl_device);
170 if (error) {
Enrico Granata60a818d2019-05-09 09:56:09 -0700171 LOG(WARNING) << "Unable to set trigger for device " << GetId()
172 << " to be device " << trigger_device->GetId()
Gwendal Grignou66393e22019-11-20 16:46:22 -0800173 << ", error: " << error;
Enrico Granata60a818d2019-05-09 09:56:09 -0700174 return false;
175 }
176 return true;
177}
178
179IioDevice* IioDeviceImpl::GetTrigger() {
180 const iio_device* trigger;
181 int error = iio_device_get_trigger(device_, &trigger);
182 if (error) {
183 LOG(WARNING) << "Unable to get trigger for device " << GetId();
184 return nullptr;
185 }
Gwendal Grignou66393e22019-11-20 16:46:22 -0800186
187 if (trigger == nullptr)
188 return nullptr;
189
Harvey Yang9260b662019-08-12 15:48:03 +0800190 const char* id_str = iio_device_get_id(trigger);
191 auto id = IioDeviceTriggerImpl::GetIdFromString(id_str);
192
193 IioDevice* trigger_device = nullptr;
194 if (id.has_value())
195 trigger_device = GetContext()->GetTriggerById(id.value());
196
Enrico Granata60a818d2019-05-09 09:56:09 -0700197 if (trigger_device == nullptr) {
Harvey Yang9260b662019-08-12 15:48:03 +0800198 LOG(WARNING) << GetId() << " has trigger device " << id_str
Enrico Granata60a818d2019-05-09 09:56:09 -0700199 << "which cannot be found in this context";
Enrico Granata60a818d2019-05-09 09:56:09 -0700200 }
Harvey Yang9260b662019-08-12 15:48:03 +0800201
Enrico Granata60a818d2019-05-09 09:56:09 -0700202 return trigger_device;
203}
204
Harvey Yangb0c30962019-09-17 15:00:25 +0800205std::vector<IioChannel*> IioDeviceImpl::GetAllChannels() {
206 std::vector<IioChannel*> channels;
207 uint32_t chn_count = iio_device_get_channels_count(device_);
208
209 for (int i = 0; i < chn_count; ++i) {
210 iio_channel* channel = iio_device_get_channel(device_, i);
211 if (channel == nullptr) {
212 LOG(WARNING) << "Unable to get " << i
213 << "th channel from device: " << GetId();
214 continue;
215 }
216
217 channels.push_back(GetChannel(iio_channel_get_id(channel)));
218 }
219
220 return channels;
221}
222
Enrico Granata60a818d2019-05-09 09:56:09 -0700223IioChannel* IioDeviceImpl::GetChannel(const std::string& name) {
224 auto k = channels_.find(name);
225 if (k != channels_.end())
226 return k->second.get();
227 iio_channel* channel = iio_device_find_channel(device_, name.c_str(), true);
228 if (channel == nullptr)
229 channel = iio_device_find_channel(device_, name.c_str(), false);
230 if (channel == nullptr)
231 return nullptr;
232 channels_.emplace(name, std::make_unique<IioChannelImpl>(channel));
233 return channels_[name].get();
234}
235
Harvey Yangc0d19d82019-07-01 12:17:34 +0800236base::Optional<size_t> IioDeviceImpl::GetSampleSize() const {
237 ssize_t sample_size = iio_device_get_sample_size(device_);
238 if (sample_size < 0) {
Harvey Yang75452e82019-10-02 16:57:01 +0800239 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800240 iio_strerror(errno, errMsg, sizeof(errMsg));
241 LOG(WARNING) << "Unable to get sample size: " << errMsg;
242 return base::nullopt;
243 }
244
245 return static_cast<size_t>(sample_size);
246}
247
Enrico Granata60a818d2019-05-09 09:56:09 -0700248bool IioDeviceImpl::EnableBuffer(size_t count) {
249 if (!WriteNumberAttribute("buffer/length", count))
250 return false;
251 if (!WriteNumberAttribute("buffer/enable", 1))
252 return false;
253
254 return true;
255}
256
257bool IioDeviceImpl::DisableBuffer() {
258 return WriteNumberAttribute("buffer/enable", 0);
259}
260
261bool IioDeviceImpl::IsBufferEnabled(size_t* count) const {
262 bool enabled = (ReadNumberAttribute("buffer/enable").value_or(0) == 1);
263 if (enabled && count)
264 *count = ReadNumberAttribute("buffer/length").value_or(0);
265
266 return enabled;
267}
268
Harvey Yang75452e82019-10-02 16:57:01 +0800269bool IioDeviceImpl::ReadEvent(std::vector<uint8_t>* event) {
270 if (!CreateBuffer())
Harvey Yangc0d19d82019-07-01 12:17:34 +0800271 return false;
272
Harvey Yang75452e82019-10-02 16:57:01 +0800273 event->clear();
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));
279 LOG(ERROR) << "Unable to refill buffer: " << errMsg;
Harvey Yangae53dc82019-07-25 18:11:20 +0800280 buffer_.reset();
Harvey Yangae53dc82019-07-25 18:11:20 +0800281
Harvey Yangc0d19d82019-07-01 12:17:34 +0800282 return false;
283 }
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) {
290 LOG(ERROR) << "sample_size doesn't match in refill: " << buf_step
291 << ", sample_size: " << sample_size;
Harvey Yangae53dc82019-07-25 18:11:20 +0800292 buffer_.reset();
Harvey Yangc0d19d82019-07-01 12:17:34 +0800293
294 return false;
295 }
296
297 uint8_t* start = reinterpret_cast<uint8_t*>(iio_buffer_start(buffer_.get()));
298 size_t len = reinterpret_cast<intptr_t>(iio_buffer_end(buffer_.get())) -
299 reinterpret_cast<intptr_t>(start);
300
Harvey Yang75452e82019-10-02 16:57:01 +0800301 event->reserve(len);
302 event->insert(event->begin(), start, start + len);
Harvey Yangc0d19d82019-07-01 12:17:34 +0800303
304 return true;
305}
306
307// static
308void IioDeviceImpl::IioBufferDeleter(iio_buffer* buffer) {
309 iio_buffer_cancel(buffer);
310 iio_buffer_destroy(buffer);
311}
312
Harvey Yang75452e82019-10-02 16:57:01 +0800313bool IioDeviceImpl::CreateBuffer() {
314 if (buffer_ &&
Harvey Yangc0d19d82019-07-01 12:17:34 +0800315 iio_device_get_sample_size(device_) == iio_buffer_step(buffer_.get()))
316 return true;
317
Harvey Yangc0d19d82019-07-01 12:17:34 +0800318 buffer_.reset();
Harvey Yang75452e82019-10-02 16:57:01 +0800319 buffer_.reset(iio_device_create_buffer(device_, kNumSamples, false));
Harvey Yangc0d19d82019-07-01 12:17:34 +0800320
321 if (!buffer_) {
Harvey Yang75452e82019-10-02 16:57:01 +0800322 char errMsg[kErrorBufferSize];
Harvey Yangc0d19d82019-07-01 12:17:34 +0800323 iio_strerror(errno, errMsg, sizeof(errMsg));
324 LOG(ERROR) << "Unable to allocate buffer: " << errMsg;
325 return false;
326 }
327
328 return true;
329}
330
Enrico Granata51cdb942019-06-18 16:40:17 -0700331} // namespace libmems