3 * @purpose Implementation of BBB pin control functions and structures
4 * THIS CODE IS NOT THREADSAFE
16 * Structure to represent a GPIO pin
17 * Note: Only accessable to this file; to use the functions pass a GPIOId
26 * Structure to represent an ADC pin
27 * Note: Only accessable to this file; to use the functions pass a ADCId
35 * Structure to represent a PWM pin
36 * Note: Only accessable to this file; to use the functions pass a PWMId
46 /** Array of GPIO pins **/
47 static GPIO_Pin g_gpio[GPIO_NUM_PINS] = {{0}};
48 /** Array of ADC pins **/
49 static ADC_Pin g_adc[ADC_NUM_PINS] = {{0}};
50 /** Array of PWM pins **/
51 static PWM_Pin g_pwm[PWM_NUM_PINS] = {{0}};
53 static char g_buffer[BUFSIZ] = "";
59 * Export a GPIO pin and open the file descriptors
61 void GPIO_Export(int pin)
63 if (pin < 0 || pin > GPIO_NUM_PINS)
65 Abort("Invalid pin number %d", pin);
71 sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
72 FILE * export = fopen(g_buffer, "w");
75 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
78 fprintf(export, "%d", pin);
81 // Setup direction file descriptor
82 sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin);
83 g_gpio[pin].fd_direction = open(g_buffer, O_RDWR);
84 if (g_gpio[pin].fd_direction < 0)
86 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
90 // Setup value file descriptor
91 sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
92 g_gpio[pin].fd_value = open(g_buffer, O_RDWR);
93 if (g_gpio[pin].fd_value < 0)
95 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
98 Log(LOGDEBUG, "Exported GPIO%d", pin);
103 * Unexport a GPIO pin and close its' file descriptors
105 void GPIO_Unexport(int pin)
108 if (pin < 0 || pin > GPIO_NUM_PINS)
110 Abort("Invalid pin number %d", pin);
113 // Close file descriptors
114 close(g_gpio[pin].fd_value);
115 close(g_gpio[pin].fd_direction);
119 if (g_buffer[0] == '\0')
120 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);
121 FILE * export = fopen(g_buffer, "w");
124 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
127 fprintf(export, "%d", pin);
135 * Export all PWM pins and open file descriptors
136 * @param pin - The pin number
138 void PWM_Export(int pin)
140 if (pin < 0 || pin > PWM_NUM_PINS)
142 Abort("Invalid pin number %d", pin);
146 sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
147 FILE * export = fopen(g_buffer, "w");
150 Abort("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno));
153 fprintf(export, "%d\n", pin);
156 // Open file descriptors
157 sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
158 g_pwm[pin].fd_run = open(g_buffer, O_WRONLY);
159 if (g_pwm[pin].fd_run < 0)
161 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
164 sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin);
165 g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY);
166 if (g_pwm[pin].fd_polarity < 0)
168 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
171 sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin);
172 g_pwm[pin].file_period = fopen(g_buffer, "w");
173 if (g_pwm[pin].file_period == NULL)
175 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
178 sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin);
179 g_pwm[pin].file_duty = fopen(g_buffer, "w");
180 if (g_pwm[pin].file_duty == NULL)
182 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
185 // Don't buffer the streams
186 setbuf(g_pwm[pin].file_period, NULL);
187 setbuf(g_pwm[pin].file_duty, NULL);
193 * Unexport a PWM pin and close its file descriptors
194 * @param pin - The pin number
196 void PWM_Unexport(int pin)
198 if (pin < 0 || pin > PWM_NUM_PINS)
200 Abort("Invalid pin number %d", pin);
203 // Close the file descriptors
204 close(g_pwm[pin].fd_polarity);
205 close(g_pwm[pin].fd_run);
206 fclose(g_pwm[pin].file_period);
207 fclose(g_pwm[pin].file_duty);
210 sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
211 FILE * export = fopen(g_buffer, "w");
214 Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));
217 fprintf(export, "%d", pin);
224 * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc
225 * Can't use sysfs like GPIO or PWM pins
226 * Bloody annoying how inconsistent stuff is on the Beaglebone
230 for (int i = 0; i < ADC_NUM_PINS; ++i)
232 sprintf(g_buffer, "%s/AIN%d", g_options.adc_device_path, i);
233 g_adc[i].fd_value = open(g_buffer, O_RDONLY);
234 if (g_adc[i].fd_value < 0)
236 Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
239 //setbuf(g_adc[i].file_value, NULL);
249 for (int i = 0; i < ADC_NUM_PINS; ++i)
250 close(g_adc[i].fd_value);
255 * @param pin - The pin to set. MUST have been exported before calling this function.
257 void GPIO_Set(int pin, bool value)
259 if (pwrite(g_gpio[pin].fd_direction, "out", 3, 0) != 3)
261 Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
264 char c = '0' + (value);
265 if (pwrite(g_gpio[pin].fd_value, &c, 1, 0) != 1)
267 Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
273 * Read from a GPIO Pin
274 * @param pin - The pin to read
276 bool GPIO_Read(int pin)
278 if (pwrite(g_gpio[pin].fd_direction, "in", 2, 0) != 2)
279 Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno));
281 if (pread(g_gpio[pin].fd_value, &c, 1, 0) != 1)
282 Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
290 * @param pin - The pin to activate
291 * @param polarity - if true, pin is active high, else active low
292 * @param period - The period in ns
293 * @param duty - The time the pin is active in ns
295 void PWM_Set(int pin, bool polarity, long period, long duty)
297 // Have to stop PWM before changing it
298 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
300 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
303 char c = '0' + polarity;
304 if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1)
306 Abort("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
309 rewind(g_pwm[pin].file_period);
310 rewind(g_pwm[pin].file_duty);
312 if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0)
314 Abort("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
316 if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0)
318 Abort("Couldn't set period for PWM %d - %s", pin, strerror(errno));
320 if (pwrite(g_pwm[pin].fd_run, "1", 1, 0) != 1)
322 Abort("Couldn't start PWM %d - %s", pin, strerror(errno));
328 * Deactivate a PWM pin
329 * @param pin - The pin to turn off
331 void PWM_Stop(int pin)
333 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
335 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
341 * @param id - The ID of the ADC pin to read
342 * @returns - The reading of the ADC channel
346 char adc_str[ADC_DIGITS] = "";
347 lseek(g_adc[id].fd_value, 0, SEEK_SET);
350 for (i = 0; i < ADC_DIGITS-1; ++i)
352 if (read(g_adc[id].fd_value, adc_str+i, 1) != 1)
354 if (adc_str[i] == '\n')
362 int val = strtol(adc_str, &end, 10);
365 Log(LOGERR, "Read non integer from ADC %d - %s", id, adc_str);