discstation 0.1.26 → 0.1.27
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.
- package/arduino/c6/DiscStation_C6.ino +1 -44
- package/arduino/v1/DiscStation.ino +1 -47
- package/package.json +1 -1
- package/src/discstation.py +1 -1
- package/src/discstation_host.py +41 -30
|
@@ -24,8 +24,6 @@
|
|
|
24
24
|
#define BTN_SELECT_PIN 21 // D3
|
|
25
25
|
#define BTN_UP_PIN 20 // D9/MISO
|
|
26
26
|
#define BTN_DOWN_PIN 18 // D10/MOSI
|
|
27
|
-
#define LED_POWER_PIN 15 // Built-in user LED
|
|
28
|
-
#define LED_ACT_PIN 16 // D6/TX
|
|
29
27
|
#define POT_PIN 0 // D0/A0 (ADC)
|
|
30
28
|
|
|
31
29
|
#define DEBOUNCE_MS 50
|
|
@@ -35,11 +33,10 @@
|
|
|
35
33
|
#define STANDBY_BLANK_MS 60000
|
|
36
34
|
#define IDLE_BLANK_MS 45000 // blank the OLED after this long with no input on HOME/STANDBY
|
|
37
35
|
#define PING_TIMEOUT_MS 30000
|
|
38
|
-
#define LED_BLINK_MS 250
|
|
39
36
|
|
|
40
37
|
#define WIFI_RESET_HOLD_MS 10000
|
|
41
38
|
#define WIFI_CONNECT_TIMEOUT_MS 18000
|
|
42
|
-
#define WIFI_RETRY_MS
|
|
39
|
+
#define WIFI_RETRY_MS 15000
|
|
43
40
|
|
|
44
41
|
#define MAX_HOME_MODES 5
|
|
45
42
|
#define BURN_COUNT 4
|
|
@@ -237,8 +234,6 @@ unsigned long downLastDebounce = 0;
|
|
|
237
234
|
int ffSpeedIndex = 0;
|
|
238
235
|
int rewSpeedIndex = 0;
|
|
239
236
|
|
|
240
|
-
bool actLedState = false;
|
|
241
|
-
unsigned long lastLedBlink = 0;
|
|
242
237
|
int homeIndex = 0;
|
|
243
238
|
int burnModeIndex = 0;
|
|
244
239
|
int burnSpeedIndex = 0;
|
|
@@ -792,10 +787,6 @@ void setup() {
|
|
|
792
787
|
pinMode(BTN_SELECT_PIN, INPUT_PULLUP);
|
|
793
788
|
pinMode(BTN_UP_PIN, INPUT_PULLUP);
|
|
794
789
|
pinMode(BTN_DOWN_PIN, INPUT_PULLUP);
|
|
795
|
-
pinMode(LED_POWER_PIN, OUTPUT);
|
|
796
|
-
pinMode(LED_ACT_PIN, OUTPUT);
|
|
797
|
-
digitalWrite(LED_POWER_PIN, HIGH);
|
|
798
|
-
digitalWrite(LED_ACT_PIN, LOW);
|
|
799
790
|
pinMode(POT_PIN, INPUT);
|
|
800
791
|
analogReadResolution(12);
|
|
801
792
|
|
|
@@ -812,13 +803,6 @@ void setup() {
|
|
|
812
803
|
delay(3000);
|
|
813
804
|
}
|
|
814
805
|
|
|
815
|
-
for (int i = 0; i < 3; i++) {
|
|
816
|
-
digitalWrite(LED_ACT_PIN, HIGH);
|
|
817
|
-
delay(150);
|
|
818
|
-
digitalWrite(LED_ACT_PIN, LOW);
|
|
819
|
-
delay(150);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
806
|
drawStandby();
|
|
823
807
|
lastMsgTime = millis();
|
|
824
808
|
lastInputTime = millis();
|
|
@@ -1134,10 +1118,6 @@ void loop() {
|
|
|
1134
1118
|
(long)(millis() - lastInputTime) >= IDLE_BLANK_MS) {
|
|
1135
1119
|
display.ssd1306_command(0xAE);
|
|
1136
1120
|
displayBlank = true;
|
|
1137
|
-
digitalWrite(LED_POWER_PIN, LOW);
|
|
1138
|
-
}
|
|
1139
|
-
if (!displayBlank) {
|
|
1140
|
-
digitalWrite(LED_POWER_PIN, HIGH);
|
|
1141
1121
|
}
|
|
1142
1122
|
|
|
1143
1123
|
if (uiState != UI_DISCONNECTED &&
|
|
@@ -1145,28 +1125,5 @@ void loop() {
|
|
|
1145
1125
|
drawDisconnected();
|
|
1146
1126
|
}
|
|
1147
1127
|
|
|
1148
|
-
{
|
|
1149
|
-
bool ledOn = false;
|
|
1150
|
-
if (uiState == UI_BURN_READY || uiState == UI_PLAY || uiState == UI_WAITING || uiState == UI_IP) {
|
|
1151
|
-
ledOn = true;
|
|
1152
|
-
} else if (uiState == UI_STATUS) {
|
|
1153
|
-
if (progressPercent >= 0) {
|
|
1154
|
-
ledOn = (millis() - lastLedBlink > LED_BLINK_MS);
|
|
1155
|
-
if (ledOn) {
|
|
1156
|
-
lastLedBlink = millis();
|
|
1157
|
-
actLedState = !actLedState;
|
|
1158
|
-
}
|
|
1159
|
-
ledOn = actLedState;
|
|
1160
|
-
} else {
|
|
1161
|
-
ledOn = true;
|
|
1162
|
-
}
|
|
1163
|
-
} else if (uiState == UI_HOME || uiState == UI_STANDBY || uiState == UI_LOADING) {
|
|
1164
|
-
ledOn = false;
|
|
1165
|
-
} else if (uiState == UI_DISCONNECTED) {
|
|
1166
|
-
ledOn = true;
|
|
1167
|
-
}
|
|
1168
|
-
digitalWrite(LED_ACT_PIN, ledOn ? HIGH : LOW);
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
1128
|
delay(20);
|
|
1172
1129
|
}
|
|
@@ -25,8 +25,6 @@
|
|
|
25
25
|
#define BTN_SELECT_PIN 14
|
|
26
26
|
#define BTN_UP_PIN 13
|
|
27
27
|
#define BTN_DOWN_PIN 15
|
|
28
|
-
#define LED_POWER_PIN 32
|
|
29
|
-
#define LED_ACT_PIN 33
|
|
30
28
|
#define POT_PIN 34
|
|
31
29
|
|
|
32
30
|
#define DEBOUNCE_MS 50
|
|
@@ -36,11 +34,10 @@
|
|
|
36
34
|
#define STANDBY_BLANK_MS 60000
|
|
37
35
|
#define IDLE_BLANK_MS 45000 // blank the OLED after this long with no input on HOME/STANDBY
|
|
38
36
|
#define PING_TIMEOUT_MS 30000
|
|
39
|
-
#define LED_BLINK_MS 250
|
|
40
37
|
|
|
41
38
|
#define WIFI_RESET_HOLD_MS 10000 // hold SELECT this long on HOME to wipe Wi-Fi creds
|
|
42
39
|
#define WIFI_CONNECT_TIMEOUT_MS 18000 // give a stored-creds join this long before falling to the portal
|
|
43
|
-
#define WIFI_RETRY_MS
|
|
40
|
+
#define WIFI_RETRY_MS 15000 // if a live link drops, force a re-join after this
|
|
44
41
|
|
|
45
42
|
#define MAX_HOME_MODES 5
|
|
46
43
|
#define BURN_COUNT 4
|
|
@@ -241,9 +238,6 @@ unsigned long downLastDebounce = 0;
|
|
|
241
238
|
int ffSpeedIndex = 0;
|
|
242
239
|
int rewSpeedIndex = 0;
|
|
243
240
|
|
|
244
|
-
// LED state
|
|
245
|
-
bool actLedState = false;
|
|
246
|
-
unsigned long lastLedBlink = 0;
|
|
247
241
|
int homeIndex = 0;
|
|
248
242
|
int burnModeIndex = 0;
|
|
249
243
|
int burnSpeedIndex = 0;
|
|
@@ -757,10 +751,6 @@ void setup() {
|
|
|
757
751
|
pinMode(BTN_SELECT_PIN, INPUT_PULLUP);
|
|
758
752
|
pinMode(BTN_UP_PIN, INPUT_PULLUP);
|
|
759
753
|
pinMode(BTN_DOWN_PIN, INPUT_PULLUP);
|
|
760
|
-
pinMode(LED_POWER_PIN, OUTPUT);
|
|
761
|
-
pinMode(LED_ACT_PIN, OUTPUT);
|
|
762
|
-
digitalWrite(LED_POWER_PIN, HIGH);
|
|
763
|
-
digitalWrite(LED_ACT_PIN, LOW);
|
|
764
754
|
pinMode(POT_PIN, INPUT);
|
|
765
755
|
analogReadResolution(12);
|
|
766
756
|
analogSetPinAttenuation(POT_PIN, ADC_11db);
|
|
@@ -778,14 +768,6 @@ void setup() {
|
|
|
778
768
|
delay(3000);
|
|
779
769
|
}
|
|
780
770
|
|
|
781
|
-
// Blink activity LED 3x to confirm it works
|
|
782
|
-
for (int i = 0; i < 3; i++) {
|
|
783
|
-
digitalWrite(LED_ACT_PIN, HIGH);
|
|
784
|
-
delay(150);
|
|
785
|
-
digitalWrite(LED_ACT_PIN, LOW);
|
|
786
|
-
delay(150);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
771
|
drawStandby();
|
|
790
772
|
lastMsgTime = millis();
|
|
791
773
|
lastInputTime = millis();
|
|
@@ -1115,10 +1097,6 @@ void loop() {
|
|
|
1115
1097
|
(long)(millis() - lastInputTime) >= IDLE_BLANK_MS) {
|
|
1116
1098
|
display.ssd1306_command(0xAE);
|
|
1117
1099
|
displayBlank = true;
|
|
1118
|
-
digitalWrite(LED_POWER_PIN, LOW);
|
|
1119
|
-
}
|
|
1120
|
-
if (!displayBlank) {
|
|
1121
|
-
digitalWrite(LED_POWER_PIN, HIGH);
|
|
1122
1100
|
}
|
|
1123
1101
|
|
|
1124
1102
|
// --- PING timeout (disconnected) ---
|
|
@@ -1127,29 +1105,5 @@ void loop() {
|
|
|
1127
1105
|
drawDisconnected();
|
|
1128
1106
|
}
|
|
1129
1107
|
|
|
1130
|
-
// --- Activity LED ---
|
|
1131
|
-
{
|
|
1132
|
-
bool ledOn = false;
|
|
1133
|
-
if (uiState == UI_BURN_READY || uiState == UI_PLAY || uiState == UI_WAITING || uiState == UI_IP) {
|
|
1134
|
-
ledOn = true;
|
|
1135
|
-
} else if (uiState == UI_STATUS) {
|
|
1136
|
-
if (progressPercent >= 0) {
|
|
1137
|
-
ledOn = (millis() - lastLedBlink > LED_BLINK_MS);
|
|
1138
|
-
if (ledOn) {
|
|
1139
|
-
lastLedBlink = millis();
|
|
1140
|
-
actLedState = !actLedState;
|
|
1141
|
-
}
|
|
1142
|
-
ledOn = actLedState;
|
|
1143
|
-
} else {
|
|
1144
|
-
ledOn = true;
|
|
1145
|
-
}
|
|
1146
|
-
} else if (uiState == UI_HOME || uiState == UI_STANDBY) {
|
|
1147
|
-
ledOn = false;
|
|
1148
|
-
} else if (uiState == UI_DISCONNECTED) {
|
|
1149
|
-
ledOn = true;
|
|
1150
|
-
}
|
|
1151
|
-
digitalWrite(LED_ACT_PIN, ledOn ? HIGH : LOW);
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
1108
|
delay(20);
|
|
1155
1109
|
}
|
package/package.json
CHANGED
package/src/discstation.py
CHANGED
|
@@ -122,7 +122,7 @@ class TcpSerial:
|
|
|
122
122
|
A dead link raises serial.SerialException from in_waiting/write, which is
|
|
123
123
|
what check_serial_alive() / main()'s reconnect loop already expect."""
|
|
124
124
|
|
|
125
|
-
def __init__(self, host, port=2323, connect_timeout=
|
|
125
|
+
def __init__(self, host, port=2323, connect_timeout=3):
|
|
126
126
|
if host.count(":") == 1 and not host.startswith("["): # "ip:port"
|
|
127
127
|
host, _, p = host.rpartition(":")
|
|
128
128
|
if p.isdigit():
|
package/src/discstation_host.py
CHANGED
|
@@ -72,6 +72,7 @@ def serial_port():
|
|
|
72
72
|
_REMOTE_MDNS_TYPE = "_discstation._tcp.local."
|
|
73
73
|
_REMOTE_DEFAULT_HOST = "discstation.local"
|
|
74
74
|
_remote_cache = {"at": 0.0, "value": None}
|
|
75
|
+
_remote_browser = {} # {"zc": Zeroconf|None, "found": {"addr": ...}} - built once, lives for the process
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
def remote_host():
|
|
@@ -79,8 +80,10 @@ def remote_host():
|
|
|
79
80
|
|
|
80
81
|
`DISC_REMOTE_HOST` unset / `auto` (default) -> mDNS browse for the
|
|
81
82
|
firmware's `_discstation._tcp` advert, falling back to resolving
|
|
82
|
-
`discstation.local` via the OS resolver.
|
|
83
|
-
|
|
83
|
+
`discstation.local` via the OS resolver. A hit is cached 60s (stable
|
|
84
|
+
address, don't hammer mDNS); a miss only ~8s, so a host that just
|
|
85
|
+
rejoined the appliance's network reconnects promptly instead of
|
|
86
|
+
waiting out a full minute.
|
|
84
87
|
`DISC_REMOTE_HOST=<ip|host>` -> that address, verbatim, instantly.
|
|
85
88
|
`DISC_REMOTE_HOST=off` / `none` / `0` -> None (never look; USB / web only).
|
|
86
89
|
|
|
@@ -92,52 +95,60 @@ def remote_host():
|
|
|
92
95
|
if setting and setting != "auto":
|
|
93
96
|
return (os.environ.get("DISC_REMOTE_HOST") or "").strip()
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
addr = _mdns_addr()
|
|
99
|
+
if addr:
|
|
100
|
+
return addr
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
# zeroconf absent / nothing advertised yet -> OS resolver for discstation.local.
|
|
103
|
+
# Cache it: a hit 60s, a miss ~8s (so a host that just rejoined reconnects fast).
|
|
104
|
+
ttl = 60 if _remote_cache["value"] else 8
|
|
105
|
+
if time.time() - _remote_cache["at"] < ttl:
|
|
106
|
+
return _remote_cache["value"]
|
|
107
|
+
try:
|
|
108
|
+
value = socket.gethostbyname(_REMOTE_DEFAULT_HOST)
|
|
109
|
+
except OSError:
|
|
110
|
+
value = None
|
|
99
111
|
_remote_cache["at"] = time.time()
|
|
100
112
|
_remote_cache["value"] = value
|
|
101
113
|
return value
|
|
102
114
|
|
|
103
115
|
|
|
104
|
-
def
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
def _mdns_addr():
|
|
117
|
+
"""Latest IPv4 advertised for the firmware's _discstation._tcp service, or None.
|
|
118
|
+
|
|
119
|
+
A single background ServiceBrowser is started on the first call and reused for
|
|
120
|
+
the whole process. (Creating a fresh Zeroconf per lookup - this runs every few
|
|
121
|
+
seconds while the link is down - leaked sockets and engine threads until the
|
|
122
|
+
process hit its fd limit and every transport died.)"""
|
|
123
|
+
if not _remote_browser:
|
|
124
|
+
try:
|
|
125
|
+
from zeroconf import Zeroconf, ServiceBrowser
|
|
126
|
+
except ImportError:
|
|
127
|
+
_remote_browser["zc"] = None
|
|
128
|
+
return None
|
|
110
129
|
found = {}
|
|
111
130
|
|
|
112
131
|
class _Listener:
|
|
113
|
-
def
|
|
114
|
-
info = zc.get_service_info(type_, name, timeout=
|
|
132
|
+
def _seen(self, zc, type_, name):
|
|
133
|
+
info = zc.get_service_info(type_, name, timeout=1000)
|
|
115
134
|
if info:
|
|
116
135
|
for addr in info.parsed_addresses():
|
|
117
136
|
if "." in addr: # IPv4
|
|
118
137
|
found["addr"] = addr
|
|
119
138
|
return
|
|
120
139
|
|
|
121
|
-
|
|
140
|
+
add_service = _seen
|
|
141
|
+
update_service = _seen
|
|
122
142
|
|
|
123
|
-
def remove_service(self,
|
|
124
|
-
|
|
143
|
+
def remove_service(self, zc, type_, name):
|
|
144
|
+
found.pop("addr", None)
|
|
125
145
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
deadline = time.time() + 2.5
|
|
130
|
-
while time.time() < deadline and "addr" not in found:
|
|
131
|
-
time.sleep(0.1)
|
|
132
|
-
finally:
|
|
133
|
-
zc.close()
|
|
134
|
-
if found.get("addr"):
|
|
135
|
-
return found["addr"]
|
|
146
|
+
_remote_browser["found"] = found
|
|
147
|
+
_remote_browser["zc"] = Zeroconf()
|
|
148
|
+
ServiceBrowser(_remote_browser["zc"], _REMOTE_MDNS_TYPE, _Listener())
|
|
136
149
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
except OSError:
|
|
140
|
-
return None
|
|
150
|
+
found = _remote_browser.get("found")
|
|
151
|
+
return found.get("addr") if found else None
|
|
141
152
|
|
|
142
153
|
|
|
143
154
|
def _stable_serial_path(device):
|