Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
787d593996 | ||
|
|
db2a541e5f | ||
|
|
5c5dcb5209 | ||
|
|
be6d47a3ab | ||
|
|
4ff009dbfc | ||
|
|
0c339e9123 | ||
|
|
75151e0b00 | ||
|
|
43845b911b | ||
|
|
0ed45e0710 | ||
|
|
5e30f8e6c0 | ||
|
|
7f3c91ac0c | ||
|
|
3853a2701d | ||
|
|
00a5f81871 | ||
|
|
53d865059d | ||
|
|
b90aedd8f2 | ||
|
|
6b190eb9f3 | ||
|
|
fae16dabf5 | ||
|
|
52692d05b1 | ||
|
|
d364bd69e4 | ||
|
|
70ab7ff769 | ||
|
|
e30976be76 | ||
|
|
1a55a134c7 | ||
|
|
23f0ba995c | ||
|
|
22a09bd06a | ||
|
|
930a08ec52 | ||
|
|
1701d4dc53 | ||
|
|
1e19a9abe2 | ||
|
|
1098e73337 | ||
|
|
99b0fc4b32 | ||
|
|
10d472d8a6 | ||
|
|
6254f44001 | ||
|
|
c435838376 | ||
|
|
3f7db7e430 | ||
|
|
f98fe32d0c | ||
|
|
d2e8ee0e41 | ||
|
|
a9a455e447 | ||
|
|
3f26bf7348 | ||
|
|
ac302d4a67 | ||
|
|
409bc58e17 | ||
|
|
fbcec2cb5a | ||
|
|
ccb90ed16f | ||
|
|
4389cfcd8b | ||
|
|
5e901fb5c2 | ||
|
|
2974e4b66a | ||
|
|
108ac9b8fc | ||
|
|
de3eca26c3 | ||
|
|
8164166465 | ||
|
|
87fe1e77ae | ||
|
|
a753f6f02e | ||
|
|
c86d4b31f2 | ||
|
|
3c89b22207 | ||
|
|
bebe79c4c9 | ||
|
|
adb0b54691 | ||
|
|
b99436543a | ||
|
|
1194823cd5 | ||
|
|
94716ceb5d | ||
|
|
13120127df | ||
|
|
46037cd54d | ||
|
|
e6cd362a1e | ||
|
|
f21b3a32bd | ||
|
|
35941dd19f | ||
|
|
0f257d38df | ||
|
|
912e68d6eb | ||
|
|
c473646389 | ||
|
|
51cf40d040 | ||
|
|
3fd9cdfa7e | ||
|
|
3189820ba0 | ||
|
|
ed74ec1e97 | ||
|
|
dd95a05487 | ||
|
|
481c02c740 | ||
|
|
0a31a65477 | ||
|
|
2d176b7ccc | ||
|
|
a1fac63710 | ||
|
|
5c7f82e2fe | ||
|
|
e765d17c2b | ||
|
|
8fb9afb955 | ||
|
|
e96780fadb | ||
|
|
2221f0fa32 | ||
|
|
f86b8f32de | ||
|
|
9389db9e9b | ||
|
|
519c3a8df3 | ||
|
|
64422367d5 | ||
|
|
dc2b03e331 | ||
|
|
fcf1b3c310 | ||
|
|
1dd6156a1f | ||
|
|
e75a4c2a95 | ||
|
|
05d8c36afe | ||
|
|
b6c9eaf00f | ||
|
|
ecf5f47960 | ||
|
|
ebf6ed7526 | ||
|
|
96f2c860fc | ||
|
|
b80d46955c | ||
|
|
0a18c64dcc | ||
|
|
b53c56e7f6 | ||
|
|
17d41b53b7 | ||
|
|
bd98cb0312 | ||
|
|
5566d71522 | ||
|
|
5e1396cc42 | ||
|
|
7fe0678c92 | ||
|
|
7ec25a39a2 | ||
|
|
98e3cde2f5 | ||
|
|
d90c02f951 | ||
|
|
bbb92c86db | ||
|
|
1635236a05 | ||
|
|
5e3a280b5c | ||
|
|
a56e2a419b | ||
|
|
9c01227572 | ||
|
|
6d37a47481 | ||
|
|
87b9e59cdb | ||
|
|
0e86b84efa | ||
|
|
bd595b7f94 | ||
|
|
06d4a3504a | ||
|
|
d68534e833 | ||
|
|
e0356bd751 | ||
|
|
4b770a8abc | ||
|
|
709436ca13 | ||
|
|
28856ef495 | ||
|
|
113bb654aa | ||
|
|
efc1883685 | ||
|
|
72921ba3be | ||
|
|
70be673fca | ||
|
|
bf5205258e | ||
|
|
98ddb0bb29 | ||
|
|
d152f89549 | ||
|
|
c61e94527e | ||
|
|
f76ccaf3d8 | ||
|
|
ebc6cd06ad | ||
|
|
017aaf71d6 | ||
|
|
4eaf16f96d | ||
|
|
718745e7b5 | ||
|
|
06ee1ce38e | ||
|
|
f122402bdd | ||
|
|
842d68af97 | ||
|
|
bfd1ce9183 | ||
|
|
4ed6575a87 | ||
|
|
1b1c656404 | ||
|
|
018eab9810 | ||
|
|
ec36658ab9 | ||
|
|
eeded0f788 | ||
|
|
8f3b738e59 | ||
|
|
62065875e3 | ||
|
|
e7f70a724b | ||
|
|
d7a7bdac7e | ||
|
|
94e34a5991 | ||
|
|
b58b1dfb35 | ||
|
|
592b903305 | ||
|
|
4ca5b4e87a | ||
|
|
5a8a8ed91b | ||
|
|
ad64e450e1 | ||
|
|
cfeffc434d | ||
|
|
8670709b6e | ||
|
|
1a457c29ac | ||
|
|
ce496ab25f | ||
|
|
964ef2da7a | ||
|
|
8c61010a84 | ||
|
|
053dbe286e | ||
|
|
e68e5cef46 | ||
|
|
b5543b6aeb | ||
|
|
a51fcf1478 | ||
|
|
247cb4dd2f | ||
|
|
394fc99485 | ||
|
|
cf0707475d | ||
|
|
73b99b2f08 | ||
|
|
005eaa3248 | ||
|
|
98f1e9443a | ||
|
|
4c2be334d5 | ||
|
|
073cc1e4a4 | ||
|
|
ba919280ac | ||
|
|
dcc60c3824 | ||
|
|
caad366b3b | ||
|
|
ce0ee859d6 | ||
|
|
a369e46fe6 | ||
|
|
defb37c06a | ||
|
|
a5f77e4caf | ||
|
|
1311cb9ea9 | ||
|
|
7d0d8525d2 | ||
|
|
201289990b | ||
|
|
3a93ce1786 | ||
|
|
4b42be8cae | ||
|
|
32f9b91def | ||
|
|
21f33abfa7 | ||
|
|
d253c9feee | ||
|
|
2552f586d8 | ||
|
|
f113b2c0e5 | ||
|
|
2d912d80c9 | ||
|
|
0682df3027 | ||
|
|
4b40efafbb | ||
|
|
02992771ad | ||
|
|
f81c497728 | ||
|
|
b46cc2087f | ||
|
|
3904daced7 | ||
|
|
623247da4f | ||
|
|
aa5368cf34 | ||
|
|
2b39d723c7 | ||
|
|
f6cb1152f9 | ||
|
|
bf9fa35338 | ||
|
|
8ab2a6a9da | ||
|
|
2316ffd493 | ||
|
|
a71eb57702 | ||
|
|
a2b2dbcfbf | ||
|
|
8cee16e96b | ||
|
|
a1135863bb | ||
|
|
ede4137101 | ||
|
|
0106f99ee0 | ||
|
|
733348059d | ||
|
|
950b763d69 | ||
|
|
22aaa9fbfe | ||
|
|
89e22f0893 | ||
|
|
809efaa8d8 | ||
|
|
271878a62f | ||
|
|
299b54f2a3 | ||
|
|
f47fec7098 | ||
|
|
04ce2cb8a1 | ||
|
|
96eddf5a0c | ||
|
|
2cd6f5d782 | ||
|
|
c6dc5cc21c | ||
|
|
502033590e | ||
|
|
f81529bd07 | ||
|
|
9714818b1f | ||
|
|
9c668969d4 | ||
|
|
241bcb273f | ||
|
|
10367d0cdb | ||
|
|
09d90d6d97 | ||
|
|
12c98ba6bd | ||
|
|
3f66a18104 | ||
|
|
8abbececd1 | ||
|
|
d6dbf4e4dd | ||
|
|
e2b3201c9f | ||
|
|
a7f4543698 | ||
|
|
2e0e55967c | ||
|
|
7877ce60f3 | ||
|
|
a3dd25e0fe | ||
|
|
441340a4d4 | ||
|
|
9a3f8c359d | ||
|
|
63ab6500c0 | ||
|
|
ec5f74bbed | ||
|
|
a597d2d08b | ||
|
|
abc9cb7afd | ||
|
|
6d579c4f00 | ||
|
|
c342964327 | ||
|
|
fd3a272255 | ||
|
|
4f4f69ecc1 | ||
|
|
c8e21b394b | ||
|
|
c34249b90a | ||
|
|
042f4324a4 | ||
|
|
e280ccd2f9 | ||
|
|
baa4e5e142 | ||
|
|
b53e7e1a06 | ||
|
|
14b45735e2 | ||
|
|
946e80cebe | ||
|
|
e2df95ba90 | ||
|
|
570ee6c995 | ||
|
|
e849af4a70 | ||
|
|
812bf3bb67 | ||
|
|
da8ec8fe88 | ||
|
|
01fa43510e | ||
|
|
d2e79d4d80 | ||
|
|
016061d8db | ||
|
|
f7989cc737 | ||
|
|
5035366551 | ||
|
|
2a8f183e6a | ||
|
|
18225f5d22 | ||
|
|
224471d676 | ||
|
|
50d06c61bc | ||
|
|
d5709bcaf3 | ||
|
|
52d943d5e4 | ||
|
|
e79e90dd35 | ||
|
|
da768171a5 | ||
|
|
94bf4425ba | ||
|
|
3e599f0e06 | ||
|
|
6c6d11ab33 | ||
|
|
791f68582d | ||
|
|
facc4afe40 | ||
|
|
8134ca7ec7 | ||
|
|
642030c7b2 | ||
|
|
8324edc5f7 | ||
|
|
f2ff7d7737 | ||
|
|
a24b63a81f | ||
|
|
abe3513bc6 | ||
|
|
49c43082a3 | ||
|
|
f71e869b97 | ||
|
|
1fe236246a | ||
|
|
2acf2499d1 | ||
|
|
56e0d0a5d1 | ||
|
|
7380aeb10d | ||
|
|
0d698dc572 | ||
|
|
c7fb354f08 | ||
|
|
2cdab5f9d9 | ||
|
|
301577efc8 | ||
|
|
1156f00f95 | ||
|
|
8cbafaa347 | ||
|
|
80ff1b25c9 | ||
|
|
1a5208110c | ||
|
|
e2717ef7ca | ||
|
|
1769528420 | ||
|
|
9d4c06d752 | ||
|
|
2565aeadf4 | ||
|
|
c3530aaafc | ||
|
|
6af19e1e6b | ||
|
|
1683eef94b | ||
|
|
036d9ca229 | ||
|
|
b31179acbe | ||
|
|
b7ad67d336 | ||
|
|
e130777b24 | ||
|
|
41f0dad49d | ||
|
|
2e48415c95 | ||
|
|
22f8b9a287 | ||
|
|
c91177d992 | ||
|
|
c1a414833d | ||
|
|
2a9c7d2828 | ||
|
|
d776118815 | ||
|
|
f7b8aed2f7 | ||
|
|
7eb3676aaf | ||
|
|
eaa21d5975 | ||
|
|
193eacf51b | ||
|
|
b60811b984 | ||
|
|
b85861347b | ||
|
|
b21bfac917 | ||
|
|
d4d12fe3b4 | ||
|
|
4440bcc43a | ||
|
|
f6a5163f33 | ||
|
|
e210f31f0e | ||
|
|
9eecdd071a | ||
|
|
c4368c68be | ||
|
|
1b02f303b2 | ||
|
|
fd9a7717ce | ||
|
|
29ce05b70e | ||
|
|
97ae6bf1d3 | ||
|
|
4ccb988d70 | ||
|
|
075d7e43f7 | ||
|
|
97e73d95aa | ||
|
|
2eb6bac4a5 | ||
|
|
7d4ccf8f23 | ||
|
|
c0f6b8a1a6 | ||
|
|
f3b6c16161 | ||
|
|
73f92f2e12 | ||
|
|
bfab8cbba3 | ||
|
|
eedb0dec01 | ||
|
|
08ad843c56 | ||
|
|
05693f5171 | ||
|
|
6eaa1985aa | ||
|
|
45ba32f65d | ||
|
|
0b4f59483b | ||
|
|
385c850d2f | ||
|
|
cdbc48f2c2 | ||
|
|
efe0c282ba | ||
|
|
54fced05b0 | ||
|
|
b64dfd8c25 | ||
|
|
5f1cd4cce0 | ||
|
|
7ffd0c25c2 | ||
|
|
8b4e09ad69 | ||
|
|
34d53dddf2 | ||
|
|
ec5f655bba | ||
|
|
7291f38e46 | ||
|
|
c3b99fdcdf | ||
|
|
9f800bae01 | ||
|
|
df498b0879 | ||
|
|
03422463e4 | ||
|
|
2bfbe5358b | ||
|
|
3bb89bfb80 | ||
|
|
dba3679e2f | ||
|
|
f331a6129a | ||
|
|
877e5a68fb | ||
|
|
ed6c95e522 | ||
|
|
cb8d0e45bb | ||
|
|
877b16e837 | ||
|
|
fce64ac368 | ||
|
|
dd9e5c8ff8 | ||
|
|
f7fcf0eda7 | ||
|
|
905cf38f1f | ||
|
|
b0370f7bb3 | ||
|
|
d21d269d49 | ||
|
|
cb81f82cf6 | ||
|
|
59e7a21955 | ||
|
|
c530ec4ae3 | ||
|
|
8e2b48ef25 | ||
|
|
65f094c1d1 | ||
|
|
090283d538 | ||
|
|
7e3a0f5d8f | ||
|
|
4706f6232a | ||
|
|
b47a868db3 | ||
|
|
454eb28bce | ||
|
|
dc283bc724 | ||
|
|
a001cd3da7 | ||
|
|
e92b4a2358 | ||
|
|
47c5443f0e | ||
|
|
baa3e7edb7 | ||
|
|
34d46aa29a | ||
|
|
6b64534f40 | ||
|
|
b18ed62042 | ||
|
|
16edc6b421 | ||
|
|
f1e5b7e31a | ||
|
|
1f6e07a1af | ||
|
|
0952676504 | ||
|
|
95cbc1a2e0 | ||
|
|
d5fdaf28e8 | ||
|
|
511d35f63d | ||
|
|
96484bc62a | ||
|
|
765000ce4f | ||
|
|
dc9b211924 | ||
|
|
b559c3b868 | ||
|
|
13fe354da7 | ||
|
|
fc4b12725c | ||
|
|
0a52386e60 | ||
|
|
4b167151a5 | ||
|
|
f474b5822b | ||
|
|
fa37940075 | ||
|
|
893dcd8fcf | ||
|
|
16f4e2a1c6 | ||
|
|
364d538abd | ||
|
|
4cef63200f | ||
|
|
a0313eab87 |
@@ -0,0 +1,19 @@
|
|||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
.github/
|
||||||
|
output/
|
||||||
|
installer/output/
|
||||||
|
*.bin
|
||||||
|
html_data.c
|
||||||
|
html_data.h
|
||||||
|
*.o
|
||||||
|
*.rel
|
||||||
|
*.lst
|
||||||
|
*.sym
|
||||||
|
*.asm
|
||||||
|
*.ihx
|
||||||
|
*.img
|
||||||
|
*.map
|
||||||
|
*.mem
|
||||||
|
*.lk
|
||||||
@@ -17,5 +17,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
apt update
|
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 -y
|
||||||
|
- name: Check if machine.c can be compiled for all machines
|
||||||
|
run: make machine_check
|
||||||
- name: Make project
|
- name: Make project
|
||||||
run: make MACHINE="KP_9000_6XHML_X2"
|
run: make MACHINE="KP_9000_6XHML_X2"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
FROM debian:13-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
make \
|
||||||
|
gcc \
|
||||||
|
sdcc \
|
||||||
|
xxd \
|
||||||
|
python3 \
|
||||||
|
libjson-c-dev \
|
||||||
|
golang-go \
|
||||||
|
git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# git safe.directory for mounted repos (Makefile uses git describe)
|
||||||
|
RUN git config --global --add safe.directory /workspace
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
CMD ["bash"]
|
||||||
@@ -4,40 +4,98 @@ DEFAULT_CONFIG_LOCATION = 454656
|
|||||||
CONFIG_LOCATION = 458752
|
CONFIG_LOCATION = 458752
|
||||||
HTML_LOCATION = 262144
|
HTML_LOCATION = 262144
|
||||||
|
|
||||||
|
ifeq ($(origin CC),default)
|
||||||
CC = sdcc
|
CC = sdcc
|
||||||
|
endif
|
||||||
CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip
|
CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip
|
||||||
ASM = sdas8051
|
ASM ?= sdas8051
|
||||||
AFLAGS= -plosgff
|
AFLAGS= -plosgff
|
||||||
|
|
||||||
SUBDIRS := tools uip httpd
|
SUBDIRS := tools
|
||||||
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
|
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
|
||||||
|
|
||||||
BUILDDIR = output/
|
|
||||||
VERSION_HEADER := version.h
|
|
||||||
|
|
||||||
ifeq ($(MACHINE),)
|
ifeq ($(MACHINE),)
|
||||||
|
MACHINE:= $(shell grep "^\s*#define MACHINE_" machine.h | sed "s/^\s*#define MACHINE_//")
|
||||||
else
|
else
|
||||||
CC_FLAGS += -DMACHINE_$(MACHINE)
|
CC_FLAGS += -DMACHINE_$(MACHINE)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)rtlplayground.bin
|
BUILDDIR = output/$(MACHINE)
|
||||||
|
VERSION_HEADER := version.h
|
||||||
|
|
||||||
|
GIT_VERSION := $(shell git rev-parse --short HEAD)
|
||||||
|
ifeq ($(shell git status --porcelain --untracked-files=no),)
|
||||||
|
else
|
||||||
|
GIT_VERSION := $(GIT_VERSION)-dirty
|
||||||
|
endif
|
||||||
|
|
||||||
|
VERSION_EXTENSION = v$(VERSION)-$(GIT_VERSION)
|
||||||
|
FILENAME_EXTENSION = $(VERSION_EXTENSION)-$(MACHINE)
|
||||||
|
|
||||||
|
# Deterministic build date: honor SOURCE_DATE_EPOCH, else the HEAD commit date,
|
||||||
|
# else wall-clock (no-git fallback). Keeps same-commit builds byte-identical
|
||||||
|
# (BUILD_DATE is baked into the image and covered by the trailing CRC).
|
||||||
|
SOURCE_DATE_EPOCH ?= $(shell git show -s --format=%ct HEAD 2>/dev/null)
|
||||||
|
ifeq ($(SOURCE_DATE_EPOCH),)
|
||||||
|
BUILD_DATE := $(shell date +"%Y-%m-%d %H:%M:%S")
|
||||||
|
else
|
||||||
|
BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/dev/null \
|
||||||
|
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
|
||||||
|
|
||||||
create_build_dir:
|
create_build_dir:
|
||||||
mkdir -p $(BUILDDIR)
|
mkdir -p "$(BUILDDIR)"
|
||||||
|
mkdir -p "$(BUILDDIR)/uip"
|
||||||
|
mkdir -p "$(BUILDDIR)/httpd"
|
||||||
|
|
||||||
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c \
|
# Keep machine.c in first position to fail immediately on invalid $MACHINE value
|
||||||
rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c cmd_editor.c rtl837x_bandwidth.c
|
SRCS = \
|
||||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
machine.c \
|
||||||
OBJS += uip/$(BUILDDIR)/timer.rel uip/$(BUILDDIR)/uip-fw.rel uip/$(BUILDDIR)/uip-split.rel uip/$(BUILDDIR)/uip.rel uip/$(BUILDDIR)/uip_arp.rel uip/$(BUILDDIR)/uiplib.rel httpd/$(BUILDDIR)/httpd.rel httpd/$(BUILDDIR)/page_impl.rel
|
cmd_editor.c \
|
||||||
|
cmd_parser.c \
|
||||||
|
dhcp.c \
|
||||||
|
html_data.c \
|
||||||
|
rtlplayground.c \
|
||||||
|
syslog.c \
|
||||||
|
udp_apps.c
|
||||||
|
|
||||||
html_data.c html_data.h: html tools
|
# RTL837x
|
||||||
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
|
SRCS += \
|
||||||
|
rtl837x_bandwidth.c \
|
||||||
|
rtl837x_flash.c \
|
||||||
|
rtl837x_igmp.c \
|
||||||
|
rtl837x_init.c \
|
||||||
|
rtl837x_leds.c \
|
||||||
|
rtl837x_phy.c \
|
||||||
|
rtl837x_pins.c\
|
||||||
|
rtl837x_port.c \
|
||||||
|
rtl837x_stp.c
|
||||||
|
SRCS += \
|
||||||
|
httpd/httpd.c \
|
||||||
|
httpd/page_impl.c
|
||||||
|
SRCS += \
|
||||||
|
uip/timer.c \
|
||||||
|
uip/uip.c \
|
||||||
|
uip/uiplib.c \
|
||||||
|
uip/uip_arp.c \
|
||||||
|
uip/uip-fw.c \
|
||||||
|
uip/uip-neighbor.c \
|
||||||
|
uip/uip-split.c
|
||||||
|
|
||||||
|
OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel}
|
||||||
|
DEPS := ${SRCS:%.c=$(BUILDDIR)/%.d}
|
||||||
|
HTML := $(shell find $(html) -name '*.js' -or -name '*.html' -or -name '*.svg')
|
||||||
|
|
||||||
|
html_data.c html_data.h: $(HTML) tools/output/fileadder
|
||||||
|
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
|
||||||
|
|
||||||
$(VERSION_HEADER):
|
$(VERSION_HEADER):
|
||||||
@echo "#ifndef VERSION_H" > $(VERSION_HEADER)
|
@echo "#ifndef VERSION_H" > $(VERSION_HEADER)
|
||||||
@echo "#define VERSION_H" >> $(VERSION_HEADER)
|
@echo "#define VERSION_H" >> $(VERSION_HEADER)
|
||||||
@echo "#define VERSION_SW \"v$(VERSION)-g$(shell git rev-parse --short HEAD)\"" >> $(VERSION_HEADER)
|
@echo "#define VERSION_SW \"$(VERSION_EXTENSION)\"" >> $(VERSION_HEADER)
|
||||||
@echo "#define BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
|
@echo "#define BUILD_DATE \"$(BUILD_DATE)\"" >> $(VERSION_HEADER)
|
||||||
@echo "#endif" >> $(VERSION_HEADER)
|
@echo "#endif" >> $(VERSION_HEADER)
|
||||||
|
|
||||||
httpd: html_data.h
|
httpd: html_data.h
|
||||||
@@ -46,37 +104,46 @@ $(SUBDIRS):
|
|||||||
$(MAKE) -C $@
|
$(MAKE) -C $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-make -C uip clean
|
-rm -f html_data.c html_data.h $(VERSION_HEADER)
|
||||||
-make -C httpd clean
|
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
|
||||||
-rm html_data.c html_data.h $(VERSION_HEADER)
|
|
||||||
-rm -r $(BUILDDIR)
|
|
||||||
|
|
||||||
$(BUILDDIR)crtstart.rel: crtstart.asm
|
distclean:
|
||||||
$(ASM) $(AFLAGS) -o $@ $<
|
-rm -f html_data.c html_data.h $(VERSION_HEADER)
|
||||||
|
-rm -rf $(BUILDDIR)
|
||||||
|
|
||||||
$(BUILDDIR)crc16.rel: crc16.asm
|
$(BUILDDIR)/%.rel: %.c
|
||||||
$(ASM) $(AFLAGS) -o $@ $<
|
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||||
|
|
||||||
$(BUILDDIR)%.rel: %.c
|
$(BUILDDIR)/%.rel: %.asm
|
||||||
$(CC) $(CC_FLAGS) -o $@ -c $<
|
|
||||||
|
|
||||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
|
||||||
${ASM} ${AFLAGS} -o $@ $<
|
${ASM} ${AFLAGS} -o $@ $<
|
||||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||||
|
|
||||||
$(BUILDDIR)rtlplayground.ihx: $(OBJS) $(BUILDDIR)crtstart.rel $(BUILDDIR)crc16.rel
|
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtstart.rel $(BUILDDIR)/crc16.rel
|
||||||
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
|
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
|
||||||
|
|
||||||
$(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx
|
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||||
objcopy --input-target=ihex -O binary $< $@
|
objcopy --input-target=ihex -O binary $< $@
|
||||||
|
|
||||||
$(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlplayground.img
|
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img
|
||||||
if [ -e $@ ]; then rm $@; fi
|
if [ -e $@ ]; then rm $@; fi
|
||||||
tools/$(BUILDDIR)imagebuilder -i $^ $@
|
tools/output/imagebuilder -i $^ $@
|
||||||
tools/$(BUILDDIR)fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||||
tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||||
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@
|
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data -b BANK1 $@
|
||||||
tools/$(BUILDDIR)crc_calculator -u $@
|
tools/output/crc_calculator -u $@
|
||||||
|
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
|
||||||
|
|
||||||
|
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER)
|
||||||
|
|
||||||
.PHONY: clean all $(SUBDIRS)
|
.PHONY:
|
||||||
|
machine_check:
|
||||||
|
@mkdir -p $(BUILDDIR)/tmp
|
||||||
|
@set -eo pipefail; \
|
||||||
|
for MACHINE in `grep -e ' MACHINE_' machine.c | sed -e 's%^.* MACHINE_%%' -e 's%[ ]*//.*$$%%' | sort -u`; \
|
||||||
|
do \
|
||||||
|
echo "Checking $${MACHINE}"; \
|
||||||
|
$(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine.c; \
|
||||||
|
done
|
||||||
|
@rm -rf $(BUILDDIR)/tmp
|
||||||
|
|
||||||
|
-include $(DEPS)
|
||||||
|
|||||||
@@ -52,88 +52,192 @@ devices by looking at the image using e.g. Ghidra. If you want to contribute to
|
|||||||
design of the web-interface or get a feeling for the interface first, a standalone
|
design of the web-interface or get a feeling for the interface first, a standalone
|
||||||
device simulator is provided, which runs entirely under Linux as a local webserver.
|
device simulator is provided, which runs entirely under Linux as a local webserver.
|
||||||
|
|
||||||
## Compiling
|
## (0) Compiling Requirements
|
||||||
|
|
||||||
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
|
Install the following particular build requisites (Debian 12/13), 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:
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>If using Docker (click to expand)</summary>
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Install Docker for your platform:
|
||||||
|
|
||||||
|
- **Linux (Debian/Ubuntu)**: `sudo apt install docker.io` then `sudo usermod -aG docker $USER` (log out and back in)
|
||||||
|
- **Linux (other distros)**: Follow the [Docker Engine install guide](https://docs.docker.com/engine/install/)
|
||||||
|
- **Windows**: Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/)
|
||||||
|
- **macOS**: Install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
A Dockerfile is provided for a reproducible build environment:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t rtlplayground-dev .
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the firmware (replace MACHINE with your target, e.g. `DEFAULT_8C_1SFP`):
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --rm -v $(pwd):/workspace rtlplayground-dev make MACHINE=DEFAULT_8C_1SFP
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting `.bin` file appears in `output/` on your host.
|
||||||
|
|
||||||
|
Build host tools only:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --rm -v $(pwd):/workspace rtlplayground-dev make -C tools
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the web-interface simulator locally:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --rm -p 8080:8080 -v $(pwd):/workspace rtlplayground-dev \
|
||||||
|
tools/output/httpd_sim /workspace/html
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `machine.h` or `config.txt` on your host, then re-run `make` — the
|
||||||
|
source directory is mounted into the container, so changes take effect
|
||||||
|
immediately. To build for a different machine, pass `MACHINE=...`.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device
|
||||||
|
|
||||||
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
|
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> You can write configuration parameters in config.txt (see below) in order your switch to get
|
||||||
|
> straight at the first boot, a correct IP configuration.
|
||||||
|
|
||||||
Now, building the firmware image should work:
|
Now, building the firmware image should work:
|
||||||
```
|
```
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
Note, that the image generated ends in .bin, not .img, in order to make
|
Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy.
|
||||||
IMSProg happy.
|
|
||||||
|
image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin`
|
||||||
|
for example
|
||||||
|
```
|
||||||
|
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
|
||||||
|
|
||||||
|
## (2) Compiling for OEM running device with management options (web upgrade)
|
||||||
|
|
||||||
|
Managed switches can be updated from the existing original firmware using a SPECIFIC upgrade image.
|
||||||
|
You first need to build the firmware for direct chip flashing : See below (1)
|
||||||
|
|
||||||
|
Then
|
||||||
|
|
||||||
|
```
|
||||||
|
cd installer
|
||||||
|
make
|
||||||
|
```
|
||||||
|
image location is stored in `RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin`
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> This image must ONLY be used for original OEM firmware web interface firmware upgrade.
|
||||||
|
> You do not need this image if you are already on RTLplayground firmware.
|
||||||
|
> Unless you go back to the original OEM firmware, you would only flash this specific firmware
|
||||||
|
> only once. Future upgrades of RTLPlayground will only need to follow (1)
|
||||||
|
|
||||||
|
example of compilation console output
|
||||||
|
|
||||||
Managed switches can be updated from the existing original firmware using an upgrade image.
|
|
||||||
In the `installer`folder of the source code you will need to run `make` which will build
|
|
||||||
an image out of `rtlplayground.bin` built in the previous step:
|
|
||||||
```
|
```
|
||||||
RTLPlayground/installer$ make
|
RTLPlayground/installer$ make
|
||||||
mkdir -p output/
|
mkdir -p output
|
||||||
gcc updatebuilder.c -o output/updatebuilder
|
gcc updatebuilder.c -o output/updatebuilder
|
||||||
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
|
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
|
||||||
sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
|
sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
|
||||||
sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
|
sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
|
||||||
cp ../output//rtlplayground.bin output/
|
./output/updatebuilder -i output/rtlinstaller.ihx -o output/rtlplayground_oem_upgrade.bin ../output/rtlplayground.bin
|
||||||
./output//updatebuilder -i output/rtlinstaller.ihx output/rtlplayground.bin
|
|
||||||
Input file size: 524288
|
Input file size: 524288
|
||||||
Bytes read: 524288
|
Bytes read: 524288
|
||||||
EOF
|
EOF
|
||||||
Payload sum 1 is: 0x29d10
|
Payload sum 1 is: 0x25100
|
||||||
Payload sum 2 is: 0x29d10
|
Payload sum 2 is: 0x25100
|
||||||
Payload sum with header is: 0x2b0fc
|
Payload sum with header is: 0x264ec
|
||||||
Payload sum is: 0xad8a75
|
Payload sum is: 0xf8fe94
|
||||||
Header checksum is: 0x4c3
|
Header checksum is: 0x5a1
|
||||||
```
|
```
|
||||||
The resulting image can be found in `RTLPlayground/installer/output/rtlplayground.bin`
|
|
||||||
> [!CAUTION]
|
|
||||||
> DO NOT UPLOAD THE UPGADE IMAGE UNLESS YOU CAN MAKE A BACKUP USING A SOIC CLAMP OF THE
|
|
||||||
> ORIGINAL FIRMWARE!
|
|
||||||
|
|
||||||
## Installation
|
## (3) Sandbox Usage with Ghidra (optional)
|
||||||
|
|
||||||
You can play with the image using ghidra or flash real Switch Hardware. For
|
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](ghidra.md).
|
||||||
|
|
||||||
|
## (4) Installation through the Web interface (software way)
|
||||||
|
|
||||||
|
Managed switches (OEM firmware of RTLplaygroud 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.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
|
||||||
|
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
|
> Check one more time that your device matches the machine type before flashing.
|
||||||
> ABSOLUTELY NO GUARANTY CAN BE GIVEN THAT YOU WILL NOT DESTROY YOUR SWITCH,
|
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung.
|
||||||
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
|
|
||||||
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
|
|
||||||
|
|
||||||
You can upload the upgrade image of managed switches via the web interface of the
|
Finally, push the Upload File Button and you're done !
|
||||||
original firmware just as if you were installing a firmware upgrade. However,
|
|
||||||
this is strongly discouraged, as you may brick your device, unless you can make
|
|
||||||
firmware backups via a SOIC clamp or soldered flash socket, first!
|
|
||||||
|
|
||||||
For unmanaged devices, the only way to install RTLPlayground is by flashing the
|
|
||||||
Flash memory directly.
|
|
||||||
|
|
||||||
You will need to open your switch to flash the image directly onto the flash chip,
|
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
|
||||||
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
|
|
||||||
flash chip and install a SOIC adapter):
|
|
||||||
- Disconnect power from switch
|
|
||||||
- Attach the clip onto the flash chip
|
|
||||||
- Connect USB of flash programmer, the power LED on the switch will light
|
|
||||||
up, check cabling if not. Don't panic, mixing up GND and 3.3V does not
|
|
||||||
seem to destroy the switch (at leasts the on I did this to).
|
|
||||||
- Use IMSProg (flashrom should work, too) to detect the clip
|
|
||||||
- MAKE A BACKUP OF THE EXISTING FIRMWARE!
|
|
||||||
- then load the firmware into IMSProg
|
|
||||||
- and program flash
|
|
||||||
|
|
||||||
Now you can connect a serial cable to the UART port found on all the
|
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
|
||||||
devices, set 8N1 @ 115200 baud and power up the switch.
|
This is also the only way to unbrick your device if something went wroong.
|
||||||
|
|
||||||
The device will perform some examples and provide a minimal console, the
|
> [!IMPORTANT]
|
||||||
documentation of which can be found in the source code rtlplayground.c`.
|
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
|
||||||
|
> Alternatively you can de-solder the flash chip and install a SOIC adapter).
|
||||||
|
> For flashing the chip directly, you must use the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
|
||||||
|
|
||||||
## The web-interface
|
> [!CAUTION]
|
||||||
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247).
|
> As you need to open your switch case, consider that the warranty is gone.
|
||||||
The default password is `1234`.
|
|
||||||
|
- Disconnect power from switch.
|
||||||
|
- Open the switch.
|
||||||
|
- Attach the clip onto the flash chip (Red line on Pin 1, Pin 1 has a point marker).
|
||||||
|
- Connect USB of flash programmer, the power LED on the switch will light up, check cabling if not.
|
||||||
|
- Don't panic, mixing up GND and 3.3V usually does not destroy the switch.
|
||||||
|
- Use IMSProg, Flashrom, or whatever Programmer to detect the chip.
|
||||||
|
- MAKE A BACKUP (DUMP) OF THE EXISTING FIRMWARE !
|
||||||
|
- ERASE THE ROM (BLANK) !
|
||||||
|
- Load the firmware into IMSProg.
|
||||||
|
- Flash is to the ROM chip.
|
||||||
|
- Disconect the clip from the ROM chip.
|
||||||
|
- You're done, ready for the first boot.
|
||||||
|
|
||||||
|
## (6) Connecting a serial interface (optional)
|
||||||
|
|
||||||
|
You can connect a serial cable to the UART port found on all the devices, set 8N1 @ 115200 baud.
|
||||||
|
|
||||||
|
## (7) Power Up
|
||||||
|
|
||||||
|
When you power up the switch, the device will perform some examples and provide a minimal console
|
||||||
|
(if wired to a serial interface), the documentation of which can be found in the source code rtlplayground.c`.
|
||||||
|
|
||||||
|
## (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.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> The default password is `1234`.
|
||||||
|
|
||||||
|
## (9) The command line
|
||||||
|
|
||||||
## The command line
|
|
||||||
The command line is very rudimentary and mostly for testing purposes.
|
The command line is very rudimentary and mostly for testing purposes.
|
||||||
The following is a boot-log with some examples:
|
The following is a boot-log with some examples:
|
||||||
```
|
```
|
||||||
@@ -198,7 +302,6 @@ PORT 04 1G
|
|||||||
<MODULE INSERTED> Rate: 67 Encoding: 01
|
<MODULE INSERTED> Rate: 67 Encoding: 01
|
||||||
Lightron Inc. WSPXG-ES3LC-IHA 0000
|
Lightron Inc. WSPXG-ES3LC-IHA 0000
|
||||||
|
|
||||||
|
|
||||||
> stat
|
> stat
|
||||||
CMD: stat
|
CMD: stat
|
||||||
Port State Link TxGood TxBad RxGood RxBad
|
Port State Link TxGood TxBad RxGood RxBad
|
||||||
@@ -216,17 +319,40 @@ Lightron Inc. WSPXG-ES3LC-IHA 0000
|
|||||||
CMD: sfp
|
CMD: sfp
|
||||||
Rate: 67 Encoding: 01
|
Rate: 67 Encoding: 01
|
||||||
Lightron Inc. WSPXG-ES3LC-IHA 0000
|
Lightron Inc. WSPXG-ES3LC-IHA 0000
|
||||||
|
```
|
||||||
|
|
||||||
|
## (10) Advanced configuration
|
||||||
|
|
||||||
|
You can configure more deeply the switch without the need of the console mode.
|
||||||
|
|
||||||
|
While in compilation part, you might write directly to config.txt file before making the binary firmware
|
||||||
|
|
||||||
```
|
```
|
||||||
|
nano config.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
|
||||||
|
|
||||||
|
<img width="1085" height="646" 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
|
||||||
|
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
|
||||||
|
```
|
||||||
|
[To be continue]
|
||||||
|
|
||||||
Enjoy playing!
|
Enjoy playing!
|
||||||
|
|
||||||
## Other documents
|
## (11) Other documents
|
||||||
The following documents give further documentation on specific features of
|
|
||||||
the RTL837x SoCs:
|
The following documents give further documentation on specific features of the RTL837x SoCs:
|
||||||
- [RTL8372/3 Feature support](doc/hardware.md)
|
- [RTL8372/3 Feature support](doc/hardware.md)
|
||||||
- [CPU Port](doc/CpuPort.md)
|
- [CPU Port](doc/CpuPort.md)
|
||||||
- [L2 learning](doc/l2.md)
|
- [L2 learning](doc/l2.md)
|
||||||
- [CPU Port](doc/CpuPort.md)
|
|
||||||
- [IGMP (IP-MC streaming)](doc/igmp.md)
|
- [IGMP (IP-MC streaming)](doc/igmp.md)
|
||||||
- [SFP+ ports](doc/sfp.md)
|
- [SFP+ ports](doc/sfp.md)
|
||||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
- [Trunking aka. port aggregation](doc/trunking.md)
|
||||||
|
|||||||
@@ -40,8 +40,10 @@ void cmd_edit(void) __banked
|
|||||||
{
|
{
|
||||||
while (l != sbuf_ptr) {
|
while (l != sbuf_ptr) {
|
||||||
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
|
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
|
||||||
if (cmd_line_len >= CMD_BUF_SIZE)
|
// Reserve one byte for the terminating NUL written on Enter. When the
|
||||||
continue;
|
// line is full, drop the character but still fall through to advance the
|
||||||
|
// serial-ring read pointer below; a 'continue' here would spin forever.
|
||||||
|
if (cmd_line_len < CMD_BUF_SIZE - 1) {
|
||||||
write_char(sbuf[l]);
|
write_char(sbuf[l]);
|
||||||
// Shift buffer to right
|
// Shift buffer to right
|
||||||
for (uint8_t i = cmd_line_len; i > cursor; i--)
|
for (uint8_t i = cmd_line_len; i > cursor; i--)
|
||||||
@@ -55,6 +57,7 @@ void cmd_edit(void) __banked
|
|||||||
// Move backwards
|
// Move backwards
|
||||||
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||||
write_char('\010'); // BS works like cursor-left
|
write_char('\010'); // BS works like cursor-left
|
||||||
|
}
|
||||||
} else if (sbuf[l] == '\033') { // ESC-Sequence
|
} else if (sbuf[l] == '\033') { // ESC-Sequence
|
||||||
// Wait until we have at least 3 characters including the ESC character in the serial buffer
|
// Wait until we have at least 3 characters including the ESC character in the serial buffer
|
||||||
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
|
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
|
||||||
@@ -169,7 +172,7 @@ void cmd_edit(void) __banked
|
|||||||
} else { // An unknown or not yet complete Escape sequence: wait
|
} else { // An unknown or not yet complete Escape sequence: wait
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (sbuf[l] == 127) { // Backspace
|
} else if (sbuf[l] == 127 || sbuf[l] == 8) { // Backspace DEL or BS/^H
|
||||||
if (cursor > 0) {
|
if (cursor > 0) {
|
||||||
write_char('\010');
|
write_char('\010');
|
||||||
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||||
@@ -197,7 +200,7 @@ void cmd_edit(void) __banked
|
|||||||
if (cmd_line_len)
|
if (cmd_line_len)
|
||||||
cmd_available = 1;
|
cmd_available = 1;
|
||||||
else
|
else
|
||||||
print_string("\n> ");
|
print_cmd_prompt();
|
||||||
cursor = 0;
|
cursor = 0;
|
||||||
cmd_line_len = 0;
|
cmd_line_len = 0;
|
||||||
history_editptr = 0xffff;
|
history_editptr = 0xffff;
|
||||||
|
|||||||
@@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||||
extern __xdata uint8_t cmd_available;
|
extern __xdata uint8_t cmd_available;
|
||||||
|
extern __xdata uint8_t err_status;
|
||||||
|
|
||||||
uint8_t cmd_tokenize(void) __banked;
|
void cmd_tokenize(void) __banked;
|
||||||
void cmd_parser(void) __banked;
|
void cmd_parser(void) __banked;
|
||||||
void execute_config(void) __banked;
|
void execute_config(void) __banked;
|
||||||
|
void execute_commands(__xdata uint8_t *p) __banked;
|
||||||
void print_sw_version(void) __banked;
|
void print_sw_version(void) __banked;
|
||||||
void clear_command_history(void) __banked;
|
void clear_command_history(void) __banked;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
__xdata struct dhcp_state dhcp_state;
|
__xdata struct dhcp_state dhcp_state;
|
||||||
__xdata uip_ipaddr_t server;
|
__xdata uip_ipaddr_t server;
|
||||||
|
|
||||||
#define BOOTP_REQUEST 1
|
|
||||||
#define BOOTP_REPY 2
|
|
||||||
|
|
||||||
#define DHCP_HW_TYPE_ETH 1
|
#define DHCP_HW_TYPE_ETH 1
|
||||||
|
|
||||||
#define DHCP_SUBNET_MASK 1
|
#define DHCP_SUBNET_MASK 1
|
||||||
@@ -35,7 +32,6 @@ __xdata uip_ipaddr_t server;
|
|||||||
#define DHCP_MESSAGE_DISCOVER 1
|
#define DHCP_MESSAGE_DISCOVER 1
|
||||||
#define DHCP_MESSAGE_OFFER 2
|
#define DHCP_MESSAGE_OFFER 2
|
||||||
#define DHCP_MESSAGE_REQUEST 3
|
#define DHCP_MESSAGE_REQUEST 3
|
||||||
#define DHCP_MESSAGE_NACK 4
|
|
||||||
#define DHCP_MESSAGE_ACK 5
|
#define DHCP_MESSAGE_ACK 5
|
||||||
#define DHCP_LEASE 51
|
#define DHCP_LEASE 51
|
||||||
#define DHCP_LEASE_LEN 4
|
#define DHCP_LEASE_LEN 4
|
||||||
@@ -45,25 +41,18 @@ __xdata uip_ipaddr_t server;
|
|||||||
#define DHCP_REBIND_LEN 4
|
#define DHCP_REBIND_LEN 4
|
||||||
#define DHCP_CLIENT_ID 61
|
#define DHCP_CLIENT_ID 61
|
||||||
#define DHCP_CLIENT_ID_LEN 7
|
#define DHCP_CLIENT_ID_LEN 7
|
||||||
|
#define DHCP_HOSTNAME 12
|
||||||
#define DHCP_REQUEST_IP 50
|
#define DHCP_REQUEST_IP 50
|
||||||
#define DHCP_REQUEST_IP_LEN 4
|
#define DHCP_REQUEST_IP_LEN 4
|
||||||
#define DHCP_CLIENT_NAME 12
|
|
||||||
#define DHCP_PARAMS 55
|
#define DHCP_PARAMS 55
|
||||||
#define DHCP_VENDOR_ID 60
|
|
||||||
#define DHCP_CLIENT_ID 61
|
|
||||||
#define DHCP_PARAM_SUBNET 1
|
#define DHCP_PARAM_SUBNET 1
|
||||||
#define DHCP_PARAM_ROUTER 3
|
#define DHCP_PARAM_ROUTER 3
|
||||||
#define DHCP_PARAM_DNS 6
|
#define DHCP_PARAM_DNS 6
|
||||||
#define DHCP_END 255
|
#define DHCP_END 255
|
||||||
|
|
||||||
#define LEASE_TIME 43200
|
|
||||||
#define RENEWAL_TIME 21600
|
|
||||||
#define REBIND_TIME 21600
|
|
||||||
|
|
||||||
#pragma codeseg BANK2
|
#pragma codeseg BANK2
|
||||||
#pragma constseg BANK2
|
#pragma constseg BANK2
|
||||||
|
|
||||||
|
|
||||||
struct dhcp_pkt {
|
struct dhcp_pkt {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t hw;
|
uint8_t hw;
|
||||||
@@ -87,11 +76,9 @@ struct dhcp_pkt {
|
|||||||
#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt))
|
#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt))
|
||||||
|
|
||||||
__xdata uint32_t long_value;
|
__xdata uint32_t long_value;
|
||||||
__xdata struct dhcpd_cstate cstates[DHCPD_MAX_CLIENTS];
|
|
||||||
__xdata uint8_t client_idx;
|
|
||||||
__xdata uint16_t dhcpd_vlan;
|
|
||||||
|
|
||||||
void dhcp_print_ip(uint8_t *a)
|
|
||||||
|
void dhcp_print_ip(__xdata uint8_t *a)
|
||||||
{
|
{
|
||||||
itoa(a[0]); write_char('.');
|
itoa(a[0]); write_char('.');
|
||||||
itoa(a[1]); write_char('.');
|
itoa(a[1]); write_char('.');
|
||||||
@@ -100,14 +87,14 @@ void dhcp_print_ip(uint8_t *a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcp_prepare_msg(void)
|
void dhcp_prepare_request(void)
|
||||||
{
|
{
|
||||||
DHCP_P->type = BOOTP_REQUEST;
|
DHCP_P->type = 1;
|
||||||
DHCP_P->hw = DHCP_HW_TYPE_ETH;
|
DHCP_P->hw = DHCP_HW_TYPE_ETH;
|
||||||
DHCP_P->hw_len = 6;
|
DHCP_P->hw_len = 6;
|
||||||
DHCP_P->hops = 0;
|
DHCP_P->hops = 0;
|
||||||
|
|
||||||
DHCP_P->tid = dhcp_state.transaction_id; // In network byte order
|
DHCP_P->tid = HTONS(dhcp_state.transaction_id);
|
||||||
DHCP_P->delay = HTONS(0);
|
DHCP_P->delay = HTONS(0);
|
||||||
DHCP_P->flags = 0;
|
DHCP_P->flags = 0;
|
||||||
// Clear fields client_ip to bootp_file
|
// Clear fields client_ip to bootp_file
|
||||||
@@ -130,6 +117,20 @@ void dhcp_addopt_client_id(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_addopt_hostname(void)
|
||||||
|
{
|
||||||
|
uint8_t len = 0;
|
||||||
|
while (hostname[len])
|
||||||
|
len++;
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HOSTNAME;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = len;
|
||||||
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], hostname, len);
|
||||||
|
dhcp_state.opt_ptr += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcp_addopt_request_ip(void)
|
void dhcp_addopt_request_ip(void)
|
||||||
{
|
{
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
|
||||||
@@ -138,6 +139,7 @@ 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[1];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
||||||
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -149,68 +151,14 @@ 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[1];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
||||||
}
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||||
|
|
||||||
|
|
||||||
void dhcp_addopt_subnet(void)
|
|
||||||
{
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SUBNET_MASK;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SUBNET_MASK_LEN;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[0];
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[1];
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[2];
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dhcp_addopt_router(void)
|
|
||||||
{
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_ROUTER;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_ROUTER_LEN;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[0];
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[1];
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[2];
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dhcp_addopt_lease(void)
|
|
||||||
{
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_LEASE;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_LEASE_LEN;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = LEASE_TIME >> 8;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = LEASE_TIME & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dhcp_addopt_renewal(void)
|
|
||||||
{
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_RENEWAL;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_RENEWAL_LEN;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = RENEWAL_TIME >> 8;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = RENEWAL_TIME & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dhcp_addopt_rebind(void)
|
|
||||||
{
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REBIND;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REBIND_LEN;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = REBIND_TIME >> 8;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = REBIND_TIME & 0xff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcp_send_discover(void)
|
void dhcp_send_discover(void)
|
||||||
{
|
{
|
||||||
print_string("dhcp_send_discover called\n");
|
print_string("dhcp_send_discover called\n");
|
||||||
dhcp_prepare_msg();
|
dhcp_prepare_request();
|
||||||
|
|
||||||
dhcp_state.opt_ptr = 0;
|
dhcp_state.opt_ptr = 0;
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
|
||||||
@@ -219,6 +167,7 @@ void dhcp_send_discover(void)
|
|||||||
|
|
||||||
dhcp_addopt_client_id();
|
dhcp_addopt_client_id();
|
||||||
dhcp_addopt_request_ip();
|
dhcp_addopt_request_ip();
|
||||||
|
dhcp_addopt_hostname();
|
||||||
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
||||||
@@ -245,7 +194,7 @@ void dhcp_send_discover(void)
|
|||||||
void dhcp_send_request(void)
|
void dhcp_send_request(void)
|
||||||
{
|
{
|
||||||
print_string("dhcp_send_request called\n");
|
print_string("dhcp_send_request called\n");
|
||||||
dhcp_prepare_msg();
|
dhcp_prepare_request();
|
||||||
|
|
||||||
dhcp_state.opt_ptr = 0;
|
dhcp_state.opt_ptr = 0;
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
|
||||||
@@ -255,6 +204,7 @@ void dhcp_send_request(void)
|
|||||||
dhcp_addopt_client_id();
|
dhcp_addopt_client_id();
|
||||||
dhcp_addopt_request_ip();
|
dhcp_addopt_request_ip();
|
||||||
dhcp_addopt_server_id();
|
dhcp_addopt_server_id();
|
||||||
|
dhcp_addopt_hostname();
|
||||||
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
||||||
@@ -278,42 +228,7 @@ void dhcp_send_request(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcp_send_reply(uint8_t rtype)
|
void ip_opt(__xdata uint8_t * ip)
|
||||||
{
|
|
||||||
print_string("dhcp_send_reply called\n");
|
|
||||||
dhcp_prepare_msg();
|
|
||||||
DHCP_P->type = BOOTP_REPY;
|
|
||||||
DHCP_P->client_addr[0] = cstates[client_idx].mac[0]; DHCP_P->client_addr[1] = cstates[client_idx].mac[1];
|
|
||||||
DHCP_P->client_addr[2] = cstates[client_idx].mac[2]; DHCP_P->client_addr[3] = cstates[client_idx].mac[3];
|
|
||||||
DHCP_P->client_addr[4] = cstates[client_idx].mac[4]; DHCP_P->client_addr[5] = cstates[client_idx].mac[5];
|
|
||||||
|
|
||||||
if (rtype != DHCP_MESSAGE_NACK) {
|
|
||||||
DHCP_P->your_ip[0] = dhcp_state.server[0];
|
|
||||||
DHCP_P->your_ip[1] = dhcp_state.server[1];
|
|
||||||
DHCP_P->your_ip[2] = dhcp_state.server[2];
|
|
||||||
DHCP_P->your_ip[3] = DHCPD_START_IP + client_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
dhcp_state.opt_ptr = 0;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE_LEN;
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = rtype;
|
|
||||||
|
|
||||||
if (rtype != DHCP_MESSAGE_NACK) {
|
|
||||||
dhcp_addopt_subnet();
|
|
||||||
dhcp_addopt_router();
|
|
||||||
dhcp_addopt_server_id();
|
|
||||||
dhcp_addopt_rebind();
|
|
||||||
dhcp_addopt_lease();
|
|
||||||
dhcp_addopt_renewal();
|
|
||||||
}
|
|
||||||
|
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_END;
|
|
||||||
uip_udp_send(sizeof(struct dhcp_pkt) + dhcp_state.opt_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ip_opt(uint8_t * __xdata ip)
|
|
||||||
{
|
{
|
||||||
dhcp_state.opt_ptr++;
|
dhcp_state.opt_ptr++;
|
||||||
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
@@ -340,22 +255,6 @@ void long_opt(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void print_txt_opt(void)
|
|
||||||
{
|
|
||||||
dhcp_state.opt_ptr++;
|
|
||||||
for (uint8_t l = DHCP_OPT[dhcp_state.opt_ptr++]; l ; l--)
|
|
||||||
write_char(DHCP_OPT[dhcp_state.opt_ptr++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void print_eth_opt(void)
|
|
||||||
{
|
|
||||||
dhcp_state.opt_ptr++;
|
|
||||||
for (uint8_t l = DHCP_OPT[dhcp_state.opt_ptr++]; l ; l--)
|
|
||||||
print_byte(DHCP_OPT[dhcp_state.opt_ptr++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void parse_opts(void)
|
void parse_opts(void)
|
||||||
{
|
{
|
||||||
while (DHCP_OPT[dhcp_state.opt_ptr] && DHCP_OPT[dhcp_state.opt_ptr] != DHCP_END) {
|
while (DHCP_OPT[dhcp_state.opt_ptr] && DHCP_OPT[dhcp_state.opt_ptr] != DHCP_END) {
|
||||||
@@ -375,9 +274,6 @@ void parse_opts(void)
|
|||||||
case DHCP_BROADCAST:
|
case DHCP_BROADCAST:
|
||||||
ip_opt(&dhcp_state.broadcast[0]);
|
ip_opt(&dhcp_state.broadcast[0]);
|
||||||
break;
|
break;
|
||||||
case DHCP_REQUEST_IP:
|
|
||||||
ip_opt(&dhcp_state.current_ip[0]);
|
|
||||||
break;
|
|
||||||
case DHCP_LEASE:
|
case DHCP_LEASE:
|
||||||
long_opt();
|
long_opt();
|
||||||
dhcp_state.lease = long_value;
|
dhcp_state.lease = long_value;
|
||||||
@@ -390,27 +286,6 @@ void parse_opts(void)
|
|||||||
long_opt();
|
long_opt();
|
||||||
dhcp_state.renewal = long_value;
|
dhcp_state.renewal = long_value;
|
||||||
break;
|
break;
|
||||||
case DHCP_CLIENT_NAME:
|
|
||||||
print_string("Client name: ");
|
|
||||||
print_txt_opt();
|
|
||||||
write_char('\n');
|
|
||||||
break;
|
|
||||||
case DHCP_VENDOR_ID:
|
|
||||||
print_string("Vendor ID: ");
|
|
||||||
print_txt_opt();
|
|
||||||
write_char('\n');
|
|
||||||
break;
|
|
||||||
case DHCP_CLIENT_ID:
|
|
||||||
print_string("Client ID: ");
|
|
||||||
print_eth_opt();
|
|
||||||
write_char('\n');
|
|
||||||
break;
|
|
||||||
case DHCP_PARAMS:
|
|
||||||
print_string("PARAMS request (ignored)\n");
|
|
||||||
dhcp_state.opt_ptr++;
|
|
||||||
dhcp_state.opt_ptr += DHCP_OPT[dhcp_state.opt_ptr];
|
|
||||||
dhcp_state.opt_ptr++;
|
|
||||||
break;
|
|
||||||
case DHCP_END:
|
case DHCP_END:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -423,39 +298,9 @@ void parse_opts(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void find_client(void)
|
void parse_dhcp(void)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
if (!DHCP_P->tid == HTONS(dhcp_state.transaction_id))
|
||||||
for (i = 0; i < DHCPD_MAX_CLIENTS; i++) {
|
|
||||||
if (cstates[i].mac[0] == DHCP_P->client_addr[0] && cstates[i].mac[1] == DHCP_P->client_addr[1]
|
|
||||||
&& cstates[i].mac[2] == DHCP_P->client_addr[2] && cstates[i].mac[3] == DHCP_P->client_addr[3]
|
|
||||||
&& cstates[i].mac[4] == DHCP_P->client_addr[4] && cstates[i].mac[5] == DHCP_P->client_addr[5]
|
|
||||||
)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i < DHCPD_MAX_CLIENTS) {
|
|
||||||
client_idx = i;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
client_idx = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void find_slot(void)
|
|
||||||
{
|
|
||||||
for (client_idx = 0; client_idx < DHCPD_MAX_CLIENTS; client_idx++) {
|
|
||||||
if (!cstates[client_idx].cstate)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client_idx = 255;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void parse_dhcp_response(void)
|
|
||||||
{
|
|
||||||
if (!DHCP_P->tid == dhcp_state.transaction_id)
|
|
||||||
return;
|
return;
|
||||||
if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63)
|
if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63)
|
||||||
return;
|
return;
|
||||||
@@ -494,50 +339,13 @@ void parse_dhcp_response(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_dhcp_request(void)
|
|
||||||
{
|
|
||||||
print_string("parse_dhcp_request called\n");
|
|
||||||
if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63)
|
|
||||||
return;
|
|
||||||
|
|
||||||
dhcp_state.opt_ptr = 0;
|
|
||||||
if (DHCP_OPT[dhcp_state.opt_ptr++] != DHCP_MESSAGE_TYPE || DHCP_OPT[dhcp_state.opt_ptr++] != DHCP_MESSAGE_TYPE_LEN)
|
|
||||||
return;
|
|
||||||
if (DHCP_OPT[dhcp_state.opt_ptr] == DHCP_MESSAGE_DISCOVER) {
|
|
||||||
dhcp_state.opt_ptr++;
|
|
||||||
find_client();
|
|
||||||
if (client_idx == 255)
|
|
||||||
find_slot();
|
|
||||||
// If there is no empty slot, we play possum and do not answer to the request
|
|
||||||
if (client_idx == 255)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cstates[client_idx].cstate = CSTATE_OFFERED;
|
|
||||||
cstates[client_idx].mac[0] = DHCP_P->client_addr[0]; cstates[client_idx].mac[1] = DHCP_P->client_addr[1];
|
|
||||||
cstates[client_idx].mac[2] = DHCP_P->client_addr[2]; cstates[client_idx].mac[3] = DHCP_P->client_addr[3];
|
|
||||||
cstates[client_idx].mac[4] = DHCP_P->client_addr[4]; cstates[client_idx].mac[5] = DHCP_P->client_addr[5];
|
|
||||||
dhcp_state.transaction_id = DHCP_P->tid;
|
|
||||||
parse_opts();
|
|
||||||
dhcp_send_reply(DHCP_MESSAGE_OFFER);
|
|
||||||
} else if (DHCP_OPT[dhcp_state.opt_ptr++] == DHCP_MESSAGE_REQUEST) {
|
|
||||||
find_client();
|
|
||||||
if (client_idx == 255) {
|
|
||||||
dhcp_send_reply(DHCP_MESSAGE_NACK);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parse_opts();
|
|
||||||
dhcp_send_reply(DHCP_MESSAGE_ACK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dhcp_start(void) __banked
|
void dhcp_start(void) __banked
|
||||||
{
|
{
|
||||||
uip_ipaddr(server, 255,255,255,255);
|
uip_ipaddr(server, 255,255,255,255);
|
||||||
dhcp_state.conn = uip_udp_new(&server, HTONS(DHCP_SERVER_PORT));
|
dhcp_state.conn = uip_udp_new(&server, HTONS(DHCPC_SERVER_PORT));
|
||||||
dhcp_state.current_ip[0] = dhcp_state.current_ip[1] = dhcp_state.current_ip[2] = dhcp_state.current_ip[3] = 0;
|
dhcp_state.current_ip[0] = dhcp_state.current_ip[1] = dhcp_state.current_ip[2] = dhcp_state.current_ip[3] = 0;
|
||||||
if(dhcp_state.conn) {
|
if(dhcp_state.conn) {
|
||||||
uip_udp_bind(dhcp_state.conn, HTONS(DHCP_CLIENT_PORT));
|
uip_udp_bind(dhcp_state.conn, HTONS(DHCPC_CLIENT_PORT));
|
||||||
} else {
|
} else {
|
||||||
print_string("dhcp_start failed to set up socket\n");
|
print_string("dhcp_start failed to set up socket\n");
|
||||||
return;
|
return;
|
||||||
@@ -549,43 +357,6 @@ void dhcp_start(void) __banked
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcpd_start(void) __banked
|
|
||||||
{
|
|
||||||
memset(&cstates[0], 0, sizeof (struct dhcpd_cstate) * DHCPD_MAX_CLIENTS);
|
|
||||||
dhcp_state.conn = uip_udp_new(0, 0);
|
|
||||||
if(dhcp_state.conn) {
|
|
||||||
uip_udp_bind(dhcp_state.conn, HTONS(DHCP_SERVER_PORT));
|
|
||||||
} else {
|
|
||||||
print_string("dhcpd_start failed to set up socket\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!dhcpd_vlan)
|
|
||||||
print_string("dhcpd: enabling for all VLANs\n");
|
|
||||||
else
|
|
||||||
print_string("dhcpd: enabling for VLAN "); print_short(dhcpd_vlan); write_char('\n');
|
|
||||||
dhcp_state.state = DHCP_SERVER;
|
|
||||||
|
|
||||||
dhcp_state.server[1] = uip_hostaddr[0] >> 8; dhcp_state.server[0] = uip_hostaddr[0] & 0xff;
|
|
||||||
dhcp_state.server[3] = uip_hostaddr[1] >> 8; dhcp_state.server[2] = uip_hostaddr[1] & 0xff;
|
|
||||||
|
|
||||||
dhcp_state.router[1] = uip_draddr[0] >> 8; dhcp_state.router[0] = uip_draddr[0] & 0xff;
|
|
||||||
dhcp_state.router[3] = uip_draddr[1] >> 8; dhcp_state.router[2] = uip_draddr[1] & 0xff;
|
|
||||||
|
|
||||||
dhcp_state.subnet[1] = uip_netmask[0] >> 8; dhcp_state.subnet[0] = uip_netmask[0] & 0xff;
|
|
||||||
dhcp_state.subnet[3] = uip_netmask[1] >> 8; dhcp_state.subnet[2] = uip_netmask[1] & 0xff;
|
|
||||||
|
|
||||||
dhcp_state.broadcast[0] = dhcp_state.router[0]; dhcp_state.broadcast[1] = dhcp_state.router[1];
|
|
||||||
dhcp_state.broadcast[2] = dhcp_state.router[2]; dhcp_state.broadcast[3] = 0xff;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < DHCPD_MAX_CLIENTS; i++) {
|
|
||||||
cstates[i].cstate = CSTATE_NONE;
|
|
||||||
}
|
|
||||||
// TODO: DNS, correct broadcast address
|
|
||||||
|
|
||||||
print_string("dhcpd_start done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dhcp_stop(void) __banked
|
void dhcp_stop(void) __banked
|
||||||
{
|
{
|
||||||
print_string("dhcp_stop called\n");
|
print_string("dhcp_stop called\n");
|
||||||
@@ -593,25 +364,18 @@ void dhcp_stop(void) __banked
|
|||||||
dhcp_state.state = DHCP_OFF;
|
dhcp_state.state = DHCP_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcpd_stop(void) __banked
|
|
||||||
{
|
|
||||||
print_string("dhcpd_stop called\n");
|
|
||||||
uip_udp_remove(dhcp_state.conn);
|
|
||||||
dhcp_state.state = DHCP_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void dhcp_callback(uint16_t lport) __banked
|
||||||
void dhcp_callback(void) __banked
|
|
||||||
{
|
{
|
||||||
|
if (lport != HTONS(DHCPC_CLIENT_PORT)) // Is this call for us? If not, ignore it
|
||||||
|
return;
|
||||||
if (!dhcp_state.state)
|
if (!dhcp_state.state)
|
||||||
return;
|
return;
|
||||||
if (uip_closed()) {
|
if (uip_closed()) {
|
||||||
print_string("Closed\n");
|
print_string("Closed\n");
|
||||||
return;
|
return;
|
||||||
} else if (dhcp_state.state == DHCP_SERVER && uip_newdata()) {
|
|
||||||
parse_dhcp_request();
|
|
||||||
} else if (uip_newdata()) {
|
} else if (uip_newdata()) {
|
||||||
parse_dhcp_response();
|
parse_dhcp();
|
||||||
} else {
|
} else {
|
||||||
if (dhcp_state.state == DHCP_START) {
|
if (dhcp_state.state == DHCP_START) {
|
||||||
dhcp_send_discover();
|
dhcp_send_discover();
|
||||||
@@ -634,4 +398,7 @@ void dhcp_callback(void) __banked
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By default we do not send anything out
|
||||||
|
uip_len = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,21 @@
|
|||||||
|
|
||||||
#include "uipopt.h"
|
#include "uipopt.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#define DHCPD_MAX_CLIENTS 20
|
|
||||||
#define DHCPD_START_IP 100
|
|
||||||
|
|
||||||
#define DHCP_SERVER_PORT 67
|
#define DHCPC_SERVER_PORT 67
|
||||||
#define DHCP_CLIENT_PORT 68
|
#define DHCPC_CLIENT_PORT 68
|
||||||
|
|
||||||
#define DHCP_OFF 0
|
#define DHCP_OFF 0
|
||||||
#define DHCP_START 1
|
#define DHCP_START 1
|
||||||
#define DHCP_DISCOVER_SENT 2
|
#define DHCP_DISCOVER_SENT 2
|
||||||
#define DHCP_REQUEST_SENT 3
|
#define DHCP_REQUEST_SENT 3
|
||||||
#define DHCP_LEASING 4
|
#define DHCP_LEASING 4
|
||||||
#define DHCP_SERVER 5
|
|
||||||
|
|
||||||
#define CSTATE_NONE 0
|
|
||||||
#define CSTATE_OFFERED 1
|
|
||||||
#define CSTATE_LEASED 2
|
|
||||||
|
|
||||||
void dhcp_start(void) __banked;
|
void dhcp_start(void) __banked;
|
||||||
void dhcp_stop(void) __banked;
|
void dhcp_stop(void) __banked;
|
||||||
void dhcp_callback(void) __banked;
|
// void dhcp_periodic(void) __banked;
|
||||||
|
void dhcp_callback(uint16_t lport) __banked;
|
||||||
|
|
||||||
|
|
||||||
struct dhcp_state {
|
struct dhcp_state {
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
@@ -40,26 +35,9 @@ struct dhcp_state {
|
|||||||
uint32_t rebind;
|
uint32_t rebind;
|
||||||
uint32_t renewal;
|
uint32_t renewal;
|
||||||
|
|
||||||
struct uip_udp_conn *conn;
|
__xdata struct uip_udp_conn *conn;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dhcpd_cstate {
|
|
||||||
uint8_t cstate;
|
|
||||||
uint16_t timer;
|
|
||||||
uint32_t transaction_id;
|
|
||||||
uint8_t mac[6];
|
|
||||||
uint8_t ip[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void dhcpd_start(void) __banked;
|
|
||||||
void dhcpd_stop(void) __banked;
|
|
||||||
|
|
||||||
typedef struct dhcp_state uip_udp_appstate_t;
|
typedef struct dhcp_state uip_udp_appstate_t;
|
||||||
|
|
||||||
/* Finally we define the application function to be called by uIP. */
|
|
||||||
#ifndef UIP_UDP_APPCALL
|
|
||||||
#define UIP_UDP_APPCALL dhcp_callback
|
|
||||||
#endif /* UIP_APPCALL */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Automation
|
||||||
|
|
||||||
|
## Upload
|
||||||
|
|
||||||
|
You can automate upload of the firmware via WEB with curl:
|
||||||
|
|
||||||
|
1. Authorize with /login endpoint and save cookie:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -c cookies.txt http://${SWITCH_IP}/login -d pwd=${PASSWORD} -i
|
||||||
|
```
|
||||||
|
|
||||||
|
This will save session cookie in cookies.txt
|
||||||
|
2. Send the firmware via form:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -b cookies.txt http://${SWITCH_IP}/upload -F "uploadedfile=@${FIRMWARE_FILE_PATH}" -i
|
||||||
|
```
|
||||||
|
|
||||||
|
You can expect that server will close connection, without responding to request.
|
||||||
|
Wait for SWITCH_IP to be responding again.
|
||||||
|
|
||||||
|
## Port status
|
||||||
|
|
||||||
|
In similar way to upload, you can fetch the json status of the ports.
|
||||||
|
|
||||||
|
1. Get the session cookie as for upload.
|
||||||
|
2. Hit the `/status.json` with cookie:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -b cookies.txt http://${SWITCH_IP}/status.json
|
||||||
|
```
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
### 2M-PCB23-V2.2
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||||
|
|----------|-----------------|---------|---------------|-------|-------------|
|
||||||
|
| keepLINK | KP-9000-9XHML-X | Yes | 2M-PCB23-V2.2 | 2M | 8373 + 8224 |
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB23-V2.2-managed/2M-PCB23-V2.2-top.jpg" width="300" />
|
||||||
|
|
||||||
|
## Port overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ┌──────────┐ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP(J13) │ │
|
||||||
|
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 9 │ │
|
||||||
|
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ PORT 5 │ │ PORT 6 │ │ PORT 7 │ │ PORT 8 │ │ MAC 8 │ O (PWR) │
|
||||||
|
│ O │ MAC 0 │ │ MAC 1 │ │ MAC 2 │ │ MAC 3 │ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 1 │ O (SFP) │
|
||||||
|
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
# Connectors
|
||||||
|
|
||||||
|
### J13, SFP connector
|
||||||
|
|
||||||
|
| SFP Pin | Signal | GPIO | Notes |
|
||||||
|
| ------- | ----------------- | ------ | ------------------------------ |
|
||||||
|
| 2 | TX_FAULT | ?? | |
|
||||||
|
| 3 | TX_DISABLE | ?? | |
|
||||||
|
| 4 | MODDEF2 – SDA | GPIO39 | |
|
||||||
|
| 5 | MODDEF1 – SCL | GPIO40 | |
|
||||||
|
| 6 | MODDEF0 – PRESENT | GPIO30 | "OE Exist" reported by `fiber` |
|
||||||
|
| 7 | RATE SEL | ?? | |
|
||||||
|
| 8 | LOS | GPIO37 | "OE LOS" reported by `fiber` |
|
||||||
|
| 9 | TO? | ?? | |
|
||||||
|
|
||||||
|
### T5, serial console
|
||||||
|
|
||||||
|
| pin | GPIO | Signal |
|
||||||
|
| --- | ------ | -------------- |
|
||||||
|
| 1 | GPIO32 | U0RXD (Input) |
|
||||||
|
| 2 | GND | Ground |
|
||||||
|
| 3 | GPIO31 | U0TXD (Output) |
|
||||||
|
|
||||||
|
### S1, unknown connector
|
||||||
|
|
||||||
|
| pin | GPIO | Signal |
|
||||||
|
| --- | -------- | -------------- |
|
||||||
|
| 1 | ??? | |
|
||||||
|
| x | | |
|
||||||
|
| 3 | ??? | |
|
||||||
|
| 4 | ??? | |
|
||||||
|
| 5 | ??? | |
|
||||||
|
|
||||||
|
Potentially slave interface or SMI.
|
||||||
|
|
||||||
|
### U7, flash memory
|
||||||
|
|
||||||
|
Flash chip is FM25Q16A.
|
||||||
|
|
||||||
|
### Reset button
|
||||||
|
|
||||||
|
GPIO54
|
||||||
|
|
||||||
|
## Register values
|
||||||
|
|
||||||
|
As probed with `regget` on stock firmware "V1.6".
|
||||||
|
|
||||||
|
### Model
|
||||||
|
|
||||||
|
| Name | Addr | Value |
|
||||||
|
| ------------------------- | ------ | ---------- |
|
||||||
|
| MODEL_NAME_INFO | 0x0004 | 0x83730000 |
|
||||||
|
| CHIP_MODE_INFO | 0x0008 | 0x00008000 |
|
||||||
|
| CHIP_INFO | 0x000C | 0x00300000 |
|
||||||
|
|
||||||
|
### GPIO
|
||||||
|
|
||||||
|
| Name | Addr | Value |
|
||||||
|
| ------------------------- | ------ | ---------- |
|
||||||
|
| GPIO_OUT0 | 0x003c | 0x10000000 |
|
||||||
|
| GPIO_OUT1 | 0x0040 | 0x00000010 |
|
||||||
|
| GPIO_OE0 | 0x004c | 0x10000000 |
|
||||||
|
| GPIO_OE1 | 0x0050 | 0x00000010 |
|
||||||
|
| BOND_INFO | 0x7f60 | 0x00000fff |
|
||||||
|
| STRAP_INFO | 0x7f64 | 0x0002f515 |
|
||||||
|
| IO_DRVING_0 | 0x7f68 | 0x00000000 |
|
||||||
|
| IO_DRVING_1 | 0x7f6c | 0x00000000 |
|
||||||
|
| IO_DRVING_2 | 0x7f70 | 0x00000000 |
|
||||||
|
| IO_SLEW_0 | 0x7f74 | 0x00000000 |
|
||||||
|
| IO_SLEW_1 | 0x7f78 | 0x00000000 |
|
||||||
|
| IO_SLEW_2 | 0x7f7c | 0x00000000 |
|
||||||
|
| IO_SMT_EN_0 | 0x7f80 | 0xffffffff |
|
||||||
|
| IO_SMT_EN_1 | 0x7f84 | 0xffffffff |
|
||||||
|
| IO_SMT_EN_2 | 0x7f88 | 0x0003ffff |
|
||||||
|
| IO_MUX_SEL_0 | 0x7f8c | 0x28000000 |
|
||||||
|
| IO_MUX_SEL_1 | 0x7f90 | 0x40000041 |
|
||||||
|
| IO_MUX_SEL_2 | 0x7f94 | 0x00000000 |
|
||||||
|
|
||||||
|
### LED
|
||||||
|
|
||||||
|
| Name | Addr | Value |
|
||||||
|
| ------------------------- | ------ | ---------- |
|
||||||
|
| LED_GLB_CTRL | 0x6520 | 0x0023e0f0 |
|
||||||
|
| LED3_0_SET3_2_CTRL1 | 0x6524 | 0xff001400 |
|
||||||
|
| LED3_0_SET1_0_CTRL1 | 0x6528 | 0x000f0000 |
|
||||||
|
| LED3_2_SET3_CTRL0 | 0x652c | 0x007f013f |
|
||||||
|
| LED1_0_SET3_CTRL0 | 0x6530 | 0x02000400 |
|
||||||
|
| LED3_2_SET2_CTRL0 | 0x6534 | 0x01400141 |
|
||||||
|
| LED1_0_SET2_CTRL0 | 0x6538 | 0x01440170 |
|
||||||
|
| LED3_2_SET1_CTRL0 | 0x653c | 0x18000041 |
|
||||||
|
| LED1_0_SET1_CTRL0 | 0x6540 | 0x0044017f |
|
||||||
|
| LED3_2_SET0_CTRL0 | 0x6544 | 0x00000044 |
|
||||||
|
| LED1_0_SET0_CTRL0 | 0x6548 | 0x00410175 |
|
||||||
|
| LED_PORT_SET_SEL_CTRL | 0x654c | 0x00010000 |
|
||||||
|
| SW_LED_LOAD | 0x6550 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_EN_CTRL[0..7] | 0x6554 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_EN_CTRL[8] | 0x6558 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[0] | 0x655c | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[1] | 0x6560 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[2] | 0x6564 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[3] | 0x6568 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[4] | 0x656c | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[5] | 0x6570 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[6] | 0x6574 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[7] | 0x6578 | 0x00000000 |
|
||||||
|
| LED_PORT_SW_CTRL[8] | 0x657c | 0x00000000 |
|
||||||
|
| LED_LOAD_LV1_10G | 0x6580 | 0x000fa000 |
|
||||||
|
| LED_LOAD_LV2_10G | 0x6584 | 0x00271000 |
|
||||||
|
| LED_LOAD_LV3_10G | 0x6588 | 0x004e2000 |
|
||||||
|
| LED_LOAD_LV1_5G | 0x658c | 0x000fa000 |
|
||||||
|
| LED_LOAD_LV2_5G | 0x6590 | 0x00271000 |
|
||||||
|
| LED_LOAD_LV3_5G | 0x6594 | 0x004e2000 |
|
||||||
|
| LED_LOAD_LV1_2P5G | 0x6598 | 0x000fa000 |
|
||||||
|
| LED_LOAD_LV2_2P5G | 0x659c | 0x00271000 |
|
||||||
|
| LED_LOAD_LV3_2P5G | 0x65a0 | 0x004e2000 |
|
||||||
|
| LED_LOAD_LV1_1G | 0x65a4 | 0x000fa000 |
|
||||||
|
| LED_LOAD_LV2_1G | 0x65a8 | 0x00271000 |
|
||||||
|
| LED_LOAD_LV3_1G | 0x65ac | 0x004e2000 |
|
||||||
|
| LED_LOAD_LV1_500M | 0x65b0 | 0x0007d000 |
|
||||||
|
| LED_LOAD_LV2_500M | 0x65b4 | 0x00138800 |
|
||||||
|
| LED_LOAD_LV3_500M | 0x65b8 | 0x00271000 |
|
||||||
|
| LED_LOAD_LV1_100M | 0x65bc | 0x00019000 |
|
||||||
|
| LED_LOAD_LV2_100M | 0x65c0 | 0x0003e800 |
|
||||||
|
| LED_LOAD_LV3_100M | 0x65c4 | 0x0007d000 |
|
||||||
|
| LED_LOAD_LV1_10M | 0x65c8 | 0x00002800 |
|
||||||
|
| LED_LOAD_LV2_10M | 0x65cc | 0x00006400 |
|
||||||
|
| LED_LOAD_LV3_10M | 0x65d0 | 0x0000c800 |
|
||||||
|
| LED_P_LOAD_CTRL | 0x65d4 | 0x00000000 |
|
||||||
|
| LED_GLB_ACTIVE | 0x65d8 | 0x3ffbedff |
|
||||||
|
| LED_GLB_IO_EN | 0x65dc | 0x77ffffff |
|
||||||
|
| LED_GLB_MUX_1 | 0c65e0 | 0x05102040 |
|
||||||
|
| LED_GLB_MUX_2 | 0x65e4 | 0x0c289206 |
|
||||||
|
| LED_GLB_MUX_3 | 0x65e8 | 0x1245038d |
|
||||||
|
| LED_GLB_MUX_4 | 0x65ec | 0x19616554 |
|
||||||
|
| LED_GLB_MUX_5 | 0x65f0 | 0x2079d71a |
|
||||||
|
| LED_GLB_MUX_6 | 0x65f4 | 0x000238a1 |
|
||||||
|
| LED_RLDP_CTRL_1 | 0x65f8 | 0x00000019 |
|
||||||
|
| LED_RLDP_CTRL_2 | 0x65fc | 0xffffffff |
|
||||||
|
| LED_RLDP_CTRL_3 | 0x6600 | 0x00006600 |
|
||||||
|
| LED_DUMY_0_ADDR | 0x6604 | 0x00000000 |
|
||||||
|
| LED_DUMY_1_ADDR | 0x6608 | 0x00000000 |
|
||||||
|
|
||||||
|
# LEDs
|
||||||
|
|
||||||
|
| Name | Components | Controlled by |
|
||||||
|
| ----------------------------- | --------------------------- | -------------------------- |
|
||||||
|
| RJ45 Right Green ("LINK/ACT") | | RJ45 LED0 |
|
||||||
|
| RJ45 Left Orange ("2.5G") | | RJ45 LED1 |
|
||||||
|
| RJ45 Left Green ("1G") | | RJ45 LED2 |
|
||||||
|
| "P" (PWR) | Top LED in "LED6" stack | probably pulled from Vcc |
|
||||||
|
| SFP Link ("9") | Bottom LED in "LED6" stack | SFP LED0 |
|
||||||
|
| ?? | D23 | SFP LED1 |
|
||||||
|
| ?? | D22 | SFP LED2 |
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# 2G040210GSM
|
||||||
|
|
||||||
|
The following is a documentation for the managed switch marked as `2G040210GSM`
|
||||||
|
and sold by Mokerlink.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**: 4-port 2.5G Web Managed Switch
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
- **Power**: 12V DC, 1A barrel connector
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- The SFP+ port supports 1G, 2.5G and 10G modules
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware (use KP_9000_6XHML_X2 in machine.h if building yourself or the corresponding pre-compiled binary)
|
||||||
|
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
|
||||||
|
|
||||||
|
### Hardware overview
|
||||||
|
Front
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-front.jpeg" width="300" />
|
||||||
|
|
||||||
|
Label
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-label.jpeg" width="300" />
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: 2M-PCB43-V1.1
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-top.jpeg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-bottom.jpeg" width="300" />
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J8` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | RX (Input) |
|
||||||
|
| 2 | TX (Output) |
|
||||||
|
| 3 | GND |
|
||||||
|
| 4 | 3V3 |
|
||||||
|
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# FG-4GT-2SX_V2.0
|
||||||
|
|
||||||
|
Following is documentation for unmanaged switch marked as `FG-4GT-2SX_V2.0`.
|
||||||
|
|
||||||
|
Original software is running UART on 9600 baud rate.
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|
||||||
|
* Ruiying RY-4GT-2SX
|
||||||
|
|
||||||
|
<img src="photos/FG-4GT-2SX_V2.0/RY-4GT-2SX_label.jpg" width="300" />
|
||||||
|
|
||||||
|
## What works
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- Both SFP ports supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs
|
||||||
|
|
||||||
|
## PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
|
||||||
|
- Top silkscreen: FG-4GT-2SX_V2.0
|
||||||
|
|
||||||
|
Front panel
|
||||||
|
|
||||||
|
<img src="photos/FG-4GT-2SX_V2.0/chassis-front.jpg" width="300" />
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/FG-4GT-2SX_V2.0/PCB-top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/FG-4GT-2SX_V2.0/PCB-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# FOXNEO FNS-1200P
|
||||||
|
|
||||||
|
RTL8372-based 4×2.5G PoE+ + 2×SFP+ unmanaged switch.
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Manufacturer**: FOXNEO
|
||||||
|
- **Model**: FNS-1200P
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps with PoE+
|
||||||
|
- 2 × SFP+: 1G / 2.5G / 10G
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE+ is not configurable via RTLPlayground)
|
||||||
|
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs: amber (2.5G) and green (1G/100M/10M) per copper port; combined link/act on SFP ports
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-K0402W-U13-V2.0 / DIP-K0402WB-V2.0
|
||||||
|
|
||||||
|
**Key components**
|
||||||
|
- U3: SPI NOR flash, 2 MiB
|
||||||
|
- U7: unpopulated SOP8 footprint — I2C bus (RTL8372 slave at 0x5c) is accessible from its pads, useful for register dumps
|
||||||
|
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
|
||||||
|
|
||||||
|
Front panel
|
||||||
|
|
||||||
|
<img src="photos/FNS-1200P/chassis-front.jpg" width="400" />
|
||||||
|
|
||||||
|
Top side (PCB)
|
||||||
|
|
||||||
|
<img src="photos/FNS-1200P/PCB-top.jpg" width="300" />
|
||||||
|
|
||||||
|
### Port layout
|
||||||
|
|
||||||
|
| Front panel position | Logical port | Physical port | Type |
|
||||||
|
|----------------------|--------------|---------------|---------|
|
||||||
|
| SFP left | 8 | 5 | SFP+ |
|
||||||
|
| RJ45 1 | 4 | 1 | Copper |
|
||||||
|
| RJ45 2 | 5 | 2 | Copper |
|
||||||
|
| RJ45 3 | 6 | 3 | Copper |
|
||||||
|
| RJ45 4 | 7 | 4 | Copper |
|
||||||
|
| SFP right | 3 | 6 | SFP+ |
|
||||||
|
|
||||||
|
### Serial console
|
||||||
|
|
||||||
|
The PCB has three unpopulated through-holes intended for a slide switch, directly connected to UART0.
|
||||||
|
Numbered from the left (SFP port side), the pinout is:
|
||||||
|
|
||||||
|
| Position (left→right) | Signal | GPIO |
|
||||||
|
|-----------------------|--------|--------------------------|
|
||||||
|
| 1 (leftmost) | RX | GPIO32\_UART0\_RX (32) |
|
||||||
|
| 2 (middle) | GND | GND |
|
||||||
|
| 3 (rightmost) | TX | GPIO31\_UART0\_TX (31) |
|
||||||
|
|
||||||
|
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
|
||||||
|
- Connect a USB-TTL adapter: adapter TX → pin 1, GND → pin 2, adapter RX → pin 3
|
||||||
|
|
||||||
|
### LED configuration
|
||||||
|
|
||||||
|
Copper ports use LED SET0, SFP ports use LED SET1.
|
||||||
|
|
||||||
|
| SET | LED0 | LED2 |
|
||||||
|
|------|--------------------------------------------------|---------------------------------------------------|
|
||||||
|
| SET0 | Amber — lights on 2.5G link | Green — lights on 1G / 100M / 10M link |
|
||||||
|
| SET1 | All speeds — lights on any link with activity | — |
|
||||||
|
|
||||||
|
LED pad to physical port mapping:
|
||||||
|
|
||||||
|
| GPIO pads | Port |
|
||||||
|
|-----------|-------------------------|
|
||||||
|
| GPIO8–11 | Physical port 5 (left SFP) |
|
||||||
|
| GPIO12–14 | Physical port 1 (RJ45 1) |
|
||||||
|
| GPIO15–17 | Physical port 2 (RJ45 2) |
|
||||||
|
| GPIO18–20 | Physical port 3 (RJ45 3) |
|
||||||
|
| GPIO21–23 | Physical port 4 (RJ45 4) |
|
||||||
|
| GPIO24–27 | Physical port 6 (right SFP) |
|
||||||
|
|
||||||
|
### SFP GPIO assignments
|
||||||
|
|
||||||
|
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|
||||||
|
|------------------|-----------------------------|------------------------|--------|----------------------|--------------------------|
|
||||||
|
| Left (logical 8) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
|
||||||
|
| Right (logical 3)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO51\_I2C\_SDA2\_UART1\_RX | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
|
||||||
|
|
||||||
|
GPIO assignments were verified by observing GPIO state changes during SFP module insertion/removal
|
||||||
|
and cross-checked against an original firmware register dump.
|
||||||
|
`pin_tx_disable` is GPIO\_NA on both ports (original firmware keeps all GPIOs as inputs).
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# Hisource Hi-K0402WS
|
|
||||||
|
|
||||||
Following is documentation for unmanaged switch marked as `Hi-K0402WS`.
|
|
||||||
|
|
||||||
Original software is running UART on 9600 baud rate.
|
|
||||||
|
|
||||||
Using SPI clamp in-board is the only method for initial installation.
|
|
||||||
|
|
||||||
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
|
|
||||||
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
|
|
||||||
|
|
||||||
### Label specifications
|
|
||||||
|
|
||||||
- **Name**: 2.5G Ethernet Switch
|
|
||||||
- **Model**: Hi-K0402WS
|
|
||||||
- **Ports**:
|
|
||||||
- 4 × RJ45: 10/100/1000/2500 Mbps
|
|
||||||
- 2 × SFP: 1000 / 2500 / 10000 Mbps
|
|
||||||
|
|
||||||
### What works (expected from label + similar devices)
|
|
||||||
|
|
||||||
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
|
||||||
- Both SFP ports supporting 1G, 2.5G and 10G modules
|
|
||||||
- LEDs
|
|
||||||
|
|
||||||
### PCB overview
|
|
||||||
|
|
||||||
**Board markings**
|
|
||||||
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
|
|
||||||
|
|
||||||
Top side
|
|
||||||
|
|
||||||
<img src="photos/K0402W-V3.0-unmanaged\PCB-top.jpg" width="300" />
|
|
||||||
|
|
||||||
Bottom
|
|
||||||
|
|
||||||
<img src="photos/K0402W-V3.0-unmanaged\PCB-bottom.jpg" width="300" />
|
|
||||||
|
|
||||||
### T2, serial console
|
|
||||||
|
|
||||||
| `J2` pin | Signal |
|
|
||||||
| -------- | ----------- |
|
|
||||||
| 1 | 3V3 |
|
|
||||||
| 2 | RX (Input) |
|
|
||||||
| 3 | TX (Output) |
|
|
||||||
| 4 | GND |
|
|
||||||
|
|
||||||
|
|
||||||
## Power supply
|
|
||||||
|
|
||||||
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
|
||||||
Board has two supply rails. `0.95` and `3.3` volt.
|
|
||||||
|
|
||||||
### `0.95` Core Voltage
|
|
||||||
|
|
||||||
Voltage is made by a `Techcode TD1720` .
|
|
||||||
|
|
||||||
### `3.3` Voltage
|
|
||||||
|
|
||||||
Voltage is created by chip marked as `Techcode TD1720`.
|
|
||||||
|
|
||||||
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Hisource Hi-K0801WS
|
||||||
|
|
||||||
|
Following is documentation for unmanaged switch marked as `Hi-K0801WS`.
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**: 2.5G Ethernet Switch
|
||||||
|
- **Model**: Hi-K0801WS
|
||||||
|
- **Ports**:
|
||||||
|
- 8 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 1 × SFP: 1000 / 2500 / 10000 Mbps
|
||||||
|
|
||||||
|
### What works (expected from label + similar devices)
|
||||||
|
|
||||||
|
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- SFP port supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-KO801W-V2.0 / DIP-KO801WS-V2.0
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/K0801W-V2.0-unmanaged\PCB-top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/K0801W-V2.0-unmanaged\PCB-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# K0501W V2.0
|
||||||
|
|
||||||
|
This board appears for example in the Davuaz Da-K6501W switch.
|
||||||
|
|
||||||
|
The general design of the board is similar to Hi-K0402WS V3.0.
|
||||||
|
However, there are several differences:
|
||||||
|
- One SFP port is replaced by a RTL8221B 2.5G PHY
|
||||||
|
- Only one LED is populated for the SFP port
|
||||||
|
- No mode switch and only one flash chip
|
||||||
|
- Older design using RTL8372 instead of RTL8372N (which also means different GPIO and LED configuration)
|
||||||
|
- Like earlier versions of the K0402W(S) board, there is no UART
|
||||||
|
|
||||||
|
All ports and LEDs are supported.
|
||||||
|
Installation is possible using a flash programmer.
|
||||||
|
The BoyaMicro 25Q16BSSIG flash chip is supported by flashprog with chip name "B.25D16AS/BY25Q16BS/BY25Q16ES".
|
||||||
|
|
||||||
|
## PCB pictures
|
||||||
|
|
||||||
|
The board is marked `PCB-K0501W-V2.0 DIP-K0501WS-V2.0`.
|
||||||
|
|
||||||
|
<img src="photos/K0501W_V2_0/pcb-top.jpg" width="300" />
|
||||||
|
|
||||||
|
<img src="photos/K0501W_V2_0/pcb-bottom.jpg" width="300" />
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Keeplink KP-9000-6XH-X2
|
||||||
|
|
||||||
|
Following is documentation for unmanaged switch marked as `KP-9000-6XH-X2`.
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**: 4X 2.5G RJ45 Port + 2 X 10G SFP+ Port
|
||||||
|
- **Model**: KP-9000-6XH-X2
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- SFP port with 10G modules
|
||||||
|
- LEDs
|
||||||
|
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
|
||||||
|
|
||||||
|
### Hardware overview
|
||||||
|
|
||||||
|
Front side:
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-front.jpg" width="600" />
|
||||||
|
|
||||||
|
Label:
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-label.jpg" width="600" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: 2M-PCB43-V2.1
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-top.jpg" width="600" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-bottom.jpg" width="600" />
|
||||||
|
|
||||||
|
## Reset Button
|
||||||
|
|
||||||
|
There's an unpopulated Reset button on the front left side of the PCB.
|
||||||
|
It can easily be soldered, you'll need an 4.5mmx4.5mm 90° button switch with a 3-pin footprint.
|
||||||
|
I got mine here: https://de.aliexpress.com/item/1005007295346702.html
|
||||||
|
The front case has already the hole in the metal case, you just have to punch a hole through the foil.
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# PCB-K0402WS-V3.0
|
||||||
|
|
||||||
|
Following is documentation for a variety of unmanaged switch internally marked as `PCB-K0402WS-V3.0`. They are sold under many brands.
|
||||||
|
|
||||||
|
Original software is running UART on 9600 baud rate.
|
||||||
|
|
||||||
|
Note during opening the device: there might be a hidden 5th screw on the back
|
||||||
|
of the device just above the big label, might be covered by a QC sticker.
|
||||||
|
|
||||||
|
### Brands
|
||||||
|
|
||||||
|
* Hisource Hi-K0402WS
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/HiSource_HI-K0402WS.jpg" width="300" />
|
||||||
|
|
||||||
|
* Ztyuav Z-QWYT0402
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402.jpg" width="300" />
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
|
||||||
|
|
||||||
|
### Programming
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
|
||||||
|
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
|
||||||
|
The switch actually controls the HOLD line of each flash chip, and toggling the switch results in a reboot.
|
||||||
|
|
||||||
|
If the programming clip keeps HOLD not connected, the flashing will commence on whatever the switch selected, regardless on which chip was clipped.
|
||||||
|
|
||||||
|
For the initial flash (at least with flashrom), the bin file produced by the build is much smaller than the flash chip, it is suggested to pad the file to keep flashrom happy: `truncate -s 2097152 rtlplayground-*-PCB_K0402WS_V3.bin`. Note: do not then proceed to use this resulting padded file for the web flashing (as it bricks the device), use the original unpadded .bin.
|
||||||
|
|
||||||
|
### What works (expected from label + similar devices)
|
||||||
|
|
||||||
|
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- Both SFP ports supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/PCB-top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/PCB-K0402WS-V3.0/PCB-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### T2, serial console
|
||||||
|
|
||||||
|
| `J2` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | 3V3 |
|
||||||
|
| 2 | RX (Input) |
|
||||||
|
| 3 | TX (Output) |
|
||||||
|
| 4 | GND |
|
||||||
|
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
|
Board has two supply rails. `0.95` and `3.3` volt.
|
||||||
|
|
||||||
|
### `0.95` Core Voltage
|
||||||
|
|
||||||
|
Voltage is made by a `Techcode TD1720` .
|
||||||
|
|
||||||
|
### `3.3` Voltage
|
||||||
|
|
||||||
|
Voltage is created by chip marked as `Techcode TD1720`.
|
||||||
|
|
||||||
|
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Steamemo IG204-V1
|
||||||
|
|
||||||
|
Following is documentation for unmanaged switch marked as `IG204-V1`.
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**: 2.5G Ethernet Switch
|
||||||
|
- **Model**: IG204 V1
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP: 1000 / 2500 / 10000 Mbps
|
||||||
|
|
||||||
|
### What works (expected from label + similar devices)
|
||||||
|
|
||||||
|
- Four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- Two SFP ports supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PB-2131
|
||||||
|
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/STEAMEMO_IG204_V1/PCB-top.jpg" width="600" />
|
||||||
|
|
||||||
|
### Connectors
|
||||||
|
### T7, serial console
|
||||||
|
|
||||||
|
| `T7` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | TX (Output) |
|
||||||
|
| 2 | GND |
|
||||||
|
| 3 | RX (Input) |
|
||||||
|
| 4 | 3V3 |
|
||||||
|
|
||||||
|
### Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
# SWTG018AS-A V2.0
|
# 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 |
|
||||||
|
|
||||||
|
|
||||||
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
|
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
|
||||||
It is e.g. sold under the Ampcom brand, but no branh-markings are found on the device.
|
It is e.g. sold under the Ampcom brand, but no branh-markings are found on the device.
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
### SWTG024AS-A-V2.0.1_4C_2SFP
|
||||||
|
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Horaco | ZX-SG4T2 | | PCB-SWTG024AS-A-V2.0.1_19650 | P25D40SH | ??? |
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**:
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-label.jpg" width="300" />
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- The SFP+ port supports 1G, 2.5G and 10G modules
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-SWTG024AS-A-V2.0.1_19650
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J1` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | 3V3 |
|
||||||
|
| 2 | GND |
|
||||||
|
| 3 | RX (Input) |
|
||||||
|
| 4 | TX (Output) |
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
### SWTG024AS-A-V2.0.1_5C_1SFP
|
||||||
|
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Horaco | HC-SWTGW215AS | | PCB-SWTG024AS-A-V2.0.1_19650 | W25Q16JV | 8272N |
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**:
|
||||||
|
- **Ports**:
|
||||||
|
- 5 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
|
||||||
|
<!-- <img src="" width="300" /> -->
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- The SFP+ port supports 1G, 2.5G and 10G modules
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-SWTG024AS-A-V2.0.1_19650
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<!-- <img src="" width="300" /> -->
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<!-- <img src="" width="300" /> -->
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J1` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | 3V3 |
|
||||||
|
| 2 | GND |
|
||||||
|
| 3 | RX (Input) |
|
||||||
|
| 4 | TX (Output) |
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
### SWTG024AS-V2.0
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| hongyavision | LG-SG5T1 | No | PCB-SWTG024AS-V2.0_16895 | 25Q40 | 8272 |
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**:
|
||||||
|
- **Ports**:
|
||||||
|
- 5 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
- **Power**: 12V DC, 1A 5525 connector
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-V2.0/label.jpg" width="300" />
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- The SFP+ port supports 1G, 2.5G and 10G modules
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware
|
||||||
|
- Online update does not work with 512KiB flash.
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-SWTG024AS-V2.0
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-V2.0/pcb_top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-V2.0/pcb_bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J1` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | GND |
|
||||||
|
| 2 | RX (Input) |
|
||||||
|
| 3 | TX (Output) |
|
||||||
|
|
||||||
|
Note,`R52`、`R53`may not be installed.You need to bridge them using either solder or resistors.
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -9,8 +9,8 @@ Also the RJ45 connectors can be all plastic/non-shielded or with metal shielding
|
|||||||
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|
||||||
|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|
|
||||||
| LIANGUO |SWTG024AS |No| SWTG024AS-v2.0-17452 | CM-23-11-2336 023-17453| 512 KiB | 8272 |
|
| LIANGUO |SWTG024AS |No| SWTG024AS-v2.0-17452 | CM-23-11-2336 023-17453| 512 KiB | 8272 |
|
||||||
| Haraco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 8272 |
|
| Horaco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 8272 |
|
||||||
| Xikestore |SKS3200M-4GPY2XF | Yes | SWTG024AS-v1.0 | CM-23-08-2043 023-16721 | ??? | 8272 |
|
| Xikestore |SKS3200M-4GPY2XF | Yes | SWTG024AS-v1.0 | CM-23-08-2043 023-16721 | 2048 KiB | 8272 |
|
||||||
| Sodola | SL-SWTG124AS-D | Yes | SWTG024AS-v2.0-17452 | ??? | 2048 KiB | 8272 |
|
| Sodola | SL-SWTG124AS-D | Yes | SWTG024AS-v2.0-17452 | ??? | 2048 KiB | 8272 |
|
||||||
|
|
||||||
## PCB
|
## PCB
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
### ZX-SWTGW215AS
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Lianguo | ZX-SWTGW215AS | Yes | PCB-SWTG115AS-V2.0 | FM25Q16A | 8272 |
|
||||||
|
|
||||||
|
## RTLPlayground target
|
||||||
|
|
||||||
|
Use machine target `MACHINE_LIANGUO_ZX_SWTGW215AS` for this device.
|
||||||
|
|
||||||
|
Physical hardware verification: 5x RJ45 ports + 1x SFP port.
|
||||||
|
Port 5 RJ45 is interfaced through a RTL8221B IC.
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
<img src="photos/ZX-SWTGW215AS/pcb_top.jpg" width="300" />
|
||||||
|
|
||||||
|
# Connectors
|
||||||
|
|
||||||
|
## Port overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ┌──────────┐ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP (J4) │ │
|
||||||
|
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 6 │ │
|
||||||
|
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ PORT 5 │ │ LOG 8 │ │
|
||||||
|
│ O │ LOG 4 │ │ LOG 5 │ │ LOG 6 │ │ LOG 7 │ │ LOG 3 │ │ SerDes 1 │ │
|
||||||
|
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
| Type | RTLPlayground logical ports | Physical index |
|
||||||
|
|---|---|---|
|
||||||
|
| RJ45 | 3, 4, 5, 6, 7 | 1-5 |
|
||||||
|
| SFP | 8 | 6 |
|
||||||
|
|
||||||
|
## J4
|
||||||
|
|
||||||
|
* Location: SFP connector `J4`.
|
||||||
|
* Connected to: 10GMAC number 8, SerDes 1.
|
||||||
|
|
||||||
|
|`J4` SFP PINs | Signal | GPIO | Notes |
|
||||||
|
|---|---|---|---|
|
||||||
|
|3| TX_DISABLE | GPIO_NA | Not connected |
|
||||||
|
|4| MODDEF2 – SDA | GPIO39 | I2C SDA |
|
||||||
|
|5| MODDEF1 – SCL | GPIO40 | I2C SCL |
|
||||||
|
|6| MODDEF0 – PRESENT | GPIO30 | Detect |
|
||||||
|
|8| LOS | GPIO37 | RX Loss of Signal |
|
||||||
|
### Notes
|
||||||
|
* Not all signals were mapped mechanically, hence they've been left out of documentation.
|
||||||
|
|
||||||
|
## T3, Slave Interface
|
||||||
|
|
||||||
|
This connector goes to U4 `I2C EEPROM` and U10 `SPI FLASH` (mappings identical to SWTG024AS).
|
||||||
|
|
||||||
|
For detailed Slave Interface functionality and protocol information, see [T3 documentation in SWTG024AS.md](SWTG024AS.md#t3-slave-interface).
|
||||||
|
|
||||||
|
|`T3` pin|what|Signal|
|
||||||
|
|---|---|---|
|
||||||
|
|1| U4-P6, 33R U10-P6 | I2C-SCL, SPI-CLK, Slave SCK/SCL/MDC/EE_SCL |
|
||||||
|
|2| GND | --- |
|
||||||
|
|3| U4-P5, U10-P5 | I2C-SDA, SPI-DI/DO, Slave SDI/SDA/MDIO/EE_SDA |
|
||||||
|
|4| VCC |
|
||||||
|
|5| 33R -> U10-P2 | SPI-DO/D1 |
|
||||||
|
|6| U10-P1 | SPI-CS |
|
||||||
|
### Notes
|
||||||
|
* 1 pin is square shaped.
|
||||||
|
|
||||||
|
|
||||||
|
## T5, Serial Console
|
||||||
|
|
||||||
|
|`T5` pin|GPIO|Signal|
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GPIO31 | U0TXD (Output) |
|
||||||
|
| 2 | GND | |
|
||||||
|
| 3 | GPIO32 | U0RXD (Input) |
|
||||||
|
| 4 | 3V3 | |
|
||||||
|
### Notes
|
||||||
|
* 1 pin is square shaped.
|
||||||
|
|
||||||
|
## T8
|
||||||
|
|
||||||
|
|`T8` pin|GPIO|Signal|
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GPIO46 | |
|
||||||
|
| 2 | GND | |
|
||||||
|
| 3 | GPIO48 | |
|
||||||
|
| 4 | 3V3 | |
|
||||||
|
| 5 | GPIO47 | |
|
||||||
|
| 6 | GPIO49 | |
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
* 1 pin is square shaped.
|
||||||
|
* Mapping unverified but assumed the same as [LIANGUO SWTG024AS](SWTG024AS.md#t8).
|
||||||
|
|
||||||
|
# Reset Circuit
|
||||||
|
| Function | GPIO |
|
||||||
|
|---|---|
|
||||||
|
| Reset button | GPIO54 |
|
||||||
|
### Notes
|
||||||
|
* Circuit is active-low
|
||||||
|
|
||||||
|
# GPIO
|
||||||
|
|
||||||
|
Note: T3/U4/U10-related signal annotations below are copied from [LIANGUO SWTG024AS T3 section](SWTG024AS.md#t3-slave-interface) as well as T8 port from [LIANGUO SWTG024AS T8 section](SWTG024AS.md#t8). They should be treated as assumed identical for ZX-SWTGW215AS as it has not been 100% confirmed true at the moment.
|
||||||
|
|
||||||
|
| HEX VAL. | GPIO | Component / Purpose | Notes | | GPIO | Component / Purpose | Notes |
|
||||||
|
| -------- | ------ | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||||
|
| 00000001 | GPIO00 | | | | GPIO32 | T5-3 | U0RXD |
|
||||||
|
| 00000002 | GPIO01 | | | | GPIO33 | | |
|
||||||
|
| 00000004 | GPIO02 | | | | GPIO34 | | |
|
||||||
|
| 00000008 | GPIO03 | | | | GPIO35 | | |
|
||||||
|
| 00000010 | GPIO04 | | | | GPIO36 | | |
|
||||||
|
| 00000020 | GPIO05 | | | | GPIO37 | J4-8 | SFP LOS |
|
||||||
|
| 00000040 | GPIO06 | | | | GPIO38 | | |
|
||||||
|
| 00000080 | GPIO07 | | | | GPIO39 | J4-4 | SFP I2C SDA |
|
||||||
|
| 00000100 | GPIO08 | | | | GPIO40 | J4-5 | SFP I2C SCL |
|
||||||
|
| 00000200 | GPIO09 | | | | GPIO41 | | |
|
||||||
|
| 00000400 | GPIO10 | | | | GPIO42 | U10-P6, U4-P6, T3-1 | SPI FLASH CLK / I2C-SCL (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00000800 | GPIO11 | | | | GPIO43 | U10-P5, U4-P5, T3-3 | SPI FLASH DI/IO0 / I2C-SDA (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00001000 | GPIO12 | | | | GPIO44 | U10-P2, T3-5 | SPI FLASH DO/IO1 (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00002000 | GPIO13 | PORT1 LED GREEN | | | GPIO45 | U10-P1, T3-6 | SPI FLASH CS (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00004000 | GPIO14 | PORT1 LED ORANGE | | | GPIO46 | T8-1 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00008000 | GPIO15 | | | | GPIO47 | T8-5 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00010000 | GPIO16 | PORT2 LED GREEN | | | GPIO48 | T8-3 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00020000 | GPIO17 | PORT2 LED ORANGE | | | GPIO49 | T8-6 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
|
||||||
|
| 00040000 | GPIO18 | PORT3 LED GREEN | | | GPIO50 | | |
|
||||||
|
| 00080000 | GPIO19 | PORT3 LED ORANGE | | | GPIO51 | | |
|
||||||
|
| 00100000 | GPIO20 | PORT4 LED GREEN | | | GPIO52 | | |
|
||||||
|
| 00200000 | GPIO21 | PORT4 LED ORANGE | | | GPIO53 | | |
|
||||||
|
| 00400000 | GPIO22 | PORT5 LED GREEN | | | GPIO54 | Reset Button | GPIO54_ACL_BIT2_EN |
|
||||||
|
| 00800000 | GPIO23 | PORT5 LED ORANGE | | | GPIO55 | | |
|
||||||
|
| 01000000 | GPIO24 | SFP LED GREEN | J4 | | GPIO56 | | |
|
||||||
|
| 02000000 | GPIO25 | | | | GPIO57 | | |
|
||||||
|
| 04000000 | GPIO26 | | | | GPIO58 | | |
|
||||||
|
| 08000000 | GPIO27 | | | | GPIO59 | | |
|
||||||
|
| 10000000 | GPIO28 | LED-SYSTEM | | | GPIO60 | | |
|
||||||
|
| 20000000 | GPIO29 | | | | GPIO61 | | |
|
||||||
|
| 40000000 | GPIO30 | J4-6 | SFP DETECT | | GPIO62 | | |
|
||||||
|
| 80000000 | GPIO31 | T5-1 | U0TXD | | GPIO63 | | |
|
||||||
|
|
||||||
|
# LEDs
|
||||||
|
|
||||||
|
| NAME | GPIO | Port(s) | Function | Notes |
|
||||||
|
| ---- | ---- | ---- | ---- | ---- |
|
||||||
|
| PORT1 LED GREEN | GPIO13 |5| Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT1 LED ORANGE | GPIO14 | 5 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT2 LED GREEN | GPIO16 | 4 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT2 LED ORANGE | GPIO17 | 4 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT3 LED GREEN | GPIO18 | 3 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT3 LED ORANGE | GPIO19 | 3 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT4 LED GREEN | GPIO20 | 2 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT4 LED ORANGE | GPIO21 | 2 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT5 LED GREEN | GPIO22 | 1 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
|
||||||
|
| PORT5 LED ORANGE | GPIO23 | 1 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
|
||||||
|
| SFP LED GREEN | GPIO24 | 6 (SFP J4) | Multi-speed | LEDS_10G, LEDS_5G, LEDS_2G5, LEDS_1G, LEDS_100M, LEDS_LINK, LEDS_ACT |
|
||||||
|
| LED-SYSTEM | GPIO28 | --- | System status | --- |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
While [SWTG024AS.md](SWTG024AS.md) can be used as a general reference for hardware concepts and interface specifications, this device should not be assumed to be identical beside the difference implicitely highlighted below. Not all information has been validated for compatibility with the SWTG215AS. Consult the SWTG024AS documentation with caution and verify any critical details against this device's.
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
|
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
|
||||||
| Sodola | | | | | |
|
| Sodola | | | | | |
|
||||||
| Horaco | | | | | |
|
| Horaco | | | | | |
|
||||||
|
| XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | |
|
||||||
|
|
||||||
|
|
||||||
## Photos
|
## Photos
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ The memory chip is `Winbond W25Q16JV` with 16M-bit size.
|
|||||||
1. 2.5G ports on all advertised speeds.
|
1. 2.5G ports on all advertised speeds.
|
||||||
2. SFP+ communication.
|
2. SFP+ communication.
|
||||||
3. Serial, Web UI.
|
3. Serial, Web UI.
|
||||||
|
4. All LEDs
|
||||||
|
|
||||||
## Known issues
|
## Known issues
|
||||||
|
|
||||||
1. LEDs are not initialized properly.
|
None.
|
||||||
|
|
||||||
## PCB
|
## PCB
|
||||||
|
|
||||||
@@ -38,10 +39,10 @@ Bottom
|
|||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ ┌──────────┐ ┌──────────┐ │
|
│ ┌──────────┐ ┌──────────┐ │
|
||||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP │ │ SFP │ │
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP 2 │ │ SFP 1 │ │
|
||||||
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 5 │ │ PORT 6 │ │
|
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 5 │ │ PORT 6 │ │
|
||||||
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC ? │ │ MAC ? │ │
|
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC 8 │ │ MAC 3 │ │
|
||||||
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes ? │ │ SerDes ? │ │
|
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 0 │ │ SerDes 1 │ │
|
||||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
|
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
|
||||||
└─────────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
@@ -105,9 +106,9 @@ GPIO mapping unknown.
|
|||||||
| 00000002 | GPIO01 | | GPIO33 | |
|
| 00000002 | GPIO01 | | GPIO33 | |
|
||||||
| 00000004 | GPIO02 | | GPIO34 | Random changes |
|
| 00000004 | GPIO02 | | GPIO34 | Random changes |
|
||||||
| 00000008 | GPIO03 | | GPIO35 | |
|
| 00000008 | GPIO03 | | GPIO35 | |
|
||||||
| 00000010 | GPIO04 | | GPIO36 | SFP1 Present |
|
| 00000010 | GPIO04 | | GPIO36 | SFP2 Present |
|
||||||
| 00000020 | GPIO05 | | GPIO37 | SFP1 RX Los |
|
| 00000020 | GPIO05 | | GPIO37 | SFP2 RX Los |
|
||||||
| 00000040 | GPIO06 | | GPIO38 | SFP2 Present |
|
| 00000040 | GPIO06 | | GPIO38 | SFP1 Present |
|
||||||
| 00000080 | GPIO07 | | GPIO39 | |
|
| 00000080 | GPIO07 | | GPIO39 | |
|
||||||
| 00000100 | GPIO08 | | GPIO40 | |
|
| 00000100 | GPIO08 | | GPIO40 | |
|
||||||
| 00000200 | GPIO09 | | GPIO41 | |
|
| 00000200 | GPIO09 | | GPIO41 | |
|
||||||
@@ -119,11 +120,11 @@ GPIO mapping unknown.
|
|||||||
| 00008000 | GPIO15 | PORT2 Link | GPIO47 | SFP1 I2C SDA |
|
| 00008000 | GPIO15 | PORT2 Link | GPIO47 | SFP1 I2C SDA |
|
||||||
| 00010000 | GPIO16 | PORT2-LED-GREEN | GPIO48 | SFP2 I2C CLK |
|
| 00010000 | GPIO16 | PORT2-LED-GREEN | GPIO48 | SFP2 I2C CLK |
|
||||||
| 00020000 | GPIO17 | PORT2-LED-AMBER | GPIO49 | SFP2 I2C SDA |
|
| 00020000 | GPIO17 | PORT2-LED-AMBER | GPIO49 | SFP2 I2C SDA |
|
||||||
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP2 Rx LOS |
|
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP1 Rx LOS |
|
||||||
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP1 TX Disable |
|
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP2 TX Disable |
|
||||||
| 00100000 | GPIO20 | PORT4-LED-AMBER | GPIO52 | |
|
| 00100000 | GPIO20 | PORT4-LED-AMBER | GPIO52 | |
|
||||||
| 00200000 | GPIO21 | PORT4 Link | GPIO53 | |
|
| 00200000 | GPIO21 | PORT4 Link | GPIO53 | |
|
||||||
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP2 TX Disable |
|
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP1 TX Disable |
|
||||||
| 00800000 | GPIO23 | PORT4-LED-AMBER | GPIO55 | |
|
| 00800000 | GPIO23 | PORT4-LED-AMBER | GPIO55 | |
|
||||||
| 01000000 | GPIO24 | | GPIO56 | |
|
| 01000000 | GPIO24 | | GPIO56 | |
|
||||||
| 02000000 | GPIO25 | | GPIO57 | |
|
| 02000000 | GPIO25 | | GPIO57 | |
|
||||||
@@ -136,8 +137,6 @@ GPIO mapping unknown.
|
|||||||
|
|
||||||
## LEDs
|
## LEDs
|
||||||
|
|
||||||
Leds are not yet working as in stock firmware. This will be handled later.
|
|
||||||
|
|
||||||
Ports 1-4 are amber for 100M/1G links, Green for 2.5G.
|
Ports 1-4 are amber for 100M/1G links, Green for 2.5G.
|
||||||
Port 5-6 are green for 10G/1G link. Both should flash on activity.
|
Port 5-6 are green for 10G/1G link. Both should flash on activity.
|
||||||
|
|
||||||
@@ -166,7 +165,7 @@ Voltage is made by a `APW8713` (U3).
|
|||||||
|
|
||||||
### `3.3` Voltage
|
### `3.3` Voltage
|
||||||
|
|
||||||
Voltage is crated regulated by chip marke as `GoIAT` (U2).
|
Voltage is crated regulated by chip marked as `GoIAT` (U2).
|
||||||
|
|
||||||
## SFP SPI
|
## SFP SPI
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# ZX310S-4T2XH/
|
||||||
|
|
||||||
|
The following is a documentation for the managed switch marked as `ZX310S-4T2XH`
|
||||||
|
and sold by Horaco.
|
||||||
|
|
||||||
|
The original software is running UART on 57600 baud rate. The solder holes
|
||||||
|
of the UART header are filled in. In order to install a UART header, they
|
||||||
|
need to be cleared first. A 1.2mm drill can be used, alternatively a
|
||||||
|
de-soldering wick.
|
||||||
|
The original firmware uses 57600 baud 8N1
|
||||||
|
|
||||||
|
CPU: RTL8372
|
||||||
|
Flash: 2MByte Winbond W25Q16DV (U3)
|
||||||
|
PHY RTL8261BE
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**:
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 1 x RJ45: 10/100/1000/2500/5000/10000 Mbps
|
||||||
|
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
- **Power**: 12V DC, 2A barrel connector
|
||||||
|
|
||||||
|
<img src="photos/ZX310S-4T2XH/label.jpg" width="300" />
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
|
||||||
|
- The 10GBit port works. TODO: Fix EEE, speed selection
|
||||||
|
- The SFP+ port supports 1G, 2.5G and 10G modules
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-SL310S-4T1T1X-V1.0.1-24107
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/ZX310S-4T2XH/pcb_top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/ZX310S-4T2XH/pcb_bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J1` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | TX (Output) |
|
||||||
|
| 2 | RX (Input) |
|
||||||
|
| 3 | GND |
|
||||||
|
| 4 | 3V3 |
|
||||||
|
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 2A` adapter was provided.
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# ZX310S-4T2XT
|
||||||
|
|
||||||
|
The following is a documentation for the managed switch marked as
|
||||||
|
`ZX310S-4T2XT` and sold by Horaco.
|
||||||
|
|
||||||
|
The original software is running UART on 57600 baud rate 8N1.
|
||||||
|
|
||||||
|
CPU: RTL8372
|
||||||
|
Flash: 2MByte Winbond W25Q16DV (U3)
|
||||||
|
PHY 2x RTL8261BE
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Name**:
|
||||||
|
- **Ports**:
|
||||||
|
- 4 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 2 x RJ45: 10/100/1000/2500/5000/10000 Mbps
|
||||||
|
- **Power**: 12V DC, 2A barrel connector
|
||||||
|
|
||||||
|
<img src="photos/ZX310S-4T2XT/label.jpg" width="300" />
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps, including EEE
|
||||||
|
- The 10GBit ports works, including EEE.
|
||||||
|
- LEDs work with the same indiciations as the OEM firmware
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
- Top silkscreen: PCB-SL310S-4T2XT-V1.0.0-22273
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/ZX310S-4T2XT/pcb_top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/ZX310S-4T2XT/pcb_bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J1` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | TX (Output) |
|
||||||
|
| 2 | RX (Input) |
|
||||||
|
| 3 | GND |
|
||||||
|
| 4 | 3V3 |
|
||||||
|
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 2A` adapter was provided.
|
||||||
|
After Width: | Height: | Size: 560 KiB |
|
After Width: | Height: | Size: 536 KiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 715 KiB |
|
After Width: | Height: | Size: 615 KiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 521 KiB After Width: | Height: | Size: 521 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 203 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 531 KiB |
|
After Width: | Height: | Size: 548 KiB |
|
After Width: | Height: | Size: 505 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.6 MiB After Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 3.1 MiB After Width: | Height: | Size: 3.1 MiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 455 KiB |
|
After Width: | Height: | Size: 710 KiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 9.7 MiB |
|
After Width: | Height: | Size: 36 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 2.4 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 2.7 MiB |
|
After Width: | Height: | Size: 3.3 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 2.7 MiB |
@@ -0,0 +1,98 @@
|
|||||||
|
|
||||||
|
# GPIO Pin, Function and MUX registers.
|
||||||
|
|
||||||
|
These functions should bevalid for `RTL8372`, `RTL8372N`, `RTL8373`, and `RTL8373N`.
|
||||||
|
|
||||||
|
`N`-version doesn't seems to have all the GPIO pins available on the outside of the package.
|
||||||
|
|
||||||
|
| GPIO | Function | TYPE | MUX REG, BIT | (RTL8372) PIN# | (RTL8372N) PIN# |
|
||||||
|
| ----- | ---- | ---- | ---- | ---- | ---- |
|
||||||
|
| GPIO0 | LED0 | I/OPU | IO_MUX_SEL_0, BIT 0 | G1 | 12 |
|
||||||
|
| GPIO1 | LED1 | I/OPU | IO_MUX_SEL_0, BIT 1 | G2 | 15 |
|
||||||
|
| GPIO2 | LED2 | I/OPU | IO_MUX_SEL_0, BIT 2 | G3 | 14 |
|
||||||
|
| GPIO3 | LED3 | I/OPU | IO_MUX_SEL_0, BIT 3 | H1 | 16 |
|
||||||
|
| GPIO4 | LED4 | I/OPU | IO_MUX_SEL_0, BIT 4 | H2 | 18 |
|
||||||
|
| GPIO5 | LED5 | I/OPU | IO_MUX_SEL_0, BIT 5 | H3 | 20 |
|
||||||
|
| GPIO6 | LED6 | I/OPU | IO_MUX_SEL_0, BIT 6 | J1 | 22 |
|
||||||
|
| GPIO7 | LED7 | I/OPU | IO_MUX_SEL_0, BIT 7 | J2 | NoPin? |
|
||||||
|
| GPIO8 | LED8 | I/OPU | IO_MUX_SEL_0, BIT 8 | J3 | 24 |
|
||||||
|
| GPIO9 | LED9 | I/OPD | IO_MUX_SEL_0, BIT 9 | L1 | 23 |
|
||||||
|
| GPIO10 | LED10 | I/OPU | IO_MUX_SEL_0, BIT 10 | L2 | 26 |
|
||||||
|
| GPIO11 | LED11 | I/OPU | IO_MUX_SEL_0, BIT 11 | L3 | NoPin? |
|
||||||
|
| GPIO12 | LED12 | I/OPD | IO_MUX_SEL_0, BIT 12 | M1 | 28 |
|
||||||
|
| GPIO13 | LED13 | I/OPU | IO_MUX_SEL_0, BIT 13 | M2 | NoPin? |
|
||||||
|
| GPIO14 | LED14 | I/OPU | IO_MUX_SEL_0, BIT 14 | M3 | NoPin? |
|
||||||
|
| GPIO15 | LED15 | I/OPU | IO_MUX_SEL_0, BIT 15 | N1 | 25 |
|
||||||
|
| GPIO16 | LED16 | I/OPU | IO_MUX_SEL_0, BIT 16 | N2 | NoPin? |
|
||||||
|
| GPIO17 | LED17 | I/OPU | IO_MUX_SEL_0, BIT 17 | N3 | NoPin? |
|
||||||
|
| GPIO18 | LED18 | I/OPD | IO_MUX_SEL_0, BIT 18 | P1 | 30 |
|
||||||
|
| GPIO19 | LED19 | I/OPU | IO_MUX_SEL_0, BIT 19 | P2 | NoPin? |
|
||||||
|
| GPIO20 | LED20 | I/OPU | IO_MUX_SEL_0, BIT 20 | P3 | NoPin? |
|
||||||
|
| GPIO21 | LED21 | I/OPU | IO_MUX_SEL_0, BIT 21 | R1 | 27 |
|
||||||
|
| GPIO22 | LED22 | I/OPU | IO_MUX_SEL_0, BIT 22 | R2 | NoPin? |
|
||||||
|
| GPIO23 | LED23 | I/OPU | IO_MUX_SEL_0, BIT 23 | R3 | NoPin? |
|
||||||
|
| GPIO24 | LED24 | I/OPU | IO_MUX_SEL_0, BIT 24 | N19 | 88 |
|
||||||
|
| GPIO25 | LED25 | I/OPU | IO_MUX_SEL_0, BIT 25 | P19 | 86 |
|
||||||
|
| GPIO26 | LED26 | I/OPU | IO_MUX_SEL_0, BIT 26 | P18 | 84 |
|
||||||
|
| GPIO27 | LED27 | I/OPU | IO_MUX_SEL_0, BIT 27 | R19 | 82 |
|
||||||
|
| GPIO28 | SYS_LED | I/OPU | IO_MUX_SEL_0, BIT 28 | F1 | 13 |
|
||||||
|
| GPIO29 | GLB_RLDP_LED_EN | | IO_MUX_SEL_0, BIT 29 | | NoPin? |
|
||||||
|
| GPIO30 | ACL_BIT3_EN | | IO_MUX_SEL_2, BIT 3 | F3 | 11 |
|
||||||
|
| GPIO31 | UART TX (OUTPUT) | | IO_MUX_SEL_1, BIT 0 | L20 | 90 |
|
||||||
|
| GPIO32 | UART TX (INPUT) | | IO_MUX_SEL_1, BIT 1 | L21 | |
|
||||||
|
| GPIO33 | GPIO_INT | | IO_MUX_SEL_1, BIT 2 | | |
|
||||||
|
| GPIO34 | MDC0 | | IO_MUX_SEL_1, BIT 3 | | |
|
||||||
|
| GPIO35 | MDIO0 | | IO_MUX_SEL_1, BIT 4 | | |
|
||||||
|
| GPIO36 | PWM_OUT | | IO_MUX_SEL_1, BIT 30 | B13 | |
|
||||||
|
| GPIO37 | --- | | | L18 | |
|
||||||
|
| GPIO38 | --- | | | K19 | |
|
||||||
|
| GPIO39 | MSDA4 | | IO_MUX_SEL_1, BIT 29 | K20 | 95 |
|
||||||
|
| GPIO40 | MDC1/SCL3 | | IO_MUX_SEL_1, BIT 5 & 6 | J29 | |
|
||||||
|
| GPIO41 | MDIO1/MSDA3 | | IO_MUX_SEL_1, BIT 5 & 6 | J19 | |
|
||||||
|
| GPIO42 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | D1 | |
|
||||||
|
| GPIO43 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | E1 | |
|
||||||
|
| GPIO44 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | D2 | |
|
||||||
|
| GPIO45 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | E2 | |
|
||||||
|
| GPIO46 | MSCK0 | | IO_MUX_SEL_1, BIT 7 & 8 | A2 | |
|
||||||
|
| GPIO47 | MSDA0 | | IO_MUX_SEL_1, BIT 9 & 10 | B2 | |
|
||||||
|
| GPIO48 | MSCK1 | | IO_MUX_SEL_1, BIT 11 & 12 | A1 | |
|
||||||
|
| GPIO49 | MSDA1 | | IO_MUX_SEL_1, BIT 13 & 14 | B1 | |
|
||||||
|
| GPIO50 | MSCL2/U1TXD | | IO_MUX_SEL_1, BIT 15 & 16 | C1 | |
|
||||||
|
| GPIO51 | MSDA2/U1RXD | | IO_MUX_SEL_1, BIT 17 & 18 | C2 | |
|
||||||
|
| GPIO52 | ACL_BIT0_EN | | IO_MUX_SEL_2, BIT 0 | | |
|
||||||
|
| GPIO53 | ACL_BIT1_EN | | IO_MUX_SEL_2, BIT 1 | | |
|
||||||
|
| GPIO54 | ACL_BIT2_EN | | IO_MUX_SEL_2, BIT 2 | E5 | |
|
||||||
|
| GPIO55 | PTP_CLK125M_IN | | IO_MUX_SEL_1, BIT 19 | | |
|
||||||
|
| GPIO56 | PTP_CLK_OUT | | IO_MUX_SEL_1, BIT 20 | | |
|
||||||
|
| GPIO57 | PTP_TOD_OUT | | IO_MUX_SEL_1, BIT 21 | | |
|
||||||
|
| GPIO58 | PTP_PPS_OUT | | IO_MUX_SEL_1, BIT 22 | | |
|
||||||
|
| GPIO59 | PTP_TOD_IN | | IO_MUX_SEL_1, BIT 23 | | |
|
||||||
|
| GPIO60 | PTP_PPS_IN | | IO_MUX_SEL_1, BIT 24 | | |
|
||||||
|
| GPIO61 | SYNCELOCK0 | | IO_MUX_SEL_1, BIT 27 | | |
|
||||||
|
| GPIO62 | SYNCELOCK1 | | IO_MUX_SEL_1, BIT 28 | | |
|
||||||
|
| GPIO63 | GPIO_MDIO0 | | IO_MUX_SEL_1, BIT 4 | | |
|
||||||
|
|
||||||
|
## I2C
|
||||||
|
|
||||||
|
| I2C | Function |Type | (RTL8372) PIN# | (RTL8372N) PIN# |
|
||||||
|
| ---- | ---- | ---- | ---- | ---- |
|
||||||
|
| GPIO47 | SDA0 | I/OPU | | B1 | 142 |
|
||||||
|
| GPIO49 | SDA1 | I/OPU | | B2 | 144 |
|
||||||
|
| GPIO51 | SDA2 | I/OPU | | C2 | ??? |
|
||||||
|
| GPIO41 | SDA3 | I/OPU | | J20 | 98 |
|
||||||
|
| GPIO39 | SDA4 | I/OPU | | K20 | 95 |
|
||||||
|
| GPIO46 | SCL0 | I/OPU | | A2 | 138 |
|
||||||
|
| GPIO48 | SCL1 | I/OPU | | A1 | 140 |
|
||||||
|
| GPIO50 | SCL2 | I/OPU | | C1 | ??? |
|
||||||
|
| GPIO40? | SCL3 | OPU | | J20 | |
|
||||||
|
|
||||||
|
# Other funcitons
|
||||||
|
|
||||||
|
| Function | Type | (RTL8372) PIN# | (RTL8372N) PIN# |
|
||||||
|
| ---- | ---- | ---- | ---- |
|
||||||
|
| nRESET | | A6 | 131 |
|
||||||
|
| PTP_SYNC | | B10 | 130 |
|
||||||
|
| INT | OPU | B6 | 132 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 64 KiB |
@@ -37,10 +37,13 @@ This list is incomplete.
|
|||||||
| Brand | Partnumber |
|
| Brand | Partnumber |
|
||||||
| ---------- |----------- |
|
| ---------- |----------- |
|
||||||
| GigaDevice | GD25Q32E |
|
| GigaDevice | GD25Q32E |
|
||||||
|
| Fundan | FM25Q16A |
|
||||||
|
| Puya | P25D40SH |
|
||||||
| Winbond | W25Q16JV |
|
| Winbond | W25Q16JV |
|
||||||
| Winbond | W25Q32FV |
|
| Winbond | W25Q32FV |
|
||||||
| Winbond | W25Q32JV |
|
| Winbond | W25Q32JV |
|
||||||
| Winbond | W25Q16JL |
|
| Winbond | W25Q16JL |
|
||||||
| Fundan | FM25Q16A |
|
| Winbond | W25Q16DV |
|
||||||
|
| Winbond | W25Q80DV |
|
||||||
|
|
||||||
*NOTE*: Part numbers are incomplete. Part numbers may contain additional information such as package, temperature specifications, and even the number of devices on a reel. So always check the datasheet so that you have the right orderable partnumber.
|
*NOTE*: Part numbers are incomplete. Part numbers may contain additional information such as package, temperature specifications, and even the number of devices on a reel. So always check the datasheet so that you have the right orderable partnumber.
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
All translation logic lives in `html/i18n.js`. The file contains:
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## How to Add a New Language
|
||||||
|
|
||||||
|
### 1. Add a dictionary entry in `html/i18n.js`
|
||||||
|
|
||||||
|
Append a new sub-object to the `LANG` object. Every key from `LANG.en` must 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
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Add the language to the navigation sidebar
|
||||||
|
|
||||||
|
In `html/navigation.js`, add an `<option>` to the language selector:
|
||||||
|
|
||||||
|
```js
|
||||||
|
+ "<option value='en'>English</option><option value='ja'>日本語</option>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
+ "<option value='en'>English</option><option value='ja'>日本語</option><option value='LANGCODE'>Native Name</option>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 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.
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
```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>
|
||||||
|
```
|
||||||
|
|
||||||
|
On page load, `applyTranslation()` sets:
|
||||||
|
|
||||||
|
- `el.value` for `<input type="submit|button">`
|
||||||
|
- `el.textContent` for `<option>`, `<title>`
|
||||||
|
- `el.innerHTML` for everything else
|
||||||
|
|
||||||
|
### (B) `t('key')` call (imperative — for JavaScript strings)
|
||||||
|
|
||||||
|
When generating HTML or text in JavaScript, wrap translatable strings with `t()`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
td.appendChild(document.createTextNode(t('common_port') + i));
|
||||||
|
td.innerHTML = t('port_auto');
|
||||||
|
iHTML += "<tr><td>" + t('port_vendor') + "</td></tr>";
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
## 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"`)
|
||||||
|
|
||||||
|
## 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>`).
|
||||||
@@ -1,17 +1,35 @@
|
|||||||
# Supported Hardware
|
# Supported Hardware
|
||||||
The following devices have been tested and are fully working:
|
The following devices have been tested and are fully working:
|
||||||
- Horaco ZX_SG4T2
|
|
||||||
- keepLINK kp-9000-6hx-x2 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
|
|
||||||
- keepLINK KP-9000-6XHML-X2, same as above, but Managed
|
|
||||||
- keepLINK kp-9000-6hx-x (RTL8372 + RTL8221B 2.5GBit PHY: 5 x 2.5GBit + 1x 10GBit SFP+)
|
|
||||||
- keepLINK kp-9000-9xh-x-eu (1 x RTL8373 + RTL8224: 8x 2.5GBit + 1x 10GBit SFP+)
|
|
||||||
- Lianguo LG-SWTGW218AS (RTL8373 + RTL8224 PHY: 8x 2.5GBit + 1x 10GBit SFP+)
|
|
||||||
- No-Name ZX-SWTGW215AS, managed version of kp-9000-6hx-x, ordered on
|
|
||||||
AliExpress as keepLINK 5+1 port managed
|
|
||||||
- TrendNet TEG-S562 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
|
|
||||||
|
|
||||||
Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide]
|
| Brand | Type | Managed | PCB | Flash | Ports |
|
||||||
(https://github.com/up-n-atom/SWTG118AS)
|
|----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------|
|
||||||
|
| 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 |
|
||||||
|
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
|
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
||||||
|
| hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 |
|
||||||
|
| Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 |
|
||||||
|
| Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
||||||
|
| Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 |
|
||||||
|
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 |
|
||||||
|
| Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 |
|
||||||
|
| Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
|
||||||
|
| Keeplink | KP-9000-6XH-X2 | No | [2M-PCB43-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 |
|
||||||
|
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
|
||||||
|
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
||||||
|
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||||
|
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
||||||
|
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
|
||||||
|
| Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 |
|
||||||
|
| TrendNet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide](https://github.com/up-n-atom/SWTG118AS)
|
||||||
|
|
||||||
Many of the RTL8272/3 devices come in versions with PoE support. The RTLPlayground usually also
|
Many of the RTL8272/3 devices come in versions with PoE support. The RTLPlayground usually also
|
||||||
works on these, however, no support for configuring PoE is provided, simply because these
|
works on these, however, no support for configuring PoE is provided, simply because these
|
||||||
|
|||||||
@@ -33,15 +33,23 @@ An entry is deleted by adding an invalid entry (00 instead of 0x02 in
|
|||||||
RTL837x_TBL_DATA_IN_A).
|
RTL837x_TBL_DATA_IN_A).
|
||||||
|
|
||||||
A port is assigned a PVID by setting the PVID-bits of the corresponding
|
A port is assigned a PVID by setting the PVID-bits of the corresponding
|
||||||
register of the port. 2 ports share a register. One port uses the higher
|
register of the port. 2 ports share a register. An odd port uses bits [23:12],
|
||||||
16 bits, the other (even ports) use the lower. The base register is
|
an even port uses bits [11:0]. The base register is
|
||||||
RTL837x_PVID_BASE_REG (0x4e1c) and the registers go to 0x4e2c so that also
|
RTL837x_PVID_BASE_REG (0x4e1c) and the registers go to 0x4e2c so that also
|
||||||
the CPU-Port may have a PVID.
|
the CPU-Port may have a PVID.
|
||||||
|
|
||||||
Register RTL837x_REG_INGRESS (0x4e10) allows to define the iingress rules of
|
Register RTL837x_REG_INGRESS (0x4e10) allows to define the ingress rules of
|
||||||
a port. 2 bits define a rule and bits 0-19 are being used. A value of 00
|
a port. 2 bits define a rule and bits 0-19 are being used. A value of 00
|
||||||
defines no filtering, 01 (0x01) allows only tagged packets, while 10 (0x02)
|
defines no filtering, 01 (0x01) allows only tagged packets, while 10 (0x02)
|
||||||
allows only untagged packets to enter a port. The default PVID is 1.
|
allows only untagged packets to enter a port.
|
||||||
|
|
||||||
|
Register RTL837X_VLAN_PORT_IGR_FLTR (0x4e18) enables or disables ingres VLAN
|
||||||
|
filtering, each bit corresponds to given port (port0 -> bit0, port9 -> bit9).
|
||||||
|
When enabled, incomming package's vlan tag is checked against VLAN membership
|
||||||
|
on given port. When package contains VLAN not in member list, package is dropped.
|
||||||
|
|
||||||
|
The default PVID on all port is 1, ingress VLAN filtering is enabled and all types of
|
||||||
|
frames are accepted on input on all ports.
|
||||||
|
|
||||||
By default, the ports transmit Ethernet frames with Realtek's proprietary
|
By default, the ports transmit Ethernet frames with Realtek's proprietary
|
||||||
tag format. By setting bit 6 (0x40) of the respective port configuration
|
tag format. By setting bit 6 (0x40) of the respective port configuration
|
||||||
@@ -51,7 +59,9 @@ registers 0x1238, 0x1338, ...
|
|||||||
The code currently provides the following functions:
|
The code currently provides the following functions:
|
||||||
```
|
```
|
||||||
void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
|
void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
|
||||||
void vlan_create(uint16_t vlan, uint16_t members, uint16_t tagged) __banked;
|
uint16_t port_pvid_get(uint8_t port) __banked;
|
||||||
|
void vlan_create(void) __banked; // reads from global vlan_settings
|
||||||
|
int8_t vlan_get(register uint16_t vlan) __banked; // returns data in sfr_data
|
||||||
void vlan_delete(uint16_t vlan) __banked;
|
void vlan_delete(uint16_t vlan) __banked;
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -66,9 +76,26 @@ vlan <VLAN-ID> p[t/u]...
|
|||||||
vlan <VLAN-ID> d
|
vlan <VLAN-ID> d
|
||||||
deletes the VLAN
|
deletes the VLAN
|
||||||
|
|
||||||
|
vlan show
|
||||||
|
Dumps the current ingress vlan settings.
|
||||||
|
|
||||||
|
vlan <VLAN-ID> mgmt
|
||||||
|
Restricts network access to the switch (web UI, syslog) to the given
|
||||||
|
VLAN. Use `vlan 0 mgmt` to disable the filter. Default is `vlan 1 mgmt`.
|
||||||
|
Warning: setting this to an unreachable VLAN locks out the web UI;
|
||||||
|
recovery requires serial console.
|
||||||
|
|
||||||
pvid <port> <VLAN-ID>
|
pvid <port> <VLAN-ID>
|
||||||
assigns PVID to a port. ports are numbered as on the casing
|
assigns PVID to a port. ports are numbered as on the casing
|
||||||
|
|
||||||
ingress <port> [tagged|untagged|all]
|
ingress [p]<t|u|a>...
|
||||||
Allows ingress only for the named packages at the given port
|
Allows ingress packages on port `p` only when `t`agged, `u`ntagged or `a`ny.
|
||||||
|
Multiple ports can be given at once as in vlan. When `p` is missing, all ports
|
||||||
|
are assigned the same mode. CPU port can not be changed.
|
||||||
|
|
||||||
|
Use `vlan show` to see current configuration.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`ingress 1t 2a` -> Set port 1 as tagged input only, set port 2 accepting any frames.
|
||||||
|
`ingress a` -> Set all ports to accept both tagged and untagged frames (default behaviour).
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>Ingress and Egress Bandwidth</title>
|
<title data-i18n="bw_title">Ingress and Egress Bandwidth</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>Ingress and Egress Bandwidth</h1>
|
<h1 data-i18n="bw_heading">Ingress and Egress Bandwidth</h1>
|
||||||
<table id="bwtable">
|
<table id="bwtable">
|
||||||
<tr> <th> </th> <th colspan="3"> Ingress </th> <th colspan="2">Egress</th> <th></th></tr>
|
<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>Port</th> <th>Limit</th> <th>Bandwidth [kBit/s]</th> <th>Flow Control</th> <th>Limit</th> <th>Bandwidth [kBit/s]</th> <th>Apply</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>
|
</table>
|
||||||
<script src="/bandwidth.js"></script>
|
<script src="/bandwidth.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,22 +3,21 @@ function createBW() {
|
|||||||
var tbl = document.getElementById('bwtable');
|
var tbl = document.getElementById('bwtable');
|
||||||
const limit = '<input type="checkbox" id="limit_port" onchange="exec();">'
|
const limit = '<input type="checkbox" id="limit_port" onchange="exec();">'
|
||||||
if (tbl.rows.length <= 2 && numPorts) {
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
clearInterval(createBWInterval);
|
|
||||||
console.log("CREATING TABLE ", tbl.rows.length);
|
console.log("CREATING TABLE ", tbl.rows.length);
|
||||||
for (let i = 2; i < 2 + numPorts; i++) {
|
for (let i = 2; i < 2 + numPorts; i++) {
|
||||||
const tr = tbl.insertRow();
|
const tr = tbl.insertRow();
|
||||||
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i-1)));
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = limit.replaceAll("limit_port", "ilimit_port_" + i).replace("exec()", "iClicked(" + i + ")");
|
td.innerHTML = limit.replaceAll("limit_port", "ilimit_port_" + i).replace("exec()", "iClicked(" + i + ")");
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = 'UNLIMITED';
|
td.innerHTML = t('bw_unlimited');
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = limit.replaceAll("limit_port", "fc_port_" + i).replace("exec()", "document.getElementById('bwapply_" + i + "').disabled=false;");
|
td.innerHTML = limit.replaceAll("limit_port", "fc_port_" + i).replace("exec()", "document.getElementById('bwapply_" + i + "').disabled=false;");
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = limit.replaceAll("limit_port", "elimit_port_" + i).replace("exec()", "eClicked(" + i + ")");
|
td.innerHTML = limit.replaceAll("limit_port", "elimit_port_" + i).replace("exec()", "eClicked(" + i + ")");
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = 'UNLIMITED';
|
td.innerHTML = t('bw_unlimited');
|
||||||
var button = '<button type="button" id="bwapply_' + i + '" style="margin: 0 0 0 24px" onclick="applyBandwidth(' + i + ');">Apply</button>';
|
var button = '<button type="button" id="bwapply_' + i + '" style="margin: 0 0 0 24px" onclick="applyBandwidth(' + i + ');">' + t('bw_col_apply') + '</button>';
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = button;
|
td.innerHTML = button;
|
||||||
document.getElementById("bwapply_" + i).disabled = true;
|
document.getElementById("bwapply_" + i).disabled = true;
|
||||||
@@ -32,7 +31,7 @@ function iClicked(i)
|
|||||||
var tbl = document.getElementById('bwtable');
|
var tbl = document.getElementById('bwtable');
|
||||||
var tr = tbl.rows[i];
|
var tr = tbl.rows[i];
|
||||||
if (!document.getElementById("ilimit_port_" + i).checked) {
|
if (!document.getElementById("ilimit_port_" + i).checked) {
|
||||||
tr.cells[2].innerHTML = "UNLIMITED";
|
tr.cells[2].innerHTML = t('bw_unlimited');
|
||||||
document.getElementById("fc_port_" + i).disabled = true;
|
document.getElementById("fc_port_" + i).disabled = true;
|
||||||
document.getElementById("fc_port_" + i).checked = true;
|
document.getElementById("fc_port_" + i).checked = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -48,7 +47,7 @@ function eClicked(i)
|
|||||||
var tbl = document.getElementById('bwtable');
|
var tbl = document.getElementById('bwtable');
|
||||||
var tr = tbl.rows[i];
|
var tr = tbl.rows[i];
|
||||||
if (!document.getElementById("elimit_port_" + i).checked) {
|
if (!document.getElementById("elimit_port_" + i).checked) {
|
||||||
tr.cells[5].innerHTML = "UNLIMITED";
|
tr.cells[5].innerHTML = t('bw_unlimited');
|
||||||
} else {
|
} else {
|
||||||
tr.cells[5].innerHTML = '<input id="ebw_' + i + iLayout + i + ')" value="0"/>';
|
tr.cells[5].innerHTML = '<input id="ebw_' + i + iLayout + i + ')" value="0"/>';
|
||||||
}
|
}
|
||||||
@@ -94,6 +93,7 @@ async function applyBandwidth(i) {
|
|||||||
function getBW() {
|
function getBW() {
|
||||||
var xhttp = new XMLHttpRequest();
|
var xhttp = new XMLHttpRequest();
|
||||||
xhttp.onreadystatechange = function() {
|
xhttp.onreadystatechange = function() {
|
||||||
|
console.log("IN getBW ");
|
||||||
if (this.readyState == 4 && this.status == 200) {
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
const s = JSON.parse(xhttp.responseText);
|
const s = JSON.parse(xhttp.responseText);
|
||||||
console.log("BW: ", JSON.stringify(s));
|
console.log("BW: ", JSON.stringify(s));
|
||||||
@@ -110,12 +110,12 @@ function getBW() {
|
|||||||
document.getElementById("ilimit_port_" + (n+1)).checked = p.iLimited;
|
document.getElementById("ilimit_port_" + (n+1)).checked = p.iLimited;
|
||||||
document.getElementById("elimit_port_" + (n+1)).checked = p.eLimited;
|
document.getElementById("elimit_port_" + (n+1)).checked = p.eLimited;
|
||||||
if (!p.iLimited) {
|
if (!p.iLimited) {
|
||||||
tr.cells[2].innerHTML = "UNLIMITED";
|
tr.cells[2].innerHTML = t('bw_unlimited');
|
||||||
} else {
|
} else {
|
||||||
tr.cells[2].innerHTML = '<input id="ibw_' + (n+1) + iLayout + (n+1) + ')" value="' + iBW +'"/>';
|
tr.cells[2].innerHTML = '<input id="ibw_' + (n+1) + iLayout + (n+1) + ')" value="' + iBW +'"/>';
|
||||||
}
|
}
|
||||||
if (!p.eLimited) {
|
if (!p.eLimited) {
|
||||||
tr.cells[5].innerHTML = "UNLIMITED";
|
tr.cells[5].innerHTML = t('bw_unlimited');
|
||||||
} else {
|
} else {
|
||||||
tr.cells[5].innerHTML = '<input id="ebw_' + (n+1) + iLayout + (n+1) + ')" value="' + eBW +'"/>';
|
tr.cells[5].innerHTML = '<input id="ebw_' + (n+1) + iLayout + (n+1) + ')" value="' + eBW +'"/>';
|
||||||
}
|
}
|
||||||
@@ -126,11 +126,13 @@ function getBW() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", "/bandwidth.json", true);
|
xhttp.open("GET", "/bandwidth.json", true);
|
||||||
xhttp.timeout = 1500; xhttp.send();
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
createBW();
|
||||||
getBW();
|
getBW();
|
||||||
const iCount = setInterval(getBW, 2000);
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
const createBWInterval = setInterval(createBW, 1010);
|
|
||||||
|
|||||||
@@ -1,32 +1,87 @@
|
|||||||
var configInterval = Number();
|
var configInterval = Number();
|
||||||
var configuration = [];
|
var configuration = [];
|
||||||
const conf_cmds = [
|
const conf_cmds = [
|
||||||
/ip\s+(\d{1,3}\.){3}\d{1,3}/, /gw\s+(\d{1,3}\.){3}\d{1,3}/, /netmask\s+(\d{1,3}\.){3}\d{1,3}/,
|
/^ip\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||||
/eee(\s+\d)?\s+(on|off)/, /mirror(\s+(\d|10))(\s+(\d|10)(t|r)?)+/, /vlan\s+(\d{1,4})(\s+(\d|10)(t|u)?)+/
|
/^ip\s+dhcp$/,
|
||||||
|
/^gw\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||||
|
/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||||
|
/^syslog\s+(on|off)$/,
|
||||||
|
/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||||
|
/^passwd\s+\S+$/,
|
||||||
|
/^vlan\s+\d{1,4}\s+d$/,
|
||||||
|
/^vlan\s+\d{1,4}\s+mgmt$/,
|
||||||
|
/^vlan\s+\d{1,4}(\s+[a-zA-Z]\w*)?(\s+\d{1,2}[tu]?)+$/,
|
||||||
|
/^pvid\s+\d{1,2}\s+\d{1,4}$/,
|
||||||
|
/^ingress(\s+\d{1,2}[tua])+$/,
|
||||||
|
/^ingress\s+[tua]$/,
|
||||||
|
/^port\s+\d{1,2}\s+(10m|100m|1g|2g5|5g|10g|auto|on|off)(\s+(half|full))?$/,
|
||||||
|
/^port\s+\d{1,2}\s+name\s+\S+$/,
|
||||||
|
/^eee(\s+\d{1,2})?\s+(on|off)$/,
|
||||||
|
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,
|
||||||
|
/^lag\s+\d(\s+\d{1,2})+$/,
|
||||||
|
/^laghash\s+\d(\s+\w+)+$/,
|
||||||
|
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
|
||||||
|
/^stp\s+(on|off)$/,
|
||||||
|
/^igmp\s+(on|off)$/,
|
||||||
|
/^mtu\s+\d{1,2}\s+\d+$/,
|
||||||
|
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
|
||||||
|
/^hostname\s+.{1,23}$/,
|
||||||
];
|
];
|
||||||
const conf_overwrite = [
|
const conf_overwrite = [
|
||||||
/ip/, /gw/, /netmask/, /eee\s+\w+/, /eee(\s+\w)/, /mirror/, /vlan\s+(\d{1,4})/
|
/^ip\b/,
|
||||||
|
/^gw\b/,
|
||||||
|
/^netmask\b/,
|
||||||
|
/^syslog\s+ip\b/,
|
||||||
|
/^syslog\b/,
|
||||||
|
/^passwd\b/,
|
||||||
|
/^vlan\s+\d{1,4}\s+mgmt$/,
|
||||||
|
/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
|
||||||
|
/^pvid\s+\d{1,2}\b/,
|
||||||
|
/^ingress\b/,
|
||||||
|
/^port\s+\d{1,2}(?!\s+name\b)/,
|
||||||
|
/^port\s+\d{1,2}\s+name\b/,
|
||||||
|
/^eee\s+\d{1,2}\b/,
|
||||||
|
/^eee\b/,
|
||||||
|
/^mirror\b/,
|
||||||
|
/^lag\s+\d+\b/,
|
||||||
|
/^laghash\b/,
|
||||||
|
/^isolate\s+\d{1,2}\b/,
|
||||||
|
/^stp\b/,
|
||||||
|
/^igmp\b/,
|
||||||
|
/^mtu\s+\d{1,2}\b/,
|
||||||
|
/^bw\s+(in|out)\s+\d{1,2}\b/,
|
||||||
|
/^hostname\b/,
|
||||||
];
|
];
|
||||||
|
|
||||||
function parseConf(s){
|
function parseConf(s){
|
||||||
var a = s.split(/\r\n|\n/);
|
var a = s.split(/\r\n|\n/);
|
||||||
for (var l = 0; l < a.length; l++) {
|
for (var l = 0; l < a.length; l++) {
|
||||||
if (!a[l].length || a[l] == "\n" || a[l] == "\r\n")
|
var line = a[l].trim().replace(/\s+/g, ' ');
|
||||||
|
if (!line.length) continue;
|
||||||
|
const deleteMatch = line.match(/^vlan\s+(\d{1,4})\s+d$/);
|
||||||
|
if (deleteMatch) {
|
||||||
|
const prefix = "vlan " + deleteMatch[1] + " ";
|
||||||
|
configuration = configuration.filter(c => !c.startsWith(prefix));
|
||||||
continue;
|
continue;
|
||||||
console.log(l + ' --> ' + a[l]);
|
}
|
||||||
|
console.log(l + ' --> ' + line);
|
||||||
var ignore = true;
|
var ignore = true;
|
||||||
for (const x of conf_cmds)
|
for (const x of conf_cmds)
|
||||||
if (x.test(a[l])) ignore = false;
|
if (x.test(line)) { ignore = false; break; }
|
||||||
if (ignore) continue;
|
if (ignore) continue;
|
||||||
for (const x of conf_overwrite) {
|
for (const x of conf_overwrite) {
|
||||||
if (x.test(a[l])) {
|
if (x.test(line)) {
|
||||||
console.log("Match ", x, " to ", a[l]);
|
let m = line.match(x);
|
||||||
m = a[l].match(x);
|
let matchStr = m[0];
|
||||||
console.log("Starts with ", m[0]);
|
configuration = configuration.filter(item =>
|
||||||
configuration = configuration.filter(item => !(item.startsWith(m[0])));
|
!(item === matchStr || (item.startsWith(matchStr + " ") && !item.endsWith(" mgmt") && !item.startsWith(matchStr + " name "))));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configuration.push(a[l]);
|
// Only one management VLAN can be active, so drop any previous mgmt entry
|
||||||
|
if (/^vlan\s+\d{1,4}\s+mgmt$/.test(line))
|
||||||
|
configuration = configuration.filter(item => !/^vlan\s+\d{1,4}\s+mgmt$/.test(item));
|
||||||
|
configuration.push(line);
|
||||||
}
|
}
|
||||||
console.log("Configuration now:");
|
console.log("Configuration now:");
|
||||||
for (const x of configuration) { console.log(x); }
|
for (const x of configuration) { console.log(x); }
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>EEE Configuration</title>
|
<title data-i18n="eee_title">EEE Configuration</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>EEE Status</h1>
|
<h1 data-i18n="eee_heading">EEE Status</h1>
|
||||||
<table id="eeetable">
|
<table id="eeetable">
|
||||||
<tr> <th> </th> <th colspan="3"> Advertising </th> <th colspan="3">Link-Partner advertises</th> <th></th></tr>
|
<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>Port</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>Active?</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>
|
</table>
|
||||||
<div>
|
<div>
|
||||||
<input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 1);" type="button" value="Enable EEE">
|
<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_enable" onclick="eeeSub(0, 0);" type="button" value="Disable EEE">
|
<input style="width:20%;" class="action" id="eee_disable" onclick="eeeSub(0, 0);" type="button" data-i18n="eee_disable" value="Disable EEE">
|
||||||
</div>
|
</div>
|
||||||
<script src="/eee.js"></script>
|
<script src="/eee.js"></script>
|
||||||
<script src="/eee_sub.js"></script>
|
<script src="/eee_sub.js"></script>
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
function createEEE() {
|
function createEEE() {
|
||||||
var tbl = document.getElementById('eeetable');
|
var tbl = document.getElementById('eeetable');
|
||||||
if (tbl.rows.length <= 2 && numPorts) {
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
clearInterval(createEEEInterval);
|
|
||||||
console.log("CREATING TABLE ", tbl.rows.length);
|
console.log("CREATING TABLE ", tbl.rows.length);
|
||||||
for (let i = 2; i < 2 + numPorts; i++) {
|
for (let i = 2; i < 2 + numPorts; i++) {
|
||||||
console.log("Table row: " + i + "pState: " + pState[i-2]);
|
console.log("Table row: " + i + "pState: " + pState[i-2]);
|
||||||
const tr = tbl.insertRow();
|
const tr = tbl.insertRow();
|
||||||
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i-1)));
|
||||||
for (let j = 0; j < 7; j++) {
|
for (let j = 0; j < 7; j++) {
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(" "));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(" "));
|
||||||
}
|
}
|
||||||
@@ -29,8 +28,8 @@ function getEEE() {
|
|||||||
let tr = tbl.rows[n+1];
|
let tr = tbl.rows[n+1];
|
||||||
if (!p.isSFP) {
|
if (!p.isSFP) {
|
||||||
let eee = parseInt(p.eee,2); let lp = parseInt(p.eee_lp,2);
|
let eee = parseInt(p.eee,2); let lp = parseInt(p.eee_lp,2);
|
||||||
tr.cells[1].innerHTML = `${eee&4?"ON":"OFF"}`; tr.cells[2].innerHTML = `${eee&2?"ON":"OFF"}`; tr.cells[3].innerHTML = `${eee&1?"ON":"OFF"}`;
|
tr.cells[1].innerHTML = `${eee&4?t('eee_on'):t('eee_off')}`; tr.cells[2].innerHTML = `${eee&2?t('eee_on'):t('eee_off')}`; tr.cells[3].innerHTML = `${eee&1?t('eee_on'):t('eee_off')}`;
|
||||||
tr.cells[4].innerHTML = `${lp&4?"ON":"OFF"}`; tr.cells[5].innerHTML = `${lp&2?"ON":"OFF"}`; tr.cells[6].innerHTML = `${lp&1?"ON":"OFF"}`;
|
tr.cells[4].innerHTML = `${lp&4?t('eee_on'):t('eee_off')}`; tr.cells[5].innerHTML = `${lp&2?t('eee_on'):t('eee_off')}`; tr.cells[6].innerHTML = `${lp&1?t('eee_on'):t('eee_off')}`;
|
||||||
tr.cells[7].innerHTML = `${p.active}`;
|
tr.cells[7].innerHTML = `${p.active}`;
|
||||||
tr.classList.toggle('disabled', pState[i-2] < 0); tr.classList.toggle('isNOK', !p.active); tr.classList.toggle('isOK', p.active);
|
tr.classList.toggle('disabled', pState[i-2] < 0); tr.classList.toggle('isNOK', !p.active); tr.classList.toggle('isOK', p.active);
|
||||||
}
|
}
|
||||||
@@ -40,11 +39,14 @@ function getEEE() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", "/eee.json", true);
|
xhttp.open("GET", "/eee.json", true);
|
||||||
xhttp.timeout = 1500; xhttp.send();
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
createEEE();
|
||||||
getEEE();
|
getEEE();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
const iCount = setInterval(getEEE, 2000);
|
const iCount = setInterval(getEEE, 2000);
|
||||||
});
|
});
|
||||||
const createEEEInterval = setInterval(createEEE, 1000);
|
});
|
||||||
|
|||||||
@@ -0,0 +1,603 @@
|
|||||||
|
var LANG = {
|
||||||
|
en: {
|
||||||
|
nav_overview: 'Overview',
|
||||||
|
nav_port_config: 'Port Configuration',
|
||||||
|
nav_port_stat: 'Port Statistics',
|
||||||
|
nav_l2: 'L2 Configuration',
|
||||||
|
nav_mirror: 'Mirroring',
|
||||||
|
nav_lag: 'Link Aggregation',
|
||||||
|
nav_eee: 'EEE',
|
||||||
|
nav_bandwidth: 'Bandwidth Limits',
|
||||||
|
nav_system: 'System Settings',
|
||||||
|
nav_fw_update: 'Firmware Update',
|
||||||
|
|
||||||
|
port_name: 'Name',
|
||||||
|
port_status: 'Status',
|
||||||
|
port_not_enabled: 'Not enabled.',
|
||||||
|
port_link_speed: 'Link speed',
|
||||||
|
port_vendor: 'Vendor',
|
||||||
|
port_model: 'Model',
|
||||||
|
port_serial: 'Serial',
|
||||||
|
port_temp: 'Temp',
|
||||||
|
port_vcc: 'Vcc',
|
||||||
|
port_tx_fault: 'TX-Fault',
|
||||||
|
port_tx_disabled: 'TX-Disabled',
|
||||||
|
port_tx_bias: 'TX-Bias',
|
||||||
|
port_tx_power: 'TX-Power',
|
||||||
|
port_rx_power: 'RX-Power',
|
||||||
|
port_rx_los: 'RX-LOS',
|
||||||
|
|
||||||
|
speed_disabled: 'Disabled',
|
||||||
|
speed_down: 'Down',
|
||||||
|
|
||||||
|
port_title: 'FreeSwitchOS Port Configuration',
|
||||||
|
port_heading: 'Port Configuration',
|
||||||
|
port_col_port: 'Port',
|
||||||
|
port_col_name: 'Name',
|
||||||
|
port_col_speed: 'Current Link Speed',
|
||||||
|
port_col_set_speed: 'Set Speed',
|
||||||
|
port_col_disabled: 'Disabled',
|
||||||
|
port_col_apply: 'Apply',
|
||||||
|
port_mtu_heading: 'Configure Maximum Frame Size (MTU) forwarded at Port',
|
||||||
|
port_auto: 'Auto',
|
||||||
|
port_2500m: '2500MBit/Full',
|
||||||
|
port_1000m: '1000MBit/Full',
|
||||||
|
port_100m_f: '100MBit/Full',
|
||||||
|
port_100m_h: '100MBit/Half',
|
||||||
|
port_10m_f: '10MBit/Full',
|
||||||
|
port_10m_h: '10MBit/Half',
|
||||||
|
port_apply: 'Apply',
|
||||||
|
|
||||||
|
stat_title: 'FreeSwitchOS Port Statistics',
|
||||||
|
stat_heading: 'Port Statistics',
|
||||||
|
stat_detailed: 'Detailed Port Statistics',
|
||||||
|
stat_close: 'Close',
|
||||||
|
stat_col_port: 'Port',
|
||||||
|
stat_col_name: 'Name',
|
||||||
|
stat_col_link: 'link',
|
||||||
|
stat_col_tx_good: 'TX Good',
|
||||||
|
stat_col_tx_bad: 'TX Bad',
|
||||||
|
stat_col_rx_good: 'RX Good',
|
||||||
|
stat_col_rx_bad: 'RX Bad',
|
||||||
|
stat_col_all: 'All Counters',
|
||||||
|
stat_counter: 'Counter',
|
||||||
|
stat_value: 'Value',
|
||||||
|
stat_show: 'Show',
|
||||||
|
|
||||||
|
vlan_title: 'FreeSwitchOS VLAN Configuration',
|
||||||
|
vlan_heading: 'VLAN Configuration',
|
||||||
|
vlan_select: 'VLAN Select:',
|
||||||
|
vlan_choose: '— VLAN Choose —',
|
||||||
|
vlan_id: 'VLAN ID:',
|
||||||
|
vlan_get_config: 'Get Configuration',
|
||||||
|
vlan_name: 'VLAN Name:',
|
||||||
|
vlan_tagged: 'Tagged Ports',
|
||||||
|
vlan_untagged: 'Untagged Ports',
|
||||||
|
vlan_select_all: 'Select all',
|
||||||
|
vlan_pvid: 'Use as default VLAN for incoming traffic (PVID)',
|
||||||
|
vlan_update: 'Update / Create',
|
||||||
|
vlan_configured: 'Configured VLANs',
|
||||||
|
vlan_col_name: 'Name',
|
||||||
|
vlan_col_member: 'Member Ports',
|
||||||
|
vlan_col_tagged: 'Tagged Ports',
|
||||||
|
vlan_col_untagged: 'Untagged Ports',
|
||||||
|
vlan_col_pvid: 'PVID Ports',
|
||||||
|
vlan_col_delete: 'Delete',
|
||||||
|
vlan_set_id_first: 'Set VLAN ID first',
|
||||||
|
vlan_delete_confirm: 'Delete VLAN ',
|
||||||
|
|
||||||
|
lag_title: 'Link Aggregation Configuration',
|
||||||
|
lag_heading: 'Link Aggregation Groups Configuration',
|
||||||
|
lag_update: 'Update / Create',
|
||||||
|
|
||||||
|
mirror_title: 'Mirror Configuration',
|
||||||
|
mirror_heading: 'Mirror Configuration',
|
||||||
|
mirror_enabled: 'Enabled:',
|
||||||
|
mirror_port: 'Mirroring Port:',
|
||||||
|
mirror_tx: 'Mirrored Ports (TX)',
|
||||||
|
mirror_rx: 'Mirrored Ports (RX)',
|
||||||
|
mirror_update: 'Update / Create',
|
||||||
|
mirror_disable: 'Disable Mirroring',
|
||||||
|
mirror_set_port_first: 'Set Mirroring Port first',
|
||||||
|
mirror_select_ports: 'Select Mirrored Ports',
|
||||||
|
|
||||||
|
eee_title: 'EEE Configuration',
|
||||||
|
eee_heading: 'EEE Status',
|
||||||
|
eee_advertising: 'Advertising',
|
||||||
|
eee_partner: 'Link-Partner advertises',
|
||||||
|
eee_port: 'Port',
|
||||||
|
eee_active: 'Active?',
|
||||||
|
eee_enable: 'Enable EEE',
|
||||||
|
eee_disable: 'Disable EEE',
|
||||||
|
eee_on: 'ON',
|
||||||
|
eee_off: 'OFF',
|
||||||
|
|
||||||
|
l2_title: 'FreeSwitchOS L2 Configuration',
|
||||||
|
l2_heading: 'L2 Configuration',
|
||||||
|
l2_col_port: 'Port',
|
||||||
|
l2_col_type: 'Type',
|
||||||
|
l2_col_remove: 'Remove Entry',
|
||||||
|
l2_shown: 'Shown:',
|
||||||
|
l2_delete: 'Delete',
|
||||||
|
l2_static: 'static',
|
||||||
|
l2_learned: 'learned',
|
||||||
|
|
||||||
|
bw_title: 'Ingress and Egress Bandwidth',
|
||||||
|
bw_heading: 'Ingress and Egress Bandwidth',
|
||||||
|
bw_ingress: 'Ingress',
|
||||||
|
bw_egress: 'Egress',
|
||||||
|
bw_col_port: 'Port',
|
||||||
|
bw_col_limit: 'Limit',
|
||||||
|
bw_col_bandwidth: 'Bandwidth [kBit/s]',
|
||||||
|
bw_col_flow: 'Flow Control',
|
||||||
|
bw_col_apply: 'Apply',
|
||||||
|
bw_unlimited: 'UNLIMITED',
|
||||||
|
|
||||||
|
sys_title: 'System Settings',
|
||||||
|
sys_tab_system: 'System',
|
||||||
|
sys_tab_advanced: 'Advanced',
|
||||||
|
sys_tab_console: 'Console',
|
||||||
|
sys_heading: 'System Settings',
|
||||||
|
sys_ip: 'IP address:',
|
||||||
|
sys_model: 'Model:',
|
||||||
|
sys_hostname: 'Hostname:',
|
||||||
|
sys_apply: 'Apply',
|
||||||
|
sys_netmask: 'Netmask:',
|
||||||
|
sys_gateway: 'Gateway:',
|
||||||
|
sys_language: 'Language:',
|
||||||
|
sys_mgmt_vlan: 'Management VLAN:',
|
||||||
|
sys_mgmt_untagged: 'untagged',
|
||||||
|
sys_mgmt_confirm: 'Move switch management to VLAN ',
|
||||||
|
sys_mgmt_warn: 'The switch will start tagging its own traffic with that VLAN. If the port you are connected through does not carry it, this page becomes unreachable and the setting can only be undone over the console. Continue?',
|
||||||
|
sys_ip_note: 'When updating the above settings, remember to point your browser to the new IP afterwards:',
|
||||||
|
sys_update: 'Update Settings',
|
||||||
|
sys_save_label: 'Save all current settings to Flash:',
|
||||||
|
sys_save: 'Save Settings to Flash',
|
||||||
|
sys_advanced: 'Advanced Settings',
|
||||||
|
sys_startup_config: 'Startup configuration:',
|
||||||
|
sys_startup_warn: 'Be careful when saving the directly edited startup configuration, you can lock yourself out:',
|
||||||
|
sys_clear_config: 'Clear Startup Config',
|
||||||
|
sys_save_startup: 'Save Startup Settings to Flash',
|
||||||
|
sys_reset: 'Reset Switch',
|
||||||
|
sys_console: 'Console Command',
|
||||||
|
sys_enter_cmd: 'Enter command:',
|
||||||
|
sys_send_cmd: 'Send Command',
|
||||||
|
sys_console_warn: 'Be careful when entering console commands, you can lock yourself out!',
|
||||||
|
sys_invalid_ip: 'Invalid ip:',
|
||||||
|
sys_reset_confirm: 'Are you sure you want to reset the switch?',
|
||||||
|
sys_resetting: 'Switch is resetting. Please wait and refresh the page.',
|
||||||
|
|
||||||
|
login_title: 'RTL Switch Login',
|
||||||
|
login_heading: 'RTL Switch Login',
|
||||||
|
login_wrong: 'Wrong password!',
|
||||||
|
login_password: 'Password',
|
||||||
|
login_login: 'Login',
|
||||||
|
|
||||||
|
index_title: 'FreeSwitchOS Main Page',
|
||||||
|
index_heading: 'Switch Configuration',
|
||||||
|
index_settings: 'Settings',
|
||||||
|
|
||||||
|
update_title: 'Firmware update',
|
||||||
|
update_heading: 'Firmware Update',
|
||||||
|
update_instruction: 'Choose a firmware update file to upload:',
|
||||||
|
update_upload: 'Upload File',
|
||||||
|
|
||||||
|
common_port: 'Port ',
|
||||||
|
common_pkts: ' pkts',
|
||||||
|
},
|
||||||
|
|
||||||
|
ja: {
|
||||||
|
nav_overview: '概要',
|
||||||
|
nav_port_config: 'ポート設定',
|
||||||
|
nav_port_stat: 'ポート統計',
|
||||||
|
nav_l2: 'L2 設定',
|
||||||
|
nav_mirror: 'ミラーリング',
|
||||||
|
nav_lag: 'リンクアグリゲーション',
|
||||||
|
nav_eee: 'EEE',
|
||||||
|
nav_bandwidth: '帯域制限',
|
||||||
|
nav_system: 'システム設定',
|
||||||
|
nav_fw_update: 'ファームウェア更新',
|
||||||
|
|
||||||
|
port_name: '名前',
|
||||||
|
port_status: '状態',
|
||||||
|
port_not_enabled: '無効',
|
||||||
|
port_link_speed: 'リンク速度',
|
||||||
|
port_vendor: 'ベンダー',
|
||||||
|
port_model: 'モデル',
|
||||||
|
port_serial: 'シリアル',
|
||||||
|
port_temp: '温度',
|
||||||
|
port_vcc: '電圧',
|
||||||
|
port_tx_fault: 'TX 障害',
|
||||||
|
port_tx_disabled: 'TX 無効',
|
||||||
|
port_tx_bias: 'TX バイアス',
|
||||||
|
port_tx_power: 'TX 電力',
|
||||||
|
port_rx_power: 'RX 電力',
|
||||||
|
port_rx_los: 'RX 信号ロス',
|
||||||
|
|
||||||
|
speed_disabled: '無効',
|
||||||
|
speed_down: 'リンクダウン',
|
||||||
|
|
||||||
|
port_title: 'FreeSwitchOS ポート設定',
|
||||||
|
port_heading: 'ポート設定',
|
||||||
|
port_col_port: 'ポート',
|
||||||
|
port_col_name: '名前',
|
||||||
|
port_col_speed: '現在のリンク速度',
|
||||||
|
port_col_set_speed: '速度設定',
|
||||||
|
port_col_disabled: '無効',
|
||||||
|
port_col_apply: '適用',
|
||||||
|
port_mtu_heading: 'ポートの最大フレームサイズ (MTU) 設定',
|
||||||
|
port_auto: '自動',
|
||||||
|
port_2500m: '2500Mbps/全二重',
|
||||||
|
port_1000m: '1000Mbps/全二重',
|
||||||
|
port_100m_f: '100Mbps/全二重',
|
||||||
|
port_100m_h: '100Mbps/半二重',
|
||||||
|
port_10m_f: '10Mbps/全二重',
|
||||||
|
port_10m_h: '10Mbps/半二重',
|
||||||
|
port_apply: '適用',
|
||||||
|
|
||||||
|
stat_title: 'FreeSwitchOS ポート統計',
|
||||||
|
stat_heading: 'ポート統計',
|
||||||
|
stat_detailed: '詳細ポート統計',
|
||||||
|
stat_close: '閉じる',
|
||||||
|
stat_col_port: 'ポート',
|
||||||
|
stat_col_name: '名前',
|
||||||
|
stat_col_link: 'リンク',
|
||||||
|
stat_col_tx_good: 'TX 正常',
|
||||||
|
stat_col_tx_bad: 'TX 異常',
|
||||||
|
stat_col_rx_good: 'RX 正常',
|
||||||
|
stat_col_rx_bad: 'RX 異常',
|
||||||
|
stat_col_all: '全カウンタ',
|
||||||
|
stat_counter: 'カウンタ',
|
||||||
|
stat_value: '値',
|
||||||
|
stat_show: '表示',
|
||||||
|
|
||||||
|
vlan_title: 'FreeSwitchOS VLAN 設定',
|
||||||
|
vlan_heading: 'VLAN 設定',
|
||||||
|
vlan_select: 'VLAN 選択:',
|
||||||
|
vlan_choose: '— VLAN 選択 —',
|
||||||
|
vlan_id: 'VLAN ID:',
|
||||||
|
vlan_get_config: '設定取得',
|
||||||
|
vlan_name: 'VLAN 名:',
|
||||||
|
vlan_tagged: 'タグ付きポート',
|
||||||
|
vlan_untagged: 'タグ無しポート',
|
||||||
|
vlan_select_all: 'すべて選択',
|
||||||
|
vlan_pvid: '受信トラフィックのデフォルト VLAN (PVID)',
|
||||||
|
vlan_update: '更新 / 作成',
|
||||||
|
vlan_configured: '設定済み VLAN',
|
||||||
|
vlan_col_name: '名前',
|
||||||
|
vlan_col_member: 'メンバーポート',
|
||||||
|
vlan_col_tagged: 'タグ付きポート',
|
||||||
|
vlan_col_untagged: 'タグ無しポート',
|
||||||
|
vlan_col_pvid: 'PVID ポート',
|
||||||
|
vlan_col_delete: '削除',
|
||||||
|
vlan_set_id_first: 'VLAN ID を先に設定してください',
|
||||||
|
vlan_delete_confirm: 'VLAN 削除 ',
|
||||||
|
|
||||||
|
lag_title: 'リンクアグリゲーション設定',
|
||||||
|
lag_heading: 'リンクアグリゲーショングループ設定',
|
||||||
|
lag_update: '更新 / 作成',
|
||||||
|
|
||||||
|
mirror_title: 'ミラーリング設定',
|
||||||
|
mirror_heading: 'ミラーリング設定',
|
||||||
|
mirror_enabled: '有効:',
|
||||||
|
mirror_port: 'ミラーポート:',
|
||||||
|
mirror_tx: 'ミラー元ポート (TX)',
|
||||||
|
mirror_rx: 'ミラー元ポート (RX)',
|
||||||
|
mirror_update: '更新 / 作成',
|
||||||
|
mirror_disable: 'ミラーリング無効化',
|
||||||
|
mirror_set_port_first: 'ミラーポートを先に設定してください',
|
||||||
|
mirror_select_ports: 'ミラー元ポートを選択してください',
|
||||||
|
|
||||||
|
eee_title: 'EEE 設定',
|
||||||
|
eee_heading: 'EEE 状態',
|
||||||
|
eee_advertising: 'EEE アドバタイジング',
|
||||||
|
eee_partner: 'リンクパートナー広告',
|
||||||
|
eee_port: 'ポート',
|
||||||
|
eee_active: '有効?',
|
||||||
|
eee_enable: 'EEE 有効化',
|
||||||
|
eee_disable: 'EEE 無効化',
|
||||||
|
eee_on: 'オン',
|
||||||
|
eee_off: 'オフ',
|
||||||
|
|
||||||
|
l2_title: 'FreeSwitchOS L2 設定',
|
||||||
|
l2_heading: 'L2 設定',
|
||||||
|
l2_col_port: 'ポート',
|
||||||
|
l2_col_type: 'タイプ',
|
||||||
|
l2_col_remove: 'エントリ削除',
|
||||||
|
l2_shown: 'Shown:',
|
||||||
|
l2_delete: '削除',
|
||||||
|
l2_static: '静的',
|
||||||
|
l2_learned: '学習',
|
||||||
|
|
||||||
|
bw_title: '入力/出力帯域制限',
|
||||||
|
bw_heading: '入力/出力帯域制限',
|
||||||
|
bw_ingress: '入力',
|
||||||
|
bw_egress: '出力',
|
||||||
|
bw_col_port: 'ポート',
|
||||||
|
bw_col_limit: '制限',
|
||||||
|
bw_col_bandwidth: '帯域 [kbps]',
|
||||||
|
bw_col_flow: 'フロー制御',
|
||||||
|
bw_col_apply: '適用',
|
||||||
|
bw_unlimited: '制限無し',
|
||||||
|
|
||||||
|
sys_title: 'システム設定',
|
||||||
|
sys_tab_system: 'システム',
|
||||||
|
sys_tab_advanced: '詳細設定',
|
||||||
|
sys_tab_console: 'コンソール',
|
||||||
|
sys_heading: 'システム設定',
|
||||||
|
sys_ip: 'IP アドレス:',
|
||||||
|
sys_model: 'モデル:',
|
||||||
|
sys_hostname: 'ホスト名:',
|
||||||
|
sys_apply: '適用',
|
||||||
|
sys_netmask: 'ネットマスク:',
|
||||||
|
sys_gateway: 'ゲートウェイ:',
|
||||||
|
sys_language: '言語:',
|
||||||
|
sys_mgmt_vlan: 'Management VLAN:',
|
||||||
|
sys_mgmt_untagged: 'untagged',
|
||||||
|
sys_mgmt_confirm: 'Move switch management to VLAN ',
|
||||||
|
sys_mgmt_warn: 'The switch will start tagging its own traffic with that VLAN. If the port you are connected through does not carry it, this page becomes unreachable and the setting can only be undone over the console. Continue?',
|
||||||
|
sys_ip_note: '上記設定を変更した場合は、ブラウザで新しい IP にアクセスしてください:',
|
||||||
|
sys_update: '設定更新',
|
||||||
|
sys_save_label: '現在の設定をフラッシュに保存:',
|
||||||
|
sys_save: '設定をフラッシュに保存',
|
||||||
|
sys_advanced: '詳細設定',
|
||||||
|
sys_startup_config: '起動設定:',
|
||||||
|
sys_startup_warn: '起動設定を直接編集する際は注意してください。ロックアウトされる可能性があります:',
|
||||||
|
sys_clear_config: '起動設定クリア',
|
||||||
|
sys_save_startup: '起動設定をフラッシュに保存',
|
||||||
|
sys_reset: 'スイッチ再起動',
|
||||||
|
sys_console: 'コンソールコマンド',
|
||||||
|
sys_enter_cmd: 'コマンド入力:',
|
||||||
|
sys_send_cmd: 'コマンド送信',
|
||||||
|
sys_console_warn: 'コンソールコマンドは注意して入力してください。ロックアウトされる可能性があります!',
|
||||||
|
sys_invalid_ip: '無効な IP: ',
|
||||||
|
sys_reset_confirm: 'スイッチを再起動してもよろしいですか?',
|
||||||
|
sys_resetting: 'スイッチを再起動中です。しばらく待ってからページをリロードしてください。',
|
||||||
|
|
||||||
|
login_title: 'RTL スイッチ ログイン',
|
||||||
|
login_heading: 'RTL スイッチ ログイン',
|
||||||
|
login_wrong: 'パスワードが違います!',
|
||||||
|
login_password: 'パスワード',
|
||||||
|
login_login: 'ログイン',
|
||||||
|
|
||||||
|
index_title: 'FreeSwitchOS メインページ',
|
||||||
|
index_heading: 'スイッチ設定',
|
||||||
|
index_settings: '設定',
|
||||||
|
|
||||||
|
update_title: 'ファームウェア更新',
|
||||||
|
update_heading: 'ファームウェア更新',
|
||||||
|
update_instruction: 'アップロードするファームウェアファイルを選択:',
|
||||||
|
update_upload: 'ファイルをアップロード',
|
||||||
|
|
||||||
|
common_port: 'ポート ',
|
||||||
|
common_pkts: ' pkts',
|
||||||
|
},
|
||||||
|
|
||||||
|
zh: {
|
||||||
|
nav_overview: '概览',
|
||||||
|
nav_port_config: '端口配置',
|
||||||
|
nav_port_stat: '端口统计',
|
||||||
|
nav_l2: 'L2 配置',
|
||||||
|
nav_mirror: '端口镜像',
|
||||||
|
nav_lag: '链路聚合',
|
||||||
|
nav_eee: 'EEE',
|
||||||
|
nav_bandwidth: '带宽限制',
|
||||||
|
nav_system: '系统设置',
|
||||||
|
nav_fw_update: '固件升级',
|
||||||
|
|
||||||
|
port_name: '名称',
|
||||||
|
port_status: '状态',
|
||||||
|
port_not_enabled: '未启用。',
|
||||||
|
port_link_speed: '链路速率',
|
||||||
|
port_vendor: '厂商',
|
||||||
|
port_model: '型号',
|
||||||
|
port_serial: '序列号',
|
||||||
|
port_temp: '温度',
|
||||||
|
port_vcc: '供电电压',
|
||||||
|
port_tx_fault: 'TX 故障',
|
||||||
|
port_tx_disabled: 'TX 禁用',
|
||||||
|
port_tx_bias: 'TX 偏置电流',
|
||||||
|
port_tx_power: 'TX 光功率',
|
||||||
|
port_rx_power: 'RX 光功率',
|
||||||
|
port_rx_los: 'RX 信号丢失',
|
||||||
|
|
||||||
|
speed_disabled: '禁用',
|
||||||
|
speed_down: '未连接',
|
||||||
|
|
||||||
|
port_title: 'FreeSwitchOS 端口配置',
|
||||||
|
port_heading: '端口配置',
|
||||||
|
port_col_port: '端口',
|
||||||
|
port_col_name: '名称',
|
||||||
|
port_col_speed: '当前链路速率',
|
||||||
|
port_col_set_speed: '设置速率',
|
||||||
|
port_col_disabled: '禁用',
|
||||||
|
port_col_apply: '应用',
|
||||||
|
port_mtu_heading: '配置端口转发的最大帧大小 (MTU)',
|
||||||
|
port_auto: '自动',
|
||||||
|
port_2500m: '2500Mbps/全双工',
|
||||||
|
port_1000m: '1000Mbps/全双工',
|
||||||
|
port_100m_f: '100Mbps/全双工',
|
||||||
|
port_100m_h: '100Mbps/半双工',
|
||||||
|
port_10m_f: '10Mbps/全双工',
|
||||||
|
port_10m_h: '10Mbps/半双工',
|
||||||
|
port_apply: '应用',
|
||||||
|
|
||||||
|
stat_title: 'FreeSwitchOS 端口统计',
|
||||||
|
stat_heading: '端口统计',
|
||||||
|
stat_detailed: '详细端口统计',
|
||||||
|
stat_close: '关闭',
|
||||||
|
stat_col_port: '端口',
|
||||||
|
stat_col_name: '名称',
|
||||||
|
stat_col_link: '链路',
|
||||||
|
stat_col_tx_good: 'TX 正常包',
|
||||||
|
stat_col_tx_bad: 'TX 错误包',
|
||||||
|
stat_col_rx_good: 'RX 正常包',
|
||||||
|
stat_col_rx_bad: 'RX 错误包',
|
||||||
|
stat_col_all: '所有计数器',
|
||||||
|
stat_counter: '计数器',
|
||||||
|
stat_value: '值',
|
||||||
|
stat_show: '查看',
|
||||||
|
|
||||||
|
vlan_title: 'FreeSwitchOS VLAN 配置',
|
||||||
|
vlan_heading: 'VLAN 配置',
|
||||||
|
vlan_select: 'VLAN 选择:',
|
||||||
|
vlan_choose: '-- 请选择 VLAN --',
|
||||||
|
vlan_id: 'VLAN ID:',
|
||||||
|
vlan_get_config: '获取配置',
|
||||||
|
vlan_name: 'VLAN 名称:',
|
||||||
|
vlan_tagged: 'Tagged 端口',
|
||||||
|
vlan_untagged: 'Untagged 端口',
|
||||||
|
vlan_select_all: '全选',
|
||||||
|
vlan_pvid: '作为入方向流量的默认 VLAN (PVID)',
|
||||||
|
vlan_update: '更新 / 创建',
|
||||||
|
vlan_configured: '已配置 VLAN',
|
||||||
|
vlan_col_name: '名称',
|
||||||
|
vlan_col_member: '成员端口',
|
||||||
|
vlan_col_tagged: 'Tagged 端口',
|
||||||
|
vlan_col_untagged: 'Untagged 端口',
|
||||||
|
vlan_col_pvid: 'PVID 端口',
|
||||||
|
vlan_col_delete: '删除',
|
||||||
|
vlan_set_id_first: '请先设置 VLAN ID',
|
||||||
|
vlan_delete_confirm: '删除 VLAN ',
|
||||||
|
|
||||||
|
lag_title: '链路聚合配置',
|
||||||
|
lag_heading: '链路聚合组配置',
|
||||||
|
lag_update: '更新 / 创建',
|
||||||
|
|
||||||
|
mirror_title: '端口镜像配置',
|
||||||
|
mirror_heading: '端口镜像配置',
|
||||||
|
mirror_enabled: '启用:',
|
||||||
|
mirror_port: '镜像目的端口:',
|
||||||
|
mirror_tx: '被镜像端口 (TX)',
|
||||||
|
mirror_rx: '被镜像端口 (RX)',
|
||||||
|
mirror_update: '更新 / 创建',
|
||||||
|
mirror_disable: '禁用端口镜像',
|
||||||
|
mirror_set_port_first: '请先设置镜像目的端口',
|
||||||
|
mirror_select_ports: '请选择被镜像端口',
|
||||||
|
|
||||||
|
eee_title: 'EEE 配置',
|
||||||
|
eee_heading: 'EEE 状态',
|
||||||
|
eee_advertising: '本端通告',
|
||||||
|
eee_partner: '链路伙伴通告',
|
||||||
|
eee_port: '端口',
|
||||||
|
eee_active: '已生效?',
|
||||||
|
eee_enable: '启用 EEE',
|
||||||
|
eee_disable: '禁用 EEE',
|
||||||
|
eee_on: '开',
|
||||||
|
eee_off: '关',
|
||||||
|
|
||||||
|
l2_title: 'FreeSwitchOS L2 配置',
|
||||||
|
l2_heading: 'L2 配置',
|
||||||
|
l2_col_port: '端口',
|
||||||
|
l2_col_type: '类型',
|
||||||
|
l2_col_remove: '删除条目',
|
||||||
|
l2_shown: 'Shown:',
|
||||||
|
l2_delete: '删除',
|
||||||
|
l2_static: '静态',
|
||||||
|
l2_learned: '动态学习',
|
||||||
|
|
||||||
|
bw_title: '入方向/出方向带宽限制',
|
||||||
|
bw_heading: '入方向/出方向带宽限制',
|
||||||
|
bw_ingress: '入方向',
|
||||||
|
bw_egress: '出方向',
|
||||||
|
bw_col_port: '端口',
|
||||||
|
bw_col_limit: '限速',
|
||||||
|
bw_col_bandwidth: '带宽 [kbit/s]',
|
||||||
|
bw_col_flow: '流量控制',
|
||||||
|
bw_col_apply: '应用',
|
||||||
|
bw_unlimited: '不限速',
|
||||||
|
|
||||||
|
sys_title: '系统设置',
|
||||||
|
sys_tab_system: '系统',
|
||||||
|
sys_tab_advanced: '高级',
|
||||||
|
sys_tab_console: '控制台',
|
||||||
|
sys_heading: '系统设置',
|
||||||
|
sys_ip: 'IP 地址:',
|
||||||
|
sys_model: '型号:',
|
||||||
|
sys_hostname: '主机名:',
|
||||||
|
sys_apply: '应用',
|
||||||
|
sys_netmask: '子网掩码:',
|
||||||
|
sys_gateway: '网关:',
|
||||||
|
sys_language: '语言:',
|
||||||
|
sys_mgmt_vlan: 'Management VLAN:',
|
||||||
|
sys_mgmt_untagged: 'untagged',
|
||||||
|
sys_mgmt_confirm: 'Move switch management to VLAN ',
|
||||||
|
sys_mgmt_warn: 'The switch will start tagging its own traffic with that VLAN. If the port you are connected through does not carry it, this page becomes unreachable and the setting can only be undone over the console. Continue?',
|
||||||
|
sys_ip_note: '更新上述设置后,请使用新的 IP 地址重新访问管理界面:',
|
||||||
|
sys_update: '更新设置',
|
||||||
|
sys_save_label: '将当前全部设置保存到 Flash:',
|
||||||
|
sys_save: '保存设置到 Flash',
|
||||||
|
sys_advanced: '高级设置',
|
||||||
|
sys_startup_config: '启动配置:',
|
||||||
|
sys_startup_warn: '直接编辑启动配置时请谨慎,错误配置可能导致无法访问设备:',
|
||||||
|
sys_clear_config: '清除启动配置',
|
||||||
|
sys_save_startup: '保存启动配置到 Flash',
|
||||||
|
sys_reset: '重启交换机',
|
||||||
|
sys_console: '控制台命令',
|
||||||
|
sys_enter_cmd: '输入命令:',
|
||||||
|
sys_send_cmd: '发送命令',
|
||||||
|
sys_console_warn: '输入控制台命令时请谨慎,错误命令可能导致无法访问设备!',
|
||||||
|
sys_invalid_ip: '无效 IP: ',
|
||||||
|
sys_reset_confirm: '确定要重启交换机吗?',
|
||||||
|
sys_resetting: '交换机正在重启。请稍候并刷新页面。',
|
||||||
|
|
||||||
|
login_title: 'RTL 交换机登录',
|
||||||
|
login_heading: 'RTL 交换机登录',
|
||||||
|
login_wrong: '密码错误!',
|
||||||
|
login_password: '密码',
|
||||||
|
login_login: '登录',
|
||||||
|
|
||||||
|
index_title: 'FreeSwitchOS 主页',
|
||||||
|
index_heading: '交换机配置',
|
||||||
|
index_settings: '设置',
|
||||||
|
|
||||||
|
update_title: '固件升级',
|
||||||
|
update_heading: '固件升级',
|
||||||
|
update_instruction: '请选择要上传的固件文件:',
|
||||||
|
update_upload: '上传文件',
|
||||||
|
|
||||||
|
common_port: '端口 ',
|
||||||
|
common_pkts: ' 个包',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var rtlLang = (function() {
|
||||||
|
var saved = localStorage.getItem('rtl_lang');
|
||||||
|
if (saved && LANG[saved]) return saved;
|
||||||
|
var browser = (navigator.language || navigator.userLanguage || 'en').substring(0, 2);
|
||||||
|
return LANG[browser] ? browser : 'en';
|
||||||
|
})();
|
||||||
|
|
||||||
|
function t(key) {
|
||||||
|
return LANG[rtlLang][key] || LANG['en'][key] || key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLang(lang) {
|
||||||
|
if (LANG[lang]) {
|
||||||
|
localStorage.setItem('rtl_lang', lang);
|
||||||
|
rtlLang = lang;
|
||||||
|
document.querySelectorAll('[data-i18n]').forEach(function(el) {
|
||||||
|
applyTranslation(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTranslation(el) {
|
||||||
|
var key = el.getAttribute('data-i18n');
|
||||||
|
if (!key) return;
|
||||||
|
if (el.tagName === 'INPUT' && (el.type === 'submit' || el.type === 'button')) {
|
||||||
|
el.value = t(key);
|
||||||
|
} else if (el.tagName === 'OPTION') {
|
||||||
|
el.textContent = t(key);
|
||||||
|
} else if (el.tagName === 'TITLE') {
|
||||||
|
el.textContent = t(key);
|
||||||
|
} else {
|
||||||
|
el.innerHTML = t(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('[data-i18n]').forEach(function(el) {
|
||||||
|
applyTranslation(el);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,18 +2,26 @@
|
|||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
<script src="/main_info.js"></script>
|
<script src="/main_info.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>FreeSwitchOS Main Page</title>
|
<title data-i18n="index_title">FreeSwitchOS Main Page</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>Switch Configuration</h1>
|
<h1 data-i18n="index_heading">Switch Configuration</h1>
|
||||||
<table id="infoTable">
|
<table id="infoTable">
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">Settings</th>
|
<th colspan="2" data-i18n="index_settings">Settings</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>FreeSwitchOS L2 Configuration</title>
|
<title data-i18n="l2_title">FreeSwitchOS L2 Configuration</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>L2 Configuration</h1>
|
<h1 data-i18n="l2_heading">L2 Configuration</h1>
|
||||||
|
<p><span data-i18n="l2_shown">Shown:</span> <span id="l2count">-</span></p>
|
||||||
<table id="l2table">
|
<table id="l2table">
|
||||||
<tr> <th>Port</th> <th>MAC</th> <th>VLAN</th> <th>Type</th> <th>Remove Entry</th></tr>
|
<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>
|
||||||
<script src="/l2.js"></script>
|
<script src="/l2.js"></script>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,22 +9,22 @@ function fillStats() {
|
|||||||
if (tbl.rows.length > 1) {
|
if (tbl.rows.length > 1) {
|
||||||
for (let i = 0; i < numPorts; i++) {
|
for (let i = 0; i < numPorts; i++) {
|
||||||
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
|
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
|
||||||
tbl.rows[i+1].cells[1].innerHTML = `${linkS[pState[i]+1]}`;
|
tbl.rows[i+1].cells[1].innerHTML = linkText(pState[i]+1);
|
||||||
tbl.rows[i+1].cells[2].innerHTML = `${txG[i]} pkts`;
|
tbl.rows[i+1].cells[2].innerHTML = `${txG[i]}` + t('common_pkts');
|
||||||
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]} pkts`;
|
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]}` + t('common_pkts');
|
||||||
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]} pkts`;
|
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]}` + t('common_pkts');
|
||||||
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`;
|
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]}` + t('common_pkts');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < numPorts; i++) {
|
for (let i = 0; i < numPorts; i++) {
|
||||||
console.log("Table row: " + i);
|
console.log("Table row: " + i);
|
||||||
const tr = tbl.insertRow();
|
const tr = tbl.insertRow();
|
||||||
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`));
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i+1)));
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(linkText(pState[i]+1)));
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]}` + t('common_pkts')));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]}` + t('common_pkts')));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]}` + t('common_pkts')));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]}` + t('common_pkts')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,6 +64,51 @@ function delL2(idx) {
|
|||||||
xhttp.timeout = 1500; xhttp.send();
|
xhttp.timeout = 1500; xhttp.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var l2All = [];
|
||||||
|
const l2Cols = ['port', 'mac', 'vlan', 'type'];
|
||||||
|
var l2SortCol = 'port';
|
||||||
|
var l2SortDir = 1;
|
||||||
|
|
||||||
|
function l2Key(e, col) {
|
||||||
|
if (col === 'port') return e.port === 'CPU' ? Number.MAX_SAFE_INTEGER : Number(e.port);
|
||||||
|
if (col === 'vlan') return Number(e.vlan);
|
||||||
|
return String(e[col]).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function l2SortBy(col) {
|
||||||
|
l2SortDir = (col === l2SortCol) ? -l2SortDir : 1;
|
||||||
|
l2SortCol = col;
|
||||||
|
renderL2();
|
||||||
|
}
|
||||||
|
|
||||||
|
function l2FilterChanged() { renderL2(); }
|
||||||
|
|
||||||
|
function renderL2() {
|
||||||
|
var tbl = document.getElementById('l2table');
|
||||||
|
if (!tbl) return;
|
||||||
|
var f = {};
|
||||||
|
l2Cols.forEach(function(c) {
|
||||||
|
var el = document.getElementById('l2f_' + c);
|
||||||
|
f[c] = el ? el.value.trim().toLowerCase() : '';
|
||||||
|
});
|
||||||
|
var rows = l2All.filter(function(e) {
|
||||||
|
return l2Cols.every(function(c) {
|
||||||
|
return !f[c] || String(e[c]).toLowerCase().indexOf(f[c]) !== -1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
rows.sort(function(a, b) {
|
||||||
|
var x = l2Key(a, l2SortCol), y = l2Key(b, l2SortCol);
|
||||||
|
return (x < y ? -1 : x > y ? 1 : 0) * l2SortDir;
|
||||||
|
});
|
||||||
|
l2Cols.forEach(function(c) {
|
||||||
|
var a = document.getElementById('l2a_' + c);
|
||||||
|
if (a) a.textContent = (c === l2SortCol) ? (l2SortDir > 0 ? ' \u25b2' : ' \u25bc') : ' \u21c5';
|
||||||
|
});
|
||||||
|
paintL2(tbl, rows);
|
||||||
|
var cnt = document.getElementById('l2count');
|
||||||
|
if (cnt) cnt.textContent = rows.length + ' / ' + l2All.length;
|
||||||
|
}
|
||||||
|
|
||||||
function fillL2(s)
|
function fillL2(s)
|
||||||
{
|
{
|
||||||
var tbl = document.getElementById('l2table');
|
var tbl = document.getElementById('l2table');
|
||||||
@@ -71,7 +116,13 @@ function fillL2(s)
|
|||||||
return;
|
return;
|
||||||
s.sort(l2CMP);
|
s.sort(l2CMP);
|
||||||
s = uniq(s);
|
s = uniq(s);
|
||||||
var s = s.map(function(e) { e.port = e.port != 9 ? e.port : "CPU"; return e; });
|
l2All = s;
|
||||||
|
renderL2();
|
||||||
|
l2Entries = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintL2(tbl, s)
|
||||||
|
{
|
||||||
console.log("L2: ", JSON.stringify(s));
|
console.log("L2: ", JSON.stringify(s));
|
||||||
for (let i = 0; i < s.length; i++) {
|
for (let i = 0; i < s.length; i++) {
|
||||||
var e = s[i];
|
var e = s[i];
|
||||||
@@ -80,19 +131,19 @@ function fillL2(s)
|
|||||||
tbl.rows[i+1].cells[0].innerHTML = `${e.port}`;
|
tbl.rows[i+1].cells[0].innerHTML = `${e.port}`;
|
||||||
tbl.rows[i+1].cells[1].innerHTML = `${e.mac}`;
|
tbl.rows[i+1].cells[1].innerHTML = `${e.mac}`;
|
||||||
tbl.rows[i+1].cells[2].innerHTML = `${e.vlan}`;
|
tbl.rows[i+1].cells[2].innerHTML = `${e.vlan}`;
|
||||||
tbl.rows[i+1].cells[4].innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">Delete</button>';
|
tbl.rows[i+1].cells[3].innerHTML = `${e.type}`;
|
||||||
|
tbl.rows[i+1].cells[4].innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">' + t('l2_delete') + '</button>';
|
||||||
} else {
|
} else {
|
||||||
const tr = tbl.insertRow();
|
const tr = tbl.insertRow();
|
||||||
let td = tr.insertCell(); td.innerHTML = `${e.port}`;
|
let td = tr.insertCell(); td.innerHTML = `${e.port}`;
|
||||||
td = tr.insertCell(); td.innerHTML = `${e.mac}`;
|
td = tr.insertCell(); td.innerHTML = `${e.mac}`;
|
||||||
td = tr.insertCell(); td.innerHTML = `${e.vlan}`;
|
td = tr.insertCell(); td.innerHTML = `${e.vlan}`;
|
||||||
td = tr.insertCell(); td.innerHTML = `${e.type}`;
|
td = tr.insertCell(); td.innerHTML = `${e.type}`;
|
||||||
td = tr.insertCell(); td.innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">Delete</button>';
|
td = tr.insertCell(); td.innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">' + t('l2_delete') + '</button>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = tbl.rows.length - 1; i > s.length; i--)
|
for (let i = tbl.rows.length - 1; i > s.length; i--)
|
||||||
tbl.deleteRow(i);
|
tbl.deleteRow(i);
|
||||||
l2Entries = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getL2() {
|
function getL2() {
|
||||||
@@ -103,8 +154,8 @@ function getL2() {
|
|||||||
var s = s.map(function(e) {
|
var s = s.map(function(e) {
|
||||||
e.vlan = parseInt(e.vlan, 16);
|
e.vlan = parseInt(e.vlan, 16);
|
||||||
e.idx = parseInt(e.idx, 16);
|
e.idx = parseInt(e.idx, 16);
|
||||||
e.type = e.type == "s" ? "static" : "learned";
|
e.type = e.type == "s" ? t('l2_static') : t('l2_learned');
|
||||||
e.port = e.port == 9 ? 9 : logToPhysPort[e.port];
|
e.port = e.port == 9 ? 'CPU' : logToPhysPort[e.port];
|
||||||
return e;
|
return e;
|
||||||
});
|
});
|
||||||
l2Entries.push(...s);
|
l2Entries.push(...s);
|
||||||
@@ -130,10 +181,14 @@ function getL2() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
|
xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
|
||||||
xhttp.timeout = 1500; xhttp.send();
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
getL2();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
l2GetInterval = setInterval(getL2, 1000);
|
l2GetInterval = setInterval(getL2, 1000);
|
||||||
|
});;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>Link Aggregation Configuration</title>
|
<title data-i18n="lag_title">Link Aggregation Configuration</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>Link Aggregation Groups Configuration</h1>
|
<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" value="Update / Create"></h2>
|
<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>
|
<div id="mLAG0"></div>
|
||||||
<br />
|
<br />
|
||||||
<h2>LAG 2 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub1" onclick="lagSub(1);" type="button" value="Update / Create"></h2>
|
<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>
|
<div id="mLAG1"></div>
|
||||||
<br />
|
<br />
|
||||||
<h2>LAG 3 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub2" onclick="lagSub(2);" type="button" value="Update / Create"></h2>
|
<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>
|
<div id="mLAG2"></div>
|
||||||
<br />
|
<br />
|
||||||
<h2>LAG 4 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub3" onclick="lagSub(3);" type="button" value="Update / Create"></h2>
|
<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 id="mLAG3"></div>
|
||||||
<script src="/lag.js"></script>
|
<script src="/lag.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ var lagInterval = Number();
|
|||||||
function lagForm() {
|
function lagForm() {
|
||||||
if (!numPorts)
|
if (!numPorts)
|
||||||
return;
|
return;
|
||||||
clearInterval(lagInterval);
|
|
||||||
for (let j=0; j < 4; j++) {
|
for (let j=0; j < 4; j++) {
|
||||||
var lag = "mLAG" + j
|
var lag = "mLAG" + j
|
||||||
console.log("Adding LAG " + lag)
|
console.log("Adding LAG " + lag)
|
||||||
@@ -35,9 +34,6 @@ function setL(p, c){
|
|||||||
console.log("LAG setting: ", p, " to ", c);
|
console.log("LAG setting: ", p, " to ", c);
|
||||||
document.getElementById(p).checked=c;
|
document.getElementById(p).checked=c;
|
||||||
}
|
}
|
||||||
window.addEventListener("load", function() {
|
|
||||||
lagInterval = setInterval(lagForm, 200);
|
|
||||||
});
|
|
||||||
|
|
||||||
function fetchLag() {
|
function fetchLag() {
|
||||||
var xhttp = new XMLHttpRequest();
|
var xhttp = new XMLHttpRequest();
|
||||||
@@ -58,7 +54,7 @@ function fetchLag() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", `/lag.json`, true);
|
xhttp.open("GET", `/lag.json`, true);
|
||||||
xhttp.send();
|
sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
async function lagSub(l) {
|
async function lagSub(l) {
|
||||||
var cmd = "lag " + l;
|
var cmd = "lag " + l;
|
||||||
@@ -76,3 +72,10 @@ async function lagSub(l) {
|
|||||||
console.error(`Error: ${err}`);
|
console.error(`Error: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
lagForm();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<title>RTL Switch Login</title>
|
<title data-i18n="login_title">RTL Switch Login</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function removeNote() {
|
function removeNote() {
|
||||||
document.getElementById("incorrect").innerHTML = "";
|
document.getElementById("incorrect").innerHTML = "";
|
||||||
}
|
}
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
if (document.referrer.endsWith("login.html"))
|
if (document.referrer.endsWith("login.html"))
|
||||||
document.getElementById("incorrect").innerHTML = "Wrong password!";
|
document.getElementById("incorrect").innerHTML = t('login_wrong');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="login_page">
|
<body class="login_page">
|
||||||
<div class = "center">
|
<div class = "center">
|
||||||
<h1> RTL Switch Login</h1>
|
<h1 data-i18n="login_heading"> RTL Switch Login</h1>
|
||||||
<form method="post" action="login">
|
<form method="post" action="login">
|
||||||
<div class="txt_field">
|
<div class="txt_field">
|
||||||
<input name="pwd" type="password" onclick="removeNote()" required />
|
<input name="pwd" type="password" autocomplete="current-password" onclick="removeNote()" required />
|
||||||
<span></span>
|
<span></span>
|
||||||
<label>Password</label>
|
<label data-i18n="login_password">Password</label>
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" value="Login"/>
|
<input type="submit" data-i18n="login_login" value="Login"/>
|
||||||
<h3 id="incorrect" style="margin-top: 5em;"></h3>
|
<h3 id="incorrect" style="margin-top: 5em;"></h3>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ var txG = new BigInt64Array(10);
|
|||||||
var txB = new BigInt64Array(10);
|
var txB = new BigInt64Array(10);
|
||||||
var rxG = new BigInt64Array(10);
|
var rxG = new BigInt64Array(10);
|
||||||
var rxB = new BigInt64Array(10);
|
var rxB = new BigInt64Array(10);
|
||||||
const linkS = ["Disabled", "Down", "10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"];
|
const linkS = [function(){return t('speed_disabled')}, function(){return t('speed_down')}, "10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"];
|
||||||
var pState = new Int8Array(10);
|
var pState = new Int8Array(10);
|
||||||
var pIsSFP = new Int8Array(10);
|
var pIsSFP = new Int8Array(10);
|
||||||
var pAdvertised = new Int8Array(10);
|
var pAdvertised = new Int8Array(10);
|
||||||
var numPorts = 0;
|
var numPorts = 0;
|
||||||
|
function linkText(idx) { var v = linkS[idx]; return typeof v === 'function' ? v() : v; }
|
||||||
var logToPhysPort = new Int8Array(10);
|
var logToPhysPort = new Int8Array(10);
|
||||||
var physToLogPort = new Int8Array(10);
|
var physToLogPort = new Int8Array(10);
|
||||||
|
var portNames = new Array(10);
|
||||||
|
var currentRequests = [];
|
||||||
|
var currentCallback;
|
||||||
function drawPorts() {
|
function drawPorts() {
|
||||||
var f = document.getElementById('ports');
|
var f = document.getElementById('ports');
|
||||||
console.log("DRAWING PORTS: ", numPorts);
|
console.log("DRAWING PORTS: ", numPorts);
|
||||||
@@ -18,7 +22,7 @@ function drawPorts() {
|
|||||||
d.classList.add('tooltip');
|
d.classList.add('tooltip');
|
||||||
const s = document.createElement("span");
|
const s = document.createElement("span");
|
||||||
s.classList.add("tooltiptext");
|
s.classList.add("tooltiptext");
|
||||||
s.innerHTML = "Tooltip text";
|
s.innerHTML = t('common_port');
|
||||||
s.id="tt_" + (i+1);
|
s.id="tt_" + (i+1);
|
||||||
const l = document.createElement("object");
|
const l = document.createElement("object");
|
||||||
d.appendChild(l);
|
d.appendChild(l);
|
||||||
@@ -38,9 +42,86 @@ function drawPorts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function parseUint16(val) {
|
||||||
|
return parseInt(val, 16) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseInt16(val) {
|
||||||
|
let valInt = parseInt(val, 16);
|
||||||
|
let num = valInt & 0x7fff;
|
||||||
|
if (valInt & 0x8000) {
|
||||||
|
return num - 0x8000;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCalibrationSlopeOffset(val, cal) {
|
||||||
|
if (typeof cal !== 'string') {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
if (cal.startsWith("0x")) {
|
||||||
|
cal = cal.substring(2);
|
||||||
|
}
|
||||||
|
if (cal.length != 8) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
let slope = parseUint16(cal.substring(0, 4)) / 256;
|
||||||
|
let offset = parseInt16(cal.substring(4, 8));
|
||||||
|
return slope * val + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRxPowerCalibration(val, cal) {
|
||||||
|
if (typeof cal !== 'string') {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
if (cal.startsWith("0x")) {
|
||||||
|
cal = cal.substring(2);
|
||||||
|
}
|
||||||
|
if (cal.length != 40) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
let bytes = cal.match(/.{1,2}/g).map(function (x) { return parseInt(x, 16); });
|
||||||
|
let view = new DataView(new Uint8Array(bytes).buffer);
|
||||||
|
return view.getFloat32(0) * Math.pow(val, 4)
|
||||||
|
+ view.getFloat32(4) * Math.pow(val, 3)
|
||||||
|
+ view.getFloat32(8) * Math.pow(val, 2)
|
||||||
|
+ view.getFloat32(12) * val
|
||||||
|
+ view.getFloat32(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSfpTemp(val, cal) {
|
||||||
|
let temp = parseInt16(val);
|
||||||
|
return applyCalibrationSlopeOffset(temp, cal) / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSfpVcc(val, cal) {
|
||||||
|
let vcc = parseUint16(val);
|
||||||
|
return applyCalibrationSlopeOffset(vcc, cal) / 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSfpTxBias(val, cal) {
|
||||||
|
let bias = parseUint16(val);
|
||||||
|
return applyCalibrationSlopeOffset(bias, cal) / 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSfpTxPower(val, cal) {
|
||||||
|
let txPower = parseUint16(val);
|
||||||
|
return applyCalibrationSlopeOffset(txPower, cal) / 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSfpRxPower(val, cal) {
|
||||||
|
let rxPower = parseUint16(val);
|
||||||
|
return applyRxPowerCalibration(rxPower, cal) / 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertPowerTodBm(val) {
|
||||||
|
return 10 * Math.log10(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(callback) {
|
||||||
var xhttp = new XMLHttpRequest();
|
var xhttp = new XMLHttpRequest();
|
||||||
xhttp.onreadystatechange = function() {
|
xhttp.onreadystatechange = function() {
|
||||||
|
console.log("IN UPDATE ");
|
||||||
if (this.readyState == 4 && this.status == 401)
|
if (this.readyState == 4 && this.status == 401)
|
||||||
document.location = "/login.html"
|
document.location = "/login.html"
|
||||||
if (this.readyState == 4 && this.status == 200) {
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
@@ -57,6 +138,7 @@ function update() {
|
|||||||
let n = p.portNum;
|
let n = p.portNum;
|
||||||
logToPhysPort[p.logPort] = n;
|
logToPhysPort[p.logPort] = n;
|
||||||
physToLogPort[n-1] = p.logPort;
|
physToLogPort[n-1] = p.logPort;
|
||||||
|
portNames[p.logPort] = p.name;
|
||||||
let pid = "port" + n;
|
let pid = "port" + n;
|
||||||
let ttid = "tt_" + n;
|
let ttid = "tt_" + n;
|
||||||
n--;
|
n--;
|
||||||
@@ -67,16 +149,25 @@ function update() {
|
|||||||
continue;
|
continue;
|
||||||
var bgs = psvg.contentDocument.getElementsByClassName("bg");
|
var bgs = psvg.contentDocument.getElementsByClassName("bg");
|
||||||
var leds = psvg.contentDocument.getElementsByClassName("led");
|
var leds = psvg.contentDocument.getElementsByClassName("led");
|
||||||
|
if (leds[0] == null || leds[0].style == null)
|
||||||
|
continue;
|
||||||
|
const portName = p.name || portNames[p.logPort] || '';
|
||||||
|
var iHTML = "<table border=\"0\" class=\"tt_table\">";
|
||||||
|
if (portName) iHTML += "<tr><td align=\"left\">" + t('port_name') + "</td><td>:</td><td>" + portName + "</td></tr>";
|
||||||
if (p.enabled == 0) {
|
if (p.enabled == 0) {
|
||||||
pState[n] = -1;
|
pState[n] = -1;
|
||||||
bgs[0].style.fill = "red";
|
bgs[0].style.fill = "red";
|
||||||
leds[0].style.fill = "black"; leds[1].style.fill = "black";
|
leds[0].style.fill = "black"; leds[1].style.fill = "black";
|
||||||
psvg.style.opacity = 0.4;
|
psvg.style.opacity = 0.4;
|
||||||
tt.innerHTML = "Not enabled.";
|
iHTML += "<tr><td align=\"left\">" + t('port_status') + "</td><td>:</td><td>" + t('port_not_enabled') + "</td></tr>";
|
||||||
|
iHTML += "</table>";
|
||||||
|
tt.innerHTML = iHTML;
|
||||||
} else {
|
} else {
|
||||||
psvg.style.opacity = 1.0;
|
psvg.style.opacity = 1.0;
|
||||||
pState[n] = p.link;
|
pState[n] = p.link;
|
||||||
if (p.link == 4 || p.link == 5 || p.link == 6) {
|
if (p.link == 5 || p.link == 7) {
|
||||||
|
leds[0].style.fill = "green"; leds[1].style.fill = "blue";
|
||||||
|
} else if (p.link == 4 || p.link == 6) {
|
||||||
leds[0].style.fill = "green"; leds[1].style.fill = "orange";
|
leds[0].style.fill = "green"; leds[1].style.fill = "orange";
|
||||||
} else if (p.link == 1 || p.link == 2 || p.link == 3) {
|
} else if (p.link == 1 || p.link == 2 || p.link == 3) {
|
||||||
leds[0].style.fill = "green"; leds[1].style.fill = "green";
|
leds[0].style.fill = "green"; leds[1].style.fill = "green";
|
||||||
@@ -84,34 +175,113 @@ function update() {
|
|||||||
leds[0].style.fill = "black"; leds[1].style.fill = "black";
|
leds[0].style.fill = "black"; leds[1].style.fill = "black";
|
||||||
psvg.style.opacity = 0.4
|
psvg.style.opacity = 0.4
|
||||||
}
|
}
|
||||||
var iHTML = "<table border=\"0\" class=\"tt_table\">";
|
iHTML += "<tr><td align=\"left\">" + t('port_link_speed') + "</td><td>:</td><td>" + linkText(p.link + 1) + "</td></tr>";
|
||||||
iHTML += "<tr><td align=\"left\">Link speed</td><td>:</td><td>" + linkS[p.link + 1] + "</td></tr>";
|
|
||||||
if (p.isSFP) {
|
if (p.isSFP) {
|
||||||
pAdvertised[n] = 0;
|
pAdvertised[n] = 0;
|
||||||
iHTML += "<tr><td>Vendor</td><td>:</td><td>" + p.sfp_vendor + "</td></tr>";
|
const hasExtendedStatus = p.sfp_options & 0x40;
|
||||||
iHTML += "<tr><td>Model</td><td>:</td><td>" + p.sfp_model + "</td></tr>";
|
iHTML += "<tr><td>" + t('port_vendor') + "</td><td>:</td><td>" + p.sfp_vendor + "</td></tr>";
|
||||||
iHTML += "<tr><td>Serial</td><td>:</td><td>" + p.sfp_serial + "</td></tr>";
|
iHTML += "<tr><td>" + t('port_model') + "</td><td>:</td><td>" + p.sfp_model + "</td></tr>";
|
||||||
if (p.sfp_options & 0x40) {
|
iHTML += "<tr><td>" + t('port_serial') + "</td><td>:</td><td>" + p.sfp_serial + "</td></tr>";
|
||||||
iHTML += "<tr><td>Temp</td><td>:</td><td>" + (Number(p.sfp_temp) >> 8) + "." + ((Number(p.sfp_temp) & 0xff)/256.0 * 100).toFixed(0) + " ℃</td></tr>";
|
if (hasExtendedStatus) {
|
||||||
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + (Number(p.sfp_vcc) / 10000.0).toFixed(2) + " V</td></tr>";
|
let txPower = decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal);
|
||||||
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + (Number(p.sfp_txbias) / 500.0).toFixed(1) + " mA</td></tr>";
|
let txPowerdBm = convertPowerTodBm(txPower);
|
||||||
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + (Number(p.sfp_txpower) / 10.0).toFixed(0) + " mW</td></tr>";
|
let rxPower = decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal);
|
||||||
iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + (Number(p.sfp_rxpower) / 10.0).toFixed(0) + " mW</td></tr>";
|
let rxPowerdBm = convertPowerTodBm(rxPower);
|
||||||
|
iHTML += "<tr><td>" + t('port_temp') + "</td><td>:</td><td>" + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + " ℃</td></tr>";
|
||||||
|
iHTML += "<tr><td>" + t('port_vcc') + "</td><td>:</td><td>" + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + " V</td></tr>";
|
||||||
|
iHTML += "<tr><td>" + t('port_tx_fault') + "</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>";
|
||||||
|
iHTML += "<tr><td>" + t('port_tx_disabled') + "</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>";
|
||||||
|
iHTML += "<tr><td>" + t('port_tx_bias') + "</td><td>:</td><td>" + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + " mA</td></tr>";
|
||||||
|
iHTML += "<tr><td>" + t('port_tx_power') + "</td><td>:</td><td>" + txPower.toFixed(3) + " mW / " + txPowerdBm.toFixed(2) + " dBm</td></tr>";
|
||||||
|
iHTML += "<tr><td>" + t('port_rx_power') + "</td><td>:</td><td>" + rxPower.toFixed(3) + " mW / " + rxPowerdBm.toFixed(2) + " dBm</td></tr>";
|
||||||
|
}
|
||||||
|
// Not all devices & modules have LOS pin...
|
||||||
|
const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null;
|
||||||
|
const rx_los_module = hasExtendedStatus ? Boolean(Number(p.sfp_state) & 0x2) : null;
|
||||||
|
if (rx_los_module !== null || rx_los_pin !== null) {
|
||||||
|
iHTML += `<tr><td>` + t('port_rx_los') + `</td><td>:</td><td>${rxLosHTML(rx_los_pin, rx_los_module)}</td></tr>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pAdvertised[n] = parseInt(p.adv, 2);
|
pAdvertised[n] = parseInt(p.adv, 2);
|
||||||
}
|
};
|
||||||
iHTML += "</table>";
|
iHTML += "</table>";
|
||||||
tt.innerHTML = iHTML;
|
tt.innerHTML = iHTML;
|
||||||
}
|
}}
|
||||||
}
|
if (callback)
|
||||||
}
|
callback();
|
||||||
};
|
}};
|
||||||
xhttp.open("GET", "/status.json", true);
|
xhttp.open("GET", "/status.json", true);
|
||||||
xhttp.timeout = 5000; xhttp.send();
|
xhttp.timeout = 5000;
|
||||||
|
sendXHTTP(xhttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rxLosHTML(pinStatus, moduleStatus) {
|
||||||
|
if (moduleStatus !== null && pinStatus !== null && moduleStatus !== pinStatus) {
|
||||||
|
return `pin=${pinStatus}<br/>mod=${moduleStatus}<br/>❗❗❗❗`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns first non null value
|
||||||
|
return moduleStatus ?? pinStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
function callbackXHTTP()
|
||||||
|
{
|
||||||
|
x = currentRequests.shift();
|
||||||
|
x.onreadystatechange = currentCallback;
|
||||||
|
x.onreadystatechange();
|
||||||
|
if (currentRequests.length === 0)
|
||||||
|
return;
|
||||||
|
x = currentRequests[0];
|
||||||
|
currentCallback = x.onreadystatechange;
|
||||||
|
x.onreadystatechange = callbackXHTTP;
|
||||||
|
var retries = 10;
|
||||||
|
while (retries) {
|
||||||
|
try {
|
||||||
|
setTimeout(() => {
|
||||||
|
x.send();
|
||||||
|
console.log("B1");
|
||||||
|
}, 20);
|
||||||
|
} catch (error) {
|
||||||
|
retries--;
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log(`Retry ${retries}/${maxRetries} failed: ${error.message}`);
|
||||||
|
}, 200);
|
||||||
|
if (retries < 1) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("B2");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendXHTTP(x)
|
||||||
|
{
|
||||||
|
console.log("sendXHTTP ", x);
|
||||||
|
if (currentRequests.length === 0) {
|
||||||
|
currentRequests.push(x);
|
||||||
|
currentCallback = x.onreadystatechange;
|
||||||
|
x.onreadystatechange = callbackXHTTP;
|
||||||
|
var retries = 10;
|
||||||
|
while (retries) {
|
||||||
|
try {
|
||||||
|
x.send();
|
||||||
|
console.log("A1");
|
||||||
|
} catch (error) {
|
||||||
|
retries--;
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log(`Retry ${retries}/${maxRetries} failed: ${error.message}`);
|
||||||
|
}, 200);
|
||||||
|
if (retries < 1) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("A2");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("A3");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentRequests.push(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
|
||||||
update();
|
|
||||||
const interval = setInterval(update, 2000);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>Mirror Configuration</title>
|
<title data-i18n="mirror_title">Mirror Configuration</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>Mirror Configuration</h1>
|
<h1 data-i18n="mirror_heading">Mirror Configuration</h1>
|
||||||
<label class="tswitch">Enabled: <input id="me" type="checkbox"></label><br/>
|
<label class="tswitch"><span data-i18n="mirror_enabled">Enabled:</span> <input id="me" type="checkbox"></label><br/>
|
||||||
<label for="mp">Mirroring Port:</label> <input type="number" id="mp" name="mp" min="1" max="9"/>
|
<label for="mp"><span data-i18n="mirror_port">Mirroring Port:</span></label> <input type="number" id="mp" name="mp" min="1" max="9"/>
|
||||||
<h2>Mirrored Ports (TX)</h2>
|
<h2 data-i18n="mirror_tx">Mirrored Ports (TX)</h2>
|
||||||
<div id="mPortsTX"></div>
|
<div id="mPortsTX"></div>
|
||||||
<br />
|
<br />
|
||||||
<h2>Mirrored Ports (RX)</h2>
|
<h2 data-i18n="mirror_rx">Mirrored Ports (RX)</h2>
|
||||||
<div id="mPortsRX"></div>
|
<div id="mPortsRX"></div>
|
||||||
<br/> <input style="width:15%;" class="action" id="mirror_sub" onclick="mirrorSub();" type="button" value="Update / Create">
|
<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" value="Disable Mirroring">
|
<input style="width:15%;" class="action" id="mirror_del" onclick="mirrorDel();" type="button" data-i18n="mirror_disable" value="Disable Mirroring">
|
||||||
<script src="/mirror.js"></script>
|
<script src="/mirror.js"></script>
|
||||||
<script src="/mirror_sub.js"></script>
|
<script src="/mirror_sub.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ const mirrors = ["mPortsTX", "mPortsRX"];
|
|||||||
function mirrorForm() {
|
function mirrorForm() {
|
||||||
if (!numPorts)
|
if (!numPorts)
|
||||||
return;
|
return;
|
||||||
clearInterval(mirrorInterval);
|
|
||||||
for (let j=0; j < mirrors.length; j++) {
|
for (let j=0; j < mirrors.length; j++) {
|
||||||
console.log("Adding Mirror " + j)
|
console.log("Adding Mirror " + j)
|
||||||
var m = document.getElementById(mirrors[j]);
|
var m = document.getElementById(mirrors[j]);
|
||||||
@@ -34,9 +33,6 @@ function mirrorForm() {
|
|||||||
function setM(p, c){
|
function setM(p, c){
|
||||||
document.getElementById(p).checked=c;
|
document.getElementById(p).checked=c;
|
||||||
}
|
}
|
||||||
window.addEventListener("load", function() {
|
|
||||||
mirrorInterval = setInterval(mirrorForm, 200);
|
|
||||||
});
|
|
||||||
|
|
||||||
function fetchMirror() {
|
function fetchMirror() {
|
||||||
var xhttp = new XMLHttpRequest();
|
var xhttp = new XMLHttpRequest();
|
||||||
@@ -57,5 +53,12 @@ function fetchMirror() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", `/mirror.json`, true);
|
xhttp.open("GET", `/mirror.json`, true);
|
||||||
xhttp.send();
|
sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
mirrorForm();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ async function mirrorSub() {
|
|||||||
var cmd = "mirror ";
|
var cmd = "mirror ";
|
||||||
var mp=document.getElementById('mp').value
|
var mp=document.getElementById('mp').value
|
||||||
if (!mp) {
|
if (!mp) {
|
||||||
alert("Set Mirroring Port first");
|
alert(t('mirror_set_port_first'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.getElementById(mirrors[0]+mp).checked=false;document.getElementById(mirrors[1]+mp).checked=false;
|
document.getElementById(mirrors[0]+mp).checked=false;document.getElementById(mirrors[1]+mp).checked=false;
|
||||||
@@ -16,7 +16,7 @@ async function mirrorSub() {
|
|||||||
cmd = cmd + ` ${i}r`;
|
cmd = cmd + ` ${i}r`;
|
||||||
}
|
}
|
||||||
if (cmd.length < 10) {
|
if (cmd.length < 10) {
|
||||||
alert("Select Mirrored Ports");
|
alert(t('mirror_select_ports'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
document.getElementById('sidebar').innerHTML =
|
document.getElementById('sidebar').innerHTML =
|
||||||
"<ul><li><a href='index.html'>Overview</a></li>"
|
"<ul><li><a href='index.html' data-i18n='nav_overview'>Overview</a></li>"
|
||||||
+ "<li><a href='ports.html'>Port Configuration</a></li>"
|
+ "<li><a href='ports.html' data-i18n='nav_port_config'>Port Configuration</a></li>"
|
||||||
+ "<li><a href='stat.html'>Port Statistics</a></li>"
|
+ "<li><a href='stat.html' data-i18n='nav_port_stat'>Port Statistics</a></li>"
|
||||||
+ "<li><a href='vlan.html' >VLAN</a></li>"
|
+ "<li><a href='vlan.html' >VLAN</a></li>"
|
||||||
+ "<li><a href='l2.html'>L2 Configuration</a></li>"
|
+ "<li><a href='l2.html' data-i18n='nav_l2'>L2 Configuration</a></li>"
|
||||||
+ "<li><a href='mirror.html'>Mirroring</a></li>"
|
+ "<li><a href='mirror.html' data-i18n='nav_mirror'>Mirroring</a></li>"
|
||||||
+ "<li><a href='lag.html'>Link Aggregation</a></li>"
|
+ "<li><a href='lag.html' data-i18n='nav_lag'>Link Aggregation</a></li>"
|
||||||
+ "<li><a href='eee.html'>EEE</a></li>"
|
+ "<li><a href='eee.html' data-i18n='nav_eee'>EEE</a></li>"
|
||||||
+ "<li><a href='bandwidth.html'>Bandwidth Limits</a></li>"
|
+ "<li><a href='bandwidth.html' data-i18n='nav_bandwidth'>Bandwidth Limits</a></li>"
|
||||||
+ "<li><a href='system.html'>System Settings</a></li>"
|
+ "<li><a href='system.html' data-i18n='nav_system'>System Settings</a></li>"
|
||||||
+ "<li><a href='update.html'>Firmware Update</a></li></ul>";
|
+ "<li><a href='update.html' data-i18n='nav_fw_update'>Firmware Update</a></li></ul>";
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var links = document.querySelectorAll('#sidebar a[data-i18n]');
|
||||||
|
links.forEach(function(el) {
|
||||||
|
var key = el.getAttribute('data-i18n');
|
||||||
|
if (key) el.textContent = t(key);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>FreeSwitchOS Port Configuration</title>
|
<title data-i18n="port_title">FreeSwitchOS Port Configuration</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<h1>Port Configuration</h1>
|
<h1 data-i18n="port_heading">Port Configuration</h1>
|
||||||
<form id="vform" action="/vlan.html">
|
<form id="vform" action="/vlan.html">
|
||||||
<table id="speedtable">
|
<table id="speedtable">
|
||||||
<tr> <th>Port</th> <th>Current Link Speed</th><th>Set Speed</th><th>Disabled</th><th>Apply</th></tr>
|
<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_set_speed">Set Speed</th><th data-i18n="port_col_disabled">Disabled</th><th data-i18n="port_col_apply">Apply</th></tr>
|
||||||
</table>
|
</table>
|
||||||
<h2 style="margin-top:3em">Configure Maximum Frame Size (MTU) forwarded at Port</h2>
|
<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 id="mtutable" style="margin-top:1em">
|
||||||
</table>
|
</table>
|
||||||
<script src="/ports.js"></script>
|
<script src="/ports.js"></script>
|
||||||
|
|||||||
@@ -3,15 +3,14 @@ var clicked = new Int8Array(10);
|
|||||||
function createPortTable() {
|
function createPortTable() {
|
||||||
var tbl = document.getElementById('speedtable');
|
var tbl = document.getElementById('speedtable');
|
||||||
if (tbl.rows.length <= 2 && numPorts) {
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
clearInterval(pTableInterval);
|
|
||||||
const sSelect = '<select name="speed_sel" id="speed_sel">'
|
const sSelect = '<select name="speed_sel" id="speed_sel">'
|
||||||
+ '<option value="auto">Auto</option>'
|
+ '<option value="auto">' + t('port_auto') + '</option>'
|
||||||
+ '<option value="2g5">2500MBit/Full</option>'
|
+ '<option value="2g5">' + t('port_2500m') + '</option>'
|
||||||
+ '<option value="1g">1000MBit/Full</option>'
|
+ '<option value="1g">' + t('port_1000m') + '</option>'
|
||||||
+ '<option value="100m full">100MBit/Full</option>'
|
+ '<option value="100m full">' + t('port_100m_f') + '</option>'
|
||||||
+ '<option value="100m half">100MBit/Half</option>'
|
+ '<option value="100m half">' + t('port_100m_h') + '</option>'
|
||||||
+ '<option value="10m full">10MBit/Full</option>'
|
+ '<option value="10m full">' + t('port_10m_f') + '</option>'
|
||||||
+ '<option value="10m half">10MBit/Half</option>'
|
+ '<option value="10m half">' + t('port_10m_h') + '</option>'
|
||||||
+ '</select>';
|
+ '</select>';
|
||||||
const dSwitch = '<input type="checkbox" id="disable_port" onchange="portOnOff();">'
|
const dSwitch = '<input type="checkbox" id="disable_port" onchange="portOnOff();">'
|
||||||
for (let i = 1; i <= numPorts; i++) {
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
@@ -19,12 +18,14 @@ function createPortTable() {
|
|||||||
continue;
|
continue;
|
||||||
console.log("Table row: " + i + "pState: " + pState[i-2]);
|
console.log("Table row: " + i + "pState: " + pState[i-2]);
|
||||||
const tr = tbl.insertRow();
|
const tr = tbl.insertRow();
|
||||||
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i}`));
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + i));
|
||||||
td = tr.insertCell(); td.innerHTML = linkS[pState[i] + 1];
|
let portName = portNames[physToLogPort[i-1]] || '';
|
||||||
|
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
|
||||||
|
td = tr.insertCell(); td.innerHTML = linkText(pState[i] + 1);
|
||||||
td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i);
|
td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i);
|
||||||
td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i)
|
td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i)
|
||||||
.replace("portOnOff()", "portOnOff(" + i + ")");
|
.replace("portOnOff()", "portOnOff(" + i + ")");
|
||||||
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="applySpeed(' + i + ');">Apply</button>';
|
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="applySpeed(' + i + ');">' + t('port_apply') + '</button>';
|
||||||
td = tr.insertCell();
|
td = tr.insertCell();
|
||||||
td.innerHTML = button;
|
td.innerHTML = button;
|
||||||
}
|
}
|
||||||
@@ -54,7 +55,7 @@ function createPortTable() {
|
|||||||
tr = tbl.insertRow();
|
tr = tbl.insertRow();
|
||||||
for (let i = 1; i <= numPorts; i++) {
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
let td = tr.insertCell();
|
let td = tr.insertCell();
|
||||||
td.innerHTML = '<button type="button" style="margin: 0 0 0 24px" onclick="applyMTU(' + i + ');">Apply</button>';
|
td.innerHTML = '<button type="button" style="margin: 0 0 0 24px" onclick="applyMTU(' + i + ');">' + t('port_apply') + '</button>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +68,7 @@ function updatePortTable() {
|
|||||||
for (let i = 1; i <= numPorts ; i++) {
|
for (let i = 1; i <= numPorts ; i++) {
|
||||||
if (pIsSFP[i-1])
|
if (pIsSFP[i-1])
|
||||||
continue;
|
continue;
|
||||||
tbl.rows[i].cells[1].innerHTML = `${linkS[pState[i-1]+1]}`;
|
tbl.rows[i].cells[2].innerHTML = linkText(pState[i-1]+1);
|
||||||
if (!clicked[i] && pState[i - 1] < 0) {
|
if (!clicked[i] && pState[i - 1] < 0) {
|
||||||
document.getElementById('speed_sel_' + i).disabled = true;
|
document.getElementById('speed_sel_' + i).disabled = true;
|
||||||
document.getElementById('disable_port_' + i).checked = true;
|
document.getElementById('disable_port_' + i).checked = true;
|
||||||
@@ -130,17 +131,19 @@ function getMTUs() {
|
|||||||
if (!mtu)
|
if (!mtu)
|
||||||
continue;
|
continue;
|
||||||
mtu.value = mtus[n];
|
mtu.value = mtus[n];
|
||||||
clearInterval(pMTUInterval);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", "/mtu.json", true);
|
xhttp.open("GET", "/mtu.json", true);
|
||||||
xhttp.timeout = 1500; xhttp.send();
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
createPortTable();
|
||||||
|
updatePortTable();
|
||||||
|
getMTUs()
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
const updatePortTableInterval = setInterval(updatePortTable, 1000);
|
const updatePortTableInterval = setInterval(updatePortTable, 1000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
const pTableInterval = setInterval(createPortTable, 1000);
|
|
||||||
const pMTUInterval = setInterval(getMTUs, 1200);
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>FreeSwitchOS Port Statistics</title>
|
<title data-i18n="stat_title">FreeSwitchOS Port Statistics</title>
|
||||||
<style>
|
<style>
|
||||||
.popup {
|
.popup {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -31,14 +32,14 @@
|
|||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
<div id="popup" class="popup">
|
<div id="popup" class="popup">
|
||||||
<div class="popup-content">
|
<div class="popup-content">
|
||||||
<h2>Detailed Port Statistics</h2>
|
<h2 data-i18n="stat_detailed">Detailed Port Statistics</h2>
|
||||||
<div id="popup_text"></div>
|
<div id="popup_text"></div>
|
||||||
<button id="closePopup" class="action">Close</button>
|
<button id="closePopup" class="action" data-i18n="stat_close">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1>Port Statistics</h1>
|
<h1 data-i18n="stat_heading">Port Statistics</h1>
|
||||||
<table id="statstable">
|
<table id="statstable">
|
||||||
<tr> <th>Port</th> <th>link</th> <th>TX Good</th> <th>TX Bad</th> <th>RX Good</th> <th>RX Bad</th> <th> All Counters </th></tr>
|
<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>
|
||||||
<script src="/stat.js"></script>
|
<script src="/stat.js"></script>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ function getCounters(port) {
|
|||||||
const s = JSON.parse(xhttp.responseText);
|
const s = JSON.parse(xhttp.responseText);
|
||||||
console.log("Counters: ", JSON.stringify(s));
|
console.log("Counters: ", JSON.stringify(s));
|
||||||
const ptext = document.getElementById('popup_text');
|
const ptext = document.getElementById('popup_text');
|
||||||
var t = "<table style='width:100%'> <tr> <th>Counter</th> <th>Value</th> <th>Counter</th> <th>Value</th></tr> <tr>";
|
var tableHtml = "<table style='width:100%'> <tr> <th>" + t('stat_counter') + "</th> <th>" + t('stat_value') + "</th> <th>" + t('stat_counter') + "</th> <th>" + t('stat_value') + "</th></tr> <tr>";
|
||||||
console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length);
|
console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length);
|
||||||
var c = 0;
|
var c = 0;
|
||||||
for (i = 0; i < mib_counters.length; i += 4) {
|
for (i = 0; i < mib_counters.length; i += 4) {
|
||||||
@@ -125,33 +125,33 @@ function getCounters(port) {
|
|||||||
}
|
}
|
||||||
var count = BigInt(s[i/4]);
|
var count = BigInt(s[i/4]);
|
||||||
if (mib_counters[i+1] == 8) {
|
if (mib_counters[i+1] == 8) {
|
||||||
t += "<td>" + mib_counters[i] + "</td><td>" + count.toString() + "</td>";
|
tableHtml += "<td>" + mib_counters[i] + "</td><td>" + count.toString() + "</td>";
|
||||||
c += 1;
|
c += 1;
|
||||||
} else if (mib_counters[i+1] == 4) {
|
} else if (mib_counters[i+1] == 4) {
|
||||||
if (mib_counters[i] != "") {
|
if (mib_counters[i] != "") {
|
||||||
t += "<td>" + mib_counters[i] + "</td><td>" + (count >> 32n).toString() + "</td>";
|
tableHtml += "<td>" + mib_counters[i] + "</td><td>" + (count >> 32n).toString() + "</td>";
|
||||||
c += 1;
|
c += 1;
|
||||||
}
|
}
|
||||||
if (c == 2) {
|
if (c == 2) {
|
||||||
t += "</tr> <tr>";
|
tableHtml += "</tr> <tr>";
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
if (mib_counters[i+2] != "") {
|
if (mib_counters[i+2] != "") {
|
||||||
t += "<td>" + mib_counters[i+2] + "</td><td>" + (count & 4294967295n).toString() + "</td>";
|
tableHtml += "<td>" + mib_counters[i+2] + "</td><td>" + (count & 4294967295n).toString() + "</td>";
|
||||||
c += 1;
|
c += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c == 2) {
|
if (c == 2) {
|
||||||
t += "</tr> <tr>";
|
tableHtml += "</tr> <tr>";
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptext.innerHTML = t + "</tr></table>";
|
ptext.innerHTML = tableHtml + "</tr></table>";
|
||||||
popup.style.display = 'flex';
|
popup.style.display = 'flex';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", "/counters.json?port=" + port, true);
|
xhttp.open("GET", "/counters.json?port=" + port, true);
|
||||||
xhttp.timeout = 1500; xhttp.send();
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -162,30 +162,30 @@ function fillStats() {
|
|||||||
if (tbl.rows.length > 1) {
|
if (tbl.rows.length > 1) {
|
||||||
for (let i = 0; i < numPorts; i++) {
|
for (let i = 0; i < numPorts; i++) {
|
||||||
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
|
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
|
||||||
tbl.rows[i+1].cells[1].innerHTML = `${linkS[pState[i]+1]}`;
|
tbl.rows[i+1].cells[2].innerHTML = linkText(pState[i]+1);
|
||||||
tbl.rows[i+1].cells[2].innerHTML = `${txG[i]} pkts`;
|
tbl.rows[i+1].cells[3].innerHTML = `${txG[i]}` + t('common_pkts');
|
||||||
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]} pkts`;
|
tbl.rows[i+1].cells[4].innerHTML = `${txB[i]}` + t('common_pkts');
|
||||||
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]} pkts`;
|
tbl.rows[i+1].cells[5].innerHTML = `${rxG[i]}` + t('common_pkts');
|
||||||
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`;
|
tbl.rows[i+1].cells[6].innerHTML = `${rxB[i]}` + t('common_pkts');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < numPorts; i++) {
|
for (let i = 0; i < numPorts; i++) {
|
||||||
console.log("Table row: " + i);
|
console.log("Table row: " + i);
|
||||||
const tr = tbl.insertRow();
|
const tr = tbl.insertRow();
|
||||||
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`));
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i+1)));
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
|
let portName = portNames[physToLogPort[i]] || '';
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(linkText(pState[i]+1)));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]}` + t('common_pkts')));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]}` + t('common_pkts')));
|
||||||
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + i + ');">Show</button>';
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]}` + t('common_pkts')));
|
||||||
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]}` + t('common_pkts')));
|
||||||
|
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + i + ');">' + t('stat_show') + '</button>';
|
||||||
td = tr.insertCell(); td.innerHTML = button;
|
td = tr.insertCell(); td.innerHTML = button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stat = setInterval(fillStats, 1000);
|
|
||||||
|
|
||||||
const popup = document.getElementById('popup');
|
const popup = document.getElementById('popup');
|
||||||
const closePopup = document.getElementById('closePopup');
|
const closePopup = document.getElementById('closePopup');
|
||||||
closePopup.addEventListener('click', () => {
|
closePopup.addEventListener('click', () => {
|
||||||
@@ -196,3 +196,12 @@ window.addEventListener('click', (event) => {
|
|||||||
popup.style.display = 'none';
|
popup.style.display = 'none';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
update();
|
||||||
|
fillStats();
|
||||||
|
const stat = setInterval(fillStats, 1000);
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ object, img {
|
|||||||
.isNOK{ color: #900;}
|
.isNOK{ color: #900;}
|
||||||
.isOK{ color: #090;}
|
.isOK{ color: #090;}
|
||||||
.ip{padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
|
.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;}
|
.row {display: flex;}
|
||||||
.rcol {flex: 90%;}
|
.rcol {flex: 90%;}
|
||||||
.lcol {flex: 10%;}
|
.lcol {flex: 10%;}
|
||||||
@@ -163,3 +164,9 @@ margin: 30px 0;
|
|||||||
}
|
}
|
||||||
select { text-align-last: right; font-family: monospace}
|
select { text-align-last: right; font-family: monospace}
|
||||||
option { direction: rtl; font-family: sans-serif}
|
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,8 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<script src="/i18n.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>System Settings</title>
|
<title data-i18n="sys_title">System Settings</title>
|
||||||
<style>
|
<style>
|
||||||
.tab-bar { display: flex; border-bottom: 2px solid #226; margin-bottom: 0; margin-left: 16%; padding: 1px 16px; padding-bottom: 0; }
|
.tab-bar { display: flex; border-bottom: 2px solid #226; margin-bottom: 0; margin-left: 16%; 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 { padding: 10px 20px; background-color: #ddf; border: none; cursor: pointer; font-size: 1em; border-radius: 8px 8px 0 0; margin-right: 4px; }
|
||||||
@@ -14,60 +15,81 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="tab-bar">
|
<div class="tab-bar">
|
||||||
<button class="tab-btn active" onclick="openTab(event, 'system-tab')">System</button>
|
<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')">Advanced</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>
|
||||||
</div>
|
</div>
|
||||||
<nav id="sidebar"></nav>
|
<nav id="sidebar"></nav>
|
||||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
<div id="ports"></div>
|
<div id="ports"></div>
|
||||||
|
|
||||||
<div id="system-tab" class="tab-content active">
|
<div id="system-tab" class="tab-content active">
|
||||||
<h1>System Settings</h1>
|
<h1 data-i18n="sys_heading">System Settings</h1>
|
||||||
<label class="dhcpon">DHCP client endabled: <input id="dhcp" type="checkbox" onchange="dhcpClicked(this)"></label><br/><br/>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="lcol"> <label for="ip">IP address:</label></div>
|
<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"/>
|
||||||
|
<button onclick="hostSub()" data-i18n="sys_apply">Apply</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="lcol"> <label data-i18n="sys_model">Model:</label></div>
|
||||||
|
<div class="rcol"><span id="model" class="rotext"></span></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" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
<div class="rcol"> <input id="ip" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="lcol"> <label for="netmask">Netmask:</label></div>
|
<div class="lcol"> <label for="netmask" data-i18n="sys_netmask">Netmask:</label></div>
|
||||||
<div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
<div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="lcol"> <label for="gw">Gateway:</label></div>
|
<div class="lcol"> <label for="gw" data-i18n="sys_gateway">Gateway:</label></div>
|
||||||
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
||||||
</div>
|
</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" class="ip" onchange="mgmtVlanChanged()"></select></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="lcol"> <label data-i18n="sys_language">Language:</label></div>
|
||||||
|
<div class="rcol">
|
||||||
|
<select id="lang-select" onchange="changeLang()">
|
||||||
|
<option value="en">English</option>
|
||||||
|
<option value="ja">日本語</option>
|
||||||
|
<option value="zh">中文</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
When updating the above settings, remember to point your browser to the new IP afterwards:<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" value="Update Settings"><br/>
|
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" data-i18n="sys_update" value="Update Settings"><br/>
|
||||||
<br/>
|
<br/>
|
||||||
Save all current settings to Flash:<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" value="Save Settings to Flash">
|
<input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" data-i18n="sys_save" value="Save Settings to Flash">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="advanced-tab" class="tab-content">
|
<div id="advanced-tab" class="tab-content">
|
||||||
<h1>Advanced Settings</h1>
|
<h1 data-i18n="sys_advanced">Advanced Settings</h1>
|
||||||
<div class="lcol"> <label for="config_display">Startup configuration:</label></div>
|
<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>
|
<textarea id="config_display" rows="8" cols="60"></textarea>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
Be careful when saving the directly edited startup configuration, you can lock yourself out:<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" value="Clear Startup Config">
|
<input style="width:40%;" class="action" id="clear_config" onclick="clearConfig();" type="button" data-i18n="sys_clear_config" value="Clear Startup Config">
|
||||||
<br/>
|
<br/>
|
||||||
<input style="width:40%;" class="action" id="flash_startup_sub" onclick="flashStartupSave();" type="button" value="Save Startup Settings to Flash">
|
<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/>
|
<br/>
|
||||||
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" value="Reset Switch">
|
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" data-i18n="sys_reset" value="Reset Switch">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="lcol"> <label for="gw">Gateway:</label></div>
|
<div id="console-tab" class="tab-content">
|
||||||
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
<h1 data-i18n="sys_console">Console Command</h1>
|
||||||
</div><br/>
|
<label for="console_command" data-i18n="sys_enter_cmd">Enter command:</label>
|
||||||
When updating the above settings, remember to point your browser to the new IP afterwards:<br/>
|
<input type="text" id="console_cmd" name="console_cmd" style="width:40%;">
|
||||||
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" value="Update Settings"><br/>
|
<input style="width:20%;" class="action" id="cmd_sub" onclick="cmdSub();" type="button" data-i18n="sys_send_cmd" value="Send Command"><br/>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<label class="dhcpdon">Enable DHCP Server: <input id="dhcpd" type="checkbox"></label><br/><br/>
|
<span data-i18n="sys_console_warn">Be careful when entering console commands, you can lock yourself out!</span><br/>
|
||||||
<label class="dhcpdvlan">Limit DHCP Server to VLAN (0: serve all VLANs): <input type="number" min="0" max="2047" value="0" id="dhcpd_vid" name="dhcpd_vid"></label><br/>
|
|
||||||
<input style="width:40%;" class="action" id="dhcpd_sub" onclick="dhcpdSub();" type="button" value="Change DHCPD State"><br/><br/><br/>
|
</div>
|
||||||
Save all current settings to Flash:<br/>
|
|
||||||
<input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" value="Save Settings to Flash">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="/config.js"></script>
|
<script src="/config.js"></script>
|
||||||
|
|||||||
@@ -1,33 +1,27 @@
|
|||||||
var systemInterval = Number();
|
var systemInterval = Number();
|
||||||
|
var isSaving = false;
|
||||||
const ips = ["ip", "netmask", "gw"];
|
const ips = ["ip", "netmask", "gw"];
|
||||||
|
|
||||||
|
function changeLang() {
|
||||||
|
var lang = document.getElementById('lang-select').value;
|
||||||
|
setLang(lang);
|
||||||
|
}
|
||||||
|
|
||||||
function checkIp(ip) {
|
function checkIp(ip) {
|
||||||
const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/;
|
const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||||
if (!ipv4.test(ip)) {alert(`Invalid ip:${ip}`); return false };
|
if (!ipv4.test(ip)) {alert(t('sys_invalid_ip') + ip); return false };
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ipSub() {
|
async function ipSub() {
|
||||||
if (document.getElementById('dhcp').checked) {
|
|
||||||
var cmd = "ip dhcp";
|
|
||||||
try {
|
|
||||||
const response = await fetch('/cmd', {
|
|
||||||
method: 'POST',
|
|
||||||
body: cmd
|
|
||||||
});
|
|
||||||
console.log('Completed!', response);
|
|
||||||
systemInterval = setInterval(fetchIP, 10000);
|
|
||||||
} catch(err) {
|
|
||||||
console.error(`Error: ${err}`);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let i=0;i<3;i++) {
|
for (let i=0;i<3;i++) {
|
||||||
if (!checkIp(document.getElementById(ips[i]).value))
|
if (!checkIp(document.getElementById(ips[i]).value))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var cmd = '';
|
||||||
for (let i=0; i<3;i++){
|
for (let i=0; i<3;i++){
|
||||||
var cmd = ips[i]+' '+document.getElementById(ips[i]).value;
|
cmd += ips[i]+' '+document.getElementById(ips[i]).value+'\n';
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/cmd', {
|
const response = await fetch('/cmd', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -39,70 +33,63 @@ async function ipSub() {
|
|||||||
console.error(`Error: ${err}`);
|
console.error(`Error: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
async function dhcpdSub() {
|
async function cmdSub() {
|
||||||
var dhcpd_cmd = "dhcpd off";
|
var cmd = document.getElementById('console_cmd').value;
|
||||||
if (document.getElementById('dhcpd').checked) {
|
|
||||||
dhcpd_cmd = "dhcpd on";
|
|
||||||
var v=document.getElementById('dhcpd_vid').value
|
|
||||||
if (v && v!= 0)
|
|
||||||
dhcpd_cmd = dhcpd_cmd + " " + v;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
console.log("Sending: ", dhcpd_cmd);
|
|
||||||
const response = await fetch('/cmd', {
|
const response = await fetch('/cmd', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: dhcpd_cmd
|
body: cmd
|
||||||
});
|
});
|
||||||
console.log('Completed!', response);
|
console.log('Completed!', response);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(`Error: ${err}`);
|
console.error(`Error: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function dhcpClicked(e)
|
|
||||||
{
|
|
||||||
console.log("dhcpClicked called");
|
async function hostSub() {
|
||||||
if (e.checked) {
|
const h = document.getElementById("hostname").value;
|
||||||
for (let i=0; i<3;i++)
|
try { await fetch('/cmd', { method: 'POST', body: "hostname " + h }); }
|
||||||
document.getElementById(ips[i]).disabled = true;
|
catch(err) { console.error(`Error: ${err}`); }
|
||||||
document.getElementById('dhcpd').disabled = true;
|
fetchIP();
|
||||||
} else {
|
|
||||||
console.log("dhcpClicked off");
|
|
||||||
for (let i=0; i<3;i++)
|
|
||||||
document.getElementById(ips[i]).disabled = false;
|
|
||||||
document.getElementById('dhcpd').disabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function sendConfig(c) {
|
async function sendConfig(c) {
|
||||||
|
if (isSaving) return;
|
||||||
|
isSaving = true;
|
||||||
|
clearInterval(systemInterval);
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append("MAX_FILE_SIZE", "4096");
|
form.append("MAX_FILE_SIZE", "4096");
|
||||||
form.append("configuration", new Blob([c], {type: "application/octet-stream"}));
|
form.append("configuration", new Blob([c], {type: "application/octet-stream"}), "config.txt");
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/config', {
|
const response = await fetch('/config', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: form
|
body: form
|
||||||
});
|
});
|
||||||
console.log('Completed!', response);
|
console.log('Completed!', response);
|
||||||
|
try {
|
||||||
|
await fetch('/cmd_log_clear', { method: 'GET' });
|
||||||
|
} catch(e) {}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(`Error: ${err}`);
|
console.error(`Error: ${err}`);
|
||||||
|
} finally {
|
||||||
|
isSaving = false;
|
||||||
|
systemInterval = setInterval(fetchIP, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function flashSave() {
|
async function flashSave() {
|
||||||
fetchConfig().then((s) => {
|
configuration = [];
|
||||||
parseConf(s);
|
const savedConfig = await fetchConfig();
|
||||||
fetchCmdLog().then((s) => {
|
const cmdLog = await fetchCmdLog();
|
||||||
parseConf(s);
|
if (savedConfig) parseConf(savedConfig);
|
||||||
var body = "";
|
if (cmdLog) parseConf(cmdLog);
|
||||||
for (const x of configuration) { body = body + x + "\n"; }
|
const body = configuration.join('\n') + '\n';
|
||||||
console.log("CONFIGURATION to save: ", body);
|
console.log("CONFIGURATION to save: ", body);
|
||||||
sendConfig(body);
|
await sendConfig(body);
|
||||||
});
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
fetchIP();
|
|
||||||
}, 500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function flashStartupSave() {
|
async function flashStartupSave() {
|
||||||
@@ -144,8 +131,9 @@ function fetchIP() {
|
|||||||
document.getElementById("ip").value=s.ip_address;
|
document.getElementById("ip").value=s.ip_address;
|
||||||
document.getElementById("netmask").value=s.ip_netmask;
|
document.getElementById("netmask").value=s.ip_netmask;
|
||||||
document.getElementById("gw").value=s.ip_gateway;
|
document.getElementById("gw").value=s.ip_gateway;
|
||||||
document.getElementById('dhcp').checked = s.dhcp_client;
|
document.getElementById("hostname").value=s.hostname;
|
||||||
document.getElementById('dhcpd').checked = s.dhcp_server;
|
document.getElementById("model").textContent=s.hw_ver;
|
||||||
|
loadMgmtVlan();
|
||||||
clearInterval(systemInterval);
|
clearInterval(systemInterval);
|
||||||
// Fetch and populate the config textbox
|
// Fetch and populate the config textbox
|
||||||
fetchConfig().then((configText) => {
|
fetchConfig().then((configText) => {
|
||||||
@@ -164,15 +152,57 @@ function fetchIP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetSwitch() {
|
function resetSwitch() {
|
||||||
if (!confirm('Are you sure you want to reset the switch?')) {
|
if (!confirm(t('sys_reset_confirm'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetch('/reset', { method: 'GET' }).catch(() => {});
|
fetch('/reset', { method: 'GET' }).catch(() => {});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
alert('Switch is resetting. Please wait and refresh the page.');
|
alert(t('sys_resetting'));
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
|
var langSel = document.getElementById('lang-select');
|
||||||
|
if (langSel) langSel.value = rtlLang;
|
||||||
systemInterval = setInterval(fetchIP, 1000);
|
systemInterval = setInterval(fetchIP, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var mgmtVlanCurrent = 0;
|
||||||
|
|
||||||
|
function loadMgmtVlan() {
|
||||||
|
var sel = document.getElementById('mgmtvlan');
|
||||||
|
if (!sel) return;
|
||||||
|
fetch('/vlanlist').then(function(r) { return r.json(); }).then(function(d) {
|
||||||
|
var cur = d.mgmt || 0;
|
||||||
|
var list = d.vlan || [];
|
||||||
|
mgmtVlanCurrent = cur;
|
||||||
|
sel.innerHTML = '';
|
||||||
|
if (!cur) {
|
||||||
|
var none = document.createElement('option');
|
||||||
|
none.value = 0; none.disabled = true;
|
||||||
|
none.textContent = t('sys_mgmt_untagged');
|
||||||
|
sel.appendChild(none);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
var o = document.createElement('option');
|
||||||
|
o.value = list[i].id;
|
||||||
|
o.textContent = list[i].name ? (list[i].id + ' (' + list[i].name + ')') : list[i].id;
|
||||||
|
sel.appendChild(o);
|
||||||
|
}
|
||||||
|
sel.value = cur;
|
||||||
|
}).catch(function(err) { console.error('VLAN list failed:', err); });
|
||||||
|
}
|
||||||
|
|
||||||
|
function mgmtVlanChanged() {
|
||||||
|
var sel = document.getElementById('mgmtvlan');
|
||||||
|
var id = parseInt(sel.value, 10);
|
||||||
|
if (!id || id === mgmtVlanCurrent) return;
|
||||||
|
if (!confirm(t('sys_mgmt_confirm') + id + '.\n\n' + t('sys_mgmt_warn'))) {
|
||||||
|
sel.value = mgmtVlanCurrent;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch('/cmd', { method: 'POST', body: 'vlan ' + id + ' mgmt' })
|
||||||
|
.then(function() { mgmtVlanCurrent = id; })
|
||||||
|
.catch(function(err) { console.error('Set management VLAN failed:', err); sel.value = mgmtVlanCurrent; });
|
||||||
|
}
|
||||||
|
|||||||