56f39282da2b9098892d0877c5aabb6d6652df11
[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 #include <fcntl.h>
27 #include <errno.h>
28
29 #include "aio.h"
30 #include "maa_internal.h"
31
32 struct _aio {
33     unsigned int channel;
34     int adc_in_fp;
35 };
36
37 static maa_result_t aio_get_valid_fp(maa_aio_context dev)
38 {
39     char file_path[64]= "";
40
41     //Open file Analog device input channel raw voltage file for reading.
42     snprintf(file_path, 64, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw",
43         dev->channel );
44
45     dev->adc_in_fp = open(file_path, O_RDONLY);
46     if (dev->adc_in_fp == -1) {
47         fprintf(stderr, "Failed to open Analog input raw file %s for "
48             "reading!\n", file_path); return( MAA_ERROR_INVALID_RESOURCE);
49     }
50
51     return MAA_SUCCESS;
52 }
53
54 /** Initialise an Analog input, connected to the specified channel
55  *
56  * @param aio_channel Analog input channel to read
57  *
58  * @returns pointer to maa_aio_context structure  after initialisation of
59  * Analog input pin connected to the device successfully, else returns NULL.
60  */
61 maa_aio_context maa_aio_init(unsigned int aio_channel)
62 {
63     int checked_pin = maa_setup_aio(aio_channel);
64     if (checked_pin < 0) {
65         switch(checked_pin) {
66             case -1:
67                 fprintf(stderr, "Invalid analog input channel %d specified\n",
68                         aio_channel);
69                 return NULL;
70             case -2:
71                 fprintf(stderr, "Failed to set-up analog input channel %d "
72                         "multiplexer\n", aio_channel);
73                 return NULL;
74             case -3:
75                 fprintf(stderr, "Platform not initialised");
76                 return NULL;
77             default: return NULL;
78         }
79     }
80
81     //Create ADC device connected to specified channel
82     maa_aio_context dev = malloc(sizeof(struct _aio));
83     if (dev == NULL) {
84         fprintf(stderr, "Insufficient memory for specified Analog input channel "
85             "%d\n", aio_channel);
86         return NULL;
87     }
88     dev->channel = checked_pin;
89
90     //Open valid  analog input file and get the pointer.
91     if (MAA_SUCCESS != aio_get_valid_fp(dev)) {
92         free(dev);
93         return NULL;
94     }
95
96     return dev;
97 }
98
99 /** Read the input voltage, represented as an unsigned short in the range [0x0,
100  * 0xFFFF]
101  *
102  * @param pointer to maa_aio_context structure  initialised by
103  * maa_aio_init()
104  *
105  * @returns
106  *   unsigned 16 bit int representing the current input voltage, normalised to
107  *   a 16-bit value
108  */
109 uint16_t maa_aio_read(maa_aio_context dev)
110 {
111     char buffer[16];
112     unsigned int shifter_value = 0;
113
114     if (dev->adc_in_fp == -1) {
115         aio_get_valid_fp(dev);
116     }
117
118     lseek(dev->adc_in_fp, 0, SEEK_SET);
119     if (read(dev->adc_in_fp, buffer, sizeof(buffer)) < 1) {
120         fprintf(stderr, "Failed to read a sensible value\n");
121     }
122     lseek(dev->adc_in_fp, 0, SEEK_SET);
123
124     errno = 0;
125     char *end;
126     uint16_t analog_value = (uint16_t) strtoul(buffer, &end, 10);
127     if (end == &buffer[0]) {
128         fprintf(stderr, "%s is not a decimal number\n", buffer);
129     }
130     else if (errno != 0) {
131         fprintf(stderr, "errno was set\n");
132     }
133
134     /* Adjust the raw analog input reading to supported resolution value*/
135     if (ADC_RAW_RESOLUTION_BITS > ADC_SUPPORTED_RESOLUTION_BITS) {
136         shifter_value = ADC_RAW_RESOLUTION_BITS - ADC_SUPPORTED_RESOLUTION_BITS;
137         analog_value =  analog_value >> shifter_value;
138     } else {
139         shifter_value = ADC_SUPPORTED_RESOLUTION_BITS - ADC_RAW_RESOLUTION_BITS;
140         analog_value = analog_value << shifter_value;
141     }
142
143     return analog_value;
144 }
145
146 /** Close the analog input and free context memory
147  *
148  * @param dev - the analog input context
149  *
150  * @return maa result type.
151  */
152 maa_result_t maa_aio_close(maa_aio_context dev)
153 {
154     if (NULL != dev)
155         free(dev);
156
157     return(MAA_SUCCESS);
158 }