-
Notifications
You must be signed in to change notification settings - Fork 0
Improve 2 #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
## Changes Summary ### Code Quality & Architecture - ✅ Add config validation system (1.1) - New: src/config_validator.h - validates all config at startup - Prevents system from starting with missing/invalid configuration - Provides clear error messages for misconfiguration - Validates WiFi SSID/password, server host/port, I2S params, timeouts - ✅ Eliminate magic numbers to config.h (1.3) - Added 12+ new constants for commonly used delays - SERIAL_INIT_DELAY, GRACEFUL_SHUTDOWN_DELAY, ERROR_RECOVERY_DELAY - TCP_KEEPALIVE_*, LOGGER_BUFFER_SIZE, WATCHDOG_TIMEOUT_SEC - TASK_PRIORITY_*, STATE_CHANGE_DEBOUNCE - Improved maintainability and configuration flexibility - ✅ Enhance watchdog configuration validation (2.1) - Validates watchdog timeout doesn't conflict with operation timeouts - Prevents false restarts from misconfigured timeouts - Checks: WATCHDOG_TIMEOUT > WIFI_TIMEOUT > ERROR_RECOVERY_DELAY ### Reliability Enhancements - ✅ Add memory leak detection (2.4) - Track peak heap, min heap, heap trend - Detect decreasing memory patterns (potential leaks) - Enhanced statistics printout with memory analysis - Warn when memory usage trends downward - ✅ Implement extended statistics (4.1) - Peak heap usage since startup - Minimum free heap (lowest point reached) - Heap range and fragmentation analysis - Memory trend detection (stable/increasing/decreasing) - All integrated into periodic stats output ### Documentation (3 comprehensive guides) - ✅ Error Handling Documentation (ERROR_HANDLING.md) - All system states and transitions documented - Error classification (critical vs non-critical) - Recovery flows with state diagrams - Error metrics and statistics tracking - Watchdog timer behavior explained - Future enhancement ideas - ✅ Configuration Guide (CONFIGURATION_GUIDE.md) - All 40+ config parameters explained - Recommended values for different scenarios - Power consumption implications - Board-specific notes (ESP32-Dev vs XIAO S3) - Scenario configs (home lab, production, mobile networks) - Configuration validation explained - ✅ Troubleshooting Guide (TROUBLESHOOTING.md) - Solutions for 30+ common issues - Startup, WiFi, server, audio, memory problems - Build & upload issues - Performance and bandwidth issues - Advanced debugging tips - When all else fails section ### Build & Configuration - Fixed SERVER_PORT type (string to uint16_t) - Added XIAO ESP32-S3 build configuration - Both boards now fully supported in PlatformIO ## Quality Metrics ✅ Build: SUCCESS (RAM: 15%, Flash: 58.7%) ✅ No warnings or errors ✅ Configuration validation passes ✅ Backward compatible with existing configs ## Testing - Full compilation verified for ESP32-DevKit - All config validators pass startup checks - Memory leak detection active - Extended statistics integrated 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
## Improvements (Task 2.2 - MEDIUM PRIORITY) ### Error Classification System - New enum: I2SErrorType (NONE, TRANSIENT, PERMANENT, FATAL) - classifyError() maps ESP errors to error types - TRANSIENT errors: memory pressure, timeout, invalid state - PERMANENT errors: invalid arg, not found, general failure - FATAL: unknown/unrecoverable errors ### Health Check System - healthCheck() method validates I2S subsystem health - Detects excessive consecutive errors - Monitors permanent error rate (threshold: 20%) - Returns health status for proactive monitoring ### Error Tracking - Total error count tracking - Transient vs permanent error categorization - Error counters accessible via getter methods - Better diagnostics for long-term monitoring ### Enhanced Diagnostics - readData() now classifies errors automatically - Graduated recovery strategy based on error type - Improved logging with error type indication - Statistics include error breakdown ### Integration - Enhanced stats output shows error breakdown - Format: "I2S errors: X (total: A, transient: B, permanent: C)" - Helps identify I2S reliability issues early ## Code Changes - src/i2s_audio.h: Added error classification enum and health check methods - src/i2s_audio.cpp: Implemented error classification logic, health checks, tracking - src/main.cpp: Enhanced stats output with error breakdown ## Build Status ✅ SUCCESS - RAM: 15.0% (49,048 / 327,680 bytes) - Flash: 58.7% (769,901 / 1,310,720 bytes) - Compile time: 4.09 seconds 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
## Summary Phase 2 successfully completed with 9 total improvements across 2 phases: ### Phase 1: 8 Improvements (COMPLETE) ✅ Config validation system (1.1) ✅ Error handling documentation (1.2) ✅ Magic numbers elimination (1.3) ✅ Watchdog validation (2.1) ✅ Memory leak detection (2.4) ✅ Extended statistics (4.1) ✅ Configuration guide (7.1) ✅ Troubleshooting guide (7.3) ### Phase 2: 1 Improvement (COMPLETE) ✅ Enhanced I2S error handling (2.2) - Error classification (TRANSIENT/PERMANENT/FATAL) - I2S health check system - Error tracking and statistics - Enhanced diagnostics ## Deliverables - ✅ Production-ready code (400 lines) - ✅ Comprehensive documentation (2,300 lines) - ✅ Zero build warnings/errors - ✅ Memory-efficient implementation - ✅ Backward compatible ## Build Status ✅ SUCCESS - RAM: 15.0% (49,048 bytes) - Flash: 58.7% (769,901 bytes) - Compile time: ~4 seconds ## Ready For ✅ Production deployment ✅ Long-term support ✅ Future enhancements ✅ User distribution ## Future Phases (Ready to implement) - 2.3: TCP Connection State Machine - 4.2: Enhanced Debug Mode - 7.2: Serial Command Interface - 3.1: Dynamic Buffer Management - 6.1: Unit Test Framework 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
… for improved network reliability
…d maintainability - Deleted PHASE2_IMPLEMENTATION_COMPLETE.md and improvements_plan.md as they are no longer needed. - Updated src/config.h to include new configuration options for TCP chunk size and logger rate limiting. - Fixed SERVER_PORT validation in src/config_validator.h to ensure it is treated as an integer and added range checks. - Enhanced I2S driver initialization in src/i2s_audio.cpp to retry without APLL on failure. - Improved logger functionality in src/logger.cpp with rate limiting and token bucket implementation. - Modified main setup in src/main.cpp to initialize logger based on compile-time DEBUG_LEVEL. - Updated network handling in src/network.cpp to implement safe backoff on WiFi connection failures and added socket timeouts for TCP writes. - Removed unnecessary forced WiFi disconnects based on RSSI in network monitoring. - Added comprehensive improvement plan for future enhancements and risk mitigation.
…ing for improved network reliability
- Updated WiFi and server configuration parameters in config.h for improved connectivity. - Added detailed comments on TCP chunk size and server expectations. - Refined logger implementation in logger.cpp for better readability and maintainability. - Introduced error handling macros for socket options in network.cpp to streamline error logging. - Enhanced jitter application logic in apply_jitter function to prevent negative values. - Improved network connection handling with better state management and logging in NetworkManager. - Added diagnostics for the first audio transmission to verify streaming starts correctly. - Cleaned up redundant code and improved overall code structure for better readability.
Summary of ChangesHello @sarpel, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a significant upgrade to the ESP32 Audio Streamer, focusing on making the system more robust, observable, and manageable. It introduces dynamic adjustments to network conditions, enforces configuration integrity, and provides powerful runtime diagnostic tools. The changes aim to enhance the overall stability and maintainability of the embedded audio streaming solution. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a comprehensive set of reliability and monitoring improvements for the ESP32 Audio Streamer v2.0. The changes focus on adding runtime control capabilities, configuration validation, adaptive buffering, enhanced error handling, and improved system observability.
Key Changes:
- Added serial command interface for runtime control and diagnostics (8 commands)
- Implemented configuration validation system to prevent invalid startup
- Added adaptive buffer management based on WiFi signal strength
- Enhanced TCP connection state machine with proper state tracking
- Improved error classification and recovery mechanisms
- Added memory leak detection with heap trend analysis
Reviewed Changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/serial_command.h/cpp | New serial command handler for runtime control (STATUS, STATS, HEALTH, etc.) |
| src/network.h/cpp | Enhanced TCP state machine, adaptive buffering, socket configuration, jitter-based backoff |
| src/main.cpp | Integrated config validation, serial commands, memory trend tracking, watchdog initialization |
| src/logger.cpp | Added rate limiting to prevent log storms |
| src/i2s_audio.h/cpp | Enhanced error classification (transient/permanent/fatal) and health checking |
| src/debug_mode.h/cpp | New runtime debug context for toggling debug output |
| src/config_validator.h | Comprehensive configuration validation at startup |
| src/config.h | Added new constants for timeouts, TCP settings, board detection, watchdog, logging |
| src/adaptive_buffer.h/cpp | RSSI-based adaptive buffer sizing for network reliability |
| src/NonBlockingTimer.h | Added startExpired() method for immediate first trigger |
| platformio.ini | Added Seeed XIAO ESP32-S3 board support |
| README.md | Complete rewrite with quick start guide and command reference |
| .serena/* | Added Serena AI assistant configuration and project memories |
| } else if (WATCHDOG_TIMEOUT_SEC < 30) { | ||
| LOG_WARN("WATCHDOG_TIMEOUT_SEC (%u sec) is short - recommend >= 30 seconds", WATCHDOG_TIMEOUT_SEC); | ||
| } else { | ||
| LOG_INFO(" \u2713 Watchdog timeout: %u seconds", WATCHDOG_TIMEOUT_SEC); |
Copilot
AI
Oct 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unicode character \u2713 (checkmark) is used inconsistently with other validation messages that use the ASCII checkmark '✓'. This creates visual inconsistency in log output.
| LOG_WARN("WATCHDOG_TIMEOUT_SEC (%u) <= WIFI_TIMEOUT (%u sec) - watchdog may reset during WiFi connection", | ||
| WATCHDOG_TIMEOUT_SEC, wifi_timeout_sec); | ||
| } else { | ||
| LOG_INFO(" \u2713 Watchdog timeout compatible with WiFi timeout"); |
Copilot
AI
Oct 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unicode character \u2713 (checkmark) is used inconsistently with other validation messages that use the ASCII checkmark '✓'. This creates visual inconsistency in log output.
| // Calculate jitter range with safety check for negative values | ||
| int32_t jitter_range = (int32_t)(base_ms * SERVER_BACKOFF_JITTER_PCT / 100); | ||
| if (jitter_range < 0) | ||
| { | ||
| jitter_range = 0; // Safety: prevent negative range | ||
| } |
Copilot
AI
Oct 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for negative jitter_range is unnecessary and suggests a logic error. Since base_ms is unsigned long and SERVER_BACKOFF_JITTER_PCT is expected to be positive (0-100), the multiplication and division cannot produce a negative result when cast to int32_t (assuming no overflow). If this is overflow protection, it should explicitly check for overflow conditions rather than negative values.
| // Calculate jitter range with safety check for negative values | |
| int32_t jitter_range = (int32_t)(base_ms * SERVER_BACKOFF_JITTER_PCT / 100); | |
| if (jitter_range < 0) | |
| { | |
| jitter_range = 0; // Safety: prevent negative range | |
| } | |
| // Calculate jitter range | |
| int32_t jitter_range = (int32_t)(base_ms * SERVER_BACKOFF_JITTER_PCT / 100); |
| #if DEBUG_LEVEL >= 4 | ||
| bootLogLevel = LOG_DEBUG; | ||
| #elif DEBUG_LEVEL == 3 | ||
| bootLogLevel = LOG_INFO; | ||
| #elif DEBUG_LEVEL == 2 | ||
| bootLogLevel = LOG_WARN; | ||
| #elif DEBUG_LEVEL == 1 | ||
| bootLogLevel = LOG_ERROR; | ||
| #else | ||
| bootLogLevel = LOG_CRITICAL; | ||
| #endif |
Copilot
AI
Oct 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mapping between DEBUG_LEVEL (0-5) and LogLevel enum is implemented in multiple places (here and in config.h comments). This duplicates logic and can lead to inconsistencies. Consider adding a helper function logLevelFromDebugLevel(int) or ensuring the mapping is documented in a single authoritative location.
| if (_logger_suppressed > 0 && _logger_tokens >= 2.0f) | ||
| { | ||
| _logger_tokens -= 1.0f; | ||
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] %s (%s:%d)\n", | ||
| millis() / 1000, | ||
| "INFO", | ||
| ESP.getFreeHeap(), | ||
| "[logger] Suppressed messages due to rate limiting", | ||
| "logger", | ||
| 0); | ||
| _logger_tokens -= 1.0f; | ||
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] Suppressed count: %u (%s:%d)\n", | ||
| millis() / 1000, | ||
| "INFO", | ||
| ESP.getFreeHeap(), | ||
| _logger_suppressed, | ||
| "logger", | ||
| 0); |
Copilot
AI
Oct 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rate limiter requires 2 tokens to report suppressed messages, but this creates a scenario where if exactly 1-2 tokens are available, messages remain suppressed indefinitely without notification. Consider allowing the suppression report with just 1 token to ensure users are always notified of rate limiting.
| if (_logger_suppressed > 0 && _logger_tokens >= 2.0f) | |
| { | |
| _logger_tokens -= 1.0f; | |
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] %s (%s:%d)\n", | |
| millis() / 1000, | |
| "INFO", | |
| ESP.getFreeHeap(), | |
| "[logger] Suppressed messages due to rate limiting", | |
| "logger", | |
| 0); | |
| _logger_tokens -= 1.0f; | |
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] Suppressed count: %u (%s:%d)\n", | |
| millis() / 1000, | |
| "INFO", | |
| ESP.getFreeHeap(), | |
| _logger_suppressed, | |
| "logger", | |
| 0); | |
| if (_logger_suppressed > 0 && _logger_tokens >= 1.0f) | |
| { | |
| if (_logger_tokens >= 2.0f) { | |
| _logger_tokens -= 1.0f; | |
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] %s (%s:%d)\n", | |
| millis() / 1000, | |
| "INFO", | |
| ESP.getFreeHeap(), | |
| "[logger] Suppressed messages due to rate limiting", | |
| "logger", | |
| 0); | |
| _logger_tokens -= 1.0f; | |
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] Suppressed count: %u (%s:%d)\n", | |
| millis() / 1000, | |
| "INFO", | |
| ESP.getFreeHeap(), | |
| _logger_suppressed, | |
| "logger", | |
| 0); | |
| } else { | |
| _logger_tokens -= 1.0f; | |
| Serial.printf("[%6lu] [%-8s] [Heap:%6u] Suppressed count: %u (%s:%d)\n", | |
| millis() / 1000, | |
| "INFO", | |
| ESP.getFreeHeap(), | |
| _logger_suppressed, | |
| "logger", | |
| 0); | |
| } |
| return 0; // Safety check | ||
| } | ||
|
|
||
| uint16_t raw_score = (current_buffer_size * 100) / optimal_size; |
Copilot
AI
Oct 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential integer overflow when current_buffer_size is large. If current_buffer_size exceeds 655 bytes (for uint16_t max 65535), the multiplication current_buffer_size * 100 could overflow. Consider using uint32_t for intermediate calculation: uint32_t raw_score = ((uint32_t)current_buffer_size * 100) / optimal_size;
| uint16_t raw_score = (current_buffer_size * 100) / optimal_size; | |
| uint32_t raw_score = ((uint32_t)current_buffer_size * 100) / optimal_size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a substantial set of improvements to the ESP32 Audio Streamer project, focusing on enhancing reliability, configurability, and diagnostics. Key additions include a startup configuration validator, a serial command interface for runtime control, a more robust TCP state machine with jittered backoff, detailed memory leak detection, and adaptive network buffering. The codebase is now significantly more resilient with the integration of a watchdog timer, smarter error classification, and rate-limited logging. The documentation has also been completely overhauled, providing a much better user experience.
My review identifies a minor documentation discrepancy and a few small inconsistencies with the project's newly defined coding style for variable and function naming. Addressing these points will further improve the quality and consistency of the codebase.
| STATS - Print system statistics (uptime, bytes sent, memory, errors) | ||
| STATUS - Print current system state | ||
| SIGNAL - Print WiFi RSSI (signal strength) in dBm | ||
| DEBUG [0-5] - Set debug level (0=OFF, 5=VERBOSE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Initialize logger | ||
| Logger::init(LOG_INFO); | ||
| // Initialize logger (align with compile-time DEBUG_LEVEL) | ||
| LogLevel bootLogLevel = LOG_INFO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable bootLogLevel uses camelCase naming. According to the project's style guide (.serena/memories/code_style_conventions.md), variables should use snake_case.1
| LogLevel bootLogLevel = LOG_INFO; | |
| LogLevel boot_log_level = LOG_INFO; |
Style Guide References
Footnotes
-
Variables should be named using
snake_case(e.g.,free_heap,audio_buffer). ↩
| _nb_rng = _nb_rng * 1664525u + 1013904223u; | ||
| return _nb_rng; | ||
| } | ||
| static inline unsigned long apply_jitter(unsigned long base_ms) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function apply_jitter uses snake_case naming. According to the project's style guide (.serena/memories/code_style_conventions.md), functions should use camelCase.1
Please also update the call sites for this function on lines 82 and 192.
static inline unsigned long applyJitter(unsigned long base_ms)Style Guide References
Footnotes
-
Functions should be named using
camelCase(e.g.,gracefulShutdown(),checkMemoryHealth()). ↩
| // TCP_NODELAY: Disable Nagle's algorithm for low-latency streaming | ||
| // Server expects immediate audio chunks without buffering delays | ||
| // This matches server's receiver.py configuration: conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) | ||
| int nodelay = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| int keepAlive = 1; | ||
| int keepIdle = 5; // Start probing after 5s idle | ||
| int keepInterval = 5; // Probe every 5s | ||
| int keepCount = 3; // Drop after 3 failed probes | ||
|
|
||
| setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(keepAlive)); | ||
| setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(keepIdle)); | ||
| setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(keepInterval)); | ||
| setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(keepCount)); | ||
|
|
||
| LOG_DEBUG("TCP keepalive configured"); | ||
| int keepIdle = TCP_KEEPALIVE_IDLE; // seconds | ||
| int keepInterval = TCP_KEEPALIVE_INTERVAL; // seconds | ||
| int keepCount = TCP_KEEPALIVE_COUNT; // count |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These local variables use camelCase naming. According to the project's style guide (.serena/memories/code_style_conventions.md), variables should use snake_case.1
int keep_alive = 1;
int keep_idle = TCP_KEEPALIVE_IDLE; // seconds
int keep_interval = TCP_KEEPALIVE_INTERVAL; // seconds
int keep_count = TCP_KEEPALIVE_COUNT; // countStyle Guide References
Footnotes
-
Variables should be named using
snake_case(e.g.,free_heap,audio_buffer). ↩
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Değişiklik AnaliziWalkthroughBu PR, yazılımın güvenilirliğini artırmak için yapılandırma doğrulaması, uyarlanabilir arabellek yönetimi, TCP bağlantı durumu izleme ve hata sınıflandırması eklemektedir. Belgelendirme yapılandırmasını basitleştirirken, sistem başlangıcı sırasında sistem durumunu kontrol etme olanağı sağlıyor. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Neden? Çok sayıda yeni dosya (ConfigValidator, AdaptiveBuffer), birbirine bağlı state machine mantığı (TCP bağlantı durumları), error classification sistemi ve 40+ yeni yapılandırma makrosu. Her alan farklı değerlendirme mantığı gerektiriyor ve değişiklikler sistem başlangıcından ağ yönetimine kadar uzanıyor. Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/i2s_audio.cpp (1)
71-76: Dönüş değerleri kontrol edilmiyor (i2s_stop / i2s_driver_uninstall).ELI5: “Kapıyı kilitlerken anahtar dönmedi mi, haberimiz olmuyor.” Her hatayı yakalayıp loglayın.
- i2s_stop(I2S_PORT); - i2s_driver_uninstall(I2S_PORT); + { + esp_err_t r1 = i2s_stop(I2S_PORT); + if (r1 != ESP_OK) { LOG_ERROR("i2s_stop failed: %d", r1); } + esp_err_t r2 = i2s_driver_uninstall(I2S_PORT); + if (r2 != ESP_OK) { LOG_ERROR("i2s_driver_uninstall failed: %d", r2); } + }src/main.cpp (1)
309-330: readDataWithRetry potansiyel bloklama: Döngünün akıcılığını koruyun.ELI5: “Topu tek atışta kaleye değil, paslarla götürelim.” Büyük timeout + tekrarlar ana döngüyü tutabilir.
- I2S okumayı kısa timeout ile yapın (örn. 10–20 ms) ve denemeleri NonBlockingTimer ile birkaç loop’a yayın.
- Böylece watchdog ve diğer görevler (WiFi, komutlar) düzenli çalışır.
🧹 Nitpick comments (38)
.gitignore (1)
6-6: Gitignore kurallarında önemli bir mantıksal çelişki var.Bu değişiklikler yeni dizinleri ve dosyaları yok saymakta -
.serena/,docs/,test/gibi. Ama bu PR'da tam da bu dizinlere yeni belge dosyaları ekleniyor! Bu tıpkı bir kütüphanecinin yeni kitapları özenle organize etmesi, ama sonra onları kütüphaneden çıkartmasına benziyor.Eğer bu belge dosyaları (
.serena/memories/) sadece yerel geliştirme için ise, sorun yok. Ama eğer depoyla birlikte kaydedilmeleri gerekiyorsa,.gitignorekurallarını ayarlamanız gerekebilir - örneğin.serena/hariç tutmak yerine sadece.serena/cache/gibi belirli alt dizinleri hariç tutmak.Also applies to: 19-21, 28-28
platformio.ini (1)
1-3: Yeni Seeed XIAO ESP32-S3 ortamı iyi eklendi.PlatformIO'ya yeni bir ortam ekliyorsunuz - tıpkı bir bilgisayarda farklı yazıcı türlerine destek eklemek gibi. Her ortamın kendi ayarları var. Bu, proje açıklamasında sözü edilen XIAO ESP32-S3 desteğiyle eşleşiyor, bu güzel.
Ancak küçük bir best practice notu: her iki ortam da (
esp32devveseeed_xiao_esp32s3) tamamen aynılib_deps,build_flags,test_frameworkvetest_ignoreayarlarına sahip. Eğer bu ayarlar gerçekten her iki pano için de aynıysa, PlatformIO'da paylaşılan ortam kullanarak deduplication yapabilirsiniz.Also applies to: 22-38
src/NonBlockingTimer.h (2)
29-34: startExpired: Sıfır aralığa davranışı netleştirelim.
Hemen tetiklemek için “- interval - 1” hilesi iyi ve millis() taşmasıyla uyumlu. Ancak interval=0 ise sürekli tetik üretebilir. En az 1 ms’e kelepçeleyelim ya da dokümante edelim.As per coding guidelines
- void setInterval(unsigned long intervalMs) + void setInterval(unsigned long intervalMs) { - interval = intervalMs; + if (intervalMs == 0) intervalMs = 1; // en küçük güvenli aralık + interval = intervalMs; }
8-13: İsimlendirme kuralı: üye değişkenlerde snake_case.
Guideline’da değişkenler snake_case. previousMillis/isRunning/autoReset yerine previous_millis/is_running/auto_reset tercih edilebilir. Davranış değişmez, sadece stil uyumu.As per coding guidelines
Also applies to: 15-17
src/network.h (3)
8-9: Header bağımlılığı: adaptive_buffer.h’ı bu header’dan çıkaralım.
Bu dosyada AdaptiveBuffer türünü kullanmıyoruz; yalnızca fonksiyon bildiriyoruz. Bağımlılığı network.cpp’ye taşıyarak derleme zincirini hafifletiriz.As per coding guidelines
-#include "adaptive_buffer.h" +// Not needed in header; included in network.cpp
54-61: TCP state getter’larında tutarlılık.
getTCPState/isTCPConnected validateConnection çağırıyor; isTCPConnecting/isTCPError çağırmıyor. Hepsinde aynı doğrulamayı yapmak “eski” durumu döndürme riskini azaltır.As per coding guidelines
bool isTCPConnecting(); bool isTCPConnected(); bool isTCPError(); +// (Öneri) Bu iki fonksiyonda da validateConnection() çağırmayı düşünün.
71-77: Gözlem metrikleri: getTimeInState faydalı olabilir.
tcp_state_change_time zaten tutuluyor; bir getTimeInState() eklemek teşhis için iş görür (seri komutlarında güzel olur). İsteğe bağlı.As per coding guidelines
src/logger.cpp (2)
37-45: delay(1000): Bloklamayı ve sabit süreyi kaldıralım.
Init’te bile olsa hard‑coded delay guideline’a aykırı. Süreyi config.h’dan alıp (ör. LOGGER_SERIAL_INIT_DELAY_MS) mümkünse NonBlockingTimer ile bekleyelim veya Serial bağlantısı hazırsa hiç beklemeyelim.As per coding guidelines
void Logger::init(LogLevel level) { min_level = level; Serial.begin(115200); - delay(1000); + #ifdef LOGGER_SERIAL_INIT_DELAY_MS + if (LOGGER_SERIAL_INIT_DELAY_MS > 0) delay(LOGGER_SERIAL_INIT_DELAY_MS); + #endif _logger_tokens = LOGGER_BURST_MAX; _logger_last_refill_ms = millis(); _logger_suppressed = 0; }
18-35: Token bucket doldurma: Mantık temiz görünüyor.
ms tabanlı yenileme ve burst kelepçesi net. ESP32’de float kabul edilebilir; istersek ileride fixed‑point’e geçilebilir.src/adaptive_buffer.h (2)
6-24: Genel API net; magic number’ları config’e taşıyalım.
adaptive_buffer.cpp’de 5000 ms aralık, %10 eşik ve 256 byte minimum sabitleri var. Bunları config.h’da isimlendirilmiş sabitler yapalım (örn. ADAPTIVE_BUF_MIN_ADJ_INTERVAL_MS, ADAPTIVE_BUF_MIN_CHANGE_PCT, ADAPTIVE_BUF_MIN_SIZE). Böylece ayar/tuningle uyumlu olur.As per coding guidelines
25-34: Başlangıç RSSI’si için makul varsayılan.
initialize içinde last_rssi’yi -80 dBm’e kurmak (orta/“acceptable”) verim skorunda daha anlamlı başlangıç verir.// in AdaptiveBuffer::initialize -// last_rssi untouched +last_rssi = -80;src/debug_mode.h (2)
9-38: LOG_ makrolarına bağımlılık: logger.h ekleyelim.*
Bu header LOG_ERROR/WARN/INFO/DEBUG makrolarını kullanıyor. Dahil sırası sorunlarına girmemek için logger.h’yı burada da include edelim.As per coding guidelines
#ifndef DEBUG_MODE_H #define DEBUG_MODE_H -// Debug level control +// Debug level control +#include "logger.h"
40-54: RuntimeDebugContext::log seviye denetimi yapmıyor.
enabled kontrolü var ama level dikkate alınmıyor. Runtime seviyesine göre filtreleyelim ve mümkünse Logger üzerinden yönlendirelim (rate‑limit ve format tutarlılığı için).As per coding guidelines
// in debug_mode.cpp -void RuntimeDebugContext::log(const char* fmt, ...) { - if (!enabled) return; +void RuntimeDebugContext::log(const char* fmt, ...) { + if (!enabled) return; + // örn: level >= 4 ise DEBUG seviyesinde logla + if (level < 4) return; va_list args; va_start(args, fmt); - char buffer[256]; - vsnprintf(buffer, sizeof(buffer), fmt, args); - Serial.println(buffer); + char buffer[256]; + vsnprintf(buffer, sizeof(buffer), fmt, args); + LOG_DEBUG("%s", buffer); va_end(args); }src/config_validator.h (2)
6-6: Kullanılmayan include.
std::string kullanılmıyor; kaldırabiliriz.As per coding guidelines
-#include <string>
54-61: ASCII dışı karakterler ve tür tutarlılığı.
✓/✗ işaretleri bazı terminallerde garip görünebilir; isterseniz ASCII alternatif kullanın. Ayrıca olası unsigned makrolar için “<= 0” yerine “== 0” kontrolleri daha nettir (niyetinizi anlatır).As per coding guidelines
Also applies to: 70-111, 117-166, 172-218, 224-251, 256-299, 304-346
src/debug_mode.cpp (2)
36-39: Sihirli sayı 256 yerine config sabiti kullanın ve kesilmeyi raporlayın.ELI5: “Kutuyu 256’lık yaptık ama neden 256 olduğunu kimse bilmiyor.” Sabitleyin ve taşma olursa uyarın.
Önerilen değişiklikler:
- char buffer[256]; - vsnprintf(buffer, sizeof(buffer), fmt, args); - Serial.println(buffer); + char buffer[RUNTIME_DEBUG_BUFFER_SIZE]; + int n = vsnprintf(buffer, sizeof(buffer), fmt, args); + if (n < 0) { + LOG_ERROR("Runtime debug format hatası"); + } else { + if ((size_t)n >= sizeof(buffer)) { + LOG_WARN("Runtime debug mesajı kesildi (>%u bayt)", (unsigned)sizeof(buffer)); + } + // Tek çıkış noktası: Logger ile tutarlılık veya Serial; proje standardına göre seçin + Serial.println(buffer); + }config.h için ek (dosya dışı):
// config.h #ifndef RUNTIME_DEBUG_BUFFER_SIZE #define RUNTIME_DEBUG_BUFFER_SIZE 256 #endif
30-42: Logger ile tutarlılık: Serial yerine Logger’ı kullanmayı değerlendirin.ELI5: “Diğer herkes kapıdan (Logger) giriyor, bu fonksiyon pencereden (Serial) atlıyor.” Seviye/oran sınırlaması kaçıyor.
- En azından
Logger’a düşük seviye (LOG_DEBUG) yolu ekleyin ya daRuntimeDebugContextiçinde mini bir oran sınırlayıcı kullanın.Proje kararınız: Runtime debug, Logger’ı kasıtlı mı baypas ediyor? Netleştirir misiniz?
src/i2s_audio.h (1)
8-14: Genel olarak iyi tasarım; birkaç küçük iyileştirme önerisi.ELI5: “Hataları sınıflara ayırmanız süper; sayacı da eklemişsiniz. Küçük etiketler ekleyelim.”
- Sağlık eşiği sabitlerini config.h’a taşıyın (örn. I2S_HEALTH_MIN_ERRORS, I2S_HEALTH_PERM_ERR_PCT).
- Dışarıya açık sayaçlar için kısa dokümantasyon yorumu ekleyin (ne zaman sıfırlanır?).
Also applies to: 25-31, 35-37
.serena/memories/implementation_completion.md (1)
82-87: Kalan işler listesi gerçek durumu yansıtmayabilir.ELI5: “Listenizde ‘I2S hata işleme’ eksik diyor ama kargo az önce geldi (classifyError/healthCheck var).”
- “Enhanced I2S error handling” maddesini güncelleyin ya da kısmi tamamlandı olarak işaretleyin.
src/i2s_audio.cpp (2)
86-103: readData başarısında/başarısızlığında bytes_read sıfırlaması.ELI5: “Kavanozu boş döndürürsek (hata), içindeki sayacı da sıfır yapalım.” Daha güvenli sözleşme.
- if (result != ESP_OK) { + if (result != ESP_OK) { + if (bytes_read) *bytes_read = 0; ... } ... - if (*bytes_read == 0) { + if (bytes_read && *bytes_read == 0) { LOG_WARN("I2S read returned 0 bytes"); ... }Also applies to: 105-113
197-220: Sağlık eşiğinde sihirli sayılar (100 toplam, %20 kalıcı).ELI5: “Termostatı 20°C’ye bantla yazmışız; ayar düğmesi yok.” config.h’a taşıyın.
- if (total_errors > 100 && (permanent_errors * 100 / total_errors) > 20) { + if (total_errors > I2S_HEALTH_MIN_ERRORS && + (permanent_errors * 100 / total_errors) > I2S_HEALTH_PERM_ERR_PCT) {config.h ekleri (dosya dışı):
#define I2S_HEALTH_MIN_ERRORS 100u #define I2S_HEALTH_PERM_ERR_PCT 20usrc/main.cpp (3)
52-59: Heap trend eşiği (1000 bayt) sihirli sayı; config.h’a taşıyın.ELI5: “1000 iyi midir, 800 mü; bilinmiyor.” Ayarlanabilir yapalım.
- if (current_heap < last_heap - 1000) { + if (current_heap < last_heap - MEMORY_TREND_DELTA) { heap_trend = -1; // Decreasing - potential leak - } else if (current_heap > last_heap + 1000) { + } else if (current_heap > last_heap + MEMORY_TREND_DELTA) { heap_trend = 1; // Increasing - memory recovered } else { heap_trend = 0; // Stable }config.h ek (dosya dışı):
#define MEMORY_TREND_DELTA 1000u
149-167: gracefulShutdown içinde sabit 1000 ms gecikme.ELI5: “Uyku süresini saatten değil hislere göre ayarlamışız.” Kılavuz: sabitler config.h’tan gelmeli.
- delay(1000); + delay(GRACEFUL_SHUTDOWN_POST_DELAY);config.h ek (dosya dışı):
#define GRACEFUL_SHUTDOWN_POST_DELAY 1000u
135-138: Unicode ok (→) seride garip görünebilir.ELI5: “Bazı terminaller ‘ok’ işaretini kare kutu gösterir.” ASCII kullanmak daha güvenli.
- LOG_INFO("State transition: %s → %s", + LOG_INFO("State transition: %s -> %s",README.md (1)
33-42: Donanım bağlantıları tablo olmalı.MD yönergelerinize göre yapılandırılmış veriler tabloda gösterilmeli. Kablolama eşlemelerini tabloya dönüştürün.
Örnek (ESP32-DevKit):
| INMP441 | ESP32 | |--------:|:-----:| | CLK | GPIO14| | WS | GPIO15| | SD | GPIO32| | GND | GND | | VCC | 3V3 |Also applies to: 44-53
src/adaptive_buffer.cpp (2)
18-31: Sihirli sayıları config.h’a taşıyın; adlandırılmış sabitler kullanın.RSSI eşikleri, yüzdeler, minimum boyut (256), ayarlama aralığı (5000 ms) ve log eşiği (≥10%) sabitler olmalı. Bu, bakım ve ayar kolaylığı sağlar.
Örnek diff (temsilî):
+#include "config.h" // RSSI-based buffer sizing... -// Strong -60,... and %50/%75/%120/%150... +// Eşikler ve yüzdeler config.h'da: +// RSSI_STRONG_THRESH, RSSI_GOOD_THRESH, RSSI_OK_THRESH, RSSI_WEAK_THRESH +// ADAPT_BUF_PCT_STRONG, ..._GOOD, ..._OK, ..._WEAK, ..._VWEAK +// ADAPT_BUF_MIN_SIZE, ADAPT_BUF_MIN_INTERVAL_MS, ADAPT_BUF_LOG_THRESHOLD_PCT - if (rssi >= -60) { new_size = (base_buffer_size * 50) / 100; } - else if (rssi >= -70) { new_size = (base_buffer_size * 75) / 100; } - else if (rssi >= -80) { new_size = base_buffer_size; } - else if (rssi >= -90) { new_size = (base_buffer_size * 120) / 100; } - else { new_size = (base_buffer_size * 150) / 100; } + if (rssi >= RSSI_STRONG_THRESH) { new_size = (base_buffer_size * ADAPT_BUF_PCT_STRONG) / 100; } + else if (rssi >= RSSI_GOOD_THRESH) { new_size = (base_buffer_size * ADAPT_BUF_PCT_GOOD) / 100; } + else if (rssi >= RSSI_OK_THRESH) { new_size = (base_buffer_size * ADAPT_BUF_PCT_OK) / 100; } + else if (rssi >= RSSI_WEAK_THRESH) { new_size = (base_buffer_size * ADAPT_BUF_PCT_WEAK) / 100; } + else { new_size = (base_buffer_size * ADAPT_BUF_PCT_VWEAK) / 100; } - if (new_size < 256) { new_size = 256; } + if (new_size < ADAPT_BUF_MIN_SIZE) { new_size = ADAPT_BUF_MIN_SIZE; } - if (now - last_adjustment_time < 5000) { return; } + if (now - last_adjustment_time < ADAPT_BUF_MIN_INTERVAL_MS) { return; } - if (new_size != current_buffer_size) { - int change_pct = ((int)new_size - (int)current_buffer_size) * 100 / (int)current_buffer_size; - if (abs(change_pct) >= 10) { + if (new_size != current_buffer_size) { + long delta = (long)new_size - (long)current_buffer_size; + int change_pct = (int)( (delta * 100L) / (long)current_buffer_size ); + if (abs(change_pct) >= ADAPT_BUF_LOG_THRESHOLD_PCT) { LOG_DEBUG("Buffer size adjusted: %u → %u bytes (%d%%) for RSSI %d dBm", current_buffer_size, new_size, change_pct, rssi); current_buffer_size = new_size; adjustment_count++; last_adjustment_time = now; } }Also applies to: 35-59, 61-66, 74-80, 83-97
74-80: Küçük değişimlerde de pencereyi kısmen kilitleyin.<10% değişimde ayar uygulanmıyor; yine de her çağrıda hesap yapılıyor. CPU titreşimini azaltmak için “hiç değişmese” de son denetim zamanını güncellemeyi düşünebilirsiniz.
Örnek:
- if (new_size != current_buffer_size) { + if (new_size != current_buffer_size) { ... - } + } else { + last_adjustment_time = now; // küçük dalgalanmalarda da bekleme penceresini yenile + }Also applies to: 83-97
src/serial_command.h (3)
4-4: Clang uyarısı: Arduino.h bulunamadı — platforma koşullu derleme ekleyin.Yerel statik analizde bu başlık yok; derleme hedefi Arduino/PlatformIO’da sorun değil. Yine de koruma eklemek hata gürültüsünü azaltır.
-#include <Arduino.h> +#ifdef ARDUINO + #include <Arduino.h> +#else + #include <cstddef> // size_t için, host analizinde +#endif“Arduino ortamında derlendiğini” doğrular mısınız?
16-18: BUFFER_SIZE’ı config.h’dan alalım.Sabitleri merkezî konumda tutmak için
SERIAL_CMD_BUFFER_SIZEgibi bir makroya taşıyın.- static const size_t BUFFER_SIZE = 128; + static const size_t BUFFER_SIZE = SERIAL_CMD_BUFFER_SIZE;
34-34: Kullanılmayan bildirim: getNextToken.Tanımı yok ve kullanılmıyor; kaldırın ya da uygulayın.
- static char* getNextToken(char* str, const char* delim);src/serial_command.cpp (4)
45-53: Tüm girdiyi büyük harfe çevirmek argümanları da bozuyor.Sadece komutu (ve gerekiyorsa alt komutu) büyük harfe çevirin; argümanları olduğu gibi bırakın (örn. host isimleri, dosya adları).
- // Convert to uppercase for case-insensitive comparison - for (size_t i = 0; i < buffer_index; i++) { - command_buffer[i] = toupper(command_buffer[i]); - } + // Sadece komutu büyük harfe çevir + for (char* p = cmd; *p; ++p) { *p = (char)toupper((unsigned char)*p); } - if (buffer_index < BUFFER_SIZE - 1) { + if (buffer_index < BUFFER_SIZE - 1) { command_buffer[buffer_index++] = c; Serial.write(c); // Echo character }Also applies to: 82-86
174-178: Bloklayan gecikme yerine sabit ve/veya zamanlayıcı kullanın.
delay(3000)ana döngüyü durdurur. Süreyi config.h’da sabitleyin veya NonBlockingTimer ile planlayın.- LOG_CRITICAL("Restarting system in 3 seconds..."); - delay(3000); + LOG_CRITICAL("Restarting system..."); + // Tercih 1: hemen yeniden başlat + // Tercih 2: NonBlockingTimer ile gecikmeli yeniden başlatmayı planlayın (önerilir) ESP.restart();“Gecikmeli yeniden başlatma” istiyorsanız
RESTART_DELAY_MSsabiti ve NonBlockingTimer ile yardımcı fonksiyon ekleyebilirim.
156-158: toupper kullanımında signed/unsigned güvenliği.
charimzasına bağlı UB’i önlemek için(unsigned char)’a dökün.- for (size_t i = 0; subcmd[i]; i++) { - subcmd[i] = toupper(subcmd[i]); - } + for (size_t i = 0; subcmd[i]; i++) { + subcmd[i] = (char)toupper((unsigned char)subcmd[i]); + }
231-241: ASCII dışı log simgeleri bazı terminallerde bozuluyor.✔/⚠/✗ yerine düz metin kullanmanız daha evrensel olur.
- LOG_INFO("✓ WiFi Connected - Signal: %d dBm", rssi); + LOG_INFO("WiFi Connected - Signal: %d dBm", rssi); ... - LOG_WARN(" ⚠ Weak signal - consider relocating device"); + LOG_WARN("Weak signal - consider relocating device"); ... - LOG_ERROR("✗ WiFi Not Connected"); + LOG_ERROR("WiFi Not Connected");Also applies to: 243-249
src/network.cpp (3)
262-291: Düşük seviye setsockopt çağrılarını yüksek seviyeli API ile destekleyin.
WiFiClient::fd()her çekirdekte garanti değil; mümkünseclient.setNoDelay(true)ve varsaclient.setKeepAlive(...)ile tamamlayın.fd()<0ya da derleyici desteği yoksa yalnızca yüksek seviyeli API’yi kullanın.Örnek (koşullu):
- int sockfd = client.fd(); - if (sockfd >= 0) - { + int sockfd = -1; + #ifdef HAS_WIFI_CLIENT_FD + sockfd = client.fd(); + #endif + // Her durumda mümkünse üst seviye ayarları da uygula + client.setNoDelay(true); + #ifdef HAS_WIFI_CLIENT_KEEPALIVE + client.setKeepAlive(TCP_KEEPALIVE_IDLE, TCP_KEEPALIVE_INTERVAL, TCP_KEEPALIVE_COUNT); + #endif + if (sockfd >= 0) { int nodelay = 1; SET_SOCKOPT(sockfd, IPPROTO_TCP, TCP_NODELAY, nodelay); ... }Doğrulama: Kullandığınız ESP32 Arduino çekirdeğinde
WiFiClient::fd()vesetKeepAlivemevcut mu?
185-197: WiFi geri çekilme (backoff) sihirli sayıları sabitleyin.
1000ULve30000ULdeğerlerini config.h sabitleriyle değiştirin (örn.WIFI_RETRY_BACKOFF_BASE_MS,WIFI_RETRY_BACKOFF_MAX_MS).- unsigned long backoff = 1000UL * (wifi_retry_count - WIFI_MAX_RETRIES); - if (backoff > 30000UL) - backoff = 30000UL; + unsigned long backoff = WIFI_RETRY_BACKOFF_BASE_MS * (wifi_retry_count - WIFI_MAX_RETRIES); + if (backoff > WIFI_RETRY_BACKOFF_MAX_MS) + backoff = WIFI_RETRY_BACKOFF_MAX_MS;
74-83: min kullanımı için tür güvenliği.Makro/şablon karışmasını önlemek adına
std::min(veya açık dönüş türüne uygun yardımcı) kullanın.- current_delay = min(current_delay * 2, max_delay); + current_delay = (std::min)(current_delay * 2, max_delay);Gerekirse
<algorithm>ekleyin.src/config.h (1)
102-105: Debug seviyesi iyi açıklanmış, ama varsayılan değer üzerine düşünelim! 🤔Debug seviyeleri çok güzel açıklanmış - her seviye ne anlama geliyor belli. Ancak şu önemli bir nokta var:
Şu anda
DEBUG_LEVEL = 3(INFO) olarak ayarlanmış ve yorum "production için 0 yap" diyor. Ama tersini düşün:
- Bir geliştirici bu kodu üretim ortamına yüklerken, değiştirmeyi unutabilir
- O zaman üretim sistemi çok fazla log basacak - performans kaybı ve gereksiz depolama
Daha güvenli yaklaşım: Varsayılanı
DEBUG_LEVEL = 1(ERROR) veya0(OFF) yapmak. Geliştirme sırasında kasıtlı olarak artırmak, yanlışlıkla azaltmayı unutmaktan daha güvenli!Alternatif: Belki bir
#ifdef PRODUCTIONkoşulu ile otomatik olarak seviye 0'a çekilebilir?Şu değişikliği değerlendir:
// ===== Debug Configuration ===== // Compile-time debug level (0=OFF, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=VERBOSE) -// Set to 0 for production (minimal logging), 3+ for development -#define DEBUG_LEVEL 3 +// Default to ERROR level; increase to 3+ for development debugging +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL 1 // ERROR level - production-safe default +#endifBu şekilde geliştirici derlemeden önce
-DDEBUG_LEVEL=3ile override edebilir, ama varsayılan üretim için güvenli olur.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
.gitignore(1 hunks).serena/.gitignore(1 hunks).serena/memories/code_style_conventions.md(1 hunks).serena/memories/implementation_completion.md(1 hunks).serena/memories/project_overview.md(1 hunks).serena/memories/suggested_commands.md(1 hunks).serena/memories/task_completion_checklist.md(1 hunks).serena/project.yml(1 hunks)README.md(1 hunks)platformio.ini(1 hunks)src/NonBlockingTimer.h(1 hunks)src/adaptive_buffer.cpp(1 hunks)src/adaptive_buffer.h(1 hunks)src/config.h(1 hunks)src/config_validator.h(1 hunks)src/debug_mode.cpp(1 hunks)src/debug_mode.h(1 hunks)src/i2s_audio.cpp(4 hunks)src/i2s_audio.h(2 hunks)src/logger.cpp(2 hunks)src/main.cpp(11 hunks)src/network.cpp(6 hunks)src/network.h(3 hunks)src/serial_command.cpp(1 hunks)src/serial_command.h(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{c,cpp,h,hpp,ino}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{c,cpp,h,hpp,ino}: Constants and macro defines must use UPPER_SNAKE_CASE (e.g., WIFI_SSID, I2S_SAMPLE_RATE)
Function names must use camelCase (e.g., gracefulShutdown, checkMemoryHealth)
Variable names must use snake_case (e.g., free_heap, audio_buffer)
Class/struct names must use PascalCase (e.g., SystemStats, StateManager)
Place all includes at the top of the file, grouped in logical sections
Declare functions before globals
Use section separators as comments: // ===== Section Name =====
Prefer static buffers over heap allocation
Consume timing values only via constants from config.h; do not use hardcoded delays/timeouts
Use Arduino fixed-width types (uint8_t, uint32_t, unsigned long)
Prefer millis() over delay() for timing to keep code non-blocking
Log all state transitions and errors using LOG_INFO, LOG_WARN, LOG_ERROR, LOG_CRITICAL
Classify errors into TRANSIENT, PERMANENT, or FATAL and handle accordingly
Prefer static allocation; monitor heap usage, warn at 40KB free and critical at 20KB; track peak and minimum heap
Use non-blocking timers (e.g., NonBlockingTimer) instead of delay() for periodic work
Periodically validate system state matches actual hardware/network state and correct mismatches
Implement features with comprehensive error handling per the error template
Add logging at key points of new code paths
Do not use hardcoded delays or timeouts; rely on constants and non-blocking timers
Avoid allocating large buffers on the heap
Never ignore error return values; always check and handle
Never log WiFi passwords or other sensitive secrets
Do not assume WiFi/TCP is always connected; check actual connection state before use
Avoid introducing magic numbers; use named constants (preferably in config.h)
Ensure all error paths log appropriately before returning/failing
Use // for inline comments and /* */ for block comments sparingly; prefer section headers // ===== Section Name =====
Files:
src/config_validator.hsrc/logger.cppsrc/network.hsrc/adaptive_buffer.hsrc/debug_mode.hsrc/adaptive_buffer.cppsrc/main.cppsrc/i2s_audio.cppsrc/i2s_audio.hsrc/serial_command.hsrc/serial_command.cppsrc/debug_mode.cppsrc/NonBlockingTimer.hsrc/network.cppsrc/config.h
src/config_validator.h
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When adding features, add configuration validation to src/config_validator.h
Files:
src/config_validator.h
**/*.md
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.md: Keep Markdown line length ~100 characters
Use tables for structured data in Markdown
Include examples for complex topics in Markdown docs
Link to related documentation from Markdown files
Files:
README.md
README.md
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Maintain the project overview in README.md
Files:
README.md
src/main.{cpp,ino}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/main.{cpp,ino}: Feed the watchdog every loop iteration: esp_task_wdt_reset() should be the first statement in loop()
Validate all configuration at startup using ConfigValidator::validateAll() and halt on failure
Do not block the main loop for more than 1 second
Do not start with invalid configuration; refuse to run until validation passes
Files:
src/main.cpp
src/serial_command.cpp
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow the serial command pattern demonstrated in src/serial_command.cpp for new commands (banner, parse, execute, summarize)
Files:
src/serial_command.cpp
src/config.h
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/config.h: All timeouts and delays must be defined as constants in config.h (no magic numbers)
When adding features, add configuration constants to src/config.h
Files:
src/config.h
🧠 Learnings (7)
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/config_validator.h : When adding features, add configuration validation to src/config_validator.h
Applied to files:
src/config_validator.h
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/main.{cpp,ino} : Validate all configuration at startup using ConfigValidator::validateAll() and halt on failure
Applied to files:
src/config_validator.h
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/main.{cpp,ino} : Do not start with invalid configuration; refuse to run until validation passes
Applied to files:
src/config_validator.h
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/serial_command.cpp : Follow the serial command pattern demonstrated in src/serial_command.cpp for new commands (banner, parse, execute, summarize)
Applied to files:
src/serial_command.hsrc/serial_command.cpp
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to **/*.{c,cpp,h,hpp,ino} : Use non-blocking timers (e.g., NonBlockingTimer) instead of delay() for periodic work
Applied to files:
src/NonBlockingTimer.h
📚 Learning: 2025-10-21T00:07:29.906Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.906Z
Learning: Implement an explicit state machine with states: INITIALIZING, CONNECTING_WIFI, CONNECTING_SERVER, CONNECTED, ERROR
Applied to files:
src/network.cpp
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/config.h : All timeouts and delays must be defined as constants in config.h (no magic numbers)
Applied to files:
src/config.h
🧬 Code graph analysis (9)
src/network.h (1)
src/network.cpp (40)
updateAdaptiveBuffer(525-530)updateAdaptiveBuffer(525-525)getAdaptiveBufferSize(532-535)getAdaptiveBufferSize(532-532)connectToServer(229-311)connectToServer(229-229)disconnectFromServer(313-327)disconnectFromServer(313-313)isServerConnected(329-340)isServerConnected(329-329)getClient(342-345)getClient(342-342)getTCPState(482-486)getTCPState(482-482)isTCPConnecting(488-491)isTCPConnecting(488-488)isTCPConnected(493-497)isTCPConnected(493-493)isTCPError(499-502)isTCPError(499-499)getTimeSinceLastWrite(504-507)getTimeSinceLastWrite(504-504)getConnectionUptime(509-516)getConnectionUptime(509-509)writeData(347-384)writeData(347-347)getWiFiReconnectCount(386-389)getWiFiReconnectCount(386-386)getServerReconnectCount(391-394)getServerReconnectCount(391-391)getTCPErrorCount(396-399)getTCPErrorCount(396-396)getTCPStateChangeCount(518-521)getTCPStateChangeCount(518-518)handleTCPError(443-457)handleTCPError(443-443)updateTCPState(423-441)updateTCPState(423-423)validateConnection(459-480)validateConnection(459-459)
src/adaptive_buffer.h (2)
src/adaptive_buffer.cpp (14)
initialize(11-16)initialize(11-11)updateBufferSize(70-98)updateBufferSize(70-70)getBufferSize(100-103)getBufferSize(100-100)getEfficiencyScore(105-124)getEfficiencyScore(105-105)getLastRSSI(126-129)getLastRSSI(126-126)getAdjustmentCount(131-134)getAdjustmentCount(131-131)calculateBufferSize(18-68)calculateBufferSize(18-18)src/network.cpp (2)
initialize(110-149)initialize(110-110)
src/debug_mode.h (1)
src/debug_mode.cpp (10)
setEnabled(8-15)setEnabled(8-8)isEnabled(17-19)isEnabled(17-17)setLevel(21-24)setLevel(21-21)getLevel(26-28)getLevel(26-26)log(30-42)log(30-30)
src/adaptive_buffer.cpp (1)
src/network.cpp (2)
initialize(110-149)initialize(110-110)
src/main.cpp (4)
src/network.cpp (8)
getWiFiReconnectCount(386-389)getWiFiReconnectCount(386-386)getServerReconnectCount(391-394)getServerReconnectCount(391-391)getTCPErrorCount(396-399)getTCPErrorCount(396-396)initialize(110-149)initialize(110-110)src/i2s_audio.cpp (8)
getErrorCount(222-224)getErrorCount(222-222)getTransientErrorCount(226-228)getTransientErrorCount(226-226)getPermanentErrorCount(230-232)getPermanentErrorCount(230-230)initialize(10-66)initialize(10-10)src/logger.cpp (2)
init(37-45)init(37-37)src/serial_command.cpp (4)
initialize(14-17)initialize(14-14)processCommands(19-87)processCommands(19-19)
src/i2s_audio.h (1)
src/i2s_audio.cpp (10)
healthCheck(197-220)healthCheck(197-197)classifyError(160-195)classifyError(160-160)getErrorCount(222-224)getErrorCount(222-222)getTransientErrorCount(226-228)getTransientErrorCount(226-226)getPermanentErrorCount(230-232)getPermanentErrorCount(230-230)
src/serial_command.h (2)
src/network.h (1)
NetworkManager(37-95)src/serial_command.cpp (26)
initialize(14-17)initialize(14-14)processCommands(19-87)processCommands(19-19)handleStatusCommand(89-93)handleStatusCommand(89-89)handleConfigCommand(142-172)handleConfigCommand(142-142)handleRestartCommand(174-178)handleRestartCommand(174-174)handleDisconnectCommand(180-184)handleDisconnectCommand(180-180)handleConnectCommand(186-193)handleConnectCommand(186-186)handleStatsCommand(195-223)handleStatsCommand(195-195)handleHealthCommand(225-229)handleHealthCommand(225-225)handleHelpCommand(278-289)handleHelpCommand(278-278)printStatus(95-140)printStatus(95-95)printHealth(231-276)printHealth(231-231)clearBuffer(291-294)clearBuffer(291-291)
src/serial_command.cpp (1)
src/network.cpp (24)
initialize(110-149)initialize(110-110)isWiFiConnected(201-204)isWiFiConnected(201-201)getTCPState(482-486)getTCPState(482-482)getConnectionUptime(509-516)getConnectionUptime(509-509)getWiFiReconnectCount(386-389)getWiFiReconnectCount(386-386)getServerReconnectCount(391-394)getServerReconnectCount(391-391)getTCPErrorCount(396-399)getTCPErrorCount(396-396)getTCPStateChangeCount(518-521)getTCPStateChangeCount(518-518)disconnectFromServer(313-327)disconnectFromServer(313-313)connectToServer(229-311)connectToServer(229-229)isTCPConnected(493-497)isTCPConnected(493-493)getTimeSinceLastWrite(504-507)getTimeSinceLastWrite(504-504)
src/network.cpp (2)
src/network.h (1)
ExponentialBackoff(20-34)src/adaptive_buffer.cpp (6)
initialize(11-16)initialize(11-11)updateBufferSize(70-98)updateBufferSize(70-70)getBufferSize(100-103)getBufferSize(100-100)
🪛 Clang (14.0.6)
src/adaptive_buffer.h
[error] 4-4: 'Arduino.h' file not found
(clang-diagnostic-error)
src/debug_mode.h
[error] 41-41: unknown type name 'class'
(clang-diagnostic-error)
[error] 41-41: expected ';' after top level declarator
(clang-diagnostic-error)
src/serial_command.h
[error] 4-4: 'Arduino.h' file not found
(clang-diagnostic-error)
🪛 markdownlint-cli2 (0.18.1)
README.md
5-5: No empty links
(MD042, no-empty-links)
6-6: No empty links
(MD042, no-empty-links)
7-7: No empty links
(MD042, no-empty-links)
8-8: No empty links
(MD042, no-empty-links)
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
46-46: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
89-89: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
131-131: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
138-138: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
145-145: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
152-152: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
158-158: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
166-166: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
191-191: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔍 Remote MCP
I'll search for relevant context to help review this ESP32 audio streaming PR effectively.Based on the context gathered, here is a concise summary of relevant facts for reviewing this ESP32 audio streaming pull request:
Key Technical Context
WiFi RSSI-Based Buffer Management
The ESP32 can use RSSI (Received Signal Strength Indicator) values to determine WiFi connection quality and take appropriate actions such as buffering adjustments or network switching. The PR's adaptive buffer implementation aligns with this pattern. RSSI values range from 0 to -120 dBm, with the implementation mapping ranges to dynamic buffer sizes capped at 150% of base size—a reasonable approach for handling weak signal conditions.
I2S Audio Error Classification
The PR's error classification scheme (TRANSIENT, PERMANENT, FATAL) addresses common I2S challenges on ESP32. I2S is used for transmitting audio data between digital audio devices, with ESP32 containing two I2S peripherals that can be configured to input/output sample data via the I2S driver. Distinguishing error types helps determine recovery strategies appropriate to each failure mode.
Board Support (XIAO ESP32-S3)
The PR introduces support for Seeed XIAO ESP32-S3 with conditional pin mappings. This is significant as not all ESP32 variants support identical I2S peripherals—proper board detection via BOARD_XIAO_ESP32S3 macros prevents runtime failures.
Configuration Validation at Startup
The new ConfigValidator class validates WiFi, server, I2S, timing, memory thresholds, and watchdog settings at boot. This follows embedded systems best practice: the main job of startup code is to correctly initialize RAM sections, with the C Standard requiring all .data sections to be initialized before calling main(). Early validation catches configuration errors before runtime and logs critical issues.
Serial Command Handler Interface
The PR adds runtime serial commands for system diagnostics and control. Best practices for serial protocols include start patterns, message length, checksums, and optional sequence numbers. The implementation provides interactive status/health/config commands suitable for debugging connected devices.
TCP Optimization Features
The implementation adds TCP_NODELAY configuration and chunked writes (19200 bytes per chunk), plus jittered exponential backoff for reconnection. TCP_NODELAY can improve latency for real-time traffic by eliminating Nagle's algorithm delays.
Rate-Limited Logging
The logger adds token-bucket-style rate limiting with configurable burst limits. This prevents log buffer saturation during high-frequency events while preserving critical messages—important for resource-constrained embedded systems.
[::web_search::], [::web_search::], [::web_search::], [::web_search::]
🔇 Additional comments (30)
.serena/.gitignore (1)
1-1: Basit ve temiz yapılandırma.Cache dizinini gitignore'dan dışlamak iyi bir uygulamadır, böylece geçici dosyalar deponuza girmez.
.serena/project.yml (1)
1-71: Serena projesi için doğru yapılandırma.Bu yapılandırma dosyası, Serena aracının projeyi doğru şekilde anlaması için gerekli bilgileri içeriyor. Tıpkı bir öğretmenin sınıf hakkında temel bilgilere ihtiyacı olması gibi, Serena da bu yapılandırmaya ihtiyaç duyuyor.
.serena/memories/code_style_conventions.md (1)
1-32: Kod stili rehberi açık ve faydalı, ama bir sorun var.Gördüğüm kural: bu dosya
.gitignoretarafından yok sayılıyor (.serena/diye yazılı), bu nedenle depo hiçbir zaman kaydedilmeyecek. Bir çocuğa öğrettiğimiz kuralları yazılı hale getirirsek, ancak kuralları çöp kutusuna atarsak, kimse okuyamaz. Bu dosya önemli bir rehber ise,.gitignorekurallarını güncellemeniz gerekebilir.Bu belgelerin kasten göz ardı mı edilmesi gerekiyor, yoksa depoyla birlikte kaydedilmeleri gerekiyor mu?
.serena/memories/task_completion_checklist.md (1)
1-28: Görev tamamlama kontrol listesi yararlı fakat .gitignore sorunu aynı.Bu kontrol listesi, proje yönetimi için gerçekten faydalı. Ancak önceki dosyadakı gibi aynı sorun:
.serena/dizini.gitignoredosyasında yok sayılıyor, bu nedenle bu kontrol listesi hiçbir zaman depoyla birlikte kaydedilmeyecek.Bu belge dosyaları kasıtlı olarak yok sayılmış mı, yoksa
.gitignorekuralları gözden kaçırılmış mı?.serena/memories/project_overview.md (1)
1-34: Proje özeti detaylı ve net, ama aynı .gitignore sorunu.Bu belge, projenin ne yaptığını, hangi bileşenlerden oluştuğunu ve kaynak kullanımını açıkça anlatıyor - tıpkı bir kitapçık gibi. Ancak önceki belgelerdeki gibi, bu belge de
.gitignoretarafından yok sayılacak ve hiçbir zaman depoyla birlikte kaydedilmeyecek.Tüm
.serena/memories/dosyaları kasten göz ardı mı edilmesi gerekiyor?.serena/memories/suggested_commands.md (1)
1-43: Geliştirici komutları açık ve faydalı.Bu belge, yeni geliştiricilerin yapılması gerekenin adımlarını açıkça gösteriyor - tıpkı bir resepte malzemelerin nasıl karıştırılacağı yazılı olması gibi. Komutlar doğru görünüyor ve Windows ve bash için örnekler içeriyor.
Ama tabii, bu dosya da
.serena/dizini yok sayıldığı için depo ile birlikte kaydedilmeyecek.src/NonBlockingTimer.h (1)
46-65: check(): Sıfır aralıkla busy-loop riski.
Aralık 0 ise her çağrıda true döner; üst katman döngünüzü gereksizce hızlandırabilir. Üstteki kelepçe ile bu risk kalkar; ayrıca isterseniz burada da koruma eklenebilir.As per coding guidelines
src/logger.cpp (1)
88-93: Dosya adı çıkarımı: Çapraz platform uyumu güzel.
Hem '/' hem '' için bakmanız iyi düşünülmüş. LGTM.src/adaptive_buffer.h (1)
4-4: Clang “Arduino.h not found” uyarısı.
Bu uyarı genelde non‑Arduino toolchain’den gelir; Arduino/ESP32 ortamında sorun değildir. Bilgi için not düşüyorum.src/config_validator.h (1)
318-336: ERROR_RECOVERY_DELAY doğrulaması: Makro mevcut mu?
Bu makroyu doğruluyorsunuz; config.h’da tanımlı olduğundan emin olalım ve birimlerin ms olduğuna dair yorumu ekleyelim. Aksi halde derleme hatası olur.As per coding guidelines
src/main.cpp (1)
171-185: Logger başlatma ve config doğrulama akışı iyi; ellerinize sağlık.ELI5: “Arabayı çalıştırmadan önce yağı ve lastikleri kontrol etmişsiniz; süper.”
- Watchdog süresi (WATCHDOG_TIMEOUT_SEC) ile worst-case loop süresinin (I2S + ağ gecikmeleri) rahat uyumlu olduğundan emin olun.
Also applies to: 191-204
src/i2s_audio.cpp (1)
19-26: Based on my web research, I can now provide a thorough analysis. Let me verify one more detail about the actual fallback constant name:I2S_COMM_FORMAT_STAND_I2S uyumluluğunu doğrulayın ve fallback ekleyin
Arduino-ESP32 1.0.6 ve daha eski sürümlerde I2S_COMM_FORMAT_STAND_I2S tanımlanmamıştır, bu da eski kartlarda derleme hatası verecektir. I2S_COMM_FORMAT_I2S (değeri 0x01) aynı işlevi görmekte olup I2S_COMM_FORMAT_STAND_I2S ile eşdeğerdir.
Uyumluluğu için önerilen #ifdef fallback gereklidir:
#ifdef I2S_COMM_FORMAT_STAND_I2S .communication_format = I2S_COMM_FORMAT_STAND_I2S, #else .communication_format = I2S_COMM_FORMAT_I2S, #endifBu şekilde kodunuz hem yeni (2.0.0+) hem de eski Arduino-ESP32 sürümlerinde çalışacaktır.
src/serial_command.cpp (1)
160-169: CONFIG SHOW, parola yazdırmıyor — iyi.SSID yazdırmak genelde sorun değil; yine de isteğe bağlı olarak maskeleme düşünebilirsiniz (ör. ilk/son 2 karakter).
İsterseniz SSID’yi kısmen maskelerim.
src/network.cpp (3)
523-535: AdaptiveBuffer kancaları temiz — iyi entegre edilmiş.RSSI ile periyodik uyarlama ve boyut sorgusu yönergelerle uyumlu görünüyor.
Bağlantı kalitesinin hızlı dalgalandığı senaryolarda log gürültüsünü kontrol ettiğinizi doğrulayın (rate-limit logger var mı?).
354-384: Kısmi yazımlar düzgün ele alınmış.Parça parça yazma, zaman aşımı tespiti ve hata geri kazanımı akışı sağlam görünüyor.
459-479: Durum eşitleme (validateConnection) iyi düşünülmüş.Gerçek bağlantı durumuyla FSM’i senkron tutmanız sahada “hayalet bağlı” sorunlarını azaltır.
src/config.h (14)
5-9: WiFi yapılandırması güzel görünüyor! 🌟Düşün ki WiFi'ye bağlanmaya çalışıyorsun - eğer ilk denemede bağlanamazsan, hemen pes etmek istemezsin değil mi? İşte bu ayarlar tam bunu yapıyor:
- Her başarısız denemeden sonra 500 milisaniye (yarım saniye) bekliyor
- Toplam 20 kez tekrar deniyor
- Ve 30 saniye içinde bağlanamazsa timeout oluyor
Bu değerler ESP32 için çok makul ve güvenli. Ayrıca şifre gibi hassas bilgilerin placeholder olarak bırakılması güvenlik açısından harika! 👍
14-17: Statik IP ayarları güvenli bir şekilde devre dışı bırakılmış.Düşün ki eve yeni bir misafir geldiğinde, ona otomatik olarak bir oda numarası verilir (DHCP gibi). Ama bazı durumlarda belirli bir odayı sabit tutmak isteyebilirsin (statik IP gibi). Bu ayarlar varsayılan olarak kapalı ve kullanıcı gerektiğinde açabilir - bu güzel bir yaklaşım! ✨
36-43: Kart algılama çok akıllıca yapılmış! 🎯Düşün ki farklı markalar için aynı oyunu oynamak istiyorsun - PlayStation ve Xbox için ayrı oyunlar yazmak yerine, tek bir oyun yazıp hangi konsolda çalıştığını algılamasını sağlıyorsun. İşte bu kod da tam bunu yapıyor!
ESP32'nin farklı varyantları (XIAO ESP32-S3 ve ESP32-DevKit) farklı pin yapılandırmalarına sahip olabiliyor. Bu otomatik algılama, doğru pini kullanmamızı sağlıyor ve çalışma zamanında hataları önlüyor. Harika! ✨
46-54: I2S pin eşlemeleri kart algılamaya mükemmel entegre edilmiş! 🎵I2S, ses verilerini dijital olarak ileten bir protokol - düşün ki kulağının içindeki kemikçikler gibi, titreşimleri iletiyorlar. Her kartın farklı "kemikçik" yerleri (pinleri) var:
- XIAO ESP32-S3: pinler 3, 9, 2
- ESP32-DevKit: pinler 15, 32, 14
Otomatik olarak doğru pinleri seçmek, yanlış pine bağlanıp hiç ses çıkmaması gibi sorunları önlüyor. Çok güzel! 👏
57-61: I2S parametreleri ses akışı için iyi ayarlanmış! 🎤Düşün ki sürekli su dolduruyorsun - çok küçük kovalar kullanırsan sürekli koşturmak zorunda kalırsın, çok büyük kovalar kullanırsan taşıyamazsın. Bu ayarlar tam dengede:
- 16000 Hz örnekleme hızı: telefon konuşması kalitesi için ideal (müzik değil, konuşma için)
- 4096 byte buffer: yaklaşık 0.13 saniye ses = çok küçük değil, çok büyük değil
- 8 DMA buffer × 256 uzunluk: donanımın verilen kopyalarken ana işlemci başka işler yapabilir
Hepsi TCP_CHUNK_SIZE (19200 byte) ile uyumlu - yani birkaç DMA buffer bir TCP chunk'ı dolduruyor. Matematik uyumlu! ✅
64-68: Güvenilirlik eşikleri çok iyi düşünülmüş! 🛡️Bunlar sistemin "kendini hissetme" ayarları gibi:
Hafıza eşikleri: 40KB'de uyarı, 20KB'de kritik. Düşün ki cüzdanında para azalıyor - 40 lira kalınca "dikkatli ol" dersin, 20 lira kalınca "acil para lazım!" dersin. Bu değerler ESP32 için çok mantıklı!
RSSI -80 dBm: WiFi sinyal gücü. -80'de sinyal zayıflıyor demek. Telefon çubuklarını düşün: 0 dBm mükemmel (imkansız), -80 dBm zayıf ama kullanılabilir, -120 dBm yok denecek kadar az.
10 ardışık hata: Bir şey 10 kere üst üste yanlış giderse, belki de durumu kabul etme zamanı gelmiştir. Çok erken pes etmiyor, çok da inatçı olmuyoruz.
Kodlama kılavuzları ile uyumlu! 👍
71-73: Zamanlama aralıkları akıllıca dengelenmiş! ⏱️Düşün ki bir öğretmen öğrencileri kontrol ediyor:
- Hafıza kontrolü (1 dakika): Çok sık kontrol ederseniz derse odaklanamaz, çok seyrek kontrol ederseniz sorunları geç fark edersiniz. 1 dakika tam dengede!
- WiFi sinyal kontrolü (10 saniye): Sinyal hızlı değişebilir, özellikle hareket ederken. 10 saniye hızlı tepki verir ama sürekli meşgul de etmez.
- İstatistik yazdırma (5 dakika): Seri port log'larını her saniye doldurmak istemeyiz - 5 dakika genel durumu takip için ideal.
Hepsi milisaniye cinsinden ve yorumlu - mükemmel! ✨
75-79: Sistem başlatma ve timeout değerleri çok iyi ayarlanmış! 🚀Her biri farklı bir amaca hizmet ediyor:
Seri port başlatma (1 saniye): USB-serial dönüştürücünün uyanması ve hazır olması için zaman tanı. Çok hızlı mesaj gönderirsen kaybolabilir!
Zarif kapatma gecikmesi (100ms): Sistemi kapatırken her adım arasında küçük bir mola. Düşün ki ışıkları kapatıp çıkarken, her odayı teker teker kapatıyorsun - aceleniz yok ama çok da yavaş değil.
Hata kurtarma gecikmesi (5 saniye): Bir şey yanlış gittiyse, hemen tekrar denersen aynı hatayla karşılaşabilirsin. 5 saniye beklemek, sistemin biraz dinlenmesini sağlar.
Task yield (1ms): Ana döngüde arka plan görevleri için minimal zaman. FreeRTOS'un iş yapması için gerekli!
Kodlama kılavuzlarına uygun - hiç magic number yok! 👏
81-84: TCP keepalive ayarları gerçek zamanlı ses için optimize edilmiş! 🔌TCP keepalive, bağlantının hala canlı olup olmadığını kontrol eden bir mekanizma. Düşün ki uzun bir telefon konuşmasında karşı taraf hiç konuşmuyorsa, hala orada mı diye "merhaba? duyuyor musun?" diye sorarsın:
- 5 saniye boşta kalma: Eğer 5 saniye veri almazsan, "hala orada mısın?" diye sormaya başla
- 5 saniye aralık: Her "hala orada mısın?" sorusu arasında 5 saniye bekle
- 3 deneme: 3 kere cevap gelmezse, bağlantı öldü kabul et
Toplam algılama süresi: 5 + (5 × 3) = 20 saniye. Ses akışı için bu hızlı algılama çok önemli - çünkü bozuk bir bağlantıda beklemek kullanıcı deneyimini kötüleştirir. İyi seçim! ✅
86-89: Logger yapılandırması kaynak koruması için harika! 📝Düşün ki bir öğrenci sürekli "öğretmenim!" diye bağırıyor - bir süre sonra dikkat etmeyi bırakırsın. Logger rate limiting tam bunu önlüyor:
- 256 byte buffer: Her log mesajı için yeterli alan - çok büyük değil ki hafızayı tüketmesin, çok küçük değil ki mesaj kesik kalsın
- Saniyede 20 satır: Normal kullanımda yeterli, ama log storm'u engeller
- 60 burst maksimum: Kısa süreliğine hızlı log basımına izin ver (örneğin hata oluştuğunda), ama sonsuza kadar değil
Bu token-bucket tarzı rate limiting, log buffer'ın dolup hafıza bitmesini önler. ESP32 gibi kısıtlı kaynaklı sistemlerde kritik! Dış araç bulgularında da belirtilmiş - mükemmel uygulama! 🌟
91-92: Watchdog timeout değeri bağlantı süreleriyle uyumlu! ⏰Watchdog, sistemin "bekçi köpeği" gibi - eğer program çalışmayı durdurursa (donma), sistem kendini yeniden başlatır. Ama köpeği çok huysuz yaparsan, meşru uzun işlemler sırasında da havlar!
60 saniye uzun görünebilir, ama şu sürelere bak:
- WiFi bağlantısı: en fazla ~40 saniye (20 deneme + timeout)
- Sunucu yeniden bağlanma: en fazla 60 saniye (backoff)
Yani watchdog bu meşru işlemleri "donma" sanmasın diye 60 saniyeye ayarlanmış. Yorumda da "connection operations ile uyumlu" diyor - çok iyi düşünülmüş! Ancak normal çalışmada program 60 saniye bloklanmamalı, sadece bağlantı kurulumu sırasında. 👍
94-97: Task öncelikleri FreeRTOS için güzel yapılandırılmış! 🎯FreeRTOS'ta her görev (task) bir öncelik numarasına sahip - düşün ki bir öğretmenin sınıfta farklı aciliyet dereceleri var:
- Yüksek öncelik (5): Çok acil işler - örneğin ses verisi kaybedilmeden işlenmeli
- Normal öncelik (3): Standart işler - çoğu görev burada
- Düşük öncelik (1): Arka plan işleri - acil değil, boş vakitte yapılabilir
Bu değerler arasında boşluk bırakılmış (1, 3, 5) - gelecekte arada öncelikler eklenebilir. Ayrıca magic number yerine isimlendirilmiş sabitler kullanılmış - kod çok daha okunabilir! Harika! ✨
99-100: State machine debounce çok akıllıca bir koruma! 🛡️Debounce, "titreşimi önleme" demek. Düşün ki bir düğmeye basıyorsun - mekanik olarak bir kere değil, çok hızlı bir sürü kere temas oluyor (birkaç milisaniye içinde). Debounce bu titreşimi filtreleyip "tek tıklama" olarak sayar.
Yazılım state machine'inde de benzer durum var - geçici koşullar yüzünden durum hızla değişebilir. 100ms debounce demek ki:
- Bir durumdan başka duruma geçtikten sonra
- En az 100ms orada kal
- Hemen geri zıplama (oscillation)
Bu, sistemin kararlılığını artırır ve gereksiz durum değişimlerini engeller. Donanım debounce'tan (10-50ms) biraz daha uzun ama yazılım için ideal! 👍
20-34: ---TCP_CHUNK_SIZE tanımı güzel, ama sunucu kontrolü eksik olabilir! 📚
Konfigürasyonun açıklaması çok iyisi - tıpkı bir öğretmen yazısı gibi net ve anlaşılır:
- 9600 örnek × 2 byte = 19200 byte (doğru matematik!)
- 16000 Hz'de bu, tam 0.6 saniye ses demek
- Hızı da hesaplamış: 32 KB/saniye
Ama bir sorunumuz var: Yorumda "MUST match server" (sunucuyla eşleşMELİ) yazıyor. Burada ne demek? Şöyle düşün: Eğer sen 19200 byte gönderirsen ama sunucu (receiver.py) 10000 byte beklerken oturuyorsa, sandık içine giren paket tam olmazsa kırılabilir - ses akışı bozulur.
Kodda gördüğümüz:
- ✅ Sabiti doğru kullanıyor (satır 366'da veri parçalıyor)
- ✅ Logluyor bile (satır 290'da "19200 bytes per chunk" yazıyor)
- ❓ Fakat: Sunucunun bu boyutu beklediğini doğrulayan bir kontrol yok!
Önerim: Lütfen
receiver.py'daTCP_CHUNK_SIZEveyachunkboyutunun gerçekten 19200 olduğunu manuel olarak kontrol et. Sunucu farklı bir değer bekliyorsa, bağlantı kurulduğunda bu değeri ESP32'ye söyleyen bir el sıkışma (handshake) mekanizması eklemen gerekebilir.
| Date: October 20, 2025 | ||
| Commit: 0c9f56b | ||
| Branch: main | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Belge meta verisi PR ile uyumsuz görünüyor (branch/commit).
ELI5: “Etikette ‘main’ yazıyor ama ürünü ‘improve_2’ rafına koymuşuz.”
Aşağıdaki komutlarla doğrular mısınız?
🏁 Script executed:
#!/bin/bash
git rev-parse --abbrev-ref HEAD
git rev-parse HEAD
git log -1 --pretty=onelineLength of output: 166
Belge meta verisi hâlâ eski bilgiler gösteriyor - güncellenmesi gerekiyor.
Öğretmen gibi anlatalım: Kütüphanede bir kitabın kapağında "3. raf" yazılı ama kitap gerçekten 5. rafta duruyordu. Senin dosyan da böyle—etikette "main" dalı ve "0c9f56b" kodu yazılı, ama gerçekte "coderabbit_3" dalında ve "d8672fe4feae76688a5408e3e4999ddb13d02251" kodu var.
Dosyayı şu gerçek bilgilerle güncelle:
- Branch: coderabbit_3
- Commit: d8672fe
🤖 Prompt for AI Agents
.serena/memories/implementation_completion.md around lines 5 to 8: the metadata
block shows outdated branch and commit values; update the Branch value to
"coderabbit_3" and the Commit value to
"d8672fe4feae76688a5408e3e4999ddb13d02251" so the file reflects the actual
branch and commit; preserve surrounding formatting and date/other fields
unchanged.
| [](#) | ||
| [](#) | ||
| [](#) | ||
| [](#) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Boş bağlantıları kaldırın (rozetler).
Rozetler (#) hedefine bağlı; bu MD042 ihlali. Bağlantı gerekmiyorsa dıştaki link sarmalamasını kaldırın; yalnızca görsel kalsın.
Örnek diff:
-[](#)
-[](#)
-[](#)
-[](#)
+
+
+
+📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| [](#) | |
| [](#) | |
| [](#) | |
| [](#) | |
|  | |
|  | |
|  | |
|  |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
5-5: No empty links
(MD042, no-empty-links)
6-6: No empty links
(MD042, no-empty-links)
7-7: No empty links
(MD042, no-empty-links)
8-8: No empty links
(MD042, no-empty-links)
🤖 Prompt for AI Agents
In README.md around lines 5 to 8, the badge images are wrapped in empty links
like ([) which violates MD042; remove the surrounding link markup so
each badge is just the image markdown (e.g. ) instead of a
linked image, leaving the visuals intact but eliminating the empty/placeholder
links.
| ``` | ||
| INMP441 Pin → ESP32 Pin | ||
| CLK → GPIO 14 | ||
| WS → GPIO 15 | ||
| SD → GPIO 32 | ||
| GND → GND | ||
| VCC → 3V3 | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Çitli kod bloklarına dil etiketi ekleyin.
MD040 uyarılarını gidermek için uygun dilleri ekleyin (bash, cpp, text).
Örnekler:
-```
+```text
INMP441 Pin → ESP32 Pin
CLK → GPIO 14-```bash
+```bash
pio device monitor --port COM8 --baud 115200-```
+```text
[INFO] ESP32 Audio Streamer Starting UpAynı deseni diğer bloklara da uygulayın (STATS/DEBUG/SIGNAL/RECONNECT/HELP örnekleri ve mimari diyagram).
Also applies to: 46-53, 89-95, 131-135, 138-142, 145-149, 152-155, 158-161, 166-186, 191-199
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In README.md around lines 35 to 42 (and also apply the same change to ranges
46-53, 89-95, 131-135, 138-142, 145-149, 152-155, 158-161, 166-186, 191-199),
several fenced code blocks lack language tags which triggers MD040; update each
fenced block by adding the appropriate language identifier (use ```text for
plain text diagrams and pin mappings, ```bash for CLI/terminal commands like pio
device monitor, and ```cpp for C/C++ snippets) so every triple-backtick block
includes a language label matching its content.
| #include "debug_mode.h" | ||
| #include "logger.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eksik bağımlılıklar: Arduino ve stdarg header’larını ekleyin.
ELI5: “Serial” ve “va_list” sihir değil; onlara hangi kutudan geldiklerini söylemeliyiz. Bu dosyada açıkça dahil edin ki transitive include’lara bağlı kalmayalım.
Aşağıdaki eklemeler derleme güvenliğini artırır:
#include "debug_mode.h"
#include "logger.h"
+#include <Arduino.h>
+#include <stdarg.h>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #include "debug_mode.h" | |
| #include "logger.h" | |
| #include "debug_mode.h" | |
| #include "logger.h" | |
| #include <Arduino.h> | |
| #include <stdarg.h> |
🤖 Prompt for AI Agents
In src/debug_mode.cpp lines 1-2, missing direct includes for Arduino and stdarg:
add #include <Arduino.h> (or appropriate Arduino core header) and #include
<stdarg.h> at the top of this file so that Serial and va_list are resolved
without relying on transitive includes; update include order so logger.h and
debug_mode.h come after these standard headers to ensure compilation robustness.
| void RuntimeDebugContext::setLevel(int new_level) { | ||
| level = new_level; | ||
| LOG_INFO("Runtime debug level set to %d", level); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seviye alanı (level) şu an davranışı etkilemiyor.
ELI5: “Sesi aç-kapa düğmesi var (level) ama hoparlöre bağlı değil.” setLevel() çağrıları log() çıktısını hiç değiştirmiyor.
Öneriler:
- API’yi genişletin:
void log(int msg_level, const char* fmt, ...)veif (msg_level <= level)ile filtreleyin. - Veya basitçe:
if (level == 0) return;gibi bir eşik mantığı tanımlayın ve dokümante edin.
Also applies to: 30-42
🤖 Prompt for AI Agents
In src/debug_mode.cpp around lines 21-24 (and also 30-42) the
RuntimeDebugContext::setLevel just stores the level but logging is never
filtered — implement a message-level filter: add a new logging signature log(int
msg_level, const char* fmt, ...) that checks if (msg_level <= level) before
emitting the message, update existing internal log calls in lines 30-42 to pass
appropriate msg_level values, and provide a backward-compatible wrapper
log(const char* fmt, ...) that forwards to the new API with a default level
(e.g., 1). Ensure varargs handling and any existing callers are updated to use
the new signature where needed.
| esp_err_t result = i2s_read(I2S_PORT, buffer, buffer_size, bytes_read, pdMS_TO_TICKS(1000)); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bloklayan çağrılar ana döngüyü 1 sn’den fazla kilitleyebilir.
ELI5: “Kapının önünde 1 dakika beklersek (1s timeout × tekrar), içerideki herkes (loop) sıraya takılır.” Kılavuz: ana döngüyü >1s bloklamayın.
pdMS_TO_TICKS(1000)yerine config.h sabiti kullanın ve küçük tutun (örn. I2S_READ_TIMEOUT_MS = 10-20).delay(10)vedelay(100)sabitlere taşınmalı ve mümkünse NonBlockingTimer ile denemeler döngü boyunca dağıtılmalı.
Önerilen değişiklikler:
- esp_err_t result = i2s_read(I2S_PORT, buffer, buffer_size, bytes_read, pdMS_TO_TICKS(1000));
+ esp_err_t result = i2s_read(I2S_PORT, buffer, buffer_size, bytes_read, pdMS_TO_TICKS(I2S_READ_TIMEOUT_MS));- delay(10); // Brief pause before retry
+ // Non-blocking: denemeleri döngüye yaymayı düşünün (NonBlockingTimer)
+ delay(I2S_RETRY_DELAY_MS);- delay(100);
+ delay(I2S_REINIT_DELAY_MS);config.h ekleri (dosya dışı):
#define I2S_READ_TIMEOUT_MS 20
#define I2S_RETRY_DELAY_MS 5
#define I2S_REINIT_DELAY_MS 50Also applies to: 118-143, 147-156
| // Memory health | ||
| uint32_t free_heap = ESP.getFreeHeap(); | ||
| if (free_heap > 50000) { | ||
| LOG_INFO("✓ Memory Healthy - Free: %u bytes", free_heap); | ||
| } else if (free_heap > 20000) { | ||
| LOG_WARN("⚠ Memory Low - Free: %u bytes", free_heap); | ||
| } else { | ||
| LOG_ERROR("✗ Memory Critical - Free: %u bytes", free_heap); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Bellek eşikleri sabitlerden gelmeli; sihirli sayılar yerine config.h kullanın.
Kurallara göre uyarı 40KB, kritik 20KB için sabitler var. Burada 50k/20k kullanılıyor ve sabitlenmemiş.
- if (free_heap > 50000) {
- LOG_INFO("✓ Memory Healthy - Free: %u bytes", free_heap);
- } else if (free_heap > 20000) {
- LOG_WARN("⚠ Memory Low - Free: %u bytes", free_heap);
+ if (free_heap > MEMORY_WARN_THRESHOLD) {
+ LOG_INFO("Memory OK - Free: %u bytes", free_heap);
+ } else if (free_heap > MEMORY_CRITICAL_THRESHOLD) {
+ LOG_WARN("Memory Low - Free: %u bytes", free_heap);
} else {
- LOG_ERROR("✗ Memory Critical - Free: %u bytes", free_heap);
+ LOG_ERROR("Memory Critical - Free: %u bytes", free_heap);
}Ek olarak, seri monitörlerde sorun çıkmaması için Unicode simgeleri yerine ASCII kullanın.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/serial_command.cpp around lines 250 to 258, the heap thresholds and
Unicode symbols are hard-coded; replace the magic numbers with constants defined
in config.h (e.g. WARNING_HEAP_THRESHOLD = 40*1024, CRITICAL_HEAP_THRESHOLD =
20*1024 or the existing names in config.h) and include config.h if not already
included, then use those constants in the comparisons instead of 50000/20000;
also swap the Unicode icons for plain ASCII labels such as "[OK]", "[WARN]",
"[CRIT]" in the LOG_* calls so serial monitors aren’t broken.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (1)
src/config_validator.h (1)
55-58: Loglarda ✓/✗ karakterleri tutarsız kullanılıyor; tek biçime geçelim.Bazı yerlerde “✓” literal, bazı yerlerde “\u2713” kaçışı kullanılmış. Seri port çıktısında tutarlılık için tek stil seçelim.
Öneri: Her yerde literal “✓” kullanın.
-LOG_INFO(" \u2713 Watchdog timeout: %u seconds", WATCHDOG_TIMEOUT_SEC); +LOG_INFO(" ✓ Watchdog timeout: %u seconds", WATCHDOG_TIMEOUT_SEC); -LOG_INFO(" \u2713 Watchdog timeout compatible with WiFi timeout"); +LOG_INFO(" ✓ Watchdog timeout compatible with WiFi timeout"); -LOG_INFO(" \u2713 Watchdog timeout compatible with error recovery delay"); +LOG_INFO(" ✓ Watchdog timeout compatible with error recovery delay");Unicode desteği sorun olursa, tamamen ASCII’ye dönüp “[OK]” / “[FAIL]” da kullanabiliriz.
Also applies to: 315-325, 334-335
🧹 Nitpick comments (8)
src/config_validator.h (5)
91-109: “Varsayılan kullanılacak” mesajı gerçekte uygulanmıyor; ifadenizi düzeltelim.Burada “using default 500ms” deniyor ama bu sınıf bir değeri değiştirmiyor; sadece log yazıyor. Yanıltıcı olmasın.
Mesajı “>0 olmalı (örn. 500 ms)” biçimine çevirelim:
-LOG_WARN("WIFI_RETRY_DELAY is 0 or negative - using default 500ms"); +LOG_WARN("WIFI_RETRY_DELAY is 0 or negative - set > 0 (e.g., 500 ms)"); -LOG_WARN("WIFI_MAX_RETRIES is 0 or negative - using default 20"); +LOG_WARN("WIFI_MAX_RETRIES is 0 or negative - set > 0 (e.g., 20)"); -LOG_WARN("WIFI_TIMEOUT is 0 or negative - using default 30000ms"); +LOG_WARN("WIFI_TIMEOUT is 0 or negative - set > 0 (e.g., 30000 ms)");ELI5: “Varsayılanı ben koymuyorum; sadece ‘böyle ayarlasan iyi olur’ diyorum.”
177-194: Sihirli sayıları isimlendirelim; eşiği config.h’a taşıyalım.8000/48000 gibi hard‑coded limitler bakımda zor. config.h’da adlandırıp burada kullanalım.
Öneri:
- config.h’a ekleyin:
+#define I2S_SAMPLE_RATE_MIN 8000 +#define I2S_SAMPLE_RATE_MAX 48000
- Burayı güncelleyin:
-} else if (I2S_SAMPLE_RATE < 8000 || I2S_SAMPLE_RATE > 48000) { +} else if (I2S_SAMPLE_RATE < I2S_SAMPLE_RATE_MIN || I2S_SAMPLE_RATE > I2S_SAMPLE_RATE_MAX) {Aynı yaklaşımı 1000 ms gibi diğer eşikler için de uygulayabiliriz (örn. SERVER_RECONNECT_MIN_RECOMMENDED_MS).
83-90: “Parola” kelimesini log’dan çıkaralım.Şifreyi yazmıyoruz (güzel), ama log’da “password” kelimesi bile bazı ortamlarda alarm tetikleyebilir. Nötr bir ifade tercih edelim.
-LOG_INFO(" ✓ WiFi password configured"); +LOG_INFO(" ✓ WiFi credentials present");ELI5: “Şifre demeden de şifrenin var olduğunu anlatabiliyoruz.”
122-137: SERVER_HOST placeholder’ını yakalayalım."192.168.x.x" boş değil diye şu an “geçti” sayılıyor. Bu tip kalıp değerleri yakalayıp uyaralım.
-} else { - LOG_INFO(" ✓ Server HOST configured: %s", SERVER_HOST); -} +} else if (strstr(SERVER_HOST, "x.x") != nullptr) { + LOG_ERROR("Server HOST looks like a placeholder ('192.168.x.x') - set a real address"); + valid = false; +} else { + LOG_INFO(" ✓ Server HOST configured: %s", SERVER_HOST); +}Bu sayede “boş değil” ama “yanlış” durumları erken yakalarız.
138-166: 1 saniyelik eşik de bir sihirli sayı; isimlendirelim.Minimum öneriyi config.h’da adlandırıp burada kullanalım; bakımı kolaylaşır.
Öneri:
-} else if (SERVER_RECONNECT_MIN < 1000) { +} else if (SERVER_RECONNECT_MIN < SERVER_RECONNECT_MIN_RECOMMENDED_MS) {config.h:
+#define SERVER_RECONNECT_MIN_RECOMMENDED_MS 1000src/config.h (3)
43-50: TCP_CHUNK_SIZE’ı türetelim; senkron kaymasını önleyelim.Sabit 19200 yerine “örnek/ses baytı” üzerinden türetmek değişikliklerde hatayı önler.
Öneri:
+// Audio framing +#define BYTES_PER_SAMPLE 2 +#define SAMPLES_PER_CHUNK 9600 -#define TCP_CHUNK_SIZE 19200 // bytes per write() chunk - MUST match server receiver.py +#define TCP_CHUNK_SIZE (SAMPLES_PER_CHUNK * BYTES_PER_SAMPLE) // must match receiver.pyİsterseniz minik bir derleme zamanı kontrolü de ekleyebiliriz:
#if (TCP_CHUNK_SIZE % BYTES_PER_SAMPLE) != 0 # error "TCP_CHUNK_SIZE must be a multiple of BYTES_PER_SAMPLE" #endifELI5: “2 lego parçası bir paketi dolduruyor; paket boyunu parçadan hesaplayalım.”
Also applies to: 72-76
71-76: Eşikleri isimlendirelim; validator ile tek kaynaktan kullanalım.I2S örnek hız aralığı ve “1 saniye min reconnect” gibi değerleri adlandırıp paylaşmak bakımı kolaylaştırır.
Öneri eklemeler:
+#define I2S_SAMPLE_RATE_MIN 8000 +#define I2S_SAMPLE_RATE_MAX 48000 +#define SERVER_RECONNECT_MIN_RECOMMENDED_MS 1000Validator tarafındaki karşılıkları da güncelledik (üstte).
Also applies to: 79-89
96-100: Keepalive ve logger ayarlarını validator’da kontrol edelim.Bu sabitler güzel; karşılık gelen doğrulamaları eklemek (üstte önerildi) “başlamadan kontrol” hedefini tamamlar.
İster misiniz, bu ayarlar için ek örnek log metinlerini ve sınırlarını PR’a ben ekleyeyim?
Also applies to: 102-105
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/config.h(1 hunks)src/config_validator.h(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{c,cpp,h,hpp,ino}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{c,cpp,h,hpp,ino}: Constants and macro defines must use UPPER_SNAKE_CASE (e.g., WIFI_SSID, I2S_SAMPLE_RATE)
Function names must use camelCase (e.g., gracefulShutdown, checkMemoryHealth)
Variable names must use snake_case (e.g., free_heap, audio_buffer)
Class/struct names must use PascalCase (e.g., SystemStats, StateManager)
Place all includes at the top of the file, grouped in logical sections
Declare functions before globals
Use section separators as comments: // ===== Section Name =====
Prefer static buffers over heap allocation
Consume timing values only via constants from config.h; do not use hardcoded delays/timeouts
Use Arduino fixed-width types (uint8_t, uint32_t, unsigned long)
Prefer millis() over delay() for timing to keep code non-blocking
Log all state transitions and errors using LOG_INFO, LOG_WARN, LOG_ERROR, LOG_CRITICAL
Classify errors into TRANSIENT, PERMANENT, or FATAL and handle accordingly
Prefer static allocation; monitor heap usage, warn at 40KB free and critical at 20KB; track peak and minimum heap
Use non-blocking timers (e.g., NonBlockingTimer) instead of delay() for periodic work
Periodically validate system state matches actual hardware/network state and correct mismatches
Implement features with comprehensive error handling per the error template
Add logging at key points of new code paths
Do not use hardcoded delays or timeouts; rely on constants and non-blocking timers
Avoid allocating large buffers on the heap
Never ignore error return values; always check and handle
Never log WiFi passwords or other sensitive secrets
Do not assume WiFi/TCP is always connected; check actual connection state before use
Avoid introducing magic numbers; use named constants (preferably in config.h)
Ensure all error paths log appropriately before returning/failing
Use // for inline comments and /* */ for block comments sparingly; prefer section headers // ===== Section Name =====
Files:
src/config_validator.hsrc/config.h
src/config_validator.h
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
When adding features, add configuration validation to src/config_validator.h
Files:
src/config_validator.h
src/config.h
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/config.h: All timeouts and delays must be defined as constants in config.h (no magic numbers)
When adding features, add configuration constants to src/config.h
Files:
src/config.h
🧠 Learnings (3)
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/config_validator.h : When adding features, add configuration validation to src/config_validator.h
Applied to files:
src/config_validator.h
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/main.{cpp,ino} : Validate all configuration at startup using ConfigValidator::validateAll() and halt on failure
Applied to files:
src/config_validator.h
📚 Learning: 2025-10-21T00:07:29.905Z
Learnt from: CR
PR: sarpel/arduino-esp32#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-21T00:07:29.905Z
Learning: Applies to src/main.{cpp,ino} : Do not start with invalid configuration; refuse to run until validation passes
Applied to files:
src/config_validator.h
🔇 Additional comments (1)
src/config.h (1)
6-18: config_local.h include yaklaşımı güzel.Yerel ayarları ayrı tutmanız ve gitignore önerisi net. Burada değişiklik yok; aynen devam.
| #include "config.h" | ||
| #include "logger.h" | ||
| #include <string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eksik başlıklar: strlen/uint32_t için bağımlılıkları ekleyelim.
Bu dosyada strlen ve uint32_t kullanılıyor ama /<stdint.h> eklenmemiş. Bazı derleyiciler transitive include sayesinde derler, ama güvenmeyelim; net ve taşınabilir olsun.
Uygulanacak küçük düzeltme:
#include "config.h"
#include "logger.h"
-#include <string>
+#include <cstring> // strlen
+#include <stdint.h> // uint32_t🤖 Prompt for AI Agents
In src/config_validator.h around lines 4 to 6, this header uses strlen and
uint32_t but doesn't include the proper headers; add #include <cstring> (or
<string.h>) for strlen and #include <cstdint> (or <stdint.h>) for uint32_t at
the top of the file so the code is self-contained and portable across compilers.
| // Validate WiFi configuration | ||
| if (!validateWiFiConfig()) { | ||
| all_valid = false; | ||
| } | ||
|
|
||
| // Validate server configuration | ||
| if (!validateServerConfig()) { | ||
| all_valid = false; | ||
| } | ||
|
|
||
| // Validate I2S configuration | ||
| if (!validateI2SConfig()) { | ||
| all_valid = false; | ||
| } | ||
|
|
||
| // Validate timing configuration | ||
| if (!validateTimingConfig()) { | ||
| all_valid = false; | ||
| } | ||
|
|
||
| // Validate memory thresholds | ||
| if (!validateMemoryThresholds()) { | ||
| all_valid = false; | ||
| } | ||
|
|
||
| // Validate watchdog configuration | ||
| if (!validateWatchdogConfig()) { | ||
| all_valid = false; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Yeni config sabitleri için doğrulamalar eksik; validateAll kapsamını genişletelim.
config.h’de eklenen bazı önemli ayarlar (LOGGER_, TCP_KEEPALIVE_, TCP_RECEIVE_TIMEOUT, TCP_CHUNK_SIZE, SERVER_BACKOFF_JITTER_PCT) burada hiç doğrulanmıyor. Başlangıçta “tam doğrulama” hedefi için bunları da kontrol etmeliyiz; aksi halde hatalar koşu zamanı sürpriz olur.
Önerilen eklemeler (özet diff):
// Validate watchdog configuration
if (!validateWatchdogConfig()) {
all_valid = false;
}
+ // Validate TCP low-level details (timeouts, chunking, backoff jitter)
+ if (!validateTcpDetails()) {
+ all_valid = false;
+ }
+
+ // Validate TCP keepalive settings
+ if (!validateKeepaliveConfig()) {
+ all_valid = false;
+ }
+
+ // Validate logger/rate-limit settings
+ if (!validateLoggerConfig()) {
+ all_valid = false;
+ }Ve sınıfın altına yeni yardımcılar (iskelet):
static bool validateTcpDetails() {
bool ok = true;
if (TCP_RECEIVE_TIMEOUT <= 0) { LOG_WARN("TCP_RECEIVE_TIMEOUT is %u ms - should be > 0", TCP_RECEIVE_TIMEOUT); }
if (TCP_CHUNK_SIZE <= 0) { LOG_ERROR("TCP_CHUNK_SIZE must be > 0"); ok = false; }
if (SERVER_BACKOFF_JITTER_PCT < 0 || SERVER_BACKOFF_JITTER_PCT > 100) {
LOG_ERROR("SERVER_BACKOFF_JITTER_PCT (%d) must be 0-100", SERVER_BACKOFF_JITTER_PCT); ok = false;
}
if ((TCP_CHUNK_SIZE % 2) != 0) { LOG_WARN("TCP_CHUNK_SIZE (%u) should be even (2 bytes/sample)", TCP_CHUNK_SIZE); }
return ok;
}
static bool validateKeepaliveConfig() {
bool ok = true;
if (TCP_KEEPALIVE_IDLE <= 0 || TCP_KEEPALIVE_INTERVAL <= 0 || TCP_KEEPALIVE_COUNT <= 0) {
LOG_ERROR("TCP keepalive values must be > 0 (idle=%u, interval=%u, count=%u)",
TCP_KEEPALIVE_IDLE, TCP_KEEPALIVE_INTERVAL, TCP_KEEPALIVE_COUNT);
ok = false;
} else {
LOG_INFO(" ✓ TCP keepalive: idle=%u s, interval=%u s, count=%u",
TCP_KEEPALIVE_IDLE, TCP_KEEPALIVE_INTERVAL, TCP_KEEPALIVE_COUNT);
}
return ok;
}
static bool validateLoggerConfig() {
bool ok = true;
if (LOGGER_BUFFER_SIZE <= 0) { LOG_ERROR("LOGGER_BUFFER_SIZE must be > 0"); ok = false; }
if (LOGGER_MAX_LINES_PER_SEC <= 0) { LOG_WARN("LOGGER_MAX_LINES_PER_SEC should be > 0"); }
if (LOGGER_BURST_MAX < LOGGER_MAX_LINES_PER_SEC) {
LOG_WARN("LOGGER_BURST_MAX (%u) < LOGGER_MAX_LINES_PER_SEC (%u) - bursts may be throttled immediately",
LOGGER_BURST_MAX, LOGGER_MAX_LINES_PER_SEC);
}
return ok;
}Kısaca: “çalıştırmadan önce tüm yapılandırmalar doğrulandı” vaadini gerçekten sağlayalım. Based on learnings
🤖 Prompt for AI Agents
In src/config_validator.h around lines 24-53, the validateAll() routine
currently omits new config constants (LOGGER_*, TCP_KEEPALIVE_*,
TCP_RECEIVE_TIMEOUT, TCP_CHUNK_SIZE, SERVER_BACKOFF_JITTER_PCT); add calls to
three new helper validators (validateLoggerConfig(), validateKeepaliveConfig(),
validateTcpDetails()) into the same all_valid accumulation so their failures
affect startup, and implement those helpers per the suggested checks:
validateLoggerConfig should verify LOGGER_BUFFER_SIZE>0, warn on
LOGGER_MAX_LINES_PER_SEC<=0 and warn if LOGGER_BURST_MAX <
LOGGER_MAX_LINES_PER_SEC; validateKeepaliveConfig should ensure
TCP_KEEPALIVE_IDLE/INTERVAL/COUNT >0 and log error otherwise (or info on
success); validateTcpDetails should ensure TCP_RECEIVE_TIMEOUT>0 (warn),
TCP_CHUNK_SIZE>0 (error), SERVER_BACKOFF_JITTER_PCT in 0-100 (error), and warn
if TCP_CHUNK_SIZE is odd; ensure each helper returns a bool and is invoked to
update all_valid so startup fails on critical misconfiguration.
| if (all_valid) { | ||
| LOG_INFO("✓ All configuration validations passed"); | ||
| } else { | ||
| LOG_CRITICAL("✗ Configuration validation FAILED - critical settings missing"); | ||
| } | ||
|
|
||
| LOG_INFO("=== Configuration Validation Complete ==="); | ||
|
|
||
| return all_valid; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Unicode taraması ve başlık doğrulaması için hızlı kontrol scripti.
Karakter tutarlılığını ve başlık ihtiyacını repo genelinde teyit edelim.
Also applies to: 309-345
🏁 Script executed:
#!/bin/bash
# Unicode işaret seti kontrolü
rg -nP "u2713|\\\u2713|✓|✗" -S -C1
# strlen kullanan yerlerde <cstring> var mı?
rg -nP --type=cpp --type=h "\bstrlen\s*\(" -C2
# uint32_t/size_t kullanan yerlerde <stdint.h> / <cstdint> var mı?
rg -nP --type=cpp --type=h "\buint32_t\b|\bsize_t\b" -C2Length of output: 24316
[/run_scripts]
🏁 Script executed:
#!/bin/bash
# Check includes at the top of config_validator.h
head -n 20 src/config_validator.h | grep -E "^#include"Length of output: 57
Karakterli tutarlılığı sağla: UTF-8 ✓ ve \u2713 karışımını düzelt
Tarama bulguları:
-
Unicode karışıklığı (config_validator.h):
- 25+ satır gerçek ✓ karakteri kullanıyor
- 4 satır (135, 315, 324, 334) \u2713 kaçış dizisini kullanıyor
- Aynı dosyada iki farklı gösterim = tutarsız. Hepsi UTF-8 ✓ karakterine standartlaştır.
-
Başlık eksikliği (config_validator.h):
strlen()kullanılıyor (satırlar 76, 84, 123)- Şu anki:
#include <string>(bu strlen() sağlamaz) - Gerekli:
#include <cstring>ekle (C-tarzı string işlevleri için)
Düzeltilecek satırlar:
- src/config_validator.h satır 135:
\u2713→✓olarak değiştir - src/config_validator.h satır 315:
\u2713→✓olarak değiştir - src/config_validator.h satır 324:
\u2713→✓olarak değiştir - src/config_validator.h satır 334:
\u2713→✓olarak değiştir - src/config_validator.h başına
#include <cstring>ekle
🤖 Prompt for AI Agents
In src/config_validator.h (around lines 54–64 and specifically lines 76, 84,
123, 135, 315, 324, 334), the file mixes literal UTF-8 checkmark characters and
\u2713 escape sequences and is missing the header that provides strlen();
replace every occurrence of the escape sequence \u2713 at lines 135, 315, 324,
and 334 with the literal UTF-8 character ✓ to standardize character
representation, and add #include <cstring> near the top of the file (alongside
the existing #include <string>) so strlen() is available; ensure file is saved
in UTF-8 encoding.
| #define WIFI_SSID "SSID NAME" | ||
| #define WIFI_PASSWORD "WIFI PASSWORD" | ||
| #define WIFI_RETRY_DELAY 500 // milliseconds | ||
| #define WIFI_MAX_RETRIES 20 | ||
| #define WIFI_TIMEOUT 30000 // milliseconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fail‑fast için SSID/parolayı boş bırakıp doğrulamada yakalayalım.
Şu an placeholder metinler boş değil; validator (strlen>0) geçti sayıyor ve cihaz hatalı girişimlere başlıyor. “Geçersiz konfig ile başlamayın” öğrenimine ters.
Uygulama kolay: Varsayılanları boş yapalım, kullanıcı doldurana kadar validator durdursun.
-#define WIFI_SSID "SSID NAME"
-#define WIFI_PASSWORD "WIFI PASSWORD"
+#define WIFI_SSID ""
+#define WIFI_PASSWORD ""Based on learnings
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #define WIFI_SSID "SSID NAME" | |
| #define WIFI_PASSWORD "WIFI PASSWORD" | |
| #define WIFI_RETRY_DELAY 500 // milliseconds | |
| #define WIFI_MAX_RETRIES 20 | |
| #define WIFI_TIMEOUT 30000 // milliseconds | |
| #define WIFI_SSID "" | |
| #define WIFI_PASSWORD "" | |
| #define WIFI_RETRY_DELAY 500 // milliseconds | |
| #define WIFI_MAX_RETRIES 20 | |
| #define WIFI_TIMEOUT 30000 // milliseconds |
🤖 Prompt for AI Agents
In src/config.h around lines 19–23, the WiFi SSID/password placeholders are
non‑empty which bypasses the strlen>0 validator; change the default defines to
empty strings ("" for WIFI_SSID and WIFI_PASSWORD) so the validator fails on
missing credentials and prevent startup with invalid config, and keep/ensure the
existing validation logic blocks initialization until the user supplies values.
| #define SERVER_HOST "192.168.x.x" | ||
| #define SERVER_PORT 9000 | ||
| #define SERVER_RECONNECT_MIN 5000 // milliseconds | ||
| #define SERVER_RECONNECT_MAX 60000 // milliseconds | ||
| #define SERVER_BACKOFF_JITTER_PCT 20 // percent jitter on backoff (0-100) | ||
| #define TCP_WRITE_TIMEOUT 5000 // milliseconds - timeout for send operations | ||
| #define TCP_RECEIVE_TIMEOUT 10000 // milliseconds - timeout for receive operations (primarily for protocol compliance) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
SERVER_HOST’ı da fail‑fast yapalım.
Boş olmayan placeholder (“192.168.x.x”) şu an validator’dan geçiyor. Varsayılanı boş yaparsak hem tutarlı hem güvenli olur.
-#define SERVER_HOST "192.168.x.x"
+#define SERVER_HOST ""Alternatif: Validator’da “x.x” desenini yakalama (üstte önerildi).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #define SERVER_HOST "192.168.x.x" | |
| #define SERVER_PORT 9000 | |
| #define SERVER_RECONNECT_MIN 5000 // milliseconds | |
| #define SERVER_RECONNECT_MAX 60000 // milliseconds | |
| #define SERVER_BACKOFF_JITTER_PCT 20 // percent jitter on backoff (0-100) | |
| #define TCP_WRITE_TIMEOUT 5000 // milliseconds - timeout for send operations | |
| #define TCP_RECEIVE_TIMEOUT 10000 // milliseconds - timeout for receive operations (primarily for protocol compliance) | |
| #define SERVER_HOST "" | |
| #define SERVER_PORT 9000 | |
| #define SERVER_RECONNECT_MIN 5000 // milliseconds | |
| #define SERVER_RECONNECT_MAX 60000 // milliseconds | |
| #define SERVER_BACKOFF_JITTER_PCT 20 // percent jitter on backoff (0-100) | |
| #define TCP_WRITE_TIMEOUT 5000 // milliseconds - timeout for send operations | |
| #define TCP_RECEIVE_TIMEOUT 10000 // milliseconds - timeout for receive operations (primarily for protocol compliance) |
🤖 Prompt for AI Agents
In src/config.h around lines 35 to 42, the SERVER_HOST default uses a non-empty
placeholder ("192.168.x.x") which can pass validation; change the default to an
empty string (e.g. "") and make the configuration fail-fast by adding a
startup/runtime check that rejects/aborts when SERVER_HOST is empty or only
contains placeholder patterns; alternatively, ensure the validator explicitly
rejects "x.x" style placeholders if you prefer keeping a non-empty default.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
@CodeRabbit "create docstrings" |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 1202 🏁 Script executed: Length of output: 3564 🏁 Script executed: Length of output: 5736 @sarpel, I've reviewed your codebase and found something interesting! 🎓 Your code style conventions document (
However, I notice that:
Could you help me understand what you'd like? Option A: Full Docstrings (like Doxygen/JavaDoc style) /**
* @brief Initialize with base buffer size
* @param base_size The initial buffer size in bytes (default: 4096)
* @return void
*/
static void initialize(size_t base_size = 4096);Option B: Keep Inline Style (current convention) // Initialize with base buffer size
static void initialize(size_t base_size = 4096);Option C: Update Convention - Add full docstrings to all public APIs and update the code style guide? Which approach would you prefer? This will help me create consistent documentation across your project! 📚 |
|
@CodeRabbit "Option A" |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 9413 @sarpel, perfect! Let me create comprehensive Doxygen-style docstrings for all your public APIs! 🎓 Here are your fully documented header files: 1. adaptive_buffer.h#ifndef ADAPTIVE_BUFFER_H
#define ADAPTIVE_BUFFER_H
#include <Arduino.h>
/**
* @brief Adaptive buffer sizing based on WiFi signal strength (RSSI)
*
* This class dynamically adjusts buffer sizes based on the current WiFi signal
* quality to optimize streaming performance. Stronger signals allow smaller
* buffers (lower latency), while weaker signals require larger buffers
* (better reliability).
*
* The buffer size adjustments are rate-limited to prevent thrashing and only
* apply when the size change exceeds a minimum threshold (10%).
*/
class AdaptiveBuffer {
public:
/**
* @brief Initialize the adaptive buffer system with a base buffer size
* @param base_size The initial buffer size in bytes (default: 4096)
* @note This must be called during system initialization before any buffer operations
*/
static void initialize(size_t base_size = 4096);
/**
* @brief Update buffer size based on current WiFi RSSI value
* @param rssi The WiFi signal strength in dBm (typically -30 to -100)
* @note Adjustments are rate-limited to once every 5 seconds minimum
* @note Size changes must exceed 10% threshold to be applied
*/
static void updateBufferSize(int32_t rssi);
/**
* @brief Get the current active buffer size
* @return Current buffer size in bytes
*/
static size_t getBufferSize();
/**
* @brief Calculate buffer efficiency score based on current conditions
* @return Efficiency score from 0-100, where 100 is optimal
* @note Score compares current buffer size against the optimal size for last RSSI
*/
static uint8_t getEfficiencyScore();
/**
* @brief Get the last RSSI value used for buffer calculation
* @return Last WiFi signal strength in dBm
*/
static int32_t getLastRSSI();
/**
* @brief Get the total number of buffer size adjustments made
* @return Cumulative count of buffer adjustments since initialization
*/
static uint32_t getAdjustmentCount();
private:
static size_t base_buffer_size; ///< Initial configured buffer size
static size_t current_buffer_size; ///< Current active buffer size
static int32_t last_rssi; ///< Last RSSI measurement used
static uint32_t adjustment_count; ///< Total adjustments made
static unsigned long last_adjustment_time; ///< Timestamp of last adjustment (millis)
/**
* @brief Calculate appropriate buffer size for given signal strength
* @param rssi WiFi signal strength in dBm
* @return Recommended buffer size in bytes (capped at 150% of base)
*/
static size_t calculateBufferSize(int32_t rssi);
};
#endif // ADAPTIVE_BUFFER_H2. debug_mode.h#ifndef DEBUG_MODE_H
#define DEBUG_MODE_H
/**
* @brief Compile-time debug level control
*
* Debug levels:
* - 0 = OFF : No debug output
* - 1 = ERROR : Critical errors only
* - 2 = WARN : Warnings and errors
* - 3 = INFO : Informational messages, warnings, and errors
* - 4 = DEBUG : Detailed debug information
* - 5 = VERBOSE : Maximum verbosity for troubleshooting
*/
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 1
#endif
// Compile-time debug macros
#if DEBUG_LEVEL >= 1
#define DEBUG_ERROR(fmt, ...) LOG_ERROR(fmt, ##__VA_ARGS__)
#else
#define DEBUG_ERROR(fmt, ...)
#endif
#if DEBUG_LEVEL >= 2
#define DEBUG_WARN(fmt, ...) LOG_WARN(fmt, ##__VA_ARGS__)
#else
#define DEBUG_WARN(fmt, ...)
#endif
#if DEBUG_LEVEL >= 3
#define DEBUG_INFO(fmt, ...) LOG_INFO(fmt, ##__VA_ARGS__)
#else
#define DEBUG_INFO(fmt, ...)
#endif
#if DEBUG_LEVEL >= 4
#define DEBUG_LOG(fmt, ...) LOG_DEBUG(fmt, ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...)
#endif
#if DEBUG_LEVEL >= 5
#define DEBUG_VERBOSE(fmt, ...) LOG_DEBUG(fmt, ##__VA_ARGS__)
#else
#define DEBUG_VERBOSE(fmt, ...)
#endif
/**
* @brief Runtime debug context for dynamic debug control
*
* Allows toggling debug output and adjusting verbosity level at runtime
* without recompiling. Useful for production deployments where debug
* output needs to be enabled temporarily via serial commands.
*
* @note This provides runtime control; compile-time macros above control code size
*/
class RuntimeDebugContext {
public:
/**
* @brief Enable or disable runtime debug output
* @param enable True to enable debug output, false to disable
*/
static void setEnabled(bool enable);
/**
* @brief Check if runtime debug output is currently enabled
* @return True if enabled, false otherwise
*/
static bool isEnabled();
/**
* @brief Set the runtime debug level
* @param level Debug level (0=OFF, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=VERBOSE)
*/
static void setLevel(int level);
/**
* @brief Get the current runtime debug level
* @return Current debug level (0-5)
*/
static int getLevel();
/**
* @brief Log a formatted message if runtime debug is enabled
* @param fmt Printf-style format string
* @param ... Variable arguments for format string
* @note Output is suppressed if runtime debug is disabled
*/
static void log(const char* fmt, ...);
private:
static bool enabled; ///< Runtime debug enabled flag
static int level; ///< Current runtime debug level
};
#endif // DEBUG_MODE_H3. i2s_audio.h#ifndef I2S_AUDIO_H
#define I2S_AUDIO_H
#include <Arduino.h>
#include "driver/i2s.h"
#include "config.h"
/**
* @brief I2S Audio Error Classification
*
* Categories for I2S errors to enable intelligent error handling and recovery
*/
enum class I2SErrorType {
NONE, ///< No error occurred
TRANSIENT, ///< Temporary error, retry likely to succeed
PERMANENT, ///< Persistent error, reinitialization needed
FATAL ///< Unrecoverable error, system reboot required
};
/**
* @brief I2S Audio interface management for INMP441 microphone
*
* Manages I2S audio capture with DMA buffering, error tracking, and health
* monitoring. Supports automatic error classification and recovery strategies.
*
* Audio Configuration:
* - Sample Rate: 16kHz (configurable)
* - Bit Depth: 16-bit
* - Channels: Mono (1 channel)
* - DMA Buffers: Configurable count and length
*
* @note All methods are static; this is a singleton-style manager
* @note Thread-safe for single reader (main loop pattern)
*/
class I2SAudio {
public:
/**
* @brief Initialize the I2S audio subsystem
* @return True if initialization successful, false otherwise
* @note Must be called once during system startup
* @note Attempts fallback configuration without APLL if primary init fails
*/
static bool initialize();
/**
* @brief Clean up and deinitialize the I2S driver
* @note Call before system shutdown or when reinitializing
*/
static void cleanup();
/**
* @brief Read audio data from I2S DMA buffer (single attempt)
* @param buffer Destination buffer for audio data
* @param buffer_size Size of destination buffer in bytes
* @param bytes_read Output parameter: actual bytes read
* @return True if read successful, false on error
* @note Non-blocking; returns immediately with available data or error
*/
static bool readData(uint8_t* buffer, size_t buffer_size, size_t* bytes_read);
/**
* @brief Read audio data with automatic retry on transient errors
* @param buffer Destination buffer for audio data
* @param buffer_size Size of destination buffer in bytes
* @param bytes_read Output parameter: actual bytes read
* @param max_retries Maximum number of retry attempts (default: I2S_MAX_READ_RETRIES)
* @return True if read successful within retry limit, false otherwise
* @note Retries are appropriate for transient errors only
*/
static bool readDataWithRetry(uint8_t* buffer, size_t buffer_size, size_t* bytes_read, int max_retries = I2S_MAX_READ_RETRIES);
/**
* @brief Reinitialize the I2S subsystem after a permanent error
* @return True if reinitialization successful, false otherwise
* @note Performs cleanup before attempting initialization
*/
static bool reinitialize();
/**
* @brief Perform health check on I2S subsystem
* @return True if system is healthy, false if intervention needed
* @note Checks initialization state, error rates, and consecutive failures
*/
static bool healthCheck();
/**
* @brief Classify an I2S error for appropriate recovery action
* @param error ESP-IDF error code from I2S operation
* @return Error classification (NONE, TRANSIENT, PERMANENT, FATAL)
*/
static I2SErrorType classifyError(esp_err_t error);
/**
* @brief Get total error count across all categories
* @return Total number of errors encountered
*/
static uint32_t getErrorCount();
/**
* @brief Get count of transient errors (temporary failures)
* @return Number of transient errors
*/
static uint32_t getTransientErrorCount();
/**
* @brief Get count of permanent errors (requiring reinitialization)
* @return Number of permanent errors
*/
static uint32_t getPermanentErrorCount();
private:
static bool is_initialized; ///< I2S driver initialization state
static int consecutive_errors; ///< Count of errors without successful read
static uint32_t total_errors; ///< Total errors (all types)
static uint32_t transient_errors; ///< Count of transient errors
static uint32_t permanent_errors; ///< Count of permanent errors
};
#endif // I2S_AUDIO_H4. network.h#ifndef NETWORK_H
#define NETWORK_H
#include <Arduino.h>
#include <WiFi.h>
#include "config.h"
#include "NonBlockingTimer.h"
#include "adaptive_buffer.h"
/**
* @brief TCP Connection State Machine
*
* Represents the lifecycle of a TCP connection for clear state tracking
* and transition logging.
*/
enum class TCPConnectionState {
DISCONNECTED, ///< No connection, ready for new attempt
CONNECTING, ///< Connection attempt in progress
CONNECTED, ///< Active connection (data can flow)
ERROR, ///< Connection error detected
CLOSING ///< Graceful disconnect in progress
};
/**
* @brief Exponential backoff strategy for connection retry attempts
*
* Implements exponential backoff with configurable min/max delays to
* prevent overwhelming servers during reconnection storms. Each failure
* doubles the delay until max is reached.
*/
class ExponentialBackoff {
private:
unsigned long min_delay; ///< Minimum delay between attempts (ms)
unsigned long max_delay; ///< Maximum delay cap (ms)
unsigned long current_delay; ///< Current delay value (ms)
int consecutive_failures; ///< Count of consecutive failures
public:
/**
* @brief Construct exponential backoff strategy
* @param min_ms Minimum delay in milliseconds (default: SERVER_RECONNECT_MIN)
* @param max_ms Maximum delay cap in milliseconds (default: SERVER_RECONNECT_MAX)
*/
ExponentialBackoff(unsigned long min_ms = SERVER_RECONNECT_MIN,
unsigned long max_ms = SERVER_RECONNECT_MAX);
/**
* @brief Get next delay value and increment for subsequent failure
* @return Delay in milliseconds with applied jitter
* @note Jitter is added to prevent thundering herd
*/
unsigned long getNextDelay();
/**
* @brief Reset backoff to initial state (on successful connection)
*/
void reset();
/**
* @brief Get count of consecutive failures
* @return Number of consecutive connection failures
*/
int getFailureCount() const { return consecutive_failures; }
};
/**
* @brief Network management with WiFi and TCP reliability features
*
* Manages WiFi connectivity, TCP server connections, adaptive buffering based
* on signal strength, and comprehensive error recovery. Includes connection
* state machine, keepalive configuration, and low-latency streaming optimizations.
*
* Features:
* - Automatic WiFi reconnection with retry limits
* - TCP connection state tracking and error recovery
* - Adaptive buffer sizing based on RSSI
* - TCP keepalive and nodelay for streaming
* - Chunked writes with timeout detection
* - Connection uptime and statistics tracking
*
* @note All methods are static; singleton-style manager
*/
class NetworkManager {
public:
/**
* @brief Initialize network subsystem and adaptive buffering
* @note Call once during system startup before any network operations
*/
static void initialize();
/**
* @brief Handle WiFi connection attempts with automatic retry
* @note Non-blocking; uses timers for retry scheduling
* @note Respects WIFI_MAX_RETRIES and WIFI_TIMEOUT configuration
*/
static void handleWiFiConnection();
/**
* @brief Check if WiFi is currently connected
* @return True if WiFi connected, false otherwise
*/
static bool isWiFiConnected();
/**
* @brief Monitor WiFi signal quality and log warnings
* @note Checks RSSI against RSSI_WEAK_THRESHOLD periodically
*/
static void monitorWiFiQuality();
/**
* @brief Update adaptive buffer size based on current RSSI
* @note Should be called periodically to adjust buffer for signal changes
*/
static void updateAdaptiveBuffer();
/**
* @brief Get current adaptive buffer size
* @return Current buffer size in bytes
*/
static size_t getAdaptiveBufferSize();
/**
* @brief Attempt connection to streaming server
* @return True if connection successful, false otherwise
* @note Configures TCP_NODELAY and keepalive options on success
* @note Updates TCP connection state machine
*/
static bool connectToServer();
/**
* @brief Gracefully disconnect from streaming server
* @note Updates connection state and resets backoff timers
*/
static void disconnectFromServer();
/**
* @brief Check if connected to streaming server
* @return True if server connection active, false otherwise
*/
static bool isServerConnected();
/**
* @brief Get reference to underlying WiFi client
* @return Reference to WiFiClient instance
* @warning Direct access; use with caution
*/
static WiFiClient& getClient();
/**
* @brief Get current TCP connection state
* @return Current state from TCPConnectionState enum
*/
static TCPConnectionState getTCPState();
/**
* @brief Check if TCP connection attempt is in progress
* @return True if state is CONNECTING, false otherwise
*/
static bool isTCPConnecting();
/**
* @brief Check if TCP connection is established and healthy
* @return True if state is CONNECTED, false otherwise
*/
static bool isTCPConnected();
/**
* @brief Check if TCP connection is in error state
* @return True if state is ERROR, false otherwise
*/
static bool isTCPError();
/**
* @brief Get time elapsed since last successful write
* @return Milliseconds since last successful write operation
* @note Useful for detecting write timeout conditions
*/
static unsigned long getTimeSinceLastWrite();
/**
* @brief Get connection uptime since last establishment
* @return Milliseconds since connection was established
* @note Returns 0 if not currently connected
*/
static unsigned long getConnectionUptime();
/**
* @brief Write data to server with chunking and timeout detection
* @param data Pointer to data buffer
* @param length Number of bytes to write
* @return True if all data written successfully, false on error
* @note Writes in chunks of TCP_CHUNK_SIZE for optimal streaming
* @note Handles partial writes and validates connection state
*/
static bool writeData(const uint8_t* data, size_t length);
/**
* @brief Get total WiFi reconnection attempts count
* @return Number of times WiFi has reconnected
*/
static uint32_t getWiFiReconnectCount();
/**
* @brief Get total server reconnection attempts count
* @return Number of times server connection has been re-established
*/
static uint32_t getServerReconnectCount();
/**
* @brief Get total TCP error events count
* @return Number of TCP errors encountered
*/
static uint32_t getTCPErrorCount();
/**
* @brief Get count of TCP state transitions
* @return Number of times TCP state has changed
*/
static uint32_t getTCPStateChangeCount();
private:
// Connection state tracking
static TCPConnectionState tcp_state; ///< Current TCP connection state
static unsigned long tcp_state_change_time; ///< Timestamp of last state change
static unsigned long tcp_connection_established_time; ///< Timestamp when connected
static uint32_t tcp_state_changes; ///< Count of state transitions
/**
* @brief Handle TCP error and update state machine
* @param error_source Descriptive string of error source for logging
*/
static void handleTCPError(const char* error_source);
/**
* @brief Update TCP connection state with logging
* @param new_state New state to transition to
*/
static void updateTCPState(TCPConnectionState new_state);
/**
* @brief Validate that connection is still alive
* @return True if connection valid, false if dead/stale
*/
static bool validateConnection();
static bool server_connected; ///< Server connection flag
static unsigned long last_successful_write; ///< Timestamp of last write success
static NonBlockingTimer wifi_retry_timer; ///< WiFi reconnection timer
static NonBlockingTimer server_retry_timer; ///< Server reconnection timer
static NonBlockingTimer rssi_check_timer; ///< RSSI monitoring timer
static ExponentialBackoff server_backoff; ///< Server reconnection backoff
static WiFiClient client; ///< Underlying WiFi client
static uint32_t wifi_reconnect_count; ///< WiFi reconnection counter
static uint32_t server_reconnect_count; ///< Server reconnection counter
static uint32_t tcp_error_count; ///< TCP error counter
static int wifi_retry_count; ///< Current WiFi retry attempt
};
#endif // NETWORK_H5. serial_command.h#ifndef SERIAL_COMMAND_H
#define SERIAL_COMMAND_H
#include <Arduino.h>
// Forward declarations
class NetworkManager;
/**
* @brief Serial command interface for runtime control and diagnostics
*
* Provides a command-line interface over serial for monitoring system health,
* adjusting configuration, and controlling connectivity at runtime without
* requiring reflashing.
*
* Supported Commands:
* - STATUS: Display current system status
* - CONFIG: Query/modify configuration parameters
* - RESTART: Trigger system restart
* - DISCONNECT: Disconnect from server
* - CONNECT: Initiate server connection
* - STATS: Display detailed statistics
* - HEALTH: Run health diagnostics
* - HELP: Display command reference
*
* @note Commands are case-insensitive and newline-terminated
* @note Command processing is non-blocking
*/
class SerialCommandHandler {
public:
/**
* @brief Initialize the serial command handler
* @note Call once during system startup after Serial.begin()
*/
static void initialize();
/**
* @brief Process incoming serial commands (non-blocking)
* @note Call repeatedly in main loop to handle user input
* @note Buffers input until newline, then dispatches to handlers
*/
static void processCommands();
private:
static const size_t BUFFER_SIZE = 128; ///< Maximum command line length
static char command_buffer[BUFFER_SIZE]; ///< Input buffer for command parsing
static size_t buffer_index; ///< Current position in buffer
/**
* @brief Handle STATUS command - display current system state
*/
static void handleStatusCommand();
/**
* @brief Handle CONFIG command - query or modify configuration
* @param args Command arguments (parameter name and optional value)
*/
static void handleConfigCommand(const char* args);
/**
* @brief Handle RESTART command - trigger system restart
*/
static void handleRestartCommand();
/**
* @brief Handle DISCONNECT command - disconnect from server
*/
static void handleDisconnectCommand();
/**
* @brief Handle CONNECT command - initiate server connection
*/
static void handleConnectCommand();
/**
* @brief Handle STATS command - display detailed statistics
*/
static void handleStatsCommand();
/**
* @brief Handle HEALTH command - run system health diagnostics
*/
static void handleHealthCommand();
/**
* @brief Handle HELP command - display command reference
*/
static void handleHelpCommand();
/**
* @brief Print formatted status summary to serial output
*/
static void printStatus();
/**
* @brief Print comprehensive health report to serial output
*/
static void printHealth();
/**
* @brief Clear the command input buffer
*/
static void clearBuffer();
/**
* @brief Tokenize string using delimiter (strtok_r wrapper)
* @param str String to tokenize (NULL for continuation)
* @param delim Delimiter characters
* @return Next token or NULL if no more tokens
*/
static char* getNextToken(char* str, const char* delim);
};
#endif // SERIAL_COMMAND_H6. NonBlockingTimer.h#ifndef NON_BLOCKING_TIMER_H
#define NON_BLOCKING_TIMER_H
#include <Arduino.h>
/**
* @brief Non-blocking timer for periodic or one-shot events
*
* Provides millisecond-precision timing without blocking the main loop.
* Supports both auto-reset (periodic) and one-shot modes, with convenient
* methods for checking expiration and querying remaining time.
*
* Typical usage:
* @code
* NonBlockingTimer timer(1000, true); // 1 second, auto-reset
* timer.start();
*
* void loop() {
* if (timer.check()) {
* // Timer expired, auto-resets if enabled
* doPeriodicTask();
* }
* }
* @endcode
*
* @note Safe against millis() rollover (every ~49.7 days)
*/
class NonBlockingTimer
{
private:
unsigned long previousMillis; ///< Timestamp of last start/reset
unsigned long interval; ///< Timer interval in milliseconds
bool isRunning; ///< Timer running state
bool autoReset; ///< Auto-reset on expiration flag
public:
/**
* @brief Construct a non-blocking timer
* @param intervalMs Timer interval in milliseconds (default: 1000)
* @param autoResetEnabled Auto-reset on expiration (default: true for periodic)
*/
NonBlockingTimer(unsigned long intervalMs = 1000, bool autoResetEnabled = true)
: previousMillis(0), interval(intervalMs), isRunning(false), autoReset(autoResetEnabled) {}
/**
* @brief Set the timer interval
* @param intervalMs New interval in milliseconds
* @note Does not affect currently running timer until next start/reset
*/
void setInterval(unsigned long intervalMs)
{
interval = intervalMs;
}
/**
* @brief Start the timer from current time
* @note Resets internal timestamp to now
*/
void start()
{
previousMillis = millis();
isRunning = true;
}
/**
* @brief Start timer in already-expired state for immediate first trigger
* @note Useful for immediate execution followed by periodic intervals
*/
void startExpired()
{
// Start timer in already-expired state for immediate first trigger
previousMillis = millis() - interval - 1;
isRunning = true;
}
/**
* @brief Stop the timer
* @note Timer can be restarted with start()
*/
void stop()
{
isRunning = false;
}
/**
* @brief Reset the timer to current time without stopping
* @note Resets countdown to full interval
*/
void reset()
{
previousMillis = millis();
}
/**
* @brief Check if timer has expired and handle auto-reset
* @return True if timer expired, false otherwise
* @note If auto-reset enabled, timer automatically restarts
* @note If auto-reset disabled, timer stops after first expiration
*/
bool check()
{
if (!isRunning)
return false;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
if (autoReset)
{
previousMillis = currentMillis;
}
else
{
isRunning = false;
}
return true;
}
return false;
}
/**
* @brief Check if timer has expired without affecting state
* @return True if expired, false otherwise
* @note Unlike check(), does not auto-reset or stop timer
*/
bool isExpired()
{
if (!isRunning)
return false;
return (millis() - previousMillis >= interval);
}
/**
* @brief Get elapsed time since timer started/reset
* @return Elapsed milliseconds
*/
unsigned long getElapsed()
{
return millis() - previousMillis;
}
/**
* @brief Get remaining time until expiration
* @return Remaining milliseconds (0 if already expired)
*/
unsigned long getRemaining()
{
unsigned long elapsed = getElapsed();
return (elapsed >= interval) ? 0 : (interval - elapsed);
}
/**
* @brief Check if timer is currently running
* @return True if running, false if stopped
*/
bool getIsRunning() const
{
return isRunning;
}
/**
* @brief Get configured timer interval
* @return Interval in milliseconds
*/
unsigned long getInterval() const
{
return interval;
}
};
#endif📝 Next Step: Update Code Style ConventionYou should also update ### Docstrings / Comments
**Doxygen-style docstrings for all public APIs:**
- Use `/** ... */` blocks with @brief, @param, @return, @note tags
- Document all public classes, methods, enums, and significant members
- Include usage examples for complex interfaces
- Explain thread-safety, lifecycle requirements, and side effects
**Inline documentation:**
- Use `///` for member variable documentation
- Use `//` for implementation notes within method bodies
- Section headers remain with `// ========== SECTION ==========`Would you like me to help you update the code style conventions document as well? 📚 ✏️ Learnings added
|
|
@CodeRabbit "Yes. I would like you to help me update the code style conventions document as well" |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 1202 @sarpel, perfect! Here's your updated code style conventions document with the new Doxygen-style docstring standard! 📚 Updated # Code Style & Conventions
## Naming Conventions
- **Constants**: `UPPER_SNAKE_CASE` (e.g., `WIFI_SSID`, `I2S_SAMPLE_RATE`)
- **Functions**: `camelCase` (e.g., `gracefulShutdown()`, `checkMemoryHealth()`)
- **Variables**: `snake_case` (e.g., `free_heap`, `audio_buffer`)
- **Classes/Structs**: `PascalCase` (e.g., `SystemStats`, `StateManager`)
- **Defines**: `UPPER_SNAKE_CASE`
## Code Organization
- Includes at top of file with sections (Arduino.h, config.h, etc.)
- Function declarations before globals
- Global state after declarations
- Main implementation after setup/loop
- Comments with `=====` separators for major sections
## Docstring/Comments Style
### Doxygen-style docstrings for all public APIs
- Use `/** ... */` blocks with standard Doxygen tags
- Document all public classes, methods, enums, and significant members
- Required tags:
- `@brief` - Short description (first sentence)
- `@param` - Parameter description (one per parameter)
- `@return` - Return value description
- `@note` - Important notes, warnings, or usage constraints
- Optional tags as needed:
- `@warning` - Critical warnings about usage
- `@code` / `@endcode` - Usage example blocks
- `@see` - Cross-references to related functions
- Include usage examples for complex interfaces
- Explain thread-safety, lifecycle requirements, and side effects
**Example:**
```cpp
/**
* @brief Initialize the adaptive buffer system with a base buffer size
* @param base_size The initial buffer size in bytes (default: 4096)
* @return True if initialization successful, false otherwise
* @note This must be called during system initialization before any buffer operations
*/
static bool initialize(size_t base_size = 4096);Inline documentation
Example: class MyClass {
private:
size_t buffer_size; ///< Current buffer size in bytes
bool is_initialized; ///< Initialization state flag
unsigned long last_update; ///< Timestamp of last update (millis)
};Implementation comments
Type Hints
Error Handling
Learnt from: sarpel Timestamp: 2025-10-21T14:37:50.565Z Learnt from: sarpel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
README.md (1)
5-8: Boş bağlantıları rozetlerden çıkarın.Rozetlerin etrafındaki
(#)bağlantıları MD042 ihlali oluşturuyor. Sanki resmin çerçevesinden kağıdı çıkarıyoruz gibi, bağlantı sarmalamasını kaldır. Böyle yapınca rozetler güzel duruyor ama fazladan parantez gidiyor.Örnek olarak, şu:
[](#)Bunu yap:
-[](#) +Dört rozet için de aynı şeyi uygula (RAM, Flash, License).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
README.md(1 hunks)platformio.ini(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- platformio.ini
🧰 Additional context used
📓 Path-based instructions (2)
**/*.md
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.md: Keep Markdown line length ~100 characters
Use tables for structured data in Markdown
Include examples for complex topics in Markdown docs
Link to related documentation from Markdown files
Files:
README.md
README.md
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Maintain the project overview in README.md
Files:
README.md
🪛 markdownlint-cli2 (0.18.1)
README.md
5-5: No empty links
(MD042, no-empty-links)
6-6: No empty links
(MD042, no-empty-links)
7-7: No empty links
(MD042, no-empty-links)
8-8: No empty links
(MD042, no-empty-links)
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
46-46: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
89-89: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
132-132: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
139-139: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
146-146: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
153-153: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
159-159: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
167-167: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
192-192: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
| ``` | ||
| INMP441 Pin → ESP32 Pin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kod bloklarına dil etiketleri ekle.
Burada biraz teknik bir kural var: Markdown'da kod bloğu yazarken (backtick üçlüsü ile), hangi dilden yazıyorsan onu söylemelisin. Mesela "bu bir text dosyası" ya da "bu bash komutu" gibi. Etiket yoksa linter çiçek açıyor ve MD040 hatası veriyor. Pin haritaları ve komut örnekleri için text etiketini kullan.
Aşağıdaki diffı uygula:
-```
+```text
INMP441 Pin → ESP32 Pin
CLK → GPIO 14
WS → GPIO 15
SD → GPIO 32
GND → GND
VCC → 3V3
-```
+```Aynı şekilde diğer kod bloklara da (`-`` başlayan tüm bloklar):
- Satır 46-53: Pin mapping →
text - Satır 89-95: Expected Output →
text - Satır 132-135: STATS komutu →
text - Satır 139-142: DEBUG komutu →
text - Satır 146-149: SIGNAL komutu →
text - Satır 153-155: RECONNECT komutu →
text - Satır 159-161: HELP komutu →
text - Satır 167-186: Mimari diyagram →
text - Satır 192-200: Komut başvurusu →
text
Also applies to: 46-47, 89-90, 132-133, 139-140, 146-147, 153-154, 159-160, 167-168, 192-193
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
Summary by CodeRabbit
Sürüm Notları
Yeni Özellikler
İyileştirmeler