Jan 2021

Feather RV Monitor


This project uses a motion sensor to trigger a WAV file player that plays the sound of a angry dog growling and barking.   It is intended to be a theft deterrent.   I utilized one Arduino Uno with Adafruit WaveShield, and two Adafruit M0 Feathers with LoRa radios.   A PIR sensor is connected to the one Adafruit M0 Feather (Tx unit).  

Functional Specification

  • Motion sensor at main door wirelessly triggers dog barking sound.
  • USB powered dog barking sound player audio output to 30W portable speaker.
  • LoRa communications between Tx and Rx units is encrypted.
  • Tx unit is powered by RV 12V battery.
  • Rx unit is powered by USB.

Feather M0 LoRa (Tx)

Feather M0 LoRa (Rx) + Arduino Wave Shield

PIR Motion Sensor

The PIR motion sensor from Adafruit has a range of about 20 feet (120 ° cone), an adjustable delay of 2 to 4 seconds, and adjustable sensitivity.  

 

Transmitter


// RV_PIR_Tx.ino
// Sends an encrypted message to the receiver consisting of an integer indicating 
// if the PIR sensor has been triggered, or if has not been. 

// This is a derivative of 'AF_Feather_M0_Basic_LoRa900MHz_ReliableDatagram_encrypted_sendr.ini'

// Reliable Datagram is reliable in the sense that messages are acknowledged by the 
// recipient, and unacknowledged messages are retransmitted until acknowledged or the
// retries are exhausted.

// The message to be sent is encrypted with AES 256 bit encryption using
// Spaniakos - AES Encryption Library.

// The built in M0 red LED will blink S-O-S upon startup if a hardware issue
// prevents initialization of the LoRa radio (typically wrong jumper wire
// or corresponding software settings). 

// The built in M0 red LED will turn on briefly when a message is sent, and
// then it will go out when receipt confirmation (from receiver) is received.
// The M0 red LED will stay on if the receiver is not responding.  But it will
// recover and begin sending again once the receiver is found. 

// Resources:
//  Pins 13, A7/9, 6, 10, 11, 5, A5/19

// M0  (Feather M0)
const byte pin_LED = 13;
const byte pin_BATT = A7;

//////////////////////////////////////////////////////////////////////////////
// 10000 ms = 10 sec = 0.1 Hz 
// 1000 ms = 1 sec = 1 Hz
// 100 ms = 0.1 sec = 10 Hz
// 10 ms = 0.01 sec = 100 Hz
unsigned long timerInterval = random(500,5000);  
unsigned long timerLast = 0;  // timer
//////////////////////////////////////////////////////////////////////////////

// RHReliableDatagram is reliable in the sense that messages are acknowledged by the 
// recipient, and unacknowledged messages are retransmitted until acknowledged or the
// retries are exhausted.

//////////////////////////////////////////////////////////////////////////////
//  LoRa 900 MHz Radio
//  RadioHead library for LoRa Radio
//  http://www.airspayce.com/mikem/arduino/RadioHead/index.html
#include <RHReliableDatagram.h>
#include <RH_RF95.h>
#include <SPI.h>

#define SENDER_ADDRESS 0x1    // This LoRa device
#define RECEIVER_ADDRESS 0x2  // The LoRa device that will receive messages from this device

// Feather M0 LoRa 900 MHz (AF product #3178)
//#define RFM95_INT 3
//#define RFM95_CS 8
//#define RFM95_RST 4
// Feather M0 (AF #2772) with the 900 MHz LoRa FeatherWing (AF #3231) stacked onto it. 
#define RFM95_INT  6   // "D"   alternative is 3
#define RFM95_CS  10   // "B"   alternative is 8
#define RFM95_RST 11   // "A"   alternative is 4
// Define frequency (set later)
#define RF95_FREQ 915.0
// RH_RF95 (uint8_t slaveSelectPin=SS, uint8_t interruptPin=2, RHGenericSPI &spi=hardware_spi)
RH_RF95 rf95(RFM95_CS, RFM95_INT);
// Class to manage message delivery and receipt, using the rf95 declared above
RHReliableDatagram manager(rf95, SENDER_ADDRESS);
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; // holds reply from receiver

//////////////////////////////////////////////////////////////////////////////
// Show serial messages when DEBUG = true, otherwise minimize them.
// WARNING:   I experienced the Feather M0 waiting for the serial monitor to be
//            loaded from the IDE before the sketch would continue to run.  
//            For this reason, I am wrapping serial output around a DEBUG check.
#define DEBUG false
//////////////////////////////////////////////////////////////////////////////
//  Encryption using Spaniakos - AES Encryption Library for Arduino and Raspberry Pi
//  Download library from: https://github.com/spaniakos/AES/archive/master.zip
//  https://spaniakos.github.io/AES/index.html
//  https://www.arduinolab.net/aes-encryptiondecryption-using-arduino-uno/
#include <AES.h>
AES aes;
byte *key = (unsigned char*)"29304320399850709430905983949092"; // encryption key
unsigned long long int myIv = 36753562; // CBC initialization vector; real iv = iv x2 ex: 01234567 = 0123456701234567
byte iv [N_BLOCK] ;
boolean bVerbose = false;
// You must define arrays for encryption / decryption here globally 
// if you intend to populate the contents of strToEncrypt in a loop 
// where the contents change (such as sensor data).
// Define arrays for encryption.  
byte iSizeUnpadded = 31;
byte iSizePadded = 33;  // +17 works for any size. See setup() for calculation of exact padding. 
byte arrToEncrypt[31]; // Array with data to be encrypted. arrToEncrypt[iSizePadded]
byte cipher[33]; // Encrypted arrToEncrypt.  cipher[iSizePadded]
//////////////////////////////////////////////////////////////////////////////
unsigned long successCount = 0;
boolean bStopOnError = false;
//////////////////////////////////////////////////////////////////////////////
int iPIR = 0;
byte pinPIR = 5;
byte pirState = LOW;
byte pinMotionLED = A5; //19

void setup() {
  pinMode(pin_LED, OUTPUT);

  #if DEBUG
  Serial.begin(9600);
  while (!Serial) {
    delay(1);
  }
  Serial.println("Serial ready");
  #endif
  
  // declare and initialize the variables for encryption / decryption
  aes.iv_inc();
  // Use the statement below to calculate the exact size for iSizePadded
  //Serial.print("iSizePadded = "); Serial.println(sizeof(arrToEncrypt) + (N_BLOCK - ((sizeof(arrToEncrypt)-1) % 16)));

  pinMode(pinPIR, INPUT);
  delay(1);
  pinMode(pinMotionLED, OUTPUT);
  delay(1);
  
  //////////////////////////////////////////////////////////////////////////////
  //  LoRa 900 MHz Radio
  pinMode(RFM95_RST, OUTPUT);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  if (!manager.init()) {
    #if DEBUG
    Serial.println("init failed");
    #endif
    while (1) blinkERR(pin_LED);
  }
  #if DEBUG
  Serial.println("LoRa radio init OK!");  
  #endif
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    #if DEBUG
    Serial.println("setFrequency failed");
    #endif
    while (1) blinkERR(pin_LED);
  }
  #if DEBUG
  Serial.print("LoRa to: "); Serial.print(RF95_FREQ); Serial.println(" Hz");
  #endif
  
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
  // If you are using Modtronix inAir4 or inAir9,or any other module which uses the
  // You can optionally require this module to wait until Channel Activity
  // Detection shows no activity on the channel before transmitting by setting
  // the CAD timeout to non-zero:
  //  rf95.setCADTimeout(10000);

  randomSeed(micros());

  blinkLED(pinMotionLED);
  blinkLED(pin_LED);
} // setup();


void loop() {

  // Read the PIR sensor
  if (digitalRead(pinPIR) == HIGH) {
    if (pirState == LOW) {
      // motion detected
      pirState = HIGH;
      digitalWrite(pinMotionLED, HIGH);
      iPIR = 1;
    }
  } else {
    if (pirState == HIGH) {
      // motion ended
      pirState = LOW;
      digitalWrite(pinMotionLED, LOW);
      iPIR = 0;
    }
  }

  if (timerLast > millis())  timerLast = millis();
  if ((millis() - timerLast) > timerInterval) {
    // Send a message to manager_server
    //blinkLED(pin_LED);  // pretty, but consumes time
    #if DEBUG
    Serial.println("Sending encrypted data via RadioHead Reliable Datagram");    
    #endif
    digitalWrite(pin_LED, HIGH);

    // Send a 5 character unsigned integer (0 to 32767) + null char
    int iTmp = iPIR;
    WriteIntToByteArr(arrToEncrypt, sizeof(arrToEncrypt), iPIR);
    iPIR = iTmp;  // restore the value if iPIR because for some reason it is changed.
    
    #if DEBUG
    Serial.print("'");
    for (int i=0; i < sizeof(arrToEncrypt); i++) {
      Serial.print(char(arrToEncrypt[i]));
    }
    Serial.println("'");  
    #endif
    
    int iSizePadded = sizeof(arrToEncrypt) + (N_BLOCK - ((sizeof(arrToEncrypt)-1) % 16)); // length of padded string
    if (iSizePadded > sizeof(cipher)) {
      #if DEBUG
      Serial.print("ERROR - array size of cipher or arrDecryptedPadded is too small!");
      #endif
      while (1) blinkERR(pin_LED);
    }
    // Encrypt arrToEncrypt and update cipher with the result
    aesEncrypt(256, bVerbose);   
    
    if (manager.sendtoWait(cipher, sizeof(cipher), RECEIVER_ADDRESS))   {
      // Now wait for a reply from the server
      uint8_t len = sizeof(buf);
      uint8_t from;   
      if (manager.recvfromAckTimeout(buf, &len, 2000, &from)) {
        #if DEBUG
        Serial.print("Reply from : 0x");Serial.print(from, HEX);
        Serial.print(": '"); Serial.print((char*)buf); Serial.println("'");
        #endif
        // Compare the received data buff to the data sent arrToEncrypt
        int matches = 0;
        for(int i=0; i < sizeof(arrToEncrypt); i++){
          if(buf[i]==arrToEncrypt[i]){     
            matches++;  
          } 
        }
        if (matches == sizeof(arrToEncrypt)) {
          successCount++;
          digitalWrite(pin_LED, LOW); 
          //iPIR = 0;
          iPIR = iTmp;
        }
        #if DEBUG
        Serial.print(matches/sizeof(arrToEncrypt)*100);
        Serial.print("% match between arrToEncrypt and buff for size = ");
        Serial.print(sizeof(arrToEncrypt)); Serial.print(" bytes  ( encrypt/decrypt count = ");
        Serial.print(successCount); Serial.println(")  ");
        if (matches != sizeof(arrToEncrypt)) {
          Serial.print("ERROR after "); Serial.print(successCount); Serial.println(" encrypt/decrypt cycles");
          Serial.print("sizeof(arrToEncrypt) = "); Serial.println(sizeof(arrToEncrypt));
          Serial.print("matches = "); Serial.println(matches);
          for(int i=0; i < sizeof(arrToEncrypt); i++){
            Serial.print(i); Serial.print(",0x"); Serial.print(arrToEncrypt[i],HEX);
            Serial.print(",0x"); Serial.println(buf[i],HEX);
          }
          if (bStopOnError == true)
            while (1);
        }
        Serial.println();
        #endif
      } else {
        #if DEBUG
        Serial.println("No reply, is receiver running?\n");
        #endif
      }
    } else {
      #if DEBUG
      Serial.println("sendtoWait failed\n");
      #endif
    }
    timerInterval = 100;
    //timerInterval = random(5,500);  
    timerLast = millis();
  } // timer

} // loop()


////////////////////////////////////////////////////////////////


void blinkLED(byte ledPIN){
  //  consumes 300 ms.
  for(int i = 5; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(30);
    digitalWrite(ledPIN, LOW);
    delay(30);
  }    
} // blinkLED()


void blinkERR(byte ledPIN){
  // S-O-S
  const int S = 150, O = 300;
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(O);
    digitalWrite(ledPIN, LOW);
    delay(O);
  }    
  delay(200);
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
} // blinkERR()

//////////////////////////////////////////////////////////////////////////////
//  Encryption using Spaniakos - AES Encryption Library for Arduino and Raspberry Pi

void aesEncrypt(int bits, boolean bVerbose) {
  //  Encrypts arrToEncrypt based on bits (256) bit encryption and updates
  //  cipher with the encrypted result.   
  aes.set_IV(myIv);
  aes.get_IV(iv);
  unsigned long us = micros ();
  //Serial.print("aesEncrypt aes.get_size() = "); Serial.println(aes.get_size());
  aes.do_aes_encrypt(arrToEncrypt,iSizeUnpadded+1,cipher,key,bits,iv);
  if (bVerbose == true) {
    Serial.print("Encryption took "); Serial.print(micros() - us); Serial.println(" us");
  }
} // aesEncrypt()

//////////////////////////////////////////////////////////////////////////////
// Feather M0 specific functions

/*
  dtostrf - Emulation for dtostrf function from avr-libc
  Copyright (c) 2015 Arduino LLC.  All rights reserved.
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
// https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/avr/dtostrf.c

/*
char buff[14];
float f = -3.1415926;
Serial.print("f = ");Serial.println(f, 6);
sprintf(buff, "%E", f);
Serial.print("buff = '"); Serial.print(buff); Serial.println("'");
*/

char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
  asm(".global _printf_float");
  char fmt[20];
  sprintf(fmt, "%%%d.%df", width, prec);
  sprintf(sout, fmt, val);
  return sout;
} // dtostrf()

//////////////////////////////////////////////////////////////////////////////


void WriteIntToByteArr(byte *arr, int len, int &iVal) {
  // Works on Feather M0 (ATSAMD21 Cortex M0)
  // WARNING: Value of iVal may change due to sprintf()
  
  for (int i=0; i<len; i++) {
    arr[i] = 0x20;  // space character
  }
  
  // ITOA() converts int to string
  //itoa(iVal, cInt, 10);

  char cInt[len-1];
  sprintf(cInt, "%1u", iVal);
  
  for (int i=0; i<strlen(cInt); i++) {
    arr[i] = cInt[i];
  } 
  arr[len] = 0x00; // null character
} // WriteIntToByteArr()


//////////////////////////////////////////////////////////////////////////////

 

Receiver


// RV_PIR_Rx.ino
// Receives an encrypted message consisting of an integer that indicates
// if the PIR sensor at the sender has been triggered (0 = false, 1 = true).
// The digital output on pinPIR will change corresponding to the received
// PIR state (for the sender with the PIR sensor). 

// This is a derivative of 'AF_Feather_M0_Basic_LoRa900MHz_ReliableDatagram_encrypted_recvr.ini'

// Reliable Datagram is reliable in the sense that messages are acknowledged by the 
// recipient, and unacknowledged messages are retransmitted until acknowledged or the
// retries are exhausted.

// The message to be sent is encrypted with AES 256 bit encryption using
// Spaniakos - AES Encryption Library.

// The built in M0 red LED will blink S-O-S upon startup if a hardware issue
// prevents initialization of the LoRa radio (typically wrong jumper wire
// or corresponding software settings). 

// The built in M0 red LED will turn on briefly when a message is received, and
// then it will go out when receipt confirmation is sent and received (it sends
// the message back to the sender unencrypted, and then the sender confirms 
// receipt).  Not production intent.

// Resources:
//  Pins 13, A7/9, 6, 10, 11, 5

// M0  (Feather M0)
const byte pin_LED = 13;
const byte pin_BATT = A7;

//////////////////////////////////////////////////////////////////////////////
//  LoRa 900 MHz Radio
//  RadioHead library for LoRa Radio
//  http://www.airspayce.com/mikem/arduino/RadioHead/index.html
#include <RHReliableDatagram.h>
#include <RH_RF95.h>
#include <SPI.h>
#define SENDER_ADDRESS 0x1    // The LoRa device that sends messages to this device
#define RECEIVER_ADDRESS 0x2  // This LoRa device
// Feather M0 (AF #2772) with the 900 MHz LoRa FeatherWing (AF #3231) stacked onto it. 
#define RFM95_INT  6   // "D"   alternative is 3
#define RFM95_CS  10   // "B"   alternative is 8
#define RFM95_RST 11   // "A"   alternative is 4
// Define the frequency
#define RF95_FREQ 915.0
// Singleton instance of the radio rf95
RH_RF95 rf95(RFM95_CS, RFM95_INT);
// Class to manage message delivery and receipt, using the rf95 declared above
RHReliableDatagram manager(rf95, RECEIVER_ADDRESS);
byte buf[RH_RF95_MAX_MESSAGE_LEN];

/////////////////////////////////////////////////////////////////////////////\/
// Show serial messages when DEBUG = true, otherwise minimize them.
// WARNING:   I experienced the Feather M0 waiting for the serial monitor to be
//            loaded from the IDE before the sketch would continue to run.  
//            For this reason, I am wrapping serial output around a DEBUG check.
#define DEBUG false
//////////////////////////////////////////////////////////////////////////////
//  Encryption using Spaniakos - AES Encryption Library for Arduino and Raspberry Pi
//  Download library from: https://github.com/spaniakos/AES/archive/master.zip
//  https://spaniakos.github.io/AES/index.html
//  https://www.arduinolab.net/aes-encryptiondecryption-using-arduino-uno/
#include <AES.h>
AES aes;
byte *key = (unsigned char*)"29304320399850709430905983949092"; // encryption key
unsigned long long int myIv = 36753562; // CBC initialization vector; real iv = iv x2 ex: 01234567 = 0123456701234567
byte iv [N_BLOCK] ;
boolean bVerbose = false;
// You must define arrays for encryption / decryption here globally 
// if you intend to populate the contents of strToEncrypt in a loop 
// where the contents change (such as sensor data).
// Define arrays for encryption
byte iSizeUnpadded = 31;
byte iSizePadded = 33;  // =iSizeUnpadded+17 works for any size. See setup() for calculation of exact padding. 
byte cipher[33]; // Encrypted arrToEncrypt.  cipher[iSizePadded]
byte arrDecryptedPadded[33]; // decrypted cipher with padding.  arrDecryptedPadded[iSizePadded]
byte decrypted[31]; // decrypted string without padding.  decrypted[iSizeUnpadded]
//////////////////////////////////////////////////////////////////////////////
byte pinPIR = A4; // #18

void setup() {

  pinMode(pin_LED, OUTPUT);

  #if DEBUG
    Serial.begin(9600);
    while (!Serial) {
      delay(1);
    }
    Serial.println("Serial ready");
  #endif

  // declare and initialize the variables for encryption / decryption
  aes.iv_inc();
  // Use the statement below to calculate the exact size for iSizePadded
  //Serial.print("iSizePadded = "); Serial.println(sizeof(arrToEncrypt) + (N_BLOCK - ((sizeof(arrToEncrypt)-1) % 16)));
  
  //////////////////////////////////////////////////////////////////////////////
  //  LoRa 900 MHz Radio
  pinMode(RFM95_RST, OUTPUT);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);
  while (!manager.init()) {
    #if DEBUG
    Serial.println("LoRa radio init failed");
    #endif
    while (1) blinkERR(pin_LED);
  }
  #if DEBUG
  Serial.println("LoRa radio mgr init OK!");
  #endif
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    #if DEBUG
    Serial.println("setFrequency failed");
    #endif
    while (1) blinkERR(pin_LED);
  }
  #if DEBUG
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
  #endif
  
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
  // You can optionally require this module to wait until Channel Activity
  // Detection shows no activity on the channel before transmitting by setting
  // the CAD timeout to non-zero:
  //rf95.setCADTimeout(10000);

  pinMode(pinPIR, OUTPUT);
  delay(1);
  digitalWrite(pinPIR, LOW);
  delay(1);

  #if DEBUG
  Serial.println("Setup complete\n");
  #endif
  blinkLED(pin_LED);
} // setup()


void loop() {
  if (manager.available())   {
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (manager.recvfromAck(buf, &len, &from))  {
      //blinkLED(pin_LED);  pretty; but consumes time
      digitalWrite(pin_LED, HIGH);
     
      // Decrypt cipher, and update decrypted with the result
      // clear cipher, arrDecryptedPadded, decrypted
      for (int i=0; i < sizeof(cipher); i++) {
        cipher[i] = 0x00;
      }
      for (int i=0; i < sizeof(arrDecryptedPadded); i++) {
        arrDecryptedPadded[i] = 0x00;
      }
      for (int i=0; i < sizeof(decrypted); i++) {
        decrypted[i] = 0x00;
      }      
      // Assign the contents of buf to cipher
      for (int i=0; i < sizeof(cipher); i++) {
        cipher[i] = buf[i];
      }
      // Decrypt cipher, and update decrypted with the result
      aesDecrypt(256, bVerbose);
      #if DEBUG
      Serial.print("From : 0x"); Serial.print(from, HEX); Serial.print(": '");
      for (int i=0; i < sizeof(decrypted); i++) {
        Serial.print(char(decrypted[i]));
      }
      Serial.print("'  RSSI:");
      Serial.println(rf95.lastRssi(),DEC);
      #endif

      // Send the decrypted message back to the originator client (sender).
      // (In production you wouldn't send back the decrypted message)
      if (!manager.sendtoWait(decrypted, sizeof(decrypted), from)) {
        #if DEBUG
        Serial.println("sendtoWait (reply) failed");
        #endif
      } else {
        digitalWrite(pin_LED, LOW);
        if (decrypted[0] == '1' && decrypted[1] == 0x20)
          digitalWrite(pinPIR, HIGH);
        else
          digitalWrite(pinPIR, LOW);    
      }

      #if DEBUG
      Serial.print("decrypted[1]: "); Serial.println(char(decrypted[1]));
      #endif
       
    }
  }
} // loop()

//////////////////////////////////////////////////////////////////////////////

void blinkLED(byte ledPIN){
  //  consumes 300 ms.
  for(int i = 5; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(30);
    digitalWrite(ledPIN, LOW);
    delay(30);
  }    
} //blinkLED()


void blinkERR(byte ledPIN){
  // S-O-S
  const int S = 150, O = 300;
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(O);
    digitalWrite(ledPIN, LOW);
    delay(O);
  }    
  delay(200);
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
} // blinkERR()

//////////////////////////////////////////////////////////////////////////////
//  Encryption using Spaniakos - AES Encryption Library for Arduino and Raspberry Pi

void aesDecrypt(int bits, boolean bVerbose) {
  // Decrypt cipher and write to arrDecryptedPadded
  aes.set_IV(myIv);
  aes.get_IV(iv);
  unsigned long us = micros();
  aes.do_aes_decrypt(cipher,iSizeUnpadded+1,arrDecryptedPadded,key,bits,iv); 
  if (bVerbose == true) {
    Serial.print("Decryption took "); Serial.print(micros() - us); Serial.println(" us");  
  }
  // Create new array decrypted with the unencrypted content  
  // from arrDecryptedPadded excluding the padding. 
  for (int i=0; i < iSizeUnpadded; i++) {
    decrypted[i] = arrDecryptedPadded[i];
  } 
} // aesDecrypt()

//////////////////////////////////////////////////////////////////////////////

 

 


Do you need help developing or customizing a IoT product for your needs?   Send me an email requesting a free one hour phone / web share consultation.  

 

The information presented on this website is for the author's use only.   Use of this information by anyone other than the author is offered as guidelines and non-professional advice only.   No liability is assumed by the author or this web site.