From: bruceperens Date: Fri, 18 Apr 2014 16:57:09 +0000 (+0000) Subject: Evdev enumeration working. X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=1801a3b86284bc9d55ad7d0a1421043f64b9f36e;p=freetel-svn-tracking.git Evdev enumeration working. git-svn-id: https://svn.code.sf.net/p/freetel/code@1501 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv-server/source/drivers.h b/freedv-server/source/drivers.h index 14946088..d92c92a3 100644 --- a/freedv-server/source/drivers.h +++ b/freedv-server/source/drivers.h @@ -796,6 +796,12 @@ Modem * ModemNoOp(const char * parameter); /// PTTInput * PTTConstant(const char * parameter); +/// Opens a push-to-talk device based on Linux evdev. +/// \param parameter +/// \return A pointer to the PTT_EvDev instance for the device. +/// +PTTInput * PTT_EvDev(const char * parameter); + /// Opens a "constant" text ionput device, which has a constant text value /// which is to be transmitted as ancillary data. /// \param parameter The text to be transmitted. diff --git a/freedv-server/source/platform/linux/alsa.h b/freedv-server/source/platform/linux/alsa.h new file mode 100644 index 00000000..5f725994 --- /dev/null +++ b/freedv-server/source/platform/linux/alsa.h @@ -0,0 +1,21 @@ +/// \file platform/linux/alsa.h +/// Definitions for use by ALSA drivers. +/// +/// \copyright Copyright (C) 2013-2014 Algoram. See the LICENSE file. +/// + +#include + +namespace FreeDV { + snd_pcm_t * + ALSASetup( + const char * name, + snd_pcm_stream_t stream, + int mode, + snd_pcm_format_t format, + snd_pcm_access_t access, + unsigned int channels, + unsigned int rate, + snd_pcm_uframes_t period_size, + snd_pcm_uframes_t buffer_size); +} diff --git a/freedv-server/source/platform/linux/evdev.cpp b/freedv-server/source/platform/linux/evdev.cpp index 073436ef..1ff4e0f5 100644 --- a/freedv-server/source/platform/linux/evdev.cpp +++ b/freedv-server/source/platform/linux/evdev.cpp @@ -10,121 +10,137 @@ #include #include -// 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() -{ } diff --git a/freedv-server/source/platform/linux/evdev.h b/freedv-server/source/platform/linux/evdev.h index e4491ef7..ade529d6 100644 --- a/freedv-server/source/platform/linux/evdev.h +++ b/freedv-server/source/platform/linux/evdev.h @@ -8,36 +8,37 @@ #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(); -}; +} diff --git a/freedv-server/source/platform/linux/ptt_evdev.cpp b/freedv-server/source/platform/linux/ptt_evdev.cpp new file mode 100644 index 00000000..ee0770b4 --- /dev/null +++ b/freedv-server/source/platform/linux/ptt_evdev.cpp @@ -0,0 +1,107 @@ +/// \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 +#include + +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(); +}