summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-12 22:39:21 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-12 22:44:50 +0000
commit852a6ccf117be4415a4c07cb10825b9faf1cdbfc (patch)
tree358f59eabde55f8ecd1fb4046a5f65e8313fd7b6 /util
parent569660ada9383b3ba1119b212f3200e7e1876539 (diff)
util/spkmodem-decode: automatic tone detection
a continuation of the previous patch. this waits for currently one second, before defaulting to the hardcoded value. otherwise, it tries to use whatever timing it gets automatically. this way, the program should now reconfigure its own timing, without intervention by the user, if the timing differs from sensible defaults. this is because spkmodem is implementation-defined; it's just however coreboot and/or GRUB happen to set it up, and on the hardware in question. Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util')
-rw-r--r--util/spkmodem_decode/spkmodem-decode.c74
1 files changed, 71 insertions, 3 deletions
diff --git a/util/spkmodem_decode/spkmodem-decode.c b/util/spkmodem_decode/spkmodem-decode.c
index f08b1b52..a621db6d 100644
--- a/util/spkmodem_decode/spkmodem-decode.c
+++ b/util/spkmodem_decode/spkmodem-decode.c
@@ -80,6 +80,8 @@
/*
* Frequency of audio in Hz
+ * WARNING: if changing, make sure to adjust
+ * SAMPLES_PER_FRAME accordingly (see maths below)
*/
#define SAMPLE_RATE 48000
@@ -153,6 +155,19 @@
#define FREQ_DATA_THRESHOLD ((DATA_TONE_THRESHOLD_HZ) / (FRAME_RATE))
/*
+ * These determine how long the program will wait during
+ * tone auto-detection, before shifting to defaults.
+ *
+ * For tone auto-detection (time waiting for detection)
+ * NOTE: you could multiply SAMPLE_PER_FRAME instead
+ * of SAMPLE_RATE in LEARN_SAMPLES, for more granularity.
+ * Here, 1 * SAMPLE_RATE represents 1 second, which seems
+ * like a reasonable, conservative default wait time.
+ */
+#define LEARN_SECONDS 1
+#define LEARN_SAMPLES ((LEARN_SECONDS) * (SAMPLE_RATE))
+
+/*
* Sample amplitude threshold used to convert the waveform
* into a pulse stream. Values near zero are regarded as noise.
*/
@@ -189,6 +204,12 @@ struct decoder_state {
int sep_samples;
int sep_min;
int sep_max;
+
+ /* for automatic tone detection */
+ int freq_min;
+ int freq_max;
+ int freq_threshold;
+ int learn_samples;
};
static const char *argv0;
@@ -197,6 +218,7 @@ static int host_is_big_endian(void);
static void handle_audio(struct decoder_state *st);
static int valid_signal(struct decoder_state *st);
static void decode_pulse(struct decoder_state *st);
+static void auto_detect_tone(struct decoder_state *st);
static signed short read_sample(struct decoder_state *st);
static int set_ascii_bit(struct decoder_state *st);
static void print_char(struct decoder_state *st);
@@ -237,6 +259,11 @@ main(int argc, char **argv)
break;
}
+ /* fallback in case tone detection fails */
+ st.freq_min = 100000;
+ st.freq_max = 0;
+ st.freq_threshold = FREQ_DATA_THRESHOLD;
+
/*
* Used for separator calibration
*/
@@ -405,9 +432,50 @@ decode_pulse(struct decoder_state *st)
st->ringpos = ringpos;
st->sep_pos = sep_pos;
+ /*
+ * Attempt to auto-detect spkmodem tone
+ */
+ auto_detect_tone(st);
+
st->sample_count++;
}
+/*
+ * Observe signal for LEARN_SAMPLES samples (e.g. 1 second).
+ * The exact amount of time is determined by LEARN_SAMPLES
+ * divided by SAMPLE_RATE, logically. For example, if
+ * LEARN_SAMPLES were half of the SAMPLE_RATE, this
+ * corresponds to roughly 500ms before timeout.
+ *
+ * to guess the correct timing. If it fails,
+ * fall back to known good values.
+ */
+static void
+auto_detect_tone(struct decoder_state *st)
+{
+ if (st->learn_samples >= LEARN_SAMPLES)
+ return;
+
+ if (st->freq_data > 0) {
+ if (st->freq_data < st->freq_min)
+ st->freq_min = st->freq_data;
+
+ if (st->freq_data > st->freq_max)
+ st->freq_max = st->freq_data;
+ }
+
+ st->learn_samples++;
+
+ if (st->learn_samples == LEARN_SAMPLES) {
+ st->freq_threshold =
+ (st->freq_min + st->freq_max) / 2;
+
+ if (st->debug)
+ printf("auto threshold: %dHz\n",
+ st->freq_threshold * FRAME_RATE);
+ }
+}
+
static signed short
read_sample(struct decoder_state *st)
{
@@ -452,7 +520,7 @@ set_ascii_bit(struct decoder_state *st)
{
if (st->debug)
print_stats(st);
- if (st->freq_data < FREQ_DATA_THRESHOLD)
+ if (st->freq_data < st->freq_threshold)
st->ascii |= (1 << st->ascii_bit);
st->ascii_bit--;
@@ -484,7 +552,7 @@ print_stats(struct decoder_state *st)
printf("%d %d %d data=%dHz sep=%dHz(min %dHz %dHz)\n",
st->freq_data,
st->freq_separator,
- FREQ_DATA_THRESHOLD,
+ st->freq_threshold,
data_hz,
sep_hz,
sep_hz_min,
@@ -495,7 +563,7 @@ print_stats(struct decoder_state *st)
printf("%d %d %d @%ld data=%dHz sep=%dHz(min %dHz %dHz)\n",
st->freq_data,
st->freq_separator,
- FREQ_DATA_THRESHOLD,
+ st->freq_threshold,
pos - SAMPLE_OFFSET,
data_hz,
sep_hz,