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] = "";
57 * Export a GPIO pin and open the file descriptors
59 void GPIO_Export(int pin)
61 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
63 Abort("Not a useable pin number: %d", pin);
66 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
68 sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
69 FILE * export = fopen(g_buffer, "w");
72 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
75 fprintf(export, "%d", pin);
78 // Setup direction file descriptor
79 sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin);
80 gpio->fd_direction = open(g_buffer, O_RDWR);
81 if (gpio->fd_direction < 0)
83 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
87 // Setup value file descriptor
88 sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
89 gpio->fd_value = open(g_buffer, O_RDWR);
90 if (gpio->fd_value < 0)
92 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
95 Log(LOGDEBUG, "Exported GPIO%d", pin);
100 * Unexport a GPIO pin and close its' file descriptors
102 void GPIO_Unexport(int pin)
104 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
106 Abort("Not a useable pin number: %d", pin);
109 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
110 // Close file descriptors
111 close(gpio->fd_value);
112 close(gpio->fd_direction);
116 if (g_buffer[0] == '\0')
117 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);
118 FILE * export = fopen(g_buffer, "w");
121 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
124 fprintf(export, "%d", pin);
132 * Export all PWM pins and open file descriptors
133 * @param pin - The pin number
135 void PWM_Export(int pin)
137 if (pin < 0 || pin > PWM_NUM_PINS)
139 Abort("Invalid pin number %d", pin);
143 sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
144 FILE * export = fopen(g_buffer, "w");
147 Abort("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno));
150 fprintf(export, "%d\n", pin);
153 // Open file descriptors
154 sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
155 g_pwm[pin].fd_run = open(g_buffer, O_WRONLY);
156 if (g_pwm[pin].fd_run < 0)
158 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
161 sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin);
162 g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY);
163 if (g_pwm[pin].fd_polarity < 0)
165 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
168 sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin);
169 g_pwm[pin].file_period = fopen(g_buffer, "w");
170 if (g_pwm[pin].file_period == NULL)
172 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
175 sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin);
176 g_pwm[pin].file_duty = fopen(g_buffer, "w");
177 if (g_pwm[pin].file_duty == NULL)
179 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
182 // Don't buffer the streams
183 setbuf(g_pwm[pin].file_period, NULL);
184 setbuf(g_pwm[pin].file_duty, NULL);
190 * Unexport a PWM pin and close its file descriptors
191 * @param pin - The pin number
193 void PWM_Unexport(int pin)
195 if (pin < 0 || pin > PWM_NUM_PINS)
197 Abort("Invalid pin number %d", pin);
200 // Close the file descriptors
201 close(g_pwm[pin].fd_polarity);
202 close(g_pwm[pin].fd_run);
203 fclose(g_pwm[pin].file_period);
204 fclose(g_pwm[pin].file_duty);
207 sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
208 FILE * export = fopen(g_buffer, "w");
211 Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));
214 fprintf(export, "%d", pin);
219 * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc
220 * Can't use sysfs like GPIO or PWM pins
221 * Bloody annoying how inconsistent stuff is on the Beaglebone
225 for (int i = 0; i < ADC_NUM_PINS; ++i)
227 sprintf(g_buffer, "%s/AIN%d", g_options.adc_device_path, i);
228 g_adc[i].fd_value = open(g_buffer, O_RDONLY);
229 if (g_adc[i].fd_value < 0)
231 Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
234 //setbuf(g_adc[i].file_value, NULL);
244 for (int i = 0; i < ADC_NUM_PINS; ++i)
245 close(g_adc[i].fd_value);
250 * @param pin - The pin to set. MUST have been exported before calling this function.
252 void GPIO_Set(int pin, bool value)
254 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
256 Abort("Not a useable pin number: %d", pin);
259 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
261 if (pwrite(gpio->fd_direction, "out", 3, 0) != 3)
263 Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
266 char c = '0' + (value);
267 if (pwrite(gpio->fd_value, &c, 1, 0) != 1)
269 Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
275 * Read from a GPIO Pin
276 * @param pin - The pin to read
278 bool GPIO_Read(int pin)
280 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
282 Log(LOGERR, "Not a useable pin number: %d", pin);
286 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
288 if (pwrite(gpio->fd_direction, "in", 2, 0) != 2)
289 Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno));
291 if (pread(gpio->fd_value, &c, 1, 0) != 1)
292 Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
300 * @param pin - The pin to activate
301 * @param polarity - if true, pin is active high, else active low
302 * @param period - The period in ns
303 * @param duty - The time the pin is active in ns
305 void PWM_Set(int pin, bool polarity, long period, long duty)
307 Log(LOGDEBUG, "Pin %d, pol %d, period: %lu, duty: %lu", pin, polarity, period, duty);
309 rewind(g_pwm[pin].file_duty);
311 if (fprintf(g_pwm[pin].file_duty, "0") == 0)
313 Abort("Couldn't zero the duty cycle for PWM %d - s", pin, strerror(errno));
316 // Have to stop PWM before changing it
317 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
319 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
322 char c = '0' + polarity;
323 if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1)
325 Abort("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
328 rewind(g_pwm[pin].file_period);
329 rewind(g_pwm[pin].file_duty);
330 if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0)
332 Abort("Couldn't set period for PWM %d - %s", pin, strerror(errno));
335 if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0)
337 Abort("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
340 if (pwrite(g_pwm[pin].fd_run, "1", 1, 0) != 1)
342 Abort("Couldn't start PWM %d - %s", pin, strerror(errno));
348 * Deactivate a PWM pin
349 * @param pin - The pin to turn off
351 void PWM_Stop(int pin)
353 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
355 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
361 * @param id - The ID of the ADC pin to read
362 * @returns - The reading of the ADC channel
366 char adc_str[ADC_DIGITS] = "";
367 lseek(g_adc[id].fd_value, 0, SEEK_SET);
370 for (i = 0; i < ADC_DIGITS-1; ++i)
372 if (read(g_adc[id].fd_value, adc_str+i, 1) != 1)
374 if (adc_str[i] == '\n')
382 int val = strtol(adc_str, &end, 10);
385 Log(LOGERR, "Read non integer from ADC %d - %s", id, adc_str);