diff --git a/brmdoor.pde b/brmdoor.pde new file mode 100644 index 0000000..57508c3 --- /dev/null +++ b/brmdoor.pde @@ -0,0 +1,181 @@ +// get file cardids.h from the Council section in our wiki! + +#define MUSIC 1 + +// if you are running Arduino0018 or older, comment the SPI.h include +#include +#include + +// pins +const int doorLock = 5; +const int soundPin = 9; +const int statusLed = 8; +const int statusBtn = 7; +const int videoLed = 6; +const int videoBtn = 3; + +int statusState = 0; +int videoState = 0; + +// cardId is the same as you can see in CARD telnet message +struct ACLdata { + byte cardId[7]; + char *nick; +} ACL[] = { +// the following include file contains lines like +// { {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE}, "username" }, +#include "cardids.h" +}; + +// run telnet server +Server server(23); + +#if MUSIC + +#include "pitches.h" + +int melody_nak[] = { NOTE_G5, NOTE_G5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5}; +int noteDurations_nak[] = { 330, 330, 330, 250, 120, 330, 250, 120, 500 }; + +int melody_ack[] = { NOTE_D6, NOTE_A6, NOTE_C7, NOTE_A6 }; +int noteDurations_ack[] = { 120, 500, 120, 500 }; + +void toneManual(int pin, int frequency, int duration) +{ + unsigned long period = 1000000/frequency; + unsigned long length; + boolean state = false; + for (length = 0; length < (long) duration * 1000; length += period) { + state = !state; + digitalWrite(pin, state); + /* The 50uS correspond to the time the rest of the loop body takes. + * It seems about right, but has not been tuned precisely for + * a 16MHz ATMega. */ + delayMicroseconds(period - 50); + //server.print(pin, DEC); server.print(state, DEC); server.write(" "); server.print(period); server.write(" "); server.print(length); server.write("\n"); + } +} + +void playMelody(int *melody, int *noteDurations, int notes) +{ + int i; + for (i = 0; i < notes; i++) { + // server.print(melody[i]); server.write(" "); server.print(noteDurations[i]); server.write("\n"); + toneManual(soundPin, melody[i], noteDurations[i]); + + delay(noteDurations[i] * 6/10); + } +} + +void playMelodyAck() +{ playMelody(melody_ack, noteDurations_ack, sizeof(melody_ack)/sizeof(melody_ack[0])); } +void playMelodyNak() +{ playMelody(melody_nak, noteDurations_nak, sizeof(melody_nak)/sizeof(melody_nak[0])); } + +#else + +void playMelodyAck() +{} +void playMelodyNak() +{} + +#endif + +// opens door for "ms" milliseconds +void openDoorForTime(int ms) +{ + digitalWrite(doorLock, HIGH); + playMelodyAck(); + delay(ms); + digitalWrite(doorLock, LOW); +} + +void readCard() +{ + byte RequestCardStatus[] = { 0xAA, 0x00, 0x03, 0x25, 0x26, 0x00, 0x00, 0xBB }; + byte NoCardResponse[] = { 0xAA, 0x00, 0x02, 0x01, 0x83, 0x80, 0xBB }; + byte buf[16]; + + // write query to serial + Serial.write(RequestCardStatus, 8); + // wait for the result, while reblinking + delay(100); + digitalWrite(statusLed, statusState); + delay(150); + + // read input from serial into the buffer + int i = 0; + while (Serial.available() > 0) { + if (i < sizeof(buf)) { + buf[i] = Serial.read(); + } + ++i; + } + + // no card is detected + if (!memcmp(buf, NoCardResponse, 7)) { + server.write("NOCARD\n"); + } + + // card detected - message has form AA0006xxxxxxxxxxxxxxBB where xxx... is the card ID + if (buf[0] == 0xAA && buf[1] == 0x00 && buf[2] == 0x06 && buf[10] == 0xBB) { + bool known = false; + // go through ACL + for (int i = 0; i < sizeof(ACL)/sizeof(ACL[0]); ++i) { + // if there is a match - print known card ... + if (!memcmp(ACL[i].cardId, buf+3, 7)) { + known = true; + server.write("CARD "); + server.write(ACL[i].nick); + server.write("\n"); + // ... and open door for 5s + openDoorForTime(5000); + break; + } + } + // card was not found in the ACL + if (!known) { + server.write("CARD UNKNOWN "); + for (int i = 0; i < 7; ++i) { + if (buf[i+3] < 0xF) server.write("0"); + server.print(buf[i+3], HEX); + } + server.write("\n"); + playMelodyNak(); + } + } + // make cycle interval 1s + delay(750); +} + +void setup() +{ + // constants for ethernet shield + byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + byte ip[] = { 192, 168, 1, 3 }; + byte gateway[] = { 192, 168, 1, 1 }; + byte subnet[] = { 255, 255, 255, 0 }; + + pinMode(doorLock, OUTPUT); + pinMode(soundPin, OUTPUT); + pinMode(statusLed, OUTPUT); + pinMode(videoLed, OUTPUT); + pinMode(statusBtn, INPUT); + digitalWrite(statusBtn, HIGH); + pinMode(videoBtn, INPUT); + digitalWrite(videoBtn, HIGH); + Serial.begin(9600); + Ethernet.begin(mac, ip, gateway, subnet); + server.begin(); +} + +void loop() +{ + statusState = !digitalRead(statusBtn); + videoState = !digitalRead(videoBtn); + digitalWrite(statusLed, !statusState); // will be turned back in readCard() + digitalWrite(videoLed, videoState); + server.print(statusState, DEC); server.write(" "); + server.print(videoState, DEC); server.write(" "); + readCard(); +} diff --git a/pitches.h b/pitches.h new file mode 100644 index 0000000..9f16b4d --- /dev/null +++ b/pitches.h @@ -0,0 +1,93 @@ +/************************************************* + * Public Constants + *************************************************/ + +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978