3 * @brief Implementation of BBB pin control functions and structures
4 * On non-beaglebone (actually non-arm) platforms, this code is disabled.
5 * THIS CODE IS NOT THREADSAFE
11 #include <sys/types.h>
17 * Structure to represent a GPIO pin
18 * Note: Only accessable to this file; to use the functions pass a GPIOId
28 * Structure to represent an ADC pin
29 * Note: Only accessable to this file; to use the functions pass a ADCId
38 * Structure to represent a PWM pin
39 * Note: Only accessable to this file; to use the functions pass a PWMId
50 /** Array of GPIO pins **/
51 static GPIO_Pin g_gpio[GPIO_NUM_PINS] = {{0}};
52 /** Array of ADC pins **/
53 static ADC_Pin g_adc[ADC_NUM_PINS] = {{0}};
54 /** Array of PWM pins **/
55 static PWM_Pin g_pwm[PWM_NUM_PINS] = {{0}};
57 static char g_buffer[BUFSIZ] = {0};
60 * Maps a GPIO number to an index into g_gpio (only for use in bbb_pin.c)
61 * If there is no index for that GPIO number, 128 is returned.
63 const unsigned char g_pin_gpio_to_index[GPIO_MAX_NUMBER+1] = {
64 128, 128, 128, 128, 0, 1, 128, 128, 2, 3, 4, 5, 128, 128,
65 6, 7, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 8, 9,
66 128, 128, 10, 11, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
67 128, 128, 12, 13, 14, 15, 16, 17, 128, 128, 128, 128, 128, 128,
68 128, 128, 128, 128, 18, 19, 128, 128, 128, 20, 21, 22, 23, 24,
69 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 128, 128,
70 128, 128, 37, 38, 39, 40, 128, 128, 128, 128, 128, 128, 128, 128,
71 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
76 * Maps an index in g_gpio to the corresponding GPIO number.
78 const unsigned char g_pin_index_to_gpio[GPIO_NUM_PINS] = {
79 4, 5, 8, 9, 10, 11, 14, 15, 26, 27, 30, 31, 44, 45,
80 46, 47, 48, 49, 60, 61, 65, 66, 67, 68, 69, 70, 71, 72,
81 73, 74, 75, 76, 77, 78, 79, 80, 81, 86, 87, 88, 89, 112,
86 * Export a GPIO pin and open the file descriptors
87 * @param pin The GPIO number to be exported
88 * @return true on success, false otherwise
90 bool GPIO_Export(int pin)
92 if (pin < 0 || pin > GPIO_MAX_NUMBER || g_pin_gpio_to_index[pin] == 128)
94 AbortBool("Not a useable pin number: %d", pin);
97 GPIO_Pin *gpio = &g_gpio[g_pin_gpio_to_index[pin]];
98 if (gpio->initialised)
100 Log(LOGNOTE, "GPIO %d already initialised.", pin);
105 sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
106 FILE * file_export = fopen(g_buffer, "w");
107 if (file_export == NULL)
109 AbortBool("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
111 fprintf(file_export, "%d", pin);
114 // Setup direction file descriptor
115 sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin);
116 gpio->fd_direction = open(g_buffer, O_RDWR);
117 if (gpio->fd_direction < 0)
119 AbortBool("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
122 // Setup value file descriptor
123 sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
124 gpio->fd_value = open(g_buffer, O_RDWR);
125 if (gpio->fd_value < 0)
127 close(gpio->fd_direction);
128 AbortBool("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
131 gpio->initialised = true;
132 Log(LOGDEBUG, "Exported GPIO%d", pin);
137 * Unexport a GPIO pin and close its' file descriptors
138 * @param pin The GPIO number to be unexported
140 void GPIO_Unexport(int pin)
142 if (pin < 0 || pin > GPIO_MAX_NUMBER || g_pin_gpio_to_index[pin] == 128)
144 Abort("Not a useable pin number: %d", pin);
147 GPIO_Pin *gpio = &g_gpio[g_pin_gpio_to_index[pin]];
148 if (!gpio->initialised)
150 Abort("GPIO %d is already uninitialised", pin);
153 // Close file descriptors
154 close(gpio->fd_value);
155 close(gpio->fd_direction);
156 // Uninitialise this one
157 gpio->initialised = false;
160 if (g_buffer[0] == '\0')
161 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);
162 FILE * file_export = fopen(g_buffer, "w");
163 if (file_export == NULL)
165 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
168 fprintf(file_export, "%d", pin);
173 * Initialise all PWM pins and open file descriptors
174 * @param pin - The sysfs pin number
175 * @return true if exported, false otherwise
177 bool PWM_Export(int pin)
179 //goto would make this easier...
180 if (pin < 0 || pin >= PWM_NUM_PINS)
182 AbortBool("Invalid PWM pin %d specified.", pin);
185 PWM_Pin *pwm = &g_pwm[pin];
186 if (pwm->initialised)
188 Log(LOGNOTE, "PWM %d already exported.", pin);
192 // Try export the pin, doesn't matter if it's already exported.
193 sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
194 FILE * file_export = fopen(g_buffer, "w");
195 if (file_export == NULL)
197 AbortBool("Couldn't open %s to export PWM pin %d - %s",
198 g_buffer, pin, strerror(errno));
200 fprintf(file_export, "%d\n", pin);
203 // Open file descriptors
204 sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
205 pwm->fd_run = open(g_buffer, O_WRONLY);
208 AbortBool("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
211 sprintf(g_buffer, "%s/pwm%d/polarity", PWM_DEVICE_PATH, pin);
212 pwm->fd_polarity = open(g_buffer, O_WRONLY);
213 if (pwm->fd_polarity < 0)
216 AbortBool("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
219 sprintf(g_buffer, "%s/pwm%d/period_ns", PWM_DEVICE_PATH, pin);
220 pwm->file_period = fopen(g_buffer, "w");
221 if (pwm->file_period == NULL)
224 close(pwm->fd_polarity);
225 AbortBool("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
228 sprintf(g_buffer, "%s/pwm%d/duty_ns", PWM_DEVICE_PATH, pin);
229 pwm->file_duty = fopen(g_buffer, "w");
230 if (pwm->file_duty == NULL)
233 close(pwm->fd_polarity);
234 fclose(pwm->file_period);
235 AbortBool("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
238 // Don't buffer the streams
239 setbuf(pwm->file_period, NULL);
240 setbuf(pwm->file_duty, NULL);
242 pwm->initialised = true;
243 Log(LOGDEBUG, "Exported PWM%d", pin);
249 * Unexport a PWM pin and close its file descriptors
250 * @param pin - The sysfs pin number
252 void PWM_Unexport(int pin)
254 if (pin < 0 || pin >= PWM_NUM_PINS)
256 Abort("Invalid PWM pin number %d specified.", pin);
259 PWM_Pin *pwm = &g_pwm[pin];
260 if (!pwm->initialised)
262 Abort("PWM %d not initialised", pin);
265 // Close the file descriptors
266 close(pwm->fd_polarity);
267 //Stop it, if it's still running
268 pwrite(pwm->fd_run, "0", 1, 0);
270 fclose(pwm->file_period);
271 fclose(pwm->file_duty);
273 pwm->initialised = false;
275 // Try unexport the pin, doesn't matter if it's already unexported.
276 sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
277 FILE * file_unexport = fopen(g_buffer, "w");
278 if (file_unexport == NULL)
280 Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));
282 fprintf(file_unexport, "%d\n", pin);
283 fclose(file_unexport);
287 * Initialise ADC structures
288 * @param pin The ADC pin number
290 bool ADC_Export(int pin)
292 if (pin < 0 || pin >= ADC_NUM_PINS)
294 AbortBool("Invalid ADC pin %d specified.", pin);
296 else if (g_adc[pin].initialised)
298 Log(LOGNOTE, "ADC %d already initialised", pin);
302 sprintf(g_buffer, "%s/in_voltage%d_raw", ADC_DEVICE_PATH, pin);
303 g_adc[pin].fd_value = open(g_buffer, O_RDONLY);
304 if (g_adc[pin].fd_value <0)
306 AbortBool("Couldn't open ADC %d device file %s - %s", pin, g_buffer, strerror(errno));
309 g_adc[pin].initialised = true;
310 Log(LOGDEBUG, "Opened ADC %d", pin);
316 * @param pin The ADC pin number
318 void ADC_Unexport(int pin)
320 if (pin < 0 || pin >= ADC_NUM_PINS)
322 Abort("Invalid ADC pin %d specified.", pin);
324 else if (!g_adc[pin].initialised)
326 Abort("ADC %d already uninitialised", pin);
329 close(g_adc[pin].fd_value);
330 g_adc[pin].fd_value = -1;
331 g_adc[pin].initialised = false;
336 * @param pin - The pin to set. MUST have been exported before calling this function.
338 bool GPIO_Set(int pin, bool value)
340 if (pin < 0 || pin > GPIO_MAX_NUMBER || g_pin_gpio_to_index[pin] == 128)
342 AbortBool("Not a useable pin number: %d", pin);
345 GPIO_Pin *gpio = &g_gpio[g_pin_gpio_to_index[pin]];
346 if (!gpio->initialised)
348 AbortBool("GPIO %d is not initialised.", pin);
350 //Set the pin direction
351 if (pwrite(gpio->fd_direction, "out", 3, 0) != 3)
353 AbortBool("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
356 char c = value ? '1' : '0';
357 if (pwrite(gpio->fd_value, &c, 1, 0) != 1)
359 AbortBool("Couldn't read GPIO %d value - %s", pin, strerror(errno));
366 * Read from a GPIO Pin
367 * @param pin - The pin to read
368 * @param result A pointer to store the result
369 * @return true on success, false otherwise
371 bool GPIO_Read(int pin, bool *result)
373 if (pin < 0 || pin > GPIO_MAX_NUMBER || g_pin_gpio_to_index[pin] == 128)
375 AbortBool("Not a useable pin number: %d", pin);
378 GPIO_Pin *gpio = &g_gpio[g_pin_gpio_to_index[pin]];
379 if (!gpio->initialised)
381 AbortBool("GPIO %d is not initialised.", pin);
384 if (pwrite(gpio->fd_direction, "in", 2, 0) != 2)
386 AbortBool("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
390 if (pread(gpio->fd_value, &c, 1, 0) != 1)
392 AbortBool("Couldn't read GPIO %d value - %s", pin, strerror(errno));
395 *result = (c == '1');
401 * @param pin - The sysfs pin number
402 * @param polarity - if true, pin is active high, else active low
403 * @param period - The period in ns
404 * @param duty - The time the pin is active in ns
406 bool PWM_Set(int pin, bool polarity, long period, long duty)
408 Log(LOGDEBUG, "Pin %d, pol %d, period: %lu, duty: %lu", pin, polarity, period, duty);
410 if (pin < 0 || pin >= PWM_NUM_PINS)
412 AbortBool("Invalid PWM pin number %d specified.", pin);
415 PWM_Pin *pwm = &g_pwm[pin];
416 if (!pwm->initialised)
418 AbortBool("PWM %d is not initialised.", pin);
421 // Have to stop PWM before changing it
422 if (pwrite(pwm->fd_run, "0", 1, 0) != 1)
424 AbortBool("Couldn't stop PWM %d - %s", pin, strerror(errno));
427 char c = polarity ? '1' : '0';
428 if (pwrite(pwm->fd_polarity, &c, 1, 0) != 1)
430 AbortBool("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
433 //This must be done first, otherwise period/duty settings can conflict
434 if (fwrite("0", 1, 1, pwm->file_duty) < 1)
436 AbortBool("Couldn't zero the duty for PWM %d - %s", pin, strerror(errno));
439 if (fprintf(pwm->file_period, "%lu", period) < 0)
441 AbortBool("Couldn't set period for PWM %d - %s", pin, strerror(errno));
445 if (fprintf(pwm->file_duty, "%lu", duty) < 0)
447 AbortBool("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
451 if (pwrite(pwm->fd_run, "1", 1, 0) != 1)
453 AbortBool("Couldn't start PWM %d - %s", pin, strerror(errno));
460 * Deactivate a PWM pin
461 * @param pin - The syfs pin number
462 * @return true on success, false otherwise
464 bool PWM_Stop(int pin)
466 if (pin < 0 || pin >= PWM_NUM_PINS)
468 AbortBool("Invalid PWM pin number %d specified.", pin);
470 else if (!g_pwm[pin].initialised)
472 AbortBool("PWM %d is not initialised.", pin);
475 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
477 AbortBool("Couldn't stop PWM %d - %s", pin, strerror(errno));
485 * @param id - The ID of the ADC pin to read
486 * @param value - A pointer to store the value read from the ADC
487 * @returns - The true if succeeded, false otherwise.
489 bool ADC_Read(int id, int *value)
491 char adc_str[ADC_DIGITS] = {0};
493 if (id < 0 || id >= ADC_NUM_PINS)
495 AbortBool("Invalid ADC pin %d specified.", id);
497 else if (!g_adc[id].initialised)
499 AbortBool("ADC %d is not initialised.", id);
502 if (pread(g_adc[id].fd_value, adc_str, ADC_DIGITS-1, 0) == -1)
504 //AbortBool("ADC %d read failed: %s", id, strerror(errno));
508 *value = strtol(adc_str, NULL, 10);
513 //For running on systems that are not the BBB
514 bool True_Stub(int arg, ...) { return true; }
515 bool ADC_Read_Stub(int *val, ...) { *val = 0; return true; }
516 bool GPIO_Read_Stub(bool *val, ...) { *val = false; return true; }