Explorar o código

Added simple networking interface for turning the machine on/off etc

Philipp Hinz %!s(int64=7) %!d(string=hai) anos
pai
achega
8ed4cad6d8

+ 9 - 3
CoffeeCode/Release/subdir.mk

@@ -12,7 +12,9 @@ CPP_SRCS += \
 ../main.cpp \
 ../spi.cpp \
 ../stripe.cpp \
-../timer.cpp 
+../timer.cpp  \
+../display.cpp  \
+../server.cpp 
 
 OBJS += \
 ./crc.o \
@@ -23,7 +25,9 @@ OBJS += \
 ./main.o \
 ./spi.o \
 ./stripe.o \
-./timer.o 
+./timer.o  \
+./display.o  \
+./server.o 
 
 CPP_DEPS += \
 ./crc.d \
@@ -34,7 +38,9 @@ CPP_DEPS += \
 ./main.d \
 ./spi.d \
 ./stripe.d \
-./timer.d 
+./timer.d  \
+./display.d  \
+./server.d
 
 
 # Each subdirectory must supply rules for building sources it contributes

+ 1 - 1
CoffeeCode/buildno

@@ -1 +1 @@
-112
+135

+ 1 - 0
CoffeeCode/global.h

@@ -32,6 +32,7 @@ extern pthread_t thread[];
 #define THREAD_STRIPE	1
 #define THREAD_DISPLAY	2
 #define THREAD_COFFEE	3
+#define THREAD_SERVER 	4
 
 
 void killThread(int threadid, int sig);

+ 1 - 1
CoffeeCode/hal.cpp

@@ -283,7 +283,7 @@ int halGetInt1(void) {
  * send Signal to coffee thread
  * @param val Integer value assigned to signal
  */
-void halSendSignal(int val) {
+void halSendSignal(HalSig val) {
 	sigval value = { 0 };
 	value.sival_int = (int) val;
 

+ 1 - 1
CoffeeCode/hal.h

@@ -68,7 +68,7 @@ bool halIsHeating(void);
 bool halProxSensorCovered(void);
 int halGetInt0(void);
 int halGetInt1(void);
-void halSendSignal(int value);
+void halSendSignal(HalSig value);
 void halMachineOn(void);
 void halMachineOff(void);
 void halInt0TimerHandler(void);

+ 13 - 3
CoffeeCode/main.cpp

@@ -24,6 +24,7 @@
 #include "stripe.h"
 #include "coffee.h"
 #include "display.h"
+#include "server.h"
 
 const int buildno = (1+(int)(
 #include "buildno"
@@ -32,6 +33,7 @@ const int buildno = (1+(int)(
 int verbose = 0;
 bool optDate = false;
 bool optPower = false;
+bool optNoNet = false;
 
 void *mainLoop(void *threadid);
 void terminationHandler(int signum);
@@ -54,7 +56,7 @@ int main(int argc, char *argv[]) {
 			"Build number %d\n", buildno);
 
 	// Argument handling
-	while (prev_ind = optind, (opt = getopt(argc, argv, "?hvVdp")) != -1) {
+	while (prev_ind = optind, (opt = getopt(argc, argv, "?hvVdpn")) != -1) {
 		if (argc > 3)
 			if (optind == prev_ind + 2 && *optarg == '-') {
 				opt = '?';
@@ -74,6 +76,9 @@ int main(int argc, char *argv[]) {
 		case 'p': // power machine on program start
 			optPower = true;
 			break;
+		case 'n': // disable network functionality
+			optNoNet = true;
+			break;
 
 		case '?':
 		case 'h':
@@ -83,6 +88,7 @@ int main(int argc, char *argv[]) {
 			printf("\t-V\t\tPrints only the version and exits\n");
 			printf("\t-d\t\tPrints a timestamp before every line\n");
 			printf("\t-p\t\tPowers the machine on program start\n");
+			printf("\t-n\t\tDisable network functionality\n");
 
 			printf("Listening to the following signals:\n");
 			printf("\tSIGUSR1(%u)\tPrints monitor data of all nodes\n",
@@ -91,7 +97,7 @@ int main(int argc, char *argv[]) {
 			SIGHUP);
 			return EXIT_SUCCESS;
 		default:
-			fprintf(stderr, "Usage: %s [-hvVdp]\n", argv[0]);
+			fprintf(stderr, "Usage: %s [-hvVdpn]\n", argv[0]);
 			return EXIT_FAILURE;
 			break;
 		}
@@ -134,7 +140,7 @@ int main(int argc, char *argv[]) {
 	if (rc != 0)
 		throw(L"pthread_mutexattr_destroy returns " + rc);
 
-	for (int i = 0; i < 4; i++) {
+	for (int i = 0; i < 5; i++) {
 		if (i == THREAD_MAIN)
 			rc = pthread_create(&thread[i], NULL, mainLoop, (void *) i);
 		else if (i == THREAD_STRIPE)
@@ -143,6 +149,8 @@ int main(int argc, char *argv[]) {
 			rc = pthread_create(&thread[i], NULL, displayThread, (void *) i);
 		else if (i == THREAD_COFFEE)
 			rc = pthread_create(&thread[i], NULL, coffeeThread, (void *) i);
+		else if (i == THREAD_SERVER && !optNoNet)
+			rc = pthread_create(&thread[i], NULL, serverThread, (void *) i);
 		if (rc) {
 			logger_error("Error:unable to create thread %d (%d)\n", i, rc);
 			exit(-1);
@@ -177,6 +185,7 @@ void terminationHandler(int signum) {
 	stopTimers();
 	//coffeeTerminate();
 	displayTerminate();
+	serverTerminate();
 
 	/*logger(V_NONE, "Saving my state to the database..\n");
 	sqlExecute("begin");
@@ -237,3 +246,4 @@ void *mainLoop(void *threadid) {
 	}
 	pthread_exit(NULL);
 }
+

+ 2 - 0
CoffeeCode/makefile.targets

@@ -7,4 +7,6 @@ OBJS2 += \
 ./spi.o \
 ./stripe.o \
 ./timer.o \
+./server.o \
+./display.o \
 ./sqlite/sqlite3.o 

+ 168 - 0
CoffeeCode/server.cpp

@@ -0,0 +1,168 @@
+/*
+ * server.cpp
+ *
+ *  Created on: Jan 4, 2018
+ *      Author: Philipp Hinz
+ *      based on: https://gist.github.com/suyash/2488ff6996c98a8ee3a84fe3198a6f85
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "server.h"
+#include "logger.h"
+#include "hal.h"
+#include "coffee.h"
+#include "stripe.h"
+
+/**
+ * TCP Uses 2 types of sockets, the connection socket and the listen socket.
+ * The Goal is to separate the connection phase from the data exchange phase.
+ * */
+
+int listen_sock;
+int sock;
+char buffer_ok[] = "OK\n";
+
+/**
+ * Just sends an ACK message back
+ */
+
+void sendACK() {
+	send(sock, buffer_ok, strlen(buffer_ok), 0);
+}
+
+/**
+ * Main thread to handle networking stuff
+ * @param *threadid Thread ID
+ */
+
+void* serverThread(void* threadid) {
+	sleep(1); // Wait for other components to initialize
+
+	// socket address used for the server
+	struct sockaddr_in server_address;
+	memset(&server_address, 0, sizeof(server_address));
+	server_address.sin_family = AF_INET;
+
+	// htons: host to network short: transforms a value in host byte
+	// ordering format to a short value in network byte ordering format
+	server_address.sin_port = htons(SERVER_PORT);
+
+	// htonl: host to network long: same as htons but to long
+	server_address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	// create a TCP socket, creation returns -1 on failure
+	if ((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+		logger_error("could not create listen socket\n");
+		pthread_exit(0);
+	}
+
+	// bind it to listen to the incoming connections on the created server
+	// address, will return -1 on error
+	if ((bind(listen_sock, (struct sockaddr *) &server_address,
+			sizeof(server_address))) < 0) {
+		logger_error("could not bind socket\n");
+		pthread_exit(0);
+	}
+
+	int wait_size = 16;  // maximum number of waiting clients, after which
+						 // dropping begins
+	if (listen(listen_sock, wait_size) < 0) {
+		logger_error("could not open socket for listening\n");
+		pthread_exit(0);
+	}
+
+	logger(V_BASIC, "Now listening for commands on port %d\n", SERVER_PORT);
+
+	// socket address used to store client address
+	struct sockaddr_in client_address;
+	unsigned int client_address_len = 0;
+
+	// run indefinitely
+	while (true) {
+		// open a new socket to transmit data per connection
+		if ((sock = accept(listen_sock, (struct sockaddr *) &client_address,
+				&client_address_len)) < 0) {
+			logger_error("could not open a socket to accept data\n");
+			pthread_exit(0);
+		}
+
+		int n = 0;
+		int len = 0, maxlen = 100, lastlen = 0;
+		char buffer[maxlen];
+		char cmd[maxlen];
+		char *pcmd = cmd;
+		char *pbuffer = buffer;
+		strncpy(buffer, "", maxlen);
+		strncpy(cmd, "", maxlen);
+
+		logger(V_HAL, "client connected with ip address: %s\n",
+				inet_ntoa(client_address.sin_addr));
+
+		// keep running as long as the client keeps the connection open
+		while ((n = recv(sock, pbuffer, maxlen, 0)) > 0) {
+			pbuffer += n;
+			maxlen -= n;
+			len += n;
+
+			strncpy(cmd, buffer, len - 1);
+			cmd[len - 1] = '\0';
+			pcmd = &cmd[lastlen];
+			logger(V_SPI, "received %d bytes: '%s' (cmd: %s)\n", len, buffer,
+					pcmd);
+
+			if (!strcmp(SERVER_CMD_ON, pcmd)) {
+				if (getState() == STATE_OFF) {
+					halSendSignal(SigInt0Rls);
+					sendACK();
+				}
+			} else if (!strcmp(SERVER_CMD_OFF, pcmd)) {
+				if (getState() != STATE_OFF) {
+					halSendSignal(SigInt1RlsLong);
+					sendACK();
+				}
+			} else if (!strcmp(SERVER_CMD_BREW, pcmd)) {
+				if (getState() == STATE_IDLE || getState() == STATE_HEATING) {
+					halSendSignal(SigInt1Rls);
+					sendACK();
+				}
+			} else if (!strcmp(SERVER_CMD_STATUS, pcmd)) {
+				char tmp[] = "0\n";
+				tmp[0] += getState();
+				send(sock, tmp, sizeof(tmp), 0);
+			} else if (!strcmp(SERVER_CMD_STRIPEON, pcmd)) {
+				stripeOn();
+				sendACK();
+			} else if (!strcmp(SERVER_CMD_STRIPEOFF, pcmd)) {
+				stripeOff();
+				sendACK();
+			}
+
+			lastlen = len;
+			// echo received content back
+			//send(sock, buffer, len, 0);
+		}
+
+		close(sock);
+	}
+
+	close(listen_sock);
+	pthread_exit(EXIT_SUCCESS);
+}
+
+/**
+ * Closes all active connections
+ */
+
+void serverTerminate() {
+	close(sock);
+	close(listen_sock);
+}
+

+ 25 - 0
CoffeeCode/server.h

@@ -0,0 +1,25 @@
+/*
+ * server.h
+ *
+ *  Created on: Jan 4, 2018
+ *      Author: sebastian
+ */
+
+#ifndef SERVER_H_
+#define SERVER_H_
+
+#define SERVER_PORT 4242
+
+#define SERVER_CMD_ON 			"turnon"
+#define SERVER_CMD_OFF 			"turnoff"
+#define SERVER_CMD_STATUS 		"status"
+#define SERVER_CMD_BREW			"brew"
+#define SERVER_CMD_STRIPEON 	"stripeon"
+#define SERVER_CMD_STRIPEOFF 	"stripeoff"
+
+void *serverThread(void *threadid);
+void serverTerminate();
+
+
+
+#endif /* SERVER_H_ */