Advertisement
Caverntwo

Door Lock Logic Code V0.1

Jun 28th, 2018
509
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.45 KB | None | 0 0
  1. /*
  2.  * Door Lock logic v0.1 by @Caverntwo
  3.  *
  4.  * This code is published to accompany my video about my new door lock. It is published under the MIT License (see below).
  5.  *
  6.  * You need to have the LiquidCrystal_I2C Library by marcoschwartz installed for it to correctly compile with the latest Arduino IDE
  7.  * (https://github.com/marcoschwartz/LiquidCrystal_I2C).
  8.  *
  9.  * I'M NOT A C/C++ PROGRAMMER AND DON'T KNOW A LOT ABOUT THE LANGUAGE!!!
  10.  * This code is probably the worst you've seen so far! I'm not proud of it, but I don't know any better.
  11.  * I'm going to improve, but this takes some time!
  12.  *
  13.  *
  14.  * The MIT License
  15.  *
  16.  * Copyright 2018 Caverntwo
  17.  *
  18.  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  19.  * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
  20.  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
  21.  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  22.  *
  23.  * The above copyright notice and this permission notice shall be included in all copies or substantial portions
  24.  * of the Software.
  25.  *
  26.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  27.  * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  28.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  29.  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  30.  * DEALINGS IN THE SOFTWARE.
  31. */
  32.  
  33.  
  34. #include <LiquidCrystal_I2C.h>
  35. #include <Wire.h>
  36.  
  37. class InputHandler
  38. {
  39.   private:
  40.     int *keys;
  41.     int *rowPins;
  42.     int *colPins;
  43.     unsigned int keysLength;
  44.     unsigned int rows;
  45.     unsigned int cols;
  46.  
  47.     unsigned int subDelay;
  48.     char entered;
  49.     char invalid;
  50.  
  51.     unsigned long unblockMillis;
  52.  
  53.   public:
  54.     InputHandler(unsigned int _subDelay, char _invalid, int *_keys, unsigned int _keysLength, int *_rowPins, unsigned int _rows, int *_colPins, unsigned int _cols)
  55.     {
  56.       keys = _keys;
  57.       rowPins = _rowPins;
  58.       colPins = _colPins;
  59.       keysLength = _keysLength;
  60.       rows = _rows;
  61.       cols = _cols;
  62.    
  63.       subDelay = _subDelay;
  64.       invalid = _invalid;
  65.       entered = invalid;
  66.     }
  67.  
  68.     void Setup()
  69.     {
  70.       for (unsigned int row = 0; row < rows; row++)
  71.       {
  72.         pinMode(rowPins[row], INPUT_PULLUP);
  73.  
  74.       }
  75.       for (unsigned int col = 0; col < cols; col++)
  76.       {
  77.         pinMode(colPins[col], OUTPUT);
  78.       }
  79.     }
  80.  
  81.     void Update()
  82.     {
  83.       if (millis() > unblockMillis)
  84.       {      
  85.         entered = invalid;
  86.        
  87.         //write columns and read rows
  88.         int activeCol = -1;
  89.         int activeRow = -1;
  90.         for (unsigned int col = 0; col < cols; col++)
  91.         {
  92.           for (unsigned int scol = 0; scol < cols; scol++)
  93.           {
  94.             if (scol != col)
  95.             {
  96.                digitalWrite(colPins[scol], HIGH);
  97.             }
  98.           }
  99.           digitalWrite(colPins[col], LOW);
  100.           delay(subDelay);
  101.  
  102.           for (unsigned int row = 0; row < rows; row++)
  103.           {
  104.             if (digitalRead(rowPins[row]) == LOW)
  105.             {
  106.               activeCol = col;
  107.               activeRow = row;
  108.             }
  109.           }
  110.         }
  111.         //decode result
  112.         if (activeCol >= 0 && activeRow >= 0)
  113.         {
  114.           entered = keys[activeRow * cols + activeCol];
  115.         }
  116.         else
  117.         {
  118.           entered = invalid;
  119.         }
  120.       }
  121.     }
  122.  
  123.     char GetEnteredKey()
  124.     {
  125.       return entered;
  126.     }
  127.  
  128.     //blocks any input for the specified milliseconds
  129.     void BlockInput(unsigned int milliseconds)
  130.     {
  131.       unblockMillis = millis() + milliseconds;
  132.     }
  133. };
  134.  
  135. class CodeBuilder
  136. {
  137.   private:
  138.     char* code;
  139.     unsigned int codeLength;
  140.     char* entered;
  141.     unsigned int currentPosition = 0;
  142.     unsigned int maxCodeLength;
  143.     char invalid;
  144.  
  145.     void clearEntered()
  146.     {
  147.       for (unsigned int i = 0; i < maxCodeLength; i++)
  148.       {
  149.         entered[i] = invalid;
  150.         currentPosition = 0;
  151.       }
  152.     }
  153.  
  154.   public:
  155.     CodeBuilder(char* _code, unsigned int _codeLength, char _invalid,  unsigned int _maxCodeLength)
  156.     {
  157.       code = _code;
  158.       codeLength = _codeLength;
  159.       maxCodeLength = _maxCodeLength;
  160.       entered = new char[maxCodeLength];
  161.       invalid = _invalid;      
  162.  
  163.       clearEntered();
  164.      
  165.     }
  166.  
  167.     void AddChar(char c)
  168.     {
  169.       if (currentPosition < maxCodeLength)
  170.       {
  171.         entered[currentPosition] = c;
  172.         currentPosition++;
  173.       }
  174.     }  
  175.  
  176.     bool VerifyEnteredCode()
  177.     {
  178.       currentPosition = 0;
  179.       bool success = true;
  180.  
  181.       //get entered length
  182.       unsigned int enteredLength = 0;
  183.       for (unsigned int i = 0; i < maxCodeLength; i++)
  184.       {
  185.         if (entered[i] != invalid)
  186.         {
  187.           enteredLength++;
  188.         }
  189.         else
  190.         {
  191.           break;
  192.         }
  193.       }
  194.       if (enteredLength != codeLength)
  195.       {
  196.         success = false;
  197.       }
  198.       else
  199.       {
  200.         //compare them in detail
  201.         for (unsigned int i = 0; i < codeLength; i++)
  202.         {
  203.           if ((entered[i] != code[i]) || (entered[i] == invalid))
  204.           {
  205.             success = false;
  206.             break;
  207.           }
  208.         }
  209.       }
  210.  
  211.       //reset everything for the next time
  212.       clearEntered();
  213.      
  214.       return success;
  215.     }
  216. };
  217.  
  218. class OutputHandler
  219. {
  220.   private:
  221.     LiquidCrystal_I2C lcd;
  222.     char secret;
  223.     long openTime;
  224.     long waitTime;
  225.     unsigned long lastMillis;
  226.     bool successfulEntry = false;
  227.     bool unsuccessfulEntry = false;
  228.     int *outputPins;
  229.     uint8_t outputPinsLength;
  230.     bool outputPinsActiveLevel;
  231.     char *line1;
  232.     char *line2;
  233.     char *success1;
  234.     char *success2;
  235.     char *fail1;
  236.     char *fail2;
  237.  
  238.     void reset()
  239.     {
  240.       lcd.clear();
  241.       lcd.setCursor(0,0);
  242.     }
  243.  
  244.     void resetMessage()
  245.     {
  246.       reset();
  247.       lcd.print(line1);
  248.       lcd.setCursor(0,1);
  249.       lcd.print(line2);
  250.     }
  251.  
  252.     void unlockDoor()
  253.     {
  254.       for(int i = 0; i < outputPinsLength; i++)
  255.       {
  256.         digitalWrite(outputPins[i], outputPinsActiveLevel);
  257.       }
  258.     }
  259.  
  260.     void lockDoor()
  261.     {
  262.       for(int i = 0; i < outputPinsLength; i++)
  263.       {
  264.         digitalWrite(outputPins[i], !outputPinsActiveLevel);
  265.       }
  266.     }
  267.   public:
  268.     OutputHandler(uint8_t lcdRows, uint8_t lcdCols, unsigned int lcdI2CAddress, char _secret, long _openTime, long _waitTime, int *_outputPins, uint8_t _outputPinsLength, bool _outputPinsActiveLevel, char* _line1, char* _line2, char* _success1, char* _success2, char* _fail1, char* _fail2) : lcd(lcdI2CAddress, lcdCols, lcdRows)
  269.     {
  270.       secret = _secret;
  271.       openTime = _openTime;
  272.       waitTime = _waitTime;
  273.  
  274.       outputPins = _outputPins;
  275.       outputPinsLength = _outputPinsLength;
  276.       outputPinsActiveLevel = _outputPinsActiveLevel;
  277.  
  278.       line1 = _line1;
  279.       line2 = _line2;
  280.       success1 = _success1;
  281.       success2 = _success2;
  282.       fail1 = _fail1;
  283.       fail2 = _fail2;
  284.     }
  285.  
  286.     void Setup()
  287.     {
  288.       lcd.init();
  289.       lcd.backlight();
  290.       resetMessage();
  291.  
  292.       for (int i = 0; i < outputPinsLength; i++)
  293.       {
  294.         pinMode(outputPins[i], OUTPUT);
  295.       }
  296.       lockDoor();
  297.     }
  298.  
  299.     void Update()
  300.     {
  301.       if (successfulEntry && (lastMillis + openTime < millis())) //openTime is over
  302.       {
  303.         resetMessage();
  304.         successfulEntry = false;
  305.         lockDoor();
  306.       }
  307.       if (unsuccessfulEntry && (lastMillis + waitTime < millis())) //closedTime is over
  308.       {
  309.         resetMessage();
  310.         unsuccessfulEntry = false;
  311.       }
  312.     }
  313.  
  314.     void CodeCharEntered()
  315.     {
  316.       lcd.print(secret);
  317.     }
  318.  
  319.     void CodeTrial(bool success)
  320.     {
  321.       if (success)
  322.       {
  323.         reset();
  324.         lcd.print(success1);
  325.         lcd.setCursor(0,1);
  326.         lcd.print(success2);
  327.         successfulEntry = true;
  328.         unlockDoor();
  329.       }
  330.       else
  331.       {
  332.         reset();
  333.         lcd.print(fail1);
  334.         lcd.setCursor(0,1);
  335.         lcd.print(fail2);
  336.         unsuccessfulEntry = true;
  337.       }
  338.       lastMillis = millis(); //get the current Time
  339.     }
  340.  
  341. };
  342.  
  343. /////////////////////////////////////////////////////////////////
  344. //Configuration Area - Do all your configs here!
  345. /////////////////////////////////////////////////////////////////
  346.  
  347. ////Section: LCD Setup
  348.  
  349. //Represent the keypad. The code will loop thru the columns and listens the rows for clicks.
  350. //Make sure that the total number of chars is equal to the total number of buttons!
  351. int keys[] = {
  352.   '1','2','3',
  353.   '4','5','6',
  354.   '7','8','9',
  355.   '*','0','#'
  356. };
  357.  
  358. //The columns of the LCD
  359. const uint8_t lcdCols = 16;
  360.  
  361. //The rows of the LCD
  362. const uint8_t lcdRows = 2;
  363.  
  364. //The I²C Address of the LCD
  365. uint8_t lcdI2CAddress = 0x27;
  366.  
  367. ////================================================================
  368. ////Section: Arduino Pins
  369. ////================================================================
  370.  
  371. //The pins where the rows are connected to: 1 pin per row only!!!
  372. int rowPins[] = {2,3,4,5};
  373.  
  374. //The pins where the columns are connected to: 1 pin per column only!!!
  375. int columnPins[] = {6,7,8};
  376.  
  377. //The pins that are switched on a successful code. You can add as many as you want and have.
  378. int outputPins[] = {10,11};
  379.  
  380. //Should the output pins be HIGH or LOW on successful entry?
  381. bool outputPinsActiveLevel = LOW;
  382.  
  383. ////================================================================
  384. ////Section: Characters and Password / Code
  385. ////================================================================
  386.  
  387. //The password that needs to be entered to unlock the door. Make sure that it only contains characters
  388. //of the keypad and neither the invalid and the accept character! Also, it mustn't be longer than the maxCodeLength!
  389. char password[] = "12345";
  390.  
  391. //The maximum code length. I was about to hard-calculate it but it could be used to set a maximum entry length.
  392. //Further characters will be ignored.
  393. //Example: if you have a 16x2 LCD, "Code:" takes 5 characters, so the most
  394. uint8_t maxCodeLength = 10;
  395.  
  396. //The character (found in the keys[]) that accepts the code entry. It mustn't be part of password[]!
  397. char acceptKey = '#';
  398.  
  399. //The character used for displaying the entered code on the LCD. It can be whatever the LCD understands.
  400. char lcdSecret = '*';
  401.  
  402. //The character representing "invalid". Set it to something you do not have in your keys[]!
  403. char invalid = ' ';
  404.  
  405. //The amount of milliseconds to wait between each keypad loop.
  406. unsigned int subDelay = 2;
  407.  
  408. ////================================================================
  409. ////Section: Timing
  410. ////================================================================
  411.  
  412. //The time to wait after unsuccessful entry [ms]
  413. long waitTime = 10000;
  414.  
  415. //The time the door relay is unlocked (successful entry) [ms]
  416. long openTime = 2500;
  417.  
  418. ////================================================================
  419. ////Section: Texts
  420. ////================================================================
  421.  
  422. //The text displayed in the first line
  423. char Line1[lcdCols+1] = "3d-print shop";
  424.  
  425. //The text displayed in front of the entered code
  426. char Line2[lcdCols+1] = "Code:";
  427.  
  428. //The text displayed in the first line when the entered code was correct.
  429. char Success1stLine[lcdCols+1] = "Code correct!";
  430.  
  431. //The text displayed in the second line when the entered code was correct.
  432. char Success2ndLine[lcdCols+1] = "Please enter...";
  433.  
  434. ////The text displayed in the first line when the entered code was wrong.
  435. char Fail1stLine[lcdCols+1] = "Wrong code!";
  436.  
  437. ////The text displayed in the second line when the entered code was wrong.
  438. char Fail2ndLine[lcdCols+1] = "Try again in 10s";
  439.  
  440.  
  441. ///End of adaptions///
  442.  
  443. unsigned int keysLength = sizeof(keys)/sizeof(keys[0]);
  444. unsigned int rows = sizeof(rowPins)/sizeof(rowPins[0]);
  445. unsigned int columns = sizeof(columnPins)/sizeof(columnPins[0]);
  446. unsigned int codeLength = sizeof(password)/sizeof(password[0]) - 1;
  447. unsigned int outputPinsLength = sizeof(outputPins)/sizeof(outputPins[0]);
  448.  
  449. InputHandler input(subDelay, invalid, keys, keysLength, rowPins, rows, columnPins, columns);
  450. CodeBuilder builder(password, codeLength, invalid, maxCodeLength);
  451. OutputHandler out(lcdCols, lcdRows, lcdI2CAddress, lcdSecret, openTime, waitTime, outputPins, outputPinsLength, outputPinsActiveLevel, Line1, Line2, Success1stLine, Success2ndLine, Fail1stLine, Fail2ndLine);
  452.  
  453.  
  454. void setup() {
  455.   // put your setup code here, to run once:
  456.   out.Setup();
  457.   input.Setup();
  458. }
  459.  
  460. char old_e = invalid;
  461. void loop() {
  462.   // put your main code here, to run repeatedly:
  463.   input.Update();
  464.  
  465.   char _e = input.GetEnteredKey();
  466.   if (_e != old_e)
  467.   {
  468.     if (_e != invalid) //a char has been entered
  469.     {
  470.       if (_e == acceptKey) //the char was the acceptKey
  471.       {
  472.         bool success = builder.VerifyEnteredCode();
  473.         out.CodeTrial(success);
  474.         if (success)
  475.         {
  476.           input.BlockInput(openTime);
  477.         }
  478.         else
  479.         {
  480.           input.BlockInput(waitTime);
  481.         }
  482.       }
  483.       else { //the char was any other
  484.         builder.AddChar(_e);
  485.         out.CodeCharEntered();
  486.       }
  487.     }
  488.     old_e = _e;
  489.   }
  490.   out.Update();
  491. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement