wiegand

海思交叉编译 wiegand

1. wiegand 输出
对应文件名wiegand_out.c
贴上代码:

#include “wiegand.h”
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/semaphore.h>
#include <linux/string.h>
#include <linux/wait.h>

// msleep:实现毫秒级的延时,该延时保证至少延时所设置的延时时间,不会提前超时返回,会让出CPU
#define delay_1ms(x) msleep(x)

#define GPIO6_2 (6 * 8 + 2)
#define GPIO10_6 (10 * 8 + 6)
#define DEVICE_DATA0_LABEL “wiegand_out_d0”
#define DEVICE_DATA1_LABEL “wiegand_out_d1”

struct wiegand26 {
bool flag;
char data[27];
} wiegand26;

struct wiegand34 {
bool flag;
char data[35];
} wiegand34;

struct wiegand66 {
bool flag;
char data[67];
} wiegand66;

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 WG_DATA1 = GPIO6_2;
static int WG_DATA0 = GPIO10_6;
static int LOW_TIME = 100;
static int HIGH_TIME = 1500;
static int isStartGPIO = false;

//设置相应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, DEVICE_DATA0_LABEL);
gpio_request(WG_DATA1, DEVICE_DATA1_LABEL);
gpio_set_output();
}

void wg_int_to_char(long long ic_card, char *buffer, int len) {
int even = 0;
int odd = 0;
int i = 0;
for (; i < len; i++) {
if ((ic_card >> i) & 0x01) {
buffer[len - i] = ‘1’;
if (i < len / 2) {
odd++;
} else {
even++;
}
} else {
buffer[len - i] = ‘0’;
}
}
buffer[0] = even & 0x01 ? ‘1’ : ‘0’;
buffer[len + 1] = odd & 0x01 ? ‘0’ : ‘1’;
printk(“str is: %s\n”, buffer);
}

void wiegand26_int_to_char(int data) {
wg_int_to_char(data, wiegand26.data, 24);
}

void wiegand34_int_to_char(int data) {
wg_int_to_char(data, wiegand34.data, 32);
}

void wiegand66_int_to_char(long long data) {
wg_int_to_char(data, wiegand66.data, 64);
}

void wg_send_bit(int wg_data_pin) {
gpio_set_value(wg_data_pin, 0);
udelay(LOW_TIME);
gpio_set_value(wg_data_pin, 1);

udelay(HIGH_TIME);
}

//韦根34格式数据发送
int send_wiegand(char *str, int len) {
int i = 0;

printk("\nsend_wiegand34 start\n");

gpio_set_output();
delay_1ms(2);

for (i = 0; i < len; i++) {
if (str[i] == ‘1’) //数据位为1的情况
{
wg_send_bit(WG_DATA1);
} else //数据位为0的情况
{
wg_send_bit(WG_DATA0);
}
}

return 0;
}

static void work_handler(struct work_struct *data) {
printk(KERN_ALERT “work_handler function\n”);

if (wiegand26.flag) {
send_wiegand(wiegand26.data, 26);
wiegand26.flag = false;
} else if (wiegand34.flag) {
send_wiegand(wiegand34.data, 34);
wiegand34.flag = false;
}else if (wiegand66.flag) {
send_wiegand(wiegand66.data, 66);
wiegand66.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 = 0;
if (isStartGPIO == false) {
//注册及初始化GPIO
gpio_init();
isStartGPIO = true;
}
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 = 0;
if (isStartGPIO == false) {
//注册及初始化GPIO
gpio_init();
isStartGPIO = true;
}
sscanf(buf, “%d”, &val);
wiegand34_int_to_char(val);
wiegand34.flag = true;
INIT_WORK(&work, work_handler);
schedule_work(&work);

return count;
}

static ssize_t wiegand66_show(struct device *dev, struct device_attribute *attr,
char *buf) {
return sprintf(buf, “%s\n”, wiegand66.data);
}

static ssize_t wiegand66_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count) {
long long val = 0;
if (isStartGPIO == false) {
//注册及初始化GPIO
gpio_init();
isStartGPIO = true;
}
printk(“buf = %s\n”, buf);
sscanf(buf, “%lld”, &val);
printk(“val = %lld\n”, val);
wiegand66_int_to_char(val);
wiegand66.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 DEVICE_ATTR(wiegand66, 0664, wiegand66_show, wiegand66_store);

static struct attribute *wiegand_out_attributes[] = {
&dev_attr_wiegand26.attr, &dev_attr_wiegand34.attr, &dev_attr_wiegand66.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 long wiegand_out_ioctl(struct file filp, unsigned int cmd,
unsigned long arg) {
/
检查设备类型 */
if (_IOC_TYPE(cmd) != IOC_MAGIC) {
pr_err("[%s] command type [%c] error!\n", func, _IOC_TYPE(cmd));
return -ENOTTY;
}

switch (cmd) {
case IOCTL_SET_DATA0:
WG_DATA0 = arg;
break;
case IOCTL_SET_DATA1:
WG_DATA1 = arg;
break;
case IOCTL_SET_LOW_TIME:
LOW_TIME = arg;
break;
case IOCTL_SET_HIGH_TIME:
HIGH_TIME = arg;
break;
default:
break;
}
printk("%u,%ld\n", cmd, arg);
return 0;
}

static struct file_operations wiegand_out_fops = {
.owner = THIS_MODULE,
.open = wiegand_out_open,
.release = wiegand_out_close,
.write = wiegand_out_write,
.compat_ioctl = wiegand_out_ioctl,
.unlocked_ioctl = wiegand_out_ioctl,
};

static int wiegand_out_probe(struct platform_device *pdev) {
int ret = 0;

printk(“wiegand_out_probe\n”);

//注册设备驱动
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) {
}

//在/sys/class/wiegand_out/wiegand_out_dev目录下创建属性文件wiegand66
ret = device_create_file(dev, &dev_attr_wiegand66);
if (ret < 0) {
}

//创建属性文件的sysfs接口函数
ret = sysfs_create_group(&pdev->dev.kobj, &wiegand_out_attribute_group);

wiegand26.flag = false;
wiegand34.flag = false;
wiegand66.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_remove_file(dev, &dev_attr_wiegand66);
//删除设备节点
device_unregister(dev);
//注销创建的设备类
class_destroy(class);
//取消注册设备驱动
unregister_chrdev(major, “wiegand_out”);

if (isStartGPIO == true) {
//释放注册的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(“suanzi@suanzi.ai”);

2. wiegand 输入
对应文件名wiegand_in.c
贴上代码:

#include “wiegand.h”
#include <linux/cdev.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/semaphore.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/wait.h>

#define WIEGAND_MAJOR 250
#define TIMER_DELAY HZ / 8
#define DEVICE_NAME “wiegand_in_dev”
#define DEVICE_NUM_NAME “wiegand_in”
#define DEVICE_DATA0_LABEL “wiegand_in_d0”
#define DEVICE_DATA1_LABEL “wiegand_in_d1”

#define GPIO12_4 (12 * 8 + 4)
#define GPIO12_2 (12 * 8 + 2)
#define WG_DATA0 GPIO12_4
#define WG_DATA1 GPIO12_2

static int wiegand_dev_major = WIEGAND_MAJOR;
static bool dev_open_flag = false;
static bool overflow_flag = false;
static bool isStart = false;
struct class *mem_class = NULL;

struct wiegand_dev {
char wiegand[34]; // wiegand-34
unsigned int data; // actual data
unsigned int count; // global counter
struct cdev cdev;
struct semaphore sem;
struct completion receive_completion;
struct timer_list wiegand_timer;
struct work_struct pen_event_work;
struct workqueue_struct *ts_workqueue;
int gpio_d0;
int gpio_d1;
int d0_irq;
int d1_irq;
int wiegand_gpio_num;
};
struct wiegand_dev *wiegand_in_devp = NULL;

//使能中断
static void enable_irqs(void) {
enable_irq(wiegand_in_devp->d0_irq);
enable_irq(wiegand_in_devp->d1_irq);
}

//禁止中断
static void disable_irqs(void) {
disable_irq(wiegand_in_devp->d0_irq);
disable_irq(wiegand_in_devp->d1_irq);
}

static char convert_data(void) {
int i;
int even = 0;
int odd = 0;

//偶校验
for (i = 1; i <= (wiegand_in_devp->wiegand_gpio_num - 2) / 2; i++) {
if (wiegand_in_devp->wiegand[i] == 1)
even++;
}
//偶校验不通过的情况
//偶校验:当实际数据中1的个数为偶数的时候,这个校验位就是0,否则这个校验位就是1
if (even % 2 != wiegand_in_devp->wiegand[0]) {
wiegand_in_devp->count = 0;
goto error;
}

//奇校验
for (i = (wiegand_in_devp->wiegand_gpio_num) / 2;
i <= wiegand_in_devp->wiegand_gpio_num - 2; i++) {
if (wiegand_in_devp->wiegand[i] == 1)
odd++;
}
//奇校验不通过的情况
//奇校验:当实际数据中1的个数为偶数的时候,这个校验位就是1,否则这个校验位就是0
if (odd % 2 ==
wiegand_in_devp->wiegand[wiegand_in_devp->wiegand_gpio_num - 1]) {
wiegand_in_devp->count = 0;
goto error;
}

//奇偶校验通过,将韦根转换为实际数据
wiegand_in_devp->data = 0;
for (i = 1; i <= wiegand_in_devp->wiegand_gpio_num - 2; i++) {
wiegand_in_devp->data <<= 1;
wiegand_in_devp->data |= wiegand_in_devp->wiegand[i];
}

wiegand_in_devp->count = 0;

printk(“data is: %#x\n”, wiegand_in_devp->data);

return 0;

error:
printk(“parity efficacy error\n”);
return -1;
}

static void wiegand_do_timer(unsigned long arg) {
int i = 0;

printk("%d\n", wiegand_in_devp->count);

for (i = 0; i < wiegand_in_devp->count; i++)
printk("%d “, wiegand_in_devp->wiegand[i]);
printk(”\n");

//如果不是数据位不是34(由于中断中有限制,实际上不会超过,只能小于34),则返回全F代表出错
if (wiegand_in_devp->count != wiegand_in_devp->wiegand_gpio_num) {
wiegand_in_devp->count = 0;
wiegand_in_devp->data = 0xFFFFFFFF; //全F代表出错
up(&wiegand_in_devp->sem);
overflow_flag = false;
return;
}

//关闭外部中断,防止wiegand_data在转换期间发生变化
disable_irqs();

//如果转换错误,则返回全F代表出错
if (convert_data() != 0) {
wiegand_in_devp->data = 0xFFFFFFFF; //全F代表出错
}
overflow_flag = false;
up(&wiegand_in_devp->sem);

//恢复中断
enable_irqs();
}

static irqreturn_t wiegand_irq0(int irq, void *dev_id) {
disable_irq_nosync(wiegand_in_devp->d0_irq);
udelay(5);

if (gpio_get_value(wiegand_in_devp->gpio_d0) ==
0) //必须有这句话!因为有很多噪声会导致误进入中断,但实际上并没有数据
{
if (overflow_flag == false) {
wiegand_in_devp->wiegand[wiegand_in_devp->count++] = 0;
// //调试的时候可以加上这句话,最终要封掉,中断中不要加入打印,否则影响接收数据
if (wiegand_in_devp->count == 1) {
// init_completion(&wiegand_in_devp->receive_completion);
//接收到第1位数据的时候就启动定时器,相当于设置一个超时时间
wiegand_in_devp->wiegand_timer.expires = jiffies + TIMER_DELAY;
add_timer(&wiegand_in_devp->wiegand_timer); //添加(注册)定时器
} else if (wiegand_in_devp->count > wiegand_in_devp->wiegand_gpio_num) {
overflow_flag = true;
}
}
}

enable_irq(wiegand_in_devp->d0_irq);
return IRQ_HANDLED;
}

static irqreturn_t wiegand_irq1(int irq, void *dev_id) {
disable_irq_nosync(wiegand_in_devp->d1_irq);
udelay(5);

if (gpio_get_value(wiegand_in_devp->gpio_d1) ==
0) //必须有这句话!因为有很多噪声会导致误进入中断,但实际上并没有数据
{
if (overflow_flag == false) {
wiegand_in_devp->wiegand[wiegand_in_devp->count++] = 1;
// //调试的时候可以加上这句话,最终要封掉,中断中不要加入打印,否则影响接收数据
if (wiegand_in_devp->count == 1) {
//接收到第1位数据的时候就启动定时器,相当于设置一个超时时间
wiegand_in_devp->wiegand_timer.expires = jiffies + TIMER_DELAY;
add_timer(&wiegand_in_devp->wiegand_timer); //添加(注册)定时器
} else if (wiegand_in_devp->count > wiegand_in_devp->wiegand_gpio_num) {
overflow_flag = true;
}
}
}

enable_irq(wiegand_in_devp->d1_irq);
return IRQ_HANDLED;
}

//注册中断
static int request_irqs(void) {
int ret;

if (!wiegand_in_devp)
return -1;

//映射操作的GPIO对应的中断号
wiegand_in_devp->d0_irq = gpio_to_irq(wiegand_in_devp->gpio_d0);
wiegand_in_devp->d1_irq = gpio_to_irq(wiegand_in_devp->gpio_d1);

//注册GPIO12_4(WG_DATA0)外部中断
ret = request_irq(wiegand_in_devp->d0_irq, wiegand_irq0,
IRQF_SHARED | IRQF_TRIGGER_FALLING, “wiegand_data0”,
wiegand_in_devp);
if (ret) {
printk(KERN_ERR “request wiegand_in_devp->d0_irq:%d, ret:%d failed\n”,
wiegand_in_devp->d0_irq, ret);
return -1;
}
//注册GPIO12_2(WG_DATA1)外部中断
ret = request_irq(wiegand_in_devp->d1_irq, wiegand_irq1,
IRQF_SHARED | IRQF_TRIGGER_FALLING, “wiegand_data1”,
wiegand_in_devp);
if (ret) {
printk(KERN_ERR “request wiegand_in_devp->d1_irq:%d, ret:%d failed\n”,
wiegand_in_devp->d1_irq, ret);
return -1;
}

printk(KERN_INFO “request irqs success\n”);
return 0;
}

//释放注册的中断
static void free_irqs(void) {
free_irq(wiegand_in_devp->d0_irq, wiegand_in_devp);
free_irq(wiegand_in_devp->d1_irq, wiegand_in_devp);
}

//设置相应GPIO引脚为输入
void gpio_set_input(void) {
gpio_direction_input(wiegand_in_devp->gpio_d0); //设置GPIO12_4(WG_DATA0)为输入
gpio_direction_input(wiegand_in_devp->gpio_d1); //设置GPIO12_2(WG_DATA1)为输入
}

void gpio_init(void) {
//注册要操作的GPIO编号
gpio_request(wiegand_in_devp->gpio_d0, DEVICE_DATA0_LABEL);
gpio_request(wiegand_in_devp->gpio_d1, DEVICE_DATA1_LABEL);
gpio_set_input();
}

//释放注册的GPIO编号
void gpio_deinit(void) {
gpio_free(wiegand_in_devp->gpio_d0);
gpio_free(wiegand_in_devp->gpio_d1);
}

static int wiegand_in_open(struct inode *inode, struct file *filp) {
if (dev_open_flag) {
printk(KERN_ERR “wiegand in device has beed opened\n”);
return -EBUSY;
}
return 0;
}

static int wiegand_in_close(struct inode *inode, struct file *filp) {
if (isStart == true) {
//释放注册的中断
disable_irqs();
free_irqs();

dev_open_flag = false;
overflow_flag = false;
del_timer_sync(&wiegand_in_devp->wiegand_timer);

//释放注册的GPIO编号
gpio_deinit();
isStart = false;

}
return 0;
}

static ssize_t wiegand_in_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos) {
if (isStart == false) {
sema_init(&wiegand_in_devp->sem, 0);
//注册及初始化GPIO
gpio_init();
dev_open_flag = true;
overflow_flag = false;
setup_timer(&wiegand_in_devp->wiegand_timer, wiegand_do_timer, 0);

memset(wiegand_in_devp->wiegand, 0x00, sizeof(wiegand_in_devp->wiegand));
wiegand_in_devp->count = 0;
//注册中断
request_irqs();
isStart = true;

}
#if 1
if (down_interruptible(&wiegand_in_devp->sem)) {
printk(KERN_ERR “down wiegand_in_devp->sem error\n”);
return -1;
}
#else
wiegand_in_devp->data = 10; // only for test.
#endif
printk(KERN_INFO “data:%#x\n”, wiegand_in_devp->data);
if (copy_to_user(buf, &wiegand_in_devp->data,
sizeof(wiegand_in_devp->data))) {
return 0;
}
return sizeof(wiegand_in_devp->data);
}

static ssize_t wiegand_in_write(struct file *filp, const char __user *buf,
size_t size, loff_t *ppos) {
return 0;
}

static long wiegand_out_ioctl(struct file filp, unsigned int cmd,
unsigned long arg) {
/
检查设备类型 */
if (_IOC_TYPE(cmd) != IOC_MAGIC) {
pr_err("[%s] command type [%c] error!\n", func, _IOC_TYPE(cmd));
return -ENOTTY;
}

switch (cmd) {
case IOCTL_SET_DATA0:
wiegand_in_devp->gpio_d0 = arg;
break;
case IOCTL_SET_DATA1:
wiegand_in_devp->gpio_d1 = arg;
break;
case IOCTL_SET_PROTOCOL:
wiegand_in_devp->wiegand_gpio_num = arg;
default:
return -1;
}
printk("%u,%ld\n", cmd, arg);
return 0;
}

static const struct file_operations wiegand_in_fops = {
.owner = THIS_MODULE,
.read = wiegand_in_read,
.write = wiegand_in_write,
.open = wiegand_in_open,
.release = wiegand_in_close,
.compat_ioctl = wiegand_out_ioctl,
.unlocked_ioctl = wiegand_out_ioctl,
};

//设备驱动模块加载函数
static int __init wiegand_in_init(void) {
int ret = 0;
dev_t devno = MKDEV(WIEGAND_MAJOR, 0);

printk(KERN_INFO “wiegand_in_init\n”);

if (wiegand_dev_major) //申请设备号
ret = register_chrdev_region(devno, 1, DEVICE_NUM_NAME);
else //动态申请设备号
{
ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NUM_NAME);
wiegand_dev_major = MAJOR(devno);
}
if (ret < 0) {
printk(KERN_ERR “register_chrdev_region or alloc_chrdev_region error\n”);
return ret;
}

wiegand_in_devp = kzalloc(sizeof(struct wiegand_dev), GFP_KERNEL);
if (!wiegand_in_devp) {
printk(KERN_ERR “kzalloc error\n”);
unregister_chrdev_region(devno, 1);
ret = -ENOMEM;
return ret;
}

//初始化wiegand_in_devp
wiegand_in_devp->count = 0;
cdev_init(&(wiegand_in_devp->cdev), &wiegand_in_fops);
wiegand_in_devp->cdev.owner = THIS_MODULE;
ret = cdev_add(&wiegand_in_devp->cdev, devno, 1);
if (ret) {
printk(KERN_ERR “cdev_add error\n”);
kfree(wiegand_in_devp);
wiegand_in_devp = NULL;
unregister_chrdev_region(devno, 1);
return ret;
}
wiegand_in_devp->gpio_d0 = WG_DATA0;
wiegand_in_devp->gpio_d1 = WG_DATA1;
wiegand_in_devp->wiegand_gpio_num = WIEGAND34_GPIO_NUM;

mem_class = class_create(THIS_MODULE, DEVICE_NUM_NAME);
device_create(mem_class, NULL, MKDEV(WIEGAND_MAJOR, 0), NULL, DEVICE_NAME);
return 0;
}

//设备驱动模块卸载函数
static void __exit wiegand_in_exit(void) {
printk(KERN_INFO “wiegand_in_exit\n”);

cdev_del(&wiegand_in_devp->cdev); //注销cdev
unregister_chrdev_region(MKDEV(wiegand_dev_major, 0), 1); //释放设备号

kfree(wiegand_in_devp); //释放设备结构体内存
wiegand_in_devp = NULL;
device_destroy(mem_class, MKDEV(WIEGAND_MAJOR, 0));
class_destroy(mem_class);
}

module_init(wiegand_in_init);
module_exit(wiegand_in_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“suanzi@suanzi.ai.com”);

3. makefile 文件
ifeq ($(WIEGAND_DIRECTION), IN)
obj-m:=hi3516dv300_wiegand_in.o
hi3516dv300_wiegand_in-objs := wiegand_in.o
else
obj-m:=hi3516dv300_wiegand_out.o
hi3516dv300_wiegand_out-objs := wiegand_out.o
endif

KDIR:= ( K E R N E L P A T H ) P W D : = (KERNEL_PATH) PWD:= (KERNELPATH)PWD:=(shell pwd)

default:
$(MAKE) -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules

clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *symvers *Module.markers *.mod

编译wiegand 输出命令
make ARCH=arm CROSS_COMPILE=arm-himix200-linux- WIEGAND_DIRECTION=OUT KERNEL_PATH=/home/zbx01/quface/hi3516DV300/osdrv/opensource/kernel/linux-4.9.y-smp/
编译wiegand 输入命令
make ARCH=arm CROSS_COMPILE=arm-himix200-linux- WIEGAND_DIRECTION=IN KERNEL_PATH=/home/zbx01/quface/hi3516DV300/osdrv/opensource/kernel/linux-4.9.y-smp/

注意: 内核路径是你自己本地的内核源代码路径,我当前路径为/home/zbx01/quface/hi3516DV300/osdrv/opensource/kernel/linux-4.9.y-smp/

应用层调用

1. wiegand 输出
c++ 文件wiegand_out.cpp
贴上代码:

#include “wiegand_out.hpp”
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include
#include
#include “wiegand.h”

// it is for ioctl function
#define WIEGAND_OUT_DEV “/dev/wiegand_out_dev”
// it is for wiegand data transmission.
#define WIEGAND34_OUT_DATA_DEV “/sys/devices/platform/wiegand_out/wiegand34”
#define WIEGAND26_OUT_DATA_DEV “/sys/devices/platform/wiegand_out/wiegand26”
// it is data0
#define GPIO6_2 (6 * 8 + 2)
// it is data1
#define GPIO10_6 (10 * 8 + 6)

WiegandOut *WiegandOut::get_instance() {
static WiegandOut self;
return &self;
}

int WiegandOut::send34(unsigned int data) {
char buf[12] = {0};
sprintf(buf, “%u”, data);
return write(fd34_, buf, strlen(buf) + 1);
}

int WiegandOut::send26(unsigned int data) {
char buf[12] = {0};
sprintf(buf, “%u”, data);
return write(fd26_, buf, strlen(buf) + 1);
}

WiegandOut::WiegandOut() {
set_option();
fd34_ = open(WIEGAND34_OUT_DATA_DEV, O_WRONLY);
if (fd34_ < 0) {
printf(“open wiegand out dev failed”);
return;
}

fd26_ = open(WIEGAND26_OUT_DATA_DEV, O_WRONLY);
if (fd26_ < 0) {
printf(“open wiegand out dev failed”);
return;
}
}

void WiegandOut::set_option() {
int fd = open(WIEGAND_OUT_DEV, O_WRONLY);
if (fd < 0) {
printf(“open wiegand out dev failed”);
return;
}

// don’t care whether it success or not.
ioctl(fd, IOCTL_SET_LOW_TIME, 101);
ioctl(fd, IOCTL_SET_HIGH_TIME, 1501);
ioctl(fd, IOCTL_SET_DATA1, GPIO6_2);
ioctl(fd, IOCTL_SET_DATA0, GPIO10_6);

close(fd);
}

WiegandOut::~WiegandOut() {
if (fd34_ != -1) {
close(fd34_);
fd34_ = -1;
}
if (fd26_ != -1) {
close(fd26_);
fd26_ = -1;
}
}

wiegand d0 和 d1 可以进行配置

2. wiegand 输入
文件名wiegand_in.cpp
贴上代码:

#include “wiegand_in.hpp”
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include
#include
#include “wiegand.h”

// it is for ioctl function
#define WIEGAND_IN_DEV “/dev/wiegand_in_dev”
#define WIEGAND_DATA0 (10 * 8 + 3)
#define WIEGAND_DATA1 (8 * 8 + 3)

WiegandIn *WiegandIn::get_instance() {
static WiegandIn self;
return &self;
}

int WiegandIn::recv(unsigned int &data) {
char buf[12] = {0};
if (read(fd_, buf, strlen(buf) + 1) == sizeof(data)) {
memcpy(&data, buf, sizeof(data));
}
return data;
}

WiegandIn::WiegandIn() { set_option(); }

void WiegandIn::set_option() {
fd_ = open(WIEGAND_IN_DEV, O_RDONLY);
if (fd_ < 0) {
printf(“open wiegand out dev failed”);
return;
}

// don’t care whether it success or not.
ioctl(fd_, IOCTL_SET_DATA1, WIEGAND_DATA0);
ioctl(fd_, IOCTL_SET_DATA0, WIEGAND_DATA1);
}

WiegandIn::~WiegandIn() {
if (fd_ != -1) {
close(fd_);
fd_ = -1;
}
}

wiegand 输入同样可以配置d0 和 d1 两根线,同时可以配置wiegand26 和 wiegand34, 后续有空可以优化为自动适应wiegand 协议,应用层不需要关注是wiegand26 还是 wiegand34 协议

end!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值