From 3c050bc4d12ae742ff54ef114a7827bc462a3280 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 20 Jul 2017 20:23:52 +0200 Subject: [PATCH] Upnp example emulating a Wemo switch --- examples/upnp/Makefile | 5 + examples/upnp/README.md | 3 + examples/upnp/httpd.c | 53 +++++ examples/upnp/httpd.h | 3 + examples/upnp/lwipopts.h | 464 ++++++++++++++++++++++++++++++++++++++ examples/upnp/upnp.c | 134 +++++++++++ examples/upnp/upnp.h | 2 + examples/upnp/upnp_test.c | 114 ++++++++++ 8 files changed, 778 insertions(+) create mode 100644 examples/upnp/Makefile create mode 100644 examples/upnp/README.md create mode 100644 examples/upnp/httpd.c create mode 100644 examples/upnp/httpd.h create mode 100644 examples/upnp/lwipopts.h create mode 100644 examples/upnp/upnp.c create mode 100644 examples/upnp/upnp.h create mode 100644 examples/upnp/upnp_test.c diff --git a/examples/upnp/Makefile b/examples/upnp/Makefile new file mode 100644 index 0000000..8e82736 --- /dev/null +++ b/examples/upnp/Makefile @@ -0,0 +1,5 @@ +PROGRAM=upnp_test +OTA=1 +EXTRA_COMPONENTS=extras/rboot-ota + +include ../../common.mk diff --git a/examples/upnp/README.md b/examples/upnp/README.md new file mode 100644 index 0000000..d39056c --- /dev/null +++ b/examples/upnp/README.md @@ -0,0 +1,3 @@ +# upnp Example + +This is an example to generate an upnp server and emulate a WeMo switch recognizable by Amazon echo Dot. diff --git a/examples/upnp/httpd.c b/examples/upnp/httpd.c new file mode 100644 index 0000000..9db2465 --- /dev/null +++ b/examples/upnp/httpd.c @@ -0,0 +1,53 @@ +#include +#include +#include + +void httpd_task(void *pvParameters) +{ + struct netconn *client = NULL; + struct netconn *nc = netconn_new(NETCONN_TCP); + if (nc == NULL) { + printf("Failed to allocate socket\n"); + vTaskDelete(NULL); + } + netconn_bind(nc, IP_ADDR_ANY, 80); + netconn_listen(nc); + while (1) { + err_t err = netconn_accept(nc, &client); + if (err == ERR_OK) { + struct netbuf *nb; + if ((err = netconn_recv(client, &nb)) == ERR_OK) { + struct sdk_station_config config; + sdk_wifi_station_get_config(&config); + char * buf = + "\ + \ + \ + urn:Belkin:device:controllee:1\ + hello\ + Belkin International Inc.\ + Emulated Socket\ + 3.1415\ + uuid:Socket-1_0-38323636-4558-4dda-9188-cda0e6cc3dc0\ + 221517K0101769\ + 0\ + \ + \ + urn:Belkin:service:basicevent:1\ + urn:Belkin:serviceId:basicevent1\ + /upnp/control/basicevent1\ + /upnp/event/basicevent1\ + /eventservice.xml\ + \ + \ + \ + "; + netconn_write(client, buf, strlen(buf), NETCONN_COPY); + } + netbuf_delete(nb); + } + printf("Closing connection\n"); + netconn_close(client); + netconn_delete(client); + } +} \ No newline at end of file diff --git a/examples/upnp/httpd.h b/examples/upnp/httpd.h new file mode 100644 index 0000000..2dfdd1b --- /dev/null +++ b/examples/upnp/httpd.h @@ -0,0 +1,3 @@ +#include + +void httpd_task(void *pvParameters); diff --git a/examples/upnp/lwipopts.h b/examples/upnp/lwipopts.h new file mode 100644 index 0000000..a82d3fc --- /dev/null +++ b/examples/upnp/lwipopts.h @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#define LWIP_ESP 1 +#define ESP_RTOS 1 +#define PBUF_RSV_FOR_WLAN 1 +#define EBUF_LWIP 1 +#define ESP_TIMEWAIT_THRESHOLD 10000 +#define LWIP_TIMEVAL_PRIVATE 0 + +#define TCP_WND (TCP_MSS * 2) + +#define LWIP_IGMP 1 +#include +#include +#define LWIP_RAND hwrand + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#define MEM_LIBC_MALLOC 1 + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#define MEMP_MEM_MALLOC 1 + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT 4 + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ + +/* + -------------------------------- + ---------- ARP options ------- + -------------------------------- +*/ +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#define ARP_QUEUEING 1 + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#define IP_REASSEMBLY 0 + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define IP_FRAG 1 + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#define IP_REASS_MAXAGE 3 + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#define IP_REASS_MAX_PBUFS 10 + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP 1 + +#define LWIP_DHCP_BOOTP_FILE 0 + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#define LWIP_DNS 1 + +#define DNS_TABLE_SIZE 1 +#define DNS_MAX_NAME_LENGTH 128 + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#define TCP_QUEUE_OOSEQ 0 + +/* + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. +*/ +#define TCP_MSS 1460 + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#define TCP_MAXRTX 6 + + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#define TCP_SYNMAXRTX 3 + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#define LWIP_NETIF_TX_SINGLE_PBUF 1 + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define TCPIP_THREAD_STACKSIZE 512 //not ok:384 + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define TCPIP_THREAD_PRIO (configMAX_PRIORITIES-5) + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#define TCPIP_MBOX_SIZE 16 + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_UDP_RECVMBOX_SIZE 6 + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_TCP_RECVMBOX_SIZE 6 + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#define DEFAULT_ACCEPTMBOX_SIZE 6 + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#define LWIP_SO_SNDTIMEO 1 + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#define LWIP_SO_RCVTIMEO 1 + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#define LWIP_TCP_KEEPALIVE 1 + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#define LWIP_SO_RCVBUF 0 + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#define SO_REUSE 1 + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ + +// Uncomment this line, and set the individual debug options you want, for IP stack debug output +//#define LWIP_DEBUG + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#define ETHARP_DEBUG LWIP_DBG_OFF + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#define PBUF_DEBUG LWIP_DBG_OFF + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#define API_LIB_DEBUG LWIP_DBG_OFF + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#define SOCKETS_DEBUG LWIP_DBG_OFF + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#define IP_DEBUG LWIP_DBG_OFF + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#define MEMP_DEBUG LWIP_DBG_OFF + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF + +/** + * UDP_DEBUG: Enable debugging in udp.c. + */ +#define UDP_DEBUG LWIP_DBG_OFF + +/** + * ICMP_DEBUG: Enable debugging in udp.c. + */ +#define ICMP_DEBUG LWIP_DBG_OFF + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#define TCPIP_DEBUG LWIP_DBG_OFF + + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#define DHCP_DEBUG LWIP_DBG_OFF + +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 + +#endif /* __LWIPOPTS_H__ */ diff --git a/examples/upnp/upnp.c b/examples/upnp/upnp.c new file mode 100644 index 0000000..a223d27 --- /dev/null +++ b/examples/upnp/upnp.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "upnp.h" + +#define UPNP_MCAST_GRP ("239.255.255.250") +#define UPNP_MCAST_PORT (1900) + +static const char* get_my_ip(void) +{ + static char ip[16] = "0.0.0.0"; + ip[0] = 0; + struct ip_info ipinfo; + (void) sdk_wifi_get_ip_info(STATION_IF, &ipinfo); + snprintf(ip, sizeof(ip), IPSTR, IP2STR(&ipinfo.ip)); + return (char*) ip; +} + +/** + * @brief This function joins a multicast group witht he specified ip/port + * @param group_ip the specified multicast group ip + * @param group_port the specified multicast port number + * @param recv the lwip UDP callback + * @retval udp_pcb* or NULL if joining failed + */ +static struct udp_pcb* mcast_join_group(char *group_ip, uint16_t group_port, void (* recv)(void * arg, struct udp_pcb * upcb, struct pbuf * p, struct ip_addr * addr, u16_t port)) +{ + bool status = false; + struct udp_pcb *upcb; + + printf("Joining mcast group %s:%d\n", group_ip, group_port); + do { + upcb = udp_new(); + if (!upcb) { + printf("Error, udp_new failed"); + break; + } + udp_bind(upcb, IP_ADDR_ANY, group_port); + struct netif* netif = sdk_system_get_netif(STATION_IF); + if (!netif) { + printf("Error, netif is null"); + break; + } + if (!(netif->flags & NETIF_FLAG_IGMP)) { + netif->flags |= NETIF_FLAG_IGMP; + igmp_start(netif); + } + ip_addr_t ipgroup; + ipaddr_aton(group_ip, &ipgroup); + err_t err = igmp_joingroup(&netif->ip_addr, &ipgroup); + if(ERR_OK != err) { + printf("Failed to join multicast group: %d", err); + break; + } + status = true; + } while(0); + + if (status) { + printf("Join successs\n"); + udp_recv(upcb, recv, upcb); + } else { + if (upcb) { + udp_remove(upcb); + } + upcb = NULL; + } + return upcb; +} + +static void send(struct udp_pcb *upcb, struct ip_addr *addr, u16_t port) +{ + struct pbuf *p; + char msg[500]; + snprintf(msg, sizeof(msg), + "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n" + "EXT:\r\n" + "LOCATION: http://%s:80/setup.xml\r\n" + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n" + "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" + "ST: urn:Belkin:device:**\r\n" + "USN: uuid:Socket-1_0-38323636-4558-4dda-9188-cda0e6cc3dc0::urn:Belkin:device:**\r\n" + "X-User-Agent: redsonic\r\n\r\n", get_my_ip()); + + p = pbuf_alloc(PBUF_TRANSPORT, strlen(msg)+1, PBUF_RAM); + + if (!p) { + printf("Failed to allocate transport buffer\n"); + } else { + memcpy(p->payload, msg, strlen(msg)+1); + err_t err = udp_sendto(upcb, p, addr, port); + if (err < 0) { + printf("Error sending message: %s (%d)\n", lwip_strerr(err), err); + } else { + printf("Sent message '%s'\n", msg); + } + pbuf_free(p); + } +} + +/** + * @brief This function is called when an UDP datagrm has been received on the port UDP_PORT. + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + * @retval None + */ +static void receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +{ + if (p) { + printf("Msg received port:%d len:%d\n", port, p->len); + uint8_t *buf = (uint8_t*) p->payload; + printf("Msg received port:%d len:%d\nbuf: %s\n", port, p->len, buf); + + send(upcb, addr, port); + + pbuf_free(p); + } +} + +/** + * @brief Initialize the upnp server + * @retval true if init was succcessful + */ +bool upnp_server_init(void) +{ + struct udp_pcb *upcb = mcast_join_group(UPNP_MCAST_GRP, UPNP_MCAST_PORT, receive_callback); + return (upcb != NULL); +} diff --git a/examples/upnp/upnp.h b/examples/upnp/upnp.h new file mode 100644 index 0000000..eb71f84 --- /dev/null +++ b/examples/upnp/upnp.h @@ -0,0 +1,2 @@ + +bool upnp_server_init(void); diff --git a/examples/upnp/upnp_test.c b/examples/upnp/upnp_test.c new file mode 100644 index 0000000..b3da04c --- /dev/null +++ b/examples/upnp/upnp_test.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lwipopts.h" +#include "upnp.h" +#include "httpd.h" + +/** User friendly FreeRTOS delay macro */ +#define delay_ms(ms) vTaskDelay(ms / portTICK_PERIOD_MS) + +/** Semaphore to signal wifi availability */ +static SemaphoreHandle_t wifi_alive; + +/** + * @brief This is the multicast task + * @param arg user supplied argument from xTaskCreate + * @retval None + */ +static void mcast_task(void *arg) +{ + xSemaphoreTake(wifi_alive, portMAX_DELAY); + xSemaphoreGive(wifi_alive); + + (void) upnp_server_init(); + while(1) { + delay_ms(2000); + } +} + +/** + * @brief This is the wifi connection task + * @param arg user supplied argument from xTaskCreate + * @retval None + */ +static void wifi_task(void *pvParameters) +{ + uint8_t status = 0; + uint8_t retries = 30; + struct sdk_station_config config = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + }; + + xSemaphoreTake(wifi_alive, portMAX_DELAY); + printf("WiFi: connecting to WiFi\n"); + sdk_wifi_set_opmode(STATION_MODE); + sdk_wifi_station_set_config(&config); + + while(1) { + while (status != STATION_GOT_IP && retries) { + status = sdk_wifi_station_get_connect_status(); + if(status == STATION_WRONG_PASSWORD) { + printf("WiFi: wrong password\n"); + break; + } else if(status == STATION_NO_AP_FOUND) { + printf("WiFi: AP not found\n"); + break; + } else if(status == STATION_CONNECT_FAIL) { + printf("WiFi: connection failed\n"); + break; + } + delay_ms(1000); + retries--; + } + if (status == STATION_GOT_IP) { + printf("WiFi: connected\n"); + xSemaphoreGive(wifi_alive); + taskYIELD(); + } + + while ((status = sdk_wifi_station_get_connect_status()) == STATION_GOT_IP) { + xSemaphoreGive(wifi_alive); + taskYIELD(); + } + printf("WiFi: disconnected\n"); + sdk_wifi_station_disconnect(); + delay_ms(1000); + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + vSemaphoreCreateBinary(wifi_alive); + ota_tftp_init_server(TFTP_PORT); + xTaskCreate(&wifi_task, "wifi_task", 256, NULL, 2, NULL); + delay_ms(250); + xTaskCreate(&httpd_task, "http_server", 1024, NULL, 4, NULL); + xTaskCreate(&mcast_task, "mcast_task", 1024, NULL, 4, NULL); +}