Skip to content
Open

2.2.3 #170

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ccfc3e5
draft: decimation filter
Dec 9, 2025
7ba6169
draft: decimation filter q15
Dec 10, 2025
fc44bde
draft: fix coefficients
Dec 10, 2025
4d1884b
draft: f32 for stereo
Dec 10, 2025
7681806
draft: cascaded decimator
Dec 10, 2025
ab87053
draft: enable downsampling make configurable via App
Dec 10, 2025
a63d37d
draft: no decimator option
Dec 10, 2025
089ea92
fix decimation factor 1
Dec 11, 2025
a6da0bd
src/audio/audio_datapath.c: stop micro correctly
Dec 11, 2025
c870162
fix: sd card crash at the end of the recording
Dec 16, 2025
7644454
fix: add mutex to decimator to prevent crash at end of recording
Dec 22, 2025
405a46c
src/SD_Card/SDLogger/SDLogger.cpp: reset signal state properly
DennisMoschina Jan 30, 2026
a9a35d5
src/audio/audio_datapath.c: removed k_poll_signal_check to avoid dead…
DennisMoschina Jan 30, 2026
f4259d8
src/SensorManager/Microphone.cpp: fixed printing mic sampling rate wr…
DennisMoschina Jan 30, 2026
f642a94
src/SD_Card/SDLogger.cpp: make sure the logger event is reset correctly
DennisMoschina Feb 4, 2026
e287241
src/SD_Card/SDLogger.cpp: allow writing multiple blocks at once, only…
DennisMoschina Feb 4, 2026
8e4ceff
feat(version): introduce automatic semantic versioning
DennisMoschina Mar 4, 2026
f4d892a
enable audio streaming
o-bagge Jan 30, 2026
8fdc81e
remove no streaming comment
o-bagge Feb 2, 2026
7e0331c
fix(sensor): enhance GATT notification handling with context management
DennisMoschina Apr 21, 2026
6f021cf
fix(sensor): improve notification context management with spinlock pr…
DennisMoschina Apr 21, 2026
2c2b0db
chore(VERSION): updated patch level
DennisMoschina Apr 21, 2026
56f9961
chore: bump version to 2.3.0
DennisMoschina Apr 27, 2026
46450e8
fix(microphone): reorder sample rates for correct initialization
DennisMoschina May 4, 2026
7d5eaca
parsing scheme is being stored in .oe files. README in ParseInfo has …
habibialireza Apr 29, 2026
b5c51ed
doc(SensorScheme): added documentation to public functions
DennisMoschina Apr 30, 2026
1e0d6b7
feat(sensor_service): added function to get sensor config status
DennisMoschina Apr 30, 2026
aa95772
feat(sensor_scheme): add function to retrieve sensor scheme with acti…
DennisMoschina Apr 30, 2026
6c520a6
fix(sensor_manager): update config_work_handler to set sensor config …
DennisMoschina Apr 30, 2026
eda4dc7
doc(ParseInfo): document Default Frequency Index for schemes in .oe h…
DennisMoschina Apr 30, 2026
eff6b19
revert(parse-info): remove active sample rate header changes
DennisMoschina May 5, 2026
3a70ef0
fix gyro
May 7, 2026
f9a5a9e
reduce PDM clock speed to 3.072 MHz
May 8, 2026
8505ce4
Revert "chore: bump version to 2.3.0"
DennisMoschina May 18, 2026
a5fe3e7
fix(audio): guard encoder lifecycle during mic capture
DennisMoschina May 12, 2026
7bcbac7
fix(DefaultSensors): remove DATA_STREAMING option from availableOptions
DennisMoschina May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
VERSION_MAJOR = 2
VERSION_MINOR = 2
PATCHLEVEL = 2
PATCHLEVEL = 3
VERSION_TWEAK = 0
EXTRAVERSION =
8 changes: 4 additions & 4 deletions src/ParseInfo/DefaultSensors.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ SensorScheme defaultSensors[SENSOR_COUNT] = {
.groupCount = MICRO_GROUP_COUNT,
.groups = microGroups,
.configOptions = {
.availableOptions = DATA_STORAGE | FREQUENCIES_DEFINED, // no streaming
.availableOptions = DATA_STORAGE | FREQUENCIES_DEFINED,
.frequencyOptions = {
.frequencyCount = sizeof(Microphone::sample_rates.reg_vals),
.defaultFrequencyIndex = 1,
.maxBleFrequencyIndex = 1,
.defaultFrequencyIndex = 8,
.maxBleFrequencyIndex = 8,
.frequencies = Microphone::sample_rates.sample_rates,
},
},
Expand All @@ -159,7 +159,7 @@ SensorScheme defaultSensors[SENSOR_COUNT] = {
.availableOptions = DATA_STREAMING | DATA_STORAGE | FREQUENCIES_DEFINED,
.frequencyOptions = {
.frequencyCount = sizeof(PPG::sample_rates.reg_vals),
.defaultFrequencyIndex = 2,
.defaultFrequencyIndex = 1,
.maxBleFrequencyIndex = 12,
.frequencies = PPG::sample_rates.sample_rates,
},
Expand Down
50 changes: 49 additions & 1 deletion src/ParseInfo/README
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,52 @@ enum SensorConfigOptions {
- `Length`: Length of the frequency array
- `Default Frequency Index`: Index of the default frequency
- `Max BLE Index`: Index of the maximum frequency for BLE streaming
- `Frequency Array`: Array of available frequencies
- `Frequency Array`: Array of available frequencies

## OE File Header

`.oe` files written by `SDLogger` now embed the active parse scheme in the file header so the file stays self-describing.
All numeric fields are written in the device's little-endian binary representation.

### Header version `0x0002`

Files only contain the fixed header below and rely on a hard-coded parser outside the file:

| Bytes | Field | Type |
|-------|-----------|--------|
| 0-1 | Version | uint16 |
| 2-9 | Timestamp | uint64 |

### Header version `0x0003`

Files with version `0x0003` extend the fixed header and add earable identity metadata ahead of it and append a serialized ParseInfo block.
`header_size` points to the first sensor data record in the file.
`Parse Info Size` is the size of the `Parse Info Blob`.
`Device ID` is the immutable Nordic chip identifier captured at boot.
`Side` is encoded as `0` for left, `1` for right, and `255` for unknown.
The ParseInfo blob starts immediately after `Side`.

| Bytes | Field | Type |
|-------|-----------------|--------|
| 0-1 | Version | uint16 |
| 2-9 | Timestamp | uint64 |
| 10-13 | Header Size | uint32 |
| 14-17 | Parse Info Size | uint32 |
| 18-25 | Device ID | uint64 |
| 26 | Side | uint8 |
| 27-X | Parse Info Blob | byte[] |

### Parse Info Blob

The blob starts with the existing `Sensor List` serialization and then stores each referenced sensor scheme in the same order as the sensor IDs:

| Bytes | Field | Type |
|-------|--------------------|--------|
| 0 | Sensor Count | uint8 |
| 1-N | Sensor IDs | uint8[] |
| ... | Sensor Scheme Size | uint16 |
| ... | Sensor Scheme | byte[] |
| ... | Sensor Scheme Size | uint16 |
| ... | Sensor Scheme | byte[] |

Each `Sensor Scheme` payload uses the existing `Single Sensor Scheme` serialization already documented above.
74 changes: 72 additions & 2 deletions src/ParseInfo/SensorScheme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <string>
#include <cstring>
#include <errno.h>
#include <stdint.h>

#include <zephyr/kernel.h>
#include <zephyr/bluetooth/gatt.h>
Expand Down Expand Up @@ -348,9 +350,77 @@ int initSensorSchemeForId(uint8_t id) {
}

struct SensorScheme* getSensorSchemeForId(uint8_t id) {
return sensorSchemesMap[id];
auto sensorSchemeIt = sensorSchemesMap.find(id);
if (sensorSchemeIt == sensorSchemesMap.end()) {
return NULL;
}

return sensorSchemeIt->second;
}

struct ParseInfoScheme* getParseInfoScheme() {
return parseInfoSchemeStruct;
}
}

size_t getParseInfoStorageSize() {
if ((parseInfoSchemeStruct == NULL) || (parseInfoScheme == NULL)) {
return 0;
}

size_t size = parseInfoSchemeSize;

for (size_t i = 0; i < parseInfoSchemeStruct->sensorCount; i++) {
SensorScheme* scheme = getSensorSchemeForId(parseInfoSchemeStruct->sensorIds[i]);
if (scheme == NULL) {
return 0;
}

size += sizeof(uint16_t);
size += getSensorSchemeSize(scheme);
}

return size;
}

ssize_t serializeParseInfoStorage(char* buffer, size_t bufferSize) {
if ((parseInfoSchemeStruct == NULL) || (parseInfoScheme == NULL) || (buffer == NULL)) {
return -ENODATA;
}

size_t size = getParseInfoStorageSize();
if ((size == 0) || (size > bufferSize)) {
return -ENOMEM;
}

char* bufferStart = buffer;
memcpy(buffer, parseInfoScheme, parseInfoSchemeSize);
buffer += parseInfoSchemeSize;

for (size_t i = 0; i < parseInfoSchemeStruct->sensorCount; i++) {
SensorScheme* scheme = getSensorSchemeForId(parseInfoSchemeStruct->sensorIds[i]);
if (scheme == NULL) {
return -ENOENT;
}

size_t sensorSchemeSize = getSensorSchemeSize(scheme);
if (sensorSchemeSize > UINT16_MAX) {
return -EOVERFLOW;
}

uint16_t encodedSchemeSize = (uint16_t)sensorSchemeSize;
memcpy(buffer, &encodedSchemeSize, sizeof(encodedSchemeSize));
buffer += sizeof(encodedSchemeSize);

ssize_t writtenSize = serializeSensorScheme(scheme, buffer, bufferSize - (buffer - bufferStart));
if (writtenSize < 0) {
return writtenSize;
}
if ((size_t)writtenSize != sensorSchemeSize) {
return -EIO;
}

buffer += writtenSize;
}

return buffer - bufferStart;
}
20 changes: 19 additions & 1 deletion src/ParseInfo/SensorScheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,29 @@ int initParseInfoService(struct ParseInfoScheme* scheme, struct SensorScheme* se
struct SensorScheme* getSensorSchemeForId(uint8_t id);
struct ParseInfoScheme* getParseInfoScheme();

/**
* @brief Calculate the byte length of the serialized parse-info storage blob.
*
* The storage blob contains the serialized sensor list followed by each sensor
* scheme prefixed with a uint16 length. Returns 0 if parse-info state is not
* initialized or any scheme cannot be represented in the storage format.
*/
size_t getParseInfoStorageSize();

/**
* @brief Serialize parse-info state into an SD-log file header payload.
*
* @param buffer Destination buffer for the serialized parse-info storage blob.
* @param bufferSize Available bytes in @p buffer.
* @return Number of bytes written on success, or a negative errno value.
*/
ssize_t serializeParseInfoStorage(char* buffer, size_t bufferSize);

float getSampleRateForSensorId(uint8_t id, uint8_t frequencyIndex);
float getSampleRateForSensor(struct SensorScheme* sensorScheme, uint8_t frequencyIndex);

#ifdef __cplusplus
}
#endif

#endif // _SENSOR_SCHEME_H
#endif // _SENSOR_SCHEME_H
Loading
Loading