Software Architecture
Understanding the internal design and organization of SerialyTTY.
System Overviewโ
SerialyTTY is built on a modular architecture using ESP-IDF framework and FreeRTOS.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application Layer โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ Menu โ โ Bridge โ โ Baud Detect โ โ
โ โ System โ โ Mode โ โ โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Hardware Abstraction โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ Display โ โ SD โ โ Hardware โ โ
โ โ Manager โ โ Logger โ โ Detector โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Driver Layer (ESP-IDF) โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ UART โ โ SPI โ โ I2C โ โ
โ โ Driver โ โ Driver โ โ Driver โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ FreeRTOS Kernel โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Module Breakdownโ
Main Application (main.cpp)โ
Central orchestrator managing system state and module coordination.
Responsibilities:
- System initialization
- State machine management
- Module lifecycle control
- Main event loop
State Machine:
enum SystemState {
STATE_BOOTING, // Initialization
STATE_MENU, // User interaction
STATE_ANALYZING, // Baud detection active
STATE_FOUND_SPEED, // Detection complete
STATE_BRIDGE, // Passthrough mode
STATE_TESTING // Communication test
};
Hardware Detector (hardware_detector.h/cpp)โ
Discovers and validates connected peripherals.
class HardwareDetector {
public:
HardwareConfig scanAll();
bool detectDisplay();
bool detectSDCard();
bool detectI2CDevices();
private:
I2CScanner i2cScanner;
GPIOProbe gpioProbe;
};
Detection Process:
- I2C bus scan (0x08-0x77)
- GPIO probe for CS lines
- SPI initialization tests
- Configuration object creation
Display Manager (display_manager.h/cpp)โ
Abstracts TFT display operations with state-aware rendering.
class DisplayManager {
public:
bool begin();
void setState(SystemState state);
void setStatus(const char* status);
void update();
void showStats(uint32_t rxBytes, uint32_t txBytes);
private:
TFTDriver tft;
SystemState currentState;
void renderBootScreen();
void renderMenuScreen();
void renderBridgeScreen();
};
Rendering Pipeline:
- State change detection
- Screen buffer preparation
- DMA transfer initiation
- Frame update completion
Baud Detector (baud_detector.h/cpp)โ
Interrupt-driven timing analysis for baud rate detection.
class BaudDetector {
public:
void start();
void stop();
uint32_t getDetectedBaud();
bool isDetectionComplete();
private:
static void IRAM_ATTR rxISR(void* arg);
void analyzeTiming();
uint32_t calculateBaud();
std::vector<uint32_t> timingSamples;
volatile bool detecting;
};
Algorithm:
- Configure GPIO interrupt (falling edge)
- Capture edge timestamps (ESP timer)
- Calculate bit periods
- Match to standard baud rates
- Verify consistency
SD Logger (sd_logger_espidf.h/cpp)โ
VFS-based filesystem logging with structured format.
class SDLogger {
public:
bool begin();
void log(LogLevel level, const char* message);
void logData(const char* prefix, uint8_t* data, size_t len);
void flush();
private:
FILE* logFile;
uint32_t entryCount;
std::string formatTimestamp();
std::string formatHexDump(uint8_t* data, size_t len);
};
File Operations:
- Mount:
/sdcardmount point - Path:
/sdcard/logs/log_YYYYMMDD_HHMMSS.txt - Write: Buffered with periodic flush
- Close: Safe unmount on shutdown
Bridge Mode (bridge_mode.h/cpp)โ
Bidirectional UART-to-USB passthrough.
class BridgeMode {
public:
void start(uint32_t baudRate);
void stop();
void process();
uint32_t getRxBytes();
uint32_t getTxBytes();
private:
void forwardUART0ToUART1();
void forwardUART1ToUART0();
bool checkEscapeSequence();
uint32_t rxCounter;
uint32_t txCounter;
char escapeBuffer[4];
};
Data Flow:
USB (UART0) โโ Bridge Controller โโ UART1 (Target)
โ โ
Statistics Statistics
Menu System (menu_system.h/cpp)โ
ANSI terminal UI with command processing.
class MenuSystem {
public:
void show();
void handleInput(char cmd);
void printHelp();
void printInfo();
private:
void clearScreen();
void printHeader();
void printCommands();
static const char* ANSI_CLEAR;
static const char* ANSI_BOLD;
static const char* ANSI_RESET;
};
ANSI Codes:
\033[2J- Clear screen\033[H- Cursor home\033[1m- Bold text\033[0m- Reset formatting
Data Flowโ
Boot Sequenceโ
Power On
โ
Initialize FreeRTOS
โ
Setup USB Serial (UART0)
โ
Scan Hardware (I2C, GPIO)
โ
Initialize Display (if present)
โ
Mount SD Card (if present)
โ
Initialize UART1
โ
Setup Baud Detector
โ
Show Menu
Baud Detection Flowโ
User presses 'D'
โ
Enter ANALYZING state
โ
Configure GPIO16 interrupt
โ
Wait for data... (interrupt fires)
โ
Capture timestamps
โ
Calculate bit periods
โ
Match to standard bauds
โ
Display result
โ
Enter FOUND_SPEED state
Bridge Mode Flowโ
User presses 'B'
โ
Configure UART1 (detected baud)
โ
Enter BRIDGE state
โ
Loop:
โโ Read UART0 โ Write UART1
โโ Read UART1 โ Write UART0
โโ Update counters
โโ Check escape sequence
โโ Update display
โ
Escape detected ('~~~')
โ
Return to MENU state
Memory Managementโ
Static Allocationโ
Advantages:
- Deterministic behavior
- No fragmentation
- Fast allocation
Usage:
static uint8_t displayBuffer[76800]; // 240x320 RGB565
static char logBuffer[512]; // SD card writes
static uint8_t uartRxBuffer[1024]; // UART receive
Heap Usageโ
ESP32-C6 Memory Map:
- Total RAM: 320 KB
- FreeRTOS: ~20 KB
- WiFi/BLE: ~40 KB (if enabled)
- Application: ~260 KB available
Optimization:
- Use
IRAM_ATTRfor ISRs - DMA buffers in DMA-capable RAM
- Stack size tuning per task
Interrupt Handlingโ
Priority Levelsโ
| Interrupt | Priority | Notes |
|---|---|---|
| GPIO (Baud Detect) | 3 | High - timing critical |
| UART RX | 2 | Medium - data critical |
| SPI (DMA) | 1 | Low - background |
| Timer | 2 | Medium - scheduling |
ISR Best Practicesโ
void IRAM_ATTR rxISR(void* arg) {
// MINIMAL code in ISR
uint32_t timestamp = esp_timer_get_time();
xQueueSendFromISR(queue, ×tamp, NULL);
// Processing in task context
}
Threading Modelโ
FreeRTOS Tasksโ
// Main task (default)
void app_main(void) {
// Priority: 1
// Stack: 8KB
setup_hardware();
while(1) {
process_state_machine();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
// Display update task (future)
void display_task(void* arg) {
// Priority: 2
// Stack: 4KB
while(1) {
update_display();
vTaskDelay(pdMS_TO_TICKS(33)); // 30 FPS
}
}
Synchronizationโ
- Mutex: SPI bus access (display vs SD)
- Semaphore: UART buffer ready
- Queue: ISR to task communication
- Event Group: State transitions
Configuration Systemโ
Compile-Time (config.h)โ
#define MIN_BAUD 9600
#define MAX_BAUD 115200
#define SPI_FREQ_MHZ 40
#define SD_MOUNT_POINT "/sdcard"
#define LOG_BUFFER_SIZE 512
Runtime (sdkconfig)โ
ESP-IDF menuconfig options:
- FreeRTOS tick rate
- UART buffer sizes
- SPI DMA channels
- Logging levels
Error Handling Strategyโ
Graceful Degradationโ
if (!display.begin()) {
ESP_LOGW(TAG, "Display not available");
// Continue without display
}
if (!logger.begin()) {
ESP_LOGW(TAG, "SD logging disabled");
// Continue without logging
}
Error Recoveryโ
esp_err_t err = uart_driver_install(...);
if (err != ESP_OK) {
ESP_LOGE(TAG, "UART init failed: %s",
esp_err_to_name(err));
return false;
}
Performance Metricsโ
Typical Operationโ
- Boot time: ~3 seconds
- Baud detection: <1 second
- Bridge latency: <1 ms
- Display update: 30 FPS
- SD write speed: ~100 KB/s
- CPU utilization: 15-25%
Optimization Techniquesโ
- DMA for bulk transfers
- Interrupt-driven I/O
- Minimal ISR code
- Efficient state machine
- Buffered logging
Next: Learn about Testing procedures and validation.