| // Copyright 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| |
| #include "i2c_device.h" |
| |
| I2CDevice::I2CDevice(const char* device_filename, |
| const uint8_t device_address) : |
| // Does nothing except store the constant values. |
| address_(device_address), |
| filename_(device_filename) |
| |
| { |
| LOG(INFO) << "New i2c device for " << address_ << " at " << filename_; |
| } |
| |
| |
| int I2CDevice::Begin() { |
| // First, this opens the /dev device. |
| int rc = open_i2c(); |
| if (rc < 0) { |
| return rc; |
| } |
| // Then, registers it as a slave. |
| rc = enslave_i2c(); |
| if (rc < 0) { |
| return rc; |
| } |
| return 0; |
| } |
| |
| |
| int I2CDevice::End() { |
| return close(fd_); |
| } |
| |
| |
| int I2CDevice::open_i2c() { |
| // Opening the device is just a R/W file open. |
| int fd = open(filename_, O_RDWR); |
| if (-1 == fd) { |
| PLOG(ERROR) << "Could not open i2c device."; |
| return -1; |
| } |
| LOG(INFO) << "i2c device opened at " << filename_; |
| fd_ = fd; |
| return fd; |
| } |
| |
| |
| int I2CDevice::enslave_i2c() { |
| // The I2C_SLAVE ioctl is sent to the device at the given address. |
| int rc = ioctl(fd_, I2C_SLAVE, address_); |
| if (rc < 0) { |
| PLOG(ERROR) << "i2c device failed to become a slave."; |
| return rc; |
| } |
| printf("yes %x\n", address_); |
| LOG(INFO) << "i2c device is a slave at" << filename_; |
| return rc; |
| } |
| |
| |
| int I2CDevice::Send(struct i2c_msg messages[], |
| const size_t count) { |
| // Sending messages requires them to be wrapped in the i2c_rdwr_ioctl_data |
| // struct and sending them using the I2C_RDWR ioctl. |
| struct i2c_rdwr_ioctl_data data = { |
| .msgs = messages, |
| .nmsgs = count |
| }; |
| int rc = ioctl(fd_, I2C_RDWR, &data); |
| if (rc < 0) { |
| PLOG(ERROR) << "Unable to send data."; |
| } |
| return rc; |
| } |
| |
| |
| int I2CDevice::SetRegister(const uint8_t register_address, |
| const uint8_t value) { |
| // Setting a register involves sending a single message with a 2-byte payload. |
| // The first byte is the register address, and the second is the value. |
| uint8_t outbuf[] = {register_address, value}; |
| struct i2c_msg messages[1]; |
| messages[0] = { |
| .addr = address_, |
| .flags = 0, |
| .len = sizeof(outbuf), |
| .buf = outbuf |
| }; |
| return Send(messages, 1); |
| } |
| |
| |
| int I2CDevice::GetRegister(const uint8_t register_address, |
| uint8_t& value) { |
| // Reading a register involves sending two messages, each with a single-byte |
| // payload. The first message contains the register address and the second |
| // message is empty and will contain the response value. |
| struct i2c_msg messages[2]; |
| uint8_t outbuf = register_address; |
| // Both messages need the addr value set. |
| messages[0] = { |
| .addr = address_, |
| .flags = 0, |
| .len = 1, |
| .buf = &outbuf |
| }; |
| // Needs to pass the I2C_M_RD flag in order to get the value. |
| messages[1] = { |
| .addr = address_, |
| .flags = I2C_M_RD, |
| .len = 1, |
| .buf = &value, |
| }; |
| // Will contain the register value. |
| int rc = Send(messages, 2); |
| return rc; |
| } |