请问H3863开发板是否支持AP+STA并发?

Viewed 62

一、描述你遇到的问题

原本开发板连接着我手机热点的情况下可以连到MQTT服务器,进行订阅、发布和接收消息,但如果要同时开启热点(该热点用于与另一块开发板K210进行无线通信)的话就连不上MQTT服务器了(先连服务器再开热点就只能和另一块开发板通信,先开热点再连服务器会一直连不上服务器)。

主函数:
#include <string.h>

#include "soc_osal.h"
#include "app_init.h"
#include "cmsis_os2.h"

#include "wifi_connect.h"
#include "mqtt.h"

uint8_t g_response_buf[32] = {0};

void mqtt_init_task(void)
{
wifi_connect();
mqtt_connect();
softap_init_hotspot();
while(1)
{
socket_receive_image();//从K210接收被转化成比特流了的图像数据
osDelay(200);//需要延时,否则会发布失败
//发送图片
mqtt_publish(MQTT_TOPIC, g_buf);//g_buf定义在wifi_connect.c中
osDelay(200);
}
}

static void network_wifi_mqtt_example(void)
{
osal_printk("Enter HUAWEI IOT example()!");

osThreadAttr_t options;
options.name = "mqtt_init_task";
options.attr_bits = 0;
options.cb_mem = NULL;
options.cb_size = 0;
options.stack_mem = NULL;
options.stack_size = 0x2000;
options.priority = osPriorityNormal;

osThreadId_t mqtt_init_task_id = osThreadNew((osThreadFunc_t)mqtt_init_task, NULL, &options);
if (mqtt_init_task_id != NULL) {
    osal_printk("ID = %d, Create mqtt_init_task_id is OK!", mqtt_init_task_id);
}

}
/* Run the sample. */
app_run(network_wifi_mqtt_example);

mqtt.c:
/*
此处是MQTT协议的相关函数,实现数据远程的、跨网络的传输。
*/
#include "soc_osal.h"
#include "app_init.h"
#include "cmsis_os2.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClientPersistence.h"
#include "MQTTClient.h"
#include "errcode.h"

#include "wifi_connect.h"
#include "mqtt.h"

char *g_username = "K210_CAMERA";
char *g_password = "123456789";//服务器的账号、密码

MQTTClient client;
volatile MQTTClient_deliveryToken deliveredToken;

extern int MQTTClient_init(void);

//处理连接丢失回调函数
void connect_lost(void* context, char* cause)
{
osal_printk("connection lost : %s\r\n",cause);
}

//处理接收到消息的回调函数
int message_arrive(void* context, char* topicName, int topicLen, MQTTClient_message* message)
{
osal_printk("[Message receive topic]: %s\r\n",topicName);
osal_printk("[Message] : %s \r\n",(char *)message->payload);
return 1;//表示消息已被处理
}

//订阅主题
int mqtt_subscribe(const char *topic)
{
osal_printk("subscribe start!\r\n");
MQTTClient_subscribe(client,topic,1);
return 0;
}

//发布主题
int mqtt_publish(const char *topic,char *msg)
{
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
int ret = 0;
pubmsg.payload = msg;
pubmsg.payloadlen = (int)strlen(msg);
pubmsg.qos = 1;
pubmsg.retained = 0;
osal_printk("[payload]: %s,[topic]:%s\r\n",msg,topic);
ret = MQTTClient_publishMessage(client,topic,&pubmsg,&token);
if(ret != MQTTCLIENT_SUCCESS)
{
osal_printk("mqtt publish failed \r\n");
return ret;
}
return ret;
}

//处理消息传递完成回调函数
void delivered(void* context, MQTTClient_deliveryToken dt)
{
osal_printk("Message with token value %d delivery confirmed\r\n",dt);

deliveredToken = dt;

}

errcode_t mqtt_connect(void)
{
int ret;
MQTTClient_connectOptions mqtt_connect_opt = MQTTClient_connectOptions_initializer;// MQTT 3.1.1
//non-WebSockets,适用于嵌入式设备。
//初始化mqtt客户端
MQTTClient_init();

//创建mqtt客户端
ret = MQTTClient_create(&client, SERVER_IP_ADDR, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
if(ret != MQTTCLIENT_SUCCESS)
{
    osal_printk("Failed to create MQTT client,return code %d\r\n",ret);
    return ERRCODE_FAIL;
}
else
{
    osal_printk("create MQTT client succeed\n");
}
mqtt_connect_opt.keepAliveInterval = KEEP_ALIVE_INTERVAL;
mqtt_connect_opt.cleansession = 1;

mqtt_connect_opt.username = g_username;
mqtt_connect_opt.password = g_password;

//创建回调函数
if(MQTTClient_setCallbacks(client, NULL, connect_lost, message_arrive, delivered) 
        == MQTTCLIENT_SUCCESS)
{
    osal_printk("SetCallbacksSucceed\n");
}
else
{
    osal_printk("SetCallbacksFail\n");
}

//尝试连接
while(1)
{
    ret = MQTTClient_connect(client, &mqtt_connect_opt);
    if(ret == MQTTCLIENT_SUCCESS)
    {
        break;
    }
    else
    {
        osal_printk("[MQTT_Task] : Failed to connect ,return code %d\r\n",ret);
        osal_msleep(500);
    }
}
osal_printk("[MQTT_Task] : Connected to MQTT brocker\r\n");
osDelay(200);

//订阅MQTT主题
mqtt_subscribe(MQTT_TOPIC);
return ERRCODE_SUCC;

}
mqtt.h:
#ifndef __MQTT_H
#define __MQTT_H

#define SERVER_IP_ADDR "broker.emqx.io" //接入地址 hostname
#define SERVER_IP_PORT 1883 //port 单片机一般使用MQTT,端口1883
#define CLIENT_ID "01Studio-K210" //client_id
#define MQTT_TOPIC "/public/01Studio/1" //订阅主题
#define KEEP_ALIVE_INTERVAL 120 //生存时间

int mqtt_publish(const char *topic,char *msg);
errcode_t mqtt_connect(void);

#endif

wifi_connect.c:
/*
连接到所需热点/WiFi以上网、开启热点以和其他设备通信
*/
#include "lwip/netifapi.h"
#include "wifi_hotspot.h"
#include "wifi_hotspot_config.h"
#include "stdlib.h"
#include "uart.h"
#include "lwip/nettool/misc.h"
#include "soc_osal.h"
#include "app_init.h"
#include "cmsis_os2.h"
#include "wifi_connect.h"

#include "td_base.h"
#include "td_type.h"
#include "stdlib.h"

#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#define WIFI_SCAN_AP_LIMIT 64
#define WIFI_CONN_STATUS_MAX_GET_TIMES 5 /* 启动连接之后,判断是否连接成功的最大尝试次数 /
#define DHCP_BOUND_STATUS_MAX_GET_TIMES 20 /
启动DHCP Client端功能之后,判断是否绑定成功的最大尝试次数 /
#define WIFI_STA_IP_MAX_GET_TIMES 5 /
判断是否获取到IP的最大尝试次数 */

char g_buf[BUF_SIZE + 1] = {0};//wifi图传的缓冲区,拿到来自K210的比特流之后通过文件操作函数把它写进.jpg格式的空文件
//里去就可以还原回图片

int sfd = -1;

/*****************************************************************************
STA 扫描-关联 sample用例
*****************************************************************************/
static errcode_t example_get_match_network(const char *expected_ssid,
const char *key,
wifi_sta_config_stru expected_bss)
{
uint32_t num = WIFI_SCAN_AP_LIMIT; /
64:扫描到的Wi-Fi网络数量 */
uint32_t bss_index = 0;

/* 获取扫描结果 */
uint32_t scan_len = sizeof(wifi_scan_info_stru) * WIFI_SCAN_AP_LIMIT;
wifi_scan_info_stru *result = osal_kmalloc(scan_len, OSAL_GFP_ATOMIC);
if (result == NULL) {
    return ERRCODE_MALLOC;
}

memset_s(result, scan_len, 0, scan_len);
if (wifi_sta_get_scan_info(result, &num) != ERRCODE_SUCC) {
    osal_kfree(result);
    return ERRCODE_FAIL;
}

/* 筛选扫描到的Wi-Fi网络,选择待连接的网络 */
for (bss_index = 0; bss_index < num; bss_index++) {
    if (strlen(expected_ssid) == strlen(result[bss_index].ssid)) {
        if (memcmp(expected_ssid, result[bss_index].ssid, strlen(expected_ssid)) == 0) {
            break;
        }
    }
}

/* 未找到待连接AP,可以继续尝试扫描或者退出 */
if (bss_index >= num) {
    osal_kfree(result);
    return ERRCODE_FAIL;
}
/* 找到网络后复制网络信息和接入密码 */
if (memcpy_s(expected_bss->ssid, WIFI_MAX_SSID_LEN, result[bss_index].ssid, WIFI_MAX_SSID_LEN) != EOK) {
    osal_kfree(result);
    return ERRCODE_MEMCPY;
}
if (memcpy_s(expected_bss->bssid, WIFI_MAC_LEN, result[bss_index].bssid, WIFI_MAC_LEN) != EOK) {
    osal_kfree(result);
    return ERRCODE_MEMCPY;
}
expected_bss->security_type = result[bss_index].security_type;
if (memcpy_s(expected_bss->pre_shared_key, WIFI_MAX_KEY_LEN, key, strlen(key)) != EOK) {
    osal_kfree(result);
    return ERRCODE_MEMCPY;
}
expected_bss->ip_type = DHCP; /* IP类型为动态DHCP获取 */
osal_kfree(result);
return ERRCODE_SUCC;

}

errcode_t wifi_connect(void)
{
char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "wlan0"; /* WiFi STA 网络设备名 /
wifi_sta_config_stru expected_bss = {0}; /
连接请求信息 /
const char expected_ssid[] = CONFIG_WIFI_SSID;
const char key[] = CONFIG_WIFI_PWD; /
待连接的网络接入密码 */
struct netif *netif_p = NULL;
wifi_linked_info_stru wifi_status;
uint8_t index = 0;

/* 等待wifi初始化完成 */
while (wifi_is_wifi_inited() == 0) {
    (void)osDelay(10); /* 10: 延时100ms  */
}
/* 创建STA */
if (wifi_sta_enable() != ERRCODE_SUCC) {
    PRINT("STA enbale fail !\r\n");
    return ERRCODE_FAIL;
}
do {
    PRINT("Start Scan !\r\n");
    (void)osDelay(100); /* 100: 延时1s  */
    /* 启动STA扫描 */
    if (wifi_sta_scan() != ERRCODE_SUCC) {
        PRINT("STA scan fail, try again !\r\n");
        continue;
    }

    (void)osDelay(300); /* 300: 延时100ms  */

    /* 获取待连接的网络 */
    if (example_get_match_network(expected_ssid, key, &expected_bss) != ERRCODE_SUCC) {
        PRINT("Can not find AP, try again !\r\n");
        continue;
    }

    PRINT("STA start connect.\r\n");
    /* 启动连接 */
    if (wifi_sta_connect(&expected_bss) != ERRCODE_SUCC) {
        continue;
    }

    /* 检查网络是否连接成功 */
    for (index = 0; index < WIFI_CONN_STATUS_MAX_GET_TIMES; index++) {
        (void)osDelay(50); /* 50: 延时5s  */
        memset_s(&wifi_status, sizeof(wifi_linked_info_stru), 0, sizeof(wifi_linked_info_stru));
        if (wifi_sta_get_ap_info(&wifi_status) != ERRCODE_SUCC) {
            continue;
        }
        if (wifi_status.conn_state == WIFI_CONNECTED) {
            break;
        }
    }
    if (wifi_status.conn_state == WIFI_CONNECTED) {
        break; /* 连接成功退出循环 */
    }
} while (1);

/* DHCP获取IP地址 */
netif_p = netifapi_netif_find(ifname);
if (netif_p == NULL) {
    return ERRCODE_FAIL;
}

if (netifapi_dhcp_start(netif_p) != ERR_OK) {
    PRINT("STA DHCP Fail.\r\n");
    return ERRCODE_FAIL;
}

for (uint8_t i = 0; i < DHCP_BOUND_STATUS_MAX_GET_TIMES; i++) {
    (void)osDelay(50); /* 50: 延时500ms  */
    if (netifapi_dhcp_is_bound(netif_p) == ERR_OK) {
        PRINT("STA DHCP bound success.\r\n");
        break;
    }
}

for (uint8_t i = 0; i < WIFI_STA_IP_MAX_GET_TIMES; i++) {
    osDelay(1); /* 1: 延时10ms  */
    if (netif_p->ip_addr.u_addr.ip4.addr != 0) {
        PRINT("STA IP %u.%u.%u.%u\r\n", (netif_p->ip_addr.u_addr.ip4.addr & 0x000000ff),
              (netif_p->ip_addr.u_addr.ip4.addr & 0x0000ff00) >> 8,   /* 8: 移位  */
              (netif_p->ip_addr.u_addr.ip4.addr & 0x00ff0000) >> 16,  /* 16: 移位  */
              (netif_p->ip_addr.u_addr.ip4.addr & 0xff000000) >> 24); /* 24: 移位  */

        /* 连接成功 */
        PRINT("STA connect success.\r\n");
        break;
    }
}
return ERRCODE_SUCC;

}

//创建热点,自己作为TCP服务器。正常创建了的话就会返回0
int softap_init_hotspot(void)
{
/* SoftAp接口的信息 /
char ssid[WIFI_MAX_SSID_LEN] = "BearPi_Pico_H3863";
char pre_shared_key[WIFI_MAX_KEY_LEN] = "123456789";
softap_config_stru hapd_conf = {0};
softap_config_advance_stru config = {0};
char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "ap0"; /
创建的SoftAp接口名 */
struct netif netif_p = TD_NULL;
ip4_addr_t st_gw;
ip4_addr_t st_ipaddr;
ip4_addr_t st_netmask;
IP4_ADDR(&st_ipaddr, 192, 168, 43, 1); /
IP地址设置:192.168.43.1 /
IP4_ADDR(&st_netmask, 255, 255, 255, 0); /
子网掩码设置:255.255.255.0 /
IP4_ADDR(&st_gw, 192, 168, 43, 2); /
网关地址设置:192.168.43.2 */

/* 配置SoftAp基本参数 */
(void)memcpy_s(hapd_conf.ssid, sizeof(hapd_conf.ssid), ssid, sizeof(ssid));
(void)memcpy_s(hapd_conf.pre_shared_key, WIFI_MAX_KEY_LEN, pre_shared_key, WIFI_MAX_KEY_LEN);
hapd_conf.security_type = 3; /* 3: 加密方式设置为WPA_WPA2_PSK */
hapd_conf.channel_num = 13; /* 13:工作信道设置为13信道 */
hapd_conf.wifi_psk_type = 0;

/* 配置SoftAp网络参数 */
config.beacon_interval = 100; /* 100:Beacon周期设置为100ms */
config.dtim_period = 2; /* 2:DTIM周期设置为2 */
config.gi = 0; /* 0:short GI默认关闭 */
config.group_rekey = 86400; /* 86400:组播秘钥更新时间设置为1天 */
config.protocol_mode = 4; /* 4:协议类型设置为802.11b + 802.11g + 802.11n + 802.11ax */
config.hidden_ssid_flag = 1; /* 1:不隐藏SSID */
if (wifi_set_softap_config_advance(&config) != 0)
{
    osal_printk("wifi set softap fail\n");
    return -1;
}
else
{
    osal_printk("wifi set softap success\n");
}
/* 启动SoftAp接口 */
if (wifi_softap_enable(&hapd_conf) != 0)
{
    osal_printk("wifi softap enable fail\n");
    return -1;
}
else
{
    osal_printk("wifi softap enable success\n");
}
/* 配置DHCP服务器 */
netif_p = netif_find(ifname);
if (netif_p == TD_NULL)
{
    (void)wifi_softap_disable();
    return -1;
}
if (netifapi_netif_set_addr(netif_p, &st_ipaddr, &st_netmask, &st_gw) != 0)
{
    (void)wifi_softap_disable();
    return -1;
}
if (netifapi_dhcps_start(netif_p, NULL, 0) != 0)
{
    (void)wifi_softap_disable();
    return -1;
}
PRINT("%s::SoftAp start success.\r\n", WIFI_SOFTAP_SAMPLE_LOG);

/* 等待wifi初始化完成 /
while (wifi_is_wifi_inited() == 0)
{
(void)osDelay(10); /
1: 等待100ms后判断状态 */
}
PRINT("%s::wifi init succ.\r\n", WIFI_SOFTAP_SAMPLE_LOG);

int lsfd = -1;
struct sockaddr_in srv_addr = {0}; 
struct sockaddr_in cln_addr = {0}; 
socklen_t cln_addr_len = sizeof(cln_addr); 
int ret = 0; 
/* tcp server */ 
printf("going to call socket\n"); 
lsfd = socket(AF_INET,SOCK_STREAM,0);//创建套接字
if (lsfd == -1)
{ 
    printf("socket failed, return is %d\n", lsfd); 
    return -1;
} 
printf("socket succeeded\n"); 
srv_addr.sin_family = AF_INET; 
srv_addr.sin_addr.s_addr = inet_addr(STACK_IP); 
srv_addr.sin_port = htons(STACK_PORT);
ret = bind(lsfd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));//绑定地址
if (ret != 0)
{
    printf("bind failed, return is %d\n",  ret); 
    return -1;
} 
ret = listen(lsfd, 0);//启动监听
if (ret != 0)
{ 
    printf("listen failed, return is %d\n", ret); 
    return -1;
} 
printf("listen succeeded, return is %d\n", ret); 
printf("going to call accept\n"); 
sfd = accept(lsfd, (struct sockaddr *)&cln_addr, &cln_addr_len);//准备接受
if (sfd < 0)
{ 
    printf("accept failed, return is %d\n", sfd); 
} 
printf("accept succeeded, return is %d\n", sfd); 
return 0;

}

void socket_receive_image(void)
{
/* tcp server /
/
send /
memset(g_buf, 0, BUF_SIZE);
strcpy((char
)g_buf, MSG);
printf("calling send...\n");
int ret = send(sfd, g_buf, sizeof(MSG), 0);
if (ret <= 0)
{
printf("send failed, return is %d, i is %d\n", ret);
}
printf("send finished ret is %d\n", ret);
/* send /
/
recv /
memset(g_buf, 0, BUF_SIZE);
printf("going to call recv\n");
ret = recv(sfd, g_buf, sizeof(g_buf), 0);
if (ret <= 0)
{
printf("recv failed, return is %d\n", ret);
}
printf("recv succeeded, return is %d\n", ret);
printf("received msg is : %s\n", g_buf);
/
recv */
}
wifi_connect.h:
#ifndef __WIFI_CONNECT_H
#define __WIFI_CONNECT_H

#define CONFIG_WIFI_SSID "test" // 要连接的WiFi 热点账号
#define CONFIG_WIFI_PWD "123456789" // 要连接的WiFi 热点密码

#define WIFI_IFNAME_MAX_SIZE 16
#define WIFI_MAX_KEY_LEN 65
#define WIFI_MAX_SSID_LEN 33
#define WIFI_SOFTAP_SAMPLE_LOG "[WIFI_SOFTAP_SAMPLE]"

#define STACK_IP "192.168.43.1" //本机IP和
#define STACK_PORT 5001 //本机端口。这个是要在后面进行自主设置的(包括网关地
//址等),请保持一致性
#define MSG "Send me your image"
#define BUF_SIZE (1024 * 8)

extern char g_buf[BUF_SIZE + 1];//储存发送和接收到的数据的数组

#include "errcode.h"

errcode_t wifi_connect(void);
int softap_init_hotspot(void);
void socket_receive_image(void);

#endif

二、你具体做的所有步骤结果截图

先开启MQTT服务器,再重置H3863开发板,可以在串口助手上看到服务器发给它的消息,随后进入socket监听,再开启K210,连接到H3863的同时,两块开发板开始正常通信,却无法和MQTT服务器通信了。

三、当前开发板状态全景照片

没有任何引脚接了东西,就是单纯一块开发板通过type-c接到电脑上了而已

四、开发板串口所有日志


1 Answers

我在lwip开发指南里看到了这样一句话:
DHCP客户端允许UDP套接字接口绑定在DHCP客户端端口上,而lwIP不允许多个网口(包括以太网和Wi-Fi的netif结构体)绑定到同一个端口。因此,如果SO_BINDTODEVICE被禁用,则lwIP可以与两个网口(以太网和Wi-Fi)同时运行,但DHCP客户端不可以。
这个是不是原因?