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

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