mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Merge branch 'main' into Support_HYWS-SGT0108S
This commit is contained in:
68 files changed
+4499
-3679
No files matched your search
@@ -0,0 +1,32 @@
|
||||
# MokerLink POE-2G080110GS
|
||||
|
||||
The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware.
|
||||
|
||||
## Brands
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|--------|------------------|-------|------------------|-----------------|---------------|
|
||||
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
|
||||
|
||||
## Hardware overview
|
||||
Front
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-front.jpg" width="300" />
|
||||
|
||||
Label
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-label.jpg" width="300" />
|
||||
|
||||
The stock firmware from a POE-2G080110GS device had a sha256sum of `4c280853465eaad80e1772075c0f2d29c11fb8c561547f06353d3a5443c388e9`.
|
||||
|
||||
### PCB
|
||||
|
||||
Top silkscreen is marked `2M-PCB51-ML-V1.1`. PoE is provided by RTL8238C. Flash chip is 4 MB Winbond 25Q32JV (U8).
|
||||
|
||||
<img src="photos/POE-2G080110GS/POE-2G080110GS-pcb.jpg" width="300" />
|
||||
|
||||
> [!CAUTION]
|
||||
> This device operates on mains voltage, which can be a dangerous or potentially lethal hazard. Even after the device is unplugged, high-voltage capacitors can remain charged afterward and may still shock you. Do not attempt to open/disassemble a mains powered device unless you understand how to do so safely. Also, opening the device may void your warranty.
|
||||
|
||||
## Notes
|
||||
|
||||
The stock firmware blinks both the 2.5G and 1G LEDs on activity, despite the front of the device indicating that each LED should be independent. The `POE_2G080110GS` machine config behaves as the front of the device indicates (and what seems more logical) -- each port LED turns on and blinks independently.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 934 KiB |
+26
@@ -58,6 +58,32 @@ port set to admit tagged frames only (`ingress <port>t`) never delivers one
|
||||
to the CPU. `stp_setup()` prints a warning for every STP-enabled port in that
|
||||
state.
|
||||
|
||||
## Link aggregation
|
||||
|
||||
A LAG (Link Aggregation Group) is handled like an additional port by the STP
|
||||
protocol, with its own timers and states. The switch devices support up to 4
|
||||
LAGs, which are shown alongside the physical ports in the STP status. A group
|
||||
carries its own path cost, priority, edge and guard settings, and gets its own
|
||||
row on the Spanning Tree page.
|
||||
|
||||
```
|
||||
stp lag 1 cost 10000 # the group decides, not its members
|
||||
stp lag 1 edge off
|
||||
```
|
||||
|
||||
LAGs are configured via the `lag` command. Once a port is a member of a LAG it
|
||||
can no longer be configured individually for STP, so `stp port <n>` on a member
|
||||
tells you which group to configure instead. Membership is re-read from the
|
||||
aggregation registers once a second, so a group changing under LACP is picked
|
||||
up without any coordination between the two.
|
||||
|
||||
The switch hardware does not handle STP state for a LAG as a whole. State
|
||||
changes for the members have to be done by the firmware, updating every member
|
||||
port, which is possible using a single register write. BPDUs go out through the
|
||||
lowest member and carry the group's own port id. Losing one member of a live
|
||||
LAG is not a topology change; the logical port only goes down with its last
|
||||
link.
|
||||
|
||||
Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port:
|
||||
`00` disabled, `01` blocking, `10` learning, `11` forwarding. A port in
|
||||
blocking forwards nothing between ports, but it still sends what the CPU
|
||||
|
||||
@@ -23,6 +23,7 @@ The following devices have been tested and are fully working:
|
||||
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
||||
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
||||
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
||||
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
||||
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
|
||||
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# Compressing the Web UI Assets
|
||||
|
||||
The Web UI (all files under `html/`) is embedded into the flash image and
|
||||
served over HTTP. Two build-time steps keep it small: a safe minifier and
|
||||
gzip compression of the embedded files.
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
html/ --(minify.py)--> output/html_min/ --(fileadder -z)--> flash image
|
||||
```
|
||||
|
||||
- `tools/minify.py` removes comments (`<!-- -->`, `//`, `/* */`) and
|
||||
line-leading whitespace without touching string or regex literals, so
|
||||
the output is functionally identical to the input. Binary files
|
||||
(`.ico`) are copied through unchanged. The raw sources in `html/` stay
|
||||
untouched for development; the minified copy in `output/` is a pure
|
||||
build artifact. Comments and indentation are pure overhead for the
|
||||
served bytes, so minification alone already reduces the transfer size
|
||||
from 109,814 to 97,730 bytes, independent of gzip.
|
||||
- The Web UI is a single-page application: `index.html` holds all pages
|
||||
as sections (`#/ports`, `#/vlan`, ...) that the sidebar switches
|
||||
between via the URL hash. `login.html` stays separate because it is
|
||||
the authentication gate. Only these two pages plus `main.js`,
|
||||
`style.css`, the three SVG port images and the favicon are embedded.
|
||||
- All JavaScript (i18n, shared helpers, navigation and the per-section
|
||||
scripts) lives in one `html/main.js` bundle that the pages load as
|
||||
their only script, so the browser fetches it once and gzip can
|
||||
compress across all of it. A section's initialisation runs when the
|
||||
section is shown, its polling intervals run only while it is visible,
|
||||
and re-entering a section refetches the data.
|
||||
- `fileadder -z` gzip-compresses every file (zlib, gzip format,
|
||||
`Z_BEST_COMPRESSION`) when it generates the file table
|
||||
(`html_data.c`/`html_data.h`) and when it embeds the files into the
|
||||
final image. Both invocations run on `output/html_min/`, so the table
|
||||
and the image always agree.
|
||||
- The httpd serves each file with `Content-Encoding: gzip` according to
|
||||
the `gzip` flag in its `f_data` entry. The 8051 only copies compressed
|
||||
bytes from flash to the socket; decompression happens in the browser.
|
||||
- Only the static files are compressed. The JSON API responses
|
||||
(`/information.json`, `/vlanlist`, ...) are generated on the fly and
|
||||
stay uncompressed.
|
||||
|
||||
## Measured effect
|
||||
|
||||
Build on any machine (the Web UI is machine-independent):
|
||||
|
||||
| | bytes |
|
||||
|---|---:|
|
||||
| raw sources | 109,814 |
|
||||
| minified (comments and indentation removed) | 97,730 |
|
||||
| gzip (flash + wire) | 25,302 (23.0 %) |
|
||||
|
||||
The minified assets are also what the browser receives when gzip support
|
||||
is missing or disabled, so the transfer size drops in both stages:
|
||||
109,814 → 97,730 bytes from minification, then → 25,302 bytes from gzip.
|
||||
|
||||
The embedded data block ends at `0x5b977` without compression and at
|
||||
`0x462d6` with it, freeing ~86 KB of the 512 KB image.
|
||||
|
||||
The consolidation helps at every step. The 17 scripts gzip to 23,302
|
||||
bytes as separate files but to 17,231 bytes as one `main.js` bundle,
|
||||
because the gzip dictionary spans all of them. The single-page layout
|
||||
then removes the per-page HTML and, more importantly, the repeated
|
||||
downloads: with the multi-page UI the browser fetched `main.js` on every
|
||||
navigation; the SPA fetches everything once and section switches are
|
||||
pure in-page JavaScript (measured on a real device: cold load ~450 ms,
|
||||
section switch ~60-160 ms, the only network traffic afterwards is the
|
||||
JSON polling of the visible section).
|
||||
|
||||
## Notes
|
||||
|
||||
- The files stay well below the `uint16_t` size limit of the file table
|
||||
(largest gzip output: 17.2 KB for the merged `main.js`).
|
||||
- `fileadder` terminates the embedded files with a NUL directly after the
|
||||
content (previously at `data_read + 1`), so the `strlen()`-based size
|
||||
computation no longer depends on uninitialised buffer content.
|
||||
- `version.h` is now written by a single atomic `printf` (change from
|
||||
upstream) instead of five separate `echo`s, so a parallel build
|
||||
(`make -j`) can no longer read a half-written copy. It stays in
|
||||
`.PHONY` so it is regenerated on every build.
|
||||
|
||||
## Verification
|
||||
|
||||
Decompress what the firmware embeds and compare it with the minified
|
||||
sources:
|
||||
|
||||
```python
|
||||
import gzip, re
|
||||
h = open('html_data.h').read(); c = open('html_data.c').read()
|
||||
starts = dict((k, int(v, 16)) for k, v in
|
||||
re.findall(r'#define FDATA_START_(\w+) 0x([0-9a-f]+)', h))
|
||||
sizes = dict((k, int(v)) for k, v in
|
||||
re.findall(r'#define FDATA_SIZE_(\w+) (\d+)', h))
|
||||
entries = [(p, sizes[z], starts[s]) for p, s, z in
|
||||
re.findall(r'\{"/([^"]+)", FDATA_START_(\w+), '
|
||||
r'FDATA_SIZE_(\w+), \w+, 1\}', c)]
|
||||
d = open('output/rtlplayground.bin', 'rb').read()
|
||||
for name, size, start in entries:
|
||||
assert gzip.decompress(d[start:start+size]) == \
|
||||
open('output/html_min/' + name, 'rb').read()
|
||||
```
|
||||
|
||||
`tools/httpd_sim` serves the raw files from `html/` and does not exercise
|
||||
the gzip path; a browser session against a flashed switch (or `curl
|
||||
--compressed`) is the final check.
|
||||
Reference in new issue
Block a user