Skip to content

Progress Log: Text Command Module Refactoring Planning

Task Description

Planning and design for consolidating text protocol layer (4 files, 1321 lines) into a unified text_command module with similar structure to binary command but accounting for higher complexity:

Current Structure (Text Protocol - Problem)

include/
  ├── text_protocol.h (114 lines)
  └── text_protocol_handler.h (101 lines)

src/
  ├── text_protocol.cpp (241 lines)
  └── text_protocol_handler.cpp (865 lines)

Identified Issues

  1. Type Definitions Scattered: text_command_t, command_response_t, command_handler_t, etc. split across files
  2. Unclear Boundaries: Protocol layer vs handler layer responsibility unclear
  3. Large Handler File: 865 lines of command handlers in single file
  4. Dependency Chain: Include dependencies: text_protocol.h → text_protocol_handler.h → multiple subsystems

Proposed Solution: Hybrid Consolidation

include/
  └── text_command.h (225 lines estimated)
      ├── All type definitions
      ├── Protocol layer declarations
      └── Handler declarations

src/
  ├── text_command.cpp (241 lines)
  │   ├── Reception & availability functions
  │   ├── Queue management
  │   ├── Flow control (text_receive, text_execute)
  │   └── Parsing & dispatching
  │
  └── text_command_handlers.cpp (865 lines)
      ├── Command dispatch table
      ├── Command alias table
      ├── Response utilities
      ├── Helper functions
      └── All command handlers (10+ functions)

Analysis & Design Decisions

Why Hybrid Approach (not full consolidation)?

Comparison with Binary Command:

  • Binary: 1 command type, 3 files → consolidated to 1 file ✅
  • Text: 10+ command types, 4 files → split to 2 implementation files ✅

Rationale:

  1. File Size Management: 241 + 865 = 1106 lines, split maintains ~500-600 line modules (editor friendly)
  2. Separation of Concerns:
  3. text_command.cpp: Protocol mechanics (serial I/O, parsing, queuing)
  4. text_command_handlers.cpp: Command logic (SET_THRESHOLD, LED, WIFI, etc.)
  5. Scalability: Adding new command only requires editing text_command_handlers.cpp
  6. Header Simplification: Single text_command.h (unified API despite dual implementation)

8-Section Organization for text_command.h

Section 1: Configuration Constants
- TEXT_COMMAND_QUEUE_SIZE = 10
- TEXT_COMMAND_TIMEOUT_MS = 500
- MAX_COMMAND_LENGTH = 64
- MAX_COMMAND_ARGS = 2

Section 2: Type Definitions
- text_command_t (command structure)
- command_response_t (response structure)
- command_handler_t (function pointer type)
- command_entry_t (dispatch table entry)
- command_alias_t (alias mapping)

Section 3: Initialization
- text_command_init(void)

Section 4: Reception & Availability
- text_available(void)
- text_receive_line(char* buffer, int buffer_size)

Section 5: Queue Management
- text_queue(text_command_t cmd)
- text_queued(void)
- text_dequeue(void) → command_response_t

Section 6: Flow Control
- text_receive(void)
- text_execute(void)

Section 7: Parsing & Dispatching
- text_parse(const char* line) → text_command_t
- text_dispatch(text_command_t cmd) → command_response_t

Section 8: Response Utilities (internal)
- (Internal functions - not in public header for this version)

Definitions

text_command.h

// ============================================================================
// SECTION 1: CONFIGURATION CONSTANTS
// ============================================================================
#define TEXT_COMMAND_QUEUE_SIZE 10
#define TEXT_COMMAND_TIMEOUT_MS 500
#define MAX_COMMAND_LENGTH 64
#define MAX_COMMAND_ARGS 2

// ============================================================================
// SECTION 2: TYPE DEFINITIONS
// ============================================================================
typedef struct {
  char command_name[32];
  uint8_t arg_count;
  char args[MAX_COMMAND_ARGS][16];
  char raw_buffer[MAX_COMMAND_LENGTH];
} text_command_t;

typedef struct {
  bool is_ok;
  char message[512];
} command_response_t;

typedef command_response_t (*command_handler_t)(text_command_t cmd);

typedef struct {
  const char* name;
  command_handler_t handler;
} command_entry_t;

typedef struct {
  const char* alias;
  const char* full_name;
} command_alias_t;

// ============================================================================
// SECTION 3: INITIALIZATION
// ============================================================================
void text_command_init(void);

// ============================================================================
// SECTION 4: RECEPTION & AVAILABILITY
// ============================================================================
bool text_available(void);
bool text_receive_line(char* buffer, int buffer_size);

// ============================================================================
// SECTION 5: QUEUE MANAGEMENT
// ============================================================================
bool text_queue(text_command_t cmd);
bool text_queued(void);
command_response_t text_dequeue(void);

// ============================================================================
// SECTION 6: FLOW CONTROL
// ============================================================================
bool text_receive(void);
bool text_execute(void);

// ============================================================================
// SECTION 7: PARSING & DISPATCHING
// ============================================================================
text_command_t text_parse(const char* line);
command_response_t text_dispatch(text_command_t cmd);

text_command.cpp

// text_command.cpp は Section 4-7 のみ実装
// Section 1-3 は定義のみ(ヘッダーにある)

// ============================================================================
// SECTION 4: RECEPTION & AVAILABILITY
// ============================================================================
bool text_available(void) { ... }
bool text_receive_line(char* buffer, int buffer_size) { ... }

// ============================================================================
// SECTION 5: QUEUE MANAGEMENT
// ============================================================================
static text_command_t text_command_queue[TEXT_COMMAND_QUEUE_SIZE];
// ... queue variables ...
bool text_queue(text_command_t cmd) { ... }
bool text_queued(void) { ... }
command_response_t text_dequeue(void) { ... }

// ============================================================================
// SECTION 6: FLOW CONTROL
// ============================================================================
bool text_receive(void) { ... }
bool text_execute(void) { ... }

// ============================================================================
// SECTION 7: PARSING & DISPATCHING
// ============================================================================
text_command_t text_parse(const char* line) { ... }
command_response_t text_dispatch(text_command_t cmd) { ... }

text_command_handlers.cpp

// text_command_handlers.cpp はハンドラーのみ実装
#include "text_command.h"
#include "cosmic_detector.h"
#include "runtime_config.h"
#include "dac_manager.h"
#include "wifi_manager.h"
#include <ArduinoJson.h>

// ============================================================================
// COMMAND TABLES & CONFIGURATION
// ============================================================================
static const command_alias_t alias_table[] = { ... };
static const command_entry_t command_table[] = { ... };

// ============================================================================
// RESPONSE UTILITIES
// ============================================================================
static void text_response_ok(const __FlashStringHelper* message) { ... }
static void text_response_error(const __FlashStringHelper* command, ...) { ... }

// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
static void to_uppercase(char* str) { ... }
static void resolve_command_alias(char* command_name) { ... }
static bool is_valid_char(char c) { ... }

// ============================================================================
// COMMAND HANDLERS
// ============================================================================
static command_response_t handle_set_poll_count(text_command_t cmd) { ... }
static command_response_t handle_set_threshold(text_command_t cmd) { ... }
// ... 10+ more handlers ...
#if ENABLE_WIFI
static command_response_t handle_wifi_enable(text_command_t cmd) { ... }
// ... WiFi handlers ...
#endif

Implementation Split Plan

text_command.cpp (241 lines - Protocol Layer):

  • Section 4: text_available(), text_receive_line()
  • Section 5: text_queue(), text_queued(), text_dequeue()
  • Section 6: text_receive(), text_execute()
  • Section 7: text_parse(), text_dispatch()
  • Static variables: FIFO queue management

text_command_handlers.cpp (865 lines - Command Processing):

  • Command dispatch table (maps command names to handlers)
  • Command alias table (single-letter shortcuts)
  • Response utilities: text_response_ok(), text_response_error()
  • Helper functions: to_uppercase(), resolve_command_alias(), is_valid_char()
  • 10+ command handlers:
  • handle_set_poll_count()
  • handle_set_threshold()
  • handle_get_threshold()
  • handle_get_version()
  • handle_status()
  • handle_led()
  • handle_uptime()
  • handle_reset()
  • handle_set_interval()
  • handle_help()
  • handle_wifi_* (3 functions, ENABLE_WIFI conditional)

Benefits of This Approach

Aspect Current Proposed
Header Files 2 1
Implementation Files 2 2
Type Definition Location Scattered Unified (text_command.h)
API Clarity Unclear Clear (single header)
Protocol/Handler Separation Via filenames Via file contents
Handler Maintenance Slow (find across files) Fast (single file)
New Command Addition 3+ files to touch 1 file (handlers)

Outcome (So Far)

Design Status: ✅ Complete Implementation Status: 🔄 Ready to begin

Finalized Architecture Pattern

This approach unifies the "protocol vs command" naming confusion from binary refactoring:

  1. Single Header (text_command.h): Presents unified API regardless of implementation
  2. Dual Implementation (text_command.cpp + text_command_handlers.cpp):
  3. Separates protocol mechanics from command logic
  4. Allows independent scaling of each layer
  5. Consistent with Binary Command: Both use command in naming (not protocol)

Files to Create

  1. include/text_command.h (new, unified types + declarations)
  2. src/text_command.cpp (new, from text_protocol.cpp)
  3. src/text_command_handlers.cpp (new, from text_protocol_handler.cpp)
  4. Update include/serial_protocol.h (change includes)
  5. Delete old files (text_protocol.h, text_protocol_handler.h, text_protocol.cpp, text_protocol_handler.cpp)

Learnings

Architecture Insights (from Binary Command refactoring)

  1. New-First Strategy: Works well - create new files, verify build, delete old files
  2. Section Numbering: Consistent 8-section pattern improves readability across modules
  3. Hybrid Consolidation: Not all consolidations are 1:1 - complex modules may benefit from 1 header + 2 implementations
  4. Dependency Removal: Implementing utilities locally (e.g., binary_discard) improves encapsulation

Text Protocol Specific Insights

  1. Handler Complexity: 865 lines of command handlers suggests handler separation is justified
  2. Type Proliferation: 5 typedef declarations better co-located than scattered
  3. Table-Driven Dispatch: Command/alias tables are reference-heavy (benefit from dedicated section)

Next Steps

Implementation Plan (v1.8.10)

  1. Create text_command.h:
  2. Copy structure from binary_command.h
  3. Add 5 typedef definitions
  4. Declare all text-specific functions (sections 3-7)

  5. Create text_command.cpp:

  6. Copy implementation from text_protocol.cpp
  7. Adjust section numbers to match header
  8. Keep queue management static variables

  9. Create text_command_handlers.cpp:

  10. Copy implementation from text_protocol_handler.cpp
  11. Update include from text_protocol_handler.h → text_command.h
  12. No functional changes (just file reorganization)

  13. Update serial_protocol.h:

  14. Change: #include "text_protocol.h"#include "text_command.h"
  15. Change: #include "text_protocol_handler.h" (delete, merged into text_command.h)

  16. Build & Verify:

  17. task dev:build
  18. task prod:build
  19. Verify no new errors

  20. Delete Old Files:

  21. include/text_protocol.h
  22. include/text_protocol_handler.h
  23. src/text_protocol.cpp
  24. src/text_protocol_handler.cpp

  25. Version & Release:

  26. Bump to v1.8.10
  27. Create release notes
  28. Update CHANGELOG

Estimated Changes

  • Files: 4 → 3 (reduction by 1 file)
  • Code Lines: No change (1321 lines → 1321 lines, just reorganized)
  • Headers: 2 → 1 (type definition consolidation)
  • Build Time: Slightly faster (fewer header includes)
  • Compile Dependencies: Simplified (single header reference)