Skip to content
Snippets Groups Projects
Commit 73404038 authored by Sergi Hernandez's avatar Sergi Hernandez
Browse files

Some improvements on the original implementation.

parent 4703fd74
No related branches found
No related tags found
No related merge requests found
Pipeline #
......@@ -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);
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment