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

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