29、基于Firefly-Rk3399信号signal异步通知

一、流程

1、概述:应用层启用signal功能->将PID传递给驱动层->获取FASYNC状态并使能它 驱动层文件操作结构体创建fasync函数并通过fasync_helper监测FASYNC状态变化绑定到PID上,中断来临后kill_fasync将signal发送到绑定的PID上。

2、 (1)打开设备文件

open

​ (2)app启用异步通知功能

signal(SIGIO, func);

​ (3)app告诉kernel他的PID(内核记录PID)

app:
	fcntl(fd, F_SETOWN, getpid());
kernel:
	记录PID

​ (4)获取文件标记位,设置flag(FASYNC),驱动调用 kill_fasync(PID, SIGIO)

app:
	Oflags = fcntl(fd, F_GETFL);
	fcntl(fd, F_SETFL, Oflags | FASYNC)  FASYNC : 启动FASYNC功能(若要禁止FASYNC,只需要将FASYNC位清零);
kernel:
	检测FASYNC变化
	fasync_helper(fd, filp, on, &button_async);
	on = FASYNC = 1 :  button_async->fa_file = filp(含有PID);
				 0 :  button_async->fa_file = NULL;

​ (5)app做其他任务

​ (6)按键按下–>调用了按键中断程序–>记录KEY值, 将信号发出

key_fasync(&button_async, SIGIO, POLL_IN);
判断:如果button_async->fa_file非空,取出里面的PID发送信号

​ (7)func被调用

​ (8)read

二、函数分析

1、signal用法:

kill -l 查询当前系统中已经定义的信号

信号特点默认对进程的处理方式
SIGKILL当产生之后让一个进程结束,不可忽略,也不可捕捉,只能默认结束进程
SIGSTOP当产生之后让一个运行的进程停止运行,不可忽略,也不可捕捉,只能默认停止进程
SIGINT当使用快捷键ctrl c会产生这个信号结束进程
SIGTSTP当使用快捷键ctrl z会产生这个信号停止进程
SIGQUIT当使用快捷键ctrl \会产生这个信号结束进程
SIGPIPE管道破裂无名管道只有写端没有读端时,执行写操作会产生这个信号有名管道一个进程只读,一个进程只写,当关闭读操作,写操作执行时会产生这个信号结束进程
SIGCONT让停止的进程恢复执行让停止的进程恢复执行
SIGALRM当调用alarm函数设定的时间到达时,会产生这个信号结束进程
SIGCHLD当子进程结束时,父进程中会产生这个信号忽略
SIGUSR1用户自定义信号忽略
SIGUSR2用户自定义信号忽略
kill  -值  进程号     向一个进程发送一个信号
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:当信号产生后设置进程的处理方式
参数:
    signum:信号
    handler:信号的处理方式
         SIG_DFL 以默认的方式处理
         SIG_IGN 以忽略的方式处理
        handler 以捕捉的方式,也就是通过信号处理函数执行
            void handler(int sig)
            {
            }
返回值:
    成功:当前信号原本默认的处理方式
2、fcntl用法
#include <fcntl.h>
#include <unistd.h>
int fcntl(int fd, int cmd, ... /* arg */ );

fd:文件描述符。

cmd:操作命令,用于指定 fcntl 的功能。

arg:根据 cmd 的不同可能需要传入不同的参数,或可以忽略

fcntl(fd, F_SETWN, getpid());

Oflags = fcntl(fd, F_GETFL);

fcntl(fd, F_SETFL, Oflags | FASYNC)

3、fasync
static int drv_fasync (int fd, struct file *filp, int on);
4、fasync_helper
int fasync_helper(int fd, struct file *filp, int on, struct fasync_struct **fapp);

fd

  • 文件描述符,由用户空间传递,用于区分不同的文件。

filp

  • 指向文件结构体的指针(struct file *),表示对设备文件的操作。

on

  • 一个布尔值,决定是启用还是禁用

    FASYNC
    

    功能:

    • 非零值:启用 FASYNC
    • 零值:禁用 FASYNC

fapp

  • 指向 struct fasync_struct * 的指针,用于存储异步通知相关的信息。

  • 成功时返回 0

  • 失败时返回负的错误码,例如:

    • -ENOMEM:内存分配失败。
5、kill_fasync
void kill_fasync(struct fasync_struct **fa, int sig, int band);

fa

  • 指向 struct fasync_struct 的指针,表示异步通知队列。

sig

  • 要发送的信号,通常是 SIGIO(表示异步 I/O 可用)或 SIGURG(表示紧急数据可用)。

band

  • 一个标志,用于指示事件的类型,例如:
    • POLL_IN:有数据可读。
    • POLL_OUT:可以写数据。
    • POLL_ERR:发生错误。

三、修改应用层程序

#include <stdio.h>
#include <poll.h>
#include <fcntl.h>      // open 函数及文件标志
#include <sys/stat.h>   // 文件权限
#include <unistd.h>     // 文件操作(如 close, read, write 等)
#include <signal.h>

static int fd;

void sighandle_func(int sig) {
    int buf = 0;
    int gpio = 0;
    int level = 0;
    int bank = 0;
    char group = 0;
    int number = 0;
    printf("调用了信号函数 fd  =  %d\n", fd);
    read(fd, &buf, 1);
    printf("读出来数据了\n");
    gpio = buf & 0x00ff;
    bank = gpio / 32;
    group = ((gpio % 32) / 8) + 'A';
    number = gpio % 8;
    buf = (buf >> 8) & 0xff;
    printf("Received gpio%d_%c%d value:%d\n", bank, group, number, buf);
}

int main() {
    int timeout = 5000;
    int Oflags;
    int buf;

    fd = open("/dev/diy_key_double", O_RDWR);
    if(fd == -1) {
        perror("open");
        return -1;
    }
    printf("按键设备文件为%d\n", fd);
    /*传入PID*/
    fcntl(fd, F_SETOWN, getpid());
    /* 获取状态标志 */
    Oflags = fcntl(fd, F_GETFL);
    /* 修改并设置状态标志 */
    fcntl(fd, F_SETFL, Oflags | FASYNC);
    /* 设置信号处理函数 */
    signal(SIGIO, sighandle_func);
    while(1) {
        read(fd, &buf, 1);
        printf("wait for signal fd = %d\n", fd);
        sleep(2);
    }

    return 0;
}

四、修改驱动层程序

static struct fasync_struct *key_async;
static int key_fasync(int fd, struct file *file, int on)
{
	return fasync_helper(fd, file, on, &key_async;);
}
const struct file_operations key_fops = {
	.owner = THIS_MODULE,
	.open = key_open,	
	.release = key_release,	
	.read = key_read,	
	.write = key_write,
     .poll = key_poll,
	.fasync = key_fasync,
};
kill_fasync(&key_async, SIGIO, POLL_IN); 
/*	第 1 个参数:button_async->fa_file 非空时,可以从中得到 PID,表示发给哪一个 APP;
    第 2 个参数表示发什么信号:SIGIO;
    第 3 个参数表示为什么发信号:POLL_IN,有数据可以读了。(APP 用不到这个参数)*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值