Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c263a8ab64 | ||
|
|
c02f660c08 | ||
|
|
4e00f5a592 | ||
|
|
eff3f42ae1 | ||
|
|
dda873a633 | ||
|
|
9b2bd7f1b8 | ||
|
|
2dfe531fe0 | ||
|
|
72c2625121 | ||
|
|
58fd1a3ccc | ||
|
|
4f1a2f04d8 | ||
|
|
cedc795b82 | ||
|
|
ccf541a06b | ||
|
|
d5124df89e | ||
|
|
3eacc9c8a5 | ||
|
|
735672ccf1 | ||
|
|
1ebee4d6e9 | ||
|
|
e67c928eb7 | ||
|
|
46f8ea8712 | ||
|
|
b0eab52a2e | ||
|
|
8ce062c349 | ||
|
|
f768220a73 | ||
|
|
eab2e26510 | ||
|
|
b0ed56d423 | ||
|
|
36a064d03d | ||
|
|
2d01b8b7d7 | ||
|
|
fa632cdc6e | ||
|
|
177fb76e1b | ||
|
|
ff57084799 | ||
|
|
2dc5520928 | ||
|
|
7c11142a04 | ||
|
|
957a5b0e23 | ||
|
|
c773230a9b | ||
|
|
0e9c997d06 | ||
|
|
5ab247e996 | ||
|
|
d80717f3f0 | ||
|
|
24069439b0 | ||
|
|
4117f549cc | ||
|
|
2e24b24426 | ||
|
|
b71239f394 | ||
|
|
6e69f5bba3 | ||
|
|
1224335b66 | ||
|
|
e5b19bc594 | ||
|
|
89fcc6836d | ||
|
|
f9d4ab0074 | ||
|
|
6f68ccef28 | ||
|
|
8e687ef28e | ||
|
|
87db2dd4b8 | ||
|
|
aac1aed4c8 | ||
|
|
f0aea3dcac | ||
|
|
f10ab30f6d | ||
|
|
de431c6d84 | ||
|
|
26547f3e01 | ||
|
|
13b75a73c9 | ||
|
|
c6fceae724 | ||
|
|
068ec4c510 | ||
|
|
3a92459190 | ||
|
|
5ffeb3d16a | ||
|
|
de705380c9 | ||
|
|
e4f3315af3 | ||
|
|
07ab04e668 | ||
|
|
c5ce24ff78 | ||
|
|
bcb237158f | ||
|
|
f103daaafa | ||
|
|
168add47a3 | ||
|
|
423886dc54 | ||
|
|
4a9137387c | ||
|
|
2fc08f40d2 | ||
|
|
4a7fd7a098 | ||
|
|
19cd1200b4 | ||
|
|
333adbaf19 | ||
|
|
8051061fd7 | ||
|
|
8ae3f5e70f | ||
|
|
9ce328d155 | ||
|
|
2e463a2f30 | ||
|
|
422dc3f24d | ||
|
|
4b01ff9f8a | ||
|
|
456a4d9d3f | ||
|
|
02e9189f5f | ||
|
|
aff7d9c098 | ||
|
|
770926abd1 | ||
|
|
13f04d8acb | ||
|
|
49284fee15 | ||
|
|
db9ce7543e | ||
|
|
7a14c2d4a5 | ||
|
|
92948079a9 | ||
|
|
e406a3e82b | ||
|
|
c43b955db0 | ||
|
|
0321763e91 | ||
|
|
4bbbcd7d04 | ||
|
|
682ed861fa | ||
|
|
3a9045b97e | ||
|
|
4b9f6c319f | ||
|
|
6e2701bc8c | ||
|
|
ac3b4b17ae | ||
|
|
f87eb70c6a | ||
|
|
214cc6b737 | ||
|
|
40177f6318 | ||
|
|
d3dda09079 | ||
|
|
277e729f2c | ||
|
|
f778b9159b | ||
|
|
b6d6d2391d | ||
|
|
2c231fdf69 | ||
|
|
689751ffe6 | ||
|
|
fa93340c24 | ||
|
|
e9523a2f67 | ||
|
|
088be074f5 | ||
|
|
340fdd97e5 | ||
|
|
09ce4b391b | ||
|
|
7e6577a811 | ||
|
|
675faf0471 | ||
|
|
175ca9464a | ||
|
|
38241f0a08 | ||
|
|
0fe323b12f | ||
|
|
94187461c6 | ||
|
|
fa0eb91586 | ||
|
|
2f872ea08e | ||
|
|
ab2d30a05b | ||
|
|
d37ce07119 | ||
|
|
4bd6ffd083 | ||
|
|
94cfec8693 | ||
|
|
a4bb3f1725 | ||
|
|
931e6da0ab | ||
|
|
88454ec7d7 | ||
|
|
f0efb84abb | ||
|
|
62d3424a92 | ||
|
|
a3860c29cb | ||
|
|
b1961c6955 | ||
|
|
bb84bdc55a | ||
|
|
9733ff61a0 | ||
|
|
1b5243714e | ||
|
|
36459fdd76 | ||
|
|
ce11790a0d | ||
|
|
55431b39f6 | ||
|
|
46e1c955ba | ||
|
|
7b728cec6f | ||
|
|
0d17dd563f | ||
|
|
d556d634ca | ||
|
|
2844a1ed6d | ||
|
|
7b5e365d5e | ||
|
|
45fb382b07 | ||
|
|
8973774594 | ||
|
|
48c5b0c9cf | ||
|
|
1557a7cf3c | ||
|
|
131bc106af | ||
|
|
19ccc4003d | ||
|
|
b5fe9f217f | ||
|
|
f65d14f452 | ||
|
|
b92fba870c | ||
|
|
4deee377a7 | ||
|
|
fe42b07e2b | ||
|
|
9984649177 | ||
|
|
7d47edb649 | ||
|
|
fdb19fe0ee | ||
|
|
b9b50f9a70 | ||
|
|
c31b67572b | ||
|
|
a4e3b4368b | ||
|
|
93003c8cb8 | ||
|
|
fd058ea74d | ||
|
|
edc469fe29 | ||
|
|
a71c5359a5 | ||
|
|
9e3863cc4e | ||
|
|
d22ec04b5b | ||
|
|
0a65536a7f | ||
|
|
0631c813e2 | ||
|
|
eaebeba528 | ||
|
|
b36fd95356 | ||
|
|
52b1d1a4ea | ||
|
|
48f28ae7ff | ||
|
|
a7fc8303e9 | ||
|
|
a62866a93a | ||
|
|
42bbed9661 | ||
|
|
3c8de6da87 | ||
|
|
3a6f62b1d5 | ||
|
|
530e2683f0 | ||
|
|
9fedc6dd3d | ||
|
|
5e23d13771 | ||
|
|
09d5857fdd | ||
|
|
be309853c9 | ||
|
|
072edb36a8 | ||
|
|
10dd330e3c | ||
|
|
c514eb8bf3 | ||
|
|
e2c4ed6be3 | ||
|
|
56ee56af2e | ||
|
|
8626b4c1d4 | ||
|
|
0cc09e4015 | ||
|
|
674dc1f35d | ||
|
|
7e6b443e07 | ||
|
|
73ec184c23 | ||
|
|
bf41fbd202 | ||
|
|
04ab442c6d | ||
|
|
c02623a610 | ||
|
|
c69bf4c5ec | ||
|
|
575274786a | ||
|
|
7f4f6dae03 | ||
|
|
4eeb12c020 | ||
|
|
7d81b15b6e | ||
|
|
d6253ddc25 | ||
|
|
8cac67cdf7 | ||
|
|
5620e950ce | ||
|
|
83491bc9e3 | ||
|
|
eb83b8be09 | ||
|
|
bece4a20a1 | ||
|
|
cdc84c75e4 | ||
|
|
6be1871bb4 | ||
|
|
4686515de3 | ||
|
|
c39cc421a7 | ||
|
|
c1df7c23d1 | ||
|
|
9bae4052a3 | ||
|
|
0d115e0e0b | ||
|
|
8e78d1e629 | ||
|
|
13cc9db1ce | ||
|
|
3dcab09047 | ||
|
|
94992562fd | ||
|
|
6150ada5f8 | ||
|
|
8116ef0a5b | ||
|
|
0cd56b1196 | ||
|
|
3b3f36256c | ||
|
|
18b28edcbb | ||
|
|
6ea9503ab2 | ||
|
|
e0df37f359 | ||
|
|
c04a5fc3a4 | ||
|
|
f0b311fc43 | ||
|
|
2f005d2993 | ||
|
|
974052877d | ||
|
|
ae77ffe495 | ||
|
|
f65416f0d1 | ||
|
|
ffde4eaf60 | ||
|
|
c05d83132b | ||
|
|
dcd3cd5a98 | ||
|
|
9f107b6e60 | ||
|
|
15b10d9ed0 | ||
|
|
abf1cd1344 | ||
|
|
b5b52776bc | ||
|
|
0486c34bfd | ||
|
|
690092d564 | ||
|
|
115ea09ebb | ||
|
|
f3e1a393b5 | ||
|
|
206c72b5ef | ||
|
|
472811cc9a | ||
|
|
80552816b9 | ||
|
|
c1caf6f569 | ||
|
|
ddad65fe90 | ||
|
|
ff7b517491 | ||
|
|
65417433eb | ||
|
|
b7621fad31 | ||
|
|
82f78cb8f2 | ||
|
|
75f2ade1a1 | ||
|
|
3e91b05a42 | ||
|
|
ec1cb4106d | ||
|
|
62c6c65f1c | ||
|
|
c691591295 | ||
|
|
434acbcc13 | ||
|
|
1aae2fac30 | ||
|
|
1f9b3df3e6 | ||
|
|
eb4bae278b | ||
|
|
7908044a44 | ||
|
|
0ec1a5e63f | ||
|
|
114af559c7 | ||
|
|
5a2c4ca029 | ||
|
|
63e367d298 | ||
|
|
5e513daf17 | ||
|
|
3ec9319d77 | ||
|
|
b42eace21d | ||
|
|
3dfd6a88c7 | ||
|
|
7fa26e0ae3 | ||
|
|
1c8cdab4bf | ||
|
|
f49ca0d6fe | ||
|
|
12fb6fd809 | ||
|
|
dad65fd550 | ||
|
|
dc82e044bc | ||
|
|
7daa9effe0 | ||
|
|
950586135a | ||
|
|
c1ad800fc5 | ||
|
|
dc4fb5becc | ||
|
|
78ecef15e9 | ||
|
|
eab927f52a | ||
|
|
02c816647c | ||
|
|
624f93a28a | ||
|
|
6616a0c9ce | ||
|
|
8d7faf5312 | ||
|
|
d6d9c368e9 | ||
|
|
36de9791be | ||
|
|
552bd1cb18 |
No files matched your search
@@ -3,6 +3,7 @@ name: Build firmware
|
||||
on:
|
||||
push:
|
||||
branches: ['**']
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -16,8 +17,14 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt update
|
||||
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev -y
|
||||
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y
|
||||
- name: Run the host-side unit tests
|
||||
run: make -C test
|
||||
- name: Check if machine.c can be compiled for all machines
|
||||
run: make machine_check
|
||||
- name: Make project
|
||||
run: make MACHINE="KP_9000_6XHML_X2"
|
||||
- name: Make project (4x2/RTL8372)
|
||||
run: make CI=1 MACHINE="KP_9000_6XHML_X2"
|
||||
- name: Make project (8x1/RTL8373)
|
||||
run: make CI=1 MACHINE="KP_9000_9XHML_X_V3_1"
|
||||
- name: Make project with the health instrumentation
|
||||
run: make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1
|
||||
@@ -7,3 +7,7 @@ version.h
|
||||
tools/httpd_sim
|
||||
tools/injector
|
||||
tools/fileadder
|
||||
|
||||
# host-test stand-ins for the two generated headers
|
||||
!test/stub/html_data.h
|
||||
!test/stub/version.h
|
||||
@@ -6,11 +6,20 @@
|
||||
|
||||
- Web UI
|
||||
- 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,
|
||||
English, Japanese and Chinese, save to flash merges the command log into the startup config and verifies the write,
|
||||
firmware images are checked in the browser before upload. #429
|
||||
|
||||
## Changed
|
||||
|
||||
## Fixed
|
||||
|
||||
- Config
|
||||
- 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 web UI and the configuration upload now refuse a line the replay cannot take,
|
||||
instead of writing it to flash.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
- Config
|
||||
|
||||
@@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y \
|
||||
python3 \
|
||||
libjson-c-dev \
|
||||
git \
|
||||
zlib1g-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# git safe.directory for mounted repos (Makefile uses git describe)
|
||||
|
||||
@@ -19,6 +19,14 @@ ifeq ($(MACHINE),)
|
||||
else
|
||||
CC_FLAGS += -DMACHINE_$(MACHINE)
|
||||
endif
|
||||
# Health instrumentation and the "health" console command: HEALTH=1 gmake ...
|
||||
ifneq ($(HEALTH),)
|
||||
CC_FLAGS += -DHEALTH
|
||||
endif
|
||||
|
||||
ifeq ($(CI),1)
|
||||
CC_FLAGS += --Werror
|
||||
endif
|
||||
|
||||
BUILDDIR = output/$(MACHINE)
|
||||
VERSION_HEADER := version.h
|
||||
@@ -59,6 +67,8 @@ SRCS = \
|
||||
dhcp.c \
|
||||
html_data.c \
|
||||
rtlplayground.c \
|
||||
boot.c \
|
||||
sfp.c \
|
||||
syslog.c \
|
||||
udp_apps.c
|
||||
|
||||
@@ -69,10 +79,13 @@ SRCS += \
|
||||
rtl837x_igmp.c \
|
||||
rtl837x_init.c \
|
||||
rtl837x_leds.c \
|
||||
rtl837x_leds_dump.c \
|
||||
rtl837x_phy.c \
|
||||
rtl837x_pins.c\
|
||||
rtl837x_port.c \
|
||||
rtl837x_stp.c
|
||||
rtl837x_stp.c \
|
||||
rtl837x_lldp.c \
|
||||
rtl837x_storm.c
|
||||
SRCS += \
|
||||
httpd/httpd.c \
|
||||
httpd/page_impl.c
|
||||
@@ -102,11 +115,14 @@ html_min: $(HTML)
|
||||
html_data.c html_data.h &: $(HTML) | tools html_min
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
|
||||
|
||||
$(VERSION_HEADER):
|
||||
$(VERSION_HEADER): FORCE
|
||||
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
|
||||
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
|
||||
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
|
||||
"#endif" > $(VERSION_HEADER)
|
||||
"#endif" > $(VERSION_HEADER).tmp
|
||||
@cmp -s $(VERSION_HEADER).tmp $(VERSION_HEADER) \
|
||||
&& rm -f $(VERSION_HEADER).tmp \
|
||||
|| mv $(VERSION_HEADER).tmp $(VERSION_HEADER)
|
||||
|
||||
httpd: html_data.h
|
||||
|
||||
@@ -124,15 +140,25 @@ distclean: $(SUBDIRSCLEAN)
|
||||
$(SUBDIRSCLEAN):
|
||||
$(MAKE) -C $(@:clean=) clean
|
||||
|
||||
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h
|
||||
# Objects depend on the flags they were built with, through a stamp file that
|
||||
# is rewritten only when CC_FLAGS actually changes.
|
||||
CCFLAGS_STAMP := $(BUILDDIR)/.ccflags
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
||||
$(CCFLAGS_STAMP): FORCE | create_build_dir
|
||||
@echo '$(CC_FLAGS)' | cmp -s - $@ 2>/dev/null || echo '$(CC_FLAGS)' > $@
|
||||
|
||||
$(BUILDDIR)/%.rel: %.c $(CCFLAGS_STAMP) | create_build_dir html_data.h
|
||||
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/%.rel: %.asm | create_build_dir
|
||||
$(BUILDDIR)/%.rel: %.asm $(CCFLAGS_STAMP) | create_build_dir
|
||||
${ASM} ${AFLAGS} -o $@ $<
|
||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||
|
||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
|
||||
$(CC) $(CC_FLAGS) --xram-size 49151 -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
||||
|
||||
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||
objcopy --input-target=ihex -O binary $< $@
|
||||
@@ -142,11 +168,11 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i
|
||||
tools/output/imagebuilder -i $^ $@
|
||||
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -p html_data -b BANK1 $@
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@
|
||||
tools/output/crc_calculator -u $@
|
||||
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
|
||||
|
||||
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) $(VERSION_HEADER) create_build_dir
|
||||
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir
|
||||
|
||||
.PHONY:
|
||||
machine_check:
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
A Playground for Firmware development for advanced user of RTL8372/RTL8373 based 2.5GBit Switches.
|
||||
|
||||
For each hardware configuration of these devices, there is usually a managed and an
|
||||
umanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||
unmanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||
features also for unmanaged devices with additional features such as Management VLAN,
|
||||
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||
DHCP servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||
only the following features are provided:
|
||||
- A modern web-interface with mouse-over to display further information
|
||||
- A serial console interface to configure all features
|
||||
- IGMP to configure Multicast streaming
|
||||
- Port configuration showing detailed informtion about own and Link-partner advertised
|
||||
Speed settins and configuration of these settings on the local side
|
||||
- Port configuration showing detailed information about own and Link-partner advertised
|
||||
Speed settings and configuration of these settings on the local side
|
||||
- Per-port configuration of frame sizes (MTUs) for Jumbo-Frame support or limiting MTUs
|
||||
for particular devices
|
||||
- EEE (Energy Efficient Ethernet) can be configured per-port. Detailed information is
|
||||
@@ -25,7 +25,7 @@ only the following features are provided:
|
||||
- Firmware updates via the web
|
||||
- Installation as a firmware upgrade from the original web-interface
|
||||
|
||||
<img width="1420" height="623" alt="GUI" src="doc/images/gui.png" />
|
||||
<img width="1673" height="977" alt="GUI" src="doc/images/gui.png" />
|
||||
|
||||
While the firmware provides already considerable improvements over the original managed firmware,
|
||||
the firmware still lacks support for the proprietary loop prevention
|
||||
@@ -37,7 +37,7 @@ a backup of the original flash content via a SOIC clamp such as also used for BI
|
||||
backups and can re-install that firmware in case something is wrong. For this no soldering
|
||||
skills are necessary.
|
||||
|
||||
The firmware supports all hardware featues of devices with
|
||||
The firmware supports all hardware features of devices with
|
||||
- 4 2.5GBit ports + 2 SFP+ ports
|
||||
- 5 2.5GBIT + 1 SFP+ port
|
||||
- 8 2.5GBit + 1 SFP+ port
|
||||
@@ -59,7 +59,7 @@ device simulator is provided, which runs entirely under Linux as a local webserv
|
||||
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
|
||||
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
|
||||
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev
|
||||
```
|
||||
|
||||
<details>
|
||||
@@ -131,7 +131,7 @@ rtlplayground-v0.1.0-12c98ba-dirty-LIANGUO_ZX_SWTGW215AS.bin
|
||||
|
||||
> [!CAUTION]
|
||||
> This image can be flashed directly to the chip OR through the firmware update/upgrade
|
||||
> interface of RTLPlaygound interface
|
||||
> interface of RTLPlayground interface
|
||||
|
||||
## (2) Compiling for OEM running device with management options (web upgrade)
|
||||
|
||||
@@ -175,11 +175,11 @@ Header checksum is: 0x5a1
|
||||
## (3) Sandbox Usage with Ghidra (optional)
|
||||
|
||||
You can play with the image using ghidra or flash real Switch Hardware. For
|
||||
ghidra see this information about [Ghidra images](ghidra.md).
|
||||
ghidra see this information about [Ghidra images](doc/ghidra.md).
|
||||
|
||||
## (4) Installation through the Web interface (software way)
|
||||
|
||||
Managed switches (OEM firmware of RTLplaygroud firmware) can be upgraded via the web interface.
|
||||
Managed switches (OEM firmware of RTLplayground firmware) can be upgraded via the web interface.
|
||||
Unmanaged switch cannot be flashed this way (see 5).
|
||||
|
||||
Go to "Firmware update" tab, select the correct file.
|
||||
@@ -190,7 +190,7 @@ Go to "Firmware update" tab, select the correct file.
|
||||
|
||||
> [!CAUTION]
|
||||
> Check one more time that your device matches the machine type before flashing.
|
||||
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung.
|
||||
> Be sure you have a backup of the original firmware before diving in RTLPlayground.
|
||||
|
||||
Finally, push the Upload File Button and you're done !
|
||||
|
||||
@@ -198,7 +198,7 @@ Finally, push the Upload File Button and you're done !
|
||||
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
|
||||
|
||||
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
|
||||
This is also the only way to unbrick your device if something went wroong.
|
||||
This is also the only way to unbrick your device if something went wrong.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
|
||||
@@ -218,7 +218,7 @@ This is also the only way to unbrick your device if something went wroong.
|
||||
- ERASE THE ROM (BLANK) !
|
||||
- Load the firmware into IMSProg.
|
||||
- Flash is to the ROM chip.
|
||||
- Disconect the clip from the ROM chip.
|
||||
- Disconnect the clip from the ROM chip.
|
||||
- You're done, ready for the first boot.
|
||||
|
||||
## (6) Connecting a serial interface (optional)
|
||||
@@ -233,7 +233,7 @@ When you power up the switch, the device will perform some examples and provide
|
||||
## (8) The web-interface
|
||||
|
||||
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
|
||||
specified an IP adress in the config.txt before compilation.
|
||||
specified an IP address in the config.txt before compilation.
|
||||
|
||||
> [!TIP]
|
||||
> The default password is `1234`.
|
||||
@@ -333,17 +333,18 @@ While in compilation part, you might write directly to config.txt file before ma
|
||||
nano config.txt
|
||||
```
|
||||
|
||||
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
|
||||
If you want to modify settings after the flash is done, go to the System tab and find the Startup Configuration.
|
||||
|
||||
<img width="1085" height="646" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
|
||||
<img width="1673" height="978" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
|
||||
|
||||
```
|
||||
ip xxx.xxx.xxx.xxx = IP adress of the switch
|
||||
gw yyy.yyy.yyy.yyy = IP adress of the gateway
|
||||
ip xxx.xxx.xxx.xxx = IP address of the switch
|
||||
gw yyy.yyy.yyy.yyy = IP address of the gateway
|
||||
netmask zzz.zzz.zzz.zzz = Network mask of the switch
|
||||
port x name xxx = Name xxx the port number x
|
||||
port z 1g = Set 1g speed for port z
|
||||
igmp on/off = Turn IGMP on or off
|
||||
session xxxx = Web session timeout in seconds (default 200)
|
||||
```
|
||||
[To be continue]
|
||||
|
||||
@@ -359,4 +360,5 @@ The following documents give further documentation on specific features of the R
|
||||
- [SFP+ ports](doc/sfp.md)
|
||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
||||
- [VLAN](doc/vlan.md)
|
||||
- [Storm control](doc/storm_control.md)
|
||||
- [Modifications and Flash replacement](doc/mods.md)
|
||||
@@ -0,0 +1,479 @@
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#include <8051.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "rtl837x_pins.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_init.h"
|
||||
#include "machine.h"
|
||||
#include "phy.h"
|
||||
#include "boot.h"
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
__xdata uint32_t rtl8224_release_tick;
|
||||
extern __xdata uint8_t tx_seq;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
|
||||
|
||||
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode) __banked
|
||||
{
|
||||
reg_read_m(RTL837X_REG_SDS_MODES);
|
||||
sfr_data[0] = 0;
|
||||
sfr_data[1] = 0;
|
||||
switch (sds) {
|
||||
case 0:
|
||||
sfr_mask_data(0, 0x1f, mode);
|
||||
break;
|
||||
case 1:
|
||||
sfr_mask_data(0, 0xe0, mode << 5);
|
||||
sfr_mask_data(1, 0x03, mode >> 3);
|
||||
break;
|
||||
case 2:
|
||||
sfr_mask_data(1, 0xfc, 0x02 << 2);
|
||||
}
|
||||
if (machine_detected.isRTL8373) // Set 3rd SERDES Mode to 0x2 for RTL8224
|
||||
sfr_mask_data(1, 0xfc, 0x02 << 2);
|
||||
else
|
||||
sfr_data[2] &= 0x03;
|
||||
reg_write_m(RTL837X_REG_SDS_MODES);
|
||||
print_string("\nRTL837X_REG_SDS_MODES: ");
|
||||
print_reg(RTL837X_REG_SDS_MODES);
|
||||
print_string("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void early_boot_handle_button(void) __banked
|
||||
{
|
||||
if (machine.reset_pin == GPIO_NA)
|
||||
return;
|
||||
|
||||
gpio_input_setup(machine.reset_pin);
|
||||
|
||||
// Debounce after init
|
||||
delay(100);
|
||||
// If the button is not already held at boot, continue normally.
|
||||
if (gpio_pin_test(machine.reset_pin))
|
||||
return;
|
||||
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
print_string("\n[Reset button held at boot]\n");
|
||||
|
||||
if (gpio_pin_test(machine.reset_pin))
|
||||
return;
|
||||
|
||||
const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ;
|
||||
const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ;
|
||||
const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms
|
||||
const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms
|
||||
__xdata uint32_t start_ticks = ticks;
|
||||
__xdata uint32_t last_blink_step = start_ticks;
|
||||
__xdata uint8_t blink_step = 0;
|
||||
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
while (!gpio_pin_test(machine.reset_pin)) {
|
||||
__xdata uint32_t held_ticks = ticks - start_ticks;
|
||||
|
||||
if (held_ticks > max_hold_ticks) {
|
||||
print_string("[Button held >30s at boot; continuing normal boot]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Double blink pattern while button is held:
|
||||
// ON (100ms), OFF (100ms), ON (100ms), OFF (500ms)
|
||||
__xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks;
|
||||
if ((ticks - last_blink_step) >= step_ticks) {
|
||||
blink_step = (blink_step + 1) & 0x3;
|
||||
set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF);
|
||||
last_blink_step = ticks;
|
||||
}
|
||||
|
||||
PCON |= 1;
|
||||
}
|
||||
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
if ((ticks - start_ticks) >= min_hold_ticks) {
|
||||
print_string("[Button held 10s-30s at boot; restoring default config]\n");
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
flash_default_config();
|
||||
delay(3UL * SYS_TICK_HZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure the SerDes of the SoC for a particular mode
|
||||
* to connect to an SFP module or a PHY
|
||||
* Valid modes are SDS_10GR, SDS_QXGMII, SDS_HISGMII, SDS_HSG, SDS_SGMII and SDS_1000BX_FIBER
|
||||
* The SerDes ID may be 0 or 1 for RTL8272 and 0-2 for RTL8373
|
||||
* SDS_QXGMII is used for 10G Fiber, RTL8224 and RTL8261BE
|
||||
*/
|
||||
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');
|
||||
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;
|
||||
uint16_t v = 0;
|
||||
|
||||
switch (mode) {
|
||||
case SDS_SGMII:
|
||||
case SDS_1000BX_FIBER:
|
||||
v = 0x0300;
|
||||
page = 0x24;
|
||||
break;
|
||||
case SDS_HISGMII:
|
||||
case SDS_HSG:
|
||||
v = 0x0200;
|
||||
page = 0x28;
|
||||
break;
|
||||
case SDS_10GR:
|
||||
case SDS_QXGMII:
|
||||
v = 0x0200;
|
||||
page = 0x2e;
|
||||
break;
|
||||
case SDS_100FX:
|
||||
v = 0x0200;
|
||||
page = 0x26;
|
||||
break;
|
||||
default:
|
||||
print_string("Error in SDS Mode\n");
|
||||
return;
|
||||
}
|
||||
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
|
||||
|
||||
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
|
||||
sds_write_v(sds, page, 0x04, 0x0080); // Q012e04:0080
|
||||
sds_write_v(sds, page, 0x06, 0x0408); // Q012e06:0408
|
||||
sds_write_v(sds, page, 0x07, 0x020d); // Q012e07:020d
|
||||
sds_write_v(sds, page, 0x09, 0x0601); // Q012e09:0601
|
||||
sds_write_v(sds, page, 0x0b, 0x222c); // Q012e0b:222c
|
||||
sds_write_v(sds, page, 0x0c, 0xa217); // Q012e0c:a217
|
||||
sds_write_v(sds, page, 0x0d, 0xfe40); // Q012e0d:fe40
|
||||
sds_write_v(sds, page, 0x15, 0xf5c1); // Q012e15:f5c1
|
||||
} else {
|
||||
sds_write_v(sds, page, 0x04, 0x0080); // Q002804:0080
|
||||
sds_write_v(sds, page, 0x07, 0x1201); // Q002807:1201
|
||||
sds_write_v(sds, page, 0x09, 0x0601); // Q002809:0601
|
||||
sds_write_v(sds, page, 0x0b, 0x232c); // Q00280b:232c
|
||||
sds_write_v(sds, page, 0x0c, 0x9217); // Q00280c:9217
|
||||
sds_write_v(sds, page, 0x0f, 0x5b50); // Q00280f:5b50
|
||||
sds_write_v(sds, page, 0x15, 0xe7c1); // Q002815:e7f1 BUG !
|
||||
}
|
||||
|
||||
sds_write_v(sds, page, 0x16, 0x0443); // Q002816:0443 / Q012e16:0443
|
||||
sds_write_v(sds, page, 0x1d, 0xabb0); // Q00281d:abb0 / Q012e1d:abb0
|
||||
|
||||
sds_write_v(sds, 0x06, 0x12, 0x5078); // Q000612:5078
|
||||
sds_write_v(sds, 0x07, 0x06, 0x9401); // Q000706:9401
|
||||
sds_write_v(sds, 0x07, 0x08, 0x9401); // Q000708:9401
|
||||
sds_write_v(sds, 0x07, 0x0a, 0x9401); // Q00070a:9401
|
||||
sds_write_v(sds, 0x07, 0x0c, 0x9401); // Q00070c:9401
|
||||
sds_write_v(sds, 0x1f, 0x0b, 0x0003); // Q001f0b:0003
|
||||
sds_write_v(sds, 0x06, 0x03, 0xc45c); // Q000603:c45c
|
||||
|
||||
// RTL8261BE
|
||||
if (machine.n_10g && mode == SDS_QXGMII) {
|
||||
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
|
||||
sds_write_v(sds, 0x07, 0x11, 0x054f); // Q000711:054f
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
|
||||
sds_write_v(sds, 0x20, 0x00, 0x0000); // Q002000:0000
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x000b); // Q001f00:000b
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
|
||||
return;
|
||||
}
|
||||
if (mode != SDS_QXGMII)
|
||||
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
|
||||
|
||||
if (mode == SDS_1000BX_FIBER) {
|
||||
sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020
|
||||
sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0
|
||||
sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d
|
||||
sds_write_v(sds, 0x20, 0x04, 0x0000); // Q002000:0000
|
||||
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void rtl8224_enable(void) __banked
|
||||
{
|
||||
// Set Pin 4 low
|
||||
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
// Configure Pin as output
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
|
||||
delay(4);
|
||||
// Set pin 4 high
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
rtl8224_release_tick = ticks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void nic_setup(void) __banked
|
||||
{
|
||||
// Enable NIC
|
||||
// r6040:00000100 R6040-00001100
|
||||
reg_bit_set(RTL837X_REG_HW_CONF, 0xc);
|
||||
|
||||
// This sets the size of the RX buffer, the filling level is in 0x7874
|
||||
// R7848-000004ff
|
||||
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff);
|
||||
|
||||
// R7844-000007fe
|
||||
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
|
||||
|
||||
// Configure NIC RX to receive various types of packets
|
||||
// RTL837X_REG_RX_CTRL: Set bits 24-31 to 0x4, clear bits 16/17
|
||||
reg_read_m(RTL837X_REG_RX_CTRL);
|
||||
sfr_mask_data(3, 0xff, 0x04);
|
||||
sfr_mask_data(2, 0x03, 0);
|
||||
reg_write_m(RTL837X_REG_RX_CTRL);
|
||||
|
||||
// Enable NIC TX (set bit 0)
|
||||
reg_bit_set(RTL837X_REG_TX_CTRL, 0);
|
||||
|
||||
// Enable NIC RX (set bit 0)
|
||||
reg_bit_set(RTL837X_REG_RX_CTRL, 0);
|
||||
|
||||
// Drop packets with invalid CRC
|
||||
reg_bit_clear(RTL837X_REG_RX_CTRL, 2);
|
||||
|
||||
// R603c-00000200
|
||||
// CPU-port is CPU-Tag aware (bit 9)
|
||||
REG_SET(RTL837X_REG_CPU_TAG_AWARE_PMASK, 0x200);
|
||||
|
||||
// Insert CPU-tag for internally received packets (bit 0), MODE is 0, i.e. ALL packets (bits 8-9)
|
||||
reg_read_m(RTL837X_REG_CPU_TAG);
|
||||
sfr_mask_data(0, 1, 1);
|
||||
sfr_mask_data(1, 3, 0);
|
||||
reg_write_m(RTL837X_REG_CPU_TAG);
|
||||
|
||||
// Force MAC mode of the CPU port (port 9)
|
||||
// r6368:00000194 R6368-00000197
|
||||
reg_read_m(RTL837X_REG_MAC_FORCE_MODE + 9 * 4);
|
||||
sfr_mask_data(0, 0, 3); // Set bits 0, 1: Force link
|
||||
reg_write_m(RTL837X_REG_MAC_FORCE_MODE+ 9 * 4);
|
||||
|
||||
// Sequence number of TX packets
|
||||
tx_seq = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rtl8373_revision(void) __banked
|
||||
{
|
||||
reg_read_m(RTL837X_REG_CHIP_INFO);
|
||||
sfr_mask_data(2, 0x0a, 0x0a); // Enable reading version
|
||||
reg_write_m(RTL837X_REG_CHIP_INFO);
|
||||
delay(50);
|
||||
|
||||
reg_read_m(RTL837X_REG_CHIP_INFO);
|
||||
print_string("CPU revision: "); print_byte(sfr_data[2]); print_byte(sfr_data[2]); write_char('\n');
|
||||
sfr_mask_data(2, 0x0a, 0x00); // Enable reading version
|
||||
reg_write_m(RTL837X_REG_CHIP_INFO);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The SoC manages Link-State for steering the LEDs and can set PHY-settings
|
||||
* automatically through Realtek's SMI (Simple Managagement) Interface, a
|
||||
* proprietary version of MDIO which for example allows for more PHYs on the same
|
||||
* bus.
|
||||
* Configure polling via SMI and the interface setup during boot.
|
||||
*/
|
||||
void init_smi(void) __banked
|
||||
{
|
||||
print_string("\ninit_switch called\n");
|
||||
|
||||
/* Set the SMI(i.e.I2C) type for PHY polling, 0b01 is 2.5/10G PHY. Disable (0b00) for the SFP-ports
|
||||
* which are at port 8 and additionally at port 3 for a dual SFP device
|
||||
*/
|
||||
|
||||
// Default: 0x00005555
|
||||
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x00005555;
|
||||
SFR_DATA_U16_UPPER = 0x0000;
|
||||
SFR_DATA_U16 = 0x5555;
|
||||
if (machine.n_10g == 2) {
|
||||
// 0x00015555, only change the bytes that differs from the default.
|
||||
SFR_DATA_16 = 0x01;
|
||||
} else if (machine.n_sfp == 2)
|
||||
// 0x00005515
|
||||
SFR_DATA_0 = 0x15;
|
||||
reg_write(RTL837X_REG_SMI_MAC_TYPE);
|
||||
|
||||
// Configure polling of all PHYs by the MAC to detect link-state changes
|
||||
// Default: 0x000000ff
|
||||
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x000000ff;
|
||||
SFR_DATA_U16_UPPER = 0x0000;
|
||||
SFR_DATA_U16 = 0x00ff;
|
||||
if (!machine_detected.isRTL8373) {
|
||||
if (machine.n_sfp == 2) {
|
||||
// 0x000000f0, only change the bytes that differs from the default.
|
||||
SFR_DATA_0 = 0xf0;
|
||||
} else {
|
||||
// 0x000001f8, only change the bytes that differs from the default.
|
||||
SFR_DATA_8 = 0x01;
|
||||
SFR_DATA_0 = 0xf8;
|
||||
}
|
||||
}
|
||||
reg_write(RTL837X_REG_SMI_PORT_POLLING);
|
||||
// Enable MDC
|
||||
reg_read_m(RTL837X_REG_SMI_CTRL);
|
||||
sfr_mask_data(1, 0, 0x70); // Set bits 12-14 to enable MDC for SMI0-SMI2
|
||||
reg_write_m(RTL837X_REG_SMI_CTRL);
|
||||
delay(50);
|
||||
|
||||
if (!machine_detected.isRTL8373) {
|
||||
// Change I2C addresses for SMI of the non-existent PHYs
|
||||
// r6450:000020e6 R6450-000000e6
|
||||
reg_read_m(RTL837X_REG_SMI_PORT6_9_ADDR);
|
||||
sfr_mask_data(1, 0x7c, 0);
|
||||
reg_write_m(RTL837X_REG_SMI_PORT6_9_ADDR);
|
||||
|
||||
// r644c:0a418820 R644c-0a400820
|
||||
reg_read_m(RTL837X_REG_SMI_PORT0_5_ADDR);
|
||||
sfr_mask_data(2, 0x0f, 0);
|
||||
sfr_mask_data(1, 0x80, 0);
|
||||
reg_write_m(RTL837X_REG_SMI_PORT0_5_ADDR);
|
||||
}
|
||||
|
||||
if (machine.n_10g == 2) {
|
||||
// Set address of second external PHY on port 8
|
||||
REG_SET(RTL837X_REG_SMI_PORT6_9_ADDR, 0x000040e6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void setup_i2c(void) __banked
|
||||
{
|
||||
REG_SET(RTL837X_REG_I2C_MST_IF_CTRL, 0);
|
||||
// Configure SFP EEPROM address (0x50) as I2C device address
|
||||
// Configure SFP readings address (0x51) as I2C device address
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16), 0x50 >> 5, (0x50 << 3) & 0xff);
|
||||
|
||||
REG_SET(RTL837X_REG_I2C_CTRL2, 0);
|
||||
|
||||
// HW Control register, enable I2C depending on PIN configuration
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
uint8_t i2c = machine.sfp_port[sfp].i2c;
|
||||
uint8_t scl_bus = (i2c >> RTL837X_REG_I2C_SCL_SHIFT) & RTL837X_REG_I2C_SCL_MASK;
|
||||
uint8_t sda_bus = (i2c >> RTL837X_REG_I2C_SDA_SHIFT) & RTL837X_REG_I2C_SDA_MASK;
|
||||
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
|
||||
// `& RTL837X_REG_I2C_SCL_MASK` is needed to silens a compiler warning 110.
|
||||
switch (scl_bus & RTL837X_REG_I2C_SCL_MASK) {
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
break;
|
||||
case 2:
|
||||
// Bit 15-16 0b01 -> SCL
|
||||
sfr_mask_data(1, 0x80, 0x80);
|
||||
sfr_mask_data(2, 0x01, 0x00);
|
||||
break;
|
||||
case 1:
|
||||
// Bit 11-12 0b01 -> SCL
|
||||
sfr_mask_data(1, 0x18, 0x08);
|
||||
break;
|
||||
case 0:
|
||||
// Bit 7-8 0b01 -> SCL
|
||||
sfr_mask_data(0, 0x80, 0x80);
|
||||
sfr_mask_data(1, 0x01, 0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (sda_bus) {
|
||||
case 4:
|
||||
// Bit 29 0b0 -> SDA
|
||||
sfr_mask_data(3, 0x20, 0x00);
|
||||
break;
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SDA (implies enabled SCL on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
break;
|
||||
case 2:
|
||||
// Bit 17-18 0b01 -> SDA
|
||||
sfr_mask_data(2, 0x06, 0x02);
|
||||
break;
|
||||
case 1:
|
||||
// Bit 13-14 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x60, 0x20);
|
||||
break;
|
||||
case 0:
|
||||
// Bit 9-10 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x06, 0x02);
|
||||
break;
|
||||
}
|
||||
}
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
}
|
||||
|
||||
|
||||
/* Give the switch a name carrying the tail of its MAC, so several of them on
|
||||
* one network are distinguishable out of the box. Called after the startup
|
||||
* config has been replayed and returns at once if that config already set a
|
||||
* name, so a configured switch does no work for it (suggested in review).
|
||||
*
|
||||
* Written without a loop on purpose. Locals - counters and pointers alike -
|
||||
* land in the 8051's internal-RAM overlay, and on an image with LACP and STP
|
||||
* both enabled that overlay is exhausted: a loop here makes the linker fail
|
||||
* with "Could not get 8 consecutive bytes in internal RAM for area OSEG".
|
||||
* Moving the code into its own function does not help; the overlay is shared
|
||||
* across the whole image. Hoisting the locals to xdata does not help either,
|
||||
* because itohex() is inline and brings its own frame. */
|
||||
void set_hostname_default(void) __banked
|
||||
{
|
||||
if (hostname[0] != NUL)
|
||||
return;
|
||||
|
||||
strcpy((__xdata uint8_t *)hostname, "RTLPlayground-");
|
||||
hostname[14] = hex[uip_ethaddr.addr[3] >> 4];
|
||||
hostname[15] = hex[uip_ethaddr.addr[3] & 0xf];
|
||||
hostname[16] = hex[uip_ethaddr.addr[4] >> 4];
|
||||
hostname[17] = hex[uip_ethaddr.addr[4] & 0xf];
|
||||
hostname[18] = hex[uip_ethaddr.addr[5] >> 4];
|
||||
hostname[19] = hex[uip_ethaddr.addr[5] & 0xf];
|
||||
hostname[20] = NUL;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef BOOT_H
|
||||
#define BOOT_H
|
||||
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode) __banked;
|
||||
void sds_config(uint8_t sds, uint8_t mode) __banked;
|
||||
void early_boot_handle_button(void) __banked;
|
||||
void rtl8224_enable(void) __banked;
|
||||
void nic_setup(void) __banked;
|
||||
void rtl8373_revision(void) __banked;
|
||||
void init_smi(void) __banked;
|
||||
void setup_i2c(void) __banked;
|
||||
void set_hostname_default(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,8 @@
|
||||
// #define DEBUG
|
||||
// #define REGDBG 1
|
||||
|
||||
#include <8051.h>
|
||||
#include "cmd_parser.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_flash.h"
|
||||
@@ -14,32 +16,39 @@
|
||||
#include "rtl837x_stp.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "rtl837x_bandwidth.h"
|
||||
#include "rtl837x_lldp.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "sfp.h"
|
||||
#include "dhcp.h"
|
||||
#include "syslog.h"
|
||||
#include "uip/uip.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "machine.h"
|
||||
#include "rtl837x_leds.h"
|
||||
#include "phy.h"
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata bool stp_enabled;
|
||||
extern __code uint8_t log_to_phys_port[9];
|
||||
extern __code const uint8_t log_to_phys_port[9];
|
||||
extern __xdata bool lldp_enabled;
|
||||
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern volatile __xdata uint8_t sfr_data[4];
|
||||
|
||||
extern __code uint8_t * __code greeting;
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code const uint8_t * __code const greeting;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
|
||||
extern __xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||
extern __xdata struct flash_region_t flash_region;
|
||||
|
||||
extern __xdata char passwd[21];
|
||||
|
||||
extern __xdata uint16_t session_timeout;
|
||||
|
||||
extern __xdata struct dhcp_state dhcp_state;
|
||||
|
||||
__xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
@@ -49,9 +58,6 @@ __xdata char port_names[9][PORT_NAME_SIZE];
|
||||
|
||||
extern __xdata uint16_t management_vlan;
|
||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||
extern __xdata uint8_t sfp_speed[2];
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t gpio_last_value[8] = { 0 };
|
||||
|
||||
// Temporatly for str to hex convertion value.
|
||||
@@ -61,11 +67,11 @@ __xdata uint8_t hexvalue[4] = { 0 };
|
||||
|
||||
// Buffer for writing to flash 0x1fd000, copy to 0x1fe000
|
||||
__xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
__xdata uint8_t cmd_available;
|
||||
|
||||
__xdata char save_cmd;
|
||||
|
||||
__xdata uint8_t ip[4];
|
||||
__xdata uint8_t mac_parse_result[6];
|
||||
|
||||
/* Scratch for parse_syslog(), in xdata: a local here would take internal RAM
|
||||
* the linker has none of. */
|
||||
@@ -106,8 +112,7 @@ inline uint8_t isnumber(uint8_t l)
|
||||
return (l <= ('9'-'0'));
|
||||
}
|
||||
|
||||
|
||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd)
|
||||
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd)
|
||||
{
|
||||
if (cmd_words_len == 0 || start > (cmd_words_len - 1)) {
|
||||
return 0;
|
||||
@@ -349,7 +354,7 @@ err:
|
||||
}
|
||||
|
||||
// Prints an IPv4 address.
|
||||
void print_ip(__xdata uint8_t * ptr)
|
||||
void print_ip(__xdata uint8_t * ptr) __banked
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint8_t num;
|
||||
@@ -364,6 +369,125 @@ void print_ip(__xdata uint8_t * ptr)
|
||||
}
|
||||
}
|
||||
|
||||
// Prints a MAC address.
|
||||
void print_mac(__xdata uint8_t *ptr) __banked
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint8_t num;
|
||||
|
||||
while (1) {
|
||||
num = *ptr++;
|
||||
print_byte(num);
|
||||
if (++idx == 6)
|
||||
break;
|
||||
|
||||
write_char(':');
|
||||
}
|
||||
}
|
||||
|
||||
// Parses a MAC address "aa:bb:cc:dd:ee:ff" (":" or "-" separators) from
|
||||
// cmd_buffer starting at idx into the global mac_parse_result[6]. Each octet
|
||||
// must be exactly two hex digits with a separator between octets and nothing
|
||||
// trailing, so repeated separators, missing digits or a trailing hex digit are
|
||||
// rejected. Returns the number of bytes consumed, or 0 on error.
|
||||
uint8_t parse_mac(uint8_t idx)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
uint8_t c = ':';
|
||||
|
||||
do {
|
||||
if (c != ':' && c != '-')
|
||||
goto err;
|
||||
|
||||
__bit again = true;
|
||||
uint8_t v = 0;
|
||||
|
||||
while(1) {
|
||||
c = cmd_buffer[idx++];
|
||||
c -= '0';
|
||||
if (c > 9) {
|
||||
c |= 0x20;
|
||||
c += '0' - 'a';
|
||||
if (c > 5)
|
||||
goto err;
|
||||
c += 10;
|
||||
}
|
||||
// force swap-instr.
|
||||
v = (v << 4) | (v >> 4);
|
||||
v |= c;
|
||||
|
||||
if (again)
|
||||
again = false;
|
||||
else
|
||||
break;
|
||||
}
|
||||
mac_parse_result[b++] = v;
|
||||
|
||||
c = cmd_buffer[idx++];
|
||||
} while(b < 6);
|
||||
|
||||
if (c == ' ' || c == NUL)
|
||||
return idx;
|
||||
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_error(__code const char *msg)
|
||||
{
|
||||
err_status = ERR_INVALID_ARGUMENT;
|
||||
print_string("Error: ");
|
||||
print_string(msg);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t name_char(uint8_t c)
|
||||
{
|
||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||
return '.';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// Sets the management MAC from a "mac <aa:bb:cc:dd:ee:ff>" command (or prints
|
||||
// the current one with a bare "mac"). Refuses blank/multicast/locally
|
||||
// administered/all-zero-OUI addresses so the running MAC stays reachable, and
|
||||
// re-registers the static L2 management entry so the change applies without a
|
||||
// reboot. As a regular command a "mac ..." line in the startup config applies
|
||||
// on every boot (execute_config runs before the final static L2 entry).
|
||||
void parse_mac_cmd(void)
|
||||
{
|
||||
if (cmd_words_len == 1) {
|
||||
print_string("Current MAC: ");
|
||||
print_mac(uip_ethaddr.addr);
|
||||
write_char('\n');
|
||||
return;
|
||||
}
|
||||
if (cmd_words_len != 2 || !parse_mac(cmd_words_b[1])) {
|
||||
cmd_error("mac [<aa:bb:cc:dd:ee:ff>]\n");
|
||||
return;
|
||||
}
|
||||
if ((mac_parse_result[0] & 0x03) || ((mac_parse_result[0] | mac_parse_result[1] | mac_parse_result[2]) == 0)) {
|
||||
cmd_error("the MAC must be unicast and globally administered\n");
|
||||
return;
|
||||
}
|
||||
if (memcmp(mac_parse_result, uip_ethaddr.addr, 6) == 0) {
|
||||
print_string("MAC unchanged\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap the static management entry over to the new address: remove the
|
||||
// old one (still in uip_ethaddr) before overwriting it.
|
||||
port_l2_static_mgmt(uip_ethaddr.addr, management_vlan, true);
|
||||
memcpy(uip_ethaddr.addr, mac_parse_result, 6);
|
||||
port_l2_static_mgmt(uip_ethaddr.addr, management_vlan, false);
|
||||
|
||||
print_string("MAC set to: ");
|
||||
print_mac(uip_ethaddr.addr);
|
||||
write_char('\n');
|
||||
print_string("Save the startup config to keep it across reboots\n");
|
||||
}
|
||||
|
||||
|
||||
void parse_lag(void)
|
||||
{
|
||||
@@ -422,7 +546,7 @@ void parse_lag(void)
|
||||
port_lag_members_set(group, members);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: lag (show | <1-4> (d | <port>...))\n");
|
||||
cmd_error("lag (show | <1-4> (d | <port>...))\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -464,7 +588,7 @@ void parse_lag_hash(void)
|
||||
port_lag_hash_set(group, hash);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: laghash <1-4> [smac|dmac|sip|dip|sport|dport]\n");
|
||||
cmd_error("laghash <1-4> [smac|dmac|sip|dip|sport|dport]\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -518,7 +642,7 @@ void parse_vlan(void)
|
||||
*vlan_str++ = hex[(vlan_settings.vlan >> 4) & 0xf] ;
|
||||
*vlan_str++ = hex[vlan_settings.vlan & 0xf];
|
||||
while(!cmd_is_space_or_nul(pos)) {
|
||||
uint8_t c = cmd_buffer[pos++];
|
||||
uint8_t c = name_char(cmd_buffer[pos++]);
|
||||
write_char(c);
|
||||
*vlan_str++ = c;
|
||||
}
|
||||
@@ -562,7 +686,7 @@ void parse_vlan(void)
|
||||
}
|
||||
return;
|
||||
err:
|
||||
print_string("Error: vlan (<vlan-id>|show) [port][t]...\n");
|
||||
cmd_error("vlan (<vlan-id>|show) [port][t]...\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -613,7 +737,7 @@ void parse_isolate(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("Error: isolate <port> [show|off] [port]...\n");
|
||||
cmd_error("isolate <port> [show|off] [port]...\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -650,7 +774,7 @@ void parse_ingress(void)
|
||||
// Setting mode for all ports at once
|
||||
for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) {
|
||||
if (!port_ingress_filter(log_port, mode)) {
|
||||
print_string("Error setting 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;
|
||||
}
|
||||
print_string("All ports ingress filter set to: ");
|
||||
@@ -661,18 +785,18 @@ void parse_ingress(void)
|
||||
idx = cmd_words_b[w];
|
||||
uint8_t ret = cmd_parse_port(idx);
|
||||
if (ret != 1) {
|
||||
print_string("Invalid physical port number\n");
|
||||
cmd_error("Invalid physical port number\n");
|
||||
continue;
|
||||
}
|
||||
log_port = atoi_results_u8;
|
||||
idx += ret;
|
||||
|
||||
if (!vlan_ingress_mode_parse(cmd_buffer[idx++], &mode) || !cmd_is_space_or_nul(idx)) {
|
||||
print_string("Invalid ingress mode for port "); print_phys_port(log_port); print_string(" in ingress command\n");
|
||||
cmd_error("Invalid ingress mode for port "); print_phys_port(log_port); print_string(" in ingress command\n");
|
||||
goto err;
|
||||
}
|
||||
if (!port_ingress_filter(log_port, mode)) {
|
||||
print_string("Error setting 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;
|
||||
}
|
||||
print_string("Port "); print_phys_port(log_port);
|
||||
@@ -682,7 +806,7 @@ void parse_ingress(void)
|
||||
}
|
||||
return;
|
||||
err:
|
||||
print_string("Error: ingress [p]<u/t/a>...\n");
|
||||
cmd_error("ingress [p]<u/t/a>...\n");
|
||||
}
|
||||
|
||||
void parse_mirror(void)
|
||||
@@ -747,7 +871,7 @@ void parse_mirror(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("Port/command missing: mirror [status/off/<mirroring port> [port][t/r]]...\n");
|
||||
cmd_error("Port/command missing: mirror [status/off/<mirroring port> [port][t/r]]...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -755,15 +879,16 @@ err:
|
||||
void parse_port(void)
|
||||
{
|
||||
if (cmd_words_len < 3) {
|
||||
print_string("\nUsage:" \
|
||||
cmd_error("\nUsage:" \
|
||||
"\nport <port> [show|on|off]" \
|
||||
"\nport <port> [10m|100m|1g|2g5|duplex] [half|full]" \
|
||||
"\nport <port> lldp [block|permit]" \
|
||||
"\nport <port> name [custom port name]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_parse_port_separator(cmd_words_b[1]) == 0) {
|
||||
print_string("Invalid port number\n");
|
||||
cmd_error("Invalid port number\n");
|
||||
return;
|
||||
}
|
||||
phy_settings.port = atoi_results_u8;
|
||||
@@ -776,17 +901,28 @@ void parse_port(void)
|
||||
print_string_x(port_names[phy_settings.port]);
|
||||
if (!machine.is_sfp[phy_settings.port]) {
|
||||
phy_show(phy_settings.port);
|
||||
} else {
|
||||
write_char('\n');
|
||||
}
|
||||
port_media_show(phy_settings.port);
|
||||
} else if (cmd_compare(2, "name")) {
|
||||
uint8_t i = 0;
|
||||
while ( (i < PORT_NAME_SIZE-1) && (cmd_buffer[cmd_words_b[3] + i] != NUL) ) {
|
||||
port_names[phy_settings.port][i] = cmd_buffer[cmd_words_b[3] + i];
|
||||
while ( cmd_words_len > 3 && (i < PORT_NAME_SIZE-1) && (cmd_buffer[cmd_words_b[3] + i] != NUL) ) {
|
||||
port_names[phy_settings.port][i] = name_char(cmd_buffer[cmd_words_b[3] + i]);
|
||||
i++;
|
||||
}
|
||||
port_names[phy_settings.port][i] = NUL;
|
||||
print_string("\nName set to: \"");
|
||||
print_string_x(port_names[phy_settings.port]);
|
||||
print_string("\"\n");
|
||||
} else if (cmd_compare(2, "lldp")) {
|
||||
if (cmd_compare(3, "block")){
|
||||
lldp_logical_port_status &= ~((uint16_t)1 << phy_settings.port);
|
||||
} else if (cmd_compare(3, "permit")) {
|
||||
lldp_logical_port_status |= (uint16_t)1 << phy_settings.port;
|
||||
} else {
|
||||
print_string ("Unknown port <port> lldp [block|permit] command\n");
|
||||
}
|
||||
} else if (machine.is_sfp[phy_settings.port]) {
|
||||
print_string(" is SFP no PHY information available.\n");
|
||||
} else if (cmd_compare(2, "10m")) {
|
||||
@@ -841,7 +977,7 @@ void parse_port(void)
|
||||
phy_settings.duplex = PHY_DUPLEX_HALF;
|
||||
phy_set_duplex();
|
||||
} else {
|
||||
print_string("Unknown port command\n");
|
||||
cmd_error("Unknown port command\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -869,7 +1005,7 @@ void parse_mtu(void)
|
||||
print_byte(p);
|
||||
|
||||
if (atoi_short(cmd_words_b[2]) == 0 || atoi_results_short < 64 || atoi_results_short > 0x3fff) {
|
||||
print_string("MTU must be 64..16383\n");
|
||||
cmd_error("MTU must be 64..16383\n");
|
||||
return;
|
||||
}
|
||||
REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (atoi_results_short >> 10) & 0xf, (atoi_results_short >> 2) & 0xff,
|
||||
@@ -878,7 +1014,7 @@ void parse_mtu(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("mtu [port] [size]\n");
|
||||
cmd_error("mtu [port] [size]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -935,11 +1071,11 @@ void parse_sfp(void)
|
||||
idx += ret;
|
||||
slot = atoi_results_u8 - 1;
|
||||
if (ret == 0 || !cmd_is_space(idx) || slot > 1) {
|
||||
print_string("Illegal SFP slot number\n");
|
||||
cmd_error("Illegal SFP slot number\n");
|
||||
return;
|
||||
}
|
||||
if (slot >= machine.n_sfp) {
|
||||
print_string("SFP slot not present\n");
|
||||
cmd_error("SFP slot not present\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -965,7 +1101,7 @@ void parse_sfp(void)
|
||||
handle_sfp();
|
||||
return;
|
||||
err:
|
||||
print_string("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
|
||||
cmd_error("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -997,7 +1133,7 @@ void parse_regget(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: regget <hexvalue>\n\tlike: regget 0BB0 or regget 0c");
|
||||
cmd_error("regget <hexvalue>\n\tlike: regget 0BB0 or regget 0c");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1044,7 +1180,33 @@ void parse_regset(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: regset <hexvalue> <hexvalue>\n\tlike regset 0b abcd1234.");
|
||||
cmd_error("regset <hexvalue> <hexvalue>\n\tlike regset 0b abcd1234.");
|
||||
}
|
||||
|
||||
|
||||
static void print_temperature(uint16_t reg)
|
||||
{
|
||||
int16_t v;
|
||||
|
||||
reg_read(reg);
|
||||
v = SFR_DATA_U16;
|
||||
if (v < 0) {
|
||||
write_char('-');
|
||||
v = -v;
|
||||
}
|
||||
itoa(v >> 7);
|
||||
write_char('.');
|
||||
itoa(((v & 0x7f) * 10) >> 7);
|
||||
print_string(" C\n");
|
||||
}
|
||||
|
||||
|
||||
void parse_temp(void)
|
||||
{
|
||||
print_string("\nChip temperature: ");
|
||||
print_temperature(RTL837X_TM_RESULT);
|
||||
print_string("At power-on: ");
|
||||
print_temperature(RTL837X_TM_RESULT_POWERON);
|
||||
}
|
||||
|
||||
|
||||
@@ -1087,7 +1249,7 @@ void parse_sdsget(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: sdsget <sds-id> <hex:page> <hex:reg>\n");
|
||||
cmd_error("sdsget <sds-id> <hex:page> <hex:reg>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1143,7 +1305,7 @@ void parse_sdsset(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: sdsset <sds-id> <hex:page> <hex:reg> <hex:val>\n");
|
||||
cmd_error("sdsset <sds-id> <hex:page> <hex:reg> <hex:val>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1192,7 +1354,7 @@ void parse_phyget(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: phyget <phy-id> <dev-id> <hex:reg>\n");
|
||||
cmd_error("phyget <phy-id> <dev-id> <hex:reg>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1252,7 +1414,7 @@ void parse_physet(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: physet <phy-id> <dev-id> <hex:reg> <hex:val>\n");
|
||||
cmd_error("physet <phy-id> <dev-id> <hex:reg> <hex:val>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1287,7 +1449,7 @@ void parse_passwd(void)
|
||||
passwd[j] = NUL;
|
||||
return;
|
||||
}
|
||||
print_string("Missing password\n");
|
||||
cmd_error("Missing password\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1310,8 +1472,8 @@ void parse_eee(void)
|
||||
speed_word = 2;
|
||||
} else if (cmd_is_space_or_nul(idx)) {
|
||||
// Word 2 is a port number
|
||||
if (cmd_parse_port_separator(idx) == 0) {
|
||||
print_string("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
if (cmd_parse_port_separator(cmd_words_b[2]) == 0) {
|
||||
cmd_error("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
return;
|
||||
}
|
||||
port = atoi_results_u8;
|
||||
@@ -1330,7 +1492,7 @@ void parse_eee(void)
|
||||
speed = EEE_2G5;
|
||||
else
|
||||
{
|
||||
print_string("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
cmd_error("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1350,7 +1512,7 @@ void parse_eee(void)
|
||||
else
|
||||
port_eee_status_all();
|
||||
} else {
|
||||
print_string("eee [on|off|status] [port] [100m|1g|2g5]\n");
|
||||
cmd_error("eee [on|off|status] [port] [100m|1g|2g5]\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,7 +1583,58 @@ void parse_bw(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
||||
cmd_error("bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
||||
}
|
||||
|
||||
static __code const char * __code const storm_types[STORM_TYPES] = { "bcast", "mcast", "ucast", "umcast" };
|
||||
|
||||
void parse_storm(void)
|
||||
{
|
||||
uint8_t port, type, d;
|
||||
__xdata uint32_t rate;
|
||||
__xdata uint8_t *p;
|
||||
|
||||
if (cmd_words_len == 1)
|
||||
return storm_show();
|
||||
if (cmd_words_len < 4 || !cmd_parse_port_separator(cmd_words_b[1]))
|
||||
goto err;
|
||||
port = atoi_results_u8;
|
||||
|
||||
type = 0;
|
||||
while (!cmd_compare(2, storm_types[type])) {
|
||||
if (++type == STORM_TYPES)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (cmd_words_len == 4 && cmd_compare(3, "off"))
|
||||
return storm_off(port, type);
|
||||
if (cmd_words_len != 5)
|
||||
goto err;
|
||||
|
||||
rate = 0;
|
||||
p = &cmd_buffer[cmd_words_b[3]];
|
||||
do {
|
||||
d = *p++ - '0';
|
||||
if (d > 9 || rate > 99999999)
|
||||
goto err;
|
||||
rate = (rate << 3) + (rate << 1) + d;
|
||||
} while (*p != ' ' && *p != NUL);
|
||||
|
||||
if (cmd_compare(4, "pps")) {
|
||||
if (!rate || rate > 0xfffff)
|
||||
goto err;
|
||||
storm_set(port, type, rate, 1);
|
||||
} else if (cmd_compare(4, "kbps")) {
|
||||
if (!rate || rate > 10000000)
|
||||
goto err;
|
||||
storm_set(port, type, rate, 0);
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: storm [<port> bcast|mcast|ucast|umcast <rate> pps|kbps|off]\n");
|
||||
}
|
||||
|
||||
void parse_syslog(void)
|
||||
@@ -1459,7 +1672,7 @@ void parse_syslog(void)
|
||||
if (was_enabled)
|
||||
syslog_start();
|
||||
} else {
|
||||
print_string("Invalid IP address\n");
|
||||
cmd_error("Invalid IP address\n");
|
||||
}
|
||||
} else if (cmd_compare(1, "port")) {
|
||||
if (cmd_words_len < 3) { // no additional argument -> print current port
|
||||
@@ -1470,7 +1683,7 @@ void parse_syslog(void)
|
||||
/* atoi_short() returns zero for no digits and for a value past
|
||||
* 65535; port zero is not a port either, so both tests are needed. */
|
||||
if (!atoi_short(cmd_words_b[2]) || !atoi_results_short) {
|
||||
print_string("Invalid port\n");
|
||||
cmd_error("Invalid port\n");
|
||||
return;
|
||||
}
|
||||
/* The port is frozen into the connection by uip_udp_new(), so
|
||||
@@ -1486,12 +1699,31 @@ void parse_syslog(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
print_string("Error: syslog [on|off|ip [ip-address]|port [number]]\n");
|
||||
print_string(" on/off enables or disables syslog, ip sets the syslog server IP address,\n");
|
||||
print_string(" port sets the destination UDP port (default 514)\n");
|
||||
cmd_error("syslog [on|off|ip [ip-address]|port [number]]\n"
|
||||
" on/off enables or disables syslog, ip sets the syslog server IP address,\n"
|
||||
" port sets the destination UDP port (default 514)\n");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_session(void)
|
||||
{
|
||||
if (cmd_words_len >= 2) {
|
||||
/* atoi_short() returns zero for no digits and for a value past
|
||||
* 65535; a zero-second timeout is not useful either, so both
|
||||
* tests are needed. */
|
||||
if (!atoi_short(cmd_words_b[1]) || !atoi_results_short) {
|
||||
print_string("Must be 1-65535 s\n");
|
||||
return;
|
||||
}
|
||||
session_timeout = atoi_results_short;
|
||||
}
|
||||
/* Also the confirmation after setting: one message for both. */
|
||||
print_string("Session timeout: ");
|
||||
itoa_short(session_timeout);
|
||||
print_string(" s\n");
|
||||
}
|
||||
|
||||
|
||||
// Parse command into words
|
||||
// cmd_words_len contains the number of words found.
|
||||
// cmd_words_b[] contains only start of a word offset.
|
||||
@@ -1656,7 +1888,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Setting ip: ");
|
||||
print_ip(ip); write_char('\n');
|
||||
} else {
|
||||
print_string("Invalid IP address\n" \
|
||||
cmd_error("Invalid IP address\n" \
|
||||
"Error: ip [<ip-address>|dhcp]\n" \
|
||||
" The dhcp option enables the dhcp client, calling ip without options prints the current IP\n" \
|
||||
" Calling with a valid IP address will stop any ongoing dhcp client and set the IP address\n");
|
||||
@@ -1672,7 +1904,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Setting gw: ");
|
||||
print_ip(ip); write_char('\n');
|
||||
} else {
|
||||
print_string("Invalid IP address\n" \
|
||||
cmd_error("Invalid IP address\n" \
|
||||
"Error: gw <ip-address>\n");
|
||||
}
|
||||
}
|
||||
@@ -1686,7 +1918,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Setting netmask: ");
|
||||
print_ip(ip); write_char('\n');
|
||||
} else {
|
||||
print_string("Invalid IP address\n");
|
||||
cmd_error("Invalid IP address\n");
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
@@ -1702,8 +1934,11 @@ void cmd_parser(void) __banked
|
||||
igmp_setup();
|
||||
else if (cmd_compare(1, "show"))
|
||||
igmp_show();
|
||||
else
|
||||
print_string("Error: igmp on|off|show\n");
|
||||
else {
|
||||
cmd_error("igmp on|off|show\n");
|
||||
}
|
||||
} else if (cmd_compare(0, "mac")) {
|
||||
parse_mac_cmd();
|
||||
} else if (cmd_compare(0, "hostname")) {
|
||||
/* "hostname" alone reports the current name; "hostname <text>"
|
||||
* sets it, sanitized to JSON-safe printable ASCII. A name with
|
||||
@@ -1719,22 +1954,25 @@ void cmd_parser(void) __banked
|
||||
uint8_t c = *hp++;
|
||||
if (c == NUL || c == '\r' || c == '\n')
|
||||
break;
|
||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||
c = '.';
|
||||
*dst++ = c;
|
||||
*dst++ = name_char(c);
|
||||
}
|
||||
*dst = NUL;
|
||||
} else {
|
||||
print_string("Error: hostname [name] - the name must not contain spaces\n");
|
||||
cmd_error("hostname [name] - the name must not contain spaces\n");
|
||||
}
|
||||
} else if (cmd_compare(0, "stp")) {
|
||||
stp_parse();
|
||||
#ifdef HEALTH
|
||||
} else if (cmd_compare(0, "health")) {
|
||||
health_show();
|
||||
#endif
|
||||
} else if (cmd_compare(0, "pvid")) {
|
||||
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)
|
||||
port_pvid_set(atoi_results_u8, atoi_results_short);
|
||||
else
|
||||
print_string("Error: pvid <port> <1-4094>\n");
|
||||
else {
|
||||
cmd_error("pvid <port> <1-4094>\n");
|
||||
}
|
||||
} else if (cmd_compare(0, "vlan")) {
|
||||
parse_vlan();
|
||||
} else if (cmd_compare(0, "isolate")) {
|
||||
@@ -1750,6 +1988,8 @@ void cmd_parser(void) __banked
|
||||
write_char('\n');
|
||||
} else if (cmd_compare(0, "gpio")) {
|
||||
print_gpio_status();
|
||||
} else if (cmd_compare(0, "leds")) {
|
||||
leds_dump();
|
||||
} else if (cmd_compare(0, "regget")) {
|
||||
parse_regget();
|
||||
} else if (cmd_compare(0, "regset")) {
|
||||
@@ -1770,6 +2010,10 @@ void cmd_parser(void) __banked
|
||||
parse_eee();
|
||||
} else if (cmd_compare(0, "bw")) {
|
||||
parse_bw();
|
||||
} else if (cmd_compare(0, "temp")) {
|
||||
parse_temp();
|
||||
} else if (cmd_compare(0, "storm")) {
|
||||
parse_storm();
|
||||
} else if (cmd_compare(0, "version")) {
|
||||
print_sw_version();
|
||||
} else if (cmd_compare(0, "time")) {
|
||||
@@ -1792,13 +2036,23 @@ void cmd_parser(void) __banked
|
||||
}
|
||||
} else if (cmd_compare(0, "ingress")) {
|
||||
parse_ingress();
|
||||
} else if (cmd_compare(0, "session")) {
|
||||
parse_session();
|
||||
} else if (cmd_compare(0, "lldp")) {
|
||||
if (cmd_compare(1, "on")) {
|
||||
print_string("LLDP enabled\n");
|
||||
lldp_enabled = 1;
|
||||
} else {
|
||||
print_string("LLDP disabled\n");
|
||||
lldp_enabled = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print_string("Unknown command\n");
|
||||
cmd_error("Unknown command\n");
|
||||
}
|
||||
|
||||
|
||||
if (save_cmd && cmd_words_len) {
|
||||
if (save_cmd && cmd_words_len && err_status == ERR_OK) {
|
||||
// Find end of the cmd-buffer, looking for the NUL-byte.
|
||||
uint8_t i = cmd_words_b[cmd_words_len - 1];
|
||||
do {
|
||||
@@ -1843,6 +2097,7 @@ void execute_config(void) __banked
|
||||
save_cmd = 0;
|
||||
|
||||
uint8_t cmd_idx = 0;
|
||||
uint8_t skipping = 0;
|
||||
do {
|
||||
flash_region.addr = pos;
|
||||
flash_region.len = FLASH_READ_BURST_SIZE;
|
||||
@@ -1853,20 +2108,23 @@ void execute_config(void) __banked
|
||||
do {
|
||||
if (cmd_idx >= (CMD_BUF_SIZE - 1)) {
|
||||
cmd_buffer[cmd_idx] = NUL;
|
||||
print_string("ERROR: Command too long: ");
|
||||
print_string("ERROR: Command too long, skipped: ");
|
||||
print_string_x(cmd_buffer);
|
||||
write_char('\n');
|
||||
err_status = ERR_CMD_TOO_LONG;
|
||||
goto config_done;
|
||||
cmd_idx = 0;
|
||||
skipping = 1;
|
||||
}
|
||||
c = flash_buf[cfg_idx++];
|
||||
if (c == 0 || c == '\n') {
|
||||
cmd_buffer[cmd_idx] = NUL;
|
||||
if (cmd_idx) {
|
||||
cmd_tokenize();
|
||||
if (err_status != ERR_OK)
|
||||
goto config_done;
|
||||
cmd_parser();
|
||||
if (skipping) {
|
||||
skipping = 0;
|
||||
} else {
|
||||
cmd_buffer[cmd_idx] = NUL;
|
||||
if (cmd_idx) {
|
||||
cmd_tokenize();
|
||||
if (err_status == ERR_OK)
|
||||
cmd_parser();
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
goto config_done;
|
||||
@@ -1874,8 +2132,10 @@ void execute_config(void) __banked
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd_buffer[cmd_idx] = c;
|
||||
cmd_idx++;
|
||||
if (!skipping) {
|
||||
cmd_buffer[cmd_idx] = c;
|
||||
cmd_idx++;
|
||||
}
|
||||
} while (cfg_idx);
|
||||
|
||||
pages_left--;
|
||||
@@ -1892,6 +2152,7 @@ config_done:
|
||||
// If a command is too long or can't be tokenized, remaining commands are not executed
|
||||
// Returns the status via `err_status`-variable.
|
||||
void execute_commands(__xdata uint8_t *p) __banked {
|
||||
__xdata uint8_t failed = ERR_OK;
|
||||
err_status = ERR_OK;
|
||||
uint8_t cmd_idx = 0;
|
||||
while (1) {
|
||||
@@ -1902,9 +2163,13 @@ void execute_commands(__xdata uint8_t *p) __banked {
|
||||
if (err_status != ERR_OK)
|
||||
return;
|
||||
cmd_parser();
|
||||
if (failed == ERR_OK)
|
||||
failed = err_status;
|
||||
}
|
||||
if (*p == 0)
|
||||
if (*p == 0) {
|
||||
err_status = failed;
|
||||
return;
|
||||
}
|
||||
cmd_idx = 0;
|
||||
} else {
|
||||
if (cmd_idx < (CMD_BUF_SIZE - 1)) {
|
||||
@@ -1921,3 +2186,161 @@ void execute_commands(__xdata uint8_t *p) __banked {
|
||||
p++;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef HEALTH
|
||||
/*
|
||||
* Health instrumentation. The counters live in xdata and are fed from the
|
||||
* main loop through the banked entry points below; the "health" command
|
||||
* prints everything in one go. All figures are raw hex, diffing two dumps
|
||||
* gives the rates. Phase times are in system ticks (SYS_TICK_HZ = 200,
|
||||
* 5 ms each); a phase counts as slow when it spans 2 or more ticks.
|
||||
*/
|
||||
extern __xdata uint16_t len_left; /* httpd: bytes still to send of the current file */
|
||||
extern __xdata uint8_t entry; /* httpd: index of the file being sent */
|
||||
|
||||
static __xdata uint32_t health_loops;
|
||||
__xdata uint16_t health_rx_frames;
|
||||
|
||||
static __xdata uint16_t ph_last_t;
|
||||
static __xdata uint8_t ph_max[HEALTH_PHASES];
|
||||
static __xdata uint16_t ph_slow[HEALTH_PHASES];
|
||||
|
||||
/* The ISR increments ticks between the two byte reads of a 16-bit load, so
|
||||
* read until two loads agree. */
|
||||
static uint16_t ticks_lo(void)
|
||||
{
|
||||
uint16_t a, b;
|
||||
a = (uint16_t)ticks;
|
||||
do {
|
||||
b = a;
|
||||
a = (uint16_t)ticks;
|
||||
} while (a != b);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void health_loop_start(void) __banked
|
||||
{
|
||||
health_loops++;
|
||||
ph_last_t = ticks_lo();
|
||||
}
|
||||
|
||||
|
||||
void health_phase(uint8_t id) __banked
|
||||
{
|
||||
__xdata uint16_t now = ticks_lo();
|
||||
__xdata uint16_t d = now - ph_last_t;
|
||||
ph_last_t = now;
|
||||
if (d > 0xff)
|
||||
d = 0xff;
|
||||
if ((uint8_t)d > ph_max[id])
|
||||
ph_max[id] = d;
|
||||
if (d >= 2)
|
||||
ph_slow[id]++;
|
||||
}
|
||||
|
||||
|
||||
/* Fill the stack area above the current frame with a pattern; the dump scans
|
||||
* for how much of it survived. The 8051 stack grows upward, so everything
|
||||
* above SP is free at this point. Interrupts are held off so an ISR does not
|
||||
* push into the area mid-paint. */
|
||||
void health_stack_paint(void) __banked
|
||||
{
|
||||
__xdata uint8_t from = SP + 4;
|
||||
__xdata uint8_t ea = EA;
|
||||
EA = 0;
|
||||
for (uint8_t i = 0xff; i >= from; i--)
|
||||
*(__idata uint8_t *)i = 0xa5;
|
||||
EA = ea;
|
||||
}
|
||||
|
||||
|
||||
static void ph_line(__code const char *name, uint8_t id)
|
||||
{
|
||||
print_string(name);
|
||||
print_string(" max ");
|
||||
print_byte(ph_max[id]);
|
||||
print_string(" slow ");
|
||||
print_short(ph_slow[id]);
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
void health_show(void) __banked
|
||||
{
|
||||
__xdata uint8_t i;
|
||||
|
||||
print_string("up ");
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
print_string(" ticks ");
|
||||
print_long(ticks);
|
||||
print_string(" loops ");
|
||||
print_long(health_loops);
|
||||
print_string(" rx ");
|
||||
print_short(health_rx_frames);
|
||||
write_char('\n');
|
||||
|
||||
/* Phase timing: max duration seen (ticks of 5 ms) and slow-pass count */
|
||||
ph_line("link", HEALTH_PH_LINK);
|
||||
ph_line("sfp ", HEALTH_PH_SFP);
|
||||
ph_line("rx ", HEALTH_PH_RX);
|
||||
ph_line("tx ", HEALTH_PH_TX);
|
||||
ph_line("stp ", HEALTH_PH_STP);
|
||||
ph_line("cmd ", HEALTH_PH_CMD);
|
||||
|
||||
/* Stack: current depth plus how much of the painted area is untouched */
|
||||
print_string("sp ");
|
||||
print_byte(SP);
|
||||
print_string(" untouched ");
|
||||
i = 0;
|
||||
while (*(__idata uint8_t *)(0xff - i) == 0xa5 && i < 0x86)
|
||||
i++;
|
||||
print_byte(i);
|
||||
write_char('\n');
|
||||
|
||||
/* The TCP connection slot. One on this configuration; a build with more
|
||||
* has to say which slot each line is, so make that a visible decision. */
|
||||
#if UIP_CONNS != 1
|
||||
#error "health: the tcp dump prints a single slot, extend it for UIP_CONNS > 1"
|
||||
#endif
|
||||
i = 0;
|
||||
{
|
||||
print_string("tcp ");
|
||||
print_string("st ");
|
||||
print_byte(uip_conns[i].tcpstateflags);
|
||||
print_string(" tmr ");
|
||||
print_byte(uip_conns[i].timer);
|
||||
print_string(" rtx ");
|
||||
print_byte(uip_conns[i].nrtx);
|
||||
print_string(" rto ");
|
||||
print_byte(uip_conns[i].rto);
|
||||
print_string(" len ");
|
||||
print_short(uip_conns[i].len);
|
||||
print_string(" mss ");
|
||||
print_short(uip_conns[i].mss);
|
||||
write_char('\n');
|
||||
print_string(" lport ");
|
||||
print_short(HTONS(uip_conns[i].lport));
|
||||
print_string(" rport ");
|
||||
print_short(HTONS(uip_conns[i].rport));
|
||||
print_string(" rip ");
|
||||
print_short(HTONS(uip_conns[i].ripaddr[0]));
|
||||
write_char(' ');
|
||||
print_short(HTONS(uip_conns[i].ripaddr[1]));
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
/* httpd transfer state and the protocol flags */
|
||||
print_string("httpd left ");
|
||||
print_short(len_left);
|
||||
print_string(" entry ");
|
||||
print_byte(entry);
|
||||
print_string(" stp ");
|
||||
print_byte(stp_enabled);
|
||||
print_string(" mvlan ");
|
||||
print_short(management_vlan);
|
||||
write_char('\n');
|
||||
}
|
||||
#endif
|
||||
@@ -6,14 +6,42 @@
|
||||
#include "rtl837x_common.h"
|
||||
|
||||
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
extern __xdata uint8_t cmd_available;
|
||||
extern __bit __at(0x03) cmd_available;
|
||||
extern __xdata uint8_t err_status;
|
||||
|
||||
/* Health instrumentation, built with HEALTH=1. Without it the hooks below
|
||||
* compile to nothing and the "health" command does not exist. */
|
||||
#ifdef HEALTH
|
||||
/* Phase ids, in main-loop order */
|
||||
#define HEALTH_PH_LINK 0
|
||||
#define HEALTH_PH_SFP 1
|
||||
#define HEALTH_PH_RX 2
|
||||
#define HEALTH_PH_TX 3
|
||||
#define HEALTH_PH_STP 4
|
||||
#define HEALTH_PH_CMD 5
|
||||
#define HEALTH_PHASES 6
|
||||
#define HEALTH_LLDP 7
|
||||
|
||||
extern __xdata uint16_t health_rx_frames;
|
||||
#define health_rx_frame() health_rx_frames++
|
||||
|
||||
void health_loop_start(void) __banked; /* once per idle() pass, resets the phase baseline */
|
||||
void health_phase(uint8_t id) __banked; /* after each phase; accounts ticks since last checkpoint */
|
||||
void health_stack_paint(void) __banked; /* paint the unused stack area once at boot */
|
||||
void health_show(void) __banked; /* "health" CLI dump */
|
||||
#else
|
||||
#define health_rx_frame()
|
||||
#define health_loop_start()
|
||||
#define health_phase(id)
|
||||
#define health_stack_paint()
|
||||
#endif
|
||||
|
||||
void cmd_tokenize(void) __banked;
|
||||
void cmd_parser(void) __banked;
|
||||
void execute_config(void) __banked;
|
||||
void execute_commands(__xdata uint8_t *p) __banked;
|
||||
void print_ip(__xdata uint8_t *ptr);
|
||||
void print_ip(__xdata uint8_t *ptr) __banked;
|
||||
void print_mac(__xdata uint8_t *ptr) __banked;
|
||||
void print_sw_version(void) __banked;
|
||||
void clear_command_history(void) __banked;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ __xdata uip_ipaddr_t server;
|
||||
#define DHCP_PARAM_DNS 6
|
||||
#define DHCP_END 255
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK2
|
||||
|
||||
struct dhcp_pkt {
|
||||
@@ -139,7 +139,6 @@ void dhcp_addopt_request_ip(void)
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,13 +150,11 @@ void dhcp_addopt_server_id(void)
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||
}
|
||||
|
||||
|
||||
void dhcp_send_discover(void)
|
||||
{
|
||||
print_string("dhcp_send_discover called\n");
|
||||
dhcp_prepare_request();
|
||||
|
||||
dhcp_state.opt_ptr = 0;
|
||||
@@ -193,7 +190,6 @@ void dhcp_send_discover(void)
|
||||
|
||||
void dhcp_send_request(void)
|
||||
{
|
||||
print_string("dhcp_send_request called\n");
|
||||
dhcp_prepare_request();
|
||||
|
||||
dhcp_state.opt_ptr = 0;
|
||||
@@ -232,19 +228,21 @@ void ip_opt(__xdata uint8_t * ip)
|
||||
{
|
||||
dhcp_state.opt_ptr++;
|
||||
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
if (len >= 4)
|
||||
memcpy(ip, &DHCP_OPT[dhcp_state.opt_ptr], 4);
|
||||
// There may be more than one IP option, such as 2 DNS servers advertised
|
||||
dhcp_state.opt_ptr += len - 4;
|
||||
dhcp_state.opt_ptr += len;
|
||||
}
|
||||
|
||||
|
||||
void long_opt(void)
|
||||
uint8_t long_opt(void)
|
||||
{
|
||||
dhcp_state.opt_ptr++;
|
||||
dhcp_state.opt_ptr++;
|
||||
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
if (len < 4) {
|
||||
dhcp_state.opt_ptr += len;
|
||||
return 0;
|
||||
}
|
||||
long_value = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
long_value <<= 8;
|
||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
@@ -252,6 +250,8 @@ void long_opt(void)
|
||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
long_value <<= 8;
|
||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
dhcp_state.opt_ptr += len - 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -275,16 +275,16 @@ void parse_opts(void)
|
||||
ip_opt(&dhcp_state.broadcast[0]);
|
||||
break;
|
||||
case DHCP_LEASE:
|
||||
long_opt();
|
||||
dhcp_state.lease = long_value;
|
||||
if (long_opt())
|
||||
dhcp_state.lease = long_value;
|
||||
break;
|
||||
case DHCP_REBIND:
|
||||
long_opt();
|
||||
dhcp_state.rebind = long_value;
|
||||
if (long_opt())
|
||||
dhcp_state.rebind = long_value;
|
||||
break;
|
||||
case DHCP_RENEWAL:
|
||||
long_opt();
|
||||
dhcp_state.renewal = long_value;
|
||||
if (long_opt())
|
||||
dhcp_state.renewal = long_value;
|
||||
break;
|
||||
case DHCP_END:
|
||||
break;
|
||||
@@ -376,13 +376,11 @@ void dhcp_start(void) __banked
|
||||
*tid++ = SFR_DATA_8;
|
||||
*tid = SFR_DATA_0;
|
||||
dhcp_state.state = DHCP_START;
|
||||
print_string("dhcp_start done\n");
|
||||
}
|
||||
|
||||
|
||||
void dhcp_stop(void) __banked
|
||||
{
|
||||
print_string("dhcp_stop called\n");
|
||||
uip_udp_remove(dhcp_state.conn);
|
||||
dhcp_state.state = DHCP_OFF;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
### 2M-PCB23-V3.2
|
||||
|
||||
## Brands
|
||||
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||
|---|---|---|---|---|---|
|
||||
| keepLINK | KP-9000-9XHML-X | Yes| 2M-PCB23-V3.2 | 2M (Winbond 25Q) | |
|
||||
|
||||
The original web interface reports this board as hardware version V3.2
|
||||
(original firmware V100.9.25, January 2026).
|
||||
|
||||
## PCB
|
||||
|
||||
<img src="photos/2M-PCB23-V3.2-managed/2M-PCB23-V3.2-top.jpeg" width="300" />
|
||||
|
||||
## Compared to V3.1
|
||||
|
||||
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
|
||||
LED, and the unpopulated U7/U9 footprints. Build with
|
||||
`MACHINE=KP_9000_9XHML_X_V3_2`, which uses the V3.1 machine definition and
|
||||
only differs in the reported name.
|
||||
|
||||
## Tested
|
||||
|
||||
Installed from the original firmware through its web interface with
|
||||
`installer/output/rtlplayground_oem_upgrade.bin`, then:
|
||||
|
||||
- RJ45 ports link at 2.5G; LEDs: orange at 2.5G, green below
|
||||
- SFP port: module detected with vendor/model/serial and DOM readings
|
||||
(temperature, Vcc, TX bias, TX/RX power), link up at 10G
|
||||
- factory MAC read from flash (0x1FC000)
|
||||
- reset button (GPIO48): held for more than 10 s it restores the default config
|
||||
|
||||
## Flash access
|
||||
|
||||
Reading the flash in-circuit with a SOIC-8 clip did not work: the chip ID
|
||||
comes back as `EF FF FF` (only the manufacturer byte is right) and reads
|
||||
return 0xff, the same as on a V3.1 board. The switch chip is powered through
|
||||
the clip and keeps driving the SPI lines. Make sure a way back is acceptable
|
||||
before installing, or hold the switch chip in reset while reading.
|
||||
@@ -0,0 +1,32 @@
|
||||
# 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.
|
||||
|
||||
## Brands
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|--------|------------------|-------|------------------|-----------------|---------------|
|
||||
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
|
||||
|
||||
## Hardware overview
|
||||
Front
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-front.jpg" width="300" />
|
||||
|
||||
Label
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-label.jpg" width="300" />
|
||||
|
||||
The stock firmware from a POE-2G080110GS device had a sha256sum of `4c280853465eaad80e1772075c0f2d29c11fb8c561547f06353d3a5443c388e9`.
|
||||
|
||||
### PCB
|
||||
|
||||
Top silkscreen is marked `2M-PCB51-ML-V1.1`. PoE is provided by RTL8238C. Flash chip is 4 MB Winbond 25Q32JV (U8).
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-pcb.jpg" width="300" />
|
||||
|
||||
> [!CAUTION]
|
||||
> This device operates on mains voltage, which can be a dangerous or potentially lethal hazard. Even after the device is unplugged, high-voltage capacitors can remain charged afterward and may still shock you. Do not attempt to open/disassemble a mains powered device unless you understand how to do so safely. Also, opening the device may void your warranty.
|
||||
|
||||
## Notes
|
||||
|
||||
The stock firmware blinks both the 2.5G and 1G LEDs on activity, despite the front of the device indicating that each LED should be independent. The `POE_2G080110GS` machine config behaves as the front of the device indicates (and what seems more logical) -- each port LED turns on and blinks independently.
|
||||
@@ -0,0 +1,70 @@
|
||||
# F7008-2.5
|
||||
|
||||
Documentation for the unmanaged 8 + 1 switch sold as `7018-2.5G` by Guangnianwei
|
||||
(光年微), board marking `F7008-2.5`, PCB `F7008-2.5GPOE-V1.2`.
|
||||
|
||||
### Brands
|
||||
|
||||
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||
|-------|------|---------|-----|-------|----------|
|
||||
| Guangnianwei (光年微) | 7018-2.5G | No | F7008-2.5GPOE-V1.2 | W25Q64JVSSIQ | 8373N + 8224N |
|
||||
|
||||
### What works
|
||||
|
||||
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||
- SFP+ port with 1G/2.5G/10G modules
|
||||
- LEDs of the eight RJ45 ports
|
||||
|
||||
### Not verified
|
||||
|
||||
- The LED pads for the SFP+ cage are not mapped yet. The SFP+ lamps are left
|
||||
undriven, so an inserted module lights nothing.
|
||||
- The UART header footprint is present but unpopulated, and no boot log could be
|
||||
captured from it, so the baud rate is unknown. There are most likely
|
||||
unpopulated 0-Ohm resistors next to the header; bridging those should bring
|
||||
the console to life.
|
||||
|
||||
### Build target
|
||||
|
||||
```
|
||||
make MACHINE=F7008_2_5
|
||||
```
|
||||
|
||||
### LED wiring
|
||||
|
||||
Measured pad to lamp map (`led_mux` index -> lamp):
|
||||
|
||||
| Port | green lamp | yellow lamp |
|
||||
|------|-----------|-------------|
|
||||
| 1 | pad 0 | pad 1 |
|
||||
| 2 | pad 2 | pad 3 |
|
||||
| 3 | pad 4 | pad 5 |
|
||||
| 4 | pad 6 | pad 8 |
|
||||
| 5 | pad 9 | pad 10 |
|
||||
| 6 | pad 12 | pad 15 |
|
||||
| 7 | pad 18 | pad 21 |
|
||||
| 8 | pad 24 | pad 25 |
|
||||
|
||||
Pads 7, 11, 13, 14, 16, 17, 19, 20, 22, 23, 26 and 27 do not drive an RJ45 lamp.
|
||||
|
||||
The front panel is silkscreened `2.5G: Green / 10/100M: Yellow`, and the target
|
||||
follows it: the green lamp is on while the port is linked at 2.5G, the yellow
|
||||
lamp blinks while data is flowing.
|
||||
|
||||
### PCB overview
|
||||
|
||||
The board is marked `F7008-2.5GPOE-V1.2`.
|
||||
|
||||
Top side:
|
||||
|
||||
<img src="photos/F7008-2.5/PCB-top.jpg" width="600" />
|
||||
|
||||
Bottom side:
|
||||
|
||||
<img src="photos/F7008-2.5/PCB-bottom.jpg" width="600" />
|
||||
|
||||
### Hardware notes
|
||||
|
||||
- 4 x `RT4802SNE` magnetics
|
||||
- Unpopulated UART header footprint, next to the magnetics
|
||||
- Power input 12V 1A, 180 x 84 x 29 mm metal case
|
||||
@@ -0,0 +1,75 @@
|
||||
# Hasivo S1100WP-8GT-1SX-SE
|
||||
|
||||
RTL8373-based 8×2.5G PoE + 1×SFP switch.
|
||||
|
||||
### Label specifications
|
||||
|
||||
- **Manufacturer**: Hasivo
|
||||
- **Model**: S1100WP-8GT-1SX-SE
|
||||
- **Ports**:
|
||||
- 8 × RJ45: 10/100/1000/2500 Mbps with PoE
|
||||
- 1 × SFP: 1G / 2.5G / 10G
|
||||
- **Power input**: DC 52V 2.5A
|
||||
- **Stock firmware defaults**: IP 192.168.0.1, user/password `admin`/`admin`
|
||||
|
||||
### 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 copper port; combined link/act on the SFP port
|
||||
|
||||
### Photos
|
||||
|
||||
Front panel:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/front.jpg" width="600" />
|
||||
|
||||
Label:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/label.jpg" width="600" />
|
||||
|
||||
### PCB overview
|
||||
|
||||
Top side:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/pcb_top.jpg" width="600" />
|
||||
|
||||
Bottom side:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/pcb_bottom.jpg" width="600" />
|
||||
|
||||
### Port layout
|
||||
|
||||
| Logical port | Physical port | Type |
|
||||
|--------------|---------------|--------|
|
||||
| 1-8 | 1-8 | Copper |
|
||||
| 9 | 9 | SFP |
|
||||
|
||||
### LED configuration
|
||||
|
||||
Copper ports use LED SET0, the SFP port uses LED SET1.
|
||||
|
||||
| SET | LED0 | LED2 |
|
||||
|------|-----------------------------------------------|------------------------------------------------------|
|
||||
| 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 | — |
|
||||
|
||||
### SFP GPIO assignments
|
||||
|
||||
| SFP (logical 9) | pin_detect (ModAbs) | pin_los | pin_tx_disable | SerDes | I2C SDA | I2C SCL |
|
||||
|-----------------|---------------------|---------|----------------|--------|-----------------|---------------------|
|
||||
| SFP | GPIO30_ACL_BIT3_EN | GPIO37 | GPIO_NA | SDS1 | GPIO39_I2C_SDA4 | GPIO40_I2C_SCL3_MDC1 |
|
||||
|
||||
### Machine configuration
|
||||
|
||||
- `reset_pin`: GPIO54_ACL_BIT2_EN
|
||||
- High LEDs (pads 27-29): mux = `LED_27 | LED_28_SYS | LED_29`, enable = `LED_28_SYS | LED_29`
|
||||
|
||||
### PoE
|
||||
|
||||
The 8 copper ports support PoE powered by a DC 52V 2.5A input. Power management is handled by two HS104PTI chipsets over I2C (GPIO47_I2C_SDA0, GPIO46_I2C_SCL0):
|
||||
|
||||
* Chip 1 (I2C address 0x1A): 2.5G Ports 1–4
|
||||
* Chip 2 (I2C address 0x2A): 2.5G Ports 5–8
|
||||
|
||||
Note: The current implementation does not yet support PoE management. Consequently, PoE currently operates in standalone mode without software control.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Lianguo HYWS-SGT0108S
|
||||
|
||||
Following is documentation for unmanaged switch marked as `HYWS-SGT0108S`.
|
||||
|
||||
Original software is running UART on 9600 baud rate. Output is very minimal.
|
||||
|
||||
Using SPI clamp in-board is the only method for initial installation and update.
|
||||
|
||||
Stock flash chip is 512KB in size. Consider replacing for update through Web UI.
|
||||
|
||||
- Header for uart is clearly identified.
|
||||
- The red LED act as a powered-on LED.
|
||||
- There is no SYS LED.
|
||||
- There is a footprint for a Reset button. Unpopulated. Unclear if routed back to RTL8373.
|
||||
|
||||
### Label specifications
|
||||
|
||||
- **Name**: 2.5G Ethernet Switch 8+1
|
||||
- **Model**: HYWS-SGT0108S
|
||||
- **Ports**:
|
||||
- 8 × RJ45: 10/100/1000/2500 Mbps
|
||||
- 1 × SFP: 1000 / 2500 / 10000 Mbps
|
||||
|
||||
### What works
|
||||
|
||||
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||
- SFP port supporting 1G, 2.5G and 10G modules
|
||||
- RJ45 LEDs (Blue+White)
|
||||
- SFP Single LED (Blue)
|
||||
|
||||
### Assembled unit
|
||||
|
||||
Top side
|
||||
|
||||
<img src="photos/HYWS-SGT0108S-unmanaged\Assembled-top.jpg" width="300" />
|
||||
|
||||
Front
|
||||
|
||||
<img src="photos/HYWS-SGT0108S-unmanaged\Assembled-front.jpg" width="300" />
|
||||
|
||||
Bottom
|
||||
|
||||
<img src="photos/HYWS-SGT0108S-unmanaged\Assembled-bottom.jpg" width="300" />
|
||||
|
||||
### PCB overview
|
||||
|
||||
**Board markings**
|
||||
- Top silkscreen: 2G5F_20G_V1.01 / 2023-09-28
|
||||
|
||||
Top side
|
||||
|
||||
<img src="photos/HYWS-SGT0108S-unmanaged\PCB-top.jpg" width="300" />
|
||||
|
||||
Bottom
|
||||
|
||||
<img src="photos/HYWS-SGT0108S-unmanaged\PCB-bot.jpg" width="300" />
|
||||
|
||||
Original SPI Flash Chip
|
||||
|
||||
<img src="photos/HYWS-SGT0108S-unmanaged\og_spi_flash.jpg" width="300" />
|
||||
|
||||
## Power supply
|
||||
|
||||
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||
@@ -0,0 +1,122 @@
|
||||
# ONT-S207CW-62TS-SE / Binardat 2G06-04210GSM / Binardat 2G06-04210GS
|
||||
|
||||
## Overview
|
||||
|
||||
ONT-S207CW-62TS-SE, Binardat 2G06-04210GSM (managed), and Binardat 2G06-04210GS (unmanaged) are **switches with identical hardware**:
|
||||
- **CPU:** RTL8372N (confirmed via serial: "Detecting CPU: RTL8372N")
|
||||
- **Flash:** GD25Q128E (16MB)
|
||||
- **Ports:** 4x 2.5G RJ45 + 2x 10G SFP+
|
||||
- **Console:** 115200 baud (RTLPlayground firmware) / 9600 baud (stock firmware)
|
||||
|
||||
**Note:** These devices are **RTL8372N-based** with **LAN ports mounted upside-down on the PCB**, requiring a custom configuration. The `MACHINE_ONT_S207CW_62TS_SE` definition uses a **custom configuration** with:
|
||||
- Corrected port mapping (physical ports 1-4 = RJ45, 5-6 = SFP)
|
||||
- Optimized LED sets for different port wiring (RJ45 Ports 1-2 have reversed LED wiring)
|
||||
- Custom LED mux configuration
|
||||
|
||||
## Device Photos
|
||||
|
||||
### Binardat 2G06-04210GSM
|
||||
|
||||
**Front View:**
|
||||
<img src="photos/ONT-S207CW-Binardat-2G06-04210GSM/binardat-2g06-04210gsm-front.jpg" width="400" />
|
||||
|
||||
**Back View:**
|
||||
<img src="photos/ONT-S207CW-Binardat-2G06-04210GSM/binardat-2g06-04210gsm-back.jpg" width="400" />
|
||||
|
||||
**PCB View:**
|
||||
<img src="photos/ONT-S207CW-Binardat-2G06-04210GSM/binardat-2g06-04210gsm-pcb.jpg" width="400" />
|
||||
|
||||
*Photos courtesy of [andreas5232](https://github.com/andreas5232) from [emesix/ONT-S207CW-62TS-SE#1](https://github.com/emesix/ONT-S207CW-62TS-SE/issues/1)*
|
||||
|
||||
## Hardware Specification
|
||||
|
||||
| Feature | Value |
|
||||
|---|---|
|
||||
| **CPU** | RTL8372N |
|
||||
| **Flash** | GD25Q128E (16MB) |
|
||||
| **RAM** | Integrated in RTL8372N |
|
||||
| **RJ45 Ports** | 4x 2.5GBase-T (Ports 1-4) |
|
||||
| **SFP+ Ports** | 2x 10G (Ports 5-6) |
|
||||
| **Console** | UART (115200 baud for RTLPlayground, 9600 baud for stock) |
|
||||
| **Stock Web UI IP** | 192.168.2.1 |
|
||||
| **Loader Mode IP** | 192.168.10.247 |
|
||||
|
||||
## Port Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
|
||||
│ │RJ45 │ │RJ45 │ │RJ45 │ │RJ45 │ │SFP+ │ │SFP+ │ │
|
||||
│ │ 1 │ │ 2 │ │ 3 │ │ 4 │ │ 5 │ │ 6 │ │
|
||||
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
|
||||
│ │
|
||||
│ [System LEDs] │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## LED Behavior
|
||||
|
||||
### RJ45 Ports (Physical 1-4)
|
||||
|
||||
| LED Color | Speed |
|
||||
|---|---|
|
||||
| **Green** | 2.5G |
|
||||
| **Orange** | 1G / 100M / 10M |
|
||||
| **Off** | No link |
|
||||
|
||||
### SFP+ Ports (Physical 5-6)
|
||||
|
||||
| LED Color | Speed |
|
||||
|---|---|
|
||||
| **Green** | 10G |
|
||||
| **Orange** | 2.5G / 1G |
|
||||
| **Off** | No link / No SFP module |
|
||||
|
||||
## Port to Logical Mapping
|
||||
|
||||
Custom mapping for ONT-S207CW-62TS-SE:
|
||||
|
||||
| Physical Port | Logical Port | Type | LED Set |
|
||||
|---|---|---|---|
|
||||
| 1 | 7 | RJ45 | 2 |
|
||||
| 2 | 6 | RJ45 | 2 |
|
||||
| 3 | 5 | RJ45 | 0 |
|
||||
| 4 | 4 | RJ45 | 0 |
|
||||
| 5 | 3 | SFP+ (SDS0) | 3 |
|
||||
| 6 | 8 | SFP+ (SDS1) | 3 |
|
||||
|
||||
**Note:** Ports 1-2 (RJ45) have reversed LED wiring and use LED-Set 2. SFP Ports 5-6 use LED-Set 3 to account for wiring differences.
|
||||
|
||||
## Flashing Instructions
|
||||
|
||||
See the [README.md](../../README.md) for general flashing instructions.
|
||||
|
||||
## Stock Firmware Information
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| **Default IP** | 192.168.2.1 (ONT) / 192.168.10.247 (Loader Mode) |
|
||||
| **Default Login** | admin/admin (may vary by OEM) |
|
||||
| **Console Baud** | 9600 (stock) / 115200 (RTLPlayground) |
|
||||
| **CPU String** | "RTL8372N" |
|
||||
| **Loader Mode IP** | 192.168.10.247 |
|
||||
|
||||
## Configuration Details
|
||||
|
||||
- **CPU:** RTL8372N
|
||||
- **SFP:** SDS0 on logical port 3 (GPIO37), SDS1 on logical port 8 (GPIO38)
|
||||
- **Port Mapping:** Physical 1-4 → Logical 7-4, Physical 5-6 → Logical 3,8
|
||||
- **LED Wiring:** RJ45 Ports 1-2 and SFP Port 6 have reversed LED pins (orange/green swapped)
|
||||
- **LED Sets:** Set 0 for RJ45 Ports 3-4, Set 1 unused, Set 2 for RJ45 Ports 1-2, Set 3 for SFP Ports 5-6
|
||||
|
||||
## Notes
|
||||
|
||||
- ONT-S207CW-62TS-SE, Binardat 2G06-04210GSM (managed), and Binardat 2G06-04210GS (unmanaged) are **RTL8372N-based** with **LAN ports mounted upside-down on the PCB**
|
||||
- Web UI shows correct physical port order (1-2-3-4 for RJ45, 5-6 for SFP)
|
||||
- Loader Mode always remains accessible at `192.168.10.247` for recovery
|
||||
- Serial console: 9600 baud (stock) → 115200 baud (RTLPlayground)
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Issue: emesix/ONT-S207CW-62TS-SE#1](https://github.com/emesix/ONT-S207CW-62TS-SE/issues/1) - Original photos and discussion
|
||||
- [PR: logicog/RTLPlayground#465](https://github.com/logicog/RTLPlayground/pull/465) - Feedback and improvements
|
||||
@@ -0,0 +1,53 @@
|
||||
# IG108
|
||||
|
||||
Following is documentation for unmanaged switch marked as `IG108`.
|
||||
|
||||
Original software is running UART on 9600 baud rate.
|
||||
|
||||
Using SPI clamp in-board is the only method for initial installation.
|
||||
|
||||
### Brands
|
||||
|
||||
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||
|---------|------------|---------|------------|-------------|---------------|
|
||||
| Goalake | IG108 | No | PB-2132 | cFeon Q32A | 8373N + 8224N |
|
||||
| Netcore | GS9 | No | PB-2132 | cFeon Q32A | 8373N + 8224N |
|
||||
|
||||
### What works
|
||||
|
||||
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||
- SFP port with 1G/2.5G/10G modules
|
||||
- LEDs
|
||||
|
||||
### PCB overview
|
||||
|
||||
**Board markings**
|
||||
|
||||
- Top silkscreen: PB-2132
|
||||
|
||||
Front Goalake:
|
||||
|
||||
<img src="photos/PB-2132/case.jpg" width="600" />
|
||||
|
||||
Label Goalake:
|
||||
|
||||
<img src="photos/PB-2132/label.jpg" width="600" />
|
||||
|
||||
Top side:
|
||||
|
||||
<img src="photos/PB-2132/PCB-top.jpg" width="600" />
|
||||
|
||||
Bottom:
|
||||
|
||||
<img src="photos/PB-2132/PCB-bottom.jpg" width="600" />
|
||||
|
||||
### Serial console
|
||||
|
||||
The PCB has unpopulated through-holes near the SFP Port, with description of each pin, works out of the box.
|
||||
|
||||
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
|
||||
|
||||
### Power supply
|
||||
|
||||
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# SWTG018AS-A V2.0
|
||||
## Brands
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|--------|------------------|-------|------------------|-----------------|---------------|
|
||||
| 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 |
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|---------|------------------|-------|------------------|-----------------|---------------|
|
||||
| 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 |
|
||||
| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | ? | 8273N + 8224N |
|
||||
|
||||
|
||||
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
|
||||
|
||||
|
After Width: | Height: | Size: 480 KiB |
|
After Width: | Height: | Size: 519 KiB |
|
After Width: | Height: | Size: 529 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 791 KiB |
|
After Width: | Height: | Size: 760 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 546 KiB |
|
After Width: | Height: | Size: 478 KiB |
|
After Width: | Height: | Size: 639 KiB |
|
After Width: | Height: | Size: 907 KiB |
|
After Width: | Height: | Size: 923 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 360 KiB |
|
After Width: | Height: | Size: 242 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 934 KiB |
@@ -0,0 +1,79 @@
|
||||
# The health command
|
||||
|
||||
`health` prints a one-page snapshot of the firmware's vital signs on the
|
||||
serial console. It exists for the situations where the switch misbehaves and
|
||||
every probe from the network measures the network instead of the device: the
|
||||
dump is taken from inside, costs one command, and works while HTTP does not.
|
||||
|
||||
```
|
||||
> health
|
||||
up 0000001f ticks 0x00001f4c loops 0x000016da rx 0x024e
|
||||
link max 01 slow 0x0000
|
||||
sfp max 74 slow 0x0001
|
||||
rx max 00 slow 0x0000
|
||||
tx max 00 slow 0x0000
|
||||
stp max 04 slow 0x0001
|
||||
cmd max 02 slow 0x0001
|
||||
sp 80 untouched 62
|
||||
tcp st 00 tmr 00 rtx 00 rto 00 len 0x0000 mss 0x05b4
|
||||
lport 0x0000 rport 0x0000 rip 0x0000 0x0000
|
||||
httpd left 0x0000 entry 00 stp 01 mvlan 0x0002
|
||||
```
|
||||
|
||||
The instrumentation is not part of a default build. It costs about 1.1 kB
|
||||
of bank 2, a few bytes of xdata and seven banked calls per main-loop pass,
|
||||
which is nothing a user needs unless they are chasing a problem, so it is
|
||||
switched on at build time:
|
||||
|
||||
```
|
||||
make MACHINE=SWTGW218AS HEALTH=1
|
||||
```
|
||||
|
||||
Without it the hooks compile to nothing and `health` is not a command.
|
||||
|
||||
All figures are raw hex. The counters are cumulative: take two dumps a known
|
||||
time apart and the differences give the rates.
|
||||
|
||||
## The first line
|
||||
|
||||
`up` is the seconds counter, `ticks` the system tick (200 per second),
|
||||
`loops` the number of main-loop passes and `rx` the frames handle_rx has
|
||||
taken off the NIC. A healthy loop completes one pass per tick, so the
|
||||
difference in `loops` tracks the difference in `ticks`; a loop that falls
|
||||
behind is being held up by one of the phases below. The `rx` rate separates
|
||||
a flooded CPU port from a stalled loop, which look identical from outside.
|
||||
|
||||
## Phases
|
||||
|
||||
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.
|
||||
`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
|
||||
names itself here, which is the difference between knowing that the loop is
|
||||
slow and knowing why.
|
||||
|
||||
A dump of its own output takes the console some milliseconds, so running
|
||||
`health` repeatedly increments the `cmd` counters by itself. That is the
|
||||
instrument observing itself, not a fault.
|
||||
|
||||
## Stack
|
||||
|
||||
At boot the free stack area is painted with a pattern. `sp` is the live
|
||||
stack pointer; `untouched` counts the painted bytes still intact at the top,
|
||||
which is the closest thing to a high-water mark this hardware offers. A
|
||||
shrinking `untouched` across dumps means something is reaching deeper than
|
||||
anything before it.
|
||||
|
||||
## The TCP slot
|
||||
|
||||
The connection table is printed whole, one slot per pair of lines: TCP
|
||||
state (3 is ESTABLISHED, 0 closed), retransmission timer and counter, bytes
|
||||
in flight, negotiated MSS, then the ports and the peer address. With a
|
||||
single slot serving the entire web interface, one glance answers the
|
||||
question every management outage starts with: who is holding it. A slot
|
||||
showing state 3 with nothing in flight and a peer that no longer answers is
|
||||
a connection whose owner went away.
|
||||
|
||||
`httpd left` and `entry` describe the file transfer the web server believes
|
||||
it is in the middle of, and the trailing flags show whether STP is running
|
||||
and which VLAN carries management.
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ The code currently provides the following functions:
|
||||
void igmp_setup(void) __banked;
|
||||
void igmp_enable(void) __banked;
|
||||
void igmp_router_port_set(uint16_t pmask) __banked;
|
||||
void igmp_packet_handler(void) __banked;
|
||||
uint8_t igmp_packet_handler(void) __banked;
|
||||
void igmp_show(void) __banked;
|
||||
```c
|
||||
`igmp_setup()` is called at boot-time and configures flooding of all IP-MC packets by
|
||||
@@ -80,7 +80,11 @@ of IP-MC packets to be limited to only subscribed ports.
|
||||
|
||||
`igmp_router_port_set()`configures forwarding ports for IGMP messages.
|
||||
|
||||
`igmp_packet_handler()` implements handling of trapped IGMP packets by the CPU.
|
||||
`igmp_packet_handler()` implements handling of trapped IGMP packets by the CPU. It is called
|
||||
for frames to 01:00:5e:xx:xx:xx and returns 0 when the frame is not a trapped IGMP packet,
|
||||
so that it is passed on to the IP stack. IGMPv1/v2 reports (0x12, 0x16) join the group given
|
||||
in the IGMP header, IGMPv2 leaves (0x17) leave it, IGMPv3 reports use the first group record
|
||||
(type 4 joins, type 3 leaves). Trapped IGMP frames arrive without a VLAN tag.
|
||||
|
||||
`igmp_show()` prints out the IGMP configuration on the CLI.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 120 KiB |
@@ -0,0 +1,54 @@
|
||||
# Storm Control
|
||||
Storm control limits the rate at which a port admits broadcast, multicast,
|
||||
unknown unicast and unknown multicast frames. Frames of a type above its limit
|
||||
are dropped at ingress, so a loop or a misbehaving host cannot flood the rest
|
||||
of the network through that port. Known unicast traffic is not affected.
|
||||
|
||||
## Commands
|
||||
```
|
||||
storm <port> bcast|mcast|ucast|umcast <rate> pps
|
||||
storm <port> bcast|mcast|ucast|umcast <rate> kbps
|
||||
storm <port> bcast|mcast|ucast|umcast off
|
||||
storm
|
||||
```
|
||||
`ucast` is unicast to a MAC address the switch has not learned yet, and
|
||||
`umcast` is multicast without an entry in the address table. Multicast groups
|
||||
get their entries from IGMP snooping, so without `igmp on` all multicast is
|
||||
unknown and only the `umcast` limit applies to it; `mcast` covers the groups
|
||||
IGMP has learned. A limit in
|
||||
packets per second goes from 1 to 1048575, a limit in kbit/s from 1 to
|
||||
10000000. `storm` without arguments prints the limits of every port. The
|
||||
limits are kept in the configuration like any other setting, and the Bandwidth
|
||||
page of the web interface has a Storm control card to set them.
|
||||
|
||||
## Registers
|
||||
Each port and type has an enable bit and a meter index, and each limit uses
|
||||
one of the 64 shared meters of the switch. RTLPlayground gives every port and
|
||||
type its own meter, index `24 + port * 4 + type`, so one port's storm does not
|
||||
eat into the limit of another. Storm control uses meters 24 to 63 and leaves
|
||||
0 to 23 to the ACL. The limit of a meter is in `RTL837X_METER_RATE + 4 *
|
||||
meter`, and bit `meter % 32` of `RTL837X_METER_MODE + 4 * (meter / 32)`
|
||||
selects pps instead of kbit/s.
|
||||
```
|
||||
#define RTL837X_STORM_CTRL 0x54e4 /* + 4 * type, bit = port */
|
||||
#define RTL837X_STORM_MIDX 0x54f4 /* + 8 * type + 4 * (port / 5), 6 bits per port */
|
||||
#define RTL837X_METER_RATE 0x5cf0 /* + 4 * meter, 24 bits, kbit/s or pps */
|
||||
#define RTL837X_METER_MODE 0x5ef0 /* + 4 * (meter / 32), bit set = pps */
|
||||
```
|
||||
In kbit/s mode one step of the rate is 1 kbit/s. Measured with 100 and 1000 byte
|
||||
frames, the meter counts a frame with its FCS, but without preamble and
|
||||
interframe gap. Every meter has a bit that adds them, in `0x5f08 + 4 * (meter
|
||||
/ 32)`, which storm control leaves cleared. `IGBW_INC_IFG` and `EGBW_INC_IFG`
|
||||
are the matching bits of the bandwidth control.
|
||||
|
||||
An ingress bandwidth limit on the same port works on the same arriving frames
|
||||
as the storm limit rather than after it, and the two together pass far less
|
||||
than either one: a 1 Mbit/s `umcast` limit with a 10 Mbit/s ingress limit let
|
||||
0.12 to 0.16 Mbit/s of a 1.4 Gbit/s stream through, where each alone passed
|
||||
1.17 and 10.2 Mbit/s.
|
||||
|
||||
The type is 0 for broadcast, 1 for multicast, 2 for unknown unicast and 3 for
|
||||
unknown multicast. The burst size of a meter (0x5df0 + 4 * meter) counts packets
|
||||
in pps mode; its default of 0x2000 lets 8192 frames through before a pps limit
|
||||
bites, so a pps limit sets the burst to one second of traffic. A kbit/s limit
|
||||
puts back the default.
|
||||
@@ -58,6 +58,32 @@ port set to admit tagged frames only (`ingress <port>t`) never delivers one
|
||||
to the CPU. `stp_setup()` prints a warning for every STP-enabled port in that
|
||||
state.
|
||||
|
||||
## 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:
|
||||
`00` disabled, `01` blocking, `10` learning, `11` forwarding. A port in
|
||||
blocking forwards nothing between ports, but it still sends what the CPU
|
||||
|
||||
@@ -1,135 +1,107 @@
|
||||
# Supporting Multiple Languages in the Web UI
|
||||
|
||||
The firmware uses a client-side i18n approach
|
||||
all translations are stored in a single JavaScript dictionary embedded in the firmware.
|
||||
No server-side changes are needed.
|
||||
The firmware uses a client-side i18n approach: all translations are stored
|
||||
in one JavaScript dictionary embedded in the firmware. No server-side
|
||||
changes are needed.
|
||||
|
||||
## Architecture
|
||||
|
||||
All translation logic lives in `html/i18n.js`. The file contains:
|
||||
All translation logic lives at the top of `html/app.js`:
|
||||
|
||||
- A `LANG` object with one sub-object per language (`en`, `ja`, ...)
|
||||
- Language auto-detection (browser language → `localStorage` override)
|
||||
- `t(key)` — look up a translated string
|
||||
- `setLang(lang)` — switch language and update the page
|
||||
- `applyTranslation(el)` — apply translation to one DOM element
|
||||
- A `LANG` object with one sub-object per language (`en`, `ja`, `zh`)
|
||||
- Language auto-detection (browser language, overridden by the
|
||||
`rtl_lang` key in `localStorage`, which the language selector in the
|
||||
System section writes)
|
||||
- `t(key, vars)` looks up a translated string; `{name}` placeholders in
|
||||
the string are replaced from `vars`, e.g. `t("v_del_q", {n: vid})`
|
||||
- `i18nApply()` applies the dictionary to the static markup once at load
|
||||
|
||||
Translation keys are **flat strings** (no nesting). The English keys in `LANG.en` also serve as the fallback when a key is missing in another language.
|
||||
Translation keys are flat strings. The English entry is the fallback when
|
||||
a key is missing in another language, and the key itself is the fallback
|
||||
when it is missing everywhere.
|
||||
|
||||
Changing the language stores the choice and reloads the page, so every
|
||||
dynamically built table is rebuilt in the new language.
|
||||
|
||||
`login.html` is served before authentication and does not load `app.js`;
|
||||
it carries its own five strings per language in an inline table.
|
||||
|
||||
## How to Add a New Language
|
||||
|
||||
### 1. Add a dictionary entry in `html/i18n.js`
|
||||
### 1. Add a dictionary entry in `html/app.js`
|
||||
|
||||
Append a new sub-object to the `LANG` object. Every key from `LANG.en` must be present:
|
||||
Append a sub-object to `LANG`. Every key from `LANG.en` should be present:
|
||||
|
||||
```js
|
||||
var LANG = {
|
||||
en: {
|
||||
nav_overview: 'Overview',
|
||||
nav_port_config: 'Port Configuration',
|
||||
// ... all keys for English
|
||||
},
|
||||
ja: {
|
||||
nav_overview: '概要',
|
||||
nav_port_config: 'ポート設定',
|
||||
// ... all keys for Japanese
|
||||
},
|
||||
LANGCODE: { // ← add your language here
|
||||
nav_overview: '...',
|
||||
nav_port_config: '...',
|
||||
// ... translate every key
|
||||
},
|
||||
var LANG={
|
||||
en:{
|
||||
nav_dash:"Dashboard",
|
||||
...
|
||||
},
|
||||
LANGCODE:{ // add your language here
|
||||
nav_dash:"...",
|
||||
...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Add the language to the navigation sidebar
|
||||
### 2. Add the language to the selector in `html/index.html`
|
||||
|
||||
In `html/navigation.js`, add an `<option>` to the language selector:
|
||||
|
||||
```js
|
||||
+ "<option value='en'>English</option><option value='ja'>日本語</option>"
|
||||
```html
|
||||
<select class="ctl" id="langSel" data-i18n-t="sy_lang">
|
||||
<option value="en">English</option>
|
||||
<option value="ja">日本語</option>
|
||||
<option value="zh">中文</option>
|
||||
<option value="LANGCODE">Native name</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
Replace with:
|
||||
### 3. Add the login strings in `html/login.html`
|
||||
|
||||
```js
|
||||
+ "<option value='en'>English</option><option value='ja'>日本語</option><option value='LANGCODE'>Native Name</option>"
|
||||
```
|
||||
The inline table there holds, per language: page title, subtitle,
|
||||
password label, button label, wrong-password message.
|
||||
|
||||
### 3. Verify auto-detection
|
||||
### 4. Verify auto-detection
|
||||
|
||||
The language detection code in `i18n.js` reads `navigator.language` and normalises it to the first two characters:
|
||||
|
||||
```js
|
||||
var browser = (navigator.language || navigator.userLanguage || 'en').substring(0, 2);
|
||||
return LANG[browser] ? browser : 'en';
|
||||
```
|
||||
|
||||
If the two-letter code matches a key in `LANG`, it will be auto-selected. No changes needed here.
|
||||
The detection normalises `navigator.language` to its first two
|
||||
characters and selects that language if `LANG` has it, otherwise English.
|
||||
|
||||
## Two Translation Mechanisms
|
||||
|
||||
### (A) `data-i18n` attribute (declarative — for HTML)
|
||||
|
||||
Add `data-i18n="key_name"` to any HTML element. The English text goes in the element content as a fallback:
|
||||
### (A) `data-i18n` attributes (declarative, for HTML)
|
||||
|
||||
```html
|
||||
<h1 data-i18n="port_heading">Port Configuration</h1>
|
||||
<input type="button" data-i18n="port_apply" value="Apply">
|
||||
<option data-i18n="port_auto">Auto</option>
|
||||
<title data-i18n="port_title">Port Configuration</title>
|
||||
<h2 data-i18n="pt_title">Port configuration</h2>
|
||||
<button class="ctl" data-i18n="c_apply" data-i18n-t="sy_dhcp_t">Apply</button>
|
||||
<input class="in" data-i18n-p="l2_filter">
|
||||
```
|
||||
|
||||
On page load, `applyTranslation()` sets:
|
||||
- `data-i18n` sets the element's text content
|
||||
- `data-i18n-t` sets the `title` attribute (tooltip)
|
||||
- `data-i18n-p` sets the `placeholder` attribute
|
||||
|
||||
- `el.value` for `<input type="submit|button">`
|
||||
- `el.textContent` for `<option>`, `<title>`
|
||||
- `el.innerHTML` for everything else
|
||||
The English text stays in the markup as the fallback and as the source
|
||||
of truth for what the key means.
|
||||
|
||||
### (B) `t('key')` call (imperative — for JavaScript strings)
|
||||
|
||||
When generating HTML or text in JavaScript, wrap translatable strings with `t()`:
|
||||
### (B) `t("key")` calls (imperative, for JavaScript)
|
||||
|
||||
```js
|
||||
td.appendChild(document.createTextNode(t('common_port') + i));
|
||||
td.innerHTML = t('port_auto');
|
||||
iHTML += "<tr><td>" + t('port_vendor') + "</td></tr>";
|
||||
tr.insertCell().textContent=t("c_port")+" "+p;
|
||||
toast(t("v_loaded",{n:vid}),"ok");
|
||||
```
|
||||
|
||||
### Special Case: Link Speed Display
|
||||
|
||||
The `linkS` array in `html/main.js` maps numeric link states to display strings. The first two entries (`speed_disabled`, `speed_down`) use `t()` for translation; the remaining entries are static literals (they are the same in all languages):
|
||||
|
||||
```js
|
||||
const linkS = [
|
||||
function(){return t('speed_disabled')},
|
||||
function(){return t('speed_down')},
|
||||
"10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"
|
||||
];
|
||||
function linkText(idx) { var v = linkS[idx]; return typeof v === 'function' ? v() : v; }
|
||||
```
|
||||
|
||||
Always use `linkText(idx)` (not `linkS[idx]`) to read these values.
|
||||
Strings that are identical in every language (`10M`, `2.5G`, `MAC`,
|
||||
`VLAN`, `CPU`, `RSTP`) are literals, not dictionary entries.
|
||||
|
||||
## Size Considerations
|
||||
|
||||
- `html/i18n.js` is embedded in the firmware filesystem (~14 KB for two languages)
|
||||
- Each new language adds roughly the same number of bytes as the English dictionary (~3–4 KB)
|
||||
- The firmware binary is padded to 512 KiB, so a few extra KB do not change the flash footprint
|
||||
- Values that are identical in all languages should be inlined as literals rather than added to the dictionary (e.g., `"10M"`, `"2.5G"`, `"MAC"`, `"VLAN"`, `"CPU"`)
|
||||
- Each language adds roughly 3 KB to `app.js` before compression; the
|
||||
build gzips the file, so the flash cost of a language is closer to 1 KB
|
||||
- The largest embedded file must stay below 64 KB after compression
|
||||
(`uint16_t` length in the file table); `app.js` with three languages
|
||||
is about 29 KB compressed
|
||||
|
||||
## Build
|
||||
|
||||
No special flags are needed. The `html/` directory is embedded by `fileadder` during the build.
|
||||
|
||||
## Script Load Order
|
||||
|
||||
`i18n.js` must be loaded after `main.js` (which defines `t()`'s dependencies like `LANG`) but before any page-specific JS that calls `t()`:
|
||||
|
||||
```html
|
||||
<script src="/main.js"></script>
|
||||
<script src="/i18n.js"></script>
|
||||
<script src="/eee.js"></script> <!-- uses t() -->
|
||||
```
|
||||
|
||||
The `navigation.js` script is loaded last (bottom of `<body>`).
|
||||
No special flags are needed. `html/` is minified and embedded by the
|
||||
normal build (see `webui-compression.md`).
|
||||
@@ -6,6 +6,9 @@ The following devices have been tested and are fully working:
|
||||
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 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 |
|
||||
| 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 |
|
||||
| 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-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
||||
@@ -19,10 +22,16 @@ The following devices have been tested and are fully working:
|
||||
| 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-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 |
|
||||
| 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 | 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| 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 |
|
||||
| Binardat | 2G06-04210GSM | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
|
||||
| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
|
||||
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||
| 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 |
|
||||
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||
@@ -32,6 +41,7 @@ The following devices have been tested and are fully working:
|
||||
| Xikestore| 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 |
|
||||
| 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 |
|
||||
|
||||
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
|
||||
|
||||
@@ -19,16 +19,17 @@ html/ --(minify.py)--> output/html_min/ --(fileadder -z)--> flash image
|
||||
served bytes, so minification alone already reduces the transfer size
|
||||
from 109,814 to 97,730 bytes, independent of gzip.
|
||||
- The Web UI is a single-page application: `index.html` holds all pages
|
||||
as sections (`#/ports`, `#/vlan`, ...) that the sidebar switches
|
||||
as sections (`#ports`, `#vlan`, ...) that the sidebar switches
|
||||
between via the URL hash. `login.html` stays separate because it is
|
||||
the authentication gate. Only these two pages plus `main.js`,
|
||||
`style.css`, the three SVG port images and the favicon are embedded.
|
||||
- All JavaScript (i18n, shared helpers, navigation and the per-section
|
||||
scripts) lives in one `html/main.js` bundle that the pages load as
|
||||
their only script, so the browser fetches it once and gzip can
|
||||
compress across all of it. A section's initialisation runs when the
|
||||
section is shown, its polling intervals run only while it is visible,
|
||||
and re-entering a section refetches the data.
|
||||
the authentication gate and is self-contained (its own styles and
|
||||
strings), so nothing else is served before login. Only these two
|
||||
pages plus `app.js` and the favicon are embedded; the stylesheet and
|
||||
the theme bootstrap are inline in `index.html`.
|
||||
- All JavaScript (translation table, shared helpers, navigation and the
|
||||
per-section code) lives in one `html/app.js` that the page loads as
|
||||
its only script, so the browser fetches it once and gzip can compress
|
||||
across all of it. A section starts its pollers when it is shown and
|
||||
stops them when it is left; re-entering a section refetches the data.
|
||||
- `fileadder -z` gzip-compresses every file (zlib, gzip format,
|
||||
`Z_BEST_COMPRESSION`) when it generates the file table
|
||||
(`html_data.c`/`html_data.h`) and when it embeds the files into the
|
||||
@@ -71,7 +72,8 @@ JSON polling of the visible section).
|
||||
## Notes
|
||||
|
||||
- The files stay well below the `uint16_t` size limit of the file table
|
||||
(largest gzip output: 17.2 KB for the merged `main.js`).
|
||||
(largest gzip output: about 29 KB for `app.js`, three languages
|
||||
included).
|
||||
- `fileadder` terminates the embedded files with a NUL directly after the
|
||||
content (previously at `data_read + 1`), so the `strlen()`-based size
|
||||
computation no longer depends on uninitialised buffer content.
|
||||
|
||||
@@ -1,310 +1,484 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/main.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title data-i18n="index_title">FreeSwitchOS Main Page</title>
|
||||
<style>
|
||||
.popup {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.popup-content {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
height: 80%
|
||||
}
|
||||
.popup .popup-content {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.tab-bar { display: flex; border-bottom: 2px solid #226; margin-bottom: 0; padding: 1px 16px; padding-bottom: 0; }
|
||||
.tab-btn { padding: 10px 20px; background-color: #ddf; border: none; cursor: pointer; font-size: 1em; border-radius: 8px 8px 0 0; margin-right: 4px; }
|
||||
.tab-btn:hover { background-color: #aaf; }
|
||||
.tab-btn.active { background-color: #aaf; font-weight: bold; border-bottom: 2px solid #aaf; margin-bottom: -2px; }
|
||||
.tab-content { display: none; }
|
||||
.tab-content.active { display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div id="ports" style="margin-left:16%;padding:1px 16px"></div>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Switch</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#f4f6f8;--panel:#ffffff;--panel2:#eaeef2;--bd:#d7dde4;--fg:#1a222c;--fg2:#5c6773;
|
||||
--ac:#0969da;--acfg:#ffffff;--ok:#158744;--bad:#cf222e;--warn:#9a6700;--cy:#1b7c83;
|
||||
--sel:rgba(9,105,218,.10);--shadow:0 2px 10px rgba(20,30,40,.07);
|
||||
--s10:#b58900;--s100:#b58900;--s1000:#159744;--s2g5:#0d9488;--s5g:#0d9488;--s10g:#2563eb;
|
||||
}
|
||||
:root[data-theme="dark"]{
|
||||
--bg:#0e1116;--panel:#161b22;--panel2:#1f262e;--bd:#2c333c;--fg:#e6edf3;--fg2:#8d96a0;
|
||||
--ac:#4c8ef7;--acfg:#ffffff;--ok:#3fb950;--bad:#f85149;--warn:#d29922;--cy:#39c5cf;
|
||||
--sel:rgba(76,142,247,.16);--shadow:0 2px 10px rgba(0,0,0,.35);
|
||||
--s10:#d29922;--s100:#d29922;--s1000:#3fb950;--s2g5:#2dd4bf;--s5g:#2dd4bf;--s10g:#58a6ff;
|
||||
}
|
||||
:root[data-theme="sel-dark"]{
|
||||
--bg:#103c48;--panel:#184956;--panel2:#2d5b69;--bd:#2d5b69;--fg:#adbcbc;--fg2:#72898f;
|
||||
--ac:#4695f7;--acfg:#ffffff;--ok:#75b938;--bad:#fa5750;--warn:#dbb32d;--cy:#41c7b9;
|
||||
--sel:rgba(70,149,247,.18);--shadow:0 2px 10px rgba(0,20,26,.35);
|
||||
--s10:#dbb32d;--s100:#dbb32d;--s1000:#75b938;--s2g5:#41c7b9;--s5g:#41c7b9;--s10g:#4695f7;
|
||||
}
|
||||
:root[data-theme="sel-light"]{
|
||||
--bg:#fbf3db;--panel:#ece3cc;--panel2:#d5cdb6;--bd:#d5cdb6;--fg:#53676d;--fg2:#909995;
|
||||
--ac:#0072d4;--acfg:#ffffff;--ok:#489100;--bad:#d2212d;--warn:#ad8900;--cy:#009c8f;
|
||||
--sel:rgba(0,114,212,.12);--shadow:0 2px 10px rgba(80,70,40,.12);
|
||||
--s10:#ad8900;--s100:#ad8900;--s1000:#489100;--s2g5:#009c8f;--s5g:#009c8f;--s10g:#0072d4;
|
||||
}
|
||||
*{box-sizing:border-box;margin:0}
|
||||
html,body{height:100%}
|
||||
body{
|
||||
font:14px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
||||
background:var(--bg);color:var(--fg);display:flex;
|
||||
}
|
||||
button,input,select,textarea{font:inherit;color:var(--fg)}
|
||||
a{color:var(--ac);text-decoration:none}
|
||||
#nav{
|
||||
width:200px;flex:none;background:var(--panel);border-right:1px solid var(--bd);
|
||||
display:flex;flex-direction:column;position:sticky;top:0;height:100vh;
|
||||
}
|
||||
#brand{display:flex;align-items:center;gap:9px;padding:16px 16px 12px;font-weight:650;font-size:15px}
|
||||
#brand svg{flex:none;stroke:var(--ac)}
|
||||
#brand span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
#navlist{list-style:none;padding:4px 8px;overflow-y:auto;flex:1}
|
||||
#navlist li{
|
||||
display:flex;align-items:center;gap:9px;padding:7px 10px;margin:1px 0;
|
||||
border-radius:7px;cursor:pointer;color:var(--fg2);font-weight:500;
|
||||
}
|
||||
#navlist li svg{flex:none;stroke:currentColor}
|
||||
#navlist li:hover{background:var(--panel2);color:var(--fg)}
|
||||
#navlist li.act{background:var(--sel);color:var(--ac)}
|
||||
#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}
|
||||
#top{
|
||||
display:flex;align-items:center;gap:10px;padding:10px 20px;
|
||||
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}
|
||||
#ttitle{font-size:16px;font-weight:650;flex:1}
|
||||
#dirty{
|
||||
display:none;font-size:12px;font-weight:600;color:var(--warn);
|
||||
border:1px solid var(--warn);border-radius:20px;padding:2px 10px;
|
||||
}
|
||||
#dirty.show{display:inline-block}
|
||||
select.ctl,button.ctl{
|
||||
background:var(--panel2);border:1px solid var(--bd);border-radius:7px;
|
||||
padding:5px 9px;cursor:pointer;font-size:13px;white-space:nowrap;
|
||||
}
|
||||
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:disabled{opacity:.45;cursor:default;filter:none}
|
||||
main{padding:18px 20px 40px;max-width:1400px;width:100%}
|
||||
section.tab{display:none}
|
||||
section.tab.act{display:block}
|
||||
.card{
|
||||
background:var(--panel);border:1px solid var(--bd);border-radius:10px;
|
||||
box-shadow:var(--shadow);padding:16px 18px;margin-bottom:16px;
|
||||
}
|
||||
.card h2{font-size:14px;font-weight:650;margin-bottom:12px;color:var(--fg)}
|
||||
.card h2 .hint{font-weight:400;font-size:12px;color:var(--fg2);margin-left:8px}
|
||||
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:16px;align-items:start}
|
||||
.grid2 .card{margin-bottom:0}
|
||||
table.t{width:100%;border-collapse:collapse;font-size:13px}
|
||||
table.t th{
|
||||
text-align:left;font-weight:600;color:var(--fg2);font-size:12px;
|
||||
padding:6px 8px;border-bottom:1px solid var(--bd);white-space:nowrap;
|
||||
}
|
||||
table.t th[data-sort]{cursor:pointer;user-select:none}
|
||||
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:hover td{background:var(--sel)}
|
||||
.num{font-variant-numeric:tabular-nums;text-align:right}
|
||||
.scrollx{overflow-x:auto}
|
||||
input.in,select.in,textarea.in{
|
||||
background:var(--bg);border:1px solid var(--bd);border-radius:7px;padding:5px 8px;outline:none;
|
||||
}
|
||||
input.in:focus,select.in:focus,textarea.in:focus{border-color:var(--ac)}
|
||||
input.in.sm{width:7em}
|
||||
label.row{display:flex;align-items:center;gap:10px;margin:8px 0}
|
||||
label.row span.lb{width:110px;flex:none;color:var(--fg2);font-size:13px}
|
||||
.switch{position:relative;display:inline-block;width:34px;height:19px;flex:none}
|
||||
.switch input{opacity:0;width:0;height:0}
|
||||
.switch i{
|
||||
position:absolute;inset:0;background:var(--bd);border-radius:19px;transition:.15s;cursor:pointer;
|
||||
}
|
||||
.switch i:before{
|
||||
content:"";position:absolute;width:15px;height:15px;border-radius:50%;
|
||||
left:2px;top:2px;background:var(--panel);transition:.15s;
|
||||
}
|
||||
.switch input:checked+i{background:var(--ok)}
|
||||
.switch input:checked+i:before{transform:translateX(15px)}
|
||||
#strip{display:flex;gap:8px;flex-wrap:wrap;padding:4px 0 2px}
|
||||
.port{
|
||||
width:46px;border:2px solid var(--bd);border-radius:7px;padding:5px 0 3px;
|
||||
text-align:center;cursor:pointer;background:var(--panel2);position:relative;
|
||||
}
|
||||
.port.sfp{width:56px}
|
||||
.port .pn{font-weight:650;font-size:13px}
|
||||
.port .ps{font-size:10px;color:var(--fg2);display:block;line-height:1.2}
|
||||
.port .jack{
|
||||
display:block;width:18px;height:12px;margin:3px auto 2px;border-radius:2px;
|
||||
border:2px solid var(--fg2);border-top-width:5px;opacity:.55;
|
||||
}
|
||||
.port.sfp .jack{width:28px;height:10px;border-top-width:3px}
|
||||
.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 .ps{color:var(--pc);font-weight:600}
|
||||
.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.ok{color:var(--ok)}.badge.bad{color:var(--bad)}
|
||||
.seg{display:inline-flex;border:1px solid var(--bd);border-radius:7px;overflow:hidden}
|
||||
.seg button{
|
||||
background:var(--panel);border:0;padding:3px 8px;cursor:pointer;font-size:12px;color:var(--fg2);
|
||||
border-right:1px solid var(--bd);
|
||||
}
|
||||
.seg button:last-child{border-right:0}
|
||||
.seg button.on{background:var(--ac);color:var(--acfg)}
|
||||
#toasts{position:fixed;right:16px;bottom:16px;z-index:50;display:flex;flex-direction:column;gap:8px}
|
||||
.toast{
|
||||
background:var(--panel);border:1px solid var(--bd);border-left:4px solid var(--ac);
|
||||
border-radius:8px;padding:9px 14px;box-shadow:var(--shadow);font-size:13px;max-width:340px;
|
||||
animation:tin .18s ease-out;
|
||||
}
|
||||
.toast.ok{border-left-color:var(--ok)}.toast.err{border-left-color:var(--bad)}
|
||||
@keyframes tin{from{transform:translateY(8px);opacity:0}to{transform:none;opacity:1}}
|
||||
#mback{
|
||||
position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:40;display:none;
|
||||
align-items:flex-start;justify-content:center;padding:6vh 16px;
|
||||
}
|
||||
#mback.show{display:flex}
|
||||
#modal{
|
||||
background:var(--panel);border:1px solid var(--bd);border-radius:12px;box-shadow:var(--shadow);
|
||||
width:min(760px,96vw);max-height:86vh;display:flex;flex-direction:column;
|
||||
}
|
||||
#mhead{display:flex;align-items:center;padding:13px 18px;border-bottom:1px solid var(--bd)}
|
||||
#mtitle{font-weight:650;font-size:15px;flex:1}
|
||||
#mx{background:none;border:0;font-size:19px;cursor:pointer;color:var(--fg2);padding:0 2px}
|
||||
#mbody{padding:14px 18px;overflow:auto}
|
||||
#mfoot{padding:12px 18px;border-top:1px solid var(--bd);display:flex;gap:10px;justify-content:flex-end}
|
||||
#mfoot:empty{display:none}
|
||||
pre.cfg{
|
||||
background:var(--bg);border:1px solid var(--bd);border-radius:8px;padding:10px 12px;
|
||||
font:12px/1.5 ui-monospace,Consolas,monospace;white-space:pre-wrap;word-break:break-all;
|
||||
}
|
||||
textarea.cfg{
|
||||
width:100%;min-height:200px;background:var(--bg);border:1px solid var(--bd);border-radius:8px;
|
||||
padding:10px 12px;font:12px/1.5 ui-monospace,Consolas,monospace;resize:vertical;outline:none;
|
||||
}
|
||||
.mono{font-family:ui-monospace,Consolas,monospace;font-size:12px}
|
||||
.mut{color:var(--fg2)}
|
||||
.small{font-size:12px}
|
||||
.dangerzone{border-color:color-mix(in srgb,var(--bad) 40%,var(--bd))}
|
||||
button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
@media (max-width:820px){
|
||||
#nav{position:fixed;left:-210px;transition:left .18s;z-index:30;box-shadow:var(--shadow)}
|
||||
#nav.open{left:0}
|
||||
#burger{display:block}
|
||||
main{padding:14px 12px 40px}
|
||||
#top{padding:8px 10px;gap:7px}
|
||||
#ttitle{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
#dirty{padding:2px 7px}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function(){
|
||||
var pref;
|
||||
try{pref=localStorage.getItem("theme")||"auto";}catch(e){pref="auto";}
|
||||
var dark=window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
var t=pref;
|
||||
if(pref==="auto")t=dark?"dark":"light";
|
||||
if(pref==="auto-sel")t=dark?"sel-dark":"sel-light";
|
||||
document.documentElement.dataset.theme=t;
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="page" id="page-overview" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="index_heading">Switch Configuration</h1>
|
||||
<table id="infoTable">
|
||||
<tr>
|
||||
<th colspan="2" data-i18n="index_settings">Settings</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav id="nav">
|
||||
<div id="brand">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke-width="2">
|
||||
<rect x="2" y="7" width="20" height="10" rx="2"/><path d="M6 11v2M10 11v2M14 11v2M18 11v2"/>
|
||||
</svg>
|
||||
<span id="brandname">Switch</span>
|
||||
</div>
|
||||
<ul id="navlist"></ul>
|
||||
<div id="navfoot"><span id="fver"></span></div>
|
||||
</nav>
|
||||
|
||||
<div class="page" id="page-ports" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="port_heading">Port Configuration</h1>
|
||||
<table id="speedtable">
|
||||
<tr> <th data-i18n="port_col_port">Port</th> <th data-i18n="port_col_name">Name</th> <th data-i18n="port_col_speed">Current Link Speed</th><th data-i18n="port_col_devices">Connected devices</th><th data-i18n="port_col_set_speed">Set Speed</th><th data-i18n="port_col_disabled">Disabled</th><th data-i18n="port_col_apply">Apply</th></tr>
|
||||
</table>
|
||||
<h2 style="margin-top:3em" data-i18n="port_mtu_heading">Configure Maximum Frame Size (MTU) forwarded at Port</h2>
|
||||
<table id="mtutable" style="margin-top:1em">
|
||||
</table>
|
||||
</div>
|
||||
<div id="wrap">
|
||||
<header id="top">
|
||||
<button id="burger" title="Menu">
|
||||
<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>
|
||||
<span id="ttitle"></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>
|
||||
</header>
|
||||
|
||||
<div class="page" id="page-stat" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="popup" class="popup">
|
||||
<div class="popup-content">
|
||||
<h2 data-i18n="stat_detailed">Detailed Port Statistics</h2>
|
||||
<div id="popup_text"></div>
|
||||
<button id="closePopup" class="action" data-i18n="stat_close">Close</button>
|
||||
<main>
|
||||
<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="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="scrollx"><table class="t" id="traffic">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="c_link">Link</th><th class="num" data-i18n="d_txpps">TX pps</th><th class="num" data-i18n="d_rxpps">RX pps</th><th class="num" data-i18n="d_txbad">TX bad</th><th class="num" data-i18n="d_rxbad">RX bad</th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
</div>
|
||||
<h1 data-i18n="stat_heading">Port Statistics</h1>
|
||||
<table id="statstable">
|
||||
<tr> <th data-i18n="stat_col_port">Port</th> <th data-i18n="stat_col_name">Name</th> <th data-i18n="stat_col_link">link</th> <th data-i18n="stat_col_tx_good">TX Good</th> <th data-i18n="stat_col_tx_bad">TX Bad</th> <th data-i18n="stat_col_rx_good">RX Good</th> <th data-i18n="stat_col_rx_bad">RX Bad</th> <th data-i18n="stat_col_all"> All Counters </th></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="page" id="page-vlan" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="vlan_heading">VLAN Configuration</h1>
|
||||
<form id="vform">
|
||||
<div>
|
||||
<label for="vlanSelect" data-i18n="vlan_select">VLAN Select:</label>
|
||||
<select id="vlanSelect" style="margin: 0 0 0 8px">
|
||||
<option value="" disabled selected data-i18n="vlan_choose">— VLAN Choose —</option>
|
||||
</select>
|
||||
</div>
|
||||
<br/>
|
||||
<div>
|
||||
<label for="vid" data-i18n="vlan_id">VLAN ID:</label>
|
||||
<input type="number" min="1" max="4094" id="vid" name="vid">
|
||||
<button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();" data-i18n="vlan_get_config">Get Configuration</button>
|
||||
</div>
|
||||
<br/><br/>
|
||||
<label for="vname" data-i18n="vlan_name">VLAN Name:</label>
|
||||
<input type="text" id="vname" name="vname"><br><br>
|
||||
<br/>
|
||||
<h2 data-i18n="vlan_tagged">Tagged Ports</h2>
|
||||
<div id="tPorts"><button type="button" style="transform: translateY(-100%);margin: 0 50px 0 0" onclick="utClicked(true);" data-i18n="vlan_select_all">Select all</button></div>
|
||||
<h2 data-i18n="vlan_untagged">Untagged Ports</h2>
|
||||
<div id="uPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="utClicked(false);" data-i18n="vlan_select_all">Select all</button> </div>
|
||||
<h2 data-i18n="vlan_pvid">Use as default VLAN for incoming traffic (PVID)</h2>
|
||||
<div id="pPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="pvClicked(true);" data-i18n="vlan_select_all">Select all</button> </div>
|
||||
<br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" data-i18n="vlan_update" value="Update / Create">
|
||||
</form>
|
||||
<h2 data-i18n="vlan_configured">Configured VLANs</h2>
|
||||
<table id="vlanTable" style="width:90%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>VLAN</th>
|
||||
<th data-i18n="vlan_col_name">Name</th>
|
||||
<th data-i18n="vlan_col_member">Member Ports</th>
|
||||
<th data-i18n="vlan_col_tagged">Tagged Ports</th>
|
||||
<th data-i18n="vlan_col_untagged">Untagged Ports</th>
|
||||
<th data-i18n="vlan_col_pvid">PVID Ports</th>
|
||||
<th data-i18n="vlan_col_delete">Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="vlanTableBody">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-l2" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="l2_heading">L2 Configuration</h1>
|
||||
<p><span data-i18n="l2_shown">Shown:</span> <span id="l2count">-</span></p>
|
||||
<table id="l2table">
|
||||
<tr>
|
||||
<th><span class="l2sort" onclick="l2SortBy('port')"><span data-i18n="l2_col_port">Port</span><span id="l2a_port" class="l2arrow"></span></span><br>
|
||||
<input id="l2f_port" class="l2filter" oninput="l2FilterChanged()" size="5"></th>
|
||||
<th><span class="l2sort" onclick="l2SortBy('mac')">MAC<span id="l2a_mac" class="l2arrow"></span></span><br>
|
||||
<input id="l2f_mac" class="l2filter" oninput="l2FilterChanged()" size="14"></th>
|
||||
<th><span class="l2sort" onclick="l2SortBy('vlan')">VLAN<span id="l2a_vlan" class="l2arrow"></span></span><br>
|
||||
<input id="l2f_vlan" class="l2filter" oninput="l2FilterChanged()" size="5"></th>
|
||||
<th><span class="l2sort" onclick="l2SortBy('type')"><span data-i18n="l2_col_type">Type</span><span id="l2a_type" class="l2arrow"></span></span><br>
|
||||
<input id="l2f_type" class="l2filter" oninput="l2FilterChanged()" size="8"></th>
|
||||
<th data-i18n="l2_col_remove">Remove Entry</th></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-stp" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1>Spanning Tree (RSTP)</h1>
|
||||
<h2>Mode: <select id="stpMode"><option value="off">Disabled</option><option value="on">Enabled</option></select>
|
||||
<input style="width:15%;margin-left: 3em;" class="action" id="stp_sub" onclick="stpSub();" type="button" value="Apply"></h2>
|
||||
<div id="stpStat" style="font-family:monospace;"></div>
|
||||
<h2>Bridge settings</h2>
|
||||
<table id="stpBridge">
|
||||
<tr>
|
||||
<th>Priority</th><th>Version</th><th>Hello [s]</th><th>Max age [s]</th><th>Fwd delay [s]</th><th>Tx hold</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select id="bPrio"></select></td>
|
||||
<td><select id="bVer"><option value="rstp">RSTP</option><option value="stp">STP compat</option></select></td>
|
||||
<td><input id="bHello" type="number" min="1" max="10" style="width:4em"></td>
|
||||
<td><input id="bMaxage" type="number" min="6" max="40" style="width:4em"></td>
|
||||
<td><input id="bFwd" type="number" min="4" max="30" style="width:4em"></td>
|
||||
<td><input id="bTxhold" type="number" min="1" max="10" style="width:4em"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="font-size:small">Changes apply immediately. Edge ports skip the listen period; guard/filter act on received BPDUs.</p>
|
||||
<h2>Port configuration</h2>
|
||||
<table id="stpPortsTbl">
|
||||
<tr>
|
||||
<th>Port</th><th>State</th><th>Path Cost<br><span style="font-weight:normal;font-size:small">(0 = Auto)</span></th><th>Priority</th><th>Edge Port</th><th>BPDU Filter</th><th>Guard</th><th>Point-to-Point</th>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Port status</h2>
|
||||
<table id="stpStatTbl">
|
||||
<tr>
|
||||
<th>Port</th><th>Port State</th><th>Role</th><th>Designated Bridge</th><th>Designated Port ID</th><th>Designated Cost</th><th>Oper. Edge</th><th>Oper. P2P</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-mirror" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="mirror_heading">Mirror Configuration</h1>
|
||||
<label class="tswitch"><span data-i18n="mirror_enabled">Enabled:</span> <input id="me" type="checkbox"></label><br/>
|
||||
<label for="mp"><span data-i18n="mirror_port">Mirroring Port:</span></label> <input type="number" id="mp" name="mp" min="1" max="9"/>
|
||||
<h2 data-i18n="mirror_tx">Mirrored Ports (TX)</h2>
|
||||
<div id="mPortsTX"></div>
|
||||
<br />
|
||||
<h2 data-i18n="mirror_rx">Mirrored Ports (RX)</h2>
|
||||
<div id="mPortsRX"></div>
|
||||
<br/> <input style="width:15%;" class="action" id="mirror_sub" onclick="mirrorSub();" type="button" data-i18n="mirror_update" value="Update / Create">
|
||||
<input style="width:15%;" class="action" id="mirror_del" onclick="mirrorDel();" type="button" data-i18n="mirror_disable" value="Disable Mirroring">
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-lag" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="lag_heading">Link Aggregation Groups Configuration</h1>
|
||||
<h2>LAG 1 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub0" onclick="lagSub(0);" type="button" data-i18n="lag_update" value="Update / Create"></h2>
|
||||
<div id="mLAG0"></div>
|
||||
<br />
|
||||
<h2>LAG 2 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub1" onclick="lagSub(1);" type="button" data-i18n="lag_update" value="Update / Create"></h2>
|
||||
<div id="mLAG1"></div>
|
||||
<br />
|
||||
<h2>LAG 3 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub2" onclick="lagSub(2);" type="button" data-i18n="lag_update" value="Update / Create"></h2>
|
||||
<div id="mLAG2"></div>
|
||||
<br />
|
||||
<h2>LAG 4 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub3" onclick="lagSub(3);" type="button" data-i18n="lag_update" value="Update / Create"></h2>
|
||||
<div id="mLAG3"></div>
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-eee" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="eee_heading">EEE Status</h1>
|
||||
<table id="eeetable">
|
||||
<tr> <th> </th> <th colspan="3" data-i18n="eee_advertising"> Advertising </th> <th colspan="3" data-i18n="eee_partner">Link-Partner advertises</th> <th></th></tr>
|
||||
<tr> <th data-i18n="eee_port">Port</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th data-i18n="eee_active">Active?</th></tr>
|
||||
</table>
|
||||
<div>
|
||||
<input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 1);" type="button" data-i18n="eee_enable" value="Enable EEE">
|
||||
<input style="width:20%;" class="action" id="eee_disable" onclick="eeeSub(0, 0);" type="button" data-i18n="eee_disable" value="Disable EEE">
|
||||
<section class="tab" id="tab-ports">
|
||||
<div class="card"><h2 data-i18n="pt_title">Port configuration</h2>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="page" id="page-bandwidth" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<h1 data-i18n="bw_heading">Ingress and Egress Bandwidth</h1>
|
||||
<table id="bwtable">
|
||||
<tr> <th> </th> <th colspan="3" data-i18n="bw_ingress"> Ingress </th> <th colspan="2" data-i18n="bw_egress">Egress</th> <th></th></tr>
|
||||
<tr> <th data-i18n="bw_col_port">Port</th> <th data-i18n="bw_col_limit">Limit</th> <th data-i18n="bw_col_bandwidth">Bandwidth [kBit/s]</th> <th data-i18n="bw_col_flow">Flow Control</th> <th data-i18n="bw_col_limit">Limit</th> <th data-i18n="bw_col_bandwidth">Bandwidth [kBit/s]</th> <th data-i18n="bw_col_apply">Apply</th></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-system" style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div class="tab-bar">
|
||||
<button class="tab-btn active" onclick="openTab(event, 'system-tab')" data-i18n="sys_tab_system">System</button>
|
||||
<button class="tab-btn" onclick="openTab(event, 'advanced-tab')" data-i18n="sys_tab_advanced">Advanced</button>
|
||||
<button class="tab-btn" onclick="openTab(event, 'console-tab')" data-i18n="sys_tab_console">Console</button>
|
||||
<section class="tab" id="tab-stp">
|
||||
<div class="card"><h2><span data-i18n="stp_title">Spanning tree</span> <span class="hint" data-i18n="stp_h">RSTP, 802.1w</span></h2>
|
||||
<label class="row"><span class="lb" data-i18n="c_enabled">Enabled</span>
|
||||
<span class="switch"><input type="checkbox" id="stpen"><i></i></span></label>
|
||||
<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">
|
||||
<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_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_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_fwd">Forward delay [s]</span><br><input class="in sm" id="stpfwd" type="number" min="4" max="30"></label>
|
||||
<label><span class="small mut" data-i18n="stp_txhold">TX hold</span><br><input class="in sm" id="stptxhold" type="number" min="1" max="10"></label>
|
||||
</div>
|
||||
<div style="margin-top:10px"><button class="ctl pri" id="stpbapply" data-i18n="stp_bridge_apply">Apply bridge settings</button></div>
|
||||
<p class="small mut" style="margin-top:8px" data-i18n="stp_prio_note">Lower priority wins the root election (default 8 = 32768). Settings apply immediately; use Save to flash to keep them.</p>
|
||||
</div>
|
||||
<div id="system-tab" class="tab-content active">
|
||||
<h1 data-i18n="sys_heading">System Settings</h1>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="hostname" data-i18n="sys_hostname">Hostname:</label></div>
|
||||
<div class="rcol"> <input id="hostname" type="text" maxlength="23" size="20"/>
|
||||
<div class="card"><h2 data-i18n="stp_portcfg">Port configuration</h2>
|
||||
<div class="scrollx"><table class="t" id="stpcfg">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="c_enabled">Enabled</th><th data-i18n="stp_edge">Edge</th><th data-i18n="stp_pcost">Path cost</th><th data-i18n="stp_pprio">Priority</th><th data-i18n="stp_guard">Guard</th><th data-i18n="stp_filter">BPDU filter</th><th data-i18n="stp_p2p">Point-to-point</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:8px" data-i18n="stp_port_note">Edge ports forward immediately and cause no topology change; Auto treats a port as edge after 3 s without BPDUs, and any received BPDU revokes it. Path cost 0 = automatic.</p>
|
||||
</div>
|
||||
<div class="card"><h2 data-i18n="stp_status">Port status</h2>
|
||||
<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>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-stats">
|
||||
<div class="card"><h2><span data-i18n="st_title">Port statistics</span> <span class="hint" data-i18n="st_h">totals since boot</span></h2>
|
||||
<div class="scrollx"><table class="t" id="stable">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="c_name">Name</th><th data-i18n="c_link">Link</th><th class="num" data-i18n="st_txg">TX good</th><th class="num" data-i18n="st_txb">TX bad</th><th class="num" data-i18n="st_rxg">RX good</th><th class="num" data-i18n="st_rxb">RX bad</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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="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>
|
||||
<tbody></tbody></table></div>
|
||||
<p class="small mut" id="vempty" style="display:none;margin-top:6px" data-i18n="v_empty">No VLANs configured.</p>
|
||||
</div>
|
||||
<div class="card"><h2 data-i18n="v_editor">VLAN editor</h2>
|
||||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
|
||||
<label><span data-i18n="v_vid">VID</span> <input class="in sm" id="vvid" type="number" min="1" max="4094"></label>
|
||||
<label><span data-i18n="c_name">Name</span> <input class="in" id="vname" size="12" maxlength="15" data-i18n-p="v_optional"></label>
|
||||
<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>
|
||||
<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 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 class="tab" id="tab-l2">
|
||||
<div class="card"><h2><span data-i18n="l2_title">MAC address table</span>
|
||||
<span class="hint"><input class="in" id="l2filter" data-i18n-p="l2_filter" size="14"></span></h2>
|
||||
<div style="display:flex;gap:10px;margin-bottom:10px">
|
||||
<button class="ctl" id="l2refresh" data-i18n="c_refresh">Refresh</button>
|
||||
<button class="ctl" id="l2flush" data-i18n="l2_flush">Flush learned entries</button>
|
||||
<span class="small mut" id="l2count" style="align-self:center"></span>
|
||||
</div>
|
||||
<div class="scrollx"><table class="t" id="l2table">
|
||||
<thead><tr><th data-sort="pport"><span data-i18n="c_port">Port</span><span class="arrow"></span></th><th data-sort="mac">MAC<span class="arrow"></span></th><th data-sort="vlan">VLAN<span class="arrow"></span></th><th data-sort="stat"><span data-i18n="c_type">Type</span><span class="arrow"></span></th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-mirror">
|
||||
<div class="card"><h2 data-i18n="m_title">Port mirroring</h2>
|
||||
<div style="display:flex;gap:12px;align-items:center;margin-bottom:10px;flex-wrap:wrap">
|
||||
<span class="badge" id="mstate">off</span>
|
||||
<label><span data-i18n="m_monitor">Monitor port</span> <select class="in" id="mport"></select></label>
|
||||
<button class="ctl pri" id="mapply" data-i18n="c_apply">Apply</button>
|
||||
<button class="ctl" id="moff" data-i18n="c_disable">Disable</button>
|
||||
</div>
|
||||
<div class="scrollx"><table class="t" id="mtable"><tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:6px" data-i18n="m_note">Both = mirror RX and TX of the port to the monitor port.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-lldp">
|
||||
<div class="card"><h2 data-i18n="lldp_title">LLDP</h2>
|
||||
<label class="row"><span class="lb" data-i18n="lldp_enabled">Enabled</span>
|
||||
<span class="switch"><input type="checkbox" id="lldp_en"><i></i></span>
|
||||
</label>
|
||||
<div class="scrollx"><table class="t" id="lldp_table">
|
||||
<thead><tr><th data-i18n="c_port">Port Number</th><th data-i18n="lldp_portname">Name</th><th data-i18n="lldp_enable">Send Frames</th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-isolate">
|
||||
<div class="card"><h2 data-i18n="iso_title">Port isolation</h2>
|
||||
<p class="small mut" style="margin-bottom:10px" data-i18n="iso_intro">A frame entering a port may only leave through the ports ticked in its row.</p>
|
||||
<div class="scrollx"><table class="t" id="isotbl" style="width:auto"><thead></thead><tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:6px" data-i18n="iso_legend">The cell of the port itself is always allowed.</p>
|
||||
<div style="display:flex;gap:12px;margin-top:10px">
|
||||
<button class="ctl pri" id="isoapply" data-i18n="c_apply">Apply</button>
|
||||
<button class="ctl" id="isoall" data-i18n="iso_all">Allow all</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-lag">
|
||||
<div id="lagwrap" class="grid2"></div>
|
||||
<p class="small mut" style="margin-top:10px" data-i18n="lag_note">A LAG needs at least one member to be saved in the startup config; applying an empty group clears it.</p>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-eee">
|
||||
<div class="card"><h2 data-i18n="e_title">Energy Efficient Ethernet</h2>
|
||||
<div class="scrollx"><table class="t" id="etable">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="e_adv">Advertised</th><th data-i18n="e_lp">Link partner</th><th data-i18n="e_active">Active</th><th data-i18n="e_enable">Enable</th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:8px" data-i18n="e_note">Advertised and link-partner flags per speed: 100M, 1G, 2.5G. SFP ports do not support EEE.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-bw">
|
||||
<div class="card"><h2><span data-i18n="bw_title">Bandwidth limits</span> <span class="hint" data-i18n="bw_h">Mbit/s, 0.016-10000</span></h2>
|
||||
<div class="scrollx"><table class="t" id="btable">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="bw_in">Ingress limit</th><th>Mbit/s</th><th data-i18n="bw_exceed">When exceeded</th><th data-i18n="bw_out">Egress limit</th><th>Mbit/s</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
<div class="card"><h2><span data-i18n="sc_title">Storm control</span> <span class="hint" data-i18n="sc_h">per port and traffic type, empty = off</span></h2>
|
||||
<div class="scrollx"><table class="t" id="sctable">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="sc_bcast">Broadcast</th><th data-i18n="sc_mcast">Multicast</th><th data-i18n="sc_ucast">Unknown unicast</th><th data-i18n="sc_umcast">Unknown multicast</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:8px" data-i18n="sc_note">Frames of a type above its limit are dropped where they enter the switch.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-system">
|
||||
<div class="grid2">
|
||||
<div class="card"><h2 data-i18n="sy_network">Network</h2>
|
||||
<label class="row"><span class="lb" data-i18n="i_host">Hostname</span><input class="in" id="sy-host" maxlength="23"></label>
|
||||
<label class="row"><span class="lb" data-i18n="i_ip">IP address</span><input class="in" id="sy-ip" size="15"></label>
|
||||
<label class="row"><span class="lb" data-i18n="i_mask">Netmask</span><input class="in" id="sy-mask" size="15"></label>
|
||||
<label class="row"><span class="lb" data-i18n="i_gw">Gateway</span><input class="in" id="sy-gw" size="15"></label>
|
||||
<div style="display:flex;gap:10px;margin-top:12px">
|
||||
<button class="ctl pri" id="sy-apply" data-i18n="c_apply">Apply</button>
|
||||
<button class="ctl" id="sy-dhcp" data-i18n="sy_dhcp" data-i18n-t="sy_dhcp_t">Use DHCP</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="ip" data-i18n="sys_ip">IP address:</label></div>
|
||||
<div class="rcol"> <input id="ip" type="text" size="15"/>
|
||||
</div>
|
||||
<div class="card"><h2 data-i18n="sy_services">Services</h2>
|
||||
<label class="row" style="justify-content:space-between"><span data-i18n="sy_igmp">IGMP snooping</span>
|
||||
<span class="switch"><input type="checkbox" id="sy-igmp"><i></i></span></label>
|
||||
<label class="row" style="justify-content:space-between"><span data-i18n="i_syslog">Syslog</span>
|
||||
<span class="switch"><input type="checkbox" id="sy-syslog"><i></i></span></label>
|
||||
<div class="row" style="display:flex;gap:8px;align-items:center;margin:-2px 0 10px">
|
||||
<span class="small mut" data-i18n="sy_server">Server</span>
|
||||
<input class="in" id="sy-sysip" style="flex:1;min-width:0;width:0" data-i18n-p="sy_sysip">
|
||||
<span class="small mut" data-i18n="sy_port">Port</span>
|
||||
<input class="in" id="sy-sysport" style="width:64px" type="number" min="1" max="65535"></div>
|
||||
<label class="row" style="justify-content:space-between"><span data-i18n="sy_sesstmo">Session timeout (s)</span>
|
||||
<input class="in" id="sy-sesstmo" style="width:80px" type="number" min="1" max="65535"></label>
|
||||
<p class="small mut" data-i18n="sy_services_note">Service state reflects the startup config; runtime state is not readable.</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="netmask" data-i18n="sys_netmask">Netmask:</label></div>
|
||||
<div class="rcol"> <input id="netmask" type="text" size="15"/>
|
||||
</div>
|
||||
<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_repeat">Repeat</span><input class="in" id="sy-pw2" type="password" maxlength="20"></label>
|
||||
<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>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="gw" data-i18n="sys_gateway">Gateway:</label></div>
|
||||
<div class="rcol"> <input id="gw" type="text" size="15"/>
|
||||
<div class="card"><h2 data-i18n="sy_console">Console</h2>
|
||||
<div style="display:flex;gap:8px">
|
||||
<input class="in" id="sy-cmd" style="flex:1" data-i18n-p="sy_cmd" spellcheck="false">
|
||||
<button class="ctl pri" id="sy-send" data-i18n="sy_send">Send</button>
|
||||
</div>
|
||||
<pre class="cfg" id="sy-cout" style="margin-top:10px;min-height:70px;max-height:180px;overflow:auto"></pre>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="model" data-i18n="sys_model">Model:</label></div>
|
||||
<div class="rcol"> <span id="model">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="lang-select" data-i18n="sys_language">Language:</label></div>
|
||||
<div class="rcol">
|
||||
<select id="lang-select" onchange="changeLang()">
|
||||
<div class="card"><h2 data-i18n="sy_display">Display</h2>
|
||||
<label class="row"><span class="lb" data-i18n="sy_lang">Language</span>
|
||||
<select class="in" id="langSel">
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="en">English</option>
|
||||
<option value="es">Español</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="ja">日本語</option>
|
||||
<option value="zh">中文</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</select></label>
|
||||
<label class="row"><span class="lb" data-i18n="sy_theme">Theme</span>
|
||||
<select class="in" id="themeSel">
|
||||
<option value="auto" data-i18n="th_auto">System</option>
|
||||
<option value="auto-sel" data-i18n="th_auto_sel">System (Selenized)</option>
|
||||
<option value="light" data-i18n="th_light">Light</option>
|
||||
<option value="dark" data-i18n="th_dark">Dark</option>
|
||||
<option value="sel-light" data-i18n="th_sel_light">Selenized Light</option>
|
||||
<option value="sel-dark" data-i18n="th_sel_dark">Selenized Dark</option>
|
||||
</select></label>
|
||||
<p class="small mut" data-i18n="sy_display_note">Stored in this browser only.</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="lcol"> <label for="mgmtvlan" data-i18n="sys_mgmt_vlan">Management VLAN:</label></div>
|
||||
<div class="rcol">
|
||||
<select id="mgmtvlan" onchange="mgmtVlanChanged()">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="margin-top:16px"><h2><span data-i18n="sy_startup">Startup configuration</span>
|
||||
<span class="hint"><span id="cfgbytes"></span>, <span data-i18n="sy_replayed">replayed on every boot</span></span></h2>
|
||||
<textarea class="cfg" id="cfgedit" spellcheck="false"></textarea>
|
||||
<div style="display:flex;gap:10px;margin-top:10px;flex-wrap:wrap">
|
||||
<button class="ctl" id="cfgreload" data-i18n="sy_reload">Reload from flash</button>
|
||||
<button class="ctl pri" id="cfgwrite" data-i18n="sy_write">Write to flash</button>
|
||||
<span class="small mut" style="align-self:center" data-i18n="sy_unknown_note">Unknown lines are highlighted before writing.</span>
|
||||
</div>
|
||||
<br/>
|
||||
<span data-i18n="sys_ip_note">When updating the above settings, remember to point your browser to the new IP afterwards:</span><br/>
|
||||
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" data-i18n="sys_update" value="Update Settings"><br/>
|
||||
<br/>
|
||||
<span data-i18n="sys_save_label">Save all current settings to Flash:</span><br/>
|
||||
<input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" data-i18n="sys_save" value="Save Settings to Flash">
|
||||
</div>
|
||||
|
||||
<div id="advanced-tab" class="tab-content">
|
||||
<h1 data-i18n="sys_advanced">Advanced Settings</h1>
|
||||
<div class="lcol"> <label for="config_display" data-i18n="sys_startup_config">Startup configuration:</label></div>
|
||||
<textarea id="config_display" rows="8" cols="60"></textarea>
|
||||
<br/><br/>
|
||||
<span data-i18n="sys_startup_warn">Be careful when saving the directly edited startup configuration, you can lock yourself out:</span><br/>
|
||||
<input style="width:40%;" class="action" id="clear_config" onclick="clearConfig();" type="button" data-i18n="sys_clear_config" value="Clear Startup Config">
|
||||
<br/>
|
||||
<input style="width:40%;" class="action" id="flash_startup_sub" onclick="flashStartupSave();" type="button" data-i18n="sys_save_startup" value="Save Startup Settings to Flash">
|
||||
<br/>
|
||||
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" data-i18n="sys_reset" value="Reset Switch">
|
||||
<div class="card dangerzone" style="margin-top:16px"><h2 data-i18n="sy_maint">Maintenance</h2>
|
||||
<button class="ctl danger" id="sy-reboot" data-i18n="sy_reboot">Reboot switch</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="console-tab" class="tab-content">
|
||||
<h1 data-i18n="sys_console">Console Command</h1>
|
||||
<label for="console_command" data-i18n="sys_enter_cmd">Enter command:</label>
|
||||
<input type="text" id="console_cmd" name="console_cmd" style="width:40%;">
|
||||
<input style="width:20%;" class="action" id="cmd_sub" onclick="cmdSub();" type="button" data-i18n="sys_send_cmd" value="Send Command"><br/>
|
||||
<br/><br/>
|
||||
<span data-i18n="sys_console_warn">Be careful when entering console commands, you can lock yourself out!</span><br/>
|
||||
<br/>
|
||||
<pre id="console_out" style="height:22em;overflow:auto;white-space:pre-wrap;border:1px solid;padding:0.5em;"></pre>
|
||||
<section class="tab" id="tab-fw">
|
||||
<div class="card"><h2 data-i18n="fw_title">Firmware update</h2>
|
||||
<p class="small mut" style="margin-bottom:12px" data-i18n="fw_intro">Upload an RTLPlayground image (512 KiB .bin). The image is staged to flash and CRC-checked; on success the switch reboots itself, re-verifies the image and applies it. The startup configuration is preserved.</p>
|
||||
<input type="file" id="fwfile" accept=".bin">
|
||||
<div id="fwinfo" class="small" style="margin:10px 0"></div>
|
||||
<div style="display:flex;gap:10px;align-items:center">
|
||||
<button class="ctl pri" id="fwup" disabled data-i18n="fw_upload">Upload</button>
|
||||
<progress id="fwprog" max="100" value="0" style="display:none;width:220px"></progress>
|
||||
<span class="small" id="fwstat"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div class="page" id="page-update" style="margin-left:16%;padding:1px 16px;height:1000px;width:40%;">
|
||||
<h1 data-i18n="update_heading">Firmware Update</h1>
|
||||
<form enctype="multipart/form-data" action="/upload" method="POST">
|
||||
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
|
||||
<span data-i18n="update_instruction">Choose a firmware update file to upload:</span> <br/> <br/>
|
||||
<input name="uploadedfile" type="file" accept=".bin" /><br />
|
||||
<input style="margin-top:3em" type="submit" data-i18n="update_upload" value="Upload File" />
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
<div id="toasts"></div>
|
||||
<div id="mback"><div id="modal">
|
||||
<div id="mhead"><span id="mtitle"></span><button id="mx">✕</button></div>
|
||||
<div id="mbody"></div><div id="mfoot"></div>
|
||||
</div></div>
|
||||
|
||||
<script src="/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,30 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<title data-i18n="login_title">RTL Switch Login</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="/main.js"></script>
|
||||
<script>
|
||||
function removeNote() {
|
||||
document.getElementById("incorrect").innerHTML = "";
|
||||
}
|
||||
window.addEventListener("load", function() {
|
||||
if (document.referrer.endsWith("login.html"))
|
||||
document.getElementById("incorrect").innerHTML = t('login_wrong');
|
||||
});
|
||||
</script>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Switch Login</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#f4f6f8;--panel:#ffffff;--bd:#d7dde4;--fg:#1a222c;--fg2:#5c6773;
|
||||
--ac:#0969da;--acfg:#ffffff;--bad:#cf222e;
|
||||
}
|
||||
:root[data-theme="dark"]{
|
||||
--bg:#0e1116;--panel:#161b22;--bd:#2c333c;--fg:#e6edf3;--fg2:#8d96a0;
|
||||
--ac:#4c8ef7;--acfg:#ffffff;--bad:#f85149;
|
||||
}
|
||||
:root[data-theme="sel-dark"]{
|
||||
--bg:#103c48;--panel:#184956;--bd:#2d5b69;--fg:#adbcbc;--fg2:#72898f;
|
||||
--ac:#4695f7;--acfg:#ffffff;--bad:#fa5750;
|
||||
}
|
||||
:root[data-theme="sel-light"]{
|
||||
--bg:#fbf3db;--panel:#ece3cc;--bd:#d5cdb6;--fg:#53676d;--fg2:#909995;
|
||||
--ac:#0072d4;--acfg:#ffffff;--bad:#d2212d;
|
||||
}
|
||||
*{box-sizing:border-box;margin:0}
|
||||
body{
|
||||
font:15px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
||||
background:var(--bg);color:var(--fg);
|
||||
min-height:100vh;display:flex;align-items:center;justify-content:center;
|
||||
}
|
||||
.card{
|
||||
background:var(--panel);border:1px solid var(--bd);border-radius:12px;
|
||||
padding:36px 32px;width:min(360px,92vw);
|
||||
box-shadow:0 8px 30px rgba(0,0,0,.12);
|
||||
}
|
||||
.logo{display:flex;align-items:center;gap:10px;margin-bottom:6px}
|
||||
h1{font-size:19px;font-weight:650}
|
||||
p.sub{color:var(--fg2);font-size:13px;margin-bottom:24px}
|
||||
label{display:block;font-size:13px;color:var(--fg2);margin-bottom:6px}
|
||||
input[type=password]{
|
||||
width:100%;padding:10px 12px;font-size:15px;color:var(--fg);
|
||||
background:var(--bg);border:1px solid var(--bd);border-radius:8px;outline:none;
|
||||
}
|
||||
input[type=password]:focus{border-color:var(--ac)}
|
||||
button{
|
||||
width:100%;margin-top:18px;padding:10px;font-size:15px;font-weight:600;
|
||||
color:var(--acfg);background:var(--ac);border:0;border-radius:8px;cursor:pointer;
|
||||
}
|
||||
button:hover{filter:brightness(1.1)}
|
||||
#err{color:var(--bad);font-size:13px;min-height:20px;margin-top:14px;text-align:center}
|
||||
</style>
|
||||
<script>
|
||||
(function(){
|
||||
var pref;
|
||||
try{pref=localStorage.getItem("theme")||"auto";}catch(e){pref="auto";}
|
||||
var dark=window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
var t=pref;
|
||||
if(pref==="auto")t=dark?"dark":"light";
|
||||
if(pref==="auto-sel")t=dark?"sel-dark":"sel-light";
|
||||
document.documentElement.dataset.theme=t;
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="login_page">
|
||||
<div class = "center">
|
||||
<h1 data-i18n="login_heading"> RTL Switch Login</h1>
|
||||
<form method="post" action="login">
|
||||
<div class="txt_field">
|
||||
<input name="pwd" type="password" autocomplete="current-password" onclick="removeNote()" required />
|
||||
<span></span>
|
||||
<label data-i18n="login_password">Password</label>
|
||||
<body>
|
||||
<div class="card">
|
||||
<div class="logo">
|
||||
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="var(--ac)" stroke-width="2">
|
||||
<rect x="2" y="7" width="20" height="10" rx="2"/>
|
||||
<path d="M6 11v2M10 11v2M14 11v2M18 11v2"/>
|
||||
</svg>
|
||||
<h1 id="hn">Switch Login</h1>
|
||||
</div>
|
||||
<input type="submit" data-i18n="login_login" value="Login"/>
|
||||
<h3 id="incorrect" style="margin-top: 5em;"></h3>
|
||||
<p class="sub" id="sub">RTLPlayground management interface</p>
|
||||
<form method="post" action="login">
|
||||
<label for="pwd" id="lp">Password</label>
|
||||
<input id="pwd" name="pwd" type="password" autocomplete="current-password" autofocus required
|
||||
oninput="document.getElementById('err').textContent=''">
|
||||
<button type="submit" id="lb">Sign in</button>
|
||||
<div id="err"></div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
(function(){
|
||||
var L={
|
||||
de:["Switch-Anmeldung","RTLPlayground-Verwaltungsoberfläche","Passwort","Anmelden","Falsches Passwort, bitte erneut versuchen."],
|
||||
en:["Switch Login","RTLPlayground management interface","Password","Sign in","Wrong password, try again."],
|
||||
ja:["スイッチ ログイン","RTLPlayground 管理インターフェース","パスワード","ログイン","パスワードが違います。もう一度お試しください。"],
|
||||
zh:["交换机登录","RTLPlayground 管理界面","密码","登录","密码错误,请重试。"],
|
||||
es:["Inicio de sesión del switch","Interfaz de gestión de RTLPlayground","Contraseña","Iniciar sesión","Contraseña incorrecta, inténtalo de nuevo."],
|
||||
fr:["Utilisateur du commutateur","Interface de management RTLPlayground","Mot de passe","Se connecter","Mot de passe erronné, essayez à nouveau."]
|
||||
};
|
||||
var l=null;
|
||||
try{l=localStorage.getItem("rtl_lang");}catch(e){}
|
||||
if(!L[l])l=(navigator.language||"en").slice(0,2);
|
||||
var s=L[l]||L.en;
|
||||
document.title=s[0];
|
||||
document.getElementById("hn").textContent=s[0];
|
||||
document.getElementById("sub").textContent=s[1];
|
||||
document.getElementById("lp").textContent=s[2];
|
||||
document.getElementById("lb").textContent=s[3];
|
||||
if(document.referrer.endsWith("login.html"))document.getElementById("err").textContent=s[4];
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="layer1" transform="translate(-314.07 -485.06)">
|
||||
<g id="g1" transform="translate(256.16 417.12)">
|
||||
<rect id="r1" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:4;fill:#ffffff" rx="4.514" ry="4.514" height="90.625" width="117.88" y="69.93" x="59.896"/>
|
||||
<g id="g2"> <g id="g3">
|
||||
<path class="bg" id="rect3787"
|
||||
d="m73.958 75.66h89.41c2.3083 0 4.1667 1.8583 4.1667 4.1667l0.00028 52.653h-21.742v9.414h-8.694l0.00004 12.586h-36.871l-0.00004-12.586h-8.694v-9.414h-21.742l-0.000336-52.653c-0.000011-2.3083 1.8583-4.1667 4.1667-4.1667z"
|
||||
style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2.5;fill:#dcdcdc"/>
|
||||
<g id="g4" transform="translate(-0.368)" style="stroke:#191919;stroke-linecap:square;fill:#666666">
|
||||
<rect id="r2" height="22.786" width="3.9062" y="75.747" x="80.556"/>
|
||||
<rect id="r3" height="22.786" width="3.9062" y="75.747" x="153.6" />
|
||||
<rect id="r4" height="22.786" width="3.9062" y="75.747" x="132.73"/>
|
||||
<rect id="r5" height="22.786" width="3.9062" y="75.747" x="122.3"/>
|
||||
<rect id="r6" height="22.786" width="3.9062" y="75.747" x="111.86"/>
|
||||
<rect id="r7" height="22.786" width="3.9062" y="75.747" x="101.43"/>
|
||||
<rect id="r8" height="22.786" width="3.9062" y="75.747" x="90.99"/>
|
||||
<rect id="r9" height="22.786" width="3.9062" y="75.747" x="143.17"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect class="led" id="r10" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2;fill:#1dfe0a" height="13.89" width="17.1" y="137.03" x="69.542"/>
|
||||
<rect class="led" id="r11" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2;fill:#ffd10a" height="13.89" width="17.1" y="137.03" x="150.68"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="layer1" transform="translate(-41.68,-55.95)">
|
||||
<g id="g1" transform="translate(-177.45,-12.07)">
|
||||
<g id="g2" transform="matrix(1.46,0,0,1.44,51.31,-317.4)">
|
||||
<path id="p1"
|
||||
d="m 117.94442,272.67478 h 7.64646 c 0.21062,0 0.38018,0.16649 0.38018,0.3733 v 4.69239 c 0,0.2068 -0.16956,0.3733 -0.38018,0.3733 h -2.1027 v 0.31956 h -3.44117 v -0.31956 h -2.1027 c -0.21062,0 -0.38018,-0.16649 -0.38018,-0.3733 v -4.69239 c 0,-0.20681 0.16956,-0.3733 0.38018,-0.3733 z"
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.4"/>
|
||||
<path class="bg" id="p2"
|
||||
d="m 118.36775,273.15632 h 6.79794 c 0.18725,0 0.338,0.14695 0.338,0.32946 v 4.14153 c 0,0.18252 -0.15074,0.32946 -0.338,0.32946 h -6.79794 c -0.18724,0 -0.338,-0.14695 -0.338,-0.32946 v -4.14153 c 0,-0.18252 0.15074,-0.32946 0.338,-0.32946 z"
|
||||
style="fill:#000000;stroke-width:0.26" />
|
||||
<path d="m 118.65,273.53 h 6.24 v 4.05 h -6.24 z" style="fill:#1a1a1a;stroke-width:0.26" id="p3" />
|
||||
<path d="m 118.86,276.61 h 5.82" style="fill:#1a1a1a;stroke:#000000;stroke-width:0.26" id="p4" />
|
||||
<path d="m 124.05,274.25 h 1.39 v 0.72 h -1.39 z" style="fill:#1a1a1a;stroke-width:0.26" id="p5" />
|
||||
<path d="m 124.05,276 h 1.39 v 0.72 h -1.39 z" style="fill:#1a1a1a;stroke-width:0.26" id="p6" />
|
||||
<path transform="matrix(0.26,0,0,0.26,116.9,272.11)" d="M 7.3648613,7.0152205 H 29.369861" style="opacity:0.61257;fill:#4d4d4d;stroke:#4d4d4d;filter:url(#filter17794-0)" id="p7" />
|
||||
</g>
|
||||
<g id="g3" style="opacity:1;fill:#37d733;" transform="matrix(0.93,0,0,0.92,62.18,-43.11)">
|
||||
<circle class="led" id="c1" cx="176.86" cy="125.7" r="0.93"/>
|
||||
<circle class="led" id="c2" r="0.93" cy="125.7" cx="180.84"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,172 +0,0 @@
|
||||
h1, h2, h3 {
|
||||
color: #226;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 12%;
|
||||
height: calc(100% - 50px);
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
li a {
|
||||
background-color: #aaf;
|
||||
display: block;
|
||||
color: #000;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Change the link color on hover */
|
||||
li a:hover {
|
||||
background-color: #226;
|
||||
color: white;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid #226;
|
||||
padding: 8px;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input[type=submit] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;border-radius: 15px;width: 100%;}
|
||||
input[type=submit]:hover { background-color: #226; color: white;}
|
||||
input[type=file] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;border-radius: 15px;width: 60%;}
|
||||
input[type=file]:hover { background-color: #226; color: white;}
|
||||
b
|
||||
button {padding: 8px; background-color:#99f; color:#000;border-radius: 15px;}
|
||||
button:hover { background-color: #226; color: white;}
|
||||
.action{padding: 8px 16px;margin-top: 2em;margin-right: 3em; background-color: #aaf;color: #000;border-radius: 15px; width: 100%;}
|
||||
.action:hover { background-color: #226; color: white;}
|
||||
|
||||
/* Port selection inputs */
|
||||
.psel {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.psel + img {
|
||||
cursor: pointer;
|
||||
opacity: 0.4;
|
||||
padding: 8px;
|
||||
}
|
||||
.psel:checked + img {
|
||||
/* outline: 2px solid #f00;*/
|
||||
opacity: 1.0;
|
||||
}
|
||||
object, img {
|
||||
margin: 0.5em 0.5em;
|
||||
}
|
||||
.cbgroup {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.cbgroup label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.disabled{ opacity: .4; background-color: #f88; color: #000}
|
||||
.isSFP{ opacity: .4; background-color: #660;}
|
||||
.isNOK{ color: #900;}
|
||||
.isOK{ color: #090;}
|
||||
.ip{padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
|
||||
.rotext{display:inline-block;padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
|
||||
.row {display: flex;}
|
||||
.rcol {flex: 90%;}
|
||||
.lcol {flex: 10%;}
|
||||
|
||||
/* Login page */
|
||||
.login_page {margin: 0; padding: 0; background: #aaf; height: 100vh; overflow: hidden;}
|
||||
.center{
|
||||
position: absolute; top: 50%; left: 50%;
|
||||
transform: translate(-50%, -40% );
|
||||
width: 500px; height: 400px;
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.center h1 {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid silver;
|
||||
}
|
||||
|
||||
.center form {
|
||||
padding: 0 60px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
form .txt_field{
|
||||
position: relative;
|
||||
border-bottom: 2px solid #adadad;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.txt_field input { width: 100%; padding: 0 5px; height: 40px; font-size: 16px; border: none;
|
||||
background: none;
|
||||
outline: none;}
|
||||
.txt_field label { position: absolute; top: 50%; left: 5px; color:#adadad; transform: translateY(-50%);
|
||||
font-size: 16px; pointer-events: none;transition: .5s; }
|
||||
.txt_field span::before{ content:''; position: absolute; top: 40px; left:0; width: 100%; height: 2px; background: #aaf;}
|
||||
.txt_field input:focus ~ label,
|
||||
.txt_field input:valid ~ label { top: -5px; color: #aaf; }
|
||||
|
||||
.tooltip {
|
||||
position: relative; display: inline-block; cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.tooltiptext {
|
||||
visibility: hidden;
|
||||
width: 260px;
|
||||
background-color: #226;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 5px 0;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 80%;
|
||||
left: 50%;
|
||||
margin-left: -130px;
|
||||
}
|
||||
|
||||
.tooltiptext::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent transparent black transparent;
|
||||
}
|
||||
|
||||
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
.tt_table {
|
||||
width: 100%; font-size:90%;
|
||||
}
|
||||
.tt_table td {
|
||||
text-align: left;
|
||||
}
|
||||
select { text-align-last: right; font-family: monospace}
|
||||
option { direction: rtl; font-family: sans-serif}
|
||||
#vlanTable td { text-align: left; }
|
||||
|
||||
.l2sort{cursor:pointer;user-select:none}
|
||||
.l2sort:hover{text-decoration:underline}
|
||||
.l2arrow{opacity:0.55;font-size:0.85em}
|
||||
.l2filter{width:100%;box-sizing:border-box;font-weight:normal;font-size:0.9em}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" version="1.1" viewBox="0 0 577 434.38">
|
||||
<defs>
|
||||
<radialGradient id="rG39" gradientUnits="userSpaceOnUse" cy="676.79" cx="508.65" gradientTransform="matrix(1,0,0,0.5704,-2,274.75)" r="86.402">
|
||||
<stop stop-color="#000000" offset="0"/>
|
||||
<stop stop-color="#000000" stop-opacity="0" offset="1"/>
|
||||
</radialGradient>
|
||||
<filter id="f39" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="2.8"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g transform="translate(-101.235,-272.06)">
|
||||
<path d="m420.75,672.71v-18.688l82.055-42.01,89.748,35.306v18.414l-93.012,43.848-78.792-36.871z" transform="matrix(3.115,0,0,3.115,-1188.5,-1524.8)" filter="url(#f39)" fill="url(#rG39)"/>
|
||||
<path style="color:#000000;" fill="#3a68b0" d="M143.37,387.98,384.43,501.62,630.32,385.7,389.26,272.06z"/>
|
||||
<path style="color:#000000;" fill="#5d9ce1" d="M384.43,501.62v141.21l245.89-115.92v-141.21z"/>
|
||||
<path style="color:#000000;" fill="#1b3a88" d="M143.37,387.98,384.43,501.62v141.21l-241.06-113.64z"/>
|
||||
<path fill-opacity="0.7" fill="#f2fdff" d="m422.47,315.78-38.514,5.6218-38.514,5.6218,16.367,5.3307-46.555,22.107,30.52,9.9405,46.555-22.107,16.367,5.3308,6.8691-15.929,6.9054-15.917z"/>
|
||||
<path fill-opacity="0.7" fill="#f2fdff" d="m269.31,421.78,6.8691-15.929,6.8691-15.929,16.367,5.3308,46.555-22.107,30.52,9.9405-46.555,22.107,16.367,5.3307-38.514,5.6218-38.477,5.6336z"/>
|
||||
<path fill-opacity="0.7" fill="#f2fdff" d="m507.05,352.03-38.514,5.6218-38.514,5.6218,16.367,5.3307-46.555,22.107,30.52,9.9405,46.555-22.107,16.367,5.3308,6.8691-15.929,6.9054-15.917z"/>
|
||||
<path fill-opacity="0.7" fill="#f2fdff" d="m353.9,458.03,6.8691-15.929,6.8691-15.929,16.367,5.3308,46.555-22.107,30.52,9.9405-46.555,22.107,16.367,5.3307-38.514,5.6218-38.477,5.6336z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -12,7 +12,11 @@
|
||||
#include "debug.h"
|
||||
|
||||
#define SESSION_ID_LENGTH 12
|
||||
#define SESSION_TIMEOUT 200
|
||||
#define SESSION_TIMEOUT_DEFAULT 200
|
||||
|
||||
/* Seconds of inactivity after which a session cookie stops validating.
|
||||
* Configurable with the "session" command, see cmd_parser.c. */
|
||||
__xdata uint16_t session_timeout = SESSION_TIMEOUT_DEFAULT;
|
||||
|
||||
#define CMARK_S 6
|
||||
|
||||
@@ -22,9 +26,9 @@
|
||||
extern volatile __xdata uint8_t sfr_data[4];
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern __xdata uint8_t cmd_capture; /* owned by rtlplayground.c, see write_char_no_syslog() */
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code struct f_data f_data[];
|
||||
extern __code char * __code mime_strings[];
|
||||
extern __code const uint8_t * __code const hex;
|
||||
extern __code const struct f_data f_data[];
|
||||
extern __code const char * __code const mime_strings[];
|
||||
extern __xdata struct flash_region_t flash_region;
|
||||
extern __xdata uint32_t flash_size;
|
||||
|
||||
@@ -37,6 +41,7 @@ __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
__xdata uint8_t entry;
|
||||
__xdata uint16_t slen;
|
||||
__xdata uint16_t o_idx;
|
||||
__xdata uint16_t sent_len;
|
||||
__xdata uint16_t len_left;
|
||||
__xdata uint16_t cont_len;
|
||||
__xdata uint32_t cont_addr;
|
||||
@@ -76,7 +81,6 @@ __xdata uint8_t fw_reset_pending;
|
||||
__xdata char session_id[SESSION_ID_LENGTH + 1];
|
||||
__xdata uint8_t authenticated;
|
||||
__xdata uint32_t now;
|
||||
__xdata uint8_t * __xdata timeptr;
|
||||
__xdata uint32_t last_session_use;
|
||||
|
||||
#define TSTATE_NONE 0
|
||||
@@ -127,7 +131,7 @@ uint8_t find_entry(__xdata uint8_t *e)
|
||||
}
|
||||
|
||||
|
||||
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
bool is_word(__xdata uint8_t *xdata_str_p, __code const uint8_t * __xdata code_str_p)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
@@ -149,7 +153,7 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
|
||||
|
||||
/* name must be lower-case, starting with the '\n' of the previous line's end */
|
||||
__xdata uint8_t *header_value(__xdata uint8_t *p, __code uint8_t *name)
|
||||
__xdata uint8_t *header_value(__xdata uint8_t *p, __code const uint8_t *name)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
@@ -341,14 +345,16 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
||||
|
||||
read_reg_timer(&now);
|
||||
|
||||
if (session) {
|
||||
if (now - last_session_use > SESSION_TIMEOUT) {
|
||||
if (session && session_id[0]) {
|
||||
if (now - last_session_use > session_timeout) {
|
||||
dbg_string("Session expired\n");
|
||||
} else {
|
||||
if (is_word_x(session, session_id))
|
||||
if (is_word_x(session, session_id)) {
|
||||
authenticated = 1;
|
||||
else
|
||||
last_session_use = now;
|
||||
} else {
|
||||
dbg_string("Invalid session cookie!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
@@ -375,8 +381,8 @@ void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
|
||||
static uint8_t config_take(void)
|
||||
{
|
||||
// #386: needs static, otherwise it still lands in SRAM/DSEG
|
||||
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
|
||||
__xdata uint8_t cfg_bl;
|
||||
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last, cfg_i;
|
||||
__xdata uint8_t cfg_bl, cfg_run;
|
||||
|
||||
cfg_bl = strlen_x(boundary);
|
||||
|
||||
@@ -418,6 +424,13 @@ static uint8_t config_take(void)
|
||||
// the payload plus its terminator must fit the sector
|
||||
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
|
||||
return 2;
|
||||
cfg_run = 0;
|
||||
for (cfg_i = cfg_body; cfg_i < cfg_end; cfg_i++) {
|
||||
if (config_buf[cfg_i] == '\n')
|
||||
cfg_run = 0;
|
||||
else if (++cfg_run >= CMD_BUF_SIZE - 1)
|
||||
return 2;
|
||||
}
|
||||
config_buf[cfg_end] = 0;
|
||||
flash_region.addr = CONFIG_START;
|
||||
flash_sector_erase();
|
||||
@@ -530,6 +543,19 @@ uint8_t stream_upload(void)
|
||||
crc16_bank1(upload_settings.p + upload_settings.bptr);
|
||||
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
||||
if (write_len >= FLASH_PAGE_SIZE) {
|
||||
/* The staged image spans FIRMWARE_UPLOAD_START to twice that,
|
||||
* the span check_and_flash_update_image() reads back. Nothing
|
||||
* else bounds uptr: a body whose closing boundary never arrives
|
||||
* keeps writing, and on a flash exactly this size the address
|
||||
* wraps onto the running image at zero. */
|
||||
if (uptr >= (uint32_t)FIRMWARE_UPLOAD_START * 2) {
|
||||
print_string("Upload runs past the image area! Aborting.\n");
|
||||
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 30\r\n"
|
||||
"Content-Type: text/plain\r\n\r\n"
|
||||
"NO: upload exceeds image area\n");
|
||||
s->tstate = TSTATE_NONE;
|
||||
return 0;
|
||||
}
|
||||
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
||||
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
||||
if (uptr % FLASH_SECTOR_SIZE == 0) {
|
||||
@@ -559,7 +585,7 @@ static void handle_config_fragment(__xdata uint8_t *p)
|
||||
__xdata uint16_t frag_len;
|
||||
uint8_t taken;
|
||||
|
||||
frag_len = uip_len - (p - uip_appdata);
|
||||
frag_len = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Configuration too large, aborting.\n");
|
||||
config_upload = 0;
|
||||
@@ -589,7 +615,7 @@ static void handle_firmware_fragment(__xdata uint8_t *p)
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata uint16_t frag_len, payload_start;
|
||||
|
||||
frag_len = uip_len - (p - uip_appdata);
|
||||
frag_len = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Firmware upload header too large, aborting.\n");
|
||||
config_upload = 0;
|
||||
@@ -684,7 +710,7 @@ static uint8_t post_body_take(__xdata uint8_t *p)
|
||||
send_bad_request();
|
||||
return 0;
|
||||
}
|
||||
have = uip_len - (p - uip_appdata);
|
||||
have = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||
if (have >= content_length) {
|
||||
p[content_length] = NUL;
|
||||
return 1;
|
||||
@@ -750,6 +776,10 @@ void handle_post(void)
|
||||
return;
|
||||
}
|
||||
if (is_word(request_path, "upload")) {
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
||||
{
|
||||
print_string("Flash too small for firmware upload!\n");
|
||||
@@ -777,7 +807,23 @@ void handle_post(void)
|
||||
dbg_string("Multipart request\n");
|
||||
}
|
||||
|
||||
if (is_word(request_path, "cmd")) {
|
||||
if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
dbg_string("POST upload/config request\n");
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
if (!boundary[0]) {
|
||||
dbg_string("Bad request, no boundary!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
if (config_upload)
|
||||
handle_config_fragment(p);
|
||||
else
|
||||
handle_firmware_fragment(p);
|
||||
return;
|
||||
} else if (is_word(request_path, "cmd")) {
|
||||
p += 4;
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
@@ -803,22 +849,6 @@ void handle_post(void)
|
||||
return;
|
||||
run_login_body(p);
|
||||
return;
|
||||
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
dbg_string("POST upload/config request\n");
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
if (!boundary[0]) {
|
||||
dbg_string("Bad request, no boundary!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
if (config_upload)
|
||||
handle_config_fragment(p);
|
||||
else
|
||||
handle_firmware_fragment(p);
|
||||
return;
|
||||
} else {
|
||||
send_not_found();
|
||||
return;
|
||||
@@ -826,6 +856,13 @@ void handle_post(void)
|
||||
}
|
||||
|
||||
|
||||
static void tx_send(uint16_t len)
|
||||
{
|
||||
sent_len = len;
|
||||
uip_send(outbuf + o_idx, len);
|
||||
}
|
||||
|
||||
|
||||
void httpd_appcall(void)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
@@ -861,23 +898,22 @@ void httpd_appcall(void)
|
||||
}
|
||||
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
||||
dbg_string("ACK\n");
|
||||
if (slen > uip_mss()) {
|
||||
slen -= uip_mss();
|
||||
o_idx += uip_mss();
|
||||
if (slen > sent_len) {
|
||||
slen -= sent_len;
|
||||
o_idx += sent_len;
|
||||
} else {
|
||||
slen = 0;
|
||||
o_idx += slen;
|
||||
}
|
||||
|
||||
s->tstate = TSTATE_ACKED;
|
||||
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
tx_send(uip_mss());
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (slen > 0) {
|
||||
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
tx_send(slen);
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (cont_len) {
|
||||
dbg_string("CONT cont_len: "); dbg_short(cont_len);
|
||||
@@ -887,7 +923,8 @@ void httpd_appcall(void)
|
||||
flash_region.addr = cont_addr;
|
||||
flash_region.len = slen;
|
||||
flash_read_bulk(outbuf);
|
||||
uip_send(outbuf, slen);
|
||||
o_idx = 0;
|
||||
tx_send(slen);
|
||||
cont_len -= slen;
|
||||
cont_addr += slen;
|
||||
s->tstate = TSTATE_TX;
|
||||
@@ -898,8 +935,9 @@ void httpd_appcall(void)
|
||||
reset_chip();
|
||||
}
|
||||
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||
// Check here maxupload by subtracting uip_len and close socekt if fails!
|
||||
if (max_upload - uip_len > 0) {
|
||||
if (config_upload || uip_len <= max_upload) {
|
||||
if (!config_upload)
|
||||
max_upload -= uip_len;
|
||||
upload_settings.p = uip_appdata;
|
||||
upload_settings.bptr = 0;
|
||||
upload_settings.plen = uip_len;
|
||||
@@ -978,6 +1016,8 @@ void httpd_appcall(void)
|
||||
send_eee();
|
||||
} else if (is_word(q, "/bandwidth.json")) {
|
||||
send_bandwidth();
|
||||
} else if (is_word(q, "/storm.json")) {
|
||||
send_storm();
|
||||
} else if (is_word(q, "/l2.json")) {
|
||||
parse_short(q + 13); // e.g.: /l2.json?idx=10
|
||||
send_l2(short_parsed);
|
||||
@@ -986,12 +1026,16 @@ void httpd_appcall(void)
|
||||
l2_delete(short_parsed);
|
||||
} else if (is_word(q, "/mirror.json")) {
|
||||
send_mirror();
|
||||
} else if (is_word(q, "/isolation.json")) {
|
||||
send_isolation();
|
||||
} else if (is_word(q, "/mtu.json")) {
|
||||
send_mtu();
|
||||
} else if (is_word(q, "/lag.json")) {
|
||||
send_lag();
|
||||
} else if (is_word(q, "/stp.json")) {
|
||||
send_stp();
|
||||
} else if (is_word(q, "/lldp.json")) {
|
||||
send_lldp();
|
||||
} else if (is_word(q, "/vlanlist")) {
|
||||
send_vlanlist();
|
||||
} else if (is_word(q, "/config")) {
|
||||
@@ -1010,19 +1054,11 @@ void httpd_appcall(void)
|
||||
}
|
||||
} else {
|
||||
dbg_string("Have entry, authenticated: "); dbg_byte(authenticated); dbg_char('\n');
|
||||
if (!authenticated && !(f_data[entry].start == FDATA_START_login_html
|
||||
|| f_data[entry].start == FDATA_START_port_svg
|
||||
|| f_data[entry].start == FDATA_START_sfp_svg
|
||||
|| f_data[entry].start == FDATA_START_main_js
|
||||
|| f_data[entry].start == FDATA_START_style_css)) {
|
||||
if (!authenticated && !(f_data[entry].start == FDATA_START_login_html
|
||||
|| f_data[entry].start == FDATA_START_favicon_ico)) {
|
||||
send_to_login();
|
||||
goto do_send;
|
||||
}
|
||||
// A web-page is actively accessed, we can reset session time-out
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
timeptr = (uint8_t*)&last_session_use; // last_session_use is Little endian
|
||||
timeptr[0] = sfr_data[3]; timeptr[1] = sfr_data[2]; timeptr[2] = sfr_data[1]; timeptr[3] = sfr_data[0];
|
||||
|
||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: ");
|
||||
slen += strtox(outbuf + slen, mime_strings[f_data[entry].mime]);
|
||||
/* 'unsafe-inline' is needed for the inline onclick handlers
|
||||
@@ -1053,24 +1089,20 @@ do_send:
|
||||
o_idx = 0;
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
tx_send(uip_mss());
|
||||
dbg_string("Sending a done\n");
|
||||
} else {
|
||||
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
tx_send(slen);
|
||||
dbg_string("Sending b done\n");
|
||||
}
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
||||
dbg_string("RETRANSMIT requested\n");
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
if (sent_len) {
|
||||
dbg_string("Sending C: "); dbg_short(sent_len); dbg_char('\n');
|
||||
tx_send(sent_len);
|
||||
dbg_string("Sending C done\n");
|
||||
} else if (slen > 0) {
|
||||
dbg_string("Sending D: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
dbg_string("Sending D done\n");
|
||||
}
|
||||
s->tstate = TSTATE_TX;
|
||||
uip_len = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "rtl837x_pins.h"
|
||||
@@ -28,9 +29,10 @@ extern __code const struct machine machine;
|
||||
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
extern __xdata uint16_t slen;
|
||||
extern __xdata uint16_t management_vlan;
|
||||
extern __xdata uint16_t session_timeout;
|
||||
extern __xdata uint16_t cont_len;
|
||||
extern __xdata uint32_t cont_addr;
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
@@ -47,8 +49,11 @@ extern __xdata char sfp_module_model[2][17];
|
||||
extern __xdata char sfp_module_serial[2][17];
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
|
||||
__code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||
__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
||||
extern __xdata uint16_t lldp_logical_port_status;
|
||||
extern __xdata bool lldp_enabled;
|
||||
|
||||
__code const uint8_t * __code const HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||
__code const uint8_t * __code const HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
||||
|
||||
// Convert uint8_t to ascii HEX char push on html-buffer.
|
||||
void charhex_to_html(char c)
|
||||
@@ -70,6 +75,21 @@ void char_to_html(char c)
|
||||
}
|
||||
|
||||
|
||||
static void str_x_to_html(__xdata const char *s)
|
||||
{
|
||||
while (*s)
|
||||
outbuf[slen++] = *s++;
|
||||
}
|
||||
|
||||
|
||||
void json_char_to_html(uint8_t c)
|
||||
{
|
||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||
c = '.';
|
||||
outbuf[slen++] = c;
|
||||
}
|
||||
|
||||
|
||||
// Convert uint8_t to ascii HEX char.
|
||||
void byte_to_html(uint8_t val)
|
||||
{
|
||||
@@ -99,12 +119,14 @@ void itoa_html(uint8_t v)
|
||||
char_to_html('0' + (v % 10));
|
||||
}
|
||||
|
||||
void itoa16_html(uint16_t v) /* sufficient for VLAN IDs (max 4094) */
|
||||
void itoa16_html(uint16_t v) /* up to five digits (65535) */
|
||||
{
|
||||
uint8_t print_zeros = 0;
|
||||
uint8_t d;
|
||||
d = v / 1000;
|
||||
d = v / 10000;
|
||||
if (d) { char_to_html('0' + d); print_zeros = 1; }
|
||||
d = (v / 1000) % 10;
|
||||
if (d || print_zeros) { char_to_html('0' + d); print_zeros = 1; }
|
||||
d = (v / 100) % 10;
|
||||
if (d || print_zeros) { char_to_html('0' + d); print_zeros = 1; }
|
||||
d = (v / 10) % 10;
|
||||
@@ -112,11 +134,28 @@ void itoa16_html(uint16_t v) /* sufficient for VLAN IDs (max 4094) */
|
||||
char_to_html('0' + (v % 10));
|
||||
}
|
||||
|
||||
void string_to_html(__code char *s)
|
||||
void string_to_html(__code const char *s)
|
||||
{
|
||||
while (*s) char_to_html(*s++);
|
||||
}
|
||||
|
||||
static void temp_to_html(void)
|
||||
{
|
||||
int16_t v;
|
||||
|
||||
reg_read(RTL837X_TM_RESULT);
|
||||
v = SFR_DATA_U16;
|
||||
if (v < 0) {
|
||||
char_to_html('-');
|
||||
v = -v;
|
||||
}
|
||||
itoa_html(v >> 7);
|
||||
char_to_html('.');
|
||||
itoa_html(((v & 0x7f) * 10) >> 7);
|
||||
char_to_html(' ');
|
||||
char_to_html('C');
|
||||
}
|
||||
|
||||
uint16_t stat_content(void)
|
||||
{
|
||||
dbg_string("stat_content called\n");
|
||||
@@ -175,6 +214,20 @@ void reg_to_html_long(uint16_t reg)
|
||||
}
|
||||
|
||||
|
||||
/* The 64-bit counter of the last STAT_GET as one number: the low word keeps
|
||||
* its leading zeros whenever the high word is set. */
|
||||
void counter_to_html(void)
|
||||
{
|
||||
reg_read_m(RTL837X_STAT_V_HIGH);
|
||||
if (SFR_DATA_24 | SFR_DATA_16 | SFR_DATA_8 | SFR_DATA_0) {
|
||||
sfr_data_to_html();
|
||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||
} else {
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_sfp_info(uint8_t sfp)
|
||||
{
|
||||
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||
@@ -184,8 +237,8 @@ void send_sfp_info(uint8_t sfp)
|
||||
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
||||
continue;
|
||||
uint8_t c = sfp_buf[i & 0xf];
|
||||
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
|
||||
char_to_html(c);
|
||||
if (c)
|
||||
json_char_to_html(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +282,9 @@ void send_basic_info(void)
|
||||
itoa_html(syslog_state.server_ip[2]); char_to_html('.');
|
||||
itoa_html(syslog_state.server_ip[3]); char_to_html(':');
|
||||
itoa16_html(syslog_state.server_port);
|
||||
slen += strtox(outbuf + slen, "\",\"mac_address\":\"");
|
||||
slen += strtox(outbuf + slen, "\",\"session_timeout\":");
|
||||
itoa16_html(session_timeout);
|
||||
slen += strtox(outbuf + slen, ",\"mac_address\":\"");
|
||||
byte_to_html(uip_ethaddr.addr[0]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[1]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[2]); char_to_html(':');
|
||||
@@ -248,6 +303,8 @@ void send_basic_info(void)
|
||||
slen += strtox(outbuf + slen, BUILD_DATE);
|
||||
slen += strtox(outbuf + slen, "\",\"hw_ver\":\"");
|
||||
slen += strtox(outbuf + slen, machine.machine_name);
|
||||
slen += strtox(outbuf + slen, "\",\"chip_temp\":\"");
|
||||
temp_to_html();
|
||||
slen += strtox(outbuf + slen, "\",\"flash_size\":\"");
|
||||
string_to_html(get_flash_size_str());
|
||||
|
||||
@@ -279,7 +336,7 @@ void send_vlan(uint16_t vlan)
|
||||
dbg_string("VLAN has no name\n");
|
||||
} else {
|
||||
while(vlan_names[n] && vlan_names[n] != ' ')
|
||||
char_to_html(vlan_names[n++]);
|
||||
json_char_to_html(vlan_names[n++]);
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
||||
uint16_t pvid_mask = 0;
|
||||
@@ -311,8 +368,7 @@ bool send_counters(uint8_t phys_port)
|
||||
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
||||
STAT_GET(counter, log_port);
|
||||
slen += strtox(outbuf + slen, "\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||
counter_to_html();
|
||||
char_to_html('\"');
|
||||
if (counter != 0x36)
|
||||
char_to_html(',');
|
||||
@@ -432,8 +488,6 @@ void l2_delete(uint16_t idx)
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("L2 DELETE\n");
|
||||
dbg_short(idx);
|
||||
__xdata uint8_t entries_left = L2_MAX_TRANSFER;
|
||||
|
||||
do {
|
||||
reg_read(RTL837X_TBL_CTRL);
|
||||
} while (SFR_DATA_0 & TBL_EXECUTE);
|
||||
@@ -568,7 +622,6 @@ static void bridge_to_html(void)
|
||||
byte_to_html(pi_mac[i]);
|
||||
}
|
||||
|
||||
|
||||
void send_stp(void)
|
||||
{
|
||||
uint8_t i, j, st, dsg;
|
||||
@@ -607,17 +660,43 @@ void send_stp(void)
|
||||
slen += strtox(outbuf + slen, "\",\"weRoot\":");
|
||||
bool_to_html(stp_root_port == 0xff ? 1 : 0);
|
||||
slen += strtox(outbuf + slen, ",\"rootPort\":");
|
||||
itoa_html(stp_root_port == 0xff ? 0 : machine.log_to_phys_port[stp_root_port]);
|
||||
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 = machine.min_port; i <= machine.max_port; i++) {
|
||||
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(machine.log_to_phys_port[i]);
|
||||
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\":");
|
||||
st = (sfr_data[3 - (i >> 2)] >> ((i << 1) & 0x7)) & 0x3;
|
||||
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))
|
||||
@@ -657,6 +736,37 @@ void send_stp(void)
|
||||
slen += strtox(outbuf + slen, "]}");
|
||||
}
|
||||
|
||||
void send_lldp(void)
|
||||
{
|
||||
dbg_string("send_lldp called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
|
||||
slen += strtox(outbuf + slen, "{\"on\":");
|
||||
bool_to_html(lldp_enabled);
|
||||
slen += strtox(outbuf + slen, ",\"portStatus\":[");
|
||||
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
|
||||
slen += strtox(outbuf + slen, ",\"logPort\":");
|
||||
itoa_html(i);
|
||||
slen += strtox(outbuf + slen, ",\"name\":\"");
|
||||
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
||||
json_char_to_html(port_names[i][j]);
|
||||
}
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"permitted\":");
|
||||
bool_to_html(1 & (lldp_logical_port_status >> i));
|
||||
slen += strtox(outbuf + slen, "}");
|
||||
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
char_to_html('}');
|
||||
}
|
||||
|
||||
void send_eee(void)
|
||||
{
|
||||
@@ -750,6 +860,63 @@ void send_bandwidth(void)
|
||||
}
|
||||
|
||||
|
||||
void send_storm(void)
|
||||
{
|
||||
__xdata uint8_t i, t, idx;
|
||||
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
char_to_html('[');
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
slen += strtox(outbuf + slen, ",\"en\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++)
|
||||
char_to_html(reg_bit_test(RTL837X_STORM_CTRL + (t << 2), i) ? '1' : '0');
|
||||
slen += strtox(outbuf + slen, "\",\"pps\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
idx = STORM_METER(i, t);
|
||||
char_to_html(reg_bit_test(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f) ? '1' : '0');
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\",\"rate\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
reg_read_m(RTL837X_METER_RATE + (STORM_METER(i, t) << 2));
|
||||
byte_to_html(sfr_data[1]);
|
||||
byte_to_html(sfr_data[2]);
|
||||
byte_to_html(sfr_data[3]);
|
||||
}
|
||||
char_to_html('"');
|
||||
char_to_html('}');
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_isolation(void)
|
||||
{
|
||||
__xdata uint16_t allow;
|
||||
|
||||
dbg_string("send_isolation called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
char_to_html('[');
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
slen += strtox(outbuf + slen, ",\"allow\":\"");
|
||||
allow = port_isolation_get(i);
|
||||
byte_to_html(allow >> 8);
|
||||
byte_to_html(allow & 0xff);
|
||||
char_to_html('"');
|
||||
char_to_html('}');
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
}
|
||||
char_to_html(']');
|
||||
}
|
||||
|
||||
|
||||
void send_mtu(void)
|
||||
{
|
||||
dbg_string("send_mtu called\n");
|
||||
@@ -786,7 +953,7 @@ void send_status(void)
|
||||
itoa_html(i);
|
||||
slen += strtox(outbuf + slen, ",\"name\":\"");
|
||||
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
||||
char_to_html(port_names[i][j]);
|
||||
json_char_to_html(port_names[i][j]);
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\"");
|
||||
|
||||
@@ -825,14 +992,11 @@ void send_status(void)
|
||||
sfp_send_data(sfp, 238, 1);
|
||||
}
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_vendor[sfp][s];
|
||||
str_x_to_html(sfp_module_vendor[sfp]);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_model[sfp][s];
|
||||
str_x_to_html(sfp_module_model[sfp]);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_serial[sfp][s];
|
||||
str_x_to_html(sfp_module_serial[sfp]);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
||||
if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
|
||||
slen += strtox(outbuf + slen,"null");
|
||||
@@ -886,8 +1050,7 @@ void send_status(void)
|
||||
|
||||
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
||||
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
counter_to_html();
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"txB\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
@@ -895,8 +1058,7 @@ void send_status(void)
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"rxG\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_RX_PKTS, i);
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
counter_to_html();
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
@@ -962,7 +1124,7 @@ void send_cmd_log(void)
|
||||
__xdata uint8_t found_begin = 0;
|
||||
dbg_string("History ptr: ");
|
||||
dbg_short(cmd_history_ptr); dbg_char('\n');
|
||||
while (p != cmd_history_ptr) {
|
||||
while (p != cmd_history_ptr && slen < TCP_OUTBUF_SIZE) {
|
||||
if (!cmd_history[p] || cmd_history[p] == '\n')
|
||||
found_begin = 1;
|
||||
if (found_begin && cmd_history[p])
|
||||
@@ -987,8 +1149,7 @@ void send_vlanlist(void)
|
||||
slen += strtox(outbuf + slen, ",\"vlan\":[");
|
||||
|
||||
for (i = 1; i < 4095; i++) {
|
||||
if (vlan_get(i) < 0)
|
||||
continue;
|
||||
vlan_get(i);
|
||||
if (!(sfr_data[0] & 0x02)) /* bit 1: VLAN table entry valid */
|
||||
continue;
|
||||
|
||||
@@ -1006,7 +1167,7 @@ void send_vlanlist(void)
|
||||
n = vlan_name(i);
|
||||
if (n != 0xffff) {
|
||||
while (vlan_names[n] && vlan_names[n] != ' ')
|
||||
char_to_html(vlan_names[n++]);
|
||||
json_char_to_html(vlan_names[n++]);
|
||||
}
|
||||
|
||||
slen += strtox(outbuf + slen, "\"}");
|
||||
|
||||
@@ -3,22 +3,27 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern __code uint8_t * __code HTTP_RESPONCE_TXT;
|
||||
extern __code const uint8_t * __code const HTTP_RESPONCE_TXT;
|
||||
|
||||
void itoa16_html(uint16_t v);
|
||||
|
||||
bool send_counters(uint8_t phys_port);
|
||||
void send_status(void);
|
||||
void send_vlan(uint16_t vlan);
|
||||
void send_basic_info(void);
|
||||
void send_bandwidth(void);
|
||||
void send_storm(void);
|
||||
void send_eee(void);
|
||||
void send_l2(uint16_t idx);
|
||||
void l2_delete(uint16_t idx);
|
||||
void send_mirror(void);
|
||||
void send_mtu(void);
|
||||
void send_isolation(void);
|
||||
void send_config(void);
|
||||
void send_cmd_log(void);
|
||||
void send_lag(void);
|
||||
void send_stp(void);
|
||||
void send_lldp(void);
|
||||
void send_vlanlist(void);
|
||||
|
||||
/* Convert only the lower nibble to ascii HEX char.
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
__xdata uint8_t buffer[0x1000];
|
||||
__xdata uint8_t dio_enabled;
|
||||
|
||||
__code uint8_t * __code hex = "0123456789abcdef";
|
||||
__code const uint8_t * __code const hex = "0123456789abcdef";
|
||||
|
||||
void isr_timer0(void) __interrupt(1)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ void write_char(char c)
|
||||
}
|
||||
|
||||
|
||||
void print_string(__code char *p)
|
||||
void print_string(__code const char *p)
|
||||
{
|
||||
while (*p)
|
||||
write_char(*p++);
|
||||
|
||||
@@ -5,6 +5,29 @@
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_common.h"
|
||||
|
||||
#define I2CBUS_INVALID (7)
|
||||
// This is a MACRO to check if I2C_BUS_FROM_SDA_PIN or I2C_BUS_FROM_SCL_PIN don't return I2CBUS_INVALID.
|
||||
// When I2CBUS_INVALID is returned, compiler stops with "machine.c:<line>: error 176: sizeof applied to an incomplete type"
|
||||
#define I2CBUS_VALID(bus) (0 * sizeof(char[(bus) != I2CBUS_INVALID ? 1 : 0]))
|
||||
#define I2CBUS(sda, scl) \
|
||||
((uint8_t)((I2C_BUS_FROM_SCL_PIN(scl) << RTL837X_REG_I2C_SCL_SHIFT) | \
|
||||
(I2C_BUS_FROM_SDA_PIN(sda) << RTL837X_REG_I2C_SDA_SHIFT) | \
|
||||
I2CBUS_VALID(I2C_BUS_FROM_SCL_PIN(scl)) | \
|
||||
I2CBUS_VALID(I2C_BUS_FROM_SDA_PIN(sda))))
|
||||
|
||||
#define I2C_BUS_FROM_SDA_PIN(sda_pin) \
|
||||
((sda_pin) == GPIO47_I2C_SDA0 ? 0 : \
|
||||
(sda_pin) == GPIO49_I2C_SDA1 ? 1 : \
|
||||
(sda_pin) == GPIO51_I2C_SDA2_UART1_RX ? 2 : \
|
||||
(sda_pin) == GPIO41_I2C_SDA3_MDIO1 ? 3 : \
|
||||
(sda_pin) == GPIO39_I2C_SDA4 ? 4 : I2CBUS_INVALID)
|
||||
|
||||
#define I2C_BUS_FROM_SCL_PIN(scl_pin) \
|
||||
((scl_pin) == GPIO46_I2C_SCL0 ? 0 : \
|
||||
(scl_pin) == GPIO48_I2C_SCL1 ? 1 : \
|
||||
(scl_pin) == GPIO50_I2C_SCL2_UART1_TX ? 2 : \
|
||||
(scl_pin) == GPIO40_I2C_SCL3_MDC1 ? 3 : I2CBUS_INVALID)
|
||||
|
||||
#if defined(MACHINE_KP_9000_6XHML_X2) || \
|
||||
defined(MACHINE_KP_9000_6XH_X2_V1_1) || \
|
||||
defined(MACHINE_KP_9000_6XHML_X2_V1_1) || \
|
||||
@@ -34,13 +57,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO10_LED10,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
// Right SFP port (6)
|
||||
.sfp_port[1].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.sfp_port[1].pin_los = GPIO37,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.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},
|
||||
@@ -70,7 +93,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
/* Conditions for LED on:
|
||||
* dual led orange: ledset_0 & ledset_2
|
||||
@@ -105,13 +128,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// Right SFP port
|
||||
.sfp_port[1].pin_detect = GPIO37,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO48_I2C_SCL1, // Button-Switch is unpopulated on PCB, but can be added manually (hole in case is already there)
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -152,7 +175,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.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},
|
||||
@@ -177,7 +200,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.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 },
|
||||
@@ -214,9 +237,14 @@ __code const struct machine machine = {
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_KP_9000_9XHML_X_V3_1
|
||||
#elif defined(MACHINE_KP_9000_9XHML_X_V3_1) || defined(MACHINE_KP_9000_9XHML_X_V3_2)
|
||||
// 2M-PCB23-V3.2 is wired like V3.1 (SFP detection, LEDs, factory MAC location)
|
||||
__code const struct machine machine = {
|
||||
#if defined(MACHINE_KP_9000_9XHML_X_V3_2)
|
||||
.machine_name = "keepLink KP-9000-9XHML-X V3.2",
|
||||
#else
|
||||
.machine_name = "keepLink KP-9000-9XHML-X V3.1",
|
||||
#endif
|
||||
.isRTL8373 = 1,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
@@ -227,7 +255,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO48_I2C_SCL1,
|
||||
.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},
|
||||
@@ -247,6 +275,7 @@ __code const struct machine machine = {
|
||||
.led_mux = {0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x09, 0x0d, 0x10,
|
||||
0x11, 0x0e, 0x14, 0x11, 0x12, 0x15, 0x15, 0x16, 0x18, 0x19,
|
||||
0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21},
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
};
|
||||
|
||||
#elif defined MACHINE_SWGT024_V2_0_MANAGED
|
||||
@@ -264,13 +293,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
|
||||
// Right SFP port (J2)
|
||||
.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 = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.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},
|
||||
@@ -305,13 +334,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
|
||||
// Right SFP port (J2)
|
||||
.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 = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
|
||||
.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},
|
||||
@@ -345,7 +374,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO48_I2C_SCL1,
|
||||
.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},
|
||||
@@ -384,12 +413,12 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = 10,
|
||||
.sfp_port[0].pin_tx_disable = 0xFF,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.sfp_port[1].pin_detect = 30,
|
||||
.sfp_port[1].pin_los = 51,
|
||||
.sfp_port[1].pin_tx_disable = 0xFF,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 , .enable = LED_27 | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
@@ -424,7 +453,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -457,7 +486,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA, // no LOS pin wired
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -498,7 +527,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -530,7 +559,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.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},
|
||||
@@ -555,12 +584,12 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[0].pin_tx_disable = GPIO54_ACL_BIT2_EN,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = { .sda = GPIO47_I2C_SDA0, .scl = GPIO46_I2C_SCL0 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO47_I2C_SDA0, GPIO46_I2C_SCL0 ),
|
||||
.sfp_port[1].pin_detect = GPIO36_PWM_OUT,
|
||||
.sfp_port[1].pin_los = GPIO37,
|
||||
.sfp_port[1].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = { .sda = GPIO49_I2C_SDA1, .scl = GPIO48_I2C_SCL1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO49_I2C_SDA1, GPIO48_I2C_SCL1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
.led_sets = {
|
||||
@@ -595,13 +624,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// Right SFP port
|
||||
.sfp_port[1].pin_detect = GPIO37,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -640,7 +669,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -675,7 +704,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO48_I2C_SCL1,
|
||||
.high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
.led_mux_custom = 1,
|
||||
@@ -719,14 +748,14 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
// Right SFP port (6)
|
||||
// LED pin 24
|
||||
.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 = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.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 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
@@ -768,11 +797,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = {
|
||||
.sda = GPIO39_I2C_SDA4,
|
||||
.scl = GPIO40_I2C_SCL3_MDC1
|
||||
},
|
||||
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
|
||||
.high_leds = {
|
||||
@@ -822,14 +847,14 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.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 = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
|
||||
@@ -878,14 +903,14 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// SFP port on SDS1 / logical port 8
|
||||
.sfp_port[1].pin_detect = GPIO38,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -910,6 +935,68 @@ __code const struct machine machine = {
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_ONT_S207CW_62TS_SE
|
||||
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "ONT-S207CW-62TS-SE / Binardat 2G06-04210GSM / Binardat 2G06-04210GS",
|
||||
.isRTL8373 = 0,
|
||||
.min_port = 3,
|
||||
.max_port = 8,
|
||||
.n_sfp = 2,
|
||||
.log_to_phys_port = {0, 0, 0, 5, 4, 3, 2, 1, 6},
|
||||
.phys_to_log_port = {7, 6, 5, 4, 3, 8, 0, 0, 0},
|
||||
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
|
||||
|
||||
// SFP port on SDS0 / logical port 3
|
||||
.sfp_port[0].pin_detect = GPIO37,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// SFP port on SDS1 / logical port 8
|
||||
.sfp_port[1].pin_detect = GPIO38,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 3, 0, 0, 2, 2, 3},
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
.led_sets = {
|
||||
{ // RJ45 Ports 3-4 (normal wiring)
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{ // Unused
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{ // RJ45 Ports 1-2 (reversed wiring)
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{ // SFP Ports 5-6
|
||||
LEDS_10G | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_2G5 | LEDS_1G | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = {
|
||||
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "SWTG024AS-A-V2.0.1-5C-1SFP",
|
||||
@@ -924,7 +1011,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -967,7 +1054,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -1048,13 +1135,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// Right SFP port
|
||||
.sfp_port[1].pin_detect = GPIO37,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.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 },
|
||||
@@ -1113,7 +1200,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -1144,6 +1231,239 @@ __code const struct machine machine = {
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_LIANGUO_HYWS_SGT0108S
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "Lianguo HYWS-SGT0108S",
|
||||
.isRTL8373 = 1,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 1,
|
||||
.log_to_phys_port = {2, 1, 4, 3, 5, 6, 7, 8, 9},
|
||||
.phys_to_log_port = {1, 0, 3, 2, 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 = 0, .enable = 0 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
.led_sets = {
|
||||
{
|
||||
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // RJ45 Blue LEDs
|
||||
LEDS_2G5 | LEDS_LINK, // RJ45 White LEDs
|
||||
0,
|
||||
0
|
||||
},
|
||||
{
|
||||
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // SFP blue LED?
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
};
|
||||
#elif defined MACHINE_POE_2G080110GS
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "MokerLink POE-2G080110GS",
|
||||
.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, 1},
|
||||
.led_sets = {
|
||||
{
|
||||
/* SET0: RJ45 2.5G = amber, 1G/100M/10M = green */
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT, /* amber */
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* green */
|
||||
0,
|
||||
0
|
||||
},
|
||||
{
|
||||
/* SET1: SFP+ port = green */
|
||||
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,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08,
|
||||
0x09, 0x0c, 0x09, 0x0d, 0x10,
|
||||
0x11, 0x0e, 0x14, 0x11, 0x12,
|
||||
0x15, 0x15, 0x16, 0x18, 0x19,
|
||||
0x1a, 0x19, 0x1d, 0x1e, 0x1c,
|
||||
0x1d, 0x20, 0x21 },
|
||||
};
|
||||
#elif defined MACHINE_PB_2132
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "PB-2132",
|
||||
.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_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
|
||||
.led_sets = {
|
||||
{
|
||||
/* LED0 = RJ45: Amber LED: 2.5G */
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
/* LED1 = RJ45: Green LED: 10M / 100M / 1000M */
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{
|
||||
/* SFP+ single Green LED. */
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_HASIVO_S600W_4GT_2XGT_SE
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "Hasivo S600W-4GT-2XGT-SE",
|
||||
.isRTL8373 = 0,
|
||||
.min_port = 3,
|
||||
.max_port = 8,
|
||||
.n_sfp = 0,
|
||||
.n_10g = 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, 0, 0, 0, 0, 0, 0},
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||
/* Ports 1-4: Green: 2.5GBit, Orange: 10/100/1000MBit
|
||||
* Ports 5-6: Green: 10GBit, Orange: 5/2.5GBit, None: 10/100/1000MBit
|
||||
*/
|
||||
.led_sets = {
|
||||
{
|
||||
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Yellow
|
||||
LEDS_2G5 | LEDS_LINK, // Green
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK, // Orange
|
||||
0, // Unused
|
||||
},
|
||||
{
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Yellow
|
||||
LEDS_10G | LEDS_LINK, // Green
|
||||
LEDS_5G | LEDS_2G5 | LEDS_LINK, // Orange
|
||||
0, // Unused
|
||||
},
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = {
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x0f, 0x20,
|
||||
0x21, 0x22, 0x10, 0x11, 0x12,
|
||||
0x14, 0x15, 0x16, 0x18, 0x19,
|
||||
0x1a, 0x1c, 0x1d, 0x1e, 0x0c,
|
||||
0x0d, 0x0e, 0x23
|
||||
},
|
||||
|
||||
};
|
||||
#elif defined MACHINE_HASIVO_S1100WP_8GT_1SX_SE
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "Hasivo S1100WP-8GT-1SX-SE",
|
||||
.isRTL8373 = 1,
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
.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 = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
|
||||
0,
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
|
||||
0
|
||||
},
|
||||
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
};
|
||||
#elif defined MACHINE_F7008_2_5
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "F7008-2.5 8+1 SFP Port Switch",
|
||||
.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, 1},
|
||||
.led_sets = {
|
||||
{ /* SET0 */
|
||||
LEDS_2G5 | LEDS_LINK, /* LEDID0 - green: 2.5G link */
|
||||
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* LEDID1 - yellow: traffic */
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{ /* SET1 - SFP+ */
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_LINK,
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = {
|
||||
0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x02,
|
||||
0x0d, 0x10, 0x11, 0x02, 0x14, 0x02, 0x02, 0x15,
|
||||
0x02, 0x02, 0x18, 0x02, 0x02, 0x19, 0x02, 0x02,
|
||||
0x1c, 0x1d, 0x02, 0x02,
|
||||
},
|
||||
};
|
||||
|
||||
#else
|
||||
#error "Please select a machine type in machine.h"
|
||||
#endif
|
||||
@@ -22,6 +22,7 @@
|
||||
// #define MACHINE_KP_9000_9XH_X_EU
|
||||
// #define MACHINE_KP_9000_9XHML_X_V2_2
|
||||
// #define MACHINE_KP_9000_9XHML_X_V3_1
|
||||
// #define MACHINE_KP_9000_9XHML_X_V3_2
|
||||
// #define MACHINE_SWGT024_V2_0_MANAGED
|
||||
// #define MACHINE_SWGT024_V2_0_UNMANAGED
|
||||
// #define MACHINE_TRENDNET_TEG_S562
|
||||
@@ -40,17 +41,17 @@
|
||||
// #define MACHINE_HI_K0801WS
|
||||
// #define MACHINE_FNS1200P
|
||||
// #define MACHINE_PCB_SWTG024AS_A_2_0_1
|
||||
// #define MACHINE_ONT_S207CW_62TS_SE
|
||||
// #define MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
|
||||
// #define MACHINE_SWTG024AS_V2_0
|
||||
// #define MACHINE_FG_4GT_2SX_V2_0
|
||||
// #define MACHINE_FG_8GT_1SX
|
||||
|
||||
typedef struct {
|
||||
// GPIO pins for SDA/SCL
|
||||
uint8_t sda;
|
||||
uint8_t scl;
|
||||
} i2c_bus_t;
|
||||
|
||||
// #define MACHINE_LIANGUO_HYWS_SGT0108S
|
||||
// #define MACHINE_POE_2G080110GS
|
||||
// #define MACHINE_PB_2132
|
||||
// #define MACHINE_HASIVO_S600W_4GT_2XGT_SE
|
||||
// #define MACHINE_HASIVO_S1100WP_8GT_1SX_SE
|
||||
// #define MACHINE_F7008_2_5
|
||||
|
||||
#define LED_27 1
|
||||
// SYSTEM LED
|
||||
@@ -70,10 +71,10 @@ struct sfp_port
|
||||
uint8_t pin_los; // gpio number 0-63, 0xFF = don't have it?
|
||||
uint8_t pin_tx_disable; // gpio number 0-63, 0xFF = not present
|
||||
uint8_t sds;
|
||||
i2c_bus_t i2c;
|
||||
uint8_t i2c;
|
||||
};
|
||||
|
||||
typedef struct machine {
|
||||
struct machine {
|
||||
char machine_name[30];
|
||||
uint8_t isRTL8373;
|
||||
// Lowest logical port number
|
||||
@@ -101,7 +102,7 @@ typedef struct machine {
|
||||
uint32_t mac_flash_offset;
|
||||
};
|
||||
|
||||
typedef struct machine_runtime
|
||||
struct machine_runtime
|
||||
{
|
||||
uint8_t isRTL8373 : 1;
|
||||
uint8_t isN : 1;
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
|
||||
#if defined(MACHINE_KP_9000_6XH_X2) || \
|
||||
defined(MACHINE_KP_9000_6XH_X2_V2_1) || \
|
||||
defined(MACHINE_KP_9000_6XHML_X2_V2_1)
|
||||
defined(MACHINE_KP_9000_6XHML_X2_V2_1) || \
|
||||
defined(MACHINE_HI_K0402WS) || \
|
||||
defined(MACHINE_PCB_K0402WS_V2) || \
|
||||
defined(MACHINE_PCB_K0402WS_V3) || \
|
||||
defined(MACHINE_FNS1200P)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
@@ -42,18 +46,6 @@ void machine_custom_init(void) __banked
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
}
|
||||
|
||||
#elif defined(MACHINE_PCB_K0402WS_V2) || defined(MACHINE_FNS1200P)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
}
|
||||
|
||||
#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
@@ -63,27 +55,8 @@ void machine_custom_init(void) __banked
|
||||
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
|
||||
}
|
||||
|
||||
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
reg_bit_set(RTL837X_REG_LED_MODE, 17);
|
||||
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
|
||||
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
|
||||
|
||||
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
|
||||
sds_read(0, 0, 0);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(0, 0, 0, pval | 0x100);
|
||||
|
||||
sds_read(0, 6, 2);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(0, 6, 2, pval | 0x4000);
|
||||
}
|
||||
|
||||
#elif defined MACHINE_SWTG024AS_V2_0
|
||||
#elif defined(MACHINE_SWTG024AS_A_2_0_1_5C_1SFP) || \
|
||||
defined(MACHINE_SWTG024AS_V2_0)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
#define SYS_TICK_HZ 200
|
||||
|
||||
/* Timers of the main loop count system ticks, not loop passes: a pass is as
|
||||
* long as the packets it handles, and since #483 the loop no longer sleeps
|
||||
* while packets wait, so passes can outrun the tick as well as lag it. `last`
|
||||
* is the low byte of ticks when the timer last ran; the byte arithmetic wraps
|
||||
* every 256 ticks, so a pass longer than 1.28 s loses time rather than
|
||||
* running the timer 64 times to catch up. */
|
||||
#define TICKS_DUE(last, period) ((uint8_t)((uint8_t)ticks - (last)) >= (period))
|
||||
|
||||
#define CPU_PORT 9
|
||||
#define NUL '\0'
|
||||
|
||||
@@ -54,6 +62,7 @@ extern __xdata uint8_t sbuf[SBUF_SIZE];
|
||||
#define ERR_OK 0
|
||||
#define ERR_TOO_MANY_ARGUMENTS 1
|
||||
#define ERR_CMD_TOO_LONG 2
|
||||
#define ERR_INVALID_ARGUMENT 3
|
||||
|
||||
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
|
||||
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
|
||||
@@ -97,7 +106,7 @@ struct vlan_tag {
|
||||
#define FIRMWARE_UPLOAD_START 0x80000
|
||||
|
||||
// Constants for the circular command buffer, the size must be 2^n
|
||||
#define CMD_HISTORY_SIZE 0x400
|
||||
#define CMD_HISTORY_SIZE 0x800
|
||||
#define CMD_HISTORY_MASK (CMD_HISTORY_SIZE - 1)
|
||||
|
||||
enum sfp_speeds {
|
||||
@@ -122,6 +131,7 @@ struct flash_region_t {
|
||||
};
|
||||
|
||||
extern __xdata char port_names[9][PORT_NAME_SIZE];
|
||||
extern __xdata uint16_t lldp_logical_port_status;
|
||||
|
||||
extern __xdata bool stp_enabled;
|
||||
|
||||
@@ -134,9 +144,9 @@ extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||
|
||||
// Headers for calls in the common code area (HOME/BANK0)
|
||||
void print_string_no_syslog(__code char *p);
|
||||
void print_string_newline_no_syslog(__code char *p);
|
||||
void print_string(__code char *p);
|
||||
void print_string_no_syslog(__code const char *p);
|
||||
void print_string_newline_no_syslog(__code const char *p);
|
||||
void print_string(__code const char *p);
|
||||
void print_string_x(__xdata char *p);
|
||||
void print_long(uint32_t a);
|
||||
void print_short(uint16_t a);
|
||||
@@ -158,7 +168,6 @@ void reg_write_m(uint16_t reg_addr);
|
||||
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
|
||||
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
|
||||
void delay(uint16_t t);
|
||||
void sleep(uint16_t t);
|
||||
void write_char_no_syslog(char c);
|
||||
void write_char(char c);
|
||||
void print_reg(uint16_t reg);
|
||||
@@ -170,26 +179,31 @@ uint8_t reg_bit_test(uint16_t reg_addr, char bit);
|
||||
void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set);
|
||||
void sfr_set_zero(void);
|
||||
void reset_chip(void);
|
||||
/* Firmware implementations that shadow libc names. Host unit-test builds
|
||||
* (RTLP_HOST_TEST) hide these prototypes so they don't clash with glibc;
|
||||
* argument order matches libc, so on-host callers transparently use the
|
||||
* C library. See test/. */
|
||||
#ifndef RTLP_HOST_TEST
|
||||
void sleep(uint16_t t);
|
||||
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
|
||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len);
|
||||
void memset(__xdata uint8_t *dst, __xdata uint8_t v, uint8_t len);
|
||||
int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len);
|
||||
uint16_t strlen(__code const char *s);
|
||||
uint16_t strlen_x(__xdata const char *s);
|
||||
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
|
||||
uint16_t strcpy(__xdata uint8_t *dst, const char *s);
|
||||
char strcmp(__xdata const uint8_t *a, __code const uint8_t *b);
|
||||
#endif
|
||||
void memcpyc(__xdata uint8_t *dst, __code const uint8_t *src, uint16_t len);
|
||||
uint16_t strlen_x(__xdata const char *s);
|
||||
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
|
||||
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b);
|
||||
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b);
|
||||
void tcpip_output(void);
|
||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
||||
uint8_t read_flash(uint8_t bank, __code const uint8_t *addr);
|
||||
void get_random_32(void);
|
||||
void read_reg_timer(__xdata uint32_t * tmr);
|
||||
bool sfp_print_info(uint8_t sfp);
|
||||
bool gpio_pin_test(uint8_t pin);
|
||||
void set_sys_led_state(uint8_t state);
|
||||
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
|
||||
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
|
||||
void sds_config_mac(uint8_t sds, uint8_t mode);
|
||||
void sds_config(uint8_t sds, uint8_t mode);
|
||||
void handle_sfp(void);
|
||||
void flash_default_config(void);
|
||||
#endif
|
||||
@@ -28,11 +28,16 @@ __xdata uint8_t flash_capacity_code;
|
||||
#define CMD_READ_JEDEC_ID 0x9f
|
||||
#define CMD_FREAD_DIO 0xbb
|
||||
|
||||
#define STATUS_REG_BUSY_MASK 0x01
|
||||
#define STATUS_REG_WEL_MASK 0x02
|
||||
|
||||
/*
|
||||
* Configure Memory Managed IO
|
||||
*/
|
||||
void flash_configure_mmio(void)
|
||||
static void flash_configure_mmio(void)
|
||||
{
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// Set configuration for MMIO access by controller
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
@@ -46,6 +51,54 @@ void flash_configure_mmio(void)
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
}
|
||||
|
||||
static void flash_configure_sio(void)
|
||||
{
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// Set configuration for SIO access by controller
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_DUMMYCYCLES = 0;
|
||||
}
|
||||
|
||||
static uint8_t flash_read_status(void)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t old_cmd_r;
|
||||
uint8_t old_tconf;
|
||||
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// SAVE SPI peripheral state at entry
|
||||
old_cmd_r = SFR_FLASH_CMD_R;
|
||||
old_tconf = SFR_FLASH_TCONF;
|
||||
|
||||
SFR_FLASH_TCONF = 0x11;
|
||||
SFR_FLASH_CMD_R = CMD_READ_STATUS;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
status = SFR_FLASH_DATA0;
|
||||
|
||||
// RESTORE SPI peripheral state
|
||||
SFR_FLASH_CMD_R = old_cmd_r;
|
||||
SFR_FLASH_TCONF = old_tconf;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void flash_write_enable(void)
|
||||
{
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
SFR_FLASH_TCONF = 0x18;
|
||||
SFR_FLASH_CMD = CMD_WRITE_ENABLE;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while (SFR_FLASH_EXEC_BUSY);
|
||||
while (!(flash_read_status() & STATUS_REG_WEL_MASK));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initializes the flash controller for programmed control
|
||||
@@ -82,30 +135,12 @@ void flash_init(uint8_t enable_dio)
|
||||
flash_configure_mmio();
|
||||
}
|
||||
|
||||
|
||||
uint8_t flash_read_status(void)
|
||||
{
|
||||
// Test Controller Busy (we might call this directly after executing a command)
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// setup status read command
|
||||
SFR_FLASH_TCONF = 0x11;
|
||||
SFR_FLASH_CMD_R = CMD_READ_STATUS;
|
||||
|
||||
// execute and wait for controller done
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
return SFR_FLASH_DATA0;
|
||||
}
|
||||
|
||||
|
||||
void flash_read_uid(void)
|
||||
{
|
||||
while (flash_read_status() & 0x1);
|
||||
flash_configure_sio();
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
|
||||
// Set slow read mode for UID
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_READ_UNIQUE_ID;
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
|
||||
@@ -136,7 +171,7 @@ void flash_read_uid(void)
|
||||
flash_configure_mmio();
|
||||
}
|
||||
|
||||
__code char* get_flash_size_str(void)
|
||||
__code const char* get_flash_size_str(void)
|
||||
{
|
||||
switch (flash_capacity_code) {
|
||||
case 0x12: return "256 KB";
|
||||
@@ -152,12 +187,12 @@ __code char* get_flash_size_str(void)
|
||||
|
||||
void flash_read_jedecid(void)
|
||||
{
|
||||
while (flash_read_status() & 0x1);
|
||||
flash_configure_sio();
|
||||
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
|
||||
// Set read mode for JEDEC ID
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_READ_JEDEC_ID;
|
||||
SFR_FLASH_DUMMYCYCLES = 0;
|
||||
|
||||
// Transfer 3 bytes back
|
||||
SFR_FLASH_TCONF = 0x13;
|
||||
@@ -180,53 +215,18 @@ void flash_read_jedecid(void)
|
||||
}
|
||||
|
||||
|
||||
void flash_write_enable(void)
|
||||
{
|
||||
short status;
|
||||
|
||||
// Wait until busy bit clear
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (status & 0x1);
|
||||
|
||||
SFR_FLASH_TCONF = 0x18;
|
||||
SFR_FLASH_CMD = CMD_WRITE_ENABLE;
|
||||
|
||||
/* The following makes sure that the PAGE_PROGRAM command,
|
||||
* where the data to be written follows the command word directly
|
||||
* works properly
|
||||
*/
|
||||
SFR_FLASH_DUMMYCYCLES = 0;
|
||||
SFR_FLASH_MODEB = 0;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
// Wait for write status enabled
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (!(status & 0x2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads bulk data of length len from the flash memory starging at address src
|
||||
* and writes the data into a buffer pointed to by dst in XMEM
|
||||
*/
|
||||
void flash_read_bulk(__xdata uint8_t *dst)
|
||||
{
|
||||
short status;
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (status & 0x1);
|
||||
if (!flash_region.len)
|
||||
return;
|
||||
|
||||
// Set fast read mode
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD_DIO;
|
||||
SFR_FLASH_DUMMYCYCLES = 4;
|
||||
} else {
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD; // Fast read
|
||||
SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks
|
||||
}
|
||||
flash_configure_sio();
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
flash_configure_mmio();
|
||||
|
||||
|
||||
// Read 4 bytes
|
||||
@@ -260,12 +260,15 @@ void flash_read_bulk(__xdata uint8_t *dst)
|
||||
|
||||
void flash_read_security(void)
|
||||
{
|
||||
while (flash_read_status() & 0x1);
|
||||
if (!flash_region.len)
|
||||
return;
|
||||
|
||||
flash_configure_sio();
|
||||
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
|
||||
// Set slow read mode
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_READ_SECURITY_REGS; // read security register
|
||||
SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks as for fast read
|
||||
|
||||
// Transfer 4 bytes (command + 3byte address)
|
||||
SFR_FLASH_TCONF = 4;
|
||||
@@ -298,6 +301,7 @@ void flash_read_security(void)
|
||||
|
||||
void flash_sector_erase(void)
|
||||
{
|
||||
flash_configure_sio();
|
||||
flash_write_enable();
|
||||
SFR_FLASH_TCONF = 8;
|
||||
SFR_FLASH_CMD = CMD_SECTOR_ERASE;
|
||||
@@ -307,7 +311,7 @@ void flash_sector_erase(void)
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while (flash_read_status() & 0x1);
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
|
||||
flash_configure_mmio();
|
||||
}
|
||||
@@ -315,33 +319,39 @@ void flash_sector_erase(void)
|
||||
|
||||
void flash_write_bytes(__xdata uint8_t *ptr)
|
||||
{
|
||||
// write_char('\n'); write_char('>'); print_long(flash_region.addr); write_char(':'); print_short(flash_region.len); write_char('-'); print_byte(*ptr); // write_char('\n');
|
||||
while(1) {
|
||||
flash_write_enable();
|
||||
SFR_FLASH_CMD = CMD_PAGE_PROGRAM;
|
||||
SFR_FLASH_TCONF = 0x40 | 8 | 4; // Bytes written is 4, 8 enables write, 0x40 is unknown
|
||||
flash_configure_sio();
|
||||
|
||||
while(1) {
|
||||
flash_write_enable();
|
||||
SFR_FLASH_CMD = CMD_PAGE_PROGRAM;
|
||||
|
||||
// Last transfer?
|
||||
if (flash_region.len < 5) {
|
||||
SFR_FLASH_TCONF = 8 | flash_region.len;
|
||||
}
|
||||
if (flash_region.len < 5) {
|
||||
SFR_FLASH_TCONF = 8 | flash_region.len;
|
||||
} else {
|
||||
SFR_FLASH_TCONF = 0x40 | 8 | 4; // Bytes written is 4, 8 enables write, 0x40 is unknown
|
||||
}
|
||||
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
SFR_FLASH_DATA0 = *ptr++;
|
||||
SFR_FLASH_DATA8 = *ptr++;
|
||||
SFR_FLASH_DATA16 = *ptr++;
|
||||
SFR_FLASH_DATA24 = *ptr++;
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
|
||||
// Safely load only the valid bytes remaining in the buffer
|
||||
SFR_FLASH_DATA0 = *ptr++;
|
||||
if (flash_region.len > 1) SFR_FLASH_DATA8 = *ptr++;
|
||||
if (flash_region.len > 2) SFR_FLASH_DATA16 = *ptr++;
|
||||
if (flash_region.len > 3) SFR_FLASH_DATA24 = *ptr++;
|
||||
|
||||
// Execute transfer, we wait for completion at top of loop
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
// Execute transfer, wait for completion at top of loop
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
|
||||
if (flash_region.len < 5)
|
||||
break;
|
||||
if (flash_region.len < 5)
|
||||
break;
|
||||
|
||||
flash_region.len -= 4;
|
||||
flash_region.addr += 4;
|
||||
};
|
||||
while (flash_read_status() & 0x1);
|
||||
flash_configure_mmio();
|
||||
flash_region.len -= 4;
|
||||
flash_region.addr += 4;
|
||||
};
|
||||
|
||||
while (flash_read_status() & STATUS_REG_BUSY_MASK);
|
||||
flash_configure_mmio();
|
||||
}
|
||||
@@ -13,14 +13,13 @@
|
||||
|
||||
void flash_init(uint8_t enable_dio);
|
||||
void flash_read_uid(void);
|
||||
void flash_write_enable(void);
|
||||
void flash_dump(uint8_t len);
|
||||
void flash_read_jedecid(void);
|
||||
void flash_read_security(void);
|
||||
void flash_sector_erase(void);
|
||||
void flash_read_bulk(__xdata uint8_t *dst);
|
||||
void flash_write_bytes(__xdata uint8_t *ptr);
|
||||
__code char* get_flash_size_str(void);
|
||||
__code const char* get_flash_size_str(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,16 +9,18 @@
|
||||
#define IPMC_USES_L3MC
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t igmpEnabled;
|
||||
|
||||
#include "uip.h"
|
||||
#include "uip_arp.h"
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
@@ -29,6 +31,13 @@ extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
|
||||
|
||||
__xdata uint16_t idx;
|
||||
#define IGMP_IP_HDR offsetof(struct igmp_pkt, hlen)
|
||||
#define IGMP_IP_IHL 0x0f
|
||||
#define IGMP_GROUP_OFS 4
|
||||
#define IGMP_V3_RECORD_OFS 8
|
||||
|
||||
static __xdata uint8_t igmp_grp;
|
||||
static __xdata uint8_t igmp_join;
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
struct ipmc_table_entry {
|
||||
@@ -198,8 +207,10 @@ void entry_to_l2mc(void)
|
||||
#endif
|
||||
|
||||
|
||||
void igmp_packet_handler(void) __banked
|
||||
uint8_t igmp_packet_handler(void) __banked
|
||||
{
|
||||
if (IGMP_I->ipv4_tag != HTONS(UIP_ETHTYPE_IP) || IGMP_I->protocol != IGMP_PROTO)
|
||||
return 0;
|
||||
// By default we do not send anything out
|
||||
uip_len = 0;
|
||||
|
||||
@@ -211,24 +222,40 @@ void igmp_packet_handler(void) __banked
|
||||
}
|
||||
write_char('\n');
|
||||
#endif
|
||||
if (IGMP_I->protocol != 2)
|
||||
return;
|
||||
igmp_grp = IGMP_IP_HDR + ((IGMP_I->hlen & IGMP_IP_IHL) << 2);
|
||||
#ifdef DEBUG
|
||||
print_string("Found IGMP, type: "); print_byte(IGMP_I->igmp_type); write_char('\n');
|
||||
print_string("Found IGMP, type: "); print_byte(uip_buf[igmp_grp]); write_char('\n');
|
||||
#endif
|
||||
// We react to IGMPv1/v2 and v3 membership reports
|
||||
if (!(IGMP_I->igmp_type == 0x12 || IGMP_I->igmp_type == 0x16 || IGMP_I->igmp_type == 0x22))
|
||||
return;
|
||||
switch (uip_buf[igmp_grp]) {
|
||||
case IGMP_V1_REPORT:
|
||||
case IGMP_V2_REPORT:
|
||||
igmp_join = 1;
|
||||
break;
|
||||
case IGMP_V2_LEAVE:
|
||||
igmp_join = 0;
|
||||
break;
|
||||
case IGMP_V3_REPORT:
|
||||
igmp_grp += IGMP_V3_RECORD_OFS;
|
||||
if (uip_buf[igmp_grp] == IGMP_V3_TO_EXCLUDE)
|
||||
igmp_join = 1;
|
||||
else if (uip_buf[igmp_grp] == IGMP_V3_TO_INCLUDE)
|
||||
igmp_join = 0;
|
||||
else
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
igmp_grp += IGMP_GROUP_OFS;
|
||||
#ifdef DEBUG
|
||||
print_string("IGMP membership report, type "); print_byte(IGMP_I->igmp_rtype); write_char('\n');
|
||||
print_string("IGMP join "); print_byte(igmp_join); write_char('\n');
|
||||
#endif
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
memset((__xdata uint8_t *)&entry, 0, sizeof(struct ipmc_table_entry));
|
||||
// For IPv4 MC, the Source-IP is 0.0.0.0
|
||||
entry.sip[0] = 0x00; entry.sip[1] = 0x00; entry.sip[2] = 0x00; entry.sip[3] = 0x00;
|
||||
// For IPv4 MC, the Destination-IP is the IPv4 MC address
|
||||
entry.dip[0] = IGMP_I->mc_ip[0]; entry.dip[1] = IGMP_I->mc_ip[1]; entry.dip[2] = IGMP_I->mc_ip[2]; entry.dip[3] = IGMP_I->mc_ip[3];
|
||||
memcpy(entry.dip, &uip_buf[igmp_grp], sizeof(entry.dip));
|
||||
entry_to_l3mc();
|
||||
#else
|
||||
/* The L2 Multicast MAC for IP-Multicast is 01:00:5e:xx:yy:zz, where
|
||||
@@ -238,7 +265,7 @@ void igmp_packet_handler(void) __banked
|
||||
*/
|
||||
memset((__xdata uint8_t *)&entry, 0, sizeof(struct l2mc_table_entry));
|
||||
entry.mac[0] = 0x01; entry.mac[1] = 0x00; entry.mac[2] = 0x5e;
|
||||
entry.mac[3] = IGMP_I->mc_ip[1] & 0x7f; entry.mac[4] = IGMP_I->mc_ip[2]; entry.mac[5] = IGMP_I->mc_ip[3];
|
||||
entry.mac[3] = uip_buf[igmp_grp + 1] & 0x7f; entry.mac[4] = uip_buf[igmp_grp + 2]; entry.mac[5] = uip_buf[igmp_grp + 3];
|
||||
entry.vlan = 1; //TODO: Get this out of the packet and compare with VLAN table!
|
||||
entry_to_ipmc();
|
||||
#endif
|
||||
@@ -286,7 +313,7 @@ void igmp_packet_handler(void) __banked
|
||||
print_sfr_data();
|
||||
#endif
|
||||
idx = ((sfr_data[2] & 0xf) << 8) | sfr_data[3];
|
||||
if (IGMP_I->igmp_rtype == 0x4) {// Join group
|
||||
if (igmp_join) {// Join group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
print_string("\nIGMP-Entry FOUND\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
@@ -295,9 +322,9 @@ void igmp_packet_handler(void) __banked
|
||||
entry.pmask |= ((uint16_t)sfr_data[3]) << 2;
|
||||
}
|
||||
// Update (found) entry with portmask from trapped Packet
|
||||
entry.pmask |= (1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
|
||||
entry.pmask |= ((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else if (IGMP_I->igmp_rtype == 0x3){ // Leave group
|
||||
} else { // Leave group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
print_string("\nIGMP_Entry FOUND\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
@@ -312,11 +339,11 @@ void igmp_packet_handler(void) __banked
|
||||
write_char('\n');
|
||||
#endif
|
||||
// Remove portmask of IGMP packet from entry
|
||||
entry.pmask &= ~(1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
|
||||
entry.pmask &= ~(((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f)); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else {
|
||||
print_string("IGMP Entry already deleted\n");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
if (!entry.pmask && idx) { // No more ports in that group and an actual entry?
|
||||
// Delete Entry
|
||||
@@ -328,14 +355,12 @@ void igmp_packet_handler(void) __banked
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
print_string("IGMP Entry deleted\n");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
} else { // Unknown message: ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entry.pmask)
|
||||
return;
|
||||
return 1;
|
||||
print_string("Updating IGMP entry\n");
|
||||
// Write the updated entry
|
||||
#ifdef IPMC_USES_L3MC
|
||||
@@ -372,4 +397,5 @@ void igmp_packet_handler(void) __banked
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
print_sfr_data();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
@@ -3,10 +3,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define IGMP_PROTO 2
|
||||
#define IGMP_V1_REPORT 0x12
|
||||
#define IGMP_V2_REPORT 0x16
|
||||
#define IGMP_V2_LEAVE 0x17
|
||||
#define IGMP_V3_REPORT 0x22
|
||||
#define IGMP_V3_TO_INCLUDE 3
|
||||
#define IGMP_V3_TO_EXCLUDE 4
|
||||
|
||||
void igmp_setup(void) __banked;
|
||||
void igmp_enable(void) __banked;
|
||||
void igmp_router_port_set(uint16_t pmask) __banked;
|
||||
void igmp_packet_handler(void) __banked;
|
||||
uint8_t igmp_packet_handler(void) __banked;
|
||||
void igmp_show(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -6,9 +6,10 @@
|
||||
#include "rtl837x_phy.h"
|
||||
#include "phy.h"
|
||||
#include "machine.h"
|
||||
#include "boot.h"
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
|
||||
#pragma codeseg BANK2
|
||||
@@ -91,8 +92,18 @@ void static sds_init(void)
|
||||
}
|
||||
|
||||
|
||||
void static tm_init(void)
|
||||
{
|
||||
reg_read_m(RTL837X_TM_CTRL2);
|
||||
sfr_mask_data(0, TM_CTRL2_EN_LATCH, 0);
|
||||
reg_write_m(RTL837X_TM_CTRL2);
|
||||
}
|
||||
|
||||
|
||||
void rtl8373_init(void) __banked
|
||||
{
|
||||
tm_init();
|
||||
|
||||
print_string("\nrtl8373_init called\n");
|
||||
|
||||
// r65d8:3ffbedff R65d8-3ffbedff
|
||||
@@ -190,6 +201,8 @@ void rtl8373_init(void) __banked
|
||||
|
||||
void rtl8372_init(void) __banked
|
||||
{
|
||||
tm_init();
|
||||
|
||||
print_string("\nrtl8372_init called\n");
|
||||
|
||||
sds_init();
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "rtl837x_leds.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
@@ -24,149 +24,6 @@ extern __code struct machine machine;
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
void leds_dump(void) __banked
|
||||
{
|
||||
print_string("RTL837X_PIN_MUX_0: "); print_reg(RTL837X_PIN_MUX_0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_IO_EN: "); print_reg(RTL837X_REG_LED_GLB_IO_EN); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET0: "); print_reg(RTL837X_REG_LED1_0_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET0: "); print_reg(RTL837X_REG_LED3_2_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET1: "); print_reg(RTL837X_REG_LED1_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET1: "); print_reg(RTL837X_REG_LED3_2_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET3: "); print_reg(RTL837X_REG_LED3_2_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_1: "); print_reg(RTL837X_REG_LED_GLB_MUX_1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_2: "); print_reg(RTL837X_REG_LED_GLB_MUX_2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_3: "); print_reg(RTL837X_REG_LED_GLB_MUX_3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_4: "); print_reg(RTL837X_REG_LED_GLB_MUX_4); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_5: "); print_reg(RTL837X_REG_LED_GLB_MUX_5); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_6: "); print_reg(RTL837X_REG_LED_GLB_MUX_6); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_ACTIVE: "); print_reg(RTL837X_REG_LED_GLB_ACTIVE); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_MODE: "); print_reg(RTL837X_REG_LED_MODE); write_char('\n');
|
||||
print_string("LED pad Configuration:\n");
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
print_byte(i);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
switch (i % 5) {
|
||||
case 0: // 0
|
||||
reg_read_m(RTL837X_REG_LED_GLB_MUX_1 + (i / 5) * 4);
|
||||
print_byte(sfr_data[3] & 0x3f);
|
||||
break;
|
||||
case 1: // 6
|
||||
print_byte(((sfr_data[3] >> 6) | (sfr_data[2] << 2)) & 0x3f);
|
||||
break;
|
||||
case 2: // 12
|
||||
print_byte(((sfr_data[1] << 4) | (sfr_data[2] >> 4)) & 0x3f);
|
||||
break;
|
||||
case 3: // 18
|
||||
print_byte((sfr_data[1] >> 2) & 0x3f);
|
||||
break;
|
||||
case 4: // 24
|
||||
print_byte(sfr_data[0] & 0x3f);
|
||||
break;
|
||||
}
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
print_string("LED-set Configuration:\n");
|
||||
print_string("LED-ID\t\t0\t\t1\t\t2\t\t3\n");
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
print_string("SET "); write_char('0' + set); write_char(':');
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
print_string("\t ");
|
||||
uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
}
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (! (ledid & 1)) { // LEDID 0, 2
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
} else {
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
reg_read_m(RTL837X_LED_PORT_SET_SEL);
|
||||
__xdata uint8_t set = sfr_data[3 - (i >> 2)];
|
||||
set = (set >> ((i & 3) << 1));
|
||||
print_string("Port "); write_char('0' + i); print_string(": SET ");
|
||||
write_char('0' + set);
|
||||
print_string(": ");
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
write_char('(');
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (ledid & 1) { // LEDID 1, 3
|
||||
sfr_data[2] = sfr_data[0];
|
||||
sfr_data[3] = sfr_data[1];
|
||||
}
|
||||
if (sfr_data[3] & 0x01)
|
||||
print_string(" 2G5");
|
||||
if (sfr_data[3] & 0x02)
|
||||
print_string(" TWO_1G");
|
||||
if (sfr_data[3] & 0x04)
|
||||
print_string(" 1G");
|
||||
if (sfr_data[3] & 0x08)
|
||||
print_string(" 500M");
|
||||
if (sfr_data[3] & 0x10)
|
||||
print_string(" 100M");
|
||||
if (sfr_data[3] & 0x20)
|
||||
print_string(" 10M");
|
||||
if (sfr_data[3] & 0x40)
|
||||
print_string(" LINK");
|
||||
if (sfr_data[3] & 0x80)
|
||||
print_string(" LINK_FLASH");
|
||||
if (sfr_data[2] & 0x01)
|
||||
print_string(" ACT");
|
||||
if (sfr_data[2] & 0x02)
|
||||
print_string(" RX");
|
||||
if (sfr_data[2] & 0x04)
|
||||
print_string(" TX");
|
||||
if (sfr_data[2] & 0x08)
|
||||
print_string(" COL");
|
||||
if (sfr_data[2] & 0x10)
|
||||
print_string(" DUPLEX");
|
||||
if (sfr_data[2] & 0x20)
|
||||
print_string(" TRAINING");
|
||||
if (sfr_data[2] & 0x40)
|
||||
print_string(" MASTER");
|
||||
__xdata uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
}
|
||||
b = ledid & 1 ? b >> 4 : b & 0xf;
|
||||
if (b & 0x1)
|
||||
print_string(" 10G");
|
||||
if (b & 0x2)
|
||||
print_string(" TWO_5G");
|
||||
if (b & 0x4)
|
||||
print_string(" 5G");
|
||||
if (b & 0x8)
|
||||
print_string(" TWO_2G5");
|
||||
print_string("), ");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void leds_setup(void) __banked
|
||||
{
|
||||
@@ -261,7 +118,7 @@ void leds_setup(void) __banked
|
||||
sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0;
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
__code uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
||||
__code const uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
sfr_data[0] = *(lptr + 5);
|
||||
sfr_data[1] = *(lptr + 4);
|
||||
@@ -275,7 +132,7 @@ void leds_setup(void) __banked
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
sfr_data[3 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
sfr_data[3 - ((set - 2) << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
}
|
||||
lptr += 8;
|
||||
@@ -291,7 +148,7 @@ void leds_setup(void) __banked
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
sfr_data[2 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
sfr_data[2 - ((set - 2) << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
}
|
||||
lptr += 8;
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_leds.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
void leds_dump(void) __banked
|
||||
{
|
||||
print_string("RTL837X_PIN_MUX_0: "); print_reg(RTL837X_PIN_MUX_0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_IO_EN: "); print_reg(RTL837X_REG_LED_GLB_IO_EN); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET0: "); print_reg(RTL837X_REG_LED1_0_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET0: "); print_reg(RTL837X_REG_LED3_2_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET1: "); print_reg(RTL837X_REG_LED1_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET1: "); print_reg(RTL837X_REG_LED3_2_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET3: "); print_reg(RTL837X_REG_LED3_2_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_1: "); print_reg(RTL837X_REG_LED_GLB_MUX_1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_2: "); print_reg(RTL837X_REG_LED_GLB_MUX_2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_3: "); print_reg(RTL837X_REG_LED_GLB_MUX_3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_4: "); print_reg(RTL837X_REG_LED_GLB_MUX_4); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_5: "); print_reg(RTL837X_REG_LED_GLB_MUX_5); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_6: "); print_reg(RTL837X_REG_LED_GLB_MUX_6); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_ACTIVE: "); print_reg(RTL837X_REG_LED_GLB_ACTIVE); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_MODE: "); print_reg(RTL837X_REG_LED_MODE); write_char('\n');
|
||||
print_string("LED pad Configuration:\n");
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
print_byte(i);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
switch (i % 5) {
|
||||
case 0: // 0
|
||||
reg_read_m(RTL837X_REG_LED_GLB_MUX_1 + (i / 5) * 4);
|
||||
print_byte(sfr_data[3] & 0x3f);
|
||||
break;
|
||||
case 1: // 6
|
||||
print_byte(((sfr_data[3] >> 6) | (sfr_data[2] << 2)) & 0x3f);
|
||||
break;
|
||||
case 2: // 12
|
||||
print_byte(((sfr_data[1] << 4) | (sfr_data[2] >> 4)) & 0x3f);
|
||||
break;
|
||||
case 3: // 18
|
||||
print_byte((sfr_data[1] >> 2) & 0x3f);
|
||||
break;
|
||||
case 4: // 24
|
||||
print_byte(sfr_data[0] & 0x3f);
|
||||
break;
|
||||
}
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
print_string("LED-set Configuration:\n");
|
||||
print_string("LED-ID\t\t0\t\t1\t\t2\t\t3\n");
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
print_string("SET "); write_char('0' + set); write_char(':');
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
print_string("\t ");
|
||||
uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
}
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (! (ledid & 1)) { // LEDID 0, 2
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
} else {
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
reg_read_m(RTL837X_LED_PORT_SET_SEL);
|
||||
__xdata uint8_t set = sfr_data[3 - (i >> 2)];
|
||||
set = (set >> ((i & 3) << 1));
|
||||
print_string("Port "); write_char('0' + i); print_string(": SET ");
|
||||
write_char('0' + set);
|
||||
print_string(": ");
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
write_char('(');
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (ledid & 1) { // LEDID 1, 3
|
||||
sfr_data[2] = sfr_data[0];
|
||||
sfr_data[3] = sfr_data[1];
|
||||
}
|
||||
if (sfr_data[3] & 0x01)
|
||||
print_string(" 2G5");
|
||||
if (sfr_data[3] & 0x02)
|
||||
print_string(" TWO_1G");
|
||||
if (sfr_data[3] & 0x04)
|
||||
print_string(" 1G");
|
||||
if (sfr_data[3] & 0x08)
|
||||
print_string(" 500M");
|
||||
if (sfr_data[3] & 0x10)
|
||||
print_string(" 100M");
|
||||
if (sfr_data[3] & 0x20)
|
||||
print_string(" 10M");
|
||||
if (sfr_data[3] & 0x40)
|
||||
print_string(" LINK");
|
||||
if (sfr_data[3] & 0x80)
|
||||
print_string(" LINK_FLASH");
|
||||
if (sfr_data[2] & 0x01)
|
||||
print_string(" ACT");
|
||||
if (sfr_data[2] & 0x02)
|
||||
print_string(" RX");
|
||||
if (sfr_data[2] & 0x04)
|
||||
print_string(" TX");
|
||||
if (sfr_data[2] & 0x08)
|
||||
print_string(" COL");
|
||||
if (sfr_data[2] & 0x10)
|
||||
print_string(" DUPLEX");
|
||||
if (sfr_data[2] & 0x20)
|
||||
print_string(" TRAINING");
|
||||
if (sfr_data[2] & 0x40)
|
||||
print_string(" MASTER");
|
||||
__xdata uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
}
|
||||
b = ledid & 1 ? b >> 4 : b & 0xf;
|
||||
if (b & 0x1)
|
||||
print_string(" 10G");
|
||||
if (b & 0x2)
|
||||
print_string(" TWO_5G");
|
||||
if (b & 0x4)
|
||||
print_string(" 5G");
|
||||
if (b & 0x8)
|
||||
print_string(" TWO_2G5");
|
||||
print_string("), ");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_lldp.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "dhcp.h"
|
||||
#include "uip.h"
|
||||
#include "uip/uip.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __xdata bool lldp_enabled;
|
||||
extern __code const struct machine machine;
|
||||
|
||||
__xdata uint16_t lldp_ticks;
|
||||
__xdata uint16_t lldp_logical_port_status = 0xffff;
|
||||
|
||||
void lldp_init(void) __banked
|
||||
{
|
||||
lldp_ticks = 0;
|
||||
}
|
||||
|
||||
void lldp_tick(void) __banked
|
||||
{
|
||||
lldp_ticks++;
|
||||
|
||||
if (lldp_ticks < LLDP_TX_INTERVAL_TICKS)
|
||||
return;
|
||||
|
||||
lldp_ticks = 0;
|
||||
|
||||
if(lldp_enabled == 1)
|
||||
lldp_send();
|
||||
}
|
||||
|
||||
//Outgoing LLDP packet.
|
||||
|
||||
struct lldp_pkt {
|
||||
struct uip_eth_addr dst;
|
||||
struct uip_eth_addr src;
|
||||
struct rtl_tag rtl_tag;
|
||||
uint16_t ether_type;
|
||||
|
||||
uint8_t payload[64];
|
||||
};
|
||||
|
||||
#define LLDP_O ((__xdata struct lldp_pkt *)&uip_buf[RTL_FRAME_DESC_SIZE])
|
||||
|
||||
// The type is 7 bits and the length is 9 bits
|
||||
// we can represent this as the 7 most significant
|
||||
// bits of the type bit and leave the least significant
|
||||
// bit as 0 always as we're not going to need 2^9 for
|
||||
// the length at any point
|
||||
#define LLDP_TYPE(value) (value << 1)
|
||||
|
||||
void lldp_send(void) __banked __reentrant
|
||||
{
|
||||
__xdata uint8_t *p;
|
||||
uint8_t port_position;
|
||||
|
||||
lldp_set_addresses();
|
||||
lldp_set_rtl_wrapper();
|
||||
|
||||
p = LLDP_O->payload;
|
||||
|
||||
//Chassis ID
|
||||
*p++ = LLDP_TYPE(LLDP_CHASSIS_ID_TLV_TYPE);
|
||||
*p++ = LLDP_CHASSIS_ID_TLV_LENGTH;
|
||||
*p++ = LLDP_CHASSIS_ID_TLV_SUBTYPE;
|
||||
|
||||
memcpy(p, uip_ethaddr.addr, MAC_ADDR_LEN);
|
||||
p += MAC_ADDR_LEN;
|
||||
|
||||
//Port ID
|
||||
*p++ = LLDP_TYPE(LLDP_PORT_ID_TLV_TYPE);
|
||||
*p++ = LLDP_PORT_ID_TLV_LENGTH;
|
||||
*p++ = LLDP_PORT_ID_TLV_SUBTYPE;
|
||||
port_position = (p-LLDP_O->payload);
|
||||
*p++ = '0'; // filled in per port below
|
||||
|
||||
//TTL
|
||||
*p++ = LLDP_TYPE(LLDP_TTL_TLV_TYPE);
|
||||
*p++ = LLDP_TTL_TLV_LENGTH;
|
||||
*p++ = 0x00; //padding
|
||||
*p++ = LLDP_TTL_TTL_SECONDS;
|
||||
|
||||
p += lldp_sysname(p);
|
||||
p += lldp_sysdesc(p);
|
||||
|
||||
// End of LLDPDU TLV
|
||||
*p++ = 0x00; //padding
|
||||
*p++ = 0x00; //padding
|
||||
|
||||
while (p < (LLDP_O->payload + LLDP_MIN_ETHERNET_PAYLOAD_LENGTH))
|
||||
*p++ = 0x00;
|
||||
|
||||
/*
|
||||
* uip_len is the Ethernet frame length excluding FCS.
|
||||
*
|
||||
* The frame consists of:
|
||||
*
|
||||
* dst mac
|
||||
* src mac
|
||||
* rtl_tag sizeof(struct rtl_tag)
|
||||
* EtherType (2 bytes)
|
||||
* payload (how far we've moved p pointer)
|
||||
*/
|
||||
uip_len = MAC_ADDR_LEN + MAC_ADDR_LEN + sizeof(struct rtl_tag) + LLDP_ETHERTYPE_LENGTH + (p - LLDP_O->payload);
|
||||
|
||||
for (uint8_t port = machine.min_port; port <= machine.max_port; port++) {
|
||||
|
||||
if ((1 << port) & lldp_logical_port_status) {
|
||||
LLDP_O->payload[port_position] = '0' + machine.log_to_phys_port[port];
|
||||
LLDP_O->rtl_tag.pmask = HTONS((uint16_t)1 << port);
|
||||
|
||||
tcpip_output();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lldp_set_addresses(void) __banked {
|
||||
// LLDP destination multicast addr: 01:80:c2:00:00:0e
|
||||
memcpyc(LLDP_O->dst.addr, "\x01\x80\xc2\x00\x00\x0e", MAC_ADDR_LEN);
|
||||
memcpy(LLDP_O->src.addr, uip_ethaddr.addr, MAC_ADDR_LEN);
|
||||
}
|
||||
|
||||
void lldp_set_rtl_wrapper(void) __banked {
|
||||
/*
|
||||
* This is the RTL CPU tag, not the Ethernet EtherType.
|
||||
* port 0 -> 0x0001
|
||||
* port 1 -> 0x0002
|
||||
* port 2 -> 0x0004
|
||||
*/
|
||||
LLDP_O->rtl_tag.tag = HTONS(RTL_FRAME_TAG_ID);
|
||||
LLDP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
|
||||
LLDP_O->rtl_tag.reason = 0x00;
|
||||
LLDP_O->rtl_tag.flags = HTONS(RTL_TAG_LEARN_DIS);
|
||||
|
||||
LLDP_O->ether_type = HTONS(LLDP_ETHERTYPE);
|
||||
}
|
||||
|
||||
uint8_t lldp_sysname(__xdata uint8_t *p) __banked
|
||||
{
|
||||
uint8_t hostname_length = strlen_x(hostname);
|
||||
|
||||
*p++ = LLDP_TYPE(LLDP_SYSNAME_TLV_TYPE);
|
||||
*p++ = hostname_length;
|
||||
memcpy(p, hostname, hostname_length);
|
||||
return hostname_length + 2;
|
||||
}
|
||||
|
||||
uint8_t lldp_sysdesc(__xdata uint8_t *p) __banked
|
||||
{
|
||||
uint16_t machine_name_length = strlen(machine.machine_name);
|
||||
|
||||
*p++ = LLDP_TYPE(LLDP_SYSDESC_TLV_TYPE);
|
||||
*p++ = machine_name_length;
|
||||
memcpyc(p, machine.machine_name, machine_name_length);
|
||||
return machine_name_length + 2;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _LLDP_H_
|
||||
#define _LLDP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LLDP_MIN_ETHERNET_PAYLOAD_LENGTH 46
|
||||
#define LLDP_ETHERTYPE 0x88cc
|
||||
#define LLDP_ETHERTYPE_LENGTH 2
|
||||
#define LLDP_MAX_FRAME 256
|
||||
#define MAC_ADDR_LEN 6
|
||||
#define LLDP_TX_INTERVAL_TICKS 6000
|
||||
|
||||
#define LLDP_PORT_ID_TLV_TYPE 2
|
||||
#define LLDP_PORT_ID_TLV_LENGTH 0x02
|
||||
#define LLDP_PORT_ID_TLV_SUBTYPE 0x07
|
||||
|
||||
#define LLDP_TTL_TLV_TYPE 3
|
||||
#define LLDP_TTL_TLV_LENGTH 2
|
||||
#define LLDP_TTL_TTL_SECONDS 120
|
||||
|
||||
#define LLDP_CHASSIS_ID_TLV_TYPE 1
|
||||
#define LLDP_CHASSIS_ID_TLV_LENGTH 7
|
||||
#define LLDP_CHASSIS_ID_TLV_SUBTYPE 4
|
||||
|
||||
#define LLDP_SYSNAME_TLV_TYPE 5
|
||||
#define LLDP_SYSDESC_TLV_TYPE 6
|
||||
|
||||
void lldp_init(void) __banked;
|
||||
void lldp_tick(void) __banked;
|
||||
void lldp_send(void) __banked;
|
||||
void lldp_set_addresses(void) __banked;
|
||||
void lldp_set_rtl_wrapper(void) __banked;
|
||||
uint8_t lldp_sysname(__xdata uint8_t *p) __banked;
|
||||
uint8_t lldp_sysdesc(__xdata uint8_t *p) __banked;
|
||||
|
||||
#endif
|
||||
@@ -20,9 +20,11 @@
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code uint16_t bit_mask[16];
|
||||
extern __code const uint16_t bit_mask[16];
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern __xdata uint32_t rtl8224_release_tick;
|
||||
|
||||
__xdata struct phy_settings phy_settings;
|
||||
|
||||
@@ -33,7 +35,7 @@ __xdata struct phy_settings phy_settings;
|
||||
// Note: Adding `Swapping the RX for N-devices`-setting on the end of the array, didn't work.
|
||||
// Setting will apply but still no packets flow.
|
||||
// Settings are `0x2000, 0xc10c`,
|
||||
__code uint16_t rtl8224_sds0_setttings[42] = {
|
||||
__code const uint16_t rtl8224_sds0_setttings[42] = {
|
||||
// SDS_DATA, SDS_CMD
|
||||
0x4480, 0xc842,
|
||||
0x0400, 0xc9c2,
|
||||
@@ -214,9 +216,20 @@ void phy_config(uint8_t phy) __banked
|
||||
}
|
||||
|
||||
|
||||
void rtl8224_wait_ready(void) __banked
|
||||
{
|
||||
do {
|
||||
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID + 1);
|
||||
if (SFR_DATA_U16 == 0x8224)
|
||||
return;
|
||||
} while ((ticks - rtl8224_release_tick) < (SYS_TICK_HZ * 5 / 2));
|
||||
print_string("\r\nRTL8224 not responding\r\n");
|
||||
}
|
||||
|
||||
void phy_config_8224(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
uint16_t tries;
|
||||
print_string("\r\nphy_config_8224 called\r\nRTL8224 ID: ");
|
||||
|
||||
// Print RTL8224 chip id
|
||||
@@ -244,9 +257,12 @@ void phy_config_8224(void) __banked
|
||||
i++;
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, rtl8224_sds0_setttings[i]);
|
||||
i++;
|
||||
tries = 0xffff;
|
||||
do {
|
||||
rtl8224_read_reg_u16(0x3f8);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
} while ((SFR_DATA_8 & 0x80) && --tries);
|
||||
if (SFR_DATA_8 & 0x80)
|
||||
print_string("\r\nRTL8224 SerDes access timed out\r\n");
|
||||
}
|
||||
|
||||
print_string("\r\nphy_config_8224 done\r\n");
|
||||
@@ -354,8 +370,9 @@ void phy_set_speed(void) __banked
|
||||
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
||||
} else {
|
||||
// AN Advertisement Register (MMD 7.0x0010)
|
||||
// bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
||||
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1001);
|
||||
// bits 0-4: 0x1 (802.3 supported), bit 10: PAUSE,
|
||||
// Extended Next Page format used
|
||||
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1401);
|
||||
if (phy_settings.speed == PHY_SPEED_1G) {
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
// bit 14: SLAVE, bit 13: Multi-Port device, 1: LD Loop timin enableed
|
||||
|
||||
@@ -22,6 +22,7 @@ extern __xdata struct phy_settings phy_settings;
|
||||
void rtl8224_phy_enable(void) __banked;
|
||||
void phy_config(uint8_t phy) __banked;
|
||||
void phy_config_8224(void) __banked;
|
||||
void rtl8224_wait_ready(void) __banked;
|
||||
void phy_set_speed(void) __banked;
|
||||
void phy_set_duplex(void) __banked;
|
||||
void phy_show(uint8_t port) __banked;
|
||||
|
||||
@@ -10,38 +10,6 @@ extern __xdata uint8_t sfr_data[4];
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked {
|
||||
switch (sda_pin) {
|
||||
case GPIO47_I2C_SDA0:
|
||||
return 0;
|
||||
case GPIO49_I2C_SDA1:
|
||||
return 1;
|
||||
case GPIO51_I2C_SDA2_UART1_RX:
|
||||
return 2;
|
||||
case GPIO41_I2C_SDA3_MDIO1:
|
||||
return 3;
|
||||
case GPIO39_I2C_SDA4:
|
||||
return 4;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked{
|
||||
switch (scl_pin) {
|
||||
case GPIO46_I2C_SCL0:
|
||||
return 0;
|
||||
case GPIO48_I2C_SCL1:
|
||||
return 1;
|
||||
case GPIO50_I2C_SCL2_UART1_TX:
|
||||
return 2;
|
||||
case GPIO40_I2C_SCL3_MDC1:
|
||||
return 3;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns RTL837X_REG_GPIO_XX_OUTPUT register address */
|
||||
static uint16_t gpio_output_reg(uint8_t pin) __banked{
|
||||
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
|
||||
@@ -147,8 +115,7 @@ bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
|
||||
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
|
||||
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
|
||||
(dev >> 5) | i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5
|
||||
| i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2,
|
||||
(dev >> 5) | machine.sfp_port[slot].i2c,
|
||||
((dev << 3) & 0xff) | 0x1);
|
||||
|
||||
do {
|
||||
|
||||
@@ -71,12 +71,6 @@
|
||||
/* Not available GPIO */
|
||||
#define GPIO_NA 0xFF
|
||||
|
||||
/* Convert SDA PIN GPIO to I2C bus number */
|
||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked;
|
||||
|
||||
/* Convert SCL PIN GPIO to I2C bus number */
|
||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked;
|
||||
|
||||
/*
|
||||
* Setup a GPIO pin as input
|
||||
* pin: GPIO pin number 0-63
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code uint16_t bit_mask[16];
|
||||
extern __code struct machine machine;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
extern __code const uint16_t bit_mask[16];
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata uint16_t vlan_ptr;
|
||||
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
@@ -40,7 +40,6 @@ static void wait_table_ready(void)
|
||||
|
||||
void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked
|
||||
{
|
||||
print_string("\nport_mirror_set called \n");
|
||||
print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: ");
|
||||
print_short(rx_pmask); print_string(", tx mask: "); print_short(tx_pmask);
|
||||
write_char('\n');
|
||||
@@ -52,7 +51,6 @@ void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t t
|
||||
|
||||
void port_mirror_del(void) __banked
|
||||
{
|
||||
print_string("\nport_mirror_del called \n");
|
||||
REG_SET(RTL837x_MIRROR_CTRL, 0);
|
||||
}
|
||||
|
||||
@@ -102,9 +100,9 @@ static void port_pvid_write(uint8_t port, __xdata uint16_t pvid)
|
||||
|
||||
reg_read_m(reg);
|
||||
if (port & 0x1) {
|
||||
REG_WRITE(reg, sfr_data[0], pvid >> 4, sfr_data[2] & 0x0f | (pvid << 4), sfr_data[3]);
|
||||
REG_WRITE(reg, sfr_data[0], pvid >> 4, (sfr_data[2] & 0x0f) | (pvid << 4), sfr_data[3]);
|
||||
} else {
|
||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0 | (pvid >> 8), pvid);
|
||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], (sfr_data[2] & 0xf0) | (pvid >> 8), pvid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +110,6 @@ void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked
|
||||
{
|
||||
uint8_t lag = port_lag_of(port);
|
||||
|
||||
print_string("\nport_pvid_set called \n");
|
||||
if (lag == PORT_LAG_NONE) {
|
||||
port_pvid_write(port, pvid);
|
||||
return;
|
||||
@@ -141,7 +138,6 @@ void vlan_delete(uint16_t vlan) __banked
|
||||
if (!vlan || vlan >= 0xfff)
|
||||
return;
|
||||
|
||||
print_string("\nvlan_delete called \n"); print_short(vlan);
|
||||
vlan_name_remove(vlan);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_A, 0, 0, 0, 0);
|
||||
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_WRITE | TBL_EXECUTE);
|
||||
@@ -232,7 +228,7 @@ void vlan_create(void) __banked
|
||||
vlan_settings.members |= 0x0200; // Set 10th bit
|
||||
vlan_settings.tagged |= 0x0200;
|
||||
|
||||
print_string("\nvlan_create called\nvlan: "); print_short(vlan_settings.vlan);
|
||||
print_string("vlan: "); print_short(vlan_settings.vlan);
|
||||
print_string(", members: "); print_short(vlan_settings.members);
|
||||
print_string(", tagged: "); print_short(vlan_settings.tagged); write_char('\n');
|
||||
|
||||
@@ -250,7 +246,6 @@ void vlan_create(void) __banked
|
||||
|
||||
wait_table_ready();
|
||||
|
||||
print_string("vlan_create done \n");
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +258,6 @@ void vlan_create(void) __banked
|
||||
*/
|
||||
void vlan_setup(void) __banked
|
||||
{
|
||||
print_string("\nvlan_setup called \n");
|
||||
|
||||
// No VLAN names set up so far
|
||||
vlan_ptr = 0;
|
||||
@@ -285,7 +279,7 @@ void vlan_setup(void) __banked
|
||||
#endif
|
||||
reg_read_m(reg);
|
||||
if (i & 0x1) {
|
||||
REG_WRITE(reg, sfr_data[0], 0, sfr_data[2] & 0x0f | 0x10, sfr_data[3]);
|
||||
REG_WRITE(reg, sfr_data[0], 0, (sfr_data[2] & 0x0f) | 0x10, sfr_data[3]);
|
||||
} else {
|
||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0, 0x01);
|
||||
}
|
||||
@@ -331,7 +325,6 @@ void vlan_setup(void) __banked
|
||||
print_string("\nvlan_setup, REG 0x4f4c: "); print_reg(0x4f4c);
|
||||
#endif
|
||||
|
||||
print_string("vlan_setup done \n");
|
||||
}
|
||||
|
||||
|
||||
@@ -354,7 +347,6 @@ void port_l2_forget_port(uint8_t port) __banked
|
||||
*/
|
||||
uint8_t port_l2_forget(void) __banked
|
||||
{
|
||||
print_string("\nport_l2_forget called\n");
|
||||
// Configure the entries to be flushed:
|
||||
// port-based (bits 0-1 are 0 and dynamic entries, bit 2 specifies dynamic entries
|
||||
REG_SET(RTL837x_L2_TBL_FLUSH_CNF, 0x0);
|
||||
@@ -370,7 +362,6 @@ uint8_t port_l2_forget(void) __banked
|
||||
reg_read_m(RTL837x_L2_TBL_FLUSH_CTRL);
|
||||
} while (sfr_data[1]);
|
||||
|
||||
print_string("port_l2_forget done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -465,7 +456,6 @@ void port_l2mc_set(uint8_t mac_last, __xdata uint16_t vid, __xdata uint16_t pmas
|
||||
*/
|
||||
void port_l2_setup(void) __banked
|
||||
{
|
||||
print_string("\nport_l2_setup called\n");
|
||||
|
||||
port_l2_forget();
|
||||
|
||||
@@ -483,7 +473,38 @@ void port_l2_setup(void) __banked
|
||||
// When maximim entries learned, then simply flood the packet
|
||||
reg_bit_set(RTL837X_L2_LRN_PORT_CONSTRT_ACT, 0);
|
||||
|
||||
print_string("\nport_l2_setup done\n");
|
||||
}
|
||||
|
||||
|
||||
void port_media_show(uint8_t port) __banked
|
||||
{
|
||||
uint8_t pause;
|
||||
|
||||
if (!machine.is_sfp[port]) {
|
||||
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||
if (sfr_data[(port / 8) + 1] >> (port % 8) & 1) {
|
||||
print_string("Link role: ");
|
||||
reg_read_m(RTL837X_MAC_MSTR_SLV_STS);
|
||||
if (sfr_data[3 - (port >> 3)] & (1 << (port & 7)))
|
||||
print_string("master\n");
|
||||
else
|
||||
print_string("slave\n");
|
||||
}
|
||||
}
|
||||
|
||||
print_string("Pause negotiated:");
|
||||
reg_read_m(RTL837X_MAC_TX_PAUSE_STS);
|
||||
pause = sfr_data[3 - (port >> 3)] & (1 << (port & 7));
|
||||
if (pause)
|
||||
print_string(" TX");
|
||||
reg_read_m(RTL837X_MAC_RX_PAUSE_STS);
|
||||
if (sfr_data[3 - (port >> 3)] & (1 << (port & 7))) {
|
||||
print_string(" RX");
|
||||
pause = 1;
|
||||
}
|
||||
if (!pause)
|
||||
print_string(" none");
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
@@ -590,12 +611,12 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
|
||||
|
||||
if (machine.is_sfp[port])
|
||||
{
|
||||
print_string("EEE can't be enabled for SFP port "); print_byte(port); print_string("\n");
|
||||
print_string("EEE can't be enabled for SFP port "); print_phys_port(port); print_string("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), EEE_RX_ENABLE | EEE_TX_ENABLE);
|
||||
print_string("EEE on for "); print_byte(port); print_string(" speed ");
|
||||
print_string("EEE on for "); print_phys_port(port); print_string(" speed ");
|
||||
// Enable all speeds up to the specified speed
|
||||
if (speed & EEE_100) {
|
||||
print_string("100m\n");
|
||||
@@ -654,7 +675,7 @@ void port_eee_disable(uint8_t port) __banked
|
||||
if (machine.is_sfp[port])
|
||||
return;
|
||||
|
||||
print_string("EEE off for "); print_byte(port); write_char('\n');
|
||||
print_string("EEE off for "); print_phys_port(port); write_char('\n');
|
||||
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), 0);
|
||||
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
|
||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
|
||||
@@ -758,7 +779,7 @@ void port_eee_enable_all(__xdata uint8_t speed) __banked
|
||||
port_eee_enable(i, speed);
|
||||
} else {
|
||||
if (speed & EEE_10G)
|
||||
port_eee_enable(i, speed & EEE_NORESET | EEE_2G5);
|
||||
port_eee_enable(i, (speed & EEE_NORESET) | EEE_2G5);
|
||||
else
|
||||
port_eee_enable(i, speed);
|
||||
}
|
||||
@@ -899,7 +920,7 @@ void vlan_dump(void) __banked
|
||||
/** Set the ingress VLAN filtering */
|
||||
bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
||||
{
|
||||
if (port < machine.min_port || port > machine.max_port && port != CPU_PORT) {
|
||||
if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) {
|
||||
return false;
|
||||
}
|
||||
if (enabled)
|
||||
@@ -913,7 +934,7 @@ bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
||||
/** Get the ingress VLAN filtering status */
|
||||
bool port_ingress_vlan_filter_get(uint8_t port) __banked
|
||||
{
|
||||
if (port < machine.min_port || port > machine.max_port && port != CPU_PORT) {
|
||||
if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ extern __xdata struct vlan_settings vlan_settings;
|
||||
uint8_t port_l2_forget(void) __banked;
|
||||
void port_l2_learned(void) __banked;
|
||||
void port_stats_print(void) __banked;
|
||||
void port_media_show(uint8_t port) __banked;
|
||||
int8_t vlan_get(uint16_t vlan) __banked;
|
||||
__xdata uint16_t vlan_name(uint16_t vlan) __banked;
|
||||
void vlan_name_remove(uint16_t vlan) __banked;
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#define RESET_SOC_BIT 0
|
||||
#define RESET_NIC_BIT 2
|
||||
|
||||
#define RTL837X_TM_CTRL2 0x0338
|
||||
#define TM_CTRL2_EN_LATCH 0x04
|
||||
#define RTL837X_TM_RESULT 0x0340
|
||||
#define RTL837X_TM_RESULT_POWERON 0x0350
|
||||
// Temperature: 19 bit value, bits 18:3 in the low 16 bits of the register,
|
||||
// bits 2:0 in bits 18:16. Bit 18 signed, bits 17:10 degrees C, bits 9:0 fraction.
|
||||
|
||||
#define RTL837X_REG_HW_CONF 0x6040
|
||||
// Bits 4 & 5: CLOCK DIVIDER from 125MHz for Timer
|
||||
|
||||
@@ -83,6 +90,10 @@
|
||||
#define RTL837X_REG_LINKS 0x63f0
|
||||
#define RTL837X_REG_LINKS_89 0x63f4
|
||||
#define RTL837X_REG_LINKS_STS 0x63E8
|
||||
/* Per-port status bits: bit N is chip port N */
|
||||
#define RTL837X_MAC_TX_PAUSE_STS 0x63FC
|
||||
#define RTL837X_MAC_RX_PAUSE_STS 0x6400
|
||||
#define RTL837X_MAC_MSTR_SLV_STS 0x6408
|
||||
|
||||
/* Each nibble encodes the link state of a port.
|
||||
Port 0 appears to be the CPU port
|
||||
@@ -126,6 +137,10 @@
|
||||
#define RTL837X_REG_I2C_CTRL2 0x041c
|
||||
#define RTL837X_REG_I2C_IN 0x0420
|
||||
#define RTL837X_REG_I2C_OUT 0x0424
|
||||
#define RTL837X_REG_I2C_SCL_SHIFT 5
|
||||
#define RTL837X_REG_I2C_SDA_SHIFT 2
|
||||
#define RTL837X_REG_I2C_SCL_MASK 0x3
|
||||
#define RTL837X_REG_I2C_SDA_MASK 0x7
|
||||
|
||||
/*
|
||||
* NIC Related registers
|
||||
@@ -137,6 +152,10 @@
|
||||
#define RTL837X_REG_RX_CTRL 0x785c
|
||||
#define RTL837X_REG_TX_CTRL 0x7860
|
||||
#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874
|
||||
#define RTL837X_NIC_INT_STS 0x7854
|
||||
#define RTL837X_NIC_INT_MSK 0x7858
|
||||
#define NIC_INT_RXIS 0x02
|
||||
#define NIC_INT_RXIE 0x02
|
||||
#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c
|
||||
#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884
|
||||
#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890
|
||||
@@ -144,6 +163,9 @@
|
||||
#define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C
|
||||
#define RTL837X_REG_MAC_FORCE_MODE 0x6344
|
||||
|
||||
/* Flags in byte 1 of the RX frame descriptor */
|
||||
#define RX_TAG_L4_CSUM_BAD 0x04
|
||||
|
||||
/*
|
||||
* Statistics related registers
|
||||
*/
|
||||
@@ -263,6 +285,9 @@
|
||||
*/
|
||||
#define RTL8373_RLDP_TIMER 0x1074
|
||||
#define RTL837X_RMA0_CONF 0x4ecc
|
||||
#define RTL837X_IMR_INT_PORT_LINK_STS_CHG 0x5f34
|
||||
#define RTL837X_ISR_SW_INT_MODE 0x5f84
|
||||
#define RTL837X_ISR_INT_PORT_LINK_CHG 0x5f88
|
||||
#define RTL837X_RMA_CONF 0x4f1c
|
||||
#define RTL837X_MSTP_STATES 0x5310
|
||||
#define RTL837X_REG_LED_RLDP_1 0x65F8
|
||||
@@ -302,6 +327,11 @@
|
||||
#define RTL837X_IGBW_PORT_FC_CTRL 0x4C8C
|
||||
#define RTL837X_EGBW_PORT_CTRL 0x1c34
|
||||
#define RTL837X_EGBW_CTRL 0x447c
|
||||
#define RTL837X_STORM_CTRL 0x54e4
|
||||
#define RTL837X_STORM_MIDX 0x54f4
|
||||
#define RTL837X_METER_RATE 0x5cf0
|
||||
#define RTL837X_METER_BURST 0x5df0
|
||||
#define RTL837X_METER_MODE 0x5ef0
|
||||
#define EGBW_INC_IFG 0x02
|
||||
#define EGBW_CPUMODE 0x01
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
/* RTL837X_STORM_MIDX words, row type * 2 + half: half 0 holds ports 0-4, half 1 ports 5-9,
|
||||
* 6 bits per port, each set to STORM_METER(port, type) */
|
||||
static const __code uint8_t storm_midx[8][4] = {
|
||||
{ 0x28, 0x92, 0x07, 0x18 }, { 0x3c, 0xe3, 0x4c, 0x2c },
|
||||
{ 0x29, 0x96, 0x17, 0x59 }, { 0x3d, 0xe7, 0x5c, 0x6d },
|
||||
{ 0x2a, 0x9a, 0x27, 0x9a }, { 0x3e, 0xeb, 0x6c, 0xae },
|
||||
{ 0x2b, 0x9e, 0x37, 0xdb }, { 0x3f, 0xef, 0x7c, 0xef },
|
||||
};
|
||||
|
||||
static __code const char * __code const storm_names[STORM_TYPES] = { " bcast ", " mcast ", " ucast ", " umcast " };
|
||||
|
||||
|
||||
void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked
|
||||
{
|
||||
__xdata uint8_t idx = STORM_METER(port, type);
|
||||
__xdata uint8_t row = (type << 1) | (port >= 5 ? 1 : 0);
|
||||
__xdata uint8_t * __xdata r = (uint8_t *)&rate;
|
||||
|
||||
sfr_data[0] = 0;
|
||||
sfr_data[1] = r[2];
|
||||
sfr_data[2] = r[1];
|
||||
sfr_data[3] = r[0];
|
||||
reg_write_m(RTL837X_METER_RATE + (idx << 2));
|
||||
|
||||
if (!pps) {
|
||||
sfr_data[1] = 0;
|
||||
sfr_data[2] = 0x20;
|
||||
sfr_data[3] = 0;
|
||||
}
|
||||
reg_write_m(RTL837X_METER_BURST + (idx << 2));
|
||||
|
||||
if (pps)
|
||||
reg_bit_set(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f);
|
||||
else
|
||||
reg_bit_clear(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f);
|
||||
|
||||
sfr_data[0] = storm_midx[row][0];
|
||||
sfr_data[1] = storm_midx[row][1];
|
||||
sfr_data[2] = storm_midx[row][2];
|
||||
sfr_data[3] = storm_midx[row][3];
|
||||
reg_write_m(RTL837X_STORM_MIDX + (row << 2));
|
||||
|
||||
reg_bit_set(RTL837X_STORM_CTRL + (type << 2), port);
|
||||
}
|
||||
|
||||
|
||||
void storm_off(uint8_t port, __xdata uint8_t type) __banked
|
||||
{
|
||||
reg_bit_clear(RTL837X_STORM_CTRL + (type << 2), port);
|
||||
}
|
||||
|
||||
|
||||
void storm_show(void) __banked
|
||||
{
|
||||
uint8_t i, t, idx;
|
||||
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
print_string("port ");
|
||||
write_char('0' + machine.log_to_phys_port[i]);
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
print_string(storm_names[t]);
|
||||
if (!reg_bit_test(RTL837X_STORM_CTRL + (t << 2), i)) {
|
||||
print_string("off");
|
||||
continue;
|
||||
}
|
||||
idx = STORM_METER(i, t);
|
||||
reg_read_m(RTL837X_METER_RATE + (idx << 2));
|
||||
print_byte(sfr_data[1]); print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
if (reg_bit_test(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f))
|
||||
print_string(" pps");
|
||||
else
|
||||
print_string(" kbps");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _RTL837X_STORM_H_
|
||||
#define _RTL837X_STORM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define STORM_TYPES 4
|
||||
#define STORM_METER_BASE 24
|
||||
#define STORM_METER(port, type) (STORM_METER_BASE + (((port) << 2) | (type)))
|
||||
|
||||
void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked;
|
||||
void storm_off(uint8_t port, __xdata uint8_t type) __banked;
|
||||
void storm_show(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -15,12 +15,14 @@
|
||||
#include "uip.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __xdata uint8_t err_status;
|
||||
|
||||
// All entry points are __banked and nothing here runs from an interrupt,
|
||||
// so the module does not need to stay in the resident bank
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
|
||||
@@ -33,7 +35,7 @@ extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
extern __xdata uint8_t cmd_words_len;
|
||||
extern __xdata uint8_t cmd_words_b[15];
|
||||
extern __xdata char save_cmd; /* 0 while execute_config() replays the saved config */
|
||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd);
|
||||
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd);
|
||||
uint8_t atoi_byte(uint8_t idx);
|
||||
uint8_t cmd_parse_port_separator(uint8_t idx);
|
||||
extern __xdata uint8_t atoi_results_u8;
|
||||
@@ -47,31 +49,36 @@ __xdata uint8_t stp_rstp; /* 1 = RST BPDUs, 0 = legacy Config BPDUs */
|
||||
__xdata uint8_t stp_txhold; /* BPDUs per port per second */
|
||||
|
||||
|
||||
__xdata uint8_t stp_pflags[10];
|
||||
__xdata uint32_t stp_pcost[10]; /* 0 = auto */
|
||||
__xdata uint8_t stp_pprio[10];
|
||||
__xdata uint8_t stp_pp2p[10]; /* admin point-to-point: 0 auto, 1 on, 2 off */
|
||||
__xdata uint8_t stp_ent_of[STP_PORTS];
|
||||
__xdata uint16_t stp_lag_mask[STP_LAG_COUNT];
|
||||
__xdata uint8_t stp_ss_i;
|
||||
__xdata uint8_t stp_map_dirty;
|
||||
__xdata uint8_t stp_pflags[STP_ENTITIES];
|
||||
__xdata uint32_t stp_pcost[STP_ENTITIES]; /* 0 = auto */
|
||||
__xdata uint8_t stp_pprio[STP_ENTITIES];
|
||||
__xdata uint8_t stp_pp2p[STP_ENTITIES]; /* admin point-to-point: 0 auto, 1 on, 2 off */
|
||||
|
||||
/* Designated bridge, port and cost last heard on the port; stp_bpdu_age tells
|
||||
* whether they are still current.
|
||||
*/
|
||||
__xdata struct bridge stp_dbridge[10];
|
||||
__xdata uint16_t stp_dpid[10];
|
||||
__xdata uint32_t stp_dcost[10];
|
||||
__xdata struct bridge stp_dbridge[STP_ENTITIES];
|
||||
__xdata uint16_t stp_dpid[STP_ENTITIES];
|
||||
__xdata uint32_t stp_dcost[STP_ENTITIES];
|
||||
|
||||
/* ---- Status / runtime ---- */
|
||||
__xdata struct bridge root_bridge;
|
||||
__xdata uint32_t root_bridge_cost; /* our cost to the root (rx cost + root port cost) */
|
||||
__xdata uint8_t stp_root_port; /* 0xff = we are the root */
|
||||
__xdata uint16_t stp_tc_count;
|
||||
__xdata uint16_t stp_scratch16; /* scratch for status printing only */
|
||||
__xdata uint16_t stp_scratch16; /* scratch for status printing and the lag map */
|
||||
__xdata uint8_t stp_st_of;
|
||||
|
||||
__xdata uint16_t port_timers[10]; /* listen-period countdown (0 = not listening) */
|
||||
__xdata uint16_t port_hello[10]; /* hello TX countdown */
|
||||
__xdata uint16_t stp_bpdu_age[10]; /* ticks since last BPDU seen on port (saturating) */
|
||||
__xdata uint8_t stp_loop_held[10]; /* port is out of forwarding because a loop was seen on it */
|
||||
__xdata uint8_t stp_tx_budget[10]; /* tx hold: BPDUs left in the current second */
|
||||
__xdata uint8_t stp_tx_count[10]; /* BPDUs actually put on the wire, wraps at 256 */
|
||||
__xdata uint16_t port_timers[STP_ENTITIES]; /* listen-period countdown (0 = not listening) */
|
||||
__xdata uint16_t port_hello[STP_ENTITIES]; /* hello TX countdown */
|
||||
__xdata uint16_t stp_bpdu_age[STP_ENTITIES]; /* ticks since last BPDU seen on port (saturating) */
|
||||
__xdata uint8_t stp_loop_held[STP_ENTITIES]; /* port is out of forwarding because a loop was seen on it */
|
||||
__xdata uint8_t stp_tx_budget[STP_ENTITIES]; /* tx hold: BPDUs left in the current second */
|
||||
__xdata uint8_t stp_tx_count[STP_ENTITIES]; /* BPDUs actually put on the wire, wraps at 256 */
|
||||
__xdata uint16_t stp_sec_tick; /* 1 s window for the tx budget */
|
||||
__xdata uint16_t stp_link_prev; /* carrier bitmap as of the last check */
|
||||
__xdata uint16_t stp_link_now;
|
||||
@@ -161,10 +168,22 @@ struct stp_pkt_in {
|
||||
#define BPDU_ROLE_ROOT (0b10 << 2)
|
||||
#define BPDU_ROLE_DESIGNATED (0b11 << 2)
|
||||
|
||||
/* Port state as the MSTP register encodes it, two bits per port. */
|
||||
#define STP_ST_DISABLED 0b00
|
||||
#define STP_ST_BLOCKING 0b01
|
||||
#define STP_ST_LEARNING 0b10
|
||||
#define STP_ST_FORWARDING 0b11
|
||||
#define STP_ST_MASK 0b11
|
||||
|
||||
/* Console messages name the port on the front panel, not the internal index. */
|
||||
static void print_port_nl(uint8_t port) __reentrant
|
||||
{
|
||||
print_byte(machine.log_to_phys_port[port]);
|
||||
if (port >= STP_LAG_BASE) {
|
||||
write_char('L');
|
||||
write_char('1' + port - STP_LAG_BASE);
|
||||
} else {
|
||||
print_byte(machine.log_to_phys_port[port]);
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
@@ -184,6 +203,8 @@ static __code const char stp_state_txt[] = "off blocklearnfwd ";
|
||||
static __code const char stp_role_txt[] = "desgroot";
|
||||
static __code const char stp_edge_txt[] = "no yes ";
|
||||
|
||||
static uint8_t stp_ent_active(uint8_t e) __reentrant;
|
||||
|
||||
static void print_field(__code const char *txt, uint8_t idx, uint8_t width) __reentrant
|
||||
{
|
||||
txt += idx * width;
|
||||
@@ -207,7 +228,12 @@ static void stp_status(void)
|
||||
print_string(" (this switch)\n");
|
||||
} else {
|
||||
print_string(" port ");
|
||||
print_byte(machine.log_to_phys_port[stp_root_port]);
|
||||
if (stp_root_port >= STP_LAG_BASE) {
|
||||
write_char('L');
|
||||
write_char('1' + stp_root_port - STP_LAG_BASE);
|
||||
} else {
|
||||
print_byte(machine.log_to_phys_port[stp_root_port]);
|
||||
}
|
||||
print_string(" cost ");
|
||||
print_long(root_bridge_cost);
|
||||
write_char('\n');
|
||||
@@ -217,11 +243,26 @@ static void stp_status(void)
|
||||
write_char('\n');
|
||||
print_string("port state role edge tx bpdu\n");
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (!stp_ent_active(stp_i))
|
||||
continue;
|
||||
write_char(' ');
|
||||
print_byte(machine.log_to_phys_port[stp_i]);
|
||||
if (stp_i >= STP_LAG_BASE) {
|
||||
write_char('L');
|
||||
write_char('1' + stp_i - STP_LAG_BASE);
|
||||
} else {
|
||||
print_byte(machine.log_to_phys_port[stp_i]);
|
||||
}
|
||||
print_string(" ");
|
||||
print_field(stp_state_txt, (sfr_data[3 - (stp_i >> 2)] >> ((stp_i << 1) & 0x7)) & 0x3, 5);
|
||||
stp_st_of = stp_i;
|
||||
if (stp_i >= STP_LAG_BASE) {
|
||||
stp_st_of = 0;
|
||||
while (stp_st_of < STP_PORTS && !((stp_lag_mask[stp_i - STP_LAG_BASE] >> stp_st_of) & 1))
|
||||
stp_st_of++;
|
||||
if (stp_st_of >= STP_PORTS)
|
||||
stp_st_of = 0;
|
||||
}
|
||||
print_field(stp_state_txt, (sfr_data[3 - (stp_st_of >> 2)] >> ((stp_st_of << 1) & 0x7)) & 0x3, 5);
|
||||
write_char(' ');
|
||||
print_field(stp_role_txt, stp_i == stp_root_port ? 1 : 0, 4);
|
||||
write_char(' ');
|
||||
@@ -266,18 +307,95 @@ int8_t cmpBytes(__xdata uint8_t *m1, __xdata uint8_t *m2, uint8_t n) __reentrant
|
||||
}
|
||||
|
||||
|
||||
/* Write one port's 2-bit state into the ASIC's MSTP register.
|
||||
* 00 disable, 01 blocking, 10 learning, 11 forwarding. */
|
||||
static void stp_lag_map(void)
|
||||
{
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
stp_ent_of[stp_ss_i] = stp_ss_i;
|
||||
for (stp_scratch = 0; stp_scratch < STP_LAG_COUNT; stp_scratch++) {
|
||||
stp_scratch16 = port_lag_members_get(stp_scratch);
|
||||
if (stp_lag_mask[stp_scratch] != stp_scratch16)
|
||||
stp_map_dirty = 1;
|
||||
stp_lag_mask[stp_scratch] = stp_scratch16;
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
if ((stp_lag_mask[stp_scratch] >> stp_ss_i) & 1)
|
||||
stp_ent_of[stp_ss_i] = STP_LAG_BASE + stp_scratch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t stp_ent_active(uint8_t e) __reentrant
|
||||
{
|
||||
if (e >= STP_ENTITIES)
|
||||
return 0;
|
||||
if (e >= STP_LAG_BASE)
|
||||
return stp_lag_mask[e - STP_LAG_BASE] != 0;
|
||||
return e >= machine.min_port && e <= machine.max_port && stp_ent_of[e] == e;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t stp_ent_has(uint8_t ent, uint8_t p) __reentrant
|
||||
{
|
||||
if (ent < STP_LAG_BASE)
|
||||
return ent == p;
|
||||
return (stp_lag_mask[ent - STP_LAG_BASE] >> p) & 1;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t stp_state_port(uint8_t e) __reentrant
|
||||
{
|
||||
if (e < STP_LAG_BASE)
|
||||
return e;
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
if ((stp_lag_mask[e - STP_LAG_BASE] >> stp_ss_i) & 1)
|
||||
return stp_ss_i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void stp_state_bits(uint8_t port, uint8_t state) __reentrant
|
||||
{
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++)
|
||||
if (stp_ent_has(port, stp_ss_i))
|
||||
sfr_data[3 - (stp_ss_i >> 2)] |= (uint8_t)(state << ((stp_ss_i << 1) & 0x7));
|
||||
}
|
||||
|
||||
|
||||
static void stp_state_set(uint8_t port, uint8_t state) __reentrant
|
||||
{
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
stp_scratch = 3 - (port >> 2);
|
||||
sfr_data[stp_scratch] &= ~(uint8_t)(0b11 << ((port << 1) & 0x7));
|
||||
sfr_data[stp_scratch] |= (uint8_t)(state << ((port << 1) & 0x7));
|
||||
for (stp_ss_i = 0; stp_ss_i < STP_PORTS; stp_ss_i++) {
|
||||
if (!stp_ent_has(port, stp_ss_i))
|
||||
continue;
|
||||
stp_scratch = 3 - (stp_ss_i >> 2);
|
||||
sfr_data[stp_scratch] &= ~(uint8_t)(STP_ST_MASK << ((stp_ss_i << 1) & 0x7));
|
||||
sfr_data[stp_scratch] |= (uint8_t)(state << ((stp_ss_i << 1) & 0x7));
|
||||
}
|
||||
reg_write_m(RTL837X_MSTP_STATES);
|
||||
}
|
||||
|
||||
|
||||
static void stp_ent_apply(uint8_t e) __reentrant
|
||||
{
|
||||
if (!(stp_pflags[e] & STP_PF_ENABLED)) {
|
||||
stp_state_set(e, STP_ST_FORWARDING);
|
||||
return;
|
||||
}
|
||||
if (stp_pflags[e] & STP_PF_TRIPPED) {
|
||||
stp_state_set(e, STP_ST_DISABLED);
|
||||
return;
|
||||
}
|
||||
if (stp_pflags[e] & STP_PF_ADMEDGE) {
|
||||
stp_pflags[e] |= STP_PF_OPEREDGE;
|
||||
stp_state_set(e, STP_ST_FORWARDING);
|
||||
return;
|
||||
}
|
||||
if (port_timers[e])
|
||||
stp_state_set(e, STP_ST_BLOCKING);
|
||||
else
|
||||
stp_state_set(e, ((stp_link_prev >> e) & 1) ? STP_ST_FORWARDING : STP_ST_BLOCKING);
|
||||
}
|
||||
|
||||
|
||||
/* Signal a topology change. Edge ports are exempt. */
|
||||
static void stp_topology_change(uint8_t port) __reentrant
|
||||
{
|
||||
@@ -285,7 +403,13 @@ static void stp_topology_change(uint8_t port) __reentrant
|
||||
return;
|
||||
stp_tc_count++;
|
||||
stp_tc_while = ((uint16_t)stp_maxage_s + stp_fwddelay_s) * STP_HZ;
|
||||
port_l2_forget_port(port);
|
||||
if (port >= STP_LAG_BASE) {
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++)
|
||||
if (stp_ent_has(port, i))
|
||||
port_l2_forget_port(i);
|
||||
} else {
|
||||
port_l2_forget_port(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +420,7 @@ static void stp_topology_change(uint8_t port) __reentrant
|
||||
*/
|
||||
static void stp_loop_hold_peer(uint8_t port) __reentrant
|
||||
{
|
||||
if (port < machine.min_port || port > machine.max_port)
|
||||
if (port >= STP_ENTITIES || !stp_ent_active(port))
|
||||
return;
|
||||
if (!(stp_pflags[port] & STP_PF_ENABLED))
|
||||
return;
|
||||
@@ -305,7 +429,7 @@ static void stp_loop_hold_peer(uint8_t port) __reentrant
|
||||
if (!port_timers[port]) {
|
||||
print_string("STP: loop detected, blocking port ");
|
||||
print_port_nl(port);
|
||||
stp_state_set(port, 0b01);
|
||||
stp_state_set(port, STP_ST_BLOCKING);
|
||||
stp_pflags[port] &= ~STP_PF_OPEREDGE;
|
||||
stp_topology_change(port);
|
||||
}
|
||||
@@ -348,7 +472,18 @@ void stp_cnf_send(uint8_t port) __reentrant
|
||||
STP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
|
||||
STP_O->rtl_tag.reason = 0x00;
|
||||
STP_O->rtl_tag.flags = HTONS(RTL_TAG_LEARN_DIS);
|
||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
|
||||
if (port >= STP_LAG_BASE) {
|
||||
stp_scratch = 0;
|
||||
while (stp_scratch < STP_PORTS && !stp_ent_has(port, stp_scratch))
|
||||
stp_scratch++;
|
||||
if (stp_scratch >= STP_PORTS) {
|
||||
stp_tx_flags_extra = 0;
|
||||
return;
|
||||
}
|
||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << stp_scratch);
|
||||
} else {
|
||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
|
||||
}
|
||||
|
||||
STP_O->dsap = 0x42;
|
||||
STP_O->ssap = 0x42;
|
||||
@@ -359,8 +494,9 @@ void stp_cnf_send(uint8_t port) __reentrant
|
||||
STP_O->version = BPDU_VER_RSTP;
|
||||
STP_O->bpdu_type = BPDU_TYPE_RST;
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
stp_scratch = stp_state_port(port);
|
||||
STP_O->flags = port == stp_root_port ? BPDU_ROLE_ROOT : BPDU_ROLE_DESIGNATED;
|
||||
if (((sfr_data[3 - (port >> 2)] >> ((port << 1) & 0x7)) & 0b11) == 0b11)
|
||||
if (((sfr_data[3 - (stp_scratch >> 2)] >> ((stp_scratch << 1) & 0x7)) & STP_ST_MASK) == STP_ST_FORWARDING)
|
||||
STP_O->flags |= BPDU_FLAG_LEARNING | BPDU_FLAG_FORWARDING;
|
||||
} else {
|
||||
STP_O->msg_len = HTONS(BPDU_LEN_CONFIG);
|
||||
@@ -424,7 +560,7 @@ void stp_in(void) __banked
|
||||
stp_scratch = ((uint8_t)HTONS(STP_I->rtl_tag.pmask)) & 0x0f;
|
||||
if (stp_scratch < machine.min_port || stp_scratch > machine.max_port)
|
||||
return;
|
||||
port = stp_scratch;
|
||||
port = stp_ent_of[stp_scratch];
|
||||
|
||||
// Make sure this is the type of (R)STP packet we are interested in:
|
||||
if (!(STP_I->dsap == 0x42 && STP_I->ssap == 0x42 && STP_I->ctrl == 0x03))
|
||||
@@ -445,7 +581,7 @@ void stp_in(void) __banked
|
||||
print_string("STP: BPDU guard tripped, disabling port ");
|
||||
print_port_nl(port);
|
||||
stp_pflags[port] |= STP_PF_TRIPPED;
|
||||
stp_state_set(port, 0b00);
|
||||
stp_state_set(port, STP_ST_DISABLED);
|
||||
stp_tc_count++;
|
||||
return;
|
||||
}
|
||||
@@ -516,8 +652,9 @@ void stp_in(void) __banked
|
||||
uint8_t i;
|
||||
stp_tc_count++;
|
||||
for (i = machine.min_port; i <= machine.max_port; i++)
|
||||
if (i != port && (stp_pflags[i] & STP_PF_ENABLED)
|
||||
&& !(stp_pflags[i] & STP_PF_OPEREDGE))
|
||||
if (!stp_ent_has(port, i)
|
||||
&& (stp_pflags[stp_ent_of[i]] & STP_PF_ENABLED)
|
||||
&& !(stp_pflags[stp_ent_of[i]] & STP_PF_OPEREDGE))
|
||||
port_l2_forget_port(i);
|
||||
}
|
||||
if (stp_tc_while < ((uint16_t)stp_hello_s + 1) * STP_HZ)
|
||||
@@ -535,7 +672,7 @@ void stp_in(void) __banked
|
||||
if (stp_pflags[port] & STP_PF_ROOTGUARD) {
|
||||
print_string("STP: root guard blocking port ");
|
||||
print_port_nl(port);
|
||||
stp_state_set(port, 0b01);
|
||||
stp_state_set(port, STP_ST_BLOCKING);
|
||||
port_timers[port] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
stp_pflags[port] &= ~STP_PF_OPEREDGE;
|
||||
return;
|
||||
@@ -563,9 +700,35 @@ void stp_timers(void) __banked
|
||||
/* Refill the per-port tx budgets once per second (tx hold count) */
|
||||
if (++stp_sec_tick >= STP_HZ) {
|
||||
stp_sec_tick = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++)
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++)
|
||||
stp_tx_budget[stp_i] = stp_txhold;
|
||||
|
||||
stp_lag_map();
|
||||
if (stp_map_dirty) {
|
||||
stp_map_dirty = 0;
|
||||
for (stp_i = 0; stp_i < STP_LAG_BASE; stp_i++) {
|
||||
if (stp_i < machine.min_port || stp_i > machine.max_port)
|
||||
continue;
|
||||
if (stp_ent_of[stp_i] != stp_i) {
|
||||
stp_loop_held[stp_i] = 0;
|
||||
port_timers[stp_i] = 0;
|
||||
} else {
|
||||
stp_ent_apply(stp_i);
|
||||
}
|
||||
}
|
||||
for (stp_i = STP_LAG_BASE; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (stp_lag_mask[stp_i - STP_LAG_BASE]) {
|
||||
stp_ent_apply(stp_i);
|
||||
} else {
|
||||
stp_pflags[stp_i] &= ~(STP_PF_OPEREDGE | STP_PF_TRIPPED);
|
||||
stp_loop_held[stp_i] = 0;
|
||||
port_timers[stp_i] = 0;
|
||||
}
|
||||
}
|
||||
if (stp_root_port != 0xff && !stp_ent_active(stp_root_port))
|
||||
stp_claim_root();
|
||||
}
|
||||
|
||||
/* Link supervision. Without this the state machine never learns
|
||||
* that a port lost carrier: it keeps the port in forwarding, keeps
|
||||
* announcing on it, and never flushes what was learned behind it -
|
||||
@@ -574,14 +737,26 @@ void stp_timers(void) __banked
|
||||
* of the 50 Hz tick. */
|
||||
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||
stp_link_now = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8);
|
||||
{
|
||||
__xdata static uint16_t eff;
|
||||
eff = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++)
|
||||
if ((stp_link_now >> stp_i) & 1)
|
||||
eff |= (uint16_t)1 << stp_ent_of[stp_i];
|
||||
stp_link_now = eff;
|
||||
}
|
||||
if (stp_link_now != stp_link_prev) {
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (stp_i < STP_PORTS && (stp_i < machine.min_port || stp_i > machine.max_port))
|
||||
continue;
|
||||
if (stp_i < STP_PORTS && stp_ent_of[stp_i] != stp_i)
|
||||
continue;
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED))
|
||||
continue;
|
||||
if (!((stp_link_now ^ stp_link_prev) >> stp_i & 1))
|
||||
continue;
|
||||
/* Either way the port must stop forwarding first. */
|
||||
stp_state_set(stp_i, 0b01);
|
||||
stp_state_set(stp_i, STP_ST_BLOCKING);
|
||||
if ((stp_link_now >> stp_i) & 1) {
|
||||
/* Carrier back: re-run the listen period rather than
|
||||
* forwarding straight away - the segment may have been
|
||||
@@ -600,8 +775,8 @@ void stp_timers(void) __banked
|
||||
}
|
||||
}
|
||||
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED))
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
if (!stp_ent_active(stp_i) || !(stp_pflags[stp_i] & STP_PF_ENABLED))
|
||||
continue;
|
||||
|
||||
if (stp_bpdu_age[stp_i] < 0xffff)
|
||||
@@ -626,7 +801,7 @@ void stp_timers(void) __banked
|
||||
if (port_timers[stp_i]) {
|
||||
if (!--port_timers[stp_i]) {
|
||||
stp_loop_held[stp_i] = 0;
|
||||
stp_state_set(stp_i, 0b11);
|
||||
stp_state_set(stp_i, STP_ST_FORWARDING);
|
||||
print_string("STP: port forwarding ");
|
||||
print_port_nl(stp_i);
|
||||
stp_topology_change(stp_i);
|
||||
@@ -637,7 +812,7 @@ void stp_timers(void) __banked
|
||||
* host-facing, go to forwarding without the full wait. */
|
||||
port_timers[stp_i] = 0;
|
||||
stp_pflags[stp_i] |= STP_PF_OPEREDGE;
|
||||
stp_state_set(stp_i, 0b11);
|
||||
stp_state_set(stp_i, STP_ST_FORWARDING);
|
||||
print_string("STP: edge port forwarding ");
|
||||
print_port_nl(stp_i);
|
||||
}
|
||||
@@ -667,7 +842,12 @@ void stp_defaults(void) __banked
|
||||
stp_fwddelay_s = 15;
|
||||
stp_rstp = 1;
|
||||
stp_txhold = 6;
|
||||
for (stp_i = 0; stp_i < 10; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_PORTS; stp_i++)
|
||||
stp_ent_of[stp_i] = stp_i;
|
||||
for (stp_i = 0; stp_i < STP_LAG_COUNT; stp_i++)
|
||||
stp_lag_mask[stp_i] = 0;
|
||||
stp_map_dirty = 0;
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
/* enabled, auto-edge on: host-facing ports go forwarding after
|
||||
* 3 s of BPDU silence instead of the full forward delay */
|
||||
stp_pflags[stp_i] = STP_PF_ENABLED | STP_PF_AUTOEDGE;
|
||||
@@ -714,25 +894,34 @@ static void stp_fdb_update(__xdata uint16_t pmask)
|
||||
void stp_setup(void) __banked
|
||||
{
|
||||
print_string("Enabling STP: ");
|
||||
stp_lag_map();
|
||||
sfr_data[0] = sfr_data[1] = sfr_data[2] = sfr_data[3] = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
stp_pflags[stp_i] &= ~(STP_PF_OPEREDGE | STP_PF_TRIPPED);
|
||||
stp_loop_held[stp_i] = 0;
|
||||
stp_bpdu_age[stp_i] = 0;
|
||||
stp_tx_budget[stp_i] = stp_txhold;
|
||||
stp_tx_count[stp_i] = 0;
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED) || (stp_pflags[stp_i] & STP_PF_ADMEDGE)) {
|
||||
port_timers[stp_i] = 0;
|
||||
port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ;
|
||||
if (stp_i < STP_PORTS && (stp_i < machine.min_port || stp_i > machine.max_port))
|
||||
continue;
|
||||
if (stp_i >= STP_LAG_BASE && !stp_lag_mask[stp_i - STP_LAG_BASE])
|
||||
continue;
|
||||
if (stp_i < STP_PORTS && stp_ent_of[stp_i] != stp_i)
|
||||
continue;
|
||||
if (!(stp_pflags[stp_i] & STP_PF_ENABLED)
|
||||
|| (stp_pflags[stp_i] & STP_PF_ADMEDGE)) {
|
||||
/* not participating, or admin edge: forwarding immediately */
|
||||
if (stp_pflags[stp_i] & STP_PF_ADMEDGE)
|
||||
stp_pflags[stp_i] |= STP_PF_OPEREDGE;
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(0b11 << ((stp_i << 1) & 0x7));
|
||||
stp_state_bits(stp_i, STP_ST_FORWARDING);
|
||||
port_timers[stp_i] = 0;
|
||||
} else {
|
||||
/* listen first: blocking until the forward-delay expires */
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(0b01 << ((stp_i << 1) & 0x7));
|
||||
stp_state_bits(stp_i, STP_ST_BLOCKING);
|
||||
port_timers[stp_i] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
}
|
||||
port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ;
|
||||
}
|
||||
sfr_data[1] |= 0x0c; // Do not block the CPU port (bits 3:2 of byte 1 = port 9)
|
||||
reg_write_m(RTL837X_MSTP_STATES);
|
||||
@@ -752,7 +941,11 @@ void stp_setup(void) __banked
|
||||
/* Seed the carrier bitmap, so turning STP on does not report every
|
||||
* port that was already down as a fresh topology change. */
|
||||
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||
stp_link_prev = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8);
|
||||
stp_link_now = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8);
|
||||
stp_link_prev = 0;
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++)
|
||||
if ((stp_link_now >> stp_i) & 1)
|
||||
stp_link_prev |= (uint16_t)1 << stp_ent_of[stp_i];
|
||||
|
||||
stp_claim_root();
|
||||
|
||||
@@ -767,7 +960,9 @@ void stp_off(void) __banked
|
||||
for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) {
|
||||
// Set STP port state to forwarding
|
||||
// States are: 00 disable, 01 blocking, 10 learning, 11 forwarding
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(0b11 << ((stp_i << 1) & 0x7));
|
||||
sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(STP_ST_FORWARDING << ((stp_i << 1) & 0x7));
|
||||
}
|
||||
for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) {
|
||||
stp_pflags[stp_i] &= ~(STP_PF_OPEREDGE | STP_PF_TRIPPED);
|
||||
stp_loop_held[stp_i] = 0;
|
||||
port_timers[stp_i] = 0;
|
||||
@@ -782,7 +977,7 @@ void stp_off(void) __banked
|
||||
|
||||
void stp_parse(void) __banked __reentrant
|
||||
{
|
||||
uint8_t port;
|
||||
uint8_t ent;
|
||||
|
||||
if (cmd_compare(1, "on")) {
|
||||
print_string("STP enabled\n");
|
||||
@@ -803,35 +998,50 @@ void stp_parse(void) __banked __reentrant
|
||||
if (cmd_words_len < 3)
|
||||
goto err;
|
||||
|
||||
if (cmd_compare(1, "port")) {
|
||||
if (cmd_compare(1, "port") || cmd_compare(1, "lag")) {
|
||||
stp_lag_map();
|
||||
if (cmd_words_len < 4)
|
||||
goto err;
|
||||
if (!cmd_parse_port_separator(cmd_words_b[2]))
|
||||
goto err;
|
||||
port = atoi_results_u8;
|
||||
if (cmd_compare(1, "lag")) {
|
||||
if (!atoi_byte(cmd_words_b[2]))
|
||||
goto err;
|
||||
if (!atoi_results_u8 || atoi_results_u8 > STP_LAG_COUNT)
|
||||
goto err;
|
||||
ent = STP_LAG_BASE + atoi_results_u8 - 1;
|
||||
} else {
|
||||
if (!cmd_parse_port_separator(cmd_words_b[2]))
|
||||
goto err;
|
||||
ent = atoi_results_u8;
|
||||
if (stp_ent_of[ent] != ent) {
|
||||
print_string("Port belongs to a LAG, configure it as lag ");
|
||||
print_byte(stp_ent_of[ent] - STP_LAG_BASE + 1);
|
||||
write_char('\n');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cmd_words_len < 5 && !cmd_compare(3, "on") && !cmd_compare(3, "off"))
|
||||
goto err;
|
||||
if (cmd_compare(3, "on")) {
|
||||
stp_pflags[port] |= STP_PF_ENABLED;
|
||||
stp_pflags[port] &= ~STP_PF_TRIPPED;
|
||||
stp_pflags[ent] |= STP_PF_ENABLED;
|
||||
stp_pflags[ent] &= ~STP_PF_TRIPPED;
|
||||
if (stp_enabled) { /* (re)join: listen first */
|
||||
stp_state_set(port, 0b01);
|
||||
port_timers[port] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
stp_state_set(ent, STP_ST_BLOCKING);
|
||||
port_timers[ent] = (uint16_t)stp_fwddelay_s * STP_HZ;
|
||||
}
|
||||
} else if (cmd_compare(3, "off")) {
|
||||
stp_pflags[port] &= ~STP_PF_ENABLED;
|
||||
stp_pflags[ent] &= ~STP_PF_ENABLED;
|
||||
if (stp_enabled)
|
||||
stp_state_set(port, 0b11); /* plain forwarding */
|
||||
stp_state_set(ent, STP_ST_FORWARDING); /* plain forwarding */
|
||||
} else if (cmd_compare(3, "edge")) {
|
||||
/* Also drop the *operational* edge flag: it is what exempts the
|
||||
* port from topology changes and lets it skip the listen period,
|
||||
* ent from topology changes and lets it skip the listen period,
|
||||
* so leaving it set would keep the old behaviour until the next
|
||||
* "stp off"/"stp on". An admin edge is operational immediately. */
|
||||
stp_pflags[port] &= ~(STP_PF_ADMEDGE | STP_PF_AUTOEDGE | STP_PF_OPEREDGE);
|
||||
stp_pflags[ent] &= ~(STP_PF_ADMEDGE | STP_PF_AUTOEDGE | STP_PF_OPEREDGE);
|
||||
if (cmd_compare(4, "on"))
|
||||
stp_pflags[port] |= STP_PF_ADMEDGE | STP_PF_OPEREDGE;
|
||||
stp_pflags[ent] |= STP_PF_ADMEDGE | STP_PF_OPEREDGE;
|
||||
else if (cmd_compare(4, "auto"))
|
||||
stp_pflags[port] |= STP_PF_AUTOEDGE;
|
||||
stp_pflags[ent] |= STP_PF_AUTOEDGE;
|
||||
else if (!cmd_compare(4, "off"))
|
||||
goto err;
|
||||
} else if (cmd_compare(3, "cost")) {
|
||||
@@ -848,14 +1058,14 @@ void stp_parse(void) __banked __reentrant
|
||||
}
|
||||
if (stp_cost_scratch > 200000000UL)
|
||||
goto err;
|
||||
stp_pcost[port] = stp_cost_scratch;
|
||||
stp_pcost[ent] = stp_cost_scratch;
|
||||
} else if (cmd_compare(3, "p2p")) {
|
||||
if (cmd_compare(4, "auto"))
|
||||
stp_pp2p[port] = 0;
|
||||
stp_pp2p[ent] = 0;
|
||||
else if (cmd_compare(4, "on"))
|
||||
stp_pp2p[port] = 1;
|
||||
stp_pp2p[ent] = 1;
|
||||
else if (cmd_compare(4, "off"))
|
||||
stp_pp2p[port] = 2;
|
||||
stp_pp2p[ent] = 2;
|
||||
else
|
||||
goto err;
|
||||
} else if (cmd_compare(3, "prio")) {
|
||||
@@ -863,20 +1073,20 @@ void stp_parse(void) __banked __reentrant
|
||||
goto err;
|
||||
if (atoi_results_u8 > 240 || (atoi_results_u8 & 0x0f))
|
||||
goto err;
|
||||
stp_pprio[port] = atoi_results_u8;
|
||||
stp_pprio[ent] = atoi_results_u8;
|
||||
} else if (cmd_compare(3, "guard")) {
|
||||
stp_pflags[port] &= ~(STP_PF_BPDUGUARD | STP_PF_ROOTGUARD);
|
||||
stp_pflags[ent] &= ~(STP_PF_BPDUGUARD | STP_PF_ROOTGUARD);
|
||||
if (cmd_compare(4, "bpdu"))
|
||||
stp_pflags[port] |= STP_PF_BPDUGUARD;
|
||||
stp_pflags[ent] |= STP_PF_BPDUGUARD;
|
||||
else if (cmd_compare(4, "root"))
|
||||
stp_pflags[port] |= STP_PF_ROOTGUARD;
|
||||
stp_pflags[ent] |= STP_PF_ROOTGUARD;
|
||||
else if (!cmd_compare(4, "none"))
|
||||
goto err;
|
||||
} else if (cmd_compare(3, "filter")) {
|
||||
if (cmd_compare(4, "on"))
|
||||
stp_pflags[port] |= STP_PF_FILTER;
|
||||
stp_pflags[ent] |= STP_PF_FILTER;
|
||||
else if (cmd_compare(4, "off"))
|
||||
stp_pflags[port] &= ~STP_PF_FILTER;
|
||||
stp_pflags[ent] &= ~STP_PF_FILTER;
|
||||
else
|
||||
goto err;
|
||||
} else {
|
||||
@@ -926,5 +1136,6 @@ void stp_parse(void) __banked __reentrant
|
||||
}
|
||||
return;
|
||||
err:
|
||||
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | port <1-9> on|off|edge|cost|prio|guard|filter ...\n");
|
||||
err_status = ERR_INVALID_ARGUMENT;
|
||||
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | port <1-9>|lag <1-4> on|off|edge|cost|prio|guard|filter ...\n");
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _RTL837X_STP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
void stp_in(void) __banked;
|
||||
void stp_setup(void) __banked;
|
||||
void stp_timers(void) __banked;
|
||||
@@ -12,6 +13,11 @@ void stp_defaults(void) __banked;
|
||||
/* Tick rate of stp_timers(), also used by the web UI. */
|
||||
#define STP_HZ 50
|
||||
|
||||
#define STP_PORTS (CPU_PORT + 1)
|
||||
#define STP_LAG_BASE STP_PORTS
|
||||
#define STP_LAG_COUNT 4
|
||||
#define STP_ENTITIES (STP_LAG_BASE + STP_LAG_COUNT)
|
||||
|
||||
/* Bridge identifier as carried in a BPDU (priority, extension, MAC). */
|
||||
struct bridge {
|
||||
uint8_t prio;
|
||||
@@ -36,15 +42,19 @@ extern __xdata uint8_t stp_txhold;
|
||||
#define STP_PF_OPEREDGE 0x40 /* runtime: port went forwarding as an edge */
|
||||
#define STP_PF_TRIPPED 0x80 /* runtime: disabled by BPDU guard */
|
||||
|
||||
extern __xdata uint8_t stp_pflags[10];
|
||||
extern __xdata uint32_t stp_pcost[10];
|
||||
extern __xdata uint8_t stp_pprio[10];
|
||||
extern __xdata uint8_t stp_pp2p[10];
|
||||
extern __xdata uint8_t stp_pflags[STP_ENTITIES];
|
||||
extern __xdata uint32_t stp_pcost[STP_ENTITIES]; /* path cost; 0 = auto (20000) */
|
||||
extern __xdata uint8_t stp_pprio[STP_ENTITIES];
|
||||
extern __xdata uint8_t stp_pp2p[STP_ENTITIES];
|
||||
extern __xdata uint8_t stp_ent_of[10]; /* the STP entity a port answers to: itself, or its lag */
|
||||
extern __xdata uint16_t stp_lag_mask[STP_LAG_COUNT]; /* member ports of each lag; 0 = not part of STP */
|
||||
|
||||
extern __xdata struct bridge stp_dbridge[10];
|
||||
extern __xdata uint16_t stp_dpid[10];
|
||||
extern __xdata uint32_t stp_dcost[10];
|
||||
extern __xdata uint16_t stp_bpdu_age[10];
|
||||
/* Last-heard designated info per port (from received BPDUs); consult
|
||||
* stp_bpdu_age to decide whether it is still current. */
|
||||
extern __xdata struct bridge stp_dbridge[STP_ENTITIES];
|
||||
extern __xdata uint16_t stp_dpid[STP_ENTITIES];
|
||||
extern __xdata uint32_t stp_dcost[STP_ENTITIES];
|
||||
extern __xdata uint16_t stp_bpdu_age[STP_ENTITIES]; /* ticks since a BPDU was heard */
|
||||
|
||||
extern __xdata struct bridge root_bridge;
|
||||
extern __xdata uint32_t root_bridge_cost;
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
; 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, 0xc7
|
||||
|
||||
|
||||
.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
|
||||
|
||||
;
|
||||
; print the address of a register read The address is in R2/R3. Registers 4-7 are scratch
|
||||
;
|
||||
reg_read_head:
|
||||
mov a, #'r'
|
||||
acall putc
|
||||
|
||||
mov a, r2
|
||||
acall wbyte
|
||||
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
clr a
|
||||
mov r7, a
|
||||
mov r6, a
|
||||
mov r5, a
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
reg_read_tail:
|
||||
mov dptr, #0xc5
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #0xc5 + 1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #0xc5 + 2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #0xc5 + 3
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov dptr,#0xc5
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
; print phy write options
|
||||
;
|
||||
phy_write:
|
||||
mov a, #'P'
|
||||
acall putc
|
||||
|
||||
mov a, r4
|
||||
acall wbyte
|
||||
|
||||
; phymask
|
||||
mov a, r6
|
||||
acall wbyte
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, #'.'
|
||||
acall putc
|
||||
|
||||
; dev_id?
|
||||
mov a, r5
|
||||
acall wbyte
|
||||
|
||||
; x_phywrite_opt
|
||||
mov dptr, #0xf1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
; The register going to SFR_C2 and SFR_C3
|
||||
mov a, r2
|
||||
acall wbyte
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov dptr, #0xf2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
|
||||
mov dptr, #0xf3
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov dptr, #0xeb
|
||||
mov r4, #0
|
||||
ret
|
||||
|
||||
;
|
||||
; print phy read options
|
||||
;
|
||||
phy_read_head:
|
||||
mov r1, 4 ; actually r4
|
||||
|
||||
mov a, #'p'
|
||||
acall putc
|
||||
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, r5
|
||||
acall wbyte
|
||||
|
||||
mov a, #'.'
|
||||
acall putc
|
||||
|
||||
mov a, r2
|
||||
acall wbyte
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov r1, 7
|
||||
mov a, r2
|
||||
ret
|
||||
|
||||
phy_read_tail:
|
||||
mov r6, 4
|
||||
mov a, r6
|
||||
acall wbyte
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
mov r4, 6
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
; print SDS write options
|
||||
;
|
||||
sds_write:
|
||||
mov a, r4
|
||||
mov r2, a ; R2 is scratch
|
||||
|
||||
mov a, #'Q'
|
||||
acall putc
|
||||
|
||||
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
mov a, r5
|
||||
acall wbyte
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov dptr, #0xe1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
|
||||
mov dptr, #0xe2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov a, r7
|
||||
mov r1, a
|
||||
mov a, r5
|
||||
mov r7, a
|
||||
mov a, r2
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
;
|
||||
; print SDS read options
|
||||
;
|
||||
sds_read_head:
|
||||
mov a, r4
|
||||
mov r1, a ; R1 is scratch
|
||||
|
||||
mov a, #'q'
|
||||
acall putc
|
||||
|
||||
mov a, r7 ; sds_index bit
|
||||
acall wbyte
|
||||
mov a, r5 ; SFR_94 (2 x r5 | r7)
|
||||
acall wbyte
|
||||
mov a, r3 ; SFR_93
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov a, r1
|
||||
mov r4, a ; R1 is scratch
|
||||
|
||||
mov a, r7
|
||||
mov r1, a
|
||||
mov a, r5
|
||||
mov r7, a
|
||||
|
||||
ret
|
||||
|
||||
;
|
||||
; print SDS read result
|
||||
;
|
||||
sds_read_tail:
|
||||
mov a, r4
|
||||
mov r6, a ; R6 is returned and preserved
|
||||
|
||||
mov a, r7 ; = r7 = SFR_DATA_8
|
||||
acall wbyte
|
||||
mov r7, SFR_DATA_0
|
||||
mov a, r7 ; SFR_DATA_0
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov a, r6 ; R6 is returned and preserved
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
;
|
||||
; Write a byte as hex to serial
|
||||
;
|
||||
nop
|
||||
nop
|
||||
wbyte:
|
||||
mov r4, a
|
||||
swap a
|
||||
anl a, #0x0f
|
||||
mov dptr,#hex
|
||||
movc a, @a+dptr
|
||||
|
||||
jb ET0, wbyte1
|
||||
ret
|
||||
wbyte1:
|
||||
jbc TI, wbyte2
|
||||
sjmp wbyte1
|
||||
wbyte2:
|
||||
mov SBUF,a
|
||||
|
||||
mov a, r4
|
||||
anl a, #0x0f
|
||||
mov dptr,#hex
|
||||
movc a, @a+dptr
|
||||
|
||||
wbyte3:
|
||||
jbc TI, wbyte4
|
||||
sjmp wbyte3
|
||||
wbyte4:
|
||||
mov SBUF,a
|
||||
|
||||
ret
|
||||
|
||||
;
|
||||
; Intercept isr_ext0
|
||||
;
|
||||
isr_ext0:
|
||||
mov a, #'i'
|
||||
acall putc
|
||||
mov r0,#0x51
|
||||
inc @r0
|
||||
ret
|
||||
|
||||
;
|
||||
; Intercept isr_ext1
|
||||
;
|
||||
isr_ext1:
|
||||
mov a, #'I'
|
||||
acall putc
|
||||
mov r0,#0x25
|
||||
mov a, @r0
|
||||
ret
|
||||
;
|
||||
; Intercept isr_ext2
|
||||
;
|
||||
isr_ext2:
|
||||
mov a, #'J'
|
||||
acall putc
|
||||
mov r0, #0x1e
|
||||
mov a, #0xa
|
||||
ret
|
||||
|
||||
;
|
||||
; Intercept isr_ext3
|
||||
;
|
||||
isr_ext3:
|
||||
mov a, #'j'
|
||||
acall putc
|
||||
mov r0,#0x1e
|
||||
mov a,#0x14
|
||||
ret
|
||||
|
||||
;
|
||||
; Write a character to serial
|
||||
;
|
||||
nop
|
||||
nop
|
||||
putc:
|
||||
jb ET0, putc1
|
||||
ret
|
||||
putc1:
|
||||
jbc TI,putc2
|
||||
sjmp putc1
|
||||
putc2:
|
||||
mov SBUF,a
|
||||
ret
|
||||
|
||||
hex:
|
||||
.byte "0123456789abcdef"
|
||||
.end
|
||||
@@ -0,0 +1,235 @@
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#include <8051.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_pins.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "machine.h"
|
||||
#include "phy.h"
|
||||
#include "boot.h"
|
||||
#include "sfp.h"
|
||||
|
||||
extern __code const struct machine machine;
|
||||
|
||||
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
||||
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
|
||||
__xdata uint8_t sfp_pins_last;
|
||||
__xdata char sfp_module_vendor[2][17];
|
||||
__xdata char sfp_module_model[2][17];
|
||||
__xdata char sfp_module_serial[2][17];
|
||||
__xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
||||
__xdata uint8_t sfp_speed[2];
|
||||
__xdata uint8_t sfp_quirks[2];
|
||||
__xdata uint8_t sfp_wake_at[2];
|
||||
__xdata uint8_t sfp_wake_pending[2];
|
||||
|
||||
|
||||
__code enum sfp_quirk {
|
||||
SFP_QUIRK_DDM = (1 << 0),
|
||||
};
|
||||
|
||||
struct sfp_quirk_entry {
|
||||
__code const char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code const char *model;
|
||||
uint8_t quirks;
|
||||
};
|
||||
|
||||
static __code const struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static inline uint8_t sfp_rate_to_sds_config(uint8_t rate)
|
||||
{
|
||||
if (rate == 0x1 || rate == 0x2)
|
||||
return SDS_100FX;
|
||||
if (rate == 0xc || rate == 0xd)
|
||||
return SDS_1000BX_FIBER;
|
||||
if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit
|
||||
return SDS_HSG;
|
||||
if (rate >= 0x62 && rate < 0x70)
|
||||
return SDS_10GR;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool sfp_print_info(uint8_t sfp) __banked
|
||||
{
|
||||
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||
for (uint8_t i = 16; i < 64; i++) {
|
||||
if (!(i & 0xf) && !sfp_read_block(sfp, i, 16))
|
||||
return false;
|
||||
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
||||
continue;
|
||||
uint8_t c = sfp_buf[i & 0xf];
|
||||
if (c)
|
||||
write_char(c);
|
||||
}
|
||||
print_string("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons
|
||||
bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __banked __reentrant
|
||||
{
|
||||
if (!sfp_read_block(sfp, start, length))
|
||||
return false;
|
||||
|
||||
dst[length] = NUL;
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
uint8_t c = sfp_buf[i];
|
||||
if (c && (c < 0x20 || c > 0x7e || c == '"' || c == '\\'))
|
||||
c = '.';
|
||||
dst[i] = c;
|
||||
}
|
||||
|
||||
while (length-- > 0 && (dst[length] == ' ' || dst[length] == NUL))
|
||||
dst[length] = NUL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool sfp_get_info(uint8_t sfp) __banked
|
||||
{
|
||||
if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16))
|
||||
return false;
|
||||
if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16))
|
||||
return false;
|
||||
|
||||
return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sfp_apply_quirks(uint8_t sfp) __banked __reentrant
|
||||
{
|
||||
sfp_quirks[sfp] = 0;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) {
|
||||
if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) {
|
||||
if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) {
|
||||
sfp_quirks[sfp] |= sfp_quirk_table[i].quirks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sfp_quirks[sfp] & SFP_QUIRK_DDM) {
|
||||
if (!(sfp_options[sfp] & 0x40)) {
|
||||
// The module reports that DDM is not implemented, but try a dummy read to confirm
|
||||
// 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V
|
||||
if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) {
|
||||
sfp_options[sfp] |= 0x40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Inititalize SFP GPIOs */
|
||||
void setup_sfp_gpio(void) __banked
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_detect);
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_los);
|
||||
gpio_output_setup(machine.sfp_port[sfp].pin_tx_disable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool sfp_module_read(uint8_t sfp)
|
||||
{
|
||||
uint8_t rate;
|
||||
|
||||
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
||||
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
||||
if (!sfp_read_block(sfp, 11, 2))
|
||||
return false;
|
||||
|
||||
rate = sfp_buf[1];
|
||||
if (sfp_speed[sfp] == SFP_SPEED_100M)
|
||||
rate = 0x1;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_1G)
|
||||
rate = 0xc;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_2G5)
|
||||
rate = 0x19;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_10G)
|
||||
rate = 0x69;
|
||||
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
|
||||
print_string(" Encoding: "); print_byte(sfp_buf[0]);
|
||||
print_string(" Module: ");
|
||||
if (!sfp_print_info(sfp))
|
||||
return false;
|
||||
print_string("\n");
|
||||
|
||||
if (!sfp_read_block(sfp, 92, 1))
|
||||
return false;
|
||||
sfp_options[sfp] = sfp_buf[0];
|
||||
if (!sfp_get_info(sfp))
|
||||
return false;
|
||||
|
||||
sfp_apply_quirks(sfp);
|
||||
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void handle_sfp(void) __banked
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
|
||||
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
||||
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
||||
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
|
||||
sfp_wake_at[sfp] = ticks;
|
||||
sfp_wake_pending[sfp] = 1;
|
||||
} else if (sfp_wake_pending[sfp]
|
||||
&& (uint8_t)((uint8_t)ticks - sfp_wake_at[sfp]) >= SFP_WAKE_TICKS) {
|
||||
sfp_wake_pending[sfp] = 0;
|
||||
if (!sfp_module_read(sfp)) {
|
||||
print_string("SFP: an I2C read failed, retrying on the next poll\n");
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
sfp_wake_pending[sfp] = 0;
|
||||
print_string("\n<MODULE REMOVED> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_los)) {
|
||||
if (sfp_pins_last & (0x2 << (sfp << 2))) { // 0x2 0x08
|
||||
sfp_pins_last &= ~(0x02 << (sfp << 2));
|
||||
print_string("\n<SFP-RX OK> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
} else {
|
||||
if (!(sfp_pins_last & 0x2 << (sfp << 2))) {
|
||||
sfp_pins_last |= 0x02 << (sfp << 2);
|
||||
print_string("\n<SFP-RX LOS> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef SFP_H
|
||||
#define SFP_H
|
||||
|
||||
#define SFP_WAKE_TICKS 100
|
||||
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata char sfp_module_vendor[2][17];
|
||||
extern __xdata char sfp_module_model[2][17];
|
||||
extern __xdata char sfp_module_serial[2][17];
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
extern __xdata uint8_t sfp_speed[2];
|
||||
extern __xdata uint8_t sfp_quirks[2];
|
||||
|
||||
bool sfp_print_info(uint8_t sfp) __banked;
|
||||
bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __banked __reentrant;
|
||||
bool sfp_get_info(uint8_t sfp) __banked;
|
||||
void sfp_apply_quirks(uint8_t sfp) __banked __reentrant;
|
||||
void setup_sfp_gpio(void) __banked;
|
||||
void handle_sfp(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -60,7 +60,7 @@ void syslog_stop(void) __banked
|
||||
void syslog_callback(uint16_t lport) __banked
|
||||
{
|
||||
uint16_t syslog_hdr;
|
||||
if (lport != state.syslog_conn->lport)
|
||||
if (!state.syslog_conn || lport != state.syslog_conn->lport)
|
||||
return;
|
||||
|
||||
if ((state.readptr != state.writeptr) && state.line_available)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# Host unit-test harness for RTLPlayground firmware logic.
|
||||
#
|
||||
# Compiles selected firmware translation units with host gcc + AddressSanitizer,
|
||||
# force-including sdcc_shim.h to erase 8051 keywords, and links them against
|
||||
# mocked hardware edges (support.c). No SDCC, no flashing, no hardware.
|
||||
#
|
||||
# make build + run all tests
|
||||
# make run run tests
|
||||
# make clean
|
||||
|
||||
CC = gcc
|
||||
SRCROOT = ..
|
||||
# -include shim first so __xdata/__code/__banked vanish before any firmware header.
|
||||
CFLAGS = -std=gnu11 -g -O1 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unknown-pragmas \
|
||||
-Wno-pointer-sign \
|
||||
-DRTLP_HOST_TEST \
|
||||
-fsanitize=address,undefined -fno-omit-frame-pointer \
|
||||
-include sdcc_shim.h -Istub -I. -I$(SRCROOT) -I$(SRCROOT)/httpd -I$(SRCROOT)/uip
|
||||
ifeq ($(findstring clang,$(shell $(CC) --version 2>/dev/null)),)
|
||||
CFLAGS += -Wno-builtin-declaration-mismatch
|
||||
endif
|
||||
LDFLAGS = -fsanitize=address,undefined
|
||||
|
||||
BUILDDIR = build
|
||||
|
||||
# One binary per subsystem under test.
|
||||
TESTS = $(BUILDDIR)/test_cmd_editor \
|
||||
$(BUILDDIR)/test_port_tables \
|
||||
$(BUILDDIR)/test_page_json \
|
||||
$(BUILDDIR)/test_httpd_tx \
|
||||
$(BUILDDIR)/test_tick_gate
|
||||
|
||||
# The table tests link the register mock and one environment file; stub/
|
||||
# stands in for the two headers a firmware build generates.
|
||||
TABLE_ENV = support.c hw_mock.c env_tables.c $(SRCROOT)/cmd_editor.c \
|
||||
$(SRCROOT)/rtl837x_port.c $(SRCROOT)/httpd/page_impl.c
|
||||
|
||||
all: run
|
||||
|
||||
$(BUILDDIR):
|
||||
mkdir -p $(BUILDDIR)
|
||||
|
||||
# cmd_editor.c is compiled UNMODIFIED from the firmware tree.
|
||||
$(BUILDDIR)/test_cmd_editor: test_cmd_editor.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
# rtl837x_port.c and httpd/page_impl.c are compiled UNMODIFIED from the firmware tree.
|
||||
$(BUILDDIR)/test_port_tables: test_port_tables.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||
|
||||
$(BUILDDIR)/test_tick_gate: test_tick_gate.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
$(BUILDDIR)/test_page_json: test_page_json.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||
|
||||
# httpd/httpd.c and uip/uip.c are compiled UNMODIFIED from the firmware tree;
|
||||
# this test carries the environment below them itself.
|
||||
$(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||
|
||||
run: $(TESTS)
|
||||
@fail=0; for t in $(TESTS); do \
|
||||
echo "=== $$t ==="; \
|
||||
$$t || fail=1; \
|
||||
echo; \
|
||||
done; \
|
||||
if [ $$fail -ne 0 ]; then echo "TESTS FAILED"; exit 1; else echo "ALL TESTS PASSED"; fi
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
.PHONY: all run clean
|
||||
@@ -0,0 +1,62 @@
|
||||
# Host unit-test harness
|
||||
|
||||
Compile and test individual firmware translation units on the build host with
|
||||
**gcc + AddressSanitizer + UBSan** — no SDCC, no flashing, no hardware. This is
|
||||
the fast inner loop for the logic-level bugs in `../../NOTES/08-findings.md`
|
||||
(parser, line editor, HTTP header, DHCP): edit → `make` → see red/green in
|
||||
seconds instead of a minutes-long flash-and-reboot cycle.
|
||||
|
||||
## Run
|
||||
```
|
||||
cd test
|
||||
make # build + run all tests (ASan/UBSan on)
|
||||
make clean
|
||||
```
|
||||
Exit status is non-zero if any check fails, a sanitizer trips, or the watchdog
|
||||
fires — so it drops straight into CI.
|
||||
|
||||
## How it works
|
||||
- **`sdcc_shim.h`** (force-included) erases SDCC 8051 keywords (`__xdata`,
|
||||
`__code`, `__banked`, …) so firmware sources compile under host gcc. It changes
|
||||
no logic — the code under test is byte-for-byte the firmware source.
|
||||
- **`hw_mock.c` / `hw_mock.h`** simulate the ASIC edge: a flat register file
|
||||
behind `reg_read`/`reg_write` and the `SFR_DATA_*` registers, with a table
|
||||
engine that performs a VLAN or L2 operation the moment `TBL_CTRL` is written,
|
||||
fetches a MIB counter on `STAT_GET` and drops entries on `L2_TBL_FLUSH_CTRL`.
|
||||
Nothing ever reports busy, so a polling loop runs once. The header states the
|
||||
VLAN and L2 entry layouts independently of the firmware, so a test can hold
|
||||
what `rtl837x_port.c` writes against what `page_impl.c` reads.
|
||||
- **`env_tables.c`** carries the globals and leaf calls those two modules link
|
||||
against; **`stub/`** stands in for the two headers only a firmware build
|
||||
generates, so the harness needs no SDCC build first.
|
||||
- **`support.c` / `support.h`** mock the hardware edges: the 16-byte serial ring
|
||||
(`sbuf`), the command/history buffers, and the character-output sink
|
||||
(`write_char` etc.). Buffers are sized **exactly** as on target, so ASan
|
||||
redzones catch the same off-by-one overflows the 8051 hits.
|
||||
- Builds define **`RTLP_HOST_TEST`**, which hides the firmware's libc-named
|
||||
prototypes (`memset`/`strlen`/…) in `rtl837x_common.h` so they don't clash with
|
||||
glibc. Argument order matches libc, so on-host callers transparently use the C
|
||||
library. This guard is compiled out of normal firmware builds — zero on-target
|
||||
effect.
|
||||
- A **SIGALRM watchdog** (`watchdog_arm`) turns an infinite-loop bug into a fast
|
||||
test failure instead of a hung runner.
|
||||
|
||||
## Current coverage
|
||||
| Test binary | TU under test | Findings exercised |
|
||||
|-------------|---------------|--------------------|
|
||||
| `test_cmd_editor` | `cmd_editor.c` | **C4** — full-line hang + `cmd_buffer` 1-byte overflow; basic entry & backspace regressions |
|
||||
| `test_port_tables` | `rtl837x_port.c` | VLAN entry layout and round trip, PVID register sharing, static multicast and management entries, per-port flush, trunk membership and hash seed |
|
||||
| `test_page_json` | `httpd/page_impl.c` + `rtl837x_port.c` | `/vlan.json`, `/vlanlist`, `/l2.json` (walk, wrap marker, paging inside `outbuf`), 64-bit counters in `/status.json` and `/counters.json` |
|
||||
| `test_httpd_tx` | `httpd/httpd.c` + `uip/uip.c` | a GET of a static file against a client that moves its receive window: ACK accounting, continuation chunks out of flash, retransmission |
|
||||
|
||||
## Adding a test for another module
|
||||
1. Write `test_<module>.c` with `main()` driving the module's entry points and
|
||||
`CHECK(cond, msg)` assertions.
|
||||
2. Add any missing mocked symbols to `support.c` (only what the linker asks for).
|
||||
3. Add a target in the `Makefile` listing `test_<module>.c support.c ../<module>.c`.
|
||||
4. If the module calls a firmware libc-name (`memcpy`/`strcpy`/…), it will use the
|
||||
C library on host (compatible arg order); provide a `fw_*`-style mock only if
|
||||
the semantics differ in a way the test cares about.
|
||||
|
||||
Good next targets (pure logic, high finding density): `cmd_parser.c` (C6/C8),
|
||||
the HTTP header parser in `httpd/httpd.c` (S1), `dhcp.c` (S5).
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* env_tables.c - what rtl837x_port.c and httpd/page_impl.c link against
|
||||
* besides the register mock: the console, the buffers page_impl writes into,
|
||||
* the machine description and leaf calls into subsystems not under test.
|
||||
* Buffers keep their firmware sizes so AddressSanitizer sees the same bounds
|
||||
* the 8051 has.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "machine.h"
|
||||
#include "uip.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "syslog.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "support.h"
|
||||
|
||||
/* ---- console: everything lands in out_buf (support.c) ---- */
|
||||
void print_byte(uint8_t v)
|
||||
{
|
||||
static const char h[] = "0123456789abcdef";
|
||||
write_char(h[(v >> 4) & 0xf]);
|
||||
write_char(h[v & 0xf]);
|
||||
}
|
||||
void print_short(uint16_t v) { print_byte(v >> 8); print_byte(v); }
|
||||
void print_long(uint32_t v) { print_short(v >> 16); print_short(v); }
|
||||
void print_reg(uint16_t v) { print_short(v); }
|
||||
void itoa_short(uint16_t v)
|
||||
{
|
||||
char b[6]; int n = 0;
|
||||
do { b[n++] = '0' + v % 10; v /= 10; } while (v);
|
||||
while (n) write_char(b[--n]);
|
||||
}
|
||||
void dbg_string(char *p) { (void)p; }
|
||||
void dbg_short(uint16_t v) { (void)v; }
|
||||
void dbg_char(char c) { (void)c; }
|
||||
void dbg_byte(uint8_t v) { (void)v; }
|
||||
|
||||
/* ---- copied verbatim from rtlplayground.c ---- */
|
||||
uint16_t strtox(uint8_t *dst, const char *s)
|
||||
{
|
||||
uint8_t *b = dst;
|
||||
while (*s)
|
||||
*dst++ = *s++;
|
||||
*dst = 0;
|
||||
return dst - b;
|
||||
}
|
||||
|
||||
const uint16_t bit_mask[16] = {
|
||||
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
||||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
||||
};
|
||||
const uint8_t hex_chars[] = "0123456789abcdef";
|
||||
uint8_t *hex = (uint8_t *)hex_chars;
|
||||
|
||||
/* ---- a 9-port RTL8373 whose logical ports map to themselves ---- */
|
||||
const struct machine machine = {
|
||||
.machine_name = "HOSTTEST",
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 0,
|
||||
.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 },
|
||||
};
|
||||
struct machine_runtime machine_detected = { .isRTL8373 = 1 };
|
||||
|
||||
/* ---- firmware state the modules read or write ---- */
|
||||
uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
uint16_t slen;
|
||||
uint16_t management_vlan = 1;
|
||||
uint16_t cont_len;
|
||||
uint32_t cont_addr;
|
||||
uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
uint16_t vlan_ptr;
|
||||
uint8_t sfp_pins_last = 0xff;
|
||||
uint8_t sfp_options[2];
|
||||
char sfp_module_vendor[2][17];
|
||||
char sfp_module_model[2][17];
|
||||
char sfp_module_serial[2][17];
|
||||
char hostname[24] = "hosttest";
|
||||
char port_names[9][PORT_NAME_SIZE];
|
||||
struct flash_region_t flash_region;
|
||||
struct syslog_state syslog_state;
|
||||
bool stp_enabled;
|
||||
bool lldp_enabled;
|
||||
uint16_t lldp_logical_port_status;
|
||||
|
||||
|
||||
uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||
struct uip_eth_addr uip_ethaddr = { .addr = { 0x02, 0x11, 0x22, 0x33, 0x44, 0x55 } };
|
||||
|
||||
/* ---- leaf calls into subsystems not under test ---- */
|
||||
void flash_read_bulk(uint8_t *dst) { (void)dst; }
|
||||
const char *get_flash_size_str(void) { return "2M"; }
|
||||
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg) { (void)slot; (void)reg; return 0; }
|
||||
bool gpio_pin_test(uint8_t pin) { (void)pin; return false; }
|
||||
void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg) { (void)phy_id; (void)dev_id; (void)reg; }
|
||||
void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t val) { (void)phy_id; (void)dev_id; (void)reg; (void)val; }
|
||||
void phy_reset(uint8_t port) { (void)port; }
|
||||
uint8_t stp_port_role(uint8_t port) { (void)port; return 0; }
|
||||
uint8_t stp_port_state(uint8_t port) { (void)port; return 3; }
|
||||
|
||||
/* ---- STP state send_stp() prints; the tree is not under test here ---- */
|
||||
#include "rtl837x_stp.h"
|
||||
struct bridge root_bridge;
|
||||
struct bridge stp_dbridge[STP_ENTITIES];
|
||||
uint16_t stp_bpdu_age[STP_ENTITIES];
|
||||
uint16_t stp_dpid[STP_ENTITIES];
|
||||
uint16_t stp_lag_mask[STP_LAG_COUNT];
|
||||
uint16_t stp_tc_count;
|
||||
uint32_t root_bridge_cost;
|
||||
uint32_t stp_dcost[STP_ENTITIES];
|
||||
uint32_t stp_pcost[STP_ENTITIES];
|
||||
uint8_t stp_ent_of[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
uint8_t stp_fwddelay_s = 15, stp_hello_s = 2, stp_maxage_s = 20;
|
||||
uint8_t stp_pflags[STP_ENTITIES];
|
||||
uint8_t stp_pp2p[STP_ENTITIES];
|
||||
uint8_t stp_pprio[STP_ENTITIES];
|
||||
uint8_t stp_prio = 0x80, stp_root_port = 0xff, stp_rstp = 1, stp_txhold = 6;
|
||||
|
||||
/* ---- SFP: no module present, reads fail ---- */
|
||||
uint8_t sfp_buf[16];
|
||||
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) { (void)slot; (void)reg; (void)len; return false; }
|
||||
void print_phys_port(uint8_t port) { itoa_short(machine.log_to_phys_port[port]); }
|
||||