Enums and Masks – Encryption
The RFM69CW/RFM69HCW module (based on the Semtech SX1231/SX1231H) has built in support for 128bit Advanced Encryption Standard(AES) encoding of message payloads. To make encryption easy to configure I added some additional constants and enumerations for the other settings configured in RegPacketConfig2.
// RegPacketConfig2
private const byte InterPacketRxDelayDefault = 0;
public const byte InterPacketRxDelayMinimum = 0x0;
public const byte InterPacketRxDelayMaximum = 0xF;
private const bool RestartRxDefault = false;
[Flags]
private enum RegPacketConfig2RestartRxDefault : byte
{
Off = 0b00000000,
On = 0b00000100,
}
private const bool AutoRestartRxDefault = true;
[Flags]
private enum RegPacketConfig2AutoRestartRxDefault : byte
{
Off = 0b00000000,
On = 0b00000010,
}
[Flags]
private enum RegPacketConfig2Aes : byte
{
Off = 0b00000000,
On = 0b00000001,
}
public const byte AesKeyLength = 16;
I then added some guard conditions to the initialise method to validate the InterPacketRxDelay and the encryption key 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,
bool syncOn = SyncOnDefault, SyncFifoFileCondition syncFifoFileCondition = SyncFifoFileConditionDefault, byte syncSize = SyncSizeDefault, byte syncTolerance = SyncToleranceDefault, 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 Guard Conditions
if ((interPacketRxDelay < InterPacketRxDelayMinimum ) || (interPacketRxDelay > InterPacketRxDelayMaximum))
{
throw new ArgumentException($"The interPacketRxDelay must be between {InterPacketRxDelayMinimum} and {InterPacketRxDelayMaximum}", "interPacketRxDelay");
}
if ((aesKey != null) && (aesKey.Length != AesKeyLength))
{
throw new ArgumentException($"The AES key must be {AesKeyLength} bytes", "aesKey");
}
#endregion
This required some modifications to the run method to catch the new exceptions gracefully.
public void Run(IBackgroundTaskInstance taskInstance)
{
byte[] syncValues ={0xAA, 0x2D, 0xD4};
byte[] aesKeyValues = {0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0X0E, 0X0F };
rfm69Device.RegisterDump();
try
{
rfm69Device.Initialise(Rfm69HcwDevice.RegOpModeMode.StandBy,
bitRate: Rfm69HcwDevice.BitRate.bps4K8,
frequency: 915000000.0, frequencyDeviation: 0X023d,
dccFrequency: 0x1,rxBwMant: Rfm69HcwDevice.RxBwMant.RxBwMant20, RxBwExp:0x2,
preambleSize: 16,
syncSize: 3,
syncValues: syncValues,
packetFormat: Rfm69HcwDevice.RegPacketConfig1PacketFormat.VariableLength,
packetCrc:true,
aesKey: aesKeyValues
);
rfm69Device.RegisterDump();
// RegDioMapping1
rfm69Device.RegisterManager.WriteByte(0x26, 0x01);
rfm69Device.RegisterDump();
while (true)
{
string message = "hello world " + DateTime.Now.ToLongTimeString();
byte[] messageBuffer = UTF8Encoding.UTF8.GetBytes(message);
Debug.WriteLine("{0:HH:mm:ss.fff} Send-{1}", DateTime.Now, message);
rfm69Device.SendMessage(messageBuffer);
Debug.WriteLine("{0:HH:mm:ss.fff} Send-Done", DateTime.Now);
Task.Delay(5000).Wait();
}
}
catch( Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
The Arduino client code works though I need modify it so I can do more testing of the initialise method parameter options.