Browse Source

fix Update button protection (prevent double click #527)

optimized scheduler #515 (thx @beegee3)
pull/558/head
lumapu 2 years ago
parent
commit
ed16cff06e
  1. 4
      src/CHANGES.md
  2. 4
      src/app.h
  3. 2
      src/appInterface.h
  4. 2
      src/defines.h
  5. 119
      src/utils/scheduler.h
  6. 7
      src/web/RestApi.h
  7. 12
      src/web/html/update.html

4
src/CHANGES.md

@ -1,5 +1,9 @@
# Changelog # Changelog
## 0.5.63
* fix Update button protection (prevent double click #527)
* optimized scheduler #515 (thx @beegee3)
## 0.5.62 ## 0.5.62
* fix MQTT `status` update * fix MQTT `status` update
* removed MQTT `available_text` (can be deducted from `available`) * removed MQTT `available_text` (can be deducted from `available`)

4
src/app.h

@ -155,8 +155,8 @@ class app : public IApp, public ah::Scheduler {
return mApi.getTimezoneOffset(); return mApi.getTimezoneOffset();
} }
void getSchedulerInfo(uint16_t *everyMax, uint16_t *atMax) { void getSchedulerInfo(uint8_t *max) {
return getStat(everyMax, atMax); return getStat(max);
} }
void setTimestamp(uint32_t newTime) { void setTimestamp(uint32_t newTime) {

2
src/appInterface.h

@ -28,7 +28,7 @@ class IApp {
virtual void setTimestamp(uint32_t newTime) = 0; virtual void setTimestamp(uint32_t newTime) = 0;
virtual String getTimeStr(uint32_t offset) = 0; virtual String getTimeStr(uint32_t offset) = 0;
virtual uint32_t getTimezoneOffset() = 0; virtual uint32_t getTimezoneOffset() = 0;
virtual void getSchedulerInfo(uint16_t *everyMax, uint16_t *atMax); virtual void getSchedulerInfo(uint8_t *max) = 0;
virtual bool getRebootRequestState() = 0; virtual bool getRebootRequestState() = 0;
virtual bool getSettingsValid() = 0; virtual bool getSettingsValid() = 0;

2
src/defines.h

@ -13,7 +13,7 @@
//------------------------------------- //-------------------------------------
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 5 #define VERSION_MINOR 5
#define VERSION_PATCH 62 #define VERSION_PATCH 63
//------------------------------------- //-------------------------------------
typedef struct { typedef struct {

119
src/utils/scheduler.h

@ -8,7 +8,6 @@
#define __SCHEDULER_H__ #define __SCHEDULER_H__
#include <functional> #include <functional>
#include "llist.h"
#include "dbg.h" #include "dbg.h"
namespace ah { namespace ah {
@ -16,24 +15,17 @@ namespace ah {
enum {SCD_SEC = 1, SCD_MIN = 60, SCD_HOUR = 3600, SCD_12H = 43200, SCD_DAY = 86400}; enum {SCD_SEC = 1, SCD_MIN = 60, SCD_HOUR = 3600, SCD_12H = 43200, SCD_DAY = 86400};
struct scdEvry_s { struct sP {
scdCb c; scdCb c;
uint32_t timeout; uint32_t timeout;
uint32_t reload; uint32_t reload;
scdEvry_s() : c(NULL), timeout(0), reload(0) {} bool isTimestamp;
scdEvry_s(scdCb a, uint32_t tmt, uint32_t rl) : c(a), timeout(tmt), reload(rl) {} sP() : c(NULL), timeout(0), reload(0), isTimestamp(false) {}
sP(scdCb a, uint32_t tmt, uint32_t rl, bool its) : c(a), timeout(tmt), reload(rl), isTimestamp(its) {}
}; };
struct scdAt_s { #define MAX_NUM_TICKER 30
scdCb c;
uint32_t timestamp;
scdAt_s() : c(NULL), timestamp(0) {}
scdAt_s(scdCb a, uint32_t ts) : c(a), timestamp(ts) {}
};
typedef node_s<scdEvry_s, scdCb, uint32_t, uint32_t> sP;
typedef node_s<scdAt_s, scdCb, uint32_t> sPAt;
class Scheduler { class Scheduler {
public: public:
Scheduler() {} Scheduler() {}
@ -41,7 +33,10 @@ namespace ah {
void setup() { void setup() {
mUptime = 0; mUptime = 0;
mTimestamp = 0; mTimestamp = 0;
mMax = 0;
mPrevMillis = millis(); mPrevMillis = millis();
for (uint8_t i = 0; i < MAX_NUM_TICKER; i++)
mTickerInUse[i] = false;
} }
void loop(void) { void loop(void) {
@ -66,37 +61,29 @@ namespace ah {
mUptime += mDiffSeconds; mUptime += mDiffSeconds;
if(0 != mTimestamp) if(0 != mTimestamp)
mTimestamp += mDiffSeconds; mTimestamp += mDiffSeconds;
checkEvery(); checkTicker();
checkAt();
} }
void once(scdCb c, uint32_t timeout) { mStack.add(c, timeout, 0); } void once(scdCb c, uint32_t timeout) { addTicker(c, timeout, 0, false); }
void onceAt(scdCb c, uint32_t timestamp) { mStackAt.add(c, timestamp); } void onceAt(scdCb c, uint32_t timestamp) { addTicker(c, timestamp, 0, true); }
uint8_t every(scdCb c, uint32_t interval){ return mStack.add(c, interval, interval)->id; } uint8_t every(scdCb c, uint32_t interval){ return addTicker(c, interval, interval, false); }
void everySec(scdCb c) { mStack.add(c, SCD_SEC, SCD_SEC); } void everySec(scdCb c) { every(c, SCD_SEC); }
void everyMin(scdCb c) { mStack.add(c, SCD_MIN, SCD_MIN); } void everyMin(scdCb c) { every(c, SCD_MIN); }
void everyHour(scdCb c) { mStack.add(c, SCD_HOUR, SCD_HOUR); } void everyHour(scdCb c) { every(c, SCD_HOUR); }
void every12h(scdCb c) { mStack.add(c, SCD_12H, SCD_12H); } void every12h(scdCb c) { every(c, SCD_12H); }
void everyDay(scdCb c) { mStack.add(c, SCD_DAY, SCD_DAY); } void everyDay(scdCb c) { every(c, SCD_DAY); }
virtual void setTimestamp(uint32_t ts) { virtual void setTimestamp(uint32_t ts) {
mTimestamp = ts; mTimestamp = ts;
} }
bool resetEveryById(uint8_t id) { bool resetEveryById(uint8_t id) {
sP *p = mStack.getFront(); if (mTickerInUse[id] == false)
while(NULL != p) { return false;
if(p->id == id) mTicker[id].timeout = mTicker[id].reload;
break; return true;
p = mStack.get(p);
}
if(NULL != p) {
p->d.timeout = p->d.reload;
return true;
}
return false;
} }
uint32_t getUptime(void) { uint32_t getUptime(void) {
@ -107,53 +94,57 @@ namespace ah {
return mTimestamp; return mTimestamp;
} }
void getStat(uint16_t *everyMax, uint16_t *atMax) { void getStat(uint8_t *max) {
*everyMax = mStack.getMaxFill(); *max = mMax;
*atMax = mStackAt.getMaxFill();
} }
protected: protected:
uint32_t mTimestamp; uint32_t mTimestamp;
private: private:
inline void checkEvery(void) { inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp) {
sP *p = mStack.getFront(); for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) {
while(NULL != p) { if (!mTickerInUse[i]) {
if(mDiffSeconds >= p->d.timeout) { // expired mTickerInUse[i] = true;
(p->d.c)(); mTicker[i].c = c;
yield(); mTicker[i].timeout = timeout;
if(0 == p->d.reload) mTicker[i].reload = reload;
p = mStack.rem(p); mTicker[i].isTimestamp = isTimestamp;
else { if(mMax == i)
p->d.timeout = p->d.reload; mMax = i + 1;
p = mStack.get(p); return i;
}
}
else { // not expired
p->d.timeout -= mDiffSeconds;
p = mStack.get(p);
} }
} }
return 0xff;
} }
inline void checkAt(void) { inline void checkTicker(void) {
sPAt *p = mStackAt.getFront(); bool inUse[MAX_NUM_TICKER];
while(NULL != p) { for (uint8_t i = 0; i < MAX_NUM_TICKER; i++)
if((p->d.timestamp) <= mTimestamp) { inUse[i] = mTickerInUse[i];
(p->d.c)(); for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) {
yield(); if (inUse[i]) {
p = mStackAt.rem(p); if (mTicker[i].timeout <= ((mTicker[i].isTimestamp) ? mTimestamp : mDiffSeconds)) { // expired
if(0 == mTicker[i].reload)
mTickerInUse[i] = false;
else
mTicker[i].timeout = mTicker[i].reload;
(mTicker[i].c)();
yield();
}
else // not expired
if (!mTicker[i].isTimestamp)
mTicker[i].timeout -= mDiffSeconds;
} }
else
p = mStackAt.get(p);
} }
} }
llist<20, scdEvry_s, scdCb, uint32_t, uint32_t> mStack; sP mTicker[MAX_NUM_TICKER];
llist<10, scdAt_s, scdCb, uint32_t> mStackAt; bool mTickerInUse[MAX_NUM_TICKER];
uint32_t mMillis, mPrevMillis, mDiff; uint32_t mMillis, mPrevMillis, mDiff;
uint32_t mUptime; uint32_t mUptime;
uint8_t mDiffSeconds; uint8_t mDiffSeconds;
uint8_t mMax;
}; };
} }

7
src/web/RestApi.h

@ -201,10 +201,9 @@ class RestApi {
//obj[F("littlefs_total")] = LittleFS.totalBytes(); //obj[F("littlefs_total")] = LittleFS.totalBytes();
//obj[F("littlefs_used")] = LittleFS.usedBytes(); //obj[F("littlefs_used")] = LittleFS.usedBytes();
uint16_t evry, at; uint8_t max;
mApp->getSchedulerInfo(&evry, &at); mApp->getSchedulerInfo(&max);
obj[F("schEvryMax")] = evry; obj[F("schMax")] = max;
obj[F("schAtMax")] = at;
} }
void getHtmlSystem(JsonObject obj) { void getHtmlSystem(JsonObject obj) {

12
src/web/html/update.html

@ -19,9 +19,11 @@
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
<form method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8"> <form id="form" method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
<input type="file" name="update"><input type="submit" value="Update"> <input type="file" name="update">
<input type="button" class="btn" value="Update" onclick="hide()">
</form> </form>
</div> </div>
</div> </div>
<div id="footer"> <div id="footer">
@ -54,6 +56,12 @@
} }
} }
function hide() {
document.getElementById("form").submit();
var e = document.getElementById("content");
e.replaceChildren(span("update started"));
}
getAjax("/api/index", parse); getAjax("/api/index", parse);
</script> </script>
</body> </body>

Loading…
Cancel
Save