esp8266 sdk 3.1.1软件bug
在调试mqtt连接时,需要使用lwip debug,打开LWIP_DEBUG debug调试
#ifdef LWIP_DEBUG
#ifndef LWIP_PLATFORM_DIAG
#error "If you want to use LWIP_DEBUG, LWIP_PLATFORM_DIAG(message) needs to be defined in your arch/cc.h"
#endif
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
((debug) & LWIP_DBG_TYPES_ON) && \
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
LWIP_PLATFORM_DIAG(message); \
if ((debug) & LWIP_DBG_HALT) { \
while(1); \
} \
} \
} while(0)
#else /* LWIP_DEBUG */
#define LWIP_DEBUGF(debug, message)
#endif /* LWIP_DEBUG */
打开调试只需要在arch/cc.h
/*
* Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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: Adam Dunkels <[email protected]>
*
*/
#ifndef __ARCH_CC_H__
#define __ARCH_CC_H__
#define EFAULT 14
#define LWIP_ERRNO_INCLUDE "sys/errno.h"
#if (1)
#define BYTE_ORDER LITTLE_ENDIAN
#else
#define BYTE_ORDER BIG_ENDIAN
#endif
typedef int sys_prot_t;
#define S16_F "hd"
#define U16_F "hu"
#define X16_F "hx"
#define S32_F "d"
#define U32_F "u"
#define X32_F "x"
//#define PACK_STRUCT_FIELD(x) x __attribute__((packed))
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
//add cdb 2019-12-18 打开lwip debug log 调试
#define LWIP_DEBUG
#include <stdio.h>
#ifdef LWIP_DEBUG
extern void sys_arch_assert(const char *file, int line);
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#define LWIP_PLATFORM_ASSERT(x) do {printf(x); sys_arch_assert(__ESP_FILE__, __LINE__);} while(0)
#else
#define LWIP_PLATFORM_DIAG(x)
#define LWIP_PLATFORM_ASSERT(x)
#endif
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 1
#endif
#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))
#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
#define LWIP_TIMEVAL_PRIVATE 0
#endif /* __ARCH_CC_H__ */
编译发现,软件报错
查看报错代码发现
sys_sem_t* sys_thread_sem_init(void)
{
sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*));
if (!sem){
// LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, "thread_sem_init: out of memory\n");
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("thread_sem_init: out of memory\n"));
return 0;
}
*sem = xSemaphoreCreateBinary();
if (!(*sem)){
free(sem);
// LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, "thread_sem_init: out of memory\n");
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("thread_sem_init: out of memory\n"));
return 0;
}
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, LWIP_THREAD_TLS, sem, sys_thread_sem_free);
return sem;
}
/*
* get per thread semphore
*/
sys_sem_t* sys_thread_sem_get(void)
{
sys_sem_t *sem = pvTaskGetThreadLocalStoragePointer(NULL, LWIP_THREAD_TLS);
if (!sem) {
sem = sys_thread_sem_init();
}
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem));
return sem;
}
从上面可以发现,调用LWIP_DEBUGF(debug, message) message 参数需要括号包起来,原因是
从新编译,就能够成功了。
想使用LWIP_DEBUG看log,除了上面定义LWIP_DEBUG,还需要LWIP_DEBUGF(debug, message),debug值置为非零值。可以从宏函数定义中看到。
下面是我打开LWIP_DEBUG的初衷,mqtt连接失败,发现问题出现在mqtt lwip_connect中:
lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
struct lwip_sock *sock;
err_t err;
sock = get_socket(s);
if (!sock) {
return -1;
}
if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
/* sockaddr does not match socket type (IPv4/IPv6) */
sock_set_errno(sock, err_to_errno(ERR_VAL));
return -1;
}
LWIP_UNUSED_ARG(namelen);
if (name->sa_family == AF_UNSPEC) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
err = netconn_disconnect(sock->conn);
} else {
ip_addr_t remote_addr;
u16_t remote_port;
/* check size, family and alignment of 'name' */
LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_connect(sock->conn, &remote_addr, remote_port);
}
if (err != ERR_OK) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
sock_set_errno(sock, err_to_errno(err));
return -1;
}
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
sock_set_errno(sock, 0);
return 0;
}
下面log代码,打开成功了
SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
总结,打开调试log很简单,本文注意记录下esp8266 rtos sdk中的bug。
关于连接mqtt服务器,本例对接阿里云平台,后面博客在做介绍,现在从log中看到,连接mqtt服务失败原因应该是port号的问题,我代码中的port为1883。查看代码,发现端口应该赋值一个int 型变量,我传了一个字符串。