Function bodies 879 total
wasPressed method · c · L27-L34 (8 LOC)firmware/src/core/INavigation.h
bool wasPressed() {
if (_wasPressed) {
_wasPressed = false;
return true;
}
return false;
}readDirection method · c · L35-L40 (6 LOC)firmware/src/core/INavigation.h
Direction readDirection() {
Direction dir = _releasedDirection;
_releasedDirection = DIR_NONE;
return dir;
}updateState method · c · L47-L68 (22 LOC)firmware/src/core/INavigation.h
protected:
void updateState(Direction currentlyHeld) {
uint32_t now = millis();
if (currentlyHeld != DIR_NONE) {
if (!_pressed) {
_pressed = true;
_pressStart = now;
}
_currDirection = currentlyHeld;
} else {
if (_pressed) {
_wasPressed = true;
_releasedDirection = _currDirection;
_pressDuration = now - _pressStart;
_pressed = false;
_currDirection = DIR_NONE;
}
}
}IPower class · c · L6-L15 (10 LOC)firmware/src/core/IPower.h
class IPower
{
public:
virtual ~IPower() = default;
virtual void begin() = 0;
virtual uint8_t getBatteryPercentage() = 0;
virtual bool isCharging() = 0;
virtual void powerOff() = 0;
};IScreen class · c · L2-L14 (13 LOC)firmware/src/core/IScreen.h
class IScreen
{
public:
virtual ~IScreen() = default;
virtual void init() = 0; // called once when screen becomes active
virtual void update() = 0; // called every loop
virtual void render() = 0; // called on demand when redraw needed
virtual bool inhibitPowerSave() { return false; } // override to keep display always on (no screen-off, no power-off)
virtual bool inhibitPowerOff() { return false; } // override to allow screen-off but block auto power-off
};ISpeaker class · c · L8-L26 (19 LOC)firmware/src/core/ISpeaker.h
class ISpeaker {
public:
virtual ~ISpeaker() = default;
virtual void begin() = 0;
virtual void tone(uint16_t freq, uint32_t durationMs) = 0;
virtual void noTone() = 0;
virtual void setVolume(uint8_t vol) = 0; // 0-100
virtual bool isPlaying() { return false; }
virtual void beep() = 0;
virtual void playWav(const uint8_t* data, size_t size) = 0;
virtual void playNotification() = 0;
virtual void playWin() = 0;
virtual void playLose() = 0;
virtual void playCorrectAnswer() = 0;
virtual void playWrongAnswer() = 0;
virtual void playRandomTone(int semitoneShift = 0, uint32_t durationMs = 150) = 0;
};IStorage class · c · L9-L33 (25 LOC)firmware/src/core/IStorage.h
class IStorage
{
public:
struct DirEntry {
String name;
bool isDir;
};
virtual bool isAvailable() = 0;
virtual uint64_t totalBytes() = 0;
virtual uint64_t usedBytes() = 0;
virtual uint64_t freeBytes() = 0;
virtual fs::File open(const char* path, const char* mode) = 0;
virtual bool exists(const char* path) = 0;
virtual String readFile(const char* path) = 0;
virtual bool writeFile(const char* path, const char* content) = 0;
virtual bool deleteFile(const char* path) = 0;
virtual bool makeDir(const char* path) = 0;
virtual uint8_t listDir(const char* path, DirEntry* out, uint8_t max) = 0;
virtual bool renameFile(const char* from, conSource: Repobility analyzer · https://repobility.com
syncSystemFromRtc function · c · L39-L68 (30 LOC)firmware/src/core/RtcManager.h
static inline void syncSystemFromRtc() {
RTC_WIRE.beginTransmission(RTC_I2C_ADDR);
RTC_WIRE.write(RTC_REG_BASE);
if (RTC_WIRE.endTransmission() != 0) return;
RTC_WIRE.requestFrom((uint8_t)RTC_I2C_ADDR, (uint8_t)7);
if (RTC_WIRE.available() < 7) return;
uint8_t sec = _bcd2bin(RTC_WIRE.read() & 0x7F);
uint8_t min = _bcd2bin(RTC_WIRE.read() & 0x7F);
uint8_t hour = _bcd2bin(RTC_WIRE.read() & 0x3F);
uint8_t day = _bcd2bin(RTC_WIRE.read() & 0x3F);
RTC_WIRE.read(); // weekday — skip
uint8_t mon = _bcd2bin(RTC_WIRE.read() & 0x1F);
uint8_t year = _bcd2bin(RTC_WIRE.read());
struct tm t = {};
t.tm_sec = sec;
t.tm_min = min;
t.tm_hour = hour;
t.tm_mday = day;
t.tm_mon = mon - 1;
t.tm_year = 2000 + year - 1900;
t.tm_isdst = -1;
time_t epoch = mktime(&t);
if (epoch < 1577836800L) return; // reject if before 2020-01-01 (RTC not yet set)
struct timeval tv = { .tv_sec = epoch, .tv_usec = 0 };
settimeofday(&tv, nullptr);
}syncRtcFromSystem function · c · L72-L89 (18 LOC)firmware/src/core/RtcManager.h
static inline void syncRtcFromSystem() {
time_t now;
time(&now);
if (now < 1577836800L) return; // don't write invalid time
struct tm* t = gmtime(&now);
RTC_WIRE.beginTransmission(RTC_I2C_ADDR);
RTC_WIRE.write(RTC_REG_BASE);
RTC_WIRE.write(_bin2bcd(t->tm_sec));
RTC_WIRE.write(_bin2bcd(t->tm_min));
RTC_WIRE.write(_bin2bcd(t->tm_hour));
RTC_WIRE.write(_bin2bcd(t->tm_mday));
RTC_WIRE.write((uint8_t)t->tm_wday);
RTC_WIRE.write(_bin2bcd(t->tm_mon + 1));
RTC_WIRE.write(_bin2bcd((uint8_t)(t->tm_year - 100))); // tm_year is years since 1900; store 0–99 from 2000
RTC_WIRE.endTransmission();
}ScreenManager class · c · L8-L38 (31 LOC)firmware/src/core/ScreenManager.h
class ScreenManager
{
public:
static ScreenManager& getInstance() {
static ScreenManager instance;
return instance;
}
void setScreen(IScreen* screen) {
if (_pending) delete _pending;
_pending = screen;
}
IScreen* current() { return _current; }
void update() {
if (_pending) {
if (_current) delete _current;
_current = _pending;
_pending = nullptr;
_current->init();
}
if (_current) _current->update();
}
private:
ScreenManager() = default;
IScreen* _current = nullptr;
IScreen* _pending = nullptr;
};getInstance method · c · L11-L15 (5 LOC)firmware/src/core/ScreenManager.h
public:
static ScreenManager& getInstance() {
static ScreenManager instance;
return instance;
}setScreen method · c · L16-L20 (5 LOC)firmware/src/core/ScreenManager.h
void setScreen(IScreen* screen) {
if (_pending) delete _pending;
_pending = screen;
}update method · c · L23-L32 (10 LOC)firmware/src/core/ScreenManager.h
void update() {
if (_pending) {
if (_current) delete _current;
_current = _pending;
_pending = nullptr;
_current->init();
}
if (_current) _current->update();
}SpeakerI2S class · c · L17-L275 (259 LOC)firmware/src/core/SpeakerI2S.h
class SpeakerI2S : public ISpeaker {
public:
void begin() override {
i2s_config_t cfg = {};
cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
cfg.sample_rate = _sampleRate;
cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
cfg.channel_format = I2S_CHANNEL_FMT_ALL_RIGHT;
cfg.communication_format = I2S_COMM_FORMAT_STAND_I2S;
cfg.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
cfg.dma_buf_count = 8;
cfg.dma_buf_len = 64;
cfg.use_apll = false;
i2s_driver_install(_port, &cfg, 0, nullptr);
i2s_pin_config_t pins = {};
pins.mck_io_num = I2S_PIN_NO_CHANGE; // no MCLK by default; subclass overrides if needed
pins.bck_io_num = SPK_BCLK;
pins.ws_io_num = SPK_WCLK;
pins.data_out_num = SPK_DOUT;
pins.data_in_num = I2S_PIN_NO_CHANGE;
i2s_set_pin(_port, &pins);
setVolume(Config.get(APP_CONFIG_VOLUME, APP_CONFIG_VOLUME_DEFAULT).toInt());
}begin method · c · L19-L42 (24 LOC)firmware/src/core/SpeakerI2S.h
public:
void begin() override {
i2s_config_t cfg = {};
cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
cfg.sample_rate = _sampleRate;
cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
cfg.channel_format = I2S_CHANNEL_FMT_ALL_RIGHT;
cfg.communication_format = I2S_COMM_FORMAT_STAND_I2S;
cfg.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
cfg.dma_buf_count = 8;
cfg.dma_buf_len = 64;
cfg.use_apll = false;
i2s_driver_install(_port, &cfg, 0, nullptr);
i2s_pin_config_t pins = {};
pins.mck_io_num = I2S_PIN_NO_CHANGE; // no MCLK by default; subclass overrides if needed
pins.bck_io_num = SPK_BCLK;
pins.ws_io_num = SPK_WCLK;
pins.data_out_num = SPK_DOUT;
pins.data_in_num = I2S_PIN_NO_CHANGE;
i2s_set_pin(_port, &pins);
setVolume(Config.get(APP_CONFIG_VOLUME, APP_CONFIG_VOLUME_DEFAULT).toInt());
}About: code-quality intelligence by Repobility · https://repobility.com
tone method · c · L43-L49 (7 LOC)firmware/src/core/SpeakerI2S.h
void tone(uint16_t freq, uint32_t durationMs) override {
_stopTask();
_freq = freq;
_duration = durationMs;
xTaskCreate(_toneTask, "spk", 2048, this, 2, &_taskHandle);
}noTone method · c · L50-L54 (5 LOC)firmware/src/core/SpeakerI2S.h
void noTone() override {
_stopTask();
i2s_zero_dma_buffer(_port);
}setVolume method · c · L55-L58 (4 LOC)firmware/src/core/SpeakerI2S.h
void setVolume(uint8_t vol) override {
_amplitude = (int16_t)((uint32_t)vol * 32767 / 100);
}beep method · c · L61-L66 (6 LOC)firmware/src/core/SpeakerI2S.h
void beep() override {
if (!Config.get(APP_CONFIG_NAV_SOUND, APP_CONFIG_NAV_SOUND_DEFAULT).toInt()) return;
if (_taskHandle) return; // already playing — skip rapid beeps to avoid DMA stall
playRandomTone();
}playRandomTone method · c · L67-L73 (7 LOC)firmware/src/core/SpeakerI2S.h
void playRandomTone(int semitoneShift = 0, uint32_t durationMs = 150) override {
static constexpr int scale[] = {60, 62, 64, 65, 67, 69, 71};
int midi = scale[random(0, 7)] + semitoneShift;
uint16_t freq = (uint16_t)(440.0 * pow(2.0, (double)(midi - 69) / 12.0));
tone(freq, durationMs);
}playWav method · c · L74-L105 (32 LOC)firmware/src/core/SpeakerI2S.h
void playWav(const uint8_t* data, size_t size) override {
_stopTask();
if (size < 44) return;
// Scan WAV chunks to find fmt and data
uint32_t pos = 12;
_wavChannels = 1;
_wavSampleRate = _sampleRate;
_wavBits = 16;
_wavData = nullptr;
_wavDataSize = 0;
while (pos + 8 <= (uint32_t)size) {
uint32_t ckId = _readU32(data + pos);
uint32_t ckSize = _readU32(data + pos + 4);
pos += 8;
if (ckId == 0x20746D66u) { // 'fmt '
_wavChannels = _readU16(data + pos + 2);
_wavSampleRate = _readU32(data + pos + 4);
_wavBits = _readU16(data + pos + 14);
} else if (ckId == 0x61746164u) { // 'data'
_wavData = data + pos;
_wavDataSize = (ckSize < (uint32_t)(size - pos)) ? ckSize : (uint32_t)(size - pos);
break;
}
pos += (ckSize + 1u) & ~1u; // word-align
}
if (!_wavData) return;
xTaskCreate(_wavTask, "spkwav", 4096, this, 2, &_taskHplayCorrectAnswer method · c · L110-L117 (8 LOC)firmware/src/core/SpeakerI2S.h
void playCorrectAnswer() override {
if (_taskHandle) return;
_seq[0] = {523, 180, 100};
_seq[1] = {784, 120, 0 };
_seqLen = 2;
xTaskCreate(_seqTask, "spkseq", 2048, this, 2, &_taskHandle);
}playWrongAnswer method · c · L118-L125 (8 LOC)firmware/src/core/SpeakerI2S.h
void playWrongAnswer() override {
if (_taskHandle) return;
_seq[0] = {1109, 150, 100};
_seq[1] = {1109, 150, 0 };
_seqLen = 2;
xTaskCreate(_seqTask, "spkseq", 2048, this, 2, &_taskHandle);
}Repobility · MCP-ready · https://repobility.com
_stopTask method · c · L149-L157 (9 LOC)firmware/src/core/SpeakerI2S.h
void _stopTask() {
if (_taskHandle) {
vTaskDelete(_taskHandle);
_taskHandle = nullptr;
i2s_zero_dma_buffer(_port);
i2s_set_clk(_port, _sampleRate, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}
}_readU16 method · c · L158-L161 (4 LOC)firmware/src/core/SpeakerI2S.h
static uint16_t _readU16(const uint8_t* p) {
return (uint16_t)(p[0] | ((uint16_t)p[1] << 8));
}_readU32 method · c · L162-L165 (4 LOC)firmware/src/core/SpeakerI2S.h
static uint32_t _readU32(const uint8_t* p) {
return (uint32_t)(p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24));
}_toneTask method · c · L166-L191 (26 LOC)firmware/src/core/SpeakerI2S.h
static void _toneTask(void* arg) {
auto* self = static_cast<SpeakerI2S*>(arg);
uint32_t total = _sampleRate * self->_duration / 1000;
uint32_t half = _sampleRate / ((uint32_t)self->_freq * 2);
if (half == 0) half = 1;
int16_t buf[64];
uint32_t done = 0;
bool high = true;
uint32_t phase = 0;
while (done < total) {
uint32_t chunk = (total - done) < 64 ? (total - done) : 64;
for (uint32_t i = 0; i < chunk; i++) {
buf[i] = high ? self->_amplitude : -self->_amplitude;
if (++phase >= half) { phase = 0; high = !high; }
}
size_t written;
i2s_write(_port, buf, chunk * sizeof(int16_t), &written, portMAX_DELAY);
done += chunk;
}
i2s_zero_dma_buffer(_port);
self->_taskHandle = nullptr;
vTaskDelete(nullptr);
}_wavTask method · c · L192-L238 (47 LOC)firmware/src/core/SpeakerI2S.h
static void _wavTask(void* arg) {
auto* self = static_cast<SpeakerI2S*>(arg);
const uint8_t* src = self->_wavData;
uint32_t remaining = self->_wavDataSize;
const uint16_t ch = self->_wavChannels;
const uint16_t bits = self->_wavBits;
const int16_t amp = self->_amplitude;
i2s_set_clk(_port, self->_wavSampleRate, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
int16_t outBuf[64];
while (remaining > 0) {
uint32_t outSamples = 0;
if (bits == 8) {
uint32_t bytesPerFrame = ch;
while (outSamples < 64 && remaining >= bytesPerFrame) {
int32_t sum = 0;
for (uint16_t c = 0; c < ch; c++) sum += (int32_t)(*src++) - 128;
outBuf[outSamples++] = (int16_t)((int32_t)(sum / (int32_t)ch) * 256 * (int32_t)amp / 32767);
remaining -= bytesPerFrame;
}
} else {
uint32_t bytesPerFrame = (uint32_t)ch * 2;
while (outSamples < 64 && _seqTask method · c · L239-L274 (36 LOC)firmware/src/core/SpeakerI2S.h
static void _seqTask(void* arg) {
auto* self = static_cast<SpeakerI2S*>(arg);
for (uint8_t n = 0; n < self->_seqLen; n++) {
const Note& note = self->_seq[n];
uint32_t total = _sampleRate * note.durationMs / 1000;
uint32_t half = _sampleRate / ((uint32_t)note.freq * 2);
if (half == 0) half = 1;
int16_t buf[64];
uint32_t done = 0;
bool high = true;
uint32_t phase = 0;
while (done < total) {
uint32_t chunk = (total - done) < 64 ? (total - done) : 64;
for (uint32_t i = 0; i < chunk; i++) {
buf[i] = high ? self->_amplitude : -self->_amplitude;
if (++phase >= half) { phase = 0; high = !high; }
}
size_t written;
i2s_write(_port, buf, chunk * sizeof(int16_t), &written, portMAX_DELAY);
done += chunk;
}
if (note.delayMs > 0) {
i2s_zero_dma_buffer(_port);
vTaskDelay(pdMS_TO_TICKS(note.delayMs));
}
}
i2s_zStorageLFS class · c · L10-L112 (103 LOC)firmware/src/core/StorageLFS.h
class StorageLFS : public IStorage
{
public:
bool begin() {
_available = LittleFS.begin(true); // true = format on fail
return _available;
}
bool isAvailable() override { return _available; }
uint64_t totalBytes() override { return _available ? LittleFS.totalBytes() : 0; }
uint64_t usedBytes() override { return _available ? LittleFS.usedBytes() : 0; }
uint64_t freeBytes() override {
uint64_t t = totalBytes(), u = usedBytes();
return (u < t) ? (t - u) : 0;
}
fs::File open(const char* path, const char* mode) override {
if (!_available) return fs::File();
return LittleFS.open(path, mode);
}
bool exists(const char* path) override {
if (!_available) return false;
return LittleFS.exists(path);
}
String readFile(const char* path) override {
if (!_available) return "";
fs::File f = LittleFS.open(path, FILE_READ);
if (!f) return "";
String content = f.readString();
f.close();
return content;
}
bobegin method · c · L13-L17 (5 LOC)firmware/src/core/StorageLFS.h
public:
bool begin() {
_available = LittleFS.begin(true); // true = format on fail
return _available;
}If a scraper extracted this row, it came from Repobility (https://repobility.com)
freeBytes method · c · L22-L25 (4 LOC)firmware/src/core/StorageLFS.h
uint64_t freeBytes() override {
uint64_t t = totalBytes(), u = usedBytes();
return (u < t) ? (t - u) : 0;
}open method · c · L26-L29 (4 LOC)firmware/src/core/StorageLFS.h
fs::File open(const char* path, const char* mode) override {
if (!_available) return fs::File();
return LittleFS.open(path, mode);
}exists method · c · L30-L34 (5 LOC)firmware/src/core/StorageLFS.h
bool exists(const char* path) override {
if (!_available) return false;
return LittleFS.exists(path);
}readFile method · c · L35-L43 (9 LOC)firmware/src/core/StorageLFS.h
String readFile(const char* path) override {
if (!_available) return "";
fs::File f = LittleFS.open(path, FILE_READ);
if (!f) return "";
String content = f.readString();
f.close();
return content;
}writeFile method · c · L44-L53 (10 LOC)firmware/src/core/StorageLFS.h
bool writeFile(const char* path, const char* content) override {
if (!_available) return false;
_makeDir(path);
fs::File f = LittleFS.open(path, FILE_WRITE);
if (!f) return false;
f.print(content);
f.close();
return true;
}deleteFile method · c · L54-L58 (5 LOC)firmware/src/core/StorageLFS.h
bool deleteFile(const char* path) override {
if (!_available) return false;
return LittleFS.remove(path);
}makeDir method · c · L59-L71 (13 LOC)firmware/src/core/StorageLFS.h
bool makeDir(const char* path) override {
if (!_available) return false;
String p = path;
for (int i = 1; i < (int)p.length(); i++) {
if (p[i] == '/') {
String sub = p.substring(0, i);
if (!LittleFS.exists(sub.c_str())) LittleFS.mkdir(sub.c_str());
}
}
if (!LittleFS.exists(path)) return LittleFS.mkdir(path);
return true;
}renameFile method · c · L72-L76 (5 LOC)firmware/src/core/StorageLFS.h
bool renameFile(const char* from, const char* to) override {
if (!_available) return false;
return LittleFS.rename(from, to);
}Source: Repobility analyzer · https://repobility.com
removeDir method · c · L77-L81 (5 LOC)firmware/src/core/StorageLFS.h
bool removeDir(const char* path) override {
if (!_available) return false;
return LittleFS.rmdir(path);
}listDir method · c · L82-L98 (17 LOC)firmware/src/core/StorageLFS.h
uint8_t listDir(const char* path, DirEntry* out, uint8_t max) override {
if (!_available) return 0;
fs::File dir = LittleFS.open(path);
if (!dir) return 0;
uint8_t count = 0;
while (count < max) {
fs::File f = dir.openNextFile();
if (!f) break;
out[count].name = f.name();
out[count].isDir = f.isDirectory();
f.close();
count++;
}
dir.close();
return count;
}_makeDir method · c · L106-L111 (6 LOC)firmware/src/core/StorageLFS.h
void _makeDir(const char* filePath) {
String p = filePath;
int last = p.lastIndexOf('/');
if (last <= 0) return;
makeDir(p.substring(0, last).c_str());
}StorageSD class · c · L10-L103 (94 LOC)firmware/src/core/StorageSD.h
class StorageSD : public IStorage
{
public:
bool begin(uint8_t csPin, SPIClass& spi, uint32_t freq = 4000000) {
_available = SD.begin(csPin, spi, freq);
return _available;
}
bool isAvailable() override { return _available; }
uint64_t totalBytes() override { return _available ? SD.totalBytes() : 0; }
uint64_t usedBytes() override { return _available ? SD.usedBytes() : 0; }
uint64_t freeBytes() override {
uint64_t t = totalBytes(), u = usedBytes();
return (u < t) ? (t - u) : 0;
}
fs::File open(const char* path, const char* mode) override {
if (!_available) return fs::File();
return SD.open(path, mode);
}
bool exists(const char* path) override {
if (!_available) return false;
return SD.exists(path);
}
String readFile(const char* path) override {
if (!_available) return "";
File f = SD.open(path, FILE_READ);
if (!f) return ""; // file not found is not an SD failure
String content = f.readString();
f.cbegin method · c · L13-L17 (5 LOC)firmware/src/core/StorageSD.h
public:
bool begin(uint8_t csPin, SPIClass& spi, uint32_t freq = 4000000) {
_available = SD.begin(csPin, spi, freq);
return _available;
}freeBytes method · c · L22-L25 (4 LOC)firmware/src/core/StorageSD.h
uint64_t freeBytes() override {
uint64_t t = totalBytes(), u = usedBytes();
return (u < t) ? (t - u) : 0;
}open method · c · L26-L29 (4 LOC)firmware/src/core/StorageSD.h
fs::File open(const char* path, const char* mode) override {
if (!_available) return fs::File();
return SD.open(path, mode);
}exists method · c · L30-L33 (4 LOC)firmware/src/core/StorageSD.h
bool exists(const char* path) override {
if (!_available) return false;
return SD.exists(path);
}About: code-quality intelligence by Repobility · https://repobility.com
readFile method · c · L34-L42 (9 LOC)firmware/src/core/StorageSD.h
String readFile(const char* path) override {
if (!_available) return "";
File f = SD.open(path, FILE_READ);
if (!f) return ""; // file not found is not an SD failure
String content = f.readString();
f.close();
return content;
}writeFile method · c · L43-L51 (9 LOC)firmware/src/core/StorageSD.h
bool writeFile(const char* path, const char* content) override {
if (!_available) return false;
File f = SD.open(path, FILE_WRITE);
if (!f) { _available = false; return false; }
f.print(content);
f.close();
return true;
}deleteFile method · c · L52-L56 (5 LOC)firmware/src/core/StorageSD.h
bool deleteFile(const char* path) override {
if (!_available) return false;
return SD.remove(path);
}