Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
humanoides
bbb_gpio_sys
Commits
73404038
Commit
73404038
authored
Aug 01, 2015
by
Sergi Hernandez
Browse files
Some improvements on the original implementation.
parent
4703fd74
Pipeline
#101
skipped
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/bbb_gpio.cpp
View file @
73404038
...
...
@@ -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
()
...
...
src/bbb_gpio.h
View file @
73404038
...
...
@@ -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
();
};
...
...
src/gpioexceptions.cpp
View file @
73404038
...
...
@@ -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
;
}
src/gpioexceptions.h
View file @
73404038
...
...
@@ -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
);
};
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment