mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-09-21 20:39:35 +00:00
feat(protocol): derive wire size and airtime at compile time
This commit is contained in:
158
IR_config.h
158
IR_config.h
@ -264,6 +264,164 @@ typedef uint16_t crc_t;
|
||||
#define bitTime (bitTakts * carrierPeriod) // Общая длительность бита
|
||||
#define tolerance 300U
|
||||
|
||||
namespace irproto
|
||||
{
|
||||
/** Maximum complete frame length representable by the five header bits. */
|
||||
constexpr uint8_t kMaxWireFrameBytes = static_cast<uint8_t>(IR_MASK_MSG_INFO);
|
||||
|
||||
constexpr uint8_t kDataFrameOverheadBytes = msgBytes + addrBytes + addrBytes + crcBytes;
|
||||
constexpr uint8_t kBackFrameOverheadBytes = msgBytes + addrBytes + crcBytes;
|
||||
constexpr uint8_t kBackToFrameOverheadBytes = msgBytes + addrBytes + addrBytes + crcBytes;
|
||||
constexpr uint8_t kAcceptFrameBytes = msgBytes + addrBytes + 1U + crcBytes;
|
||||
constexpr uint8_t kRequestFrameBytes = msgBytes + addrBytes + addrBytes + crcBytes;
|
||||
|
||||
constexpr uint8_t kMaxDataPayloadBytes = kMaxWireFrameBytes - kDataFrameOverheadBytes;
|
||||
constexpr uint8_t kMaxBackPayloadBytes = kMaxWireFrameBytes - kBackFrameOverheadBytes;
|
||||
constexpr uint8_t kMaxBackToPayloadBytes = kMaxWireFrameBytes - kBackToFrameOverheadBytes;
|
||||
|
||||
/** Complete DATA frame size, or zero when payloadBytes cannot fit on wire. */
|
||||
constexpr uint8_t dataWireBytes(uint8_t payloadBytes)
|
||||
{
|
||||
return payloadBytes <= kMaxDataPayloadBytes
|
||||
? static_cast<uint8_t>(kDataFrameOverheadBytes + payloadBytes)
|
||||
: 0U;
|
||||
}
|
||||
|
||||
/** Complete non-addressed BACK frame size, or zero when it cannot fit. */
|
||||
constexpr uint8_t backWireBytes(uint8_t payloadBytes)
|
||||
{
|
||||
return payloadBytes <= kMaxBackPayloadBytes
|
||||
? static_cast<uint8_t>(kBackFrameOverheadBytes + payloadBytes)
|
||||
: 0U;
|
||||
}
|
||||
|
||||
/** Complete addressed BACK_TO frame size, or zero when it cannot fit. */
|
||||
constexpr uint8_t backToWireBytes(uint8_t payloadBytes)
|
||||
{
|
||||
return payloadBytes <= kMaxBackToPayloadBytes
|
||||
? static_cast<uint8_t>(kBackToFrameOverheadBytes + payloadBytes)
|
||||
: 0U;
|
||||
}
|
||||
|
||||
/** Minimum complete frame size for a known message type; zero means reserved/unknown. */
|
||||
constexpr uint8_t minimumWireBytes(uint8_t msgType)
|
||||
{
|
||||
return (msgType == IR_MSG_DATA_ACCEPT || msgType == IR_MSG_DATA_NOACCEPT)
|
||||
? kDataFrameOverheadBytes
|
||||
: msgType == IR_MSG_BACK
|
||||
? kBackFrameOverheadBytes
|
||||
: (msgType == IR_MSG_BACK_TO || msgType == IR_MSG_REQUEST)
|
||||
? kRequestFrameBytes
|
||||
: msgType == IR_MSG_ACCEPT
|
||||
? kAcceptFrameBytes
|
||||
: 0U;
|
||||
}
|
||||
|
||||
constexpr bool isTypedWireSizeValid(uint8_t msgType, uint8_t wireBytes)
|
||||
{
|
||||
return minimumWireBytes(msgType) != 0U &&
|
||||
wireBytes >= minimumWireBytes(msgType) &&
|
||||
wireBytes <= kMaxWireFrameBytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* TX FSM timing contract.
|
||||
*
|
||||
* The FSM runs on 2*carrierFrec. The preamble contains preambPulse*2
|
||||
* constant runs; each run is preambToggle+1 ticks. Every data bit and every
|
||||
* per-byte sync bit occupies bitTakts*2 ticks, independently of its value.
|
||||
*/
|
||||
constexpr uint32_t kTxLogicalClockHz = static_cast<uint32_t>(carrierFrec) * 2U;
|
||||
constexpr uint32_t kPreambleLogicalTicks =
|
||||
static_cast<uint32_t>(preambPulse * 2U) * static_cast<uint32_t>(preambToggle + 1U);
|
||||
constexpr uint32_t kEncodedBitLogicalTicks = static_cast<uint32_t>(bitTakts * 2U);
|
||||
constexpr uint32_t kWireByteLogicalTicks =
|
||||
static_cast<uint32_t>(bitPerByte + syncBits) * kEncodedBitLogicalTicks;
|
||||
|
||||
constexpr uint32_t wireLogicalTicks(uint8_t wireBytes)
|
||||
{
|
||||
return wireBytes != 0U && wireBytes <= kMaxWireFrameBytes
|
||||
? kPreambleLogicalTicks + static_cast<uint32_t>(wireBytes) * kWireByteLogicalTicks
|
||||
: 0U;
|
||||
}
|
||||
|
||||
constexpr uint32_t logicalTicksToUsCeil(uint32_t logicalTicks)
|
||||
{
|
||||
return logicalTicks == 0U
|
||||
? 0U
|
||||
: static_cast<uint32_t>(
|
||||
(static_cast<uint64_t>(logicalTicks) * 1000000ULL +
|
||||
static_cast<uint64_t>(kTxLogicalClockHz) - 1ULL) /
|
||||
static_cast<uint64_t>(kTxLogicalClockHz));
|
||||
}
|
||||
|
||||
constexpr uint32_t preambleAirtimeUsCeil()
|
||||
{
|
||||
return logicalTicksToUsCeil(kPreambleLogicalTicks);
|
||||
}
|
||||
|
||||
/** Complete nominal on-air duration, rounded up to a whole microsecond. */
|
||||
constexpr uint32_t wireAirtimeUsCeil(uint8_t wireBytes)
|
||||
{
|
||||
return logicalTicksToUsCeil(wireLogicalTicks(wireBytes));
|
||||
}
|
||||
|
||||
constexpr uint32_t wireAirtimeMsCeil(uint8_t wireBytes)
|
||||
{
|
||||
return wireAirtimeUsCeil(wireBytes) == 0U
|
||||
? 0U
|
||||
: (wireAirtimeUsCeil(wireBytes) + 999U) / 1000U;
|
||||
}
|
||||
|
||||
/* Preserve the deployed library turn-around policy, but expose it by name. */
|
||||
constexpr uint16_t kMandatoryInterPacketQuietMs =
|
||||
static_cast<uint16_t>(
|
||||
static_cast<uint16_t>(
|
||||
(static_cast<uint32_t>(bitTime + tolerance) *
|
||||
static_cast<uint32_t>(bitPerByte + syncBits + 1U)) *
|
||||
2.7735) /
|
||||
1000U);
|
||||
constexpr uint32_t kMandatoryInterPacketQuietUs =
|
||||
static_cast<uint32_t>(kMandatoryInterPacketQuietMs) * 1000U;
|
||||
|
||||
constexpr uint16_t kDefaultTimingGuardPermille = 1150U;
|
||||
|
||||
constexpr uint32_t addTimingGuardUs(uint32_t durationUs,
|
||||
uint16_t marginPermille = kDefaultTimingGuardPermille)
|
||||
{
|
||||
return marginPermille == 0U
|
||||
? 0U
|
||||
: static_cast<uint32_t>(
|
||||
(static_cast<uint64_t>(durationUs) * marginPermille + 999ULL) / 1000ULL);
|
||||
}
|
||||
|
||||
/** Deadline for seeing enough preamble to know that a response has started. */
|
||||
constexpr uint32_t responseStartGuardUs(
|
||||
uint16_t marginPermille = kDefaultTimingGuardPermille)
|
||||
{
|
||||
return addTimingGuardUs(kMandatoryInterPacketQuietUs + preambleAirtimeUsCeil(),
|
||||
marginPermille);
|
||||
}
|
||||
|
||||
/** Conservative deadline for receiving a complete response of maxWireBytes. */
|
||||
constexpr uint32_t responseFrameGuardUs(
|
||||
uint8_t maxWireBytes,
|
||||
uint16_t marginPermille = kDefaultTimingGuardPermille)
|
||||
{
|
||||
return wireAirtimeUsCeil(maxWireBytes) == 0U
|
||||
? 0U
|
||||
: addTimingGuardUs(kMandatoryInterPacketQuietUs +
|
||||
wireAirtimeUsCeil(maxWireBytes),
|
||||
marginPermille);
|
||||
}
|
||||
|
||||
static_assert(kMaxDataPayloadBytes == 24U, "DATA payload contract changed");
|
||||
static_assert(kMaxBackPayloadBytes == 26U, "BACK payload contract changed");
|
||||
static_assert(kPreambleLogicalTicks == 588U, "preamble timing contract changed");
|
||||
static_assert(kWireByteLogicalTicks == 814U, "wire-byte timing contract changed");
|
||||
static_assert(kMandatoryInterPacketQuietMs == 42U, "inter-packet quiet policy changed");
|
||||
}
|
||||
|
||||
constexpr uint16_t test_all_Time = bitTime;
|
||||
constexpr uint16_t test_all_Takts = bitTakts * 2;
|
||||
constexpr uint16_t test_hi = ((bitPauseTakts) * 2 - 0) + ((bitActiveTakts) * 2 - 0);
|
||||
|
||||
Reference in New Issue
Block a user