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.