From 276856de6c63bbbf3e56cc08dcca00ba10080b7e Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sun, 7 Sep 2025 17:04:34 +0800 Subject: Door lock with MOSFETs and and without RFM. --- door_lock/Makefile | 47 ++++++ door_lock/README.txt | 48 +++++++ door_lock/fpm.c | 297 ++++++++++++++++++++++++++++++++++++++ door_lock/fpm.h | 46 ++++++ door_lock/main.c | 287 +++++++++++++++++++++++++++++++++++++ door_lock/uart.c | 31 ++++ door_lock/uart.h | 10 ++ door_lock_rfm/Client.Makefile | 46 ++++++ door_lock_rfm/Server.Makefile | 44 ++++++ door_lock_rfm/client.c | 198 ++++++++++++++++++++++++++ door_lock_rfm/fpm.c | 324 ++++++++++++++++++++++++++++++++++++++++++ door_lock_rfm/fpm.h | 38 +++++ door_lock_rfm/nrfm.c | 303 +++++++++++++++++++++++++++++++++++++++ door_lock_rfm/nrfm.h | 21 +++ door_lock_rfm/server.c | 191 +++++++++++++++++++++++++ door_lock_rfm/uart.h | 8 ++ door_lock_rfm/util.c | 89 ++++++++++++ door_lock_rfm/util.h | 27 ++++ lock/Client.Makefile | 46 ------ lock/Server.Makefile | 44 ------ lock/client.c | 198 -------------------------- lock/fpm.c | 324 ------------------------------------------ lock/fpm.h | 38 ----- lock/nrfm.c | 303 --------------------------------------- lock/nrfm.h | 21 --- lock/server.c | 191 ------------------------- lock/uart.h | 8 -- lock/util.c | 89 ------------ lock/util.h | 27 ---- 29 files changed, 2055 insertions(+), 1289 deletions(-) create mode 100644 door_lock/Makefile create mode 100644 door_lock/README.txt create mode 100644 door_lock/fpm.c create mode 100644 door_lock/fpm.h create mode 100644 door_lock/main.c create mode 100644 door_lock/uart.c create mode 100644 door_lock/uart.h create mode 100644 door_lock_rfm/Client.Makefile create mode 100644 door_lock_rfm/Server.Makefile create mode 100644 door_lock_rfm/client.c create mode 100644 door_lock_rfm/fpm.c create mode 100644 door_lock_rfm/fpm.h create mode 100644 door_lock_rfm/nrfm.c create mode 100644 door_lock_rfm/nrfm.h create mode 100644 door_lock_rfm/server.c create mode 100644 door_lock_rfm/uart.h create mode 100644 door_lock_rfm/util.c create mode 100644 door_lock_rfm/util.h delete mode 100644 lock/Client.Makefile delete mode 100644 lock/Server.Makefile delete mode 100644 lock/client.c delete mode 100644 lock/fpm.c delete mode 100644 lock/fpm.h delete mode 100644 lock/nrfm.c delete mode 100644 lock/nrfm.h delete mode 100644 lock/server.c delete mode 100644 lock/uart.h delete mode 100644 lock/util.c delete mode 100644 lock/util.h diff --git a/door_lock/Makefile b/door_lock/Makefile new file mode 100644 index 0000000..ee25780 --- /dev/null +++ b/door_lock/Makefile @@ -0,0 +1,47 @@ +CC = avr-gcc +MCU = atmega328p +PORT = /dev/cuaU0 +TARGET = app + +SRC = main.c uart.c fpm.c +OBJ = $(SRC:.c=.o) + +CFLAGS = -std=gnu99 +CFLAGS += -Os +CFLAGS += -Wall +CFLAGS += -mmcu=$(MCU) +CFLAGS += -DBAUD=57600 +CFLAGS += -DF_CPU=8000000UL +CFLAGS += -DFPM_PWD=$(FPM_PWD) +CFLAGS += -ffunction-sections -fdata-sections + +LDFLAGS = -mmcu=$(MCU) +LDFLAGS += -Wl,--gc-sections + +HEX_FLAGS = -O ihex +HEX_FLAGS += -j .text -j .data + +AVRDUDE_FLAGS = -p $(MCU) +AVRDUDE_FLAGS += -c arduino +AVRDUDE_FLAGS += -P $(PORT) +AVRDUDE_FLAGS += -b 57600 +AVRDUDE_FLAGS += -D -U + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +elf: $(OBJ) + $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf + +hex: elf + avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex + +upload: hex + avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i + +.PHONY: clean + +clean: + rm -f *.o *.elf *.hex + + diff --git a/door_lock/README.txt b/door_lock/README.txt new file mode 100644 index 0000000..08f320f --- /dev/null +++ b/door_lock/README.txt @@ -0,0 +1,48 @@ +CURRENT MEASUREMENTS + +PERIPHERALS: + +R503 FPM: + +When VCC is connected to a 3.31V supply, FPM draws 13.8mA of quiescent current. When +VCC is disconnected (3.3VT connected to 3.31V supply), it draws 2.9uA. + +FS5106B high-torque servo: + +One of them draws 6.1mA when connected and stabilizes at 4.6mA. The other drew +variable amounts initially (4.7mA, 5mA+, but mostly 4.7). Both draw 4.6mA of +quiescent current with a 5.07V supply. + +TARGET CURRENT DRAW + + 1. 2.7mA for 1 month + 2. 1.4mA for 2 months + 3. 900uA for 3 months + 3. 694uA for 4 months + +LINEAR REGULATORS + + 1. When the ATmega328P is in normal mode, the MCU + FPM + Servo + linear + regulators draw 30.6mA of quiescent current at 5.07V. + 2. When the ATmega328P is in power down mode, the MCU + FPM + Servo + linear + regulators draw 26.2mA of quiescent current at 5.07V. + 3. When the ATmega328P is in power down mode, the MCU + linear regulators draw + 13.7mA of quiescent current at 5.07V (without MOSFETS). + +MP1584EN BUCK CONVERTER + + 1. When the system is in power down mode, the MCU + FPM + Servo draw 8.9mA at + 3.3V. The real amount is likely about 8.9 + 4.6 = 13.5mA. + 2. When FETs are used quiescent current drops to 0uA. + 3. Active current draw (when the servo rotates) measured are 152.8mA, 162.8mA, + 170.3mA + +REMARKS + + 1. Can't use 3.3V FPM modules with Arduino Uno. The RX and TX lines have + resistors. + 2. When measuring current with the buck chips on, the servo doesn't respond. + So, the value measured probably doesn't include the current the servo + draws. + 3. N-channel high-side switching doesn't work without a 9V supply. 7.2V+ with + batteries don't work either. diff --git a/door_lock/fpm.c b/door_lock/fpm.c new file mode 100644 index 0000000..862b938 --- /dev/null +++ b/door_lock/fpm.c @@ -0,0 +1,297 @@ +#include + +#include "fpm.h" +#include "uart.h" + +#define MAXPDLEN 64 + +#define HEADER_HO 0xEF +#define HEADER_LO 0x01 +#define ADDR 0xFFFFFFFF + +#define OK 0x00 +#define PACKID 0x01 + +static inline uint8_t read(void) +{ + return uart_recv(); +} + +static inline void write(uint8_t c) +{ + uart_send(c); +} + +static inline void send(uint8_t *data, uint8_t n) +{ + int i; + uint16_t pktlen, sum; + + write(HEADER_HO); + write(HEADER_LO); + + write((uint8_t)(ADDR >> 24)); + write((uint8_t)(ADDR >> 16)); + write((uint8_t)(ADDR >> 8)); + write((uint8_t)(ADDR & 0xFF)); + + write(PACKID); + + pktlen = n + 2; + write((uint8_t)(pktlen >> 8)); + write((uint8_t)pktlen); + + sum = (pktlen >> 8) + (pktlen & 0xFF) + PACKID; + for (i = 0; i < n; i++) { + write(data[i]); + sum += data[i]; + } + + write((uint8_t)(sum >> 8)); + write((uint8_t)sum); +} + +static inline uint16_t recv(uint8_t buf[MAXPDLEN]) +{ + int i; + uint16_t len; + uint8_t byte; + + i = 0, len = 0; + + for (;;) { + byte = read(); + switch (i) { + case 0: + if (byte != HEADER_HO) + continue; + break; + case 1: + if (byte != HEADER_LO) + return 0; + case 2: + case 3: + case 4: + case 5: + // address + break; + case 6: + // packet id + break; + case 7: + len = (uint16_t)byte << 8; + break; + case 8: + len |= byte; + break; + default: + if ((i - 9) < MAXPDLEN) { + buf[i - 9] = byte; + if ((i - 8) == len) + return len; + } else + return 0; + break; + } + i++; + } + return 0; +} + +void fpm_led(LED_CTRL ctrl, LED_COLOR color, uint8_t count) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x35; + buf[1] = ctrl; + buf[2] = 0x60; + buf[3] = color; + buf[4] = count; + + send(buf, 5); + recv(buf); +} + +static inline uint8_t check_pwd(void) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x13; + buf[1] = (uint8_t)((uint32_t)FPM_PWD >> 24); + buf[2] = (uint8_t)((uint32_t)FPM_PWD >> 16); + buf[3] = (uint8_t)((uint32_t)FPM_PWD >> 8); + buf[4] = (uint8_t)((uint32_t)FPM_PWD & 0xFF); + + send(buf, 5); + recv(buf); + return buf[0] == OK; +} + +static inline uint8_t scan(void) +{ + uint16_t retries; + uint8_t buf[MAXPDLEN]; + + retries = 0; + fpm_led(BREATHE, PURPLE, 0); + + do { + buf[0] = 0x28; + send(buf, 1); + recv(buf); + if (buf[0] != OK) { + retries++; + _delay_ms(100); + } + } while(buf[0] != OK && retries < 100); + + fpm_led(GRAD_OFF, PURPLE, 0); + return buf[0] == OK; +} + +static inline uint8_t img2tz(uint8_t bufid) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x02; + buf[1] = bufid; + send(buf, 2); + recv(buf); + return buf[0] == OK; +} + +uint8_t fpm_init(void) +{ + return check_pwd(); +} + +uint8_t fpm_get_cfg(struct fpm_cfg *cfg) +{ + uint16_t n; + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x0F; + send(buf, 1); + n = recv(buf); + + if (buf[0] == OK && n >= 17) { + cfg->status = ((uint16_t)buf[1] << 8) | buf[2]; + cfg->sysid = ((uint16_t)buf[3] << 8) | buf[4]; + cfg->cap = ((uint16_t)buf[5] << 8) | buf[6]; + cfg->sec_level = ((uint16_t)buf[7] << 8) | buf[8]; + cfg->addr[0] = buf[9]; + cfg->addr[1] = buf[10]; + cfg->addr[2] = buf[11]; + cfg->addr[3] = buf[12]; + cfg->pkt_size = ((uint16_t)buf[13] << 8) | buf[14]; + cfg->pkt_size = 1 << (cfg->pkt_size + 5); + cfg->baud = (((uint16_t)buf[15] << 8) | buf[16]); + + return 1; + } + return 0; +} + +uint8_t fpm_set_pwd(uint32_t pwd) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x12; + buf[1] = (uint8_t)(pwd >> 24); + buf[2] = (uint8_t)(pwd >> 16); + buf[3] = (uint8_t)(pwd >> 8); + buf[4] = (uint8_t)(pwd & 0xFF); + + send(buf, 5); + recv(buf); + return buf[0] == OK; +} + +uint16_t fpm_get_count(void) +{ + uint16_t n, count; + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x1D; + send(buf, 1); + n = recv(buf); + + count = 0; + if (buf[0] == OK && n >= 2) { + count = buf[1]; + count <<= 8; + count |= buf[2]; + } + return count; +} + +uint8_t fpm_enroll(void) +{ + struct fpm_cfg cfg; + uint16_t n; + uint8_t buf[MAXPDLEN]; + + fpm_get_cfg(&cfg); + n = fpm_get_count() + 1; + if (n >= cfg.cap) + return 0; + + if (!scan()) + return 0; + + if (!img2tz(1)) + return 0; + + _delay_ms(2000); + + if (!scan()) + return 0; + + if (!img2tz(2)) + return 0; + + buf[0] = 0x05; + send(buf, 1); + recv(buf); + if (buf[0] != OK) + return 0; + + buf[0] = 0x06; + buf[1] = 1; + buf[2] = (uint8_t)(n >> 8); + buf[3] = (uint8_t)(n & 0xFF); + send(buf, 4); + recv(buf); + + return buf[0] == OK; +} + +uint16_t fpm_match(void) +{ + struct fpm_cfg cfg; + uint8_t buf[MAXPDLEN]; + + if (!fpm_get_cfg(&cfg)) + return 0; + + if (!scan()) + return 0; + + if (!img2tz(1)) + return 0; + + buf[0] = 0x04; + buf[1] = 1; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = (uint8_t)(cfg.cap >> 8); + buf[5] = (uint8_t)(cfg.cap & 0xFF); + + send(buf, 6); + recv(buf); + + if (buf[0] != OK) + return 0; + + return ((uint16_t)buf[1] << 8) | buf[2]; +} diff --git a/door_lock/fpm.h b/door_lock/fpm.h new file mode 100644 index 0000000..f424c56 --- /dev/null +++ b/door_lock/fpm.h @@ -0,0 +1,46 @@ +#ifndef FPM_R503_H +#define FPM_R503_H + +#include + +struct fpm_cfg { + uint16_t status; + uint16_t sysid; + uint16_t cap; + uint16_t sec_level; + uint8_t addr[4]; + uint16_t pkt_size; + uint16_t baud; +}; + +typedef enum { + NIL = 0x00, + RED = 0x01, + BLUE = 0x02, + PURPLE = 0x03 +} LED_COLOR; + +typedef enum { + BREATHE = 0x01, + FLASH = 0x02, + ON = 0x03, + OFF = 0x04, + GRAD_ON = 0x05, + GRAD_OFF = 0x06, +} LED_CTRL; + +uint8_t fpm_init(void); + +uint8_t fpm_get_cfg(struct fpm_cfg *cfg); + +uint8_t fpm_set_pwd(uint32_t pwd); + +uint16_t fpm_get_count(void); + +uint8_t fpm_enroll(void); + +uint16_t fpm_match(void); + +void fpm_led(LED_CTRL ctrl, LED_COLOR color, uint8_t count); + +#endif /* FPM_R50_H */ diff --git a/door_lock/main.c b/door_lock/main.c new file mode 100644 index 0000000..caab488 --- /dev/null +++ b/door_lock/main.c @@ -0,0 +1,287 @@ +#include +#include +#include +#include +#include + +#include "fpm.h" +#include "uart.h" + +#define BAT_MIN 5100 + +#define SRVO_PIN PB1 +#define SRVO_DDR DDRB + +#define PWM_MIN 500 +#define PWM_MID 1600 +#define PWM_MAX 2550 +#define PWM_TOP 19999 + +#define LED_FPM_PIN PD5 +#define LED_BACK_PIN PD6 +#define LED_DDR DDRD +#define LED_PORT PORTD + +#define PWR_BAT PB2 +#define PWR_SRVO PB3 +#define PWR_FPM PB4 +#define PWR_DDR DDRB +#define PWR_PORT PORTB + +#define FPM_UNLOCK_PIN PC1 /*back up for FPM's touch sensor */ +#define FPM_LOCK_PIN PC2 +#define ENROLL_PIN PC3 +#define BACK_LOCK_PIN PC4 +#define BACK_UNLOCK_PIN PC5 +#define INPUT_DDR DDRC +#define INPUT_PORT PORTC + +#define FPM_UNLOCK_INT PCINT9 +#define FPM_LOCK_INT PCINT10 +#define ENROLL_INT PCINT11 +#define BACK_LOCK_INT PCINT12 +#define BACK_UNLOCK_INT PCINT13 +#define INPUT_INT PCIE1 +#define INPUT_INT_MSK PCMSK1 +#define INPUT_INT_VEC PCINT1_vect + +enum CTRL { + NONE = 0, + LOCK_FPM = 1, + LOCK_BACK = 2, + UNLOCK_FPM = 3, + UNLOCK_BACK = 4, + UNLOCK_FPM_2 = 5, + ENROLL = 6 +}; + +static volatile enum CTRL cmd = NONE; + +static inline void pwron_bat(void) +{ + PWR_PORT &= ~(1 << PWR_BAT); +} + +static inline void pwroff_bat(void) +{ + PWR_PORT |= (1 << PWR_BAT); +} + +static inline void pwron_fpm(void) +{ + PWR_PORT &= ~(1 << PWR_FPM); + _delay_ms(50); +} + +static inline void pwroff_fpm(void) +{ + PWR_PORT |= (1 << PWR_FPM); +} + +static inline void pwron_srvo(void) +{ + PWR_PORT |= (1 << PWR_SRVO); +} + +static inline void pwroff_srvo(void) +{ + PWR_PORT &= ~(1 << PWR_SRVO); +} + +static inline void lock(void) +{ + pwron_srvo(); + OCR1A = PWM_MID; + _delay_ms(500); + pwroff_srvo(); +} + +static inline void unlock(void) +{ + pwron_srvo(); + OCR1A = PWM_MAX; + _delay_ms(500); + pwroff_srvo(); +} + +static inline void flash_led(void) +{ + TCCR0A = (1 << COM0A0) | (1 << COM0B0) | (1 << WGM01); + OCR0A = 255; + OCR0B = 255; + TCCR0B = (1 << CS02) | (1 << CS00); +} + +static inline void stop_led(void) +{ + TCCR0B = 0; + TCCR0A = 0; + LED_PORT &= ~((1 << LED_FPM_PIN) | (1 << LED_BACK_PIN)); +} + +static void check_bat(void) +{ + uint16_t vbg, vcc; + + pwron_bat(); + + ADMUX |= (1 << REFS1) | (1 << REFS0); + ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); /* clk: 50-200 kHz */ + + _delay_us(500); /* https://www.sciencetronics.com/greenphotons/?p=1521 */ + + ADCSRA |= (1 << ADSC); + while (ADCSRA & (1 << ADSC)) + ; + + ADCSRA &= ~(1 << ADEN); + vbg = (1100UL * ADC) / 1024; + ADCSRA &= ~(1 << ADEN); + + pwroff_bat(); + + vcc = (vbg * 66) / 10; /* 56k/10k divider */ + if (vcc < BAT_MIN) + flash_led(); +} + +int main(void) +{ + uint16_t id; + + /* disable wdt */ + cli(); + wdt_reset(); + MCUSR &= ~(1 << WDRF); + WDTCSR |= (1 << WDCE) | (1 << WDE); + WDTCSR = 0x00; + + PWR_DDR |= (1 << PWR_BAT) | (1 << PWR_FPM) | (1 << PWR_SRVO); + pwroff_bat(); + + uart_init(); + pwron_fpm(); + fpm_init(); + + /* servo */ + TCCR1A |= (1 << WGM11); + TCCR1B |= (1 << WGM12) | (1 << WGM13); + TCCR1B |= (1 << CS11); + ICR1 = PWM_TOP; + TCCR1A |= (1 << COM1A1); + SRVO_DDR |= (1 << SRVO_PIN); + + /* bat check */ + LED_DDR |= (1 << LED_FPM_PIN) | (1 << LED_BACK_PIN); + LED_PORT &= ~((1 << LED_FPM_PIN) | (1 << LED_BACK_PIN)); + + DDRD &= ~(1 << PD2); /* FPM unlock pin */ + PORTD |= (1 << PD2); /* FPM unlock pin internal pull-up */ + EICRA = 0b00000000; + EIMSK = (1 << INT0); /* FPM unlock interrupt */ + + INPUT_DDR &= ~((1 << FPM_LOCK_PIN) | (1 << FPM_UNLOCK_PIN) | + (1 << BACK_LOCK_PIN) | (1 << BACK_UNLOCK_PIN) | + (1 << ENROLL_PIN)); + + INPUT_PORT |= ((1 << FPM_LOCK_PIN) | (1 << FPM_UNLOCK_PIN) | + (1 << BACK_LOCK_PIN) | (1 << BACK_UNLOCK_PIN) | + (1 << ENROLL_PIN)); + + PCICR |= (1 << INPUT_INT); + INPUT_INT_MSK |= ((1 << FPM_LOCK_INT) | (1 << FPM_UNLOCK_INT) | + (1 << BACK_LOCK_INT) | (1 << BACK_UNLOCK_INT) | + (1 << ENROLL_INT)); + + for (;;) { + check_bat(); + + switch(cmd) { + case LOCK_FPM: + lock(); + fpm_led(FLASH, RED, 1); + break; + case LOCK_BACK: + lock(); + break; + case UNLOCK_FPM: + case UNLOCK_FPM_2: + if (fpm_match()) { + fpm_led(BREATHE, BLUE, 1); + unlock(); + } else { + fpm_led(BREATHE, RED, 1); + } + break; + case UNLOCK_BACK: + unlock(); + fpm_led(FLASH, BLUE, 1); + break; + case ENROLL: + id = fpm_match(); + if (id == 1 || id == 2) { + fpm_led(BREATHE, BLUE, 1); + _delay_ms(1000); + if (fpm_enroll()) + fpm_led(BREATHE, BLUE, 1); + else + fpm_led(BREATHE, RED, 1); + } + break; + default: + break; + } + + cmd = NONE; + _delay_ms(500); + + pwroff_fpm(); + stop_led(); + + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_enable(); + sleep_bod_disable(); + sei(); + sleep_cpu(); + + cli(); + sleep_disable(); + pwron_fpm(); + fpm_init(); + } + return 0; +} + +static inline int is_pressed(uint8_t btn) +{ + if (!((PINC >> btn) & 0x01)) { + _delay_ms(50); + return !((PINC >> btn) & 0x01); + } + return 0; +} + +ISR(INT0_vect) +{ + cmd = UNLOCK_FPM; +} + +ISR(INPUT_INT_VEC) +{ + cli(); + + if (is_pressed(FPM_LOCK_PIN)) + cmd = LOCK_FPM; + else if (is_pressed(FPM_UNLOCK_PIN)) + cmd = UNLOCK_FPM_2; + else if (is_pressed(BACK_LOCK_PIN)) + cmd = LOCK_BACK; + else if (is_pressed(BACK_UNLOCK_PIN)) + cmd = UNLOCK_BACK; + else if (is_pressed(ENROLL_PIN)) + cmd = ENROLL; + else + cmd = NONE; + + sei(); +} diff --git a/door_lock/uart.c b/door_lock/uart.c new file mode 100644 index 0000000..1a9956d --- /dev/null +++ b/door_lock/uart.c @@ -0,0 +1,31 @@ +#include +#include + +#include "uart.h" + +void uart_init(void) +{ + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; +#if USE_2X + UCSR0A |= (1 << U2X0); +#else + UCSR0A &= ~(1 << U2X0); +#endif + UCSR0B = (1 << TXEN0) | (1 << RXEN0); + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); +} + +uint8_t uart_recv(void) +{ + while (!(UCSR0A & (1 << RXC0))) + ; + return UDR0; +} + +void uart_send(uint8_t c) +{ + while (!(UCSR0A & (1 << UDRE0))) + ; + UDR0 = c; +} diff --git a/door_lock/uart.h b/door_lock/uart.h new file mode 100644 index 0000000..c5fc87e --- /dev/null +++ b/door_lock/uart.h @@ -0,0 +1,10 @@ +#ifndef UART_H +#define UART_H + +void uart_init(void); + +uint8_t uart_recv(void); + +void uart_send(uint8_t c); + +#endif /* UART_H */ diff --git a/door_lock_rfm/Client.Makefile b/door_lock_rfm/Client.Makefile new file mode 100644 index 0000000..a6758fd --- /dev/null +++ b/door_lock_rfm/Client.Makefile @@ -0,0 +1,46 @@ +CC = avr-gcc +MCU = atmega328p +PORT = /dev/cuaU0 +TARGET = client + +SRC = client.c fpm.c nrfm.c util.c +OBJ = $(SRC:.c=.o) + +CFLAGS = -std=gnu99 +CFLAGS += -Os +CFLAGS += -Wall +CFLAGS += -mmcu=$(MCU) +CFLAGS += -DBAUD=57600 +CFLAGS += -DF_CPU=16000000UL +CFLAGS += -DFPM_PWD=$(FPM_PWD) +CFLAGS += -ffunction-sections -fdata-sections + +LDFLAGS = -mmcu=$(MCU) +LDFLAGS += -Wl,--gc-sections + +HEX_FLAGS = -O ihex +HEX_FLAGS += -j .text -j .data + +AVRDUDE_FLAGS = -p $(MCU) +AVRDUDE_FLAGS += -c arduino +AVRDUDE_FLAGS += -P $(PORT) +AVRDUDE_FLAGS += -D -U + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +elf: $(OBJ) + $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf + +hex: elf + avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex + +upload: hex + avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i + +.PHONY: clean + +clean: + rm -f *.o *.elf *.hex + + diff --git a/door_lock_rfm/Server.Makefile b/door_lock_rfm/Server.Makefile new file mode 100644 index 0000000..f853a34 --- /dev/null +++ b/door_lock_rfm/Server.Makefile @@ -0,0 +1,44 @@ +CC = avr-gcc +MCU = atmega328p +PORT = /dev/cuaU0 +TARGET = server + +SRC = server.c nrfm.c util.c +OBJ = $(SRC:.c=.o) + +CFLAGS = -std=gnu99 +CFLAGS += -Os +CFLAGS += -Wall +CFLAGS += -mmcu=$(MCU) +CFLAGS += -DF_CPU=16000000UL +CFLAGS += -ffunction-sections -fdata-sections + +LDFLAGS = -mmcu=$(MCU) +LDFLAGS += -Wl,--gc-sections + +HEX_FLAGS = -O ihex +HEX_FLAGS += -j .text -j .data + +AVRDUDE_FLAGS = -p $(MCU) +AVRDUDE_FLAGS += -c arduino +AVRDUDE_FLAGS += -P $(PORT) +AVRDUDE_FLAGS += -D -U + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +elf: $(OBJ) + $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf + +hex: elf + avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex + +upload: hex + avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i + +.PHONY: clean + +clean: + rm -f *.o *.elf *.hex + + diff --git a/door_lock_rfm/client.c b/door_lock_rfm/client.c new file mode 100644 index 0000000..91fe040 --- /dev/null +++ b/door_lock_rfm/client.c @@ -0,0 +1,198 @@ +/* Lock front, connected to the fingerprint scanner */ + +#include +#include + +#include +#include +#include +#include + +#include "fpm.h" +#include "nrfm.h" +#include "util.h" + +#define LOCK_PIN PD3 +#define UNLOCK_PIN PD2 +#define ENROLL_PIN PD4 + +#define RX_IRQ_PIN PC0 +#define RX_DDR DDRC +#define RX_PIN PINC +#define RX_ICR PCICR +#define RX_IE PCIE1 +#define RX_INT PCINT8 +#define RX_MSK PCMSK1 +#define RX_INTVEC PCINT1_vect + +#define VCC_MIN 4000 + +static volatile uint8_t rxd = 0; +static volatile uint8_t sync = 0; +static volatile uint8_t islock = 0; +static volatile uint8_t isunlock = 0; + +static inline void wdt_off(void) +{ + cli(); + wdt_reset(); + MCUSR &= ~(1 << WDRF); + WDTCSR |= (1 << WDCE) | (1 << WDE); + WDTCSR = 0x00; +} + +static inline void init_rx(void) +{ + RX_DDR &= ~(1 << RX_IRQ_PIN); + RX_ICR |= (1 << RX_IE); + RX_MSK |= (1 << RX_INT); +} + +static inline void init_btns(void) +{ + DDRD &= ~((1 << LOCK_PIN) | (1 << UNLOCK_PIN) | (1 << ENROLL_PIN)); + PORTD |= ((1 << LOCK_PIN) | (1 << UNLOCK_PIN) | (1 << ENROLL_PIN)); + + EICRA = 0b00000000; + EIMSK = (1 << INT0) | (1 << INT1); + + PCICR |= (1 << PCIE2); + PCMSK2 |= (1 << PCINT20); +} + +static inline void fpm_ok(void) +{ + fpm_led_on(BLUE); + _delay_ms(500); + fpm_led_off(); +} + +static inline void fpm_nok(void) +{ + fpm_led_on(RED); + _delay_ms(500); + fpm_led_off(); +} + +int main(void) +{ + int i, retries; + uint8_t rxaddr[ADDRLEN] = { 194, 178, 82 }; + uint8_t txaddr[ADDRLEN] = { 194, 178, 83 }; + + char buf[WDLEN], key[WDLEN]; + + wdt_off(); + led_init(); + + fpm_init(); + if (fpm_get_count() == 0) + fpm_enroll(); + + init_rx(); + init_btns(); + + radio_init(rxaddr); + + sei(); + radio_listen(); + + for (;;) { + if (!sync && (islock || isunlock)) { + if (isunlock) { + if (!fpm_match()) { + isunlock = 0; + fpm_nok(); + continue; + } + else + fpm_ok(); + } + + xor(KEY, SYN, buf, WDLEN); + retries = 0; + do { + sync = radio_sendto(txaddr, buf, WDLEN); + retries++; + } while (!sync && retries < 2); + + if (!sync) { + islock = 0; + isunlock = 0; + } + } + + if (rxd) { + radio_recv(buf, WDLEN); + rxd = 0; + if (sync && (islock || isunlock)) { + sync = 0; + xor(KEY, buf, key, WDLEN); + if (islock) { + islock = 0; + xor(key, LOCK, buf, WDLEN); + if (radio_sendto(txaddr, buf, WDLEN)) + led_locked(); + } else if (isunlock) { + isunlock = 0; + xor(key, UNLOCK, buf, WDLEN); + if (radio_sendto(txaddr, buf, WDLEN)) + led_unlocked(); + } + } + } + + if (!sync) { + if (getvcc() < VCC_MIN) { + for (i = 0; i < 5; i++) { + led_bat(); + _delay_ms(100); + } + } + + radio_pwr_dwn(); + sleep_bod_disable(); + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_mode(); + radio_listen(); + } + } + return 0; +} + +ISR(RX_INTVEC) +{ + if (!(RX_PIN & (1 << RX_IRQ_PIN))) + rxd = 1; +} + +ISR(INT0_vect) +{ + sync = 0; + isunlock = 1; +} + +ISR(INT1_vect) +{ + if (is_btn_pressed(PIND, LOCK_PIN)) { + sync = 0; + islock = 1; + } +} + +ISR(PCINT2_vect) +{ + uint16_t id; + + if (is_btn_pressed(PIND, ENROLL_PIN)) { + id = fpm_match(); + if (id == 1 || id == 2) { + fpm_ok(); + _delay_ms(1000); + if (fpm_enroll()) + fpm_ok(); + } else + fpm_nok(); + } +} + diff --git a/door_lock_rfm/fpm.c b/door_lock_rfm/fpm.c new file mode 100644 index 0000000..73a175a --- /dev/null +++ b/door_lock_rfm/fpm.c @@ -0,0 +1,324 @@ +#include +#include +#include + +#include "fpm.h" + +#define MAXPDLEN 64 +#define RST_DELAY_MS 500 + +#define HEADER_HO 0xEF +#define HEADER_LO 0x01 +#define ADDR 0xFFFFFFFF + +#define OK 0x00 +#define PACKID 0x01 + +static inline uint8_t read(void) +{ + while (!(UCSR0A & (1 << RXC0))) + ; + return UDR0; +} + +static inline void write(uint8_t c) +{ + while (!(UCSR0A & (1 << UDRE0))) + ; + UDR0 = c; +} + +static inline void send(uint8_t *data, uint8_t n) +{ + int i; + uint16_t pktlen, sum; + + write(HEADER_HO); + write(HEADER_LO); + + write((uint8_t)(ADDR >> 24)); + write((uint8_t)(ADDR >> 16)); + write((uint8_t)(ADDR >> 8)); + write((uint8_t)(ADDR & 0xFF)); + + write(PACKID); + + pktlen = n + 2; + write((uint8_t)(pktlen >> 8)); + write((uint8_t)pktlen); + + sum = (pktlen >> 8) + (pktlen & 0xFF) + PACKID; + for (i = 0; i < n; i++) { + write(data[i]); + sum += data[i]; + } + + write((uint8_t)(sum >> 8)); + write((uint8_t)sum); +} + +static inline uint16_t recv(uint8_t buf[MAXPDLEN]) +{ + int i; + uint16_t len; + uint8_t byte; + + i = 0, len = 0; + + for (;;) { + byte = read(); + switch (i) { + case 0: + if (byte != HEADER_HO) + continue; + break; + case 1: + if (byte != HEADER_LO) + return 0; + case 2: + case 3: + case 4: + case 5: + // toss address + break; + case 6: + // toss packet id + break; + case 7: + len = (uint16_t)byte << 8; + break; + case 8: + len |= byte; + break; + default: + if ((i - 9) < MAXPDLEN) { + buf[i - 9] = byte; + if ((i - 8) == len) + return len; + } else + return 0; + break; + } + i++; + } + return 0; +} + +static inline void led_ctrl(uint8_t mode, COLOR color) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x35; + buf[1] = mode; + buf[2] = 0x60; + buf[3] = color; + buf[4] = 0x00; + + send(buf, 5); + recv(buf); +} + +static inline uint8_t check_pwd(void) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x13; + buf[1] = (uint8_t)((uint32_t)FPM_PWD >> 24); + buf[2] = (uint8_t)((uint32_t)FPM_PWD >> 16); + buf[3] = (uint8_t)((uint32_t)FPM_PWD >> 8); + buf[4] = (uint8_t)((uint32_t)FPM_PWD & 0xFF); + + send(buf, 5); + recv(buf); + return buf[0] == OK; +} + +static inline uint8_t scan(void) +{ + uint16_t retries; + uint8_t buf[MAXPDLEN]; + + retries = 0; + led_ctrl(0x01, PURPLE); + + do { + buf[0] = 0x28; + send(buf, 1); + recv(buf); + if (buf[0] != OK) { + retries++; + _delay_ms(100); + } + } while(buf[0] != OK && retries < 100); + + led_ctrl(0x06, PURPLE); + return buf[0] == OK; +} + +static inline uint8_t img2tz(uint8_t bufid) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x02; + buf[1] = bufid; + send(buf, 2); + recv(buf); + return buf[0] == OK; +} + +void fpm_led_on(COLOR color) +{ + led_ctrl(0x03, color); +} + +void fpm_led_off(void) +{ + led_ctrl(0x04, 0x00); +} + +uint8_t fpm_init(void) +{ + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; +#if USE_2X + UCSR0A |= (1 << U2X0); +#else + UCSR0A &= ~(1 << U2X0); +#endif + UCSR0B = (1 << TXEN0) | (1 << RXEN0); + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); + + _delay_ms(RST_DELAY_MS); + return check_pwd(); +} + +uint8_t fpm_get_cfg(struct fpm_cfg *cfg) +{ + uint16_t n; + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x0F; + send(buf, 1); + n = recv(buf); + + if (buf[0] == OK && n >= 17) { + cfg->status = ((uint16_t)buf[1] << 8) | buf[2]; + cfg->sysid = ((uint16_t)buf[3] << 8) | buf[4]; + cfg->cap = ((uint16_t)buf[5] << 8) | buf[6]; + cfg->sec_level = ((uint16_t)buf[7] << 8) | buf[8]; + cfg->addr[0] = buf[9]; + cfg->addr[1] = buf[10]; + cfg->addr[2] = buf[11]; + cfg->addr[3] = buf[12]; + cfg->pkt_size = ((uint16_t)buf[13] << 8) | buf[14]; + cfg->pkt_size = 1 << (cfg->pkt_size + 5); + cfg->baud = (((uint16_t)buf[15] << 8) | buf[16]); + + return 1; + } + return 0; +} + +uint8_t fpm_set_pwd(uint32_t pwd) +{ + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x12; + buf[1] = (uint8_t)(pwd >> 24); + buf[2] = (uint8_t)(pwd >> 16); + buf[3] = (uint8_t)(pwd >> 8); + buf[4] = (uint8_t)(pwd & 0xFF); + + send(buf, 5); + recv(buf); + return buf[0] == OK; +} + +uint16_t fpm_get_count(void) +{ + uint16_t n, count; + uint8_t buf[MAXPDLEN]; + + buf[0] = 0x1D; + send(buf, 1); + n = recv(buf); + + count = 0; + if (buf[0] == OK && n >= 2) { + count = buf[1]; + count <<= 8; + count |= buf[2]; + } + return count; +} + +uint8_t fpm_enroll(void) +{ + struct fpm_cfg cfg; + uint16_t n; + uint8_t buf[MAXPDLEN]; + + fpm_get_cfg(&cfg); + n = fpm_get_count() + 1; + if (n >= cfg.cap) + return 0; + + if (!scan()) + return 0; + + if (!img2tz(1)) + return 0; + + _delay_ms(2000); + + if (!scan()) + return 0; + + if (!img2tz(2)) + return 0; + + buf[0] = 0x05; + send(buf, 1); + recv(buf); + if (buf[0] != OK) + return 0; + + buf[0] = 0x06; + buf[1] = 1; + buf[2] = (uint8_t)(n >> 8); + buf[3] = (uint8_t)(n & 0xFF); + send(buf, 4); + recv(buf); + + return buf[0] == OK; +} + +uint16_t fpm_match(void) +{ + struct fpm_cfg cfg; + uint8_t buf[MAXPDLEN]; + + if (!fpm_get_cfg(&cfg)) + return 0; + + if (!scan()) + return 0; + + if (!img2tz(1)) + return 0; + + buf[0] = 0x04; + buf[1] = 1; + buf[2] = 0x00; + buf[3] = 0x00; + buf[4] = (uint8_t)(cfg.cap >> 8); + buf[5] = (uint8_t)(cfg.cap & 0xFF); + + send(buf, 6); + recv(buf); + + if (buf[0] != OK) + return 0; + + return ((uint16_t)buf[1] << 8) | buf[2]; +} diff --git a/door_lock_rfm/fpm.h b/door_lock_rfm/fpm.h new file mode 100644 index 0000000..31f53eb --- /dev/null +++ b/door_lock_rfm/fpm.h @@ -0,0 +1,38 @@ +#ifndef FPM_R503_H +#define FPM_R503_H + +#include + +struct fpm_cfg { + uint16_t status; + uint16_t sysid; + uint16_t cap; + uint16_t sec_level; + uint8_t addr[4]; + uint16_t pkt_size; + uint16_t baud; +}; + +typedef enum { + RED = 0x01, + BLUE = 0x02, + PURPLE = 0x03 +} COLOR; + +uint8_t fpm_init(void); + +uint8_t fpm_get_cfg(struct fpm_cfg *cfg); + +uint8_t fpm_set_pwd(uint32_t pwd); + +void fpm_led_on(COLOR color); + +void fpm_led_off(void); + +uint16_t fpm_get_count(void); + +uint8_t fpm_enroll(void); + +uint16_t fpm_match(void); + +#endif /* FPM_R50_H */ diff --git a/door_lock_rfm/nrfm.c b/door_lock_rfm/nrfm.c new file mode 100644 index 0000000..d1bb5c3 --- /dev/null +++ b/door_lock_rfm/nrfm.c @@ -0,0 +1,303 @@ +#include +#include + +#include +#include +#include + +#include "nrfm.h" + +#define SPI_SS PB2 +#define SPI_SCK PB5 +#define SPI_MISO PB4 +#define SPI_MOSI PB3 +#define SPI_DDR DDRB +#define SPI_PORT PORTB + +#define NRF_CE PC1 +#define NRF_CE_DDR DDRC +#define NRF_CE_PORT PORTC + +#define NOP 0xFF +#define R_REGISTER 0x1F +#define W_REGISTER 0x20 + +#define PWR_UP 1 +#define PRIM_RX 0 + +#define MODCHG_DELAY_MS 5 + +#define LEN(a) (sizeof(a) / sizeof(a[0])) + +const char *bittab[16] = { + [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011", + [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111", + [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011", + [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111", +}; + +static inline uint8_t read_reg(uint8_t reg) +{ + SPI_PORT &= ~(1 << SPI_SS); + SPDR = reg & R_REGISTER; + while (!(SPSR & (1 << SPIF))) + ; + SPDR = NOP; + while (!(SPSR & (1 << SPIF))) + ; + SPI_PORT |= (1 << SPI_SS); + return SPDR; +} + +static inline void write_reg(uint8_t reg, uint8_t val) +{ + SPI_PORT &= ~(1 << SPI_SS); + SPDR = (reg & 0x1F) | W_REGISTER; + while (!(SPSR & (1 << SPIF))) + ; + SPDR = val; + while (!(SPSR & (1 << SPIF))) + ; + SPI_PORT |= (1 << SPI_SS); +} + +static inline void read_reg_bulk(uint8_t reg, uint8_t *data, uint8_t n) +{ + uint8_t i; + + SPI_PORT &= ~(1 << SPI_SS); + SPDR = reg & R_REGISTER; + while (!(SPSR & (1 << SPIF))) + ; + for (i = 0; i < n; i++) { + SPDR = NOP; + while (!(SPSR & (1 << SPIF))) + ; + data[i] = SPDR; + } + SPI_PORT |= (1 << SPI_SS); +} + +static inline void setaddr(uint8_t reg, const uint8_t addr[ADDRLEN]) +{ + int i; + + SPI_PORT &= ~(1 << SPI_SS); + SPDR = (reg & 0x1F) | W_REGISTER; + while (!(SPSR & (1 << SPIF))) + ; + for (i = ADDRLEN - 1; i >= 0; i--) { + SPDR = addr[i]; + while (!(SPSR & (1 << SPIF))) + ; + } + SPI_PORT |= (1 << SPI_SS); +} + +static inline void reset_irqs(void) +{ + uint8_t rv; + + rv = read_reg(0x07); + if (rv != 0b00001110) + write_reg(0x07, 0b01111110); +} + +static inline void tx_mode(void) +{ + uint8_t rv; + + rv = read_reg(0x00); + if ((rv & 0x03) != 0x02) { + rv |= (1 << PWR_UP); + rv &= ~(1 << PRIM_RX); + write_reg(0x00, rv); + _delay_ms(MODCHG_DELAY_MS); + } +} + +static inline void rx_mode(void) +{ + uint8_t rv; + + rv = read_reg(0x00); + if ((rv & 0x03) != 0x02) { + rv |= (1 << PWR_UP); + rv |= (1 << PRIM_RX); + write_reg(0x00, rv); + _delay_ms(MODCHG_DELAY_MS); + } +} + +static inline void enable_chip(void) +{ + NRF_CE_PORT |= (1 << NRF_CE); + _delay_us(130); +} + +static inline void disable_chip(void) +{ + NRF_CE_PORT &= ~(1 << NRF_CE); +} + +static inline void flush_tx(void) +{ + SPI_PORT &= ~(1 << SPI_SS); + SPDR = 0b11100001; + while (!(SPSR & (1 << SPIF))) + ; + SPI_PORT |= (1 << SPI_SS); + + reset_irqs(); +} + +void radio_flush_rx(void) +{ + SPI_PORT &= ~(1 << SPI_SS); + SPDR = 0b11100010; + while (!(SPSR & (1 << SPIF))) + ; + SPI_PORT |= (1 << SPI_SS); + + reset_irqs(); +} + +static inline uint8_t rx_pdlen(void) +{ + SPI_PORT &= ~(1 << SPI_SS); + SPDR = 0b01100000; + while (!(SPSR & (1 << SPIF))) + ; + SPDR = NOP; + while (!(SPSR & (1 << SPIF))) + ; + SPI_PORT |= (1 << SPI_SS); + return SPDR; +} + +void radio_init(const uint8_t rxaddr[ADDRLEN]) +{ + SPI_DDR |= (1 << SPI_SS) | (1 << SPI_SCK) | (1 << SPI_MOSI); + SPI_PORT |= (1 << SPI_SS); + SPCR |= (1 << SPE) | (1 << MSTR); + + NRF_CE_DDR |= (1 << NRF_CE); + NRF_CE_PORT &= ~(1 << NRF_CE); + + _delay_ms(110); /* power on reset delay */ + + write_reg(0x00, 0b00111100); /* use 2-byte CRC, enable only the rx interrupt */ + write_reg(0x01, 0b00111111); /* enable auto ack on all pipes */ + write_reg(0x02, 0b00000011); /* enable rx address on pipes 0 and 1 */ + write_reg(0x03, 0b00000001); /* set address width to 3 bytes */ + write_reg(0x04, 0b11111111); /* 4000uS retransmission delay, 15 tries */ + write_reg(0x05, 0b01110011); /* use 2.515GHz channel */ + write_reg(0x06, 0b00001110); /* set data rate to 1Mbps */ + write_reg(0x1D, 0b00000100); /* enable dynamic payload length */ + write_reg(0x1C, 0b00111111); /* enable dynamic payload length for all pipes */ + + reset_irqs(); + setaddr(0x0B, rxaddr); /* pipe 1 for rx, pipe 0 for auto-ack */ +} + +void radio_listen(void) +{ + disable_chip(); + rx_mode(); + enable_chip(); +} + +void radio_pwr_dwn(void) +{ + uint8_t rv; + + disable_chip(); + rv = read_reg(0x00); + rv &= ~(1 << PWR_UP); + write_reg(0x00, rv); +} + +uint8_t radio_sendto(const uint8_t addr[ADDRLEN], const char *msg, uint8_t n) +{ + int i, imax; + uint8_t cfg, rv, maxrt, txds; + + disable_chip(); + + cfg = read_reg(0x00); + + tx_mode(); + flush_tx(); + + setaddr(0x10, addr); + setaddr(0x0A, addr); + + imax = n < MAXPDLEN ? n : MAXPDLEN; + + SPI_PORT &= ~(1 << SPI_SS); + SPDR = 0b10100000; + while (!(SPSR & (1 << SPIF))) + ; + for (i = 0; i < imax; i++) { + SPDR = msg[i]; + while (!(SPSR & (1 << SPIF))) + ; + } + SPI_PORT |= (1 << SPI_SS); + + enable_chip(); + _delay_us(12); + disable_chip(); + + txds = 0, maxrt = 0; + do { + rv = read_reg(0x07); + txds = rv & (1 << 5); + maxrt = rv & (1 << 4); + } while (txds == 0 && maxrt == 0); + + if (maxrt) + flush_tx(); + + // restore config, typically rx mode + write_reg(0x00, cfg); + enable_chip(); + return txds; +} + +uint8_t radio_recv(char *buf, uint8_t n) +{ + int readlen, pdlen, readmax; + + pdlen = 0; + disable_chip(); + + pdlen = rx_pdlen(); + if (pdlen == 0) { + radio_flush_rx(); + return 0; + } + + if (pdlen > MAXPDLEN) { + radio_flush_rx(); + return 0; + } + + readmax = n < pdlen ? n : pdlen; + + SPI_PORT &= ~(1 << SPI_SS); + SPDR = 0b01100001; + while (!(SPSR & (1 << SPIF))) + ; + for (readlen = 0; readlen < readmax; readlen++) { + SPDR = NOP; + while (!(SPSR & (1 << SPIF))) + ; + buf[readlen] = SPDR; + } + SPI_PORT |= (1 << SPI_SS); + + radio_flush_rx(); + enable_chip(); + return readlen; +} diff --git a/door_lock_rfm/nrfm.h b/door_lock_rfm/nrfm.h new file mode 100644 index 0000000..52d4edb --- /dev/null +++ b/door_lock_rfm/nrfm.h @@ -0,0 +1,21 @@ +#ifndef NRFM_H +#define NRFM_H + +#include + +#define ADDRLEN 3 +#define MAXPDLEN 32 + +void radio_init(const uint8_t rxaddr[ADDRLEN]); + +void radio_listen(void); + +void radio_pwr_dwn(void); + +uint8_t radio_recv(char *buf, uint8_t n); + +void radio_flush_rx(void); + +uint8_t radio_sendto(const uint8_t addr[ADDRLEN], const char *msg, uint8_t n); + +#endif /* NRFM_H */ diff --git a/door_lock_rfm/server.c b/door_lock_rfm/server.c new file mode 100644 index 0000000..6d51c00 --- /dev/null +++ b/door_lock_rfm/server.c @@ -0,0 +1,191 @@ +/* Lock back, connected to the servo */ + +#include +#include + +#include +#include +#include +#include + +#include "nrfm.h" +#include "util.h" + +#define PWM_MIN 500 +#define PWM_MID 1500 +#define PWM_MAX 2500 +#define PWM_TOP 20000 + +#define SERVO_PIN PB1 +#define LOCK_PIN PD3 +#define UNLOCK_PIN PD4 + +#define RX_IRQ_PIN PC0 +#define RX_DDR DDRC +#define RX_PIN PINC +#define RX_ICR PCICR +#define RX_IE PCIE1 +#define RX_INT PCINT8 +#define RX_MSK PCMSK1 +#define RX_INTVEC PCINT1_vect + +#define VCC_MIN 4000 + +static char tab[] = { + '0', '8', '3', '6', 'a', 'Z', '$', '4', 'v', 'R', '@', + 'E', '1', 'o', '#', ')', '2', '5', 'q', ';', '.', 'I', + 'c', '7', '9', '*', 'L', 'V', '&', 'k', 'K', '!', 'm', + 'N', '(', 'O', 'Q', 'A', '>', 'T', 't', '?', 'S', 'h', + 'w', '/', 'n', 'W', 'l', 'M', 'e', 'H', 'j', 'g', '[', + 'P', 'f', ':', 'B', ']', 'Y', '^', 'F', '%', 'C', 'x' +}; + +static volatile uint8_t rxd = 0; +static uint16_t tablen = sizeof(tab) / sizeof(tab[0]); + +static inline void keygen(char *buf, uint8_t n) +{ + int i, imax; + uint8_t sreg; + uint16_t seed; + + sreg = SREG; + cli(); + seed = TCNT1; + SREG = sreg; + + for (i = 0, imax = n - 1; i < imax; i++, seed++) + buf[i] = tab[(seed % tablen)]; + buf[imax] = '\0'; +} + +static inline void keydel(char *buf, uint8_t n) +{ + int i; + + for (i = 0; i < n; i++) + buf[i] = 0; +} + +static inline void init_wdt(void) +{ + cli(); + wdt_reset(); + + WDTCSR |= (1 << WDCE) | ( 1 << WDE); + WDTCSR = (1 << WDE) | (1 << WDP1); /* reset after 64ms */ +} + +static inline void init_rx(void) +{ + RX_DDR &= ~(1 << RX_IRQ_PIN); + RX_ICR |= (1 << RX_IE); + RX_MSK |= (1 << RX_INT); +} + +static inline void init_btns(void) +{ + DDRD &= ~((1 << LOCK_PIN) | (1 << UNLOCK_PIN)); + PORTD |= ((1 << LOCK_PIN) | (1 << UNLOCK_PIN)); + + EICRA = 0b00000000; + EIMSK = (1 << INT1); + + PCICR |= (1 << PCIE2); + PCMSK2 |= (1 << PCINT20); +} + +static inline void init_servo(void) +{ + ICR1 = PWM_TOP; + TCCR1A |= (1 << WGM11) | (1 << COM1A1); + TCCR1B |= (1 << WGM13) | (1 << CS11); + + DDRB |= (1 << SERVO_PIN); +} + +static inline void lock(void) +{ + OCR1A = PWM_MID; + _delay_ms(100); + OCR1A = PWM_TOP; +} + +static inline void unlock(void) +{ + OCR1A = PWM_MAX - 50; + _delay_ms(100); + OCR1A = PWM_TOP; +} + +int main(void) +{ + uint8_t rxaddr[ADDRLEN] = { 194, 178, 83 }; + uint8_t txaddr[ADDRLEN] = { 194, 178, 82 }; + + char buf[WDLEN], key[WDLEN], msg[WDLEN]; + + init_wdt(); + init_rx(); + init_btns(); + init_servo(); + + led_init(); + radio_init(rxaddr); + + sei(); + radio_listen(); + + for (;;) { + if (rxd) { + radio_recv(buf, WDLEN); + rxd = 0; + xor(KEY, buf, msg, WDLEN); + if (memcmp(msg, SYN, WDLEN) == 0) { + keygen(key, WDLEN); + xor(KEY, key, buf, WDLEN); + radio_sendto(txaddr, buf, WDLEN); + } else { + xor(key, buf, msg, WDLEN); + if (memcmp(msg, LOCK, WDLEN) == 0) { + lock(); + keydel(key, WDLEN); + } else if (memcmp(msg, UNLOCK, WDLEN) == 0) { + unlock(); + keydel(key, WDLEN); + } + } + } else { + radio_pwr_dwn(); + if (getvcc() < VCC_MIN) + led_bat(); + sleep_bod_disable(); + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_mode(); + } + } + return 0; +} + +ISR(RX_INTVEC) +{ + if (!(RX_PIN & (1 << RX_IRQ_PIN))) + rxd = 1; +} + +ISR(INT1_vect) +{ + if (is_btn_pressed(PIND, LOCK_PIN)) { + lock(); + led_locked(); + } +} + +ISR(PCINT2_vect) +{ + if (is_btn_pressed(PIND, UNLOCK_PIN)) { + unlock(); + led_unlocked(); + } +} + diff --git a/door_lock_rfm/uart.h b/door_lock_rfm/uart.h new file mode 100644 index 0000000..a88a3c6 --- /dev/null +++ b/door_lock_rfm/uart.h @@ -0,0 +1,8 @@ +#ifndef UART_H +#define UART_H + +void uart_init(void); +void uart_write(const char *s); +void uart_write_line(const char *s); + +#endif /* UART_H */ diff --git a/door_lock_rfm/util.c b/door_lock_rfm/util.c new file mode 100644 index 0000000..ec5369e --- /dev/null +++ b/door_lock_rfm/util.c @@ -0,0 +1,89 @@ +#include +#include +#include + +#include "util.h" + +#define LOCK_LED PC3 +#define UNLOCK_LED PC4 +#define BATLOW_LED PC5 +#define LED_DDR DDRC +#define LED_PORT PORTC + +int is_btn_pressed(uint8_t pin, uint8_t btn) +{ + if (!((pin >> btn) & 0x01)) { + _delay_ms(100); + return !((pin >> btn) & 0x01); + } + return 0; +} + +void xor(const char *k, const char *s, char *d, uint8_t n) +{ + int i; + + for (i = 0; i < n; i++) + d[i] = s[i] ^ k[i]; +} + +/* Measure vcc by measuring known internal 1.1v bandgap + * reference voltage against AVCC. + * Place a 100nF bypass capacitor on AREF. + */ +uint16_t getvcc(void) +{ + uint16_t vcc; + + ADMUX |= (1 << REFS0); + ADMUX |= (1 << MUX3) | (1 << MUX2) | (1 << MUX1); + ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0); + + // https://www.sciencetronics.com/greenphotons/?p=1521 + _delay_us(500); + + ADCSRA |= (1 << ADSC); + while (ADCSRA & (1 << ADSC)) + ; + vcc = (1100UL * 1023 / ADC); + + ADCSRA &= ~(1 << ADEN); + return vcc; +} + +void led_init(void) +{ + LED_DDR |= (1 << LOCK_LED) | (1 << UNLOCK_LED); + LED_DDR |= (1 << BATLOW_LED); + + LED_PORT &= ~(1 << LOCK_LED); + LED_PORT &= ~(1 << UNLOCK_LED); + LED_PORT &= ~(1 << BATLOW_LED); +} + +void led_locked(void) +{ + LED_PORT |= (1 << LOCK_LED); + _delay_ms(100); + LED_PORT &= ~(1 << LOCK_LED); + _delay_ms(100); + LED_PORT |= (1 << LOCK_LED); + _delay_ms(100); + LED_PORT &= ~(1 << LOCK_LED); +} + +void led_unlocked(void) +{ + LED_PORT |= (1 << UNLOCK_LED); + _delay_ms(70); + LED_PORT &= ~(1 << UNLOCK_LED); + _delay_ms(70); + LED_PORT |= (1 << UNLOCK_LED); + _delay_ms(70); + LED_PORT &= ~(1 << UNLOCK_LED); +} + +void led_bat(void) +{ + LED_PORT ^= (1 << BATLOW_LED); +} diff --git a/door_lock_rfm/util.h b/door_lock_rfm/util.h new file mode 100644 index 0000000..84584aa --- /dev/null +++ b/door_lock_rfm/util.h @@ -0,0 +1,27 @@ +#ifndef MY_UTIL_H +#define MY_UTIL_H + +#include + +#define KEY "dM>}jdb,6gsnC$J^K 8(I5vyPemPs%;K" +#define SYN "dM>}jdb,6gsnC$J^K 8(I5vyPemPs%;O" +#define LOCK "R,I7l^E4j]KyLR9'*Q{Jd'zu.~!84}Ij" +#define UNLOCK "R,I7l^E4j]KyLR9'*Q{Jd'zu.~!84}IL" + +#define WDLEN 32 + +int is_btn_pressed(uint8_t pin, uint8_t btn); + +void xor(const char *k, const char *s, char *d, uint8_t n); + +uint16_t getvcc(void); + +void led_init(void); + +void led_locked(void); + +void led_unlocked(void); + +void led_bat(void); + +#endif /* MY_UTIL_H */ diff --git a/lock/Client.Makefile b/lock/Client.Makefile deleted file mode 100644 index a6758fd..0000000 --- a/lock/Client.Makefile +++ /dev/null @@ -1,46 +0,0 @@ -CC = avr-gcc -MCU = atmega328p -PORT = /dev/cuaU0 -TARGET = client - -SRC = client.c fpm.c nrfm.c util.c -OBJ = $(SRC:.c=.o) - -CFLAGS = -std=gnu99 -CFLAGS += -Os -CFLAGS += -Wall -CFLAGS += -mmcu=$(MCU) -CFLAGS += -DBAUD=57600 -CFLAGS += -DF_CPU=16000000UL -CFLAGS += -DFPM_PWD=$(FPM_PWD) -CFLAGS += -ffunction-sections -fdata-sections - -LDFLAGS = -mmcu=$(MCU) -LDFLAGS += -Wl,--gc-sections - -HEX_FLAGS = -O ihex -HEX_FLAGS += -j .text -j .data - -AVRDUDE_FLAGS = -p $(MCU) -AVRDUDE_FLAGS += -c arduino -AVRDUDE_FLAGS += -P $(PORT) -AVRDUDE_FLAGS += -D -U - -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $< - -elf: $(OBJ) - $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf - -hex: elf - avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex - -upload: hex - avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i - -.PHONY: clean - -clean: - rm -f *.o *.elf *.hex - - diff --git a/lock/Server.Makefile b/lock/Server.Makefile deleted file mode 100644 index f853a34..0000000 --- a/lock/Server.Makefile +++ /dev/null @@ -1,44 +0,0 @@ -CC = avr-gcc -MCU = atmega328p -PORT = /dev/cuaU0 -TARGET = server - -SRC = server.c nrfm.c util.c -OBJ = $(SRC:.c=.o) - -CFLAGS = -std=gnu99 -CFLAGS += -Os -CFLAGS += -Wall -CFLAGS += -mmcu=$(MCU) -CFLAGS += -DF_CPU=16000000UL -CFLAGS += -ffunction-sections -fdata-sections - -LDFLAGS = -mmcu=$(MCU) -LDFLAGS += -Wl,--gc-sections - -HEX_FLAGS = -O ihex -HEX_FLAGS += -j .text -j .data - -AVRDUDE_FLAGS = -p $(MCU) -AVRDUDE_FLAGS += -c arduino -AVRDUDE_FLAGS += -P $(PORT) -AVRDUDE_FLAGS += -D -U - -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $< - -elf: $(OBJ) - $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf - -hex: elf - avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex - -upload: hex - avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i - -.PHONY: clean - -clean: - rm -f *.o *.elf *.hex - - diff --git a/lock/client.c b/lock/client.c deleted file mode 100644 index 91fe040..0000000 --- a/lock/client.c +++ /dev/null @@ -1,198 +0,0 @@ -/* Lock front, connected to the fingerprint scanner */ - -#include -#include - -#include -#include -#include -#include - -#include "fpm.h" -#include "nrfm.h" -#include "util.h" - -#define LOCK_PIN PD3 -#define UNLOCK_PIN PD2 -#define ENROLL_PIN PD4 - -#define RX_IRQ_PIN PC0 -#define RX_DDR DDRC -#define RX_PIN PINC -#define RX_ICR PCICR -#define RX_IE PCIE1 -#define RX_INT PCINT8 -#define RX_MSK PCMSK1 -#define RX_INTVEC PCINT1_vect - -#define VCC_MIN 4000 - -static volatile uint8_t rxd = 0; -static volatile uint8_t sync = 0; -static volatile uint8_t islock = 0; -static volatile uint8_t isunlock = 0; - -static inline void wdt_off(void) -{ - cli(); - wdt_reset(); - MCUSR &= ~(1 << WDRF); - WDTCSR |= (1 << WDCE) | (1 << WDE); - WDTCSR = 0x00; -} - -static inline void init_rx(void) -{ - RX_DDR &= ~(1 << RX_IRQ_PIN); - RX_ICR |= (1 << RX_IE); - RX_MSK |= (1 << RX_INT); -} - -static inline void init_btns(void) -{ - DDRD &= ~((1 << LOCK_PIN) | (1 << UNLOCK_PIN) | (1 << ENROLL_PIN)); - PORTD |= ((1 << LOCK_PIN) | (1 << UNLOCK_PIN) | (1 << ENROLL_PIN)); - - EICRA = 0b00000000; - EIMSK = (1 << INT0) | (1 << INT1); - - PCICR |= (1 << PCIE2); - PCMSK2 |= (1 << PCINT20); -} - -static inline void fpm_ok(void) -{ - fpm_led_on(BLUE); - _delay_ms(500); - fpm_led_off(); -} - -static inline void fpm_nok(void) -{ - fpm_led_on(RED); - _delay_ms(500); - fpm_led_off(); -} - -int main(void) -{ - int i, retries; - uint8_t rxaddr[ADDRLEN] = { 194, 178, 82 }; - uint8_t txaddr[ADDRLEN] = { 194, 178, 83 }; - - char buf[WDLEN], key[WDLEN]; - - wdt_off(); - led_init(); - - fpm_init(); - if (fpm_get_count() == 0) - fpm_enroll(); - - init_rx(); - init_btns(); - - radio_init(rxaddr); - - sei(); - radio_listen(); - - for (;;) { - if (!sync && (islock || isunlock)) { - if (isunlock) { - if (!fpm_match()) { - isunlock = 0; - fpm_nok(); - continue; - } - else - fpm_ok(); - } - - xor(KEY, SYN, buf, WDLEN); - retries = 0; - do { - sync = radio_sendto(txaddr, buf, WDLEN); - retries++; - } while (!sync && retries < 2); - - if (!sync) { - islock = 0; - isunlock = 0; - } - } - - if (rxd) { - radio_recv(buf, WDLEN); - rxd = 0; - if (sync && (islock || isunlock)) { - sync = 0; - xor(KEY, buf, key, WDLEN); - if (islock) { - islock = 0; - xor(key, LOCK, buf, WDLEN); - if (radio_sendto(txaddr, buf, WDLEN)) - led_locked(); - } else if (isunlock) { - isunlock = 0; - xor(key, UNLOCK, buf, WDLEN); - if (radio_sendto(txaddr, buf, WDLEN)) - led_unlocked(); - } - } - } - - if (!sync) { - if (getvcc() < VCC_MIN) { - for (i = 0; i < 5; i++) { - led_bat(); - _delay_ms(100); - } - } - - radio_pwr_dwn(); - sleep_bod_disable(); - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - sleep_mode(); - radio_listen(); - } - } - return 0; -} - -ISR(RX_INTVEC) -{ - if (!(RX_PIN & (1 << RX_IRQ_PIN))) - rxd = 1; -} - -ISR(INT0_vect) -{ - sync = 0; - isunlock = 1; -} - -ISR(INT1_vect) -{ - if (is_btn_pressed(PIND, LOCK_PIN)) { - sync = 0; - islock = 1; - } -} - -ISR(PCINT2_vect) -{ - uint16_t id; - - if (is_btn_pressed(PIND, ENROLL_PIN)) { - id = fpm_match(); - if (id == 1 || id == 2) { - fpm_ok(); - _delay_ms(1000); - if (fpm_enroll()) - fpm_ok(); - } else - fpm_nok(); - } -} - diff --git a/lock/fpm.c b/lock/fpm.c deleted file mode 100644 index 73a175a..0000000 --- a/lock/fpm.c +++ /dev/null @@ -1,324 +0,0 @@ -#include -#include -#include - -#include "fpm.h" - -#define MAXPDLEN 64 -#define RST_DELAY_MS 500 - -#define HEADER_HO 0xEF -#define HEADER_LO 0x01 -#define ADDR 0xFFFFFFFF - -#define OK 0x00 -#define PACKID 0x01 - -static inline uint8_t read(void) -{ - while (!(UCSR0A & (1 << RXC0))) - ; - return UDR0; -} - -static inline void write(uint8_t c) -{ - while (!(UCSR0A & (1 << UDRE0))) - ; - UDR0 = c; -} - -static inline void send(uint8_t *data, uint8_t n) -{ - int i; - uint16_t pktlen, sum; - - write(HEADER_HO); - write(HEADER_LO); - - write((uint8_t)(ADDR >> 24)); - write((uint8_t)(ADDR >> 16)); - write((uint8_t)(ADDR >> 8)); - write((uint8_t)(ADDR & 0xFF)); - - write(PACKID); - - pktlen = n + 2; - write((uint8_t)(pktlen >> 8)); - write((uint8_t)pktlen); - - sum = (pktlen >> 8) + (pktlen & 0xFF) + PACKID; - for (i = 0; i < n; i++) { - write(data[i]); - sum += data[i]; - } - - write((uint8_t)(sum >> 8)); - write((uint8_t)sum); -} - -static inline uint16_t recv(uint8_t buf[MAXPDLEN]) -{ - int i; - uint16_t len; - uint8_t byte; - - i = 0, len = 0; - - for (;;) { - byte = read(); - switch (i) { - case 0: - if (byte != HEADER_HO) - continue; - break; - case 1: - if (byte != HEADER_LO) - return 0; - case 2: - case 3: - case 4: - case 5: - // toss address - break; - case 6: - // toss packet id - break; - case 7: - len = (uint16_t)byte << 8; - break; - case 8: - len |= byte; - break; - default: - if ((i - 9) < MAXPDLEN) { - buf[i - 9] = byte; - if ((i - 8) == len) - return len; - } else - return 0; - break; - } - i++; - } - return 0; -} - -static inline void led_ctrl(uint8_t mode, COLOR color) -{ - uint8_t buf[MAXPDLEN]; - - buf[0] = 0x35; - buf[1] = mode; - buf[2] = 0x60; - buf[3] = color; - buf[4] = 0x00; - - send(buf, 5); - recv(buf); -} - -static inline uint8_t check_pwd(void) -{ - uint8_t buf[MAXPDLEN]; - - buf[0] = 0x13; - buf[1] = (uint8_t)((uint32_t)FPM_PWD >> 24); - buf[2] = (uint8_t)((uint32_t)FPM_PWD >> 16); - buf[3] = (uint8_t)((uint32_t)FPM_PWD >> 8); - buf[4] = (uint8_t)((uint32_t)FPM_PWD & 0xFF); - - send(buf, 5); - recv(buf); - return buf[0] == OK; -} - -static inline uint8_t scan(void) -{ - uint16_t retries; - uint8_t buf[MAXPDLEN]; - - retries = 0; - led_ctrl(0x01, PURPLE); - - do { - buf[0] = 0x28; - send(buf, 1); - recv(buf); - if (buf[0] != OK) { - retries++; - _delay_ms(100); - } - } while(buf[0] != OK && retries < 100); - - led_ctrl(0x06, PURPLE); - return buf[0] == OK; -} - -static inline uint8_t img2tz(uint8_t bufid) -{ - uint8_t buf[MAXPDLEN]; - - buf[0] = 0x02; - buf[1] = bufid; - send(buf, 2); - recv(buf); - return buf[0] == OK; -} - -void fpm_led_on(COLOR color) -{ - led_ctrl(0x03, color); -} - -void fpm_led_off(void) -{ - led_ctrl(0x04, 0x00); -} - -uint8_t fpm_init(void) -{ - UBRR0H = UBRRH_VALUE; - UBRR0L = UBRRL_VALUE; -#if USE_2X - UCSR0A |= (1 << U2X0); -#else - UCSR0A &= ~(1 << U2X0); -#endif - UCSR0B = (1 << TXEN0) | (1 << RXEN0); - UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); - - _delay_ms(RST_DELAY_MS); - return check_pwd(); -} - -uint8_t fpm_get_cfg(struct fpm_cfg *cfg) -{ - uint16_t n; - uint8_t buf[MAXPDLEN]; - - buf[0] = 0x0F; - send(buf, 1); - n = recv(buf); - - if (buf[0] == OK && n >= 17) { - cfg->status = ((uint16_t)buf[1] << 8) | buf[2]; - cfg->sysid = ((uint16_t)buf[3] << 8) | buf[4]; - cfg->cap = ((uint16_t)buf[5] << 8) | buf[6]; - cfg->sec_level = ((uint16_t)buf[7] << 8) | buf[8]; - cfg->addr[0] = buf[9]; - cfg->addr[1] = buf[10]; - cfg->addr[2] = buf[11]; - cfg->addr[3] = buf[12]; - cfg->pkt_size = ((uint16_t)buf[13] << 8) | buf[14]; - cfg->pkt_size = 1 << (cfg->pkt_size + 5); - cfg->baud = (((uint16_t)buf[15] << 8) | buf[16]); - - return 1; - } - return 0; -} - -uint8_t fpm_set_pwd(uint32_t pwd) -{ - uint8_t buf[MAXPDLEN]; - - buf[0] = 0x12; - buf[1] = (uint8_t)(pwd >> 24); - buf[2] = (uint8_t)(pwd >> 16); - buf[3] = (uint8_t)(pwd >> 8); - buf[4] = (uint8_t)(pwd & 0xFF); - - send(buf, 5); - recv(buf); - return buf[0] == OK; -} - -uint16_t fpm_get_count(void) -{ - uint16_t n, count; - uint8_t buf[MAXPDLEN]; - - buf[0] = 0x1D; - send(buf, 1); - n = recv(buf); - - count = 0; - if (buf[0] == OK && n >= 2) { - count = buf[1]; - count <<= 8; - count |= buf[2]; - } - return count; -} - -uint8_t fpm_enroll(void) -{ - struct fpm_cfg cfg; - uint16_t n; - uint8_t buf[MAXPDLEN]; - - fpm_get_cfg(&cfg); - n = fpm_get_count() + 1; - if (n >= cfg.cap) - return 0; - - if (!scan()) - return 0; - - if (!img2tz(1)) - return 0; - - _delay_ms(2000); - - if (!scan()) - return 0; - - if (!img2tz(2)) - return 0; - - buf[0] = 0x05; - send(buf, 1); - recv(buf); - if (buf[0] != OK) - return 0; - - buf[0] = 0x06; - buf[1] = 1; - buf[2] = (uint8_t)(n >> 8); - buf[3] = (uint8_t)(n & 0xFF); - send(buf, 4); - recv(buf); - - return buf[0] == OK; -} - -uint16_t fpm_match(void) -{ - struct fpm_cfg cfg; - uint8_t buf[MAXPDLEN]; - - if (!fpm_get_cfg(&cfg)) - return 0; - - if (!scan()) - return 0; - - if (!img2tz(1)) - return 0; - - buf[0] = 0x04; - buf[1] = 1; - buf[2] = 0x00; - buf[3] = 0x00; - buf[4] = (uint8_t)(cfg.cap >> 8); - buf[5] = (uint8_t)(cfg.cap & 0xFF); - - send(buf, 6); - recv(buf); - - if (buf[0] != OK) - return 0; - - return ((uint16_t)buf[1] << 8) | buf[2]; -} diff --git a/lock/fpm.h b/lock/fpm.h deleted file mode 100644 index 31f53eb..0000000 --- a/lock/fpm.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FPM_R503_H -#define FPM_R503_H - -#include - -struct fpm_cfg { - uint16_t status; - uint16_t sysid; - uint16_t cap; - uint16_t sec_level; - uint8_t addr[4]; - uint16_t pkt_size; - uint16_t baud; -}; - -typedef enum { - RED = 0x01, - BLUE = 0x02, - PURPLE = 0x03 -} COLOR; - -uint8_t fpm_init(void); - -uint8_t fpm_get_cfg(struct fpm_cfg *cfg); - -uint8_t fpm_set_pwd(uint32_t pwd); - -void fpm_led_on(COLOR color); - -void fpm_led_off(void); - -uint16_t fpm_get_count(void); - -uint8_t fpm_enroll(void); - -uint16_t fpm_match(void); - -#endif /* FPM_R50_H */ diff --git a/lock/nrfm.c b/lock/nrfm.c deleted file mode 100644 index d1bb5c3..0000000 --- a/lock/nrfm.c +++ /dev/null @@ -1,303 +0,0 @@ -#include -#include - -#include -#include -#include - -#include "nrfm.h" - -#define SPI_SS PB2 -#define SPI_SCK PB5 -#define SPI_MISO PB4 -#define SPI_MOSI PB3 -#define SPI_DDR DDRB -#define SPI_PORT PORTB - -#define NRF_CE PC1 -#define NRF_CE_DDR DDRC -#define NRF_CE_PORT PORTC - -#define NOP 0xFF -#define R_REGISTER 0x1F -#define W_REGISTER 0x20 - -#define PWR_UP 1 -#define PRIM_RX 0 - -#define MODCHG_DELAY_MS 5 - -#define LEN(a) (sizeof(a) / sizeof(a[0])) - -const char *bittab[16] = { - [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011", - [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111", - [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011", - [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111", -}; - -static inline uint8_t read_reg(uint8_t reg) -{ - SPI_PORT &= ~(1 << SPI_SS); - SPDR = reg & R_REGISTER; - while (!(SPSR & (1 << SPIF))) - ; - SPDR = NOP; - while (!(SPSR & (1 << SPIF))) - ; - SPI_PORT |= (1 << SPI_SS); - return SPDR; -} - -static inline void write_reg(uint8_t reg, uint8_t val) -{ - SPI_PORT &= ~(1 << SPI_SS); - SPDR = (reg & 0x1F) | W_REGISTER; - while (!(SPSR & (1 << SPIF))) - ; - SPDR = val; - while (!(SPSR & (1 << SPIF))) - ; - SPI_PORT |= (1 << SPI_SS); -} - -static inline void read_reg_bulk(uint8_t reg, uint8_t *data, uint8_t n) -{ - uint8_t i; - - SPI_PORT &= ~(1 << SPI_SS); - SPDR = reg & R_REGISTER; - while (!(SPSR & (1 << SPIF))) - ; - for (i = 0; i < n; i++) { - SPDR = NOP; - while (!(SPSR & (1 << SPIF))) - ; - data[i] = SPDR; - } - SPI_PORT |= (1 << SPI_SS); -} - -static inline void setaddr(uint8_t reg, const uint8_t addr[ADDRLEN]) -{ - int i; - - SPI_PORT &= ~(1 << SPI_SS); - SPDR = (reg & 0x1F) | W_REGISTER; - while (!(SPSR & (1 << SPIF))) - ; - for (i = ADDRLEN - 1; i >= 0; i--) { - SPDR = addr[i]; - while (!(SPSR & (1 << SPIF))) - ; - } - SPI_PORT |= (1 << SPI_SS); -} - -static inline void reset_irqs(void) -{ - uint8_t rv; - - rv = read_reg(0x07); - if (rv != 0b00001110) - write_reg(0x07, 0b01111110); -} - -static inline void tx_mode(void) -{ - uint8_t rv; - - rv = read_reg(0x00); - if ((rv & 0x03) != 0x02) { - rv |= (1 << PWR_UP); - rv &= ~(1 << PRIM_RX); - write_reg(0x00, rv); - _delay_ms(MODCHG_DELAY_MS); - } -} - -static inline void rx_mode(void) -{ - uint8_t rv; - - rv = read_reg(0x00); - if ((rv & 0x03) != 0x02) { - rv |= (1 << PWR_UP); - rv |= (1 << PRIM_RX); - write_reg(0x00, rv); - _delay_ms(MODCHG_DELAY_MS); - } -} - -static inline void enable_chip(void) -{ - NRF_CE_PORT |= (1 << NRF_CE); - _delay_us(130); -} - -static inline void disable_chip(void) -{ - NRF_CE_PORT &= ~(1 << NRF_CE); -} - -static inline void flush_tx(void) -{ - SPI_PORT &= ~(1 << SPI_SS); - SPDR = 0b11100001; - while (!(SPSR & (1 << SPIF))) - ; - SPI_PORT |= (1 << SPI_SS); - - reset_irqs(); -} - -void radio_flush_rx(void) -{ - SPI_PORT &= ~(1 << SPI_SS); - SPDR = 0b11100010; - while (!(SPSR & (1 << SPIF))) - ; - SPI_PORT |= (1 << SPI_SS); - - reset_irqs(); -} - -static inline uint8_t rx_pdlen(void) -{ - SPI_PORT &= ~(1 << SPI_SS); - SPDR = 0b01100000; - while (!(SPSR & (1 << SPIF))) - ; - SPDR = NOP; - while (!(SPSR & (1 << SPIF))) - ; - SPI_PORT |= (1 << SPI_SS); - return SPDR; -} - -void radio_init(const uint8_t rxaddr[ADDRLEN]) -{ - SPI_DDR |= (1 << SPI_SS) | (1 << SPI_SCK) | (1 << SPI_MOSI); - SPI_PORT |= (1 << SPI_SS); - SPCR |= (1 << SPE) | (1 << MSTR); - - NRF_CE_DDR |= (1 << NRF_CE); - NRF_CE_PORT &= ~(1 << NRF_CE); - - _delay_ms(110); /* power on reset delay */ - - write_reg(0x00, 0b00111100); /* use 2-byte CRC, enable only the rx interrupt */ - write_reg(0x01, 0b00111111); /* enable auto ack on all pipes */ - write_reg(0x02, 0b00000011); /* enable rx address on pipes 0 and 1 */ - write_reg(0x03, 0b00000001); /* set address width to 3 bytes */ - write_reg(0x04, 0b11111111); /* 4000uS retransmission delay, 15 tries */ - write_reg(0x05, 0b01110011); /* use 2.515GHz channel */ - write_reg(0x06, 0b00001110); /* set data rate to 1Mbps */ - write_reg(0x1D, 0b00000100); /* enable dynamic payload length */ - write_reg(0x1C, 0b00111111); /* enable dynamic payload length for all pipes */ - - reset_irqs(); - setaddr(0x0B, rxaddr); /* pipe 1 for rx, pipe 0 for auto-ack */ -} - -void radio_listen(void) -{ - disable_chip(); - rx_mode(); - enable_chip(); -} - -void radio_pwr_dwn(void) -{ - uint8_t rv; - - disable_chip(); - rv = read_reg(0x00); - rv &= ~(1 << PWR_UP); - write_reg(0x00, rv); -} - -uint8_t radio_sendto(const uint8_t addr[ADDRLEN], const char *msg, uint8_t n) -{ - int i, imax; - uint8_t cfg, rv, maxrt, txds; - - disable_chip(); - - cfg = read_reg(0x00); - - tx_mode(); - flush_tx(); - - setaddr(0x10, addr); - setaddr(0x0A, addr); - - imax = n < MAXPDLEN ? n : MAXPDLEN; - - SPI_PORT &= ~(1 << SPI_SS); - SPDR = 0b10100000; - while (!(SPSR & (1 << SPIF))) - ; - for (i = 0; i < imax; i++) { - SPDR = msg[i]; - while (!(SPSR & (1 << SPIF))) - ; - } - SPI_PORT |= (1 << SPI_SS); - - enable_chip(); - _delay_us(12); - disable_chip(); - - txds = 0, maxrt = 0; - do { - rv = read_reg(0x07); - txds = rv & (1 << 5); - maxrt = rv & (1 << 4); - } while (txds == 0 && maxrt == 0); - - if (maxrt) - flush_tx(); - - // restore config, typically rx mode - write_reg(0x00, cfg); - enable_chip(); - return txds; -} - -uint8_t radio_recv(char *buf, uint8_t n) -{ - int readlen, pdlen, readmax; - - pdlen = 0; - disable_chip(); - - pdlen = rx_pdlen(); - if (pdlen == 0) { - radio_flush_rx(); - return 0; - } - - if (pdlen > MAXPDLEN) { - radio_flush_rx(); - return 0; - } - - readmax = n < pdlen ? n : pdlen; - - SPI_PORT &= ~(1 << SPI_SS); - SPDR = 0b01100001; - while (!(SPSR & (1 << SPIF))) - ; - for (readlen = 0; readlen < readmax; readlen++) { - SPDR = NOP; - while (!(SPSR & (1 << SPIF))) - ; - buf[readlen] = SPDR; - } - SPI_PORT |= (1 << SPI_SS); - - radio_flush_rx(); - enable_chip(); - return readlen; -} diff --git a/lock/nrfm.h b/lock/nrfm.h deleted file mode 100644 index 52d4edb..0000000 --- a/lock/nrfm.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef NRFM_H -#define NRFM_H - -#include - -#define ADDRLEN 3 -#define MAXPDLEN 32 - -void radio_init(const uint8_t rxaddr[ADDRLEN]); - -void radio_listen(void); - -void radio_pwr_dwn(void); - -uint8_t radio_recv(char *buf, uint8_t n); - -void radio_flush_rx(void); - -uint8_t radio_sendto(const uint8_t addr[ADDRLEN], const char *msg, uint8_t n); - -#endif /* NRFM_H */ diff --git a/lock/server.c b/lock/server.c deleted file mode 100644 index 6d51c00..0000000 --- a/lock/server.c +++ /dev/null @@ -1,191 +0,0 @@ -/* Lock back, connected to the servo */ - -#include -#include - -#include -#include -#include -#include - -#include "nrfm.h" -#include "util.h" - -#define PWM_MIN 500 -#define PWM_MID 1500 -#define PWM_MAX 2500 -#define PWM_TOP 20000 - -#define SERVO_PIN PB1 -#define LOCK_PIN PD3 -#define UNLOCK_PIN PD4 - -#define RX_IRQ_PIN PC0 -#define RX_DDR DDRC -#define RX_PIN PINC -#define RX_ICR PCICR -#define RX_IE PCIE1 -#define RX_INT PCINT8 -#define RX_MSK PCMSK1 -#define RX_INTVEC PCINT1_vect - -#define VCC_MIN 4000 - -static char tab[] = { - '0', '8', '3', '6', 'a', 'Z', '$', '4', 'v', 'R', '@', - 'E', '1', 'o', '#', ')', '2', '5', 'q', ';', '.', 'I', - 'c', '7', '9', '*', 'L', 'V', '&', 'k', 'K', '!', 'm', - 'N', '(', 'O', 'Q', 'A', '>', 'T', 't', '?', 'S', 'h', - 'w', '/', 'n', 'W', 'l', 'M', 'e', 'H', 'j', 'g', '[', - 'P', 'f', ':', 'B', ']', 'Y', '^', 'F', '%', 'C', 'x' -}; - -static volatile uint8_t rxd = 0; -static uint16_t tablen = sizeof(tab) / sizeof(tab[0]); - -static inline void keygen(char *buf, uint8_t n) -{ - int i, imax; - uint8_t sreg; - uint16_t seed; - - sreg = SREG; - cli(); - seed = TCNT1; - SREG = sreg; - - for (i = 0, imax = n - 1; i < imax; i++, seed++) - buf[i] = tab[(seed % tablen)]; - buf[imax] = '\0'; -} - -static inline void keydel(char *buf, uint8_t n) -{ - int i; - - for (i = 0; i < n; i++) - buf[i] = 0; -} - -static inline void init_wdt(void) -{ - cli(); - wdt_reset(); - - WDTCSR |= (1 << WDCE) | ( 1 << WDE); - WDTCSR = (1 << WDE) | (1 << WDP1); /* reset after 64ms */ -} - -static inline void init_rx(void) -{ - RX_DDR &= ~(1 << RX_IRQ_PIN); - RX_ICR |= (1 << RX_IE); - RX_MSK |= (1 << RX_INT); -} - -static inline void init_btns(void) -{ - DDRD &= ~((1 << LOCK_PIN) | (1 << UNLOCK_PIN)); - PORTD |= ((1 << LOCK_PIN) | (1 << UNLOCK_PIN)); - - EICRA = 0b00000000; - EIMSK = (1 << INT1); - - PCICR |= (1 << PCIE2); - PCMSK2 |= (1 << PCINT20); -} - -static inline void init_servo(void) -{ - ICR1 = PWM_TOP; - TCCR1A |= (1 << WGM11) | (1 << COM1A1); - TCCR1B |= (1 << WGM13) | (1 << CS11); - - DDRB |= (1 << SERVO_PIN); -} - -static inline void lock(void) -{ - OCR1A = PWM_MID; - _delay_ms(100); - OCR1A = PWM_TOP; -} - -static inline void unlock(void) -{ - OCR1A = PWM_MAX - 50; - _delay_ms(100); - OCR1A = PWM_TOP; -} - -int main(void) -{ - uint8_t rxaddr[ADDRLEN] = { 194, 178, 83 }; - uint8_t txaddr[ADDRLEN] = { 194, 178, 82 }; - - char buf[WDLEN], key[WDLEN], msg[WDLEN]; - - init_wdt(); - init_rx(); - init_btns(); - init_servo(); - - led_init(); - radio_init(rxaddr); - - sei(); - radio_listen(); - - for (;;) { - if (rxd) { - radio_recv(buf, WDLEN); - rxd = 0; - xor(KEY, buf, msg, WDLEN); - if (memcmp(msg, SYN, WDLEN) == 0) { - keygen(key, WDLEN); - xor(KEY, key, buf, WDLEN); - radio_sendto(txaddr, buf, WDLEN); - } else { - xor(key, buf, msg, WDLEN); - if (memcmp(msg, LOCK, WDLEN) == 0) { - lock(); - keydel(key, WDLEN); - } else if (memcmp(msg, UNLOCK, WDLEN) == 0) { - unlock(); - keydel(key, WDLEN); - } - } - } else { - radio_pwr_dwn(); - if (getvcc() < VCC_MIN) - led_bat(); - sleep_bod_disable(); - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - sleep_mode(); - } - } - return 0; -} - -ISR(RX_INTVEC) -{ - if (!(RX_PIN & (1 << RX_IRQ_PIN))) - rxd = 1; -} - -ISR(INT1_vect) -{ - if (is_btn_pressed(PIND, LOCK_PIN)) { - lock(); - led_locked(); - } -} - -ISR(PCINT2_vect) -{ - if (is_btn_pressed(PIND, UNLOCK_PIN)) { - unlock(); - led_unlocked(); - } -} - diff --git a/lock/uart.h b/lock/uart.h deleted file mode 100644 index a88a3c6..0000000 --- a/lock/uart.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef UART_H -#define UART_H - -void uart_init(void); -void uart_write(const char *s); -void uart_write_line(const char *s); - -#endif /* UART_H */ diff --git a/lock/util.c b/lock/util.c deleted file mode 100644 index ec5369e..0000000 --- a/lock/util.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include - -#include "util.h" - -#define LOCK_LED PC3 -#define UNLOCK_LED PC4 -#define BATLOW_LED PC5 -#define LED_DDR DDRC -#define LED_PORT PORTC - -int is_btn_pressed(uint8_t pin, uint8_t btn) -{ - if (!((pin >> btn) & 0x01)) { - _delay_ms(100); - return !((pin >> btn) & 0x01); - } - return 0; -} - -void xor(const char *k, const char *s, char *d, uint8_t n) -{ - int i; - - for (i = 0; i < n; i++) - d[i] = s[i] ^ k[i]; -} - -/* Measure vcc by measuring known internal 1.1v bandgap - * reference voltage against AVCC. - * Place a 100nF bypass capacitor on AREF. - */ -uint16_t getvcc(void) -{ - uint16_t vcc; - - ADMUX |= (1 << REFS0); - ADMUX |= (1 << MUX3) | (1 << MUX2) | (1 << MUX1); - ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0); - - // https://www.sciencetronics.com/greenphotons/?p=1521 - _delay_us(500); - - ADCSRA |= (1 << ADSC); - while (ADCSRA & (1 << ADSC)) - ; - vcc = (1100UL * 1023 / ADC); - - ADCSRA &= ~(1 << ADEN); - return vcc; -} - -void led_init(void) -{ - LED_DDR |= (1 << LOCK_LED) | (1 << UNLOCK_LED); - LED_DDR |= (1 << BATLOW_LED); - - LED_PORT &= ~(1 << LOCK_LED); - LED_PORT &= ~(1 << UNLOCK_LED); - LED_PORT &= ~(1 << BATLOW_LED); -} - -void led_locked(void) -{ - LED_PORT |= (1 << LOCK_LED); - _delay_ms(100); - LED_PORT &= ~(1 << LOCK_LED); - _delay_ms(100); - LED_PORT |= (1 << LOCK_LED); - _delay_ms(100); - LED_PORT &= ~(1 << LOCK_LED); -} - -void led_unlocked(void) -{ - LED_PORT |= (1 << UNLOCK_LED); - _delay_ms(70); - LED_PORT &= ~(1 << UNLOCK_LED); - _delay_ms(70); - LED_PORT |= (1 << UNLOCK_LED); - _delay_ms(70); - LED_PORT &= ~(1 << UNLOCK_LED); -} - -void led_bat(void) -{ - LED_PORT ^= (1 << BATLOW_LED); -} diff --git a/lock/util.h b/lock/util.h deleted file mode 100644 index 84584aa..0000000 --- a/lock/util.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MY_UTIL_H -#define MY_UTIL_H - -#include - -#define KEY "dM>}jdb,6gsnC$J^K 8(I5vyPemPs%;K" -#define SYN "dM>}jdb,6gsnC$J^K 8(I5vyPemPs%;O" -#define LOCK "R,I7l^E4j]KyLR9'*Q{Jd'zu.~!84}Ij" -#define UNLOCK "R,I7l^E4j]KyLR9'*Q{Jd'zu.~!84}IL" - -#define WDLEN 32 - -int is_btn_pressed(uint8_t pin, uint8_t btn); - -void xor(const char *k, const char *s, char *d, uint8_t n); - -uint16_t getvcc(void); - -void led_init(void); - -void led_locked(void); - -void led_unlocked(void); - -void led_bat(void); - -#endif /* MY_UTIL_H */ -- cgit v1.2.3