summaryrefslogtreecommitdiffstats
path: root/CAN-binder/low-can-demo/binding/stat-binding.c
diff options
context:
space:
mode:
Diffstat (limited to 'CAN-binder/low-can-demo/binding/stat-binding.c')
-rw-r--r--CAN-binder/low-can-demo/binding/stat-binding.c272
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 0000000..1e5b2db
--- /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 */
+}
+