RFM69 hat library Part12D

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 &gt; SyncValuesSizeMaximum))
		{
			throw new ArgumentException($"The syncValues array length must be between {SyncValuesSizeMinimum} and {SyncValuesSizeMaximum} bytes", "syncValues");
		}
		if (syncTolerance.HasValue)
		{
			if ((syncTolerance < SyncToleranceMinimum) || (syncTolerance &gt; 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.

RegPacketConfig1 address filtering options

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.

RFM69 hat library Part12C

Enums and Masks – Synchronisation

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 &gt; SyncValuesSizeMaximum))
		{
			throw new ArgumentException($"The syncValues array length must be between {SyncValuesSizeMinimum} and {SyncValuesSizeMaximum} bytes", "syncValues");
		}
		if (syncTolerance.HasValue)
		{
			if ((syncTolerance < SyncToleranceMinimum) || (syncTolerance &gt; 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 Arduino client code works though I need modify it so I can do more testing of the initialise method parameter options.