Interops with non-BBB platforms
[matches/MCTX3420.git] / server / bbb_pin.c
1 /**
2  * @file bbb_pin.c
3  * @purpose Implementation of BBB pin control functions and structures
4  * THIS CODE IS NOT THREADSAFE
5  */
6
7 #define _BBB_PIN_SRC
8 #include "bbb_pin.h"
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <ctype.h>
14 #include "options.h"
15
16 /**
17  * Structure to represent a GPIO pin
18  * Note: Only accessable to this file; to use the functions pass a GPIOId
19  */
20 typedef struct
21 {
22         int fd_value;
23         int fd_direction;
24 } GPIO_Pin;
25
26 /**
27  * Structure to represent an ADC pin
28  * Note: Only accessable to this file; to use the functions pass a ADCId
29  */
30 typedef struct
31 {
32         int fd_value;
33 } ADC_Pin;
34
35 /**
36  * Structure to represent a PWM pin
37  * Note: Only accessable to this file; to use the functions pass a PWMId
38  */
39 typedef struct
40 {
41         int fd_run;
42         FILE * file_duty;
43         FILE * file_period;
44         int fd_polarity;
45 } PWM_Pin;
46
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}};
53
54 static char g_buffer[BUFSIZ] = "";
55
56
57 /**
58  * Export a GPIO pin and open the file descriptors
59  */
60 void GPIO_Export(int pin)
61 {
62         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
63         {
64                 Abort("Not a useable pin number: %d", pin);
65         }
66
67         GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
68         // Export the pin
69         sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
70         FILE * export = fopen(g_buffer, "w");
71         if (export == NULL)
72         {
73                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
74         }
75
76         fprintf(export, "%d", pin);     
77         fclose(export);
78         
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)
83         {
84                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
85         }
86
87
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)
92         {
93                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
94         }
95
96         Log(LOGDEBUG, "Exported GPIO%d", pin);
97         //sleep(1);
98 }
99
100 /**
101  * Unexport a GPIO pin and close its' file descriptors
102  */
103 void GPIO_Unexport(int pin)
104 {
105         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
106         {
107                 Abort("Not a useable pin number: %d", pin);
108         }
109
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);
114
115         // Unexport the pin
116
117         if (g_buffer[0] == '\0')
118                 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);     
119         FILE * export = fopen(g_buffer, "w");
120         if (export == NULL)
121         {
122                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
123         }
124
125         fprintf(export, "%d", pin);     
126         fclose(export);
127 }
128
129
130 /**
131  * Initialise all PWM pins and open file descriptors
132  * @param pin - The sysfs pin number
133  */
134 void PWM_Export(int pin)
135 {
136         if (pin < 0 || pin >= PWM_NUM_PINS)
137         {
138                 Abort("Invalid PWM pin number %d specified.", pin);
139         }
140
141         PWM_Pin *pwm = &g_pwm[pin];
142
143         if (pwm->file_duty != NULL)
144         {
145                 Abort("PWM %d already exported.", pin);
146         }
147
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);
151         if (pwm->fd_run < 0)
152         {
153                 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
154         }
155
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)
159         {
160                 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
161         }
162
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)
166         {
167                 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
168         }
169
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)
173         {
174                 Abort("Couldn't open %s for PWM%d - %s", g_buffer, pin, strerror(errno));
175         }
176
177         // Don't buffer the streams
178         setbuf(pwm->file_period, NULL);
179         setbuf(pwm->file_duty, NULL);   
180
181         Log(LOGDEBUG, "Exported PWM%d", pin);
182 }
183
184 /**
185  * Unexport a PWM pin and close its file descriptors
186  * @param pin - The sysfs pin number
187  */
188 void PWM_Unexport(int pin)
189 {
190         if (pin < 0 || pin >= PWM_NUM_PINS)
191         {
192                 Abort("Invalid PWM pin number %d specified.", pin);
193         }
194
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)
200                 close(pwm->fd_run);
201         if (pwm->file_period != NULL)
202                 fclose(pwm->file_period);
203         if (pwm->file_duty != NULL)
204                 fclose(pwm->file_duty);
205
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;
209 }
210
211
212 /**
213  * Initialise ADC structures
214  * @param pin The ADC pin number
215  */
216 void ADC_Export(int pin)
217 {
218         if (pin < 0 || pin >= ADC_NUM_PINS)
219         {
220                 Abort("Invalid ADC pin %d specified.", pin);
221         }
222
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)
226         {
227                 Abort("Couldn't open ADC %d device file %s - %s", pin, g_buffer, strerror(errno));
228         }
229         Log(LOGDEBUG, "Opened ADC %d", pin);
230 }
231
232 /**
233  * Unexport ADC pins
234  * @param pin The ADC pin number
235  */
236 void ADC_Unexport(int pin)
237 {
238         if (pin < 0 || pin >= ADC_NUM_PINS)
239         {
240                 Abort("Invalid ADC pin %d specified.", pin);
241         }
242         if (pin != -1)
243                 close(g_adc[pin].fd_value);     
244
245         g_adc[pin].fd_value = -1;
246 }
247
248 /**
249  * Set a GPIO pin
250  * @param pin - The pin to set. MUST have been exported before calling this function.
251  */
252 void GPIO_Set(int pin, bool value)
253 {
254         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
255         {
256                 Abort("Not a useable pin number: %d", pin);
257         }
258
259         GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
260
261         if (pwrite(gpio->fd_direction, "out", 3, 0) != 3)
262         {
263                 Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
264         }
265
266         char c = '0' + (value);
267         if (pwrite(gpio->fd_value, &c, 1, 0) != 1)
268         {
269                 Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
270         }
271
272 }
273
274 /** 
275  * Read from a GPIO Pin
276  * @param pin - The pin to read
277  */
278 bool GPIO_Read(int pin)
279 {
280         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
281         {
282                 Log(LOGERR, "Not a useable pin number: %d", pin);
283                 return false;
284         }
285
286         GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
287
288         if (pwrite(gpio->fd_direction, "in", 2, 0) != 2)
289                 Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno)); 
290         char c = '0';
291         if (pread(gpio->fd_value, &c, 1, 0) != 1)
292                 Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
293
294         return (c == '1');
295
296 }
297
298 /**
299  * Activate a PWM pin
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
304  */
305 void PWM_Set(int pin, bool polarity, long period, long duty)
306 {
307         Log(LOGDEBUG, "Pin %d, pol %d, period: %lu, duty: %lu", pin, polarity, period, duty);
308         
309         if (pin < 0 || pin >= PWM_NUM_PINS)
310         {
311                 Abort("Invalid PWM pin number %d specified.", pin);
312         }
313
314         PWM_Pin *pwm = &g_pwm[pin];
315
316         // Have to stop PWM before changing it
317         if (pwrite(pwm->fd_run, "0", 1, 0) != 1)
318         {
319                 Abort("Couldn't stop PWM%d - %s", pin, strerror(errno));
320         }
321
322         char c = polarity ? '1' : '0';
323         if (pwrite(pwm->fd_polarity, &c, 1, 0) != 1)
324         {
325                 Abort("Couldn't set PWM%d polarity - %s", pin, strerror(errno));
326         }
327
328         if (fprintf(pwm->file_period, "%lu", period) < 0)
329         {
330                 Abort("Couldn't set period for PWM%d - %s", pin, strerror(errno));
331         }
332
333         if (fprintf(pwm->file_duty, "%lu", duty) < 0)
334         {
335                 Abort("Couldn't set duty cycle for PWM%d - %s", pin, strerror(errno));
336         }
337
338         if (pwrite(pwm->fd_run, "1", 1, 0) != 1)
339         {
340                 Abort("Couldn't start PWM%d - %s", pin, strerror(errno));
341         }
342 }
343
344 /**
345  * Deactivate a PWM pin
346  * @param pin - The syfs pin number
347  */
348 void PWM_Stop(int pin)
349 {
350         if (pin < 0 || pin >= PWM_NUM_PINS)
351         {
352                 Abort("Invalid PWM pin number %d specified.", pin);
353         }
354
355         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
356         {
357                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
358         }
359 }
360
361 /**
362  * Read an ADC value
363  * @param id - The ID of the ADC pin to read
364  * @returns - The reading of the ADC channel
365  */
366 int ADC_Read(int id)
367 {
368         char adc_str[ADC_DIGITS] = {0};
369
370         if (pread(g_adc[id].fd_value, adc_str, ADC_DIGITS-1, 0) == -1)
371         {
372                 Log(LOGERR, "ADC %d read failed: %s", id, strerror(errno));
373                 return 0;
374         }
375
376         return strtol(adc_str, NULL, 10);
377 }

UCC git Repository :: git.ucc.asn.au