Enums and Masks – Packet lengths, addressing & CRCs
The RFM69CW/RFM69HCW module (based on the Semtech SX1231/SX1231H) has configurable (RegSyncConfig) synchronisation sequences (the length, tolerance for errors and the individual byte values).

By default synchronisation is enabled and a default sequence of bytes is used, in my library synchronisation is NOT enabled until a SyncValue is provided.
I added some additional constants and enumerations for the other settings configured in RegSyncConfig.
// RegSyncConfig // This is private because default ignored and flag set based on SyncValues parameter being specified rather than default private enum RegSyncConfigSyncOn { Off = 0b00000000, On = 0b10000000 } public enum RegSyncConfigFifoFileCondition { SyncAddressInterrupt = 0b00000000, FifoFillCondition = 0b01000000 } private const RegSyncConfigFifoFileCondition SyncFifoFileConditionDefault = RegSyncConfigFifoFileCondition.SyncAddressInterrupt; readonly byte[] SyncValuesDefault = {0x01, 0x01, 0x01, 0x01}; public const byte SyncValuesSizeDefault = 4; public const byte SyncValuesSizeMinimum = 1; public const byte SyncValuesSizeMaximum = 8; private const byte SyncToleranceDefault = 0; public const byte SyncToleranceMinimum = 0; public const byte SyncToleranceMaximum = 7;
I also added some guard conditions to the initialise method which validate the syncFifoFileCondition, syncTolerance and syncValues length.
public void Initialise(RegOpModeMode modeAfterInitialise, BitRate bitRate = BitRateDefault, ushort frequencyDeviation = frequencyDeviationDefault, double frequency = FrequencyDefault, ListenModeIdleResolution listenModeIdleResolution = ListenModeIdleResolutionDefault, ListenModeRXTime listenModeRXTime = ListenModeRXTimeDefault, ListenModeCrieria listenModeCrieria = ListenModeCrieriaDefault, ListenModeEnd listenModeEnd = ListenModeEndDefault, byte listenCoefficientIdle = ListenCoefficientIdleDefault, byte listenCoefficientReceive = ListenCoefficientReceiveDefault, bool pa0On = pa0OnDefault, bool pa1On = pa1OnDefaut, bool pa2On = pa2OnDefault, byte outputpower = OutputpowerDefault, PaRamp paRamp = PaRampDefault, bool ocpOn = OcpOnDefault, byte ocpTrim = OcpTrimDefault, LnaZin lnaZin = LnaZinDefault, LnaCurrentGain lnaCurrentGain = LnaCurrentGainDefault, LnaGainSelect lnaGainSelect = LnaGainSelectDefault, byte dccFrequency = DccFrequencyDefault, RxBwMant rxBwMant = RxBwMantDefault, byte RxBwExp = RxBwExpDefault, byte dccFreqAfc = DccFreqAfcDefault, byte rxBwMantAfc = RxBwMantAfcDefault, byte bxBwExpAfc = RxBwExpAfcDefault, ushort preambleSize = PreambleSizeDefault, RegSyncConfigFifoFileCondition? syncFifoFileCondition = null, byte? syncTolerance = null, byte[] syncValues = null, RegPacketConfig1PacketFormat packetFormat = RegPacketConfig1PacketFormat.FixedLength, RegPacketConfig1DcFree packetDcFree = RegPacketConfig1DcFreeDefault, bool packetCrc = PacketCrcOnDefault, bool packetCrcAutoClearOff = PacketCrcAutoClearOffDefault, RegPacketConfig1CrcAddressFiltering packetAddressFiltering = PacketAddressFilteringDefault, byte payloadLength = PayloadLengthDefault, byte addressNode = NodeAddressDefault, byte addressbroadcast = BroadcastAddressDefault, TxStartCondition txStartCondition = TxStartConditionDefault, byte fifoThreshold = FifoThresholdDefault, byte interPacketRxDelay = InterPacketRxDelayDefault, bool restartRx = RestartRxDefault, bool autoRestartRx = AutoRestartRxDefault, byte[] aesKey = null ) { RegOpModeModeCurrent = modeAfterInitialise; PacketFormat = packetFormat; #region RegSyncConfig + RegSyncValue1 to RegSyncValue8 guard conditions if (syncValues != null) { // If sync enabled (i.e. SyncValues array provided) check that SyncValues not to short/long and SyncTolerance not to small/big if ((syncValues.Length < SyncValuesSizeMinimum) || (syncValues.Length > SyncValuesSizeMaximum)) { throw new ArgumentException($"The syncValues array length must be between {SyncValuesSizeMinimum} and {SyncValuesSizeMaximum} bytes", "syncValues"); } if (syncTolerance.HasValue) { if ((syncTolerance < SyncToleranceMinimum) || (syncTolerance > SyncToleranceMaximum)) { throw new ArgumentException($"The syncTolerance size must be between {SyncToleranceMinimum} and {SyncToleranceMaximum}", "syncTolerance"); } } } else { // If sync not enabled (i.e. SyncValues array null) check that no syncFifoFileCondition or syncTolerance configuration specified if (syncFifoFileCondition.HasValue) { throw new ArgumentException($"If Sync not enabled syncFifoFileCondition is not supported", "syncFifoFileCondition"); } if (syncTolerance.HasValue) { throw new ArgumentException($"If Sync not enabled SyncTolerance is not supported", "syncTolerance"); } } #endregion
I also ensure that the syncFifoFileCondition and syncTolerance are not specified if synchronisation is not enabled.
The library also supports the built in RFRM69 node and broadcast addressing which is enabled when the AddressNode and/or AddressBroadcast parameters of the Initialise method are set.

My first attempt at getting encryption and addressing working together failed badly, the Windows 10 IoT Core device didn’t receive any addressed messages when encryption was enabled. So, I went back and re-read the datasheet again and noticed
“If the address filtering is expected then AddressFiltering must be enabled on the transmitter side as well to prevent address byte to be encrypted”(Sic).
The Arduino client code had to be modified so I could set the node + broadcast address registers and AddressFiltering bit flag in RegPacketConfig1
My RMRFM69.h modifications
enum moduleType {RFM65, RFM65C, RFM69, RFM69C, RFM69H, RFM69HC}; #define ADDRESS_NODE_DEFAULT 0x0 #define ADDRESS_BROADCAST_DEFAULT 0x0 #define ADDRESSING_ENABLED_NODE 0x2 #define ADDRESSING_ENABLED_NODE_AND_BROADCAST 0x4 class RMRFM69 { public: RMRFM69(SPIClass &spiPort, byte csPin, byte dio0Pin, byte rstPin); modulationType Modulation; //OOK/FSK/GFSK moduleType COB; //Chip on board uint32_t Frequency; //unit: KHz uint32_t SymbolTime; //unit: ns uint32_t Devation; //unit: KHz word BandWidth; //unit: KHz byte OutputPower; //unit: dBm range: 0-31 [-18dBm~+13dBm] for RFM69/RFM69C // range: 0-31 [-11dBm~+20dBm] for RFM69H/RFM69HC word PreambleLength; //unit: byte bool CrcDisable; //fasle: CRC enable�� & use CCITT 16bit //true : CRC disable bool CrcMode; //false: CCITT bool FixedPktLength; //false: for contain packet length in Tx message, the same mean with variable lenth //true : for doesn't include packet length in Tx message, the same mean with fixed length bool AesOn; //false: //true: bool AfcOn; //false: //true: byte SyncLength; //unit: none, range: 1-8[Byte], value '0' is not allowed! byte SyncWord[8]; byte PayloadLength; //PayloadLength is need to be set a value, when FixedPktLength is true. byte AesKey[16]; //AES Key block, note [0]->[15] == MSB->LSB byte AddressNode = ADDRESS_NODE_DEFAULT; byte AddressBroadcast = ADDRESS_BROADCAST_DEFAULT; void vInitialize(void); void vConfig(void); void vGoRx(void); void vGoStandby(void); void vGoSleep(void); bool bSendMessage(byte msg[], byte length); bool bSendMessage(byte Address, byte msg[], byte length); byte bGetMessage(byte msg[]); void vRF69SetAesKey(void); void vTrigAfc(void); void vDirectRx(void); //go continuous rx mode, with init. inside void vChangeFreq(uint32_t freq); //change frequency byte bReadRssi(void); //read rssi value void dumpRegisters(Stream& out);
My RMRFM69.cpp modifications in vConfig
if(!CrcDisable) { i += CrcOn; if(CrcMode) i += CrcCalc_IBM; else i += CrcCalc_CCITT; } if((AddressNode!=ADDRESS_NODE_DEFAULT) || (AddressBroadcast==ADDRESS_BROADCAST_DEFAULT)) { i += ADDRESSING_ENABLED_NODE; } if((AddressNode!=ADDRESS_NODE_DEFAULT) || (AddressBroadcast!=ADDRESS_BROADCAST_DEFAULT)) { i += ADDRESSING_ENABLED_NODE_AND_BROADCAST; } vSpiWrite(((word)RegPacketConfig1<<8)+i);
I also validate the lengths of the messages to be sent taking into account whether encryption is enabled\disabled.