Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1400431337 | ||
|
|
119b5ddf13 | ||
|
|
231b43b264 | ||
|
|
e53ebddc21 | ||
|
|
f23eb6bebb | ||
|
|
cd51cffb1d | ||
|
|
01fc5db9a3 | ||
|
|
bdca888ecd | ||
|
|
e8431999e5 | ||
|
|
7ca4d2c8dc | ||
|
|
32dd21bbd3 | ||
|
|
92f9025109 | ||
|
|
b65aa82d78 | ||
|
|
851eb39344 | ||
|
|
970e98f4c5 | ||
|
|
4d009bc8e8 | ||
|
|
eb51128ec7 | ||
|
|
b86fd37eaa | ||
|
|
b92a773cad | ||
|
|
068e7467af | ||
|
|
da4f5058a7 | ||
|
|
fee4f17bff | ||
|
|
e19271fc44 | ||
|
|
aff6ac0923 | ||
|
|
7e11be0d97 | ||
|
|
23862bc648 | ||
|
|
6c62791d23 | ||
|
|
413690a748 | ||
|
|
3910888052 | ||
|
|
a0cb3c1850 | ||
|
|
73bb4c8af2 | ||
|
|
0443ba428b | ||
|
|
62abd08aa2 | ||
|
|
70426ff24a | ||
|
|
2d62cc493d | ||
|
|
bbce2d6727 | ||
|
|
36de7b7241 | ||
|
|
ea320d813d | ||
|
|
ca2abcc4e1 | ||
|
|
4d7159092c | ||
|
|
98763e3bff | ||
|
|
80a30b705e | ||
|
|
4c3e1fde81 | ||
|
|
5cd14e6227 | ||
|
|
5105018d90 | ||
|
|
5bc7cf43db | ||
|
|
c776d10129 | ||
|
|
7b4d0d55d2 | ||
|
|
e95e450813 | ||
|
|
fe1d4119d0 | ||
|
|
c5f62bff95 | ||
|
|
7535c0d9b7 | ||
|
|
a57319557d | ||
|
|
1b29fb687f | ||
|
|
2e62f9eea7 | ||
|
|
5c6a82d50f | ||
|
|
1d158d21d1 | ||
|
|
26c420d26a | ||
|
|
eb394af95f | ||
|
|
4a4caeffd7 | ||
|
|
391360f517 | ||
|
|
ed8e4b1a56 | ||
|
|
78f28488c1 | ||
|
|
e1c79ec4cd | ||
|
|
a7db0ca8b6 | ||
|
|
70f59b64f5 | ||
|
|
f0cbaba7b1 | ||
|
|
2d5424fedc | ||
|
|
23c8b2a8b3 | ||
|
|
c9f6362da5 | ||
|
|
742aef5461 | ||
|
|
a77d219baf | ||
|
|
f94204e56f | ||
|
|
8d6adedb56 | ||
|
|
c3f9acea10 | ||
|
|
c46261e052 | ||
|
|
834403b97b | ||
|
|
48087d3520 | ||
|
|
1d359afba5 | ||
|
|
ec14dbf323 | ||
|
|
deedb92c5d | ||
|
|
a18c334139 | ||
|
|
337b171ac4 | ||
|
|
53eb3f5486 | ||
|
|
241edfdbda | ||
|
|
714c9eb343 | ||
|
|
f2c89fd75b | ||
|
|
ca2f1d101d | ||
|
|
9cc859ad30 | ||
|
|
0181276ec6 | ||
|
|
905e588071 | ||
|
|
bb16302a80 | ||
|
|
50fda40fd9 | ||
|
|
9c65039bab | ||
|
|
7e0bc93b55 | ||
|
|
e1e1292ab0 | ||
|
|
975caaff02 | ||
|
|
cffe4793b1 | ||
|
|
9ed1e89c8b | ||
|
|
ba2f759df3 | ||
|
|
884a1ac016 | ||
|
|
51ed063dcb | ||
|
|
0da6318777 | ||
|
|
d13a5d125d | ||
|
|
889c94404c | ||
|
|
0f98734ae2 | ||
|
|
2d0abbbca0 | ||
|
|
fdcdfa9b45 | ||
|
|
c043c671d7 | ||
|
|
11a24783e4 | ||
|
|
e864c32980 | ||
|
|
bb329daab0 | ||
|
|
89c8903454 | ||
|
|
63a3bc50d6 | ||
|
|
a94be7d524 | ||
|
|
50be5308d9 | ||
|
|
9731a33fa9 | ||
|
|
c3dddd9c90 | ||
|
|
6e5617c82f | ||
|
|
6638748e3c | ||
|
|
98965b73f6 | ||
|
|
ef0d9d872e | ||
|
|
7d7585fa6d | ||
|
|
13801241ca | ||
|
|
94ca35f65e | ||
|
|
69714c8a75 | ||
|
|
2bc6939f86 | ||
|
|
aea537f8e7 | ||
|
|
7346977f91 | ||
|
|
7b0a07efaa | ||
|
|
3c00ab0ae9 | ||
|
|
7673ef8322 | ||
|
|
c9e8403c6e | ||
|
|
3deee14f94 | ||
|
|
6d539bfb1b | ||
|
|
7a44d8181f | ||
|
|
d698e180e4 | ||
|
|
566e26ace2 | ||
|
|
674dc23a27 | ||
|
|
620edafd62 | ||
|
|
413d10bbcc | ||
|
|
0faceab1d0 | ||
|
|
7e12f0a62c | ||
|
|
491a919105 | ||
|
|
2588965eee | ||
|
|
827d3b389c | ||
|
|
ef224ec8f4 | ||
|
|
0a3d7d360a | ||
|
|
9561f239b4 | ||
|
|
b06ff76a21 | ||
|
|
b28ead65dc | ||
|
|
a079c803d9 | ||
|
|
cc3ae654a0 | ||
|
|
2a9f9b2508 | ||
|
|
57d6337940 | ||
|
|
3b58eb36e5 | ||
|
|
34c0ef77d0 | ||
|
|
e6182dbe0d | ||
|
|
1d5e4cd722 | ||
|
|
a02116a24b | ||
|
|
98369c37fe | ||
|
|
d104b3129d | ||
|
|
138acfadb1 | ||
|
|
08f8498b39 | ||
|
|
dd521cc79d | ||
|
|
723d16b4cb | ||
|
|
2c2349dcef | ||
|
|
6d1380fb36 | ||
|
|
eacf13690c | ||
|
|
a1998c70d7 | ||
|
|
4ed74f05db | ||
|
|
0de18ff457 | ||
|
|
3195a14870 | ||
|
|
3ffb311e95 | ||
|
|
f0c672418c | ||
|
|
41ed689ae0 | ||
|
|
11eadc5a49 | ||
|
|
24d2cd7bab | ||
|
|
28c09737b2 | ||
|
|
3e1d3f40d2 | ||
|
|
389dc2af76 | ||
|
|
4963fbe50a | ||
|
|
44b5ab0e64 | ||
|
|
088321deaf | ||
|
|
3af1b049ee | ||
|
|
6a5d3cdf2c | ||
|
|
d21ea52c46 | ||
|
|
c6cc3ee595 | ||
|
|
424a963301 | ||
|
|
1344e02fb7 | ||
|
|
2ae297bc20 | ||
|
|
ce77cc273d | ||
|
|
6376a10288 | ||
|
|
a202842107 | ||
|
|
6fad2836ae | ||
|
|
2415015a87 | ||
|
|
d9fc20addf | ||
|
|
c15b2d48da | ||
|
|
f17ca1c9fc | ||
|
|
be5dee04e3 | ||
|
|
196d22d7c3 | ||
|
|
496ac8b757 | ||
|
|
bf670aed0b | ||
|
|
6af5580433 | ||
|
|
6194356f66 | ||
|
|
bd56c1a8c5 | ||
|
|
d562fd661e | ||
|
|
0b6b613c03 | ||
|
|
f325bdbd11 | ||
|
|
680a40dab5 | ||
|
|
97b15f4022 | ||
|
|
c263a8ab64 | ||
|
|
d5ccd38dd3 | ||
|
|
adecc26ae2 | ||
|
|
44ae7a8d3b | ||
|
|
c3fc541339 | ||
|
|
6fdb19f18c | ||
|
|
70f8964918 | ||
|
|
aba58e7f99 | ||
|
|
2404e7a9b6 | ||
|
|
6a31b4a279 | ||
|
|
6cd1f683bb | ||
|
|
7e90f6a126 | ||
|
|
9bd301447b | ||
|
|
9745dfe6ae | ||
|
|
d4345c1bf8 | ||
|
|
fcaacd4429 | ||
|
|
0f63244ca1 | ||
|
|
913e9780b8 | ||
|
|
0d748fa808 | ||
|
|
bd974e0aaf | ||
|
|
56686185ce | ||
|
|
ed069b67fd | ||
|
|
b1026490a8 | ||
|
|
28ea2184c2 | ||
|
|
d5f84cc2fb | ||
|
|
682ac462c4 | ||
|
|
ecc8356f4d | ||
|
|
3a8d1d323f | ||
|
|
e125ebd097 | ||
|
|
4050555667 | ||
|
|
e890e429a5 | ||
|
|
813a62ca7d | ||
|
|
b096efd63a | ||
|
|
8a7c847ad9 | ||
|
|
b94d2aeabc | ||
|
|
6bae5c5c90 | ||
|
|
c2980e42d8 | ||
|
|
875933b9f9 | ||
|
|
0e85137e7a | ||
|
|
c02f660c08 | ||
|
|
706dea63a2 | ||
|
|
d0374541c5 |
No files matched your search
@@ -3,6 +3,7 @@
|
|||||||
.gitattributes
|
.gitattributes
|
||||||
.github/
|
.github/
|
||||||
output/
|
output/
|
||||||
|
toolchain/
|
||||||
installer/output/
|
installer/output/
|
||||||
*.bin
|
*.bin
|
||||||
html_data.c
|
html_data.c
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ on:
|
|||||||
branches: ['**']
|
branches: ['**']
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -13,18 +18,41 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
path: branch
|
||||||
|
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
path: main
|
||||||
|
ref: main
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
apt update
|
apt update
|
||||||
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y
|
apt install make gcc g++ bison flex libboost-dev patch bzip2 curl ca-certificates xxd python-is-python3 libjson-c-dev zlib1g-dev -y
|
||||||
|
- name: Cache the patched SDCC
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: branch/toolchain
|
||||||
|
key: sdcc-${{ hashFiles('branch/sdcc/*') }}
|
||||||
- name: Run the host-side unit tests
|
- name: Run the host-side unit tests
|
||||||
run: make -C test
|
run: cd branch && make -C test
|
||||||
- name: Check that every machine definition can be compiled
|
- name: Check that every machine definition can be compiled
|
||||||
run: make machine_check
|
run: cd branch && make machine_check
|
||||||
- name: Make project (4x2/RTL8372)
|
- name: Make project (4x2/RTL8372)
|
||||||
run: make CI=1 MACHINE="KP_9000_6XHML_X2"
|
run: cd branch && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/branch.map
|
||||||
- name: Make project (8x1/RTL8373)
|
- name: Make project (8x1/RTL8373)
|
||||||
run: make CI=1 MACHINE="KP_9000_9XHML_X_V3_1"
|
run: cd branch && make CI=1 MACHINE="KP_9000_9XHML_X_V3_1"
|
||||||
- name: Make project with the health instrumentation
|
- name: Make project with the health instrumentation
|
||||||
run: make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1
|
run: cd branch && make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1
|
||||||
|
- name: Make main
|
||||||
|
run: |
|
||||||
|
ln -s ../branch/toolchain main/toolchain
|
||||||
|
PATH="$(echo "$PWD"/branch/toolchain/sdcc-*/bin):$PATH"
|
||||||
|
cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map
|
||||||
|
- name: Calculate bank growth
|
||||||
|
run: |
|
||||||
|
sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV"
|
||||||
|
sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort -u >> "$GITHUB_ENV"
|
||||||
|
du -sb main/output/KP_9000_6XHML_X2/html_min | awk '{print "MAIN_WEB="$1}' >> "$GITHUB_ENV"
|
||||||
|
du -sb branch/output/KP_9000_6XHML_X2/html_min | awk '{print "BRANCH_WEB="$1}' >>"$GITHUB_ENV"
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
.gitignore
|
.gitignore
|
||||||
.idea/
|
.idea/
|
||||||
output/
|
output/
|
||||||
|
output-main/
|
||||||
|
toolchain/
|
||||||
html_data.c
|
html_data.c
|
||||||
html_data.h
|
html_data.h
|
||||||
version.h
|
version.h
|
||||||
tools/httpd_sim
|
tools/httpd_sim
|
||||||
tools/injector
|
tools/injector
|
||||||
tools/fileadder
|
tools/fileadder
|
||||||
|
build/
|
||||||
|
|
||||||
# host-test stand-ins for the two generated headers
|
# host-test stand-ins for the two generated headers
|
||||||
!test/stub/html_data.h
|
!test/stub/html_data.h
|
||||||
!test/stub/version.h
|
!test/stub/version.h
|
||||||
|
.vscode
|
||||||
@@ -4,6 +4,17 @@
|
|||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
|
- Devices
|
||||||
|
- Support the hongyavision HYWS-SGT0204S (PCB marking `2G5F4_10G2_V1.01`), an
|
||||||
|
RTL8372 based 4x2.5G + 2xSFP+ unmanaged switch with a 512 KB Bright Moon
|
||||||
|
`T25S40` flash. It is a sibling of the KP-9000-6XH-X2 (2M-PCB43-V1.1) with
|
||||||
|
the two SFP+ cages wired the other way round (physical 5 is on SDS1,
|
||||||
|
physical 6 on SDS0), no reset button fitted, wrong silkscreen labels on the
|
||||||
|
serial header, `LED_GLB_IO_EN` bit 6 has to be set for the port LEDs to
|
||||||
|
work, and the fitted T25S40 cannot be read in DIO mode on this board, so the
|
||||||
|
target selects single-IO flash reads (`flash_sio`). New machine target
|
||||||
|
`MACHINE_2G5F4_10G2_V1_01`, see `doc/devices/2G5F4_10G2_V1.01.md`.
|
||||||
|
|
||||||
- Web UI
|
- Web UI
|
||||||
- Compress the embedded assets (minify + gzip) and switch to a single-page layout. #315
|
- Compress the embedded assets (minify + gzip) and switch to a single-page layout. #315
|
||||||
- Replace the multi-page UI with a themed single-page app: light, dark and Selenized themes following the browser by default,
|
- Replace the multi-page UI with a themed single-page app: light, dark and Selenized themes following the browser by default,
|
||||||
@@ -14,12 +25,34 @@
|
|||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
- Time
|
||||||
|
- `rtl8372_init()` sets SDS 0 to SGMII as the stock firmware does. The masks were 0, so on RTL8372
|
||||||
|
boards without 10G ports both SerDes stayed off, and with SDS 0 off `RTL837X_REG_SEC_COUNTER`
|
||||||
|
does not hold a written value: NTP never retried after a failed first attempt at boot and
|
||||||
|
froze the clock after a sync.
|
||||||
|
|
||||||
|
- Web UI
|
||||||
|
- Firefox no longer fills a saved login into the new admin password fields. It also put the
|
||||||
|
user name into the NTP poll interval, which marked the Time card as edited, so it kept its
|
||||||
|
defaults (NTP off, no server, UTC-12:00) instead of the switch's settings.
|
||||||
|
- Accept firmware uploads regardless of the file part's MIME type, including
|
||||||
|
`application/macbinary` sent by Chrome on macOS for `.bin` files.
|
||||||
|
|
||||||
|
- Health
|
||||||
|
- `HEALTH=1` builds no longer write past the phase timing arrays at the LLDP checkpoint, which
|
||||||
|
corrupted the `link` slow counter and the DHCP client state. #658
|
||||||
- Config
|
- Config
|
||||||
- A startup configuration line longer than the command buffer no longer stops the replay:
|
- A startup configuration line longer than the command buffer no longer stops the replay:
|
||||||
the offending line is skipped and the following lines are still applied.
|
the offending line is skipped and the following lines are still applied.
|
||||||
- The web UI and the configuration upload now refuse a line the replay cannot take,
|
- The web UI and the configuration upload now refuse a line the replay cannot take,
|
||||||
instead of writing it to flash.
|
instead of writing it to flash.
|
||||||
|
|
||||||
|
- Startup
|
||||||
|
- Initialised and zero-initialised globals above xdata 0x4000 now get their values at boot.
|
||||||
|
Hardware reset leaves SFR 0x97 at 1, which maps xdata 0x4000-0xbfff to the flash image,
|
||||||
|
and it was cleared only in `main()`, after the C startup code had copied and cleared them.
|
||||||
|
This showed as a random web session timeout and LLDP blocked on some ports without config.
|
||||||
|
|
||||||
## Breaking changes
|
## Breaking changes
|
||||||
|
|
||||||
- Config
|
- Config
|
||||||
|
|||||||
@@ -3,7 +3,14 @@ FROM debian:13-slim
|
|||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
make \
|
make \
|
||||||
gcc \
|
gcc \
|
||||||
sdcc \
|
g++ \
|
||||||
|
bison \
|
||||||
|
flex \
|
||||||
|
libboost-dev \
|
||||||
|
patch \
|
||||||
|
bzip2 \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
xxd \
|
xxd \
|
||||||
python3 \
|
python3 \
|
||||||
libjson-c-dev \
|
libjson-c-dev \
|
||||||
|
|||||||
@@ -4,8 +4,25 @@ DEFAULT_CONFIG_LOCATION = 454656
|
|||||||
CONFIG_LOCATION = 458752
|
CONFIG_LOCATION = 458752
|
||||||
HTML_LOCATION = 262144
|
HTML_LOCATION = 262144
|
||||||
|
|
||||||
|
# Startup configuration embedded in the image. Override it to build a specific
|
||||||
|
# machine with its own configuration: make MACHINE=<name> CONFIG=<file>
|
||||||
|
CONFIG ?= config.txt
|
||||||
|
|
||||||
|
SDCC_TOOLCHAIN = sdcc-$(shell cat sdcc/* | cksum | cut -d' ' -f1)
|
||||||
|
SDCC_PREFIX = toolchain/$(SDCC_TOOLCHAIN)
|
||||||
ifeq ($(origin CC),default)
|
ifeq ($(origin CC),default)
|
||||||
CC = sdcc
|
SDCC = $(SDCC_PREFIX)/bin/sdcc
|
||||||
|
CC = $(SDCC)
|
||||||
|
ASM = $(SDCC_PREFIX)/bin/sdas8051
|
||||||
|
SDCC_REV := $(shell git log -1 --format=%h -- sdcc 2>/dev/null)
|
||||||
|
ifneq ($(SDCC_REV),)
|
||||||
|
ifneq ($(shell git status --porcelain --untracked-files=no -- sdcc 2>/dev/null),)
|
||||||
|
SDCC_REV := $(SDCC_REV)-dirty
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
SDCC_BANNER = $(if $(SDCC_REV),sdcc/ at $(SDCC_REV),$(SDCC_TOOLCHAIN)) ($(words $(wildcard sdcc/*.patch)) patches)
|
||||||
|
else
|
||||||
|
SDCC_BANNER = system
|
||||||
endif
|
endif
|
||||||
CC_FLAGS = -mmcs51 -I. -Imachine -Ihttpd -Iuip
|
CC_FLAGS = -mmcs51 -I. -Imachine -Ihttpd -Iuip
|
||||||
ASM ?= sdas8051
|
ASM ?= sdas8051
|
||||||
@@ -15,11 +32,10 @@ SUBDIRS := tools
|
|||||||
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
|
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
|
||||||
|
|
||||||
# $MACHINE selects machine/$(MACHINE).c as the board definition and is passed
|
# $MACHINE selects machine/$(MACHINE).c as the board definition and is passed
|
||||||
# on as -DMACHINE_$(MACHINE), which the rest of the firmware tests with
|
# on as -DMACHINE_NAME, which machine.h uses to include machine/$(MACHINE).h.
|
||||||
# #if defined(MACHINE_...), and as -DMACHINE_NAME, which machine.h uses to
|
# Board selection itself needs no MACHINE_* symbol for #if chains, so the
|
||||||
# include machine/$(MACHINE).h. Both take the same value, so they cannot drift.
|
# definition is all the compiler has to know.
|
||||||
ifneq ($(MACHINE),)
|
ifneq ($(MACHINE),)
|
||||||
CC_FLAGS += -DMACHINE_$(MACHINE)
|
|
||||||
CC_FLAGS += -DMACHINE_NAME=$(MACHINE)
|
CC_FLAGS += -DMACHINE_NAME=$(MACHINE)
|
||||||
endif
|
endif
|
||||||
# Health instrumentation and the "health" console command: HEALTH=1 gmake ...
|
# Health instrumentation and the "health" console command: HEALTH=1 gmake ...
|
||||||
@@ -34,7 +50,17 @@ endif
|
|||||||
# The board definition being built: one file per MACHINE_* symbol in machine.h.
|
# The board definition being built: one file per MACHINE_* symbol in machine.h.
|
||||||
MACHINE_SRC = machine/$(MACHINE).c
|
MACHINE_SRC = machine/$(MACHINE).c
|
||||||
|
|
||||||
BUILDDIR = output/$(MACHINE)
|
MACHINE_INIT_DEFAULT := machine/default_machine_init.c
|
||||||
|
MACHINE_INIT_SRC := $(wildcard machine/$(MACHINE)_init.c)
|
||||||
|
ifeq ($(MACHINE_INIT_SRC),)
|
||||||
|
MACHINE_INIT_SRC := $(MACHINE_INIT_DEFAULT)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef BUILDDIR
|
||||||
|
BUILDDIR = output/$(MACHINE)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CONFIG_STAMP := $(BUILDDIR)/.config
|
||||||
VERSION_HEADER := version.h
|
VERSION_HEADER := version.h
|
||||||
|
|
||||||
GIT_VERSION := $(shell git rev-parse --short HEAD)
|
GIT_VERSION := $(shell git rev-parse --short HEAD)
|
||||||
@@ -57,11 +83,15 @@ BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/d
|
|||||||
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
|
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# $(MACHINE_SRC) is listed here so an unknown $MACHINE fails before anything else
|
# $(MACHINE_SRC) and $(CONFIG) are listed here so an unknown $MACHINE or a
|
||||||
# is built, including the tools/ subdirectory.
|
# missing config file fails before anything else is built, including the tools/
|
||||||
all: create_build_dir $(VERSION_HEADER) $(MACHINE_SRC) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
|
# subdirectory.
|
||||||
|
all: create_build_dir $(VERSION_HEADER) $(MACHINE_SRC) $(CONFIG) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
|
||||||
|
|
||||||
create_build_dir:
|
bank_size:
|
||||||
|
tools/bank_occupancy.sh "$(MACHINE)"
|
||||||
|
|
||||||
|
create_build_dir: $(SDCC)
|
||||||
mkdir -p "$(BUILDDIR)"
|
mkdir -p "$(BUILDDIR)"
|
||||||
mkdir -p "$(BUILDDIR)/uip"
|
mkdir -p "$(BUILDDIR)/uip"
|
||||||
mkdir -p "$(BUILDDIR)/httpd"
|
mkdir -p "$(BUILDDIR)/httpd"
|
||||||
@@ -77,11 +107,17 @@ $(MACHINE_SRC):
|
|||||||
@echo " Example: make MACHINE=KP_9000_6XHML_X2" >&2
|
@echo " Example: make MACHINE=KP_9000_6XHML_X2" >&2
|
||||||
@false
|
@false
|
||||||
|
|
||||||
|
# Fail with a clear message when CONFIG names a file that does not exist.
|
||||||
|
$(CONFIG):
|
||||||
|
@echo "ERROR: CONFIG='$(CONFIG)' does not exist." >&2
|
||||||
|
@echo " Point CONFIG at a configuration file, or omit it to use config.txt." >&2
|
||||||
|
@false
|
||||||
|
|
||||||
# Keep the per-machine definition in first position to fail immediately on an
|
# Keep the per-machine definition in first position to fail immediately on an
|
||||||
# invalid $MACHINE value
|
# invalid $MACHINE value
|
||||||
SRCS = \
|
SRCS = \
|
||||||
$(MACHINE_SRC) \
|
$(MACHINE_SRC) \
|
||||||
machine_init.c \
|
$(MACHINE_INIT_SRC) \
|
||||||
cmd_editor.c \
|
cmd_editor.c \
|
||||||
cmd_parser.c \
|
cmd_parser.c \
|
||||||
dhcp.c \
|
dhcp.c \
|
||||||
@@ -91,6 +127,7 @@ SRCS = \
|
|||||||
sfp.c \
|
sfp.c \
|
||||||
dns.c \
|
dns.c \
|
||||||
dns_cli.c \
|
dns_cli.c \
|
||||||
|
sessions.c \
|
||||||
ntp.c \
|
ntp.c \
|
||||||
ntp_cli.c \
|
ntp_cli.c \
|
||||||
syslog.c \
|
syslog.c \
|
||||||
@@ -99,9 +136,11 @@ SRCS = \
|
|||||||
# RTL837x
|
# RTL837x
|
||||||
SRCS += \
|
SRCS += \
|
||||||
rtl837x_bandwidth.c \
|
rtl837x_bandwidth.c \
|
||||||
|
rtl837x_cabletest.c \
|
||||||
rtl837x_flash.c \
|
rtl837x_flash.c \
|
||||||
rtl837x_igmp.c \
|
rtl837x_igmp.c \
|
||||||
rtl837x_init.c \
|
rtl837x_init.c \
|
||||||
|
rtl837x_nic.c \
|
||||||
rtl837x_leds.c \
|
rtl837x_leds.c \
|
||||||
rtl837x_leds_dump.c \
|
rtl837x_leds_dump.c \
|
||||||
rtl837x_phy.c \
|
rtl837x_phy.c \
|
||||||
@@ -111,10 +150,12 @@ SRCS += \
|
|||||||
rtl837x_lldp.c \
|
rtl837x_lldp.c \
|
||||||
rtl837x_storm.c \
|
rtl837x_storm.c \
|
||||||
rtl837x_lacp.c \
|
rtl837x_lacp.c \
|
||||||
rtl837x_trap.c
|
rtl837x_trap.c \
|
||||||
|
rtl837x_stp_cli.c
|
||||||
SRCS += \
|
SRCS += \
|
||||||
httpd/httpd.c \
|
httpd/httpd.c \
|
||||||
httpd/page_impl.c
|
httpd/page_impl.c \
|
||||||
|
httpd/page_stp.c
|
||||||
SRCS += \
|
SRCS += \
|
||||||
uip/timer.c \
|
uip/timer.c \
|
||||||
uip/uip.c \
|
uip/uip.c \
|
||||||
@@ -131,20 +172,31 @@ HTML := $(shell find html -name '*.js' -or -name '*.html' -or -name '*.svg' -or
|
|||||||
# Minified copy of the web UI sources, used as the fileadder input.
|
# Minified copy of the web UI sources, used as the fileadder input.
|
||||||
# The raw html/ sources stay untouched for development; the minified
|
# The raw html/ sources stay untouched for development; the minified
|
||||||
# copy is a build artifact under output/.
|
# copy is a build artifact under output/.
|
||||||
HTML_MIN := output/html_min
|
HTML_MIN := $(BUILDDIR)/html_min
|
||||||
|
HTML_MIN_LIST := $(BUILDDIR)/html_min.list
|
||||||
|
HTML_MIN_STAMP := $(BUILDDIR)/html_min.stamp
|
||||||
.PHONY: html_min
|
.PHONY: html_min
|
||||||
html_min: $(HTML)
|
html_min: $(HTML_MIN_STAMP)
|
||||||
|
|
||||||
|
$(HTML_MIN_LIST): FORCE
|
||||||
|
@mkdir -p $(BUILDDIR)
|
||||||
|
@echo $(sort $(HTML)) > $@.tmp
|
||||||
|
@cmp -s $@.tmp $@ && rm -f $@.tmp || mv $@.tmp $@
|
||||||
|
|
||||||
|
$(HTML_MIN_STAMP): $(HTML) $(HTML_MIN_LIST) tools/minify.py $(if $(wildcard $(HTML_MIN)),,FORCE)
|
||||||
rm -rf $(HTML_MIN)
|
rm -rf $(HTML_MIN)
|
||||||
mkdir -p $(HTML_MIN)
|
mkdir -p $(HTML_MIN)
|
||||||
@for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done
|
@for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done
|
||||||
|
@touch $@
|
||||||
|
|
||||||
html_data.c html_data.h &: $(HTML) | tools html_min
|
html_data.c html_data.h &: $(HTML_MIN_STAMP) | tools
|
||||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
|
tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
|
||||||
|
|
||||||
$(VERSION_HEADER): FORCE
|
$(VERSION_HEADER): FORCE
|
||||||
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
|
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
|
||||||
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
|
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
|
||||||
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
|
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
|
||||||
|
"#define SDCC_TOOLCHAIN \"$(SDCC_BANNER)\"" \
|
||||||
"#endif" > $(VERSION_HEADER).tmp
|
"#endif" > $(VERSION_HEADER).tmp
|
||||||
@cmp -s $(VERSION_HEADER).tmp $(VERSION_HEADER) \
|
@cmp -s $(VERSION_HEADER).tmp $(VERSION_HEADER) \
|
||||||
&& rm -f $(VERSION_HEADER).tmp \
|
&& rm -f $(VERSION_HEADER).tmp \
|
||||||
@@ -153,15 +205,21 @@ $(VERSION_HEADER): FORCE
|
|||||||
httpd: html_data.h
|
httpd: html_data.h
|
||||||
|
|
||||||
$(SUBDIRS):
|
$(SUBDIRS):
|
||||||
$(MAKE) -C $@
|
$(MAKE) -C $@ BUILDDIR=$(BUILDDIR)
|
||||||
|
|
||||||
clean: $(SUBDIRSCLEAN)
|
clean: $(SUBDIRSCLEAN)
|
||||||
-rm -f html_data.c html_data.h $(VERSION_HEADER)
|
-rm -f html_data.c html_data.h $(VERSION_HEADER) $(HTML_MIN_LIST) $(HTML_MIN_STAMP)
|
||||||
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
|
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
|
||||||
|
|
||||||
distclean: $(SUBDIRSCLEAN)
|
distclean: $(SUBDIRSCLEAN)
|
||||||
-rm -f html_data.c html_data.h $(VERSION_HEADER)
|
-rm -f html_data.c html_data.h $(VERSION_HEADER) $(HTML_MIN_LIST) $(HTML_MIN_STAMP)
|
||||||
-rm -rf $(BUILDDIR)
|
-rm -rf $(BUILDDIR)
|
||||||
|
-rm -rf toolchain
|
||||||
|
|
||||||
|
ifneq ($(SDCC),)
|
||||||
|
$(SDCC):
|
||||||
|
sh sdcc/build.sh $(abspath $(SDCC_PREFIX))
|
||||||
|
endif
|
||||||
|
|
||||||
$(SUBDIRSCLEAN):
|
$(SUBDIRSCLEAN):
|
||||||
$(MAKE) -C $(@:clean=) clean
|
$(MAKE) -C $(@:clean=) clean
|
||||||
@@ -176,6 +234,12 @@ FORCE:
|
|||||||
$(CCFLAGS_STAMP): FORCE | create_build_dir
|
$(CCFLAGS_STAMP): FORCE | create_build_dir
|
||||||
@echo '$(CC_FLAGS)' | cmp -s - $@ 2>/dev/null || echo '$(CC_FLAGS)' > $@
|
@echo '$(CC_FLAGS)' | cmp -s - $@ 2>/dev/null || echo '$(CC_FLAGS)' > $@
|
||||||
|
|
||||||
|
# The same for $(CONFIG): its path is stamped so switching to a config file
|
||||||
|
# older than the image still rebuilds it, while $(CONFIG) itself as a normal
|
||||||
|
# prerequisite covers edits to the selected file.
|
||||||
|
$(CONFIG_STAMP): FORCE | create_build_dir
|
||||||
|
@echo '$(CONFIG)' | cmp -s - $@ 2>/dev/null || echo '$(CONFIG)' > $@
|
||||||
|
|
||||||
$(BUILDDIR)/%.rel: %.c $(CCFLAGS_STAMP) | create_build_dir html_data.h
|
$(BUILDDIR)/%.rel: %.c $(CCFLAGS_STAMP) | create_build_dir html_data.h
|
||||||
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||||
|
|
||||||
@@ -184,38 +248,44 @@ $(BUILDDIR)/%.rel: %.asm $(CCFLAGS_STAMP) | create_build_dir
|
|||||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||||
|
|
||||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
||||||
$(CC) $(CC_FLAGS) --xram-size 49151 -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
$(CC) $(CC_FLAGS) --xram-size 49151 -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-bBANK4=0x44000 -Wl-r -o $@ $^
|
||||||
|
|
||||||
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||||
objcopy --input-target=ihex -O binary $< $@
|
objcopy --input-target=ihex -O binary $< $@
|
||||||
|
|
||||||
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img | tools
|
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img $(CONFIG) $(CONFIG_STAMP) | tools
|
||||||
if [ -e $@ ]; then rm $@; fi
|
if [ -e $@ ]; then rm $@; fi
|
||||||
tools/output/imagebuilder -i $^ $@
|
tools/$(BUILDDIR)/imagebuilder -i $(BUILDDIR)/rtlplayground.img $@
|
||||||
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
tools/$(BUILDDIR)/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d "$(CONFIG)" $@
|
||||||
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
tools/$(BUILDDIR)/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d "$(CONFIG)" $@
|
||||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@
|
tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@
|
||||||
tools/output/crc_calculator -u $@
|
tools/$(BUILDDIR)/crc_calculator -u $@
|
||||||
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
|
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin $(BUILDDIR)/../rtlplayground.bin
|
||||||
|
|
||||||
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir
|
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir
|
||||||
|
|
||||||
# Every machine/ definition is compiled, so a machine added to machine/ is
|
# Every machine/ definition is compiled, so a machine added to machine/ is
|
||||||
# covered without registering it anywhere. The machine-specific defines are
|
# covered without registering it anywhere. A board only counts once both its
|
||||||
# filtered out of $(CC_FLAGS) and supplied per iteration instead, so this also
|
# <machine>.c and its <machine>.h are present: the header is what the rest of
|
||||||
# works as "make machine_check MACHINE=...".
|
# the build includes, so a .c without one is an incomplete board. The _init.c
|
||||||
MACHINE_DEFS := $(sort $(patsubst machine/%.c,%,$(wildcard machine/*.c)))
|
# files are excluded here: they are the boot hooks, compiled separately below
|
||||||
|
# (the board's own if it exists, otherwise default_machine_init.c). The
|
||||||
|
# machine-specific defines are filtered out of $(CC_FLAGS) and supplied per
|
||||||
|
# iteration instead, so this also works as "make machine_check MACHINE=...".
|
||||||
|
MACHINE_DEFS := $(sort $(filter $(patsubst machine/%.h,%,$(wildcard machine/*.h)),$(patsubst machine/%.c,%,$(filter-out machine/%_init.c,$(wildcard machine/*.c)))))
|
||||||
MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS))
|
MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS))
|
||||||
|
|
||||||
.PHONY:
|
.PHONY: machine_check
|
||||||
machine_check:
|
machine_check: $(SDCC)
|
||||||
@mkdir -p $(BUILDDIR)/tmp
|
@mkdir -p $(BUILDDIR)/tmp
|
||||||
@set -eo pipefail; \
|
@set -eo pipefail; \
|
||||||
for MACHINE in $(MACHINE_DEFS); \
|
for MACHINE in $(MACHINE_DEFS); \
|
||||||
do \
|
do \
|
||||||
echo "Checking $${MACHINE}"; \
|
echo "Checking $${MACHINE}"; \
|
||||||
$(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_$${MACHINE} -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine/$${MACHINE}.c; \
|
$(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine/$${MACHINE}.c; \
|
||||||
$(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_$${MACHINE} -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine_init.c; \
|
INIT=machine/$${MACHINE}_init.c; \
|
||||||
|
if [ ! -e $$INIT ] && [ ! -L $$INIT ]; then INIT=$(MACHINE_INIT_DEFAULT); fi; \
|
||||||
|
$(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c $$INIT; \
|
||||||
done
|
done
|
||||||
@rm -rf $(BUILDDIR)/tmp
|
@rm -rf $(BUILDDIR)/tmp
|
||||||
|
|
||||||
|
|||||||
@@ -56,12 +56,19 @@ device simulator is provided, which runs entirely under Linux as a local webserv
|
|||||||
|
|
||||||
## (0) Compiling Requirements
|
## (0) Compiling Requirements
|
||||||
|
|
||||||
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
|
Install the following particular build requisites (Debian 12/13):
|
||||||
still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile:
|
|
||||||
```
|
```
|
||||||
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev
|
sudo apt install make gcc g++ bison flex libboost-dev patch bzip2 curl xxd python-is-python3 libjson-c-dev zlib1g-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The first `make` downloads SDCC 4.6.0, applies the fixes in `sdcc/` and builds it into
|
||||||
|
`toolchain/`, which takes a few minutes. Later builds reuse it. The released SDCC 4.5.0
|
||||||
|
and 4.6.0 miscompile parts of this code, see [SDCC bug #4153](https://sourceforge.net/p/sdcc/bugs/4153/)
|
||||||
|
and [#4154](https://sourceforge.net/p/sdcc/bugs/4154/); both fixes are in SDCC trunk since
|
||||||
|
r17039. The third patch is for [#4070](https://sourceforge.net/p/sdcc/bugs/4070/), where the
|
||||||
|
assembler drops the top byte of a `__sfr32` address list; it is proposed upstream and lets
|
||||||
|
`SFR_DATA_U32` be used again. To use an SDCC you installed yourself instead, run `make CC=sdcc ...`.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>If using Docker (click to expand)</summary>
|
<summary>If using Docker (click to expand)</summary>
|
||||||
|
|
||||||
@@ -90,6 +97,14 @@ docker run --rm -v $(pwd):/workspace rtlplayground-dev make MACHINE=DEFAULT_8C_1
|
|||||||
|
|
||||||
The resulting `.bin` file appears in `output/` on your host.
|
The resulting `.bin` file appears in `output/` on your host.
|
||||||
|
|
||||||
|
Build the OEM web upgrade bin (after building the firmware bin)
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --rm -v $(pwd):/workspace rtlplayground-dev make -C installer
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting `rtlplayground_oem_upgrade.bin` file appears in `installer/output/` on your host.
|
||||||
|
|
||||||
Build host tools only:
|
Build host tools only:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -103,24 +118,36 @@ docker run --rm -p 8080:8080 -v $(pwd):/workspace rtlplayground-dev \
|
|||||||
tools/output/httpd_sim /workspace/html
|
tools/output/httpd_sim /workspace/html
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit `machine.h` or `config.txt` on your host, then re-run `make` — the
|
Edit `config.txt` on your host, then re-run `make` — the
|
||||||
source directory is mounted into the container, so changes take effect
|
source directory is mounted into the container, so changes take effect
|
||||||
immediately. To build for a different machine, pass `MACHINE=...`.
|
immediately. To build for a different machine, pass `MACHINE=<name>`, which
|
||||||
|
selects `machine/<name>.c` (see [Adding a new device](doc/adding-a-device.md)).
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device
|
## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device
|
||||||
|
|
||||||
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
|
Pass the machine that matches your device, for example:
|
||||||
|
```
|
||||||
|
make MACHINE=DEFAULT_8C_1SFP
|
||||||
|
```
|
||||||
|
The name selects the board definition `machine/<name>.c`; `make` without a
|
||||||
|
`MACHINE` value stops with an error listing what is expected. If your board is
|
||||||
|
not in the list yet, see [Adding a new device](doc/adding-a-device.md).
|
||||||
|
|
||||||
|
To embed a machine-specific startup configuration, pass `CONFIG`:
|
||||||
|
```
|
||||||
|
make MACHINE=DEFAULT_8C_1SFP CONFIG=configs/DEFAULT_8C_1SFP.txt
|
||||||
|
```
|
||||||
|
`CONFIG` defaults to `config.txt`; the selected file is embedded in the image
|
||||||
|
and changing it triggers a rebuild.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> You can write configuration parameters in config.txt (see below) in order your switch to get
|
> You can write configuration parameters in config.txt (see below) in order your switch to get
|
||||||
> straight at the first boot, a correct IP configuration.
|
> straight at the first boot, a correct IP configuration.
|
||||||
|
|
||||||
Now, building the firmware image should work:
|
Now, building the firmware image should work.
|
||||||
```
|
|
||||||
make
|
|
||||||
```
|
|
||||||
Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy.
|
Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy.
|
||||||
|
|
||||||
image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin`
|
image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin`
|
||||||
@@ -158,9 +185,9 @@ example of compilation console output
|
|||||||
RTLPlayground/installer$ make
|
RTLPlayground/installer$ make
|
||||||
mkdir -p output
|
mkdir -p output
|
||||||
gcc updatebuilder.c -o output/updatebuilder
|
gcc updatebuilder.c -o output/updatebuilder
|
||||||
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
|
../toolchain/sdcc-3390765201/bin/sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
|
||||||
sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
|
../toolchain/sdcc-3390765201/bin/sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
|
||||||
sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
|
../toolchain/sdcc-3390765201/bin/sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
|
||||||
./output/updatebuilder -i output/rtlinstaller.ihx -o output/rtlplayground_oem_upgrade.bin ../output/rtlplayground.bin
|
./output/updatebuilder -i output/rtlinstaller.ihx -o output/rtlplayground_oem_upgrade.bin ../output/rtlplayground.bin
|
||||||
Input file size: 524288
|
Input file size: 524288
|
||||||
Bytes read: 524288
|
Bytes read: 524288
|
||||||
@@ -186,7 +213,7 @@ Go to "Firmware update" tab, select the correct file.
|
|||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
|
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
|
||||||
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin
|
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Check one more time that your device matches the machine type before flashing.
|
> Check one more time that your device matches the machine type before flashing.
|
||||||
@@ -353,12 +380,13 @@ Enjoy playing!
|
|||||||
## (11) Other documents
|
## (11) Other documents
|
||||||
|
|
||||||
The following documents give further documentation on specific features of the RTL837x SoCs:
|
The following documents give further documentation on specific features of the RTL837x SoCs:
|
||||||
|
- [Adding a new device](doc/adding-a-device.md)
|
||||||
- [RTL8372/3 Feature support](doc/hardware.md)
|
- [RTL8372/3 Feature support](doc/hardware.md)
|
||||||
- [CPU Port](doc/CpuPort.md)
|
- [CPU Port](doc/CpuPort.md)
|
||||||
- [L2 learning](doc/l2.md)
|
- [L2 learning](doc/l2.md)
|
||||||
- [IGMP (IP-MC streaming)](doc/igmp.md)
|
- [IGMP (IP-MC streaming)](doc/igmp.md)
|
||||||
- [SFP+ ports](doc/sfp.md)
|
- [SFP+ ports](doc/sfp.md)
|
||||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
- [Trunking aka. port aggregation](doc/link_aggregation.md)
|
||||||
- [LACP (802.3ad link aggregation)](doc/lacp.md)
|
- [LACP (802.3ad link aggregation)](doc/lacp.md)
|
||||||
- [VLAN](doc/vlan.md)
|
- [VLAN](doc/vlan.md)
|
||||||
- [Storm control](doc/storm_control.md)
|
- [Storm control](doc/storm_control.md)
|
||||||
|
|||||||
@@ -125,18 +125,6 @@ void early_boot_handle_button(void) __banked
|
|||||||
void sds_config(uint8_t sds, uint8_t mode) __banked
|
void sds_config(uint8_t sds, uint8_t mode) __banked
|
||||||
{
|
{
|
||||||
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
|
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
|
||||||
sds_config_mac(sds, mode);
|
|
||||||
|
|
||||||
if (mode == SDS_10GR || mode == SDS_QXGMII)
|
|
||||||
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
|
|
||||||
else
|
|
||||||
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
|
|
||||||
sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400
|
|
||||||
sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02
|
|
||||||
sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e
|
|
||||||
sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002
|
|
||||||
sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390
|
|
||||||
sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f
|
|
||||||
|
|
||||||
uint8_t page = 0;
|
uint8_t page = 0;
|
||||||
uint16_t v = 0;
|
uint16_t v = 0;
|
||||||
@@ -165,6 +153,21 @@ void sds_config(uint8_t sds, uint8_t mode) __banked
|
|||||||
print_string("Error in SDS Mode\n");
|
print_string("Error in SDS Mode\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sds_config_mac(sds, mode);
|
||||||
|
|
||||||
|
if (mode == SDS_10GR || mode == SDS_QXGMII)
|
||||||
|
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
|
||||||
|
else
|
||||||
|
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
|
||||||
|
|
||||||
|
sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400
|
||||||
|
sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02
|
||||||
|
sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e
|
||||||
|
sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002
|
||||||
|
sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390
|
||||||
|
sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f
|
||||||
|
|
||||||
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
|
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
|
||||||
|
|
||||||
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
|
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
|
||||||
@@ -257,7 +260,7 @@ void nic_setup(void) __banked
|
|||||||
|
|
||||||
// This sets the size of the RX buffer, the filling level is in 0x7874
|
// This sets the size of the RX buffer, the filling level is in 0x7874
|
||||||
// R7848-000004ff
|
// R7848-000004ff
|
||||||
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff);
|
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, RTL837X_NIC_RX_LAST_SLOT);
|
||||||
|
|
||||||
// R7844-000007fe
|
// R7844-000007fe
|
||||||
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
|
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
|
||||||
@@ -296,6 +299,7 @@ void nic_setup(void) __banked
|
|||||||
|
|
||||||
// Sequence number of TX packets
|
// Sequence number of TX packets
|
||||||
tx_seq = 0;
|
tx_seq = 0;
|
||||||
|
REG_SET(RTL837X_NIC_INT_MSK, NIC_INT_RXIE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,11 @@
|
|||||||
#include "rtl837x_lldp.h"
|
#include "rtl837x_lldp.h"
|
||||||
#include "rtl837x_storm.h"
|
#include "rtl837x_storm.h"
|
||||||
#include "rtl837x_trap.h"
|
#include "rtl837x_trap.h"
|
||||||
|
#include "rtl837x_cabletest.h"
|
||||||
#include "sfp.h"
|
#include "sfp.h"
|
||||||
#include "dhcp.h"
|
#include "dhcp.h"
|
||||||
#include "syslog.h"
|
#include "syslog.h"
|
||||||
|
#include "sessions.h"
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
#include "ntp.h"
|
#include "ntp.h"
|
||||||
#include "uip/uip.h"
|
#include "uip/uip.h"
|
||||||
@@ -166,10 +168,15 @@ uint8_t atoi_hex(uint8_t idx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (h_idx == 8) {
|
||||||
|
h_idx = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// swap hex nibbles
|
// swap hex nibbles
|
||||||
val = (val >> 4) | (val << 4);
|
val = (val >> 4) | (val << 4);
|
||||||
|
|
||||||
if (c - '0' < 10) {
|
if ((uint8_t)(c - '0') < 10) {
|
||||||
val |= c - '0';
|
val |= c - '0';
|
||||||
} else {
|
} else {
|
||||||
c |= 0x20;
|
c |= 0x20;
|
||||||
@@ -260,7 +267,7 @@ uint8_t cmd_parse_port(uint8_t idx) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
port = machine.phys_to_log_port[port];
|
port = machine.phys_to_log_port[port];
|
||||||
if (port < machine.min_port || port > machine.max_port)
|
if (!MACHINE_PORT_VALID(port))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
atoi_results_u8 = port;
|
atoi_results_u8 = port;
|
||||||
@@ -737,9 +744,9 @@ void parse_isolate(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_compare(2, "off")) {
|
if (cmd_compare(2, "off")) {
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++)
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++)
|
||||||
members |= ((uint16_t)1) << i;
|
members |= ((uint16_t)1) << i;
|
||||||
members |= 0x200; // CPU-port
|
members |= PMASK_CPU; // CPU-port
|
||||||
port_isolate(port_configured, members);
|
port_isolate(port_configured, members);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -791,7 +798,7 @@ void parse_ingress(void)
|
|||||||
if (!cmd_is_space_or_nul(idx))
|
if (!cmd_is_space_or_nul(idx))
|
||||||
goto err;
|
goto err;
|
||||||
// Setting mode for all ports at once
|
// Setting mode for all ports at once
|
||||||
for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) {
|
for (log_port = MACHINE_MIN_PORT; log_port <= MACHINE_MAX_PORT; log_port++) {
|
||||||
if (!port_ingress_filter(log_port, mode)) {
|
if (!port_ingress_filter(log_port, mode)) {
|
||||||
cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||||
return;
|
return;
|
||||||
@@ -843,7 +850,7 @@ void parse_mirror(void)
|
|||||||
print_string("NOT Enabled: ");
|
print_string("NOT Enabled: ");
|
||||||
}
|
}
|
||||||
print_string("Mirroring port: ");
|
print_string("Mirroring port: ");
|
||||||
print_phys_port(mirroring_port);
|
print_phys_port(mPort >> 1);
|
||||||
reg_read_m(RTL837x_MIRROR_CONF);
|
reg_read_m(RTL837x_MIRROR_CONF);
|
||||||
uint16_t m = sfr_data[0];
|
uint16_t m = sfr_data[0];
|
||||||
m = (m << 8) | sfr_data[1];
|
m = (m << 8) | sfr_data[1];
|
||||||
@@ -903,6 +910,7 @@ void parse_port(void)
|
|||||||
"\nport <port> [show|on|off]" \
|
"\nport <port> [show|on|off]" \
|
||||||
"\nport <port> [10m|100m|1g|2g5|duplex] [half|full]" \
|
"\nport <port> [10m|100m|1g|2g5|duplex] [half|full]" \
|
||||||
"\nport <port> lldp [block|permit]" \
|
"\nport <port> lldp [block|permit]" \
|
||||||
|
"\nport <port> cabletest [show]" \
|
||||||
"\nport <port> name [custom port name]\n");
|
"\nport <port> name [custom port name]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -945,6 +953,11 @@ void parse_port(void)
|
|||||||
}
|
}
|
||||||
} else if (machine.is_sfp[phy_settings.port]) {
|
} else if (machine.is_sfp[phy_settings.port]) {
|
||||||
print_string(" is SFP no PHY information available.\n");
|
print_string(" is SFP no PHY information available.\n");
|
||||||
|
} else if (cmd_compare(2, "cabletest")) {
|
||||||
|
if (cmd_words_len > 3 && cmd_compare(3, "show"))
|
||||||
|
cabletest_show();
|
||||||
|
else
|
||||||
|
cabletest_run();
|
||||||
} else if (cmd_compare(2, "10m")) {
|
} else if (cmd_compare(2, "10m")) {
|
||||||
print_string(" 10M\n");
|
print_string(" 10M\n");
|
||||||
phy_settings.speed = PHY_SPEED_10M;
|
phy_settings.speed = PHY_SPEED_10M;
|
||||||
@@ -1007,7 +1020,7 @@ void parse_mtu(void)
|
|||||||
uint8_t p;
|
uint8_t p;
|
||||||
|
|
||||||
if (cmd_compare(1, "show")) {
|
if (cmd_compare(1, "show")) {
|
||||||
for (p = machine.min_port; p <= machine.max_port; p++) {
|
for (p = MACHINE_MIN_PORT; p <= MACHINE_MAX_PORT; p++) {
|
||||||
reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8));
|
reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8));
|
||||||
uint16_t mtu = SFR_DATA_U16 & 0x3fff;
|
uint16_t mtu = SFR_DATA_U16 & 0x3fff;
|
||||||
print_string("Port "); print_phys_port(p);
|
print_string("Port "); print_phys_port(p);
|
||||||
@@ -1467,6 +1480,9 @@ void parse_passwd(void)
|
|||||||
passwd[j++] = c;
|
passwd[j++] = c;
|
||||||
} while (c != NUL && j < 20);
|
} while (c != NUL && j < 20);
|
||||||
passwd[j] = NUL;
|
passwd[j] = NUL;
|
||||||
|
/* Logins made with the old password end here. With one session the next
|
||||||
|
* login pushed a leftover one out; with several it would stay valid. */
|
||||||
|
session_init();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cmd_error("Missing password\n");
|
cmd_error("Missing password\n");
|
||||||
@@ -1824,6 +1840,8 @@ void print_gpio_status(void) {
|
|||||||
void print_sw_version(void) __banked {
|
void print_sw_version(void) __banked {
|
||||||
print_string("Software version: " VERSION_SW);
|
print_string("Software version: " VERSION_SW);
|
||||||
print_string("\nBuild date: " BUILD_DATE);
|
print_string("\nBuild date: " BUILD_DATE);
|
||||||
|
print_string("\nCompiler: SDCC " STR(__SDCC_VERSION_MAJOR) "." STR(__SDCC_VERSION_MINOR) "." STR(__SDCC_VERSION_PATCH) " #" STR(__SDCC_REVISION));
|
||||||
|
print_string("\nToolchain: " SDCC_TOOLCHAIN);
|
||||||
print_string("\nHardware: ");
|
print_string("\nHardware: ");
|
||||||
print_string(machine.machine_name);
|
print_string(machine.machine_name);
|
||||||
write_char('\n');
|
write_char('\n');
|
||||||
@@ -1999,10 +2017,10 @@ void cmd_parser(void) __banked
|
|||||||
cmd_error("lacp (show | off); a group starts LACP with: lag <1-4> lacp <port>...\n");
|
cmd_error("lacp (show | off); a group starts LACP with: lag <1-4> lacp <port>...\n");
|
||||||
} else if (cmd_compare(0, "pvid")) {
|
} else if (cmd_compare(0, "pvid")) {
|
||||||
if (cmd_words_len == 3 && cmd_parse_port_separator(cmd_words_b[1]) != 0
|
if (cmd_words_len == 3 && cmd_parse_port_separator(cmd_words_b[1]) != 0
|
||||||
&& atoi_short(cmd_words_b[2]) && atoi_results_short && atoi_results_short <= 4094)
|
&& atoi_short(cmd_words_b[2]) && atoi_results_short <= 4094)
|
||||||
port_pvid_set(atoi_results_u8, atoi_results_short);
|
port_pvid_set(atoi_results_u8, atoi_results_short);
|
||||||
else {
|
else {
|
||||||
cmd_error("pvid <port> <1-4094>\n");
|
cmd_error("pvid <port> <0-4094>\n");
|
||||||
}
|
}
|
||||||
} else if (cmd_compare(0, "vlan")) {
|
} else if (cmd_compare(0, "vlan")) {
|
||||||
parse_vlan();
|
parse_vlan();
|
||||||
@@ -2143,7 +2161,7 @@ void execute_config(void) __banked
|
|||||||
skipping = 1;
|
skipping = 1;
|
||||||
}
|
}
|
||||||
c = flash_buf[cfg_idx++];
|
c = flash_buf[cfg_idx++];
|
||||||
if (c == 0 || c == '\n') {
|
if (c == 0 || c == '\n' || c == '\r') {
|
||||||
if (skipping) {
|
if (skipping) {
|
||||||
skipping = 0;
|
skipping = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -2317,6 +2335,7 @@ void health_show(void) __banked
|
|||||||
ph_line("tx ", HEALTH_PH_TX);
|
ph_line("tx ", HEALTH_PH_TX);
|
||||||
ph_line("stp ", HEALTH_PH_STP);
|
ph_line("stp ", HEALTH_PH_STP);
|
||||||
ph_line("cmd ", HEALTH_PH_CMD);
|
ph_line("cmd ", HEALTH_PH_CMD);
|
||||||
|
ph_line("lldp", HEALTH_PH_LLDP);
|
||||||
|
|
||||||
/* Stack: current depth plus how much of the painted area is untouched */
|
/* Stack: current depth plus how much of the painted area is untouched */
|
||||||
print_string("sp ");
|
print_string("sp ");
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ extern __xdata uint8_t err_status;
|
|||||||
#define HEALTH_PH_TX 3
|
#define HEALTH_PH_TX 3
|
||||||
#define HEALTH_PH_STP 4
|
#define HEALTH_PH_STP 4
|
||||||
#define HEALTH_PH_CMD 5
|
#define HEALTH_PH_CMD 5
|
||||||
#define HEALTH_PHASES 6
|
#define HEALTH_PH_LLDP 6
|
||||||
#define HEALTH_LLDP 7
|
#define HEALTH_PHASES (HEALTH_PH_LLDP + 1) /* last id + 1: sizes the arrays in cmd_parser.c */
|
||||||
|
|
||||||
extern __xdata uint16_t health_rx_frames;
|
extern __xdata uint16_t health_rx_frames;
|
||||||
#define health_rx_frame() health_rx_frames++
|
#define health_rx_frame() health_rx_frames++
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ __xdata uip_ipaddr_t server;
|
|||||||
#define DHCP_END 255
|
#define DHCP_END 255
|
||||||
|
|
||||||
#pragma codeseg BANK3
|
#pragma codeseg BANK3
|
||||||
#pragma constseg BANK2
|
#pragma constseg BANK3
|
||||||
|
|
||||||
struct dhcp_pkt {
|
struct dhcp_pkt {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|||||||
@@ -34,6 +34,21 @@ Next, transfer the actual packet over by repeating the SFR function with a
|
|||||||
pointer to the frame on the ASIC directly after the frame header and a
|
pointer to the frame on the ASIC directly after the frame header and a
|
||||||
length as given by the length in the frame header + 7, again divided by 8.
|
length as given by the length in the frame header + 7, again divided by 8.
|
||||||
|
|
||||||
|
The RX ring's inclusive last slot is configured as `0x4ff`, giving a byte
|
||||||
|
range of `0x0000` through `0x27ff`. If the descriptor occupies the last slot
|
||||||
|
at `0x27f8`, its payload starts at `0x0000`, not `0x2800`. The RX copy code
|
||||||
|
normalizes that starting address before DMA. It relies on the hardware to
|
||||||
|
wrap transfers that start inside the ring and cross its end, as observed
|
||||||
|
on SWTGW218AS. Programming an initial address of `0x2800` does not wrap
|
||||||
|
and can instead read zeros or stale TX data outside the RX ring.
|
||||||
|
|
||||||
|
Frame lengths are checked against `UIP_CONF_BUFFER_SIZE` before copying.
|
||||||
|
DMA works in whole eight-byte units. `UIP_CONF_BUFFER_ALLOC_SIZE` rounds
|
||||||
|
the backing storage up to the next complete word: 1,560 bytes for the
|
||||||
|
1,556-byte logical frame limit. This padding allows a maximum-size frame
|
||||||
|
to be transferred directly without a separate tail copy. The logical
|
||||||
|
frame limit and advertised MSS are unchanged.
|
||||||
|
|
||||||
The received frame will have an RTL proprietary Ethernet frame type of
|
The received frame will have an RTL proprietary Ethernet frame type of
|
||||||
0x8899 (RRPC) where normally the frame type 0x0800 for IPv4 would be located.
|
0x8899 (RRPC) where normally the frame type 0x0800 for IPv4 would be located.
|
||||||
Further 6 bytes follow describing the frame, before the normal IPv4 data
|
Further 6 bytes follow describing the frame, before the normal IPv4 data
|
||||||
|
|||||||
@@ -0,0 +1,220 @@
|
|||||||
|
# Adding a new device
|
||||||
|
|
||||||
|
A device is supported by adding one board header `.h` and board definition `.c` file
|
||||||
|
under `machine/`.
|
||||||
|
the build selects the definition by name, and CI compiles every file it finds.
|
||||||
|
|
||||||
|
To compile for your added device, do:
|
||||||
|
```
|
||||||
|
make MACHINE=<NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
## What a new device consists of
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `machine/<NAME>.c` | the `struct machine machine` board definition |
|
||||||
|
| `machine/<NAME>.h` | `MACHINE_MODEL` (the model string shown in the UI and the CLI) and `MACHINE_CHIPSET` (`RTL8372` or `RTL8373`) |
|
||||||
|
| `machine/<NAME>_init.c` | optional `machine_custom_init()` boot hook, for registers the machine definition cannot express |
|
||||||
|
| `doc/devices/<name>.md` + `doc/supported_devices.md` | (only if the board is verified and you want to support it publicly) user-facing documentation |
|
||||||
|
|
||||||
|
`<NAME>` is the machine symbol without its `MACHINE_` prefix, so `MACHINE` is
|
||||||
|
passed exactly as spelled on the command line: `make MACHINE=MY_BOARD_1_0`
|
||||||
|
needs `machine/MY_BOARD_1_0.c` and `machine/MY_BOARD_1_0.h`.
|
||||||
|
|
||||||
|
## Step 1: the board header
|
||||||
|
|
||||||
|
`machine/<NAME>.h` carries the product string and the SoC family. Use the
|
||||||
|
existing files as the template:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#ifndef _MACHINE_MY_BOARD_1_0_H_
|
||||||
|
#define _MACHINE_MY_BOARD_1_0_H_
|
||||||
|
|
||||||
|
#define MACHINE_MODEL "Brand Model V1.0"
|
||||||
|
#define MACHINE_CHIPSET RTL8373
|
||||||
|
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
`MACHINE_CHIPSET` is `RTL8373` or `RTL8372`; a build without it will fail. It selects the default
|
||||||
|
logical port range: `MACHINE_MIN_PORT` is `0` for RTL8373 and `3` for RTL8372, while
|
||||||
|
`MACHINE_MAX_PORT` is `8`, the highest logical port index. A board with a different range defines
|
||||||
|
`MACHINE_MIN_PORT` and/or `MACHINE_MAX_PORT` in its header to override the
|
||||||
|
defaults.
|
||||||
|
|
||||||
|
The device product string is what the CLI or the Web-Interface will print to identify the device; `machine.h` includes it by name.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> `machine_name` is a `char[30]` and `MACHINE_MODEL` is copied into it at
|
||||||
|
> compile time. A longer model string still builds, but SDCC emits
|
||||||
|
> `warning 147: excess elements in array of chars initializer` and the name is
|
||||||
|
> truncated in the UI. Keep it to 29 characters or less.
|
||||||
|
|
||||||
|
## Step 2: the board definition
|
||||||
|
|
||||||
|
`machine/<NAME>.c` starts with the shared prelude and then defines the single
|
||||||
|
`machine` object. Copy the closest existing board and adjust it — do not start
|
||||||
|
from a blank file, the field meanings are easier to see in a real example.
|
||||||
|
The best choice is usually a device that has the same number and type of Ethernet
|
||||||
|
ports and the same number of SFP+ cages.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "machine_defs.h"
|
||||||
|
|
||||||
|
__code const struct machine machine = {
|
||||||
|
MACHINE_COMMON_SETTING,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||||
|
.led_sets = {
|
||||||
|
{ /* RJ45 ports */
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
}, { /* SFP port, single green LED */
|
||||||
|
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`MACHINE_COMMON_SETTING` (from `machine_defs.h`) initializes `machine_name` and
|
||||||
|
`isRTL8373` from the header's `MACHINE_MODEL` and `MACHINE_CHIPSET`. The logical
|
||||||
|
port range comes from `MACHINE_MIN_PORT` and `MACHINE_MAX_PORT` in `machine.h`.
|
||||||
|
Keep it as the first initializer and list the board-specific fields after it.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Meaning |
|
||||||
|
|-------|---------|
|
||||||
|
| `MACHINE_COMMON_SETTING` | expands to `machine_name` (`MACHINE_MODEL`) and `isRTL8373` (`1` for `RTL8373`, `0` for `RTL8372`); both are derived from the header's `MACHINE_CHIPSET` (see Step 1) |
|
||||||
|
| `n_sfp` | number of SFP+ cages |
|
||||||
|
| `n_10g` | SerDes 10G capability used by the RTL837xN init: `0` none, `1` one, `2` two 10G-capable SerDes |
|
||||||
|
| `log_to_phys_port[9]` | logical port (0-based index) → physical front-panel port number |
|
||||||
|
| `phys_to_log_port[9]` | the inverse, physical port 1 is index 0, unused slots are 0 |
|
||||||
|
| `is_sfp[9]` | `0` for copper, `1` for left slot and `2` for right slot |
|
||||||
|
| `sfp_port[2]` | per-cage wiring, `sfp_port[0]` is the leftmost cage |
|
||||||
|
| `reset_pin` | GPIO of the reset button, `GPIO_NA` if unpopulated |
|
||||||
|
| `high_leds` | mux/enable for the LED pins 27–29 (`LED_27`, `LED_28_SYS`, `LED_29`) |
|
||||||
|
| `port_led_set[9]` | which LED set (0–3) each logical port uses |
|
||||||
|
| `led_sets[4][4]` | Each port can have up to 4 GPIO output pins assigned. 4 sets of LEDs with 4 LED-conditions per set; the conditions define which GPIO pins become active for a port given a port link-state. Which LEDs are then enabled depends on the wiring of the pins to up to 3 LEDs for that port, which can make a logical combination of the 4 LED output-pins. |
|
||||||
|
| `led_mux_custom` / `led_mux[28]` | `1` plus the 28 mux values when the stock LED muxing does not fit the board |
|
||||||
|
| `mac_flash_offset` | flash offset of the factory MAC address, omit or `0` if the board does not store one |
|
||||||
|
|
||||||
|
Each `struct sfp_port` entry holds `pin_detect`, `pin_los`, `pin_tx_disable`,
|
||||||
|
`sds` (which SerDes drives the cage) and `i2c` (built with `I2CBUS(sda, scl)`,
|
||||||
|
or `GPIO_NA`-based values where a cage has no such pin).
|
||||||
|
|
||||||
|
`I2CBUS(...)` only accepts the pin pairs listed in `machine_defs.h`. A wrong
|
||||||
|
pair is caught at compile time: SDCC reports
|
||||||
|
`error 176: sizeof applied to an incomplete type` pointing at the offending
|
||||||
|
`.i2c` line, because the macro deliberately turns an invalid bus number into an
|
||||||
|
array of size 0.
|
||||||
|
|
||||||
|
### Reusing an existing definition
|
||||||
|
|
||||||
|
If the new board is electrically identical to one that already exists — same
|
||||||
|
port mapping, same SFP wiring, same LEDs — do not copy the file. Make the new
|
||||||
|
`.c` a symlink and keep only a distinct `.h`, so the two boards cannot drift
|
||||||
|
apart:
|
||||||
|
|
||||||
|
```
|
||||||
|
ln -s KP_9000_6XHML_X2.c machine/MY_BOARD_1_0.c
|
||||||
|
```
|
||||||
|
|
||||||
|
The new board still needs `machine/MY_BOARD_1_0.h` (pick the version number on
|
||||||
|
the PCB) with its own `MACHINE_MODEL` and `MACHINE_CHIPSET`: `MACHINE_MODEL` is
|
||||||
|
what distinguishes the products, and `MACHINE_CHIPSET` must match the SoC of
|
||||||
|
the board definition being reused.
|
||||||
|
Existing examples: `machine/PCB_K0402WS_V3.c`, `machine/KP_9000_9XHML_X_V3_2.c`
|
||||||
|
and the six `KP_9000_*` revision variants.
|
||||||
|
|
||||||
|
Two files that differ only in whitespace or comments are duplicates and should
|
||||||
|
be collapsed this way.
|
||||||
|
|
||||||
|
### Optional custom init hook
|
||||||
|
|
||||||
|
If the board needs custom initialization, add
|
||||||
|
`machine/<NAME>_init.c` defining `machine_custom_init()`. The Makefile picks the
|
||||||
|
file up by name and compiles it.
|
||||||
|
|
||||||
|
Boards that need the same hook share one file: keep the code in a single
|
||||||
|
`machine/<NAME>_init.c` whose `machine/<NAME>.c` is a real file (not a symlink),
|
||||||
|
and make the other boards' `_init.c` symlinks to it, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
ln -s KP_9000_6XH_X2_init.c machine/MY_BOARD_1_0_init.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: build and verify
|
||||||
|
|
||||||
|
```
|
||||||
|
make MACHINE=MY_BOARD_1_0
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated flash image appears as `output/rtlplayground-<version>-MY_BOARD_1_0.bin`. An
|
||||||
|
unknown or empty `MACHINE` fails immediately with a message naming the expected
|
||||||
|
file, before anything is compiled.
|
||||||
|
|
||||||
|
Then run the checks CI runs:
|
||||||
|
|
||||||
|
```
|
||||||
|
make machine_check # compiles machine/<NAME>.c and its optional _init.c for every machine
|
||||||
|
make -C test # host-side unit tests
|
||||||
|
```
|
||||||
|
|
||||||
|
`make machine_check` discovers the definitions with
|
||||||
|
`$(wildcard machine/*.c)`, so a new file is covered without registering it
|
||||||
|
anywhere. CI (`.github/workflows/build.yml`) runs it on every push and pull
|
||||||
|
request, alongside full builds for a 4+2 and an 8+1 board.
|
||||||
|
|
||||||
|
A successful compile only proves the definition is syntactically valid. The
|
||||||
|
actual behaviour — port numbering, SFP detection, LEDs — has to be confirmed on
|
||||||
|
hardware, and the console commands (`port`, `stat`, `sfp`, `leds`) are the
|
||||||
|
tools for that.
|
||||||
|
|
||||||
|
## Step 4: documentation
|
||||||
|
|
||||||
|
Once the board has been tested on hardware:
|
||||||
|
|
||||||
|
1. Add a row to the table in [Supported devices](supported_devices.md).
|
||||||
|
2. Add `doc/devices/<name>.md` describing the board, the build target
|
||||||
|
(`make MACHINE=MY_BOARD_1_0`), what works and what is unverified, plus
|
||||||
|
photos and the PCB silkscreen marking.
|
||||||
|
3. If the board shares a PCB with other revisions, follow
|
||||||
|
`doc/devices/KP-9000-6XH-X2.md` and document which `MACHINE` to pick for
|
||||||
|
which silkscreen.
|
||||||
|
|
||||||
|
### Identifying the CPU variant
|
||||||
|
|
||||||
|
For RTL8373-based devices, use the read-only console command below to distinguish
|
||||||
|
the N and non-N CPU variants:
|
||||||
|
|
||||||
|
```text
|
||||||
|
regget 4
|
||||||
|
```
|
||||||
|
|
||||||
|
| Register 0x0004 value | CPU |
|
||||||
|
|---|---|
|
||||||
|
| `0x83730000` | RTL8373 (non-N) |
|
||||||
|
| `0x83737000` | RTL8373N |
|
||||||
|
|
||||||
|
Record the identified CPU in the device documentation. These values identify
|
||||||
|
only the CPU variant; document PHY and flash-chip models separately when verified.
|
||||||
|
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
hongyavision HYWS-SGT0204S
|
||||||
|
|
||||||
|
RTL8372-based 4×2.5G + 2×SFP+ unmanaged switch.
|
||||||
|
|
||||||
|
Also marked on the PCB as `2G5F4_10G2_V1.01`.
|
||||||
|
|
||||||
|
Stock firmware runs a factory test console on UART at 9600 baud 8N1 (banner
|
||||||
|
`RTL8371B start`, prompt `RTL8371B:`). There is no management CLI and no Web
|
||||||
|
interface.
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation and update.
|
||||||
|
Erase the whole chip and verify the write (`flashrom -v`) before powering the
|
||||||
|
board, so an incomplete write is caught before the board is powered up.
|
||||||
|
|
||||||
|
Stock flash chip is 512 KB (Bright Moon `T25S40`, 4 Mbit, SOP-8), which the
|
||||||
|
RTLPlayground image fills exactly.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
Case, top / front / nameplate:
|
||||||
|
|
||||||
|
<img src="photos/2G5F4_10G2_V1.01/assembled-top.jpg" width="300" />
|
||||||
|
<img src="photos/2G5F4_10G2_V1.01/assembled-front.jpg" width="300" />
|
||||||
|
<img src="photos/2G5F4_10G2_V1.01/assembled-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
- **Manufacturer**: hongyavision (Shenzhen Hongyavision Electronic Technology
|
||||||
|
Co., Ltd.)
|
||||||
|
- **Model**: HYWS-SGT0204S — the nameplate is printed in Chinese and reads
|
||||||
|
"10/100/1000/2500M fibre switch" and "4x 2.5G copper port + 2x 10G SFP+
|
||||||
|
optical port"
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1G / 2.5G / 10G
|
||||||
|
- **Power**: 12 V DC, 2 A
|
||||||
|
- **Serial number**: `S/N-YYYYMMDDNNNN`, e.g. `S/N-202312010028`
|
||||||
|
|
||||||
|
The top of the case only carries generic printing ("2.5G+10G High Speed Fiber
|
||||||
|
Transceiver / 4-Port 2.5G Ethernet Switch+10G Fiber"), so the nameplate on the
|
||||||
|
bottom is what identifies the device.
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
|
||||||
|
- Copper LEDs: white (2.5G) and blue (link/activity)
|
||||||
|
- SFP LEDs: one single LED per port (link/activity)
|
||||||
|
- SFP EEPROM and DDM readable on both cages, verified with a 10G module
|
||||||
|
(`Rate: 0x67`, module identity and DDM values via the `sfp` console command)
|
||||||
|
- Serial console at 115200 8N1 (RTLPlayground) / 9600 8N1 (stock)
|
||||||
|
|
||||||
|
### Not verified
|
||||||
|
|
||||||
|
- The reset button footprint is unpopulated and the case has no opening for it,
|
||||||
|
so it could not be tested.
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: `2G5F4_10G2_V1.01`
|
||||||
|
|
||||||
|
**Key components**
|
||||||
|
- Main switch: RTL8372 (RTL8371B family), reported as `RTL8372` (non-N) by
|
||||||
|
RTLPlayground. The chip sits under a heatsink and its package marking is not
|
||||||
|
readable.
|
||||||
|
- U1: SPI NOR flash, Bright Moon `T25S40`, 4 Mbit / 512 KB, SOP-8
|
||||||
|
- A 3-hole reset button footprint is present but unpopulated, and the case has
|
||||||
|
no opening for it, so there is no usable reset button
|
||||||
|
|
||||||
|
Top side:
|
||||||
|
|
||||||
|
<img src="photos/2G5F4_10G2_V1.01/pcb_top.jpg" width="600" />
|
||||||
|
|
||||||
|
Bottom:
|
||||||
|
|
||||||
|
<img src="photos/2G5F4_10G2_V1.01/pcb_bottom.jpg" width="600" />
|
||||||
|
|
||||||
|
The stock flash chip, Bright Moon `T25S40` (SOP-8, 4 Mbit / 512 KB):
|
||||||
|
|
||||||
|
<img src="photos/2G5F4_10G2_V1.01/flash_t25s40.jpg" width="300" />
|
||||||
|
|
||||||
|
### Port layout
|
||||||
|
|
||||||
|
| Front panel position | Logical port | Physical port | Type |
|
||||||
|
|----------------------|--------------|---------------|---------|
|
||||||
|
| SFP left | 8 | 5 | SFP+ |
|
||||||
|
| RJ45 1 | 4 | 1 | Copper |
|
||||||
|
| RJ45 2 | 5 | 2 | Copper |
|
||||||
|
| RJ45 3 | 6 | 3 | Copper |
|
||||||
|
| RJ45 4 | 7 | 4 | Copper |
|
||||||
|
| SFP right | 3 | 6 | SFP+ |
|
||||||
|
|
||||||
|
Copper ports 1–4 match the KP-9000-6XH-X2 (2M-PCB43-V1.1) layout, which this
|
||||||
|
board is a sibling of. The two SFP+ cages are wired the other way round
|
||||||
|
compared to that board: physical port 5 is on SDS1 and physical port 6 is on
|
||||||
|
SDS0.
|
||||||
|
|
||||||
|
### Serial console
|
||||||
|
|
||||||
|
The board has three through-holes used as the serial console, next to the
|
||||||
|
heatsink in the middle of the board and visible in the top side photo above (the
|
||||||
|
silkscreen labels are printed rotated by 90°). **The silkscreen labels are
|
||||||
|
wrong**: they are shifted relative to the actual signals.
|
||||||
|
|
||||||
|
| Silkscreen label | Actual signal |
|
||||||
|
|------------------|---------------|
|
||||||
|
| TX | GND |
|
||||||
|
| RX | TX |
|
||||||
|
| GND | RX |
|
||||||
|
|
||||||
|
Wiring (following the measured signals, not the labels):
|
||||||
|
|
||||||
|
| USB-TTL adapter | Board pad |
|
||||||
|
|-----------------|----------------------|
|
||||||
|
| GND | pad labelled `TX` |
|
||||||
|
| RX | pad labelled `RX` |
|
||||||
|
| TX | pad labelled `GND` |
|
||||||
|
|
||||||
|
- **Settings**: 115200 baud / 8N1 / 3.3V TTL (RTLPlayground), 9600 baud for the
|
||||||
|
stock firmware
|
||||||
|
- The stock firmware only prints a few bytes and a factory test menu
|
||||||
|
(`?`, `rst`, `f`, `r`, `10`, `100`, `g1`, `sd`, `eye`, …); it is not an
|
||||||
|
interactive management console
|
||||||
|
|
||||||
|
### LED configuration
|
||||||
|
|
||||||
|
Case silkscreen, below the RJ45 ports:
|
||||||
|
|
||||||
|
```
|
||||||
|
White : 2.5G Blue : 1000M/2500M L/A
|
||||||
|
```
|
||||||
|
|
||||||
|
The front panel also carries a `PWR` LED and one LED per SFP cage (`SFP1`,
|
||||||
|
`SFP2`) on the right hand side.
|
||||||
|
|
||||||
|
| Port | LED | Linked, idle | With traffic |
|
||||||
|
|------------|--------------|--------------|--------------|
|
||||||
|
| Copper | white | 2.5G only | same |
|
||||||
|
| Copper | blue | solid | blinks (L/A) |
|
||||||
|
| SFP | single LED | solid | blinks (L/A) |
|
||||||
|
|
||||||
|
Measured LED-ID mapping (from the RTL837x LED set registers):
|
||||||
|
|
||||||
|
| LED-ID | Function |
|
||||||
|
|--------|---------------------------------|
|
||||||
|
| LED-ID0| copper blue LED |
|
||||||
|
| LED-ID1| copper white LED |
|
||||||
|
| LED-ID2| SFP single LED |
|
||||||
|
|
||||||
|
**Important**: `RTL837X_REG_LED_GLB_IO_EN` bit 6 must be set in
|
||||||
|
`machine_custom_init()`. Without it the RTL837x "solid" conditions (LINK/speed)
|
||||||
|
do not drive the LEDs at all and only `ACT` does, which makes the white LED
|
||||||
|
glow faintly at non-2.5G speeds.
|
||||||
|
|
||||||
|
### SFP GPIO assignments
|
||||||
|
|
||||||
|
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|
||||||
|
|-------------------|-------------------------------|------------------|--------|-------------------------|--------------------------|
|
||||||
|
| Left (logical 8, physical 5) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
|
||||||
|
| Right (logical 3, physical 6)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO10\_LED10 | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
|
||||||
|
|
||||||
|
`pin_tx_disable` is GPIO\_NA on both ports. Both I2C buses are confirmed
|
||||||
|
working: with the same 10G module inserted, the `sfp` console command reads its
|
||||||
|
vendor and model from the left cage (`Slot 1`) and from the right cage
|
||||||
|
(`Slot 2`), DDM values included. The insertion also shows which SerDes drives
|
||||||
|
each cage - the left cage reports `sds_config sds: 01` and the right cage
|
||||||
|
`sds: 00`, which matches the table above.
|
||||||
|
|
||||||
|
### Machine target
|
||||||
|
|
||||||
|
Build for this device with `make MACHINE=2G5F4_10G2_V1_01`, which selects the
|
||||||
|
`machine/2G5F4_10G2_V1_01.c` board definition. It is derived from
|
||||||
|
`machine/KP_9000_6XHML_X2.c` with the SFP cage order and the reset pin changed.
|
||||||
|
The fitted T25S40 cannot be read in DIO mode on this board: an image that leaves
|
||||||
|
DIO enabled does not come up at all, both at the default read clock divider of 4
|
||||||
|
and at 8 (two boards tested), while the same image with single-IO boots and runs
|
||||||
|
normally. The board definition therefore sets `flash_sio`, which makes
|
||||||
|
`flash_init()` use `CMD_FREAD` at divider 8. Only the management plane is
|
||||||
|
slower, the ASIC keeps forwarding in hardware.
|
||||||
@@ -17,8 +17,8 @@ The original web interface reports this board as hardware version V3.2
|
|||||||
The component placement matches [2M-PCB23-V3.1](2M-PCB23-V3_1.md): same
|
The component placement matches [2M-PCB23-V3.1](2M-PCB23-V3_1.md): same
|
||||||
positions for the flash (U8), the T7/T8/T9/T10 headers, the SFP cage and its
|
positions for the flash (U8), the T7/T8/T9/T10 headers, the SFP cage and its
|
||||||
LED, and the unpopulated U7/U9 footprints. Build with
|
LED, and the unpopulated U7/U9 footprints. Build with
|
||||||
`MACHINE=KP_9000_9XHML_X_V3_2`, which uses the V3.1 machine definition and
|
`make MACHINE=KP_9000_9XHML_X_V3_2`, whose board file is a symlink to the V3.1
|
||||||
only differs in the reported name.
|
definition and only differs in the reported name.
|
||||||
|
|
||||||
## Tested
|
## Tested
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ and sold by Mokerlink.
|
|||||||
The device is fully supported:
|
The device is fully supported:
|
||||||
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
- The SFP+ port supports 1G, 2.5G and 10G modules
|
- The SFP+ port supports 1G, 2.5G and 10G modules
|
||||||
- LEDs work with the same indiciations as the OEM firmware (use KP_9000_6XHML_X2_V1_1 in machine.h if building yourself or the corresponding pre-compiled binary)
|
- LEDs work with the same indiciations as the OEM firmware (build with `make MACHINE=KP_9000_6XHML_X2_V1_1` if building yourself, or use the corresponding pre-compiled binary)
|
||||||
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
|
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
|
||||||
|
|
||||||
### Hardware overview
|
### Hardware overview
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
# MokerLink POE-2G080110GS
|
# MokerLink POE-2G080110GS
|
||||||
|
|
||||||
The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware.
|
The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware.
|
||||||
|
The`KP-9000-9XHP-X` is the KeepLink rebrand for same product.
|
||||||
|
|
||||||
## Brands
|
## Brands
|
||||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||||
|--------|------------------|-------|------------------|-----------------|---------------|
|
|--------|------------------|-------|------------------|-----------------|---------------|
|
||||||
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
|
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
|
||||||
|
| KeepLink | KP-9000-9XHP-X | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
|
||||||
|
|
||||||
## Hardware overview
|
## Hardware overview
|
||||||
Front
|
Front
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Hasivo S1100P-8GT-1SX-S
|
||||||
|
|
||||||
|
RTL8373N switch with 8 × 2.5G RJ45 ports and 1 × SFP port. GD25Q16 2 MiB flash.
|
||||||
|
|
||||||
|
## Port mapping
|
||||||
|
|
||||||
|
| Front port | ASIC MAC | Interface |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1–8 | 0–7 | RJ45 |
|
||||||
|
| 9 | 8 | SFP (SDS1) |
|
||||||
|
|
||||||
|
## Board signals
|
||||||
|
|
||||||
|
| Function | GPIO |
|
||||||
|
| --- | --- |
|
||||||
|
| SFP detect | 38 |
|
||||||
|
| SFP LOS | 37 |
|
||||||
|
| SFP TX disable | Not connected (`GPIO_NA`) |
|
||||||
|
| SFP I2C SDA / SCL | 39 / 40 |
|
||||||
|
| Reset | 54 |
|
||||||
|
|
||||||
|
PoE is managed by an RTL8238B and a separate STC8H8K64U controller, not directly by the RTL8373N. RTLPlayground does not control PoE on this board.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
`make MACHINE=HASIVO_S1100P_8GT_1SX_S CI=1`
|
||||||
|
|
||||||
|
## Photos
|
||||||
|
|
||||||
|
Front panel:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
PCB top:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
PCB bottom:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
@@ -90,6 +90,8 @@ Custom mapping for ONT-S207CW-62TS-SE:
|
|||||||
## Flashing Instructions
|
## Flashing Instructions
|
||||||
|
|
||||||
See the [README.md](../../README.md) for general flashing instructions.
|
See the [README.md](../../README.md) for general flashing instructions.
|
||||||
|
For compilation, use command `make MACHINE=ONT_S207CW_62TS_SE` to specify the machine.
|
||||||
|
If you are using managed version of the switch, you can then also compile the installer and flash using GUI - run command `cd installer` and finally `make`.
|
||||||
|
|
||||||
## Stock Firmware Information
|
## Stock Firmware Information
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# PCB-AFGW SWTG218ANS V2.0.2
|
||||||
|
|
||||||
|
RTL8373-based 8×2.5G PoE + 1×10G SFP+ web-managed switch, sold as the
|
||||||
|
**RealHD PSW8-25MG**.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Manufacturer**: RealHD
|
||||||
|
- **Model**: PSW8-25MG
|
||||||
|
- **PCB marking**: `PCB-AFGW SWTG218ANS_V2.0.2` (silkscreened as `PCB-AFGW SWTG218ANS_V2.0.2_23308`)
|
||||||
|
- **Ports**:
|
||||||
|
- 8 × RJ45: 10/100/1000/2500 Mbps with PoE
|
||||||
|
- 1 × SFP+: 1G / 2.5G / 10G (front panel marking `9(10G)`)
|
||||||
|
- **Power input**: internal AC PSU, `100-240V~ 50/60Hz 2A MAX`, DC output `53.5V 2.8A 150W`
|
||||||
|
- **Front panel LEDs**: `PWR`, `SYS`, per RJ45 port `Link/Act` and `PoE`, per SFP port 2.5G (green) and 10G (blue)
|
||||||
|
- **Stock firmware defaults**: web-managed PoE switch
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE is not configurable via RTLPlayground)
|
||||||
|
- SFP+ port supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs: green (2.5G) and amber (1G/100M/10M) per RJ45 port with activity, green (1G/2.5G) and blue (10G) on the SFP port, plus the `SYS` LED
|
||||||
|
|
||||||
|
### Photos
|
||||||
|
|
||||||
|
Front panel:
|
||||||
|
|
||||||
|
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/device_front.jpg" width="800" />
|
||||||
|
|
||||||
|
Board mounted in the case, with the internal PSU above it:
|
||||||
|
|
||||||
|
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/dev_top_w_pcb.jpg" width="800" />
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
Top side:
|
||||||
|
|
||||||
|
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/pcb_front.jpg" width="800" />
|
||||||
|
|
||||||
|
Bottom side:
|
||||||
|
|
||||||
|
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/pcb_back.jpg" width="800" />
|
||||||
|
|
||||||
|
A 4-pad UART header with `RXD` / `TXD` silkscreened sits next to the right heatsink.
|
||||||
|
|
||||||
|
### Port layout
|
||||||
|
|
||||||
|
| Logical port | Physical port | Type |
|
||||||
|
|--------------|---------------|--------|
|
||||||
|
| 1-8 | 1-8 | RJ45 |
|
||||||
|
| 9 | 9 | SFP+ |
|
||||||
|
|
||||||
|
### LED configuration
|
||||||
|
|
||||||
|
RJ45 ports use LED SET0, the SFP+ port uses LED SET1. The board needs the custom
|
||||||
|
LED mux (`led_mux_custom = 1`), and `RTL837X_REG_LED_GLB_IO_EN` is written to
|
||||||
|
`0x7f24977f` in `machine_custom_init()` so the LED pins are enabled as wired here.
|
||||||
|
|
||||||
|
| SET | LED pin 0 | LED pin 1 |
|
||||||
|
|------|-----------------------------------------------|-------------------------------------------------------|
|
||||||
|
| SET0 | Green — lights on 2.5G link with activity | Amber — lights on 1G / 100M / 10M link with activity |
|
||||||
|
| SET1 | All speeds — lights on any link with activity | 10G — lights on 10G link with activity |
|
||||||
|
|
||||||
|
On the front panel this gives one bi-color `Link/Act` LED per RJ45 port (green at
|
||||||
|
2.5G, amber at 10/100/1000M, blinking with activity) and one `PoE` LED per RJ45
|
||||||
|
port, which is driven by the PoE hardware and not by the switch. The SFP+ port has
|
||||||
|
a green 2.5G LED and a blue 10G LED.
|
||||||
|
|
||||||
|
### SFP GPIO assignments
|
||||||
|
|
||||||
|
| SFP (logical 9) | pin_detect (ModAbs) | pin_los | pin_tx_disable | SerDes | I2C SDA | I2C SCL |
|
||||||
|
|-----------------|---------------------|---------|----------------|--------|------------------|----------------------|
|
||||||
|
| SFP | GPIO38 | GPIO_NA | GPIO_NA | SDS1 | GPIO39_I2C_SDA4 | GPIO40_I2C_SCL3_MDC1 |
|
||||||
|
|
||||||
|
### Machine configuration
|
||||||
|
|
||||||
|
```
|
||||||
|
make MACHINE=REALHD_PSW8_25MG
|
||||||
|
```
|
||||||
|
|
||||||
|
### Programming
|
||||||
|
|
||||||
|
The serial console runs at 8N1 on 115200 baud with the RTLPlayground firmware
|
||||||
|
(see the UART header note under *PCB overview*). The stock firmware baud rate 57600. The flash chip was 2MB.
|
||||||
|
|
||||||
|
### PoE
|
||||||
|
|
||||||
|
The 8 RJ45 ports support PoE, powered by the internal 150W AC PSU (DC output
|
||||||
|
53.5V 2.8A) mounted above the main board.
|
||||||
|
|
||||||
|
Note: RTLPlayground does not provide PoE management for this board. The PoE
|
||||||
|
hardware runs with its own configuration, the same as on the other PoE boards in
|
||||||
|
this project.
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# PCB-K0402WS-V1.0
|
||||||
|
|
||||||
|
This is the first revision of the PCB-K0402WS series of boards; it's very similar to 2.0 in terms of layout/wiring.
|
||||||
|
|
||||||
|
The board does have footprints for a VLAN modeswitch at the front and a second flash chip on the bottom of the PCB, but these have been seen to ship unpopulated.
|
||||||
|
|
||||||
|
### Brands
|
||||||
|
|
||||||
|
* YuanLey YS25-0402 <sup><sub>Note: there are [multiple revisions](PCB-K0402WS-V3.0.md) of the YS25-0402. This first revision lacks the "Vlan" switch cutout on the front of the enclosure.</sub></sup>
|
||||||
|
|
||||||
|
### Programming
|
||||||
|
|
||||||
|
Use a SOIC-8 clamp to the flash chip (U1 on silkscreen) at the top of the board, leaving it otherwise unpowered.
|
||||||
|
|
||||||
|
The board has been seen to ship with a single [BoyaMicro BY25Q16BSSIG](https://www.lcsc.com/datasheet/C382744.pdf) 16Mbit (2MiB) chip, though exact BOM may vary.
|
||||||
|
|
||||||
|
<a href="photos/PCB-K0402WS-V1.0/flash.jpg"><img src="photos/PCB-K0402WS-V1.0/flash.jpg" width="300" /></a>
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- Both SFP ports supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs (Power LED is always on)
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
#### Board markings
|
||||||
|
- Top silkscreen: PCB-K0402W-V1.0 / DIP-K0402WS-V1.0
|
||||||
|
|
||||||
|
#### Key components
|
||||||
|
- U1: SPI NOR flash, 2 MiB
|
||||||
|
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
|
||||||
|
|
||||||
|
Front panel
|
||||||
|
|
||||||
|
<a href="photos/PCB-K0402WS-V1.0/ports.jpg"><img src="photos/PCB-K0402WS-V1.0/ports.jpg" width="300" /></a>
|
||||||
|
|
||||||
|
PCB top
|
||||||
|
|
||||||
|
<a href="photos/PCB-K0402WS-V1.0/pcb-top.jpg"><img src="photos/PCB-K0402WS-V1.0/pcb-top.jpg" width="300" /></a>
|
||||||
|
|
||||||
|
PCB bottom
|
||||||
|
|
||||||
|
<a href="photos/PCB-K0402WS-V1.0/pcb-bottom.jpg"><img src="photos/PCB-K0402WS-V1.0/pcb-bottom.jpg" width="300" /></a>
|
||||||
|
|
||||||
|
Bottom and rear
|
||||||
|
|
||||||
|
<a href="photos/PCB-K0402WS-V1.0/bottom.jpg"><img src="photos/PCB-K0402WS-V1.0/bottom.jpg" width="300" /></a>
|
||||||
|
|
||||||
|
### Power supply
|
||||||
|
|
||||||
|
Input power is delivered via a standard DC barrel jack (5.5x2.1mm) with an included 12V 1A adapter.
|
||||||
|
|
||||||
|
There is an optional grounding screw next to the DC input.
|
||||||
|
|
||||||
|
### Serial console
|
||||||
|
|
||||||
|
The PCB has a slide switch footprint (unpopulated) at the front right that is connected to the UART. It is labeled as "S1" on the silkscreen.
|
||||||
|
|
||||||
|
Facing the top front (port) side of the board, the pinout from left to right is:
|
||||||
|
|
||||||
|
| Position | Signal | GPIO |
|
||||||
|
|----------|--------|-------------------|
|
||||||
|
| 1 | RX | GPIO32\_UART0\_RX |
|
||||||
|
| 2 | GND | N/A |
|
||||||
|
| 3 | TX | GPIO31\_UART0\_TX |
|
||||||
|
|
||||||
|
Standard 0.1" / 2.54mm pin headers will not fit, so wires or clips may be used instead.
|
||||||
|
|
||||||
|
The image below shows some oversized clips clumsily attached.
|
||||||
|
|
||||||
|
<a href="photos/PCB-K0402WS-V1.0/uart.jpg"><img src="photos/PCB-K0402WS-V1.0/uart.jpg" width="300" /></a>
|
||||||
@@ -19,9 +19,14 @@ of the device just above the big label, might be covered by a QC sticker.
|
|||||||
|
|
||||||
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
|
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
|
||||||
|
|
||||||
* Siscolink SL-G0402F
|
* SICSOLINK SL-G0402F
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/SICSOLINK SL-G0402F.jpg" width="300"/>
|
||||||
|
|
||||||
|
* YuanLey YS25-0402 <sup><sub>Note: there are [multiple revisions](PCB-K0402WS-V1.0.md) of the YS25-0402. This is the newer revision that has a "Vlan" switch on the front.</sub></sup>
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/YuanLey_YS25-0402.jpg" width="300"/>
|
||||||
|
|
||||||
<img src="photos/PCB-K0402WS-V3.0/Siscolink SL-G0402F.jpg" width="300"/>
|
|
||||||
### Programming
|
### Programming
|
||||||
|
|
||||||
Using SPI clamp in-board is the only method for initial installation.
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
@@ -43,7 +48,7 @@ For the initial flash (at least with flashrom), the bin file produced by the bui
|
|||||||
### PCB overview
|
### PCB overview
|
||||||
|
|
||||||
**Board markings**
|
**Board markings**
|
||||||
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
|
- Top silkscreen: PCB-K0402W-V3.0 / DIP-K0402WS-V3.0
|
||||||
|
|
||||||
Top side
|
Top side
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# Sirivision SR-S25G2109F (S25G1109FP V1.3)
|
||||||
|
|
||||||
|
RTL8373 (non-N) with an RTL8224 quad 2.5G PHY: 8 × 2.5G RJ45 + 1 × SFP+,
|
||||||
|
2 MB flash, no PoE.
|
||||||
|
|
||||||
|
## Label specifications
|
||||||
|
|
||||||
|
| Item | Value |
|
||||||
|
|------|-------|
|
||||||
|
| Manufacturer | Sirivision |
|
||||||
|
| Model | SR-S25G2109F |
|
||||||
|
| Ports | 8 × RJ45 10/100/1000/2500 Mbps, 1 × SFP+ 1G/2.5G/10G |
|
||||||
|
| Power input | 12 V DC, 1.5 A |
|
||||||
|
| Stock firmware | version 1.0.8.0 |
|
||||||
|
| Stock defaults | IP 192.168.1.199, user `admin`, password `admin` |
|
||||||
|
| Serial number | 001008130002003A000005 (also on the PCB barcode sticker) |
|
||||||
|
|
||||||
|
The label does not carry a MAC address. After a factory initialisation the
|
||||||
|
stock firmware uses exactly the values printed on the label.
|
||||||
|
|
||||||
|
## PCB silkscreen and naming
|
||||||
|
|
||||||
|
Top side: `S25G1109FP V1.3 SIRIVISION`. That model name belongs to an unmanaged
|
||||||
|
PoE switch; this board omits the PoE section entirely. What is actually shipped
|
||||||
|
is the label model `SR-S25G2109F`: a simply managed, non-PoE switch. Its stock
|
||||||
|
firmware provides a web interface, but it responds very slowly.
|
||||||
|
|
||||||
|
## CPU, PHY and flash
|
||||||
|
|
||||||
|
| Part | Identification |
|
||||||
|
|------|----------------|
|
||||||
|
| SoC | RTL8373, non-N: `regget 4` returns `0x83730000` and the boot console prints `Detecting CPU: RTL8373` |
|
||||||
|
| PHY | RTL8224, reported as `RTL8224 ID: 0x82240000` |
|
||||||
|
| Flash | GigaDevice 25Q16ESIG (U7), 2 MB, JEDEC id `c8 40 15` |
|
||||||
|
|
||||||
|
The two large ICs sit under soldered heatsinks, their markings are not readable.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```
|
||||||
|
make MACHINE=S25G1109FP_V1_3 CI=1
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting image can be uploaded through the web interface (`System` page)
|
||||||
|
or the stock web UI.
|
||||||
|
|
||||||
|
## Port mapping
|
||||||
|
|
||||||
|
| Front port | ASIC MAC | Interface |
|
||||||
|
|------------|----------|-----------|
|
||||||
|
| 1–8 | 0–7 | RJ45 2.5G |
|
||||||
|
| 9 | 8 | SFP+ (SDS1) |
|
||||||
|
|
||||||
|
## Board signals
|
||||||
|
|
||||||
|
| Function | GPIO |
|
||||||
|
|----------|------|
|
||||||
|
| SFP detect (ModAbs) | 30, low with a module inserted |
|
||||||
|
| SFP LOS | 37, high without light |
|
||||||
|
| SFP TX disable | not connected, `GPIO_NA` |
|
||||||
|
| SFP I2C | SDA 39 / SCL 40, `I2CBUS(GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1)` |
|
||||||
|
| Reset button | 54 |
|
||||||
|
|
||||||
|
ModAbs and LOS are separate signals here: GPIO30 tells whether a module is
|
||||||
|
inserted, GPIO37 whether it receives light, so a module is identified even
|
||||||
|
before the link comes up and loss of signal is reported. GPIO38 and GPIO48,
|
||||||
|
which the 8+1 reference boards use for ModAbs and for the reset button, never
|
||||||
|
change on this board; with GPIO38 as ModAbs the firmware believed a module was
|
||||||
|
permanently present and retried the I2C read forever.
|
||||||
|
|
||||||
|
Serial console: the stock firmware runs the loader at 57600 baud and the runtime
|
||||||
|
at 9600 baud, RTLPlayground uses 115200.
|
||||||
|
|
||||||
|
## Front panel
|
||||||
|
|
||||||
|
Each copper port has two LEDs, labelled `Link/Act` (left, yellow) and `2.5G`
|
||||||
|
(right, green). The SFP cage has a single green `Link/Act` LED; next to it are
|
||||||
|
a `Power` LED and the `Reset` button.
|
||||||
|
|
||||||
|
## LED configuration
|
||||||
|
|
||||||
|
Copper ports use LED set 0, the SFP port uses LED set 1:
|
||||||
|
|
||||||
|
| Set | Function 0 (left / SFP) | Function 1 (right) |
|
||||||
|
|-----|-------------------------|--------------------|
|
||||||
|
| SET0 | all speeds, link with activity | 2.5G link |
|
||||||
|
| SET1 | all speeds, link with activity | not populated |
|
||||||
|
|
||||||
|
The board is wired in the stock port order — LED pin `3n+m` belongs to port
|
||||||
|
`n+1`, LED function `m` — so the mux table is the chip default with a single
|
||||||
|
change: the SFP LED sits on pin 25 and is driven by LED function 0, while the
|
||||||
|
default table maps pin 25 to function 1, which is unpopulated in SET1. Without
|
||||||
|
that change the SFP LED stays dark.
|
||||||
|
|
||||||
|
A speed condition alone leaves an LED dark, `LEDS_LINK` has to be set as well.
|
||||||
|
|
||||||
|
## Reset button
|
||||||
|
|
||||||
|
| Hold time while running | Effect |
|
||||||
|
|-------------------------|--------|
|
||||||
|
| less than 3 s | no action |
|
||||||
|
| 3–10 s | reset the switch chip, the firmware reboots (~20 s of downtime) |
|
||||||
|
| more than 10 s | additionally restore the default configuration |
|
||||||
|
|
||||||
|
The system LED blinks slowly while the button is held. Holding the button
|
||||||
|
during power-up instead waits for the release and restores the default
|
||||||
|
configuration when it is released after 10–30 s.
|
||||||
|
|
||||||
|
## MAC address
|
||||||
|
|
||||||
|
The factory MAC sits at `0x1FC000`, six bytes followed by `0xFF` padding. The
|
||||||
|
stock value is a locally administered address (`1A:5D:23:47:4D:EB`), which the
|
||||||
|
firmware rejects, so the device runs with a UUID-derived MAC (`06:…`). A valid
|
||||||
|
globally administered address stored there is used instead.
|
||||||
|
|
||||||
|
## What works
|
||||||
|
|
||||||
|
- all eight 2.5GBASE-T ports at 10/100/1000/2500 Mbps
|
||||||
|
- SFP+ with 10G and 1G modules, including DDM data where the module provides it
|
||||||
|
- 10G: Finisar FCBG110SD1C05 AOC (no DDM), rate `0x67`, SerDes mode `1a`
|
||||||
|
- 1G: ETU ESB5312-3SCD20 (DDM), rate `0x0d`, SerDes mode `04`
|
||||||
|
- LEDs, module insert/remove detection, loss of signal reporting, reset button
|
||||||
|
|
||||||
|
## Unverified
|
||||||
|
|
||||||
|
- 2.5G SFP modules, none was available for testing
|
||||||
|
|
||||||
|
## Photos
|
||||||
|
|
||||||
|
Front panel:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Label:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
PCB top side:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
PCB bottom side:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Flash chip, GigaDevice 25Q16ESIG:
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
### SIRIVISION_S25G2206FP_V1_1
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| YuanLey | YS25-0402M | Yes | SIRIVISION_S25G2206FP_V1_1 | 2M | 8372 |
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**:
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
- **Power**: 12V DC, 1A 5525 connector
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- ALL SFP+ ports support 1G, 2.5G and 10G modules
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: SIRIVISION S25G2206FP V1.1
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/SIRIVISION_S25G2206FP_V1_1/dev_pcb_top.jpg" width="300" />
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -4,7 +4,8 @@
|
|||||||
|---------|------------------|-------|------------------|-----------------|---------------|
|
|---------|------------------|-------|------------------|-----------------|---------------|
|
||||||
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
|
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
|
||||||
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
|
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
|
||||||
| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | ? | 8273N + 8224N |
|
| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
|
||||||
|
| MokerLink | 2G08110GSN | No | SWTG018AS-A V2.0 | 512KB(25Q40) | 8273N + 8224N |
|
||||||
|
|
||||||
|
|
||||||
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
|
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
|
||||||
@@ -14,7 +15,7 @@ The original software is running UART on 9600 baud rate.
|
|||||||
|
|
||||||
Using a SOIC clamp in-board is the only method for initial installation.
|
Using a SOIC clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
The board has a single flash chips `BS` with 4M-bit size. The front switch, switches between the two flash chips.
|
The board has a single flash chips `BS` with 2M-byte size. The front switch, switches between the two flash chips.
|
||||||
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
|
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
|
||||||
|
|
||||||
### Label specifications
|
### Label specifications
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
|
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
|
||||||
|
|
||||||
## Brands
|
## Brands
|
||||||
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
|Brand |Type |Managed|PCB |Flash |Chip RTL|
|
||||||
|---|---|---|---|---|---|
|
|---------|--------------|-------|------------------------------|----------------|--------|
|
||||||
| Horaco | ZX-SG4T2 | | PCB-SWTG024AS-A-V2.0.1_19650 | P25D40SH | ??? |
|
| Horaco | ZX-SG4T2 | No | PCB-SWTG024AS-A-V2.0.1_19650 | 512K (P25D40SH)| 8372N |
|
||||||
|
| Horaco | HC-SWTG124AS | Yes | PCB-SWTG024AS-A-V2.0.1_19650 | 2M (W25Q16JV)| 8372N |
|
||||||
|
| GoodTop | GT-ST024M | Yes | PCB-SWTG024AS-A-V2.0.1 | 2M | 8372N |
|
||||||
|
|
||||||
### Label specifications
|
### Label specifications
|
||||||
|
|
||||||
@@ -33,6 +35,8 @@ Bottom
|
|||||||
|
|
||||||
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-bottom.jpg" width="300" />
|
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
On Horaco HC-SWTG124AS with board PCB-SWTG024AS-A-V2.0.1_19650 the reset button is soldered at `SW1` (on the top left, GPIO48).
|
||||||
|
|
||||||
### J1, serial console
|
### J1, serial console
|
||||||
|
|
||||||
| `J1` pin | Signal |
|
| `J1` pin | Signal |
|
||||||
|
|||||||
@@ -46,4 +46,4 @@ Note,`R52`、`R53`may not be installed.You need to bridge them using either sold
|
|||||||
|
|
||||||
## Power supply
|
## Power supply
|
||||||
|
|
||||||
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
### SWTG024AS-V2.1
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Xikestor | SKS3200-4E2X | Yes | PCB-SWTG024AS-V2.1.0_19023 | 25Q16A | 8372N |
|
||||||
|
| Solola | SL902-SWTG024AS | Yes | PCB-SWTG024AS-V2.1.0_19023 | | 8372N |
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1000/2500/10000 Mbps
|
||||||
|
- **Power**: 1A @ 12V DC
|
||||||
|
|
||||||
|
#### Xikestore SKS-3200-4E2X label
|
||||||
|
<img src="photos/SWTG024AS-V2.1.0/label.jpg" width="300" />
|
||||||
|
|
||||||
|
### What works
|
||||||
|
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- The SFP+ ports supports 1G, 2.5G and 10G modules.
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware.
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-SWTG024AS-V2.1.0
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-V2.1.0/pcb-top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-V2.1.0/pcb-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### Serial console
|
||||||
|
|
||||||
|
The four-pin through-hole serial header can be seen to the right of the CPU heatsink in the photo above. It is labelled J1, with pin 1 (Indicated by a triangle on the silkscren) at the bottom. the pinout is also on the silkscreen:
|
||||||
|
|
||||||
|
| Pin | Label |
|
||||||
|
|-----|--------|
|
||||||
|
| 1 | TX |
|
||||||
|
| 2 | RX |
|
||||||
|
| 3 | GND |
|
||||||
|
| 4 | 3V3 |
|
||||||
|
|
||||||
|
Adding a header is a few moments work with a soldering iron. Only pins 1-3 are required for serial port use, and the stock firmware outputs at 57600bps at boot.
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## RTLPlayground target
|
## RTLPlayground target
|
||||||
|
|
||||||
Use machine target `MACHINE_LIANGUO_ZX_SWTGW215AS` for this device.
|
Build for this device with `make MACHINE=LIANGUO_ZX_SWTGW215AS`, which selects the `machine/LIANGUO_ZX_SWTGW215AS.c` board definition.
|
||||||
|
|
||||||
Physical hardware verification: 5x RJ45 ports + 1x SFP port.
|
Physical hardware verification: 5x RJ45 ports + 1x SFP port.
|
||||||
Port 5 RJ45 is interfaced through a RTL8221B IC.
|
Port 5 RJ45 is interfaced through a RTL8221B IC.
|
||||||
|
|||||||
@@ -5,9 +5,15 @@
|
|||||||
|---|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
|
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
|
||||||
| Sodola | | | | | |
|
| Sodola | | | | | |
|
||||||
| Horaco | | | | | |
|
| Horaco | HC-SWTGW218AS | Yes | SWTG118AS-V2.1 | 2MB | 8373 (non-N) |
|
||||||
| XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | |
|
| XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | |
|
||||||
|
|
||||||
|
All boards in this table use `MACHINE=SWTGW218AS`. The Horaco HC-SWTGW218AS is also sold with the
|
||||||
|
[SWTG018AS-A V2.0](SWTG018AS_A_V2_0.md) board, which needs a different firmware. Check the marking
|
||||||
|
on the PCB before flashing.
|
||||||
|
|
||||||
|
The PHY and flash-chip models for the tested Horaco units remain unverified.
|
||||||
|
|
||||||
|
|
||||||
## Photos
|
## Photos
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
### HG0402XG V1.1
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| ZoeRax | HG0402XG | No| HG0402XG V1.1 | 1M (Winbond 25Q) | |
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**: ZOERAX 2.5G 2SFP 4-Port Gigabit Switch
|
||||||
|
- **Model**: HG0402XG-EU
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
<img src="photos/HG0402XG_V1_1/HG0402XG_V1_1_bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
<img src="photos/HG0402XG_V1_1/HG0402XG_V1_1_top.jpg" width="300" />
|
||||||
|
<img src="photos/HG0402XG_V1_1/HG0402XG_V1_1_bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
Be aware that the UART header is metric, the pitch is 2mm. The JST PH2.0mm header shown was addeded after purchase
|
||||||
|
|
||||||
|
The slider switch controls microcontroller U4 in order to configure the VLAN on/off settings. U4 can reset the SoC
|
||||||
|
and also write into its registers to configure VLAN. With RTLPlayground the slider cannot be used for anything else
|
||||||
|
than triggering reset. Any change in the position will trigger this reset.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
Using SPI clamp on-board is the only method for initial installation.
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- SFP ports with various 1G/10G Fiber and Ethernet modules
|
||||||
|
- LEDs
|
||||||
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 434 KiB |
|
After Width: | Height: | Size: 565 KiB |
|
After Width: | Height: | Size: 3.0 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 308 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 469 KiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 944 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 229 KiB |
|
After Width: | Height: | Size: 804 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 253 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 398 KiB |
|
After Width: | Height: | Size: 283 KiB |
@@ -14,6 +14,7 @@ rx max 00 slow 0x0000
|
|||||||
tx max 00 slow 0x0000
|
tx max 00 slow 0x0000
|
||||||
stp max 04 slow 0x0001
|
stp max 04 slow 0x0001
|
||||||
cmd max 02 slow 0x0001
|
cmd max 02 slow 0x0001
|
||||||
|
lldp max 00 slow 0x0000
|
||||||
sp 80 untouched 62
|
sp 80 untouched 62
|
||||||
tcp st 00 tmr 00 rtx 00 rto 00 len 0x0000 mss 0x05b4
|
tcp st 00 tmr 00 rtx 00 rto 00 len 0x0000 mss 0x05b4
|
||||||
lport 0x0000 rport 0x0000 rip 0x0000 0x0000
|
lport 0x0000 rport 0x0000 rip 0x0000 0x0000
|
||||||
@@ -46,7 +47,7 @@ a flooded CPU port from a stalled loop, which look identical from outside.
|
|||||||
## Phases
|
## Phases
|
||||||
|
|
||||||
Each line is one section of the main loop: the link poll, SFP handling,
|
Each line is one section of the main loop: the link poll, SFP handling,
|
||||||
frame reception, TCP transmission, the STP timers and the command dispatch.
|
frame reception, TCP transmission, the STP timers, the LLDP timer and the command dispatch.
|
||||||
`max` is the worst time that section has taken, in ticks of 5 ms; `slow`
|
`max` is the worst time that section has taken, in ticks of 5 ms; `slow`
|
||||||
counts the passes that took two ticks or more. A misbehaving subsystem
|
counts the passes that took two ticks or more. A misbehaving subsystem
|
||||||
names itself here, which is the difference between knowing that the loop is
|
names itself here, which is the difference between knowing that the loop is
|
||||||
|
|||||||
@@ -0,0 +1,572 @@
|
|||||||
|
# LEDs HOWTO using firmware function tracing
|
||||||
|
|
||||||
|
This is a tutorial to show how to figure out the LED configuration for
|
||||||
|
unmanaged switches (on managed ones one can just print out the registers
|
||||||
|
from the command line) without using an I2C port on the device together
|
||||||
|
an I2C-capable microcontroller. You will only need to have a SOIC clamp
|
||||||
|
and will have to run ghidra to do a bit of reversing.
|
||||||
|
|
||||||
|
The additional advantage of this method is that it not only gives the LED
|
||||||
|
configuration but also the full PHY configuration and SDS configuration e.g.
|
||||||
|
in case of additional PHYs being used on the device.
|
||||||
|
|
||||||
|
We will use the ZoeRax HG0402XG V1.1 as an example device.
|
||||||
|
|
||||||
|
The first step is to read out the flash with a SOIC clamp.
|
||||||
|
Save the image as
|
||||||
|
`zoerax_hg0402xg.bin`
|
||||||
|
|
||||||
|
The next step is to use a decompiler such as ghidra to identify the
|
||||||
|
functions used to write or read registers, SDS or to the PHY.
|
||||||
|
|
||||||
|
<img src="images/ghidra_open.png" width="300" />
|
||||||
|
|
||||||
|
First, load the code in BANK0 into ghidra. The type of code is
|
||||||
|
8051 default big-endian. The code starts at offset 0x0002 in the file
|
||||||
|
and has length 0x3ffd
|
||||||
|
|
||||||
|
<img src="images/ghidra_add_block.png" width="300" />
|
||||||
|
Add BANK1 into ghidra by using File->Add to program...
|
||||||
|
and add the code starting at 0x4000 in `zoerax_hg0402xg.bin` with length
|
||||||
|
0xc000. Repeat for BANK2 (starts at 0x10000) and BANK3 (starts at 0x1c0000).
|
||||||
|
They both have length 0xc000.
|
||||||
|
|
||||||
|
<img src="images/ghidra_search_read_reg.png" width="300" />
|
||||||
|
|
||||||
|
Now, find the read_reg function. An example of the read-register function
|
||||||
|
is given below. Note the critical bit, namely the execution of the
|
||||||
|
read-function of an ASIC register via an SFR:
|
||||||
|
```
|
||||||
|
CODE1::4dc9 75 a0 01 MOV SFR_EXEC_GO,#0x1
|
||||||
|
```
|
||||||
|
|
||||||
|
This sequence of bytes is very specific. Replace 0x01 with 0x03 and you have
|
||||||
|
the regster write SFR, 0x05 reads the SerDes, 0x07 writes it. 0x09 reads
|
||||||
|
from the PHY and 0x0b writes to it.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
**************************************************************
|
||||||
|
* FUNCTION *
|
||||||
|
**************************************************************
|
||||||
|
undefined reg_read()
|
||||||
|
undefined <UNASSIGNED> <RETURN>
|
||||||
|
reg_read
|
||||||
|
CODE1::4da9 ab 07 MOV R3,BANK0_R7 = ??
|
||||||
|
CODE1::4dab aa 06 MOV R2,BANK0_R6 = ??
|
||||||
|
CODE1::4dad e4 CLR A
|
||||||
|
CODE1::4dae ff MOV R7,A
|
||||||
|
CODE1::4daf fe MOV R6,A
|
||||||
|
CODE1::4db0 fd MOV R5,A
|
||||||
|
CODE1::4db1 fc MOV R4,A
|
||||||
|
CODE1::4db2 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4db5 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4db8 e4 CLR A
|
||||||
|
CODE1::4db9 ff MOV R7,A
|
||||||
|
CODE1::4dba fe MOV R6,A
|
||||||
|
CODE1::4dbb fd MOV R5,A
|
||||||
|
CODE1::4dbc fc MOV R4,A
|
||||||
|
CODE1::4dbd 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4dc0 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4dc3 ea MOV A,R2
|
||||||
|
CODE1::4dc4 f5 a2 MOV SFR_A_ADDRH,A = ??
|
||||||
|
CODE1::4dc6 eb MOV A,R3
|
||||||
|
CODE1::4dc7 f5 a3 MOV SFR_A_ADDRL,A = ??
|
||||||
|
CODE1::4dc9 75 a0 01 MOV SFR_EXEC_GO,#0x1 <<<<<<<< Executes READ REG
|
||||||
|
LAB_CODE1__4dcc XREF[1]: CODE1::4dcf(j)
|
||||||
|
CODE1::4dcc af a1 MOV R7,SFR_EXEC_STATUS = ??
|
||||||
|
CODE1::4dce ef MOV A,R7
|
||||||
|
CODE1::4dcf 70 fb JNZ LAB_CODE1__4dcc
|
||||||
|
CODE1::4dd1 af a4 MOV R7,DAT_SFR_a4 = ??
|
||||||
|
CODE1::4dd3 fc MOV R4,A
|
||||||
|
CODE1::4dd4 fd MOV R5,A
|
||||||
|
CODE1::4dd5 fe MOV R6,A
|
||||||
|
CODE1::4dd6 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4dd9 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4ddc 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4ddf 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||||
|
CODE1::4de2 c0 00 PUSH BANK0_R0
|
||||||
|
CODE1::4de4 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4de7 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||||
|
CODE1::4dea 78 18 MOV R0,#0x18
|
||||||
|
CODE1::4dec 12 05 86 LCALL FUN_CODE_0586 undefined FUN_CODE_0586()
|
||||||
|
CODE1::4def d0 00 POP BANK0_R0
|
||||||
|
CODE1::4df1 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||||
|
CODE1::4df4 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4df7 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4dfa af a5 MOV R7,DAT_SFR_a5 = ??
|
||||||
|
CODE1::4dfc e4 CLR A
|
||||||
|
CODE1::4dfd fc MOV R4,A
|
||||||
|
CODE1::4dfe fd MOV R5,A
|
||||||
|
CODE1::4dff fe MOV R6,A
|
||||||
|
CODE1::4e00 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4e03 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4e06 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e09 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||||
|
CODE1::4e0c c0 00 PUSH BANK0_R0
|
||||||
|
CODE1::4e0e 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4e11 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||||
|
CODE1::4e14 78 10 MOV R0,#0x10
|
||||||
|
CODE1::4e16 12 05 86 LCALL FUN_CODE_0586 undefined FUN_CODE_0586()
|
||||||
|
CODE1::4e19 d0 00 POP BANK0_R0
|
||||||
|
CODE1::4e1b 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||||
|
CODE1::4e1e 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e21 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4e24 af a6 MOV R7,DAT_SFR_a6 = ??
|
||||||
|
CODE1::4e26 e4 CLR A
|
||||||
|
CODE1::4e27 fc MOV R4,A
|
||||||
|
CODE1::4e28 fd MOV R5,A
|
||||||
|
CODE1::4e29 fe MOV R6,A
|
||||||
|
CODE1::4e2a 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4e2d 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4e30 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e33 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||||
|
CODE1::4e36 c0 00 PUSH BANK0_R0
|
||||||
|
CODE1::4e38 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4e3b 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||||
|
CODE1::4e3e 78 08 MOV R0,#0x8
|
||||||
|
CODE1::4e40 12 05 86 LCALL FUN_CODE_0586 undefined FUN_CODE_0586()
|
||||||
|
CODE1::4e43 d0 00 POP BANK0_R0
|
||||||
|
CODE1::4e45 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||||
|
CODE1::4e48 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e4b 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4e4e af a7 MOV R7,DAT_SFR_a7 = ??
|
||||||
|
CODE1::4e50 e4 CLR A
|
||||||
|
CODE1::4e51 fc MOV R4,A
|
||||||
|
CODE1::4e52 fd MOV R5,A
|
||||||
|
CODE1::4e53 fe MOV R6,A
|
||||||
|
CODE1::4e54 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4e57 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4e5a 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e5d 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||||
|
CODE1::4e60 90 00 c9 MOV DPTR,#0xc9
|
||||||
|
CODE1::4e63 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||||
|
CODE1::4e66 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||||
|
CODE1::4e69 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e6c 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||||
|
CODE1::4e6f 90 00 c5 MOV DPTR,#0xc5
|
||||||
|
CODE1::4e72 02 05 dd LJMP read_xmem_32_b undefined read_xmem_32_b()
|
||||||
|
-- Flow Override: CALL_RETURN (CALL_TERMINATOR)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
INSERT ghidra_search_read_reg.png
|
||||||
|
|
||||||
|
Identify all the read and write function to the HW of the SoC using the find
|
||||||
|
in memory function.
|
||||||
|
|
||||||
|
The next task is to adapt the intercept routines in a special assembler
|
||||||
|
file. Don't worry, you do not need to understand assembler to do this.
|
||||||
|
|
||||||
|
```
|
||||||
|
; Assembler file to intercept register writes/reads and PHY writes/reads
|
||||||
|
; assemble with as31
|
||||||
|
; Compile with
|
||||||
|
; as31 -Fbyte -Orwintercept_zoerax_hg0402xg.hex rwintercept_zoerax_hg0402xg.asm
|
||||||
|
; ./injector zoerax_hg0402xg.bin RTLPlayground/rwintercept_zoerax_hg0402xg.hex zoerax_hg0402xg_patched.bin
|
||||||
|
; Start at 0x3b00, where there is always some space in BANK 0
|
||||||
|
.equ valptr, 0x199
|
||||||
|
|
||||||
|
|
||||||
|
.equ SFR_DATA_0, 0xa7
|
||||||
|
.equ SFR_DATA_8, 0xa6
|
||||||
|
.equ SFR_DATA_16, 0xa5
|
||||||
|
.equ SFR_DATA_24, 0xa4
|
||||||
|
|
||||||
|
; Intercept Register Write
|
||||||
|
.org 0x4d62
|
||||||
|
lcall reg_write
|
||||||
|
nop
|
||||||
|
|
||||||
|
; Intercept Register Read
|
||||||
|
.org 0x4dad
|
||||||
|
lcall reg_read_head
|
||||||
|
.org 0x4e6f
|
||||||
|
lcall reg_read_tail
|
||||||
|
|
||||||
|
; Intercept PHY write
|
||||||
|
.org 0x522c
|
||||||
|
lcall phy_write
|
||||||
|
|
||||||
|
; Intercept PHY read
|
||||||
|
.org 0x526f
|
||||||
|
lcall phy_read_head
|
||||||
|
.org 0x5295
|
||||||
|
ljmp phy_read_tail
|
||||||
|
|
||||||
|
; Intercept SDS write
|
||||||
|
.org 0x503c
|
||||||
|
lcall sds_write
|
||||||
|
nop
|
||||||
|
|
||||||
|
; Intercept SDS read
|
||||||
|
.org 0x5061
|
||||||
|
lcall sds_read_head
|
||||||
|
nop
|
||||||
|
.org 0x507b
|
||||||
|
ljmp sds_read_tail
|
||||||
|
|
||||||
|
;
|
||||||
|
; BEGIN actual code at unused end of BANK0
|
||||||
|
;
|
||||||
|
.org 0x3b00
|
||||||
|
|
||||||
|
;
|
||||||
|
; print the address of a register write. The address is in R6/R7. A and r4 can be scratched
|
||||||
|
;
|
||||||
|
reg_write:
|
||||||
|
mov a, #'R'
|
||||||
|
acall putc
|
||||||
|
|
||||||
|
mov a, r6
|
||||||
|
acall wbyte
|
||||||
|
|
||||||
|
mov a, r7
|
||||||
|
acall wbyte
|
||||||
|
|
||||||
|
mov a, #'-'
|
||||||
|
acall putc
|
||||||
|
|
||||||
|
mov dptr, #valptr
|
||||||
|
movx a, @dptr
|
||||||
|
acall wbyte
|
||||||
|
mov dptr, #valptr + 1
|
||||||
|
movx a, @dptr
|
||||||
|
acall wbyte
|
||||||
|
mov dptr, #valptr + 2
|
||||||
|
movx a, @dptr
|
||||||
|
acall wbyte
|
||||||
|
mov dptr, #valptr + 3
|
||||||
|
movx a, @dptr
|
||||||
|
acall wbyte
|
||||||
|
|
||||||
|
mov a, #' '
|
||||||
|
acall putc
|
||||||
|
|
||||||
|
mov a, r7
|
||||||
|
mov r5, a
|
||||||
|
mov a, r6
|
||||||
|
mov r4, a
|
||||||
|
ret
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
|
||||||
|
The full assembler file can be found here: XXXXXXXXXX
|
||||||
|
|
||||||
|
|
||||||
|
Once you have assembled the code, inject the bytes into the existing image,
|
||||||
|
creating a patched version:
|
||||||
|
```
|
||||||
|
$ as31 -Fbyte -Orwintercept_zoerax_hg0402xg.hex rwintercept_zoerax_hg0402xg.asm
|
||||||
|
Begin Pass #1
|
||||||
|
Begin Pass #2
|
||||||
|
./injector zoerax_hg0402xg.bin rwintercept_zoerax_hg0402xg.hex zoerax_hg0402xg_patched.bin
|
||||||
|
Input file size: 1048576
|
||||||
|
Bytes read:: 1048576
|
||||||
|
Patched 417 bytes.
|
||||||
|
```
|
||||||
|
|
||||||
|
Now flash `zoerax_hg0402xg_patched.bin` onto device.
|
||||||
|
|
||||||
|
Connect a serial adapter and plug in power. You will see:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ picocom -b 9600 /dev/ttyUSB0
|
||||||
|
picocom v3.1
|
||||||
|
|
||||||
|
port is : /dev/ttyUSB0
|
||||||
|
flowcontrol : none
|
||||||
|
baudrate is : 9600
|
||||||
|
parity is : none
|
||||||
|
databits are : 8
|
||||||
|
stopbits are : 1
|
||||||
|
escape is : C-a
|
||||||
|
local echo is : no
|
||||||
|
noinit is : no
|
||||||
|
noreset is : no
|
||||||
|
hangup is : no
|
||||||
|
nolock is : no
|
||||||
|
send_cmd is : sz -vv
|
||||||
|
receive_cmd is : rz -vv -E
|
||||||
|
imap is :
|
||||||
|
omap is :
|
||||||
|
emap is : crcrlf,delbs,
|
||||||
|
logfile is : none
|
||||||
|
initstring : none
|
||||||
|
exit_after is : not set
|
||||||
|
exit is : no
|
||||||
|
|
||||||
|
Type [C-a] [C-h] to see available commands
|
||||||
|
Terminal ready
|
||||||
|
[The printout only starts once the serial peripherial has been set up. Initially its timing is off:]
|
||||||
|
�.Ӛ�҂���������30-00005555 r6330:00005555 R6330-00005515 [RTL837X_REG_SMI_MAC_TYPE]
|
||||||
|
[RTL837X_REG_SMI_PORT_POLLING: ]
|
||||||
|
r6334:00000000 R6334-000000f0
|
||||||
|
r6454:00000000 R6454-00007000
|
||||||
|
|
||||||
|
[Read SoC-Revision]
|
||||||
|
r000c:00200000 R000c-002a0000 r000c:202a6818 r000c:202a6818 R000c-20206818
|
||||||
|
p001e.000d:ffff R02f8-0000ffff R02f4-0000fffa P000001.1e00000d:fffa p001e.000d:ffff p001e.000d:ffff
|
||||||
|
R02f8-0000ffff R02f4-0000fff0 P000001.1e00000d:fff0
|
||||||
|
|
||||||
|
[RTL837X_REG_LED_MODE being configured:]
|
||||||
|
r6520:0021fdb0 R6520-0021e7b0 r6520:0021e7b0 R6520-0021e6b0
|
||||||
|
|
||||||
|
[RLDP Leds configured via RTL837X_REG_LED_RLDP_X:]
|
||||||
|
r65f8:00000018 R65f8-0000001b R65fc-fffff000 r6600:00000000 R6600-0000000f
|
||||||
|
|
||||||
|
[RTL837X_REG_LED_GLB_IO_EN: ]
|
||||||
|
r65dc:5fffff00 R65dc-7fffff00 r65dc:7fffff00 R65dc-77ffff00
|
||||||
|
|
||||||
|
[RTL837X_PIN_MUX_0, makes serial go out of sync:]
|
||||||
|
r7f8c:30000000 R7f8c-30000000 r7f8c:300��.Ӛ�҂���������30-00005555
|
||||||
|
|
||||||
|
r6330:00005555 R6330-00005515 r6334:00000000 R6334-000000f0
|
||||||
|
|
||||||
|
r6454:00000000 R6454-00007000
|
||||||
|
|
||||||
|
[Read SoC-Revision (again)]
|
||||||
|
r000c:00200000 R000c-002a0000 r000c:202a6818 r000c:202a6818 R000c-20206818
|
||||||
|
p001e.000d:ffff R02f8-0000ffff R02f4-0000fffa P000001.1e00000d:fffa p001e.000d:ffff p001e.000d:ffff
|
||||||
|
R02f8-0000ffff R02f4-0000fff0
|
||||||
|
P000001.1e00000d:fff0
|
||||||
|
|
||||||
|
#### LED configuration ########
|
||||||
|
[RTL837X_REG_LED_MODE being configured (final):]
|
||||||
|
r6520:0021fdb0 R6520-0021e7b0 r6520:0021e7b0 R6520-0021e6b0
|
||||||
|
|
||||||
|
[More RTL837X_REG_LED_RLDP]
|
||||||
|
r65f8:00000018 R65f8-0000001b R65fc-fffff000 r6600:00000000 R6600-0000000f
|
||||||
|
|
||||||
|
[RTL837X_REG_LED_GLB_IO_EN]
|
||||||
|
r65dc:5fffff00 R65dc-7fffff00 r65dc:7fffff00 R65dc-77ffff00
|
||||||
|
|
||||||
|
[RTL837X_PIN_MUX_0
|
||||||
|
r7f8c:30000000 R7f8c-30000000 r7f8c:30000000 R7f8c-38000000
|
||||||
|
|
||||||
|
[RTL837X_LED_PORT_SET_SEL]
|
||||||
|
r654c:00000000 R654c-00010000
|
||||||
|
|
||||||
|
[RTL837X_REG_LED1_0_SET0]
|
||||||
|
R6548-00000141
|
||||||
|
|
||||||
|
[RTL837X_REG_LED3_2_SET0]
|
||||||
|
r6544:01411000 R6544-01410174
|
||||||
|
|
||||||
|
[RTL837X_REG_LED1_0_SET1]
|
||||||
|
r6540:00440070 R6540-0044017f
|
||||||
|
|
||||||
|
[RTL837X_REG_LED3_0_SET1]
|
||||||
|
r6528:00000000 R6528-000f0000
|
||||||
|
|
||||||
|
[SDS 0 being configure:]
|
||||||
|
r7b20:00000bff R7b20-000003ff r7b20:000003ff R7b20-000003fa r7b20:000003fa R7b20-000003fa
|
||||||
|
Q002110:4480 Q002113:0400 Q002118:6d02 Q00211b:424e Q00211d:0002 Q00361c:1390
|
||||||
|
Q003614:003f Q003610:0200 Q002e04:0080 Q002e06:0408 Q002e07:020d Q002e09:0601
|
||||||
|
Q002e0b:222c Q002e0c:a217 Q002e0d:fe40 Q002e15:f5c1 Q002e16:0443 Q002e1d:abb0
|
||||||
|
Q000612:5078 Q000706:9401 Q000708:9401 Q00070a:9401 Q00070c:9401 Q001f0b:0003
|
||||||
|
Q000603:c45c Q00061f:2100 q001f0b:0003 Q001f0b:000f q002000:0000 Q002000:0030
|
||||||
|
q002000:0030 Q002000:0010 q002000:0010 Q002000:0050 q002000:0050 Q002000:00d0
|
||||||
|
q002000:00d0 Q002000:0cd0 q002000:0cd0 Q002000:04d0 q002000:04d0 Q002000:04d0
|
||||||
|
q002000:04d0 Q002000:0cd0 q002000:0cd0 Q002000:00d0 q002000:00d0 Q002000:00d0
|
||||||
|
q002000:00d0 Q002000:0050 q002000:0050 Q002000:0010 q002000:0010 Q002000:0010
|
||||||
|
q002000:0010 Q002000:0030 q002000:0030 Q002000:0000 q001f00:0000 Q001f00:000b
|
||||||
|
q001f00:000b Q001f00:0000
|
||||||
|
|
||||||
|
[SDS 1 being configured]
|
||||||
|
r7b20:000003fa R7b20-000003fa r7b20:000003fa R7b20-0000035a r7b20:0000035a R7b20-0000035a
|
||||||
|
Q012110:4480 Q012113:0400 Q012118:6d02 Q01211b:424e Q01211d:0002 Q01361c:1390
|
||||||
|
Q013614:003f Q013610:0200 Q012e04:0080 Q012e06:0408 Q012e07:020d Q012e09:0601
|
||||||
|
Q012e0b:222c Q012e0c:a217 Q012e0d:fe40 Q012e15:f5c1 Q012e16:0443 Q012e1d:abb0
|
||||||
|
Q010612:5078 Q010706:9401 Q010708:9401 Q01070a:9401 Q01070c:9401 Q011f0b:0003
|
||||||
|
Q010603:c45c Q01061f:2100 q011f0b:0003 Q011f0b:000f q012000:0000 Q012000:0030
|
||||||
|
q012000:0030 Q012000:0010 q012000:0010 Q012000:0050 q012000:0050 Q012000:00d0
|
||||||
|
q012000:00d0 Q012000:0cd0 q012000:0cd0 Q012000:04d0 q012000:04d0 Q012000:04d0
|
||||||
|
q012000:04d0 Q012000:0cd0 q012000:0cd0 Q012000:00d0 q012000:00d0 Q012000:00d0
|
||||||
|
q012000:00d0 Q012000:0050 q012000:0050 Q012000:0010 q012000:0010 Q012000:0010
|
||||||
|
q012000:0010 Q012000:0030 q012000:0030 Q012000:0000 q011f00:0000 Q011f00:000b
|
||||||
|
q011f00:000b Q011f00:0000 q012100:4902 Q012100:4906 q013605:0000 Q013605:4000
|
||||||
|
Q011f02:001f q011f15:0096 q002100:4902 Q002100:4906 q003605:0000 Q003605:4000
|
||||||
|
Q001f02:001f q001f15:00a6
|
||||||
|
|
||||||
|
r0a90:000000f3 R0a90-000000fc P0000f0.1f00a610:2858 r5fd4:0002914a
|
||||||
|
R5fd4-001a914a r1538:00000e33 R1538-00000e37 r1538:00000e37 R1538-00000e37
|
||||||
|
r1538:00000e37 R1538-00000f37 r1638:00000e33 R1638-00000e37 r1638:00000e37
|
||||||
|
R1638-00000e37 r1638:00000e37 R1638-00000f37 r1738:00000e33 R1738-00000e37
|
||||||
|
r1738:00000e37 R1738-00000e37 r1738:00000e37 R1738-00000f37 r1838:00000e33
|
||||||
|
R1838-00000e37 r1838:00000e37 R1838-00000e37 r1838:00000e37 R1838-00000f37
|
||||||
|
r1938:00000e33 R1938-00000e37 r1938:00000e37 R1938-00000e37 r1938:00000e37
|
||||||
|
R1938-00000f37 r1a38:00000e33 R1a38-00000e37 r1a38:00000e37 R1a38-00000e37
|
||||||
|
r1a38:00000e37 R1a38-00000f37 r0b7c:000000d8 R0b7c-000000f8 R7124-00001050
|
||||||
|
R7128-00001050 R712c-00001050 R7130-00001050 R7134-00001050 R7138-00001050
|
||||||
|
R713c-00001050 R7140-00001050 R7144-00001050 R7148-00001050 r6040:00000030
|
||||||
|
R6040-00000031 p041f.a436:8195 P000010.1f00a436:0005 p041f.a438:02d4
|
||||||
|
P000010.1f00a436:801e p041f.a438:0000 p041f.b820:0000 P000010.1f00b820:0010
|
||||||
|
p041f.b800:00c0 p041f.a436:801e P000010.1f00a436:8023 p041f.a438:0000
|
||||||
|
P000010.1f00a438:1802 p041f.a436:8025
|
||||||
|
|
||||||
|
[PHY with ID 5 being patched] P000010.1f00a436:b82e p041f.a438:0000
|
||||||
|
P000010.1f00a438:0001 p041f.b820:0010 P000010.1f00b820:0090
|
||||||
|
P000010.1f00a436:a016 P000010.1f00a438:0000 P000010.1f00a436:a012
|
||||||
|
P000010.1f00a438:0000 P000010.1f00a436:a014 P000010.1f00a438:1800
|
||||||
|
P000010.1f00a438:8010 P000010.1f00a438:1800 P000010.1f00a438:8013
|
||||||
|
P000010.1f00a438:1800 P000010.1f00a438:8026 P000010.1f00a438:1800
|
||||||
|
P000010.1f00a438:802a P000010.1f00a438:1800 P000010.1f00a438:802e
|
||||||
|
P000010.1f00a438:1800 P000010.1f00a438:802e P000010.1f00a438:1800
|
||||||
|
P000010.1f00a438:802e P000010.1f00a438:1800 P000010.1f00a438:802e
|
||||||
|
...
|
||||||
|
```
|
||||||
|
Where:
|
||||||
|
```
|
||||||
|
r: read-reg
|
||||||
|
R: write-reg
|
||||||
|
q: read SDS
|
||||||
|
Q: write SDS
|
||||||
|
p: read PHY
|
||||||
|
P: write SDS
|
||||||
|
```
|
||||||
|
|
||||||
|
The LED configuration has been marked above. We now write exactly those registers
|
||||||
|
into the registers of `rtlplayground.c` on startup:
|
||||||
|
|
||||||
|
```
|
||||||
|
[...]
|
||||||
|
set_sys_led_state(SYS_LED_ON);
|
||||||
|
|
||||||
|
// [RTL837X_REG_LED_MODE being configured (final):]
|
||||||
|
// r6520:0021fdb0 R6520-0021e7b0 r6520:0021e7b0 R6520-0021e6b0
|
||||||
|
REG_SET(RTL837X_REG_LED_MODE, 0x0021e6b0);
|
||||||
|
|
||||||
|
// [More RTL837X_REG_LED_RLDP]
|
||||||
|
// r65f8:00000018 R65f8-0000001b R65fc-fffff000 r6600:00000000 R6600-0000000f
|
||||||
|
REG_SET(0x65f8, 0x0000001b);
|
||||||
|
REG_SET(0x65fc, 0xfffff000);
|
||||||
|
REG_SET(0x6600, 0x0000000f);
|
||||||
|
|
||||||
|
// [RTL837X_REG_LED_GLB_IO_EN]
|
||||||
|
// r65dc:5fffff00 R65dc-7fffff00 r65dc:7fffff00 R65dc-77ffff00
|
||||||
|
REG_SET(0x65dc, 0x77ffff00);
|
||||||
|
|
||||||
|
// [RTL837X_PIN_MUX_0
|
||||||
|
// r7f8c:30000000 R7f8c-30000000 r7f8c:30000000 R7f8c-38000000
|
||||||
|
REG_SET(0x7f8c, 0x38000000);
|
||||||
|
|
||||||
|
// [RTL837X_LED_PORT_SET_SEL]
|
||||||
|
// r654c:00000000 R654c-00010000
|
||||||
|
REG_SET(0x654c, 0x00010040);
|
||||||
|
|
||||||
|
// [RTL837X_REG_LED1_0_SET0]
|
||||||
|
// R6548-00000141
|
||||||
|
REG_SET(0x6548, 0x00000141);
|
||||||
|
|
||||||
|
// [RTL837X_REG_LED3_2_SET0]
|
||||||
|
// r6544:01411000 R6544-01410174
|
||||||
|
REG_SET(0x6544, 0x01410174);
|
||||||
|
|
||||||
|
// [RTL837X_REG_LED1_0_SET1]
|
||||||
|
// r6540:00440070 R6540-0044017f
|
||||||
|
REG_SET(0x6540, 0x0044017f);
|
||||||
|
|
||||||
|
// [RTL837X_REG_LED3_0_SET1]
|
||||||
|
// r6528:00000000 R6528-000f0000
|
||||||
|
REG_SET(0x6528, 0x000f0000);
|
||||||
|
|
||||||
|
cmd_editor_init();
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
|
||||||
|
Create an initial configuraiton for your device by copying over an existing one
|
||||||
|
for the same device type, i.e. same port-configuraiton and same SoC,
|
||||||
|
give it a new name. Make sure that the led_mux_custom and led_mux fields are not
|
||||||
|
used, because our device does not customize the LED muxes.
|
||||||
|
|
||||||
|
Compile and flash onto your device.
|
||||||
|
|
||||||
|
Now, boot the switch and issue the `leds`command, which will print out:
|
||||||
|
```
|
||||||
|
RTL837X_PIN_MUX_0: 0x38000000
|
||||||
|
RTL837X_REG_LED_GLB_IO_EN: 0x77ffff00
|
||||||
|
RTL837X_REG_LED1_0_SET0: 0x00000141
|
||||||
|
RTL837X_REG_LED3_2_SET0: 0x01410174
|
||||||
|
RTL837X_REG_LED1_0_SET1: 0x0044017f
|
||||||
|
RTL837X_REG_LED3_2_SET1: 0x18000040
|
||||||
|
RTL837X_REG_LED1_0_SET2: 0x00000000
|
||||||
|
RTL837X_REG_LED3_2_SET2: 0x00000000
|
||||||
|
RTL837X_REG_LED1_0_SET3: 0x00000000
|
||||||
|
RTL837X_REG_LED3_2_SET3: 0x00000000
|
||||||
|
RTL837X_REG_LED3_0_SET1: 0x000f0000
|
||||||
|
RTL837X_REG_LED3_0_SET3: 0x00000000
|
||||||
|
RTL837X_LED_PORT_SET_SEL: 0x00010040
|
||||||
|
RTL837X_REG_LED_GLB_MUX_1: 0x3fffffff
|
||||||
|
RTL837X_REG_LED_GLB_MUX_2: 0x0c3fffff
|
||||||
|
RTL837X_REG_LED_GLB_MUX_3: 0x1245038d
|
||||||
|
RTL837X_REG_LED_GLB_MUX_4: 0x19616554
|
||||||
|
RTL837X_REG_LED_GLB_MUX_5: 0x2079d71a
|
||||||
|
RTL837X_REG_LED_GLB_MUX_6: 0x000238a1
|
||||||
|
RTL837X_REG_LED_GLB_ACTIVE: 0x3ffbedff
|
||||||
|
RTL837X_REG_LED_MODE: 0x0021e6b0
|
||||||
|
LED pad Configuration:
|
||||||
|
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b
|
||||||
|
3f 3f 3f 3f 3f 3f 3f 3f 0f 0c 0d 0e 10 11 12 14 15 16 18 19 1a 1c 1d 1e 20 21 22 23
|
||||||
|
LED-set Configuration:
|
||||||
|
LED-ID 0 1 2 3
|
||||||
|
SET 0: 000141 000000 000174 000141
|
||||||
|
SET 1: 0f017f 000044 000040 001800
|
||||||
|
SET 2: 000000 000000 000000 000000
|
||||||
|
SET 3: 000000 000000 000000 000000
|
||||||
|
Port 3: SET 1: ( 2G5 TWO_1G 1G 500M 100M 10M LINK ACT 10G TWO_5G 5G TWO_2G5), ( 1G LINK), ( LINK), ( COL DUPLEX),
|
||||||
|
Port 4: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||||
|
Port 5: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||||
|
Port 6: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||||
|
Port 7: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||||
|
Port 8: SET 1: ( 2G5 TWO_1G 1G 500M 100M 10M LINK ACT 10G TWO_5G 5G TWO_2G5), ( 1G LINK), ( LINK), ( COL DUPLEX),
|
||||||
|
|
||||||
|
```
|
||||||
|
Together with the GPIO information, this will give you the following machine configuration:
|
||||||
|
```
|
||||||
|
_code const struct machine machine = {
|
||||||
|
.machine_name = "ZOERAX HG0402XG",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
|
||||||
|
// Left SFP port (5)
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
// Right SFP port (6)
|
||||||
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[1].sds = 0,
|
||||||
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
|
/* On Ethernet: Left led is orange, right green
|
||||||
|
* 100M and 1G give right led green with activity
|
||||||
|
* 2.5GBit adds solid left orange LED
|
||||||
|
* LEDs for the SFP-ports are the same as for the Ethernet ports
|
||||||
|
*/
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT
|
||||||
|
},
|
||||||
|
{ LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M |
|
||||||
|
LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
LEDS_LINK,
|
||||||
|
LEDS_COL | LEDS_DUPLEX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 100 KiB |
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
The switch can take part in a spanning tree (IEEE 802.1D / 802.1w) so that
|
The switch can take part in a spanning tree (IEEE 802.1D / 802.1w) so that
|
||||||
redundant links between bridges are blocked instead of forming a loop. The
|
redundant links between bridges are blocked instead of forming a loop. The
|
||||||
implementation elects a root bridge from the BPDUs it receives, promotes ports
|
implementation elects a root bridge from the BPDUs it receives, picks the
|
||||||
to forwarding once their listen period expires, ages the root out when it goes
|
cheapest path to it as the root port, blocks ports on which a better bridge is
|
||||||
silent, and blocks a port on which it sees its own BPDU.
|
already designated, promotes ports to forwarding once their listen period
|
||||||
|
expires, drops information a neighbour stopped sending, and blocks a port on
|
||||||
|
which it sees its own BPDU.
|
||||||
|
|
||||||
STP can be enabled and controlled via the web interface or the command line,
|
STP can be enabled and controlled via the web interface or the command line,
|
||||||
as follows:
|
as follows:
|
||||||
@@ -64,32 +66,6 @@ LACPDUs, delivered by forward, stopped arriving on port 3, and BPDUs sent into
|
|||||||
the same port, delivered by trap, kept arriving. A port that admits tagged
|
the same port, delivered by trap, kept arriving. A port that admits tagged
|
||||||
frames only therefore takes part in STP.
|
frames only therefore takes part in STP.
|
||||||
|
|
||||||
## Link aggregation
|
|
||||||
|
|
||||||
A LAG (Link Aggregation Group) is handled like an additional port by the STP
|
|
||||||
protocol, with its own timers and states. The switch devices support up to 4
|
|
||||||
LAGs, which are shown alongside the physical ports in the STP status. A group
|
|
||||||
carries its own path cost, priority, edge and guard settings, and gets its own
|
|
||||||
row on the Spanning Tree page.
|
|
||||||
|
|
||||||
```
|
|
||||||
stp lag 1 cost 10000 # the group decides, not its members
|
|
||||||
stp lag 1 edge off
|
|
||||||
```
|
|
||||||
|
|
||||||
LAGs are configured via the `lag` command. Once a port is a member of a LAG it
|
|
||||||
can no longer be configured individually for STP, so `stp port <n>` on a member
|
|
||||||
tells you which group to configure instead. Membership is re-read from the
|
|
||||||
aggregation registers once a second, so a group changing under LACP is picked
|
|
||||||
up without any coordination between the two.
|
|
||||||
|
|
||||||
The switch hardware does not handle STP state for a LAG as a whole. State
|
|
||||||
changes for the members have to be done by the firmware, updating every member
|
|
||||||
port, which is possible using a single register write. BPDUs go out through the
|
|
||||||
lowest member and carry the group's own port id. Losing one member of a live
|
|
||||||
LAG is not a topology change; the logical port only goes down with its last
|
|
||||||
link.
|
|
||||||
|
|
||||||
Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port:
|
Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port:
|
||||||
`00` disabled, `01` blocking, `10` learning, `11` forwarding. A port in
|
`00` disabled, `01` blocking, `10` learning, `11` forwarding. A port in
|
||||||
blocking forwards nothing between ports, but it still sends what the CPU
|
blocking forwards nothing between ports, but it still sends what the CPU
|
||||||
@@ -109,19 +85,83 @@ encodes. All configured values are in seconds:
|
|||||||
| `stp fwd <n>` | 15 | 4–30 |
|
| `stp fwd <n>` | 15 | 4–30 |
|
||||||
| `stp txhold <n>` | 6 | 1–10 |
|
| `stp txhold <n>` | 6 | 1–10 |
|
||||||
|
|
||||||
A port entering the tree spends `fwd` seconds in blocking before it forwards
|
802.1D also requires `2 * (fwd - 1) >= maxage >= 2 * (hello + 1)`. A
|
||||||
(an edge port skips the wait). Root information is discarded after `maxage`
|
command typed on the console or sent by the web page that would break it is
|
||||||
seconds without a BPDU, and the switch then reclaims the root role.
|
refused and the value stays as it was, so change the values in an order that
|
||||||
|
keeps the rule at every step (for a larger max age raise the forward delay
|
||||||
|
first). The web page shows the error, and a refused command is not recorded
|
||||||
|
in the command history, so saving the configuration does not pick it up. Lines of the saved configuration are taken one by one whatever their
|
||||||
|
order, and `stp on` checks the result: if the rule is broken it warns and
|
||||||
|
starts with 2/20/15 instead.
|
||||||
|
|
||||||
|
The values above are what the switch uses while it is the root. Otherwise it
|
||||||
|
takes max age and forward delay from the BPDUs on its root port, as 802.1D
|
||||||
|
requires, and passes them on in its own BPDUs with the message age one second
|
||||||
|
higher; the hello time stays its own.
|
||||||
|
|
||||||
|
A port entering the tree discards for one forward delay, then learns
|
||||||
|
addresses without forwarding for a second one, and only then forwards (an
|
||||||
|
edge port skips the wait). In RSTP mode on a point-to-point link
|
||||||
|
(`p2p auto` or `on`) it can go faster: a designated port that is still
|
||||||
|
discarding sets the proposal flag, and forwards as soon as the bridge on the
|
||||||
|
other side answers with an agreement. When the root port receives a proposal,
|
||||||
|
the switch first puts its other non-edge designated ports back to discarding
|
||||||
|
(they propose in turn), then forwards the root port and answers with an
|
||||||
|
agreement; this sync happens once per root port, later proposals are only
|
||||||
|
answered. An alternate or backup port that receives a proposal does the same
|
||||||
|
sync once for the information it holds and answers with an agreement in a
|
||||||
|
BPDU with the alternate role, so the bridge on the other side does not have
|
||||||
|
to wait out its timers; it stays discarding itself. An agreement is accepted
|
||||||
|
from a root or an alternate port on the other side. A new root port forwards at once, after every port that was root within
|
||||||
|
the last forward delay has been put back to discarding; such a recent root
|
||||||
|
port stays closed, even to an agreement, until that forward delay is over.
|
||||||
|
A new root port that was a backup port within the last two hello times does
|
||||||
|
not take the fast path and waits for its timers.
|
||||||
|
|
||||||
|
A designated port that hears worse information from a bridge that still
|
||||||
|
claims to be designated and learning or forwarding on the same link has a
|
||||||
|
dispute: usually one direction of the link is lost and the other bridge does
|
||||||
|
not hear this switch's BPDUs. The port goes back to discarding, and every
|
||||||
|
further such BPDU restarts its listen period, so it does not forward while
|
||||||
|
the dispute lasts.
|
||||||
|
|
||||||
|
With `stp version rstp` each port still talks 802.1D to a neighbour that
|
||||||
|
does: once a Config BPDU or TCN arrives and the migrate time (3 s since the
|
||||||
|
port came up or last switched) is over, the port sends Config BPDUs, uses
|
||||||
|
the 802.1D TC window and reports changes with TCN if it is the root port. An
|
||||||
|
RST BPDU after the migrate time switches it back, and so does a link that
|
||||||
|
comes up again or `stp port <n> mcheck`. Any worse information heard on a designated port, disputed or
|
||||||
|
not, is answered with a BPDU at once instead of at the next hello, so the
|
||||||
|
other bridge learns sooner that it is not the designated one. Information heard on a port stays
|
||||||
|
valid for three of the sender's hello times; a BPDU whose message age has
|
||||||
|
reached its max age is not used at all. When the root port's information
|
||||||
|
expires the switch moves to the next best port, or reclaims the root role if
|
||||||
|
there is none.
|
||||||
|
|
||||||
|
Among ports offering the same root, the lowest root path cost wins, then the
|
||||||
|
designated bridge, the designated port ID, and finally this switch's own port
|
||||||
|
ID. A worse BPDU from a different bridge does not replace what a port holds;
|
||||||
|
a worse one from the same designated bridge and port does.
|
||||||
|
The number in a port ID is the one on the front panel, and 101 and up for
|
||||||
|
the LAGs, so it matches the port labels on both ends of a link.
|
||||||
|
|
||||||
## Topology changes
|
## Topology changes
|
||||||
|
|
||||||
A change on a local non-edge port (the link coming or going, a port promoted
|
A topology change is detected when a non-edge port enters forwarding. That
|
||||||
to forwarding) flushes the addresses learned on it and sets the TC flag in
|
port, and every other forwarding non-edge port, then carries the TC flag in
|
||||||
our BPDUs for `maxage + fwd` seconds. A TC flag received in a BPDU is passed
|
its BPDUs for hello time plus one second (max age plus forward delay with
|
||||||
on: the switch flushes the other non-edge ports once and keeps the flag in
|
`stp version stp`), and each of the other ports flushes the addresses it
|
||||||
its own BPDUs until one hello after the last flagged frame, so the
|
learned. The root port takes part too: while its TC window runs it sends
|
||||||
notification crosses the switch instead of dying at it. A legacy TCN is
|
BPDUs toward the root, so the change reaches the rest of the network. With
|
||||||
acknowledged with TCA and then treated like a local change.
|
`stp version stp` the root port sends TCN instead, until a Config BPDU with
|
||||||
|
TCA comes back.
|
||||||
|
|
||||||
|
A TC flag received on a forwarding root or designated port is passed on the
|
||||||
|
same way to the other ports, not back to the port it came in on; a port that
|
||||||
|
is still discarding or learning drops it. A legacy TCN is acknowledged with
|
||||||
|
TCA and then treated like a received TC. A port that turns
|
||||||
|
alternate, loses its link, or is blocked for a loop flushes its own addresses
|
||||||
|
without raising a topology change, and an edge port never raises one.
|
||||||
|
|
||||||
## Bridge settings
|
## Bridge settings
|
||||||
|
|
||||||
@@ -129,6 +169,8 @@ acknowledged with TCA and then treated like a local change.
|
|||||||
stp prio <0-15> # bridge priority = n * 4096, default 8 (32768)
|
stp prio <0-15> # bridge priority = n * 4096, default 8 (32768)
|
||||||
stp version rstp|stp # RST BPDUs (default) or legacy Config BPDUs
|
stp version rstp|stp # RST BPDUs (default) or legacy Config BPDUs
|
||||||
stp hello|maxage|fwd|txhold <seconds>
|
stp hello|maxage|fwd|txhold <seconds>
|
||||||
|
stp pathcost long|short # automatic port costs, 802.1D-2004 (default) or 802.1D-1998
|
||||||
|
stp bpdu flood|filter # BPDUs while STP is off: pass them on (default) or drop them
|
||||||
```
|
```
|
||||||
|
|
||||||
The bridge with the lowest priority wins the root election; ties are broken by
|
The bridge with the lowest priority wins the root election; ties are broken by
|
||||||
@@ -136,6 +178,17 @@ the MAC address. If you do not want this switch to become the root of an
|
|||||||
existing network, give it a worse priority than the current root — `stp prio 15`
|
existing network, give it a worse priority than the current root — `stp prio 15`
|
||||||
(61440) is the usual "never me" value.
|
(61440) is the usual "never me" value.
|
||||||
|
|
||||||
|
A port without a configured cost takes it from its link speed. The long
|
||||||
|
method uses the 802.1D-2004 values (20000 for 1G, 2000 for 10G); the short
|
||||||
|
one the 802.1D-1998 table for bridges that still use 16-bit costs (100 for
|
||||||
|
10M, 19 for 100M, 4 for 1G, 2 for 10G, and 3 for 2.5G and 5G, which that
|
||||||
|
table does not list). All bridges in a network should use the same method.
|
||||||
|
|
||||||
|
`stp bpdu filter` keeps BPDUs from being passed between ports while STP is
|
||||||
|
off, instead of the default flooding that lets a surrounding spanning tree
|
||||||
|
run through the switch. It takes effect at once when STP is off, otherwise
|
||||||
|
when STP is turned off.
|
||||||
|
|
||||||
## Per-port settings
|
## Per-port settings
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -146,6 +199,7 @@ stp port <1-9> prio <0-240> # port priority, steps of 16
|
|||||||
stp port <1-9> guard none|bpdu|root
|
stp port <1-9> guard none|bpdu|root
|
||||||
stp port <1-9> filter on|off # neither send nor accept BPDUs
|
stp port <1-9> filter on|off # neither send nor accept BPDUs
|
||||||
stp port <1-9> p2p auto|on|off
|
stp port <1-9> p2p auto|on|off
|
||||||
|
stp port <1-9> mcheck # try RSTP again on a port that fell back to STP
|
||||||
```
|
```
|
||||||
|
|
||||||
**edge** — an edge port forwards immediately and does not trigger a
|
**edge** — an edge port forwards immediately and does not trigger a
|
||||||
@@ -162,26 +216,76 @@ claims a better priority.
|
|||||||
on the far side reacts badly to them (some unmanaged switches with loop
|
on the far side reacts badly to them (some unmanaged switches with loop
|
||||||
prevention cut the link) but you still want STP on the rest of the ports.
|
prevention cut the link) but you still want STP on the rest of the ports.
|
||||||
|
|
||||||
|
## Link aggregation
|
||||||
|
|
||||||
|
A LAG (Link Aggregation Group) is one port of the tree, with its own roles,
|
||||||
|
timers and states. The switch supports up to 4 LAGs; each one takes the place
|
||||||
|
of its member ports in the STP status and gets its own row on the Spanning
|
||||||
|
Tree page. A group carries its own path cost, priority, edge, guard and
|
||||||
|
point-to-point settings, and takes the same commands as a port:
|
||||||
|
|
||||||
|
```
|
||||||
|
stp lag <1-4> on|off|mcheck|edge|cost|prio|guard|filter|p2p ...
|
||||||
|
stp lag 1 cost 10000 # the group decides, not its members
|
||||||
|
```
|
||||||
|
|
||||||
|
LAGs are configured with the `lag` command. Once a port is a member of a LAG
|
||||||
|
it can no longer be configured on its own for STP, and `stp port <n>` on a
|
||||||
|
member names the group to configure instead. Membership is read from the
|
||||||
|
aggregation registers once a second, so a group changing under LACP is picked
|
||||||
|
up without any coordination between the two; a port that joins or leaves a
|
||||||
|
group, and the group itself, start over from discarding. The automatic path
|
||||||
|
cost of a group is the one of its lowest member that has a link.
|
||||||
|
|
||||||
|
The hardware keeps no STP state for a LAG as a whole, so every state change is
|
||||||
|
written to all member ports, in a single register write. BPDUs go out through
|
||||||
|
the lowest member that has a link and carry the group's own port id, and a
|
||||||
|
BPDU received on any member belongs to the group. Losing one member of a live
|
||||||
|
LAG is not a topology change; the group only goes down with its last link.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
The Spanning Tree page shows the elected root (priority and MAC), the path cost
|
The Spanning Tree page shows the elected root (priority and MAC), the path cost
|
||||||
to it, the root port, the topology-change counter and, per port, the live state
|
to it, the root port, the topology-change counter and the time since it last
|
||||||
read from the ASIC together with the configured options. The same data is
|
moved, the max age and forward
|
||||||
available as JSON:
|
delay in use (the root's, when this switch is not the root) and, per port, the
|
||||||
|
live state read from the ASIC, or "No link", together with the configured
|
||||||
|
options. For a port taking part in the tree it also shows the designated
|
||||||
|
bridge, port and cost, and whether it talks RSTP or 802.1D to its neighbour;
|
||||||
|
the Check button runs `stp port <n> mcheck`. The same data is available as
|
||||||
|
JSON:
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /stp.json
|
GET /stp.json
|
||||||
```
|
```
|
||||||
|
|
||||||
The `stp status` command prints the same view on the serial console.
|
The Counters section of the same page (or `/stpcnt.json`) shows per port the
|
||||||
|
BPDUs received and sent, those of them that carried the topology change flag
|
||||||
|
(TCNs included), and the time since the last BPDU arrived. The counters start
|
||||||
|
from zero with `stp on`, and `stp clear` resets them; the topology change
|
||||||
|
counter is not reset.
|
||||||
|
|
||||||
|
The `stp status` command prints the same view on the serial console. A port
|
||||||
|
is reported with one of the roles Root, Designated, Alternate, Backup or
|
||||||
|
Disabled; Disabled covers a port with STP turned off on it, one shut down by
|
||||||
|
BPDU guard and one without link.
|
||||||
|
|
||||||
|
The console's `age[s]` column (previously labelled `bpdu`) is the elapsed
|
||||||
|
time since the last BPDU, capped at 255 seconds; it is not a receive count.
|
||||||
|
Use the web counters or `/stpcnt.json` for full receive counts.
|
||||||
|
|
||||||
|
An own BPDU received back on another port can temporarily hold its sending
|
||||||
|
port in discarding, even if that sending port has received no BPDUs itself.
|
||||||
|
When the hold expires, auto-edge is restored if the sending port has remained
|
||||||
|
silent. A continuing loop keeps the hold active.
|
||||||
|
|
||||||
|
BPDUs shorter than their type allows, judged by the 802.3 length field, are
|
||||||
|
dropped: 7 bytes for a TCN, 38 for a Config BPDU and 39 for an RST BPDU,
|
||||||
|
LLC header included.
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
* One spanning-tree instance; no MSTP, no per-VLAN trees.
|
* One spanning-tree instance; no MSTP, no per-VLAN trees.
|
||||||
* No proposal/agreement handshake — an RST-capable neighbour will still
|
* A backup port, one that hears the BPDUs of another port of this switch,
|
||||||
converge, but through the timers rather than the fast transition.
|
is blocked and reported as Backup, but keeps sending BPDUs: loop detection
|
||||||
* Port roles are approximated: the root port and designated ports are
|
on that segment relies on them.
|
||||||
distinguished, alternate/backup are not.
|
|
||||||
* Topology changes propagate away from the root only: nothing is announced
|
|
||||||
on the root port (no TCN and no BPDUs at all), so bridges upstream rely on
|
|
||||||
their own detection.
|
|
||||||
@@ -4,44 +4,58 @@ The following devices have been tested and are fully working:
|
|||||||
| Brand | Type | Managed | PCB | Flash | Ports |
|
| Brand | Type | Managed | PCB | Flash | Ports |
|
||||||
|----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------|
|
|----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------|
|
||||||
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
||||||
|
| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
|
||||||
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
|
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
|
||||||
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
|
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
|
||||||
| Goalake | IG108 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
| Goalake | IG108 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||||
| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | ? | 8 + 1 |
|
| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 2M | 8 + 1 |
|
||||||
|
| GoodTop | GT-ST024M | Yes | [SWTG024AS-A V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 |
|
||||||
|
| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 |
|
||||||
| Hasivo | S1100WP_8GT_1SX_SE | Yes | [S1100WP_8GT_1SX_SE-V1.05](devices/HASIVO_S1100WP_8GT_1SX_SE.md) | 2M | 8 + 1 |
|
| Hasivo | S1100WP_8GT_1SX_SE | Yes | [S1100WP_8GT_1SX_SE-V1.05](devices/HASIVO_S1100WP_8GT_1SX_SE.md) | 2M | 8 + 1 |
|
||||||
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
|
||||||
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
|
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
|
||||||
|
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
||||||
|
| hongyavision | HYWS-SGT0204S | No | [2G5F4_10G2_V1.01](devices/2G5F4_10G2_V1.01.md) | 0.5M | 4 + 2 |
|
||||||
| hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 |
|
| hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 |
|
||||||
|
| Horaco | HC-SWTG124AS | Yes | [SWTG024AS-A-V2.0.1](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 2M | 4 + 2 |
|
||||||
| Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 |
|
| Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 |
|
||||||
| Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
| Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
||||||
|
| Horaco | HC-SWTGW218AS | Yes | [SWTG118AS-V2.1](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||||
| Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 |
|
| Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 |
|
||||||
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 |
|
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 |
|
||||||
| Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 |
|
| Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 |
|
||||||
| Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
|
| Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
|
||||||
| Keeplink | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
|
| keepLINK | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
|
||||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 |
|
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 |
|
||||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
|
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
|
||||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 |
|
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 |
|
||||||
|
| keepLINK | KP-9000-9XHP-X | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
||||||
|
| LIANGUO | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
|
||||||
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
|
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
|
||||||
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
| LIANGUO | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
||||||
| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
|
| MokerLink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
||||||
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
|
||||||
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
|
||||||
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
||||||
| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
|
| MokerLink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||||
| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
|
| MokerLink| 2G08110GSN | No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 0.5M | 8 + 1 |
|
||||||
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||||
|
| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
|
||||||
|
| RealHD | PSW8-25MG | Yes | [PCB-AFGW SWTG218ANS V2.0.2](devices/PCB-AFGW_SWTG218ANS_V2.0.2.md) | 2M | 8 + 1 |
|
||||||
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
||||||
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
|
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
|
||||||
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
| SICSOLINK| SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
|
| Sirivision | SR-S25G2109F | Yes | [S25G1109FP V1.3](devices/S25G1109FP_V1_3.md) | 2M | 8 + 1 |
|
||||||
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
|
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
|
||||||
|
| Sodola | SL902-SWTG024AS | Yes | [SWTG024AS-v2.1.0](devices/SWTG024AS-V2.1.0.md) | 2M | 4 + 2 |
|
||||||
| Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 |
|
| Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 |
|
||||||
| TrendNet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
|
| TRENDnet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
|
||||||
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
|
| XikeStor | SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
|
||||||
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||||
|
| XikeStor | SKS3200-4E2X | Yes | [SWTG024AS-v2.1.0](devices/SWTG024AS-V2.1.0.md) | 2M | 4 + 2 |
|
||||||
|
| YuanLey | YS25-0402 | No | [PCB-K0402WS-V1.0](devices/PCB-K0402WS-V1.0.md) | 2M | 4 + 2 |
|
||||||
|
| YuanLey | YS25-0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | 2M | 4 + 2 |
|
||||||
|
| YuanLey | YS25-0402M | Yes | [SIRIVISION_S25G2206FP_V1_1](devices/SIRIVISION_S25G2206FP_V1_1.md) | 2M | 4 + 2 |
|
||||||
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 |
|
| ZoeRax | HG0402XG | No | [HG0402XG_V1.1](devices/ZOERAX_HG0402XG_V1.1.md) | 1M | 4 + 2 |
|
||||||
|
|
||||||
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
|
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
|
||||||
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
|
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
|
||||||
|
|||||||
@@ -79,8 +79,11 @@ JSON polling of the visible section).
|
|||||||
computation no longer depends on uninitialised buffer content.
|
computation no longer depends on uninitialised buffer content.
|
||||||
- `version.h` is now written by a single atomic `printf` (change from
|
- `version.h` is now written by a single atomic `printf` (change from
|
||||||
upstream) instead of five separate `echo`s, so a parallel build
|
upstream) instead of five separate `echo`s, so a parallel build
|
||||||
(`make -j`) can no longer read a half-written copy. It stays in
|
(`make -j`) can no longer read a half-written copy. It depends on
|
||||||
`.PHONY` so it is regenerated on every build.
|
`FORCE`, so its recipe runs on every build, but the file is only
|
||||||
|
rewritten when its content changes. The minified copy in
|
||||||
|
`output/html_min/` is redone only when a web file, the list of web
|
||||||
|
files or `tools/minify.py` changes.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
html,body{height:100%}
|
html,body{height:100%}
|
||||||
body{
|
body{
|
||||||
font:14px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
font:14px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
||||||
background:var(--bg);color:var(--fg);display:flex;
|
background:var(--bg);color:var(--fg);display:flex;overflow:hidden;
|
||||||
}
|
}
|
||||||
button,input,select,textarea{font:inherit;color:var(--fg)}
|
button,input,select,textarea{font:inherit;color:var(--fg)}
|
||||||
a{color:var(--ac);text-decoration:none}
|
a{color:var(--ac);text-decoration:none}
|
||||||
@@ -55,11 +55,11 @@ a{color:var(--ac);text-decoration:none}
|
|||||||
#navfoot{padding:10px 16px;border-top:1px solid var(--bd);font-size:12px;color:var(--fg2)}
|
#navfoot{padding:10px 16px;border-top:1px solid var(--bd);font-size:12px;color:var(--fg2)}
|
||||||
#wrap{flex:1;min-width:0;display:flex;flex-direction:column}
|
#wrap{flex:1;min-width:0;display:flex;flex-direction:column}
|
||||||
#top{
|
#top{
|
||||||
display:flex;align-items:center;gap:10px;padding:10px 20px;
|
display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:8px 20px;
|
||||||
background:var(--panel);border-bottom:1px solid var(--bd);position:sticky;top:0;z-index:5;
|
background:var(--panel);border-bottom:1px solid var(--bd);position:sticky;top:0;z-index:5;
|
||||||
}
|
}
|
||||||
#burger{display:none;background:none;border:0;cursor:pointer;padding:4px}
|
#burger{display:none;background:none;border:0;cursor:pointer;padding:4px}
|
||||||
#ttitle{font-size:16px;font-weight:650;flex:1}
|
#ttitle{font-size:16px;font-weight:650;min-width:120px}
|
||||||
#dirty{
|
#dirty{
|
||||||
display:none;font-size:12px;font-weight:600;color:var(--warn);
|
display:none;font-size:12px;font-weight:600;color:var(--warn);
|
||||||
border:1px solid var(--warn);border-radius:20px;padding:2px 10px;
|
border:1px solid var(--warn);border-radius:20px;padding:2px 10px;
|
||||||
@@ -72,8 +72,8 @@ select.ctl,button.ctl{
|
|||||||
button.pri{background:var(--ac);color:var(--acfg);border-color:transparent;font-weight:600}
|
button.pri{background:var(--ac);color:var(--acfg);border-color:transparent;font-weight:600}
|
||||||
button.pri:hover,button.ctl:hover{filter:brightness(1.07)}
|
button.pri:hover,button.ctl:hover{filter:brightness(1.07)}
|
||||||
button:disabled{opacity:.45;cursor:default;filter:none}
|
button:disabled{opacity:.45;cursor:default;filter:none}
|
||||||
main{padding:18px 20px 40px;max-width:1400px;width:100%}
|
main{padding:18px 20px 40px;width:100%;overflow-y:auto;}
|
||||||
section.tab{display:none}
|
section.tab{display:none;max-width:1400px;}
|
||||||
section.tab.act{display:block}
|
section.tab.act{display:block}
|
||||||
.card{
|
.card{
|
||||||
background:var(--panel);border:1px solid var(--bd);border-radius:10px;
|
background:var(--panel);border:1px solid var(--bd);border-radius:10px;
|
||||||
@@ -89,9 +89,11 @@ table.t th{
|
|||||||
padding:6px 8px;border-bottom:1px solid var(--bd);white-space:nowrap;
|
padding:6px 8px;border-bottom:1px solid var(--bd);white-space:nowrap;
|
||||||
}
|
}
|
||||||
table.t th[data-sort]{cursor:pointer;user-select:none}
|
table.t th[data-sort]{cursor:pointer;user-select:none}
|
||||||
|
table.t th.num{text-align:right}
|
||||||
table.t td{padding:6px 8px;border-bottom:1px solid var(--bd);vertical-align:middle}
|
table.t td{padding:6px 8px;border-bottom:1px solid var(--bd);vertical-align:middle}
|
||||||
table.t tr:last-child td{border-bottom:0}
|
table.t tr:last-child td{border-bottom:0}
|
||||||
table.t tr:hover td{background:var(--sel)}
|
table.t tr:hover td{background:var(--sel)}
|
||||||
|
table.t tr.sel{background:var(--panel2); font-weight: bold;}
|
||||||
.num{font-variant-numeric:tabular-nums;text-align:right}
|
.num{font-variant-numeric:tabular-nums;text-align:right}
|
||||||
.scrollx{overflow-x:auto}
|
.scrollx{overflow-x:auto}
|
||||||
input.in,select.in,textarea.in{
|
input.in,select.in,textarea.in{
|
||||||
@@ -112,21 +114,31 @@ label.row span.lb{width:110px;flex:none;color:var(--fg2);font-size:13px}
|
|||||||
}
|
}
|
||||||
.switch input:checked+i{background:var(--ok)}
|
.switch input:checked+i{background:var(--ok)}
|
||||||
.switch input:checked+i:before{transform:translateX(15px)}
|
.switch input:checked+i:before{transform:translateX(15px)}
|
||||||
#strip{display:flex;gap:8px;flex-wrap:wrap;padding:4px 0 2px}
|
#strip{display:flex;gap:6px;flex:1;min-width:0;overflow-x:auto;scrollbar-width:thin}
|
||||||
|
.port:first-child{margin-left:auto}
|
||||||
|
.port:last-child{margin-right:auto}
|
||||||
.port{
|
.port{
|
||||||
width:46px;border:2px solid var(--bd);border-radius:7px;padding:5px 0 3px;
|
width:40px;border:2px solid var(--bd);border-radius:7px;padding:3px 0 2px;
|
||||||
text-align:center;cursor:pointer;background:var(--panel2);position:relative;
|
text-align:center;cursor:pointer;background:var(--panel2);position:relative;
|
||||||
}
|
}
|
||||||
.port.sfp{width:56px}
|
.port.sfp{width:50px}
|
||||||
.port .pn{font-weight:650;font-size:13px}
|
.port .pn{font-weight:650;font-size:12px}
|
||||||
.port .ps{font-size:10px;color:var(--fg2);display:block;line-height:1.2}
|
.port .ps{font-size:9px;color:var(--fg2);display:block;line-height:1.2}
|
||||||
.port .jack{
|
.port .jack{
|
||||||
display:block;width:18px;height:12px;margin:3px auto 2px;border-radius:2px;
|
display:block;width:21px;height:12px;margin:4px auto 2px;border-radius:2px;
|
||||||
border:2px solid var(--fg2);border-top-width:5px;opacity:.55;
|
border:2px solid var(--fg2);border-top-width:8px;opacity:.55;position:relative;
|
||||||
}
|
}
|
||||||
.port.sfp .jack{width:28px;height:10px;border-top-width:3px}
|
.port .jack:before{content:"";
|
||||||
|
position:absolute;bottom:100%;left:50%;transform:translateX(-50%);
|
||||||
|
width:6px;height:5px;margin-bottom:7px;border-radius: 1px 1px 0 0;
|
||||||
|
background-color:var(--fg2);
|
||||||
|
}
|
||||||
|
.port.sfp .jack{width:24px;height:16px;margin:0 auto 2px;border-top-width:5px}
|
||||||
|
.port.sfp .jack:before{width:10px;margin-bottom:2px;border-radius:0 0 1px 1px;background-color:var(--panel2)}
|
||||||
.port.up{border-color:var(--pc);background:color-mix(in srgb,var(--pc) 10%,var(--panel2))}
|
.port.up{border-color:var(--pc);background:color-mix(in srgb,var(--pc) 10%,var(--panel2))}
|
||||||
.port.up .jack{border-color:var(--pc);opacity:1}
|
.port.up .jack{border-color:var(--pc);opacity:1}
|
||||||
|
.port.up .jack:before{background-color:var(--pc)}
|
||||||
|
.port.up.sfp .jack:before{background-color:color-mix(in srgb,var(--pc) 10%,var(--panel2))}
|
||||||
.port.up .ps{color:var(--pc);font-weight:600}
|
.port.up .ps{color:var(--pc);font-weight:600}
|
||||||
.port.dis{opacity:.45;border-style:dashed}
|
.port.dis{opacity:.45;border-style:dashed}
|
||||||
.badge{font-size:11px;font-weight:600;border-radius:10px;padding:1px 8px;background:var(--panel2);color:var(--fg2)}
|
.badge{font-size:11px;font-weight:600;border-radius:10px;padding:1px 8px;background:var(--panel2);color:var(--fg2)}
|
||||||
@@ -183,6 +195,10 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
#ttitle{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
#ttitle{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||||
#dirty{padding:2px 7px}
|
#dirty{padding:2px 7px}
|
||||||
}
|
}
|
||||||
|
@media (max-width:720px){
|
||||||
|
#ttitle{flex:1}
|
||||||
|
#strip{order:3;flex-basis:100%}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
(function(){
|
(function(){
|
||||||
@@ -215,15 +231,13 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--fg)" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--fg)" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<span id="ttitle"></span>
|
<span id="ttitle"></span>
|
||||||
|
<div id="strip"></div>
|
||||||
<span id="dirty" data-i18n="hdr_dirty" data-i18n-t="hdr_dirty_t">unsaved changes</span>
|
<span id="dirty" data-i18n="hdr_dirty" data-i18n-t="hdr_dirty_t">unsaved changes</span>
|
||||||
<button class="ctl pri" id="saveBtn" data-i18n="hdr_save" data-i18n-t="hdr_save_t">Save to flash</button>
|
<button class="ctl" id="saveBtn" data-i18n="hdr_save" data-i18n-t="hdr_save_t">Save to flash</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<section class="tab act" id="tab-dash">
|
<section class="tab act" id="tab-dash">
|
||||||
<div class="card"><h2><span data-i18n="d_ports">Ports</span> <span class="hint" data-i18n="d_ports_h">click a port for details</span></h2>
|
|
||||||
<div id="strip"></div>
|
|
||||||
</div>
|
|
||||||
<div class="grid2">
|
<div class="grid2">
|
||||||
<div class="card"><h2 data-i18n="d_system">System</h2><table class="t" id="sysinfo"></table></div>
|
<div class="card"><h2 data-i18n="d_system">System</h2><table class="t" id="sysinfo"></table></div>
|
||||||
<div class="card"><h2><span data-i18n="d_traffic">Traffic</span> <span class="hint" data-i18n="d_traffic_h">packets/s, live</span></h2>
|
<div class="card"><h2><span data-i18n="d_traffic">Traffic</span> <span class="hint" data-i18n="d_traffic_h">packets/s, live</span></h2>
|
||||||
@@ -237,7 +251,7 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
<section class="tab" id="tab-ports">
|
<section class="tab" id="tab-ports">
|
||||||
<div class="card"><h2 data-i18n="pt_title">Port configuration</h2>
|
<div class="card"><h2 data-i18n="pt_title">Port configuration</h2>
|
||||||
<div class="scrollx"><table class="t" id="ptable">
|
<div class="scrollx"><table class="t" id="ptable">
|
||||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="c_name">Name</th><th data-i18n="c_link">Link</th><th data-i18n="pt_conn">Connected</th><th data-i18n="pt_speed">Speed</th><th data-i18n="c_enabled">Enabled</th><th data-i18n="pt_mtu">MTU</th><th></th></tr></thead>
|
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="c_name">Name</th><th data-i18n="c_link">Link</th><th data-i18n="pt_conn">Devices learned</th><th data-i18n="pt_speed">Speed</th><th data-i18n="c_enabled">Enabled</th><th data-i18n="pt_mtu">MTU</th><th></th></tr></thead>
|
||||||
<tbody></tbody></table></div>
|
<tbody></tbody></table></div>
|
||||||
<p class="small mut" style="margin-top:8px" data-i18n="pt_sfp_note">SFP speed is set per slot and is not saved in the startup config.</p>
|
<p class="small mut" style="margin-top:8px" data-i18n="pt_sfp_note">SFP speed is set per slot and is not saved in the startup config.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,6 +264,8 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
<p class="small mono" id="stpids">-</p>
|
<p class="small mono" id="stpids">-</p>
|
||||||
<div id="stpbridge" style="display:flex;gap:14px;flex-wrap:wrap;align-items:flex-end;margin-top:10px">
|
<div id="stpbridge" style="display:flex;gap:14px;flex-wrap:wrap;align-items:flex-end;margin-top:10px">
|
||||||
<label><span class="small mut" data-i18n="stp_version">Version</span><br><select class="in" id="stpver"><option value="rstp">RSTP</option><option value="stp" data-i18n="stp_v_stp">STP compatible</option></select></label>
|
<label><span class="small mut" data-i18n="stp_version">Version</span><br><select class="in" id="stpver"><option value="rstp">RSTP</option><option value="stp" data-i18n="stp_v_stp">STP compatible</option></select></label>
|
||||||
|
<label><span class="small mut" data-i18n="stp_pcs">Path cost</span><br><select class="in" id="stppcs"><option value="long" data-i18n="stp_pcs_long">Long (32 bit)</option><option value="short" data-i18n="stp_pcs_short">Short (16 bit)</option></select></label>
|
||||||
|
<label><span class="small mut" data-i18n="stp_bh">BPDUs while disabled</span><br><select class="in" id="stpbh"><option value="flood" data-i18n="stp_bh_flood">Flood</option><option value="filter" data-i18n="stp_bh_filter">Filter</option></select></label>
|
||||||
<label><span class="small mut" data-i18n="stp_prio">Bridge priority</span><br><select class="in" id="stpprio"></select></label>
|
<label><span class="small mut" data-i18n="stp_prio">Bridge priority</span><br><select class="in" id="stpprio"></select></label>
|
||||||
<label><span class="small mut" data-i18n="stp_hello">Hello [s]</span><br><input class="in sm" id="stphello" type="number" min="1" max="10"></label>
|
<label><span class="small mut" data-i18n="stp_hello">Hello [s]</span><br><input class="in sm" id="stphello" type="number" min="1" max="10"></label>
|
||||||
<label><span class="small mut" data-i18n="stp_maxage">Max age [s]</span><br><input class="in sm" id="stpmaxage" type="number" min="6" max="40"></label>
|
<label><span class="small mut" data-i18n="stp_maxage">Max age [s]</span><br><input class="in sm" id="stpmaxage" type="number" min="6" max="40"></label>
|
||||||
@@ -267,9 +283,14 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
</div>
|
</div>
|
||||||
<div class="card"><h2 data-i18n="stp_status">Port status</h2>
|
<div class="card"><h2 data-i18n="stp_status">Port status</h2>
|
||||||
<div class="scrollx"><table class="t" id="stpstat">
|
<div class="scrollx"><table class="t" id="stpstat">
|
||||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="stp_role">Role</th><th data-i18n="c_state">State</th><th data-i18n="stp_db">Designated bridge</th><th data-i18n="stp_dp">Designated port</th><th data-i18n="stp_dc">Designated cost</th><th data-i18n="stp_oedge">Oper. edge</th><th data-i18n="stp_op2p">Oper. P2P</th></tr></thead>
|
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="stp_role">Role</th><th data-i18n="c_state">State</th><th data-i18n="stp_db">Designated bridge</th><th data-i18n="stp_dp">Designated port</th><th data-i18n="stp_dc">Designated cost</th><th data-i18n="stp_oedge">Oper. edge</th><th data-i18n="stp_op2p">Oper. P2P</th><th data-i18n="stp_proto">Protocol</th><th></th></tr></thead>
|
||||||
<tbody></tbody></table></div>
|
<tbody></tbody></table></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card"><details id="stpcntd"><summary><h2 style="display:inline" data-i18n="stp_cnt">Counters</h2></summary>
|
||||||
|
<div class="scrollx"><table class="t" id="stpcnt">
|
||||||
|
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="stp_crx">BPDUs received</th><th data-i18n="stp_ctx">BPDUs sent</th><th data-i18n="stp_ctrx">TC received</th><th data-i18n="stp_cttx">TC sent</th><th data-i18n="stp_cage">Last BPDU [s]</th></tr></thead>
|
||||||
|
<tbody></tbody></table></div></details>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="tab" id="tab-stats">
|
<section class="tab" id="tab-stats">
|
||||||
@@ -281,27 +302,21 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="tab" id="tab-vlan">
|
<section class="tab" id="tab-vlan">
|
||||||
<div class="card"><h2><span data-i18n="v_title">VLANs</span> <span class="hint"><span data-i18n="v_mgmt">Management VLAN</span>: <span id="vmgmtcur">-</span></span></h2>
|
<div class="card"><h2><span data-i18n="v_title">VLANs</span><span id="vmgmtcur"></span></h2>
|
||||||
<div class="scrollx"><table class="t" id="vtable">
|
<div class="scrollx"><table class="t" id="vtable">
|
||||||
<thead><tr><th data-i18n="v_vid">VID</th><th data-i18n="c_name">Name</th><th data-i18n="v_members">Members</th><th data-i18n="v_tagged">Tagged</th><th data-i18n="v_untagged">Untagged</th><th data-i18n="v_pvid_on">PVID on</th><th></th></tr></thead>
|
<thead><tr><th data-i18n="v_vid">VID</th><th data-i18n="c_name">Name</th><th data-i18n="v_members">Members</th><th data-i18n="v_tagged">Tagged</th><th data-i18n="v_untagged">Untagged</th><th data-i18n="v_pvid_on">PVID on</th><th></th></tr></thead>
|
||||||
<tbody></tbody></table></div>
|
<tbody></tbody></table></div>
|
||||||
<p class="small mut" id="vempty" style="display:none;margin-top:6px" data-i18n="v_empty">No VLANs configured.</p>
|
<p class="small mut" id="vempty" style="display:none;margin-top:6px" data-i18n="v_empty">No VLANs configured.</p>
|
||||||
|
<button class="ctl pri" id="vlan_add" data-i18n="v_add">Add a new VLAN</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card"><h2 data-i18n="v_editor">VLAN editor</h2>
|
<div class="card"><h2><span data-i18n="v_editor">VLAN editor</span> <span class="hint" id="vtitle"></span></h2>
|
||||||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
|
<div><label class="row"><span class="lb" style="width:150px;" data-i18n="v_setmgmt_t"></span>
|
||||||
<label><span data-i18n="v_vid">VID</span> <input class="in sm" id="vvid" type="number" min="1" max="4094"></label>
|
<span class="switch"><input type="checkbox" id="vmgmtpromote"><i></i></span>
|
||||||
<label><span data-i18n="c_name">Name</span> <input class="in" id="vname" size="12" maxlength="15" data-i18n-p="v_optional"></label>
|
</label></div>
|
||||||
<button class="ctl" id="vload" data-i18n="c_load">Load</button>
|
|
||||||
<button class="ctl pri" id="vapply" data-i18n="c_apply">Apply</button>
|
|
||||||
<button class="ctl" id="vmgmt" data-i18n="v_setmgmt" data-i18n-t="v_setmgmt_t">Set as mgmt VLAN</button>
|
|
||||||
</div>
|
|
||||||
<div class="scrollx"><table class="t" id="vedit"><tbody></tbody></table></div>
|
<div class="scrollx"><table class="t" id="vedit"><tbody></tbody></table></div>
|
||||||
|
<div style="margin-top:10px"><button class="ctl pri" id="vapply" data-i18n="c_apply">Apply</button></div>
|
||||||
<p class="small mut" style="margin-top:6px" data-i18n="v_legend">U = untagged member, T = tagged member, - = not a member. PVID assigns this VLAN to untagged ingress traffic.</p>
|
<p class="small mut" style="margin-top:6px" data-i18n="v_legend">U = untagged member, T = tagged member, - = not a member. PVID assigns this VLAN to untagged ingress traffic.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card"><h2><span data-i18n="v_ingress">Ingress filtering</span> <span class="hint" data-i18n="v_ingress_h">write-only: the state is not readable from the switch</span></h2>
|
|
||||||
<div class="scrollx"><table class="t" id="ingress"><tbody></tbody></table></div>
|
|
||||||
<div style="margin-top:10px"><button class="ctl pri" id="ingapply" data-i18n="v_ing_apply">Apply ingress modes</button></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="tab" id="tab-l2">
|
<section class="tab" id="tab-l2">
|
||||||
@@ -433,8 +448,8 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
<p class="small mut" style="margin-top:8px" data-i18n="sy_time_note">The switch has no battery backed clock.</p>
|
<p class="small mut" style="margin-top:8px" data-i18n="sy_time_note">The switch has no battery backed clock.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card"><h2 data-i18n="sy_password">Admin password</h2>
|
<div class="card"><h2 data-i18n="sy_password">Admin password</h2>
|
||||||
<label class="row"><span class="lb" data-i18n="sy_newpw">New password</span><input class="in" id="sy-pw1" type="password" maxlength="20"></label>
|
<label class="row"><span class="lb" data-i18n="sy_newpw">New password</span><input class="in" id="sy-pw1" type="password" autocomplete="new-password" maxlength="20"></label>
|
||||||
<label class="row"><span class="lb" data-i18n="sy_repeat">Repeat</span><input class="in" id="sy-pw2" type="password" maxlength="20"></label>
|
<label class="row"><span class="lb" data-i18n="sy_repeat">Repeat</span><input class="in" id="sy-pw2" type="password" autocomplete="new-password" maxlength="20"></label>
|
||||||
<button class="ctl pri" id="sy-pwapply" style="margin-top:8px" data-i18n="sy_pwapply">Change password</button>
|
<button class="ctl pri" id="sy-pwapply" style="margin-top:8px" data-i18n="sy_pwapply">Change password</button>
|
||||||
<p class="small mut" style="margin-top:8px" data-i18n="sy_pw_note">Takes effect immediately; save to flash to keep it after reboot.</p>
|
<p class="small mut" style="margin-top:8px" data-i18n="sy_pw_note">Takes effect immediately; save to flash to keep it after reboot.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
#include "cmd_parser.h"
|
#include "cmd_parser.h"
|
||||||
#include "rtl837x_flash.h"
|
#include "rtl837x_flash.h"
|
||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
|
#include "sessions.h"
|
||||||
#include "html_data.h"
|
#include "html_data.h"
|
||||||
|
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#define SESSION_ID_LENGTH 12
|
|
||||||
#define SESSION_TIMEOUT_DEFAULT 200
|
#define SESSION_TIMEOUT_DEFAULT 200
|
||||||
|
|
||||||
/* Seconds of inactivity after which a session cookie stops validating.
|
/* Seconds of inactivity after which a session cookie stops validating.
|
||||||
@@ -55,8 +55,8 @@ __xdata uint8_t boundary[72];
|
|||||||
#define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384)
|
#define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384)
|
||||||
__xdata uint8_t config_upload;
|
__xdata uint8_t config_upload;
|
||||||
__xdata uint8_t config_buf[CONFIG_UPLOAD_BUF];
|
__xdata uint8_t config_buf[CONFIG_UPLOAD_BUF];
|
||||||
// bytes buffered in config_buf so far (config body, or a firmware part
|
// bytes buffered in config_buf so far (HTTP header, POST body, or a firmware
|
||||||
// header); accumulates across TCP segments
|
// part header); accumulates across TCP segments
|
||||||
__xdata uint16_t pre_acc;
|
__xdata uint16_t pre_acc;
|
||||||
__xdata uint8_t * __xdata content_type = 0;
|
__xdata uint8_t * __xdata content_type = 0;
|
||||||
__xdata uint8_t * __xdata session = 0;
|
__xdata uint8_t * __xdata session = 0;
|
||||||
@@ -75,13 +75,9 @@ __xdata uint8_t postbody_endpoint;
|
|||||||
__xdata uint16_t postbody_start;
|
__xdata uint16_t postbody_start;
|
||||||
|
|
||||||
__xdata char passwd[21];
|
__xdata char passwd[21];
|
||||||
// Set when a verified firmware upload awaits its response ACK, after
|
// Up to four logins at once, see sessions.c
|
||||||
// which the chip resets to apply the staged image
|
|
||||||
__xdata uint8_t fw_reset_pending;
|
|
||||||
__xdata char session_id[SESSION_ID_LENGTH + 1];
|
|
||||||
__xdata uint8_t authenticated;
|
__xdata uint8_t authenticated;
|
||||||
__xdata uint32_t now;
|
__xdata uint32_t now;
|
||||||
__xdata uint32_t last_session_use;
|
|
||||||
|
|
||||||
#define TSTATE_NONE 0
|
#define TSTATE_NONE 0
|
||||||
#define TSTATE_TX 1
|
#define TSTATE_TX 1
|
||||||
@@ -90,6 +86,7 @@ __xdata uint32_t last_session_use;
|
|||||||
#define TSTATE_POST 4
|
#define TSTATE_POST 4
|
||||||
#define TSTATE_MULTIPART 5
|
#define TSTATE_MULTIPART 5
|
||||||
#define TSTATE_POSTBODY 6
|
#define TSTATE_POSTBODY 6
|
||||||
|
#define TSTATE_HEADER 7
|
||||||
|
|
||||||
extern __xdata uint16_t crc_value;
|
extern __xdata uint16_t crc_value;
|
||||||
__xdata uint16_t crc_final;
|
__xdata uint16_t crc_final;
|
||||||
@@ -109,8 +106,9 @@ void httpd_init(void) __banked
|
|||||||
uip_listen(HTONS(80));
|
uip_listen(HTONS(80));
|
||||||
// Not through uip_conn: it only points at a connection while uIP is
|
// Not through uip_conn: it only points at a connection while uIP is
|
||||||
// handling one, and nothing has set it yet at init time.
|
// handling one, and nothing has set it yet at init time.
|
||||||
uip_conns[0].appstate.tstate = TSTATE_CLOSED;
|
for (uint8_t i = 0; i < UIP_CONNS; i++)
|
||||||
fw_reset_pending = 0; // xdata is not zeroed by the startup code
|
uip_conns[i].appstate.tstate = TSTATE_CLOSED;
|
||||||
|
session_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -345,38 +343,11 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
|||||||
|
|
||||||
read_reg_timer(&now);
|
read_reg_timer(&now);
|
||||||
|
|
||||||
if (session && session_id[0]) {
|
if (session)
|
||||||
if (now - last_session_use > session_timeout) {
|
session_check();
|
||||||
dbg_string("Session expired\n");
|
|
||||||
} else {
|
|
||||||
if (is_word_x(session, session_id)) {
|
|
||||||
authenticated = 1;
|
|
||||||
last_session_use = now;
|
|
||||||
} else {
|
|
||||||
dbg_string("Invalid session cookie!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate random HEX-chars at the buffer location.
|
|
||||||
*/
|
|
||||||
void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
|
|
||||||
{
|
|
||||||
uint8_t i = 0;
|
|
||||||
while (bytes) {
|
|
||||||
if (!i)
|
|
||||||
get_random_32();
|
|
||||||
b[--bytes] = itohex(sfr_data[i]);
|
|
||||||
if (!bytes) { break; }
|
|
||||||
b[--bytes] = itohex(sfr_data[i] >> 4 | sfr_data[i] << 4);
|
|
||||||
i = (i + 1) & 0x3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 0: body incomplete, 1: configuration stored, 2: malformed */
|
/* 0: body incomplete, 1: configuration stored, 2: malformed */
|
||||||
static uint8_t config_take(void)
|
static uint8_t config_take(void)
|
||||||
{
|
{
|
||||||
@@ -450,15 +421,9 @@ static uint8_t config_take(void)
|
|||||||
// unlike scan_header(), keeps no auth state, so it may run on every buffered segment
|
// unlike scan_header(), keeps no auth state, so it may run on every buffered segment
|
||||||
static uint16_t preamble_payload_start(uint16_t n)
|
static uint16_t preamble_payload_start(uint16_t n)
|
||||||
{
|
{
|
||||||
uint16_t pos;
|
// Skip the HTTP header separator retained by handle_post().
|
||||||
|
uint16_t pos = 4;
|
||||||
|
|
||||||
for (pos = 0; pos + 24 <= n; pos++) {
|
|
||||||
if (strstart(&config_buf[pos], "application/octet-stream"))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pos + 24 > n)
|
|
||||||
return 0;
|
|
||||||
pos += 24;
|
|
||||||
while (pos + 3 < n && !strstart(&config_buf[pos], "\r\n\r\n"))
|
while (pos + 3 < n && !strstart(&config_buf[pos], "\r\n\r\n"))
|
||||||
pos++;
|
pos++;
|
||||||
if (pos + 3 >= n)
|
if (pos + 3 >= n)
|
||||||
@@ -511,7 +476,7 @@ uint8_t stream_upload(void)
|
|||||||
"Content-Type: text/plain\r\n\r\n"
|
"Content-Type: text/plain\r\n\r\n"
|
||||||
"OK: checksum verified, rebooting\n");
|
"OK: checksum verified, rebooting\n");
|
||||||
// Reset once the response is fully ACKed
|
// Reset once the response is fully ACKed
|
||||||
fw_reset_pending = 1;
|
s->fw_reset_pending = 1;
|
||||||
} else {
|
} else {
|
||||||
print_string("Checksum incorrect! Aborting.\n");
|
print_string("Checksum incorrect! Aborting.\n");
|
||||||
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 33\r\n"
|
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 33\r\n"
|
||||||
@@ -539,9 +504,10 @@ uint8_t stream_upload(void)
|
|||||||
memcpy(flash_buf + write_len, boundary, bindex);
|
memcpy(flash_buf + write_len, boundary, bindex);
|
||||||
write_len += bindex;
|
write_len += bindex;
|
||||||
bindex = 0;
|
bindex = 0;
|
||||||
|
} else {
|
||||||
|
crc16_bank1(upload_settings.p + upload_settings.bptr);
|
||||||
|
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
||||||
}
|
}
|
||||||
crc16_bank1(upload_settings.p + upload_settings.bptr);
|
|
||||||
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
|
||||||
if (write_len >= FLASH_PAGE_SIZE) {
|
if (write_len >= FLASH_PAGE_SIZE) {
|
||||||
/* The staged image spans FIRMWARE_UPLOAD_START to twice that,
|
/* The staged image spans FIRMWARE_UPLOAD_START to twice that,
|
||||||
* the span check_and_flash_update_image() reads back. Nothing
|
* the span check_and_flash_update_image() reads back. Nothing
|
||||||
@@ -573,7 +539,6 @@ uint8_t stream_upload(void)
|
|||||||
memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len);
|
memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bindex = 0;
|
|
||||||
}
|
}
|
||||||
} while(1);
|
} while(1);
|
||||||
}
|
}
|
||||||
@@ -683,13 +648,10 @@ static void run_login_body(__xdata uint8_t *body)
|
|||||||
{
|
{
|
||||||
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
|
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
|
||||||
dbg_string("Password accepted!\n");
|
dbg_string("Password accepted!\n");
|
||||||
read_reg_timer(&last_session_use);
|
read_reg_timer(&now);
|
||||||
gen_random_hex_chars(session_id, SESSION_ID_LENGTH);
|
|
||||||
session_id[SESSION_ID_LENGTH] = NUL;
|
|
||||||
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
|
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
|
||||||
"Set-Cookie: session=");
|
"Set-Cookie: session=");
|
||||||
for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
|
session_new();
|
||||||
outbuf[slen++] = session_id[i];
|
|
||||||
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
dbg_string("Password invalid!\n");
|
dbg_string("Password invalid!\n");
|
||||||
@@ -746,7 +708,42 @@ static void post_body_continue(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handle_post(void)
|
|
||||||
|
/*
|
||||||
|
* Buffer an HTTP request header across TCP receive events. Stop copying at
|
||||||
|
* CRLFCRLF so any body bytes in the final segment stay in uip_appdata.
|
||||||
|
*
|
||||||
|
* Return the body offset in the current receive buffer, 0 while incomplete,
|
||||||
|
* or 0xffff after sending an error response.
|
||||||
|
*/
|
||||||
|
static uint16_t request_header_take(void)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < uip_len; i++) {
|
||||||
|
if (pre_acc + 1 >= CONFIG_UPLOAD_BUF) {
|
||||||
|
uip_conn->appstate.tstate = TSTATE_NONE;
|
||||||
|
send_bad_request();
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
config_buf[pre_acc++] = ((__xdata uint8_t *)uip_appdata)[i];
|
||||||
|
config_buf[pre_acc] = NUL;
|
||||||
|
if (pre_acc >= 4
|
||||||
|
&& config_buf[pre_acc - 4] == '\r'
|
||||||
|
&& config_buf[pre_acc - 3] == '\n'
|
||||||
|
&& config_buf[pre_acc - 2] == '\r'
|
||||||
|
&& config_buf[pre_acc - 1] == '\n') {
|
||||||
|
uip_conn->appstate.tstate = TSTATE_NONE;
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postbody_start = ticks;
|
||||||
|
uip_conn->appstate.tstate = TSTATE_HEADER;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_post(uint16_t body_off)
|
||||||
{
|
{
|
||||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
__xdata uint8_t *p = uip_appdata;
|
__xdata uint8_t *p = uip_appdata;
|
||||||
@@ -759,6 +756,9 @@ void handle_post(void)
|
|||||||
|
|
||||||
// Was the multipart header sent in multiple packets?
|
// Was the multipart header sent in multiple packets?
|
||||||
if (s->tstate != TSTATE_MULTIPART) {
|
if (s->tstate != TSTATE_MULTIPART) {
|
||||||
|
p = config_buf;
|
||||||
|
request_path = p + 6;
|
||||||
|
|
||||||
dbg_string("Is POST\n");
|
dbg_string("Is POST\n");
|
||||||
p += 5; // Skip post
|
p += 5; // Skip post
|
||||||
// Find end of request path
|
// Find end of request path
|
||||||
@@ -772,9 +772,12 @@ void handle_post(void)
|
|||||||
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
||||||
if (!*p || !content_type) {
|
if (!*p || !content_type) {
|
||||||
dbg_string("Bad Request!\n");
|
dbg_string("Bad Request!\n");
|
||||||
send_not_found();
|
send_bad_request();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre_acc = 0;
|
||||||
|
p = (__xdata uint8_t *)uip_appdata + body_off;
|
||||||
if (is_word(request_path, "upload")) {
|
if (is_word(request_path, "upload")) {
|
||||||
if (!authenticated) {
|
if (!authenticated) {
|
||||||
send_unauthorized();
|
send_unauthorized();
|
||||||
@@ -800,7 +803,10 @@ void handle_post(void)
|
|||||||
dbg_string("Configuration upload\n");
|
dbg_string("Configuration upload\n");
|
||||||
verify_crc = 0;
|
verify_crc = 0;
|
||||||
config_upload = 1;
|
config_upload = 1;
|
||||||
pre_acc = 0;
|
// config_take() matches CRLF-prefixed delimiters, including the first.
|
||||||
|
config_buf[0] = '\r';
|
||||||
|
config_buf[1] = '\n';
|
||||||
|
pre_acc = 2;
|
||||||
}
|
}
|
||||||
// Check for other POST requests, which are not multipart, below
|
// Check for other POST requests, which are not multipart, below
|
||||||
} else {
|
} else {
|
||||||
@@ -824,7 +830,6 @@ void handle_post(void)
|
|||||||
handle_firmware_fragment(p);
|
handle_firmware_fragment(p);
|
||||||
return;
|
return;
|
||||||
} else if (is_word(request_path, "cmd")) {
|
} else if (is_word(request_path, "cmd")) {
|
||||||
p += 4;
|
|
||||||
if (!authenticated) {
|
if (!authenticated) {
|
||||||
send_unauthorized();
|
send_unauthorized();
|
||||||
return;
|
return;
|
||||||
@@ -843,7 +848,6 @@ void handle_post(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p += 4;
|
|
||||||
postbody_endpoint = POSTBODY_LOGIN;
|
postbody_endpoint = POSTBODY_LOGIN;
|
||||||
if (!post_body_take(p))
|
if (!post_body_take(p))
|
||||||
return;
|
return;
|
||||||
@@ -874,9 +878,10 @@ void httpd_appcall(void)
|
|||||||
print_byte(s->tstate);
|
print_byte(s->tstate);
|
||||||
write_char(' ');
|
write_char(' ');
|
||||||
#endif
|
#endif
|
||||||
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
|
if(uip_connected()) {
|
||||||
dbg_string("Connected...\n");
|
dbg_string("Connected...\n");
|
||||||
s->tstate = TSTATE_NONE;
|
s->tstate = TSTATE_NONE;
|
||||||
|
s->fw_reset_pending = 0; // explicitly initialize reused XDATA appstate
|
||||||
} else if (uip_closed()) {
|
} else if (uip_closed()) {
|
||||||
dbg_string("Connection closed\n");
|
dbg_string("Connection closed\n");
|
||||||
s->tstate = TSTATE_CLOSED;
|
s->tstate = TSTATE_CLOSED;
|
||||||
@@ -890,9 +895,9 @@ void httpd_appcall(void)
|
|||||||
dbg_string("Closing because everything has been transmitted\n");
|
dbg_string("Closing because everything has been transmitted\n");
|
||||||
uip_close();
|
uip_close();
|
||||||
s->tstate = TSTATE_CLOSED;
|
s->tstate = TSTATE_CLOSED;
|
||||||
} else if (s->tstate == TSTATE_POSTBODY
|
} else if ((s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_HEADER)
|
||||||
&& (uint16_t)ticks - postbody_start > POSTBODY_TIMEOUT) {
|
&& (uint16_t)ticks - postbody_start > POSTBODY_TIMEOUT) {
|
||||||
dbg_string("Body never arrived\n");
|
dbg_string("HTTP request never completed\n");
|
||||||
uip_abort();
|
uip_abort();
|
||||||
s->tstate = TSTATE_CLOSED;
|
s->tstate = TSTATE_CLOSED;
|
||||||
}
|
}
|
||||||
@@ -928,7 +933,7 @@ void httpd_appcall(void)
|
|||||||
cont_len -= slen;
|
cont_len -= slen;
|
||||||
cont_addr += slen;
|
cont_addr += slen;
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
} else if (fw_reset_pending) {
|
} else if (s->fw_reset_pending) {
|
||||||
// The upload verdict has been fully ACKed by the client;
|
// The upload verdict has been fully ACKed by the client;
|
||||||
// now it is safe to reset and apply the staged image
|
// now it is safe to reset and apply the staged image
|
||||||
print_string("Resetting to apply update\n");
|
print_string("Resetting to apply update\n");
|
||||||
@@ -955,6 +960,7 @@ void httpd_appcall(void)
|
|||||||
cont_len = 0;
|
cont_len = 0;
|
||||||
dbg_char('<'); dbg_short(uip_len); dbg_char('\n');
|
dbg_char('<'); dbg_short(uip_len); dbg_char('\n');
|
||||||
__xdata uint8_t *p = uip_appdata;
|
__xdata uint8_t *p = uip_appdata;
|
||||||
|
uint16_t body_off = 0;
|
||||||
// Mark end of request header with \0
|
// Mark end of request header with \0
|
||||||
p[uip_len] = 0;
|
p[uip_len] = 0;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -963,9 +969,21 @@ void httpd_appcall(void)
|
|||||||
dbg_char('\n');
|
dbg_char('\n');
|
||||||
#endif
|
#endif
|
||||||
p = uip_appdata;
|
p = uip_appdata;
|
||||||
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART
|
if (s->tstate != TSTATE_MULTIPART && s->tstate != TSTATE_POSTBODY) {
|
||||||
|| s->tstate == TSTATE_POSTBODY) {
|
if (s->tstate != TSTATE_HEADER)
|
||||||
handle_post();
|
pre_acc = 0;
|
||||||
|
body_off = request_header_take();
|
||||||
|
if (!body_off) {
|
||||||
|
uip_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (body_off == 0xffff)
|
||||||
|
goto do_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->tstate == TSTATE_MULTIPART || s->tstate == TSTATE_POSTBODY
|
||||||
|
|| is_word(config_buf, "POST")) {
|
||||||
|
handle_post(body_off);
|
||||||
// If this is an ongoing post stream, then wait for the next packet
|
// If this is an ongoing post stream, then wait for the next packet
|
||||||
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART
|
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART
|
||||||
|| s->tstate == TSTATE_POSTBODY) {
|
|| s->tstate == TSTATE_POSTBODY) {
|
||||||
@@ -975,12 +993,11 @@ void httpd_appcall(void)
|
|||||||
goto do_send;
|
goto do_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only expect a GET request here.
|
p = config_buf;
|
||||||
if (!is_word(p, "GET")) {
|
if (!is_word(p, "GET")) {
|
||||||
send_bad_request();
|
send_bad_request();
|
||||||
goto do_send;
|
goto do_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg_string("GET request ");
|
dbg_string("GET request ");
|
||||||
p += 4;
|
p += 4;
|
||||||
scan_header(p);
|
scan_header(p);
|
||||||
@@ -1038,6 +1055,8 @@ void httpd_appcall(void)
|
|||||||
send_lldp();
|
send_lldp();
|
||||||
} else if (is_word(q, "/lacp.json")) {
|
} else if (is_word(q, "/lacp.json")) {
|
||||||
send_lacp();
|
send_lacp();
|
||||||
|
} else if (is_word(q, "/stpcnt.json")) {
|
||||||
|
send_stp_counters();
|
||||||
} else if (is_word(q, "/vlanlist")) {
|
} else if (is_word(q, "/vlanlist")) {
|
||||||
send_vlanlist();
|
send_vlanlist();
|
||||||
} else if (is_word(q, "/config")) {
|
} else if (is_word(q, "/config")) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
for each TCP connection. */
|
for each TCP connection. */
|
||||||
typedef struct httpd_state {
|
typedef struct httpd_state {
|
||||||
uint8_t tstate;
|
uint8_t tstate;
|
||||||
|
uint8_t fw_reset_pending;
|
||||||
} uip_tcp_appstate_t;
|
} uip_tcp_appstate_t;
|
||||||
|
|
||||||
/* Finally we define the application function to be called by uIP. */
|
/* Finally we define the application function to be called by uIP. */
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ void send_vlan(uint16_t vlan)
|
|||||||
}
|
}
|
||||||
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
||||||
uint16_t pvid_mask = 0;
|
uint16_t pvid_mask = 0;
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
if (port_pvid_get(i) == vlan)
|
if (port_pvid_get(i) == vlan)
|
||||||
pvid_mask |= (1 << i);
|
pvid_mask |= (1 << i);
|
||||||
}
|
}
|
||||||
@@ -357,7 +357,7 @@ void send_vlan(uint16_t vlan)
|
|||||||
bool send_counters(uint8_t phys_port)
|
bool send_counters(uint8_t phys_port)
|
||||||
{
|
{
|
||||||
uint8_t phys_port_idx = phys_port - 1;
|
uint8_t phys_port_idx = phys_port - 1;
|
||||||
if (phys_port_idx > (machine.max_port - machine.min_port))
|
if (phys_port_idx > (MACHINE_MAX_PORT - MACHINE_MIN_PORT))
|
||||||
goto err;
|
goto err;
|
||||||
uint8_t log_port = machine.phys_to_log_port[phys_port_idx];
|
uint8_t log_port = machine.phys_to_log_port[phys_port_idx];
|
||||||
|
|
||||||
@@ -600,143 +600,6 @@ void send_lag(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static __xdata uint32_t pi_u32;
|
|
||||||
static __xdata uint8_t pi_prio, pi_ext;
|
|
||||||
static __xdata uint8_t * __xdata pi_mac;
|
|
||||||
|
|
||||||
|
|
||||||
static void u32hex_html(void)
|
|
||||||
{
|
|
||||||
__xdata uint8_t *b = (__xdata uint8_t *)&pi_u32;
|
|
||||||
byte_to_html(b[3]);
|
|
||||||
byte_to_html(b[2]);
|
|
||||||
byte_to_html(b[1]);
|
|
||||||
byte_to_html(b[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void bridge_to_html(void)
|
|
||||||
{
|
|
||||||
byte_to_html(pi_prio);
|
|
||||||
byte_to_html(pi_ext);
|
|
||||||
for (uint8_t i = 0; i < 6; i++)
|
|
||||||
byte_to_html(pi_mac[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_stp(void)
|
|
||||||
{
|
|
||||||
uint8_t i, j, st, dsg;
|
|
||||||
|
|
||||||
dbg_string("send_stp called\n");
|
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
|
||||||
|
|
||||||
slen += strtox(outbuf + slen, "{\"on\":");
|
|
||||||
bool_to_html(stp_enabled);
|
|
||||||
slen += strtox(outbuf + slen, ",\"rstp\":");
|
|
||||||
bool_to_html(stp_rstp);
|
|
||||||
slen += strtox(outbuf + slen, ",\"prio\":");
|
|
||||||
itoa_html(stp_prio >> 4);
|
|
||||||
slen += strtox(outbuf + slen, ",\"hello\":");
|
|
||||||
itoa_html(stp_hello_s);
|
|
||||||
slen += strtox(outbuf + slen, ",\"maxage\":");
|
|
||||||
itoa_html(stp_maxage_s);
|
|
||||||
slen += strtox(outbuf + slen, ",\"fwd\":");
|
|
||||||
itoa_html(stp_fwddelay_s);
|
|
||||||
slen += strtox(outbuf + slen, ",\"txhold\":");
|
|
||||||
itoa_html(stp_txhold);
|
|
||||||
slen += strtox(outbuf + slen, ",\"rootPrio\":\"");
|
|
||||||
byte_to_html(root_bridge.prio);
|
|
||||||
byte_to_html(root_bridge.ext);
|
|
||||||
slen += strtox(outbuf + slen, "\",\"rootMac\":\"");
|
|
||||||
for (j = 0; j < 6; j++)
|
|
||||||
byte_to_html(root_bridge.mac[j]);
|
|
||||||
slen += strtox(outbuf + slen, "\",\"myMac\":\"");
|
|
||||||
for (j = 0; j < 6; j++)
|
|
||||||
byte_to_html(uip_ethaddr.addr[j]);
|
|
||||||
slen += strtox(outbuf + slen, "\",\"cost\":\"");
|
|
||||||
byte_to_html(root_bridge_cost >> 24);
|
|
||||||
byte_to_html(root_bridge_cost >> 16);
|
|
||||||
byte_to_html(root_bridge_cost >> 8);
|
|
||||||
byte_to_html(root_bridge_cost);
|
|
||||||
slen += strtox(outbuf + slen, "\",\"weRoot\":");
|
|
||||||
bool_to_html(stp_root_port == 0xff ? 1 : 0);
|
|
||||||
slen += strtox(outbuf + slen, ",\"rootPort\":");
|
|
||||||
j = stp_root_port;
|
|
||||||
if (j != 0xff && j >= STP_LAG_BASE) {
|
|
||||||
j = 0;
|
|
||||||
while (j < STP_LAG_BASE && !((stp_lag_mask[stp_root_port - STP_LAG_BASE] >> j) & 1))
|
|
||||||
j++;
|
|
||||||
if (j >= STP_LAG_BASE)
|
|
||||||
j = 0;
|
|
||||||
}
|
|
||||||
itoa_html(j == 0xff ? 0 : machine.log_to_phys_port[j]);
|
|
||||||
slen += strtox(outbuf + slen, ",\"tc\":\"");
|
|
||||||
byte_to_html(stp_tc_count >> 8);
|
|
||||||
byte_to_html(stp_tc_count);
|
|
||||||
slen += strtox(outbuf + slen, "\",\"ports\":[");
|
|
||||||
reg_read_m(RTL837X_MSTP_STATES);
|
|
||||||
for (i = 0; i < STP_ENTITIES; i++) {
|
|
||||||
if (i < STP_LAG_BASE && (i < machine.min_port || i > machine.max_port))
|
|
||||||
continue;
|
|
||||||
if (i < STP_LAG_BASE && stp_ent_of[i] != i)
|
|
||||||
continue;
|
|
||||||
if (i >= STP_LAG_BASE && !stp_lag_mask[i - STP_LAG_BASE])
|
|
||||||
continue;
|
|
||||||
slen += strtox(outbuf + slen, "{\"p\":");
|
|
||||||
itoa_html(i < STP_LAG_BASE ? machine.log_to_phys_port[i] : 0);
|
|
||||||
slen += strtox(outbuf + slen, ",\"lag\":");
|
|
||||||
itoa_html(i < STP_LAG_BASE ? 0 : i - STP_LAG_BASE + 1);
|
|
||||||
slen += strtox(outbuf + slen, ",\"mbr\":");
|
|
||||||
itoa16_html(i < STP_LAG_BASE ? 0 : stp_lag_mask[i - STP_LAG_BASE]);
|
|
||||||
slen += strtox(outbuf + slen, ",\"st\":");
|
|
||||||
j = i;
|
|
||||||
if (i >= STP_LAG_BASE) {
|
|
||||||
j = 0;
|
|
||||||
while (j < STP_LAG_BASE && !((stp_lag_mask[i - STP_LAG_BASE] >> j) & 1))
|
|
||||||
j++;
|
|
||||||
if (j >= STP_LAG_BASE)
|
|
||||||
j = 0;
|
|
||||||
}
|
|
||||||
st = (sfr_data[3 - (j >> 2)] >> ((j << 1) & 0x7)) & 0x3;
|
|
||||||
itoa_html(st);
|
|
||||||
slen += strtox(outbuf + slen, ",\"role\":");
|
|
||||||
if (!(stp_pflags[i] & STP_PF_ENABLED) || (stp_pflags[i] & STP_PF_TRIPPED))
|
|
||||||
itoa_html(0);
|
|
||||||
else if (i == stp_root_port)
|
|
||||||
itoa_html(1);
|
|
||||||
else if (st == 3)
|
|
||||||
itoa_html(2);
|
|
||||||
else
|
|
||||||
itoa_html(3);
|
|
||||||
slen += strtox(outbuf + slen, ",\"f\":");
|
|
||||||
itoa_html(stp_pflags[i]);
|
|
||||||
slen += strtox(outbuf + slen, ",\"pc\":\"");
|
|
||||||
pi_u32 = stp_pcost[i]; u32hex_html();
|
|
||||||
slen += strtox(outbuf + slen, "\",\"prio\":");
|
|
||||||
itoa_html(stp_pprio[i]);
|
|
||||||
slen += strtox(outbuf + slen, ",\"p2\":");
|
|
||||||
itoa_html(stp_pp2p[i]);
|
|
||||||
dsg = stp_dpid[i] && stp_bpdu_age[i] < (uint16_t)stp_maxage_s * STP_HZ;
|
|
||||||
slen += strtox(outbuf + slen, ",\"db\":\"");
|
|
||||||
if (dsg) {
|
|
||||||
pi_prio = stp_dbridge[i].prio; pi_ext = stp_dbridge[i].ext;
|
|
||||||
pi_mac = stp_dbridge[i].mac;
|
|
||||||
} else {
|
|
||||||
pi_prio = stp_prio; pi_ext = 0;
|
|
||||||
pi_mac = uip_ethaddr.addr;
|
|
||||||
}
|
|
||||||
bridge_to_html();
|
|
||||||
slen += strtox(outbuf + slen, "\",\"dp\":\"");
|
|
||||||
byte_to_html(dsg ? (stp_dpid[i] >> 8) : stp_pprio[i]);
|
|
||||||
byte_to_html(dsg ? stp_dpid[i] : (i + 1));
|
|
||||||
slen += strtox(outbuf + slen, "\",\"dc\":\"");
|
|
||||||
pi_u32 = dsg ? stp_dcost[i] : root_bridge_cost; u32hex_html();
|
|
||||||
slen += strtox(outbuf + slen, "\"},");
|
|
||||||
}
|
|
||||||
slen -= 1; // remove comma
|
|
||||||
slen += strtox(outbuf + slen, "]}");
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_lacp(void)
|
void send_lacp(void)
|
||||||
{
|
{
|
||||||
dbg_string("send_lacp called\n");
|
dbg_string("send_lacp called\n");
|
||||||
@@ -761,7 +624,7 @@ void send_lacp(void)
|
|||||||
}
|
}
|
||||||
slen -= 1; // remove comma
|
slen -= 1; // remove comma
|
||||||
slen += strtox(outbuf + slen, "],\"ports\":[");
|
slen += strtox(outbuf + slen, "],\"ports\":[");
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"p\":");
|
slen += strtox(outbuf + slen, "{\"p\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
slen += strtox(outbuf + slen, ",\"lag\":");
|
slen += strtox(outbuf + slen, ",\"lag\":");
|
||||||
@@ -793,7 +656,7 @@ void send_lldp(void)
|
|||||||
bool_to_html(lldp_enabled);
|
bool_to_html(lldp_enabled);
|
||||||
slen += strtox(outbuf + slen, ",\"portStatus\":[");
|
slen += strtox(outbuf + slen, ",\"portStatus\":[");
|
||||||
|
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
|
|
||||||
@@ -808,14 +671,14 @@ void send_lldp(void)
|
|||||||
bool_to_html(1 & (lldp_logical_port_status >> i));
|
bool_to_html(1 & (lldp_logical_port_status >> i));
|
||||||
slen += strtox(outbuf + slen, "}");
|
slen += strtox(outbuf + slen, "}");
|
||||||
|
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
|
||||||
char_to_html(']');
|
|
||||||
}
|
}
|
||||||
|
char_to_html(']');
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_eee(void)
|
void send_eee(void)
|
||||||
{
|
{
|
||||||
dbg_string("send_eee called\nsending EEE status\n");
|
dbg_string("send_eee called\nsending EEE status\n");
|
||||||
@@ -825,7 +688,7 @@ void send_eee(void)
|
|||||||
uint8_t eee_ablty = sfr_data[3];
|
uint8_t eee_ablty = sfr_data[3];
|
||||||
|
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
|
|
||||||
@@ -857,11 +720,10 @@ void send_eee(void)
|
|||||||
bool_to_html(eee_ablty & (1 << i));
|
bool_to_html(eee_ablty & (1 << i));
|
||||||
}
|
}
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
|
||||||
char_to_html(']');
|
|
||||||
}
|
}
|
||||||
|
char_to_html(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -870,7 +732,7 @@ void send_bandwidth(void)
|
|||||||
dbg_string("send_bandwidth called\n");
|
dbg_string("send_bandwidth called\n");
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
slen += strtox(outbuf + slen, ",\"iLimited\":");
|
slen += strtox(outbuf + slen, ",\"iLimited\":");
|
||||||
@@ -900,11 +762,10 @@ void send_bandwidth(void)
|
|||||||
byte_to_html(sfr_data[3]);
|
byte_to_html(sfr_data[3]);
|
||||||
char_to_html('"');
|
char_to_html('"');
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
|
||||||
char_to_html(']');
|
|
||||||
}
|
}
|
||||||
|
char_to_html(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -914,7 +775,7 @@ void send_storm(void)
|
|||||||
|
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
for (i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
slen += strtox(outbuf + slen, ",\"en\":\"");
|
slen += strtox(outbuf + slen, ",\"en\":\"");
|
||||||
@@ -934,11 +795,10 @@ void send_storm(void)
|
|||||||
}
|
}
|
||||||
char_to_html('"');
|
char_to_html('"');
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
|
||||||
char_to_html(']');
|
|
||||||
}
|
}
|
||||||
|
char_to_html(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -949,7 +809,7 @@ void send_isolation(void)
|
|||||||
dbg_string("send_isolation called\n");
|
dbg_string("send_isolation called\n");
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
slen += strtox(outbuf + slen, ",\"allow\":\"");
|
slen += strtox(outbuf + slen, ",\"allow\":\"");
|
||||||
@@ -958,7 +818,7 @@ void send_isolation(void)
|
|||||||
byte_to_html(allow & 0xff);
|
byte_to_html(allow & 0xff);
|
||||||
char_to_html('"');
|
char_to_html('"');
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
}
|
}
|
||||||
char_to_html(']');
|
char_to_html(']');
|
||||||
@@ -970,7 +830,7 @@ void send_mtu(void)
|
|||||||
dbg_string("send_mtu called\n");
|
dbg_string("send_mtu called\n");
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
slen += strtox(outbuf + slen, ",\"mtu\":\"0x");
|
slen += strtox(outbuf + slen, ",\"mtu\":\"0x");
|
||||||
@@ -980,11 +840,10 @@ void send_mtu(void)
|
|||||||
byte_to_html(mtu & 0xff);
|
byte_to_html(mtu & 0xff);
|
||||||
char_to_html('"');
|
char_to_html('"');
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
|
||||||
char_to_html(']');
|
|
||||||
}
|
}
|
||||||
|
char_to_html(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -994,7 +853,7 @@ void send_status(void)
|
|||||||
dbg_string("sending status\n");
|
dbg_string("sending status\n");
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
|
|
||||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
itoa_html(machine.log_to_phys_port[i]);
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
slen += strtox(outbuf + slen, ",\"logPort\":");
|
slen += strtox(outbuf + slen, ",\"logPort\":");
|
||||||
@@ -1111,12 +970,14 @@ void send_status(void)
|
|||||||
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
||||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH); // 32bit RX packet errors
|
reg_to_html(RTL837X_STAT_V_HIGH); // 32bit RX packet errors
|
||||||
|
|
||||||
|
slen += strtox(outbuf + slen, "\",\"macs\":\"0x");
|
||||||
|
reg_to_html(RTL837X_L2_LRN_PORT_CONSTRT_CNT + (i << 2));
|
||||||
slen += strtox(outbuf + slen, "\"}");
|
slen += strtox(outbuf + slen, "\"}");
|
||||||
if (i < machine.max_port)
|
if (i < MACHINE_MAX_PORT)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
|
||||||
char_to_html(']');
|
|
||||||
}
|
}
|
||||||
|
char_to_html(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ void send_isolation(void);
|
|||||||
void send_config(void);
|
void send_config(void);
|
||||||
void send_cmd_log(void);
|
void send_cmd_log(void);
|
||||||
void send_lag(void);
|
void send_lag(void);
|
||||||
void send_stp(void);
|
void send_stp(void) __banked;
|
||||||
void send_lldp(void);
|
void send_lldp(void);
|
||||||
void send_lacp(void);
|
void send_lacp(void);
|
||||||
|
void send_stp_counters(void) __banked;
|
||||||
void send_vlanlist(void);
|
void send_vlanlist(void);
|
||||||
|
|
||||||
/* Convert only the lower nibble to ascii HEX char.
|
/* Convert only the lower nibble to ascii HEX char.
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
#include "rtl837x_sfr.h"
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "rtl837x_port.h"
|
||||||
|
#include "uip.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "phy.h"
|
||||||
|
#include "machine.h"
|
||||||
|
#include "rtl837x_stp.h"
|
||||||
|
#include "page_impl.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#pragma codeseg BANK4
|
||||||
|
#pragma constseg BANK4
|
||||||
|
|
||||||
|
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||||
|
extern __xdata uint16_t slen;
|
||||||
|
|
||||||
|
static __code const uint8_t stp_json_hdr[] = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||||
|
|
||||||
|
static void stp_bool_html(char c)
|
||||||
|
{
|
||||||
|
outbuf[slen++] = c ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stp_byte_html(uint8_t val)
|
||||||
|
{
|
||||||
|
outbuf[slen++] = itohex(val >> 4);
|
||||||
|
outbuf[slen++] = itohex(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stp_itoa_html(uint8_t v)
|
||||||
|
{
|
||||||
|
uint8_t t = v / 100;
|
||||||
|
uint8_t print_zeros = t;
|
||||||
|
if (print_zeros)
|
||||||
|
outbuf[slen++] = '0' + t;
|
||||||
|
t = (v / 10) % 10;
|
||||||
|
print_zeros |= t;
|
||||||
|
if (print_zeros)
|
||||||
|
outbuf[slen++] = '0' + t;
|
||||||
|
outbuf[slen++] = '0' + (v % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static __xdata uint32_t pi_u32;
|
||||||
|
static __xdata uint8_t pi_prio, pi_ext;
|
||||||
|
static __xdata uint8_t * __xdata pi_mac;
|
||||||
|
|
||||||
|
|
||||||
|
static void u32hex_html(void)
|
||||||
|
{
|
||||||
|
__xdata uint8_t *b = (__xdata uint8_t *)&pi_u32;
|
||||||
|
stp_byte_html(b[3]);
|
||||||
|
stp_byte_html(b[2]);
|
||||||
|
stp_byte_html(b[1]);
|
||||||
|
stp_byte_html(b[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void bridge_to_html(void)
|
||||||
|
{
|
||||||
|
stp_byte_html(pi_prio);
|
||||||
|
stp_byte_html(pi_ext);
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
stp_byte_html(pi_mac[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_stp(void) __banked
|
||||||
|
{
|
||||||
|
static __xdata uint8_t i, j, st, dsg;
|
||||||
|
|
||||||
|
dbg_string("send_stp called\n");
|
||||||
|
slen = strtox(outbuf, stp_json_hdr);
|
||||||
|
|
||||||
|
slen += strtox(outbuf + slen, "{\"on\":");
|
||||||
|
stp_bool_html(stp_enabled);
|
||||||
|
slen += strtox(outbuf + slen, ",\"rstp\":");
|
||||||
|
stp_bool_html(stp_rstp);
|
||||||
|
slen += strtox(outbuf + slen, ",\"prio\":");
|
||||||
|
stp_itoa_html(stp_prio >> 4);
|
||||||
|
slen += strtox(outbuf + slen, ",\"hello\":");
|
||||||
|
stp_itoa_html(stp_hello_s);
|
||||||
|
slen += strtox(outbuf + slen, ",\"maxage\":");
|
||||||
|
stp_itoa_html(stp_maxage_s);
|
||||||
|
slen += strtox(outbuf + slen, ",\"fwd\":");
|
||||||
|
stp_itoa_html(stp_fwddelay_s);
|
||||||
|
slen += strtox(outbuf + slen, ",\"txhold\":");
|
||||||
|
stp_itoa_html(stp_txhold);
|
||||||
|
slen += strtox(outbuf + slen, ",\"pcs\":");
|
||||||
|
stp_itoa_html(stp_pcost_short);
|
||||||
|
slen += strtox(outbuf + slen, ",\"bh\":");
|
||||||
|
stp_itoa_html(stp_bpdu_filter);
|
||||||
|
slen += strtox(outbuf + slen, ",\"tcs\":\"");
|
||||||
|
pi_u32 = stp_tc_secs; u32hex_html();
|
||||||
|
slen += strtox(outbuf + slen, "\",\"rMaxage\":");
|
||||||
|
stp_itoa_html(stp_root_port == 0xff ? stp_maxage_s : stp_root_maxage);
|
||||||
|
slen += strtox(outbuf + slen, ",\"rFwd\":");
|
||||||
|
stp_itoa_html(stp_root_port == 0xff ? stp_fwddelay_s : stp_root_fwd);
|
||||||
|
slen += strtox(outbuf + slen, ",\"rootPrio\":\"");
|
||||||
|
stp_byte_html(root_bridge.prio);
|
||||||
|
stp_byte_html(root_bridge.ext);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"rootMac\":\"");
|
||||||
|
for (j = 0; j < 6; j++)
|
||||||
|
stp_byte_html(root_bridge.mac[j]);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"myMac\":\"");
|
||||||
|
for (j = 0; j < 6; j++)
|
||||||
|
stp_byte_html(uip_ethaddr.addr[j]);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"cost\":\"");
|
||||||
|
stp_byte_html(root_bridge_cost >> 24);
|
||||||
|
stp_byte_html(root_bridge_cost >> 16);
|
||||||
|
stp_byte_html(root_bridge_cost >> 8);
|
||||||
|
stp_byte_html(root_bridge_cost);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"weRoot\":");
|
||||||
|
stp_bool_html(stp_root_port == 0xff ? 1 : 0);
|
||||||
|
slen += strtox(outbuf + slen, ",\"tc\":\"");
|
||||||
|
stp_byte_html(stp_tc_count >> 8);
|
||||||
|
stp_byte_html(stp_tc_count);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"ports\":[");
|
||||||
|
for (i = 0; i < STP_ENTITIES; i++) {
|
||||||
|
j = stp_ent_id(i);
|
||||||
|
if (!j)
|
||||||
|
continue;
|
||||||
|
slen += strtox(outbuf + slen, "{\"p\":");
|
||||||
|
stp_itoa_html(j);
|
||||||
|
slen += strtox(outbuf + slen, ",\"st\":");
|
||||||
|
st = stp_port_state(i);
|
||||||
|
stp_itoa_html(st);
|
||||||
|
slen += strtox(outbuf + slen, ",\"role\":");
|
||||||
|
stp_itoa_html(stp_port_role(i));
|
||||||
|
slen += strtox(outbuf + slen, ",\"f\":");
|
||||||
|
stp_itoa_html(stp_pflags[i]);
|
||||||
|
slen += strtox(outbuf + slen, ",\"pc\":\"");
|
||||||
|
pi_u32 = stp_pcost[i]; u32hex_html();
|
||||||
|
slen += strtox(outbuf + slen, "\",\"prio\":");
|
||||||
|
stp_itoa_html(stp_pprio[i]);
|
||||||
|
slen += strtox(outbuf + slen, ",\"p2\":");
|
||||||
|
stp_itoa_html(stp_pp2p[i]);
|
||||||
|
slen += strtox(outbuf + slen, ",\"lk\":");
|
||||||
|
stp_itoa_html((stp_link_prev >> i) & 1);
|
||||||
|
slen += strtox(outbuf + slen, ",\"lg\":");
|
||||||
|
stp_itoa_html((stp_legacy >> i) & 1);
|
||||||
|
dsg = stp_dpid[i] && stp_info_while[i];
|
||||||
|
slen += strtox(outbuf + slen, ",\"db\":\"");
|
||||||
|
if (dsg) {
|
||||||
|
pi_prio = stp_dbridge[i].prio; pi_ext = stp_dbridge[i].ext;
|
||||||
|
pi_mac = stp_dbridge[i].mac;
|
||||||
|
} else {
|
||||||
|
pi_prio = stp_prio; pi_ext = 0;
|
||||||
|
pi_mac = uip_ethaddr.addr;
|
||||||
|
}
|
||||||
|
bridge_to_html();
|
||||||
|
slen += strtox(outbuf + slen, "\",\"dp\":\"");
|
||||||
|
stp_byte_html(dsg ? (stp_dpid[i] >> 8) : stp_pprio[i]);
|
||||||
|
stp_byte_html(dsg ? stp_dpid[i] : j);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"dc\":\"");
|
||||||
|
pi_u32 = dsg ? stp_dcost[i] : root_bridge_cost; u32hex_html();
|
||||||
|
slen += strtox(outbuf + slen, "\"},");
|
||||||
|
}
|
||||||
|
slen -= 1; // remove comma
|
||||||
|
slen += strtox(outbuf + slen, "]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_stp_counters(void) __banked
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
|
||||||
|
slen = strtox(outbuf, stp_json_hdr);
|
||||||
|
slen += strtox(outbuf + slen, "{\"on\":");
|
||||||
|
stp_bool_html(stp_enabled);
|
||||||
|
slen += strtox(outbuf + slen, ",\"hz\":");
|
||||||
|
stp_itoa_html(STP_HZ);
|
||||||
|
slen += strtox(outbuf + slen, ",\"tc\":\"");
|
||||||
|
stp_byte_html(stp_tc_count >> 8);
|
||||||
|
stp_byte_html(stp_tc_count);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"ports\":[");
|
||||||
|
for (i = 0; i < STP_ENTITIES; i++) {
|
||||||
|
j = stp_ent_id(i);
|
||||||
|
if (!j)
|
||||||
|
continue;
|
||||||
|
slen += strtox(outbuf + slen, "{\"p\":");
|
||||||
|
stp_itoa_html(j);
|
||||||
|
slen += strtox(outbuf + slen, ",\"c\":\"");
|
||||||
|
for (j = 0; j < STP_CNT_N; j++) {
|
||||||
|
pi_u32 = stp_cnt[j][i]; u32hex_html();
|
||||||
|
}
|
||||||
|
stp_byte_html(stp_bpdu_age[i] >> 8);
|
||||||
|
stp_byte_html(stp_bpdu_age[i]);
|
||||||
|
slen += strtox(outbuf + slen, "\"},");
|
||||||
|
}
|
||||||
|
slen -= 1;
|
||||||
|
slen += strtox(outbuf + slen, "]}");
|
||||||
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
CODE_LOCATION=0x1000
|
CODE_LOCATION=0x1000
|
||||||
INSTALLER_ADDRESS=0x1100
|
INSTALLER_ADDRESS=0x1100
|
||||||
|
|
||||||
CC = sdcc
|
SDCC_PREFIX = ../toolchain/sdcc-$(shell cat ../sdcc/* | cksum | cut -d' ' -f1)
|
||||||
|
ifeq ($(origin CC),default)
|
||||||
|
SDCC = $(SDCC_PREFIX)/bin/sdcc
|
||||||
|
CC = $(SDCC)
|
||||||
|
ASM = $(SDCC_PREFIX)/bin/sdas8051
|
||||||
|
endif
|
||||||
CC_FLAGS = -mmcs51
|
CC_FLAGS = -mmcs51
|
||||||
ASM = sdas8051
|
ASM ?= sdas8051
|
||||||
AFLAGS= -plosgff
|
AFLAGS= -plosgff
|
||||||
|
|
||||||
BUILDDIR = output
|
BUILDDIR = output
|
||||||
@@ -13,9 +18,14 @@ OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel}
|
|||||||
|
|
||||||
all: create_build_dir $(BUILDDIR)/updatebuilder $(BUILDDIR)/rtlplayground_oem_upgrade.bin
|
all: create_build_dir $(BUILDDIR)/updatebuilder $(BUILDDIR)/rtlplayground_oem_upgrade.bin
|
||||||
|
|
||||||
create_build_dir:
|
create_build_dir: $(SDCC)
|
||||||
mkdir -p $(BUILDDIR)
|
mkdir -p $(BUILDDIR)
|
||||||
|
|
||||||
|
ifneq ($(SDCC),)
|
||||||
|
$(SDCC):
|
||||||
|
sh ../sdcc/build.sh $(abspath $(SDCC_PREFIX))
|
||||||
|
endif
|
||||||
|
|
||||||
$(BUILDDIR)/updatebuilder: updatebuilder.c
|
$(BUILDDIR)/updatebuilder: updatebuilder.c
|
||||||
gcc $^ -o $@
|
gcc $^ -o $@
|
||||||
|
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ void installer(void)
|
|||||||
{
|
{
|
||||||
|
|
||||||
CKCON = 0; // Initial Clock configuration
|
CKCON = 0; // Initial Clock configuration
|
||||||
SFR_97 = 0; // HADDR?
|
MAP_FLASH_PAGE_TO_XDATA = 0; // HADDR?
|
||||||
|
|
||||||
// Set in managed mode:
|
// Set in managed mode:
|
||||||
SFR_b9 = 0x00;
|
SFR_b9 = 0x00;
|
||||||
|
|||||||
@@ -15,8 +15,51 @@
|
|||||||
|
|
||||||
#define MACHINE_INC(dir,file) MACHINE_STR(dir/file)
|
#define MACHINE_INC(dir,file) MACHINE_STR(dir/file)
|
||||||
|
|
||||||
|
#define RTL8370 0x70
|
||||||
|
#define RTL8372 0x72
|
||||||
|
#define RTL8373 0x73
|
||||||
|
|
||||||
#include MACHINE_INC(MACHINE_DEF_DIR,MACHINE_NAME.h)
|
#include MACHINE_INC(MACHINE_DEF_DIR,MACHINE_NAME.h)
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MACHINE_CHIPSET
|
||||||
|
#error "MACHINE_CHIPSET shall be defined in <machine>.h file"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MACHINE_MIN_PORT
|
||||||
|
#if MACHINE_CHIPSET == RTL8372
|
||||||
|
#define MACHINE_MIN_PORT 3
|
||||||
|
#else
|
||||||
|
#define MACHINE_MIN_PORT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MACHINE_MAX_PORT
|
||||||
|
#if MACHINE_CHIPSET == RTL8370
|
||||||
|
#define MACHINE_MAX_PORT 7
|
||||||
|
#else
|
||||||
|
#define MACHINE_MAX_PORT 8
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MACHINE_PORT_VALID(p) \
|
||||||
|
((uint8_t)((p) - MACHINE_MIN_PORT) <= (MACHINE_MAX_PORT - MACHINE_MIN_PORT))
|
||||||
|
|
||||||
|
// auto derive SOC_FAMILY
|
||||||
|
#define RTL836X 6
|
||||||
|
#define RTL837X 7
|
||||||
|
|
||||||
|
#ifdef SOC_FAMILY
|
||||||
|
#error "SOC_FAMILY can not be manually defined, shall be auto derived"
|
||||||
|
#endif
|
||||||
|
#if (MACHINE_CHIPSET == RTL8372) || (MACHINE_CHIPSET == RTL8373)
|
||||||
|
#define SOC_FAMILY RTL837X
|
||||||
|
#elif (MACHINE_CHIPSET == RTL8370 )
|
||||||
|
#define SOC_FAMILY RTL836X
|
||||||
|
#else
|
||||||
|
#error "Unsupported MACHINE_CHIPSET is specified!"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LED_27 1
|
#define LED_27 1
|
||||||
// SYSTEM LED
|
// SYSTEM LED
|
||||||
#define LED_28_SYS 2
|
#define LED_28_SYS 2
|
||||||
@@ -41,10 +84,6 @@ struct sfp_port
|
|||||||
struct machine {
|
struct machine {
|
||||||
char machine_name[30];
|
char machine_name[30];
|
||||||
uint8_t isRTL8373;
|
uint8_t isRTL8373;
|
||||||
// Lowest logical port number
|
|
||||||
uint8_t min_port;
|
|
||||||
// Highest logical port number
|
|
||||||
uint8_t max_port;
|
|
||||||
uint8_t n_sfp;
|
uint8_t n_sfp;
|
||||||
uint8_t n_10g;
|
uint8_t n_10g;
|
||||||
uint8_t log_to_phys_port[9];
|
uint8_t log_to_phys_port[9];
|
||||||
@@ -64,6 +103,12 @@ struct machine {
|
|||||||
uint8_t led_mux_custom;
|
uint8_t led_mux_custom;
|
||||||
uint8_t led_mux[28];
|
uint8_t led_mux[28];
|
||||||
uint32_t mac_flash_offset;
|
uint32_t mac_flash_offset;
|
||||||
|
// Read the flash with single-IO (CMD_FREAD) instead of DIO for MMIO/code
|
||||||
|
// fetch. Set for boards whose flash chip is not usable in DIO mode, which
|
||||||
|
// shows up as a board that does not boot at all, garbled console output or
|
||||||
|
// random resets. Costs management-plane speed only, the ASIC keeps
|
||||||
|
// forwarding in hardware.
|
||||||
|
uint8_t flash_sio;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct machine_runtime
|
struct machine_runtime
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
SWTG018AS_A_V_2_0.c
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _MACHINE_2G08110GSN_H_
|
||||||
|
#define _MACHINE_2G08110GSN_H_
|
||||||
|
|
||||||
|
#define MACHINE_MODEL "MokerLink 2G08110GSN"
|
||||||
|
#define MACHINE_CHIPSET RTL8373
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include "machine_defs.h"
|
||||||
|
|
||||||
|
__code const struct machine machine = {
|
||||||
|
MACHINE_COMMON_SETTING,
|
||||||
|
.n_sfp = 2,
|
||||||
|
/* Same 2M-PCB43-V1.1 board family as the KP-9000-6XH-X2 (see
|
||||||
|
* machine/KP_9000_6XHML_X2.c), but the two SFP+ cages (physical ports 5 and
|
||||||
|
* 6) are wired the other way round: physical 5 is on SDS1, physical 6 on
|
||||||
|
* SDS0. Copper ports 1-4 match the KP-9000 layout. */
|
||||||
|
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
|
||||||
|
// Left SFP cage (physical port 5) = SDS1
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
// Right SFP cage (physical port 6) = SDS0
|
||||||
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
|
.sfp_port[1].pin_los = GPIO10_LED10,
|
||||||
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[1].sds = 0,
|
||||||
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
/* The board has a 3-hole reset button footprint, but it is unpopulated and
|
||||||
|
* the case has no opening for it, so reset_pin stays GPIO_NA. GPIO54, the
|
||||||
|
* reset pin on the KP-9000 layout, reads as permanently pressed here. */
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
/* The fitted T25S40 does not work in DIO mode on this board, so read the flash
|
||||||
|
* with single-IO; see doc/devices/2G5F4_10G2_V1.01.md. */
|
||||||
|
.flash_sio = 1,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
/* Conditions for LED on:
|
||||||
|
* dual led orange: ledset_0 & ledset_2
|
||||||
|
* dual led green: ledset_2 & !ledset_0
|
||||||
|
* single right led green: ledset_0 & !ledset_1
|
||||||
|
*
|
||||||
|
* Measured on this board: LED-ID0 is the copper blue LED, LED-ID1 the
|
||||||
|
* copper white one (setting LED-ID0 to 0 killed blue while leaving white on
|
||||||
|
* at 2.5G only) and LED-ID2 carries the SFP single LED. The "solid"
|
||||||
|
* conditions (LINK/speed) barely drive the LEDs here and ACT is what
|
||||||
|
* actually lights them, which is why the white LED used to glow faintly at
|
||||||
|
* non-2.5G speeds; the fix for that is LED_GLB_IO_EN bit 6, set in the
|
||||||
|
* shared machine_custom_init() hook (machine/2G5F4_10G2_V1_01_init.c). */
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_10G,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _MACHINE_2G5F4_10G2_V1_01_H_
|
||||||
|
#define _MACHINE_2G5F4_10G2_V1_01_H_
|
||||||
|
|
||||||
|
#define MACHINE_MODEL "2G5F4_10G2_V1.01 / SGT0204S"
|
||||||
|
#define MACHINE_CHIPSET RTL8372
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
KP_9000_6XH_X2_init.c
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#include "machine_defs.h"
|
|
||||||
|
|
||||||
__code const struct machine machine = {
|
|
||||||
.machine_name = MACHINE_MODEL,
|
|
||||||
.isRTL8373 = 1,
|
|
||||||
.min_port = 0,
|
|
||||||
.max_port = 8,
|
|
||||||
.n_sfp = 1,
|
|
||||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
|
||||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
|
||||||
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
|
||||||
.sfp_port[0].pin_los = GPIO37,
|
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
|
||||||
.sfp_port[0].sds = 1,
|
|
||||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
|
||||||
.reset_pin = GPIO_NA,
|
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
||||||
.led_sets = { { LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
|
||||||
LEDS_2G5 | LEDS_LINK,
|
|
||||||
LEDS_1G | LEDS_LINK,
|
|
||||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
KP_9000_9XH_X_EU.c
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
#define _MACHINE_DEFAULT_8C_1SFP_H_
|
#define _MACHINE_DEFAULT_8C_1SFP_H_
|
||||||
|
|
||||||
#define MACHINE_MODEL "8+1 SFP Port Switch"
|
#define MACHINE_MODEL "8+1 SFP Port Switch"
|
||||||
|
#define MACHINE_CHIPSET RTL8373
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
#include "machine_defs.h"
|
#include "machine_defs.h"
|
||||||
|
|
||||||
__code const struct machine machine = {
|
__code const struct machine machine = {
|
||||||
.machine_name = MACHINE_MODEL,
|
MACHINE_COMMON_SETTING,
|
||||||
.isRTL8373 = 1,
|
|
||||||
.min_port = 0,
|
|
||||||
.max_port = 8,
|
|
||||||
.n_sfp = 1,
|
.n_sfp = 1,
|
||||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
#define _MACHINE_F7008_2_5_H_
|
#define _MACHINE_F7008_2_5_H_
|
||||||
|
|
||||||
#define MACHINE_MODEL "F7008-2.5 8+1 SFP Port Switch"
|
#define MACHINE_MODEL "F7008-2.5 8+1 SFP Port Switch"
|
||||||
|
#define MACHINE_CHIPSET RTL8373
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
#include "machine_defs.h"
|
#include "machine_defs.h"
|
||||||
|
|
||||||
__code const struct machine machine = {
|
__code const struct machine machine = {
|
||||||
.machine_name = MACHINE_MODEL,
|
MACHINE_COMMON_SETTING,
|
||||||
.isRTL8373 = 0,
|
|
||||||
.min_port = 3,
|
|
||||||
.max_port = 8,
|
|
||||||
.n_sfp = 2,
|
.n_sfp = 2,
|
||||||
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
||||||
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
#define _MACHINE_FG_4GT_2SX_V2_0_H_
|
#define _MACHINE_FG_4GT_2SX_V2_0_H_
|
||||||
|
|
||||||
#define MACHINE_MODEL "FG-4GT-2SX_V2.0"
|
#define MACHINE_MODEL "FG-4GT-2SX_V2.0"
|
||||||
|
#define MACHINE_CHIPSET RTL8372
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "machine_init_defs.h"
|
||||||
|
|
||||||
|
void machine_custom_init(void) __banked
|
||||||
|
{
|
||||||
|
REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7624155b);
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
#include "machine_defs.h"
|
#include "machine_defs.h"
|
||||||
|
|
||||||
__code const struct machine machine = {
|
__code const struct machine machine = {
|
||||||
.machine_name = MACHINE_MODEL,
|
MACHINE_COMMON_SETTING,
|
||||||
.isRTL8373 = 1,
|
|
||||||
.min_port = 0,
|
|
||||||
.max_port = 8,
|
|
||||||
.n_sfp = 1,
|
.n_sfp = 1,
|
||||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
#define _MACHINE_FG_8GT_1SX_H_
|
#define _MACHINE_FG_8GT_1SX_H_
|
||||||
|
|
||||||
#define MACHINE_MODEL "FG-8GT-1SX"
|
#define MACHINE_MODEL "FG-8GT-1SX"
|
||||||
|
#define MACHINE_CHIPSET RTL8373
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#include "machine_defs.h"
|
|
||||||
|
|
||||||
__code const struct machine machine = {
|
|
||||||
.machine_name = MACHINE_MODEL,
|
|
||||||
.isRTL8373 = 0,
|
|
||||||
.min_port = 3,
|
|
||||||
.max_port = 8,
|
|
||||||
.n_sfp = 2,
|
|
||||||
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
|
||||||
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
|
||||||
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
|
|
||||||
|
|
||||||
/* Left SFP (logical 8, SDS1): GPIO30=ModAbs, GPIO37=RX_LOS */
|
|
||||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
|
||||||
.sfp_port[0].pin_los = GPIO37,
|
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
|
||||||
.sfp_port[0].sds = 1,
|
|
||||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
|
||||||
|
|
||||||
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
|
|
||||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
|
||||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
|
||||||
.sfp_port[1].sds = 0,
|
|
||||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
|
||||||
|
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
|
||||||
|
|
||||||
/* Copper ports use SET0; SFP ports use SET1 */
|
|
||||||
.port_led_set = {0, 0, 0, 1, 0, 0, 0, 0, 1},
|
|
||||||
|
|
||||||
.led_sets = {
|
|
||||||
{ /* SET0: copper — LED0=amber (2.5G), LED2=green (1G/100M/10M) */
|
|
||||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
|
||||||
0,
|
|
||||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
{ /* SET1: SFP — all speeds link/act */
|
|
||||||
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
|
||||||
0,
|
|
||||||
0, 0
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
.led_mux_custom = 1,
|
|
||||||
.led_mux = {
|
|
||||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* GPIO0-7: unused */
|
|
||||||
0x0f, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, /* GPIO8-14 */
|
|
||||||
0x14, 0x15, 0x16, 0x18, 0x19, 0x1a, /* GPIO15-20 */
|
|
||||||
0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x23 /* GPIO21-27 */
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
PCB_K0402WS_V2.c
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
#define _MACHINE_FNS1200P_H_
|
#define _MACHINE_FNS1200P_H_
|
||||||
|
|
||||||
#define MACHINE_MODEL "FNS-1200P"
|
#define MACHINE_MODEL "FNS-1200P"
|
||||||
|
#define MACHINE_CHIPSET RTL8372
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||