18 struct dataparser_struct {
19 struct eventhandler_entry evhandler;
27 static int separate_entries(char *buf, char *entries[], int max_entries)
34 while (*buf && i< max_entries) {
49 static void init_data(struct charger_data *data)
53 bzero(data, sizeof(*data));
54 for (i = 0; i < MAX_CELLS; i++)
55 data->cell_voltage[i] = NAN;
57 data->timestamp = NAN;
58 data->input_voltage = NAN;
59 data->charging_voltage = NAN;
60 data->charging_current = NAN;
61 data->total_charge = NAN;
67 * Convert one log line into charger_data structure. Supports at least
68 * iCharger 6 and 10 cell chargers. Others are not tested.
70 * Returns negative on incorrect data, zero on success
72 static int parse_logline(const char *buf, struct charger_data *data)
74 int i, j, entry_count;
78 char *str = strdup(buf);
81 entry_count = separate_entries(str, entries, ARRAY_SIZE(entries));
83 pr_debug("Entry count: %d\n", entry_count);
87 if (entries[0][0] != '$') {
88 pr_debug("Discarding malformed data entry\n");
92 for (i = 0; i < entry_count; i++)
93 pr_debug("Entry %d: data: %s\n", i, entries[i]);
96 entries[i]++; /* discard the dollar sign */
97 data->channel = atoi(entries[i++]);
99 data->state = atoi(entries[i++]);
101 /* Timestamp is optional */
102 if (strlen(entries[1]) > 0)
103 data->timestamp = atof(entries[i++]);
105 data->input_voltage = atof(entries[i++]) / 1000.0;
106 data->charging_voltage = atof(entries[i++]) / 1000.0;
107 data->charging_current = atof(entries[i++]) / 100.0;
109 #define ASSIGN_OR_NAN(data, val) \
117 max_cells = entry_count - 10;
118 pr_debug("max_cells: %d\n", max_cells);
120 for (j = 0; j < max_cells; j++, i++) {
121 d = atoi(entries[i]);
122 ASSIGN_OR_NAN(data->cell_voltage[j], d / 1000.0);
125 d = atoi(entries[i++]);
126 ASSIGN_OR_NAN(data->int_temp, d / 10.0);
128 d = atoi(entries[i++]);
129 ASSIGN_OR_NAN(data->ext_temp, d / 10.0);
131 data->total_charge = atof(entries[i++]);
139 static void dump_data(struct charger_data *data)
143 pr_debug("channel %d\n", data->channel);
144 pr_debug("state %d\n", data->state);
145 pr_debug("timestamp %.1f\n", data->timestamp);
146 pr_debug("input_voltage %.3f\n", data->input_voltage);
147 pr_debug("charging_voltage %.3f\n", data->charging_voltage);
148 pr_debug("charging_current %.3f\n", data->charging_current);
150 for (i = 0; i < MAX_CELLS; i++) {
151 if (isnan(data->cell_voltage[i]))
154 pr_debug("cell_voltage[%d] %f\n", i,
155 data->cell_voltage[i]);
158 pr_debug("total_charge %.0f\n", data->total_charge);
159 pr_debug("int_temp %.1f\n", data->int_temp);
160 pr_debug("ext_temp %.1f\n", data->ext_temp);
163 static void print_status_line(struct charger_data *data)
165 int i, active_cells = 0;
169 if (data->timestamp > 3600) {
170 snprintf(time_str, sizeof(time_str), "%d:%02d:%02d",
171 (int)(data->timestamp / 3600),
172 (int)((int)data->timestamp % 3600) / 60,
173 (int)data->timestamp % 60);
175 snprintf(time_str, sizeof(time_str), "%2d:%02d",
176 ((int)data->timestamp % 3600) / 60,
177 (int)data->timestamp % 60);
180 for (i = 0; i < MAX_CELLS; i++) {
181 if (!isnan(data->cell_voltage[i])) {
182 cell_avg += data->cell_voltage[i];
186 cell_avg /= (double)active_cells;
188 pr_info("\r\033[K%8s Ubat: %.3fV Ucell avg: %.3fV "
189 "Current: %.2fA Charge %.0fmAh ",
190 time_str, data->charging_voltage, cell_avg,
191 data->charging_current, data->total_charge);
198 * Read data from a slow device
200 * return 1 when a complete NULL terminated line has been read
202 * return 0 when a partial line has been read and appended to the
205 * return negative on error
207 static int read_log_line(int infd, char *buf, size_t bufsize, int *offset)
212 ret = read(infd, buf + *offset, bufsize - *offset - 1);
214 pr_err("read: %m\n");
219 pr_err("Read EOF, stopping\n");
222 buf[*offset + ret] = 0;
224 for (i = 0; i < ret; i++) {
225 if (buf[i + *offset] == '\n' ||
226 buf[i + *offset] == '\r') {
228 * Got a complete line when there is a newline
229 * at the end. Remove the newline and possible
230 * other junk, such as '\r'
232 buf[i + *offset] = 0;
239 * Fixme! Nothing guarantees that there isn't actually
240 * more data (a part of a new log entry perhaps) after
241 * the newline. So in rare cases (we are prevented
242 * from reading the serial line in very long time) we
243 * might lose data from the stream..
251 static int read_data(struct eventhandler_entry *h)
253 struct dataparser_struct *dt;
256 struct charger_data data;
260 dt = container_of(h, struct dataparser_struct, evhandler);
262 ret = read_log_line(dt->infd, dt->buf, sizeof(dt->buf), &dt->offset);
263 pr_debug("Line now %d: %s\n", dt->offset, dt->buf);
268 pr_err("%s %s: EOF\n", __FILE__, __func__);
270 if (strlen(dt->buf) < 5) {
271 pr_debug("discarding truncated log entry\n");
277 dt->start_time = time(NULL);
279 cur_time = time(NULL);
281 parse_logline(dt->buf, &data);
283 /* Fill in possibly missing timestamp */
284 if (isnan(data.timestamp) || data.timestamp == 0)
285 data.timestamp = cur_time - dt->start_time;
287 print_status_line(&data);
294 len = snprintf(str, sizeof(str),
297 "%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;"
298 "%.f;%.1f;%.1f\n", /* mAh, and temp */
304 data.charging_voltage,
305 data.charging_current,
307 data.cell_voltage[0],
308 data.cell_voltage[1],
309 data.cell_voltage[2],
310 data.cell_voltage[3],
311 data.cell_voltage[4],
312 data.cell_voltage[5],
313 data.cell_voltage[6],
314 data.cell_voltage[7],
315 data.cell_voltage[8],
316 data.cell_voltage[9],
321 ret = write(dt->outfd, str, len);
323 pr_err("write: %m\n");
330 static struct dataparser_struct dataparser = {
331 .evhandler.name = "OpenLog Parser",
332 .evhandler.events = EPOLLIN,
333 .evhandler.handle_event = read_data,
336 int init_data_parser(int infd, int outfd)
340 dataparser.evhandler.fd = infd;
341 dataparser.infd = infd;
342 dataparser.outfd = outfd;
344 ret = register_event_handler(&dataparser.evhandler);