|
|
|
@@ -2672,16 +2672,13 @@ EOT
|
|
|
|
|
# says "this channel, this note". Channel THREE, effects counting down from the top, so music
|
|
|
|
|
# can one day take nought and count up without the two having to negotiate.
|
|
|
|
|
#
|
|
|
|
|
# Checked against silence, which is the useful half: a landing in the same conditions makes no
|
|
|
|
|
# sound at all, so this is measuring the crash and not the machine humming.
|
|
|
|
|
# Checked against silence BEFORE it rather than against a quiet landing, because a landing is
|
|
|
|
|
# not quiet any more - it latches two notes of its own. The silence that still means something
|
|
|
|
|
# is the second before the crash: the machine does not hum, so anything there is the event.
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles 3000000 --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/none.pad" --sound "$BUILD/bang.raw" \
|
|
|
|
|
--disk "$BUILD/crash.img" --ram-disk 2048 \
|
|
|
|
|
"$BUILD/cosmos.bin" > "$BUILD/bang.out" 2>&1 || true
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles 3000000 --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/none.pad" --sound "$BUILD/hush.raw" \
|
|
|
|
|
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
|
|
|
|
"$BUILD/cosmos.bin" > "$BUILD/hush.out" 2>&1 || true
|
|
|
|
|
read -r BANGPEAK BANGLOUD BANGFADE HUSHPEAK <<EOT
|
|
|
|
|
$(python3 -c "
|
|
|
|
|
import struct
|
|
|
|
@@ -2698,12 +2695,17 @@ def look(path):
|
|
|
|
|
back = max((abs(v) for v in s[half:]), default=0)
|
|
|
|
|
return peak, loud, (1 if front > back else 0)
|
|
|
|
|
b = look('$BUILD/bang.raw')
|
|
|
|
|
print(b[0], b[1], b[2], look('$BUILD/hush.raw')[0])
|
|
|
|
|
# The second before it, which is a lander falling and making no noise at all.
|
|
|
|
|
import struct
|
|
|
|
|
raw = open('$BUILD/bang.raw', 'rb').read()
|
|
|
|
|
s = struct.unpack('<%dh' % (len(raw) // 2), raw)
|
|
|
|
|
before = max((abs(v) for v in s[:48000]), default=0)
|
|
|
|
|
print(b[0], b[1], b[2], before)
|
|
|
|
|
" 2>/dev/null || echo "0 0 0 -1")
|
|
|
|
|
EOT
|
|
|
|
|
[ "$BANGPEAK" -gt 2000 ] && [ "$BANGLOUD" -gt 5000 ] && [ "$HUSHPEAK" = "0" ] \
|
|
|
|
|
&& result ok "a crash makes a noise, and a landing does not" "peak $BANGPEAK against silence" \
|
|
|
|
|
|| result no "a crash makes a noise, and a landing does not" "crash peak $BANGPEAK, landing peak $HUSHPEAK"
|
|
|
|
|
&& result ok "a crash makes a noise out of silence" "peak $BANGPEAK, and nothing at all before it" \
|
|
|
|
|
|| result no "a crash makes a noise out of silence" "crash peak $BANGPEAK, $HUSHPEAK beforehand"
|
|
|
|
|
# ---- And it fades ----
|
|
|
|
|
#
|
|
|
|
|
# A byte of envelope is not seconds: it is squared and scaled to four of them, so the first
|
|
|
|
@@ -2714,6 +2716,82 @@ EOT
|
|
|
|
|
&& result ok "and it is loudest at the front" "which is what makes it a bang" \
|
|
|
|
|
|| result no "and it is loudest at the front" "louder in the second half than the first"
|
|
|
|
|
|
|
|
|
|
# ---- The thruster: a bang at ignition and a rumble under it ----
|
|
|
|
|
#
|
|
|
|
|
# The rumble is the first HELD note this game plays, and a held note outlives whatever was
|
|
|
|
|
# holding it. Its gate goes down when a thruster lights and does not come up until every one
|
|
|
|
|
# of them is out - so what is checked is that it goes QUIET again, which is the half that can
|
|
|
|
|
# fail silently in the other direction.
|
|
|
|
|
#
|
|
|
|
|
# Placed high with a full tank so the burn can be let go of with plenty of air left: three
|
|
|
|
|
# clear seconds between the thruster going out and the ground arriving.
|
|
|
|
|
python3 -c "
|
|
|
|
|
import struct
|
|
|
|
|
open('$BUILD/high.state','wb').write(struct.pack('<hhhhhhBBBB',
|
|
|
|
|
0x14A0, -2000, 0, 0, 0x14A0, 2600, 255, 0, 0, 0))
|
|
|
|
|
"
|
|
|
|
|
cp "$ROOT/Tests/build/disks/cosmos.img" "$BUILD/high.img"
|
|
|
|
|
"$ROOT/SplitDisk" put "$BUILD/high.img" "$BUILD/high.state" /lander.state > /dev/null
|
|
|
|
|
python3 -c "open('$BUILD/hold.pad','wb').write(b'\x00' * 130 + b'\x08' * 60 + b'\x00' * 40000)"
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles 12000000 --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/hold.pad" --sound "$BUILD/hold.raw" \
|
|
|
|
|
--disk "$BUILD/high.img" --ram-disk 2048 \
|
|
|
|
|
"$BUILD/cosmos.bin" > "$BUILD/hold.out" 2>&1 || true
|
|
|
|
|
# ---- And landing with the thruster STILL DOWN ----
|
|
|
|
|
#
|
|
|
|
|
# The case the release above cannot reach. Braking into the ground ends the flying and then
|
|
|
|
|
# waits to be told the message has been read, so the frame that would have noticed the button
|
|
|
|
|
# coming up never runs - and a held note outlives the loop that was holding it. It roared under
|
|
|
|
|
# the verdict and went on roaring until the machine stopped.
|
|
|
|
|
python3 -c "open('$BUILD/brakeland.pad','wb').write(b'\x00' * 150 + b'\x08' * 90 + b'\x00' * 8000)"
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles 8000000 --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/brakeland.pad" --sound "$BUILD/braked.raw" \
|
|
|
|
|
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
|
|
|
|
"$BUILD/cosmos.bin" > "$BUILD/braked.out" 2>&1 || true
|
|
|
|
|
# And a docking, where the latch sounds on its own with nothing else going on.
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles 8000000 --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/none.pad" --sound "$BUILD/latch.raw" \
|
|
|
|
|
--disk "$BUILD/dock.img" --ram-disk 2048 \
|
|
|
|
|
"$BUILD/cosmos.bin" > "$BUILD/latch.out" 2>&1 || true
|
|
|
|
|
read -r BURNING AFTERWARDS LATCHLONG UNDERVERDICT <<EOT
|
|
|
|
|
$(python3 -c "
|
|
|
|
|
import struct
|
|
|
|
|
def samples(path):
|
|
|
|
|
raw = open(path, 'rb').read()
|
|
|
|
|
return struct.unpack('<%dh' % (len(raw) // 2), raw)
|
|
|
|
|
def peak(s, a, b):
|
|
|
|
|
w = s[a:b]
|
|
|
|
|
return max((abs(v) for v in w), default=0)
|
|
|
|
|
h = samples('$BUILD/hold.raw')
|
|
|
|
|
b = samples('$BUILD/braked.raw')
|
|
|
|
|
l = samples('$BUILD/latch.raw')
|
|
|
|
|
loud = [i for i, x in enumerate(l) if abs(x) > 300]
|
|
|
|
|
span = (loud[-1] - loud[0]) if loud else 0
|
|
|
|
|
# During the burn, and a second and a half after it, which is still long before the ground.
|
|
|
|
|
print(peak(h, 115200, 124800), peak(h, 192000, 288000), span, peak(b, 240000, 336000))
|
|
|
|
|
" 2>/dev/null || echo "0 -1 0 -1")
|
|
|
|
|
EOT
|
|
|
|
|
[ "$BURNING" -gt 1000 ] \
|
|
|
|
|
&& result ok "a held thruster rumbles" "$BURNING while it burns" \
|
|
|
|
|
|| result no "a held thruster rumbles" "$BURNING while it burns"
|
|
|
|
|
# ---- And stops ----
|
|
|
|
|
#
|
|
|
|
|
# A gated note ends when its gate comes up and at no other time. Landing while the thruster was
|
|
|
|
|
# still down used to leave it roaring under the verdict for ever, because the frame that would
|
|
|
|
|
# have noticed the button coming up never ran - so anything that stops to wait now hushes it.
|
|
|
|
|
[ "$AFTERWARDS" = "0" ] \
|
|
|
|
|
&& result ok "and goes quiet when it stops" "silence a second and a half later" \
|
|
|
|
|
|| result no "and goes quiet when it stops" "still $AFTERWARDS long after the thruster went out"
|
|
|
|
|
# Two notes an eighth of a second apart, so the whole thing outlasts either of them. One note
|
|
|
|
|
# is about a fifth of a second; this is four tenths.
|
|
|
|
|
[ "$LATCHLONG" -gt 14400 ] \
|
|
|
|
|
&& result ok "and a dock latches on two notes" "$LATCHLONG samples, which is longer than one" \
|
|
|
|
|
|| result no "and a dock latches on two notes" "$LATCHLONG samples, which is about one note"
|
|
|
|
|
# Two seconds of the verdict being up, with nothing under it.
|
|
|
|
|
[ "$UNDERVERDICT" = "0" ] \
|
|
|
|
|
&& result ok "and nothing roars under the verdict" "landed on the thruster, and it stopped anyway" \
|
|
|
|
|
|| result no "and nothing roars under the verdict" "$UNDERVERDICT still sounding after landing"
|
|
|
|
|
|
|
|
|
|
# ---- A quarter of a tank, said once ----
|
|
|
|
|
#
|
|
|
|
|
# ONCE is the whole design of it. A lander is at its most careful in the last few seconds
|
|
|
|
@@ -2731,7 +2809,9 @@ open('$BUILD/lowfuel.state','wb').write(struct.pack('<hhhhhhBBBB',
|
|
|
|
|
"
|
|
|
|
|
cp "$ROOT/Tests/build/disks/cosmos.img" "$BUILD/lowfuel.img"
|
|
|
|
|
"$ROOT/SplitDisk" put "$BUILD/lowfuel.img" "$BUILD/lowfuel.state" /lander.state > /dev/null
|
|
|
|
|
python3 -c "open('$BUILD/burn.pad','wb').write(b'\x08' * 40000)"
|
|
|
|
|
# Three hundred frames of thruster and then nothing. Long enough to drain past a quarter
|
|
|
|
|
# several times over, and it STOPS - which is what makes the measurement below possible.
|
|
|
|
|
python3 -c "open('$BUILD/burn.pad','wb').write(b'\x08' * 300 + b'\x00' * 40000)"
|
|
|
|
|
for when in 1700000 2400000; do
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles $when --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/burn.pad" --screen "$BUILD/fuel$when.ppm" \
|
|
|
|
@@ -2757,26 +2837,28 @@ def gauge(path):
|
|
|
|
|
import struct
|
|
|
|
|
raw = open('$BUILD/warn.raw', 'rb').read()
|
|
|
|
|
s = struct.unpack('<%dh' % (len(raw) // 2), raw)
|
|
|
|
|
# ---- HOW LONG it sounds for, not how many times it starts ----
|
|
|
|
|
# ---- WHAT IS STILL SOUNDING once the thruster stops ----
|
|
|
|
|
#
|
|
|
|
|
# Counting bursts cannot tell one beep from a nag. Without the latch the warning fires on
|
|
|
|
|
# every tick the tank goes down, which is once every ten frames - far faster than the sound
|
|
|
|
|
# decays, so the beeps run into each other and a burst counter sees ONE long burst either way.
|
|
|
|
|
# The length is what differs: six tenths of a second against ten seconds of it.
|
|
|
|
|
loud = [i for i, x in enumerate(s) if abs(x) > 300]
|
|
|
|
|
span = (loud[-1] - loud[0]) if loud else 0
|
|
|
|
|
print(gauge('$BUILD/fuel1700000.ppm'), gauge('$BUILD/fuel2400000.ppm'), span)
|
|
|
|
|
# Two measurements failed before this one. Counting bursts cannot tell a beep from a nag: the
|
|
|
|
|
# warning would fire every tick the tank drops, far faster than the sound decays, so the beeps
|
|
|
|
|
# run together and a burst counter sees one long burst either way. Measuring the total length
|
|
|
|
|
# stopped working the day the thruster got a rumble of its own, which sounds for the whole burn
|
|
|
|
|
# whatever the warning does.
|
|
|
|
|
#
|
|
|
|
|
# So: burn, stop, and listen AFTER. Warned once, the beep went long ago and the rumble releases
|
|
|
|
|
# at once, so there is nothing. Nagging, the last beep was on the burn's final tick and is
|
|
|
|
|
# still fading. Measured, that is nought against five thousand six hundred.
|
|
|
|
|
after = max((abs(x) for x in s[250000:275000]), default=0)
|
|
|
|
|
print(gauge('$BUILD/fuel1700000.ppm'), gauge('$BUILD/fuel2400000.ppm'), after)
|
|
|
|
|
" 2>/dev/null || echo "none none -1")
|
|
|
|
|
EOT
|
|
|
|
|
# Green cells then red cells, and none of the other colour either time.
|
|
|
|
|
[ "$ABOVE" = "8,0" ] && [ "$BELOW" = "0,7" ] \
|
|
|
|
|
&& result ok "the fuel gauge goes red at a quarter" "eight green became seven red" \
|
|
|
|
|
|| result no "the fuel gauge goes red at a quarter" "$ABOVE above, $BELOW below"
|
|
|
|
|
# Twelve seconds of holding the thruster, which empties the tank entirely and keeps it empty.
|
|
|
|
|
# The warning is under a second of that, or it is a nag rather than a warning.
|
|
|
|
|
[ "$WARNINGS" -gt 0 ] && [ "$WARNINGS" -lt 48000 ] \
|
|
|
|
|
&& result ok "and the warning sounds once, not once a tick" "$WARNINGS samples of it in twelve seconds of running dry" \
|
|
|
|
|
|| result no "and the warning sounds once, not once a tick" "$WARNINGS samples of warning"
|
|
|
|
|
[ "$WARNINGS" -lt 500 ] \
|
|
|
|
|
&& result ok "and the warning sounds once, not once a tick" "nothing left over when the burn ends" \
|
|
|
|
|
|| result no "and the warning sounds once, not once a tick" "$WARNINGS still sounding after the burn"
|
|
|
|
|
|
|
|
|
|
# ---- Dust on landing, and gas on letting go ----
|
|
|
|
|
#
|
|
|
|
@@ -2808,7 +2890,9 @@ for when in 9900000 10150000 10800000; do
|
|
|
|
|
"$BUILD/cosmos.bin" > "$BUILD/gas.out" 2>&1 || true
|
|
|
|
|
done
|
|
|
|
|
# And a plain fall onto the pad it starts over, which lands rather than crashes.
|
|
|
|
|
for when in 2700000 2820000 3100000; do
|
|
|
|
|
# Eight frames later than they used to be: the landing latch plays its two notes before the
|
|
|
|
|
# dust goes up, and runPend waits for the second of them.
|
|
|
|
|
for when in 2900000 3050000 3300000; do
|
|
|
|
|
timeout 60 "$EMU" --fast --cycles $when --keyboard "$BUILD/fly.keys" \
|
|
|
|
|
--pad "$BUILD/none.pad" --screen "$BUILD/dust$when.ppm" \
|
|
|
|
|
--disk "$ROOT/Tests/build/disks/cosmos.img" --ram-disk 2048 \
|
|
|
|
@@ -2828,8 +2912,8 @@ def look(path):
|
|
|
|
|
puff = len([1 for x, y in where('f0f0f0') if y > 20])
|
|
|
|
|
ship = where('d8c048')
|
|
|
|
|
return puff, (min(y for x, y in ship) if ship else -1)
|
|
|
|
|
print(look('$BUILD/dust2700000.ppm')[0], look('$BUILD/dust2820000.ppm')[0],
|
|
|
|
|
look('$BUILD/dust3100000.ppm')[0],
|
|
|
|
|
print(look('$BUILD/dust2900000.ppm')[0], look('$BUILD/dust3050000.ppm')[0],
|
|
|
|
|
look('$BUILD/dust3300000.ppm')[0],
|
|
|
|
|
look('$BUILD/gas9900000.ppm')[0], look('$BUILD/gas10150000.ppm')[0],
|
|
|
|
|
look('$BUILD/gas10800000.ppm')[0],
|
|
|
|
|
look('$BUILD/gas10150000.ppm')[1], look('$BUILD/gas10800000.ppm')[1])
|
|
|
|
|