openwrt按键检测驱动修改——实现连续三次按键检测

背景

目前公司一个产品要实现:一个带按键手咪同时要两种功能,连续三次按键呼sip电话,正常按下使用ptt对讲功能,为此要区分按键的方式从而触发不同功能。
驱动框架和关键结构体的可以参考这个老哥,还算比较详细,推荐:https://blog.csdn.net/wind0419/article/details/120270021

驱动位置:$(TOP_DIR)/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c

按键功能实现脚本

按键功能实现的脚本位置:package/base-files/files/etc/rc.button/ptt。主要有几个参数, ACTION和SEEN,分别代表按键动作(按下/抬起)和上次按键到本次按键按下之间的时间。另外PRESSED_TIMES代表连续三次按键按下,pressed代表按键按下,released代表按键松开

. /lib/functions.sh
if [ "$PRESSED_TIMES" -eq 1 ] 
then
    echo "AUDIO:3times" > dev/console
    cat /www/ptt_backdial| while read line
        do  
        #echo -e $line > dev/console
        if [ "$line" = "0" ]
        then
#           echo "status = 1 call" > dev/console
            echo "1" >/www/ptt_backdial
        else
#           echo "status = 0 hang up" > dev/console
            echo "0" >/www/ptt_backdial
            fi  
    done
    sync
fi

if [ "$THREE_RELEASED" -eq 1 ] 
then
#   echo "AUDIO:3times Released" > dev/console
    echo "0" > /script/ptt_push
    sync
fi

if [ "${ACTION}" = "pressed" ] ; then
#   aplay /lib/signal-audio/ptt_waring.wav
#   echo "AUDIO-PTT:pressed" > dev/console
#   sync
    echo "1" > /script/ptt_push
    aplay /lib/signal-audio/ptt_waring.wav
fi

if [ "${ACTION}" = "released" ] ; then
    echo "0" > /script/ptt_push
#   echo "AUDIO-PTT:released" > dev/console                                                                                                                                                                 
    exit 0
fi

return 0

驱动分析

1、button_hotplug_fill_event能够一直读取按键状态,并将状态通知到用户空间,消息封装完毕后使用netlink将消息发送到应用层,例如:bh_event_add_var(event, 0, “ACTION=%s”, event->action),会向应用层传递的变量为ACTION,该变量的值为event->action。

162 static int button_hotplug_fill_event(struct bh_event *event)
163 {
164     int ret;
165 
166     ret = bh_event_add_var(event, 0, "HOME=%s", "/");
167     if (ret)
168         return ret;
169 
170     ret = bh_event_add_var(event, 0, "PATH=%s",
171                     "/sbin:/bin:/usr/sbin:/usr/bin");
172     if (ret)
173         return ret;
174 
175     ret = bh_event_add_var(event, 0, "SUBSYSTEM=%s", "button");
176     if (ret)
177         return ret;
178 
179     ret = bh_event_add_var(event, 0, "ACTION=%s", event->action);
180     if (ret)
181         return ret;
182 
183     ret = bh_event_add_var(event, 0, "BUTTON=%s", event->name);
184     if (ret)
185         return ret;
186 
187     if (event->type == EV_SW) {
188         ret = bh_event_add_var(event, 0, "TYPE=%s", "switch");
189         if (ret)
190             return ret;
191     }
192 /******将三次按键是否触发的变量的PRESSED_TIMES和THREE_RELEASED的值传递给应用层******/
197 #if ENABLE_AUDIO
198     ret = bh_event_add_var(event, 0, "PRESSED_TIMES=%d", event->times_flag);
199     if (ret)
200         return ret;
201 
202     ret = bh_event_add_var(event, 0, "THREE_RELEASED=%d", event->released_flag);
203     if (ret)
204         return ret;
205 #endif
206 
207     ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
208 
209     return ret;
210 }           

2、具体事件上报位于button_hotplug_create_event,判断如果是按下pressed事件,会额外检查是否是已经连续按了两次,根据check_ptt_button_pressed函数的返回值确定给times_flag和released_flag赋值,当这两个变量值为真(1)时候,button_hotplug_fill_event向应用层传递的值中就会包含PRESSED_TIMES和THREE_RELEASED的值,这两个值一一对应

240 
241 static int button_hotplug_create_event(const char *name, unsigned int type,
242         unsigned long seen, int pressed)
243 {
244     struct bh_event *event;
245 
246     //printk("~~~~~~~~~~~seen - dbata_seen = %ld~~~~~~~~~~~\n", seen);
247     pr_debug(PFX "create event, name=%s, seen=%lu, pressed=%d\n",
248          name, seen, pressed);
249 
250     event = kzalloc(sizeof(*event), GFP_KERNEL);
251     if (!event)
252         return -ENOMEM;
253 
254     event->name = name;
255     event->type = type;
256     event->seen = seen;
257     event->action = pressed ? "pressed" : "released";
258
259 #if ENABLE_AUDIO
260     if (! strcmp(event->action, "pressed")) {
261         if (check_ptt_button_pressed(event)) {
262             event->times_flag = 1;
263             connect_flag = 1;
264         } else {
265             event->times_flag = 0;
266         }
267     }
268 
269     if (! strcmp(event->action, "released")) {
270         if (connect_flag) {
271             event->released_flag = 1;
272             connect_flag = 0;
273         } else {
274             event->released_flag = 0;                                                                                                                                                                   
275         }
276     }
277 #endif
278 
279     INIT_WORK(&event->work, (void *)(void *)button_hotplug_work);
280     schedule_work(&event->work);
281 
282     return 0;
283 }

3、其中check_ptt_button_pressed函数就是为了检测是否是三次连续按下,实现如下:

144 #if ENABLE_AUDIO
145 static int check_ptt_button_pressed(struct bh_event *event)
146 {
147     //printk("\n--> seen = %ld -->\n", event->seen);
	/******由于HZ=100,也就是时钟节拍数每增加100等于1秒,而按键据上次按键时间这个参数seen由事件触发函数   button_hotplug_create_event传递而来,根据实际测试结果当连续按键时间小于30的节拍数就会累加pressed_time******/
148     if (event->seen < 30) {
149         ++pressed_time;
150     } else {
151         //printk("--> gpio_keys_button_dev --> pressed_time = %d , seen = %ld,action = %s\n", pressed_time, event->seen, event->action);
152         pressed_time = 0;
153     }
154     if (pressed_time == 2) {
155         pressed_time = 0;
156         return 1;
157     }
158     return 0;
159 }
160 #endif

4、主要是修改了gpip-button驱动中按键按下时间seen的检测,原先是按秒来计数,内核时钟节拍数unsigned long类型数据整除HZ以后对于0-2之间的秒数都当作1s对待,而根据测试反馈三次按键之间时间太长,所以直接根据系统当前时间节拍数与上次按键时候记录的时间节拍数之差比较,目前定的差值在30,差不多在30/100秒,在现有按键的物理机械特性下还是能和正常按下区别开:

310 static void gpio_keys_handle_button(struct gpio_keys_button_data *bdata)
311 {
312     unsigned int type = bdata->b->type ?: EV_KEY;
313     int state = gpio_button_get_value(bdata);
314     unsigned long seen = jiffies;
315 
316     pr_debug(PFX "event type=%u, code=%u, pressed=%d\n",
317          type, bdata->b->code, state);
318 
319     /* is this the initialization state? */
320     if (bdata->last_state == -1) {
321         /*
322          * Don't advertise unpressed buttons on initialization.
323          * Just save their state and continue otherwise this
324          * can cause OpenWrt to enter failsafe.
325          */
326         if (type == EV_KEY && state == 0)
327             goto set_state;
328         /*
329          * But we are very interested in pressed buttons and
330          * initial switch state. These will be reported to
331          * userland.
332          */
333     } else if (bdata->last_state == state) {
334         /* reset asserted counter (only relevant for polled keys) */
335         bdata->count = 0;
336         return;
337     }
338 
339     if (bdata->count < bdata->threshold) {
340         bdata->count++;
341         return;
342     }
343 
344     if (bdata->seen == 0)
345         bdata->seen = seen;
346 
347     //button_hotplug_create_event(button_map[bdata->map_entry].name, type,
348     //              (seen - bdata->seen) / HZ, state);
        /****** 其中可以根据 (seen - bdata->seen) / HZ就可以计算出按键时间,而我需要更加精确的时间,
        所以秒数对我来说无法满足应用场景,所以更改为了时钟节拍数差。这个时钟节拍数差值就是为了提高按键
        的使用手感 ******/
349 #if ENABLE_AUDIO 
350     button_hotplug_create_event(button_map[bdata->map_entry].name, type,
351                     (seen - bdata->seen), state);
352     bdata->seen = seen;
353 #endif                                                                                                                                                                                                                                                            
354 set_state:
355     bdata->last_state = state;
356     bdata->count = 0;
357 }
358 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值