This is a lot of code.

This first section contains the libraries and global variables that are used to run the program.

#include <hidboot.h> /*handles the card reader*/ #include <spi.h> /*Serial for the mag Reader and SD Shield */ #include <sd.h> /*library to handle the SD SHield*/ #include <wire.h> /*I2c Library for Real Time Clock (RTC)*/ #include "RTClib.h" /*RTC library*/ #include <liquidcrystal_i2c.h> /*LCD Display library*/ /*various variables*/ String readMag; /*string to store car info*/ String checkName = ""; /*buffer for reading names from List file*/ unsigned long currentMillis = 0; /*handles timeout for card reader to reset readMag after entire card is read*/ long previousMillis = 0; /*part of currentMillis situation for the card reading code*/ long pMillis = 0; /*used for loop code to indicate "ready" or "wait" for user to waait for card reader to reset*/ /*various pins for the different hardware Special note: USB Shield chip selecter is 10 SD Shield chip selecter is 4 Turn them low to activate and high to deactivate */ const byte relayPin = 3; const byte keyInput = 5; const byte GreenLED = 7; const byte button = 6; /*various state recording variables*/ boolean powerState = false; /*tool power is off at start*/ boolean keyState = false; /*key is off*/ boolean buttonState = false; /*button is off*/ boolean swipeState = false; /*no one has swiped yet*/ boolean once = false; /*only lets the lcd print the swiped card and time once rather than indeffinitely*/ boolean adminSwipe = false; /*handles admin adding cards*/ boolean timer = false; /*records state for*/ /*instnaces for the magReader*/ USB Usb; HIDBoot<usb_hid_protocol_keyboard> HidKeyboard(&Usb); /* instance for the SD file handler*/ File openedFile; /* instance to RTC*/ RTC_PCF8523 rtc; /* LCD instance */ LiquidCrystal_I2C lcd(0x27, 20, 4); /*Class for the magReader*/ class KbdRptParser : public KeyboardReportParser { protected: void OnKeyDown (uint8_t mod, uint8_t key); void OnKeyPressed(uint8_t key); }; /*instance of the magReader class*/ KbdRptParser Prs;

This next section is the setup that initiates all of the variables and starts all the different serial communications, and the Class header and cpp code for the magReader. The thing to note is in the MagReader class cpp is where most of the action happens when a card is swiped. This is also where the Admin's first 15 characters of their card are stored.

The logic for manipulating the swiped card's data down below is as follows: *****

If the button is pressed and the Admin swiped then activate Admin mode so the next swiped card is added to the list of registered people. Else if admin mode has been activated go to WriteToList to add this new person's card. If neither of those then go to CheckList to see if this new swipe is on the list.

void setup() { Serial.begin( 115200 ); /*start usb mag Reader*/ digitalWrite(10, LOW); if (Usb.Init() == -1) Serial.println(F("OSC did not start.")); ( 200 ); HidKeyboard.SetReportParser(0, &Prs); digitalWrite(10, HIGH); /*start RTC */ rtc.begin(); if (! rtc.initialized()) { Serial.println(F("RTC is NOT running!")); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); /*saves the time and date of your pc to rtc*/ } /*start sd shield*/ digitalWrite(4, HIGH); if (!SD.begin(4)) { Serial.println(F("initialization failed!")); lcd.print("init Failed"); return; } digitalWrite(4, HIGH); digitalWrite(10, LOW); /*starts lcd display*/ lcd.begin(); lcd.backlight(); /*pinmodes for the various hardware*/ pinMode(button, INPUT); pinMode(keyInput, INPUT); pinMode(GreenLED, OUTPUT); pinMode(relayPin, OUTPUT); } //--------------------Reading card-------------------------------------------// void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) { // Serial.print("DN "); // PrintKey(mod, key); uint8_t c = OemToAscii(mod, key); if (c) OnKeyPressed(c); } void KbdRptParser::OnKeyPressed(uint8_t key) { timer = true; /*card has been swiped, saved for lcd indication timeout*/ /*timeout for card reader to reset readMag after larger cards have been read*/ currentMillis = millis(); if (currentMillis - previousMillis > 17000) { //if it has been more than 1 second clear variable previousMillis = currentMillis; readMag = ""; } char theChar; //buffer to store ascii value from reader theChar = ((char)key); //pass ascii value from usbhost to variable /*this prevents the card reader from reading any more than the required characters*/ if (readMag.length() < 16) { readMag += theChar; // assemble the ascii into a string } /*if readMag is 15 characters long do the stuff*/ if (readMag.length() == 15) { /*Switch communication from USB Shield to SD Shield*/ digitalWrite(10, HIGH); digitalWrite(4, LOW); // Serial.println(readMag); /*if the button is pressed during a swipe then activate admin mode and indicate on lcd*/ ***** if (digitalRead(button) == HIGH && readMag == /*Admin's card info*/(F("first_15_Characters_Of_Your_Admin_ID"))) { adminSwipe = true; lcd.setCursor(0, 1); lcd.print(F("ADMIN ACCESS ")); lcd.setCursor(0, 2); lcd.print(F(" ")); lcd.setCursor(0, 3); lcd.print(F(" ")); } else if (adminSwipe) { WriteToList(readMag); /*go to WriteToList method with swiped card info if in admin mode*/ } else { checkList(readMag); /*check to see if you are on the list*/ } /*switch communication from SD Shield to USB Shield*/ digitalWrite(4, HIGH); digitalWrite(10, LOW); return; } }

The loop method monitors the user inputs. Usb.Task() watches the card reader. The timer controls the "READY" or "WAIT" indications on the LCD for when the card reader is busy. The rest monitors if the button is pressed and if a card turns tool power on(cardState = true) or if the key turns tool power on(keyState = true). I used this cascading boolean state logic so that either the key or card reader can activate the powerState, but whenever the powerState is true then power is on. Whenever either the swipeState or the keyState is true, the Arduino is constantly checking the time, and whenever it reaches 5:15 pm it turns the power off. If the button is pressed then power is turned off.

void loop() { /*handle the card reader*/ Usb.Task(); /*if a card has been swiped start the indication timer. Run for 20 seconds indicating "wait", when the timer runs out record the state and indicate "ready" */ if (timer) { if (millis() - pMillis > 20000) { pMillis = millis(); timer = false; } else { lcd.setCursor(15, 0); lcd.print(F("WAIT ")); } } else { lcd.setCursor(15, 0); lcd.print(F("READY")); } /*Do all the stuff if the button is not pressed*/ if (!buttonState) { /*if the key is turned on turn power on*/ if (digitalRead(keyInput) == HIGH) { keyState = true; } else { keyState = false; buttonState = false; powerState = false; } /*if either the key is on or someone on the list swiped, the power is on. Record the time someone swiped and turned power on */ if (keyState || swipeState) { DateTime now = rtc.now(); powerState = true; // if (keyState && once) { // lcd.setCursor(0, 1); // lcd.print(F("KEY POWERED AT ")); // lcd.print(String(now.hour())); // lcd.print(F(":")); // lcd.print(String(now.minute())); // lcd.setCursor(0, 2); // lcd.print(F(" ")); // once = false; if (swipeState && once) { lcd.setCursor(0, 1); lcd.print(readMag); lcd.print(F(" ")); lcd.setCursor(0, 2); lcd.print(F("SWIPED AT ")); lcd.print(String(now.hour())); lcd.print(F(":")); lcd.print(String(now.minute())); once = false; } if (now.hour() == 17 && now.minute() == 15) { swipeState = false; keyState = false; powerState = false; lcd.setCursor(0,3); lcd.print(F("AUTO POWER OFF ")); } } /*If the button is pressed turn power off, record and indicate time, and reset states*/ if (digitalRead(button) == HIGH) { buttonState = true; keyState = false; swipeState = false; powerState = false; DateTime rn = rtc.now(); lcd.setCursor(0, 3); lcd.print("POWERED OFF "); lcd.print(rn.hour()); lcd.print(":"); lcd.print(rn.minute()); } /*If the power is on, turn LED and relay on and indicate on lcd. Else do the opposite of all that */ if (powerState) { digitalWrite(GreenLED, HIGH); digitalWrite(relayPin, HIGH); lcd.setCursor(0, 0); lcd.print(F("TOOL POWER ON ")); lcd.setCursor(0, 3); lcd.print(F(" ")); } else { digitalWrite(GreenLED, LOW); digitalWrite(relayPin, LOW); lcd.setCursor(0, 0); lcd.print(F("TOOL POWER OFF")); } }

The WriteToLog method takes the recently read card's info and writes it, the date, and the time to the SwipeLog file, creating a running log of whoever turns tool power on with their card. The benefit of using an SD card to store the log and the list of registered people is that if the power goes out in the building the data is preserved on the card. That and we can have much larger logs and lists on the SD card than stored on the Arduino itself.

/*This method writes the card info, time, and date to the SwipeLog file on the SD card*/ void WriteToLog(String Name) { DateTime now = rtc.now(); openedFile.close(); openedFile = SD.open(F("SwipeLog.txt"), FILE_WRITE); if (openedFile) { Serial.print(F("here?")); openedFile.print(Name); openedFile.print(','); openedFile.print(now.month(), DEC); openedFile.print('/'); openedFile.print(now.day(), DEC); openedFile.print('/'); openedFile.print(now.year(), DEC); openedFile.print(','); openedFile.print(now.hour(), DEC); openedFile.print(':'); openedFile.print(now.minute(), DEC); openedFile.print(':'); openedFile.print(now.second(), DEC); openedFile.println(); } openedFile.close(); }

The checkList method takes the recently read card's info and compares it to the list of names in the List file. The file.read() command only reads one byte at a time so checkName is a buffer that stores the characters until it reaches 17, trims the carriage return, and compares to the newly read card. If there is a match then it writes the card to the log file in WriteToLog and activates swipeState to turn tool power on. There are three different checkName = ""; to ensure each name in the list file is only one name and not a combination of two. If there is no match then it indicates so on the LCD.

/*This method iterated through the List file and compares the swiped card with each in the list If one matches then power state is on and WriteToLog, else indicate you are not on the list */ void checkList(String Name) { openedFile.close(); openedFile = SD.open(F("List.txt")); if (openedFile) { while (openedFile.available()) { /*only reads one character at a time, store wach in a string and when that reaches the return character in the file trim it and compare to swiped card info*/ char temp = char(openedFile.read()); checkName += temp; if (checkName.length() == 17) { checkName.trim(); if (Name.equals(checkName)) { swipeState = true; once = true; WriteToLog(readMag); checkName = ""; return; } checkName = ""; } } checkName = ""; } lcd.setCursor(0, 1); lcd.print(F("NOT ON LIST ")); lcd.setCursor(0, 2); lcd.print(F(" ")); }

WriteToList takes the recently read card's info and writes it to the list of registered people and indicates this on the LCD. It restores the admin mode to false so the next swiped card isn't added as well.

void WriteToList(String Name) { openedFile.close(); openedFile = SD.open(F("List.txt"), FILE_WRITE); if (openedFile) { openedFile.println(Name); openedFile.close(); lcd.setCursor(0, 1); lcd.print(Name); lcd.print(F(" ")); lcd.setCursor(0, 2); lcd.print(F("ADDED TO LIST ")); lcd.setCursor(0, 3); lcd.print(F(" ")); adminSwipe = false; } }