以下程序是结合我的驱动编写的应用层程序,双击,单击,长按都能正确识别,效果很好,不知有哪位大侠有更好的结构和算法程序?想借此抛砖引玉,也愿高手们修改指正!QQ:26451602.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include "sysconfig.h"
#include "powercontrolboard.h"
/* keyflag: bit4:y/n longkey; bit0:y/n quickkey; bit1:quickkey valid; bit5: key valid; */
/* keyflag: bit8-bit11: pressed key num:1-15 */
#define QUICKKEYbit 0
#define QUICKKEYVALbit 1
#define LONGKEYbit 4
#define KEYVALIDbit 5
volatile key_reg_t keyregdat;
pthread_t g_LedCheckThreadId;
int ledrpm_key_reg(int keyfd){
volatile int ret, key_val,keyflag=keyregdat.key_flag;
ret=read(keyfd, (char *)&key_val,sizeof(key_val));
if (ret<0){
perror("ledrpm_key_reg:read");
goto ERRRT;
}
if(ret==0)
return 0;/* 非阻塞读键盘返回0*/
printf("button%x/n",key_val);
if(key_val < 0x1000){ /* 初始值处理 */
if(key_val==keyregdat.keybuf[0]){
SETBIT(keyflag, QUICKKEYVALbit);
}else{
CLRBIT(keyflag, QUICKKEYVALbit);
keyregdat.press_holdtime=0;
keyregdat.keybuf[1]=keyregdat.keybuf[2]=0;
keyregdat.keybuf[0]=key_val;
}
}else if (key_val >= 0x2000){ /* 保持值处理 */
if(keyregdat.keybuf[0]==key_val-0x2000){
keyregdat.keybuf[1]=key_val;
keyregdat.press_holdtime++;
keyregdat.interval_time=14;
}else goto ERRRT;
}else{ /* 释放值处理 */
if(keyregdat.keybuf[0]==key_val-0x1000){ /*释放值和初始值一样 */
/* 先判断是否是长按键 */
if (keyregdat.press_holdtime>=21){
CLRALLBIT(keyflag);
SETBIT(keyflag, LONGKEYbit);
keyflag &=0xf0ff;
keyflag |= ((keyregdat.keybuf[0]&0x000f)<<8);
memset((char *)&keyregdat, 0, sizeof(key_reg_t));
keyregdat.interval_time=14;
goto RIGHTRT;
}else { /* 不是长按键 */
keyregdat.press_holdtime=0;
if (keyregdat.keybuf[2]==0){ /* 若是第一次按下,则不判断是否是双击键 */
keyregdat.keybuf[2]=key_val;
gettimeofday((struct timeval *)&(keyregdat.tv1), NULL);
keyregdat.interval_time=7;
goto RIGHTRT;
}
}
/*以下判断是否是双击键 */
if(keyregdat.keybuf[2]==key_val){ /* 第二次按下释放值一样 */
gettimeofday((struct timeval *)&(keyregdat.tv2), NULL);
ret=1000000*(keyregdat.tv2.tv_sec-keyregdat.tv1.tv_sec)+
keyregdat.tv2.tv_usec-keyregdat.tv1.tv_usec;
if(ret<1000000 && ret>0 && ISSETBIT(keyflag, QUICKKEYVALbit)){
CLRALLBIT(keyflag);
SETBIT(keyflag, QUICKKEYbit);
keyflag &=0xf0ff;
keyflag |= ((keyregdat.keybuf[0]&0x000f)<<8);
memset((char *)&keyregdat, 0, sizeof(key_reg_t));
keyregdat.interval_time=14;
}else {
CLRALLBIT(keyflag);
memset((char *)&keyregdat, 0, sizeof(key_reg_t));
keyregdat.interval_time=14;
}
}else goto ERRRT;/* 初始键值相同,不同释放值*/
}
else goto ERRRT; /* 释放值和初始值不一样,则错误 */
}
RIGHTRT:
keyregdat.key_flag=keyflag;
return 0;
ERRRT:
CLRALLBIT(keyflag);
memset((char *)&keyregdat, 0, sizeof(key_reg_t));
keyregdat.interval_time=14;
keyregdat.key_flag=keyflag;
return -1;
}
void timer1s1_handler(int signo){
if(keyregdat.interval_time <14){
if(++keyregdat.interval_time>=14){
memset((char *)&keyregdat, 0, sizeof(key_reg_t));
keyregdat.interval_time=14;
printf(" clear keyregdat!!/n");
}
}
}
void init_sigaction(void){
struct sigaction act;
act.sa_handler=timer1s1_handler;
act.sa_flags=0; //SA_ONESHOT|SA_NOMASK; /* 只能等于0,否则如后面结果是定时到一次就退出 */
sigemptyset(&act.sa_mask);
if(sigaction(SIGPROF, &act, NULL)==-1)
perror("signaction");
}
void init_time(void){
struct itimerval value;
value.it_value.tv_sec=0;
value.it_value.tv_usec=200000; /* 定时时间改小一点,这样平均误差小一点 */
value.it_interval=value.it_value;
setitimer(ITIMER_PROF, &value, NULL);
}
void * ledrpm_fun(void * pa){
int led_fd,key_fd,conf_fd,fifo_fd;
unsigned char write_value[6]={0x81,0x02,0x83,0x04,0x05,0x06};
char dataptr[12];
char * p[4];
char read_value[4]={5,5,5,5};
int i,ret,key_value;
i=key_value=0;
key_fd=open(KBDFILE,O_RDONLY|O_NONBLOCK, S_IRWXU|S_IRWXG|S_IROTH);
if(key_fd<0){
perror("cann't open device /dev/keybutton");
exit(1);
}
led_fd = open(LEDFILE, O_RDWR|O_NONBLOCK, S_IRWXU|S_IRWXG|S_IROTH);
if (led_fd < 0) {
perror("cann't open device /dev/ledrpm ");
exit(1);
}
ret = write(led_fd, write_value,4);
if (ret < 0) {
perror("first write led ");
}
conf_fd = open(CONFIGFILE, O_RDWR|O_CREAT|O_NONBLOCK, S_IRWXU|S_IRWXG|S_IROTH);
if (conf_fd < 0)
perror("cann't open config file:");
else{
i=lseek(conf_fd, 0, SEEK_SET);
if(i==-1)
perror("lseek");
if((i=read(conf_fd, dataptr, 12)) != 12 ){
perror("cann't read data to dataptr!");
printf("read num:%d /n", i);
}else{
for (i=0; i<4; i++){
p[i]=strtok((char *)(dataptr+i*3)," "); // 分割空格字符
printf("%s ", p[i]);
write_value[i]=strtoul(p[i],NULL,16); // 转成无符号整型
}
printf("/n write_value:%x,%x,%x,%x /n",write_value[0],write_value[1],write_value[2],write_value[3]);
}
}
ret = read(led_fd, read_value, 4);
if(ret==-1){
printf("init read led1-4 error!!!/n");
exit(1);
}else{
printf("init read led1:%d,led2:%d,led3:%d,led4:%d *_*/n",
read_value[0],read_value[1],read_value[2],read_value[3]);
sleep(3);
if ((ret=write(led_fd, write_value,4)) == -1)
printf("second write led return:%d /n", ret);
}
init_sigaction();
init_time();
for (;;) {
if(ledrpm_key_reg(key_fd) == -1)
perror("ledrpm_key_reg");
if(keyregdat.key_flag & 0x01){
ret=(keyregdat.key_flag&0x0f00)>>8;
printf("You pressed quick button:%d/n",ret);
if(ret>=1 && ret<=6 ){
write_value[ret-1] ^=(1<<7);
// if(write(led_fd, &write_value[ret-1],1)==-1)
if(ioctl(led_fd, write_value[ret-1],1)==-1)
printf(" write led%d error!!!/n",ret);
else{
printf(" write led%d successful*_* /n",ret);
fifo_fd=0;
/* if(fifo_fd=open(RPM_FIFO,O_WRONLY|O_NONBLOCK,0755) < 0)
perror("fifo write open");
if(write(fifo_fd,&write_value[ret-1],1)<0 && errno != ENXIO)
perror("fifo write");
else printf("write fifo:0x%x success/n",write_value[ret-1]);
close(fifo_fd); */
}
keyregdat.key_to_sw=write_value[ret-1];
g_PowerControlBoard.Start();
sleep(1);
g_PowerControlBoard.Pause();
}
keyregdat.key_flag=0;
}else if(keyregdat.key_flag & 0x10){
ret=(keyregdat.key_flag&0x0f00)>>8;
printf("You pressed long button:%d/n",ret);
keyregdat.key_flag=0;
}
}
close(conf_fd);
close(led_fd);
close(key_fd);
return 0;
}
int main(int argc, char** argv){
/* if((mkfifo(RPM_FIFO,O_CREAT|O_EXCL|O_NONBLOCK)<0)&&(errno!=EEXIST))
printf("cannot create fifoserver/n");
if(errno!=EEXIST)
printf("/ncreat:%s successful!/n",RPM_FIFO); */
g_PowerControlBoard.InitComPort(COM1, B9600);
g_PowerControlBoard.Pause(); /*电源控制板串口通讯线程开始*/
/*LED检测线程,根据LED状态控制电源状态*/
pthread_create((pthread_t *)&g_LedCheckThreadId, NULL, ledrpm_fun, NULL);
while (true)
{
sleep(1000);
}
if(unlink(RPM_FIFO)==-1)
perror("unlink RPM_FIFO");
return 1;
}