17 struct owparser_state {
18 double prev_delta[20];
22 static struct owparser_state *allocate_parser_state(const char **datastr)
26 /* Count how many sensor entries we need */
27 for (i = 0; datastr[i]; i++)
30 /* The first entry belongs to server address or mount point */
33 return calloc(sizeof(struct owparser_state), i);
36 static int might_be_glitch(double data, const struct owparser_state *s)
38 double max_delta = 0, delta;
41 for (i = 0; i < ARRAY_SIZE(s->prev_delta); i++)
42 max_delta = max(s->prev_delta[i], max_delta);
44 /* Probably no enough data yet, so no glitch detection */
49 * Simple glitch detection. If delta to previous value is more
50 * than twice as larger as some older delta, we might have a
53 delta = fabs(data - s->prev_data);
54 return delta > max_delta * 2;
57 static void update_glitch_data(double data, struct owparser_state *s)
62 for (i = 1; i < ARRAY_SIZE(s->prev_delta); i++) {
63 s->prev_delta[i - 1] = s->prev_delta[i];
64 max_delta = max(s->prev_delta[i], max_delta);
67 /* Avoid storing the first incorrect delta value */
68 if (s->prev_data || max_delta)
69 s->prev_delta[--i] = fabs(data - s->prev_data);
74 static int parse_opts(const char *str, char *ow_path, size_t pathlen,
78 const char *start_str = str;
79 const char offset_str[] = "offset=";
85 * Skip the onewire path entry. Options begin after the first
92 /* Copy the onewire path without options */
93 strncpy(ow_path, start_str, pathlen);
94 ow_path[str - start_str] = '\0';
96 /* Get the next non-space, which is where the argument begins */
101 if (strncmp(str, offset_str, sizeof(offset_str) - 1))
103 str += sizeof(offset_str) - 1;
105 *offset = strtod(str, &endptr);
113 static int make_uncached(char *path, size_t len)
115 char p1[1024], p2[1024], *p = path;
117 if (strstr(path, "/uncached/"))
120 p1[sizeof(p1) - 1] = '\0';
121 p2[sizeof(p2) - 1] = '\0';
124 * Naively assume the "uncached" string can be put after the
127 while (*p && *p != '/')
136 strncpy(p1, path, sizeof(p1) - 1);
137 strncpy(p2, p, sizeof(p2) - 1);
138 snprintf(path, len, "%s/uncached/%s", p1, p2);
143 static int owfs_read(const char *mount_point, const char *path, char **res)
149 snprintf(file, sizeof(file), "%s/%s", mount_point, path);
151 fd = open(file, O_RDONLY | O_CLOEXEC);
153 pr_err("Failed to open file %s: %m\n", file);
157 ret = read(fd, result, sizeof(result));
159 pr_err("Failed to read from file %s: %m\n", file);
163 *res = strndup(result, sizeof(result));
171 static int is_mount_point(const char *str)
174 * Filesystem paths begin with a slash, everything else must
175 * be a network addresses
183 static int onewire_parser(char *rrd_data, const char **parser_data, void **s)
186 const char *server_addr, *mount_point;
187 struct owparser_state *state = *s;
190 int max_str = RRD_DATA_MAX_LEN;
191 int is_mountpoint = is_mount_point(parser_data[0]);
194 pr_err("No parser data available\n");
199 *s = state = allocate_parser_state(parser_data);
202 mount_point = parser_data[0];
205 pr_err("Server address not specified\n");
209 server_addr = parser_data[0];
212 pr_err("Server address not specified\n");
216 h = OWNET_init(server_addr);
218 pr_err("Failed to connect to server %s\n", server_addr);
223 while (parser_data[i]) {
224 double offset = 0, data, prev_data = 85;
230 if (!strcmp("U", parser_data[i])) {
232 ret = snprintf(rrd_data, max_str, "U");
238 parse_opts(parser_data[i], ow_path, sizeof(ow_path), &offset);
245 pr_info("Reading data for entry %s with offset of %.2f\n",
249 ret = owfs_read(mount_point, ow_path, &tmp);
251 ret = OWNET_read(h, ow_path, &tmp);
253 /* Skip leading white space */
255 for (j = 0; j < ret && *tmp2 == ' '; j++)
259 fail = !strncmp(tmp2, "85", 2);
263 if (ret <= 0 || fail)
268 * Older versions of OWNET_read did not NULL
271 memcpy(buf, tmp, min(ret, sizeof(buf) -1));
274 data = strtod(buf, &endptr);
280 * If we read the same value as previously,
283 if (glitches && prev_data == data)
286 if (might_be_glitch(data, &state[i]) &&
287 glitches < 2 && retries < 7) {
290 pr_info("Retrying due to a glitch: %f\n", data);
297 * In case of failure, retry with uncached
298 * data. This is likely to help as it forces a
299 * retry even if the sensor is missing from
300 * the cache. We treat "85" also as a failure,
301 * as temp sensors some times report 85 under
304 ret = make_uncached(ow_path, sizeof(ow_path));
305 if (retries >= 10 || ret < 0) {
306 pr_err("Failed to read entry %s: %m\n",
315 update_glitch_data(data, &state[i]);
318 pr_err("Failed to parse data %s\n", buf);
324 ret = snprintf(rrd_data, max_str, "%f", data);
333 ret = snprintf(rrd_data, max_str, ":");
345 static struct parser_info onewire_parser_info = {
347 .parse = onewire_parser,
350 static int init_onewire_parser(void)
352 return register_parser(&onewire_parser_info);
355 struct plugin_info plugin_info = {
356 .name = "onewire_parser",
357 .init = init_onewire_parser,
358 .version = RRDD_VERSION,