/*******************************************************************************
  Function:
    void DRV_WIFI_SecurityGet(uint8_t *p_securityType,
                              uint8_t *p_securityKey,
                              uint8_t *p_securityKeyLength)

  Summary:
    Gets the current WiFi security setting

  Description:
    This function gets the current WiFi security setting.

    <table>
    Security                                      Key         Length
    --------                                      ---         ------
    DRV_WIFI_SECURITY_OPEN                        N/A         N/A
    DRV_WIFI_SECURITY_WEP_40                      binary      4 keys, 5 bytes each (total of 20 bytes)
    DRV_WIFI_SECURITY_WEP_104                     binary      4 keys, 13 bytes each (total of 52 bytes)
    DRV_WIFI_SECURITY_WPA_WITH_KEY                binary      32 bytes
    DRV_WIFI_SECURITY_WPA_WITH_PASS_PHRASE        ascii       8-63 ascii characters
    DRV_WIFI_SECURITY_WPA2_WITH_KEY               binary      32 bytes
    DRV_WIFI_SECURITY_WPA2_WITH_PASS_PHRASE       ascii       8-63 ascii characters
    DRV_WIFI_SECURITY_WPA_AUTO_WITH_KEY           binary      32 bytes
    DRV_WIFI_SECURITY_WPA_AUTO_WITH_PASS_PHRASE   ascii       8-63 ascii characters
    </table>

  Precondition:
    WiFi initialization must be complete.

  Parameters:
    p_securityType      - Value corresponding to the security type desired.
    p_securityKey       - Binary key or passphrase (not used if security is DRV_WIFI_SECURITY_OPEN)
    p_securityKeyLength - Number of bytes in p_securityKey (not used if security is DRV_WIFI_SECURITY_OPEN)

  Returns:
    None.

   Example:
    <code>
        uint8_t securityType;
        uint8_t securityKey[DRV_WIFI_MAX_SECURITY_KEY_LENGTH];
        uint8_t keyLength;

        DRV_WIFI_SecurityGet(&securityType, securityKey, &keyLength);
    </code>

  Remarks:
    If security was initially set with a passphrase that the MRF24WG used to generate
    a binary key, this function returns the binary key, not the passphrase.
*/
void DRV_WIFI_SecurityGet(uint8_t *p_securityType,
                          uint8_t *p_securityKey,
                          uint8_t *p_securityKeyLength)
{
    tCPElementResponseHdr mgmtHdr;
    uint8_t keyLength;
    uint8_t wepKeyIndex;
    
    /* send request, wait for mgmt response, do not read and do not free up response buffer */
     LowLevel_CPGetElement(WF_CP_ELEMENT_SECURITY,        /* Element ID      */
                           NULL,                          /* do not read     */
                           0,                             /* do not read     */
                           false);                        /* do not read, do not free mgmt buffer */

    /* at this point, management response is mounted and ready to be read */

    /* At this point, management response is mounted and ready to be read.                 */
    /* Set raw index to 0, read normal 4 byte header plus the next 3 bytes, these will be: */
    /*   profile id             [4]                                                        */
    /*   element id             [5]                                                        */
    /*   element data length    [6]                                                        */
    RawRead(RAW_SCRATCH_ID, MGMT_RX_BASE, sizeof(tCPElementResponseHdr), (uint8_t *)&mgmtHdr);

    // security type
    RawReadRelative(RAW_SCRATCH_ID, 1, p_securityType);

    // read wep key index to increment pointer in raw buffer, but throw away, it is always 0
    RawReadRelative(RAW_SCRATCH_ID, 1, &wepKeyIndex);

    /* determine security key length and read if it is present */
    keyLength = mgmtHdr.elementDataLength - 2;
    if (keyLength > 0)
    {
        *p_securityKeyLength = keyLength;
        RawReadRelative(RAW_SCRATCH_ID, keyLength, p_securityKey);
    }
    /* no security key, so set key length param to 0 */
    else
    {
        *p_securityKeyLength = 0;
    }       
}    
void DRV_WIFI_SecurityTypeGet(uint8_t *p_securityType)
{
    CPELEMENT_RESPONSE_HDR mgmtHdr;

    /* send request, wait for mgmt response, do not read and do not free up response buffer */
    CPElementGet(WF_CP_ELEMENT_SECURITY, /* Element ID */
                 NULL,                   /* do not read */
                 0,                      /* do not read */
                 false);                 /* do not read, do not free mgmt buffer */

    /* at this point, management response is mounted and ready to be read */

    /* At this point, management response is mounted and ready to be read.                 */
    /* Set raw index to 0, read normal 4 byte header plus the next 3 bytes, these will be: */
    /*   profile id             [4]                                                        */
    /*   element id             [5]                                                        */
    /*   element data length    [6]                                                        */
    RawRead(RAW_SCRATCH_ID, MGMT_RX_BASE, sizeof(CPELEMENT_RESPONSE_HDR), (uint8_t *)&mgmtHdr);

    // security type
    RawReadRelative(RAW_SCRATCH_ID, 1, p_securityType);
}
/* Function:
    void DRV_WIFI_SsidGet(uint8_t *p_ssid, uint8_t *p_ssidLength);

  Summary:
    Sets the SSID

  Description:
    Gets the SSID and SSID Length.

 Parameters:
    p_ssid      - Pointer to buffer where SSID will be written
    ssidLength  - number of bytes in SSID

  Returns:
 */
void DRV_WIFI_SsidGet(uint8_t *p_ssid, uint8_t *p_ssidLength)
{
    tCPElementResponseHdr  mgmtHdr;
    
    /* Request SSID, but don't have this function read data or free response buffer.       */
    LowLevel_CPGetElement(WF_CP_ELEMENT_SSID,     /* Element ID                            */
                          NULL,                   /* ptr to element data (not used here    */
                          0,                      /* num data bytes to read (not used here */ 
                          false);                 /* no read, leave response mounted       */

    /* At this point, management response is mounted and ready to be read.                 */
    /* Set raw index to 0, read normal 4 byte header plus the next 3 bytes, these will be: */
    /*   profile id             [4]                                                        */
    /*   element id             [5]                                                        */
    /*   element data length    [6]                                                        */
    RawRead(RAW_SCRATCH_ID, MGMT_RX_BASE, sizeof(tCPElementResponseHdr), (uint8_t *)&mgmtHdr);

    /* extract SSID length and write to caller */
    *p_ssidLength = mgmtHdr.elementDataLength;
    
    /* copy SSID name to callers buffer */
    RawReadRelative(RAW_SCRATCH_ID, *p_ssidLength, p_ssid);
}
/*****************************************************************************
 * FUNCTION: WFProcessMgmtIndicateMsg
 *
 * RETURNS:  error code
 *
 * PARAMS:   None
 *
 *  NOTES:   Processes a management indicate message
 *****************************************************************************/
void WFProcessMgmtIndicateMsg()
{
    tMgmtIndicateHdr  hdr;
    uint8_t buf[6];
    uint8_t event = 0xff;
    uint16_t eventInfo;

    // read mgmt indicate header (2 bytes)
    RawRead(RAW_SCRATCH_ID, MGMT_INDICATE_BASE, sizeof(tMgmtIndicateHdr), (uint8_t *)&hdr);

    /* if not a management indicate then fatal error */
    SYS_ASSERT((hdr.type == WF_MGMT_INDICATE_TYPE), "Invalid Indicate Header" );
        
    /* Determine which event occurred and handle it */
    switch (hdr.subType)
    {
        /*-----------------------------------------------------------------*/        
        case WF_EVENT_CONNECTION_ATTEMPT_STATUS_SUBTYPE:
        /*-----------------------------------------------------------------*/
            RawReadRelative(RAW_SCRATCH_ID, 2, buf); /* read first 2 bytes after header */
            /* if connection attempt successful */
            if (buf[0] == CONNECTION_ATTEMPT_SUCCESSFUL)
            {
                event     = DRV_WIFI_EVENT_CONNECTION_SUCCESSFUL;
                eventInfo = DRV_WIFI_NO_ADDITIONAL_INFO;
                SignalWiFiConnectionChanged(true);
                #if defined(TCPIP_STACK_USE_IPV6)
                    WF_Initialize_IPV6_Multicast_Filter();
                #endif
                #if defined (TCPIP_STACK_USE_DHCP_CLIENT)
                    RenewDhcp();
                #endif
                SetLogicalConnectionState(true);
            }
            /* else connection attempt failed */
            else
            {
                event     = DRV_WIFI_EVENT_CONNECTION_FAILED;
                eventInfo = (uint16_t)(buf[0] << 8 | buf[1]);   /* contains connection failure code */
                SetLogicalConnectionState(false);
            }
            break;
            
        /*-----------------------------------------------------------------*/
        case WF_EVENT_CONNECTION_LOST_SUBTYPE:
        /*-----------------------------------------------------------------*/ 
            /* read next two data bytes in message
               buf[0] -- 1: Connection temporarily lost  2: Connection permanently lost 3: Connection Reestablished 
               buf[1] -- 0: Beacon Timeout  1: Deauth from AP  */
            RawReadRelative(RAW_SCRATCH_ID, 2, buf);

            if (buf[0] == CONNECTION_TEMPORARILY_LOST)
            {
                event     = DRV_WIFI_EVENT_CONNECTION_TEMPORARILY_LOST;
                eventInfo = (uint16_t)buf[1];    /* lost due to beacon timeout or deauth */
                SignalWiFiConnectionChanged(false);
                
                SetLogicalConnectionState(false);
            }    
            else if (buf[0] == CONNECTION_PERMANENTLY_LOST)
            {
                event     = DRV_WIFI_EVENT_CONNECTION_PERMANENTLY_LOST;
                eventInfo = (uint16_t)buf[1];   /* lost due to beacon timeout or deauth */
                SetLogicalConnectionState(false);
                SignalWiFiConnectionChanged(false);                
            }
            else if (buf[0] == CONNECTION_REESTABLISHED)
            {
                event     = DRV_WIFI_EVENT_CONNECTION_REESTABLISHED;
                eventInfo = (uint16_t)buf[1];    /* originally lost due to beacon timeout or deauth */
                #if defined(TCPIP_STACK_USE_DHCP_CLIENT)
                RenewDhcp();
                #endif
                SignalWiFiConnectionChanged(true);  
                
                SetLogicalConnectionState(true);
            }    
            else
            {
                /* invalid parameter in message */
                SYS_ASSERT(false, "");
            }        
            break;
        
        /*-----------------------------------------------------------------*/                    
        case WF_EVENT_SCAN_RESULTS_READY_SUBTYPE:        
        /*-----------------------------------------------------------------*/
            RawReadRelative(RAW_SCRATCH_ID, 1, buf);
            event = DRV_WIFI_EVENT_SCAN_RESULTS_READY;
            eventInfo = (uint16_t)buf[0];          /* number of scan results */
            break;
            
        /*-----------------------------------------------------------------*/
        case WF_EVENT_SCAN_IE_RESULTS_READY_SUBTYPE:
        /*-----------------------------------------------------------------*/
            event = DRV_WIFI_EVENT_IE_RESULTS_READY;
            /* read indexes 2 and 3 containing the 16-bit value of IE bytes */
            RawReadRelative(RAW_SCRATCH_ID, 2, (uint8_t *)&eventInfo);
            eventInfo = TCPIP_Helper_ntohs(eventInfo);     /* fix endianess of 16-bit value */
            break;    
        
        /*-----------------------------------------------------------------*/
        case WF_EVENT_KEY_CALCULATION_REQUEST_SUBTYPE:
        /*-----------------------------------------------------------------*/
            event = DRV_WIFI_EVENT_KEY_CALCULATION_REQUEST;
            RawReadRelative(RAW_SCRATCH_ID, sizeof(tMgmtIndicatePassphraseReady), (uint8_t *)&passphraseReady);
            WifiAsyncSetEventPending(ASYNC_WPABUTTON_CONNECT);
            break;

        /*-----------------------------------------------------------------*/
        case WF_EVENT_SOFT_AP_EVENT_SUBTYPE:    /* Valid only with 3108 or the later module FW version */
        /*-----------------------------------------------------------------*/
            event = DRV_WIFI_EVENT_SOFT_AP;
            RawReadRelative(RAW_SCRATCH_ID, sizeof(DRV_WIFI_MGMT_INDICATE_SOFT_AP_EVENT), (uint8_t *)&g_softAPEvent);
            break;
            
        /*-----------------------------------------------------------------*/
        case WF_EVENT_DISCONNECT_DONE_SUBTYPE:
        /*-----------------------------------------------------------------*/
            event =  DRV_WIFI_EVENT_DISCONNECT_DONE;
            /* set state to no connection */
            SetLogicalConnectionState(false);
            break;
            
        /*-----------------------------------------------------------------*/
        default:
        /*-----------------------------------------------------------------*/
            SYS_ASSERT(false, "");
            break;        
    }

    /* if the application wants to be notified of the event */
    WF_UserEventsSet(event, eventInfo, 1);
}