From 6b8379ba7a10dda50bbaf29a256f698b7c929b7c Mon Sep 17 00:00:00 2001 From: Will Bradley Date: Wed, 14 Sep 2011 22:10:08 -0700 Subject: [PATCH] initial commit --- Open_Access_Control/Open_Access_Control.pde | 1244 +++++++++++++++++++ README.markdown | 13 + 2 files changed, 1257 insertions(+) create mode 100644 Open_Access_Control/Open_Access_Control.pde create mode 100644 README.markdown diff --git a/Open_Access_Control/Open_Access_Control.pde b/Open_Access_Control/Open_Access_Control.pde new file mode 100644 index 0000000..f37ffe1 --- /dev/null +++ b/Open_Access_Control/Open_Access_Control.pde @@ -0,0 +1,1244 @@ +/* + * Open Source RFID Access Controller + * + * 4/3/2011 v1.32 + * Last build test with Arduino v00.21 + * Arclight - arclight@23.org + * Danozano - danozano@gmail.com + * + * Notice: This is free software and is probably buggy. Use it at + * at your own peril. Use of this software may result in your + * doors being left open, your stuff going missing, or buggery by + * high seas pirates. No warranties are expressed on implied. + * You are warned. + * + * + * For latest downloads, including Eagle CAD files for the hardware, check out + * http://code.google.com/p/open-access-control/downloads/list + * + * Latest update moves strings to PROGMEM to free up memory and adds a + * console password feature. + * + * + * This program interfaces the Arduino to RFID, PIN pad and all + * other input devices using the Wiegand-26 Communications + * Protocol. It is recommended that the keypad inputs be + * opto-isolated in case a malicious user shorts out the + * input device. + * Outputs go to a Darlington relay driver array for door hardware/etc control. + * Analog inputs are used for alarm sensor monitoring. These should be + * isolated as well, since many sensors use +12V. Note that resistors of + * different values can be used on each zone to detect shorting of the sensor + * or wiring. + * + * Version 1.00+ of the hardware implements these features and uses the following pin + * assignments on a standard Arduino Duemilanova or Uno: + * + * Relay outpus on digital pins 6,7,8,9 + * DS1307 Real Time Clock (I2C):A4 (SDA), A5 (SCL) + * Analog pins (for alarm):A0,A1,A2,A3 + * Reader 1: pins 2,3 + * Reader 2: pins 4,5 + * Ethernet: pins 10,11,12,13 (Not connected to the board, reserved for the Ethernet shield) + * + * Quickstart tips: + * Set the console password(PRIVPASSWORD) value to a numeric DEC or HEX value. + * Define the static user list by swiping a tag and copying the value received into the #define values shown below + * Compile and upload the code, then log in via serial console at 57600,8,N,1 + * + */ + +#include // Needed for I2C Connection to the DS1307 date/time chip +#include // Needed for saving to non-voilatile memory on the Arduino. +#include // Allows data to be stored in FLASH instead of RAM + + +#include // Ethernet stuff, comment out if not used. +#include +#include +#include + + +#include // DS1307 RTC Clock/Date/Time chip library +#include // Wiegand 26 reader format libary +#include // Pcint.h implementation, allows for >2 software interupts. + + +/* Static user List - Implemented as an array for testing and access override + */ + +#define DEBUG 2 // Set to 2 for display of raw tag numbers in log files, 1 for only denied, 0 for never. + +#define will 0xabcdef // Name and badge number in HEX. We are not using checksums or site ID, just the whole +#define jeremy 0xabcdef // output string from the reader. +#define jacob 0xabcdef +const long superUserList[] = { will, jeremy, jacob}; // Super user table (cannot be changed by software) + +#define PRIVPASSWORD 0x1234 // Console "priveleged mode" password + +#define DOORDELAY 5000 // How long to open door lock once access is granted. (2500 = 2.5s) +#define SENSORTHRESHOLD 100 // Analog sensor change that will trigger an alarm (0..255) + +#define EEPROM_ALARM 0 // EEPROM address to store alarm triggered state between reboots (0..511) +#define EEPROM_ALARMARMED 1 // EEPROM address to store alarm armed state between reboots +#define EEPROM_ALARMZONES 20 // Starting address to store "normal" analog values for alarm zone sensor reads. +#define KEYPADTIMEOUT 5000 // Timeout for pin pad entry. Users on keypads can enter commands after reader swipe. + +#define EEPROM_FIRSTUSER 24 +#define EEPROM_LASTUSER 1024 +#define NUMUSERS ((EEPROM_LASTUSER - EEPROM_FIRSTUSER)/5) //Define number of internal users (200 for UNO/Duemillanova) + + +#define DOORPIN1 relayPins[0] // Define the pin for electrified door 1 hardware +#define DOORPIN2 relayPins[2] // Define the pin for electrified door 2 hardware +#define ALARMSTROBEPIN relayPins[3] // Define the "non alarm: output pin. Can go to a strobe, small chime, etc +#define ALARMSIRENPIN relayPins[1] // Define the alarm siren pin. This should be a LOUD siren for alarm purposes. + +byte reader1Pins[]={2,3}; // Reader 1 connected to pins 4,5 +byte reader2Pins[]= {4,5}; // Reader2 connected to pins 6,7 + +//byte reader3Pins[]= {10,11}; // Reader3 connected to pins X,Y (Not implemented on v1.x and 2.x Access Control Board) + +const byte analogsensorPins[] = {0,1,2,3}; // Alarm Sensors connected to other analog pins +const byte relayPins[]= {6,7,8,9}; // Relay output pins + +bool door1Locked=true; // Keeps track of whether the doors are supposed to be locked right now +bool door2Locked=true; + +unsigned long door1locktimer=0; // Keep track of when door is supposed to be relocked +unsigned long door2locktimer=0; // after access granted. + +boolean doorChime=false; // Keep track of when door chime last activated +boolean doorClosed=false; // Keep track of when door last closed for exit delay + +unsigned long alarmDelay=0; // Keep track of alarm delay. Used for "delayed activation" or level 2 alarm. +unsigned long alarmSirenTimer=0; // Keep track of how long alarm has gone off + + +unsigned long consolefailTimer=0; // Console password timer for failed logins +byte consoleFail=0; +#define numUsers (sizeof(superUserList)/sizeof(long)) //User access array size (used in later loops/etc) +#define NUMDOORS (sizeof(doorPin)/sizeof(byte)) +#define numAlarmPins (sizeof(analogsensorPins)/sizeof(byte)) + +//Other global variables +byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // Global RTC clock variables. Can be set using DS1307.getDate function. + +byte alarmActivated = EEPROM.read(EEPROM_ALARM); // Read the last alarm state as saved in eeprom. +byte alarmArmed = EEPROM.read(EEPROM_ALARMARMED); // Alarm level variable (0..5, 0==OFF) + +boolean sensor[4]={false}; // Keep track of tripped sensors, do not log again until reset. +unsigned long sensorDelay[2]={0}; // Same as above, but sets a timer for 2 of them. Useful for logging + // motion detector hits for "occupancy check" functions. + +// Enable up to 3 door access readers. +volatile long reader1 = 0; +volatile int reader1Count = 0; +volatile long reader2 = 0; +volatile int reader2Count = 0; +int userMask1=0; +int userMask2=0; +boolean keypadGranted=0; // Variable that is set for authenticated users to use keypad after login + +//volatile long reader3 = 0; // Uncomment if using a third reader. +//volatile int reader3Count = 0; + +unsigned long keypadTime = 0; // Timeout counter for reader with key pad +unsigned long keypadValue=0; + + +// Serial terminal buffer (needs to be global) +char inString[40]={0}; // Size of command buffer (<=128 for Arduino) +byte inCount=0; +boolean privmodeEnabled = false; // Switch for enabling "priveleged" commands + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +byte ip[] = { 172,22,110,177 }; +byte server[] = { 172,22,110,15 }; // hsl-access + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +Client client(server, 80); + +/* Create an instance of the various C++ libraries we are using. + */ + +DS1307 ds1307; // RTC Instance +WIEGAND26 wiegand26; // Wiegand26 (RFID reader serial protocol) library +PCATTACH pcattach; // Software interrupt library + +/* Set up some strings that will live in flash instead of memory. This saves our precious 2k of + * RAM for something else. +*/ + +const prog_uchar rebootMessage[] PROGMEM = {"Access Control System rebooted."}; + +const prog_uchar doorChimeMessage[] PROGMEM = {"Front Door opened."}; +const prog_uchar doorslockedMessage[] PROGMEM = {"All Doors relocked"}; +const prog_uchar alarmtrainMessage[] PROGMEM = {"Alarm Training performed."}; +const prog_uchar privsdeniedMessage[] PROGMEM = {"Access Denied. Priveleged mode is not enabled."}; +const prog_uchar privsenabledMessage[] PROGMEM = {"Priveleged mode enabled."}; +const prog_uchar privsdisabledMessage[] PROGMEM = {"Priveleged mode disabled."}; +const prog_uchar privsAttemptsMessage[] PROGMEM = {"Too many failed attempts. Try again later."}; + +const prog_uchar consolehelpMessage1[] PROGMEM = {"Valid commands are:"}; +const prog_uchar consolehelpMessage2[] PROGMEM = {"(d)ate, (s)show user, (m)odify user "}; +const prog_uchar consolehelpMessage3[] PROGMEM = {"(a)ll user dump,(r)emove_user ,(o)open door "}; +const prog_uchar consolehelpMessage4[] PROGMEM = {"(u)nlock all doors,(l)lock all doors"}; +const prog_uchar consolehelpMessage5[] PROGMEM = {"(1)disarm_alarm, (2)arm_alarm,(3)train_alarm (9)show_status"}; +const prog_uchar consolehelpMessage6[] PROGMEM = {"(e)nable - enable or disable priveleged mode"}; +const prog_uchar consoledefaultMessage[] PROGMEM = {"Invalid command. Press '?' for help."}; + +const prog_uchar statusMessage1[] PROGMEM = {"Alarm armed state (1=armed):"}; +const prog_uchar statusMessage2[] PROGMEM = {"Alarm siren state (1=activated):"}; +const prog_uchar statusMessage3[] PROGMEM = {"Front door open state (0=closed):"}; +const prog_uchar statusMessage4[] PROGMEM = {"Roll up door open state (0=closed):"}; +const prog_uchar statusMessage5[] PROGMEM = {"Door 1 unlocked state(1=locked):"}; +const prog_uchar statusMessage6[] PROGMEM = {"Door 2 unlocked state(1=locked):"}; + + + + +void setup(){ // Runs once at Arduino boot-up + + + Wire.begin(); // start Wire library as I2C-Bus Master + + /* Attach pin change interrupt service routines from the Wiegand RFID readers + */ + pcattach.PCattachInterrupt(reader1Pins[0], callReader1Zero, CHANGE); + pcattach.PCattachInterrupt(reader1Pins[1], callReader1One, CHANGE); + pcattach.PCattachInterrupt(reader2Pins[1], callReader2One, CHANGE); + pcattach.PCattachInterrupt(reader2Pins[0], callReader2Zero, CHANGE); + + //Clear and initialize readers + wiegand26.initReaderOne(); //Set up Reader 1 and clear buffers. + wiegand26.initReaderTwo(); + + + //Initialize output relays + + for(byte i=0; i<4; i++){ + pinMode(relayPins[i], OUTPUT); + digitalWrite(relayPins[i], LOW); // Sets the relay outputs to LOW (relays off) + } + + + ds1307.setDateDs1307(0,49,1,3,7,6,11); + /* Sets the date/time (needed once at commissioning) + + byte second, // 0-59 + byte minute, // 0-59 + byte hour, // 1-23 + byte dayOfWeek, // 1-7 + byte dayOfMonth, // 1-28/29/30/31 + byte month, // 1-12 + byte year); // 0-99 + */ + + + + Serial.begin(57600); // Set up Serial output at 8,N,1,57600bps + logReboot(); + + + // start the Ethernet connection: + Ethernet.begin(mac, ip); + // start the serial library: + //Serial.begin(9600); + // give the Ethernet shield a second to initialize: + //delay(1000); + + + chirpAlarm(1); // Chirp the alarm to show system ready. + +// hardwareTest(100); // IO Pin testing routing (use to check your inputs with hi/lo +(5-12V) sources) + // Also checks relays + + +} +void loop() // Main branch, runs over and over again +{ + if(reader1Count >= 26) + { // When tag presented to reader1 (No keypad on this reader) + logTagPresent(reader1,1); // write log entry to serial port + + Serial.println("connecting..."); + + // if you get a connection, report back via serial: + if (client.connect()) + { + Serial.println("connected"); + + Serial.print("GET /~access/access?device=laser&id="); + Serial.print(reader1, HEX); + Serial.println(" HTTP/1.0"); + Serial.println(); + + client.print("GET /~access/access?device=laser&id="); + client.print(reader1, HEX); + client.println(" HTTP/1.0"); + client.println(); + } + else + { + // kf you didn't get a connection to the server: + Serial.println("connection failed"); + } + + wiegand26.initReaderOne(); // Reset for next tag scan + } + + // if there are incoming bytes available + // from the server, read them and print them: + String httpresponse = ""; + String username = ""; + + while (client.available()) { + httpresponse += (char)client.read(); + } + + if(httpresponse.length()>0) { + Serial.println("Response: "); + int c = httpresponse.indexOf('$'); + + Serial.println(httpresponse.substring(c+1)); + + username = httpresponse.substring(c+1); + httpresponse = ""; + + Serial.println("End Response"); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + client.stop(); + } +} // End of loop() + + +void runCommand(long command) { // Run any commands entered at the pin pad. + + switch(command) { + + + case 0x1: + { // If command = 1, deactivate alarm + alarmState(0); // Set global alarm level variable + armAlarm(0); + chirpAlarm(1); + break; + } + + case 0x2: + { // If command =2, activate alarm with delay. + + doorUnlock(1); // Set global alarm level variable + door1Locked=false; + doorClosed=false; // 200 chirps = ~30 seconds delay + + if((pollAlarm(3) == 0) && (pollAlarm(2) == 0)) { // Do not arm the alarm if doors are open + + for(byte i=0; i<30; i++) { + if((pollAlarm(3) !=0) && doorClosed==false) { // Set door to be unlocked until alarm timeout or user exits + lockall(); + doorClosed=true; + } + digitalWrite(ALARMSTROBEPIN, HIGH); + delay(500); + digitalWrite(ALARMSTROBEPIN, LOW); + delay(500); + } + chirpAlarm(2); + armAlarm(1); + lockall(); // Lock all doors on exit + } + else { // Beep the alarm once and exit if attempt made to arm alarm with doors open + digitalWrite(ALARMSTROBEPIN, HIGH); + delay(500); + digitalWrite(ALARMSTROBEPIN, LOW); + delay(500); + lockall(); // Lock all doors anyway + } + break; + } + + case 0x3: + { + + doorLock(1); // Set door 2 to stay unlocked, and door 1 to be locked + doorUnlock(2); + door1Locked=true; + door2Locked=false; + chirpAlarm(3); + break; + } + + case 0x4: // Set doors to remain open + { + armAlarm(4); + doorUnlock(1); + doorUnlock(2); + door1Locked=false; + door2Locked=false; + chirpAlarm(4); + break; + } + case 0x5: // Relock all doors + { + lockall(); + chirpAlarm(5); + break; + } + + case 0x911: + { + chirpAlarm(9); // Emergency + armAlarm(1); + alarmState(1); + break; + } + + case 0x20: + { // If command = 20, do nothing + break; + } + default: + { + break; + } + } + + +} + + +/* Alarm System Functions - Modify these as needed for your application. + Sensor zones may be polled with digital or analog pins. Unique reader2 + resistors can be used to check more zones from the analog pins. + */ + +void alarmState(byte alarmLevel) { //Changes the alarm status based on this flow + + logalarmState(alarmLevel); + switch (alarmLevel) { + case 0: + { // If alarmLevel == 0 turn off alarm. + digitalWrite(ALARMSIRENPIN, LOW); + digitalWrite(ALARMSTROBEPIN, LOW); + alarmActivated = alarmLevel; //Set global alarm level variable + break; + } + case 1: + { + digitalWrite(ALARMSIRENPIN, HIGH); // If alarmLevel == 1 turn on strobe lights and siren + // digitalWrite(ALARMSTROBEPIN, HIGH); // Optionally activate yoru strobe/chome + alarmSirenTimer=millis(); + alarmActivated = alarmLevel; //Set global alarm level variable + logalarmTriggered(); + + break; + } + + case 2: + { + digitalWrite(ALARMSTROBEPIN, HIGH); + alarmActivated = alarmLevel; + break; + } + + case 3: + { + + alarmActivated = alarmLevel; + break; + } + /* + case 4: { + vaporize_intruders(STUN); + break; + } + + case 5: { + vaporize_intruders(MAIM); + } etc. etc. etc. + break; + */ + + default: + { // Exceptional cases kill alarm outputs + digitalWrite(ALARMSIRENPIN, LOW); // Turn off siren and strobe + // digitalWrite(ALARMSTROBEPIN, LOW); + break; + } + + + + + } + + if(alarmActivated != EEPROM.read(EEPROM_ALARM)){ // Update eeprom value + EEPROM.write(EEPROM_ALARM,alarmActivated); + } + +} //End of alarmState() + +void chirpAlarm(byte chirps){ // Chirp the siren pin or strobe to indicate events. + for(byte i=0; iSENSORTHRESHOLD){ + return 1; + + } + else return 0; +} + +void trainAlarm(){ // Train the system about the default states of the alarm pins. + armAlarm(0); // Disarm alarm first + alarmState(0); + + int temp[5]={0}; + int avg; + + for(int i=0; i NUMUSERS)) { // Do not write to invalid EEPROM addresses. + + Serial.print("Invalid user modify attempted."); + } + else + { + + + + + EEPROM_buffer[0] = byte(tagNumber & 0xFFF); // Fill the buffer with the values to write to bytes 0..4 + EEPROM_buffer[1] = byte(tagNumber >> 8); + EEPROM_buffer[2] = byte(tagNumber >> 16); + EEPROM_buffer[3] = byte(tagNumber >> 24); + EEPROM_buffer[4] = byte(userMask); + + + + for(int i=0; i<5; i++){ + EEPROM.write((offset+i), (EEPROM_buffer[i])); // Store the resulting value in 5 bytes of EEPROM. + + } + + Serial.print("User "); + Serial.print(userNum,DEC); + Serial.println(" successfully modified"); + + + } +} + +void deleteUser(int userNum) // Deletes a user from the local database. +{ // Users number 0..NUMUSERS + int offset = (EEPROM_FIRSTUSER+(userNum*5)); // Find the offset to write this user to + + logDate(); + + if((userNum <0) || (userNum > NUMUSERS)) { // Do not write to invalid EEPROM addresses. + + Serial.print("Invalid user delete attempted."); + } + else + { + + + + for(int i=0; i<5; i++){ + EEPROM.write((offset+i), 0xFF); // Store the resulting value in 5 bytes of EEPROM. + // Starting at offset. + + + + } + + Serial.print("User deleted at position "); + Serial.println(userNum); + + } + +} + + + +int checkUser(unsigned long tagNumber) // Check if a particular tag exists in the local database. Returns userMask if found. +{ // Users number 0..NUMUSERS + // Find the first offset to check + + unsigned long EEPROM_buffer=0; // Buffer for recreating tagNumber from the 4 stored bytes. + int found=-1; + + logDate(); + + + for(int i=EEPROM_FIRSTUSER; i<=(EEPROM_LASTUSER-5); i=i+5){ + + + EEPROM_buffer=0; + EEPROM_buffer=(EEPROM.read(i+3)); + EEPROM_buffer= EEPROM_buffer<<8; + EEPROM_buffer=(EEPROM_buffer ^ EEPROM.read(i+2)); + EEPROM_buffer= EEPROM_buffer<<8; + EEPROM_buffer=(EEPROM_buffer ^ EEPROM.read(i+1)); + EEPROM_buffer= EEPROM_buffer<<8; + EEPROM_buffer=(EEPROM_buffer ^ EEPROM.read(i)); + + + if((EEPROM_buffer == tagNumber) && (tagNumber !=0xFFFFFFFF) && (tagNumber !=0x0)) { // Return a not found on blank (0xFFFFFFFF) entries + Serial.print("User "); + Serial.print(((i-EEPROM_FIRSTUSER)/5),DEC); + Serial.println(" authenticated."); + found = EEPROM.read(i+4); + return found; + } + + } + Serial.println("User not found"); + delay(1000); // Delay to prevent brute-force attacks on reader + return found; +} + + + + + +void dumpUser(byte usernum) // Return information ona particular entry in the local DB +{ // Users number 0..NUMUSERS + + + unsigned long EEPROM_buffer=0; // Buffer for recreating tagNumber from the 4 stored bytes. + + + if((0<=usernum) && (usernum <=199)){ + + int i=usernum*5+EEPROM_FIRSTUSER; + + EEPROM_buffer=0; + EEPROM_buffer=(EEPROM.read(i+3)); + EEPROM_buffer= EEPROM_buffer<<8; + EEPROM_buffer=(EEPROM_buffer ^ EEPROM.read(i+2)); + EEPROM_buffer= EEPROM_buffer<<8; + EEPROM_buffer=(EEPROM_buffer ^ EEPROM.read(i+1)); + EEPROM_buffer= EEPROM_buffer<<8; + EEPROM_buffer=(EEPROM_buffer ^ EEPROM.read(i)); + + + + Serial.print(((i-EEPROM_FIRSTUSER)/5),DEC); + Serial.print("\t"); + Serial.print(EEPROM.read(i+4),DEC); + Serial.print("\t"); + + if(DEBUG==2){ + Serial.println(EEPROM_buffer,HEX); + } + else { + if(EEPROM_buffer != 0xFFFFFFFF) { + Serial.println("********"); + } + } + + } + else Serial.println("Bad user number!"); +} + + +/* Displays a serial terminal menu system for + * user management and other tasks + */ + +void readCommand() { + + +byte stringSize=(sizeof(inString)/sizeof(char)); +char cmdString[4][9]; // Size of commands (4=number of items to parse, 10 = max length of each) + + +byte j=0; // Counters +byte k=0; +char cmd=0; + + +char ch; + + if (Serial.available()) { // Check if user entered a command this round + ch = Serial.read(); + if( ch == '\r' || inCount >=stringSize-1) { // Check if this is the terminating carriage return + inString[inCount] = 0; + inCount=0; + } + else{ + (inString[inCount++] = ch); } + //Serial.print(ch); // Turns echo on or off + + +if(inCount==0) { + for(byte i=0; i=5) && (millis()-consolefailTimer<300000)) // Do not allow priv mode if more than 5 failed logins in 5 minute + { + PROGMEMprintln(privsAttemptsMessage); + break; + } + if (strtoul(cmdString[1],NULL,16) == PRIVPASSWORD) + { + consoleFail=0; + PROGMEMprintln(privsenabledMessage); + privmodeEnabled=true; + } + else { + PROGMEMprintln(privsdisabledMessage); + privmodeEnabled=false; + if(consoleFail==0) { // Set the timeout for failed logins + consolefailTimer=millis(); + } + consoleFail++; // Increment the login failure counter + } + + break; + + } + +//privmodeEnabled=true; //Debugging statement + + + case 'a': { // List whole user database + if(privmodeEnabled==true) { + logDate(); + Serial.println("User dump started."); + Serial.print("UserNum:"); + Serial.print(" "); + Serial.print("Usermask:"); + Serial.print(" "); + Serial.println("TagNum:"); + + for(int i=0; i<(NUMUSERS); i++){ + dumpUser(i); + //Serial.println(); // commented out due to dumpUser now always printing a line -WB 7-7-2011 + } + } + else{logprivFail();} + break; + } + + case 's': { // List user + if(privmodeEnabled==true) { + Serial.print("UserNum:"); + Serial.print(" "); + Serial.print("Usermask:"); + Serial.print(" "); + Serial.println("TagNum:"); + dumpUser(atoi(cmdString[1])); + //Serial.println(); // commented out due to dumpUser always printing a line -WB 7-7-2011 + } + else{logprivFail();} + break; + } + + case 'd': { // Display current time + logDate(); + Serial.println(); + break; + } + + case '1': { // Deactivate alarm + if(privmodeEnabled==true) { + armAlarm(0); + alarmState(0); + chirpAlarm(1); + } + else{logprivFail();} + break; + } + case '2': { // Activate alarm with delay. + chirpAlarm(20); // 200 chirps = ~30 seconds delay + armAlarm(1); + break; + } + + case 'u': { + if(privmodeEnabled==true) { + alarmState(0); // Set to door chime only/open doors + armAlarm(4); + doorUnlock(1); + doorUnlock(2); + door1Locked=false; + door2Locked=false; + chirpAlarm(3); + } + + else{logprivFail();} + break; + } + case 'l': { // Lock all doors + lockall(); + chirpAlarm(1); + break; + } + + case '3': { // Train alarm sensors + if(privmodeEnabled==true) { + trainAlarm(); + } + else{logprivFail();} + break; + } + case '9': { // Show site status + PROGMEMprint(statusMessage1); + Serial.println(alarmArmed,DEC); + PROGMEMprint(statusMessage2); + Serial.println(alarmActivated,DEC); + PROGMEMprint(statusMessage3); + Serial.println(pollAlarm(3),DEC); + PROGMEMprint(statusMessage4); + Serial.println(pollAlarm(2),DEC); + PROGMEMprint(statusMessage5); + Serial.println(door1Locked); + PROGMEMprint(statusMessage6); + Serial.println(door2Locked); + break; + } + + case 'o': { + if(privmodeEnabled==true) { + if(atoi(cmdString[1]) == 1){ + alarmState(0); // Set to door chime only/open doors + armAlarm(4); + doorUnlock(1); // Open the door specified + door1locktimer=millis(); + break; + } + if(atoi(cmdString[1]) == 2){ + alarmState(0); // Set to door chime only/open doors + armAlarm(4); + doorUnlock(2); + door2locktimer=millis(); + break; + } + Serial.print("Invalid door number!"); + } + + else{logprivFail();} + break; + } + + case 'r': { // Remove a user + if(privmodeEnabled==true) { + dumpUser(atoi(cmdString[1])); + deleteUser(atoi(cmdString[1])); + } + else{logprivFail();} + break; + } + + case 'm': { // Add/change a user + if(privmodeEnabled==true) { + dumpUser(atoi(cmdString[1])); + addUser(atoi(cmdString[1]), atoi(cmdString[2]), strtoul(cmdString[3],NULL,16)); + dumpUser(atoi(cmdString[1])); + } + else{logprivFail();} + + break; + } + + case '?': { // Display help menu + PROGMEMprintln(consolehelpMessage1); + PROGMEMprintln(consolehelpMessage2); + PROGMEMprintln(consolehelpMessage3); + PROGMEMprintln(consolehelpMessage4); + PROGMEMprintln(consolehelpMessage5); + PROGMEMprintln(consolehelpMessage6); + break; + } + + default: + PROGMEMprintln(consoledefaultMessage); + break; + } + + } // End of 'if' statement for Serial.available + } // End of 'if' for string finished +} // End of function + + + + +/* Wrapper functions for interrupt attachment + Could be cleaned up in library? + */ +void callReader1Zero(){wiegand26.reader1Zero();} +void callReader1One(){wiegand26.reader1One();} +void callReader2Zero(){wiegand26.reader2Zero();} +void callReader2One(){wiegand26.reader2One();} +void callReader3Zero(){wiegand26.reader3Zero();} +void callReader3One(){wiegand26.reader3One();} + + diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..789ad6a --- /dev/null +++ b/README.markdown @@ -0,0 +1,13 @@ +Open Access Control - Arduino Ethernet +====================================== + +This is a stripped-down version of the 23b hackerspace's Open Access Control system, intended for embedded use with an RFID reader and Ethernet shield for authenticating Wiegand RFID cards with a webservice. + +For more info, contact @willbradley on Twitter or will@heatsynclabs.org + +Structure +--------- + +* This folder + * Open Access Control folder + * Open Access Control.pde (Arduino code -- requires the Wiegand26 library to be installed in your IDE.)