Added module for direct control over pins
[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
58 /**
59  * Export a GPIO pin and open the file descriptors
60  */
61 void GPIO_Export(int pin)
62 {
63         if (pin < 0 || pin > GPIO_NUM_PINS)
64         {
65                 Abort("Invalid pin number %d", pin);
66         }
67
68         
69
70         // Export the pin
71         sprintf(g_buffer, "%s/export", GPIO_DEVICE_PATH);
72         FILE * export = fopen(g_buffer, "w");
73         if (export == NULL)
74         {
75                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
76         }
77
78         fprintf(export, "%d", pin);     
79         fclose(export);
80         
81         // Setup direction file descriptor
82         sprintf(g_buffer, "%s/gpio%d/direction", GPIO_DEVICE_PATH, pin);
83         g_gpio[pin].fd_direction = open(g_buffer, O_RDWR);
84         if (g_gpio[pin].fd_direction < 0)
85         {
86                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
87         }
88
89
90         // Setup value file descriptor
91         sprintf(g_buffer, "%s/gpio%d/value", GPIO_DEVICE_PATH, pin);
92         g_gpio[pin].fd_value = open(g_buffer, O_RDWR);
93         if (g_gpio[pin].fd_value < 0)
94         {
95                 Abort("Couldn't open %s for GPIO pin %d - %s", g_buffer, pin, strerror(errno));
96         }
97
98         Log(LOGDEBUG, "Exported GPIO%d", pin);
99         //sleep(1);
100 }
101
102 /**
103  * Unexport a GPIO pin and close its' file descriptors
104  */
105 void GPIO_Unexport(int pin)
106 {
107
108         if (pin < 0 || pin > GPIO_NUM_PINS)
109         {
110                 Abort("Invalid pin number %d", pin);
111         }
112
113         // Close file descriptors
114         close(g_gpio[pin].fd_value);
115         close(g_gpio[pin].fd_direction);
116
117         // Unexport the pin
118
119         if (g_buffer[0] == '\0')
120                 sprintf(g_buffer, "%s/unexport", GPIO_DEVICE_PATH);     
121         FILE * export = fopen(g_buffer, "w");
122         if (export == NULL)
123         {
124                 Abort("Couldn't open %s to export GPIO pin %d - %s", g_buffer, pin, strerror(errno));
125         }
126
127         fprintf(export, "%d", pin);     
128         fclose(export);
129 }
130
131
132
133
134 /**
135  * Export all PWM pins and open file descriptors
136  * @param pin - The pin number
137  */
138 void PWM_Export(int pin)
139 {
140         if (pin < 0 || pin > PWM_NUM_PINS)
141         {
142                 Abort("Invalid pin number %d", pin);
143         }
144         
145         // Export the pin
146         sprintf(g_buffer, "%s/export", PWM_DEVICE_PATH);
147         FILE * export = fopen(g_buffer, "w");
148         if (export == NULL)
149         {
150                 Abort("Couldn't open %s to export PWM pin %d - %s", g_buffer, pin, strerror(errno));
151         }
152         
153         fprintf(export, "%d\n", pin);
154         fclose(export);
155
156         // Open file descriptors
157         sprintf(g_buffer, "%s/pwm%d/run", PWM_DEVICE_PATH, pin);
158         g_pwm[pin].fd_run = open(g_buffer, O_WRONLY);
159         if (g_pwm[pin].fd_run < 0)
160         {
161                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
162         }
163
164         sprintf(g_buffer, "%s/pwm%d/polarity",PWM_DEVICE_PATH, pin);
165         g_pwm[pin].fd_polarity = open(g_buffer, O_WRONLY);
166         if (g_pwm[pin].fd_polarity < 0)
167         {
168                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
169         }
170
171         sprintf(g_buffer, "%s/pwm%d/period_ns",PWM_DEVICE_PATH, pin);
172         g_pwm[pin].file_period = fopen(g_buffer, "w");
173         if (g_pwm[pin].file_period == NULL)
174         {
175                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
176         }
177
178         sprintf(g_buffer, "%s/pwm%d/duty_ns",PWM_DEVICE_PATH, pin);
179         g_pwm[pin].file_duty = fopen(g_buffer, "w");
180         if (g_pwm[pin].file_duty == NULL)
181         {
182                 Abort("Couldn't open %s for PWM pin %d - %s", g_buffer, pin, strerror(errno));
183         }
184
185         // Don't buffer the streams
186         setbuf(g_pwm[pin].file_period, NULL);
187         setbuf(g_pwm[pin].file_duty, NULL);
188
189         
190 }
191
192 /**
193  * Unexport a PWM pin and close its file descriptors
194  * @param pin - The pin number
195  */
196 void PWM_Unexport(int pin)
197 {
198         if (pin < 0 || pin > PWM_NUM_PINS)
199         {
200                 Abort("Invalid pin number %d", pin);
201         }
202
203         // Close the file descriptors
204         close(g_pwm[pin].fd_polarity);
205         close(g_pwm[pin].fd_run);
206         fclose(g_pwm[pin].file_period);
207         fclose(g_pwm[pin].file_duty);
208
209         //Unexport the pin
210         sprintf(g_buffer, "%s/unexport", PWM_DEVICE_PATH);
211         FILE * export = fopen(g_buffer, "w");
212         if (export == NULL)
213         {
214                 Abort("Couldn't open %s to unexport PWM pin %d - %s", g_buffer, pin, strerror(errno));  
215         }
216         
217         fprintf(export, "%d", pin);
218         fclose(export);
219
220
221 }
222
223 /**
224  * Export ADC pins; http://beaglebone.cameon.net/home/reading-the-analog-inputs-adc
225  * Can't use sysfs like GPIO or PWM pins
226  * Bloody annoying how inconsistent stuff is on the Beaglebone
227  */
228 void ADC_Export()
229 {
230         for (int i = 0; i < ADC_NUM_PINS; ++i)
231         {
232                 sprintf(g_buffer, "%s/AIN%d", g_options.adc_device_path, i);
233                 g_adc[i].fd_value = open(g_buffer, O_RDONLY);
234                 if (g_adc[i].fd_value < 0)
235                 {
236                         Abort("Couldn't open ADC %d device file %s - %s", i, g_buffer, strerror(errno));
237                 }
238
239                 //setbuf(g_adc[i].file_value, NULL);
240
241         }
242 }
243
244 /**
245  * Unexport ADC pins
246  */
247 void ADC_Unexport()
248 {
249         for (int i = 0; i < ADC_NUM_PINS; ++i)
250                 close(g_adc[i].fd_value);
251 }
252
253 /**
254  * Set a GPIO pin
255  * @param pin - The pin to set. MUST have been exported before calling this function.
256  */
257 void GPIO_Set(int pin, bool value)
258 {
259         if (pwrite(g_gpio[pin].fd_direction, "out", 3, 0) != 3)
260         {
261                 Abort("Couldn't set GPIO %d direction - %s", pin, strerror(errno));
262         }
263
264         char c = '0' + (value);
265         if (pwrite(g_gpio[pin].fd_value, &c, 1, 0) != 1)
266         {
267                 Abort("Couldn't read GPIO %d value - %s", pin, strerror(errno));
268         }
269
270 }
271
272 /** 
273  * Read from a GPIO Pin
274  * @param pin - The pin to read
275  */
276 bool GPIO_Read(int pin)
277 {
278         if (pwrite(g_gpio[pin].fd_direction, "in", 2, 0) != 2)
279                 Log(LOGERR,"Couldn't set GPIO %d direction - %s", pin, strerror(errno)); 
280         char c = '0';
281         if (pread(g_gpio[pin].fd_value, &c, 1, 0) != 1)
282                 Log(LOGERR,"Couldn't read GPIO %d value - %s", pin, strerror(errno));
283
284         return (c == '1');
285
286 }
287
288 /**
289  * Activate a PWM pin
290  * @param pin - The pin to activate
291  * @param polarity - if true, pin is active high, else active low
292  * @param period - The period in ns
293  * @param duty - The time the pin is active in ns
294  */
295 void PWM_Set(int pin, bool polarity, long period, long duty)
296 {
297         // Have to stop PWM before changing it
298         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
299         {
300                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
301         }
302
303         char c = '0' + polarity;
304         if (pwrite(g_pwm[pin].fd_polarity, &c, 1, 0) != 1)
305         {
306                 Abort("Couldn't set PWM %d polarity - %s", pin, strerror(errno));
307         }
308         
309         rewind(g_pwm[pin].file_period); 
310         rewind(g_pwm[pin].file_duty);
311
312         if (fprintf(g_pwm[pin].file_duty, "%lu", duty) == 0)
313         {
314                 Abort("Couldn't set duty cycle for PWM %d - %s", pin, strerror(errno));
315         }
316         if (fprintf(g_pwm[pin].file_period, "%lu", period) == 0)
317         {
318                 Abort("Couldn't set period for PWM %d - %s", pin, strerror(errno));
319         }
320         if (pwrite(g_pwm[pin].fd_run, "1", 1, 0) != 1)
321         {
322                 Abort("Couldn't start PWM %d - %s", pin, strerror(errno));
323         }
324
325 }
326
327 /**
328  * Deactivate a PWM pin
329  * @param pin - The pin to turn off
330  */
331 void PWM_Stop(int pin)
332 {
333         if (pwrite(g_pwm[pin].fd_run, "0", 1, 0) != 1)
334         {
335                 Abort("Couldn't stop PWM %d - %s", pin, strerror(errno));
336         }
337 }
338
339 /**
340  * Read an ADC value
341  * @param id - The ID of the ADC pin to read
342  * @returns - The reading of the ADC channel
343  */
344 int ADC_Read(int id)
345 {
346         char adc_str[ADC_DIGITS] = "";
347         lseek(g_adc[id].fd_value, 0, SEEK_SET);
348         
349         int i = 0;
350         for (i = 0; i < ADC_DIGITS-1; ++i)
351         {
352                 if (read(g_adc[id].fd_value, adc_str+i, 1) != 1)
353                         break;
354                 if (adc_str[i] == '\n')
355                 {
356                         adc_str[i] = '\0';
357                         break;
358                 }
359         }
360
361         char * end;
362         int val = strtol(adc_str, &end, 10);
363         if (*end != '\0')
364         {
365                 Log(LOGERR, "Read non integer from ADC %d - %s", id, adc_str);
366         }       
367         return val;     
368 }

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