From 36499f35aba6de42cd608f3ae95174e5b3748fc3 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 26 Jun 2021 18:35:28 -0500 Subject: [PATCH 01/54] Added ESP32 chip type, revision, memory, etc. to initial output --- src/HomeSpan.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 4c4480d..2ce3689 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -99,6 +99,8 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(HOMESPAN_VERSION); Serial.print("\nESP-IDF Version: "); Serial.print(esp_get_idf_version()); + Serial.printf("\nESP32 Chip: %s Rev %d %s-core %dMB Flash", ESP.getChipModel(),ESP.getChipRevision(), + ESP.getChipCores()==1?"single":"dual",ESP.getFlashChipSize()/1024/1024); #ifdef ARDUINO_VARIANT Serial.print("\nESP32 Board: "); From 2e9539a1153a152832d7ec87e15d6129f1ee473b Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 15 Aug 2021 07:09:30 -0500 Subject: [PATCH 02/54] Fixed "space" bug in AP code Fixed bug in which Access Point was not properly translating a '+' sign to a space when processing HTML forms. --- src/Network.cpp | 3 ++- src/src.ino | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Network.cpp b/src/Network.cpp index 5d33383..7de6045 100644 --- a/src/Network.cpp +++ b/src/Network.cpp @@ -403,7 +403,8 @@ int Network::getFormValue(char *formData, const char *tag, char *value, int maxS sscanf(v,"%2x",(unsigned int *)value++); v+=2; } else { - *value++=*v++; + *value++=(*v=='+'?' ':*v); // HTML Forms use '+' for spaces (and '+' signs are escaped) + v++; } len++; } diff --git a/src/src.ino b/src/src.ino index 60385c0..485e18d 100644 --- a/src/src.ino +++ b/src/src.ino @@ -22,7 +22,7 @@ void setup() { new SpanUserCommand('e',"- My second Description",userCom2); homeSpan.enableAutoStartAP(); - homeSpan.setApFunction(myWiFiAP); +// homeSpan.setApFunction(myWiFiAP); homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); From 6a74ce92838be3491c77d4ded6386f6b5c130d08 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 5 Sep 2021 08:54:34 -0500 Subject: [PATCH 03/54] Add setValidValues(int n, ...) method to Characteristic Allows user to explicitly set the valid values for a Characteristic of type UINT8. Throws an error if used with any other Characteristic type. --- src/HomeSpan.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/HomeSpan.h | 4 +++- src/Span.h | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 2ce3689..47f3567 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1600,6 +1600,10 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){ if(uvGet(stepValue)>0) nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minStep\":%s",uvPrint(stepValue).c_str()); } + + if(validValues){ + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"valid-values\":%s",validValues); + } } if(desc && (flags&GET_DESC)){ @@ -1720,6 +1724,40 @@ unsigned long SpanCharacteristic::timeVal(){ return(homeSpan.snapTime-updateTime); } +/////////////////////////////// + +void SpanCharacteristic::setValidValues(int n, ...){ + char c[256]; + String *s = new String("["); + va_list vl; + va_start(vl,n); + for(int i=0;ic_str(); + sprintf(c,": ValidValues=%s\n",validValues); + } + + homeSpan.configLog+=c; +} + /////////////////////////////// // SpanRange // /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index d1e5b14..f61d911 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -256,8 +256,9 @@ struct SpanCharacteristic{ UVal minValue; // Characteristic minimum (not applicable for STRING) UVal maxValue; // Characteristic maximum (not applicable for STRING) UVal stepValue; // Characteristic step size (not applicable for STRING) - boolean staticRange; // Flag that indiates whether Range is static and cannot be changed with setRange() + boolean staticRange; // Flag that indicates whether Range is static and cannot be changed with setRange() boolean customRange=false; // Flag for custom ranges + const char *validValues=NULL; // Optional JSON array of valid values. Applicable only to uint8 Characteristics boolean *ev; // Characteristic Event Notify Enable (per-connection) char *nvsKey=NULL; // key for NVS storage of Characteristic value @@ -274,6 +275,7 @@ struct SpanCharacteristic{ boolean updated(){return(isUpdated);} // returns isUpdated unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated + void setValidValues(int n, ...); // sets a list of 'n' valid values allowed for a Characteristic. Only applicable if format=uint8 String uvPrint(UVal &u){ char c[64]; diff --git a/src/Span.h b/src/Span.h index 64695af..be8b4aa 100644 --- a/src/Span.h +++ b/src/Span.h @@ -381,7 +381,7 @@ namespace Service { // SPAN CHARACTERISTICS (HAP Chapter 9) // ////////////////////////////////////////// -// Macro to define Span Characteristic structures based on name of HAP Characteristic, default value, and mix/max value (not applicable for STRING or BOOL which default to min=0, max=1) +// Macro to define Span Characteristic structures based on name of HAP Characteristic, default value, and min/max value (not applicable for STRING or BOOL which default to min=0, max=1) #define CREATE_CHAR(TYPE,HAPCHAR,DEFVAL,MINVAL,MAXVAL) \ struct HAPCHAR : SpanCharacteristic { HAPCHAR(TYPE val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val,nvsStore,(TYPE)MINVAL,(TYPE)MAXVAL); } }; From 946819f3d4b5d127c4ef23d457ed835155277b1d Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 5 Sep 2021 09:14:21 -0500 Subject: [PATCH 04/54] updated setValidValues() to return pointer to self Allows for chaining methods. --- src/HomeSpan.cpp | 3 ++- src/HomeSpan.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 47f3567..0f5c25b 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1726,7 +1726,7 @@ unsigned long SpanCharacteristic::timeVal(){ /////////////////////////////// -void SpanCharacteristic::setValidValues(int n, ...){ +SpanCharacteristic *SpanCharacteristic::setValidValues(int n, ...){ char c[256]; String *s = new String("["); va_list vl; @@ -1756,6 +1756,7 @@ void SpanCharacteristic::setValidValues(int n, ...){ } homeSpan.configLog+=c; + return(this); } /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index f61d911..7f72fb3 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -275,7 +275,8 @@ struct SpanCharacteristic{ boolean updated(){return(isUpdated);} // returns isUpdated unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated - void setValidValues(int n, ...); // sets a list of 'n' valid values allowed for a Characteristic. Only applicable if format=uint8 + + SpanCharacteristic *setValidValues(int n, ...); // sets a list of 'n' valid values allowed for a Characteristic and returns pointer to self. Only applicable if format=uint8 String uvPrint(UVal &u){ char c[64]; From 3d6bc0d095503674b4d07dbec7990c3a3f46ae57 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 5 Sep 2021 09:29:08 -0500 Subject: [PATCH 05/54] Update Reference.md --- docs/Reference.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/Reference.md b/docs/Reference.md index 51e6742..0c85f02 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -217,6 +217,14 @@ The following methods are supported: * returns a pointer to the Characteristic itself so that the method can be chained during instantiation * example: `(new Characteristic::Brightness(50))->setRange(10,100,5);` +* `SpanCharacteristic *setValidValues(int n, [int v1, int v2 ...])` + * overrides the default HAP Valid Values for Characteristics that have specific enumerated Valid Values with a variable-length list of *n* values *v1*, *v2*, etc. + * an error is thrown if: + * called on a Characteristic that does not have specific enumerated Valid Values, or + * called more than once on the same Characteristic + * returns a pointer to the Characteristic itself so that the method can be chained during instantiation + * example: `(new Characteristic::SecuritySystemTargetState())->setValidValues(3,0,1,3);` creates a new valid value list of length=3 containing the values 0, 1, and 3. This has the effect of informing the HomeKit that a SecuritySystemTargetState value of 2 (Night Arm) is not valid and should not be shown as a choice in the Home App + ## *SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime)* Creating an instance of this **class** attaches a pushbutton handler to the ESP32 *pin* specified. From 70ebb290da485ca87dccede6fadd280648ac4f9d Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 5 Sep 2021 09:30:00 -0500 Subject: [PATCH 06/54] Update Reference.md --- docs/Reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index 0c85f02..b41a93b 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -223,7 +223,7 @@ The following methods are supported: * called on a Characteristic that does not have specific enumerated Valid Values, or * called more than once on the same Characteristic * returns a pointer to the Characteristic itself so that the method can be chained during instantiation - * example: `(new Characteristic::SecuritySystemTargetState())->setValidValues(3,0,1,3);` creates a new valid value list of length=3 containing the values 0, 1, and 3. This has the effect of informing the HomeKit that a SecuritySystemTargetState value of 2 (Night Arm) is not valid and should not be shown as a choice in the Home App + * example: `(new Characteristic::SecuritySystemTargetState())->setValidValues(3,0,1,3);` creates a new valid value list of length=3 containing the values 0, 1, and 3. This has the effect of informing HomeKit that a SecuritySystemTargetState value of 2 (Night Arm) is not valid and should not be shown as a choice in the Home App ## *SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime)* From 28356c327a79a497d045a4c1eead369cf622080f Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 5 Sep 2021 09:31:19 -0500 Subject: [PATCH 07/54] Update Reference.md --- docs/Reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index b41a93b..cdf2d0a 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -223,7 +223,7 @@ The following methods are supported: * called on a Characteristic that does not have specific enumerated Valid Values, or * called more than once on the same Characteristic * returns a pointer to the Characteristic itself so that the method can be chained during instantiation - * example: `(new Characteristic::SecuritySystemTargetState())->setValidValues(3,0,1,3);` creates a new valid value list of length=3 containing the values 0, 1, and 3. This has the effect of informing HomeKit that a SecuritySystemTargetState value of 2 (Night Arm) is not valid and should not be shown as a choice in the Home App + * example: `(new Characteristic::SecuritySystemTargetState())->setValidValues(3,0,1,3);` creates a new Valid Value list of length=3 containing the values 0, 1, and 3. This has the effect of informing HomeKit that a SecuritySystemTargetState value of 2 (Night Arm) is not valid and should not be shown as a choice in the Home App ## *SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime)* From edf5522ca0eefd435a51fa7e802f92ad2664fc94 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 5 Sep 2021 20:39:37 -0500 Subject: [PATCH 08/54] Addresses compiler warnings in Arduino-ESP32 2.0.0 --- src/HAP.cpp | 2 +- src/HomeSpan.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 6f1f2c1..822f84e 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -719,7 +719,7 @@ int HAPClient::postPairVerifyURL(){ memcpy(iosCurveKey,tlv8.buf(kTLVType_PublicKey),32); // save iosCurveKey (will persist until end of verification process) - crypto_scalarmult_curve25519(sharedCurveKey,secretCurveKey,iosCurveKey); // generate (and persist) Pair Verify SharedSecret CurveKey from Accessory's Curve25519 secret key and Controller's Curve25519 public key (32 bytes) + int _x = crypto_scalarmult_curve25519(sharedCurveKey,secretCurveKey,iosCurveKey); // generate (and persist) Pair Verify SharedSecret CurveKey from Accessory's Curve25519 secret key and Controller's Curve25519 public key (32 bytes) uint8_t *accessoryPairingID = accessory.ID; // set accessoryPairingID size_t accessoryPairingIDLen = 17; diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 7f72fb3..1c707d0 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -33,6 +33,7 @@ #include #include +#include #include #include "Settings.h" @@ -301,7 +302,8 @@ struct SpanCharacteristic{ sprintf(c,"\"%s\"",u.STRING); return(String(c)); } // switch - } // str() + return(String()); // included to prevent compiler warnings + } void uvSet(UVal &u, const char *val){ u.STRING=val; @@ -331,7 +333,7 @@ struct SpanCharacteristic{ u.FLOAT=(double)val; break; } // switch - } // set() + } template T uvGet(UVal &u){ @@ -354,7 +356,8 @@ struct SpanCharacteristic{ Serial.print("\n*** WARNING: Can't use getVal() or getNewVal() with string Characteristics.\n\n"); return(0); } - } // get() + return(0); // included to prevent compiler warnings + } template SpanCharacteristic *setRange(A min, B max, S step=0){ From 6088fb16fece19ecd09c6a15a132685838c8b6dd Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 6 Sep 2021 12:35:26 -0500 Subject: [PATCH 09/54] Added logic to Timer code to allow for compiling under S2 and C3 With these changes the code compiles but nothing has been tested yet to see if it actually works under S2 and C3! --- src/Utils.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 0bf1578..59a1da2 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -229,8 +229,13 @@ void Blinker::init(int pin, int timerNum){ pinMode(pin,OUTPUT); digitalWrite(pin,0); +#if SOC_TIMER_GROUP_TIMERS_PER_GROUP>1 // ESP32 and ESP32-S2 contains two timers per timer group group=((timerNum/2)%2==0)?TIMER_GROUP_0:TIMER_GROUP_1; - idx=(timerNum%2==0)?TIMER_0:TIMER_1; + idx=(timerNum%2==0)?TIMER_0:TIMER_1; // ESP32-C3 only contains one timer per timer group +#else + group=(timerNum%2==0)?TIMER_GROUP_0:TIMER_GROUP_1; + idx=TIMER_0; +#endif timer_config_t conf; conf.alarm_en=TIMER_ALARM_EN; @@ -251,7 +256,8 @@ void Blinker::init(int pin, int timerNum){ void Blinker::isrTimer(void *arg){ Blinker *b=(Blinker *)arg; - + +#if CONFIG_IDF_TARGET_ESP32 if(b->group){ if(b->idx) TIMERG1.int_clr_timers.t1=1; @@ -263,6 +269,25 @@ void Blinker::isrTimer(void *arg){ else TIMERG0.int_clr_timers.t0=1; } +#elif CONFIG_IDF_TARGET_ESP32S2 // for some reason, the ESP32-S2 and ESP32-C3 use "int_clr" instead of "int_clr_timers" in their timer structure + if(b->group){ + if(b->idx) + TIMERG1.int_clr.t1=1; + else + TIMERG1.int_clr.t0=1; + } else { + if(b->idx) + TIMERG0.int_clr.t1=1; + else + TIMERG0.int_clr.t0=1; + } +#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 only has one timer per timer group + if(b->group){ + TIMERG1.int_clr.t0=1; + } else { + TIMERG0.int_clr.t0=1; + } +#endif if(!digitalRead(b->pin)){ digitalWrite(b->pin,1); From 8d45e2067185b993de3d9b214e27f6ffe26d7179 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 6 Sep 2021 21:29:13 -0500 Subject: [PATCH 10/54] Update Utils.h --- src/Utils.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Utils.h b/src/Utils.h index a16d53d..c90a78d 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -184,14 +184,18 @@ class Blinker { // the specified pin, obviating the need for a separate call to init(). // // pin: Pin mumber to control. Blinker will set pinMode to OUTPUT automatically -// timerNum: ESP32 Alarm Timer to use. 0=Group0/Timer0, 1=Group0/Timer1, 2=Group1/Timer0, 3=Group1/Timer1 +// timerNum: ESP32 Alarm Timer to use. +// For ESP32 and ESP32-S2: 0=Group0/Timer0, 1=Group0/Timer1, 2=Group1/Timer0, 3=Group1/Timer1 +// For ESP32-C3: 0=Group0/Timer0, 1=Group1/Timer0 void init(int pin, int timerNum=0); // Initializes Blinker, if not configured during instantiation. // // pin: Pin mumber to control. Blinker will set pinMode to OUTPUT automatically -// timerNum: ESP32 Alarm Timer to use. 0=Group0/Timer0, 1=Group0/Timer1, 2=Group1/Timer0, 3=Group1/Timer1 +// timerNum: ESP32 Alarm Timer to use. +// For ESP32 and ESP32-S2: 0=Group0/Timer0, 1=Group0/Timer1, 2=Group1/Timer0, 3=Group1/Timer1 +// For ESP32-C3: 0=Group0/Timer0, 1=Group1/Timer0 void start(int period, float dutyCycle=0.5); From a5d31b1ea53190c8db775ae6426fb8797d53f28d Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 12 Sep 2021 09:23:29 -0500 Subject: [PATCH 11/54] Re-working PWM routines --- .DS_Store | Bin 0 -> 6148 bytes src/.DS_Store | Bin 0 -> 6148 bytes src/extras/PwmPin.cpp | 103 ++++++++++++++++++++++++++---------------- src/extras/PwmPin.h | 28 +++++++++--- src/extras/extras.ino | 71 ++++++++++++----------------- 5 files changed, 113 insertions(+), 89 deletions(-) create mode 100644 .DS_Store create mode 100644 src/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9a874b5768f336915163bb88cd434575b859f936 GIT binary patch literal 6148 zcmeH~Jr2S!425ml0g0s}V-^m;4I%_5-~tF3k&vj^b9A16778<}(6eNJu~Vz<8=6`~ zboab&MFtUB!i}=AFfm2m$tVxGT*u4pe81nUlA49C} z?O@64YO)2RT{MRe%{!}2F))pG(Sih~)xkgosK7*lF7m<7{{#Hn{6A@7N(HFEpDCdI z{A>JE0C0h@8|L0i z0E-2HHE{|=1g1d+2351g(4Zq;GOs31fk79|=0o#l%??HVcAQ^4U9<*rqykjnT!H6U zuB`sQ!LRiH=OnJE02O#B1$5E9cP*ZjwRQG5tF;CG0k@nJ+zfN4VDNGb^m2@amE%`W bio9ZT?AOF8(CLUf9mt;n(}hL_?ybNt5oZ;o literal 0 HcmV?d00001 diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index 1f85bbe..c9c377e 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -3,56 +3,75 @@ /////////////////// -LedPin::LedPin(uint8_t pin, uint8_t level){ - if(numChannels+ServoPin::numChannels>15){ - Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels ***\n\n",pin); - ledChannel.gpio_num=0; - return; +LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq){ + + if(freq==0) + freq=DEFAULT_PWM_FREQ; + + for(int nMode=0;nModespeed_mode=(ledc_mode_t)nMode; + timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; + timerList[nTimer][nMode]->freq_hz=freq; + + int res=20; // find the maximum possible resolution + while(getApbFrequency()/(freq*pow(2,res))<1) + res--; + + timerList[nTimer][nMode]->duty_resolution=(ledc_timer_bit_t)res; + ledc_timer_config(timerList[nTimer][nMode]); + } + + if(timerList[nTimer][nMode]->freq_hz==freq){ // if timer matches desired frequency (always true if newly-created above) + channelList[nChannel][nMode]=new ledc_channel_config_t; // create new channel instance + channelList[nChannel][nMode]->speed_mode=(ledc_mode_t)nMode; + channelList[nChannel][nMode]->channel=(ledc_channel_t)nChannel; + channelList[nChannel][nMode]->timer_sel=(ledc_timer_t)nTimer; + channelList[nChannel][nMode]->intr_type=LEDC_INTR_DISABLE; + channelList[nChannel][nMode]->hpoint=0; + channelList[nChannel][nMode]->gpio_num=pin; + ledTimer=timerList[nTimer][nMode]; + ledChannel=channelList[nChannel][nMode]; + set(level); + return; + } + + } + } + } } - enabled=true; - - if(numChannels==0){ // first instantiation of an LedPin - ledc_timer_config_t ledTimer; - ledTimer.timer_num=LEDC_TIMER_0; - ledTimer.duty_resolution=LEDC_TIMER_10_BIT; - ledTimer.freq_hz=5000; + Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); - ledTimer.speed_mode=LEDC_HIGH_SPEED_MODE; // configure both the HIGH-Speed Timer 0 and Low-Speed Timer 0 - ledc_timer_config(&ledTimer); - - ledTimer.speed_mode=LEDC_LOW_SPEED_MODE; - ledc_timer_config(&ledTimer); - } - - ledChannel.gpio_num=pin; - if(numChannels<8){ - ledChannel.speed_mode=LEDC_LOW_SPEED_MODE; - ledChannel.channel=(ledc_channel_t)(7-numChannels); - } else { - ledChannel.speed_mode=LEDC_HIGH_SPEED_MODE; - ledChannel.channel=(ledc_channel_t)(15-numChannels); - } - - numChannels++; - - ledChannel.intr_type=LEDC_INTR_DISABLE; - ledChannel.timer_sel=LEDC_TIMER_0; - ledChannel.hpoint=0; - ledc_channel_config(&ledChannel); - set(level); } /////////////////// void LedPin::set(uint8_t level){ - if(!enabled) + + if(!ledChannel) return; + + Serial.printf("pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", + ledChannel->gpio_num, + ledChannel->channel, + ledChannel->speed_mode, + ledChannel->timer_sel, + ledTimer->freq_hz, + ledTimer->duty_resolution + ); + + if(level>100) + level=100; - ledChannel.duty=level*1023; - ledChannel.duty/=100; - ledChannel.duty&=0x03FF; - ledc_channel_config(&ledChannel); + ledChannel->duty=level*(pow(2,ledTimer->duty_resolution)-1); + ledChannel->duty/=100; + ledc_channel_config(ledChannel); } @@ -170,6 +189,10 @@ void ServoPin::set(double degrees){ const double ServoPin::micros2duty=65535.0/20000.0; uint8_t LedPin::numChannels=0; uint8_t ServoPin::numChannels=0; +uint8_t LedC::nChannels=0; +vector LedC::timers; +ledc_channel_config_t *LedC::channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]={}; +ledc_timer_config_t *LedC::timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]={}; //******************************************************* // DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index 76b79fb..5281f1c 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -22,17 +22,33 @@ #include #include +#include + +using std::vector; + +#define DEFAULT_PWM_FREQ 5000 ///////////////////////////////////// -class LedPin { - boolean enabled=false; - ledc_channel_config_t ledChannel; +class LedC { + + protected: + static uint8_t nChannels; + static vector timers; + static ledc_channel_config_t *channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]; + static ledc_timer_config_t *timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]; +}; + +///////////////////////////////////// + +class LedPin : LedC { + ledc_channel_config_t *ledChannel=NULL; + ledc_timer_config_t *ledTimer; public: - LedPin(uint8_t pin, uint8_t level=0); // assigns pin to be output of one of 16 PWM channels within initial level - void set(uint8_t level); // sets the PWM duty to level (0-100) - int getPin(){return ledChannel.gpio_num;} // returns the pin number + LedPin(uint8_t pin, uint8_t level=0, uint16_t freq=DEFAULT_PWM_FREQ); // assigns pin to be output of one of 16 PWM channels initial level and frequency + void set(uint8_t level); // sets the PWM duty to level (0-100) + int getPin(){return(ledChannel?ledChannel->gpio_num:-1);} // returns the pin number static uint8_t numChannels; static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 1bdb34a..e98d842 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -3,7 +3,8 @@ // as well as compile and test from this point. This file is ignored when the library is included in other sketches. #include "PwmPin.h" - +#include + void setup(){ Serial.begin(115200); @@ -13,53 +14,37 @@ void setup(){ Serial.println("Starting..."); + LedPin led0(18,100,0); + LedPin led1(19,100,2000); + LedPin led2(16,10,80000); + LedPin led3(17,100,2000); + LedPin led4(23); + LedPin led5(22,0,3000); + LedPin led6(14,0,1); + LedPin led7(32,0,1850); + LedPin led8(15); + LedPin led9(33); + LedPin led10(27); + LedPin led11(12,100,23); + LedPin led12(13,100); + LedPin led13(26); + LedPin led14(25,0); + LedPin led15(4,0); + LedPin led16(5,0); - LedPin yellow(16,10); - LedPin d1(19); - LedPin d2(19); - LedPin d3(19); - LedPin d4(19); - LedPin d5(19); - LedPin d6(19); - LedPin d7(19); - LedPin d8(19); - LedPin d9(19); - LedPin d10(19); - LedPin d11(19); - LedPin d12(19); - LedPin red(17); + led16.set(20); + led0.set(5); + led2.set(100); -// ServoPin servo(18,0,500,2200,-90,90); - ServoPin s0(19); - ServoPin servo(18,45); - ServoPin s1(19); + uint32_t v=REG_READ(LEDC_HSTIMER0_CONF_REG); + Serial.printf("HS %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF); + + v=REG_READ(LEDC_LSTIMER0_CONF_REG); + Serial.printf("LS %d %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF,REG_READ(LEDC_CONF_REG)); - while(1){ - for(int i=0;i<100;i++){ - yellow.set(i); - delay(10); - } - for(int i=100;i>=0;i--){ - red.set(i); - delay(10); - } - } - - while(1){ - double STEP=1; - - for(int i=-100*STEP;i<=100*STEP;i++){ - servo.set((double)i/STEP); - delay(10); - } - - for(int i=100*STEP;i>=-100*STEP;i--){ - servo.set((double)i/STEP); - delay(10); - } - } + while(1); } void loop(){ From 0a0c536b6d75e9ad5d4eca5e52be3af470637ed7 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 12 Sep 2021 12:31:08 -0500 Subject: [PATCH 12/54] Starting work on ServoPin update --- src/extras/PwmPin.cpp | 103 +++++++++++++++++++++++------------------- src/extras/PwmPin.h | 19 ++++---- src/extras/extras.ino | 5 ++ 3 files changed, 72 insertions(+), 55 deletions(-) diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index c9c377e..fc6daa7 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -3,7 +3,7 @@ /////////////////// -LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq){ +LedC::LedC(uint8_t pin, uint16_t freq){ if(freq==0) freq=DEFAULT_PWM_FREQ; @@ -35,43 +35,49 @@ LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq){ channelList[nChannel][nMode]->intr_type=LEDC_INTR_DISABLE; channelList[nChannel][nMode]->hpoint=0; channelList[nChannel][nMode]->gpio_num=pin; - ledTimer=timerList[nTimer][nMode]; - ledChannel=channelList[nChannel][nMode]; - set(level); + timer=timerList[nTimer][nMode]; + channel=channelList[nChannel][nMode]; return; - } - + } } } } } +} - Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); - +/////////////////// + +LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq) : LedC(pin, freq){ + + if(!channel) + Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); + + set(level); + } /////////////////// void LedPin::set(uint8_t level){ - if(!ledChannel) + if(!channel) return; Serial.printf("pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", - ledChannel->gpio_num, - ledChannel->channel, - ledChannel->speed_mode, - ledChannel->timer_sel, - ledTimer->freq_hz, - ledTimer->duty_resolution + channel->gpio_num, + channel->channel, + channel->speed_mode, + channel->timer_sel, + timer->freq_hz, + timer->duty_resolution ); if(level>100) level=100; - ledChannel->duty=level*(pow(2,ledTimer->duty_resolution)-1); - ledChannel->duty/=100; - ledc_channel_config(ledChannel); + channel->duty=level*(pow(2,timer->duty_resolution)-1); + channel->duty/=100; + ledc_channel_config(channel); } @@ -134,37 +140,42 @@ void LedPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ //////////////////////////// -ServoPin::ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees){ - if(numChannels>7 || numChannels>(15-LedPin::numChannels)){ - Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels ***\n\n",pin); - servoChannel.gpio_num=0; - return; - } - - enabled=true; +ServoPin::ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees) : LedC(pin, 50){ +// if(numChannels>7 || numChannels>(15-numChannels)){ +// Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels ***\n\n",pin); +// servoChannel.gpio_num=0; +// return; +// } +// +// enabled=true; + if(!channel) + Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); + + set(initDegrees); + this->minMicros=minMicros; this->maxMicros=maxMicros; this->minDegrees=minDegrees; microsPerDegree=(double)(maxMicros-minMicros)/(maxDegrees-minDegrees); - - if(numChannels==0){ // first instantiation of a ServoPin - ledc_timer_config_t ledTimer; - ledTimer.timer_num=LEDC_TIMER_1; - ledTimer.speed_mode=LEDC_HIGH_SPEED_MODE; - ledTimer.duty_resolution=LEDC_TIMER_16_BIT; - ledTimer.freq_hz=50; - ledc_timer_config(&ledTimer); - } - - servoChannel.gpio_num=pin; - servoChannel.speed_mode=LEDC_HIGH_SPEED_MODE; - servoChannel.channel=(ledc_channel_t)numChannels++; - servoChannel.intr_type=LEDC_INTR_DISABLE; - servoChannel.timer_sel=LEDC_TIMER_1; - servoChannel.hpoint=0; - servoChannel.duty*=micros2duty; - set(initDegrees); + +// if(numChannels==0){ // first instantiation of a ServoPin +// ledc_timer_config_t ledTimer; +// ledTimer.timer_num=LEDC_TIMER_1; +// ledTimer.speed_mode=LEDC_HIGH_SPEED_MODE; +// ledTimer.duty_resolution=LEDC_TIMER_16_BIT; +// ledTimer.freq_hz=50; +// ledc_timer_config(&ledTimer); +// } +// +// servoChannel.gpio_num=pin; +// servoChannel.speed_mode=LEDC_HIGH_SPEED_MODE; +// servoChannel.channel=(ledc_channel_t)numChannels++; +// servoChannel.intr_type=LEDC_INTR_DISABLE; +// servoChannel.timer_sel=LEDC_TIMER_1; +// servoChannel.hpoint=0; +// servoChannel.duty*=micros2duty; +// set(initDegrees); } /////////////////// @@ -187,10 +198,8 @@ void ServoPin::set(double degrees){ //////////////////////////// const double ServoPin::micros2duty=65535.0/20000.0; -uint8_t LedPin::numChannels=0; +//uint8_t LedPin::numChannels=0; uint8_t ServoPin::numChannels=0; -uint8_t LedC::nChannels=0; -vector LedC::timers; ledc_channel_config_t *LedC::channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]={}; ledc_timer_config_t *LedC::timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]={}; diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index 5281f1c..923a7de 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -33,30 +33,33 @@ using std::vector; class LedC { protected: - static uint8_t nChannels; - static vector timers; static ledc_channel_config_t *channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]; static ledc_timer_config_t *timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]; + + ledc_channel_config_t *channel=NULL; + ledc_timer_config_t *timer; + + LedC(uint8_t pin, uint16_t freq); + + public: + int getPin(){return(channel?channel->gpio_num:-1);} // returns the pin number + }; ///////////////////////////////////// -class LedPin : LedC { - ledc_channel_config_t *ledChannel=NULL; - ledc_timer_config_t *ledTimer; +class LedPin : public LedC { public: LedPin(uint8_t pin, uint8_t level=0, uint16_t freq=DEFAULT_PWM_FREQ); // assigns pin to be output of one of 16 PWM channels initial level and frequency void set(uint8_t level); // sets the PWM duty to level (0-100) - int getPin(){return(ledChannel?ledChannel->gpio_num:-1);} // returns the pin number - static uint8_t numChannels; static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B }; ///////////////////////////////////// -class ServoPin { +class ServoPin : public LedC { boolean enabled=false; uint16_t minMicros; uint16_t maxMicros; diff --git a/src/extras/extras.ino b/src/extras/extras.ino index e98d842..639d8b4 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -36,6 +36,11 @@ void setup(){ led0.set(5); led2.set(100); + Serial.println(led0.getPin()); + Serial.println(led14.getPin()); + Serial.println(led15.getPin()); + Serial.println(led16.getPin()); + uint32_t v=REG_READ(LEDC_HSTIMER0_CONF_REG); Serial.printf("HS %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF); From 60cb20f13269248f3094929c8cec60ecc112079a Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 12 Sep 2021 15:17:27 -0500 Subject: [PATCH 13/54] Completed update to PWM code Should now work with ESP32-S2 and C3. Allows for as many LEDs and Servos as there are channels and timers across low and high (esp32 only) modes. Allows LED to be set with floating point precession instead of just uint8. Allows specification of LED frequency for each LED (1-65535 Hz). Automatically provides maximum duty resolution for frequency chosen. --- src/extras/PwmPin.cpp | 73 ++++++++++++++++++------------------------- src/extras/PwmPin.h | 9 +----- src/extras/extras.ino | 4 +-- 3 files changed, 33 insertions(+), 53 deletions(-) diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index fc6daa7..034c92a 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -58,12 +58,12 @@ LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq) : LedC(pin, freq){ /////////////////// -void LedPin::set(uint8_t level){ +void LedPin::set(float level){ if(!channel) return; - Serial.printf("pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", + Serial.printf("LED pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", channel->gpio_num, channel->channel, channel->speed_mode, @@ -141,68 +141,55 @@ void LedPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ //////////////////////////// ServoPin::ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees) : LedC(pin, 50){ -// if(numChannels>7 || numChannels>(15-numChannels)){ -// Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels ***\n\n",pin); -// servoChannel.gpio_num=0; -// return; -// } -// -// enabled=true; if(!channel) - Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); + Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); - set(initDegrees); - this->minMicros=minMicros; this->maxMicros=maxMicros; this->minDegrees=minDegrees; microsPerDegree=(double)(maxMicros-minMicros)/(maxDegrees-minDegrees); + + set(initDegrees); -// if(numChannels==0){ // first instantiation of a ServoPin -// ledc_timer_config_t ledTimer; -// ledTimer.timer_num=LEDC_TIMER_1; -// ledTimer.speed_mode=LEDC_HIGH_SPEED_MODE; -// ledTimer.duty_resolution=LEDC_TIMER_16_BIT; -// ledTimer.freq_hz=50; -// ledc_timer_config(&ledTimer); -// } -// -// servoChannel.gpio_num=pin; -// servoChannel.speed_mode=LEDC_HIGH_SPEED_MODE; -// servoChannel.channel=(ledc_channel_t)numChannels++; -// servoChannel.intr_type=LEDC_INTR_DISABLE; -// servoChannel.timer_sel=LEDC_TIMER_1; -// servoChannel.hpoint=0; -// servoChannel.duty*=micros2duty; -// set(initDegrees); } /////////////////// void ServoPin::set(double degrees){ - if(!enabled) - return; - - servoChannel.duty=(degrees-minDegrees)*microsPerDegree+minMicros; - - if(servoChannel.dutymaxMicros) - servoChannel.duty=maxMicros; - servoChannel.duty*=micros2duty; - ledc_channel_config(&servoChannel); + if(!channel) + return; + + Serial.printf("Servo pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", + channel->gpio_num, + channel->channel, + channel->speed_mode, + channel->timer_sel, + timer->freq_hz, + timer->duty_resolution + ); + + double usec=(degrees-minDegrees)*microsPerDegree+minMicros; + + if(usecmaxMicros) + usec=maxMicros; + + usec*=timer->freq_hz/1e6*(pow(2,timer->duty_resolution)-1); + + channel->duty=usec; + ledc_channel_config(channel); } //////////////////////////// -const double ServoPin::micros2duty=65535.0/20000.0; -//uint8_t LedPin::numChannels=0; -uint8_t ServoPin::numChannels=0; ledc_channel_config_t *LedC::channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]={}; ledc_timer_config_t *LedC::timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]={}; +//////////////////////////// + //******************************************************* // DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY //******************************************************* diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index 923a7de..28a280f 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -52,7 +52,7 @@ class LedPin : public LedC { public: LedPin(uint8_t pin, uint8_t level=0, uint16_t freq=DEFAULT_PWM_FREQ); // assigns pin to be output of one of 16 PWM channels initial level and frequency - void set(uint8_t level); // sets the PWM duty to level (0-100) + void set(float level); // sets the PWM duty to level (0-100) static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B }; @@ -60,23 +60,16 @@ class LedPin : public LedC { ///////////////////////////////////// class ServoPin : public LedC { - boolean enabled=false; uint16_t minMicros; uint16_t maxMicros; double minDegrees; double microsPerDegree; - ledc_channel_config_t servoChannel; - - static const double micros2duty; public: ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees); ServoPin(uint8_t pin, double initDegrees=0) : ServoPin(pin,initDegrees,1000,2000,-90,90) {}; void set(double degrees); // sets the Servo to degrees, where degrees is bounded by [minDegrees,maxDegrees] - int getPin(){return servoChannel.gpio_num;} // returns the pin number - - static uint8_t numChannels; }; //******************************************************* diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 639d8b4..e9839e0 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -25,16 +25,16 @@ void setup(){ LedPin led8(15); LedPin led9(33); LedPin led10(27); + ServoPin led14(25); LedPin led11(12,100,23); LedPin led12(13,100); LedPin led13(26); - LedPin led14(25,0); LedPin led15(4,0); LedPin led16(5,0); led16.set(20); led0.set(5); - led2.set(100); + led14.set(100); Serial.println(led0.getPin()); Serial.println(led14.getPin()); From 98a5a895cccdceeda7be892bed3ecd6796ef1d95 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 12 Sep 2021 16:19:10 -0500 Subject: [PATCH 14/54] Update PwmPin.cpp Tested new functionality on RGB LED. Works well with using floating point precision. --- src/extras/PwmPin.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index 034c92a..f1021e2 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -63,15 +63,6 @@ void LedPin::set(float level){ if(!channel) return; - Serial.printf("LED pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", - channel->gpio_num, - channel->channel, - channel->speed_mode, - channel->timer_sel, - timer->freq_hz, - timer->duty_resolution - ); - if(level>100) level=100; @@ -161,15 +152,6 @@ void ServoPin::set(double degrees){ if(!channel) return; - Serial.printf("Servo pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", - channel->gpio_num, - channel->channel, - channel->speed_mode, - channel->timer_sel, - timer->freq_hz, - timer->duty_resolution - ); - double usec=(degrees-minDegrees)*microsPerDegree+minMicros; if(usec Date: Mon, 13 Sep 2021 06:01:31 -0500 Subject: [PATCH 15/54] Update Extras.md --- docs/Extras.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/Extras.md b/docs/Extras.md index 2adb084..f9bbbc4 100644 --- a/docs/Extras.md +++ b/docs/Extras.md @@ -4,21 +4,27 @@ HomeSpan includes integrated access to a number of ESP32 features you'll likely ## Pulse Width Modulation (PWM) -The ESP32 has 16 PWM channels that can be used to drive a variety of devices. HomeSpan includes an integrated PWM library with dedicated classes designed for controlling **Dimmable LEDs** as well as **Servo Motors**. Both classes are provided in a standalone header file that is accessd by placing the following near the top of your sketch: +The ESP32 has up to 16 PWM channels that can be used to drive a variety of devices. HomeSpan includes an integrated PWM library with dedicated classes designed for controlling **Dimmable LEDs** as well as **Servo Motors**. Both classes are provided in a standalone header file that is accessed by placing the following near the top of your sketch: `#include "extras/PwmPin.h"` -### *LedPin(uint8_t pin)* +### *LedPin(uint8_t pin [,float level [,uint16_t frequency]])* -Creating an instance of this **class** configures the specified *pin* to output a 5000 Hz PWM signal, which is suitable for dimming LEDs. The following methods are supported: +Creating an instance of this **class** configures the specified *pin* to output a PWM signal suitable for a controlling dimmable LED. Arguments, along with their defaults if left unspecified, are as follows: -* `void set(uint8_t level)` + * *pin* - the pin on which the PWM control signal will be output + * *level* - sets the initial %duty-cycle of the PWM from from 0 (LED completely off) to 100 (LED fully on). Default=0 (LED initially off) + * *frequency* - sets the PWM frequency, in Hz, from 1-65535. Defaults to 5000 Hz if unspecified, or if set to 0 + + The following methods are supported: + +* `void set(float level)` * sets the PWM %duty-cycle to *level*, where *level* ranges from 0 (LED completely off) to 100 (LED fully on) * `int getPin()` - * returns the pin number + * returns the pin number, or -1 if LedPin was not successfully initialized LedPin also includes a static class function that converts Hue/Saturation/Brightness values (typically used by HomeKit) to Red/Green/Blue values (typically used to control multi-color LEDS). @@ -46,21 +52,19 @@ Creating an instance of this **class** configures the specified *pin* to output The *minMicros* parameter must be less than the *maxMicros* parameter, but setting *minDegrees* to a value greater than *maxDegrees* is allowed and can be used to reverse the minimum and maximum positions of the Servo Motor. The following methods are supported: -* `void set(uint8_t position)` +* `void set(double position)` * sets the position of the Servo Motor to *position* (in degrees). In order to protect the Servo Motor, values of *position* less than *minDegrees* are automatically reset to *minDegrees*, and values greater than *maxDegrees* are automatically reset to *maxDegrees*. * `int getPin()` - * returns the pin number + * returns the pin number, or -1 if LedPin was not successfully initialized A worked example showing how ServoPin can be used to control the Horizontal Tilt of a motorized Window Shade can be found in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → ServoControl*](../Other%20Examples/ServoControl). Resource limitations: -* A maximum of 16 LedPin objects can be instantiated -* A maximum of 8 ServoPin objects can be instantiated -* A maximum combined total of 16 LedPin and ServoPin objects can be instantiated (for example 10 LedPin and 6 ServoPin objects) +* ESP32: 16 PWM Channels HomeSpan will report a non-fatal error message to the Arduino Serial Monitor for each LedPin or ServoPin that instantiated beyond these limits. Calls to the `set()` method for objects that exceed these limits are ignored. From 3ea8f956a554bde1cb315f53c04633fbfd7cb16c Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 13 Sep 2021 06:02:20 -0500 Subject: [PATCH 16/54] Converted initial level of LedPin from uint8_t to float --- .DS_Store | Bin 6148 -> 14340 bytes src/.DS_Store | Bin 6148 -> 6148 bytes src/extras/PwmPin.cpp | 2 +- src/extras/PwmPin.h | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.DS_Store b/.DS_Store index 9a874b5768f336915163bb88cd434575b859f936..119a2839ec6f6ca0c9e18ab08e6d6aa9322c8d55 100644 GIT binary patch literal 14340 zcmeHO32+q075#rCq1j!7MqH~Ath6A51qhG?LgElwT}VP;$>`=1EA1d{d9^EcRuYFH zR4&H>8|T7_?aJjiPHb!wCqV2ZL{2I$7hpSOtAerP_{arz?l|#566bf%p4wRi6crO{ zrfR0AfA^nNcmLn-{XZiBz={D^0YE+gh;*`2x{fZN1hBI*>R|2cj60G@f^;sRlkOz| zC-gx-ct8O)u6MjZAQ96~rc)%H?a}%!wcFF>^LfzIQ_$4y>+9$GM@l=n0{cnhFlNA* z0b>S?88BwRn1Rcf0fxPFh!(9huEq=)Ghoa>cm~-1V5gInj$pZ0EBV$z7e?V(JEQRY zpnHk~xXd0b9l>(1R&rI+;i^<>su&D0P*W$lopq-KpY{mP(Q8S0eMyPcly z0qUfbdpu3Dl?eh%ud3o<{zt7`o^r`NE+vn|Q4=CFMtPguoOjG-M)#ndXa>aHx zJzwiJk^M$PKT}p)6~9WQ$z*yYEyFf*_PqR}Wo1>hYi}Bn(kD)`OtDzo2HmQ=%cHam zxm|(Y4yW3!cwKI9&w95@@dn&m-HP8NJz#3~I{Or^BxlOgMJY#YALw##8*m49j7&L0qKUWUWXtjf)>7$L=;{(hF1{gGwlu3WEXf({m^a^IX};O* zbxEp8Q!Oa8$Sodcm*SCJCQWTgu|;kh)J7%M2ZhU5Smbs}oAl9NtfpgLQ0yp|<<0Du z*ErQcL%-sszv^lFc{X%8Tdons4%S-kaw#rNxLRH#O3#by)n2DxX&CY<{*b&;6!}7u zoIS1DCw+J@MMpZy7Y^GGw z4%i0=;VbYxI08rE7(4~f!D)B}eh+_xzr#P^pKu3Weo@L#WgKb|HvNus$@%puC>Sco$O# z`!)9wKA*sSYU^rO*Oy(r?sF!MS_^@m=`TwSsAuC%|t_18Exy_z+>Ek8#uRv zQIl$HMDh$NMXTmo=8EJK(m1U;-?mUBFO&pc zwG`SGo5w*)GEs@r6%$^DS2di<}|s?VX;U+PH)m4RBfvf$#EocEQ=n) zo=?CFa0Xt7KaxFvK$dL644gqWybzaS8QE|pR^cja2wHIqZpKb@a!c+*FZSa$RPh$v zjUU0iWX=1yH6Oq);+OCqycfTW58$`)Av}Z+<54_@kK+^gL;M*&i!Y3_*)_2?i@(&f z**;%Ym1eUberLm>x8AG#X}Nws*G2W~?~TgrrtrTY&QAuL{9cdG+e59)za~Hf1fZ9a z#eT3ub!^JGYe)_H6r2qC)aei;iK0auFK%ig+|l-;3a5Vqt2H_Uy;mqTPA+ zT?Ivpim6hNU$A?(Nwm%?D6QMlw`1q7TXyfchYuVuw0)#$_3-uHv4$Pal#kUh2G*hG zgR%NYulLqft(#s?;_H3EHR$t2*8XC3V(fr6{jvV8Q8tl8FB|;OeU+_#QSp*Idtp(* z6WRlpR-_5NomEZ8`q6YARsYMGEYgg&Fk{6^fYOLHA9xeoQwFEs6EOiXPao3 zj{zCpBHLu@6pcoj!fZL0;Q)swO)}3spY8q}nl#mXb0Gs34cIhMk-3!LxV*VNXnu9xM}{4+E^QCy6enbyC7`p2`eU}F<+ zjALV>n1F_v2(@H-t>=Jd*hqUV<6-;Z4mbdJ5*Pax940O{3@70fJWG6Rg!tI+;4GYj zH;I$IO`Pl0AUXQbgmF41mT!O`fYRd@MYO#)(*&1SI8*n4Xv>uLS0b*u* z@K*d3@v?n*H!-q@iH|*s-^b(lH2xf4##iuH#K+F!`*LFEiPZ zkcAaeW5hQ?+-sArZ&a_U`LKNB%y{MvoK|Hs7b#xh2wT#XAywowM61kM8hJ`&V^XRX zG_cRm`8@VfE(g+T!E!Tu4-{LH^vrh!wy_eCh4Lep$B_8xf;Mh3Kkf-`WSwkLWKkP z8T>4Mj>y&5@Ih{I5t9oB0-BWg%0m&8i-yu4+<0oip&<^XL4%A2&G^YPlj-UDt3gb;>3AS{f*n8^Egt`I$}gU6l=4J)i0JutoY=%L|ld}ztw z0v~jPdbQ#Ck`lu6!lhRL&%;BEo$uhdW9B>c54Z8P2(^V#T{x?|b2T-aTch$Gmy%}D zLvr2VQ-?Ez1Nc$kUf;mcZ{j4gISRxR?KwOKBUuo!Bg5jx19h6ugCKzWqA;G6I$ZIi=r0-mQl${BbGUWVVmZz-R0 zmTj4E9{vsgK?_dCDL55pQYIyjw#$W-PbtNfJf{+gMms1D?dBO3FVCm!qDb@;luOaJ zNZKBGn~|kOe3abV z$I^m-5Otbkpi!=GrUKFJ}OgtD34R=uc0yiLh_& z>~wCSll2*l09n|Jv_f+oHO1h)tfBqq0qR))<(E2j+ UU-1BL#Q#S8AN~int0w;cFLitguK)l5 delta 151 zcmZoEXfcprU|?W$DortDU=RQ@Ie-{MGpJ516gFW5GME{P8HyN^Q;L&wlJfI&Ktf=^ z1f@X&KrFxjmEU;LjD6yRqQ&eS9D>XcH3Hl~+7*aZH(vbCJel7_krSjV0f-qUoA4-4 RPB39-1v!Lab3D%+W&rVX7^46H diff --git a/src/.DS_Store b/src/.DS_Store index 9265ca9824eb34af67e3c33625e24c4686274aed..bd87f60885d3c139b0a9960a74cbde3daf66f512 100644 GIT binary patch delta 203 zcmZoMXfc=|#>B`mu~2NHo+2ab!~pAw2O5BMk4!xqLn=cBLkU9>Ln1?QPP$=ma(-?B z0~jPU11S{w+CJzu~2NHo+2aT!~knX#>qU4GMl$B2D5EGz{tb6nVo~51E^&4M#k^V allet-IT;xk7!Ck2!(CG`BOPB$$_z~Iw diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index f1021e2..c6c7265 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -47,7 +47,7 @@ LedC::LedC(uint8_t pin, uint16_t freq){ /////////////////// -LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq) : LedC(pin, freq){ +LedPin::LedPin(uint8_t pin, float level, uint16_t freq) : LedC(pin, freq){ if(!channel) Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index 28a280f..b66fcb5 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -51,7 +51,7 @@ class LedC { class LedPin : public LedC { public: - LedPin(uint8_t pin, uint8_t level=0, uint16_t freq=DEFAULT_PWM_FREQ); // assigns pin to be output of one of 16 PWM channels initial level and frequency + LedPin(uint8_t pin, float level=0, uint16_t freq=DEFAULT_PWM_FREQ); // assigns pin to be output of one of 16 PWM channels initial level and frequency void set(float level); // sets the PWM duty to level (0-100) static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B From 7469ab8a93ea182f5549e8d3a742e8edc3f3b821 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 14 Sep 2021 06:17:16 -0500 Subject: [PATCH 17/54] Update Extras.md --- docs/Extras.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/Extras.md b/docs/Extras.md index f9bbbc4..3370af1 100644 --- a/docs/Extras.md +++ b/docs/Extras.md @@ -62,11 +62,17 @@ The *minMicros* parameter must be less than the *maxMicros* parameter, but setti A worked example showing how ServoPin can be used to control the Horizontal Tilt of a motorized Window Shade can be found in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → ServoControl*](../Other%20Examples/ServoControl). -Resource limitations: +### PWM Resource Allocation and Limitations -* ESP32: 16 PWM Channels +The following PWM resources are available: -HomeSpan will report a non-fatal error message to the Arduino Serial Monitor for each LedPin or ServoPin that instantiated beyond these limits. Calls to the `set()` method for objects that exceed these limits are ignored. +* ESP32: 16 Channels / 8 Timers (arranged in two distinct sets of 8 Channels and 4 Timers) +* ESP32-S2: 8 Channels / 4 Timer +* ESP32-C3: 6 Channels / 4 Timers + +HomeSpan *automatically* allocates Channels and Timers to LedPin and ServoPin objects as they are instantiated. Every pin assigned consumes a single Channel; every *unique* frequency specified among all channels (within the same set, for the ESP32) consumes a single Timer. HomeSpan will conserve resources by re-using the same Timer for all Channels operating at the same frequency. HoneSpan also automatically configures each Timer to support the maximum duty-resolution possible for the frequency specified. + +HomeSpan will report a non-fatal error message to the Arduino Serial Monitor when insufficient Channel or Timer resources prevent the creation of a new LedPin or ServoPin object. Calls to the `set()` method for objects that failed to be properly created are silently ignored. ## Remote Control Radio Frequency / Infrared Signal Generation From 6c9bf39f546b590ae7c1a8ae9e6d8405916b614c Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 14 Sep 2021 21:09:58 -0500 Subject: [PATCH 18/54] Added PWM diagnostic messages and chip-specific maximum duty resolution --- src/HomeSpan.cpp | 4 ++++ src/extras/PwmPin.cpp | 24 +++++++++++++++++++++--- src/extras/PwmPin.h | 6 ------ src/extras/extras.ino | 16 ++++++++-------- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 0f5c25b..c853869 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "HomeSpan.h" #include "HAP.h" @@ -107,6 +108,9 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(ARDUINO_VARIANT); #endif + Serial.printf("\nPWM Resources: %d channels, %d timers, max %d-bit duty resolution", + LEDC_SPEED_MODE_MAX*LEDC_CHANNEL_MAX,LEDC_SPEED_MODE_MAX*LEDC_TIMER_MAX,LEDC_TIMER_BIT_MAX-1); + Serial.print("\nSketch Compiled: "); Serial.print(__DATE__); Serial.print(" "); diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index c6c7265..59e7aa6 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -19,7 +19,7 @@ LedC::LedC(uint8_t pin, uint16_t freq){ timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; timerList[nTimer][nMode]->freq_hz=freq; - int res=20; // find the maximum possible resolution + int res=LEDC_TIMER_BIT_MAX-1; // find the maximum possible resolution while(getApbFrequency()/(freq*pow(2,res))<1) res--; @@ -51,7 +51,16 @@ LedPin::LedPin(uint8_t pin, float level, uint16_t freq) : LedC(pin, freq){ if(!channel) Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); - + else + Serial.printf("LedPin=%d: mode=%d channel=%d, timer=%d, freq=%d Hz, resolution=%d bits\n", + channel->gpio_num, + channel->speed_mode, + channel->channel, + channel->timer_sel, + timer->freq_hz, + timer->duty_resolution + ); + set(level); } @@ -135,7 +144,16 @@ ServoPin::ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t if(!channel) Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); - + else + Serial.printf("ServoPin=%d: mode=%d channel=%d, timer=%d, freq=%d Hz, resolution=%d bits\n", + channel->gpio_num, + channel->speed_mode, + channel->channel, + channel->timer_sel, + timer->freq_hz, + timer->duty_resolution + ); + this->minMicros=minMicros; this->maxMicros=maxMicros; this->minDegrees=minDegrees; diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index b66fcb5..9bc28be 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -11,12 +11,6 @@ // ServoPin(pin) - controls a Servo Motor on specified pin with frequency=50 Hz // - use set(degrees) to set position to degrees // -// Max number of LedPin instantiations: 16 -// Max number of ServoPin instantiatons: 8 -// Max combined limit (LedPins+ServoPins): 16 -// -// Instantiation of an LedPin or ServoPin that causes any of the maximums above to be exceeded throws -// an error message. The object will still be created, but calls to set(level) or set(degrees) are ignored. // ///////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/extras/extras.ino b/src/extras/extras.ino index e9839e0..76c7343 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -18,7 +18,7 @@ void setup(){ LedPin led1(19,100,2000); LedPin led2(16,10,80000); LedPin led3(17,100,2000); - LedPin led4(23); + LedPin led4(23,100,2); LedPin led5(22,0,3000); LedPin led6(14,0,1); LedPin led7(32,0,1850); @@ -37,15 +37,15 @@ void setup(){ led14.set(100); Serial.println(led0.getPin()); - Serial.println(led14.getPin()); - Serial.println(led15.getPin()); - Serial.println(led16.getPin()); +// Serial.println(led14.getPin()); +// Serial.println(led15.getPin()); +// Serial.println(led16.getPin()); - uint32_t v=REG_READ(LEDC_HSTIMER0_CONF_REG); - Serial.printf("HS %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF); +// uint32_t v=REG_READ(LEDC_HSTIMER0_CONF_REG); +// Serial.printf("HS %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF); - v=REG_READ(LEDC_LSTIMER0_CONF_REG); - Serial.printf("LS %d %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF,REG_READ(LEDC_CONF_REG)); +// v=REG_READ(LEDC_LSTIMER0_CONF_REG); +// Serial.printf("LS %d %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF,REG_READ(LEDC_CONF_REG)); From 014def4c661047aec6b9cb194d933fdc630f51da Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 15 Sep 2021 20:05:15 -0500 Subject: [PATCH 19/54] Fixed compiler complaint about pow() function. AND added 2.0.0 only variable - see LED_USE_APB_CLK. --- src/extras/PwmPin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index 59e7aa6..e33902f 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -18,6 +18,7 @@ LedC::LedC(uint8_t pin, uint16_t freq){ timerList[nTimer][nMode]->speed_mode=(ledc_mode_t)nMode; timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; timerList[nTimer][nMode]->freq_hz=freq; + timerList[nTimer][nMode]->clk_cfg=LEDC_USE_APB_CLK; int res=LEDC_TIMER_BIT_MAX-1; // find the maximum possible resolution while(getApbFrequency()/(freq*pow(2,res))<1) @@ -75,7 +76,7 @@ void LedPin::set(float level){ if(level>100) level=100; - channel->duty=level*(pow(2,timer->duty_resolution)-1); + channel->duty=level*(pow(2,(int)timer->duty_resolution)-1); channel->duty/=100; ledc_channel_config(channel); @@ -177,7 +178,7 @@ void ServoPin::set(double degrees){ else if(usec>maxMicros) usec=maxMicros; - usec*=timer->freq_hz/1e6*(pow(2,timer->duty_resolution)-1); + usec*=timer->freq_hz/1e6*(pow(2,(int)timer->duty_resolution)-1); channel->duty=usec; ledc_channel_config(channel); From c67336ab57af791b558bbc758817f7083aab5020 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 18 Sep 2021 06:35:41 -0500 Subject: [PATCH 20/54] Updated Blinker logic to support S2 and C3 Needed to set clk_src to APB, else default is XTAL, which is only 40MHz clock! --- .DS_Store | Bin 14340 -> 14340 bytes src/.DS_Store | Bin 6148 -> 6148 bytes src/Utils.cpp | 7 ++++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.DS_Store b/.DS_Store index 119a2839ec6f6ca0c9e18ab08e6d6aa9322c8d55..87e48cc7fd91cb793f86876fd66056a1117d73c1 100644 GIT binary patch delta 114 zcmZoEXepSmi+LLZ!^XW*l1%&SH{X<8%F6b=dWBg;)#MiWZ6K-1wh9t#MX!%MO|P6B ztsn(sRx3y|bwAiVLqV94>BFVXYZZH0*|r|qsu@?Y*+Jco18T_T7X5APQ1QtQ>PG;o Cr7y?; delta 114 zcmZoEXepSmi+QVU{Kmafl1vBoZN4eFl$C9_-x<9%<&#_Fw}GT4+bT$~P1}ARBowV6 z1!Gn#NHcX#*gQi)n33sC=jOGFy{v2>jvd(4UbNXk-Hrol$mSOPZR}9-$qwpA0RI0m Ap#T5? diff --git a/src/.DS_Store b/src/.DS_Store index bd87f60885d3c139b0a9960a74cbde3daf66f512..06a362e58201a14d5ed0ab99a69fd20031892ea4 100644 GIT binary patch delta 49 zcmZoMXffE}%&3w$mw|zSjUknxf}w<=h#`@oI5*$LB`GIA2`J7{W89mgroup,b->idx,TIMER_ALARM_EN); + } ////////////////////////////////////// From 8b33f61464069371d8aaf08cb20f46076d126d1a Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 18 Sep 2021 13:59:36 -0500 Subject: [PATCH 21/54] Update src.ino --- src/src.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/src.ino b/src/src.ino index 485e18d..4e2fd9f 100644 --- a/src/src.ino +++ b/src/src.ino @@ -9,6 +9,8 @@ void setup() { Serial.begin(115200); homeSpan.setLogLevel(1); + homeSpan.setStatusPin(5); + homeSpan.setControlPin(33); homeSpan.setHostNameSuffix("-lamp1"); homeSpan.setPortNum(1201); @@ -21,7 +23,7 @@ void setup() { new SpanUserCommand('d',"- My Description",userCom1); new SpanUserCommand('e',"- My second Description",userCom2); - homeSpan.enableAutoStartAP(); +// homeSpan.enableAutoStartAP(); // homeSpan.setApFunction(myWiFiAP); homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); From 7255a9530f783b4d3eefc48b96d0cf95bb242e42 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 18 Sep 2021 16:28:56 -0500 Subject: [PATCH 22/54] Updating Extras to work through S2 and C3 issues --- src/.DS_Store | Bin 6148 -> 6148 bytes src/extras/PwmPin.cpp | 14 ++++++++--- src/extras/RFControl.cpp | 4 +-- src/extras/extras.ino | 51 +++++++++++++++++++++++---------------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/.DS_Store b/src/.DS_Store index 06a362e58201a14d5ed0ab99a69fd20031892ea4..6c095b11a1dce045bb2733cdec97daff5ce0d95c 100644 GIT binary patch delta 327 zcmZoMXfc=|#>B)qu~2NHo}wr-0|Nsi1A_nqLn1?QQh9MfQcix-=8cTY8S6n(Yz(Ok z6$~W|Maa@X@smjfIhn;J1_sv|nV4Bv+1NQifR`gSI3vG2xFoTpwAd-JC>q2ING!=n zg0e&M^K;81l9=%H%)FHRa;N;#yp&?FLBS9i zP7sI}kf^SmG_b7IQK&XFG_llCFgG!)t>xqpS2eWtOvtUQs;;T6n+bF+5HJEg z2?qR78b-~U%)_Y3Qx;s5my@5D4ises`u-uyW_AvK4qz|=Ip3Kl^NUz=01W_}u{l6w G3o`&y-c|qr delta 214 zcmZoMXfc=|#>B`mu~2NHo}wr#0|Nsi1A_nqLn1?QN^x>dQht8U#KPr_tdl=7Y1ZeY z8wMxm=N14}0YTziAi>6v%22^j!cYX#k(=-0l9ZF51Qh3}G44%at~~6BsU`)k=FRuB zdTYut)f8kP+p_>@1Q=|#WIo5Tv7wc5Gdl-A2hi1<4Vk|)Pv#e~duty_resolution=(ledc_timer_bit_t)res; ledc_timer_config(timerList[nTimer][nMode]); @@ -191,9 +193,11 @@ ledc_timer_config_t *LedC::timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]={}; //////////////////////////// -//******************************************************* -// DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY -//******************************************************* +//***************************************************************** +// DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY FOR ESP32 ONLY +//***************************************************************** + +#ifdef CONFIG_IDF_TARGET_ESP32 PwmPin::PwmPin(uint8_t channel, uint8_t pin){ this->channel=channel & 0x0F; @@ -283,3 +287,5 @@ void PwmPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ break; } } + +#endif diff --git a/src/extras/RFControl.cpp b/src/extras/RFControl.cpp index 0e5990a..5990831 100644 --- a/src/extras/RFControl.cpp +++ b/src/extras/RFControl.cpp @@ -15,7 +15,7 @@ RFControl::RFControl(int pin){ REG_SET_BIT(RMT_APB_CONF_REG,3); // enables access to RMT memory and enables wraparound mode (though the latter does not seem to be needed to set continuous TX) REG_WRITE(RMT_INT_ENA_REG,1<>8); +Serial.printf("DIV1: %d\n",REG_GET_FIELD(LEDC_LSTIMER1_CONF_REG,LEDC_CLK_DIV_LSTIMER1)>>8); +Serial.printf("DIV2: %d\n",REG_GET_FIELD(LEDC_LSTIMER2_CONF_REG,LEDC_CLK_DIV_LSTIMER2)>>8); + // uint32_t v=REG_READ(LEDC_HSTIMER0_CONF_REG); // Serial.printf("HS %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF); From 0ccb1d34a04e1a9b7835fcf6633ea72a71b009ce Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 19 Sep 2021 13:39:40 -0500 Subject: [PATCH 23/54] More updates to PWM to ensure S2 and C3 compatibility New IDF parameter in 2.0.0 for LEDC allows PWM signal to be inverted! Need to ensure flags.output_inverted is set to 0! Also: Deleted old PWM class, which was saved for backwards compatibility. This "breaks" HomeSpan for those using the old PWM class (instead of LedPin). Also: Added checks to ensure that frequency is achievable (for S2 and C3, the 14-bit duty resolution is insufficient to allow frequencies slower than 5 Hz - this is not a practical limit when using LedPin to drive actual LEDs and lights). --- src/.DS_Store | Bin 6148 -> 6148 bytes src/extras/PwmPin.cpp | 115 ++++-------------------------------------- src/extras/PwmPin.h | 17 ------- src/extras/extras.ino | 108 +++++++++++++++++++++++++-------------- 4 files changed, 78 insertions(+), 162 deletions(-) diff --git a/src/.DS_Store b/src/.DS_Store index 6c095b11a1dce045bb2733cdec97daff5ce0d95c..ba874113d6552e063b01ff44295ccf783c55a32c 100644 GIT binary patch delta 214 zcmZoMXfc=|#>B`mu~2NHo}wr#0|Nsi1A_nqLn1?QN^x>dQht8U#KPr_tdl=7Y1ZeY z8wMxm=N14}0YQ8tkYHm-WvE~%VJHIW$jx_gNy^Dj0*Z57Sj~L&PW53&Of@NRHE+J3 z)mu}Jsiq(U*`5VJBfwy@CG$C!jSa1go7p+|Ie@O-Y{>kbc{0CB)qu~2NHo}wr-0|Nsi1A_nqLn1?QQh9MfQcix-=8cTY8S6n(Yz(Ok z6$~W|Maa@X@smjfIhn;J1_sv|nV4Bv+1NQifR`gSI3vG2xFoTpwAd-JC>q2ING!=n zg0e&M^K;81l9=%H%)FHRa;N;#yp&?FLBS9i zP7sI}kf^SmG_b7IQK&XFG_llCFgG!)t>xqpS2eWtOvtUQs;;T6n+bF+5HJEg z2?qR78b-~U%)_Y3Qx;s5my@5D4ises`u-uyW_AvK4qz|=Ip3Kl^NUz=01W_}u{l6w G3o`&y-c|qr diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index db0a7d9..018437c 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -19,15 +19,16 @@ LedC::LedC(uint8_t pin, uint16_t freq){ timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; timerList[nTimer][nMode]->freq_hz=freq; timerList[nTimer][nMode]->clk_cfg=LEDC_USE_APB_CLK; - + int res=LEDC_TIMER_BIT_MAX-1; // find the maximum possible resolution while(getApbFrequency()/(freq*pow(2,res))<1) res--; - - Serial.println(getApbFrequency()/(freq*pow(2,res))); timerList[nTimer][nMode]->duty_resolution=(ledc_timer_bit_t)res; - ledc_timer_config(timerList[nTimer][nMode]); + if(ledc_timer_config(timerList[nTimer][nMode])!=0){ + Serial.printf("\n*** ERROR: Frequency=%d Hz is out of allowed range ---",freq); + return; + } } if(timerList[nTimer][nMode]->freq_hz==freq){ // if timer matches desired frequency (always true if newly-created above) @@ -36,6 +37,7 @@ LedC::LedC(uint8_t pin, uint16_t freq){ channelList[nChannel][nMode]->channel=(ledc_channel_t)nChannel; channelList[nChannel][nMode]->timer_sel=(ledc_timer_t)nTimer; channelList[nChannel][nMode]->intr_type=LEDC_INTR_DISABLE; + channelList[nChannel][nMode]->flags.output_invert=0; channelList[nChannel][nMode]->hpoint=0; channelList[nChannel][nMode]->gpio_num=pin; timer=timerList[nTimer][nMode]; @@ -77,9 +79,9 @@ void LedPin::set(float level){ if(level>100) level=100; - - channel->duty=level*(pow(2,(int)timer->duty_resolution)-1); - channel->duty/=100; + + float d=level*(pow(2,(int)timer->duty_resolution)-1)/100.0; + channel->duty=d; ledc_channel_config(channel); } @@ -190,102 +192,3 @@ void ServoPin::set(double degrees){ ledc_channel_config_t *LedC::channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]={}; ledc_timer_config_t *LedC::timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]={}; - -//////////////////////////// - -//***************************************************************** -// DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY FOR ESP32 ONLY -//***************************************************************** - -#ifdef CONFIG_IDF_TARGET_ESP32 - -PwmPin::PwmPin(uint8_t channel, uint8_t pin){ - this->channel=channel & 0x0F; - this->pin=pin; - - ledc_timer_config_t ledTimer; - ledTimer.timer_num=LEDC_TIMER_0; - ledTimer.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE; - ledTimer.duty_resolution=LEDC_TIMER_10_BIT; - ledTimer.freq_hz=5000; - ledc_timer_config(&ledTimer); - - ledChannel.gpio_num=pin; - ledChannel.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE; - ledChannel.channel=(ledc_channel_t)(this->channel&0x07); - ledChannel.intr_type=LEDC_INTR_DISABLE; - ledChannel.timer_sel=LEDC_TIMER_0; - ledChannel.duty=0; - ledChannel.hpoint=0; - ledc_channel_config(&ledChannel); - -} - -/////////////////// - -void PwmPin::set(uint8_t channel, uint8_t level){ - ledChannel.duty=level*1023; - ledChannel.duty/=100; - ledChannel.duty&=0x03FF; - ledc_channel_config(&ledChannel); - -} - -/////////////////// - -void PwmPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ - - // The algorithm below was provided on the web at https://www.cs.rit.edu/~ncs/color/t_convert.html - // h = [0,360] - // s = [0,1] - // v = [0,1] - - int i; - float f, p, q, t; - - if( s == 0 ){ - *r = *g = *b = v; - return; - } - - h /= 60; - i = floor( h ) ; - f = h - i; - p = v * ( 1 - s ); - q = v * ( 1 - s * f ); - t = v * ( 1 - s * ( 1 - f ) ); - switch( i % 6 ) { - case 0: - *r = v; - *g = t; - *b = p; - break; - case 1: - *r = q; - *g = v; - *b = p; - break; - case 2: - *r = p; - *g = v; - *b = t; - break; - case 3: - *r = p; - *g = q; - *b = v; - break; - case 4: - *r = t; - *g = p; - *b = v; - break; - case 5: - *r = v; - *g = p; - *b = q; - break; - } -} - -#endif diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index 9bc28be..963aee7 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -65,20 +65,3 @@ class ServoPin : public LedC { void set(double degrees); // sets the Servo to degrees, where degrees is bounded by [minDegrees,maxDegrees] }; - -//******************************************************* -// DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY -//******************************************************* - -class PwmPin { - uint8_t channel; - uint8_t pin; - ledc_channel_config_t ledChannel; - - public: - PwmPin(uint8_t channel, uint8_t pin); // assigns pin to be output of one of 16 PWM channels (0-15) - void set(uint8_t channel, uint8_t level); // sets the PWM duty to level (0-100) - int getPin(){return pin;} // returns the pin number - - static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B -}; diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 5cf40df..3b9cb04 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -4,6 +4,7 @@ #include "PwmPin.h" #include +#include "esp_rom_gpio.h" void setup(){ @@ -14,49 +15,78 @@ void setup(){ Serial.println("Starting..."); - LedPin led12(12,99,500); - LedPin led5(5,20,20000); - LedPin led6(6,20,5000); -// LedPin led3(17,50,1); -// LedPin led2(16,10,8000); -// LedPin led4(23,100,2); -// LedPin led5(22,0,3000); -// LedPin led6(14,0,1); -// LedPin led7(32,0,1850); -// LedPin led8(15); -// LedPin led9(33); -// LedPin led10(27); -// ServoPin led14(25); -// LedPin led11(12,100,23); -// LedPin led12(13,100); -// LedPin led13(26); -// LedPin led15(4,0); + LedPin *led[20]; -Serial.printf("HELLO\n"); +// int p[]={33,27,4,32,18,19,16,17,5}; + int p[]={11,7,3,1,38,33,9}; -// led16.set(20); -// led0.set(5); -// led14.set(100); - -// Serial.println(led0.getPin()); -// Serial.println(led14.getPin()); -// Serial.println(led15.getPin()); -// Serial.println(led16.getPin()); - -Serial.printf("RES0: %d\n",REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_LSTIMER0_DUTY_RES)); -Serial.printf("RES1: %d\n",REG_GET_FIELD(LEDC_LSTIMER1_CONF_REG,LEDC_LSTIMER1_DUTY_RES)); -Serial.printf("RES2: %d\n",REG_GET_FIELD(LEDC_LSTIMER2_CONF_REG,LEDC_LSTIMER2_DUTY_RES)); -Serial.printf("DIV0: %d\n",REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_CLK_DIV_LSTIMER0)>>8); -Serial.printf("DIV1: %d\n",REG_GET_FIELD(LEDC_LSTIMER1_CONF_REG,LEDC_CLK_DIV_LSTIMER1)>>8); -Serial.printf("DIV2: %d\n",REG_GET_FIELD(LEDC_LSTIMER2_CONF_REG,LEDC_CLK_DIV_LSTIMER2)>>8); - -// uint32_t v=REG_READ(LEDC_HSTIMER0_CONF_REG); -// Serial.printf("HS %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF); - -// v=REG_READ(LEDC_LSTIMER0_CONF_REG); -// Serial.printf("LS %d %d %d %d %d\n",(v>>25)&1,v&0x1f,(v>>13)&0x3FF,(v>>5)&0xFF,REG_READ(LEDC_CONF_REG)); + for(int i=0;i>8, +// REG_GET_FIELD(LEDC_HSTIMER0_CONF_REG,LEDC_DIV_NUM_HSTIMER0)&0xFF, +// REG_GET_FIELD(LEDC_HSTIMER0_CONF_REG,LEDC_HSTIMER0_DUTY_RES) +// ); +// +//Serial.printf("HSCHAN0: %d %d %d %d %d\n", +// REG_READ(LEDC_HSCH0_CONF0_REG), +// REG_READ(LEDC_HSCH0_HPOINT_REG), +// REG_READ(LEDC_HSCH0_DUTY_REG)>>4, +// REG_READ(LEDC_HSCH0_DUTY_REG)&0xF, +// REG_GET_FIELD(LEDC_HSCH0_CONF1_REG,LEDC_DUTY_INC_HSCH0) +// ); +// +//Serial.printf("LSTIMER0: %d %d %d %d\n", +// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_TICK_SEL_LSTIMER0), +// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_DIV_NUM_LSTIMER0)>>8, +// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_DIV_NUM_LSTIMER0)&0xFF, +// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_LSTIMER0_DUTY_RES) +// ); +// +//delay(100); +// +//Serial.printf("LSCHAN0: %d %d %d %d %d\n", +// REG_READ(LEDC_LSCH0_CONF0_REG), +// REG_READ(LEDC_LSCH0_HPOINT_REG), +// REG_READ(LEDC_LSCH0_DUTY_REG)>>4, +// REG_READ(LEDC_LSCH0_DUTY_REG)&0xF, +// REG_GET_FIELD(LEDC_LSCH0_CONF1_REG,LEDC_DUTY_INC_LSCH0) +// ); +// +//Serial.printf("LOW CLOCK: %d\n",REG_READ(LEDC_CONF_REG)); +// +//Serial.printf("GPIO 32: %d %d %d %d\n", +// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OEN_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OEN_SEL), +// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OUT_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OUT_SEL) +// ); +// +//Serial.printf("GPIO 5: %d %d %d %d\n", +// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OEN_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OEN_SEL), +// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OUT_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OUT_SEL) +// ); +// +//Serial.printf("GPIO 4: %d %d %d %d\n", +// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OEN_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OEN_SEL), +// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OUT_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OUT_SEL) +// ); +// +//Serial.printf("GPIO 33: %d %d %d %d\n", +// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OEN_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OEN_SEL), +// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OUT_INV_SEL), +// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OUT_SEL) +// ); while(1); } From fdc3dfb47452221a5218017a404615ae3d1076cb Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 19 Sep 2021 13:40:50 -0500 Subject: [PATCH 24/54] Update .DS_Store --- .DS_Store | Bin 14340 -> 14340 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 87e48cc7fd91cb793f86876fd66056a1117d73c1..86381ba3a85e5e94a47b3dea5da57e9ee876b65e 100644 GIT binary patch delta 81 zcmZoEXepSmn<;Mn#=TOKOa~WlzA3qsl`X3D__fsP$u08RfijbA6(rbf&XsSwTRk~i aK?=sKR*+`uZP+|R;Ta!P{pJ?^1`YtX-y=8x delta 81 zcmZoEXepSmn~8y8<6bFArv3GsZ%Qs@W&2*e!Yra{a*O Date: Sun, 19 Sep 2021 13:53:20 -0500 Subject: [PATCH 25/54] Clean up PWM - ready for testing To do: Test RGB LED Examples with ESP32 and ESP32-S2 boards. Next: Re-work Remote Control routines to make compatible with S2 and C3 --- .DS_Store | Bin 14340 -> 14340 bytes .gitignore | 2 ++ src/.DS_Store | Bin 6148 -> 6148 bytes src/extras/PwmPin.h | 3 -- src/extras/extras.ino | 75 +++--------------------------------------- 5 files changed, 7 insertions(+), 73 deletions(-) diff --git a/.DS_Store b/.DS_Store index 86381ba3a85e5e94a47b3dea5da57e9ee876b65e..4cf94eadcbafbf219f6e63bd7b418e0b5be548ec 100644 GIT binary patch delta 53 zcmZoEXepSmn<+bb<6bFArtSWlZ%QVy0lAZH6(m?R9tqr>9H}4!VN@!}F>csALm@{T E044DgfdBvi delta 53 zcmZoEXepSmn<;Mn#=TOKOa~WlzA2f+2INk*Rghq@Iaj`Ia-@O`gi)y=$JnrWhC+@w E08u;?#Q*>R diff --git a/.gitignore b/.gitignore index 169af9e..06d5ef4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .development +.DS_Store +src/.DS_Store diff --git a/src/.DS_Store b/src/.DS_Store index ba874113d6552e063b01ff44295ccf783c55a32c..cd8393a9b53d65b9061407073572938ae3331f4d 100644 GIT binary patch delta 382 zcmZoMXfc=|#>B)qu~2NHo}wr_0|Nsi1A_nqLn1?QQh9MfQcix-=8cTY8S6n(Yz(Ok z6$~W|Maa@X@zY5KIhn;J1_sv|nV4Bv+1NQaIJh}@Ibwq|^2>uu5=%;pof39_j~5Ve&d)1J%*;zI0&C7pNd+p23D3;TOUW;H$}i1JDFz!9 z43XjFB`mu~2NHo}wr#0|Nsi1A_nqLn1?QN^x>dQht8U#KPr_tdl=8nKQ*V zPS# #include -#include - -using std::vector; #define DEFAULT_PWM_FREQ 5000 diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 3b9cb04..c433195 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -3,8 +3,6 @@ // as well as compile and test from this point. This file is ignored when the library is included in other sketches. #include "PwmPin.h" -#include -#include "esp_rom_gpio.h" void setup(){ @@ -17,76 +15,13 @@ void setup(){ LedPin *led[20]; -// int p[]={33,27,4,32,18,19,16,17,5}; - int p[]={11,7,3,1,38,33,9}; +// uint8_t p[]={33,27,4,32,18,19,16,17,5}; // ESP32 test + uint8_t p[]={11,7,3,1,38,33,9,10}; // ESP32-S2 test - for(int i=0;i>8, -// REG_GET_FIELD(LEDC_HSTIMER0_CONF_REG,LEDC_DIV_NUM_HSTIMER0)&0xFF, -// REG_GET_FIELD(LEDC_HSTIMER0_CONF_REG,LEDC_HSTIMER0_DUTY_RES) -// ); -// -//Serial.printf("HSCHAN0: %d %d %d %d %d\n", -// REG_READ(LEDC_HSCH0_CONF0_REG), -// REG_READ(LEDC_HSCH0_HPOINT_REG), -// REG_READ(LEDC_HSCH0_DUTY_REG)>>4, -// REG_READ(LEDC_HSCH0_DUTY_REG)&0xF, -// REG_GET_FIELD(LEDC_HSCH0_CONF1_REG,LEDC_DUTY_INC_HSCH0) -// ); -// -//Serial.printf("LSTIMER0: %d %d %d %d\n", -// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_TICK_SEL_LSTIMER0), -// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_DIV_NUM_LSTIMER0)>>8, -// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_DIV_NUM_LSTIMER0)&0xFF, -// REG_GET_FIELD(LEDC_LSTIMER0_CONF_REG,LEDC_LSTIMER0_DUTY_RES) -// ); -// -//delay(100); -// -//Serial.printf("LSCHAN0: %d %d %d %d %d\n", -// REG_READ(LEDC_LSCH0_CONF0_REG), -// REG_READ(LEDC_LSCH0_HPOINT_REG), -// REG_READ(LEDC_LSCH0_DUTY_REG)>>4, -// REG_READ(LEDC_LSCH0_DUTY_REG)&0xF, -// REG_GET_FIELD(LEDC_LSCH0_CONF1_REG,LEDC_DUTY_INC_LSCH0) -// ); -// -//Serial.printf("LOW CLOCK: %d\n",REG_READ(LEDC_CONF_REG)); -// -//Serial.printf("GPIO 32: %d %d %d %d\n", -// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OEN_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OEN_SEL), -// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OUT_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC32_OUT_SEL_CFG_REG,GPIO_FUNC32_OUT_SEL) -// ); -// -//Serial.printf("GPIO 5: %d %d %d %d\n", -// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OEN_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OEN_SEL), -// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OUT_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC5_OUT_SEL_CFG_REG,GPIO_FUNC5_OUT_SEL) -// ); -// -//Serial.printf("GPIO 4: %d %d %d %d\n", -// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OEN_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OEN_SEL), -// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OUT_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC4_OUT_SEL_CFG_REG,GPIO_FUNC4_OUT_SEL) -// ); -// -//Serial.printf("GPIO 33: %d %d %d %d\n", -// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OEN_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OEN_SEL), -// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OUT_INV_SEL), -// REG_GET_FIELD(GPIO_FUNC33_OUT_SEL_CFG_REG,GPIO_FUNC33_OUT_SEL) -// ); + led[7]->set(100); while(1); } From 09fec33f50e8da89648a412213cde08f3d1369dc Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 19 Sep 2021 13:55:23 -0500 Subject: [PATCH 26/54] Update .DS_Store --- .DS_Store | Bin 14340 -> 14340 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 4cf94eadcbafbf219f6e63bd7b418e0b5be548ec..3b6d4bf00e4f950944212b9afbd159af0868f9e2 100644 GIT binary patch delta 48 ycmZoEXepSmo2m8v#=Uj&Kx(qBf&}Z@$sqyvCr2qrLs?Y{GE99An`bEGhywr(SQGL9 delta 48 ycmZoEXepSmn<+bb Date: Sun, 19 Sep 2021 13:55:36 -0500 Subject: [PATCH 27/54] Update .DS_Store --- .DS_Store | Bin 14340 -> 14340 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 3b6d4bf00e4f950944212b9afbd159af0868f9e2..8fa65051cc7e41ea2defdf88eaa9a4e284ee0e0a 100644 GIT binary patch delta 45 vcmZoEXepSmn`w&S#=Uj&Kx(qBf&`1=|4Y4-BNb#Ij7kML#)8c=6mrA?r|uD~ delta 45 vcmZoEXepSmo2m8v#=Uj&Kx(qBf&|Oj$sqxgBNb#Ij7kMLMu*Ka6mrA?!5$H$ From 013622c2638782498d5680c7655eb00e48eafaa9 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 19 Sep 2021 14:01:30 -0500 Subject: [PATCH 28/54] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 06d5ef4..d7e1472 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ .development .DS_Store -src/.DS_Store From 4da033195a90ba4d4a11ef88c4e43411a92c4553 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 19 Sep 2021 14:04:16 -0500 Subject: [PATCH 29/54] Removing .DS_Store files --- .DS_Store | Bin 14340 -> 0 bytes src/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 src/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 8fa65051cc7e41ea2defdf88eaa9a4e284ee0e0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14340 zcmeHO32+nF8UFvZjaO2@Yc6>WvIP#rfC1ZJYz|}j!ZwE3!M8b#Y%R7XvShrH4LDFH zJ*Ql0n6NBw6OzyaXwo(%>9oxNNjt<7Lei8Zy&#$1X>-t){_m}BtuQc5LmBPN z?%Vgj_pkKc`~UZS|GyFdV1>_70FVy=BAu+1ZlcR40IaMGJ6JnAV~!+}Ae{^7qJ*?=^ZN&NW}D$=@dz4Te!YM?QwN`JT7$g7BuyE`UklFk-OGn~FD!W~tZVLUgy9ZoO)tjIH3JOWd zDdSQ_gVAI%O=xLtX>0H3k|dw1tW#WeuX9MLvU?S^OG;DwJi~Q89(UuQGUQZ-yQK6U zyQ{}Xos@EytI4@TQQLYvE?>W!_wE_=xLl1M)#-J5+#T&+Wt*4vVGoLEYVTA%gWgK6 z*zTm~YrQ72&uAE6%4(}Js8VS#7#>f{u*{r2FTZG6Syk=Y+eW4IiIYrIOy;&Br|Rr> zDJ{cJhqtf8uJ$Nyhtu8L>2xS=uXBr288k=_8=BqreuXQ^neuc|$`RXr-OjB(r+544 zr1XhWR<>-~;GhAm^*ET4Lpm%PcuP*UEU#xRm4gah9iqs^x8%yEW|f8|+5H{!=9^5- zw>#YqNi}Gy1%)QL#bxhST$00}sVyls$!$a0sHA$oaQO<8+)inee)`60I_CMswsKkC z#6EeAUG+8$C~o>z&(X)Tq08BFjVN}o)^dkKacIKT@)}V(C3dQP_Ccj#*sTl(>M#y3;yP;Zt)02AE^Z)o%GD=GgMJ8g1SpSSTA+0j;o! zQc2rk58MM^hVQ{)I08rEXYdO+4X?o;;BWAE_y_zGE?_dIU@D53j+uB1&cV4j4;P~i z%drCMu@To{6E@>U>_!JFxCK4v!(rTp+wo5PH15THxF7Guui%6Db$kdP#~(_nGq%o_RJY}jmV+Ql0r7J6g7N?nLz$(LSof~+BTW|yC zb`WKmqjKi7>6R>$HJ(GZkY^~{L}uPns@6NlG)pAUkW#d2u4%4FJ|T_Ms`D)iMe;&P z;8jzhWwC*LO-j#!MegVIT_u~WjC43mag^%Jvd<>7^QG61g!XM&K@dbP_%4XL@+ARJ` z&u05QRaKhJg81$A2j70b@+al`{T!FoZ=f$Mvzx-dL5!aaH4VC59(OObGXI(Y4d8`7 zN)``-6{;gs#@)lJ->2Y2z^6_JAW0NW;&^dm6XA}w7gg8?*Rxuq-P_mgzi+05bMW5Y z-O7<^a;3-ZwL59&Uvp@=AVK23FBhK%(VUu)IXMu`5T*f zV+;BOCwM5Y)nek zf(F*xI>VSHrSN!zRcFnn>Np;0ucadiqm;xW7*<_8kE%%F46BqZ zH5#R49?P(*p_HnOQn5;T1wDqj$kiC-gK!YO15Z(SZ~|T?b9@v23LhZgIFyJ`WugVM zFq@2UF6NOTF5rf^99Li|k*iu<&5f}I+pq&W$s`>VB=lk*Cs#fkqF{lMtB>NxC{#Fr zpTW=K=ZIW=6(8Xi7cx12AfQQ!uRIzuxo{}$^!@xLWrRbi-yp+5^9Q${TyStWyfp$I zQ|@Aq_v=LgVc>(Wq?}5f+3WOPaDq30Fzf+AVFbp6-oJB&@L|okcxvBSZCF9w@PX;I zhYt<+bL3A32Y8?d)awn;my{5m7cRX9cpe;Luh1BG48@b>W=u&ehax zYz@nMTuGWm56N|dPaVz>4B(@{y}p5?-^58qV;G3X+jDpf$TtKH+|8MhNfjnFTFg4& z&ih-;(csP%W}Cynol7FXovTKII~PTRI~T@+I~SLk?Q$XIQ%Z3qo>(GH43dw530&GRWE z6p4PEaw*ytN!ufjJdaQ|7>3vJ_6r` zC*c`*o(%FVnc{hP50TP&h ze}0ywsdRgWR_@Y0Bi1mJwpiWgMXhE`GV2DVH2hUeBK}Xr|B3iN;>D#NqYfh{y1B7f z`jCkK*>21B+xSVTMEoCkd!WtL7n&i|ZDpQS;b4uV()wPfxTVB5Ajj87J z%&ZV%PCOC&UQgy;=4Yd{?GJacx9MlSz}Q<-#uM8QK1AL8p!IZJCYc{4-Jwd3!Y+jD z?Lbuf4na{9rJyQ@alB^ zrue>Aj|nF+KYv{=eaq`HgWlbBE^xWZbDVg?B$mlB_-{9bF(kwQF+dDF1Ow(=5pxeQ z8O=cq5Ce~j0X!dUP(;^YsZkvr(5MmsunBG@U}G(TIkrL9V5t#CK)6l?)T!K*7+j}= z-!^fs!BV46XWSGY+^oz^g~HY9Fu$$B8Fw{OOAHVLRR*SXw}tor`@h%!)g1H{0i zVt_Y0UZ)LPGIwijb9mR Date: Sun, 19 Sep 2021 22:07:34 -0500 Subject: [PATCH 30/54] Added version info for sodium and mbedtls Also, fixed "bug" in SRP route (did not impact function - just a generated less random numbers than expected). --- src/HomeSpan.cpp | 6 ++++++ src/SRP.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index c853869..f127a0c 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "HomeSpan.h" #include "HAP.h" @@ -111,6 +112,11 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.printf("\nPWM Resources: %d channels, %d timers, max %d-bit duty resolution", LEDC_SPEED_MODE_MAX*LEDC_CHANNEL_MAX,LEDC_SPEED_MODE_MAX*LEDC_TIMER_MAX,LEDC_TIMER_BIT_MAX-1); + Serial.printf("\nSodium Version: %s Lib %d.%d",sodium_version_string(),sodium_library_version_major(),sodium_library_version_minor()); + char mbtlsv[64]; + mbedtls_version_get_string_full(mbtlsv); + Serial.printf("\nMbedTLS Version: %s",mbtlsv); + Serial.print("\nSketch Compiled: "); Serial.print(__DATE__); Serial.print(" "); diff --git a/src/SRP.cpp b/src/SRP.cpp index d18259a..9fd0f1d 100644 --- a/src/SRP.cpp +++ b/src/SRP.cpp @@ -144,7 +144,7 @@ void SRP6A::createPublicKey(){ void SRP6A::getPrivateKey(){ uint8_t privateKey[32]; - randombytes_buf(privateKey,16); // generate 32 random bytes using libsodium (which uses the ESP32 hardware-based random number generator) + randombytes_buf(privateKey,32); // generate 32 random bytes using libsodium (which uses the ESP32 hardware-based random number generator) mbedtls_mpi_read_binary(&b,privateKey,32); } From 0dd341faa9f76cc8f6755320458f161182892e7f Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 22 Sep 2021 05:31:46 -0500 Subject: [PATCH 31/54] Update HomeSpan.h eliminates -Wpmf-conversion warnings generated by our checks for override of update(), loop(), and button() methods --- src/HomeSpan.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 1c707d0..c7192cd 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -31,6 +31,8 @@ #error ERROR: HOMESPAN IS ONLY AVAILABLE FOR ESP32 MICROCONTROLLERS! #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 + #include #include #include From 07da5ac924c0f9cc5c39db78c9fb27b24a9f557e Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 23 Sep 2021 21:12:37 -0500 Subject: [PATCH 32/54] Updated SRP code for 2.0.0 compatibility Arduino-ESP32 has modified the Mbed TLS library so that it uses ESP32 hardware acceleration. However, there is a 512-byte limit to the size of the variables used in an exponential modulo calculation. One of the steps in the SRP code used a 768-byte variable, which cannot be handled in version 2.0.0 though it works fine in version 1.0.6. Solution was to simply reduce the 768-byte variable by modulo N prior to performing the exponential modulo calculation. --- src/SRP.cpp | 13 +++++++------ src/src.ino | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/SRP.cpp b/src/SRP.cpp index 9fd0f1d..8af05eb 100644 --- a/src/SRP.cpp +++ b/src/SRP.cpp @@ -144,8 +144,8 @@ void SRP6A::createPublicKey(){ void SRP6A::getPrivateKey(){ uint8_t privateKey[32]; + randombytes_buf(privateKey,32); // generate 32 random bytes using libsodium (which uses the ESP32 hardware-based random number generator) - mbedtls_mpi_read_binary(&b,privateKey,32); } @@ -164,10 +164,11 @@ void SRP6A::createSessionKey(){ mbedtls_mpi_read_binary(&u,tHash,64); // load hash result into mpi structure u // compute S = (Av^u)^b %N - + mbedtls_mpi_exp_mod(&t1,&v,&u,&N,&_rr); // t1 = v^u %N mbedtls_mpi_mul_mpi(&t2,&A,&t1); // t2 = A*t1 - mbedtls_mpi_exp_mod(&S,&t2,&b,&N,&_rr); // S = t2^b %N + mbedtls_mpi_mod_mpi(&t1,&t2,&N); // t1 = t2 %N (this is needed to reduce size of t2 before next calculation) + mbedtls_mpi_exp_mod(&S,&t1,&b,&N,&_rr); // S = t1^b %N // compute K = SHA512( S ) @@ -176,7 +177,7 @@ void SRP6A::createSessionKey(){ mbedtls_mpi_read_binary(&K,tHash,64); // load hash result into mpi structure K. This is the SRP SHARED SECRET KEY mbedtls_mpi_write_binary(&K,sharedSecret,64); // store SHARED SECRET in easy-to-use binary (uint8_t) format - + } ////////////////////////////////////// @@ -267,10 +268,10 @@ int SRP6A::writeTLV(kTLVType tag, mbedtls_mpi *mpi){ void SRP6A::print(mbedtls_mpi *mpi){ - char sBuf[1000]; + char sBuf[2000]; size_t sLen; - mbedtls_mpi_write_string(mpi,16,sBuf,1000,&sLen); + mbedtls_mpi_write_string(mpi,16,sBuf,2000,&sLen); Serial.print((sLen-1)/2); // subtract 1 for null-terminator, and then divide by 2 to get number of bytes (e.g. 4F = 2 characters, but represents just one mpi byte) Serial.print(" "); diff --git a/src/src.ino b/src/src.ino index 4e2fd9f..d294292 100644 --- a/src/src.ino +++ b/src/src.ino @@ -8,7 +8,7 @@ void setup() { Serial.begin(115200); - homeSpan.setLogLevel(1); + homeSpan.setLogLevel(2); homeSpan.setStatusPin(5); homeSpan.setControlPin(33); From 5d9fc5ed582ba559af1692d31298fa966a184738 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 25 Sep 2021 13:42:20 -0500 Subject: [PATCH 33/54] Update Extras.md --- docs/Extras.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Extras.md b/docs/Extras.md index 3370af1..ebfe19a 100644 --- a/docs/Extras.md +++ b/docs/Extras.md @@ -14,7 +14,7 @@ Creating an instance of this **class** configures the specified *pin* to output * *pin* - the pin on which the PWM control signal will be output * *level* - sets the initial %duty-cycle of the PWM from from 0 (LED completely off) to 100 (LED fully on). Default=0 (LED initially off) - * *frequency* - sets the PWM frequency, in Hz, from 1-65535. Defaults to 5000 Hz if unspecified, or if set to 0 + * *frequency* - sets the PWM frequency, in Hz, from 1-65535 (ESP32 only) or 5-65535 (ESP32-S2 and ESP32-C3). Defaults to 5000 Hz if unspecified, or if set to 0 The following methods are supported: @@ -24,7 +24,7 @@ Creating an instance of this **class** configures the specified *pin* to output * `int getPin()` - * returns the pin number, or -1 if LedPin was not successfully initialized + * returns the pin number (or -1 if LedPin was not successfully initialized) LedPin also includes a static class function that converts Hue/Saturation/Brightness values (typically used by HomeKit) to Red/Green/Blue values (typically used to control multi-color LEDS). @@ -58,7 +58,7 @@ The *minMicros* parameter must be less than the *maxMicros* parameter, but setti * `int getPin()` - * returns the pin number, or -1 if LedPin was not successfully initialized + * returns the pin number (or -1 if ServoPin was not successfully initialized) A worked example showing how ServoPin can be used to control the Horizontal Tilt of a motorized Window Shade can be found in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → ServoControl*](../Other%20Examples/ServoControl). @@ -70,7 +70,7 @@ The following PWM resources are available: * ESP32-S2: 8 Channels / 4 Timer * ESP32-C3: 6 Channels / 4 Timers -HomeSpan *automatically* allocates Channels and Timers to LedPin and ServoPin objects as they are instantiated. Every pin assigned consumes a single Channel; every *unique* frequency specified among all channels (within the same set, for the ESP32) consumes a single Timer. HomeSpan will conserve resources by re-using the same Timer for all Channels operating at the same frequency. HoneSpan also automatically configures each Timer to support the maximum duty-resolution possible for the frequency specified. +HomeSpan *automatically* allocates Channels and Timers to LedPin and ServoPin objects as they are instantiated. Every pin assigned consumes a single Channel; every *unique* frequency specified among all channels (within the same set, for the ESP32) consumes a single Timer. HomeSpan will conserve resources by re-using the same Timer for all Channels operating at the same frequency. *HomeSpan also automatically configures each Timer to support the maximum duty-resolution possible for the frequency specified.* HomeSpan will report a non-fatal error message to the Arduino Serial Monitor when insufficient Channel or Timer resources prevent the creation of a new LedPin or ServoPin object. Calls to the `set()` method for objects that failed to be properly created are silently ignored. From 0ea762b4a83cfafa663da1591208450650eb677b Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 25 Sep 2021 14:33:32 -0500 Subject: [PATCH 34/54] Added backwards compatibility to PWM to operate in 2.0.0 and 1.0.6 Accounts for new *required* elements of the LEDC channel and timer structures to be set in later versions of the IDF. These elements are not available in earlier versions of the IDF and the program can't be compiled unless ignored. --- src/extras/PwmPin.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index 018437c..e45e873 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -18,7 +18,10 @@ LedC::LedC(uint8_t pin, uint16_t freq){ timerList[nTimer][nMode]->speed_mode=(ledc_mode_t)nMode; timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; timerList[nTimer][nMode]->freq_hz=freq; + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) timerList[nTimer][nMode]->clk_cfg=LEDC_USE_APB_CLK; +#endif int res=LEDC_TIMER_BIT_MAX-1; // find the maximum possible resolution while(getApbFrequency()/(freq*pow(2,res))<1) @@ -37,7 +40,9 @@ LedC::LedC(uint8_t pin, uint16_t freq){ channelList[nChannel][nMode]->channel=(ledc_channel_t)nChannel; channelList[nChannel][nMode]->timer_sel=(ledc_timer_t)nTimer; channelList[nChannel][nMode]->intr_type=LEDC_INTR_DISABLE; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) channelList[nChannel][nMode]->flags.output_invert=0; +#endif channelList[nChannel][nMode]->hpoint=0; channelList[nChannel][nMode]->gpio_num=pin; timer=timerList[nTimer][nMode]; From 50bdfd7d373d4b953e8167523de8a12364b925b4 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 25 Sep 2021 14:41:20 -0500 Subject: [PATCH 35/54] Added better display of IDF Version --- src/HomeSpan.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index f127a0c..a470ef8 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -99,8 +99,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(getSketchVersion()); Serial.print("\nHomeSpan Version: "); Serial.print(HOMESPAN_VERSION); - Serial.print("\nESP-IDF Version: "); - Serial.print(esp_get_idf_version()); + Serial.printf("\nESP-IDF Version: %d.%d.%d",ESP_IDF_VERSION_MAJOR,ESP_IDF_VERSION_MINOR,ESP_IDF_VERSION_PATCH); Serial.printf("\nESP32 Chip: %s Rev %d %s-core %dMB Flash", ESP.getChipModel(),ESP.getChipRevision(), ESP.getChipCores()==1?"single":"dual",ESP.getFlashChipSize()/1024/1024); From 82ad33c98f87a54bea52a775420c8f0b057d5ce2 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 25 Sep 2021 15:58:23 -0500 Subject: [PATCH 36/54] Updated error-check for out-of-range PWM frequency (an ESP32-S2 check) PWM has now been fully tested and verified with an ESP32 device under Arduino-ESP32 versions 1.0.6 and 2.0.0, and with an ESP32-S2 device under Arduino-ESP32 version 2.0.0. Tests confirmed using both high (5000 Hz) and low (1 Hz or 5Hz) frequencies to ensure timers are correctly configured. Next Task: Update RFControl routines for 2.0.0 and ESP32-S2 compatibility. --- src/extras/PwmPin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index e45e873..31609de 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -30,6 +30,8 @@ LedC::LedC(uint8_t pin, uint16_t freq){ timerList[nTimer][nMode]->duty_resolution=(ledc_timer_bit_t)res; if(ledc_timer_config(timerList[nTimer][nMode])!=0){ Serial.printf("\n*** ERROR: Frequency=%d Hz is out of allowed range ---",freq); + delete timerList[nTimer][nMode]; + timerList[nTimer][nMode]=NULL; return; } } From dc5844b520d9210f426dae565da8c289a75bddc1 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 3 Oct 2021 12:08:33 -0500 Subject: [PATCH 37/54] Updated RFControl for compatibility with ESP32-S2 and ESP32-C3 Complete re-write of code. --- src/extras/RFControl.cpp | 95 ++++++++++++++-------------------------- src/extras/RFControl.h | 33 +++++++++----- src/extras/extras.ino | 89 +++++++++++++++++++++++++++++-------- 3 files changed, 124 insertions(+), 93 deletions(-) diff --git a/src/extras/RFControl.cpp b/src/extras/RFControl.cpp index 5990831..81d3c34 100644 --- a/src/extras/RFControl.cpp +++ b/src/extras/RFControl.cpp @@ -7,49 +7,42 @@ /////////////////// -RFControl::RFControl(int pin){ - if(!configured){ // configure RMT peripheral +RFControl::RFControl(uint8_t pin){ - DPORT_REG_SET_BIT(DPORT_PERIP_CLK_EN_REG,1<<9); // enable RMT clock by setting bit 9 - DPORT_REG_CLR_BIT(DPORT_PERIP_RST_EN_REG,1<<9); // set RMT to normal ("un-reset") mode by clearing bit 9 - REG_SET_BIT(RMT_APB_CONF_REG,3); // enables access to RMT memory and enables wraparound mode (though the latter does not seem to be needed to set continuous TX) - REG_WRITE(RMT_INT_ENA_REG,1<pin=pin; - - pinMode(pin,OUTPUT); - REG_WRITE(GPIO_FUNC0_OUT_SEL_CFG_REG+4*pin,87); // set GPIO OUTPUT of pin in GPIO_MATRIX to use RMT Channel-0 Output (=signal 87) - REG_SET_FIELD(GPIO_FUNC0_OUT_SEL_CFG_REG+4*pin,GPIO_FUNC0_OEN_SEL,1); // use GPIO_ENABLE_REG of pin (not RMT) to enable this channel - REG_WRITE(GPIO_ENABLE_W1TC_REG,1<32767 || numTicks<1){ - Serial.print("\n*** ERROR: Request to add RF Control entry with numTicks="); - Serial.print(numTicks); - Serial.print(" is out of allowable range: 1-32767\n\n"); - } else { + uint32_t ticks=nTicks&0x7FFF; - int index=pCount/2; - - if(pCount%2==0) - pRMT[index]=numTicks | (phase?(1<<15):0); // load entry into lower 16 bits of 32-bit memory - else - pRMT[index]=pRMT[index] & 0xFFFF | (numTicks<<16) | (phase?(1<<31):0); // load entry into upper 16 bits of 32-bit memory, preserving lower 16 bits - - pCount++; - } + if(lowWord) + data.push_back(ticks | (phase?(1<<15):0)); + else + data.back()|=ticks<<16 | (phase?(1<<31):0); + lowWord=!lowWord; } /////////////////// -void RFControl::eot_int(void *arg){ - numCycles--; - REG_WRITE(RMT_INT_CLR_REG,~0); // interrupt MUST be cleared first; transmission re-started after (clearing after restart crestes havoc) - if(numCycles) - REG_WRITE(RMT_CH0CONF1_REG,0x0000000D); // use REF_TICK clock; reset xmit and receive memory address to start of channel; re-start transmission -} - -/////////////////// - -boolean RFControl::configured=false; -volatile int RFControl::numCycles; -//int32_t *RFControl::pRMT=(uint32_t *)RMT_CHANNEL_MEM(0); -int RFControl::pCount=0; +uint8_t RFControl::nChannels=0; diff --git a/src/extras/RFControl.h b/src/extras/RFControl.h index 1c26111..7bc2430 100644 --- a/src/extras/RFControl.h +++ b/src/extras/RFControl.h @@ -3,21 +3,30 @@ // RF Control Module // //////////////////////////////////// +#include "driver/rmt.h" +#include + +using std::vector; + class RFControl { private: - int pin; - static volatile int numCycles; - static boolean configured; - static uint32_t *pRMT; - static int pCount; - static void eot_int(void *arg); - + rmt_config_t config; + vector data; + boolean lowWord=true; + static uint8_t nChannels; + public: - RFControl(int pin); // creates transmitter on pin - static void clear(); // clears transmitter memory - static void add(uint16_t onTime, uint16_t offTime); // adds pulse of onTime ticks HIGH followed by offTime ticks LOW - static void phase(uint16_t numTicks, uint8_t phase); // adds either a HIGH phase or LOW phase lasting numTicks ticks - void start(uint8_t _numCycles, uint8_t tickTime=1); // starts transmission of pulses, repeated for numCycles, where each tick in pulse is tickTime microseconds long + RFControl(uint8_t pin); // creates transmitter on pin + + void start(uint32_t *data, int nData, uint8_t nCycles=1, uint8_t tickTime=1); // starts transmission of pulses from specified data pointer, repeated for numCycles, where each tick in pulse is tickTime microseconds long + void start(uint8_t nCycles=1, uint8_t tickTime=1); // starts transmission of pulses from internal data structure, repeated for numCycles, where each tick in pulse is tickTime microseconds long + + void clear(); // clears transmitter memory + void add(uint16_t onTime, uint16_t offTime); // adds pulse of onTime ticks HIGH followed by offTime ticks LOW + void phase(uint16_t nTicks, uint8_t phase); // adds either a HIGH phase or LOW phase lasting numTicks ticks }; +// Helper macro for creating your own storage of uint32_t data array elements - used with first variation of start() above + +#define RF_PULSE(highTicks,lowTicks) (1 << 15 | highTicks | lowTicks << 16) diff --git a/src/extras/extras.ino b/src/extras/extras.ino index c433195..6730da6 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -1,30 +1,83 @@ +/* HomeSpan Remote Control Example */ -// This is a placeholder .ino file that allows you to easily edit the contents of this library using the Arduino IDE, -// as well as compile and test from this point. This file is ignored when the library is included in other sketches. +#include "RFControl.h" // include RF Control Library -#include "PwmPin.h" - -void setup(){ +void setup() { - Serial.begin(115200); - delay(1000); + Serial.begin(115200); // start the Serial interface + Serial.flush(); + delay(1000); // wait for interface to flush - Serial.print("\n\nTest sketch for HomeSpan Extras Library\n\n"); + Serial.print("\n\nHomeSpan RF Transmitter Example\n\n"); - Serial.println("Starting..."); + RFControl rf(17); // create an instance of RFControl with signal output to pin 17 of the ESP32 - LedPin *led[20]; +// rf.phase(1000,HIGH); +// rf.phase(9000,LOW); +// rf.phase(1000,HIGH); +// rf.phase(9000,LOW); +// rf.phase(1000,HIGH); +// rf.phase(30000,LOW); -// uint8_t p[]={33,27,4,32,18,19,16,17,5}; // ESP32 test - uint8_t p[]={11,7,3,1,38,33,9,10}; // ESP32-S2 test +// rf.add(1000,9000); // create a pulse train with three 5000-tick high/low pulses +// rf.add(1000,9000); // create a pulse train with three 5000-tick high/low pulses +// rf.add(1000,9000); // create a pulse train with three 5000-tick high/low pulses +// rf.add(1000,30000); // create a pulse train with three 5000-tick high/low pulses +// +// rf.start(2,100); +// Serial.println("Done"); +// while(1); - for(int i=0;iset(100); + rf.clear(); // clear the pulse train memory buffer - while(1); -} + rf.add(5000,5000); // create a pulse train with three 5000-tick high/low pulses + rf.add(5000,5000); + rf.add(5000,10000); // double duration of final low period + + Serial.print("Starting 4 cycles of three 500 ms on pulses..."); + + rf.start(4,100); // start transmission of 4 cycles of the pulse train with 1 tick=100 microseconds + + Serial.print("Done!\n"); + + delay(2000); + + rf.clear(); + + for(int i=1000;i<10000;i+=1000) + rf.add(i,10000-i); + rf.add(10000,10000); + + Serial.print("Starting 3 cycles of 100-1000 ms pulses..."); + + rf.start(3,100); // start transmission of 3 cycles of the pulse train with 1 tick=100 microseconds + + Serial.print("Done!\n"); + + Serial.print("\nEnd Example"); + +} // end of setup() void loop(){ -} + +} // end of loop() From 79802736094b5298f7850374964ef405bce7cc51 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 3 Oct 2021 18:08:07 -0500 Subject: [PATCH 38/54] Completed update of RFControl for ESP32-S2 and -C3 compatability Testing completed for RFControl and PWM on all three ESP32 chip types. To Do: update RFControl documentation to include total number of usable channels per chip, as well as the alternate version of start(); --- src/extras/RFControl.cpp | 52 +++++++++++++++++++------- src/extras/RFControl.h | 2 +- src/extras/extras.ino | 80 +++++++++------------------------------- 3 files changed, 56 insertions(+), 78 deletions(-) diff --git a/src/extras/RFControl.cpp b/src/extras/RFControl.cpp index 81d3c34..c71c4ce 100644 --- a/src/extras/RFControl.cpp +++ b/src/extras/RFControl.cpp @@ -1,7 +1,6 @@ #include #include -#include #include "RFControl.h" @@ -9,18 +8,40 @@ RFControl::RFControl(uint8_t pin){ -// config=new rmt_config_t; - - config.rmt_mode=RMT_MODE_TX; - config.tx_config.carrier_en=false; - config.channel=RMT_CHANNEL_0; - config.clk_div = 1; - config.mem_block_num=1; - config.gpio_num=(gpio_num_t)pin; +#ifdef CONFIG_IDF_TARGET_ESP32C3 + if(nChannels==RMT_CHANNEL_MAX/2){ +#else + if(nChannels==RMT_CHANNEL_MAX){ +#endif + Serial.printf("\n*** ERROR: Can't create RFControl(%d) - no open channels ***\n\n",pin); + return; + } + + config=new rmt_config_t; + + config->rmt_mode=RMT_MODE_TX; + config->tx_config.carrier_en=false; + config->channel=(rmt_channel_t)nChannels; + config->flags=0; + config->clk_div = 1; + config->mem_block_num=1; + config->gpio_num=(gpio_num_t)pin; + config->tx_config.idle_output_en=false; + config->tx_config.loop_en=false; + + rmt_config(config); + rmt_driver_install(config->channel,0,0); + + // Below we set the base clock to 1 MHz so tick-units are in microseconds (before CLK_DIV) + +#ifdef CONFIG_IDF_TARGET_ESP32C3 + REG_SET_FIELD(RMT_SYS_CONF_REG,RMT_SCLK_DIV_NUM,80); // ESP32-C3 does not have a 1 MHz REF Tick Clock, but allows the 80 MHz APB clock to be scaled by an additional RMT-specific divider +#else + rmt_set_source_clk(config->channel,RMT_BASECLK_REF); // use 1 MHz REF Tick Clock for ESP32 and ESP32-S2 +#endif + + nChannels++; - ESP_ERROR_CHECK(rmt_config(&config)); - ESP_ERROR_CHECK(rmt_driver_install(config.channel,0,0)); - rmt_set_source_clk(RMT_CHANNEL_0,RMT_BASECLK_REF); } /////////////////// @@ -33,10 +54,13 @@ void RFControl::start(uint8_t nCycles, uint8_t tickTime){ // starts transmis void RFControl::start(uint32_t *data, int nData, uint8_t nCycles, uint8_t tickTime){ // starts transmission of pulses from specified data pointer, repeated for nCycles, where each tick in pulse is tickTime microseconds long - rmt_set_clk_div(RMT_CHANNEL_0,tickTime); // set clock divider + if(!config || nData==0) + return; + + rmt_set_clk_div(config->channel,tickTime); // set clock divider for(int i=0;ichannel, (rmt_item32_t *) data, nData, true); // start transmission and wait until completed before returning } /////////////////// diff --git a/src/extras/RFControl.h b/src/extras/RFControl.h index 7bc2430..b840f37 100644 --- a/src/extras/RFControl.h +++ b/src/extras/RFControl.h @@ -10,7 +10,7 @@ using std::vector; class RFControl { private: - rmt_config_t config; + rmt_config_t *config=NULL; vector data; boolean lowWord=true; static uint8_t nChannels; diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 6730da6..86e56d3 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -8,73 +8,27 @@ void setup() { Serial.flush(); delay(1000); // wait for interface to flush - Serial.print("\n\nHomeSpan RF Transmitter Example\n\n"); + Serial.println("\n\nHomeSpan RF Transmitter Example"); - RFControl rf(17); // create an instance of RFControl with signal output to pin 17 of the ESP32 + RFControl rf(19); // create an instance of RFControl with signal output to pin 6 -// rf.phase(1000,HIGH); -// rf.phase(9000,LOW); -// rf.phase(1000,HIGH); -// rf.phase(9000,LOW); -// rf.phase(1000,HIGH); -// rf.phase(30000,LOW); - -// rf.add(1000,9000); // create a pulse train with three 5000-tick high/low pulses -// rf.add(1000,9000); // create a pulse train with three 5000-tick high/low pulses -// rf.add(1000,9000); // create a pulse train with three 5000-tick high/low pulses -// rf.add(1000,30000); // create a pulse train with three 5000-tick high/low pulses -// -// rf.start(2,100); -// Serial.println("Done"); -// while(1); - -// -//#define NPOINTS 3 -// -// uint32_t data[NPOINTS]; -// -// for(int i=0;i Date: Sun, 3 Oct 2021 21:39:23 -0500 Subject: [PATCH 39/54] Update Blinker() to fix inherent problem with digitalRead() in ESP32-C3 Pin must be INPUT_OUTPUT for digitalRead to work with ESP32-C3 (the IDF uses a new protocol for the C3). --- src/Utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Utils.cpp b/src/Utils.cpp index 9417f75..dbeeaab 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -227,6 +227,7 @@ Blinker::Blinker(int pin, int timerNum){ void Blinker::init(int pin, int timerNum){ this->pin=pin; pinMode(pin,OUTPUT); + gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT_OUTPUT); // needed to ensure digitalRead() functions correctly on ESP32-C3 digitalWrite(pin,0); #if SOC_TIMER_GROUP_TIMERS_PER_GROUP>1 // ESP32 and ESP32-S2 contains two timers per timer group From 641e2ca955a7f42b94e46b2f5e225c038bac3b62 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 3 Oct 2021 22:01:37 -0500 Subject: [PATCH 40/54] Added check in RFControl to allow for backwards compatibility with Arduino-ESP 1.0.6 To do: Disable watchdog timer in ESP32-C3 --- src/extras/RFControl.cpp | 2 ++ src/extras/extras.ino | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/extras/RFControl.cpp b/src/extras/RFControl.cpp index c71c4ce..ed89819 100644 --- a/src/extras/RFControl.cpp +++ b/src/extras/RFControl.cpp @@ -22,7 +22,9 @@ RFControl::RFControl(uint8_t pin){ config->rmt_mode=RMT_MODE_TX; config->tx_config.carrier_en=false; config->channel=(rmt_channel_t)nChannels; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) config->flags=0; +#endif config->clk_div = 1; config->mem_block_num=1; config->gpio_num=(gpio_num_t)pin; diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 86e56d3..c709135 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -10,11 +10,8 @@ void setup() { Serial.println("\n\nHomeSpan RF Transmitter Example"); - RFControl rf(19); // create an instance of RFControl with signal output to pin 6 + RFControl rf(18); // create an instance of RFControl with signal output to pin 6 - for(int i=0;i<8;i++) - new RFControl(18); - #define NPOINTS 3 uint32_t data[NPOINTS]; From d82566158a5a6a0980ad2da8bfc6bc4b1cd194de Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 4 Oct 2021 20:39:32 -0500 Subject: [PATCH 41/54] Disabled watchdog timeout messages when running on ESP32-C3 --- src/HomeSpan.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index a470ef8..f33b898 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "HomeSpan.h" #include "HAP.h" @@ -54,6 +55,8 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa this->modelName=modelName; sprintf(this->category,"%d",(int)catID); + esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(0)); // required to avoid watchdog timeout messages from ESP32-C3 + controlButton.init(controlPin); statusLED.init(statusPin); From 0fd9424d79e84c7319a52c17808643600996dfc8 Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 4 Oct 2021 21:14:16 -0500 Subject: [PATCH 42/54] Added Arduino-ESP32 Version Number to initial output --- src/HomeSpan.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index f33b898..51693c5 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "HomeSpan.h" #include "HAP.h" @@ -102,6 +103,8 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(getSketchVersion()); Serial.print("\nHomeSpan Version: "); Serial.print(HOMESPAN_VERSION); + Serial.print("\nArduino Version: "); + Serial.print(STRINGIFY(ARDUINO_ESP32_GIT_DESC)); Serial.printf("\nESP-IDF Version: %d.%d.%d",ESP_IDF_VERSION_MAJOR,ESP_IDF_VERSION_MINOR,ESP_IDF_VERSION_PATCH); Serial.printf("\nESP32 Chip: %s Rev %d %s-core %dMB Flash", ESP.getChipModel(),ESP.getChipRevision(), ESP.getChipCores()==1?"single":"dual",ESP.getFlashChipSize()/1024/1024); From 56c09c44aadeab1fa5e82499cebe3965c42c44c5 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 5 Oct 2021 06:32:19 -0500 Subject: [PATCH 43/54] Updated Blinker again to ensure C3 compatibility moved gpio_set_direction to start() method so that it is called every time needed in case another part of the program (i.e. DEV_Identify) calls pinMode() and resets the pin to a strict OUTPUT. --- src/Utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index dbeeaab..dd97b63 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -227,7 +227,6 @@ Blinker::Blinker(int pin, int timerNum){ void Blinker::init(int pin, int timerNum){ this->pin=pin; pinMode(pin,OUTPUT); - gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT_OUTPUT); // needed to ensure digitalRead() functions correctly on ESP32-C3 digitalWrite(pin,0); #if SOC_TIMER_GROUP_TIMERS_PER_GROUP>1 // ESP32 and ESP32-S2 contains two timers per timer group @@ -323,6 +322,8 @@ void Blinker::start(int period, float dutyCycle){ void Blinker::start(int period, float dutyCycle, int nBlinks, int delayTime){ + gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT_OUTPUT); // needed to ensure digitalRead() functions correctly on ESP32-C3 + period*=10; onTime=dutyCycle*period; offTime=period-onTime; From b95ebcb4fa30e4988e03fb2abbb26b0f56620e5c Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 5 Oct 2021 20:08:34 -0500 Subject: [PATCH 44/54] Added ARDUINO_ESP_VERSION Macro Will be "1.0.6", "2.0.0", etc. Can be used as anywhere as a c-string --- src/HomeSpan.cpp | 5 ++--- src/Settings.h | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 51693c5..54d96c3 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include "HomeSpan.h" #include "HAP.h" @@ -103,8 +102,8 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(getSketchVersion()); Serial.print("\nHomeSpan Version: "); Serial.print(HOMESPAN_VERSION); - Serial.print("\nArduino Version: "); - Serial.print(STRINGIFY(ARDUINO_ESP32_GIT_DESC)); + Serial.print("\nArduino-ESP Ver: "); + Serial.print(ARDUINO_ESP_VERSION); Serial.printf("\nESP-IDF Version: %d.%d.%d",ESP_IDF_VERSION_MAJOR,ESP_IDF_VERSION_MINOR,ESP_IDF_VERSION_PATCH); Serial.printf("\nESP32 Chip: %s Rev %d %s-core %dMB Flash", ESP.getChipModel(),ESP.getChipRevision(), ESP.getChipCores()==1?"single":"dual",ESP.getFlashChipSize()/1024/1024); diff --git a/src/Settings.h b/src/Settings.h index ccf0323..ec240a1 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -27,6 +27,8 @@ // USER-DEFINED SETTINGS AND REFERENCE ENUMERATION CLASSES +#include + #pragma once ////////////////////////////////////////////////////// @@ -49,7 +51,9 @@ #if (REQUIRED>VERSION(HS_MAJOR,HS_MINOR,HS_PATCH)) #error THIS SKETCH REQUIRES A LATER VERISON OF THE HOMESPAN LIBRARY -#endif +#endif + +#define ARDUINO_ESP_VERSION STRINGIFY(ARDUINO_ESP32_GIT_DESC) ////////////////////////////////////////////////////// // DEFAULT SETTINGS // From 6de645216c6ec638fb77eb9b1c02657917fdc7a3 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 5 Oct 2021 21:10:24 -0500 Subject: [PATCH 45/54] CHANGED default settings for StatusPin and ControlPin Re-worked code to allow for NO Status LED Pin and NO Control Pin. If Control Pin is not set explicitly with homeSpan.setControlPin(), there will be no Control Pin. There is no longer a default since there are too many board variations with S2 and C3 chips now supported. Same for Status Pin - it will not be defined unless set explicitly with homeSpan.setStatusPin(), with the exception that if LED_BUILTIN is defined (i.e. there is a built-in LED), then the Status LED Pin will default to LED_BUILTIN if not explicitly defined. MUST UPDATE DOCUMENTATION - THIS CHANGES DEFAULT BEHAVIOR OF HOMESPAN AND MAY REQUIRE UPDATES TO EXISTING SKETCHES --- src/HomeSpan.cpp | 12 +++++++++--- src/HomeSpan.h | 6 +++--- src/Settings.h | 16 ++++++++++------ src/Utils.cpp | 37 +++++++++++++++++++++++++++++++++++-- src/Utils.h | 6 +++--- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 54d96c3..8e53c99 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -95,14 +95,20 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print("Message Logs: Level "); Serial.print(logLevel); Serial.print("\nStatus LED: Pin "); - Serial.print(statusPin); + if(statusPin>=0) + Serial.print(statusPin); + else + Serial.print("- *** WARNING: Status LED Pin is UNDEFINED"); Serial.print("\nDevice Control: Pin "); - Serial.print(controlPin); + if(controlPin>=0) + Serial.print(controlPin); + else + Serial.print("- *** WARNING: Device Control Pin is UNDEFINED"); Serial.print("\nSketch Version: "); Serial.print(getSketchVersion()); Serial.print("\nHomeSpan Version: "); Serial.print(HOMESPAN_VERSION); - Serial.print("\nArduino-ESP Ver: "); + Serial.print("\nArduino-ESP Ver.: "); Serial.print(ARDUINO_ESP_VERSION); Serial.printf("\nESP-IDF Version: %d.%d.%d",ESP_IDF_VERSION_MAJOR,ESP_IDF_VERSION_MINOR,ESP_IDF_VERSION_PATCH); Serial.printf("\nESP32 Chip: %s Rev %d %s-core %dMB Flash", ESP.getChipModel(),ESP.getChipRevision(), diff --git a/src/HomeSpan.h b/src/HomeSpan.h index c7192cd..daafb93 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -118,8 +118,8 @@ struct Span{ unsigned long alarmConnect=0; // time after which WiFi connection attempt should be tried again const char *defaultSetupCode=DEFAULT_SETUP_CODE; // Setup Code used for pairing - uint8_t statusPin=DEFAULT_STATUS_PIN; // pin for status LED - uint8_t controlPin=DEFAULT_CONTROL_PIN; // pin for Control Pushbutton + int statusPin=DEFAULT_STATUS_PIN; // pin for status LED + int controlPin=DEFAULT_CONTROL_PIN; // pin for Control Pushbutton uint8_t logLevel=DEFAULT_LOG_LEVEL; // level for writing out log messages to serial monitor uint8_t maxConnections=DEFAULT_MAX_CONNECTIONS; // number of simultaneous HAP connections unsigned long comModeLife=DEFAULT_COMMAND_TIMEOUT*1000; // length of time (in milliseconds) to keep Command Mode alive before resuming normal operations @@ -171,7 +171,7 @@ struct Span{ void setControlPin(uint8_t pin){controlPin=pin;} // sets Control Pin void setStatusPin(uint8_t pin){statusPin=pin;} // sets Status Pin - int getStatusPin(){return(statusPin);} // gets Status Pin + int getStatusPin(){return(statusPin);} // get Status Pin void setApSSID(const char *ssid){network.apSSID=ssid;} // sets Access Point SSID void setApPassword(const char *pwd){network.apPassword=pwd;} // sets Access Point Password void setApTimeout(uint16_t nSec){network.lifetime=nSec*1000;} // sets Access Point Timeout (seconds) diff --git a/src/Settings.h b/src/Settings.h index ec240a1..bcf1178 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -67,12 +67,17 @@ #define DEFAULT_QR_ID "HSPN" // change with homeSpan.setQRID(qrID); -#define DEFAULT_CONTROL_PIN 21 // change with homeSpan.setControlPin(pin) -#define DEFAULT_STATUS_PIN 13 // change with homeSpan.setStatusPin(pin) +#define DEFAULT_CONTROL_PIN -1 // change with homeSpan.setControlPin(pin) -#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(ssid) -#define DEFAULT_AP_PASSWORD "homespan" // change with homeSpan.setApPassword(pwd) -#define DEFAULT_OTA_PASSWORD "homespan-ota" // change with 'O' command +#ifdef LED_BUILTIN +#define DEFAULT_STATUS_PIN LED_BUILTIN // change with homeSpan.setStatusPin(pin) +#else +#define DEFAULT_STATUS_PIN -1 // change with homeSpan.setStatusPin(pin) +#endif + +#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(ssid) +#define DEFAULT_AP_PASSWORD "homespan" // change with homeSpan.setApPassword(pwd) +#define DEFAULT_OTA_PASSWORD "homespan-ota" // change with 'O' command #define DEFAULT_AP_TIMEOUT 300 // change with homeSpan.setApTimeout(nSeconds) #define DEFAULT_COMMAND_TIMEOUT 120 // change with homeSpan.setCommandTimeout(nSeconds) @@ -82,7 +87,6 @@ #define DEFAULT_MAX_CONNECTIONS 8 // change with homeSpan.setMaxConnections(num); #define DEFAULT_TCP_PORT 80 // change with homeSpan.setPort(port); - ///////////////////////////////////////////////////// // STATUS LED SETTINGS // diff --git a/src/Utils.cpp b/src/Utils.cpp index dd97b63..ea34718 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -89,13 +89,17 @@ PushButton::PushButton(){} ////////////////////////////////////// -PushButton::PushButton(uint8_t pin){ +PushButton::PushButton(int pin){ init(pin); } ////////////////////////////////////// -void PushButton::init(uint8_t pin){ +void PushButton::init(int pin){ + + if(pin<0) + return; + status=0; doubleCheck=false; this->pin=pin; @@ -106,6 +110,9 @@ void PushButton::init(uint8_t pin){ boolean PushButton::triggered(uint16_t singleTime, uint16_t longTime, uint16_t doubleTime){ + if(pin<0) + return(false); + unsigned long cTime=millis(); switch(status){ @@ -182,6 +189,9 @@ boolean PushButton::triggered(uint16_t singleTime, uint16_t longTime, uint16_t d ////////////////////////////////////// boolean PushButton::primed(){ + + if(pin<0) + return(false); if(millis()>singleAlarm && status==1){ status=2; @@ -200,6 +210,10 @@ int PushButton::type(){ ////////////////////////////////////// void PushButton::wait(){ + + if(pin<0) + return; + while(!digitalRead(pin)); } @@ -225,7 +239,11 @@ Blinker::Blinker(int pin, int timerNum){ ////////////////////////////////////// void Blinker::init(int pin, int timerNum){ + this->pin=pin; + if(pin<0) + return; + pinMode(pin,OUTPUT); digitalWrite(pin,0); @@ -322,6 +340,9 @@ void Blinker::start(int period, float dutyCycle){ void Blinker::start(int period, float dutyCycle, int nBlinks, int delayTime){ + if(pin<0) + return; + gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT_OUTPUT); // needed to ensure digitalRead() functions correctly on ESP32-C3 period*=10; @@ -338,12 +359,20 @@ void Blinker::start(int period, float dutyCycle, int nBlinks, int delayTime){ ////////////////////////////////////// void Blinker::stop(){ + + if(pin<0) + return; + timer_pause(group,idx); } ////////////////////////////////////// void Blinker::on(){ + + if(pin<0) + return; + stop(); digitalWrite(pin,1); } @@ -351,6 +380,10 @@ void Blinker::on(){ ////////////////////////////////////// void Blinker::off(){ + + if(pin<0) + return; + stop(); digitalWrite(pin,0); } diff --git a/src/Utils.h b/src/Utils.h index c90a78d..c928054 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -74,7 +74,7 @@ struct TempBuffer { class PushButton{ int status; - uint8_t pin; + int pin; boolean doubleCheck; uint32_t singleAlarm; uint32_t doubleAlarm; @@ -90,7 +90,7 @@ class PushButton{ }; PushButton(); - PushButton(uint8_t pin); + PushButton(int pin); // Creates generic pushbutton functionality on specified pin // that is wired to connect to ground when the button is pressed. @@ -104,7 +104,7 @@ class PushButton{ // // pin: Pin mumber to which pushbutton connects to ground when pressed - void init(uint8_t pin); + void init(int pin); // Initializes PushButton, if not configured during instantiation. // From 8236b6fb9acba0a6dc765491a72b1b8343511a8d Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 5 Oct 2021 21:27:41 -0500 Subject: [PATCH 46/54] Marked old SpanRange() class as [[deprecated]] This will cause a Warning (not an Error) at compile time indicating the class has been deprecated and that the Characteristic::setRange() method should be used instead. Sketch will still run and SpanRange will still function correctly if used. Will delete from code base at some point in the future. --- src/HomeSpan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index daafb93..485fea2 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -501,7 +501,7 @@ struct SpanCharacteristic{ /////////////////////////////// -struct SpanRange{ +struct [[deprecated("Please use Characteristic::setRange() method instead.")]] SpanRange{ SpanRange(int min, int max, int step); }; From b9bf0e32f0bd98e9cd62bf830668fd0630084ea3 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Wed, 6 Oct 2021 06:43:17 -0500 Subject: [PATCH 47/54] Update Extras.md --- docs/Extras.md | 54 ++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/docs/Extras.md b/docs/Extras.md index ebfe19a..0571b3f 100644 --- a/docs/Extras.md +++ b/docs/Extras.md @@ -88,34 +88,52 @@ Signals are defined as a sequence of HIGH and LOW phases that together form a pu ![Pulse Train](images/pulseTrain.png) -Since most RF/IR signals repeat the same train of pulses more than once, the duration of the last LOW phase should be extended to account for the delay between repeats of the pulse train. The following methods are used to construct the pulse train, set the number of repeats, set the duration of a *tick*, and start the transmission: +Since most RF/IR signals repeat the same train of pulses more than once, the duration of the last LOW phase should be extended to account for the delay between repeats of the pulse train. Each instance of RFControl supports a distinct memory buffer to store its own pulse train, subject only to overall limitations of heap memory on the ESP32. The following methods are used to construct a pulse train, set the number of repeats, set the duration of a *tick*, and start the transmission: -* `static void phase(uint16_t numTicks, uint8_t phase)` +* `void phase(uint16_t numTicks, uint8_t phase)` - * appends either a HIGH or LOW phase to the pulse train memory buffer, which has room to store a maximum of 1023 phases. Requests to add more than 1023 phases are ignored, but raise a non-fatal warning message. Note that this is a class-level method as there is only one pulse train memory buffer that is **shared** across all instances of the RFControl object + * appends either a HIGH or LOW phase to the pulse train memory buffer for a specific instance of RFControl - * *numTicks* - the duration, in *ticks* of the pulse phase. Allowable range is 1-32767 ticks. Requests to add a pulse with *numTicks* outside this range are ignored, but raise non-fatal warning message + * *numTicks* - the duration, in *ticks* of the pulse phase. Allowable range is 0-32767 ticks. Requests to add a pulse with *numTicks* outside this range are ignored, but raise non-fatal warning message * *phase* - set to 0 to create a LOW phase; set to 1 (or any non-zero number) to create a HIGH phase * repeated phases of the same type (e.g. HIGH followed by another HIGH) is permitted and result in a single HIGH phase with a duration equal to the sum of the *numTicks* specified for each repeated phase (this is helpful when generating Manchester-encoded signals) -* `static void add(uint16_t onTime, uint16_t offTime)` +* `void add(uint16_t onTime, uint16_t offTime)` - * a convenience function that create a single HIGH/LOW pulse. Implemented as `phase(onTime,HIGH); phase(offTime,LOW);` as defined above, and subject to all the same limits and error-checks + * a convenience function that appends a single HIGH/LOW pulse to the pulse train of a specific instance of RFControl. Implemented as `phase(onTime,HIGH); phase(offTime,LOW);` as defined above -* `static void clear()` +* `void clear()` - * clears the pulse train memory buffer + * clears the pulse train memory buffer of a specific instance of RFControl * `void start(uint8_t _numCycles, uint8_t tickTime)` - * starts the transmission of the pulse train stored in the pulse train memory buffer. The signal will be output on the *pin* specified when RFControl was instantiated. Note this is a blocking call—the method waits until transmission is completed before returning. This should not produce a noticeable delay in program operations since most RF/IR pulse trains are only a few tens-of-milliseconds long + * starts the transmission of the pulse train stored in the pulse train memory buffer for a given instance of RFControl. The signal will be output on the *pin* specified when RFControl was instantiated. Note this is a blocking call—the method waits until transmission is completed before returning. This should not produce a noticeable delay in program operations since most RF/IR pulse trains are only a few tens-of-milliseconds long - * *numCycles* - the total number of times to transmit the pulse train (i.e. a value of 3 means the pulse train will be transmitted once, followed by 2 additional re-transmissions) + * *numCycles* - the total number of times to transmit the pulse train (i.e. a value of 3 means the pulse train will be transmitted once, followed by 2 additional re-transmissions). This is an optional argument with a default of 1 if not specified. * *tickTime* - the duration, in **microseconds**, of a *tick*. This is an optional argument with a default of 1𝛍s if not specified. Valid range is 1-255𝛍s, or set to 0 for 256𝛍s +* `void start(uint32_t *data, int nData, uint8_t nCycles, uint8_t tickTime)` + + * as an alternative to starting the transmission of a pulse train stored in the memory buffer associated with a specific instance of RFControl, this method starts the transmission of a pulse train stored in the memory buffer *data*. This allows the upfront creation and storage of different pulse trains that can be started by simply passing a pointer reference to the appropriate memory buffer + + * *data* - pointer to a memory buffer containing 32-bit *pulses* in the following format: + * bits 0-14: the duration, in *ticks* from 0-32767, of the first part of the pulse to be transmitted + * bit 15: indicates whether the first part of the pulse to be trasnmitted is HIGH (1) or LOW (0) + * bits 16-30: the duration, in *ticks* from 0-32767, of the second part of the pulse to be transmitted + * bit 31: indicates whether the second part of the pulse to be trasnmitted is HIGH (1) or LOW (0) + + * *nData* - the number of data elements (*pulses*) stored in *data* + + * *numCycles* - the total number of times to transmit the pulse train (i.e. a value of 3 means the pulse train will be transmitted once, followed by 2 additional re-transmissions). This is an optional argument with a default of 1 if not specified. + + * *tickTime* - the duration, in **microseconds**, of a *tick*. This is an optional argument with a default of 1𝛍s if not specified. Valid range is 1-255𝛍s, or set to 0 for 256𝛍s + + * To aid in the creation of a pulse-train to be stored in *data*, RFControl includes the macro *RF_PULSE(highTicks,lowTicks)* that returns a properly-formatted uint32_t value defining a single HIGH/LOW pulse of duration highTicks and lowTicks, respectively. This is an analog to the add() method above + Below is a complete sketch that produces two different pulse trains with the signal output linked to the ESP32 device's built-in LED (rather than an RF or IR transmitter). For illustrative purposes the tick duration has been set to a very long 100𝛍s, and pulse times range from of 1000-10,000 ticks, so that the individual pulses are easily discernable on the LED. Note this example sketch is also available in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → RemoteControl*](https://github.com/HomeSpan/HomeSpan/tree/dev/Other%20Examples/RemoteControl). ```C++ @@ -171,20 +189,4 @@ void loop(){ --- -#### Deprecated functions (available for backwards compatibility with older sketches): - -*PwmPin(uint8_t channel, uint8_t pin)* - - * this legacy function was used to generically control the ESP32's built-in PWM generators to drive a dimmable LED and required the user to keep track of individual PWM channels. It has been replaced by two specific (and much easier-to-use) methods: - - * *LedPin(uint8_t pin)* - drives a dimmable LED - - * *ServoPin(uint8_t pin [,double initDegrees [,uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees]])* - drives a Servo Motor - - * last supported version: [v1.2.1](https://github.com/HomeSpan/HomeSpan/blob/release-1.2.1/docs/Extras.md#pwmpinuint8_t-channel-uint8_t-pin) - - * **please use** `LedPin` and `ServoPin` **for all new sketches** - ---- - [↩️](README.md) Back to the Welcome page From 59b21e2f0287f6d4f05288d4f0e7672a70f914d8 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 7 Oct 2021 05:50:34 -0500 Subject: [PATCH 48/54] Update Extras.md --- docs/Extras.md | 60 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/docs/Extras.md b/docs/Extras.md index 0571b3f..245c7c3 100644 --- a/docs/Extras.md +++ b/docs/Extras.md @@ -67,7 +67,7 @@ A worked example showing how ServoPin can be used to control the Horizontal Tilt The following PWM resources are available: * ESP32: 16 Channels / 8 Timers (arranged in two distinct sets of 8 Channels and 4 Timers) -* ESP32-S2: 8 Channels / 4 Timer +* ESP32-S2: 8 Channels / 4 Timers * ESP32-C3: 6 Channels / 4 Timers HomeSpan *automatically* allocates Channels and Timers to LedPin and ServoPin objects as they are instantiated. Every pin assigned consumes a single Channel; every *unique* frequency specified among all channels (within the same set, for the ESP32) consumes a single Timer. HomeSpan will conserve resources by re-using the same Timer for all Channels operating at the same frequency. *HomeSpan also automatically configures each Timer to support the maximum duty-resolution possible for the frequency specified.* @@ -82,13 +82,28 @@ The ESP32 has an on-chip signal-generator peripheral designed to drive an RF or ### *RFControl(int pin)* -Creating an instance of this **class** initializes the RF/IR signal generator and specifies the ESP32 *pin* to output the signal. You may create more than one instance of this class if driving more than one RF/IR transmitter (each connected to different *pin*). +Creating an instance of this **class** initializes the RF/IR signal generator and specifies the ESP32 *pin* to output the signal. You may create more than one instance of this class if driving more than one RF/IR transmitter (each connected to different *pin*), subject to the following limitations: ESP32 - 8 instances; ESP32-S2 - 4 instances; ESP32-C3 - 2 instances. Signals are defined as a sequence of HIGH and LOW phases that together form a pulse train where you specify the duration, in *ticks*, of each HIGH and LOW phase, shown respectively as H1-H4 and L1-L4 in the diagram below. ![Pulse Train](images/pulseTrain.png) -Since most RF/IR signals repeat the same train of pulses more than once, the duration of the last LOW phase should be extended to account for the delay between repeats of the pulse train. Each instance of RFControl supports a distinct memory buffer to store its own pulse train, subject only to overall limitations of heap memory on the ESP32. The following methods are used to construct a pulse train, set the number of repeats, set the duration of a *tick*, and start the transmission: +Since most RF/IR signals repeat the same train of pulses more than once, the duration of the last LOW phase should be extended to account for the delay between repeats of the pulse train. Pulse trains are encoded as sequential arrays of 32-bit words, where each 32-bit word represents an individual pulse using the following protocol: + + * bits 0-14: the duration, in *ticks* from 0-32767, of the first part of the pulse to be transmitted + * bit 15: indicates whether the first part of the pulse to be trasnmitted is HIGH (1) or LOW (0) + * bits 16-30: the duration, in *ticks* from 0-32767, of the second part of the pulse to be transmitted + * bit 31: indicates whether the second part of the pulse to be trasnmitted is HIGH (1) or LOW (0) + +HomeSpan provides two easy methods to create, store, and transmit a pulse train. The first method relies on the fact that each instance of RFControl maintains its own internal memory structure to store a pulse train of arbitrary length. The functions `clear()`, `add()`, and `pulse()`, described below, allow you to create a pulse train using this internal memory structure. The `start()` function is then used to begin transmission of the full pulse train. This method is generally used when pulse trains are to be created on-the-fly as needed, since each RFControl instance can only store a single pulse train at one time. + +In the second method, you create one or more pulse trains in external arrays of 32-bit words using the protocol above. To begin transmission of a specific pulse train, call the `start()` function with a pointer reference to the external array containing that pulse train. This method is generally used when you want to pre-compute many different pulse trains and have them ready-to-transmit as needed. Note that this method requires the array to be stored in RAM, not PSRAM. + +Details of each function are as follows: + +* `void clear()` + + * clears the pulse train memory structure of a specific instance of RFControl * `void phase(uint16_t numTicks, uint8_t phase)` @@ -98,41 +113,38 @@ Since most RF/IR signals repeat the same train of pulses more than once, the dur * *phase* - set to 0 to create a LOW phase; set to 1 (or any non-zero number) to create a HIGH phase - * repeated phases of the same type (e.g. HIGH followed by another HIGH) is permitted and result in a single HIGH phase with a duration equal to the sum of the *numTicks* specified for each repeated phase (this is helpful when generating Manchester-encoded signals) + * repeated phases of the same type (e.g. HIGH followed by another HIGH) are permitted and result in a single HIGH or LOW phase with a duration equal to the sum of the *numTicks* specified for each repeated phase (this is helpful when generating Manchester-encoded signals) * `void add(uint16_t onTime, uint16_t offTime)` - * a convenience function that appends a single HIGH/LOW pulse to the pulse train of a specific instance of RFControl. Implemented as `phase(onTime,HIGH); phase(offTime,LOW);` as defined above - -* `void clear()` - - * clears the pulse train memory buffer of a specific instance of RFControl + * appends a single HIGH/LOW pulse with duration *onTime* followed by *offTime* to the pulse train of a specific instance of RFControl. This is functionally equivalent to calling `phase(onTime,HIGH);` followed by `phase(offTime,LOW);` as defined above * `void start(uint8_t _numCycles, uint8_t tickTime)` +* `void start(uint32_t *data, int nData, uint8_t nCycles, uint8_t tickTime)` - * starts the transmission of the pulse train stored in the pulse train memory buffer for a given instance of RFControl. The signal will be output on the *pin* specified when RFControl was instantiated. Note this is a blocking call—the method waits until transmission is completed before returning. This should not produce a noticeable delay in program operations since most RF/IR pulse trains are only a few tens-of-milliseconds long + * in the first variation, this starts the transmission of the pulse train stored in the internal memory structure of a given instance of RFControl that was created using the `clear()`, `add()`, and `phase()` functions above. In the second variation, this starts the transmission of the pulse train stored in an external array *data* containing *nData* 32-bit words. The signal will be output on the pin specified when RFControl was instantiated. Note this is a blocking call—the method waits until transmission is completed before returning. This should not produce a noticeable delay in program operations since most RF/IR pulse trains are only a few tens-of-milliseconds long * *numCycles* - the total number of times to transmit the pulse train (i.e. a value of 3 means the pulse train will be transmitted once, followed by 2 additional re-transmissions). This is an optional argument with a default of 1 if not specified. * *tickTime* - the duration, in **microseconds**, of a *tick*. This is an optional argument with a default of 1𝛍s if not specified. Valid range is 1-255𝛍s, or set to 0 for 256𝛍s -* `void start(uint32_t *data, int nData, uint8_t nCycles, uint8_t tickTime)` +* To aid in the creation of a pulse train stored in an external array of 32-bit words, RFControl includes the macro *RF_PULSE(highTicks,lowTicks)* that returns a properly-formatted 32-bit value representing a single HIGH/LOW pulse of duration *highTicks* followed by *lowTicks*. This is basically an analog to the `add()` function. For example, the following code snippet shows two ways of creating and transmitting the same 3-pulse pulse-train --- the only difference being that one uses the internal memory structure of RFControl, and the second uses an external array: - * as an alternative to starting the transmission of a pulse train stored in the memory buffer associated with a specific instance of RFControl, this method starts the transmission of a pulse train stored in the memory buffer *data*. This allows the upfront creation and storage of different pulse trains that can be started by simply passing a pointer reference to the appropriate memory buffer - - * *data* - pointer to a memory buffer containing 32-bit *pulses* in the following format: - * bits 0-14: the duration, in *ticks* from 0-32767, of the first part of the pulse to be transmitted - * bit 15: indicates whether the first part of the pulse to be trasnmitted is HIGH (1) or LOW (0) - * bits 16-30: the duration, in *ticks* from 0-32767, of the second part of the pulse to be transmitted - * bit 31: indicates whether the second part of the pulse to be trasnmitted is HIGH (1) or LOW (0) - - * *nData* - the number of data elements (*pulses*) stored in *data* +```C++ - * *numCycles* - the total number of times to transmit the pulse train (i.e. a value of 3 means the pulse train will be transmitted once, followed by 2 additional re-transmissions). This is an optional argument with a default of 1 if not specified. - - * *tickTime* - the duration, in **microseconds**, of a *tick*. This is an optional argument with a default of 1𝛍s if not specified. Valid range is 1-255𝛍s, or set to 0 for 256𝛍s +RFControl rf(11); // create an instance of RFControl - * To aid in the creation of a pulse-train to be stored in *data*, RFControl includes the macro *RF_PULSE(highTicks,lowTicks)* that returns a properly-formatted uint32_t value defining a single HIGH/LOW pulse of duration highTicks and lowTicks, respectively. This is an analog to the add() method above +rf.clear(); // clear the internal memory structure +rf.add(100,50); // create pulse of 100 ticks HIGH followed by 50 ticks LOW +rf.add(100,50); // create a second pulse of 100 ticks HIGH followed by 50 ticks LOW +rf.add(25,500); // create a third pulse of 25 ticks HIGH followed by 500 ticks LOW +rf.start(4,1000); // start transmission of the pulse train; repeat for 4 cycles; one tick = 1000𝛍s + +uint32_t pulseTrain[] = {RF_PULSE(100,50), RF_PULSE(100,50), RF_PULSE(25,500)}; // create the same pulse train in an external array +rf.start(pulseTrain,3,4,1000); // start transmission using the same parameters +``` + +### Example RFControl Sketch Below is a complete sketch that produces two different pulse trains with the signal output linked to the ESP32 device's built-in LED (rather than an RF or IR transmitter). For illustrative purposes the tick duration has been set to a very long 100𝛍s, and pulse times range from of 1000-10,000 ticks, so that the individual pulses are easily discernable on the LED. Note this example sketch is also available in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → RemoteControl*](https://github.com/HomeSpan/HomeSpan/tree/dev/Other%20Examples/RemoteControl). From 7295803dde98a3b3a0597fec5f346984260c00bf Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 8 Oct 2021 05:47:51 -0500 Subject: [PATCH 49/54] Remove LED_BUILTIN as default for statusPin HomeSpan default is that there is NO control button and NO status LED. Must use setStatusPin() or setControlPin() to enable. --- src/Settings.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Settings.h b/src/Settings.h index bcf1178..d8391f0 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -68,12 +68,7 @@ #define DEFAULT_QR_ID "HSPN" // change with homeSpan.setQRID(qrID); #define DEFAULT_CONTROL_PIN -1 // change with homeSpan.setControlPin(pin) - -#ifdef LED_BUILTIN -#define DEFAULT_STATUS_PIN LED_BUILTIN // change with homeSpan.setStatusPin(pin) -#else #define DEFAULT_STATUS_PIN -1 // change with homeSpan.setStatusPin(pin) -#endif #define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(ssid) #define DEFAULT_AP_PASSWORD "homespan" // change with homeSpan.setApPassword(pwd) From 597abfb09736c2825d96e5784013cafa05399beb Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Fri, 8 Oct 2021 06:18:54 -0500 Subject: [PATCH 50/54] Update GettingStarted.md --- docs/GettingStarted.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index aaaaa03..8a945e6 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -48,11 +48,13 @@ Though the device is now programmed and fully operational, it needs to be config In addition to being able to configure a HomeSpan device using the [HomeSpan CLI](CLI.md) via the Arduino Serial Monitor, HomeSpan provides an alternative method for end-users to configure a standalone HomeSpan device that is not connected to a computer. This method requires the installation of two external components: 1. a normally-open single-pole pushbutton to function as the HomeSpan Control Button, and -1. an LED to function as the HomeSpan Status LED. +1. an LED (with a current-limiting resistor) to function as the HomeSpan Status LED. -The Control Button should be installed between the HomeSpan Control Pin on the ESP32 and ground. The HomeSpan Control Pin defaults to pin 21, but can be set to any other pin during HomeSpan initializaton (see the [HomeSpan API Reference](Reference.md) for details). The LED can similarly be connected to any pin you specify, but defaults to pin 13, which for some boards is connected to a built-in LED, thereby saving you the need to install a separate LED. +The Control Button should be installed between ground and any pin on the ESP32 that can serve as an input. To inform HomeSpan of which pin you chose, you must call the method `homeSpan.setControlPin(pin)` near the top of your sketch (see the [HomeSpan API Reference](Reference.md) for details), else HomeSpan will assume a Control Button has **not** be installed. -The use of these two components to configure a standalone HomeSpan device, including starting HomeSpan's temporary WiFi network to configure the device's WiFi Credentials and HomeKit Setup Code, are fully explained in the [HomeSpan User Guide](UserGuide.md). +Similarly, the Status LED can be connected to any pin on the ESP32 that can serve as an output (and grounded through an appropriately-sized current-limiting resistor). To inform HomeSpan of which pin you chose, you must call the method `homeSpan.setStatusPin(pin)` near the top of your sketch, else HomeSpan will assume a Status LED has **not** been installed. Note some ESP32 boards have a built-in LED --- it is fine to use this for the Status LED if it is a simple on/off LED, *not* an addressable color LED that requires a special driver. + +Using the Control Button and Status LED to configure a standalone HomeSpan device, including starting HomeSpan's temporary WiFi network to configure the device's WiFi Credentials and HomeKit Setup Code, is fully explained in the [HomeSpan User Guide](UserGuide.md). ## What Next? From cd08d75d1da5d575719dce33a2e9a69c83683eb0 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Fri, 8 Oct 2021 06:23:03 -0500 Subject: [PATCH 51/54] Update Reference.md --- docs/Reference.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index bfa7bde..5dfc163 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -29,10 +29,13 @@ At runtime HomeSpan will create a global **object** named `homeSpan` that suppor The following **optional** `homeSpan` methods override various HomeSpan initialization parameters used in `begin()`, and therefore **should** be called before `begin()` to take effect. If a method is *not* called, HomeSpan uses the default parameter indicated below: * `void setControlPin(uint8_t pin)` - * sets the ESP32 pin to use for the HomeSpan Control Button (default=21) + * sets the ESP32 pin to use for the HomeSpan Control Button. If not specified, HomeSpan will assume there is no Control Button * `void setStatusPin(uint8_t pin)` - * sets the ESP32 pin to use for the HomeSpan Status LED (default=13). There is also a corresponding `getStatusPin()` method that returns this pin number + * sets the ESP32 pin to use for the HomeSpan Status LED. If not specified, HomeSpan will assume there is no Status LED + +* `int getStatusPin()` +* returns the pin number of the Status LED as set by `setStatusPin(pin)`, or -1 if no pin has been set * `void setApSSID(const char *ssid)` * sets the SSID (network name) of the HomeSpan Setup Access Point (default="HomeSpan-Setup") From 7d6265d5438d82428dc7bd96154755588d71633b Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 9 Oct 2021 08:12:29 -0500 Subject: [PATCH 52/54] Upgrade version number from 1.3.0 to 1.4.0 --- library.properties | 4 ++-- src/Settings.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index 2ac5483..7380088 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=HomeSpan -version=1.3.0 +version=1.4.0 author=Gregg maintainer=Gregg sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE. -paragraph=This library provides a microcontroller-focused implementation of Apple's HomeKit Accessory Protocol (HAP - Release R2) designed specifically for the ESP32 running on the Arduino IDE. HomeSpan pairs directly to iOS Home via WiFi without the need for any external bridges or components. The user can then use the full power of the ESP32's I/O functionality to create custom control software and/or hardware to operate external devices. +paragraph=This library provides a microcontroller-focused implementation of Apple's HomeKit Accessory Protocol (HAP - Release R2) designed specifically for the ESP32 running on the Arduino IDE. HomeSpan pairs directly to iOS Home via WiFi without the need for any external bridges or components. Compatible with ESP32, ESP32-S2, and ESP32-C3. url=https://github.com/HomeSpan/HomeSpan architectures=esp32 includes=HomeSpan.h diff --git a/src/Settings.h b/src/Settings.h index d8391f0..a19545b 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -35,7 +35,7 @@ // HomeSpan Version // #define HS_MAJOR 1 -#define HS_MINOR 3 +#define HS_MINOR 4 #define HS_PATCH 0 #define STRINGIFY(x) _STR(x) From cd00235f6d52d85c6666ced0313da89905fe75fb Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 9 Oct 2021 09:38:43 -0500 Subject: [PATCH 53/54] Update README.md --- docs/README.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/README.md b/docs/README.md index 18c0c45..a7625c1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ Welcome to HomeSpan - a robust and extremely easy-to-use Arduino library for cre HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit Accessory Protocol Specification Release R2 (HAP-R2)](https://developer.apple.com/homekit/specification/) designed specifically for the Espressif ESP32 microcontroller running within the Arduino IDE. HomeSpan pairs directly to HomeKit via your home WiFi network without the need for any external bridges or components. With HomeSpan you can use the full power of the ESP32's I/O functionality to create custom control software and/or hardware to automatically operate external devices from the Home App on your iPhone, iPad, or Mac, or with Siri. -> :exclamation: HomeSpan currently works only under the version 1 series of the Arduino-ESP32 board manager (the latest being version 1.0.6). The new version 2 series (including version 2.0.0 released by Espressif in Sep 2021) is not backwards compatible with version 1.0.6 and breaks HomeSpan. A new version of HomeSpan will be released shortly that is compatible with version 2.0.0 of the Arduino-ESP32 board manager. At this time please use version 1.0.6 of the board manager to compile HomeSpan sketches. +> HomeSpan is fully compatible with both Versions 1 and 2 of the [Arduino-ESP32 Board Manager](https://github.com/espressif/arduino-esp32). Under V1, HomeSpan can be run only on the original ESP32. Under V2, HomeSpan can be run on the original ESP32 as well as Espressif's ESP32-S2 and ESP32-C3 chips. ### HomeSpan Highlights @@ -41,18 +41,24 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A * Launch the WiFi Access Point * A standalone, detailed End-User Guide -## Latest Update - HomeSpan 1.3.0 (6/20/2021) +## Latest Update - HomeSpan 1.4.0 (10/9/2021) -This update brings a number of new features and enhancements: +👍🏻 HomeSpan is now fully compatible with Version 2 of the Arduino-ESP32 Board Manager and will run on Espressif's ESP32-S2 and ESP32-C3 chips, as well as the original ESP32. HomeSpan also maintains full backwards-compatability with Version 1 of the Arduino-ESP Board Manager should you need to revert to that version. - * The PWM library has been— - * upgraded to allow for much easier control of up to 16 dimmable LEDs, ***and*** - * extended with a dedicated class to simultaneously operate up to 8 Servo Motors! - * Characteristic values can be automatically saved in non-volatile storage for retention in the event of a power loss. When power is restored your Accessories will automatically revert to their most recent state! - * The HomeSpan CLI can now be customized — extend the CLI with your own functions and commands! - * Enable the automatic launch of HomeSpan's WiFi Access Point upon start-up whenever WiFi Credentials are not found. - * For advanced users: create your own custom WiFi Access Point and set your WiFi Credentials programmatically. +This update also includes the following additional features and enhancements: + +* The PWM library has been upgraded--- + * to allow the user to specify the PWM frequency of an LedPin() + * to automatically set the duty resolution to the maximum allowable value for a chosen PWM frequency + * to allow the user to set the duty cycle of an LedPin() as a decimal floating number (e.g., 34.56), instead of just an integer + * to optimize the distribution of multiple LedPin() and ServoPin() instances across all available PWM channels +* The RFControl library has been upgraded--- + * to allow for the transmisison of arbitrary-length pulse trains + * to transmit pre-computed pulse trains stored in any standalone array + +* A new method `setValidValues()` has been added to multiple-choice based Characteristics (such as SecuritySystemTargetState) to allow you to restrict which choices can be selected in the Home App + See [Releases](https://github.com/HomeSpan/HomeSpan/releases) for details on all changes included in this update. # HomeSpan Resources From 4698b036cc31d4fe18d90ed1b41ed5bd4b155005 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 9 Oct 2021 15:02:29 -0500 Subject: [PATCH 54/54] Update README.md --- docs/README.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/README.md b/docs/README.md index a7625c1..2c0e18f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ Welcome to HomeSpan - a robust and extremely easy-to-use Arduino library for cre HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit Accessory Protocol Specification Release R2 (HAP-R2)](https://developer.apple.com/homekit/specification/) designed specifically for the Espressif ESP32 microcontroller running within the Arduino IDE. HomeSpan pairs directly to HomeKit via your home WiFi network without the need for any external bridges or components. With HomeSpan you can use the full power of the ESP32's I/O functionality to create custom control software and/or hardware to automatically operate external devices from the Home App on your iPhone, iPad, or Mac, or with Siri. -> HomeSpan is fully compatible with both Versions 1 and 2 of the [Arduino-ESP32 Board Manager](https://github.com/espressif/arduino-esp32). Under V1, HomeSpan can be run only on the original ESP32. Under V2, HomeSpan can be run on the original ESP32 as well as Espressif's ESP32-S2 and ESP32-C3 chips. +HomeSpan is fully compatible with both Versions 1 and 2 of the [Arduino-ESP32 Board Manager](https://github.com/espressif/arduino-esp32). Under Version 1, HomeSpan can be run only on the original ESP32. Under Version 2, HomeSpan can be run on the original ESP32 as well as Espressif's ESP32-S2 and ESP32-C3 chips. ### HomeSpan Highlights @@ -41,23 +41,34 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A * Launch the WiFi Access Point * A standalone, detailed End-User Guide -## Latest Update - HomeSpan 1.4.0 (10/9/2021) +## ❗Latest Update - HomeSpan 1.4.0 (10/9/2021) + +**HomeSpan is now fully compatible with Version 2.0.0 of the Arduino-ESP32 Board Manager and will run on the following Espressif chips:** +* **ESP32** +* **ESP32-S2** +* **ESP32-C3** -👍🏻 HomeSpan is now fully compatible with Version 2 of the Arduino-ESP32 Board Manager and will run on Espressif's ESP32-S2 and ESP32-C3 chips, as well as the original ESP32. HomeSpan also maintains full backwards-compatability with Version 1 of the Arduino-ESP Board Manager should you need to revert to that version. +HomeSpan also maintains full backwards-compatability with Version 1.0.6 of the Arduino-ESP Board Manager should you need to revert to that version. This has been a complicated update! Please report any bugs or issues found when using Version 2 of the Arduino-ESP32. -This update also includes the following additional features and enhancements: +Also included in HomeSpan 1.4.0 are the following new features and enhancements: -* The PWM library has been upgraded--- - * to allow the user to specify the PWM frequency of an LedPin() - * to automatically set the duty resolution to the maximum allowable value for a chosen PWM frequency - * to allow the user to set the duty cycle of an LedPin() as a decimal floating number (e.g., 34.56), instead of just an integer - * to optimize the distribution of multiple LedPin() and ServoPin() instances across all available PWM channels +* **The PWM library has been upgraded** + * users can specify a custom PWM frequency for each instance of LedPin() (subject to chip-specific resource limitations) + * users can set the duty cycle of an LedPin() as a decimal floating number (e.g., 34.56), instead of just an integer + * the library automatically sets the duty resolution to the maximum allowable value for a chosen PWM frequency + * the library optimzizes the distribution of multiple LedPin() and ServoPin() instances to ensure all available PWM channels are used -* The RFControl library has been upgraded--- - * to allow for the transmisison of arbitrary-length pulse trains - * to transmit pre-computed pulse trains stored in any standalone array +* **The RFControl library has been upgraded** + * the library allows for the transmisison of arbitrary-length pulse trains + * users can pre-load pulse trains into one or more arbitrary-length arrays of 32-bit words for on-demand transmission as needed -* A new method `setValidValues()` has been added to multiple-choice based Characteristics (such as SecuritySystemTargetState) to allow you to restrict which choices can be selected in the Home App +* Users can now **limit the selection choices** of certain Characteristics (such as the Target State for a Security System) in the Home App using a new method, `setValidValues()` + +* **The Status LED and Control Button are now optional components that are ignored unless specifically enabled** + * because HomeSpan now runs on chips with many different pin configurations, HomeSpan's use of preset pin numbers for the Status LED and Control Button is likely to conflict with many devices + * the default behavior for HomeSpan has been changed to ignore all logic related to the Status LED and Control Button + * to enable the Status LED you must specify the pin to which your LED is attached using the usual method `homeSpan.setStatusPin(pin)` + * to enable the Control Button you must specify the pin to which your Control Button is attached using the usual method `homeSpan.setControlPin(pin)` See [Releases](https://github.com/HomeSpan/HomeSpan/releases) for details on all changes included in this update.