diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2017-04-29 18:17:08 +0200 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2017-05-02 16:17:08 +0200 |
commit | 7e6d6d0a37e37804e3a751e2bfde11a9c1e85b0b (patch) | |
tree | dcc513f232f608021a55fd317ccd3b1f623ccb70 /CAN-binder/low-can-demo/binding/stat-binding.c | |
parent | 10e7cf8b0d84be658069f60e5dd4831ec202cd70 (diff) |
Adding HTML5 UI with cpu stat binding
Change-Id: Id63b7d338140097a5f2f0943f1b63ee978141829
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
Diffstat (limited to 'CAN-binder/low-can-demo/binding/stat-binding.c')
-rw-r--r-- | CAN-binder/low-can-demo/binding/stat-binding.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/CAN-binder/low-can-demo/binding/stat-binding.c b/CAN-binder/low-can-demo/binding/stat-binding.c new file mode 100644 index 00000000..1e5b2dbd --- /dev/null +++ b/CAN-binder/low-can-demo/binding/stat-binding.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <netdb.h> +#include <fcntl.h> +#include <math.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/timerfd.h> + +#include <json-c/json.h> + +#include <systemd/sd-event.h> + +#include <afb/afb-binding.h> +#include <afb/afb-service-itf.h> + +/* + * the interface to afb-daemon + */ +const struct afb_binding_interface *afbitf; + +#define DEFAULT_PERIOD 1 /* 1 second */ + +struct event; + +const char *cpu_fields[]= { + "user", + "nice", + "system", + "idle", + "iowait", + "irq", + "softirq", + "steal", + "guest", + "guest_nice" +}; + +#define CPU_FIELD_COUNT (sizeof cpu_fields / sizeof *cpu_fields) + +struct status { + uint64_t cpu[CPU_FIELD_COUNT]; +}; + +static int fd_proc; +static int fd_timer; +static struct sd_event_source *source = NULL; + +static struct status older; +static struct status newer; +static struct status diff; +static struct afb_event event; + +/***************************************************************************************/ +/***************************************************************************************/ +/** **/ +/** **/ +/** SECTION: BINDING VERBS IMPLEMENTATION **/ +/** **/ +/** **/ +/***************************************************************************************/ +/***************************************************************************************/ + +static int read_status(int fd, struct status *s) +{ + int n; + ssize_t sz; + off_t off; + char buffer[8192]; + long long unsigned x[CPU_FIELD_COUNT]; + + off = lseek(fd, 0, SEEK_SET); + if (off == (off_t)-1) + return -1; + + sz = read(fd, buffer, sizeof buffer); + if (sz == -1) + return -1; + + n = sscanf(buffer, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &x[8], &x[9]); + if (n != CPU_FIELD_COUNT) + return -1; + while(n) { + n--; + s->cpu[n] = x[n]; + } + return 0; +} + +static void stop() +{ + sd_event_source_unref(source); + afb_event_drop(event); + close(fd_timer); + close(fd_proc); + fd_timer = -1; + fd_proc = -1; + event.itf = NULL; + source = NULL; +} + +static int emit(sd_event_source *src, int fd, uint32_t revents, void *userdata) +{ + int f, rc, p; + struct json_object *obj; + uint64_t u, s, i; + + read(fd, &i, sizeof i); + + memcpy(&older, &newer, sizeof older); + rc = read_status(fd_proc, &newer); + for(f = 0; f < (int)CPU_FIELD_COUNT ; f++) + diff.cpu[f] = newer.cpu[f] - older.cpu[f]; + + u = 0; + s = 0; + i = 0; + u += diff.cpu[0]; // "user", + u += diff.cpu[1]; // "nice", + s += diff.cpu[2]; // "system", + i += diff.cpu[3]; // "idle", + i += diff.cpu[4]; // "iowait", + s += diff.cpu[5]; // "irq", + s += diff.cpu[6]; // "softirq", + i += diff.cpu[7]; // "steal", + u += diff.cpu[8]; // "guest", + u += diff.cpu[9]; // "guest_nice" + p = (int)(unsigned)((100 * (u + s)) / (u + s + i)); + + obj = json_object_new_int(p); + if (afb_event_push(event, obj) == 0) + stop(); + return 0; +} + +static int start() +{ + int fdp, fdt, rc; + struct itimerspec ts; + struct sd_event_source *src; + + fdp = open("/proc/stat", O_RDONLY|O_CLOEXEC); + if (fdp >= 0) { + rc = read_status(fdp, &newer); + if (rc >= 0) { + fdt = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); + if (fdt >= 0) { + ts.it_interval.tv_sec = 1; + ts.it_value.tv_sec = 1; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_nsec = 0; + rc = timerfd_settime(fdt, 0, &ts, NULL); + if (rc >= 0) { + event = afb_daemon_make_event(afbitf->daemon, "stat"); + if (afb_event_is_valid(event)) { + rc = sd_event_add_io(afb_daemon_get_event_loop(afbitf->daemon), &src, fdt, EPOLLIN, emit, NULL); + if (rc >= 0) { + fd_proc = fdp; + fd_timer = fdt; + source = src; + return 0; + } + afb_event_drop(event); + } + } + close(fdt); + } + } + close(fdp); + } + return -1; +} + +static int ensure_started() +{ + return source == NULL ? start() : 0; +} + +/***************************************************************************************/ +/***************************************************************************************/ +/** **/ +/** **/ +/** SECTION: BINDING VERBS IMPLEMENTATION **/ +/** **/ +/** **/ +/***************************************************************************************/ +/***************************************************************************************/ + +/* + * subscribe to notification of stat + */ +static void subscribe(struct afb_req req) +{ + int rc; + + rc = ensure_started(); + if (rc < 0) { + afb_req_fail(req, "failed", "Can't start"); + } else if (afb_req_subscribe(req, event) != 0) { + afb_req_fail_f(req, "failed", "afb_req_subscribe returned an error: %m"); + } else { + afb_req_success(req, NULL, NULL); + } +} + +/* + * unsubscribe a previous subscription + * + * parameters of the unsubscription are: + * + * id: integer: the numeric identifier of the event as returned when subscribing + */ +static void unsubscribe(struct afb_req req) +{ + if (afb_event_is_valid(event)) + afb_req_unsubscribe(req, event); + afb_req_success(req, NULL, NULL); +} + +/* + * array of the verbs exported to afb-daemon + */ +static const struct afb_verb_desc_v1 binding_verbs[] = { + /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ + { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= subscribe, .info= "subscribe to notification of statistics" }, + { .name= "unsubscribe", .session= AFB_SESSION_NONE, .callback= unsubscribe, .info= "unsubscribe a previous subscription" }, + { .name= NULL } /* marker for end of the array */ +}; + +/* + * description of the binding for afb-daemon + */ +static const struct afb_binding binding_description = +{ + /* description conforms to VERSION 1 */ + .type= AFB_BINDING_VERSION_1, + .v1= { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */ + .prefix= "stat", /* the API name (or binding name or prefix) */ + .info= "Get system statistics", /* short description of of the binding */ + .verbs = binding_verbs /* the array describing the verbs of the API */ + } +}; + +/* + * activation function for registering the binding called by afb-daemon + */ +const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) +{ + afbitf = itf; /* records the interface for accessing afb-daemon */ + return &binding_description; /* returns the description of the binding */ +} + |