From 7235920b7d54cd62ce1e386ae735891240433e89 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 16 Apr 2024 18:47:02 +0100 Subject: [PATCH] Added additional drawing optimisations, changed values from signed ints to doubles for greater precision, removed redundant function calls and attributes --- BarGauge.cpp | 159 +++++++++++++++++++++++----------------- BarGauge.h | 60 ++++++++------- BlockGauge.cpp | 90 ++++++++++++++++++++--- BlockGauge.h | 10 ++- ColumnLayout.cpp | 4 +- Gauge.cpp | 21 ++---- Gauge.h | 49 ++++++------- GridLayout.cpp | 4 +- Layout.cpp | 10 ++- Layout.h | 1 + Measurement.cpp | 7 +- Measurement.h | 16 ++-- adafruit-tft-gauges.ino | 145 +++++++++++++++++++++--------------- main.h | 15 ++-- 14 files changed, 355 insertions(+), 236 deletions(-) diff --git a/BarGauge.cpp b/BarGauge.cpp index f8a59b9..321bf33 100644 --- a/BarGauge.cpp +++ b/BarGauge.cpp @@ -6,7 +6,7 @@ /* ------------------------------------------------------------------------- */ BarGauge::BarGauge(Adafruit_ILI9341 * display, Measurement * measurement, - char * name, int32_t range_min, int32_t range_max) + char * name, double range_min, double range_max) : Gauge(display, measurement, name, range_min, range_max) { this->bar_colour = GREEN; @@ -25,14 +25,20 @@ BarGauge::BarGauge(Adafruit_ILI9341 * display, Measurement * measurement, /* ------------------------------------------------------------------------- */ uint16_t BarGauge::get_bar_y_for_value(uint16_t x, uint16_t y, uint16_t w, - uint16_t h, uint32_t value) { - uint16_t max_avail_height = h - (this->padding * 2) - - this->label_section_height; - int new_value_height = ((value - this->value_min) * max_avail_height) / - (this->value_max - this->value_min); - uint16_t new_value_y = y + (h - new_value_height) - - this->padding - this->label_section_height; - return new_value_y; + uint16_t h, double value) { + if (this->value_max == this->value_min) { + return y + this->padding; + } + + uint16_t max_avail_height = + (h > (this->padding * 2 + this->label_section_height)) ? + h - (this->padding * 2 + this->label_section_height) : 0; + + double range = this->value_max - this->value_min; + double scaled_value = (value - this->value_min) / range; + uint16_t new_value_height = round(scaled_value * max_avail_height); + + return y + h - new_value_height - this->padding - this->label_section_height; } /* ------------------------------------------------------------------------- */ @@ -57,7 +63,7 @@ uint16_t BarGauge::get_max_bar_height(uint16_t frame_h) { /* ------------------------------------------------------------------------- */ void BarGauge::draw_limit_bar(uint16_t x, uint16_t y, uint16_t w, - uint16_t h, uint16_t colour, int32_t value) { + uint16_t h, uint16_t colour, double value) { int limit_x1 = x; int limit_x2 = x + w - 1; int limit_y = this->get_bar_y_for_value(x, @@ -83,8 +89,9 @@ void BarGauge::draw_reading(uint16_t x, uint16_t y, uint16_t width, this->display->setTextSize(2); - char str[8]; - sprintf(str, "%d", this->value); + double value = this->measurement->get_value(); + char str[8]; + dtostrf(value, 0, 0, str); /* If we're writing a shorter string than last time we'll need to redraw the area */ @@ -120,23 +127,23 @@ void BarGauge::draw_name(uint16_t x, uint16_t y, uint16_t width, * @width: The width of the gauge to be drawn. * @height: The height of the gauge to be drawn. */ -void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16_t gauge_h) { +void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, + uint16_t gauge_h) { /* --------------- */ /* Bounds Clamping */ /* --------------- */ this->value = this->measurement->get_value(); - uint32_t bar_value = 0; - + double bar_value = 0; if(this->value > this->value_max) { bar_value = this->value_max; } else { bar_value = this->value; } - if(this->value < 0) { - bar_value = 0; + if(this->value < this->value_min) { + bar_value = this->value_min; } /* --------------------------------------- */ @@ -161,27 +168,32 @@ void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16 /* Calculate the X and Y co-ordinates of where our bar will begin */ uint16_t bar_x, bar_y, prev_x, prev_y = 0; - this->get_bar_xy(frame_x, frame_y, frame_w, frame_h, &bar_x, &bar_y, bar_height); - this->get_bar_xy(frame_x, frame_y, frame_w, frame_h, &prev_x, &prev_y, prev_bar_height); + this->get_bar_xy(frame_x, frame_y, frame_w, frame_h, &bar_x, &bar_y, + bar_height); + this->get_bar_xy(frame_x, frame_y, frame_w, frame_h, &prev_x, &prev_y, + prev_bar_height); /* ---------------- */ /* Bar Border Frame */ /* ---------------- */ - /* Draw a frame around the bar bounds */ uint16_t bar_frame_width = bar_width + (BAR_FRAME_PADDING * 2); uint16_t bar_frame_height = max_bar_height + BAR_FRAME_PADDING; - this->display->drawRect(frame_x, - frame_y, - frame_w, - frame_h, - this->frame_colour); + /* Draw a frame around the bar bounds */ + if(this->requires_redraw) { + this->display->drawRect(frame_x, + frame_y, + frame_w, + frame_h, + this->frame_colour); + } /* ------------- */ /* Bar Rendering */ /* ------------- */ uint16_t bar_colour = this->colour_normal; + uint16_t text_colour = WHITE; if(this->has_limit_higher && (this->value >= this->limit_higher)) { bar_colour = this->colour_high; } @@ -190,9 +202,8 @@ void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16 bar_colour = this->colour_low; } - /* If we have a new alarm state, we'll need to re-render the entire bar in the - colour appropriate for the state */ - if(bar_colour != this->last_bar_colour) { + /* If the bar has changed colour, we'll have to re-render the whole bar */ + if(bar_colour != this->last_colour) { this->display->fillRect(bar_x, bar_y, bar_width, @@ -202,15 +213,13 @@ void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16 /* If this is the first time rendering, render the full bar and do no more checks */ - if(this->initialised == 0) { + if(this->requires_redraw == 1) { this->display->fillRect(bar_x, bar_y, bar_width, bar_height, bar_colour); this->value_last = bar_value; - this->initialised = 1; - return; } /* If the value hasn't changed, we don't need to render anything */ @@ -243,32 +252,39 @@ void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16 /* The limit bar indicates where the alarm limit is on the bar, and changes colour when the limit has been reached. */ - - if(this->has_limit_higher) { - if(this->value >= this->limit_higher) { - this->draw_limit_bar(bar_x - BAR_FRAME_PADDING, - gauge_y, - bar_frame_width, - gauge_h, - YELLOW, - this->limit_higher); - } else { - this->draw_limit_bar(bar_x - BAR_FRAME_PADDING, - gauge_y, - bar_frame_width, - gauge_h, - WHITE, - this->limit_higher); + if(this->requires_redraw + || (bar_value >= limit_higher-(limit_higher * 0.05) && bar_value <= limit_higher+(limit_higher * 0.05) + || bar_colour != this->last_colour)) { + if(this->has_limit_higher) { + if(this->value >= this->limit_higher) { + this->draw_limit_bar(bar_x - BAR_FRAME_PADDING, + gauge_y, + bar_frame_width, + gauge_h, + YELLOW, + this->limit_higher); + } else { + this->draw_limit_bar(bar_x - BAR_FRAME_PADDING, + gauge_y, + bar_frame_width, + gauge_h, + WHITE, + this->limit_higher); + } } } - if(this->has_limit_lower) { - this->draw_limit_bar(bar_x - BAR_FRAME_PADDING, - gauge_y, - bar_frame_width, - gauge_h, - WHITE, - this->limit_lower); + if(this->requires_redraw + || (bar_value >= limit_lower-(limit_lower * 0.05) && bar_value <= limit_lower+(limit_lower * 0.05)) + || bar_colour != this->last_colour) { + if(this->has_limit_lower) { + this->draw_limit_bar(bar_x - BAR_FRAME_PADDING, + gauge_y, + bar_frame_width, + gauge_h, + WHITE, + this->limit_lower); + } } /* --------------- */ @@ -276,37 +292,44 @@ void BarGauge::draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16 /* --------------- */ if(this->label_enabled) { - this->draw_reading(gauge_x, gauge_y, gauge_w, gauge_h); - this->draw_name(gauge_x, gauge_y, gauge_w, gauge_h); + if(this->requires_redraw + || fabs(this->measurement->get_value() - this->value_last) > EPSILON) + this->draw_reading(gauge_x, gauge_y, gauge_w, gauge_h); + if(this->requires_redraw) + this->draw_name(gauge_x, gauge_y, gauge_w, gauge_h); } this->value_last = bar_value; - this->last_bar_colour = bar_colour; + this->last_colour = bar_colour; + this->requires_redraw = false; } /* ------------------------------------------------------------------------- */ /* Setters and Getters */ /* ------------------------------------------------------------------------- */ -void BarGauge::set_frame_colour(uint16_t frame_colour) { - this->frame_colour = frame_colour; +void BarGauge::set_frame_colour(uint16_t value) { + this->frame_colour = value; } /* ------------------------------------------------------------------------- */ -void BarGauge::set_limit_bar_height(uint32_t height) { - this->limit_bar_height = height; +void BarGauge::set_limit_bar_height(uint32_t value) { + this->limit_bar_height = value; } /* ------------------------------------------------------------------------- */ -void BarGauge::set_label_state(uint8_t state) { - this->label_enabled = state; - if(state == 0) { - this->label_section_height = 0; - } else { - this->label_section_height = LABEL_SECTION_HEIGHT; - } +void BarGauge::enable_labels() { + this->label_enabled = true; + this->label_section_height = LABEL_SECTION_HEIGHT; +} + +/* ------------------------------------------------------------------------- */ + +void BarGauge::disable_labels() { + this->label_enabled = false; + this->label_section_height = 0; } /* ------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/BarGauge.h b/BarGauge.h index 8be4c80..6666c98 100644 --- a/BarGauge.h +++ b/BarGauge.h @@ -12,38 +12,46 @@ /* ------------------------------------------------------------------------- */ class BarGauge : public Gauge { + public: - BarGauge(Adafruit_ILI9341 * display, Measurement * easurement, - char * name, int32_t range_min, int32_t range_max); - void draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16_t gauge_h) override; - void draw_limit_bar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t colour, int32_t value); - void draw_reading(uint16_t x, uint16_t y, uint16_t width, uint16_t height); - void draw_name(uint16_t x, uint16_t y, uint16_t width, uint16_t height); + BarGauge(Adafruit_ILI9341 * display, Measurement * easurement, + char * name, double range_min, double range_max); - void set_frame_colour(uint16_t frame_colour); - void set_limit_bar_height(uint32_t height); - void set_label_state(uint8_t state); + void draw(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, + uint16_t gauge_h) override; + void set_frame_colour(uint16_t value); + void set_limit_bar_height(uint32_t value); + + void enable_labels(); + void disable_labels(); - uint16_t get_bar_y_for_value(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t value); - void get_bar_xy(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, uint16_t gauge_h, uint16_t * dst_x, uint16_t * dst_y, uint16_t bar_height); - uint16_t get_max_bar_height(uint16_t frame_h); private: - uint8_t last_reading_length; - - uint16_t bar_colour; - uint16_t bar_colour_high; - uint16_t bar_colour_low; - uint16_t last_bar_colour; - uint16_t frame_colour; - - int32_t min_bar_value; - int32_t max_bar_value; - uint16_t frame_padding; - uint16_t label_section_height; - uint8_t limit_bar_height; - uint8_t label_enabled; + + void draw_limit_bar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + uint16_t colour, double value); + void draw_reading(uint16_t x, uint16_t y, uint16_t width, uint16_t height); + void draw_name(uint16_t x, uint16_t y, uint16_t width, uint16_t height); + + uint16_t get_bar_y_for_value(uint16_t x, uint16_t y, uint16_t w, + uint16_t h, double value); + uint16_t get_max_bar_height(uint16_t frame_h); + void get_bar_xy(uint16_t gauge_x, uint16_t gauge_y, uint16_t gauge_w, + uint16_t gauge_h, uint16_t * dst_x, uint16_t * dst_y, + uint16_t bar_height); + + uint8_t last_reading_length; + + uint16_t bar_colour; + uint16_t bar_colour_high; + uint16_t bar_colour_low; + uint16_t frame_colour; + + uint16_t frame_padding; + uint16_t label_section_height; + uint8_t limit_bar_height; + uint8_t label_enabled; }; /* ------------------------------------------------------------------------- */ diff --git a/BlockGauge.cpp b/BlockGauge.cpp index b087840..99ac283 100644 --- a/BlockGauge.cpp +++ b/BlockGauge.cpp @@ -3,9 +3,13 @@ /* ------------------------------------------------------------------------- */ BlockGauge::BlockGauge(Adafruit_ILI9341 * display, - Measurement * measurement, char * name, - int32_t range_min, int32_t range_max) + Measurement * measurement, char * name, + double range_min, double range_max) : Gauge(display, measurement, name, range_min, range_max) { + this->text_colour_high = WHITE; + this->text_colour_low = WHITE; + this->text_colour_normal = WHITE; + this->frame_colour = WHITE; } /* ------------------------------------------------------------------------- */ @@ -15,23 +19,85 @@ void BlockGauge::draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height) { int frame_y = y + this->padding; int frame_w = width - (this->padding * 2); int frame_h = height - (this->padding * 2); - this->display->drawRect(frame_x, frame_y, frame_w, frame_h, WHITE); + + /* Draw outer frame */ + if(this->requires_redraw) + this->display->drawRect(frame_x, frame_y, frame_w, frame_h, WHITE); + + /* Determine block colour */ + int16_t block_colour = BLACK; + int16_t text_colour = this->text_colour_normal; + if(this->has_limit_higher && (this->measurement->get_value() >= this->limit_higher)) { + block_colour = this->colour_high; + text_colour = this->text_colour_high; + } + + if(this->has_limit_lower && (this->measurement->get_value() < this->limit_lower)) { + block_colour = this->colour_low; + text_colour = this->text_colour_low; + } + + if(this->requires_redraw || (block_colour != this->last_colour)) { + this->display->fillRect(frame_x + 1, + frame_y + 1, + frame_w - 2, + frame_h - 2, + block_colour); + } int value_x = x + (width / 2); int value_y = y + (height / 2); - char value_str[8]; - sprintf(value_str, "%d", this->measurement->get_value()); + double value = this->measurement->get_value(); + char str[20]; // Ensure the buffer is large enough for the number and decimal places + dtostrf(value, 0, 0, str); // Convert double to string with 3 decimal places + + this->display->setTextColor(text_colour, block_colour); + + /* Draw the value reading */ + if(this->requires_redraw || fabs(this->measurement->get_value() - this->value_last) > EPSILON) { + this->display->setTextSize(4); + if(strlen(str) < this->last_reading_length) { + char clearing_str[this->last_reading_length + 1]; + memset(clearing_str, ' ', this->last_reading_length); + clearing_str[this->last_reading_length] = '\0'; + this->draw_centred_string(clearing_str, value_x, value_y - 5); + } + this->draw_centred_string(str, value_x, value_y - 5); + } + + /* Draw the measurement name */ + if(this->requires_redraw || (block_colour != this->last_colour)) { + this->display->setTextSize(1); + this->draw_centred_string(this->name, value_x, value_y + 25); + } + + this->last_reading_length = strlen(str); + this->requires_redraw = false; + this->last_colour = block_colour; +} + +/* ------------------------------------------------------------------------- */ + +void BlockGauge::set_text_colour_low(uint16_t value) { + this->text_colour_low = value; +} + +/* ------------------------------------------------------------------------- */ - this->display->setTextSize(4); +void BlockGauge::set_text_colour_high(uint16_t value) { + this->text_colour_high = value; +} - if(strlen(value_str) < this->last_reading_length) - this->draw_centred_string(" ", value_x, value_y - 5); - this->draw_centred_string(value_str, value_x, value_y - 5); +/* ------------------------------------------------------------------------- */ - this->display->setTextSize(2); - this->draw_centred_string(this->name, value_x, value_y + 25); +void BlockGauge::set_text_colour_normal(uint16_t value) { + this->text_colour_normal = value; +} + +/* ------------------------------------------------------------------------- */ - this->last_reading_length = strlen(value_str); +void BlockGauge::set_frame_colour(uint16_t value) { + this->frame_colour = value; } /* ------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/BlockGauge.h b/BlockGauge.h index b2711f0..a90feb8 100644 --- a/BlockGauge.h +++ b/BlockGauge.h @@ -8,10 +8,18 @@ class BlockGauge : public Gauge { public: BlockGauge(Adafruit_ILI9341 * display, Measurement * measurement, - char * name, int32_t range_min, int32_t range_max); + char * name, double range_min, double range_max); void draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height) override; + void set_text_colour_low(uint16_t value); + void set_text_colour_high(uint16_t value); + void set_text_colour_normal(uint16_t value); + void set_frame_colour(uint16_t value); private: uint8_t last_reading_length; + uint16_t text_colour_low; + uint16_t text_colour_high; + uint16_t text_colour_normal; + uint16_t frame_colour; }; /* ------------------------------------------------------------------------- */ diff --git a/ColumnLayout.cpp b/ColumnLayout.cpp index 2fcb344..093a4ec 100644 --- a/ColumnLayout.cpp +++ b/ColumnLayout.cpp @@ -11,8 +11,8 @@ ColumnLayout::ColumnLayout(Adafruit_ILI9341 * display) : Layout(display) { void ColumnLayout::draw() { uint16_t x = 0; uint16_t y = 0; - uint16_t width = 320 / this->gauge_count; - uint16_t height = 240; + uint16_t width = this->display->width() / this->gauge_count; + uint16_t height = this->display->height(); if(this->title_enabled) { y = 27; diff --git a/Gauge.cpp b/Gauge.cpp index a27af8a..00f29e0 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -17,7 +17,7 @@ Gauge::Gauge(Adafruit_ILI9341 * display, Measurement * measurement, this->limit_higher = 0; this->padding = GAUGE_PADDING_DEFAULT; this->measurement = measurement; - this->initialised = 0; + this->requires_redraw = 1; this->colour_high = RED; this->colour_low = CYAN; this->colour_normal = GREEN; @@ -35,7 +35,8 @@ void Gauge::draw_frame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, /* ------------------------------------------------------------------------- */ -void Gauge::initial_draw() { +void Gauge::redraw() { + this->requires_redraw = 1; } /* ------------------------------------------------------------------------- */ @@ -56,14 +57,14 @@ void Gauge::draw_centred_string(const char *buf, int x, int y) /* Setters and Getters */ /* ------------------------------------------------------------------------- */ -void Gauge::set_limit_lower(int32_t value) { +void Gauge::set_limit_lower(double value) { this->has_limit_lower = 1; this->limit_lower = value; } /* ------------------------------------------------------------------------- */ -void Gauge::set_limit_higher(int32_t value) { +void Gauge::set_limit_higher(double value) { this->has_limit_higher = 1; this->limit_higher = value; this->value_max = this->limit_higher * GAUGE_LIMIT_MULTIPLIER; @@ -71,20 +72,14 @@ void Gauge::set_limit_higher(int32_t value) { /* ------------------------------------------------------------------------- */ -void Gauge::set_value(uint32_t value) { +void Gauge::set_value(double value) { this->value = value; } /* ------------------------------------------------------------------------- */ -void Gauge::set_padding(uint16_t padding) { - this->padding = padding; -} - -/* ------------------------------------------------------------------------- */ - -void Gauge::set_initialised(uint8_t state) { - this->initialised = state; +void Gauge::set_padding(uint8_t value) { + this->padding = value; } /* ------------------------------------------------------------------------- */ diff --git a/Gauge.h b/Gauge.h index 55fb050..a3c9bc2 100644 --- a/Gauge.h +++ b/Gauge.h @@ -1,6 +1,7 @@ #ifndef CGAUGE_H #define CGAUGE_H +#include #include "Arduino.h" #include "SPI.h" #include "Adafruit_GFX.h" @@ -8,7 +9,6 @@ #include "Measurement.h" #define GAUGE_LIMIT_MULTIPLIER 1.25 - #define GAUGE_PADDING_DEFAULT 3 #define BLACK ILI9341_BLACK @@ -31,61 +31,58 @@ #define GREENYELLOW ILI9341_GREENYELLOW #define PINK ILI9341_PINK - -/* ------------------------------------------------------------------------- */ - -typedef struct { - uint16_t x; - uint16_t y; - uint16_t w; - uint16_t h; -} dimensions_t; +const double EPSILON = 0.001; /* ------------------------------------------------------------------------- */ class Gauge { + public: + Gauge(Adafruit_ILI9341 * display, Measurement * measurement, char * name, int32_t range_min, int32_t range_max); + void draw_frame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t colour); - void initial_draw(); + void redraw(); - void set_limit_lower(int32_t value); - void set_limit_higher(int32_t value); - void set_value(uint32_t value); - void set_padding(uint16_t padding); - void set_initialised(uint8_t state); + void set_limit_lower(double value); + void set_limit_higher(double value); + void set_value(double value); + void set_padding(uint8_t value); void set_colour_normal(uint16_t value); void set_colour_high(uint16_t value); void set_colour_low(uint16_t value); - void draw_centred_string(const char *buf, int x, int y); - virtual void draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height) { } + protected: - int32_t value; - int32_t value_min; - int32_t value_max; - int32_t value_last; + + void draw_centred_string(const char *buf, int x, int y); + + double value; + double value_min; + double value_max; + double value_last; uint16_t colour_normal; uint16_t colour_low; uint16_t colour_high; + uint16_t last_colour; uint8_t has_limit_lower; uint8_t has_limit_higher; - int32_t limit_lower; - int32_t limit_higher; + double limit_lower; + double limit_higher; Measurement * measurement; - uint16_t padding; + uint8_t padding; char name[16]; - uint8_t initialised; + uint8_t requires_redraw; Adafruit_ILI9341 * display; }; diff --git a/GridLayout.cpp b/GridLayout.cpp index 87a9422..87e500b 100644 --- a/GridLayout.cpp +++ b/GridLayout.cpp @@ -12,8 +12,8 @@ GridLayout::GridLayout(Adafruit_ILI9341 * display) : Layout(display) { void GridLayout::draw() { uint16_t x = 0; uint16_t y = 0; - uint16_t width = 320 / this->gauges_wide; - uint16_t height = 240; + uint16_t width = this->display->width() / this->gauges_wide; + uint16_t height = this->display->height(); for(uint8_t i = 0; i < this->gauge_count; i++) { diff --git a/Layout.cpp b/Layout.cpp index b71a749..56b6446 100644 --- a/Layout.cpp +++ b/Layout.cpp @@ -29,7 +29,7 @@ void Layout::add_gauge(Gauge * gauge) { void Layout::redraw() { for(uint8_t i = 0; i < MAX_GAUGES; i++) { if(this->gauges[i] != NULL) { - this->gauges[i]->set_initialised(0); + this->gauges[i]->redraw(); } } } @@ -52,4 +52,12 @@ void Layout::disable_title() { this->title_enabled = 0; } +/* ------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ + +uint16_t Layout::get_gauge_count() { + return this->gauge_count; +} + /* ------------------------------------------------------------------------- */ \ No newline at end of file diff --git a/Layout.h b/Layout.h index 593df67..679d27b 100644 --- a/Layout.h +++ b/Layout.h @@ -12,6 +12,7 @@ class Layout { void add_gauge(Gauge * gauge); void redraw(); void set_title(char * title); + uint16_t get_gauge_count(); void enable_title(); void disable_title(); protected: diff --git a/Measurement.cpp b/Measurement.cpp index adb9eed..0d1f9b0 100644 --- a/Measurement.cpp +++ b/Measurement.cpp @@ -2,8 +2,7 @@ /* ------------------------------------------------------------------------- */ -Measurement::Measurement(char * name) { - strncpy(this->name, name, MEASUREMENT_NAME_MAX); +Measurement::Measurement() { } /* ------------------------------------------------------------------------- */ @@ -14,13 +13,13 @@ void Measurement::set_data_type(uint32_t data_type) { /* ------------------------------------------------------------------------- */ -void Measurement::set_value(int32_t value) { +void Measurement::set_value(double value) { this->value = value; } /* ------------------------------------------------------------------------- */ -int32_t Measurement::get_value() { +double Measurement::get_value() { return this->value; } diff --git a/Measurement.h b/Measurement.h index 3092800..7998422 100644 --- a/Measurement.h +++ b/Measurement.h @@ -5,22 +5,16 @@ /* ------------------------------------------------------------------------- */ -#define MEASUREMENT_NAME_MAX 16 - -/* ------------------------------------------------------------------------- */ - class Measurement { public: - Measurement(char * name); - void set_data_type(uint32_t data_type); - - int32_t get_value(); - void set_value(int32_t value); + Measurement(); + void set_data_type(uint32_t data_type); + double get_value(); + void set_value(double value); private: uint32_t id; uint32_t data_type; - int32_t value; - char name[MEASUREMENT_NAME_MAX]; + double value; }; /* ------------------------------------------------------------------------- */ diff --git a/adafruit-tft-gauges.ino b/adafruit-tft-gauges.ino index 618e614..78dfd4f 100644 --- a/adafruit-tft-gauges.ino +++ b/adafruit-tft-gauges.ino @@ -20,19 +20,19 @@ /* Measurement Set-up */ /* ------------------------------------------------------------------------- */ -/* Analog to Digital Converter Pin Values */ -Measurement adc0Data = Measurement("ADC0"); -Measurement adc1Data = Measurement("ADC1"); -Measurement adc2Data = Measurement("ADC2"); -Measurement adc3Data = Measurement("ADC3"); -Measurement adc4Data = Measurement("ADC4"); - /* Simulated Car Sensor Data */ -Measurement coolTemp = Measurement("CoolT"); -Measurement oilTemp = Measurement("OilT"); -Measurement oilPres = Measurement("OilP"); -Measurement iat = Measurement("IAT"); -Measurement boost = Measurement("Boost"); +Measurement coolTemp = Measurement(); +Measurement oilTemp = Measurement(); +Measurement oilPres = Measurement(); +Measurement iat = Measurement(); +Measurement boost = Measurement(); + +/* Values to test drawing of values in and out of bounds */ +Measurement testMax = Measurement(); +Measurement testMin = Measurement(); +Measurement testNeg = Measurement(); +Measurement testBelowMin = Measurement(); +Measurement testAboveMax = Measurement(); /* ------------------------------------------------------------------------- */ /* Device Initialisation */ @@ -49,88 +49,121 @@ void setup() { display.setTextColor(WHITE, BLACK); touchscreen.begin(); - /* ADC bar gauge initialisation */ - BarGauge * adcGauge0 = new BarGauge(&display, &adc0Data, "ADC0", 0, 512); - adcGauge0->set_colour_normal(RED); - BarGauge * adcGauge1 = new BarGauge(&display, &adc1Data, "ADC1", 0, 512); - adcGauge1->set_colour_normal(GREEN); - BarGauge * adcGauge2 = new BarGauge(&display, &adc2Data, "ADC2", 0, 512); - adcGauge2->set_colour_normal(BLUE); - BarGauge * adcGauge3 = new BarGauge(&display, &adc3Data, "ADC3", 0, 512); - adcGauge3->set_colour_normal(YELLOW); - BarGauge * adcGauge4 = new BarGauge(&display, &adc4Data, "ADC4", 0, 512); - adcGauge4->set_colour_normal(ORANGE); - adcLayout.add_gauge(adcGauge0); - adcLayout.add_gauge(adcGauge1); - adcLayout.add_gauge(adcGauge2); - adcLayout.add_gauge(adcGauge3); - adcLayout.add_gauge(adcGauge4); - - /* Car bar gauge initialisation */ + /* Coolant temperature bar: ensuring our coolant is not too hot is the + priority, as this will allow the engine to overheat. We set the bar + to red in this scenario, but also add a lower limit just to tell us + when the coolant is still quite cold. */ BarGauge * coolTBar = new BarGauge(&display, &coolTemp, "CoolT", 0, 100); coolTBar->set_limit_higher(100); - coolTBar->set_limit_lower(70); + coolTBar->set_limit_lower(50); coolTBar->set_colour_low(CYAN); coolTBar->set_colour_normal(GREEN); coolTBar->set_colour_high(RED); - BarGauge * oilTBar = new BarGauge(&display, &oilTemp, "OilT", 0, 150); + + /* Oil temperature bar: we want to keep oil within a certain acceptable + temp. range, as oil that's too cold is not viscous enough, and oil that's + too hot can degrade and lose its effectiveness. The bar therefore is + cyan when the oil is below its limits (too cold), and red when the oil + is above its limits (too hot). When it's in the middle, it's green. */ + BarGauge * oilTBar = new BarGauge(&display, &oilTemp, "OilT", 0, 150); oilTBar->set_limit_higher(120); oilTBar->set_limit_lower(70); oilTBar->set_colour_low(CYAN); oilTBar->set_colour_normal(GREEN); oilTBar->set_colour_high(RED); - BarGauge * oilPBar = new BarGauge(&display, &oilPres, "OilP", 0, 50); + + /* Oil pressure bar: maintaining pressure is critical, and ensuring that + it does not drop too low is most important. However, oil pressure that's + too high is also a sign of a failure (e.g. blockage), so we set the limits + for both, and make the bar red for either scenario. */ + BarGauge * oilPBar = new BarGauge(&display, &oilPres, "OilP", 0, 50); oilPBar->set_limit_lower(20); oilPBar->set_limit_higher(50); /* We don't want oil pressure to be too low OR too high */ oilPBar->set_colour_low(RED); oilPBar->set_colour_high(RED); - BarGauge * iatBar = new BarGauge(&display, &iat, "IAT", 0, 50); - iatBar->set_colour_normal(WHITE); - BarGauge * boostBar = new BarGauge(&display, &boost, "Boost", 0, 15); + + /* Intake air temperature bar: Colder air is better for engine performance, + so we don't set a lower limit. Hotter air will reduce engine performance, + but is also unlikely to be a major issue, so we set the higher limit but + assign the colour to orange, as red suggests a failure. */ + BarGauge * iatBar = new BarGauge(&display, &iat, "IAT", 0, 40); + iatBar->set_limit_higher(40); + iatBar->set_colour_high(ORANGE); + + /* Turbo boost: boost levels will be very low at low RPM, so we don't need + any sort of lower limit. Additionally, low boost isn't necessarily good + or bad, so we make the bar white by default. Too high boost can definitely + be a problem, so we set an upper limit and set the bar to red if it's + exceeded. */ + BarGauge * boostBar = new BarGauge(&display, &boost, "Boost", 0, 30); + boostBar->set_limit_higher(30); + boostBar->set_colour_high(RED); boostBar->set_colour_normal(WHITE); + + /* Add all of the registered car gauges to the car layout */ carBarLayout.add_gauge(coolTBar); carBarLayout.add_gauge(oilTBar); carBarLayout.add_gauge(oilPBar); carBarLayout.add_gauge(iatBar); carBarLayout.add_gauge(boostBar); - /* Car block gauge initialisation */ + /* Configure block gauges for car sensors */ BlockGauge * coolTBlock = new BlockGauge(&display, &coolTemp, "CoolT", 0, 100); - BlockGauge * oilTBlock = new BlockGauge(&display, &oilTemp, "OilT", 0, 140); + coolTBlock->set_limit_higher(100); + coolTBlock->set_limit_lower(84); + coolTBlock->set_text_colour_normal(DARKGREY); + coolTBlock->set_text_colour_low(BLACK); + coolTBlock->set_frame_colour(DARKGREY); + BlockGauge * oilTBlock = new BlockGauge(&display, &oilTemp, "OilT", 0, 125); + oilTBlock->set_limit_higher(120); BlockGauge * oilPBlock = new BlockGauge(&display, &oilPres, "OilP", 0, 65); BlockGauge * iatBlock = new BlockGauge(&display, &iat, "IAT", 0, 50); BlockGauge * boostBlock = new BlockGauge(&display, &boost, "Boost", 0, 15); + + /* Add car block gauges */ carBlockLayout.add_gauge(coolTBlock); carBlockLayout.add_gauge(oilTBlock); carBlockLayout.add_gauge(oilPBlock); carBlockLayout.add_gauge(iatBlock); carBlockLayout.add_gauge(boostBlock); + /* Bounds testing */ + BarGauge * testMinBar = new BarGauge(&display, &testMin, "Min", 0, 100); + BarGauge * testMaxBar = new BarGauge(&display, &testMax, "Max", 0, 100); + BarGauge * testNegBar = new BarGauge(&display, &testNeg, "Neg", -10, 10); + BarGauge * testBMinBar = new BarGauge(&display, &testBelowMin, "BMin", 0, 100); + BarGauge * testAMaxBar = new BarGauge(&display, &testAboveMax, "AMax", 0, 100); + testMin.set_value(0); + testMax.set_value(100); + testNeg.set_value(-5); + testBelowMin.set_value(-10); + testAboveMax.set_value(110); + + testLayout.add_gauge(testMinBar); + testLayout.add_gauge(testMaxBar); + testLayout.add_gauge(testNegBar); + testLayout.add_gauge(testBMinBar); + testLayout.add_gauge(testAMaxBar); + /* Register the three layouts for use */ add_layout(&carBarLayout); - add_layout(&adcLayout); add_layout(&carBlockLayout); + add_layout(&testLayout); } /* ------------------------------------------------------------------------- */ /* Main Loop */ /* ------------------------------------------------------------------------- */ void loop() { - /* Pressing the touch screen will skip to the next layout */ if(touchscreen.touched() && last_touch_state != 1) { next_layout(); } last_touch_state = touchscreen.touched(); - /* We want to handle touchscreen events very quickly, but don't want to - call the intensive draw function that often. */ - if(millis() - last_draw >= DRAW_DELAY) { - update_measurements(); - draw(); - last_draw = millis(); - } + update_measurements(); + draw(); delay(MAIN_LOOP_DELAY); } @@ -148,20 +181,12 @@ void draw() { /* ------------------------------------------------------------------------- */ void update_measurements() { - adc0Data.set_value(analogRead(A0)); - adc1Data.set_value(analogRead(A1)); - adc2Data.set_value(analogRead(A2)); - adc3Data.set_value(analogRead(A3)); - adc4Data.set_value(analogRead(A4)); - adc4Data.set_value(analogRead(A5)); - /* Generate some simulated values for car sensors */ - coolTemp.set_value(random(87, 92)); - oilTemp.set_value(random(105, 108)); - oilPres.set_value(random(20, 35)); - oilPres.set_value(random(37, 42)); - iat.set_value(random(32, 35)); - boost.set_value(random(7, 12)); + coolTemp.set_value(random(42, 47)); + oilTemp.set_value(random(132, 133)); + oilPres.set_value(random(37, 38)); + iat.set_value(random(24, 27)); + boost.set_value(random(18, 21)); } /* ------------------------------------------------------------------------- */ diff --git a/main.h b/main.h index b850c40..5fdf87d 100644 --- a/main.h +++ b/main.h @@ -1,8 +1,6 @@ -#include "SPI.h" #include "Adafruit_GFX.h" #include #include -#include #include "Measurement.h" #include "BarGauge.h" @@ -14,9 +12,9 @@ #define TFT_DC 9 #define TFT_CS 10 -#define MAX_LAYOUTS 32 +#define MAX_LAYOUTS 4 #define MAIN_LOOP_DELAY 50 -#define DRAW_DELAY 200 +#define DRAW_DELAY 100 /* ------------------------------------------------------------------------- */ @@ -26,16 +24,13 @@ Adafruit_FT6206 touchscreen = Adafruit_FT6206(); uint8_t current_layout = 0; Layout * layouts[MAX_LAYOUTS] = {NULL}; -ColumnLayout adcLayout = ColumnLayout(&display); -ColumnLayout carBarLayout = ColumnLayout(&display); -GridLayout carBlockLayout = GridLayout(&display); +ColumnLayout carBarLayout = ColumnLayout(&display); +GridLayout carBlockLayout = GridLayout(&display); +ColumnLayout testLayout = ColumnLayout(&display); /* Used to ensure we know whether the touch event is new or not */ uint8_t last_touch_state = 0; -/* Used to call the draw() function less frequently than the main loop fires */ -uint32_t last_draw = 0; - /* ------------------------------------------------------------------------- */ void update_measurements();