-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDoorControl2.ino
262 lines (233 loc) · 7.19 KB
/
DoorControl2.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#define VERSION_BANNER "Compiled " __TIME__ " " __DATE__
#define STATUS_PERIOD 10000UL // Emit a heartbeat message every 10 seconds
// globals for LED flash
unsigned long NextFlash = 0;
unsigned long FlashRate = 0;
// globals for periodic status
unsigned long NextStatus = 0;
boolean reboot=true;
// globals for using the doorbell as a shift key
#define BELL_NONE 0
#define BELL_RING 1
#define BELL_SHIFT 2
byte isBell = BELL_NONE;
// Feeling buggy?
#define DEBUG true
// BittyMorse settings - define before including!
// #define MORSE_DEBUG true
#define MORSE_OUTPUT_ON LOW
#define MORSE_OUTPUT_OFF HIGH
// No display ... yet.
// #include <LiquidCrystal_I2C.h>
// reader instance
#include <Wiegand.h>
WIEGAND wg;
#include <String.h>
#include <Bounce2.h>
#include <TimeLib.h>
#include "hardware.h"
#include "BittyMorse.h"
// bitmask for Status()
#define STATUS_TIME 0x01
#define STATUS_INPUT 0x02
#define STATUS_OUTPUT 0x04
#define STATUS_FLASH 0x08
#define STATUS_ALL 0xFF
///////////////////// FUNCTIONS /////////////////////
String readLine(boolean numeric=false) { // read serial input until CR/LF
unsigned long timeout = millis() + 3000UL; // or 3 second timeout
String mybuffer;
while (millis() < timeout) {
if (Serial.available()) {
uint8_t inbyte = Serial.read();
if (inbyte == 0x0D) break; // end on CR
if (inbyte == 0x0A) break; // or LF
if (inbyte < 0x20) continue; // skip other control chars
if ((numeric) && ((inbyte < '0') || (inbyte > '9'))) continue;
mybuffer += char(inbyte);
}
}
#ifdef DEBUG
Serial.print(F("DEBUG readLine returning "));
Serial.println(mybuffer);
#endif
return(mybuffer);
}
String WallClock() {
String mytime="00:00:00";
mytime.setCharAt(0, (hour() / 10) + 0x30);
mytime.setCharAt(1, (hour() % 10) + 0x30);
mytime.setCharAt(3, (minute() / 10) + 0x30);
mytime.setCharAt(4, (minute() % 10) + 0x30);
mytime.setCharAt(6, (second() / 10) + 0x30);
mytime.setCharAt(7, (second() % 10) + 0x30);
return(mytime);
}
void Status(uint8_t section=STATUS_ALL) {
if (section & STATUS_TIME) {
Serial.print(F("STATUS UPTIME "));
Serial.print(millis(), DEC);
Serial.print(F(" CLOCK "));
if (timeStatus()!= timeNotSet) {
Serial.println(WallClock());
} else {
Serial.println(F("NOTSET"));
}
}
if (section & STATUS_INPUT) {
Serial.print(F("STATUS INPUT "));
Serial.print(Input1.read(), DEC);
Serial.print(" ");
Serial.print(Input2.read(), DEC);
Serial.print(" ");
Serial.print(Input3.read(), DEC);
#ifdef INPUT4
Serial.print(" ");
Serial.print(Input4.read(), DEC);
#endif
#ifdef INPUT5
Serial.print(" ");
Serial.println(Input5.read(), DEC);
#endif
Serial.println("");
}
//// Future: Analog inputs?
if (section & STATUS_OUTPUT) {
Serial.print(F("STATUS OUTPUT "));
Serial.print(digitalRead(OUTPUT1), DEC);
Serial.print(" ");
Serial.print(digitalRead(OUTPUT2), DEC);
Serial.print(" ");
Serial.print(digitalRead(OUTPUT3), DEC);
Serial.print(" ");
Serial.println(digitalRead(OUTPUT4), DEC);
}
if (section & STATUS_FLASH) {
Serial.print(F("STATUS FLASHRATE "));
Serial.print(FlashRate, DEC);
Serial.print(" ");
Serial.println(NextFlash, DEC);
}
}
void OK(String remark) { Serial.print("OK "); Serial.println(remark); }
void getFlashRate() {
FlashRate = (0 + readLine(true).toInt());
OK("FLASHRATE " + String(FlashRate, DEC));
pinMode(RFID_LED, OUTPUT);
}
void getClockOffset() {
unsigned long pctime = (0 + readLine(true).toInt());
setTime(pctime); // Sync Arduino clock to the time received on the serial port
}
void doMorse(String somejunk=readLine()) {
Serial.print("DEBUG: doMorse: ");
Serial.println(somejunk);
for (int i=0; i < somejunk.length(); i++) {
playMorse(somejunk.charAt(i));
}
}
void checkAction() {
if (! Serial.available()) return;
uint8_t newcmd = Serial.read(); // gobble up one byte
switch (int(newcmd)) {
case '1': digitalWrite(OUTPUT1, LOW); Status(STATUS_OUTPUT); break;
case '2': digitalWrite(OUTPUT2, LOW); Status(STATUS_OUTPUT); break;
case '3': digitalWrite(OUTPUT3, LOW); Status(STATUS_OUTPUT); break;
case '4': digitalWrite(OUTPUT4, LOW); Status(STATUS_OUTPUT); break;
case '!': digitalWrite(OUTPUT1, HIGH); Status(STATUS_OUTPUT); break;
case '@': digitalWrite(OUTPUT2, HIGH); Status(STATUS_OUTPUT); break;
case '#': digitalWrite(OUTPUT3, HIGH); Status(STATUS_OUTPUT); break;
case '$': digitalWrite(OUTPUT4, HIGH); Status(STATUS_OUTPUT); break;
case '.': Status(STATUS_ALL); break;
case '?': Help(); break;
case 'B': BEEP(true); OK("BEEP ON"); break;
case 'b': BEEP(false); OK("BEEP OFF"); break;
case 'L': LED(true); OK("LED GREEN"); break;
case 'l': LED(false); OK("LED RED"); break;
case 'f': getFlashRate(); break;
case 't': getClockOffset(); break;
case 'm': doMorse(); break;
#ifdef MORSE_DEBUG
case 'M': MorseDump(); break;
#endif
case 0x0D: Serial.println("OK"); return; break; // acknowledge CR
case 0x0A: Serial.println("OK"); return; break; // acknowledge LF
}
}
void Help() {
OK(F(VERSION_BANNER));
OK(F("HELP: (?)Help (.)Status"));
OK(F("HELP: (l)ed red (L)ed green (f)(msec)(CR) Flash LED"));
OK(F("HELP: (b)eep off (B)eep on (m)(string)(CR) Output Morse"));
OK(F("HELP: (1/2/3/4) Output LOW (!/@/#/$) Output HIGH"));
}
// KEYPAD LAYOUT (without / with shift)
// 1 2 3 A B C
// 4 5 6 D E F
// 7 8 9 G H I
// : 0 ; J @ K
void checkWiegand() {
if (wg.available()) {
uint32_t myCode = wg.getCode();
if (myCode < 0xFF) { // Keypress
myCode = (myCode & 0x0F); // Only keep the meaningful part - the low 4 bits
if (isBell == BELL_NONE) {
myCode += 0x30; // 0 ... 9, ESC=:, ENT=; = Unshifed keys
} else {
myCode += 0x40; // @, A ... I, ESC=J, ENT=K = Shifted keys
isBell = BELL_SHIFT; // not a doorbell request
}
Serial.print(F("KEY "));
Serial.println(char(myCode));
return;
}
Serial.print(F("READ "));
if (isBell == BELL_NONE) {
Serial.println(myCode, HEX);
} else {
isBell = BELL_SHIFT;
Serial.print(myCode, HEX);
Serial.println(F(" SHIFT"));
}
}
}
void doFlash() {
if (FlashRate == 0) return;
if (millis() < NextFlash) return;
digitalWrite(RFID_LED, !digitalRead(RFID_LED));
NextFlash=millis() + FlashRate;
}
void periodicStatus() {
if (millis() < STATUS_PERIOD) {
if (NextStatus > 10000000UL ) {
Serial.println(F("DEBUG caught millis() overflow"));
NextStatus = STATUS_PERIOD;
return;
}
if (NextStatus == 0UL ) {
Serial.println(F("DEBUG rebooted"));
NextStatus = STATUS_PERIOD;
return;
}
}
if (NextStatus > millis()) return;
NextStatus= ( millis() + STATUS_PERIOD);
Status(STATUS_TIME);
}
/////////////////// Main program //////////////////////
void setup() {
Serial.begin(115200);
HardwareSetup();
while (!Serial); // required for some models ... but which ones?
pinMode(MORSE_PIN, OUTPUT);
}
void loop() {
periodicStatus();
doFlash();
checkEvent();
doFlash();
checkWiegand();
doFlash();
checkAction();
doFlash();
}