Commits

Anonymous committed 3d46fbd

initial commit

  • Participants

Comments (0)

Files changed (3)

File interrupt_support.c

+/*
+ * an extension to the interrupt support for arduino.
+ * add pin change interrupts to the external interrupts, giving a way
+ * for users to have interrupts drive off of any pin.
+ * Refer to avr-gcc header files, arduino source and atmega datasheet.
+ */
+
+/*
+ * Theory: all IO pins on Atmega168 & Atmega328 are covered by Pin Change Interrupts.
+ * The PCINT corresponding to the pin must be enabled and masked, and
+ * an ISR routine provided.  Since PCINTs are per port, not per pin, the ISR
+ * must use some logic to actually implement a per-pin interrupt service.
+ */
+
+/* Pin to interrupt map:
+ * D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
+ * D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
+ * A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
+ */
+#ifndef interrupt_support_h
+#define interrupt_support_h
+
+#include "WProgram.h"
+#include "interrupt_support.h"
+#include "pins_arduino.h"
+
+volatile uint8_t *port_to_pcmask[] = {
+  &PCMSK0,
+  &PCMSK1,
+  &PCMSK2
+};  
+
+typedef void (*voidFuncPtr)(void);
+
+volatile static voidFuncPtr PCintFunc[24] = {
+  NULL };
+
+volatile static uint8_t PCintLast[3];
+
+/*
+ * attach an interrupt to a specific pin using pin change interrupts.
+ * First version only supports CHANGE mode.
+ */
+void PCattachInterrupt(uint8_t pin, void (*userFunc)(void), int mode) {
+  uint8_t bit = digitalPinToBitMask(pin);
+  uint8_t port = digitalPinToPort(pin);
+  uint8_t slot;
+  volatile uint8_t *pcmask;
+
+  if (mode != CHANGE) {
+    return;
+  }
+  // map pin to PCIR register
+  if (port == NOT_A_PORT) {
+    return;
+  }
+  else {
+    port -= 2;
+    pcmask = port_to_pcmask[port];
+  }
+  slot = port * 8 + (pin % 8);
+  PCintFunc[slot] = userFunc;
+  // set the mask
+  *pcmask |= bit;
+  // enable the interrupt
+  PCICR |= 0x01 << port;
+}
+
+void PCdetachInterrupt(uint8_t pin) {
+  uint8_t bit = digitalPinToBitMask(pin);
+  uint8_t port = digitalPinToPort(pin);
+  volatile uint8_t *pcmask;
+
+  // map pin to PCIR register
+  if (port == NOT_A_PORT) {
+    return;
+  }
+  else {
+    port -= 2;
+    pcmask = port_to_pcmask[port];
+  }
+
+  // disable the mask.
+  *pcmask &= ~bit;
+  // if that's the last one, disable the interrupt.
+  if (*pcmask == 0) {
+    PCICR &= ~(0x01 << port);
+  }
+}
+
+// common code for isr handler. "port" is the PCINT number.
+// there isn't really a good way to back-map ports and masks to pins.
+static void PCint(uint8_t port) {
+  uint8_t bit;
+  uint8_t curr;
+  uint8_t mask;
+  uint8_t pin;
+
+  // get the pin states for the indicated port.
+  curr = *portInputRegister(port+2);
+  mask = curr ^ PCintLast[port];
+  PCintLast[port] = curr;
+  // mask is pins that have changed. screen out non pcint pins.
+  if ((mask &= *port_to_pcmask[port]) == 0) {
+    return;
+  }
+  // mask is pcint pins that have changed.
+  uint8_t i;
+  for (i=0; i < 8; i++) {
+    bit = 0x01 << i;
+    if (bit & mask) {
+      pin = port * 8 + i;
+      if (PCintFunc[pin] != NULL) {
+        PCintFunc[pin]();
+      }
+    }
+  }
+}
+
+SIGNAL(PCINT0_vect) {
+  PCint(0);
+}
+SIGNAL(PCINT1_vect) {
+  PCint(1);
+}
+SIGNAL(PCINT2_vect) {
+  PCint(2);
+}
+
+void resetInterruptPin(int i)
+{
+  // the interrupt in the Atmel processor mises out the first negitave pulse as the inputs are already high,
+  // so this gives a pulse to each reader input line to get the interrupts working properly.
+  // Then clear out the reader variables.
+  // The readers are open collector sitting normally at a one so this is OK
+  pinMode(i, OUTPUT);
+  digitalWrite(i, HIGH); // enable internal pull up causing a one
+  digitalWrite(i, LOW); // disable internal pull up causing zero and thus an interrupt
+  pinMode(i, INPUT);
+  digitalWrite(i, HIGH); // enable internal pull up
+}
+#endif
+

File interrupt_support.h

+/*
+ * an extension to the interrupt support for arduino.
+ * add pin change interrupts to the external interrupts, giving a way
+ * for users to have interrupts drive off of any pin.
+ * Refer to avr-gcc header files, arduino source and atmega datasheet.
+ */
+ 
+#ifdef __cplusplus
+extern "C" {
+#endif
+void PCattachInterrupt(uint8_t pin, void (*userFunc)(void), int mode);
+void resetInterruptPin(int i);
+#ifdef __cplusplus
+}
+#endif

File wiegand_card_reader_v0.pde

+/*
+ * ©2010 Lokkju Brennr
+ * RFID readers outputing 26-XX bit Wiegand code to pins, truncated to 32 bits and hashed :-
+ * READER    WIRE COLOR PIN# DESCRIPTION CABLE COLOR
+ * --------- ---------- ---- ----------- -----------
+ * Reader A  Orange     2    Green LED   BLUE
+ * Reader A  White      3    DATA1       GREEN/WHITE
+ * Reader A  Green      4    DATA0       GREEN
+ * Reader A  Red             +12v        ORANGE
+ * Reader A  Black           GND         BROWN
+ * Interrupt service routine gathers Wiegand pulses (zero or one) until a minimum of 32 have been recieved
+ * Then a sting is sent to processing
+ */
+
+#include <EEPROM.h>
+
+#include "interrupt_support.h"
+
+#define BUFFERSIZE 20
+#define MAX_NO_CARDS 200
+#define READER_A_DATA0 4
+#define READER_A_DATA1 3
+#define READER_A_GREEN 2
+#define OPEN_DOOR_PIN1 5
+
+#define waitingLED 6
+#define successLED 13
+#define failureLED 8
+
+int toggleState = 0;    // state of the toggling LED
+long toggleTime = 0;    // delay time of the toggling LED
+byte tag[4];
+char inBytes[BUFFERSIZE]; //Buffer for serial in messages
+
+// has to be a long - ints are 16 bits on this platform!
+volatile long reader1 = 0;
+volatile int reader1Count = 0;
+int serialAvail = 0;
+int serialIndex = 0;
+
+void reader1One(void) {
+  if(reader1Count < 32 && digitalRead(READER_A_DATA1) == LOW){
+    reader1Count++;
+    reader1 = reader1 << 1;
+    reader1 |= 1;
+  }
+}
+
+void reader1Zero(void) {
+  if(reader1Count < 32 && digitalRead(READER_A_DATA0) == LOW){
+    reader1Count++;
+    reader1 = reader1 << 1;
+  }
+}
+
+void setup()
+{
+  Serial.begin(9600);
+  // Attach pin change interrupt service routines from the Wiegand RFID readers
+  PCattachInterrupt(READER_A_DATA1, reader1One, CHANGE);
+  PCattachInterrupt(READER_A_DATA0, reader1Zero, CHANGE);
+
+  delay(10);
+  resetInterruptPin(3);
+  resetInterruptPin(4);
+  pinMode(OPEN_DOOR_PIN1, OUTPUT);
+  digitalWrite(OPEN_DOOR_PIN1, LOW);
+  pinMode(READER_A_GREEN, OUTPUT);
+  digitalWrite(READER_A_GREEN, HIGH);
+  digitalWrite(13, HIGH);
+  delay(10);
+  // put the reader input variables to zero
+  reader1 = 0;
+  reader1Count = 0;
+  blink(13,200,3);
+  printHelp();
+  delay(200);
+}
+void printHelp() {
+  Serial.println("ARDUINO SECURITY v0.1");
+  Serial.println(" all commands end with ;");
+  Serial.println("h - print this help");
+  Serial.println("n - add next card to database");
+  Serial.println("r - delete next card from database");
+  Serial.println("p - print database");
+  Serial.println("c - clear entire database");
+  Serial.println("d [x] - delete tag at provided index from database");
+  Serial.println("o - open door");
+}
+void loop() {
+  readSerialInput();
+  seekKnownTags();
+  delay(200);
+} 
+
+// erase the entire EEPROM memory storage:
+void eraseEEPROM(){
+  for(int i = 0; i < 1024; i++){
+    EEPROM.write(i, 0);
+  }
+}
+
+// writes tag number in a location:
+void writeTag(int startingAddress, byte byte0, byte byte1, byte byte2, byte byte3){
+  EEPROM.write( startingAddress*5, byte(1));
+  EEPROM.write(startingAddress*5+1, byte0);
+  EEPROM.write(startingAddress*5+2, byte1);
+  EEPROM.write(startingAddress*5+3, byte2);
+  EEPROM.write(startingAddress*5+4, byte3);
+}
+// delete tag from a specified location
+void deleteTag(int startingAddress){
+  EEPROM.write( startingAddress*5, byte(0));
+  EEPROM.write(startingAddress*5+1, byte(0));
+  EEPROM.write(startingAddress*5+2, byte(0));
+  EEPROM.write(startingAddress*5+3, byte(0));
+  EEPROM.write(startingAddress*5+4, byte(0));
+}
+// find the first empty entry in the database:
+int findEmptyTag(){
+  for (int startingAddress = 0; startingAddress< MAX_NO_CARDS; startingAddress++){
+    byte value = EEPROM.read(startingAddress*5);
+    if (value == byte(0)) {
+      return(startingAddress);
+    }
+  }
+  return(200);
+}
+
+// print the entire database
+void printTags(){
+  for (int thisTag = 0; thisTag< MAX_NO_CARDS; thisTag++){
+    printOneTag(thisTag);
+  }
+}
+
+// print a single tag given the tag's address:
+void printOneTag(int address) {
+  Serial.print(address);
+  Serial.print(":");
+  for (int offset = 1; offset < 5; offset++) {
+    int thisByte = int(EEPROM.read(address*5+offset));
+    // if the byte is less than 16, i.e. only one hex character
+    // add a leading 0:
+    if (thisByte < 0x10) {
+      Serial.print("0");
+    }
+    // print the value:
+    Serial.print(thisByte,HEX);
+  }
+  // add a final linefeed and carriage return:
+  Serial.println();
+}
+
+//lookup tag in the database:
+int lookupTag(byte byte0, byte byte1, byte byte2, byte byte3){
+  for (int thisCard = 0; thisCard< MAX_NO_CARDS; thisCard++){
+    byte value = EEPROM.read(thisCard*5);
+    if (value != byte(0)){                    //it is a valid tag
+      //see if all four bytes are the same as the ones we're looking for
+      if(byte0 == byte(0) && byte1 == byte(0) && byte2 == byte(0) && byte1 == byte(0)){
+        return 200;
+      }
+      if(byte0 == byte(255) && byte1 == byte(255) && byte2 == byte(255) && byte1 == byte(255)){
+        return 200;
+      }
+      if(byte0 == EEPROM.read(thisCard*5+1) && byte1 == EEPROM.read(thisCard*5+2) && byte2 == EEPROM.read(thisCard*5+3) && byte3 == EEPROM.read(thisCard*5+4)) {
+        return(thisCard);
+      }
+    }
+  }
+  // if you don't find the tag, return 200;
+  return(200);
+}
+
+int getTag(){
+  if(reader1Count >= 20){
+    delay(100);
+    long ret = hash(reader1);
+    reader1 = 0;
+    reader1Count = 0;
+    tag[0] = (byte)(ret >> 24);
+    tag[1] = (byte)(ret >> 16);
+    tag[2] = (byte)(ret >> 8);
+    tag[3] = (byte)ret;
+    return 1;
+  } 
+  else {
+    return 0;
+  }
+}
+
+void cycleDoor() {
+    digitalWrite(OPEN_DOOR_PIN1, HIGH);
+    delay(500);
+    digitalWrite(OPEN_DOOR_PIN1, LOW);  
+}
+void seekNewTag() {
+  Serial.println("Next tag will be added to database");
+  Serial.println("Waiting for card");
+  while(getTag() == 0){
+    // wait for tag
+    if (millis() - toggleTime > 1000) {
+      toggle(waitingLED);
+      toggleTime  = millis();
+    }
+    // unless you get a byte of serial data,
+    if (Serial. available()) {
+      // break out of the while loop
+      // and out of the seekNewTag() method:
+      return;
+    }
+  }
+
+  // look it up in the database:
+  int tagToCheck = lookupTag(tag[0], tag[1], tag[2], tag[3]);      
+
+  if (tagToCheck != 200){
+    Serial.println("That tag is already stored");
+    printOneTag(tagToCheck);
+  }
+  else {
+    int emptyTagLocation = findEmptyTag();
+    if (emptyTagLocation != 200){
+      writeTag(emptyTagLocation, tag[0], tag[1], tag[2], tag[3]);
+      Serial.println("That tag is new, saving...");
+      printOneTag(emptyTagLocation);
+      blink(successLED, 100, 1);
+    }
+    else {
+      Serial.println("Maximum number of cards stored");
+      blink(failureLED, 50, 10);
+    }
+  }
+}
+
+
+void seekAndDeleteTag() {
+  Serial.println("Deleting the next card");
+  Serial.println("Waiting for card");
+  while(getTag() == 0){
+    // do nothing; wait for tag
+    // unless you get a byte of serial data,
+    if (Serial. available()) {
+      // break out of the while loop
+      // and out of the method:
+      return;
+    }
+  }
+  int tagToDelete = lookupTag(tag[0], tag[1], tag[2], tag[3]);
+  if (tagToDelete == 200){
+    Serial.print("That tag is not stored");
+  }
+  else {
+    deleteTag(tagToDelete);
+  }
+}
+
+void toggle(int thisLED) {
+  toggleState = !toggleState;
+  digitalWrite(thisLED, toggleState);
+}
+
+void blink(int thisLED, int interval, int count) {
+  for (int i = 0; i < count; i++) {
+    digitalWrite(thisLED, LOW);
+    delay(interval/2);
+    digitalWrite(thisLED, HIGH);
+    delay(interval/2);
+  }
+}
+
+void seekKnownTags() {
+  Serial.println("Waiting for card");
+  while(getTag() == 0){
+    // wait for tag
+    if (millis() - toggleTime > 1000) {
+      toggle(waitingLED);
+      toggleTime  = millis();
+    }
+    // unless you get a byte of serial data,
+    if (Serial.available()) {
+      // break out of the while loop
+      // and out of the seekKnownTag() method:
+      return;
+    }
+  }
+
+  // look it up in the database:
+  int tagToCheck = lookupTag(tag[0], tag[1], tag[2], tag[3]);      
+
+  if (tagToCheck != 200){
+    digitalWrite(READER_A_GREEN,LOW);
+    cycleDoor();
+    printOneTag(tagToCheck);
+    Serial.println("OPEN SESAME!!!");
+    blink(successLED,500,2);
+    digitalWrite(READER_A_GREEN,HIGH);
+  }
+  else {
+    blink(READER_A_GREEN, 50, 10);
+    Serial.print("INVALID CARD!!!");
+    printOneTag(tagToCheck);
+    blink(successLED, 50, 10);
+  }
+}
+long hash( long a)
+{
+  a = (a+0x7ed55d16) + (a<<12);
+  a = (a^0xc761c23c) ^ (a>>19);
+  a = (a+0x165667b1) + (a<<5);
+  a = (a+0xd3a2646c) ^ (a<<9);
+  a = (a+0xfd7046c5) + (a<<3);
+  a = (a^0xb55a4f09) ^ (a>>16);
+  return a;
+}
+
+// Reads serial input if available and parses command when full command has been sent. 
+void readSerialInput() {
+  int si = serialIndex;
+  serialAvail = Serial.available();  
+  for (int i = 0; i < serialAvail; i++) {
+    char c = Serial.read();
+    if(si + i >= BUFFERSIZE) {
+      // don't want to overflow the buffer!
+      serialIndex = 0;
+      for (int i= 0; i < BUFFERSIZE; i++) { 
+        inBytes[i] = '\0';
+      }
+      Serial.flush();
+      return;
+    }
+    //Store into buffer.
+    inBytes[i + si] = c;
+    //Check for command end. 
+    if (inBytes[i + si] == ';') {
+      // print the buffer  
+      inBytes[i + si] = '\0'; //end of string char
+      parseCommand(inBytes); 
+      Serial.flush();
+      serialIndex = 0;
+      for (int i= 0; i < BUFFERSIZE; i++) { 
+        inBytes[i] = '\0';
+      }
+    } 
+    else {
+      //expecting more of the command to come later.
+      serialIndex += 1;
+    }
+  }  
+}
+
+// Cleans and parses the command
+void parseCommand(char* com) {
+  if (com[0] == '\0') { 
+    return; 
+  } //bit of error checking
+  int start = 0;
+  //get start of command
+  while (com[start] != '<'){
+    start++; 
+    if (com[start] == '\0') {
+      //its not there. Must be old version
+      start = -1;
+      break;
+    }
+  }
+  start++;
+  //Shift to beginning
+  int i = 0;
+  while (com[i + start - 1] != '\0') {
+    com[i] = com[start + i];
+    i++; 
+  } 
+  performCommand(com);
+}
+
+void serialReply(char* sensorname, char* tmpmsg) {
+  Serial.print(sensorname);
+  Serial.print(":");
+  Serial.println(tmpmsg); // Send the message back out the serial line
+  //Wait for the serial debugger to shut up
+  delay(200); //this is a magic number
+  Serial.flush(); //clears all incoming data
+}
+
+void performCommand(char* com) {
+  if (strcmp(com, "n") == 0) { // store the next tag number
+    seekNewTag();
+  } 
+  else if (strcmp(com,"c") == 0) { // erase entire database 
+    Serial.println("i Deleting entire database");
+    eraseEEPROM();    // if user enters 'c' then 
+    serialReply("i","Database deleted");
+  } 
+  else if (com[0] == 'd' && com[1] == ' ') { // delete the specified tag number "d 20"
+    serialReply("i","Deleting indicated tag from database");
+    int value;
+    Serial.println(com);
+    sscanf(com,"d %d",&value); // Parse the input into multiple values
+    Serial.println(value);
+    deleteTag(value);
+  } 
+  else if (strcmp(com,"r") == 0) { // delete the next tag
+    seekAndDeleteTag();
+  } 
+  else if (strcmp(com,"p") == 0) { // print the database
+    printTags();
+  } 
+  else if (strcmp(com,"h") == 0) { // print help
+    printHelp();
+  }
+  else if (strcmp(com,"o") == 0) { //cycle door
+    cycleDoor();
+  }
+  else { 
+    Serial.print("e ");
+    Serial.println(com); // Echo unknown command back
+  }
+}
+
+