/*
 * productionMode.cpp
 *
 *  Created on: Jan 24, 2018
 *      Author: wn
 */


#include "defines.h"

#define MQTT_MAX_PACKET_SIZE 256

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <PubSubClient.h>

#include "configuration.h"






WiFiClientSecure espClient;
PubSubClient client(espClient);

void setup_wifi() {
	delay(10);
	WiFi.mode(WIFI_STA);

	// We start by connecting to a WiFi network
#ifdef DEBUG
	Serial.println();
	Serial.print("Connecting to ");
	Serial.println(configBlock.wifiSsid);
#endif

	WiFi.begin(configBlock.wifiSsid, configBlock.wifiKey);

	while (WiFi.status() != WL_CONNECTED) {
		delay(50);
#ifdef DEBUG
		Serial.print(".");
#endif
	}
	Serial.println("!");

#ifdef DEBUG
	Serial.println("");
	Serial.println("WiFi connected");
	Serial.println("IP address: ");
	Serial.println(WiFi.localIP());
#endif
}



void reconnect() {
	// Loop until we're reconnected
	while (!client.connected()) {
#ifdef DEBUG
		Serial.print("Attempting MQTT connection...");
#endif
		// Attempt to connect
		//char clientId[128];
		//snprintf(clientId, 127, "esp%s", WiFi.macAddress().c_str());
		if (client.connect(configBlock.mqttClientId, configBlock.mqttUser, configBlock.mqttPass)) {
#ifdef DEBUG
			Serial.println("connected");
#endif
			// Once connected, publish an announcement...
			client.publish(configBlock.mqttDebugTopic, "hello world");
		} else {
#ifdef DEBUG
			Serial.print("failed, rc=");
			Serial.print(client.state());
			Serial.println(" try again in 5 seconds");
#endif
			// Wait 5 seconds before retrying
			delay(5000);
		}
	}
}


bool mqtt_connect() {
	bool reconnected = false;
	if (!client.connected()) {
		reconnect();
		reconnected = true;
	}
	client.loop();
	return reconnected;
}


void setupProduction() {
	setup_wifi();
	client.setServer(configBlock.mqttBroker, configBlock.mqttPort);
}


void loopProduction() {
	bool reconnected = mqtt_connect();



	noInterrupts();
	// discharge
	digitalWrite(TOUCH_PIN_SEND, LOW);
	pinMode(TOUCH_PIN_SEND, OUTPUT);
	digitalWrite(TOUCH_PIN_RECEIVE, LOW);
	pinMode(TOUCH_PIN_RECEIVE, OUTPUT);

	// sense
	pinMode(TOUCH_PIN_RECEIVE, INPUT);
	digitalWrite(TOUCH_PIN_SEND, HIGH);

	const uint32_t MAX_CHARGE_CNT = 1000;
	uint32_t chargeCnt = 0;

	while ((! digitalRead(TOUCH_PIN_RECEIVE)) && (chargeCnt < MAX_CHARGE_CNT)) {
		chargeCnt++;
	}
	interrupts();

	static uint32_t senseCnt = 0;
	static uint32_t chargeCntSum = 0;

	chargeCntSum += chargeCnt;
	senseCnt++;

	static uint32_t lastMillis = 0;
	uint32_t currentMillis = millis();


	if ((currentMillis - lastMillis > configBlock.period) && (! reconnected)) {
		lastMillis = currentMillis;

		uint32_t chargeCntAvg = chargeCntSum / senseCnt;

		static uint32_t baseline = UINT32_MAX;
		if (chargeCntAvg < baseline) {
			baseline = chargeCntAvg;

			char payload[128];
			snprintf(payload, 127, "%ld", baseline);
			client.publish(configBlock.mqttBaselineTopic, payload);
		}

		uint32_t capNum = chargeCntAvg - baseline;

		if (configBlock.debugMode) {
			char payload[128];
			snprintf(payload, 127, "%ld %ld %ld %ld", senseCnt, baseline, chargeCntAvg, capNum);
			client.publish(configBlock.mqttDebugTopic, payload);
		}

		chargeCntSum = 0;
		senseCnt = 0;

		static enum { NOT_PRESSED, PRESSED, LONG_SHORT_GAP_1, LONG_SHORT_GAP_2, LONG_PRESSED } state = NOT_PRESSED;
		if (capNum > configBlock.threshold) {
#ifdef DEBUG
			char payload[128];
			snprintf(payload, 127, "%ld %ld %ld %ld", senseCnt, baseline, chargeCntAvg, capNum);
			Serial.println(payload);
#endif

			switch (state) {
			case NOT_PRESSED:
				state = PRESSED;
				break;
			case PRESSED:
				state = LONG_SHORT_GAP_1;
				break;
			case LONG_SHORT_GAP_1:
				state = LONG_SHORT_GAP_2;
				break;
			case LONG_SHORT_GAP_2:
				state = LONG_PRESSED;
				client.publish(configBlock.mqttTopic, "LONG_BEGIN");
				break;
			case LONG_PRESSED:
				state = LONG_PRESSED;
				client.publish(configBlock.mqttTopic, "LONG_CONT");
				break;
			}
		} else {
			static uint32_t lastCalibration = 0;
			if (currentMillis - lastCalibration > configBlock.calibrationTimeout) {
				baseline = UINT32_MAX;
				lastCalibration = currentMillis;
			}

			switch (state) {
			case NOT_PRESSED:
				break;
			case PRESSED:
			case LONG_SHORT_GAP_1:
			case LONG_SHORT_GAP_2:
				client.publish(configBlock.mqttTopic, "SHORT");
				break;
			case LONG_PRESSED:
				client.publish(configBlock.mqttTopic, "LONG_END");
				break;
			}
			state = NOT_PRESSED;
		}
	}
}




