Browse Source

Implemented display control depending on coffee state and some fixes

Philipp Hinz 8 years ago
parent
commit
200e4fa918

+ 1 - 1
CoffeeCode/buildno

@@ -1 +1 @@
-63
+85

+ 10 - 12
CoffeeCode/coffee.cpp

@@ -22,6 +22,7 @@
 #include "logger.h"
 #include "timer.h"
 #include "database.h"
+#include "display.h"
 
 int state;
 int sigValue;
@@ -70,7 +71,7 @@ void *coffeeThread(void *threadid) {
 		changeState(STATE_OFF);
 	}
 
-	logger(V_BREW, "Start Coffee FSM\n");
+	logger(V_BREW, "Starting Coffee FSM\n");
 	//begin FSM
 	while (1) {
 		switch (state) {
@@ -83,7 +84,6 @@ void *coffeeThread(void *threadid) {
 			if (getSigValue() == SigInt0Rls) {
 				if (halProxSensorCovered()) { //Check Waterlevel
 					//turn machine on
-					logger(V_BREW, "Turn machine on\n");
 					halMachineOn();
 					sleep(1);
 					if (halIsHeating()) { //check if System starts to heat when turned on
@@ -108,7 +108,6 @@ void *coffeeThread(void *threadid) {
 			switch (getSigValue()) {
 			case SigInt1RlsLong:
 				//Turn machine off again
-				logger(V_BREW, "Turn machine off\n");
 				halMachineOff();
 				changeState(STATE_OFF);
 				break;
@@ -132,12 +131,10 @@ void *coffeeThread(void *threadid) {
 			switch (getSigValue()) {
 			case SigInt1RlsLong:
 				//Turn machine off again
-				logger(V_BREW, "Turn machine off\n");
 				halMachineOff();
 				changeState(STATE_OFF);
 				break;
 			case SigPressOpn:
-				logger(V_BREW, "Change state: IDLE\n");
 				changeState(STATE_IDLE);
 				break;
 			case SigInt0Psh:
@@ -162,7 +159,6 @@ void *coffeeThread(void *threadid) {
 			switch (getSigValue()) {
 			case SigInt1RlsLong:
 				//Turn machine off again
-				logger(V_BREW, "Turn machine off\n");
 				halMachineOff();
 				changeState(STATE_OFF);
 				break;
@@ -184,7 +180,7 @@ void *coffeeThread(void *threadid) {
 			 */
 		case STATE_BREW:
 			coffeeBrew();
-			logger(V_BREW, "Finish brewing\n");
+			logger(V_BREW, "Finishing brewing\n");
 			changeState(STATE_IDLE);
 			break;
 
@@ -252,8 +248,10 @@ bool SigValueEmpty(void) {
  * @param newState
  */
 void changeState(int newState) {
-	logger(V_BREW, "Change state to %d\n", newState);
+	logger(V_BREW, "Changing state to %d\n", newState);
 	state = newState;
+
+	displayPushState(newState);
 }
 
 /**
@@ -340,8 +338,8 @@ void coffeeBrew(void) {
  *
  */
 void coffeeIncreaseBrewCounter(void) {
-	uint64_t brewcounter = sqlGetConf(SQLbrewcounter);
-	if (sqlSetConf(SQLbrewcounter, ++brewcounter)) {
+	uint64_t brewcounter = sqlGetConf(CFGbrewcounter);
+	if (sqlSetConf(CFGbrewcounter, ++brewcounter)) {
 		logger_error("Couldn't write brewcounter to database");
 	}
 }
@@ -350,8 +348,8 @@ void coffeeIncreaseBrewCounter(void) {
  *
  */
 void coffeeIncreaseHeatingTime(uint64_t heatingTime) {
-	uint64_t totalHeatingTime = sqlGetConf(SQLHeatingTime);
-	if (sqlSetConf(SQLHeatingTime, (totalHeatingTime + heatingTime))) {
+	uint64_t totalHeatingTime = sqlGetConf(CFGHeatingTime);
+	if (sqlSetConf(CFGHeatingTime, (totalHeatingTime + heatingTime))) {
 			logger_error("Couldn't write heating time to database");
 	}
 }

+ 1 - 1
CoffeeCode/coffee.h

@@ -7,7 +7,7 @@
 
 #ifndef COFFEE_H_
 #define COFFEE_H_
-
+#include <csignal>
 
 
 //define status

+ 3 - 2
CoffeeCode/database.h

@@ -19,8 +19,9 @@ using namespace std;
 
 // Config Keys
 typedef enum {
-	SQLbrewcounter = 1,
-	SQLHeatingTime = 2
+	CFGbrewcounter = 1,
+	CFGHeatingTime = 2,
+	CFGdisplaylang = 3
 } config_key_t;
 
 int sqlOpen();

+ 269 - 0
CoffeeCode/display.cpp

@@ -0,0 +1,269 @@
+/*
+ * display.cpp
+ *
+ *  Created on: Sep 26, 2017
+ *      Author: Philipp Hinz
+ */
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "global.h"
+#include "display.h"
+#include "logger.h"
+#include "database.h"
+#include "timer.h"
+#include "lcd.h"
+#include "coffee.h"
+#include "hal.h"
+
+display_lang_t displayLang;
+timer displayTimer(displayTimerHandler);
+int lcd = 0;
+volatile int timerScaler = 0;
+volatile int elapsedCnt = 0;
+int coffeeState = STATE_OFF;
+
+/**
+ * Prints out the current time in a centered position
+ * @param line Target line in display
+ */
+
+void displayPrintTime(int line) {
+	time_t rawtime;
+	struct tm * timeinfo;
+	if (line > DISPLAY_ROWS)
+		line = 0;
+
+	time(&rawtime);
+	timeinfo = localtime(&rawtime);
+	lcdPosition(lcd, 0, line);
+	lcdPrintf(lcd, "    %.2d:%.2d:%.2d    ", timeinfo->tm_hour,
+			timeinfo->tm_min, timeinfo->tm_sec);
+}
+
+/**
+ * Prints out the total volume flow
+ * @param line Target line in display
+ */
+
+void displayPrintFlow(int line) {
+	float flow = halGetFlow();
+	lcdPosition(lcd, 0, line);
+	lcdPrintf(lcd, "%s: %.0f", displayGetString(str_flow), flow);
+}
+
+/**
+ * Prints a string to a specific line, optionally centered.
+ * This function also fills out the remaining row of the display with spaces,
+ * to ensure there is no old data left.
+ * @param line Target line in display
+ * @param *str String to print
+ * @param centered Print centered or not
+ */
+
+void displayPrintLn(int line, const char* str, bool centered) {
+	char buf[DISPLAY_COLS + 1];
+	int len = strlen(str);
+	int i = 0;
+	int spaces = 0;
+	if (len > DISPLAY_COLS)
+		len = DISPLAY_COLS;
+	if (line > DISPLAY_ROWS)
+		line = 0;
+	if (centered) {
+		spaces = (DISPLAY_COLS - len) / 2;
+		if (spaces) {
+			for (i = 0; i < spaces; i++) {
+				buf[i] = ' ';
+			}
+		}
+	}
+	for (i = 0; i < len; i++) {
+		buf[spaces + i] = str[i];
+	}
+	if ((len + spaces) < DISPLAY_COLS) { // fill remaining space
+		for (i = i + spaces; i < DISPLAY_COLS; i++) {
+			buf[i] = ' ';
+		}
+	}
+	lcdPosition(lcd, 0, line);
+	buf[DISPLAY_COLS] = '\0';
+	lcdPrintf(lcd, buf);
+	//logger(V_HAL, "Printed out on display: \"%s\"\n", buf);
+}
+
+/**
+ * Main thread to handle display data
+ * @param *threadid Thread ID
+ */
+
+void* displayThread(void* threadid) {
+	sleep(1); // Wait for other components to initialize
+	int tmp = sqlGetConf(CFGdisplaylang);
+	if (!tmp || tmp >= lang_last)
+		tmp = DEFAULT_LANG;
+	displaySetLang((display_lang_t) tmp);
+	displayTimer.start();
+	while (1) {
+		pause();
+		if (1) {
+			timerScaler--;
+			displayTimer.call();
+		}
+	}
+	pthread_exit(EXIT_SUCCESS);
+}
+
+/**
+ * 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;
+	}
+	int scale5Hz = (timerScaler == (REFRESH_RATE / 5) ? 0 : 1);
+	if (scale1Hz) {
+		switch (coffeeState) {
+		case STATE_OFF:
+		case STATE_HEATING:
+		case STATE_INITALHEATING:
+		case STATE_IDLE:
+		case STATE_CLEANING:
+		case STATE_ERROR:
+			displayRefresh();
+		}
+	}
+	if (scale5Hz) {
+		switch (coffeeState) {
+		case STATE_BREW:
+		case STATE_BREWMANUAL:
+			displayRefresh();
+		}
+	}
+	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)
+		logger_error("Error: unable to init LCD (%d)\n", lcd);
+	lcdClear(lcd);
+	lcdHome(lcd);
+	displayPrintLn(0, (char*) "CoffeePi", true);
+	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);
+}
+
+/**
+ * Handles cleanup before program termination
+ */
+
+void displayTerminate(void) {
+	displayPrintLn(0, "CoffeePi", true);
+	displayPrintLn(1, displayGetString(str_bye), true);
+}
+
+/**
+ * Sets the language of the display text
+ * @param lang New language
+ */
+
+void displaySetLang(display_lang_t lang) {
+	displayLang = lang;
+}
+
+/**
+ * Refreshed the display content and outputs it
+ */
+
+void displayRefresh(void) {
+	switch (coffeeState) { //coffeeGetState()
+	case STATE_IDLE:
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintLn(1, displayGetString(str_ready), true);
+		break;
+
+	case STATE_INITALHEATING:
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintLn(1, displayGetString(str_heating), true);
+		break;
+
+	case STATE_HEATING:
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintLn(1, displayGetString(str_heatingready), true);
+		break;
+
+	case STATE_BREW:
+		if (elapsedCnt <= REFRESH_RATE) {
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintLn(1, displayGetString(str_brewing), true);
+		} else
+			displayPrintFlow(1);
+		break;
+
+	case STATE_BREWMANUAL:
+		displayPrintLn(0, displayGetString(str_brewing), true);
+		displayPrintFlow(1);
+		break;
+
+	case STATE_CLEANING:
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintLn(1, displayGetString(str_cleaning), true);
+		break;
+
+	case STATE_ERROR:
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintLn(1, displayGetString(str_error), true);
+		break;
+
+	case STATE_OFF:
+	default:
+		displayPrintLn(0, "CoffeePi", true);
+		displayPrintTime(1);
+		break;
+	}
+}
+
+/**
+ * Returns the matching translation of a string
+ * @param string Requested string
+ * @return Translated string
+ */
+
+const char* displayGetString(display_strings_t string) {
+	if (displayLang >= lang_last)
+		displayLang = DEFAULT_LANG;
+	return display_strings[string].text[displayLang];
+}
+
+/**
+ * Updates the display state to the matching coffee state
+ * @param state New state
+ */
+
+void displayPushState(int state) {
+	if (state != coffeeState) {
+		coffeeState = state;
+		timerScaler--;
+		displayTimer.call();
+	}
+}

+ 103 - 0
CoffeeCode/display.h

@@ -0,0 +1,103 @@
+/*
+ * display.h
+ *
+ *  Created on: Sep 26, 2017
+ *      Author: Philipp Hinz
+ */
+
+#ifndef DISPLAY_H_
+#define DISPLAY_H_
+#include <string>
+
+typedef enum {
+	lang_de,
+	lang_en,
+	lang_last
+} display_lang_t;
+
+typedef enum {
+	str_heating,
+	str_heatingready,
+	str_ready,
+	str_brewing,
+	str_cleaning,
+	str_error,
+	str_flow,
+	str_bye,
+	str_last
+} display_strings_t;
+
+typedef struct {
+	char const * const text[lang_last];
+} display_string_t;
+
+static const display_string_t display_strings[str_last] =
+{
+		{ // heating
+				{
+						"Heizt auf",
+						"Heating"
+				}
+		},
+		{ // heatingready
+				{
+						"Bereit (Heizt)",
+						"Ready (Heating)"
+				}
+		},
+		{ // ready
+				{
+						"Bereit",
+						"Ready"
+				}
+		},
+		{ // brewing
+				{
+						"Bezug..",
+						"Brewing.."
+				}
+		},
+		{ // cleaning
+				{
+						"Reinigt..",
+						"Cleaning.."
+				}
+		},
+		{ // error
+				{
+						"Fehler",
+						"Error"
+				}
+		},
+		{ // flow
+				{
+						"Menge",
+						"Flow"
+				}
+		},
+		{ // bye
+				{
+						"Auf wiedersehen",
+						"Good bye"
+				}
+		}
+};
+
+#define DEFAULT_LANG 	lang_de /**< Default display language */
+#define REFRESH_RATE	10 /**< Display refresh rate in Hz */
+#define DISPLAY_ROWS	2
+#define DISPLAY_COLS	16
+
+void *displayThread(void *threadid);
+void *displayTimerHandler(void *threadid);
+void displayInit(void);
+void displayTerminate(void);
+void displaySetLang(display_lang_t lang);
+
+void displayPushState(int state);
+
+void displayRefresh(void);
+const char* displayGetString(display_strings_t string);
+
+
+#endif /* DISPLAY_H_ */

+ 0 - 1
CoffeeCode/global.h

@@ -24,7 +24,6 @@
 extern int verbose;
 extern bool optDate, optPower;
 extern pthread_mutex_t mutex;
-extern int lcd;
 extern pthread_t thread[];
 
 

+ 21 - 18
CoffeeCode/hal.cpp

@@ -9,7 +9,6 @@
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
-#include "lcd.h"
 #include "hal.h"
 #include "global.h"
 #include "logger.h"
@@ -23,9 +22,11 @@ bool flagIgnoreRlsInt0;
 bool flagIgnoreRlsInt1;
 timer Int0Timer(&halInt0TimerHandler);
 timer Int1Timer(&halInt1TimerHandler);
+
 /**
  * Initializes HAL
  */
+
 void halInit(void) {
 	if (optPower) {
 		halMachineOn();
@@ -65,7 +66,8 @@ void halInit(void) {
 		logger_error("Unable to setup ISRPressure: %s\n", strerror(errno));
 		return;
 	}
-	if (wiringPiISR(PIN_PROXIMITY_SENSOR, INT_EDGE_BOTH, &halIntProximity) < 0) {
+	if (wiringPiISR(PIN_PROXIMITY_SENSOR, INT_EDGE_BOTH, &halIntProximity)
+			< 0) {
 		logger_error("Unable to setup ISRProximity: %s\n", strerror(errno));
 		return;
 	}
@@ -124,7 +126,7 @@ int halGetRelaisState(int relais) {
  * Interrupt routine for Int0 (Top button)
  */
 void halInt0(void) {
-	logger(V_BASIC, "Int0 triggered\n");
+	logger(V_HAL, "Int0 triggered\n");
 	if (halGetInt0()) {
 		if (flagIgnoreRlsInt0) {
 			flagIgnoreRlsInt0 = false;
@@ -155,18 +157,18 @@ void halInt0TimerHandler(void) {
  * Interrupt routine for Int1 (Bottom button)
  */
 void halInt1(void) {
-	logger(V_BASIC, "Int1 triggered\n");
-		if (halGetInt1()) {
-			if (flagIgnoreRlsInt1) {
-				flagIgnoreRlsInt1 = false;
-			} else {
-				halSendSignal(SigInt1Rls);
-			}
+	logger(V_HAL, "Int1 triggered\n");
+	if (halGetInt1()) {
+		if (flagIgnoreRlsInt1) {
+			flagIgnoreRlsInt1 = false;
 		} else {
-			halSendSignal(SigInt1Psh);
-			Int1Time = 0;
-			Int1Timer.start();
+			halSendSignal(SigInt1Rls);
 		}
+	} else {
+		halSendSignal(SigInt1Psh);
+		Int1Time = 0;
+		Int1Timer.start();
+	}
 }
 
 /*
@@ -188,9 +190,8 @@ void halInt1TimerHandler(void) {
  */
 void halIntFlow(void) {
 	//halRelaisOff(RELAIS_POWER);
-	logger(V_BASIC, "IntFlow triggered #%d total: %.2fml\n", flowcnt, halGetFlow());
-	lcdPosition(lcd, 0, 0);
-	lcdPrintf(lcd, "ml = %.2f   ", halGetFlow());
+	logger(V_HAL, "IntFlow triggered #%d total: %.2fml\n", flowcnt,
+			halGetFlow());
 	if (flowcnt == 99) {
 		halRelaisOff(RELAIS_PUMP);
 	}
@@ -201,7 +202,7 @@ void halIntFlow(void) {
  * Interrupt routine for the pressure control
  */
 void halIntPressure(void) {
-	logger(V_BASIC, "IntPressure Control triggered\n");
+	logger(V_HAL, "IntPressure Control triggered\n");
 	if (halIsHeating()) {
 		halSendSignal(SigPressCls);
 	} else {
@@ -213,7 +214,7 @@ void halIntPressure(void) {
  * Method to handle toggle of the proximity sensor
  */
 void halIntProximity(void) {
-	logger(V_BASIC, "IntProximity triggered\n");
+	logger(V_HAL, "IntProximity triggered\n");
 	if (halProxSensorCovered()) {
 		halSendSignal(SigProxCvrd);
 	} else {
@@ -299,6 +300,7 @@ void halMachineOn(void) {
 	halRelaisOn(RELAIS_HEAT);
 	halRelaisOff(RELAIS_PUMP);
 	halRelaisOn(RELAIS_POWER);
+	logger(V_HAL, "Turning machine on\n");
 }
 
 /**
@@ -308,4 +310,5 @@ void halMachineOff(void) {
 	halRelaisOff(RELAIS_HEAT);
 	halRelaisOff(RELAIS_PUMP);
 	halRelaisOff(RELAIS_POWER);
+	logger(V_HAL, "Turning machine off\n");
 }

+ 6 - 29
CoffeeCode/main.cpp

@@ -15,7 +15,6 @@
 #include <unistd.h>
 #include <iostream>
 #include <csignal>
-#include <time.h>
 #include "global.h"
 #include "timer.h"
 #include "database.h"
@@ -24,12 +23,12 @@
 #include "hal.h"
 #include "stripe.h"
 #include "coffee.h"
+#include "display.h"
 
 const int buildno = (1+(int)(
 #include "buildno"
 		));
 
-int lcd = 0;
 int verbose = 0;
 bool optDate = false;
 bool optPower = false;
@@ -38,8 +37,6 @@ void *mainLoop(void *threadid);
 void terminationHandler(int signum);
 void usr1Handler(int signum);
 void hupHandler(int signum);
-void timeHandler(void);
-timer timeTimer(&timeHandler);
 pthread_t thread[4];
 pthread_mutex_t mutex;
 
@@ -117,12 +114,7 @@ int main(int argc, char *argv[]) {
 
 	logger_reset();
 	initTimers();
-	lcd = lcdInit();
-	if (lcd < 0)
-		logger_error("Error: unable to init LCD (%d)\n", lcd);
-	lcdClear(lcd);
-	lcdHome(lcd);
-	lcdPrintf(lcd, "    CoffeePi   ", buildno);
+	displayInit();
 
 	// http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm
 
@@ -142,6 +134,8 @@ int main(int argc, char *argv[]) {
 			rc = pthread_create(&thread[i], NULL, mainLoop, (void *) i);
 		else if (i == THREAD_STRIPE)
 			rc = pthread_create(&thread[i], NULL, stripeThread, (void *) i);
+		else if (i == THREAD_DISPLAY)
+			rc = pthread_create(&thread[i], NULL, displayThread, (void *) i);
 		else if (i == THREAD_COFFEE)
 			rc = pthread_create(&thread[i], NULL, coffeeThread, (void *) i);
 		if (rc) {
@@ -155,9 +149,6 @@ int main(int argc, char *argv[]) {
 	// free attribute and wait for the other threads
 	pthread_attr_destroy(&attr);
 
-	// Insert main stuff here.
-	timeTimer.setDivider(20);
-	timeTimer.start();
 
 	sleep(2);
 
@@ -179,8 +170,8 @@ int main(int argc, char *argv[]) {
 void terminationHandler(int signum) {
 	logger(V_NONE, "Caught signal %d, exiting gracefully..\n", signum);
 	stopTimers();
-	coffeeTerminate();
-	//displayTerminate();
+	//coffeeTerminate();
+	displayTerminate();
 
 	/*logger(V_NONE, "Saving my state to the database..\n");
 	sqlExecute("begin");
@@ -241,17 +232,3 @@ void *mainLoop(void *threadid) {
 	}
 	pthread_exit(NULL);
 }
-
-/**
- * Temporary timer for displaying the current time
- */
-void timeHandler(void) {
-	time_t rawtime;
-	struct tm * timeinfo;
-
-	time(&rawtime);
-	timeinfo = localtime(&rawtime);
-	lcdPosition(lcd, 0, 1);
-	lcdPrintf(lcd, "    %.2d:%.2d:%.2d    ", timeinfo->tm_hour,
-			timeinfo->tm_min, timeinfo->tm_sec);
-}

+ 2 - 2
CoffeeCode/stripe.cpp

@@ -75,7 +75,7 @@ void *stripeThread(void *threadid) {
 /**
  * Initializes i2c communication to stripe controller
  */
-void stripeInit() {
+void stripeInit(void) {
 	i2cfd = wiringPiI2CSetup(I2C_ADDRESS_STRIPE);
 	if (i2cfd < 0) {
 		logger_error("Could not initialize i2c with device ID 0x%.2x (%s)\n",
@@ -276,7 +276,7 @@ void stripeEffectHeating(int percent) {
 void stripeEffectPulse(stripe_color color) {
 	effectColor = color;
 	stripeSetTransient(TRANS_MEDIUM);
-	stripeTimer.setDivider(40);
+	stripeTimer.setDivider(43);
 	stripeTimer.start();
 }
 

+ 2 - 2
CoffeeCode/stripe.h

@@ -26,7 +26,7 @@
 typedef enum {
 	TRANS_DIRECT = 0,
 	TRANS_FAST = 6,
-	TRANS_MEDIUM = 33,
+	TRANS_MEDIUM = 35,
 	TRANS_SLOW = 200
 } stripe_transient_t;
 
@@ -38,7 +38,7 @@ struct stripe_color {
 
 void *stripeThread(void *threadid);
 void *stripeTimerHandler(void *threadid);
-void stripeInit();
+void stripeInit(void);
 int stripeCommand(int len, char* data);
 void stripeUpdate(void);
 void stripeUpdateDim(void);