blob: 5a9c76ec812289adf74aab9aadcfef4861b3bb86 [file] [log] [blame]
Brian Silverman1662a0e2013-12-19 17:50:01 -08001#include "bbb/gpios.h"
2
3#include <stdio.h>
4#include <stdlib.h>
Daniel Petti23dcf6c2013-12-19 08:56:41 -08005
6#include "aos/common/logging/logging_impl.h"
Daniel Petti23dcf6c2013-12-19 08:56:41 -08007
8namespace bbb {
9
Brian Silverman1662a0e2013-12-19 17:50:01 -080010Pin::Pin(int bank, int pin)
11 : handle_(NULL),
12 direction_(0),
13 kernel_pin_(bank * 32 + pin),
14 exported_(false) {}
Daniel Petti23dcf6c2013-12-19 08:56:41 -080015
Brian Silverman1662a0e2013-12-19 17:50:01 -080016Pin::~Pin() {
17 // Unexport the pin.
18 if ((handle_ = fopen("/sys/class/gpio/unexport", "ab")) == NULL) {
19 LOG(WARNING, "Could not unexport gpio pin.\n");
20 // There's nothing intelligent we can really do here.
21 return;
Daniel Petti23dcf6c2013-12-19 08:56:41 -080022 }
23
Brian Silverman1662a0e2013-12-19 17:50:01 -080024 char gpio_num[2];
25 snprintf(gpio_num, sizeof(gpio_num), "%d", kernel_pin_);
26 fwrite(gpio_num, sizeof(char), 2, handle_);
27 fclose(handle_);
28}
Daniel Petti23dcf6c2013-12-19 08:56:41 -080029
Brian Silverman1662a0e2013-12-19 17:50:01 -080030int Pin::DoExport() {
31 char gpio_num[2];
32 snprintf(gpio_num, sizeof(gpio_num), "%d", kernel_pin_);
Daniel Petti23dcf6c2013-12-19 08:56:41 -080033
Brian Silverman1662a0e2013-12-19 17:50:01 -080034 // Export the pin.
35 if ((handle_ = fopen("/sys/class/gpio/export", "ab")) == NULL) {
36 LOG(ERROR, "Could not export GPIO pin.\n");
37 return -1;
Daniel Petti23dcf6c2013-12-19 08:56:41 -080038 }
39
Brian Silverman1662a0e2013-12-19 17:50:01 -080040 fwrite(gpio_num, sizeof(char), 2, handle_);
41 fclose(handle_);
Daniel Petti23dcf6c2013-12-19 08:56:41 -080042
Brian Silverman1662a0e2013-12-19 17:50:01 -080043 exported_ = true;
44 return 0;
45}
Daniel Petti23dcf6c2013-12-19 08:56:41 -080046
Brian Silverman1662a0e2013-12-19 17:50:01 -080047int Pin::DoPinDirSet(int direction) {
48 char buf[4], type_path[64];
49 snprintf(type_path, sizeof(type_path), "/sys/class/gpio/gpio%d/direction",
50 kernel_pin_);
51
52 if ((handle_ = fopen(type_path, "rb+")) == NULL) {
53 LOG(ERROR, "Unable to set pin direction.\n");
54 return -1;
Daniel Petti23dcf6c2013-12-19 08:56:41 -080055 }
56
Brian Silverman1662a0e2013-12-19 17:50:01 -080057 direction_ = direction;
58 switch (direction) {
59 case 1:
60 strcpy(buf, "in");
61 break;
62 case 2:
63 strcpy(buf, "low");
64 break;
65 case 0:
66 return 0;
67 default:
68 LOG(ERROR, "Invalid direction identifier %d.\n", direction);
69 direction_ = 0;
70 return -1;
71 }
72 fwrite(buf, sizeof(char), 3, handle_);
73 fclose(handle_);
Daniel Petti23dcf6c2013-12-19 08:56:41 -080074
Brian Silverman1662a0e2013-12-19 17:50:01 -080075 return 0;
76}
77
78int Pin::MakeInput() {
79 if (!exported_) {
80 if (DoExport()) {
81 return -1;
82 }
Daniel Petti23dcf6c2013-12-19 08:56:41 -080083 }
84
Brian Silverman1662a0e2013-12-19 17:50:01 -080085 return DoPinDirSet(1);
86}
Daniel Petti23dcf6c2013-12-19 08:56:41 -080087
Brian Silverman1662a0e2013-12-19 17:50:01 -080088int Pin::MakeOutput() {
89 if (!exported_) {
90 if (DoExport()) {
91 return -1;
92 }
Daniel Petti23dcf6c2013-12-19 08:56:41 -080093 }
94
Brian Silverman1662a0e2013-12-19 17:50:01 -080095 return DoPinDirSet(2);
96}
Daniel Petti23dcf6c2013-12-19 08:56:41 -080097
Brian Silverman1662a0e2013-12-19 17:50:01 -080098int Pin::Write(uint8_t value) {
99 if (direction_ != 2) {
100 LOG(ERROR, "Only pins set as output can be written to.\n");
101 return -1;
Daniel Petti23dcf6c2013-12-19 08:56:41 -0800102 }
103
Brian Silverman1662a0e2013-12-19 17:50:01 -0800104 char buf, val_path[64];
105 snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
106 kernel_pin_);
107 if (value != 0) {
108 value = 1;
Daniel Petti23dcf6c2013-12-19 08:56:41 -0800109 }
110
Brian Silverman1662a0e2013-12-19 17:50:01 -0800111 if ((handle_ = fopen(val_path, "rb+")) == NULL) {
112 LOG(ERROR, "Unable to set pin value.\n");
113 return -1;
114 }
115
116 snprintf(&buf, sizeof(buf), "%d", value);
117 fwrite(&buf, sizeof(char), 1, handle_);
118 fclose(handle_);
119
120 return 0;
121}
122
123int Pin::Read() {
124 // NOTE: I can't find any docs confirming that one can indeed
125 // poll a pin's value using this method, but it seems that it
126 // should work. Really, the "right" (interrupt driven) way to
127 // do this is to set an event, but that involves messing with
128 // dev tree crap, which I'm not willing to do unless we need
129 // this functionality.
130
131 if (direction_ != 1) {
132 LOG(ERROR, "Only pins set as input can be read from.\n");
133 return -1;
134 }
135
136 char buf, val_path[64];
137 snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
138 kernel_pin_);
139
140 if ((handle_ = fopen(val_path, "rb")) == NULL) {
141 LOG(ERROR, "Unable to read pin value.\n");
142 return -1;
143 }
144
145 if (fread(&buf, sizeof(char), 1, handle_) <= 0) {
146 LOG(ERROR, "Failed to read pin value from file.\n");
147 return -1;
148 }
149 fclose(handle_);
150 return atoi(&buf);
151}
152
153} // namespace bbb