/*

  SCKBase.cpp
  Supports core and data management functions (Power, WiFi, SD storage, RTClock and EEPROM storage)

  - Modules supported:

    - WIFI (Microchip RN131 (WiFly))
    - RTC (DS1339U and DS1307Z)
    - EEPROM (24LC256)
    - POWER MANAGEMENT IC's

*/

#include "Constants.h"
#include "SCKBase.h"
#include <Wire.h>
#include <EEPROM.h>

#define debugBASE false



void SCKBase::begin() {
  Wire.begin();
  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;  
  Serial.begin(115200);
  Serial1.begin(9600);
  pinMode(IO0, OUTPUT); //VH_MICS5525
  pinMode(IO1, OUTPUT); //VH_MICS2710
  pinMode(IO2, OUTPUT); //MICS2710_HIGH_IMPEDANCE
  pinMode(AWAKE, OUTPUT);
  pinMode(MOSI, OUTPUT);
  pinMode(SCK, OUTPUT);
  pinMode(FACTORY, OUTPUT);
  pinMode(CONTROL, INPUT);
  digitalWrite(AWAKE, LOW); 
  digitalWrite(FACTORY, LOW); 
}

void SCKBase::config(){
  eepromCheck();
  timer1Initialize();
}

void SCKBase::eepromCheck() {
  //do a clearmemory only if needed
  digitalWrite(AWAKE, HIGH);
  boolean doClearMemory = false;
  char temp[17];
  strncpy(temp, MAC(), 18);
  while (compareData(temp, "-1")){
    #if debugBASE
      Serial.println(F("Can't get MAC from Wifly!!!"));
    #endif
    strncpy(temp, MAC(), 18);
  }
  if (!compareData(temp, readData(EE_ADDR_MAC, 0, INTERNAL))) doClearMemory = true;
  uint32_t intTemp;
  intTemp = readData(EE_ADDR_SENSOR_MODE, INTERNAL);
  if (intTemp < 0 || intTemp > 3) doClearMemory = true;
  intTemp = readData(EE_ADDR_TIME_UPDATE, INTERNAL);
  if (intTemp < MIN_TIME_UPDATE || intTemp > MAX_TIME_UPDATE) doClearMemory = true;
  intTemp = readData(EE_ADDR_NUMBER_UPDATES, INTERNAL);
  if (intTemp < DEFAULT_MIN_UPDATES || intTemp > POST_MAX) doClearMemory = true;
  if (doClearMemory) clearmemory();

  //if there are hardcoded networks write them without clearing memory
  //so the user can add more networks after hardcoded one's
  #if (networks > 0)
    intTemp = readData(EE_ADDR_NUMBER_NETS, INTERNAL);
    if (intTemp < networks || intTemp > 5) writeData(EE_ADDR_NUMBER_NETS, networks, INTERNAL);
    for (byte i=0; i<networks; i++){
      if (!compareData(readData(DEFAULT_ADDR_SSID, i, INTERNAL), mySSID[i])) writeData(DEFAULT_ADDR_SSID, i, mySSID[i], INTERNAL);
      if (!compareData(readData(DEFAULT_ADDR_PASS, i, INTERNAL), myPassword[i])) writeData(DEFAULT_ADDR_PASS, i, myPassword[i], INTERNAL);
      if (!compareData(readData(DEFAULT_ADDR_AUTH, i, INTERNAL), wifiEncript[i])) writeData(DEFAULT_ADDR_AUTH, i, wifiEncript[i], INTERNAL);
      if (!compareData(readData(DEFAULT_ADDR_ANTENNA, i, INTERNAL), antennaExt[i])) writeData(DEFAULT_ADDR_ANTENNA, i, antennaExt[i], INTERNAL);
    }
    reset();
  #endif
}

void SCKBase::clearmemory() {
    for(uint16_t i=0; i<(DEFAULT_ADDR_ANTENNA + 160); i++) EEPROM.write(i, 0x00);  // Memory erasing
    writeData(EE_ADDR_SENSOR_MODE, DEFAULT_MODE_SENSOR, INTERNAL);
    writeData(EE_ADDR_TIME_UPDATE, DEFAULT_TIME_UPDATE, INTERNAL);
    writeData(EE_ADDR_NUMBER_UPDATES, DEFAULT_MIN_UPDATES, INTERNAL);
    writeData(EE_ADDR_MAC, 0, MAC(), INTERNAL);
}
  
float SCKBase::average(int anaPin) {
  int lecturas = 100;
  long total = 0;
  float average = 0;
  for(int i=0; i<lecturas; i++)
  {
    //delay(1);
    total = total + analogRead(anaPin);
  }
  average = (float)total / lecturas;  
  return(average);
}

boolean SCKBase::checkText(char* text, char *text1)
{
  byte check = 0;
  byte limit = strlen(text);
  int i = 0;
  for (i = 0; ((i< strlen(text1))&&(check<limit)); i++)
    {
        if (text[check]==text1[i]) check++;
        else check = 0;
    }
  if (check == limit) 
    {
      limit = strlen(text1);
      int j = 0;
      for (j = 0; i<=limit; j++) 
        {
          if (text1[i]=='\r') text1[j]=0x00;
          else text1[j] = text1[i];
          i++;
        }
      return true;
    }
  else return false;
}

boolean SCKBase::compareData(char* text, char* text1)
{
  if ((strlen(text))!=(strlen(text1))) return false;
  else 
  {
    for(int i=0; i<strlen(text); i++)
    {
      if (text[i]!=text1[i]) return false;
    }
  }
  return true;
}

float kr= ((float)P1*1000)/RES;     //  Resistance conversion Constant for the digital pot.

void SCKBase::writeMCP(byte deviceaddress, byte address, int data ) {
  if (data>RES) data=RES;
  Wire.beginTransmission(deviceaddress);
  address=(address<<4)|bitRead(data, 8) ;
  Wire.write(address);
  Wire.write(lowByte(data));
  Wire.endTransmission();
  delay(4);
}

int SCKBase::readMCP(int deviceaddress, uint16_t address ) {
  byte rdata = 0xFF;
  int  data = 0x0000;
  Wire.beginTransmission(deviceaddress);
  address=(address<<4)|B00001100;
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,2);
  unsigned long time = millis();
  while (!Wire.available()) if ((millis() - time)>500) return 0x00;
  rdata = Wire.read(); 
  data=rdata<<8;
  while (!Wire.available()); 
  rdata = Wire.read(); 
  data=data|rdata;
  return data;
}

#if F_CPU == 8000000 
  #define MCP3               0x2D    // Direction of the mcp3 Ajust the battary charge
float SCKBase::readCharge() {
  float resistor = kr*readMCP(MCP3, 0x00)/1000;    
  float current = 1000./(2+((resistor * 10)/(resistor + 10)));
  #if debugBASE
    Serial.print("Resistor : ");
    Serial.print(resistor);
    Serial.print(" kOhm, ");  
    Serial.print("Current : ");
    Serial.print(current);
    Serial.println(" mA");  
  #endif
  return(current);
}

void SCKBase::writeCharge(int current) {
  if (current < 100) current = 100;
  else if (current > 500) current = 500;
  float Rp = (1000./current)-2;
  float resistor = Rp*10/(10-Rp);
  writeMCP(MCP3, 0x00, (uint8_t)(resistor*1000/kr));    
#if debugBASE
  Serial.print("Rc : ");
  Serial.print(Rp + 2);
  Serial.print(" kOhm, ");
  Serial.print("Rpot : ");
  Serial.print(resistor);
  Serial.print(" kOhm, ");  
  Serial.print("Current : ");
  Serial.print(current);
  Serial.println(" mA");  
#endif
}
#endif    

void SCKBase::writeEEPROM(uint16_t eeaddress, uint8_t data) {
  uint8_t retry = 0;
  while ((readEEPROM(eeaddress)!=data)&&(retry<10))
  {  
    Wire.beginTransmission(E2PROM);
    Wire.write((byte)(eeaddress >> 8));   // MSB
    Wire.write((byte)(eeaddress & 0xFF)); // LSB
    Wire.write(data);
    Wire.endTransmission();
    delay(6);
    retry++;
  }
}

byte SCKBase::readEEPROM(uint16_t eeaddress) {
  byte rdata = 0xFF;
  Wire.beginTransmission(E2PROM);
  Wire.write((byte)(eeaddress >> 8));   // MSB
  Wire.write((byte)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(E2PROM,1);
  while (!Wire.available()); 
  rdata = Wire.read();
  return rdata;
}

void SCKBase::writeData(uint32_t eeaddress, long data, uint8_t location)
{
    for (int i =0; i<4; i++) 
      {
        if (location == EXTERNAL) writeEEPROM(eeaddress + (3 -i) , data>>(i*8));
        else EEPROM.write(eeaddress + (3 -i), data>>(i*8));
      }

}

void SCKBase::writeData(uint32_t eeaddress, uint16_t pos, char* text, uint8_t location)
{
  uint16_t eeaddressfree = eeaddress + buffer_length * pos;
  if (location == EXTERNAL)
    {
      for (uint16_t i = eeaddressfree; i< (eeaddressfree + buffer_length); i++) writeEEPROM(i, 0x00);
      for (uint16_t i = eeaddressfree; text[i - eeaddressfree]!= 0x00; i++) writeEEPROM(i, text[i - eeaddressfree]);
    }
  else
    {
      
      for (uint16_t i = eeaddressfree; i< (eeaddressfree + buffer_length); i++) EEPROM.write(i, 0x00);
      for (uint16_t i = eeaddressfree; text[i - eeaddressfree]!= 0x00; i++) 
        {
          if (eeaddressfree>=DEFAULT_ADDR_SSID) if (text[i - eeaddressfree]==' ') text[i - eeaddressfree]='$';
          EEPROM.write(i, text[i - eeaddressfree]); 
        }
    }
}

uint32_t SCKBase::readData(uint16_t eeaddress, uint8_t location)
{
  uint32_t data = 0;
  for (int i =0; i<4; i++)
    {
      if (location == EXTERNAL)  data = data + (uint32_t)((uint32_t)readEEPROM(eeaddress + i)<<((3-i)*8));
      else data = data + (uint32_t)((uint32_t)EEPROM.read(eeaddress + i)<<((3-i)*8));
    }
  return data;
}

char* SCKBase::readData(uint16_t eeaddress, uint16_t pos, uint8_t location)
{
  eeaddress = eeaddress + buffer_length * pos;
  uint16_t i;
  if (location == EXTERNAL)
    {
      uint8_t temp = readEEPROM(eeaddress);
      for ( i = eeaddress; ((temp!= 0x00)&&(temp<0x7E)&&(temp>0x1F)&&((i - eeaddress)<buffer_length)); i++) 
      {
        buffer[i - eeaddress] = readEEPROM(i);
        temp = readEEPROM(i + 1);
      }
    }
  else
    {
      uint8_t temp = EEPROM.read(eeaddress);
      for ( i = eeaddress; ((temp!= 0x00)&&(temp<0x7E)&&(temp>0x1F)&&((i - eeaddress)<buffer_length)); i++) 
      {
        buffer[i - eeaddress] = EEPROM.read(i);
        temp = EEPROM.read(i + 1);
      }
    }
  buffer[i - eeaddress] = 0x00; 
  return buffer;
}

boolean SCKBase::checkRTC() {
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00); //Address
  Wire.endTransmission();
  delay(4);
  Wire.requestFrom(RTC_ADDRESS,1);
  unsigned long time = millis();
  while (!Wire.available()) if ((millis() - time)>500) return false;
  Wire.read();
  return true;
}

boolean SCKBase::RTCadjust(char *time) {    
  byte rtc[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  byte count = 0x00;
  byte data_count=0;
  while (time[count]!=0x00)
  {
    if(time[count] == '-') data_count++;
    else if(time[count] == ' ') data_count++;
    else if(time[count] == ':') data_count++;
    else if ((time[count] >= '0')&&(time[count] <= '9'))
    { 
      rtc[data_count] =(rtc[data_count]<<4)|(0x0F&time[count]);
    }  
    else break;
    count++;
  }  
  if (data_count == 5)
  {
#if F_CPU == 8000000 
    Wire.beginTransmission(RTC_ADDRESS);
    Wire.write((int)0);
    Wire.write(rtc[5]);
    Wire.write(rtc[4]);
    Wire.write(rtc[3]);
    Wire.write(0x00);
    Wire.write(rtc[2]);
    Wire.write(rtc[1]);
    Wire.write(rtc[0]);
    Wire.endTransmission();
    delay(4);
    Wire.beginTransmission(RTC_ADDRESS);
    Wire.write(0x0E); //Address
    Wire.write(0x00); //Value
    Wire.endTransmission();
#else
    Wire.beginTransmission(RTC_ADDRESS);
    Wire.write((int)0);
    Wire.write(rtc[5]);
    Wire.write(rtc[4]);
    Wire.write(rtc[3]);
    Wire.write(0x00);
    Wire.write(rtc[2]);
    Wire.write(rtc[1]);
    Wire.write(rtc[0]);
    Wire.write((int)0);
    Wire.endTransmission();
    return true;
#endif
    return true;
  }
  return false;  
}

boolean SCKBase::RTCtime(char *time) {
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write((int)0);	
  Wire.endTransmission();
  Wire.requestFrom(RTC_ADDRESS, 7);
  uint8_t seconds = (Wire.read() & 0x7F);
  uint8_t minutes = Wire.read();
  uint8_t hours = Wire.read();
  Wire.read();
  uint8_t day = Wire.read();
  uint8_t month = Wire.read();
  uint8_t year = Wire.read();
  time[0] = '2';
  time[1] = '0';
  time[2] = (year>>4) + '0';
  time[3] = (year&0x0F) + '0';
  time[4] = '-';
  time[5] = (month>>4) + '0';
  time[6] = (month&0x0F) + '0';
  time[7] = '-';
  time[8] = (day>>4) + '0';
  time[9] = (day&0x0F) + '0';
  time[10] = ' ';
  time[11] = (hours>>4) + '0';
  time[12] = (hours&0x0F) + '0';
  time[13] = ':';
  time[14] = (minutes>>4) + '0';
  time[15] = (minutes&0x0F) + '0';
  time[16] = ':';
  time[17] = (seconds>>4) + '0';
  time[18] = (seconds&0x0F) + '0';
  time[19] = 0x00;
  return true;
}

boolean SCKBase::RTCisValid(char *time) {
  RTCtime(time);
  //If year is 2016 we consider rtc data to ba a valid date (without update RTC starts in year 2000)
  if (time[0] == '2' && time[1] == '0' && time[2] == '1' && time[3] == '6') return true;
  return false;
}

uint16_t SCKBase::getPanel(float Vref){
#if F_CPU == 8000000 
  uint16_t value = 11*average(PANEL)*Vref/1023.;
  if (value > 500) value = value + 120; //Voltage protection diode
  else value = 0;
#else
  uint16_t value = 3*average(PANEL)*Vref/1023.;
  if (value > 500) value = value + 750; //Voltage protection diode
  else value = 0;
#endif
#if debugBASE
  Serial.print("Panel = ");
  Serial.print(value);
  Serial.println(" mV");
#endif
  return value;
}

const uint16_t batTable[] = {
  3078,
  3364,
  3468,
  3540,
  3600,
  3641,
  3682,
  3701,
  3710,
  3716,
  3716,
  3716,
  3720,
  3714,
  3720,
  3725,
  3732,
  3742,
  3739,
  3744,
  3744,
  3754,
  3760,
  3762,
  3770,
  3768,
  3774,
  3774,
  3774,
  3779,
  3784,
  3790,
  3788,
  3794,
  3798,
  3798,
  3804,
  3809,
  3809,
  3812,
  3817,
  3817,
  3822,
  3823,
  3828,
  3828,
  3828,
  3833,
  3838,
  3838,
  3842,
  3847,
  3852,
  3859,
  3858,
  3864,
  3862,
  3869,
  3877,
  3877,
  3883,
  3888,
  3894,
  3898,
  3902,
  3906,
  3912,
  3923,
  3926,
  3936,
  3942,
  3946,
  3960,
  3972,
  3979,
  3982,
  3991,
  3997,
  4002,
  4002,
  4012,
  4018,
  4028,
  4043,
  4057,
  4074,
  4084,
  4094,
  4098,
  4098,
  4109,
  4115,
  4123,
  4134,
  4142,
  4153,
  4158,
  4170,
  4180,
  4188
};

uint16_t SCKBase::getBattery(float Vref) {
  uint16_t temp = average(BAT);
#if F_CPU == 8000000 
  float voltage = Vref*temp/1023.;
  voltage = voltage + (voltage/180)*100;
#else
  float voltage = Vref*temp/1023.;
#endif
  uint16_t percent = 1000;
  for(uint16_t i = 0; i < 100; i++) {
    if(voltage < batTable[i]) {
      percent = i * 10;
      break;
    }
  }
  if(percent < 10) percent = 10;
#if debugBASE
  Serial.print("Vbat: ");
  Serial.print(voltage);
  Serial.print(" mV, ");
  Serial.print("Battery level: ");
  Serial.print(percent/10);
  Serial.println(" %");
#endif
  return percent;
}

boolean SCKBase::findInResponse(const char *toMatch,
unsigned int timeOut = 1000) {
  int byteRead;

  unsigned long timeOutTarget; // in milliseconds

  for (unsigned int offset = 0; offset < strlen(toMatch); offset++) {
    timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping
    while (!Serial1.available()) {
      // Wait, with optional time out.
      if (timeOut > 0) {
        if (millis() > timeOutTarget) {
          return false;
        }
      }
      delay(1); // This seems to improve reliability slightly
    }
    byteRead = Serial1.read();
    //Serial.print((char)byteRead);
    delay(1); // Removing logging may affect timing slightly

    if (byteRead != toMatch[offset]) {
      offset = 0;
      // Ignore character read if it's not a match for the start of the string
      if (byteRead != toMatch[offset]) {
        offset = -1;
      }
      continue;
    }
  }

  return true;
}

void SCKBase::skipRemainderOfResponse(unsigned int timeOut) {
  unsigned long time = millis();
  while (((millis()-time)<timeOut))
  {
    if (Serial1.available())
    { 
      byte temp = Serial1.read();
      //Serial.write(temp);
      time = millis();
    }
  }
}

boolean SCKBase::sendCommand(const __FlashStringHelper *command,
boolean isMultipartCommand = false,
const char *expectedResponse = "AOK") {
  Serial1.print(command);
  delay(20);
  if (!isMultipartCommand) {
    Serial1.flush();
    Serial1.println();

    // TODO: Handle other responses
    //       (e.g. autoconnect message before it's turned off,
    //        DHCP messages, and/or ERR etc)
    if (!findInResponse(expectedResponse, 3000)) {
      return false;
    }
    //findInResponse(expectedResponse);
  }
  return true;
}

boolean SCKBase::sendCommand(const char *command,
boolean isMultipartCommand = false,
const char *expectedResponse = "AOK") {
  Serial1.print(command);
  delay(20);
  if (!isMultipartCommand) {
    Serial1.flush();
    Serial1.println();

    // TODO: Handle other responses
    //       (e.g. autoconnect message before it's turned off,
    //        DHCP messages, and/or ERR etc)
    if (!findInResponse(expectedResponse, 3000)) {
      return false;
    }
    //findInResponse(expectedResponse);
  }
  return true;
}

#define COMMAND_MODE_ENTER_RETRY_ATTEMPTS 2

#define COMMAND_MODE_GUARD_TIME 250 // in milliseconds

boolean SCKBase::enterCommandMode() {
  for (int retryCount = 0; retryCount < COMMAND_MODE_ENTER_RETRY_ATTEMPTS; retryCount++) 
  {
    delay(COMMAND_MODE_GUARD_TIME);
    Serial1.print(F("$$$"));
    delay(COMMAND_MODE_GUARD_TIME);
    Serial1.println();
    Serial1.println();
    if (findInResponse("\r\n<", 1000))
    {
      return true;
    }
  }
  return false;
}


boolean SCKBase::sleep() {
  enterCommandMode();
  sendCommand(F("sleep"));
}

boolean SCKBase::reset() {
  enterCommandMode();
  sendCommand(F("factory R"), false, "Set Factory Defaults"); // Store settings
  sendCommand(F("save"), false, "Storing in config"); // Store settings
  sendCommand(F("reboot"), false, "*READY*");
}

boolean SCKBase::exitCommandMode() {
  for (int retryCount = 0; retryCount < COMMAND_MODE_ENTER_RETRY_ATTEMPTS; retryCount++) 
  {
    if (sendCommand(F("exit"), false, "EXIT")) 
    {
      return true;
    }
  }
  return false;
}

boolean SCKBase::connect()
{
  if (!ready())
  {
    if (readData(EE_ADDR_NUMBER_NETS, INTERNAL)<1) return false;
    if(enterCommandMode())
    {    
      sendCommand(F("set comm remote 0")); // FFR Hide Hello message
      sendCommand(F("set wlan join 1")); // Disable AP mode
      sendCommand(F("set ip dhcp 1")); // Enable DHCP server
      sendCommand(F("set ip proto 10")); //TCP mode and HTML mode
      sendCommand(F(DEFAULT_WIFLY_FTP_UPDATE)); //ftp server update
      sendCommand(F("set ftp mode 1"));
      char* auth;
      char* ssid;
      char* pass;
      char* antenna;
      for (uint16_t nets = 0  ; nets < readData(EE_ADDR_NUMBER_NETS, INTERNAL); nets++) {
        auth = readData(DEFAULT_ADDR_AUTH, nets, INTERNAL);
        sendCommand(F("set wlan auth "), true);
        sendCommand(auth);
        boolean mode = true;
        if ((auth==WEP)||(auth==WEP64)) mode=false;
        ssid = readData(DEFAULT_ADDR_SSID, nets, INTERNAL);
        sendCommand(F("set wlan ssid "), true);
        sendCommand(ssid);
        pass = readData(DEFAULT_ADDR_PASS, nets, INTERNAL);
        if (mode) sendCommand(F("set wlan phrase "), true);  // WPA1, WPA2, OPEN
        else sendCommand(F("set wlan key "), true);
        sendCommand(pass);
        antenna = readData(DEFAULT_ADDR_ANTENNA, nets, INTERNAL);
        sendCommand(F("set wlan ext_antenna "), true);
        sendCommand(antenna);
        sendCommand(F("save"), false, "Storing in config"); // Store settings
        sendCommand(F("reboot"), false, "*READY*");
        if (ready()) return true;
        enterCommandMode();
      }    
    } 
    return false;
  }
  else return true;  
}  

void SCKBase::APmode(char* ssid)
{
  if (enterCommandMode())
  {    
    sendCommand(F("set wlan join 7")); // Enable AP mode
    //sendCommand(F("set wlan channel <value> // Specify the channel to create network
    sendCommand(F("set wlan ssid "), true); // Set up network broadcast SSID
    sendCommand(ssid);

    buffer[6] = 0x00;
    sendCommand(F("set opt device_id "), true); // Set up network broadcast SSID
    sendCommand(ssid);

    sendCommand(F("set ip dhcp 4")); // Enable DHCP server
    sendCommand(F("set ip address 1.2.3.4")); // Specify the IP address
    sendCommand(F("set ip net 255.255.255.0")); // Specify the subnet mask
    sendCommand(F("set ip gateway 1.2.3.4")); // Specify the gateway
    sendCommand(F("save"), false, "Storing in config"); // Store settings
    sendCommand(F("reboot"), false, "*READY*"); // Reboot the module in AP mode
  }
} 

boolean SCKBase::ready()
{
  if(!enterCommandMode())
  {
    repair();
    return(false);
  }
  else
  {
    Serial1.println(F("join"));
    if (findInResponse("Associated!", 8000)) 
    {
      skipRemainderOfResponse(3000);
      exitCommandMode();
      return(true);
    }
  } 
 
}

boolean connected = false;

boolean SCKBase::open(const char *addr, int port) {

  if (connected) {
    close();
  } 
  if (enterCommandMode())
  {
    sendCommand(F("open "), true);
    sendCommand(addr, true);
    Serial1.print(F(" "));
    Serial1.print(port);
    if (sendCommand("", false, "*OPEN*")) 
    {
      connected = true;
      return true;
    }
    else return false;
  }
  enterCommandMode();
  return false;
}

boolean SCKBase::close() {
  if (!connected) {
    return true;
  }
  if (sendCommand(F("close"), false, "*CLOS*")) {
    connected = false;
    return true;
  }
  connected = false;
  return false;
}

#define MAC_ADDRESS_BUFFER_SIZE 18 // "FF:FF:FF:FF:FF:FF\0"

char* SCKBase::MAC() {
  if (enterCommandMode()) 
  {
    if (sendCommand(F("get mac"), false, "Mac Addr="))
    {
      char newChar;
      byte offset = 0;

      while (offset < MAC_ADDRESS_BUFFER_SIZE) {
        if (Serial1.available())
        {
          newChar = Serial1.read();
          if ((newChar == '\n')||(newChar < '0')) {
            buffer[offset] = '\x00';
            return buffer;
          } 
          else if (newChar != -1) {
            buffer[offset] = newChar;
            offset++;
          }
        }
      }
      buffer[MAC_ADDRESS_BUFFER_SIZE-1] = '\x00';
      exitCommandMode();
    }        
  }
  return "-1";
}

char* SCKBase::id() {
  char* temp = MAC();  
  byte len = strlen(temp);
  byte j = 4;
  buffer[0] = 'S';
  buffer[1] = 'C';
  buffer[2] = 'K';
  buffer[3] = '_';
  for(byte i=12; i<len; i++)
  {
    if (temp[i] == ':') buffer[j] = '-';
    else buffer[j] = temp[i];
    j++;
  }
  buffer[j] = 0x00;
  return buffer;
}


#define SCAN_BUFFER_SIZE 4 

uint32_t SCKBase::scan() {
  if (enterCommandMode()) 
  {
    if (sendCommand(F("scan"), false, "Found "))
    {
      char newChar;
      byte offset = 0;

      while (offset < SCAN_BUFFER_SIZE) {
        if (Serial1.available())
        {
          newChar = Serial1.read();
          if ((newChar == '\r')||(newChar < '0')) {
            buffer[offset] = '\x00';
            break;
          } 
          else if (newChar != -1) {
            buffer[offset] = newChar;
            offset++;
          }
        }
      }
      buffer[SCAN_BUFFER_SIZE-1] = '\x00';
      findInResponse("END:\r\n", 2000);
      exitCommandMode();
    }        
  }
  return atol(buffer);
} 

int SCKBase::checkWiFly() {
  int ver = getWiFlyVersion();
  if (ver > 0)
  {
    if (ver < WIFLY_LATEST_VERSION)
     {
      byte state = 1;
      if(update()); //Wifly Updated.
      else state = 2; //Update Fail.
      reset();
      return state;
     }   
    else return 0; //WiFly up to date.
  }
  else return -1; //Error reading the wifi version.
}

int SCKBase::getWiFlyVersion() {
  if (enterCommandMode()) 
  {
    if (sendCommand(F("ver"), false, "wifly-GSX Ver"))
    {
      char newChar;
      byte offset = 0;
      boolean prevWasNumber = false;
      while (offset < 3) {
        if (Serial1.available())
        {
          newChar = Serial1.read();
          if ((newChar != -1 && isdigit(newChar)) || newChar == '.') {
            if (newChar != '.') {
              buffer[offset] = newChar;
              offset++;
            }
            prevWasNumber = true;
          } 
          else {
            if (prevWasNumber){
              break;
            }
            prevWasNumber = false; 
          }
        }
      }
      exitCommandMode();
      buffer[offset] = 0x00;
     return atoi(buffer);
    } 
    return 0;
  }
  return 0;
}


boolean SCKBase::update() {
  if (enterCommandMode())
  {
    sendCommand(F(DEFAULT_WIFLY_FIRMWARE));
    delay(1000);
    if (findInResponse("FTP OK.", 60000))
    {
      return true;
    }
  }
  else return false;
}

uint32_t baud[7]={
  2400, 4800, 9600, 19200, 38400, 57600, 115200};

void SCKBase::repair()
{
  if(!enterCommandMode())
  {
    boolean repair = true;
    for (int i=6; ((i>=0)&&repair); i--)
    {
      Serial1.begin(baud[i]);
      if(enterCommandMode()) 
      {
        reset();
        repair = false;
      }
      Serial1.begin(9600);
    }
  }
}

/*TIMER*/

#define RESOLUTION 65536    // Timer1 is 16 bit
unsigned int pwmPeriod;
unsigned char clockSelectBits;
char oldSREG;					// To hold Status 

void SCKBase::timer1SetPeriod(long microseconds)		// AR modified for atomic access
{

  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum

  oldSREG = SREG;				
  cli();							// Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;

  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

void SCKBase::timer1Initialize()
{
  TCCR1A = 0;                 // clear control register A 
  TCCR1B = _BV(WGM13);        // set mode 8: phase and frequency correct pwm, stop the timer
  timer1SetPeriod(1500); 
  TIMSK1 = _BV(TOIE1);                                  
}

void SCKBase::timer1Stop()
{
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));          // clears all clock selects bits
  TIMSK1 &= ~(_BV(TOIE1)); 
  
}












