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));
85 if (entries[0][0] != '$') {
86 pr_debug("Discarding malformed data entry\n");
91 entries[i]++; /* discard the dollar sign */
92 data->channel = atoi(entries[i++]);
94 data->state = atoi(entries[i++]);
96 /* Timestamp is optional */
97 if (strlen(entries[1]) > 0)
98 data->timestamp = atof(entries[i++]);
100 data->input_voltage = atof(entries[i++]) / 1000.0;
101 data->charging_voltage = atof(entries[i++]) / 1000.0;
102 data->charging_current = atof(entries[i++]) / 100.0;
104 #define ASSIGN_OR_NAN(data, val) \
112 max_cells = entry_count - 10;
113 pr_debug("max_cells: %d\n", max_cells);
115 for (j = 0; j < max_cells; j++, i++) {
116 d = atoi(entries[i]);
117 ASSIGN_OR_NAN(data->cell_voltage[j], d / 1000.0);
120 d = atoi(entries[i++]);
121 ASSIGN_OR_NAN(data->int_temp, d / 10.0);
123 d = atoi(entries[i++]);
124 ASSIGN_OR_NAN(data->ext_temp, d / 10.0);
126 data->total_charge = atof(entries[i++]);
134 static void dump_data(struct charger_data *data)
138 pr_debug("channel %d\n", data->channel);
139 pr_debug("state %d\n", data->state);
140 pr_debug("timestamp %.1f\n", data->timestamp);
141 pr_debug("input_voltage %.3f\n", data->input_voltage);
142 pr_debug("charging_voltage %.3f\n", data->charging_voltage);
143 pr_debug("charging_current %.3f\n", data->charging_current);
145 for (i = 0; i < MAX_CELLS; i++) {
146 if (isnan(data->cell_voltage[i]))
149 pr_debug("cell_voltage[%d] %f\n", i,
150 data->cell_voltage[i]);
153 pr_debug("total_charge %.0f\n", data->total_charge);
154 pr_debug("int_temp %.1f\n", data->int_temp);
155 pr_debug("ext_temp %.1f\n", data->ext_temp);
158 static void print_status_line(struct charger_data *data)
160 int i, active_cells = 0;
164 if (data->timestamp > 3600) {
165 snprintf(time_str, sizeof(time_str), "%d:%02d:%02d",
166 (int)(data->timestamp / 3600),
167 (int)((int)data->timestamp % 3600) / 60,
168 (int)data->timestamp % 60);
170 snprintf(time_str, sizeof(time_str), "%2d:%02d",
171 ((int)data->timestamp % 3600) / 60,
172 (int)data->timestamp % 60);
175 for (i = 0; i < MAX_CELLS; i++) {
176 if (!isnan(data->cell_voltage[i])) {
177 cell_avg += data->cell_voltage[i];
181 cell_avg /= (double)active_cells;
183 pr_info("\r\033[K%8s Ubat: %.3fV Ucell avg: %.3fV "
184 "Current: %.2fA Charge %.0fmAh ",
185 time_str, data->charging_voltage, cell_avg,
186 data->charging_current, data->total_charge);
193 * Read data from a slow device
195 * return 1 when a complete NULL terminated line has been read
197 * return 0 when a partial line has been read and appended to the
200 * return negative on error
202 static int read_log_line(int infd, char *buf, size_t bufsize, int *offset)
207 ret = read(infd, buf + *offset, bufsize - *offset - 1);
209 pr_err("read: %m\n");
214 pr_err("Read EOF, stopping\n");
217 buf[*offset + ret] = 0;
219 for (i = 0; i < ret; i++) {
220 if (buf[i + *offset] == '\n' ||
221 buf[i + *offset] == '\r') {
223 * Got a complete line when there is a newline
224 * at the end. Remove the newline and possible
225 * other junk, such as '\r'
227 buf[i + *offset] = 0;
234 * Fixme! Nothing guarantees that there isn't actually
235 * more data (a part of a new log entry perhaps) after
236 * the newline. So in rare cases (we are prevented
237 * from reading the serial line in very long time) we
238 * might lose data from the stream..
246 static int read_data(struct eventhandler_entry *h)
248 struct dataparser_struct *dt;
251 struct charger_data data;
255 dt = container_of(h, struct dataparser_struct, evhandler);
257 ret = read_log_line(dt->infd, dt->buf, sizeof(dt->buf), &dt->offset);
262 pr_err("%s %s: EOF\n", __FILE__, __func__);
264 if (strlen(dt->buf) < 5) {
265 pr_debug("discarding truncated log entry\n");
271 dt->start_time = time(NULL);
273 cur_time = time(NULL);
275 parse_logline(dt->buf, &data);
277 /* Fill in possibly missing timestamp */
278 if (isnan(data.timestamp) || data.timestamp == 0)
279 data.timestamp = cur_time - dt->start_time;
281 print_status_line(&data);
289 len = snprintf(str, sizeof(str),
292 "%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;%.3f;"
293 "%.f;%.1f;%.1f\n", /* mAh, and temp */
299 data.charging_voltage,
300 data.charging_current,
302 data.cell_voltage[0],
303 data.cell_voltage[1],
304 data.cell_voltage[2],
305 data.cell_voltage[3],
306 data.cell_voltage[4],
307 data.cell_voltage[5],
308 data.cell_voltage[6],
309 data.cell_voltage[7],
310 data.cell_voltage[8],
311 data.cell_voltage[9],
316 ret = write(dt->outfd, str, len);
318 pr_err("write: %m\n");
325 static struct dataparser_struct dataparser = {
326 .evhandler.name = "OpenLog Parser",
327 .evhandler.events = EPOLLIN,
328 .evhandler.handle_event = read_data,
331 int init_data_parser(int infd, int outfd)
335 dataparser.evhandler.fd = infd;
336 dataparser.infd = infd;
337 dataparser.outfd = outfd;
339 ret = register_event_handler(&dataparser.evhandler);