Webserver+3d print

Dependents:   Nucleo

cyclone_tcp/drivers/wilc1000_driver.c

Committer:
Sergunb
Date:
2017-02-04
Revision:
0:8918a71cdbe9

File content as of revision 0:8918a71cdbe9:

/**
 * @file wilc1000_driver.c
 * @brief WILC1000 Wi-Fi controller
 *
 * @section License
 *
 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneTCP Open.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.7.6
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL NIC_TRACE_LEVEL

//Dependencies
#include "driver/include/m2m_wifi.h"
#include "core/net.h"
#include "wilc1000_driver.h"
#include "wilc1000_config.h"
#include "debug.h"

//Underlying network interface
static NetInterface *wilc1000StaInterface = NULL;
static NetInterface *wilc1000ApInterface = NULL;

//Transmit buffer
static uint8_t txBuffer[WILC1000_TX_BUFFER_SIZE];
//Receive buffer
static uint8_t rxBuffer[WILC1000_RX_BUFFER_SIZE];


/**
 * @brief WILC1000 driver (STA mode)
 **/

const NicDriver wilc1000StaDriver =
{
   NIC_TYPE_ETHERNET,
   ETH_MTU,
   wilc1000Init,
   wilc1000Tick,
   wilc1000EnableIrq,
   wilc1000DisableIrq,
   wilc1000EventHandler,
   wilc1000SendPacket,
   wilc1000SetMulticastFilter,
   NULL,
   NULL,
   NULL,
   TRUE,
   TRUE,
   TRUE,
   TRUE
};


/**
 * @brief WILC1000 driver (AP mode)
 **/

const NicDriver wilc1000ApDriver =
{
   NIC_TYPE_ETHERNET,
   ETH_MTU,
   wilc1000Init,
   wilc1000Tick,
   wilc1000EnableIrq,
   wilc1000DisableIrq,
   wilc1000EventHandler,
   wilc1000SendPacket,
   wilc1000SetMulticastFilter,
   NULL,
   NULL,
   NULL,
   TRUE,
   TRUE,
   TRUE,
   TRUE
};


/**
 * @brief WILC1000 initialization
 * @param[in] interface Underlying network interface
 * @return Error code
 **/

error_t wilc1000Init(NetInterface *interface)
{
   int8_t status;
   tstrWifiInitParam param;
   MacAddr staMacAddr;
   MacAddr apMacAddr;

   //STA or AP mode?
   if(interface->nicDriver == &wilc1000StaDriver)
   {
      //Debug message
      TRACE_INFO("Initializing WILC1000 (STA mode)...\r\n");
      //Save underlying network interface
      wilc1000StaInterface = interface;
   }
   else
   {
      //Debug message
      TRACE_INFO("Initializing WILC1000 (AP mode)...\r\n");
      //Save underlying network interface
      wilc1000ApInterface = interface;
   }

   //Start of exception handling block
   do
   {
      //Initialization sequence is performed once
      if(wilc1000StaInterface == NULL || wilc1000ApInterface == NULL)
      {
         //Low-level initialization
         status = nm_bsp_init();

         //Check status code
         if(status != M2M_SUCCESS)
            break;

         //Set default parameters
         memset(&param, 0, sizeof(param));

         //Register callback functions
         param.pfAppWifiCb = wilc1000AppWifiEvent;
         param.pfAppMonCb = NULL;
         param.strEthInitParam.pfAppWifiCb = NULL;
         param.strEthInitParam.pfAppEthCb = wilc1000AppEthEvent;

         //Set receive buffer
         param.strEthInitParam.au8ethRcvBuf = rxBuffer;
         param.strEthInitParam.u16ethRcvBufSize = WILC1000_RX_BUFFER_SIZE;

         //Initialize WILC1000 controller
         status = m2m_wifi_init(&param);

         //Check status code
         if(status != M2M_SUCCESS)
            break;
      }

      //Retrieve current MAC addresses
      status = m2m_wifi_get_mac_address(staMacAddr.b, apMacAddr.b);

      //Check status code
      if(status != M2M_SUCCESS)
         break;

      //Optionally set the MAC address
      if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
      {
         //Use the factory preprogrammed MAC address
         if(interface == wilc1000StaInterface)
            interface->macAddr = staMacAddr;
         else
            interface->macAddr = apMacAddr;

         //Generate the 64-bit interface identifier
         macAddrToEui64(&interface->macAddr, &interface->eui64);
      }
      else
      {
         //Override the factory preprogrammed address
         if(interface == wilc1000StaInterface)
            staMacAddr = interface->macAddr;
         else
            apMacAddr = interface->macAddr;

         //Assign MAC addresses
         status = m2m_wifi_set_mac_address(apMacAddr.b, staMacAddr.b);

         //Check status code
         if(status != M2M_SUCCESS)
            break;
      }

      //End of exception handling block
   } while(0);

   //WILC1000 is now ready to send
   osSetEvent(&interface->nicTxEvent);

   //Return status code
   if(status == M2M_SUCCESS)
      return NO_ERROR;
   else
      return ERROR_FAILURE;
}


/**
 * @brief WILC1000 timer handler
 *
 * This routine is periodically called by the TCP/IP stack to
 * handle periodic operations such as polling the link state
 *
 * @param[in] interface Underlying network interface
 **/

void wilc1000Tick(NetInterface *interface)
{
}


/**
 * @brief Enable interrupts
 * @param[in] interface Underlying network interface
 **/

void wilc1000EnableIrq(NetInterface *interface)
{
}


/**
 * @brief Disable interrupts
 * @param[in] interface Underlying network interface
 **/

void wilc1000DisableIrq(NetInterface *interface)
{
}


/**
 * @brief WILC1000 interrupt service routine
 * @return TRUE if a higher priority task must be woken. Else FALSE is returned
 **/

bool_t wilc1000IrqHandler(void)
{
   bool_t flag;

   //This flag will be set if a higher priority task must be woken
   flag = FALSE;

   //STA and/or AP mode?
   if(wilc1000StaInterface != NULL)
      wilc1000StaInterface->nicEvent = TRUE;
   else if(wilc1000ApInterface != NULL)
      wilc1000ApInterface->nicEvent = TRUE;

   //Notify the TCP/IP stack of the event
   flag = osSetEventFromIsr(&netEvent);

   //A higher priority task must be woken?
   return flag;
}


/**
 * @brief WILC1000 event handler
 * @param[in] interface Underlying network interface
 **/

void wilc1000EventHandler(NetInterface *interface)
{
   //Process Wi-Fi events
   m2m_wifi_handle_events(NULL);
}


/**
 * @brief Send a packet
 * @param[in] interface Underlying network interface
 * @param[in] buffer Multi-part buffer containing the data to send
 * @param[in] offset Offset to the first data byte
 * @return Error code
 **/

error_t wilc1000SendPacket(NetInterface *interface,
   const NetBuffer *buffer, size_t offset)
{
   int8_t status;
   size_t length;

   //Retrieve the length of the packet
   length = netBufferGetLength(buffer) - offset;

   //Check the frame length
   if(length > WILC1000_TX_BUFFER_SIZE)
   {
      //The transmitter can accept another packet
      osSetEvent(&interface->nicTxEvent);
      //Report an error
      return ERROR_INVALID_LENGTH;
   }

   //Make sure the link is up before transmitting the frame
   if(!interface->linkState)
   {
      //The transmitter can accept another packet
      osSetEventFromIsr(&interface->nicTxEvent);
      //Drop current packet
      return NO_ERROR;
   }

   //Copy user data to the transmit buffer
   netBufferRead(txBuffer + M2M_ETHERNET_HDR_OFFSET + M2M_ETH_PAD_SIZE,
      buffer, offset, length);

   //STA or AP mode?
   if(interface == wilc1000StaInterface)
   {
      //Send packet
      status = m2m_wifi_send_ethernet_pkt(txBuffer, length);
   }
   else
   {
      //Send packet
      status = m2m_wifi_send_ethernet_pkt_ifc1(txBuffer, length);
   }

   //The transmitter can accept another packet
   osSetEvent(&interface->nicTxEvent);

   //Return status code
   if(status == M2M_SUCCESS)
      return NO_ERROR;
   else
      return ERROR_FAILURE;
}


/**
 * @brief Configure multicast MAC address filtering
 * @param[in] interface Underlying network interface
 * @return Error code
 **/

error_t wilc1000SetMulticastFilter(NetInterface *interface)
{
   uint_t i;
   uint_t refCount;
   MacFilterEntry *entry;

   //Debug message
   TRACE_INFO("Updating WILC1000 multicast filter...\r\n");

   //The MAC filter table contains the multicast MAC addresses
   //to accept when receiving an Ethernet frame
   for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
   {
      //Point to the current entry
      entry = &interface->macMulticastFilter[i];

      //Valid entry?
      if(!macCompAddr(&entry->addr, &MAC_UNSPECIFIED_ADDR))
      {
         //Check whether the multicast MAC address has already been registered
         //on the alternate interface
         if(interface == wilc1000StaInterface)
            refCount = wilc1000GetAddrRefCount(wilc1000ApInterface, &entry->addr);
         else
            refCount = wilc1000GetAddrRefCount(wilc1000StaInterface, &entry->addr);

         //Ensure that there are not duplicate address entries in the table
         if(refCount == 0)
         {
            //Update MAC filter table only if necessary
            if(entry->addFlag)
            {
               //Add a new entry to the MAC filter table
               m2m_wifi_enable_mac_mcast(entry->addr.b, TRUE);
            }
            else if(entry->deleteFlag)
            {
               //Remove the current entry from the MAC filter table
               m2m_wifi_enable_mac_mcast(entry->addr.b, FALSE);
            }
         }
      }
   }

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Get reference count for the specified multicast MAC address
 * @param[in] interface Underlying network interface
 * @param[in] macAddr MAC address
 * @return Reference count
 **/

bool_t wilc1000GetAddrRefCount(NetInterface *interface, const MacAddr *macAddr)
{
   uint_t i;
   uint_t refCount;
   MacFilterEntry *entry;

   //Clear reference count
   refCount = 0;

   //Valid network interface?
   if(interface != NULL)
   {
      //Go through the multicast filter table
      for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
      {
         //Point to the current entry
         entry = &interface->macMulticastFilter[i];

         //Valid entry?
         if(entry->refCount > 0)
         {
            //Check whether the specified MAC address matches
            //a multicast address in the table
            if(macCompAddr(&entry->addr, macAddr))
            {
               //Get reference count
               refCount = entry->refCount;
               //We are done
               break;
            }
         }
      }
   }

   //Return reference count
   return refCount;
}


/**
 * @brief Callback function that handles Wi-Fi events
 * @param[in] msgType Type of notification
 * @param[in] msg Pointer to the buffer containing the notification parameters
 **/

void wilc1000AppWifiEvent(uint8_t msgType, void *msg)
{
   tstrM2mWifiStateChanged *stateChangedMsg;

   //Debug message
   TRACE_INFO("WILC1000 Wi-Fi event callback\r\n");

   //Check message type
   if(msgType == M2M_WIFI_RESP_FIRMWARE_STRTED)
   {
      //Debug message
      TRACE_INFO("  M2M_WIFI_RESP_FIRMWARE_STRTED\r\n");
   }
   else if(msgType == M2M_WIFI_RESP_CON_STATE_CHANGED)
   {
      //Debug message
      TRACE_INFO("  M2M_WIFI_RESP_CON_STATE_CHANGED\r\n");

      //Connection state
      stateChangedMsg = (tstrM2mWifiStateChanged*) msg;

      //Check interface identifier
      if(stateChangedMsg->u8IfcId == INTERFACE_1)
      {
         //Check whether STA mode is enabled
         if(wilc1000StaInterface != NULL)
         {
            //Check link state
            if(stateChangedMsg->u8CurrState == M2M_WIFI_CONNECTED)
            {
               //Link is up
               wilc1000StaInterface->linkState = TRUE;
            }
            else
            {
               //Link is down
               wilc1000StaInterface->linkState = FALSE;
            }

            //Process link state change event
            nicNotifyLinkChange(wilc1000StaInterface);
         }
      }
      else if(stateChangedMsg->u8IfcId == INTERFACE_2)
      {
         //Check whether AP mode is enabled
         if(wilc1000ApInterface != NULL)
         {
            //Check link state
            if(stateChangedMsg->u8CurrState == M2M_WIFI_CONNECTED)
            {
               //Link is up
               wilc1000ApInterface->linkState = TRUE;
            }
            else
            {
               //Link is down
               wilc1000ApInterface->linkState = FALSE;
            }

            //Process link state change event
            nicNotifyLinkChange(wilc1000ApInterface);
         }
      }
   }

#if defined(CONF_WILC_EVENT_HOOK)
   //Release exclusive access
   osReleaseMutex(&netMutex);
   //Invoke user callback function
   CONF_WILC_EVENT_HOOK(msgType, msg);
   //Get exclusive access
   osAcquireMutex(&netMutex);
#endif
}


/**
 * @brief Callback function that handles events in bypass mode
 * @param[in] msgType Type of notification
 * @param[in] msg Pointer to the buffer containing the notification parameters
 * @param[in] ctrlBuf Pointer to the control buffer
 **/

void wilc1000AppEthEvent(uint8_t msgType, void *msg, void *ctrlBuf)
{
   size_t length;
   uint8_t *packet;
   tstrM2mIpCtrlBuf *ctrl;

   //Debug message
   TRACE_DEBUG("WILC1000 RX event callback\r\n");

   //Point to the control buffer
   ctrl = (tstrM2mIpCtrlBuf *) ctrlBuf;

   //Check message type
   if(msgType == M2M_WIFI_RESP_ETHERNET_RX_PACKET)
   {
      //Debug message
      TRACE_DEBUG("  M2M_WIFI_RESP_ETHERNET_RX_PACKET\r\n");

      //Point to the beginning of the packet
      packet = rxBuffer + ctrl->u8DataOffset;
      //Retrieve the length of the packet
      length = ctrl->u16DataSize;

      //Check interface identifier
      if(ctrl->u8IfcId == INTERFACE_1)
      {
         //Valid interface?
         if(wilc1000StaInterface != NULL)
         {
            //Check destination MAC address
            if(wilc1000ApInterface != NULL)
            {
               if(macCompAddr(packet, wilc1000ApInterface->macAddr.b))
                  macCopyAddr(packet, wilc1000StaInterface->macAddr.b);
            }

            //Pass the packet to the upper layer (STA mode)
            nicProcessPacket(wilc1000StaInterface, packet, length);
         }
      }
      else if(ctrl->u8IfcId == INTERFACE_2)
      {
         //Valid interface?
         if(wilc1000ApInterface != NULL)
         {
            //Check destination MAC address
            if(wilc1000StaInterface != NULL)
            {
               if(macCompAddr(packet, wilc1000StaInterface->macAddr.b))
                  macCopyAddr(packet, wilc1000ApInterface->macAddr.b);
            }

            //Pass the packet to the upper layer (STA mode)
            nicProcessPacket(wilc1000ApInterface, packet, length);
         }
      }
   }
}