5ab14e9041b4480f5b71d98bba62309ac7588e59
[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
56 /**
57  * Export a GPIO pin and open the file descriptors
58  */
59 void GPIO_Export(int pin)
60 {
61         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
62         {
63                 Abort("Not a useable pin number: %d", pin);
64         }
65
66         GPIO_Pin *gpio = &g_gpio[g_gpio_to_index[pin]];
67         // Export the pin
68         sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
69         FILE * export = fopen(g_buffer, "w");
70         if (export == NULL)
71         {
72                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
73         }
74
75         fprintf(export, "%d", pin);     
76         fclose(export);
77         
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)
82         {
83                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
84         }
85
86
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)
91         {
92                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
93         }
94
95         Log(LOGDEBUG, "Exported GPIO%d", pin);
96         //sleep(1);
97 }
98
99 /**
100  * Unexport a GPIO pin and close its' file descriptors
101  */
102 void GPIO_Unexport(int pin)
103 {
104         if (pin < 0 || pin >= GPIO_INDEX_SIZE || g_gpio_to_index[pin] == 128)
105         {
106                 Abort("Not a useable pin number: %d", pin);
107         }
108
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);
113
114         // Unexport the pin
115
116         if (g_buffer[0] == '\0')
117                 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);     
118         FILE * export = fopen(g_buffer, "w");
119         if (export == NULL)
120         {
121                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
122         }
123
124         fprintf(export, "%d", pin);     
125         fclose(export);
126 }
127
128
129
130
131 /**
132  * Export all PWM pins and open file descriptors
133  * @param pin - The pin number
134  */
135 void PWM_Export(int pin)
136 {
137         if (pin < 0 || pin > PWM_NUM_PINS)
138         {
139                 Abort("Invalid pin number %d", pin);
140         }
141         
142         // Export the pin
143         sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
144         FILE * export = fopen(g_buffer, "w");
145         if (export == NULL)
146         {
147                 Abort("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno));
148         }
149         
150         fprintf(export, "%d\n", pin);
151         fclose(export);
152
153         // Open file descriptors
154         sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
155         g_pwm[pin].fd_run = open(g_buffer, O_WRONLY);
156         if (g_pwm[pin].fd_run < 0)
157         {
158                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
159         }
160
161         sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin);
162         g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY);
163         if (g_pwm[pin].fd_polarity < 0)
164         {
165                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
166         }
167
168         sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin);
169         g_pwm[pin].file_period = fopen(g_buffer, "w");
170         if (g_pwm[pin].file_period == NULL)
171         {
172                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
173         }
174
175         sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin);
176         g_pwm[pin].file_duty = fopen(g_buffer, "w");
177         if (g_pwm[pin].file_duty == NULL)
178         {
179                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
180         }
181
182         // Don't buffer the streams
183         setbuf(g_pwm[pin].file_period, NULL);
184         setbuf(g_pwm[pin].file_duty, NULL);
185
186         
187 }
188
189 /**
190  * Unexport a PWM pin and close its file descriptors
191  * @param pin - The pin number
192  */
193 void PWM_Unexport(int pin)
194 {
195         if (pin < 0 || pin > PWM_NUM_PINS)
196         {
197                 Abort("Invalid pin number %d", pin);
198         }
199
200         // Close the file descriptors
201         close(g_pwm[pin].fd_polarity);
202         close(g_pwm[pin].fd_run);
203         fclose(g_pwm[pin].file_period);
204         fclose(g_pwm[pin].file_duty);
205
206         //Unexport the pin
207         sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
208         FILE * export = fopen(g_buffer, "w");
209         if (export == NULL)
210         {
211                 Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));  
212         }
213         
214         fprintf(export, "%d", pin);
215         fclose(export);
216 }
217
218 /**
219  * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc
220  * Can't use sysfs like GPIO or PWM pins
221  * Bloody annoying how inconsistent stuff is on the Beaglebone
222  */
223 void ADC_Export()
224 {
225         for (int i = 0; i < ADC_NUM_PINS; ++i)
226         {
227                 sprintf(g_buffer, "%s/AIN%d", g_options.adc_device_path, i);
228                 g_adc[i].fd_value = open(g_buffer, O_RDONLY);
229                 if (g_adc[i].fd_value < 0)
230                 {
231                         Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
232                 }
233
234                 //setbuf(g_adc[i].file_value, NULL);
235
236         }
237 }
238
239 /**
240  * Unexport ADC pins
241  */
242 void ADC_Unexport()
243 {
244         for (int i = 0; i < ADC_NUM_PINS; ++i)
245                 close(g_adc[i].fd_value);
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 pin to activate
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         rewind(g_pwm[pin].file_duty);
310
311         if (fprintf(g_pwm[pin].file_duty, "0") == 0)
312         {
313                 Abort("Couldn't zero the duty cycle for PWM %d - s", pin, strerror(errno));
314         }
315         
316         // Have to stop PWM before changing it
317         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
318         {
319                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
320         }
321
322         char c = '0' + polarity;
323         if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1)
324         {
325                 Abort("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
326         }
327         
328         rewind(g_pwm[pin].file_period); 
329         rewind(g_pwm[pin].file_duty);
330         if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0)
331         {
332                 Abort("Couldn't set period for PWM %d - %s", pin, strerror(errno));
333         }
334
335         if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0)
336         {
337                 Abort("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
338         }
339
340         if (pwrite(g_pwm[pin].fd_run, "1", 1, 0) != 1)
341         {
342                 Abort("Couldn't start PWM %d - %s", pin, strerror(errno));
343         }
344
345 }
346
347 /**
348  * Deactivate a PWM pin
349  * @param pin - The pin to turn off
350  */
351 void PWM_Stop(int pin)
352 {
353         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
354         {
355                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
356         }
357 }
358
359 /**
360  * Read an ADC value
361  * @param id - The ID of the ADC pin to read
362  * @returns - The reading of the ADC channel
363  */
364 int ADC_Read(int id)
365 {
366         char adc_str[ADC_DIGITS] = "";
367         lseek(g_adc[id].fd_value, 0, SEEK_SET);
368         
369         int i = 0;
370         for (i = 0; i < ADC_DIGITS-1; ++i)
371         {
372                 if (read(g_adc[id].fd_value, adc_str+i, 1) != 1)
373                         break;
374                 if (adc_str[i] == '\n')
375                 {
376                         adc_str[i] = '\0';
377                         break;
378                 }
379         }
380
381         char * end;
382         int val = strtol(adc_str, &end, 10);
383         if (*end != '\0')
384         {
385                 Log(LOGERR, "Read non integer from ADC %d - %s", id, adc_str);
386         }       
387         return val;     
388 }

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