125KHZ RFID 曼彻斯特码在内核域解码

2024-02-24 06:40

本文主要是介绍125KHZ RFID 曼彻斯特码在内核域解码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一. 曼彻斯特码理论分析:
曼彻斯特码编码的ID卡每次输出64bit 数据/8个字节,其载波编码为曼彻斯特码.
其时序图如下:
在这里插入图片描述
曼彻斯特码调制方式下,EM4100卡片每传送一位数据的时间是64个振荡周期。125KHZ载波时,卡片传送一bit数据理论频率为125KHz / 64 = 1.953125KHz。那么得到一个周期为:1 000 000us / 1.953125KHz = 512us。

也就是说:曼彻斯特码一个完整的数据跳变为一个周期(512us)。
但是特别需要注意的是:存在空跳则半个跳变为半个周期(256us)。

那么如何得到一个bit的数据呢?

如果捕获到一个电平变化,这个电平距离上次检测到电平变化时间为512us,则该位按以下读取:低电平-bit = 1,高电平-bit = 0;如果捕获到一个电平变化,这个电平距离上次检测到电平变化时间256us,则此次不作判断,再次捕获到一个边沿时再判断如下:上次bit = 1 此次bit = 1,上次bit = 0,此次bit = 0.
此处有一个特别注意的地方,如果上次读取到256us,不管这次读取间隔是256us还是512us,都应该读取上一次的电平,并且重新检测跳包。

二.设备树配置:
配置设备树节点,用于内核驱动程序找到对应能检波的IO口。在anyka v300 平台如下:

编辑:anycloud_ak39ev330_common.dtsi
添加节点:在 gpiokeys: gpiokeys {
compatible = "anyka,ak39ev330-gpiokeys";status = "disable";};附近添加以下节点信息:rfid_control: rfid_control {compatible = "leo_rfid_control";status = "disable";};编辑:C500_SQ38_AK3918EV330_GC2063_MIPI_V1.0.0.dts:在"$gpio" 节点内部添加rfid_pins:rfid_pins{anyka,pins = <0>;anyka,function = <0>;anyka,pull = <0x00000001>;};然后退出$gpio节点,使能“rfid_control”节点,如下:&rfid_control{gpios = <&gpio 0 1>;pinctrl-names ="default";pinctrl-0 = <&rfid_pins>;status = "okay";};

好了,完成了设备树信息的编写,

第二部:接下来开始写驱动内核程序。
整个代码如下:

#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm/current.h>
#include <linux/kthread.h>
#include <linux/delay.h>#define diff_us(t1,t2) ((u64)t1.tv_sec - (u64)t2.tv_sec) * 1000000 + ((u64)t1.tv_usec - (u64)t2.tv_usec);#define rfid_code_bit_value(data,index) ((data[(index)/8] >> (7 - (index)%8))&0x01)
/* 主设备号 */
static int major = 0;
/* 创建设备类的结构体 */
static struct class* rfid_class;
/* 记录设备树信息的结构体*/
static int rfid_gpio_index;static struct task_struct *rfid_kthread;   static char rfid_data_code[16] = {0};
static int rfid_data_count = 0;static char rfid_code_number[4] = {0};
static char rfid_code_number_ready = 0;static DEFINE_MUTEX(rfid_code_mutex);static ssize_t rfid_read(struct file* file,char __user*buf,size_t size,loff_t* offset){int len  = 0;if(size < 4){return 0;}len = sizeof(rfid_code_number);//printk("read rfid value \n");	mutex_lock(&rfid_code_mutex);if(rfid_code_number_ready == 0){mutex_unlock(&rfid_code_mutex);return 0;}copy_to_user(buf, rfid_code_number , len); rfid_code_number_ready = 0;mutex_unlock(&rfid_code_mutex);return len;
}
/* 创建设备方法 */
static struct file_operations rfid_control_fops = {.owner = THIS_MODULE,.read = rfid_read,
};static int rfid_code_leave_wait(int* level,int min,int middle,int max,struct timeval* pre_tv){u64 us = 0;struct timeval tv;int cur_level = gpio_get_value(rfid_gpio_index) ;while(gpio_get_value(rfid_gpio_index) == cur_level){do_gettimeofday(&tv);us = diff_us(tv,(*pre_tv));if(us > max){return -1;}}do_gettimeofday(&tv);us = diff_us(tv,(*pre_tv));*level = cur_level?0:1;if(us < min){return -1;}else if((us > min)&&(us < middle)){return 0;}return 1;
}static char rfid_code_jump_flg = 0;static int rfid_code_read_proc(void){int i = 0;int reslut = 0;int level = 0;struct timeval tv;unsigned char value = 0;memset(rfid_data_code,0,sizeof(rfid_data_code));rfid_data_count = 0;rfid_code_jump_flg = 0;do_gettimeofday(&tv);while(1){reslut = rfid_code_leave_wait(&level,125,375,625,&tv);do_gettimeofday(&tv);if((reslut == 0)&&(rfid_code_jump_flg == 0)){rfid_code_jump_flg = 1;}else if((reslut == 1)||((reslut == 0)&&(rfid_code_jump_flg == 1))){if(rfid_code_jump_flg == 1){value = ((rfid_data_code[(rfid_data_count - 1) / 8] >> (7 - (rfid_data_count - 1) % 8)) & 0x01) ? 1 : 0;}else{value = level?0:1;}rfid_code_jump_flg = 0;rfid_data_code[rfid_data_count / 8] |= (value << (7 - rfid_data_count % 8));rfid_data_count++;if(rfid_data_count >= 128){return 1;}}else if(reslut < 0){return -1;}}return 0;
}static int rfid_code_data_check(void){int index = 0,i = 0,j = 0,n = 0;int value = 0;for(index = 0; index < 64 ; index++){value = 0;for(i = 0 ; i < 9 ; i++){value <<= 1;value |= rfid_code_bit_value(rfid_data_code,index + i);//printk("%d",rfid_code_bit_value(rfid_data_code,index + i));}if(value == 0x1FF){index += 9;break;}}if(index == 64){printk("check rfid data failed (%s,%d)\n",__func__,__LINE__);return -1;}for(i = index; i < (index + 45) ; i+=5){value = 0;for( j = 0 ;j < 4 ; j++){value += rfid_code_bit_value(rfid_data_code,i + j);}if((value %2) != rfid_code_bit_value(rfid_data_code,i + j)){printk("check rfid data failed (%s,%d)\n",__func__,__LINE__);return -1;}}for( i = index; i < (index + 4) ; i++){value = 0;for( j = 0 ; j < 50 ; j+= 5){value += rfid_code_bit_value(rfid_data_code,i + j);}if((value %2) != rfid_code_bit_value(rfid_data_code,i + j)){printk("check rfid data failed (%s,%d)\n",__func__,__LINE__);return -1;}}if(rfid_code_bit_value(rfid_data_code,index + 54) != 0){printk("stop failed \n");return -1;}n = 0;mutex_lock(&rfid_code_mutex);rfid_code_number_ready = 0;mutex_unlock(&rfid_code_mutex);memset(rfid_code_number,0,sizeof(rfid_code_number));for(i = index + 10 ; i < (index + 50) ; i+=10){value = 0;for( j = 0 ; j < 9; j++){if(j == 4){continue;}value <<= 1;value |= rfid_code_bit_value(rfid_data_code,i+j);}rfid_code_number[n++] = value;//printk("%02x ",value);}//printk("\n");mutex_lock(&rfid_code_mutex);rfid_code_number_ready = 1;mutex_unlock(&rfid_code_mutex);return 1;
}static int k_rfid_task(void*data){int pre_level = gpio_get_value(rfid_gpio_index);int cur_level = pre_level;char det_start_flag = 0;printk("leo:kernel rfid card task success! \n");while(1){if(kthread_should_stop()){break;}if(det_start_flag == 0){cur_level = gpio_get_value(rfid_gpio_index);if(cur_level == 0){det_start_flag = 1;pre_level = cur_level;}else{msleep(100);}}else{if(rfid_code_read_proc() == 1){//printk("check data \n");rfid_code_data_check();	}gpio_set_value(rfid_gpio_index,1);pre_level = gpio_get_value(rfid_gpio_index);det_start_flag = 0;msleep(10);}}return 0;
}static int rfid_probe(struct platform_device*pdev){int irq;struct device_node *np = pdev->dev.of_node;printk("leo:rfid probe success \n");rfid_gpio_index = of_get_named_gpio(np, "gpios", 0);if(rfid_gpio_index < 0){printk("rfid gpio setting failed\n");}else{printk("rfid setting gpio%d\n",rfid_gpio_index);}device_create(rfid_class,NULL,MKDEV(major,0),NULL,"rfid_control");gpio_direction_output(rfid_gpio_index,1);msleep(100);gpio_direction_input(rfid_gpio_index);mutex_init(&rfid_code_mutex);rfid_kthread = kthread_create(k_rfid_task,NULL,"rfid_kthread");if(IS_ERR(rfid_kthread)){printk("create rfid_kthread faield\n");return 0;}wake_up_process(rfid_kthread);return 0;	
}static int rfid_remove(struct platform_device*pdev)
{int irq;printk("leo:rfid driver remove\n");kthread_stop(rfid_kthread);device_destroy(rfid_class,MKDEV(major,0));return 0;
}static const struct of_device_id rfid_board_control[]={{.compatible = "leo_rfid_control"},{}
};static struct platform_driver rfid_platform_drv = {.probe = rfid_probe,.remove = rfid_remove,.driver = {.name = "rfid_control",.of_match_table = rfid_board_control,},
};static int __init rfid_drv_init(void){printk("leo:rfid drv init start\n");//注册主字符设备号major = register_chrdev(0,"rfid_control",&rfid_control_fops);//创建设备类rfid_class = class_create(THIS_MODULE,"rfid_class");if(IS_ERR(rfid_class)){printk("rfid class create failed\n");unregister_chrdev(major,"rfid_control");return PTR_ERR(rfid_class);}return platform_driver_register(&rfid_platform_drv);
}static void __exit rfid_drv_exit(void){platform_driver_unregister(&rfid_platform_drv);class_destroy(rfid_class);unregister_chrdev(major,"rfid_control");
}/*
* ko创建
*/
module_init(rfid_drv_init);
module_exit(rfid_drv_exit);MODULE_LICENSE("GPL");

生成rfid.ko之后,上次insom rfid.ko,完成内核模块的安装。
第三步:应用层的编写:
整体代码如下:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>#define RFID_DEVICE_PATH "/dev/rfid_control"int main(int argc,char** argv){if(access(RFID_DEVICE_PATH,F_OK) != 0){printf("%s not exit\n",RFID_DEVICE_PATH);return 0;}int fd = open(RFID_DEVICE_PATH,O_RDONLY);if(fd < 0 ){printf("open %s failed \n",RFID_DEVICE_PATH);return 0;}unsigned char data[4] = {0};while(1){if(read(fd,data,sizeof(data)) == 4){printf("%02x%02x%02x%02x\n",data[0],data[1],data[2],data[3]);}usleep(1000*10);}return 0;
}

这篇关于125KHZ RFID 曼彻斯特码在内核域解码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741254

相关文章

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

Ubuntu22.04回退系统内核

文章目录 起因回退操作卸载内核禁止内核升级 起因 最近因为系统内核自动升级,导致显卡驱动检测不到,炼丹环境被破坏。无奈只能重装驱动,于是跟着手册操作发现驱动要求的是内核版本是5.15.0-25-generic,而我通过uname -r发现这时候的内核版本是6.8.0-40-generic,看来只能回退了。 我搜索了网上很多的文章,没有一篇文章能够完全解决这个问题,所以在我多次尝

跟我一起玩《linux内核设计的艺术》第1章(四)——from setup.s to head.s,这回一定让main滚出来!(已解封)

看到书上1.3的大标题,以为马上就要见着main了,其实啊,还早着呢,光看setup.s和head.s的代码量就知道,跟bootsect.s没有可比性,真多……这确实需要包括我在内的大家多一些耐心,相信见着main后,大家的信心和干劲会上一个台阶,加油! 既然上篇已经玩转gdb,接下来的讲解肯定是边调试边分析书上的内容,纯理论讲解其实我并不在行。 setup.s: 目标:争取把setup.

编译linux内核出现 arm-eabi-gcc: error: : No such file or directory

external/e2fsprogs/lib/ext2fs/tdb.c:673:29: warning: comparison between : In function 'max2165_set_params': -。。。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。 。。。。。。。。 host asm: libdvm <= dalvik/vm/mterp/out/Inte

FFmpeg系列-视频解码后保存帧图片为ppm

在正常开发中遇到花屏时怎么处理呢?可以把解码后的数据直接保存成帧图片保存起来,然后直接看图片有没有花屏来排除是否是显示的问题,如果花屏,则代表显示无问题,如果图片中没有花屏,则可以往显示的方向去排查了。 void saveFrame(AVFrame* pFrame, int width, int height, int iFrame){FILE *pFile;char szFilename[

linux 内核提权总结(demo+exp分析) -- 任意读写(四)

hijack_modprobe_path篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     原理同hijack_prctl, 当用户执行错误格式的elf文件时内核调用call_usermod

linux 内核提权总结(demo+exp分析) -- 任意读写(三)

hijack_prctl篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   prctl函数: 用户态函数,可用于定制进程参数,非常适合和内核进行交互 用户态执行prctl函数后触发prctl系统

linux 内核提权总结(demo+exp分析) -- 任意读写(二)

hijack_vdso篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     vdso: 内核实现的一个动态库,存在于内核,然后映射到用户态空间,可由用户态直接调用 内核中的vdso如果被修改