Search code examples
cstructesp32esp-idf

Issue with struct assign values in C using ESP-IDF


I have 2 code setup wifi station for ESP32 using ESP-IDF:

Code A using initialize struct

wifi_config_t wifi_config = {
    .sta = {
        .ssid = "my_ssid",
        .password = "my_ssid_password"
    }
};

ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

Code B using assign value to struct

static uint8_t wifi_ssid[32] = "my_ssid";
static uint8_t wifi_pwd[64] = "my_ssid_password";

...

wifi_config_t wifi_config;
memset(wifi_config.sta.ssid, 0, 32);
memcpy(wifi_config.sta.ssid, wifi_ssid, 32);

memset(wifi_config.sta.password, 0, 64);
memcpy(wifi_config.sta.password, wifi_pwd, 64);
....

And wifi_config_t struct look like this:

typedef union {
    wifi_ap_config_t  ap;  /**< configuration of AP */
    wifi_sta_config_t sta; /**< configuration of STA */
} wifi_config_t;


/** @brief STA configuration settings for the ESP32 */
typedef struct {
    uint8_t ssid[32];      /**< SSID of target AP. */
    uint8_t password[64];  /**< Password of target AP. */
    wifi_scan_method_t scan_method;    /**< do all channel scan or fast scan */
    bool bssid_set;        /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
    uint8_t bssid[6];     /**< MAC address of target AP*/
    uint8_t channel;       /**< channel of target AP. Set to 1~13 to scan starting from the specified channel before connecting to AP. If the channel of AP is unknown, set it to 0.*/
    uint16_t listen_interval;   /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */
    wifi_sort_method_t sort_method;    /**< sort the connect AP in the list by rssi or security mode */
    wifi_scan_threshold_t  threshold;     /**< When sort_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
    wifi_pmf_config_t pmf_cfg;    /**< Configuration for Protected Management Frame. Will be advertized in RSN Capabilities in RSN IE. */
    uint32_t rm_enabled:1;        /**< Whether Radio Measurements are enabled for the connection */
    uint32_t btm_enabled:1;       /**< Whether BSS Transition Management is enabled for the connection */
    uint32_t mbo_enabled:1;       /**< Whether MBO is enabled for the connection */
    uint32_t transition_disable:1;      /**< Whether to enable transition disable feature */
    uint32_t reserved:28;         /**< Reserved for future feature set */
    wifi_sae_pwe_method_t sae_pwe_h2e;     /**< Whether SAE hash to element is enabled */
    uint8_t failure_retry_cnt;    /**< Number of connection retries station will do before moving to next AP. scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config. Note: Enabling this may cause connection time to increase incase best AP doesn't behave properly. */
} wifi_sta_config_t;

And some how, just code A work. Code B isn't work, I have an error WIFI_REASON_NO_AP_FOUND. Can someone help to explain this issue?


Solution

  • In "code A", the whole wifi_sta_config_t will be initialized. It's as-if you did

    memset(&wifi_config, 0, sizeof wifi_config);
    

    before initializing the two members, ssid and password.

    In "code B", that initialization is absent so, all the rest of the members in the wifi_sta_config_t are left uninitialized and reading from those will result in undefined behavior.

    Either do

    memset(&wifi_config, 0, sizeof wifi_config);
    

    before doing the two memcpys, or initialize the whole instance directly when you create it and skip the memsets:

    static uint8_t wifi_ssid[sizeof (wifi_sta_config_t){}.ssid] = "my_ssid";
    static uint8_t wifi_pwd[sizeof (wifi_sta_config_t){}.password] = "my_ssid_password";
    
    // ...
    
    void func() {
        wifi_config_t wifi_config = {0};                            // zero-initialize
    
        memcpy(wifi_config.sta.ssid, wifi_ssid, sizeof wifi_ssid);
        memcpy(wifi_config.sta.password, wifi_pwd, sizeof wifi_pwd);
    
        // ...
    }