請問如何同時啟用 STA 與 AP Mode 呢? (RTL8722DM)

Hi,我想於 RTL8722DM 同時啟用 AP 與 STA
但是實際情況會如下:
AP、STA 單獨啟動 => 正常
AP and STA 同時啟動 => 先啟動者會斷開連線, 剩下後啟動者
請問要怎麼做才能讓 AP 與 STA 模式同時啟用呢?

編譯器為 Arduino IDE
以下是我使用的 Code
#include <WiFi.h>

char ap_ssid[] = “yourNetwork”; //Set the AP’s SSID
char ap_pass[] = “Password”; //Set the AP’s password

char channel[] = “1”; //Set the AP’s channel
int ap_status = WL_IDLE_STATUS; //Set the Wifi radio’s status
int sta_status = WL_IDLE_STATUS; //Set the Wifi radio’s status

char sta_ssid[] = “yourNetwork”; //Set the STA’s SSID
char sta_pass[] = “Password”; //Set the STA’s password

int ssid_status = 0; //Set SSID status, 1 hidden, 0 not hidden

void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    while (true);
}

// attempt to start AP:
while (ap_status != WL_CONNECTED) {
    Serial.print("Attempting to start AP with SSID: ");
    Serial.println(ap_ssid);
    ap_status = WiFi.apbegin(ap_ssid, ap_pass, channel, ssid_status);
    delay(5000);
}
Serial.print("AP Status: ");
Serial.println(ap_status);

// attempt to start STA:
while (sta_status != WL_CONNECTED) {
    Serial.print("Attempting to start AP with SSID: ");
    Serial.println(sta_ssid);
    sta_status = WiFi.begin(sta_ssid, sta_pass);
    delay(5000);
}
Serial.print("STA Status: ");
Serial.println(sta_status);

}

void loop() {
//
}

1 Like

Hi @David_Xiao

請查看下面的code

如果要AP和STA同時開啓,需要將這一行的參數改成下面的macro:

RTW_MODE_STA_AP

更多訊息可以在下面找到:

您好,非常感謝您的幫忙
但是有些問題想要請教您
問題1:修改 macro 後,先啟動 STA(WiFi.begin) 後,啟動 AP (WiFi.apbegin),原本連線到的 STA 會斷開連線,我嘗試修改 wifi_drv.cpp 的RTW_MODE_STA → RTW_MODE_STA_AP,但依然無法改善

問題2:先啟動 AP (WiFi.apbegin) 後,啟動 STA(WiFi.begin) ,AP的 SSID 可以搜尋的到,STA 也無中斷連線,但是 Print 出現的 code 顯示 AP 錯誤:LwIP_DHCP: dhcp stop,ERROR: Start AP timeout
手機嘗試連線時,則出現:無法加入網路,若您的網路安全性由WiFi 位址所管理,您可能需要關閉"專用WIFI 位址" 或修改您的網路設定

問題3:今日嘗試連線 5 GHz 的網路,但是無法連線上,想詢問您要如何使用 WiFi.h 的 Function 進行設定呢?

不好意思,再麻煩您協助指教了

1 Like

當你使用wifi begin的時候,你就用到了下面的function,這裏是默認只支持STA模式的,看這裏

你可以試著用上面的方法改一下,但是這不是最好的解決方法,最好的還是可以創建一個新的API來調整WiFi的模式參數

您好,我嘗試創建 Function 來測試
STA 連線的同時,AP 的顯示也出現了
但是點選 AP 名稱連線時,則顯示無法連線

附件為我模仿原有 Code 創建的 Function
WiFi.cpp
//----------------------New----------------------//
int WiFiClass::repeaterBegin(char* ap_ssid, char* ap_password, char* ap_channel, uint8_t ap_hidden_ssid, char* sta_ssid, const char* sta_passphrase)
{
uint8_t status = WL_IDLE_STATUS;
WiFiDrv::repeaterInit();

status = WiFiDrv::apRepeaterSetting(ap_ssid, strlen(ap_ssid), ap_password, strlen(ap_password), ap_channel);
printf("AP : %d\n", status);

status = WiFiDrv::staRepeaterSetting(sta_ssid, strlen(sta_ssid), sta_passphrase, strlen(sta_passphrase));
printf("STA : %d\n", status);

WiFiDrv::repeaterDriverRun(ap_hidden_ssid);

return status;

}
//----------------------New----------------------//

wifi_drv.cpp
//----------------------New----------------------//
int8_t WiFiDrv::apRepeaterSetting(char* ssid, uint8_t ssid_len, const char *passphrase, uint8_t len, const char *channel)
{
int ret = WL_SUCCESS;

//SSID Cheak
ap.ssid.len = ssid_len;

if (ap.ssid.len > 32) {
    printf("Error: SSID length can't exceed 32\n\r");
    ret = WL_FAILURE;
}
strcpy((char *)ap.ssid.val, (char*)ssid);

if (ap.ssid.val[0] == 0) {
    printf("Error: SSID can't be empty\n\r");
    ret = WL_FAILURE;
}

//Password Cheak
strcpy((char *)password, (char*)passphrase);
ap.password = password;
ap.password_len = len;
if (ap.password_len <= 0) {
    printf("Error: Password can't be empty\n\r");
    ret = WL_FAILURE;
}

ap.security_type = RTW_SECURITY_WPA2_AES_PSK;

//Channel
ap.channel = (unsigned char) atoi((const char *)channel);
	
return ret;

}

int8_t WiFiDrv::staRepeaterSetting(char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len)
{
int ret = WL_SUCCESS;

memset(wifi.bssid.octet, 0, ETH_ALEN);
memcpy(wifi.ssid.val, ssid, ssid_len);
wifi.ssid.len = ssid_len;

if(wifi.ssid.len <= 0){
	printf("Error: SSID can't be empty\n\r");
    ret = WL_FAILURE;
}

memset(password, 0, sizeof(password));
memcpy(password, passphrase, len);

wifi.password = password;
wifi.password_len = len;

if(wifi.password_len <= 0){
	printf("Error: Password can't be empty\n\r");
    ret = WL_FAILURE;
}

wifi.security_type = RTW_SECURITY_WPA2_AES_PSK;
wifi.key_id = 0;

return ret;

//
uint8_t dhcp_result;
ret = wifi_connect((char*)wifi.ssid.val, wifi.security_type, (char*)wifi.password, wifi.ssid.len, wifi.password_len, wifi.key_id, NULL);

if (ret == RTW_SUCCESS) {
	dhcp_result = LwIP_DHCP(0, DHCP_START);
    if (dhcp_result == DHCP_ADDRESS_ASSIGNED) {
        return WL_SUCCESS;
    } else {
        wifi_disconnect();
        return WL_FAILURE;
    }
}

return ret;

}

int8_t apRepeaterActivate(uint8_t hidden_ssid)
{
int timeout = 20;
int ret = WL_SUCCESS;

printf("\n\rStarting AP ...");

if (hidden_ssid == 1) {
    ret = wifi_start_ap_with_hidden_ssid((char*)ap.ssid.val, ap.security_type, (char*)ap.password, ap.ssid.len, ap.password_len, ap.channel);
} else {
    ret = wifi_start_ap((char*)ap.ssid.val, ap.security_type, (char*)ap.password, ap.ssid.len, ap.password_len, ap.channel);
}

if(ret < 0) {
    printf("\n\rERROR: Operation failed!");
    ret = WL_FAILURE;
}

while (1) {
    char essid[33];

    if (wext_get_ssid(WLAN1_NAME, ((unsigned char *)essid)) > 0) {
        if (strcmp(((const char *)essid), ((const char *)ap.ssid.val)) == 0) {
            printf("\n\r%s started\n", ap.ssid.val);
            ret = WL_SUCCESS;
            break;
        }
    }

    if (timeout == 0) {
        printf("\n\rERROR: Start AP timeout!");
        ret = WL_FAILURE;
        break;
    }

    vTaskDelay(1 * configTICK_RATE_HZ);
    timeout --;
}
return ret;

}

int8_t staRepeaterActivate()
{
int ret;
uint8_t dhcp_result;

ret = wifi_connect((char*)wifi.ssid.val, wifi.security_type, (char*)wifi.password, wifi.ssid.len, wifi.password_len, wifi.key_id, NULL);

if (ret == RTW_SUCCESS) {
	dhcp_result = LwIP_DHCP(0, DHCP_START);
    if (dhcp_result == DHCP_ADDRESS_ASSIGNED) {
        return WL_SUCCESS;
    } else {
        wifi_disconnect();
        return WL_FAILURE;
    }
}

return ret;

}

void WiFiDrv::repeaterDriverRun(uint8_t hidden_ssid)
{
struct netif *pnetif = &xnetif[0];
wifi_mode = RTW_MODE_STA_AP;

if (init_wlan == false) {
	printf("init_wlan : false\n\r");	
    init_wlan = true;
    LwIP_Init();
	wifi_on(RTW_MODE_STA_AP);	
	staRepeaterActivate();		
	apRepeaterActivate(hidden_ssid);
	dhcps_init(pnetif);		
} else if(init_wlan == true){
	printf("init_wlan : true\n\r");		
	dhcps_deinit();
	wifi_off();
	vTaskDelay(20);
	wifi_on(RTW_MODE_STA_AP);
	staRepeaterActivate();
	apRepeaterActivate(hidden_ssid);
    dhcps_init(pnetif);
}

}

void WiFiDrv::repeaterInit()
{
init_wifi_struct();
}
//----------------------New----------------------//

再麻煩您協助解惑了

1 Like

hi @David_Xiao
看來你是想要做wifi repeater,這樣子的話,或許你直接看在standard SDK裏面已有的wifi repeater示例會比較好,因爲這個功能在arduino SDK是暫時還沒有支援的。

這個示例在GCC環境下編譯后一樣是可以用在RTL8722DM的

這邊有完整的過程解釋:

Hi @xidameng
wifi repeater 是由朋友告訴我的名稱
但並不確定 AP 與 STA 模式同時啟用是否為這個稱呼
我想要製作的是類似 ESP32 - “AP與STA模式” 同時存在的功能
並以此為基底製作 Wifi Mesh 的功能
非常感謝您的耐心指導,我會嘗試看看的

1 Like

@xidameng 您好!请问 STA 和 AP 同时开启的话,必须在同一信道吗?支不支持 STA 和 AP 在不同信道的情况?比如 STA 在信道 1,AP 在信道 6

STA 和 AP 是必须在同一信道,因为无线通讯硬件只有一个。

@wyy RTL8710BN 也是吗?STA 和 AP 必须同一个信道?

应该是,这些芯片都只有一个无线通讯硬件