#include <fcntl.h>
#include <sstream>
-// Remove extra spaces from string, in place.
-char *
-clean_string(char * string)
-{
- char * s = string;
-
- while ( *s != 0 ) {
- if ( *s == ' ' && s[1] == ' ' ) {
+namespace FreeDV {
+ // Remove extra spaces from string, in place.
+ char *
+ clean_string(char * string)
+ {
+ char * s = string;
+
+ while ( *s != 0 ) {
+ if ( *s == ' ' && s[1] == ' ' ) {
+ s++;
+ char * end = s;
+ while ( *end == ' ' )
+ end++;
+ memmove(s, end, strlen(end) + 1);
+ }
s++;
- char * end = s;
- while ( *end == ' ' )
- end++;
- memmove(s, end, strlen(end) + 1);
}
- s++;
+
+ const std::size_t length = strlen(string);
+
+ if ( length > 1 && string[length - 1] == ' ' )
+ string[length - 1] = '\0';
+
+ return string;
}
-
- const std::size_t length = strlen(string);
-
- if ( length > 1 && string[length - 1] == ' ' )
- string[length - 1] = '\0';
-
- return string;
-}
-
-void
-EvDev::delete_enumeration(
- EvDev::device_enumeration * data,
- std::size_t count)
-{
- for ( std::size_t i = 0; i < count; i++ ) {
- delete data[i].special_file;
- delete data[i].name;
+
+ void
+ EvDev::delete_enumeration(
+ EvDev::device_enumeration * data,
+ std::size_t count)
+ {
+ for ( std::size_t i = 0; i < count; i++ ) {
+ if ( data[i].special_file )
+ delete data[i].special_file;
+ if ( data[i].name )
+ delete data[i].name;
+ }
+ delete data;
}
- delete data;
-}
-
-struct EvDev::device_enumeration *
-EvDev::enumerate(std::size_t & count)
-{
- struct device_enumeration devices[100];
-
- count = 0;
-
- for ( int i = 0; sizeof(devices) / sizeof(*devices); i++ ) {
+
+ struct EvDev::device_enumeration *
+ EvDev::enumerate(std::size_t & count)
+ {
+ struct device_enumeration devices[100];
+
+ count = 0;
+
+ for ( std::size_t i = 0; i < (sizeof(devices) / sizeof(*devices)); i++ ) {
+ std::ostringstream str;
+
+ str << "/dev/input/event" << i;
+
+ const char * const special_file = str.str().c_str();
+
+ const int fd = open(special_file, O_RDONLY);
+
+ if ( fd >= 0 ) {
+ if ( enumerate_device(special_file, fd, devices[count]) )
+ count++;
+ close(fd);
+ }
+ }
+ device_enumeration * const r = new device_enumeration[count];
+
+ memcpy(r, devices, count * sizeof(*r));
+
+ return r;
+ }
+
+ bool
+ EvDev::enumerate_device(
+ const char * special_file,
+ int fd,
+ device_enumeration & device)
+ {
+ char buf[100];
std::ostringstream str;
-
- str << "/dev/input/event" << i;
-
- const char * const special_file = str.str().c_str();
-
- const int fd = open(special_file, O_RDONLY);
-
- if ( fd >= 0 ) {
- if ( enumerate_device(special_file, fd, devices[count]) )
- count++;
- close(fd);
+
+ device.special_file = strdup(special_file);
+
+ if ( ioctl(fd, EVIOCGNAME(sizeof(buf)), buf) < 0
+ || ioctl(fd, EVIOCGBIT(0, sizeof(device.event_types)), device.event_types)
+ < 0 )
+ return false;
+
+ str << clean_string(buf);
+
+ if ( ioctl(fd, EVIOCGUNIQ(sizeof(buf)), buf) >= 0
+ && buf[0] != '\0'
+ && buf[0] != ' ' )
+ str << ' ' << clean_string(buf);
+
+ if ( ioctl(fd, EVIOCGPHYS(sizeof(buf)), buf) >= 0 )
+ str << " at " << clean_string(buf);
+
+ device.name = strdup(str.str().c_str());
+
+ return true;
+ }
+
+ char * *
+ EvDev::EnumerateButtonDevices()
+ {
+ std::size_t count = 0;
+ std::size_t length = 0;
+ device_enumeration * const devices = enumerate(count);
+
+ for ( std::size_t i = 0; i < count; i++ ) {
+ if ( test_bit(EV_KEY, devices[i].event_types) )
+ length++;
}
+
+ char * * names = new char * [length + 1];
+
+ std::size_t j = 0;
+ for ( std::size_t i = 0; i < count; i++ ) {
+ if ( test_bit(EV_KEY, devices[i].event_types) )
+ names[j++] = devices[i].name;
+ devices[i].name = 0;
+ }
+ names[j] = 0;
+
+ delete_enumeration(devices, count);
+ return names;
}
- device_enumeration * const r = new device_enumeration[count];
- memcpy(r, devices, count * sizeof(*r));
-
- return r;
-}
-
-bool
-EvDev::enumerate_device(
- const char * special_file,
- int fd,
- device_enumeration & device)
-{
- char buf[100];
- std::ostringstream str;
-
- device.special_file = strdup(special_file);
-
- if ( ioctl(fd, EVIOCGNAME(sizeof(buf)), buf) < 0
- || ioctl(fd, EVIOCGBIT(0, sizeof(device.event_types)), device.event_types)
- < 0 )
- return false;
-
- str << clean_string(buf);
-
- if ( ioctl(fd, EVIOCGUNIQ(sizeof(buf)), buf) >= 0 )
- str << ' ' << clean_string(buf);
-
- if ( ioctl(fd, EVIOCGPHYS(sizeof(buf)), buf) >= 0 )
- str << " at " << clean_string(buf);
-
- device.name = strdup(str.str().c_str());
-
- return true;
-}
-
-const char * const *
-EvDev::EnumerateButtonDevices()
-{
- std::size_t count = 0;
- std::size_t length = 0;
- device_enumeration * const devices = enumerate(count);
-
- for ( std::size_t i = 0; i < count; i++ ) {
- if ( test_bit(EV_KEY, devices[i].event_types) )
- length++;
+ EvDev::EvDev(const char *)
+ {
+ }
+
+ EvDev::~EvDev()
+ {
}
-
- delete_enumeration(devices, count);
- return 0;
-}
-
-EvDev::EvDev(const char *)
-{
-}
-
-EvDev::~EvDev()
-{
}
#define LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
-class EvDev {
-protected:
- struct device_enumeration {
- const char * special_file;
- const char * name;
- uint8_t event_types[(EV_MAX + 7) / 8];
+namespace FreeDV {
+ class EvDev {
+ protected:
+ struct device_enumeration {
+ char * special_file;
+ char * name;
+ uint8_t event_types[(EV_MAX + 7) / 8];
+ };
+
+ private:
+
+ EvDev(const EvDev &);
+ EvDev & operator =(const EvDev &);
+
+ static bool enumerate_device(
+ const char * name,
+ int fd,
+ struct device_enumeration & device);
+
+ protected:
+ static void delete_enumeration(
+ device_enumeration * data,
+ std::size_t count);
+
+ static device_enumeration *
+ enumerate(std::size_t & count);
+
+ public:
+ static char * * EnumerateButtonDevices();
+
+ EvDev(const char * name);
+ ~EvDev();
};
-
-private:
-
- EvDev(const EvDev &);
- EvDev & operator =(const EvDev &);
-
- static bool enumerate_device(
- const char * name,
- int fd,
- struct device_enumeration & device);
-
-protected:
- static void delete_enumeration(
- device_enumeration * data,
- std::size_t count);
-
- static device_enumeration *
- enumerate(std::size_t & count);
-
-public:
- static const char * const *
- EnumerateButtonDevices();
-
- EvDev(const char * name);
- ~EvDev();
-};
+}
--- /dev/null
+/// \file ptt_evdev.cpp
+/// Implementation of the evdev PTT driver.
+///
+/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file.
+///
+
+#include "evdev.h"
+#include "drivers.h"
+#include <iostream>
+#include <stdexcept>
+
+namespace FreeDV {
+ /// PTT driver using Linux evdev.
+ ///
+ class PTT_EvDev : public PTTInput {
+ private:
+ /// This is true if ready has not yet been sent.
+ ///
+ bool pressed;
+ bool ready_one_shot;
+ public:
+ /// Instantiate.
+ ///
+ PTT_EvDev(const char * parameters);
+ virtual ~PTT_EvDev();
+
+ /// Return file descriptors for poll()
+ /// \param array The address of an array that will be written
+ /// with a sequence of file descriptors.
+ /// \param space The maximum number of file descriptors that may be
+ /// stored in the array.
+ /// \return The number of file descriptors written to the array.
+ virtual int poll_fds(PollType * array, int space);
+
+ /// Return the amount of bytes ready for read.
+ ///
+ std::size_t ready();
+
+ /// Return true if the PTT input is pressed.
+ ///
+ bool state();
+ };
+
+ PTT_EvDev::PTT_EvDev(const char * _parameters)
+ : PTTInput("constant", _parameters), pressed(false), ready_one_shot(true)
+ {
+ }
+
+ PTT_EvDev::~PTT_EvDev()
+ {
+ }
+
+ int
+ PTT_EvDev::poll_fds(PollType *, int)
+ {
+ return 0;
+ }
+
+ std::size_t
+ PTT_EvDev::ready()
+ {
+ if ( ready_one_shot )
+ return 1;
+ else
+ return 0;
+ }
+
+ bool
+ PTT_EvDev::state()
+ {
+ return false;
+ }
+
+ PTTInput *
+ Driver::PTT_EvDev(const char * parameter)
+ {
+ return new ::FreeDV::PTT_EvDev(parameter);
+ }
+
+ static std::ostream &
+ PTT_EvDevEnumerator(std::ostream & stream)
+ {
+ char * * devices = EvDev::EnumerateButtonDevices();
+
+ char * * d = devices;
+
+ while ( *d != 0 )
+ stream << "\"evdev:" << *d++ << '\"' << std::endl;
+
+ d = devices;
+
+ while ( *d != 0 )
+ delete *d++;
+
+ delete devices;
+
+ return stream;
+ }
+
+ static bool
+ initializer()
+ {
+ driver_manager()->register_ptt_input("evdev", Driver::PTT_EvDev, PTT_EvDevEnumerator);
+ return true;
+ }
+ static const bool UNUSED initialized = initializer();
+}