/*******************************************************************************
    PocketScreen "Create WiFi Access Point" Example
    written by Florian Keller
    last changed 30 Nov 20

    Automatically creates a WiFi access point with the given name and password.
*******************************************************************************/

// WiFi name and password
#define WIFI_NAME "PocketScreenTestWiFi"
#define WIFI_PASSWORD "12345678"

// include libraries
#include <PocketScreen.h>
#include <stdarg.h>

// create a character buffer where the text response coming from the ESP gets stored
#define ANSWER_BUFFER_SIZE 128
char answerBuffer[ANSWER_BUFFER_SIZE];

void setup() {
    // wait a bit
    delay(2000);
    
    // enable ESP
    pinMode(PIN_ESP_ENABLE, OUTPUT);
    digitalWrite(PIN_ESP_ENABLE, HIGH);

    // open serial monitor
    // don't forget to set your serial monitor baud rate to 115200, too!
    SerialUSB.begin(115200);
    while (!SerialUSB);
    SerialUSB.println("SerialUSB here.");

    // open serial communication to ESP
    SerialESP.begin(115200);
    while (!SerialESP);
    SerialUSB.println("ESP Serial open.");

    // begin talking - send 'AT', wait for 'OK'
    int tries = 5, i;
    for (i = 0; i < tries; i++) {
        sendATCommand("AT", 0);
        if (waitForATAnswer("OK", 2000))
            break;
    }
    if (i == tries) {
        SerialUSB.println("Timeout when talking to the ESP.");
        return;
    }

    // set wifi mode. answer is either 'OK' or 'no change'
    sendATCommand("AT+CWMODE=3", 0);
    if (!waitForATAnswer("OK", "no change", 2000)) {
        SerialUSB.println("Failed to set WiFi mode.");
        return;
    }

    // set name, password, channel and encryption type
    sendATCommand("AT+CWSAP=\"" WIFI_NAME "\",\"" WIFI_PASSWORD "\",1,4", 0);
    if (!waitForATAnswer("OK", 2000)) {
        SerialUSB.println("Failed to set WiFi name and password.");
        return;
    }
}

// argument list has to end with 0
void sendATCommand(char* command, ...) {
    char *p = (char*) command;
    va_list argptr;

    // clear serial buffer
    while (SerialESP.available() > 0)
        SerialESP.read();
    
    va_start(argptr, command);

    // print to PC serial, too
    SerialUSB.print(millis());
    SerialUSB.print(": >>> '");

    // send everything to the ESP and PC
    while (p) {
        SerialESP.write(p);
        SerialUSB.print(p);
        p = va_arg(argptr, char*);
    }
    
    SerialUSB.println("'");
    
    va_end(argptr);

    // CR and LF mark the end of the command
    SerialESP.write("\r\n");
}

boolean waitForATAnswer(char* expectedAnswer, int timeOut) {
    return waitForATAnswer(expectedAnswer, NULL, timeOut);
}

boolean waitForATAnswer(char* expectedAnswer1, char* expectedAnswer2, int timeOut) {
    // buffer character
    uint8_t b;
    
    int i = 0;
    long start = millis();

    while (millis() - start <= timeOut) {
        if (SerialESP.available()) {
            // read next character
            b = SerialESP.read();

            // ignore LF
            if (b == '\n')
                continue;

            // end at CR
            if (b == '\r') {
                answerBuffer[i] = '\0';

                // send timestamp and text to serial monitor
                SerialUSB.print(millis());
                SerialUSB.print(": <<< '");
                SerialUSB.print(answerBuffer);
                SerialUSB.println("'");

                // compare with expected answers
                if (strcmp(answerBuffer, expectedAnswer1) == 0)
                    return 1;
                if (expectedAnswer2 != NULL && strcmp(answerBuffer, expectedAnswer2) == 0)
                    return 1;
                i = 0;
                continue;
            }

            // put into buffer
            answerBuffer[i] = b;

            // end when reaching answer buffer limit
            i += 1;
            if (i == ANSWER_BUFFER_SIZE - 1) {
                answerBuffer[i] = '\0';
                return 1;
            }
        }
    }
    
    return 0;
}

void loop() {
    // send any further text coming from the ESP to USB serial...
    while (SerialESP.available()) {
        SerialUSB.write((char) SerialESP.read());
    }

    // ...and vice versa
    while (SerialUSB.available()) {
        SerialESP.write((char) SerialUSB.read());
    }
    
    delay(10);
}
