* @brief Solves gs_usb bit-timing segments for a target bitrate from BT_CONST limits. */
| 184 | * @brief Solves gs_usb bit-timing segments for a target bitrate from BT_CONST limits. |
| 185 | */ |
| 186 | [[nodiscard]] static bool solveBitTiming(const GsDeviceBtConst& bt, |
| 187 | std::uint32_t bitrate, |
| 188 | GsDeviceBitTiming& out) |
| 189 | { |
| 190 | if (bitrate == 0 || bt.fclkCan == 0) |
| 191 | return false; |
| 192 | |
| 193 | const std::uint32_t step = std::max<std::uint32_t>(1, bt.brpInc); |
| 194 | for (std::uint32_t brp = bt.brpMin; brp <= bt.brpMax; brp += step) { |
| 195 | const std::uint32_t divisor = bitrate * brp; |
| 196 | if (divisor == 0 || (bt.fclkCan % divisor) != 0) |
| 197 | continue; |
| 198 | |
| 199 | const std::uint32_t total = bt.fclkCan / divisor; |
| 200 | if (total < 1 + bt.tseg1Min + bt.tseg2Min || total > 1 + bt.tseg1Max + bt.tseg2Max) |
| 201 | continue; |
| 202 | |
| 203 | std::uint32_t tseg2 = static_cast<std::uint32_t>(std::lround(total * 0.125)); |
| 204 | tseg2 = std::clamp(tseg2, std::max<std::uint32_t>(1, bt.tseg2Min), bt.tseg2Max); |
| 205 | if (total <= 1 + tseg2) |
| 206 | continue; |
| 207 | |
| 208 | const std::uint32_t tseg1 = total - 1 - tseg2; |
| 209 | if (tseg1 < bt.tseg1Min || tseg1 > bt.tseg1Max) |
| 210 | continue; |
| 211 | |
| 212 | out.phaseSeg2 = tseg2; |
| 213 | out.phaseSeg1 = std::max<std::uint32_t>(1, tseg1 / 2); |
| 214 | out.propSeg = tseg1 - out.phaseSeg1; |
| 215 | if (out.propSeg == 0) { |
| 216 | out.propSeg = 1; |
| 217 | out.phaseSeg1 = tseg1 - 1; |
| 218 | } |
| 219 | |
| 220 | out.sjw = std::min(bt.sjwMax, tseg2); |
| 221 | out.brp = brp; |
| 222 | return true; |
| 223 | } |
| 224 | |
| 225 | return false; |
| 226 | } |
| 227 | |
| 228 | /** |
| 229 | * @brief Decodes a received gs_host_frame; returns false for TX echoes that must be dropped. |
no test coverage detected