2 * Copyright (C) 2010-2012 Intel Corporation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <cutils/log.h>
20 #include <cutils/properties.h>
21 #include "SensorIIODev.h"
26 static const std::string IIO_DIR = "/sys/bus/iio/devices";
27 static const int DEF_BUFFER_LEN = 2;
28 static const int DEF_HYST_VALUE = 0;
30 SensorIIODev::SensorIIODev(const std::string& dev_name, const std::string& units,
31 const std::string& exponent,
32 const std::string& channel_prefix, int retry_cnt)
35 unit_expo_str(exponent),
37 device_name(dev_name),
38 channel_prefix_str(channel_prefix),
41 retry_count(retry_cnt),
44 sample_delay_min_ms(0)
46 ALOGV("%s", __func__);
49 SensorIIODev::SensorIIODev(const std::string& dev_name, const std::string& units,
50 const std::string& exponent,
51 const std::string& channel_prefix)
54 unit_expo_str(exponent),
56 device_name(dev_name),
57 channel_prefix_str(channel_prefix),
65 ALOGV("%s", __func__);
68 int SensorIIODev::discover()
74 // Allow overriding sample_delay_min_ms via properties using
75 // the IIO device name. e.g.:
76 // ro.sys.sensors_accel_3d_samp_min_ms = 16
77 char sampmin[PROPERTY_VALUE_MAX];
78 std::string pn = "ro.sys.sensors_" + device_name + "_samp_min_ms";
79 property_get(pn.c_str(), sampmin, "");
81 sample_delay_min_ms = strtol(sampmin, NULL, 10);
83 ALOGD(">>%s discover", __func__);
84 for (cnt = 0; cnt < retry_count; cnt++) {
85 status = ParseIIODirectory(device_name);
87 std::stringstream filename;
89 filename << "/dev/iio:device" << device_number;
90 mDevPath = filename.str();
91 ALOGV("mDevPath %s", mDevPath.c_str());
96 ALOGE("Sensor IIO Init failed, retry left:%d\n", retry_count-cnt);
100 // Device not enumerated yet, wait and retry
106 int SensorIIODev::AllocateRxBuffer()
108 ALOGV(">>%s Allocate:%d", __func__, datum_size * buffer_len);
109 raw_buffer = new unsigned char[datum_size * buffer_len];
111 ALOGE("AllocateRxBuffer: Failed\n");
117 int SensorIIODev::FreeRxBuffer()
119 ALOGV(">>%s", __func__);
125 int SensorIIODev::enable(int enabled)
127 // startStop() handles the internal sensor stream, which may be
128 // used by slaves. The mEnabled flag is what gates the output of
129 // this particular sensor.
130 int ret = startStop(enabled);
137 int SensorIIODev::startStop(int enabled)
139 int alive = mRefCount > 0;
140 mRefCount = max(0, enabled ? mRefCount+1 : mRefCount-1);
141 int alivenew = mRefCount > 0;
142 if (alive == alivenew)
147 ALOGD(">>%s enabled:%d", __func__, enabled);
150 if ((ret = discover()) < 0) {
151 ALOGE("discover failed: %s\n", device_name.c_str());
154 if ((ret = open()) < 0) {
155 ALOGE("open failed: %s\n", device_name.c_str());
159 // QUIRK: some sensor hubs need to be turned on and off and on
160 // before sending any information. So we turn it on and off first
161 // before enabling again later in this function.
165 if (ReadHIDExponentValue(&unit_expo_value) < 0)
167 if (ReadHIDMeasurmentUnit(&units_value) < 0)
169 if (SetDataReadyTrigger(GetDeviceNumber(), true) < 0)
171 if (EnableBuffer(1) < 0)
173 if (DeviceActivate(GetDeviceNumber(), 1) < 0)
175 if (DeviceSetSensitivity(GetDeviceNumber(), DEF_HYST_VALUE) < 0)
177 if (AllocateRxBuffer() < 0)
181 if (SetDataReadyTrigger(GetDeviceNumber(), false) < 0)
183 if (EnableBuffer(0) < 0)
185 if (DeviceActivate(GetDeviceNumber(), 0) < 0)
187 if (DeviceSetSensitivity(GetDeviceNumber(), 0))
189 if (FreeRxBuffer() < 0)
198 ALOGE("SesnorIIO: Enable failed\n");
202 int SensorIIODev::setDelay(int64_t delay_ns){
203 int ms = nsToMs(delay_ns);
206 ALOGV(">>%s %ld", __func__, delay_ns);
207 if (IsDeviceInitialized() == false){
208 ALOGE("Device was not initialized \n");
212 if ((r = SetSampleDelay(GetDeviceNumber(), ms)) < 0)
215 ALOGV("<<%s", __func__);
219 int SensorIIODev::setInitialState(){
220 mHasPendingEvent = false;
224 long SensorIIODev::GetUnitValue()
229 long SensorIIODev::GetExponentValue()
231 return unit_expo_value;
234 bool SensorIIODev::IsDeviceInitialized(){
238 int SensorIIODev::GetDeviceNumber(){
239 return device_number;
242 int SensorIIODev::GetDir(const std::string& dir, std::vector < std::string >& files){
246 if ((dp = opendir(dir.c_str())) == NULL){
247 ALOGE("Error opening directory %s\n", (char*)dir.c_str());
250 while ((dirp = readdir(dp)) != NULL){
251 files.push_back(std::string(dirp->d_name));
257 void SensorIIODev::ListFiles(const std::string& dir){
258 std::vector < std::string > files = std::vector < std::string > ();
262 for (unsigned int i = 0; i < files.size(); i++){
263 ALOGV("File List.. %s\n", (char*)files[i].c_str());
267 // This function returns a device number for IIO device
268 // For example if the device is "iio:device1", this will return 1
269 int SensorIIODev::FindDeviceNumberFromName(const std::string& name, const std::string&
272 std::vector < std::string > files = std::vector < std::string > ();
273 std::string device_name;
275 GetDir(std::string(IIO_DIR), files);
277 for (unsigned int i = 0; i < files.size(); i++){
278 std::stringstream ss;
279 if ((files[i] == ".") || (files[i] == "..") || files[i].length() <=
283 if (files[i].compare(0, prefix.length(), prefix) == 0){
284 sscanf(files[i].c_str() + prefix.length(), "%d", &dev_number);
286 ss << IIO_DIR << "/" << prefix << dev_number;
287 std::ifstream ifs(ss.str().c_str(), std::ifstream::in);
295 std::ifstream ifn((ss.str() + "/" + "name").c_str(), std::ifstream::in);
302 std::getline(ifn, device_name);
303 if (name.compare(device_name) == 0){
304 ALOGV("matched %s\n", device_name.c_str());
315 int SensorIIODev::SetUpTrigger(int dev_num){
316 std::stringstream trigger_name;
319 trigger_name << device_name << "-dev" << dev_num;
320 if (trigger_name.str().length()){
321 ALOGV("trigger_name %s\n", (char*)trigger_name.str().c_str());
322 trigger_num = FindDeviceNumberFromName(trigger_name.str(), "trigger");
323 if (trigger_num < 0){
324 ALOGE("Failed to find trigger\n");
329 ALOGE("trigger_name not found \n");
335 // Setup buffer length in terms of datum size
336 int SensorIIODev::SetUpBufferLen(int len){
337 std::stringstream filename;
338 std::stringstream len_str;
340 ALOGV("%s: len:%d", __func__, len);
342 filename << buffer_dir_name.str() << "/" << "length";
346 int ret = path_ops.write(filename.str(), len_str.str());
348 ALOGE("Write Error %s", filename.str().c_str());
356 int SensorIIODev::EnableBuffer(int status){
357 std::stringstream filename;
358 std::stringstream status_str;
360 ALOGV("%s: len:%d", __func__, status);
362 filename << buffer_dir_name.str() << "/" << "enable";
364 status_str << status;
365 int ret = path_ops.write(filename.str(), status_str.str());
367 ALOGE("Write Error %s", filename.str().c_str());
370 enable_buffer = status;
374 int SensorIIODev::EnableChannels(){
378 std::string dir = std::string(IIO_DIR);
379 std::vector < std::string > files = std::vector < std::string > ();
380 const std::string FORMAT_SCAN_ELEMENTS_DIR = "/scan_elements";
381 unsigned char signchar, bits_used, total_bits, shift, unused;
382 SensorIIOChannel iio_channel;
384 ALOGV(">>%s", __func__);
385 scan_el_dir.str(std::string());
386 scan_el_dir << dev_device_name.str() << FORMAT_SCAN_ELEMENTS_DIR;
387 GetDir(scan_el_dir.str(), files);
389 for (unsigned int i = 0; i < files.size(); i++){
390 int len = files[i].length();
391 if (len > 3 && files[i].compare(len - 3, 3, "_en") == 0){
392 std::stringstream filename, file_type;
395 filename << scan_el_dir.str() << "/" << files[i];
396 ret = path_ops.write(filename.str(), "1");
398 ALOGE("Channel Enable Error %s:%d", filename.str().c_str(), ret);
404 int SensorIIODev::BuildChannelList(){
408 std::string dir = std::string(IIO_DIR);
409 std::vector < std::string > files = std::vector < std::string > ();
410 const std::string FORMAT_SCAN_ELEMENTS_DIR = "/scan_elements";
411 unsigned char signchar, bits_used, total_bits, shift, unused;
412 SensorIIOChannel iio_channel;
413 std::string type_name;
415 ALOGV(">>%s", __func__);
416 scan_el_dir.str(std::string());
417 scan_el_dir << dev_device_name.str() << FORMAT_SCAN_ELEMENTS_DIR;
418 GetDir(scan_el_dir.str(), files);
420 // File ending with _en will specify a channel
421 // it contains the count. If we add all these count
422 // those many channels present
424 for (unsigned int i = 0; i < files.size(); i++){
425 int len = files[i].length();
426 // At the least the length should be more than 3 for "_en"
427 if (len > 3 && files[i].compare(len - 3, 3, "_en") == 0){
428 std::stringstream filename, file_type;
429 filename << scan_el_dir.str() << "/" << files[i];
430 std::ifstream ifs(filename.str().c_str(), std::ifstream::in);
436 count = ifs.get() - '0';
441 iio_channel.enabled = 1;
442 iio_channel.scale = 1.0;
443 iio_channel.offset = 0;
445 iio_channel.name = files[i].substr(0, files[i].length() - 3);
447 ALOGV("IIO channel name:%s\n", (char*)iio_channel.name.c_str());
448 file_type << scan_el_dir.str() << "/" << iio_channel.name <<
451 std::ifstream its(file_type.str().c_str(), std::ifstream::in);
456 std::getline(its, type_name);
457 sscanf(type_name.c_str(), "%c%c%c%c%u/%u>>%u", (unsigned char*) &unused,
458 (unsigned char*) &unused, (unsigned char*) &unused, (unsigned
459 char*) &signchar, (unsigned int*) &bits_used, (unsigned int*)
460 &total_bits, (unsigned int*) &shift);
463 // Buggy sscanf on some platforms
464 if (total_bits == 0 || bits_used == 0){
465 if (!strcmp(type_name.c_str(), "le:s16/32")){
469 else if (!strcmp(type_name.c_str(), "le:s16/16")){
479 iio_channel.bytes = total_bits / 8;
480 iio_channel.real_bytes = bits_used / 8;
481 iio_channel.shift = shift;
482 iio_channel.is_signed = signchar;
485 info_array.push_back(iio_channel);
488 ALOGV("<<%s", __func__);
492 int SensorIIODev::GetSizeFromChannels(){
494 for (unsigned int i = 0; i < info_array.size(); i++){
495 SensorIIOChannel channel = info_array[i];
496 size += channel.bytes;
498 ALOGD("%s:%d:%d", __func__, info_array.size(), size);
502 int SensorIIODev::GetChannelBytesUsedSize(unsigned int channel_no){
503 if (channel_no < info_array.size()){
504 SensorIIOChannel channel = info_array[channel_no];
505 return channel.real_bytes;
511 int SensorIIODev::ParseIIODirectory(const std::string& name){
516 ALOGV(">>%s", __func__);
518 dev_device_name.str(std::string());
519 buffer_dir_name.str(std::string());
521 device_number = dev_num = FindDeviceNumberFromName(name, "iio:device");
523 ALOGE("Failed to find device %s\n", (char*)name.c_str());
527 // Construct device directory Eg. /sys/devices/iio:device0
528 dev_device_name << IIO_DIR << "/" << "iio:device" << dev_num;
530 // Construct device directory Eg. /sys/devices/iio:device0:buffer0
531 buffer_dir_name << dev_device_name.str() << "/" << "buffer";
534 ret = SetUpTrigger(dev_num);
536 ALOGE("ParseIIODirectory Failed due to Trigger\n");
540 // Setup buffer len. This is in the datum units, not an absolute number
541 SetUpBufferLen(DEF_BUFFER_LEN);
543 // Set up channel masks
544 ret = EnableChannels();
546 ALOGE("ParseIIODirectory Failed due Enable Channels failed\n");
547 if (ret == -EACCES) {
548 // EACCES means the nodes do not have current owner.
549 // Need to retry, or else sensors won't power on.
550 // Other errors can be ignored, as these nodes are
551 // set once, and will return error when set again.
556 // Parse the channels and build a list
557 ret = BuildChannelList();
559 ALOGE("ParseIIODirectory Failed due BuildChannelList\n");
563 datum_size = GetSizeFromChannels();
564 ALOGV("Datum Size %d", datum_size);
565 ALOGV("<<%s", __func__);
570 int SensorIIODev::SetDataReadyTrigger(int dev_num, bool status){
571 std::stringstream filename;
572 std::stringstream trigger_name;
575 ALOGV("%s: status:%d", __func__, status);
577 filename << dev_device_name.str() << "/trigger/current_trigger";
578 trigger_name << device_name << "-dev" << dev_num;
583 ret = path_ops.write(filename.str(), trigger_name.str());
585 ret = path_ops.write(filename.str(), " ");
587 ALOGE("Write Error %s:%d", filename.str().c_str(), ret);
588 // Ignore error, as this may be due to
589 // Trigger was active during resume
595 int SensorIIODev::DeviceActivate(int dev_num, int state){
596 std::stringstream filename;
597 std::stringstream activate_str;
599 ALOGV("%s: Device Activate:%d", __func__, state);
603 // Set sensitivity in absolute terms
604 int SensorIIODev::DeviceSetSensitivity(int dev_num, int value){
605 std::stringstream filename;
606 std::stringstream sensitivity_str;
608 ALOGV("%s: Sensitivity :%d", __func__, value);
610 filename << IIO_DIR << "/" << "iio:device" << dev_num << "/" << channel_prefix_str << "hysteresis";
613 sensitivity_str << value;
614 int ret = path_ops.write(filename.str(), sensitivity_str.str());
616 ALOGE("Write Error %s", filename.str().c_str());
617 // Don't bail out as this field may be absent
622 // Set the sample period delay: units ms
623 int SensorIIODev::SetSampleDelay(int dev_num, int period){
624 std::stringstream filename;
625 std::stringstream sample_rate_str;
627 ALOGV("%s: sample_rate:%d", __func__, period);
629 if (sample_delay_min_ms && period < sample_delay_min_ms)
630 period = sample_delay_min_ms;
632 filename << IIO_DIR << "/" << "iio:device" << dev_num << "/" << channel_prefix_str << "sampling_frequency";
634 ALOGE("%s: Invalid_rate:%d", __func__, period);
637 sample_rate_str << 1000/period;
638 int ret = path_ops.write(filename.str(), sample_rate_str.str());
640 ALOGE("Write Error %s", filename.str().c_str());
641 // Don't bail out as this field may be absent
646 int SensorIIODev::readEvents(sensors_event_t *data, int count){
648 int numEventReceived;
659 if (mHasPendingEvent){
660 mHasPendingEvent = false;
661 mPendingEvent.timestamp = getTimestamp();
662 *data = mPendingEvent;
665 read_size = read(mFd, raw_buffer, datum_size);
666 numEventReceived = 0;
667 if(read_size != datum_size) {
668 ALOGE("read() error (or short count) from IIO device: %d\n", errno);
670 // Always call processEvent(), but only emit output if
671 // enabled. We may have slave devices (e.g. we could be a
672 // RotVec serving a SynthCompass without clients of our own).
673 if (processEvent(raw_buffer, datum_size) >= 0) {
675 mPendingEvent.timestamp = getTimestamp();
676 *data = mPendingEvent;
681 return numEventReceived;
684 int SensorIIODev::ReadHIDMeasurmentUnit(long *unit){
685 std::stringstream filename;
687 std::string long_str;
689 filename << IIO_DIR << "/" << "iio:device" << device_number << "/" << unit_str;
691 std::ifstream its(filename.str().c_str(), std::ifstream::in);
693 ALOGE("%s: Can't Open :%s",
694 __func__, filename.str().c_str());
698 std::getline(its, long_str);
701 if (long_str.length() > 0){
702 *unit = atol(long_str.c_str());
705 ALOGE("ReadHIDMeasurmentUnit failed");
709 int SensorIIODev::ReadHIDExponentValue(long *exponent){
710 std::stringstream filename;
712 std::string long_str;
714 filename << IIO_DIR << "/" << "iio:device" << device_number << "/" << unit_expo_str;
716 std::ifstream its(filename.str().c_str(), std::ifstream::in);
718 ALOGE("%s: Can't Open :%s",
719 __func__, filename.str().c_str());
723 std::getline(its, long_str);
726 if (long_str.length() > 0){
727 *exponent = atol(long_str.c_str());
730 ALOGE("ReadHIDExponentValue failed");