1/**
2 *  @brief    Provides helpful file IO wrappers for use with sysfs.
3 *  @details  Based on Jonathan Cameron's @e iio_utils.h.
4 */
5
6#include <string.h>
7#include <stdlib.h>
8#include <ctype.h>
9#include <stdio.h>
10#include <stdint.h>
11#include <dirent.h>
12#include <errno.h>
13#include <unistd.h>
14#include "inv_sysfs_utils.h"
15
16/* General TODO list:
17 * Select more reasonable string lengths or use fseek and malloc.
18 */
19
20/**
21 *  inv_sysfs_write() - Write an integer to a file.
22 *  @filename:	Path to file.
23 *  @data:	Value to write to file.
24 *  Returns number of bytes written or a negative error code.
25 */
26int inv_sysfs_write(char *filename, long data)
27{
28	FILE *fp;
29	int count;
30
31	if (!filename)
32		return -1;
33	fp = fopen(filename, "w");
34	if (!fp)
35		return -errno;
36	count = fprintf(fp, "%ld", data);
37	fclose(fp);
38	return count;
39}
40
41/**
42 *  inv_sysfs_read() - Read a string from a file.
43 *  @filename:	Path to file.
44 *  @num_bytes:	Number of bytes to read.
45 *  @data:	Data from file.
46 *  Returns number of bytes written or a negative error code.
47 */
48int inv_sysfs_read(char *filename, long num_bytes, char *data)
49{
50	FILE *fp;
51	int count;
52
53	if (!filename)
54		return -1;
55	fp = fopen(filename, "r");
56	if (!fp)
57		return -errno;
58	count = fread(data, 1, num_bytes, fp);
59	fclose(fp);
60	return count;
61}
62
63/**
64 *  inv_read_buffer() - Read data from ring buffer.
65 *  @fd:	File descriptor for buffer file.
66 *  @data:	Data in hardware units.
67 *  @timestamp:	Time when data was read from device. Use NULL if unsupported.
68 *  Returns number of bytes written or a negative error code.
69 */
70int inv_read_buffer(int fd, long *data, long long *timestamp)
71{
72	char str[35];
73	int count;
74
75	count = read(fd, str, sizeof(str));
76	if (!count)
77		return count;
78	if (!timestamp)
79		count = sscanf(str, "%ld%ld%ld", &data[0], &data[1], &data[2]);
80	else
81		count = sscanf(str, "%ld%ld%ld%lld", &data[0], &data[1],
82			&data[2], timestamp);
83
84	if (count < (timestamp?4:3))
85		return -EAGAIN;
86	return count;
87}
88
89/**
90 *  inv_read_raw() - Read raw data.
91 *  @names:	Names of sysfs files.
92 *  @data:	Data in hardware units.
93 *  @timestamp:	Time when data was read from device. Use NULL if unsupported.
94 *  Returns number of bytes written or a negative error code.
95 */
96int inv_read_raw(const struct inv_sysfs_names_s *names, long *data,
97	long long *timestamp)
98{
99	char str[40];
100	int count;
101
102	count = inv_sysfs_read((char*)names->raw_data, sizeof(str), str);
103	if (count < 0)
104		return count;
105	if (!timestamp)
106		count = sscanf(str, "%ld%ld%ld", &data[0], &data[1], &data[2]);
107	else
108		count = sscanf(str, "%ld%ld%ld%lld", &data[0], &data[1],
109			&data[2], timestamp);
110	if (count < (timestamp?4:3))
111		return -EAGAIN;
112	return count;
113}
114
115/**
116 *  inv_read_temperature_raw() - Read temperature.
117 *  @names:	Names of sysfs files.
118 *  @data:	Data in hardware units.
119 *  @timestamp:	Time when data was read from device.
120 *  Returns number of bytes written or a negative error code.
121 */
122int inv_read_temperature_raw(const struct inv_sysfs_names_s *names, short *data,
123	long long *timestamp)
124{
125	char str[25];
126	int count;
127
128	count = inv_sysfs_read((char*)names->temperature, sizeof(str), str);
129	if (count < 0)
130		return count;
131	count = sscanf(str, "%hd%lld", &data[0], timestamp);
132	if (count < 2)
133		return -EAGAIN;
134	return count;
135}
136
137/**
138 *  inv_read_fifo_rate() - Read fifo rate.
139 *  @names:	Names of sysfs files.
140 *  @data:	Fifo rate.
141 *  Returns number of bytes written or a negative error code.
142 */
143int inv_read_fifo_rate(const struct inv_sysfs_names_s *names, short *data)
144{
145	char str[8];
146	int count;
147
148	count = inv_sysfs_read((char*)names->fifo_rate, sizeof(str), str);
149	if (count < 0)
150		return count;
151	count = sscanf(str, "%hd", data);
152	if (count < 1)
153		return -EAGAIN;
154	return count;
155}
156
157/**
158 *  inv_read_power_state() - Read power state.
159 *  @names:	Names of sysfs files.
160 *  @data:	1 if device is on.
161 *  Returns number of bytes written or a negative error code.
162 */
163int inv_read_power_state(const struct inv_sysfs_names_s *names, char *data)
164{
165	char str[2];
166	int count;
167
168	count = inv_sysfs_read((char*)names->power_state, sizeof(str), str);
169	if (count < 0)
170		return count;
171	count = sscanf(str, "%hd", (short*)data);
172	if (count < 1)
173		return -EAGAIN;
174	return count;
175}
176
177/**
178 *  inv_read_scale() - Read scale.
179 *  @names:	Names of sysfs files.
180 *  @data:	1 if device is on.
181 *  Returns number of bytes written or a negative error code.
182 */
183int inv_read_scale(const struct inv_sysfs_names_s *names, float *data)
184{
185	char str[5];
186	int count;
187
188	count = inv_sysfs_read((char*)names->scale, sizeof(str), str);
189	if (count < 0)
190		return count;
191	count = sscanf(str, "%f", data);
192	if (count < 1)
193		return -EAGAIN;
194	return count;
195}
196
197/**
198 *  inv_read_temp_scale() - Read temperature scale.
199 *  @names:	Names of sysfs files.
200 *  @data:	1 if device is on.
201 *  Returns number of bytes written or a negative error code.
202 */
203int inv_read_temp_scale(const struct inv_sysfs_names_s *names, short *data)
204{
205	char str[4];
206	int count;
207
208	count = inv_sysfs_read((char*)names->temp_scale, sizeof(str), str);
209	if (count < 0)
210		return count;
211	count = sscanf(str, "%hd", data);
212	if (count < 1)
213		return -EAGAIN;
214	return count;
215}
216
217/**
218 *  inv_read_temp_offset() - Read temperature offset.
219 *  @names:	Names of sysfs files.
220 *  @data:	1 if device is on.
221 *  Returns number of bytes written or a negative error code.
222 */
223int inv_read_temp_offset(const struct inv_sysfs_names_s *names, short *data)
224{
225	char str[4];
226	int count;
227
228	count = inv_sysfs_read((char*)names->temp_offset, sizeof(str), str);
229	if (count < 0)
230		return count;
231	count = sscanf(str, "%hd", data);
232	if (count < 1)
233		return -EAGAIN;
234	return count;
235}
236
237/**
238 *  inv_read_q16() - Get data as q16 fixed point.
239 *  @names:	Names of sysfs files.
240 *  @data:	1 if device is on.
241 *  @timestamp:	Time when data was read from device.
242 *  Returns number of bytes written or a negative error code.
243 */
244int inv_read_q16(const struct inv_sysfs_names_s *names, long *data,
245	long long *timestamp)
246{
247	int count;
248	short raw[3];
249	float scale;
250	count = inv_read_raw(names, (long*)raw, timestamp);
251	count += inv_read_scale(names, &scale);
252	data[0] = (long)(raw[0] * (65536.f / scale));
253	data[1] = (long)(raw[1] * (65536.f / scale));
254	data[2] = (long)(raw[2] * (65536.f / scale));
255	return count;
256}
257
258/**
259 *  inv_read_q16() - Get temperature data as q16 fixed point.
260 *  @names:	Names of sysfs files.
261 *  @data:	1 if device is on.
262 *  @timestamp:	Time when data was read from device.
263 *  Returns number of bytes read or a negative error code.
264 */
265int inv_read_temp_q16(const struct inv_sysfs_names_s *names, long *data,
266	long long *timestamp)
267{
268	int count = 0;
269	short raw;
270	static short scale, offset;
271	static unsigned char first_read = 1;
272
273	if (first_read) {
274		count += inv_read_temp_scale(names, &scale);
275		count += inv_read_temp_offset(names, &offset);
276		first_read = 0;
277	}
278	count += inv_read_temperature_raw(names, &raw, timestamp);
279	data[0] = (long)((35 + ((float)(raw - offset) / scale)) * 65536.f);
280
281	return count;
282}
283
284/**
285 *  inv_write_fifo_rate() - Write fifo rate.
286 *  @names:	Names of sysfs files.
287 *  @data:	Fifo rate.
288 *  Returns number of bytes written or a negative error code.
289 */
290int inv_write_fifo_rate(const struct inv_sysfs_names_s *names, short data)
291{
292	return inv_sysfs_write((char*)names->fifo_rate, (long)data);
293}
294
295/**
296 *  inv_write_buffer_enable() - Enable/disable buffer in /dev.
297 *  @names:	Names of sysfs files.
298 *  @data:	Fifo rate.
299 *  Returns number of bytes written or a negative error code.
300 */
301int inv_write_buffer_enable(const struct inv_sysfs_names_s *names, char data)
302{
303	return inv_sysfs_write((char*)names->enable, (long)data);
304}
305
306/**
307 *  inv_write_power_state() - Turn device on/off.
308 *  @names:	Names of sysfs files.
309 *  @data:	1 to turn on.
310 *  Returns number of bytes written or a negative error code.
311 */
312int inv_write_power_state(const struct inv_sysfs_names_s *names, char data)
313{
314	return inv_sysfs_write((char*)names->power_state, (long)data);
315}
316
317
318
319