text: /*
   * main.c - sample application for WPS provisioning
   *
   * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
   *
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *    Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   *    Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the
   *    distribution.
   *
   *    Neither the name of Texas Instruments Incorporated nor the names of
   *    its contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
  */
  
  /*
   * Application Name     -   Provisioning WPS
   * Application Overview -   This is a sample application demonstrating how to use WPS
   *                          Wi-Fi provisioning with CC3100. The application provisions
   *                          the device to a Wi-Fi network using the two options
   *                          available w/ WPS:
   *                                 Push button
   *                                 PIN code
   * Application Details  -   http://processors.wiki.ti.com/index.php/CC31xx_Provisioning_WPS_Application
   *                          doc\examples\provisioning_wps.pdf
   */
  
  #include "simplelink.h"
  #include "sl_common.h"
  
  #define APPLICATION_VERSION "1.3.0"
  
  #define SL_STOP_TIMEOUT        0xFF
  
  #define WPS_SSID_NAME        ""    /* AP name to connect to */
  
  /* Application specific status/error codes */
  typedef enum{
      DEVICE_NOT_IN_STATION_MODE = -0x7D0,        /* Choosing this number to avoid overlap w/ host-driver's error codes */
  
      STATUS_CODE_MAX = -0xBB8
  }e_AppStatusCodes;
  
  /*
   * GLOBAL VARIABLES -- Start
   */
  _u8 g_Status = 0;
  /*
   * GLOBAL VARIABLES -- End
   */
  
  /*
   * STATIC FUNCTION DEFINITIONS -- Start
   */
  static _i32 configureSimpleLinkToDefaultState();
  static _i32 initializeAppVariables();
  static _i32 WpsConnectPinCode();
  static _i32 WpsConnectPushButton();
  static _i32 WlanDisconnect();
  static void displayBanner();
  /*
   * STATIC FUNCTION DEFINITIONS -- End
   */
  
  /*
   * ASYNCHRONOUS EVENT HANDLERS -- Start
   */
  /*!
      \brief This function handles WLAN events
  
      \param[in]      pWlanEvent is the event passed to the handler
  
      \return         None
  
      \note
  
      \warning
  */
  void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent)
  {
      if(pWlanEvent == NULL)
      {
          CLI_Write(" [WLAN EVENT] NULL Pointer Error \n\r");
          return;
      }
      
      switch(pWlanEvent->Event)
      {
          case SL_WLAN_CONNECT_EVENT:
          {
              SET_STATUS_BIT(g_Status, STATUS_BIT_CONNECTION);
  
              /*
               * Information about the connected AP (like name, MAC etc) will be
               * available in 'slWlanConnectAsyncResponse_t' - Applications
               * can use it if required
               *
               * slWlanConnectAsyncResponse_t *pEventData = NULL;
               * pEventData = &pWlanEvent->EventData.STAandP2PModeWlanConnected;
               *
               */
          }
          break;
  
          case SL_WLAN_DISCONNECT_EVENT:
          {
              slWlanConnectAsyncResponse_t*  pEventData = NULL;
  
              CLR_STATUS_BIT(g_Status, STATUS_BIT_CONNECTION);
              CLR_STATUS_BIT(g_Status, STATUS_BIT_IP_ACQUIRED);
  
              pEventData = &pWlanEvent->EventData.STAandP2PModeDisconnected;
  
              /* If the user has initiated 'Disconnect' request, 'reason_code' is
               * SL_USER_INITIATED_DISCONNECTION */
              if(SL_WLAN_DISCONNECT_USER_INITIATED_DISCONNECTION == pEventData->reason_code)
              {
                  CLI_Write(" Device disconnected from the AP on application's request \n\r");
              }
              else
              {
                  CLI_Write(" Device disconnected from the AP on an ERROR..!! \n\r");
              }
          }
          break;
  
          default:
          {
              CLI_Write(" [WLAN EVENT] Unexpected event \n\r");
          }
          break;
      }
  }
  
  /*!
      \brief This function handles events for IP address acquisition via DHCP
             indication
  
      \param[in]      pNetAppEvent is the event passed to the handler
  
      \return         None
  
      \note
  
      \warning
  */
  void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent)
  {
      if(pNetAppEvent == NULL)
      {
          CLI_Write(" [NETAPP EVENT] NULL Pointer Error \n\r");
          return;
      }
   
      switch(pNetAppEvent->Event)
      {
          case SL_NETAPP_IPV4_IPACQUIRED_EVENT:
          {
              SET_STATUS_BIT(g_Status, STATUS_BIT_IP_ACQUIRED);
  
              /*
               * Information about the connection (like IP, gateway address etc)
               * will be available in 'SlIpV4AcquiredAsync_t'
               * Applications can use it if required
               *
               * SlIpV4AcquiredAsync_t *pEventData = NULL;
               * pEventData = &pNetAppEvent->EventData.ipAcquiredV4;
               *
               */
          }
          break;
  
          default:
          {
              CLI_Write(" [NETAPP EVENT] Unexpected event \n\r");
          }
          break;
      }
  }
  
  /*!
      \brief This function handles callback for the HTTP server events
  
      \param[in]      pHttpEvent - Contains the relevant event information
      \param[in]      pHttpResponse - Should be filled by the user with the
                      relevant response information
  
      \return         None
  
      \note
  
      \warning
  */
  void SimpleLinkHttpServerCallback(SlHttpServerEvent_t *pHttpEvent,
                                    SlHttpServerResponse_t *pHttpResponse)
  {
      /* Unused in this application */
      CLI_Write(" [HTTP EVENT] Unexpected event \n\r");
  }
  
  /*!
      \brief This function handles general error events indication
  
      \param[in]      pDevEvent is the event passed to the handler
  
      \return         None
  */
  void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent)
  {
      /*
       * Most of the general errors are not FATAL are are to be handled
       * appropriately by the application
       */
      CLI_Write(" [GENERAL EVENT] \n\r");
  }
  
  /*!
      \brief This function handles socket events indication
  
      \param[in]      pSock is the event passed to the handler
  
      \return         None
  */
  void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
  {
      /*
       * This application doesn't work w/ socket - Hence not handling these events
       */
      CLI_Write(" [SOCK EVENT] Unexpected event \n\r");
  }
  /*
   * ASYNCHRONOUS EVENT HANDLERS -- End
   */
  
  /*
   * Application's entry point
   */
  int main(int argc, char** argv)
  {
      _i32 retVal = -1;
  
      retVal = initializeAppVariables();
      ASSERT_ON_ERROR(retVal);
  
      /* Stop WDT and initialize the system-clock of the MCU
         These functions needs to be implemented in PAL */
      stopWDT();
      initClk();
  
      /* Configure command line interface */
      CLI_Configure();
  
      displayBanner();
  
  
      /*
       * Following function configures the device to default state by cleaning
       * the persistent settings stored in NVMEM (viz. connection profiles &
       * policies, power policy etc)
       *
       * Applications may choose to skip this step if the developer is sure
       * that the device is in its default state at start of application
       *
       * Note that all profiles and persistent settings that were done on the
       * device will be lost
       */
      retVal = configureSimpleLinkToDefaultState();
      if(retVal < 0)
      {
          if (DEVICE_NOT_IN_STATION_MODE == retVal)
          {
              CLI_Write(" Failed to configure the device in its default state \n\r");
          }
  
          LOOP_FOREVER();
      }
  
      CLI_Write(" Device is configured in default state \n\r");
  
      /*
       * Assumption is that the device is configured in station mode already
       * and it is in its default state
       */
      /* Initializing the CC3100 device */
      retVal = sl_Start(0, 0, 0);
      if ((retVal < 0) ||
          (ROLE_STA != retVal) )
      {
          CLI_Write(" Failed to start the device \n\r");
          LOOP_FOREVER();
      }
  
      CLI_Write(" Device started as STATION \n\r");
  
      /* Delete all profiles (0xFF) stored */
      retVal = sl_WlanProfileDel(0xFF);
      if(retVal < 0)
          LOOP_FOREVER();
  
      /* Reset policy settings */
      retVal = sl_WlanPolicySet(SL_POLICY_CONNECTION, SL_CONNECTION_POLICY(0,0,0,0,0), 0, 0);
      if(retVal < 0)
          LOOP_FOREVER();
  
      CLI_Write(" Establishing connection w/ an AP using wps-push button \n\r");
  
      /* Connecting to WLAN AP with WPS security, using Push Button method.
       * The AP parameters are set with static values defined at the top.
       * After this function call we will be connected and have IP address. */
      retVal = WpsConnectPushButton();
      if(retVal < 0)
      {
          CLI_Write(" Failed to establish connection w/ an AP \n\r");
          LOOP_FOREVER();
      }
  
      CLI_Write(" Connection established w/ AP and IP is acquired \n\r");
  
      /* Disconnect from the WLAN AP.
       * After this function call we will be disconnected
       */
      retVal = WlanDisconnect();
      if(retVal < 0)
      {
          LOOP_FOREVER();
      }
  
      CLI_Write(" Establishing connection w/ an AP using wps-pin \n\r");
  
      /* Connecting to WLAN AP with WPS security, using Pin Code method.
       * The pin code is stored in the SFlash (should be updated by the customer)
       * the default pin code is 35072317.
       * The AP parameters are set with static values defined at the top.
       * After this function call we will be connected and have IP address. */
      retVal = WpsConnectPinCode();
      if(retVal < 0)
      {
          CLI_Write(" Failed to establish connection w/ an AP \n\r");
          LOOP_FOREVER();
      }
  
      CLI_Write(" Connection established w/ AP and IP is acquired \n\r");
  
      /* Disconnect from the WLAN AP.
       * After this function call we will be disconnected
       */
      retVal = WlanDisconnect();
      if(retVal < 0)
      {
          LOOP_FOREVER();
      }
  ;
  
      /* Stop the CC3100 device */
      retVal = sl_Stop(SL_STOP_TIMEOUT);
      if(retVal < 0)
          LOOP_FOREVER();
  
      return 0;
  }
  
  /*!
      \brief This function configure the SimpleLink device in its default state. It:
             - Sets the mode to STATION
             - Configures connection policy to Auto and AutoSmartConfig
             - Deletes all the stored profiles
             - Enables DHCP
             - Disables Scan policy
             - Sets Tx power to maximum
             - Sets power policy to normal
             - Unregisters mDNS services
             - Remove all filters
  
      \param[in]      none
  
      \return         On success, zero is returned. On error, negative is returned
  */
  static _i32 configureSimpleLinkToDefaultState()
  {
      SlVersionFull   ver = {0};
      _WlanRxFilterOperationCommandBuff_t  RxFilterIdMask = {0};
  
      _u8           val = 1;
      _u8           configOpt = 0;
      _u8           configLen = 0;
      _u8           power = 0;
  
      _i32          retVal = -1;
      _i32          mode = -1;
  
      mode = sl_Start(0, 0, 0);
      ASSERT_ON_ERROR(mode);
  
      /* If the device is not in station-mode, try configuring it in station-mode */
      if (ROLE_STA != mode)
      {
          if (ROLE_AP == mode)
          {
              /* If the device is in AP mode, we need to wait for this event before doing anything */
              while(!IS_IP_ACQUIRED(g_Status)) { _SlNonOsMainLoopTask(); }
          }
  
          /* Switch to STA role and restart */
          retVal = sl_WlanSetMode(ROLE_STA);
          ASSERT_ON_ERROR(retVal);
  
          retVal = sl_Stop(SL_STOP_TIMEOUT);
          ASSERT_ON_ERROR(retVal);
  
          retVal = sl_Start(0, 0, 0);
          ASSERT_ON_ERROR(retVal);
  
          /* Check if the device is in station again */
          if (ROLE_STA != retVal)
          {
              /* We don't want to proceed if the device is not coming up in station-mode */
              ASSERT_ON_ERROR(DEVICE_NOT_IN_STATION_MODE);
          }
      }
  
      /* Get the device's version-information */
      configOpt = SL_DEVICE_GENERAL_VERSION;
      configLen = sizeof(ver);
      retVal = sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION, &configOpt, &configLen, (_u8 *)(&ver));
      ASSERT_ON_ERROR(retVal);
  
      /* Set connection policy to Auto + SmartConfig (Device's default connection policy) */
      retVal = sl_WlanPolicySet(SL_POLICY_CONNECTION, SL_CONNECTION_POLICY(1, 0, 0, 0, 1), NULL, 0);
      ASSERT_ON_ERROR(retVal);
  
      /* Remove all profiles */
      retVal = sl_WlanProfileDel(0xFF);
      ASSERT_ON_ERROR(retVal);
  
      /*
       * Device in station-mode. Disconnect previous connection if any
       * The function returns 0 if 'Disconnected done', negative number if already disconnected
       * Wait for 'disconnection' event if 0 is returned, Ignore other return-codes
       */
      retVal = sl_WlanDisconnect();
      if(0 == retVal)
      {
          /* Wait */
          while(IS_CONNECTED(g_Status)) { _SlNonOsMainLoopTask(); }
      }
  
      /* Enable DHCP client*/
      retVal = sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE,1,1,&val);
      ASSERT_ON_ERROR(retVal);
  
      /* Disable scan */
      configOpt = SL_SCAN_POLICY(0);
      retVal = sl_WlanPolicySet(SL_POLICY_SCAN , configOpt, NULL, 0);
      ASSERT_ON_ERROR(retVal);
  
      /* Set Tx power level for station mode
         Number between 0-15, as dB offset from max power - 0 will set maximum power */
      power = 0;
      retVal = sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, 1, (_u8 *)&power);
      ASSERT_ON_ERROR(retVal);
  
      /* Set PM policy to normal */
      retVal = sl_WlanPolicySet(SL_POLICY_PM , SL_NORMAL_POLICY, NULL, 0);
      ASSERT_ON_ERROR(retVal);
  
      /* Unregister mDNS services */
      retVal = sl_NetAppMDNSUnRegisterService(0, 0);
      ASSERT_ON_ERROR(retVal);
  
      /* Remove  all 64 filters (8*8) */
      pal_Memset(RxFilterIdMask.FilterIdMask, 0xFF, 8);
      retVal = sl_WlanRxFilterSet(SL_REMOVE_RX_FILTER, (_u8 *)&RxFilterIdMask,
                         sizeof(_WlanRxFilterOperationCommandBuff_t));
      ASSERT_ON_ERROR(retVal);
  
      retVal = sl_Stop(SL_STOP_TIMEOUT);
      ASSERT_ON_ERROR(retVal);
  
      retVal = initializeAppVariables();
      ASSERT_ON_ERROR(retVal);
  
      return retVal; /* Success */
  }
  
  /*!
      \brief Connecting to a WLAN Access point using WPS push button feature
  
      This function connects to the required AP using WPS push button feature.
      The function will return only once we are connected and have acquired IP
      address
  
      \param[in]      None
  
      \return     0 on success, negative error-code on error
  
      \note
  
      \warning        If the WLAN connection fails or we don't aquire an IP
                      address, We will be stuck in this function forever.
  */
  static _i32 WpsConnectPushButton()
  {
      SlSecParams_t secParams = {0};
      _i32 retVal = 0;
  
      secParams.Key = "";
      secParams.KeyLen = 0;
      secParams.Type = SL_SEC_TYPE_WPS_PBC;;
  
      retVal = sl_WlanConnect(WPS_SSID_NAME, pal_Strlen(WPS_SSID_NAME), 0, &secParams,0);
      ASSERT_ON_ERROR(retVal);
  
      /* Wait */
      while((!IS_CONNECTED(g_Status)) || (!IS_IP_ACQUIRED(g_Status))) { _SlNonOsMainLoopTask(); }
  
      return SUCCESS;
  }
  
  /*!
      \brief Connecting to a WLAN Access point using WPS pin feature
  
      This function connects to the required AP using WPS pin feature.
      The function will return only once we are connected and have acquired IP
      address
  
      \param[in]      None
  
      \return     0 on success, negative error-code on error
  
      \note
  
      \warning        If the WLAN connection fails or we don't aquire an IP
                      address, We will be stuck in this function forever.
  */
  static _i32 WpsConnectPinCode()
  {
      SlSecParams_t secParams = {0};
      _i32 retVal = 0;
  
      secParams.Key = "35072317";
      secParams.KeyLen = 8;
      secParams.Type = SL_SEC_TYPE_WPS_PIN;;
  
      retVal = sl_WlanConnect(WPS_SSID_NAME, pal_Strlen(WPS_SSID_NAME), 0, &secParams, 0);
      ASSERT_ON_ERROR(retVal);
  
      /* Wait */
      while((!IS_CONNECTED(g_Status)) || (!IS_IP_ACQUIRED(g_Status))) { _SlNonOsMainLoopTask(); }
  
      return SUCCESS;
  }
  
  /*!
      \brief Disconnect from the Access point
  
      \param[in]      None
  
      \return         None
  
      \note
  
      \warning        If fails to disconnect, We will be stuck in this
                      function forever.
  */
  static _i32 WlanDisconnect()
  {
      _i32 retVal = -1;
  
      retVal = sl_WlanDisconnect();
      if(0 == retVal)
      {
          /* Wait */
          while(IS_CONNECTED(g_Status)) { _SlNonOsMainLoopTask(); }
      }
  
      return retVal;
  }
  
  /*!
      \brief This function initializes the application variables
  
      \param[in]  None
  
      \return     0 on success, negative error-code on error
  */
  static _i32 initializeAppVariables()
  {
      g_Status = 0;
  
      return SUCCESS;
  }
  
  /*!
      \brief This function displays the application's banner
  
      \param      None
  
      \return     None
  */
  static void displayBanner()
  {
      CLI_Write("\n\r\n\r");
      CLI_Write(" Provisioning WPS application - Version ");
      CLI_Write(APPLICATION_VERSION);
      CLI_Write("\n\r*******************************************************************************\n\r");
  }
  