The firmware has never been flashed, and a real bug already reached the repo because of it: RD03E_FRAME_LEN was 5 for a 6-byte frame, so the footer check collided with the distance high byte and EVERY distance reading was garbage — always `lo | 0x5500`, about 218 metres, regardless of what the sensor saw. That was pure logic with no hardware dependency. It should have been catchable on a laptop, and there was simply no way to run the code. Extracted the hardware-free logic out of the three drivers — rd03e_parse, bmp280_compensate, mems_level — as moves rather than rewrites, carrying the explanatory comments along with the code they explain. The drivers now own only their bus I/O and call into the pure units, so nothing changes for the real device. `./run_tests.sh` builds them with gcc -Wall -Wextra -Werror plus a dependency-free assert harness: 175 checks, 0 failed, from a clean tree. Proven to catch the actual bug rather than assumed to: reintroducing FRAME_LEN 5 fails four checks, including one that reads "a simple-report frame is 6 bytes, not 5", plus the truncated-frame and 5-byte-window cases. Restored, green again. This does NOT make the firmware verified, and the README says so plainly — it is called a narrow exception and scoped to pure logic. Wiring, timing, real register behaviour and the reconstructed RD-03E frame format all still need the physical board. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
48 lines
1.8 KiB
C
48 lines
1.8 KiB
C
// I2S MEMS microphone level maths (RMS -> dBFS) — PURE LOGIC.
|
|
//
|
|
// ESP-IDF-free by design: no I2S, no esp_err_t, no logging. Only
|
|
// <stdint.h>/<stddef.h> and <math.h> in the .c, so it compiles and is
|
|
// testable on a host with plain gcc (see ../test/). `mems_mic.c` does the
|
|
// I2S read and calls in here for the arithmetic.
|
|
//
|
|
// The INMP441 family outputs 24-bit signed PCM, MSB-first, left-justified
|
|
// in a 32-bit I2S slot (Philips/standard I2S timing). The right-shift-by-8
|
|
// used below to recover the 24-bit sample from the 32-bit slot, and the
|
|
// dBFS reference level (2^23, a 24-bit signed sample's full-scale
|
|
// magnitude), are the commonly-documented values for this exact mic family
|
|
// — but "commonly documented" is not "verified against this specific
|
|
// board." Host tests prove the arithmetic (full scale reads ~0 dBFS,
|
|
// silence reads the floor and never -inf/NaN); they cannot prove the shift
|
|
// amount matches this module revision's real bit alignment.
|
|
|
|
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// dBFS reference: full-scale magnitude of a 24-bit signed sample.
|
|
#define MEMS_FULL_SCALE_24BIT (8388608.0) // 2^23
|
|
|
|
// Level reported for a true-silent (or sub-LSB) input, and the clamp
|
|
// applied to anything quieter.
|
|
#define MEMS_DBFS_FLOOR (-120.0)
|
|
|
|
// RMS over a block of raw 32-bit I2S slots. The mic's 24-bit sample is
|
|
// left-justified in the 32-bit slot -- shift right 8 to recover it before
|
|
// squaring, so the magnitude lines up with MEMS_FULL_SCALE_24BIT.
|
|
// Returns 0.0 for an empty block.
|
|
double mems_level_rms(const int32_t *samples, size_t n_samples);
|
|
|
|
// dBFS: 20*log10(rms / full_scale). A true-silent input gives rms=0,
|
|
// which is -inf in dB -- clamp to a floor rather than emit a value the
|
|
// JSON encoder/backend can't handle.
|
|
double mems_level_dbfs(double rms);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|