Obiecany kod, to nadal nie skończone rozwiązanie (nie mam jeszcze dopracowanego otwierania i zamykania drzwi garażowych oraz obsługi czujników odległości);
#include <Wiegand.h>
#include <EEPROM.h>
WIEGAND wg;
// keyboard support
String code = "";
byte index = 0;
byte maxIndex = 6;
// Serial support
String inputString = "";
boolean stringComplete = false;
// card and code storage
String codes[10] = { String( " " ), String( "" ), String( "" ), String( "" ), String( "" ), String( "" ), String( "" ), String( "" ), String( "" ), String( "" ) };
unsigned long cards[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // ten slots for cards
// programming variables
byte programmingMode = 0;
byte programmingSlot = 0;
String enteredProgrammingCode = "";
String enteredNewCode = "";
unsigned long enteredProgrammingCard = 0;
unsigned long enteredNewCard = 0;
// persistence
byte serialized[141];
/*
* This solution has 10 slots for codes (0-9) and 10 slots for cards (0-9).
* Slot 9 is special - in addition to opening door, it is also used
* as a programming code/card.
*
* Serial Port Commands:
* L - change code length (resets all codes) - example L5
* D - delete code - example D1
* S - set code - example D1202030
* G - get code - example G1
* C - get card - example C1
* A - add card - example A1544370
* B - delete card - example B1
* P - ping - example P
* E - write cards and codes to EEPROM - example E
* R - read cards and codes from EEPROM - example R
*
* Commands respond with OK: [command][some extra data if required] or ERROR: [comand][some extra data] if there was an error:
* L[length] responds with OK: L[length]
* D[slot] responds with OK: D[slot]
* S[slot][code] responds with OK: S[slot][code] or ERROR: S[slot][code] if code length is <> preset length
* G[slot] responds with OK: G[slot][code at this slot - may be empty]
* C[slot] responds with OK: C[slot][card # or 0 if no card]
* A[slot][card #] responds with OK: A[slot][card #] if card # was parsed to long or ERROR: A[slot][card #] if card # was not parsable
* B[slot] responds with OK: B[slot]
* P responds with OK: PONG
* E responds with OK: E: BYTES :[number of bytes written]
* R responds with OK: R: BYTES :[number of bytes read]
*
* Programming via keyboard/card:
* - press ENT
* - enter code (slot 9) or scan card (slot 9)
* - press ENT
* - enter slot (0-9)
* - press ENT
* - enter code or scan card to remember
* - press ENT
* Delete code/card via keyboard/card:
* - press ENT
* - enter code (slot 9) or scan card (slot 9)
* - press ENT
* - enter slot (0-9)
* - press ENT
* - press ESC
*/
void setup() {
inputString.reserve(20);
resetLength();
for ( byte i = 0; i < 141; i++ )
{
serialized[i] = 0;
}
Serial.begin(9600);
wg.begin();
pinMode(4, OUTPUT); // keypad LED
pinMode(5, OUTPUT); // keypad annnoying speaker
pinMode(6, OUTPUT); // garage door opener
pinMode(7, OUTPUT); // garage door light
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
Serial.println( "STARTED:");
}
void loop() {
if (wg.available())
{
unsigned long input = wg.getCode();
if ( input == 10 )
{
processESC();
}
else if ( input == 11 )
{
processENT();
}
else if ( input >= 0 && input < 10 )
{
processKey(input);
}
else
{
processCard(input);
}
}
if ( stringComplete )
{
processSerial();
}
}
// handles asynchronous serial input
void serialEvent()
{
while (Serial.available())
{
// get the new byte:
char inChar = (char)Serial.read();
if (inChar == '\n')
{
stringComplete = true;
}
else
{
if ( inputString.length() < 20 )
{
inputString += inChar;
}
}
}
}
// make error sound
void beepError()
{
for ( byte i = 0; i < 3; i++ )
{
digitalWrite(5, LOW);
delay(100);
digitalWrite(5, HIGH);
delay(100);
digitalWrite(5, LOW);
delay(50);
digitalWrite(5, HIGH);
delay(50);
digitalWrite(5, LOW);
delay(50);
digitalWrite(5, HIGH);
delay(50);
}
}
// make OK sound and blink green
void beepOk()
{
digitalWrite(4, LOW);
digitalWrite(5, LOW);
delay(100);
digitalWrite(5, HIGH);
delay(500);
digitalWrite(4, HIGH);
}
// make escape key sound
void beepEscape()
{
for ( byte i = 0; i < 3 ; i ++) {
digitalWrite(5, LOW);
delay(50);
digitalWrite(5, HIGH);
delay(50);
}
}
// resets everything and reports beeping error
void resetError()
{
beepError();
reset();
}
// resets everything (programming mode, keyboard input)
void reset()
{
resetInput();
programmingMode = 0;
enteredNewCode = "";
enteredProgrammingCode = "";
enteredProgrammingCard = 0;
enteredNewCard = 0;
}
// resets keyboard input
void resetInput()
{
index = 0;
code = "";
}
// call after maxLength is changed to adjust memory storage
void resetLength()
{
index = 0;
code = "";
code.reserve(maxIndex);
for ( byte i = 0; i < 10; i++ )
{
codes[i] = "";
codes[i].reserve( maxIndex );
}
enteredProgrammingCode = "";
enteredProgrammingCode.reserve(maxIndex);
enteredNewCode = "";
enteredNewCode.reserve(maxIndex);
}
byte saveToEEPROM()
{
byte eIdx = 0;
serialized[ eIdx++ ] = maxIndex;
for ( byte i = 0; i < 10; i++ )
{
if ( codes[i] == "" )
{
serialized[ eIdx++ ] = 0;
}
else
{
for ( byte j = 0; j < maxIndex; j++ )
{
serialized[ eIdx++ ] = byte( codes[i].charAt(j) );
}
}
}
for ( byte i = 0; i < 10; i++ )
{
serialized[ eIdx++ ] = (byte)cards[i];
serialized[ eIdx++ ] = (byte) (cards[i] >> 8 );
serialized[ eIdx++ ] = (byte) (cards[i] >> 16 );
serialized[ eIdx++ ] = (byte) (cards[i] >> 24 );
}
EEPROM.put( 0, serialized );
return eIdx;
}
byte readFromEEPROM()
{
for ( byte i = 0; i < 141; i++ )
{
serialized[i] = 0;
}
EEPROM.get( 0, serialized );
byte eIdx = 0;
maxIndex = serialized[ eIdx++ ];
resetLength();
for ( byte i = 0; i < 10; i++ )
{
byte eval = serialized[ eIdx++ ];
if ( eval == 0 )
{
codes[i] = "";
}
else
{
String c = String( (char)eval );
for ( byte j = 1; j < maxIndex; j++ )
{
c += (char) serialized[ eIdx++ ];
}
codes[i] = c;
}
}
for ( byte i = 0; i < 10; i++ )
{
byte c0 = serialized[ eIdx++ ];
byte c1 = serialized[ eIdx++ ];
byte c2 = serialized[ eIdx++ ];
byte c3 = serialized[ eIdx++ ];
cards[i] = (unsigned long)(c3 << 24) | (unsigned long)(c2 << 16) | (unsigned long)(c1 << 8) | (unsigned long)c0 ;
}
return eIdx;
}
void processESC()
{
if ( programmingMode == 4 )
{
if ( enteredProgrammingCard > 0 )
{
cards[programmingSlot] = 0;
Serial.print( "OK: CARD REMOVED FROM SLOT " );
Serial.println( programmingSlot );
}
else
{
codes[programmingSlot] = "";
Serial.print( "OK: CODE REMOVED FROM SLOT " );
Serial.println( programmingSlot );
}
beepOk();
beepOk();
beepEscape();
beepEscape();
reset();
}
else
{
beepEscape();
reset();
}
}
void processENT()
{
if ( programmingMode == 0 )
{
Serial.println( "OK: PROGRAMMING MODE 1" );
programmingMode = 1;
programmingSlot = 0;
resetInput();
}
else if ( programmingMode == 1 )
{
Serial.println( "ERROR: DOUBLE ENTER IN PROGRAMMING MODE 1" );
resetError();
}
else if ( programmingMode == 2 )
{
if ( enteredProgrammingCode == codes[9] )
{
Serial.println( "OK: PROGRAMMING MODE 3" );
beepOk();
beepOk();
programmingMode = 3;
resetInput();
}
else
{
Serial.print( "ERROR: INVALID PROGRAMMING CODE: " );
Serial.println( enteredProgrammingCode );
resetError();
}
}
else if ( programmingMode == 3 && index == 1 )
{
programmingSlot = code.charAt(0) - '0';
if ( programmingSlot >= 0 && programmingSlot < 10 )
{
Serial.println( "OK: PROGRAMMING MODE 4" );
programmingMode = 4;
beepOk();
resetInput();
}
else
{
Serial.print( "ERROR: INVALID PROGRAMMING SLOT: " );
Serial.println( code );
resetError();
}
}
else if ( programmingMode == 4 )
{
Serial.println( "ERROR: DOUBLE ENTER IN PROGRAMMING MODE 4" );
resetError();
}
else if ( programmingMode == 5 )
{
Serial.print( "OK: CODE: " );
Serial.print( enteredNewCode );
Serial.print( " PROGRAMMED INTO SLOT " );
Serial.println( programmingSlot );
codes[programmingSlot] = enteredNewCode;
beepOk();
beepOk();
beepOk();
beepOk();
reset();
}
else if ( programmingMode == 6 )
{
if ( enteredProgrammingCard == cards[9] && enteredProgrammingCard > 0)
{
Serial.println( "OK: PROGRAMMING MODE 3" );
beepOk();
beepOk();
programmingMode = 3;
resetInput();
}
else
{
Serial.print( "ERROR: INVALID PROGRAMMING CARD: " );
Serial.println( enteredProgrammingCard );
resetError();
}
}
else if ( programmingMode == 7 && enteredNewCard > 0)
{
Serial.print( "OK: CARD: " );
Serial.print( enteredNewCard );
Serial.print( " PROGRAMMED INTO SLOT " );
Serial.println( programmingSlot );
cards[programmingSlot] = enteredNewCard;
beepOk();
beepOk();
beepOk();
beepOk();
reset();
}
else
{
Serial.println( "ERROR: UNKNOWN PROGRAMMING MODE" );
resetError();
}
}
void processKey(unsigned long input)
{
code += (char)( '0' + input );
index++;
if ( index == maxIndex )
{
if ( programmingMode == 1 )
{
Serial.println( "OK: PROGRAMMING MODE 2" );
programmingMode = 2;
enteredProgrammingCode = code;
resetInput();
}
else if ( programmingMode == 4 )
{
Serial.println( "OK: PROGRAMMING MODE 5" );
programmingMode = 5;
enteredNewCode = code;
resetInput();
}
else if ( programmingMode != 0 )
{
Serial.println( "ERROR: CODE ENTRY IN UNKNOWN PROGRAMMING MODE" );
resetError();
}
else if ( programmingMode == 0 )
{
boolean correctCode = false;
for ( byte i = 0; i < 10; i++ )
{
if ( code == codes[i] )
{
correctCode = true;
break;
}
}
if ( correctCode )
{
Serial.print("CODE: ");
Serial.println(code);
beepOk();
resetInput();
programmingMode = 0;
triggerDoor();
}
else
{
Serial.print("INV: ");
Serial.println(code);
resetError();
}
}
}
else if (index > maxIndex )
{
Serial.println( "ERROR: TOO MANY CHARS" );
resetError();
}
}
void processCard(unsigned long input)
{
if ( programmingMode == 1 )
{
Serial.println( "OK: PROGRAMMING MODE 6" );
programmingMode = 6;
enteredProgrammingCard = input;
resetInput();
}
else if ( programmingMode == 4 )
{
Serial.println( "OK: PROGRAMMING MODE 7" );
programmingMode = 7;
enteredNewCard = input;
resetInput();
}
else if ( programmingMode != 0 )
{
Serial.println( "ERROR: CARD ENTRY IN UNKNOWN PROGRAMMING MODE" );
resetError();
}
else if ( programmingMode == 0 )
{
boolean correctCode = false;
for ( byte i = 0; i < 10; i++ )
{
if ( input == cards[i] )
{
correctCode = true;
break;
}
}
if ( correctCode )
{
Serial.print("CARD: ");
Serial.println(input);
beepOk();
resetInput();
programmingMode = 0;
triggerDoor();
}
else
{
Serial.print("INVCARD: ");
Serial.println(input);
resetError();
}
}
}
void processSerial()
{
digitalWrite(4, LOW);
boolean processed = false;
if ( inputString.length() > 0 )
{
if ( inputString.charAt( 0 ) == 'L' && inputString.length() == 2 )
{
maxIndex = inputString.charAt( 1 ) - '0';
if ( maxIndex > 0 && maxIndex < 10 )
{
resetLength();
processed = true;
}
}
else if ( inputString.charAt( 0 ) == 'D' && inputString.length() == 2 )
{
int codeIndex = inputString.charAt( 1 ) - '0';
if ( codeIndex >= 0 && codeIndex < 10 )
{
codes[codeIndex] = "" ;
processed = true;
}
}
else if ( inputString.charAt( 0 ) == 'S' && inputString.length() == 2 + maxIndex )
{
int codeIndex = inputString.charAt( 1 ) - '0';
if ( codeIndex >= 0 && codeIndex < 10 )
{
codes[codeIndex] = inputString.substring(2);
processed = true;
}
}
else if ( inputString.charAt( 0 ) == 'G' && inputString.length() == 2 )
{
int codeIndex = inputString.charAt( 1 ) - '0';
if ( codeIndex >= 0 && codeIndex < 10 )
{
inputString += codes[codeIndex] ;
processed = true;
}
}
else if ( inputString.charAt( 0 ) == 'C' && inputString.length() == 2 )
{
int codeIndex = inputString.charAt( 1 ) - '0';
if ( codeIndex >= 0 && codeIndex < 10 )
{
inputString += cards[codeIndex] ;
processed = true;
}
}
else if ( inputString.charAt( 0 ) == 'A' )
{
int codeIndex = inputString.charAt( 1 ) - '0';
if ( codeIndex >= 0 && codeIndex < 10 )
{
cards[codeIndex] = inputString.substring(2).toInt();
if ( cards[codeIndex] > 0 )
{
inputString = String( "A" ) + String( inputString.charAt( 1 ) ) + String( cards[codeIndex], DEC );
processed = true;
}
}
}
else if ( inputString.charAt( 0 ) == 'B' && inputString.length() == 2 )
{
int codeIndex = inputString.charAt( 1 ) - '0';
if ( codeIndex >= 0 && codeIndex < 10 )
{
cards[codeIndex] = 0 ;
processed = true;
}
}
else if ( inputString.charAt( 0 ) == 'P' && inputString.length() == 1 )
{
inputString += "ONG" ;
processed = true;
}
else if ( inputString.charAt( 0 ) == 'E' && inputString.length() == 1 )
{
byte eIdx = saveToEEPROM();
inputString += ": BYTES :" + String( eIdx, DEC) ;
processed = true;
}
else if ( inputString.charAt( 0 ) == 'R' && inputString.length() == 1 )
{
byte eIdx = readFromEEPROM();
inputString += ": BYTES :" + String( eIdx, DEC) ;
processed = true;
}
}
if ( processed )
{
Serial.print( "OK: " );
Serial.println(inputString);
}
else
{
Serial.print( "ERROR: " );
Serial.println(inputString);
}
// clear the string:
delay(500);
digitalWrite(4, HIGH);
inputString = "";
stringComplete = false;
}
void triggerDoor()
{
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
delay( 500 );
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
}