3 * @purpose Implementation of BBB pin control functions and structures
4 * THIS CODE IS NOT THREADSAFE
10 #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
27 * Structure to represent an ADC pin
28 * Note: Only accessable to this file; to use the functions pass a ADCId
36 * Structure to represent a PWM pin
37 * Note: Only accessable to this file; to use the functions pass a PWMId
47 /** Array of GPIO pins **/
48 static GPIO_Pin g_gpio[GPIO_NUM_PINS] = {{0}};
49 /** Array of ADC pins **/
50 static ADC_Pin g_adc[ADC_NUM_PINS] = {{0}};
51 /** Array of PWM pins **/
52 static PWM_Pin g_pwm[PWM_NUM_PINS] = {{0}};
54 static char g_buffer[BUFSIZ] = "";
58 * Export a GPIO pin and open the file descriptors
60 void GPIO_Export(int pin)
62 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
64 Abort("Not a useable pin number: %d", pin);
67 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
69 sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
70 FILE * export = fopen(g_buffer, "w");
73 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
76 fprintf(export, "%d", pin);
79 // Setup direction file descriptor
80 sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin);
81 gpio->fd_direction = open(g_buffer, O_RDWR);
82 if (gpio->fd_direction < 0)
84 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
88 // Setup value file descriptor
89 sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
90 gpio->fd_value = open(g_buffer, O_RDWR);
91 if (gpio->fd_value < 0)
93 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
96 Log(LOGDEBUG, "Exported GPIO%d", pin);
101 * Unexport a GPIO pin and close its' file descriptors
103 void GPIO_Unexport(int pin)
105 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
107 Abort("Not a useable pin number: %d", pin);
110 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
111 // Close file descriptors
112 close(gpio->fd_value);
113 close(gpio->fd_direction);
117 if (g_buffer[0] == '\0')
118 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);
119 FILE * export = fopen(g_buffer, "w");
122 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
125 fprintf(export, "%d", pin);
131 * Initialise all PWM pins and open file descriptors
132 * @param pin - The sysfs pin number
134 void PWM_Export(int pin)
136 if (pin < 0 || pin >= PWM_NUM_PINS)
138 Abort("Invalid PWM pin number %d specified.", pin);
141 PWM_Pin *pwm = &g_pwm[pin];
143 if (pwm->file_duty != NULL)
145 Abort("PWM %d already exported.", pin);
148 // Open file descriptors
149 sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
150 pwm->fd_run = open(g_buffer, O_WRONLY);
153 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
156 sprintf(g_buffer, "%s/pwm%d/polarity", PWM_DEVICE_PATH, pin);
157 pwm->fd_polarity = open(g_buffer, O_WRONLY);
158 if (pwm->fd_polarity < 0)
160 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
163 sprintf(g_buffer, "%s/pwm%d/period_ns", PWM_DEVICE_PATH, pin);
164 pwm->file_period = fopen(g_buffer, "w");
165 if (pwm->file_period == NULL)
167 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
170 sprintf(g_buffer, "%s/pwm%d/duty_ns", PWM_DEVICE_PATH, pin);
171 pwm->file_duty = fopen(g_buffer, "w");
172 if (pwm->file_duty == NULL)
174 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
177 // Don't buffer the streams
178 setbuf(pwm->file_period, NULL);
179 setbuf(pwm->file_duty, NULL);
181 Log(LOGDEBUG, "Exported PWM%d", pin);
185 * Unexport a PWM pin and close its file descriptors
186 * @param pin - The sysfs pin number
188 void PWM_Unexport(int pin)
190 if (pin < 0 || pin >= PWM_NUM_PINS)
192 Abort("Invalid PWM pin number %d specified.", pin);
195 PWM_Pin *pwm = &g_pwm[pin];
196 // Close the file descriptors
197 if (pwm->fd_polarity != -1)
198 close(pwm->fd_polarity);
199 if (pwm->fd_run != -1)
201 if (pwm->file_period != NULL)
202 fclose(pwm->file_period);
203 if (pwm->file_duty != NULL)
204 fclose(pwm->file_duty);
206 //So that another call to PWM_Unexport is OK.
207 pwm->fd_polarity = pwm->fd_run = -1;
208 pwm->file_period = pwm->file_duty = NULL;
213 * Initialise ADC structures
214 * @param pin The ADC pin number
216 void ADC_Export(int pin)
218 if (pin < 0 || pin >= ADC_NUM_PINS)
220 Abort("Invalid ADC pin %d specified.", pin);
223 sprintf(g_buffer, "%s/in_voltage%d_raw", g_options.adc_device_path, pin);
224 g_adc[pin].fd_value = open(g_buffer, O_RDONLY);
225 if (g_adc[pin].fd_value <0)
227 Abort("Couldn't open ADC %d device file %s - %s", pin, g_buffer, strerror(errno));
229 Log(LOGDEBUG, "Opened ADC %d", pin);
234 * @param pin The ADC pin number
236 void ADC_Unexport(int pin)
238 if (pin < 0 || pin >= ADC_NUM_PINS)
240 Abort("Invalid ADC pin %d specified.", pin);
243 close(g_adc[pin].fd_value);
245 g_adc[pin].fd_value = -1;
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 sysfs pin number
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 if (pin < 0 || pin >= PWM_NUM_PINS)
311 Abort("Invalid PWM pin number %d specified.", pin);
314 PWM_Pin *pwm = &g_pwm[pin];
316 // Have to stop PWM before changing it
317 if (pwrite(pwm->fd_run, "0", 1, 0) != 1)
319 Abort("Couldn't stop PWM%d - %s", pin, strerror(errno));
322 char c = polarity ? '1' : '0';
323 if (pwrite(pwm->fd_polarity, &c, 1, 0) != 1)
325 Abort("Couldn't set PWM%d polarity - %s", pin, strerror(errno));
328 if (fprintf(pwm->file_period, "%lu", period) < 0)
330 Abort("Couldn't set period for PWM%d - %s", pin, strerror(errno));
333 if (fprintf(pwm->file_duty, "%lu", duty) < 0)
335 Abort("Couldn't set duty cycle for PWM%d - %s", pin, strerror(errno));
338 if (pwrite(pwm->fd_run, "1", 1, 0) != 1)
340 Abort("Couldn't start PWM%d - %s", pin, strerror(errno));
345 * Deactivate a PWM pin
346 * @param pin - The syfs pin number
348 void PWM_Stop(int pin)
350 if (pin < 0 || pin >= PWM_NUM_PINS)
352 Abort("Invalid PWM pin number %d specified.", pin);
355 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
357 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
363 * @param id - The ID of the ADC pin to read
364 * @returns - The reading of the ADC channel
368 char adc_str[ADC_DIGITS] = {0};
370 if (pread(g_adc[id].fd_value, adc_str, ADC_DIGITS-1, 0) == -1)
372 Log(LOGERR, "ADC %d read failed: %s", id, strerror(errno));
376 return strtol(adc_str, NULL, 10);