int I2C::endTransaction() { if (!transactionState) { iooo_error( "I2C::endTransaction() warning: There is no currently active transaction.\n"); return 0; } if (!isReady()) return -1; transactionState = false; struct i2c_rdwr_ioctl_data msgset; msgset.nmsgs = msgs.size(); msgset.msgs = &msgs[0]; if (ioctl(fd, I2C_RDWR, &msgset) < 0) { iooo_error("I2C::endTransaction() error: %s (%d)\n", strerror(errno), errno); msgs.clear(); return -1; } msgs.clear(); return 0; }
int SPI::setSpeed(uint32_t speed) { if (resources == nullptr) { iooo_error("SPI::setSpeed(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); int r; if (!isReady()) return -ENODEV; r = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (r < 0) { iooo_error("ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed): %s", strerror(r)); return r; } uint32_t tmp; r = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &tmp); if (r < 0) { iooo_error("ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed): %s", strerror(r)); return r; } this->speed = tmp; return 1; }
int SPI::xfer1(const void *wbuf, void *rbuf, int len) { if (resources == nullptr) { iooo_error("SPI::xfer1(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); struct spi_ioc_transfer txinfo; txinfo.tx_buf = (__u64 ) wbuf; txinfo.rx_buf = (__u64 ) rbuf; txinfo.len = len; txinfo.delay_usecs = 0; txinfo.speed_hz = speed; txinfo.bits_per_word = bpw; txinfo.cs_change = 0; int r = ioctl(fd, SPI_IOC_MESSAGE(1), &txinfo); if (r < 0) { iooo_error("ioctl(fd, SPI_IOC_MESSAGE(1), &txinfo): %s (len=%d)\n", strerror(r), len); return r; } return len; }
int SPI::setMode(uint8_t mode) { if (resources == nullptr) { iooo_error("SPI::setMode(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); mode &= SPI_CPHA | SPI_CPOL; mode = (this->mode & ~(SPI_CPHA | SPI_CPOL)) | mode; int r = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (r < 0) return r; r = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (r < 0) return r; this->mode = mode; return 1; }
int SPI::close() { // Check if chip select and mutex lock resources have been initialized if (resources == nullptr) { iooo_error("SPI::close(): failed - no device has been opened\n"); return -EDESTADDRREQ; } // Mutex lock on this bus and channel std::lock_guard<std::recursive_mutex> lock(resources->rwlock); if (!isReady()) { active_bus = active_channel = -1; resources = nullptr; return -ENODEV; } iooo_debug(3, "SPI::close()\n"); mode = 0; bpw = 0; speed = 0; active_bus = active_channel = -1; resources = nullptr; int tmpfd = fd; fd = -1; return ::close(tmpfd); }
int NativeADC::close() { if (activeADC < 0) { iooo_error("NativeADC::close() error: No ADC device has been initialized.\n"); errno = EDESTADDRREQ; return -EDESTADDRREQ; } if ((::close(fd)) != 0) { iooo_error("NativeADC::close() close() error: %s (%d)\n", strerror(errno), errno); return -errno; } return 0; }
int SPI::chipSelect(GPIOpin* pin, int bit, int polarity) { if (bit < 0) return -ENODEV; if (resources == nullptr) { iooo_error("SPI::chipSelect(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); // If the same chip is being selected, return if (resources->cspin == pin && resources->csbit == bit && resources->cspol == polarity) return 1; // Deselect last chip chipDeselect(); // Select new chip resources->cspin = pin; resources->csbit = bit; resources->cspol = polarity; if (resources->cspol == 0) resources->cspin->clearBit(resources->csbit); else resources->cspin->setBit(resources->csbit); return 1; }
int I2C::writeRead(const void *wbuf, size_t wlength, void *rbuf, size_t rlength, bool ignoreNack, bool noAck) { bool was_transaction = true; // If not already in a transaction, make a transaction state if (!transactionState) { was_transaction = false; beginTransaction(); } if (write(wbuf, wlength, ignoreNack) < 0) return -1; if (read(rbuf, rlength, noAck) < 0) return -1; // Commit transaction if the system was not already in a // transaction state if (!was_transaction) { if (endTransaction() < 0) { iooo_error( "I2C::writeRead() Unable to perform consecutive write and read\n"); return -1; } } return 0; }
int NativeADC::open() { if (activeADC < 0) { iooo_error("NativeADC::open() error: No ADC device has been initialized.\n"); errno = EDESTADDRREQ; return -EDESTADDRREQ; } if ((fd = ::open(adcPath, O_RDONLY)) < 0) { iooo_error("NativeADC::open() open(%s) error: %s (%d)\n", adcPath, strerror(errno), errno); return fd; // fd is negative } return 0; }
bool I2C::slaveReady() { if (activeAddr < 0) { iooo_error("I2C::slaveReady() error: No slave address has been set.\n"); errno = EDESTADDRREQ; return false; } return true; }
bool I2C::busReady() { if (activeBus < 0) { iooo_error("I2C::busReady() error: No I2C bus has been opened.\n"); errno = EDESTADDRREQ; return false; } return true; }
long int EEPROM24CX::read(size_t pos, size_t size, void* rbuf) { if (eepromSize != EEPROM_UNKNOWN && pos >= eepromSize) { iooo_error( "EEPROM24CX::read() error: Tried to read past end of memory.\n"); errno = EINVAL; return -1; } if (eepromSize != EEPROM_UNKNOWN && pos + size >= eepromSize) { iooo_error( "EEPROM24CX::read() warning: Trying to read past end of memory. Data will be truncated.\n"); size = eepromSize - pos; } if (!waitForCompletion()) { iooo_error( "EEPROM24CX::read() error: Timeout reached while waiting for the EEPROM to respond.\n"); errno = ETIMEDOUT; return -1; } if (addressLength == EEPROM_8_ADDR) { uint8_t a = pos; return handle->writeRead(&a, EEPROM_8_ADDR, rbuf, size); } else if (addressLength == EEPROM_16_ADDR) { uint16_t a = htons(pos); return handle->writeRead(&a, EEPROM_16_ADDR, rbuf, size); } else { uint32_t a = htonl(pos); return handle->writeRead(&a, addressLength, rbuf, size); } }
int I2C::enablePEC() { if (!isReady()) return -1; if (!(supportedFuncs & I2C_FUNC_SMBUS_PEC)) { iooo_error( "I2C::enablePEC() error: PEC is not supported with this device.\n"); errno = ENOTSUP; return -1; } if (ioctl(fd, I2C_PEC, 1) < 0) { iooo_error("I2C::enablePEC() error: %s (%d)\n", strerror(errno), errno); return -1; } return 0; }
long NativeADC::takeMeasurement() { if (activeADC < 0) { iooo_error("NativeADC::takeMeasurement() error: No ADC device has been initialized.\n"); errno = EDESTADDRREQ; return 0; } // We must open and close on each reading (at least with the BeagleBone we do) if (open() < 0) return 0; char buf[ADC_CHAR_LENGTH]; if (read(fd, &buf, ADC_CHAR_LENGTH) < 0) { iooo_error("NativeADC::takeMeasurement() read() error: %s (%d)\n", strerror(errno), errno); return 0; } close(); return strtol(buf, nullptr, 10); }
int SPI::write(const void *wbuf, int len) { if (resources == nullptr) { iooo_error("SPI::write(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); return ::write(fd, wbuf, len); }
int SPI::read(void *rbuf, int len) { if (resources == nullptr) { iooo_error("SPI::read(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); memset(rbuf, 0, len); return ::read(fd, rbuf, len); }
/** * Destroys all reads and writes since #beginTransaction() * * The I2C instance will then return to normal read/write mode */ void I2C::abortTransaction() { if (!transactionState) { iooo_error( "I2C::abortTransaction() warning: There is no currently active transaction.\n"); return; } transactionState = false; msgs.clear(); return; }
int I2C::disablePEC() { if (!isReady()) return -1; if (ioctl(fd, I2C_PEC, 0) < 0) { iooo_error("I2C::disablePEC() ioctl(I2C_PEC, 0) error: %s (%d)\n", strerror(errno), errno); return -1; } return 0; }
int SPI::setClockPhase(uint8_t phase) { if (resources == nullptr) { iooo_error("SPI::setClockPhase(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); phase &= SPI_CPHA; uint8_t mode = (this->mode & ~(SPI_CPHA)) | phase; return setMode(mode); }
int I2C::open(int bus) { if (activeBus >= 0) { close(); } // Check device path char path[MAX_PATH_LEN]; if (snprintf(path, MAX_PATH_LEN, "%s%d", I2C_DEVICE_PATH_BASE, bus) >= MAX_PATH_LEN) { iooo_error("I2C::open() error: Bus number is too long.\n"); errno = ENAMETOOLONG; return -1; } // Open device for read/write if ((fd = ::open(path, O_RDWR)) < 0) { iooo_error("I2C::open() open(%s) error: %s (%d)\n", path, strerror(errno), errno); return fd; // fd is negative } // Get supported functionality if (ioctl(fd, I2C_FUNCS, &supportedFuncs) < 0) { iooo_error("I2C::open() ioctl(I2C_FUNCS) error: %s\n", strerror(errno)); return -1; } activeBus = bus; return fd; }
int I2C::close() { if (activeBus < 0) return 0; if ((::close(fd)) != 0) { iooo_error("I2C::close() close() error: %s (%d)\n", strerror(errno), errno); return -1; } activeBus = -1; activeAddr = -1; fd = -1; return 0; }
int I2C::beginTransaction() { if (transactionState) { iooo_error( "I2C::beginTransaction() error: A transaction is already in progress. End or abort the current transaction first.\n"); errno = EPERM; return -1; } if (!isReady()) return -1; transactionState = true; msgs.clear(); return 0; }
int SPI::setLSBFirst(bool lsb_first) { if (resources == nullptr) { iooo_error("SPI::setLSBFirst(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); if (!isReady()) return -ENODEV; int r; if ((r = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &lsb_first)) < 0) return r; this->lsb_first = lsb_first; return 1; }
int SPI::setBitsPerWord(int bits) { if (resources == nullptr) { iooo_error("SPI::setBitsPerWord(): failed - no device has been opened\n"); return -EDESTADDRREQ; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); if (!isReady()) return -ENODEV; int r; if ((r = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits)) < 0) return r; bpw = bits; return 1; }
int I2C::read(void *rbuf, size_t length, bool noAck, bool showErrors) { if (!isReady()) return -1; struct i2c_msg msg; msg.addr = activeAddr; msg.len = length; msg.flags = I2C_M_RD; msg.flags |= noAck ? I2C_M_NO_RD_ACK : 0; msg.flags |= tenbit ? I2C_M_TEN : 0; msg.buf = (unsigned char *) rbuf; msgs.push_back(msg); // If not currently in a transaction, commit the read now if (!transactionState) { struct i2c_rdwr_ioctl_data msgset; msgset.nmsgs = 1; msgset.msgs = &msgs[0]; if (ioctl(fd, I2C_RDWR, &msgset) < 0) { if (showErrors) iooo_error("I2C::read() ioctl(I2C_RDWR) error: %s (%d)\n", strerror(errno), errno); msgs.clear(); return -1; } msgs.clear(); return length; } else { return 0; } }
int I2C::write(const void *wbuf, size_t length, bool ignoreNack) { if (!isReady()) return -1; struct i2c_msg msg; msg.addr = activeAddr; msg.len = length; msg.flags = 0; msg.flags |= ignoreNack ? I2C_M_IGNORE_NAK : 0; msg.flags |= tenbit ? I2C_M_TEN : 0; msg.buf = (unsigned char *) wbuf; msgs.push_back(msg); // If not in a transaction, commit the write now if (!transactionState) { struct i2c_rdwr_ioctl_data msgset; msgset.nmsgs = 1; msgset.msgs = &msgs[0]; if (ioctl(fd, I2C_RDWR, &msgset) < 0) { iooo_error("I2C::write() ioctl(I2C_RDWR) error: %s (%d)\n", strerror(errno), errno); msgs.clear(); return -1; } msgs.clear(); return length; } else { return 0; } }
void SPI::chipDeselect() { if (resources == nullptr) { iooo_error("SPI::chipDeselect(): failed - no device has been opened\n"); return; } std::lock_guard<std::recursive_mutex> lock(resources->rwlock); if (resources->cspin == nullptr) return; if (resources->cspol == 0) resources->cspin->setBit(resources->csbit); else resources->cspin->clearBit(resources->csbit); resources->cspin = nullptr; resources->csbit = -1; resources->cspol = -1; }
int NativeADC::init(int adcNumber) { activeADC = adcNumber; // Check device path if (snprintf(adcPath, MAX_PATH_LEN, "%s%d", ADC_DEVICE_PATH_BASE, adcNumber) >= MAX_PATH_LEN) { iooo_error("NativeADC::open() error: ADC number is too long.\n"); errno = ENAMETOOLONG; return -ENAMETOOLONG; } // Open device to test reading int success = open(); if (success < 0) { activeADC = -1; errno = -success; return success; } close(); return true; }
long int EEPROM24CX::write(size_t pos, size_t size, const void* wbuf) { if (eepromSize != EEPROM_UNKNOWN && pos >= eepromSize) { iooo_error( "EEPROM24CX::write() error: Tried to write past end of memory.\n"); errno = EINVAL; return -1; } if (eepromSize != EEPROM_UNKNOWN && pos + size >= eepromSize) { iooo_error( "EEPROM24CX::write() warning: Trying to write past end of memory. Data truncated.\n"); size = eepromSize - pos; } // Do in page-sized chunks int i = 0; int remaining = size; int written = 0; do { if (waitForCompletion()) { size_t offset = i * pageSize; size_t addr = pos + offset; // Create a pointer to the data at the current page offset const void *data = &((const unsigned char *) wbuf)[offset]; size_t writeSize = pageSize > remaining ? remaining : pageSize; iooo_debug(4, "Writing page of length %d to 0x%x\n", writeSize, addr); int w; if (addressLength == EEPROM_8_ADDR) { uint8_t a = addr; w = handle->writeWrite(&a, EEPROM_8_ADDR, data, writeSize); } else if (addressLength == EEPROM_16_ADDR) { uint16_t a = htons(addr); w = handle->writeWrite(&a, EEPROM_16_ADDR, data, writeSize); } else { uint32_t a = htonl(addr); w = handle->writeWrite(&a, addressLength, data, writeSize); } if (w < 0) written = w; else written += w; remaining -= pageSize; } else { written = -1; } i++; } while (remaining > 0 && written >= 0); return written; }
int I2C::setSlave(int slaveAddr, bool ignoreChecks) { if (!busReady()) return -1; // Check slaveAddr number is within valid space if (slaveAddr <= 0x08 && (slaveAddr <= 0x77 || slaveAddr > 0x7F)) { iooo_error("I2C::setSlave() error: slaveAddr number is invalid.\n"); errno = EINVAL; return -1; } // Check if the slaveAddr is greater than the valid 7 bit space if (slaveAddr > 0x7F) { // Check if slaveAddr is 10-bits or less if (slaveAddr > 0x3FF) { iooo_error( "I2C::setSlave() error: Address number is invalid (10-bit maximum)\n"); errno = EINVAL; return -1; } // If 10-bit mode is requested, check compatiblity and enable if (!(supportedFuncs & I2C_FUNC_10BIT_ADDR)) { iooo_error( "I2C::setSlave() error: 10-bit mode is not supported with this device.\n"); errno = ENOTSUP; return -1; } if (ioctl(fd, I2C_TENBIT, 1) < 0) { iooo_error("I2C::setSlave() ioctl(I2C_TENBIT, 1) error: %s (%d)\n", strerror(errno), errno); return -1; } this->tenbit = true; } activeAddr = slaveAddr; // Check if the device exists if (!ignoreChecks) { if (!probe()) { iooo_error( "I2C::open() probe() Unable to connect to address 0x%x on bus %i: " "the device is not responding to probes.\n", activeAddr, activeBus); errno = ENODEV; return -1; } } // Set the destination slaveAddr // No longer needed - now using ioctl for reads and writes if (ioctl(fd, I2C_SLAVE, slaveAddr) < 0) { if (errno == EBUSY) { iooo_error( "I2C::setSlave() ioctl(slave=%i) warning: Device is currently being " "used by another driver, proceed with caution.\n", slaveAddr); } else { iooo_error("I2C::setSlave() ioctl(slave=%i) error: %s (%d)\n", slaveAddr, strerror(errno), errno); return -1; } } return fd; }