discstation 0.1.28 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,8 @@
31
31
  #define POT_READ_MS 200
32
32
  #define DONE_RESET_MS 30000
33
33
  #define STANDBY_BLANK_MS 60000
34
- #define IDLE_BLANK_MS 45000 // blank the OLED after this long with no input on HOME/STANDBY
34
+ #define IDLE_BLANK_MS 45000 // no input this long on HOME/STANDBY -> spinning-disc screensaver
35
+ #define SAVER_FRAME_MS 90 // screensaver frame interval (~11fps)
35
36
  #define PING_TIMEOUT_MS 30000
36
37
 
37
38
  #define WIFI_RESET_HOLD_MS 10000
@@ -241,8 +242,10 @@ bool editingSpeed = false;
241
242
  int playVolume = 50;
242
243
  unsigned long standbyStartTime = 0;
243
244
  unsigned long lastMsgTime = 0;
244
- unsigned long lastInputTime = 0; // last button press / screen change; drives OLED idle-blank
245
- bool displayBlank = false;
245
+ unsigned long lastInputTime = 0; // last button press / screen change; drives the idle screensaver
246
+ bool displayBlank = false; // true = real UI hidden, disc screensaver running; any input restores it
247
+ unsigned long lastSaverFrame = 0;
248
+ int saverStep = 0;
246
249
  bool audioPlayMode = false;
247
250
  int displayRotation = 0;
248
251
 
@@ -545,6 +548,46 @@ void drawLoading() {
545
548
  display.display();
546
549
  }
547
550
 
551
+ // 24-step sine table x64: sin(i*15deg)*64. Drives the idle disc screensaver.
552
+ const int8_t SIN24[24] = {
553
+ 0, 17, 32, 45, 55, 62, 64, 62, 55, 45, 32, 17,
554
+ 0, -17, -32, -45, -55, -62, -64, -62, -55, -45, -32, -17
555
+ };
556
+
557
+ // Spinning-disc screensaver frame - shown after IDLE_BLANK_MS on HOME/STANDBY
558
+ // instead of powering the panel off. Keeps the OLED lit and the I2C bus busy so
559
+ // a USB power-bank feeding the remote doesn't hit its no-load auto-shutoff.
560
+ void drawDiscSaver(int step) {
561
+ if (!displayOk) return;
562
+ const int cx = 64, cy = 32, R = 30;
563
+ display.clearDisplay();
564
+ display.fillCircle(cx, cy, R, SSD1306_WHITE); // vinyl body
565
+
566
+ for (int cl = 0; cl < 2; cl++) { // 2 groove clusters, 180 apart
567
+ int base = step + cl * 12;
568
+ for (int g = 0; g < 3; g++) { // 3 nested "sound wave" grooves
569
+ for (int t = 0; t < 3; t++) { // 3px-thick stroke
570
+ int r = 16 + g * 5 + t;
571
+ int px = -100, py = -100;
572
+ for (int a = 0; a <= 4; a++) { // ~60deg arc, 4 chords
573
+ int i = (base + a) % 24;
574
+ int x = cx + r * SIN24[(i + 6) % 24] / 64;
575
+ int y = cy + r * SIN24[i] / 64;
576
+ if (px > -100) display.drawLine(px, py, x, y, SSD1306_BLACK);
577
+ px = x; py = y;
578
+ }
579
+ }
580
+ }
581
+ }
582
+
583
+ display.fillCircle(cx, cy, 13, SSD1306_BLACK); // concentric label
584
+ display.fillCircle(cx, cy, 11, SSD1306_WHITE);
585
+ display.fillCircle(cx, cy, 8, SSD1306_BLACK);
586
+ display.fillCircle(cx, cy, 5, SSD1306_WHITE);
587
+ display.fillCircle(cx, cy, 2, SSD1306_BLACK); // center hole
588
+ display.display();
589
+ }
590
+
548
591
  // Returns true if this call actually woke a blanked screen - callers use that
549
592
  // to swallow the wake press so it doesn't also trigger a menu action.
550
593
  bool wakeDisplay() {
@@ -1118,11 +1161,19 @@ void loop() {
1118
1161
  if (!displayBlank) drawLoading();
1119
1162
  }
1120
1163
 
1164
+ // --- Idle disc screensaver (HOME + STANDBY) ---
1121
1165
  if (displayOk && !displayBlank &&
1122
1166
  (uiState == UI_HOME || uiState == UI_STANDBY) &&
1123
1167
  (long)(millis() - lastInputTime) >= IDLE_BLANK_MS) {
1124
- display.ssd1306_command(0xAE);
1125
1168
  displayBlank = true;
1169
+ saverStep = 0;
1170
+ lastSaverFrame = 0;
1171
+ }
1172
+ if (displayBlank && displayOk &&
1173
+ (long)(millis() - lastSaverFrame) >= SAVER_FRAME_MS) {
1174
+ lastSaverFrame = millis();
1175
+ drawDiscSaver(saverStep);
1176
+ saverStep = (saverStep + 1) % 24;
1126
1177
  }
1127
1178
 
1128
1179
  if (uiState != UI_DISCONNECTED &&
@@ -32,7 +32,8 @@
32
32
  #define POT_READ_MS 200
33
33
  #define DONE_RESET_MS 30000
34
34
  #define STANDBY_BLANK_MS 60000
35
- #define IDLE_BLANK_MS 45000 // blank the OLED after this long with no input on HOME/STANDBY
35
+ #define IDLE_BLANK_MS 45000 // no input this long on HOME/STANDBY -> spinning-disc screensaver
36
+ #define SAVER_FRAME_MS 90 // screensaver frame interval (~11fps)
36
37
  #define PING_TIMEOUT_MS 30000
37
38
 
38
39
  #define WIFI_RESET_HOLD_MS 10000 // hold SELECT this long on HOME to wipe Wi-Fi creds
@@ -245,8 +246,10 @@ bool editingSpeed = false;
245
246
  int playVolume = 50;
246
247
  unsigned long standbyStartTime = 0;
247
248
  unsigned long lastMsgTime = 0;
248
- unsigned long lastInputTime = 0; // last button press / screen change; drives OLED idle-blank
249
- bool displayBlank = false;
249
+ unsigned long lastInputTime = 0; // last button press / screen change; drives the idle screensaver
250
+ bool displayBlank = false; // true = real UI hidden, disc screensaver running; any input restores it
251
+ unsigned long lastSaverFrame = 0;
252
+ int saverStep = 0;
250
253
  bool audioPlayMode = false;
251
254
  int displayRotation = 0;
252
255
 
@@ -531,6 +534,46 @@ void drawDisconnected() {
531
534
  display.display();
532
535
  }
533
536
 
537
+ // 24-step sine table x64: sin(i*15deg)*64. Drives the idle disc screensaver.
538
+ const int8_t SIN24[24] = {
539
+ 0, 17, 32, 45, 55, 62, 64, 62, 55, 45, 32, 17,
540
+ 0, -17, -32, -45, -55, -62, -64, -62, -55, -45, -32, -17
541
+ };
542
+
543
+ // Spinning-disc screensaver frame - shown after IDLE_BLANK_MS on HOME/STANDBY
544
+ // instead of powering the panel off. Keeps the OLED lit and the I2C bus busy so
545
+ // a USB power-bank feeding the remote doesn't hit its no-load auto-shutoff.
546
+ void drawDiscSaver(int step) {
547
+ if (!displayOk) return;
548
+ const int cx = 64, cy = 32, R = 30;
549
+ display.clearDisplay();
550
+ display.fillCircle(cx, cy, R, SSD1306_WHITE); // vinyl body
551
+
552
+ for (int cl = 0; cl < 2; cl++) { // 2 groove clusters, 180 apart
553
+ int base = step + cl * 12;
554
+ for (int g = 0; g < 3; g++) { // 3 nested "sound wave" grooves
555
+ for (int t = 0; t < 3; t++) { // 3px-thick stroke
556
+ int r = 16 + g * 5 + t;
557
+ int px = -100, py = -100;
558
+ for (int a = 0; a <= 4; a++) { // ~60deg arc, 4 chords
559
+ int i = (base + a) % 24;
560
+ int x = cx + r * SIN24[(i + 6) % 24] / 64;
561
+ int y = cy + r * SIN24[i] / 64;
562
+ if (px > -100) display.drawLine(px, py, x, y, SSD1306_BLACK);
563
+ px = x; py = y;
564
+ }
565
+ }
566
+ }
567
+ }
568
+
569
+ display.fillCircle(cx, cy, 13, SSD1306_BLACK); // concentric label
570
+ display.fillCircle(cx, cy, 11, SSD1306_WHITE);
571
+ display.fillCircle(cx, cy, 8, SSD1306_BLACK);
572
+ display.fillCircle(cx, cy, 5, SSD1306_WHITE);
573
+ display.fillCircle(cx, cy, 2, SSD1306_BLACK); // center hole
574
+ display.display();
575
+ }
576
+
534
577
  // Returns true if this call actually woke a blanked screen - callers use that
535
578
  // to swallow the wake press so it doesn't also trigger a menu action.
536
579
  bool wakeDisplay() {
@@ -1096,12 +1139,19 @@ void loop() {
1096
1139
  if (!displayBlank) drawStatus();
1097
1140
  }
1098
1141
 
1099
- // --- OLED idle blanking (HOME + STANDBY) ---
1142
+ // --- Idle disc screensaver (HOME + STANDBY) ---
1100
1143
  if (displayOk && !displayBlank &&
1101
1144
  (uiState == UI_HOME || uiState == UI_STANDBY) &&
1102
1145
  (long)(millis() - lastInputTime) >= IDLE_BLANK_MS) {
1103
- display.ssd1306_command(0xAE);
1104
1146
  displayBlank = true;
1147
+ saverStep = 0;
1148
+ lastSaverFrame = 0;
1149
+ }
1150
+ if (displayBlank && displayOk &&
1151
+ (long)(millis() - lastSaverFrame) >= SAVER_FRAME_MS) {
1152
+ lastSaverFrame = millis();
1153
+ drawDiscSaver(saverStep);
1154
+ saverStep = (saverStep + 1) % 24;
1105
1155
  }
1106
1156
 
1107
1157
  // --- PING timeout (disconnected) ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discstation",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
4
4
  "description": "DiscStation optical-media appliance host — one cross-OS installer",
5
5
  "bin": {
6
6
  "discstation-setup": "scripts/setup.mjs",