Jelajahi Sumber

added functionality to display information during state, mode or page transitions
Now displaying the elapsed time at the end of the brewing
Using the divider of the timer to control the refresh rate of the display

Sebastian Vendt 6 tahun lalu
induk
melakukan
8303e6db0d
6 mengubah file dengan 220 tambahan dan 109 penghapusan
  1. 10 1
      CoffeeCode/coffee.cpp
  2. 7 3
      CoffeeCode/coffee.h
  3. 180 81
      CoffeeCode/display2.cpp
  4. 12 22
      CoffeeCode/display2.h
  5. 10 2
      CoffeeCode/hal.cpp
  6. 1 0
      CoffeeCode/hal.h

+ 10 - 1
CoffeeCode/coffee.cpp

@@ -28,7 +28,8 @@ coffee_menuPage_t page;
 coffee_mode_t mode;
 
 int sigValue;
-int brewTime; //Brew time in ms
+uint16_t brewTime; //Brew time in ms
+uint16_t lastBrewTime;
 timer brewTimer(&brewTimeHandler);
 
 uint64_t totalHeatingTime; //local copies of the corresponding database entries
@@ -659,6 +660,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
  */
@@ -836,6 +844,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[];
@@ -61,6 +64,7 @@ void changeMode(coffee_mode_t newMode);
 void changePage(coffee_menuPage_t newPage);
 void leaveMenu(void);
 coffee_status_t getState(void);
+uint16_t getLastBrewTime(void);
 int getSigValue(coffee_mode_t mode);
 uint16_t getBrewCounter(void);
 uint64_t getTotalHeatingTime(void);

+ 180 - 81
CoffeeCode/display2.cpp

@@ -22,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
@@ -58,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;
 
@@ -94,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
@@ -166,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();
 }
 
 /**
@@ -186,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
  */
 
@@ -206,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();
 }
 
 /**
@@ -230,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:
@@ -246,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);
@@ -257,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();
 		}
 	}
@@ -275,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);
+
+	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
+ */
 
-	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();
+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)
@@ -331,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
@@ -362,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);
@@ -385,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:
@@ -420,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);

+ 12 - 22
CoffeeCode/display2.h

@@ -10,13 +10,15 @@
 #include <string>
 #include "coffee.h"
 
-#define DEFAULT_LANG 	lang_en /**< Default display language */
-#define REFRESH_RATE	5 /**< Display refresh rate in Hz when active */
+#define DEFAULT_LANG 	lang_en // Default display language
+
+
+#define REFRESH_FAST	5
+#define REFRESH_STD		2
+
 #define DISPLAY_ROWS	2
 #define DISPLAY_COLS	16
 
-#define MAX_PAGENAME	20
-
 void *displayThread(void *threadid);
 void *displayTimerHandler(void *threadid);
 void displayInit(void);
@@ -27,6 +29,12 @@ 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,
@@ -56,24 +64,6 @@ typedef enum {
 	str_last
 } display_strings_t;
 
-typedef struct {
-	const char * const pagename[MAX_PAGENAME];
-	void (*ContentFunction)(void);
-	uint16_t refreshrate;
-	uint16_t timeToDisplay;
-	uint16_t displayTime;
-}display2_page_t;
-
-static const display2_page_t pages[] =
-{
-		{
-				{"demopage"},
-				displayInit,
-				10,
-				19,
-				10
-		}
-};
 
 typedef struct {
 	char const * const text[lang_last];

+ 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;
@@ -43,6 +43,7 @@ time_t heatingCycle[] = {0, 0};
 timespec flowTimestep[] = {{0,0},{0,0}};
 uint8_t flowIndex = 0;
 
+
 timespec pumpCycle[] = {{0,0},{0,0}};
 
 //delay of the debounce in milliseconds
@@ -335,17 +336,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

@@ -71,6 +71,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);