| 112 | // ---------------------------------------------------------------------------- |
| 113 | |
| 114 | bool SPITransposer::transpose4(const fl::optional<LaneData>& lane0, |
| 115 | const fl::optional<LaneData>& lane1, |
| 116 | const fl::optional<LaneData>& lane2, |
| 117 | const fl::optional<LaneData>& lane3, |
| 118 | fl::span<u8> output, |
| 119 | const char** error) { |
| 120 | // Validate output buffer size (must be divisible by 4) |
| 121 | if (output.size() % 4 != 0) { |
| 122 | if (error) { |
| 123 | *error = "Output buffer size must be divisible by 4"; |
| 124 | } |
| 125 | return false; |
| 126 | } |
| 127 | |
| 128 | // Calculate max lane size from output buffer |
| 129 | const size_t max_size = output.size() / 4; |
| 130 | |
| 131 | // Handle empty case |
| 132 | if (max_size == 0) { |
| 133 | if (error) { |
| 134 | *error = nullptr; // No error, just empty |
| 135 | } |
| 136 | return true; |
| 137 | } |
| 138 | |
| 139 | // Create array of lane references for easier iteration |
| 140 | const fl::optional<LaneData>* lanes[4] = {&lane0, &lane1, &lane2, &lane3}; |
| 141 | |
| 142 | // Determine default padding byte from first available lane |
| 143 | u8 default_padding = 0x00; |
| 144 | for (size_t i = 0; i < 4; i++) { |
| 145 | if (lanes[i]->has_value() && !(*lanes[i])->padding_frame.empty()) { |
| 146 | default_padding = (*lanes[i])->padding_frame[0]; |
| 147 | break; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | // Gather all bytes from each lane into temporary buffers |
| 152 | fl::vector<u8> lane_buffers[4]; |
| 153 | const u8* lane_ptrs[4]; |
| 154 | |
| 155 | for (size_t lane = 0; lane < 4; lane++) { |
| 156 | lane_buffers[lane].resize(max_size); |
| 157 | lane_ptrs[lane] = lane_buffers[lane].data(); |
| 158 | |
| 159 | for (size_t byte_idx = 0; byte_idx < max_size; byte_idx++) { |
| 160 | lane_buffers[lane][byte_idx] = lanes[lane]->has_value() ? |
| 161 | getLaneByte(**lanes[lane], byte_idx, max_size) : default_padding; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | // Perform transposition using ISR-safe primitive |
| 166 | transpose_4lane_inline(lane_ptrs, output.data(), max_size); |
| 167 | |
| 168 | if (error) { |
| 169 | *error = nullptr; // Success, no error |
| 170 | } |
| 171 | return true; |