~jacqueline/neon-genesis-ovengeleon

ab7348247c1268eec1cf696c9054165734b08eab — jacqueline 4 months ago 903cc6a
Mostly working? w/pretty colours
1 files changed, 110 insertions(+), 47 deletions(-)

M src/main.cpp
M src/main.cpp => src/main.cpp +110 -47
@@ 1,3 1,5 @@
#include "Adafruit_ST77xx.h"
#include "hardware/sync.h"
#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>


@@ 18,8 20,6 @@

#define DISPLAY_CS (17)
#define DISPLAY_DC (16)
#define DISPLAY_SCLK (18)
#define DISPLAY_MOSI (19)
#define DISPLAY_BACKLIGHT_EN (20)

#define TEMP_DO (27)


@@ 44,6 44,23 @@
#define TEMPERATURE_WARM (50)
#define TEMPERATURE_HOT (85)

word colour(byte R, byte G, byte B) {
  return ( ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | (B >> 3) );
}

word colour(uint32_t col) {
  return colour((col & 0xFF0000) >> 4, (col & 0xFF00) >> 2, (col & 0xFF));
}

static const word kColorText = ST77XX_WHITE;
static const word kColorBackground = colour(0x1e0010);
static const word kColorSafeTemp = colour(0x131218);
static const word kColorWarningTemp = colour(0xDCC8FF);
static const word kColorDangerTemp = colour(0xC5A3FF);
static const word kColorGraphLines = colour(0xFFB8D1);
static const word kColorIdealGraph = colour(0xBFBFBF);
static const word kColorActualGraph = colour(0xF8F8F2);

using std::string;
using std::ostringstream;



@@ 108,7 125,7 @@ class DrawMessage {
queue_t drawing_queue;

// Drawing
uint16_t text_bg_color = 0x0000;
uint16_t text_bg_color = kColorBackground;

// State machine
enum State {


@@ 127,7 144,7 @@ State next_state = MAIN_MENU;
// Temperature
int current_temp = -1;
int last_temp = -1;
uint16_t current_temp_color = 0x0000;
uint16_t current_temp_color = kColorBackground;

// Calibration
bool is_calibrated = false;


@@ 158,11 175,12 @@ int reflow_duration = 60'000;
int cool_duration = 35'000;

// Reflow meta
int holding_at_temp = 0;
int holding_at_time = 0;
int holding_at_reheat_time = 0;
int desired_temp = 0;
int reflow_rise_time = 0;
bool is_holding = false;
int holding_at_temp = -1;
int holding_at_time = -1;
int holding_at_reheat_time = -1;
int desired_temp = -1;
int reflow_rise_time = -1;
unsigned long reflow_state_start_time = 0;

// Menus


@@ 177,7 195,7 @@ void send_clear() {
  queue_add_blocking(&drawing_queue, &msg);
}

void send_text(string text, int x, int y, Justification j, uint16_t fg=0xFFFF, uint16_t bg=0x0000) {
void send_text(string text, int x, int y, Justification j, uint16_t fg=kColorText, uint16_t bg=kColorBackground) {
  DrawMessage msg{
    DrawMessage::TEXT,
      {


@@ 192,7 210,7 @@ void send_text(string text, int x, int y, Justification j, uint16_t fg=0xFFFF, u
  queue_add_blocking(&drawing_queue, &msg);
}

void send_config(int textSize=1, uint16_t textColor=0xFFFF, const GFXfont *font=NULL) {
void send_config(int textSize=1, uint16_t textColor=kColorText, const GFXfont *font=NULL) {
  DrawMessage msg{
    DrawMessage::CONFIG,
      {


@@ 281,11 299,11 @@ void draw_temperature() {
  int y = 240 - HEADER_FOOTER_SIZE + 2;

  send_config();
  send_text(text, x, y, CENTER, 0xFFFF, current_temp_color);
  send_text(text, x, y, CENTER, kColorText, current_temp_color);
}

void draw_header() {
  uint16_t color_fg = ST77XX_WHITE;
  uint16_t color_fg = kColorText;
  uint16_t color_bg = current_temp_color;
  text_bg_color = color_bg;



@@ 346,7 364,7 @@ void draw_header() {
}

void draw_footer() {
  uint16_t color_fg = ST77XX_WHITE;
  uint16_t color_fg = kColorText;
  uint16_t color_bg = current_temp_color;
  text_bg_color = color_bg;



@@ 402,15 420,15 @@ void set_elements_state(bool on_or_off) {

uint16_t get_temperature_color() {
  if (current_temp == -1 || last_temp == -1) {
    return 0x0000;
    return kColorBackground;
  }
  if (current_temp > TEMPERATURE_HOT) {
    return 0x8082;
    return kColorDangerTemp;
  }
  if (current_temp > TEMPERATURE_WARM) {
    return 0xBDA3;
    return kColorWarningTemp;
  }
  return 0x1423;
  return kColorSafeTemp;
}

void update_temperature() {


@@ 439,14 457,14 @@ void update_temperature() {
void main_menu_setup() {
  set_elements_state(false);

  send_config(1, 0xFFFF, &FreeSerif18pt7b);
  send_config(1, kColorText, &FreeSerif18pt7b);
  send_print("NEON\nGENESIS\nOVENGELION", 0, 50);

  send_config();
  if (is_calibrated) {
    send_text("CALIBRATION OK", 320, 220, RIGHT, 0x0000, 0x0F00);
    send_text("CALIBRATION OK", 320, 220, RIGHT, kColorText, kColorSafeTemp);
  } else {
    send_text("NO CALIBRATION", 320, 220, RIGHT, 0x0000, 0xF000);
    send_text("NO CALIBRATION", 320, 220, RIGHT, kColorText, kColorDangerTemp);
  }

  num_items = 2;


@@ 458,12 476,12 @@ void main_menu_loop() {
  if (last_drawn_selection != selection) {
    int fg, bg;

    if (selection == 0) { fg=0x0000; bg=0xFFFF; }
    else { fg=0xFFFF; bg=0x0000; }
    if (selection == 0) { fg=kColorBackground; bg=kColorText; }
    else { fg=kColorText; bg=kColorBackground; }
    send_text("BAKE", 320 / 2, 165, CENTER, fg, bg);

    if (selection == 1) { fg=0x0000; bg=0xFFFF; }
    else { fg=0xFFFF; bg=0x0000; }
    if (selection == 1) { fg=kColorBackground; bg=kColorText; }
    else { fg=kColorText; bg=kColorBackground; }
    send_text("CALIBRATE", 320 / 2, 195, CENTER, fg, bg);

    last_drawn_selection = selection;


@@ 652,15 670,19 @@ int get_desired_temperature(ReflowState state, unsigned long time_in_state) {
  return (int) (desired_temp + 0.5);
}

void bake_setup() {
  int graph_width = 280;
  int graph_height = 140;
  int graph_x = 20;
  int graph_y = 80;
int graph_x = 20;
int graph_y = 80;
int graph_width = 280;
int graph_height = 140;

double ms_per_pixel = 0;
double degrees_per_pixel = 0;
unsigned long bake_start_time = 0;

void bake_setup() {
  // First draw the axises!
  send_line(graph_x-1,graph_y+graph_height+1,graph_x+graph_width+1,graph_y+graph_height+1,0xF000);
  send_line(graph_x-1,graph_y-1,graph_x-1,graph_y+graph_height+1,0xF000);
  send_line(graph_x-1,graph_y+graph_height+1,graph_x+graph_width+1,graph_y+graph_height+1,kColorGraphLines);
  send_line(graph_x-1,graph_y-1,graph_x-1,graph_y+graph_height+1,kColorGraphLines);

  // Now draw the pretty ideal curve!
  unsigned long total_time =


@@ 668,6 690,10 @@ void bake_setup() {
    soak_duration +
    reflow_duration +
    cool_duration;

  ms_per_pixel = (double) graph_width / (double) total_time;
  degrees_per_pixel = ((float) graph_height / 275);

  for (int x = graph_x; x < graph_x + graph_width; x++) {
    double progress = (x - graph_x) / (float) graph_width;
    unsigned long current_time = total_time * progress;


@@ 689,10 715,12 @@ void bake_setup() {
      }
      desired_temp = get_desired_temperature(state, time_in_state);
    }
    double scaled_temp = ((float) graph_height / 275) * desired_temp;
    double scaled_temp = degrees_per_pixel * desired_temp;
    int y = graph_y + graph_height - scaled_temp;
    send_pixel(x, y, 0xFFFF);
    send_pixel(x, y, kColorIdealGraph);
  }

  bake_start_time = millis();
}

void pick_profile_loop() {


@@ 701,23 729,41 @@ void pick_profile_loop() {

void reflow_loop() {
  unsigned long current_time = millis();

  ostringstream debug_str;
  string text;

  unsigned long time_so_far = current_time - bake_start_time;
  int y = graph_y + graph_height - (degrees_per_pixel * current_temp);
  send_pixel(graph_x + ((double) ms_per_pixel * (double) time_so_far), y, kColorActualGraph);

  switch (reflow_state) {
    case PREHEAT:
      if (current_temp > preheat_temp) {
      debug_str << " PREHEAT ";

      if (current_temp > preheat_temp - calibration_lag_degrees) {
	reflow_state = SOAK;
	reflow_state_start_time = current_time;
        text = debug_str.str();
        send_text(text, 20, 20, LEFT, kColorText, kColorBackground);
	return;
      }
      break;
    case SOAK:
      debug_str << " SOAK ";

      if (current_time - reflow_state_start_time > soak_duration) {
	reflow_state = REFLOW;
	reflow_state_start_time = current_time;
        text = debug_str.str();
        send_text(text, 20, 20, LEFT, kColorText, kColorBackground);
	return;
      }
      break;
    case REFLOW:
      if (reflow_rise_time == 0) {
      debug_str << " REFLOW ";

      if (reflow_rise_time == -1) {
	if (current_temp >= reflow_temp - calibration_lag_degrees) {
	  reflow_rise_time = current_time - reflow_state_start_time;
	}


@@ 740,8 786,11 @@ void reflow_loop() {
      }
      break;
    case COOL:
      debug_str << " COOL ";
      if (current_temp < 150) {
	next_state = FINISHED_BAKE;
        text = debug_str.str();
        send_text(text, 20, 20, LEFT, kColorText, kColorBackground);
	return;
      }
      break;


@@ 749,24 798,28 @@ void reflow_loop() {

  unsigned long time_in_state = current_time - reflow_state_start_time;
  int desired_temp = get_desired_temperature(reflow_state, time_in_state);
  debug_str << " desired: " << desired_temp;

  if (desired_temp - current_temp < calibration_lag_degrees && holding_at_time == -1) {
    // We are within lag_temp of the temperature we should be aiming for.
    // Time to start turning the elements off!
    holding_at_temp = desired_temp;
    is_holding = true;
    holding_at_time = current_time;
  }

  if (holding_at_temp == desired_temp) {
  if (is_holding) {
    debug_str << " HOLDING ";
    // We are currently holding the elements off. But what's the state of
    // things?
    if (current_temp > desired_temp) {
      // We overshot! Keep holding the elements off.
      debug_str << " (overshot) ";
      set_elements_state(false);
    } else if (current_temp < desired_temp - calibration_lag_degrees) {
      debug_str << " (undershot) ";
      // We have held off for too long. This hopefully shouldn't happen,
      // but if it does we immediately stop holding.
      holding_at_temp = -1;
      is_holding = false;
      holding_at_time = -1;
      holding_at_reheat_time = -1;
      set_elements_state(true);


@@ 775,10 828,12 @@ void reflow_loop() {
      // We have been holding the element off for long enough that it
      // should be dropping very soon, or temp is already dropping.
      if (holding_at_reheat_time == -1) {
        debug_str << " (reheat) ";
	// Turn the elements back on for a bit.
	set_elements_state(true);
	holding_at_reheat_time = current_time;
      } else if (current_time - holding_at_reheat_time < calibration_heat_lag_time) {
        debug_str << " (cool) ";
	// We have held them on for long enough. Turn them back off,
	// and begin the cycle again.
	set_elements_state(false);


@@ 788,7 843,14 @@ void reflow_loop() {
    }
    // Otherwise, we are holding the element off and everything looks okay.
    // Stay the course.
    set_elements_state(false);
  } else {
    set_elements_state(true);
  }

  debug_str << "        ";
  text = debug_str.str();
  send_text(text, 20, 20, LEFT, kColorText, kColorBackground);
}

bool read_debounced(int pin) {


@@ 801,7 863,7 @@ void top_left_pushed() {
  switch (current_state) {
    case MAIN_MENU:
      if (selection == 0) {
	next_state = PICK_PROFILE;
	next_state = BAKE;
      }
      if (selection == 1) {
	next_state = CALIBRATE_1;


@@ 858,7 920,7 @@ void change_state(State new_state) {
  send_clear();
  draw_header();
  draw_footer();
  text_bg_color = 0x0000;
  text_bg_color = kColorBackground;

  // Any menu would want to be reset anyway.
  last_drawn_selection = -1;


@@ 870,7 932,7 @@ void change_state(State new_state) {
    case MAIN_MENU:
      main_menu_setup();
      break;
    case PICK_PROFILE:
    case BAKE:
      bake_setup();
      break;
    case CALIBRATE_1:


@@ 962,7 1024,7 @@ void loop() {
    draw_temperature();
  }

  text_bg_color = 0x0000;
  text_bg_color = kColorBackground;

  int delay_ms = 100;
  switch (current_state) {


@@ 981,6 1043,7 @@ void loop() {
    case PICK_PROFILE:
      break;
    case BAKE:
      reflow_loop();
      break;
    case FINISHED_BAKE:
      break;


@@ 996,7 1059,7 @@ void loop() {
}

/** SECOND CORE **/
Adafruit_ST7789 core1_display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, DISPLAY_MOSI, DISPLAY_SCLK);
Adafruit_ST7789 core1_display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, -1);

void core1_draw_text(const TextType& text, const string& actual_text) {
  auto str = actual_text.c_str();


@@ 1019,12 1082,12 @@ void core1_draw_text(const TextType& text, const string& actual_text) {

void setup1() {
  core1_display.init(240, 320);
  core1_display.setSPISpeed(62'500'000);
  //core1_display.setSPISpeed(62'500'000);
  core1_display.setRotation(3);

  core1_display.setFont();
  core1_display.setTextSize(2);
  core1_display.setTextColor(ST77XX_WHITE);
  core1_display.setTextColor(kColorText);

  // Wait for the other core to signal us before starting our loop.
  rp2040.fifo.pop();


@@ 1042,7 1105,7 @@ void loop1() {

  switch (message.type) {
    case DrawMessage::CLEAR:
      core1_display.fillScreen(0x0000);
      core1_display.fillScreen(kColorBackground);
      break;
    case DrawMessage::RECT:
      core1_display.fillRect(