174 lines
5.4 KiB
Markdown
174 lines
5.4 KiB
Markdown
# 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<uint8_t>& 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 <cstddef>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
namespace mag160c::core {
|
|
|
|
struct TcmFrame {
|
|
uint8_t main_cmd = 0;
|
|
uint8_t sub_cmd = 0;
|
|
uint16_t frame_id = 0;
|
|
std::vector<uint8_t> payload;
|
|
};
|
|
|
|
uint8_t checksum(const uint8_t* data, size_t begin, size_t end);
|
|
std::vector<uint8_t> encode_tcm_frame(uint8_t main_cmd, uint8_t sub_cmd, uint16_t frame_id, const std::vector<uint8_t>& 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
|