Commit 73404038 authored by Sergi Hernandez's avatar Sergi Hernandez
Browse files

Some improvements on the original implementation.

parent 4703fd74
Pipeline #101 skipped
......@@ -9,11 +9,13 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
CGPIO::CGPIO(gpio_ports port,int pin)
{
int fp;
std::stringstream text;
struct stat sb;
std::stringstream text,gpio_file;
/* try to export the desired pin */
if((fp=open("/sys/class/gpio/export",O_WRONLY))==-1)
......@@ -31,12 +33,17 @@ CGPIO::CGPIO(gpio_ports port,int pin)
throw CGPIOException(_HERE_,"Invalid pin identifier");
}
this->gpio_id=(int)port+pin;
text << this->gpio_id;
if(write(fp,text.str().c_str(),text.str().size())!=(int)text.str().size())
gpio_file << "/sys/class/gpio/gpio" << this->gpio_id;
/* check if the file already exists */
if(stat(gpio_file.str().c_str(),&sb)!=0)
{
/* handle exceptions */
close(fp);
throw CGPIOException(_HERE_,"Error while writing to the export file");
text << this->gpio_id;
if(write(fp,text.str().c_str(),text.str().size())!=(int)text.str().size())
{
/* handle exceptions */
close(fp);
throw CGPIOException(_HERE_,"Error while writing to the export file");
}
}
// close the export file
close(fp);
......@@ -55,9 +62,6 @@ CGPIO::CGPIO(gpio_ports port,int pin)
this->thread_server->create_thread(this->edge_thread_id);
this->thread_server->attach_thread(this->edge_thread_id,this->edge_thread,this);
this->input_fd=-1;
// wait for the pin to be available
sleep(1);
}
void *CGPIO::edge_thread(void *param)
......@@ -110,10 +114,13 @@ void *CGPIO::edge_thread(void *param)
void CGPIO::set_direction(dir_t direction)
{
int fp;
struct stat sb;
std::stringstream text;
//Open the GPIO's sysfs file for writing
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/direction";
//Open the GPIO's sysfs file for writing
while(stat(text.str().c_str(),&sb)!=0 || (sb.st_mode&(S_IWUSR | S_IWGRP))!=(S_IWUSR | S_IWGRP))
usleep(100000);
if((fp=open(text.str().c_str(), O_WRONLY)) == -1)
{
/* handle exceptions */
......@@ -153,12 +160,15 @@ void CGPIO::set_direction(dir_t direction)
void CGPIO::set_value(bool value)
{
int fp;
struct stat sb;
std::stringstream text;
if(this->direction==output)
{
//Open the GPIO's sysfs file for reading and writing
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/value";
while(stat(text.str().c_str(),&sb)!=0 || (sb.st_mode&(S_IWUSR | S_IWGRP))!=(S_IWUSR | S_IWGRP))
usleep(100000);
if((fp=open(text.str().c_str(),O_RDWR)) == -1)
{
/* handle exceptions */
......@@ -183,79 +193,123 @@ void CGPIO::set_value(bool value)
bool CGPIO::get_value(void)
{
int fp;
struct stat sb;
unsigned char value;
std::stringstream text;
if(this->direction==input)
{
//Open the GPIO's sysfs file for reading and writing
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/value";
while(stat(text.str().c_str(),&sb)!=0 || (sb.st_mode&(S_IWUSR | S_IWGRP))!=(S_IWUSR | S_IWGRP))
usleep(100000);
if((fp=open(text.str().c_str(),O_RDWR)) == -1)
{
/* handle exceptions */
throw CGPIOException(_HERE_,"Impossible to open the value file");
}
//Set pointer to begining of the file
lseek(fp,0,SEEK_SET);
if(read(fp,&value,1)!=1)
{
close(fp);
throw CGPIOException(_HERE_,"Error while writing to the value file");
}
close(fp);
if(value=='0') return false;
else return true;
}
return false;
}
std::string CGPIO::set_active_edge(edge_t edge)
{
int fp;
struct stat sb;
std::stringstream text;
unsigned char buffer[1024];
//Open the GPIO's sysfs file for reading and writing
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/edge";
if((fp=open(text.str().c_str(),O_WRONLY)) == -1)
if(this->direction==input)
{
/* handle exceptions */
throw CGPIOException(_HERE_,"Impossible to open the edge file");
}
//Set pointer to begining of the file
lseek(fp,0,SEEK_SET);
//Write our value of "1" to the file
text.str(std::string());
switch(edge)
{
case edge_none: text << "none";
break;
case edge_rising: text << "rising";
//Open the GPIO's sysfs file for reading and writing
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/edge";
while(stat(text.str().c_str(),&sb)!=0 || (sb.st_mode&(S_IWUSR | S_IWGRP))!=(S_IWUSR | S_IWGRP))
usleep(100000);
if((fp=open(text.str().c_str(),O_WRONLY)) == -1)
{
/* handle exceptions */
throw CGPIOException(_HERE_,"Impossible to open the edge file");
}
//Set pointer to begining of the file
lseek(fp,0,SEEK_SET);
//Write our value of "1" to the file
text.str(std::string());
switch(edge)
{
case edge_none: text << "none";
break;
case edge_falling: text << "falling";
case edge_rising: text << "rising";
break;
case edge_falling: text << "falling";
break;
case edge_both: text << "both";
break;
case edge_both: text << "both";
break;
}
if(write(fp,text.str().c_str(),text.str().size())!=(int)text.str().size())
{
close(fp);
throw CGPIOException(_HERE_,"Error while writing to the edge file");
}
}
if(write(fp,text.str().c_str(),text.str().size())!=(int)text.str().size())
{
close(fp);
throw CGPIOException(_HERE_,"Error while writing to the edge file");
}
close(fp);
close(fp);
this->edge=edge;
this->edge=edge;
// open the input file
text.str(std::string(""));
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/value";
if((this->input_fd=open(text.str().c_str(),O_RDONLY|O_NONBLOCK)) == -1)
{
/* handle exceptions */
throw CGPIOException(_HERE_,"Impossible to open the value file");
}
//Set pointer to begining of the file
lseek(this->input_fd,0,SEEK_SET);
read(this->input_fd,buffer,1024);
if(this->edge!=edge_none)
{
if(this->thread_server->get_thread_state(this->edge_thread_id)==attached)
// open the input file
text.str(std::string(""));
text << "/sys/devices/virtual/gpio/gpio" << this->gpio_id << "/value";
while(stat(text.str().c_str(),&sb)!=0 || (sb.st_mode&(S_IWUSR | S_IWGRP))!=(S_IWUSR | S_IWGRP))
usleep(100000);
if((this->input_fd=open(text.str().c_str(),O_RDONLY|O_NONBLOCK)) == -1)
{
// start the waiting thread
this->thread_server->start_thread(this->edge_thread_id);
// create the edge event
text.str(std::string(""));
text << "pin_" << this->gpio_id << "_event";
this->edge_event_id=text.str();
this->event_server->create_event(this->edge_event_id);
/* handle exceptions */
throw CGPIOException(_HERE_,"Impossible to open the value file");
}
//Set pointer to begining of the file
lseek(this->input_fd,0,SEEK_SET);
read(this->input_fd,buffer,1024);
if(this->edge!=edge_none)
{
if(this->thread_server->get_thread_state(this->edge_thread_id)==attached)
{
// start the waiting thread
this->thread_server->start_thread(this->edge_thread_id);
// create the edge event
text.str(std::string(""));
text << "pin_" << this->gpio_id << "_event";
this->edge_event_id=text.str();
this->event_server->create_event(this->edge_event_id);
}
}
else
{
// stop the thread if it is running
if(this->thread_server->get_thread_state(this->edge_thread_id)==starting ||
this->thread_server->get_thread_state(this->edge_thread_id)==active)
{
this->event_server->set_event(this->finish_thread_event_id);
this->thread_server->end_thread(this->edge_thread_id);
}
if(this->edge_event_id!="")
this->event_server->delete_event(this->edge_event_id);
this->edge_event_id="";
}
}
else
{
if(this->edge_event_id!="")
this->event_server->delete_event(this->edge_event_id);
this->edge_event_id="";
}
return this->edge_event_id;
return this->edge_event_id;
}
else
return std::string("");
}
CGPIO::~CGPIO()
......
......@@ -4,34 +4,240 @@
#include "eventserver.h"
#include "threadserver.h"
/*! \file */
/*!
* \brief GPIO direction ennumeration
*
* Specifies the direction of a given GPIO pin as either input or output.
* Bidirectional ports are not supported.
*/
typedef enum {output=0,input=1} dir_t;
/*!
* \brief GPIO edge sensitive ennumeration
*
* Specifies the input signal transitions that will generate an interal event
* only for GPIO pins configured as inputs.
*/
typedef enum {edge_none=0,edge_rising,edge_falling,edge_both} edge_t;
/*!
* \brief GPIO ports ennumeration
*
* Identifiers of the different GPIO ports available on the beaglebone black.
*/
typedef enum {GPIO0=0,GPIO1=32,GPIO2=64,GPIO3=96} gpio_ports;
/*!
* \brief Implmentation of a GPIO interface for ARM
*
* This class is a wrapper to the file system interface to GPIO signals for ARM
* processors. The file system interface required to open and close several
* files to perform any action on a given GPIO pin, which this class
* encapsulates, providing a simple user interface.
*
* This class requires some system configuration to allow standard users to
* access the GPIO signals. See section ?? on technical report ?? for more
* details on the required configuration.
*
* In its simplest form, this class allows to access any available GPIO pin
* as either an input or an ouput pin, providing functions to get the current
* value or set the desired value respectively.
*
* More advanced features are available when the GPIO isconfigured as an input.
* In this case, it is possible to select a sensitive transition on the input
* signal that will generate an internal event no notify it. This event is
* implemented as a CEvent from the iriutils library ???.
*
* This feature will allow an external process to wait on an input signal event
* without continuously polling the value of the input pin.
*/
class CGPIO
{
private:
/**
* \brief input pin value file descriptor
*
* This attribute points to the value file of the GPIO pin when it is
* configured as an input, and it is used for handling the internal
* events usign the select() function.
*/
int input_fd;
/**
* \brief Identifier of the GPIO pin
*
* This attribute holds the unique system identifier number for the GPIO
* pin, which is build from the port identifier and the port bit.
*/
int gpio_id;
/**
* \brief Current direction of the GPIO pin
*
* This attribute holds the current direction configuration of the GPIO
* pin.
*/
dir_t direction;
/**
* \brief Current sensitive edge for the GPIO
*
* This attribute holds the kind of transition on the input signal that
* will generate an internal event only for GPIO pins configured as
* inputs.
*/
edge_t edge;
/* events */
/**
* \brief Identifier of the active transition event.
*
* This attribute is the string identifier for the active transition event
* for any GPIO configured as an input. This identifier should be used by
* any external process to wait for the desired event on the GPIO pin, and
* therefore a copy is returned by the set_active_edge() function.
*/
std::string edge_event_id;
/**
* \brief Identifier of the finish event
*
* This attribute is a string identifier for the internal event used to
* terminate the internal thread to detect the desired transitions on the
* input signal.
*/
std::string finish_thread_event_id;
/**
* \brief Reference to the event server
*
* This is a reference to the unique event server to handle the internal
* events.
*/
CEventServer *event_server;
/* threads */
/**
* \brief Identifier of the internal thread
*
* This attribute is a string identifier for the internal thread used to
* monitor the desired transitions on the input value only for GPIO pins
* configured as inputs.
*/
std::string edge_thread_id;
/**
* \brief Reference to the thread server
*
* This is a reference to the unique thread server to handle the internal
* threads.
*/
CThreadServer *thread_server;
protected:
/**
* \brief Input transitions monitor function
*
* This is the main function executed by the internal thread to detect
* any desired transition on the input value. This function is only called
* when the GPIO pin is configured as an input, and it is charge to
* activate the edge_event_id event whenever the desired transition is
* detected on the input value.
*
* \param param a pointer to the object itself (this) since the function is
* declared as static.
*
* \return Value passed to the process that created the thread when it
* finishes execution.
*/
static void *edge_thread(void *param);
public:
/*!
* \brief Constructor
*
* This constructor tries to create the file system entries for the GPIO pin
* specified by the input parameters. If successfull, all the internal
* attributes are initialized by default.
*
* The default configuration is as an input, but without monitoring any
* transitions on the input value.
*
* A CGPIOException object may be thrown in the following cases:
* * Not enough privileges to access the GPIO file system
* * Invalid port identifier
*
* \param port identifier of the desired GPIO port. It must be one of the
* #gpio_ports values.
* \param pin desired bit number inside the given GPIO port. It must be a
* non-negative integer between 0 and 31.
*/
CGPIO(gpio_ports port, int pin);
/**
* \brief Function to change the direction of the current GPIO signal
*
* This function changes the direction of the current GPIO port. If the
* GPIO port changes from input to output, the monitoring of the input
* value is stopped (if it was active)
*
* A CGPIOException object may be thrown in the following cases:
* * Not enough privileges to access the GPIO file system
*
* \param direction The new direction identifier for the current GPIO
* port. It must be one of the #dir_t values.
*/
void set_direction(dir_t direction);
/**
* \brief Function to set the output value of the current GPIO signal
*
* This functions changes the output value of the current GPIO signal if
* it is configured as an output. Otherwise, this function does nothing.
*
* A CGPIOException object may be thrown in the following cases:
* * Not enough privileges to access the GPIO file system
*
* \param value Desired output value for the current GPIO signal. True
* for a logic '1' and false for '0'.
*/
void set_value(bool value);
/**
* \brief Function to get the current value of the current GPIO signal
*
* This function returns the current value of teh current GPIO signal if
* it is configured as an input. Otherwise, this function does nothing.
*
* A CGPIOException object may be thrown in the following cases:
* * Not enough privileges to access the GPIO file system
*
* \return The current value of the input port. True for a logic '1' and
* false for '0'.
*/
bool get_value(void);
/**
* \brief Function to enable the input monitoring
*
* This function starts the monitoring process on the input value if the
* GPIO pin is configured as an input. If the GPIO pin is configured as
* an output, this function does nothing.
*
* This function can also be used to stop the monitoring system by passing
* a value of none. This will stop the internal thread and will render
* inactive the previously returned event identifier.
*
* A CGPIOException object may be thrown in the following cases:
* * Not enough privileges to access the GPIO file system
*
* \param edge identifier of the desired transition on the input value to
* look for. It must be one of the #edge_t value.
*
* \return a string with the identifier of the internal event associated to
* the desired transition on the input value. This string will be
* empty if the GPIO is configured as an output or the desired edge
* is edge_none.
*/
std::string set_active_edge(edge_t edge);
/**
* \brief Destructor
*
* This destructor stops the monitoring process, if it is active, and free
* all object resources.
*
* A CGPIOException object may be thrown in the following cases:
* * Not enough privileges to access the GPIO file system
*
*/
~CGPIO();
};
......
......@@ -2,9 +2,9 @@
#include <string.h>
#include <stdio.h>
const std::string comm_exception_msg="[GPIO class] - ";
const std::string gpio_exception_msg="[GPIO class] - ";
CGPIOException::CGPIOException(const std::string& where,const std::string& error_msg):CException(where,comm_exception_msg)
CGPIOException::CGPIOException(const std::string& where,const std::string& error_msg):CException(where,gpio_exception_msg)
{
this->error_msg+=error_msg;
}
......@@ -4,8 +4,11 @@
#include "exceptions.h"
/**
* \brief
*
* \brief Exception class for the CGPIO class
*
* This class is used as the main exception to be thrown from the CGPIO class.
* It inherits from the basic CException class from iriutils and preappends
* some additional information to the standard error message.
*/
class CGPIOException : public CException
{
......@@ -13,6 +16,25 @@ class CGPIOException : public CException
/**
* \brief Constructor
*
* The constructor calls the base class constructor to add the general
* exception identifier and then adds the class identifier string
* "[CGPIO class]" and the supplied error message.
*
* So, the total exception message will look like this:
*
* \verbatim
* [Exception caught] - <where>
* [CGPIO class] - <error message>
* \endverbatim
*
* \param where a null terminated string with the information about the name
* of the function, the source code filename and the line where
* the exception was generated. This string must be generated
* by the _HERE_ macro.
*
* \param error_msg a null terminated string that contains the error message.
* This string may have any valid character and there is no
* limit on its length.
*/
CGPIOException(const std::string& where, const std::string& error_msg);
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment