海思Hi3559AV100平台韦根发送程序

      项目中需要基于海思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]");

项目资源下载地址:

 https://download.csdn.net/download/phmatthaus/12209392

发布了34 篇原创文章 · 获赞 12 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/104637403