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
|
||||
Enable support for Full-MAC WiFi devices.
|
||||
|
||||
source "drivers/wifi/Kconfig.winc1500"
|
||||
|
||||
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_
|
||||
#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_
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue