Skip to content

Instantly share code, notes, and snippets.

@mvduin
Last active September 9, 2019 09:33
Show Gist options
  • Save mvduin/578509d458da8948ae3a14a81dc639e4 to your computer and use it in GitHub Desktop.
Save mvduin/578509d458da8948ae3a14a81dc639e4 to your computer and use it in GitHub Desktop.
sysfs gpio event example
#pragma once
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
[[ noreturn ]]
inline void die( char const *fmt, ... )
{
va_list ap;
va_start( ap, fmt );
vfprintf( stderr, fmt, ap );
va_end( ap );
exit( EXIT_FAILURE );
}
#include "sysfs-gpio.h"
int main()
{
GpIn in { "/sys/class/gpio/gpio60", GpIn::Edge::BOTH };
bool value = in;
for(;;) {
printf( "%d\n", value );
do in.wait(); while( value == in );
value = ! value;
}
}
#pragma once
#include "die.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct Gpio {
protected:
int fd = -1;
int pathfd = -1;
char *path = NULL;
Gpio( char const *dir, bool output )
{
assert( dir != NULL );
path = strdup( dir );
if( path == NULL )
die( "strdup: %m\n" );
pathfd = open( path, O_PATH | O_CLOEXEC );
if( pathfd < 0 )
die( "open %s: %m\n", path );
fd = open_attribute( "value", output );
}
int open_attribute( char const *attr, bool write ) const
{
int flags = (write ? O_RDWR : O_RDONLY) | O_CLOEXEC;
int afd = openat( pathfd, attr, flags );
if( afd < 0 )
die( "open %s/%s: %m\n", path, attr );
return afd;
}
char read_attribute( char const *attr ) const
{
int afd = open_attribute( attr, false );
char c = 0;
if( read( afd, &c, 1 ) < 0 )
die( "read %s/%s: %m\n", path, attr );
close( afd );
return c;
}
void write_attribute( char const *attr, char const *value )
{
int afd = open_attribute( attr, true );
if( write( afd, value, strlen( value ) ) < 0 )
die( "write %s/%s: %m\n", path, attr );
close( afd );
}
public:
Gpio() = delete;
Gpio( Gpio const & ) = delete;
~Gpio()
{
if( fd >= 0 )
close( fd );
if( pathfd >= 0 )
close( pathfd );
free( path );
}
bool active_low() const
{
return read_attribute( "active_low" ) != '0';
}
operator bool () const
{
char c;
ssize_t res = pread( fd, &c, 1, 0 );
if( res < 0 )
die( "pread %s/value: %m\n", path );
if( res == 0 )
die( "pread %s/value: no data\n", path );
return c != '0';
}
};
struct GpIn : Gpio {
enum Edge { NONE, RISING, FALLING, BOTH };
GpIn( const char *dir, Edge event_edge ) : Gpio{ dir, false }
{
if( read_attribute( "direction" ) != 'i' )
write_attribute( "direction", "in" );
static char const *const edge_names[]
= { "none", "rising", "falling", "both" };
write_attribute( "edge", edge_names[ event_edge ] );
}
// wait for edge event
void wait()
{
struct pollfd pfd = { fd, POLLPRI, 0 };
if( poll( &pfd, 1, -1 ) < 0 )
die( "poll %s: %m\n", path );
}
};
struct GpOut : Gpio {
GpOut( const char *dir, bool init ) : Gpio{ dir, true }
{
if( read_attribute( "direction" ) != 'i' ) {
*this = init;
return;
}
write_attribute( "edge", "none" );
if( active_low() )
init = ! init;
write_attribute( "direction", init ? "high" : "low" );
}
bool operator = ( bool value )
{
char c = '0' + value;
ssize_t res = pwrite( fd, &c, 1, 0 );
if( res < 0 )
die( "pwrite %s/value: %m\n", path );
return value;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment