linux 应用层下/dev/i2c-%d 设备文件访问封装

6 篇文章 0 订阅

Brief

在linux 应用层使用/dev/i2c-%d的原因有以下几点

  1. 有些器件的驱动需要经常的进行优化改进,并且不是完全稳定可靠,放在内核驱动中可能导致内核oops
  2. 目前的习惯是内核的设备树仅针对核心部分,这样相同的配置可用于不同的硬件,其他的如gpio,spi,i2c等容易变动的地方仅保留了用户接口,没有具体的设备驱动,个人习惯

为啥要封装一层

  • 主要是因为担心总线上多个设备多线程的使用/dev/i2c-%d接口对从设备进行通讯,不加以限制会导致I2C通讯过程不完整.

其他

  • 多进程情况下安全访问 可以使用sem或者mutex的进程共享属性,实现多进程间的同步

Code

/******************************************************************************
 * LJSY C/C++ SOURCE FILE
 ******************************************************************************
 * @file         : i2cmod.c
 * @brief        : This module encapsulates the application layer's access to /dev/i2c-%d device files to ensure the integrity of bus access
 * @version      : 1.0
 * @author       : zhangbin (zhangbin.eos@foxmail.com)
 * @date         : 2023/03/21
 *****************************************************************************/
/*=============INCLUDE ======================================*/
#include <linux/i2c-dev.h>
#include <linux/i2c.h>

#include <stdlib.h> /*< for malloc interface>*/
#include <string.h>	/*< for mem interface */
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <pthread.h>
#include "i2cmod.h"

#include "common_type.h"
#include "zlog.h"
#include "myzlog.h"

/*=============STATIC DEFINE=================================*/
#define I2C_DEV_FORMAT	"/dev/i2c-%d"  // 0,1,2,3 ... 

/*=============STATIC ENUM===================================*/

/*=============STATIC STRUCT ================================*/

/*=============STATIC FUNC DEFINE============================*/
/**
 * @brief 总线互斥锁,也能再这个接口中添加文件建议锁
 * @param  bus              总线句柄
 * @return int
 */
static int i2cmod_bus_lock_init(struct i2cmod_bus * bus);
static int i2cmod_bus_lock_deinit(struct i2cmod_bus * bus);
static int i2cmod_bus_lock(struct i2cmod_bus * bus);
static int i2cmod_bus_module_TryLock(struct i2cmod_bus * bus);
static int i2cmod_bus_unlock(struct i2cmod_bus * bus);


static int i2cmod_set_slave_addr(struct i2cmod_bus * bus, int slave_addr);

/*=============STATIC VARIABLE===============================*/
/**
 * @brief 根据设备上的总线数量来修改这个结构体
 */
static struct i2cmod_bus m_i2cmod_bus_list[] = {
	{
		.id = 0,
		.fd = -1,
		.request_cnt = 0,
	},
	{
		.id = 1,
		.fd = -1,
		.request_cnt = 0,
	},
};

/*=============EXTERN VARIABLE===============================*/

/*=============EXTERN FUNC===================================*/
void i2cmod_init(void)
{
	for (int i = 0; i < ARRAYSIZE(m_i2cmod_bus_list); i++) {
		struct i2cmod_bus * bus = &m_i2cmod_bus_list[i];
		if (bus->fd > 0) {
			close(bus->fd);
			bus->fd = -1;
		}
		sprintf(bus->name, I2C_DEV_FORMAT, bus->id);
		bus->fd = open(bus->name, O_RDWR);
		if (bus->fd < 0) {
			pr_syserr_log("open %s error:", bus->name);
		}
		//init mutex lock
		i2cmod_bus_lock_init(bus);
	}
}

struct i2cmod_bus * i2cmod_request_handle(int bus)
{
	struct i2cmod_bus * objbus = NULL;
	//Find the bus from the list and return the bus related information
	for (int i = 0; i < ARRAYSIZE(m_i2cmod_bus_list); i++) {
		objbus = &m_i2cmod_bus_list[i];
		if (bus == objbus->id) {
			i2cmod_bus_lock(objbus);
			objbus->request_cnt++;
			i2cmod_bus_unlock(objbus);
			break;
		}
	}
	if (objbus == NULL) {
		pr_log(MYLOG_ERROR, "no found bus %d\n", bus);
		return NULL;
	}
	else {
		return objbus;
	}
}

void i2cmod_free_handle(struct i2cmod_bus * bus)
{
	i2cmod_bus_lock(bus);
	bus->request_cnt--;
	i2cmod_bus_unlock(bus);
}

int i2cmod_read(struct i2cmod_bus * bus, uint8_t slave, uint8_t regaddr, uint8_t * buff, uint16_t datasize)
{
	int ret = -1;
	if (bus == NULL) {
		pr_log(MYLOG_ERROR, "handle is NULL\n");
		return -1;
	}
	if (bus->fd < 0) {
		pr_log(MYLOG_ERROR, "bus %d invalid\n", bus->id);
		return -1;
	}
	i2cmod_bus_lock(bus);
	//读数据有2个msg
	struct i2c_msg msg[2] = {
		{
			.addr = slave,
			.flags = 0,
			.buf = &regaddr,
			.len = sizeof(regaddr),
		},
		{
			.addr = slave,
			.flags = I2C_M_RD,
			.buf = buff,
			.len = datasize,
		},
	};
	struct i2c_rdwr_ioctl_data rdwr_msg = {
		.msgs = msg,
		.nmsgs = ARRAYSIZE(msg),
	};
	ret = ioctl(bus->fd, I2C_RDWR, &rdwr_msg);
	i2cmod_bus_unlock(bus);
	if (ret < 0) {
		pr_syserr_log("bus %d slave %02X reg %02X", bus->id, slave, regaddr);
	}
	return ret == -1 ? ret : datasize;
}

int i2cmod_write(struct i2cmod_bus * bus, uint8_t slave, uint8_t regaddr, const uint8_t * data, uint16_t datasize)
{
	int ret = -1;
	if (bus == NULL) {
		pr_log(MYLOG_ERROR, "handle is NULL\n");
		return -1;
	}
	if (bus->fd < 0) {
		pr_log(MYLOG_ERROR, "bus %d invalid\n", bus->id);
		return -1;
	}
	if (datasize + sizeof(regaddr) > sizeof(bus->wbuff)) {
		pr_log(MYLOG_ERROR, "datasize %d must < %ld\n", datasize, sizeof(bus->wbuff) - sizeof(regaddr));
		return -1;
	}
	i2cmod_bus_lock(bus);
	memcpy(&bus->wbuff[0], &regaddr, sizeof(regaddr));
	memcpy(&bus->wbuff[sizeof(regaddr)], data, datasize);
	//写数据是1个msg
	struct i2c_msg msg[1] = {
		{
			.addr = slave,
			.flags = 0,
			.buf = bus->wbuff,
			.len = datasize + 1,
		}
	};
	struct i2c_rdwr_ioctl_data rdwr_msg = {
		.msgs = msg,
		.nmsgs = ARRAYSIZE(msg),
	};
	ret = ioctl(bus->fd, I2C_RDWR, &rdwr_msg);
	i2cmod_bus_unlock(bus);
	if (ret < 0) {
		pr_syserr_log("bus %d slave %02X reg %02X", bus->id, slave, regaddr);
	}
	return ret == -1 ? ret : datasize;
}

int i2cmod_read16(struct i2cmod_bus * bus, uint8_t slave, uint16_t regaddr, uint8_t * buff, uint16_t datasize)
{
	if (bus == NULL) {
		pr_log(MYLOG_ERROR, "handle is NULL\n");
		return -1;
	}
	if (bus->fd < 0) {
		pr_log(MYLOG_ERROR, "bus %d invalid\n", bus->id);
		return -1;
	}
	i2cmod_bus_lock(bus);
	//memcpy(&wbuff[0],&regaddr,sizeof(regaddr));
	if (write(bus->fd, &regaddr, sizeof(regaddr)) != sizeof(regaddr)) {
		pr_syserr_log("bus %d slave %02X reg %02X", bus->id, slave, regaddr);
		goto failed;
	}
	if (read(bus->fd, buff, datasize) != datasize) {
		pr_syserr_log("bus %d slave %02X reg %02X", bus->id, slave, regaddr);
		goto failed;
	}
	i2cmod_bus_unlock(bus);
	return datasize;
failed:
	i2cmod_bus_unlock(bus);
	return -1;
}

int i2cmod_write16(struct i2cmod_bus * bus, uint8_t slave, uint16_t regaddr, const uint8_t * data, uint16_t datasize)
{
	int ret = -1;
	if (bus == NULL) {
		pr_log(MYLOG_ERROR, "handle is NULL\n");
		return -1;
	}
	if (bus->fd < 0) {
		pr_log(MYLOG_ERROR, "bus %d invalid\n", bus->id);
		return -1;
	}
	if (datasize + sizeof(regaddr) > sizeof(bus->wbuff)) {
		pr_log(MYLOG_ERROR, "datasize %d must < %ld\n", datasize, sizeof(bus->wbuff) - sizeof(regaddr));
		return -1;
	}
	i2cmod_bus_lock(bus);
	memcpy(&bus->wbuff[0], &regaddr, sizeof(regaddr));
	memcpy(&bus->wbuff[sizeof(regaddr)], data, datasize);
	int totalsize = datasize + sizeof(regaddr);
	ret = write(bus->fd, bus->wbuff, totalsize);
	if (ret != totalsize) {
		pr_syserr_log("bus %d slave %02X reg %02X", bus->id, slave, regaddr);
		ret = -1;
	}
	i2cmod_bus_unlock(bus);
	return ret;
}

/*=============STATIC FUNC===================================*/
static int i2cmod_bus_lock_init(struct i2cmod_bus * bus)
{
	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
	return pthread_mutex_init(&bus->lock, &attr);
}

static int i2cmod_bus_lock_deinit(struct i2cmod_bus * bus)
{
	return pthread_mutex_destroy(&bus->lock);
}

static int i2cmod_bus_lock(struct i2cmod_bus * bus)
{
	return pthread_mutex_lock(&bus->lock);
}

static int i2cmod_bus_module_TryLock(struct i2cmod_bus * bus)
{
	return pthread_mutex_trylock(&bus->lock);
}

static int i2cmod_bus_unlock(struct i2cmod_bus * bus)
{
	return pthread_mutex_unlock(&bus->lock);
}

static int i2cmod_set_slave_addr(struct i2cmod_bus * bus, int slave_addr)
{
	if (ioctl(bus->fd, I2C_SLAVE_FORCE/*I2C_SLAVE*/, slave_addr) < 0) {
		/* ERROR HANDLING; you can check errno to see what went wrong */
		pr_syserr_log("ioctl %d:\n", slave_addr);
		return (-1);
	}
	return (0);
}
/*===========================================================*/

/*END */
/******************************************************************************
 * LJSY C/C++ HEAD FILE
 ******************************************************************************
 * @file         : i2cmod.h
 * @brief        :
 * @version      : 1.0
 * @author       : zhangbin (zhangbin.eos@foxmail.com)
 * @date         : 2023/03/21
 *****************************************************************************/
#ifndef __I2CMOD_H__
#define __I2CMOD_H__
#ifdef __cplusplus
extern "C" {
#endif

/*=============INCLUDE=======================================*/
#include <stdint.h>
#include <pthread.h>

/*=============EXTERN DEFINE=================================*/
#define I2C_WBUFF_MAX	(512+2)

/*=============EXTERN ENUM===================================*/

/*=============EXTERN STRUCT ================================*/
typedef struct i2cmod_bus {
	int id;//bus id
	char name[32];//dev name
	int fd;//i2c dev file handle
	size_t request_cnt;//Bus Request Count
	uint8_t wbuff[I2C_WBUFF_MAX];
	pthread_mutex_t lock;
} OBJ_I2CMOD_BUS;

/*=============EXTERN VARIABLE===============================*/

/*=============EXTERN FUNC===================================*/
/**
 * @brief 模块初始化
 */
extern void i2cmod_init(void);

/**
 * @brief 从模块中申请一个接口的访问句柄
 * @param  bus              i2c bus id:0,1,2 ...
 * @return void* 			bus handle
 */
extern struct i2cmod_bus * i2cmod_request_handle(int bus);

/**
 * @brief 释放一个接口的访问句柄
 * @param  bus           bus handle
 */
extern void i2cmod_free_handle(struct i2cmod_bus * bus);

/**
 * @brief i2c读写接口
 * @param  handle           bus handle
 * @param  slave			slave device addr 7bit
 * @param  regaddr          device's reg addr
 * @param  buff             data buffer
 * @param  datasize         data len
 * @return int 				-1=failed;
 */
extern int i2cmod_read(struct i2cmod_bus * bus, uint8_t slave, uint8_t regaddr, uint8_t * buff, uint16_t datasize);
extern int i2cmod_write(struct i2cmod_bus * bus, uint8_t slave, uint8_t regaddr, const uint8_t * data, uint16_t datasize);
extern int i2cmod_read16(struct i2cmod_bus * bus, uint8_t slave, uint16_t regaddr, uint8_t * buff, uint16_t datasize);
extern int i2cmod_write16(struct i2cmod_bus * bus, uint8_t slave, uint16_t regaddr, const uint8_t * data, uint16_t datasize);


#ifdef __cplusplus
}
#endif

#endif//__I2CMOD_H__
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值