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);
130 * Initialise all PWM pins and open file descriptors
131 * @param pin - The sysfs pin number
133 void PWM_Export(int pin)
135 if (pin < 0 || pin >= PWM_NUM_PINS)
137 Abort("Invalid PWM pin number %d specified.", pin);
140 PWM_Pin *pwm = &g_pwm[pin];
142 if (pwm->file_duty != NULL)
144 Abort("PWM %d already exported.", pin);
147 // Open file descriptors
148 sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
149 pwm->fd_run = open(g_buffer, O_WRONLY);
152 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
155 sprintf(g_buffer, "%s/pwm%d/polarity", PWM_DEVICE_PATH, pin);
156 pwm->fd_polarity = open(g_buffer, O_WRONLY);
157 if (pwm->fd_polarity < 0)
159 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
162 sprintf(g_buffer, "%s/pwm%d/period_ns", PWM_DEVICE_PATH, pin);
163 pwm->file_period = fopen(g_buffer, "w");
164 if (pwm->file_period == NULL)
166 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
169 sprintf(g_buffer, "%s/pwm%d/duty_ns", PWM_DEVICE_PATH, pin);
170 pwm->file_duty = fopen(g_buffer, "w");
171 if (pwm->file_duty == NULL)
173 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
176 // Don't buffer the streams
177 setbuf(pwm->file_period, NULL);
178 setbuf(pwm->file_duty, NULL);
180 Log(LOGDEBUG, "Exported PWM%d", pin);
184 * Unexport a PWM pin and close its file descriptors
185 * @param pin - The sysfs pin number
187 void PWM_Unexport(int pin)
189 if (pin < 0 || pin >= PWM_NUM_PINS)
191 Abort("Invalid PWM pin number %d specified.", pin);
194 PWM_Pin *pwm = &g_pwm[pin];
195 // Close the file descriptors
196 if (pwm->fd_polarity != -1)
197 close(pwm->fd_polarity);
198 if (pwm->fd_run != -1)
200 if (pwm->file_period != NULL)
201 fclose(pwm->file_period);
202 if (pwm->file_duty != NULL)
203 fclose(pwm->file_duty);
205 //So that another call to PWM_Unexport is OK.
206 pwm->fd_polarity = pwm->fd_run = -1;
207 pwm->file_period = pwm->file_duty = NULL;
212 * Initialise ADC structures
213 * @param pin The ADC pin number
215 void ADC_Export(int pin)
217 if (pin < 0 || pin >= ADC_NUM_PINS)
219 Abort("Invalid ADC pin %d specified.", pin);
222 sprintf(g_buffer, "%s/in_voltage%d_raw", g_options.adc_device_path, pin);
223 g_adc[pin].fd_value = open(g_buffer, O_RDONLY);
224 if (g_adc[pin].fd_value <0)
226 Abort("Couldn't open ADC %d device file %s - %s", pin, g_buffer, strerror(errno));
228 Log(LOGDEBUG, "Opened ADC %d", pin);
233 * @param pin The ADC pin number
235 void ADC_Unexport(int pin)
237 if (pin < 0 || pin >= ADC_NUM_PINS)
239 Abort("Invalid ADC pin %d specified.", pin);
242 close(g_adc[pin].fd_value);
244 g_adc[pin].fd_value = -1;
249 * @param pin - The pin to set. MUST have been exported before calling this function.
251 void GPIO_Set(int pin, bool value)
253 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
255 Abort("Not a useable pin number: %d", pin);
258 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
260 if (pwrite(gpio->fd_direction, "out", 3, 0) != 3)
262 Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
265 char c = '0' + (value);
266 if (pwrite(gpio->fd_value, &c, 1, 0) != 1)
268 Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
274 * Read from a GPIO Pin
275 * @param pin - The pin to read
277 bool GPIO_Read(int pin)
279 if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
281 Log(LOGERR, "Not a useable pin number: %d", pin);
285 GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
287 if (pwrite(gpio->fd_direction, "in", 2, 0) != 2)
288 Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno));
290 if (pread(gpio->fd_value, &c, 1, 0) != 1)
291 Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
299 * @param pin - The sysfs pin number
300 * @param polarity - if true, pin is active high, else active low
301 * @param period - The period in ns
302 * @param duty - The time the pin is active in ns
304 void PWM_Set(int pin, bool polarity, long period, long duty)
306 Log(LOGDEBUG, "Pin %d, pol %d, period: %lu, duty: %lu", pin, polarity, period, duty);
308 if (pin < 0 || pin >= PWM_NUM_PINS)
310 Abort("Invalid PWM pin number %d specified.", pin);
313 PWM_Pin *pwm = &g_pwm[pin];
315 // Have to stop PWM before changing it
316 if (pwrite(pwm->fd_run, "0", 1, 0) != 1)
318 Abort("Couldn't stop PWM%d - %s", pin, strerror(errno));
321 char c = polarity ? '1' : '0';
322 if (pwrite(pwm->fd_polarity, &c, 1, 0) != 1)
324 Abort("Couldn't set PWM%d polarity - %s", pin, strerror(errno));
327 if (fprintf(pwm->file_period, "%lu", period) < 0)
329 Abort("Couldn't set period for PWM%d - %s", pin, strerror(errno));
332 if (fprintf(pwm->file_duty, "%lu", duty) < 0)
334 Abort("Couldn't set duty cycle for PWM%d - %s", pin, strerror(errno));
337 if (pwrite(pwm->fd_run, "1", 1, 0) != 1)
339 Abort("Couldn't start PWM%d - %s", pin, strerror(errno));
344 * Deactivate a PWM pin
345 * @param pin - The syfs pin number
347 void PWM_Stop(int pin)
349 if (pin < 0 || pin >= PWM_NUM_PINS)
351 Abort("Invalid PWM pin number %d specified.", pin);
354 if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
356 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
362 * @param id - The ID of the ADC pin to read
363 * @returns - The reading of the ADC channel
367 char adc_str[ADC_DIGITS] = {0};
369 if (pread(g_adc[id].fd_value, adc_str, ADC_DIGITS-1, 0) == -1)
371 Log(LOGERR, "ADC %d read failed: %s", id, strerror(errno));
375 return strtol(adc_str, NULL, 10);