@@ 12,142 12,144 @@
enum {
N_PROBES = 4,
+ PROBE_TIMEOUT = 300000, /* 5 min */
FS_LABEL = 30,
FS_TEMP = 60,
FS_HUMI = 30,
FS_PRES = 30,
+ FS_WARN = 45,
PAD = 8,
M_DOT = 3,
R_DOT = 2,
N_DOT = 3,
};
-const size_t ui_period_s = 60;
-
-float bufs[3 * N_PROBES * 4]; /* 3 quantities, 4 probes, 4 samples each */
-struct ringbuf
- temps[N_PROBES] = {
- { .buf = bufs + 0, .cap = 4 },
- { .buf = bufs + 5, .cap = 4 },
- { .buf = bufs + 10, .cap = 4 },
- { .buf = bufs + 15, .cap = 4 },
- },
- humis[N_PROBES] = {
- { .buf = bufs + 20, .cap = 4 },
- { .buf = bufs + 25, .cap = 4 },
- { .buf = bufs + 30, .cap = 4 },
- { .buf = bufs + 35, .cap = 4 },
- },
- press = { .buf = bufs + 40, .cap = N_PROBES * 4 };
-size_t dots[N_PROBES];
+float outside_temps[2] = { NAN, NAN }, outside_humis[2] = { NAN, NAN };
+float pressures[5] = { NAN, NAN, NAN, NAN, NAN };
+uint32_t last_updated[5] = {0};
static void
-draw_dots(uint8_t c, uint8_t r, uint8_t w, uint8_t h, uint8_t idx, bool filled,
- size_t count)
+cell_init(uint8_t c, uint8_t r, uint8_t w, uint8_t h, char label[])
{
int x0 = c * ui_width / 12;
int y0 = r * ui_height / 12;
- int w0 = w * ui_width / 12;
int h0 = h * ui_height / 12;
+ (void) w;
- int dx0 = x0 + w0 - PAD - (N_DOT - 1) * M_DOT - (2 * N_DOT - 1) * R_DOT;
- int dy0 = y0 + h0 - PAD - (N_DOT - 1) * M_DOT - (2 * N_DOT - 1) * R_DOT;
-
- while (count--) {
- if (dots[idx] < N_DOT * N_DOT - 1) {
- ui_draw_circle(
- dx0 + (dots[idx] % N_DOT) * (2 * R_DOT + M_DOT),
- dy0 + (dots[idx] / N_DOT) * (2 * R_DOT + M_DOT),
- R_DOT,
- 0x00,
- filled ? 0x00 : 0xe0,
- filled ? 2.0f * M_PI : 0.0f
- );
- } else if (dots[idx] == N_DOT * N_DOT - 1) {
- /* ellipsis */
- ui_draw_circle(x0 + w0 - PAD - R_DOT,
- y0 + h0 - PAD - R_DOT, 0, 0x00, 0x00, 2 * M_PI);
- ui_draw_circle(x0 + w0 - PAD - R_DOT - 2,
- y0 + h0 - PAD - R_DOT, 0, 0x00, 0x00, 2 * M_PI);
- ui_draw_circle(x0 + w0 - PAD - R_DOT + 2,
- y0 + h0 - PAD - R_DOT, 0, 0x00, 0x00, 2 * M_PI);
- }
- ++dots[idx];
- }
+ text_draw_align(label, x0 + PAD, y0 + PAD, FS_LABEL, TEXT_TOP_LEFT);
+ text_draw_align("---.- °C", x0 + PAD, y0 + h0 / 2, FS_TEMP, TEXT_MIDDLE_LEFT);
+ text_draw_align("---.- %RH", x0 + PAD, y0 + h0 - PAD, FS_HUMI, TEXT_BOTTOM_LEFT);
}
static void
-draw_cell(uint8_t c, uint8_t r, uint8_t w, uint8_t h, uint8_t idx,
- char label[])
+cell_update_temp(uint8_t c, uint8_t r, uint8_t w, uint8_t h, float temp, float humi)
{
char buf[128];
int x0 = c * ui_width / 12;
int y0 = r * ui_height / 12;
+ int w0 = w * ui_width / 12;
int h0 = h * ui_height / 12;
- text_draw_align(label, x0 + PAD, y0 + PAD, FS_LABEL, TEXT_TOP_LEFT);
+ ui_draw_rect(x0 + 1 + PAD, y0 + 1 + PAD + FS_LABEL,
+ x0 + w0 - PAD, y0 + h0 - PAD, 0xff);
- float temp = idx == 2 ? ringbuf_min(temps + idx)
- : ringbuf_median(temps + idx);
- ui_sprintf_or_nan(buf, "%.1f °C", temp, "---.- °C");
+ sprintf(buf, "%.1f °C", temp);
text_draw_align(buf, x0 + PAD, y0 + h0 / 2, FS_TEMP, TEXT_MIDDLE_LEFT);
- float humi = idx == 2 ? ringbuf_max(humis + idx)
- : ringbuf_median(humis + idx);
- ui_sprintf_or_nan(buf, "%.1f %%RH", humi, "---.- %RH");
+ sprintf(buf, "%.1f %%RH", humi);
text_draw_align(buf, x0 + PAD, y0 + h0 - PAD, FS_HUMI, TEXT_BOTTOM_LEFT);
- dots[idx] = 0;
- draw_dots(c, r, w, h, idx, true, temps[idx].size);
+ ui_mark_dirty(x0 + 1, y0 + 1, x0 + w0, y0 + h0);
+}
+
+static void
+cell_update_pres(uint8_t c, uint8_t r, uint8_t w, uint8_t h, float pres)
+{
+ char buf[128];
- while (temps[idx].size) { ringbuf_get(temps + idx); }
- while (humis[idx].size) { ringbuf_get(humis + idx); }
+ int x0 = c * ui_width / 12;
+ int y0 = r * ui_height / 12;
+ int w0 = w * ui_width / 12;
+ int h0 = h * ui_height / 12;
+
+ ui_draw_rect(x0 + 1 + PAD, y0 + 1 + PAD,
+ x0 + w0 - PAD, y0 + h0 - PAD, 0xff);
+
+ sprintf(buf, "%.1f hPa", pres);
+ text_draw_align(buf, PAD, y0 + h0 / 2, FS_PRES, TEXT_MIDDLE_LEFT);
+
+ ui_mark_dirty(x0 + 1, y0 + 1, x0 + w0, y0 + h0);
}
-void
-ui_on_packet(uint16_t serial, float temperature, float pressure, float humidity)
+static void
+cell_update_warn(uint8_t c, uint8_t r, uint8_t w, uint8_t h)
{
- switch (serial) {
- case SERIAL1:
- ringbuf_put(temps + 0, temperature);
- ringbuf_put(&press, pressure);
- ringbuf_put(humis + 0, humidity);
- draw_dots(0, 0, 6, 5, 0, false, 1);
- break;
- case SERIAL2:
- ringbuf_put(temps + 1, temperature);
- ringbuf_put(&press, pressure);
- ringbuf_put(humis + 1, humidity);
- draw_dots(6, 0, 6, 5, 1, false, 1);
- break;
- case SERIAL3:
- ringbuf_put(temps + 2, temperature);
- ringbuf_put(&press, pressure);
- ringbuf_put(humis + 2, humidity);
- draw_dots(0, 5, 6, 5, 2, false, 1);
- break;
- case SERIAL4:
- ringbuf_put(temps + 3, temperature);
- ringbuf_put(&press, pressure);
- ringbuf_put(humis + 3, humidity);
- draw_dots(6, 5, 6, 5, 3, false, 1);
- break;
- case SERIAL5:
- ringbuf_put(temps + 2, temperature);
- ringbuf_put(&press, pressure);
- ringbuf_put(humis + 2, humidity);
- draw_dots(0, 5, 6, 5, 2, false, 1);
- break;
- default:
- return;
+ int x0 = c * ui_width / 12;
+ int y0 = r * ui_height / 12;
+ int w0 = w * ui_width / 12;
+ int h0 = h * ui_height / 12;
+
+ text_draw_align("?", x0 + w0 - PAD, y0 + h0 - PAD, FS_WARN,
+ TEXT_BOTTOM_RIGHT);
+ ui_mark_dirty(x0 + 1, y0 + 1, x0 + w0, y0 + h0);
+}
+
+float
+min(float arr[], size_t sz)
+{
+ float min_ = FLT_MAX;
+ for (size_t i = 0; i < sz; ++i) {
+ if (!isnan(arr[i]) && arr[i] < min_) {
+ min_ = arr[i];
+ }
}
- ui_partref_flag = true;
+ if (min_ == FLT_MAX) {
+ return NAN;
+ }
+
+ return min_;
+}
+
+float
+max(float arr[], size_t sz)
+{
+ float max_ = FLT_MIN;
+ for (size_t i = 0; i < sz; ++i) {
+ if (!isnan(arr[i]) && arr[i] > max_) {
+ max_ = arr[i];
+ }
+ }
+
+ if (max_ == FLT_MIN) {
+ return NAN;
+ }
+
+ return max_;
+}
+
+float
+avg(float arr[], size_t sz)
+{
+ float avg_ = 0;
+ size_t n = 0;
+ for (size_t i = 0; i < sz; ++i) {
+ if (!isnan(arr[i])) {
+ avg_ += arr[i];
+ ++n;
+ }
+ }
+
+ if (n == 0) {
+ return NAN;
+ }
+
+ return avg_ / n;
}
void
-ui_update()
+ui_init()
{
memset(ui_pixbuf, 0xff, ui_width * ui_height);
@@ 155,30 157,77 @@ ui_update()
ui_draw_hline(5 * ui_height / 12, 0, ui_width);
ui_draw_hline(5 * ui_height / 6, 0, ui_width);
- draw_cell(0, 0, 6, 5, 0, "SALON");
- draw_cell(6, 0, 6, 5, 1, "SYPIALNIA");
- draw_cell(0, 5, 6, 5, 2, "NA ZEWNĄTRZ");
- draw_cell(6, 5, 6, 5, 3, "ŁAZIENKA");
+ cell_init(0, 0, 6, 5, "SALON");
+ cell_init(6, 0, 6, 5, "SYPIALNIA");
+ cell_init(0, 5, 6, 5, "NA ZEWNĄTRZ");
+ cell_init(6, 5, 6, 5, "ŁAZIENKA");
- char buf[128];
- int y0 = 10 * ui_height / 12;
- int h0 = 2 * ui_height / 12;
- ui_sprintf_or_nan(buf, "%.1f hPa", ringbuf_median(&press), "----.- hPa");
- text_draw_align(buf, PAD, y0 + h0 / 2, FS_PRES, TEXT_MIDDLE_LEFT);
- while (press.size) { ringbuf_get(&press); }
+ text_draw_align("----.- hPa", PAD, 5 * ui_height / 6 + ui_height / 12,
+ FS_PRES, TEXT_MIDDLE_LEFT);
- /* XXX: BUGGY
- ui_draw_circle(ui_width - ui_height / 12, ui_height - ui_height / 12,
- 10, 0x00, 0x00, 0);
- */
+ ui_mark_dirty(0, 0, ui_width, ui_height);
}
void
-ui_refresh_time(float fraction)
+ui_on_packet(uint32_t timestamp, uint16_t serial, float temperature, float pressure, float humidity)
{
- /* XXX: BUGGY
- ui_draw_circle(ui_width - ui_height / 12, ui_height - ui_height / 12,
- 10, 0x00, 0x00, fraction * 2 * M_PI);
- */
- ui_partref_flag = true;
+ switch (serial) {
+ case SERIAL1:
+ pressures[0] = pressure;
+ cell_update_temp(0, 0, 6, 5, temperature, humidity);
+ cell_update_pres(0, 10, 12, 2, avg(pressures, 5));
+ last_updated[0] = timestamp;
+ break;
+ case SERIAL2:
+ pressures[1] = pressure;
+ cell_update_temp(6, 0, 6, 5, temperature, humidity);
+ cell_update_pres(0, 10, 12, 2, avg(pressures, 5));
+ last_updated[1] = timestamp;
+ break;
+ case SERIAL3:
+ outside_temps[0] = temperature;
+ outside_humis[0] = humidity;
+ pressures[2] = pressure;
+ cell_update_temp(0, 5, 6, 5, min(outside_temps, 2), max(outside_humis, 2));
+ cell_update_pres(0, 10, 12, 2, avg(pressures, 5));
+ last_updated[2] = timestamp;
+ break;
+ case SERIAL4:
+ pressures[3] = pressure;
+ cell_update_temp(6, 5, 6, 5, temperature, humidity);
+ cell_update_pres(0, 10, 12, 2, avg(pressures, 5));
+ last_updated[3] = timestamp;
+ break;
+ case SERIAL5:
+ outside_temps[1] = temperature;
+ outside_humis[1] = humidity;
+ pressures[4] = pressure;
+ cell_update_temp(0, 5, 6, 5, min(outside_temps, 2), max(outside_humis, 2));
+ cell_update_pres(0, 10, 12, 2, avg(pressures, 5));
+ last_updated[4] = timestamp;
+ break;
+ }
+}
+
+void
+ui_update(uint32_t timestamp)
+{
+ bool all = true;
+ for (size_t i = 0; i < 5; ++i) {
+ if (timestamp - last_updated[i] > PROBE_TIMEOUT) {
+ switch (i) {
+ case 0: cell_update_warn(0, 0, 6, 5); break;
+ case 1: cell_update_warn(6, 0, 6, 5); break;
+ case 2: cell_update_warn(0, 5, 6, 5); break;
+ case 3: cell_update_warn(6, 5, 6, 5); break;
+ case 4: cell_update_warn(0, 5, 6, 5); break;
+ }
+ } else {
+ all = false;
+ }
+ }
+
+ if (all) {
+ cell_update_warn(0, 10, 12, 2);
+ }
}