glennedi
Published © GPL3+

Diceware password lookup box

Strengthen your passwords now!

BeginnerFull instructions provided423
Diceware password lookup box

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Deek robot data logging shield version 1.0
×1
LCD shield with keyboard
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

How everything fits together

SD shield

You don't need the piezo sounder

Code

Arduino code

C/C++
//Diceware word look up box
//January 2021

/*
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 10 for deek robot data logging shield v1.0
 * 
 * RTC connections (I2C) - Clock not used in this project:
 * gnd to gnd
 * + to +5V
 * SDA to A4
 * SCL to A5
 * 
 * LCD shield:
 * Backlight - pin 10 removed
 * B4 to D4
 * B5 to D5
 * B6 to D6
 * B7 to D7 
 * RS to D8
 * E to D9
 * 
 * LCD shield buttons:
 * Analog 0
 * 
 * Buzzer - not used
 * GND to GND
 * + to D3 
 */


#include <SPI.h>
#include <SD.h>
#define CS_PIN 10 //for SD card reader

//CHECK TO SEE IF LCD IS ONE OF THE FAULTY ONES
//MINE HAD PROBLEMS SO I DESOLDERED AND REMOVED THE FAULTY PIN 10
//REFERENCE - https://forum.arduino.cc/index.php?topic=96747.0 (Retrieved 7/June/2019)
//for the LCD shield
#include <LiquidCrystal.h>
// select the pins used on the lcd panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// http://www.robotshop.com/content/PDF/dfrobot-lcd-keypad-shield-schematic.pdf 


//required to debounce switch
#define MAX_CHECKS 10
volatile uint8_t Debounced_State=0;//accessed by isr and main loop code
uint8_t State[MAX_CHECKS]={0};
uint8_t Index=0;




//set the name of the file we are reading from
#define my_filename "diceware.txt" 
//#define my_filename "eff_l.txt"
#define MAX_DICE 5 //the size of the dice numbers array - it can only be 4 or 5

//#define my_filename "eff_s.txt"
//#define my_filename "eff_s2.txt"
//#define MAX_DICE 4 //the size of the dice numbers array - it can only be 4 or 5


void setup()
{

        // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 625;              // compare match register  16MHX/256/100HZ 
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  interrupts();

//initial lcd setup
  lcd.begin(16,2);    // initialize the lcd for 16 chars 2 lines    
  lcd.clear();

  if (!SD.begin(CS_PIN)) {
    display_error(1);
    return;
  }

  //set up display for first time
  display_setup();

}

void loop()
{
  
//variables
bool select_pressed=false;
bool dice_updated=false;

static bool button_up=false;
static bool chord_ready=false;
static int Stored_State=0;
static int Action_Me=0;

static int dice_array[]={1,1,1,1,1};
static int dice_count=0;
static int selection=0;

String l_line;
l_line.reserve(128); //Avoids heap memory fragmentation
                     //Reserve space for your longest expected data line
 
while(1){

    noInterrupts();           // disable all interrupts    
if (Debounced_State>Stored_State){Stored_State=Debounced_State;chord_ready=true;}//store chord and flag as ready
if (Debounced_State<Stored_State){if(chord_ready){button_up=true;Action_Me=Stored_State;}Stored_State=Debounced_State;} 
    interrupts();             // enable all interrupts

if(button_up && chord_ready)
{
chord_ready=false;
button_up=false;

if (Action_Me&1<<0){select_pressed=true;}//select button                      
if (Action_Me&1<<2){dice_updated=true;}//down button

}
 
  if (select_pressed){
    
  select_pressed=false;
  selection++;

  unsigned long x=0;

  if(MAX_DICE==5){
  x=(unsigned long)dice_array[0]*10000;
  x+=dice_array[1]*1000;
  x+=dice_array[2]*100;
  x+=dice_array[3]*10;
  x+=dice_array[4];}
  
  if(MAX_DICE==4){
  x+=dice_array[0]*1000;
  x+=dice_array[1]*100;
  x+=dice_array[2]*10;
  x+=dice_array[3];   
    }

  /*do word lookup*/
  if(selection==MAX_DICE){
    
  selection=0;

  display_dash(true);
  move_cursor(selection);

  // re-open the file for reading:
  File myFile = SD.open(my_filename);
  if (!myFile) {
    display_error(2);
    return;
  }
  
  // read from the file until you find the required number and print out the complimentary word:
  bool found_item=false;
                       
  while (myFile.available() && !found_item) {
    l_line = myFile.readStringUntil('\n');
    l_line.trim();
    
    if (l_line != "") {
      int l_start_posn = 0;
      while (l_start_posn != -1)

 if((unsigned long)(ENDF2(l_line,l_start_posn,'\t').toInt())==x)
        {display_dash(false);display_word(ENDF2(l_line,l_start_posn,'\t').c_str() );found_item=true;}

        
    } //skip blank (NULL) lines
  }//Read the file line by line
  myFile.close();      
    }

  move_cursor(selection); 
                   
                    }

if (dice_updated){
  
  dice_updated=false;
  dice_count=dice_array[selection];
  dice_count++;
  if (dice_count>6){dice_count=1;}
  dice_array[selection]=dice_count;

  display_numbers(dice_array);
  move_cursor(selection);

                  }
                  
                         
}//end of while loop
}

String ENDF2(String &p_line, int &p_start, char p_delimiter) {
//EXTRACT NEXT DELIMITED FIELD VERSION 2
//Extract fields from a line one at a time based on a delimiter.
//Because the line remains intact we dont fragment heap memory
//p_start would normally start as 0
//p_start increments as we move along the line
//We return p_start = -1 with the last field

  //If we have already parsed the whole line then return null
  if (p_start == -1) {
    return "";
  }

  int l_start = p_start;
  int l_index = p_line.indexOf(p_delimiter,l_start);
  if (l_index == -1) { //last field of the data line
    p_start = l_index;
    return p_line.substring(l_start);
  }
  else { //take the next field off the data line
    p_start = l_index + 1;
    return p_line.substring(l_start,l_index); //Include, Exclude
  }
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{

//read buttons
  uint8_t temp=0x00;
/*
 * //rough values from read of analog buttons
636 //select
408 //left
254 //down
101 //up
0   //right
*/  
 if (analogRead(0) > 600  && analogRead(0) < 650){temp|=1<<0;} //select  
 if (analogRead(0) > 380 && analogRead(0) < 450){temp|=1<<1;} //left
 if (analogRead(0) > 200 && analogRead(0) < 300){temp|=1<<2;} //down
 if (analogRead(0) > 50 && analogRead(0) < 150){temp|=1<<3;} //up
 if (analogRead(0) >= 0 && analogRead(0) < 45){temp|=1<<4;} //right
 
//debounce
  uint8_t i,j;
  State[Index]= temp;
  ++Index;
  j=0xFF;
  for (i=0;i<MAX_CHECKS;i++){j=j&State[i];}
  Debounced_State=j;
  if(Index>=MAX_CHECKS){Index=0;} 
}

//for the display

//the error codes
void display_error(int code){
  
  switch (code){
    
    case 1: lcd.clear();lcd.print("Initialization");lcd.setCursor(0,1);lcd.print("failed");break;
    case 2: lcd.clear();lcd.print("Can't open file");break;
    }
  while(1){};
  }

//the initial setup
void display_setup(){  
  lcd.clear();
  lcd.cursor();
  lcd.setCursor(0,0);
  lcd.print("Number: ");
  int i=0;
  for(i=0;i<MAX_DICE;i++){lcd.print("1");}
  lcd.setCursor(0,1);
  lcd.print("Word: ");
  lcd.setCursor(8,0);
  }

//the array of dice numbers
void display_numbers (int dice_array[]){
  
  lcd.setCursor(8,0);
  int i=0;
  for(i=0;i<MAX_DICE;i++){lcd.print(dice_array[i]);}
    
  }

//a dashed line or blank
void display_dash(bool isTrue){

  if (isTrue){lcd.setCursor(6,1);lcd.print("---------");}else{lcd.setCursor(6,1);lcd.print("         ");}
  
  }

//output the word to the display
void display_word(char* my_word){
  
  lcd.setCursor(6,1);
  lcd.print(my_word);
  
  }

//cursor movement 
void move_cursor(int selection){ 
  switch (selection){
    case 0:lcd.setCursor(8,0);break;
    case 1:lcd.setCursor(9,0);break;
    case 2:lcd.setCursor(10,0);break;
    case 3:lcd.setCursor(11,0);break;
    case 4:lcd.setCursor(12,0);break;
    }}

Credits

glennedi

glennedi

5 projects • 23 followers

Comments