data.c 5.04 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright (c) 2014-2016 Cesanta Software Limited
 * All rights reserved
 */

#include "data.h"

#include <stdio.h>
#include <stdlib.h>

#include "gpio_if.h"

#include "bm222.h"
#include "tmp006.h"
15
#include "cs_dbg.h"
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

struct temp_data {
  double ts;
  double volt;
  double temp;
};

struct conn_state {
  struct temp_data td;
  double last_sent_td;
  unsigned char led;
  double last_sent_led;
  double last_sent_acc;
};

static int s_tmp006_addr;
static struct temp_data s_temp_data;
static struct bm222_ctx *s_accel_ctx;

void data_init_sensors(int tmp006_addr, int bm222_addr) {
  s_tmp006_addr = tmp006_addr;
  if (!tmp006_init(tmp006_addr, TMP006_CONV_2, false)) {
    LOG(LL_ERROR, ("Failed to init temperature sensor"));
  } else {
    LOG(LL_INFO, ("Temperature sensor initialized"));
  }
  s_accel_ctx = bm222_init(bm222_addr);
  if (s_accel_ctx == NULL) {
    LOG(LL_ERROR, ("Failed to init accelerometer"));
  } else {
    LOG(LL_INFO, ("Accelerometer initialized"));
  }
}

50
void data_collect(void) {
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
  double volt = tmp006_read_sensor_voltage(s_tmp006_addr);
  double temp = tmp006_read_die_temp(s_tmp006_addr);
  if (volt != TMP006_INVALID_READING && temp != TMP006_INVALID_READING) {
    s_temp_data.temp = temp;
    s_temp_data.volt = volt;
    s_temp_data.ts = mg_time();
    LOG(LL_DEBUG, ("V = %lf mV, T = %lf C", volt, temp));
  }
  bm222_get_data(s_accel_ctx);
}

static void send_temp(struct mg_connection *nc, const struct temp_data *td) {
  if (td->ts == 0) return;
  mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT,
                            "{\"t\": 0, \"ts\": %lf, \"sv\": %lf, \"dt\": %lf}",
                            td->ts, td->volt, td->temp);
}

static void send_led(struct mg_connection *nc, double ts, unsigned char led) {
  if (ts == 0) return;
  mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT,
                            "{\"t\": 1, \"ts\": %lf, \"v\": %d}", ts, led);
}

static void send_acc_sample(struct mg_connection *nc,
                            const struct bm222_sample *s) {
  if (s->ts == 0) return;
  mg_printf_websocket_frame(
      nc, WEBSOCKET_OP_TEXT,
      "{\"t\": 2, \"ts\": %lf, \"x\": %d, \"y\": %d, \"z\": %d}", s->ts, s->x,
      s->y, s->z);
}

static double send_acc_data_since(struct mg_connection *nc,
                                  const struct bm222_ctx *ctx, double since) {
  int i = (ctx->last_index + 1) % BM222_NUM_SAMPLES, n = BM222_NUM_SAMPLES;
  double last_sent_ts = 0;
  for (; n > 0; i = (i + 1) % BM222_NUM_SAMPLES, n--) {
    const struct bm222_sample *s = ctx->data + i;
    if (s->ts <= since) continue;
    send_acc_sample(nc, s);
    last_sent_ts = s->ts;
  }
  return last_sent_ts;
}

static void process_command(struct mg_connection *nc, unsigned char *data,
                            size_t len) {
99
  // TODO(lsm): use proper JSON parser
100 101 102
  int cmd, val;
  if (sscanf((char *) data, "{\"t\":%d,\"v\":%d}", &cmd, &val) != 2) {
    LOG(LL_ERROR, ("Invalid request: %.*s", (int) len, data));
103 104
    return;
  }
105
  if (cmd == 1) {
106
    switch (val) {
107 108 109 110 111 112 113 114 115 116 117 118 119 120
      case '0': {
        GPIO_IF_LedOff(MCU_RED_LED_GPIO);
        break;
      }
      case '1': {
        GPIO_IF_LedOn(MCU_RED_LED_GPIO);
        break;
      }
      case '2': {
        GPIO_IF_LedToggle(MCU_RED_LED_GPIO);
        break;
      }
      default: {
        LOG(LL_ERROR, ("Invalid value: %.*s", (int) len, data));
121
        return;
122 123 124
      }
    }
  } else {
125 126
    LOG(LL_ERROR, ("Unknown command: %.*s", (int) len, data));
    return;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  }
}

void data_conn_handler(struct mg_connection *nc, int ev, void *ev_data) {
  struct conn_state *cs = (struct conn_state *) nc->user_data;
  if (cs == NULL) {
    cs = (struct conn_state *) calloc(1, sizeof(*cs));
    nc->user_data = cs;
  }
  switch (ev) {
    case MG_EV_POLL:
    case MG_EV_TIMER: {
      const double now = mg_time();
      const unsigned char led = GPIO_IF_LedStatus(MCU_RED_LED_GPIO);
      /* Send if there was a change or repeat last data every second. */
      if (s_temp_data.volt != cs->td.volt || s_temp_data.temp != cs->td.temp ||
          now > cs->last_sent_td + 1.0) {
        memcpy(&cs->td, &s_temp_data, sizeof(cs->td));
        send_temp(nc, &cs->td);
        cs->last_sent_td = now;
      }
      if (led != cs->led || now > cs->last_sent_led + 1.0) {
        send_led(nc, now, led);
        cs->led = led;
        cs->last_sent_led = now;
      }
      if (s_accel_ctx != NULL) {
        const struct bm222_sample *ls =
            s_accel_ctx->data + s_accel_ctx->last_index;
        if (cs->last_sent_acc == 0) {
          send_acc_sample(nc, ls);
          cs->last_sent_acc = ls->ts;
        } else {
          double last_sent_ts =
              send_acc_data_since(nc, s_accel_ctx, cs->last_sent_acc);
          if (last_sent_ts > 0) cs->last_sent_acc = last_sent_ts;
        }
      }
      nc->ev_timer_time = now + 0.05;
      break;
    }
    case MG_EV_WEBSOCKET_FRAME: {
      struct websocket_message *wm = (struct websocket_message *) ev_data;
      process_command(nc, wm->data, wm->size);
      break;
    }
    case MG_EV_CLOSE: {
      LOG(LL_INFO, ("%p closed", nc));
      free(cs);
      break;
    }
  }
}