mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-11-04 08:04:12 +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;
 | 
						|
}
 | 
						|
 |