diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..20913a5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,45 @@ +version: 2 + +# Only github-actions applies here. There is no Dependabot ecosystem for +# arduino-cli, so the core and library pins in .github/workflows/*.yml +# (PLATFORM_VERSION, ONEWIRE_VERSION, ETHERNET3_VERSION) are NOT tracked below +# and have to be reviewed by hand. That is deliberate rather than an oversight: +# this firmware sits at ~95% of flash, so a toolchain bump can push it over the +# ceiling and wants a human looking at the size delta. +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + time: "09:00" + timezone: America/Los_Angeles + + # One PR for everything, rather than one per action. + groups: + github-actions: + patterns: + - "*" + update-types: + - minor + - patch + - major + + # Produces "chore(deps): bump the github-actions group with 3 updates". + # + # "chore" is deliberate, not cosmetic. Under release-please's default + # versioning strategy only feat, fix and breaking changes bump a version, so + # a chore commit cannot cause a release on its own -- merging a Dependabot PR + # will not mint a new firmware version. "chore" is also hidden in + # changelog-sections, so action bumps stay out of release notes that are read + # by people deciding whether to reflash a board. + # + # It also has to be *some* conventional prefix: without one, every Dependabot + # PR would fail the check in .github/workflows/commits.yml. + commit-message: + prefix: chore + include: scope + + labels: + - dependencies + open-pull-requests-limit: 3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..35b7759 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI + +on: + push: + branches: [main, osl-docs] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + bom: + name: BOM / layout consistency + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + # Pure stdlib -- deliberately needs no EDA tooling, so it stays fast and + # cannot break when pcb-rnd or lepton-eda change. + - name: Check assembly files against the layouts + run: python3 tools/check_bom.py --allow-known + + links: + name: docs links + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Check relative links in markdown resolve + run: | + python3 - <<'PY' + import pathlib, re, sys + root = pathlib.Path('.') + bad = 0 + for md in sorted(root.rglob('*.md')): + if '.git' in md.parts: + continue + for m in re.finditer(r'\[([^\]]*)\]\(([^)\s]+)\)', md.read_text(encoding='utf-8')): + target = m.group(2) + if target.startswith(('http://', 'https://', '#', 'mailto:')): + continue + if not (md.parent / target.split('#')[0]).exists(): + print(f"BROKEN {md}: [{m.group(1)}]({target})") + bad += 1 + print(f"\n{bad} broken relative link(s)") + sys.exit(1 if bad else 0) + PY diff --git a/.github/workflows/commits.yml b/.github/workflows/commits.yml new file mode 100644 index 0000000..d1d55ec --- /dev/null +++ b/.github/workflows/commits.yml @@ -0,0 +1,72 @@ +name: Commits + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + lint: + name: conventional + sign-off + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + # Every commit is preserved on main (we do not squash), so every commit is + # what release-please parses and what the changelog is built from. A + # non-conventional subject does not fail at release time -- the change just + # silently never appears in the changelog. So it is checked here instead. + - name: Check every commit in this PR + env: + BASE: ${{ github.event.pull_request.base.sha }} + HEAD: ${{ github.event.pull_request.head.sha }} + run: | + python3 - <<'PY' + import os, re, subprocess, sys + + TYPES = "feat|fix|perf|docs|build|ci|refactor|test|chore|revert" + SUBJECT = re.compile(rf"^({TYPES})(\([a-z0-9._/-]+\))?!?: .+") + + rng = f"{os.environ['BASE']}..{os.environ['HEAD']}" + shas = subprocess.run( + ["git", "rev-list", "--no-merges", rng], + capture_output=True, text=True, check=True, + ).stdout.split() + + # Bots cannot sign off: Dependabot has no DCO option. Their commits still + # have to be conventional -- Dependabot uses chore(deps), which keeps it + # out of the changelog and stops it triggering a release, but it still + # has to parse. + BOTS = ("dependabot[bot]", "github-actions[bot]", "release-please[bot]") + + bad = [] + for sha in shas: + msg = subprocess.run( + ["git", "log", "-1", "--format=%B", sha], + capture_output=True, text=True, check=True, + ).stdout + author = subprocess.run( + ["git", "log", "-1", "--format=%an <%ae>", sha], + capture_output=True, text=True, check=True, + ).stdout.strip() + subject = msg.splitlines()[0] if msg.strip() else "" + short = sha[:8] + is_bot = any(b in author for b in BOTS) + if not SUBJECT.match(subject): + bad.append(f"{short} not conventional: {subject!r}") + elif subject[len(subject.split(':')[0]) + 2:][:1].isupper(): + bad.append(f"{short} subject should start lowercase: {subject!r}") + if subject.endswith("."): + bad.append(f"{short} subject should not end with a period: {subject!r}") + if not is_bot and "Signed-off-by:" not in msg: + bad.append(f"{short} missing Signed-off-by (commit with -s): {subject!r}") + + print(f"checked {len(shas)} commit(s) in {rng}") + for line in bad: + print(f"::error::{line}") + if bad: + print("\nFix with: git rebase -i --signoff " + os.environ["BASE"]) + sys.exit(1) + print("all commits OK") + PY diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..539414e --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,31 @@ +name: release-please + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v5.0.0 + id: release + with: + # Falls back to GITHUB_TOKEN when the secret is not set, so this + # workflow works either way. But a PR created with GITHUB_TOKEN does + # not trigger workflows, so its required checks never report and it + # shows as blocked by branch protection -- mergeable only by an admin. + # Setting RELEASE_PLEASE_TOKEN (see CONTRIBUTING.md) makes release PRs + # run CI like any other and removes the need for that bypass. + token: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }} + config-file: release-please-config.json + manifest-file: .release-please-manifest.json + + outputs: + released: ${{ steps.release.outputs.release_created }} + tag: ${{ steps.release.outputs.tag_name }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..e18ee07 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.0" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..085f922 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,610 @@ +# AGENTS.md — PRC / PROC-V1 PC Remote Control Card + +Orientation and reference for agents (and humans) working in this repository. +Everything upstream is written in Chinese; this file is the English working +translation plus the analysis that is not written down anywhere else. + +**Last verified:** 2026-07-25 against `lshw/prc` @ `5bf428b`, `lshw/proc` @ `a8f458f`, +`lshw/procV2` @ 2025-07-28, and https://bjlx.org.cn/node/914 + /node/926. + +--- + +## 1. Read this first: the firmware is not in this repository + +This repo (`lshw/prc`) is **the hardware design plus an abandoned prototype sketch.** +It has not been touched since 2020-01-31. + +The sketch at [control/control.ino](control/control.ino) is a 182-line +TCP-to-serial pass-through with no menu, no authentication, no DHCP, no +configuration and no temperature support. It is *not* what ships on the boards. + +The production firmware lives in a **different repository**, `lshw/proc`, which +was seeded from this very file on 2020-01-02 (the two files still differ by only +11 lines) and then developed for another five years. Verified: + +- `git cat-file -t d58845a` and `4b34ae9` — the commit IDs baked into the + released `.hex` images — **do not exist in this repository**. +- `lshw/proc` commit `fc48b63` ("init", 2020-01-02) is byte-comparable to + [control/control.ino](control/control.ino). + +> **If the task is "improve the software", the work belongs in +> [osuosl/proc](https://github.com/osuosl/proc/blob/main/AGENTS.md), not here.** + +**This file is the hardware reference.** Firmware build, EEPROM layout, menu, +scripting and the bug list live in [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md). + +--- + +## 2. Where this sits in the workspace + +Related repositories: + +| Directory | Relevance to this repo | +|---|---| +| [osuosl/proc](https://github.com/osuosl/proc/blob/main/AGENTS.md) | **The firmware that runs on this hardware.** Seeded from `control/control.ino` on 2020-01-02 | +| [lshw/procV2](https://github.com/lshw/procV2) | The ESP8266 successor. Different board, different firmware | +| [lshw/jlc_gEDA_pcb](https://github.com/lshw/jlc_gEDA_pcb) | Footprint library the author used for some parts of this board | +| [lshw/pcb](https://github.com/lshw/pcb), [lshw/geda-pcb](https://github.com/lshw/geda-pcb) | Forks of the layout tool that reads `control*.pcb`. Debian's `pcb-rnd` also works | +| [lshw/ATmega328PB](https://github.com/lshw/ATmega328PB) | Arduino core for the MCU on this board. **Not** used by production builds | + +Author: **Liu Shiwei (刘世伟)** ``, Beijing Loongson & +Debian User Club (北京龙芯&debian用户俱乐部, https://bjlx.org.cn/). + +Existing third-party forks of this repo: `winthundr/loongsonprc`, `WSYUTeam/prc` +— both stale (2019–2020) and contain nothing useful. + +Of the author's other repositories, only `prc` and `proc` were forked to OSL. +`procV2` has no LICENSE file (all rights reserved), and the `pcb`, `geda-pcb`, +`optiboot` and `ATmega328PB` forks each carry only one to nine commits of his +own work — take those from their real upstreams instead. See +[CONTRIBUTING.md](CONTRIBUTING.md) for the sync policy. + +--- + +## 3. This repository, file by file + +| Path | What it is | +|---|---| +| [README.md](README.md) | 19-line Chinese product blurb — see §4 for translation | +| [control/control.ino](control/control.ino) | Abandoned prototype sketch (2020-01-02). Historical only | +| [control.sch](control.sch) / [control.pcb](control.pcb) | gEDA `gschem` schematic / `pcb` layout — **rev 1** (has an on-board DB9) | +| [control1.sch](control1.sch) / [control1.pcb](control1.pcb) | **rev 2** — ATmega328PB TQFP32 swap, adds L1 | +| [control2.sch](control2.sch) / [control2.pcb](control2.pcb) | **rev 3, the final layout** in this repo. DB9 removed, R17 added | +| [control_bom.csv](control_bom.csv), [control1_bom.csv](control1_bom.csv) | JLCPCB assembly BOM (`编号` column = JLCPCB part number, e.g. `C38896`) | +| [control_xy.csv](control_xy.csv), [control1_xy.csv](control1_xy.csv) | JLCPCB pick-and-place centroid files | +| [20191222.zip](20191222.zip), [20191223.zip](20191223.zip) | Gerber + drill sets sent to fab | +| [control.pdf](control.pdf), [control.png](control.png) | Rendered schematic + PCB (the PNG is the best single overview) | +| [com.pdf](com.pdf), [w5500.pdf](w5500.pdf) | Footprint/mechanical drawings (image-only, no text layer) | +| [link.txt](link.txt) | Serial cable pin mapping — see §6.4 | +| [update.sh](update.sh) | One-line `avrdude` invocation. Superseded by the version in `lshw/proc` | +| [LICENSE](LICENSE) | LGPL-3.0 | + +**Note:** there is no `control2_bom.csv` / `control2_xy.csv`. The final layout was +never re-exported for assembly in this repo. + +### Working with the EDA files + +All of the required tools are already installed on this machine: + +```bash +lepton-schematic control2.sch # gEDA/gschem-format schematic (lepton-eda 1.9.18) +pcb-rnd control2.pcb # gEDA pcb-format layout (pcb-rnd 3.1.6) +gerbv 20191223/*.gbr # Gerber viewer +``` + +`geda-pcb` itself is no longer in Debian; `pcb-rnd` and `lepton-eda` are the +maintained successors and read these files. The author uses his own forks +(`lshw/pcb`, `lshw/geda-pcb`) and the `lshw/jlc_gEDA_pcb` footprint library. + +The `.pcb` file carries an embedded `NetList()` block — that is the fastest way +to answer connectivity questions without opening a GUI: + +```bash +sed -n '/^NetList/,$p' control2.pcb +grep -o '^Element\[[^]]*\]' control2.pcb # refdes + footprint + value +``` + +--- + +## 4. Translations of the upstream Chinese documentation + +> **Fork divergence:** in this fork the in-repo Chinese has already been +> translated in place — [README.md](README.md), +> [control/control.ino](control/control.ino), [link.txt](link.txt) and the +> `编号` column header in both BOMs are now English. Upstream is still Chinese, +> so **expect conflicts on those files when rebasing on `upstream/master`**. +> The translation is one isolated commit; `git log --oneline -- README.md +> control/control.ino link.txt` finds it if it needs to be replayed or dropped. + +### 4.1 [README.md](README.md) + +> **PC Remote Control Card** +> +> Uses a W5500 10M/100M network chip to expose a PC's serial port on a TCP port, +> which makes remote Linux maintenance convenient. It can also drive the reset +> and power buttons, provides one 20 A switched voltage output, and provides +> chassis temperature monitoring supporting up to 32 temperature probes. +> +> Input voltage 5–30 V. +> Serial speeds 300–921600 bps. +> Development environment: Arduino. +> +> Seven units were donated to the Debian MIPS build machine cluster; they work well. +> +> Taobao item: https://item.taobao.com/item.htm?id=611681003797 +> Taobao shop: https://shop316166779.taobao.com + +Two claims in this README do not match the shipping firmware: "up to 32 +temperature probes" — the firmware supports **10** — and "20 A output", which is +a MOSFET/copper rating, not something the firmware knows about. See §8 issue H4. + +### 4.2 Commit log, translated + +Read newest-first. This is the whole history of this repo. + +| Date | Commit | Chinese | English | +|---|---|---|---| +| 2020-02-01 | `5bf428b` | 成品样机完成,增加淘宝链接 | Finished prototype complete; add Taobao links | +| 2020-01-21 | `6f18abf` | firmware升级脚本 | Firmware update script | +| 2020-01-02 | `1fef6fe` | 初步的RJ45-串口透传程序 | Preliminary RJ45-to-serial pass-through program | +| 2020-01-01 | `3afd16c` | 调整pcb | Adjust PCB | +| 2020-01-01 | `0686cb0` | w5500测试 | W5500 test | +| 2019-12-30 | `9471b27` | pcb2 | PCB rev 2 | +| 2019-12-30 | `2598147` | ardino程序 | Arduino program | +| 2019-12-28 | `a3ad509` | 根据贴片进行调整 | Adjust according to (SMT) assembly | +| 2019-12-23 | `f3beeac` | 修改cpu 封装格式 | Change the CPU package format (TQFN32 → TQFP32, 328P → 328PB) | +| 2019-12-23 | `16ac95b` | fix bom xy file | — | +| 2019-12-22 | `6743553` | 最终pcb稿 20191222 | Final PCB draft 2019-12-22 | +| 2019-12-22 | `3096ff0` | w5500封装 | W5500 footprint | +| 2019-12-21 | `627081a` | 根据嘉立创的规范, 调整元件型号和方向 | Adjust part numbers and orientations to JLCPCB's rules | +| 2019-12-21 | `38e7797` | mos管背靠背,防止电源进出接反,通过寄生二极管损坏mos管 | Back-to-back MOSFETs, to stop a reversed supply from destroying them through the body diode | +| 2019-12-21 | `9065fb9` | 增加S1复位开关 | Add reset switch S1 | +| 2019-12-21 | `4044844` | Initial commit | — | + +### 4.3 Hardware manual — https://bjlx.org.cn/node/914 (2020-04-25) + +*Abridged. Full translation with images: [doc/node-914-hardware-manual.md](doc/node-914-hardware-manual.md).* + +> **PROC-V1 Remote Controller Hardware User Manual** +> +> PROC (PC remote operation controller) can control a PC's reset button and power +> button over the network, for remote power on/off and remote restart. It can also +> enter the serial port and interact with the BIOS, bootloader and Linux console +> to complete OS installation, network configuration, fault recovery, remote +> maintenance and so on. +> +> PROC-V1 is the RJ45 version. PROC-V2 is the WiFi version. Installation of V1 follows. +> +> **Installation** (the pinout photo is an early revision; the newer PROC V1.1 no +> longer distinguishes switch polarity): +> +> Take power from the power supply's purple wire (standby 5 V) and black wire +> (ground). The purple wire supplies 5 V while the computer is off. +> +> Motherboard front-panel switches usually look like this. PROC provides two sets +> of switch leads: an ordinary 2-pin Dupont lead, and a 2×5 shell — you can pull +> the HDD-LED and power-LED wires out of their Dupont shells, fit them into the +> 2×5 shell, and plug the whole thing onto the motherboard. +> +> That completes the installation. For a router or a mini PC with a separate 12 V +> input, you have to solder your own leads. +> +> The serial port is **RS-232 level — do not connect it to a TTL-level serial +> port**. Two sets of leads are provided: an external 9-pin serial cable and an +> internal 2×5 Dupont header for the motherboard. Any other cable shape you make +> yourself. + +Board-photo annotations (translated): + +- 5-30V电源输入 — 5–30 V power input +- 大电流输入直接焊在这里 — solder the high-current input directly here +- 大电流输出焊点 — high-current output solder pad +- 大电流负极焊点在背面 — the high-current negative pad is on the back side +- 去主板的电源开关,分正负 — to the motherboard power switch; polarity matters +- 去主板的复位开关 分 正 负 — to the motherboard reset switch; polarity matters +- 插原来的按键开关杜邦线 — plug in the original button-switch Dupont lead +- 串口 — serial port +- 复位线和开机线连接方式,如果出现按键不可控,把极性反转一下 — how to wire the + reset and power lines; if the buttons do not respond, reverse the polarity + +Attachments on that page: + +- https://bjlx.org.cn/system/files/update_0.sh — flashing script +- https://bjlx.org.cn/system/files/prc.ino__0.hex — `PROC-V1-20210201-4b34ae9` firmware +- Images: `proc_v1.1.png` (V1.1 board pinout), `9pin_com.png` (motherboard COM header), + `proc_pcb.preview.jpeg`, `power.preview.jpeg`, `mb_switch.jpeg`, `proc_com_0.jpeg`, + `proc_ok_0.jpeg` — all under https://bjlx.org.cn/system/files/images/ + +### 4.4 Software manual — https://bjlx.org.cn/node/926 (2020-04-26) + +*Abridged. Full translation, annotated with every point where it no longer +matches the firmware: [proc: vendor software manual](https://github.com/osuosl/proc/blob/main/doc/node-926-software-manual.md).* + +> **PROC software instructions** +> +> Default IP is **192.168.1.2/24**. For initial setup, log in over the serial port, +> or configure your PC onto that subnet and `telnet 192.168.1.2`. +> +> There is **no password by default**. You can set one; the password only applies +> to network logins. +> +> To log in over serial: `minicom -D /dev/ttyS0 -b 115200 -R utf-8`, then type +> seven `+` and seven `U` followed by Enter. If nothing happens, PROC may be busy +> doing DHCP — wait 30 seconds and try again. +> *(See §8 issue 9 — the current firmware wants **six** of each.)* +> +> Set telnet to character mode by default; in the default line mode nothing is +> sent until you press Enter. Create `~/.telnetrc` with these three lines — no +> leading space on the first line, leading spaces on the other two: +> +> ``` +> default +> mode character +> set binary +> ``` +> +> then `telnet 192.168.1.2`. Besides telnet you can also connect with PuTTY. +> +> When logging in over serial you must first type `+++++++UUUUUUU` and Enter +> before it responds. This is to stop serial output during PC boot from +> interfering with the boot process. +> +> After login the main menu appears. It is very simple: `0` enters serial +> pass-through; `r`, `R`, `p`, `P` control the PC's power switch and reset. +> If the PWM option is fitted, `<`, `,`, `.`, `>` control the PWM output. +> There are also user scripts 1–9 (documented on a separate page), plus network +> setup, password setup, serial setup, script setup, factory reset and reboot. +> +> After setting the network to DHCP you can enable **active outbound mode** to +> work around not having a public IP or VPN. In active outbound mode you set a +> remote server (IP or hostname); PROC periodically connects to that server's +> port, and on the server you just listen with `nc` or `socat` to reach PROC's +> menu, control the machine, and log in over serial. +> *(See §8 issue 10 — this feature was **removed** from the firmware in 2024.)* +> +> **PROC script commands** — main menu `f`, then pick a script (1–9). Each script +> is at most 50 characters: +> +> | Cmd | Meaning | +> |---|---| +> | `P` | press the power switch; optional following number (1–65536) = hold in ms. Non-blocking — the next command runs immediately | +> | `p` | release the power switch | +> | `R` | press the reset switch; optional following number (1–65536) = hold in ms. Non-blocking | +> | `r` | release the reset switch | +> | `V` | turn the (5–28 V) output on | +> | `v` | turn the (5–28 V) output off | +> | `M` | followed by a number (0–255): set PWM output | +> | `T` | followed by a number (1–65536): wait this many ms. **Blocking** — the next command runs only after the delay | +> +> **Serial-console setup on the managed machine** (this is the genuinely useful part): +> +> *Redirect BIOS output to serial* — needs motherboard support, e.g. +> `Server Management → Console Redirection → Console Redirection = "Serial Port A"`. +> +> *PMON output on serial* — needs no setup; PMON supports serial directly. The +> `boot.cfg` menu is not drawn but keyboard input works. LoongArch board firmware +> outputs on serial as long as no monitor is plugged in — but release firmware +> usually lacks serial support, so use a `dbg` build. +> +> *GRUB 1* (`/boot/grub/menu.list`): +> `GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8"` +> +> *GRUB 2* (`/etc/default/grub` or `/etc/default/grub.d/serial.cfg`): +> ``` +> GRUB_TERMINAL="serial console" +> GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" +> GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty" +> ``` +> +> *Kernel boot messages on serial* — add `console=ttyS0,115200n8 console=tty0` +> to the kernel command line via GRUB. +> +> *Login shell on serial* — non-systemd: add to `/etc/inittab` then `kill -1 1`: +> `T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100` +> systemd: `systemctl start getty@ttyS0 && systemctl enable getty@ttyS0` + +Attachments on that page: + +- https://bjlx.org.cn/system/files/procv1_20200523.zip — three firmware builds: + `prcv1.hex` (minimal), `prcv1_pwm.hex`, `prcv1_pwm_autolink.hex` +- https://bjlx.org.cn/system/files/telnetrc. — the `~/.telnetrc` above + +--- + +## 5. Released firmware binaries (for comparison / rollback) + +Version strings extracted with `strings` from the Intel-HEX images: + +| File | Version string | Flash used | % of 30720 | +|---|---|---|---| +| `prcv1.hex` | `PROC-V1-20200523-d58845a` | 30452 | 99.1% | +| `prcv1_pwm.hex` | `PROC-V1-20200523-d58845a` | 30672 | 99.8% | +| `prcv1_pwm_autolink.hex` | `PROC-V1-20200523-d58845a` | 31406 | 102.2% (!) | +| `prc.ino__0.hex` | `PROC-V1-20210201-4b34ae9` | 30642 | 99.7% | +| current `lshw/proc` HEAD (`a8f458f`) | `PROC-V1-20241103-a8f458f` | **29062** | **94.6%** | + +The `autolink` image exceeds the 30720 bytes left by a 2 KB bootloader, so that +2020 build must have been paired with a 512-byte bootloader (hfuse `0xDE`) rather +than the 2 KB one (`0xDA`) the current build assumes. Check the fuses on any +board before flashing an old image onto it. + +Useful one-liner for pulling strings out of a `.hex`: + +```bash +python3 -c " +import sys +d=bytearray();base=0 +for l in open(sys.argv[1]): + l=l.strip() + if not l.startswith(':'): continue + b=bytes.fromhex(l[1:]); n,a,t=b[0],(b[1]<<8)|b[2],b[3] + if t==0: + a+=base + if len(d) prcv1.bin +strings -n 4 prcv1.bin +avr-objdump -D -m avr5 -b binary prcv1.bin | less # binutils-avr is installed +``` + +--- + +## 6. Hardware reference + +Derived from the `NetList()` block in [control2.pcb](control2.pcb) (rev 3, the +final layout here), cross-checked against [control.png](control.png) and the +V1.1 board photo at https://bjlx.org.cn/system/files/images/proc_v1.1.png. + +Board size: **52.0 × 36.0 mm**, 2 layers. + +### 6.1 Major parts + +| Ref | Part | Role | +|---|---|---| +| U3 | **ATmega328PB**, TQFP-32 | MCU. Runs at **3.3 V / 8 MHz on the internal RC oscillator** | +| U7 | **W5500** | 10/100 Ethernet MAC+PHY with hardware TCP/IP, on SPI | +| U2 | **SP3232** (SSOP-16) | RS-232 transceiver (2× TX, 2× RX) | +| U1 | **MP1584** (SO-8) | Buck converter, VIN → 3.3 V | +| U4, U5, U10, U11 | **AO4407A** P-ch MOSFET ×4 | High-side VOUT switch, wired **source-to-source (back-to-back)** so the body diodes block reverse current in both directions | +| Q1 | **AO3400A** N-ch MOSFET | Level shifter driving the P-FET gate node | +| U8, U9 | **EL357N** optocouplers | Isolated dry-contact outputs to the PC's power / reset switch headers | +| U6 | 8 MHz crystal + C11/C12 22 pF | **Footprint present but not populated** — it is absent from both BOMs, which is why the firmware calibrates `OSCCAL` (see §7.5) | +| D3 | **DS18B20** (TO-92) | On-board 1-Wire temperature sensor — **also the device's identity** (see §6.5) | +| L1 | 10 µH, D1 SS34 | Buck inductor + catch diode | +| D2 | 20 V zener | Gate-source clamp on the P-FET bank | +| S1 | Pushbutton | MCU hardware reset | +| LED1 blue / LED2, LED3 red | | See §6.3 | + +### 6.2 MCU pin map + +Package pins confirmed against the netlist (GND on 3/5/21, VCC on 4/6, AVCC on 18, +crystal on 7/8 — the standard 32-pin ATmega328P/PB arrangement). + +| Net | Pkg pin | Port | Arduino | Function | +|---|---|---|---|---| +| `_24V_OUT` | 1 | PD3 | **D3** | Drives Q1 → P-FET bank → VOUT. `HIGH` = output on | +| `NET_RESET` | 2 | PD4 | **D4** | W5500 `/RST` | +| `INT` | 32 | PD2 | **D2** | W5500 `/INT` — **wired but unused by the firmware** | +| `CS` | 14 | PB2 | **D10** | W5500 `SCS` | +| `MOSI` | 15 | PB3 | **D11** | SPI MOSI — also ISP | +| `MISO` | 16 | PB4 | **D12** | SPI MISO — also ISP | +| `CLK` | 17 | PB5 | **D13** | SPI SCK — also ISP — **and LED1 (blue) via R9** | +| `RX` | 30 | PD0 | **D0** | UART RX ← SP3232 R1OUT | +| `TX` | 31 | PD1 | **D1** | UART TX → SP3232 T1IN | +| `DS` | 26 | PC3 | **A3** | 1-Wire bus, R10 3.3 kΩ pull-up to 3V3 | +| `PC_RESET` | 27 | PC4 | **A4** | → R15 → opto U9 → reset header; **and LED3 (red) via R14** | +| `PC_POWER` | 28 | PC5 | **A5** | → R13 → opto U8 → power header; **and LED2 (red) via R12** | +| `RESET` | 29 | PC6 | `/RESET` | S1, R11 10 kΩ pull-up, and the CONN3 auto-reset jumper | +| — | 9 | PD5 | **D5** | **PWM output on V1.1 boards** (firmware `#define PWM 5`). Not routed on the rev-3 layout in this repo | + +### 6.3 LEDs + +| LED | Colour | Driven by | Meaning | +|---|---|---|---| +| LED1 | blue | `CLK` / D13 via R9 10 kΩ | Flickers with SPI traffic to the W5500 — effectively a network-activity light | +| LED2 | red | `PC_POWER` / A5 via R12 10 kΩ | Lit while the PC power button is being "pressed" | +| LED3 | red | `PC_RESET` / A4 via R14 10 kΩ | Lit while the PC reset button is being "pressed" | + +### 6.4 Connectors + +| Ref | Pins | Purpose | +|---|---|---| +| CONN1 | 2 | **VIN**, 5–30 V DC. Large solder pads alongside for high current | +| CONN4 | 2 | **VOUT**, switched, 5–28 V. Large solder pads; **the negative pad is on the back of the board** | +| CONN5 | 3 | External 1-Wire probes: 3V3 / DQ / GND | +| CONN3 | 2 | **"Update" jumper.** SP3232 R2OUT → C5 100 nF → MCU `/RESET`. Closed = the host's RTS/DTR can reset the MCU (needed for `avrdude -c arduino`). Leave open in normal service so the managed PC cannot reset the controller | +| CONN6 + CONN8 | 2 + 2 | **PC POWER switch**, opto U8 collector/emitter. Two headers in parallel: plain 2-pin Dupont and the 2×5 shell | +| CONN7 + CONN9 | 2 + 2 | **PC RESET switch**, opto U9. Same pairing | +| CONN10 | 6 | Serial header — see below | +| CONN2 | DB9 | **rev 1 only** — the on-board 9-pin D-sub was deleted in rev 3 | + +CONN10 pinout (silkscreen on the V1.1 board reads `RTS TX_232 RX_232 GND RX_TTL TX_TTL`): + +| Pin | Net | Level | Goes to | +|---|---|---|---| +| 1 | `TX` | **TTL** | MCU PD1 and SP3232 T1IN | +| 2 | `RX` | **TTL** | MCU PD0 and SP3232 R1OUT | +| 3 | `GND` | — | | +| 4 | `HRX` | **RS-232** | SP3232 R1IN — the host's TX comes in here | +| 5 | `HTX` | **RS-232** | SP3232 T1OUT — goes out to the host's RX | +| 6 | `RTS` | **RS-232** | SP3232 R2IN → R2OUT → C5 → CONN3 → MCU `/RESET` | + +Cable mapping from [link.txt](link.txt) — 9-pin male / 9-pin female / the 6-pin header: + +| Signal | DB9 male | DB9 female | 6-pin | +|---|---|---|---| +| GND | 5 | 5 | 3 | +| TX | 2 | 3 | 4 | +| RX | 3 | 2 | 5 | +| DTR | 8 | 7 | 6 | + +The motherboard's internal 2×5 COM header (image `9pin_com.png`) is the standard +layout: bottom row pin 1 `DCD`, `TXD`, `GND`, `RTS`, `RI`; top row `RXD`, `DTR`, +`DSR`, `CTS`. + +### 6.5 Power tree and the VOUT switch + +``` +CONN1 VIN (5-30V) ─ C1 10uF/50V ─┬─ R4 100k / R5 ── MP1584 EN (under-voltage lockout) + ├─ MP1584 (U1) ── L1 10uH ── C2 100uF ── Vcc 3.3V + │ D1 SS34 catch diode + │ R1 120k / R2 39k feedback: 0.8V * (1 + 120/39) = 3.26V + └─ U10/U11 (P-FET, source) ══╗ + ║ gates tied, R7 1M to VIN, + ║ D2 20V zener clamp, + ║ pulled down through R8 47k by Q1 + U4/U5 (P-FET, source) ════╝ + └─ CONN4 VOUT (switched) + +Vcc 3.3V ─ ATmega328PB, W5500, SP3232, DS18B20 +``` + +R17 (1 MΩ, added in rev 3) pulls the `_24V_OUT` gate net down so the output stays +off while the MCU is in reset. + +> **Component-value discrepancy:** R5 (the MP1584 enable divider) is `27k` in +> [control_bom.csv](control_bom.csv), [control1_bom.csv](control1_bom.csv) and the +> rendered schematic, but `72k` in the `Element[]` line of both +> [control.pcb](control.pcb) and [control2.pcb](control2.pcb). This changes the +> input under-voltage lockout from ~7.0 V to ~3.6 V — i.e. whether the board +> actually starts at the 5 V the README claims. **Measure a real board before +> respinning.** Similarly C4 is `0.01uF` on the schematic (MP1584 bootstrap) but +> is ordered as `100nF` in both BOMs. Tracked as §8 issues H1 and H2. + +### 6.6 Device identity — the DS18B20 is the serial number + +This is non-obvious and matters for a fleet. On first boot the firmware: + +1. Enumerates the 1-Wire bus. If exactly one probe is found, its 64-bit ROM code + is written to EEPROM as the device **serial number** (`SN0..SN7`). +2. Builds the **MAC address** as `DC:AD:BE:::`. +3. Sets the default **device name** to `PROC` + the same three bytes in hex. + +So the on-board DS18B20 (D3) is what makes each unit unique. Consequences: + +- The `#SN:` line in the banner is the DS18B20 ROM code. +- Probe index 0 is reserved for the identity probe and is excluded from the + temperature display. +- `DC:AD:BE` is not an IEEE-assigned OUI **and has the locally-administered bit + clear**, so these boards claim a globally-unique OUI they do not own. Setting + bit 1 of the first octet (e.g. `DE:AD:BE`) would be correct. Worth fixing in a fork. +- If the probe is missing or fails, see §8 issue 5 — the unit factory-resets on + every boot. + +--- + +## 7. Firmware — see [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) + +The firmware reference used to live here. It now lives with the code: + +| Topic | Where | +|---|---| +| Building (`arduino-cli`, FQBN, libraries, flash budget) | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §3 | +| Bootloader and fuses (why the crystal is unpopulated) | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §3 | +| Flashing with `avrdude` (and the CONN3 "Update" jumper) | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §3 and §6.4 below | +| EEPROM layout, factory defaults | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §4.2 | +| Device identity from the DS18B20 | §6.6 below, and [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §4.3 | +| RC-oscillator calibration | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §4.4 | +| Menu, banner, escape sequences, script language | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §4.5–4.7 | +| **Verified bug list and improvement targets** | [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §5 | + +## 8. Hardware-side issues found while reading these files + +Firmware bugs are in [osuosl/proc AGENTS.md](https://github.com/osuosl/proc/blob/main/AGENTS.md) §5. These are the +problems that live in *this* repository: + +> **Tracked as GitHub issues** — . +> H1 → [#1](https://github.com/osuosl/prc/issues/1) · +> H3 → [#2](https://github.com/osuosl/prc/issues/2) · +> H5 → [#3](https://github.com/osuosl/prc/issues/3). +> H2 (C4) is folded into #1; H4 was fixed by the README rewrite. +> `tools/check_bom.py` enforces H1 and H3 in CI. + +| # | Severity | Issue | +|---|---|---| +| H1 | **Check before respin** | **R5 disagrees between the BOM and the layout.** `27k` in [control_bom.csv](control_bom.csv), [control1_bom.csv](control1_bom.csv) and the rendered schematic; `72k` in the `Element[]` line of both [control.pcb](control.pcb) and [control2.pcb](control2.pcb). R5 is the MP1584 enable divider, so this moves the input under-voltage lockout between roughly 7.0 V and 3.6 V — i.e. whether the board starts at the 5 V the README claims. **Measure a real board.** | +| H2 | Low | **C4 disagrees too** — `0.01uF` on the schematic (the MP1584 bootstrap cap, where 10 nF is conventional) but ordered as `100nF` in both BOMs | +| H3 | Medium | **The final layout was never re-exported for assembly.** `control2.pcb` is rev 3, but there is no `control2_bom.csv` / `control2_xy.csv`, and the Gerber zips ([20191222.zip](20191222.zip), [20191223.zip](20191223.zip)) predate it. Anything sent to a fab must be re-exported from rev 3 | +| H4 | Low | **The README overstates the firmware.** "Up to 32 temperature probes" — the firmware supports 10. "20 A output" is a MOSFET/copper rating, not something the firmware knows about | +| H5 | Note | **This repo is rev 1.0 hardware.** The vendor sells **V1.1**, which adds a PWM pad (Arduino D5), a W5500 SPI breakout header and TTL serial pads, and — per the vendor page — no longer distinguishes switch polarity. **No V1.1 design files are published anywhere.** If OSL has V1.1 boards, the files here do not fully describe them | + +## 9. Chinese → English glossary + +Terms you will hit constantly in commits, comments and the vendor pages. + +| Chinese | English | +|---|---| +| 远程控制卡 / 远程控制器 | remote control card / remote controller | +| 串口 | serial port | +| 透传 | pass-through (transparent forwarding) | +| 开关机 | power on/off | +| 重启 / 复位 | restart / reset | +| 电源开关 | power switch | +| 看门狗 | watchdog | +| 主动外联 | active outbound connection ("autolink" / dial-out) | +| 固件 | firmware | +| 编译 / 编译机 | compile / build machine | +| 引导程序 / 烧录引导程序 | bootloader / burn bootloader | +| 校准 | calibration | +| 晶振 | crystal oscillator | +| 温度探头 | temperature probe | +| 封装 | (component) footprint / package | +| 贴片 | SMT assembly | +| 嘉立创 | JLCPCB (the fab) | +| 杜邦线 / 杜邦座 | Dupont jumper wire / Dupont header | +| 主板 | motherboard | +| 恢复出厂设置 | restore factory defaults | +| 脚本 | script | +| 菜单 | menu | +| 密码 | password | +| 网段 | subnet | +| 寄生二极管 | (MOSFET) body diode | +| 背靠背 | back-to-back | +| 龙芯 | Loongson (the CPU vendor) | +| 淘宝 | Taobao (the shop) | + +--- + +## 10. Conventions when working in this repo + +- **Do not "fix" the hardware files casually.** `.sch` and `.pcb` are gEDA + formats where a GUI round-trip rewrites the entire file. Edit with `pcb-rnd` / + `lepton-schematic` and keep the diff reviewable, or don't touch them. +- **The final layout here is `control2.*`**, not `control.*`. Anything you export + (BOM, XY, Gerbers) should come from rev 3. +- **Never regenerate the Gerber zips** unless you are actually respinning the + board — they are the record of what was fabricated. +- **Upstream commit messages are Chinese.** In an OSL fork, write commit messages + in English; if a patch is intended for upstream, a bilingual subject line is a + courtesy. +- **Do not edit [control/control.ino](control/control.ino).** It is a dead + prototype kept for history. Firmware changes go in + [osuosl/proc](https://github.com/osuosl/proc/blob/main/AGENTS.md), which has its own conventions. +- **The pin assignments are a hardware contract.** `_24V_OUT`=D3, `NET_RESET`=D4, + W5500 SPI on D10–D13, `DS`=A3, `PC_RESET`=A4, `PC_POWER`=A5 (§6.2). Changing + them here means changing the firmware too, and vice versa. + +## 11. Source documents + +Every vendor page has a **full English translation checked in under +[doc/](doc/)**, with the images mirrored locally. The abridged versions in §4.3 +and §4.4 above are kept for reading in context; the files below are complete. + +| Source | Original title | Translation | +|---|---|---| +| https://bjlx.org.cn/node/914 | PROC-V1 远程控制器硬件用户手册 | [doc/node-914-hardware-manual.md](doc/node-914-hardware-manual.md) | +| https://bjlx.org.cn/node/926 | proc软件使用说明 | [proc: vendor software manual](https://github.com/osuosl/proc/blob/main/doc/node-926-software-manual.md) | +| https://bjlx.org.cn/node/953 | 主板上的串口杜邦座 | [doc/node-953-motherboard-com-header.md](doc/node-953-motherboard-com-header.md) | +| https://bjlx.org.cn/node/954 | procv1.1 hardware | [doc/node-954-procv1.1-hardware.md](doc/node-954-procv1.1-hardware.md) | +| https://bjlx.org.cn/node/929 | PROC-V2 用户手册 | [PROC-V2 manual](https://bjlx.org.cn/node/929) | + +Downloadable artefacts on those pages (not mirrored — they are binaries): + +| URL | What | +|---|---| +| https://bjlx.org.cn/system/files/prc.ino__0.hex | firmware `PROC-V1-20210201-4b34ae9` | +| https://bjlx.org.cn/system/files/procv1_20200523.zip | three 2020-05-23 firmware builds | +| https://bjlx.org.cn/system/files/update_0.sh | flashing script | +| https://bjlx.org.cn/system/files/telnetrc. | `~/.telnetrc` for character-mode telnet | +| https://item.taobao.com/item.htm?id=611681003797 | product listing | diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c2a8033 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,43 @@ +# Changelog + +**This file is maintained by [release-please](https://github.com/googleapis/release-please).** +Do not edit the generated sections by hand — write +[conventional commits](CONTRIBUTING.md#commit-messages) and they will appear +here on the next release. + +A release here is a snapshot of the **design and its documentation**, not a +fabricated board revision. Board revisions are `control.*`, `control1.*`, +`control2.*` and the unpublished V1.1; see [README.md](README.md). + + + +## Fork baseline + +Context for everything above, written by hand before release automation existed. + +OSU OSL's fork of [`lshw/prc`](https://github.com/lshw/prc) by Liu Shiwei, who +designed the board. Fork point is +[`5bf428b`](https://github.com/lshw/prc/commit/5bf428b) (2020-02-01); upstream +has not changed since. + +The baseline translated all Chinese text (README, prototype sketch comments, +`link.txt`, the BOM part-number column — no schematic, layout, footprint, BOM +value or centroid data was touched), added `AGENTS.md` as a hardware reference +derived from the layout's embedded `NetList()`, translated the vendor manuals +under `doc/` with images mirrored locally, and added `tools/check_bom.py` plus +CI. + +It also corrected the README, which claimed support for 32 temperature probes +where the firmware supports 10. + +### Open hardware questions from the baseline + +- **R5 is `27k` in both BOMs and the rendered schematic, `72k` in all three + layouts.** It sets the MP1584 under-voltage lockout, so that is a ~7.0 V + versus ~3.6 V minimum input — whether the board starts at the advertised 5 V. + Needs measuring on a physical board. Baselined in + `tools/known_bom_issues.txt` so CI blocks on new drift meanwhile. +- **`control2.*`, the final layout, was never exported for assembly** — no BOM, + no XY, and the Gerber zips predate it. +- **C4** is `0.01uF` on the schematic but ordered as `100nF` in both BOMs. +- **No design files exist for V1.1**, which is the revision actually sold. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..19343b1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,222 @@ +# Contributing + +## Commit messages + +We use [Conventional Commits](https://www.conventionalcommits.org/), because +[release-please](https://github.com/googleapis/release-please) derives the +version bump and the changelog from them. + +``` +fix: correct the R5 value in both BOM exports + +Longer explanation of why, and what you measured. + +Refs: #1 +Signed-off-by: Your Name +``` + +| Type | Use for | Bumps | +|---|---|---| +| `feat` | a design change — new part, new net, a re-export | minor | +| `fix` | correcting something wrong in the design or its exports | patch | +| `docs`, `build`, `ci`, `refactor`, `chore` | everything else | none | + +Most work here is `docs` or `fix`. Reserve `feat` for changes to the design +itself, and use `!` or a `BREAKING CHANGE:` footer when a change would make an +already-fabricated board incorrect — a changed pinout, a moved connector, a part +that is no longer compatible with firmware in the field. + +**⚠ We do not squash-merge.** Every commit you write lands on `main` intact and +is parsed by release-please, so each one appears in the changelog on its own. CI +checks every commit in a PR for a conventional subject and a `Signed-off-by` +trailer. + +## Sign off every commit + +```bash +git commit -s +``` + +Every commit needs a `Signed-off-by:` trailer (the +[DCO](https://developercertificate.org/)). `-s` generates it from your git +identity; don't write the line by hand. + +## Releases + +Merging to `main` makes release-please open (or update) a release PR that bumps +`version.txt` and `CHANGELOG.md`. Merging that PR tags `vX.Y.Z` and publishes a +GitHub Release. + +**A release here is a snapshot of the design and its documentation, not a +fabricated board revision.** Board revisions are `control.*`, `control1.*`, +`control2.*` and the unpublished V1.1. Don't conflate the two: `v1.2.0` says +nothing about which PCB is in the rack. + +Never hand-edit [CHANGELOG.md](CHANGELOG.md) or `version.txt`; release-please +owns both. Release PRs are created with `GITHUB_TOKEN`, so CI does not run on +them and they show as blocked by branch protection — see +[Branch protection](#branch-protection). + +## Branch protection + +`main` is protected: + +| Rule | Setting | +|---|---| +| Changes must go through a PR | yes, **0 approvals required** | +| Required status checks | all of them (see below) | +| Force pushes / deletions | blocked | +| Conversation resolution | required | +| Linear history | **not** required — merge commits are the workflow | +| Admin enforcement | **off** — see the release caveat below | + +Approvals are not required so a solo maintainer can still land a fix. Review +anyway when there is someone to review. + +### ⚠ The release PR will look blocked + +release-please's PR is created with `GITHUB_TOKEN`, and by GitHub's design a +token-created PR **does not trigger workflows**. So the release PR gets no CI +runs, its required checks never report, and it shows as blocked. + +Admin enforcement is deliberately off so a repo admin can merge it anyway. That +is a workaround, not a fix. + +The workflow already reads `secrets.RELEASE_PLEASE_TOKEN` and falls back to +`GITHUB_TOKEN` when it is unset, so setting the secret is all that is needed. + +**Creating the token** (needs org owner/admin): + +1. — a *fine-grained* + PAT. +2. Resource owner: **osuosl**. Repository access: **only** `osuosl/proc` and + `osuosl/prc`. +3. Repository permissions — exactly two: + - **Contents: Read and write** (branches, commits, tags, releases) + - **Pull requests: Read and write** (open and update the release PR) +4. Expiry: pick a date and put a calendar reminder on it. An expired token + fails silently — release PRs simply stop appearing. +5. If the org requires approval for fine-grained PATs, approve it at + *Organization settings → Personal access tokens → Pending requests*. + +**Storing it** — set it once at the org so both repos share it: + +```bash +gh secret set RELEASE_PLEASE_TOKEN --org osuosl --repos proc,prc +# paste the token at the prompt; it is read from stdin and never hits your shell history +``` + +Per-repo instead, if you prefer: + +```bash +gh secret set RELEASE_PLEASE_TOKEN --repo osuosl/proc +gh secret set RELEASE_PLEASE_TOKEN --repo osuosl/prc +``` + +**After it works** — confirm a release PR shows CI runs, then close the loop by +turning admin enforcement back on, which is the whole point of the exercise: + +```bash +gh api -X PATCH repos/osuosl/proc/branches/main/protection/enforce_admins +gh api -X PATCH repos/osuosl/prc/branches/main/protection/enforce_admins +``` + +**A note on authorship.** A user PAT makes release PRs appear authored by that +user, and they will not be able to approve their own PR if approvals are ever +required. A GitHub App installation token or a dedicated machine account avoids +both, at the cost of more setup. For two low-traffic repos a PAT is proportionate. + +## Merging + +**Merge commit or rebase — never squash.** Squashing collapses a branch into one +commit, which would reduce a PR's worth of distinct fixes to a single changelog +line and lose the individual sign-offs. Squash merging is disabled on the +repository for that reason. + +Keep the branch tidy before it merges, since nothing will tidy it afterwards: +fold up "fix typo" commits with `git rebase -i`, and make sure each surviving +commit is one logical change. + +## ⚠ Check the base repo on every PR + +This repository is a **fork**, so GitHub defaults the base of a new pull request +to **`lshw/prc`** — upstream — not to us. Always confirm the base is +`osuosl/prc` and the branch is `main`: + +```bash +gh pr create --repo osuosl/prc --base main +``` + +No repository setting changes this default; it has to be checked each time. + +## Syncing with upstream: merge, never rebase + +Upstream's default branch is still `master`; ours is `main`. + +```bash +git fetch upstream +git checkout main +git merge upstream/master # NOT rebase +``` + +Our translation commit rewrites `README.md`, `control/control.ino`, `link.txt` +and the BOM part-number column. Rebasing replays that on top of upstream and +re-conflicts every line, every time; merging conflicts once. Upstream has not +moved since 2020-02-01, so this should be rare. + +## Working on the EDA files + +These are gEDA formats. A GUI round-trip rewrites the **entire file**, renumbers +primitives and reorders sections, so a one-component change can produce a +thousand-line diff that nobody can review. + +- Use `pcb-rnd` for `.pcb` and `lepton-schematic` for `.sch`. Both are in Debian. +- **Keep the diff reviewable.** If a GUI save produces churn far beyond your + change, say so in the PR description. +- **`control2.*` is the current layout.** Anything exported — BOM, XY, Gerbers — + must come from rev 3, not from `control.*` or `control1.*`. +- **Never regenerate the Gerber zips** unless you are actually respinning the + board. They are the record of what was fabricated. +- Run `python3 tools/check_bom.py` before pushing. + +## The pin assignments are a contract + +`_24V_OUT`=D3, `NET_RESET`=D4, W5500 SPI on D10–D13, `DS`=A3, `PC_RESET`=A4, +`PC_POWER`=A5. Changing any of them here means changing +[osuosl/proc](https://github.com/osuosl/proc) in the same breath, and reflashing +every deployed board. See [AGENTS.md](AGENTS.md) §6.2 for the full map. + +## Known-issue baseline + +`tools/check_bom.py` fails on any BOM-versus-layout mismatch except those listed +in `tools/known_bom_issues.txt`. That file currently holds the unresolved R5 +discrepancy, so CI blocks on *new* drift without being permanently red. + +**When an entry is resolved, delete it** — that is what turns the check back on +for that part. Don't add entries to silence a finding you haven't investigated. + +## Dependency updates + +Dependabot opens a **single grouped PR** for GitHub Actions, weekly on Monday — +one PR for all actions rather than one per action. + +Its commits are prefixed **`chore(deps):`**, so they never trigger a release +(only `feat`, `fix` and breaking changes bump a version) and stay out of the +changelog, while still satisfying the conventional-commit check. + +Bot authors are exempt from the sign-off requirement, because Dependabot has no +DCO option. They are not exempt from the format check. + +Nothing else here has a manifest Dependabot understands: `tools/check_bom.py` is +pure standard library, by design, so CI has no dependencies to drift. + +## What CI enforces + +| Check | Blocking | Notes | +|---|---|---| +| BOM / layout consistency | yes | except the baselined entries above | +| Relative links in markdown resolve | yes | cross-repo links must be absolute URLs | +| Conventional subject + sign-off, every commit | yes | commits land on `main` intact and drive the changelog | + +None of these need EDA tooling, so CI stays fast and can't break when `pcb-rnd` +changes. diff --git a/README.md b/README.md index 06ba419..dfa7b16 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,112 @@ -PC远程控制卡 +# prc — PROC-V1 remote management board (hardware) -用W5500 10M/100M网卡,把电脑的串口挂在tcp的端口上,方便linux的远程维护。 -还可以控制reset和power按键,提供一路20A的电压输出,提供机箱温度检测, -支持最多32个温度探头。 - -输入电压5-30V +[![CI](https://github.com/osuosl/prc/actions/workflows/ci.yml/badge.svg)](https://github.com/osuosl/prc/actions/workflows/ci.yml) -串口速率支持300-921600Bps +Hardware design for **PROC-V1**, a small board that gives a PC out-of-band +management: network-controlled power and reset buttons, and the machine's serial +console exposed over TCP. Roughly "poor man's IPMI" for hardware without a BMC. -开发环境:arduino +gEDA schematic and PCB, Gerbers, BOM and pick-and-place files. -对debian的mips编译机集群捐助了7台,工作良好 +![PROC-V1 schematic and board](control.png) -![Image](https://github.com/lshw/prc/blob/master/control.png?raw=true) +## ⚠ The firmware is not in this repository -淘宝链接:https://item.taobao.com/item.htm?id=611681003797 +`control/control.ino` here is an **abandoned 182-line prototype** — no menu, no +authentication, no DHCP, no temperature support. It is not what runs on the +boards. -淘宝店铺:https://shop316166779.taobao.com +The firmware lives in **[osuosl/proc](https://github.com/osuosl/proc)**. It was +seeded from this file on 2020-01-02 and developed for another five years; the +two still differ by only 11 lines. The commit IDs baked into the released `.hex` +images don't exist in this repository at all. + +## What the board does + +| | | +|---|---| +| MCU | ATmega328PB, TQFP-32, **3.3 V / 8 MHz on the internal RC oscillator** | +| Network | W5500 10/100 Ethernet with hardware TCP/IP, on SPI | +| Serial | SP3232, RS-232 level, 300–921600 bps. TTL pads also broken out | +| Switch outputs | 2× EL357N optocouplers → host power and reset headers | +| Power output | 4× AO4407A P-FETs, back-to-back, switched 5–28 V | +| Input | 5–30 V, MP1584 buck to 3.3 V | +| Temperature | DS18B20 on 1-Wire — **also the device's identity** | +| Board | 52.0 × 36.0 mm, 2 layers | + +The on-board DS18B20's 64-bit ROM code becomes the serial number, the MAC +address and the default hostname, which is what makes each unit unique. + +## Fork status + +OSU Open Source Lab's maintained fork of +[`lshw/prc`](https://github.com/lshw/prc) by Liu Shiwei +(刘世伟, [bjlx.org.cn](https://bjlx.org.cn/)), who designed the board. **All +credit for the design is his.** OSL runs several of these and forked to document +the hardware in English and track discrepancies. + +What differs from upstream: all Chinese text translated (README, prototype +comments, `link.txt`, the BOM part-number column); English documentation added; +a BOM-versus-layout consistency check in CI. + +## ⚠ Two things to know before ordering boards + +1. **`control2.*` is the final layout here, but it was never exported for + assembly.** There is no `control2_bom.csv` or `control2_xy.csv`, and the + Gerber zips predate it. Anything sent to a fab must be re-exported from + rev 3. +2. **R5 disagrees between the files.** It is `27k` in both BOMs and in the + rendered schematic, but `72k` in all three layouts. R5 sets the MP1584 + under-voltage lockout, so this is the difference between the board starting + at ~7.0 V and at ~3.6 V — i.e. whether it works at the 5 V this README used + to advertise. **Measure a real board before any respin.** + +`tools/check_bom.py` checks for exactly this class of drift and runs in CI. + +## Working with the design files + +Everything needed is packaged in Debian; you do **not** need to build the +author's `pcb` forks: + +```bash +lepton-schematic control2.sch # schematic (lepton-eda) +pcb-rnd control2.pcb # layout (pcb-rnd) +gerbv 20191223/*.gbr # fabrication output +python3 tools/check_bom.py # BOM vs layout consistency +``` + +Both files open cleanly; `pcb-rnd` emits one benign warning about Q1's rotation +reference pin. + +The `.pcb` file carries an embedded `NetList()` block, which is the fastest way +to answer connectivity questions without opening a GUI: + +```bash +sed -n '/^NetList/,$p' control2.pcb +``` + +## Revisions + +| Files | Revision | Notes | +|---|---|---| +| `control.*` | rev 1 | on-board DB9, ATmega328 TQFN32 | +| `control1.*` | rev 2 | ATmega328PB TQFP32, adds L1 | +| `control2.*` | **rev 3, final here** | DB9 removed, R17 added | +| — | **V1.1, sold** | adds a PWM pad, W5500 SPI breakout, TTL serial pads. **No design files published** | + +If you have V1.1 boards, the files here do not fully describe them. See +[doc/node-954-procv1.1-hardware.md](doc/node-954-procv1.1-hardware.md). + +## Documentation + +| | | +|---|---| +| [AGENTS.md](AGENTS.md) | Full hardware reference — pin map, connectors, power tree, identity | +| [CONTRIBUTING.md](CONTRIBUTING.md) | Sign-off requirement, EDA file conventions, upstream sync | +| [CHANGELOG.md](CHANGELOG.md) | What changed | +| [doc/](doc/) | Vendor manuals, translated, with images mirrored locally | +| [osuosl/proc](https://github.com/osuosl/proc) | The firmware that runs on this board | + +## License + +LGPL-3.0, inherited from upstream. See [LICENSE](LICENSE). diff --git a/control/control.ino b/control/control.ino index f225ffc..381651d 100644 --- a/control/control.ino +++ b/control/control.ino @@ -10,13 +10,13 @@ #include #include -//eeprom 内存分配 +//eeprom memory layout enum { MAC0, //0 MAC1, //1 - MAC2, //2,序列号存放地址 - MAC3, //3,版本 + MAC2, //2, address where the serial number is stored + MAC3, //3, version MAC4, //4 MAC5, //5 IP0, @@ -33,7 +33,7 @@ enum COMSET_L }; -//设置 +//settings struct setting { int mac[6]; char ip[4]; @@ -53,7 +53,7 @@ EthernetServer server(23); void setup() { pinMode(_24V_OUT, OUTPUT); - digitalWrite(_24V_OUT, HIGH); //默认24V开启输出 + digitalWrite(_24V_OUT, HIGH); //24V output enabled by default pinMode(PC_RESET, OUTPUT); digitalWrite(PC_RESET, LOW); pinMode(PC_POWER, OUTPUT); @@ -74,7 +74,7 @@ void setup() { setup_watchdog(WDTO_30MS); if (debug) displaybz(); - OSCCAL = 147; //校准rc震荡器 + OSCCAL = 147; //calibrate the rc oscillator } boolean alreadyConnected = false; EthernetClient client; @@ -91,14 +91,14 @@ void loop() { client = server.available(); if (!client) return; alreadyConnected = true; - blank_time = millis() + 100; //10毫秒内收到的乱码,忽略 + blank_time = millis() + 100; //ignore the garbage received within the first 10 milliseconds if (debug) Serial.println(F("\r\n#new client in")); } - while (client.available() > 0) { //tcp有数据进来 + while (client.available() > 0) { //data arriving from tcp ch = client.read(); - if (blank_time > millis()) continue; //开始10ms收到的内容会被忽略 + if (blank_time > millis()) continue; //anything received in the first 10ms is ignored if (debug) { Serial.write(' '); Serial.write('['); @@ -114,14 +114,14 @@ void loop() { } } -//看门狗中断做定时任务 30ms 1次 +//the watchdog interrupt runs the periodic tasks, once every 30ms uint16_t volatile sec = 0, ms = 0; -uint16_t volatile dogcount = 0; //超时重启,主程序循环清零,不清零的话100秒重启系统 -int16_t volatile pc_reset_on = 0; //按下pc_reset键的ms时长 -int16_t volatile pc_power_on = 0; //按下pc_power键的ms时长 +uint16_t volatile dogcount = 0; //watchdog counter, cleared by the main loop. If it is never cleared the system reboots after 100 seconds +int16_t volatile pc_reset_on = 0; //how many ms the pc_reset key stays pressed +int16_t volatile pc_power_on = 0; //how many ms the pc_power key stays pressed ISR(WDT_vect) { dogcount++; //30ms - if (dogcount > 100000 / 30) asm volatile (" jmp 0"); //100秒看门狗超时重启 + if (dogcount > 100000 / 30) asm volatile (" jmp 0"); //100 second watchdog timeout: reboot ms += 30; if (ms > 1000) { ms -= 1000; @@ -130,28 +130,28 @@ ISR(WDT_vect) { if (sec % 10 == 0) Serial.println(sec); } - //处理reset键,其它程序只要修改 pc_reset_on=300,就可以按下300ms + //handle the reset key: other code only has to set pc_reset_on=300 to press it for 300ms if (pc_reset_on > 0) pc_reset_on -= 30; //30ms - if (pc_reset_on > 0) { //reset开关按下 + if (pc_reset_on > 0) { //reset switch pressed if (digitalRead(PC_RESET) != HIGH) digitalWrite(PC_RESET, HIGH); - } else { //reset开关松开 + } else { //reset switch released if (digitalRead(PC_RESET) != LOW) digitalWrite(PC_RESET, LOW); } - //处理reset键,其它程序只要修改 pc_power_on=300,就可以按下300ms + //handle the power key: other code only has to set pc_power_on=300 to press it for 300ms if (pc_power_on > 0) pc_power_on -= 30; //30ms - if (pc_power_on > 0) { //power开关按下 + if (pc_power_on > 0) { //power switch pressed if (digitalRead(PC_POWER) != HIGH) digitalWrite(PC_POWER, HIGH); - } else { //power开关松开 + } else { //power switch released if (digitalRead(PC_POWER) != LOW) digitalWrite(PC_POWER, LOW); } } -//设置看门狗定时中断时间ii=WDTO_15MS .... WDTO_8S +//set the watchdog interrupt interval; ii=WDTO_15MS .... WDTO_8S void setup_watchdog(int ii) { byte bb; if (ii > 9 ) ii = 9; @@ -166,7 +166,7 @@ void setup_watchdog(int ii) { WDTCSR |= _BV(WDIE); } -//校准rc振荡器 +//calibrate the rc oscillator inline void displaybz() { uint8_t osc; delay(10); diff --git a/control1_bom.csv b/control1_bom.csv index 535de8a..9b50ba3 100644 --- a/control1_bom.csv +++ b/control1_bom.csv @@ -1,4 +1,4 @@ -Quantity, Footprint, Comment, Description,编号 +Quantity, Footprint, Comment, Description,JLCPCB Part No. 2,"0402","22pF",C11 C12,"C1555" 1,"DO-214AA","10uH",L1,"C139506" 1,"0402","68k",R6,"C36871" diff --git a/control_bom.csv b/control_bom.csv index adc3052..19130c5 100644 --- a/control_bom.csv +++ b/control_bom.csv @@ -1,4 +1,4 @@ -Quantity, Footprint, Comment, Description,编号 +Quantity, Footprint, Comment, Description,JLCPCB Part No. 2,"0402","22pF",C11 C12,"C1555" 1,"0402","68k",R6,"C36871" 7,"0402","100nF",C8 C9 C4 C5 C6 C7 C10,"C1525" diff --git a/doc/img/9pin_com.png b/doc/img/9pin_com.png new file mode 100644 index 0000000..b9eff7d Binary files /dev/null and b/doc/img/9pin_com.png differ diff --git a/doc/img/mb_switch.jpeg b/doc/img/mb_switch.jpeg new file mode 100644 index 0000000..c830cc7 Binary files /dev/null and b/doc/img/mb_switch.jpeg differ diff --git a/doc/img/power.jpeg b/doc/img/power.jpeg new file mode 100644 index 0000000..b857a2f Binary files /dev/null and b/doc/img/power.jpeg differ diff --git a/doc/img/proc_com_0.jpeg b/doc/img/proc_com_0.jpeg new file mode 100644 index 0000000..576be4e Binary files /dev/null and b/doc/img/proc_com_0.jpeg differ diff --git a/doc/img/proc_ok_0.jpeg b/doc/img/proc_ok_0.jpeg new file mode 100644 index 0000000..41ca6e2 Binary files /dev/null and b/doc/img/proc_ok_0.jpeg differ diff --git a/doc/img/proc_pcb.jpeg b/doc/img/proc_pcb.jpeg new file mode 100644 index 0000000..1c41aa1 Binary files /dev/null and b/doc/img/proc_pcb.jpeg differ diff --git a/doc/img/proc_v1.1.png b/doc/img/proc_v1.1.png new file mode 100644 index 0000000..cb86f47 Binary files /dev/null and b/doc/img/proc_v1.1.png differ diff --git a/doc/node-914-hardware-manual.md b/doc/node-914-hardware-manual.md new file mode 100644 index 0000000..54cc7e5 --- /dev/null +++ b/doc/node-914-hardware-manual.md @@ -0,0 +1,154 @@ +# PROC-V1 Remote Controller Hardware User Manual + +> **English translation of** https://bjlx.org.cn/node/914 +> Original title: **PROC-V1 远程控制器硬件用户手册** +> Author: 刘世伟 (Liu Shiwei) · Published Saturday, 2020-04-25 09:56 +> Site: 北京龙芯&debian用户俱乐部 (Beijing Loongson & Debian User Club) +> +> Translated 2026-07-25. Images are local copies of the originals from +> `bjlx.org.cn/system/files/images/`. Editorial notes added by the translator +> are marked **[Note]** and are not part of the original. + +**Companion page:** [Software user manual](https://github.com/osuosl/proc/blob/main/doc/node-926-software-manual.md) +(original: https://bjlx.org.cn/node/926) + +--- + +PROC (PC remote operation controller) can control a PC's reset button and power +button over the network, for remote power on/off and remote restart. It can also +enter the serial port and interact with the BIOS, the bootloader and the Linux +console, to complete OS installation, network configuration, fault recovery, +remote maintenance and so on. + +**PROC-V1** is the RJ45-interface PC remote operation controller. **PROC-V2** is +the WiFi-interface PC remote controller. The installation method for V1 follows. + +## Installation + +### Pin descriptions + +*(The photo is of an early revision; the newer PROC V1.1 no longer distinguishes +switch polarity.)* + +![PROC PCB with annotated connections](img/proc_pcb.jpeg) + +Annotations in that image, translated: + +| Chinese | English | +|---|---| +| 5-30V电源输入 | 5–30 V power input | +| 大电流输入直接焊在这里 | Solder the high-current input directly here | +| 大电流输出焊点 | High-current output solder pad | +| 大电流负极焊点在背面 | The high-current negative pad is on the back of the board | +| 去主板的电源开关,分正负 | To the motherboard power switch — polarity matters | +| 去主板的复位开关 分 正 负 | To the motherboard reset switch — polarity matters | +| 插原来的按键开关杜邦线 | Plug in the original button-switch Dupont lead | +| 串口 | Serial port | + +![PROC V1.1 board](img/proc_v1.1.png) + +**[Note]** The V1.1 board silkscreen reads, from the serial pad group: +`RTS · TX_232 · RX_232 · GND · RX_TTL · TX_TTL`, and on the opposite edge +`PWM · 3.3V · GND · 5-28V`, a W5500 SPI breakout (`MOSI · CLK · CS · MISO · +INT · RESET`), an `Update` header, and `POWER SWITCH` / `RESET SWITCH` headers. +See [../AGENTS.md](../AGENTS.md) §6 for the full connector reference. + +### Power + +Take power from the power supply's **purple wire (standby 5 V)** and a **black +wire (ground)**. The purple wire can supply 5 V while the computer is switched +off. + +![Quick-splice taps on the PSU purple wire](img/power.jpeg) + +### Front-panel switches + +The motherboard's on-board switch header generally looks like this. PROC provides +two sets of switch leads: an ordinary 2-pin Dupont lead, and a 2×5 shell — you +can pull the hard-disk-LED and power-LED wires out of their Dupont shells, fit +them into the 2×5 shell, and plug the whole assembly onto the motherboard. + +![Motherboard JFP1 front-panel header](img/mb_switch.jpeg) + +That diagram's labels, translated (this is the common MSI-style **JFP1** header): + +| Chinese | English | Pins | +|---|---|---| +| 电源开关键 | Power switch button | 6, 8 | +| 电源指示灯 | Power LED | 2, 4 | +| 重启键 | Reset button | 5, 7 | +| 硬盘指示灯 | Hard-disk activity LED | 1, 3 | +| 9. Reserved | Reserved | 9 | +| 10. No Pin | Keyed — no pin | 10 | + +![Motherboard 2x5 COM header](img/9pin_com.png) + +That is the internal COM header pinout — bottom row from pin 1: `DCD`, `TXD`, +`GND`, `RTS`, `RI`; top row: `RXD`, `DTR`, `DSR`, `CTS`. See also +[node 953](node-953-motherboard-com-header.md). + +At this point installation is complete. For a router, or a mini PC with a +separate 12 V input supply, you have to solder your own leads. + +### Serial port + +The serial port is **RS-232 level — do not connect it to a TTL-level serial +port.** Two sets of leads are provided: an external 9-pin serial cable, and an +internal 2×5 Dupont header for the motherboard. Any other cable form you make +yourself. + +![DB9 serial port on the PC rear panel](img/proc_com_0.jpeg) + +### Finished + +Once everything is connected it looks like this: + +![PROC installed in a chassis](img/proc_ok_0.jpeg) + +Annotations in that image, translated: + +> 原来的按键接到PRC盒子上 — *The original buttons connect to the PRC box.* +> +> 复位线和开机线连接方式,如果出现按键不可控,把极性反转一下。 — *How to wire +> the reset and power lines. If the buttons turn out to be uncontrollable, +> reverse the polarity.* + +--- + +## Attachments on the original page + +| File | Size | URL | +|---|---|---| +| `update.sh` | 222 bytes | https://bjlx.org.cn/system/files/update_0.sh | +| `ver 20210201-4b34ae9 firmware` | 84.18 KB | https://bjlx.org.cn/system/files/prc.ino__0.hex | + +**[Note]** `update.sh` is a two-attempt `avrdude` wrapper: + +```bash +#!/bin/bash +cd `dirname $0` +avrdude -v -patmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:prc.ino.hex:i +if [ $? != 0 ] ; then +avrdude -v -patmega328pb -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:prc.ino.hex:i +fi +``` + +**[Note]** The linked `.hex` reports itself as `PROC-V1-20210201-4b34ae9`. That +commit does not exist in the public [`prc`](https://github.com/osuosl/prc) repository; the firmware +source is in [`proc`](https://github.com/osuosl/proc/blob/main/AGENTS.md). Current upstream `proc` HEAD builds +as `PROC-V1-20241103-a8f458f`, so this attachment is roughly four years behind. + +## Linked image pages + +- [node 953 — 主板上的串口杜邦座 / Motherboard serial Dupont header](node-953-motherboard-com-header.md) +- [node 954 — procv1.1 hardware](node-954-procv1.1-hardware.md) + +## Original page navigation (not part of the article) + +The site chrome links to: Debian (http://debian.org), flygoat's blog +(https://blog.flygoat.com/), USTC Linux User Association +(https://lug.ustc.edu.cn/wiki/), Loongson official site (http://www.loongson.cn/), +Loongson User Club (http://www.loongsonclub.cn), and the author's blog at +https://bjlx.org.cn/blog/1. + +© 2007-2024 北京龙芯用户俱乐部 (Beijing Loongson User Club) diff --git a/doc/node-953-motherboard-com-header.md b/doc/node-953-motherboard-com-header.md new file mode 100644 index 0000000..feb0f0d --- /dev/null +++ b/doc/node-953-motherboard-com-header.md @@ -0,0 +1,43 @@ +# Serial Dupont Header on the Motherboard + +> **English translation of** https://bjlx.org.cn/node/953 +> Original title: **主板上的串口杜邦座** +> Author: 刘世伟 (Liu Shiwei) · Published Saturday, 2021-09-18 22:05 +> Site: 北京龙芯&debian用户俱乐部 (Beijing Loongson & Debian User Club) +> +> Translated 2026-07-25. + +This is an **image-only page** on the original site — a photo gallery node with +a title and no body text. It is linked from the +[hardware manual](node-914-hardware-manual.md) as the reference for the +motherboard's internal COM header. + +--- + +![Motherboard internal COM header pinout](img/9pin_com.png) + +The diagram is the standard internal **COM** header found on most ATX +motherboards: a 2×5 header with pin 10 keyed (absent). + +| Row | Pins, left to right | +|---|---| +| Bottom (pin 1 first) | `DCD` (1), `TXD` (3), `GND` (5), `RTS` (7), `RI` (9) | +| Top | `RXD` (2), `DTR` (4), `DSR` (6), `CTS` (8), *(pin 10 keyed/absent)* | + +## How this maps to PROC + +PROC-V1 ships two serial lead options — an external 9-pin D-sub cable and an +internal 2×5 Dupont shell for this header. The mapping from +[../link.txt](../link.txt): + +| Signal | DB9 male | DB9 female | PROC 6-pin header | +|---|---|---|---| +| GND (地) | 5 | 5 | 3 | +| TX | 2 | 3 | 4 | +| RX | 3 | 2 | 5 | +| DTR | 8 | 7 | 6 | + +Remember that PROC's `HTX` / `HRX` / `RTS` lines are **RS-232 level** — this +motherboard header is also RS-232 level, so they connect directly. Do **not** +connect them to PROC's `TX_TTL` / `RX_TTL` pads. See +[../AGENTS.md](../AGENTS.md) §6.4. diff --git a/doc/node-954-procv1.1-hardware.md b/doc/node-954-procv1.1-hardware.md new file mode 100644 index 0000000..b503c5f --- /dev/null +++ b/doc/node-954-procv1.1-hardware.md @@ -0,0 +1,54 @@ +# procv1.1 hardware + +> **English translation of** https://bjlx.org.cn/node/954 +> Original title: **procv1.1 hardware** (already in English upstream) +> Author: 刘世伟 (Liu Shiwei) · Published Saturday, 2021-09-18 22:16 +> Site: 北京龙芯&debian用户俱乐部 (Beijing Loongson & Debian User Club) +> +> Translated 2026-07-25. + +This is an **image-only page** on the original site — a photo gallery node with +a title and no body text. It is linked from the +[hardware manual](node-914-hardware-manual.md) as the reference board render for +revision **V1.1**. + +--- + +![PROC V1.1 board render with serial pads annotated](img/proc_v1.1.png) + +The red annotations on the render label the four serial pads on the lower left: +**GND · RX · TX · RTS**. The caption reads `PROC V1.1 hardware`. + +## What the silkscreen says + +Reading the render, left board (top copper) and right board (bottom copper): + +| Area | Silkscreen | +|---|---| +| Top left | `W5500`, `LED1`, and the `R` / `P` switch headers | +| Centre | `github.com/lshw/prc` | +| Right edge, top | `PWM`, `3.3V`, `GND`, `5-28V`, `+` | +| Right edge, middle | W5500 SPI breakout: `GND`, `GND`, `MOSI`, `CLK`, `CS`, `MISO`, `INT`, `RESET`, `3.3V`, `3.3V` | +| Right edge, lower | `Update`, `POWER SWITCH`, `RESET SWITCH` | +| Bottom edge | `RTS`, `TX`, `RX`, `GND`, `TX-TTL`, `RX-TTL`, `GND` | +| Bottom left | `VOUT`, `VIN`, `5-30V` | + +## ⚠ V1.1 design files are not published + +**This render is the only public artefact of revision V1.1.** The schematic and +PCB in this repository ([../control2.sch](../control2.sch), +[../control2.pcb](../control2.pcb)) are **revision 1.0** from December 2019. + +Differences visible in the render that are absent from the published rev-1.0 +files: + +- a **PWM pad** — the firmware's `#define PWM 5` puts it on Arduino D5 + (PD5, package pin 9), which is unconnected in the rev-1.0 schematic +- a **W5500 SPI breakout header** +- separate **TTL-level serial pads** alongside the RS-232 ones +- per the [hardware manual](node-914-hardware-manual.md), V1.1 **no longer + distinguishes switch polarity**, implying a different opto-isolator output + arrangement than the EL357N single-transistor output on rev 1.0 + +If OSU OSL has V1.1 boards, the files in this repository do not fully describe +them. See [../AGENTS.md](../AGENTS.md) §8 issue H5. diff --git a/link.txt b/link.txt index b54f47a..8b98abf 100644 --- a/link.txt +++ b/link.txt @@ -1,5 +1,5 @@ -9针公座 9针母座 6P串口 说明 -5 5 3 地 +DB9 male DB9 female 6P serial description +5 5 3 GND 2 3 4 TX 3 2 5 RX 8 7 6 DTR diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..290035e --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "simple", + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "include-component-in-tag": false, + "separate-pull-requests": false, + "packages": { + ".": { + "package-name": "prc", + "changelog-path": "CHANGELOG.md" + } + }, + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance and flash savings" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration" + }, + { + "type": "refactor", + "section": "Refactoring" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "chore", + "section": "Miscellaneous", + "hidden": true + } + ], + "bootstrap-sha": "5bf428bb5fc9490e3648775e764a814052b6644a" +} diff --git a/tools/__pycache__/check_bom.cpython-313.pyc b/tools/__pycache__/check_bom.cpython-313.pyc new file mode 100644 index 0000000..6d59ec7 Binary files /dev/null and b/tools/__pycache__/check_bom.cpython-313.pyc differ diff --git a/tools/check_bom.py b/tools/check_bom.py new file mode 100755 index 0000000..48bb8d6 --- /dev/null +++ b/tools/check_bom.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +"""Cross-check the JLCPCB assembly files against the PCB layout they came from. + +The BOM and pick-and-place CSVs are exported from the layout, but they are +exported *by hand* and then edited by hand, so they drift. This has already +happened at least once: R5 is 27k in both BOMs and in the rendered schematic, +but 72k in the layout, which moves the MP1584 input under-voltage lockout +between roughly 7.0 V and 3.6 V -- i.e. whether the board starts at the 5 V the +README advertises. + +Nothing here needs an EDA tool; both formats are plain text. + +Usage: tools/check_bom.py # check every known pcb/bom/xy set + tools/check_bom.py --quiet # only print problems +Exit status is non-zero if any mismatch is found. +""" + +import argparse +import csv +import pathlib +import re +import sys + +REPO = pathlib.Path(__file__).resolve().parent.parent + +# (layout, bom, xy). control2.pcb is deliberately absent -- see check_unexported(). +SETS = [ + ("control.pcb", "control_bom.csv", "control_xy.csv"), + ("control1.pcb", "control1_bom.csv", "control1_xy.csv"), +] + +# Element["" "" "" "" ...] +ELEMENT_RE = re.compile(r'^Element\["([^"]*)" "([^"]*)" "([^"]*)" "([^"]*)"') + + +def norm(value): + """Values are hand-typed, so compare them case- and space-insensitively. + '100uF/6.3v' and '100UF/6.3V' are the same part; '27k' and '72k' are not.""" + return value.strip().lower().replace(" ", "") + + +def read_pcb(path): + """refdes -> (footprint, value) for every placed element.""" + out = {} + for line in path.read_text(encoding="utf-8", errors="replace").splitlines(): + m = ELEMENT_RE.match(line) + if not m: + continue + _flags, footprint, refdes, value = m.groups() + if refdes: + out[refdes] = (footprint, value) + return out + + +def read_bom(path): + """refdes -> (footprint, value). + + Column header says 'Description' but the column actually holds a + space-separated list of reference designators. Upstream naming, left as-is + so the file still matches what JLCPCB expects. + """ + out = {} + with path.open(encoding="utf-8", errors="replace") as fh: + for row in csv.reader(fh): + if len(row) < 4 or row[0].strip().lower() == "quantity": + continue + footprint, value, refdes_field = row[1].strip(), row[2].strip(), row[3].strip() + for refdes in refdes_field.split(): + out[refdes] = (footprint, value) + return out + + +def read_xy(path): + """refdes -> (footprint, value). Here 'Description' really is the refdes.""" + out = {} + with path.open(encoding="utf-8", errors="replace") as fh: + for row in csv.reader(fh): + if len(row) < 3 or row[0].strip().lower() == "description": + continue + out[row[0].strip()] = (row[1].strip(), row[2].strip()) + return out + + +def compare(problems, layout_name, pcb, other_name, other): + """Compare one exported file against the layout it was exported from.""" + only_pcb = sorted(set(pcb) - set(other)) + only_other = sorted(set(other) - set(pcb)) + + # Parts legitimately absent from an assembly export: through-hole connectors, + # the crystal (never populated -- the firmware runs the internal RC), and + # anything hand-soldered. Report as info, not failure. + if only_pcb: + problems.append( + ("info", f"{layout_name}: {len(only_pcb)} part(s) not in {other_name}: " + f"{', '.join(only_pcb)}") + ) + if only_other: + problems.append( + ("error", f"{other_name} lists part(s) absent from {layout_name}: " + f"{', '.join(only_other)}") + ) + + for refdes in sorted(set(pcb) & set(other)): + pcb_fp, pcb_val = pcb[refdes] + oth_fp, oth_val = other[refdes] + if norm(pcb_val) != norm(oth_val): + problems.append( + ("error", f"{refdes}: value differs -- {layout_name} says " + f"'{pcb_val}', {other_name} says '{oth_val}'") + ) + if norm(pcb_fp) != norm(oth_fp): + problems.append( + ("error", f"{refdes}: footprint differs -- {layout_name} says " + f"'{pcb_fp}', {other_name} says '{oth_fp}'") + ) + + +def check_unexported(problems): + """The newest layout must have assembly files, or a fab order will silently + be placed from a stale export.""" + layouts = sorted(REPO.glob("control*.pcb")) + exported = {s[0] for s in SETS} + for layout in layouts: + if layout.name not in exported: + problems.append( + ("warn", f"{layout.name} has no BOM/XY export. Anything sent to a " + f"fab must be re-exported from the newest layout.") + ) + + +def load_known(path): + """Substrings of findings that are already tracked as issues. They are still + printed, but do not fail the run -- so CI blocks on *new* drift without + being permanently red over something already filed.""" + if not path.exists(): + return [] + return [ + line.strip() + for line in path.read_text(encoding="utf-8").splitlines() + if line.strip() and not line.lstrip().startswith("#") + ] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--quiet", action="store_true", help="only print problems") + ap.add_argument( + "--allow-known", + action="store_true", + help="downgrade findings listed in tools/known_bom_issues.txt", + ) + args = ap.parse_args() + known = load_known(REPO / "tools" / "known_bom_issues.txt") if args.allow_known else [] + + problems = [] + for pcb_name, bom_name, xy_name in SETS: + pcb_path, bom_path, xy_path = (REPO / n for n in (pcb_name, bom_name, xy_name)) + if not pcb_path.exists(): + problems.append(("error", f"{pcb_name} is missing")) + continue + pcb = read_pcb(pcb_path) + if not args.quiet: + print(f"{pcb_name}: {len(pcb)} placed elements") + for name, path, reader in ( + (bom_name, bom_path, read_bom), + (xy_name, xy_path, read_xy), + ): + if not path.exists(): + problems.append(("error", f"{name} is missing")) + continue + other = reader(path) + if not args.quiet: + print(f" vs {name}: {len(other)} entries") + compare(problems, pcb_name, pcb, name, other) + + check_unexported(problems) + + graded = [] + for level, msg in problems: + if level == "error" and any(k in msg for k in known): + level = "known" + graded.append((level, msg)) + + errors = [p for p in graded if p[0] == "error"] + for level, msg in graded: + if args.quiet and level == "info": + continue + prefix = {"error": "ERROR", "warn": "WARN ", "info": "info ", "known": "known"}[level] + print(f"{prefix} {msg}") + + print() + print(f"{len(errors)} new error(s), " + f"{len([p for p in graded if p[0] == 'known'])} known, " + f"{len([p for p in graded if p[0] == 'warn'])} warning(s)") + return 1 if errors else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/known_bom_issues.txt b/tools/known_bom_issues.txt new file mode 100644 index 0000000..c590d7d --- /dev/null +++ b/tools/known_bom_issues.txt @@ -0,0 +1,9 @@ +# Findings that tools/check_bom.py should report but not fail on, because they +# are already tracked. Each entry is matched as a substring of the finding text. +# Delete the entry when the underlying issue is closed, so CI starts enforcing it. +# +# R5, the MP1584 enable divider, is 27k in every exported assembly file and in +# the rendered schematic, but 72k in all three layouts. That moves the input +# under-voltage lockout between roughly 7.0 V and 3.6 V. Which one is on the +# physical boards has to be measured before it can be resolved. +R5: value differs diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..77d6f4c --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.0.0