| 31 | #include "pixel_controller.h" |
| 32 | |
| 33 | FL_TEST_FILE(FL_FILEPATH) { |
| 34 | |
| 35 | using namespace fl; |
| 36 | |
| 37 | namespace { |
| 38 | |
| 39 | /// Helper to extract 16-bit big-endian value from byte span |
| 40 | u16 getBigEndian16(const fl::span<const u8>& bytes, size_t offset) { |
| 41 | return (u16(bytes[offset]) << 8) | u16(bytes[offset + 1]); |
| 42 | } |
| 43 | |
| 44 | /// Helper to decode RGB gains from HD108 header bytes |
| 45 | void decodeGains(u8 f0, u8 f1, u8* r_gain, u8* g_gain, u8* b_gain) { |
| 46 | // f0: [1][RRRRR][GG] - marker bit, 5-bit R gain, 2 MSBs of G gain |
| 47 | *r_gain = (f0 >> 2) & 0x1F; |
| 48 | u8 g_msb = f0 & 0x03; |
| 49 | |
| 50 | // f1: [GGG][BBBBB] - 3 LSBs of G gain, 5-bit B gain |
| 51 | u8 g_lsb = (f1 >> 5) & 0x07; |
| 52 | *g_gain = (g_msb << 3) | g_lsb; |
| 53 | *b_gain = f1 & 0x1F; |
| 54 | } |
| 55 | |
| 56 | /// Helper to verify header bytes match expected RGB gains |
| 57 | void checkHeaderBytes(u8 f0, u8 f1, u8 expected_r, u8 expected_g, u8 expected_b) { |
| 58 | // Verify f0 encoding: 0x80 | ((r_gain & 0x1F) << 2) | ((g_gain >> 3) & 0x03) |
| 59 | u8 expected_f0 = 0x80 | ((expected_r & 0x1F) << 2) | ((expected_g >> 3) & 0x03); |
| 60 | FL_CHECK_EQ(f0, expected_f0); |
| 61 | |
| 62 | // Verify f1 encoding: ((g_gain & 0x07) << 5) | (b_gain & 0x1F) |
| 63 | u8 expected_f1 = ((expected_g & 0x07) << 5) | (expected_b & 0x1F); |
| 64 | FL_CHECK_EQ(f1, expected_f1); |
| 65 | |
| 66 | // Verify decoded gains match |
| 67 | u8 r_decoded, g_decoded, b_decoded; |
| 68 | decodeGains(f0, f1, &r_decoded, &g_decoded, &b_decoded); |
| 69 | FL_CHECK_EQ(r_decoded, expected_r); |
| 70 | FL_CHECK_EQ(g_decoded, expected_g); |
| 71 | FL_CHECK_EQ(b_decoded, expected_b); |
| 72 | } |
| 73 | |
| 74 | /// Test fixture that exposes protected showPixels method |
| 75 | template<int DATA_PIN, fl::u8 CLOCK_PIN, EOrder RGB_ORDER> |
| 76 | class HD108TestController : public HD108Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> { |
| 77 | public: |
| 78 | using HD108Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER>::showPixels; |
| 79 | }; |
| 80 | |
| 81 | /// Helper to capture bytes from a controller without using FastLED.show() |
| 82 | /// This provides complete test isolation by directly calling the controller |
| 83 | /// Returns an owned vector to avoid lifetime issues |
| 84 | template<int DATA_PIN, fl::u8 CLOCK_PIN, EOrder RGB_ORDER> |
| 85 | fl::vector<u8> captureBytes(const CRGB* leds, int num_leds, u8 brightness) { |
| 86 | // CRITICAL: Ensure complete isolation between tests |
| 87 | // Clear all previous strip data and reset tracking state |
| 88 | ActiveStripData& stripData = ActiveStripData::Instance(); |
| 89 | stripData.onBeginFrame(); // Clears mStripMap |
| 90 | ActiveStripTracker::resetForTesting(); |
nothing calls this directly
no test coverage detected