Author SHA1 Message Date
logicog 984831620c Use multiple concurrent TCP connections
This uses multiple concurrent TCP connections by making the state
of the connection including the output buffer a part of the application
data. This leads to the buffer, to be sent length of data and the already
sent data to be part of that state and must be handed over to functions
that generate data. At this point this leads to an overuse of OSEG and DSEG
memory space so further work needs to be done on tuning the code.
Putting it into a branch for now.
2025-08-06 17:00:14 +02:00
110 changed files with 1746 additions and 10987 deletions
-21
View File
@@ -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
-9
View File
@@ -1,9 +0,0 @@
.gitignore
.idea/
output/
html_data.c
html_data.h
version.h
tools/httpd_sim
tools/injector
tools/fileadder
-21
View File
@@ -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.
+25 -43
View File
@@ -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
+162 -89
View File
@@ -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)
+218 -857
View File
File diff suppressed because it is too large Load Diff
+2 -10
View File
@@ -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
-3
View File
@@ -1,3 +0,0 @@
ip 192.168.10.247
gw 192.168.10.1
netmask 255.255.255.0
-121
View File
@@ -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
+3 -3
View File
@@ -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
-18
View File
@@ -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
-391
View File
@@ -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;
}
-48
View File
@@ -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
+1 -8
View File
@@ -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
-133
View File
@@ -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.
-213
View File
@@ -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.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 MiB

-41
View File
@@ -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.
-58
View File
@@ -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.
-135
View File
@@ -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.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

+1 -4
View File
@@ -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),
-227
View File
@@ -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:
![Alt text](images/LAG_config.png?raw=true "Link Aggregation Web-Page")
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.
-46
View File
@@ -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 doesnt 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.
-25
View File
@@ -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/)
+25
View File
@@ -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
View File
@@ -1 +0,0 @@
../config.txt
-55
View File
@@ -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);
}
}
-25
View File
@@ -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>
-50
View File
@@ -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);
-18
View File
@@ -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}`);
}
}
+11 -19
View File
@@ -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>
-19
View File
@@ -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>
-139
View File
@@ -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);
});
-27
View File
@@ -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>
-78
View File
@@ -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}`);
}
}
-30
View File
@@ -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>
-117
View File
@@ -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) + "&#8239;&#8451;</td></tr>";
iHTML += "<tr><td>Vcc</td><td>:</td><td>" + (Number(p.sfp_vcc) / 10000.0).toFixed(2) + "&#8239;V</td></tr>";
iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + (Number(p.sfp_txbias) / 500.0).toFixed(1) + "&#8239;mA</td></tr>";
iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + (Number(p.sfp_txpower) / 10.0).toFixed(0) + "&#8239;mW</td></tr>";
iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + (Number(p.sfp_rxpower) / 10.0).toFixed(0) + "&#8239;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);
});
-22
View File
@@ -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));
});
-26
View File
@@ -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>
-61
View File
@@ -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();
}
-43
View File
@@ -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}`);
}
}
-11
View File
@@ -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>";
+3 -3
View File
@@ -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

-24
View File
@@ -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>
-146
View File
@@ -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);
+5 -5
View File
@@ -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

-47
View File
@@ -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>
-198
View File
@@ -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';
}
});
+11
View File
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Statistics</title>
</head>
<body>
<h1>Port configuration:</h1>
<p>#{stat_content}</p>
</body>
</html>
-164
View File
@@ -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}
-36
View File
@@ -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>
-76
View File
@@ -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);
});
-19
View File
@@ -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>
-35
View File
@@ -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>
-87
View File
@@ -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();
}
-35
View File
@@ -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}`);
}
}
+10 -13
View File
@@ -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
+95 -563
View File
@@ -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;
+5 -2
View File
@@ -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. */
+51 -678
View File
@@ -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;
}
-32
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/python
import re
import sys
-42
View File
@@ -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)
-26
View File
@@ -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
-385
View File
@@ -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);
}
-271
View File
@@ -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;
}
-238
View File
@@ -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
-72
View File
@@ -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
-58
View File
@@ -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
+4 -61
View File
@@ -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
+175 -112
View File
@@ -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();
}
+10 -9
View File
@@ -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
-374
View File
@@ -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
}
-12
View File
@@ -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
-296
View File
@@ -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");
}
-28
View File
@@ -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
+134 -378
View File
@@ -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);
}
+4 -21
View File
@@ -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
-120
View File
@@ -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));
}
-93
View File
@@ -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
+151 -310
View File
@@ -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);
}
+3 -24
View File
@@ -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
+32 -193
View File
@@ -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);
+6 -24
View File
@@ -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;
-239
View File
@@ -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);
}
-12
View File
@@ -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
+453 -799
View File
File diff suppressed because it is too large Load Diff
+6 -21
View File
@@ -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 $@
-179
View File
@@ -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;
}
+20 -26
View File
@@ -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) {
-854
View File
@@ -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;
}
-26
View File
@@ -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
-166
View File
@@ -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;
}
+7 -12
View File
@@ -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
-1
View File
@@ -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

Some files were not shown because too many files have changed in this diff Show More