Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kriegsman <kriegsman@tr.org>2014-12-09 09:35:32 +0300
committerMark Kriegsman <kriegsman@tr.org>2014-12-09 09:35:32 +0300
commitf97e22c5915948d5bfd14a95f5bf804ac0e1ce77 (patch)
treebfe28ae27d621981661ed4cbcf31cf16aed96162
parent4d9c0c60d09e5e9256f8a16bbb62ed5bea295a85 (diff)
Added EVERY_N_SECONDS and several variations. Some of it is preprocessor macros instead of templates because of C++03 template rules (which have subsequently been relaxed in C++11).
-rw-r--r--lib8tion.cpp3
-rw-r--r--lib8tion.h167
2 files changed, 167 insertions, 3 deletions
diff --git a/lib8tion.cpp b/lib8tion.cpp
index 557fa005..84bcafdb 100644
--- a/lib8tion.cpp
+++ b/lib8tion.cpp
@@ -121,6 +121,9 @@ void * memmove8 ( void * dst, void* src, uint16_t num )
#endif /* AVR */
+
+
+
#if 0
// TEST / VERIFICATION CODE ONLY BELOW THIS POINT
#include <Arduino.h>
diff --git a/lib8tion.h b/lib8tion.h
index 957f481c..bef1cb70 100644
--- a/lib8tion.h
+++ b/lib8tion.h
@@ -1815,10 +1815,10 @@ typedef q<uint16_t, 12,4> q124;
#if defined(ARDUINO) && !defined(USE_GET_MILLISECOND_TIMER)
// Forward declaration of Arduino function 'millis'.
uint32_t millis();
-#define GET_MILLIS (millis())
+#define GET_MILLIS millis
#else
uint32_t get_millisecond_timer();
-#define GET_MILLIS (get_millisecond_timer())
+#define GET_MILLIS get_millisecond_timer
#endif
// beat16 generates a 16-bit 'sawtooth' wave at a given BPM,
@@ -1836,7 +1836,7 @@ LIB8STATIC uint16_t beat88( accum88 beats_per_minute_88, uint32_t timebase = 0)
// The ratio 65536:60000 is 279.620266667:256; we'll call it 280:256.
// The conversion is accurate to about 0.05%, more or less,
// e.g. if you ask for "120 BPM", you'll get about "119.93".
- return (((GET_MILLIS) - timebase) * beats_per_minute_88 * 280) >> 16;
+ return (((GET_MILLIS()) - timebase) * beats_per_minute_88 * 280) >> 16;
}
// beat16 generates a 16-bit 'sawtooth' wave at a given BPM
@@ -1897,4 +1897,165 @@ LIB8STATIC uint8_t beatsin8( accum88 beats_per_minute, uint8_t lowest = 0, uint8
}
+// seconds16, minutes16, hours8
+// functions to return the current seconds, minutes, or hours
+// since boot time, in the specified width. Used as part of
+// the "every N time-periods" mechanism.
+
+LIB8STATIC uint16_t seconds16()
+{
+ uint32_t ms = GET_MILLIS();
+ uint16_t s16;
+ s16 = ms / 1000;
+ return s16;
+}
+
+LIB8STATIC uint16_t minutes16()
+{
+ uint32_t ms = GET_MILLIS();
+ uint16_t m16;
+ m16 = (ms / (60000L)) & 0xFFFF;
+ return m16;
+}
+
+LIB8STATIC uint8_t hours8()
+{
+ uint32_t ms = GET_MILLIS();
+ uint8_t h8;
+ h8 = (ms / (3600000L)) & 0xFF;
+ return h8;
+}
+
+
+// Helper routine to divide a 32-bit value by 1024, returning
+// only the low 16 bits. You'd think this would be just
+// result = (in32 >> 10) & 0xFFFF;
+// and on ARM, that's what you want and all is well.
+// But on AVR that code turns into a loop that executes
+// a four-byte shift ten times: 40 shifts in all, plus loop
+// overhead. This routine gets exactly the same result with
+// just six shifts (vs 40), and no loop overhead.
+// Used to convert millis to 'binary seconds' aka bseconds:
+// one bsecond == 1024 millis.
+LIB8STATIC uint16_t div1024_32_16( uint32_t in32)
+{
+ uint16_t out16;
+#if defined(__AVR__)
+ asm volatile (
+ " lsr %D[in] \n\t"
+ " ror %C[in] \n\t"
+ " ror %B[in] \n\t"
+ " lsr %D[in] \n\t"
+ " ror %C[in] \n\t"
+ " ror %B[in] \n\t"
+ " mov %B[out],%C[in] \n\t"
+ " mov %A[out],%B[in] \n\t"
+ : [in] "+r" (in32),
+ [out] "=r" (out16)
+ );
+#else
+ out16 = (in32 >> 10) & 0xFFFF;
+#endif
+ return out16;
+}
+
+// bseconds16 returns the current time-since-boot in
+// "binary seconds", which are actually 1024/1000 of a
+// second long.
+LIB8STATIC uint16_t bseconds16()
+{
+ uint32_t ms = GET_MILLIS();
+ uint16_t s16;
+ s16 = div1024_32_16( ms);
+ return s16;
+}
+
+
+// Classes to implement "Every N Milliseconds", "Every N Seconds",
+// "Every N Minutes", "Every N Hours", and "Every N BSeconds".
+#if 1
+#define INSTANTIATE_EVERY_N_TIME_PERIODS(NAME,TIMETYPE,TIMEGETTER) \
+class NAME { \
+public: \
+ TIMETYPE mPrevTrigger; \
+ TIMETYPE mPeriod; \
+ \
+ NAME() { reset(); mPeriod = 1; }; \
+ NAME(TIMETYPE period) { reset(); setPeriod(period); }; \
+ void setPeriod( TIMETYPE period) { mPeriod = period; }; \
+ TIMETYPE getTime() { return (TIMETYPE)(TIMEGETTER()); }; \
+ TIMETYPE getPeriod() { return mPeriod; }; \
+ TIMETYPE getElapsed() { return getTime() - mPrevTrigger; } \
+ TIMETYPE getRemaining() { return mPeriod - getElapsed(); } \
+ TIMETYPE getLastTriggerTime() { return mPrevTrigger; } \
+ bool ready() { \
+ bool isReady = (getElapsed() >= mPeriod); \
+ if( isReady ) { reset(); } \
+ return isReady; \
+ } \
+ void reset() { mPrevTrigger = getTime(); }; \
+ void trigger() { mPrevTrigger = getTime() - mPeriod; }; \
+ \
+ operator bool() { return ready(); } \
+};
+INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNMillis,uint32_t,GET_MILLIS);
+INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNSeconds,uint16_t,seconds16);
+INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNBSeconds,uint16_t,bseconds16);
+INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNMinutes,uint16_t,minutes16);
+INSTANTIATE_EVERY_N_TIME_PERIODS(CEveryNHours,uint8_t,hours8);
+#else
+
+// Under C++11 rules, we would be allowed to use not-external
+// -linkage-type symbols as template arguments,
+// e.g., LIB8STATIC seconds16, and we'd be able to use these
+// templates as shown below.
+// However, under C++03 rules, we cannot do that, and thus we
+// have to resort to the preprocessor to 'instantiate' 'templates',
+// as handled above.
+template<typename timeType,timeType (*timeGetter)()>
+class CEveryNTimePeriods {
+public:
+ timeType mPrevTrigger;
+ timeType mPeriod;
+
+ CEveryNTimePeriods() { reset(); mPeriod = 1; };
+ CEveryNTimePeriods(timeType period) { reset(); setPeriod(period); };
+ void setPeriod( timeType period) { mPeriod = period; };
+ timeType getTime() { return (timeType)(timeGetter()); };
+ timeType getPeriod() { return mPeriod; };
+ timeType getElapsed() { return getTime() - mPrevTrigger; }
+ timeType getRemaining() { return mPeriod - getElapsed(); }
+ timeType getLastTriggerTime() { return mPrevTrigger; }
+ bool ready() {
+ bool isReady = (getElapsed() >= mPeriod);
+ if( isReady ) { reset(); }
+ return isReady;
+ }
+ void reset() { mPrevTrigger = getTime(); };
+ void trigger() { mPrevTrigger = getTime() - mPeriod; };
+
+ operator bool() { return ready(); }
+};
+typedef CEveryNTimePeriods<uint16_t,seconds16> CEveryNSeconds;
+typedef CEveryNTimePeriods<uint16_t,bseconds16> CEveryNBSeconds;
+typedef CEveryNTimePeriods<uint32_t,millis> CEveryNMillis;
+typedef CEveryNTimePeriods<uint16_t,minutes16> CEveryNMinutes;
+typedef CEveryNTimePeriods<uint8_t,hours8> CEveryNHours;
+#endif
+
+
+#define CONCAT_HELPER( x, y ) x##y
+#define CONCAT_MACRO( x, y ) CONCAT_HELPER( x, y )
+#define EVERY_N_MILLIS(N) EVERY_N_MILLIS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
+#define EVERY_N_MILLIS_I(NAME,N) static CEveryNMillis NAME(N); if( NAME )
+#define EVERY_N_SECONDS(N) EVERY_N_SECONDS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
+#define EVERY_N_SECONDS_I(NAME,N) static CEveryNSeconds NAME(N); if( NAME )
+#define EVERY_N_BSECONDS(N) EVERY_N_BSECONDS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
+#define EVERY_N_BSECONDS_I(NAME,N) static CEveryNBSeconds NAME(N); if( NAME )
+#define EVERY_N_MINUTES(N) EVERY_N_MINUTES_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
+#define EVERY_N_MINUTES_I(NAME,N) static CEveryNMinutes NAME(N); if( NAME )
+#define EVERY_N_HOURS(N) EVERY_N_HOURS_I(CONCAT_MACRO(PER, __COUNTER__ ),N)
+#define EVERY_N_HOURS_I(NAME,N) static CEveryNHours NAME(N); if( NAME )
+
+
#endif