/** * @brief Provides helpful file IO wrappers for use with sysfs. * @details Based on Jonathan Cameron's @e iio_utils.h. */ #include #include #include #include #include #include #include #include #include "inv_sysfs_utils.h" /* General TODO list: * Select more reasonable string lengths or use fseek and malloc. */ /** * inv_sysfs_write() - Write an integer to a file. * @filename: Path to file. * @data: Value to write to file. * Returns number of bytes written or a negative error code. */ int inv_sysfs_write(char *filename, long data) { FILE *fp; int count; if (!filename) return -1; fp = fopen(filename, "w"); if (!fp) return -errno; count = fprintf(fp, "%ld", data); fclose(fp); return count; } /** * inv_sysfs_read() - Read a string from a file. * @filename: Path to file. * @num_bytes: Number of bytes to read. * @data: Data from file. * Returns number of bytes written or a negative error code. */ int inv_sysfs_read(char *filename, long num_bytes, char *data) { FILE *fp; int count; if (!filename) return -1; fp = fopen(filename, "r"); if (!fp) return -errno; count = fread(data, 1, num_bytes, fp); fclose(fp); return count; } /** * inv_read_buffer() - Read data from ring buffer. * @fd: File descriptor for buffer file. * @data: Data in hardware units. * @timestamp: Time when data was read from device. Use NULL if unsupported. * Returns number of bytes written or a negative error code. */ int inv_read_buffer(int fd, long *data, long long *timestamp) { char str[35]; int count; count = read(fd, str, sizeof(str)); if (!count) return count; if (!timestamp) count = sscanf(str, "%ld%ld%ld", &data[0], &data[1], &data[2]); else count = sscanf(str, "%ld%ld%ld%lld", &data[0], &data[1], &data[2], timestamp); if (count < (timestamp?4:3)) return -EAGAIN; return count; } /** * inv_read_raw() - Read raw data. * @names: Names of sysfs files. * @data: Data in hardware units. * @timestamp: Time when data was read from device. Use NULL if unsupported. * Returns number of bytes written or a negative error code. */ int inv_read_raw(const struct inv_sysfs_names_s *names, long *data, long long *timestamp) { char str[40]; int count; count = inv_sysfs_read((char*)names->raw_data, sizeof(str), str); if (count < 0) return count; if (!timestamp) count = sscanf(str, "%ld%ld%ld", &data[0], &data[1], &data[2]); else count = sscanf(str, "%ld%ld%ld%lld", &data[0], &data[1], &data[2], timestamp); if (count < (timestamp?4:3)) return -EAGAIN; return count; } /** * inv_read_temperature_raw() - Read temperature. * @names: Names of sysfs files. * @data: Data in hardware units. * @timestamp: Time when data was read from device. * Returns number of bytes written or a negative error code. */ int inv_read_temperature_raw(const struct inv_sysfs_names_s *names, short *data, long long *timestamp) { char str[25]; int count; count = inv_sysfs_read((char*)names->temperature, sizeof(str), str); if (count < 0) return count; count = sscanf(str, "%hd%lld", &data[0], timestamp); if (count < 2) return -EAGAIN; return count; } /** * inv_read_fifo_rate() - Read fifo rate. * @names: Names of sysfs files. * @data: Fifo rate. * Returns number of bytes written or a negative error code. */ int inv_read_fifo_rate(const struct inv_sysfs_names_s *names, short *data) { char str[8]; int count; count = inv_sysfs_read((char*)names->fifo_rate, sizeof(str), str); if (count < 0) return count; count = sscanf(str, "%hd", data); if (count < 1) return -EAGAIN; return count; } /** * inv_read_power_state() - Read power state. * @names: Names of sysfs files. * @data: 1 if device is on. * Returns number of bytes written or a negative error code. */ int inv_read_power_state(const struct inv_sysfs_names_s *names, char *data) { char str[2]; int count; count = inv_sysfs_read((char*)names->power_state, sizeof(str), str); if (count < 0) return count; count = sscanf(str, "%hd", (short*)data); if (count < 1) return -EAGAIN; return count; } /** * inv_read_scale() - Read scale. * @names: Names of sysfs files. * @data: 1 if device is on. * Returns number of bytes written or a negative error code. */ int inv_read_scale(const struct inv_sysfs_names_s *names, float *data) { char str[5]; int count; count = inv_sysfs_read((char*)names->scale, sizeof(str), str); if (count < 0) return count; count = sscanf(str, "%f", data); if (count < 1) return -EAGAIN; return count; } /** * inv_read_temp_scale() - Read temperature scale. * @names: Names of sysfs files. * @data: 1 if device is on. * Returns number of bytes written or a negative error code. */ int inv_read_temp_scale(const struct inv_sysfs_names_s *names, short *data) { char str[4]; int count; count = inv_sysfs_read((char*)names->temp_scale, sizeof(str), str); if (count < 0) return count; count = sscanf(str, "%hd", data); if (count < 1) return -EAGAIN; return count; } /** * inv_read_temp_offset() - Read temperature offset. * @names: Names of sysfs files. * @data: 1 if device is on. * Returns number of bytes written or a negative error code. */ int inv_read_temp_offset(const struct inv_sysfs_names_s *names, short *data) { char str[4]; int count; count = inv_sysfs_read((char*)names->temp_offset, sizeof(str), str); if (count < 0) return count; count = sscanf(str, "%hd", data); if (count < 1) return -EAGAIN; return count; } /** * inv_read_q16() - Get data as q16 fixed point. * @names: Names of sysfs files. * @data: 1 if device is on. * @timestamp: Time when data was read from device. * Returns number of bytes written or a negative error code. */ int inv_read_q16(const struct inv_sysfs_names_s *names, long *data, long long *timestamp) { int count; short raw[3]; float scale; count = inv_read_raw(names, (long*)raw, timestamp); count += inv_read_scale(names, &scale); data[0] = (long)(raw[0] * (65536.f / scale)); data[1] = (long)(raw[1] * (65536.f / scale)); data[2] = (long)(raw[2] * (65536.f / scale)); return count; } /** * inv_read_q16() - Get temperature data as q16 fixed point. * @names: Names of sysfs files. * @data: 1 if device is on. * @timestamp: Time when data was read from device. * Returns number of bytes read or a negative error code. */ int inv_read_temp_q16(const struct inv_sysfs_names_s *names, long *data, long long *timestamp) { int count = 0; short raw; static short scale, offset; static unsigned char first_read = 1; if (first_read) { count += inv_read_temp_scale(names, &scale); count += inv_read_temp_offset(names, &offset); first_read = 0; } count += inv_read_temperature_raw(names, &raw, timestamp); data[0] = (long)((35 + ((float)(raw - offset) / scale)) * 65536.f); return count; } /** * inv_write_fifo_rate() - Write fifo rate. * @names: Names of sysfs files. * @data: Fifo rate. * Returns number of bytes written or a negative error code. */ int inv_write_fifo_rate(const struct inv_sysfs_names_s *names, short data) { return inv_sysfs_write((char*)names->fifo_rate, (long)data); } /** * inv_write_buffer_enable() - Enable/disable buffer in /dev. * @names: Names of sysfs files. * @data: Fifo rate. * Returns number of bytes written or a negative error code. */ int inv_write_buffer_enable(const struct inv_sysfs_names_s *names, char data) { return inv_sysfs_write((char*)names->enable, (long)data); } /** * inv_write_power_state() - Turn device on/off. * @names: Names of sysfs files. * @data: 1 to turn on. * Returns number of bytes written or a negative error code. */ int inv_write_power_state(const struct inv_sysfs_names_s *names, char data) { return inv_sysfs_write((char*)names->power_state, (long)data); }