drivers/wifi: Add winc1500 WiFi driver
Adding support for WINC1500 WiFi chip. It introduces the wifi drivers sub-directory. It provides a Full-MAC for 802.11 and an offloaded network stack as well. The driver uses Atmel's winc1500 HAL. Signed-off-by: Dario Pennisi <dario@iptronix.com> Signed-off-by: Anas Nashif <anas.nashif@intel.com> Signed-off-by: Massimiliano Agneni <massimiliano.agneni@iptronix.com> Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
4d1da3f723
commit
9bdf1cdb0e
9 changed files with 1372 additions and 1 deletions
9
drivers/wifi/CMakeLists.txt
Normal file
9
drivers/wifi/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
if(CONFIG_WIFI_WINC1500)
|
||||||
|
zephyr_include_directories(./)
|
||||||
|
|
||||||
|
zephyr_sources(
|
||||||
|
wifi_winc1500_nm_bsp.c
|
||||||
|
wifi_winc1500_nm_bus_wrapper.c
|
||||||
|
wifi_winc1500.c
|
||||||
|
)
|
||||||
|
endif()
|
|
@ -43,4 +43,6 @@ config WIFI_OFFLOAD
|
||||||
help
|
help
|
||||||
Enable support for Full-MAC WiFi devices.
|
Enable support for Full-MAC WiFi devices.
|
||||||
|
|
||||||
|
source "drivers/wifi/Kconfig.winc1500"
|
||||||
|
|
||||||
endif # WIFI
|
endif # WIFI
|
||||||
|
|
62
drivers/wifi/Kconfig.winc1500
Normal file
62
drivers/wifi/Kconfig.winc1500
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# Kconfig - Atmel WINC1500 WiFi driver options
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 Intel Corporation
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
menuconfig WIFI_WINC1500
|
||||||
|
bool "WINC1500 driver support"
|
||||||
|
default n
|
||||||
|
select ATMEL_WINC1500
|
||||||
|
|
||||||
|
if WIFI_WINC1500
|
||||||
|
|
||||||
|
config WIFI_WINC1500_NAME
|
||||||
|
string "Driver name"
|
||||||
|
default "WINC1500"
|
||||||
|
|
||||||
|
config WIFI_WINC1500_SPI_DRV_NAME
|
||||||
|
string "SPI device where WINC1500 is connected"
|
||||||
|
default "SPI_1"
|
||||||
|
help
|
||||||
|
Specify the device name of the SPI device to which WINC1500 is
|
||||||
|
connected.
|
||||||
|
|
||||||
|
config WIFI_WINC1500_SPI_SLAVE
|
||||||
|
int "SPI Slave Select where WINC1500 is connected"
|
||||||
|
default 1
|
||||||
|
help
|
||||||
|
Specify the slave select pin of the SPI to which WINC1500 is
|
||||||
|
connected.
|
||||||
|
|
||||||
|
config WIFI_WINC1500_SPI_FREQ
|
||||||
|
int "SPI frequency to use with WINC1500"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
SPI frequency to use with WINC1500
|
||||||
|
|
||||||
|
# TODO GPIO
|
||||||
|
|
||||||
|
config WIFI_WINC1500_SSID
|
||||||
|
string "SSID the chip shall try to connect to"
|
||||||
|
default ""
|
||||||
|
help
|
||||||
|
Set the SSID you want the chip to connect to. Note: only WPA PSK
|
||||||
|
based AP is supported. Test purpose only, a full featured interface
|
||||||
|
will be used at some point for more flexible configuration.
|
||||||
|
|
||||||
|
config WIFI_WINC1500_SSID_LENGTH
|
||||||
|
int "Length of the SSID (do not count the \0)"
|
||||||
|
default 0
|
||||||
|
help
|
||||||
|
SSID length, without counting the terminal character '\0'
|
||||||
|
|
||||||
|
config WIFI_WINC1500_PSK
|
||||||
|
string "Pre-Shared Key (human readable)"
|
||||||
|
default ""
|
||||||
|
help
|
||||||
|
Set the PSK for the given SSID.
|
||||||
|
|
||||||
|
endif # WIFI_WINC1500
|
924
drivers/wifi/wifi_winc1500.c
Normal file
924
drivers/wifi/wifi_winc1500.c
Normal file
|
@ -0,0 +1,924 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017 IpTronix
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_WIFI_LEVEL
|
||||||
|
#define SYS_LOG_DOMAIN "dev/winc1500"
|
||||||
|
#include <logging/sys_log.h>
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <net/net_pkt.h>
|
||||||
|
#include <net/net_if.h>
|
||||||
|
#include <net/net_l2.h>
|
||||||
|
#include <net/net_context.h>
|
||||||
|
#include <net/net_offload.h>
|
||||||
|
|
||||||
|
#include <misc/printk.h>
|
||||||
|
|
||||||
|
/* We do not need <socket/include/socket.h>
|
||||||
|
* It seems there is a bug in ASF side: if OS is already defining sockaddr
|
||||||
|
* and all, ASF will not need to define it. Unfortunately its socket.h does
|
||||||
|
* but also defines some NM API functions there (??), so we need to redefine
|
||||||
|
* those here.
|
||||||
|
*/
|
||||||
|
#define __SOCKET_H__
|
||||||
|
#define HOSTNAME_MAX_SIZE (64)
|
||||||
|
|
||||||
|
#include <driver/include/m2m_wifi.h>
|
||||||
|
#include <socket/include/m2m_socket_host_if.h>
|
||||||
|
|
||||||
|
NMI_API void socketInit(void);
|
||||||
|
typedef void (*tpfAppSocketCb) (SOCKET sock, uint8 u8Msg, void *pvMsg);
|
||||||
|
typedef void (*tpfAppResolveCb) (uint8 *pu8DomainName, uint32 u32ServerIP);
|
||||||
|
NMI_API void registerSocketCallback(tpfAppSocketCb socket_cb,
|
||||||
|
tpfAppResolveCb resolve_cb);
|
||||||
|
NMI_API SOCKET socket(uint16 u16Domain, uint8 u8Type, uint8 u8Flags);
|
||||||
|
NMI_API sint8 bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen);
|
||||||
|
NMI_API sint8 listen(SOCKET sock, uint8 backlog);
|
||||||
|
NMI_API sint8 accept(SOCKET sock, struct sockaddr *addr, uint8 *addrlen);
|
||||||
|
NMI_API sint8 connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen);
|
||||||
|
NMI_API sint16 recv(SOCKET sock, void *pvRecvBuf,
|
||||||
|
uint16 u16BufLen, uint32 u32Timeoutmsec);
|
||||||
|
NMI_API sint16 send(SOCKET sock, void *pvSendBuffer,
|
||||||
|
uint16 u16SendLength, uint16 u16Flags);
|
||||||
|
NMI_API sint16 sendto(SOCKET sock, void *pvSendBuffer,
|
||||||
|
uint16 u16SendLength, uint16 flags,
|
||||||
|
struct sockaddr *pstrDestAddr, uint8 u8AddrLen);
|
||||||
|
|
||||||
|
enum socket_errors {
|
||||||
|
SOCK_ERR_NO_ERROR = 0,
|
||||||
|
SOCK_ERR_INVALID_ADDRESS = -1,
|
||||||
|
SOCK_ERR_ADDR_ALREADY_IN_USE = -2,
|
||||||
|
SOCK_ERR_MAX_TCP_SOCK = -3,
|
||||||
|
SOCK_ERR_MAX_UDP_SOCK = -4,
|
||||||
|
SOCK_ERR_INVALID_ARG = -6,
|
||||||
|
SOCK_ERR_MAX_LISTEN_SOCK = -7,
|
||||||
|
SOCK_ERR_INVALID = -9,
|
||||||
|
SOCK_ERR_ADDR_IS_REQUIRED = -11,
|
||||||
|
SOCK_ERR_CONN_ABORTED = -12,
|
||||||
|
SOCK_ERR_TIMEOUT = -13,
|
||||||
|
SOCK_ERR_BUFFER_FULL = -14,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum socket_messages {
|
||||||
|
SOCKET_MSG_BIND = 1,
|
||||||
|
SOCKET_MSG_LISTEN,
|
||||||
|
SOCKET_MSG_DNS_RESOLVE,
|
||||||
|
SOCKET_MSG_ACCEPT,
|
||||||
|
SOCKET_MSG_CONNECT,
|
||||||
|
SOCKET_MSG_RECV,
|
||||||
|
SOCKET_MSG_SEND,
|
||||||
|
SOCKET_MSG_SENDTO,
|
||||||
|
SOCKET_MSG_RECVFROM,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sint8 status;
|
||||||
|
} tstrSocketBindMsg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sint8 status;
|
||||||
|
} tstrSocketListenMsg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SOCKET sock;
|
||||||
|
struct sockaddr_in strAddr;
|
||||||
|
} tstrSocketAcceptMsg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SOCKET sock;
|
||||||
|
sint8 s8Error;
|
||||||
|
} tstrSocketConnectMsg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8 *pu8Buffer;
|
||||||
|
sint16 s16BufferSize;
|
||||||
|
uint16 u16RemainingSize;
|
||||||
|
struct sockaddr_in strRemoteAddr;
|
||||||
|
} tstrSocketRecvMsg;
|
||||||
|
|
||||||
|
#include <driver/include/m2m_wifi.h>
|
||||||
|
#include <socket/include/m2m_socket_host_if.h>
|
||||||
|
|
||||||
|
#ifndef CONFIG_WINC1500_THREAD_STACK_SIZE
|
||||||
|
#define CONFIG_WINC1500_THREAD_STACK_SIZE 5000
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_WINC1500_THREAD_PRIO
|
||||||
|
#define CONFIG_WINC1500_THREAD_PRIO 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_WINC1500_BUF_CTR
|
||||||
|
#define CONFIG_WINC1500_BUF_CTR 1
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_WINC1500_MAX_PACKET_SIZE
|
||||||
|
#define CONFIG_WINC1500_MAX_PACKET_SIZE 1500
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_OFFLOAD_MAX_SOCKETS
|
||||||
|
#define CONFIG_OFFLOAD_MAX_SOCKETS 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WINC1500_BIND_TIMEOUT 500
|
||||||
|
#define WINC1500_LISTEN_TIMEOUT 500
|
||||||
|
|
||||||
|
NET_BUF_POOL_DEFINE(winc1500_tx_pool, CONFIG_WINC1500_BUF_CTR,
|
||||||
|
CONFIG_WINC1500_MAX_PACKET_SIZE, 0, NULL);
|
||||||
|
NET_BUF_POOL_DEFINE(winc1500_rx_pool, CONFIG_WINC1500_BUF_CTR,
|
||||||
|
CONFIG_WINC1500_MAX_PACKET_SIZE, 0, NULL);
|
||||||
|
|
||||||
|
K_THREAD_STACK_MEMBER(winc1500_stack, CONFIG_WINC1500_THREAD_STACK_SIZE);
|
||||||
|
struct k_thread winc1500_thread_data;
|
||||||
|
|
||||||
|
struct socket_data {
|
||||||
|
struct net_context *context;
|
||||||
|
net_context_connect_cb_t connect_cb;
|
||||||
|
net_tcp_accept_cb_t accept_cb;
|
||||||
|
net_context_send_cb_t send_cb;
|
||||||
|
net_context_recv_cb_t recv_cb;
|
||||||
|
void *connect_user_data;
|
||||||
|
void *send_user_data;
|
||||||
|
void *recv_user_data;
|
||||||
|
void *accept_user_data;
|
||||||
|
struct net_pkt *rx_pkt;
|
||||||
|
struct net_buf *pkt_buf;
|
||||||
|
int ret_code;
|
||||||
|
struct k_sem wait_sem;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct winc1500_data {
|
||||||
|
struct socket_data socket_data[CONFIG_OFFLOAD_MAX_SOCKETS];
|
||||||
|
struct net_if *iface;
|
||||||
|
unsigned char mac[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct winc1500_data w1500_data;
|
||||||
|
|
||||||
|
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_OFF)
|
||||||
|
|
||||||
|
static char *socket_error_string(s8_t err)
|
||||||
|
{
|
||||||
|
switch (err) {
|
||||||
|
case SOCK_ERR_NO_ERROR:
|
||||||
|
return "Successful socket operation";
|
||||||
|
case SOCK_ERR_INVALID_ADDRESS:
|
||||||
|
return "Socket address is invalid."
|
||||||
|
"The socket operation cannot be completed successfully"
|
||||||
|
" without specifying a specific address. "
|
||||||
|
"For example: bind is called without specifying"
|
||||||
|
" a port number";
|
||||||
|
case SOCK_ERR_ADDR_ALREADY_IN_USE:
|
||||||
|
return "Socket operation cannot bind on the given address."
|
||||||
|
" With socket operations, only one IP address per "
|
||||||
|
"socket is permitted. Any attempt for a new socket "
|
||||||
|
"to bind with an IP address already bound to another "
|
||||||
|
"open socket, will return the following error code. "
|
||||||
|
"States that bind operation failed.";
|
||||||
|
case SOCK_ERR_MAX_TCP_SOCK:
|
||||||
|
return "Exceeded the maximum number of TCP sockets."
|
||||||
|
"A maximum number of TCP sockets opened simultaneously"
|
||||||
|
" is defined through TCP_SOCK_MAX. It is not permitted"
|
||||||
|
" to exceed that number at socket creation."
|
||||||
|
" Identifies that @ref socket operation failed.";
|
||||||
|
case SOCK_ERR_MAX_UDP_SOCK:
|
||||||
|
return "Exceeded the maximum number of UDP sockets."
|
||||||
|
"A maximum number of UDP sockets opened simultaneously"
|
||||||
|
" is defined through UDP_SOCK_MAX. It is not permitted"
|
||||||
|
" to exceed that number at socket creation."
|
||||||
|
" Identifies that socket operation failed";
|
||||||
|
case SOCK_ERR_INVALID_ARG:
|
||||||
|
return "An invalid argument is passed to a function.";
|
||||||
|
case SOCK_ERR_MAX_LISTEN_SOCK:
|
||||||
|
return "Exceeded the maximum number of TCP passive listening "
|
||||||
|
"sockets. Identifies Identifies that listen operation"
|
||||||
|
" failed.";
|
||||||
|
case SOCK_ERR_INVALID:
|
||||||
|
return "The requested socket operation is not valid in the "
|
||||||
|
"current socket state. For example: @ref accept is "
|
||||||
|
"called on a TCP socket before bind or listen.";
|
||||||
|
case SOCK_ERR_ADDR_IS_REQUIRED:
|
||||||
|
return "Destination address is required. Failure to provide "
|
||||||
|
"the socket address required for the socket operation "
|
||||||
|
"to be completed. It is generated as an error to the "
|
||||||
|
"sendto function when the address required to send the"
|
||||||
|
" data to is not known.";
|
||||||
|
case SOCK_ERR_CONN_ABORTED:
|
||||||
|
return "The socket is closed by the peer. The local socket is "
|
||||||
|
"also closed.";
|
||||||
|
case SOCK_ERR_TIMEOUT:
|
||||||
|
return "The socket pending operation has timedout.";
|
||||||
|
case SOCK_ERR_BUFFER_FULL:
|
||||||
|
return "No buffer space available to be used for the requested"
|
||||||
|
" socket operation.";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *wifi_cb_msg_2_str(u8_t message_type)
|
||||||
|
{
|
||||||
|
switch (message_type) {
|
||||||
|
case M2M_WIFI_RESP_CURRENT_RSSI:
|
||||||
|
return "M2M_WIFI_RESP_CURRENT_RSSI";
|
||||||
|
case M2M_WIFI_REQ_WPS:
|
||||||
|
return "M2M_WIFI_REQ_WPS";
|
||||||
|
case M2M_WIFI_RESP_IP_CONFIGURED:
|
||||||
|
return "M2M_WIFI_RESP_IP_CONFIGURED";
|
||||||
|
case M2M_WIFI_RESP_IP_CONFLICT:
|
||||||
|
return "M2M_WIFI_RESP_IP_CONFLICT";
|
||||||
|
case M2M_WIFI_RESP_CLIENT_INFO:
|
||||||
|
return "M2M_WIFI_RESP_CLIENT_INFO";
|
||||||
|
|
||||||
|
case M2M_WIFI_RESP_GET_SYS_TIME:
|
||||||
|
return "M2M_WIFI_RESP_GET_SYS_TIME";
|
||||||
|
case M2M_WIFI_REQ_SEND_ETHERNET_PACKET:
|
||||||
|
return "M2M_WIFI_REQ_SEND_ETHERNET_PACKET";
|
||||||
|
case M2M_WIFI_RESP_ETHERNET_RX_PACKET:
|
||||||
|
return "M2M_WIFI_RESP_ETHERNET_RX_PACKET";
|
||||||
|
|
||||||
|
case M2M_WIFI_RESP_CON_STATE_CHANGED:
|
||||||
|
return "M2M_WIFI_RESP_CON_STATE_CHANGED";
|
||||||
|
case M2M_WIFI_REQ_DHCP_CONF:
|
||||||
|
return "Response indicating that IP address was obtained.";
|
||||||
|
case M2M_WIFI_RESP_SCAN_DONE:
|
||||||
|
return "M2M_WIFI_RESP_SCAN_DONE";
|
||||||
|
case M2M_WIFI_RESP_SCAN_RESULT:
|
||||||
|
return "M2M_WIFI_RESP_SCAN_RESULT";
|
||||||
|
case M2M_WIFI_RESP_PROVISION_INFO:
|
||||||
|
return "M2M_WIFI_RESP_PROVISION_INFO";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *socket_message_to_string(u8_t message)
|
||||||
|
{
|
||||||
|
switch (message) {
|
||||||
|
case SOCKET_MSG_BIND:
|
||||||
|
return "Bind socket event.";
|
||||||
|
case SOCKET_MSG_LISTEN:
|
||||||
|
return "Listen socket event.";
|
||||||
|
case SOCKET_MSG_DNS_RESOLVE:
|
||||||
|
return "DNS Resolution event.";
|
||||||
|
case SOCKET_MSG_ACCEPT:
|
||||||
|
return "Accept socket event.";
|
||||||
|
case SOCKET_MSG_CONNECT:
|
||||||
|
return "Connect socket event.";
|
||||||
|
case SOCKET_MSG_RECV:
|
||||||
|
return "Receive socket event.";
|
||||||
|
case SOCKET_MSG_SEND:
|
||||||
|
return "Send socket event.";
|
||||||
|
case SOCKET_MSG_SENDTO:
|
||||||
|
return "Sendto socket event.";
|
||||||
|
case SOCKET_MSG_RECVFROM:
|
||||||
|
return "Recvfrom socket event.";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* (SYS_LOG_LEVEL > SYS_LOG_LEVEL_OFF) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when the socket is to be opened.
|
||||||
|
*/
|
||||||
|
static int winc1500_get(sa_family_t family,
|
||||||
|
enum net_sock_type type,
|
||||||
|
enum net_ip_protocol ip_proto,
|
||||||
|
struct net_context **context)
|
||||||
|
{
|
||||||
|
struct socket_data *sd;
|
||||||
|
|
||||||
|
if (family != AF_INET) {
|
||||||
|
SYS_LOG_ERR("Only AF_INET is supported!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*context)->user_data = (void *)(sint32)socket(family, type, 0);
|
||||||
|
if ((*context)->user_data < 0) {
|
||||||
|
SYS_LOG_ERR("socket error!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd = &w1500_data.socket_data[(int)(*context)->user_data];
|
||||||
|
|
||||||
|
k_sem_init(&sd->wait_sem, 0, 1);
|
||||||
|
|
||||||
|
sd->context = *context;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to bind to local IP address.
|
||||||
|
*/
|
||||||
|
static int winc1500_bind(struct net_context *context,
|
||||||
|
const struct sockaddr *addr,
|
||||||
|
socklen_t addrlen)
|
||||||
|
{
|
||||||
|
SOCKET socket = (int)context->user_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* FIXME atmel winc1500 don't support bind on null port */
|
||||||
|
if (net_sin(addr)->sin_port == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bind((int)context->user_data, (struct sockaddr *)addr, addrlen);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("bind error %d %s!",
|
||||||
|
ret, socket_message_to_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_sem_take(&w1500_data.socket_data[socket].wait_sem,
|
||||||
|
WINC1500_BIND_TIMEOUT)) {
|
||||||
|
SYS_LOG_ERR("bind error timeout expired");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w1500_data.socket_data[socket].ret_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to mark the socket
|
||||||
|
* to be a listening one.
|
||||||
|
*/
|
||||||
|
static int winc1500_listen(struct net_context *context, int backlog)
|
||||||
|
{
|
||||||
|
SOCKET socket = (int)context->user_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = listen((int)context->user_data, backlog);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("listen error %d %s!",
|
||||||
|
ret, socket_error_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_sem_take(&w1500_data.socket_data[socket].wait_sem,
|
||||||
|
WINC1500_LISTEN_TIMEOUT)) {
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w1500_data.socket_data[socket].ret_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to create a connection
|
||||||
|
* to a peer host.
|
||||||
|
*/
|
||||||
|
static int winc1500_connect(struct net_context *context,
|
||||||
|
const struct sockaddr *addr,
|
||||||
|
socklen_t addrlen,
|
||||||
|
net_context_connect_cb_t cb,
|
||||||
|
s32_t timeout,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
SOCKET socket = (int)context->user_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
w1500_data.socket_data[socket].connect_cb = cb;
|
||||||
|
w1500_data.socket_data[socket].connect_user_data = user_data;
|
||||||
|
w1500_data.socket_data[socket].ret_code = 0;
|
||||||
|
|
||||||
|
ret = connect(socket, (struct sockaddr *)addr, addrlen);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("connect error %d %s!",
|
||||||
|
ret, socket_error_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout != 0 &&
|
||||||
|
k_sem_take(&w1500_data.socket_data[socket].wait_sem, timeout)) {
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w1500_data.socket_data[socket].ret_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to accept a connection
|
||||||
|
* being established.
|
||||||
|
*/
|
||||||
|
static int winc1500_accept(struct net_context *context,
|
||||||
|
net_tcp_accept_cb_t cb,
|
||||||
|
s32_t timeout,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
SOCKET socket = (int)context->user_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
w1500_data.socket_data[socket].accept_cb = cb;
|
||||||
|
|
||||||
|
ret = accept(socket, NULL, 0);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("accept error %d %s!",
|
||||||
|
ret, socket_error_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
if (k_sem_take(&w1500_data.socket_data[socket].wait_sem,
|
||||||
|
timeout)) {
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
k_sem_take(&w1500_data.socket_data[socket].wait_sem,
|
||||||
|
K_FOREVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
return w1500_data.socket_data[socket].ret_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to send data to peer host.
|
||||||
|
*/
|
||||||
|
static int winc1500_send(struct net_pkt *pkt,
|
||||||
|
net_context_send_cb_t cb,
|
||||||
|
s32_t timeout,
|
||||||
|
void *token,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct net_context *context = pkt->context;
|
||||||
|
SOCKET socket = (int)context->user_data;
|
||||||
|
bool first_frag;
|
||||||
|
struct net_buf *frag;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
w1500_data.socket_data[socket].send_cb = cb;
|
||||||
|
w1500_data.socket_data[socket].send_user_data = user_data;
|
||||||
|
|
||||||
|
first_frag = true;
|
||||||
|
|
||||||
|
for (frag = pkt->frags; frag; frag = frag->frags) {
|
||||||
|
u8_t *data_ptr;
|
||||||
|
u16_t data_len;
|
||||||
|
|
||||||
|
if (first_frag) {
|
||||||
|
data_ptr = net_pkt_ll(pkt);
|
||||||
|
data_len = net_pkt_ll_reserve(pkt) + frag->len;
|
||||||
|
first_frag = false;
|
||||||
|
} else {
|
||||||
|
data_ptr = frag->data;
|
||||||
|
data_len = frag->len;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = send(socket, data_ptr, data_len, 0);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("send error %d %s!",
|
||||||
|
ret, socket_error_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
net_pkt_unref(pkt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to send data to peer host.
|
||||||
|
*/
|
||||||
|
static int winc1500_sendto(struct net_pkt *pkt,
|
||||||
|
const struct sockaddr *dst_addr,
|
||||||
|
socklen_t addrlen,
|
||||||
|
net_context_send_cb_t cb,
|
||||||
|
s32_t timeout,
|
||||||
|
void *token,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct net_context *context = pkt->context;
|
||||||
|
SOCKET socket = (int)context->user_data;
|
||||||
|
bool first_frag;
|
||||||
|
struct net_buf *frag;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
w1500_data.socket_data[socket].send_cb = cb;
|
||||||
|
w1500_data.socket_data[socket].send_user_data = user_data;
|
||||||
|
|
||||||
|
first_frag = true;
|
||||||
|
|
||||||
|
for (frag = pkt->frags; frag; frag = frag->frags) {
|
||||||
|
u8_t *data_ptr;
|
||||||
|
u16_t data_len;
|
||||||
|
|
||||||
|
if (first_frag) {
|
||||||
|
data_ptr = net_pkt_ll(pkt);
|
||||||
|
data_len = net_pkt_ll_reserve(pkt) + frag->len;
|
||||||
|
first_frag = false;
|
||||||
|
} else {
|
||||||
|
data_ptr = frag->data;
|
||||||
|
data_len = frag->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sendto(socket, data_ptr, data_len, 0,
|
||||||
|
(struct sockaddr *)dst_addr, addrlen);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("send error %d %s!",
|
||||||
|
ret, socket_error_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
net_pkt_unref(pkt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
static int prepare_pkt(struct socket_data *sock_data)
|
||||||
|
{
|
||||||
|
/* Get the frame from the buffer */
|
||||||
|
sock_data->rx_pkt = net_pkt_get_reserve_rx(0, K_NO_WAIT);
|
||||||
|
if (!sock_data->rx_pkt) {
|
||||||
|
SYS_LOG_ERR("Could not allocate rx packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reserve a data frag to receive the frame */
|
||||||
|
sock_data->pkt_buf = net_pkt_get_frag(sock_data->rx_pkt, K_NO_WAIT);
|
||||||
|
if (!sock_data->pkt_buf) {
|
||||||
|
SYS_LOG_ERR("Could not allocate data frag");
|
||||||
|
net_pkt_unref(sock_data->rx_pkt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_pkt_frag_insert(sock_data->rx_pkt, sock_data->pkt_buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to receive data from peer
|
||||||
|
* host.
|
||||||
|
*/
|
||||||
|
static int winc1500_recv(struct net_context *context,
|
||||||
|
net_context_recv_cb_t cb,
|
||||||
|
s32_t timeout,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
SOCKET socket = (int) context->user_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = prepare_pkt(&w1500_data.socket_data[socket]);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("Could not reserve packet buffer");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
w1500_data.socket_data[socket].recv_cb = cb;
|
||||||
|
w1500_data.socket_data[socket].recv_user_data = user_data;
|
||||||
|
|
||||||
|
ret = recv(socket, w1500_data.socket_data[socket].pkt_buf->data,
|
||||||
|
CONFIG_WINC1500_MAX_PACKET_SIZE, timeout);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("recv error %d %s!",
|
||||||
|
ret, socket_error_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called when user wants to close the socket.
|
||||||
|
*/
|
||||||
|
static int winc1500_put(struct net_context *context)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct net_offload winc1500_offload = {
|
||||||
|
.get = winc1500_get,
|
||||||
|
.bind = winc1500_bind,
|
||||||
|
.listen = winc1500_listen,
|
||||||
|
.connect = winc1500_connect,
|
||||||
|
.accept = winc1500_accept,
|
||||||
|
.send = winc1500_send,
|
||||||
|
.sendto = winc1500_sendto,
|
||||||
|
.recv = winc1500_recv,
|
||||||
|
.put = winc1500_put,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void winc1500_wifi_cb(u8_t message_type, void *pvMsg)
|
||||||
|
{
|
||||||
|
SYS_LOG_INF("Msg Type %d %s",
|
||||||
|
message_type, wifi_cb_msg_2_str(message_type));
|
||||||
|
|
||||||
|
switch (message_type) {
|
||||||
|
case M2M_WIFI_RESP_CON_STATE_CHANGED:
|
||||||
|
{
|
||||||
|
tstrM2mWifiStateChanged *pstrWifiState =
|
||||||
|
(tstrM2mWifiStateChanged *)pvMsg;
|
||||||
|
|
||||||
|
switch (pstrWifiState->u8CurrState) {
|
||||||
|
case M2M_WIFI_DISCONNECTED:
|
||||||
|
/* TODO status disconnected */
|
||||||
|
break;
|
||||||
|
case M2M_WIFI_CONNECTED:
|
||||||
|
/* TODO status connected */
|
||||||
|
break;
|
||||||
|
case M2M_WIFI_UNDEF:
|
||||||
|
/* TODO status undefined*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M2M_WIFI_REQ_DHCP_CONF:
|
||||||
|
{
|
||||||
|
u8_t *pu8IPAddress = (u8_t *)pvMsg;
|
||||||
|
struct in_addr addr;
|
||||||
|
u8_t i;
|
||||||
|
|
||||||
|
/* Connected and got IP address*/
|
||||||
|
SYS_LOG_INF("Wi-Fi connected, IP is %u.%u.%u.%u",
|
||||||
|
pu8IPAddress[0], pu8IPAddress[1],
|
||||||
|
pu8IPAddress[2], pu8IPAddress[3]);
|
||||||
|
/* TODO at this point the standby mode should be enable
|
||||||
|
* status = WiFi connected IP assigned
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
addr.s4_addr[i] = pu8IPAddress[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO fill in net mask, gateway and lease time */
|
||||||
|
|
||||||
|
net_if_ipv4_addr_add(w1500_data.iface,
|
||||||
|
&addr, NET_ADDR_DHCP, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void winc1500_socket_cb(SOCKET sock, uint8 message, void *pvMsg)
|
||||||
|
{
|
||||||
|
struct socket_data *sd = &w1500_data.socket_data[sock];
|
||||||
|
|
||||||
|
if (message != 6) {
|
||||||
|
SYS_LOG_INF(": sock %d Msg %d %s",
|
||||||
|
sock, message, socket_message_to_string(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
sd->ret_code = 0;
|
||||||
|
|
||||||
|
switch (message) {
|
||||||
|
case SOCKET_MSG_CONNECT:
|
||||||
|
{
|
||||||
|
tstrSocketConnectMsg *strConnMsg =
|
||||||
|
(tstrSocketConnectMsg *)pvMsg;
|
||||||
|
|
||||||
|
SYS_LOG_ERR("CONNECT: socket %d error %d",
|
||||||
|
strConnMsg->sock, strConnMsg->s8Error);
|
||||||
|
|
||||||
|
if (sd->connect_cb) {
|
||||||
|
sd->connect_cb(sd->context,
|
||||||
|
strConnMsg->s8Error,
|
||||||
|
sd->connect_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
sd->ret_code = strConnMsg->s8Error;
|
||||||
|
}
|
||||||
|
k_sem_give(&sd->wait_sem);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOCKET_MSG_SEND:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOCKET_MSG_RECV:
|
||||||
|
{
|
||||||
|
tstrSocketRecvMsg *pstrRx = (tstrSocketRecvMsg *)pvMsg;
|
||||||
|
|
||||||
|
if ((pstrRx->pu8Buffer != NULL) &&
|
||||||
|
(pstrRx->s16BufferSize > 0)) {
|
||||||
|
|
||||||
|
net_buf_add(sd->pkt_buf,
|
||||||
|
pstrRx->s16BufferSize);
|
||||||
|
|
||||||
|
net_pkt_set_appdata(sd->rx_pkt,
|
||||||
|
sd->pkt_buf->data);
|
||||||
|
net_pkt_set_appdatalen(sd->rx_pkt,
|
||||||
|
pstrRx->s16BufferSize);
|
||||||
|
|
||||||
|
if (sd->recv_cb) {
|
||||||
|
sd->recv_cb(sd->context,
|
||||||
|
sd->rx_pkt,
|
||||||
|
0,
|
||||||
|
sd->recv_user_data);
|
||||||
|
}
|
||||||
|
} else if (pstrRx->pu8Buffer == NULL) {
|
||||||
|
if (pstrRx->s16BufferSize == SOCK_ERR_CONN_ABORTED) {
|
||||||
|
net_pkt_unref(sd->rx_pkt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prepare_pkt(&w1500_data.socket_data[sock])) {
|
||||||
|
SYS_LOG_ERR("Could not reserve packet buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv(sock, sd->pkt_buf->data,
|
||||||
|
CONFIG_WINC1500_MAX_PACKET_SIZE, K_NO_WAIT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SOCKET_MSG_BIND:
|
||||||
|
{
|
||||||
|
/* The result of the bind operation.
|
||||||
|
* Holding a value of ZERO for a successful
|
||||||
|
* bind or otherwise a negative error code
|
||||||
|
* corresponding to the type of error.
|
||||||
|
*/
|
||||||
|
tstrSocketBindMsg *bind_msg = (tstrSocketBindMsg *)pvMsg;
|
||||||
|
|
||||||
|
if (bind_msg->status) {
|
||||||
|
SYS_LOG_ERR("BIND: error %d %s",
|
||||||
|
bind_msg->status,
|
||||||
|
socket_message_to_string(bind_msg->status));
|
||||||
|
sd->ret_code = bind_msg->status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k_sem_give(&sd->wait_sem);
|
||||||
|
break;
|
||||||
|
case SOCKET_MSG_LISTEN:
|
||||||
|
{
|
||||||
|
/* Holding a value of ZERO for a successful listen or
|
||||||
|
* otherwise a negative error code corresponding to
|
||||||
|
* the type of error.
|
||||||
|
*/
|
||||||
|
tstrSocketListenMsg *listen_msg = (tstrSocketListenMsg *)pvMsg;
|
||||||
|
|
||||||
|
if (listen_msg->status) {
|
||||||
|
SYS_LOG_ERR("winc1500_socket_cb:LISTEN: error %d %s\n",
|
||||||
|
listen_msg->status,
|
||||||
|
socket_message_to_string(listen_msg->status));
|
||||||
|
sd->ret_code = listen_msg->status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k_sem_give(&sd->wait_sem);
|
||||||
|
break;
|
||||||
|
case SOCKET_MSG_ACCEPT:
|
||||||
|
{
|
||||||
|
/* sock
|
||||||
|
* On a successful accept operation, the return information
|
||||||
|
* is the socket ID for the accepted connection with the
|
||||||
|
* remote peer.
|
||||||
|
* Otherwise a negative error code is returned to indicate
|
||||||
|
* failure of the accept operation.
|
||||||
|
* strAddr;
|
||||||
|
* Socket address structure for the remote peer.
|
||||||
|
*/
|
||||||
|
tstrSocketAcceptMsg *accept_msg = (tstrSocketAcceptMsg *)pvMsg;
|
||||||
|
|
||||||
|
SYS_LOG_INF("ACCEPT:"
|
||||||
|
"from %d.%d.%d.%d:%d, new socket is %d",
|
||||||
|
accept_msg->strAddr.sin_addr.s4_addr[0],
|
||||||
|
accept_msg->strAddr.sin_addr.s4_addr[1],
|
||||||
|
accept_msg->strAddr.sin_addr.s4_addr[2],
|
||||||
|
accept_msg->strAddr.sin_addr.s4_addr[3],
|
||||||
|
ntohs(accept_msg->strAddr.sin_port),
|
||||||
|
accept_msg->sock);
|
||||||
|
|
||||||
|
if (accept_msg->sock < 0) {
|
||||||
|
SYS_LOG_ERR("ACCEPT: error %d %s",
|
||||||
|
accept_msg->sock,
|
||||||
|
socket_message_to_string(accept_msg->sock));
|
||||||
|
sd->ret_code = accept_msg->sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sd->accept_cb) {
|
||||||
|
struct socket_data *a_sd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
a_sd = &w1500_data.socket_data[accept_msg->sock];
|
||||||
|
|
||||||
|
memcpy(a_sd, sd, sizeof(struct socket_data));
|
||||||
|
|
||||||
|
ret = net_context_get(AF_INET, SOCK_STREAM,
|
||||||
|
IPPROTO_TCP, &a_sd->context);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYS_LOG_ERR("Cannot get new network"
|
||||||
|
"context for ACCEPT");
|
||||||
|
} else {
|
||||||
|
a_sd->context->user_data =
|
||||||
|
(void *)((int)accept_msg->sock);
|
||||||
|
|
||||||
|
sd->accept_cb(
|
||||||
|
a_sd->context,
|
||||||
|
(struct sockaddr *)&accept_msg->strAddr,
|
||||||
|
sizeof(struct sockaddr_in),
|
||||||
|
(accept_msg->sock > 0) ?
|
||||||
|
0 :accept_msg->sock,
|
||||||
|
sd->accept_user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k_sem_give(&sd->wait_sem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void winc1500_thread(void)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
while (m2m_wifi_handle_events(NULL) != 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void winc1500_iface_init(struct net_if *iface)
|
||||||
|
{
|
||||||
|
SYS_LOG_INF("eth_init:net_if_set_link_addr:"
|
||||||
|
"MAC Address %02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
w1500_data.mac[0], w1500_data.mac[1], w1500_data.mac[2],
|
||||||
|
w1500_data.mac[3], w1500_data.mac[4], w1500_data.mac[5]);
|
||||||
|
|
||||||
|
net_if_set_link_addr(iface, w1500_data.mac, sizeof(w1500_data.mac),
|
||||||
|
NET_LINK_ETHERNET);
|
||||||
|
|
||||||
|
iface->if_dev->offload = &winc1500_offload;
|
||||||
|
|
||||||
|
w1500_data.iface = iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct net_if_api winc1500_api = {
|
||||||
|
.init = winc1500_iface_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int winc1500_init(struct device *dev)
|
||||||
|
{
|
||||||
|
tstrWifiInitParam param = {
|
||||||
|
.pfAppWifiCb = winc1500_wifi_cb,
|
||||||
|
};
|
||||||
|
tuniM2MWifiAuth creds = {
|
||||||
|
.au8PSK = CONFIG_WIFI_WINC1500_PSK,
|
||||||
|
};
|
||||||
|
unsigned char is_valid;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
ret = m2m_wifi_init(¶m);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("m2m_wifi_init return error!(%d)", ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
socketInit();
|
||||||
|
registerSocketCallback(winc1500_socket_cb, NULL);
|
||||||
|
|
||||||
|
m2m_wifi_get_otp_mac_address(w1500_data.mac, &is_valid);
|
||||||
|
SYS_LOG_INF("WINC1500 MAC Address from OTP (%d) "
|
||||||
|
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
is_valid,
|
||||||
|
w1500_data.mac[0], w1500_data.mac[1], w1500_data.mac[2],
|
||||||
|
w1500_data.mac[3], w1500_data.mac[4], w1500_data.mac[5]);
|
||||||
|
|
||||||
|
m2m_wifi_set_power_profile(PWR_LOW1);
|
||||||
|
m2m_wifi_set_tx_power(TX_PWR_LOW);
|
||||||
|
|
||||||
|
/* monitoring thread for winc wifi callbacks */
|
||||||
|
k_thread_create(&winc1500_thread_data, winc1500_stack,
|
||||||
|
CONFIG_WINC1500_THREAD_STACK_SIZE,
|
||||||
|
(k_thread_entry_t)winc1500_thread, NULL, NULL, NULL,
|
||||||
|
K_PRIO_COOP(CONFIG_WINC1500_THREAD_PRIO),
|
||||||
|
0, K_NO_WAIT);
|
||||||
|
|
||||||
|
SYS_LOG_INF("Connecting to %s (%u) with %s",
|
||||||
|
CONFIG_WIFI_WINC1500_SSID,
|
||||||
|
CONFIG_WIFI_WINC1500_SSID_LENGTH,
|
||||||
|
CONFIG_WIFI_WINC1500_PSK);
|
||||||
|
|
||||||
|
ret = m2m_wifi_connect(CONFIG_WIFI_WINC1500_SSID,
|
||||||
|
CONFIG_WIFI_WINC1500_SSID_LENGTH,
|
||||||
|
M2M_WIFI_SEC_WPA_PSK, &creds,
|
||||||
|
M2M_WIFI_CH_ALL);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_WRN("Connecting to wifi does not seem to work");
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_LOG_INF("WINC1500 driver Initialized");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_DEVICE_OFFLOAD_INIT(winc1500, CONFIG_WIFI_WINC1500_NAME,
|
||||||
|
winc1500_init, &w1500_data, NULL,
|
||||||
|
CONFIG_WIFI_INIT_PRIORITY, &winc1500_api,
|
||||||
|
CONFIG_WINC1500_MAX_PACKET_SIZE);
|
66
drivers/wifi/wifi_winc1500_config.h
Normal file
66
drivers/wifi/wifi_winc1500_config.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017 IpTronix
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONF_WINC_H_INCLUDED
|
||||||
|
#define CONF_WINC_H_INCLUDED
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------------
|
||||||
|
---------- PIN settings ---------
|
||||||
|
---------------------------------
|
||||||
|
*/
|
||||||
|
#define CONF_WINC_PIN_RESET IOPORT_CREATE_PIN(PIOA, 24)
|
||||||
|
#define CONF_WINC_PIN_CHIP_ENABLE IOPORT_CREATE_PIN(PIOA, 6)
|
||||||
|
#define CONF_WINC_PIN_WAKE IOPORT_CREATE_PIN(PIOA, 25)
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------------
|
||||||
|
---------- SPI settings ---------
|
||||||
|
---------------------------------
|
||||||
|
*/
|
||||||
|
#define CONF_WINC_USE_SPI (1)
|
||||||
|
|
||||||
|
/** SPI pin and instance settings. */
|
||||||
|
#define CONF_WINC_SPI SPI
|
||||||
|
#define CONF_WINC_SPI_ID ID_SPI
|
||||||
|
#define CONF_WINC_SPI_MISO_GPIO SPI_MISO_GPIO
|
||||||
|
#define CONF_WINC_SPI_MISO_FLAGS SPI_MISO_FLAGS
|
||||||
|
#define CONF_WINC_SPI_MOSI_GPIO SPI_MOSI_GPIO
|
||||||
|
#define CONF_WINC_SPI_MOSI_FLAGS SPI_MOSI_FLAGS
|
||||||
|
#define CONF_WINC_SPI_CLK_GPIO SPI_SPCK_GPIO
|
||||||
|
#define CONF_WINC_SPI_CLK_FLAGS SPI_SPCK_FLAGS
|
||||||
|
#define CONF_WINC_SPI_CS_GPIO SPI_NPCS0_GPIO
|
||||||
|
#define CONF_WINC_SPI_CS_FLAGS PIO_OUTPUT_1
|
||||||
|
#define CONF_WINC_SPI_NPCS (0)
|
||||||
|
|
||||||
|
/** SPI delay before SPCK and between consecutive transfer. */
|
||||||
|
#define CONF_WINC_SPI_DLYBS (0)
|
||||||
|
#define CONF_WINC_SPI_DLYBCT (0)
|
||||||
|
|
||||||
|
/** SPI interrupt pin. */
|
||||||
|
#define CONF_WINC_SPI_INT_PIN IOPORT_CREATE_PIN(PIOA, 1)
|
||||||
|
#define CONF_WINC_SPI_INT_PIO PIOA
|
||||||
|
#define CONF_WINC_SPI_INT_PIO_ID ID_PIOA
|
||||||
|
#define CONF_WINC_SPI_INT_MASK (1 << 1)
|
||||||
|
#define CONF_WINC_SPI_INT_PRIORITY (0)
|
||||||
|
|
||||||
|
/** Clock polarity & phase. */
|
||||||
|
#define CONF_WINC_SPI_POL (0)
|
||||||
|
#define CONF_WINC_SPI_PHA (1)
|
||||||
|
|
||||||
|
/** SPI clock. */
|
||||||
|
#define CONF_WINC_SPI_CLOCK (48000000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------------
|
||||||
|
--------- Debug Options ---------
|
||||||
|
---------------------------------
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#define CONF_WINC_DEBUG (0)
|
||||||
|
#define CONF_WINC_PRINTF printf
|
||||||
|
|
||||||
|
#endif /* CONF_WINC_H_INCLUDED */
|
98
drivers/wifi/wifi_winc1500_nm_bsp.c
Normal file
98
drivers/wifi/wifi_winc1500_nm_bsp.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017 IpTronix
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <board.h>
|
||||||
|
|
||||||
|
#include "wifi_winc1500_nm_bsp_internal.h"
|
||||||
|
|
||||||
|
#include <bsp/include/nm_bsp.h>
|
||||||
|
#include <common/include/nm_common.h>
|
||||||
|
|
||||||
|
#include "wifi_winc1500_config.h"
|
||||||
|
|
||||||
|
struct winc1500_device winc1500;
|
||||||
|
|
||||||
|
void (*isr_function)(void);
|
||||||
|
|
||||||
|
static inline void chip_isr(struct device *port,
|
||||||
|
struct gpio_callback *cb,
|
||||||
|
uint32_t pins)
|
||||||
|
{
|
||||||
|
if (isr_function) {
|
||||||
|
isr_function();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s8_t nm_bsp_init(void)
|
||||||
|
{
|
||||||
|
isr_function = NULL;
|
||||||
|
|
||||||
|
/* Initialize chip IOs. */
|
||||||
|
winc1500.gpios = winc1500_configure_gpios();
|
||||||
|
|
||||||
|
winc1500.spi_dev = device_get_binding(CONFIG_WINC1500_SPI_DRV_NAME);
|
||||||
|
if (!winc1500.spi_dev) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform chip reset. */
|
||||||
|
nm_bsp_reset();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s8_t nm_bsp_deinit(void)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nm_bsp_reset(void)
|
||||||
|
{
|
||||||
|
gpio_pin_write(winc1500.gpios[WINC1500_GPIO_IDX_CHIP_EN],
|
||||||
|
CONFIG_WINC1500_GPIO_CHIP_EN, 0);
|
||||||
|
gpio_pin_write(winc1500.gpios[WINC1500_GPIO_IDX_RESET_N],
|
||||||
|
CONFIG_WINC1500_GPIO_RESET_N, 0);
|
||||||
|
nm_bsp_sleep(100);
|
||||||
|
|
||||||
|
gpio_pin_write(winc1500.gpios[WINC1500_GPIO_IDX_CHIP_EN],
|
||||||
|
CONFIG_WINC1500_GPIO_CHIP_EN, 1);
|
||||||
|
nm_bsp_sleep(10);
|
||||||
|
|
||||||
|
gpio_pin_write(winc1500.gpios[WINC1500_GPIO_IDX_RESET_N],
|
||||||
|
CONFIG_WINC1500_GPIO_RESET_N, 1);
|
||||||
|
nm_bsp_sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nm_bsp_sleep(uint32 u32TimeMsec)
|
||||||
|
{
|
||||||
|
k_busy_wait(u32TimeMsec * MSEC_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nm_bsp_register_isr(void (*isr_fun)(void))
|
||||||
|
{
|
||||||
|
isr_function = isr_fun;
|
||||||
|
|
||||||
|
gpio_init_callback(&winc1500.gpio_cb,
|
||||||
|
chip_isr,
|
||||||
|
BIT(CONFIG_WINC1500_GPIO_IRQN));
|
||||||
|
|
||||||
|
gpio_add_callback(winc1500.gpios[WINC1500_GPIO_IDX_IRQN],
|
||||||
|
&winc1500.gpio_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nm_bsp_interrupt_ctrl(u8_t enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
gpio_pin_enable_callback(
|
||||||
|
winc1500.gpios[WINC1500_GPIO_IDX_IRQN],
|
||||||
|
CONFIG_WINC1500_GPIO_IRQN);
|
||||||
|
} else {
|
||||||
|
gpio_pin_disable_callback(
|
||||||
|
winc1500.gpios[WINC1500_GPIO_IDX_IRQN],
|
||||||
|
CONFIG_WINC1500_GPIO_IRQN);
|
||||||
|
}
|
||||||
|
}
|
33
drivers/wifi/wifi_winc1500_nm_bsp_internal.h
Normal file
33
drivers/wifi/wifi_winc1500_nm_bsp_internal.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017 IpTronix
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WIFI_WINC1500_NM_BSP_INTERNAL_H__
|
||||||
|
#define __WIFI_WINC1500_NM_BSP_INTERNAL_H__
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
#include <gpio.h>
|
||||||
|
|
||||||
|
#include "wifi_winc1500_config.h"
|
||||||
|
#include <bus_wrapper/include/nm_bus_wrapper.h>
|
||||||
|
|
||||||
|
extern tstrNmBusCapabilities egstrNmBusCapabilities;
|
||||||
|
|
||||||
|
#define NM_EDGE_INTERRUPT (1)
|
||||||
|
|
||||||
|
#define NM_DEBUG CONF_WINC_DEBUG
|
||||||
|
#define NM_BSP_PRINTF CONF_WINC_PRINTF
|
||||||
|
|
||||||
|
struct winc1500_device {
|
||||||
|
struct device **gpios;
|
||||||
|
struct gpio_callback gpio_cb;
|
||||||
|
|
||||||
|
struct device *spi_dev;
|
||||||
|
int spi_slave;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct winc1500_device winc1500;
|
||||||
|
|
||||||
|
#endif /* __WIFI_WINC1500_NM_BSP_INTERNAL_H__ */
|
175
drivers/wifi/wifi_winc1500_nm_bus_wrapper.c
Normal file
175
drivers/wifi/wifi_winc1500_nm_bus_wrapper.c
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017 IpTronix
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_WIFI_LEVEL
|
||||||
|
#define SYS_LOG_DOMAIN "dev/winc1500"
|
||||||
|
#include <logging/sys_log.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <board.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <spi.h>
|
||||||
|
|
||||||
|
#include "wifi_winc1500_nm_bsp_internal.h"
|
||||||
|
|
||||||
|
#include <bsp/include/nm_bsp.h>
|
||||||
|
#include <common/include/nm_common.h>
|
||||||
|
#include <bus_wrapper/include/nm_bus_wrapper.h>
|
||||||
|
|
||||||
|
#include "wifi_winc1500_config.h"
|
||||||
|
|
||||||
|
#define NM_BUS_MAX_TRX_SZ 256
|
||||||
|
|
||||||
|
tstrNmBusCapabilities egstrNmBusCapabilities = {
|
||||||
|
NM_BUS_MAX_TRX_SZ
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONF_WINC_USE_I2C
|
||||||
|
|
||||||
|
#define SLAVE_ADDRESS 0x60
|
||||||
|
|
||||||
|
/** Number of times to try to send packet if failed. */
|
||||||
|
#define I2C_TIMEOUT 100
|
||||||
|
|
||||||
|
static s8_t nm_i2c_write(u8_t *b, u16_t sz)
|
||||||
|
{
|
||||||
|
/* Not implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
static s8_t nm_i2c_read(u8_t *rb, u16_t sz)
|
||||||
|
{
|
||||||
|
/* Not implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
static s8_t nm_i2c_write_special(u8_t *wb1, u16_t sz1,
|
||||||
|
u8_t *wb2, u16_t sz2)
|
||||||
|
{
|
||||||
|
/* Not implemented */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONF_WINC_USE_SPI
|
||||||
|
|
||||||
|
static s8_t spi_rw(u8_t *mosi, u8_t *miso, u16_t size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spi_slave_select(winc1500.spi_dev, winc1500.spi_slave);
|
||||||
|
|
||||||
|
ret = spi_transceive(winc1500.spi_dev,
|
||||||
|
mosi, size,
|
||||||
|
miso, miso ? size : 0);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("spi_transceive fail %d", ret);
|
||||||
|
return M2M_ERR_BUS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return M2M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s8_t nm_bus_init(void *pvinit)
|
||||||
|
{
|
||||||
|
s8_t result = 0;
|
||||||
|
|
||||||
|
#ifdef CONF_WINC_USE_I2C
|
||||||
|
/* Not implemented */
|
||||||
|
#elif defined CONF_WINC_USE_SPI
|
||||||
|
struct spi_config spi_config;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* configure GPIOs */
|
||||||
|
winc1500.gpios = winc1500_configure_gpios();
|
||||||
|
|
||||||
|
/* setup SPI device */
|
||||||
|
winc1500.spi_dev = device_get_binding(
|
||||||
|
CONFIG_WIFI_WINC1500_SPI_DRV_NAME);
|
||||||
|
if (!winc1500.spi_dev) {
|
||||||
|
SYS_LOG_ERR("spi device binding");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_config.config = SPI_WORD(8) | SPI_TRANSFER_MSB;
|
||||||
|
spi_config.max_sys_freq = CONFIG_WIFI_WINC1500_SPI_FREQ;
|
||||||
|
|
||||||
|
ret = spi_configure(winc1500.spi_dev, &spi_config);
|
||||||
|
if (ret) {
|
||||||
|
SYS_LOG_ERR("spi_configure fail %d", ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
winc1500.spi_slave = CONFIG_WIFI_WINC1500_SPI_SLAVE;
|
||||||
|
SYS_LOG_INF("spi_configure OK");
|
||||||
|
|
||||||
|
winc1500_configure_intgpios();
|
||||||
|
|
||||||
|
nm_bsp_reset();
|
||||||
|
nm_bsp_sleep(1);
|
||||||
|
|
||||||
|
nm_bsp_interrupt_ctrl(1);
|
||||||
|
|
||||||
|
SYS_LOG_INF("NOTICE:DONE");
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
s8_t nm_bus_ioctl(u8_t cmd, void *parameter)
|
||||||
|
{
|
||||||
|
sint8 ret = 0;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
#ifdef CONF_WINC_USE_I2C
|
||||||
|
case NM_BUS_IOCTL_R: {
|
||||||
|
struct nm_i2c_default *param =
|
||||||
|
(struct nm_i2c_default *)parameter;
|
||||||
|
|
||||||
|
ret = nm_i2c_read(param->buffer, param->size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NM_BUS_IOCTL_W: {
|
||||||
|
struct nm_i2c_default *param =
|
||||||
|
(struct nm_i2c_default *)parameter;
|
||||||
|
|
||||||
|
ret = nm_i2c_write(param->buffer, param->size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NM_BUS_IOCTL_W_SPECIAL: {
|
||||||
|
struct nm_i2c_special *param =
|
||||||
|
(struct nm_i2c_special *)parameter;
|
||||||
|
|
||||||
|
ret = nm_i2c_write_special(param->buffer1, param->size1,
|
||||||
|
param->buffer2, param->size2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#elif defined CONF_WINC_USE_SPI
|
||||||
|
case NM_BUS_IOCTL_RW: {
|
||||||
|
tstrNmSpiRw *param = (tstrNmSpiRw *)parameter;
|
||||||
|
|
||||||
|
ret = spi_rw(param->pu8InBuf, param->pu8OutBuf, param->u16Sz);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
ret = -1;
|
||||||
|
M2M_ERR("ERROR:invalid ioclt cmd\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
s8_t nm_bus_deinit(void)
|
||||||
|
{
|
||||||
|
return M2M_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
s8_t nm_bus_reinit(void *config)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef _NM_BSP_INTERNAL_H_
|
#ifndef _NM_BSP_INTERNAL_H_
|
||||||
#define _NM_BSP_INTERNAL_H_
|
#define _NM_BSP_INTERNAL_H_
|
||||||
|
|
||||||
/* dummy nm_bsp_internal.h to make nm_debug.c happy */
|
#if defined(CONFIG_WIFI_WINC1500)
|
||||||
|
#include <wifi_winc1500_nm_bsp_internal.h>
|
||||||
|
#endif /* CONFIG_WIFI_WINC1500 */
|
||||||
|
|
||||||
#endif //_NM_BSP_INTERNAL_H_
|
#endif //_NM_BSP_INTERNAL_H_
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue