项目中需要基于海思Hi3559AV100开发韦根功能。韦根分为韦根输出和韦根输入,这篇文章讲韦根输出程序,前一篇文章讲韦根输出程序。
首先,必须要感谢https://blog.csdn.net/qq_37803273/article/details/84993627 《RK3288韦根发送驱动》的作者的无私分享,文章中提供了源码(以下简称例程),很详细,我的代码也是以这篇文章中的代码为基础进行修正改进而得到的。
其次,需要说明的是,韦根发送程序的坑不像韦根接收程序那么多,主要的点在延时上。例程中使用了msleep和usleep_range函数,但实测是无法保证精确低脉冲的。纠结于是否使用udelay,担心其占据CPU特性以及相对较长的延时会影响实时视频传输导致卡顿。但最终实测下来,效果还是可以接受的,因此在代码中广泛使用了udelay。
最后,整个工程源码以附件形式放到网上,初始设定为0积分加载。
韦根输出代码如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
//msleep:实现毫秒级的延时,该延时保证至少延时所设置的延时时间,不会提前超时返回,会让出CPU
#define delay_1ms(x) msleep(x)
#define GPIO12_4 (12 * 8 + 4)
#define GPIO12_2 (12 * 8 + 2)
#define WG_DATA0 GPIO12_4
#define WG_DATA1 GPIO12_2
struct wiegand26
{
bool flag;
char data[24];
} wiegand26;
struct wiegand34
{
bool flag;
char data[32];
} wiegand34;
static struct workqueue_struct *queue = NULL;
static struct work_struct work;
static int major;
static struct class *class = NULL;
static struct device *dev = NULL;
static int even = 0;
static int odd = 0;
//设置相应GPIO引脚为输出,并输出为高
void gpio_set_output(void)
{
gpio_direction_output(WG_DATA0, 1); //DATA0初始为高
gpio_direction_output(WG_DATA1, 1); //DATA1初始为高
}
//初始化相应GPIO
void gpio_init(void)
{
gpio_request(WG_DATA0, "wiegand_d0");
gpio_request(WG_DATA1, "wiegand_d1");
gpio_set_output();
}
int wiegand26_int_to_char(int data)
{
int i = 0;
odd = 0;
even = 0;
for(i=0; i<24; i++)
{
if((1<<i) & data)
{
wiegand26.data[23-i] = '1';
if(i < 12)
odd++;
else
even++;
}
else
wiegand26.data[23-i] = '0';
}
//printk("data is %#x\n", data);
//printk("str is: %s\n", wiegand26.data);
//printk("check even=%d, odd=%d\n", even, odd);
return 0;
}
int wiegand34_int_to_char(int data)
{
int i = 0;
odd = 0;
even = 0;
for(i=0; i<32; i++)
{
if((1<<i) & data)
{
wiegand34.data[31-i] = '1';
if(i < 16)
odd++;
else
even++;
}
else
wiegand34.data[31-i] = '0';
}
printk("data is %#x\n", data);
printk("str is: %s\n", wiegand34.data);
printk("check even=%d, odd=%d\n", even, odd);
return 0;
}
void wg_send_bit_0(void)
{
//输出'0'时,DATA0线上出现负脉冲
gpio_set_value(WG_DATA0, 0); //DATA0输出低
udelay(100); //延时100us,符合韦根标准
gpio_set_value(WG_DATA0, 1); //DATA0输出高
udelay(1500);
}
void wg_send_bit_1(void)
{
//输出'1'时,DATA1线上出现正脉冲
gpio_set_value(WG_DATA1, 0); //DATA1输出低
udelay(100); //延时100us,符合韦根标准
gpio_set_value(WG_DATA1, 1); //DATA1输出高
udelay(1500);
}
//韦根26格式数据发送
int send_wiegand26(unsigned char *str)
{
int i = 0;
//printk("\nsend_wiegand26 start\n");
//WG_DATA0 = 1;
//WG_DATA1 = 1;
gpio_set_output();
delay_1ms(2);
//偶校验:当实际数据中1的个数为偶数的时候,这个校验位就是0,否则这个校验位就是1
if(even % 2)
{
printk("1 ");
wg_send_bit_1(); //偶校验位为1
}
else
{
printk("0");
wg_send_bit_0(); //偶校验位为0
}
//delay_1ms(2); //延时2ms
for(i=0; i<24; i++)
{
//WG_DATA0 = 1;
//WG_DATA1 = 1;
if(str[i] & 0x01) //数据位为1的情况
{
printk("1");
wg_send_bit_1();
}
else //数据位为0的情况
{
printk("0");
wg_send_bit_0();
}
//delay_1ms(2);
}
//WG_DATA0 = 1;
//WG_DATA1 = 1;
//奇校验:当实际数据中1的个数为偶数的时候,这个校验位就是1,否则这个校验位就是0
if(odd % 2)
{
//printk("0");
wg_send_bit_0();
}
else
{
//printk("1");
wg_send_bit_1();
}
//delay_1ms(2);
//printk("\nend_weigand26 end\n");
return 0;
}
//韦根34格式数据发送
int send_wiegand34(unsigned char *str)
{
int i = 0;
printk("\nsend_wiegand34 start\n");
//WG_DATA0 = 1;
//WG_DATA1 = 1;
gpio_set_output();
delay_1ms(2);
//偶校验:当实际数据中1的个数为偶数的时候,这个校验位就是0,否则这个校验位就是1
if(even % 2)
{
//printk("1");
wg_send_bit_1();
}
else
{
//printk("0");
wg_send_bit_0();
}
//delay_1ms(2); //延时2ms
for(i=0; i<32; i++)
{
//WG_DATA0 = 1;
//WG_DATA1 = 1;
if(str[i] & 0x01) //数据位为1的情况
{
//printk("1");
wg_send_bit_1();
}
else //数据位为0的情况
{
//printk("0");
wg_send_bit_0();
}
//delay_1ms(2);
}
//WG_DATA0 = 1;
//WG_DATA1 = 1;
//奇校验:当实际数据中1的个数为偶数的时候,这个校验位就是1,否则这个校验位就是0
if(odd % 2)
{
//printk("0");
wg_send_bit_0();
}
else
{
//printk("1");
wg_send_bit_1();
}
//delay_1ms(2);
printk("\nsend_weigand34 end\n");
return 0;
}
static void work_handler(struct work_struct *data)
{
printk(KERN_ALERT "work_handler function\n");
if(wiegand26.flag)
{
send_wiegand26(wiegand26.data);
wiegand26.flag = false;
}
else if(wiegand34.flag)
{
send_wiegand34(wiegand34.data);
wiegand34.flag = false;
}
else
{
printk(KERN_ALERT "work handler function error\n");
}
printk(KERN_ALERT "work handler end\n");
}
static ssize_t wiegand26_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", wiegand26.data);
}
static ssize_t wiegand26_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
wiegand26_int_to_char(val);
wiegand26.flag = true;
INIT_WORK(&work, work_handler);
schedule_work(&work);
return count;
}
static ssize_t wiegand34_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", wiegand34.data);
}
static ssize_t wiegand34_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
wiegand34_int_to_char(val);
wiegand34.flag = true;
INIT_WORK(&work, work_handler);
schedule_work(&work);
return count;
}
static DEVICE_ATTR(wiegand26, 0664, wiegand26_show, wiegand26_store);
static DEVICE_ATTR(wiegand34, 0664, wiegand34_show, wiegand34_store);
static struct attribute *wiegand_out_attributes[] =
{
&dev_attr_wiegand26.attr,
&dev_attr_wiegand34.attr,
NULL
};
static struct attribute_group wiegand_out_attribute_group = {
.attrs = wiegand_out_attributes
};
static int wiegand_out_open(struct inode *inode, struct file *file)
{
return 0;
}
static int wiegand_out_close(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t wiegand_out_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
return 0;
}
static struct file_operations wiegand_out_fops =
{
.owner = THIS_MODULE,
.open = wiegand_out_open,
.release = wiegand_out_close,
.write = wiegand_out_write,
};
static int wiegand_out_probe(struct platform_device *pdev)
{
int ret = 0;
printk("wiegand_out_probe\n");
//注册及初始化GPIO
gpio_init();
//注册设备驱动
major = register_chrdev(0, "wiegand_out", &wiegand_out_fops);
//创建类
class = class_create(THIS_MODULE, "wiegand_out");
//创建设备节点
dev = device_create(class, NULL, MKDEV(major, 0), NULL, "wiegand_out_dev");
if(IS_ERR(dev))
{
//return -1;
}
//在/sys/class/wiegand_out/wiegand_out目录下创建属性文件wiegand26
ret = device_create_file(dev, &dev_attr_wiegand26);
if(ret < 0)
{
}
//在/sys/class/wiegand_out/wiegand_out_dev目录下创建属性文件wiegand34
ret = device_create_file(dev, &dev_attr_wiegand34);
if(ret < 0)
{
}
//创建属性文件的sysfs接口函数
ret = sysfs_create_group(&pdev->dev.kobj, &wiegand_out_attribute_group);
wiegand26.flag = false;
wiegand34.flag = false;
printk("wiegand_out_probe, end ret=%d\n",ret);
return ret;
}
static int wiegand_out_remove(struct platform_device *pdev)
{
printk("wiegand_out_remove\n");
//删除接口函数
sysfs_remove_group(&pdev->dev.kobj, &wiegand_out_attribute_group);
device_remove_file(dev, &dev_attr_wiegand26);
device_remove_file(dev, &dev_attr_wiegand34);
//删除设备节点
device_unregister(dev);
//注销创建的设备类
class_destroy(class);
//取消注册设备驱动
unregister_chrdev(major, "wiegand_out");
//释放注册的GPIO编号
gpio_free(WG_DATA0);
gpio_free(WG_DATA1);
return 0;
}
static struct platform_driver wiegand_out_drv =
{
//完成具体设备的初始化操作
.probe = wiegand_out_probe, //匹配到dev之后调用probe
//完成具体设备的退出操作
.remove = wiegand_out_remove,
.driver =
{
.name = "wiegand_out",
.owner = THIS_MODULE,
//.of_match_table = of_match_ptr(wiegand_out_of_match),
},
};
static void wiegand_out_device_release(struct device *dev)
{
return;
}
static struct platform_device wiegand_out_device =
{
.name = "wiegand_out",
.id = -1,
//必须有release函数,否则卸载模块时会报"Device 'wiegand_out' does not have a release() function, it is broken and must be fixed."
.dev =
{
.release = wiegand_out_device_release,
}
};
//设备驱动模块加载函数
static int __init wiegand_out_init(void)
{
int ret = 0;
printk("wiegand_out_init\n");
//创建一个单线程的工作队列
queue = create_singlethread_workqueue("weigand_send");
if(!queue)
{
printk(KERN_ERR "create_singlethread_workqueue failed\n");
return -1;
}
//平台驱动注册
ret = platform_driver_register(&wiegand_out_drv);
if(ret)
{
printk(KERN_ERR "platform_driver_register failed\n");
destroy_workqueue(queue);
return -1;
}
//平台设备注册
ret = platform_device_register(&wiegand_out_device);
if(ret)
{
printk(KERN_ERR"platform_device_register failed\n");
platform_driver_unregister(&wiegand_out_drv);
destroy_workqueue(queue);
return -1;
}
return 0;
}
//设备驱动模块卸载函数
static void __exit wiegand_out_exit(void)
{
printk(KERN_ALERT "wiegand_out_exit\n");
//平台设备注销
platform_device_unregister(&wiegand_out_device);
//平台驱动注销
platform_driver_unregister(&wiegand_out_drv);
//释放工作队列所占的资源
destroy_workqueue(queue);
}
module_init(wiegand_out_init);
module_exit(wiegand_out_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("[email protected]");
项目资源下载地址: