#define VERSION 	"1.2"

#include <mbed.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <millis.h>
#include "IO_Ports.h"
#include "MQTT_Com.h"
#include "WIZnetInterface.h"
#include "DS18B20Sensor.h"
#include "TEnergyMonitor/TEnergyMonitor.h"
//#include "MAX6675.h"

#define IP 					"10.0.2.251"
#define NETMASK				"255.255.255.0"
#define GATEWAY 			"10.0.2.1"
#define RECEIVE_TOPIC 		"emonhub/etcontroller/send"
#define SEND_TOPIC 			"emonhub/etcontroller/receive"

// General Functions Prototypes
void sendMessage(char*topic, char* msg);
void sendPoll(void);
void readCurrent(void);
void onMessage(MQTT::MessageData &msgMQTT);
void initEth(void);

/////////////// ETHERNET ///////////////////////////
extern int connack_rc;
uint8_t MAC[6]={0x58,0x72,0x2D,0xBF,0xB3,0x88};
SPI spi(MOSI, MISO, SCLK);
MQTTEthernet ipstack(MAC, IP, NETMASK, GATEWAY, &spi, CS, RST);
MQTT::Client<MQTTEthernet, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
/////////////// WIFI ///////////////////////////

/////////////// SYSTEM /////////////////////////
Serial pc(SERIAL_TX, SERIAL_RX);
DigitalOut myLed(LED1);
Ticker pollTimer, currentTimer;
BusOut relayOut(DO0,DO1,DO2,DO3,DO4,DO5,DO6,DO7);
char type,command;
int relayStatus = 0, relayCommand = 0, lastPower = 0;

/////////////// SYSTEM /////////////////////////

/////////////// GLOBAL VARS /////////////////////
char inMessage[MQTT_MAX_PAYLOAD_SIZE],outMessage[MQTT_MAX_PAYLOAD_SIZE],buf1[8],buf2[8],buf3[8];
bool newMessage=false, poll=false, rcurrent=true, DEBUG=true;
unsigned int i=0;
unsigned int pLevels[]={3500,0,2000,2500,3000};
/////////////// GLOBAL VARS /////////////////////

/////////////// SENSORS /////////////
DS18B20Sensor TempSens(D8);
TEnergyMonitor ct1(&pc);
/////////////// SENSORS /////////////

//////////////////////////////////////////////////////////////////
/////////////////////////   MAIN    //////////////////////////////
//////////////////////////////////////////////////////////////////

int main() {
	millisStart();
	pc.printf("%c[2J \tE&T Soft. Heatpump Power Controller and Heating System Monitoring V%s \n",27,VERSION);
	myLed=1;
	wait(2);
	initEth(); // Enables Network Connection to MQTT Server
    pc.printf("Subscribed to: %s, %d \r\n", RECEIVE_TOPIC, client.subscribe(RECEIVE_TOPIC, MQTT::QOS1, onMessage));
    pollTimer.attach(&sendPoll, 5);
    currentTimer.attach(&readCurrent, 5);
    TempSens.search();
    relayOut=255;
    ct1.current(A0,40);
//////////////////////////////////////////////////////////////////
///////////////////////// MAIN LOOP //////////////////////////////
//////////////////////////////////////////////////////////////////
    while (true){
    	client.yield(10);
        myLed=!myLed;
        if (newMessage) {
        	newMessage=false;
        	relayStatus = ~relayOut.read();
        	int rv = sscanf(inMessage,"%c:%d",&type,&command);
        	//pc.printf("sscanf:%d - %c,%d\n", rv,type,command);
        	if (rv <= 1 || rv == EOF)
        		sprintf(outMessage,"NAK");
        	else {
        		switch (type) {
        		case 'P':
        			if(command >= 1 && command <= 4) {
        				relayCommand = (relayStatus & 0x0070) | (1 << (command-1));
        			}
        			else if (command == 0) {
        				relayCommand = (relayStatus & 0x0070);
        			}
        			//lastPower=pLevels[command];
        			sprintf(outMessage,"RL_O:%02X",relayCommand);
        			relayOut=~relayCommand;
        			break;

        		case 'R':
        			if(command>=0 && command<=7){
        				relayCommand = (relayStatus & 0x000F) | (command << 4);
        				sprintf(outMessage,"RL_O:%02X",relayCommand);
        				relayOut=~relayCommand;
        			}
        			break;

        		case 'S':
        			sprintf(outMessage,"RL_O:%02X",relayCommand);
        			break;

        		case 'T':
        			TempSens.startReading(true);
        			TempSens.getReading(buf1,0);
        			TempSens.getReading(buf2,1);
        			TempSens.getReading(buf3,2);
        			sprintf(outMessage,"WT_T:%s;SL_T:%s;HT_T:%s",buf2,buf3,buf1);
        			break;

        		case 'H':
        			sprintf(outMessage,"HP_W:%d",lastPower);
        			break;

        		default:
        			break;
        		}
        	}
        	sendMessage(SEND_TOPIC,outMessage);
        }
        if (poll){
        	poll=false;
        	sprintf(outMessage,"POLL [%d]",i++);
        	sendMessage(SEND_TOPIC, outMessage);
        	client.yield(10);
        }
        if (rcurrent){
        	rcurrent=false;
        	lastPower=(int)((ct1.calcIrms(2)-0.08)*235);
        	if(DEBUG) pc.printf("current:%1.3f, power:%d\n",ct1.calcIrms(2)-0.08,lastPower);
        }
        wait(1);
    }
}

//////////////////////////////////////////////////////////////////
////////////////////// GENERAL FUNCTS ////////////////////////////
//////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////
////////////////////// ETHERNET FUNCTIONS ////////////////////////
//////////////////////////////////////////////////////////////////
void onMessage(MQTT::MessageData &msgMQTT) {
	strncpy(inMessage,(char*)msgMQTT.message.payload,(uint)msgMQTT.message.payloadlen);
	inMessage[(uint)msgMQTT.message.payloadlen]='\0';
    newMessage=true;
    if (DEBUG) pc.printf("Received: %s\n",inMessage);
}

void sendMessage(char*topic,char* msg){
	if (DEBUG) pc.printf("Sent: %s\n", msg);
	publish(&client, &ipstack, topic, msg);
}

void sendPoll(void){
	poll=true;
}

void readCurrent(void){
	rcurrent=true;
}

void initEth (void){
    pc.printf("\nConnecting to ETH\n");
    attemptConnect(&client, &ipstack);
   if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD){
      while (true){
            wait(1.0); // Permanent failures - don't retry
            pc.printf("\nMQTT_NOT_AUTHORIZED or BAD_USERNAME_OR_PASSWORD\n");
      }
   }   
}
