/*
* The Sphinx -- A Device for Asking Riddles at the Entrance to the Garage
*
- * (c) 2017 Martin Mares <mj@ucw.cz>
+ * (c) 2017--2019 Martin Mares <mj@ucw.cz>
*/
/*
*
* +-------------------+
* | RESET* VCC |
- * button* | PB3 PB2=SCK |
- * output | PB4 PB1=MISO |
+ * button* | PB3 PB2=SCK | signal "closed" from drive*
+ * output to drive | PB4 PB1=MISO | corridor LED
* | GND PB0=MOSI | diagnostic LED*
* +-------------------+
*
- * Note that MOSI is used for programming, so the LED is connected
- * via jumper, which must be open during programming.
+ * Note that MISO, MOSI, and SCK are used for programming, so our signals
+ * are connected via jumpers, which must be kept open during programming.
+ *
+ * Connections to door control unit:
+ *
+ * 3 = +24V
+ * 1 = GND
+ * 2 = output
+ *
+ * Connections to EP 161 module:
+ *
+ * H1 = signal +
+ * 92 = signal -
*/
#define F_CPU 1200000UL
static byte pressed;
static u16 press_timer;
#define LONG_PRESS 150
-static byte second_timer;
-static byte unlocked;
-#define UNLOCK_SECONDS 60
+static u16 unlock_timer;
+#define UNLOCK_SECONDS 30
+static byte blink_timer;
ISR(TIM0_COMPA_vect)
{
+ // Generate output pulse
if (out_pulse) {
if (!--out_pulse)
PORTB &= ~B(PB4);
}
- if (!second_timer) {
- second_timer = 100;
- if (unlocked)
- unlocked--;
- }
- second_timer--;
-
+ // Debounce the button
if (PINB & B(PB3)) {
// Switch open
if (debounce)
pressed = 1;
}
- if (unlocked) {
- if (!(second_timer & 7))
- PORTB ^= B(PB0);
+ // PB2 is 0 if the door is fully closed,
+ // we need to set door_open if it is at least partially open.
+ byte door_open;
+ if (PINB & B(PB2)) {
+ door_open = 1;
+ PORTB |= B(PB1);
+ unlock_timer = UNLOCK_SECONDS * 60;
+ } else {
+ door_open = 0;
+ PORTB &= ~B(PB1);
+ }
+
+ // Locking
+ if (unlock_timer) {
if (pressed) {
+ PORTB &= ~B(PB0);
if (out_pulse < 2)
out_pulse = 2;
PORTB |= B(PB4);
- unlocked = UNLOCK_SECONDS;
+ unlock_timer = UNLOCK_SECONDS * 100;
+ } else if (door_open) {
+ if (!(blink_timer & 63))
+ PORTB ^= B(PB0);
+ } else {
+ if (!(blink_timer & 15))
+ PORTB ^= B(PB0);
+ unlock_timer--;
}
} else {
if (!pressed) {
PORTB &= ~B(PB0);
if (press_timer < LONG_PRESS) {
press_timer++;
- if (press_timer == LONG_PRESS) {
- out_pulse = OUT_PULSE_WIDTH;
- PORTB |= B(PB4);
- unlocked = UNLOCK_SECONDS;
- }
+ if (press_timer == LONG_PRESS)
+ unlock_timer = UNLOCK_SECONDS * 100;
}
}
}
+
+ blink_timer++;
}
int main(void)
// PB0: output for diagnostic LED
DDRB |= B(PB0);
+ // PB1: output for corridor LED
+ PORTB &= ~B(PB1);
+ DDRB |= B(PB1);
+
+ // PB2: signal "door closed" from the drive, needs pull up
+ PORTB |= B(PB2);
+
// PB3: button input, needs pull up
PORTB |= B(PB3);
// Copy mode
for (;;) {
sleep(10);
- if (PINB & B(PB3)) {
+ if (PINB & B(PB2)) {
PORTB |= B(PB0);
+ PORTB &= ~B(PB1);
PORTB &= ~B(PB4);
} else {
PORTB &= ~B(PB0);
+ PORTB |= B(PB1);
PORTB |= B(PB4);
}
}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fs.h>
+
+// XXX: Assuming block size == 512
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <from> <to>\n", argv[0]);
+ return 1;
+ }
+
+ int fi = open(argv[1], O_RDONLY);
+ if (fi < 0) {
+ fprintf(stderr, "Cannot open source %s: %m\n", argv[1]);
+ return 1;
+ }
+
+ int fo = open(argv[2], O_WRONLY);
+ if (fo < 0) {
+ fprintf(stderr, "Cannot open destination %s: %m\n", argv[1]);
+ return 1;
+ }
+
+ struct stat sti, sto;
+ if (fstat(fi, &sti) < 0 || fstat(fo, &sto) < 0) {
+ fprintf(stderr, "Stat failed: %m\n");
+ return 1;
+ }
+ if (!S_ISBLK(sti.st_mode)) {
+ fprintf(stderr, "Input is not a block device\n");
+ return 1;
+ }
+ if (!S_ISBLK(sto.st_mode)) {
+ fprintf(stderr, "Output is not a block device\n");
+ return 1;
+ }
+
+ unsigned long leni, leno;
+ if (ioctl(fi, BLKGETSIZE, &leni) < 0 ||
+ ioctl(fo, BLKGETSIZE, &leno) < 0) {
+ fprintf(stderr, "Cannot get device size: %m\n");
+ return 1;
+ }
+ if (leni > leno) {
+ fprintf(stderr, "Will not fit: %ld > %ld\n", leni, leno);
+ return 1;
+ }
+
+#define BUFSIZE 65536
+ char *buf = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (buf == MAP_FAILED) {
+ fprintf(stderr, "Cannot mmap buffer: %m\n");
+ return 1;
+ }
+
+ unsigned int remi = leni;
+ int verb = 1;
+ while (remi) {
+ int s = (remi < BUFSIZE/512) ? remi : BUFSIZE/512;
+ int l = read(fi, buf, s*512);
+ if (l < 0) {
+ fprintf(stderr, "Read error: %m\n");
+ return 1;
+ }
+ if (l != s*512) {
+ fprintf(stderr, "Short read: %d of %d. Recovering.\n", l, s*512);
+ }
+ int w = write(fo, buf, l);
+ if (w < 0) {
+ fprintf(stderr, "Write error: %m\n");
+ return 1;
+ }
+ if (w != l) {
+ fprintf(stderr, "Short write: %d of %d\n", w, l);
+ return 1;
+ }
+ remi -= s;
+ if (!--verb) {
+ printf("\rCopied %d of %d MB (%d%%)...", (int)((leni-remi)/2048), (int)((leni+2047)/2048),
+ (int)((double)(leni-remi) / leni * 100));
+ verb = 64;
+ }
+ }
+
+ printf("Copied %d MB \n", (int)((leni+2047)/2048));
+ close(fo);
+ close(fi);
+ return 0;
+}