merging in (some of) Daniel's GPIO pin stuff
diff --git a/bbb_cape/src/bbb/bbb.gyp b/bbb_cape/src/bbb/bbb.gyp
index 1722bce..86bad66 100644
--- a/bbb_cape/src/bbb/bbb.gyp
+++ b/bbb_cape/src/bbb/bbb.gyp
@@ -130,6 +130,7 @@
'packet_finder',
'data_struct',
'<(AOS)/common/common.gyp:time',
+ 'gpios',
],
},
{
@@ -137,6 +138,8 @@
'type': 'static_library',
'sources': [
'gpios.cc',
+ 'gpi.cc',
+ 'gpo.cc',
],
'dependencies': [
'<(AOS)/build/aos.gyp:logging',
diff --git a/bbb_cape/src/bbb/byte_reader.h b/bbb_cape/src/bbb/byte_reader.h
index 16e364c..80bb208 100644
--- a/bbb_cape/src/bbb/byte_reader.h
+++ b/bbb_cape/src/bbb/byte_reader.h
@@ -8,11 +8,11 @@
namespace bbb {
class ByteReader {
- public:
+public:
// We have 64-bit ints in some of our data.
typedef char __attribute__((aligned(8))) AlignedChar;
- // Implemented by subclasses to provide a data source
+ // Implemented by subclasses to provide a data source
// for these algorithms.
// Returns the number of bytes read, -1 if there is an error in errno, or -2
// if reading takes longer than timeout.
diff --git a/bbb_cape/src/bbb/gpi.cc b/bbb_cape/src/bbb/gpi.cc
new file mode 100644
index 0000000..90c46d5
--- /dev/null
+++ b/bbb_cape/src/bbb/gpi.cc
@@ -0,0 +1,48 @@
+#include "gpi.h"
+
+#include <stdio.h>
+
+#include "aos/common/logging/logging.h"
+
+namespace bbb {
+
+Gpi::Gpi(int bank, int pin) {
+ // All the failures here are fatal, seeing as
+ // if we can't initialize the pin, we're
+ // probably screwed anyway.
+ if (!InitPin(bank, pin)) {
+ LOG(FATAL, "Failed to export pin.\n");
+ }
+ if (!DoPinDirSet(1)) {
+ LOG(FATAL, "Failed to set pin as an input.\n");
+ }
+}
+
+int Gpi::Read() {
+ // NOTE: I can't find any docs confirming that one can indeed
+ // poll a pin's value using this method, but it seems that it
+ // should work. Really, the "right" (interrupt driven) way to
+ // do this is to set an event, but that involves messing with
+ // dev tree crap, which I'm not willing to do unless we need
+ // this functionality.
+ char buf, val_path[64];
+ snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
+ kernel_pin_);
+
+ if ((handle_ = fopen(val_path, "rb")) == NULL) {
+ LOG(ERROR, "Unable to open file for pin value reading.\n");
+ fclose(handle_);
+ return -1;
+ }
+
+ if (fread(&buf, sizeof(char), 1, handle_) <= 1) {
+ LOG(ERROR, "Reading from file failed with error %d\n",
+ ferror(handle_));
+ fclose(handle_);
+ return -1;
+ }
+ fclose(handle_);
+ return atoi(&buf);
+}
+
+} // namespace bbb
diff --git a/bbb_cape/src/bbb/gpi.h b/bbb_cape/src/bbb/gpi.h
new file mode 100644
index 0000000..be41a11
--- /dev/null
+++ b/bbb_cape/src/bbb/gpi.h
@@ -0,0 +1,23 @@
+#ifndef BBB_CAPE_SRC_BBB_GPI_H_
+#define BBB_CAPE_SRC_BBB_GPI_H_
+
+#include "gpios.h"
+
+// Subclass of Pin for input pins.
+
+namespace bbb {
+
+class Gpi : public Pin {
+ public:
+ // See the base class for what these args mean.
+ Gpi(int bank, int pin);
+
+ // Read the current value of the pin.
+ // Returns 1 if it reads high, 0 for low.
+ // Returns -1 if fails to read the pin for some reason.
+ int Read();
+};
+
+} // namespace bbb
+
+#endif
diff --git a/bbb_cape/src/bbb/gpios.cc b/bbb_cape/src/bbb/gpios.cc
index 5a9c76e..8594ba4 100644
--- a/bbb_cape/src/bbb/gpios.cc
+++ b/bbb_cape/src/bbb/gpios.cc
@@ -7,147 +7,62 @@
namespace bbb {
-Pin::Pin(int bank, int pin)
- : handle_(NULL),
- direction_(0),
- kernel_pin_(bank * 32 + pin),
- exported_(false) {}
+Pin::Pin() {}
Pin::~Pin() {
// Unexport the pin.
if ((handle_ = fopen("/sys/class/gpio/unexport", "ab")) == NULL) {
- LOG(WARNING, "Could not unexport gpio pin.\n");
+ LOG(WARNING, "Could not open file to unexport pin.\n");
// There's nothing intelligent we can really do here.
return;
}
- char gpio_num[2];
- snprintf(gpio_num, sizeof(gpio_num), "%d", kernel_pin_);
- fwrite(gpio_num, sizeof(char), 2, handle_);
+ fprintf(handle_, "%d", kernel_pin_);
fclose(handle_);
}
-int Pin::DoExport() {
- char gpio_num[2];
- snprintf(gpio_num, sizeof(gpio_num), "%d", kernel_pin_);
+bool Pin::InitPin(int bank, int pin) {
+ kernel_pin_ = bank * 32 + pin;
// Export the pin.
if ((handle_ = fopen("/sys/class/gpio/export", "ab")) == NULL) {
- LOG(ERROR, "Could not export GPIO pin.\n");
- return -1;
+ LOG(ERROR, "Could not open file for exporting pin.\n");
+ return false;
}
- fwrite(gpio_num, sizeof(char), 2, handle_);
+ fprintf(handle_, "%d", kernel_pin_);
fclose(handle_);
-
- exported_ = true;
- return 0;
+ return true;
}
-int Pin::DoPinDirSet(int direction) {
- char buf[4], type_path[64];
+bool Pin::DoPinDirSet(int direction) {
+ char type_path[64];
snprintf(type_path, sizeof(type_path), "/sys/class/gpio/gpio%d/direction",
kernel_pin_);
if ((handle_ = fopen(type_path, "rb+")) == NULL) {
- LOG(ERROR, "Unable to set pin direction.\n");
- return -1;
+ LOG(ERROR, "Unable open file for pin direction setting.\n");
+ return false;
}
- direction_ = direction;
switch (direction) {
case 1:
- strcpy(buf, "in");
+ // Input.
+ fprintf(handle_, "in");
break;
case 2:
- strcpy(buf, "low");
+ // Output.
+ // If it's an output, we should specify an initial direction.
+ fprintf(handle_, "low");
break;
- case 0:
- return 0;
default:
LOG(ERROR, "Invalid direction identifier %d.\n", direction);
- direction_ = 0;
- return -1;
+ fclose(handle_);
+ return false;
}
- fwrite(buf, sizeof(char), 3, handle_);
+
fclose(handle_);
-
- return 0;
-}
-
-int Pin::MakeInput() {
- if (!exported_) {
- if (DoExport()) {
- return -1;
- }
- }
-
- return DoPinDirSet(1);
-}
-
-int Pin::MakeOutput() {
- if (!exported_) {
- if (DoExport()) {
- return -1;
- }
- }
-
- return DoPinDirSet(2);
-}
-
-int Pin::Write(uint8_t value) {
- if (direction_ != 2) {
- LOG(ERROR, "Only pins set as output can be written to.\n");
- return -1;
- }
-
- char buf, val_path[64];
- snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
- kernel_pin_);
- if (value != 0) {
- value = 1;
- }
-
- if ((handle_ = fopen(val_path, "rb+")) == NULL) {
- LOG(ERROR, "Unable to set pin value.\n");
- return -1;
- }
-
- snprintf(&buf, sizeof(buf), "%d", value);
- fwrite(&buf, sizeof(char), 1, handle_);
- fclose(handle_);
-
- return 0;
-}
-
-int Pin::Read() {
- // NOTE: I can't find any docs confirming that one can indeed
- // poll a pin's value using this method, but it seems that it
- // should work. Really, the "right" (interrupt driven) way to
- // do this is to set an event, but that involves messing with
- // dev tree crap, which I'm not willing to do unless we need
- // this functionality.
-
- if (direction_ != 1) {
- LOG(ERROR, "Only pins set as input can be read from.\n");
- return -1;
- }
-
- char buf, val_path[64];
- snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
- kernel_pin_);
-
- if ((handle_ = fopen(val_path, "rb")) == NULL) {
- LOG(ERROR, "Unable to read pin value.\n");
- return -1;
- }
-
- if (fread(&buf, sizeof(char), 1, handle_) <= 0) {
- LOG(ERROR, "Failed to read pin value from file.\n");
- return -1;
- }
- fclose(handle_);
- return atoi(&buf);
+ return true;
}
} // namespace bbb
diff --git a/bbb_cape/src/bbb/gpios.h b/bbb_cape/src/bbb/gpios.h
index a377d68..4925f1b 100644
--- a/bbb_cape/src/bbb/gpios.h
+++ b/bbb_cape/src/bbb/gpios.h
@@ -1,38 +1,46 @@
#ifndef BBB_CAPE_SRC_BBB_CAPE_CONTROL_H_
#define BBB_CAPE_SRC_BBB_CAPE_CONTROL_H_
-#include <stdint.h>
#include <stdio.h>
+#include "aos/common/macros.h"
+
// As it turns out, controlling the BBB's GPIO pins
// from C++ is kind of a pain. The purpose of this
// code is to provide a simple wrapper that masks
// all the ugly stuff and exposes a nice API.
-// Based on example from
+// Based on example from
// <http://learnbuildshare.wordpress.com/2013/05/29/beaglebone-black-digital-ouput/>
+// This is a base class for all gpio related stuff.
+// Use either a gpi or gpo subclass if you want to do things.
namespace bbb {
class Pin {
- FILE *handle_;
- int direction_;
- int kernel_pin_;
- bool exported_;
+ public:
+ // Not strictly necessary for this to be virtual,
+ // but it's a good idea.
+ virtual ~Pin();
+ // When you don't define this and use the
+ // DISALLOW_COPY_AND_ASSIGN macro, the compiler
+ // doesn't seem to create a default one.
+ Pin();
- int DoPinDirSet(int direction);
- int DoExport();
-
-public:
+ protected:
+ // Set the pin direction.
+ // 1 makes it an input.
+ // 2 makes it an output and sets the initial state to low.
+ bool DoPinDirSet(int direction);
+ // Export the pin, so we can use it.
// Here, for example, if you wanted to use
- // GPIO1_28, you would give the ctor
- // 1, 28 as arguments.
- Pin(int bank, int pin);
- ~Pin();
- int MakeInput();
- int MakeOutput();
- int Write(uint8_t value);
- int Read();
+ // GPIO1_28, you would give it 1, 28 as arguments.
+ bool InitPin(int bank, int pin);
+
+ FILE *handle_ = NULL;
+ int kernel_pin_ = -1;
+
+ DISALLOW_COPY_AND_ASSIGN(Pin);
};
} // namespace bbb
diff --git a/bbb_cape/src/bbb/gpo.cc b/bbb_cape/src/bbb/gpo.cc
new file mode 100644
index 0000000..959b132
--- /dev/null
+++ b/bbb_cape/src/bbb/gpo.cc
@@ -0,0 +1,37 @@
+#include "gpo.h"
+
+#include <stdio.h>
+
+#include "aos/common/logging/logging.h"
+
+namespace bbb {
+
+Gpo::Gpo(int bank, int pin) {
+ // All the failures here are fatal, seeing as
+ // failure to initialize the pin would at best
+ // severely cripple the calling process.
+ if (!InitPin(bank, pin)) {
+ LOG(FATAL, "Failed to export the pin.\n");
+ }
+ if (!DoPinDirSet(2)) {
+ LOG(FATAL, "Failed to make the pin an output.\n");
+ }
+}
+
+bool Gpo::Set(const bool high) {
+ char val_path[64];
+ snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
+ kernel_pin_);
+
+ if ((handle_ = fopen(val_path, "rb+")) == NULL) {
+ LOG(ERROR, "Unable open file for pin value setting.\n");
+ return false;
+ }
+
+ fprintf(handle_, "%d", high);
+ fclose(handle_);
+
+ return true;
+}
+
+} // namespace bbb
diff --git a/bbb_cape/src/bbb/gpo.h b/bbb_cape/src/bbb/gpo.h
new file mode 100644
index 0000000..596daf5
--- /dev/null
+++ b/bbb_cape/src/bbb/gpo.h
@@ -0,0 +1,22 @@
+#ifndef BBB_CAPE_SRC_BBB_GPO_H_
+#define BBB_CAPE_SRC_BBB_GPO_H_
+
+#include "gpios.h"
+
+namespace bbb {
+
+// Gpios subclass for output pins.
+class Gpo : public Pin {
+ public:
+ // See the base class for what these args mean.
+ Gpo(int bank, int pin);
+ // Sets the pin to either high or low.
+ // If the argument is true, is sets it high.
+ // Otherwise, it sets it low.
+ bool Set(const bool high);
+
+};
+
+} // namespace bbb
+
+#endif