PSRAM: Adds custom allocator and HS_MALLOC/HS_CALLOC macros
Forces all heap requests to be drawn from PSRAM, unless the device does not contain PSRAM. To do: Provide easy-to-use NEW() macro; add custom allocator to unordered sets; auto-shrink vectors after updateDatabase()
This commit is contained in:
parent
77e7ff2b2e
commit
8268e519dd
|
|
@ -1741,7 +1741,7 @@ nvs_handle HAPClient::srpNVS;
|
|||
HKDF HAPClient::hkdf;
|
||||
pairState HAPClient::pairStatus;
|
||||
Accessory HAPClient::accessory;
|
||||
list<Controller> HAPClient::controllerList;
|
||||
list<Controller, Mallocator<Controller>> HAPClient::controllerList;
|
||||
SRP6A HAPClient::srp;
|
||||
int HAPClient::conNum;
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ struct HAPClient {
|
|||
static pairState pairStatus; // tracks pair-setup status
|
||||
static SRP6A srp; // stores all SRP-6A keys used for Pair-Setup
|
||||
static Accessory accessory; // Accessory ID and Ed25519 public and secret keys- permanently stored
|
||||
static list<Controller> controllerList; // linked-list of Paired Controller IDs and ED25519 long-term public keys - permanently stored
|
||||
static list<Controller, Mallocator<Controller>> controllerList; // linked-list of Paired Controller IDs and ED25519 long-term public keys - permanently stored
|
||||
static int conNum; // connection number - used to keep track of per-connection EV notifications
|
||||
|
||||
// individual structures and data defined for each Hap Client connection
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa
|
|||
if(requestedMaxCon<maxConnections) // if specific request for max connections is less than computed max connections
|
||||
maxConnections=requestedMaxCon; // over-ride max connections with requested value
|
||||
|
||||
hap=(HAPClient **)calloc(maxConnections,sizeof(HAPClient *));
|
||||
hap=(HAPClient **)HS_CALLOC(maxConnections,sizeof(HAPClient *));
|
||||
for(int i=0;i<maxConnections;i++)
|
||||
hap[i]=new HAPClient;
|
||||
|
||||
|
|
@ -854,10 +854,14 @@ void Span::processSerialCommand(const char *c){
|
|||
break;
|
||||
|
||||
case 'm': {
|
||||
LOG0("Free Heap=%d bytes (low=%d)\n",heap_caps_get_free_size(MALLOC_CAP_DEFAULT),heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT));
|
||||
LOG0("Free Heap Internal RAM : %7d bytes. Low: %7d\n",heap_caps_get_free_size(MALLOC_CAP_INTERNAL),heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL));
|
||||
#if defined(BOARD_HAS_PSRAM)
|
||||
LOG0("Free Heap SPI (PS) RAM : %7d bytes. Low: %7d\n",heap_caps_get_free_size(MALLOC_CAP_SPIRAM),heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
|
||||
#endif
|
||||
LOG0("Lowest stack level : %7d bytes\n",uxTaskGetStackHighWaterMark(NULL));
|
||||
nvs_stats_t nvs_stats;
|
||||
nvs_get_stats(NULL, &nvs_stats);
|
||||
LOG0("NVS: %d of %d records used\n",nvs_stats.used_entries,nvs_stats.total_entries-126);
|
||||
LOG0("NVS Flash Partition : %7d of %d records used\n\n",nvs_stats.used_entries,nvs_stats.total_entries-126);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -868,7 +872,7 @@ void Span::processSerialCommand(const char *c){
|
|||
int nErrors=0;
|
||||
int nWarnings=0;
|
||||
|
||||
vector<uint32_t> aidValues;
|
||||
vector<uint32_t, Mallocator<uint32_t>> aidValues;
|
||||
char pNames[][7]={"PR","PW","EV","AA","TW","HD","WR"};
|
||||
|
||||
for(auto acc=Accessories.begin(); acc!=Accessories.end(); acc++){
|
||||
|
|
@ -1825,7 +1829,7 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){
|
|||
service=homeSpan.Accessories.back()->Services.back();
|
||||
aid=homeSpan.Accessories.back()->aid;
|
||||
|
||||
ev=(boolean *)calloc(homeSpan.maxConnections,sizeof(boolean));
|
||||
ev=(boolean *)HS_CALLOC(homeSpan.maxConnections,sizeof(boolean));
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
|
|
@ -2152,7 +2156,7 @@ void SpanWebLog::init(uint16_t maxEntries, const char *serv, const char *tz, con
|
|||
timeServer=serv;
|
||||
timeZone=tz;
|
||||
statusURL="GET /" + String(url) + " ";
|
||||
log = (log_t *)calloc(maxEntries,sizeof(log_t));
|
||||
log = (log_t *)HS_CALLOC(maxEntries,sizeof(log_t));
|
||||
if(timeServer)
|
||||
homeSpan.reserveSocketConnections(1);
|
||||
}
|
||||
|
|
@ -2492,7 +2496,7 @@ void SpanPoint::dataReceived(const uint8_t *mac, const uint8_t *incomingData, in
|
|||
uint8_t SpanPoint::lmk[16];
|
||||
boolean SpanPoint::initialized=false;
|
||||
boolean SpanPoint::isHub=false;
|
||||
vector<SpanPoint *> SpanPoint::SpanPoints;
|
||||
vector<SpanPoint *, Mallocator<SpanPoint *>> SpanPoint::SpanPoints;
|
||||
uint16_t SpanPoint::channelMask=0x3FFE;
|
||||
QueueHandle_t SpanPoint::statusQueue;
|
||||
nvs_handle SpanPoint::pointNVS;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@
|
|||
#error ERROR: HOMESPAN IS ONLY AVAILABLE FOR ESP32 MICROCONTROLLERS!
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_HAS_PSRAM)
|
||||
#define HS_MALLOC ps_malloc
|
||||
#define HS_CALLOC ps_calloc
|
||||
#else
|
||||
#define HS_MALLOC malloc
|
||||
#define HS_CALLOC calloc
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wpmf-conversions" // eliminates warning messages from use of pointers to member functions to detect whether update() and loop() are overridden by user
|
||||
#pragma GCC diagnostic ignored "-Wunused-result" // eliminates warning message regarded unused result from call to crypto_scalarmult_curve25519()
|
||||
|
||||
|
|
@ -69,6 +77,25 @@ enum {
|
|||
|
||||
///////////////////////////////
|
||||
|
||||
template <class T>
|
||||
struct Mallocator {
|
||||
typedef T value_type;
|
||||
Mallocator() = default;
|
||||
template <class U> constexpr Mallocator(const Mallocator<U>&) noexcept {}
|
||||
[[nodiscard]] T* allocate(std::size_t n) {
|
||||
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
|
||||
if(auto p = static_cast<T*>(HS_MALLOC(n*sizeof(T)))) return p;
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
void deallocate(T* p, std::size_t) noexcept { std::free(p); }
|
||||
};
|
||||
template <class T, class U>
|
||||
bool operator==(const Mallocator<T>&, const Mallocator<U>&) { return true; }
|
||||
template <class T, class U>
|
||||
bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { return false; }
|
||||
|
||||
///////////////////////////////
|
||||
|
||||
#define STATUS_UPDATE(LED_UPDATE,MESSAGE_UPDATE) {homeSpan.statusLED->LED_UPDATE;if(homeSpan.statusCallback)homeSpan.statusCallback(MESSAGE_UPDATE);}
|
||||
|
||||
enum HS_STATUS {
|
||||
|
|
@ -251,10 +278,10 @@ class Span{
|
|||
|
||||
SpanOTA spanOTA; // manages OTA process
|
||||
SpanConfig hapConfig; // track configuration changes to the HAP Accessory database; used to increment the configuration number (c#) when changes found
|
||||
vector<SpanAccessory *> Accessories; // vector of pointers to all Accessories
|
||||
vector<SpanService *> Loops; // vector of pointer to all Services that have over-ridden loop() methods
|
||||
vector<SpanBuf> Notifications; // vector of SpanBuf objects that store info for Characteristics that are updated with setVal() and require a Notification Event
|
||||
vector<SpanButton *> PushButtons; // vector of pointer to all PushButtons
|
||||
vector<SpanAccessory *, Mallocator<SpanAccessory *>> Accessories; // vector of pointers to all Accessories
|
||||
vector<SpanService *, Mallocator<SpanService *>> Loops; // vector of pointer to all Services that have over-ridden loop() methods
|
||||
vector<SpanBuf, Mallocator<SpanBuf>> Notifications; // vector of SpanBuf objects that store info for Characteristics that are updated with setVal() and require a Notification Event
|
||||
vector<SpanButton *, Mallocator<SpanButton *>> PushButtons; // vector of pointer to all PushButtons
|
||||
unordered_map<uint64_t, uint32_t> TimedWrites; // map of timed-write PIDs and Alarm Times (based on TTLs)
|
||||
|
||||
unordered_map<char, SpanUserCommand *> UserCommands; // map of pointers to all UserCommands
|
||||
|
|
@ -387,7 +414,7 @@ class SpanAccessory{
|
|||
|
||||
uint32_t aid=0; // Accessory Instance ID (HAP Table 6-1)
|
||||
int iidCount=0; // running count of iid to use for Services and Characteristics associated with this Accessory
|
||||
vector<SpanService *> Services; // vector of pointers to all Services in this Accessory
|
||||
vector<SpanService *, Mallocator<SpanService*>> Services; // vector of pointers to all Services in this Accessory
|
||||
|
||||
int sprintfAttributes(char *cBuf, int flags); // prints Accessory JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator, even if buf=NULL
|
||||
|
||||
|
|
@ -414,8 +441,8 @@ class SpanService{
|
|||
const char *hapName; // HAP Name
|
||||
boolean hidden=false; // optional property indicating service is hidden
|
||||
boolean primary=false; // optional property indicating service is primary
|
||||
vector<SpanCharacteristic *> Characteristics; // vector of pointers to all Characteristics in this Service
|
||||
vector<SpanService *> linkedServices; // vector of pointers to any optional linked Services
|
||||
vector<SpanCharacteristic *, Mallocator<SpanCharacteristic*>> Characteristics; // vector of pointers to all Characteristics in this Service
|
||||
vector<SpanService *, Mallocator<SpanService *>> linkedServices; // vector of pointers to any optional linked Services
|
||||
boolean isCustom; // flag to indicate this is a Custom Service
|
||||
SpanAccessory *accessory=NULL; // pointer to Accessory containing this Service
|
||||
|
||||
|
|
@ -424,8 +451,8 @@ class SpanService{
|
|||
protected:
|
||||
|
||||
virtual ~SpanService(); // destructor
|
||||
vector<HapChar *> req; // vector of pointers to all required HAP Characteristic Types for this Service
|
||||
vector<HapChar *> opt; // vector of pointers to all optional HAP Characteristic Types for this Service
|
||||
vector<HapChar *, Mallocator<HapChar*>> req; // vector of pointers to all required HAP Characteristic Types for this Service
|
||||
vector<HapChar *, Mallocator<HapChar*>> opt; // vector of pointers to all optional HAP Characteristic Types for this Service
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -433,7 +460,7 @@ class SpanService{
|
|||
SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self
|
||||
SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self
|
||||
SpanService *addLink(SpanService *svc); // adds svc as a Linked Service and returns pointer to self
|
||||
vector<SpanService *> getLinks(){return(linkedServices);} // returns linkedServices vector for use as range in "for-each" loops
|
||||
vector<SpanService *, Mallocator<SpanService *>> getLinks(){return(linkedServices);} // returns linkedServices vector for use as range in "for-each" loops
|
||||
|
||||
virtual boolean update() {return(true);} // placeholder for code that is called when a Service is updated via a Controller. Must return true/false depending on success of update
|
||||
virtual void loop(){} // loops for each Service - called every cycle if over-ridden with user-defined code
|
||||
|
|
@ -589,7 +616,7 @@ class SpanCharacteristic{
|
|||
uvSet(value,val);
|
||||
|
||||
if(nvsStore){
|
||||
nvsKey=(char *)malloc(16);
|
||||
nvsKey=(char *)HS_MALLOC(16);
|
||||
uint16_t t;
|
||||
sscanf(type,"%hx",&t);
|
||||
sprintf(nvsKey,"%04X%08X%03X",t,aid,iid&0xFFF);
|
||||
|
|
@ -901,7 +928,7 @@ class SpanPoint {
|
|||
static uint8_t lmk[16];
|
||||
static boolean initialized;
|
||||
static boolean isHub;
|
||||
static vector<SpanPoint *> SpanPoints;
|
||||
static vector<SpanPoint *, Mallocator<SpanPoint *>> SpanPoints;
|
||||
static uint16_t channelMask; // channel mask (only used for remote devices)
|
||||
static QueueHandle_t statusQueue; // queue for communication between SpanPoint::dataSend and SpanPoint::send
|
||||
static nvs_handle pointNVS; // NVS storage for channel number (only used for remote devices)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ void Network::scan(){
|
|||
int n=WiFi.scanNetworks();
|
||||
|
||||
free(ssidList);
|
||||
ssidList=(char **)calloc(n,sizeof(char *));
|
||||
ssidList=(char **)HS_CALLOC(n,sizeof(char *));
|
||||
numSSID=0;
|
||||
|
||||
for(int i=0;i<n;i++){
|
||||
|
|
@ -50,7 +50,7 @@ void Network::scan(){
|
|||
found=true;
|
||||
}
|
||||
if(!found){
|
||||
ssidList[numSSID]=(char *)calloc(WiFi.SSID(i).length()+1,sizeof(char));
|
||||
ssidList[numSSID]=(char *)HS_CALLOC(WiFi.SSID(i).length()+1,sizeof(char));
|
||||
sprintf(ssidList[numSSID],"%s",WiFi.SSID(i).c_str());
|
||||
numSSID++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ int TLV<tagType, maxTags>::create(tagType tag, int maxLen, const char *name){
|
|||
tlv[numTags].maxLen=maxLen;
|
||||
tlv[numTags].name=name;
|
||||
tlv[numTags].len=-1;
|
||||
tlv[numTags].val=(uint8_t *)malloc(maxLen);
|
||||
tlv[numTags].val=(uint8_t *)HS_MALLOC(maxLen);
|
||||
numTags++;
|
||||
|
||||
return(1);
|
||||
|
|
|
|||
10
src/Utils.h
10
src/Utils.h
|
|
@ -30,6 +30,14 @@
|
|||
#include <Arduino.h>
|
||||
#include <driver/timer.h>
|
||||
|
||||
#if defined(BOARD_HAS_PSRAM)
|
||||
#define HS_MALLOC ps_malloc
|
||||
#define HS_CALLOC ps_calloc
|
||||
#else
|
||||
#define HS_MALLOC malloc
|
||||
#define HS_CALLOC calloc
|
||||
#endif
|
||||
|
||||
namespace Utils {
|
||||
|
||||
char *readSerial(char *c, int max); // read serial port into 'c' until <newline>, but storing only first 'max' characters (the rest are discarded)
|
||||
|
|
@ -54,7 +62,7 @@ class TempBuffer {
|
|||
|
||||
TempBuffer(int _nElements) : nElements(_nElements) {
|
||||
nBytes=nElements*sizeof(bufType);
|
||||
buf=(bufType *)malloc(nBytes);
|
||||
buf=(bufType *)HS_MALLOC(nBytes);
|
||||
if(buf==NULL){
|
||||
Serial.print("\n\n*** FATAL ERROR: Requested allocation of ");
|
||||
Serial.print(nBytes);
|
||||
|
|
|
|||
98
src/src.ino
98
src/src.ino
|
|
@ -25,101 +25,39 @@
|
|||
*
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
#include "HomeSpan.h"
|
||||
|
||||
struct LED_Service : Service::LightBulb {
|
||||
|
||||
int ledPin;
|
||||
SpanCharacteristic *power;
|
||||
|
||||
LED_Service(int ledPin) : Service::LightBulb(){
|
||||
power=new Characteristic::On();
|
||||
this->ledPin=ledPin;
|
||||
pinMode(ledPin,OUTPUT);
|
||||
}
|
||||
|
||||
boolean update(){
|
||||
digitalWrite(ledPin,power->getNewVal());
|
||||
WEBLOG("Power = %s",power->getNewVal()?"ON":"OFF");
|
||||
return(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void extraData(String &r){
|
||||
r+="<tr><td>Free DRAM:</td><td>" + String(esp_get_free_internal_heap_size()) + " bytes</td></tr>\n";
|
||||
r+="</table><p><a href=\"https://github.com/HomeSpan/HomeSpan\">Click Here to Access HomeSpan Repo</a><p>";
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// homeSpan.setHostNameSuffix("");
|
||||
homeSpan.setLogLevel(2);
|
||||
|
||||
// homeSpan.setControlPin(21);
|
||||
homeSpan.begin(Category::Lighting,"HomeSpan Max");
|
||||
|
||||
homeSpan.setLogLevel(2).enableWebLog(500).setWebLogCallback(extraData);
|
||||
// homeSpan.reserveSocketConnections(10);
|
||||
new(HS_MALLOC(sizeof(SpanAccessory))) SpanAccessory();
|
||||
new(HS_MALLOC(sizeof(SpanService))) Service::AccessoryInformation();
|
||||
new(HS_MALLOC(sizeof(SpanCharacteristic))) Characteristic::Identify();
|
||||
|
||||
// homeSpan.setApSSID("HS_Setup");
|
||||
// homeSpan.setApPassword("");
|
||||
|
||||
// .setStatusPin(13);
|
||||
// homeSpan.setSerialInputDisable(true);
|
||||
// homeSpan.enableOTA();
|
||||
|
||||
homeSpan.setWifiCallback(wifiCB);
|
||||
homeSpan.setWifiCallbackAll(wifiCB_ALL).setVerboseWifiReconnect(true);
|
||||
homeSpan.setRebootCallback( [](uint8_t c) {if(c==3) homeSpan.processSerialCommand("X");} );
|
||||
|
||||
|
||||
new SpanUserCommand('D', " - disconnect WiFi", [](const char *buf){WiFi.disconnect();});
|
||||
|
||||
homeSpan.begin(Category::Lighting,"HomeSpan LED");
|
||||
|
||||
new SpanAccessory();
|
||||
new Service::AccessoryInformation();
|
||||
new Characteristic::Identify();
|
||||
new LED_Service(13);
|
||||
|
||||
// homeSpan.autoPoll();
|
||||
|
||||
// for(int i=0;i<300;i++)
|
||||
// WEBLOG("Here is some text of a log file %d",i);
|
||||
for(int i=0;i<80;i++){
|
||||
new(HS_MALLOC(sizeof(SpanAccessory))) SpanAccessory();
|
||||
new(HS_MALLOC(sizeof(SpanService))) Service::AccessoryInformation();
|
||||
new(HS_MALLOC(sizeof(SpanCharacteristic))) Characteristic::Identify();
|
||||
char c[30];
|
||||
sprintf(c,"Light-%d",i);
|
||||
new(HS_MALLOC(sizeof(SpanCharacteristic))) Characteristic::Name(c);
|
||||
new(HS_MALLOC(sizeof(SpanService))) Service::LightBulb();
|
||||
new(HS_MALLOC(sizeof(SpanCharacteristic))) Characteristic::On();
|
||||
new(HS_MALLOC(sizeof(SpanCharacteristic))) Characteristic::Brightness();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void loop(){
|
||||
|
||||
homeSpan.poll();
|
||||
//delay(10000);
|
||||
//Serial.println(millis());
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void wifiCB(){
|
||||
Serial.printf("\n\n****** IN WIFI CALLBACK *******\n\n");
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void wifiCB_ALL(int n){
|
||||
Serial.printf("\n\n****** IN WIFI CALLBACK ALL. Count=%d *******\n\n",n);
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void rebootCB(uint8_t count){
|
||||
if(count>=3){
|
||||
Serial.printf("\n*** Detected 3 or more short reboots. Erasing WiFi data...\n");
|
||||
homeSpan.processSerialCommand("X");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue