TFT Password Entry & Validation

Edit: I have figured it out - I'm using strings and a counter, every time a button is pressed, it appends that number to string1 and adds 1 to the counter. When the counter reaches 5, string1 is checked against string2 to see if it is the same (string2 containing the password).

Now I just need to know how the hell to cut down my spaghetti code...I'll paste it below, maybe someone can help me with that :}

This is my radical number device:

1 of 2

#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include <TouchScreen.h>
#define MINPRESSURE 200
#define MAXPRESSURE 1000

#include <Fonts/FreeSans9pt7b.h>

const int XP=6,XM=A1,YP=A2,YM=7; //240x320 ID=0x9338
const int TS_LEFT=202,TS_RT=889,TS_TOP=953,TS_BOT=228;
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
int pixel_x, pixel_y;     //Touch_getXY() updates global vars


String pWord, pString;
int counter = 0;
boolean correctP = false;

Adafruit_GFX_Button one_btn, two_btn, three_btn, four_btn, five_btn, six_btn, seven_btn, eight_btn, nine_btn, clear_btn, zero_btn, call_btn, return1_btn;

bool Touch_getXY(void)
{
    TSPoint p = ts.getPoint();
    pinMode(YP, OUTPUT);      //restore shared pins
    pinMode(XM, OUTPUT);
    digitalWrite(YP, HIGH);   //because TFT control pins
    digitalWrite(XM, HIGH);
    bool pressed = (p.z > MINPRESSURE && p.z < MAXPRESSURE);
    if (pressed) {
        pixel_x = map(p.x, TS_LEFT, TS_RT, 0, tft.width());
        pixel_y = map(p.y, TS_TOP, TS_BOT, 0, tft.height());
    }
    return pressed;
}

#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
#define LTBL    0x6EFC
#define BG222   0x2104
#define BG333   0x3186
#define BG111   0x1082

boolean keyScrn = true;
boolean callScrn = false;

void setup(void)
{
    Serial.begin(9600);
    pWord = String("54321");
    pString = String("");
    uint16_t ID = tft.readID();
    if (ID == 0xD3D3) ID = 0x9486; // write-only shield
    tft.begin(ID);
    tft.setRotation(0);            //PORTRAIT
    tft.fillScreen(BG222);
    showmsgXY(100, 150, 1, &FreeSans9pt7b, "Hello", WHITE);
    delay(2000);
    drawKeypad();
}

void TopTXT() {
  tft.setTextColor(WHITE);
  tft.setCursor(38,20);
  tft.setTextSize(1);
  tft.setTextWrap(false);
  tft.println("ENTER PIN or CALL");
}
void PassTXT() {
  tft.setTextColor(BLACK);
  tft.setCursor(90,50);
  tft.setTextSize(1);
  tft.setTextWrap(false);
  tft.println("[     ]");
}

2 of 2

Try not to laugh too much at this...

void drawKeypad () {
  clear();
  TopTXT();
  PassTXT();
    one_btn.initButton(&tft, 55, 93, 50, 50, BLACK, LTBL, BG333, "1", 1);
    two_btn.initButton(&tft, 120, 93, 50, 50, BLACK, LTBL, BG333, "2", 1);
    three_btn.initButton(&tft, 185, 93, 50, 50, BLACK, LTBL, BG333, "3", 1);
    four_btn.initButton(&tft, 55, 158, 50, 50, BLACK, LTBL, BG333, "4", 1);
    five_btn.initButton(&tft, 120, 158, 50, 50, BLACK, LTBL, BG333, "5", 1);
    six_btn.initButton(&tft, 185, 158, 50, 50, BLACK, LTBL, BG333, "6", 1);
    seven_btn.initButton(&tft, 55, 223, 50, 50, BLACK, LTBL, BG333, "7", 1);
    eight_btn.initButton(&tft, 120, 223, 50, 50, BLACK, LTBL, BG333, "8", 1);
    nine_btn.initButton(&tft, 185, 223, 50, 50, BLACK, LTBL, BG333, "9", 1);
    clear_btn.initButton(&tft, 55, 288, 50, 50, BLACK, LTBL, BG333, "CLR", 1);
    zero_btn.initButton(&tft, 120, 288, 50, 50, BLACK, LTBL, BG333, "0", 1);
    call_btn.initButton(&tft, 185, 288, 50, 50, BLACK, LTBL, BG333, "CALL", 1);
    
    one_btn.drawButton(false);
    two_btn.drawButton(false);
    three_btn.drawButton(false);
    four_btn.drawButton(false);
    five_btn.drawButton(false);
    six_btn.drawButton(false);
    seven_btn.drawButton(false);
    eight_btn.drawButton(false);
    nine_btn.drawButton(false);
    clear_btn.drawButton(false);
    zero_btn.drawButton(false);
    call_btn.drawButton(false);
  }

void drawCallpad() {
  clear();
    return1_btn.initButton(&tft, 185, 288, 50, 50, BLACK, LTBL, BG333, "Back", 1);
    return1_btn.drawButton(false);
  }


void clear() {
  tft.fillScreen(BG222);
  }
  
void showmsgXY(int x, int y, int sz, const GFXfont *f, const char *msg, int clr)
{
    int16_t x1, y1;
    uint16_t wid, ht;
    // tft.drawFastHLine(0, y, tft.width(), WHITE);
    tft.setFont(f);
    tft.setCursor(x, y);
    tft.setTextColor(clr);
    tft.setTextSize(sz);
    tft.print(msg);
}


void loop() {
  while (keyScrn) {
    keypad();
    }
    while (callScrn) {
    callpad();
    }
  }


void keypad(void)
{
    bool down = Touch_getXY();
    one_btn.press(down && one_btn.contains(pixel_x, pixel_y));
    two_btn.press(down && two_btn.contains(pixel_x, pixel_y));
    three_btn.press(down && three_btn.contains(pixel_x, pixel_y));
    four_btn.press(down && four_btn.contains(pixel_x, pixel_y));
    five_btn.press(down && five_btn.contains(pixel_x, pixel_y));
    six_btn.press(down && six_btn.contains(pixel_x, pixel_y));
    seven_btn.press(down && seven_btn.contains(pixel_x, pixel_y));
    eight_btn.press(down && eight_btn.contains(pixel_x, pixel_y));
    nine_btn.press(down && nine_btn.contains(pixel_x, pixel_y));
    clear_btn.press(down && clear_btn.contains(pixel_x, pixel_y));
    zero_btn.press(down && zero_btn.contains(pixel_x, pixel_y));
    call_btn.press(down && call_btn.contains(pixel_x, pixel_y));

    if (one_btn.justReleased())
        one_btn.drawButton();
        
    if (two_btn.justReleased())
        two_btn.drawButton();
        
    if (three_btn.justReleased())
        three_btn.drawButton();

    if (four_btn.justReleased())
        four_btn.drawButton();
        
    if (five_btn.justReleased())
        five_btn.drawButton();
        
    if (six_btn.justReleased())
        six_btn.drawButton();

    if (seven_btn.justReleased())
        seven_btn.drawButton();
        
    if (eight_btn.justReleased())
        eight_btn.drawButton();
        
    if (nine_btn.justReleased())
        nine_btn.drawButton();
        
    if (clear_btn.justReleased())
        clear_btn.drawButton();
        
    if (zero_btn.justReleased())
        zero_btn.drawButton();
        
    if (call_btn.justReleased())
        call_btn.drawButton();

        
    if (one_btn.justPressed()) {
        one_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, BLACK);
        counter++;
        Serial.println(counter);
        Serial.println("1");
        pString += 1;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (two_btn.justPressed()) {
        two_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, BLUE);
        counter++;
        Serial.println(counter);
        Serial.println("2");
        pString += 2;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (three_btn.justPressed()) {
        three_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, RED);
        counter++;
        Serial.println(counter);
        Serial.println("3");
        pString += 3;
        Serial.println(pString);
        checkPword();
        delay(100);}

        
    if (four_btn.justPressed()) {
        four_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, GREEN);
        counter++;
        Serial.println(counter);
        Serial.println("4");
        pString += 4;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (five_btn.justPressed()) {
        five_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, CYAN);
        counter++;
        Serial.println(counter);
        Serial.println("5");
        pString += 5;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (six_btn.justPressed()) {
        six_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, MAGENTA);
        counter++;
        Serial.println(counter);
        Serial.println("6");
        pString += 6;
        Serial.println(pString);
        checkPword();
        delay(100);}

        
    if (seven_btn.justPressed()) {
        seven_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, YELLOW);
        counter++;
        Serial.println(counter);
        Serial.println("7");
        pString += 7;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (eight_btn.justPressed()) {
        eight_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, WHITE);
        counter++;
        Serial.println(counter);
        Serial.println("8");
        pString += 8;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (nine_btn.justPressed()) {
        nine_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, BLACK);
        counter++;
        Serial.println(counter);
        Serial.println("9");
        pString += 9;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (clear_btn.justPressed()) {
        clear_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, GREEN);
        counter = 0;
        Serial.println(counter);
        Serial.println("CLEAR");
        pString = "";
        Serial.println(pString);
        delay(100);}
        
    if (zero_btn.justPressed()) {
        zero_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, YELLOW);
        counter++;
        Serial.println(counter);
        Serial.println("0");
        pString += 0;
        Serial.println(pString);
        checkPword();
        delay(100);}
        
    if (call_btn.justPressed()) {
        call_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, RED);
        Serial.println("CALL");
        counter = 0;
        pString = "";
        delay(100);
        callScrn = true;
        keyScrn = false;
        drawCallpad();
        }
        
}

void checkPword() {
        if (counter == 5) {
          if (pString == pWord) {
            counter = 0;
            correctP = true;
            pString = "";
            Serial.println("Correct Password Entered");
            } else {
            counter = 0;
            correctP = false;
            pString = "";
            Serial.println("Incorrect Password Entered");
            }
          }
}

void callpad(void) {
    bool down = Touch_getXY();
    return1_btn.press(down && return1_btn.contains(pixel_x, pixel_y));
    
    if (return1_btn.justReleased())
        return1_btn.drawButton();

    if (return1_btn.justPressed()) {
        return1_btn.drawButton(true);
        tft.fillRect(40, 8, 160, 4, BLACK);
        Serial.println("RETURN TO KEYPAD");
        delay(100);
        callScrn = false;
        keyScrn = true;
        drawKeypad();
        }
}

If it works, move on to the next project.

Looking at the code, it's not too bad. You might want to consider using an array for the number buttons.

The other thing that you might want to clean up is your password is visible in clear in the code. If someone sees this code, then they know the passcode to whatever this device is protecting. There's a cryptographic solution to this and there's an Arduino solution.

It is possible to encrypt the code in your source code. Then when the passcode is entered, it is encrypted and checked against the stored code. I don't recommend this on an Arduino, but this method is used on web pages all the time.

On the Arduino, it's best to make the code configurable. Make it possible to type in a new code. Then the actual code on the device isn't in the source code. Study how the Arduino EEPROM can be used to permanently store small amounts of data in the Arduino, where they are not readily accessible from the outside.

For extra credit, do both, so even a relatively sophisticated hacker who can extract the EEPROM contents only gets the encrypted code and not the code to be typed in on the keypad.

By the way, the photo of the keypad on the screen looks great!

MorganS:
If it works, move on to the next project.

It works very nicely now, but it's about to get even uglier once I add code to I2C the WeMos board and have call functions & app control going through it :expressionless: - I think I should try to figure out how to reduce the repeated iterations of defined objects that I'd like to assign a function/parameter to.

For example - I have all these buttons defined:

Adafruit_GFX_Button one_btn, two_btn, three_btn, four_btn, five_btn, six_btn, seven_btn, eight_btn, nine_btn, clear_btn, zero_btn, call_btn, return1_btn;

they are each called on for similar functions over and over again:

one_btn.drawButton(false); // * 12
one_btn.press(down && one_btn.contains(pixel_x, pixel_y)); // * 12
if (one_btn.justReleased())
        one_btn.drawButton(); // * 12
if (one_btn.justPressed()) {
        one_btn.drawButton(true);
        counter++;
        pString += 1;
        Serial.println(pString);
        PassTXT();
        checkPword();
        delay(100);} // * 12

If I could just get these few parts whittled down, the whole thing would be about 75% smaller. I'll go google stuff now but if you have some things to point me in the right direction, that'd be very helpful.

MorganS:
Looking at the code, it's not too bad. You might want to consider using an array for the number buttons.

I saw this being done with standard button keypad examples, and they would all use a function after like "buildKeypad". I wasn't sure how to apply it to objects I'd made in a TFT screen - I'll read about it more though.

MorganS:
The other thing that you might want to clean up is your password is visible in clear in the code. If someone sees this code, then they know the passcode to whatever this device is protecting.

I'll have to come back to this EEPROM business - I don't expect many people around here to be pulling apart the housing and jacking in with a laptop and usb cable, but maybe I'm just not being cautious enough. Seems like they could just kick the door down for less effort.

MorganS:
By the way, the photo of the keypad on the screen looks great!

Thanks! I am happy with it - I used Illustrator to come up with the layout and colors before copying the coordinates and sizes over:

jtbennett:

  • I don't expect many people around here to be pulling apart the housing and jacking in with a laptop and usb cable, but maybe I'm just not being cautious enough. Seems like they could just kick the door down for less effort.

Exactly. You only need to make the security strong "enough".

Using an array of buttons won't dramatically shorten the code. You still have to set all the positions and sizes individually.

MorganS:
Exactly. You only need to make the security strong "enough".

If I were to change the string via Blynk running through WiFi after it'd been compiled, written and disconnected from the computer, would that technically leave the password floating around in the memory instead of written? I don't know how that thing operates...but it seems to work. Much like my stupid projects.

I've finished the first stage of it now, which just means I have a connected SIM900 and a second interface page that'll let you make phone calls to me from the front doorstep or ring the doorbell, as well as unlock with code.


I put the pictures here: https://imgur.com/a/WdVB155

MorganS:
Study how the Arduino EEPROM can be used to permanently store small amounts of data