summaryrefslogtreecommitdiffstats
path: root/_log/fpm-door-lock-rf.md
blob: 97779dbc5d8fdfedb2cf09d677c90052c6f773f9 (plain)
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
---
title: Fingerprint door lock (RF)
date: 2025-06-05
layout: post
project: true
thumbnail: thumb_sm.jpeg
---

Wanted to unlock door with fingerprint, wirelessly to avoid drilling.

2024-11: Started with basic 433MHz RF modules and two Arduinos. Connected data
lines of the transceivers to UART RXD/TXD of an ATmega328P.
Unreliable--constant packet loss.

2025-01: Switched to RFM69 modules. Complete ball-ache. Followed datasheet to
the letter, audited code many times, cross-checked with RadioHead and RFM69
open-source drivers. No luck. 

ATmega328P runs at 5V; RFM69 3.3V. Suspect logic-level converter (LLC)
issues. High resistance. Not enough swing.

2025-04: Ditched RFM69s. Switched to NRF24L01+ modules--data pins 5V tolerant,
no LLC required. Spent six weekends writing a clean-room driver from scratch.
Works like a charm. 

Basic security via xor cipher–good enough for a door behind a guard post and
gate:

```
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];
}
``` 

Resists replay attacks by cycling the key:

```
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';
}
```

Protocol: FPM sends SYN. Servo responds with session key. Both xor-ed with
static key. Session key used thereafter. Private command set authenticates
endpoints.

2025-05: Wrote FPM drivers for R503 and FPM10A. UART RX sequence was
tricky--adopted Adafruit C++ FOSS implementation to C. R503 has built-in LEDs
and better form factor. Chose it for the lock.

2025-06: Two PCBs for FPM (front) and servo (back) controllers. 

<table style="border: none; width: 100%">
  <tr style="border: none;">
    <td style="border: none; width: 49.5%; vertical-align: top; text-align: center;">
      <img src="front_design.jpeg" alt="Design (front)" style="width: 100%">
      <p>Footprint (front)</p>
    </td>
    <td style="border: none; vertical-align: top; text-align: center;">
      <img src="front.jpeg" alt="PCB (front)" style="width: 100%">
      <p>PCB (front)</p>
    </td>
  </tr>
  <tr style="border: none;">
    <td style="border: none; width: 49.5%; vertical-align: top; text-align: center;">
      <img src="back_design.jpeg" alt="Design (back)" style="width: 100%">
      <p>Footprint (back)</p>
    </td>
    <td style="border: none; vertical-align: top; text-align: center;">
      <img src="back.jpeg" alt="PCB (back)" style="width: 100%">
      <p>PCB (back)</p>
    </td>
  </tr>
</table>

PCB specs: 2-layer, 1oz copper, 0.3mm traces (0.5mm for power). Ground plane.

2025-06: NRF24L01+ on the back stopped working after mounting on PCB. Too close
to servo's PWM line. Soldering a large 47uF (16V) electrolytic capacitor
between VCC and ground fixed it.

Power problems became clear. Linear regulators dissipated too much heat. Sensor
and servo drew 13.8mA and 4.6mA quiescent currents--unacceptable for battery.
Servo inrush current exceeds 1A. 0.3mm tracks cuts it too close.

Verdict: Functional but not practical. Battery dead in under 24 hours. Led to
[redesign](../fpm-door-lock-lp/) with proper power management.

Commit: <a
href="https://git.asciimx.com/smart-home/commit/?id=f4b0b734a595919cf451ab9448b06274c8e609a4"
class="external" target="_blank" rel="noopener noreferrer">f4b0b73</a> |
Gerber: [gerber_back.zip](gerber_back.zip),
[gerber_front.zip](gerber_front.zip)