From a3a63e64d00a6554f935d574358c88afb453b09d Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sat, 7 Jun 2025 14:26:01 +0800 Subject: FPM and the buttons. --- .gitignore | 9 ++ Makefile | 46 +++++++++ README.txt | 17 ++++ fpm.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fpm.h | 46 +++++++++ main.c | 99 +++++++++++++++++++ 6 files changed, 536 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.txt create mode 100644 fpm.c create mode 100644 fpm.h create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..596a14b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# C +**/*.o +**/*.elf +**/*.hex +**/*.out + +# Vim +*.swp +*.core diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..883a3cf --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +CC = avr-gcc +MCU = atmega328p +PORT = /dev/cuaU0 +TARGET = app + +SRC = main.c fpm.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/README.txt b/README.txt new file mode 100644 index 0000000..be66f81 --- /dev/null +++ b/README.txt @@ -0,0 +1,17 @@ +CURRENT MEASUREMENTS + +R503 FPM: +ATmega328P: +MOSFET: + + +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. + +REMARKS + + 1. Can't use the 3.3V FPM modules with Arduino Uno. The RX and TX lines have + resistors. diff --git a/fpm.c b/fpm.c new file mode 100644 index 0000000..4f3b4ed --- /dev/null +++ b/fpm.c @@ -0,0 +1,319 @@ +#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: + // 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) +{ + uint8_t rc; + + 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); + + if ((rc = check_pwd())) + fpm_led(OFF, NIL, 0); + return rc; +} + +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/fpm.h b/fpm.h new file mode 100644 index 0000000..f424c56 --- /dev/null +++ b/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/main.c b/main.c new file mode 100644 index 0000000..abc5b1b --- /dev/null +++ b/main.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +#include "fpm.h" + +#define FRONT_UNLOCK_PIN PD2 +#define FRONT_LOCK_PIN PD3 +#define ENROLL_PIN PD4 +#define BACK_LOCK_PIN PD5 +#define BACK_UNLOCK_PIN PD6 + +#define INPUT_DDR DDRD +#define INPUT_PORT PORTD + +#define FPM_UNLOCK_INT INT0 +#define FPM_INT_VEC INT0_vect + +#define FRONT_LOCK_INT PCINT19 +#define ENROLL_INT PCINT20 +#define BACK_LOCK_INT PCINT21 +#define BACK_UNLOCK_INT PCINT22 +#define BTN_INT_VEC PCINT2_vect + +int main(void) +{ + /* input ports */ + INPUT_DDR &= ~((1 << BACK_LOCK_PIN) | (1 << BACK_UNLOCK_PIN) | + (1 << FRONT_LOCK_PIN) | (1 << FRONT_UNLOCK_PIN) | + (1 << ENROLL_PIN)); + + INPUT_PORT |= ((1 << BACK_LOCK_PIN) | (1 << BACK_UNLOCK_PIN) | + (1 << FRONT_LOCK_PIN) | (1 << FRONT_UNLOCK_PIN) | + (1 << ENROLL_PIN)); + + EICRA = 0b00000000; + EIMSK = (1 << FPM_UNLOCK_INT); + + PCICR |= (1 << PCIE2); + PCMSK2 |= ((1 << FRONT_LOCK_INT) | (1 << ENROLL_INT) | + (1 << BACK_LOCK_INT) | (1 << BACK_UNLOCK_INT)); + + fpm_init(); + sei(); + + for (;;) { + } + + return 0; +} + +static inline int is_pressed(uint8_t btn) +{ + if (!((PIND >> btn) & 0x01)) { + _delay_ms(50); + return !((PIND >> btn) & 0x01); + } + return 0; +} + +ISR(FPM_INT_VEC) +{ + cli(); + + if (fpm_match()) { + fpm_led(BREATHE, BLUE, 1); + } else { + fpm_led(BREATHE, RED, 1); + } + + sei(); +} + +ISR(BTN_INT_VEC) +{ + uint16_t id; + + cli(); + + if (is_pressed(FRONT_LOCK_PIN)) { + fpm_led(FLASH, RED, 1); + } else if (is_pressed(BACK_LOCK_PIN)) { + } else if (is_pressed(BACK_UNLOCK_PIN)) { + } else if (is_pressed(ENROLL_PIN)) { + 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); + } + + sei(); +} -- cgit v1.2.3