788d813f934818f02c71ddce876f431acea2abec
[platform/core/api/peripheral-io.git] / src / peripheral_adc.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <fcntl.h>
18 #include <inttypes.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <sys/file.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include "peripheral_io.h"
27 #include "common.h"
28 #include "log.h"
29
30 FEATURE("http://tizen.org/feature/peripheral_io.adc")
31
32 /* Path format for device file */
33 #define DEV_PATH_BASE(device, channel) ("/sys/bus/iio/devices/iio:device" device "/in_voltage" channel "_raw")
34 #define DEV_PATH_FMT_MAX_SIZE sizeof(DEV_PATH_BASE(MAX_d_FMT, MAX_d_FMT))
35 #define DEV_PATH_FMT DEV_PATH_BASE("%d", "%d")
36
37 #define ADC_BUFFER_MAX 64
38
39 /**
40  * @brief Internal struct for adc context
41  */
42 struct _peripheral_adc_s {
43         int fd;
44 };
45
46 static inline void cleanup_handlep(peripheral_adc_h *handle)
47 {
48         if (*handle != NULL) {
49                 close_fd((*handle)->fd);
50                 free(*handle);
51         }
52 }
53
54 /**
55  * @brief Initializes adc pin and creates adc handle.
56  */
57 int peripheral_adc_open(int device, int channel, peripheral_adc_h *adc)
58 {
59         RETVM_IF(!__is_feature_supported(), PERIPHERAL_ERROR_NOT_SUPPORTED, "ADC feature is not supported");
60         RETVM_IF(adc == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid adc handle");
61         RETVM_IF(device < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid adc device number");
62         RETVM_IF(channel < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid adc channel number");
63
64         __attribute__ ((cleanup(cleanup_handlep))) peripheral_adc_h handle = (peripheral_adc_h)calloc(1, sizeof *handle);
65         if (handle == NULL) {
66                 _E("Failed to allocate peripheral_adc_h");
67                 return PERIPHERAL_ERROR_OUT_OF_MEMORY;
68         }
69
70         /* space for /sys/bus/iio/devices/iio:device%d/in_voltage%d_raw */
71         char path[DEV_PATH_FMT_MAX_SIZE] = {0, };
72
73         snprintf(path, sizeof path, DEV_PATH_FMT, device, channel);
74         handle->fd = open(path, O_RDONLY | O_CLOEXEC);
75         CHECK_ERROR(handle->fd < 0);
76
77         int ret = PERIPHERAL_ERROR_NONE;
78         TRY_FLOCK(ret, handle->fd, LOCK_EX | LOCK_NB, "device : %d, channel : 0x%x", device, channel);
79         CHECK_ERROR(ret != PERIPHERAL_ERROR_NONE);
80
81         *adc = handle;
82         handle = NULL;
83
84         return PERIPHERAL_ERROR_NONE;
85 }
86
87 /**
88  * @brief Releases the adc handle.
89  */
90 int peripheral_adc_close(peripheral_adc_h adc)
91 {
92         RETVM_IF(!__is_feature_supported(), PERIPHERAL_ERROR_NOT_SUPPORTED, "ADC feature is not supported");
93         RETVM_IF(adc == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "adc handle is NULL");
94
95         cleanup_handlep(&adc);
96
97         return PERIPHERAL_ERROR_NONE;
98 }
99
100 /**
101  * @brief Reads value of the adc.
102  */
103 int peripheral_adc_read(peripheral_adc_h adc, uint32_t *value)
104 {
105         RETVM_IF(!__is_feature_supported(), PERIPHERAL_ERROR_NOT_SUPPORTED, "ADC feature is not supported");
106         RETVM_IF(adc == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "adc handle is NULL");
107         RETVM_IF(value == NULL, PERIPHERAL_ERROR_INVALID_PARAMETER, "adc read value is invalid");
108
109         int ret;
110         char adc_buf[ADC_BUFFER_MAX] = {0, };
111
112         ret = pread(adc->fd, &adc_buf, ADC_BUFFER_MAX, 0);
113         CHECK_ERROR(ret <= 0);
114
115         ret = sscanf(adc_buf, "%" SCNu32, value);
116         if (ret != 1) {
117                 _E("Error: unable to read adc value: %m\n");
118                 return PERIPHERAL_ERROR_IO_ERROR;
119         }
120
121         return PERIPHERAL_ERROR_NONE;
122 }