diff --git a/src/AutoConnectCredential.cpp b/src/AutoConnectCredential.cpp index 5c4f1ff..ba46345 100644 --- a/src/AutoConnectCredential.cpp +++ b/src/AutoConnectCredential.cpp @@ -129,7 +129,6 @@ int8_t AutoConnectCredential::load(const char* ssid, struct station_config* conf _dp = AC_HEADERSIZE; if (_entries) { - Serial.printf("load: length series, AC_HEADERSIZE(%d), _containSize(%d)\n", AC_HEADERSIZE, _containSize); _eeprom->begin(AC_HEADERSIZE + _containSize); for (uint8_t i = 0; i < _entries; i++) { _retrieveEntry(reinterpret_cast(config->ssid), reinterpret_cast(config->password), config->bssid); @@ -315,12 +314,24 @@ void AutoConnectCredential::_retrieveEntry(char* ssid, char* password, uint8_t* * Free area are filled with FF, which is reused as an area for insertion. */ AutoConnectCredential::AutoConnectCredential() { + _allocateEntry(); +} + +AutoConnectCredential::AutoConnectCredential(uint16_t offset) { + // In ESP32, always use from the beginning of the Preferences area. + // The offset parameter is invalid but preserved for backward compatibility. + (void)(offset); + _allocateEntry(); +} + +void AutoConnectCredential::_allocateEntry(void) { _pref.reset(new Preferences); _entries = _import(); } AutoConnectCredential::~AutoConnectCredential() { _credit.clear(); + _pref->end(); _pref.reset(); } @@ -335,10 +346,8 @@ bool AutoConnectCredential::del(const char* ssid) { if (it != _credit.end()) { _credit.erase(it); _entries = _credit.size(); - Serial.printf("%s deleted.\n", ssid); return true; } - Serial.printf("%s could not deleted, not found.\n", ssid); return false; } @@ -356,7 +365,7 @@ int8_t AutoConnectCredential::load(const char* ssid, struct station_config* conf if (it != _credit.end()) { _obtain(it, config); - // Detemine the number in entries + // Determine the number in entries int8_t en = 0; for (decltype(_credit)::iterator se = _credit.begin(), e = _credit.end(); se != e; ++se) { if (it == se) @@ -398,7 +407,6 @@ bool AutoConnectCredential::load(int8_t entry, struct station_config* config) { */ bool AutoConnectCredential::save(const struct station_config* config) { if (_add(config)) { - Serial.printf("%s added.\n", config->ssid); return _commit() > 0 ? true : false; } return false; @@ -424,8 +432,8 @@ bool AutoConnectCredential::_add(const station_config_t* config) { // Insert AC_CREDTBODY_t credtBody; credtBody.password = String(reinterpret_cast(config->password)); - memcpy(credtBody.bssid, config->bssid, sizeof(((AC_CREDTBODY_t*)0)->bssid)); - std::pair::iterator, bool> rc = _credit.insert(std::make_pair(ssid, credtBody)); + memcpy(credtBody.bssid, config->bssid, sizeof(AC_CREDTBODY_t::bssid)); + std::pair rc = _credit.insert(std::make_pair(ssid, credtBody)); _entries = _credit.size(); return rc.second; } @@ -442,16 +450,14 @@ size_t AutoConnectCredential::_commit(void) { size_t psz = 0; // Calculate the container size for saving to NVS. - // Calculate the serialization size for each entry and add the size - // of 'e' with the size of 'ss' to it. + // Calculate the serialization size for each entry and add the size of 'e' with the size of 'ss' to it. for (const auto& credt : _credit) { ssid = credt.first; credtBody = credt.second; - sz += ssid.length() + sizeof('\0') + credtBody.password.length() + sizeof('\0') + sizeof(((AC_CREDTBODY_t*)0)->bssid); + sz += ssid.length() + sizeof('\0') + credtBody.password.length() + sizeof('\0') + sizeof(AC_CREDTBODY_t::bssid); } _entries = _credit.size(); - // When the entry is not empty, the size of container terminator as - // '\0' must be added. + // When the entry is not empty, the size of container terminator as '\0' must be added. _containSize = sz + (_entries ? sizeof('\0') : 0); // Add size of 'e' and 'ss' field. psz = _containSize + sizeof(uint8_t) + sizeof(uint16_t); @@ -459,29 +465,42 @@ size_t AutoConnectCredential::_commit(void) { // Dump container to serialization pool and write it back to NVS. uint8_t* credtPool = (uint8_t*)malloc(psz); if (credtPool) { - credtPool[0] = _entries; - credtPool[1] = (uint8_t)((uint16_t)psz & 0x00ff); - credtPool[2] = (uint8_t)((uint16_t)psz >> 8); + credtPool[0] = _entries; // 'e' + credtPool[1] = (uint8_t)((uint16_t)psz & 0x00ff); // 'ss' low byte + credtPool[2] = (uint8_t)((uint16_t)psz >> 8); // 'ss' high byte + // Starts dump of credential entries uint16_t dp = 3; for (const auto& credt : _credit) { - ssid = credt.first; - credtBody = credt.second; + ssid = credt.first; // Retrieve SSID + credtBody = credt.second; // Retrieve an entry + // SSID size_t itemLen = ssid.length() + sizeof('\0'); ssid.toCharArray(reinterpret_cast(&credtPool[dp]), itemLen); + // Password dp += itemLen; itemLen = credtBody.password.length() + sizeof('\0'); credtBody.password.toCharArray(reinterpret_cast(&credtPool[dp]), itemLen); + // BSSID dp += itemLen; - memcpy(&credtPool[dp], credtBody.bssid, sizeof(((station_config_t*)0)->bssid)); - dp += sizeof(((station_config_t*)0)->bssid); + memcpy(&credtPool[dp], credtBody.bssid, sizeof(station_config_t::bssid)); + dp += sizeof(station_config_t::bssid); } - credtPool[dp] = '\0'; - if (_pref->begin(AC_CREDENTIAL_NVSNAME)) { + credtPool[dp] = '\0'; // Terminates a container + // Write back to the nvs + if (_pref->begin(AC_CREDENTIAL_NVSNAME, false)) { sz = _pref->putBytes(AC_CREDENTIAL_NVSKEY, credtPool, psz); _pref->end(); } + #ifdef AC_DBG + else + AC_DBG("Preferences begin failed to save " AC_CREDENTIAL_NVSKEY "\n"); + #endif free(credtPool); } + #ifdef AC_DBG + else + AC_DBG("Preferences pool %d(B) allocation failed\n", psz); + #endif return sz; } @@ -491,40 +510,60 @@ size_t AutoConnectCredential::_commit(void) { */ uint8_t AutoConnectCredential::_import(void) { uint8_t cn = 0; - if (_pref->begin(AC_CREDENTIAL_NVSNAME)) { + if (_pref->begin(AC_CREDENTIAL_NVSNAME, true)) { size_t psz = _pref->getBytesLength(AC_CREDENTIAL_NVSKEY); if (psz) { uint8_t* credtPool = (uint8_t*)malloc(psz); if (credtPool) { _pref->getBytes(AC_CREDENTIAL_NVSKEY, static_cast(credtPool), psz); _credit.clear(); - cn = credtPool[0]; - _containSize = credtPool[1] + (uint16_t)(credtPool[2] << 8); + cn = credtPool[0]; // Retrieve 'e' + _containSize = credtPool[1] + (uint16_t)(credtPool[2] << 8); // Retrieve 'ss' uint16_t dp = sizeof(uint8_t) + sizeof(uint16_t); + // Starts import while (dp < psz - sizeof('\0')) { AC_CREDTBODY_t credtBody; + // SSID String ssid = String(reinterpret_cast(&credtPool[dp])); + // Password dp += ssid.length() + sizeof('\0'); credtBody.password = String(reinterpret_cast(&credtPool[dp])); + // BSSID dp += credtBody.password.length() + sizeof('\0'); - for (uint8_t ep = 0; ep < sizeof(((AC_CREDTBODY_t*)0)->bssid); ep++) + for (uint8_t ep = 0; ep < sizeof(AC_CREDTBODY_t::bssid); ep++) credtBody.bssid[ep] = credtPool[dp++]; + // Make an entry _credit.insert(std::make_pair(ssid, credtBody)); } free(credtPool); } + #ifdef AC_DBG + else + AC_DBG("Preferences pool %d(B) allocation failed\n", psz); + #endif } _pref->end(); } + #ifdef AC_DBG + else + AC_DBG("Preferences begin failed to import " AC_CREDENTIAL_NVSKEY "\n"); + #endif return cn; } -void AutoConnectCredential::_obtain(std::map::iterator const& it, station_config_t* config) { +/** + * Obtains an entry pointed to by the specified iterator from the + * dictionary as the std::map that maintains the credentials into the + * station_config structure. + * @param it An iterator to an entry + * @param config the station_config structure storing SSID and password. + */ +void AutoConnectCredential::_obtain(AC_CREDT_t::iterator const& it, station_config_t* config) { String ssid = it->first; AC_CREDTBODY_t& credtBody = it->second; - ssid.toCharArray(reinterpret_cast(config->ssid), sizeof(((station_config_t*)0)->ssid)); - credtBody.password.toCharArray(reinterpret_cast(config->password), sizeof(((station_config_t*)0)->password)); - memcpy(config->bssid, credtBody.bssid, sizeof(((station_config_t*)0)->bssid)); + ssid.toCharArray(reinterpret_cast(config->ssid), sizeof(station_config_t::ssid)); + credtBody.password.toCharArray(reinterpret_cast(config->password), sizeof(station_config_t::password)); + memcpy(config->bssid, credtBody.bssid, sizeof(station_config_t::bssid)); } #endif diff --git a/src/AutoConnectCredential.h b/src/AutoConnectCredential.h index 6b6164b..cd8858a 100644 --- a/src/AutoConnectCredential.h +++ b/src/AutoConnectCredential.h @@ -22,25 +22,20 @@ extern "C" { #include #include #include -struct station_config { - uint8_t ssid[32]; - uint8_t password[64]; - uint8_t bssid_set; - uint8_t bssid[6]; - wifi_fast_scan_threshold_t threshold; -}; #endif -/** Credential storage area offset specifier in EEPROM. - * By defining AC_IDENTIFIER_OFFSET macro in the user sketch, the credential - * storage area can be shifted in EEPROM. +/** + * Credential storage area offset specifier in EEPROM. + * By defining AC_IDENTIFIER_OFFSET macro in the user sketch, the credential + * storage area can be shifted in EEPROM. */ #ifndef AC_IDENTIFIER_OFFSET #define AC_IDENTIFIER_OFFSET 0 #endif /** - * + * Storage identifier for AutoConnect credentials. It is global constant + * and reserved. */ #ifndef AC_IDENTIFIER #define AC_IDENTIFIER "AC_CREDT" @@ -48,7 +43,7 @@ struct station_config { class AutoConnectCredentialBase { public: - explicit AutoConnectCredentialBase() {} + explicit AutoConnectCredentialBase() : _entries(0), _containSize(0) {} virtual ~AutoConnectCredentialBase() {} virtual uint8_t entries(void) { return _entries; } virtual bool del(const char* ssid) = 0; @@ -57,6 +52,8 @@ class AutoConnectCredentialBase { virtual bool save(const struct station_config* config) = 0; protected: + virtual void _allocateEntry(void) = 0; /**< Initialize storage for credentials. */ + uint8_t _entries; /**< Count of the available entry */ uint16_t _containSize; /**< Container size */ }; @@ -69,14 +66,16 @@ class AutoConnectCredential : public AutoConnectCredentialBase { AutoConnectCredential(); explicit AutoConnectCredential(uint16_t offset); ~AutoConnectCredential(); - bool del(const char* ssid) override; - int8_t load(const char* ssid, struct station_config* config) override; - bool load(int8_t entry, struct station_config* config) override; - bool save(const struct station_config* config) override; + bool del(const char* ssid) override; + int8_t load(const char* ssid, struct station_config* config) override; + bool load(int8_t entry, struct station_config* config) override; + bool save(const struct station_config* config) override; + + protected: + void _allocateEntry(void) override; /**< Initialize storage for credentials. */ private: - void _allocateEntry(void); /**< Initialize storage for credentials. */ - void _retrieveEntry(char* ssid, char* password, uint8_t* bssid); /**< Read an available entry. */ + void _retrieveEntry(char* ssid, char* password, uint8_t* bssid); /**< Read an available entry. */ int _dp; /**< The current address in EEPROM */ int _ep; /**< The current entry address in EEPROM */ @@ -89,31 +88,43 @@ class AutoConnectCredential : public AutoConnectCredentialBase { #define AC_CREDENTIAL_NVSNAME AC_IDENTIFIER #define AC_CREDENTIAL_NVSKEY AC_CREDENTIAL_NVSNAME +struct station_config { + uint8_t ssid[32]; + uint8_t password[64]; + uint8_t bssid_set; + uint8_t bssid[6]; + wifi_fast_scan_threshold_t threshold; +}; + /** AutoConnectCredential class using Preferences for ESP32 */ class AutoConnectCredential : public AutoConnectCredentialBase { public: AutoConnectCredential(); explicit AutoConnectCredential(uint16_t offset); ~AutoConnectCredential(); - bool del(const char* ssid) override; - int8_t load(const char* ssid, struct station_config* config) override; - bool load(int8_t entry, struct station_config* config) override; - bool save(const struct station_config* config) override; + bool del(const char* ssid) override; + int8_t load(const char* ssid, struct station_config* config) override; + bool load(int8_t entry, struct station_config* config) override; + bool save(const struct station_config* config) override; + + protected: + void _allocateEntry(void) override; /**< Initialize storage for credentials. */ private: - typedef station_config station_config_t; typedef struct { String password; uint8_t bssid[6]; - } AC_CREDTBODY_t; + } AC_CREDTBODY_t; /**< Credential entry */ + typedef std::map AC_CREDT_t; + typedef station_config station_config_t; - bool _add(const station_config_t* config); - size_t _commit(void); - uint8_t _import(void); - void _obtain(std::map::iterator const& it, station_config_t* config); + bool _add(const station_config_t* config); /**< Add an entry */ + size_t _commit(void); /**< Write back to the nvs */ + uint8_t _import(void); /**< Import from the nvs */ + void _obtain(AC_CREDT_t::iterator const& it, station_config_t* config); /**< Obtain an entry from iterator */ - std::unique_ptr _pref; - std::map _credit; + AC_CREDT_t _credit; /**< Dictionary to maintain the credentials */ + std::unique_ptr _pref; /**< Preferences class instance to access the nvs */ }; #endif