#include "i2cif.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "conv.h" #include #include #include #include #include #include #include #define DEFAULT_I2C_DEV QString("/dev/i2c-1/") I2cif::I2cif(QObject *parent) : QObject(parent) { m_probingResult = QStringList(); m_readResult = "Nothing yet"; tohVddSet("on"); emit tohVddStatusChanged(); } I2cif::~I2cif() { tohVddSet("off"); } QStringList I2cif::i2cProbingStatus() { return m_probingResult; } QString I2cif::i2cReadResult() { return m_readResult; } /* * Function to set TOH VDD On and Off * * */ void I2cif::tohVddSet(QString onOff) { int fd; fd = open("/sys/devices/platform/reg-userspace-consumer.0/state", O_WRONLY); if (!(fd < 0)) { if (write (fd, QString::localeAwareCompare( onOff, "on") ? "0" : "1", 1) != 1) fprintf(stderr, "Vdd set failed\n"); else fprintf(stderr, "Vdd set OK\n"); close(fd); } else fprintf(stderr, "Vdd failed to open. Did you start i2ctool as root?\n"); emit tohVddStatusChanged(); } void I2cif::requestTohVddState() { emit tohVddStatusChanged(); } /* * Function to check which is current state of Vdd * */ bool I2cif::tohVddGet() { int fd; int retval = 0; char buf[1] = { 0 }; fd = open("/sys/devices/platform/reg-userspace-consumer.0/state", O_RDONLY); if (!(fd < 0)) { retval += read(fd, buf ,1); close(fd); } return (buf[0] == 'e'); // values are "enabled" or "disabled" } /* * I2C Write Function * * */ Q_INVOKABLE int I2cif::i2cWrite(const uint8_t &slaveAddr, const uint16_t &writeAddress, const uint16_t &data){ int file; __u8 buf[4]; const char* devNameChar = "/dev/i2c-1"; //fprintf(stderr, "writing to address %02x: ", slaveAddr); if ((file = open (devNameChar, O_RDWR)) < 0) { fprintf(stderr,"open error\n"); emit i2cError(); return -1; } if (ioctl(file, I2C_SLAVE, slaveAddr) < 0) { close(file); fprintf(stderr,"ioctl error\n"); emit i2cError(); return -1; } buf[0] = (writeAddress >> 8) & 0xFF; // High byte buf[1] = writeAddress & 0xFF; // Low byte buf[2] = (data >> 8) & 0xFF; // High byte buf[3] = data & 0xFF; // Low byte /*fprintf(stderr, "Data to be written: "); for (int i = 0; i < 4; i++) { fprintf(stderr, "%02x ", buf[i]); } fprintf(stderr, "\n"); */ /* write the data */ if (write(file, buf, 4) != 4) { close(file); fprintf(stderr,"write error\n"); emit i2cError(); return -1; } close(file); //fprintf(stderr,"write ok\n"); emit i2cWriteOk(); return 0; } int I2cif::i2cRead(const uint8_t &slaveAddr, const uint16_t &startAddress, const uint16_t &nMemAddressRead, uint16_t *data) { int file; Conv conv; m_readResult = QString(); uint16_t addr = startAddress; __u8 *buf = new __u8[2 * nMemAddressRead]; const char* devNameChar = "/dev/i2c-1"; if ((file = open (devNameChar, O_RDWR)) < 0) { fprintf(stderr,"open error\n"); emit i2cError(); delete[] buf; return -1; } struct i2c_rdwr_ioctl_data i2c_data; struct i2c_msg msg[2]; __u8 regAddrBytes[2] = {0,0}; regAddrBytes[0] = (startAddress >> 8) & 0xFF; // High byte regAddrBytes[1] = startAddress & 0xFF; // Low byte i2c_data.msgs = msg; i2c_data.nmsgs = 2; i2c_data.msgs[0].addr = slaveAddr; i2c_data.msgs[0].flags = 0; i2c_data.msgs[0].len = 2; i2c_data.msgs[0].buf = regAddrBytes; i2c_data.msgs[1].addr = slaveAddr; i2c_data.msgs[1].flags = I2C_M_RD; constexpr uint16_t ChunkSize = 32; // 192 bytes (96 uint16_t) uint16_t chunks = nMemAddressRead / ChunkSize; uint16_t remainder = nMemAddressRead % ChunkSize; for (uint16_t chunk = 0; chunk <= chunks; chunk++) { uint16_t length = (chunk == chunks ? remainder : ChunkSize); if (length == 0) break; regAddrBytes[0] = (addr >> 8) & 0xFF; // High byte regAddrBytes[1] = addr & 0xFF; // Low byte i2c_data.msgs[0].buf = regAddrBytes; i2c_data.msgs[1].len = length * 2; i2c_data.msgs[1].buf = &buf[chunk * ChunkSize * 2]; int ret = ioctl(file, I2C_RDWR, &i2c_data); if (ret < 0) { fprintf(stderr, "read data fail %d\n", ret); emit i2cError(); delete[] buf; return -1; } //fprintf(stderr, "read "); for (uint16_t i = 0; i < length; ++i) { uint16_t index = chunk * ChunkSize + i; data[index] = ((buf[2 * index] << 8) == 0xFF ? 0x00 : (buf[2 * index] << 8)) | buf[2 * index + 1]; m_readResult = m_readResult + conv.toHex(data[index], 4) + " "; //fprintf(stderr, "%04x ", data[index]); } //fprintf(stderr, "\n"); // Wait 0.4ms before next chunk usleep(400); addr += ChunkSize; } //fprintf(stderr, "\n"); delete[] buf; emit i2cReadResultChanged(); close(file); return 0; } /* * I2C Read function * */ void I2cif::i2cRead(QString devName, unsigned char address, int count) { int file; char buf[200]; Conv conv; m_readResult = ""; //emit i2cReadResultChanged(); QByteArray tmpBa = devName.toUtf8(); const char* devNameChar = tmpBa.constData(); fprintf(stderr, "reading from address %02x count %d\n", address, count); if ((file = open (devNameChar, O_RDWR)) < 0) { fprintf(stderr,"open error\n"); emit i2cError(); return; } if (ioctl(file, I2C_SLAVE, address) < 0) { close(file); fprintf(stderr,"ioctl error\n"); emit i2cError(); return; } /* Read data */ if (read( file, buf, count ) != count) { close(file); fprintf(stderr,"read error\n"); emit i2cError(); return; } close(file); /* copy buf to m_readResult */ int i; fprintf(stderr, "read "); for (i=0; i= 4 && address <= 7) { m_probingResult.append("skipped"); continue; } QByteArray tmpBa = devName.toUtf8(); const char* devNameChar = tmpBa.constData(); fprintf(stderr, "probing %s address %02x: ", devNameChar, address); if ((file = open (devNameChar, O_RDWR)) < 0) { m_probingResult.append("openFail"); fprintf(stderr, "open failed\n"); close(file); continue; } if (ioctl(file, I2C_SLAVE, address) < 0) { close(file); m_probingResult.append("ioctlFail"); fprintf(stderr, "ioctl failed\n"); close(file); continue; } /* Try to read 2 bytes. This is also safe for LM75 */ if (read( file, buf, 2 ) != 2) { close(file); m_probingResult.append("readFail"); fprintf(stderr, "read failed\n"); close(file); continue; } close(file); m_probingResult.append("ok"); fprintf(stderr, "device found at address %02x\n", address); } emit i2cProbingChanged(); } /* * If microswitch is pressed tohd takes control over i2c-1-0050 (eeprom) * this is used to release it. * but duh, needs to be done as root * echo toh-core.0 > /sys/bus/platform/drivers/toh-core/unbind */ void I2cif::unbindTohCore() { int fd; fd = open("/sys/bus/platform/drivers/toh-core/unbind", O_WRONLY); if (!(fd < 0)) { if (write (fd, "toh-core.0", 10) != 10) fprintf(stderr, "unbind failed\n"); else fprintf(stderr, "unbind OK\n"); close(fd); } else fprintf(stderr, "unbind failed. Did you start i2ctool as root?\n"); } /* * Default values commands * */ void I2cif::setAsDefault(QString index, QString value) { QSettings s("harbour-i2ctool", "harbour-i2ctool"); s.beginGroup("Defaults"); s.setValue(index, value); s.endGroup(); } QString I2cif::getDefault(QString index) { QString value; QSettings s("harbour-i2ctool", "harbour-i2ctool"); s.beginGroup("Defaults"); value = s.value(index, firstTimeDefault(index)).toString(); s.endGroup(); return value; } /* helper :) */ QString I2cif::firstTimeDefault(QString index) { if (index == "0") return "4B4C"; if (index == "1") return "0001"; if (index == "2") return "01"; if (index == "3") return "0100"; if (index == "4") return "0040"; if (index == "5") return "0040"; if (index == "6") return "0080"; if (index == "7") return "0000"; return "0000"; } /* use xdg-open to start pdf-viewer for showing usersguide */ void I2cif::openUsersGuide() { QProcess proc; QString ugpath = SailfishApp::pathTo("i2ctool-ug.pdf").toString(); fprintf(stderr, "loading user's guide %s\n", qPrintable(ugpath)); proc.startDetached("/usr/bin/xdg-open" , QStringList() << ugpath); QThread::msleep(100); }