3 * @purpose Implementation of BBB pin control functions and structures
4 * THIS CODE IS NOT THREADSAFE
14 * Structure to represent a GPIO pin
15 * Note: Only accessable to this file; to use the functions pass a GPIOId
24 * Structure to represent an ADC pin
25 * Note: Only accessable to this file; to use the functions pass a ADCId
33 * Structure to represent a PWM pin
34 * Note: Only accessable to this file; to use the functions pass a PWMId
44 /** Array of GPIO pins **/
45 static GPIO_Pin g_gpio[GPIO_NUM_PINS] = {{0}};
46 /** Array of ADC pins **/
47 static ADC_Pin g_adc[ADC_NUM_PINS] = {{0}};
48 /** Array of PWM pins **/
49 static PWM_Pin g_pwm[PWM_NUM_PINS] = {{0}};
51 static char g_buffer[BUFSIZ] = "";
57 * Export a GPIO pin and open the file descriptors
59 void GPIO_Export(int pin)
61 if (pin < 0 || pin > GPIO_NUM_PINS)
62 Fatal("Invalid pin number %d", pin);
67 sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
68 FILE * export = fopen(g_buffer, "w");
70 Fatal("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
72 fprintf(export, "%d", pin);
75 // Setup direction file descriptor
76 sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin);
77 g_gpio[pin].fd_direction = open(g_buffer, O_RDWR);
78 if (g_gpio[pin].fd_direction < 0)
79 Fatal("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
82 // Setup value file descriptor
83 sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
84 g_gpio[pin].fd_value = open(g_buffer, O_RDWR);
85 if (g_gpio[pin].fd_value < 0)
86 Fatal("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
90 * Unexport a GPIO pin and close its' file descriptors
92 void GPIO_Unexport(int pin)
95 if (pin < 0 || pin > GPIO_NUM_PINS)
96 Fatal("Invalid pin number %d", pin);
98 // Close file descriptors
99 close(g_gpio[pin].fd_value);
100 close(g_gpio[pin].fd_direction);
104 if (g_buffer[0] == '\0')
105 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);
106 FILE * export = fopen(g_buffer, "w");
108 Fatal("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
110 fprintf(export, "%d", pin);
118 * Export all PWM pins and open file descriptors
119 * @param pin - The pin number
121 void PWM_Export(int pin)
123 if (pin < 0 || pin > PWM_NUM_PINS)
124 Fatal("Invalid pin number %d", pin);
127 sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
128 FILE * export = fopen(g_buffer, "w");
130 Fatal("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno));
132 fprintf(export, "%d", pin);
135 // Open file descriptors
136 sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
137 g_pwm[pin].fd_run = open(g_buffer, O_WRONLY);
138 if (g_pwm[pin].fd_run < 0)
139 Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
141 sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin);
142 g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY);
143 if (g_pwm[pin].fd_polarity < 0)
144 Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
146 sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin);
147 g_pwm[pin].file_period = fopen(g_buffer, "w");
148 if (g_pwm[pin].file_period == NULL)
149 Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
151 sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin);
152 g_pwm[pin].file_duty = fopen(g_buffer, "w");
153 if (g_pwm[pin].file_duty == NULL)
154 Fatal("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
156 // Don't buffer the streams
157 setbuf(g_pwm[pin].file_period, NULL);
158 setbuf(g_pwm[pin].file_duty, NULL);
164 * Unexport a PWM pin and close its file descriptors
165 * @param pin - The pin number
167 void PWM_Unexport(int pin)
169 if (pin < 0 || pin > PWM_NUM_PINS)
170 Fatal("Invalid pin number %d", pin);
172 // Close the file descriptors
173 close(g_pwm[pin].fd_polarity);
174 close(g_pwm[pin].fd_run);
175 fclose(g_pwm[pin].file_period);
176 fclose(g_pwm[pin].file_duty);
179 sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
180 FILE * export = fopen(g_buffer, "w");
182 Fatal("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));
184 fprintf(export, "%d", pin);
191 * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc
192 * Can't use sysfs like GPIO or PWM pins
193 * Bloody annoying how inconsistent stuff is on the Beaglebone
198 FILE * export = fopen(ADC_EXPORT_PATH, "w");
200 Fatal("Couldn't open %s to export ADCs - %s", ADC_EXPORT_PATH, strerror(errno));
202 fprintf(export, "cape-bone-iio");
205 for (int i = 0; i < ADC_NUM_PINS; ++i)
207 sprintf(g_buffer, "%s/AIN%d", ADC_DEVICE_PATH, i);
208 g_adc[i].file_value = fopen(g_buffer, "r");
209 if (g_adc[i].file_value == NULL)
210 Fatal("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
212 setbuf(g_adc[i].file_value, NULL);
222 for (int i = 0; i < ADC_NUM_PINS; ++i)
223 fclose(g_adc[i].file_value);
228 * @param pin - The pin to set. MUST have been exported before calling this function.
230 void GPIO_Set(int pin, bool value)
232 if (pwrite(g_gpio[pin].fd_direction, "out", 3*sizeof(char), 0) != 3)
233 Fatal("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
235 char c = '0' + (value);
236 if (pwrite(g_gpio[pin].fd_value, &c, 1*sizeof(char), 0) != 1)
237 Fatal("Couldn't read GPIO %d value - %s", pin, strerror(errno));
242 * Read from a GPIO Pin
243 * @param pin - The pin to read
245 bool GPIO_Read(int pin)
247 if (pwrite(g_gpio[pin].fd_direction, "in", 2*sizeof(char), 0) != 2)
248 Fatal("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
250 if (pread(g_gpio[pin].fd_value, &c, 1*sizeof(char), 0) != 1)
251 Fatal("Couldn't read GPIO %d value - %s", pin, strerror(errno));
259 * @param pin - The pin to activate
260 * @param polarity - if true, pin is active high, else active low
261 * @param period - The period in ns
262 * @param duty - The time the pin is active in ns
264 void PWM_Set(int pin, bool polarity, long period, long duty)
266 // Have to stop PWM before changing it
267 if (pwrite(g_pwm[pin].fd_run, "0", 1*sizeof(char), 0) != 1)
268 Fatal("Couldn't stop PWM %d - %s", pin, strerror(errno));
270 char c = '0' + polarity;
271 if (pwrite(g_pwm[pin].fd_polarity, &c, 1*sizeof(char), 0) != 1)
272 Fatal("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
275 rewind(g_pwm[pin].file_period);
276 rewind(g_pwm[pin].file_duty);
278 if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0)
279 Fatal("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
281 if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0)
282 Fatal("Couldn't set period for PWM %d - %s", pin, strerror(errno));
284 if (pwrite(g_pwm[pin].fd_run, "1", 1*sizeof(char), 0) != 1)
285 Fatal("Couldn't start PWM %d - %s", pin, strerror(errno));
290 * Deactivate a PWM pin
291 * @param pin - The pin to turn off
293 void PWM_Stop(int pin)
295 if (pwrite(g_pwm[pin].fd_run, "0", 1*sizeof(char), 0) != 1)
296 Fatal("Couldn't stop PWM %d - %s", pin, strerror(errno));
302 * @param id - The ID of the ADC pin to read
303 * @returns - The reading of the ADC channel
305 long ADC_Read(int id)
308 //Log(LOGDEBUG, "Called for pin %d", id);
309 char adc_val[ADC_DIGITS] = "";
310 rewind(g_adc[id].file_value);
311 fgets(adc_val, sizeof(adc_val)/sizeof(char), g_adc[id].file_value);
312 for(int i = ADC_DIGITS-1; i > 0; --i)
314 if (adc_val[i] == '\n')
319 long val = strtol(adc_val, &end, 10);
322 Log(LOGERR, "Reading ADC%d gives %s - invalid!", id, adc_val);
324 //Log(LOGDEBUG, "Returns %lu", val);