|
@@ -13,92 +13,92 @@ I2C i2c(PA_10, PA_9);
|
|
|
bool RtcTick, RefreshTick, RngTick;
|
|
|
|
|
|
typedef enum {
|
|
|
- Idle = 0,
|
|
|
+ Decrementing = 0,
|
|
|
Incrementing = 1,
|
|
|
- Decrementing = 2,
|
|
|
} DigitState;
|
|
|
|
|
|
typedef struct {
|
|
|
DigitState CurrentState;
|
|
|
int Value;
|
|
|
- int Brightness;
|
|
|
- int Step;
|
|
|
bool Updated;
|
|
|
} Digit;
|
|
|
|
|
|
typedef struct {
|
|
|
Digit Digits[10];
|
|
|
bool Refresh;
|
|
|
- int UpdateRate;
|
|
|
+ int FadeDuration;
|
|
|
} Tube;
|
|
|
|
|
|
Tube Tubes[4];
|
|
|
Digit Dot;
|
|
|
|
|
|
-Ticker RuntimeUpdateTicker, RngUpdateTicker;
|
|
|
-int RuntimeTickerIter, RngTickerIter;
|
|
|
-
|
|
|
-void RtcTickCallback(void) {
|
|
|
- RtcTick = true;
|
|
|
-}
|
|
|
-
|
|
|
-void RefreshTickCallback(void) {
|
|
|
- RefreshTick = true;
|
|
|
-}
|
|
|
-
|
|
|
-void RngTickCallback(void) {
|
|
|
- RngTick = true;
|
|
|
-}
|
|
|
-
|
|
|
-Timeout DotUpdateTick;
|
|
|
+Timeout DotUpdateTimeout;
|
|
|
void DotUpdateCallback(void) {
|
|
|
- if (Dot.CurrentState == Incrementing && Dot.Brightness < PCA9685_Max_Brightness) {
|
|
|
- Dot.Brightness += Dot.Step;
|
|
|
- } else if (Dot.CurrentState == Decrementing && Dot.Brightness > PCA9685_Min_Brightness) {
|
|
|
- Dot.Brightness -= Dot.Step;
|
|
|
+ if (Dot.CurrentState == Incrementing && Dot.Value < DOT_MAX) {
|
|
|
+ Dot.Value = (Dot.Value + DOT_FADE_STEP >= DOT_MAX) ? DOT_MAX : Dot.Value + DOT_FADE_STEP;
|
|
|
+ } else if (Dot.CurrentState == Decrementing && Dot.Value > DOT_MIN) {
|
|
|
+ Dot.Value = (Dot.Value - DOT_FADE_STEP <= DOT_MIN) ? DOT_MIN : Dot.Value - DOT_FADE_STEP;
|
|
|
}
|
|
|
Dot.Updated = true;
|
|
|
|
|
|
- if (Dot.Brightness == PCA9685_Max_Brightness ||
|
|
|
- Dot.Brightness == PCA9685_Min_Brightness) {
|
|
|
- DotUpdateTick.detach();
|
|
|
- } else {
|
|
|
-
|
|
|
- DotUpdateTick.attach_us(DotUpdateCallback, 700);
|
|
|
- }
|
|
|
+ if (Dot.Value != DOT_MAX && Dot.Value != DOT_MIN) {
|
|
|
+ DotUpdateTimeout.attach_us(DotUpdateCallback, DOT_FADE_DURATION_US / REFRESH_RATE_US);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void Tube0UpdateCallback(void) {
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+#define TUBE_CALLBACK(x) \
|
|
|
+void Tube##x##UpdateCallback(void) { \
|
|
|
+ int step = (DOT_MAX + (Tubes[x].FadeDuration / REFRESH_RATE_US) - 1) / (Tubes[x].FadeDuration / REFRESH_RATE_US); \
|
|
|
+ bool activeTube = false; \
|
|
|
+ for (int i = 0; i < 10; i++) { \
|
|
|
+ Digit *digit = &Tubes[x].Digits[i]; \
|
|
|
+ if (digit->CurrentState == Incrementing && digit->Value < DIGIT_MAX) { \
|
|
|
+ digit->Value = (digit->Value + step >= DIGIT_MAX) ? DIGIT_MAX : digit->Value + step; \
|
|
|
+ digit->Updated = true; \
|
|
|
+ } else if (digit->CurrentState == Decrementing && digit->Value > DOT_MIN) { \
|
|
|
+ digit->Value = (digit->Value - step <= DIGIT_MIN) ? DIGIT_MIN : digit->Value - step; \
|
|
|
+ digit->Updated = true; \
|
|
|
+ } \
|
|
|
+ activeTube |= (digit->Value != DIGIT_MAX && digit->Value != DIGIT_MIN); \
|
|
|
+ } \
|
|
|
+ if (activeTube) { \
|
|
|
+ Tube##x##UpdateTimeout.attach_us(Tube##x##UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US); \
|
|
|
+ } \
|
|
|
+}
|
|
|
+
|
|
|
+Timeout Tube0UpdateTimeout;
|
|
|
+TUBE_CALLBACK(0)
|
|
|
+Timeout Tube1UpdateTimeout;
|
|
|
+TUBE_CALLBACK(1)
|
|
|
+Timeout Tube2UpdateTimeout;
|
|
|
+TUBE_CALLBACK(2)
|
|
|
+Timeout Tube3UpdateTimeout;
|
|
|
+TUBE_CALLBACK(3)
|
|
|
+
|
|
|
+void FadeInOutDigit(int T, int D, int Duration) {
|
|
|
+ for (int i = 0; i < 10; i++) {
|
|
|
+ Tubes[T].Digits[i].CurrentState = Decrementing;
|
|
|
+ }
|
|
|
+ if (D != -1) {
|
|
|
+ Tubes[T].Digits[D].CurrentState = Incrementing;
|
|
|
+ }
|
|
|
+ Tubes[T].FadeDuration = Duration;
|
|
|
+
|
|
|
+ if (T == 0) {
|
|
|
+ Tube0UpdateTimeout.attach_us(Tube0UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
|
|
|
+ } else if (T == 1) {
|
|
|
+ Tube1UpdateTimeout.attach_us(Tube1UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
|
|
|
+ } else if (T == 2) {
|
|
|
+ Tube2UpdateTimeout.attach_us(Tube2UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
|
|
|
+ } else if (T == 3) {
|
|
|
+ Tube3UpdateTimeout.attach_us(Tube3UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+Ticker RefreshTicker, RngUpdateTicker;
|
|
|
+int RngTickerIter;
|
|
|
void RngTickerUpdate(void) {
|
|
|
|
|
|
|
|
@@ -107,12 +107,36 @@ void RngTickerUpdate(void) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+void RtcTickCallback(void) {
|
|
|
+ RtcTick = true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void RefreshTickCallback(void) {
|
|
|
+ RefreshTick = true;
|
|
|
+}
|
|
|
+
|
|
|
+void RngTickCallback(void) {
|
|
|
+ RngTick = true;
|
|
|
+}
|
|
|
+
|
|
|
int main() {
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ for (int i = 0; i < NUM_TUBES; i++) {
|
|
|
+ for (int j = 0; j < 10; j++) {
|
|
|
+ Tubes[i].Digits[j].CurrentState = Decrementing;
|
|
|
+ Tubes[i].Digits[j].Value = 0;
|
|
|
+ Tubes[i].Digits[j].Updated = false;
|
|
|
+ }
|
|
|
+ Tubes[i].Refresh = false;
|
|
|
+ Tubes[i].FadeDuration = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ Dot.CurrentState = Decrementing;
|
|
|
+ Dot.Value = 0;
|
|
|
+ Dot.Updated = false;
|
|
|
|
|
|
RtcTick = false;
|
|
|
RefreshTick = false;
|
|
@@ -144,8 +168,7 @@ int main() {
|
|
|
|
|
|
|
|
|
|
|
|
- Ticker refreshTicker;
|
|
|
- refreshTicker.attach_us(RefreshTickCallback, DIGIT_REFRESH_RATE_US);
|
|
|
+ RefreshTicker.attach_us(RefreshTickCallback, REFRESH_RATE_US);
|
|
|
|
|
|
|
|
|
|
|
@@ -154,10 +177,6 @@ int main() {
|
|
|
|
|
|
|
|
|
|
|
|
- Dot.CurrentState = Decrementing;
|
|
|
- Dot.Step = DOT_TICK_STEP;
|
|
|
- Dot.Brightness = 0;
|
|
|
-
|
|
|
while(1) {
|
|
|
|
|
|
|
|
@@ -173,24 +192,17 @@ int main() {
|
|
|
if (RefreshTick) {
|
|
|
RefreshTick = false;
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ for (int j = 0; j < 10; j++) {
|
|
|
+ if (Tubes[i].Digits[j].Updated) {
|
|
|
+ PCA9685_SetDigit(i, j, Tubes[i].Digits[j].Value);
|
|
|
+ Tubes[i].Digits[j].Updated = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if (Dot.Updated) {
|
|
|
- PCA9685_SetDot(Dot.Brightness);
|
|
|
+ PCA9685_SetDot(Dot.Value);
|
|
|
Dot.Updated = false;
|
|
|
}
|
|
|
}
|
|
@@ -206,54 +218,24 @@ int main() {
|
|
|
DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ if (startup || prevHour / 10 != nextHour / 10) {
|
|
|
+ FadeInOutDigit(0, (nextHour / 10 != 0) ? nextHour / 10 : -1 , DIGIT_FADE_DURATION_US);
|
|
|
+ }
|
|
|
+ if (startup || prevHour % 10 != nextHour % 10) {
|
|
|
+ FadeInOutDigit(1, nextHour % 10, DIGIT_FADE_DURATION_US);
|
|
|
+ }
|
|
|
+ if (startup || prevMinute / 10 != nextMinute / 10) {
|
|
|
+ FadeInOutDigit(2, nextMinute / 10, DIGIT_FADE_DURATION_US);
|
|
|
+ }
|
|
|
+ if (startup || prevMinute % 10 != nextMinute % 10) {
|
|
|
+ FadeInOutDigit(3, nextMinute % 10, DIGIT_FADE_DURATION_US);
|
|
|
+ }
|
|
|
|
|
|
Dot.CurrentState = (Dot.CurrentState == Decrementing) ? Incrementing : Decrementing;
|
|
|
-
|
|
|
- DotUpdateTick.attach_us(DotUpdateCallback, 700);
|
|
|
+ DotUpdateTimeout.attach_us(DotUpdateCallback, DOT_FADE_DURATION_US / REFRESH_RATE_US);
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ startup = false;
|
|
|
}
|
|
|
|
|
|
if (RngTick) {
|