Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
984831620c |
@@ -1,21 +0,0 @@
|
||||
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: Make project
|
||||
run: make
|
||||
@@ -1,9 +0,0 @@
|
||||
.gitignore
|
||||
.idea/
|
||||
output/
|
||||
html_data.c
|
||||
html_data.h
|
||||
version.h
|
||||
tools/httpd_sim
|
||||
tools/injector
|
||||
tools/fileadder
|
||||
@@ -1,21 +0,0 @@
|
||||
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,38 +1,21 @@
|
||||
BOOTLOADER_ADDRESS=0x100
|
||||
|
||||
VERSION=0.1.0
|
||||
IMAGESIZE = 524288
|
||||
CONFIG_LOCATION = 458752
|
||||
HTML_LOCATION = 262144
|
||||
|
||||
CC = sdcc
|
||||
CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip
|
||||
CC_FLAGS = -mmcs51 -Ihttpd -Iuip
|
||||
ASM = sdas8051
|
||||
AFLAGS= -plosgff
|
||||
|
||||
SUBDIRS := tools uip httpd
|
||||
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
|
||||
|
||||
BUILDDIR = output/
|
||||
VERSION_HEADER := version.h
|
||||
all: $(SUBDIRS) rtlplayground.bin
|
||||
|
||||
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)rtlplayground.bin
|
||||
|
||||
create_build_dir:
|
||||
mkdir -p $(BUILDDIR)
|
||||
|
||||
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c
|
||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
||||
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 = rtlplayground.c rtl837x_flash.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c
|
||||
OBJS = ${SRCS:.c=.rel}
|
||||
OBJS += uip/timer.rel uip/uip-fw.rel uip/uip-neighbor.rel uip/uip-split.rel uip/uip.rel uip/uip_arp.rel uip/uiplib.rel httpd/httpd.rel httpd/page_impl.rel
|
||||
|
||||
html_data.c html_data.h: html tools
|
||||
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 "#endif" >> $(VERSION_HEADER)
|
||||
tools/fileadder -a -s -b BANK1 -d html -p html_data
|
||||
|
||||
httpd: html_data.h
|
||||
|
||||
@@ -42,34 +25,33 @@ $(SUBDIRS):
|
||||
clean:
|
||||
-make -C uip clean
|
||||
-make -C httpd clean
|
||||
-rm html_data.c html_data.h $(VERSION_HEADER)
|
||||
-rm -r $(BUILDDIR)
|
||||
-rm html_data.c html_data.c
|
||||
if [ -e rtlplayground.bin ]; then rm rtlplayground.bin; fi
|
||||
if [ -e rtlplayground.asm ]; then rm rtlplayground.asm; fi
|
||||
-rm *.ihx *.lk *.lst *.map *.mem *.rel *.rst *.sym *.bin
|
||||
|
||||
$(BUILDDIR)crtstart.rel: crtstart.asm
|
||||
$(ASM) $(AFLAGS) -o $@ $<
|
||||
|
||||
$(BUILDDIR)crc16.rel: crc16.asm
|
||||
$(ASM) $(AFLAGS) -o $@ $<
|
||||
%.rel: %.c
|
||||
$(CC) $(CC_FLAGS) -c $<
|
||||
|
||||
$(BUILDDIR)%.rel: %.c
|
||||
$(CC) $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
||||
${ASM} ${AFLAGS} -o $@ $<
|
||||
%.rel: %.asm
|
||||
${ASM} ${AFLAGS} $^
|
||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||
|
||||
$(BUILDDIR)rtlplayground.ihx: $(BUILDDIR)crtstart.rel $(OBJS) $(BUILDDIR)crc16.rel
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
|
||||
rtlplayground.ihx: crtstart.rel $(OBJS)
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -Wl-bBANK1=0x14000 -Wl-r -o $@ $^
|
||||
|
||||
$(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx
|
||||
%.img: %.ihx
|
||||
objcopy --input-target=ihex -O binary $< $@
|
||||
|
||||
$(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlplayground.img
|
||||
%.bin: %.img
|
||||
if [ -e $@ ]; then rm $@; fi
|
||||
tools/$(BUILDDIR)imagebuilder -i $^ $@
|
||||
tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@
|
||||
tools/$(BUILDDIR)crc_calculator -u $@
|
||||
|
||||
echo "0000000: 00 40" | xxd -r - $@
|
||||
cat $< >> $@
|
||||
truncate --size=16K $@
|
||||
dd if=$< skip=80 bs=1024 >>$@
|
||||
tools/fileadder -s -d config.txt $@
|
||||
tools/fileadder -a -s -d html -p html_data $@
|
||||
|
||||
.PHONY: clean all $(SUBDIRS)
|
||||
.PRECIOUS: %.rel %.ihx .img
|
||||
|
||||
@@ -1,62 +1,58 @@
|
||||
# RTLPlayground
|
||||
A Playground for Firmware development for advanced user of RTL8372/RTL8373 based 2.5GBit Switches.
|
||||
A Playground for Firmware development for RTL8372/RTL8373 based 2.5GBit Switches.
|
||||
|
||||
For each hardware configuration of these devices, there is usually a managed and an
|
||||
umanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||
features also for unmanaged devices with additional features such as Management VLAN,
|
||||
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||
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
|
||||
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages.
|
||||
|
||||
<img width="1420" height="623" alt="GUI" src="doc/images/gui.png" />
|
||||
The playground currently provides a minimal alternative firmware for both the managed and unmanaged switches.
|
||||
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.
|
||||
|
||||
While the firmware provides already considerable improvements over the original managed firmware,
|
||||
the firmware still lacks support for STP and the proprietary loop prevention
|
||||
protocols as well as DHCP. If you need these features, do not install the playground on your managed
|
||||
devices. In any case, installation is strongly discouraged unless you can at least make
|
||||
a backup of the original flash content via a SOIC clamp such as also used for BIOS
|
||||
backups and can re-install that firmware in case something is wrong. For this no soldering
|
||||
skills are necessary.
|
||||
At this point, the firmware can be installed on the hardware as given below,
|
||||
all of the ports and SFP-slots will be supported. The following has been tested:
|
||||
On the keepLINK kp-9000-6hx-x (RTL8372 + RTL8221B 2.5GBit PHY: 5 x 2.5GBit + 1x 10GBit SFP+),
|
||||
at present the system will provide the same featurs as a dumb switch plus a tiny
|
||||
TCP stack that will allow to reply to ARP and ping messages, thus enabling pinging the device.
|
||||
VLAN and mirroring can be configured (but not saved to flash).
|
||||
The ports served by the RTL8372 will be 100M/1G/2.5G auto-detect. Port 5 to RTL8221B PHY
|
||||
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 firmware supports all hardware featues of devices with
|
||||
- 4 2.5GBit ports + 2 SFP+ ports
|
||||
- 5 2.5GBIT + 1 SFP+ port
|
||||
- 8 2.5GBit + 1 SFP+ port
|
||||
Devices sold usually have a fairly common design, however there may be differences in the LED
|
||||
configuration (switches have LEDs with different colours and use types of LEDs). The list
|
||||
of tested devices can be found in [Supported devices](doc/supported_devices.md).
|
||||
The 4-Port Ethernet + 2 Port SFP+ devices (e.g. KP-9000-6HX-x2) are fully supported, too
|
||||
(e.g. KP-9000-6hx-x2) with the same features as above. In particular all fiber/Ethernet
|
||||
modules work in both SFP+ ports.
|
||||
|
||||
On the 9-port devices with RTL8273 + RTL8224 (for example kp-9000-9xh-x) all ports will
|
||||
work for switching and CPU-access, the SFP+ port will work normally and TCP connectivity
|
||||
will work as above. Not all features of the RTL8224-ports (the first 4) have been tested.
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
devices by looking at the image using e.g. Ghidra.
|
||||
|
||||
## Compiling
|
||||
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:
|
||||
Install the following particular build requisites (Debian 12, should work on Ubuntu)
|
||||
```
|
||||
sudo apt install sdcc xxd python-is-python3 libjson-c-dev
|
||||
sudo apt install sdcc xxd
|
||||
```
|
||||
|
||||
Now, building the firmware image should work:
|
||||
@@ -74,35 +70,126 @@ cat rtlplayground.img >> rtlplayground.bin
|
||||
Note, that the image generated ends in .bin, not .img, in order to make
|
||||
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
|
||||
You can play with the image using ghidra or flash real Switch Hardware. For
|
||||
ghidra see this information about [Ghidra images](ghidra.md).
|
||||
You can play with the image using ghidra or flash real Switch Hardware
|
||||
|
||||
### 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]
|
||||
> NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
|
||||
@@ -110,15 +197,8 @@ ghidra see this information about [Ghidra images](ghidra.md).
|
||||
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
|
||||
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
|
||||
|
||||
You can upload the upgrade image of managed switches via the web interface of the
|
||||
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,
|
||||
There is no support for uploading the firmware via ethernet. Instead you
|
||||
need to open the switch and flash the image directly onto the flash chip,
|
||||
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
|
||||
flash chip and install a SOIC adapter):
|
||||
- Disconnect power from switch
|
||||
@@ -137,10 +217,6 @@ devices, set 8N1 @ 115200 baud and power up the switch.
|
||||
The device will perform some examples and provide a minimal console, the
|
||||
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 is very rudimentary and mostly for testing purposes.
|
||||
The following is a boot-log with some examples:
|
||||
@@ -231,12 +307,9 @@ Enjoy playing!
|
||||
## Other documents
|
||||
The following documents give further documentation on specific features of
|
||||
the RTL837x SoCs:
|
||||
- [RTL8372/3 Feature support](doc/hardware.md)
|
||||
- [CPU Port](doc/CpuPort.md)
|
||||
- [L2 learning](doc/l2.md)
|
||||
- [CPU Port](doc/CpuPort.md)
|
||||
- [IGMP (IP-MC streaming)](doc/igmp.md)
|
||||
- [Mirroring](doc/mirroring.md)
|
||||
- [SFP+ ports](doc/sfp.md)
|
||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
||||
- [VLAN](doc/vlan.md)
|
||||
- [Modifications and Flash replacement](doc/mods.md)
|
||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
||||
- [VLAN](doc/vlan.md)
|
||||
@@ -1,15 +1,7 @@
|
||||
#ifndef _CMD_PARSER_H_
|
||||
#define _CMD_PARSER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
|
||||
extern __xdata uint8_t cmd_buffer[SBUF_SIZE];
|
||||
extern __xdata uint8_t cmd_available;
|
||||
|
||||
uint8_t cmd_tokenize(void) __banked;
|
||||
void cmd_parser(void) __banked;
|
||||
void execute_config(void) __banked;
|
||||
void print_sw_version(void) __banked;
|
||||
void cmd_parser_setup(void) __banked;
|
||||
void execute_config() __banked;
|
||||
#endif
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
ip 192.168.10.247
|
||||
gw 192.168.10.1
|
||||
netmask 255.255.255.0
|
||||
@@ -1,121 +0,0 @@
|
||||
;
|
||||
; CRC16 calculation module
|
||||
;
|
||||
.globl _crc_value
|
||||
.globl _crc16
|
||||
.equ BANK, 0x96
|
||||
; .equ DPS, 0x86
|
||||
; Variable in XMEM holding current CRC16 value, being updated
|
||||
.area XSEG (XDATA)
|
||||
_crc_value::
|
||||
.ds 2
|
||||
|
||||
;-------------------------------------------------------
|
||||
; CRC16 subroutine
|
||||
; - dptr points to byte to be CRCd in xmem
|
||||
; - algorithm uses table lookup
|
||||
;-------------------------------------------------------
|
||||
.area HOME (CODE)
|
||||
.area CSEG (CODE)
|
||||
; .area BANK1 (CODE)
|
||||
_crc16:
|
||||
mov BANK, #1
|
||||
push dph
|
||||
push dpl
|
||||
movx a, @dptr
|
||||
; inc DPS
|
||||
mov b, a
|
||||
mov dptr, #_crc_value
|
||||
movx a, @dptr
|
||||
|
||||
xrl a, b ; create index into tables
|
||||
push a ; save index
|
||||
mov dptr, #crc16_table_l ; low part of table address
|
||||
movc a, @a+dptr ; get low byte
|
||||
mov b, a
|
||||
|
||||
mov dptr, #_crc_value + 1
|
||||
movx a, @dptr
|
||||
|
||||
xrl a, b
|
||||
mov dptr, #_crc_value
|
||||
movx @dptr, a ; save result low part
|
||||
mov dptr, #crc16_table_h ; high part of table address
|
||||
pop a ; restore index
|
||||
movc a, @a+dptr
|
||||
mov dptr, #_crc_value+1
|
||||
movx @dptr, a ; save result high part
|
||||
pop dpl
|
||||
pop dph
|
||||
; clr DPS
|
||||
ret
|
||||
|
||||
.area BANK1 (CODE)
|
||||
|
||||
crc16_table_l:
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
|
||||
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
|
||||
|
||||
crc16_table_h:
|
||||
.byte #0x00, #0xc0, #0xc1, #0x01, #0xc3, #0x03, #0x02, #0xc2
|
||||
.byte #0xc6, #0x06, #0x07, #0xc7, #0x05, #0xc5, #0xc4, #0x04
|
||||
.byte #0xcc, #0x0c, #0x0d, #0xcd, #0x0f, #0xcf, #0xce, #0x0e
|
||||
.byte #0x0a, #0xca, #0xcb, #0x0b, #0xc9, #0x09, #0x08, #0xc8
|
||||
.byte #0xd8, #0x18, #0x19, #0xd9, #0x1b, #0xdb, #0xda, #0x1a
|
||||
.byte #0x1e, #0xde, #0xdf, #0x1f, #0xdd, #0x1d, #0x1c, #0xdc
|
||||
.byte #0x14, #0xd4, #0xd5, #0x15, #0xd7, #0x17, #0x16, #0xd6
|
||||
.byte #0xd2, #0x12, #0x13, #0xd3, #0x11, #0xd1, #0xd0, #0x10
|
||||
.byte #0xf0, #0x30, #0x31, #0xf1, #0x33, #0xf3, #0xf2, #0x32
|
||||
.byte #0x36, #0xf6, #0xf7, #0x37, #0xf5, #0x35, #0x34, #0xf4
|
||||
.byte #0x3c, #0xfc, #0xfd, #0x3d, #0xff, #0x3f, #0x3e, #0xfe
|
||||
.byte #0xfa, #0x3a, #0x3b, #0xfb, #0x39, #0xf9, #0xf8, #0x38
|
||||
.byte #0x28, #0xe8, #0xe9, #0x29, #0xeb, #0x2b, #0x2a, #0xea
|
||||
.byte #0xee, #0x2e, #0x2f, #0xef, #0x2d, #0xed, #0xec, #0x2c
|
||||
.byte #0xe4, #0x24, #0x25, #0xe5, #0x27, #0xe7, #0xe6, #0x26
|
||||
.byte #0x22, #0xe2, #0xe3, #0x23, #0xe1, #0x21, #0x20, #0xe0
|
||||
.byte #0xa0, #0x60, #0x61, #0xa1, #0x63, #0xa3, #0xa2, #0x62
|
||||
.byte #0x66, #0xa6, #0xa7, #0x67, #0xa5, #0x65, #0x64, #0xa4
|
||||
.byte #0x6c, #0xac, #0xad, #0x6d, #0xaf, #0x6f, #0x6e, #0xae
|
||||
.byte #0xaa, #0x6a, #0x6b, #0xab, #0x69, #0xa9, #0xa8, #0x68
|
||||
.byte #0x78, #0xb8, #0xb9, #0x79, #0xbb, #0x7b, #0x7a, #0xba
|
||||
.byte #0xbe, #0x7e, #0x7f, #0xbf, #0x7d, #0xbd, #0xbc, #0x7c
|
||||
.byte #0xb4, #0x74, #0x75, #0xb5, #0x77, #0xb7, #0xb6, #0x76
|
||||
.byte #0x72, #0xb2, #0xb3, #0x73, #0xb1, #0x71, #0x70, #0xb0
|
||||
.byte #0x50, #0x90, #0x91, #0x51, #0x93, #0x53, #0x52, #0x92
|
||||
.byte #0x96, #0x56, #0x57, #0x97, #0x55, #0x95, #0x94, #0x54
|
||||
.byte #0x9c, #0x5c, #0x5d, #0x9d, #0x5f, #0x9f, #0x9e, #0x5e
|
||||
.byte #0x5a, #0x9a, #0x9b, #0x5b, #0x99, #0x59, #0x58, #0x98
|
||||
.byte #0x88, #0x48, #0x49, #0x89, #0x4b, #0x8b, #0x8a, #0x4a
|
||||
.byte #0x4e, #0x8e, #0x8f, #0x4f, #0x8d, #0x4d, #0x4c, #0x8c
|
||||
.byte #0x44, #0x84, #0x85, #0x45, #0x87, #0x47, #0x46, #0x86
|
||||
.byte #0x82, #0x42, #0x43, #0x83, #0x41, #0x81, #0x80, #0x40
|
||||
@@ -16,12 +16,12 @@ __interrupt_vect:
|
||||
.ds 5
|
||||
ljmp _isr_ext1 ; 0x13
|
||||
.ds 5
|
||||
reti ; 0x1b TIMER 1 IRQ
|
||||
reti
|
||||
.ds 7
|
||||
ljmp _isr_serial ; 0x23
|
||||
.ds 5
|
||||
ljmp _isr_timer2 ; 0x2b TIMER 2 IRQ
|
||||
.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
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#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
|
||||
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
extern __code struct uip_eth_addr uip_ethaddr;
|
||||
__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_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE])
|
||||
#define DHCP_OPT ((__xdata uint8_t *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE + sizeof (struct dhcp_pkt)])
|
||||
*/
|
||||
|
||||
#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(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);
|
||||
memcpyc(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;
|
||||
memcpyc(&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];
|
||||
memcpyc(&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];
|
||||
memcpyc(&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(uint8_t * __xdata 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;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#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;
|
||||
|
||||
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
|
||||
@@ -3,12 +3,6 @@
|
||||
The RTL827x provide a CPU Port for a NIC on the 8051 side of the SoC.
|
||||
|
||||
## Receiving packets
|
||||
In order to receive packets on the ASIC side, bit 0 of RTL837X_REG_RX_CTRL
|
||||
(0x785c) must be set. Further bits in the register enable reception of various
|
||||
kinds of Ethernet frames. They should all be set in order for the firmware
|
||||
to decide what to do with them. To drop packets with incorrect Ethernet frame CRC
|
||||
already by the ASIC, clear bit 2 of this register.
|
||||
|
||||
Packets are received by either polling the RTL837X_REG_RX_AVAIL register
|
||||
(0x7874), which will be > 0 if data is within a ring-buffer on the ASIC side
|
||||
of the SoC. Alternatively, an interrupt can be triggered (EX1).
|
||||
@@ -45,8 +39,7 @@ buffer on the ASIC side by writing 0x1 to RTL837X_REG_RX_DONE (0x784c).
|
||||
|
||||
## Transmissing packets
|
||||
Packets are transmitted by preparing a frame-header plus frame in xdata memory
|
||||
and transferring both to the ASIC side via the SFRs. The ASIC will transmit
|
||||
packets if bit 0 of RTL837X_REG_TX_CTRL (0x7860) is set.
|
||||
and transferring both to the ASIC side via the SFRs.
|
||||
|
||||
```
|
||||
SS 07 00 00 LL LH 00 00
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
### 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 |
|
||||
|
||||
# Connectors
|
||||
|`J4` SFP PINs | Signal | Component | GPIO | Notes |
|
||||
|---|---|---|---|---|
|
||||
|2| TX_FAULT | | --- | |
|
||||
|3| TX_DISABLE | | --- | Pull down - 0R |
|
||||
|4| MODDEF2 – SDA | b-r273 | GPIO39 | |
|
||||
|5| MODDEF1 – SCL | b-r274 | GPIO40 | |
|
||||
|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
|
||||
|`T7` pin|what|Signal|
|
||||
|---|---|---|
|
||||
| 1 | GPIO | |
|
||||
| 2 | GND | |
|
||||
| 3 | GPIO | |
|
||||
| 4 | 3V3 | |
|
||||
| 5 | GPIO | |
|
||||
| 6 | GPIO | |
|
||||
|
||||
### 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 RTL8225 | Already driver HIGH INT? |
|
||||
| 00000008 | GPIO03 | T-R113-R, P2-LED-GR |? | | GPIO35 | B-R173, To RTL8225 | Easy to pulldown Reset? |
|
||||
| 00000010 | GPIO04 | T-R115-R, P3-LED-YL |? | | GPIO36 || | |
|
||||
| 00000020 | GPIO05 | T-R117-R, P3-LED-GR |? | | GPIO37 | To RTL8225 | Already driver low I2C-SCL? | |
|
||||
| 00000040 | GPIO06 | |? | | GPIO38 | sfp-6 via B-R275, sfp-8 via B-R276 | |
|
||||
| 00000080 | GPIO07 | |? | | GPIO39 | sfp-4, b-r273, B-r143 | |
|
||||
| 00000100 | GPIO08 | | | | GPIO40 | T9-2, sfp-5 b-r274, B-r146 | SMI-MDC |
|
||||
| 00000200 | GPIO09 | |LEDx[^1] | | GPIO41 | T9-1, | SMI-MDO , B-r143 |
|
||||
| 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 | |
|
||||
| 00008000 | GPIO15 | |LEDx[^1] | | GPIO47 | T10-2 | |
|
||||
| 00010000 | GPIO16 | |LEDx[^1] | | GPIO48 | T10-4, J6 (BUTTON RESET) | |
|
||||
| 00020000 | GPIO17 | |LEDx[^1] | | GPIO49 | T10-1 | |
|
||||
| 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 | |SFP-DETE | | GPIO62 | To RTL8225 | Already driver INT? | |
|
||||
| 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.
|
||||
@@ -1,213 +0,0 @@
|
||||
### SWTG024AS
|
||||
SWTG024AS has at least 4 variants that look the same.
|
||||
|
||||
Variants are `managed` and a `unmanaged` version.
|
||||
But both have pcb version `v1.0` and `v2.0`.
|
||||
Also the RJ45 connectors can be all plastic/non-shielded or with metal shielding.
|
||||
|
||||
## Brands
|
||||
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|
||||
|---|---|---|---|---|---|---|
|
||||
| LIANGUO |SWTG024AS |No| SWTG024AS-v2.0-17452 | CM-23-11-2336 023-17453| 512 KiB | 8272 |
|
||||
| Haraco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 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
|
||||
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
|
||||
* R105: Installed, goes to R10-PullDown SFP2 (J2) -> TX-DISABLE
|
||||
* R85: Not Installed (Connected to K1 Reset Button)
|
||||
* R90: Not installed (System Led)
|
||||
* LED3: Not installed (System Led)
|
||||
### Top
|
||||
* K1: Not installed (Reset Button)
|
||||
* R95: Installed (SFP2 (J2) signal RX-LOS), means that the managed-version can´t use the RX-LOS function.
|
||||
* R270: Installed (SFP1 (J4) signal RX-LOS), same here as above.
|
||||
* 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 512 KiB instead of 2/4 MiB.
|
||||
|
||||
### Notes
|
||||
* `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`.
|
||||
* `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.
|
||||
|
||||
# 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 |
|
||||
|---|---|---|---|---|
|
||||
|2| TX_FAULT | B-R262 | --- | |
|
||||
|3| TX_DISABLE | B-R263, T-R268 | GPIO38 | R262 = Pull-down 200R|
|
||||
|4| MODDEF2 – SDA | B-R261, T-R266 | GPIO39 | |
|
||||
|5| MODDEF1 – SCL | B-R260, T-R267 | GPIO40 | Shared with both SFP |
|
||||
|6| MODDEF0 – PRESENT | B-R259, T-R296 | GPIO30 | |
|
||||
|7| RATE SEL | B-R257 | --- | |
|
||||
|8| LOS | B-R258, T-R270 | GPIO37 | |
|
||||
|9| TO? | B-R256 | --- | |
|
||||
|
||||
## J2
|
||||
|
||||
* Location: Right SFP connector `J2`.
|
||||
* Connected to: 10GMAC number 3, first SerDes.
|
||||
|
||||
|`J2` SFP2 PINs | Signal | Component | GPIO | Notes |
|
||||
|---|---|---|---|---|
|
||||
|2| TX_FAULT | B-R70 | --- | |
|
||||
|3| TX_DISABLE | B-R10, B-R105-R, T-R88-L | GPIO54 | R10 = Pull-down 200R |
|
||||
|4| MODDEF2 – SDA | B-R26, T-R85 | GPIO41 | |
|
||||
|5| MODDEF1 – SCL | B-R15, T-R87 | GPIO40 | Shared with both SFP |
|
||||
|6| MODDEF0 – PRESENT | B-R14, T-R89 | GPIO50 | |
|
||||
|7| RATE SEL | B-R12 | --- | |
|
||||
|8| LOS | B-R13, T-R95 | GPIO51 | |
|
||||
|9| TO? | B-R11 | --- | |
|
||||
|
||||
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.
|
||||
|
||||
### T3, Slave Interface
|
||||
This connector goes to U4 `I2C EEPROM` and U10 `SPI FLASH`.
|
||||
Signals are based on that `U4` is likely a I2C-EEPROM, `U10` is likely other SPI-chip.
|
||||
|`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 |
|
||||
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` pin|GPIO|Signal|
|
||||
|---|---|---|
|
||||
| 1 | GPIO31 | U0TXD (Output) |
|
||||
| 2 | GND | |
|
||||
| 3 | GPIO32 | U0RXD (Input) |
|
||||
| 4 | 3V3 | |
|
||||
Note: 1 pin is square shaped.
|
||||
|
||||
### T8
|
||||
|`T8` pin|what|Signal|
|
||||
|---|---|---|
|
||||
| 1 | GPIO46 | |
|
||||
| 2 | GND | |
|
||||
| 3 | GPIO48 | |
|
||||
| 4 | 3V3 | |
|
||||
| 5 | GPIO47 | |
|
||||
| 6 | GPIO49 | |
|
||||
Note: 1 pin is square shaped.
|
||||
|
||||
# Reset ciruit
|
||||
| Cmp | Function |
|
||||
|---|---|
|
||||
| T-R78 | 33k PullUp |
|
||||
| T-D3 | Discharge Diode |
|
||||
| T-C187 | RC-Delay |
|
||||
|
||||
Reset-line found at `T-D3-D` active-low.
|
||||
|
||||
# GPIO
|
||||
| HEX VAL. | GPIO | Component | What | | GPIO | Component | What |
|
||||
| -------- | ------ | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| 00000001 | GPIO00 | T-C151-T, T-R28-T, T-R29-T |? | | GPIO32 | T-R143-R | U0RXD |
|
||||
| 00000002 | GPIO01 | T-C152-T |? | | GPIO33 | | |
|
||||
| 00000004 | GPIO02 | T-C153-T |? | | GPIO34 | | |
|
||||
| 00000008 | GPIO03 | T-R33-T |? | | GPIO35 | | |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 00000400 | GPIO10 | | | | GPIO42 | U8-P6, T-R124 | SPI-MEMORY, CLK |
|
||||
| 00000800 | GPIO11 | |LEDx[^1] | | GPIO43 | U8-P5, T-R127 | SPI-MEMORY, DI,IO0 |
|
||||
| 00001000 | GPIO12 | |LEDx[^1] | | GPIO44 | U8-P2, T-R128 | SPI-MEMORY, DO,IO1 |
|
||||
| 00002000 | GPIO13 | PORT1-LED-GREEN |LEDx[^1] | | GPIO45 | U8-P1, T-R123 | SPI-MEMORY, CS |
|
||||
| 00004000 | GPIO14 | PORT1-LED-YELLOW |LEDx | | GPIO46 | T8-1, T-R188| ? |
|
||||
| 00008000 | GPIO15 | |LEDx[^1] | | GPIO47 | T8-5, T-R190 | ? |
|
||||
| 00010000 | GPIO16 | PORT2-LED-GREEN |LEDx[^1] | | GPIO48 | T8-3, T-R189 | ? |
|
||||
| 00020000 | GPIO17 | PORT2-LED-YELLOW |LEDx | | GPIO49 | T8-6, T-R190 | ? |
|
||||
| 00040000 | GPIO18 | |LEDx[^1] | | GPIO50 | SFP2-6, T-R89 | SFP-DETECT |
|
||||
| 00080000 | GPIO19 | PORT3-LED-GREEN |LEDx[^1] | | GPIO51 | SFP2-8, T-R95 | SFP-LOS |
|
||||
| 00100000 | GPIO20 | PORT3-LED-YELLOW |LEDx | | GPIO52 | | |
|
||||
| 00200000 | GPIO21 | |LEDx[^1] | | GPIO53 | | |
|
||||
| 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 | |
|
||||
| 01000000 | GPIO24 | SFP1-LED-J4, T-R35 |LED-SFP1 | | GPIO56 | | |
|
||||
| 02000000 | GPIO25 | | | | GPIO57 | | |
|
||||
| 04000000 | GPIO26 | ? |LEDx | | GPIO58 | | |
|
||||
| 08000000 | GPIO27 | R44L |? | | GPIO59 | | |
|
||||
| 10000000 | GPIO28 | LED-SYSTEM, T-R50-R |LED-SYSTEM | | GPIO60 | | |
|
||||
| 20000000 | GPIO29 | T-R187-R | | | GPIO61 | | |
|
||||
| 40000000 | GPIO30 | SFP1-6, T-R269 |SFP-DETECT | | GPIO62 | | |
|
||||
| 80000000 | GPIO31 | T-R144-R |U0TXD| | GPIO63 | | |
|
||||
|
||||
# LEDs
|
||||
|
||||
| NAME | COMPONENTS | GPIO | Active |
|
||||
| ---- | ---------- | ---- | ------ |
|
||||
| SYSTEM | T-R50-R (PU-4k2), T-R49-L, T-C185-L, B-R90 | GPIO28 | Low |
|
||||
| SFP1 | T-R35-L (PU-3k9), T-R34-L, T-C179-L | GPIO24 | Low |
|
||||
| SFP2 | T-R36-T (PD-4k0) | GPIO09 | High |
|
||||
| PORT1-LED-YELLOW | | GPIO14 | Low |
|
||||
| PORT2-LED-YELLOW | | GPIO17 | Low |
|
||||
| PORT3-LED-YELLOW | | GPIO20 | Low |
|
||||
| PORT4-LED-YELLOW | | GPIO23 | Low |
|
||||
|
||||
# Power supply
|
||||
|
||||
Board has two supply rails.
|
||||
`0.95` and `3.3` volt.
|
||||
|
||||
## `0.95` Core Voltage.
|
||||
|
||||
Voltage is made by a `Richtek RT8120A` Buck converter.
|
||||
0.95V must be within 3%.
|
||||
|
||||
## `3.3` Voltage
|
||||
|
||||
Voltage is crated by a `TMI3244T` Buck converter.
|
||||
3.3V must be within 4.5%.
|
||||
Chip can deliver up to 4A and the sweetspot is at 1A.
|
||||
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.
|
||||
[^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.
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 7.8 MiB |
|
Before Width: | Height: | Size: 8.8 MiB |
@@ -1,41 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,58 +0,0 @@
|
||||
#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.
|
||||
@@ -1,135 +0,0 @@
|
||||
# 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.
|
||||
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 83 KiB |
@@ -32,7 +32,7 @@ cleared by the ASIC. Data then is in the output data registers
|
||||
#define RTL837x_L2_DATA_OUT_C 0x5cd4
|
||||
|
||||
DATA_OUT_A DATA_OUT_B L2_DATA_OUT_C
|
||||
M2 M3 M4 M5 fV VV M0 M1 xx xF xx gg
|
||||
M2 M3 M4 M5 fV VV M0 M1 xx xF xx xg
|
||||
|
||||
M0-M5: 6 bytes of MAC, M0 is MSB
|
||||
V: 12 bits of VLAN-ID
|
||||
@@ -41,9 +41,6 @@ f: bit 5 set: Entry is valid, otherwise stale
|
||||
bit 7: bit 1 of port-number
|
||||
g: bit 0: bit 2 of port-number
|
||||
bit 1: bit 3 of port-number (MSB)
|
||||
bit 2: bit 0 of entry-age
|
||||
bit 3: bit 1 of entry-age
|
||||
bit 4: bit 2 of entry-age (MSB)
|
||||
F: bit 0: entry is static(1) or learned (0)
|
||||
```
|
||||
The next entry can be now found in RTL837x_TBL_DATA_0 (entry = RTL837x_TBL_DATA_0_bits(0-11) + 1),
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,46 +0,0 @@
|
||||
# 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 / 2 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 `16 MBit / 4 MiB` (theoretic max. `128 MBit / 32 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 |
|
||||
| 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.
|
||||
@@ -1,25 +0,0 @@
|
||||
# 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
|
||||
|
||||
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/)
|
||||
@@ -0,0 +1,25 @@
|
||||
# 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
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
../config.txt
|
||||
@@ -1,55 +0,0 @@
|
||||
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(error) {
|
||||
console.error("Error: ", err);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/main.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>EEE Configuration</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<h1>EEE Status</h1>
|
||||
<table id="eeetable">
|
||||
<tr> <th> </th> <th colspan="3"> Advertising </th> <th colspan="3">Link-Partner advertises</th> <th></th></tr>
|
||||
<tr> <th>Port</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>Active?</th></tr>
|
||||
</table>
|
||||
<div>
|
||||
<input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 1);" type="button" value="Enable EEE">
|
||||
<input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 0);" type="button" value="Disable EEE">
|
||||
</div>
|
||||
<script src="/eee.js"></script>
|
||||
<script src="/eee_sub.js"></script>
|
||||
</div>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
function createEEE() {
|
||||
var tbl = document.getElementById('eeetable');
|
||||
if (tbl.rows.length <= 2 && numPorts) {
|
||||
clearInterval(createEEEInterval);
|
||||
console.log("CREATING TABLE ", tbl.rows.length);
|
||||
for (let i = 2; i < 2 + numPorts; i++) {
|
||||
console.log("Table row: " + i + "pState: " + pState[i-2]);
|
||||
const tr = tbl.insertRow();
|
||||
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
|
||||
for (let j = 0; j < 7; j++) {
|
||||
td = tr.insertCell(); td.appendChild(document.createTextNode(" "));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEEE() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
const s = JSON.parse(xhttp.responseText);
|
||||
console.log("EEE: ", JSON.stringify(s));
|
||||
var tbl = document.getElementById('eeetable');
|
||||
if (tbl.rows.length > 2 && numPorts) {
|
||||
for (let i = 2; i < 2 + numPorts; i++) {
|
||||
p = s[i-2];
|
||||
let n = p.portNum;
|
||||
console.log("Table Update row: " + i + " portNum is " + n + ", pState is " + pState[i-2]);
|
||||
let tr = tbl.rows[n+1];
|
||||
if (!p.isSFP) {
|
||||
let eee = parseInt(p.eee,2); let lp = parseInt(p.eee_lp,2);
|
||||
tr.cells[1].innerHTML = `${eee&4?"ON":"OFF"}`; tr.cells[2].innerHTML = `${eee&2?"ON":"OFF"}`; tr.cells[3].innerHTML = `${eee&1?"ON":"OFF"}`;
|
||||
tr.cells[4].innerHTML = `${lp&4?"ON":"OFF"}`; tr.cells[5].innerHTML = `${lp&2?"ON":"OFF"}`; tr.cells[6].innerHTML = `${lp&1?"ON":"OFF"}`;
|
||||
tr.cells[7].innerHTML = `${p.active}`;
|
||||
tr.classList.toggle('disabled', pState[i-2] < 0); tr.classList.toggle('isNOK', !p.active); tr.classList.toggle('isOK', p.active);
|
||||
}
|
||||
tr.classList.toggle('isSFP', p.isSFP);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", "/eee.json", true);
|
||||
xhttp.timeout = 1500; xhttp.send();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
getEEE();
|
||||
const iCount = setInterval(getEEE, 2000);
|
||||
});
|
||||
const createEEEInterval = setInterval(createEEE, 1000);
|
||||
@@ -1,18 +0,0 @@
|
||||
async function eeeSub(port, enable) {
|
||||
var cmd = "eee ";
|
||||
if (enable)
|
||||
cmd = cmd + "on";
|
||||
else
|
||||
cmd = cmd + "off";
|
||||
console.log("eeeSub port " + port, ", value " + enable);
|
||||
try {
|
||||
const response = await fetch('/cmd', {
|
||||
method: 'POST',
|
||||
body: cmd
|
||||
});
|
||||
console.log('Completed!', response);
|
||||
} catch(err) {
|
||||
console.error(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/main.js"></script>
|
||||
<script src="/main_info.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>FreeSwitchOS Main Page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<head>
|
||||
<title>FreeSwitchOS Main Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="ports"> <img id="port1" width="40" height="40" src="port.svg"/> <img id="port2" width="40" height="40" src="port.svg"/>
|
||||
<img id="port3" width="40" height="40" src="port.svg"/> <img id="port4" width="40" height="40" src="port.svg"/> <img id="sfp1" width="60" height="60" src="sfp.svg"/>
|
||||
<img id="sfp2" width="60" height="60" src="sfp.svg"/> </div>
|
||||
<h1>Switch Configuration</h1>
|
||||
<table id="infoTable">
|
||||
<tr>
|
||||
<th colspan="2">Settings</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<table>
|
||||
<tr> <th>Setting</th> <th></th> </tr>
|
||||
#{html_index}
|
||||
</table>
|
||||
</div>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,139 +0,0 @@
|
||||
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; xhttp.send();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
l2GetInterval = setInterval(getL2, 1000);
|
||||
});
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,78 +0,0 @@
|
||||
var lagInterval = Number();
|
||||
|
||||
function lagForm() {
|
||||
if (!numPorts)
|
||||
return;
|
||||
clearInterval(lagInterval);
|
||||
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;
|
||||
}
|
||||
window.addEventListener("load", function() {
|
||||
lagInterval = setInterval(lagForm, 200);
|
||||
});
|
||||
|
||||
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);
|
||||
xhttp.send();
|
||||
}
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<!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>
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
var txG = new BigInt64Array(10);
|
||||
var txB = new BigInt64Array(10);
|
||||
var rxG = new BigInt64Array(10);
|
||||
var rxB = new BigInt64Array(10);
|
||||
const linkS = ["Disabled", "No Link", "100M", "1000M", "500M", "10G", "2.5G", "5G"];
|
||||
var pState = new Int8Array(10);
|
||||
var pIsSFP = new Int8Array(10);
|
||||
var pAdvertised = new Int8Array(10);
|
||||
var numPorts = 0;
|
||||
var logToPhysPort = new Int8Array(10);
|
||||
var physToLogPort = new Int8Array(10);
|
||||
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() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 401)
|
||||
document.location = "/login.html"
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
const s = JSON.parse(xhttp.responseText);
|
||||
if (!numPorts) {
|
||||
numPorts = s.length;
|
||||
for (let i = 0; i < s.length; i++)
|
||||
pIsSFP[s[i].portNum-1] = s[i].isSFP;
|
||||
drawPorts();
|
||||
}
|
||||
console.log("RES:", JSON.stringify(s));
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
p = s[i];
|
||||
let n = p.portNum;
|
||||
logToPhysPort[p.logPort] = n;
|
||||
physToLogPort[n-1] = p.logPort;
|
||||
let pid = "port" + n;
|
||||
let ttid = "tt_" + n;
|
||||
n--;
|
||||
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 tt = document.getElementById(ttid);
|
||||
if (psvg == null || !psvg.contentDocument)
|
||||
continue;
|
||||
var bgs = psvg.contentDocument.getElementsByClassName("bg");
|
||||
var leds = psvg.contentDocument.getElementsByClassName("led");
|
||||
if (p.enabled == 0) {
|
||||
pState[n] = -1;
|
||||
bgs[0].style.fill = "red";
|
||||
leds[0].style.fill = "black"; leds[1].style.fill = "black";
|
||||
psvg.style.opacity = 0.4;
|
||||
tt.innerHTML = "Not enabled.";
|
||||
} else {
|
||||
psvg.style.opacity = 1.0;
|
||||
pState[n] = p.link;
|
||||
if (p.link == 4 || p.link == 5 || p.link == 6) {
|
||||
leds[0].style.fill = "green"; leds[1].style.fill = "orange";
|
||||
} else if (p.link == 1 || p.link == 2 || p.link == 3) {
|
||||
leds[0].style.fill = "green"; leds[1].style.fill = "green";
|
||||
} else {
|
||||
leds[0].style.fill = "black"; leds[1].style.fill = "black";
|
||||
psvg.style.opacity = 0.4
|
||||
}
|
||||
var iHTML = "<table border=\"0\" class=\"tt_table\">";
|
||||
iHTML += "<tr><td align=\"left\">Link speed</td><td>:</td><td>" + linkS[p.link + 1] + "</td></tr>";
|
||||
if (p.isSFP) {
|
||||
pAdvertised[n] = 0;
|
||||
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 (p.sfp_options & 0x40) {
|
||||
iHTML += "<tr><td>Temp</td><td>:</td><td>" + (Number(p.sfp_temp) >> 8) + "." + ((Number(p.sfp_temp) & 0xff)/256.0 * 100).toFixed(0) + " ℃</td></tr>";
|
||||
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + (Number(p.sfp_vcc) / 10000.0).toFixed(2) + " V</td></tr>";
|
||||
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + (Number(p.sfp_txbias) / 500.0).toFixed(1) + " mA</td></tr>";
|
||||
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + (Number(p.sfp_txpower) / 10.0).toFixed(0) + " mW</td></tr>";
|
||||
iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + (Number(p.sfp_rxpower) / 10.0).toFixed(0) + " mW</td></tr>";
|
||||
}
|
||||
} else {
|
||||
pAdvertised[n] = parseInt(p.adv, 2);
|
||||
}
|
||||
iHTML += "</table>";
|
||||
tt.innerHTML = iHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", "/status.json", true);
|
||||
xhttp.timeout = 5000; xhttp.send();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
update();
|
||||
const interval = setInterval(update, 2000);
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
fetch('/information.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const tableBody = document.getElementById('infoTable').querySelector('tbody');
|
||||
|
||||
// Create table rows
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
const row = document.createElement('tr');
|
||||
const cellKey = document.createElement('td');
|
||||
const cellValue = document.createElement('td');
|
||||
|
||||
cellKey.textContent = key;
|
||||
cellValue.textContent = value;
|
||||
|
||||
row.appendChild(cellKey);
|
||||
row.appendChild(cellValue);
|
||||
tableBody.appendChild(row);
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error fetching the data:', error));
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/main.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Mirror Configuration</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<h1>Mirror Configuration</h1>
|
||||
<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"/>
|
||||
<h2>Mirrored Ports (TX)</h2>
|
||||
<div id="mPortsTX"></div>
|
||||
<br />
|
||||
<h2>Mirrored Ports (RX)</h2>
|
||||
<div id="mPortsRX"></div>
|
||||
<br/> <input style="width:15%;" class="action" id="mirror_sub" onclick="mirrorSub();" type="button" value="Update / Create">
|
||||
<input style="width:15%;" class="action" id="mirror_del" onclick="mirrorDel();" type="button" value="Disable Mirroring">
|
||||
<script src="/mirror.js"></script>
|
||||
<script src="/mirror_sub.js"></script>
|
||||
</div>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,61 +0,0 @@
|
||||
var mirrorInterval = Number();
|
||||
const mirrors = ["mPortsTX", "mPortsRX"];
|
||||
|
||||
function mirrorForm() {
|
||||
if (!numPorts)
|
||||
return;
|
||||
clearInterval(mirrorInterval);
|
||||
for (let j=0; j < mirrors.length; j++) {
|
||||
console.log("Adding Mirror " + j)
|
||||
var m = document.getElementById(mirrors[j]);
|
||||
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 = mirrors[j] + 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);
|
||||
}
|
||||
}
|
||||
fetchMirror();
|
||||
}
|
||||
|
||||
function setM(p, c){
|
||||
document.getElementById(p).checked=c;
|
||||
}
|
||||
window.addEventListener("load", function() {
|
||||
mirrorInterval = setInterval(mirrorForm, 200);
|
||||
});
|
||||
|
||||
function fetchMirror() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
const s = JSON.parse(xhttp.responseText);
|
||||
console.log("MIRROR: ", JSON.stringify(s));
|
||||
document.getElementById('me').checked = s.enabled;
|
||||
document.getElementById('mp').value = s.mPort;
|
||||
let m_tx = parseInt(s.mirror_tx, 2);
|
||||
let m_rx = parseInt(s.mirror_rx, 2);
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
let p = i - 1;
|
||||
if (numPorts < 9)
|
||||
p = physToLogPort[p];members & (1<<p)
|
||||
setM("mPortsTX"+i, m_tx&(1<<p)); setM("mPortsRX"+i, m_rx&(1<<p));
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", `/mirror.json`, true);
|
||||
xhttp.send();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
async function mirrorSub() {
|
||||
var cmd = "mirror ";
|
||||
var mp=document.getElementById('mp').value
|
||||
if (!mp) {
|
||||
alert("Set Mirroring Port first");
|
||||
return;
|
||||
}
|
||||
document.getElementById(mirrors[0]+mp).checked=false;document.getElementById(mirrors[1]+mp).checked=false;
|
||||
cmd = cmd + mp;
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
if (document.getElementById(mirrors[0] + i).checked && document.getElementById(mirrors[1] + i).checked)
|
||||
cmd = cmd + ` ${i}`;
|
||||
else if (document.getElementById(mirrors[0] + i).checked)
|
||||
cmd = cmd + ` ${i}t`;
|
||||
else if (document.getElementById(mirrors[1] + i).checked)
|
||||
cmd = cmd + ` ${i}r`;
|
||||
}
|
||||
if (cmd.length < 10) {
|
||||
alert("Select Mirrored Ports");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/cmd', {
|
||||
method: 'POST',
|
||||
body: cmd
|
||||
});
|
||||
console.log('Completed!', response);
|
||||
} catch(err) {
|
||||
console.error(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
async function mirrorDel() {
|
||||
var cmd = "mirror off";
|
||||
try {
|
||||
const response = await fetch('/cmd', {
|
||||
method: 'POST',
|
||||
body: cmd
|
||||
});
|
||||
location.reload();
|
||||
} catch(err) {
|
||||
console.error(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
document.getElementById('sidebar').innerHTML =
|
||||
"<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='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='lag.html'>Link Aggregation</a></li>"
|
||||
+ "<li><a href='eee.html'>EEE</a></li>"
|
||||
+ "<li><a href='system.html'>System Settings</a></li>"
|
||||
+ "<li><a href='update.html'>Firmware Update</a></li></ul>";
|
||||
@@ -4,7 +4,7 @@
|
||||
<g id="g1" transform="translate(256.16 417.12)">
|
||||
<rect id="r1" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:4;fill:#ffffff" rx="4.514" ry="4.514" height="90.625" width="117.88" y="69.93" x="59.896"/>
|
||||
<g id="g2"> <g id="g3">
|
||||
<path class="bg" id="rect3787"
|
||||
<path id="rect3787"
|
||||
d="m73.958 75.66h89.41c2.3083 0 4.1667 1.8583 4.1667 4.1667l0.00028 52.653h-21.742v9.414h-8.694l0.00004 12.586h-36.871l-0.00004-12.586h-8.694v-9.414h-21.742l-0.000336-52.653c-0.000011-2.3083 1.8583-4.1667 4.1667-4.1667z"
|
||||
style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2.5;fill:#dcdcdc"/>
|
||||
<g id="g4" transform="translate(-0.368)" style="stroke:#191919;stroke-linecap:square;fill:#666666">
|
||||
@@ -18,8 +18,8 @@
|
||||
<rect id="r9" height="22.786" width="3.9062" y="75.747" x="143.17"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect class="led" id="r10" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2;fill:#1dfe0a" height="13.89" width="17.1" y="137.03" x="69.542"/>
|
||||
<rect class="led" id="r11" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2;fill:#ffd10a" height="13.89" width="17.1" y="137.03" x="150.68"/>
|
||||
<rect id="r10" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2;fill:#1dfe0a" height="13.89" width="17.1" y="137.03" x="69.542"/>
|
||||
<rect id="r11" style="stroke:#0a0a0a;stroke-linecap:square;stroke-width:2;fill:#ffd10a" height="13.89" width="17.1" y="137.03" x="150.68"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,24 +0,0 @@
|
||||
<!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>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,146 +0,0 @@
|
||||
var mtus = new Int16Array(10);
|
||||
var clicked = new Int8Array(10);
|
||||
function createPortTable() {
|
||||
var tbl = document.getElementById('speedtable');
|
||||
if (tbl.rows.length <= 2 && numPorts) {
|
||||
clearInterval(pTableInterval);
|
||||
const sSelect = '<select name="speed_sel" id="speed_sel">'
|
||||
+ '<option value="auto">Auto</option>'
|
||||
+ '<option value="2g5">2500MBit/Full</option>'
|
||||
+ '<option value="1g">1000MBit/Full</option>'
|
||||
+ '<option value="100m full">100MBit/Full</option>'
|
||||
+ '<option value="100m half">100MBit/Half</option>'
|
||||
+ '<option value="10m full">10MBit/Full</option>'
|
||||
+ '<option value="10m half">10MBit/Half</option>'
|
||||
+ '</select>';
|
||||
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}`));
|
||||
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;
|
||||
}
|
||||
}
|
||||
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[1].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];
|
||||
clearInterval(pMTUInterval);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", "/mtu.json", true);
|
||||
xhttp.timeout = 1500; xhttp.send();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
const updatePortTableInterval = setInterval(updatePortTable, 1000);
|
||||
});
|
||||
|
||||
const pTableInterval = setInterval(createPortTable, 1000);
|
||||
const pMTUInterval = setInterval(getMTUs, 1200);
|
||||
@@ -6,18 +6,18 @@
|
||||
<path id="p1"
|
||||
d="m 117.94442,272.67478 h 7.64646 c 0.21062,0 0.38018,0.16649 0.38018,0.3733 v 4.69239 c 0,0.2068 -0.16956,0.3733 -0.38018,0.3733 h -2.1027 v 0.31956 h -3.44117 v -0.31956 h -2.1027 c -0.21062,0 -0.38018,-0.16649 -0.38018,-0.3733 v -4.69239 c 0,-0.20681 0.16956,-0.3733 0.38018,-0.3733 z"
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.4"/>
|
||||
<path class="bg" id="p2"
|
||||
<path id="p2"
|
||||
d="m 118.36775,273.15632 h 6.79794 c 0.18725,0 0.338,0.14695 0.338,0.32946 v 4.14153 c 0,0.18252 -0.15074,0.32946 -0.338,0.32946 h -6.79794 c -0.18724,0 -0.338,-0.14695 -0.338,-0.32946 v -4.14153 c 0,-0.18252 0.15074,-0.32946 0.338,-0.32946 z"
|
||||
style="fill:#000000;stroke-width:0.26" />
|
||||
<path d="m 118.65,273.53 h 6.24 v 4.05 h -6.24 z" style="fill:#1a1a1a;stroke-width:0.26" id="p3" />
|
||||
<path d="m 118.86,276.61 h 5.82" style="fill:#1a1a1a;stroke:#000000;stroke-width:0.26" id="p4" />
|
||||
<path d="m 124.05,274.25 h 1.39 v 0.72 h -1.39 z" style="fill:#1a1a1a;stroke-width:0.26" id="p5" />
|
||||
<path d="m 124.05,276 h 1.39 v 0.72 h -1.39 z" style="fill:#1a1a1a;stroke-width:0.26" id="p6" />
|
||||
<path d="m 124.05,274.25 h 1.39 v 0.72 h -1.39 z" style="fill:url(#linearGradient63614);stroke-width:0.26" id="p5" />
|
||||
<path d="m 124.05,276 h 1.39 v 0.72 h -1.39 z" style="fill:url(#linearGradient63616);stroke-width:0.26" id="p6" />
|
||||
<path transform="matrix(0.26,0,0,0.26,116.9,272.11)" d="M 7.3648613,7.0152205 H 29.369861" style="opacity:0.61257;fill:#4d4d4d;stroke:#4d4d4d;filter:url(#filter17794-0)" id="p7" />
|
||||
</g>
|
||||
<g id="g3" style="opacity:1;fill:#37d733;" transform="matrix(0.93,0,0,0.92,62.18,-43.11)">
|
||||
<circle class="led" id="c1" cx="176.86" cy="125.7" r="0.93"/>
|
||||
<circle class="led" id="c2" r="0.93" cy="125.7" cx="180.84"/>
|
||||
<circle id="c1" cx="176.86" cy="125.7" r="0.93"/>
|
||||
<circle id="c2" r="0.93" cy="125.7" cx="180.84"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/main.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<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>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<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>
|
||||
<table id="statstable">
|
||||
<tr> <th>Port</th> <th>link</th> <th>TX Good</th> <th>TX Bad</th> <th>RX Good</th> <th>RX Bad</th> <th> All Counters </th></tr>
|
||||
<script src="/stat.js"></script>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/navigation.js"></script>
|
||||
</html>
|
||||
@@ -1,198 +0,0 @@
|
||||
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; xhttp.send();
|
||||
}
|
||||
|
||||
|
||||
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`));
|
||||
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';
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Statistics</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Port configuration:</h1>
|
||||
<p>#{stat_content}</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,164 +0,0 @@
|
||||
h1, h2, h3 {
|
||||
color: #226;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 12%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
li a {
|
||||
background-color: #aaf;
|
||||
display: block;
|
||||
color: #000;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Change the link color on hover */
|
||||
li a:hover {
|
||||
background-color: #226;
|
||||
color: white;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid #226;
|
||||
padding: 8px;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input[type=submit] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;border-radius: 15px;width: 100%;}
|
||||
input[type=submit]:hover { background-color: #226; color: white;}
|
||||
input[type=file] { padding: 8px 16px;background-color:#aaf;color:#000; margin-bottom: 2em;border-radius: 15px;width: 60%;}
|
||||
input[type=file]:hover { background-color: #226; color: white;}
|
||||
b
|
||||
button {padding: 8px; background-color:#99f; color:#000;border-radius: 15px;}
|
||||
button:hover { background-color: #226; color: white;}
|
||||
.action{padding: 8px 16px;margin-top: 2em;margin-right: 3em; background-color: #aaf;color: #000;border-radius: 15px; width: 100%;}
|
||||
.action:hover { background-color: #226; color: white;}
|
||||
|
||||
/* Port selection inputs */
|
||||
.psel {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.psel + img {
|
||||
cursor: pointer;
|
||||
opacity: 0.4;
|
||||
padding: 8px;
|
||||
}
|
||||
.psel:checked + img {
|
||||
/* outline: 2px solid #f00;*/
|
||||
opacity: 1.0;
|
||||
}
|
||||
object, img {
|
||||
margin: 0.5em 0.5em;
|
||||
}
|
||||
.cbgroup {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.cbgroup label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.disabled{ opacity: .4; background-color: #f88; color: #000}
|
||||
.isSFP{ opacity: .4; background-color: #660;}
|
||||
.isNOK{ color: #900;}
|
||||
.isOK{ color: #090;}
|
||||
.ip{padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
|
||||
.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}
|
||||
@@ -1,36 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>System Settings</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<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/><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/><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>
|
||||
<script src="/config.js"></script>
|
||||
<script src="/system.js"></script>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,76 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", `/information.json`, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
systemInterval = setInterval(fetchIP, 1000);
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Firmware update</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;width:40%;">
|
||||
<h1>Firmware Update</h1>
|
||||
<form enctype="multipart/form-data" action="/upload" method="POST">
|
||||
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
|
||||
Choose a firmware update file to upload: <br/> <br/>
|
||||
<input name="uploadedfile" type="file" accept=".bin" /><br />
|
||||
<input style="margin-top:3em" type="submit" value="Upload File" />
|
||||
</form>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/main.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>FreeSwitchOS VLAN Configuration</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="sidebar"></nav>
|
||||
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
|
||||
<div id="ports"></div>
|
||||
<h1>VLAN Configuration</h1>
|
||||
<form id="vform" action="/vlan.html">
|
||||
<div>
|
||||
<label for="vid">VLAN ID:</label>
|
||||
<input type="number" min="1" max="2047" id="vid" name="vid">
|
||||
<button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();">Get Configuration</button>
|
||||
</div>
|
||||
<br/><br/>
|
||||
<label for="vname">VLAN Name:</label>
|
||||
<input type="text" id="vname" name="vname"><br><br>
|
||||
<br/>
|
||||
<h2>Tagged Ports</h2>
|
||||
<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>
|
||||
<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>
|
||||
<br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" value="Update / Create">
|
||||
<script src="/vlan_sub.js"></script>
|
||||
</form>
|
||||
</div>
|
||||
<script src="/navigation.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,87 +0,0 @@
|
||||
var vlanInterval = Number();
|
||||
|
||||
function vlanForm() {
|
||||
if (!numPorts)
|
||||
return;
|
||||
clearInterval(vlanInterval);
|
||||
var t = document.getElementById('tPorts');
|
||||
var u = document.getElementById('uPorts');
|
||||
var p = document.getElementById('pPorts');
|
||||
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 = "tport" + i;
|
||||
inp.setAttribute('onclick', `setC("u", ${i}, false);`);
|
||||
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)
|
||||
t.appendChild(d);
|
||||
var d2=d.cloneNode(true);
|
||||
d2.children[0].children[0].id = "uport" + i;
|
||||
d2.children[0].children[0].setAttribute('onclick', `setC("t", ${i}, false);`);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function setC(t, p, c){
|
||||
document.getElementById(t+'port'+p).checked=c;
|
||||
// When a tagged port is checked, automatically select the PVID port as well
|
||||
const tportElem = document.getElementById('tport'+p);
|
||||
if (tportElem && tportElem.checked) {
|
||||
document.getElementById('pport'+p).checked=true;
|
||||
}
|
||||
}
|
||||
|
||||
function utClicked(t){
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
setC('t', i, t); setC('u', i, !t);
|
||||
}
|
||||
}
|
||||
|
||||
function pvClicked(p){
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
setC('p', i, p);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
vlanInterval = setInterval(vlanForm, 100);
|
||||
});
|
||||
|
||||
function fetchVLAN() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
const s = JSON.parse(xhttp.responseText);
|
||||
console.log("VLAN: ", JSON.stringify(s));
|
||||
m = parseInt(s.members, 16);
|
||||
document.getElementById('vname').value = s.name;
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
setC('t', i, (m>>(10+i-1))&1);
|
||||
setC('u', i, (m>>(i-1))&1);
|
||||
setC('p', i, (m>>(20+i-1))&1);
|
||||
}
|
||||
}
|
||||
};
|
||||
var v=document.getElementById('vid').value
|
||||
if (!v) {
|
||||
alert("Set VLAN ID first");
|
||||
return;
|
||||
}
|
||||
xhttp.open("GET", `/vlan.json?vid=${v}`, true);
|
||||
xhttp.send();
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
async function vlanSub() {
|
||||
var commands = [];
|
||||
var cmd = "vlan ";
|
||||
var v=document.getElementById('vid').value
|
||||
if (!v) {
|
||||
alert("Set VLAN ID first");
|
||||
return;
|
||||
}
|
||||
cmd = cmd + v;
|
||||
if (document.getElementById('vname').value)
|
||||
cmd = cmd + ' ' + document.getElementById('vname').value;
|
||||
for (let i = 1; i <= numPorts; i++) {
|
||||
if (document.getElementById('tport' + i).checked)
|
||||
cmd = cmd + ` ${i}t`;
|
||||
else if (document.getElementById('uport' + i).checked)
|
||||
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 {
|
||||
for (let c of commands) {
|
||||
const response = await fetch('/cmd', {
|
||||
method: 'POST',
|
||||
body: c
|
||||
});
|
||||
console.log('Completed!', response);
|
||||
}
|
||||
} catch(err) {
|
||||
console.error(`Error: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
CC = sdcc
|
||||
CC_FLAGS = -mmcs51 -I. -I.. -I../uip
|
||||
CC_FLAGS = -mmcs51 -I. -I../uip
|
||||
ASM = sdas8051
|
||||
AFLAGS= -plosgff
|
||||
|
||||
BUILDDIR = output/
|
||||
|
||||
SRCS = httpd.c page_impl.c
|
||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
||||
OBJS = ${SRCS:.c=.rel}
|
||||
|
||||
all: create_build_dir $(OBJS)
|
||||
all: $(OBJS)
|
||||
|
||||
create_build_dir:
|
||||
mkdir -p $(BUILDDIR)
|
||||
%.asm: %.c
|
||||
$(CC) $(CC_FLAGS) -c -S $<
|
||||
|
||||
$(BUILDDIR)%.asm: %.c
|
||||
$(CC) $(CC_FLAGS) -o $@ -c -S $<
|
||||
|
||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
||||
${ASM} ${AFLAGS} -o $@ $^
|
||||
%.rel: %.asm
|
||||
./treatasm.py $^ >$^.new
|
||||
mv $^.new $^
|
||||
${ASM} ${AFLAGS} $^
|
||||
|
||||
clean:
|
||||
rm -r $(BUILDDIR)
|
||||
rm .asm *.lst *.rel *.rst *.sym
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
|
||||
@@ -1,96 +1,45 @@
|
||||
|
||||
#include "httpd.h"
|
||||
#include "page_impl.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "cmd_parser.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "../rtl837x_common.h"
|
||||
#include "../rtl837x_flash.h"
|
||||
#include "uip.h"
|
||||
#include "html_data.h"
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#define SESSION_ID_LENGTH 12
|
||||
#define SESSION_TIMEOUT 200
|
||||
|
||||
// Upload Firmware to 1M
|
||||
#define FIRMWARE_UPLOAD_START 0x100000
|
||||
|
||||
// SPI FLASH MEMORY PAGE SIZE.
|
||||
#define FLASHMEM_PAGE_SIZE 0x100
|
||||
#include "../html_data.h"
|
||||
|
||||
#define CMARK_S 6
|
||||
|
||||
#pragma codeseg 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 char * __code mime_strings[];
|
||||
extern __xdata struct flash_region_t flash_region;
|
||||
extern __code fcall_ptr f_calls[];
|
||||
|
||||
// Flash buffer to optimize flash writing speed, write_len is the current filling position
|
||||
extern __xdata uint8_t flash_buf[512];
|
||||
__xdata uint32_t uptr; // Current flash write position
|
||||
__xdata uint16_t write_len;
|
||||
|
||||
__xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
__xdata uint8_t entry;
|
||||
__xdata uint16_t slen;
|
||||
__xdata uint16_t o_idx;
|
||||
__xdata uint16_t mpos;
|
||||
__xdata uint16_t len_left;
|
||||
__xdata uint16_t cont_len;
|
||||
__xdata uint32_t cont_addr;
|
||||
|
||||
// HTTP header properties
|
||||
__xdata uint8_t boundary[72];
|
||||
__xdata uint8_t *content_type = 0;
|
||||
__xdata uint8_t *session = 0;
|
||||
|
||||
// Global variables holding POST state
|
||||
__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 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_TX 1
|
||||
#define TSTATE_ACKED 2
|
||||
#define TSTATE_CLOSED 3
|
||||
#define TSTATE_POST 4
|
||||
|
||||
extern __xdata uint16_t crc_value;
|
||||
__xdata uint16_t crc_final;
|
||||
void crc16(__xdata uint8_t *v) __naked;
|
||||
|
||||
|
||||
inline uint8_t is_separator(uint8_t c)
|
||||
inline uint8_t is_space(uint8_t c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '?' || c == '=';
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
|
||||
void httpd_init(void) __banked
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata struct httpd_state *s = &(uip_conn->appstate);
|
||||
// Start listening to port 80
|
||||
uip_listen(HTONS(80));
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
}
|
||||
|
||||
|
||||
uint8_t find_entry(__xdata uint8_t *e)
|
||||
uint8_t find_entry(uint8_t *e)
|
||||
{
|
||||
uint8_t i, j;
|
||||
register uint8_t i, j;
|
||||
|
||||
for (i = 0; f_data[i].len; i++) {
|
||||
j = 0;
|
||||
@@ -105,550 +54,133 @@ uint8_t find_entry(__xdata uint8_t *e)
|
||||
}
|
||||
|
||||
|
||||
char strcmp(__xdata uint8_t *c, __code uint8_t * __xdata d)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
while (d[i] && (d[i] == c[i]))
|
||||
i++;
|
||||
|
||||
if (c[i] < d[i])
|
||||
return -1;
|
||||
else if (c[i] > d[i])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char is_word(__xdata uint8_t *c, __code uint8_t * __xdata d)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
while (d[i] && (d[i] == c[i]))
|
||||
i++;
|
||||
|
||||
if (d[i])
|
||||
return 0;
|
||||
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
char is_word_x(__xdata uint8_t *c, __xdata uint8_t *d)
|
||||
{
|
||||
register uint8_t i = 0;
|
||||
|
||||
while (d[i] && (d[i] == c[i]))
|
||||
i++;
|
||||
|
||||
if (d[i])
|
||||
return 0;
|
||||
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint8_t parse_short(__xdata uint8_t *p)
|
||||
{
|
||||
uint8_t err = 1;
|
||||
uint8_t c = 0;
|
||||
|
||||
short_parsed = 0;
|
||||
while(1) {
|
||||
c = *p++ - '0';
|
||||
if (c > 9) { break; }
|
||||
err = 0;
|
||||
short_parsed = (short_parsed * 10) + c;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void send_not_found(void)
|
||||
{
|
||||
slen = strtox(outbuf, "HTTP/1.1 404 Not found\r\nContent-Type: text/html\r\n\r\n" \
|
||||
"<!DOCTYPE HTML PUBLIC>\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n");
|
||||
}
|
||||
|
||||
|
||||
void send_bad_request(void)
|
||||
{
|
||||
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n\r\n" \
|
||||
"<!DOCTYPE HTML PUBLIC>\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n");
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
while (*p) {
|
||||
if (is_word_x(p, boundary))
|
||||
return p + strlen_x(boundary);
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
__xdata uint8_t *scan_header(__xdata uint8_t *p)
|
||||
{
|
||||
content_type = 0;
|
||||
session = 0;
|
||||
authenticated = 0;
|
||||
|
||||
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
||||
dbg_char(*p);
|
||||
if (!*p++)
|
||||
break;
|
||||
if (is_word(p, "\nContent-Type:"))
|
||||
content_type = p + 15;
|
||||
else if (is_word(p, "\nCookie:"))
|
||||
session = p + 17;
|
||||
}
|
||||
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
|
||||
dbg_string("\nFound multipart\n");
|
||||
content_type += 30;
|
||||
uint8_t i = 0;
|
||||
while (content_type[i] != '\r' && content_type[i] != '\n') {
|
||||
boundary[i + 4] = content_type[i];
|
||||
i++;
|
||||
}
|
||||
// The boundary between parts is "\r\n--" + the boundary given in the header
|
||||
boundary[0] = '\r';
|
||||
boundary[1] = '\n';
|
||||
boundary[2] = '-';
|
||||
boundary[3] = '-';
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
* Input: the current position in the TCP buffer (uip_appdata)
|
||||
* Returns 1: More data to read, 0: Upload complete, all parts reads
|
||||
*/
|
||||
uint8_t stream_upload(uint16_t bptr)
|
||||
{
|
||||
__xdata uint8_t *p = uip_appdata;
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
|
||||
dbg_string("Stream_upload called: ");
|
||||
dbg_short(bptr); dbg_char('\n');
|
||||
|
||||
do {
|
||||
if (bptr >= uip_len) {
|
||||
s->tstate = TSTATE_POST;
|
||||
return 1;
|
||||
}
|
||||
// Have we reached the end of the part?
|
||||
if (!boundary[bindex]) {
|
||||
s->tstate = TSTATE_NONE;
|
||||
dbg_string("len 2: "); dbg_short(write_len); dbg_char(' ');
|
||||
flash_region.addr = uptr;
|
||||
flash_region.len = write_len;
|
||||
flash_write_bytes(flash_buf);
|
||||
uptr += write_len;
|
||||
write_len = 0;
|
||||
// TODO: This is a bit premature, what about a nice web-page saying the device will reset???
|
||||
if (verify_crc) {
|
||||
dbg_string("CRC16: "); dbg_short(crc_final); dbg_char('\n');
|
||||
if (crc_final == 0xb001) {
|
||||
print_string("Checksum OK.");
|
||||
} else {
|
||||
print_string("Checksum incorrect!");
|
||||
}
|
||||
print_string("\nUpload to flash done, will reset!\n");
|
||||
reset_chip();
|
||||
}
|
||||
// Make sure there is a 0 at the end of the uploaded data
|
||||
flash_buf[0] = 0;
|
||||
flash_region.addr = uptr;
|
||||
flash_region.len = 1;
|
||||
flash_write_bytes(flash_buf);
|
||||
if (bptr >= uip_len)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (p[bptr] == boundary[bindex]) {
|
||||
if (!bindex)
|
||||
crc_final = crc_value;
|
||||
crc16(p + bptr);
|
||||
bptr++;
|
||||
bindex++;
|
||||
} else {
|
||||
if (bindex) {
|
||||
memcpy(flash_buf + write_len, boundary, bindex);
|
||||
write_len += bindex;
|
||||
bindex = 0;
|
||||
}
|
||||
crc16(p + bptr);
|
||||
flash_buf[write_len++] = p[bptr++];
|
||||
if (write_len >= FLASHMEM_PAGE_SIZE) {
|
||||
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
||||
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
||||
flash_region.addr = uptr;
|
||||
flash_region.len = FLASHMEM_PAGE_SIZE;
|
||||
flash_write_bytes(flash_buf);
|
||||
uptr += FLASHMEM_PAGE_SIZE;
|
||||
write_len -= FLASHMEM_PAGE_SIZE;
|
||||
|
||||
// Copy the remaining byte for the next page to the beginning of the buffer.
|
||||
if (write_len > 0) {
|
||||
memcpy(flash_buf, flash_buf + FLASHMEM_PAGE_SIZE, write_len);
|
||||
}
|
||||
}
|
||||
bindex = 0;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
|
||||
void handle_post(void)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata uint8_t *p = uip_appdata;
|
||||
__xdata uint8_t *request_path = p + 6;
|
||||
|
||||
dbg_string("Is POST\n");
|
||||
p += 5; // Skip post
|
||||
// Find end of request path
|
||||
while (*p && !is_separator(*p))
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
|
||||
// Find end of request header
|
||||
boundary[0] ='\0';
|
||||
p = scan_header(p);
|
||||
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
||||
if (!*p || !content_type) {
|
||||
dbg_string("Bad Request!\n");
|
||||
send_not_found();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_word(request_path, "cmd")) {
|
||||
register uint8_t i = 0;
|
||||
p += 4;
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
while (*p && *p != '\n' && *p != '\r')
|
||||
cmd_buffer[i++] = *p++;
|
||||
cmd_buffer[i] = '\0';
|
||||
if (i)
|
||||
cmd_available = 1;
|
||||
} else if (is_word(request_path, "login")) {
|
||||
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]) {
|
||||
dbg_string("Bad request, no boundary!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
// We skip the intial parts as part of the header
|
||||
do {
|
||||
p = skip_boundary(p);
|
||||
if (!*p)
|
||||
goto bad_request;
|
||||
p = scan_header(p);
|
||||
if (!*p)
|
||||
goto bad_request;
|
||||
if (!content_type) // We are waiting for the part with the octet stream
|
||||
continue;
|
||||
} while (!is_word(content_type, "application/octet-stream"));
|
||||
dbg_string("Have content octets\n");
|
||||
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
|
||||
|
||||
if (is_word(request_path, "upload")) {
|
||||
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;
|
||||
bindex = 0;
|
||||
write_len = 0;
|
||||
stream_upload(p - uip_appdata);
|
||||
|
||||
dbg_string("Done reading first fragment\n");
|
||||
return;
|
||||
|
||||
} else {
|
||||
send_not_found();
|
||||
return;
|
||||
}
|
||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\n\r\n");
|
||||
return;
|
||||
bad_request:
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void httpd_appcall(void)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata struct httpd_state *s = &(uip_conn->appstate);
|
||||
__xdata uint8_t *outbuf = s->outbuf;
|
||||
|
||||
dbg_char('P');
|
||||
write_char('P');
|
||||
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
|
||||
dbg_string("Connected...\n");
|
||||
print_string("Connected...\n");
|
||||
s->tstate = TSTATE_NONE;
|
||||
} else if (uip_closed()) {
|
||||
dbg_string("Connection closed\n");
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
} else if (uip_aborted()) {
|
||||
dbg_string("Connection aborted\n");
|
||||
uip_close();
|
||||
print_string("Connection closed\n");
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
} else if (uip_poll()) {
|
||||
uip_len = 0;
|
||||
if (s->tstate == TSTATE_ACKED) {
|
||||
dbg_string("Closing because everything has been transmitted\n");
|
||||
print_string("Closing because everything has been transmitted\n");
|
||||
uip_close();
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
}
|
||||
// write_char('p');
|
||||
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
||||
dbg_string("ACK\n");
|
||||
if (slen > uip_mss()) {
|
||||
slen -= uip_mss();
|
||||
o_idx += uip_mss();
|
||||
print_string("ACK\n");
|
||||
if (s->slen > uip_mss()) {
|
||||
s->slen -= uip_mss();
|
||||
s->o_idx += uip_mss();
|
||||
} else {
|
||||
slen = 0;
|
||||
o_idx += slen;
|
||||
s->slen = 0;
|
||||
s->o_idx += s->slen;
|
||||
}
|
||||
|
||||
s->tstate = TSTATE_ACKED;
|
||||
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
if (s->slen > uip_mss()) {
|
||||
print_string("Sending A: "); print_short(s->slen); write_char('\n');
|
||||
uip_send(outbuf + s->o_idx, uip_mss());
|
||||
print_string("Sending A done\n");
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (slen > 0) {
|
||||
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
} else if (s->slen > 0) {
|
||||
print_string("Sending B: "); print_short(s->slen); write_char('\n');
|
||||
uip_send(outbuf + s->o_idx, s->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;
|
||||
}
|
||||
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||
// Check here maxupload by subtracting uip_len and close socekt if fails!
|
||||
if (max_upload - uip_len > 0) {
|
||||
stream_upload(0);
|
||||
write_char('.');
|
||||
} else {
|
||||
send_bad_request();
|
||||
goto do_send;
|
||||
}
|
||||
} else if (uip_newdata() && s->tstate != TSTATE_TX) {
|
||||
cont_len = 0;
|
||||
dbg_char('<'); dbg_short(uip_len); dbg_char('\n');
|
||||
write_char('<'); print_short(uip_len); write_char('\n');
|
||||
__xdata uint8_t *p = uip_appdata;
|
||||
// Mark end of request header with \0
|
||||
p[uip_len] = 0;
|
||||
#ifdef DEBUG
|
||||
while (*p)
|
||||
dbg_char(*p++);
|
||||
dbg_char('\n');
|
||||
#endif
|
||||
write_char(*p++);
|
||||
write_char('\n');
|
||||
p = uip_appdata;
|
||||
if (is_word(p, "POST")) {
|
||||
handle_post();
|
||||
// If this is an ongoing post stream, then wait for the next packet
|
||||
if (s->tstate == TSTATE_POST) {
|
||||
uip_len = 0;
|
||||
return;
|
||||
}
|
||||
goto do_send;
|
||||
}
|
||||
|
||||
if (is_word(p, "GET"))
|
||||
dbg_string("GET request ");
|
||||
if (p[0] == 'G' && p[1] == 'E' && p[2] == 'T' && p[3] == ' ')
|
||||
print_string("GET request ");
|
||||
p += 4;
|
||||
scan_header(p);
|
||||
__xdata uint8_t *q = p;
|
||||
while (!is_separator(*p))
|
||||
while (!is_space(*p))
|
||||
p++;
|
||||
*p = '\0';
|
||||
dbg_string_x(q);
|
||||
dbg_char('\n');
|
||||
print_string_x(q);
|
||||
write_char('\n');
|
||||
|
||||
s->tstate = TSTATE_NONE;
|
||||
entry = find_entry(q);
|
||||
dbg_string("Entry is: "); dbg_byte(entry); dbg_char('\n');
|
||||
print_string("Entry is: "); print_byte(entry); write_char('\n');
|
||||
if (entry == 0xff) {
|
||||
if (!authenticated) {
|
||||
dbg_string("Not authorized!\n");
|
||||
send_unauthorized();
|
||||
goto do_send;
|
||||
}
|
||||
dbg_string("Not file entry\n");
|
||||
if (!strcmp(q, "/status.json")) {
|
||||
send_status();
|
||||
} else if (!strcmp(q, "/information.json")) {
|
||||
send_basic_info();
|
||||
} else if (!strcmp(q, "/vlan.json")) {
|
||||
parse_short(q + 15);
|
||||
send_vlan(short_parsed);
|
||||
} else if (is_word(q, "/counters.json")) {
|
||||
send_counters(q[20]-'0');
|
||||
} else if (is_word(q, "/eee.json")) {
|
||||
send_eee();
|
||||
} 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")) {
|
||||
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 {
|
||||
send_not_found();
|
||||
}
|
||||
print_string("Not found\n");
|
||||
s->slen = strtox(outbuf, "HTTP/1.1 404 Not found\r\nContent-Type: text/html\r\n\r\n");
|
||||
print_string("slen: "); print_short(s->slen); write_char('\n');
|
||||
s->slen += strtox(outbuf + s->slen, "<!DOCTYPE HTML PUBLIC>\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n");
|
||||
} else {
|
||||
dbg_string("Have entry, authenticated: "); dbg_byte(authenticated); dbg_char('\n');
|
||||
if (!authenticated && !(f_data[entry].start == FDATA_START_login_html
|
||||
|| f_data[entry].start == FDATA_START_port_svg
|
||||
|| f_data[entry].start == FDATA_START_sfp_svg
|
||||
|| f_data[entry].start == FDATA_START_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 + slen, mime_strings[f_data[entry].mime]);
|
||||
slen += strtox(outbuf + slen, "; charset=UTF-8\r\nCache-Control: max-age=60, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\n\r\n");
|
||||
|
||||
print_string("Have entry\n");
|
||||
s->slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: ");
|
||||
s->slen += strtox(outbuf + s->slen, f_data[entry].mime);
|
||||
s->slen += strtox(outbuf + s->slen, "\r\n\r\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;
|
||||
if (f_data[entry].mime[0] == 't' && f_data[entry].mime[5] == 'h') {
|
||||
print_string("MIME is html len is "); print_short(len_left); write_char('\n');
|
||||
mpos = 0;
|
||||
flash_find_mark(f_data[entry].start, len_left, "#{");
|
||||
print_string("mpos: "); print_short(mpos); write_char('\n');
|
||||
while (mpos != 0xffff) {
|
||||
print_string("Entry-len:"); print_short(len_left); write_char('\n');
|
||||
mpos = len_left - mpos;
|
||||
print_string("l/pos: "); print_short(mpos); write_char('\n');
|
||||
flash_read_bulk(outbuf + s->slen, f_data[entry].start + f_data[entry].len - len_left, mpos + CMARK_S); // call marker is e.g. #{001}
|
||||
s->slen += mpos;
|
||||
write_char('@'); write_char(outbuf[s->slen + 2]); write_char(outbuf[s->slen + 3]); write_char(outbuf[s->slen + 4]);
|
||||
fcall_ptr ptr = f_calls[(outbuf[s->slen + 2] - '0') * 100 + (outbuf[s->slen + 3]-'0') * 10 + outbuf[s->slen + 4] - '0'];
|
||||
s->slen -= CMARK_S; // Overwrite marker with generated html
|
||||
print_string("Call location is: "); print_short((uint16_t)ptr); write_char('\n');
|
||||
// f_calls[outbuf[s->slen + 2] * 100 + outbuf[s->slen + 3] * 10 + outbuf[s->slen + 4]]();
|
||||
ptr(outbuf);
|
||||
print_string("call done\n");
|
||||
mpos += CMARK_S;
|
||||
len_left -= mpos;
|
||||
flash_find_mark(f_data[entry].start + mpos, len_left, "#{");
|
||||
}
|
||||
print_string("At end mpos: "); print_short(mpos); write_char('\n');
|
||||
flash_read_bulk(outbuf + s->slen, f_data[entry].start + f_data[entry].len - len_left, len_left);
|
||||
s->slen += len_left;
|
||||
} else {
|
||||
print_string("MIME: "); print_string(f_data[entry].mime); write_char('\n');
|
||||
flash_read_bulk(outbuf + s->slen, f_data[entry].start, len_left);
|
||||
s->slen += 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.len = len_left;
|
||||
flash_read_bulk(outbuf + slen);
|
||||
slen += len_left;
|
||||
}
|
||||
do_send:
|
||||
dbg_string("slen: "); dbg_short(slen); dbg_char('\n');
|
||||
o_idx = 0;
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
dbg_string("Sending a done\n");
|
||||
print_string("slen: "); print_short(s->slen); write_char('\n');
|
||||
s->o_idx = 0;
|
||||
if (s->slen > uip_mss()) {
|
||||
print_string("Sending a: "); print_short(s->slen); write_char('\n');
|
||||
uip_send(outbuf + s->o_idx, uip_mss());
|
||||
print_string("Sending a done\n");
|
||||
} else {
|
||||
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
dbg_string("Sending b done\n");
|
||||
print_string("Sending b: "); print_short(s->slen); write_char('\n');
|
||||
uip_send(outbuf + s->o_idx, s->slen);
|
||||
print_string("Sending b done\n");
|
||||
}
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
||||
dbg_string("RETRANSMIT requested\n");
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
dbg_string("Sending C done\n");
|
||||
} else if (slen > 0) {
|
||||
dbg_string("Sending D: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
dbg_string("Sending D done\n");
|
||||
print_string("RETRANSMIT requested\n");
|
||||
if (s->slen > uip_mss()) {
|
||||
print_string("Sending C: "); print_short(s->slen); write_char('\n');
|
||||
uip_send(outbuf + s->o_idx, uip_mss());
|
||||
print_string("Sending C done\n");
|
||||
} else if (s->slen > 0) {
|
||||
print_string("Sending D: "); print_short(s->slen); write_char('\n');
|
||||
uip_send(outbuf + s->o_idx, s->slen);
|
||||
print_string("Sending D done\n");
|
||||
}
|
||||
s->tstate = TSTATE_TX;
|
||||
uip_len = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef __HTTPD_H__
|
||||
#define __HTTPD_H__
|
||||
#ifndef __HELLO_WORLD_H__
|
||||
#define __HELLO_WORLD_H__
|
||||
|
||||
/* Since this file will be included by uip.h, we cannot include uip.h
|
||||
here. But we might need to include uipopt.h if we need the u8_t and
|
||||
@@ -12,6 +12,9 @@
|
||||
for each TCP connection. */
|
||||
typedef struct httpd_state {
|
||||
uint8_t tstate;
|
||||
uint8_t outbuf[2048];
|
||||
uint16_t slen;
|
||||
uint16_t o_idx;
|
||||
} uip_tcp_appstate_t;
|
||||
|
||||
/* Finally we define the application function to be called by uIP. */
|
||||
|
||||
@@ -1,705 +1,78 @@
|
||||
// #define REGDBG 1
|
||||
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "rtl837x_pins.h"
|
||||
#include "../rtl837x_common.h"
|
||||
#include "uip.h"
|
||||
#include "html_data.h"
|
||||
#include <stdint.h>
|
||||
#include "phy.h"
|
||||
#include "version.h"
|
||||
#include "machine.h"
|
||||
#include "page_impl.h"
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#define L2_MAX_TRANSFER 30
|
||||
#include "../html_data.h"
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
extern __xdata uint16_t slen;
|
||||
extern __xdata uint16_t cont_len;
|
||||
extern __xdata uint32_t cont_addr;
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||
extern __code struct uip_eth_addr uip_ethaddr;
|
||||
extern __code uint8_t ownMAC[];
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
#define PUTC(c) *outbuf++ = c;
|
||||
|
||||
extern __xdata uint8_t cmd_history[CMD_HISTORY_SIZE];
|
||||
extern __xdata uint16_t cmd_history_ptr;
|
||||
#define PUTBYTE(a) { *outbuf++ = hex[(a >> 4) & 0xf]; *outbuf++ = hex[a & 0xf]; }
|
||||
|
||||
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_TXT = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
|
||||
|
||||
// Convert uint8_t to ascii HEX char push on html-buffer.
|
||||
void charhex_to_html(char c)
|
||||
inline uint8_t itoa_html(uint8_t v, __xdata uint8_t *outbuf)
|
||||
{
|
||||
outbuf[slen++] = itohex(c);
|
||||
}
|
||||
|
||||
|
||||
// Convert (uint8_t) bool to ascii '0' or '1' char push on html-buffer.
|
||||
void bool_to_html(char c)
|
||||
{
|
||||
outbuf[slen++] = c ? '1' : '0';
|
||||
}
|
||||
|
||||
|
||||
void char_to_html(char c)
|
||||
{
|
||||
outbuf[slen++] = c;
|
||||
}
|
||||
|
||||
|
||||
// Convert uint8_t to ascii HEX char.
|
||||
void byte_to_html(uint8_t val)
|
||||
{
|
||||
uint8_t cnt = 2;
|
||||
do {
|
||||
val = (val >> 4) | (val << 4);
|
||||
charhex_to_html(val);
|
||||
cnt -= 1;
|
||||
} while(cnt);
|
||||
}
|
||||
|
||||
/* Converts a uint8_t to raw string.
|
||||
Suppress leading zeros.
|
||||
*/
|
||||
void itoa_html(uint8_t v)
|
||||
{
|
||||
uint8_t t = (v / 100);
|
||||
// when print_zeros is not zero, we know that a non-zero number has printed.
|
||||
// That have to print all the next numbers.
|
||||
uint8_t print_zeros = t;
|
||||
if (print_zeros)
|
||||
char_to_html('0' + t);
|
||||
uint8_t t = (v / 100) % 10;
|
||||
if (t)
|
||||
PUTC('0' + t);
|
||||
t = (v / 10) % 10;
|
||||
print_zeros |= t;
|
||||
if (print_zeros)
|
||||
char_to_html('0' + t);
|
||||
char_to_html('0' + (v % 10));
|
||||
if (t)
|
||||
PUTC('0' + t);
|
||||
PUTC('0' + (v % 10));
|
||||
|
||||
if (v >= 100)
|
||||
return 3;
|
||||
else if (v >= 10)
|
||||
return 2;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint16_t stat_content(void)
|
||||
uint16_t stat_content(__xdata uint8_t *outbuf)
|
||||
{
|
||||
dbg_string("stat_content called\n");
|
||||
print_string("stat_content called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint16_t port_status(void)
|
||||
uint16_t port_status(__xdata uint8_t *outbuf)
|
||||
{
|
||||
dbg_string("port_status called\n");
|
||||
print_string("port_status called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Converts sfr_data[] into raw hex string.
|
||||
Suppress leading zeros.
|
||||
*/
|
||||
void sfr_data_to_html(void)
|
||||
uint16_t html_index(__xdata uint8_t *outbuf)
|
||||
{
|
||||
uint8_t print_zeros = 0;
|
||||
uint8_t val = 0;
|
||||
__xdata uint8_t *oldptr = outbuf;
|
||||
|
||||
for (uint8_t nibble = 0; nibble < 8; nibble++) {
|
||||
if (!(nibble & 1))
|
||||
val = sfr_data[nibble>>1];
|
||||
// force the swap instruction, itohex() ignores the upper nibble.
|
||||
val = (val << 4) | (val >> 4);
|
||||
// when print_zeros is not zero, we know that a non-zero number has printed.
|
||||
// That have to print all the next numbers.
|
||||
print_zeros |= val;
|
||||
// only care about lower nibble, that is what is printed.
|
||||
print_zeros &= 0x0f;
|
||||
if (print_zeros)
|
||||
charhex_to_html(val);
|
||||
}
|
||||
if (print_zeros == 0) {
|
||||
char_to_html('0');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void reg_to_html(register uint16_t reg)
|
||||
{
|
||||
reg_read_m(reg);
|
||||
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)
|
||||
{
|
||||
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 & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
|
||||
} else {
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 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 & 0xf; i++) {
|
||||
if (!(i & 0x3))
|
||||
reg_read_m(RTL837X_REG_I2C_OUT + (i >> 2));
|
||||
if (len & 0x80)
|
||||
char_to_html(sfr_data[3 - (i & 0x3)]);
|
||||
else
|
||||
byte_to_html(sfr_data[3 - (i & 0x3)]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_basic_info(void)
|
||||
{
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("send_basic_info called\n");
|
||||
slen += strtox(outbuf + slen, "{\"ip_address\":\"");
|
||||
itoa_html(uip_hostaddr[0]); char_to_html('.');
|
||||
itoa_html(uip_hostaddr[0] >> 8); char_to_html('.');
|
||||
itoa_html(uip_hostaddr[1]); char_to_html('.');
|
||||
itoa_html(uip_hostaddr[1] >> 8);
|
||||
slen += strtox(outbuf + slen, "\",\"ip_gateway\":\"");
|
||||
itoa_html(uip_draddr[0]); char_to_html('.');
|
||||
itoa_html(uip_draddr[0] >> 8); char_to_html('.');
|
||||
itoa_html(uip_draddr[1]); char_to_html('.');
|
||||
itoa_html(uip_draddr[1] >> 8);
|
||||
slen += strtox(outbuf + slen, "\",\"ip_netmask\":\"");
|
||||
itoa_html(uip_netmask[0]); char_to_html('.');
|
||||
itoa_html(uip_netmask[0] >> 8); char_to_html('.');
|
||||
itoa_html(uip_netmask[1]); char_to_html('.');
|
||||
itoa_html(uip_netmask[1] >> 8);
|
||||
slen += strtox(outbuf + slen, "\",\"mac_address\":\"");
|
||||
byte_to_html(uip_ethaddr.addr[0]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[1]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[2]); char_to_html(':');
|
||||
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[5]);
|
||||
slen += strtox(outbuf + slen, "\",\"sw_ver\":\"");
|
||||
slen += strtox(outbuf + slen, VERSION_SW);
|
||||
slen += strtox(outbuf + slen, "\",\"hw_ver\":\"");
|
||||
slen += strtox(outbuf + slen, machine.machine_name);
|
||||
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)
|
||||
{
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("sending VLAN\n");
|
||||
//{"members":"0x00060011"}
|
||||
slen += strtox(outbuf + slen, "{\"members\":\"0x");
|
||||
vlan_get(vlan);
|
||||
sfr_data_to_html();
|
||||
slen += strtox(outbuf + slen, "\",\"name\":\"");
|
||||
__xdata uint16_t n = vlan_name(vlan);
|
||||
if (n== 0xffff) {
|
||||
dbg_string("VLAN has no name\n");
|
||||
} else {
|
||||
while(vlan_names[n] && vlan_names[n] != ' ')
|
||||
char_to_html(vlan_names[n++]);
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\"}");
|
||||
}
|
||||
|
||||
|
||||
void send_counters(char port)
|
||||
{
|
||||
dbg_string("send_counters called: "); dbg_byte(port); dbg_char('\n');
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("sending counters\n");
|
||||
dbg_byte(port);
|
||||
uint8_t i = machine.phys_to_log_port[port];
|
||||
slen += strtox(outbuf + slen, "[");
|
||||
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
||||
STAT_GET(counter, i);
|
||||
slen += strtox(outbuf + slen, "\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||
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('}');
|
||||
}
|
||||
|
||||
|
||||
void send_mirror(void)
|
||||
{
|
||||
dbg_string("send_mirror called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
|
||||
reg_read_m(RTL837x_MIRROR_CTRL);
|
||||
uint8_t mPort = sfr_data[3];
|
||||
if (mPort & 1) {
|
||||
slen += strtox(outbuf + slen, "{\"enabled\":1,\"mPort\":");
|
||||
} else {
|
||||
slen += strtox(outbuf + slen, "{\"enabled\":0,\"mPort\":");
|
||||
}
|
||||
itoa_html(machine.log_to_phys_port[mPort >> 1]);
|
||||
|
||||
reg_read_m(RTL837x_MIRROR_CONF);
|
||||
uint16_t m = sfr_data[0];
|
||||
m = (m << 8) | sfr_data[1];
|
||||
slen += strtox(outbuf + slen, ",\"mirror_rx\":\"");
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bool_to_html(!!(m & 0x8000));
|
||||
m <<= 1;
|
||||
}
|
||||
m = sfr_data[2];
|
||||
m = (m << 8) | sfr_data[3];
|
||||
slen += strtox(outbuf + slen, "\",\"mirror_tx\":\"");
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
bool_to_html(!!(m & 0x8000));
|
||||
m <<= 1;
|
||||
}
|
||||
char_to_html('\"');
|
||||
char_to_html('}');
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
dbg_string("send_eee called\nsending EEE status\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
|
||||
reg_read_m(RTL8373_PHY_EEE_ABLTY);
|
||||
uint8_t eee_ablty = sfr_data[3];
|
||||
|
||||
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]);
|
||||
|
||||
if (machine.is_sfp[i]) {
|
||||
slen += strtox(outbuf + slen, ",\"isSFP\":1");
|
||||
} else {
|
||||
slen += strtox(outbuf + slen, ",\"isSFP\":0,\"eee\":\"");
|
||||
uint16_t v;
|
||||
phy_read(i, PHY_MMD_AN, PHY_EEE_ADV2);
|
||||
v = SFR_DATA_U16;
|
||||
bool_to_html(v & PHY_EEE_BIT_2G5);
|
||||
|
||||
phy_read(i, PHY_MMD_AN, PHY_EEE_ADV);
|
||||
v = SFR_DATA_U16;
|
||||
bool_to_html(v & PHY_EEE_BIT_1G);
|
||||
bool_to_html(v & PHY_EEE_BIT_100M);
|
||||
|
||||
phy_read(i, PHY_MMD_AN, PHY_EEE_LP_ABILITY2);
|
||||
v = SFR_DATA_U16;
|
||||
slen += strtox(outbuf + slen, "\",\"eee_lp\":\"");
|
||||
bool_to_html (v & PHY_EEE_BIT_2G5);
|
||||
|
||||
phy_read(i, PHY_MMD_AN, PHY_EEE_LP_ABILITY);
|
||||
v = SFR_DATA_U16;
|
||||
bool_to_html(v & PHY_EEE_BIT_1G);
|
||||
bool_to_html(v & PHY_EEE_BIT_100M);
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"active\":");
|
||||
bool_to_html(eee_ablty & (1 << i));
|
||||
}
|
||||
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(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_status(void)
|
||||
{
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("sending status\n");
|
||||
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, ",\"logPort\":");
|
||||
itoa_html(i);
|
||||
|
||||
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) {
|
||||
sfp_send_data(machine.is_sfp[i] - 1, 92, 1);
|
||||
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);
|
||||
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];
|
||||
char_to_html('"');
|
||||
} 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\":");
|
||||
|
||||
if (i < 8)
|
||||
reg_read_m(RTL837X_REG_LINKS);
|
||||
else
|
||||
reg_read_m(RTL837X_REG_LINKS_89);
|
||||
uint8_t b = sfr_data[3 - ((i & 7) >> 1)];
|
||||
b = (i & 1) ? b >> 4 : b & 0xf;
|
||||
char_to_html('0' + b);
|
||||
|
||||
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
||||
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"txB\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
reg_to_html(RTL837X_STAT_V_LOW); // 32 bit Tx Packet errors
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"rxG\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_RX_PKTS, i);
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
reg_to_html(RTL837X_STAT_V_HIGH); // 32bit RX packet errors
|
||||
slen += strtox(outbuf + slen, "\"}");
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_config(void)
|
||||
{
|
||||
dbg_string("send_config called\n");
|
||||
__xdata uint32_t pos = CONFIG_START; // 70000 , 6c000 / 0xc000 = 9
|
||||
|
||||
extern __xdata uint16_t len_left = CONFIG_LEN;
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_TXT);
|
||||
while (read_flash((CONFIG_START-CODE0_SIZE) / CODE_BANK_SIZE + 1,
|
||||
(__code uint8_t *) (((CONFIG_START + len_left - CODE0_SIZE) % CODE_BANK_SIZE) + CODE0_SIZE + len_left)) == 0xff) {
|
||||
dbg_short(len_left);
|
||||
len_left--;
|
||||
}
|
||||
len_left++;
|
||||
|
||||
if (len_left > (TCP_OUTBUF_SIZE - slen)) {
|
||||
cont_len = len_left - (TCP_OUTBUF_SIZE - slen);
|
||||
len_left = TCP_OUTBUF_SIZE - slen;
|
||||
cont_addr = len_left;
|
||||
}
|
||||
flash_region.addr = CONFIG_START;
|
||||
flash_region.len = len_left;
|
||||
flash_read_bulk(outbuf + slen);
|
||||
slen += len_left;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
print_string("html_index called\n");
|
||||
outbuf += strtox(outbuf, "<tr><td>IP Address</td><td>");
|
||||
outbuf += itoa_html(uip_hostaddr[0], outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_hostaddr[0] >> 8, outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_hostaddr[1], outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_hostaddr[1] >> 8, outbuf);
|
||||
outbuf += strtox(outbuf, "</td></tr><tr><td>Gateway</td><td>");
|
||||
outbuf += itoa_html(uip_draddr[0], outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_draddr[0] >> 8, outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_draddr[1], outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_draddr[1] >> 8, outbuf);
|
||||
outbuf += strtox(outbuf, "</td></tr><tr><td>Netmask</td><td>");
|
||||
outbuf += itoa_html(uip_netmask[0], outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_netmask[0] >> 8, outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_netmask[1], outbuf); PUTC('.');
|
||||
outbuf += itoa_html(uip_netmask[1] >> 8, outbuf);
|
||||
outbuf += strtox(outbuf, "</td></tr><tr><td>MAC Address</td><td>");
|
||||
PUTBYTE(ownMAC[0]); PUTC(':');
|
||||
PUTBYTE(ownMAC[1]); PUTC(':');
|
||||
PUTBYTE(ownMAC[2]); PUTC(':');
|
||||
PUTBYTE(ownMAC[3]); PUTC(':');
|
||||
PUTBYTE(ownMAC[4]); PUTC(':');
|
||||
PUTBYTE(ownMAC[5]);
|
||||
outbuf += strtox(outbuf, "</td></tr>");
|
||||
|
||||
return outbuf - oldptr;
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef __PAGE_IMPL_H__
|
||||
#define __PAGE_IMPL_H__
|
||||
|
||||
void send_counters(char port);
|
||||
void send_status(void);
|
||||
void send_vlan(uint16_t vlan);
|
||||
void send_basic_info(void);
|
||||
void send_eee(void);
|
||||
void send_l2(uint16_t idx);
|
||||
void l2_delete(uint16_t idx);
|
||||
void send_mirror(void);
|
||||
void send_mtu(void);
|
||||
void send_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
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
CODE_LOCATION=0x1000
|
||||
INSTALLER_ADDRESS=0x1100
|
||||
|
||||
CC = sdcc
|
||||
CC_FLAGS = -mmcs51
|
||||
ASM = sdas8051
|
||||
AFLAGS= -plosgff
|
||||
|
||||
BUILDDIR = output/
|
||||
|
||||
SRCS = installer.c
|
||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
||||
|
||||
all: create_build_dir $(BUILDDIR)updatebuilder $(BUILDDIR)rtlplayground.bin
|
||||
|
||||
create_build_dir:
|
||||
mkdir -p $(BUILDDIR)
|
||||
|
||||
$(BUILDDIR)updatebuilder: updatebuilder.c
|
||||
gcc $^ -o $@
|
||||
|
||||
$(BUILDDIR)installer.rel: installer.c
|
||||
$(CC) $(CC_FLAGS) --code-loc ${CODE_LOCATION} -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)crtstart.rel: crtstart.asm
|
||||
$(ASM) $(AFLAGS) -o $@ $<
|
||||
|
||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
||||
${ASM} ${AFLAGS} -o $@ $^
|
||||
|
||||
$(BUILDDIR)%.rel: %.c
|
||||
$(CC) $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)rtlinstaller.ihx: $(BUILDDIR)crtstart.rel $(OBJS)
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=${INSTALLER_ADDRESS} -Wl-r -o $@ $^
|
||||
|
||||
$(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlinstaller.ihx ../$(BUILDDIR)/rtlplayground.bin
|
||||
cp ../$(BUILDDIR)/rtlplayground.bin $(BUILDDIR)
|
||||
./$(BUILDDIR)/updatebuilder -i $< $(BUILDDIR)rtlplayground.bin
|
||||
|
||||
clean:
|
||||
rm -r $(BUILDDIR)
|
||||
@@ -1,26 +0,0 @@
|
||||
.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 + 0x1000
|
||||
ljmp _isr_ext0 ; 0x03
|
||||
.ds 5
|
||||
ljmp _isr_timer0 ; 0x0b
|
||||
.ds 5
|
||||
ljmp _isr_ext1 ; 0x13
|
||||
.globl __start__stack
|
||||
|
||||
.area GSINIT0 (CODE)
|
||||
|
||||
__sdcc_gsinit_startup:
|
||||
mov sp,#__start__stack - 1
|
||||
|
||||
.area GSFINAL (CODE)
|
||||
ljmp _installer
|
||||
@@ -1,385 +0,0 @@
|
||||
#include <8051.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// #define REGDBG 1
|
||||
// #define RXTXDBG 1
|
||||
|
||||
#define UPDATE_LOC 0x0001D000
|
||||
#define HEADER_LENGTH 0x14
|
||||
#define UPDATE_CODE_LOC (UPDATE_LOC + HEADER_LENGTH)
|
||||
|
||||
#include "../rtl837x_sfr.h"
|
||||
#include "../rtl837x_regs.h"
|
||||
|
||||
// See setup_serial_timer1() for valid baudrate settings!
|
||||
#define SERIAL_BAUD_RATE 57600
|
||||
#define CLOCK_HZ 125000000
|
||||
|
||||
// Derive the divider settings for the internal clock
|
||||
#if CLOCK_HZ == 20800000
|
||||
#define CLOCK_DIV 3
|
||||
#elif CLOCK_HZ == 31250000
|
||||
#define CLOCK_DIV 2
|
||||
#elif CLOCK_HZ == 62500000
|
||||
#define CLOCK_DIV 1
|
||||
#elif CLOCK_HZ == 125000000
|
||||
#define CLOCK_DIV 0
|
||||
#endif
|
||||
|
||||
// We buffer 1 sector as this is also the erase size
|
||||
__xdata uint8_t buffer[0x1000];
|
||||
__xdata uint8_t dio_enabled;
|
||||
|
||||
__code uint8_t * __code hex = "0123456789abcdef";
|
||||
|
||||
void isr_timer0(void) __interrupt(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void isr_ext0(void) __interrupt(0)
|
||||
{
|
||||
EX0 = 0; // Disable interrupt for the moment
|
||||
IT0 = 1; // Trigger on falling edge of external interrupt
|
||||
EX0 = 1; // Re-enable interrupt
|
||||
}
|
||||
|
||||
|
||||
void isr_ext1(void) __interrupt(2)
|
||||
{
|
||||
EX1 = 0;
|
||||
EX1 = 1;
|
||||
}
|
||||
|
||||
|
||||
void write_char(char c)
|
||||
{
|
||||
do {
|
||||
} while (TI == 0);
|
||||
TI = 0;
|
||||
if (c =='\n') {
|
||||
SBUF = '\r';
|
||||
do {
|
||||
} while (TI == 0);
|
||||
TI = 0;
|
||||
}
|
||||
SBUF = c;
|
||||
}
|
||||
|
||||
|
||||
void print_string(__code char *p)
|
||||
{
|
||||
while (*p)
|
||||
write_char(*p++);
|
||||
}
|
||||
|
||||
|
||||
void print_byte(uint8_t a)
|
||||
{
|
||||
write_char(hex[(a >> 4) & 0xf]);
|
||||
write_char(hex[a & 0xf]);
|
||||
}
|
||||
|
||||
void print_short(uint16_t a)
|
||||
{
|
||||
print_string("0x");
|
||||
for (signed char i = 12; i >= 0; i -= 4) {
|
||||
write_char(hex[(a >> i) & 0xf]);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
// 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
|
||||
|
||||
PCON |= 0x80; // SMOD0 = 1; Double the Baud Rate, don't divide Timer 1 Overflag signal.
|
||||
|
||||
SCON = 0x50; // Mode = 1: ASYNC 8N1 with Timer 2 as baud-rate generator, REN_0 Receive enable
|
||||
|
||||
/* 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;
|
||||
|
||||
TCON |= 0x40; // Start timer 1
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure Memory Managed IO
|
||||
*/
|
||||
void flash_configure_mmio(void)
|
||||
{
|
||||
// Set configuration for MMIO access by controller
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = 0xbb; // By default we read with Dual speed
|
||||
SFR_FLASH_DUMMYCYCLES = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = 0xb; // By default we read with single speed
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initializes the flash controller for programmed control
|
||||
* The configuration options are not really understood, the SPI speed
|
||||
* seems to be directly linked to the CPU frequency
|
||||
* This configures fast single IO at 20.8 MHz when the CPU clock is at 20.8MHz
|
||||
* and 62.5MHz when the CPU clock is configured at 125MHz
|
||||
*/
|
||||
void flash_init(uint8_t enable_dio)
|
||||
{
|
||||
if (enable_dio) {
|
||||
// Configure fast DIO via divider/DIO/SIOconfig = 4 and read-cmd being 0xbb (for mmio)
|
||||
SFR_FLASH_CONFIG = 9; // There may be a chip-select in here
|
||||
SFR_FLASH_CONF_RCMD = 0xbb;
|
||||
SFR_FLASH_CONF_DIV = 4;
|
||||
} else {
|
||||
// Configure fast read via divider = 8 and read-cmd being 0xb (for mmio)
|
||||
SFR_FLASH_CONFIG = 9;
|
||||
SFR_FLASH_CONF_RCMD = 0xb;
|
||||
SFR_FLASH_CONF_DIV = 8;
|
||||
}
|
||||
// Test Controller Busy
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// Write 0 to status register
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
SFR_FLASH_MODEB = 0;
|
||||
SFR_FLASH_TCONF = 0x19;
|
||||
SFR_FLASH_CMD = 1;
|
||||
SFR_FLASH_DATA0 = 0;
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
dio_enabled = enable_dio;
|
||||
flash_configure_mmio();
|
||||
}
|
||||
|
||||
|
||||
uint8_t flash_read_status(void)
|
||||
{
|
||||
// Test Controller Busy (we might call this directly after executing a command)
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// setup status read command
|
||||
SFR_FLASH_TCONF = 0x11;
|
||||
SFR_FLASH_CMD_R = 5;
|
||||
|
||||
// execute and wait for controller done
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
return SFR_FLASH_DATA0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reads bulk data of length len from the flash memory starging at address src
|
||||
* and writes the data into a buffer pointed to by dst in XMEM
|
||||
*/
|
||||
void flash_read_bulk(register __xdata uint8_t *dst, __xdata uint32_t src, register uint16_t len)
|
||||
{
|
||||
short status;
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (status & 0x1);
|
||||
|
||||
// Set fast read mode
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = 0xbb;
|
||||
SFR_FLASH_DUMMYCYCLES = 4;
|
||||
} else {
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = 0xb; // Fast read
|
||||
SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks after read?
|
||||
}
|
||||
// Read 4 bytes
|
||||
SFR_FLASH_TCONF = 4;
|
||||
while (len) {
|
||||
SFR_FLASH_ADDR16 = src >> 16;
|
||||
SFR_FLASH_ADDR8 = src >> 8;
|
||||
SFR_FLASH_ADDR0 = src;
|
||||
src += 4;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
*dst++ = SFR_FLASH_DATA0;
|
||||
if (len == 1)
|
||||
return;
|
||||
*dst++ = SFR_FLASH_DATA8;
|
||||
if (len == 2)
|
||||
return;
|
||||
*dst++ = SFR_FLASH_DATA16;
|
||||
if (len == 3)
|
||||
return;
|
||||
*dst++ = SFR_FLASH_DATA24;
|
||||
|
||||
len -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void flash_write_enable(void)
|
||||
{
|
||||
short status;
|
||||
|
||||
// Wait until busy bit clear
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (status & 0x1);
|
||||
// while (flash_read_status() & 0x1);
|
||||
|
||||
SFR_FLASH_TCONF = 0x18;
|
||||
SFR_FLASH_CMD = 6;
|
||||
SFR_FLASH_DUMMYCYCLES = 0;
|
||||
SFR_FLASH_MODEB = 0;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
// Wait for write status enabled
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (!(status & 0x2));
|
||||
}
|
||||
|
||||
|
||||
// Erases the 4k sector in which the address lies
|
||||
void flash_sector_erase(uint32_t addr)
|
||||
{
|
||||
flash_write_enable();
|
||||
SFR_FLASH_TCONF = 8;
|
||||
SFR_FLASH_CMD = 0x20;
|
||||
|
||||
SFR_FLASH_ADDR16 = addr >> 16;
|
||||
SFR_FLASH_ADDR8 = addr >> 8;
|
||||
SFR_FLASH_ADDR0 = addr;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while (flash_read_status() & 0x1);
|
||||
|
||||
flash_configure_mmio();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void flash_write_bytes(__xdata uint32_t addr, __xdata uint8_t *ptr, uint16_t len)
|
||||
{
|
||||
uint8_t exit_loop = 0;
|
||||
|
||||
while(1) {
|
||||
flash_write_enable();
|
||||
SFR_FLASH_CMD = 2;
|
||||
SFR_FLASH_TCONF = 0x40 | 8 | 4; // Bytes written is 4, 8 enables write, 0x40 is unknown
|
||||
// Last transfer?
|
||||
if (len < 5) {
|
||||
SFR_FLASH_TCONF = 8 | len;
|
||||
exit_loop = 1;
|
||||
}
|
||||
|
||||
SFR_FLASH_ADDR16 = addr >> 16;
|
||||
SFR_FLASH_ADDR8 = addr >> 8;
|
||||
SFR_FLASH_ADDR0 = addr;
|
||||
SFR_FLASH_DATA0 = *ptr++;
|
||||
SFR_FLASH_DATA8 = *ptr++;
|
||||
SFR_FLASH_DATA16 = *ptr++;
|
||||
SFR_FLASH_DATA24 = *ptr++;
|
||||
|
||||
// Execute transfer, we wait for completion at top of loop
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
if (exit_loop)
|
||||
break;
|
||||
len -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
while (flash_read_status() & 0x1);
|
||||
flash_configure_mmio();
|
||||
}
|
||||
|
||||
|
||||
void reg_write(uint16_t reg_addr)
|
||||
{
|
||||
/* Data to write must be in SFR A4, A5, A6, A7 */
|
||||
SFR_REG_ADDR_U16 = reg_addr;
|
||||
SFR_EXEC_GO = SFR_EXEC_WRITE_REG;
|
||||
do {
|
||||
} while (SFR_EXEC_STATUS != 0);
|
||||
}
|
||||
|
||||
|
||||
void installer(void)
|
||||
{
|
||||
|
||||
CKCON = 0; // Initial Clock configuration
|
||||
SFR_97 = 0; // HADDR?
|
||||
|
||||
// Set in managed mode:
|
||||
SFR_b9 = 0x00;
|
||||
SFR_ba = 0x80;
|
||||
|
||||
// Disable all interrupts (global and individually) by setting IE register (SFR A8) to 0
|
||||
IE = 0;
|
||||
EIE = 0; // SFR e8: EIE. Disable all external IRQs
|
||||
|
||||
setup_serial_timer1();
|
||||
print_string("\nRTLPlayground installer starting...\n");
|
||||
|
||||
// Initialize flash functions with disable DIO because writing does not work otherwise
|
||||
flash_init(0);
|
||||
|
||||
__xdata uint32_t dest = 0x0;
|
||||
__xdata uint32_t source = UPDATE_CODE_LOC;
|
||||
// A 512kByte = 4MBit Flash has 128 sectors, we copy only 120
|
||||
for (uint8_t i=0; i < 120; i++) {
|
||||
print_string("Moving block\n");
|
||||
flash_read_bulk(buffer, source, 0x1000);
|
||||
for (uint8_t j = 0; j < 32; j++) {
|
||||
write_char(' '); print_byte(buffer[j]);
|
||||
}
|
||||
write_char('\n');
|
||||
flash_sector_erase(dest);
|
||||
flash_write_bytes(dest, buffer, 0x1000);
|
||||
dest += 0x1000;
|
||||
source += 0x1000;
|
||||
}
|
||||
print_string("Done.\n");
|
||||
print_string("Reseting now\n");
|
||||
REG_SET(RTL837X_REG_RESET, 1);
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* Adds data files into specified locations of an image, optionally creates
|
||||
* an index in the form of a header file
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <argp.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define HEADER_LENGTH 0x14
|
||||
#define HEADER_MAGIC 0x12345678
|
||||
#define HEADER_RESERVED 0x332255ff
|
||||
|
||||
#define SEG_01002_LENGTH 0x2ffe
|
||||
#define SEG_1C000_LENGTH 0x1000
|
||||
#define SEG_1d000_OFFSET 0x3ffe
|
||||
|
||||
|
||||
// Use a 4MB buffer, the maximum flash rom size
|
||||
#define BUFFER_SIZE 0x400000
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
FILE *inptr;
|
||||
int outptr;
|
||||
char line[256];
|
||||
|
||||
const char *argp_program_version = "updatebuilder 0.1";
|
||||
const char *argp_program_bug_address = "<git@logicog.de>";
|
||||
static char doc[] = "Create an update image for RTL837X-based switches";
|
||||
static char args_doc[] = "INPUT_IMAGE";
|
||||
static struct argp_option options[] = {
|
||||
{ "magic", 'm', "MAGIC", 0, "Magic number"},
|
||||
{ "reserved", 'r', "MAGIC", 0, "Reserved number"},
|
||||
{ "installer", 'i', "FILE", 0, "Installer file"},
|
||||
{ "output", 'o', "FILE", 0, "Output file"},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
struct arguments {
|
||||
uint32_t reserved;
|
||||
uint32_t magic;
|
||||
char *installer_file;
|
||||
char *output_file;
|
||||
};
|
||||
|
||||
|
||||
int get_byte(int pos)
|
||||
{
|
||||
int c1 = line[pos];
|
||||
if (c1 >= '0' && c1 <= '9')
|
||||
c1 -= '0';
|
||||
else if (c1 >= 'a' && c1 <= 'f')
|
||||
c1 = c1 - 'a' + 10;
|
||||
else if (c1 >= 'A' && c1 <= 'F')
|
||||
c1 = c1 - 'A' + 10;
|
||||
else
|
||||
return -1;
|
||||
|
||||
int c2 = line[pos + 1];
|
||||
if (c2 >= '0' && c2 <= '9')
|
||||
c2 -= '0';
|
||||
else if (c2 >= 'a' && c2 <= 'f')
|
||||
c2 = c2 - 'a' + 10;
|
||||
else if (c2 >= 'A' && c2 <= 'F')
|
||||
c2 = c2 - 'A' + 10;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return c1 << 4 | c2;
|
||||
}
|
||||
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct arguments *arguments = state->input;
|
||||
switch (key) {
|
||||
case 'm':
|
||||
arguments->magic = arg? strtol(arg, NULL, 16): HEADER_MAGIC;
|
||||
break;
|
||||
case 'r':
|
||||
arguments->reserved = arg? strtol(arg, NULL, 16): HEADER_RESERVED;
|
||||
break;
|
||||
case 'i':
|
||||
arguments->installer_file = arg;
|
||||
break;
|
||||
case 'o':
|
||||
arguments->output_file = arg;
|
||||
break;
|
||||
case ARGP_KEY_END:
|
||||
if(state->arg_num < 1) // Expect 1 command line argument at end
|
||||
argp_usage(state);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct argp argp = {
|
||||
options, parse_opt, args_doc, doc, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct arguments arguments;
|
||||
int arg_index;
|
||||
char tmpfilename[] = "image_XXXXXX";
|
||||
|
||||
arguments.reserved = HEADER_RESERVED;
|
||||
arguments.magic = HEADER_MAGIC;
|
||||
arguments.output_file = NULL;
|
||||
|
||||
argp_parse(&argp, argc, argv, 0, &arg_index, &arguments);
|
||||
|
||||
memset(buffer, 0, BUFFER_SIZE);
|
||||
|
||||
size_t filesize = 0;
|
||||
inptr = fopen(argv[arg_index], "rb");
|
||||
if (inptr == NULL) {
|
||||
printf("Cannot open input file %s\n", argv[arg_index]);
|
||||
return 5;
|
||||
}
|
||||
|
||||
fseek(inptr, 0L, SEEK_END);
|
||||
filesize = ftell(inptr);
|
||||
rewind(inptr);
|
||||
printf("Input file size: %ld\n", filesize);
|
||||
if (filesize > BUFFER_SIZE) {
|
||||
printf("File too large.\n");
|
||||
return 5;
|
||||
}
|
||||
size_t bytes_read = fread(buffer + SEG_1d000_OFFSET + 2 * HEADER_LENGTH, 1, sizeof(buffer), inptr);
|
||||
|
||||
printf("Bytes read: %ld\n", bytes_read);
|
||||
|
||||
if (bytes_read != filesize) {
|
||||
printf("Error reading input file.\n");
|
||||
return 5;
|
||||
}
|
||||
fclose(inptr);
|
||||
filesize += SEG_1d000_OFFSET + 2 * HEADER_LENGTH;
|
||||
|
||||
// Read the installer file, which is in Intel Hex format
|
||||
if (arguments.installer_file) {
|
||||
inptr = fopen(arguments.installer_file, "rb");
|
||||
if (inptr == NULL) {
|
||||
printf("Cannot open installer file %s\n", arguments.installer_file);
|
||||
return 5;
|
||||
}
|
||||
int line_num = 1;
|
||||
int address_high = 0;
|
||||
bool eof = false;
|
||||
while(fgets(line, 255, inptr)) {
|
||||
if (line[0] != ':') {
|
||||
printf("Unknwon installer file format for %s\n", arguments.installer_file);
|
||||
return 5;
|
||||
}
|
||||
int bytes = get_byte(1);
|
||||
if (bytes < 0 || bytes > 200) {
|
||||
printf("Error in %s, line %d, incorrect byte number\n", arguments.installer_file, line_num);
|
||||
return 5;
|
||||
}
|
||||
int address = (get_byte(3) *256) + get_byte(5);
|
||||
if (address < 0) {
|
||||
printf("Error in %s, line %d, not an address\n", arguments.installer_file, line_num);
|
||||
return 5;
|
||||
}
|
||||
int type = get_byte(7);
|
||||
if (type < 0 || type > 5) {
|
||||
printf("Error in %s, line %d incorrect type\n", arguments.installer_file, line_num);
|
||||
return 5;
|
||||
}
|
||||
if (type == 0) {
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
int data = get_byte(9 + 2 * i);
|
||||
if (data < 0) {
|
||||
printf("Error in %s, line %d, illegal data byte\n", arguments.installer_file, line_num);
|
||||
return 5;
|
||||
} else {
|
||||
address = address > 0x1000 ? address - 0x1000 : address;
|
||||
buffer[address + HEADER_LENGTH + i] = data;
|
||||
}
|
||||
}
|
||||
} else if (type == 1) {
|
||||
eof = true;
|
||||
printf("EOF\n");
|
||||
} else {
|
||||
printf("UNKNOWN type, line %d\n", line_num);
|
||||
}
|
||||
line_num++;
|
||||
}
|
||||
if (!eof)
|
||||
printf("Something was wrong: EOF not found\n");
|
||||
|
||||
fclose(inptr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fill in the header with the magic, file-length, header sum, payload sum
|
||||
* and the reserved bytes
|
||||
*/
|
||||
*(uint32_t *)(buffer + 0x00) = htonl(arguments.magic);
|
||||
*(uint32_t *)(buffer + 0x04) = htonl(filesize - HEADER_LENGTH);
|
||||
uint32_t sum = 0;
|
||||
// for (int i = HEADER_LENGTH; i < filesize; i++)
|
||||
// sum += buffer[i];
|
||||
|
||||
for (int i = HEADER_LENGTH; i < SEG_01002_LENGTH; i++)
|
||||
sum += buffer[i];
|
||||
printf("Payload sum 1 is: 0x%x\n", sum);
|
||||
|
||||
for (int i = HEADER_LENGTH + SEG_01002_LENGTH; i < SEG_01002_LENGTH + SEG_1C000_LENGTH + HEADER_LENGTH; i++)
|
||||
sum += buffer[i];
|
||||
printf("Payload sum 2 is: 0x%x\n", sum);
|
||||
|
||||
sum += 0xff * HEADER_LENGTH;
|
||||
printf("Payload sum with header is: 0x%x\n", sum);
|
||||
|
||||
for (int i = 2 * HEADER_LENGTH + SEG_01002_LENGTH + SEG_1C000_LENGTH; i < filesize; i++)
|
||||
sum += buffer[i];
|
||||
printf("Payload sum is: 0x%x\n", sum);
|
||||
*(uint32_t *)(buffer + 0x0c) = htonl(sum);
|
||||
|
||||
*(uint32_t *)(buffer + 0x10) = htonl(arguments.reserved);
|
||||
|
||||
sum = 0;
|
||||
for (int i = 0; i < HEADER_LENGTH; i++)
|
||||
sum += buffer[i];
|
||||
printf("Header checksum is: 0x%x\n", sum);
|
||||
*(uint32_t *)(buffer + 0x08) = htonl(sum);
|
||||
|
||||
// Second header is copy of initial one:
|
||||
*(uint32_t *)(buffer + 0x00 + HEADER_LENGTH + SEG_1d000_OFFSET) = *(uint32_t *)(buffer + 0x00);
|
||||
*(uint32_t *)(buffer + 0x04 + HEADER_LENGTH + SEG_1d000_OFFSET) = *(uint32_t *)(buffer + 0x04);
|
||||
*(uint32_t *)(buffer + 0x08 + HEADER_LENGTH + SEG_1d000_OFFSET) = *(uint32_t *)(buffer + 0x08);
|
||||
*(uint32_t *)(buffer + 0x0c + HEADER_LENGTH + SEG_1d000_OFFSET) = *(uint32_t *)(buffer + 0x0c);
|
||||
*(uint32_t *)(buffer + 0x10 + HEADER_LENGTH + SEG_1d000_OFFSET) = *(uint32_t *)(buffer + 0x10);
|
||||
|
||||
if (filesize) {
|
||||
if (arguments.output_file)
|
||||
outptr = creat(arguments.output_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
else
|
||||
outptr = mkstemp(tmpfilename);
|
||||
|
||||
if (!outptr) {
|
||||
printf("Cannot open %s\n", arguments.output_file ? arguments.output_file : tmpfilename);
|
||||
return 5;
|
||||
}
|
||||
size_t written = write(outptr, buffer, filesize);
|
||||
|
||||
if (written != filesize) {
|
||||
printf("Error writing output file.\n");
|
||||
return 5;
|
||||
}
|
||||
close(outptr);
|
||||
|
||||
if (!arguments.output_file)
|
||||
rename(tmpfilename, argv[arg_index]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
#include "machine.h"
|
||||
#include "rtl837x_pins.h"
|
||||
#include "rtl837x_leds.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, 2, 0, 0, 0, 0, 1},
|
||||
.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 },
|
||||
.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 = GPIO46_I2C_SCL0,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | 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 },
|
||||
},
|
||||
.led_mux_custom = 0,
|
||||
// LED0 LED1 LED2 LED3 LED4 LED5 LED6 LED7 LED8 LED9 LED10 LED11 LED12 LED13 LED14 LED15
|
||||
// L-SFP R-SFP | PORT 1
|
||||
// LED16 LED17 LED18 LED19 LED20 LED21 LED22 LED23 LED24 LED25 LED26 LED27
|
||||
// | PORT 2 | PORT 3 | PORT 4
|
||||
// .led_mux = { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x0f, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14,
|
||||
// 0x15, 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x23 },
|
||||
};
|
||||
#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_bus = { .sda = 4, .scl = 3 },
|
||||
.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 },
|
||||
},
|
||||
};
|
||||
#elif defined MACHINE_KP_9000_9XH_X_EU
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "keepLink KP-9000-6XH-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 | 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 },
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_SWGT024_V2_0
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "SWGT024 V2.0",
|
||||
.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 = GPIO36_PWM_OUT,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28 | 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 },
|
||||
},
|
||||
};
|
||||
|
||||
#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_bus ={ .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_bus = { .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 },
|
||||
},
|
||||
};
|
||||
#elif defined MACHINE_ZX_SWTGW215AS_HASIVO
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "ZX-SWTGW215AS HASIVO",
|
||||
.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 },
|
||||
.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 | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.led_sets = {
|
||||
/* The Ethernet ports have 1 amber LED (bi-color left) and 2 green LED (left/right)
|
||||
* The SFP port has 1 green LED
|
||||
* Ethernet ports use LED-set 0, SFP port uses LED-set 1
|
||||
* Amber-LED: ledid0 & ledid1 & !ledid2
|
||||
* Left-Green: ledid-2
|
||||
* Right-Green: ledid-0
|
||||
* ledid3 is not used
|
||||
*/
|
||||
{ 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 },
|
||||
{
|
||||
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||
LEDS_1G | LEDS_LINK,
|
||||
LEDS_2G5 | LEDS_LINK,
|
||||
LEDS_COL | LEDS_DUPLEX,
|
||||
}
|
||||
},
|
||||
.led_mux_custom = 0,
|
||||
};
|
||||
#elif defined 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 | 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 },
|
||||
},
|
||||
};
|
||||
#endif
|
||||
@@ -1,72 +0,0 @@
|
||||
#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_SWGT024_V2_0
|
||||
// #define MACHINE_HORACO_ZX_SG4T2
|
||||
// #define MACHINE_HG0402XG_V1_1
|
||||
#define MACHINE_ZX_SWTGW215AS_HASIVO
|
||||
// #define DEFAULT_8C_1SFP
|
||||
|
||||
// #define DEFAULT_5C_1SFP
|
||||
|
||||
typedef struct {
|
||||
// GPIO pins for SDA/SCL
|
||||
uint8_t sda;
|
||||
uint8_t scl;
|
||||
} i2c_bus_t;
|
||||
|
||||
|
||||
#define LED_27 1
|
||||
#define LED_28 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;
|
||||
uint8_t min_port;
|
||||
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];
|
||||
int8_t reset_pin;
|
||||
struct high_leds high_leds;
|
||||
uint8_t port_led_set[9];
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
#ifndef _PHY_H_
|
||||
#define _PHY_H_
|
||||
|
||||
/*
|
||||
* The RTL8272/RTL8273 appear to comprise an RTL8224 PHY
|
||||
* which in turn is a 4x RTL8221B PHY
|
||||
* These phys are all Clause 45
|
||||
* The defines below are taken from the RTL8221B datasheet
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define PHY pages
|
||||
*/
|
||||
#define PHY_MMD_PMAPMD 1
|
||||
#define PHY_MMD_AN 7
|
||||
#define PHY_MMD30 30
|
||||
#define PHY_MMD31 31
|
||||
|
||||
/*
|
||||
* Define registers in Auto-Negotiation page
|
||||
*/
|
||||
#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_LP_ABILITY 0x3d
|
||||
#define PHY_EEE_ADV2 0x3e
|
||||
#define PHY_EEE_LP_ABILITY2 0x3f
|
||||
// Register bits for EEE capabilities at a given speed
|
||||
#define PHY_EEE_BIT_2G5 0x01
|
||||
#define PHY_EEE_BIT_1G 0x04
|
||||
#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 PHY_CTRL_5 0x7582
|
||||
|
||||
/*
|
||||
* Duplex settings
|
||||
*/
|
||||
#define PHY_DUPLEX_HALF 0
|
||||
#define PHY_DUPLEX_FULL 1
|
||||
#define PHY_DUPLEX_BOTH 2
|
||||
#endif
|
||||
@@ -3,51 +3,17 @@
|
||||
|
||||
#include "uip/uip-conf.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SYS_TICK_HZ 200
|
||||
|
||||
#define CPU_PORT 9
|
||||
|
||||
// Define Port-masks for 9-port devices and 6-port devices
|
||||
#define PMASK_9 0x1ff
|
||||
#define PMASK_6 0x1f8
|
||||
#define PMASK_CPU 0x200
|
||||
|
||||
// Defines a port mask for dropping all packets on Lookup-miss
|
||||
#define LOOKUP_MISS_DROP_6 0x00015540
|
||||
#define LOOKUP_MISS_DROP_9 0x00015555
|
||||
#define LOOKUP_MISS_FLOOD 0x00000000
|
||||
|
||||
// The serial buffer. Defines the command line size
|
||||
// Must be 2^x and <= 128
|
||||
#define SBUF_SIZE 128
|
||||
|
||||
// Size of the TCP Output buffer
|
||||
#define TCP_OUTBUF_SIZE 2500
|
||||
|
||||
// Size of the memory area dedicated to VLAN-names
|
||||
#define VLAN_NAMES_SIZE 1024
|
||||
|
||||
// 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 VLAN tag is inserted after the RTL tag
|
||||
// See here for the RTL tag: https://github.com/torvalds/linux/commit/1521d5adfc2b557e15f97283c8b7ad688c3ebc40
|
||||
struct rtl_tag {
|
||||
uint16_t tag; // This is 0x8899 for the RTL837X
|
||||
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
|
||||
};
|
||||
|
||||
struct vlan_tag {
|
||||
uint16_t svlan; // Service VLAN
|
||||
uint16_t vlan;
|
||||
};
|
||||
|
||||
#define RTL_TAG_SIZE (sizeof (struct rtl_tag))
|
||||
#define VLAN_TAG_SIZE (sizeof (struct vlan_tag))
|
||||
#define RTL_TAG_SIZE 8
|
||||
#define VLAN_TAG_SIZE 4
|
||||
#define RTL_FRAME_TAG_ID 0x8899
|
||||
|
||||
// For RX and TX, an 8 byte header describing the frame to be moved to the Asic
|
||||
@@ -57,14 +23,6 @@ struct vlan_tag {
|
||||
// This is the standard size of an Ethernet frame header
|
||||
#define ETHER_HEADER_SIZE 14
|
||||
|
||||
#define CONFIG_START 0x70000
|
||||
#define CONFIG_LEN 0x1000
|
||||
#define CODE0_SIZE 0x4000
|
||||
#define CODE_BANK_SIZE 0xc000
|
||||
|
||||
// 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.
|
||||
@@ -73,25 +31,18 @@ struct uip_eth_addr {
|
||||
uint8_t addr[6];
|
||||
};
|
||||
|
||||
struct flash_region_t {
|
||||
uint32_t addr;
|
||||
uint16_t len;
|
||||
};
|
||||
|
||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
||||
|
||||
|
||||
// Headers for calls in the common code area (HOME/BANK0)
|
||||
void print_string(__code char *p);
|
||||
void print_long(__xdata uint32_t a);
|
||||
void print_short(uint16_t a);
|
||||
void print_byte(uint8_t a);
|
||||
void itoa(uint8_t v);
|
||||
void print_sfr_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(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t v);
|
||||
void phy_write(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v);
|
||||
void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg);
|
||||
void phy_modify(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t mask, uint16_t set);
|
||||
void reg_read(uint16_t reg_addr);
|
||||
void reg_read_m(uint16_t reg_addr);
|
||||
void reg_write(uint16_t reg_addr);
|
||||
@@ -103,8 +54,6 @@ void print_reg(uint16_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_clear(uint16_t reg_addr, char bit);
|
||||
void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set);
|
||||
void sfr_set_zero(void);
|
||||
void reset_chip(void);
|
||||
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
|
||||
void memcpyc(register __xdata uint8_t *dst, register __code uint8_t *src, register uint16_t len);
|
||||
@@ -114,11 +63,5 @@ uint16_t strlen_x(register __xdata const char *s);
|
||||
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s);
|
||||
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(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);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,22 +8,10 @@
|
||||
#include "rtl837x_sfr.h"
|
||||
|
||||
__xdata uint8_t dio_enabled;
|
||||
__xdata struct flash_region_t flash_region;
|
||||
__xdata uint8_t markbuf[16];
|
||||
extern __xdata uint16_t mpos;
|
||||
|
||||
|
||||
// For the flash commands, see e.g. Windbond W25Q32JV datasheet
|
||||
#define CMD_WRITE_STATUS 0x01
|
||||
#define CMD_PAGE_PROGRAM 0x02
|
||||
// Don't use command `READ 0x03`, because on many device this command can't run at maximum SPI-clock speed.
|
||||
// Use `Fast READ 0x0b` instead!
|
||||
//#define CMD_READ 0x03
|
||||
#define CMD_WRITE_ENABLE 0x06
|
||||
#define CMD_FREAD 0x0b
|
||||
#define CMD_SECTOR_ERASE 0x20
|
||||
#define CMD_READ_SECURITY_REGS 0x48
|
||||
#define CMD_READ_UNIQUE_ID 0x4b
|
||||
#define CMD_READ_JEDEC_ID 0x9f
|
||||
#define CMD_FREAD_DIO 0xbb
|
||||
#pragma codeseg BANK1
|
||||
|
||||
/*
|
||||
* Configure Memory Managed IO
|
||||
@@ -33,14 +21,14 @@ void flash_configure_mmio(void)
|
||||
// Set configuration for MMIO access by controller
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD_DIO; // By default we read with Dual speed
|
||||
SFR_FLASH_DUMMYCYCLES = 4;
|
||||
SFR_FLASH_CMD_R = 0xbb; // By default we read with Dual speed
|
||||
SFR_FLASH_DUMMYCICLES = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD; // Default is Single IO
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
SFR_FLASH_CMD_R = 0xb; // By default we read with single speed
|
||||
SFR_FLASH_DUMMYCICLES = 8;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,26 +39,27 @@ void flash_configure_mmio(void)
|
||||
* This configures fast single IO at 20.8 MHz when the CPU clock is at 20.8MHz
|
||||
* and 62.5MHz when the CPU clock is configured at 125MHz
|
||||
*/
|
||||
void flash_init(uint8_t enable_dio)
|
||||
void flash_init(uint8_t enable_dio) __banked
|
||||
{
|
||||
if (enable_dio) {
|
||||
// Configure fast DIO via divider/DIO/SIOconfig = 4 and read-cmd being 0xbb (for mmio)
|
||||
SFR_FLASH_CONFIG = 9; // There may be a chip-select in here
|
||||
SFR_FLASH_CONF_RCMD = CMD_FREAD_DIO;
|
||||
SFR_FLASH_CONF_RCMD = 0xbb;
|
||||
SFR_FLASH_CONF_DIV = 4;
|
||||
} else {
|
||||
// Configure fast read via divider = 8 and read-cmd being CMD_FREAD (for mmio)
|
||||
// Configure fast read via divider = 8 and read-cmd being 0xb (for mmio)
|
||||
SFR_FLASH_CONFIG = 9;
|
||||
SFR_FLASH_CONF_RCMD = CMD_FREAD;
|
||||
SFR_FLASH_CONF_RCMD = 0xb;
|
||||
SFR_FLASH_CONF_DIV = 8;
|
||||
}
|
||||
// Test Controller Busy
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
// Write 0 to status register
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
SFR_FLASH_DUMMYCICLES = 8;
|
||||
SFR_FLASH_MODEB = 0;
|
||||
SFR_FLASH_TCONF = 0x19;
|
||||
SFR_FLASH_CMD = CMD_WRITE_STATUS;
|
||||
SFR_FLASH_CMD = 1;
|
||||
SFR_FLASH_DATA0 = 0;
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
@@ -97,14 +86,14 @@ uint8_t flash_read_status(void)
|
||||
}
|
||||
|
||||
|
||||
void flash_read_uid(void)
|
||||
void flash_read_uid(void) __banked
|
||||
{
|
||||
while (flash_read_status() & 0x1);
|
||||
|
||||
// Set slow read mode for UID
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_READ_UNIQUE_ID;
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
SFR_FLASH_CMD_R = 0x4b;
|
||||
SFR_FLASH_DUMMYCICLES = 8;
|
||||
|
||||
// Transfer 4 bytes (command + 3 dummy bytes)
|
||||
SFR_FLASH_TCONF = 4;
|
||||
@@ -121,7 +110,7 @@ void flash_read_uid(void)
|
||||
print_byte(SFR_FLASH_DATA24);
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
SFR_FLASH_DUMMYCYCLES = 24;
|
||||
SFR_FLASH_DUMMYCICLES = 24;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
print_byte(SFR_FLASH_DATA0);
|
||||
@@ -133,14 +122,14 @@ void flash_read_uid(void)
|
||||
}
|
||||
|
||||
|
||||
void flash_read_jedecid(void)
|
||||
void flash_read_jedecid(void) __banked
|
||||
{
|
||||
while (flash_read_status() & 0x1);
|
||||
|
||||
// Set read mode for JEDEC ID
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_READ_JEDEC_ID;
|
||||
SFR_FLASH_DUMMYCYCLES = 0;
|
||||
SFR_FLASH_CMD_R = 0x9f;
|
||||
SFR_FLASH_DUMMYCICLES = 0;
|
||||
|
||||
// Transfer 3 bytes back
|
||||
SFR_FLASH_TCONF = 0x13;
|
||||
@@ -155,14 +144,12 @@ void flash_read_jedecid(void)
|
||||
|
||||
// Reset slow read mode
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD;
|
||||
SFR_FLASH_DUMMYCYCLES = 8;
|
||||
|
||||
flash_configure_mmio();
|
||||
SFR_FLASH_CMD_R = 0xb;
|
||||
SFR_FLASH_DUMMYCICLES = 8;
|
||||
}
|
||||
|
||||
|
||||
void flash_write_enable(void)
|
||||
void flash_write_enable(void) __banked
|
||||
{
|
||||
short status;
|
||||
|
||||
@@ -170,16 +157,14 @@ void flash_write_enable(void)
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (status & 0x1);
|
||||
// while (flash_read_status() & 0x1);
|
||||
|
||||
SFR_FLASH_TCONF = 0x18;
|
||||
SFR_FLASH_CMD = CMD_WRITE_ENABLE;
|
||||
|
||||
/* The following makes sure that the PAGE_PROGRAM command,
|
||||
* where the data to be written follows the command word directly
|
||||
* works properly
|
||||
*/
|
||||
SFR_FLASH_CMD = 6;
|
||||
/* The following is explicitly set for SIO, is this necessary?:
|
||||
SFR_FLASH_DUMMYCYCLES = 0;
|
||||
SFR_FLASH_MODEB = 0;
|
||||
*/
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
// Wait for write status enabled
|
||||
@@ -189,7 +174,7 @@ void flash_write_enable(void)
|
||||
}
|
||||
|
||||
|
||||
void flash_dump(uint8_t len)
|
||||
void flash_dump(register uint32_t addr, register uint8_t len) __banked
|
||||
{
|
||||
short status;
|
||||
do {
|
||||
@@ -200,20 +185,20 @@ void flash_dump(uint8_t len)
|
||||
// Set fast read mode
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD_DIO;
|
||||
SFR_FLASH_DUMMYCYCLES = 4;
|
||||
SFR_FLASH_CMD_R = 0xbb;
|
||||
SFR_FLASH_DUMMYCICLES = 4;
|
||||
} else {
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD; // Fast read
|
||||
SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks after read?
|
||||
SFR_FLASH_CMD_R = 0xb; // Fast read
|
||||
SFR_FLASH_DUMMYCICLES = 8; // Add 8 dummy clocks after read?
|
||||
}
|
||||
// Read 4 bytes
|
||||
SFR_FLASH_TCONF = 4;
|
||||
while (len) {
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
flash_region.addr += 4;
|
||||
SFR_FLASH_ADDR16 = addr >> 16;
|
||||
SFR_FLASH_ADDR8 = addr >> 8;
|
||||
SFR_FLASH_ADDR0 = addr;
|
||||
addr += 4;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
@@ -237,7 +222,7 @@ void flash_dump(uint8_t len)
|
||||
* Reads bulk data of length len from the flash memory starging at address src
|
||||
* and writes the data into a buffer pointed to by dst in XMEM
|
||||
*/
|
||||
void flash_read_bulk(__xdata uint8_t *dst)
|
||||
void flash_read_bulk(register __xdata uint8_t *dst, __xdata uint32_t src, register uint16_t len) __banked
|
||||
{
|
||||
short status;
|
||||
do {
|
||||
@@ -247,114 +232,193 @@ void flash_read_bulk(__xdata uint8_t *dst)
|
||||
// Set fast read mode
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD_DIO;
|
||||
SFR_FLASH_DUMMYCYCLES = 4;
|
||||
SFR_FLASH_CMD_R = 0xbb;
|
||||
SFR_FLASH_DUMMYCICLES = 4;
|
||||
} else {
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_FREAD; // Fast read
|
||||
SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks
|
||||
SFR_FLASH_CMD_R = 0xb; // Fast read
|
||||
SFR_FLASH_DUMMYCICLES = 8; // Add 8 dummy clocks after read?
|
||||
}
|
||||
|
||||
|
||||
// Read 4 bytes
|
||||
while (1) {
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
flash_region.addr += 4;
|
||||
|
||||
SFR_FLASH_TCONF = 4;
|
||||
SFR_FLASH_TCONF = 4;
|
||||
while (len) {
|
||||
SFR_FLASH_ADDR16 = src >> 16;
|
||||
SFR_FLASH_ADDR8 = src >> 8;
|
||||
SFR_FLASH_ADDR0 = src;
|
||||
src += 4;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
*dst++ = SFR_FLASH_DATA0;
|
||||
if (flash_region.len == 1)
|
||||
break;
|
||||
if (len == 1)
|
||||
return;
|
||||
*dst++ = SFR_FLASH_DATA8;
|
||||
if (flash_region.len == 2)
|
||||
break;
|
||||
if (len == 2)
|
||||
return;
|
||||
*dst++ = SFR_FLASH_DATA16;
|
||||
if (flash_region.len == 3)
|
||||
break;
|
||||
if (len == 3)
|
||||
return;
|
||||
*dst++ = SFR_FLASH_DATA24;
|
||||
if (flash_region.len == 4)
|
||||
break;
|
||||
flash_region.len -= 4;
|
||||
|
||||
len -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void flash_read_security(void)
|
||||
void flash_find_mark(__xdata uint32_t src, register uint16_t len, __code uint8_t *mark) __banked
|
||||
{
|
||||
uint16_t status;
|
||||
do {
|
||||
status = flash_read_status();
|
||||
} while (status & 0x1);
|
||||
|
||||
// Set fast read mode
|
||||
if (dio_enabled) {
|
||||
SFR_FLASH_MODEB = 0x18;
|
||||
SFR_FLASH_CMD_R = 0xbb;
|
||||
SFR_FLASH_DUMMYCICLES = 4;
|
||||
} else {
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = 0xb; // Fast read
|
||||
SFR_FLASH_DUMMYCICLES = 8; // Add 8 dummy clocks after read?
|
||||
}
|
||||
|
||||
uint8_t i = 0;
|
||||
uint8_t l = 0;
|
||||
uint8_t k;
|
||||
|
||||
// Calculate the length
|
||||
while (mark[i++])
|
||||
l++;
|
||||
|
||||
if (l >= 12) {
|
||||
mpos = 0xffff;
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
SFR_FLASH_TCONF = 4;
|
||||
while (len) {
|
||||
SFR_FLASH_ADDR16 = src >> 16;
|
||||
SFR_FLASH_ADDR8 = src >> 8;
|
||||
SFR_FLASH_ADDR0 = src;
|
||||
src += 4;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
markbuf[i++] = SFR_FLASH_DATA0;
|
||||
if (len != 1) {
|
||||
markbuf[i++] = SFR_FLASH_DATA8;
|
||||
if (len != 2) {
|
||||
markbuf[i++] = SFR_FLASH_DATA16;
|
||||
if (len != 3) {
|
||||
markbuf[i++] = SFR_FLASH_DATA24;
|
||||
} else {
|
||||
markbuf[i++] = 0;
|
||||
}
|
||||
} else {
|
||||
markbuf[i++] = 0;
|
||||
}
|
||||
} else {
|
||||
markbuf[i++] = 0;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
uint8_t j = 0;
|
||||
k = (i + 13 - l) & 0xf;
|
||||
i &= 0xf;
|
||||
while (mark[j] && (k != ((i) & 0xf))) {
|
||||
if (mark[j] != markbuf[k]) {
|
||||
k = k - j + 17;
|
||||
j = 0;
|
||||
} else {
|
||||
k++;
|
||||
j++;
|
||||
}
|
||||
k &= 0xf;
|
||||
}
|
||||
if (!mark[j]) {
|
||||
mpos = len + l + ((4 - ( k & 0x3)) & 0x3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mpos = 0xffff;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void flash_read_security(uint32_t addr, uint8_t len) __banked
|
||||
{
|
||||
while (flash_read_status() & 0x1);
|
||||
|
||||
// Set slow read mode
|
||||
SFR_FLASH_MODEB = 0x0;
|
||||
SFR_FLASH_CMD_R = CMD_READ_SECURITY_REGS; // read security register
|
||||
SFR_FLASH_DUMMYCYCLES = 8; // Add 8 dummy clocks as for fast read
|
||||
SFR_FLASH_CMD_R = 0x48; // read security register
|
||||
SFR_FLASH_DUMMYCICLES = 8; // Add 8 dummy clocks as for fast read
|
||||
|
||||
// Transfer 4 bytes (command + 3byte address)
|
||||
SFR_FLASH_TCONF = 4;
|
||||
do {
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
flash_region.addr += 4;
|
||||
while (len) {
|
||||
SFR_FLASH_ADDR16 = addr >> 16;
|
||||
SFR_FLASH_ADDR8 = addr >> 8;
|
||||
SFR_FLASH_ADDR0 = addr;
|
||||
addr += 4;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while(SFR_FLASH_EXEC_BUSY);
|
||||
|
||||
print_byte(SFR_FLASH_DATA0);
|
||||
if (flash_region.len == 1)
|
||||
break;
|
||||
if (len == 1)
|
||||
return;
|
||||
print_byte(SFR_FLASH_DATA8);
|
||||
if (flash_region.len == 2)
|
||||
break;
|
||||
if (len == 2)
|
||||
return;
|
||||
print_byte(SFR_FLASH_DATA16);
|
||||
if (flash_region.len == 3)
|
||||
break;
|
||||
if (len == 3)
|
||||
return;
|
||||
print_byte(SFR_FLASH_DATA24);
|
||||
|
||||
flash_region.len -= 4;
|
||||
} while(flash_region.len);
|
||||
|
||||
flash_configure_mmio();
|
||||
len -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void flash_sector_erase(void)
|
||||
void flash_block_erase(uint32_t addr) __banked
|
||||
{
|
||||
flash_write_enable();
|
||||
SFR_FLASH_TCONF = 8;
|
||||
SFR_FLASH_CMD = CMD_SECTOR_ERASE;
|
||||
SFR_FLASH_CMD = 0x20;
|
||||
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
SFR_FLASH_ADDR16 = addr >> 16;
|
||||
SFR_FLASH_ADDR8 = addr >> 8;
|
||||
SFR_FLASH_ADDR0 = addr;
|
||||
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
while (flash_read_status() & 0x1);
|
||||
|
||||
flash_configure_mmio();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void flash_write_bytes(__xdata uint8_t *ptr)
|
||||
void flash_write_bytes(__xdata uint32_t addr, __xdata uint8_t *ptr, uint16_t len) __banked
|
||||
{
|
||||
// write_char('\n'); write_char('>'); print_long(flash_region.addr); write_char(':'); print_short(flash_region.len); write_char('-'); print_byte(*ptr); // write_char('\n');
|
||||
static __xdata uint8_t exit_loop = 0;
|
||||
|
||||
while(1) {
|
||||
flash_write_enable();
|
||||
SFR_FLASH_CMD = CMD_PAGE_PROGRAM;
|
||||
SFR_FLASH_TCONF = 0x40 | 8 | 4; // Bytes written is 4, 8 enables write, 0x40 is unknown
|
||||
SFR_FLASH_CMD = 2;
|
||||
SFR_FLASH_TCONF = 0x40 | 8 | 2; // Bytes written is is 4, 8 enables write, 0x2 is unkown
|
||||
// Last transfer?
|
||||
if (flash_region.len < 5) {
|
||||
SFR_FLASH_TCONF = 8 | flash_region.len;
|
||||
if (len < 5) {
|
||||
SFR_FLASH_TCONF = 8 | len;
|
||||
exit_loop = 1;
|
||||
}
|
||||
|
||||
SFR_FLASH_ADDR16 = flash_region.addr >> 16;
|
||||
SFR_FLASH_ADDR8 = flash_region.addr >> 8;
|
||||
SFR_FLASH_ADDR0 = flash_region.addr;
|
||||
SFR_FLASH_ADDR16 = addr >> 16;
|
||||
SFR_FLASH_ADDR8 = addr >> 8;
|
||||
SFR_FLASH_ADDR0 = addr;
|
||||
SFR_FLASH_DATA0 = *ptr++;
|
||||
SFR_FLASH_DATA8 = *ptr++;
|
||||
SFR_FLASH_DATA16 = *ptr++;
|
||||
@@ -362,13 +426,12 @@ void flash_write_bytes(__xdata uint8_t *ptr)
|
||||
|
||||
// Execute transfer, we wait for completion at top of loop
|
||||
SFR_FLASH_EXEC_GO = 1;
|
||||
|
||||
if (flash_region.len < 5)
|
||||
if (exit_loop)
|
||||
break;
|
||||
len -= 4;
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
flash_region.len -= 4;
|
||||
flash_region.addr += 4;
|
||||
};
|
||||
while (flash_read_status() & 0x1);
|
||||
flash_configure_mmio();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef _RTL837X_FLASH_H_
|
||||
#define _RTL837X_FLASH_H_
|
||||
|
||||
void flash_init(uint8_t enable_dio);
|
||||
void flash_read_uid(void);
|
||||
void flash_write_enable(void);
|
||||
void flash_dump(uint8_t len);
|
||||
void flash_read_jedecid(void);
|
||||
void flash_read_security(void);
|
||||
void flash_sector_erase(void);
|
||||
void flash_read_bulk(__xdata uint8_t *dst);
|
||||
void flash_write_bytes(__xdata uint8_t *ptr);
|
||||
void flash_init(uint8_t enable_dio) __banked;
|
||||
void flash_read_uid(void) __banked;
|
||||
void flash_write_enable(void)__banked ;
|
||||
void flash_dump(register uint32_t addr, register uint8_t len) __banked;
|
||||
void flash_read_jedecid(void) __banked;
|
||||
void flash_read_security(uint32_t addr, uint8_t len)__banked ;
|
||||
void flash_block_erase(uint32_t addr) __banked;
|
||||
void flash_read_bulk(register __xdata uint8_t *dst, __xdata uint32_t src, register uint16_t len) __banked;
|
||||
void flash_write_bytes(__xdata uint32_t addr, register __xdata uint8_t *ptr, register uint16_t len)__banked;
|
||||
void flash_find_mark(__xdata uint32_t src, register uint16_t len, __code uint8_t *mark) __banked;
|
||||
#endif
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
* This is a driver implementation for the IGMP features for the RTL827x platform
|
||||
* This code is in the Public Domain
|
||||
*/
|
||||
|
||||
// #define REGDBG
|
||||
// #define DEBUG
|
||||
|
||||
#define IPMC_USES_L3MC
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
extern __xdata uint8_t cpuPort;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
|
||||
|
||||
__xdata uint16_t idx;
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
struct ipmc_table_entry {
|
||||
uint8_t sip[4];
|
||||
uint8_t dip[4];
|
||||
uint16_t pmask;
|
||||
uint8_t igmp_index;
|
||||
uint8_t igmp_asic;
|
||||
};
|
||||
static __xdata struct ipmc_table_entry entry;
|
||||
#else
|
||||
struct l2mc_table_entry {
|
||||
uint8_t mac[6];
|
||||
uint16_t vlan;
|
||||
uint16_t pmask;
|
||||
uint8_t is_svl;
|
||||
uint8_t igmp_index;
|
||||
uint8_t igmp_asic;
|
||||
};
|
||||
static __xdata struct l2mc_table_entry entry;
|
||||
#endif
|
||||
|
||||
struct igmp_pkt {
|
||||
uint8_t ipv4mc_addr[6];
|
||||
uint8_t src_addr[6];
|
||||
struct rtl_tag rtl_tag;
|
||||
uint16_t ipv4_tag;
|
||||
uint8_t hlen;
|
||||
uint8_t dscp;
|
||||
uint16_t len;
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t checksum;
|
||||
uint8_t src_ip[4];
|
||||
uint8_t dst_ip[4];
|
||||
uint8_t ip_opt;
|
||||
uint8_t ip_len;
|
||||
uint16_t ra;
|
||||
uint8_t igmp_type;
|
||||
uint8_t igmp_res1;
|
||||
uint16_t igmp_checksum;
|
||||
uint16_t igmp_res2;
|
||||
uint16_t igmp_records;
|
||||
uint8_t igmp_rtype;
|
||||
uint8_t igmp_auxlen;
|
||||
uint16_t igmp_nsrc;
|
||||
uint8_t mc_ip[4];
|
||||
};
|
||||
#define IGMP_I ((__xdata struct igmp_pkt *)&uip_buf[0])
|
||||
|
||||
|
||||
void igmp_setup(void) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
print_string("igmp_setup called\n");
|
||||
// For now, forward all unkown IP-MC pkts (2 bits per port. 00: flood via floodmask, 01: drop, 10: trap, 11: to rport)
|
||||
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
|
||||
REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
|
||||
|
||||
// Define ports where unknown MC addresses are flooded to:
|
||||
REG_SET(RTL837X_IPV4_UNKN_MC_FLD_PMSK, machine_detected.isRTL8373? PMASK_9: PMASK_6);
|
||||
REG_SET(RTL837X_IPV6_UNKN_MC_FLD_PMSK, machine_detected.isRTL8373? PMASK_9: PMASK_6);
|
||||
|
||||
// Enable lookup of IPv4 MC addresses in table
|
||||
reg_bit_set(RTL837X_L2_CTRL, L2_CTRL_LUT_IPMC_HASH);
|
||||
|
||||
// Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping,
|
||||
// bits 16-24 configure max MC group used by that port. For now all protocols are flooded (01)
|
||||
for (i = machine.min_port; i <= machine.max_port; i++)
|
||||
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), 0x00ff7c15);
|
||||
|
||||
/* Configure per-port IGMP operations when protocol messages are received
|
||||
* bits 0-9 enable MC protocol snooping
|
||||
* bit 10: Enable dynamic router port learning
|
||||
* bit 11: Enable MRP (Multicast Routing Protocol)
|
||||
* bit 12: Allow fast leave
|
||||
* bit 13: Allow IGMP reporting
|
||||
* bit 14: Allow queries
|
||||
* bits 16-24 configure max MC group used by that port.
|
||||
* Operations for IGMP packets are:
|
||||
* 00: handle in HW by ASIC
|
||||
* 01: flood
|
||||
* 10: trap
|
||||
* 11: drop
|
||||
* Bits 0-1: IGMPv1, 2-3: IGMPv2, 4-5: IGMPv3, 6-7: MLDv1 (for IPv6), 8-9: MLDv2
|
||||
* For now the IGMP protocols are flooded (01), MLD which MAC-based is handled by ASIC
|
||||
* All messages are allowed and maximum MC group is 0xff
|
||||
*/
|
||||
for (i = machine.min_port; i <= machine.max_port; i++)
|
||||
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_FLOOD);
|
||||
|
||||
/* // Allow all physical ports to be dynamic router ports
|
||||
reg_read_m(RTL837X_IGMP_ROUTER_PORT);
|
||||
if (machine_detected.isRTL8373) {
|
||||
REG_WRITE(RTL837X_IGMP_ROUTER_PORT, PMASK_9 >> 8, PMASK_9 & 0xff, sfr_data[1], sfr_data[0]);
|
||||
} else {
|
||||
REG_WRITE(RTL837X_IGMP_ROUTER_PORT, PMASK_6 >> 8, PMASK_6 & 0xff, sfr_data[1], sfr_data[0]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void igmp_enable(void) __banked
|
||||
{
|
||||
print_string("igmp_enable called\n");
|
||||
// Configure trapping of unhandled IGMP protocol packets to CPU
|
||||
REG_SET(RTL837X_IGMP_TRAP_CFG, IGMP_CPU_PORT | IGMP_TRAP_PRIORITY);
|
||||
|
||||
// Drop unknown IP-MC packets
|
||||
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, machine_detected.isRTL8373? LOOKUP_MISS_DROP_9: LOOKUP_MISS_DROP_6);
|
||||
// REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, machine_detected.isRTL8373? LOOKUP_MISS_DROP_9: LOOKUP_MISS_DROP_6);
|
||||
|
||||
// Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping,
|
||||
// bits 16-24 configure max MC group used by that port. Trap to CPU (10)
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_TRAP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configures the IGMP static router port(s) that will receive all IGMP
|
||||
* Report and Leave messages
|
||||
*/
|
||||
void igmp_router_port_set(uint16_t pmask) __banked
|
||||
{
|
||||
print_string("igmp_router_port_set: "); print_short(pmask); print_string(", currently set to:\n");
|
||||
reg_read_m(RTL837X_IGMP_ROUTER_PORT);
|
||||
print_sfr_data(); write_char('\n');
|
||||
REG_WRITE(RTL837X_IGMP_ROUTER_PORT, sfr_data[0], sfr_data[1], pmask >> 8, pmask & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IGMP show the current entries and state
|
||||
*/
|
||||
void igmp_show(void) __banked
|
||||
{
|
||||
print_string("igmp_show called\n");
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
write_char('0' + i); write_char(':');
|
||||
reg_read_m(RTL837X_IGMP_PORT_CFG + (i << 2));
|
||||
print_sfr_data();
|
||||
write_char('\n');
|
||||
}
|
||||
// TODO: print all L3MC entries in the table
|
||||
}
|
||||
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
void entry_to_l3mc(void)
|
||||
{
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_A, entry.sip[0], entry.sip[1], entry.sip[2], entry.sip[3]);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_B, ((entry.pmask & 0x3) << 6) | (entry.dip[0] & 0xf) | 0x10, entry.dip[1], entry.dip[2], entry.dip[3]);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_C, 0x00, entry.igmp_asic & 1, entry.igmp_index, entry.pmask >> 2);
|
||||
}
|
||||
#else
|
||||
void entry_to_l2mc(void)
|
||||
{
|
||||
// R5cb8-5e004201 R5cbc-20010100 R5cc0-00000020 R5cac-00000403
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_A, entry.mac[2], entry.mac[3], entry.mac[4], entry.mac[5]);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_B, 0x20 | ((entry.pmask & 0x3) << 6) | (entry.vlan >> 8), entry.vlan & 0xff, entry.mac[0], entry.mac[1]);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_C, 0x00, entry.igmp_asic & 1, entry.igmp_index, entry.pmask >> 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void igmp_packet_handler(void) __banked
|
||||
{
|
||||
// By default we do not send anything out
|
||||
uip_len = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
print_string("\nIPv4 MC packet:\n");
|
||||
for (uint8_t i = 0; i < 80; i++) {
|
||||
print_byte(uip_buf[i]);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
#endif
|
||||
if (IGMP_I->protocol != 2)
|
||||
return;
|
||||
#ifdef DEBUG
|
||||
print_string("Found IGMP, type: "); print_byte(IGMP_I->igmp_type); write_char('\n');
|
||||
#endif
|
||||
// We react to IGMPv1/v2 and v3 membership reports
|
||||
if (!(IGMP_I->igmp_type == 0x12 || IGMP_I->igmp_type == 0x16 || IGMP_I->igmp_type == 0x22))
|
||||
return;
|
||||
#ifdef DEBUG
|
||||
print_string("IGMP membership report, type "); print_byte(IGMP_I->igmp_rtype); write_char('\n');
|
||||
#endif
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
memset(&entry, 0, sizeof(struct ipmc_table_entry));
|
||||
// For IPv4 MC, the Source-IP is 0.0.0.0
|
||||
entry.sip[0] = 0x00; entry.sip[1] = 0x00; entry.sip[2] = 0x00; entry.sip[3] = 0x00;
|
||||
// For IPv4 MC, the Destination-IP is the IPv4 MC address
|
||||
entry.dip[0] = IGMP_I->mc_ip[0]; entry.dip[1] = IGMP_I->mc_ip[1]; entry.dip[2] = IGMP_I->mc_ip[2]; entry.dip[3] = IGMP_I->mc_ip[3];
|
||||
entry_to_l3mc();
|
||||
#else
|
||||
/* The L2 Multicast MAC for IP-Multicast is 01:00:5e:xx:yy:zz, where
|
||||
* xx = MC_IP[1] & 0x7f
|
||||
* yy = MC_IP[2]
|
||||
* zz = MC_IP[3]
|
||||
*/
|
||||
memset(&entry, 0, sizeof(struct l2mc_table_entry));
|
||||
entry.mac[0] = 0x01; entry.mac[1] = 0x00; entry.mac[2] = 0x5e;
|
||||
entry.mac[3] = IGMP_I->mc_ip[1] & 0x7f; entry.mac[4] = IGMP_I->mc_ip[2]; entry.mac[5] = IGMP_I->mc_ip[3];
|
||||
entry.vlan = 1; //TODO: Get this out of the packet and compare with VLAN table!
|
||||
entry_to_ipmc();
|
||||
#endif
|
||||
// Wait for any pending Table operations to end
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 1);
|
||||
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
#ifdef DEBUG
|
||||
print_sfr_data();
|
||||
#endif
|
||||
sfr_data[2] &= 0x3f; // Sets the Read-method to 0 (why MAC-lookup?) and clear the CLEAR-Entry bit
|
||||
sfr_data[1] &= 0xf8;
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
#ifdef DEBUG
|
||||
print_string(" l2 ctrl now: ");
|
||||
print_sfr_data();
|
||||
#endif
|
||||
// First try to find entry to see whether it needs to be updated
|
||||
REG_WRITE(RTL837X_TBL_CTRL, 0x00, 0x00, TBL_L2_UNICAST, TBL_EXECUTE);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
#ifdef DEBUG
|
||||
print_string("\nsearch done\n");
|
||||
print_string("Table data searched:\n");
|
||||
reg_read_m(RTL837x_TBL_DATA_IN_A);
|
||||
print_sfr_data(); write_char(' ');
|
||||
reg_read_m(RTL837x_TBL_DATA_IN_B);
|
||||
print_sfr_data(); write_char(' ');
|
||||
reg_read_m(RTL837x_TBL_DATA_IN_C);
|
||||
print_sfr_data(); write_char('\n');
|
||||
print_string("Table data gotten:\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_A); write_char(' ');
|
||||
print_sfr_data();
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
print_sfr_data(); write_char(' ');
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||
print_sfr_data(); write_char('\n');
|
||||
print_string("Result: ");
|
||||
#endif
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
#ifdef DEBUG
|
||||
print_sfr_data();
|
||||
#endif
|
||||
idx = ((sfr_data[2] & 0xf) << 8) | sfr_data[3];
|
||||
if (IGMP_I->igmp_rtype == 0x4) {// Join group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
print_string("\nIGMP-Entry FOUND\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
entry.pmask = sfr_data[0] >> 6;
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||
entry.pmask |= ((uint16_t)sfr_data[3]) << 2;
|
||||
}
|
||||
// Update (found) entry with portmask from trapped Packet
|
||||
entry.pmask |= (1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else if (IGMP_I->igmp_rtype == 0x3){ // Leave group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
print_string("\nIGMP_Entry FOUND\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
entry.pmask = sfr_data[0] >> 6;
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||
entry.pmask |= ((uint16_t)sfr_data[3]) << 2;
|
||||
#ifdef DEBUG
|
||||
print_string("Portmask: ");
|
||||
print_short(entry.pmask);
|
||||
print_string("Index: ");
|
||||
print_short(idx);
|
||||
write_char('\n');
|
||||
#endif
|
||||
// Remove portmask of IGMP packet from entry
|
||||
entry.pmask &= ~(1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else {
|
||||
print_string("IGMP Entry already deleted\n");
|
||||
return;
|
||||
}
|
||||
if (!entry.pmask && idx) { // No more ports in that group and an actual entry?
|
||||
// Delete Entry
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
sfr_data[1] |= 0x04; // Clear entry
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
REG_WRITE(RTL837X_TBL_CTRL, idx >> 8, idx & 0xff, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
print_string("IGMP Entry deleted\n");
|
||||
return;
|
||||
}
|
||||
} else { // Unknown message: ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entry.pmask)
|
||||
return;
|
||||
print_string("Updating IGMP entry\n");
|
||||
// Write the updated entry
|
||||
#ifdef IPMC_USES_L3MC
|
||||
entry_to_l3mc();
|
||||
#else
|
||||
entry_to_ipmc();
|
||||
#endif
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
#ifdef DEBUG
|
||||
print_sfr_data();
|
||||
#endif
|
||||
sfr_data[2] &= 0x3f; // Set the Read-method to 0 and clear the CLEAR-Entry bit
|
||||
sfr_data[1] &= 0xf8;
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
#ifdef DEBUG
|
||||
print_string(" l2 ctrl now: ");
|
||||
print_sfr_data();
|
||||
#endif
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
REG_WRITE(RTL837X_TBL_CTRL, sfr_data[0], sfr_data[1], TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
#ifdef DEBUG
|
||||
print_string("\nupdate done\n");
|
||||
print_string("Table data written:\n");
|
||||
reg_read_m(RTL837x_TBL_DATA_IN_A);
|
||||
print_sfr_data(); write_char(' ');
|
||||
reg_read_m(RTL837x_TBL_DATA_IN_B);
|
||||
print_sfr_data(); write_char(' ');
|
||||
reg_read_m(RTL837x_TBL_DATA_IN_C);
|
||||
print_sfr_data(); write_char('\n');
|
||||
print_string("Result: ");
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
print_sfr_data();
|
||||
#endif
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef _RTL837X_IGMP_H_
|
||||
#define _RTL837X_IGMP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
|
||||
#endif
|
||||
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
* This is a driver implementation for the IGMP features for the RTL827x platform
|
||||
* This code is in the Public Domain
|
||||
*/
|
||||
|
||||
// #define REGDBG
|
||||
// #define DEBUG
|
||||
|
||||
#define IPMC_USES_L3MC
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_leds.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
void leds_dump(void) __banked
|
||||
{
|
||||
print_string("RTL837X_PIN_MUX_0: "); print_reg(RTL837X_PIN_MUX_0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_IO_EN: "); print_reg(RTL837X_REG_LED_GLB_IO_EN); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET0: "); print_reg(RTL837X_REG_LED1_0_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET0: "); print_reg(RTL837X_REG_LED3_2_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET1: "); print_reg(RTL837X_REG_LED1_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET1: "); print_reg(RTL837X_REG_LED3_2_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_1: "); print_reg(RTL837X_REG_LED_GLB_MUX_1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_2: "); print_reg(RTL837X_REG_LED_GLB_MUX_2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_3: "); print_reg(RTL837X_REG_LED_GLB_MUX_3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_4: "); print_reg(RTL837X_REG_LED_GLB_MUX_4); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_5: "); print_reg(RTL837X_REG_LED_GLB_MUX_5); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_6: "); print_reg(RTL837X_REG_LED_GLB_MUX_6); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_ACTIVE: "); print_reg(RTL837X_REG_LED_GLB_ACTIVE); write_char('\n');
|
||||
print_string("LED pad Configuration:\n");
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
print_byte(i);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
switch (i % 5) {
|
||||
case 0: // 0
|
||||
reg_read_m(RTL837X_REG_LED_GLB_MUX_1 + (i / 5) * 4);
|
||||
print_byte(sfr_data[3] & 0x3f);
|
||||
break;
|
||||
case 1: // 6
|
||||
print_byte(((sfr_data[3] >> 6) | (sfr_data[2] << 2)) & 0x3f);
|
||||
break;
|
||||
case 2: // 12
|
||||
print_byte(((sfr_data[1] << 4) | (sfr_data[2] >> 4)) & 0x3f);
|
||||
break;
|
||||
case 3: // 18
|
||||
print_byte((sfr_data[1] >> 2) & 0x3f);
|
||||
break;
|
||||
case 4: // 24
|
||||
print_byte(sfr_data[0] & 0x3f);
|
||||
break;
|
||||
}
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
print_string("LED-set Configuration:\n");
|
||||
print_string("LED-ID\t\t0\t\t1\t\t2\t\t3\n");
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
print_string("SET "); write_char('0' + set); write_char(':');
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
print_string("\t ");
|
||||
uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
}
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (! (ledid & 1)) { // LEDID 0, 2
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
} else {
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
reg_read_m(RTL837X_LED_PORT_SET_SEL);
|
||||
__xdata uint8_t set = sfr_data[3 - (i >> 2)];
|
||||
set = (set >> ((i & 3) << 1));
|
||||
print_string("Port "); write_char('0' + i); print_string(": SET ");
|
||||
write_char('0' + set);
|
||||
print_string(": ");
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
write_char('(');
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (ledid & 1) { // LEDID 1, 3
|
||||
sfr_data[2] = sfr_data[0];
|
||||
sfr_data[3] = sfr_data[1];
|
||||
}
|
||||
if (sfr_data[3] & 0x01)
|
||||
print_string(" 2G5");
|
||||
if (sfr_data[3] & 0x02)
|
||||
print_string(" TWO_1G");
|
||||
if (sfr_data[3] & 0x04)
|
||||
print_string(" 1G");
|
||||
if (sfr_data[3] & 0x08)
|
||||
print_string(" 500M");
|
||||
if (sfr_data[3] & 0x10)
|
||||
print_string(" 100M");
|
||||
if (sfr_data[3] & 0x20)
|
||||
print_string(" 10M");
|
||||
if (sfr_data[3] & 0x40)
|
||||
print_string(" LINK");
|
||||
if (sfr_data[3] & 0x80)
|
||||
print_string(" LINK_FLASH");
|
||||
if (sfr_data[2] & 0x01)
|
||||
print_string(" ACT");
|
||||
if (sfr_data[2] & 0x02)
|
||||
print_string(" RX");
|
||||
if (sfr_data[2] & 0x04)
|
||||
print_string(" TX");
|
||||
if (sfr_data[2] & 0x08)
|
||||
print_string(" COL");
|
||||
if (sfr_data[2] & 0x10)
|
||||
print_string(" DUPLEX");
|
||||
if (sfr_data[2] & 0x20)
|
||||
print_string(" TRAINING");
|
||||
if (sfr_data[2] & 0x40)
|
||||
print_string(" MASTER");
|
||||
__xdata uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
}
|
||||
b = ledid & 1 ? b >> 4 : b & 0xf;
|
||||
if (b & 0x1)
|
||||
print_string(" 10G");
|
||||
if (b & 0x2)
|
||||
print_string(" TWO_5G");
|
||||
if (b & 0x4)
|
||||
print_string(" 5G");
|
||||
if (b & 0x8)
|
||||
print_string(" TWO_2G5");
|
||||
print_string("), ");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void leds_setup(void) __banked
|
||||
{
|
||||
print_string("leds_setup called\n");
|
||||
REG_SET(RTL837X_REG_LED_MODE, 0x0021e6b0);
|
||||
|
||||
// Disable RLDP (Realtek Loop Detection Protocol) LEDs on loop detection
|
||||
reg_read_m(RTL837X_REG_LED_RLDP_1);
|
||||
sfr_mask_data(0, 0x03, 0);
|
||||
reg_write_m(RTL837X_REG_LED_RLDP_1);
|
||||
|
||||
// Set up all Port-LEDs to belong to RLDP
|
||||
sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0;
|
||||
for (uint8_t i = machine.min_port; i <= (machine.max_port > 7 ? 7 : machine.max_port); i++)
|
||||
sfr_data[3 - (i >> 2)] |= i & 1 ? 0xf0 : 0x0f;
|
||||
reg_write_m(RTL837X_REG_LED_RLDP_2);
|
||||
if (machine.max_port == 8)
|
||||
REG_SET(RTL837X_REG_LED_RLDP_3, 0x0000000f); // Port 8
|
||||
|
||||
// Configure high LEDs 27-29: mux and LED enable
|
||||
if (machine.high_leds.mux & LED_27)
|
||||
reg_bit_set(RTL837X_PIN_MUX_0, 27);
|
||||
else
|
||||
reg_bit_clear(RTL837X_PIN_MUX_0, 27);
|
||||
|
||||
if (machine.high_leds.mux & LED_28)
|
||||
reg_bit_set(RTL837X_PIN_MUX_0, 28);
|
||||
else
|
||||
reg_bit_clear(RTL837X_PIN_MUX_0, 28);
|
||||
|
||||
if (machine.high_leds.mux & LED_29)
|
||||
reg_bit_set(RTL837X_PIN_MUX_0, 29);
|
||||
else
|
||||
reg_bit_clear(RTL837X_PIN_MUX_0, 29);
|
||||
|
||||
if (machine.high_leds.enable & LED_27)
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 27);
|
||||
else
|
||||
reg_bit_clear(RTL837X_REG_LED_GLB_IO_EN, 27);
|
||||
|
||||
if (machine.high_leds.enable & LED_28)
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 28);
|
||||
else
|
||||
reg_bit_clear(RTL837X_REG_LED_GLB_IO_EN, 28);
|
||||
|
||||
if (machine.high_leds.enable & LED_29)
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 29);
|
||||
else
|
||||
reg_bit_clear(RTL837X_REG_LED_GLB_IO_EN, 29);
|
||||
|
||||
// Configure the LED-mux
|
||||
if (machine.led_mux_custom) {
|
||||
print_string("Configuring custom LED-muxes: ");
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
switch (i % 5) {
|
||||
case 0: // 0
|
||||
sfr_data[3] = machine.led_mux[i];
|
||||
break;
|
||||
case 1: // 6
|
||||
sfr_data[3] |= machine.led_mux[i] << 6;
|
||||
sfr_data[2] = machine.led_mux[i] >> 2;
|
||||
break;
|
||||
case 2: // 12
|
||||
sfr_data[2] |= machine.led_mux[i] << 4;
|
||||
sfr_data[1] = machine.led_mux[i] >> 4;
|
||||
break;
|
||||
case 3: // 18
|
||||
sfr_data[1] |= machine.led_mux[i] << 2;
|
||||
break;
|
||||
case 4: // 24
|
||||
sfr_data[0] = machine.led_mux[i];
|
||||
print_sfr_data(); write_char(' ');
|
||||
reg_write_m(RTL837X_REG_LED_GLB_MUX_1 + (i / 5) * 4);
|
||||
break;
|
||||
}
|
||||
write_char(' ');
|
||||
}
|
||||
sfr_data[0] = 0; sfr_data[1] &= 0xf;
|
||||
print_sfr_data(); write_char('\n');
|
||||
reg_write_m(RTL837X_REG_LED_GLB_MUX_6);
|
||||
}
|
||||
|
||||
// Configure the LED-set of a port
|
||||
sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0;
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++)
|
||||
sfr_data[3 - (i >> 2)] |= machine.port_led_set[i] << ((i & 3) << 1);
|
||||
reg_write_m(RTL837X_LED_PORT_SET_SEL);
|
||||
|
||||
// Configure the LED-sets
|
||||
sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0;
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
__code uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
sfr_data[0] = *(lptr + 5);
|
||||
sfr_data[1] = *(lptr + 4);
|
||||
sfr_data[2] = *(lptr + 1);
|
||||
sfr_data[3] = *(lptr);
|
||||
reg_write_m(RTL837X_REG_LED1_0_SET0 - set * 8);
|
||||
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
sfr_data[3 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
sfr_data[3 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
}
|
||||
lptr += 8;
|
||||
sfr_data[0] = *(lptr + 5);
|
||||
sfr_data[1] = *(lptr + 4);
|
||||
sfr_data[2] = *(lptr + 1);
|
||||
sfr_data[3] = *(lptr);
|
||||
reg_write_m(RTL837X_REG_LED1_0_SET0 - set * 8 - 4);
|
||||
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
sfr_data[2 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
sfr_data[2 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
}
|
||||
lptr += 8;
|
||||
}
|
||||
print_string("leds_setup done\n");
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef _RTL837X_LEDS_H_
|
||||
#define _RTL837X_LEDS_H_
|
||||
|
||||
#define LEDS_2G5 0x00001
|
||||
#define LEDS_TWO_PAIR_1G 0x00002
|
||||
#define LEDS_1G 0x00004
|
||||
#define LEDS_500M 0x00008
|
||||
#define LEDS_100M 0x00010
|
||||
#define LEDS_10M 0x00020
|
||||
#define LEDS_LINK 0x00040
|
||||
#define LEDS_LINK_FLASH 0x00080
|
||||
#define LEDS_ACT 0x00100
|
||||
#define LEDS_RX 0x00200
|
||||
#define LEDS_TX 0x00400
|
||||
#define LEDS_COL 0x00800
|
||||
#define LEDS_DUPLEX 0x01000
|
||||
#define LEDS_TRAINING 0x02000
|
||||
#define LEDS_MASTER 0x04000
|
||||
#define LEDS_10G 0x10000
|
||||
#define LEDS_TWO_PAIR_5G 0x20000
|
||||
#define LEDS_5G 0x40000
|
||||
#define LEDS_TWO_PAIR_2G5 0x80000
|
||||
|
||||
#include <stdint.h>
|
||||
void leds_dump(void) __banked;
|
||||
void leds_setup(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -6,33 +6,18 @@
|
||||
|
||||
#define REGDBG
|
||||
|
||||
// Phy ID of the external RTL8224 PHY.
|
||||
#define RTL8224_PHY_ID 0x00
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "phy.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
#pragma codeseg BANK1
|
||||
|
||||
extern __code uint16_t bit_mask[16];
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
|
||||
// SDS-settings for RTL8224 first SerDes which is connected to the RTL837x-SOC.
|
||||
// Array contrains register-value, and SDS-CMD, which already encodes (sds_index, page, reg).
|
||||
// This array is used in phy_config_8224().
|
||||
//
|
||||
// Note: Adding `Swapping the RX for N-devices`-setting on the end of the array, didn't work.
|
||||
// Setting will apply but still no packets flow.
|
||||
// Settings are `0x2000, 0xc10c`,
|
||||
__code uint16_t rtl8224_sds0_setttings[42] = {
|
||||
// SDS_DATA, SDS_CMD
|
||||
|
||||
__code uint16_t rtl8224_ca[42] = {
|
||||
0x4480, 0xc842,
|
||||
0x0400, 0xc9c2,
|
||||
0x6d02, 0xcc42,
|
||||
@@ -56,86 +41,147 @@ __code uint16_t rtl8224_sds0_setttings[42] = {
|
||||
0, 0
|
||||
};
|
||||
|
||||
__code uint16_t rtl8224_cb[60] = {
|
||||
0xc45c, 0xc18c, 0x8040,
|
||||
0x0030, 0xc040, 0x8040,
|
||||
0x0010, 0xc040, 0x8040,
|
||||
0x0050, 0xc040, 0x8040,
|
||||
0x00d0, 0xc040, 0x8040,
|
||||
0x0cd0, 0xc040, 0x8040,
|
||||
0x04d0, 0xc040, 0x8040,
|
||||
0x04d0, 0xc040, 0x8040,
|
||||
0x0cd0, 0xc040, 0x8040,
|
||||
0x00d0, 0xc040, 0x8040,
|
||||
0x00d0, 0xc040, 0x8040,
|
||||
0x0050, 0xc040, 0x8040,
|
||||
0x0010, 0xc040, 0x8040,
|
||||
0x0010, 0xc040, 0x8040,
|
||||
0x0030, 0xc040, 0x8040,
|
||||
0x0000, 0xc040, 0x803e,
|
||||
0x000b, 0xc03e, 0x803e,
|
||||
0x0000, 0xc03e, 0x8042,
|
||||
0x4906, 0xc042, 0x82ec,
|
||||
0xffff,0,0
|
||||
};
|
||||
|
||||
void rtl8224_phy_enable(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
|
||||
// p001e.0a90:00f3 R02f8-000000f3 R02f4-000000fc P000001.1e000a90:00fc
|
||||
print_string("\r\nrtl8224_phy_enable called\r\n");
|
||||
phy_read(RTL8224_PHY_ID, PHY_MMD30, RTL837X_CFG_PHY_MDI_REVERSE);
|
||||
pval = SFR_DATA_U16;
|
||||
phy_read(0, 0x1e, 0xa90);
|
||||
uint16_t pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0;
|
||||
|
||||
// PHY Initialization:
|
||||
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
|
||||
|
||||
pval &= 0xfff0;
|
||||
pval |= 0x0c;
|
||||
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
|
||||
|
||||
phy_write(RTL8224_PHY_ID, PHY_MMD30, RTL837X_CFG_PHY_MDI_REVERSE, pval);
|
||||
phy_write(0x1, 0x1e, 0xa90, pval);
|
||||
|
||||
phy_read(0, 0x1e, 0xa90);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (machine_detected.isN) {
|
||||
print_string(" N-settings");
|
||||
// TX_POLARITY_SWAP
|
||||
rtl8224_write_reg_u16(RTL837X_CFG_PHY_TX_POLARITY_SWAP, 0x596A);
|
||||
}
|
||||
|
||||
print_string("\r\nrtl8224_phy_enable done\r\n");
|
||||
}
|
||||
|
||||
|
||||
void phy_config(uint8_t phy) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
print_string("\r\nphy_config: ");
|
||||
write_char('0' + phy);
|
||||
|
||||
delay(20);
|
||||
// PHY configuration: External 8221B?
|
||||
// p081e.75f3:ffff P000100.1e0075f3:fffe
|
||||
phy_modify(phy, PHY_MMD30, 0x75f3, 0x0001, 0x0000);
|
||||
// p081e.75f3:ffff P000100.1e0075f3:fffe
|
||||
phy_read(phy, 0x1e, 0x75f3);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0 & 0xfe;
|
||||
phy_write(bit_mask[phy], 0x1e, 0x75f3, pval);
|
||||
delay(20);
|
||||
|
||||
// p081e.697a:ffff P000100.1e00697a:ffc1 / p031e.697a:0003 P000008.1e00697a:0001
|
||||
// p081e.697a:ffff P000100.1e00697a:ffc1 / p031e.697a:0003 P000008.1e00697a:0001
|
||||
// SERDES OPTION 1 Register (MMD 30.0x6) bits 0-5: 0x01: Set HiSGMII+SGMII
|
||||
phy_modify(phy, PHY_MMD30, 0x697a, 0x003f, 0x0001);
|
||||
phy_read(phy, 0x1e, 0x697a);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0 & 0xc0 | 0x01;
|
||||
phy_write(bit_mask[phy], 0x1e, 0x697a, pval);
|
||||
delay(20);
|
||||
|
||||
// p031f.a432:0811 P000008.1f00a432:0831
|
||||
// p031f.a432:0811 P000008.1f00a432:0831
|
||||
// PHYCR2 PHY Specific Control Register 2, MMD 31. 0xA432), set bit 5: enable EEE
|
||||
phy_modify(phy, PHY_MMD31, PHY_MMD31_PHYCR2, 0x0000, 0x0020);
|
||||
phy_read(phy, 0x1f, 0xa432);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0 | 0x20;
|
||||
phy_write(bit_mask[phy], 0x1f, 0xa432, pval);
|
||||
|
||||
// p0307.003e:0000 P000008.0700003e:0001
|
||||
// p0307.003e:0000 P000008.0700003e:0001
|
||||
// EEE avertisment 2 register MMMD 7.0x003e, set bit 0: 2.5G has EEE capability
|
||||
phy_modify(phy, PHY_MMD_AN, PHY_EEE_ADV2, 0x0000, 0x0001);
|
||||
phy_read(phy, 0x7, 0x3e);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0 | 0x1;
|
||||
phy_write(bit_mask[phy], 0x7, 0x3e, pval);
|
||||
delay(20);
|
||||
|
||||
// p031f.a442:043c P000008.1f00a442:0430
|
||||
// p031f.a442:043c P000008.1f00a442:0430
|
||||
// Unknown, but clear bits 2/3
|
||||
phy_modify(phy, PHY_MMD31, 0xa442, 0x000c, 0x0000);
|
||||
phy_read(phy, 0x1f, 0xa442);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0 & 0xf3;
|
||||
phy_write(bit_mask[phy], 0x1f, 0xa442, pval);
|
||||
delay(20);
|
||||
|
||||
// P000100.1e0075b5:e084
|
||||
phy_write(phy, PHY_MMD30, 0x75b5, 0xe084);
|
||||
phy_write(bit_mask[phy], 0x1e, 0x75b5, 0xe084);
|
||||
delay(20);
|
||||
|
||||
// p031e.75b2:0000 P000008.1e0075b2:0060
|
||||
// p031e.75b2:0000 P000008.1e0075b2:0060
|
||||
// set bits 5/6
|
||||
phy_modify(phy, PHY_MMD30, 0x75b2, 0x0000, 0x0060);
|
||||
phy_read(phy, 0x1e, 0x75b2);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0 | 0x60;
|
||||
phy_write(bit_mask[phy], 0x1e, 0x75b2, pval);
|
||||
delay(20);
|
||||
|
||||
// p081f.d040:ffff P000100.1f00d040:feff
|
||||
// p081f.d040:ffff P000100.1f00d040:feff
|
||||
// LCR6 (LED Control Register 6, MMD 31.D040), set bits 8/9 to 0b10
|
||||
phy_modify(phy, PHY_MMD30, 0xd040, 0x0300, 0x0200);
|
||||
phy_read(phy, 0x1e, 0xd040);
|
||||
pval = (SFR_DATA_8 & 0xfc) | 0x02;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0;
|
||||
phy_write(bit_mask[phy], 0x1e, 0xd040, pval);
|
||||
delay(20);
|
||||
|
||||
// p081f.a400:ffff P000100.1f00a400:ffff, then: p081f.a400:ffff P000100.1f00a400:bfff
|
||||
// p031f.a400:1040 P000008.1f00a400:5040, then: p031f.a400:5040 P000008.1f00a400:1040
|
||||
// p081f.a400:ffff P000100.1f00a400:ffff, then: p081f.a400:ffff P000100.1f00a400:bfff
|
||||
// p031f.a400:1040 P000008.1f00a400:5040, then: p031f.a400:5040 P000008.1f00a400:1040
|
||||
// FEDCR (Fast Ethernet Duplex Control Register, MMD 31.0xA400)
|
||||
// Set bit 14, sleep, then clear again, according to the datasheet these bits are reserved
|
||||
phy_modify(phy, PHY_MMD31, PHY_MMD31_FEDCR, 0x0000, 0x4000);
|
||||
|
||||
phy_read(phy, 0x1f, 0xa400);
|
||||
pval = SFR_DATA_8 | 0x40;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0;
|
||||
phy_write(bit_mask[phy], 0x1f, 0xa400, pval);
|
||||
delay(20);
|
||||
|
||||
phy_modify(phy, PHY_MMD31, PHY_MMD31_FEDCR, 0x4000, 0x0000);
|
||||
phy_read(phy, 0x1f, 0xa400);
|
||||
pval = SFR_DATA_8 & 0xbf;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0;
|
||||
phy_write(bit_mask[phy], 0x1f, 0xa400, pval);
|
||||
delay(20);
|
||||
|
||||
print_string("\r\n phy config done\r\n");
|
||||
@@ -144,36 +190,29 @@ void phy_config(uint8_t phy) __banked
|
||||
|
||||
void phy_config_8224(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
print_string("\r\nphy_config_8224 called\r\nRTL8224 ID: ");
|
||||
|
||||
// Print RTL8224 chip id
|
||||
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID + 1);
|
||||
print_short(SFR_DATA_U16);
|
||||
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID);
|
||||
print_byte(SFR_DATA_U16 >> 8);
|
||||
print_byte(SFR_DATA_U16);
|
||||
write_char('\n');
|
||||
|
||||
// p001e.7b20:0bff R02f8-00000bff R02f4-00000bed P000001.1e007b20:0bed
|
||||
phy_read(RTL8224_PHY_ID, PHY_MMD30, 0x7b20);
|
||||
pval = SFR_DATA_U16;
|
||||
|
||||
uint16_t pval;
|
||||
print_string("\r\nphy_config_8224 called\r\n");
|
||||
phy_read(0, 0x1e, 0x7b20);
|
||||
pval = SFR_DATA_8;
|
||||
pval <<= 8;
|
||||
pval |= SFR_DATA_0;
|
||||
|
||||
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
|
||||
pval &= 0x0fe0;
|
||||
pval |= 0x000d;
|
||||
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
|
||||
|
||||
phy_write(RTL8224_PHY_ID, PHY_MMD30, 0x7b20, pval);
|
||||
phy_write(0x01, 0x1e, 0x7b20, pval);
|
||||
|
||||
uint8_t i = 0;
|
||||
while (rtl8224_sds0_setttings[i]) {
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_WRITE_DATA, rtl8224_sds0_setttings[i]);
|
||||
while (rtl8224_ca[i]) {
|
||||
phy_write(0x1, 0x1e, 0x400, rtl8224_ca[i]);
|
||||
i++;
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, rtl8224_sds0_setttings[i]);
|
||||
phy_write(0x1, 0x1e, 0x3f8, rtl8224_ca[i]);
|
||||
i++;
|
||||
do {
|
||||
rtl8224_read_reg_u16(0x3f8);
|
||||
phy_read(0, 0x1e, 0x3f8);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
}
|
||||
|
||||
@@ -182,331 +221,48 @@ void phy_config_8224(void) __banked
|
||||
|
||||
|
||||
/*
|
||||
* Set Speed of a PHY
|
||||
* Set Speed, duplex and flow control mode of a PHY
|
||||
* See e.g. RTL8221B datasheet
|
||||
* duplex: 0: half, 1: full, 2: both
|
||||
*/
|
||||
void phy_set_speed(uint8_t port, uint8_t speed, uint8_t duplex) __banked
|
||||
void phy_set_mode(uint8_t port, uint8_t speed, uint8_t flow_control, uint8_t duplex) __banked
|
||||
{
|
||||
uint16_t v;
|
||||
phy_read(port, PHY_MMD31, 0xa610);
|
||||
v = SFR_DATA_U16;
|
||||
phy_read(port, 0x1f, 0xa610);
|
||||
v = (((uint16_t)SFR_DATA_8) << 8) | SFR_DATA_0;
|
||||
if (speed == PHY_OFF) {
|
||||
phy_write(port, PHY_MMD31, 0xa610, v | 0x0800);
|
||||
phy_write(bit_mask[port], 0x1f, 0xa610, v | 0x0800);
|
||||
return;
|
||||
}
|
||||
// Port is on, make sure of it:
|
||||
if (v & 0x0800)
|
||||
phy_write(port, PHY_MMD31, 0xa610, v & 0xf7ff);
|
||||
phy_write(bit_mask[port], 0x1f, 0xa610, v & 0xf7ff);
|
||||
|
||||
if (speed == PHY_SPEED_AUTO) {
|
||||
// AN Advertisement Register (MMD 7.0x0010)
|
||||
// bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x15e1);
|
||||
phy_write(bit_mask[port], 0x07, 0x10, 0x1001); // bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
// bit 14: SLAVE, bit 13: Multi-Port device, bit 8: 2.5GBit available, 1: LD
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
|
||||
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
|
||||
phy_modify(port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0200); // Loop timing enabled
|
||||
phy_write(port, PHY_MMD31, PHY_ANEG_CTRL, 0x3200); // Restart AN
|
||||
phy_write(bit_mask[port], 0x07, 0x20, 0x6081); // bit 14: SLAVE, bit 13: Multi-Port device, bit 8: 2.5GBit available, 1: LD Loop timin enableed
|
||||
phy_write(bit_mask[port], 0x07, 0x00, 0x3200); // Restart AN
|
||||
} else {
|
||||
// AN Control Register (MMD 7.0x0000)
|
||||
phy_write(port, PHY_MMD31, PHY_ANEG_CTRL, 0x2000); // Clear bit 12: No Autoneg, Set Extended Pages (bit 13)
|
||||
if (speed == PHY_SPEED_10M) {
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6001);
|
||||
if (!duplex)
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1421);
|
||||
else if (duplex == 1)
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1441);
|
||||
else
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1461);
|
||||
phy_modify(port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
||||
} else if (speed == PHY_SPEED_100M) {
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6001);
|
||||
if (!duplex)
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1481);
|
||||
if (duplex == 1)
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1501);
|
||||
else
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1581);
|
||||
phy_modify(port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
||||
} else {
|
||||
// AN Advertisement Register (MMD 7.0x0010)
|
||||
// bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1001);
|
||||
if (speed == PHY_SPEED_1G) {
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
// bit 14: SLAVE, bit 13: Multi-Port device, 1: LD Loop timin enableed
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6001);
|
||||
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
|
||||
phy_modify(port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0200);
|
||||
} else if (speed == PHY_SPEED_2G5) {
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
// bit 14: SLAVE, bit 13: Multi-Port device, bit 8: 2.5GBit available, 1: LD Loop timin enableed
|
||||
phy_write(port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
|
||||
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
|
||||
phy_modify(port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
||||
}
|
||||
phy_write(bit_mask[port], 0x07, 0x00, 0x2000); // Clear bit 12: No Autoneg, Set Extended Pages (bit 13)
|
||||
// AN Advertisement Register (MMD 7.0x0010)
|
||||
phy_write(bit_mask[port], 0x07, 0x10, 0x1001); // bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
||||
if (speed == PHY_SPEED_1G) {
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
phy_write(bit_mask[port], 0x07, 0x20, 0x6001); // bit 14: SLAVE, bit 13: Multi-Port device, 1: LD Loop timin enableed
|
||||
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
|
||||
phy_read(port, 0x1f, 0xa412);
|
||||
v = (((uint16_t)SFR_DATA_8) << 8) | SFR_DATA_0;
|
||||
phy_write(bit_mask[port], 0x1f, 0xa412, v | 0x0200);
|
||||
} else if (speed == PHY_SPEED_2G5) {
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
phy_write(bit_mask[port], 0x07, 0x20, 0x6081); // bit 14: SLAVE, bit 13: Multi-Port device, bit 8: 2.5GBit available, 1: LD Loop timin enableed
|
||||
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
|
||||
phy_read(port, 0x1f, 0xa412);
|
||||
v = (((uint16_t)SFR_DATA_8) << 8) | SFR_DATA_0;
|
||||
phy_write(bit_mask[port], 0x1f, 0xa412, v & 0xfdff);
|
||||
}
|
||||
phy_write(port, PHY_MMD31, PHY_ANEG_CTRL, 0x3000); // Enable AN
|
||||
phy_write(bit_mask[port], 0x07, 0x00, 0x3200); // Enable AN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void phy_set_duplex(uint8_t port, uint8_t fullduplex) __banked
|
||||
{
|
||||
uint16_t v;
|
||||
phy_read(port, PHY_MMD31, PHY_ANEG_CTRL);
|
||||
v = SFR_DATA_U16;
|
||||
if (!(v & 0x1000)) { // AN disabled, we are in forced mode
|
||||
phy_read(port, PHY_MMD31, PHY_MMD31_FEDCR);
|
||||
v = SFR_DATA_U16;
|
||||
if (fullduplex)
|
||||
v |= 0x0100;
|
||||
else
|
||||
v &= 0xfeff;
|
||||
phy_write(port, PHY_MMD31, PHY_MMD31_FEDCR, v);
|
||||
return;
|
||||
}
|
||||
// Disable AN
|
||||
phy_write(port, PHY_MMD31, PHY_ANEG_CTRL, 0x2000);
|
||||
phy_read(port, PHY_MMD_AN, PHY_ANEG_ADV);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & 0x0060) {
|
||||
if (fullduplex)
|
||||
phy_modify(port, PHY_MMD_AN, PHY_ANEG_ADV, 0xffbf, 0x0040);
|
||||
else
|
||||
phy_modify(port, PHY_MMD_AN, PHY_ANEG_ADV, 0xffdf, 0x0020);
|
||||
}
|
||||
if (v & 0x0180) {
|
||||
if (fullduplex)
|
||||
phy_modify(port, PHY_MMD_AN, PHY_ANEG_ADV, 0xfeff, 0x0100);
|
||||
else
|
||||
phy_modify(port, PHY_MMD_AN, PHY_ANEG_ADV, 0xff7f, 0x0080);
|
||||
}
|
||||
// Restart AN
|
||||
phy_write(port, PHY_MMD31, PHY_ANEG_CTRL, 0x3000);
|
||||
}
|
||||
|
||||
|
||||
void phy_show(uint8_t port) __banked
|
||||
{
|
||||
uint16_t v;
|
||||
|
||||
// The actual PHY speed is in a Realtek propriatary register
|
||||
print_string("\nLink speed: ");
|
||||
phy_read(port, PHY_MMD31, PHY_MMD31_PHYSR);
|
||||
v = SFR_DATA_U16;
|
||||
switch(((v & 0x0600) >> 7) | ((v & 0x0030) >> 4)) {
|
||||
case 0:
|
||||
print_string("10M");
|
||||
break;
|
||||
case 1:
|
||||
print_string("100M");
|
||||
break;
|
||||
case 2:
|
||||
print_string("1000M");
|
||||
break;
|
||||
case 3:
|
||||
print_string("500M");
|
||||
break;
|
||||
case 4:
|
||||
print_string("10G");
|
||||
break;
|
||||
case 5:
|
||||
print_string("2500M");
|
||||
break;
|
||||
case 6:
|
||||
print_string("5G");
|
||||
break;
|
||||
default:
|
||||
print_string("10M");
|
||||
}
|
||||
if (v & 0x8)
|
||||
print_string(" full duplex");
|
||||
else
|
||||
print_string(" half duplex");
|
||||
|
||||
phy_read(port, PHY_MMD31, PHY_ANEG_CTRL);
|
||||
v = SFR_DATA_U16;
|
||||
if (!(v & 0x1000)) { // AN disabled, we are in forced mode
|
||||
phy_read(port, PHY_MMD_PMAPMD, 0);
|
||||
v = SFR_DATA_U16;
|
||||
print_string("\nForced speed: "); print_short(v); write_char('\n');
|
||||
uint8_t s1 = ((v & 0x40) ? 0x2 : 0x0) | ((v & 0x2000) ? 0x1 : 0x0);
|
||||
uint8_t s2 = (v >> 2) & 0xf;
|
||||
switch(s1) {
|
||||
case 0:
|
||||
print_string("10M\n");
|
||||
break;
|
||||
case 1:
|
||||
print_string("100M\n");
|
||||
break;
|
||||
case 2:
|
||||
print_string("1000M\n");
|
||||
break;
|
||||
case 3:
|
||||
switch (s2) {
|
||||
case 0:
|
||||
print_string("10G\n");
|
||||
break;
|
||||
case 6:
|
||||
print_string("2500M\n");
|
||||
break;
|
||||
case 7:
|
||||
print_string("5G\n");
|
||||
break;
|
||||
default:
|
||||
print_string("Unknown\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print_string("Unknown\n");
|
||||
}
|
||||
phy_read(port, PHY_MMD31, PHY_MMD31_FEDCR);
|
||||
v = SFR_DATA_U16;
|
||||
print_string("Duplex: "); print_short(v); print_string(" enabled: ");
|
||||
if (v & 0x100)
|
||||
print_string("yes");
|
||||
else
|
||||
print_string("no");
|
||||
write_char('\n');
|
||||
|
||||
} else {
|
||||
print_string("\nAN enabled, advertising:");
|
||||
phy_read(port, PHY_MMD_AN, PHY_ANEG_ADV);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & 0x0020)
|
||||
print_string(" 10Base-Half");
|
||||
if (v & 0x0040)
|
||||
print_string(" 10Base-Full");
|
||||
if (v & 0x0080)
|
||||
print_string(" 100Base-Half");
|
||||
if (v & 0x0100)
|
||||
print_string(" 100Base-Full");
|
||||
phy_read(port, PHY_MMD31, PHY_MMD31_GBCR);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & 0x0200)
|
||||
print_string(" 1000Base-Full");
|
||||
phy_read(port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & 0x0080)
|
||||
print_string(" 2500BaseN-Full");
|
||||
}
|
||||
phy_read(port, PHY_MMD_AN, PHY_ANEG_LP_ABILITY);
|
||||
v = SFR_DATA_U16;
|
||||
print_string("\nLink Partner advertises:");
|
||||
if (v & 0x0020)
|
||||
print_string(" 10Base-Half");
|
||||
if (v & 0x0040)
|
||||
print_string(" 10Base-Full");
|
||||
if (v & 0x0080)
|
||||
print_string(" 100Base-Half");
|
||||
if (v & 0x0100)
|
||||
print_string(" 100Base-Full");
|
||||
phy_read(port, PHY_MMD31, PHY_MMD31_GANLPAR);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & 0x0400)
|
||||
print_string(" 1000Base-Half");
|
||||
if (v & 0x0800)
|
||||
print_string(" 1000Base-Full");
|
||||
phy_read(port, PHY_MMD_AN, PHY_ANEG_MGBASE_ADV);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & 0x0020)
|
||||
print_string(" 2500Base-Full");
|
||||
if (v & 0x0040)
|
||||
print_string(" 5000Base-Full");
|
||||
if (v & 0x0800)
|
||||
print_string(" 10GBase-Full");
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
void phy_reset(uint8_t port) __banked
|
||||
{
|
||||
uint16_t v;
|
||||
phy_read(port, PHY_MMD31, 0xa610);
|
||||
v = SFR_DATA_U16;
|
||||
// If PHY off, do nothing
|
||||
if (v & 0x0800)
|
||||
return;
|
||||
|
||||
// Disable PHY
|
||||
phy_write(port, PHY_MMD31, 0xa610, v | 0x0800);
|
||||
delay(2);
|
||||
// Re-enable PHY
|
||||
phy_write(port, PHY_MMD31, 0xa610, v & 0xf7ff);
|
||||
}
|
||||
|
||||
// Read RTL8224 register.
|
||||
// Registers names are the same as on the RTL837x.
|
||||
// Reading only reads the lower 16-bit part of the 32-bit register.
|
||||
// When also needing read the upper 16-bits, use register address + 1.
|
||||
// Readed values it return via sfr-data.
|
||||
void inline rtl8224_read_reg_u16(uint16_t reg) __banked
|
||||
{
|
||||
// void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg)
|
||||
// phy_read(RTL8224_PHY_ID, PHY_MMD30, reg);
|
||||
|
||||
SFR_SMI_REG_U16 = reg; // c2, c2
|
||||
|
||||
SFR_SMI_PHY = RTL8224_PHY_ID; // a5
|
||||
SFR_SMI_DEV = PHY_MMD30 << 3 | 2; // c4
|
||||
|
||||
SFR_EXEC_GO = SFR_EXEC_READ_SMI;
|
||||
do {
|
||||
} while (SFR_EXEC_STATUS != 0);
|
||||
}
|
||||
|
||||
// Write RTL8224 register.
|
||||
// Registers names are the same as on the RTL837x.
|
||||
// Writing only the lower 16-bit part of the 32-bit register.
|
||||
// When also needing to write the upper 16-bits, use register address + 1.
|
||||
void inline rtl8224_write_reg_u16(uint16_t reg, uint16_t val) __banked
|
||||
{
|
||||
SFR_DATA_U16 = val; // SFR_A6, SFR_A7
|
||||
SFR_SMI_REG_U16 = reg; // SFR_C2, SFR_C3
|
||||
|
||||
//void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t v)
|
||||
// phy_write(RTL8224_PHY_ID, PHY_MMD30, reg, val);
|
||||
|
||||
uint16_t phy_mask = bit_mask[RTL8224_PHY_ID];
|
||||
|
||||
SFR_SMI_PHYMASK = phy_mask; // SFR_C5
|
||||
SFR_SMI_DEV = (phy_mask >> 8) | PHY_MMD30 << 3 | 2; // SFR_C4: bit 2 can also be set for some option
|
||||
SFR_EXEC_GO = SFR_EXEC_WRITE_SMI;
|
||||
do {
|
||||
} while (SFR_EXEC_STATUS != 0);
|
||||
}
|
||||
|
||||
// // Modify RTL8224 register.
|
||||
// // Registers names are the same as on the RTL837x.
|
||||
// // Modifies only the lower 16-bit part of the 32-bit register.
|
||||
// // When also needing to modifie the upper 16-bits, use register address + 1.
|
||||
// void rtl8224_modify_reg_u16(uint16_t reg, uint16_t clear, uint16_t set) __banked
|
||||
// {
|
||||
// phy_read(RTL8224_PHY_ID, PHY_MMD30, reg);
|
||||
// uint16_t pval = SFR_DATA_U16;
|
||||
// pval &= ~(clear);
|
||||
// pval |= set;
|
||||
// phy_write(RTL8224_PHY_ID, PHY_MMD30, reg, pval);
|
||||
// }
|
||||
|
||||
|
||||
// Write to the RTL8224 SDS registers.
|
||||
void rtl8224_sds_write(uint16_t sds_cmd, uint16_t value) __banked
|
||||
{
|
||||
// Wait for command bit is cleared
|
||||
do {
|
||||
rtl8224_read_reg_u16(RTL837X_SDS_INDACS_CMD);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_WRITE_DATA, value);
|
||||
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, sds_cmd);
|
||||
|
||||
// Wait for command bit is cleared
|
||||
do {
|
||||
rtl8224_read_reg_u16(RTL837X_SDS_INDACS_CMD);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
}
|
||||
|
||||
@@ -1,31 +1,14 @@
|
||||
#ifndef _RTL837X_PHY_H_
|
||||
#define _RTL837X_PHY_H_
|
||||
|
||||
#define PHY_SPEED_10M 0x2
|
||||
#define PHY_SPEED_100M 0x3
|
||||
#define PHY_SPEED_1G 0x4
|
||||
#define PHY_SPEED_2G5 0x5
|
||||
#define PHY_SPEED_5G 0x6
|
||||
#define PHY_SPEED_10G 0x7
|
||||
#define PHY_SPEED_AUTO 0x10
|
||||
#define PHY_SPEED_AUTO 0x1
|
||||
#define PHY_SPEED_1G 0x2
|
||||
#define PHY_SPEED_2G5 0x3
|
||||
#define PHY_OFF 0xff
|
||||
|
||||
void rtl8224_phy_enable(void) __banked;
|
||||
void phy_config(uint8_t phy) __banked;
|
||||
void phy_config_8224(void) __banked;
|
||||
void phy_set_speed(uint8_t port, uint8_t speed, uint8_t duplex) __banked;
|
||||
void phy_set_duplex(uint8_t port, uint8_t fullduplex) __banked;
|
||||
void phy_show(uint8_t port) __banked;
|
||||
void phy_reset(uint8_t port) __banked;
|
||||
void rtl8224_read_reg_u16(uint16_t reg) __banked;
|
||||
void rtl8224_write_reg_u16(uint16_t reg, uint16_t val) __banked;
|
||||
void rtl8224_sds_write(uint16_t sds_cmd, uint16_t val) __banked;
|
||||
|
||||
#define RTL8224_SDS_WRITE(sds_id, page, reg, v) uint16_t _sdscmd = (uint16_t)(sds_id & 0x01) | (1 << 14) | (1 << 15); \
|
||||
_sdscmd |= (page & 0x3F) << 1; \
|
||||
_sdscmd |= ((uint16_t)(reg & 0x1f)) << 7; \
|
||||
print_string("CMD: "); print_short(_sdscmd); \
|
||||
write_char('-'); print_short(v); \
|
||||
rtl8224_sds_write(_sdscmd, v);
|
||||
void phy_set_mode(uint8_t port, uint8_t speed, uint8_t flow_control, uint8_t duplex) __banked;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
#include "rtl837x_pins.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
|
||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) {
|
||||
switch (sda_pin) {
|
||||
case GPIO47_I2C_SDA0:
|
||||
return 0;
|
||||
case GPIO49_I2C_SDA1:
|
||||
return 1;
|
||||
case GPIO51_I2C_SDA2_UART1_RX:
|
||||
return 2;
|
||||
case GPIO41_I2C_SDA3_MDIO1:
|
||||
return 3;
|
||||
case GPIO39_I2C_SDA4:
|
||||
return 4;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) {
|
||||
switch (scl_pin) {
|
||||
case GPIO46_I2C_SCL0:
|
||||
return 0;
|
||||
case GPIO48_I2C_SCL1:
|
||||
return 1;
|
||||
case GPIO50_I2C_SCL2_UART1_TX:
|
||||
return 2;
|
||||
case GPIO40_I2C_SCL3_MDC1:
|
||||
return 3;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns RTL837X_REG_GPIO_XX_OUTPUT register address */
|
||||
static uint16_t gpio_output_reg(uint8_t pin) {
|
||||
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
|
||||
}
|
||||
|
||||
/* Returns RTL837X_REG_GPIO_XX_DIRECTION register address */
|
||||
static uint16_t gpio_direction_reg(uint8_t pin) {
|
||||
return pin < 32 ? RTL837X_REG_GPIO_00_31_DIRECTION : RTL837X_REG_GPIO_32_63_DIRECTION;
|
||||
}
|
||||
|
||||
|
||||
/* Enable GPIO functions for pin */
|
||||
static void gpio_mux_setup(uint8_t pin)
|
||||
{
|
||||
// Some GPIOs require setting MUX registers to enable GPIO
|
||||
switch (pin) {
|
||||
case GPIO10_LED10:
|
||||
reg_bit_clear(RTL837X_PIN_MUX_0, 10);
|
||||
break;
|
||||
case GPIO30_ACL_BIT3_EN:
|
||||
reg_bit_clear(RTL837X_PIN_MUX_2, 3);
|
||||
break;
|
||||
case GPIO36_PWM_OUT:
|
||||
reg_bit_set(RTL837X_PIN_MUX_1, 30);
|
||||
break;
|
||||
case GPIO37:
|
||||
case GPIO38:
|
||||
// Intentionally empty, always GPIO
|
||||
break;
|
||||
case GPIO46_I2C_SCL0:
|
||||
// Bit 7-8 0b00 -> GPIO
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
sfr_mask_data(0, 0x80, 0x00);
|
||||
sfr_mask_data(1, 0x01, 0x00);
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
break;
|
||||
case GPIO50_I2C_SCL2_UART1_TX:
|
||||
// Bit 15-16 0b00 -> GPIO
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
sfr_mask_data(1, 0x80, 0x00);
|
||||
sfr_mask_data(2, 0x01, 0x00);
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
break;
|
||||
case GPIO51_I2C_SDA2_UART1_RX:
|
||||
// Bit 17-18 0b00 -> GPIO
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
sfr_mask_data(2, 0x06, 0x00);
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
break;
|
||||
case GPIO54_ACL_BIT2_EN:
|
||||
reg_bit_clear(RTL837X_PIN_MUX_2, 2);
|
||||
break;
|
||||
case GPIO_NA:
|
||||
print_string("Attemped to assign GPIO function to N/A pin!");
|
||||
break;
|
||||
default:
|
||||
print_string("GPIO MUX setup not implemented for pin="); print_byte(pin); print_string("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_input_setup(uint8_t pin) {
|
||||
if (pin == GPIO_NA) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_mux_setup(pin);
|
||||
reg_bit_clear(gpio_direction_reg(pin), (pin % 32));
|
||||
}
|
||||
|
||||
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) {
|
||||
if (pin == GPIO_NA) {
|
||||
return;
|
||||
}
|
||||
gpio_mux_setup(pin);
|
||||
|
||||
// We need to setup value before enabling output on PIN
|
||||
if (initial_val) {
|
||||
reg_bit_set(gpio_output_reg(pin), (pin % 32));
|
||||
} else {
|
||||
reg_bit_clear(gpio_output_reg(pin), (pin % 32));
|
||||
}
|
||||
|
||||
reg_bit_set(gpio_direction_reg(pin), (pin % 32));
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#ifndef _RTL837X_PINS_H_
|
||||
#define _RTL837X_PINS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define GPIO0_LED0 0
|
||||
#define GPIO1_LED1 1
|
||||
#define GPIO2_LED2 2
|
||||
#define GPIO3_LED3 3
|
||||
#define GPIO4_LED4 4
|
||||
#define GPIO5_LED5 5
|
||||
#define GPIO6_LED6 6
|
||||
#define GPIO7_LED7 7
|
||||
#define GPIO8_LED8 8
|
||||
#define GPIO9_LED9 9
|
||||
#define GPIO10_LED10 10
|
||||
#define GPIO11_LED11 11
|
||||
#define GPIO12_LED12 12
|
||||
#define GPIO13_LED13 13
|
||||
#define GPIO14_LED14 14
|
||||
#define GPIO15_LED15 15
|
||||
#define GPIO16_LED16 16
|
||||
#define GPIO17_LED17 17
|
||||
#define GPIO18_LED18 18
|
||||
#define GPIO19_LED19 19
|
||||
#define GPIO20_LED20 20
|
||||
#define GPIO21_LED21 21
|
||||
#define GPIO22_LED22 22
|
||||
#define GPIO23_LED23 23
|
||||
#define GPIO24_LED24 24
|
||||
#define GPIO25_LED25 25
|
||||
#define GPIO26_LED26 26
|
||||
#define GPIO27_LED27 27
|
||||
#define GPIO28_SYS_LED 28
|
||||
#define GPIO29_GLB_RLDP_LED_EN 29
|
||||
#define GPIO30_ACL_BIT3_EN 30
|
||||
#define GPIO31_UART0_TX 31
|
||||
#define GPIO32_UART0_RX 32
|
||||
#define GPIO33_INT 33
|
||||
#define GPIO34_MDC0 34
|
||||
#define GPIO35_MDIO0 35
|
||||
#define GPIO36_PWM_OUT 36
|
||||
#define GPIO37 37
|
||||
#define GPIO38 38
|
||||
#define GPIO39_I2C_SDA4 39
|
||||
#define GPIO40_I2C_SCL3_MDC1 40
|
||||
#define GPIO41_I2C_SDA3_MDIO1 41
|
||||
#define GPIO42_SPI 42
|
||||
#define GPIO43_SPI 43
|
||||
#define GPIO44_SPI 44
|
||||
#define GPIO45_SPI 45
|
||||
#define GPIO46_I2C_SCL0 46
|
||||
#define GPIO47_I2C_SDA0 47
|
||||
#define GPIO48_I2C_SCL1 48
|
||||
#define GPIO49_I2C_SDA1 49
|
||||
#define GPIO50_I2C_SCL2_UART1_TX 50
|
||||
#define GPIO51_I2C_SDA2_UART1_RX 51
|
||||
#define GPIO52_ACL_BIT0_EN 52
|
||||
#define GPIO53_ACL_BIT1_EN 53
|
||||
#define GPIO54_ACL_BIT2_EN 54
|
||||
#define GPIO55_PTP_CLK_IN 55
|
||||
#define GPIO56_PTP_CLK_OUT 56
|
||||
#define GPIO57_PTP_TOD_OUT 57
|
||||
#define GPIO58_PTP_PPS_OUT 58
|
||||
#define GPIO59_PTP_TOD_IN 59
|
||||
#define GPIO60_PTP_PPS_IN 60
|
||||
#define GPIO61_SYNCELOCK0 61
|
||||
#define GPIO62_SYNCELOCK1 62
|
||||
#define GPIO63_MDIO 63
|
||||
|
||||
/* Not available GPIO */
|
||||
#define GPIO_NA 0xFF
|
||||
|
||||
/* Convert SDA PIN GPIO to I2C bus number */
|
||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin);
|
||||
|
||||
/* Convert SCL PIN GPIO to I2C bus number */
|
||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin);
|
||||
|
||||
/*
|
||||
* Setup a GPIO pin as input
|
||||
* pin: GPIO pin number 0-63
|
||||
*/
|
||||
void gpio_input_setup(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Setup a GPIO pin as output
|
||||
* pin: GPIO pin number 0-63
|
||||
* initial_val: 1 for bit set in RTL837X_REG_GPIO_xx_OUTPUT, 0 for bit not set
|
||||
*/
|
||||
void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val);
|
||||
|
||||
#endif
|
||||
@@ -10,24 +10,22 @@
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "phy.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
extern __code uint8_t * __code hex;
|
||||
|
||||
extern __code uint16_t bit_mask[16];
|
||||
extern __code struct machine machine;
|
||||
extern __xdata uint8_t minPort;
|
||||
extern __xdata uint8_t maxPort;
|
||||
extern __xdata uint8_t nSFPPorts;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata uint16_t vlan_ptr;
|
||||
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t cpuPort;
|
||||
|
||||
extern __xdata uint8_t isRTL8373;
|
||||
|
||||
__xdata uint32_t l2_head;
|
||||
|
||||
|
||||
void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked
|
||||
{
|
||||
print_string("\nport_mirror_set called \n");
|
||||
@@ -85,41 +83,6 @@ void vlan_delete(uint16_t vlan) __banked
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reads VLAN information from VLAN table
|
||||
* Returns data in sfr_data
|
||||
*/
|
||||
int8_t vlan_get(register uint16_t vlan) __banked
|
||||
{
|
||||
if (vlan >= 0x3ff) // VLAN 4095 is special
|
||||
return -1;
|
||||
|
||||
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_EXECUTE);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_A);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
__xdata uint16_t vlan_name(register uint16_t vlan) __banked
|
||||
{
|
||||
__xdata int16_t i = 0;
|
||||
__xdata uint8_t begin = 1;
|
||||
while (vlan_names[i]) {
|
||||
if (begin && vlan_names[i] == hex[(vlan >> 8) & 0xf] && vlan_names[i + 1] == hex[(vlan >> 4) & 0xf] && vlan_names[i + 2] == hex[vlan & 0xf])
|
||||
break;
|
||||
begin = vlan_names[i++] == ' ' ? 1 : 0;
|
||||
}
|
||||
if (vlan_names[i])
|
||||
return i + 3;
|
||||
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A member that is not tagged, is untagged
|
||||
*/
|
||||
@@ -134,7 +97,7 @@ void vlan_create(register uint16_t vlan, register uint16_t members, register uin
|
||||
|
||||
uint16_t a = (~members) ^ tagged ^ members;
|
||||
// On RTL8372, port-bits 0-2 must be 0, although they are not members
|
||||
if (!machine_detected.isRTL8373) {
|
||||
if (!isRTL8373) {
|
||||
a &= 0x1f8;
|
||||
tagged &= 0x3f8;
|
||||
}
|
||||
@@ -160,20 +123,19 @@ void vlan_setup(void) __banked
|
||||
{
|
||||
print_string("\nvlan_setup called \n");
|
||||
|
||||
// No VLAN names set up so far
|
||||
vlan_ptr = 0;
|
||||
vlan_names[0] = 0;
|
||||
|
||||
// Initialize VLAN table for VLAN 1, by disabling that entry
|
||||
REG_SET(RTL837x_TBL_DATA_IN_A, machine_detected.isRTL8373? 0x0007ffff : 0x0007e3f8);
|
||||
|
||||
if (isRTL8373) {
|
||||
REG_SET(RTL837x_TBL_DATA_IN_A, 0x0007ffff);
|
||||
} else {
|
||||
REG_SET(RTL837x_TBL_DATA_IN_A, 0x0007e3f8);
|
||||
}
|
||||
REG_SET(RTL837X_TBL_CTRL, 0x00010303);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
|
||||
// Set PVID 1 for every port. TODO: Skip unused ports!
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port + 1; i++) { // Do this also for the CPU port (+1)
|
||||
for (uint8_t i = minPort; i <= maxPort + 1; i++) { // Do this also for the CPU port (+1)
|
||||
uint16_t reg = RTL837x_PVID_BASE_REG + ((i >> 1) << 2);
|
||||
#ifdef DEBUG
|
||||
print_byte(i); write_char(':'); write_char(' '); print_short(reg); write_char('=');
|
||||
@@ -190,10 +152,10 @@ void vlan_setup(void) __banked
|
||||
write_char(' '); write_char('A'); write_char('>'); print_sfr_data();
|
||||
#endif
|
||||
|
||||
// EGRESS filtering for port: removal of additional VLAN tag (mode 0x3 for each port)
|
||||
reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, i << 1);
|
||||
reg_bit_clear(RTL837X_VLAN_PORT_EGR_TAG, (i << 1) + 1);
|
||||
reg_bit_set(RTL837X_VLAN_PORT_IGR_FLTR, i);
|
||||
// EGRESS filtering for port: removal of additional VLAN tag
|
||||
reg_bit_clear(0x6738, i << 1);
|
||||
reg_bit_clear(0x6738, (i << 1) + 1);
|
||||
reg_bit_set(0x4e18, i);
|
||||
|
||||
#ifdef DEBUG
|
||||
print_string("\n");
|
||||
@@ -204,18 +166,27 @@ void vlan_setup(void) __banked
|
||||
REG_SET(RTL837x_REG_INGRESS, 0); // No filtering for all ports
|
||||
|
||||
// Enable 4k VLAN
|
||||
REG_SET(RTL837X_VLAN_CTRL, VLAN_CVLAN_FILTER);
|
||||
REG_SET(RTL837X_VLAN_L2_LRN_DIS_0, 0);
|
||||
REG_SET(RTL837X_VLAN_L2_LRN_DIS_1, 0);
|
||||
REG_SET(0x4e14, 4);
|
||||
REG_SET(0x4e30, 0);
|
||||
REG_SET(0x4e34, 0);
|
||||
|
||||
// Enable VLAN 1: Ports 0-9, i.e. including the CPU port are untagged members
|
||||
REG_SET(RTL837x_TBL_DATA_IN_A, machine_detected.isRTL8373? 0x0207ffff : 0x0207e3f8); // 02: Entry valid, 7...: membership
|
||||
|
||||
if (isRTL8373) {
|
||||
REG_SET(RTL837x_TBL_DATA_IN_A, 0x0207ffff); // 02: Entry valid, 7ffff: membership
|
||||
} else {
|
||||
REG_SET(RTL837x_TBL_DATA_IN_A, 0x0207e3f8);
|
||||
}
|
||||
REG_SET(RTL837X_TBL_CTRL, 0x00010303); // Write VLAN 1
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
|
||||
// Configure trunking
|
||||
if (isRTL8373) {
|
||||
REG_SET(0x4f4c, 0x0000007e); // Removes RTL VLAN-Tags
|
||||
REG_SET(0x4f48, 0x0000007e); // Adds 802.1Q VLAN-Tags to tagged ports
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
print_string("\nvlan_setup, REG 0x6738: "); print_reg(0x6738);
|
||||
print_string("\nvlan_setup, REG 0x4e18: "); print_reg(0x4e18);
|
||||
@@ -230,23 +201,37 @@ void vlan_setup(void) __banked
|
||||
}
|
||||
|
||||
|
||||
void trunk_set(uint8_t group, uint16_t mask) __banked
|
||||
{
|
||||
if (group == 1) {
|
||||
REG_WRITE(RTL837x_TRUNK_CTRL_A, 0, 0, mask >> 8, mask);
|
||||
} else if (group == 2) {
|
||||
REG_WRITE(RTL837x_TRUNK_CTRL_B, 0, 0, mask >> 8, mask);
|
||||
} else {
|
||||
print_string("\nTrunk group must be 1 or 2\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Forget all dynamic L2 learned entries
|
||||
*/
|
||||
uint8_t port_l2_forget(void) __banked
|
||||
{
|
||||
print_string("\nport_l2_forget called\n");
|
||||
// Configure the entries to be flushed:
|
||||
// port-based (bits 0-1 are 0 and dynamic entries, bit 2 specifies dynamic entries
|
||||
REG_SET(RTL837x_L2_TBL_FLUSH_CNF, 0x0);
|
||||
// r53dc:00000000 R53dc-00000000 r53d4:000001ff r53d4:000001ff R53d4-000101ff r53d4:000001ff
|
||||
reg_read_m(0x53dc);
|
||||
if (sfr_data[0] || sfr_data[1] ||sfr_data[2] ||sfr_data[3]) {
|
||||
print_string("List busy\n");
|
||||
return 0xff;
|
||||
}
|
||||
REG_WRITE(0x53dc, sfr_data[0], sfr_data[1], sfr_data[2], sfr_data[3]);
|
||||
|
||||
// Flush L2 table for all ports by setting the ports and the flush-exec bit (bit 16)
|
||||
REG_SET(RTL837x_L2_TBL_FLUSH_CTRL, L2_TBL_FLUSH_EXEC | (machine_detected.isRTL8373 ? PMASK_9 : PMASK_6));
|
||||
|
||||
// Wait for flush completed
|
||||
reg_read_m(RTL837x_L2_TBL_CTRL);
|
||||
REG_WRITE(RTL837x_L2_TBL_CTRL, 0x00, 0x01, sfr_data[2], sfr_data[3]);
|
||||
do {
|
||||
reg_read_m(RTL837x_L2_TBL_FLUSH_CTRL);
|
||||
} while (sfr_data[1]);
|
||||
reg_read_m(RTL837x_L2_TBL_CTRL);
|
||||
} while (sfr_data[1] & 0x1);
|
||||
|
||||
print_string("port_l2_forget done\n");
|
||||
return 0;
|
||||
@@ -264,23 +249,14 @@ void port_l2_learned(void) __banked
|
||||
__xdata uint16_t first_entry = 0xffff; // Table does not have that many entries
|
||||
|
||||
while (1) {
|
||||
uint8_t port = 0;
|
||||
uint8_t port = 0, other = 0;
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1],sfr_data[2] | 0xc0, sfr_data[3]);
|
||||
|
||||
REG_WRITE(RTL837X_TBL_CTRL, (entry >> 8) & 0xf, entry, TBL_L2_UNICAST, TBL_EXECUTE);
|
||||
REG_WRITE(RTL837X_TBL_CTRL, entry >> 8, entry, TBL_L2_UNICAST, 0x1);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3];
|
||||
if (first_entry == 0xffff) {
|
||||
first_entry = entry;
|
||||
} else {
|
||||
if (first_entry == entry)
|
||||
break;
|
||||
}
|
||||
} while (sfr_data[3] & 0x1);
|
||||
|
||||
// MAC
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
@@ -288,6 +264,7 @@ void port_l2_learned(void) __banked
|
||||
print_byte(sfr_data[2]); write_char(':');
|
||||
print_byte(sfr_data[3]); write_char(':');
|
||||
port = (sfr_data[0] >> 6) & 0x3;
|
||||
other = sfr_data[0];
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_A);
|
||||
print_byte(sfr_data[0]); write_char(':');
|
||||
print_byte(sfr_data[1]); write_char(':');
|
||||
@@ -296,7 +273,7 @@ void port_l2_learned(void) __banked
|
||||
|
||||
// VLAN
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
print_short( (((uint16_t) (sfr_data[0] & 0x0f)) << 8) | sfr_data[1]); // VLAN
|
||||
print_short( ((uint16_t) (sfr_data[0] & 0x0f)) | sfr_data[1]); // VLAN
|
||||
|
||||
// type
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||
@@ -307,12 +284,22 @@ void port_l2_learned(void) __banked
|
||||
|
||||
port |= (sfr_data[3] & 0x3) << 2;
|
||||
if (port < 9)
|
||||
write_char(machine.log_to_phys_port[port] + '0');
|
||||
write_char('1' + port);
|
||||
else
|
||||
print_string("CPU");
|
||||
print_string("10");
|
||||
}
|
||||
|
||||
entry++;
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3] + 1;
|
||||
if (first_entry == 0xffff) {
|
||||
first_entry = entry;
|
||||
} else {
|
||||
if (first_entry == entry)
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
write_char(' '); print_sfr_data();
|
||||
write_char(' '); print_byte(other);
|
||||
#endif
|
||||
print_string("\n");
|
||||
}
|
||||
}
|
||||
@@ -321,23 +308,27 @@ void port_l2_learned(void) __banked
|
||||
/*
|
||||
* Basic L2 configuration such as time to forget an entry
|
||||
*/
|
||||
void port_l2_setup(void) __banked
|
||||
void port_l2_setup() __banked
|
||||
{
|
||||
print_string("\nport_l2_setup called\n");
|
||||
|
||||
port_l2_forget();
|
||||
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
// Limit the number of automatically learned MAC-Entries per port to 0x1040
|
||||
uint16_t reg = RTL837X_L2_LRN_PORT_CONSTRAINT + (i << 2);
|
||||
REG_SET(0x53dc, 0x00000000);
|
||||
if(isRTL8373) {
|
||||
REG_SET(0x53d4, 0x000101ff);
|
||||
} else {
|
||||
REG_SET(0x53d4, 0x000001f8);
|
||||
}
|
||||
for (uint8_t i = minPort; i <= maxPort; i++) {
|
||||
uint16_t reg = 0x5384 + (i << 2);
|
||||
REG_SET(reg, 0x00001040);
|
||||
|
||||
// All ports may communicate with each other and CPU-Port
|
||||
reg = RTL837X_PORT_ISOLATION_BASE + (i << 2);
|
||||
REG_SET(reg, PMASK_CPU | (machine_detected.isRTL8373? PMASK_9 : PMASK_6));
|
||||
reg = 0x50c0 + (i << 2);
|
||||
if(isRTL8373) {
|
||||
REG_SET(reg, 0x3ff);
|
||||
} else {
|
||||
REG_SET(reg, 0x3f8);
|
||||
}
|
||||
}
|
||||
// When maximim entries learned, then simply flood the packet
|
||||
reg_bit_set(RTL837X_L2_LRN_PORT_CONSTRT_ACT, 0);
|
||||
reg_bit_set(0x4f80, 0);
|
||||
|
||||
print_string("\nport_l2_setup done\n");
|
||||
}
|
||||
@@ -346,228 +337,78 @@ void port_l2_setup(void) __banked
|
||||
void port_stats_print(void) __banked
|
||||
{
|
||||
print_string("\n Port\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\n");
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
write_char('0' + machine.log_to_phys_port[i]); write_char('\t');
|
||||
|
||||
if (!machine.is_sfp[i]) {
|
||||
phy_read(i, PHY_MMD31, 0xa610);
|
||||
for (uint8_t i = minPort; i <= maxPort; i++) {
|
||||
write_char('1' + i); write_char('\t');
|
||||
phy_read(i, 0x1f, 0xa610); // p001f.a610:2058
|
||||
if (i <= maxPort - nSFPPorts) {
|
||||
if (SFR_DATA_8 == 0x20)
|
||||
print_string("On\t");
|
||||
else
|
||||
print_string("Off\t");
|
||||
} else { // An SFP Module
|
||||
if (!gpio_pin_test(machine.sfp_port[machine.is_sfp[i]-1].pin_detect)) {
|
||||
print_string("SFP IN\t");
|
||||
reg_read_m(RTL837X_REG_LINKS);
|
||||
uint8_t b = sfr_data[3 - (i >> 1)];
|
||||
b = (i & 1) ? b >> 4 : b & 0xf;
|
||||
switch (b) {
|
||||
case 0:
|
||||
print_string("Down\t");
|
||||
break;
|
||||
case 1:
|
||||
print_string("100M\t");
|
||||
break;
|
||||
case 2:
|
||||
print_string("1000M\t");
|
||||
break;
|
||||
case 5:
|
||||
print_string("2.5G\t");
|
||||
break;
|
||||
default:
|
||||
print_string("Up\t");
|
||||
break;
|
||||
}
|
||||
} else { // An SFP Module TODO: This is for 1 module devices
|
||||
reg_read_m(RTL837X_REG_GPIO_B);
|
||||
if (!(sfr_data[0] & 0x40)) {
|
||||
print_string("SFP OK\t");
|
||||
} else {
|
||||
print_string("NO SFP\t");
|
||||
}
|
||||
reg_read_m(RTL837X_REG_GPIO_C);
|
||||
if (sfr_data[3] & 0x20) {
|
||||
print_string("Down\t");
|
||||
} else {
|
||||
uint8_t rate = sfp_read_reg(0, 12);
|
||||
if (rate == 0xd)
|
||||
print_string("1000BX\t");
|
||||
else if (rate == 0x1f)
|
||||
print_string("2500G\t");
|
||||
else if (rate > 0x65 && rate < 0x70)
|
||||
print_string("10G\t");
|
||||
else
|
||||
print_string("Up\t");
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 8)
|
||||
reg_read_m(RTL837X_REG_LINKS);
|
||||
else
|
||||
reg_read_m(RTL837X_REG_LINKS_89);
|
||||
uint8_t b = sfr_data[3 - ((i & 7) >> 1)];
|
||||
b = (i & 1) ? b >> 4 : b & 0xf;
|
||||
switch (b) {
|
||||
case 0:
|
||||
print_string("Down\t");
|
||||
break;
|
||||
case 1:
|
||||
print_string("100M\t");
|
||||
break;
|
||||
case 2:
|
||||
print_string("1000M\t");
|
||||
break;
|
||||
case 4:
|
||||
print_string("10G\t");
|
||||
break;
|
||||
case 5:
|
||||
print_string("2.5G\t");
|
||||
break;
|
||||
default:
|
||||
print_string("Up\t");
|
||||
break;
|
||||
}
|
||||
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
||||
REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, 0x05, 0xe0 | (i << 1) | 1);
|
||||
do {
|
||||
reg_read_m(RTL837X_STAT_GET);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
// FIXME: Ignore HIGHER part of 64 bit value for now
|
||||
print_reg(RTL837X_STAT_V_LOW); write_char('\t');
|
||||
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, 0x06, (i << 1) | 1);
|
||||
do {
|
||||
reg_read_m(RTL837X_STAT_GET);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
print_reg(RTL837X_STAT_V_LOW); write_char('\t');
|
||||
|
||||
STAT_GET(STAT_COUNTER_RX_PKTS, i);
|
||||
REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, 0x05, 0xc0 | (i << 1) | 1);
|
||||
do {
|
||||
reg_read_m(RTL837X_STAT_GET);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
print_reg(RTL837X_STAT_V_LOW); write_char('\t');
|
||||
REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, 0x06, (i << 1) | 1);
|
||||
do {
|
||||
reg_read_m(RTL837X_STAT_GET);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
print_reg(RTL837X_STAT_V_LOW); write_char('\t');
|
||||
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
print_reg(RTL837X_STAT_V_HIGH); write_char('\t');
|
||||
print_string("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void port_isolate(register uint8_t port, __xdata uint16_t pmask)
|
||||
{
|
||||
if (port <= machine.max_port)
|
||||
REG_SET(RTL837X_PORT_ISOLATION_BASE + (port << 2), pmask);
|
||||
}
|
||||
|
||||
|
||||
uint16_t port_isolation_get(register uint8_t port)
|
||||
{
|
||||
if (port > machine.max_port)
|
||||
return 0;
|
||||
|
||||
reg_read_m(RTL837X_PORT_ISOLATION_BASE + (port << 2));
|
||||
return ((uint16_t)sfr_data[2]) << 8 | sfr_data[3];
|
||||
}
|
||||
|
||||
|
||||
void port_eee_enable(uint8_t port) __banked
|
||||
{
|
||||
if (machine.is_sfp[port])
|
||||
return;
|
||||
|
||||
REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100 | EEE_1000 | EEE_2G5);
|
||||
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
|
||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
|
||||
// Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
|
||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, PHY_EEE_BIT_2G5);
|
||||
phy_reset(port);
|
||||
}
|
||||
|
||||
|
||||
void port_eee_disable(uint8_t port) __banked
|
||||
{
|
||||
if (machine.is_sfp[port])
|
||||
return;
|
||||
|
||||
print_string("EEE off for "); print_byte(port); write_char('\n');
|
||||
REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), 0);
|
||||
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
|
||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
|
||||
// Disable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
|
||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, 0);
|
||||
phy_reset(port);
|
||||
}
|
||||
|
||||
|
||||
void port_eee_status(uint8_t port) __banked
|
||||
{
|
||||
print_string("Port: "); write_char('0' + machine.log_to_phys_port[port]);
|
||||
print_string(": ");
|
||||
if (machine.is_sfp[port]) {
|
||||
print_string("SFP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t v;
|
||||
print_string("Advertising: ");
|
||||
phy_read(port, PHY_MMD_AN, PHY_EEE_ADV2);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & PHY_EEE_BIT_2G5)
|
||||
print_string(" 2.5G");
|
||||
else
|
||||
print_string(" ");
|
||||
phy_read(port, PHY_MMD_AN, PHY_EEE_ADV);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & PHY_EEE_BIT_1G)
|
||||
print_string(" 1G ");
|
||||
else
|
||||
print_string(" ");
|
||||
if (v & PHY_EEE_BIT_100M)
|
||||
print_string(" 100M");
|
||||
else
|
||||
print_string(" ");
|
||||
|
||||
print_string(" Link Partner: ");
|
||||
phy_read(port, PHY_MMD_AN, PHY_EEE_LP_ABILITY2);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & PHY_EEE_BIT_2G5)
|
||||
print_string(" 2.5G");
|
||||
else
|
||||
print_string(" ");
|
||||
phy_read(port, PHY_MMD_AN, PHY_EEE_LP_ABILITY);
|
||||
v = SFR_DATA_U16;
|
||||
if (v & PHY_EEE_BIT_1G)
|
||||
print_string(" 1G ");
|
||||
else
|
||||
print_string(" ");
|
||||
if (v & PHY_EEE_BIT_100M)
|
||||
print_string(" 100M");
|
||||
else
|
||||
print_string(" ");
|
||||
|
||||
reg_read_m(RTL8373_PHY_EEE_ABLTY);
|
||||
if (sfr_data[3] & (1 << port))
|
||||
print_string(" ACTIVE ");
|
||||
else
|
||||
print_string(" INACTIVE ");
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
void port_eee_enable_all(void) __banked
|
||||
{
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
port_eee_enable(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void port_eee_disable_all(void) __banked
|
||||
{
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
port_eee_disable(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void port_eee_status_all(void) __banked
|
||||
{
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
port_eee_status(i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable RLDP, Realtek's version of LLDP
|
||||
*/
|
||||
void port_rldp_on(__xdata uint16_t p_ms)
|
||||
{
|
||||
REG_WRITE(RTL8373_RLDP_TIMER, p_ms >> 8, p_ms, p_ms >> 8, p_ms);
|
||||
|
||||
REG_SET(RTL837X_RMA0_CONF, 0x00000000); // R4ecc
|
||||
REG_SET(RTL837X_RMA_CONF, 0x00000000); // R4ecc
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
print_string("port_lag_members_set, lag: "); print_byte(lag); print_string(", members: "); print_short(members);
|
||||
if (lag > 3)
|
||||
print_string("Link aggregation group must be 0-3!");
|
||||
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2));
|
||||
if (!(sfr_data[0] | sfr_data [1] | sfr_data [2] | sfr_data [3]))
|
||||
REG_SET(RTL837X_TRK_HASH_CTRL_BASE, LAG_HASH_DEFAULT);
|
||||
REG_WRITE(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2), 0, 0, members >> 8, members & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
print_string("port_lag_hash_set, lag: "); print_byte(lag); print_string(", hash: "); print_byte(hash_bits);
|
||||
if (lag > 3)
|
||||
print_string("Link aggregation group must be 0-3!");
|
||||
REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits);
|
||||
}
|
||||
|
||||
@@ -1,37 +1,16 @@
|
||||
#ifndef _RTL837X_PORT_H_
|
||||
#define _RTL837X_PORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define STAT_COUNTER_TX_PKTS 46
|
||||
#define STAT_COUNTER_RX_PKTS 47
|
||||
#define STAT_COUNTER_ERR_PKTS 48
|
||||
|
||||
#define STAT_GET(cnt, port) \
|
||||
REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, cnt >> 3, (cnt << 5) | (port << 1) | 1); \
|
||||
do { \
|
||||
reg_read_m(RTL837X_STAT_GET); \
|
||||
} while (sfr_data[3] & 0x1);
|
||||
|
||||
uint8_t port_l2_forget(void) __banked;
|
||||
void port_l2_learned(void) __banked;
|
||||
void port_stats_print(void) __banked;
|
||||
int8_t vlan_get(register uint16_t vlan) __banked;
|
||||
__xdata uint16_t vlan_name(register uint16_t vlan) __banked;
|
||||
void vlan_setup(void) __banked;
|
||||
void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
|
||||
void vlan_create(register uint16_t vlan, register uint16_t members, register uint16_t tagged) __banked;
|
||||
void vlan_create(uint16_t vlan, uint16_t members, uint16_t tagged) __banked;
|
||||
void vlan_delete(uint16_t vlan) __banked;
|
||||
void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked;
|
||||
void port_mirror_del(void) __banked;
|
||||
void port_ingress_filter(register uint8_t port, uint8_t type) __banked;
|
||||
void port_l2_setup(void) __banked;
|
||||
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
|
||||
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash) __banked;
|
||||
void port_eee_enable_all(void) __banked;
|
||||
void port_eee_disable_all(void) __banked;
|
||||
void port_eee_status_all(void) __banked;
|
||||
void port_eee_enable(uint8_t port) __banked;
|
||||
void port_eee_disable(uint8_t port) __banked;
|
||||
void port_eee_status(uint8_t port) __banked;
|
||||
void port_l2_setup() __banked;
|
||||
void trunk_set(uint8_t group, uint16_t mask) __banked;
|
||||
#endif
|
||||
|
||||
@@ -1,69 +1,24 @@
|
||||
#ifndef _RTL837X_REGS_H_
|
||||
#define _RTL837X_REGS_H_
|
||||
|
||||
#define RTL837X_REG_CHIP_ID 0x0004
|
||||
#define RTL837X_REG_CHIP_INFO 0x000c
|
||||
#define RTL837X_REG_RESET 0x0024
|
||||
#define RESET_SOC_BIT 0
|
||||
#define RESET_NIC_BIT 2
|
||||
|
||||
#define RTL837X_REG_HW_CONF 0x6040
|
||||
#define RTL837X_REG_HW_CONF 0x6040
|
||||
// Bits 4 & 5: CLOCK DIVIDER from 125MHz for Timer
|
||||
|
||||
#define SYS_LED_OFF 0
|
||||
#define SYS_LED_FAST 1
|
||||
#define SYS_LED_SLOW 2
|
||||
#define SYS_LED_ON 3
|
||||
|
||||
#define RTL837X_REG_LED_MODE 0x6520
|
||||
#define RTL837X_REG_LED_MODE 0x6520
|
||||
// Defines the LED Mode for steering the Port LEDS and the System LED
|
||||
// BIT 17 set: LED solid on
|
||||
// Bytes 0/1 hold the LED mode, e.g. serial, RTL8231?
|
||||
// Blink rate is defined by setAsicRegBits(0x6520,0xe00000,rate);
|
||||
#define RTL837X_REG_LED_GLB_MUX_1 0x65E0
|
||||
#define RTL837X_REG_LED_GLB_MUX_2 0x65E4
|
||||
#define RTL837X_REG_LED_GLB_MUX_3 0x65E8
|
||||
#define RTL837X_REG_LED_GLB_MUX_4 0x65EC
|
||||
#define RTL837X_REG_LED_GLB_MUX_5 0x65F0
|
||||
#define RTL837X_REG_LED_GLB_MUX_6 0x65F4
|
||||
#define RTL837X_REG_LED_GLB_ACTIVE 0x65D8
|
||||
#define RTL837X_REG_LED_GLB_IO_EN 0x65DC
|
||||
#define RTL837X_REG_LED3_0_SET3 0x6524
|
||||
#define RTL837X_REG_LED3_0_SET1 0x6528
|
||||
#define RTL837X_REG_LED1_0_SET3 0x6530
|
||||
#define RTL837X_REG_LED3_2_SET2 0x6534
|
||||
#define RTL837X_REG_LED1_0_SET2 0x6538
|
||||
#define RTL837X_REG_LED3_2_SET1 0x653C
|
||||
#define RTL837X_REG_LED1_0_SET1 0x6540
|
||||
#define RTL837X_REG_LED3_2_SET0 0x6544
|
||||
#define RTL837X_REG_LED1_0_SET0 0x6548
|
||||
#define RTL837X_LED_PORT_SET_SEL 0x654c
|
||||
|
||||
// SMI control
|
||||
#define RTL837X_REG_SMI_PORT0_5_ADDR 0x644C
|
||||
#define RTL837X_REG_SMI_PORT6_9_ADDR 0x6450
|
||||
#define RTL837X_REG_SMI_CTRL 0x6454
|
||||
#define RTL837X_REG_SMI_MAC_TYPE 0x6330
|
||||
#define RTL837X_REG_SMI_PORT_POLLING 0x6334
|
||||
#define RTL837X_REG_SMI_CTRL 0x6454
|
||||
#define RTL837X_REG_RESET 0x0024
|
||||
// Writing 0x01 into this register causes a reset of the entire SoC
|
||||
|
||||
#define RTL837X_REG_SEC_COUNTER 0x06f4
|
||||
#define RTL837X_REG_SEC_COUNTER2 0x06f8
|
||||
// Used for counting seconds
|
||||
|
||||
|
||||
/*
|
||||
* SDS
|
||||
*/
|
||||
#define RTL837X_SDS_INDACS_CMD 0x3F8
|
||||
#define RTL837X_SDS_INDACS_WRITE_DATA 0x400
|
||||
#define RTL837X_REG_SDS_MODES 0x7b20
|
||||
|
||||
/*
|
||||
* PHY
|
||||
*/
|
||||
#define RTL837X_CFG_PHY_TX_POLARITY_SWAP 0xA94
|
||||
#define RTL837X_CFG_PHY_MDI_REVERSE 0xA90
|
||||
|
||||
#define RTL837X_REG_SDS_MODES 0x7b20
|
||||
/*
|
||||
* 5 Bits each give the state of the 2 SerDes of the RTL8372
|
||||
* Values are:
|
||||
@@ -76,8 +31,7 @@
|
||||
#define SDS_10GR 0x1a
|
||||
#define SDS_OFF 0x1f
|
||||
|
||||
#define RTL837X_REG_LINKS 0x63f0
|
||||
#define RTL837X_REG_LINKS_89 0x63f4
|
||||
#define RTL837X_REG_LINKS 0x63f0
|
||||
/* Each nibble encodes the link state of a port.
|
||||
Port 0 appears to be the CPU port
|
||||
The RTL8372 serves ports 4-7, port 3 is the RTL8221
|
||||
@@ -85,58 +39,33 @@
|
||||
5: 2.5Gbit
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Pin configuration (pinmux)
|
||||
*/
|
||||
|
||||
#define RTL837X_PIN_MUX_0 0x7f8c
|
||||
#define RTL837X_PIN_MUX_1 0x7f90
|
||||
#define RTL837X_PIN_MUX_2 0x7f94
|
||||
|
||||
// Output Registers
|
||||
#define RTL837X_REG_GPIO_00_31_OUTPUT 0x3c
|
||||
#define RTL837X_REG_GPIO_32_63_OUTPUT 0x40
|
||||
#define RTL837X_REG_GPIO_A 0x40
|
||||
// BIT 4 resets RTL8224 on 9000-9XH
|
||||
|
||||
// Input Registers
|
||||
#define RTL837X_REG_GPIO_00_31_INPUT 0x44
|
||||
#define RTL837X_REG_GPIO_32_63_INPUT 0x48
|
||||
#define RTL837X_REG_GPIO_B 0x44
|
||||
// Bit 1e cleared: SFP Module inserted on 9000-6XH (MOD_DEF0 pin)
|
||||
|
||||
#define RTL837X_REG_GPIO_C 0x48
|
||||
// BIT 5 set: SIGNAL LOS of SFP module on 9000-6XH (RX_LOS pin)
|
||||
|
||||
// Direction Registers, 0 = input, 1 = output
|
||||
#define RTL837X_REG_GPIO_00_31_DIRECTION 0x4c
|
||||
#define RTL837X_REG_GPIO_32_63_DIRECTION 0x50
|
||||
#define RTL837X_REG_GPIO_CONF_A 0x50
|
||||
// Configures IO direction for bank a
|
||||
|
||||
#define RTL837X_REG_GPIO_EXT 0x63e8
|
||||
|
||||
/*
|
||||
* I2C controller
|
||||
*/
|
||||
#define RTL837X_REG_I2C_MST_IF_CTRL 0x0414
|
||||
#define RTL837X_REG_I2C_CTRL 0x0418
|
||||
#define I2C_DEV_ADDR 3
|
||||
#define I2C_MEM_ADDR_WIDTH 20
|
||||
#define RTL837X_REG_I2C_CTRL2 0x041c
|
||||
#define RTL837X_REG_I2C_IN 0x0420
|
||||
#define RTL837X_REG_I2C_OUT 0x0424
|
||||
#define RTL837X_REG_I2C_CTRL 0x0418
|
||||
#define RTL837X_REG_I2C_IN 0x0420
|
||||
#define RTL837X_REG_I2C_OUT 0x0424
|
||||
|
||||
/*
|
||||
* NIC Related registers
|
||||
*/
|
||||
#define RTL837X_REG_NIC_BUFFSIZE_TX 0x7844
|
||||
#define RTL837X_REG_NIC_RXBUFF_RX 0x7848
|
||||
#define RTL837X_REG_NIC_RXCMD 0x784c
|
||||
#define RTL837X_REG_NIC_TXCMD 0x7850
|
||||
#define RTL837X_REG_RX_CTRL 0x785c
|
||||
#define RTL837X_REG_TX_CTRL 0x7860
|
||||
#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874
|
||||
#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c
|
||||
#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884
|
||||
#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890
|
||||
#define RTL837X_REG_CPU_TAG 0x6720
|
||||
#define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C
|
||||
#define RTL837X_REG_MAC_FORCE_MODE 0x6344
|
||||
#define RTL837X_REG_RX_AVAIL 0x7874
|
||||
#define RTL837X_REG_RX_RINGPTR 0x787c
|
||||
#define RTL837X_REG_RX_DONE 0x784c
|
||||
|
||||
/*
|
||||
* Statistics related registers
|
||||
@@ -160,44 +89,15 @@
|
||||
// Table types
|
||||
#define TBL_L2_UNICAST 0x04
|
||||
#define TBL_VLAN 0x03
|
||||
// Table read methods for the L2 table (TBL_L2_UNICAST):
|
||||
#define TBL_LUTREAD_MAC 0
|
||||
#define TBL_LUTREAD_ADDRESS 1
|
||||
#define TBL_LUTREAD_NEXT_ADDRESS 2
|
||||
#define TBL_LUTREAD_NEXT_L2UC 3
|
||||
#define TBL_LUTREAD_NEXT_L2MC 4
|
||||
#define TBL_LUTREAD_NEXT_L3MC 5
|
||||
#define TBL_LUTREAD_NEXT_L2L3MC 6
|
||||
#define TBL_LUTREAD_NEXT_L2UCSPA 7
|
||||
|
||||
#define RTL837X_L2_CTRL 0x5350
|
||||
#define L2_CTRL_LUT_IPMC_HASH 3
|
||||
#define RTL837x_TBL_DATA_0 0x5cb0
|
||||
#define RTL837x_L2_DATA_OUT_A 0x5ccc
|
||||
#define RTL837x_L2_DATA_OUT_B 0x5cd0
|
||||
#define RTL837x_L2_DATA_OUT_C 0x5cd4
|
||||
#define RTL837x_TBL_DATA_IN_A 0x5cb8
|
||||
#define RTL837x_TBL_DATA_IN_B 0x5cbc
|
||||
#define RTL837x_TBL_DATA_IN_C 0x5cc0
|
||||
#define RTL837x_L2_TBL_CTRL 0x53d4
|
||||
#define RTL837x_PVID_BASE_REG 0x4e1c
|
||||
|
||||
#define RTL837x_L2_TBL_FLUSH_CTRL 0x53d4
|
||||
#define L2_TBL_FLUSH_EXEC 0x10000
|
||||
#define RTL837x_L2_TBL_FLUSH_CNF 0x53dc
|
||||
#define RTL837X_L2_LRN_PORT_CONSTRAINT 0x5384
|
||||
#define RTL837X_L2_LRN_PORT_CONSTRT_ACT 0x4f80
|
||||
#define RTL8373_REG_MAC_L2_PORT_MAX_LEN 0x1250
|
||||
|
||||
/*
|
||||
* VLAN configuration
|
||||
*/
|
||||
#define RTL837X_VLAN_CTRL 0x4e14
|
||||
#define VLAN_CVLAN_FILTER 0x4
|
||||
#define RTL837X_VLAN_PORT_EGR_TAG 0x6738
|
||||
#define RTL837X_VLAN_PORT_IGR_FLTR 0x4e18
|
||||
#define RTL837X_VLAN_L2_LRN_DIS_0 0x4e30
|
||||
#define RTL837X_VLAN_L2_LRN_DIS_1 0x4e34
|
||||
|
||||
/*
|
||||
* Egress / ingress filtering
|
||||
*/
|
||||
@@ -210,81 +110,20 @@
|
||||
/*
|
||||
* Mirroring
|
||||
*/
|
||||
#define RTL837x_MIRROR_CONF 0x604c
|
||||
#define RTL837x_MIRROR_CTRL 0x6048
|
||||
#define RTL837x_MIRROR_CONF 0x604c
|
||||
#define RTL837x_MIRROR_CTRL 0x6048
|
||||
|
||||
/*
|
||||
* Link Aggregation aka Trunking
|
||||
* Trunking
|
||||
*/
|
||||
#define RTL837X_TRK_MBR_CTRL_BASE 0x4f38
|
||||
#define RTL837X_TRK_HASH_CTRL_BASE 0x4f48
|
||||
#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)
|
||||
|
||||
/*
|
||||
* Port isolation
|
||||
*/
|
||||
#define RTL837X_PORT_ISOLATION_BASE 0x50c0
|
||||
|
||||
/*
|
||||
* Multicast handling
|
||||
*/
|
||||
#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
|
||||
|
||||
/*
|
||||
* Loop detection / STP
|
||||
*/
|
||||
#define RTL8373_RLDP_TIMER 0x1074
|
||||
#define RTL837X_RMA0_CONF 0x4ecc
|
||||
#define RTL837X_RMA_CONF 0x4f1c
|
||||
#define RTL837X_MSTP_STATES 0x5310
|
||||
#define RTL837X_REG_LED_RLDP_1 0x65F8
|
||||
#define RTL837X_REG_LED_RLDP_2 0x65FC
|
||||
#define RTL837X_REG_LED_RLDP_3 0x6600
|
||||
|
||||
/*
|
||||
* EEE
|
||||
*/
|
||||
#define RTL837X_EEE_STATUS 0x125C
|
||||
#define RTL837X_MAC_EEE_ABLTY 0x6404
|
||||
#define RTL8373_PHY_EEE_ABLTY 0x642C
|
||||
#define RTL8373_EEE_CTRL_BASE 0x606c
|
||||
#define EEE_100 0x01
|
||||
#define EEE_1000 0x04
|
||||
#define EEE_2G5 0x10
|
||||
|
||||
/*
|
||||
* RANDOM
|
||||
*/
|
||||
#define RTL837X_RLDP_RLPP 0x106C
|
||||
#define RLDP_RND_EN 3
|
||||
#define RTL837X_RAND_NUM0 0x107C
|
||||
#define RTL837X_RAND_NUM1 0x1080
|
||||
#define RTL837x_TRUNK_CTRL_A 0x4f38
|
||||
#define RTL837x_TRUNK_CTRL_B 0x4f3c
|
||||
|
||||
#ifdef REGDBG
|
||||
|
||||
#define REG_SET(r, v) SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
|
||||
SFR_DATA_16 = (((uint32_t)v) >> 16) & 0xff; \
|
||||
SFR_DATA_8 = (((uint16_t)v) >> 8 & 0xff); \
|
||||
#define REG_SET(r, v) SFR_DATA_24 = ((v) >> 24) & 0xff; \
|
||||
SFR_DATA_16 = ((v) >> 16) & 0xff; \
|
||||
SFR_DATA_8 = ((v) >> 8 & 0xff); \
|
||||
SFR_DATA_0 = (v) & 0xff; \
|
||||
reg_write(r); \
|
||||
write_char('R'); print_byte(r >> 8); print_byte(r); write_char('-'); \
|
||||
@@ -297,9 +136,9 @@
|
||||
reg_write(r); \
|
||||
write_char('R'); print_byte(r>>8); print_byte(r); write_char('-'); print_byte(v24); print_byte(v16); print_byte(v8); print_byte(v0); write_char(' ');
|
||||
#else
|
||||
#define REG_SET(r, v) SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
|
||||
SFR_DATA_16 = (((uint32_t)v) >> 16) & 0xff; \
|
||||
SFR_DATA_8 = (((uint16_t)v) >> 8 & 0xff); \
|
||||
#define REG_SET(r, v) SFR_DATA_24 = ((v) >> 24) & 0xff; \
|
||||
SFR_DATA_16 = ((v) >> 16) & 0xff; \
|
||||
SFR_DATA_8 = ((v) >> 8 & 0xff); \
|
||||
SFR_DATA_0 = (v) & 0xff; \
|
||||
reg_write(r);
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
/* SFR control registers for switch register access */
|
||||
__sfr __at(0xa0) SFR_EXEC_GO;
|
||||
__sfr __at(0xa1) SFR_EXEC_STATUS;
|
||||
__sfr16 __at(0xa2a3) SFR_REG_ADDR_U16;
|
||||
__sfr __at(0xa2) SFR_REG_ADDRH;
|
||||
__sfr __at(0xa3) SFR_REG_ADDRL;
|
||||
__sfr16 __at(0xa6a7) SFR_DATA_U16;
|
||||
__sfr32 __at(0xa4a5a6a7) SFR_DATA_U32;
|
||||
__sfr32 __at(0xa7a6a5a4) SFR_DATA_U32LE;
|
||||
__sfr __at(0xa4) SFR_DATA_24;
|
||||
__sfr __at(0xa5) SFR_DATA_16;
|
||||
__sfr __at(0xa6) SFR_DATA_8;
|
||||
@@ -21,7 +17,6 @@ __sfr __at(0xa7) SFR_DATA_0;
|
||||
#define SFR_EXEC_WRITE_SMI 11
|
||||
|
||||
/* SFR control registers for phy access via SMI/MDIO */
|
||||
__sfr16 __at(0xc2c3) SFR_SMI_REG_U16;
|
||||
__sfr __at(0xc2) SFR_SMI_REG_H;
|
||||
__sfr __at(0xc3) SFR_SMI_REG_L;
|
||||
__sfr __at(0xc4) SFR_SMI_DEV;
|
||||
@@ -40,6 +35,11 @@ __sfr __at(0x91) EXIF;
|
||||
__sfr __at(0xf8) EIP;
|
||||
__sbit __at(0xf9) PX3;
|
||||
|
||||
/* SFR control registers for serial communication */
|
||||
__sfr __at(0xc8) T2CON;
|
||||
__sfr __at(0xca) RCAP2L;
|
||||
__sfr __at(0xcb) RCAP2H;
|
||||
|
||||
/* SFR Bank control register: 0x0-3f. A value of 0 is bank 1 */
|
||||
__sfr __at(0x96) PSBANK;
|
||||
// SFR used to store return bank for trampoline
|
||||
@@ -66,7 +66,7 @@ __sfr __at(0xbc) SFR_FLASH_CONFIG;
|
||||
|
||||
__sfr __at(0x9b) SFR_FLASH_CONF_DIV;
|
||||
__sfr __at(0x9c) SFR_FLASH_CONF_RCMD;
|
||||
__sfr __at(0x9d) SFR_FLASH_DUMMYCYCLES;
|
||||
__sfr __at(0x9d) SFR_FLASH_DUMMYCICLES;
|
||||
__sfr __at(0x9a) SFR_FLASH_MODEB;
|
||||
|
||||
__sfr __at(0x9e) SFR_FLASH_TCONF;
|
||||
@@ -86,25 +86,7 @@ __sfr __at(0xa9) SFR_FLASH_ADDR0;
|
||||
* CAREFUL: This is now Little Endian
|
||||
*/
|
||||
__sfr __at(0xb7) SFR_NIC_CTRL;
|
||||
__sfr16 __at(0xb4b3) SFR_NIC_DATA_U16LE;
|
||||
__sfr __at(0xb3) SFR_NIC_DATA_L;
|
||||
__sfr __at(0xb4) SFR_NIC_DATA_H;
|
||||
__sfr16 __at(0xb6b5) SFR_NIC_RING_U16LE;
|
||||
__sfr __at(0xb5) SFR_NIC_RING_L;
|
||||
__sfr __at(0xb6) SFR_NIC_RING_H;
|
||||
|
||||
/* Standard 8051 sfr */
|
||||
// Timer 0 value
|
||||
__sfr16 __at(0x8c8a) T0_U16;
|
||||
|
||||
// Timer 1 enable interrupt
|
||||
__sbit __at(0xad) ET2;
|
||||
|
||||
// Timer 2
|
||||
__sfr __at(0xcc) TL2;
|
||||
__sfr __at(0xcd) TH2;
|
||||
__sfr16 __at(0xcdcc) T2_U16;
|
||||
__sfr __at(0xc8) T2CON;
|
||||
__sfr __at(0xca) RCAP2L;
|
||||
__sfr __at(0xcb) RCAP2H;
|
||||
__sfr16 __at(0xcbca) RCAP2_U16;
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* This is a driver implementation for the Spanning Tree Protocol features for the RTL837x platform
|
||||
* This code is in the Public Domain
|
||||
*/
|
||||
|
||||
// #define REGDBG
|
||||
// #define DEBUG
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_stp.h"
|
||||
#include "uip.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
extern __code struct uip_eth_addr uip_ethaddr;
|
||||
|
||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
|
||||
|
||||
struct bridge {
|
||||
uint8_t prio;
|
||||
uint8_t ext;
|
||||
uint8_t mac[6];
|
||||
};
|
||||
|
||||
__xdata struct bridge root_bridge;
|
||||
__xdata uint32_t root_bridge_cost;
|
||||
|
||||
__xdata uint8_t port_types[10];
|
||||
__xdata uint16_t port_timers[10];
|
||||
__xdata uint16_t port_hello[10];
|
||||
|
||||
|
||||
struct stp_pkt {
|
||||
uint8_t stp_addr[6];
|
||||
uint8_t src_addr[6];
|
||||
struct rtl_tag rtl_tag;
|
||||
uint16_t msg_len;
|
||||
uint8_t dsap;
|
||||
uint8_t ssap;
|
||||
uint8_t ctrl;
|
||||
uint16_t proto;
|
||||
uint8_t version;
|
||||
uint8_t bpdu_type;
|
||||
uint8_t flags;
|
||||
struct bridge root;
|
||||
uint32_t root_path_cost;
|
||||
struct bridge bridge;
|
||||
uint8_t port_prio;
|
||||
uint8_t port_id;
|
||||
uint16_t age;
|
||||
uint16_t age_max;
|
||||
uint16_t hello;
|
||||
uint16_t fwd_delay;
|
||||
};
|
||||
|
||||
struct stp_pkt_in {
|
||||
uint8_t stp_addr[6];
|
||||
uint8_t src_addr[6];
|
||||
struct rtl_tag rtl_tag;
|
||||
uint8_t vtag[4];
|
||||
uint16_t msg_len;
|
||||
uint8_t dsap;
|
||||
uint8_t ssap;
|
||||
uint8_t ctrl;
|
||||
uint16_t proto;
|
||||
uint8_t version;
|
||||
uint8_t bpdu_type;
|
||||
uint8_t flags;
|
||||
struct bridge root;
|
||||
uint32_t root_path_cost;
|
||||
struct bridge bridge;
|
||||
uint8_t port_prio;
|
||||
uint8_t port_id;
|
||||
uint16_t age;
|
||||
uint16_t age_max;
|
||||
uint16_t hello;
|
||||
uint16_t fwd_delay;
|
||||
};
|
||||
|
||||
#define STP_O ((__xdata struct stp_pkt *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE])
|
||||
#define STP_I ((__xdata struct stp_pkt_in *)&uip_buf[0])
|
||||
|
||||
#define FLAG_PROPOSAL 0x02
|
||||
#define P_DESIGNATED ((STP_I->flags & 0x0c) == 0x0c)
|
||||
#define P_PROPOSAL (STP_I->flags & FLAG_PROPOSAL)
|
||||
|
||||
signed char cmpMAC(__xdata uint8_t *m1, __xdata uint8_t *m2)
|
||||
{
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (m1[i] == m2[i])
|
||||
continue;
|
||||
if (m1[i] < m2[i])
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void stp_in(void) __banked
|
||||
{
|
||||
// By default we do not send anything out
|
||||
uip_len = 0;
|
||||
// MSTPSTP_I_STATES 0x5310
|
||||
// reg_read_m(RTL837X_MSTP_STATES);
|
||||
|
||||
print_string("Check BPDU... \n");
|
||||
for (uint8_t i = 0; i < 80; i++) {
|
||||
print_byte(uip_buf[i]);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
print_byte(STP_I->dsap);
|
||||
print_byte(STP_I->ssap);
|
||||
print_byte(STP_I->ctrl);
|
||||
|
||||
write_char('\n');
|
||||
// Make sure this is the type of RSTP packet we are interested in:
|
||||
if (!(STP_I->dsap == 0x42 && STP_I->ssap == 0x42 && STP_I->ctrl == 0x03))
|
||||
return;
|
||||
print_string("Checking RSTP\n");
|
||||
if (STP_I->proto)
|
||||
return;
|
||||
// write_char('A'); print_byte(STP_I->version); write_char('\n');
|
||||
if (STP_I->version != 2)
|
||||
return;
|
||||
// write_char('B'); print_byte(STP_I->bpdu_type); write_char('\n');
|
||||
if (STP_I->bpdu_type != 2)
|
||||
return;
|
||||
// write_char('\n');
|
||||
// print_string("Flags: "); print_byte(STP_I->flags); write_char('\n');
|
||||
print_string("Check new Root\n");
|
||||
if (STP_I->root.prio < root_bridge.prio
|
||||
|| ((STP_I->root.prio == root_bridge.prio) && cmpMAC(STP_I->root.mac, STP_I->root.mac) < 0)) {
|
||||
print_string("Updating Root bridge\n");
|
||||
root_bridge.prio = STP_I->root.prio;
|
||||
memcpy(root_bridge.mac, STP_I->root.mac, 6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stp_cnf_send(uint8_t port)
|
||||
{
|
||||
STP_O->stp_addr[0] = 0x01; STP_O->stp_addr[1] = 0x80; STP_O->stp_addr[2] = 0xc2;
|
||||
STP_O->stp_addr[3] = STP_O->stp_addr[4] = STP_O->stp_addr[5] = 0x00;
|
||||
|
||||
STP_O->rtl_tag.tag = HTONS(0x8899);
|
||||
STP_O->rtl_tag.version = 0x04;
|
||||
STP_O->rtl_tag.reason = 0x00;
|
||||
STP_O->rtl_tag.flags = 0x0020; // Disable L2 learning
|
||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
|
||||
|
||||
STP_O->msg_len = HTONS(0x27);
|
||||
STP_O->dsap = 0x42;
|
||||
STP_O->ssap = 0x42;
|
||||
STP_O->ctrl = 0x03;
|
||||
STP_O->proto = 0x0000;
|
||||
STP_O->version = 0x02; // RSTP
|
||||
STP_O->bpdu_type = 0x00; // Config
|
||||
STP_O->flags = 0x81;
|
||||
|
||||
memcpyc(STP_O->src_addr, uip_ethaddr.addr, 6);
|
||||
memcpy(STP_O->root.mac, root_bridge.mac, 6);
|
||||
memcpyc(STP_O->bridge.mac, uip_ethaddr.addr, 6);
|
||||
|
||||
STP_O->root.prio = root_bridge.prio;
|
||||
STP_O->root.ext = 0x00;
|
||||
STP_O->root_path_cost = 0x00000000;
|
||||
|
||||
STP_O->bridge.prio = 0x80;
|
||||
STP_O->bridge.ext = 0x00;
|
||||
|
||||
STP_O->port_prio = 0x80;
|
||||
STP_O->port_id = port;
|
||||
STP_O->age = 0x00; // FIXME: This only works because we do not use HTONS and the values are in 1/256 seconds
|
||||
STP_O->age_max = 20;
|
||||
STP_O->hello = 2;
|
||||
STP_O->fwd_delay = 0x0f;
|
||||
|
||||
// uip_len = 0x27 + sizeof(struct rtl_tag);
|
||||
uip_len = sizeof(struct stp_pkt);
|
||||
tcpip_output();
|
||||
}
|
||||
|
||||
|
||||
void stp_timers(void) __banked
|
||||
{
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
port_hello[i]--;
|
||||
if (!port_hello[i]) {
|
||||
port_hello[i] = TIME_HELLO;
|
||||
print_string("STP_HELLO port ");
|
||||
print_byte(i); write_char('\n');
|
||||
stp_cnf_send(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stp_setup(void) __banked
|
||||
{
|
||||
print_string("Enabling STP: ");
|
||||
sfr_data[0] = sfr_data[1] = sfr_data[2] = sfr_data[3] = 0;
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
// Set STP port state to blocking
|
||||
// States are: 00 disable, 01 blocking, 10 learning, 11 forwarding
|
||||
uint8_t bit_mask = 0b01 << ( (i << 1) & 0x7);
|
||||
sfr_data[3 - (i >> 2)] |= bit_mask;
|
||||
port_hello[i] = TIME_HELLO;
|
||||
port_timers[i] = 0xa00; // 10 sec in blocking state
|
||||
}
|
||||
sfr_data[1] |= 0x0f; // Do not block CPU-Port
|
||||
reg_write_m(RTL837X_MSTP_STATES); // R5310-000d555f
|
||||
|
||||
print_reg(RTL837X_MSTP_STATES); write_char('\n');
|
||||
|
||||
root_bridge.prio = 0x80; // This corresponds to 32768
|
||||
root_bridge.ext = 0x00;
|
||||
memcpyc(root_bridge.mac, uip_ethaddr.addr, 6);
|
||||
}
|
||||
|
||||
|
||||
void stp_off(void) __banked
|
||||
{
|
||||
sfr_data[0] = sfr_data[1] = sfr_data[2] = sfr_data[3] = 0;
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
// Set STP port state to forwarding
|
||||
// States are: 00 disable, 01 blocking, 10 learning, 11 forwarding
|
||||
uint8_t bit_mask = 0b11 << ( (i << 1) & 0x7);
|
||||
sfr_data[3 - (i >> 2)] |= bit_mask;
|
||||
}
|
||||
sfr_data[1] |= 0x0f; // Do not block CPU-Port
|
||||
reg_write_m(RTL837X_MSTP_STATES);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef _RTL837X_STP_H_
|
||||
#define _RTL837X_STP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
void stp_in(void) __banked;
|
||||
void stp_setup(void) __banked;
|
||||
void stp_timers(void) __banked;
|
||||
void stp_off(void) __banked;
|
||||
|
||||
#define TIME_HELLO 0x200 // 2 sec
|
||||
|
||||
#endif
|
||||
@@ -1,27 +1,12 @@
|
||||
CC = gcc
|
||||
CCFLAGS = -Wall -o
|
||||
BUILDDIR = output/
|
||||
|
||||
all: create_build_dir $(BUILDDIR)injector $(BUILDDIR)fileadder $(BUILDDIR)httpd_sim\
|
||||
$(BUILDDIR)crc_calculator $(BUILDDIR)imagebuilder
|
||||
|
||||
create_build_dir:
|
||||
mkdir -p $(BUILDDIR)
|
||||
all: injector fileadder
|
||||
|
||||
clean:
|
||||
rm -r $(BUILDDIR)
|
||||
rm *.o
|
||||
|
||||
$(BUILDDIR)injector: injector.c
|
||||
gcc $^ $(CCFLAGS) $@
|
||||
injector: injector.c
|
||||
gcc $^ -o $@
|
||||
|
||||
$(BUILDDIR)fileadder: fileadder.c
|
||||
gcc $^ $(CCFLAGS) $@
|
||||
|
||||
$(BUILDDIR)crc_calculator: crc_calculator.c
|
||||
gcc $^ $(CCFLAGS) $@
|
||||
|
||||
$(BUILDDIR)httpd_sim: httpd_sim.c httpd_sim.h
|
||||
gcc $< $(CCFLAGS) $@ -I/usr/include/json-c -ljson-c
|
||||
|
||||
$(BUILDDIR)imagebuilder: imagebuilder.c
|
||||
gcc $^ $(CCFLAGS) $@
|
||||
fileadder: fileadder.c
|
||||
gcc $^ -o $@
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Calculator for the CRC16 as described in AN27 by Dallas Semiconductor
|
||||
* http://www.microshadow.com/files/files8051/app27.pdf
|
||||
* The implementation in C is based on the code given in
|
||||
* https://carta.tech/man-pages/man3/_crc_ibutton_update.3avr.html
|
||||
* The polynomial of the CRC is 0xa001: x^16 + x^15 + x^2 + 1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <argp.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
// Use a 4MB buffer, the same as the flash rom size
|
||||
#define BUFFER_SIZE 0x400000
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
struct arguments {
|
||||
char *input_file;
|
||||
char *output_file;
|
||||
bool update;
|
||||
bool verify;
|
||||
};
|
||||
|
||||
const char *argp_program_version = "crc_calculator 0.1";
|
||||
const char *argp_program_bug_address = "https://github.com/logicog/RTLPlayground/issues";
|
||||
static char doc[] = "Calculate (and optionally update) the CRC of an image";
|
||||
static char args_doc[] = "crc_calculator [options] INPUT_IMAGE";
|
||||
static struct argp_option options[] = {
|
||||
{ "output", 'o', "FILE", 0, "Output image file name instead of overwriting input image"},
|
||||
{ "update", 'u', 0, OPTION_ARG_OPTIONAL, "Update the image with the CRC"},
|
||||
{ "verify", 'v', 0, OPTION_ARG_OPTIONAL, "Verify the CRC of the file"},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
uint16_t crc16_update(uint16_t crc, uint8_t a)
|
||||
{
|
||||
crc ^= a;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
crc = crc & 1 ? (crc >> 1) ^ 0xA001 : crc >> 1;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct arguments *arguments = state->input;
|
||||
switch (key) {
|
||||
case 'u':
|
||||
arguments->update = true;
|
||||
break;
|
||||
case 'v':
|
||||
arguments->verify = true;
|
||||
break;
|
||||
case 'o':
|
||||
arguments->output_file = arg;
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct argp argp = {
|
||||
options, parse_opt, args_doc, doc, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct arguments arguments;
|
||||
int arg_index;
|
||||
char tmpfilename[] = "crc_XXXXXX";
|
||||
uint16_t crc = 0;
|
||||
FILE *inptr;
|
||||
int outptr;
|
||||
int range;
|
||||
|
||||
arguments.input_file = NULL;
|
||||
arguments.output_file = NULL;
|
||||
arguments.update = false;
|
||||
arguments.verify = false;
|
||||
|
||||
argp_parse(&argp, argc, argv, 0, &arg_index, &arguments);
|
||||
if (!arg_index)
|
||||
argp_usage (0);
|
||||
|
||||
memset(buffer, 0, BUFFER_SIZE);
|
||||
|
||||
size_t filesize = 0;
|
||||
if (argv[arg_index]) {
|
||||
inptr = fopen(argv[arg_index], "rb");
|
||||
if (inptr == NULL) {
|
||||
printf("Cannot open input file %s\n", argv[arg_index]);
|
||||
return 5;
|
||||
}
|
||||
|
||||
fseek(inptr, 0L, SEEK_END);
|
||||
filesize = ftell(inptr);
|
||||
rewind(inptr);
|
||||
printf("Input file size: %ld\n", filesize);
|
||||
if (filesize > BUFFER_SIZE) {
|
||||
printf("File too large.\n");
|
||||
return 5;
|
||||
}
|
||||
size_t bytes_read = fread(buffer, 1, sizeof(buffer), inptr);
|
||||
|
||||
printf("Bytes read: %ld\n", bytes_read);
|
||||
|
||||
if (bytes_read != filesize) {
|
||||
printf("Error reading input file.\n");
|
||||
return 5;
|
||||
}
|
||||
fclose(inptr);
|
||||
}
|
||||
|
||||
range = filesize;
|
||||
if (!arguments.verify) {
|
||||
if (arguments.update) {
|
||||
range -= 2;
|
||||
} else if (arguments.output_file) {
|
||||
filesize += 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < range; i++)
|
||||
crc = crc16_update(crc, buffer[i]);
|
||||
|
||||
printf("CRC16 is: 0x%04x\n", crc);
|
||||
|
||||
if (arguments.verify) {
|
||||
if (crc == 0xb001) {
|
||||
printf("Checksum OK\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("Checksum Incorrect\n");
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to create a new image with updated CRC
|
||||
if (arguments.update || arguments.output_file) {
|
||||
crc ^= 0xffff;
|
||||
printf("Setting CRC bytes at position: 0x%x to CRC 1s complement 0x%04x\n", range, crc);
|
||||
// The CRC algorithm expects as input always first the LO-Byte
|
||||
buffer[range] = crc;
|
||||
buffer[range + 1] = crc >> 8;
|
||||
|
||||
if (!arguments.update)
|
||||
outptr = creat(arguments.output_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
else
|
||||
outptr = mkstemp(tmpfilename);
|
||||
|
||||
if (!outptr) {
|
||||
printf("Cannot open %s\n", arguments.output_file);
|
||||
return 5;
|
||||
}
|
||||
size_t written = write(outptr, buffer, filesize);
|
||||
|
||||
if (written != filesize) {
|
||||
printf("Error writing output file.\n");
|
||||
return 5;
|
||||
}
|
||||
close(outptr);
|
||||
|
||||
if (arguments.update)
|
||||
rename(tmpfilename, argv[arg_index]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -19,9 +19,9 @@
|
||||
char buffer[BUFFER_SIZE];
|
||||
FILE *inptr, *dataptr, *ofile;
|
||||
int outptr;
|
||||
#define PATH_SIZE 20480
|
||||
#define INDEX_SIZE 20480
|
||||
#define DEF_SIZE 20480
|
||||
#define PATH_SIZE 1024
|
||||
#define INDEX_SIZE 1024
|
||||
#define DEF_SIZE 1024
|
||||
char pathbuffer[PATH_SIZE];
|
||||
char ibuf[INDEX_SIZE];
|
||||
char dbuf[DEF_SIZE];
|
||||
@@ -39,10 +39,10 @@ const char *argp_program_bug_address = "<git@logicog.de>";
|
||||
static char doc[] = "Adds a file or a directory of files into an image";
|
||||
static char args_doc[] = "addfile [options] INPUT_IMAGE";
|
||||
static struct argp_option options[] = {
|
||||
{ "size", 's', "SIZE", 0, "Resize image"},
|
||||
{ "size", 's', "SIZE", OPTION_ARG_OPTIONAL, "Resize image"},
|
||||
{ "output", 'o', "FILE", 0, "Output image file name instead of overwriting input image"},
|
||||
{ "data", 'd', "FILE", 0, "File or directory to add to image"},
|
||||
{ "address", 'a', "SIZE", 0, "Address where data is placed, default is 0x1000000 if option is used, otherwise 0x1fd000"},
|
||||
{ "address", 'a', 0, OPTION_ARG_OPTIONAL, "Address where data is placed, default is 0x1000000 if option is used, otherwise 0x1fd000"},
|
||||
{ "prefix", 'p', "FILE", 0, "Prefix for header and index file generation"},
|
||||
{ "bank", 'b', "BANKNAME", 0, "Generate #pragma with given bank-name"},
|
||||
{ 0 }
|
||||
@@ -136,18 +136,14 @@ int hasSuffix(const char *str, const char *suffix)
|
||||
char *getMime(const char *name)
|
||||
{
|
||||
if (hasSuffix(name, ".html"))
|
||||
return "mime_HTML";
|
||||
return "text/html";
|
||||
else if (hasSuffix(name, ".svg"))
|
||||
return "mime_SVG";
|
||||
return "image/svg+xml";
|
||||
else if (hasSuffix(name, ".ico"))
|
||||
return "mime_SVG";
|
||||
return "image/svg+xml";
|
||||
else if (hasSuffix(name, ".png"))
|
||||
return "mime_PNG";
|
||||
else if (hasSuffix(name, ".js"))
|
||||
return "mime_JS";
|
||||
else if (hasSuffix(name, ".css"))
|
||||
return "mime_CSS";
|
||||
return "mime_TXT";
|
||||
return "image/png";
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
|
||||
@@ -164,9 +160,9 @@ int addidx(const char *name, int addr, int len)
|
||||
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#define FDATA_START_%s 0x%x\n", s, addr);
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#define FDATA_SIZE_%s %d\n", s, len);
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " {\"/%s\", FDATA_START_%s, FDATA_SIZE_%s, %s},\n", name, s, s, getMime(name));
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " {\"/%s\", FDATA_START_%s, FDATA_SIZE_%s, \"%s\"},\n", name, s, s, getMime(name));
|
||||
if (!strcmp(name, "index.html"))
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " {\"/\", FDATA_START_%s, FDATA_SIZE_%s, mime_HTML},\n", s, s);
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " {\"/\", FDATA_START_%s, FDATA_SIZE_%s, \"text/html\"},\n", s, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -204,7 +200,7 @@ int replaceCalls(int pos)
|
||||
buffer[pos + i + 5] = '}';
|
||||
i += 6;
|
||||
fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, " %s,\n", function_buf);
|
||||
xbuf_p += snprintf(&xbuf[xbuf_p], DEF_SIZE - xbuf_p, "extern uint16_t %s(void);\n", function_buf);
|
||||
xbuf_p += snprintf(&xbuf[xbuf_p], DEF_SIZE - xbuf_p, "extern uint16_t %s(__xdata uint8_t *outbuf);\n", function_buf);
|
||||
callNum++;
|
||||
}
|
||||
i++;
|
||||
@@ -216,6 +212,8 @@ int replaceCalls(int pos)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char * line = NULL;
|
||||
size_t len = 0;
|
||||
struct arguments arguments;
|
||||
int arg_index;
|
||||
char tmpfilename[] = "image_XXXXXX";
|
||||
@@ -267,20 +265,16 @@ int main(int argc, char **argv)
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#ifndef FDATA_DEFS_H\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#define FDATA_DEFS_H\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#include <stdint.h>\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p,
|
||||
"typedef enum mime_type_e {\n mime_HTML = 0,\n mime_SVG,\n mime_ICO,\n mime_PNG,\n mime_JS,\n mime_CSS,\n mime_TXT\n} mime_type_t;\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "struct f_data {\n __code char *file;\n uint32_t start;\n uint16_t len;\n mime_type_t mime;\n};\n\n");
|
||||
// defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "typedef uint16_t (* fcall_ptr)(void);\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "struct f_data {\n __code char *file;\n uint32_t start;\n uint16_t len;\n __code char *mime;\n};\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "typedef uint16_t (* fcall_ptr)(__xdata uint8_t *outbuf);\n\n");
|
||||
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "// This file is automatically generated, do not edit!\n\n");
|
||||
if (arguments.prefix)
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#include \"%s.h\"\n\n", arguments.prefix);
|
||||
if (arguments.bank)
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#pragma codeseg %s\n#pragma constseg %s\n\n", arguments.bank, arguments.bank);
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " __code char * __code mime_strings[] = {\n \"text/html\",\n \"image/svg+xml\",\n"
|
||||
" \"image/svg+xml\",\n \"image/png\",\n \"text/javascript\",\n \"text/css\",\n \"text/plain\"};\n\n");
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#pragma codeseg %s\n", arguments.bank);
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "__code struct f_data f_data[] = {\n");
|
||||
// fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, "\n__code fcall_ptr f_calls[] = {\n");
|
||||
fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, "\n__code fcall_ptr f_calls[] = {\n");
|
||||
|
||||
// Now that the beginning of the buffer is filled with out image, optionally resize the image
|
||||
if (filesize)
|
||||
@@ -335,7 +329,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " {0, 0, 0}\n};\n");
|
||||
// fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, "};\n");
|
||||
fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, "};\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#endif\n");
|
||||
|
||||
if (filesize) {
|
||||
|
||||
@@ -1,854 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include "httpd_sim.h"
|
||||
#include <json.h>
|
||||
#include <signal.h>
|
||||
#include "../version.h"
|
||||
|
||||
#define SESSION_ID "1234567890ab"
|
||||
#define PASSWORD "1234"
|
||||
#define SESSION_TIMEOUT 2000
|
||||
|
||||
#define PORTS 9
|
||||
#define NSFP 1
|
||||
|
||||
#define N_COUNTERS 52
|
||||
|
||||
#if PORTS == 9
|
||||
const uint8_t physToLogPort[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
#else
|
||||
const uint8_t physToLogPort[] = { 4, 5, 6, 7, 3, 8};
|
||||
#endif
|
||||
|
||||
struct l2_entry {
|
||||
char mac[18];
|
||||
char vlan[4];
|
||||
char type;
|
||||
uint8_t port;
|
||||
uint16_t idx;
|
||||
};
|
||||
|
||||
#define L2_ENTRY_NUM 12
|
||||
#define L2_MAX_TRANSFER 5
|
||||
const struct l2_entry l2_entries[12] = {
|
||||
{ "00:01:2f:00:00:01", "001", 'l', 7, 0x10 },
|
||||
{ "00:06:78:00:00:02", "001", 'l', 7, 0x20 },
|
||||
{ "00:01:2e:00:00:03", "001", 's', 7, 0x30 },
|
||||
{ "60:7d:09:00:00:04", "001", 'l', 7, 0x40 },
|
||||
{ "1c:2a:a3:00:00:05", "001", 'l', 7, 0x50 },
|
||||
{ "1c:2a:a3:00:00:06", "001", 's', 7, 0x60 },
|
||||
{ "02:e0:4c:00:00:07", "001", 'l', 7, 0x70 },
|
||||
{ "00:e0:4c:00:00:08", "001", 'l', 4, 0x80 },
|
||||
{ "1c:2a:a3:00:00:09", "001", 'l', 9, 0x90 }, // CPU-Port
|
||||
{ "3c:8c:f8:00:00:0a", "001", 'l', 7, 0xa0 },
|
||||
{ "00:01:2e:00:00:0b", "001", 'l', 7, 0xb0 },
|
||||
{ "00:01:2f:00:01:01", "001", 'l', 7, 0xc0 }
|
||||
};
|
||||
|
||||
time_t last_called;
|
||||
time_t last_session_use;
|
||||
|
||||
uint64_t txG[PORTS], txB[PORTS], rxG[PORTS], rxB[PORTS];
|
||||
char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20], counter_buf[20], counter_name[20];
|
||||
char sfp_temp[8], sfp_vcc[8], sfp_txbias[8], sfp_txpower[8], sfp_rxpower[8], sfp_laser[8], sfp_options[6];
|
||||
char num_buff[20];
|
||||
char l2_idx_buff[20];
|
||||
char upload_buffer[4194304]; // 4MB
|
||||
|
||||
char *content_type = NULL;
|
||||
char boundary[72];
|
||||
char cmd_history[1024][256];
|
||||
uint16_t cmd_ptr = 0;
|
||||
char *uploaded_config = NULL;
|
||||
int uploaded_config_len;
|
||||
const char *session = NULL;
|
||||
bool authenticated = false;
|
||||
|
||||
char is_word(char *c, char *d)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
while (d[i] && (d[i] == c[i]))
|
||||
i++;
|
||||
|
||||
if (d[i])
|
||||
return 0;
|
||||
if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int hasSuffix(const char *str, const char *suffix)
|
||||
{
|
||||
if (!str || !suffix)
|
||||
return 0;
|
||||
|
||||
size_t lenstr = strlen(str);
|
||||
size_t lensuffix = strlen(suffix);
|
||||
|
||||
if (lensuffix > lenstr)
|
||||
return 0;
|
||||
|
||||
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
|
||||
}
|
||||
|
||||
|
||||
char *getMime(const char *name)
|
||||
{
|
||||
if (hasSuffix(name, ".html"))
|
||||
return "text/html";
|
||||
else if (hasSuffix(name, ".svg"))
|
||||
return "image/svg+xml";
|
||||
else if (hasSuffix(name, ".ico"))
|
||||
return "image/svg+xml";
|
||||
else if (hasSuffix(name, ".png"))
|
||||
return "image/png";
|
||||
else if (hasSuffix(name, ".js"))
|
||||
return "text/javascript";
|
||||
else if (hasSuffix(name, ".css"))
|
||||
return "text/css";
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
void send_basic_info(int socket)
|
||||
{
|
||||
char *response = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n"
|
||||
"{\"ip_address\":\"192.168.10.247\",\"ip_gateway\":\"192.168.2.22\",\"ip_netmask\":\"255.255.255.0\",\"mac_address\":\"1c:2a:a3:23:00:02\",\"sw_ver\":\"" VERSION_SW "\",\"hw_ver\":\"SWGT024-V2.0\"}";
|
||||
write(socket, response, strlen(response));
|
||||
}
|
||||
|
||||
void send_vlan(int s, int vlan)
|
||||
{
|
||||
struct json_object *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
v = json_object_new_object();
|
||||
|
||||
sprintf(num_buff, "0x%08x", 0x00060011);
|
||||
json_object_object_add(v, "members", json_object_new_string(num_buff));
|
||||
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(v, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(v);
|
||||
}
|
||||
|
||||
|
||||
void send_status(int s)
|
||||
{
|
||||
struct json_object *ports, *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
printf("Sending status.\n");
|
||||
time_t now = time(NULL);
|
||||
now = last_called ? last_called + 1 : now; // Make sure we don't divide by 0 for rates
|
||||
|
||||
ports = json_object_new_array_ext(PORTS);
|
||||
for (int i = 1; i <= PORTS; i++) {
|
||||
v = json_object_new_object();
|
||||
json_object_object_add(v, "portNum", json_object_new_int(i));
|
||||
json_object_object_add(v, "logPort", json_object_new_int(physToLogPort[i-1]));
|
||||
json_object_object_add(v, "isSFP", json_object_new_int(i <= PORTS - NSFP ? 0 : 1));
|
||||
json_object_object_add(v, "enabled", json_object_new_int((i % 4) ? 1 : 0));
|
||||
json_object_object_add(v, "link", json_object_new_int(i % 2 ? ((i == 1)? 5 : 2) : 0));
|
||||
if (i % 2) {
|
||||
uint64_t rate = (i == 1) ? 2400000000 : 950000000;
|
||||
txG[i-1] += rate * (now - last_called);
|
||||
rxG[i-1] += rate * (now - last_called);
|
||||
txB[i-1] += rate * (now - last_called) / 10000000;
|
||||
rxB[i-1] += rate * (now - last_called) / 10000000;
|
||||
}
|
||||
sprintf(txG_buff, "0x%016lx", txG[i-1]);
|
||||
sprintf(txB_buff, "0x%016lx", txB[i-1]);
|
||||
sprintf(rxG_buff, "0x%016lx", rxG[i-1]);
|
||||
sprintf(rxB_buff, "0x%016lx", rxB[i-1]);
|
||||
json_object_object_add(v, "txG", json_object_new_string(txG_buff));
|
||||
json_object_object_add(v, "txB", json_object_new_string(txB_buff));
|
||||
json_object_object_add(v, "rxG", json_object_new_string(rxG_buff));
|
||||
json_object_object_add(v, "rxB", json_object_new_string(rxB_buff));
|
||||
if (i >= PORTS - NSFP) {
|
||||
uint16_t temp = 0x28fb + rand() / (RAND_MAX / 100);
|
||||
uint16_t vcc = 0x7eda + rand() / (RAND_MAX / 100);
|
||||
uint16_t txbias = 0x0d24 +rand() / (RAND_MAX / 100);
|
||||
uint16_t txpower = 0x14bd + rand() / (RAND_MAX / 100);
|
||||
uint16_t rxpower = 0;
|
||||
uint16_t laser = 0;
|
||||
uint16_t options = 0x68;
|
||||
|
||||
sprintf(sfp_options, "0x%02x", options);
|
||||
sprintf(sfp_temp, "0x%04x", temp);
|
||||
sprintf(sfp_vcc, "0x%04x", vcc);
|
||||
sprintf(sfp_txbias, "0x%04x", txbias);
|
||||
sprintf(sfp_txpower, "0x%04x", txpower);
|
||||
sprintf(sfp_rxpower, "0x%04x", rxpower);
|
||||
sprintf(sfp_laser, "0x%04x", laser);
|
||||
json_object_object_add(v, "sfp_vendor", json_object_new_string("OEM"));
|
||||
json_object_object_add(v, "sfp_model", json_object_new_string("10G-SFP+"));
|
||||
json_object_object_add(v, "sfp_serial", json_object_new_string("12345678"));
|
||||
json_object_object_add(v, "sfp_options", json_object_new_string(sfp_options));
|
||||
json_object_object_add(v, "sfp_temp", json_object_new_string(sfp_temp));
|
||||
json_object_object_add(v, "sfp_vcc", json_object_new_string(sfp_vcc));
|
||||
json_object_object_add(v, "sfp_txbias", json_object_new_string(sfp_txbias));
|
||||
json_object_object_add(v, "sfp_txpower", json_object_new_string(sfp_txpower));
|
||||
json_object_object_add(v, "sfp_rxpower", json_object_new_string(sfp_rxpower));
|
||||
json_object_object_add(v, "sfp_laser", json_object_new_string(sfp_laser));
|
||||
} else {
|
||||
if (i == 1)
|
||||
json_object_object_add(v, "adv", json_object_new_string("100000"));
|
||||
else if (i==2)
|
||||
json_object_object_add(v, "adv", json_object_new_string("000011"));
|
||||
else
|
||||
json_object_object_add(v, "adv", json_object_new_string("000100"));
|
||||
|
||||
}
|
||||
json_object_array_add(ports, v);
|
||||
}
|
||||
last_called = now;
|
||||
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(ports, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(v);
|
||||
}
|
||||
|
||||
|
||||
void send_counters(int s, int port)
|
||||
{
|
||||
struct json_object *v, *counters;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
printf("Sending counters\n");
|
||||
counters = json_object_new_array_ext(N_COUNTERS);
|
||||
|
||||
for (int i = 0; i < N_COUNTERS; i++) {
|
||||
v = json_object_new_object();
|
||||
sprintf(counter_buf, "0x%016lx", 0x1234UL + i);
|
||||
json_object_array_add(counters, json_object_new_string(counter_buf));
|
||||
}
|
||||
write(s, header, strlen(header));
|
||||
jstring = json_object_to_json_string_ext(counters, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(counters);
|
||||
}
|
||||
|
||||
|
||||
void send_eee(int s)
|
||||
{
|
||||
struct json_object *ports, *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
ports = json_object_new_array_ext(PORTS);
|
||||
for (int i = 1; i <= PORTS; i++) {
|
||||
v = json_object_new_object();
|
||||
json_object_object_add(v, "portNum", json_object_new_int(i));
|
||||
json_object_object_add(v, "isSFP", json_object_new_int(i < 5 ? 0 : 1));
|
||||
uint8_t eee = 0;
|
||||
eee |= 0x02;
|
||||
char eee_buf[20];
|
||||
sprintf(eee_buf, "%08b", eee);
|
||||
json_object_object_add(v, "eee", json_object_new_string(eee_buf));
|
||||
uint8_t eee_lp = 0;
|
||||
eee_lp |= 0x04;
|
||||
sprintf(eee_buf, "%08b", eee_lp);
|
||||
json_object_object_add(v, "eee_lp", json_object_new_string(eee_buf));
|
||||
json_object_object_add(v, "active", json_object_new_int((i % 2) ? 1 : 0));
|
||||
json_object_array_add(ports, v);
|
||||
}
|
||||
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(ports, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(ports);
|
||||
}
|
||||
|
||||
|
||||
void send_mirror(int s)
|
||||
{
|
||||
uint16_t mirror_tx, mirror_rx = 0;
|
||||
char mirror_tx_buf[20];
|
||||
char mirror_rx_buf[20];
|
||||
struct json_object *mirror;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
mirror = json_object_new_object();
|
||||
json_object_object_add(mirror, "mPort", json_object_new_int(1));
|
||||
json_object_object_add(mirror, "enabled", json_object_new_int(1));
|
||||
|
||||
mirror_tx = 0b000110;
|
||||
mirror_rx = 0b000010;
|
||||
sprintf(mirror_tx_buf, "%016b", mirror_tx);
|
||||
sprintf(mirror_rx_buf, "%016b", mirror_rx);
|
||||
json_object_object_add(mirror, "mirror_tx", json_object_new_string(mirror_tx_buf));
|
||||
json_object_object_add(mirror, "mirror_rx", json_object_new_string(mirror_rx_buf));
|
||||
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(mirror, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(mirror);
|
||||
}
|
||||
|
||||
|
||||
void send_l2(int s, int idx)
|
||||
{
|
||||
struct json_object *entries, *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
entries = json_object_new_array();
|
||||
|
||||
// We find the next entry to transfer based on the index
|
||||
printf("Starting with idx %04x\n", idx);
|
||||
int j = 0;
|
||||
while (j < L2_ENTRY_NUM && l2_entries[j].idx < idx)
|
||||
j++;
|
||||
|
||||
printf("First entry %d, idx: %04x\n", j, l2_entries[j].idx);
|
||||
int transferred = 0;
|
||||
while ((j < L2_ENTRY_NUM + 1) && (transferred < L2_MAX_TRANSFER)) {
|
||||
// if (rand() / (RAND_MAX / 2) >= 1)
|
||||
// continue;
|
||||
int i = j % L2_ENTRY_NUM;
|
||||
printf("Entry %d, idx: %04x, transferred %d\n", i, l2_entries[i].idx, transferred);
|
||||
v = json_object_new_object();
|
||||
json_object_object_add(v, "mac", json_object_new_string(l2_entries[i].mac));
|
||||
json_object_object_add(v, "vlan", json_object_new_string(l2_entries[i].vlan));
|
||||
if (l2_entries[i].type == 'l')
|
||||
json_object_object_add(v, "type", json_object_new_string("l"));
|
||||
else
|
||||
json_object_object_add(v, "type", json_object_new_string("s"));
|
||||
json_object_object_add(v, "port", json_object_new_int(l2_entries[i].port));
|
||||
sprintf(l2_idx_buff, "%04x", l2_entries[i].idx);
|
||||
json_object_object_add(v, "idx", json_object_new_string(l2_idx_buff));
|
||||
json_object_array_add(entries, v);
|
||||
j++;
|
||||
transferred++;
|
||||
printf("j %d, transferred %d\n", j, transferred);
|
||||
}
|
||||
|
||||
write(s, header, strlen(header));
|
||||
jstring = json_object_to_json_string_ext(entries, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(entries);
|
||||
}
|
||||
|
||||
|
||||
void send_lag(int s)
|
||||
{
|
||||
char lag_buf[20];
|
||||
struct json_object *lags = json_object_new_array_ext(4);
|
||||
struct json_object *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v = json_object_new_object();
|
||||
json_object_object_add(v, "lagNum", json_object_new_int(i));
|
||||
sprintf(lag_buf, "%016b", 0x30 << (i * 2) & 0x1f8);
|
||||
json_object_object_add(v, "members", json_object_new_string(lag_buf));
|
||||
json_object_object_add(v, "hash", json_object_new_string("0x7e"));
|
||||
json_object_array_add(lags, v);
|
||||
}
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(lags, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(lags);
|
||||
}
|
||||
|
||||
|
||||
void send_mtu(int s)
|
||||
{
|
||||
struct json_object *mtus, *v;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
mtus = json_object_new_array_ext(PORTS);
|
||||
char mtu[8];
|
||||
for (int i = 1; i <= PORTS; i++) {
|
||||
v = json_object_new_object();
|
||||
json_object_object_add(v, "portNum", json_object_new_int(i));
|
||||
sprintf(mtu, "0x%04x", i % 2 ? 16383 : 1522);
|
||||
json_object_object_add(v, "mtu", json_object_new_string(mtu));
|
||||
json_object_array_add(mtus, v);
|
||||
}
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(mtus, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(mtus);
|
||||
}
|
||||
|
||||
|
||||
void send_cmd_log(int s)
|
||||
{
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\r\n\r\n";
|
||||
write(s, header, strlen(header));
|
||||
|
||||
for (int i = 0; i < cmd_ptr; i++) {
|
||||
write(s, cmd_history[i], strlen(cmd_history[i]));
|
||||
write(s, "\n", 1);
|
||||
printf("%d: %s\n", i, cmd_history[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_config(int s)
|
||||
{
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\r\n\r\n";
|
||||
printf("Sending uploaded config\n");
|
||||
write(s, header, strlen(header));
|
||||
printf("Uploaded config len: %d\n", uploaded_config_len);
|
||||
printf(">%s<", uploaded_config);
|
||||
write(s, uploaded_config, uploaded_config_len);
|
||||
}
|
||||
|
||||
|
||||
struct Server serverConstructor(int port, void (*launch)(struct Server *server)) {
|
||||
struct Server server;
|
||||
|
||||
server.domain = AF_INET;
|
||||
server.service = SOCK_STREAM;
|
||||
server.port = port;
|
||||
server.protocol = 0;
|
||||
server.backlog = 10;
|
||||
|
||||
server.address.sin_family = server.domain;
|
||||
server.address.sin_port = htons(port);
|
||||
server.address.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
server.socket = socket(server.domain, server.service, server.protocol);
|
||||
if (server.socket < 0) {
|
||||
perror("Failed to initialize/connect to socket...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bind(server.socket, (struct sockaddr*)&server.address, sizeof(server.address)) < 0) {
|
||||
perror("Failed to bind socket...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (listen(server.socket, server.backlog) < 0) {
|
||||
perror("Failed to start listening...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server.launch = launch;
|
||||
return server;
|
||||
}
|
||||
|
||||
void send_not_found(int socket) {
|
||||
char *response = "HTTP/1.1 404 Not found\r\n"
|
||||
"Content-Type: text/html\r\n\r\n"
|
||||
"<!DOCTYPE html> <html><head><title>Not Found</title></head>"
|
||||
"<body><h1>Not found!</h1></html>";
|
||||
write(socket, response, strlen(response));
|
||||
}
|
||||
|
||||
|
||||
void send_bad_request(int socket) {
|
||||
char *response = "HTTP/1.1 400 Bad Request\r\n"
|
||||
"Content-Type: text/html\r\n\r\n"
|
||||
"<!DOCTYPE html> <html><head><title>Bad Request</title></head>"
|
||||
"<body><h1>Bad Request!</h1></html>";
|
||||
write(socket, response, strlen(response));
|
||||
}
|
||||
|
||||
|
||||
void send_to_login(int socket) {
|
||||
char *response = "HTTP/1.1 302 Found\r\n"
|
||||
"Location: login.html\r\n\r\n";
|
||||
write(socket, response, strlen(response));
|
||||
}
|
||||
|
||||
|
||||
void send_unauthorized(int socket) {
|
||||
char *response = "HTTP/1.1 401 Unauthorized\r\n\r\n";
|
||||
write(socket, response, strlen(response));
|
||||
}
|
||||
|
||||
|
||||
char *scan_header(char *p)
|
||||
{
|
||||
session = 0;
|
||||
authenticated = false;
|
||||
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
||||
if (!*p++)
|
||||
break;
|
||||
if (is_word(p, "\nContent-Type:"))
|
||||
content_type = p + 15;
|
||||
else if (is_word(p, "\nCookie:"))
|
||||
session = p + 17;
|
||||
}
|
||||
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
|
||||
printf("Found multiplart\n");
|
||||
content_type += 30;
|
||||
uint8_t i = 0;
|
||||
while (content_type[i] != '\r' && content_type[i] != '\n') {
|
||||
boundary[i + 2] = content_type[i];
|
||||
i++;
|
||||
}
|
||||
// The boundary between parts is "--" + the boundary given in the header
|
||||
boundary[0] = '-';
|
||||
boundary[1] = '-';
|
||||
boundary[i + 2] = 0;
|
||||
}
|
||||
|
||||
time_t now = time(NULL);
|
||||
if (session) {
|
||||
printf("Session: >%s<. time now: %ld last %ld\n", session, now, last_session_use);
|
||||
if (now - last_session_use > SESSION_TIMEOUT) {
|
||||
printf("Session expired\n");
|
||||
} else {
|
||||
if (!strncmp(session, SESSION_ID, 12))
|
||||
authenticated = true;
|
||||
else
|
||||
printf("Invalid session cookie!\n");
|
||||
}
|
||||
}
|
||||
printf("Time now: %ld last %ld\n", now, last_session_use);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
char *skip_boundary(char *p)
|
||||
{
|
||||
while (*p) {
|
||||
if (is_word(p, boundary))
|
||||
return p + strlen(boundary);
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void print_cmd_history(void)
|
||||
{
|
||||
for (int i = 0; i < cmd_ptr; i++)
|
||||
printf("%d: %s\n", i, cmd_history[i]);
|
||||
}
|
||||
|
||||
void launch(struct Server *server)
|
||||
{
|
||||
char buffer[BUFFER_SIZE];
|
||||
FILE *inptr;
|
||||
|
||||
last_called = time(NULL);
|
||||
for (int i=0; i < PORTS; i++)
|
||||
txG[i] = txB[i] = rxG[i] = rxB[i] = 0;
|
||||
|
||||
while (1) {
|
||||
printf("=== Waiting for connection on port %d === \n", server->port);
|
||||
int addrlen = sizeof(server->address);
|
||||
int new_socket = accept(server->socket, (struct sockaddr*)&server->address, (socklen_t*)&addrlen);
|
||||
ssize_t bytesRead = read(new_socket, buffer, BUFFER_SIZE - 1);
|
||||
printf("bytesRead: %ld\n", bytesRead);
|
||||
int filesize = 0;
|
||||
char *mime;
|
||||
|
||||
if (bytesRead > 0) {
|
||||
buffer[bytesRead] = '\0'; // Null terminate the string
|
||||
puts(buffer);
|
||||
|
||||
if (is_word(buffer, "GET")) {
|
||||
scan_header(buffer);
|
||||
if (!strncmp(&buffer[4], "/status.json", 12)) {
|
||||
printf("Status request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_status(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/eee.json", 9)) {
|
||||
printf("EEE request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_eee(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/information.json", 17)) {
|
||||
printf("Status request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_basic_info(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/mirror.json", 12)) {
|
||||
printf("Mirror request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_mirror(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/lag.json", 9)) {
|
||||
printf("LAG request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_lag(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/l2.json?idx=", 13)) {
|
||||
int idx = atoi(&buffer[17]);
|
||||
printf("L2 request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_l2(new_socket, idx);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/mtu.json", 9)) {
|
||||
printf("MTU request\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_mtu(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/vlan.json?vid=", 15)) {
|
||||
int vlan = atoi(&buffer[19]);
|
||||
printf("VLAN request for %d\n", vlan);
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_vlan(new_socket, vlan);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/cmd_log", 8)) {
|
||||
printf("Request cmd_log\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_cmd_log(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/config ", 8) && uploaded_config) {
|
||||
printf("Request current config.\n");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_config(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/counters.json?port=", 20)) {
|
||||
int port = atoi(&buffer[24]);
|
||||
printf("Counters request for %d\n", port);
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_counters(new_socket, port);
|
||||
goto done;
|
||||
}
|
||||
if (!authenticated && !(!strncmp(&buffer[4], "/login.html", 11) || !strncmp(&buffer[4], "/style.css", 10))) {
|
||||
send_to_login(new_socket);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// A web-page is actively accessed, we can reset session time-out
|
||||
last_session_use = time(NULL);
|
||||
|
||||
int i = 0;
|
||||
while (!isspace(buffer[4 + i]))
|
||||
i++;
|
||||
buffer[4+i] = '\0';
|
||||
|
||||
printf("Serving file: >%s<, name length %d\n", &buffer[5], i);
|
||||
if (i > 1)
|
||||
inptr = fopen(&buffer[5], "rb");
|
||||
else
|
||||
inptr = fopen("/index.html", "rb");
|
||||
if (inptr == NULL) {
|
||||
printf("Cannot open input file %s\n", &buffer[5]);
|
||||
send_not_found(new_socket);
|
||||
goto done;
|
||||
}
|
||||
|
||||
mime = getMime(&buffer[5]);
|
||||
printf("MIME type: %s\n", mime);
|
||||
|
||||
fseek(inptr, 0L, SEEK_END);
|
||||
filesize = ftell(inptr);
|
||||
printf("Filesize: %d\n", filesize);
|
||||
rewind(inptr);
|
||||
printf("Input file size: %d\n", filesize);
|
||||
if (filesize > BUFFER_SIZE) {
|
||||
printf("File too large.\n");
|
||||
goto done;
|
||||
}
|
||||
size_t bytes_read = fread(buffer, 1, sizeof(buffer), inptr);
|
||||
|
||||
printf("Bytes read: %ld\n", bytes_read);
|
||||
|
||||
if (bytes_read != filesize) {
|
||||
printf("Error reading input file.\n");
|
||||
goto done;
|
||||
}
|
||||
fclose(inptr);
|
||||
} else if (is_word(buffer, "POST")) {
|
||||
printf("POST request\n");
|
||||
// Find end of request header
|
||||
char *p = buffer;
|
||||
boundary[0] ='\0';
|
||||
p = scan_header(p);
|
||||
printf("Boundary: >%s<\n", boundary);
|
||||
if (!*p || !content_type) {
|
||||
printf("Bad request, no content type!\n");
|
||||
send_bad_request(new_socket);
|
||||
goto done;
|
||||
}
|
||||
if (!authenticated && !is_word(&buffer[5], "/login")) {
|
||||
send_unauthorized(new_socket);
|
||||
goto done;
|
||||
}
|
||||
printf("Bytes read %ld\n", bytesRead);
|
||||
if (is_word(&buffer[5], "/cmd")) {
|
||||
printf("POST cmd\n");
|
||||
printf("CMD: %s\n", p + 4);
|
||||
strcpy(cmd_history[cmd_ptr], p + 4);
|
||||
cmd_ptr++;
|
||||
print_cmd_history();
|
||||
char *response = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n\r\n"
|
||||
"<!DOCTYPE html> <html><head><title>Upload OK</title></head>"
|
||||
"<body><h1>Command executed successully</h1></html>";
|
||||
write(new_socket, response, strlen(response));
|
||||
goto done;
|
||||
} else if (is_word(&buffer[5], "/login")) {
|
||||
printf("POST login\n");
|
||||
p += 4;
|
||||
p += 4; // Read also over "pwd="
|
||||
char *response;
|
||||
if (is_word(p, PASSWORD)) {
|
||||
printf("Password accepted!\n");
|
||||
response = "HTTP/1.1 302 Found\r\n"
|
||||
"Location: index.html\r\n"
|
||||
"Set-Cookie: session=" SESSION_ID "; SameSite=Strict\r\n";
|
||||
} else {
|
||||
response = "HTTP/1.1 302 Found\r\n"
|
||||
"Location: login.html\r\n\r\n";
|
||||
}
|
||||
write(new_socket, response, strlen(response));
|
||||
goto done;
|
||||
} else if (is_word(&buffer[5], "/upload") || is_word(&buffer[5], "/config")) {
|
||||
printf("POST upload/config request\n");
|
||||
bool config_upload = false;
|
||||
if (is_word(&buffer[5], "/config"))
|
||||
config_upload = true;
|
||||
if (!boundary[0]) {
|
||||
printf("Bad request, no boundary!\n");
|
||||
send_bad_request(new_socket);
|
||||
goto done;
|
||||
}
|
||||
// We skip the intial parts as part of the header
|
||||
do {
|
||||
p = skip_boundary(p);
|
||||
if (!*p)
|
||||
goto bad_request;
|
||||
p = scan_header(p);
|
||||
if (!*p || !content_type)
|
||||
goto bad_request;
|
||||
} while (!is_word(content_type, "application/octet-stream"));
|
||||
printf("Have content: >%s<\n", content_type);
|
||||
|
||||
p += 4; // Skip \r\n\r\n after content type
|
||||
char *uptr = upload_buffer;
|
||||
int bindex = 0;
|
||||
int bptr = p - buffer;
|
||||
do {
|
||||
if (bptr >= bytesRead) {
|
||||
bptr = 0;
|
||||
bytesRead = read(new_socket, buffer, BUFFER_SIZE - 1);
|
||||
printf("bytesRead: %ld\n", bytesRead);
|
||||
if (!bytesRead)
|
||||
break;
|
||||
}
|
||||
if (!boundary[bindex])
|
||||
break;
|
||||
if (buffer[bptr] == boundary[bindex]) {
|
||||
bptr++;
|
||||
bindex++;
|
||||
} else {
|
||||
for (int i = 0; i < bindex; i++)
|
||||
*uptr++ = boundary[i];
|
||||
*uptr++ = buffer[bptr++];
|
||||
bindex = 0;
|
||||
}
|
||||
} while(1);
|
||||
printf("Done reading\n");
|
||||
printf("%s", upload_buffer);
|
||||
if (!bindex || boundary[bindex])
|
||||
goto bad_request;
|
||||
char *response = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n\r\n"
|
||||
"<!DOCTYPE html> <html><head><title>Upload OK</title></head>"
|
||||
"<body><h1>File uploaded successully</h1></html>";
|
||||
write(new_socket, response, strlen(response));
|
||||
if (config_upload) {
|
||||
uploaded_config_len = (uptr - upload_buffer);
|
||||
if (uploaded_config)
|
||||
free (uploaded_config);
|
||||
uploaded_config = malloc(uploaded_config_len + 1);
|
||||
memcpy(uploaded_config, upload_buffer, uploaded_config_len);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
char *response = "HTTP/1.1 200 OK\r\n"
|
||||
"Cache-Control: max-age=60, must-revalidate\r\n"
|
||||
"Content-Type: ";
|
||||
write(new_socket, response, strlen(response));
|
||||
|
||||
write(new_socket, mime, strlen(mime));
|
||||
response = "; charset=UTF-8\r\n\r\n";
|
||||
write(new_socket, response, strlen(response));
|
||||
if (filesize)
|
||||
write(new_socket, buffer, filesize);
|
||||
} else if (bytesRead == 0) {
|
||||
printf("EOF\n");
|
||||
continue;
|
||||
} else {
|
||||
perror("Error reading buffer, nothing read...\n");
|
||||
}
|
||||
|
||||
done:
|
||||
close(new_socket);
|
||||
continue;
|
||||
bad_request:
|
||||
printf("Bad request!\n");
|
||||
send_bad_request(new_socket);
|
||||
close(new_socket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// Make sure we can handle writes to a dead client without a signal handler
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
struct Server server = serverConstructor(8080, launch);
|
||||
server.launch(&server);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define BUFFER_SIZE 24000
|
||||
|
||||
struct Server {
|
||||
int domain;
|
||||
int port;
|
||||
int service;
|
||||
int protocol;
|
||||
int backlog;
|
||||
u_long interface;
|
||||
|
||||
int socket;
|
||||
struct sockaddr_in address;
|
||||
|
||||
void (*launch)(struct Server *server);
|
||||
};
|
||||
|
||||
struct Server server_Constructor(int port, void (*launch)(struct Server *server));
|
||||
void launch(struct Server *server);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Adds data files into specified locations of an image, optionally creates
|
||||
* an index in the form of a header file
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <argp.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#define OFFSET 2
|
||||
#define BANK0_SIZE 0x4000
|
||||
#define BANK_SIZE 0xc000
|
||||
#define BANK_STRIDE 0x10000
|
||||
|
||||
// Use a 4MB buffer, the maximum flash rom size
|
||||
#define BUFFER_SIZE 0x400000
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
FILE *inptr;
|
||||
int outptr;
|
||||
|
||||
const char *argp_program_version = "imagebuilder 0.1";
|
||||
const char *argp_program_bug_address = "<git@logicog.de>";
|
||||
static char doc[] = "Create an image with multiple banks for RTL837X-based switches";
|
||||
static char args_doc[] = "INPUT_IMAGE";
|
||||
static struct argp_option options[] = {
|
||||
{ "input", 'i', "FILE", 0, "Input file"},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
struct arguments {
|
||||
char *input_file;
|
||||
};
|
||||
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct arguments *arguments = state->input;
|
||||
switch (key) {
|
||||
case 'i':
|
||||
arguments->input_file = arg;
|
||||
break;
|
||||
case ARGP_KEY_END:
|
||||
if (state->arg_num < 1) // Expect 1 command line argument at end
|
||||
argp_usage(state);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct argp argp = {
|
||||
options, parse_opt, args_doc, doc, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct arguments arguments;
|
||||
int arg_index;
|
||||
|
||||
arguments.input_file = NULL;
|
||||
|
||||
argp_parse(&argp, argc, argv, 0, &arg_index, &arguments);
|
||||
|
||||
memset(buffer, 0, BUFFER_SIZE);
|
||||
|
||||
size_t filesize = 0;
|
||||
inptr = fopen(arguments.input_file, "rb");
|
||||
if (inptr == NULL) {
|
||||
printf("Cannot open input file %s\n", arguments.input_file);
|
||||
return 5;
|
||||
}
|
||||
|
||||
fseek(inptr, 0L, SEEK_END);
|
||||
filesize = ftell(inptr);
|
||||
rewind(inptr);
|
||||
printf("Input file size: %ld\n", filesize);
|
||||
if (filesize > BUFFER_SIZE) {
|
||||
printf("File too large.\n");
|
||||
return 5;
|
||||
}
|
||||
|
||||
int nbanks = (filesize - BANK0_SIZE) / BANK_STRIDE;
|
||||
printf("Input file contains %d banks\n", nbanks);
|
||||
|
||||
/* Verify the size of banks in input file:
|
||||
* Bank 0: 0x00002 - 0x04000 <- 0x00000 - 0x03ffe
|
||||
* Bank 1: 0x04000 - 0x10000 <- 0x14000 - 0x20000
|
||||
* Bank 2: 0x10000 - 0x1c000 <- 0x24000 - 0x33000
|
||||
* [...]
|
||||
* by verifying whether other than 0-bytes are found in the input
|
||||
* file after these ranges.
|
||||
*/
|
||||
size_t bytes_read = fread(buffer, 1, filesize, inptr);
|
||||
if (bytes_read != filesize) {
|
||||
printf("Error reading input file.\n");
|
||||
return 5;
|
||||
}
|
||||
for (int b = BANK0_SIZE; b < BANK_STRIDE + BANK0_SIZE; b ++) {
|
||||
if (buffer[b]) {
|
||||
printf("WARNING: Bank 0: code segment too large at 0x%x!\n", b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int bank = 1; bank <= nbanks; bank++) {
|
||||
for (int b = (bank + 1) * BANK_STRIDE; b < (bank + 1) * BANK_STRIDE + BANK0_SIZE; b ++) {
|
||||
if (buffer[b]) {
|
||||
printf("WARNING: Bank %d: code segment too large at 0x%x!\n", bank, b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rewind(inptr);
|
||||
memset(buffer, 0, BUFFER_SIZE);
|
||||
|
||||
// BANK0-Size
|
||||
buffer[0] = 0x00;
|
||||
buffer[1] = 0x40;
|
||||
|
||||
// Read bank 0
|
||||
bytes_read = fread(buffer + OFFSET, 1, BANK0_SIZE, inptr);
|
||||
printf("Bank 0: Bytes read: %ld\n", bytes_read);
|
||||
|
||||
if (bytes_read != BANK0_SIZE) {
|
||||
printf("Error reading input file.\n");
|
||||
return 5;
|
||||
}
|
||||
fseek(inptr, BANK_STRIDE, SEEK_CUR);
|
||||
|
||||
for (int bank = 1; bank <= nbanks; bank++) {
|
||||
bytes_read = fread(buffer + (bank - 1) * BANK_SIZE + BANK0_SIZE, 1, BANK_SIZE, inptr);
|
||||
printf("Bank %d: bytes read: %ld\n", bank, bytes_read);
|
||||
if (bank != nbanks)
|
||||
fseek(inptr, BANK0_SIZE, SEEK_CUR);
|
||||
}
|
||||
|
||||
fclose(inptr);
|
||||
|
||||
outptr = creat(argv[arg_index], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
|
||||
if (!outptr) {
|
||||
printf("Cannot open %s\n", argv[arg_index]);
|
||||
return 5;
|
||||
}
|
||||
|
||||
size_t written = write(outptr, buffer, (nbanks + 1) * BANK_STRIDE);
|
||||
|
||||
if (written != (nbanks + 1) * BANK_STRIDE) {
|
||||
printf("Error writing output file.\n");
|
||||
return 5;
|
||||
}
|
||||
close(outptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,26 +1,21 @@
|
||||
CC = sdcc
|
||||
CC_FLAGS = -mmcs51 -I. -I.. -I../httpd
|
||||
CC_FLAGS = -mmcs51 -I. -I../httpd
|
||||
ASM = sdas8051
|
||||
AFLAGS= -plosgff
|
||||
|
||||
BUILDDIR = output/
|
||||
|
||||
SRCS = timer.c uip_arp.c uip.c uip-fw.c uiplib.c uip-neighbor.c uip-split.c
|
||||
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
|
||||
OBJS = ${SRCS:.c=.rel}
|
||||
|
||||
all: create_build_dir $(OBJS)
|
||||
all: $(OBJS)
|
||||
|
||||
create_build_dir:
|
||||
mkdir -p $(BUILDDIR)
|
||||
%.rel: %.c
|
||||
$(CC) $(CC_FLAGS) -c $<
|
||||
|
||||
$(BUILDDIR)%.rel: %.c
|
||||
$(CC) $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
|
||||
%.rel: %.asm
|
||||
${ASM} ${AFLAGS} $^
|
||||
|
||||
clean:
|
||||
rm -r $(BUILDDIR)
|
||||
rm *.ihx *.lk *.lst *.map *.mem *.rel *.rst *.sym *.bin
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#define STATE_DATA_SENT 6
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
/*
|
||||
* Return value of the buffering functions that indicates that a
|
||||
|
||||