Skip to the content
2 layers61.9 × 76.2 mmDigits pcb, the printed circuit board in 3D

Encrypted retro phone network — private VoIP over vintage desk phones

Size
61.9 × 76.2 mm
Copper layers
2
Thickness
1.6 mm
Parts
77
Nets
104
Pads
335
Tracks, vias
909, 131
Pours
2
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
3 Apr 2026
Updated
6 Nov 2026

Overview

Digits pcb is an open-source printed circuit board by justinlindh, from the justinlindh/digits repository on GitHub, published under the AGPL-3.0 licence. It is a 2-layer board of 61.9 × 76.2 mm with 77 parts on 104 nets, routed with 909 tracks and 131 vias.

It is built around the RP2040, DRV8871DDARQ1 and TLV320AIC3104IRHBR, with the W25Q16JVSSIQ, XL6019E1 and AMS1117-3.3 among its other parts. Its parts include 43 capacitors, 10 resistors, 7 ICs, 4 diodes and 2 switches. It belongs with the retro computing and games boards and the RP2040 boards of this library.

Main components

9

README

README.md

Digits

Digits

Private encrypted phone network built from gutted vintage desk phones.

Server CI

Server release Pi release Firmware release Go 1.26 C / Pico SDK AGPL-3.0 License CC BY-SA 4.0 License

Website · App · Docs


Each phone is a gutted vintage desk phone with two processors inside: an RP2040 handling real-time phone hardware (keypad scanning, hook switch, bell ringer, DTMF tones) and a Raspberry Pi Zero 2 W running a Go daemon for VoIP, end-to-end encrypted media (DTLS-SRTP), and call signaling. A Go server handles call routing, device pairing, and household management. There's a free public instance at app.digits.family, or you can run your own.

Table of Contents

Architecture

ComponentRole
RP2040 (firmware, C)Real-time phone I/O: keypad matrix, hook switch, bell driver, DTMF/tone generation, status LED. Communicates with the Pi over UART. V0/V1 use a Pico H module; V2/V3 have the RP2040 onboard.
Pi Zero 2 W (digitsd, Go)VoIP daemon: WebRTC media, Opus codec, DTLS-SRTP, signaling client, call state machine, Wi-Fi setup, OTA updates.
Audio codecMic input and earpiece output. Codec Zero HAT (DA7212) on V0/V1, onboard TLV320AIC3104 on V2/V3.
Signaling server (Go)WebSocket relay for SDP/ICE exchange, PostgreSQL persistence, device pairing, household management, web dashboard.

Calls are peer-to-peer WebRTC sessions between two phones (or three, for party-line calls). The server brokers the signaling handshake but never handles media.

See Architecture deep-dive for the full call path, data model, and NAT traversal.

Hardware

Four hardware iterations, each a different build strategy:

RevConstructionAudioRingerStatus
V0Perfboard, off-the-shelf modulesCodec Zero HAT (DA7212)L298N + step-up transformerDone, documented end-to-end
V1Hand-assembled PCB, Pico H moduleCodec Zero HAT (DA7212)L298N + step-up transformerFabricated, has errata
V2Contract-assembled (JLCPCB), onboard RP2040Onboard TLV320AIC3104Onboard DRV8871Deployed, ~10 units in use
V3Contract-assembled (JLCPCB), onboard RP2040Onboard TLV320AIC3104Onboard DRV8871 + XL6019 boostIn progress, see changes

V1 is a bench-build target: single-sided, mostly through-hole, hand-solderable. External modules handle audio (Codec Zero HAT) and bell ringing (L298N H-bridge plus a step-up transformer).

V2 is a fab-service target: onboard RP2040, audio codec (TLV320AIC3104, 32-pin QFN), and ringer driver (DRV8871). Arrives pre-assembled from JLCPCB. Not practical to hand-solder.

V3 is a major spin of V2: +5 V input (the 12 V buck stage is gone), an on-board XL6019 boost converter making ~37 V to ring the bell in place of the external step-up transformer, a single DPDT cradle switch for hook sense and series mic-kill, an SW2 BOOTSEL button, power indicator LEDs, components flipped to face up, and J8/LED pinouts matched to the stock donor-phone cables. Like V2, it arrives pre-assembled from JLCPCB.

Schematics, PCB layouts, Gerbers, and BOMs are in hardware/pcb/. All designed in KiCad. The firmware abstracts board differences at runtime, so the same binary runs on V1, V2, and V3.

Project Structure

text
firmware/       RP2040 firmware (C, CMake, Pico SDK)
pi/digitsd/     Pi-side VoIP daemon (Go, cross-compiled to arm64)
pi/image/       Raspberry Pi OS image builder
server/         Signaling server + web dashboard (Go, htmx, Tailwind)
hardware/pcb/   KiCad schematics, PCB layouts, Gerbers, BOMs
charts/digits/  Helm chart for Kubernetes deployment
tools/          Build scripts for firmware, Pi binaries, and OS images
docs/           Architecture notes, build guides, self-hosting
scripts/        Firmware build and flash helpers

Quick Start

Server

bash
cd server
make build     # builds bin/signald
make run       # build + run (defaults to :8443)
make test      # go test ./...

Requires Go 1.26+ and PostgreSQL. The server reads DATABASE_URL and runs migrations on startup.

Firmware

bash
./scripts/build.sh     # auto-detects PICO_SDK_PATH
./scripts/flash.sh     # hold BOOTSEL, plug in USB, then run

Pi Daemon

bash
cd pi/digitsd
make build             # cross-compiles to linux/arm64 via Docker
make build-local       # native build (requires cross-compile libs)
make test

Hosting

The server is a single Go binary (signald) backed by Postgres. For calls across different networks, you also need a TURN relay (coturn). Docker Compose is the straightforward way to run both: clone the repo, fill in an .env file, docker compose up -d. The self-hosting guide covers the full setup including TURN, TLS, SMTP for magic-link auth, phone pairing, backups, and troubleshooting.

There is also a Helm chart if you happen to have a Kubernetes cluster. There is no good reason for a family phone network to run on k8s, but I over-engineered almost everything in this project and it would have felt wrong to stop at the deployment layer. The chart supports CNPG Postgres, Redis Sentinel for multi-replica signaling, OpenTelemetry tracing, Pyroscope profiling, and Prometheus metrics. It is what runs in production. Completely unnecessary, but it works and it is there if you want it.

Web App

The server includes a web dashboard for pairing phones, organizing households, viewing call history, and configuring per-line settings.

Digits web dashboard

Service Codes

Hidden codes entered on the keypad while the handset is off-hook.

CodeActionDetails
*#*0 -- *#*9VolumeSets earpiece volume (0 = quiet, 9 = max). Persists across reboots.
*#8378#Audio testRecords 5 s from mic, plays it back through earpiece. (*#TEST# on keypad.)
*#*#ShutdownGraceful power-off. Safe to unplug after LED goes dark.
*##*RebootImmediate reboot.
*#0*Force re-pairClears device token, reboots into pairing mode.
*#73887#Wi-Fi setupReboots into AP mode for Wi-Fi reconfiguration. (*#SETUP# on keypad.)
*#873283#Update checkChecks for OTA firmware and daemon updates. (*#UPDATE# on keypad.)
*#00000#Factory resetWipes config, Wi-Fi, contacts. Fresh AP + pairing mode.

Call Return (*69 / *89)

CodeActionDetails
*69Call returnAnnounces who last called you. Press 1 to call them back. If the line is busy, the system retries for 30 minutes and rings you with a distinctive pattern when the line is free.
*89Cancel call returnCancels any pending *69 busy-retry. Voice confirmation plays.

These are dialed from dial tone (not prefixed with *#), matching the original 1990s POTS behavior.

Voicemail (*96 / *97 / *98 / *99)

CodeActionDetails
*96Audition greetingPlays your current outgoing greeting through the earpiece, so you can hear what callers hear.
*97Record greetingRecords a custom outgoing greeting after the tone.
*98Listen to messagesPlays your messages oldest first, then any saved (already heard) messages. During playback: 7 deletes, 9 saves, # skips, * replays.
*99Delete greetingRemoves your custom greeting and restores the default.

When a call rings unanswered past the configured timeout, the phone answers it, plays your greeting, and records the caller's message. The handset microphone is muted while recording, so a caller never hears your room. See the voicemail guide for using and configuring it, or Voicemail for the engineering reference: FSM, on-disk storage format, signaling, and configuration.

Confirmation feedback

  • Volume change. 1 beep, then dial tone resumes.
  • Audio test. 2 beeps (start speaking), 1 beep (playback done), dial tone resumes.
  • Shutdown. 3 beeps, then powers off.
  • Reboot. 2 beeps, then reboots.

Party Line (Three-Way Calling)

Classic 90s residential three-way calling. During an active call, press and briefly release the hook switch (a "flash", 100-600 ms on-hook) to get a second dial tone. Dial a third number, talk to them privately, then flash again to merge all three into a single call.

GestureWhat happens
Flash during an active callHeld party drops to silent hold; you hear a second dial tone
Dial a numberRingback; third party's phone rings
Flash again after they answerAll three merged into the conference
Flash before they answerDrops the add attempt; returns to the held party
Hang up (host)Collapses the conference for everyone
Hang up (non-host)Remaining pair keeps talking as a normal 2-party call

Hard-capped at three parties, matching residential TWC on 5ESS / DMS-100 switches. Audio stays end-to-end encrypted on three independent DTLS-SRTP legs; the server never sees media, and mixing happens locally on each phone.

See Party Line for the state machine, media topology, signalling protocol, and failure-mode coverage.

Easter Eggs

Hidden sequences that play audio clips through the earpiece. Each keypress must be within ~1.5 s of the last.

SequenceWhat plays
5-5-4-2Towelie: "That's it! That's the melody to Funky Town!"
0-0-0-0Rick Astley: "Never gonna give you up..."
8-6-7-5-3-0-9Tommy Tutone: "Jenny I got your number... 867-5309!" (intercepts the dial)

Privacy

Calls use WebRTC with DTLS-SRTP. Voice data is encrypted end-to-end between the two devices on the call. The signaling server facilitates connection setup but never has access to the audio stream. Even if the server were compromised, there would be no voice data to extract.

A dedicated hardware kill switch (separate from the hook switch) physically disconnects the microphone circuit when the handset is on the cradle. This is an electrical disconnect, not a software mute.

What the server stores: user accounts (email, name), household membership, phone line assignments, device pairing tokens, session data, call metadata (caller, callee, timestamps, duration), and connection quality telemetry (packet loss, jitter, bandwidth).

What the server does not store: voice audio, call recordings, transcripts, or location data. There is no mechanism in the server to capture call audio.

The server is designed to be self-hosted. If you do not want to use the public instance at app.digits.family, you can run the same code on your own infrastructure. See Self-hosting.

Contributing

This is a personal project, not a company. Contributions to both the software and the hardware are welcome.

On the software side, the server is vanilla Go with htmx and Tailwind, the Pi daemon is Go with WebRTC, and the firmware is C on the Pico SDK. Standard open source workflow: fork, branch, PR.

On the hardware side, I am not an electrical engineer. I learned KiCad, read datasheets, and iterated until the board worked. The result is a functional PCB with minimal errata, which I'm genuinely proud of, but there is a lot of room for someone with real PCB design experience to improve the layout, power integrity, signal routing, and DFM. If you have those skills and this project interests you, I would particularly welcome that kind of help. The schematics and board files are all KiCad and licensed CC BY-SA 4.0.

Documentation

License

Code (firmware, server, tooling): AGPL-3.0

Hardware (schematics, PCB layout, BOM): CC BY-SA 4.0

Parts

77
QtyValueFootprintReferences
24100nFCapacitor_SMD:C_0402_1005MetricC12, C13, C14, C15, C16, C28, C29, C30, C32, C33, C34, C35, C36, C38, C40, C41 +8
41uFCapacitor_SMD:C_0402_1005MetricC10, C31, C39, C44
3MountingHoleMountingHole:MountingHole_3.2mm_M3MH1, MH2, MH3
20.47uFCapacitor_SMD:C_0402_1005MetricC46, C47
2100nFCapacitor_SMD:C_0805_2012MetricC3, C4
210kResistor_SMD:R_0402_1005MetricR5, R11
210uFCapacitor_SMD:C_0402_1005MetricC37, C45
210uFCapacitor_SMD:C_0603_1608MetricC9, C11
215pFCapacitor_SMD:C_0402_1005MetricC5, C6
11.5AFuse:Fuse_1210_3225MetricF1
1100uFcap-out-lcsc:CAP-SMD_BD10.0-L10.3-W10.3-FDC100
110uFCapacitor_SMD:CP_Elec_5x5.3C55
1120Resistor_SMD:R_0402_1005MetricR13
11kResistor_SMD:R_0402_1005MetricR9
11nFCapacitor_SMD:C_0402_1005MetricC53
11uFCapacitor_SMD:C_0805_2012MetricC101
12.2kResistor_SMD:R_0402_1005MetricR10
1220Resistor_SMD:R_0805_2012MetricR1
12kResistor_SMD:R_0402_1005MetricR21
1300Resistor_SMD:R_0402_1005MetricR12
133kResistor_SMD:R_0402_1005MetricR2
1470uFCapacitor_SMD:CP_Elec_10x10.5C1
147uHinductor-lcsc:IND-SMD_L12.3-W12.3L10
157.6kResistor_SMD:R_0402_1005MetricR20
1ABM8-272-T3Crystal:Crystal_SMD_3225-4Pin_3.2x2.5mmY1
1AMS1117-3.3Package_TO_SOT_SMD:SOT-223-3_TabPin2U5
1Conn_01x02Connector_JST:JST_ZH_B2B-ZR-SM4-TF_1x02-1MP_P1.50mm_VerticalLED1
1Conn_01x04Connector_JST:JST_ZH_B4B-ZR-SM4-TF_1x04-1MP_P1.50mm_VerticalJ8
1Conn_01x07Connector_JST:JST_ZH_B7B-ZR-SM4-TF_1x07-1MP_P1.50mm_VerticalKEYPAD1
1Conn_02x20_Odd_EvenConnector_PinHeader_2.54mm:PinHeader_2x20_P2.54mm_VerticalPI_ZERO_W1
1DRV8871DDARPackage_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.29x3mmU2
1Hook_DPDTdigits-pcb:SW_DPDT_Hook_24.2x17.1mmSW1
1LED_GREENLED_SMD:LED_0603_1608MetricD3
1LED_REDLED_SMD:LED_0603_1608MetricD2
1RP2040Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP3.2x3.2mmU3
1SS56ss56-lcsc:SMA_L4.3-W2.6-LS5.2-RDD10
1SW_PushButton_Switch_THT:SW_PUSH_6mmSW2
1Screw_Terminal_01x02Connector_JST:JST_ZH_B2B-ZR-SM4-TF_1x02-1MP_P1.50mm_VerticalBELL1
1TLV320AIC3104IRHBRPackage_DFN_QFN:Texas_RHB0032E_VQFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mmU6
1VIN_BARREL_PIGTAILConnector_JST:JST_XH_B2B-XH-A_1x02_P2.50mm_VerticalPWR1
1W25Q16JVSSIQPackage_SO:SOIC-8_5.3x5.3mm_P1.27mmU4
1XC6206P182MRPackage_TO_SOT_SMD:SOT-23U7
1XL6019E1xl6019:TO-263-5_L10.2-W9.9-P1.70-LS14.4-TLU10

More from justinlindh/digits

2
  • 2 layers76.2 × 61.9 mmDigits pcb, the printed circuit board in 3D

    Digits pcb

    justinlindh/digits

    Encrypted retro phone network — private VoIP over vintage desk phones

    71 parts4AGPL-3.0
  • 2 layers76.2 × 56.9 mmDigits pcb, the printed circuit board in 3D

    Digits pcb

    justinlindh/digits

    Encrypted retro phone network — private VoIP over vintage desk phones

    22 parts4AGPL-3.0

Similar boards

  • 4 layers65 × 30.9 mmElec RPI Robot HAT, the printed circuit board in 3D

    Elec RPI Robot HAT

    armature-ai-labs/indieduck

    Open robot prototype: editable FreeCAD CAD, printable parts and fit-test documentation. Adapted from Open Duck Mini.

    132 partsApache-2.0
  • 4 layers65 × 30.9 mmElec RPI Robot HAT, the printed circuit board in 3D

    Elec RPI Robot HAT

    modewang/elec_RPI_Robot_HAT

    The RPIRobotHAT can be power from 5 to 28V. It is designed to use of the motor connector as an power input.

    127 partsApache-2.0
  • 2 layers85.2 × 85.1 mmBoost convertor, the printed circuit board in 3D

    Boost convertor

    sakshamgupta2004/VegapodAll

    All the vegapod material

    55 parts
  • 4 layers144 × 112 mmQuadcuber, the printed circuit board in 3D

    Quadcuber

    gonewx/quadcuber

    本目录是 A1 电子源目录。打开 quadcuber.kicadpro,包含原生可编辑原理图和四层 PCB、本地符号/封装库。本设计为单块PCB,RP2040、QSPI Flash、晶振、USB-C、驱动和电源均直接焊接在板上;A0的Pico H插装已移除。马达使用EV3裸插座。接线定义仍从 ../wiring/spec.py 导入,固件未改动,也没有把 R/L 固件描述成已支持四臂控制。

    200 parts
  • 4 layers68 × 75 mmDeltaRhoRobot, the printed circuit board in 3D

    DeltaRhoRobot

    valleyquail/DeltaRhoPCB

    PCB files for the robot

    119 parts1
  • 4 layers240 × 180 mmOparroy ci, the printed circuit board in 3D

    Oparroy ci

    kristofferkoch/oparroy

    WS2812 inspired versatile serial protocol and hardware

    570 partsMIT
  • 2 layers100.1 × 121.4 mmPanel, the printed circuit board in 3D

    Panel

    da-penguin-guy/Proteus

    The Proteus is a modular collection of PCBs that will be used to develop the Virgil sound Protocol

    137 parts3
  • 2 layers60 × 70 mmMedia controller, the printed circuit board in 3D

    Media controller

    bgb-0/media-controller

    Open-source USB-C media controller. RP2040, 3× MX hot-swap keys, EC11 encoder, SSD1306 OLED. KiCad + QMK.

    42 parts1GPL-2.0

Questions

How big is the Digits pcb PCB?

It measures 61.9 × 76.2 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Digits pcb use?

77 parts, built around the RP2040, DRV8871DDARQ1, TLV320AIC3104IRHBR and W25Q16JVSSIQ. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Digits pcb KiCad files?

From the justinlindh/digits repository on GitHub, at the commit this page was made from: the board is hardware/pcb/v3/kicad/digits-pcb.kicad_pcb and its schematic hardware/pcb/v1/kicad/digits-pcb.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Digits pcb design in my own project?

Its repository publishes it under the AGPL-3.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).