Merge pull request #2729 from bulislaw/feature_wifi

HAL: Add Emac interface
pull/2797/merge
Martin Kojtal 2016-09-23 12:52:13 +01:00 committed by GitHub
commit 8bfd108aa5
11 changed files with 576 additions and 16 deletions

View File

@ -21,7 +21,7 @@
/* Interface implementation */ /* Interface implementation */
int EthernetInterface::connect() int EthernetInterface::connect()
{ {
return lwip_bringup(); return lwip_bringup(NULL);
} }
int EthernetInterface::disconnect() int EthernetInterface::disconnect()

View File

@ -0,0 +1,40 @@
/* LWIPIPStackInterface
* Copyright (c) 2015 - 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IPStackInterface.h"
#include "lwip_stack.h"
/** LWIP specific implementation of IPStackInterface */
void IPStackInterface::bringup(emac_interface_t *emac)
{
lwip_bringup(emac);
}
void IPStackInterface::bringdown()
{
lwip_bringdown();
}
const char * IPStackInterface::get_mac_address()
{
return lwip_get_mac_address();
}
const char * IPStackInterface::get_ip_address()
{
return lwip_get_ip_address();
}

View File

@ -0,0 +1,111 @@
/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform.h"
#if DEVICE_EMAC
#include "emac_api.h"
#include "emac_stack_mem.h"
#include "lwip/tcpip.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
static err_t emac_lwip_low_level_output(struct netif *netif, struct pbuf *p)
{
emac_interface_t *mac = (emac_interface_t *)netif->state;
bool ret = mac->ops.link_out(mac, (emac_stack_mem_t *)p);
return ret ? ERR_OK : ERR_IF;
}
static err_t emac_lwip_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
{
/* Only send packets if the link is up */
if (netif->flags & NETIF_FLAG_UP) {
return etharp_output(netif, q, ipaddr);
}
return ERR_CONN;
}
static void emac_lwip_input(void *data, emac_stack_t *buf)
{
struct eth_hdr *ethhdr;
struct pbuf *p = (struct pbuf *)buf;
struct netif *netif = (struct netif *)data;
/* pass all packets to ethernet_input, which decides what packets it supports */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Emac LWIP: IP input error\n"));
pbuf_free(p);
}
}
static void emac_lwip_state_change(void *data, bool up)
{
struct netif *netif = (struct netif *)data;
if (up) {
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, netif, 1);
} else {
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, netif, 1);
}
}
err_t emac_lwip_if_init(struct netif *netif)
{
int err = ERR_OK;
emac_interface_t *mac = (emac_interface_t *)netif->state;
mac->ops.set_link_input_cb(mac, emac_lwip_input, netif);
mac->ops.set_link_state_cb(mac, emac_lwip_state_change, netif);
netif->hwaddr_len = mac->ops.get_hwaddr_size(mac);
mac->ops.get_hwaddr(mac, netif->hwaddr);
netif->mtu = mac->ops.get_mtu_size(mac);
/* Interface capabilities */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
mac->ops.get_ifname(mac, netif->name, 2);
netif->output = emac_lwip_output;
netif->linkoutput = emac_lwip_low_level_output;
if (!mac->ops.power_up(mac)) {
err = ERR_IF;
}
return err;
}
/* That's a compatibility layer for lwip_stack.c, it's already done by emac_interface in power_up and power_down */
void eth_arch_enable_interrupts(void)
{
}
void eth_arch_disable_interrupts(void)
{
}
#endif /* DEVICE_EMAC */

View File

@ -0,0 +1,83 @@
/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform.h"
#if DEVICE_EMAC
#include "emac_stack_mem.h"
#include "pbuf.h"
emac_stack_mem_t *emac_stack_mem_alloc(emac_stack_t* stack, uint32_t size, uint32_t align)
{
struct pbuf *pbuf = pbuf_alloc(PBUF_RAW, size + align, PBUF_RAM);
if (pbuf == NULL) {
return NULL;
}
if (align) {
uint32_t remainder = (uint32_t)pbuf->payload % align;
uint32_t offset = align - remainder;
if (offset >= align) {
offset = align;
}
pbuf->payload = (void*)((char*)pbuf->payload + offset);
pbuf->tot_len -= offset;
pbuf->len -= offset;
}
return (emac_stack_mem_t*)pbuf;
}
void emac_stack_mem_free(emac_stack_t* stack, emac_stack_mem_t *mem)
{
pbuf_free((struct pbuf*)mem);
}
void *emac_stack_mem_ptr(emac_stack_t* stack, emac_stack_mem_t *mem)
{
return ((struct pbuf*)mem)->payload;
}
uint32_t emac_stack_mem_len(emac_stack_t* stack, emac_stack_mem_t *mem)
{
return ((struct pbuf*)mem)->len;
}
void emac_stack_mem_set_len(emac_stack_t* stack, emac_stack_mem_t *mem, uint32_t len)
{
struct pbuf *pbuf = (struct pbuf*)mem;
pbuf->len = len;
}
emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_t* stack, emac_stack_mem_chain_t **chain)
{
struct pbuf **list = (struct pbuf**)chain;
struct pbuf *head = *list;
*list = (*list)->next;
return (emac_stack_mem_t *)head;
}
uint32_t emac_stack_mem_chain_len(emac_stack_t* stack, emac_stack_mem_chain_t *chain)
{
return ((struct pbuf*)chain)->tot_len;
}
#endif /* DEVICE_EMAC */

View File

@ -31,7 +31,12 @@ extern "C" {
void eth_arch_enable_interrupts(void); void eth_arch_enable_interrupts(void);
void eth_arch_disable_interrupts(void); void eth_arch_disable_interrupts(void);
#if DEVICE_EMAC
err_t emac_lwip_if_init(struct netif *netif);
#else /* DEVICE_EMAC */
err_t eth_arch_enetif_init(struct netif *netif); err_t eth_arch_enetif_init(struct netif *netif);
#endif /* DEVICE_MAC */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -30,6 +30,7 @@
#include "lwip/tcp.h" #include "lwip/tcp.h"
#include "lwip/ip.h" #include "lwip/ip.h"
#include "emac_api.h"
/* Static arena of sockets */ /* Static arena of sockets */
static struct lwip_socket { static struct lwip_socket {
@ -142,7 +143,7 @@ const char *lwip_get_ip_address(void)
return lwip_ip_addr[0] ? lwip_ip_addr : 0; return lwip_ip_addr[0] ? lwip_ip_addr : 0;
} }
int lwip_bringup(void) int lwip_bringup(emac_interface_t *emac)
{ {
// Check if we've already connected // Check if we've already connected
if (!lwip_get_mac_address()) { if (!lwip_get_mac_address()) {
@ -157,7 +158,11 @@ int lwip_bringup(void)
sys_arch_sem_wait(&lwip_tcpip_inited, 0); sys_arch_sem_wait(&lwip_tcpip_inited, 0);
memset(&lwip_netif, 0, sizeof lwip_netif); memset(&lwip_netif, 0, sizeof lwip_netif);
#if DEVICE_EMAC
netif_add(&lwip_netif, 0, 0, 0, emac, emac_lwip_if_init, tcpip_input);
#else /* DEVICE_EMAC */
netif_add(&lwip_netif, 0, 0, 0, NULL, eth_arch_enetif_init, tcpip_input); netif_add(&lwip_netif, 0, 0, 0, NULL, eth_arch_enetif_init, tcpip_input);
#endif /* DEVICE_EMAC */
netif_set_default(&lwip_netif); netif_set_default(&lwip_netif);
netif_set_link_callback (&lwip_netif, lwip_netif_link_irq); netif_set_link_callback (&lwip_netif, lwip_netif_link_irq);

View File

@ -18,6 +18,7 @@
#define LWIP_STACK_H #define LWIP_STACK_H
#include "nsapi.h" #include "nsapi.h"
#include "emac_api.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -25,7 +26,7 @@ extern "C" {
// Access to lwip through the nsapi // Access to lwip through the nsapi
int lwip_bringup(void); int lwip_bringup(emac_interface_t *emac);
void lwip_bringdown(void); void lwip_bringdown(void);
extern nsapi_stack_t lwip_stack; extern nsapi_stack_t lwip_stack;

View File

@ -0,0 +1,57 @@
/* IPStackInterface
* Copyright (c) 2015 - 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IP_STACK_INTERFACE_H
#define IP_STACK_INTERFACE_H
#include "emac_api.h"
/**
* IPStackInterface
*
* Abstraction class on top of IP stack, enables WiFiInterface implementation to setup IP stack
*/
class IPStackInterface
{
public:
/**
* Brings up the IP stack using provided @a emac interface
*
* @param emac Emack backend to use
*/
virtual void bringup(emac_interface_t *emac);
/**
* Brings down the IP stack
*/
virtual void bringdown();
/**
* Returns MAC address
*
* @return MAC address in "00:11:22:33:44:55" form
*/
virtual const char *get_mac_address();
/**
* Returns interfaces IP address
*
* @return IP address in "10.11.12.13" form
*/
virtual const char *get_ip_address();
};
#endif /* IP_STACK_INTERFACE_H */

View File

@ -29,7 +29,7 @@ typedef struct wifi_ap {
} wifi_ap_t; } wifi_ap_t;
typedef void (*wifi_ap_scan_cb_t)(wifi_ap_t *ap, void *data); typedef void (*wifi_ap_scan_cb_t)(wifi_ap_t *ap, void *data);
typedef void (*wifi_connect_cb_t)(nsapi_error_t res, void *data); typedef void (*wifi_connect_cb_t)(nsapi_error_t res, wifi_ap_t *ap, void *data);
/** WiFiInterface class /** WiFiInterface class
* *
@ -44,30 +44,34 @@ public:
* *
* @param ssid Name of the network to connect to * @param ssid Name of the network to connect to
* @param pass Security passphrase to connect to the network * @param pass Security passphrase to connect to the network
* @param security Type of encryption for connection * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
* @param timeout Timeout in milliseconds; 0 for no timeout * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0)
* @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
* @return 0 on success, or error code on failure * @return 0 on success, or error code on failure
*/ */
virtual nsapi_error_t connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, virtual nsapi_error_t connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE,
unsigned timeout = 0) = 0; uint8_t channel = 0, unsigned timeout = 0) = 0;
/** Start the interface /** Start the interface
* *
* Attempts to connect to a WiFi network asynchronously, the call will return straight away. If the @a cb was NULL * Attempts to connect to a WiFi network asynchronously, the call will return straight away. If the @a cb was NULL
* you'll need to query @a get_state until it's in NSAPI_IF_STATE_CONNECTED state, otherwise the @a cb will be * you'll need to query @a get_state until it's in NSAPI_IF_STATE_CONNECTED state, otherwise the @a cb will be
* called with connection results. * called with connection results, connected AP details and user data.
* *
* Note: @a ssid and @a pass must be kept until the connection is made, that is the callback has been called or the * Note: @a ssid and @a pass must be kept until the connection is made, that is the callback has been called or the
* state changed to @a NSAPI_IF_STATE_CONNECTED as they are passed by value. * state changed to @a NSAPI_IF_STATE_CONNECTED as they are passed by value.
* *
* @param ssid Name of the network to connect to * @param ssid Name of the network to connect to
* @param pass Security passphrase to connect to the network * @param pass Security passphrase to connect to the network
* @param security Type of encryption for connection * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0)
* @param cb Function to be called when the connect finishes * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
* @param data Arbitrary user data to pass to @a cb function * @param cb Function to be called when the connect finishes (Default: NULL)
* @param data Arbitrary user data to pass to @a cb function (Default: NULL)
* @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
*/ */
virtual void connect_async(const char *ssid, const char *pass,nsapi_security_t security = NSAPI_SECURITY_NONE, virtual void connect_async(const char *ssid, const char *pass,nsapi_security_t security = NSAPI_SECURITY_NONE,
wifi_connect_cb_t cb = NULL, void *data = NULL) = 0; uint8_t channel = 0, wifi_connect_cb_t cb = NULL, void *data = NULL,
unsigned timeout = 0) = 0;
/** Stop the interface /** Stop the interface
* *
@ -77,7 +81,7 @@ public:
/** Get the local MAC address /** Get the local MAC address
* *
* @return Null-terminated representation of the local MAC address * @return Null-terminated representation of the local MAC address in "00:11:22:33:44:55" form
*/ */
virtual const char *get_mac_address() = 0; virtual const char *get_mac_address() = 0;
@ -99,7 +103,7 @@ public:
* *
* @param ap Pointer to allocated array to store discovered AP * @param ap Pointer to allocated array to store discovered AP
* @param count Size of allocated @a res array, or 0 to only count available AP * @param count Size of allocated @a res array, or 0 to only count available AP
* @param timeout Timeout in milliseconds; 0 for no timeout * @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
* @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error
* see @a nsapi_error * see @a nsapi_error
*/ */
@ -112,9 +116,10 @@ public:
* will be always called at least once. * will be always called at least once.
* *
* @param cb Function to be called for every discovered network * @param cb Function to be called for every discovered network
* @param data A user handle that will be passed to @a cb along with the AP data * @param data User handle that will be passed to @a cb along with the AP data (Default: NULL)
* @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
*/ */
virtual void scan_async(wifi_ap_scan_cb_t cb, void *data = NULL) = 0; virtual void scan_async(wifi_ap_scan_cb_t cb, void *data = NULL, unsigned timeout = 0) = 0;
}; };
#endif #endif

View File

@ -0,0 +1,95 @@
/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_EMAC_STACK_MEM_H
#define MBED_EMAC_STACK_MEM_H
#include <stdint.h>
/**
* Stack memory module
*
* This interface provides abstraction for memory modules used in different IP stacks (often to accommodate zero copy).
* Emac interface may be required to accept output packets and provide received data using this stack specific API.
* This header should be implemented for each IP stack, so that we keep emacs module independent.
*/
typedef void emac_stack_mem_t;
typedef void emac_stack_mem_chain_t;
typedef void emac_stack_t;
/**
* Allocates stack memory
*
* @param stack Emac stack context
* @param size Size of memory to allocate
* @param align Memory alignment requirements
* @return Allocated memory struct, or NULL in case of error
*/
emac_stack_mem_t *emac_stack_mem_alloc(emac_stack_t* stack, uint32_t size, uint32_t align);
/**
* Free memory allocated using @a stack_mem_alloc
*
* @param stack Emac stack context
* @param mem Memory to be freed
*/
void emac_stack_mem_free(emac_stack_t* stack, emac_stack_mem_t *mem);
/**
* Return pointer to the payload
*
* @param stack Emac stack context
* @param mem Memory structure
* @return Pointer to the payload
*/
void *emac_stack_mem_ptr(emac_stack_t* stack, emac_stack_mem_t *mem);
/**
* Return actual payload size
*
* @param stack Emac stack context
* @param mem Memory structure
* @return Size in bytes
*/
uint32_t emac_stack_mem_len(emac_stack_t* stack, emac_stack_mem_t *mem);
/**
* Sets the actual payload size (the allocated payload size will not change)
*
* @param stack Emac stack context
* @param mem Memory structure
* @param len Actual payload size
*/
void emac_stack_mem_set_len(emac_stack_t* stack, emac_stack_mem_t *mem, uint32_t len);
/**
* Returns first memory structure from the list and move the head to point to the next node
*
* @param stack Emac stack context
* @param list Pointer to the list
* @return First memory structure from the list
*/
emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_t* stack, emac_stack_mem_chain_t **chain);
/**
* Return total length of the memory chain
*
* @param stack Emac stack context
* @param chain Memory chain
* @return Chain length
*/
uint32_t emac_stack_mem_chain_len(emac_stack_t* stack, emac_stack_mem_chain_t *chain);
#endif /* EMAC_MBED_STACK_MEM_h */

158
hal/hal/emac_api.h Normal file
View File

@ -0,0 +1,158 @@
/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_EMAC_API_H
#define MBED_EMAC_API_H
#include "platform.h"
#if DEVICE_EMAC
#include <stdbool.h>
#include "emac_stack_mem.h"
typedef struct emac_interface emac_interface_t;
/**
* EmacInterface
*
* This interface should be used to abstract low level access to networking hardware
*/
/**
* Callback to be register with Emac interface and to be called fore received packets
*
* @param data Arbitrary user data (IP stack)
* @param buf Received data
*/
typedef void (*emac_link_input_fn)(void *data, emac_stack_mem_chain_t *buf);
/**
* Callback to be register with Emac interface and to be called for link status changes
*
* @param data Arbitrary user data (IP stack)
* @param up Link status
*/
typedef void (*emac_link_state_change_fn)(void *data, bool up);
/**
* Return maximum transmission unit
*
* @param emac Emac interface
* @return MTU in bytes
*/
typedef uint32_t (*emac_get_mtu_size_fn)(emac_interface_t *emac);
/**
* Return interface name
*
* @param emac Emac interface
* @param name Pointer to where the name should be written
* @param size Maximum number of character to copy
*/
typedef void (*emac_get_ifname_fn)(emac_interface_t *emac, char *name, uint8_t size);
/**
* Returns size of the underlying interface HW address size
*
* @param emac Emac interface
* @return HW address size in bytes
*/
typedef uint8_t (*emac_get_hwaddr_size_fn)(emac_interface_t *emac);
/**
* Return interface hw address
*
* Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size
*
* @param emac Emac interface
* @param addr HW address for underlying interface
*/
typedef void (*emac_get_hwaddr_fn)(emac_interface_t *emac, uint8_t *addr);
/**
* Set HW address for interface
*
* Provided address has to be of correct size, see @a get_hwaddr_size
*
* @param emac Emac interface
* @param addr Address to be set
*/
typedef void (*emac_set_hwaddr_fn)(emac_interface_t *emac, uint8_t *addr);
/**
* Sends the packet over the link
*
* That can not be called from an interrupt context.
*
* @param emac Emac interface
* @param buf Packet to be send
* @return True if the packet was send successfully, False otherwise
*/
typedef bool (*emac_link_out_fn)(emac_interface_t *emac, emac_stack_mem_t *buf);
/**
* Initializes the HW
*
* @return True on success, False in case of an error.
*/
typedef bool (*emac_power_up_fn)(emac_interface_t *emac);
/**
* Deinitializes the HW
*
* @param emac Emac interface
*/
typedef void (*emac_power_down_fn)(emac_interface_t *emac);
/**
* Sets a callback that needs to be called for packets received for that interface
*
* @param emac Emac interface
* @param input_cb Function to be register as a callback
* @param data Arbitrary user data to be passed to the callback
*/
typedef void (*emac_set_link_input_cb_fn)(emac_interface_t *emac, emac_link_input_fn input_cb, void *data);
/**
* Sets a callback that needs to be called on link status changes for given interface
*
* @param emac Emac interface
* @param state_cb Function to be register as a callback
* @param data Arbitrary user data to be passed to the callback
*/
typedef void (*emac_set_link_state_cb_fn)(emac_interface_t *emac, emac_link_state_change_fn state_cb, void *data);
typedef struct emac_interface_ops {
emac_get_mtu_size_fn get_mtu_size;
emac_get_ifname_fn get_ifname;
emac_get_hwaddr_size_fn get_hwaddr_size;
emac_get_hwaddr_fn get_hwaddr;
emac_set_hwaddr_fn set_hwaddr;
emac_link_out_fn link_out;
emac_power_up_fn power_up;
emac_power_down_fn power_down;
emac_set_link_input_cb_fn set_link_input_cb;
emac_set_link_state_cb_fn set_link_state_cb;
} emac_interface_ops_t;
typedef struct emac_interface {
const emac_interface_ops_t ops;
void *hw;
} emac_interface_t;
#endif /* DEVICE_EMAC */
#endif /* MBED_EMAC_API_H */