Repository navigation
Conversation
The T330 collar variant reads shock intensity from the lower nibble (0-15) of the intensity byte, not as a raw 0-100 value. The upper bits carry a rolling counter and toggle bit. Map 0-100 intensity to 0-15 level in the lower nibble and maintain per-shocker rolling state (counter + toggle) in the upper bits. Vibrate and sound encoding remain unchanged.
e15d8e2 to
6ae60f4
Compare
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The 4-bit level + toggle/counter shock encoding belongs to a different collar variant, not the stock Wellturn T330. Restore the T330 encoder to develop's version and port the encoding to a new WellturnT330Alt1 model in the components/protocols layout. The encoder takes the current time as a parameter instead of calling millis(), so the protocols component stays free of a clock dependency and the rolling state is host-testable. Sequence keeps the last command and RFTransmitter calls refill(now) before each payload frame; refill is a no-op for models without rolling state.
| uint8_t intensityByte = intensity; | ||
| if (type == ShockerCommandType::Shock) { | ||
| auto& state = s_shockState[shockerId]; | ||
| uint8_t level = (intensity * 15) / 100; |
There was a problem hiding this comment.
should this have a floor at 1? 1-6 produce level 0 in the final 4-bit field
we might want similar logic as:
There was a problem hiding this comment.
Good catch, fixed in ea68d05. This encoding now lives in its own WellturnT330Alt1 model (the stock T330 is back to develop), and shock uses the same floor as D80: any non-zero intensity is at least level 1. Added test cases for 1, 6 and 14%.
|
|
||
| if (timeToLive > 0) { | ||
| // Send the command | ||
| seq->refill(); |
There was a problem hiding this comment.
we're ignoring the return value, not sure it matters since it looks a little edge-casey but if it returns false we might want to log an error or skip the transmit for that round, vs now i think the prior contents of the payload buffer would be transmitted
There was a problem hiding this comment.
Fixed in ea68d05. If refill() fails, the transmit loop now logs an error and sets the sequence's end to now, so it goes straight to the terminator instead of resending the previous payload. That matches what modifySequence already does when fill() fails.
- Floor non-zero shock intensities at level 1, like D80, so 1-6% no longer encode as level 0. - Terminate a sequence instead of resending a stale frame when refill() fails, and log it. - Add the namespace comment clang-format wants on T330Alt1Encoder.h.
Summary
[toggle:1][counter:3][level:4]). The stock T330 takes a raw 0-100 value.WellturnT330Alt1model ("wellturnt330alt1"/"t330alt1"). The stockWellturnT330encoder is unchanged fromdevelop.Sequencestores the last command and has a newrefill(nowMs).RFTransmittercalls it before each payload frame. It does nothing for models without rolling state.millis(), so theprotocolscomponent stays free of a clock dependency and the rolling logic can be host-tested without anesp_timermock.refill()fails, the sequence is terminated and logged instead of resending the previous frame.Limitations
ShockerModelTypeschema has no value for it (D80 has the same gap), so commands from the hub or backend are dropped untilschemas, the backend and the frontend are updated.Known issues to follow up
baseCounter + 1, which can repeat a counter value already sent during a long previous press.std::unordered_mapthat never removes entries.Test plan
components/protocols,components/common,components/device_control)wellturnt330model behaves exactly as it does ondevelop