aio: add initial analog input support
[contrib/mraa.git] / src / aio / aio.c
1 /*
2  * Author: Nandkishor Sonar
3  * Copyright (c) 2014 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <stdlib.h>
26
27 #include "aio.h"
28
29 static maa_result_t aio_get_valid_fp(maa_aio_context* dev)
30 {
31     char file_path[64]= "";
32
33     //Open file Analog device input channel raw voltage file for reading.
34     snprintf(file_path, 64, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw",
35         dev->channel );
36
37     if (NULL == (dev->adc_in_fp = fopen(file_path, "r"))) {
38         fprintf(stderr, "Failed to open Analog input raw file %s for "
39             "reading!\n", file_path); return( MAA_ERROR_INVALID_RESOURCE);
40     }
41
42     return MAA_SUCCESS;
43 }
44
45 /** Configure multiplexer for Analog Input
46  *
47  * @param aio_channel = Analog input channel to read
48  *
49  * @return maa_result_t - result type.
50  *
51  */
52 static maa_result_t maa_aio_set_mux(unsigned int aio_channel)
53 {
54     maa_result_t result;
55     maa_gpio_context* aio_gate;
56
57     //Initialise VINx multiplexer gate pins
58     aio_gate = maa_gpio_init(adc_gate_pins[aio_channel]);
59
60     if (NULL == aio_gate) {
61         fprintf(stderr, "Failed to initialise first gate pin %d for  ADC "
62             "channel %d !\n", adc_gate_pins[aio_channel], aio_channel);
63         return MAA_ERROR_INVALID_RESOURCE;
64     }
65
66     //Set direction to output for the ADC input gate
67     result = maa_gpio_dir(aio_gate, MAA_GPIO_OUT);
68
69     if (MAA_SUCCESS == result) {
70         // Write gate configuration output value
71         result = maa_gpio_write(aio_gate, 0);
72
73         if (MAA_SUCCESS == result) {
74             //For A4 and A5 Analog common gate pin should be high for the
75             // Galileo board revision D
76             if (A4 == aio_channel || A5 == aio_channel) {
77                 aio_gate = maa_gpio_init(ADC_COMMON_GATE_A4_A5);
78
79                 //Set direction to output for the gate
80                 if (NULL == aio_gate) {
81                     fprintf(stderr, "Failed to initialise second gate pin %d "
82                     "for  ADC channel %d !\n", ADC_COMMON_GATE_A4_A5,
83                     aio_channel);
84                     return(MAA_ERROR_INVALID_RESOURCE);
85                 }
86
87                 result = maa_gpio_dir(aio_gate, MAA_GPIO_OUT);
88                 if (MAA_SUCCESS == result)
89                 // Write gate configuration output value
90                 result = maa_gpio_write(aio_gate, 1);
91             }
92         }
93     }
94
95     if (NULL != aio_gate)
96         free(aio_gate);
97
98     return (result);
99 }
100
101 /** Initialise an Analog input, connected to the specified channel
102  *
103  * @param aio_channel Analog input channel to read
104  *
105  * @returns pointer to maa_aio_context structure  after initialisation of
106  * Analog input pin connected to the device successfully, else returns NULL.
107  */
108 maa_aio_context* maa_aio_init(unsigned int aio_channel)
109 {
110     maa_aio_context* dev;
111
112     // Validate input pins 0-5
113     if (aio_channel > TOTAL_ANALOG_INPUTS_ON_BOARD) {
114             fprintf(stderr, "Invalid Analog  input channel %d specified!\n",
115             aio_channel);
116         return NULL;
117     }
118
119     //Set-up multiplexer for the Analog input channel
120     if (MAA_SUCCESS != maa_aio_set_mux(aio_channel)) {
121         fprintf(stderr, "Failed to set-up  Analog  input channel %d "
122             "multiplexer!\n", aio_channel); return NULL;
123     }
124
125     //Create ADC device connected to specified channel
126     dev = (maa_aio_context*) malloc(sizeof(maa_aio_context));
127     if (NULL == dev) {
128         fprintf(stderr, "Insufficient memory for specified Analog input channel "
129             "%d !\n", aio_channel);
130         return NULL;
131     }
132     dev->channel = aio_channel;
133
134     //Open valid  analog input file and get the pointer.
135     if (MAA_SUCCESS != aio_get_valid_fp(dev)) {
136         free(dev);
137         return NULL;
138     }
139
140     return dev;
141 }
142
143 /** Read the input voltage, represented as an unsigned short in the range [0x0,
144  * 0xFFFF]
145  *
146  * @param pointer to maa_aio_context structure  initialised by
147  * maa_aio_init()
148  *
149  * @returns
150  *   16-bit unsigned int representing the current input voltage, normalised to
151  *   a 16-bit value
152  */
153 unsigned int maa_aio_read_u16(maa_aio_context* dev)
154 {
155     char buffer[16] = "";
156     unsigned int raw_value=0;
157     unsigned int analog_value=0;
158     unsigned int shifter_value=0;
159
160     if (NULL == dev->adc_in_fp) {
161         aio_get_valid_fp(dev);
162     }
163
164     fseek(dev->adc_in_fp, SEEK_SET, 0);
165     fread(buffer, sizeof(buffer), 1, dev->adc_in_fp);
166     fseek(dev->adc_in_fp, SEEK_SET, 0);
167
168     raw_value = atoi(buffer);
169
170     /* Adjust the raw analog input reading to supported resolution value*/
171     if (ADC_RAW_RESOLUTION_BITS == ADC_SUPPORTED_RESOLUTION_BITS) {
172         analog_value = raw_value;
173     }
174     else {
175         if (ADC_RAW_RESOLUTION_BITS > ADC_SUPPORTED_RESOLUTION_BITS) {
176             shifter_value = ADC_RAW_RESOLUTION_BITS - ADC_SUPPORTED_RESOLUTION_BITS;
177             analog_value =  raw_value >> shifter_value;
178         } else {
179             shifter_value = ADC_SUPPORTED_RESOLUTION_BITS - ADC_RAW_RESOLUTION_BITS;
180             analog_value = raw_value << shifter_value;
181         }
182     }
183
184     return analog_value;
185 }
186
187 /** Close the analog input and free context memory
188  *
189  * @param dev - the analog input context
190  *
191  * @return maa result type.
192  */
193 maa_result_t maa_aio_close(maa_aio_context* dev)
194 {
195     if (NULL != dev)
196         free(dev);
197
198     return(MAA_SUCCESS);
199 }