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