partial fix to gpio stuff (limit what can be exported)
[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 #include "bbb_pin.h"
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <ctype.h>
13 #include "options.h"
14
15 /**
16  * Structure to represent a GPIO pin
17  * Note: Only accessable to this file; to use the functions pass a GPIOId
18  */
19 typedef struct
20 {
21         int fd_value;
22         int fd_direction;
23 } GPIO_Pin;
24
25 /**
26  * Structure to represent an ADC pin
27  * Note: Only accessable to this file; to use the functions pass a ADCId
28  */
29 typedef struct
30 {
31         int fd_value;
32 } ADC_Pin;
33
34 /**
35  * Structure to represent a PWM pin
36  * Note: Only accessable to this file; to use the functions pass a PWMId
37  */
38 typedef struct
39 {
40         int fd_run;
41         FILE * file_duty;
42         FILE * file_period;
43         int fd_polarity;
44 } PWM_Pin;
45
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}};
52
53 static char g_buffer[BUFSIZ] = "";
54
55 #define GPIO_LUT_SIZE 93
56 #define GPIO_INDEX_SIZE 128
57
58 /** 
59  * A lookup table from header number to GPIO pin number.
60  * e.g P8_13 is g_gpio_lut[0*46+13] = g_gpio_lut[13]
61  * e.g P9_13 is g_gpio_lut[1*46+13] = g_gpio_lut[59]
62  *
63  * Where the returned value is 0, there is no GPIO pin
64  * at that location.
65  */
66 const unsigned char g_gpio_lut[GPIO_LUT_SIZE] = {
67           0,   0,   0,   0,   0,   0,   0,  66,  67,  69,  68,  45,  44,  23,
68          26,  47,  46,  27,  65,  22,   0,   0,   0,   0,   0,   0,  61,  86,
69          88,  87,  89,  10,  11,   9,  81,   8,  80,  78,  79,  76,  77,  74,
70          75,  72,  73,  70,  71,   0,   0,   0,   0,   0,   0,   0,   0,   0,
71           0,  30,  60,  31,  50,  48,  51,   5,   4,   0,   0,   3,   2,  49,
72          15, 117,  14, 115,   0,   0, 112,   0,   0,   0,   0,   0,   0,   0,
73           0,   0,   0,   0,   0,   0,   0,   0,   0
74 };
75
76 /**
77  * Converts GPIO number to index into g_gpio, or 128 if no map.
78  */
79 const unsigned char g_gpio_index[GPIO_INDEX_SIZE] = {
80         128, 128,   0,   1,   2,   3, 128, 128,   4,   5,   6,   7, 128, 128,
81           8,   9, 128, 128, 128, 128, 128, 128,  10,  11, 128, 128,  12,  13,
82         128, 128,  14,  15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
83         128, 128,  16,  17,  18,  19,  20,  21,  22,  23, 128, 128, 128, 128,
84         128, 128, 128, 128,  24,  25, 128, 128, 128,  26,  27,  28,  29,  30,
85          31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42, 128, 128,
86         128, 128,  43,  44,  45,  46, 128, 128, 128, 128, 128, 128, 128, 128,
87         128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
88          47, 128, 128,  48, 128,  49, 128, 128, 128, 128, 128, 128, 128, 128,
89         128, 128
90 };
91
92 /**
93  * Export a GPIO pin and open the file descriptors
94  */
95 void GPIO_Export(int pin)
96 {
97         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_index[pin] == 128)
98         {
99                 Abort("Not a useable pin (number %d)", pin);
100         }
101
102         // Export the pin
103         sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
104         FILE * export = fopen(g_buffer, "w");
105         if (export == NULL)
106         {
107                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
108         }
109
110         fprintf(export, "%d", pin);     
111         fclose(export);
112         
113         GPIO_Pin *gpio = &g_gpio[g_gpio_index[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)
118         {
119                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
120         }
121
122
123         // Setup value file descriptor
124         sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
125         gpio->fd_value = open(g_buffer, O_RDWR);
126         if (gpio->fd_value < 0)
127         {
128                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
129         }
130
131         Log(LOGDEBUG, "Exported GPIO%d", pin);
132         //sleep(1);
133 }
134
135 /**
136  * Unexport a GPIO pin and close its' file descriptors
137  */
138 void GPIO_Unexport(int pin)
139 {
140
141         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_index[pin] == 128)
142         {
143                 Abort("Not a useable pin (number %d)", pin);
144         }
145
146         GPIO_Pin *gpio = &g_gpio[g_gpio_index[pin]];
147         // Close file descriptors
148         close(gpio->fd_value);
149         close(gpio->fd_direction);
150
151         // Unexport the pin
152
153         if (g_buffer[0] == '\0')
154                 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);     
155         FILE * export = fopen(g_buffer, "w");
156         if (export == NULL)
157         {
158                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
159         }
160
161         fprintf(export, "%d", pin);     
162         fclose(export);
163 }
164
165
166
167
168 /**
169  * Export all PWM pins and open file descriptors
170  * @param pin - The pin number
171  */
172 void PWM_Export(int pin)
173 {
174         if (pin < 0 || pin > PWM_NUM_PINS)
175         {
176                 Abort("Invalid pin number %d", pin);
177         }
178         
179         // Export the pin
180         sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
181         FILE * export = fopen(g_buffer, "w");
182         if (export == NULL)
183         {
184                 Abort("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno));
185         }
186         
187         fprintf(export, "%d\n", pin);
188         fclose(export);
189
190         // Open file descriptors
191         sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
192         g_pwm[pin].fd_run = open(g_buffer, O_WRONLY);
193         if (g_pwm[pin].fd_run < 0)
194         {
195                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
196         }
197
198         sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin);
199         g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY);
200         if (g_pwm[pin].fd_polarity < 0)
201         {
202                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
203         }
204
205         sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin);
206         g_pwm[pin].file_period = fopen(g_buffer, "w");
207         if (g_pwm[pin].file_period == NULL)
208         {
209                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
210         }
211
212         sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin);
213         g_pwm[pin].file_duty = fopen(g_buffer, "w");
214         if (g_pwm[pin].file_duty == NULL)
215         {
216                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
217         }
218
219         // Don't buffer the streams
220         setbuf(g_pwm[pin].file_period, NULL);
221         setbuf(g_pwm[pin].file_duty, NULL);
222
223         
224 }
225
226 /**
227  * Unexport a PWM pin and close its file descriptors
228  * @param pin - The pin number
229  */
230 void PWM_Unexport(int pin)
231 {
232         if (pin < 0 || pin > PWM_NUM_PINS)
233         {
234                 Abort("Invalid pin number %d", pin);
235         }
236
237         // Close the file descriptors
238         close(g_pwm[pin].fd_polarity);
239         close(g_pwm[pin].fd_run);
240         fclose(g_pwm[pin].file_period);
241         fclose(g_pwm[pin].file_duty);
242
243         //Unexport the pin
244         sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
245         FILE * export = fopen(g_buffer, "w");
246         if (export == NULL)
247         {
248                 Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));  
249         }
250         
251         fprintf(export, "%d", pin);
252         fclose(export);
253 }
254
255 /**
256  * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc
257  * Can't use sysfs like GPIO or PWM pins
258  * Bloody annoying how inconsistent stuff is on the Beaglebone
259  */
260 void ADC_Export()
261 {
262         for (int i = 0; i < ADC_NUM_PINS; ++i)
263         {
264                 sprintf(g_buffer, "%s/AIN%d", g_options.adc_device_path, i);
265                 g_adc[i].fd_value = open(g_buffer, O_RDONLY);
266                 if (g_adc[i].fd_value < 0)
267                 {
268                         Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
269                 }
270
271                 //setbuf(g_adc[i].file_value, NULL);
272
273         }
274 }
275
276 /**
277  * Unexport ADC pins
278  */
279 void ADC_Unexport()
280 {
281         for (int i = 0; i < ADC_NUM_PINS; ++i)
282                 close(g_adc[i].fd_value);
283 }
284
285 /**
286  * Set a GPIO pin
287  * @param pin - The pin to set. MUST have been exported before calling this function.
288  */
289 void GPIO_Set(int pin, bool value)
290 {
291         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_index[pin] == 128)
292         {
293                 Abort("Not a useable pin (number %d)", pin);
294         }
295
296         GPIO_Pin *gpio = &g_gpio[g_gpio_index[pin]];
297         if (pwrite(gpio->fd_direction, "out", 3, 0) != 3)
298         {
299                 Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
300         }
301
302         char c = '0' + (value);
303         if (pwrite(gpio->fd_value, &c, 1, 0) != 1)
304         {
305                 Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
306         }
307
308 }
309
310 /** 
311  * Read from a GPIO Pin
312  * @param pin - The pin to read
313  */
314 bool GPIO_Read(int pin)
315 {
316         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_index[pin] == 128)
317         {
318                 Log(LOGERR, "Not a useable pin (number %d)", pin);
319                 return false;
320         }
321
322         GPIO_Pin *gpio = &g_gpio[g_gpio_index[pin]];
323         if (pwrite(gpio->fd_direction, "in", 2, 0) != 2)
324                 Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno)); 
325         char c = '0';
326         if (pread(gpio->fd_value, &c, 1, 0) != 1)
327                 Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
328
329         return (c == '1');
330
331 }
332
333 /**
334  * Activate a PWM pin
335  * @param pin - The pin to activate
336  * @param polarity - if true, pin is active high, else active low
337  * @param period - The period in ns
338  * @param duty - The time the pin is active in ns
339  */
340 void PWM_Set(int pin, bool polarity, long period, long duty)
341 {
342         Log(LOGDEBUG, "Pin %d, pol %d, period: %lu, duty: %lu", pin, polarity, period, duty);
343         
344         rewind(g_pwm[pin].file_duty);
345
346         if (fprintf(g_pwm[pin].file_duty, "0") == 0)
347         {
348                 Abort("Couldn't zero the duty cycle for PWM %d - s", pin, strerror(errno));
349         }
350         
351         // Have to stop PWM before changing it
352         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
353         {
354                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
355         }
356
357         char c = '0' + polarity;
358         if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1)
359         {
360                 Abort("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
361         }
362         
363         rewind(g_pwm[pin].file_period); 
364         rewind(g_pwm[pin].file_duty);
365         if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0)
366         {
367                 Abort("Couldn't set period for PWM %d - %s", pin, strerror(errno));
368         }
369
370         if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0)
371         {
372                 Abort("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
373         }
374
375         if (pwrite(g_pwm[pin].fd_run, "1", 1, 0) != 1)
376         {
377                 Abort("Couldn't start PWM %d - %s", pin, strerror(errno));
378         }
379
380 }
381
382 /**
383  * Deactivate a PWM pin
384  * @param pin - The pin to turn off
385  */
386 void PWM_Stop(int pin)
387 {
388         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
389         {
390                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
391         }
392 }
393
394 /**
395  * Read an ADC value
396  * @param id - The ID of the ADC pin to read
397  * @returns - The reading of the ADC channel
398  */
399 int ADC_Read(int id)
400 {
401         char adc_str[ADC_DIGITS] = "";
402         lseek(g_adc[id].fd_value, 0, SEEK_SET);
403         
404         int i = 0;
405         for (i = 0; i < ADC_DIGITS-1; ++i)
406         {
407                 if (read(g_adc[id].fd_value, adc_str+i, 1) != 1)
408                         break;
409                 if (adc_str[i] == '\n')
410                 {
411                         adc_str[i] = '\0';
412                         break;
413                 }
414         }
415
416         char * end;
417         int val = strtol(adc_str, &end, 10);
418         if (*end != '\0')
419         {
420                 Log(LOGERR, "Read non integer from ADC %d - %s", id, adc_str);
421         }       
422         return val;     
423 }

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