build+tools: fw_content.conf 填 audiod/audio CLI md5; 新增诊断工具 sndprobe(PCM设备探测)/tonepcm2(HW_REFINE能力探测+写计时时钟验证) — 无声定位用。M2.90(0.7.85) 已打包 504bc74b 回验0diff

This commit is contained in:
MeowOS committed 2026-08-31 22:45:43 +08:00
1 parent ade0a57353
commit 942bdece78
4 files changed
+249 -2

No files matched your search

+82
View File
@@ -0,0 +1,82 @@
/* tonepcm.c — 直开 /dev/snd/pcmC0D0p 写 N 秒正弦并计时(不需要耳朵的 DAC 时钟验证):
* 若写 5s PCM 的墙钟 ≈5s(扣除缓冲),说明硬件时钟在走、DMA 在消费;
* 若瞬间返回,说明硬件没在走(静音根因在时钟/电源域,不在数据)。
* 用法: tonepcm [sec] [freq] 静态 mipsel。 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sound/asound.h>
static void pmask(struct snd_mask *m, unsigned bit) { m->bits[bit / 32] |= 1u << (bit % 32); }
static void pivset(struct snd_interval *iv, unsigned val)
{
iv->min = iv->max = val; iv->integer = 1;
iv->openmin = iv->openmax = 0; iv->empty = 0;
}
static long long now_ms(void)
{
struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
return (long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
int main(int argc, char **argv)
{
int sec = argc > 1 ? atoi(argv[1]) : 5;
int freq = argc > 2 ? atoi(argv[2]) : 440;
int rate = 44100, ch = 2;
int fd = open("/dev/snd/pcmC0D0p", O_RDWR);
if (fd < 0) { printf("open pcmC0D0p fail\n"); return 1; }
struct snd_pcm_hw_params p;
memset(&p, 0, sizeof p);
pmask(&p.masks[SNDRV_PCM_HW_PARAM_ACCESS - SNDRV_PCM_HW_PARAM_FIRST_MASK],
SNDRV_PCM_ACCESS_RW_INTERLEAVED);
pmask(&p.masks[SNDRV_PCM_HW_PARAM_FORMAT - SNDRV_PCM_HW_PARAM_FIRST_MASK],
SNDRV_PCM_FORMAT_S16_LE);
pmask(&p.masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - SNDRV_PCM_HW_PARAM_FIRST_MASK],
SNDRV_PCM_SUBFORMAT_STD);
pivset(&p.intervals[SNDRV_PCM_HW_PARAM_CHANNELS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL], ch);
pivset(&p.intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL], rate);
p.rmask = ~0u;
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, &p) != 0) { printf("HW_PARAMS fail\n"); close(fd); return 1; }
printf("HW_PARAMS ok (rate interval now [%u,%u])\n",
p.intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL].min,
p.intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL].max);
if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0) != 0) { printf("PREPARE fail\n"); close(fd); return 1; }
/* 生成 1 秒正弦(整数查表近似:简单累加相位,定点幅度 0.3 满幅) */
int frames1s = rate;
short *buf = malloc((size_t)frames1s * ch * 2);
for (int i = 0; i < frames1s; i++) {
/* 粗略正弦:三角波即可(验证用) */
int period = rate / freq;
int ph = i % period;
int v = (ph < period / 2) ? (ph * 4 - period) : (3 * period - ph * 4);
short s = (short)(v * 9830 / period); /* ~0.3 * 32767 */
buf[i * 2] = s; buf[i * 2 + 1] = s;
}
long long t0 = now_ms();
long long written = 0;
for (int s2 = 0; s2 < sec; s2++) {
ssize_t w = write(fd, buf, (size_t)frames1s * ch * 2);
if (w <= 0) { printf("write fail at sec %d (ret=%zd)\n", s2, w); break; }
written += w;
}
long long el = now_ms() - t0;
long long bytes = (long long)sec * frames1s * ch * 2;
printf("wrote %lld/%lld bytes in %lld ms (expected ~%d ms if hw clocking; instant = clock dead)\n",
written, bytes, el, sec * 1000);
struct snd_pcm_status st;
memset(&st, 0, sizeof st);
if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, &st) == 0)
printf("STATUS: state=%d avail=%lu\n", st.state, (unsigned long)st.avail);
close(fd);
return 0;
}