Explorar o código

Merge branch 'display2'

Sebastian Vendt %!s(int64=6) %!d(string=hai) anos
pai
achega
6ea2a5d520
Modificáronse 7 ficheiros con 240 adicións e 106 borrados
  1. 10 1
      CoffeeCode/coffee.cpp
  2. 7 3
      CoffeeCode/coffee.h
  3. 182 82
      CoffeeCode/display2.cpp
  4. 29 17
      CoffeeCode/display2.h
  5. 10 2
      CoffeeCode/hal.cpp
  6. 1 0
      CoffeeCode/hal.h
  7. 1 1
      CoffeeCode/main.cpp

+ 10 - 1
CoffeeCode/coffee.cpp

@@ -28,8 +28,9 @@ coffee_menuPage_t page;
 coffee_mode_t mode;
 
 int sigValue;
-int brewTime; //Brew time in ms
 int menuTimeout;
+uint16_t brewTime; //Brew time in ms
+uint16_t lastBrewTime;
 timer brewTimer(&brewTimeHandler);
 timer menuTimer(&menuTimeHandler);
 
@@ -736,6 +737,13 @@ coffee_status_t getState(void) {
 	return state;
 }
 
+/**
+ * Returns the last elapsed brew time in ms
+ */
+uint16_t getLastBrewTime(void) {
+	return lastBrewTime;
+}
+
 /**
  * Returns the local up-to-date brewcounter
  */
@@ -927,6 +935,7 @@ void coffeeBrew(void) {
 void stopBrewing() {
 	halPumpOff();
 	brewTimer.stop();
+	lastBrewTime = brewTime;
 	brewTime = 0;
 	halResetFlow();
 }

+ 7 - 3
CoffeeCode/coffee.h

@@ -22,12 +22,14 @@ typedef enum {
 	STATE_CLEANING,
 	STATE_ERROR,
 	STATE_WAIT_OFF,
-	STATE_FULLTANK
+	STATE_FULLTANK,
+	STATE_NULL
 } coffee_status_t;
 
 typedef enum {
 	MODE_STATE,
-	MODE_MENU
+	MODE_MENU,
+	MODE_NULL
 } coffee_mode_t;
 
 typedef enum {
@@ -39,7 +41,8 @@ typedef enum {
 	PAGE_TEMP,
 	PAGE_CLEAN,
 	PAGE_DEMO,
-	PAGE_EXIT
+	PAGE_EXIT,
+	PAGE_NULL
 } coffee_menuPage_t;
 
 extern const char* StateName[];
@@ -63,6 +66,7 @@ void changePage(coffee_menuPage_t newPage);
 void leaveMenu(void);
 void enterMenu(void);
 coffee_status_t getState(void);
+uint16_t getLastBrewTime(void);
 int getSigValue(coffee_mode_t mode);
 uint16_t getBrewCounter(void);
 uint64_t getTotalHeatingTime(void);

+ 182 - 82
CoffeeCode/display.cpp → CoffeeCode/display2.cpp

@@ -10,8 +10,9 @@
 #include <unistd.h>
 #include <string.h>
 
+#include "display2.h"
+
 #include "global.h"
-#include "display.h"
 #include "logger.h"
 #include "database.h"
 #include "timer.h"
@@ -21,15 +22,39 @@
 #include "events.h"
 #include "DS18B20.h"
 
+#define CURRENT	0
+#define NEXT	1
+
+//timeouts for the transitions in ms
+#define TIMEOUT_PREBREW		1000
+#define TIMEOUT_POSTBREW	4000
+
 display_lang_t displayLang;
 timer displayTimer(displayTimerHandler);
 int lcd = 0;
-volatile int timerScaler = 0;
-volatile int elapsedCnt = 0;
-coffee_status_t coffeeState = STATE_OFF;
-coffee_mode_t coffeeMode = MODE_STATE;
-coffee_menuPage_t coffeePage = PAGE_SOFTOFF;
+// currently only the history of states is of interest
+coffee_status_t coffeeState[] = {STATE_OFF, STATE_NULL}; // current - next state
+coffee_mode_t coffeeMode[] = {MODE_STATE, MODE_NULL};
+coffee_menuPage_t coffeePage[] = {PAGE_SOFTOFF, PAGE_NULL};
 bool coffeeDescaling = false;
+refreshRate_t currentRefreshRate = refresh_std;
+uint16_t holdNext[3] = {0, 0, 0}; 	//holdtime of the new {state, Mode, Page} in ms
+uint16_t nextWaitTime[3] = {0, 0, 0}; //actual waiting time of the new {state, Mode, Page}
+
+
+typedef enum {
+	state_idx = 0,
+	mode_idx = 1,
+	page_idx = 2
+} idx_t;
+
+void track(idx_t idx);
+void switchToNextPage(coffee_menuPage_t* history);
+void switchToNextMode(coffee_mode_t* history);
+void switchToNextState(coffee_status_t* history);
+void setRefreshRate(refreshRate_t rate);
+void setSwitchToNextTimeout(idx_t idx, uint16_t millis);
+
 
 /**
  * Prints out the current time in a centered position
@@ -57,6 +82,8 @@ void displayPrintTemp(int line) {
 	//after the first refresh the right temperature is displayed
 	//no idea where this comes from, datasheet says nothing about dummy readouts.
 	//no old values are used, conversion is started before every readout...
+	//Quick fix:
+	DS18B20_readTemp();
 	if (line > DISPLAY_ROWS)
 		line = 0;
 
@@ -93,13 +120,25 @@ void displayPrintStats2(int line) {
  */
 void displayPrintNextDesc(int line) {
 	char buffer[17];
-	if (line > DISPLAY_ROWS)
-		line = 0;
+	if (line > DISPLAY_ROWS) line = 0;
 
 	sprintf(buffer, "%d d or %d C", checkDirtyTime(), checkDirtyEspresso());
 	displayPrintLn(line, buffer, true);
 }
 
+/**
+ *
+ */
+void displayPrintPostBrew(int line){
+	char buffer[17];
+	if (line > DISPLAY_ROWS) line = 0;
+
+	float brewTime = (float)getLastBrewTime();
+
+	sprintf(buffer, "%.1f ml / %.1f s", halGetLastFlow(), brewTime / 1000);
+	displayPrintLn(line, buffer, true);
+}
+
 /**
  * Prints out the total volume flow
  * @param line Target line in display
@@ -165,13 +204,8 @@ void displayStateUpdated(event_t *event) {
 		return;
 	}
 	coffee_status_t state = *(coffee_status_t*) event->data;
-	if (state != coffeeState) {
-		coffeeState = state;
-		if (timerScaler)
-			timerScaler--;
-		elapsedCnt = 0;
-		displayTimer.call();
-	}
+	coffeeState[NEXT] = state;
+	displayTimer.call();
 }
 
 /**
@@ -185,17 +219,16 @@ void displayModeUpdated(event_t *event) {
 		return;
 	}
 	coffee_mode_t mode = *(coffee_mode_t*) event->data;
-	if (mode != coffeeMode) {
-		coffeeMode = mode;
-		if (timerScaler)
-			timerScaler--;
-		elapsedCnt = 0;
-		displayTimer.call();
-	}
+	coffeeMode[NEXT] = mode;
+	displayTimer.call();
 }
 
 /**
  * Updates the display state to the matching coffee display page
+ * The new state is put on hold (next) and the display can decided if it immediately makes the
+ * new state to the current one or if a timeout is specified in which the new state is put on hold and the
+ * state transition is processed.
+ * One initial asynchronous call
  * @param event Event data
  */
 
@@ -205,12 +238,8 @@ void displayPageUpdated(event_t *event) {
 		return;
 	}
 	coffee_menuPage_t page = *(coffee_menuPage_t*) event->data;
-	if (page != coffeePage) {
-		coffeePage = page;
-		timerScaler = REFRESH_RATE;
-		elapsedCnt = 0;
-		displayTimer.call();
-	}
+	coffeePage[NEXT] = page;
+	displayTimer.call();
 }
 
 /**
@@ -229,7 +258,7 @@ void displayDescaling(event_t *event) {
  */
 void displayPrintLogo(void) {
 	char buffer[17];
-	switch (coffeeState) {
+	switch (coffeeState[CURRENT]) {
 		case STATE_HEATING:
 		case STATE_INITALHEATING:
 		case STATE_IDLE:
@@ -245,7 +274,6 @@ void displayPrintLogo(void) {
 /**
  * Handles cleanup before program termination
  */
-
 void displayTerminate(event_t *e) {
 	logger(V_BASIC, "display.cpp: Terminating\n");
 	displayPrintLn(0, "CoffeePi", true);
@@ -256,14 +284,12 @@ void displayTerminate(event_t *e) {
  * Main thread to handle display data
  * @param *threadid Thread ID
  */
-
 void* displayThread(void* threadid) {
 	//sleep(1); // Wait for other components to initialize
 	displayTimer.start();
 	while (1) {
 		pause();
 		if (1) {
-			timerScaler = REFRESH_RATE;
 			displayTimer.call();
 		}
 	}
@@ -274,52 +300,42 @@ void* displayThread(void* threadid) {
  * Timer handler for display update
  * @param *threadid Thread ID
  */
-
 void* displayTimerHandler(void* threadid) {
-	int scale1Hz = 0;
-	if (timerScaler++ >= REFRESH_RATE) { // 1s elapsed, reset
-		timerScaler = 0;
-		scale1Hz = 1;
-	}
+	//track time of the new state in hold and switch if necessary
+	track(state_idx);
+	track(page_idx);
+	track(mode_idx);
 
-	if (scale1Hz) {
-		if (coffeeMode == MODE_STATE) {
-			switch (coffeeState) {
-			case STATE_OFF:
-			case STATE_HEATING:
-			case STATE_INITALHEATING:
-			case STATE_IDLE:
-			case STATE_CLEANING:
-			case STATE_ERROR:
-			case STATE_WAIT_OFF:
-				displayRefresh();
+	displayRefresh();
+	pthread_exit(EXIT_SUCCESS);
+}
+
+/**
+ * Tracks the elapsed time in ms of the new state waiting to become the current one if a hold time is specified
+ */
+
+void track(idx_t idx){
+	if (holdNext[idx] != 0) {
+		nextWaitTime[idx] += 1000 / currentRefreshRate;
+		if (holdNext[idx] <= nextWaitTime[idx]) {
+			switch(idx){
+			case state_idx:
+				switchToNextState(coffeeState);
+				break;
+			case page_idx:
+				switchToNextPage(coffeePage);
 				break;
-			default:
+			case mode_idx:
+				switchToNextMode(coffeeMode);
 				break;
 			}
-		} else if (coffeeMode == MODE_MENU) {
-			displayRefresh();
 		}
 	}
-
-	switch (coffeeState) {
-	case STATE_BREW:
-	case STATE_BREWMANUAL:
-		displayRefresh();
-		break;
-	default:
-		break;
-	}
-
-	if (elapsedCnt < (5 * REFRESH_RATE)) // Don't let it grow too large
-		elapsedCnt++;
-	pthread_exit(EXIT_SUCCESS);
 }
 
 /**
  * Initializes display
  */
-
 void displayInit(void) {
 	lcd = lcdInit();
 	if (lcd < 0)
@@ -330,11 +346,11 @@ void displayInit(void) {
 	displayPrintLn(1, (char*) "booting...", true);
 	//lcdPrintf(lcd, "    CoffeePi       booting...");
 
-	timerScaler = 0;
-	displayTimer.setDivider((1000000 / TIMER_DELAY_US) / REFRESH_RATE);
 
-	logger(V_BASIC, "Initialized display with a refresh rate of %d Hz\n",
-	REFRESH_RATE);
+	setRefreshRate(refresh_std);
+
+	logger(V_BASIC, "display2.cpp Initialized display with a refresh rate of %d Hz\n",
+			refresh_std);
 	/**The following block comes from void* displayThread(void* threadid)
 	 * The idea is that the initialization functions get the component ready to react on external events
 	 * once the threads start, events might be triggered and every component can process them
@@ -361,13 +377,92 @@ void displaySetLang(display_lang_t lang) {
 	displayLang = lang;
 }
 
+/*
+ *
+ */
+void switchToNextPage(coffee_menuPage_t* history){
+	if(history[NEXT] != PAGE_NULL) {
+		history[CURRENT] = history[NEXT];
+		history[NEXT] = PAGE_NULL;
+
+		holdNext[page_idx] = 0;
+		nextWaitTime[page_idx] = 0;
+	}
+}
+
+/*
+ *
+ */
+void switchToNextMode(coffee_mode_t* history){
+	if(history[NEXT] != MODE_NULL) {
+		history[CURRENT] = history[NEXT];
+		history[NEXT] = MODE_NULL;
+
+		holdNext[mode_idx] = 0;
+		nextWaitTime[mode_idx] = 0;
+	}
+}
+
+/*
+ *
+ */
+void switchToNextState(coffee_status_t* history){
+	if(history[NEXT] != STATE_NULL) {
+		history[CURRENT] = history[NEXT];
+		history[NEXT] = STATE_NULL;
+
+		holdNext[state_idx] = 0;
+		nextWaitTime[state_idx] = 0;
+	}
+}
+
+/**
+ * sets the refresh rate of the the display
+ * to one of the predefined refresh rates.
+ */
+void setRefreshRate(refreshRate_t rate) {
+	currentRefreshRate = rate;
+	displayTimer.setDivider(20 / rate);
+}
+
+/**
+ * specifies a timeout at which the new state will be made to the current one
+ * This function is necessary for the special state transitions which hold the new state while they
+ * process the current transition. These cases set a timeout specifying how long the state transition should be paused.
+ * After the time specified in the timeout the timerhandler of the display will switch the states and makes the new one to the current one.
+ */
+void setSwitchToNextTimeout(idx_t idx, uint16_t millis) {
+	holdNext[idx] = millis;
+}
+
 /**
- * Refreshed the display content and outputs it
+ * The core description of what will be displayed in what displaystate
  */
 
 void displayRefresh(void) {
-	if (coffeeMode == MODE_STATE) {
-		switch (coffeeState) { //coffeeGetState()
+	//handle mode trainsitions
+	switchToNextMode(coffeeMode);
+
+	//FSM of the display
+	if (coffeeMode[CURRENT] == MODE_STATE) {
+		//handle state transitions
+		if (coffeeState[NEXT] == STATE_BREW) { //Pre brew
+			//check how long the new state is already in hold ... and either switch or process transition
+			setSwitchToNextTimeout(state_idx, TIMEOUT_PREBREW);
+			setRefreshRate(refresh_fast);
+			displayPrintLogo();
+			displayPrintLn(1, displayGetString(str_brewing), true);
+			return;
+		} else if (coffeeState[CURRENT] == STATE_BREW && coffeeState[NEXT] != STATE_NULL) { //Post brew
+			setSwitchToNextTimeout(state_idx, TIMEOUT_POSTBREW);
+			setRefreshRate(refresh_std);
+			displayPrintPostBrew(1);
+			return;
+		} else { //no special state transition -> make new state to the current one
+			switchToNextState(coffeeState);
+		}
+
+		switch (coffeeState[CURRENT]) { //coffeeGetState()
 		case STATE_IDLE:
 			displayPrintLogo();
 			displayPrintLn(1, displayGetString(str_ready), true);
@@ -384,13 +479,8 @@ void displayRefresh(void) {
 			break;
 
 		case STATE_BREW:
-			if (elapsedCnt <= 2 * REFRESH_RATE) {
-				displayPrintLogo();
-				displayPrintLn(1, displayGetString(str_brewing), true);
-			} else {
-				displayPrintLn(0, displayGetString(str_brewing), true);
-				displayPrintFlow(1);
-			}
+			displayPrintLn(0, displayGetString(str_brewing), true);
+			displayPrintFlow(1);
 			break;
 
 		case STATE_BREWMANUAL:
@@ -419,8 +509,18 @@ void displayRefresh(void) {
 			displayPrintTime(1);
 			break;
 		}
-	} else if (coffeeMode == MODE_MENU) {
-		switch (coffeePage) {
+	} else if (coffeeMode[CURRENT] == MODE_MENU) {
+		//handle page transitions
+		if(coffeePage[NEXT] == PAGE_EXIT) {
+			setSwitchToNextTimeout(page_idx, 2000);
+			displayPrintLn(0, "test vor exit", true);
+			displayPrintLn(1, "Test", true);
+			return;
+		} else {
+			switchToNextPage(coffeePage);
+		}
+
+		switch (coffeePage[CURRENT]) {
 		case PAGE_SOFTOFF:
 			displayPrintLn(0, displayGetString(str_menu), true);
 			displayPrintLn(1, displayGetString(str_menu_softoff), true);

+ 29 - 17
CoffeeCode/display.h → CoffeeCode/display2.h

@@ -5,11 +5,36 @@
  *      Author: Philipp Hinz
  */
 
-#ifndef DISPLAY_H_
-#define DISPLAY_H_
+#ifndef DISPLAY2_H_
+#define DISPLAY2_H_
 #include <string>
 #include "coffee.h"
 
+#define DEFAULT_LANG 	lang_en // Default display language
+
+
+#define REFRESH_FAST	5
+#define REFRESH_STD		2
+
+#define DISPLAY_ROWS	2
+#define DISPLAY_COLS	16
+
+void *displayThread(void *threadid);
+void *displayTimerHandler(void *threadid);
+void displayInit(void);
+void displayPrintLn(int line, const char* str, bool centered);
+
+void displayPushState(coffee_status_t state);
+
+void displayRefresh(void);
+
+
+//(DO NOT change the following values unless you know what you do -> Integer division)
+typedef enum {
+	refresh_fast = 5, 	// Display refresh rate in Hz when active
+	refresh_std = 2 	// Display refresh rate in Hz when not active
+} refreshRate_t;
+
 typedef enum {
 	lang_de,
 	lang_en,
@@ -39,6 +64,7 @@ typedef enum {
 	str_last
 } display_strings_t;
 
+
 typedef struct {
 	char const * const text[lang_last];
 } display_string_t;
@@ -160,21 +186,7 @@ static const display_string_t display_strings[str_last] =
 		}
 };
 
-#define DEFAULT_LANG 	lang_en /**< Default display language */
-#define REFRESH_RATE	5 /**< Display refresh rate in Hz when active */
-#define DISPLAY_ROWS	2
-#define DISPLAY_COLS	16
-
-void *displayThread(void *threadid);
-void *displayTimerHandler(void *threadid);
-void displayInit(void);
-void displaySetLang(display_lang_t lang);
-void displayPrintLn(int line, const char* str, bool centered);
-
-void displayPushState(coffee_status_t state);
-
-void displayRefresh(void);
 const char* displayGetString(display_strings_t string);
-
+void displaySetLang(display_lang_t lang);
 
 #endif /* DISPLAY_H_ */

+ 10 - 2
CoffeeCode/hal.cpp

@@ -23,7 +23,7 @@
 typedef struct timespec timespec;
 
 volatile int flowcnt = 0;
-
+int lastFlowcnt = 0;
 
 int Int0Time, Int1Time;
 int idleCounter;
@@ -51,6 +51,7 @@ timespec flowTimestep[] = {{0,0},{0,0}};
 uint8_t flowIndex = 0;
 int16_t tickCounter = 0;
 
+
 timespec pumpCycle[] = {{0,0},{0,0}};
 
 //delay of the debounce in milliseconds
@@ -405,17 +406,24 @@ void halIntProximity(void) {
 }
 
 /**
- * Returns total flow trough sensor in ml
+ * Returns total flow through sensor in ml
  */
 float halGetFlow(void) {
 	return flowcnt * FLOW_ML_PULSE;
 }
 
+/*
+ * Returns the last total flow through the sensor in ml after reset
+ */
+float halGetLastFlow(void) {
+	return lastFlowcnt * FLOW_ML_PULSE;
+}
 /**
  * Resets the Flow counter
  */
 void halResetFlow(void) {
 	logger(V_HAL, "Flow counter reset, amount so far: %.2f ml\n", halGetFlow());
+	lastFlowcnt = flowcnt;
 	flowcnt = 0;
 }
 

+ 1 - 0
CoffeeCode/hal.h

@@ -85,6 +85,7 @@ void halIntPressure(void);
 double halgetHeatingTime(void);
 void halIntProximity(void);
 float halGetFlow(void);
+float halGetLastFlow(void);
 void halResetFlow(void);
 bool halIsHeating(void);
 bool halProxSensorCovered(void);

+ 1 - 1
CoffeeCode/main.cpp

@@ -23,7 +23,7 @@
 #include "hal.h"
 #include "stripe.h"
 #include "coffee.h"
-#include "display.h"
+#include "display2.h"
 #include "server.h"
 #include "events.h"
 #include "DS18B20.h"