Prechádzať zdrojové kódy

Implemented the detection of long pressed buttons
Swopped INT0 with INT1 so the top button is INT0
Put the brewing process in extra method
Added condition to pause commands in Coffee FSM to avoid ignoring
signals
Started to track the brewed coffees and the heating time with sql

pek72 8 rokov pred
rodič
commit
74caa30d39
6 zmenil súbory, kde vykonal 314 pridanie a 106 odobranie
  1. 1 1
      CoffeeCode/buildno
  2. 175 55
      CoffeeCode/coffee.cpp
  3. 8 4
      CoffeeCode/coffee.h
  4. 2 2
      CoffeeCode/database.h
  5. 100 33
      CoffeeCode/hal.cpp
  6. 28 11
      CoffeeCode/hal.h

+ 1 - 1
CoffeeCode/buildno

@@ -1 +1 @@
-61
+63

+ 175 - 55
CoffeeCode/coffee.cpp

@@ -16,17 +16,20 @@
 #include <iostream>
 #include <csignal>
 #include <time.h>
+#include <ctime>
 #include "coffee.h"
 #include "hal.h"
 #include "logger.h"
 #include "timer.h"
-
+#include "database.h"
 
 int state;
 int sigValue;
 int brewTime; //Brew time in ms
 timer brewTimer(&brewTimeHandler);
-
+clock_t beginHeating;
+clock_t endHeating;
+double heatingTime;
 /**
  * Thread for the finite state machine
  * It represents the current state of the machine and handles signals coming from
@@ -47,8 +50,9 @@ void *coffeeThread(void *threadid) {
 	brewTimer.setDivider(4);
 	brewTimer.stop();
 	brewTime = 0;
+	heatingTime = 0;
+	beginHeating = endHeating = clock();
 
-	state = STATE_OFF;
 	logger(V_BREW, "Determining inital state\n");
 	//determine inital state
 	if (halGetRelaisState(RELAIS_POWER) && halGetRelaisState(RELAIS_HEAT) && !halGetRelaisState(RELAIS_PUMP)) {
@@ -62,21 +66,25 @@ void *coffeeThread(void *threadid) {
 	} else if (halGetRelaisState(RELAIS_PUMP)) {
 		logger_error("Whoops, why is the pump running...\n");
 		changeState(STATE_ERROR);
+	} else {
+		changeState(STATE_OFF);
 	}
 
 	logger(V_BREW, "Start Coffee FSM\n");
 	//begin FSM
-	while(1){
-		switch(state){
+	while (1) {
+		switch (state) {
+		/*
+		 *
+		 */
 		case STATE_OFF:
-			pause();
+			if (SigValueEmpty())
+				pause();
 			if (getSigValue() == SigInt0Rls) {
 				if (halProxSensorCovered()) { //Check Waterlevel
 					//turn machine on
 					logger(V_BREW, "Turn machine on\n");
-					halRelaisOn(RELAIS_HEAT);
-					halRelaisOff(RELAIS_PUMP);
-					halRelaisOn(RELAIS_POWER);
+					halMachineOn();
 					sleep(1);
 					if (halIsHeating()) { //check if System starts to heat when turned on
 						changeState(STATE_INITALHEATING);
@@ -89,15 +97,19 @@ void *coffeeThread(void *threadid) {
 				break;
 			}
 			break;
+
+			/*
+			 *
+			 */
 		case STATE_INITALHEATING:
-			pause();
+			beginHeating = clock();
+			if (SigValueEmpty())
+				pause();
 			switch (getSigValue()) {
-			case SigInt1Rls:
+			case SigInt1RlsLong:
 				//Turn machine off again
 				logger(V_BREW, "Turn machine off\n");
-				halRelaisOff(RELAIS_HEAT);
-				halRelaisOff(RELAIS_PUMP);
-				halRelaisOff(RELAIS_POWER);
+				halMachineOff();
 				changeState(STATE_OFF);
 				break;
 			case SigPressOpn:
@@ -105,16 +117,23 @@ void *coffeeThread(void *threadid) {
 				changeState(STATE_IDLE);
 				break;
 			}
+			endHeating = clock();
+			heatingTime = double(endHeating - beginHeating) / CLOCKS_PER_SEC;
+			coffeeIncreaseHeatingTime((uint64_t)heatingTime);
 			break;
+
+			/*
+			 *
+			 */
 		case STATE_HEATING:
-			pause();
-			switch(getSigValue()){
-			case SigInt1Rls:
+			beginHeating = clock();
+			if (SigValueEmpty())
+				pause();
+			switch (getSigValue()) {
+			case SigInt1RlsLong:
 				//Turn machine off again
 				logger(V_BREW, "Turn machine off\n");
-				halRelaisOff(RELAIS_HEAT);
-				halRelaisOff(RELAIS_PUMP);
-				halRelaisOff(RELAIS_POWER);
+				halMachineOff();
 				changeState(STATE_OFF);
 				break;
 			case SigPressOpn:
@@ -130,16 +149,21 @@ void *coffeeThread(void *threadid) {
 				changeState(STATE_BREWMANUAL);
 				break;
 			}
+			endHeating = clock();
+			heatingTime = double(endHeating - beginHeating) / CLOCKS_PER_SEC;
+			coffeeIncreaseHeatingTime((uint64_t)heatingTime);
 			break;
+			/*
+			 *
+			 */
 		case STATE_IDLE:
-			pause();
-			switch(getSigValue()){
-			case SigInt1Rls:
+			if (SigValueEmpty())
+				pause();
+			switch (getSigValue()) {
+			case SigInt1RlsLong:
 				//Turn machine off again
 				logger(V_BREW, "Turn machine off\n");
-				halRelaisOff(RELAIS_HEAT);
-				halRelaisOff(RELAIS_PUMP);
-				halRelaisOff(RELAIS_POWER);
+				halMachineOff();
 				changeState(STATE_OFF);
 				break;
 			case SigPressCls:
@@ -155,40 +179,37 @@ void *coffeeThread(void *threadid) {
 				break;
 			}
 			break;
+			/*
+			 *
+			 */
 		case STATE_BREW:
-			//Preinfusion
-			logger(V_BREW, "Starting preinfusion...\n");
-			halRelaisOn(RELAIS_PUMP);
-			brewTime = 0;
-			brewTimer.start();
-			while(brewTime < TIME_PREINFUSION){
-				usleep(100000);
-			}
-			brewTimer.stop();
-			brewTime = 0;
-			halRelaisOff(RELAIS_PUMP);
-			sleep(TIME_SOAK/1000);
-			logger(V_BREW, "Starting infusion...\n");
-			halResetFlow();
-			halRelaisOn(RELAIS_PUMP);
-			brewTimer.start();
-			while(brewTime < TIME_INFUSION && halGetFlow() < TIME_DBLESPRESSO){
-				usleep(100000);
-			}
-			halRelaisOff(RELAIS_PUMP);
-			brewTimer.stop();
-			brewTime = 0;
+			coffeeBrew();
 			logger(V_BREW, "Finish brewing\n");
 			changeState(STATE_IDLE);
 			break;
+
+			/*
+			 *
+			 */
 		case STATE_BREWMANUAL:
-			pause();
+			if (SigValueEmpty())
+				pause();
 			break;
+
+			/*
+			 *
+			 */
 		case STATE_CLEANING:
-			pause();
+			if (SigValueEmpty())
+				pause();
 			break;
+
+			/*
+			 *
+			 */
 		case STATE_ERROR:
-			pause();
+			if (SigValueEmpty())
+				pause();
 			break;
 		}
 	}
@@ -196,7 +217,8 @@ void *coffeeThread(void *threadid) {
 }
 /**
  * Handler for the Signal send to this thread
- * It safes a value sent with the signal in sigValue
+ * It saves the type of signal received and tracks the time between a push and release event of up to 4 signals
+ * The time is stored in the HalEvent variable when a release event is received
  * @param signum
  * @param siginfo
  * @param context
@@ -211,27 +233,125 @@ void coffeeHandler(int signum, siginfo_t *siginfo, void *context) {
  * returns the Signal value from the last received Signal and clears the variable
  * @return value sent with the last signal
  */
-int getSigValue(void){
+int getSigValue(void) {
 	int tmp = sigValue;
 	sigValue = 0;
 	return tmp;
 }
 
+bool SigValueEmpty(void) {
+	if (sigValue == 0)
+		return true;
+	else
+		return false;
+}
+
 /**
  * Changes the state of the machine to newState
  * prints the change to the logger
  * @param newState
  */
-void changeState(int newState){
+void changeState(int newState) {
 	logger(V_BREW, "Change state to %d\n", newState);
 	state = newState;
 }
 
+/**
+ * Returns the current state of the FSM
+ */
+int getState(void) {
+	return state;
+}
 
 /**
  * Counter for the brew time
  * refresh every 200ms
  */
-void brewTimeHandler (void){
+void brewTimeHandler(void) {
 	brewTime += 200;
 }
+
+/**
+ * handles program termination
+ */
+void coffeeTerminate(void) {
+	logger_error("Coffee thread terminated");
+	//stop brewing
+	halRelaisOff(RELAIS_PUMP);
+	brewTimer.stop();
+}
+
+/**
+ * Brewing process
+ */
+void coffeeBrew(void) {
+	coffeeIncreaseBrewCounter();
+
+	/*
+	 * Preinfusion
+	 */
+	logger(V_BREW, "Starting preinfusion...\n");
+	halResetFlow();
+	halRelaisOn(RELAIS_PUMP);
+	brewTime = 0;
+	brewTimer.start();
+	while (halGetFlow() < AMOUNT_PREINFUSION) {
+		usleep(100000);
+		if (getState() == SigInt1Psh)
+			return;
+	}
+	brewTimer.stop();
+	brewTime = 0;
+	halResetFlow();
+	halRelaisOff(RELAIS_PUMP);
+
+	/*
+	 * Wait for coffee to soak in infused water
+	 */
+	brewTimer.start();
+	while (brewTime < TIME_SOAK) {
+		usleep(100000);
+		if (getState() == SigInt1Psh)
+			return;
+	}
+	brewTimer.stop();
+	brewTime = 0;
+
+	/*
+	 * Brewing the actual espresso
+	 */
+	logger(V_BREW, "Starting infusion...\n");
+	halRelaisOn(RELAIS_PUMP);
+	brewTimer.start();
+	while (brewTime < TIME_INFUSION && halGetFlow() < AMOUNT_DBLESPRESSO) {
+		usleep(100000);
+		if (getState() == SigInt1Psh)
+			return;
+	}
+	halRelaisOff(RELAIS_PUMP);
+	halResetFlow();
+	brewTimer.stop();
+	brewTime = 0;
+	changeState(STATE_IDLE);
+	return;
+}
+
+/**
+ *
+ */
+void coffeeIncreaseBrewCounter(void) {
+	uint64_t brewcounter = sqlGetConf(SQLbrewcounter);
+	if (sqlSetConf(SQLbrewcounter, ++brewcounter)) {
+		logger_error("Couldn't write brewcounter to database");
+	}
+}
+
+/**
+ *
+ */
+void coffeeIncreaseHeatingTime(uint64_t heatingTime) {
+	uint64_t totalHeatingTime = sqlGetConf(SQLHeatingTime);
+	if (sqlSetConf(SQLHeatingTime, (totalHeatingTime + heatingTime))) {
+			logger_error("Couldn't write heating time to database");
+	}
+}

+ 8 - 4
CoffeeCode/coffee.h

@@ -20,18 +20,22 @@
 #define STATE_CLEANING	6
 #define STATE_ERROR	7
 
-#define TIME_PREINFUSION	3000 //Preinfusion time in ms
+#define AMOUNT_PREINFUSION	3 //Preinfusion amount in ml
 #define TIME_SOAK	3000//Time between preinfusion and infusion in ms
 #define TIME_INFUSION 25000	//Infusion time in ms
-#define TIME_DBLESPRESSO	25.0	//Size of a double espresso in ml
+#define AMOUNT_DBLESPRESSO	25.0	//Size of a double espresso in ml
 
 void *coffeeThread(void *threadid);
 
 void coffeeHandler (int signum, siginfo_t *siginfo, void *context);
 int getSigValue(void);
+bool SigValueEmpty(void);
 void changeState(int newState);
+int getState(void);
 void brewTimeHandler (void);
-
-void coffeeTerminate(void);  //@TODO: Implement this method, called on program termination
+void coffeeTerminate(void);
+void coffeeBrew(void);
+void coffeeIncreaseBrewCounter(void);
+void coffeeIncreaseHeatingTime(uint64_t heatingTime);
 
 #endif /* COFFEE_H_ */

+ 2 - 2
CoffeeCode/database.h

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

+ 100 - 33
CoffeeCode/hal.cpp

@@ -13,21 +13,24 @@
 #include "hal.h"
 #include "global.h"
 #include "logger.h"
+#include "timer.h"
 
 int flowcnt = 0;
 
+int Int0Time;
+int Int1Time;
+bool flagIgnoreRlsInt0;
+bool flagIgnoreRlsInt1;
+timer Int0Timer(&halInt0TimerHandler);
+timer Int1Timer(&halInt1TimerHandler);
 /**
  * Initializes HAL
  */
 void halInit(void) {
 	if (optPower) {
-		halRelaisOn(RELAIS_HEAT);
-		halRelaisOff(RELAIS_PUMP);
-		halRelaisOn(RELAIS_POWER);
+		halMachineOn();
 	} else {
-		halRelaisOff(RELAIS_HEAT);
-		halRelaisOff(RELAIS_PUMP);
-		halRelaisOff(RELAIS_POWER);
+		halMachineOff();
 	}
 	pinMode(RELAIS_HEAT, OUTPUT);
 	pinMode(RELAIS_PUMP, OUTPUT);
@@ -37,6 +40,15 @@ void halInit(void) {
 	pinMode(PIN_INT0, INPUT);
 	pinMode(PIN_INT1, INPUT);
 	pinMode(PIN_FLOW, INPUT);
+
+	Int0Timer.setDivider(4); //200ms
+	Int1Timer.setDivider(4);
+	Int0Time = 0;
+	Int1Time = 0;
+
+	flagIgnoreRlsInt0 = false;
+	flagIgnoreRlsInt1 = false;
+
 	if (wiringPiISR(PIN_INT0, INT_EDGE_BOTH, &halInt0) < 0) {
 		logger_error("Unable to setup ISR0: %s\n", strerror(errno));
 		return;
@@ -49,11 +61,11 @@ void halInit(void) {
 		logger_error("Unable to setup ISRFLOW: %s\n", strerror(errno));
 		return;
 	}
-	if(wiringPiISR(PIN_PRESSURE_CTRL, INT_EDGE_BOTH, &halIntPressure) < 0) {
+	if (wiringPiISR(PIN_PRESSURE_CTRL, INT_EDGE_BOTH, &halIntPressure) < 0) {
 		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;
 	}
@@ -109,26 +121,64 @@ int halGetRelaisState(int relais) {
 }
 
 /**
- * Interrupt routine for Int0 (bottom button)
+ * Interrupt routine for Int0 (Top button)
  */
 void halInt0(void) {
 	logger(V_BASIC, "Int0 triggered\n");
 	if (halGetInt0()) {
-		halSendSignal(SigInt0Rls);
+		if (flagIgnoreRlsInt0) {
+			flagIgnoreRlsInt0 = false;
+		} else {
+			halSendSignal(SigInt0Rls);
+		}
 	} else {
 		halSendSignal(SigInt0Psh);
+		Int0Time = 0;
+		Int0Timer.start();
 	}
 }
 
 /**
- * Interrupt routine for Int1 (top button)
+ *
+ */
+void halInt0TimerHandler(void) {
+	Int0Time += 200;
+	if (Int0Time >= (TIME_BUTTONLONGPRESS * 1000)) {
+		halSendSignal(SigInt0RlsLong);
+		flagIgnoreRlsInt0 = true;
+		Int0Time = 0;
+		Int0Timer.stop();
+	}
+}
+
+/**
+ * Interrupt routine for Int1 (Bottom button)
  */
 void halInt1(void) {
 	logger(V_BASIC, "Int1 triggered\n");
-	if (halGetInt1()) {
-		halSendSignal(SigInt1Rls);
-	} else {
-		halSendSignal(SigInt1Psh);
+		if (halGetInt1()) {
+			if (flagIgnoreRlsInt1) {
+				flagIgnoreRlsInt1 = false;
+			} else {
+				halSendSignal(SigInt1Rls);
+			}
+		} else {
+			halSendSignal(SigInt1Psh);
+			Int1Time = 0;
+			Int1Timer.start();
+		}
+}
+
+/*
+ *
+ */
+void halInt1TimerHandler(void) {
+	Int1Time += 200;
+	if (Int1Time >= TIME_BUTTONLONGPRESS) {
+		halSendSignal(SigInt1RlsLong);
+		flagIgnoreRlsInt1 = true;
+		Int1Time = 0;
+		Int1Timer.stop();
 	}
 }
 
@@ -140,11 +190,11 @@ 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());
-	 if (flowcnt == 99) {
-	 halRelaisOff(RELAIS_PUMP);
-	 }
-	 flowcnt++;
+	lcdPrintf(lcd, "ml = %.2f   ", halGetFlow());
+	if (flowcnt == 99) {
+		halRelaisOff(RELAIS_PUMP);
+	}
+	flowcnt++;
 }
 
 /**
@@ -175,13 +225,13 @@ void halIntProximity(void) {
  * Returns total flow trough sensor in ml
  */
 float halGetFlow(void) {
-	return flowcnt*FLOW_ML_PULSE;
+	return flowcnt * FLOW_ML_PULSE;
 }
 
 /**
  * Resets the Flow counter
  */
-void halResetFlow(void){
+void halResetFlow(void) {
 	flowcnt = 0;
 }
 
@@ -190,7 +240,7 @@ void halResetFlow(void){
  * @return 0 for closed Pressure Control(heating) and 1 for open
  */
 bool halIsHeating(void) {
-	if(digitalRead(PIN_PRESSURE_CTRL) == 0){
+	if (digitalRead(PIN_PRESSURE_CTRL) == 0) {
 		return true;
 	} else {
 		return false;
@@ -201,13 +251,13 @@ bool halIsHeating(void) {
  * Returns status of the proximity switch
  * @return 1 if the proximity switch is covered and 0 if uncovered
  */
-bool halProxSensorCovered(void){
+bool halProxSensorCovered(void) {
 	//for legacy till sensor is installed
 	/*if(digitalRead(PROXIMITY_SENSOR) == 0){
-		return false;
-	} else {
-		return true;
-	}*/
+	 return false;
+	 } else {
+	 return true;
+	 }*/
 	return true;
 }
 
@@ -215,7 +265,7 @@ bool halProxSensorCovered(void){
  * Returns the value of the top button Int0 (low active)
  * @return LOW or HIGH
  */
-int halGetInt0(void){
+int halGetInt0(void) {
 	return digitalRead(PIN_INT0);
 }
 
@@ -223,7 +273,7 @@ int halGetInt0(void){
  * Returns the value of the bottom button Int1 (low active)
  * @return LOW or HIGH
  */
-int halGetInt1(void){
+int halGetInt1(void) {
 	return digitalRead(PIN_INT1);
 }
 
@@ -231,14 +281,31 @@ int halGetInt1(void){
  * send Signal to coffee thread
  * @param val Integer value assigned to signal
  */
-void halSendSignal(int val){
-	sigval value = {0};
+void halSendSignal(int val) {
+	sigval value = { 0 };
 	value.sival_int = (int) val;
 
-	if(pthread_sigqueue(thread[THREAD_COFFEE], SIGUSR2, value)) {
+	if (pthread_sigqueue(thread[THREAD_COFFEE], SIGUSR2, value)) {
 		logger_error("Failed to queue signal %d %s", val, strerror(errno));
 		//No Signals reach the state machine anymore...
 		exit(EXIT_FAILURE);
 	}
 }
 
+/**
+ * Turn machine on
+ */
+void halMachineOn(void) {
+	halRelaisOn(RELAIS_HEAT);
+	halRelaisOff(RELAIS_PUMP);
+	halRelaisOn(RELAIS_POWER);
+}
+
+/**
+ * Turn machine off
+ */
+void halMachineOff(void) {
+	halRelaisOff(RELAIS_HEAT);
+	halRelaisOff(RELAIS_PUMP);
+	halRelaisOff(RELAIS_POWER);
+}

+ 28 - 11
CoffeeCode/hal.h

@@ -13,30 +13,43 @@
 #define RELAIS_POWER	28
 #define PIN_PRESSURE_CTRL	7
 #define PIN_PROXIMITY_SENSOR	6
-#define PIN_INT0		0 // bottom button
-#define PIN_INT1		2 // top button
-#define PIN_FLOW		3 // flow sensor
+#define PIN_INT0		2 // Top button
+#define PIN_INT1		0 // Bottom button
+#define PIN_FLOW		3 // Flow sensor
 #define FLOW_ML_PULSE	(1000.0/990) // Flow sensor: volume (ml) per pulse
+
+#define TIME_BUTTONLONGPRESS	3	//Time in s until a Signal for a long pressed button is sent
 /*
  * Explanation for the signal levels
  * SigInt_Psh 			Button is pushed
  * SigInt_Rls 		Button is released
+ * SigInt_RlsLong	Button is pressed for more than TIME_BUTTONLONGPRESS seconds
  * SigPressCls 		Pressure control is closed, System is heating
  * SigPressOpn		Pressure control is open, heating is off
  * SigProxOpn		Proximity Sensor is uncovered
  * SigProxCvrd	Proximity Sensor is covered
  */
+
+/*
+ * Functions of the buttons, the letter in brackets defines if the event is triggered
+ * on push(P), release(R) or long pressing(RLong) of the button
+ * TOP Button: Turn machine on(R), start brewing(P),
+ *
+ * BOTTOM button: Stop brewing immediately(P), Turn machine off(RLong),
+ */
 enum HalSig {
 	SigInt0Psh = 1,
 	SigInt0Rls = 2,
-	SigInt1Psh = 3,
-	SigInt1Rls = 4,
-	SigPressCls = 5,
-	SigPressOpn = 6,
-	SigProxOpn = 7,
-	SigProxCvrd = 8,
-	SigBrewOn = 9,
-	SigBrewOff = 10
+	SigInt0RlsLong = 3,
+	SigInt1Psh = 4,
+	SigInt1Rls = 5,
+	SigInt1RlsLong = 6,
+	SigPressCls = 7,
+	SigPressOpn = 8,
+	SigProxOpn = 9,
+	SigProxCvrd = 10,
+	SigBrewOn = 11,
+	SigBrewOff = 12
 };
 
 void halInit(void);
@@ -56,5 +69,9 @@ bool halProxSensorCovered(void);
 int halGetInt0(void);
 int halGetInt1(void);
 void halSendSignal(int value);
+void halMachineOn(void);
+void halMachineOff(void);
+void halInt0TimerHandler(void);
+void halInt1TimerHandler(void);
 
 #endif /* HAL_H_ */