/*
    
Annie Conover
Senior Design: Sudden Death
ESP8266 code

This code connects to a raspberry pi that is set up as an Wi-Fi access point and running 
a MQTT server when provided with a username, password and IP Address. 

This code also sets up the SPI as a slave on the ESP8266 to read from the microcontroller. 
It uses the following pins on the ESP9266:

 |  GPIO  |   Name   |
 =====================
 |   15   |    SS    |
 |   13   |    MOSI  |  
 |   12   |    MISO  |  
 |   14   |    SCK   | 

    Note: If the ESP is booting at a moment when the SPI Master has the Select line HIGH (deselected)
    the ESP8266 WILL FAIL to boot!
    See SPISlave_SafeMaster example for possible workaround

*/


//include libraries
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "SPISlave.h"

// Set given network information: using the Pi-3 network
const char *ssid =  "Pi3-AP";   // cannot be longer than 32 characters
const char *pass =  "raspberry";   

IPAddress server(172, 24, 1, 1);

void callback(const MQTT::Publish& pub) {
  // handle message arrived
}

WiFiClient wclient;
PubSubClient client(wclient, server);

// initialize variables
const char* s1 = 0;
char* s = "test";
int spi_interrupt = 0;

void setup() {
  // Setup console
  Serial.begin(115200); //baud rate
  delay(10);
  Serial.println();
  Serial.println();

  Serial.printf("\n Start \n\r"); //begin SPI Slave routine

  // Note: 
  // Data must be recieved from master for SPISlave interrupt to begin.
  // Beware that len is fixed and set to 6 in the SPISlave.cpp file.
  // The buffer is autofilled with zeroes if data is less than 6 bytes long
  // The user to implement protocol for handling data length

  // Start SPISlave interrupt routine to recieve data
  SPISlave.onData([](uint8_t * data, size_t len) {

    s1 = (char *)data;
    //Serial.println("recieved");    
    memcpy(s, s1+2, 4);
    // interrupt flag
    spi_interrupt = 1;

  });

  // Setup SPI Slave registers and pins
  SPISlave.begin();

  // Set the status register (if the master reads it, it will read this value)
  SPISlave.setStatus(millis());

  // Sets the data registers. Limited to 32 bytes at a time.
  // SPISlave.setData(uint8_t * data, size_t len); is also available with the same limitation
  SPISlave.setData("Ask me a question!");
  Serial.println("end");

}


void loop() {

  // Connect to Wi-Fi
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    // wait for a connection
    if (WiFi.waitForConnectResult() != WL_CONNECTED)
      return;
    Serial.println("WiFi connected");
  }

  // Connect to MQTT server
  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      Serial.println("Connecting to MQTT server");
      if (client.connect(MQTT::Connect("arduinoClient")
                         .set_auth("testeruser", "testpass"))) {
        Serial.println("Connected to MQTT server");
        //client.set_callback(callback);
        // client.publish("outTopic", s);

      } else {
        Serial.println("Could not connect to MQTT server");
      }
    }

    if (client.connected())
      client.loop(); 
      //loop if connected to client, maintain connection to server
  }

// Case structure that publishes to the correct topic and sub topic
// based off of the identifier bytes at the beginning of the data
// read by the SPI Slave.

// The first byte determines which topic that is published to
// The second byte determines which sub topic that is published to

// if the SPI interrupt flag is high, enter into the case structure
 
  if (spi_interrupt == 1) {
    switch (s1[0]) { 
      case 1 :
        switch (s1[1]) { 
          case 1 :          
            client.publish("smashStats/player1/characterID", s);
            spi_interrupt = 0;
            Serial.println("character 1 recieved");
            break;

          case 2 :
            client.publish("smashStats/player1/hit_percent", s);
            spi_interrupt = 0;
            Serial.println("hits 1 recieved");
            break;

          case 3 :
            client.publish("smashStats/player1/center_control", s);
            spi_interrupt = 0;
            Serial.println("cc recieved");
            break;

          case 4 :
            client.publish("smashStats/player1/roll_count", s);
            spi_interrupt = 0;
            Serial.println("rc recieved");
            break;

          case 5 :
            client.publish("smashStats/player1/dodge_count", s);
            spi_interrupt = 0;
            Serial.println("dc recieved");
            break;

          case 6 :
            client.publish("smashStats/player1/apm", s);
            spi_interrupt = 0;
            Serial.println("apm recieved");
            break;

          case 7 :
            client.publish("smashStats/player1/avg_combo_damage", s);
            spi_interrupt = 0;
            Serial.println("acd recieved");
            break;

          case 8 :
            client.publish("smashStats/player1/avg_hits_p_combo", s);
            spi_interrupt = 0;
            Serial.println("ahpc recieved");
            break;

          case 9 :
            client.publish("smashStats/player1/openings_p_kill", s);
            spi_interrupt = 0;
            Serial.println("opk recieved");
            break;

          case 10 :
            client.publish("smashStats/player1/edge_guard_eff", s);
            spi_interrupt = 0;
            Serial.println("age recieved");
            break;

          case 11 :
            client.publish("smashStats/player1/neutral_wins", s);
            spi_interrupt = 0;
            Serial.println("opk recieved");
            break;

          case 12 :
            client.publish("smashStats/player1/avg_death_percent", s);
            spi_interrupt = 0;
            Serial.println("adp recieved");
            break;
       }
        break;

      case 2 :
        switch (s1[1]) { 
          case 1 :
            client.publish("smashStats/player2/characterID", s);
            spi_interrupt = 0;
            Serial.println("character 2 recieved");
            break;

          case 2 :
            client.publish("smashStats/player2/hit_percent", s);
            spi_interrupt = 0;
            Serial.println("hits 2 recieved");
            break;

          case 3 :
            client.publish("smashStats/player2/center_control", s);
            spi_interrupt = 0;
            Serial.println("cc recieved");
            break;

          case 4 :
            client.publish("smashStats/player2/roll_count", s);
            spi_interrupt = 0;
            Serial.println("rc recieved");
            break;

          case 5 :
            client.publish("smashStats/player2/dodge_count", s);
            spi_interrupt = 0;
            Serial.println("dc recieved");
            break;

          case 6 :
            client.publish("smashStats/player2/apm", s);
            spi_interrupt = 0;
            Serial.println("apm recieved");
            break;

          case 7 :
            client.publish("smashStats/player2/avg_combo_damage", s);
            spi_interrupt = 0;
            Serial.println("acd recieved");
            break;

          case 8 :
            client.publish("smashStats/player2/avg_hits_p_combo", s);
            spi_interrupt = 0;
            Serial.println("ahpc recieved");
            break;

          case 9 :
            client.publish("smashStats/player2/openings_p_kill", s);
            spi_interrupt = 0;
            Serial.println("opk recieved");
            break;

          case 10 :
            client.publish("smashStats/player2/edge_guard_eff", s);
            spi_interrupt = 0;
            Serial.println("age recieved");
            break;

          case 11 :
            client.publish("smashStats/player2/neutral_wins", s);
            spi_interrupt = 0;
            Serial.println("opk recieved");
            break;

          case 12 :
            client.publish("smashStats/player2/avg_death_percent", s);
            spi_interrupt = 0;
            Serial.println("adp recieved");
            break;
       }
        break;

      case 3 :
        switch (s1[1]) { // switch case second byte (subtopic)
          case 1 :
            client.publish("smashStats/gameinfo/stage", s);
            spi_interrupt = 0;
            Serial.println("stage recieved");
            break;

          case 2 :
            client.publish("smashStats/gameinfo/time", s);
            spi_interrupt = 0;
            Serial.println("time recieved");
            break;
        }
        break;
    }
  }
}




