this is using the mbed os version 5-13-1

Dependencies:   mbed-http

source/WiFiManager.cpp

Committer:
ocomeni
Date:
2019-07-19
Branch:
PassingRegression
Revision:
129:590bdc2dcf5b
Parent:
127:a21788227ca6

File content as of revision 129:590bdc2dcf5b:

#include "debug.h"
#include "WiFiManager.h"
#include "common_config.h"
#define FILE_CODE       "wifi"
#define USE_EVENTS_FOR_HTTPS_REQUESTS

WiFiManager::WiFiManager(wifi_config_t *wifi_config, WiFiInterface *wifi, 
                         internet_config_t *internet_config, 
                         events::EventQueue &event_queue, 
                         MemoryPool<wifi_cmd_message_t, 16> *aT2WiFimPool, 
                         Queue<wifi_cmd_message_t, 16> *aT2WiFiCmdQueue, 
                         MemoryPool<at_resp_message_t, 16> *wiFi2ATmPool, 
                         Queue<at_resp_message_t, 16> *wiFi2ATCmdQueue, 
                         MemoryPool<wifi_data_msg_t, PQDSZ> *aT2WiFiDatamPool, 
                         Queue<wifi_data_msg_t, PQDSZ> *aT2WiFiDataQueue, 
                         MemoryPool<at_data_msg_t, PQDSZ> *wiFi2ATDatamPool, 
                         Queue<at_data_msg_t, PQDSZ> *wiFi2ATDataQueue) 
:
     wifi_config(wifi_config),
     network(wifi),
     internet_config(internet_config),
    _event_queue(event_queue),
    _aT2WiFimPool(aT2WiFimPool),
    _aT2WiFiCmdQueue(aT2WiFiCmdQueue),
    
    _wiFi2ATmPool(wiFi2ATmPool),
    _wiFi2ATCmdQueue(wiFi2ATCmdQueue),
    
    _aT2WiFiDatamPool(aT2WiFiDatamPool),
    _aT2WiFiDataQueue(aT2WiFiDataQueue),
    
    _wiFi2ATDatamPool(wiFi2ATDatamPool),
    _wiFi2ATDataQueue(wiFi2ATDataQueue)

{
    lastScanCount = 0;
    wifiCmd = WIFI_CMD_NONE;
    //internet_config.connectionScheme = ALWAYS_CONNECTED; // set default connection scheme
    is_connected = false;
    http_response = NULL;
    chunkNum = 0;
    socket = NULL;
    responseString = NULL;
    responseBytes = NULL;
    at_data_resp = NULL;
    https_connection_active = false;
    use_full_hostname       = false;
    wifiBusy = 0;
    wifiWatchdogTimer.start();
    watchdogCnt = 0;
    //_event_queue.call_every(10000, this, &WiFiManager::callWifiWatchDog);
    //keep_alive_id = _event_queue.call_every(CLOUD_KEEP_ALIVE_INTERVAL, this, &WiFiManager::callInternetKeepAlive);
    keep_alive_id = 0;
    https_token_valid = false;
    token_refresh_count = 0;
    //watchDogTick.attach(callback(this, &WiFiManager::callWifiWatchDogIsr), 10.0); // call flip function every 10 seconds
}

WiFiManager::~WiFiManager()
{
    delete network;
    wifiWatchdogTimer.stop();
    socket->close();
    delete socket;
    free(aws_id_token);
    free(aws_refresh_token);    
}
//#define DISABLE_WATCHDOG

void WiFiManager::callWifiWatchDogIsr()
{
    _event_queue.call_in(10, this, &WiFiManager::callWifiWatchDog);    
}
void WiFiManager::callWifiWatchDog()
{
#ifdef DISABLE_WATCHDOG
    return;
#else
    static int inactivity_monitor = 0;
    watchdogCnt++;
    if(watchdogCnt >= 6 && outputBuffersAvailable()) // every minute
    {
        char * respStr = (char *) malloc(120);
        sprintf(responseString, "\r\n[WiFi-MAN] WiFi Manager Alive : state = %d busy = %d httpsConnActive = %d\r\n",
                                wifiCmd, wifiBusy, https_connection_active);
        sendThreadATresponseString(respStr, WIFI_WATCH_DOG);
        watchdogCnt = 0;
    }
    else if(wifiWatchdogTimer.read() > 30 && responseString==NULL)
    {
        if(wifiCmd == WIFI_CMD_NONE)
            inactivity_monitor++;
        char * respStr = (char *) malloc(120);
        sprintf(responseString, "\r\n[WiFi-MAN] Main Loop InActive : state = %d busy = %d httpsConnActive = %d\r\n", 
                                 wifiCmd, wifiBusy, https_connection_active);
        sendThreadATresponseString(respStr, WIFI_WATCH_DOG);
        if(inactivity_monitor >= 3)
        {
            free_DataMsg();
            inactivity_monitor = 0;
        }
    }
#endif    
}

void WiFiManager::callInternetKeepAlive()
{
    if(https_connection_active)
    {
        setNextCommand(WIFI_CMD_INTERNET_KEEP_ALIVE);
    }
    else
    {
        setNextCommand(WIFI_CMD_TLS_CONNECT);
    }
}


void WiFiManager::keepSocketAlive()
{
    // Send data
    nsapi_size_or_error_t error;
    //serr = socket->send("GET /nudgebox/v1 HTTP/1.0\r\nHost: https://dev2.dnanudge.io\r\n\r\n", 18);
    dbg_printf(LOG, "\n[WIFI MAN] KEEP ALIVE SERVER REQUEST\r\n");
    char *httpsReq = new char[KEEPALIVE_MSG_SIZE];
    sprintf(httpsReq,"%s\r\nAuthorization: %s\r\n\r\n", KEEPALIVE_MSG_HDR, aws_id_token);
    int hdrlen= strlen(httpsReq);
    dbg_printf(LOG, "\n[WIFI MAN] KEEP ALIVE MSG [len = %d]\r\n%s", hdrlen, httpsReq);
    memcpy(&httpsReq[hdrlen], KEEPALIVE_MSG_BDY,sizeof(KEEPALIVE_MSG_BDY));
    error = socket->send(httpsReq, (hdrlen+sizeof(KEEPALIVE_MSG_BDY)));
    
    if(error < 0)
    {
       queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED);
       https_connection_active = false;
       socket->close();
       delete socket;
       socket = NULL;
       return;
    }
    
    // Receive data
    char buf[500];
    error = socket->recv(buf, 500);
    if(error >= 0 && strstr(buf, "HTTP/1.1 200")!= NULL) // received HTTP 200 OK status
    {
        dbg_printf(LOG, "\n[WIFI MAN] KEEP ALIVE SERVER RESPONSE: \r\n %s\r\n", buf);
        queueATresponse(AT_SOCKET_KEEP_ALIVE_OK);
        https_connection_active = true;
    }
    else
    {
       queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED);
       https_connection_active = false;
       socket->close();
       delete socket;
       socket = NULL;
    }
    delete httpsReq;
}

void WiFiManager::CreateTokenHttpsRequest(char * httpsReq)
{
    char *httpsBody = new char[200];
    sprintf(httpsBody,"{\r\n\"AuthParameters\" : {\r\n"
                     "\"USERNAME\" : \"%s\",\r\n\"PASSWORD\" : \"%s\"\r\n},\r\n"
                     "\"AuthFlow\" : \"%s\",\r\n"
                     "\"ClientId\" : \"%s\"\r\n}", UserName, Password, AuthFlow, ClientId);
    int bodyLen = strlen(httpsBody);
    sprintf(httpsReq,"%s\r\ncontent-length: %d"
                     "\r\n\r\n%s", TOKEN_REQ_HDR, bodyLen, httpsBody);
    dbg_printf(LOG, "\n[WIFI MAN] Cloud Access Token REQUEST:\r\n%s\r\n", httpsReq);
    delete httpsBody;
}

void WiFiManager::GetCloudAccessToken()
{
    int start = Kernel::get_ms_count();
    // Send data
    nsapi_size_or_error_t error;
    dbg_printf(LOG, "\n[WIFI MAN] Get Cloud Access Token REQUEST\r\n");
    // first free up access token memory to avoid leak
    freeAccessTokenMemory();
    char *httpsReq = new char[500];
    httpsReq[0] = NULL;
    CreateTokenHttpsRequest(httpsReq);
    if(strlen(httpsReq) == 0)
    {
       queueATresponse(AT_ACCESS_TOKEN_FAILED);
       return;
    }
    error = socket->send(httpsReq, strlen(httpsReq)+1);
    delete httpsReq;
    if(error < 0)
    {
       queueATresponse(AT_ACCESS_TOKEN_FAILED);
       return;
    }
    
    // Receive data
    // reserve large buffer from heap to hold response
    char *respBuf = new char[TOKEN_RESPONSE_SIZE]; 
    error = socket->recv(respBuf, TOKEN_RESPONSE_SIZE);
    if(error >= 0 && strstr(respBuf, "HTTP/1.1 200")!= NULL) // received HTTP 200 OK status
    {
        dbg_printf(LOG, "\n[WIFI MAN] ACCESS TOKEN RESPONSE: \r\n %s\r\n", respBuf);
        // extract ID TOKEN    
        char *sp1 = strstr(respBuf,ID_TOKEN_STR_START);   
        char *sp2 = strstr(sp1+strlen(ID_TOKEN_STR_START),ACCESS_TOKEN_STR_END);  
        int tokenLen = sp2-sp1-(strlen(ID_TOKEN_STR_START));
        // reserve memomry on the heap for id token
        aws_id_token      = new char[tokenLen+1]; 
        strncpy(aws_id_token, sp1+(strlen(ID_TOKEN_STR_START)), tokenLen);
        dbg_printf(LOG, "\n[WIFI MAN] Token Length: %d \r\n IdToken: \r\n %s\r\n", tokenLen, aws_id_token);
#ifdef EXTRACT_REFRESH_TOKEN
        // extract Refresh TOKEN    
        sp1 = strstr(respBuf,REFRESH_TOKEN_STR_START);   
        sp2 = strstr(sp1+strlen(REFRESH_TOKEN_STR_START),ACCESS_TOKEN_STR_END);  
        tokenLen = sp2-sp1-(strlen(REFRESH_TOKEN_STR_START));
        // reserve memomry on the heap for refresh token
        aws_refresh_token      = new char[tokenLen+1]; 
        strncpy(aws_refresh_token, sp1+(strlen(REFRESH_TOKEN_STR_START)), tokenLen);
        dbg_printf(LOG, "\n[WIFI MAN] Token Length: %d \r\nRefreshToken: \r\n %s\r\n", tokenLen, aws_refresh_token);  
#endif     
        queueATresponse(AT_ACCESS_TOKEN_SUCCESS);
        token_refresh_count++;
        //https_connection_active = true;
        https_token_valid = true;
        // schedule the invalidation of the token for 59 minutes time
        _event_queue.call_in(TOKEN_VALID_PERIOD_MS, this, &WiFiManager::invalidateAccessToken);
    }
    else
    {
        dbg_printf(LOG, "\n[WIFI MAN] Failure Response: \r\n %s\r\n", respBuf);  
        queueATresponse(AT_ACCESS_TOKEN_FAILED);
       //https_connection_active = false;
    }
    delete respBuf;
    int elapsed_ms = Kernel::get_ms_count() - start;
    dbg_printf(LOG, "\n[WIFI MAN] Access token Acquisition::\r\n Time Elapsed : %ld ms\r\n", elapsed_ms);  
    socket->close();
    delete socket;
    socket = NULL;
}

void WiFiManager::invalidateAccessToken()
{
    https_token_valid = false;
}

void WiFiManager::freeAccessTokenMemory()
{
    free(aws_id_token);
    aws_id_token = NULL;
#ifdef EXTRACT_REFRESH_TOKEN
    free(aws_refresh_token);
    aws_refresh_token = NULL;
#endif
}
void  WiFiManager::sendThreadATresponseString(const char * buf, at_cmd_resp_t at_cmd)
{
    if(at_data_resp != NULL) return;
    int strLen = strlen(buf) + 1;
    at_data_resp = new at_data_msg_t;
    // set string length 
    at_data_resp->dataLen = strLen;
    memcpy(at_data_resp->buffer, buf, strLen);
    // package and send on wifi data queue    
    at_data_resp->at_resp = at_cmd;
    bool queueResult = true;
    int wait_count = 0;
    do
    {
        if(!queueResult){
            wait_count+=10;
            dbg_printf(LOG, "ATCMD Queue full waiting %d ms so far...\n", wait_count);
            wait_ms(10);
        }
        queueResult = queueWiFiDataResponse(*at_data_resp);
    }while(queueResult == false && wait_count<QUEUE_WAIT_TIMEOUT_MS);
    delete at_data_resp;
    at_data_resp = NULL;
}


bool WiFiManager::outputBuffersAvailable()
{
    int timeout = 0;
    while(timeout < 100)
    {
        if(responseBytes==NULL && responseString==NULL && at_data_resp==NULL)
        {
            return true;
        }
        else
        {
            timeout += 10;
            wait_ms(10);
        }
    }
    if(responseBytes==NULL && responseString==NULL && at_data_resp==NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}


bool WiFiManager::queueATresponse(at_cmd_resp_t resp){
#ifndef USE_MALLOC_FOR_COMMAND_MEMORY_POOL
    at_resp_message_t *atResp  = _wiFi2ATmPool->alloc();
#else
    at_resp_message_t *atResp  = (at_resp_message_t *) malloc(sizeof(at_resp_message_t));
#endif
    if(atResp == NULL) return false; // queue full;
    atResp->at_resp            = resp;
    _wiFi2ATCmdQueue->put(atResp);
    return true;
}


bool WiFiManager::queueWiFiDataResponse(at_data_msg_t at_resp){
    at_data_msg_t *atData = _wiFi2ATDatamPool->alloc();
    if(atData == NULL) return false; // queue full;
    atData->at_resp        = at_resp.at_resp;
    atData->dataLen        = at_resp.dataLen;
    memcpy(atData->buffer, at_resp.buffer, at_resp.dataLen);
    _wiFi2ATDataQueue->put(atData);
    dbg_printf(LOG, "[WIFI MAN] queued data size = %d : at_resp = %d\n", at_resp.dataLen, at_resp.at_resp);
    return true;
}

void WiFiManager::getWiFiInstance()
{
    network = WiFiInterface::get_default_instance();
    if (!network) {
        dbg_printf(LOG, "ERROR: No WiFiInterface found.\n");
    }
}

void WiFiManager::runMain(){
    nsapi_error_t error;
    bool result;
    dbg_printf(LOG, "\r\n [WIFI MAN]  Thread Id = %X\r\n", (uint32_t)ThisThread::get_id());
    while(true){
        dequeueWiFiCommands();
        dequeueATdataResponse();
        wifiWatchdogTimer.reset();
        switch(wifiCmd){
            case WIFI_CMD_NONE:
                // IDLE STATE
                break;
            case WIFI_CMD_SCAN:
                wifiBusy = 1;
                error = scanNetworks();
                wifiCmd = WIFI_CMD_NONE;
                queueATresponse(AT_SCAN_RESP);
                wifiBusy = 0;
                break;
            case WIFI_CMD_DETAILED_SCAN:
            {
                wifiBusy = 1;
                nsapi_size_or_error_t cnt_err;
                cnt_err = getAvailableAPs(lastScanCount);
                wifiCmd = WIFI_CMD_NONE;
                if(cnt_err >= 0)
                {
                    queueATresponse(AT_DETAILED_SCAN_RESP);
                }
                wifiBusy = 0;
                break;
            }
            case WIFI_CMD_CONNECT:
            {
                if(is_connected) // already connected
                {
                    wifiCmd = WIFI_CMD_NONE;
                    break;
                }
                wifiBusy = 1;
                error = connect();
                int secCount = 0;
                while(secCount++ < WIFI_CONNECT_TIMEOUT_SECS && is_connected==false){
                    wait(1); // wait 1 sec
                }
                wifiCmd = WIFI_CMD_NONE;
                if(is_connected==false){
                    if(outputBuffersAvailable() == false) // first free it
                    {
                        free(responseString);
                    }
                    dbg_printf(LOG, "[WIFI MAN] +++ WIFI CONNECTION TIMEOUT +++ \r\n");
                    //queueATresponse(AT_COMMAND_FAILED);
                    responseString = (char *) malloc(100);
                    sprintf(responseString, "\r\n+UUTIMEOUT\r\n");
                    sendATresponseString(AT_COMMAND_FAILED);
                }
                else {
                    sendATresponseString(AT_CONNECT_RESP);
                }
                wifiBusy = 0;
                break;
            }
            case WIFI_CMD_DISCONNECT:
            {
                if(!is_connected) // already disconnected
                {
                    wifiCmd = WIFI_CMD_NONE;
                    break;
                }
                wifiBusy = 1;
                error = disconnect();
                wifiCmd = WIFI_CMD_NONE;
                if(error >= 0)
                {
                    int secCount = 0;
                    while(secCount++ < WIFI_CONNECT_TIMEOUT_SECS && is_connected==true){
                        wait(1); // wait 1 sec
                    }
                    if(!is_connected)
                    {
                        sendATresponseString(AT_DISCONNECT_RESP);
                    }
                    else
                    {
                        dbg_printf(LOG, "[WIFI MAN] +++ WIFI DISCONNECTION TIMEOUT +++ \r\n");
                        //queueATresponse(AT_COMMAND_FAILED);
                        responseString = (char *) malloc(100);
                        sprintf(responseString, "\r\n+UUTIMEOUT\r\n");
                        sendATresponseString(AT_COMMAND_FAILED);
                    }
                    // attempt reconnection if always connected scheme is set
                    if(internet_config->connectionScheme == ALWAYS_CONNECTED)
                    {
                        setNextCommand(WIFI_CMD_CONNECT);
                    }
                }
                wifiBusy = 0;
                break;
            }
            case WIFI_CMD_CONFIG:
                wifiBusy = 1;
                set_WIFI_CONFIG();
                wifiCmd = WIFI_CMD_NONE;
                queueATresponse(AT_CONFIG_RESP);
                wifiBusy = 0;
                break;
            case WIFI_CMD_INTERNET_CONFIG:
            {
                wifiBusy = 1;
                backgroundTaskCompleted = false;
                set_internet_config();
                // Wait for callback semaphore
#ifdef DNANUDGE_DEBUG
                callback_semaphore.wait();
#endif
                int msecCount = 0;
                while(!backgroundTaskCompleted && msecCount < 1000)
                {
                    msecCount++;
                    wait_ms(10);
                }
                if(backgroundTaskCompleted)
                {
                    queueATresponse(AT_INTERNET_CONFIG_RESP);
                }
                backgroundTaskCompleted = false;
                wifiCmd = WIFI_CMD_NONE;
                //wifiCmd = WIFI_CMD_GET_TOKEN;
                break;
            }
            case WIFI_CMD_NETWORK_STATUS:
                wifiBusy = 1;
                if(outputBuffersAvailable())
                {
                    getNetworkStatus();
                }
                sendATresponseString(AT_NETWORK_STATUS_RESP);
                wifiCmd = WIFI_CMD_NONE;
                wifiBusy = 0;
                break;
            case WIFI_CMD_WIFI_STATUS:
                wifiBusy = 1;
                if(outputBuffersAvailable())
                {
                    getWiFiStatus();
                }
                sendATresponseString(AT_WIFI_STATUS_RESP);
                wifiCmd = WIFI_CMD_NONE;
                wifiBusy = 0;
                break;
            case WIFI_CMD_SEND_HTTPS_REQ:
            {
                wifiBusy = 1;
                if(!https_token_valid) // if this is the first time get token
                {
                    wifiCmd = WIFI_CMD_NONE;
                    fromWiFiCmd = WIFI_CMD_TLS_CONNECT;
                    nextWiFiCmd = WIFI_CMD_SEND_HTTPS_REQ;
                    setNextCommand(WIFI_CMD_GET_TOKEN);
                    break;
                }
                // cancel keep alive event as not needed since new request has come in.
                if(keep_alive_id != 0) // only cancel if it has been activated
                {
                    _event_queue.cancel(keep_alive_id); 
                }               
#ifdef SEND_DEBUG_MESSAGES
                if(outputBuffersAvailable())
                {
                    responseString = (char *) malloc(100);
                    sprintf(responseString, "\r\nHTTP REQUEST RECEIVED\r\n");
                    sendATresponseString(AT_EVENT);
                }
#endif
                dbg_printf(LOG, "before call to send http request \n");
                dbg_printf(LOG, "\r\n[WIFI-MAN] Received HTTPS request...\r\n");
                print_memory_info();
                // disable network interrupts during https request
                network->attach(NULL);
#ifdef USE_EVENTS_FOR_HTTPS_REQUESTS
                
                // Events can be cancelled as long as they have not been dispatched. If the
                // event has already expired, cancel has no side-effects.
                int event_id = _event_queue.call(this, &WiFiManager::createSendHttpsRequest);
                waitForBackgroundTask(6000, 10); // six second timeout
//                backgroundTaskCompleted = false;               
//                int msecCount = 0;
//                int oldChunkNum = chunkNum;
//                while(!backgroundTaskCompleted && msecCount < 6000)
//                {
//                    msecCount+=10;
//                    wait_ms(10);
//                    if(oldChunkNum != chunkNum) // new payload received
//                    {
//                        oldChunkNum = chunkNum;
//                        msecCount = 0;
//                    }
//                }
                if(backgroundTaskCompleted)
                {
                    //queueATresponse(AT_INTERNET_CONFIG_RESP);
                    result = true;
                }
                else
                {
                    //_event_queue.cancel(event_id); 
                    result = false;
                }
                backgroundTaskCompleted = false;
#else
                result = createHttpsRequest();
#endif
                if(result == false && outputBuffersAvailable())
                {
                    responseString = (char *) malloc(100);
                    if(http_result==TLS_CONNECTION_FAILED)
                    {
                        sprintf(responseString, "\r\nTLS CONNECTION FAILURE\r\n");
                    }
                    else
                    {
                        sprintf(responseString, "\r\nHTTP REQUEST FAILED\r\n");
                    }
                    sendATresponseString(AT_COMMAND_FAILED);
                }
                dbg_printf(LOG, "after call to send http request \n");
                print_memory_info();
                wifiCmd = WIFI_CMD_NONE;
                wifiBusy = 0;
                // enable keep alive after https request completes
                keep_alive_id = _event_queue.call_every(CLOUD_KEEP_ALIVE_INTERVAL, this, &WiFiManager::callInternetKeepAlive);
                // re-enable network interrupts after https request.
                network->attach(callback(this, &WiFiManager::status_callback));
                break;
            }            
            case WIFI_CMD_TLS_CONNECT:
            {
                dbg_printf(LOG, "\r\n[WIFI-MAN] ATTEMPTING TLS CONNECTION\r\n");
                char* hostName = strstr(internet_config->url,"//");
                wifiBusy = 1;
                if(hostName != NULL)
                {
                    hostName += 2; 
                    //https_connection_active = createTLSconnection(hostName);
                    _event_queue.call(this, &WiFiManager::createTLSconnThreadCall, (const char*)hostName);
                    waitForBackgroundTask(6000, 10); // six second timeout
                    if(backgroundTaskCompleted == false)
                    {
                        https_connection_active = false;
                        queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED);
                        delete socket;
                        socket = NULL;
                    }
                    else
                    {
                        https_connection_active = true;
                    }
                }
                if(fromWiFiCmd == WIFI_CMD_TLS_CONNECT)
                {
                    wifiCmd = nextWiFiCmd;
                    fromWiFiCmd = WIFI_CMD_NONE;
                    nextWiFiCmd = WIFI_CMD_NONE;
                }
                else
                {
                    wifiCmd = WIFI_CMD_NONE;
                }
                wifiBusy = 0;
                break;
            }
            case WIFI_CMD_INTERNET_KEEP_ALIVE:
            {
                wifiBusy = 1;
                if(!https_token_valid) // if this is the first time get token
                {
                    wifiCmd = WIFI_CMD_NONE;
                    fromWiFiCmd = WIFI_CMD_TLS_CONNECT;
                    nextWiFiCmd = WIFI_CMD_INTERNET_KEEP_ALIVE;
                    setNextCommand(WIFI_CMD_GET_TOKEN);
                    break;
                }
                keepSocketAlive();
                wifiCmd = WIFI_CMD_NONE;
                wifiBusy = 0;
                break;
            }
            case WIFI_CMD_GET_TOKEN:
            {
                wifiBusy = 1;                
                _event_queue.call(this, &WiFiManager::createTLSconnThreadCall, AWS_HOST_NAME);
                waitForBackgroundTask(6000, 10); // six second timeout
                if(backgroundTaskCompleted == false)
                {
                    queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED);
                    delete socket;
                    socket = NULL;
                }
                else
                {
                    https_connection_active = false;
                    GetCloudAccessToken();
                    wifiCmd = WIFI_CMD_NONE;
                    setNextCommand(WIFI_CMD_TLS_CONNECT);
                    //_event_queue.call_in(ONE_SECOND,this, &WiFiManager::setNextCommand, WIFI_CMD_TLS_CONNECT);
                    //wifiCmd = WIFI_CMD_TLS_CONNECT;
                }
                //wifiBusy = 0;
                break;
            }
            case WIFI_CMD_WIFI_MAC_ADDR:
            {
                wifiBusy = 1;
                if(outputBuffersAvailable())
                {
                    getWiFiMACaddress();
                    sendATresponseString(AT_WIFI_MAC_RESP);
                }
                wifiCmd = WIFI_CMD_NONE;
                wifiBusy = 0;
                break;
            }
            case WIFI_CMD_SEND_HTTP_REQ:
                break;
            default:
                break;
        }
        wait_ms(WIFI_MAIN_LOOP_WAIT_TIME_MS); // 
    }
    
}

void  WiFiManager::createSendHttpsRequest()
{
    backgroundTaskCompleted = createHttpsRequest();
}


void  WiFiManager::createTLSconnThreadCall(const char * hostName)
{
    bool result;
    backgroundTaskCompleted = false;
    result = createTLSconnection(hostName);
    if(result)
    {
        // update remote peer details after socket connection
        updateRemotePeerDetails();
        // send socket connection event before proceeding to send https request
        // give about 2 ms
        sendSocketConnectionEvent();
        backgroundTaskCompleted = true;
    }
}
void  WiFiManager::waitForBackgroundTask(int timeout_ms, int inc_ms)
{
    backgroundTaskCompleted = false;               
    int msecCount = 0;
    int oldChunkNum = chunkNum;
    while(!backgroundTaskCompleted && msecCount < timeout_ms)
    {
        msecCount+=inc_ms;
        wait_ms(inc_ms);
        if(oldChunkNum != chunkNum) // new payload received
        {
            oldChunkNum = chunkNum;
            msecCount = 0;
        }
    }
}
void  WiFiManager::sendATresponseString(at_cmd_resp_t at_cmd)
{
    int strLen = strlen(responseString) + 1;
    at_data_resp = new at_data_msg_t;
    // set string length 
    at_data_resp->dataLen = strLen;
    memcpy(at_data_resp->buffer, responseString, strLen);
    free(responseString);
    responseString = NULL;
    // package and send on wifi data queue    
    at_data_resp->at_resp = at_cmd;
    bool queueResult = true;
    int wait_count = 0;
    do
    {
        if(!queueResult){
            wait_count+=10;
            dbg_printf(LOG, "ATCMD Queue full waiting %d ms so far...\n", wait_count);
            wait_ms(10);
        }
        queueResult = queueWiFiDataResponse(*at_data_resp);
    }while(queueResult == false && wait_count<QUEUE_WAIT_TIMEOUT_MS);
    delete at_data_resp;
    at_data_resp = NULL;
}                                            


void  WiFiManager::sendATresponseBytes(at_cmd_resp_t at_cmd, int len)
{
    at_data_resp = new at_data_msg_t;
    // set string length 
    at_data_resp->dataLen = len;
    memcpy(at_data_resp->buffer, responseBytes, len);
    delete responseBytes;
    responseBytes = NULL;
    // package and send on wifi data queue    
    at_data_resp->at_resp = at_cmd;
    bool queueResult = true;
    int wait_count = 0;
    do
    {
        if(!queueResult){
            wait_count+=10;
            wait_ms(10);
            dbg_printf(LOG, "ATCMD Queue full waited %d ms so far...\n", wait_count);
        }
        queueResult = queueWiFiDataResponse(*at_data_resp);
    }while(queueResult == false && wait_count<QUEUE_WAIT_TIMEOUT_MS);
    delete at_data_resp;
    at_data_resp = NULL;
    dbg_printf(LOG, "[WIFI-MAN] sendATresponseBytes completed successfully\r\n");
}                                            



bool  WiFiManager::dequeueWiFiCommands(){
    if(wifiCmd != WIFI_CMD_NONE || wifiBusy!=0) return false; // busy
    osEvent evt = _aT2WiFiCmdQueue->get(0);
    if(evt.status == osEventMessage){
        wifi_cmd_message_t *cmd = (wifi_cmd_message_t*)evt.value.p;
        setNextCommand(cmd->wifi_cmd);
#ifndef USE_MALLOC_FOR_COMMAND_MEMORY_POOL
        _aT2WiFimPool->free(cmd);
        cmd = NULL;
#else
        free(cmd);
        cmd = NULL;
#endif
    }
    return true;
}


bool WiFiManager::dequeueATdataResponse(){
    if(wifiCmd != WIFI_CMD_NONE || wifiBusy!=0) return false; // busy
    osEvent evt = _aT2WiFiDataQueue->get(0);
    if(evt.status == osEventMessage){
        data_msg = (wifi_data_msg_t*)evt.value.p;
        setNextCommand(data_msg->wifi_cmd);
        //_wiFi2ATDatamPool->free(data_msg);
    }
    return true;
}


bool WiFiManager::setNextCommand(wifi_cmd_t cmd)
{
    dbg_printf(LOG, "\n [WIFI-MAN] About to set next WiFi manager command to %d\n", cmd);
    if(wifiCmd == WIFI_CMD_NONE){
        wifiCmd = cmd;
        return true; // success
    }
    dbg_printf(LOG, "\n [WIFI-MAN] Busy : current state = %d \n", wifiCmd);
    return false; // wiFiManager busy
}

const char * WiFiManager::sec2str(nsapi_security_t sec)
{
    switch (sec) {
        case NSAPI_SECURITY_NONE:
            return "None";
        case NSAPI_SECURITY_WEP:
            return "WEP";
        case NSAPI_SECURITY_WPA:
            return "WPA";
        case NSAPI_SECURITY_WPA2:
            return "WPA2";
        case NSAPI_SECURITY_WPA_WPA2:
            return "WPA/WPA2";
        case NSAPI_SECURITY_UNKNOWN:
        default:
            return "Unknown";
    }
}


nsapi_size_or_error_t WiFiManager::scanNetworks()
{
    getWiFiInstance();
    if(network == NULL)
    {
        dbg_printf(LOG, "\n [WIFI-MAN] Error instantiating WiFi!! \n");
        return 0;
    }
    //nsapi_error_t error;
    dbg_printf(LOG, "\n [WIFI-MAN] About to start scan for WiFi networks\n");
    lastScanCount = network->scan(NULL, 0);
    dbg_printf(LOG, "\n [WIFI-MAN] Scan for WiFi networks completed - \n");
    return lastScanCount;
}


//nsapi_size_or_error_t WiFiManager::getAvailableAPs(WiFiAccessPoint * res, 
//                                                   nsapi_size_t ncount)
nsapi_size_or_error_t WiFiManager::getAvailableAPs(nsapi_size_t ncount)
{
    getWiFiInstance();
    if(network == NULL)
    {
        dbg_printf(LOG, "\n [WIFI-MAN] Error instantiating WiFi!! \n");
        return 0;
    }
    WiFiAccessPoint       *ap;
    nsapi_size_or_error_t count;
    count = ncount;
    if (count <= 0) {
        dbg_printf(LOG, "[WIFI-MAN] scan() failed with return value: %d\n", count);
        return 0;
    }
    /* Limit number of network arbitrary to 15 */
    count = count < 15 ? count : 15;
    ap = new WiFiAccessPoint[count];
    count = network->scan(ap, count);
    if (count <= 0) {
        dbg_printf(LOG, "[WIFI-MAN] scan() failed with return value: %d\n", count);
        return 0;
    }

    for (int i = 0; i < count; i++) {
        dbg_printf(LOG, "[WIFI-MAN]: %s secured: %s BSSID: %hhX:%hhX:%hhX:%hhx:%hhx:%hhx RSSI: %hhd Ch: %hhd\n", ap[i].get_ssid(),
               sec2str(ap[i].get_security()), ap[i].get_bssid()[0], ap[i].get_bssid()[1], ap[i].get_bssid()[2],
               ap[i].get_bssid()[3], ap[i].get_bssid()[4], ap[i].get_bssid()[5], ap[i].get_rssi(), ap[i].get_channel());
    }
    dbg_printf(LOG, "[WIFI-MAN]  %d networks available.\n", count);

    delete[] ap;
    return count;
}


void WiFiManager::set_WIFI_CONFIG()
{
    wifi_config_t *wifi_cfg= (wifi_config_t *) data_msg->buffer;
    if(wifi_cfg->ssid[0] != NULL)set_WIFI_SSID(wifi_cfg->ssid);
    if(wifi_cfg->pass[0] != NULL)set_WIFI_PASSWORD(wifi_cfg->pass);
    if(wifi_cfg->security != NSAPI_SECURITY_UNKNOWN)set_WIFI_SECURITY(wifi_cfg->security);
    free_DataMsg();
}

void WiFiManager::set_WIFI_SSID(char * wifi_ssid)
{
    strcpy(wifi_config->ssid, wifi_ssid);
    dbg_printf(LOG, "[WIFI-MAN]  wifi_ssid set to %s\n", wifi_config->ssid);
    https_connection_active = false; // reset whenever any of the security credentials change
    delete socket;
}


void WiFiManager::set_WIFI_PASSWORD(char * wifi_pass)
{
    strcpy(wifi_config->pass, wifi_pass);
    dbg_printf(LOG, "[WIFI-MAN]  wifi_pass set to %s\n", "****************");
    https_connection_active = false; // reset whenever any of the security credentials change
    delete socket;
}


void WiFiManager::set_WIFI_SECURITY(nsapi_security_t wifi_security)
{
    wifi_config->security = wifi_security;
    dbg_printf(LOG, "[WIFI-MAN]  wifi_security set to %s\n", sec2str(wifi_config->security));
    https_connection_active = false; // reset whenever any of the security credentials change
    delete socket;
}

void WiFiManager::gethostbyname()
{
    nsapi_value_or_error_t value_or_error;
#ifdef DNANUDGE_DEBUG
    SocketAddress * addr = new SocketAddress;
    bool res;
    res = addr->set_ip_address("8.8.8.8");
    if(res)
    {
        dbg_printf(LOG, "[WIFI-MAN] added ip address %s\r\n", addr->get_ip_address());
    }
    else
    {
        dbg_printf(LOG, "[WIFI-MAN] Error adding ip address \r\n");
    }
    network->add_dns_server(*addr);
#endif
    char * serverAddress = new char[100];
    char *p = strstr(internet_config->url, "//");
    if(p != NULL && use_full_hostname == false)
    {
        strcpy(serverAddress,p+2);
    }
    else
    {
        strcpy(serverAddress,internet_config->url);
    }
    value_or_error = network->gethostbyname_async(serverAddress, 
                                         callback(this, &WiFiManager::gethostbyname_callback), 
                                         NSAPI_UNSPEC);
                                                                                  
    if(value_or_error >= NSAPI_ERROR_OK) // success
    {
        dbg_printf(LOG, "[WIFI-MAN] hostname translation successful value_or_error = %d\r\n", value_or_error);
        //strcpy(responseString, UDDRP_WRITE_OK);
        //printBufferInHex(responseBytes, HOSTNAME_RESPONSE_LEN);
        //sendATresponseBytes(CONNECT_EVENT, HOSTNAME_RESPONSE_LEN);
    }
    else if(outputBuffersAvailable()) // -ve number means error
    {
        responseString = (char *) malloc(20);
        dbg_printf(LOG, "[WIFI-MAN] hostname translation failed\r\n");
        strcpy(responseString, UDDRP_ERROR);
        sendATresponseString(AT_COMMAND_FAILED);
    }

}

void WiFiManager::set_internet_config()
{
    internet_config_t *internet_cfg  = (internet_config_t *) data_msg->buffer;
    internet_config->peer_id          = internet_cfg->peer_id;
    strncpy(internet_config->url,internet_cfg->url, strlen(internet_cfg->url)+1);
    internet_config->connectionScheme = internet_cfg->connectionScheme;
    free_DataMsg();
    dbg_printf(LOG, "[WIFI MAN] Internet configuration setup completed\n"); 
    dbg_printf(LOG, "peer_id = %1d, url = %s, connScheme = %1d\n", internet_config->peer_id, 
                                                      internet_config->url, 
                                                      internet_config->connectionScheme);
    if(https_connection_active)
    {
        https_connection_active = false; // reset whenever any of the security credentials change
        socket->close();    // close socket before deleting memory    
        delete socket;
        socket = NULL;
    }
    _event_queue.call_in(10, this, &WiFiManager::gethostbyname);
}



void WiFiManager::getNetworkStatus(){
    
    responseString = (char *) malloc(MAX_RESPONSE_STRING_LEN);
    net_stat_id_t status_id;
    char * nextStrPtr = responseString;
    for(int i=0; i< NumNetworkStatus;i++){
        status_id = netStatusIds[i]; // get current status id
        switch(status_id){
            case IF_HW_ADDRESS:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%s\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              network->get_mac_address());
                break;
            case NETWORK_IF_STATUS:
                sprintf(nextStrPtr, "\r\n%s%d,%d, %d\r\n", NETWORK_STATUS, 
                                                           WIFI_CHANNEL,
                                                           status_id,
                                                           (uint8_t)is_connected);
                break;
            case INTERFACE_TYPE:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%d\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              WIFI_STATION);
                break;
            case IPv4_ADDRESS:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%s\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              network->get_ip_address());
                break;
            case SUBNET_MASK:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%s\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              network->get_netmask());
                break;
            case GATEWAY_ADDRESS:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%s\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              network->get_gateway());
                break;
            case PRIMARY_DNS_SERVER:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%s\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              DEFAULT_DNS_ADDRESS);
                break;
            case SECONDARY_DNS_SERVER:
                sprintf(nextStrPtr, "\r\n%s%d,%d,%s\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id,
                                                              DEFAULT_DNS_ADDRESS);
                break;
            case IPv6_ADDRESS:
                sprintf(nextStrPtr, "\r\n%s%d,%d,::\r\n", NETWORK_STATUS, 
                                                              WIFI_CHANNEL,
                                                              status_id);
                break;
            default:
                sprintf(nextStrPtr, "\r\n%s,::\r\n", NETWORK_STATUS);
                break;
        }
        nextStrPtr += strlen(nextStrPtr) ; // progress to end of current string
    }
    sprintf(nextStrPtr, "%s", UDDRP_WRITE_OK);
}

void WiFiManager::getWiFiMACaddress()
{
    char * mp = new char[20];
    sscanf(network->get_mac_address(),"%02s:%2s:%2s:%2s:%2s:%2s",&mp[0],&mp[2],&mp[4],&mp[6],&mp[8],&mp[10]);
    responseString = (char *) malloc(100);
    
    sprintf(responseString, "\r\n%s%d,%sOK\r\n", LOCAL_ADDRESS_RESP, 
                                                 WIFI_IF_ID,
                                                 mp);
    delete mp;
}


void WiFiManager::getWiFiStatus(){
    
    responseString = (char *) malloc(MAX_RESPONSE_STRING_LEN);
    wifi_stat_id_t status_id;
    char * nextStrPtr = responseString;
    for(int i=0; i< NumWiFiStatus;i++){
        status_id = wifiStatusIds[i]; // get current status id
        switch(status_id){
            case WIFI_SSID:
                sprintf(nextStrPtr, "\r\n%s%d,%s\r\n", WIFI_NETWORK_STATUS, 
                                                       status_id,
                                                       wifi_config->ssid);
                break;
            case WIFI_BSSID:
                sprintf(nextStrPtr, "\r\n%s%d,%s\r\n", WIFI_NETWORK_STATUS, 
                                                       status_id,
                                                       network->get_mac_address());
                break;
            case WIFI__CURRENT_CHANNEL:
                sprintf(nextStrPtr, "\r\n%s%d,%d\r\n", WIFI_NETWORK_STATUS, 
                                                       status_id,
                                                       DEFAULT_WIFI_CHANNEL);
                break;
            case WIFI_STA_STATUS:
                sprintf(nextStrPtr, "\r\n%s%d,%d\r\n", WIFI_NETWORK_STATUS, 
                                                       status_id,
                                                       (uint8_t)is_connected);
                break;
            case WIFI_RSSI:
                sprintf(nextStrPtr, "\r\n%s%d,%d\r\n", WIFI_NETWORK_STATUS, 
                                                       status_id,
                                                       network->get_rssi());
                break;
            default:
                sprintf(nextStrPtr, "\r\n%s,::\r\n", WIFI_NETWORK_STATUS);
                break;
        }
        nextStrPtr += strlen(nextStrPtr) ; // progress to end of current string
    }
    sprintf(nextStrPtr, "%s", UDDRP_WRITE_OK);
}


void WiFiManager::free_DataMsg()
{
    // free memory after processing
    _aT2WiFiDatamPool->free(data_msg);
    data_msg = NULL;
}



void WiFiManager::status_callback(nsapi_event_t status, intptr_t param)
{
    dbg_printf(LOG, "[WIFI-MAN] about to call status_callback_event... \r\n");
    _event_queue.call_in(50, this, &WiFiManager::status_callback_event, status, param);
}
void WiFiManager::status_callback_event(nsapi_event_t status, intptr_t param)
{
    switch(param) {
        case NSAPI_STATUS_LOCAL_UP:
            dbg_printf(LOG, "[WIFI-MAN] Local IP address set!\r\n");
            dbg_printf(LOG, "[WIFI-MAN] IP address: %s\n", network->get_ip_address());
            break;
        case NSAPI_STATUS_GLOBAL_UP:
            dbg_printf(LOG, "Global IP address set!\r\n");
            dbg_printf(LOG, "[WIFI-MAN] IP address: %s\n", network->get_ip_address());
            dbg_printf(LOG, "[WIFI-MAN] Connected to the network %s\n", wifi_config->ssid);
            if(outputBuffersAvailable())
            {
                responseString = (char *) malloc(MAX_RESPONSE_STRING_LEN); 
                sprintf(responseString, "\r\n%s%d,%s,%d\r\n", WIFI_LINK_ENABLED, 
                                                              WIFI_CHANNEL,
                                                              network->get_mac_address(),
                                                              DEFAULT_WIFI_CHANNEL);
                
                wifiBusy = 0;
                is_connected = true;
            }
            break;
        case NSAPI_STATUS_DISCONNECTED:
            dbg_printf(LOG, "No connection to network!\r\n");
            dbg_printf(LOG, "\n [WIFI-MAN] No connection to network!\n");
            if(outputBuffersAvailable())
            {
                responseString = (char *) malloc(100);
                sprintf(responseString, "\r\n%s%d,5\r\n", WIFI_LINK_DISABLED, WIFI_CHANNEL);
                //sendATresponseString(AT_EVENT);
            }
            wifiBusy = 0;
            is_connected = false;
            break;
        case NSAPI_STATUS_CONNECTING:
            dbg_printf(LOG, "Connecting to network!\r\n");
            break;
        default:
            dbg_printf(LOG, "Not supported");
            break;
    }
}



   
nsapi_error_t WiFiManager::connect()
{
    getWiFiInstance();
    if(network == NULL)
    {
        dbg_printf(LOG, "\n [WIFI-MAN] Error instantiating WiFi!! \n");
        return 0;
    }
    nsapi_error_t error;
    dbg_printf(LOG, "\n [WIFI-MAN] About to connect to WiFi network\n");
    network->attach(callback(this, &WiFiManager::status_callback));
    error = network->set_blocking(false);
    if(error)
    {
        dbg_printf(LOG, "\n [WIFI-MAN] Could not set non-blocking mode for Wifi -- aborting!! - \n");
        return error;
    }
    dbg_printf(LOG, "[WIFI-MAN] Connecting to network ssid = %s passwd = %s  security = %s \r\n", 
                                                    wifi_config->ssid, 
                                                    "****************", 
                                                    sec2str(wifi_config->security));
    error = network->connect(wifi_config->ssid,
                             wifi_config->pass,
                             wifi_config->security);
    dbg_printf(LOG, "[WIFI-MAN] network->connect called. error = %d\r\n", error);
    return error;
}

void WiFiManager::processGetHostByNameResult(nsapi_error_t result, SocketAddress *address)
{
    
    dbg_printf(LOG, "gethostbyname_callback called... result = %d \r\n", result);
    print_memory_info();
    if(outputBuffersAvailable())
    {
        responseBytes = new uint8_t[HOSTNAME_RESPONSE_LEN]; //malloc(HOSTNAME_RESPONSE_LEN);
        int i = 0;
        responseBytes[i++] = IPv4_CONNECTION; // connect type IPv4
        responseBytes[i++] = TCP_PROTOCOL; // Protocol = TCP
        if(is_connected && result>=0)
        {
            memcpy(&responseBytes[i], address->get_ip_bytes(), 4); // remote IPv4 address
            strcpy(internet_config->remote_IPv4Address, address->get_ip_address());
            i +=4;
            uint16_t port = address->get_port();
            internet_config->remote_port = port;
            memcpy(&responseBytes[i], &port, 2); // remote IPv4 port #
            i +=2;
            // local IPv4 address
            int ipAddr[4];
            strcpy(internet_config->local_IPv4Address, network->get_ip_address());
            sscanf(internet_config->local_IPv4Address, "%d.%d.%d.%d", &ipAddr[0], &ipAddr[1], 
                                                                     &ipAddr[2], &ipAddr[3]);
            responseBytes[i++] = (uint8_t) ipAddr[0];
            responseBytes[i++] = (uint8_t) ipAddr[1];
            responseBytes[i++] = (uint8_t) ipAddr[2];
            responseBytes[i++] = (uint8_t) ipAddr[3];
            // local port number
            responseBytes[i++] = 0;
            responseBytes[i]   = 0;
            printBufferInHex(responseBytes, HOSTNAME_RESPONSE_LEN);
            sendATresponseBytes(CONNECT_EVENT, HOSTNAME_RESPONSE_LEN);
        }
        else
        {
            // if unconnected set ip and port to zeroes
            memset(&responseBytes[i], 0x00, 6);
            delete responseBytes;
            dbg_printf(LOG, "\r\nHOSTNAME TRANSLATION FAILURE : error code = %d \r\n", result);
            if(responseString == NULL)
            {
                responseString = (char *) malloc(100);
                sprintf(responseString, "\r\nHOSTNAME TRANSLATION FAILURE : error code = %d \r\n", result);
                sendATresponseString(AT_EVENT);
            }
            use_full_hostname = not use_full_hostname;
       }
       wifiBusy = 0;
       backgroundTaskCompleted = true;
   }
    
}

void WiFiManager::gethostbyname_callback(nsapi_error_t res, SocketAddress *addr)
{
    nsapi_error_t result = res;
    SocketAddress *address = new SocketAddress;
    address = addr;
    _event_queue.call(this, &WiFiManager::processGetHostByNameResult, 
                                    result, address);
    
#ifdef DNANUDGE_DEBUG
    callback_semaphore.release();
#endif
}   

void WiFiManager::sendSocketConnectionEvent()
{
    // 
    responseString = (char *) malloc(MAX_RESPONSE_STRING_LEN); 
    sprintf(responseString, "\r\n%s%d,%d,%d,%s,%d,%s,%d\r\n", PEER_CONNECTED_URC, 
                                                              IP_PEER_HANDLE,
                                                              IPv4_CONNECTION,
                                                              TCP_PROTOCOL,
                                                              internet_config->local_IPv4Address,
                                                              DEFAULT_LOCAL_PORT,
                                                              internet_config->remote_IPv4Address,
                                                              internet_config->remote_port);
    sendATresponseString(AT_EVENT);
}


nsapi_error_t WiFiManager::disconnect()
{
    nsapi_error_t error;
    error = network->disconnect();
    if(error < 0)
    {
        responseString = (char *) malloc(100); 
        sprintf(responseString, "%s", UDDRP_ERROR);
        sendATresponseString(AT_EVENT);
    }
    return error;
}

#define MIX_HDR_AND_BODY
void WiFiManager::sendResponseDownloadData(at_cmd_resp_t at_cmd, const uint8_t * buf, int bufLen)
{    

    at_data_resp = new at_data_msg_t;
    at_data_resp->at_resp = at_cmd;
    size_t bufSize = sizeof(at_data_resp->buffer);
    int pos = 0;
    at_data_resp->dataLen = 0;
    bool queueResult = true;
    int hdrLen = 0;
    int wait_count = 0;
    do {
        if(!queueResult){
            wait_count++;
            dbg_printf(LOG, "[WIFI-MAN] ATCMD Queue full waiting %d ms so far...\n", wait_count*10);
            wait_ms(10);
        }
        else {            
            if(http_response_hdr_sent == false && chunkNum==1){ // only do this for first chunk
                bool status = copyResponseHdr2Queue(buf);  
                if(status == true){
                    dbg_printf(LOG, "[WIFI-MAN] Http Response header copied to response buffer [bytes = %d] \r\n",at_data_resp->dataLen);
                    hdrLen =  at_data_resp->dataLen;
                    http_response_hdr_sent = true;  
                } 
                else {     
                    dbg_printf(LOG, "[WIFI-MAN] Http Response header copy failed\r\n");
                }
            }
            int cpyLen = (bufLen - pos) > bufSize? bufSize : (bufLen - pos) ;
            dbg_printf(LOG, "[WIFI-MAN] Http Response body [bytes = %d] \r\n",cpyLen);
            at_data_resp->dataLen += cpyLen;
            memcpy(&at_data_resp->buffer[hdrLen], &buf[pos], cpyLen);
            dbg_printf(LOG, "[WIFI-MAN] Http Response header and body copied to response buffer [bytes = %d] \r\n",at_data_resp->dataLen);
        }
        queueResult = queueWiFiDataResponse(*at_data_resp);
        if(queueResult){ 
            pos+= at_data_resp->dataLen;
            at_data_resp->dataLen = 0;
            hdrLen = 0; 
        }
    }while(queueResult ==  false || pos < bufLen);
    dbg_printf(LOG, "[WIFI-MAN] response data queued - deleting data memory\r\n");
    delete at_data_resp;
    at_data_resp = NULL;
}

bool WiFiManager::copyResponseHdr2Queue(const uint8_t * buf)
{
    const char *arbPtr = (const char *)buf - MAX_HTTP_HDR_LEN;
    const char *hdrPtr;
    int len;
    bool hdrFound = false;
    int i;
    for(i=0;i<(MAX_HTTP_HDR_LEN-50);i++)
    {
        // get location of start of the http header string
        hdrPtr = strstr(&arbPtr[i], HTTP_HEADER_START_LINE);
        len = strlen(HTTP_HEADER_START_LINE);
        // validate that header string
        if((strstr(&arbPtr[i+len], HTTP_HEADER_START_LINE) == NULL ||
           (strstr(&arbPtr[i+len], HTTP_HEADER_START_LINE) > (const char*)buf)) && //
            strstr(&arbPtr[i+len], HTTP_HEADER_CONTENT_TYPE) != NULL &&
            strstr(&arbPtr[i+len], HTTP_HEADER_CONTENT_LEN) != NULL  &&
            hdrPtr != NULL)
        {
            hdrFound = true;
            break;
        }
    }
    // calculate header length 
    int hdrLen = (const char*) buf -hdrPtr;
    // copy header 
    memcpy(at_data_resp->buffer, (const uint8_t *) hdrPtr, hdrLen);
    dbg_printf(LOG, "[i = %d] This is the header\r\n%s\r\n", i, hdrPtr);
    if(hdrFound == false)
    {
        dbg_printf(LOG, "[WIFI-MAN] copy failed: HTTP header not found!!\r\n");
        return false;
    }
    at_data_resp->dataLen = hdrLen;
    return true;
}

void WiFiManager::return_response(HttpResponse* res) {
    
    at_data_resp = new at_data_msg_t;
    int numChars = 0;
    // create message pointer for response header generation
    char * msgPtr = (char *)at_data_resp->buffer;
    // do status line
    numChars = sprintf(msgPtr, "HTTP/1.1 %d %s\r\n", res->get_status_code(), res->get_status_message().c_str());
    msgPtr += numChars;
    for (size_t ix = 0; ix < res->get_headers_length(); ix++) {
        numChars = sprintf(msgPtr, "%s: %s\r\n", 
                           res->get_headers_fields()[ix]->c_str(), 
                           res->get_headers_values()[ix]->c_str());
        msgPtr += numChars;
    }
    numChars = sprintf(msgPtr, "\r\n\r\n");
    msgPtr += numChars;
    // print out generated header
    dbg_printf(LOG, "[WiFi MAN] generated response header:\n");
    dbg_printf(LOG, "%s\r\n", (char *)at_data_resp->buffer);
    // calculate header length 
    at_data_resp->dataLen = (msgPtr - (char *)at_data_resp->buffer);
    
    // package and send on wifi data queue    
    at_data_resp->at_resp = AT_HTTPS_RESP;
    bool queueResult = true;
    int wait_count = 0;
    do
    {
        if(!queueResult){
            wait_count++;
            dbg_printf(LOG, "ATCMD Queue full waiting %d ms so far...\n", wait_count*10);
            wait_ms(10);
        }
        queueResult = queueWiFiDataResponse(*at_data_resp);
    }while(queueResult == false);
    delete at_data_resp;
    at_data_resp = NULL;
}


void WiFiManager::printBufferInHex(const uint8_t *buf, int pLen)
{
    print_debug_hex(buf, pLen);
}

//#define TRY_PRINTF

void WiFiManager::body_callback(const char *at, uint32_t length) {    
    dbg_printf(LOG, "\n Chunked response: Chunk %d : Total Bytes = %d\n", chunkNum , length);
    chunkNum++;
    dbg_printf(LOG, "This is the start when response is excluded\r\n%s\r\nend of packet \r\n", at);
    if(http_response == NULL)
    {
        dbg_printf(LOG, "[WIFI-MAN] response pointer NULL!!\r\n");
    }
    else
    {
        dbg_printf(LOG, "[WIFI-MAN] response pointer NULL not!!\r\n");
    }
#ifdef SEND_DEBUG_MESSAGES
    if(responseString == NULL && chunkNum==1)
    {
        responseString = (char *) malloc(100);
        sprintf(responseString, "\r\nHTTPS BODY CALLBACK RECEIVED:: length= %d\r\n", length);
        sendATresponseString(AT_EVENT);
    }
#endif
    sendResponseDownloadData(AT_HTTPS_RESP_DOWNLOAD, (uint8_t *)at, length);
}

//#define ENABLE_MBED_TRACE
bool WiFiManager::createTLSconnection(const char * hostName)
{
#ifdef ENABLE_MBED_TRACE
    mbed_trace_init();
#endif
    socket = new TLSSocket();
    nsapi_error_t r;
    // make sure to check the return values for the calls below (should return NSAPI_ERROR_OK)
    r = socket->open(network);
    if(r != NSAPI_ERROR_OK)
    { 
        dbg_printf(LOG, "TLS open failed!!\n");
        return false;
    }
    dbg_printf(LOG, "TLS open passed!!\n");
    r = socket->set_root_ca_cert(SSL_CA_PEM);
    if(r != NSAPI_ERROR_OK)
    { 
        dbg_printf(LOG, "TLS set_root_ca_cert failed!!\n");
        socket->close();
        dbg_printf(LOG, "closing TLS socket!!\n");
        return false;
    }
    dbg_printf(LOG, "TLS set_root_ca_cert passed!!\n");
    int start_ms = _event_queue.tick();
    int elapsed_ms;
    do{
        r = socket->connect(hostName, 443);
        elapsed_ms = _event_queue.tick() - start_ms;
        if(r == NSAPI_ERROR_OK)
        { 
            dbg_printf(LOG, "TLS connection successful for https site :  %s"
                            " \r\n[TLS conn elapsed_ms = %d]\n", hostName, elapsed_ms);
            return true;
        }
    }while(elapsed_ms < TLS_RETRY_TIMEOUT_MS);
    char errstr[100];
    mbedtls_strerror(r, errstr, 100);
    dbg_printf(LOG, "TLS connect failed (err = %d) for hostname '%s' -- ERROR = %s !!\n", r, hostName, errstr);
    socket->close();
    return false;
}


void WiFiManager::updateRemotePeerDetails()
{
    dbg_printf(LOG, "Updating internet_config... \r\n");
    nsapi_error_t error;
    SocketAddress * address = new SocketAddress;
    error = socket->getpeername(address);
    if(error>=0)   
    {
        strcpy(internet_config->remote_IPv4Address, address->get_ip_address());
        uint16_t port = address->get_port();
        internet_config->remote_port = port;
    }
    else  
    {
        strcpy(internet_config->remote_IPv4Address, "");
        internet_config->remote_port = 0;
    }
    delete address;
}


void WiFiManager::sendDebugMessage()
{
#ifdef SEND_HTTPS_DEBUG_MESSAGES
    sendATresponseString(AT_EVENT);
    wait_ms(100);
#else
    free(responseString);
#endif
}
#define TESTING_HTTPS

//#define DONT_USE_TLS_SOCKET
bool WiFiManager::createHttpsRequest()
{
    int  starttime;
    int stoptime;
    // reset chunk #;
    chunkNum = 0;
    http_response_hdr_sent = false;
    dbg_printf(LOG, "\n[WIFI MAN] Http Request received:\n");
    http_req_cfg = (http_request_t *) data_msg->buffer;
#ifdef FULL_DEBUG_ENABLED
    dbg_printf(LOG, "\n[WIFI MAN] uri = %s\n", http_req_cfg->request_URI);
    dbg_printf(LOG, "\n[WIFI MAN] internet cfg url = %s\n", internet_config->url);
#endif
    char full_url[100];
    char host[60] ;
    strncpy(full_url,internet_config->url, strlen(internet_config->url)+1);
    //strncpy(host,http_req_cfg->hostName, strlen(http_req_cfg->hostName)+1);
    char *eu = strstr(internet_config->url,HTTPS_URL_PREFIX);
    if(eu == NULL)
        eu = internet_config->url;
    else
        eu += strlen(HTTPS_URL_PREFIX);
    char *eu2 = strstr(eu, "/"); // find the api path
    int hLen = eu2 != NULL ? eu2-eu-1:  strlen(eu);
        
    
    strncpy(host,eu, hLen+1);
    strncat(full_url, http_req_cfg->request_URI, strlen(http_req_cfg->request_URI)+1);
#ifdef FULL_DEBUG_ENABLED
    dbg_printf(LOG, "\n[WIFI MAN] server host name = %s\n", host);
    dbg_printf(LOG, "\n[WIFI MAN] server url+uri = %s\n", full_url);
    dbg_printf(LOG, "\n[WIFI MAN] Host = %s\n", http_req_cfg->hostName);
    dbg_printf(LOG, "\n[WIFI MAN] Accept = %s\n", http_req_cfg->AcceptVal);
    dbg_printf(LOG, "\n[WIFI MAN] Content-Type = %s\n", http_req_cfg->contentType);
    dbg_printf(LOG, "\n[WIFI MAN] contentLenstr = %s\n", http_req_cfg->contentLen);
#endif
                                           
    int bodyLen;
    sscanf(http_req_cfg->contentLen, "%d", &bodyLen);
#ifdef FULL_DEBUG_ENABLED
    dbg_printf(LOG, "contenLenstr = %s bodyLen = %d\n", http_req_cfg->contentLen, bodyLen);
    if(bodyLen > 10){
        dbg_printf(LOG, "\n [WIFI MAN] Message Body:\n");
        printBufferInHex(http_req_cfg->body, bodyLen);
    }
#endif    
    if(strstr(internet_config->url, "http:")!=NULL) // http request
    {
        http_request = new HttpRequest(network,  
                                       http_req_cfg->method, 
                                       full_url,
                                       callback(this, &WiFiManager::body_callback));
        setHttpHeader("Host", http_req_cfg->hostName);
        setHttpHeader("Accept", http_req_cfg->AcceptVal);
        if(http_req_cfg->method == HTTP_GET){
            dbg_printf(LOG, "HTTP_GET -- ignoring body\n");
            http_response = http_request->send(NULL, 0);
        }
        else{
            setHttpHeader("Content-Type", http_req_cfg->contentType);
            setHttpHeader("Content-Length", http_req_cfg->contentLen);
            http_response = http_request->send(http_req_cfg->body, bodyLen);
        }
        free_DataMsg();
        if (!http_response) {
            char buf[100];
            mbedtls_strerror(http_request->get_error(), buf, 100);
            dbg_printf(LOG, "HttpRequest failed (error code %s)\n", buf);
            delete http_request; // free the memory
            return false;
        }
        delete http_request; // free the memory
        dbg_printf(LOG, "\n----- HTTP POST response -----\n");
    }
    else
    {
        mbed_stats_heap_t heap_stats;
        mbed_stats_heap_get(&heap_stats);
        dbg_printf(LOG, "Heap size: %lu / %lu bytes\r\n", heap_stats.current_size, heap_stats.reserved_size);
        starttime = Kernel::get_ms_count();
#ifndef DONT_USE_TLS_SOCKET
        if(https_connection_active == false){
            bool tlsResult;
            tlsResult = createTLSconnection(host);
#ifdef ENABLE_MBED_TRACE
            mbed_trace_free(); // free trace memory
#endif
            stoptime = Kernel::get_ms_count();
            dbg_printf(LOG, "\r\nTLS connection time : %d ms\r\n", (stoptime - starttime));
            if(tlsResult == false){
                 delete socket;
                 dbg_printf(LOG, "TLS Socket connection failed - deleting data msg\r\n");
                 free_DataMsg();
                 dbg_printf(LOG, "data msg deleted \r\n");
                 http_result = TLS_CONNECTION_FAILED;
                 return false;
            }
            // update remote peer details after socket connection
            updateRemotePeerDetails();
            // send socket connection event before proceeding to send https request
            // give about 2 ms
            sendSocketConnectionEvent();
        }        
        // Pass in `socket`, instead of `network` as first argument, and omit the `SSL_CA_PEM` argument
        stoptime = Kernel::get_ms_count();
        dbg_printf(LOG, "\r\nTLS connection time : %d ms\r\n", (stoptime - starttime));
        starttime = Kernel::get_ms_count();
        https_request = new HttpsRequest(socket, 
                                         http_req_cfg->method, 
                                         full_url,
                                         callback(this, &WiFiManager::body_callback));
#ifdef SEND_DEBUG_MESSAGES
        responseString = (char *) malloc(100);
        sprintf(responseString, "\r\nHTTP REQUEST OBJECT CREATED\r\n");
        sendDebugMessage();
#endif
#else
        https_request = new HttpsRequest(network, 
                                         SSL_CA_PEM,
                                         http_req_cfg->method, 
                                         full_url,
                                         callback(this, &WiFiManager::body_callback));
#endif        
#ifdef TESTING_HTTPS
        dbg_printf(LOG, "http_req_cfg->method = %d\n", http_req_cfg->method);
        if(http_req_cfg->method == HTTP_GET){
            dbg_printf(LOG, "HTTP_GET -- ignoring body\n");
            setHttpsHeader("Host", host);
            setHttpsHeader("Accept", http_req_cfg->AcceptVal);
            http_response = https_request->send(NULL, 0);
        }
        else{
            setHttpsHeader("Host", host);
            setHttpsHeader("Authorization", aws_id_token);
            setHttpsHeader("Accept", http_req_cfg->AcceptVal);
            setHttpsHeader("Content-Type", http_req_cfg->contentType);
            setHttpsHeader("Content-Length", http_req_cfg->contentLen);
            dbg_printf(LOG, "https headers setup - about to send request\r\n");
            // Grab the heap statistics
            dbg_printf(LOG, "Heap size: %lu / %lu bytes\r\n", heap_stats.current_size, heap_stats.reserved_size);
            dbg_printf(LOG, "\n[WIFI MAN] Token Length: %d \r\n IdToken: \r\n %s\r\n", strlen(aws_id_token), aws_id_token);
            
#ifdef PRINT_REQUEST_LOGS  
            uint8_t *http_req_log_buf = (uint8_t*)calloc(2048, 1);
            https_request->set_request_log_buffer(http_req_log_buf, 2048);
#endif
            http_response = https_request->send(http_req_cfg->body, bodyLen);
        }
#else
        setHttpsHeader("Host", host);
        setHttpsHeader("Authorization", aws_id_token);
        setHttpsHeader("Accept", http_req_cfg->AcceptVal);
        setHttpsHeader("Content-Type", http_req_cfg->contentType);
        setHttpsHeader("Content-Length", http_req_cfg->contentLen);
        http_response = https_request->send(http_req_cfg->body, bodyLen);
#endif      
#ifdef PRINT_REQUEST_LOGS  
        printHttpRequestLogBuffer();
#endif
        nsapi_error_t error = https_request->get_error();
        if(error < 0)
        {
            char buf[100];
            mbedtls_strerror(error, buf, 100);
            printf("HttpsRequest failed (error code %s)\n", buf);
            delete https_request; // free the memory
            https_request = NULL;
            https_connection_active = false; // reset true whenever connection fails
            socket->close();
            delete socket;
            socket = NULL;
            free_DataMsg();
            http_result = HTTP_REQUEST_FAILED;
            return false;
        }
        https_connection_active = true; // set true whenever connection succeeds
        dbg_printf(LOG, "\n----- HTTPS POST response -----\r\n");
    } 
    if(http_response_hdr_sent == false)
    {
        socket->close();
        delete socket;
        https_connection_active = false; 
#ifdef SEND_DEBUG_MESSAGES
        responseString = (char *) malloc(100);
        sprintf(responseString, "\r\n[WIFI-MAN] NO RESPONSE RECEIVED:: CLOSING CURRENT TLS CONNECTION.\r\n");
        sendDebugMessage();
#endif
        //return_response(http_response);
    }
    free_DataMsg();
    delete https_request; // free the request & response memory
    dbg_printf(LOG, "deleted https_request\r\n");
    https_request = NULL;
    http_result = RESPONSE_OK;
    stoptime = Kernel::get_ms_count();
    dbg_printf(LOG, "\r\nhttp request to response time : %d ms\r\n", (stoptime - starttime));
    return true;
}

void WiFiManager::createHttpRequest(http_method method,
                                    const char* url,
                                    Callback<void(const char *at, uint32_t length)> body_callback)
{
    http_request = new HttpRequest(network, 
                                   method, url, body_callback);;
}

void WiFiManager::setHttpHeader(string key, string value)
{
    http_request->set_header(key, value);
}

void WiFiManager::setHttpsHeader(string key, string value)
{
    https_request->set_header(key, value);
}

void WiFiManager::printHttpRequestLogBuffer()
{   
    
    // after the request is done:
#ifdef PRINT_BUFFER_IN_HEX
    dbg_printf(LOG, "\n----- Request buffer Hex-----\n");
    for (size_t ix = 0; ix < https_request->get_request_log_buffer_length(); ix++) {
        if(ix%16 == 0)dbg_printf(LOG, "\n[%04x] ", ix);
        dbg_printf(LOG, "%02x ", http_req_log_buf[ix]);
    }
#endif
    dbg_printf(LOG, "\n[ request size = %d bytes]\r\n", https_request->get_request_log_buffer_length());
    dbg_printf(LOG, "----- Request buffer string -----\r\n%s ", (char *)http_req_log_buf);
    //wait_ms(100);
    free(http_req_log_buf);
}
void WiFiManager::sendHttpsRequest(const char * body, int bodyLen)
{
}

void WiFiManager::sendHttpRequest(const char * body, int bodyLen)
{
}