blob: e2ab654f423d14611146eddef8e9ce062281c359 [file] [log] [blame]
Daniel Petti23dcf6c2013-12-19 08:56:41 -08001#include <cstdio>
2#include <cstdlib>
3
4#include "aos/common/logging/logging_impl.h"
5#include "gpios.h"
6
7namespace bbb {
8
9 Pin::Pin(int bank, int pin) : handle_(NULL), direction_(0),
10 kernel_pin_(bank * 32 + pin), exported_(false) {}
11
12 Pin::~Pin() {
13 // Unexport the pin.
14 if ((handle_ = fopen("/sys/class/gpio/unexport", "ab")) == NULL) {
15 LOG(WARNING, "Could not unexport gpio pin.\n");
16 // There's nothing intelligent we can really do here.
17 return;
18 }
19
20 char gpio_num[2];
21 snprintf(gpio_num, sizeof(gpio_num), "%d", kernel_pin_);
22 fwrite(gpio_num, sizeof(char), 2, handle_);
23 fclose(handle_);
24 }
25
26 int Pin::DoExport() {
27 char gpio_num[2];
28 snprintf(gpio_num, sizeof(gpio_num), "%d", kernel_pin_);
29
30 // Export the pin.
31 if ((handle_ = fopen("/sys/class/gpio/export", "ab")) == NULL) {
32 LOG(ERROR, "Could not export GPIO pin.\n");
33 return -1;
34 }
35
36 fwrite(gpio_num, sizeof(char), 2, handle_);
37 fclose(handle_);
38
39 exported_ = true;
40 return 0;
41 }
42
43 int Pin::DoPinDirSet(int direction) {
44 char buf[4], type_path[64];
45 snprintf(type_path, sizeof(type_path), "/sys/class/gpio/gpio%d/direction", kernel_pin_);
46
47 if ((handle_ = fopen(type_path, "rb+")) == NULL) {
48 LOG(ERROR, "Unable to set pin direction.\n");
49 return -1;
50 }
51
52 direction_ = direction;
53 switch (direction) {
54 case 1:
55 strcpy(buf, "in");
56 break;
57 case 2:
58 strcpy(buf, "low");
59 break;
60 case 0:
61 return 0;
62 default:
63 LOG(ERROR, "Invalid direction identifier %d.\n", direction);
64 direction_ = 0;
65 return -1;
66 }
67 fwrite(buf, sizeof(char), 3, handle_);
68 fclose(handle_);
69
70 return 0;
71 }
72
73 int Pin::MakeInput() {
74 if (!exported_) {
75 if (DoExport()) {
76 return -1;
77 }
78 }
79
80 return DoPinDirSet(1);
81 }
82
83 int Pin::MakeOutput() {
84 if (!exported_) {
85 if (DoExport()) {
86 return -1;
87 }
88 }
89
90 return DoPinDirSet(2);
91 }
92
93 int Pin::Write(uint8_t value) {
94 if (direction_ != 2) {
95 LOG(ERROR, "Only pins set as output can be written to.\n");
96 return -1;
97 }
98
99 char buf, val_path [64];
100 snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value", kernel_pin_);
101 if (value != 0) {
102 value = 1;
103 }
104
105 if ((handle_ = fopen(val_path, "rb+")) == NULL) {
106 LOG(ERROR, "Unable to set pin value.\n");
107 return -1;
108 }
109
110 snprintf(&buf, sizeof(buf), "%d", value);
111 fwrite(&buf, sizeof(char), 1, handle_);
112 fclose(handle_);
113
114 return 0;
115 }
116
117 int Pin::Read() {
118 // NOTE: I can't find any docs confirming that one can indeed
119 // poll a pin's value using this method, but it seems that it
120 // should work. Really, the "right" (interrupt driven) way to
121 // do this is to set an event, but that involves messing with
122 // dev tree crap, which I'm not willing to do unless we need
123 // this functionality.
124
125 if (direction_ != 1) {
126 LOG(ERROR, "Only pins set as input can be read from.\n");
127 return -1;
128 }
129
130 char buf, val_path [64];
131 snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value", kernel_pin_);
132
133 if ((handle_ = fopen(val_path, "rb")) == NULL) {
134 LOG(ERROR, "Unable to read pin value.\n");
135 return -1;
136 }
137
138 if (fread(&buf, sizeof(char), 1, handle_) <= 0) {
139 LOG(ERROR, "Failed to read pin value from file.\n");
140 return -1;
141 }
142 fclose(handle_);
143 return atoi(&buf);
144 }
145
146} // bbb