eclipse / mraa

Linux Library for low speed IO Communication in C with bindings for C++, Python, Node.js & Java. Supports generic io platforms, as well as Intel Edison, Intel Joule, Raspberry Pi and many more.
http://mraa.io
MIT License
1.38k stars 615 forks source link

AIO reads same value for all analog pins since v0.9.6 #495

Closed vidavidorra closed 8 years ago

vidavidorra commented 8 years ago

Since v0.9.6 the AIO reads the same value for all the analog pins off the Intel Edison Arduino board. This means that the value of A0 is returned when reading A1 for example.

At the moment we've found a temporary solution which avoids using the Aio read function. This method is basically accessing the kernel files directly using normal file I/O.

The file that needs to be read to get an analog value directly from the kernel is shown below. /sys/bus/iio/devices/iio:device1/in_voltage0_raw where the voltage0 is the value of A0 and voltage1 is A1, and so on. This works for both the C++ and javascript environment. Please note that this solution will always read an integer value. So to get a float, the read value needs to be divided by the maximum value (1024 for 10-bit ADC and 4096 for 12-bit ADC).

Hope this helps!

vidavidorra commented 8 years ago

C++ solution in a function that takes the analog pin number as argument and returns the read value as integer.

#include <iostream>
#include <fstream>
#include <unistd.h>
#include <stdint.h>
#include <string>
...

int readAnalogPin(uint8_t pin)
{
    std::string filePath = "";
    switch (pin) {
    case 0:
        filePath = "/sys/bus/iio/devices/iio:device1/in_voltage0_raw";
        break;
    case 1:
        filePath = "/sys/bus/iio/devices/iio:device1/in_voltage1_raw";
        break;
    case 2:
        filePath = "/sys/bus/iio/devices/iio:device1/in_voltage2_raw";
        break;
    case 3:
        filePath = "/sys/bus/iio/devices/iio:device1/in_voltage3_raw";
        break;
    case 4:
        filePath = "/sys/bus/iio/devices/iio:device1/in_voltage4_raw";
        break;
    case 5:
        filePath = "/sys/bus/iio/devices/iio:device1/in_voltage5_raw";
        break;
    default:
        std::cout << "ERROR: Unspecified analog pin number.";
        return (-1);
        break;
    }

    if (filePath != "") {
        std::ifstream inFile(filePath.c_str());

        if (inFile.is_open()) {
            std::string line;
            getline(inFile, line);
            inFile.close();
            int readVal = std::stoi (line ,nullptr, 10);
            return (readVal);
        } else {
            std::cerr << "ERROR: Could not open file" << inFile << "\n";
            return (-1);
        }
    }

    return -1;
}
arfoll commented 8 years ago

So we definately have a bug there I think introduced from subplatforms, I'm hunting now.

Note that what you're doing is a really bad idea because there's pinmuxing involved, doing so will not work in many configurations and is also very platform dependant. This is the fix, bug was introduced with firmata merge, I'll make sure nothing breaks with this and merge it later today.

diff --git a/src/aio/aio.c b/src/aio/aio.c
index 8ebf7c0..58a8883 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -122,14 +122,15 @@ mraa_aio_init(unsigned int aio)
         }
     }

+    dev->channel = board->pins[pin].aio.pinmap;
+    dev->value_bit = DEFAULT_BITS;
+
     // Create ADC device connected to specified channel
     mraa_aio_context dev = mraa_aio_init_internal(board->adv_func, aio);
     if (dev == NULL) {
         syslog(LOG_ERR, "aio: Insufficient memory for specified input channel %d", aio);
         return NULL;
     }
-    dev->channel = board->pins[pin].aio.pinmap;
-    dev->value_bit = DEFAULT_BITS;

     if (IS_FUNC_DEFINED(dev, aio_init_pre)) {
         mraa_result_t pre_ret = (dev->advance_func->aio_init_pre(aio));
arfoll commented 8 years ago

Fixed properly :/ Not on form today