# Task 2 Brief: TCM frame codec ## Context Task 1 is complete. Existing files include CMakeLists.txt, include/mag160c/mag160c.h, src/core/error.*, src/core/context.*, src/c_api.cpp, and tests/cpp/test_c_api.cpp. CMake is currently unavailable on PATH in this environment. Still keep CMakeLists.txt correct, but if CMake verification cannot run, use direct MinGW g++ verification and record the substitution in the report. ## Global constraints - Use only original source code; do not link proprietary SDK binaries. - Current workspace is not a git repository; replace commit steps with verification plus updates to progress.md. - Keep public C ABI free of C++ types. - Use C++17. - libusb-1.0 is the only native runtime dependency for the core library. - Firmware update commands are not exposed as an easy accidental CLI action. - IR protocol gaps return MAG160C_ERR_PROTOCOL_UNKNOWN or MAG160C_ERR_UNSUPPORTED. ## Files - Create: src/core/tcm_frame.hpp - Create: src/core/tcm_frame.cpp - Create: tests/cpp/test_tcm_frame.cpp - Modify: CMakeLists.txt - Modify: include/mag160c/mag160c.h - Modify: src/c_api.cpp - Update: progress.md with the checkpoint at the end. ## Interfaces to produce - mag160c::core::TcmFrame - mag160c::core::checksum(const uint8_t* data, size_t begin, size_t end) - mag160c::core::encode_tcm_frame(uint8_t main_cmd, uint8_t sub_cmd, uint16_t frame_id, const std::vector& payload) - mag160c::core::decode_tcm_frame(const uint8_t* data, size_t size, TcmFrame* out) - mag160c_tcm_encode_frame C ABI - mag160c_tcm_decode_header C ABI ## TCM frame rules - Header byte 0 is 0x7e. - Bytes 1..2 are big-endian body length. - Byte 3 is additive checksum over bytes 0..2. - Body is main, sub, frame high, frame low, payload, body checksum. - Body checksum is additive checksum over body bytes before the final checksum byte. - Body length is payload length + 5. - Minimum valid full packet length is 9 bytes. ## Required exact test vector Encoding main 0x02, sub 0x77, frame id 0x0001, payload {0x00, 0x05} must produce: ```text 7e 00 07 85 02 77 00 01 00 05 7f ``` ## Required tests Create tests/cpp/test_tcm_frame.cpp with: - test_rotate_frame_encoding: exact bytes above. - test_decode_rejects_bad_header_checksum: corrupt byte 3 and expect MAG160C_ERR_CHECKSUM. - test_decode_roundtrip: encode then decode and assert main, sub, frame id, payload. ## Required C++ header src/core/tcm_frame.hpp must declare: ```cpp #pragma once #include "mag160c/mag160c.h" #include #include #include namespace mag160c::core { struct TcmFrame { uint8_t main_cmd = 0; uint8_t sub_cmd = 0; uint16_t frame_id = 0; std::vector payload; }; uint8_t checksum(const uint8_t* data, size_t begin, size_t end); std::vector encode_tcm_frame(uint8_t main_cmd, uint8_t sub_cmd, uint16_t frame_id, const std::vector& payload); mag160c_error_t decode_tcm_frame(const uint8_t* data, size_t size, TcmFrame* out); } ``` ## Required C ABI declarations Add to include/mag160c/mag160c.h inside the extern C block: ```c MAG160C_API mag160c_error_t mag160c_tcm_encode_frame( uint8_t main_cmd, uint8_t sub_cmd, uint16_t frame_id, const uint8_t* payload, size_t payload_size, uint8_t* out_bytes, size_t out_capacity, size_t* out_size ); MAG160C_API mag160c_error_t mag160c_tcm_decode_header( const uint8_t* data, size_t size, uint8_t* out_main_cmd, uint8_t* out_sub_cmd, uint16_t* out_frame_id, size_t* out_payload_size ); ``` ## Required C ABI behavior - mag160c_tcm_encode_frame requires out_size. - If output buffer is null or too small, set out_size to the required encoded size and return MAG160C_ERR_INVALID_ARGUMENT. - If payload_size is nonzero and payload is null, return MAG160C_ERR_INVALID_ARGUMENT. - On success, copy encoded bytes, set out_size, clear last error, return MAG160C_OK. - mag160c_tcm_decode_header requires all output pointers. - It should call decode_tcm_frame and return any error from it. - On success, fill main, sub, frame id, and payload size. ## CMake update - Add src/core/tcm_frame.cpp to mag160c_core sources. - Add test_tcm_frame executable linked to mag160c_core. - Give test_tcm_frame access to src private headers. - Register test_tcm_frame with CTest. ## Verification First try: ```powershell cmake --build build ctest --test-dir build --output-on-failure ``` If CMake is unavailable, run direct verification equivalent to: ```powershell g++ -std=c++17 -DMAG160C_STATIC -DMAG160C_HAS_LIBUSB=0 -Iinclude -Isrc src\core\error.cpp src\core\context.cpp src\core\tcm_frame.cpp src\c_api.cpp tests\cpp\test_c_api.cpp -o build_task2_c_api_test.exe .\build_task2_c_api_test.exe g++ -std=c++17 -DMAG160C_STATIC -DMAG160C_HAS_LIBUSB=0 -Iinclude -Isrc src\core\error.cpp src\core\context.cpp src\core\tcm_frame.cpp src\c_api.cpp tests\cpp\test_tcm_frame.cpp -o build_task2_tcm_frame_test.exe .\build_task2_tcm_frame_test.exe ``` Expected: both executables exit 0. ## Progress checkpoint Append this line to progress.md after verification: ```markdown - Implemented Task 2 TCM frame codec with byte-exact encode/decode tests and C ABI utility functions. ``` ## Report contract Write a report to .superpowers/sdd/task-2-report.md with: - status: DONE, DONE_WITH_CONCERNS, NEEDS_CONTEXT, or BLOCKED - files created/modified - exact commands run - test results - concerns, if any - self-review notes