mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-10-31 06:03:51 +01:00 
			
		
		
		
	* Removed all CVS tags. * Removed 'const char *name' parameter from all QObject contructors.
		
			
				
	
	
		
			432 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			432 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //   rdgpio.cpp
 | |
| //
 | |
| //   A driver for General-Purpose I/O devices.
 | |
| //
 | |
| //   (C) Copyright 2002-2003,2016 Fred Gleason <fredg@paravelsystems.com>
 | |
| //
 | |
| //   This program is free software; you can redistribute it and/or modify
 | |
| //   it under the terms of the GNU Library General Public License 
 | |
| //   version 2 as published by the Free Software Foundation.
 | |
| //
 | |
| //   This program is distributed in the hope that it will be useful,
 | |
| //   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| //   GNU General Public License for more details.
 | |
| //
 | |
| //   You should have received a copy of the GNU General Public
 | |
| //   License along with this program; if not, write to the Free Software
 | |
| //   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| //
 | |
| //
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <sys/ioctl.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <qobject.h>
 | |
| 
 | |
| #include <rdgpio.h>
 | |
| 
 | |
| RDGpio::RDGpio(QObject *parent)
 | |
|   : QObject(parent)
 | |
| {
 | |
|   Clear();
 | |
| 
 | |
|   //
 | |
|   // Input Timer
 | |
|   //
 | |
|   gpio_input_timer=new QTimer(this,"input_timer");
 | |
|   connect(gpio_input_timer,SIGNAL(timeout()),this,SLOT(inputTimerData()));
 | |
|   gpio_revert_mapper=NULL;
 | |
|   for(int i=0;i<GPIO_MAX_LINES;i++) {
 | |
|     gpio_revert_timer[i]=NULL;
 | |
|   }
 | |
|   for(int i=0;i<KEY_MAX;i++) {
 | |
|     gpio_key_map[i]=-1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| QString RDGpio::device() const
 | |
| {
 | |
|   return gpio_device;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::setDevice(QString dev)
 | |
| {
 | |
|   gpio_device=dev;
 | |
| }
 | |
| 
 | |
| 
 | |
| QString RDGpio::description() const
 | |
| {
 | |
|   return gpio_description;
 | |
| }
 | |
| 
 | |
| 
 | |
| RDGpio::Mode RDGpio::mode()
 | |
| {
 | |
|   struct gpio_info info;
 | |
| 
 | |
|   switch(gpio_api) {
 | |
|       case RDGpio::ApiGpio:
 | |
| 	ioctl(gpio_fd,GPIO_GETINFO,&info);
 | |
| 	return (RDGpio::Mode)info.mode;
 | |
| 
 | |
|       case RDGpio::ApiInput:
 | |
| 	return RDGpio::Auto;
 | |
|   }
 | |
|   return RDGpio::Auto;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::setMode(RDGpio::Mode mode)
 | |
| {
 | |
|   unsigned umode=(unsigned)mode;
 | |
| 
 | |
|   switch(gpio_api) {
 | |
|       case RDGpio::ApiGpio:
 | |
| 	ioctl(gpio_fd,GPIO_SETMODE,&umode);
 | |
| 	RemapTimers();
 | |
| 	break;
 | |
| 
 | |
|       default:
 | |
| 	break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDGpio::open()
 | |
| {
 | |
|   int ver;
 | |
|   
 | |
|   if(gpio_open) {
 | |
|     return false;
 | |
|   }
 | |
|   if((gpio_fd=::open((const char *)gpio_device,O_RDONLY|O_NONBLOCK))<0) {
 | |
|     return false;
 | |
|   }
 | |
|   if(ioctl(gpio_fd,GPIO_GETINFO,&gpio_info)==0) {
 | |
|     gpio_api=RDGpio::ApiGpio;
 | |
|     InitGpio();
 | |
|     RemapTimers();
 | |
|   }
 | |
|   else {
 | |
|     if(ioctl(gpio_fd,EVIOCGVERSION,&ver)==0) {
 | |
|       gpio_api=RDGpio::ApiInput;
 | |
|       InitInput();
 | |
|     }
 | |
|     else {
 | |
|       ::close(gpio_fd);
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
|   gpio_open=true;
 | |
|   gpio_input_timer->start(GPIO_CLOCK_INTERVAL);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::close()
 | |
| {
 | |
|   if(!gpio_open) {
 | |
|     return;
 | |
|   }
 | |
|   gpio_input_timer->stop();
 | |
|   ::close(gpio_fd);
 | |
|   gpio_open=false;
 | |
|   if(gpio_revert_mapper!=NULL) {
 | |
|     delete gpio_revert_mapper;
 | |
|     gpio_revert_mapper=NULL;
 | |
|   }
 | |
|   for(int i=0;i<outputs();i++) {
 | |
|     if(gpio_revert_timer[i]!=NULL) {
 | |
|       delete gpio_revert_timer[i];
 | |
|       gpio_revert_timer[i]=NULL;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| int RDGpio::inputs() const
 | |
| {
 | |
|   if(!gpio_open) {
 | |
|     return 0;
 | |
|   }
 | |
|   return gpio_info.inputs;
 | |
| }
 | |
| 
 | |
| 
 | |
| int RDGpio::outputs() const
 | |
| {
 | |
|   if(!gpio_open) {
 | |
|     return 0;
 | |
|   }
 | |
|   return gpio_info.outputs;
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned RDGpio::inputMask()
 | |
| {
 | |
|   struct gpio_mask mask;
 | |
|   struct input_event input;
 | |
|   static unsigned input_mask=0;
 | |
| 
 | |
|   if(!gpio_open) {
 | |
|     return 0;
 | |
|   }
 | |
|   switch(gpio_api) {
 | |
|       case RDGpio::ApiGpio:
 | |
| 	memset(&mask,0,sizeof(struct gpio_mask));
 | |
| 	ioctl(gpio_fd,GPIO_GET_INPUTS,&mask);
 | |
| 	return mask.mask[0];
 | |
| 
 | |
|       case RDGpio::Input:
 | |
| 	while(read(gpio_fd,&input,sizeof(input))>0) {
 | |
| 	  if((input.type==EV_KEY)&&(gpio_key_map[input.code]>=0)) {
 | |
| 	    if(input.value==0) {
 | |
| 	      input_mask&=~(1<<gpio_key_map[input.code]);
 | |
| 	    }
 | |
| 	    else {
 | |
| 	      input_mask|=(1<<gpio_key_map[input.code]);
 | |
| 	    }
 | |
| 	  }
 | |
| 	}
 | |
| 	return input_mask;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool RDGpio::inputState(int line)
 | |
| {
 | |
|   if(!gpio_open) {
 | |
|     return false;
 | |
|   }
 | |
|   if((inputMask()&(1<<line))==0) {
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned RDGpio::outputMask() const
 | |
| {
 | |
|   struct gpio_mask mask;
 | |
| 
 | |
|   if(!gpio_open) {
 | |
|     return 0;
 | |
|   }
 | |
|   switch(gpio_api) {
 | |
|       case RDGpio::ApiGpio:
 | |
| 	memset(&mask,0,sizeof(struct gpio_mask));
 | |
| 	ioctl(gpio_fd,GPIO_GET_OUTPUTS,&mask);
 | |
| 	return mask.mask[0];
 | |
| 
 | |
|       case RDGpio::ApiInput:
 | |
| 	return 0;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::gpoSet(int line,unsigned interval)
 | |
| {
 | |
|   struct gpio_line out;
 | |
| 
 | |
|   if(!gpio_open) {
 | |
|     return;
 | |
|   }
 | |
|   switch(gpio_api) {
 | |
|       case RDGpio::ApiGpio:
 | |
| 	out.line=line;
 | |
| 	out.state=1;
 | |
| 	ioctl(gpio_fd,GPIO_SET_OUTPUT,&out);
 | |
| 	SetReversion(line,interval);
 | |
| 	break;
 | |
| 
 | |
|       case RDGpio::ApiInput:
 | |
| 	break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::gpoReset(int line,unsigned interval)
 | |
| {
 | |
|   struct gpio_line out;
 | |
| 
 | |
|   if(!gpio_open) {
 | |
|     return;
 | |
|   }
 | |
|   switch(gpio_api) {
 | |
|       case RDGpio::ApiGpio:
 | |
| 	out.line=line;
 | |
| 	out.state=0;
 | |
| 	ioctl(gpio_fd,GPIO_SET_OUTPUT,&out);
 | |
| 	SetReversion(line,interval);
 | |
| 	break;
 | |
| 
 | |
|       case RDGpio::ApiInput:
 | |
| 	break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::inputTimerData()
 | |
| {
 | |
|   unsigned input_mask;
 | |
|   unsigned output_mask;
 | |
|   unsigned mask;
 | |
| 
 | |
|   if((input_mask=inputMask())!=gpio_input_mask) {
 | |
|     for(int i=0;i<inputs();i++) {
 | |
|       mask=1<<i;
 | |
|       if((gpio_input_mask&mask)!=(input_mask&mask)) {
 | |
| 	if((input_mask&mask)==0) {
 | |
| 	  emit inputChanged(i,false);
 | |
| 	}
 | |
| 	else {
 | |
| 	  emit inputChanged(i,true);
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|     gpio_input_mask=input_mask;
 | |
|   }
 | |
|   if((output_mask=outputMask())!=gpio_output_mask) {
 | |
|     for(int i=0;i<outputs();i++) {
 | |
|       mask=1<<i;
 | |
|       if((gpio_output_mask&mask)!=(output_mask&mask)) {
 | |
| 	if((output_mask&mask)==0) {
 | |
| 	  emit outputChanged(i,false);
 | |
| 	}
 | |
| 	else {
 | |
| 	  emit outputChanged(i,true);
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|     gpio_output_mask=output_mask;
 | |
|   }
 | |
| }
 | |
|   
 | |
|   void RDGpio::revertData(int id)
 | |
| {
 | |
|   if((outputMask()&(1<<id))==0) {
 | |
|     gpoSet(id);
 | |
|   }
 | |
|   else {
 | |
|     gpoReset(id);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::RemapTimers()
 | |
| {
 | |
|   struct gpio_info info;
 | |
| 
 | |
|   //
 | |
|   // Free Old Timers
 | |
|   //
 | |
|   if(gpio_revert_mapper!=NULL) {
 | |
|     delete gpio_revert_mapper;
 | |
|     gpio_revert_mapper=NULL;
 | |
|   }
 | |
|   for(int i=0;i<gpio_info.outputs;i++) {
 | |
|     if(gpio_revert_timer[i]!=NULL) {
 | |
|       delete gpio_revert_timer[i];
 | |
|       gpio_revert_timer[i]=NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create New Timers
 | |
|   //
 | |
|   ioctl(gpio_fd,GPIO_GETINFO,&info);
 | |
|   gpio_revert_mapper=new QSignalMapper(this,"gpio_revert_mapper");
 | |
|   connect(gpio_revert_mapper,SIGNAL(mapped(int)),this,SLOT(revertData(int)));
 | |
|   for(int i=0;i<info.outputs;i++) {
 | |
|     gpio_revert_timer[i]=new QTimer(this);
 | |
|     gpio_revert_mapper->setMapping(gpio_revert_timer[i],i);
 | |
|     connect(gpio_revert_timer[i],SIGNAL(timeout()),
 | |
| 	    gpio_revert_mapper,SLOT(map()));
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::SetReversion(int line,unsigned interval)
 | |
| {
 | |
|   if(interval==0) {
 | |
|     if(gpio_revert_timer[line]->isActive()) {
 | |
|       gpio_revert_timer[line]->stop();
 | |
|     }
 | |
|     return;
 | |
|   }
 | |
|   if(gpio_revert_timer[line]->isActive()) {
 | |
|     gpio_revert_timer[line]->changeInterval(interval);
 | |
|   }
 | |
|   else {
 | |
|     gpio_revert_timer[line]->start(interval,true);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::Clear()
 | |
| {
 | |
|   gpio_open=false;
 | |
|   gpio_description="Unknown Device";
 | |
|   memset(&gpio_info,0,sizeof(struct gpio_info));
 | |
|   gpio_input_mask=0;
 | |
|   gpio_api=RDGpio::ApiGpio;
 | |
|   for(int i=0;i<KEY_MAX;i++) {
 | |
|     gpio_key_map[i]=-1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::InitGpio()
 | |
| {
 | |
|   gpio_description=gpio_info.name;
 | |
| 
 | |
|   //
 | |
|   // Enable Input Filters
 | |
|   //
 | |
|   if((gpio_info.caps&GPIO_CAP_FILTER)!=0) {
 | |
|     gpio_mask mask;
 | |
|     memset(&mask,0xFF,sizeof(struct gpio_mask));
 | |
|     ioctl(gpio_fd,GPIO_SET_FILTERS,&mask);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void RDGpio::InitInput()
 | |
| {
 | |
|   unsigned char bitmask[EV_MAX/8+1];
 | |
|   unsigned char keymask[KEY_MAX/8+1];
 | |
|   int i=0;
 | |
|   char desc[256];
 | |
| 
 | |
|   memset(&gpio_info,0,sizeof(struct gpio_info));
 | |
| 
 | |
|   if(ioctl(gpio_fd,EVIOCGNAME(256),desc)>=0) {
 | |
|     gpio_description=desc;
 | |
|   }
 | |
|   if(ioctl(gpio_fd,EVIOCGBIT(0,EV_MAX),bitmask)<0) {
 | |
|     return;
 | |
|   }
 | |
|   if((bitmask[0]&(1<<EV_KEY))==0) {
 | |
|     return;
 | |
|   }
 | |
|   ioctl(gpio_fd,EVIOCGBIT(EV_KEY,KEY_MAX),keymask);
 | |
|   while((i<KEY_MAX)&&(gpio_info.inputs<GPIO_MAX_LINES)) {
 | |
|     if((keymask[i/8]&(1<<(i%8)))!=0) {
 | |
|       gpio_key_map[i]=gpio_info.inputs++;
 | |
|     }
 | |
|     i++;
 | |
|   }
 | |
|   gpio_info.mode=RDGpio::Auto;
 | |
|   gpio_info.outputs=0;
 | |
| }
 | |
| 
 |