# Task 4 Brief: USB discovery and endpoint model ## Context Tasks 1-3 are complete. CMake remains unavailable on PATH; keep CMakeLists.txt correct but use direct MinGW g++ verification if CMake cannot run. ## 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/device.hpp - Create: src/core/device.cpp - Create: tests/cpp/test_device_model.cpp - Modify: CMakeLists.txt - Modify: include/mag160c/mag160c.h - Modify: src/c_api.cpp - Update: progress.md with the checkpoint. ## Interfaces to produce - mag160c::core::EndpointType - mag160c::core::EndpointDescriptor - mag160c::core::EndpointPair - mag160c::core::DeviceInfo - mag160c::core::is_in_endpoint - mag160c::core::find_bulk_pair - mag160c::core::list_devices - mag160c_list_devices C ABI - mag160c_free_device_list C ABI ## Required constants and structs ```cpp constexpr uint16_t MAG_IR_VENDOR_ID = 0x833c; constexpr uint16_t MAG_IR_PRODUCT_ID = 0x0001; enum class EndpointType { Other, Bulk, Interrupt, Isochronous }; struct EndpointDescriptor { uint8_t address = 0; EndpointType type = EndpointType::Other; }; struct EndpointPair { uint8_t bulk_in = 0; uint8_t bulk_out = 0; }; struct DeviceInfo { mag160c_device_info_t c_info{}; }; ``` ## Required public C struct and declarations Add to include/mag160c/mag160c.h: ```c typedef struct mag160c_device_info_t { uint16_t vendor_id; uint16_t product_id; uint8_t bus; uint8_t address; uint8_t interface_number; uint8_t bulk_in_endpoint; uint8_t bulk_out_endpoint; char product[128]; char manufacturer[128]; char serial[128]; } mag160c_device_info_t; MAG160C_API mag160c_error_t mag160c_list_devices( mag160c_context_t* ctx, mag160c_device_info_t** out_devices, size_t* out_count ); MAG160C_API void mag160c_free_device_list(mag160c_device_info_t* devices); ``` ## Required endpoint behavior - is_in_endpoint returns true when endpoint address has bit 0x80 set. - find_bulk_pair scans endpoints and returns the first bulk IN and first bulk OUT. - find_bulk_pair returns false if either direction is absent. - find_bulk_pair returns false for null out pointer. ## Required list_devices behavior - If out is null, return MAG160C_ERR_INVALID_ARGUMENT. - If MAG160C_HAS_LIBUSB is 0, return MAG160C_ERR_UNSUPPORTED and set last_error explaining libusb was not available at build time. - If MAG160C_HAS_LIBUSB is 1 and no matching device is present, return MAG160C_OK and an empty vector. - Only match VID 0x833C and PID 0x0001 initially. - If libusb is enabled, inspect config descriptors and report the first interface/altsetting with both bulk IN and bulk OUT. - Avoid including libusb.h unless MAG160C_HAS_LIBUSB is true so direct no-libusb builds compile. ## Required C ABI behavior - mag160c_list_devices requires ctx, out_devices, and out_count. - On invalid arguments, return MAG160C_ERR_INVALID_ARGUMENT. - Initialize *out_devices to null and *out_count to 0 before enumeration. - On empty device list, return MAG160C_OK with null devices and count 0. - On non-empty list, allocate an array with new[] and copy mag160c_device_info_t values. - mag160c_free_device_list deletes the array and accepts null. ## Required tests Create tests/cpp/test_device_model.cpp: - endpoints {0x01 interrupt, 0x82 bulk, 0x03 bulk} returns bulk_in 0x82 and bulk_out 0x03. - endpoints {0x82 bulk} returns false because bulk OUT is absent. - optional: null out pointer returns false. Extend tests/cpp/test_c_api.cpp if convenient: - mag160c_list_devices(nullptr, nullptr, nullptr) returns MAG160C_ERR_INVALID_ARGUMENT. - with a valid context and MAG160C_HAS_LIBUSB=0, mag160c_list_devices returns MAG160C_ERR_UNSUPPORTED, devices remains null, count remains 0. ## CMake update - Add src/core/device.cpp to mag160c_core sources. - Add test_device_model executable linked to mag160c_core. - Give test_device_model access to src private headers. - Register test_device_model with CTest. ## Verification First try: ```powershell cmake --build build ctest --test-dir build --output-on-failure ``` If CMake is unavailable, run: ```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\core\tcm_device.cpp src\core\device.cpp src\c_api.cpp tests\cpp\test_c_api.cpp -o build_task4_c_api_test.exe .\build_task4_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\core\tcm_device.cpp src\core\device.cpp src\c_api.cpp tests\cpp\test_device_model.cpp -o build_task4_device_model_test.exe .\build_task4_device_model_test.exe ``` Expected: both executables exit 0. ## Progress checkpoint Append this line to progress.md after verification: ```markdown - Implemented Task 4 USB device model, endpoint-pair selection, and C ABI device listing/freeing. ``` ## Report contract Write a report to .superpowers/sdd/task-4-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