15 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
17 static int separate_entries(char *buf, char *entries[], int max_entries)
24 while (*buf && i< max_entries) {
39 static void init_data(struct charger_data *data)
43 bzero(data, sizeof(*data));
44 for (i = 0; i < MAX_CELLS; i++)
45 data->cell_voltage[i] = NAN;
47 data->timestamp = NAN;
48 data->input_voltage = NAN;
49 data->charging_voltage = NAN;
50 data->charging_current = NAN;
51 data->total_charge = NAN;
57 * Convert one log line into charger_data structure. Supports at least
58 * iCharger 6 and 10 cell chargers. Others are not tested.
60 * Returns negative on incorrect data, zero on success
62 static int parse_logline(const char *buf, struct charger_data *data)
64 int i, j, entry_count;
68 char *str = strdup(buf);
71 entry_count = separate_entries(str, entries, ARRAY_SIZE(entries));
73 pr_debug("Entry count: %d\n", entry_count);
77 if (entries[0][0] != '$') {
78 pr_debug("Discarding malformed data entry\n");
82 for (i = 0; i < entry_count; i++)
83 pr_debug("Entry %d: data: %s\n", i, entries[i]);
86 entries[i]++; /* discard the dollar sign */
87 data->channel = atoi(entries[i++]);
89 data->state = atoi(entries[i++]);
91 /* Timestamp is optional */
92 if (strlen(entries[1]) > 0)
93 data->timestamp = atof(entries[i++]);
95 data->input_voltage = atof(entries[i++]) / 1000.0;
96 data->charging_voltage = atof(entries[i++]) / 1000.0;
97 data->charging_current = atof(entries[i++]) / 100.0;
99 #define ASSIGN_OR_NAN(data, val) \
107 max_cells = entry_count - 10;
108 pr_debug("max_cells: %d\n", max_cells);
110 for (j = 0; j < max_cells; j++, i++) {
111 d = atoi(entries[i]);
112 ASSIGN_OR_NAN(data->cell_voltage[j], d / 1000.0);
115 d = atoi(entries[i++]);
116 ASSIGN_OR_NAN(data->int_temp, d / 10.0);
118 d = atoi(entries[i++]);
119 ASSIGN_OR_NAN(data->ext_temp, d / 10.0);
121 data->total_charge = atof(entries[i++]);
129 static void dump_data(struct charger_data *data)
133 pr_debug("channel %d\n", data->channel);
134 pr_debug("state %d\n", data->state);
135 pr_debug("timestamp %.1f\n", data->timestamp);
136 pr_debug("input_voltage %.3f\n", data->input_voltage);
137 pr_debug("charging_voltage %.3f\n", data->charging_voltage);
138 pr_debug("charging_current %.3f\n", data->charging_current);
140 for (i = 0; i < MAX_CELLS; i++) {
141 if (isnan(data->cell_voltage[i]))
144 pr_debug("cell_voltage[%d] %f\n", i,
145 data->cell_voltage[i]);
148 pr_debug("total_charge %.0f\n", data->total_charge);
149 pr_debug("int_temp %.1f\n", data->int_temp);
150 pr_debug("ext_temp %.1f\n", data->ext_temp);
154 * Read data from a slow device
156 * return 1 when a complete NULL terminated line has been read
158 * return 0 when a partial line has been read and appended to the
161 * return negative on error
163 static int read_log_line(int infd, char *buf, size_t bufsize, int *offset)
168 ret = read(infd, buf + *offset, bufsize - *offset - 1);
170 pr_err("read: %m\n");
175 pr_err("Read EOF, stopping\n");
178 buf[*offset + ret] = 0;
180 for (i = 0; i < ret; i++) {
181 if (buf[i + *offset] == '\n' ||
182 buf[i + *offset] == '\r') {
184 * Got a complete line when there is a newline
185 * at the end. Remove the newline and possible
186 * other junk, such as '\r'
188 buf[i + *offset] = 0;
195 * Fixme! Nothing guarantees that there isn't actually
196 * more data (a part of a new log entry perhaps) after
197 * the newline. So in rare cases (we are prevented
198 * from reading the serial line in very long time) we
199 * might lose data from the stream..
207 int read_data(int infd, int outfd)
209 struct epoll_event ev;
210 time_t start_time = 0, cur_time;
216 epoll_fd = epoll_create(1);
218 pr_err("Failed to create epoll socket: %m\n");
224 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, infd, &ev) == -1) {
225 pr_err("epoll_ctl: %m\n");
230 struct charger_data data;
234 ret = epoll_wait(epoll_fd, &ev, 1, -1);
239 pr_err("epoll: %m\n");
243 ret = read_log_line(infd, buf, sizeof(buf), &offset);
250 if (strlen(buf) < 5) {
251 pr_debug("discarding truncated log entry\n");
257 start_time = time(NULL);
259 cur_time = time(NULL);
261 pr_info("%s\n", buf);
263 parse_logline(buf, &data);
267 if (isnan(data.timestamp))
268 data.timestamp = cur_time - start_time;
273 len = snprintf(str, sizeof(str),
276 "%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;"
277 "%.f;%.1f;%.1f\n", /* mAh, and temp */
283 data.charging_voltage,
284 data.charging_current,
286 data.cell_voltage[0],
287 data.cell_voltage[1],
288 data.cell_voltage[2],
289 data.cell_voltage[3],
290 data.cell_voltage[4],
291 data.cell_voltage[5],
292 data.cell_voltage[6],
293 data.cell_voltage[7],
294 data.cell_voltage[8],
295 data.cell_voltage[9],
299 ret = write(outfd, str, len);
301 pr_err("write: %m\n");