Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85244d85f9 | ||
|
|
e280ccd2f9 | ||
|
|
baa4e5e142 | ||
|
|
b53e7e1a06 | ||
|
|
14b45735e2 | ||
|
|
946e80cebe | ||
|
|
e2df95ba90 | ||
|
|
570ee6c995 | ||
|
|
01fa43510e | ||
|
|
d2e79d4d80 | ||
|
|
016061d8db | ||
|
|
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 | ||
|
|
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 | ||
|
|
c2f5a91763 | ||
|
|
ed8dc0f43c | ||
|
|
893dcd8fcf | ||
|
|
16f4e2a1c6 | ||
|
|
364d538abd | ||
|
|
7949975191 | ||
|
|
1374272db6 | ||
|
|
20fb626cc1 | ||
|
|
31a488e4e9 | ||
|
|
14bc823024 | ||
|
|
87c161dc70 | ||
|
|
04ab083652 | ||
|
|
1836c7dcb6 | ||
|
|
4cef63200f | ||
|
|
e33cd9d0c5 | ||
|
|
71880a95f5 | ||
|
|
494320b191 | ||
|
|
eb13d4ab04 | ||
|
|
a15500c493 | ||
|
|
a89467febc | ||
|
|
706abcf78d | ||
|
|
c868482669 | ||
|
|
9bd2d446d7 | ||
|
|
c3a6a46852 | ||
|
|
7a0f248424 | ||
|
|
23e2f5a99e | ||
|
|
81a7393a81 | ||
|
|
dc16b25d62 | ||
|
|
ffbd2c512d | ||
|
|
ba18fa19b0 | ||
|
|
70127018da | ||
|
|
e26a9e3db9 | ||
|
|
d29d7dcf98 | ||
|
|
734cce381a | ||
|
|
dfc96761b3 | ||
|
|
94d4ace88b | ||
|
|
284b2b003d | ||
|
|
68a8a9ee92 | ||
|
|
0045a74df0 | ||
|
|
0bdb238c0a | ||
|
|
033616ef63 | ||
|
|
a57aeda053 | ||
|
|
556899d346 | ||
|
|
cc734ecac2 | ||
|
|
e5d23f11de | ||
|
|
3c648d5936 | ||
|
|
4658667459 | ||
|
|
e966b153af | ||
|
|
5ecd0e6a32 | ||
|
|
d8b52d50de | ||
|
|
1f6f7fbcd4 | ||
|
|
c7ea28393a | ||
|
|
2f787feebf | ||
|
|
4c1266dca9 | ||
|
|
4d11d70356 | ||
|
|
ff94e383aa | ||
|
|
9f7e10fe7c | ||
|
|
b67e3eb602 | ||
|
|
5d731393f1 | ||
|
|
0e2a5fb7bc | ||
|
|
79c9d0deab | ||
|
|
73c56ecfe5 | ||
|
|
5e9f3324d5 | ||
|
|
94739644b7 | ||
|
|
257d8aac4f | ||
|
|
d5019b41df | ||
|
|
eae7f10d7a | ||
|
|
1b43addb11 | ||
|
|
f8c1ab4198 | ||
|
|
11a5feb49d | ||
|
|
1e7e1f42cc | ||
|
|
ea37126e87 | ||
|
|
670e0f02ec | ||
|
|
b4e7865bb7 | ||
|
|
15b0bf9664 | ||
|
|
8bd07ee649 | ||
|
|
3e1031b0f0 | ||
|
|
9918a6267c | ||
|
|
bea162962e | ||
|
|
a2ce5550fc | ||
|
|
1d91c1bf2c | ||
|
|
9d8d6f03cc | ||
|
|
98f3f15e7e | ||
|
|
6f223d3f66 | ||
|
|
fe1df83a88 | ||
|
|
e7b7cb0253 | ||
|
|
4a3cd7b73c | ||
|
|
f538a9344b | ||
|
|
f2b81af702 | ||
|
|
651bdb6489 | ||
|
|
841e1bf95e | ||
|
|
7e652f3fb7 | ||
|
|
90be2f47a3 | ||
|
|
859a50bd82 | ||
|
|
75b06ac90a | ||
|
|
d2edb92ddf | ||
|
|
0099c2a03a | ||
|
|
d29adafe3c | ||
|
|
59894e68cb | ||
|
|
6af072eb2c | ||
|
|
8cae3f1212 | ||
|
|
9aaddcd9b9 | ||
|
|
196e430ec6 | ||
|
|
9424aa3a3b | ||
|
|
7a57416e4c | ||
|
|
fc53003022 | ||
|
|
47878ac580 | ||
|
|
d83f91f9e8 | ||
|
|
708b6b7f28 | ||
|
|
9d07416641 | ||
|
|
4747eac9bf | ||
|
|
ecf152990f | ||
|
|
d4ed753715 | ||
|
|
ea230615f9 | ||
|
|
8f3cabdaff | ||
|
|
eafe2e96e8 | ||
|
|
c4dc930ca8 | ||
|
|
180de32060 | ||
|
|
68fd5d41a7 | ||
|
|
6263b7e4c6 | ||
|
|
ee190a86a1 | ||
|
|
97b46071e0 | ||
|
|
ed37d75aba | ||
|
|
3496d12111 | ||
|
|
cfb7a589a8 | ||
|
|
5391d3ec32 | ||
|
|
f6e4f13ebd | ||
|
|
dbb8fe1249 | ||
|
|
620edc1ba3 | ||
|
|
48455a57b2 | ||
|
|
7d62b24a42 | ||
|
|
2c200417b5 | ||
|
|
2a5f1de8f7 | ||
|
|
9d4eef2dd6 | ||
|
|
55fd2d5fb6 | ||
|
|
aae055123e | ||
|
|
5a11515c36 | ||
|
|
934014c68c | ||
|
|
5662285a3e | ||
|
|
1d94e99612 | ||
|
|
a134335308 | ||
|
|
6495310ba9 | ||
|
|
5962c3a8a6 | ||
|
|
a6e452e638 | ||
|
|
7f4c276285 | ||
|
|
f9fdc6b81d | ||
|
|
d9185b3505 | ||
|
|
3d7ef55ced | ||
|
|
44779404df | ||
|
|
1997d7379b | ||
|
|
b5c249995f | ||
|
|
c61fb6d2fe | ||
|
|
c11099b9ec | ||
|
|
13d0781455 | ||
|
|
b2514bf176 | ||
|
|
c36136047c | ||
|
|
fc327810ed | ||
|
|
b7b4594406 | ||
|
|
aa750d8ff1 | ||
|
|
17b428a603 | ||
|
|
a0313eab87 | ||
|
|
0345bf7bf2 | ||
|
|
1e8382bd56 | ||
|
|
8dc914eb07 | ||
|
|
a528436572 | ||
|
|
2cdeda3bc9 | ||
|
|
a72528b724 | ||
|
|
1e073b20b6 | ||
|
|
efcbc8b4a8 | ||
|
|
13e9dbbc7b | ||
|
|
f48c84b18e | ||
|
|
3bfcabbb99 | ||
|
|
5eecab4844 | ||
|
|
fd1d14a3e7 | ||
|
|
34cebe5971 | ||
|
|
4269745521 | ||
|
|
af3be9a067 | ||
|
|
e8a719d911 | ||
|
|
e74c4f148a | ||
|
|
d1d5d5e18f | ||
|
|
892920a627 | ||
|
|
eb0e90df5c | ||
|
|
2ce168883b | ||
|
|
e54313eded | ||
|
|
300f599551 | ||
|
|
73a355cff5 | ||
|
|
e53f5e7134 | ||
|
|
3509f7da04 | ||
|
|
55d10ae3fc | ||
|
|
88e706c295 | ||
|
|
e59158e006 | ||
|
|
e0c9338357 | ||
|
|
e7df748b6a | ||
|
|
5cb1acfc15 | ||
|
|
46864ca9a7 | ||
|
|
00b42db5da | ||
|
|
84fe44cc9a | ||
|
|
6326428406 | ||
|
|
f33c4e3dc9 | ||
|
|
4a615cb4bd | ||
|
|
030772f1ef | ||
|
|
4ce8adf954 | ||
|
|
66c58a50df | ||
|
|
48c12fa0bb | ||
|
|
d2d7ab7ff1 | ||
|
|
f43bb4eac4 | ||
|
|
4e8eb6d766 | ||
|
|
c5c6b97ad1 | ||
|
|
229fad3809 | ||
|
|
52522968c7 | ||
|
|
7d04ea1980 | ||
|
|
34d6024eeb | ||
|
|
d52aeca609 | ||
|
|
e085fc9cc9 | ||
|
|
f621563479 | ||
|
|
0fe70f6b62 | ||
|
|
745c170f0a | ||
|
|
5b4b0efb16 | ||
|
|
b818a94202 | ||
|
|
bbd4656810 | ||
|
|
8b061d5fb9 | ||
|
|
5ed4d7afc7 | ||
|
|
e73d82ec33 | ||
|
|
52832ff299 | ||
|
|
787a82e846 | ||
|
|
3653f90356 | ||
|
|
9ff114d234 | ||
|
|
0abe83e3e5 | ||
|
|
2a7b8f9838 | ||
|
|
7fdf9ca86d | ||
|
|
2b364943c2 | ||
|
|
a8227f1855 | ||
|
|
34a0e2d338 | ||
|
|
4878a36638 | ||
|
|
dd7a5ebb95 | ||
|
|
3ef7e45649 | ||
|
|
2a7bfdc119 | ||
|
|
367bef2b2f | ||
|
|
cad74017a9 | ||
|
|
3af63af4a4 | ||
|
|
b7cfc73752 | ||
|
|
51345a07e6 | ||
|
|
67fbad38ce | ||
|
|
67439efd2b | ||
|
|
b4b8ad5738 | ||
|
|
eb0106d9f4 | ||
|
|
f0537d759f | ||
|
|
36d5ee3ddd | ||
|
|
6441e85752 | ||
|
|
053c16b84e | ||
|
|
4e9fb19e05 | ||
|
|
0a0e1856ae | ||
|
|
cedd81cf00 | ||
|
|
bf00f9aa2c | ||
|
|
f46cb02828 | ||
|
|
0779222194 | ||
|
|
44ce073869 | ||
|
|
c20ec6b081 | ||
|
|
ed62e46790 | ||
|
|
12595f806a | ||
|
|
58c9af242d | ||
|
|
dc9bc5ec7d | ||
|
|
44792699bf | ||
|
|
12db61faf7 | ||
|
|
519c224dd2 | ||
|
|
b442417a8a | ||
|
|
87717a0790 | ||
|
|
81fdb14213 | ||
|
|
6fd32d290c | ||
|
|
6272d949cd | ||
|
|
9c4d49bc8c | ||
|
|
95fae8bad2 | ||
|
|
6dfad825c0 | ||
|
|
c8c524b71f | ||
|
|
96977b5d88 | ||
|
|
a84c5dcd0c | ||
|
|
b1d5352214 | ||
|
|
677e01fa18 | ||
|
|
b41452026f | ||
|
|
0197c9b6cf | ||
|
|
2ed9974c04 | ||
|
|
11d2c843e5 | ||
|
|
28f832a24d | ||
|
|
d71a303f6c | ||
|
|
74364ed7e8 | ||
|
|
e6cf97b895 | ||
|
|
1cdc8d2cf7 | ||
|
|
a453ec72dc | ||
|
|
edfb86bff4 | ||
|
|
45d4fc19c4 | ||
|
|
d75ad636f9 | ||
|
|
6b96c3b70b | ||
|
|
35ab8cc5e0 | ||
|
|
06fbf85bce | ||
|
|
3c869e927a | ||
|
|
ab6a66a223 | ||
|
|
636981c3b8 | ||
|
|
101b4937e1 | ||
|
|
e9b8ab5b79 | ||
|
|
32b5539670 | ||
|
|
fccafe8059 | ||
|
|
68405f70d2 | ||
|
|
e7301dc39f | ||
|
|
94b6688e57 | ||
|
|
3679b46ff2 | ||
|
|
52fe23570c | ||
|
|
6557fc53e5 | ||
|
|
4b2d7002dc | ||
|
|
b82b957750 | ||
|
|
8284554f69 | ||
|
|
47aa6ab7bf | ||
|
|
42ea80a480 | ||
|
|
e63d1bf577 | ||
|
|
1c78d32493 | ||
|
|
b910692caf | ||
|
|
9c21d94b65 | ||
|
|
7f715e9218 | ||
|
|
ad27566030 | ||
|
|
0722b147fe | ||
|
|
4e4e6a55ba | ||
|
|
dc6734236c | ||
|
|
70c14fb23e | ||
|
|
73a81ec031 | ||
|
|
cac7fbe080 | ||
|
|
6e0e907afb | ||
|
|
a8a770f27f | ||
|
|
69110531b7 | ||
|
|
00a415c755 | ||
|
|
f485102d26 | ||
|
|
4d915a0d80 | ||
|
|
9d4ba57cd0 | ||
|
|
ba9bc2e845 | ||
|
|
76344e172c | ||
|
|
f59be9cf2b | ||
|
|
17fdbf39f0 |
@@ -0,0 +1,23 @@
|
|||||||
|
name: Build firmware
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ['**']
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: debian:trixie
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
apt update
|
||||||
|
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
|
||||||
|
run: make MACHINE="KP_9000_6XHML_X2"
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
.gitignore
|
.gitignore
|
||||||
|
.idea/
|
||||||
output/
|
output/
|
||||||
html_data.c
|
html_data.c
|
||||||
html_data.h
|
html_data.h
|
||||||
|
version.h
|
||||||
tools/httpd_sim
|
tools/httpd_sim
|
||||||
tools/injector
|
tools/injector
|
||||||
tools/fileadder
|
tools/fileadder
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 The RTLPlayground Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,30 +1,51 @@
|
|||||||
BOOTLOADER_ADDRESS=0x100
|
VERSION=0.1.0
|
||||||
|
|
||||||
IMAGESIZE = 524288
|
IMAGESIZE = 524288
|
||||||
|
DEFAULT_CONFIG_LOCATION = 454656
|
||||||
CONFIG_LOCATION = 458752
|
CONFIG_LOCATION = 458752
|
||||||
HTML_LOCATION = 262144
|
HTML_LOCATION = 262144
|
||||||
|
|
||||||
CC = sdcc
|
CC = sdcc
|
||||||
CC_FLAGS = -mmcs51 -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/
|
BUILDDIR = output
|
||||||
|
VERSION_HEADER := version.h
|
||||||
|
|
||||||
all: create_build_dir $(SUBDIRS) $(BUILDDIR)rtlplayground.bin
|
ifeq ($(MACHINE),)
|
||||||
|
else
|
||||||
|
CC_FLAGS += -DMACHINE_$(MACHINE)
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground.bin
|
||||||
|
|
||||||
create_build_dir:
|
create_build_dir:
|
||||||
mkdir -p $(BUILDDIR)
|
mkdir -p $(BUILDDIR)
|
||||||
|
mkdir -p $(BUILDDIR)/uip
|
||||||
|
mkdir -p $(BUILDDIR)/httpd
|
||||||
|
mkdir -p $(BUILDDIR)/crypto
|
||||||
|
|
||||||
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c rtl837x_stp.c
|
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c
|
||||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
SRCS += rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c cmd_editor.c rtl837x_bandwidth.c rtl837x_init.c
|
||||||
OBJS += uip/$(BUILDDIR)/timer.rel uip/$(BUILDDIR)/uip-fw.rel uip/$(BUILDDIR)/uip-neighbor.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
|
SRCS += uip/timer.c uip/uip.c uip/uip_arp.c uip/uiplib.c uip/uip-fw.c uip/uip-neighbor.c uip/uip-split.c
|
||||||
|
SRCS += httpd/httpd.c httpd/page_impl.c
|
||||||
|
SRCS += crypto/chacha20.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
|
html_data.c html_data.h: $(HTML) tools/$(BUILDDIR)/fileadder
|
||||||
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
|
tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
|
||||||
|
|
||||||
|
$(VERSION_HEADER):
|
||||||
|
@echo "#ifndef 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 BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
|
||||||
|
@echo "#endif" >> $(VERSION_HEADER)
|
||||||
|
|
||||||
httpd: html_data.h
|
httpd: html_data.h
|
||||||
|
|
||||||
@@ -32,39 +53,41 @@ $(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
|
-rm -rf $(BUILDDIR)
|
||||||
-rm html_data.c html_data.h
|
|
||||||
-rm -r $(BUILDDIR)
|
|
||||||
|
|
||||||
$(BUILDDIR)crtstart.rel: crtstart.asm
|
$(BUILDDIR)/%.rel: %.asm
|
||||||
$(ASM) $(AFLAGS) -o $@ $<
|
|
||||||
|
|
||||||
$(BUILDDIR)crc16.rel: crc16.asm
|
|
||||||
$(ASM) $(AFLAGS) -o $@ $<
|
|
||||||
|
|
||||||
$(BUILDDIR)%.rel: %.c
|
|
||||||
$(CC) $(CC_FLAGS) -o $@ -c $<
|
|
||||||
|
|
||||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
|
||||||
${ASM} ${AFLAGS} -o $@ $<
|
${ASM} ${AFLAGS} -o $@ $<
|
||||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
|
||||||
|
|
||||||
$(BUILDDIR)rtlplayground.ihx: $(BUILDDIR)crtstart.rel $(OBJS) $(BUILDDIR)crc16.rel
|
$(BUILDDIR)/%.rel: %.c
|
||||||
$(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -Wl-bBANK1=0x14000 -Wl-r -o $@ $^
|
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||||
|
|
||||||
$(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx
|
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtstart.rel $(BUILDDIR)/crc16.rel $(BUILDDIR)/crypto/chacha_8051.rel
|
||||||
|
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
|
||||||
|
|
||||||
|
$(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.bin: $(BUILDDIR)/rtlplayground.img
|
||||||
if [ -e $@ ]; then rm $@; fi
|
if [ -e $@ ]; then rm $@; fi
|
||||||
echo "0000000: 00 40" | xxd -r - $@
|
tools/$(BUILDDIR)/imagebuilder -i $^ $@
|
||||||
cat $< >> $@
|
tools/$(BUILDDIR)/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||||
truncate --size=16K $@
|
tools/$(BUILDDIR)/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||||
dd if=$< skip=80 bs=1024 >>$@
|
tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data -b BANK1 $@
|
||||||
tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
tools/$(BUILDDIR)/crc_calculator -u $@
|
||||||
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@
|
|
||||||
tools/$(BUILDDIR)crc_calculator -u $@
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean all $(SUBDIRS)
|
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER)
|
||||||
|
|
||||||
|
.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)
|
||||||
|
|||||||
@@ -1,195 +1,100 @@
|
|||||||
# RTLPlayground
|
# RTLPlayground
|
||||||
A Playground for Firmware development for RTL8372/RTL8373 based 2.5GBit Switches.
|
A Playground for Firmware development for advanced user of RTL8372/RTL8373 based 2.5GBit Switches.
|
||||||
|
|
||||||
For each hardware configuration of these devices, there is usually a managed and an
|
For each hardware configuration of these devices, there is usually a managed and an
|
||||||
umanaged version sold, with mostly identical hardware. The aim is to provide management
|
umanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||||
features also for unmanaged devices with additional features such as Management VLAN,
|
features also for unmanaged devices with additional features such as Management VLAN,
|
||||||
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages.
|
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||||
|
only the following features are provided:
|
||||||
|
- A modern web-interface with mouse-over to display further information
|
||||||
|
- A serial console interface to configure all features
|
||||||
|
- IGMP to configure Multicast streaming
|
||||||
|
- Port configuration showing detailed informtion about own and Link-partner advertised
|
||||||
|
Speed settins and configuration of these settings on the local side
|
||||||
|
- Per-port configuration of frame sizes (MTUs) for Jumbo-Frame support or limiting MTUs
|
||||||
|
for particular devices
|
||||||
|
- EEE (Energy Efficient Ethernet) can be configured per-port. Detailed information is
|
||||||
|
provided for support offered by the link partner and the EEE status of a port.
|
||||||
|
- VLAN configuration
|
||||||
|
- SFP information is displayed on the inserted modules, the current sensor values such as
|
||||||
|
temperatures, RX and TX power are displayed in the CLI and as mouse-over on the web
|
||||||
|
- Mirror configuration
|
||||||
|
- Link Aggregation Groups can be set up
|
||||||
|
- Detailed information on port packet statistics
|
||||||
|
- Configuration saved to flash via the web-interface
|
||||||
|
- Firmware updates via the web
|
||||||
|
- Installation as a firmware upgrade from the original web-interface
|
||||||
|
|
||||||
The playground currently provides a minimal alternative firmware for both the managed and unmanaged switches.
|
<img width="1420" height="623" alt="GUI" src="doc/images/gui.png" />
|
||||||
When used with unmanaged switches, it will provide some management features such as
|
|
||||||
setting up VLANs, mirroring ports and provide a Web-Server (currently no functions,
|
|
||||||
really), but will need to be configured via a serial connection. Installation on
|
|
||||||
managed devices only makes sense for developers, as plenty of features of the managed
|
|
||||||
switches are not supported, yet.
|
|
||||||
|
|
||||||
At this point, the firmware can be installed on the hardware as given below,
|
While the firmware provides already considerable improvements over the original managed firmware,
|
||||||
all of the ports and SFP-slots will be supported. The following has been tested:
|
the firmware still lacks support for STP and the proprietary loop prevention
|
||||||
On the keepLINK kp-9000-6hx-x (RTL8372 + RTL8221B 2.5GBit PHY: 5 x 2.5GBit + 1x 10GBit SFP+),
|
protocols as well as DHCP. If you need these features, do not install the playground on your managed
|
||||||
at present the system will provide the same featurs as a dumb switch plus a tiny
|
devices. In any case, installation is strongly discouraged unless you can at least make
|
||||||
TCP stack that will allow to reply to ARP and ping messages, thus enabling pinging the device.
|
a backup of the original flash content via a SOIC clamp such as also used for BIOS
|
||||||
VLAN and mirroring can be configured (but not saved to flash).
|
backups and can re-install that firmware in case something is wrong. For this no soldering
|
||||||
The ports served by the RTL8372 will be 100M/1G/2.5G auto-detect. Port 5 to RTL8221B PHY
|
skills are necessary.
|
||||||
SerDes configuration works and supports 1GBit and 2.5GBit Ethernet (SGMII/HISGMII).
|
|
||||||
SFP module insert/removal identification and reading of the SFP EEProm works. SFP
|
|
||||||
module configuration works, too, tested for 1G, 2.5G and 10G Ethernet and Fiber modules.
|
|
||||||
|
|
||||||
The 4-Port Ethernet + 2 Port SFP+ devices (e.g. KP-9000-6HX-x2) are fully supported, too
|
The firmware supports all hardware featues of devices with
|
||||||
(e.g. KP-9000-6hx-x2) with the same features as above. In particular all fiber/Ethernet
|
- 4 2.5GBit ports + 2 SFP+ ports
|
||||||
modules work in both SFP+ ports.
|
- 5 2.5GBIT + 1 SFP+ port
|
||||||
|
- 8 2.5GBit + 1 SFP+ port
|
||||||
On the 9-port devices with RTL8273 + RTL8224 (for example kp-9000-9xh-x) all ports will
|
Devices sold usually have a fairly common design, however there may be differences in the LED
|
||||||
work for switching and CPU-access, the SFP+ port will work normally and TCP connectivity
|
configuration (switches have LEDs with different colours and use types of LEDs). The list
|
||||||
will work as above. Not all features of the RTL8224-ports (the first 4) have been tested.
|
of tested devices can be found in [Supported devices](doc/supported_devices.md).
|
||||||
|
|
||||||
To do meaningful development you will need to use a serial console, so soldering skills
|
To do meaningful development you will need to use a serial console, so soldering skills
|
||||||
are required. Flashing must be done via a SOIC-8 PatchClamp or by soldering a socket
|
are required. Flashing must be done via a SOIC-8 PatchClamp or by soldering a socket
|
||||||
for the flash chip.
|
for the flash chip.
|
||||||
|
|
||||||
UPDATE: The Code comes with a port of the [uIP](https://github.com/adamdunkels/uip)
|
|
||||||
TCP/IP stack and includes a minimal web-server that can be used to work with the switch,
|
|
||||||
so if you use a patch-clamp for updating the firmware (~3 USD/EUR), you can try this
|
|
||||||
out without the need to solder anything. See the instructions below.
|
|
||||||
Note that updating the firmware of a managed switch with the images created in this
|
|
||||||
project via the OEM web-interface will not work, because it is currently unknown how
|
|
||||||
to generate the require checksum, see this
|
|
||||||
[issue](https://github.com/up-n-atom/SWTG118AS/issues/4).
|
|
||||||
However, if you use the patch-clamp to flash, this is not a problem.
|
|
||||||
|
|
||||||
If you don't want to open your device, you can use the project's code to learn about the
|
If you don't want to open your device, you can use the project's code to learn about the
|
||||||
devices by looking at the image using e.g. Ghidra.
|
devices by looking at the image using e.g. Ghidra. If you want to contribute to the
|
||||||
|
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.
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
Install the following particular build requisites (Debian 12, should work on Ubuntu)
|
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
|
||||||
|
still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile:
|
||||||
```
|
```
|
||||||
sudo apt install sdcc xxd python
|
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev
|
||||||
```
|
```
|
||||||
|
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
|
||||||
Now, building the firmware image should work:
|
Now, building the firmware image should work:
|
||||||
```
|
```
|
||||||
$ make
|
make
|
||||||
sdas8051 -plosgff crtstart.asm
|
|
||||||
sdcc -mmcs51 -c rtlplayground.c
|
|
||||||
sdcc -mmcs51 -c rtl837x_flash.c
|
|
||||||
sdcc -mmcs51 -Wl-bHOME=0x100 -o rtlplayground.ihx crtstart.rel rtlplayground.rel rtl837x_flash.rel
|
|
||||||
objcopy --input-target=ihex -O binary rtlplayground.ihx rtlplayground.img
|
|
||||||
if [ -e rtlplayground.bin ]; then rm rtlplayground.bin; fi
|
|
||||||
echo "0000000: 00 40" | xxd -r - rtlplayground.bin
|
|
||||||
cat rtlplayground.img >> rtlplayground.bin
|
|
||||||
```
|
```
|
||||||
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
mkdir -p output/
|
||||||
|
gcc updatebuilder.c -o output/updatebuilder
|
||||||
|
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
|
||||||
|
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
|
||||||
|
cp ../output//rtlplayground.bin output/
|
||||||
|
./output//updatebuilder -i output/rtlinstaller.ihx output/rtlplayground.bin
|
||||||
|
Input file size: 524288
|
||||||
|
Bytes read: 524288
|
||||||
|
EOF
|
||||||
|
Payload sum 1 is: 0x29d10
|
||||||
|
Payload sum 2 is: 0x29d10
|
||||||
|
Payload sum with header is: 0x2b0fc
|
||||||
|
Payload sum is: 0xad8a75
|
||||||
|
Header checksum is: 0x4c3
|
||||||
|
```
|
||||||
|
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
|
## Installation
|
||||||
You can play with the image using ghidra or flash real Switch Hardware
|
You can play with the image using ghidra or flash real Switch Hardware. For
|
||||||
|
ghidra see this information about [Ghidra images](ghidra.md).
|
||||||
### Supported Hardware
|
|
||||||
If you do not have an RTL837x-based switch device such as the ones
|
|
||||||
mentionned here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide]
|
|
||||||
(https://github.com/up-n-atom/SWTG118AS) or one of the other that
|
|
||||||
deployment was tested on, including:
|
|
||||||
- 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
|
|
||||||
|
|
||||||
### Understanding the image using ghidra
|
|
||||||
Start ghidra, load file starting from offset 0x0002 into
|
|
||||||
memory starting at 0x0000. The lengthe is 0x10000. Select generic 8051, big
|
|
||||||
endian.
|
|
||||||
|
|
||||||
After loading, the boot vector is at 0x0000, which will jump to 0x0100 for
|
|
||||||
the boot routine.
|
|
||||||
|
|
||||||
The firmware uses only bank 1 of the RTL837x since it is quite short.
|
|
||||||
Otherwise the firmware would be organized as follows
|
|
||||||
```
|
|
||||||
--------------------------- 0x0000 ---------------------------------
|
|
||||||
Boot-Vector
|
|
||||||
ISRs
|
|
||||||
Common Code
|
|
||||||
Trampoline for inter-bank calls
|
|
||||||
Inter-bank calls, calling trampoline, one for each callable function
|
|
||||||
|
|
||||||
----- Bank 1 0x4000 ------ ---- Bank 2 0x4000 ----- -------- .....
|
|
||||||
Overlay 1 Overlay 2 Overlay n
|
|
||||||
|
|
||||||
--------- 0xffff --------- -------- 0xffff -------- -------- 0xffff
|
|
||||||
```
|
|
||||||
The RTL837x firmware images are organized as follows:
|
|
||||||
The first 2 bytes of the image give the size of the prefetched data at the
|
|
||||||
start of the CPU power up. The default is 0x4000 (bytes: 0x00 0x40), which
|
|
||||||
means that the entire shared area of the code memory in all banks,
|
|
||||||
0x4000 bytes is read immediately into the code RAM.
|
|
||||||
|
|
||||||
Common code starts at
|
|
||||||
0x0002 in the image and has length 0x3ffd, the first bank starts at 0x4000
|
|
||||||
in the image, is mapped to 0x4000 and has length 0xc000. The second bank
|
|
||||||
starts at 0x10000, is mapped to 0x4000 and has length 0xc000. The third
|
|
||||||
bank would start at 0x1c000 and would again be mapped to 0x4000.
|
|
||||||
There are about 30 banks in use for managed switches, unmanaged ones use
|
|
||||||
2-3, while the hardware would allow to use 0x3f banks, i.e. up to 4 MB of
|
|
||||||
flash.
|
|
||||||
|
|
||||||
The current image uses Common BANK0 and the first BANK1 via sdccs __banked
|
|
||||||
function keyword and custom banking trampoline code for the RTL837x in
|
|
||||||
assembler.
|
|
||||||
|
|
||||||
|
|
||||||
### Hardware supported by the code so far
|
|
||||||
|
|
||||||
-The following hardware is supported:
|
|
||||||
- Clock generation, including different divider settings
|
|
||||||
- Interrupt control for timer, serial, external irqs 0, 1
|
|
||||||
- Serial console via SFRs
|
|
||||||
- Flash operations via SFRs
|
|
||||||
- Bank switching via SFRs
|
|
||||||
- Access to Switch registers via SFRs
|
|
||||||
- LED setup
|
|
||||||
- Reset
|
|
||||||
- Some switch settings such as MAC configuration
|
|
||||||
- GPIO to detect SFP module insert/removal/RX-LOS
|
|
||||||
- I2C to read SFP EEPROM on 1 and 2 SFP slot devices
|
|
||||||
- NIC setup
|
|
||||||
- L2 learning table access, L2 table flushing
|
|
||||||
- VLAN setup/configuration
|
|
||||||
- Port mirroring
|
|
||||||
- Access to PHYs via MDIO (clause 45 via SFR):
|
|
||||||
- Internal PHYs of RTL8372 and RTL8373
|
|
||||||
- RTL8221 (1x2.5GBit port on devices with 5 ports)
|
|
||||||
- RTL8224 (4x2.5GBit ports on devices with 8 ports)
|
|
||||||
- SerDes settings of SoC via SFR:
|
|
||||||
- Configure SFPs with 10Gbit/2.5Gbit/1Gbit (Ethernet and Fiber SFP(+) tested)
|
|
||||||
- RTL8221, RTL8224
|
|
||||||
- NIC TX and RX of packets via SFRs
|
|
||||||
- send and receive Ethernet frames via SFRs and Switch registers
|
|
||||||
- RTL-tags and VLAN ingress-tag decoding for CPU-port
|
|
||||||
|
|
||||||
Ethernet frame RX IRQ via IRQ1 is conceptually understood, but not activated. RX is
|
|
||||||
currently done via polling, which allows ping-times of <10ms.
|
|
||||||
|
|
||||||
The RTL8372/3 have 256 bytes of internal RAM (INTMEM) accessible through MOV
|
|
||||||
instructions, which are used for the stack and important globals. Some of
|
|
||||||
these are bit-adressable, e.g. for storing global flags.
|
|
||||||
|
|
||||||
Additionally, 64kB of extended RAM (XMEM) is built in, which is accessed
|
|
||||||
through the MOVX instruction. It is used for global variables, for most
|
|
||||||
of the function argument passing that is not done using the 8 registers
|
|
||||||
R0-R7 or registers A/B, and for local variables (which requires extremely
|
|
||||||
careful planning). The flash memory is transparently accessible for code
|
|
||||||
being executed and can be used to store configuration. Access is done through
|
|
||||||
the MOVC instruction, possibly setting the bank register before and
|
|
||||||
resetting it to access the entire 4MB space. Code is prefetched from flash
|
|
||||||
and cached in a small RAM automatically by the HW.
|
|
||||||
|
|
||||||
The peripherial functions are accessed through 2 different mechanisms:
|
|
||||||
- Special Function Registers (SFRs, 0x80-0xff) for banking, timers, UART, access to
|
|
||||||
switch registers, MDIO, SPI (flash) and NIC transfers. Some SFRs are not
|
|
||||||
used for HW purposes and can be used as RAM. Some SFRs are bit-adressable,
|
|
||||||
allowing for very tight event wait loops (a single 2-byte instruction).
|
|
||||||
- 0x10000 switch registers, which appear to be very similar to the registers
|
|
||||||
of the RTL838x, for which source code and datasheets are available. This
|
|
||||||
controls clock dividers, GPIO/LEDs and general switch functionality.
|
|
||||||
|
|
||||||
The playground image shows access to the different types of memory using the
|
|
||||||
SDCC compiler. Any support of Linux or e.g. Zephyr would require porting gcc.
|
|
||||||
There are FreeRTOS ports to 8051 processors using sdcc, however.
|
|
||||||
|
|
||||||
|
|
||||||
### Installation on an actual switch
|
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
|
> NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
|
||||||
@@ -197,8 +102,15 @@ There are FreeRTOS ports to 8051 processors using sdcc, however.
|
|||||||
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
|
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
|
||||||
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
|
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
|
||||||
|
|
||||||
There is no support for uploading the firmware via ethernet. Instead you
|
You can upload the upgrade image of managed switches via the web interface of the
|
||||||
need to open the switch and flash the image directly onto the flash chip,
|
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,
|
||||||
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
|
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
|
||||||
flash chip and install a SOIC adapter):
|
flash chip and install a SOIC adapter):
|
||||||
- Disconnect power from switch
|
- Disconnect power from switch
|
||||||
@@ -217,6 +129,10 @@ devices, set 8N1 @ 115200 baud and power up the switch.
|
|||||||
The device will perform some examples and provide a minimal console, the
|
The device will perform some examples and provide a minimal console, the
|
||||||
documentation of which can be found in the source code rtlplayground.c`.
|
documentation of which can be found in the source code rtlplayground.c`.
|
||||||
|
|
||||||
|
## The web-interface
|
||||||
|
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247).
|
||||||
|
The default password is `1234`.
|
||||||
|
|
||||||
## 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:
|
||||||
@@ -307,9 +223,12 @@ Enjoy playing!
|
|||||||
## Other documents
|
## Other documents
|
||||||
The following documents give further documentation on specific features of
|
The following documents give further documentation on specific features of
|
||||||
the RTL837x SoCs:
|
the RTL837x SoCs:
|
||||||
|
- [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)
|
||||||
- [Mirroring](doc/mirroring.md)
|
- [CPU Port](doc/CpuPort.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)
|
||||||
- [VLAN](doc/vlan.md)
|
- [VLAN](doc/vlan.md)
|
||||||
|
- [Modifications and Flash replacement](doc/mods.md)
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
#include "cmd_parser.h"
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
#pragma codeseg BANK2
|
||||||
|
#pragma constseg BANK2
|
||||||
|
|
||||||
|
// Position in the serial buffer
|
||||||
|
__xdata uint8_t l;
|
||||||
|
// Properties of currently edited command line in cmd_buffer[CMD_BUF_SIZE]
|
||||||
|
__xdata uint8_t cursor;
|
||||||
|
__xdata uint8_t cmd_line_len;
|
||||||
|
__xdata uint8_t current_cmdline[CMD_BUF_SIZE];
|
||||||
|
__xdata uint16_t history_editptr;
|
||||||
|
|
||||||
|
|
||||||
|
extern __xdata uint8_t cmd_history[CMD_HISTORY_SIZE];
|
||||||
|
extern __xdata uint16_t cmd_history_ptr;
|
||||||
|
|
||||||
|
void cmd_editor_init(void) __banked
|
||||||
|
{
|
||||||
|
l = sbuf_ptr; // We have printed out entered characters until l
|
||||||
|
cursor = 0;
|
||||||
|
cmd_line_len = 0;
|
||||||
|
cmd_available = 0;
|
||||||
|
history_editptr = 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allows editing the current command line held in cmd_buffer[CMD_BUF_SIZE] by
|
||||||
|
* identifying new characters typed or up to 4-byte escape sequences in the
|
||||||
|
* serial buffer ring sbuf[SBUF_SIZE].
|
||||||
|
* Upon detecting new characters or escape sequences, the cmd_buffer and the
|
||||||
|
* representation of the command line in the terminal are updated.
|
||||||
|
* To debug, the easist is to interpose a tty-interceptor between the physical
|
||||||
|
* serial device and a logical one created by interceptty:
|
||||||
|
* sudo interceptty -s 'ispeed 115200 ospeed 115200' /dev/ttyUSB0 /dev/tmpS
|
||||||
|
* picocom -b 115200 /dev/tmpS
|
||||||
|
*/
|
||||||
|
void cmd_edit(void) __banked
|
||||||
|
{
|
||||||
|
while (l != sbuf_ptr) {
|
||||||
|
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
|
||||||
|
if (cmd_line_len >= CMD_BUF_SIZE)
|
||||||
|
continue;
|
||||||
|
write_char(sbuf[l]);
|
||||||
|
// Shift buffer to right
|
||||||
|
for (uint8_t i = cmd_line_len; i > cursor; i--)
|
||||||
|
cmd_buffer[i] = cmd_buffer[i-1];
|
||||||
|
// Insert char in comand buffer
|
||||||
|
cmd_buffer[cursor++] = sbuf[l];
|
||||||
|
cmd_line_len++;
|
||||||
|
// Print rest of line
|
||||||
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||||
|
write_char(cmd_buffer[i]);
|
||||||
|
// Move backwards
|
||||||
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||||
|
write_char('\010'); // BS works like cursor-left
|
||||||
|
} else if (sbuf[l] == '\033') { // ESC-Sequence
|
||||||
|
// 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)
|
||||||
|
continue;
|
||||||
|
if (((sbuf_ptr > l ? sbuf_ptr - l : SBUF_SIZE + sbuf_ptr - l) >= 4)
|
||||||
|
&& sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == '3' && sbuf[(l + 3) & SBUF_MASK] == '~') { // DEL
|
||||||
|
if (cursor < cmd_line_len) {
|
||||||
|
write_char('\033'); write_char('['); write_char('1'); write_char('P'); // Delete to end of line
|
||||||
|
cmd_line_len--;
|
||||||
|
for (uint8_t i = cursor; i < cmd_line_len; i++) {
|
||||||
|
cmd_buffer[i] = cmd_buffer[i+1];
|
||||||
|
write_char(cmd_buffer[i]);
|
||||||
|
}
|
||||||
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||||
|
write_char('\010');
|
||||||
|
}
|
||||||
|
l += 4;
|
||||||
|
l &= SBUF_MASK;
|
||||||
|
continue;
|
||||||
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'D') { // <CURSOR-LEFT>
|
||||||
|
if (cursor) {
|
||||||
|
write_char('\010'); // BS works like cursor-left
|
||||||
|
cursor--;
|
||||||
|
}
|
||||||
|
l += 3;
|
||||||
|
l &= SBUF_MASK;
|
||||||
|
continue;
|
||||||
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'C') { // <CURSOR-RIGHT>
|
||||||
|
if (cursor < cmd_line_len) {
|
||||||
|
write_char('\033'); write_char('['); write_char('C');
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
l += 3;
|
||||||
|
l &= SBUF_MASK;
|
||||||
|
continue;
|
||||||
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'A') { // <CURSOR-UP>
|
||||||
|
for (uint8_t i = 0; i < cmd_line_len; i++)
|
||||||
|
current_cmdline[i] = cmd_buffer[i];
|
||||||
|
current_cmdline[cmd_line_len] = 0;
|
||||||
|
__xdata uint16_t p;
|
||||||
|
if (history_editptr == 0xffff)
|
||||||
|
p = (cmd_history_ptr - 2) & CMD_HISTORY_MASK;
|
||||||
|
else
|
||||||
|
p = history_editptr;
|
||||||
|
// Move cursor to beginning of line
|
||||||
|
write_char('\033'); write_char('['); itoa(cursor + 2); write_char('D');
|
||||||
|
cursor = 0;
|
||||||
|
while (cmd_history[p] && cmd_history[p] != '\n') {
|
||||||
|
cursor++;
|
||||||
|
p--;
|
||||||
|
p &= CMD_HISTORY_MASK;
|
||||||
|
}
|
||||||
|
history_editptr = (p - 1) & CMD_HISTORY_MASK;
|
||||||
|
p = (p + 1) & CMD_HISTORY_MASK;
|
||||||
|
if (cursor) {
|
||||||
|
print_string("\033[2K> "); // Clear entire line: ^[[2K and print new prompt
|
||||||
|
for (uint8_t i = 0; i < cursor; i++) {
|
||||||
|
cmd_buffer[i] = cmd_history[p];
|
||||||
|
write_char(cmd_buffer[i]);
|
||||||
|
p = (p+1) & CMD_HISTORY_MASK;
|
||||||
|
}
|
||||||
|
cmd_line_len = cursor;
|
||||||
|
} else {
|
||||||
|
print_string("\033[2C"); // Move 2 right to start of editing space
|
||||||
|
}
|
||||||
|
l += 3;
|
||||||
|
l &= SBUF_MASK;
|
||||||
|
continue;
|
||||||
|
} else if (sbuf[l] == '\033' && sbuf[(l + 1) & SBUF_MASK] == '[' && sbuf[(l + 2) & SBUF_MASK] == 'B') { // <CURSOR-DOWN>
|
||||||
|
if (history_editptr != 0xffff) {
|
||||||
|
__xdata uint16_t p = (history_editptr + 2) & CMD_HISTORY_MASK;
|
||||||
|
// Move cursor to beginning of line
|
||||||
|
write_char('\033'); write_char('['); itoa(cursor + 2); write_char('D');
|
||||||
|
print_string("\033[2K> "); // Clear entire line: ^[[2K and print new prompt
|
||||||
|
uint8_t i = 0;
|
||||||
|
while (cmd_history[p] && cmd_history[p] != '\n') {
|
||||||
|
p = (p + 1) & CMD_HISTORY_MASK;
|
||||||
|
}
|
||||||
|
p = (p + 1) & CMD_HISTORY_MASK;
|
||||||
|
while (cmd_history[p] && cmd_history[p] != '\n') {
|
||||||
|
cmd_buffer[i] = cmd_history[p];
|
||||||
|
write_char(cmd_buffer[i++]);
|
||||||
|
p = (p + 1) & CMD_HISTORY_MASK;
|
||||||
|
}
|
||||||
|
history_editptr = (p - 1) & CMD_HISTORY_MASK;
|
||||||
|
if (!i) {
|
||||||
|
if (current_cmdline[i]) {
|
||||||
|
while (current_cmdline[i]) {
|
||||||
|
cmd_buffer[i] = current_cmdline[i];
|
||||||
|
write_char(cmd_buffer[i++]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write_char('\033'); write_char('['); write_char('C');
|
||||||
|
}
|
||||||
|
history_editptr = 0xffff;
|
||||||
|
// Move cursor right
|
||||||
|
}
|
||||||
|
cmd_line_len = i;
|
||||||
|
cursor = 0;
|
||||||
|
// Move cursor again to beginning of line
|
||||||
|
write_char('\033'); write_char('['); itoa(i); write_char('D');
|
||||||
|
} else {
|
||||||
|
// If we are at the last entry of the history, just move the cursor to the end of the line
|
||||||
|
if (cursor < cmd_line_len) {
|
||||||
|
write_char('\033'); write_char('['); itoa(cmd_line_len - cursor); write_char('C');
|
||||||
|
}
|
||||||
|
cursor = cmd_line_len;
|
||||||
|
}
|
||||||
|
l += 3;
|
||||||
|
l &= SBUF_MASK;
|
||||||
|
continue;
|
||||||
|
} else { // An unknown or not yet complete Escape sequence: wait
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (sbuf[l] == 127 || sbuf[l] == 8) { // Backspace DEL or BS/^H
|
||||||
|
if (cursor > 0) {
|
||||||
|
write_char('\010');
|
||||||
|
for (uint8_t i = cursor; i < cmd_line_len; i++)
|
||||||
|
write_char(cmd_buffer[i]);
|
||||||
|
write_char(' '); // Overwrite end of line
|
||||||
|
// Move backwards n steps:
|
||||||
|
for (uint8_t i = cursor; i <= cmd_line_len; i++)
|
||||||
|
write_char('\010');
|
||||||
|
cursor--;
|
||||||
|
for (uint8_t i = cursor; i <= cmd_line_len; i++)
|
||||||
|
cmd_buffer[i] = cmd_buffer[i+1];
|
||||||
|
cmd_line_len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the command buffer is currently in use, we cannot copy to it
|
||||||
|
if (cmd_available)
|
||||||
|
break;
|
||||||
|
// Check whether return was pressed:
|
||||||
|
if (sbuf[l] == '\n' || sbuf[l] == '\r') {
|
||||||
|
write_char('\n');
|
||||||
|
cmd_buffer[cmd_line_len] = '\0';
|
||||||
|
// write_char('>'); print_string_x(cmd_buffer); write_char('<');
|
||||||
|
// If there is a command we print the prompt after execution
|
||||||
|
// otherwise immediately because there is nothing to execute
|
||||||
|
if (cmd_line_len)
|
||||||
|
cmd_available = 1;
|
||||||
|
else
|
||||||
|
print_string("\n> ");
|
||||||
|
cursor = 0;
|
||||||
|
cmd_line_len = 0;
|
||||||
|
history_editptr = 0xffff;
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
l &= SBUF_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _CMD_EDITOR_H_
|
||||||
|
#define _CMD_EDITOR_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void cmd_editor_init(void) __banked;
|
||||||
|
void cmd_edit(void) __banked;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
#include "rtl837x_common.h"
|
#include "rtl837x_common.h"
|
||||||
|
|
||||||
extern __xdata uint8_t cmd_buffer[SBUF_SIZE];
|
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||||
extern __xdata uint8_t cmd_available;
|
extern __xdata uint8_t cmd_available;
|
||||||
|
|
||||||
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 print_sw_version(void) __banked;
|
||||||
|
void clear_command_history(void) __banked;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,44 +1,4 @@
|
|||||||
.globl __start__stack
|
|
||||||
;--------------------------------------------------------
|
|
||||||
; Stack segment in internal ram
|
|
||||||
;--------------------------------------------------------
|
|
||||||
.area SSEG (DATA)
|
|
||||||
__start__stack:
|
|
||||||
.ds 1
|
|
||||||
|
|
||||||
.area VECTOR (CODE)
|
|
||||||
.globl __interrupt_vect
|
|
||||||
__interrupt_vect:
|
|
||||||
ljmp __sdcc_gsinit_startup
|
|
||||||
ljmp _isr_ext0 ; 0x03
|
|
||||||
.ds 5
|
|
||||||
ljmp _isr_timer0 ; 0x0b
|
|
||||||
.ds 5
|
|
||||||
ljmp _isr_ext1 ; 0x13
|
|
||||||
.ds 5
|
|
||||||
reti
|
|
||||||
.ds 7
|
|
||||||
ljmp _isr_serial ; 0x23
|
|
||||||
.ds 5
|
|
||||||
reti ; 0x2b TIMER 2 IRQ
|
|
||||||
.ds 7
|
|
||||||
reti ; 0x33 NOT used by DW8051
|
|
||||||
.ds 7
|
|
||||||
reti ; 0x3b Serial port 1 RX/TX IRQ
|
|
||||||
.ds 7
|
|
||||||
ljmp _isr_ext2 ; 0x43
|
|
||||||
.ds 5
|
|
||||||
ljmp _isr_ext3 ; 0x4b
|
|
||||||
|
|
||||||
.globl __start__stack
|
|
||||||
|
|
||||||
.area GSINIT0 (CODE)
|
|
||||||
|
|
||||||
__sdcc_gsinit_startup::
|
|
||||||
mov sp,#__start__stack - 1
|
|
||||||
|
|
||||||
.area GSFINAL (CODE)
|
.area GSFINAL (CODE)
|
||||||
ljmp _bootloader
|
|
||||||
|
|
||||||
__sdcc_banked_call::
|
__sdcc_banked_call::
|
||||||
push _PSBANK
|
push _PSBANK
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef _CHACHA_H_
|
||||||
|
#define _CHACHA_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct chacha20_t {
|
||||||
|
uint8_t wstate[64]; // 64 bytes written here
|
||||||
|
uint8_t constant[16]; // 128 bit constant
|
||||||
|
uint8_t key[32]; // 256-bit secret key
|
||||||
|
uint32_t cnt; // 32-bit block counter 1, 2.. Big Endian!
|
||||||
|
uint8_t nonce[12]; // 96-bit nonce
|
||||||
|
__xdata uint8_t *plaintext;
|
||||||
|
uint16_t length;
|
||||||
|
__xdata uint8_t *cyphertext;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Encrypt a plaintext with ChaCha20 as per RFC7539
|
||||||
|
void chacha20_encrypt(void);
|
||||||
|
|
||||||
|
// Test ChaCha20 using the example from RFC7539
|
||||||
|
void chacha20_test(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "chacha.h"
|
||||||
|
|
||||||
|
void chacha_20(void);
|
||||||
|
void chacha_update(void);
|
||||||
|
void chacha_count(void);
|
||||||
|
|
||||||
|
// generate a block of ChaCha20 keystream as per RFC7539
|
||||||
|
|
||||||
|
|
||||||
|
__xdata struct chacha20_t __at(0x7000) chacha20;
|
||||||
|
__xdata uint8_t plaintext[256];
|
||||||
|
__xdata uint8_t cyphertext[256];
|
||||||
|
|
||||||
|
void chacha20_print_block(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i=0; i < 64; i++) {
|
||||||
|
print_byte(*(uint8_t * __xdata)(chacha20.wstate + i));
|
||||||
|
if (i%4 == 3)
|
||||||
|
write_char(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void chacha20_encrypt(void)
|
||||||
|
{
|
||||||
|
__xdata uint8_t *p = chacha20.plaintext;
|
||||||
|
|
||||||
|
while (chacha20.length) {
|
||||||
|
register uint8_t i;
|
||||||
|
chacha_count();
|
||||||
|
memcpy(chacha20.wstate, chacha20.wstate + 64, 64);
|
||||||
|
#ifdef DEBUG
|
||||||
|
chacha20_print_block(); write_char('\n');
|
||||||
|
#endif
|
||||||
|
chacha_20();
|
||||||
|
chacha_update();
|
||||||
|
#ifdef DEBUG
|
||||||
|
chacha20_print_block(); write_char('\n');
|
||||||
|
#endif
|
||||||
|
for (i = 0; i < ((chacha20.length > 64) ? 64 : chacha20.length); i++)
|
||||||
|
*chacha20.cyphertext++ = *p++ ^ chacha20.wstate[i];
|
||||||
|
chacha20.length -= chacha20.length > 64 ? 64 : chacha20.length;
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_string("\n round done\n");
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Test the example of RFC 7539 Section 2.4.2
|
||||||
|
void chacha20_test(void)
|
||||||
|
{
|
||||||
|
__code uint8_t chacha_c[16] =
|
||||||
|
{ 0x61, 0x70, 0x78, 0x65, 0x33, 0x20, 0x64, 0x6e,
|
||||||
|
0x79, 0x62, 0x2d, 0x32, 0x6b, 0x20, 0x65, 0x74 };
|
||||||
|
|
||||||
|
__code uint8_t key[32] =
|
||||||
|
{ 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
|
||||||
|
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
|
||||||
|
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
|
||||||
|
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c };
|
||||||
|
|
||||||
|
__code uint8_t nonce[12] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
__code uint8_t sunscreen[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for " \
|
||||||
|
"the future, sunscreen would be it.";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ciphertext Sunscreen (from RFC 7539 Section 2.4.2):
|
||||||
|
000 6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81 n.5.%h..A..(..i.
|
||||||
|
016 e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b .~z..C`..'......
|
||||||
|
032 f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57 ..e.RG3..Y=..b.W
|
||||||
|
048 16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8 .9.$.QR..S.5..a.
|
||||||
|
064 07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e ....P.jaV....".^
|
||||||
|
080 52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36 R.QM.........y76
|
||||||
|
096 5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42 Z...t.[......x^B
|
||||||
|
112 87 4d
|
||||||
|
*/
|
||||||
|
strcpy(plaintext, sunscreen);
|
||||||
|
memcpyc(chacha20.constant, chacha_c, 16);
|
||||||
|
memcpyc(chacha20.key, key, 32);
|
||||||
|
chacha20.cnt = 0;
|
||||||
|
memcpyc(chacha20.nonce, nonce, 12);
|
||||||
|
chacha20.plaintext = plaintext;
|
||||||
|
chacha20.length = strlen_x(plaintext);
|
||||||
|
chacha20.cyphertext = cyphertext;
|
||||||
|
|
||||||
|
print_string("Encrypting...\n");
|
||||||
|
chacha20_encrypt();
|
||||||
|
print_string("Cypertext:\n");
|
||||||
|
uint16_t len = strlen_x(plaintext);
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
print_byte(cyphertext[i]); write_char(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,489 @@
|
|||||||
|
; ChaCha Quater-Round implementation in Assembler
|
||||||
|
.module chacha_8051
|
||||||
|
; Global variables:
|
||||||
|
.globl _chacha_20
|
||||||
|
.globl _chacha_test_1
|
||||||
|
.globl _chacha_qr_r
|
||||||
|
.globl _chacha_update
|
||||||
|
.globl _chacha_count
|
||||||
|
|
||||||
|
;#define CHACHA_QR(A, B, C, D) { \
|
||||||
|
; A += B; D ^= A; D = ROTL32(D, 16); \
|
||||||
|
; C += D; B ^= C; B = ROTL32(B, 12); \
|
||||||
|
; A += B; D ^= A; D = ROTL32(D, 8); \
|
||||||
|
; C += D; B ^= C; B = ROTL32(B, 7); \
|
||||||
|
;}
|
||||||
|
|
||||||
|
; r0 r1 r2 r3
|
||||||
|
; CHACHA_QR( v[ 0], v[ 4], v[ 8], v[12] );
|
||||||
|
|
||||||
|
.area HOME (CODE)
|
||||||
|
|
||||||
|
store_32:
|
||||||
|
ar7 = 0x07
|
||||||
|
ar6 = 0x06
|
||||||
|
ar5 = 0x05
|
||||||
|
ar4 = 0x04
|
||||||
|
ar3 = 0x03
|
||||||
|
ar2 = 0x02
|
||||||
|
ar1 = 0x01
|
||||||
|
ar0 = 0x00
|
||||||
|
|
||||||
|
mov a, r7
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r6
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r5
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r4
|
||||||
|
movx @dptr, a
|
||||||
|
ret
|
||||||
|
|
||||||
|
rol_b:
|
||||||
|
clr c
|
||||||
|
mov a, r7
|
||||||
|
rlc a
|
||||||
|
mov r7, a
|
||||||
|
mov a, r6
|
||||||
|
rlc a
|
||||||
|
mov r6, a
|
||||||
|
mov a, r5
|
||||||
|
rlc a
|
||||||
|
mov r5, a
|
||||||
|
mov a, r4
|
||||||
|
rlc a
|
||||||
|
mov r4, a
|
||||||
|
clr a
|
||||||
|
addc a, r7
|
||||||
|
mov r7, a
|
||||||
|
djnz dpl, rol_b
|
||||||
|
ret
|
||||||
|
|
||||||
|
print_regs:
|
||||||
|
push a
|
||||||
|
push ar6
|
||||||
|
push ar7
|
||||||
|
push dpl
|
||||||
|
mov dpl, a
|
||||||
|
lcall _print_byte
|
||||||
|
|
||||||
|
pop dpl
|
||||||
|
pop ar7
|
||||||
|
pop ar6
|
||||||
|
pop a
|
||||||
|
|
||||||
|
|
||||||
|
chacha_plus_xor:
|
||||||
|
; Load A into registers r4-r7, A pointed to by r0
|
||||||
|
mov dptr, #_chacha20
|
||||||
|
mov dpl, r0
|
||||||
|
movx a, @dptr
|
||||||
|
mov r7, a
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
mov r6, a
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
mov r5, a
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
mov r4, a
|
||||||
|
|
||||||
|
; A += B, B pointed to by r1
|
||||||
|
mov dpl, r1
|
||||||
|
movx a, @dptr
|
||||||
|
add a, r7
|
||||||
|
mov r7, a
|
||||||
|
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
addc a, r6
|
||||||
|
mov r6, a
|
||||||
|
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
addc a, r5
|
||||||
|
mov r5, a
|
||||||
|
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
addc a, r4
|
||||||
|
mov r4, a
|
||||||
|
|
||||||
|
mov dpl, r0 ; Store A back
|
||||||
|
mov a, r7
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r6
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r5
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r4
|
||||||
|
movx @dptr, a
|
||||||
|
|
||||||
|
; D ^= A
|
||||||
|
mov dpl, r3
|
||||||
|
movx a, @dptr
|
||||||
|
xrl a, r7
|
||||||
|
mov r7, a
|
||||||
|
dec dpl
|
||||||
|
|
||||||
|
movx a, @dptr
|
||||||
|
xrl a, r6
|
||||||
|
mov r6, a
|
||||||
|
dec dpl
|
||||||
|
|
||||||
|
movx a, @dptr
|
||||||
|
xrl a, r5
|
||||||
|
mov r5, a
|
||||||
|
dec dpl
|
||||||
|
|
||||||
|
movx a, @dptr
|
||||||
|
xrl a, r4
|
||||||
|
mov r4, a
|
||||||
|
dec dpl
|
||||||
|
ret
|
||||||
|
|
||||||
|
chacha_qr:
|
||||||
|
; QR Part: A += B; D ^= A; D = ROTL32(D, 16);
|
||||||
|
acall chacha_plus_xor
|
||||||
|
|
||||||
|
; rotate left 16. D is r4, r5, r6, r7 -> r6, r7, r4, r5
|
||||||
|
mov a, r6
|
||||||
|
xch a, r4
|
||||||
|
mov r6, a
|
||||||
|
mov a, r7
|
||||||
|
xch a, r5
|
||||||
|
mov r7, a
|
||||||
|
mov dpl, r3 ; Store D
|
||||||
|
acall store_32
|
||||||
|
|
||||||
|
;QR Part: C += D; B ^= C; B = ROTL32(B, 12);
|
||||||
|
; Swap A <-> C and D <-> B
|
||||||
|
mov a, r0
|
||||||
|
xch a, r2
|
||||||
|
mov r0, a
|
||||||
|
mov a, r1
|
||||||
|
xch a, r3
|
||||||
|
mov r1, a
|
||||||
|
acall chacha_plus_xor
|
||||||
|
|
||||||
|
; rotate left 12. D is r4, r5, r6, r7 -> r5, r6, r7, r4
|
||||||
|
mov a, r4
|
||||||
|
xch a, r7
|
||||||
|
xch a, r6
|
||||||
|
xch a, r5
|
||||||
|
mov r4, a
|
||||||
|
|
||||||
|
mov dpl, #4
|
||||||
|
acall rol_b
|
||||||
|
mov dpl, r3 ; Store D (being B)
|
||||||
|
acall store_32
|
||||||
|
|
||||||
|
; Swap A <-> C and D <-> B
|
||||||
|
mov a, r0
|
||||||
|
xch a, r2
|
||||||
|
mov r0, a
|
||||||
|
mov a, r1
|
||||||
|
xch a, r3
|
||||||
|
mov r1, a
|
||||||
|
|
||||||
|
mov dpl, r1 ; Store B
|
||||||
|
acall store_32
|
||||||
|
|
||||||
|
; QR Part A += B; D ^= A; D = ROTL32(D, 8);
|
||||||
|
acall chacha_plus_xor
|
||||||
|
mov a, r4
|
||||||
|
xch a, r7
|
||||||
|
xch a, r6
|
||||||
|
xch a, r5
|
||||||
|
mov r4, a
|
||||||
|
mov dpl, r3 ; Store D
|
||||||
|
acall store_32
|
||||||
|
|
||||||
|
; QR Part
|
||||||
|
; C += D; B ^= C; B = ROTL32(B, 7);
|
||||||
|
line4:
|
||||||
|
; Swap A <-> C and D <-> B
|
||||||
|
mov a, r0
|
||||||
|
xch a, r2
|
||||||
|
mov r0, a
|
||||||
|
mov a, r1
|
||||||
|
xch a, r3
|
||||||
|
mov r1, a
|
||||||
|
acall chacha_plus_xor
|
||||||
|
|
||||||
|
; Roll left 7 bits, start by rolling 8 bits left, then roll 1 to the right
|
||||||
|
mov a, r4
|
||||||
|
xch a, r7
|
||||||
|
xch a, r6
|
||||||
|
xch a, r5
|
||||||
|
mov r4, a
|
||||||
|
|
||||||
|
clr c
|
||||||
|
mov a, r4
|
||||||
|
rrc a
|
||||||
|
mov r4, a
|
||||||
|
mov a, r5
|
||||||
|
rrc a
|
||||||
|
mov r5, a
|
||||||
|
mov a, r6
|
||||||
|
rrc a
|
||||||
|
mov r6, a
|
||||||
|
mov a, r7
|
||||||
|
rrc a
|
||||||
|
mov r7, a
|
||||||
|
clr a
|
||||||
|
rrc a
|
||||||
|
add a, r4
|
||||||
|
mov r4, a
|
||||||
|
|
||||||
|
; Swap A <-> C and D <-> B
|
||||||
|
mov a, r0
|
||||||
|
xch a, r2
|
||||||
|
mov r0, a
|
||||||
|
mov a, r1
|
||||||
|
xch a, r3
|
||||||
|
mov r1, a
|
||||||
|
mov dpl, r1 ; Store B
|
||||||
|
acall store_32
|
||||||
|
ret
|
||||||
|
|
||||||
|
_chacha_test_1:
|
||||||
|
mov r0, #3
|
||||||
|
mov r1, #7
|
||||||
|
mov r2, #11
|
||||||
|
mov r3, #15
|
||||||
|
acall line4
|
||||||
|
ret
|
||||||
|
|
||||||
|
; QUARTERROUND(2,7,8,13)
|
||||||
|
_chacha_qr_r:
|
||||||
|
mov r0, #11
|
||||||
|
mov r1, #31
|
||||||
|
mov r2, #35
|
||||||
|
mov r3, #55
|
||||||
|
acall chacha_qr
|
||||||
|
ret
|
||||||
|
|
||||||
|
;
|
||||||
|
; Implementation of 20 ChaCha Rounds (10 Double Rounds)
|
||||||
|
;
|
||||||
|
_chacha_20:
|
||||||
|
push acc
|
||||||
|
push b
|
||||||
|
push dpl
|
||||||
|
push dph
|
||||||
|
push ar7
|
||||||
|
push ar6
|
||||||
|
push ar5
|
||||||
|
push ar4
|
||||||
|
push ar3
|
||||||
|
push ar2
|
||||||
|
push ar1
|
||||||
|
push ar0
|
||||||
|
push psw
|
||||||
|
|
||||||
|
mov b, #10 ; 10 Double rounds
|
||||||
|
chacha_20_loop:
|
||||||
|
; CHACHA_QR( v[ 0], v[ 4], v[ 8], v[12] );
|
||||||
|
mov r0, #3
|
||||||
|
mov r1, #19
|
||||||
|
mov r2, #35
|
||||||
|
mov r3, #51
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 1], v[ 5], v[ 9], v[13] ); 7 23 39 55
|
||||||
|
mov r0, #7
|
||||||
|
mov r1, #23
|
||||||
|
mov r2, #39
|
||||||
|
mov r3, #55
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 2], v[ 6], v[10], v[14] ); 11 27 43 59
|
||||||
|
mov r0, #11
|
||||||
|
mov r1, #27
|
||||||
|
mov r2, #43
|
||||||
|
mov r3, #59
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 3], v[ 7], v[11], v[15] ); 15 31 47 63
|
||||||
|
mov r0, #15
|
||||||
|
mov r1, #31
|
||||||
|
mov r2, #47
|
||||||
|
mov r3, #63
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 0], v[ 5], v[10], v[15] ); 3 23 43 63
|
||||||
|
mov r0, #3
|
||||||
|
mov r1, #23
|
||||||
|
mov r2, #43
|
||||||
|
mov r3, #63
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 1], v[ 6], v[11], v[12] ); 7 27 47 51
|
||||||
|
mov r0, #7
|
||||||
|
mov r1, #27
|
||||||
|
mov r2, #47
|
||||||
|
mov r3, #51
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 2], v[ 7], v[ 8], v[13] ); 11 31 35 55
|
||||||
|
mov r0, #11
|
||||||
|
mov r1, #31
|
||||||
|
mov r2, #35
|
||||||
|
mov r3, #55
|
||||||
|
acall chacha_qr
|
||||||
|
|
||||||
|
; CHACHA_QR( v[ 3], v[ 4], v[ 9], v[14] ); 15 19 39 59
|
||||||
|
mov r0, #15
|
||||||
|
mov r1, #19
|
||||||
|
mov r2, #39
|
||||||
|
mov r3, #59
|
||||||
|
acall chacha_qr
|
||||||
|
djnz b, chacha_20_loop
|
||||||
|
|
||||||
|
pop psw
|
||||||
|
pop ar0
|
||||||
|
pop ar1
|
||||||
|
pop ar2
|
||||||
|
pop ar3
|
||||||
|
pop ar4
|
||||||
|
pop ar5
|
||||||
|
pop ar6
|
||||||
|
pop ar7
|
||||||
|
pop dph
|
||||||
|
pop dpl
|
||||||
|
pop b
|
||||||
|
pop acc
|
||||||
|
ret
|
||||||
|
|
||||||
|
;
|
||||||
|
; Update ChaCHa state
|
||||||
|
;
|
||||||
|
_chacha_update:
|
||||||
|
push acc
|
||||||
|
push b
|
||||||
|
push dpl
|
||||||
|
push dph
|
||||||
|
push ar4
|
||||||
|
push ar3
|
||||||
|
push ar2
|
||||||
|
push ar1
|
||||||
|
push ar0
|
||||||
|
push psw
|
||||||
|
|
||||||
|
mov dptr, #_chacha20
|
||||||
|
mov b, #16 ; 16 uint32
|
||||||
|
update_loop:
|
||||||
|
mov a, b ; multiply by 4 and subtract 1
|
||||||
|
rl a
|
||||||
|
rl a
|
||||||
|
dec a
|
||||||
|
; Load Working State variable into registers r0-r3
|
||||||
|
mov dpl, a
|
||||||
|
|
||||||
|
orl a, #64 ; Save pointer to state
|
||||||
|
mov r4, a
|
||||||
|
|
||||||
|
movx a, @dptr
|
||||||
|
mov r3, a
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
mov r2, a
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
mov r1, a
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
mov r0, a
|
||||||
|
|
||||||
|
; Add to State variable
|
||||||
|
mov a, r4
|
||||||
|
mov dpl, a
|
||||||
|
movx a, @dptr
|
||||||
|
add a, r3
|
||||||
|
mov r3, a
|
||||||
|
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
addc a, r2
|
||||||
|
mov r2, a
|
||||||
|
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
addc a, r1
|
||||||
|
mov r1, a
|
||||||
|
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
addc a, r0
|
||||||
|
mov r0, a
|
||||||
|
|
||||||
|
; Store back state variable in LSB, first sequence (serialized)
|
||||||
|
mov a, r4
|
||||||
|
xrl a, #64 ; Save pointer to working state
|
||||||
|
mov dpl, a
|
||||||
|
mov a, r0
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r1
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r2
|
||||||
|
movx @dptr, a
|
||||||
|
dec dpl
|
||||||
|
mov a, r3
|
||||||
|
movx @dptr, a
|
||||||
|
|
||||||
|
djnz b, update_loop
|
||||||
|
|
||||||
|
pop psw
|
||||||
|
pop ar0
|
||||||
|
pop ar1
|
||||||
|
pop ar2
|
||||||
|
pop ar3
|
||||||
|
pop ar4
|
||||||
|
pop dph
|
||||||
|
pop dpl
|
||||||
|
pop b
|
||||||
|
pop acc
|
||||||
|
ret
|
||||||
|
|
||||||
|
;
|
||||||
|
; Increase counter in state
|
||||||
|
;
|
||||||
|
_chacha_count:
|
||||||
|
push acc
|
||||||
|
push dpl
|
||||||
|
push dph
|
||||||
|
mov dptr, #_chacha20
|
||||||
|
mov dpl, #112 + 3
|
||||||
|
movx a, @dptr
|
||||||
|
inc a
|
||||||
|
movx @dptr, a
|
||||||
|
jnc chacha_count_done
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
inc a
|
||||||
|
movx @dptr, a
|
||||||
|
jnc chacha_count_done
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
inc a
|
||||||
|
movx @dptr, a
|
||||||
|
jnc chacha_count_done
|
||||||
|
dec dpl
|
||||||
|
movx a, @dptr
|
||||||
|
inc a
|
||||||
|
movx @dptr, a
|
||||||
|
chacha_count_done:
|
||||||
|
pop dph
|
||||||
|
pop dpl
|
||||||
|
pop acc
|
||||||
|
ret
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __DEBUG_H__
|
||||||
|
#define __DEBUG_H__
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define dbg_string(s) print_string(s)
|
||||||
|
#define dbg_string_x(s) print_string_x(s)
|
||||||
|
#define dbg_byte(s) print_byte(s)
|
||||||
|
#define dbg_short(s) print_short(s)
|
||||||
|
#define dbg_char(s) write_char(s)
|
||||||
|
#else
|
||||||
|
#define dbg_string(s)
|
||||||
|
#define dbg_string_x(s)
|
||||||
|
#define dbg_byte(s)
|
||||||
|
#define dbg_short(s)
|
||||||
|
#define dbg_char(s)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,385 @@
|
|||||||
|
/*
|
||||||
|
* This is a DHCP client implementation for the RTL837x-based switches
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #define REGDBG
|
||||||
|
// #define DEBUG
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "rtl837x_sfr.h"
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "dhcp.h"
|
||||||
|
#include "uip.h"
|
||||||
|
#include "uip/uip.h"
|
||||||
|
|
||||||
|
__xdata struct dhcp_state dhcp_state;
|
||||||
|
__xdata uip_ipaddr_t server;
|
||||||
|
|
||||||
|
#define DHCP_HW_TYPE_ETH 1
|
||||||
|
|
||||||
|
#define DHCP_SUBNET_MASK 1
|
||||||
|
#define DHCP_SUBNET_MASK_LEN 4
|
||||||
|
#define DHCP_ROUTER 3
|
||||||
|
#define DHCP_ROUTER_LEN 4
|
||||||
|
#define DHCP_DNS 6
|
||||||
|
#define DHCP_DNS_LEN 4
|
||||||
|
#define DHCP_BROADCAST 28
|
||||||
|
#define DHCP_BROADCAST_LEN 4
|
||||||
|
#define DHCP_SERVER_ID 54
|
||||||
|
#define DHCP_SERVER_ID_LEN 4
|
||||||
|
#define DHCP_MESSAGE_TYPE 53
|
||||||
|
#define DHCP_MESSAGE_TYPE_LEN 1
|
||||||
|
#define DHCP_MESSAGE_DISCOVER 1
|
||||||
|
#define DHCP_MESSAGE_OFFER 2
|
||||||
|
#define DHCP_MESSAGE_REQUEST 3
|
||||||
|
#define DHCP_MESSAGE_ACK 5
|
||||||
|
#define DHCP_LEASE 51
|
||||||
|
#define DHCP_LEASE_LEN 4
|
||||||
|
#define DHCP_RENEWAL 58
|
||||||
|
#define DHCP_RENEWAL_LEN 4
|
||||||
|
#define DHCP_REBIND 59
|
||||||
|
#define DHCP_REBIND_LEN 4
|
||||||
|
#define DHCP_CLIENT_ID 61
|
||||||
|
#define DHCP_CLIENT_ID_LEN 7
|
||||||
|
#define DHCP_REQUEST_IP 50
|
||||||
|
#define DHCP_REQUEST_IP_LEN 4
|
||||||
|
#define DHCP_PARAMS 55
|
||||||
|
#define DHCP_PARAM_SUBNET 1
|
||||||
|
#define DHCP_PARAM_ROUTER 3
|
||||||
|
#define DHCP_PARAM_DNS 6
|
||||||
|
#define DHCP_END 255
|
||||||
|
|
||||||
|
#pragma codeseg BANK2
|
||||||
|
#pragma constseg BANK2
|
||||||
|
|
||||||
|
struct dhcp_pkt {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t hw;
|
||||||
|
uint8_t hw_len;
|
||||||
|
uint8_t hops;
|
||||||
|
uint32_t tid;
|
||||||
|
uint16_t delay;
|
||||||
|
uint16_t flags;
|
||||||
|
uint8_t client_ip[4];
|
||||||
|
uint8_t your_ip[4];
|
||||||
|
uint8_t next_server_ip[4];
|
||||||
|
uint8_t relay_ip[4];
|
||||||
|
uint8_t client_addr[6];
|
||||||
|
uint8_t client_pad[10];
|
||||||
|
uint8_t server_name[64];
|
||||||
|
uint8_t file[128];
|
||||||
|
uint8_t cookie[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DHCP_P ((__xdata struct dhcp_pkt *)uip_appdata)
|
||||||
|
#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt))
|
||||||
|
|
||||||
|
__xdata uint32_t long_value;
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_print_ip(__xdata uint8_t *a)
|
||||||
|
{
|
||||||
|
itoa(a[0]); write_char('.');
|
||||||
|
itoa(a[1]); write_char('.');
|
||||||
|
itoa(a[2]); write_char('.');
|
||||||
|
itoa(a[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_prepare_request(void)
|
||||||
|
{
|
||||||
|
DHCP_P->type = 1;
|
||||||
|
DHCP_P->hw = DHCP_HW_TYPE_ETH;
|
||||||
|
DHCP_P->hw_len = 6;
|
||||||
|
DHCP_P->hops = 0;
|
||||||
|
|
||||||
|
DHCP_P->tid = HTONS(dhcp_state.transaction_id);
|
||||||
|
DHCP_P->delay = HTONS(0);
|
||||||
|
DHCP_P->flags = 0;
|
||||||
|
// Clear fields client_ip to bootp_file
|
||||||
|
memset(DHCP_P->client_ip, 0, 224);
|
||||||
|
memcpy(DHCP_P->client_addr, uip_ethaddr.addr, 6);
|
||||||
|
DHCP_P->cookie[0] = 0x63;
|
||||||
|
DHCP_P->cookie[1] = 0x82;
|
||||||
|
DHCP_P->cookie[2] = 0x53;
|
||||||
|
DHCP_P->cookie[3] = 0x63;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_addopt_client_id(void)
|
||||||
|
{
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_CLIENT_ID;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_CLIENT_ID_LEN;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HW_TYPE_ETH;
|
||||||
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 6);
|
||||||
|
dhcp_state.opt_ptr += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_addopt_request_ip(void)
|
||||||
|
{
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP_LEN;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[0];
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1];
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
||||||
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_addopt_server_id(void)
|
||||||
|
{
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SERVER_ID;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SERVER_ID_LEN;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[0];
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1];
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
||||||
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_send_discover(void)
|
||||||
|
{
|
||||||
|
print_string("dhcp_send_discover called\n");
|
||||||
|
dhcp_prepare_request();
|
||||||
|
|
||||||
|
dhcp_state.opt_ptr = 0;
|
||||||
|
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++] = DHCP_MESSAGE_DISCOVER;
|
||||||
|
|
||||||
|
dhcp_addopt_client_id();
|
||||||
|
dhcp_addopt_request_ip();
|
||||||
|
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_SUBNET;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_ROUTER;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_DNS;
|
||||||
|
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_END;
|
||||||
|
// Padding to 300 bytes
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
|
||||||
|
uip_udp_send(sizeof(struct dhcp_pkt) + dhcp_state.opt_ptr);
|
||||||
|
dhcp_state.state = DHCP_DISCOVER_SENT;
|
||||||
|
dhcp_state.ticks = SYS_TICK_HZ;
|
||||||
|
dhcp_state.dhcp_timer = 30; // Timeout for discover
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_send_request(void)
|
||||||
|
{
|
||||||
|
print_string("dhcp_send_request called\n");
|
||||||
|
dhcp_prepare_request();
|
||||||
|
|
||||||
|
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++] = DHCP_MESSAGE_REQUEST;
|
||||||
|
|
||||||
|
dhcp_addopt_client_id();
|
||||||
|
dhcp_addopt_request_ip();
|
||||||
|
dhcp_addopt_server_id();
|
||||||
|
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_SUBNET;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_ROUTER;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_DNS;
|
||||||
|
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_END;
|
||||||
|
// Padding to 300 bytes
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
|
||||||
|
|
||||||
|
uip_udp_send(sizeof(struct dhcp_pkt) + dhcp_state.opt_ptr);
|
||||||
|
dhcp_state.state = DHCP_REQUEST_SENT;
|
||||||
|
dhcp_state.ticks = SYS_TICK_HZ;
|
||||||
|
dhcp_state.dhcp_timer = 30; // Timeout for request
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ip_opt(__xdata uint8_t * ip)
|
||||||
|
{
|
||||||
|
dhcp_state.opt_ptr++;
|
||||||
|
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
// There may be more than one IP option, such as 2 DNS servers advertised
|
||||||
|
dhcp_state.opt_ptr += len - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void long_opt(void)
|
||||||
|
{
|
||||||
|
dhcp_state.opt_ptr++;
|
||||||
|
dhcp_state.opt_ptr++;
|
||||||
|
long_value = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
long_value <<= 8;
|
||||||
|
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
long_value <<= 8;
|
||||||
|
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
long_value <<= 8;
|
||||||
|
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parse_opts(void)
|
||||||
|
{
|
||||||
|
while (DHCP_OPT[dhcp_state.opt_ptr] && DHCP_OPT[dhcp_state.opt_ptr] != DHCP_END) {
|
||||||
|
switch(DHCP_OPT[dhcp_state.opt_ptr]) {
|
||||||
|
case DHCP_SUBNET_MASK:
|
||||||
|
ip_opt(&dhcp_state.subnet[0]);
|
||||||
|
break;
|
||||||
|
case DHCP_ROUTER:
|
||||||
|
ip_opt(&dhcp_state.router[0]);
|
||||||
|
break;
|
||||||
|
case DHCP_DNS:
|
||||||
|
ip_opt(&dhcp_state.dns[0]);
|
||||||
|
break;
|
||||||
|
case DHCP_SERVER_ID:
|
||||||
|
ip_opt(&dhcp_state.server[0]);
|
||||||
|
break;
|
||||||
|
case DHCP_BROADCAST:
|
||||||
|
ip_opt(&dhcp_state.broadcast[0]);
|
||||||
|
break;
|
||||||
|
case DHCP_LEASE:
|
||||||
|
long_opt();
|
||||||
|
dhcp_state.lease = long_value;
|
||||||
|
break;
|
||||||
|
case DHCP_REBIND:
|
||||||
|
long_opt();
|
||||||
|
dhcp_state.rebind = long_value;
|
||||||
|
break;
|
||||||
|
case DHCP_RENEWAL:
|
||||||
|
long_opt();
|
||||||
|
dhcp_state.renewal = long_value;
|
||||||
|
break;
|
||||||
|
case DHCP_END:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_string("Unknown DHCP option: "); print_byte(DHCP_OPT[dhcp_state.opt_ptr]); write_char('\n');
|
||||||
|
dhcp_state.opt_ptr++;
|
||||||
|
dhcp_state.opt_ptr += DHCP_OPT[dhcp_state.opt_ptr];
|
||||||
|
dhcp_state.opt_ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parse_dhcp(void)
|
||||||
|
{
|
||||||
|
if (!DHCP_P->tid == HTONS(dhcp_state.transaction_id))
|
||||||
|
return;
|
||||||
|
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_OFFER) {
|
||||||
|
dhcp_state.opt_ptr++;
|
||||||
|
dhcp_state.current_ip[0] = DHCP_P->your_ip[0];
|
||||||
|
dhcp_state.current_ip[1] = DHCP_P->your_ip[1];
|
||||||
|
dhcp_state.current_ip[2] = DHCP_P->your_ip[2];
|
||||||
|
dhcp_state.current_ip[3] = DHCP_P->your_ip[3];
|
||||||
|
parse_opts();
|
||||||
|
print_string("DHCP offer received for IP "); dhcp_print_ip(dhcp_state.current_ip);
|
||||||
|
write_char('\n');
|
||||||
|
dhcp_send_request();
|
||||||
|
} else if (DHCP_OPT[dhcp_state.opt_ptr++] == DHCP_MESSAGE_ACK) {
|
||||||
|
parse_opts();
|
||||||
|
print_string("DHCP ACK, our IP is "); dhcp_print_ip(dhcp_state.current_ip);
|
||||||
|
write_char('\n');
|
||||||
|
print_string("DHCP netmask "); dhcp_print_ip(dhcp_state.subnet);
|
||||||
|
write_char('\n');
|
||||||
|
print_string("DHCP gateway "); dhcp_print_ip(dhcp_state.router);
|
||||||
|
write_char('\n');
|
||||||
|
print_string("DHCP lease-time ");
|
||||||
|
print_long(dhcp_state.lease);
|
||||||
|
write_char('\n');
|
||||||
|
uip_ipaddr(&uip_hostaddr, dhcp_state.current_ip[0], dhcp_state.current_ip[1], dhcp_state.current_ip[2], dhcp_state.current_ip[3]);
|
||||||
|
uip_ipaddr(&uip_draddr, dhcp_state.router[0], dhcp_state.router[1], dhcp_state.router[2], dhcp_state.router[3]);
|
||||||
|
uip_ipaddr(&uip_netmask, dhcp_state.subnet[0], dhcp_state.subnet[1], dhcp_state.subnet[2], dhcp_state.subnet[3]);
|
||||||
|
dhcp_state.state = DHCP_LEASING;
|
||||||
|
dhcp_state.ticks = SYS_TICK_HZ;
|
||||||
|
dhcp_state.dhcp_timer = dhcp_state.renewal > 0xffff ? 0xffff : dhcp_state.renewal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_start(void) __banked
|
||||||
|
{
|
||||||
|
uip_ipaddr(server, 255,255,255,255);
|
||||||
|
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;
|
||||||
|
if(dhcp_state.conn) {
|
||||||
|
uip_udp_bind(dhcp_state.conn, HTONS(DHCPC_CLIENT_PORT));
|
||||||
|
} else {
|
||||||
|
print_string("dhcp_start failed to set up socket\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
get_random_32();
|
||||||
|
dhcp_state.transaction_id = SFR_DATA_U32;
|
||||||
|
dhcp_state.state = DHCP_START;
|
||||||
|
print_string("dhcp_start done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_stop(void) __banked
|
||||||
|
{
|
||||||
|
print_string("dhcp_stop called\n");
|
||||||
|
uip_udp_remove(dhcp_state.conn);
|
||||||
|
dhcp_state.state = DHCP_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp_callback(void) __banked
|
||||||
|
{
|
||||||
|
if (!dhcp_state.state)
|
||||||
|
return;
|
||||||
|
if (uip_closed()) {
|
||||||
|
print_string("Closed\n");
|
||||||
|
return;
|
||||||
|
} else if (uip_newdata()) {
|
||||||
|
parse_dhcp();
|
||||||
|
} else {
|
||||||
|
if (dhcp_state.state == DHCP_START) {
|
||||||
|
dhcp_send_discover();
|
||||||
|
} else if (!--dhcp_state.ticks) {
|
||||||
|
// print_string("Timer: "); print_short(dhcp_state.ticks); write_char(' '); print_short(dhcp_state.dhcp_timer);
|
||||||
|
dhcp_state.dhcp_timer--;
|
||||||
|
dhcp_state.ticks = SYS_TICK_HZ;
|
||||||
|
}
|
||||||
|
if (!dhcp_state.dhcp_timer) {
|
||||||
|
switch (dhcp_state.state) {
|
||||||
|
case DHCP_DISCOVER_SENT:
|
||||||
|
dhcp_send_discover();
|
||||||
|
break;
|
||||||
|
case DHCP_LEASING:
|
||||||
|
case DHCP_REQUEST_SENT:
|
||||||
|
dhcp_send_request();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_string("UNKNOWN STATE\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default we do not send anything out
|
||||||
|
uip_len = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef _DHCP_H_
|
||||||
|
#define _DHCP_H_
|
||||||
|
|
||||||
|
#include "uipopt.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define DHCPC_SERVER_PORT 67
|
||||||
|
#define DHCPC_CLIENT_PORT 68
|
||||||
|
|
||||||
|
#define DHCP_OFF 0
|
||||||
|
#define DHCP_START 1
|
||||||
|
#define DHCP_DISCOVER_SENT 2
|
||||||
|
#define DHCP_REQUEST_SENT 3
|
||||||
|
#define DHCP_LEASING 4
|
||||||
|
|
||||||
|
void dhcp_start(void) __banked;
|
||||||
|
void dhcp_stop(void) __banked;
|
||||||
|
// void dhcp_periodic(void) __banked;
|
||||||
|
void dhcp_callback(void) __banked;
|
||||||
|
|
||||||
|
|
||||||
|
struct dhcp_state {
|
||||||
|
uint8_t state;
|
||||||
|
uint32_t transaction_id;
|
||||||
|
uint16_t dhcp_timer;
|
||||||
|
uint8_t ticks;
|
||||||
|
uint16_t opt_ptr;
|
||||||
|
uint8_t current_ip[4];
|
||||||
|
uint8_t server[4];
|
||||||
|
uint8_t router[4];
|
||||||
|
uint8_t subnet[4];
|
||||||
|
uint8_t dns[4];
|
||||||
|
uint8_t broadcast[4];
|
||||||
|
uint32_t lease;
|
||||||
|
uint32_t rebind;
|
||||||
|
uint32_t renewal;
|
||||||
|
|
||||||
|
__xdata struct uip_udp_conn *conn;
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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,238 @@
|
|||||||
|
# Egress and Ingress Bandwidth Control
|
||||||
|
The RTL8372/3 allows to control the bandwidth of data transmitted (egress) and/or
|
||||||
|
admitted (ingress) at any given port. Once admitted, packets are internally switched
|
||||||
|
at wire-speed, since the backplane of the devices has a bandwidth of 60GBit/s.
|
||||||
|
|
||||||
|
The devices schedules transmission of packets by assigning packets to 8 queues
|
||||||
|
implemented in hardware per port, which share a total of 8Mbit of memory internal
|
||||||
|
to the switching part of the SoCs. Packets are assigned to the respective queues
|
||||||
|
based on the priority assigned to a packet, which can be based on various
|
||||||
|
properties of a packet such as IEEE 802.1P priority, DSCP value, physical port
|
||||||
|
number, destination or source MAC, Ether-Type-based, CVID, SVID, IPv4 source or
|
||||||
|
destination IP, IPv4/IPv6 TOS field, IPv6 Flow Label and even TCP/UDP
|
||||||
|
source/destination port. Once in a queue, packets are scheduled for egress
|
||||||
|
based on differnent configurable algorithms.
|
||||||
|
|
||||||
|
RTLPlayground currently allows only to control the bandwidth at ingress at a port
|
||||||
|
or just before packets leave a port. There is no control of the priority assignment
|
||||||
|
or queue scheduling mechanisms. The bandwidth can be controlled in steps of 16Kbit/s
|
||||||
|
from 16Kbit/s to 10Gbp/s.
|
||||||
|
|
||||||
|
The bandwidth control as currently implemented allows e.g. to assign a certain
|
||||||
|
share of bandwidth to an attached device (e.g. to share an uplink), or simulate
|
||||||
|
connections with low bandwidth and even bad connectivity with packet drops when
|
||||||
|
ingress is not controlled by Flow Control but by simply droping packets.
|
||||||
|
|
||||||
|
## Ingress/Egress control
|
||||||
|
The relevant registers for controlling Ingress and Egress at a port are:
|
||||||
|
```
|
||||||
|
#define RTL837X_IGBW_CTRL 0x4c10
|
||||||
|
#define IGBW_INC_BYPASS_PKT 0x100
|
||||||
|
#define IGBW_INC_IFG 0x80
|
||||||
|
#define IGBW_ADM_DHCP 0x20
|
||||||
|
#define IGBW_ADM_ARPREQ 0x10
|
||||||
|
#define IGBW_ADM_RMA 0x08
|
||||||
|
#define IGBW_ADM_BPDU 0x04
|
||||||
|
#define IGBW_ADM_RTKPKT 0x02
|
||||||
|
#define IGBW_ADM_IGMP 0x01
|
||||||
|
#define RTL837X_IGBW_PORT_CTRL 0x4C18
|
||||||
|
#define RTL837X_IGBW_PORT_FC_CTRL 0x4C8C
|
||||||
|
#define RTL837X_EGBW_PORT_CTRL 0x1c34
|
||||||
|
#define RTL837X_EGBW_CTRL 0x447c
|
||||||
|
#define EGBW_INC_IFG 0x02
|
||||||
|
#define EGBW_CPUMODE 0x01
|
||||||
|
```
|
||||||
|
`RTL837X_IGBW_CTRL/RTL837X_EGBW_CTRL` control the behaviour of the bandwidth control
|
||||||
|
at ingress and egress. The flags such as `IGBW_ADM_DHCP`control whether certain types
|
||||||
|
of packets such as DHCP are exempt from being ingress controlled. The
|
||||||
|
`IGBW_INC_IFG/EGBW_INC_IFG` flags control whether the Inter Frame Gaps are part of
|
||||||
|
the bandwidth being controlled. `EGBW_CPUMODE` controls whether packets generated
|
||||||
|
by the internal CPU are subject to egress control.
|
||||||
|
|
||||||
|
`RTL837X_IGBW_PORT_CTRL/RTL837X_EGBW_PORT_CTRL` configure the bandwidth for ingress
|
||||||
|
and egress at a port.
|
||||||
|
|
||||||
|
`RTL837X_IGBW_PORT_FC_CTRL` configures whether packets are bandwidth-controlled using
|
||||||
|
Flow Control (port-bit set), or simply dropped (port-bit clear).
|
||||||
|
|
||||||
|
## Ingress/Egress bandwidth API
|
||||||
|
The code currently provides the following functions:
|
||||||
|
```
|
||||||
|
void bandwidth_setup(void) __banked;
|
||||||
|
void bandwidth_ingress_set(uint8_t port, __xdata uint32_t bw) __banked;
|
||||||
|
void bandwidth_ingress_disable(uint8_t port) __banked;
|
||||||
|
void bandwidth_ingress_drop(uint8_t port) __banked;
|
||||||
|
void bandwidth_egress_set(uint8_t port, __xdata uint32_t bw) __banked;
|
||||||
|
void bandwidth_egress_disable(uint8_t port) __banked;
|
||||||
|
void bandwidth_status(uint8_t port) __banked;
|
||||||
|
```c
|
||||||
|
|
||||||
|
`bandwidth_setup()` is called at boot-time and configures excluding all special packets
|
||||||
|
that may be for the CPU and packets outgoing from the CPU to be excluded from bandwidth
|
||||||
|
control. IFG is not part of the bandwidth calculation.
|
||||||
|
|
||||||
|
`bandwidth_ingress_set()` enables ingress bandwidth control for a particular port given
|
||||||
|
the specified bandwidth. This also enabled Flow Control at a port.
|
||||||
|
|
||||||
|
`bandwidth_ingress_set()` enables egress bandwidth control for a particular port given
|
||||||
|
the specified bandwidth
|
||||||
|
|
||||||
|
`bandwidth_ingress_disable() / bandwidth_egress_disable()` disable ingress and egress
|
||||||
|
bandwidth control at a given port
|
||||||
|
|
||||||
|
`bandwidth_ingress_drop(port)` configures packets exceeding bandwidth limitations to
|
||||||
|
simply be dropped
|
||||||
|
|
||||||
|
`bandwidth_status(port)` shows the current bandwidth control status for a given port
|
||||||
|
|
||||||
|
## Bandwidth control configuration on the Serial Console
|
||||||
|
The following commands are provided on the serial console:
|
||||||
|
```
|
||||||
|
> bw [in|out|status] <port> [<hexvalue>|off|drop]
|
||||||
|
Configures or shows the status of bandwidth control
|
||||||
|
```
|
||||||
|
The bandwidth is given as the `<hexvalue>` in Kbit/s. Note that the control is only
|
||||||
|
possible at a granularity of 16 Kbit/s and the minimum value is also 16 Kbit/s. The
|
||||||
|
hexadecimal numbers must be given in full bytes, i.e. have an even number of digits.
|
||||||
|
|
||||||
|
To enable bandwidth control of ingress for physical port 2 to be set to 256 Kbit/s
|
||||||
|
do:
|
||||||
|
```
|
||||||
|
> bw in 2 0100
|
||||||
|
```
|
||||||
|
|
||||||
|
To drop packets when the bandwidth is exceeeded at port 2 do:
|
||||||
|
```
|
||||||
|
> bw in 2 drop
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable bandwidth control for incoming packets on port 2 do:
|
||||||
|
```
|
||||||
|
> bw in 2 off
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bandwidth configuration via the Web Interface
|
||||||
|
Not implemented, yet!
|
||||||
|
|
||||||
|
## A Test using iperf3
|
||||||
|
The following is and example how to test bandwidth control with a signle Linux device using
|
||||||
|
network namespaces to route packets between a client and a server on the same Linux device
|
||||||
|
through an external switch.
|
||||||
|
|
||||||
|
You will need 2 network intefaces on the linux device, say, 2 USB-Ethernet controllers called
|
||||||
|
eth0 and eth1:
|
||||||
|
```
|
||||||
|
$ sudo ip netns add client
|
||||||
|
$ sudo ip netns add server
|
||||||
|
|
||||||
|
$ sudo ip link set dev eth0 netns client
|
||||||
|
$ sudo ip link set dev eth1 netns server
|
||||||
|
|
||||||
|
$ sudo ip netns exec client ip link set dev eth0 up
|
||||||
|
$ sudo ip netns exec server ip link set dev eth1 up
|
||||||
|
|
||||||
|
$ sudo ip netns exec client ip addr add dev eth0 192.168.99.1/24
|
||||||
|
$ sudo ip netns exec server ip addr add dev eth1 192.168.99.2/24
|
||||||
|
|
||||||
|
$ sudo ip netns exec server iperf3 -s
|
||||||
|
```
|
||||||
|
This will start an iper3 server in the above shell.
|
||||||
|
|
||||||
|
In a different shell you can now run the iperf3 client against your server:
|
||||||
|
```
|
||||||
|
$ sudo ip netns exec client iperf -c 192.168.99.2
|
||||||
|
```
|
||||||
|
The LEDs on your switch where your network adapters are connected should start to flicker.
|
||||||
|
On a 1GBit connection, you should see:
|
||||||
|
```
|
||||||
|
$ sudo ip netns exec client iperf3 -c 192.168.99.2
|
||||||
|
Connecting to host 192.168.99.2, port 5201
|
||||||
|
[ 5] local 192.168.99.1 port 46776 connected to 192.168.99.2 port 5201
|
||||||
|
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||||
|
[ 5] 0.00-1.00 sec 114 MBytes 952 Mbits/sec 0 339 KBytes
|
||||||
|
[ 5] 1.00-2.00 sec 113 MBytes 946 Mbits/sec 0 356 KBytes
|
||||||
|
[ 5] 2.00-3.00 sec 112 MBytes 937 Mbits/sec 0 390 KBytes
|
||||||
|
[ 5] 3.00-4.00 sec 112 MBytes 942 Mbits/sec 0 390 KBytes
|
||||||
|
[ 5] 4.00-5.00 sec 112 MBytes 943 Mbits/sec 0 390 KBytes
|
||||||
|
[ 5] 5.00-6.00 sec 112 MBytes 944 Mbits/sec 0 390 KBytes
|
||||||
|
[ 5] 6.00-7.00 sec 112 MBytes 938 Mbits/sec 0 390 KBytes
|
||||||
|
[ 5] 7.00-8.00 sec 112 MBytes 942 Mbits/sec 0 410 KBytes
|
||||||
|
[ 5] 8.00-9.00 sec 113 MBytes 947 Mbits/sec 0 410 KBytes
|
||||||
|
[ 5] 9.00-10.00 sec 112 MBytes 940 Mbits/sec 0 410 KBytes
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
[ ID] Interval Transfer Bitrate Retr
|
||||||
|
[ 5] 0.00-10.00 sec 1.10 GBytes 943 Mbits/sec 0 sender
|
||||||
|
[ 5] 0.00-10.00 sec 1.10 GBytes 941 Mbits/sec receiver
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, we limit ingress on port 1 (connected to eth0) to 4 MBit/s:
|
||||||
|
```> bw in 1 1000
|
||||||
|
bandwidth_ingress_set called, port 04
|
||||||
|
RTL837X_IGBW_PORT_CTRL:0x00100100
|
||||||
|
RTL837X_IGBW_PORT_FC_CTRL:0x00000010
|
||||||
|
```
|
||||||
|
|
||||||
|
We now get:
|
||||||
|
```
|
||||||
|
$ sudo ip netns exec client iperf3 -c 192.168.99.2
|
||||||
|
[ 5] local 192.168.99.1 port 43324 connected to 192.168.99.2 port 5201
|
||||||
|
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||||
|
[ 5] 0.00-1.00 sec 1.12 MBytes 9.43 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 1.00-2.00 sec 640 KBytes 5.24 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 2.00-3.00 sec 384 KBytes 3.15 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 3.00-4.00 sec 384 KBytes 3.15 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 4.00-5.00 sec 640 KBytes 5.24 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 5.00-6.00 sec 256 KBytes 2.10 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 6.00-7.00 sec 640 KBytes 5.24 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 7.00-8.00 sec 384 KBytes 3.15 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 8.00-9.00 sec 640 KBytes 5.24 Mbits/sec 0 160 KBytes
|
||||||
|
[ 5] 9.00-10.00 sec 256 KBytes 2.10 Mbits/sec 0 160 KBytes
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
[ ID] Interval Transfer Bitrate Retr
|
||||||
|
[ 5] 0.00-10.00 sec 5.25 MBytes 4.40 Mbits/sec 0 sender
|
||||||
|
[ 5] 0.00-10.16 sec 4.75 MBytes 3.92 Mbits/sec receiver
|
||||||
|
|
||||||
|
iperf Done.
|
||||||
|
```
|
||||||
|
Which is the 4Mbit/s we configured. There are no packet drops (retries) because
|
||||||
|
Flow Control is used to signal the Ethernet adapter on the incoming interface
|
||||||
|
(port 1 of the router) to slow down.
|
||||||
|
|
||||||
|
We can also configure a mere 256KBit/s and packet drop to simulate a bad connection:
|
||||||
|
```
|
||||||
|
> bw in 1 0100
|
||||||
|
bandwidth_ingress_set called, port 04
|
||||||
|
RTL837X_IGBW_PORT_CTRL:0x00100010
|
||||||
|
RTL837X_IGBW_PORT_FC_CTRL:0x00000010
|
||||||
|
|
||||||
|
> bw in 1 drop
|
||||||
|
RTL837X_IGBW_PORT_FC_CTRL:0x00000000
|
||||||
|
```
|
||||||
|
|
||||||
|
We now get:
|
||||||
|
```
|
||||||
|
$ sudo ip netns exec client iperf3 -c 192.168.99.2
|
||||||
|
Connecting to host 192.168.99.2, port 5201
|
||||||
|
[ 5] local 192.168.99.1 port 46060 connected to 192.168.99.2 port 5201
|
||||||
|
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||||
|
[ 5] 0.00-1.00 sec 384 KBytes 3.14 Mbits/sec 2 1.41 KBytes
|
||||||
|
[ 5] 1.00-2.00 sec 0.00 Bytes 0.00 bits/sec 54 1.41 KBytes
|
||||||
|
[ 5] 2.00-3.00 sec 0.00 Bytes 0.00 bits/sec 31 29.7 KBytes
|
||||||
|
[ 5] 3.00-4.00 sec 0.00 Bytes 0.00 bits/sec 2 1.41 KBytes
|
||||||
|
[ 5] 4.00-5.00 sec 0.00 Bytes 0.00 bits/sec 23 1.41 KBytes
|
||||||
|
[ 5] 5.00-6.00 sec 128 KBytes 1.05 Mbits/sec 16 14.1 KBytes
|
||||||
|
[ 5] 6.00-7.00 sec 0.00 Bytes 0.00 bits/sec 2 1.41 KBytes
|
||||||
|
[ 5] 7.00-8.00 sec 0.00 Bytes 0.00 bits/sec 11 1.41 KBytes
|
||||||
|
[ 5] 8.00-9.00 sec 128 KBytes 1.05 Mbits/sec 9 8.48 KBytes
|
||||||
|
[ 5] 9.00-10.00 sec 0.00 Bytes 0.00 bits/sec 2 1.41 KBytes
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
[ ID] Interval Transfer Bitrate Retr
|
||||||
|
[ 5] 0.00-10.00 sec 640 KBytes 524 Kbits/sec 152 sender
|
||||||
|
[ 5] 0.00-10.00 sec 256 KBytes 210 Kbits/sec receiver
|
||||||
|
|
||||||
|
iperf Done.
|
||||||
|
```
|
||||||
|
Which shows a large number of retries due to dropped packets and an average number
|
||||||
|
of received packets (the client sends the packets to the server, and they are sent
|
||||||
|
back to the client by the server) of 210 KBit/s, the number is higher for the transmitted
|
||||||
|
packets, because they may include dropped packets.
|
||||||
@@ -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,161 @@
|
|||||||
|
### 2M-PCB23-V3.1
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| keepLINK | KP-9000-9XHML-X | Yes| 2M-PCB23-V3.1 | 2M| 8273N + 8224N |
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
<img src="photos/2M-PCB23-V3.1-managed/2M-PCB23-V3.1-top.jpeg" width="300" />
|
||||||
|
|
||||||
|
## Port overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ┌──────────┐ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP (J4) │ │
|
||||||
|
│ │ 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
|
||||||
|
|`J4` SFP PINs | Signal | Component | GPIO | Notes |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|2| TX_FAULT | | --- | |
|
||||||
|
|3| TX_DISABLE | | --- | Pull down - 0R |
|
||||||
|
|4| MODDEF2 – SDA | b-r273 | GPIO39-SDA4 | |
|
||||||
|
|5| MODDEF1 – SCL | b-r274 | GPIO40-SCL3 | |
|
||||||
|
|6| MODDEF0 – PRESENT | B-R275 | GPIO38 | |
|
||||||
|
|7| RATE SEL | | --- | |
|
||||||
|
|8| LOS | B-R276 | GPIO38 | |
|
||||||
|
|9| TO? | | --- | |
|
||||||
|
|
||||||
|
Note: component numbering `<L>-<REFDES>-<SIDE>`
|
||||||
|
* L: Layer, T=Top, B=Bottom
|
||||||
|
* REFDEES: full silkscreen like `R123`
|
||||||
|
* SIDE: Side of the component. when the rj45 are facing towards you are you can read the silkscreen normal.
|
||||||
|
L = Left, R=right, B=bottom, T=top or P with a pin number.
|
||||||
|
|
||||||
|
### T8, serial console
|
||||||
|
|`T9` pin|GPIO|Signal|
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GPIO31 | U0TXD (Output) |
|
||||||
|
| 2 | GND | PWR |
|
||||||
|
| 3 | GPIO32 | U0RXD (Input) |
|
||||||
|
| 4 | 3V3 | PWR |
|
||||||
|
|
||||||
|
### T7, Slave Interface
|
||||||
|
|`T7` pin|what|Signal|Components|
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | Slave Interface | Slave SCK/SCL/MDC/EE_SCL | U7-6 |
|
||||||
|
| 2 | GND | | |
|
||||||
|
| 3 | Slave Interface | Slave SDI/SDA/MDIO/EE_SDA | U7-5 |
|
||||||
|
| 4 | 3V3 | | |
|
||||||
|
| 5 | GPIO? | | |
|
||||||
|
| 6 | GPIO? | | |
|
||||||
|
|
||||||
|
`U7` can be a standard I2C eeprom memory, like `24LC32`.
|
||||||
|
|
||||||
|
The Slave Interface allows an extenal host to controll the SOC even if the internal MCU is used.
|
||||||
|
Depending on the `IF_SEL` bootstrap resistors, this can me `I2C`, `SPI` or `SMI`.
|
||||||
|
On this device it is `I2C` on address `0b1011100` or `0x5c` (7-bit notation).
|
||||||
|
|
||||||
|
* I2c Read: must be a write_read opperation `<Dev-ADDR><RegAddr15:8><RegAddr7:0>` `<DevAddr><Data7:0><Data15:8><Data23:16><Data31:24>`.
|
||||||
|
* I2c Write: `<Dev-ADDR><RegAddr15:8><RegAddr7:0><DevAddr><Data7:0><Data15:8><Data23:16><Data31:24>`.
|
||||||
|
|
||||||
|
Example register `0x0004` return chip id `0x00, 0x00, 0x72, 0x83` = `0x83720000`.
|
||||||
|
|
||||||
|
### T9
|
||||||
|
|`T9` SMI | Signal | Component | GPIO | Notes |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
|1| MDO | SMI-MDO | GPIO41 | |
|
||||||
|
|2| GND | PWR | | |
|
||||||
|
|3| MDC | SMI-MDC | GPio40 | |
|
||||||
|
|
||||||
|
### T10
|
||||||
|
|`T10` pin|what|Signal|
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GPIO49 | |
|
||||||
|
| 2 | GPIO47 | |
|
||||||
|
| 3 | 3V3 | |
|
||||||
|
| 4 | GPIO48 | |
|
||||||
|
| 5 | GND | |
|
||||||
|
| 6 | GPIO46 | |
|
||||||
|
|
||||||
|
# Reset ciruit
|
||||||
|
|
||||||
|
Reset-line found at `T-D6-L`, `T-R83`, `T-R97`, `T-R94`, `T-R93` active-low.
|
||||||
|
|
||||||
|
# GPIO
|
||||||
|
|
||||||
|
| HEX VAL. | GPIO | Component | What | | GPIO | Component | What |
|
||||||
|
| -------- | ------ | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||||
|
| 00000001 | GPIO00 | T-R34-R, P1-LED-YL |? | | GPIO32 | B-r126-r | U0RXD |
|
||||||
|
| 00000002 | GPIO01 | T-R99-R, P1-LED-GR |? | | GPIO33 | | |
|
||||||
|
| 00000004 | GPIO02 | |? | | GPIO34 | B-R172, To RTL8224 | SMI-MDC0 |
|
||||||
|
| 00000008 | GPIO03 | T-R113-R, P2-LED-GR |? | | GPIO35 | B-R173, To RTL8224 | SMI-MDIO0 |
|
||||||
|
| 00000010 | GPIO04 | T-R115-R, P3-LED-YL |? | | GPIO36 | | | |
|
||||||
|
| 00000020 | GPIO05 | T-R117-R, P3-LED-GR |? | | GPIO37 | To RTL8224 ?? | Already driver low | |
|
||||||
|
| 00000040 | GPIO06 | |? | | GPIO38 | sfp-6 via B-R275, sfp-8 via B-R276 | SFP-PRESENT |
|
||||||
|
| 00000080 | GPIO07 | |? | | GPIO39 | sfp-4, b-r273, B-r143 | I2C4-SDA |
|
||||||
|
| 00000100 | GPIO08 | | | | GPIO40 | T9-2, sfp-5 b-r274, B-r146 | I2C3-SCL |
|
||||||
|
| 00000200 | GPIO09 | |LEDx[^1] | | GPIO41 | T9-1, B-r143 | | I2C3-SDA (Unused) |
|
||||||
|
| 00000400 | GPIO10 | | | | GPIO42 | U6?8?-P6, T-R | SPI-MEMORY, CLK |
|
||||||
|
| 00000800 | GPIO11 | |LEDx[^1] | | GPIO43 | U6?8?-P5, T-R | SPI-MEMORY, DI,IO0 |
|
||||||
|
| 00001000 | GPIO12 | |LEDx[^1] | | GPIO44 | U6?8?-P2, T-R | SPI-MEMORY, DO,IO1 |
|
||||||
|
| 00002000 | GPIO13 | |LEDx[^1] | | GPIO45 | U6?8?-P1, T-R | SPI-MEMORY, CS |
|
||||||
|
| 00004000 | GPIO14 | |LEDx[^1] | | GPIO46 | T10-6 | SPI0-SCK |
|
||||||
|
| 00008000 | GPIO15 | |LEDx[^1] | | GPIO47 | T10-2 | SPI0-SDA |
|
||||||
|
| 00010000 | GPIO16 | |LEDx[^1] | | GPIO48 | T10-4, J6 (BUTTON RESET) | SPI1-SCK |
|
||||||
|
| 00020000 | GPIO17 | |LEDx[^1] | | GPIO49 | T10-1 | SPI1-SDA |
|
||||||
|
| 00040000 | GPIO18 | |LEDx[^1] | | GPIO50 | | |
|
||||||
|
| 00080000 | GPIO19 | |LEDx[^1] | | GPIO51 | | |
|
||||||
|
| 00100000 | GPIO20 | |LEDx[^1] | | GPIO52 | | |
|
||||||
|
| 00200000 | GPIO21 | P7-LED-GR, B-R139 |LEDx[^1] | | GPIO53 | | |
|
||||||
|
| 00400000 | GPIO22 | |LEDx[^1] | | GPIO54 | | |
|
||||||
|
| 00800000 | GPIO23 | |LEDx[^1] | | GPIO55 | | |
|
||||||
|
| 01000000 | GPIO24 | P8-led-yellow,b-r154 |LEDx | | GPIO56 | | |
|
||||||
|
| 02000000 | GPIO25 | | | | GPIO57 | | |
|
||||||
|
| 04000000 | GPIO26 | |LEDx | | GPIO58 | | |
|
||||||
|
| 08000000 | GPIO27 | |? | | GPIO59 | | |
|
||||||
|
| 10000000 | GPIO28 | | | | GPIO60 | | |
|
||||||
|
| 20000000 | GPIO29 | | | | GPIO61 | | |
|
||||||
|
| 40000000 | GPIO30 | RTL8224N Reset |RTL8224 | | GPIO62 | To RTL8224 | Already driver | |
|
||||||
|
| 80000000 | GPIO31 | B-r129-r? |U0TXD | | GPIO63 | | |
|
||||||
|
|
||||||
|
## GPIO Register Input value
|
||||||
|
|
||||||
|
GPIO 1: 0a7ffbdd
|
||||||
|
GPIO 0: effb6dff
|
||||||
|
|
||||||
|
# LEDs
|
||||||
|
|
||||||
|
| NAME | COMPONENTS | GPIO |
|
||||||
|
| ---- | ---------- | ---- |
|
||||||
|
| SYSTEM | | ? |
|
||||||
|
| SFP | | ? |
|
||||||
|
|
||||||
|
|
||||||
|
# Power supply
|
||||||
|
|
||||||
|
Board has two supply rails.
|
||||||
|
`0.95` and `3.3` volt.
|
||||||
|
|
||||||
|
## `0.95` Core Voltage.
|
||||||
|
|
||||||
|
Voltage is crated by a `MP2225GJ` Buck converter.
|
||||||
|
0.95V must be within 3%.
|
||||||
|
|
||||||
|
## `3.3` Voltage
|
||||||
|
|
||||||
|
Voltage is crated by a `MP2225GJ` Buck converter.
|
||||||
|
3.3V must be within 4.5%.
|
||||||
|
Chip can deliver up to 5A and the sweetspot is at 2A.
|
||||||
|
So higher power SFP-modules should work.
|
||||||
|
|
||||||
|
|
||||||
|
[^1]: LEDs are found by just plugin a RJ45 connector and see with cmd `gpio` the status change. But the bit pattern for port 1,2 are diffrent from port 3,4.
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# 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,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,54 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
The original software is running UART on 9600 baud rate.
|
||||||
|
|
||||||
|
Using a SOIC clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
The board has a single flash chips `BS` with 4M-bit size. The front switch, switches between the two flash chips.
|
||||||
|
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**: 9-Ports 2.5G Ethernet Switch
|
||||||
|
- **Ports**:
|
||||||
|
- 8 × RJ45: 10/100/1000/2500 Mbps
|
||||||
|
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
|
||||||
|
- **Power**: 12V DC, 1A barrel connector
|
||||||
|
|
||||||
|
<img src="photos/SWTG018AS_A_V_2_0/label.jpg" width="300" />
|
||||||
|
|
||||||
|
### What works
|
||||||
|
The device is fully supported:
|
||||||
|
- All 8 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: SWTG018AS-A-V2.0.1_19649
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/SWTG018AS_A_V_2_0/pcb_top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/SWTG018AS_A_V_2_0/pcb_bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
### J1, serial console
|
||||||
|
|
||||||
|
| `J1` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | 3V3 |
|
||||||
|
| 2 | GND |
|
||||||
|
| 3 | RX (Input) |
|
||||||
|
| 4 | TX (Output) |
|
||||||
|
|
||||||
|
|
||||||
|
## Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
@@ -8,32 +8,56 @@ Also the RJ45 connectors can be all plastic/non-shielded or with metal shielding
|
|||||||
## Brands
|
## Brands
|
||||||
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|
||||||
|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|
|
||||||
| LIANGUO |SWTG024AS |No| SWTG024AS-v2.0 | CM-23-11-2336 023-17453| 512kB| 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 |
|
| Haraco |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 | ??? | 8272 |
|
||||||
|
| Sodola | SL-SWTG124AS-D | Yes | SWTG024AS-v2.0-17452 | ??? | 2048 KiB | 8272 |
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
<img src="photos/SWTG024AS-v2.0-unmanaged/SWTG024AS-v2.0-top-uman.png" width="300" />
|
||||||
|
|
||||||
# SWTG024AS-v2.0 managed vs unmanged
|
# SWTG024AS-v2.0 managed vs unmanged
|
||||||
Changes I found with my board vs [Managed version](https://github.com/up-n-atom/SWTG118AS/tree/main/photos/SWGT024AS-v2.0) of the PCB.
|
Changes I found with my board vs [Managed version](https://github.com/up-n-atom/SWTG118AS/tree/main/photos/SWGT024AS-v2.0) of the PCB.
|
||||||
|
|
||||||
### Bottom
|
### Bottom
|
||||||
* R105: Installed, goes to R10-PullDown SFP2 -> TX DISABLE
|
* R105: Installed, goes to R10-PullDown SFP2 (J2) -> TX-DISABLE
|
||||||
* R85: Not Installed (Connected to K1 Reset Button)
|
* R85: Not Installed (Connected to K1 Reset Button)
|
||||||
* R90: Not installed (System Led)
|
* R90: Not installed (System Led)
|
||||||
* LED3: Not installed (System Led)
|
* LED3: Not installed (System Led)
|
||||||
### Top
|
### Top
|
||||||
* K1: Not installed (Reset Button)
|
* K1: Not installed (Reset Button)
|
||||||
* R95: Installed (SFP2 signal RX-LOS), means that the managed-version can´t use the RX-LOS function.
|
* R95: Installed (SFP2 (J2) signal RX-LOS), means that the managed-version can´t use the RX-LOS function.
|
||||||
* R270: Installed (SFP1 signal RX-LOS), same here as above.
|
* R270: Installed (SFP1 (J4) signal RX-LOS), same here as above.
|
||||||
* R268: Installed (SFP2 signal TX_DISABLE, but R262 200R pull-down is to high to drive by the SOC, needs mod!)
|
* R268: Installed (SFP2 (J2) signal TX-DISABLE, but R262 200R pull-down is to high to drive by the SOC, needs mod!)
|
||||||
* U5: Flash is only 512kB instead of 2/4 MBit.
|
* U5: Flash is only 512 KiB instead of 2/4 MiB.
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
* `TX Disable`-SFP2 and Button `K1` share the same GPIO pin via `R105` and `R85`.
|
* `TX-Disable`-SFP2 and Button `K1` share the same GPIO pin via `R105` and `R85`.
|
||||||
But via `R88`, `TX Disable`-SFP2 can be mapped to `GPIO36`.
|
But via `R88`, `TX-Disable`-SFP2 can be mapped to `GPIO36`.
|
||||||
* `TX Disable` pull-down resistos on both SFP are to low to drive by the SOC.
|
* `TX-Disable` pull-down resistos on both SFP are to low to drive by the SOC.
|
||||||
We need to make a `Best`-BOM variant so we can use all the featues.
|
We need to make a `Best`-BOM variant so we can use all the featues.
|
||||||
|
|
||||||
# Connectors
|
# Connectors
|
||||||
|
|
||||||
|
## Port overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP (J4) │ │ SFP (J2) │ │
|
||||||
|
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 5 │ │ PORT 6 │ │
|
||||||
|
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC 8 │ │ MAC 3 │ │
|
||||||
|
│ O │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 1 │ │ SerDes 0 │ │
|
||||||
|
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
|
||||||
|
└────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## J4
|
||||||
|
|
||||||
|
* Location: Left SFP connector `J4`.
|
||||||
|
* Connected to: 10GMAC number 8, second SerDes.
|
||||||
|
|
||||||
|`J4` SFP1 PINs | Signal | Component | GPIO | Notes |
|
|`J4` SFP1 PINs | Signal | Component | GPIO | Notes |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|2| TX_FAULT | B-R262 | --- | |
|
|2| TX_FAULT | B-R262 | --- | |
|
||||||
@@ -45,6 +69,11 @@ Changes I found with my board vs [Managed version](https://github.com/up-n-atom/
|
|||||||
|8| LOS | B-R258, T-R270 | GPIO37 | |
|
|8| LOS | B-R258, T-R270 | GPIO37 | |
|
||||||
|9| TO? | B-R256 | --- | |
|
|9| TO? | B-R256 | --- | |
|
||||||
|
|
||||||
|
## J2
|
||||||
|
|
||||||
|
* Location: Right SFP connector `J2`.
|
||||||
|
* Connected to: 10GMAC number 3, first SerDes.
|
||||||
|
|
||||||
|`J2` SFP2 PINs | Signal | Component | GPIO | Notes |
|
|`J2` SFP2 PINs | Signal | Component | GPIO | Notes |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|2| TX_FAULT | B-R70 | --- | |
|
|2| TX_FAULT | B-R70 | --- | |
|
||||||
@@ -62,19 +91,27 @@ Note: component numbering `<L>-<REFDES>-<SIDE>`
|
|||||||
* SIDE: Side of the component. when the rj45 are facing towards you are you can read the silkscreen normal.
|
* SIDE: Side of the component. when the rj45 are facing towards you are you can read the silkscreen normal.
|
||||||
L = Left, R=right, B=bottom, T=top or P with a pin number.
|
L = Left, R=right, B=bottom, T=top or P with a pin number.
|
||||||
|
|
||||||
### T3
|
### T3, Slave Interface
|
||||||
This connector seems to go to U4 and U10.
|
This connector goes to U4 `I2C EEPROM` and U10 `SPI FLASH`.
|
||||||
I thing is used to connect a external CPU to controlle the SOC.
|
|
||||||
Even to program the flash via the SOC.
|
|
||||||
Signals are based on that `U4` is likely a I2C-EEPROM, `U10` is likely other SPI-chip.
|
Signals are based on that `U4` is likely a I2C-EEPROM, `U10` is likely other SPI-chip.
|
||||||
|`T3` pin|what|Signal|
|
|`T3` pin|what|Signal|
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|1| U4-P6, 33R U10-P6 | I2C-SCL, SPI-CLK |
|
|1| U4-P6, 33R U10-P6 | I2C-SCL, SPI-CLK, Slave SCK/SCL/MDC/EE_SCL |
|
||||||
|2| GND | --- |
|
|2| GND | --- |
|
||||||
|3| U4-P5, U10-P5 | I2C-SDA, SPI-DI/DO |
|
|3| U4-P5, U10-P5 | I2C-SDA, SPI-DI/DO, Slave SDI/SDA/MDIO/EE_SDA |
|
||||||
|4| VCC |
|
|4| VCC |
|
||||||
|5| 33R -> U10-P2 | SPI-DO/D1 |
|
|5| 33R -> U10-P2 | SPI-DO/D1 |
|
||||||
|6| U10-P1 | SPI-CS |
|
|6| U10-P1 | SPI-CS |
|
||||||
|
Note: 1 pin is square shaped.
|
||||||
|
|
||||||
|
The Slave Interface allows an extenal host to controll the SOC even if the internal MCU is used.
|
||||||
|
Depending on the `IF_SEL` bootstrap resistors, this can me `I2C`, `SPI` or `SMI`.
|
||||||
|
On this device it is `I2C` on address `0b1011100` or `0x5c` (7-bit notation).
|
||||||
|
|
||||||
|
* I2c Read: must be a write_read opperation `<Dev-ADDR><RegAddr15:8><RegAddr7:0>` `<DevAddr><Data7:0><Data15:8><Data23:16><Data31:24>`.
|
||||||
|
* I2c Write: `<Dev-ADDR><RegAddr15:8><RegAddr7:0><DevAddr><Data7:0><Data15:8><Data23:16><Data31:24>`.
|
||||||
|
|
||||||
|
Example register `0x0004` return chip id `0x00, 0x00, 0x72, 0x83` = `0x83720000`.
|
||||||
|
|
||||||
### T5, serial console
|
### T5, serial console
|
||||||
|`T5` pin|GPIO|Signal|
|
|`T5` pin|GPIO|Signal|
|
||||||
@@ -83,6 +120,7 @@ Signals are based on that `U4` is likely a I2C-EEPROM, `U10` is likely other SPI
|
|||||||
| 2 | GND | |
|
| 2 | GND | |
|
||||||
| 3 | GPIO32 | U0RXD (Input) |
|
| 3 | GPIO32 | U0RXD (Input) |
|
||||||
| 4 | 3V3 | |
|
| 4 | 3V3 | |
|
||||||
|
Note: 1 pin is square shaped.
|
||||||
|
|
||||||
### T8
|
### T8
|
||||||
|`T8` pin|what|Signal|
|
|`T8` pin|what|Signal|
|
||||||
@@ -93,6 +131,7 @@ Signals are based on that `U4` is likely a I2C-EEPROM, `U10` is likely other SPI
|
|||||||
| 4 | 3V3 | |
|
| 4 | 3V3 | |
|
||||||
| 5 | GPIO47 | |
|
| 5 | GPIO47 | |
|
||||||
| 6 | GPIO49 | |
|
| 6 | GPIO49 | |
|
||||||
|
Note: 1 pin is square shaped.
|
||||||
|
|
||||||
# Reset ciruit
|
# Reset ciruit
|
||||||
| Cmp | Function |
|
| Cmp | Function |
|
||||||
@@ -110,9 +149,9 @@ Reset-line found at `T-D3-D` active-low.
|
|||||||
| 00000002 | GPIO01 | T-C152-T |? | | GPIO33 | | |
|
| 00000002 | GPIO01 | T-C152-T |? | | GPIO33 | | |
|
||||||
| 00000004 | GPIO02 | T-C153-T |? | | GPIO34 | | |
|
| 00000004 | GPIO02 | T-C153-T |? | | GPIO34 | | |
|
||||||
| 00000008 | GPIO03 | T-R33-T |? | | GPIO35 | | |
|
| 00000008 | GPIO03 | T-R33-T |? | | GPIO35 | | |
|
||||||
| 00000010 | GPIO04 | B-C155 |? | | GPIO36 | T-R88-L, T-R84-B | Optional SFP-TX-DIS[^2], Reset |
|
| 00000010 | GPIO04 | B-C155 |? | | GPIO36 | T-R88-L, T-R84-B | Optional SFP2 TX-DISABLE[^2], Reset |
|
||||||
| 00000020 | GPIO05 | B-C156 |? | | GPIO37 | SFP1-8, T-R270 | SFP-LOS |
|
| 00000020 | GPIO05 | B-C156 |? | | GPIO37 | SFP1-8, T-R270 | SFP-LOS |
|
||||||
| 00000040 | GPIO06 | T-C157-T |? | | GPIO38 | SFP1-3, T-R268 | SFP-TX-DIS[^2] |
|
| 00000040 | GPIO06 | T-C157-T |? | | GPIO38 | SFP1-3, T-R268 | SFP1 TX-DISABLE[^2] |
|
||||||
| 00000080 | GPIO07 | T-C158-T, R165 |? | | GPIO39 | SFP1-4, T-R266 | I2C-SDA4 |
|
| 00000080 | GPIO07 | T-C158-T, R165 |? | | GPIO39 | SFP1-4, T-R266 | I2C-SDA4 |
|
||||||
| 00000100 | GPIO08 | | | | GPIO40 | SFP2-5, T-R87; SFP1-5, T-R267; | I2C-SCL |
|
| 00000100 | GPIO08 | | | | GPIO40 | SFP2-5, T-R87; SFP1-5, T-R267; | I2C-SCL |
|
||||||
| 00000200 | GPIO09 | SFP2-LED, T-R36-T |LED-SFP2 | | GPIO41 | SFP2-4, T-R85 | I2C-SDA |
|
| 00000200 | GPIO09 | SFP2-LED, T-R36-T |LED-SFP2 | | GPIO41 | SFP2-4, T-R85 | I2C-SDA |
|
||||||
@@ -128,7 +167,7 @@ Reset-line found at `T-D3-D` active-low.
|
|||||||
| 00080000 | GPIO19 | PORT3-LED-GREEN |LEDx[^1] | | GPIO51 | SFP2-8, T-R95 | SFP-LOS |
|
| 00080000 | GPIO19 | PORT3-LED-GREEN |LEDx[^1] | | GPIO51 | SFP2-8, T-R95 | SFP-LOS |
|
||||||
| 00100000 | GPIO20 | PORT3-LED-YELLOW |LEDx | | GPIO52 | | |
|
| 00100000 | GPIO20 | PORT3-LED-YELLOW |LEDx | | GPIO52 | | |
|
||||||
| 00200000 | GPIO21 | |LEDx[^1] | | GPIO53 | | |
|
| 00200000 | GPIO21 | |LEDx[^1] | | GPIO53 | | |
|
||||||
| 00400000 | GPIO22 | PORT4-LED-GREEN |LEDx[^1] | | GPIO54 | SFP2-3, T-R105-L | SFP-TX-DIS[^2] or via T-R85 to RESET[^3], T-R84-T |
|
| 00400000 | GPIO22 | PORT4-LED-GREEN |LEDx[^1] | | GPIO54 | SFP2-3, T-R105-L | SFP2 TX-DISABLE[^2] or via T-R85 to RESET[^3], T-R84-T |
|
||||||
| 00800000 | GPIO23 | PORT4-LED-YELLOW |LEDx | | GPIO55 | T-R78-B | |
|
| 00800000 | GPIO23 | PORT4-LED-YELLOW |LEDx | | GPIO55 | T-R78-B | |
|
||||||
| 01000000 | GPIO24 | SFP1-LED-J4, T-R35 |LED-SFP1 | | GPIO56 | | |
|
| 01000000 | GPIO24 | SFP1-LED-J4, T-R35 |LED-SFP1 | | GPIO56 | | |
|
||||||
| 02000000 | GPIO25 | | | | GPIO57 | | |
|
| 02000000 | GPIO25 | | | | GPIO57 | | |
|
||||||
@@ -170,5 +209,5 @@ So higher power SFP-modules should work.
|
|||||||
|
|
||||||
|
|
||||||
[^1]: LEDs are found by just plugin a RJ45 connector and see with cmd `gpio` the status change. But the bit pattern for port 1,2 are diffrent from port 3,4.
|
[^1]: LEDs are found by just plugin a RJ45 connector and see with cmd `gpio` the status change. But the bit pattern for port 1,2 are diffrent from port 3,4.
|
||||||
[^2]: Only on the unmanaged verions are `R10` and `R268` placed. But the very low pull-down resistor `R10` & `R262` prevent to SOC to drive does pins. A mod is needed.
|
[^2]: Only on the unmanaged verions are `R10` and `R268` placed. But the very low pull-down resistor `R10` and `R262` prevent to SOC to drive does pins. A mod is needed.
|
||||||
[^3]: GPIO54 is used for the reset-button. `T-R85` is placed.
|
[^3]: GPIO54 is used for the reset-button. `T-R85` is placed.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
### ZX-SWTGW218AS
|
||||||
|
|
||||||
|
## Brands
|
||||||
|
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
|
||||||
|
| Sodola | | | | | |
|
||||||
|
| Horaco | | | | | |
|
||||||
|
|
||||||
|
|
||||||
|
## Photos
|
||||||
|
|
||||||
|
<img src="photos/SWTGW218AS-managed/front.png" width="800" />
|
||||||
|
|
||||||
|
<img src="photos/SWTGW218AS-managed/label.jpg" width="800" />
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
See up'n'atom's Repo:
|
||||||
|
|
||||||
|
https://github.com/up-n-atom/SWTG118AS/blob/main/photos/SWTG118AS-v2.0/SWTG118AS-v2.0-pcb-top.JPG
|
||||||
|
|
||||||
|
https://github.com/up-n-atom/SWTG118AS/blob/main/photos/SWTG118AS-v2.0/SWTG118AS-v2.0-pcb-bottom.JPG
|
||||||
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
# TrendNet TEG-S562
|
||||||
|
|
||||||
|
Following is documentation for unmanaged switch marked as `TEG-S563/EU H/W: V1.0R`.
|
||||||
|
|
||||||
|
Original software is running UART on 57600 baud rate. The software does not allow to
|
||||||
|
do anything fancy via serial. There is `IP` configuration which can be printed as well.
|
||||||
|
There might be also some flash upload procedure, but using SPI clamp in-board seems to
|
||||||
|
be easier method.
|
||||||
|
|
||||||
|
The memory chip is `Winbond W25Q16JV` with 16M-bit size.
|
||||||
|
|
||||||
|
## What does work
|
||||||
|
|
||||||
|
1. 2.5G ports on all advertised speeds.
|
||||||
|
2. SFP+ communication.
|
||||||
|
3. Serial, Web UI.
|
||||||
|
4. All LEDs
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## PCB
|
||||||
|
|
||||||
|
Manufacturer information be found [on the product page](https://www.trendnet.com/support/support-detail.asp?prod=105_TEG-S562).
|
||||||
|
|
||||||
|
Top side
|
||||||
|
|
||||||
|
<img src="photos/TEG-S562/TEG-S562-v1.0R-top.jpg" width="300" />
|
||||||
|
|
||||||
|
Bottom
|
||||||
|
|
||||||
|
<img src="photos/TEG-S562/TEG-S562-v1.0R-bottom.jpg" width="300" />
|
||||||
|
|
||||||
|
## Connectors
|
||||||
|
|
||||||
|
### Port overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP 2 │ │ SFP 1 │ │
|
||||||
|
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 5 │ │ PORT 6 │ │
|
||||||
|
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC 8 │ │ MAC 3 │ │
|
||||||
|
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 0 │ │ SerDes 1 │ │
|
||||||
|
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### J2, serial console
|
||||||
|
|
||||||
|
| `J2` pin | Signal |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| 1 | 3V3 |
|
||||||
|
| 2 | TX (Output) |
|
||||||
|
| 3 | RX (Input) |
|
||||||
|
| 4 | GND |
|
||||||
|
|
||||||
|
Note: 1 pin is square shaped, towards the power input.
|
||||||
|
|
||||||
|
### J5, power pass-thru
|
||||||
|
|
||||||
|
| `J5` pin | Signal |
|
||||||
|
| -------- | ------ |
|
||||||
|
| 1 | 12V |
|
||||||
|
| 2 | 12V |
|
||||||
|
| 3 | GND |
|
||||||
|
| 4 | GND |
|
||||||
|
|
||||||
|
Note: 1 pin is square shaped.
|
||||||
|
|
||||||
|
### U5, I2C eeprom placeholder
|
||||||
|
|
||||||
|
| `J5` pin | Signal |
|
||||||
|
| -------- | ------------- |
|
||||||
|
| 1 | GND |
|
||||||
|
| 2 | GND |
|
||||||
|
| 3 | GND |
|
||||||
|
| 4 | GND |
|
||||||
|
| 5 | 3V3 |
|
||||||
|
| 6 | ??? Logic Low |
|
||||||
|
| 7 | SCL |
|
||||||
|
| 8 | SDA |
|
||||||
|
|
||||||
|
SOC I2C address is 0x5c.
|
||||||
|
|
||||||
|
### SW1 GPIO switch?
|
||||||
|
|
||||||
|
Not populated but looks like a switch for selecting
|
||||||
|
GPIO level. Missing resistors in place.
|
||||||
|
|
||||||
|
GPIO mapping unknown.
|
||||||
|
|
||||||
|
### S2 Reset ciruit
|
||||||
|
|
||||||
|
Not populated but looks like a button can be added on `S2` connector,
|
||||||
|
requires additional `R571` resistor which will pull signal to ground.
|
||||||
|
|
||||||
|
GPIO mapping unknown.
|
||||||
|
|
||||||
|
### GPIO
|
||||||
|
|
||||||
|
| HEX VAL. | GPIO | When | GPIO | When |
|
||||||
|
| -------- | ------ | ----------------| ------ | -----------------------|
|
||||||
|
| 00000001 | GPIO00 | | GPIO32 | |
|
||||||
|
| 00000002 | GPIO01 | | GPIO33 | |
|
||||||
|
| 00000004 | GPIO02 | | GPIO34 | Random changes |
|
||||||
|
| 00000008 | GPIO03 | | GPIO35 | |
|
||||||
|
| 00000010 | GPIO04 | | GPIO36 | SFP2 Present |
|
||||||
|
| 00000020 | GPIO05 | | GPIO37 | SFP2 RX Los |
|
||||||
|
| 00000040 | GPIO06 | | GPIO38 | SFP1 Present |
|
||||||
|
| 00000080 | GPIO07 | | GPIO39 | |
|
||||||
|
| 00000100 | GPIO08 | | GPIO40 | |
|
||||||
|
| 00000200 | GPIO09 | | GPIO41 | |
|
||||||
|
| 00000400 | GPIO10 | | GPIO42 | Random changes |
|
||||||
|
| 00000800 | GPIO11 | | GPIO43 | |
|
||||||
|
| 00001000 | GPIO12 | PORT1 Link | GPIO44 | |
|
||||||
|
| 00002000 | GPIO13 | PORT1-LED-GREEN | GPIO45 | |
|
||||||
|
| 00004000 | GPIO14 | PORT1-LED-AMBER | GPIO46 | SFP1 I2C CLK |
|
||||||
|
| 00008000 | GPIO15 | PORT2 Link | GPIO47 | SFP1 I2C SDA |
|
||||||
|
| 00010000 | GPIO16 | PORT2-LED-GREEN | GPIO48 | SFP2 I2C CLK |
|
||||||
|
| 00020000 | GPIO17 | PORT2-LED-AMBER | GPIO49 | SFP2 I2C SDA |
|
||||||
|
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP1 Rx LOS |
|
||||||
|
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP2 TX Disable |
|
||||||
|
| 00100000 | GPIO20 | PORT4-LED-AMBER | GPIO52 | |
|
||||||
|
| 00200000 | GPIO21 | PORT4 Link | GPIO53 | |
|
||||||
|
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP1 TX Disable |
|
||||||
|
| 00800000 | GPIO23 | PORT4-LED-AMBER | GPIO55 | |
|
||||||
|
| 01000000 | GPIO24 | | GPIO56 | |
|
||||||
|
| 02000000 | GPIO25 | | GPIO57 | |
|
||||||
|
| 04000000 | GPIO26 | | GPIO58 | |
|
||||||
|
| 08000000 | GPIO27 | | GPIO59 | |
|
||||||
|
| 10000000 | GPIO28 | | GPIO60 | |
|
||||||
|
| 20000000 | GPIO29 | | GPIO61 | |
|
||||||
|
| 40000000 | GPIO30 | | GPIO62 | |
|
||||||
|
| 80000000 | GPIO31 | | GPIO63 | |
|
||||||
|
|
||||||
|
## LEDs
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
| NAME | When active |
|
||||||
|
| ---------------- | ---------------|
|
||||||
|
| PWR | 3V3 |
|
||||||
|
| SFP1 | |
|
||||||
|
| SFP2 | |
|
||||||
|
| PORT1-LED-GREEN | - |
|
||||||
|
| PORT2-LED-GREEN | PORT2 2.5G |
|
||||||
|
| PORT3-LED-GREEN | PORT3 2.5G |
|
||||||
|
| PORT4-LED-GREEN | PORT4 2.5G |
|
||||||
|
| PORT1-LED-AMBER | PORT1 1GB/100M |
|
||||||
|
| PORT2-LED-AMBER | PORT2 1GB/100M |
|
||||||
|
| PORT3-LED-AMBER | PORT3 1GB/100M |
|
||||||
|
| PORT4-LED-AMBER | PORT4 1GB/100M |
|
||||||
|
|
||||||
|
## 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 `APW8713` (U3).
|
||||||
|
|
||||||
|
### `3.3` Voltage
|
||||||
|
|
||||||
|
Voltage is crated regulated by chip marked as `GoIAT` (U2).
|
||||||
|
|
||||||
|
## SFP SPI
|
||||||
|
|
||||||
|
There is separate clock and data lines for both SFP modules. MSDA/MSCK 0 and 1 need to be enabled.
|
||||||
|
|
||||||
|
SFP1 slot is connected to SPI0. SFP2 slot is connected to SPI1.
|
||||||
|
After Width: | Height: | Size: 560 KiB |
|
After Width: | Height: | Size: 536 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 754 KiB |
|
After Width: | Height: | Size: 521 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 548 KiB |
|
After Width: | Height: | Size: 505 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 876 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 558 KiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 2.4 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
@@ -0,0 +1,41 @@
|
|||||||
|
# Understanding the image using ghidra
|
||||||
|
Start ghidra, load file starting from offset 0x0002 into
|
||||||
|
memory starting at 0x0000. The lengthe is 0x10000. Select generic 8051, big
|
||||||
|
endian.
|
||||||
|
|
||||||
|
After loading, the boot vector is at 0x0000, which will jump to 0x0100 for
|
||||||
|
the boot routine.
|
||||||
|
|
||||||
|
The firmware uses only bank 1 of the RTL837x since it is quite short.
|
||||||
|
Otherwise the firmware would be organized as follows
|
||||||
|
```
|
||||||
|
--------------------------- 0x0000 ---------------------------------
|
||||||
|
Boot-Vector
|
||||||
|
ISRs
|
||||||
|
Common Code
|
||||||
|
Trampoline for inter-bank calls
|
||||||
|
Inter-bank calls, calling trampoline, one for each callable function
|
||||||
|
|
||||||
|
----- Bank 1 0x4000 ------ ---- Bank 2 0x4000 ----- -------- .....
|
||||||
|
Overlay 1 Overlay 2 Overlay n
|
||||||
|
|
||||||
|
--------- 0xffff --------- -------- 0xffff -------- -------- 0xffff
|
||||||
|
```
|
||||||
|
The RTL837x firmware images are organized as follows:
|
||||||
|
The first 2 bytes of the image give the size of the prefetched data at the
|
||||||
|
start of the CPU power up. The default is 0x4000 (bytes: 0x00 0x40), which
|
||||||
|
means that the entire shared area of the code memory in all banks,
|
||||||
|
0x4000 bytes is read immediately into the code RAM.
|
||||||
|
|
||||||
|
Common code starts at
|
||||||
|
0x0002 in the image and has length 0x3ffd, the first bank starts at 0x4000
|
||||||
|
in the image, is mapped to 0x4000 and has length 0xc000. The second bank
|
||||||
|
starts at 0x10000, is mapped to 0x4000 and has length 0xc000. The third
|
||||||
|
bank would start at 0x1c000 and would again be mapped to 0x4000.
|
||||||
|
There are about 30 banks in use for managed switches, unmanaged ones use
|
||||||
|
2-3, while the hardware would allow to use 0x3f banks, i.e. up to 4 MB of
|
||||||
|
flash.
|
||||||
|
|
||||||
|
The current image uses Common BANK0 and the first BANK1 via sdccs __banked
|
||||||
|
function keyword and custom banking trampoline code for the RTL837x in
|
||||||
|
assembler.
|
||||||
@@ -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 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#RTL8272/3 features
|
||||||
|
|
||||||
|
The following hardware features of the RTL8372/3 is supported:
|
||||||
|
- Clock generation, including different divider settings
|
||||||
|
- Interrupt control for timer, serial, external irqs 0, 1
|
||||||
|
- Serial console via SFRs
|
||||||
|
- Flash operations via SFRs
|
||||||
|
- Bank switching via SFRs
|
||||||
|
- Access to Switch registers via SFRs
|
||||||
|
- LED setup
|
||||||
|
- Reset
|
||||||
|
- Some switch settings such as MAC configuration
|
||||||
|
- GPIO to detect SFP module insert/removal/RX-LOS (depending on device/module support)
|
||||||
|
- I2C to read SFP EEPROM on 1 and 2 SFP slot devices
|
||||||
|
- NIC setup
|
||||||
|
- L2 learning table access, L2 table flushing
|
||||||
|
- VLAN setup/configuration
|
||||||
|
- Port mirroring
|
||||||
|
- Access to PHYs via MDIO (clause 45 via SFR):
|
||||||
|
- Internal PHYs of RTL8372 and RTL8373
|
||||||
|
- RTL8221 (1x2.5GBit port on devices with 5 ports)
|
||||||
|
- RTL8224 (4x2.5GBit ports on devices with 8 ports)
|
||||||
|
- SerDes settings of SoC via SFR:
|
||||||
|
- Configure SFPs with 10Gbit/2.5Gbit/1Gbit (Ethernet and Fiber SFP(+) tested)
|
||||||
|
- RTL8221, RTL8224
|
||||||
|
- NIC TX and RX of packets via SFRs
|
||||||
|
- send and receive Ethernet frames via SFRs and Switch registers
|
||||||
|
- RTL-tags and VLAN ingress-tag decoding for CPU-port
|
||||||
|
|
||||||
|
Ethernet frame RX IRQ via IRQ1 is conceptually understood, but not activated. RX is
|
||||||
|
currently done via polling, which allows ping-times of <10ms.
|
||||||
|
|
||||||
|
The RTL8372/3 have 256 bytes of internal RAM (INTMEM) accessible through MOV
|
||||||
|
instructions, which are used for the stack and important globals. Some of
|
||||||
|
these are bit-adressable, e.g. for storing global flags.
|
||||||
|
|
||||||
|
Additionally, 64kB of extended RAM (XMEM) is built in, which is accessed
|
||||||
|
through the MOVX instruction. It is used for global variables, for most
|
||||||
|
of the function argument passing that is not done using the 8 registers
|
||||||
|
R0-R7 or registers A/B, and for local variables (which requires extremely
|
||||||
|
careful planning). The flash memory is transparently accessible for code
|
||||||
|
being executed and can be used to store configuration. Access is done through
|
||||||
|
the MOVC instruction, possibly setting the bank register before and
|
||||||
|
resetting it to access the entire 4MB space. Code is prefetched from flash
|
||||||
|
and cached in a small RAM automatically by the HW.
|
||||||
|
|
||||||
|
The peripherial functions are accessed through 2 different mechanisms:
|
||||||
|
- Special Function Registers (SFRs, 0x80-0xff) for banking, timers, UART, access to
|
||||||
|
switch registers, MDIO, SPI (flash) and NIC transfers. Some SFRs are not
|
||||||
|
used for HW purposes and can be used as RAM. Some SFRs are bit-adressable,
|
||||||
|
allowing for very tight event wait loops (a single 2-byte instruction).
|
||||||
|
- 0x10000 switch registers, which appear to be very similar to the registers
|
||||||
|
of the RTL838x, for which source code and datasheets are available. This
|
||||||
|
controls clock dividers, GPIO/LEDs and general switch functionality.
|
||||||
|
|
||||||
|
The playground image shows access to the different types of memory using the
|
||||||
|
SDCC compiler. Any support of Linux or e.g. Zephyr would require porting gcc.
|
||||||
|
There are FreeRTOS ports to 8051 processors using sdcc, however.
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# IGMP (Internet Group Management Protocol) and MLD (Multicast Listener Discovery)
|
||||||
|
IGMP (for IPv4) and MLD (for IPv6) are protocols that control the distribution
|
||||||
|
of Layer-3 Multicast packets on the LAN, which otherwise would be flooded across the
|
||||||
|
entire network. For this to work, IGMP/MLD messages are sent, in particular
|
||||||
|
from MC consumers (e.g. the video-player that plays an IP-Multicast stream), but
|
||||||
|
also Multicast-aware routers to control switching of the IP-MC or underlying
|
||||||
|
L2-MC packets. The main usage in home networks is IPTV.
|
||||||
|
|
||||||
|
The RTL8372/3 SoC supports managing IPv4-MC using either Destination-IP (the IPv4
|
||||||
|
multicast group address)/Source-IP (typically 0.0.0.0) matching or via controlling
|
||||||
|
the switching of the underlying L2-MC packets (i.e. packets in 01:00:5e:xx:yy:zz, where
|
||||||
|
xx:yy:zz are the LSBs of the IPv4-MC address). The DIP/SIP-based switching is
|
||||||
|
not VLAN-aware, meaning a stream will be available in all VLANs if subscribed to.
|
||||||
|
This is not a problem in a typical home network, however. The L2-based method
|
||||||
|
is VLAN aware, but currently not supported in the software.
|
||||||
|
|
||||||
|
Although there is hardware support for IPv6/MLD-based Multicast management (i.e. intelligent
|
||||||
|
management by the switch), the current software does not implement managing IPv6 Multicast.
|
||||||
|
Instead, all IPv6 Multicast pakets will be flooded to all ports, just as an unmanaged
|
||||||
|
switch would do.
|
||||||
|
|
||||||
|
The current software support works by trapping IGMP packets (only v3 supported, which
|
||||||
|
is used in the vast majority of today's networks) to the CPU of the switch which will
|
||||||
|
update the L3 and L2 switching tables to include switch ports in a stream or remove
|
||||||
|
them. This trapping to the CPU is also called IGMP snooping. While there is support
|
||||||
|
in the HW to handle IGMP/MLD packets (v3 has only limited support) entirely in hardware
|
||||||
|
and even send out reports, it is currently not understood
|
||||||
|
how this works, and instead IGMP is handled entirely in software, which also allows
|
||||||
|
to fully support IGMPv3 packet which are the standard in present-day networks.
|
||||||
|
|
||||||
|
## IP-MC control
|
||||||
|
The relevant registers for controlling IP-MC switching are:
|
||||||
|
```
|
||||||
|
#define RTL837X_IPV4_PORT_MC_LM_ACT 0x4f78
|
||||||
|
#define RTL837X_IPV6_PORT_MC_LM_ACT 0x4f7c
|
||||||
|
#define RTL837X_IGMP_PORT_CFG 0x52a0
|
||||||
|
#define IGMP_MAX_GROUP 0x00ff0000
|
||||||
|
#define IGMP_PROTOCOL_ENABLE 0x00007c00
|
||||||
|
#define IGMP_TRAP 0x0000002a
|
||||||
|
#define IGMP_FLOOD 0x00000015
|
||||||
|
#define IGMP_ASIC 0x00000000
|
||||||
|
#define RTL837X_IGMP_ROUTER_PORT 0x529c
|
||||||
|
#define RTL837X_IPV4_UNKN_MC_FLD_PMSK 0x5368
|
||||||
|
#define RTL837X_IPV6_UNKN_MC_FLD_PMSK 0x536c
|
||||||
|
#define RTL837X_IGMP_TRAP_CFG 0x50bc
|
||||||
|
#define IGMP_TRAP_PRIORITY 0x7
|
||||||
|
#define IGMP_CPU_PORT 0x00010000
|
||||||
|
```
|
||||||
|
`RTL837X_IPV4_PORT_MC_LM_ACT/RTL837X_IPV6_PORT_MC_LM_ACT` control the action when an
|
||||||
|
IP-MC packet is encountered at a switch port and there is no rule for forwarding in
|
||||||
|
the forwarding tables. The default action is to flood such Lookup-Miss packets to all
|
||||||
|
ports. This is the configuration without IGMP/MLD enabled.
|
||||||
|
|
||||||
|
When IGMP/MLD is turned on, the Lookup-Miss action will be changed to drop such packets
|
||||||
|
unless a rule is found in the forwarding tables, which will need to be configured by
|
||||||
|
IGMP packets.
|
||||||
|
|
||||||
|
Switching on IGMP also configures all ports via `RTL837X_IGMP_PORT_CFG` to trap all
|
||||||
|
incoming IGMP packets to the CPU. `RTL837X_IGMP_TRAP_CFG` then is used to configure
|
||||||
|
priority and CPU-Port of trapped IGMP/MLD packets.
|
||||||
|
|
||||||
|
Configuration of the IP-MC-forwarding to the listening ports is done by managing the
|
||||||
|
forwarding tables of the switch, see [L2 learning](l2.md).
|
||||||
|
|
||||||
|
|
||||||
|
## IGMP API
|
||||||
|
The code currently provides the following functions:
|
||||||
|
```
|
||||||
|
void igmp_setup(void) __banked;
|
||||||
|
void igmp_enable(void) __banked;
|
||||||
|
void igmp_router_port_set(uint16_t pmask) __banked;
|
||||||
|
void igmp_packet_handler(void) __banked;
|
||||||
|
void igmp_show(void) __banked;
|
||||||
|
```c
|
||||||
|
`igmp_setup()` is called at boot-time and configures flooding of all IP-MC packets by
|
||||||
|
default, as otherwise no IP-MC would be possible in the network.
|
||||||
|
|
||||||
|
`igmp_enable()`starts IGMP which cause IGMP packets to be handled by the CPU and forwarding
|
||||||
|
of IP-MC packets to be limited to only subscribed ports.
|
||||||
|
|
||||||
|
`igmp_router_port_set()`configures forwarding ports for IGMP messages.
|
||||||
|
|
||||||
|
`igmp_packet_handler()` implements handling of trapped IGMP packets by the CPU.
|
||||||
|
|
||||||
|
`igmp_show()` prints out the IGMP configuration on the CLI.
|
||||||
|
|
||||||
|
|
||||||
|
## IGMP configuration on the Serial Console
|
||||||
|
For testing the following commands are provided on the serial console:
|
||||||
|
```
|
||||||
|
> igmp [on/off]
|
||||||
|
Enables or disables IGMP
|
||||||
|
|
||||||
|
> igmp show
|
||||||
|
Shows information on IGMP
|
||||||
|
```
|
||||||
|
|
||||||
|
## LAG configuration via the Web Interface
|
||||||
|
Not implemented, yet!
|
||||||
|
|
||||||
|
## A Test with IP-MC streaming using vlc
|
||||||
|
The following is a simple test verifying the IGMP and IP-MC switching capabilities.
|
||||||
|
|
||||||
|
You will need 2 Linux/Windows devices with a GUI plus a switch.
|
||||||
|
|
||||||
|
Connect the switch to an MC-aware router (e.g. to your home network). Connect the 2 Linux/Windows
|
||||||
|
devices to the switch. The connection to the router makes sure that Linux/Windows will send
|
||||||
|
out IGMP messages on the ports connected to the switch, which they will only do if they are aware
|
||||||
|
that there is a MC-aware router in the network. Make sure the 2 GUI devices are in the home network
|
||||||
|
(e.g. via DHCP).
|
||||||
|
|
||||||
|
Start streaming on one of the Linux/Windows machines:
|
||||||
|
```
|
||||||
|
$ vlc your_video.mp4 --sout="#std{access=udp, mux=ts, dst=239.255.0.1:8090}"
|
||||||
|
```
|
||||||
|
At this point you should see all switch ports flickering heavily as the MC stream is switched to all
|
||||||
|
switch ports, including flooding your home network. If you do not see any packets arriving at the switch,
|
||||||
|
you can force the output interface of vlc by using `--miface=<ifname>`
|
||||||
|
|
||||||
|
Enable IGMP on the switch-CLI:
|
||||||
|
```
|
||||||
|
> igmp on
|
||||||
|
```
|
||||||
|
The flickering should now stop on all ports except the port where the streaming device is connected:
|
||||||
|
the switch drops all IP-MC packets as there are no listeners.
|
||||||
|
|
||||||
|
Now, on the second Linux/Windows device start listening to the stream:
|
||||||
|
```
|
||||||
|
$ vlc udp://@239.255.0.1:8090
|
||||||
|
```
|
||||||
|
You should see the port-led of the port the displaying machine is connected to, to start flickering
|
||||||
|
and after some synchronization, the video should start playing.
|
||||||
|
|
||||||
|
Stopping vlc should also switching of the IP-MC frames to the listening device, i.e. the port-leds
|
||||||
|
should stop flickering.
|
||||||
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 83 KiB |
@@ -0,0 +1,227 @@
|
|||||||
|
# Link Aggregation (aka Trunking)
|
||||||
|
|
||||||
|
The RTL827x allows to combine multiple ports to a single logical link
|
||||||
|
(Link Aggregation / Trunking) according to IEEE 802.3ad. LAGs allow to
|
||||||
|
combine the individual physical links into a single link with the combined
|
||||||
|
throughput and automatic redundancy when one of the link fails.
|
||||||
|
Up to 4 Link Aggregation Groups (LAGs) can be defined on the switch devices.
|
||||||
|
|
||||||
|
## LAG control
|
||||||
|
Four registers `RTL837X_TRK_MBR_CTRL_BASE(lag) (0x4f38-0x4f44)` define the LAG membership
|
||||||
|
via a port mask of the logical port numbers.
|
||||||
|
|
||||||
|
A hash algorithm applied to L2, L3 and L4 properties of a packet are used to decide which
|
||||||
|
of the links (ports) is being used to transfer the packet. The possible properties used in the
|
||||||
|
hash are:
|
||||||
|
```
|
||||||
|
#define LAG_HASH_SOURCE_PORT_NUMBER 0x01
|
||||||
|
#define LAG_HASH_L2_SMAC 0x02
|
||||||
|
#define LAG_HASH_L2_DMAC 0x04
|
||||||
|
#define LAG_HASH_L3_SIP 0x08
|
||||||
|
#define LAG_HASH_L3_DIP 0x10
|
||||||
|
#define LAG_HASH_L4_SPORT 0x20
|
||||||
|
#define LAG_HASH_L4_DPORT 0x40
|
||||||
|
#define LAG_HASH_DEFAULT (LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC | LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT | LAG_HASH_L4_DPORT)
|
||||||
|
```
|
||||||
|
The hash algorithm used to select links (exit ports) is defined for each LAG individually in
|
||||||
|
`RTL837X_TRK_HASH_CTRL_BASE (0x4f48-0x4f54)`.
|
||||||
|
|
||||||
|
## Trunking API
|
||||||
|
The code currently provides the following functions:
|
||||||
|
```
|
||||||
|
/*
|
||||||
|
* Configure LAGs
|
||||||
|
* Sets the members via port bitmask of a given Link Aggregation Group
|
||||||
|
* The groups have numbers 0-3
|
||||||
|
* The bitmask represents up to 10 ports
|
||||||
|
* If currently no LAG has algorithm used, a default is applied
|
||||||
|
*/
|
||||||
|
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configures the hash algorithm used for a LAG
|
||||||
|
* lag is the Group to configure and hash is a bitmask
|
||||||
|
*/
|
||||||
|
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked;
|
||||||
|
```
|
||||||
|
|
||||||
|
## LAG configuration on the Serial Console
|
||||||
|
For testing the following commands are provided on the serial console:
|
||||||
|
```
|
||||||
|
> lag <LAG-ID> [p1] [p2]...
|
||||||
|
Create or set a LAG. Trunk-ID is 1 or 2. Ports are physical ports
|
||||||
|
If only the LAG-ID is given but no members, the LAG is deleted
|
||||||
|
|
||||||
|
> lag show
|
||||||
|
Shows information on all 4 lags
|
||||||
|
|
||||||
|
> laghash 0 [hash1] [hash2]...
|
||||||
|
Uses the given packet properties when hashing the packet to select the link
|
||||||
|
Names for the hashes are spa, smac, dmac, sip, dip, sport, dport
|
||||||
|
```
|
||||||
|
When a lag is creates, by default the hash is based on smac, dmac, sip, dip, sport, dport. When you
|
||||||
|
use your own hash settings, make sure that the hash always uses both the source and destination
|
||||||
|
property of the packet, as otherwise pakets will not be routed symmetrically.
|
||||||
|
|
||||||
|
## LAG configuration via the Web Interface
|
||||||
|
In the web-interface select Link Aggregation in the left navigation panel. The page will look like this:
|
||||||
|

|
||||||
|
Each of th 4 LAGs is configured separately. After the web-page has loaded, the current configuration
|
||||||
|
can be edited by clicking on the port-images to include that port or exclude it from a LAG.
|
||||||
|
When pressing on the Create/Update button, the LAG will be automatically created if not yet done, or
|
||||||
|
updated. If a lage is updated to not having any members, then it is effectively deleted.
|
||||||
|
|
||||||
|
All LAGs are created with the default hash-function (see above). This currently cannot be changed
|
||||||
|
from the Web.
|
||||||
|
|
||||||
|
## A Test using a single Linux Desktop
|
||||||
|
The following is a simple test using 2 RTL 2.5 GBit switches with at least 1 SFP+-port each. You
|
||||||
|
will also need 4 10GBit SFP+ modules (DAC or Fiber) and 2 SFP+ ports on your desktop.
|
||||||
|
|
||||||
|
The following shows the network configuration
|
||||||
|
```
|
||||||
|
----------------- -----------------
|
||||||
|
Linux Comuter | | 2.5 GBit | | same Linux Computer
|
||||||
|
---------- 10G | P1 |------------| P1 | 10G ----------
|
||||||
|
192.168.9.1 | SFP+ |==========| Switch 1 | 2.5 GBit | Switch 2 |==========| SFP+ | 192.168.9.2
|
||||||
|
enp1s0f0 ---------- | P2 |------------| P2 | ---------- enp1s0f1
|
||||||
|
| | | |
|
||||||
|
------------------ -----------------
|
||||||
|
```
|
||||||
|
|
||||||
|
On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes
|
||||||
|
source and destination ports into account, e.g. just use the default:
|
||||||
|
```
|
||||||
|
> lag 0 1 2
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The following shows the configuration on the desktop using a dual 10GBit card with 2 SFP+ modules:
|
||||||
|
```
|
||||||
|
[234690.755634] ixgbe: Intel(R) 10 Gigabit PCI Express Network Driver
|
||||||
|
[234690.755637] ixgbe: Copyright (c) 1999-2016 Intel Corporation.
|
||||||
|
[234690.921614] ixgbe 0000:01:00.0: Multiqueue Enabled: Rx Queue count = 12, Tx Queue count = 12 XDP Queue count = 0
|
||||||
|
[234690.921914] ixgbe 0000:01:00.0: 32.000 Gb/s available PCIe bandwidth (5.0 GT/s PCIe x8 link)
|
||||||
|
[234690.921999] ixgbe 0000:01:00.0: MAC: 2, PHY: 19, SFP+: 5, PBA No: FFFFFF-0FF
|
||||||
|
[234690.922002] ixgbe 0000:01:00.0: 28:41:c6:xx:xx:aa
|
||||||
|
[234690.924946] ixgbe 0000:01:00.0: Intel(R) 10 Gigabit Network Connection
|
||||||
|
[234690.990024] ixgbe 0000:01:00.0 enp1s0f0: renamed from eth0
|
||||||
|
[234691.056447] ixgbe 0000:01:00.0: registered PHC device on enp1s0f0
|
||||||
|
[234691.089417] ixgbe 0000:01:00.1: Multiqueue Enabled: Rx Queue count = 12, Tx Queue count = 12 XDP Queue count = 0
|
||||||
|
[234691.089706] ixgbe 0000:01:00.1: 32.000 Gb/s available PCIe bandwidth (5.0 GT/s PCIe x8 link)
|
||||||
|
[234691.089788] ixgbe 0000:01:00.1: MAC: 2, PHY: 19, SFP+: 18, PBA No: FFFFFF-0FF
|
||||||
|
[234691.089790] ixgbe 0000:01:00.1: 28:41:c6:xx:xx:ab
|
||||||
|
[234691.160997] ixgbe 0000:01:00.1: Intel(R) 10 Gigabit Network Connection
|
||||||
|
[234691.166102] ixgbe 0000:01:00.1 enp1s0f1: renamed from eth0
|
||||||
|
[234691.231579] ixgbe 0000:01:00.1: registered PHC device on enp1s0f1
|
||||||
|
[234691.236965] ixgbe 0000:01:00.0 enp1s0f0: detected SFP+: 5
|
||||||
|
[234691.485031] ixgbe 0000:01:00.0 enp1s0f0: NIC Link is Up 10 Gbps, Flow Control: RX/TX
|
||||||
|
[234691.557003] ixgbe 0000:01:00.1 enp1s0f1: detected SFP+: 18
|
||||||
|
[234691.753061] ixgbe 0000:01:00.1 enp1s0f1: NIC Link is Up 10 Gbps, Flow Control: RX/TX
|
||||||
|
```
|
||||||
|
|
||||||
|
Now set up 2 network namespaces and put each interface inside one:
|
||||||
|
```
|
||||||
|
sudo ip netns add netns_eth0
|
||||||
|
sudo ip netns add netns_eth1
|
||||||
|
sudo ip link set enp1s0f0 netns netns_eth0
|
||||||
|
sudo ip link set enp1s0f1 netns netns_eth1
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure network interface addresses 192.168.9.2 and 192.168.9.1 in each namespace:
|
||||||
|
```
|
||||||
|
sudo ip netns exec netns_eth0 ifconfig enp1s0f0 192.168.9.1 netmask 255.255.255.0
|
||||||
|
|
||||||
|
sudo ip netns exec netns_eth0 ip a
|
||||||
|
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
|
||||||
|
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||||
|
24: enp1s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||||
|
link/ether 28:41:c6:xx:xx:aa brd ff:ff:ff:ff:ff:ff
|
||||||
|
altname enx2841c6xxxxaa
|
||||||
|
inet 192.168.9.1/24 scope global enp1s0f0
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
inet6 fe80::2a41:c6ff:fexx:xxaa/64 scope link proto kernel_ll
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
|
||||||
|
sudo ip netns exec netns_eth1 ifconfig enp1s0f1 192.168.9.2 netmask 255.255.255.0
|
||||||
|
|
||||||
|
sudo ip netns exec netns_eth1 ip a
|
||||||
|
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
|
||||||
|
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||||
|
25: enp1s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||||
|
link/ether 28:41:c6:xx:xx:ab brd ff:ff:ff:ff:ff:ff
|
||||||
|
altname enx2841c6xxxxab
|
||||||
|
inet 192.168.9.2/24 scope global enp1s0f1
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
inet6 fe80::2a41:c6ff:fexx:xxab/64 scope link proto kernel_ll
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
```
|
||||||
|
Test is using ping. On both switches one of the 2.5Gbit links and all 10GBit links should show activity:
|
||||||
|
```
|
||||||
|
$ sudo ip netns exec netns_eth1 ping 192.168.9.1
|
||||||
|
PING 192.168.9.1 (192.168.9.1) 56(84) bytes of data.
|
||||||
|
64 bytes from 192.168.9.1: icmp_seq=1 ttl=64 time=0.082 ms
|
||||||
|
64 bytes from 192.168.9.1: icmp_seq=2 ttl=64 time=0.130 ms
|
||||||
|
^C
|
||||||
|
--- 192.168.9.1 ping statistics ---
|
||||||
|
2 packets transmitted, 2 received, 0% packet loss, time 1030ms
|
||||||
|
rtt min/avg/max/mdev = 0.082/0.106/0.130/0.024 ms
|
||||||
|
```
|
||||||
|
You can also verify that the redundancy works by unplugging the active link, the ping should continue
|
||||||
|
undisturbed with the other link now tranporting the pakets.
|
||||||
|
|
||||||
|
In 2 shells, start 2 instances of iperf, listening on 2 different ports. You will need to make sure that
|
||||||
|
the hash algorithm assigns different switch ports for the different port numbers. You can check this by
|
||||||
|
running the iperf3 client against each server instance and verify that different links show activity:
|
||||||
|
```
|
||||||
|
sudo ip netns exec netns_eth0 iperf3 -s
|
||||||
|
|
||||||
|
sudo ip netns exec netns_eth0 iperf3 -s -p 5333
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can run the clients in parallel:
|
||||||
|
```
|
||||||
|
$ sudo ip netns exec netns_eth1 iperf3 -c 192.168.9.1 & sudo ip netns exec netns_eth1 iperf3 -p 5333 -c 192.168.9.1
|
||||||
|
[1] 295484
|
||||||
|
Connecting to host 192.168.9.1, port 5201
|
||||||
|
[ 5] local 192.168.9.2 port 60996 connected to 192.168.9.1 port 5201
|
||||||
|
Connecting to host 192.168.9.1, port 5333
|
||||||
|
[ 5] local 192.168.9.2 port 39660 connected to 192.168.9.1 port 5333
|
||||||
|
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||||
|
[ 5] 0.00-1.00 sec 283 MBytes 2.37 Gbits/sec 485 272 KBytes
|
||||||
|
[ ID] Interval Transfer Bitrate Retr Cwnd
|
||||||
|
[ 5] 0.00-1.00 sec 283 MBytes 2.37 Gbits/sec 479 379 KBytes
|
||||||
|
[ 5] 1.00-2.00 sec 280 MBytes 2.35 Gbits/sec 444 260 KBytes
|
||||||
|
[ 5] 1.00-2.00 sec 280 MBytes 2.35 Gbits/sec 578 267 KBytes
|
||||||
|
[ 5] 2.00-3.00 sec 281 MBytes 2.36 Gbits/sec 385 263 KBytes
|
||||||
|
[ 5] 2.00-3.00 sec 280 MBytes 2.35 Gbits/sec 373 375 KBytes
|
||||||
|
[ 5] 3.00-4.00 sec 280 MBytes 2.35 Gbits/sec 430 385 KBytes
|
||||||
|
[ 5] 3.00-4.00 sec 280 MBytes 2.35 Gbits/sec 452 273 KBytes
|
||||||
|
[ 5] 4.00-5.00 sec 281 MBytes 2.36 Gbits/sec 319 256 KBytes
|
||||||
|
[ 5] 4.00-5.00 sec 281 MBytes 2.36 Gbits/sec 425 269 KBytes
|
||||||
|
[ 5] 5.00-6.00 sec 280 MBytes 2.35 Gbits/sec 364 264 KBytes
|
||||||
|
[ 5] 5.00-6.00 sec 281 MBytes 2.36 Gbits/sec 561 264 KBytes
|
||||||
|
[ 5] 6.00-7.00 sec 281 MBytes 2.35 Gbits/sec 446 255 KBytes
|
||||||
|
[ 5] 6.00-7.00 sec 280 MBytes 2.35 Gbits/sec 582 263 KBytes
|
||||||
|
[ 5] 7.00-8.00 sec 281 MBytes 2.35 Gbits/sec 494 263 KBytes
|
||||||
|
[ 5] 7.00-8.00 sec 280 MBytes 2.35 Gbits/sec 539 181 KBytes
|
||||||
|
[ 5] 8.00-9.00 sec 281 MBytes 2.36 Gbits/sec 617 389 KBytes
|
||||||
|
[ 5] 8.00-9.00 sec 280 MBytes 2.35 Gbits/sec 490 232 KBytes
|
||||||
|
[ 5] 9.00-10.00 sec 281 MBytes 2.35 Gbits/sec 363 215 KBytes
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
[ ID] Interval Transfer Bitrate Retr
|
||||||
|
[ 5] 0.00-10.00 sec 2.74 GBytes 2.36 Gbits/sec 4347 sender
|
||||||
|
[ 5] 0.00-10.00 sec 2.74 GBytes 2.35 Gbits/sec receiver
|
||||||
|
|
||||||
|
iperf Done.
|
||||||
|
[ 5] 9.00-10.00 sec 282 MBytes 2.36 Gbits/sec 536 380 KBytes
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
[ ID] Interval Transfer Bitrate Retr
|
||||||
|
[ 5] 0.00-10.00 sec 2.74 GBytes 2.36 Gbits/sec 5015 sender
|
||||||
|
[ 5] 0.00-10.00 sec 2.74 GBytes 2.35 Gbits/sec receiver
|
||||||
|
|
||||||
|
iperf Done.
|
||||||
|
[1]+ Done sudo ip netns exec netns_eth1 iperf3 -c 192.168.9.1
|
||||||
|
```
|
||||||
|
As you can see, the total throughput was 4.71 GBit/sec which is close to the
|
||||||
|
maximum possible with a single 5GBit link.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Modifications
|
||||||
|
|
||||||
|
## SPI-Flash Memory
|
||||||
|
|
||||||
|
SPI-Flash memory can be replaced with an other type. Because the chip is defect, like #69 & #70 or you have an unmanaged-switch with a small flash size, and want to convert it to a managed-variant to run `RTLPlayground` software on it. Currently `RTLPlayground`-firmware expects `8 MBit / 1 MiB`.
|
||||||
|
|
||||||
|
### Size
|
||||||
|
|
||||||
|
The SOC (RTL837x network chip) used 24-bit address to access the device. This means that in theory, a memory size up to `2^24 x 8-bit = 16777216 x 8-bit = 128 MBit or 16 MiB` could be used, this is *untested*!
|
||||||
|
|
||||||
|
### Speed
|
||||||
|
|
||||||
|
The SOC (RTL837x network chip) is connected via an SPI-BUS to the flash memory. SPI-BUS frequency is `62.5 MHz`.
|
||||||
|
Look in the datasheet for `AC Electrical Characteristics` and lookup symbol `Fr`. Maximum value should be equal or higher than `62.5 MHz`.
|
||||||
|
A device that supports the highest possible clock speed is not a better device, nor is the SOC going to run faster. So pick one which have common frequency between `80 MHz` to `133 MHz`.
|
||||||
|
Memory speed is dictated by the SPI-BUS clock frequency which is `62.5 MHz`.
|
||||||
|
|
||||||
|
### SPI Operation
|
||||||
|
|
||||||
|
By default, SPI-BUS uses `CLK`, `CS`, `DI` and `DO`. To increase the data throughput without increasing the bus frequency, a single command can run in `DUAL SPI operation`. This means that for a specific command `DI` and `DO` are both used to transfer the data to/from the device. So it makes the data transfer up-to twice as fast. Although the SOC datasheet doesn’t mention it, our software is making use of this mode.
|
||||||
|
|
||||||
|
### Package
|
||||||
|
|
||||||
|
Most use package are `SO8`-type may also called `SOIC8`-type. Which can also have different width. Like `150-mil`, `208-mil` or `300-mil`. Best to measure what you need and confirm the measurement with the device-datasheet.
|
||||||
|
|
||||||
|
### Specification
|
||||||
|
|
||||||
|
1. Size: At least `8 MBit / 1 MiB` (theoretic max. `128 MBit / 16 MiB`, but is not *tested*!)
|
||||||
|
2. Speed: `62.5 MHz` or better.
|
||||||
|
3. Support for `DUAL SPI operation`.
|
||||||
|
Device need support for command `BBh`, `Dual I/O Fast Read` or `Fast Read Dual I/O`.
|
||||||
|
|
||||||
|
### Known Working
|
||||||
|
|
||||||
|
This list is incomplete.
|
||||||
|
|
||||||
|
| Brand | Partnumber |
|
||||||
|
| ---------- |----------- |
|
||||||
|
| GigaDevice | GD25Q32E |
|
||||||
|
| Winbond | W25Q16JV |
|
||||||
|
| Winbond | W25Q32FV |
|
||||||
|
| Winbond | W25Q32JV |
|
||||||
|
| Winbond | W25Q16JL |
|
||||||
|
| Winbond | W25Q16DV |
|
||||||
|
| Winbond | W25Q80DV |
|
||||||
|
| Fundan | FM25Q16A |
|
||||||
|
|
||||||
|
*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,26 @@
|
|||||||
|
# Supported Hardware
|
||||||
|
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]
|
||||||
|
(https://github.com/up-n-atom/SWTG118AS)
|
||||||
|
|
||||||
|
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
|
||||||
|
devices usually just provide PoE on all ports without further configuration possibilitites.
|
||||||
|
|
||||||
|
The following forum also discusses this type of switches: [ServeTheHome](https://forums.servethehome.com/index.php?threads/horaco-2-5gbe-managed-switch-8-x-2-5gbe-1-10gb-sfp.41571/)
|
||||||
|
|
||||||
|
There are also 16-port unmanaged devices with RTL8272 SoCs, however these devices do not have
|
||||||
|
serial consoles and use 4 independent RTL8272 SoCs. No central control is provided by RTLPlayground,
|
||||||
|
even if it has been successfully demonstrated to install RTLPlayground to individual SoCs.
|
||||||
|
- [GigaPlus GP-S25-1602](https://www.servethehome.com/gigaplus-gp-s25-1602-review-a-cheap-16-port-2-5gbe-and-2-port-10g-switch/)
|
||||||
|
- [Vimin VM S251602P 16 Port 2.5G PoE Switch With 2x 10G SFP+](https://www.servethehome.com/vimin-vm-s251602p-16-port-2-5g-poe-switch-review-cyperf/vimin-vm-s251602p-16-port-2-5g-poe-switch-with-2x-10g-sfp-battery-2/)
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Trunking
|
|
||||||
|
|
||||||
The RTL827x allows to combine multiple ports to a single logical port
|
|
||||||
(trunking). Up to 2 trunk groups can be defined.
|
|
||||||
|
|
||||||
## Trunking control
|
|
||||||
Two registers RTL837x_TRUNK_CTRL_A (0x4f38) and RTL837x_TRUNK_CTRL_B (0x4f3c)
|
|
||||||
define the trunk groups. Each holds a bitmap of ports making up the trunk
|
|
||||||
group.
|
|
||||||
|
|
||||||
## Trunking API
|
|
||||||
The code currently provides the following functions:
|
|
||||||
```
|
|
||||||
void trunk_set(uint8_t group, uint16_t mask) __banked
|
|
||||||
```
|
|
||||||
|
|
||||||
# VLAN configuration on the Serial Console
|
|
||||||
For testing the following commands are provided on the serial console:
|
|
||||||
```
|
|
||||||
trunk <TRUNK-ID> [p1] [p2]...
|
|
||||||
create or set a trunk group. Trunk-ID is 1 or 2. ports a physical ports
|
|
||||||
|
|
||||||
trunk <VLAN-ID> d
|
|
||||||
deletes the trunk group
|
|
||||||
```
|
|
||||||
@@ -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,20 @@ 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.
|
||||||
|
|
||||||
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).
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/main.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>Ingress and Egress Bandwidth</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav id="sidebar"></nav>
|
||||||
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
|
<div id="ports"></div>
|
||||||
|
<h1>Ingress and Egress Bandwidth</h1>
|
||||||
|
<table id="bwtable">
|
||||||
|
<tr> <th> </th> <th colspan="3"> Ingress </th> <th colspan="2">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>
|
||||||
|
</table>
|
||||||
|
<script src="/bandwidth.js"></script>
|
||||||
|
</div>
|
||||||
|
<script src="/navigation.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
const iLayout = '" type="number" maxlength="10" size="10" onfocus="inputFocus(';
|
||||||
|
function createBW() {
|
||||||
|
var tbl = document.getElementById('bwtable');
|
||||||
|
const limit = '<input type="checkbox" id="limit_port" onchange="exec();">'
|
||||||
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
|
console.log("CREATING TABLE ", tbl.rows.length);
|
||||||
|
for (let i = 2; i < 2 + numPorts; i++) {
|
||||||
|
const tr = tbl.insertRow();
|
||||||
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = limit.replaceAll("limit_port", "ilimit_port_" + i).replace("exec()", "iClicked(" + i + ")");
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = 'UNLIMITED';
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = limit.replaceAll("limit_port", "fc_port_" + i).replace("exec()", "document.getElementById('bwapply_" + i + "').disabled=false;");
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = limit.replaceAll("limit_port", "elimit_port_" + i).replace("exec()", "eClicked(" + i + ")");
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = 'UNLIMITED';
|
||||||
|
var button = '<button type="button" id="bwapply_' + i + '" style="margin: 0 0 0 24px" onclick="applyBandwidth(' + i + ');">Apply</button>';
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = button;
|
||||||
|
document.getElementById("bwapply_" + i).disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function iClicked(i)
|
||||||
|
{
|
||||||
|
document.getElementById("bwapply_" + i).disabled=false;
|
||||||
|
var tbl = document.getElementById('bwtable');
|
||||||
|
var tr = tbl.rows[i];
|
||||||
|
if (!document.getElementById("ilimit_port_" + i).checked) {
|
||||||
|
tr.cells[2].innerHTML = "UNLIMITED";
|
||||||
|
document.getElementById("fc_port_" + i).disabled = true;
|
||||||
|
document.getElementById("fc_port_" + i).checked = true;
|
||||||
|
} else {
|
||||||
|
tr.cells[2].innerHTML = '<input id="ibw_' + i + iLayout + i + ')" value="0"/>';
|
||||||
|
document.getElementById("fc_port_" + i).disabled = false;
|
||||||
|
document.getElementById("fc_port_" + i).checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function eClicked(i)
|
||||||
|
{
|
||||||
|
document.getElementById("bwapply_" + i).disabled=false;
|
||||||
|
var tbl = document.getElementById('bwtable');
|
||||||
|
var tr = tbl.rows[i];
|
||||||
|
if (!document.getElementById("elimit_port_" + i).checked) {
|
||||||
|
tr.cells[5].innerHTML = "UNLIMITED";
|
||||||
|
} else {
|
||||||
|
tr.cells[5].innerHTML = '<input id="ebw_' + i + iLayout + i + ')" value="0"/>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputFocus(i)
|
||||||
|
{
|
||||||
|
document.getElementById("bwapply_" + i).disabled=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doCMD(cmd)
|
||||||
|
{
|
||||||
|
console.log("Sending >" + cmd + "<");
|
||||||
|
try {
|
||||||
|
const response = await fetch('/cmd', {
|
||||||
|
method: 'POST',
|
||||||
|
body: cmd
|
||||||
|
});
|
||||||
|
console.log('Completed!', response);
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyBandwidth(i) {
|
||||||
|
var tbl = document.getElementById('bwtable');
|
||||||
|
var tr = tbl.rows[i];
|
||||||
|
var cmd = "bw in " + (i-1) + " off";
|
||||||
|
if (document.getElementById("ilimit_port_" + i).checked)
|
||||||
|
cmd = 'bw in ' + (i-1) + ' ' + parseInt(document.getElementById("ibw_" + i).value).toString(16).padStart(4, "0");;
|
||||||
|
doCMD(cmd);
|
||||||
|
if (document.getElementById("ilimit_port_" + i).checked) {
|
||||||
|
if (!document.getElementById("fc_port_" + i).checked)
|
||||||
|
cmd = "bw in " + (i-1) + " drop";
|
||||||
|
doCMD(cmd);
|
||||||
|
}
|
||||||
|
var cmd = "bw out " + (i-1) + " off";
|
||||||
|
if (document.getElementById("elimit_port_" + i).checked)
|
||||||
|
cmd = 'bw out ' + (i-1) + ' ' + parseInt(document.getElementById("ebw_" + i).value).toString(16).padStart(4, "0");;
|
||||||
|
doCMD(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBW() {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
console.log("IN getBW ");
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
const s = JSON.parse(xhttp.responseText);
|
||||||
|
console.log("BW: ", JSON.stringify(s));
|
||||||
|
var tbl = document.getElementById('bwtable');
|
||||||
|
if (tbl.rows.length > 2 && numPorts) {
|
||||||
|
for (let i = 2; i < 2 + numPorts; i++) {
|
||||||
|
p = s[i-2];
|
||||||
|
let n = p.portNum;
|
||||||
|
let tr = tbl.rows[n+1];
|
||||||
|
if (!document.getElementById("bwapply_" + (n+1)).disabled)
|
||||||
|
continue;
|
||||||
|
console.log("Table Update row: " + i + " portNum is " + n + ", pState is " + pState[i-2] + ", row number is " + (n+1));
|
||||||
|
let iBW = parseInt(p.iBW,16) * 16; let eBW = parseInt(p.eBW,16) * 16;
|
||||||
|
document.getElementById("ilimit_port_" + (n+1)).checked = p.iLimited;
|
||||||
|
document.getElementById("elimit_port_" + (n+1)).checked = p.eLimited;
|
||||||
|
if (!p.iLimited) {
|
||||||
|
tr.cells[2].innerHTML = "UNLIMITED";
|
||||||
|
} else {
|
||||||
|
tr.cells[2].innerHTML = '<input id="ibw_' + (n+1) + iLayout + (n+1) + ')" value="' + iBW +'"/>';
|
||||||
|
}
|
||||||
|
if (!p.eLimited) {
|
||||||
|
tr.cells[5].innerHTML = "UNLIMITED";
|
||||||
|
} else {
|
||||||
|
tr.cells[5].innerHTML = '<input id="ebw_' + (n+1) + iLayout + (n+1) + ')" value="' + eBW +'"/>';
|
||||||
|
}
|
||||||
|
document.getElementById("fc_port_" + (n+1)).checked = p.iFC==1?true:false;
|
||||||
|
document.getElementById("fc_port_" + (n+1)).disabled = p.iLimited==1?false:true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/bandwidth.json", true);
|
||||||
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
createBW();
|
||||||
|
getBW();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
var configInterval = Number();
|
||||||
|
var configuration = [];
|
||||||
|
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}/,
|
||||||
|
/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)?)+/
|
||||||
|
];
|
||||||
|
const conf_overwrite = [
|
||||||
|
/ip/, /gw/, /netmask/, /eee\s+\w+/, /eee(\s+\w)/, /mirror/, /vlan\s+(\d{1,4})/
|
||||||
|
];
|
||||||
|
|
||||||
|
function parseConf(s){
|
||||||
|
var a = s.split(/\r\n|\n/);
|
||||||
|
for (var l = 0; l < a.length; l++) {
|
||||||
|
if (!a[l].length || a[l] == "\n" || a[l] == "\r\n")
|
||||||
|
continue;
|
||||||
|
console.log(l + ' --> ' + a[l]);
|
||||||
|
var ignore = true;
|
||||||
|
for (const x of conf_cmds)
|
||||||
|
if (x.test(a[l])) ignore = false;
|
||||||
|
if (ignore) continue;
|
||||||
|
for (const x of conf_overwrite) {
|
||||||
|
if (x.test(a[l])) {
|
||||||
|
console.log("Match ", x, " to ", a[l]);
|
||||||
|
m = a[l].match(x);
|
||||||
|
console.log("Starts with ", m[0]);
|
||||||
|
configuration = configuration.filter(item => !(item.startsWith(m[0])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configuration.push(a[l]);
|
||||||
|
}
|
||||||
|
console.log("Configuration now:");
|
||||||
|
for (const x of configuration) { console.log(x); }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchConfig() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/config');
|
||||||
|
console.log("CONFIG: ", response);
|
||||||
|
const t = await response.text();
|
||||||
|
return t;
|
||||||
|
} catch(err) {
|
||||||
|
console.error("Error: ", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchCmdLog() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/cmd_log');
|
||||||
|
console.log("CMD-Log: ", response);
|
||||||
|
const t = await response.text();
|
||||||
|
return t;
|
||||||
|
} catch(err) {
|
||||||
|
console.error("Error: ", err);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/ports.js"></script>
|
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>EEE Configuration</title>
|
<title>EEE Configuration</title>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
function createEEE() {
|
function createEEE() {
|
||||||
var tbl = document.getElementById('eeetable');
|
var tbl = document.getElementById('eeetable');
|
||||||
if (tbl.rows.length <= 2) {
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
console.log("CREATING TABLE ", tbl.rows.length);
|
console.log("CREATING TABLE ", tbl.rows.length);
|
||||||
for (let i = 2; i < 8; 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(`Port ${i-1}`));
|
||||||
@@ -20,8 +20,8 @@ function getEEE() {
|
|||||||
const s = JSON.parse(xhttp.responseText);
|
const s = JSON.parse(xhttp.responseText);
|
||||||
console.log("EEE: ", JSON.stringify(s));
|
console.log("EEE: ", JSON.stringify(s));
|
||||||
var tbl = document.getElementById('eeetable');
|
var tbl = document.getElementById('eeetable');
|
||||||
if (tbl.rows.length > 2) {
|
if (tbl.rows.length > 2 && numPorts) {
|
||||||
for (let i = 2; i < 8; i++) {
|
for (let i = 2; i < 2 + numPorts; i++) {
|
||||||
p = s[i-2];
|
p = s[i-2];
|
||||||
let n = p.portNum;
|
let n = p.portNum;
|
||||||
console.log("Table Update row: " + i + " portNum is " + n + ", pState is " + pState[i-2]);
|
console.log("Table Update row: " + i + " portNum is " + n + ", pState is " + pState[i-2]);
|
||||||
@@ -39,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() {
|
||||||
getEEE();
|
update( () => {
|
||||||
const iCount = setInterval(getEEE, 2000);
|
createEEE();
|
||||||
|
getEEE();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
const iCount = setInterval(getEEE, 2000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
const stat = setInterval(createEEE, 1000);
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/ports.js"></script>
|
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
<script src="/main_info.js"></script>
|
<script src="/main_info.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>FreeSwitchOS Main Page</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/main.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>FreeSwitchOS L2 Configuration</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav id="sidebar"></nav>
|
||||||
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
|
<div id="ports"></div>
|
||||||
|
<h1>L2 Configuration</h1>
|
||||||
|
<table id="l2table">
|
||||||
|
<tr> <th>Port</th> <th>MAC</th> <th>VLAN</th> <th>Type</th> <th>Remove Entry</th></tr>
|
||||||
|
<script src="/l2.js"></script>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script src="/navigation.js"></script>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
var l2GetInterval;
|
||||||
|
var l2Entries = [];
|
||||||
|
var l2CurrentEntry = 0;
|
||||||
|
|
||||||
|
function fillStats() {
|
||||||
|
var tbl = document.getElementById('statstable');
|
||||||
|
if (!numPorts)
|
||||||
|
return;
|
||||||
|
if (tbl.rows.length > 1) {
|
||||||
|
for (let i = 0; i < numPorts; i++) {
|
||||||
|
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 = `${txG[i]} pkts`;
|
||||||
|
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]} pkts`;
|
||||||
|
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]} pkts`;
|
||||||
|
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < numPorts; i++) {
|
||||||
|
console.log("Table row: " + i);
|
||||||
|
const tr = tbl.insertRow();
|
||||||
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`));
|
||||||
|
td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
|
||||||
|
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
|
||||||
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
|
||||||
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
|
||||||
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function l2CMP(a, b)
|
||||||
|
{
|
||||||
|
if (a.port < b.port)
|
||||||
|
return -1;
|
||||||
|
if (a.port > b.port)
|
||||||
|
return 1;
|
||||||
|
if (a.mac < b.mac)
|
||||||
|
return -1;
|
||||||
|
if (a.mac > b.mac)
|
||||||
|
return 1;
|
||||||
|
if (a.vlan < b.vlan)
|
||||||
|
return -1;
|
||||||
|
if (a.vlan > b.vlan)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniq(a) {
|
||||||
|
return a.filter(function(item, pos, ary) {
|
||||||
|
return !pos || item.idx != ary[pos - 1].idx;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function delL2(idx) {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
var s = JSON.parse(xhttp.responseText);
|
||||||
|
console.log("Entry deletion result: ", s.result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/l2_del.json?idx=" + idx, true);
|
||||||
|
xhttp.timeout = 1500; xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillL2(s)
|
||||||
|
{
|
||||||
|
var tbl = document.getElementById('l2table');
|
||||||
|
if (!s.length)
|
||||||
|
return;
|
||||||
|
s.sort(l2CMP);
|
||||||
|
s = uniq(s);
|
||||||
|
var s = s.map(function(e) { e.port = e.port != 9 ? e.port : "CPU"; return e; });
|
||||||
|
console.log("L2: ", JSON.stringify(s));
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
var e = s[i];
|
||||||
|
console.log(i, e);
|
||||||
|
if (tbl.rows[i+1]) {
|
||||||
|
tbl.rows[i+1].cells[0].innerHTML = `${e.port}`;
|
||||||
|
tbl.rows[i+1].cells[1].innerHTML = `${e.mac}`;
|
||||||
|
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>';
|
||||||
|
} else {
|
||||||
|
const tr = tbl.insertRow();
|
||||||
|
let td = tr.insertCell(); td.innerHTML = `${e.port}`;
|
||||||
|
td = tr.insertCell(); td.innerHTML = `${e.mac}`;
|
||||||
|
td = tr.insertCell(); td.innerHTML = `${e.vlan}`;
|
||||||
|
td = tr.insertCell(); td.innerHTML = `${e.type}`;
|
||||||
|
td = tr.insertCell(); td.innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">Delete</button>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = tbl.rows.length - 1; i > s.length; i--)
|
||||||
|
tbl.deleteRow(i);
|
||||||
|
l2Entries = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getL2() {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
var s = JSON.parse(xhttp.responseText);
|
||||||
|
var s = s.map(function(e) {
|
||||||
|
e.vlan = parseInt(e.vlan, 16);
|
||||||
|
e.idx = parseInt(e.idx, 16);
|
||||||
|
e.type = e.type == "s" ? "static" : "learned";
|
||||||
|
e.port = e.port == 9 ? 9 : logToPhysPort[e.port];
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
l2Entries.push(...s);
|
||||||
|
if (l2Entries >= 4096) {
|
||||||
|
l2Entries = [];
|
||||||
|
l2CurrentEntry = 0;
|
||||||
|
clearInterval(l2GetInterval);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var w = 0;
|
||||||
|
for (var i = l2Entries.length-1; i > 0; i--) {
|
||||||
|
if (l2Entries[0].idx == l2Entries[i].idx) {
|
||||||
|
w = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (w) {
|
||||||
|
l2CurrentEntry = 0;
|
||||||
|
fillL2(l2Entries);
|
||||||
|
} else {
|
||||||
|
l2CurrentEntry = s[s.length-1].idx + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
|
||||||
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
getL2();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
l2GetInterval = setInterval(getL2, 1000);
|
||||||
|
});;
|
||||||
|
});
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/main.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>Link Aggregation Configuration</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav id="sidebar"></nav>
|
||||||
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
|
<div id="ports"></div>
|
||||||
|
<h1>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>
|
||||||
|
<div id="mLAG0"></div>
|
||||||
|
<br />
|
||||||
|
<h2>LAG 2 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub1" onclick="lagSub(1);" type="button" value="Update / Create"></h2>
|
||||||
|
<div id="mLAG1"></div>
|
||||||
|
<br />
|
||||||
|
<h2>LAG 3 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub2" onclick="lagSub(2);" type="button" value="Update / Create"></h2>
|
||||||
|
<div id="mLAG2"></div>
|
||||||
|
<br />
|
||||||
|
<h2>LAG 4 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub3" onclick="lagSub(3);" type="button" value="Update / Create"></h2>
|
||||||
|
<div id="mLAG3"></div>
|
||||||
|
<script src="/lag.js"></script>
|
||||||
|
</div>
|
||||||
|
<script src="/navigation.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
var lagInterval = Number();
|
||||||
|
|
||||||
|
function lagForm() {
|
||||||
|
if (!numPorts)
|
||||||
|
return;
|
||||||
|
for (let j=0; j < 4; j++) {
|
||||||
|
var lag = "mLAG" + j
|
||||||
|
console.log("Adding LAG " + lag)
|
||||||
|
var m = document.getElementById(lag);
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
const d = document.createElement("div");
|
||||||
|
d.classList.add("cbgroup");
|
||||||
|
const l = document.createElement("label");
|
||||||
|
l.innerHTML = "" + i;
|
||||||
|
l.classList.add("cbgroup");
|
||||||
|
const inp = document.createElement("input");
|
||||||
|
inp.type = "checkbox"; inp.setAttribute("class","psel");
|
||||||
|
inp.id = "p_" + lag + "_" + i;
|
||||||
|
const o = document.createElement("img");
|
||||||
|
if (pIsSFP[i - 1]) {
|
||||||
|
o.src = "sfp.svg"; o.width ="60"; o.height ="60";
|
||||||
|
} else {
|
||||||
|
o.src = "port.svg"; o.width = "40"; o.height = "40";
|
||||||
|
}
|
||||||
|
l.appendChild(inp); l.appendChild(o);
|
||||||
|
d.appendChild(l)
|
||||||
|
m.appendChild(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchLag();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setL(p, c){
|
||||||
|
console.log("LAG setting: ", p, " to ", c);
|
||||||
|
document.getElementById(p).checked=c;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchLag() {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
const s = JSON.parse(xhttp.responseText);
|
||||||
|
console.log("LAG: ", JSON.stringify(s));
|
||||||
|
for (let l = 0; l < 4; l++) {
|
||||||
|
let members = parseInt(s[l].members, 2);
|
||||||
|
let hash = parseInt(s[l].hash, 16);
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
let p = i - 1;
|
||||||
|
if (numPorts < 9)
|
||||||
|
p = physToLogPort[p];
|
||||||
|
setL("p_mLAG"+l+"_"+i, members & (1<<p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", `/lag.json`, true);
|
||||||
|
sendXHTTP(xhttp);
|
||||||
|
}
|
||||||
|
async function lagSub(l) {
|
||||||
|
var cmd = "lag " + l;
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
if (document.getElementById("p_mLAG"+l+"_"+i).checked)
|
||||||
|
cmd = cmd + ` ${i}`;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch('/cmd', {
|
||||||
|
method: 'POST',
|
||||||
|
body: cmd
|
||||||
|
});
|
||||||
|
console.log('Completed!', response);
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
lagForm();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>RTL Switch Login</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script>
|
||||||
|
function removeNote() {
|
||||||
|
document.getElementById("incorrect").innerHTML = "";
|
||||||
|
}
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
if (document.referrer.endsWith("login.html"))
|
||||||
|
document.getElementById("incorrect").innerHTML = "Wrong password!";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="login_page">
|
||||||
|
<div class = "center">
|
||||||
|
<h1> RTL Switch Login</h1>
|
||||||
|
<form method="post" action="login">
|
||||||
|
<div class="txt_field">
|
||||||
|
<input name="pwd" type="password" onclick="removeNote()" required />
|
||||||
|
<span></span>
|
||||||
|
<label>Password</label>
|
||||||
|
</div>
|
||||||
|
<input type="submit" value="Login"/>
|
||||||
|
<h3 id="incorrect" style="margin-top: 5em;"></h3>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -2,14 +2,127 @@ 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", "No Link", "100M", "1000M", "NO", "NO", "2.5G"];
|
const linkS = ["Disabled", "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 numPorts = 0;
|
var numPorts = 0;
|
||||||
|
var logToPhysPort = new Int8Array(10);
|
||||||
|
var physToLogPort = new Int8Array(10);
|
||||||
|
var portNames = new Array(10);
|
||||||
|
var currentRequests = [];
|
||||||
|
var currentCallback;
|
||||||
|
function drawPorts() {
|
||||||
|
var f = document.getElementById('ports');
|
||||||
|
console.log("DRAWING PORTS: ", numPorts);
|
||||||
|
for (let i = 0; i < numPorts; i++) {
|
||||||
|
console.log("DRAWING isSFP: ", pIsSFP[i]);
|
||||||
|
const d = document.createElement("div");
|
||||||
|
d.classList.add('tooltip');
|
||||||
|
const s = document.createElement("span");
|
||||||
|
s.classList.add("tooltiptext");
|
||||||
|
s.innerHTML = "Tooltip text";
|
||||||
|
s.id="tt_" + (i+1);
|
||||||
|
const l = document.createElement("object");
|
||||||
|
d.appendChild(l);
|
||||||
|
d.appendChild(s);
|
||||||
|
l.type = "image/svg+xml";
|
||||||
|
if (!pIsSFP[i]) {
|
||||||
|
l.data = "port.svg";
|
||||||
|
l.width ="40";
|
||||||
|
l.height ="40";
|
||||||
|
} else {
|
||||||
|
l.data = "sfp.svg";
|
||||||
|
l.width = "60";
|
||||||
|
l.height = "60";
|
||||||
|
}
|
||||||
|
l.id="port" + (i+1);
|
||||||
|
f.appendChild(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
document.location = "/login.html"
|
||||||
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);
|
||||||
if (!numPorts) {
|
if (!numPorts) {
|
||||||
@@ -22,39 +135,150 @@ function update() {
|
|||||||
for (let i = 0; i < s.length; i++) {
|
for (let i = 0; i < s.length; i++) {
|
||||||
p = s[i];
|
p = s[i];
|
||||||
let n = p.portNum;
|
let n = p.portNum;
|
||||||
|
logToPhysPort[p.logPort] = n;
|
||||||
|
physToLogPort[n-1] = p.logPort;
|
||||||
|
portNames[p.logPort] = p.name;
|
||||||
let pid = "port" + n;
|
let pid = "port" + n;
|
||||||
|
let ttid = "tt_" + n;
|
||||||
n--;
|
n--;
|
||||||
txG[n] = BigInt(p.txG); txB[n] = BigInt(p.txB); rxG[n] = BigInt(p.rxG); rxB[n] = BigInt(p.rxB);
|
txG[n] = BigInt(p.txG); txB[n] = BigInt(p.txB); rxG[n] = BigInt(p.rxG); rxB[n] = BigInt(p.rxB);
|
||||||
var psvg = document.getElementById(pid);
|
var psvg = document.getElementById(pid);
|
||||||
|
var tt = document.getElementById(ttid);
|
||||||
if (psvg == null || !psvg.contentDocument)
|
if (psvg == null || !psvg.contentDocument)
|
||||||
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\">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;
|
||||||
|
iHTML += "<tr><td align=\"left\">Status</td><td>:</td><td>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 == 5) {
|
if (p.link == 4 || p.link == 5 || 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 == 2) {
|
} 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";
|
||||||
} else {
|
} else {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
iHTML += "<tr><td align=\"left\">Link speed</td><td>:</td><td>" + linkS[p.link + 1] + "</td></tr>";
|
||||||
|
if (p.isSFP) {
|
||||||
|
pAdvertised[n] = 0;
|
||||||
|
const hasExtendedStatus = p.sfp_options & 0x40;
|
||||||
|
iHTML += "<tr><td>Vendor</td><td>:</td><td>" + p.sfp_vendor + "</td></tr>";
|
||||||
|
iHTML += "<tr><td>Model</td><td>:</td><td>" + p.sfp_model + "</td></tr>";
|
||||||
|
iHTML += "<tr><td>Serial</td><td>:</td><td>" + p.sfp_serial + "</td></tr>";
|
||||||
|
if (hasExtendedStatus) {
|
||||||
|
let txPower = decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal);
|
||||||
|
let txPowerdBm = convertPowerTodBm(txPower);
|
||||||
|
let rxPower = decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal);
|
||||||
|
let rxPowerdBm = convertPowerTodBm(rxPower);
|
||||||
|
iHTML += "<tr><td>Temp</td><td>:</td><td>" + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + " ℃</td></tr>";
|
||||||
|
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + " V</td></tr>";
|
||||||
|
iHTML += "<tr><td>TX-Fault</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>";
|
||||||
|
iHTML += "<tr><td>TX-Disabled</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>";
|
||||||
|
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + " mA</td></tr>";
|
||||||
|
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + txPower.toFixed(3) + " mW / " + txPowerdBm.toFixed(2) + " dBm</td></tr>";
|
||||||
|
iHTML += "<tr><td>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>RX-LOS</td><td>:</td><td>${rxLosHTML(rx_los_pin, rx_los_module)}</td></tr>`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pAdvertised[n] = parseInt(p.adv, 2);
|
||||||
|
};
|
||||||
|
iHTML += "</table>";
|
||||||
|
tt.innerHTML = iHTML;
|
||||||
|
}}
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
}};
|
||||||
|
xhttp.open("GET", "/status.json", true);
|
||||||
|
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");
|
||||||
xhttp.open("GET", "/status.json", true);
|
return;
|
||||||
xhttp.timeout = 5000; xhttp.send();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,6 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/ports.js"></script>
|
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>Mirror Configuration</title>
|
<title>Mirror Configuration</title>
|
||||||
@@ -10,7 +9,7 @@
|
|||||||
<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>Mirror Configuration</h1>
|
||||||
<label class="tswitch">Enabled: <input id="me" type="checkbox"><span class="slider"></span></label><br/>
|
<label class="tswitch">Enabled: <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">Mirroring Port:</label> <input type="number" id="mp" name="mp" min="1" max="9"/>
|
||||||
<h2>Mirrored Ports (TX)</h2>
|
<h2>Mirrored Ports (TX)</h2>
|
||||||
<div id="mPortsTX"></div>
|
<div id="mPortsTX"></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();
|
||||||
@@ -49,11 +45,20 @@ function fetchMirror() {
|
|||||||
let m_tx = parseInt(s.mirror_tx, 2);
|
let m_tx = parseInt(s.mirror_tx, 2);
|
||||||
let m_rx = parseInt(s.mirror_rx, 2);
|
let m_rx = parseInt(s.mirror_rx, 2);
|
||||||
for (let i = 1; i <= numPorts; i++) {
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
setM("mPortsTX"+i, m_tx&1); setM("mPortsRX"+i, m_rx&1);
|
let p = i - 1;
|
||||||
m_tx = m_tx >> 1; m_rx = m_tx >> 1;
|
if (numPorts < 9)
|
||||||
|
p = physToLogPort[p];
|
||||||
|
setM("mPortsTX"+i, m_tx&(1<<p)); setM("mPortsRX"+i, m_rx&(1<<p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
document.getElementById('sidebar').innerHTML =
|
document.getElementById('sidebar').innerHTML =
|
||||||
"<ul><li><a href='index.html'>Overview</a></li>"
|
"<ul><li><a href='index.html'>Overview</a></li>"
|
||||||
|
+ "<li><a href='ports.html'>Port Configuration</a></li>"
|
||||||
+ "<li><a href='stat.html'>Port Statistics</a></li>"
|
+ "<li><a href='stat.html'>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='mirror.html'>Mirroring</a></li>"
|
+ "<li><a href='mirror.html'>Mirroring</a></li>"
|
||||||
+ "<li><a href='trunk.html'>Port Aggregation</a></li>"
|
+ "<li><a href='lag.html'>Link Aggregation</a></li>"
|
||||||
+ "<li><a href='eee.html'>EEE</a></li>"
|
+ "<li><a href='eee.html'>EEE</a></li>"
|
||||||
|
+ "<li><a href='bandwidth.html'>Bandwidth Limits</a></li>"
|
||||||
|
+ "<li><a href='system.html'>System Settings</a></li>"
|
||||||
+ "<li><a href='update.html'>Firmware Update</a></li></ul>";
|
+ "<li><a href='update.html'>Firmware Update</a></li></ul>";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/main.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>FreeSwitchOS Port Configuration</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav id="sidebar"></nav>
|
||||||
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
|
<div id="ports"></div>
|
||||||
|
<h1>Port Configuration</h1>
|
||||||
|
<form id="vform" action="/vlan.html">
|
||||||
|
<table id="speedtable">
|
||||||
|
<tr> <th>Port</th> <th>Name</th> <th>Current Link Speed</th><th>Set Speed</th><th>Disabled</th><th>Apply</th></tr>
|
||||||
|
</table>
|
||||||
|
<h2 style="margin-top:3em">Configure Maximum Frame Size (MTU) forwarded at Port</h2>
|
||||||
|
<table id="mtutable" style="margin-top:1em">
|
||||||
|
</table>
|
||||||
|
<script src="/ports.js"></script>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<script src="/navigation.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,21 +1,149 @@
|
|||||||
function drawPorts() {
|
var mtus = new Int16Array(10);
|
||||||
var f = document.getElementById('ports');
|
var clicked = new Int8Array(10);
|
||||||
console.log("DRAWING PORTS: ", numPorts);
|
function createPortTable() {
|
||||||
for (let i = 0; i < numPorts; i++) {
|
var tbl = document.getElementById('speedtable');
|
||||||
console.log("DRAWING isSFP: ", pIsSFP[i]);
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
const l = document.createElement("object");
|
const sSelect = '<select name="speed_sel" id="speed_sel">'
|
||||||
l.type = "image/svg+xml";
|
+ '<option value="auto">Auto</option>'
|
||||||
if (!pIsSFP[i]) {
|
+ '<option value="2g5">2500MBit/Full</option>'
|
||||||
l.data = "port.svg";
|
+ '<option value="1g">1000MBit/Full</option>'
|
||||||
l.width ="40";
|
+ '<option value="100m full">100MBit/Full</option>'
|
||||||
l.height ="40";
|
+ '<option value="100m half">100MBit/Half</option>'
|
||||||
} else {
|
+ '<option value="10m full">10MBit/Full</option>'
|
||||||
l.data = "sfp.svg";
|
+ '<option value="10m half">10MBit/Half</option>'
|
||||||
l.width = "60";
|
+ '</select>';
|
||||||
l.height = "60";
|
const dSwitch = '<input type="checkbox" id="disable_port" onchange="portOnOff();">'
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
if (pIsSFP[i-1])
|
||||||
|
continue;
|
||||||
|
console.log("Table row: " + i + "pState: " + pState[i-2]);
|
||||||
|
const tr = tbl.insertRow();
|
||||||
|
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i}`));
|
||||||
|
let portName = portNames[physToLogPort[i-1]] || '';
|
||||||
|
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
|
||||||
|
td = tr.insertCell(); td.innerHTML = linkS[pState[i] + 1];
|
||||||
|
td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i);
|
||||||
|
td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i)
|
||||||
|
.replace("portOnOff()", "portOnOff(" + i + ")");
|
||||||
|
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="applySpeed(' + i + ');">Apply</button>';
|
||||||
|
td = tr.insertCell();
|
||||||
|
td.innerHTML = button;
|
||||||
}
|
}
|
||||||
l.id="port" + (i+1);
|
|
||||||
f.appendChild(l);
|
|
||||||
}
|
}
|
||||||
console.log("DRAWING DONE ");
|
tbl = document.getElementById('mtutable');
|
||||||
|
if (tbl.rows.length <= 2 && numPorts) {
|
||||||
|
const mSelect = '<select name="mtu_sel" id="mtu_sel">'
|
||||||
|
+ '<option value="16383">16383</option>'
|
||||||
|
+ '<option value="1522">1522</option>'
|
||||||
|
+ '<option value="1536">1536</option>'
|
||||||
|
+ '<option value="1552">1552</option>'
|
||||||
|
+ '<option value="9216">9216</option>'
|
||||||
|
+ '</select>';
|
||||||
|
var tr = tbl.insertRow();
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
let td = tr.insertCell();
|
||||||
|
if (pIsSFP[i-1])
|
||||||
|
td.innerHTML = '<object type="image/svg+xml" data="sfp.svg" width="60"></object>'
|
||||||
|
else
|
||||||
|
td.innerHTML = '<object type="image/svg+xml" data="port.svg" width="40"></object>'
|
||||||
|
}
|
||||||
|
tr = tbl.insertRow();
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
let td = tr.insertCell();
|
||||||
|
td.innerHTML = mSelect.replaceAll("mtu_sel", "mtu_sel_" + i);
|
||||||
|
}
|
||||||
|
tr = tbl.insertRow();
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
let td = tr.insertCell();
|
||||||
|
td.innerHTML = '<button type="button" style="margin: 0 0 0 24px" onclick="applyMTU(' + i + ');">Apply</button>';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePortTable() {
|
||||||
|
console.log("updatePortTable called");
|
||||||
|
var tbl = document.getElementById('speedtable');
|
||||||
|
if (tbl.rows.length <= 2 || !numPorts)
|
||||||
|
return;
|
||||||
|
for (let i = 1; i <= numPorts ; i++) {
|
||||||
|
if (pIsSFP[i-1])
|
||||||
|
continue;
|
||||||
|
tbl.rows[i].cells[2].innerHTML = `${linkS[pState[i-1]+1]}`;
|
||||||
|
if (!clicked[i] && pState[i - 1] < 0) {
|
||||||
|
document.getElementById('speed_sel_' + i).disabled = true;
|
||||||
|
document.getElementById('disable_port_' + i).checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applySpeed(port) {
|
||||||
|
var speed = document.getElementById('speed_sel_' + port).value;
|
||||||
|
var disabled = document.getElementById('disable_port_' + port).checked;
|
||||||
|
var cmd = "port " + port + " ";
|
||||||
|
if (!disabled)
|
||||||
|
cmd = cmd + speed;
|
||||||
|
else
|
||||||
|
cmd = cmd + "off";
|
||||||
|
console.log("CMD: " + cmd);
|
||||||
|
try {
|
||||||
|
const response = await fetch('/cmd', {
|
||||||
|
method: 'POST',
|
||||||
|
body: cmd
|
||||||
|
});
|
||||||
|
console.log('Completed!', response);
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function portOnOff(p) {
|
||||||
|
var disabled = document.getElementById('disable_port_' + p).checked;
|
||||||
|
document.getElementById('speed_sel_' + p).disabled = disabled;
|
||||||
|
clicked[p] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyMTU(port) {
|
||||||
|
var mtu = document.getElementById('mtu_sel_' + port).value;
|
||||||
|
var cmd = "mtu " + port + " " + mtu;
|
||||||
|
try {
|
||||||
|
const response = await fetch('/cmd', {
|
||||||
|
method: 'POST',
|
||||||
|
body: cmd
|
||||||
|
});
|
||||||
|
console.log('MTU Completed!', response);
|
||||||
|
getMTUs();
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMTUs() {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
const s = JSON.parse(xhttp.responseText);
|
||||||
|
console.log("MTUS: ", JSON.stringify(s));
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
p = s[i];
|
||||||
|
let n = p.portNum;
|
||||||
|
mtus[n] = parseInt(p.mtu, 16);
|
||||||
|
var mtu = document.getElementById('mtu_sel_' + n);
|
||||||
|
if (!mtu)
|
||||||
|
continue;
|
||||||
|
mtu.value = mtus[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/mtu.json", true);
|
||||||
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
createPortTable();
|
||||||
|
updatePortTable();
|
||||||
|
getMTUs()
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
const updatePortTableInterval = setInterval(updatePortTable, 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,17 +1,44 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/ports.js"></script>
|
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>FreeSwitchOS Port Statistics</title>
|
<title>FreeSwitchOS Port Statistics</title>
|
||||||
|
<style>
|
||||||
|
.popup {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: 100%; height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.popup-content {
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
height: 80%
|
||||||
|
}
|
||||||
|
.popup .popup-content {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</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>
|
||||||
|
<div id="popup" class="popup">
|
||||||
|
<div class="popup-content">
|
||||||
|
<h2>Detailed Port Statistics</h2>
|
||||||
|
<div id="popup_text"></div>
|
||||||
|
<button id="closePopup" class="action">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<h1>Port Statistics</h1>
|
<h1>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> </tr>
|
<tr> <th>Port</th> <th>Name</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>
|
||||||
<script src="/stat.js"></script>
|
<script src="/stat.js"></script>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,26 +1,207 @@
|
|||||||
|
const mib_counters = [
|
||||||
|
"Interface in Octets", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface out Octets", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface in Unicast Pkts", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface in Multicast Pkts", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface in Broadcast Pkts", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface out Unicast Pkts", 8, // 10
|
||||||
|
"", 0,
|
||||||
|
"Interface out Multicast Pkts", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface out Broadcast Pkts", 8,
|
||||||
|
"", 0,
|
||||||
|
"Interface out discards", 4,
|
||||||
|
"802.1d Tp Port in discards", 4,
|
||||||
|
"802.3 Single collision frames", 4,
|
||||||
|
"802.3 Multi collision frames", 4,
|
||||||
|
"802.3 Deferred transmissions", 4, // 20
|
||||||
|
"802.3 Late collisions", 4,
|
||||||
|
"802.3 Excessive collisions", 4,
|
||||||
|
"802.3 Symbol errors", 4,
|
||||||
|
"802.3 Control in unknown opcodes", 4,
|
||||||
|
"802.3 In Pause frames", 4,
|
||||||
|
"802.3 Out Pause frames", 4,
|
||||||
|
"Ether drop events", 4,
|
||||||
|
"TX Ether Broadcast Pkts", 4,
|
||||||
|
"TX Ether Multicast Pkts", 4,
|
||||||
|
"TX Ether CRC Align errors", 4, // 30
|
||||||
|
"RX Ether CRC Align errors", 4,
|
||||||
|
"TX Ether Undersized Pkts", 4,
|
||||||
|
"RX Ether Undersized Pkts", 4,
|
||||||
|
"TX Ether Oversized Pkts", 4,
|
||||||
|
"RX Ether Oversized Pkts", 4,
|
||||||
|
"TX Ether Fragments", 4,
|
||||||
|
"RX Ether fragments", 4,
|
||||||
|
"TX Ether Jabbers", 4,
|
||||||
|
"RX Ether Jabbers", 4,
|
||||||
|
"TX Ether Collisions", 4, // 40
|
||||||
|
"TX Ether Pkts 640 Octets", 4,
|
||||||
|
"RX Ether Pkts 640 Octets", 4,
|
||||||
|
"TX Ether 65-127 Octets", 4,
|
||||||
|
"RX Ether 65-127 Octets", 4,
|
||||||
|
"TX Ether Pkts 128-255 Octets", 4,
|
||||||
|
"RX Ether Pkts 128-255 Octets", 4,
|
||||||
|
"TX Ether Pkts 256-511 Octets", 4,
|
||||||
|
"RX Ether Pkts 256-511 Octets", 4,
|
||||||
|
"TX Ether Pkts 512-1023 Octets", 4,
|
||||||
|
"RX Ether Pkts 512-1023 Octets", 4, // 50
|
||||||
|
"TX Ether Pkts 1024-1518 Octets", 4,
|
||||||
|
"RX Ether Pkts 1024-1518 Octets", 4,
|
||||||
|
"", 4,
|
||||||
|
"RX Ether Undersized Drop Pkts", 4, // 54
|
||||||
|
"TX Ether Pkts >1518 Octets", 4,
|
||||||
|
"RX Ether Pkts >1518 Octets", 4,
|
||||||
|
"TX Ether Pkts too large", 4,
|
||||||
|
"RX Ether Pkts too large", 4,
|
||||||
|
"TX Ether Flexible Octets Set 1", 4,
|
||||||
|
"RX Ether Flexible Octets Set 1", 4,// 60
|
||||||
|
"TX Ether Flexible Octets CRC Set 1", 4,
|
||||||
|
"RX Ether Flexible Octets CRC Set 1", 4,
|
||||||
|
"TX Ether Flexible Octets Set 0", 4,
|
||||||
|
"RX Ether Flexible Octets Set 0", 4,
|
||||||
|
"TX Ether Flexible Octets CRC Set 0", 4,
|
||||||
|
"RX Ether Flexible Octets CRC Set 0", 4,
|
||||||
|
"Lenth Field Errors", 4,
|
||||||
|
"False Carriers", 4,
|
||||||
|
"Undersized Octets", 4,
|
||||||
|
"Framing Errors", 4, // 70
|
||||||
|
"", 4,
|
||||||
|
"RX MAC Discards", 4, // 72
|
||||||
|
"RX MAC IPG Short Drop", 4,
|
||||||
|
"", 4,
|
||||||
|
"802.1d TP Learned Entry Discards", 4, // 75
|
||||||
|
"Egress Queue 7 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 6 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 5 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 4 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 3 Dropped Pkts", 4, // 80
|
||||||
|
"Egress Queue 2 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 1 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 0 Dropped Pkts", 4,
|
||||||
|
"Egress Queue 7 Out Pkts", 4,
|
||||||
|
"Egress Queue 6 Out Pkts", 4,
|
||||||
|
"Egress Queue 5 Out Pkts", 4,
|
||||||
|
"Egress Queue 4 Out Pkts", 4,
|
||||||
|
"Egress Queue 3 Out Pkts", 4,
|
||||||
|
"Egress Queue 2 Out Pkts", 4,
|
||||||
|
"Egress Queue 1 Out Pkts", 4, // 90
|
||||||
|
"Egress Queue 0 Out Pkts", 4,
|
||||||
|
"TX Good Counter", 8,
|
||||||
|
"", 0,
|
||||||
|
"RX Good Counter", 8,
|
||||||
|
"", 0,
|
||||||
|
"RX Error Counter", 4,
|
||||||
|
"TX Error Counter", 4,
|
||||||
|
"TX Good Counter PHY", 8,
|
||||||
|
"", 0,
|
||||||
|
"RX Good Counter PHY", 8, // 100
|
||||||
|
"", 0,
|
||||||
|
"RX Error Counter PHY", 4,
|
||||||
|
"TX Error Counter PHY", 4
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
function getCounters(port) {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
const popup = document.getElementById('popup');
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
const s = JSON.parse(xhttp.responseText);
|
||||||
|
console.log("Counters: ", JSON.stringify(s));
|
||||||
|
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>";
|
||||||
|
console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length);
|
||||||
|
var c = 0;
|
||||||
|
for (i = 0; i < mib_counters.length; i += 4) {
|
||||||
|
console.log(i, " ", mib_counters[i], ": ", mib_counters[i+1]);
|
||||||
|
if (mib_counters[i] == "" && mib_counters[i + 1] == 8) {
|
||||||
|
console.log("c " + i + ": continue");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var count = BigInt(s[i/4]);
|
||||||
|
if (mib_counters[i+1] == 8) {
|
||||||
|
t += "<td>" + mib_counters[i] + "</td><td>" + count.toString() + "</td>";
|
||||||
|
c += 1;
|
||||||
|
} else if (mib_counters[i+1] == 4) {
|
||||||
|
if (mib_counters[i] != "") {
|
||||||
|
t += "<td>" + mib_counters[i] + "</td><td>" + (count >> 32n).toString() + "</td>";
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
if (c == 2) {
|
||||||
|
t += "</tr> <tr>";
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
if (mib_counters[i+2] != "") {
|
||||||
|
t += "<td>" + mib_counters[i+2] + "</td><td>" + (count & 4294967295n).toString() + "</td>";
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 2) {
|
||||||
|
t += "</tr> <tr>";
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptext.innerHTML = t + "</tr></table>";
|
||||||
|
popup.style.display = 'flex';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/counters.json?port=" + port, true);
|
||||||
|
xhttp.timeout = 1500; sendXHTTP(xhttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function fillStats() {
|
function fillStats() {
|
||||||
var tbl = document.getElementById('statstable');
|
var tbl = document.getElementById('statstable');
|
||||||
|
if (!numPorts)
|
||||||
|
return;
|
||||||
if (tbl.rows.length > 1) {
|
if (tbl.rows.length > 1) {
|
||||||
for (let i = 0; i < 6; 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 = `${linkS[pState[i]+1]}`;
|
||||||
tbl.rows[i+1].cells[2].innerHTML = `${txG[i]} pkts`;
|
tbl.rows[i+1].cells[3].innerHTML = `${txG[i]} pkts`;
|
||||||
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]} pkts`;
|
tbl.rows[i+1].cells[4].innerHTML = `${txB[i]} pkts`;
|
||||||
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]} pkts`;
|
tbl.rows[i+1].cells[5].innerHTML = `${rxG[i]} pkts`;
|
||||||
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`;
|
tbl.rows[i+1].cells[6].innerHTML = `${rxB[i]} pkts`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < 6; 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(`Port ${i+1}`));
|
||||||
|
let portName = portNames[physToLogPort[i]] || '';
|
||||||
|
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
|
||||||
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
|
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
|
||||||
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
|
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
|
||||||
|
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + i + ');">Show</button>';
|
||||||
|
td = tr.insertCell(); td.innerHTML = button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stat = setInterval(fillStats, 1000);
|
const popup = document.getElementById('popup');
|
||||||
|
const closePopup = document.getElementById('closePopup');
|
||||||
|
closePopup.addEventListener('click', () => {
|
||||||
|
popup.style.display = 'none';
|
||||||
|
});
|
||||||
|
window.addEventListener('click', (event) => {
|
||||||
|
if (event.target === popup) {
|
||||||
|
popup.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
update();
|
||||||
|
fillStats();
|
||||||
|
const stat = setInterval(fillStats, 1000);
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
h1, h2 {
|
h1, h2, h3 {
|
||||||
color: #226;
|
color: #226;
|
||||||
}
|
}
|
||||||
ul {
|
ul {
|
||||||
@@ -6,8 +6,9 @@ ul {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 12%;
|
width: 12%;
|
||||||
height: 100%;
|
height: calc(100% - 50px);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
top: 50px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ li a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
table, th, td {
|
table, th, td {
|
||||||
border: 1px solid navy;
|
border: 1px solid #226;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
@@ -38,10 +39,17 @@ td {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=submit] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;}
|
input[type=submit] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;border-radius: 15px;width: 100%;}
|
||||||
input[type=submit]:hover { background-color: #226; color: white;}
|
input[type=submit]:hover { background-color: #226; color: white;}
|
||||||
button {padding: 8px; background-color:#99f; color:#000;}
|
input[type=file] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;border-radius: 15px;width: 60%;}
|
||||||
|
input[type=file]:hover { background-color: #226; color: white;}
|
||||||
|
b
|
||||||
|
button {padding: 8px; background-color:#99f; color:#000;border-radius: 15px;}
|
||||||
button:hover { background-color: #226; color: white;}
|
button:hover { background-color: #226; color: white;}
|
||||||
|
.action{padding: 8px 16px;margin-top: 2em;margin-right: 3em; background-color: #aaf;color: #000;border-radius: 15px; width: 100%;}
|
||||||
|
.action:hover { background-color: #226; color: white;}
|
||||||
|
|
||||||
|
/* Port selection inputs */
|
||||||
.psel {
|
.psel {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -58,7 +66,7 @@ button:hover { background-color: #226; color: white;}
|
|||||||
/* outline: 2px solid #f00;*/
|
/* outline: 2px solid #f00;*/
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
object {
|
object, img {
|
||||||
margin: 0.5em 0.5em;
|
margin: 0.5em 0.5em;
|
||||||
}
|
}
|
||||||
.cbgroup {
|
.cbgroup {
|
||||||
@@ -73,4 +81,85 @@ object {
|
|||||||
.isSFP{ opacity: .4; background-color: #660;}
|
.isSFP{ opacity: .4; background-color: #660;}
|
||||||
.isNOK{ color: #900;}
|
.isNOK{ color: #900;}
|
||||||
.isOK{ color: #090;}
|
.isOK{ color: #090;}
|
||||||
.action{padding: 8px 16px;margin-top: 2em;margin-right: 3em; background-color: #aaf;color: #000;}
|
.ip{padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
|
||||||
|
.row {display: flex;}
|
||||||
|
.rcol {flex: 90%;}
|
||||||
|
.lcol {flex: 10%;}
|
||||||
|
|
||||||
|
/* Login page */
|
||||||
|
.login_page {margin: 0; padding: 0; background: #aaf; height: 100vh; overflow: hidden;}
|
||||||
|
.center{
|
||||||
|
position: absolute; top: 50%; left: 50%;
|
||||||
|
transform: translate(-50%, -40% );
|
||||||
|
width: 500px; height: 400px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center h1 {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center form {
|
||||||
|
padding: 0 60px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
form .txt_field{
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 2px solid #adadad;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
.txt_field input { width: 100%; padding: 0 5px; height: 40px; font-size: 16px; border: none;
|
||||||
|
background: none;
|
||||||
|
outline: none;}
|
||||||
|
.txt_field label { position: absolute; top: 50%; left: 5px; color:#adadad; transform: translateY(-50%);
|
||||||
|
font-size: 16px; pointer-events: none;transition: .5s; }
|
||||||
|
.txt_field span::before{ content:''; position: absolute; top: 40px; left:0; width: 100%; height: 2px; background: #aaf;}
|
||||||
|
.txt_field input:focus ~ label,
|
||||||
|
.txt_field input:valid ~ label { top: -5px; color: #aaf; }
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
position: relative; display: inline-block; cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tooltiptext {
|
||||||
|
visibility: hidden;
|
||||||
|
width: 260px;
|
||||||
|
background-color: #226;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px 0;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 80%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltiptext::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-width: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: transparent transparent black transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tooltip:hover .tooltiptext {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.tt_table {
|
||||||
|
width: 100%; font-size:90%;
|
||||||
|
}
|
||||||
|
.tt_table td {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
select { text-align-last: right; font-family: monospace}
|
||||||
|
option { direction: rtl; font-family: sans-serif}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>System Settings</title>
|
||||||
|
<style>
|
||||||
|
.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:hover { background-color: #aaf; }
|
||||||
|
.tab-btn.active { background-color: #aaf; font-weight: bold; border-bottom: 2px solid #aaf; margin-bottom: -2px; }
|
||||||
|
.tab-content { display: none; }
|
||||||
|
.tab-content.active { display: block; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="tab-bar">
|
||||||
|
<button class="tab-btn active" onclick="openTab(event, 'system-tab')">System</button>
|
||||||
|
<button class="tab-btn" onclick="openTab(event, 'advanced-tab')">Advanced</button>
|
||||||
|
</div>
|
||||||
|
<nav id="sidebar"></nav>
|
||||||
|
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||||
|
<div id="ports"></div>
|
||||||
|
|
||||||
|
<div id="system-tab" class="tab-content active">
|
||||||
|
<h1>System Settings</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="lcol"> <label for="ip">IP address:</label></div>
|
||||||
|
<div class="rcol"> <input id="ip" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="lcol"> <label for="netmask">Netmask:</label></div>
|
||||||
|
<div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="lcol"> <label for="gw">Gateway:</label></div>
|
||||||
|
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
When updating the above settings, remember to point your browser to the new IP afterwards:<br/>
|
||||||
|
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" value="Update Settings"><br/>
|
||||||
|
<br/>
|
||||||
|
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 id="advanced-tab" class="tab-content">
|
||||||
|
<h1>Advanced Settings</h1>
|
||||||
|
<div class="lcol"> <label for="config_display">Startup configuration:</label></div>
|
||||||
|
<textarea id="config_display" rows="8" cols="60"></textarea>
|
||||||
|
<br/><br/>
|
||||||
|
Be careful when saving the directly edited startup configuration, you can lock yourself out:<br/>
|
||||||
|
<input style="width:40%;" class="action" id="clear_config" onclick="clearConfig();" type="button" value="Clear Startup Config">
|
||||||
|
<br/>
|
||||||
|
<input style="width:40%;" class="action" id="flash_startup_sub" onclick="flashStartupSave();" type="button" value="Save Startup Settings to Flash">
|
||||||
|
<br/>
|
||||||
|
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" value="Reset Switch">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script src="/config.js"></script>
|
||||||
|
<script src="/system.js"></script>
|
||||||
|
<script src="/navigation.js"></script>
|
||||||
|
<script>
|
||||||
|
function openTab(evt, tabId) {
|
||||||
|
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||||||
|
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||||
|
document.getElementById(tabId).classList.add('active');
|
||||||
|
evt.currentTarget.classList.add('active');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
var systemInterval = Number();
|
||||||
|
const ips = ["ip", "netmask", "gw"];
|
||||||
|
|
||||||
|
function checkIp(ip) {
|
||||||
|
const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||||
|
if (!ipv4.test(ip)) {alert(`Invalid ip:${ip}`); return false };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ipSub() {
|
||||||
|
for (let i=0;i<3;i++) {
|
||||||
|
if (!checkIp(document.getElementById(ips[i]).value))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i=0; i<3;i++){
|
||||||
|
var cmd = ips[i]+' '+document.getElementById(ips[i]).value;
|
||||||
|
try {
|
||||||
|
const response = await fetch('/cmd', {
|
||||||
|
method: 'POST',
|
||||||
|
body: cmd
|
||||||
|
});
|
||||||
|
console.log('Completed!', response);
|
||||||
|
fetchIP();
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendConfig(c) {
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("MAX_FILE_SIZE", "4096");
|
||||||
|
form.append("configuration", new Blob([c], {type: "application/octet-stream"}));
|
||||||
|
try {
|
||||||
|
const response = await fetch('/config', {
|
||||||
|
method: 'POST',
|
||||||
|
body: form
|
||||||
|
});
|
||||||
|
console.log('Completed!', response);
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function flashSave() {
|
||||||
|
fetchConfig().then((s) => {
|
||||||
|
parseConf(s);
|
||||||
|
fetchCmdLog().then((s) => {
|
||||||
|
parseConf(s);
|
||||||
|
var body = "";
|
||||||
|
for (const x of configuration) { body = body + x + "\n"; }
|
||||||
|
console.log("CONFIGURATION to save: ", body);
|
||||||
|
sendConfig(body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
fetchIP();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function flashStartupSave() {
|
||||||
|
var configContent = document.getElementById("config_display").value;
|
||||||
|
console.log("CONFIGURATION to save: ", configContent);
|
||||||
|
sendConfig(configContent);
|
||||||
|
// Clear the command log 1 second after initiating the config save
|
||||||
|
setTimeout(() => {
|
||||||
|
fetch('/cmd_log_clear', { method: 'GET' })
|
||||||
|
.then(response => console.log('Command log cleared', response))
|
||||||
|
.catch(err => console.error('Error clearing command log:', err));
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearConfig() {
|
||||||
|
document.getElementById("config_display").value = "";
|
||||||
|
|
||||||
|
// Validate and populate with current IP settings
|
||||||
|
for (let i=0; i<3; i++) {
|
||||||
|
if (!checkIp(document.getElementById(ips[i]).value))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var configLines = "";
|
||||||
|
for (let i=0; i<3; i++){
|
||||||
|
var cmd = ips[i]+' '+document.getElementById(ips[i]).value;
|
||||||
|
configLines += cmd + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("config_display").value = configLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchIP() {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
const s = JSON.parse(xhttp.responseText);
|
||||||
|
console.log("IP: ", s);
|
||||||
|
document.getElementById("ip").value=s.ip_address;
|
||||||
|
document.getElementById("netmask").value=s.ip_netmask;
|
||||||
|
document.getElementById("gw").value=s.ip_gateway;
|
||||||
|
clearInterval(systemInterval);
|
||||||
|
// Fetch and populate the config textbox
|
||||||
|
fetchConfig().then((configText) => {
|
||||||
|
let fullConfig = configText;
|
||||||
|
// Fetch and append cmd_log
|
||||||
|
//return fetchCmdLog().then((cmdLogText) => {
|
||||||
|
// if (cmdLogText) {
|
||||||
|
// fullConfig = fullConfig + cmdLogText;
|
||||||
|
// }
|
||||||
|
document.getElementById("config_display").value = fullConfig;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
xhttp.open("GET", `/information.json`, true);
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetSwitch() {
|
||||||
|
if (!confirm('Are you sure you want to reset the switch?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch('/reset', { method: 'GET' }).catch(() => {});
|
||||||
|
setTimeout(() => {
|
||||||
|
alert('Switch is resetting. Please wait and refresh the page.');
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
systemInterval = setInterval(fetchIP, 1000);
|
||||||
|
});
|
||||||
@@ -6,13 +6,13 @@
|
|||||||
</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;width:40%;">
|
||||||
<div id="ports"></div>
|
|
||||||
<h1>Firmware Update</h1>
|
<h1>Firmware Update</h1>
|
||||||
<form enctype="multipart/form-data" action="/upload" method="POST">
|
<form enctype="multipart/form-data" action="/upload" method="POST">
|
||||||
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
|
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
|
||||||
Choose a firmware update file to upload: <input name="uploadedfile" type="file" accept=".bin" /><br />
|
Choose a firmware update file to upload: <br/> <br/>
|
||||||
<input type="submit" value="Upload File" />
|
<input name="uploadedfile" type="file" accept=".bin" /><br />
|
||||||
|
<input style="margin-top:3em" type="submit" value="Upload File" />
|
||||||
</form>
|
</form>
|
||||||
<script src="/navigation.js"></script>
|
<script src="/navigation.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<script src="/ports.js"></script>
|
|
||||||
<script src="/main.js"></script>
|
<script src="/main.js"></script>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<title>FreeSwitchOS VLAN Configuration</title>
|
<title>FreeSwitchOS VLAN Configuration</title>
|
||||||
@@ -13,7 +12,7 @@
|
|||||||
<form id="vform" action="/vlan.html">
|
<form id="vform" action="/vlan.html">
|
||||||
<div>
|
<div>
|
||||||
<label for="vid">VLAN ID:</label>
|
<label for="vid">VLAN ID:</label>
|
||||||
<input type="number" min="1" max="2047" id="vid" name="vid">
|
<input type="number" min="1" max="4094" id="vid" name="vid">
|
||||||
<button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();">Get Configuration</button>
|
<button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();">Get Configuration</button>
|
||||||
</div>
|
</div>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
@@ -24,6 +23,8 @@
|
|||||||
<div id="tPorts"><button type="button" style="transform: translateY(-100%);margin: 0 50px 0 0" onclick="utClicked(true);">Select all</button></div>
|
<div id="tPorts"><button type="button" style="transform: translateY(-100%);margin: 0 50px 0 0" onclick="utClicked(true);">Select all</button></div>
|
||||||
<h2>Untagged Ports</h2>
|
<h2>Untagged Ports</h2>
|
||||||
<div id="uPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="utClicked(false);">Select all</button> </div>
|
<div id="uPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="utClicked(false);">Select all</button> </div>
|
||||||
|
<h2>Use as default VLAN for incoming traffic (PVID)</h2>
|
||||||
|
<div id="pPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="pvClicked(true);">Select all</button> </div>
|
||||||
<script src="/vlan.js"></script>
|
<script src="/vlan.js"></script>
|
||||||
<br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" value="Update / Create">
|
<br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" value="Update / Create">
|
||||||
<script src="/vlan_sub.js"></script>
|
<script src="/vlan_sub.js"></script>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ var vlanInterval = Number();
|
|||||||
function vlanForm() {
|
function vlanForm() {
|
||||||
if (!numPorts)
|
if (!numPorts)
|
||||||
return;
|
return;
|
||||||
clearInterval(vlanInterval);
|
|
||||||
var t = document.getElementById('tPorts');
|
var t = document.getElementById('tPorts');
|
||||||
var u = document.getElementById('uPorts');
|
var u = document.getElementById('uPorts');
|
||||||
|
var p = document.getElementById('pPorts');
|
||||||
for (let i = 1; i <= numPorts; i++) {
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
const d = document.createElement("div");
|
const d = document.createElement("div");
|
||||||
d.classList.add("cbgroup");
|
d.classList.add("cbgroup");
|
||||||
@@ -29,6 +29,10 @@ function vlanForm() {
|
|||||||
d2.children[0].children[0].id = "uport" + i;
|
d2.children[0].children[0].id = "uport" + i;
|
||||||
d2.children[0].children[0].setAttribute('onclick', `setC("t", ${i}, false);`);
|
d2.children[0].children[0].setAttribute('onclick', `setC("t", ${i}, false);`);
|
||||||
u.appendChild(d2);
|
u.appendChild(d2);
|
||||||
|
var d3=d.cloneNode(true);
|
||||||
|
d3.children[0].children[0].id = "pport" + i;
|
||||||
|
d3.children[0].children[0].removeAttribute('onclick');
|
||||||
|
p.appendChild(d3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,9 +46,11 @@ function utClicked(t){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
function pvClicked(p){
|
||||||
vlanInterval = setInterval(vlanForm, 100);
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
});
|
setC('p', i, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fetchVLAN() {
|
function fetchVLAN() {
|
||||||
var xhttp = new XMLHttpRequest();
|
var xhttp = new XMLHttpRequest();
|
||||||
@@ -54,9 +60,17 @@ function fetchVLAN() {
|
|||||||
console.log("VLAN: ", JSON.stringify(s));
|
console.log("VLAN: ", JSON.stringify(s));
|
||||||
m = parseInt(s.members, 16);
|
m = parseInt(s.members, 16);
|
||||||
document.getElementById('vname').value = s.name;
|
document.getElementById('vname').value = s.name;
|
||||||
for (let i = 1; i <= numPorts; i++) {
|
var members = m & 0x3FF;
|
||||||
setC('t', i, (m>>(10+i-1))&1);
|
var untag = (m >> 10) & 0x3FF;
|
||||||
setC('u', i, (m>>(i-1))&1);
|
var pvid = parseInt(s.pvid, 16);
|
||||||
|
console.log("PVID: ", pvid);
|
||||||
|
for (let p = 1; p <= numPorts; p++) {
|
||||||
|
var bit = physToLogPort[p-1];
|
||||||
|
var isMember = (members >> bit) & 1;
|
||||||
|
var isUntag = (untag >> bit) & 1;
|
||||||
|
setC('t', p, isMember && !isUntag);
|
||||||
|
setC('u', p, isMember && isUntag);
|
||||||
|
setC('p', p, (pvid >> bit) & 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -66,5 +80,12 @@ function fetchVLAN() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xhttp.open("GET", `/vlan.json?vid=${v}`, true);
|
xhttp.open("GET", `/vlan.json?vid=${v}`, true);
|
||||||
xhttp.send();
|
sendXHTTP(xhttp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
update( () => {
|
||||||
|
vlanForm();
|
||||||
|
const interval = setInterval(update, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
async function vlanSub() {
|
async function vlanSub() {
|
||||||
|
var commands = [];
|
||||||
var cmd = "vlan ";
|
var cmd = "vlan ";
|
||||||
var v=document.getElementById('vid').value
|
var v=document.getElementById('vid').value
|
||||||
if (!v) {
|
if (!v) {
|
||||||
@@ -14,12 +15,19 @@ async function vlanSub() {
|
|||||||
else if (document.getElementById('uport' + i).checked)
|
else if (document.getElementById('uport' + i).checked)
|
||||||
cmd = cmd + ` ${i}`;
|
cmd = cmd + ` ${i}`;
|
||||||
}
|
}
|
||||||
|
commands.push(cmd);
|
||||||
|
for (let i = 1; i <= numPorts; i++) {
|
||||||
|
if (document.getElementById('pport' + i).checked)
|
||||||
|
commands.push(`pvid ${i} ${v}`);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/cmd', {
|
for (let c of commands) {
|
||||||
method: 'POST',
|
const response = await fetch('/cmd', {
|
||||||
body: cmd
|
method: 'POST',
|
||||||
});
|
body: c
|
||||||
console.log('Completed!', response);
|
});
|
||||||
|
console.log('Completed!', response);
|
||||||
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(`Error: ${err}`);
|
console.error(`Error: ${err}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
CC = sdcc
|
|
||||||
CC_FLAGS = -mmcs51 -I. -I../uip
|
|
||||||
ASM = sdas8051
|
|
||||||
AFLAGS= -plosgff
|
|
||||||
|
|
||||||
BUILDDIR = output/
|
|
||||||
|
|
||||||
SRCS = httpd.c page_impl.c
|
|
||||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
|
||||||
|
|
||||||
all: create_build_dir $(OBJS)
|
|
||||||
|
|
||||||
create_build_dir:
|
|
||||||
mkdir -p $(BUILDDIR)
|
|
||||||
|
|
||||||
$(BUILDDIR)%.asm: %.c
|
|
||||||
$(CC) $(CC_FLAGS) -o $@ -c -S $<
|
|
||||||
|
|
||||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
|
||||||
${ASM} ${AFLAGS} -o $@ $^
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -r $(BUILDDIR)
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
|
|
||||||
#include "httpd.h"
|
#include "httpd.h"
|
||||||
#include "page_impl.h"
|
#include "page_impl.h"
|
||||||
#include "../rtl837x_common.h"
|
#include "rtl837x_common.h"
|
||||||
#include "../cmd_parser.h"
|
#include "rtl837x_regs.h"
|
||||||
#include "../rtl837x_flash.h"
|
#include "cmd_parser.h"
|
||||||
|
#include "rtl837x_flash.h"
|
||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
#include "../html_data.h"
|
#include "html_data.h"
|
||||||
|
|
||||||
// Upload Firmware to 1M
|
// #define DEBUG
|
||||||
#define FIRMWARE_UPLOAD_START 0x100000
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define SESSION_ID_LENGTH 12
|
||||||
|
#define SESSION_TIMEOUT 200
|
||||||
|
|
||||||
// SPI FLASH MEMORY PAGE SIZE.
|
// SPI FLASH MEMORY PAGE SIZE.
|
||||||
#define FLASHMEM_PAGE_SIZE 0x100
|
#define FLASHMEM_PAGE_SIZE 0x100
|
||||||
@@ -18,12 +22,15 @@
|
|||||||
#pragma codeseg BANK1
|
#pragma codeseg BANK1
|
||||||
#pragma constseg BANK1
|
#pragma constseg BANK1
|
||||||
|
|
||||||
|
extern volatile __xdata uint8_t sfr_data[4];
|
||||||
|
extern __code uint8_t * __code hex;
|
||||||
extern __code struct f_data f_data[];
|
extern __code struct f_data f_data[];
|
||||||
extern __code char * __code mime_strings[];
|
extern __code char * __code mime_strings[];
|
||||||
extern __xdata struct flash_region_t flash_region;
|
extern __xdata struct flash_region_t flash_region;
|
||||||
|
extern __xdata uint32_t flash_size;
|
||||||
|
|
||||||
// Flash buffer to optimize flash writing speed, write_len is the current filling position
|
// Flash buffer to optimize flash writing speed, write_len is the current filling position
|
||||||
extern __xdata uint8_t flash_buf[512];
|
extern __xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||||
__xdata uint32_t uptr; // Current flash write position
|
__xdata uint32_t uptr; // Current flash write position
|
||||||
__xdata uint16_t write_len;
|
__xdata uint16_t write_len;
|
||||||
|
|
||||||
@@ -31,18 +38,28 @@ __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
|||||||
__xdata uint8_t entry;
|
__xdata uint8_t entry;
|
||||||
__xdata uint16_t slen;
|
__xdata uint16_t slen;
|
||||||
__xdata uint16_t o_idx;
|
__xdata uint16_t o_idx;
|
||||||
__xdata uint16_t mpos;
|
|
||||||
__xdata uint16_t len_left;
|
__xdata uint16_t len_left;
|
||||||
|
__xdata uint16_t cont_len;
|
||||||
|
__xdata uint32_t cont_addr;
|
||||||
|
|
||||||
// HTTP header properties
|
// HTTP header properties
|
||||||
__xdata uint8_t boundary[72];
|
__xdata uint8_t boundary[72];
|
||||||
__xdata uint8_t *content_type = 0;
|
__xdata uint8_t *content_type = 0;
|
||||||
|
__xdata uint8_t *session = 0;
|
||||||
|
|
||||||
// Global variables holding POST state
|
// Global variables holding POST state
|
||||||
__xdata uint16_t bindex; // Current index into the boundary
|
__xdata uint16_t bindex; // Current index into the boundary
|
||||||
|
__xdata uint8_t verify_crc;
|
||||||
|
__xdata uint32_t max_upload;
|
||||||
__xdata uint16_t short_parsed;
|
__xdata uint16_t short_parsed;
|
||||||
|
|
||||||
|
__xdata char passwd[21];
|
||||||
|
__xdata char session_id[SESSION_ID_LENGTH + 1];
|
||||||
|
__xdata uint8_t authenticated;
|
||||||
|
__xdata uint32_t now;
|
||||||
|
__xdata uint8_t *timeptr;
|
||||||
|
__xdata uint32_t last_session_use;
|
||||||
|
|
||||||
#define TSTATE_NONE 0
|
#define TSTATE_NONE 0
|
||||||
#define TSTATE_TX 1
|
#define TSTATE_TX 1
|
||||||
#define TSTATE_ACKED 2
|
#define TSTATE_ACKED 2
|
||||||
@@ -161,6 +178,19 @@ void send_bad_request(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_to_login(void)
|
||||||
|
{
|
||||||
|
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\n" \
|
||||||
|
"Location: login.html\r\n\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_unauthorized(void)
|
||||||
|
{
|
||||||
|
slen = strtox(outbuf, "HTTP/1.1 401 Unauthorized\r\n\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__xdata uint8_t *skip_boundary(__xdata uint8_t *p)
|
__xdata uint8_t *skip_boundary(__xdata uint8_t *p)
|
||||||
{
|
{
|
||||||
while (*p) {
|
while (*p) {
|
||||||
@@ -175,16 +205,20 @@ __xdata uint8_t *skip_boundary(__xdata uint8_t *p)
|
|||||||
__xdata uint8_t *scan_header(__xdata uint8_t *p)
|
__xdata uint8_t *scan_header(__xdata uint8_t *p)
|
||||||
{
|
{
|
||||||
content_type = 0;
|
content_type = 0;
|
||||||
|
session = 0;
|
||||||
|
authenticated = 0;
|
||||||
|
|
||||||
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
||||||
write_char(*p);
|
dbg_char(*p);
|
||||||
if (!*p++)
|
if (!*p++)
|
||||||
break;
|
break;
|
||||||
if (is_word(p, "\nContent-Type:"))
|
if (is_word(p, "\nContent-Type:"))
|
||||||
content_type = p + 15;
|
content_type = p + 15;
|
||||||
|
else if (is_word(p, "\nCookie:"))
|
||||||
|
session = p + 17;
|
||||||
}
|
}
|
||||||
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
|
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
|
||||||
print_string("\nFound multiplart\n");
|
dbg_string("\nFound multipart\n");
|
||||||
content_type += 30;
|
content_type += 30;
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
while (content_type[i] != '\r' && content_type[i] != '\n') {
|
while (content_type[i] != '\r' && content_type[i] != '\n') {
|
||||||
@@ -198,10 +232,37 @@ __xdata uint8_t *scan_header(__xdata uint8_t *p)
|
|||||||
boundary[3] = '-';
|
boundary[3] = '-';
|
||||||
boundary[i + 4] = 0;
|
boundary[i + 4] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_reg_timer(&now);
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
if (now - last_session_use > SESSION_TIMEOUT) {
|
||||||
|
dbg_string("Session expired\n");
|
||||||
|
} else {
|
||||||
|
if (is_word_x(session, session_id))
|
||||||
|
authenticated = 1;
|
||||||
|
else
|
||||||
|
dbg_string("Invalid session cookie!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes)
|
||||||
|
{
|
||||||
|
__xdata uint8_t i = 0;
|
||||||
|
while (bytes) {
|
||||||
|
if (!i)
|
||||||
|
get_random_32();
|
||||||
|
b[--bytes] = itohex(sfr_data[i]);
|
||||||
|
if (!bytes) { break; }
|
||||||
|
b[--bytes] = itohex(sfr_data[i] >> 4 | sfr_data[i] << 4);
|
||||||
|
i = (i + 1) & 0x3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads post data from the http stream and writes it into flash memory
|
* Reads post data from the http stream and writes it into flash memory
|
||||||
* Input: the current position in the TCP buffer (uip_appdata)
|
* Input: the current position in the TCP buffer (uip_appdata)
|
||||||
@@ -212,8 +273,8 @@ uint8_t stream_upload(uint16_t bptr)
|
|||||||
__xdata uint8_t *p = uip_appdata;
|
__xdata uint8_t *p = uip_appdata;
|
||||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
|
|
||||||
print_string("Stream_upload called: ");
|
dbg_string("Stream_upload called: ");
|
||||||
print_short(bptr); write_char('\n');
|
dbg_short(bptr); dbg_char('\n');
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (bptr >= uip_len) {
|
if (bptr >= uip_len) {
|
||||||
@@ -223,23 +284,35 @@ uint8_t stream_upload(uint16_t bptr)
|
|||||||
// Have we reached the end of the part?
|
// Have we reached the end of the part?
|
||||||
if (!boundary[bindex]) {
|
if (!boundary[bindex]) {
|
||||||
s->tstate = TSTATE_NONE;
|
s->tstate = TSTATE_NONE;
|
||||||
print_string("len 2: "); print_short(write_len); write_char(' ');
|
dbg_string("len 2: "); dbg_short(write_len); dbg_char(' ');
|
||||||
flash_region.addr = uptr;
|
flash_region.addr = uptr;
|
||||||
flash_region.len = write_len;
|
flash_region.len = write_len;
|
||||||
flash_write_bytes(flash_buf);
|
flash_write_bytes(flash_buf);
|
||||||
uptr += write_len;
|
uptr += write_len;
|
||||||
write_len = 0;
|
write_len = 0;
|
||||||
// TODO: This is a bit premature, what about a nice web-page saying the device will reset???
|
// TODO: This is a bit premature, what about a nice web-page saying the device will reset???
|
||||||
print_string("CRC16: "); print_short(crc_final); write_char('\n');
|
if (verify_crc) {
|
||||||
if (crc_final == 0xb001) {
|
dbg_string("CRC16: "); dbg_short(crc_final); dbg_char('\n');
|
||||||
print_string("Checksum OK.");
|
if (crc_final == 0xb001) {
|
||||||
} else {
|
print_string("Checksum OK.");
|
||||||
print_string("Checksum incorrect!");
|
} else {
|
||||||
|
print_string("Checksum incorrect!");
|
||||||
|
}
|
||||||
|
print_string("\nUpload to flash done, will reset!\n");
|
||||||
|
// close connection to avoid retries by browser
|
||||||
|
uip_close();
|
||||||
|
reset_chip();
|
||||||
}
|
}
|
||||||
print_string("Upload to flash done, will reset!\n");
|
// Make sure there is a 0 at the end of the uploaded data
|
||||||
reset_chip();
|
flash_buf[0] = 0;
|
||||||
|
flash_region.addr = uptr;
|
||||||
|
flash_region.len = 1;
|
||||||
|
flash_write_bytes(flash_buf);
|
||||||
if (bptr >= uip_len)
|
if (bptr >= uip_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
if(!verify_crc)
|
||||||
|
//ugly hack to signal connection finished after config upload.
|
||||||
|
uip_close();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (p[bptr] == boundary[bindex]) {
|
if (p[bptr] == boundary[bindex]) {
|
||||||
@@ -257,8 +330,8 @@ uint8_t stream_upload(uint16_t bptr)
|
|||||||
crc16(p + bptr);
|
crc16(p + bptr);
|
||||||
flash_buf[write_len++] = p[bptr++];
|
flash_buf[write_len++] = p[bptr++];
|
||||||
if (write_len >= FLASHMEM_PAGE_SIZE) {
|
if (write_len >= FLASHMEM_PAGE_SIZE) {
|
||||||
print_string("len: "); print_short(write_len); write_char(' ');
|
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
||||||
print_string("CRC16: "); print_short(crc_value); write_char('\n');
|
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
||||||
flash_region.addr = uptr;
|
flash_region.addr = uptr;
|
||||||
flash_region.len = FLASHMEM_PAGE_SIZE;
|
flash_region.len = FLASHMEM_PAGE_SIZE;
|
||||||
flash_write_bytes(flash_buf);
|
flash_write_bytes(flash_buf);
|
||||||
@@ -282,7 +355,7 @@ void handle_post(void)
|
|||||||
__xdata uint8_t *p = uip_appdata;
|
__xdata uint8_t *p = uip_appdata;
|
||||||
__xdata uint8_t *request_path = p + 6;
|
__xdata uint8_t *request_path = p + 6;
|
||||||
|
|
||||||
print_string("Is POST\n");
|
dbg_string("Is POST\n");
|
||||||
p += 5; // Skip post
|
p += 5; // Skip post
|
||||||
// Find end of request path
|
// Find end of request path
|
||||||
while (*p && !is_separator(*p))
|
while (*p && !is_separator(*p))
|
||||||
@@ -292,9 +365,9 @@ void handle_post(void)
|
|||||||
// Find end of request header
|
// Find end of request header
|
||||||
boundary[0] ='\0';
|
boundary[0] ='\0';
|
||||||
p = scan_header(p);
|
p = scan_header(p);
|
||||||
print_string("Boundary: >"); print_string_x(boundary); print_string("<\n");
|
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
||||||
if (!*p || !content_type) {
|
if (!*p || !content_type) {
|
||||||
print_string("Bad Request!\n");
|
dbg_string("Bad Request!\n");
|
||||||
send_not_found();
|
send_not_found();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -302,15 +375,40 @@ void handle_post(void)
|
|||||||
if (is_word(request_path, "cmd")) {
|
if (is_word(request_path, "cmd")) {
|
||||||
register uint8_t i = 0;
|
register uint8_t i = 0;
|
||||||
p += 4;
|
p += 4;
|
||||||
|
if (!authenticated) {
|
||||||
|
send_unauthorized();
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (*p && *p != '\n' && *p != '\r')
|
while (*p && *p != '\n' && *p != '\r')
|
||||||
cmd_buffer[i++] = *p++;
|
cmd_buffer[i++] = *p++;
|
||||||
cmd_buffer[i] = '\0';
|
cmd_buffer[i] = '\0';
|
||||||
if (i)
|
if (i)
|
||||||
cmd_available = 1;
|
cmd_available = 1;
|
||||||
} else if (is_word(request_path, "upload")) {
|
} else if (is_word(request_path, "login")) {
|
||||||
print_string("POST upload request\n");
|
dbg_string("POST login\n");
|
||||||
|
p += 8; // Read also over "pwd="
|
||||||
|
if (is_word_x(p, passwd)) {
|
||||||
|
dbg_string("Password accepted!\n");
|
||||||
|
read_reg_timer(&last_session_use);
|
||||||
|
gen_random_bytes(session_id, SESSION_ID_LENGTH);
|
||||||
|
session_id[SESSION_ID_LENGTH] = '\0';
|
||||||
|
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nLocation: index.html\r\n" \
|
||||||
|
"Set-Cookie: session=");
|
||||||
|
for (register uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
|
||||||
|
outbuf[slen++] = session_id[i];
|
||||||
|
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
||||||
|
} else {
|
||||||
|
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nLocation: login.html\r\n\r\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||||
|
dbg_string("POST upload/config request\n");
|
||||||
|
if (!authenticated) {
|
||||||
|
send_unauthorized();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!boundary[0]) {
|
if (!boundary[0]) {
|
||||||
print_string("Bad request, no boundary!\n");
|
dbg_string("Bad request, no boundary!\n");
|
||||||
send_bad_request();
|
send_bad_request();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -325,16 +423,37 @@ void handle_post(void)
|
|||||||
if (!content_type) // We are waiting for the part with the octet stream
|
if (!content_type) // We are waiting for the part with the octet stream
|
||||||
continue;
|
continue;
|
||||||
} while (!is_word(content_type, "application/octet-stream"));
|
} while (!is_word(content_type, "application/octet-stream"));
|
||||||
print_string("Have content octets\n");
|
dbg_string("Have content octets\n");
|
||||||
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
|
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
|
||||||
|
|
||||||
uptr = FIRMWARE_UPLOAD_START;
|
if (is_word(request_path, "upload")) {
|
||||||
|
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
||||||
|
{
|
||||||
|
print_string("Flash too small for firmware upload!\n");
|
||||||
|
send_bad_request();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print_string("Firmware upload started.");
|
||||||
|
uptr = FIRMWARE_UPLOAD_START;
|
||||||
|
verify_crc = 1;
|
||||||
|
max_upload = 1024576;
|
||||||
|
} else {
|
||||||
|
dbg_string("Configuration upload, erasing config mem!\n");
|
||||||
|
uptr = CONFIG_START;
|
||||||
|
verify_crc = 0;
|
||||||
|
max_upload = 2048;
|
||||||
|
flash_region.addr = CONFIG_START;
|
||||||
|
flash_sector_erase();
|
||||||
|
}
|
||||||
|
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails
|
||||||
|
set_sys_led_state(SYS_LED_FAST);
|
||||||
|
|
||||||
crc_value = 0;
|
crc_value = 0;
|
||||||
bindex = 0;
|
bindex = 0;
|
||||||
write_len = 0;
|
write_len = 0;
|
||||||
stream_upload(p - uip_appdata);
|
stream_upload(p - uip_appdata);
|
||||||
|
|
||||||
print_string("Done reading first fragment\n");
|
dbg_string("Done reading first fragment\n");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -353,26 +472,26 @@ void httpd_appcall(void)
|
|||||||
{
|
{
|
||||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
|
|
||||||
write_char('P');
|
dbg_char('P');
|
||||||
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
|
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
|
||||||
print_string("Connected...\n");
|
dbg_string("Connected...\n");
|
||||||
s->tstate = TSTATE_NONE;
|
s->tstate = TSTATE_NONE;
|
||||||
} else if (uip_closed()) {
|
} else if (uip_closed()) {
|
||||||
print_string("Connection closed\n");
|
dbg_string("Connection closed\n");
|
||||||
s->tstate = TSTATE_CLOSED;
|
s->tstate = TSTATE_CLOSED;
|
||||||
} else if (uip_aborted()) {
|
} else if (uip_aborted()) {
|
||||||
print_string("Connection aborted\n");
|
dbg_string("Connection aborted\n");
|
||||||
uip_close();
|
uip_close();
|
||||||
s->tstate = TSTATE_CLOSED;
|
s->tstate = TSTATE_CLOSED;
|
||||||
} else if (uip_poll()) {
|
} else if (uip_poll()) {
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
if (s->tstate == TSTATE_ACKED) {
|
if (s->tstate == TSTATE_ACKED) {
|
||||||
print_string("Closing because everything has been transmitted\n");
|
dbg_string("Closing because everything has been transmitted\n");
|
||||||
uip_close();
|
uip_close();
|
||||||
s->tstate = TSTATE_CLOSED;
|
s->tstate = TSTATE_CLOSED;
|
||||||
}
|
}
|
||||||
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
||||||
print_string("ACK\n");
|
dbg_string("ACK\n");
|
||||||
if (slen > uip_mss()) {
|
if (slen > uip_mss()) {
|
||||||
slen -= uip_mss();
|
slen -= uip_mss();
|
||||||
o_idx += uip_mss();
|
o_idx += uip_mss();
|
||||||
@@ -384,26 +503,46 @@ void httpd_appcall(void)
|
|||||||
s->tstate = TSTATE_ACKED;
|
s->tstate = TSTATE_ACKED;
|
||||||
|
|
||||||
if (slen > uip_mss()) {
|
if (slen > uip_mss()) {
|
||||||
print_string("Sending A: "); print_short(slen); write_char('\n');
|
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, uip_mss());
|
uip_send(outbuf + o_idx, uip_mss());
|
||||||
print_string("Sending A done\n");
|
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
} else if (slen > 0) {
|
} else if (slen > 0) {
|
||||||
print_string("Sending B: "); print_short(slen); write_char('\n');
|
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, slen);
|
uip_send(outbuf + o_idx, slen);
|
||||||
print_string("Sending B done\n");
|
s->tstate = TSTATE_TX;
|
||||||
|
} else if (cont_len) {
|
||||||
|
dbg_string("CONT cont_len: "); dbg_short(cont_len);
|
||||||
|
slen = cont_len > uip_mss() ? uip_mss() : cont_len;
|
||||||
|
if (slen > TCP_OUTBUF_SIZE)
|
||||||
|
slen = TCP_OUTBUF_SIZE;
|
||||||
|
flash_region.addr = cont_addr;
|
||||||
|
flash_region.len = slen;
|
||||||
|
flash_read_bulk(outbuf);
|
||||||
|
uip_send(outbuf, slen);
|
||||||
|
cont_len -= slen;
|
||||||
|
cont_addr += slen;
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
}
|
}
|
||||||
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||||
stream_upload(0);
|
// Check here maxupload by subtracting uip_len and close socekt if fails!
|
||||||
|
if (max_upload - uip_len > 0) {
|
||||||
|
stream_upload(0);
|
||||||
|
write_char('.');
|
||||||
|
} else {
|
||||||
|
send_bad_request();
|
||||||
|
goto do_send;
|
||||||
|
}
|
||||||
} else if (uip_newdata() && s->tstate != TSTATE_TX) {
|
} else if (uip_newdata() && s->tstate != TSTATE_TX) {
|
||||||
write_char('<'); print_short(uip_len); write_char('\n');
|
cont_len = 0;
|
||||||
|
dbg_char('<'); dbg_short(uip_len); dbg_char('\n');
|
||||||
__xdata uint8_t *p = uip_appdata;
|
__xdata uint8_t *p = uip_appdata;
|
||||||
// Mark end of request header with \0
|
// Mark end of request header with \0
|
||||||
p[uip_len] = 0;
|
p[uip_len] = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
while (*p)
|
while (*p)
|
||||||
write_char(*p++);
|
dbg_char(*p++);
|
||||||
write_char('\n');
|
dbg_char('\n');
|
||||||
|
#endif
|
||||||
p = uip_appdata;
|
p = uip_appdata;
|
||||||
if (is_word(p, "POST")) {
|
if (is_word(p, "POST")) {
|
||||||
handle_post();
|
handle_post();
|
||||||
@@ -416,20 +555,26 @@ void httpd_appcall(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_word(p, "GET"))
|
if (is_word(p, "GET"))
|
||||||
print_string("GET request ");
|
dbg_string("GET request ");
|
||||||
p += 4;
|
p += 4;
|
||||||
|
scan_header(p);
|
||||||
__xdata uint8_t *q = p;
|
__xdata uint8_t *q = p;
|
||||||
while (!is_separator(*p))
|
while (!is_separator(*p))
|
||||||
p++;
|
p++;
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
print_string_x(q);
|
dbg_string_x(q);
|
||||||
write_char('\n');
|
dbg_char('\n');
|
||||||
|
|
||||||
s->tstate = TSTATE_NONE;
|
s->tstate = TSTATE_NONE;
|
||||||
entry = find_entry(q);
|
entry = find_entry(q);
|
||||||
print_string("Entry is: "); print_byte(entry); write_char('\n');
|
dbg_string("Entry is: "); dbg_byte(entry); dbg_char('\n');
|
||||||
if (entry == 0xff) {
|
if (entry == 0xff) {
|
||||||
print_string("Not file entry\n");
|
if (!authenticated) {
|
||||||
|
dbg_string("Not authorized!\n");
|
||||||
|
send_unauthorized();
|
||||||
|
goto do_send;
|
||||||
|
}
|
||||||
|
dbg_string("Not file entry\n");
|
||||||
if (!strcmp(q, "/status.json")) {
|
if (!strcmp(q, "/status.json")) {
|
||||||
send_status();
|
send_status();
|
||||||
} else if (!strcmp(q, "/information.json")) {
|
} else if (!strcmp(q, "/information.json")) {
|
||||||
@@ -438,50 +583,90 @@ void httpd_appcall(void)
|
|||||||
parse_short(q + 15);
|
parse_short(q + 15);
|
||||||
send_vlan(short_parsed);
|
send_vlan(short_parsed);
|
||||||
} else if (is_word(q, "/counters.json")) {
|
} else if (is_word(q, "/counters.json")) {
|
||||||
send_counters(q[19]-'0');
|
send_counters(q[20]-'0');
|
||||||
} else if (is_word(q, "/eee.json")) {
|
} else if (is_word(q, "/eee.json")) {
|
||||||
send_eee();
|
send_eee();
|
||||||
|
} else if (is_word(q, "/bandwidth.json")) {
|
||||||
|
send_bandwidth();
|
||||||
|
} else if (is_word(q, "/l2.json")) {
|
||||||
|
parse_short(q + 13); // e.g.: /l2.json?idx=10
|
||||||
|
send_l2(short_parsed);
|
||||||
|
} else if (is_word(q, "/l2_del.json")) {
|
||||||
|
parse_short(q + 17);
|
||||||
|
l2_delete(short_parsed);
|
||||||
} else if (is_word(q, "/mirror.json")) {
|
} else if (is_word(q, "/mirror.json")) {
|
||||||
send_mirror();
|
send_mirror();
|
||||||
|
} else if (is_word(q, "/mtu.json")) {
|
||||||
|
send_mtu();
|
||||||
|
} else if (is_word(q, "/lag.json")) {
|
||||||
|
send_lag();
|
||||||
|
} else if (is_word(q, "/config")) {
|
||||||
|
send_config();
|
||||||
|
} else if (is_word(q, "/cmd_log")) {
|
||||||
|
send_cmd_log();
|
||||||
|
} else if (is_word(q, "/cmd_log_clear")) {
|
||||||
|
clear_command_history();
|
||||||
|
send_mtu(); // dummy response
|
||||||
|
} else if (is_word(q, "/reset")) {
|
||||||
|
uip_close();
|
||||||
|
delay(1000); //wait for the close packet to be sent, otherwise the browser will retry
|
||||||
|
reset_chip();
|
||||||
} else {
|
} else {
|
||||||
send_not_found();
|
send_not_found();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_string("Have entry\n");
|
dbg_string("Have entry, authenticated: "); dbg_byte(authenticated); dbg_char('\n');
|
||||||
|
if (!authenticated && !(f_data[entry].start == FDATA_START_login_html
|
||||||
|
|| f_data[entry].start == FDATA_START_port_svg
|
||||||
|
|| f_data[entry].start == FDATA_START_sfp_svg
|
||||||
|
|| f_data[entry].start == FDATA_START_style_css)) {
|
||||||
|
send_to_login();
|
||||||
|
goto do_send;
|
||||||
|
}
|
||||||
|
// A web-page is actively accessed, we can reset session time-out
|
||||||
|
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||||
|
timeptr = (uint8_t*)&last_session_use; // last_session_use is Little endian
|
||||||
|
timeptr[0] = sfr_data[3]; timeptr[1] = sfr_data[2]; timeptr[2] = sfr_data[1]; timeptr[3] = sfr_data[0];
|
||||||
|
|
||||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: ");
|
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: ");
|
||||||
slen += strtox(outbuf + slen, mime_strings[f_data[entry].mime]);
|
slen += strtox(outbuf + slen, mime_strings[f_data[entry].mime]);
|
||||||
slen += strtox(outbuf + slen, "\r\nCache-Control: max-age=2592000\r\n\r\n");
|
slen += strtox(outbuf + slen, "; charset=UTF-8\r\nCache-Control: max-age=60, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\nContent-Security-Policy: style-src 'self' 'unsafe-inline'\r\n\r\n");
|
||||||
len_left = f_data[entry].len;
|
|
||||||
|
|
||||||
print_string("MIME: "); print_string(mime_strings[f_data[entry].mime]); write_char('\n');
|
len_left = f_data[entry].len;
|
||||||
|
if (len_left > (TCP_OUTBUF_SIZE - slen)) {
|
||||||
|
cont_len = len_left - (TCP_OUTBUF_SIZE - slen);
|
||||||
|
len_left = TCP_OUTBUF_SIZE - slen;
|
||||||
|
cont_addr = f_data[entry].start + len_left;
|
||||||
|
}
|
||||||
|
dbg_string("MIME: "); dbg_string(mime_strings[f_data[entry].mime]); dbg_char('\n');
|
||||||
flash_region.addr = f_data[entry].start;
|
flash_region.addr = f_data[entry].start;
|
||||||
flash_region.len = len_left;
|
flash_region.len = len_left;
|
||||||
flash_read_bulk(outbuf + slen);
|
flash_read_bulk(outbuf + slen);
|
||||||
slen += len_left;
|
slen += len_left;
|
||||||
}
|
}
|
||||||
do_send:
|
do_send:
|
||||||
print_string("slen: "); print_short(slen); write_char('\n');
|
dbg_string("slen: "); dbg_short(slen); dbg_char('\n');
|
||||||
o_idx = 0;
|
o_idx = 0;
|
||||||
if (slen > uip_mss()) {
|
if (slen > uip_mss()) {
|
||||||
print_string("Sending a: "); print_short(slen); write_char('\n');
|
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, uip_mss());
|
uip_send(outbuf + o_idx, uip_mss());
|
||||||
print_string("Sending a done\n");
|
dbg_string("Sending a done\n");
|
||||||
} else {
|
} else {
|
||||||
print_string("Sending b: "); print_short(slen); write_char('\n');
|
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, slen);
|
uip_send(outbuf + o_idx, slen);
|
||||||
print_string("Sending b done\n");
|
dbg_string("Sending b done\n");
|
||||||
}
|
}
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
||||||
print_string("RETRANSMIT requested\n");
|
dbg_string("RETRANSMIT requested\n");
|
||||||
if (slen > uip_mss()) {
|
if (slen > uip_mss()) {
|
||||||
print_string("Sending C: "); print_short(slen); write_char('\n');
|
dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, uip_mss());
|
uip_send(outbuf + o_idx, uip_mss());
|
||||||
print_string("Sending C done\n");
|
dbg_string("Sending C done\n");
|
||||||
} else if (slen > 0) {
|
} else if (slen > 0) {
|
||||||
print_string("Sending D: "); print_short(slen); write_char('\n');
|
dbg_string("Sending D: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, slen);
|
uip_send(outbuf + o_idx, slen);
|
||||||
print_string("Sending D done\n");
|
dbg_string("Sending D done\n");
|
||||||
}
|
}
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
|
|||||||
@@ -1,50 +1,52 @@
|
|||||||
// #define REGDBG 1
|
// #define REGDBG 1
|
||||||
|
|
||||||
#include "../rtl837x_sfr.h"
|
#include "rtl837x_sfr.h"
|
||||||
#include "../rtl837x_common.h"
|
#include "rtl837x_common.h"
|
||||||
#include "../rtl837x_regs.h"
|
#include "rtl837x_regs.h"
|
||||||
#include "../rtl837x_port.h"
|
#include "rtl837x_port.h"
|
||||||
|
#include "rtl837x_flash.h"
|
||||||
|
#include "rtl837x_pins.h"
|
||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
#include "../html_data.h"
|
#include "html_data.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../phy.h"
|
#include "phy.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "machine.h"
|
||||||
|
#include "page_impl.h"
|
||||||
|
|
||||||
|
// #define DEBUG
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define L2_MAX_TRANSFER 30
|
||||||
|
|
||||||
#pragma codeseg BANK1
|
#pragma codeseg BANK1
|
||||||
#pragma constseg BANK1
|
#pragma constseg BANK1
|
||||||
|
|
||||||
|
extern __code const struct machine machine;
|
||||||
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||||
extern __xdata uint16_t slen;
|
extern __xdata uint16_t slen;
|
||||||
|
extern __xdata uint16_t cont_len;
|
||||||
|
extern __xdata uint32_t cont_addr;
|
||||||
extern __code uint8_t * __code hex;
|
extern __code uint8_t * __code hex;
|
||||||
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||||
extern __code struct uip_eth_addr uip_ethaddr;
|
|
||||||
extern __code uint8_t log_to_phys_port[9];
|
|
||||||
extern __code uint8_t phys_to_log_port[6];
|
|
||||||
|
|
||||||
extern __xdata uint8_t minPort;
|
|
||||||
extern __xdata uint8_t maxPort;
|
|
||||||
extern __xdata uint8_t nSFPPorts;
|
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
extern __xdata uint8_t cpuPort;
|
|
||||||
extern __xdata uint8_t isRTL8373;
|
|
||||||
extern __xdata uint8_t sfp_pins_last;
|
extern __xdata uint8_t sfp_pins_last;
|
||||||
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||||
|
|
||||||
|
extern __xdata uint8_t cmd_history[CMD_HISTORY_SIZE];
|
||||||
|
extern __xdata uint16_t cmd_history_ptr;
|
||||||
|
|
||||||
|
extern __xdata struct flash_region_t flash_region;
|
||||||
|
|
||||||
|
extern __xdata char sfp_module_vendor[2][17];
|
||||||
|
extern __xdata char sfp_module_model[2][17];
|
||||||
|
extern __xdata char sfp_module_serial[2][17];
|
||||||
|
extern __xdata uint8_t sfp_options[2];
|
||||||
|
|
||||||
__code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n";
|
__code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n";
|
||||||
|
__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
|
||||||
/* Convert only the lower nibble to ascii HEX char.
|
|
||||||
For convenience the upper nibble is masked out.
|
|
||||||
*/
|
|
||||||
inline char itohex(uint8_t val) {
|
|
||||||
// Ignore upper nibble for convenience.
|
|
||||||
val &= 0x0f;
|
|
||||||
val -= 10;
|
|
||||||
|
|
||||||
// 10 or above
|
|
||||||
if ((int8_t)val >= 0)
|
|
||||||
val += ('a' - '0' - 10);
|
|
||||||
|
|
||||||
return val + ('0' + 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert uint8_t to ascii HEX char push on html-buffer.
|
// Convert uint8_t to ascii HEX char push on html-buffer.
|
||||||
void charhex_to_html(char c)
|
void charhex_to_html(char c)
|
||||||
@@ -95,17 +97,21 @@ void itoa_html(uint8_t v)
|
|||||||
char_to_html('0' + (v % 10));
|
char_to_html('0' + (v % 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void string_to_html(__code char *s)
|
||||||
|
{
|
||||||
|
while (*s) char_to_html(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t stat_content(void)
|
uint16_t stat_content(void)
|
||||||
{
|
{
|
||||||
print_string("stat_content called\n");
|
dbg_string("stat_content called\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t port_status(void)
|
uint16_t port_status(void)
|
||||||
{
|
{
|
||||||
print_string("port_status called\n");
|
dbg_string("port_status called\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,10 +149,69 @@ void reg_to_html(register uint16_t reg)
|
|||||||
sfr_data_to_html();
|
sfr_data_to_html();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reg_to_html_long(register uint16_t reg)
|
||||||
|
{
|
||||||
|
reg_read_m(reg);
|
||||||
|
byte_to_html(sfr_data[0]);
|
||||||
|
byte_to_html(sfr_data[1]);
|
||||||
|
byte_to_html(sfr_data[2]);
|
||||||
|
byte_to_html(sfr_data[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_sfp_info(uint8_t sfp)
|
||||||
|
{
|
||||||
|
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||||
|
for (uint8_t i = 20; i < 60; i++) {
|
||||||
|
if (i >= 36 && i < 40) // Skip Non-ASCII codes
|
||||||
|
continue;
|
||||||
|
uint8_t c = sfp_read_reg(sfp, i);
|
||||||
|
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
|
||||||
|
char_to_html(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
|
||||||
|
{
|
||||||
|
// maximum supported transfer size is 16 bytes
|
||||||
|
if (len > 16)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
|
||||||
|
reg &= 0x7f;
|
||||||
|
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
|
||||||
|
} else {
|
||||||
|
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_read_m(RTL837X_REG_I2C_CTRL);
|
||||||
|
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2);
|
||||||
|
reg_write_m(RTL837X_REG_I2C_CTRL);
|
||||||
|
|
||||||
|
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
|
||||||
|
|
||||||
|
// Execute I2C Read
|
||||||
|
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
|
||||||
|
|
||||||
|
// Wait for execution to finish
|
||||||
|
do {
|
||||||
|
reg_read_m(RTL837X_REG_I2C_CTRL);
|
||||||
|
} while (sfr_data[3] & 0x1);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
if (!(i & 0x3))
|
||||||
|
reg_read_m(RTL837X_REG_I2C_OUT + i);
|
||||||
|
byte_to_html(sfr_data[3 - (i & 0x3)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_basic_info(void)
|
void send_basic_info(void)
|
||||||
{
|
{
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
print_string("send_basic_info called\n");
|
dbg_string("send_basic_info called\n");
|
||||||
slen += strtox(outbuf + slen, "{\"ip_address\":\"");
|
slen += strtox(outbuf + slen, "{\"ip_address\":\"");
|
||||||
itoa_html(uip_hostaddr[0]); char_to_html('.');
|
itoa_html(uip_hostaddr[0]); char_to_html('.');
|
||||||
itoa_html(uip_hostaddr[0] >> 8); char_to_html('.');
|
itoa_html(uip_hostaddr[0] >> 8); char_to_html('.');
|
||||||
@@ -169,15 +234,31 @@ void send_basic_info(void)
|
|||||||
byte_to_html(uip_ethaddr.addr[3]); char_to_html(':');
|
byte_to_html(uip_ethaddr.addr[3]); char_to_html(':');
|
||||||
byte_to_html(uip_ethaddr.addr[4]); char_to_html(':');
|
byte_to_html(uip_ethaddr.addr[4]); char_to_html(':');
|
||||||
byte_to_html(uip_ethaddr.addr[5]);
|
byte_to_html(uip_ethaddr.addr[5]);
|
||||||
slen += strtox(outbuf + slen, "\",\"sw_ver\":\"v0.1-ge4c48586\",\"hw_ver\":\"SWGT024-V2.0\"}");
|
slen += strtox(outbuf + slen, "\",\"sw_ver\":\"");
|
||||||
// slen += strtox(outbuf + slen, "\"}");
|
slen += strtox(outbuf + slen, VERSION_SW);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"build_date\":\"");
|
||||||
|
slen += strtox(outbuf + slen, BUILD_DATE);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"hw_ver\":\"");
|
||||||
|
slen += strtox(outbuf + slen, machine.machine_name);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"flash_size\":\"");
|
||||||
|
string_to_html(get_flash_size_str());
|
||||||
|
|
||||||
|
slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\"");
|
||||||
|
send_sfp_info(0);
|
||||||
|
char_to_html('"');
|
||||||
|
if (machine.n_sfp == 2) {
|
||||||
|
slen += strtox(outbuf + slen, ",\"sfp_slot_1\":\"");
|
||||||
|
send_sfp_info(1);
|
||||||
|
char_to_html('"');
|
||||||
|
}
|
||||||
|
char_to_html('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_vlan(uint16_t vlan)
|
void send_vlan(uint16_t vlan)
|
||||||
{
|
{
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
print_string("sending VLAN\n");
|
dbg_string("sending VLAN\n");
|
||||||
//{"members":"0x00060011"}
|
//{"members":"0x00060011"}
|
||||||
slen += strtox(outbuf + slen, "{\"members\":\"0x");
|
slen += strtox(outbuf + slen, "{\"members\":\"0x");
|
||||||
vlan_get(vlan);
|
vlan_get(vlan);
|
||||||
@@ -185,33 +266,182 @@ void send_vlan(uint16_t vlan)
|
|||||||
slen += strtox(outbuf + slen, "\",\"name\":\"");
|
slen += strtox(outbuf + slen, "\",\"name\":\"");
|
||||||
__xdata uint16_t n = vlan_name(vlan);
|
__xdata uint16_t n = vlan_name(vlan);
|
||||||
if (n== 0xffff) {
|
if (n== 0xffff) {
|
||||||
print_string("VLAN has no name\n");
|
dbg_string("VLAN has no name\n");
|
||||||
} else {
|
} else {
|
||||||
while(vlan_names[n] && vlan_names[n] != ' ')
|
while(vlan_names[n] && vlan_names[n] != ' ')
|
||||||
char_to_html(vlan_names[n++]);
|
char_to_html(vlan_names[n++]);
|
||||||
}
|
}
|
||||||
|
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
||||||
|
uint16_t pvid_mask = 0;
|
||||||
|
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||||
|
if (port_pvid_get(i) == vlan)
|
||||||
|
pvid_mask |= (1 << i);
|
||||||
|
}
|
||||||
|
byte_to_html(pvid_mask >> 8);
|
||||||
|
byte_to_html(pvid_mask);
|
||||||
slen += strtox(outbuf + slen, "\"}");
|
slen += strtox(outbuf + slen, "\"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_counters(char port)
|
void send_counters(char port)
|
||||||
{
|
{
|
||||||
print_string("send_counters called: "); print_byte(port); write_char('\n');
|
dbg_string("send_counters called: "); dbg_byte(port); dbg_char('\n');
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
print_string("sending counters\n");
|
dbg_string("sending counters\n");
|
||||||
|
dbg_byte(port);
|
||||||
port--;
|
uint8_t i = machine.phys_to_log_port[port];
|
||||||
uint8_t i = isRTL8373 ? port - 1: phys_to_log_port[port];
|
slen += strtox(outbuf + slen, "[");
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
||||||
itoa_html(i + 1);
|
STAT_GET(counter, i);
|
||||||
for (uint8_t j = 0; j < 0x3f; j++) {
|
slen += strtox(outbuf + slen, "\"0x");
|
||||||
STAT_GET(j, i);
|
|
||||||
slen += strtox(outbuf + slen, ",\"cnt_");
|
|
||||||
itoa_html(j);
|
|
||||||
slen += strtox(outbuf + slen, "\":\"0x");
|
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||||
reg_to_html(RTL837X_STAT_V_LOW);
|
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||||
char_to_html('\"');
|
char_to_html('\"');
|
||||||
|
if (counter != 0x36)
|
||||||
|
char_to_html(',');
|
||||||
|
}
|
||||||
|
char_to_html(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_l2(uint16_t idx)
|
||||||
|
{
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
|
dbg_string("sending L2\n");
|
||||||
|
dbg_short(idx);
|
||||||
|
__xdata uint8_t entries_left = L2_MAX_TRANSFER;
|
||||||
|
|
||||||
|
do {
|
||||||
|
reg_read_m(RTL837X_TBL_CTRL);
|
||||||
|
} while (sfr_data[3] & TBL_EXECUTE);
|
||||||
|
|
||||||
|
/* The L2 table in the ASIC can hold up to 4096 (0x1000) entries, which
|
||||||
|
* are accessed using an index. The index is the hash of the MAC address
|
||||||
|
* and forwarding ID (basically VID). The hash-table is 4-way associative,
|
||||||
|
* i.e. for a given hash value, 4 entries with that same hash can be stored
|
||||||
|
* (i.e. the hash points to a bucket with up to 4 entries).
|
||||||
|
* When the table or a hash bucket is full, further entries will lead to
|
||||||
|
* L2 flooding.
|
||||||
|
* To find all entries, we start with entry-index 0 and iteratively search for
|
||||||
|
* the next entry (with the next higher index), until we arrive again at the first
|
||||||
|
* entry. The indices are sorted, so if an entry has a smaller index than
|
||||||
|
* the previous one, we know that we have wrapped around the entire table.
|
||||||
|
*/
|
||||||
|
__xdata uint16_t entry = idx & 0xfff;
|
||||||
|
__xdata uint16_t first_entry = 0xffff; // An illegal entry index
|
||||||
|
char_to_html('[');
|
||||||
|
while (1) {
|
||||||
|
entries_left--;
|
||||||
|
uint8_t port = 0;
|
||||||
|
reg_read_m(RTL837x_TBL_DATA_0);
|
||||||
|
REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1] & 0xfc, sfr_data[2] | (TBL_LUTREAD_NEXT_L2UC << 6), sfr_data[3]);
|
||||||
|
|
||||||
|
REG_WRITE(RTL837X_TBL_CTRL, entry >> 8, entry, TBL_L2_UNICAST, TBL_EXECUTE);
|
||||||
|
do {
|
||||||
|
reg_read_m(RTL837X_TBL_CTRL);
|
||||||
|
} while (sfr_data[3] & TBL_EXECUTE);
|
||||||
|
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||||
|
if ((sfr_data[0] & 0x20)) { // Check entry is valid
|
||||||
|
// MAC
|
||||||
|
slen += strtox(outbuf + slen, "{\"mac\":\"");
|
||||||
|
byte_to_html(sfr_data[2]); char_to_html(':');
|
||||||
|
byte_to_html(sfr_data[3]); char_to_html(':');
|
||||||
|
port = (sfr_data[0] >> 6) & 0x3;
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_A);
|
||||||
|
byte_to_html(sfr_data[0]); char_to_html(':');
|
||||||
|
byte_to_html(sfr_data[1]); char_to_html(':');
|
||||||
|
byte_to_html(sfr_data[2]); char_to_html(':');
|
||||||
|
byte_to_html(sfr_data[3]);
|
||||||
|
|
||||||
|
// VLAN
|
||||||
|
slen += strtox(outbuf + slen, "\",\"vlan\":\"");
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||||
|
charhex_to_html(sfr_data[0] & 0x0f);
|
||||||
|
byte_to_html(sfr_data[1]);
|
||||||
|
|
||||||
|
// type
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||||
|
if (sfr_data[2] & 0x1)
|
||||||
|
slen += strtox(outbuf + slen, "\",\"type\":\"s\",\"port\":");
|
||||||
|
else
|
||||||
|
slen += strtox(outbuf + slen, "\",\"type\":\"l\",\"port\":");
|
||||||
|
|
||||||
|
port |= (sfr_data[3] & 0x3) << 2;
|
||||||
|
itoa_html(port);
|
||||||
|
|
||||||
|
// Index
|
||||||
|
reg_read_m(RTL837x_TBL_DATA_0);
|
||||||
|
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3];
|
||||||
|
slen += strtox(outbuf + slen, ",\"idx\":\"");
|
||||||
|
byte_to_html(entry >> 8);
|
||||||
|
byte_to_html(entry);
|
||||||
|
char_to_html('"');
|
||||||
|
char_to_html('}');
|
||||||
|
entry += 1; // We want the next entry following after the current entry
|
||||||
|
} else {
|
||||||
|
reg_read_m(RTL837x_TBL_DATA_0);
|
||||||
|
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3] + 1;
|
||||||
|
}
|
||||||
|
if (first_entry == 0xffff) {
|
||||||
|
char_to_html(',');
|
||||||
|
first_entry = entry;
|
||||||
|
} else {
|
||||||
|
if (first_entry == entry || !entries_left) {
|
||||||
|
char_to_html(']');
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
char_to_html(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void l2_delete(uint16_t idx)
|
||||||
|
{
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
|
dbg_string("L2 DELETE\n");
|
||||||
|
dbg_short(idx);
|
||||||
|
__xdata uint8_t entries_left = L2_MAX_TRANSFER;
|
||||||
|
|
||||||
|
do {
|
||||||
|
reg_read_m(RTL837X_TBL_CTRL);
|
||||||
|
} while (sfr_data[3] & TBL_EXECUTE);
|
||||||
|
slen += strtox(outbuf + slen, "{\"result\":");
|
||||||
|
// First, search for the entry based on the index
|
||||||
|
reg_read_m(RTL837x_TBL_DATA_0);
|
||||||
|
REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1] & 0xfc, sfr_data[2] | (TBL_LUTREAD_NEXT_L2UC << 6), sfr_data[3]);
|
||||||
|
|
||||||
|
REG_WRITE(RTL837X_TBL_CTRL, (idx >> 8) & 0xf, idx, TBL_L2_UNICAST, TBL_EXECUTE);
|
||||||
|
do {
|
||||||
|
reg_read_m(RTL837X_TBL_CTRL);
|
||||||
|
} while (sfr_data[3] & 0x1);
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||||
|
if (!(sfr_data[0] & 0x20)) {
|
||||||
|
char_to_html('0');
|
||||||
|
} else {
|
||||||
|
sfr_data[0] &= 0x3f; // Clear SPA
|
||||||
|
reg_write_m(RTL837x_TBL_DATA_IN_B);
|
||||||
|
|
||||||
|
// Second half of MAC is copied
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_A);
|
||||||
|
reg_write_m(RTL837x_TBL_DATA_IN_A);
|
||||||
|
|
||||||
|
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||||
|
sfr_data[3] &= 0xc0; // Clear age, auth and second part of ports
|
||||||
|
sfr_data[1] &= 0xfe; // Clear nosalearn
|
||||||
|
reg_write_m(RTL837x_TBL_DATA_IN_C);
|
||||||
|
|
||||||
|
reg_read_m(RTL837x_TBL_DATA_0);
|
||||||
|
REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1], TBL_L2_UNICAST, sfr_data[3]);
|
||||||
|
|
||||||
|
REG_WRITE(RTL837X_TBL_CTRL, idx >> 8, idx, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
|
||||||
|
do {
|
||||||
|
reg_read_m(RTL837X_TBL_CTRL);
|
||||||
|
} while (sfr_data[3] & TBL_EXECUTE);
|
||||||
|
|
||||||
|
char_to_html('1');
|
||||||
}
|
}
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
}
|
}
|
||||||
@@ -219,9 +449,8 @@ void send_counters(char port)
|
|||||||
|
|
||||||
void send_mirror(void)
|
void send_mirror(void)
|
||||||
{
|
{
|
||||||
print_string("send_eee called\n");
|
dbg_string("send_mirror called\n");
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
print_string("sending EEE status\n");
|
|
||||||
|
|
||||||
reg_read_m(RTL837x_MIRROR_CTRL);
|
reg_read_m(RTL837x_MIRROR_CTRL);
|
||||||
uint8_t mPort = sfr_data[3];
|
uint8_t mPort = sfr_data[3];
|
||||||
@@ -230,24 +459,21 @@ void send_mirror(void)
|
|||||||
} else {
|
} else {
|
||||||
slen += strtox(outbuf + slen, "{\"enabled\":0,\"mPort\":");
|
slen += strtox(outbuf + slen, "{\"enabled\":0,\"mPort\":");
|
||||||
}
|
}
|
||||||
if (!isRTL8373)
|
itoa_html(machine.log_to_phys_port[mPort >> 1]);
|
||||||
itoa_html(log_to_phys_port[mPort >> 1]);
|
|
||||||
else
|
|
||||||
itoa_html((mPort >> 1) + 1);
|
|
||||||
|
|
||||||
reg_read_m(RTL837x_MIRROR_CONF);
|
reg_read_m(RTL837x_MIRROR_CONF);
|
||||||
uint16_t m = sfr_data[0];
|
uint16_t m = sfr_data[0];
|
||||||
m = (m << 8) | sfr_data[1];
|
m = (m << 8) | sfr_data[1];
|
||||||
slen += strtox(outbuf + slen, ",\"mirror_rx\":\"");
|
slen += strtox(outbuf + slen, ",\"mirror_rx\":\"");
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
bool_to_html(m & 0x8000);
|
bool_to_html(!!(m & 0x8000));
|
||||||
m <<= 1;
|
m <<= 1;
|
||||||
}
|
}
|
||||||
m = sfr_data[2];
|
m = sfr_data[2];
|
||||||
m = (m << 8) | sfr_data[3];
|
m = (m << 8) | sfr_data[3];
|
||||||
slen += strtox(outbuf + slen, "\",\"mirror_tx\":\"");
|
slen += strtox(outbuf + slen, "\",\"mirror_tx\":\"");
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
bool_to_html(m & 0x8000);
|
bool_to_html(!!(m & 0x8000));
|
||||||
m <<= 1;
|
m <<= 1;
|
||||||
}
|
}
|
||||||
char_to_html('\"');
|
char_to_html('\"');
|
||||||
@@ -255,23 +481,46 @@ void send_mirror(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_lag(void)
|
||||||
|
{
|
||||||
|
dbg_string("send_lag called\n");
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
|
|
||||||
|
char_to_html('[');
|
||||||
|
for (uint8_t l=0; l < 4; l++) {
|
||||||
|
slen += strtox(outbuf + slen, "{\"lagNum\":");
|
||||||
|
itoa_html(l);
|
||||||
|
slen += strtox(outbuf + slen, ",\"members\":\"");
|
||||||
|
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (l << 2));
|
||||||
|
uint16_t ports = ((uint16_t)sfr_data[2] << 8) | sfr_data[3];
|
||||||
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
|
bool_to_html(!!(ports & 0x8000));
|
||||||
|
ports <<= 1;
|
||||||
|
}
|
||||||
|
slen += strtox(outbuf + slen, "\",\"hash\":\"");
|
||||||
|
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (l << 2));
|
||||||
|
sfr_data_to_html();
|
||||||
|
slen += strtox(outbuf + slen, "\"},");
|
||||||
|
}
|
||||||
|
slen -=1; // remove comma
|
||||||
|
char_to_html(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_eee(void)
|
void send_eee(void)
|
||||||
{
|
{
|
||||||
print_string("send_eee called\nsending EEE status\n");
|
dbg_string("send_eee called\nsending EEE status\n");
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
|
|
||||||
reg_read_m(RTL8373_PHY_EEE_ABLTY);
|
reg_read_m(RTL8373_PHY_EEE_ABLTY);
|
||||||
uint8_t eee_ablty = sfr_data[3];
|
uint8_t eee_ablty = sfr_data[3];
|
||||||
|
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
for (uint8_t i = minPort; i <= maxPort; i++) {
|
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
if (!isRTL8373)
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
itoa_html(log_to_phys_port[i]);
|
|
||||||
else
|
|
||||||
itoa_html(i + 1);
|
|
||||||
|
|
||||||
if (IS_SFP(i)) {
|
if (machine.is_sfp[i]) {
|
||||||
slen += strtox(outbuf + slen, ",\"isSFP\":1");
|
slen += strtox(outbuf + slen, ",\"isSFP\":1");
|
||||||
} else {
|
} else {
|
||||||
slen += strtox(outbuf + slen, ",\"isSFP\":0,\"eee\":\"");
|
slen += strtox(outbuf + slen, ",\"isSFP\":0,\"eee\":\"");
|
||||||
@@ -299,7 +548,73 @@ void send_eee(void)
|
|||||||
bool_to_html(eee_ablty & (1 << i));
|
bool_to_html(eee_ablty & (1 << i));
|
||||||
}
|
}
|
||||||
char_to_html('}');
|
char_to_html('}');
|
||||||
if (i < maxPort)
|
if (i < machine.max_port)
|
||||||
|
char_to_html(',');
|
||||||
|
else
|
||||||
|
char_to_html(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_bandwidth(void)
|
||||||
|
{
|
||||||
|
dbg_string("send_bandwidth called\n");
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
|
char_to_html('[');
|
||||||
|
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||||
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
|
slen += strtox(outbuf + slen, ",\"iLimited\":");
|
||||||
|
reg_read_m(RTL837X_IGBW_PORT_CTRL + i * 4);
|
||||||
|
if (sfr_data[1] & 0x10)
|
||||||
|
char_to_html('1');
|
||||||
|
else
|
||||||
|
char_to_html('0');
|
||||||
|
slen += strtox(outbuf + slen, ",\"iBW\":\"");
|
||||||
|
byte_to_html(sfr_data[1] & 0x0f);
|
||||||
|
byte_to_html(sfr_data[2]);
|
||||||
|
byte_to_html(sfr_data[3]);
|
||||||
|
slen += strtox(outbuf + slen, "\",\"iFC\":");
|
||||||
|
if (reg_bit_test(RTL837X_IGBW_PORT_FC_CTRL, i))
|
||||||
|
char_to_html('1');
|
||||||
|
else
|
||||||
|
char_to_html('0');
|
||||||
|
reg_read_m(RTL837X_EGBW_PORT_CTRL + i * 1024);
|
||||||
|
slen += strtox(outbuf + slen, ",\"eLimited\":");
|
||||||
|
if (sfr_data[1] & 0x10)
|
||||||
|
char_to_html('1');
|
||||||
|
else
|
||||||
|
char_to_html('0');
|
||||||
|
slen += strtox(outbuf + slen, ",\"eBW\":\"");
|
||||||
|
byte_to_html(sfr_data[1] & 0x0f);
|
||||||
|
byte_to_html(sfr_data[2]);
|
||||||
|
byte_to_html(sfr_data[3]);
|
||||||
|
char_to_html('"');
|
||||||
|
char_to_html('}');
|
||||||
|
if (i < machine.max_port)
|
||||||
|
char_to_html(',');
|
||||||
|
else
|
||||||
|
char_to_html(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_mtu(void)
|
||||||
|
{
|
||||||
|
dbg_string("send_mtu called\n");
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
|
char_to_html('[');
|
||||||
|
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||||
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
|
slen += strtox(outbuf + slen, ",\"mtu\":\"0x");
|
||||||
|
reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) i << 8));
|
||||||
|
uint16_t mtu = SFR_DATA_U16 & 0x3fff;
|
||||||
|
byte_to_html(mtu >> 8);
|
||||||
|
byte_to_html(mtu & 0xff);
|
||||||
|
char_to_html('"');
|
||||||
|
char_to_html('}');
|
||||||
|
if (i < machine.max_port)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
else
|
||||||
char_to_html(']');
|
char_to_html(']');
|
||||||
@@ -310,41 +625,113 @@ void send_eee(void)
|
|||||||
void send_status(void)
|
void send_status(void)
|
||||||
{
|
{
|
||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
print_string("sending status\n");
|
dbg_string("sending status\n");
|
||||||
char_to_html('[');
|
char_to_html('[');
|
||||||
|
|
||||||
for (uint8_t i = minPort; i <= maxPort; i++) {
|
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||||
if (!isRTL8373)
|
itoa_html(machine.log_to_phys_port[i]);
|
||||||
itoa_html(log_to_phys_port[i]);
|
slen += strtox(outbuf + slen, ",\"logPort\":");
|
||||||
else
|
itoa_html(i);
|
||||||
itoa_html(i + 1);
|
slen += strtox(outbuf + slen, ",\"name\":\"");
|
||||||
|
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
||||||
if (IS_SFP(i)) {
|
char_to_html(port_names[i][j]);
|
||||||
slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":");
|
|
||||||
bool_to_html(!((sfp_pins_last >> (i == maxPort ? 0 : 4)) & 1));
|
|
||||||
|
|
||||||
slen += strtox(outbuf + slen, ",\"link\":");
|
|
||||||
uint8_t rate = sfp_read_reg(i == maxPort ? 0 : 1, 12);
|
|
||||||
if (rate == 0xd)
|
|
||||||
char_to_html('2'); // 1000BX
|
|
||||||
else if (rate == 0x1f)
|
|
||||||
char_to_html('5'); // 2G5
|
|
||||||
else if (rate > 0x65 && rate < 0x70)
|
|
||||||
char_to_html('4'); // 10G "4" is not a valid value for port LINK speed
|
|
||||||
else
|
|
||||||
char_to_html('1'); // 100M ???
|
|
||||||
} else {
|
|
||||||
slen += strtox(outbuf + slen, ",\"isSFP\":0,\"enabled\":");
|
|
||||||
phy_read(i, 0x1f, 0xa610);
|
|
||||||
bool_to_html(SFR_DATA_8 == 0x20);
|
|
||||||
|
|
||||||
slen += strtox(outbuf + slen, ",\"link\":");
|
|
||||||
reg_read_m(RTL837X_REG_LINKS);
|
|
||||||
uint8_t b = sfr_data[3 - (i >> 1)];
|
|
||||||
b = (i & 1) ? b >> 4 : b & 0xf;
|
|
||||||
char_to_html('0' + b);
|
|
||||||
}
|
}
|
||||||
|
slen += strtox(outbuf + slen, "\"");
|
||||||
|
|
||||||
|
if (machine.is_sfp[i]) {
|
||||||
|
slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":");
|
||||||
|
if (!(sfp_pins_last & (0x1 << ((machine.is_sfp[i] - 1) << 2)))) {
|
||||||
|
bool_to_html(1);
|
||||||
|
slen += strtox(outbuf + slen,",\"sfp_options\":\"0x");
|
||||||
|
byte_to_html(sfp_options[machine.is_sfp[i]-1]);
|
||||||
|
if (sfp_options[machine.is_sfp[i]-1] & 0x40) {
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 224, 2);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 226, 2);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_txbias\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 228, 2);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_txpower\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 230, 2);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 232, 2);
|
||||||
|
if (sfp_options[machine.is_sfp[i]-1] & 0x10) {
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 212, 4);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 216, 4);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 204, 4);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 208, 4);
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 184, 16);
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 200, 4);
|
||||||
|
}
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x");
|
||||||
|
sfp_send_data(machine.is_sfp[i] - 1, 238, 1);
|
||||||
|
}
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
||||||
|
for (register uint8_t s = 0; s < 16; s++)
|
||||||
|
outbuf[slen++] = sfp_module_vendor[machine.is_sfp[i]-1][s];
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
||||||
|
for (register uint8_t s = 0; s < 16; s++)
|
||||||
|
outbuf[slen++] = sfp_module_model[machine.is_sfp[i]-1][s];
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
||||||
|
for (register uint8_t s = 0; s < 16; s++)
|
||||||
|
outbuf[slen++] = sfp_module_serial[machine.is_sfp[i]-1][s];
|
||||||
|
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
||||||
|
if (machine.sfp_port[machine.is_sfp[i]-1].pin_los == GPIO_NA) {
|
||||||
|
slen += strtox(outbuf + slen,"null");
|
||||||
|
} else {
|
||||||
|
bool_to_html(sfp_pins_last & (0x2 << (((machine.is_sfp[i]-1) << 2))));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool_to_html(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slen += strtox(outbuf + slen, ",\"isSFP\":0,\"enabled\":");
|
||||||
|
phy_read(i, PHY_MMD31, 0xa610);
|
||||||
|
bool_to_html(SFR_DATA_8 == 0x20);
|
||||||
|
slen += strtox(outbuf + slen, ",\"adv\":\"");
|
||||||
|
phy_read(i, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL);
|
||||||
|
uint16_t w = SFR_DATA_U16;
|
||||||
|
bool_to_html(!!(w & 0x80)); // 2500BaseN-Full
|
||||||
|
phy_read(i, PHY_MMD31, PHY_MMD31_GBCR);
|
||||||
|
w = SFR_DATA_U16;
|
||||||
|
bool_to_html(!!(w & 0x0200)); // 1000Base-Full
|
||||||
|
phy_read(i, PHY_MMD_AN, PHY_ANEG_ADV);
|
||||||
|
w = SFR_DATA_U16;
|
||||||
|
bool_to_html(!!(w & 0x0100)); // 100Base-Full
|
||||||
|
bool_to_html(!!(w & 0x80)); // 100Base-Half
|
||||||
|
bool_to_html(!!(w & 0x40)); // 10Base-Full
|
||||||
|
bool_to_html(!!(w & 0x20)); // 10Base-Half
|
||||||
|
char_to_html('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
slen += strtox(outbuf + slen, ",\"link\":");
|
||||||
|
|
||||||
|
uint8_t b = 0;
|
||||||
|
// Determine link state
|
||||||
|
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||||
|
if(!((sfr_data[(i / 8) + 1] >> (i % 8 ) & 1)))
|
||||||
|
{
|
||||||
|
b = 0; //link down
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Determine link speed
|
||||||
|
if (i < 8)
|
||||||
|
reg_read_m(RTL837X_REG_LINKS);
|
||||||
|
else
|
||||||
|
reg_read_m(RTL837X_REG_LINKS_89);
|
||||||
|
|
||||||
|
b = sfr_data[3 - ((i & 7) >> 1)];
|
||||||
|
b = ((i & 1) ? b >> 4 : b & 0xf) + 1;
|
||||||
|
}
|
||||||
|
char_to_html('0' + b);
|
||||||
|
|
||||||
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
||||||
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||||
@@ -363,9 +750,71 @@ void send_status(void)
|
|||||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH); // 32bit RX packet errors
|
reg_to_html(RTL837X_STAT_V_HIGH); // 32bit RX packet errors
|
||||||
slen += strtox(outbuf + slen, "\"}");
|
slen += strtox(outbuf + slen, "\"}");
|
||||||
if (i < maxPort)
|
if (i < machine.max_port)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
else
|
else
|
||||||
char_to_html(']');
|
char_to_html(']');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_config(void)
|
||||||
|
{
|
||||||
|
dbg_string("send_config called\n");
|
||||||
|
__xdata uint32_t pos = CONFIG_START;
|
||||||
|
__xdata uint16_t valid_len = 0;
|
||||||
|
__xdata uint16_t len_left = CONFIG_LEN;
|
||||||
|
__xdata uint8_t flash_buf[256];
|
||||||
|
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_TXT);
|
||||||
|
|
||||||
|
// Scan through config to find the end of valid data (null terminator)
|
||||||
|
do {
|
||||||
|
flash_region.addr = pos;
|
||||||
|
flash_region.len = (len_left > 256) ? 256 : len_left;
|
||||||
|
flash_read_bulk(flash_buf);
|
||||||
|
|
||||||
|
// Look for null terminator in this chunk
|
||||||
|
for (uint16_t i = 0; i < flash_region.len; i++) {
|
||||||
|
if (flash_buf[i] == 0) {
|
||||||
|
// Found end of valid data
|
||||||
|
valid_len += i;
|
||||||
|
goto found_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valid_len += flash_region.len;
|
||||||
|
len_left -= flash_region.len;
|
||||||
|
pos += flash_region.len;
|
||||||
|
} while (len_left > 0);
|
||||||
|
|
||||||
|
found_end:
|
||||||
|
// Now send the valid data
|
||||||
|
if (valid_len > (TCP_OUTBUF_SIZE - slen)) {
|
||||||
|
cont_len = valid_len - (TCP_OUTBUF_SIZE - slen);
|
||||||
|
valid_len = TCP_OUTBUF_SIZE - slen;
|
||||||
|
cont_addr = valid_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_region.addr = CONFIG_START;
|
||||||
|
flash_region.len = valid_len;
|
||||||
|
flash_read_bulk(outbuf + slen);
|
||||||
|
slen += valid_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_cmd_log(void)
|
||||||
|
{
|
||||||
|
dbg_string("send_cmd_log called\n");
|
||||||
|
slen = strtox(outbuf, HTTP_RESPONCE_TXT);
|
||||||
|
__xdata uint16_t p = (cmd_history_ptr + 1) & CMD_HISTORY_MASK;
|
||||||
|
__xdata uint8_t found_begin = 0;
|
||||||
|
dbg_string("History ptr: ");
|
||||||
|
dbg_short(cmd_history_ptr); dbg_char('\n');
|
||||||
|
while (p != cmd_history_ptr) {
|
||||||
|
if (!cmd_history[p] || cmd_history[p] == '\n')
|
||||||
|
found_begin = 1;
|
||||||
|
if (found_begin && cmd_history[p])
|
||||||
|
outbuf[slen++] = cmd_history[p];
|
||||||
|
p = (p + 1) & CMD_HISTORY_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,9 +3,31 @@
|
|||||||
|
|
||||||
void send_counters(char port);
|
void send_counters(char port);
|
||||||
void send_status(void);
|
void send_status(void);
|
||||||
void send_vlan(register uint16_t vlan);
|
void send_vlan(uint16_t vlan);
|
||||||
void send_basic_info(void);
|
void send_basic_info(void);
|
||||||
|
void send_bandwidth(void);
|
||||||
void send_eee(void);
|
void send_eee(void);
|
||||||
|
void send_l2(uint16_t idx);
|
||||||
|
void l2_delete(uint16_t idx);
|
||||||
void send_mirror(void);
|
void send_mirror(void);
|
||||||
|
void send_mtu(void);
|
||||||
|
void send_config(void);
|
||||||
|
void send_cmd_log(void);
|
||||||
|
void send_lag(void);
|
||||||
|
|
||||||
|
/* Convert only the lower nibble to ascii HEX char.
|
||||||
|
For convenience the upper nibble is masked out.
|
||||||
|
*/
|
||||||
|
inline char itohex(uint8_t val) {
|
||||||
|
// Ignore upper nibble for convenience.
|
||||||
|
val &= 0x0f;
|
||||||
|
val -= 10;
|
||||||
|
|
||||||
|
// 10 or above
|
||||||
|
if ((int8_t)val >= 0)
|
||||||
|
val += ('a' - '0' - 10);
|
||||||
|
|
||||||
|
return val + ('0' + 10);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "../rtl837x_sfr.h"
|
#include "../rtl837x_sfr.h"
|
||||||
#include "../rtl837x_regs.h"
|
#include "../rtl837x_regs.h"
|
||||||
|
|
||||||
#define SYS_TICK_HZ 100
|
// See setup_serial_timer1() for valid baudrate settings!
|
||||||
#define SERIAL_BAUD_RATE 57600
|
#define SERIAL_BAUD_RATE 57600
|
||||||
#define CLOCK_HZ 125000000
|
#define CLOCK_HZ 125000000
|
||||||
|
|
||||||
@@ -26,10 +26,6 @@
|
|||||||
#define CLOCK_DIV 0
|
#define CLOCK_DIV 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
volatile __xdata uint32_t ticks;
|
|
||||||
volatile __xdata uint8_t sec_counter;
|
|
||||||
volatile __xdata uint16_t sleep_ticks;
|
|
||||||
|
|
||||||
// We buffer 1 sector as this is also the erase size
|
// We buffer 1 sector as this is also the erase size
|
||||||
__xdata uint8_t buffer[0x1000];
|
__xdata uint8_t buffer[0x1000];
|
||||||
__xdata uint8_t dio_enabled;
|
__xdata uint8_t dio_enabled;
|
||||||
@@ -38,16 +34,6 @@ __code uint8_t * __code hex = "0123456789abcdef";
|
|||||||
|
|
||||||
void isr_timer0(void) __interrupt(1)
|
void isr_timer0(void) __interrupt(1)
|
||||||
{
|
{
|
||||||
TR0 = 0; // Stop timer 0
|
|
||||||
TH0 = (0x10000 - (CLOCK_HZ / SYS_TICK_HZ / 32)) >> 8;
|
|
||||||
TL0 = (0x10000 - (CLOCK_HZ / SYS_TICK_HZ / 32)) % 0xff;
|
|
||||||
|
|
||||||
ticks++;
|
|
||||||
if (sleep_ticks > 0)
|
|
||||||
sleep_ticks--;
|
|
||||||
sec_counter++;
|
|
||||||
|
|
||||||
TR0 = 1; // Re-start timer 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,25 +88,52 @@ void print_short(uint16_t a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_serial(void)
|
/* Set up serial port 0 using Timer 1 as baudrate generator.
|
||||||
|
* For x Bd these settings are needed, see table below.
|
||||||
|
* NOTE: Settings only valid for F_SYS = 125 MHz!
|
||||||
|
* | Wanted | | TMR | F_SYS | | Actual | |
|
||||||
|
* | baudrate | SMOD0 | DIV | DIV | TH1 | baudrate | Error |
|
||||||
|
* | -------- | ----- | --- | ----- | ---- | -------- | ------ |
|
||||||
|
* | 1200 | 0 | 12 | 255 | 0x01 | 1276.6 | 6.00% |
|
||||||
|
* | 2400 | 0 | 12 | 136 | 0x78 | 2393.5 | −0.27% |
|
||||||
|
* | 4800 | 0 | 4 | 203 | 0x35 | 4810.7 | 0.22% |
|
||||||
|
* | 9600 | 1 | 4 | 203 | 0x35 | 9621.3 | 0.22% |
|
||||||
|
* | 14400 | 1 | 4 | 136 | 0x78 | 14361.2 | −0.27% |
|
||||||
|
* | 19200 | 1 | 4 | 102 | 0x9a | 19148.3 | −0.27% |
|
||||||
|
* | 38400 | 1 | 4 | 51 | 0xcd | 38296.6 | −0.27% |
|
||||||
|
* | 57600 | 1 | 4 | 34 | 0xde | 57444.9 | −0.27% |
|
||||||
|
* | 115200 | 1 | 4 | 17 | 0xef | 114889.7 | −0.27% |
|
||||||
|
*/
|
||||||
|
#if CLOCK_HZ != 125000000
|
||||||
|
#warning "SERIAL 0 baudrate setting may only valid for F_CPU = 125 MHz!"
|
||||||
|
#endif
|
||||||
|
void setup_serial_timer1(void)
|
||||||
{
|
{
|
||||||
IE = 0;
|
// Timer 1: Mode 2: automatic reload
|
||||||
|
TMOD &= 0x0F;
|
||||||
|
TMOD |= 0x20; // Timer1: Mode2: Timer, 8-bit with auto-reload
|
||||||
|
CKCON |= 0x10; // Timer1 clock divider: F_SYS / 4: T2M = 1, Timer 1 uses clk/4
|
||||||
|
|
||||||
T2CON = 0x34; // Enable RCLK/TCLK (serial transmit/receive clock for T2), TR2 (Timer 2 RUN), disable CP/RL2 (bit 0)
|
PCON |= 0x80; // SMOD0 = 1; Double the Baud Rate, don't divide Timer 1 Overflag signal.
|
||||||
SCON = 0x50; // Mode = 1: ASYNC 8N1 with T2 as baud-rate generator, REN_0 Receive enable
|
|
||||||
|
|
||||||
// The RCAP2 registers contain the high/low byte that is loaded into
|
SCON = 0x50; // Mode = 1: ASYNC 8N1 with Timer 2 as baud-rate generator, REN_0 Receive enable
|
||||||
// timer2 when T2 overflows to 0x10000
|
|
||||||
RCAP2H = (0x10000 - (CLOCK_HZ / SERIAL_BAUD_RATE / 32)) >> 8;
|
|
||||||
RCAP2L = (0x10000 - (CLOCK_HZ / SERIAL_BAUD_RATE / 32)) % 0xff;
|
|
||||||
|
|
||||||
PCON |= 0x80; // Double the Baud Rate
|
/* The TH1 register contain the reload value, timer1 when T1 overflows to 0x100.
|
||||||
|
* NOTE: compiler computs the wrong value. 0xF0 is calculated but 0xEF is the right value for 115200.
|
||||||
|
* Also https://www.keil.com/products/c51/baudrate.asp confirms this.
|
||||||
|
* Added 32 before div by 64 to make sure rounding is correct so that the results are right.
|
||||||
|
*
|
||||||
|
* TH1 = 0x100 - (2^SMOD0 * F_SYS) / ( TMR1_DIV / BAUDRATE * 32)
|
||||||
|
*/
|
||||||
|
TH1 = (0x100 - (((CLOCK_HZ / SERIAL_BAUD_RATE) + 32) / (4 * 16))) & 0xff;
|
||||||
|
|
||||||
SCON = 0x50;
|
TCON |= 0x40; // Start timer 1
|
||||||
TI = 1;
|
|
||||||
RI = 0;
|
|
||||||
|
|
||||||
ES = 1; // Enable serial IRQ
|
ET1 = 0; // Timer1 Interrupt is NOT wanted!
|
||||||
|
TI = 1; // Set TI-interrupt/flag, to flag that the TX-buf is empty.
|
||||||
|
RI = 0; // Clear RI-interrupt flag
|
||||||
|
|
||||||
|
ES = 0; // Disable serial IRQ, software is only printing data and just polls TI-flag.
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -345,10 +358,7 @@ void installer(void)
|
|||||||
IE = 0;
|
IE = 0;
|
||||||
EIE = 0; // SFR e8: EIE. Disable all external IRQs
|
EIE = 0; // SFR e8: EIE. Disable all external IRQs
|
||||||
|
|
||||||
// Disable all interrupts (global interrupt enable bit)
|
setup_serial_timer1();
|
||||||
EA = 0; // SFR A8.7 / IE.7
|
|
||||||
|
|
||||||
setup_serial();
|
|
||||||
print_string("\nRTLPlayground installer starting...\n");
|
print_string("\nRTLPlayground installer starting...\n");
|
||||||
|
|
||||||
// Initialize flash functions with disable DIO because writing does not work otherwise
|
// Initialize flash functions with disable DIO because writing does not work otherwise
|
||||||
|
|||||||
@@ -0,0 +1,576 @@
|
|||||||
|
#include "machine.h"
|
||||||
|
#include "rtl837x_pins.h"
|
||||||
|
#include "rtl837x_leds.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
|
||||||
|
#ifdef MACHINE_KP_9000_6XHML_X2
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "keepLink KP-9000-6XHML-X2",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
|
||||||
|
// Left SFP port (5)
|
||||||
|
.sfp_port[0].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
|
.sfp_port[0].pin_los = GPIO10_LED10,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 0,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
// Right SFP port (6)
|
||||||
|
.sfp_port[1].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[1].pin_los = GPIO37,
|
||||||
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[1].sds = 1,
|
||||||
|
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
/* Conditions for LED on:
|
||||||
|
* dual led orange: ledset_0 & ledset_2
|
||||||
|
* dual led green: ledset_2 & !ledset_0
|
||||||
|
* single right led green: ledset_0 & !ledset_1
|
||||||
|
*/
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_10G,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_KP_9000_6XH_X
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "keepLink KP-9000-6XH-X",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
/* Conditions for LED on:
|
||||||
|
* dual led orange: ledset_0 & ledset_2
|
||||||
|
* dual led green: ledset_2 & !ledset_0
|
||||||
|
* single right led green: ledset_0 & !ledset_1
|
||||||
|
*/
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_10G,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_KP_9000_9XH_X_EU
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "keepLink KP-9000-9XH-X-EU",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_KP_9000_9XHML_X_V2_2
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "keepLink KP-9000-9XHML-X V2.2",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||||
|
.phys_to_log_port = { 0, 1, 2, 3, 4, 5, 6, 7, 8 },
|
||||||
|
.is_sfp = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||||
|
.led_sets = {
|
||||||
|
{ /* Set 0 for RJ45 connectors */
|
||||||
|
/* LED0: Right Green */
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
/* LED1: Left Orange */
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
/* LED2: Left Green */
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
/* LED3: None */
|
||||||
|
0,
|
||||||
|
}, { /* Set 1 for SFP port */
|
||||||
|
/* LED0: Single Green "9" LED */
|
||||||
|
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||||
|
/* LED1: D23 LED on PCB */
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
/* LED2: D22 LED on PCB */
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
/* LED3: Unused */
|
||||||
|
LEDS_COL | LEDS_DUPLEX,
|
||||||
|
}, { /* Set 2: Unused, but set to same things as stock firmware for consistency */
|
||||||
|
LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
LEDS_1G | LEDS_LINK | LEDS_ACT,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT | LEDS_5G,
|
||||||
|
LEDS_10G | LEDS_ACT | LEDS_LINK,
|
||||||
|
}, { /* Set 3: Unused, but set to same things as stock firmware for consistency */
|
||||||
|
LEDS_TX,
|
||||||
|
LEDS_RX,
|
||||||
|
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||||
|
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_KP_9000_9XHML_X_V3_1
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "keepLink KP-9000-9XHML-X V3.1",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO48_I2C_SCL1,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = {
|
||||||
|
{ /* RJ45: First LED, yellow, second LED: green */
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}, { /* SFP PORT, SINGLE GREEN LED */
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}},
|
||||||
|
.led_mux_custom = 1,
|
||||||
|
.led_mux = {0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x09, 0x0d, 0x10,
|
||||||
|
0x11, 0x0e, 0x14, 0x11, 0x12, 0x15, 0x15, 0x16, 0x18, 0x19,
|
||||||
|
0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_SWGT024_V2_0_MANAGED
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "SWGT024 V2.0 Managed",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
||||||
|
.is_sfp= {0, 0, 0, 2, 0, 0, 0, 0, 1},
|
||||||
|
// Left SFP port (J4)
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
||||||
|
// Right SFP port (J2)
|
||||||
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[1].sds = 0,
|
||||||
|
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
/* Green LED */
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
0,
|
||||||
|
/* Amber LED */
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_SWGT024_V2_0_UNMANAGED
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "SWGT024 V2.0 Unmanaged",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
||||||
|
.is_sfp= {0, 0, 0, 2, 0, 0, 0, 0, 1},
|
||||||
|
// Left SFP port (J4)
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
||||||
|
// Right SFP port (J2)
|
||||||
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
|
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||||
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[1].sds = 0,
|
||||||
|
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
/* Green LED */
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
0,
|
||||||
|
/* Amber LED */
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_SWTG018AS_A_V_2_0
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "SWTG018AS-A V2.0",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = {
|
||||||
|
{ /* RJ45: First LED, yellow, second LED: green */
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}, { /* SFP PORT, SINGLE GREEN LED */
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}},
|
||||||
|
.led_mux_custom = 1,
|
||||||
|
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
|
||||||
|
0x09, 0x0c, 0x09, 0x0d, 0x10, // 65e4
|
||||||
|
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
|
||||||
|
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
|
||||||
|
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
|
||||||
|
0x1d, 0x20, 0x21 },
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_HG0402XG_V1_1
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "HG0402XG V1.1",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = 50,
|
||||||
|
.sfp_port[0].pin_los = 10,
|
||||||
|
.sfp_port[0].pin_tx_disable = 0xFF,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.sfp_port[1].pin_detect = 30,
|
||||||
|
.sfp_port[1].pin_los = 51,
|
||||||
|
.sfp_port[1].pin_tx_disable = 0xFF,
|
||||||
|
.sfp_port[1].sds = 0,
|
||||||
|
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 , .enable = LED_27 | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
|
/* The Ethernet ports have 1 amber LED (left) and 1 green LED (right)
|
||||||
|
* The SFP ports have also 1 amber LED and 1 green LED
|
||||||
|
* Ethernet ports use LED-set 0, SFP ports use LED-set 1
|
||||||
|
*/
|
||||||
|
.led_sets = { { LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
0 },
|
||||||
|
{ LEDS_100M | LEDS_10M | LEDS_LINK,
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
LEDS_10G | LEDS_LINK,
|
||||||
|
0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_SWTGW218AS
|
||||||
|
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "SWTGW218AS 8+1 Managed Switch",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
|
||||||
|
0, // unused
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
|
||||||
|
0
|
||||||
|
}, // unused
|
||||||
|
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
|
||||||
|
0, // unused
|
||||||
|
0, // unused
|
||||||
|
0
|
||||||
|
}, // unused },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
#elif defined MACHINE_LIANGUO_ZX_SWTGW215AS // Has PCB branded PCB-SWTG115AS-V2.0 but is labeled and reports as a ZX-SWTGW215AS, seems to be identical to the "real" ZX-SWTGW215AS except for the LEDs
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "Lianguo ZX-SWTGW215AS",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
|
||||||
|
0, // unused
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
|
||||||
|
0
|
||||||
|
}, // unused
|
||||||
|
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
|
||||||
|
0, // unused
|
||||||
|
0, // unused
|
||||||
|
0
|
||||||
|
}, // unused },
|
||||||
|
},
|
||||||
|
.led_mux_custom = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_DEFAULT_8C_1SFP
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "8+1 SFP Port Switch",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||||
|
LEDS_2G5 | LEDS_LINK,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_TRENDNET_TEG_S562
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "Trendnet TEG-S562",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
|
||||||
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
|
.sfp_port[0].pin_los = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO54_ACL_BIT2_EN,
|
||||||
|
.sfp_port[0].sds = 0,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO47_I2C_SDA0, .scl = GPIO46_I2C_SCL0 },
|
||||||
|
.sfp_port[1].pin_detect = GPIO36_PWM_OUT,
|
||||||
|
.sfp_port[1].pin_los = GPIO37,
|
||||||
|
.sfp_port[1].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
|
||||||
|
.sfp_port[1].sds = 1,
|
||||||
|
.sfp_port[1].i2c = { .sda = GPIO49_I2C_SDA1, .scl = GPIO48_I2C_SCL1 },
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
0, // Unused
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber
|
||||||
|
0 // Unused
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, // Unused
|
||||||
|
0, // Unused
|
||||||
|
LEDS_10G | LEDS_1G | LEDS_LINK | LEDS_ACT, // Green
|
||||||
|
0, // Unused
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#elif defined MACHINE_HI_K0402WS
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "HiSource HI-K0402WS",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 2,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
|
||||||
|
|
||||||
|
// Left SFP port
|
||||||
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
|
||||||
|
// Right SFP port
|
||||||
|
.sfp_port[1].pin_detect = GPIO37,
|
||||||
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
|
.sfp_port[1].sds = 0,
|
||||||
|
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_10M | LEDS_ACT,
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
|
||||||
|
LEDS_1G | LEDS_LINK,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK,
|
||||||
|
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.led_mux_custom = 1,
|
||||||
|
.led_mux = {
|
||||||
|
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) {
|
||||||
|
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined MACHINE_K0501W_V2_0
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "K0501W V2.0",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 1,
|
||||||
|
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||||
|
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||||
|
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
|
||||||
|
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
|
.sfp_port[0].sds = 1,
|
||||||
|
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||||
|
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void) { }
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Please select a machine type in machine.h"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef _MACHINE_H_
|
||||||
|
#define _MACHINE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select your machine type below
|
||||||
|
*/
|
||||||
|
#define MACHINE_KP_9000_6XHML_X2
|
||||||
|
// #define MACHINE_KP_9000_6XH_X
|
||||||
|
// #define MACHINE_KP_9000_9XH_X_EU
|
||||||
|
// #define MACHINE_KP_9000_9XHML_X_V2_2
|
||||||
|
// #define MACHINE_KP_9000_9XHML_X_V3_1
|
||||||
|
// #define MACHINE_SWGT024_V2_0_MANAGED
|
||||||
|
// #define MACHINE_SWGT024_V2_0_UNMANAGED
|
||||||
|
// #define MACHINE_TRENDNET_TEG_S562
|
||||||
|
// #define MACHINE_HG0402XG_V1_1
|
||||||
|
// #define MACHINE_SWTG018AS_A_V_2_0
|
||||||
|
// #define MACHINE_SWTGW218AS
|
||||||
|
// #define MACHINE_HI_K0402WS
|
||||||
|
// #define MACHINE_K0501W_V2_0
|
||||||
|
// #define MACHINE_LIANGUO_ZX_SWTGW215AS
|
||||||
|
// #define MACHINE_DEFAULT_8C_1SFP
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// GPIO pins for SDA/SCL
|
||||||
|
uint8_t sda;
|
||||||
|
uint8_t scl;
|
||||||
|
} i2c_bus_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define LED_27 1
|
||||||
|
// SYSTEM LED
|
||||||
|
#define LED_28_SYS 2
|
||||||
|
#define LED_29 4
|
||||||
|
|
||||||
|
struct high_leds {
|
||||||
|
// Defines MUX and LED enabling for pins 27-29
|
||||||
|
uint8_t mux : 3;
|
||||||
|
uint8_t enable : 3;
|
||||||
|
uint8_t reserved : 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfp_port
|
||||||
|
{
|
||||||
|
uint8_t pin_detect; // gpio number 0-63, 0xFF = don't have it?
|
||||||
|
uint8_t pin_los; // gpio number 0-63, 0xFF = don't have it?
|
||||||
|
uint8_t pin_tx_disable; // gpio number 0-63, 0xFF = not present
|
||||||
|
uint8_t sds;
|
||||||
|
i2c_bus_t i2c;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct machine {
|
||||||
|
char machine_name[30];
|
||||||
|
uint8_t isRTL8373;
|
||||||
|
// Lowest logical port number
|
||||||
|
uint8_t min_port;
|
||||||
|
// Highest logical port number
|
||||||
|
uint8_t max_port;
|
||||||
|
uint8_t n_sfp;
|
||||||
|
uint8_t log_to_phys_port[9];
|
||||||
|
uint8_t phys_to_log_port[9]; // Starts at 0 for port 1
|
||||||
|
uint8_t is_sfp[9]; // 0 for non-SFP ports 1 or 2 for the I2C port number
|
||||||
|
// sfp_port[0] is the first SFP-port from the left on the device, sfp_port[1] the next if present
|
||||||
|
struct sfp_port sfp_port[2];
|
||||||
|
uint8_t reset_pin;
|
||||||
|
struct high_leds high_leds;
|
||||||
|
// Defines which led-set (0-3) will be used for given logical port
|
||||||
|
// led-set is physical group of LEDs that can be configured to show different port status combinations (see port_led_set below)
|
||||||
|
uint8_t port_led_set[9];
|
||||||
|
// Defines led-set configuration, applied to all ports using particular led-set
|
||||||
|
// Each led-set can have 4 different hardware LED configurations. Which one should be used, depends how LED is wired on the board
|
||||||
|
// See stock RTL837X_REG_LED3_2_SETx and RTL837X_REG_LED1_0_SETx registers for reference configuration
|
||||||
|
uint32_t led_sets[4][4];
|
||||||
|
uint8_t led_mux_custom;
|
||||||
|
uint8_t led_mux[28];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct machine_runtime
|
||||||
|
{
|
||||||
|
uint8_t isRTL8373 : 1;
|
||||||
|
uint8_t isN : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
void machine_custom_init(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -11,15 +11,19 @@
|
|||||||
/*
|
/*
|
||||||
* Define PHY pages
|
* Define PHY pages
|
||||||
*/
|
*/
|
||||||
|
#define PHY_MMD_PMAPMD 1
|
||||||
#define PHY_MMD_AN 7
|
#define PHY_MMD_AN 7
|
||||||
#define PHY_SDS_CTRL 30
|
#define PHY_MMD30 30
|
||||||
#define PHY_MMD_CTRL 31
|
#define PHY_MMD31 31
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define registers in Auto-Negotiation page
|
* Define registers in Auto-Negotiation page
|
||||||
*/
|
*/
|
||||||
#define PHY_ANEG_CTRL 0x00
|
#define PHY_ANEG_CTRL 0x00
|
||||||
|
#define PHY_ANEG_ADV 0x10
|
||||||
|
#define PHY_ANEG_LP_ABILITY 0x13
|
||||||
|
#define PHY_ANEG_MGBASE_CTRL 0x20
|
||||||
|
#define PHY_ANEG_MGBASE_ADV 0x21
|
||||||
#define PHY_EEE_ADV 0x3c
|
#define PHY_EEE_ADV 0x3c
|
||||||
#define PHY_EEE_LP_ABILITY 0x3d
|
#define PHY_EEE_LP_ABILITY 0x3d
|
||||||
#define PHY_EEE_ADV2 0x3e
|
#define PHY_EEE_ADV2 0x3e
|
||||||
@@ -29,8 +33,26 @@
|
|||||||
#define PHY_EEE_BIT_1G 0x04
|
#define PHY_EEE_BIT_1G 0x04
|
||||||
#define PHY_EEE_BIT_100M 0x02
|
#define PHY_EEE_BIT_100M 0x02
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MMD 31 Registers
|
||||||
|
*/
|
||||||
|
#define PHY_MMD31_FEDCR 0xa400
|
||||||
|
#define PHY_MMD31_GBCR 0xa412
|
||||||
|
#define PHY_MMD31_GANLPAR 0xa414
|
||||||
|
#define PHY_MMD31_PHYCR2 0xa432
|
||||||
|
#define PHY_MMD31_PHYSR 0xa434
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define registers in Control page
|
* Define registers in Control page
|
||||||
*/
|
*/
|
||||||
#define PHY_CTRL_5 0x7582
|
#define PHY_CTRL_5 0x7582
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Duplex settings
|
||||||
|
*/
|
||||||
|
#define PHY_DUPLEX_HALF 0
|
||||||
|
#define PHY_DUPLEX_FULL 1
|
||||||
|
#define PHY_DUPLEX_BOTH 2
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// #define REGDBG
|
||||||
|
// #define DEBUG
|
||||||
|
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_sfr.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "rtl837x_bandwidth.h"
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
#pragma codeseg BANK2
|
||||||
|
#pragma constseg BANK2
|
||||||
|
|
||||||
|
extern __xdata uint8_t sfr_data[4];
|
||||||
|
|
||||||
|
void bandwidth_setup(void) __banked
|
||||||
|
{
|
||||||
|
print_string("bandwidth_setup called\n");
|
||||||
|
// Exclude all packets possibly for the CPU port, but do not include bypassed packets or Inter-Frame-Gap into bandwidth
|
||||||
|
REG_SET(RTL837X_IGBW_CTRL, IGBW_ADM_DHCP | IGBW_ADM_ARPREQ | IGBW_ADM_RMA | IGBW_ADM_BPDU | IGBW_ADM_RTKPKT | IGBW_ADM_IGMP);
|
||||||
|
|
||||||
|
// We do not count IFG for Egress and allways allow CPU-traffic
|
||||||
|
REG_SET(RTL837X_EGBW_CTRL, EGBW_CPUMODE);
|
||||||
|
|
||||||
|
print_string("RTL837X_IGBW_CTRL: "); print_reg(RTL837X_IGBW_CTRL); write_char('\n');
|
||||||
|
print_string("RTL837X_EGBW_CTRL: "); print_reg(RTL837X_EGBW_CTRL); write_char('\n');
|
||||||
|
print_string("bandwidth_setup done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the ingress bandwidth
|
||||||
|
* bw: Bandwidth in kb
|
||||||
|
*/
|
||||||
|
void bandwidth_ingress_set(uint8_t port, __xdata uint32_t bw) __banked
|
||||||
|
{
|
||||||
|
__xdata uint8_t * __xdata bwptr = &bw;
|
||||||
|
|
||||||
|
print_string("bandwidth_ingress_set called, port "); print_byte(port); write_char('\n');
|
||||||
|
sfr_data[0] = 0;
|
||||||
|
sfr_data[1] = 0x10 | (*(bwptr + 2) >> 4); // Set bit 20 to enable ingress bandwidth control
|
||||||
|
sfr_data[2] = (*(bwptr + 2) << 4) | (*(bwptr + 1) >> 4);
|
||||||
|
sfr_data[3] = (*(bwptr) >> 4) | (*(bwptr + 1) << 4);
|
||||||
|
reg_write_m(RTL837X_IGBW_PORT_CTRL + port * 4);
|
||||||
|
|
||||||
|
// We enable Flow Control instead of just dropping packets
|
||||||
|
reg_bit_set(RTL837X_IGBW_PORT_FC_CTRL, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bandwidth_ingress_drop(uint8_t port) __banked
|
||||||
|
{
|
||||||
|
reg_bit_clear(RTL837X_IGBW_PORT_FC_CTRL, port);
|
||||||
|
print_string("RTL837X_IGBW_PORT_FC_CTRL:"); print_reg(RTL837X_IGBW_PORT_FC_CTRL); write_char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bandwidth_ingress_fc(uint8_t port) __banked
|
||||||
|
{
|
||||||
|
reg_bit_set(RTL837X_IGBW_PORT_FC_CTRL, port);
|
||||||
|
print_string("RTL837X_IGBW_PORT_FC_CTRL:"); print_reg(RTL837X_IGBW_PORT_FC_CTRL); write_char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bandwidth_ingress_disable(uint8_t port) __banked
|
||||||
|
{
|
||||||
|
print_string("Ingress bandwidth limit disabled, port "); print_byte(port); write_char('\n');
|
||||||
|
REG_SET(RTL837X_IGBW_PORT_CTRL + port * 4, 0x0fffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bandwidth_egress_set(uint8_t port, __xdata uint32_t bw) __banked
|
||||||
|
{
|
||||||
|
__xdata uint8_t * __xdata bwptr = &bw;
|
||||||
|
|
||||||
|
print_string("bandwidth_egress_set called, port "); print_byte(port); write_char('\n');
|
||||||
|
sfr_data[0] = 0;
|
||||||
|
sfr_data[1] = 0x10 | (*(bwptr + 2) >> 4); // Set bit 20 to enable egress bandwidth control
|
||||||
|
sfr_data[2] = (*(bwptr + 2) << 4) | (*(bwptr + 1) >> 4);
|
||||||
|
sfr_data[3] = (*(bwptr) >> 4) | (*(bwptr + 1) << 4);
|
||||||
|
reg_write_m(RTL837X_EGBW_PORT_CTRL + port * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bandwidth_egress_disable(uint8_t port) __banked
|
||||||
|
{
|
||||||
|
print_string("Egress bandwidth limit disabled, port "); print_byte(port); write_char('\n');
|
||||||
|
REG_SET(RTL837X_EGBW_PORT_CTRL + port * 1024, 0x0fffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bandwidth_status(uint8_t port) __banked
|
||||||
|
{
|
||||||
|
print_string("ingress: ");
|
||||||
|
reg_read_m(RTL837X_IGBW_PORT_CTRL + port * 4);
|
||||||
|
if (sfr_data[1] & 0x10) {
|
||||||
|
print_string("enabled: ");
|
||||||
|
sfr_data[1] &= 0xef;
|
||||||
|
print_string("0x");
|
||||||
|
print_byte(sfr_data[1]);
|
||||||
|
print_byte(sfr_data[2]);
|
||||||
|
print_byte(sfr_data[3]);
|
||||||
|
write_char('0');
|
||||||
|
write_char('\n');
|
||||||
|
} else {
|
||||||
|
print_string("disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_string("egress: ");
|
||||||
|
reg_read_m(RTL837X_EGBW_PORT_CTRL + port * 1024);
|
||||||
|
if (sfr_data[1] & 0x10) {
|
||||||
|
print_string("enabled: ");
|
||||||
|
sfr_data[1] &= 0xef;
|
||||||
|
print_string("0x");
|
||||||
|
print_byte(sfr_data[1]);
|
||||||
|
print_byte(sfr_data[2]);
|
||||||
|
print_byte(sfr_data[3]);
|
||||||
|
write_char('0');
|
||||||
|
write_char('\n');
|
||||||
|
} else {
|
||||||
|
print_string("disabled\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _RTL837X_BANDWIDTH_H_
|
||||||
|
#define _RTL837X_BANDWIDTH_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void bandwidth_setup(void) __banked;
|
||||||
|
void bandwidth_ingress_set(uint8_t port, __xdata uint32_t bw) __banked;
|
||||||
|
void bandwidth_ingress_disable(uint8_t port) __banked;
|
||||||
|
void bandwidth_ingress_drop(uint8_t port) __banked;
|
||||||
|
void bandwidth_ingress_fc(uint8_t port) __banked;
|
||||||
|
void bandwidth_egress_set(uint8_t port, __xdata uint32_t bw) __banked;
|
||||||
|
void bandwidth_egress_disable(uint8_t port) __banked;
|
||||||
|
void bandwidth_status(uint8_t port) __banked;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -3,49 +3,94 @@
|
|||||||
|
|
||||||
#include "uip/uip-conf.h"
|
#include "uip/uip-conf.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
// This has to be set to the number of SFP+ ports, i.e. 1 or 2
|
#define SYS_TICK_HZ 200
|
||||||
#define NSFP 2
|
|
||||||
// SCL and SDA pin numbers for SFP cage 0 and SFP cage 1
|
#define CPU_PORT 9
|
||||||
#define SCL_PIN 3
|
|
||||||
#define SDA_PIN_0 4
|
|
||||||
#define SDA_PIN_1 3
|
|
||||||
|
|
||||||
// Define Port-masks for 9-port devices and 6-port devices
|
// Define Port-masks for 9-port devices and 6-port devices
|
||||||
#define PMASK_9 0x1ff
|
#define PMASK_9 0x1ff
|
||||||
#define PMASK_6 0x1f8
|
#define PMASK_6 0x1f8
|
||||||
#define PMASK_CPU 0x200
|
#define PMASK_CPU 0x200
|
||||||
|
|
||||||
// The serial buffer. Defines the command line size
|
// Defines a port mask for dropping all packets on Lookup-miss
|
||||||
// Must be 2^x and <= 128
|
#define LOOKUP_MISS_DROP_6 0x00015540
|
||||||
#define SBUF_SIZE 128
|
#define LOOKUP_MISS_DROP_9 0x00015555
|
||||||
|
#define LOOKUP_MISS_FLOOD 0x00000000
|
||||||
|
|
||||||
|
/* Buffer for serial input, SBUF_SIZE must be power of 2 < 256
|
||||||
|
* Writing to this buffer is under the sole control of the serial ISR
|
||||||
|
* Note that key-presses such as <cursor-left> can create multiple
|
||||||
|
* keys (3 to 4) being sent via the serial line, so this must be
|
||||||
|
* sufficiently large */
|
||||||
|
#define SBUF_SIZE 16
|
||||||
|
#define SBUF_MASK (SBUF_SIZE - 1)
|
||||||
|
|
||||||
|
extern __xdata volatile uint8_t sbuf_ptr;
|
||||||
|
extern __xdata uint8_t sbuf[SBUF_SIZE];
|
||||||
|
|
||||||
|
// Define the command buffer size, Must be 2^x and <= 128
|
||||||
|
#define CMD_BUF_SIZE 128
|
||||||
|
|
||||||
// Size of the TCP Output buffer
|
// Size of the TCP Output buffer
|
||||||
#define TCP_OUTBUF_SIZE 2500
|
#define TCP_OUTBUF_SIZE 2500
|
||||||
|
|
||||||
|
// Size of the port name, including the terminating null byte
|
||||||
|
#define PORT_NAME_SIZE 32
|
||||||
|
|
||||||
// Size of the memory area dedicated to VLAN-names
|
// Size of the memory area dedicated to VLAN-names
|
||||||
#define VLAN_NAMES_SIZE 1024
|
#define VLAN_NAMES_SIZE 1024
|
||||||
|
|
||||||
|
// Size of the flash buffer used for writing to flash, must be a multiple of the flash page size (0x100)
|
||||||
|
#define FLASH_BUF_SIZE 512
|
||||||
|
|
||||||
|
// Errors for commands
|
||||||
|
#define ERR_OK 0
|
||||||
|
#define ERR_TOO_MANY_ARGUMENTS 1
|
||||||
|
#define ERR_CMD_TOO_LONG 2
|
||||||
|
|
||||||
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
|
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
|
||||||
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
|
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
|
||||||
// the VLAN tag is inserted after the RTL tag
|
// the VLAN tag is inserted after the RTL tag
|
||||||
// See here for the RTL tag: https://github.com/torvalds/linux/commit/1521d5adfc2b557e15f97283c8b7ad688c3ebc40
|
// See here for the RTL tag: https://github.com/torvalds/linux/commit/1521d5adfc2b557e15f97283c8b7ad688c3ebc40
|
||||||
#define RTL_TAG_SIZE 8
|
struct rtl_tag {
|
||||||
#define VLAN_TAG_SIZE 4
|
uint16_t tag; // This is 0x8899 for the RTL837X
|
||||||
#define RTL_FRAME_TAG_ID 0x8899
|
uint8_t version; // Version is 4
|
||||||
|
uint8_t reason;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t pmask; // A bit mask for a TX pkt, 4-bit port-number for RX
|
||||||
|
};
|
||||||
|
|
||||||
// For RX and TX, an 8 byte header describing the frame to be moved to the Asic
|
struct vlan_tag {
|
||||||
// and received from the Asic is used
|
uint16_t svlan; // Service VLAN
|
||||||
#define RTL_FRAME_HEADER_SIZE 8
|
uint16_t vlan;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RTL_TAG_SIZE (sizeof (struct rtl_tag))
|
||||||
|
#define VLAN_TAG_SIZE (sizeof (struct vlan_tag))
|
||||||
|
#define RTL_FRAME_TAG_ID 0x8899
|
||||||
|
#define RTL_FRAME_TAG_VERSION 0x04
|
||||||
|
|
||||||
|
// For TX, an 8 byte (plus 4 byte padding when when VLAN is enabled)
|
||||||
|
// header describing the frame to be moved to the Asic is used
|
||||||
|
#define RTL_FRAME_DESC_SIZE 12
|
||||||
|
|
||||||
// This is the standard size of an Ethernet frame header
|
// This is the standard size of an Ethernet frame header
|
||||||
#define ETHER_HEADER_SIZE 14
|
#define ETHER_HEADER_SIZE 14
|
||||||
|
|
||||||
#if NSFP == 1
|
#define DEFAULT_CONFIG_START 0x6f000
|
||||||
#define IS_SFP(port) (i == maxPort)
|
#define CONFIG_START 0x70000
|
||||||
#else
|
#define CONFIG_LEN 0x1000
|
||||||
#define IS_SFP(port) (i == maxPort || i == 3)
|
#define CODE0_SIZE 0x4000
|
||||||
#endif
|
#define CODE_BANK_SIZE 0xc000
|
||||||
|
|
||||||
|
// Store update image after running image
|
||||||
|
#define FIRMWARE_UPLOAD_START 0x80000
|
||||||
|
|
||||||
|
// Constants for the circular command buffer, the size must be 2^n
|
||||||
|
#define CMD_HISTORY_SIZE 0x400
|
||||||
|
#define CMD_HISTORY_MASK (CMD_HISTORY_SIZE - 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of a 48-bit Ethernet address.
|
* Representation of a 48-bit Ethernet address.
|
||||||
@@ -59,14 +104,18 @@ struct flash_region_t {
|
|||||||
uint16_t len;
|
uint16_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
extern __xdata char port_names[9][PORT_NAME_SIZE];
|
||||||
|
|
||||||
|
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
||||||
|
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||||
|
|
||||||
// Headers for calls in the common code area (HOME/BANK0)
|
// Headers for calls in the common code area (HOME/BANK0)
|
||||||
void print_string(__code char *p);
|
void print_string(__code char *p);
|
||||||
void print_long(__xdata uint32_t a);
|
void print_string_x(__xdata char *p);
|
||||||
|
void print_long(uint32_t a);
|
||||||
void print_short(uint16_t a);
|
void print_short(uint16_t a);
|
||||||
void print_byte(uint8_t a);
|
void print_byte(uint8_t a);
|
||||||
|
void itoa(uint8_t v);
|
||||||
void print_sfr_data(void);
|
void print_sfr_data(void);
|
||||||
void print_phy_data(void);
|
void print_phy_data(void);
|
||||||
void phy_write_mask(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v);
|
void phy_write_mask(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v);
|
||||||
@@ -77,6 +126,8 @@ void reg_read(uint16_t reg_addr);
|
|||||||
void reg_read_m(uint16_t reg_addr);
|
void reg_read_m(uint16_t reg_addr);
|
||||||
void reg_write(uint16_t reg_addr);
|
void reg_write(uint16_t reg_addr);
|
||||||
void reg_write_m(uint16_t reg_addr);
|
void reg_write_m(uint16_t reg_addr);
|
||||||
|
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
|
||||||
|
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
|
||||||
void delay(uint16_t t);
|
void delay(uint16_t t);
|
||||||
void sleep(uint16_t t);
|
void sleep(uint16_t t);
|
||||||
void write_char(char c);
|
void write_char(char c);
|
||||||
@@ -84,6 +135,8 @@ void print_reg(uint16_t reg);
|
|||||||
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg);
|
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg);
|
||||||
void reg_bit_set(uint16_t reg_addr, char bit);
|
void reg_bit_set(uint16_t reg_addr, char bit);
|
||||||
void reg_bit_clear(uint16_t reg_addr, char bit);
|
void reg_bit_clear(uint16_t reg_addr, char bit);
|
||||||
|
uint8_t reg_bit_test(uint16_t reg_addr, char bit);
|
||||||
|
void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set);
|
||||||
void sfr_set_zero(void);
|
void sfr_set_zero(void);
|
||||||
void reset_chip(void);
|
void reset_chip(void);
|
||||||
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
|
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
|
||||||
@@ -92,8 +145,16 @@ void memset(register __xdata uint8_t *dst, register __xdata uint8_t v, register
|
|||||||
uint16_t strlen(register __code const char *s);
|
uint16_t strlen(register __code const char *s);
|
||||||
uint16_t strlen_x(register __xdata const char *s);
|
uint16_t strlen_x(register __xdata const char *s);
|
||||||
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s);
|
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s);
|
||||||
|
uint16_t strcpy(register __xdata uint8_t *dst, register const char *s);
|
||||||
void tcpip_output(void);
|
void tcpip_output(void);
|
||||||
void print_string_x(__xdata char *p);
|
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
||||||
|
void get_random_32(void);
|
||||||
|
void read_reg_timer(__xdata uint32_t * tmr);
|
||||||
|
void sfp_print_info(uint8_t sfp);
|
||||||
|
bool gpio_pin_test(uint8_t pin);
|
||||||
|
void set_sys_led_state(uint8_t state);
|
||||||
|
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
|
||||||
|
void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v);
|
||||||
|
void sds_config_mac(uint8_t sds, uint8_t mode);
|
||||||
|
void sds_config(uint8_t sds, uint8_t mode);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||