-
Notifications
You must be signed in to change notification settings - Fork 57
Closed
Description
Hi,
I'm mainly experienced in C development and I saw in Rust a massive game changer in memory safety & some other things like concurrency, so I started to move to Rust for my developments.
My first program was to develop a device driver using I2C bus, I'm on RPI4, but I'm facing one massive issue, I am not able to write register on the device, but I don't know why.
There is program samples & strace logs:
From my working C program:
#include <stdio.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
int read_status(int fd) {
int rc = 0;
uint8_t buf[3] = {0x6a, 0x0, 0x0};
struct i2c_msg messages[] = {
{.addr = 0x4b, .flags = 0, .buf = buf, .len = 1},
{.addr = 0x4b, .flags = I2C_M_RD, .buf = buf, .len = 3},
};
struct i2c_rdwr_ioctl_data ioctl_data = {
.msgs = messages,
.nmsgs = 2,
};
rc = ioctl(fd, I2C_RDWR, &ioctl_data);
if(rc != 2) {
perror("Unable to read\n");
return -1;
}
printf("Status: [%x, %x, %x]\n", buf[0], buf[1], buf[2]);
return 0;
}
int start_fan(int fd, uint8_t start_stop) {
uint8_t buf[2] = {0x2b, start_stop};
int ret = 0;
ret = i2c_smbus_write_byte_data(fd, buf[0], buf[1]);
if(ret < 0) {
perror("Failed to start fan");
return -1;
}
return 0;
}
int main() {
int ret = 0;
int fd = open("/dev/i2c-1", O_RDWR);
if (fd < 0) {
printf("Failed to open i2c-1\n");
return 1;
}
uint8_t addr = 0x4b;
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
printf("Failed to acquire bus access/talk to slave\n");
return 1;
}
ret = read_status(fd);
if(ret < 0) {
printf("Failed to verify status\n");
return 1;
}
ret = start_fan(fd, 1);
if(ret < 0) {
printf("Failed to start fan\n");
return 1;
}
printf("Fan started\n");
ret = read_status(fd);
if(ret < 0) {
printf("Failed to verify status\n");
return 1;
}
close(fd);
return 0;
}Status: [0, 78, f0]
Fan started
Status: [1, f1, e1]openat(AT_FDCWD, "/dev/i2c-1", O_RDWR) = 3
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x3, 0), 0x4b) = 0
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x20, 0), 0xbee68538) = 0
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0xbee68570) = 2
write(1, "Status: [0, 78, f0]\n", 20Status: [0, 78, f0]
) = 20
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x20, 0), 0xbee68538) = 0
write(1, "Fan started\n", 12Fan started
) = 12
ioctl(3, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0xbee68570) = 2
write(1, "Status: [1, f1, e1]\n", 20Status: [1, f1, e1]
) = 20
close(3) = 0
From my non-working rust program :
device.rs
use embedded_hal::i2c::blocking::{I2c, Operation};
#[cfg(feature = "serde")]
use serde::Serialize;
pub const Devcie_I2C_ADDR: u8 = 0x4b;
#[derive(Debug)]
pub enum Error<E> {
/// I²C bus error
I2c(E),
/// Failed to parse sensor data
InvalidData,
/// No calibration data is available (probably forgot to call or check BME280::init for failure)
NoCalibrationData,
/// Chip ID doesn't match expected value
UnsupportedChip,
}
#[derive(Debug, Default)]
pub struct Device<I2C> {
/// concrete I²C device implementation
i2c: I2C,
/// I²C device address
address: u8,
}
impl<I2C> Device<I2C>
where
I2C: I2c,
{
/// Create a new BME280 struct using a custom I²C address
pub fn new(i2c: I2C, address: u8) -> Self {
Device { i2c, address }
}
pub fn verify_status(&mut self) -> Result<u8, I2C::Error> {
let status = self.read_register(0x64, 3)?;
let crc = crc16(&status[..2]);
Ok(status[0])
}
pub fn start_mode(&mut self) -> Result<(), I2C::Error> {
self.write_register(0x10, 0x2)
}
pub fn start_fan(&mut self) -> Result<(), I2C::Error> {
self.write_register(0x2b, 1)
}
fn read_register(&mut self, register: u8, length: u8) -> Result<Vec<u8>, I2C::Error> {
let mut data: Vec<u8> = vec![0; length as usize];
let buf: Vec<u8> = vec![register];
let mut ops = [Operation::Write(&buf), Operation::Read(&mut data)];
self.i2c.transaction(self.address, &mut ops)?;
println!("{:x?}", data);
Ok(data)
}
fn write_register(&mut self, register: u8, payload: u8) -> Result<(), I2C::Error> {
println!("Writing to register 0x{:02x}: 0x{:02x}", register, payload);
let data: Vec<u8> = vec![register, payload];
let mut ops = [Operation::Write(&data)];
self.i2c.transaction(self.address, &mut ops)
}
}
fn crc16(data: &[u8]) -> u16 {
let mut _data: u16 = 0;
let mut crc = 0xffff_u16;
for i in 0..data.len() {
_data = 0xff as u16 & data[i] as u16;
for _ in 0..8 {
if (crc & 0x0001_u16) ^ (_data & 0x0001_u16) != 0 {
crc = (crc >> 1) ^ 0x8408_u16;
} else {
crc >>= 1;
}
_data >>= 1;
}
}
crc = !crc;
_data = crc;
crc = (crc << 8) | (_data >> 8 & 0xff);
crc
}
#[cfg(test)]
#[test]
pub fn test_crc_16() {
// Test simple command
let data = [0_u8, 0x78_u8, 0xf0_u8];
let crc = crc16(&data[..data.len() - 2]);
assert_eq!(crc, 0x78f0_u16);
let data = [0x0_u8, 0x9_u8, 0x3a_u8, 0x80_u8, 0x1a_u8, 0xaf_u8];
let interval = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
assert_eq!(interval, 604800_u32);
let crc = crc16(&data[..data.len() - 2]);
assert_eq!(crc, 0x1aaf_u16);
let data = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xca, 6,
];
let crc = crc16(&data[..data.len() - 2]);
println!("{:x}", crc);
assert_eq!(crc, 0xca06_u16);
let data = [
0, 0x3, 0x90, 0x4c, 0, 1, 0xf5, 0x7a, 0, 0, 0x6e, 0xb4, 0, 0, 5, 0xd5, 0, 0, 1, 0xf, 0, 0,
0, 0, 0, 0, 0, 0, 0x11, 0xe1,
];
let crc = crc16(&data[..data.len() - 2]);
assert_eq!(crc, 0x11e1_u16);
let data = [
0, 2, 0x63, 0x8d, 0, 1, 0x43, 0x1d, 0, 0, 0x42, 0x29, 0, 0, 1, 0xf7, 0, 0, 0, 0x15, 0, 0,
0, 0, 0, 0, 0, 0, 0xb4, 0x19,
];
let crc = crc16(&data[..data.len() - 2]);
assert_eq!(crc, 0xb419_u16);
}main.rs
use linux_embedded_hal::I2cdev;
mod device;
fn main() {
let i2c_bus = I2cdev::new("/dev/i2c-1").unwrap();
let mut ipsx100: ips7100_v2::Device<I2cdev> =
ips7100_v2::Device::new(i2c_bus, ips7100_v2::Devcie_I2C_ADDR);
match ipsx100.verify_status() {
Ok(status) => println!("Device status verified: {}", status),
Err(e) => println!("Error: {:?}", e),
}
match ipsx100.start_fan() {
Ok(_) => println!("Fan started"),
Err(e) => println!("Error: {:?}", e),
}
match ipsx100.verify_status() {
Ok(status) => println!("Device status verified: {:x}", status),
Err(e) => println!("Error: {:?}", e),
}
}[0, 78, f0]
Device status verified: 0
Writing to register 0x2b: 0x01
Fan started
[0, 78, f0]
Device status verified: 0openat(AT_FDCWD, "/dev/i2c-1", O_RDWR|O_LARGEFILE|O_CLOEXEC) = 4
ioctl(4, _IOC(_IOC_NONE, 0x7, 0x3, 0), 0x4b) = 0
ioctl(4, _IOC(_IOC_NONE, 0x7, 0x8, 0), 0) = 0
ioctl(4, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0xbebc1388) = 2
write(1, "[0, 78, f0]\n", 12[0, 78, f0]
) = 12
ioctl(4, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0xbea0e3a0) = 1
write(1, "Fan started\n", 12Fan started
) = 12
ioctl(4, _IOC(_IOC_NONE, 0x7, 0x7, 0), 0xbebc1388) = 2
write(1, "[0, 78, f0]\n", 12[0, 78, f0]
) = 12
close(4) = 0
What I'm doing wrong ?
Can someone help me ?
Thanks in advance, and sorry for this long post.
Metadata
Metadata
Assignees
Labels
No labels