feat: MEMS microphone software handling for TX15 and TX16SMK3 (#7328)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
3djc
2026-06-03 13:31:40 +10:00
committed by GitHub
co-authored by Claude Sonnet 4.6
parent 13bba22a4d
commit a7d730fded
39 changed files with 1385 additions and 4 deletions
+68
View File
@@ -50,8 +50,10 @@
#include <malloc.h>
#include <new>
#include <stdarg.h>
#include <string.h>
#include "lua/lua_states.h"
#include "pdm_wav_recorder.h"
#define CLI_COMMAND_MAX_ARGS 8
#define CLI_COMMAND_MAX_LEN 256
@@ -262,6 +264,69 @@ int cliPlay(const char ** argv)
return 0;
}
#if defined(PDM_CLOCK)
// Record from the PDM microphone to a 16-bit mono WAV file. The actual
// capture + resampling + WAV I/O lives in PdmWavRecorder so the same
// pipeline is reused by the GUI recorder tool.
int cliRecord(const char ** argv)
{
if (!argv[1] || !argv[1][0]) {
cliSerialPrint("%s: missing filename", argv[0]);
return 0;
}
int seconds = 5;
if (argv[2] && argv[2][0]) {
if (toInt(argv, 2, &seconds) == 0 || seconds <= 0 || seconds > 600) {
cliSerialPrint("%s: Invalid duration \"%s\"", argv[0], argv[2]);
return 0;
}
}
char pathBuf[64];
const char* path = argv[1];
const size_t nameLen = strlen(argv[1]);
const bool hasExt =
nameLen >= 4 && strcasecmp(argv[1] + nameLen - 4, ".wav") == 0;
if (!hasExt) {
if (nameLen + 5 > sizeof(pathBuf)) {
cliSerialPrint("%s: path too long", argv[0]);
return 0;
}
memcpy(pathBuf, argv[1], nameLen);
memcpy(pathBuf + nameLen, ".wav", 5);
path = pathBuf;
}
const uint32_t totalSamples = PdmWavRecorder::DST_RATE * (uint32_t)seconds;
// Capture only runs while needed — bring the hardware up for this command.
pdmStart();
PdmWavRecorder rec;
FRESULT res = rec.start(path, (uint32_t)seconds);
if (res != FR_OK) {
pdmStop();
cliSerialPrint("%s: cannot open \"%s\" (err %u)", argv[0], path,
(unsigned)res);
return 0;
}
cliSerialPrint("Recording %d s (%u samples @ %u Hz) to %s",
seconds, (unsigned)totalSamples,
(unsigned)PdmWavRecorder::DST_RATE, path);
while (rec.isRecording() && rec.getSamplesWritten() < totalSamples) {
sleep_ms(50);
}
rec.stop();
pdmStop();
cliSerialPrint("Recorded %u samples (%u bytes)",
(unsigned)rec.getSamplesWritten(),
(unsigned)rec.getBytesWritten());
return 0;
}
#endif // PDM_CLOCK
int cliLs(const char ** argv)
{
FILINFO fno;
@@ -1787,6 +1852,9 @@ const CliCommand cliCommands[] = {
{ "readsd", cliReadSD, "<start sector> <sectors count> <read buffer size (sectors)>" },
{ "testsd", cliTestSD, "" },
{ "play", cliPlay, "<filename>" },
#if defined(PDM_CLOCK)
{ "rec", cliRecord, "<filename> [<seconds>]" },
#endif
{ "reboot", cliReboot, "[wdt]" },
{ "set", cliSet, "<what> <value>" },
#if defined(ENABLE_SERIAL_PASSTHROUGH)