RFPPF 4.0.9

dotnet add package RFPPF --version 4.0.9
                    
NuGet\Install-Package RFPPF -Version 4.0.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RFPPF" Version="4.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RFPPF" Version="4.0.9" />
                    
Directory.Packages.props
<PackageReference Include="RFPPF" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RFPPF --version 4.0.9
                    
#r "nuget: RFPPF, 4.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RFPPF@4.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RFPPF&version=4.0.9
                    
Install as a Cake Addin
#tool nuget:?package=RFPPF&version=4.0.9
                    
Install as a Cake Tool

RFPPF {#mainpage}

RF-Networks Protocol Parser Framework

LICENSE

Copyright (C) 2019 RF-Networks Ltd. All Rights Reserved.

Changelog

  • 3.0.0 - First version

  • 3.0.2 - Check-In message voltage fix

      	 - Check-In message voltage byte(15) is divided to 62.5
    
  • 3.0.3 - Old protocol tag periodic message fix

      	 - Old protocol tag periodic message max voltage raised up to 5V
    
  • 3.0.4 - GPIO sensor message change

      	 - GPIO sensor message added trigger mask and value mask
    
  • 3.0.5 - GPS message added

      	 - Receiver GPS message added
    
  • 3.0.6 - Old protocol receiver configuration message fix

      	 - Receiver Configuration message bugfix
    
  • 3.0.7 - Old protocol receiver configuration messages added

      	 - Receiver Configuration Voltage, External Voltage, Temperature messages added
    
      	 - Receiver Modem Voltage message added
    
  • 3.0.8 - Old protocol receiver configuration messages fix

      	 - Receiver Configuration message bugfix
    
  • 3.0.9 - Old protocol receiver configuration external voltage messages fix

      	 - Receiver Configuration External voltage message DataSize exception fix bugfix
    
  • 3.0.10 - Minor bugfixes

      	 - Minor bugfixes
    
  • 3.0.11 - Old protocol receiver configuration temperature messages fix

      	 - Receiver Configuration Temperature message DataSize exception fix bugfix (old versions of radio send 2 bytes instead of 1)
    
  • 3.0.12 - Java version fix

      	 - Java version bugfixes
    
  • 3.0.13 - New message types added

          - Mesh BME280 message changed
    
          - Mesh GPIO16, Analog3 messages added
    
  • 3.0.14 - Message factory fix for RFM protocol

          - ParseMeshMessage function added
    
  • 3.0.15 - Bugfixes

          - Minor bugfixes and Mesh message ToString function implemented
    
  • 3.0.16 - Bugfixes

          - Mesh protocol parsing bugfix
    
  • 3.0.17 - Mesh scheduler messages

          - Mesh scheduler messages implementation
    
          - Minor bugfixes
    
  • 3.0.18 - Mesh scheduler event messages

          - Mesh scheduler event messages implementation
    
  • 3.0.19 - Bugfix

          - Mesh set scheduler messages parsing bugfix
    
  • 3.0.20 - Bugfix

          - Java version fixes
    
  • 3.0.21 - DS18B20 Sensor Bugfix

          - DS18B20 Sensor mesh message size fixes
    
  • 3.0.22 - DS18B20 Sensor Bugfix

          - DS18B20 Sensor mesh message temperature fixes
    
  • 3.0.23 - Bugfix

          - Minor bugfixes
    
  • 3.0.24 - DiagnosticTestInfoMessage change

          - DiagnosticTestInfoMessage structure change
    
  • 3.0.25 - DiagnosticTestInfoMessage fixes

          - DiagnosticTestInfoMessage fixes
    
  • 3.0.26 - TesterCommandMessage fix

          - TesterCommandMessage fix
    
  • 3.0.27 - TagAveragePulsesPerSecondMessage added

          - TagAveragePulsesPerSecondMessage message type added
    
  • 3.0.28 - Old protocol parser fix

          - Old protocol parser fix
    
  • 3.0.29 - TagAveragePulsesPerSecondMessage change

          - TagAveragePulsesPerSecondMessage message structure change (Voltage removed)
    
  • 3.0.30 - TagAveragePulsesPerSecondMessage Java fix

          - TagAveragePulsesPerSecondMessage message Java fix
    
  • 3.0.31 - C# Bug fix

      	 - Data sensor missing messages type fix
    
  • 3.0.32 - Receiver Weight & Modbus Meter messages added

      	 - Receiver Weight message added
    
      	 - Receiver Modbus Meter message added
    
  • 3.0.33 - Mesh protocol version 2 implemented

      	 - Mesh protocol version 2 implemented
    
  • 3.0.34 - Mesh protocol check out message added

      	 - Mesh protocol check out message added
    
  • 3.0.35 - DS18B20 Sensor Message parsing fix

      	 - DS18B20 Sensor Message parsing fix
    
  • 3.0.36 - Old protocol Acknowledge Message parsing fix

      	 - Old protocol Acknowledge Message parsing fix
    
  • 3.0.37 - Old protocol Extended Protocol with GPS message added

      	 - Old protocol Extended Protocol with GPS message added
    
  • 3.0.38 - Old protocol Extended Protocol with PH & EC message added

      	 - Old protocol Extended Protocol with PH & EC message added
    
  • 3.0.39 - Old protocol Extended Protocol with PH & EC message fix

      	 - Old protocol Extended Protocol with PH & EC message fix
    
  • 3.0.40 - Old protocol Mesh & Mesh RSSI parsers added

      	 - Old protocol Mesh & Mesh RSSI parsers added
    
  • 3.0.41 - Old protocol Mesh & Mesh RSSI parsers fix

      	 - Old protocol Mesh & Mesh RSSI parsers fix
    
  • 3.0.42 - Old protocol Extended Protocol with magnitude message added

      	 - Old protocol Extended Protocol with magnitude message added
    
  • 3.0.44 - Old protocol Extended Protocol with magnitude message fixes

      	 - Old protocol Extended Protocol with magnitude message fixes
    
  • 3.0.45 - Bufgixes

      	 - Tag Extended protocol message RSSI fix
    
      	 - Tag Extended protocol magnitude message added
    
  • 3.0.46 - Bufgixes

      	 - Tag Extended protocol message GPS fix
    
  • 3.0.47 - Bufgixes

      	 - Tag Extended protocol parsing fix
    
  • 3.0.48 - Tag Extended protocol Moistures array & Temperatures array messages

      	 - Tag Extended protocol Moistures array & Temperatures array messages added
    
  • 3.0.49 - Mesh protocol messages bugfix

      	 - Mesh protocol messages bugfix
    
  • 3.0.50 - Mesh protocol GPIOV2 & AnalogV2 messages

      	 - Mesh protocol GPIOV2 & AnalogV2 messages added
    
  • 3.0.51 - Old protocol Receiver WhoIAm, PRCRequest and RPCResponse messages added

      	 - Old protocol Receiver WhoIAm, PRCRequest and RPCResponse messages added
    
  • 3.0.52 - Bugfixes

      	 - Bugfixes
    
  • 3.0.53 - Gateway messages added to GPRS message

      	 - Gateway messages added to GPRS message
    
      	 - Old protocol Receiver WhoIAm, PRCRequest and RPCResponse messages are depricated
    
  • 3.0.54 - GPRS message Gateway messages generate functions added

      	 - GPRS message Gateway messages generate functions added
    
  • 3.0.55 - GPRS message Gateway message generation function fix

      	 - GPRS message Gateway message generation function fix
    
  • 3.0.56 - GPRS message parametrized constructor bugfix

      	 - GPRS message parametrized constructor bugfix
    
  • 3.0.57 - GPRS WhoIAm message radio bootloader version field added

      	 - GPRS WhoIAm message radio bootloader version field added
    
  • 3.0.58 - Old protocol tag pressure message pressure multiplier changed to 100

      	 - Old protocol tag pressure message pressure multiplier changed to 10
    
  • 3.0.59 - Java bit-stuffing decode bugfix

      	 - Java bit-stuffing decode bugfix
    
  • 3.0.60 - Mesh protocol SI7021V2 message

      	 - Mesh protocol SI7021V2 message added
    
  • 3.0.61 - Mesh protocol DiagnosticChildrenList message

      	 - Mesh protocol DiagnosticChildrenList message added
    
  • 3.0.62 - Mesh protocol GPIOV2 message fix

      	 - Mesh protocol GPIOV2 message fix
    
  • 3.0.63 - Mesh protocol CheckIn message change

      	 - Mesh protocol CheckIn message Upload and Download error percentage fields added
    
  • 3.0.64 - Old protocol Extended Protocol CO2 and Binary data messages added

      	 - Old protocol Extended Protocol CO2 and Binary data messages added
    
  • 3.0.65 - Old protocol Extended Protocol parsing fix

      	 - Old protocol Extended Protocol parsing fix
    
  • 3.0.66 - Old protocol Extended Protocol message size fix

      	 - Old protocol Extended Protocol message size fix
    
  • 3.0.67 - Mesh protocol PulseCounterV2 message added

      	 - Mesh protocol PulseCounterV2 message added
    
  • 3.0.68 - Old protocol Extended Protocol Repeater message added

      	 - Old protocol Extended Protocol Repeater message added
    
  • 4.0.0 - Architecture refactor: handler chains, Template Method parsers, decorators

      	 - Handler chain (Chain of Responsibility) added for each protocol family:
      	   OldProtocol/Mesh (`MeshMessageHandler → ReceiverMessageHandler → TagMessageHandler → ErrorMessageHandler`),
      	   RFM (`RFMEnvelopeHandler → ErrorMessageHandler`), GPRS (`GPRSEnvelopeHandler → ErrorMessageHandler`)
    
      	 - `ProtocolParser` rewritten as a Template Method base handling buffer management
      	   and event firing; subclasses implement only `ParseFrame`; frame extraction moved
      	   into pluggable `IFrameDecoder` strategies (`BitStuffingFrameDecoder`,
      	   `AnchorLengthFrameDecoder`, `MagicHeaderFrameDecoder`)
    
      	 - `LoggingParserDecorator` and `FilteringParserDecorator` added
    
      	 - `MessageRegistry` converted to a Meyer's singleton with self-registering message types
    
      	 - Structured error reporting added: `ParseErrorCode` enum, `ParseException`,
      	   and `ErrorMessage.GetProperties()` now returns `Error`, `ErrorCode`, `RawFrame`
    
      	 - `MessageTypeId` enum expanded to cover all protocol families
    
      	 - Breaking: `MeshRSSIParser`, `SensorRecord.SensorRecords`,
      	   `SensorRecord.SensorMessage`, and `MessageFactory.ParseMeshMessage` deprecated
      	   in favour of `MeshParser`/`GetProperties()`; scheduled for removal in v5.0
    
      	 - Bugfixes: `ProtocolParser.AppendBytes` missing `out` keyword corrected;
      	   `RFMParseContext` accessors fixed for .NET 4.6 compatibility
    
  • 4.0.1 - Frame decoding and CO2 message bugfixes

      	 - `BitStuffingFrameDecoder` fixed to extract every complete frame present in the
      	   buffer per call instead of only the first one, so messages are no longer
      	   silently dropped or misattributed when multiple frames arrive together
    
      	 - `AnchorLengthFrameDecoder` now validates the anchor byte and resyncs instead of
      	   misreading trailing padding as a bogus extra frame
    
      	 - `TagExtendedProtocolCO2Message` now accepts both the standard 26-byte payload
      	   and the 27-byte variant produced when a reading is relayed through a repeater,
      	   instead of throwing "Payload is not correct"
    
      	 - `MeshRSSIMessage.ReceptionLevel` property added: null when RSSI is 0xFF (no
      	   reading), otherwise the negated RSSI value
    
  • 4.0.2 - Extended Protocol Repeater message dispatch fix

      	 - `TagDataMessage.Parse` now dispatches `ExtendedProtocolMessageTypes.Repeater` to
      	   `TagExtendedProtocolRepeaterMessage` instead of falling through to the generic
      	   `TagExtendedProtocolMessage`, fixing repeater-relayed tag messages
    
  • 4.0.3 - Extended Protocol RSSI byte offset fix

      	 - `TagExtendedProtocolRepeaterMessage.TagMessage` was trimming one byte too many
      	   (the outer message's own trailing RSSI byte) when re-deriving the nested tag
      	   message, shifting every field after the trim point by one byte — confirmed on
      	   real data where a CO2 message's Humidity byte was being read back as its RSSI
    
      	 - C++ `TagMessage::getRSSI()` is now `virtual`, with `TagExtendedProtocolMessage`
      	   overriding it to read the last byte of the (variable-length) body instead of the
      	   fixed offset that's only valid for classic 13-byte tag messages; the C# side of
      	   this override was already correct
    
  • 4.0.5 - Extended Protocol Repeater message trim/RSSI fixes

      	 - The 4.0.3 trim-length fix was itself off by one byte: it widened the kept tail
      	   slice to avoid dropping the outer message's RSSI, but that byte was already kept
      	   by the pre-4.0.3 code, so the widening just pulled in an extra CRC byte instead —
      	   silently misaligning fields for single-hop relays and throwing "Payload is not
      	   correct" for double-hop-relayed CO2 readings. Reverted to trimming 3 trailing
      	   bytes (RSSI + 2-byte CRC), confirmed against existing byte-for-byte unit tests
    
  • 4.0.6 - RFMeshParser double bit-stuffing decode fix

      	 - `RFMeshParser.ParseFrame` (C#) was decoding frames a second time — they arrive
      	   already de-stuffed from `BitStuffingFrameDecoder`. Harmless unless the decoded
      	   payload itself contained a literal `0xAB`/`0xCD`/`0xEF` byte (e.g. RSSI -17 ==
      	   0xEF), in which case the redundant pass misread real data as bit-stuffing control
      	   bytes and corrupted the message. Removed the extra decode call to match the C++
      	   implementation, which never had this bug
    
      	 - `TagExtendedProtocolRepeaterMessage` now overrides `RSSI`/`ReceptionLevel`
      	   (C# and C++) instead of inheriting them: a Repeater message's body ends with
      	   `[RSSI, CRC byte 1, CRC byte 2]` rather than just `[RSSI]`, so the inherited
      	   "last byte of body" getter was reading the CRC as RSSI
    
      	 - `TagExtendedProtocolRepeaterMessage.Parse` now validates that the received frame
      	   length matches `Size + 4`, throwing a clear "Truncated Repeater message" error for
      	   an incomplete frame instead of letting it surface two calls later as a confusing,
      	   unrelated length mismatch from the nested message's own Parse
    
  • 4.0.7 - Repeater message truncation check and C++ CRC regression fixes

      	 - The 4.0.5 truncation check itself validated against the wrong invariant:
      	   `Size + 4` is the outer serial envelope's declared length (protocol byte + message
      	   counter + Star message + checksum), not the length of the Star message the class
      	   actually holds. Every real gateway frame satisfies `Size + 1`, same as every other
      	   `TagMessage` — confirmed byte-for-byte against live gateway captures. The old check
      	   rejected every genuine Repeater frame as "truncated" by exactly 3 bytes; fixed in
      	   both C# and C++ to check `Size + 1`
    
      	 - C++ `TagMessage::getBytes()` was appending a CRC16-XModem checksum copy-pasted from
      	   the unrelated `RFMMessage::getBytes()`, making it report 2 bytes more than the
      	   message actually contains. This has no C# equivalent and no place in the OldProtocol
      	   wire format (the only checksum is the outer envelope's 1-byte sum, validated
      	   separately in `ProtocolMessageParser::parseReceiverMessage`). Harmless while the
      	   4.0.5 bug above rejected real Repeater frames before `getBytes()` was ever called
      	   post-parse on real data; once that check was fixed, it surfaced as "expected N,
      	   got N+2" on every real Repeater frame. Removed
    
      	 - Added regression tests built from real gateway captures — both a direct parse of
      	   the Star message bytes and a full round trip through `MeshParser`/`MeshRSSIParser`
      	   with bit-stuffing and checksum validation — covering both fixes above
    
  • 4.0.8 - Repeater nested-message crash and C++ CO2 validation fixes

      	 - C++ `TagExtendedProtocolCO2Message::parse` was missing the 26/27-byte length check
      	   its C# counterpart has, so it silently parsed a wrong-length buffer at fixed field
      	   offsets and produced a fabricated, plausible-looking CO2 reading instead of
      	   failing. Added the same length check as C#
    
      	 - `TagExtendedProtocolRepeaterMessage.TagMessage` (C#) / `getTagMessage()` (C++)
      	   picks which nested message subtype to parse from a byte re-sliced from the
      	   repeater's payload — a heuristic, not a confirmed field of the relayed message's
      	   real layout. On three independent real gateway captures that byte was `8`, which
      	   collides with `ExtendedProtocolMessageTypes.CO2`; parsing the reconstructed
      	   (wrong-length) buffer as CO2 then threw "Payload is not correct" in C#, crashing
      	   every caller of this property for every real Repeater message sharing that byte
      	   value. Both ports now catch a failed subtype parse and fall back to the generic
      	   probe message (`Type`/`TagID` only) instead of propagating the exception. The
      	   correct field layout of the relayed message itself remains unconfirmed pending
      	   firmware reference — this only stops a bad guess from crashing the caller
    
      	 - Added `TestRepeaterTagMessageDoesNotThrowOnUnreliableTypeGuess`, built from a
      	   third real gateway capture, covering the crash above
    
  • 4.0.9 - Repeater relayed-message field layout, and two C++ builder bugs

      	 - `TagExtendedProtocolRepeaterMessage.TagMessage` (C#) / `getTagMessage()` /
      	   `setTagMessage()` (C++) now reconstruct the relayed message using the layout
      	   confirmed against embedded firmware source (`repeater.c`) and three independent
      	   real captures: the repeater's own header (Size/Type/TagID) and `msg_num` belong
      	   to the *original* relayed tag, reused unchanged; the relayed message itself
      	   carries no header, no `msg_num`, and no RSSI of its own — its RSSI is
      	   `FirstRSSI` (the tag→repeater hop). The previous code grafted a mangled copy of
      	   the *outer* header onto the relayed payload instead, so a wrapped
      	   `TagExtendedProtocolCO2Message` never resolved correctly. Verified with an
      	   exact-field builder round trip and against all three real captures, which now
      	   decode to physically plausible CO2 readings (~24°C, ~45-50% humidity,
      	   ~1008 hPa, ~3V) in both ports
    
      	 - C++ `TagMessage::setRSSI` is now `virtual` and overridden by
      	   `TagExtendedProtocolMessage` to write `body_.back()` (mirroring `getRSSI()`).
      	   Previously it always wrote the fixed offset `body_[6]`, an out-of-bounds write
      	   whenever an extended message's `body_` was still smaller than 7 bytes — e.g.
      	   calling `setReceptionLevel()` early in a builder sequence
    
      	 - C++ `TagExtendedProtocolMessage::setPayload` now keeps `Size` in sync (matching
      	   the C# `Payload` setter). `TagExtendedProtocolCO2Message`'s constructor never
      	   called `setPayload` at all, leaving `Size == 0` for any builder-constructed
      	   instance; `TagExtendedProtocolBinaryDataMessage` had the same gap via
      	   `setBinaryData`. Both are now fixed by this one shared change plus adding the
      	   missing constructor call
    
      	 - Added `TagExtendedProtocolRepeaterMessageUnitTest` covering the `TagMessage`
      	   getter and setter against the confirmed layout; replaced
      	   `TestRepeaterTagMessageDoesNotThrowOnUnreliableTypeGuess` (which asserted the
      	   previous, incorrect decode) with a defensive-fallback test for a too-short
      	   payload
    
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
.NET Framework net46 is compatible.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.9 104 8/25/2026
4.0.8 87 8/25/2026
4.0.7 98 8/25/2026
4.0.6 91 8/24/2026
4.0.5 92 8/24/2026
4.0.4 105 8/24/2026
4.0.3 106 8/24/2026
4.0.2 98 8/23/2026
4.0.1 111 8/23/2026
3.0.68 270 6/17/2026
3.0.67 170 5/19/2026
3.0.66 400 8/26/2025
3.0.65 429 8/25/2025
3.0.64 415 8/25/2025
3.0.63 358 3/30/2025
3.0.62 358 3/10/2025
3.0.61 310 2/3/2025
3.0.60 279 1/30/2025
3.0.58 280 1/22/2025
3.0.57 292 1/21/2025
Loading failed

v4.0.9: TagExtendedProtocolRepeaterMessage.TagMessage (C#) / getTagMessage()/setTagMessage() (C++) reconstructed the relayed message with the wrong field layout; fixed per embedded firmware source and confirmed against three real captures -- the outer header/msg_num belong to the original relayed tag reused unchanged, the relayed message carries no header/msg_num/RSSI of its own (its RSSI is FirstRSSI), and CO2-wrapped-in-Repeater now decodes to physically plausible values in both ports. C++ TagMessage.setRSSI was not overridden for extended messages the way getRSSI was, causing an out-of-bounds write to a fixed offset when body_ was still small; now virtual and overridden to write body_.back(). C++ TagExtendedProtocolMessage.setPayload did not keep Size in sync (unlike the C# Payload setter), leaving builder-constructed CO2Message/BinaryDataMessage instances with Size==0; fixed, plus CO2Message's constructor now calls setPayload. v4.0.8: C++ TagExtendedProtocolCO2Message.Parse was missing the 26/27-byte length check C# has, so it silently accepted a wrong-length buffer and fabricated a plausible-looking CO2 reading instead of failing. TagExtendedProtocolRepeaterMessage.TagMessage (C#) / getTagMessage() (C++) now catch a failed nested-subtype Parse and fall back to the generic probe message instead of crashing/propagating -- the type byte driving that dispatch is a heuristic re-slice of the repeater's payload, not a confirmed field layout, and a wrong guess (e.g. colliding with CO2's enum value) must not take down the whole accessor. v4.0.7: TagExtendedProtocolRepeaterMessage.Parse (C# and C++) validated the received frame length against Size+4 (the outer serial envelope's length, not this class's own Star message length) instead of Size+1, the invariant every real gateway frame satisfies and every other TagMessage relies on; confirmed against live gateway captures and fixed. C++ TagMessage.getBytes() was also appending a CRC16-XModem checksum copy-pasted from the unrelated RFMMessage.getBytes() -- OldProtocol TagMessages carry no such per-message CRC on the wire -- which the Size+4 bug above had been masking; removed. Replaced the synthetic Repeater test fixtures (tuned to the old incorrect check) with real gateway captures, including a full round trip through MeshRSSIParser. v4.0.6: RFMeshParser.ParseFrame was calling BitStuffDecode a second time on frames that BitStuffingFrameDecoder had already decoded. Harmless when the decoded payload had no literal 0xAB/0xCD/0xEF bytes, but whenever it did (e.g. an RSSI of -17 == 0xEF), the redundant pass misread that real data as bit-stuffing control bytes — merging a literal 0xEF with the following byte, or silently dropping a literal 0xCD — corrupting the message. Removed the redundant decode call; ParseFrame now passes the already-decoded frame straight to the handler chain, matching the C++ implementation. v4.0.5: The v4.0.3 trim-length fix was itself off by one byte, re-widening the kept slice of the nested tag message past the outer CRC (silently misaligned fields, or "Payload is not correct" for double-hop-relayed CO2 readings); reverted to trimming 3 trailing bytes (RSSI + 2-byte CRC). TagExtendedProtocolRepeaterMessage now overrides RSSI/ReceptionLevel instead of inheriting them, since its body ends with [RSSI, CRC byte 1, CRC byte 2] rather than just [RSSI]. TagExtendedProtocolRepeaterMessage.Parse now validates the received frame length against Size+4, throwing a clear "Truncated Repeater message" error instead of a confusing unrelated failure two calls later in the nested message's own Parse. v4.0.3: TagExtendedProtocolRepeaterMessage.TagMessage dropped one byte too many when re-deriving the nested tag message, shifting its trailing fields (e.g. voltage/humidity byte misread as RSSI) instead of dropping only the CRC. v4.0.2: TagDataMessage now dispatches ExtendedProtocolMessageTypes.Repeater to TagExtendedProtocolRepeaterMessage (was falling through to the generic TagExtendedProtocolMessage, so repeater-relayed tag messages failed to unwrap/display). v4.0.1: BitStuffingFrameDecoder now extracts every complete frame per call instead of dropping/misattributing extras; AnchorLengthFrameDecoder validates the anchor byte and resyncs past trailing padding; TagExtendedProtocolCO2Message accepts the 27-byte repeater-relayed payload variant; MeshRSSIMessage.ReceptionLevel property added.