summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Traut <manut@mecka.net>2013-01-16 20:50:58 +0100
committerManuel Traut <manut@mecka.net>2013-01-16 20:50:58 +0100
commit7ad35373a45f151c3a25cfabeb529bc04aecb580 (patch)
treebba5319df6a4cb286f6ecb78efce9b30daf98924
parent33a7f9331cbce18c5f706ed614cbd7c04ef7a9da (diff)
io: generic_gpio - add input observation
inputs needs to be monitored for change. this patch implements input monitoring based on a poll of the sys/class/gpio/gpioX/value file if raising, falling or both edges should be monitored can be configured in the conf file. Signed-off-by: Manuel Traut <manut@mecka.net>
-rw-r--r--io/bin/generic_gpio/generic_gpio.cpp160
-rw-r--r--io/bin/generic_gpio/gpio.conf13
-rw-r--r--io/lib/distrio_io.h5
3 files changed, 150 insertions, 28 deletions
diff --git a/io/bin/generic_gpio/generic_gpio.cpp b/io/bin/generic_gpio/generic_gpio.cpp
index f0e2145..cdf69f2 100644
--- a/io/bin/generic_gpio/generic_gpio.cpp
+++ b/io/bin/generic_gpio/generic_gpio.cpp
@@ -5,7 +5,11 @@
#include <ace/Task.h>
#include <iostream>
+#include <map>
+#include <string>
+
#include <gpio.h>
+#include <poll.h>
#include "ini.h"
@@ -18,25 +22,33 @@ static void err (const char *s)
class GPIO : public Distrio_Digital_i {
public:
- GPIO (int _id, std::string name, ::Distrio::Direction dir) :
- Distrio_Digital_i (name, dir) {
- int ret = -1;
- if (dir == ::Distrio::OUTPUT)
- ret = gpio_open_dir (&p, _id, GPIO_OUT);
- if (dir == ::Distrio::INPUT)
- ret = gpio_open_dir (&p, _id, GPIO_IN);
- if (ret) {
- id(-1);
- err ("open gpio failed\n");
- } else
- id(0);
+ GPIO (std::string name, ::Distrio::Direction dir, gpio_pin _p) :
+ Distrio_Digital_i (name, dir) { p = _p; }
+
+ int update_input (void) {
+ gpio_value v;
+ int ret = gpio_get_value (&p, &v);
+
+ if (ret) {
+ std::cerr << "update gpio " << io_name << " failed: " << ret << std::endl;
+ return -1;
+ }
+
+ update_timestamp ();
+
+ if (val)
+ raise ();
+ else
+ fall ();
}
::Distrio::Error *set () {
if (gpio_set_value (&p, GPIO_HIGH))
- return distrio_error
- (Distrio::E_NOTSUPPORTED, Distrio::L_NORMAL, MODULE_ID, "set gpio failed");
+ return distrio_error (Distrio::E_NOTSUPPORTED,
+ Distrio::L_NORMAL,
+ MODULE_ID,
+ "set gpio failed");
update_timestamp ();
val = 1;
@@ -48,8 +60,10 @@ class GPIO : public Distrio_Digital_i {
::Distrio::Error *reset () {
if (gpio_set_value (&p, GPIO_LOW))
- return distrio_error
- (Distrio::E_NOTSUPPORTED, Distrio::L_NORMAL, MODULE_ID, "reset gpio failed");
+ return distrio_error (Distrio::E_NOTSUPPORTED,
+ Distrio::L_NORMAL,
+ MODULE_ID,
+ "reset gpio failed");
update_timestamp ();
val = 0;
@@ -66,12 +80,56 @@ class GPIO : public Distrio_Digital_i {
gpio_pin p;
};
+class Input_observer : public ACE_Task < ACE_MT_SYNCH > {
+ public:
+ Input_observer (std::map <int, GPIO *> _input_list) {
+ input_list = _input_list;
+ }
+ ~Input_observer () { }
+ private:
+ std::map <int, GPIO *> input_list;
+ int svc (void) {
+ struct pollfd *fds = (struct pollfd *)
+ malloc (input_list.size () * sizeof (struct pollfd));
+ int fd_cnt = 0;
+
+ for (std::map <int, GPIO *> :: iterator it = input_list.begin ();
+ it != input_list.end ();
+ it++)
+ {
+ fds[fd_cnt].fd = it->first;
+ fds[fd_cnt].events = POLLPRI | POLLERR;
+ }
+
+ while (1) {
+ int pos = 0;
+ int ret = poll (fds, input_list.size (), -1);
+
+ while (ret > 0) {
+ if (fds [pos].revents) {
+ if (fds [pos].revents & POLLPRI)
+ input_list[pos]->update_input ();
+ ret--;
+ }
+ pos++;
+ if (pos > input_list.size ()) {
+ std::cerr << "fatal error in poll checker" << std::endl;
+ abort ();
+ }
+ }
+ }
+ }
+};
ACE_TMAIN (int argc, ACE_TCHAR *argv[])
{
int ret = 0, num = 0, i = 0;
- std::list<GPIO *> io_list;
- dictionary *d = _iniparser_load (GPIO_CONFIG);
+ std::map<int, GPIO *> input_list;
+ std::list<GPIO *> output_list;
+ Input_observer *obs;
+ dictionary *d;
+
+ d = _iniparser_load (GPIO_CONFIG);
if (!d) {
err ("load inifile failed\n");
@@ -92,15 +150,20 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
return -EINVAL;
for (i = 0; i < num; i++) {
+ GPIO *g;
+ gpio_pin p;
::Distrio::Direction dir;
char tmp [255];
- char *name = _iniparser_getsecname (d, i);
int id;
+ int rising = 0, falling = 0;
+ int ret = -1;
char *direction;
+ char *name = _iniparser_getsecname (d, i);
+
sprintf (tmp, "%s:id", name);
id = _iniparser_getint (d, tmp, -1);
sprintf (tmp, "%s:direction", name);
- direction = _iniparser_getstring (d, tmp, "unknown");
+ direction = _iniparser_getstring (d, tmp, (char *) "unknown");
if (strcmp (direction, "in") == 0)
dir = ::Distrio::INPUT;
@@ -108,28 +171,73 @@ ACE_TMAIN (int argc, ACE_TCHAR *argv[])
dir = ::Distrio::OUTPUT;
std::cout << " new gpio: " << id << ": " << name << std::endl;
- GPIO *g = new GPIO (id, std::string (name), dir);
- if (g->id () == -1) {
- err ("create gpio object failed - hw error?\n");
- delete g;
+ if (dir == ::Distrio::OUTPUT)
+ ret = gpio_open_dir (&p, id, GPIO_OUT);
+ if (dir == ::Distrio::INPUT)
+ ret = gpio_open_dir (&p, id, GPIO_IN);
+
+ if (ret) {
+ std::cerr << "open gpio: " << id << ": " << name << "failed" << std::endl;
continue;
}
+ if (dir == ::Distrio::INPUT) {
+ sprintf (tmp, "%s:rising", name);
+ rising = _iniparser_getint (d, tmp, -1);
+ sprintf (tmp, "%s:falling", name);
+ falling = _iniparser_getint (d, tmp, -1);
+
+ if (((rising == -1) && (falling == -1)) || (!rising && !falling)) {
+ std::cout << "gpio: " << id << ": " << name;
+ std::cout << "no edge defined.";
+ std::cout << "events will be emitted on rising and falling edge";
+ ret = gpio_enable_irq (&p, GPIO_BOTH);
+ }
+ else if (rising && falling)
+ ret = gpio_enable_irq (&p, GPIO_BOTH);
+ else if (rising)
+ ret = gpio_enable_irq (&p, GPIO_RISING);
+ else if (falling)
+ ret = gpio_enable_irq (&p, GPIO_FALLING);
+ else {
+ std::cerr << "gpio: " << id << ": " << name;
+ std::cerr << "no edge defined - gpio will be skipped." << std::endl;
+ continue;
+ }
+
+ if (ret) {
+ std::cerr << "gpio: " << id << ": " << name;
+ std::cerr << "enable irq failed - gpio will be skipped." << std::endl;
+ continue;
+ }
+ }
+
+ g = new GPIO (std::string (name), dir, p);
+
if (register_digital (g)) {
err ("register gpio object at the manager failed\n");
delete g;
continue;
}
+
+ if (dir == ::Distrio::INPUT) {
+ int fd = gpio_get_fd (&p);
+ input_list[fd] = g;
+ } else
+ output_list.push_back (g);
+
std::cout << "registered gpio " << name <<" with id: " << g->id () << std::endl;
- io_list.push_back (g);
}
_iniparser_freedict (d);
+ obs = new Input_observer (input_list);
+
join_orb ();
out:
- /* io_list.erase (); */
+ /* input_list.erase (); */
+ /* output_list.erase (); */
return ret;
}
diff --git a/io/bin/generic_gpio/gpio.conf b/io/bin/generic_gpio/gpio.conf
index 44068de..df70859 100644
--- a/io/bin/generic_gpio/gpio.conf
+++ b/io/bin/generic_gpio/gpio.conf
@@ -9,3 +9,16 @@
[keyboard]
id = 272;
direction = in;
+ rising = 1;
+ falling = 1;
+
+[button1]
+ id = 150;
+ direction = in;
+ rising = 1;
+
+[button2]
+ id = 151;
+ direction = in;
+ rising = 0;
+ falling = 1;
diff --git a/io/lib/distrio_io.h b/io/lib/distrio_io.h
index 997e305..d32dd7e 100644
--- a/io/lib/distrio_io.h
+++ b/io/lib/distrio_io.h
@@ -99,9 +99,9 @@ public:
protected:
::CORBA::Long val;
+ std::string io_name;
private:
- std::string io_name;
::CORBA::Long io_id;
std::list<Distrio::Device_ptr> cb_list_rise;
std::list<Distrio::Device_ptr> cb_list_fall;
@@ -164,8 +164,9 @@ public:
virtual
void id (
::CORBA::Long id);
-private:
+protected:
std::string io_name;
+private:
::Distrio::Direction dir;
::CORBA::Long io_id;
};