diff --git a/libraries/AP_HAL_Linux/I2CDriver.cpp b/libraries/AP_HAL_Linux/I2CDriver.cpp index bf461844fa..fb5cb3f46d 100644 --- a/libraries/AP_HAL_Linux/I2CDriver.cpp +++ b/libraries/AP_HAL_Linux/I2CDriver.cpp @@ -4,26 +4,85 @@ #if CONFIG_HAL_BOARD == HAL_BOARD_LINUX #include "I2CDriver.h" +#include #include #include +#include #include #include #include +#include +#include #include #include #ifndef I2C_SMBUS_BLOCK_MAX #include #endif +extern const AP_HAL::HAL& hal; + using namespace Linux; /* constructor */ LinuxI2CDriver::LinuxI2CDriver(AP_HAL::Semaphore* semaphore, const char *device) : - _semaphore(semaphore), - _device(device) + _semaphore(semaphore) { + _device = strdup(device); +} + +/* Match a given device by the prefix its devpath, i.e. the path returned by + * udevadm info -q path /dev/'. This constructor can be used when + * the number of the I2C bus is not stable across reboots. It matches the + * first device with a prefix in @devpaths */ +LinuxI2CDriver::LinuxI2CDriver(AP_HAL::Semaphore* semaphore, + const char * const devpaths[]) : + _semaphore(semaphore) +{ + const char *dirname = "/sys/class/i2c-dev"; + struct dirent *de; + DIR *d; + + d = opendir(dirname); + if (!d) + hal.scheduler->panic("Could not get list of I2C buses"); + + for (de = readdir(d); de; de = readdir(d)) { + const char *p, * const *t; + char buf[PATH_MAX], buf2[PATH_MAX]; + + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + + if (snprintf(buf, sizeof(buf), "%s/%s", dirname, de->d_name) >= PATH_MAX) + continue; + + p = realpath(buf, buf2); + if (!p || strncmp(p, "/sys", sizeof("/sys") - 1)) + continue; + + p += sizeof("/sys") - 1; + + for (t = devpaths; t && *t; t++) { + if (strncmp(p, *t, strlen(*t)) == 0) + break; + } + + if (!*t) + continue; + + /* Found the device name, use the new path */ + asprintf(&_device, "/dev/%s", de->d_name); + break; + } + + closedir(d); +} + +LinuxI2CDriver::~LinuxI2CDriver() +{ + free(_device); } /* diff --git a/libraries/AP_HAL_Linux/I2CDriver.h b/libraries/AP_HAL_Linux/I2CDriver.h index c874e778a8..7c2984b326 100644 --- a/libraries/AP_HAL_Linux/I2CDriver.h +++ b/libraries/AP_HAL_Linux/I2CDriver.h @@ -7,6 +7,8 @@ class Linux::LinuxI2CDriver : public AP_HAL::I2CDriver { public: LinuxI2CDriver(AP_HAL::Semaphore* semaphore, const char *device); + LinuxI2CDriver(AP_HAL::Semaphore* semaphore, const char * const devpaths[]); + ~LinuxI2CDriver(); void begin(); void end(); @@ -44,7 +46,7 @@ private: bool set_address(uint8_t addr); AP_HAL::Semaphore* _semaphore; - const char *_device = NULL; + char *_device = NULL; int _fd = -1; uint8_t _addr; };