Merge remote-tracking branch 'origin/main' into feat/session-timeout-config
No files matched your search
@@ -22,5 +22,9 @@ jobs:
|
|||||||
run: make -C test
|
run: make -C test
|
||||||
- name: Check if machine.c can be compiled for all machines
|
- name: Check if machine.c can be compiled for all machines
|
||||||
run: make machine_check
|
run: make machine_check
|
||||||
- name: Make project
|
- name: Make project (4x2/RTL8372)
|
||||||
run: make MACHINE="KP_9000_6XHML_X2"
|
run: make CI=1 MACHINE="KP_9000_6XHML_X2"
|
||||||
|
- name: Make project (8x1/RTL8373)
|
||||||
|
run: make CI=1 MACHINE="KP_9000_9XHML_X_V3_1"
|
||||||
|
- name: Make project with the health instrumentation
|
||||||
|
run: make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1
|
||||||
@@ -7,3 +7,7 @@ version.h
|
|||||||
tools/httpd_sim
|
tools/httpd_sim
|
||||||
tools/injector
|
tools/injector
|
||||||
tools/fileadder
|
tools/fileadder
|
||||||
|
|
||||||
|
# host-test stand-ins for the two generated headers
|
||||||
|
!test/stub/html_data.h
|
||||||
|
!test/stub/version.h
|
||||||
@@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
- Config
|
||||||
|
- A startup configuration line longer than the command buffer no longer stops the replay:
|
||||||
|
the offending line is skipped and the following lines are still applied.
|
||||||
|
- The web UI and the configuration upload now refuse a line the replay cannot take,
|
||||||
|
instead of writing it to flash.
|
||||||
|
|
||||||
## Breaking changes
|
## Breaking changes
|
||||||
|
|
||||||
- Config
|
- Config
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
python3 \
|
python3 \
|
||||||
libjson-c-dev \
|
libjson-c-dev \
|
||||||
git \
|
git \
|
||||||
|
zlib1g-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# git safe.directory for mounted repos (Makefile uses git describe)
|
# git safe.directory for mounted repos (Makefile uses git describe)
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ ifeq ($(MACHINE),)
|
|||||||
else
|
else
|
||||||
CC_FLAGS += -DMACHINE_$(MACHINE)
|
CC_FLAGS += -DMACHINE_$(MACHINE)
|
||||||
endif
|
endif
|
||||||
|
# Health instrumentation and the "health" console command: HEALTH=1 gmake ...
|
||||||
|
ifneq ($(HEALTH),)
|
||||||
|
CC_FLAGS += -DHEALTH
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CI),1)
|
||||||
|
CC_FLAGS += --Werror
|
||||||
|
endif
|
||||||
|
|
||||||
BUILDDIR = output/$(MACHINE)
|
BUILDDIR = output/$(MACHINE)
|
||||||
VERSION_HEADER := version.h
|
VERSION_HEADER := version.h
|
||||||
@@ -126,15 +134,25 @@ distclean: $(SUBDIRSCLEAN)
|
|||||||
$(SUBDIRSCLEAN):
|
$(SUBDIRSCLEAN):
|
||||||
$(MAKE) -C $(@:clean=) clean
|
$(MAKE) -C $(@:clean=) clean
|
||||||
|
|
||||||
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h
|
# Objects depend on the flags they were built with, through a stamp file that
|
||||||
|
# is rewritten only when CC_FLAGS actually changes.
|
||||||
|
CCFLAGS_STAMP := $(BUILDDIR)/.ccflags
|
||||||
|
|
||||||
|
.PHONY: FORCE
|
||||||
|
FORCE:
|
||||||
|
|
||||||
|
$(CCFLAGS_STAMP): FORCE | create_build_dir
|
||||||
|
@echo '$(CC_FLAGS)' | cmp -s - $@ 2>/dev/null || echo '$(CC_FLAGS)' > $@
|
||||||
|
|
||||||
|
$(BUILDDIR)/%.rel: %.c $(CCFLAGS_STAMP) | create_build_dir html_data.h
|
||||||
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||||
|
|
||||||
$(BUILDDIR)/%.rel: %.asm | create_build_dir
|
$(BUILDDIR)/%.rel: %.asm $(CCFLAGS_STAMP) | create_build_dir
|
||||||
${ASM} ${AFLAGS} -o $@ $<
|
${ASM} ${AFLAGS} -o $@ $<
|
||||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||||
|
|
||||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
||||||
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
$(CC) $(CC_FLAGS) --xram-size 49151 -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
||||||
|
|
||||||
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||||
objcopy --input-target=ihex -O binary $< $@
|
objcopy --input-target=ihex -O binary $< $@
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
A Playground for Firmware development for advanced user of RTL8372/RTL8373 based 2.5GBit Switches.
|
A Playground for Firmware development for advanced user of RTL8372/RTL8373 based 2.5GBit Switches.
|
||||||
|
|
||||||
For each hardware configuration of these devices, there is usually a managed and an
|
For each hardware configuration of these devices, there is usually a managed and an
|
||||||
umanaged version sold, with mostly identical hardware. The aim is to provide management
|
unmanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||||
features also for unmanaged devices with additional features such as Management VLAN,
|
features also for unmanaged devices with additional features such as Management VLAN,
|
||||||
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
DHCP servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||||
only the following features are provided:
|
only the following features are provided:
|
||||||
- A modern web-interface with mouse-over to display further information
|
- A modern web-interface with mouse-over to display further information
|
||||||
- A serial console interface to configure all features
|
- A serial console interface to configure all features
|
||||||
- IGMP to configure Multicast streaming
|
- IGMP to configure Multicast streaming
|
||||||
- Port configuration showing detailed informtion about own and Link-partner advertised
|
- Port configuration showing detailed information about own and Link-partner advertised
|
||||||
Speed settins and configuration of these settings on the local side
|
Speed settings and configuration of these settings on the local side
|
||||||
- Per-port configuration of frame sizes (MTUs) for Jumbo-Frame support or limiting MTUs
|
- Per-port configuration of frame sizes (MTUs) for Jumbo-Frame support or limiting MTUs
|
||||||
for particular devices
|
for particular devices
|
||||||
- EEE (Energy Efficient Ethernet) can be configured per-port. Detailed information is
|
- EEE (Energy Efficient Ethernet) can be configured per-port. Detailed information is
|
||||||
@@ -25,7 +25,7 @@ only the following features are provided:
|
|||||||
- Firmware updates via the web
|
- Firmware updates via the web
|
||||||
- Installation as a firmware upgrade from the original web-interface
|
- Installation as a firmware upgrade from the original web-interface
|
||||||
|
|
||||||
<img width="1420" height="623" alt="GUI" src="doc/images/gui.png" />
|
<img width="1673" height="977" alt="GUI" src="doc/images/gui.png" />
|
||||||
|
|
||||||
While the firmware provides already considerable improvements over the original managed firmware,
|
While the firmware provides already considerable improvements over the original managed firmware,
|
||||||
the firmware still lacks support for the proprietary loop prevention
|
the firmware still lacks support for the proprietary loop prevention
|
||||||
@@ -37,7 +37,7 @@ a backup of the original flash content via a SOIC clamp such as also used for BI
|
|||||||
backups and can re-install that firmware in case something is wrong. For this no soldering
|
backups and can re-install that firmware in case something is wrong. For this no soldering
|
||||||
skills are necessary.
|
skills are necessary.
|
||||||
|
|
||||||
The firmware supports all hardware featues of devices with
|
The firmware supports all hardware features of devices with
|
||||||
- 4 2.5GBit ports + 2 SFP+ ports
|
- 4 2.5GBit ports + 2 SFP+ ports
|
||||||
- 5 2.5GBIT + 1 SFP+ port
|
- 5 2.5GBIT + 1 SFP+ port
|
||||||
- 8 2.5GBit + 1 SFP+ port
|
- 8 2.5GBit + 1 SFP+ port
|
||||||
@@ -131,7 +131,7 @@ rtlplayground-v0.1.0-12c98ba-dirty-LIANGUO_ZX_SWTGW215AS.bin
|
|||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> This image can be flashed directly to the chip OR through the firmware update/upgrade
|
> This image can be flashed directly to the chip OR through the firmware update/upgrade
|
||||||
> interface of RTLPlaygound interface
|
> interface of RTLPlayground interface
|
||||||
|
|
||||||
## (2) Compiling for OEM running device with management options (web upgrade)
|
## (2) Compiling for OEM running device with management options (web upgrade)
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ ghidra see this information about [Ghidra images](doc/ghidra.md).
|
|||||||
|
|
||||||
## (4) Installation through the Web interface (software way)
|
## (4) Installation through the Web interface (software way)
|
||||||
|
|
||||||
Managed switches (OEM firmware of RTLplaygroud firmware) can be upgraded via the web interface.
|
Managed switches (OEM firmware of RTLplayground firmware) can be upgraded via the web interface.
|
||||||
Unmanaged switch cannot be flashed this way (see 5).
|
Unmanaged switch cannot be flashed this way (see 5).
|
||||||
|
|
||||||
Go to "Firmware update" tab, select the correct file.
|
Go to "Firmware update" tab, select the correct file.
|
||||||
@@ -190,7 +190,7 @@ Go to "Firmware update" tab, select the correct file.
|
|||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Check one more time that your device matches the machine type before flashing.
|
> Check one more time that your device matches the machine type before flashing.
|
||||||
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung.
|
> Be sure you have a backup of the original firmware before diving in RTLPlayground.
|
||||||
|
|
||||||
Finally, push the Upload File Button and you're done !
|
Finally, push the Upload File Button and you're done !
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ Finally, push the Upload File Button and you're done !
|
|||||||
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
|
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
|
||||||
|
|
||||||
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
|
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
|
||||||
This is also the only way to unbrick your device if something went wroong.
|
This is also the only way to unbrick your device if something went wrong.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
|
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
|
||||||
@@ -218,7 +218,7 @@ This is also the only way to unbrick your device if something went wroong.
|
|||||||
- ERASE THE ROM (BLANK) !
|
- ERASE THE ROM (BLANK) !
|
||||||
- Load the firmware into IMSProg.
|
- Load the firmware into IMSProg.
|
||||||
- Flash is to the ROM chip.
|
- Flash is to the ROM chip.
|
||||||
- Disconect the clip from the ROM chip.
|
- Disconnect the clip from the ROM chip.
|
||||||
- You're done, ready for the first boot.
|
- You're done, ready for the first boot.
|
||||||
|
|
||||||
## (6) Connecting a serial interface (optional)
|
## (6) Connecting a serial interface (optional)
|
||||||
@@ -233,7 +233,7 @@ When you power up the switch, the device will perform some examples and provide
|
|||||||
## (8) The web-interface
|
## (8) The web-interface
|
||||||
|
|
||||||
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
|
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
|
||||||
specified an IP adress in the config.txt before compilation.
|
specified an IP address in the config.txt before compilation.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> The default password is `1234`.
|
> The default password is `1234`.
|
||||||
@@ -333,13 +333,13 @@ While in compilation part, you might write directly to config.txt file before ma
|
|||||||
nano config.txt
|
nano config.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
|
If you want to modify settings after the flash is done, go to the System tab and find the Startup Configuration.
|
||||||
|
|
||||||
<img width="1085" height="646" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
|
<img width="1673" height="978" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
|
||||||
|
|
||||||
```
|
```
|
||||||
ip xxx.xxx.xxx.xxx = IP adress of the switch
|
ip xxx.xxx.xxx.xxx = IP address of the switch
|
||||||
gw yyy.yyy.yyy.yyy = IP adress of the gateway
|
gw yyy.yyy.yyy.yyy = IP address of the gateway
|
||||||
netmask zzz.zzz.zzz.zzz = Network mask of the switch
|
netmask zzz.zzz.zzz.zzz = Network mask of the switch
|
||||||
port x name xxx = Name xxx the port number x
|
port x name xxx = Name xxx the port number x
|
||||||
port z 1g = Set 1g speed for port z
|
port z 1g = Set 1g speed for port z
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ extern __code const struct machine machine;
|
|||||||
extern __xdata struct machine_runtime machine_detected;
|
extern __xdata struct machine_runtime machine_detected;
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
extern volatile __xdata uint32_t ticks;
|
extern volatile __xdata uint32_t ticks;
|
||||||
|
__xdata uint32_t rtl8224_release_tick;
|
||||||
extern __xdata uint8_t tx_seq;
|
extern __xdata uint8_t tx_seq;
|
||||||
extern __code uint8_t * __code hex;
|
extern __code const uint8_t * __code const hex;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -240,10 +241,10 @@ void rtl8224_enable(void) __banked
|
|||||||
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||||
// Configure Pin as output
|
// Configure Pin as output
|
||||||
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
|
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
|
||||||
delay(100);
|
delay(4);
|
||||||
// Set pin 4 high
|
// Set pin 4 high
|
||||||
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||||
delay(500);
|
rtl8224_release_tick = ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -397,10 +398,12 @@ void setup_i2c(void) __banked
|
|||||||
// HW Control register, enable I2C depending on PIN configuration
|
// HW Control register, enable I2C depending on PIN configuration
|
||||||
reg_read_m(RTL837X_PIN_MUX_1);
|
reg_read_m(RTL837X_PIN_MUX_1);
|
||||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||||
const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl);
|
uint8_t i2c = machine.sfp_port[sfp].i2c;
|
||||||
const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda);
|
uint8_t scl_bus = (i2c >> RTL837X_REG_I2C_SCL_SHIFT) & RTL837X_REG_I2C_SCL_MASK;
|
||||||
|
uint8_t sda_bus = (i2c >> RTL837X_REG_I2C_SDA_SHIFT) & RTL837X_REG_I2C_SDA_MASK;
|
||||||
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
|
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
|
||||||
switch (scl_bus) {
|
// `& RTL837X_REG_I2C_SCL_MASK` is needed to silens a compiler warning 110.
|
||||||
|
switch (scl_bus & RTL837X_REG_I2C_SCL_MASK) {
|
||||||
case 3:
|
case 3:
|
||||||
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
|
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
|
||||||
sfr_mask_data(0, 0x60, 0x40);
|
sfr_mask_data(0, 0x60, 0x40);
|
||||||
@@ -419,8 +422,6 @@ void setup_i2c(void) __banked
|
|||||||
sfr_mask_data(0, 0x80, 0x80);
|
sfr_mask_data(0, 0x80, 0x80);
|
||||||
sfr_mask_data(1, 0x01, 0x00);
|
sfr_mask_data(1, 0x01, 0x00);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sda_bus) {
|
switch (sda_bus) {
|
||||||
@@ -444,8 +445,6 @@ void setup_i2c(void) __banked
|
|||||||
// Bit 9-10 0b01 -> SDA
|
// Bit 9-10 0b01 -> SDA
|
||||||
sfr_mask_data(1, 0x06, 0x02);
|
sfr_mask_data(1, 0x06, 0x02);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reg_write_m(RTL837X_PIN_MUX_1);
|
reg_write_m(RTL837X_PIN_MUX_1);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
// #define REGDBG 1
|
// #define REGDBG 1
|
||||||
|
|
||||||
|
#include <8051.h>
|
||||||
|
#include "cmd_parser.h"
|
||||||
#include "rtl837x_common.h"
|
#include "rtl837x_common.h"
|
||||||
#include "rtl837x_port.h"
|
#include "rtl837x_port.h"
|
||||||
#include "rtl837x_flash.h"
|
#include "rtl837x_flash.h"
|
||||||
@@ -26,15 +28,15 @@
|
|||||||
#pragma codeseg BANK2
|
#pragma codeseg BANK2
|
||||||
#pragma constseg BANK2
|
#pragma constseg BANK2
|
||||||
|
|
||||||
extern __code struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata bool stp_enabled;
|
extern __xdata bool stp_enabled;
|
||||||
extern __code uint8_t log_to_phys_port[9];
|
extern __code const uint8_t log_to_phys_port[9];
|
||||||
|
|
||||||
extern volatile __xdata uint32_t ticks;
|
extern volatile __xdata uint32_t ticks;
|
||||||
extern volatile __xdata uint8_t sfr_data[4];
|
extern volatile __xdata uint8_t sfr_data[4];
|
||||||
|
|
||||||
extern __code uint8_t * __code greeting;
|
extern __code const uint8_t * __code const greeting;
|
||||||
extern __code uint8_t * __code hex;
|
extern __code const uint8_t * __code const hex;
|
||||||
|
|
||||||
extern __xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
extern __xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||||
extern __xdata struct flash_region_t flash_region;
|
extern __xdata struct flash_region_t flash_region;
|
||||||
@@ -61,7 +63,6 @@ __xdata uint8_t hexvalue[4] = { 0 };
|
|||||||
|
|
||||||
// Buffer for writing to flash 0x1fd000, copy to 0x1fe000
|
// Buffer for writing to flash 0x1fd000, copy to 0x1fe000
|
||||||
__xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
__xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||||
__xdata uint8_t cmd_available;
|
|
||||||
|
|
||||||
__xdata char save_cmd;
|
__xdata char save_cmd;
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ inline uint8_t isnumber(uint8_t l)
|
|||||||
return (l <= ('9'-'0'));
|
return (l <= ('9'-'0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd)
|
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd)
|
||||||
{
|
{
|
||||||
if (cmd_words_len == 0 || start > (cmd_words_len - 1)) {
|
if (cmd_words_len == 0 || start > (cmd_words_len - 1)) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -428,6 +429,22 @@ err:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmd_error(__code const char *msg)
|
||||||
|
{
|
||||||
|
err_status = ERR_INVALID_ARGUMENT;
|
||||||
|
print_string("Error: ");
|
||||||
|
print_string(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t name_char(uint8_t c)
|
||||||
|
{
|
||||||
|
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||||
|
return '.';
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Sets the management MAC from a "mac <aa:bb:cc:dd:ee:ff>" command (or prints
|
// Sets the management MAC from a "mac <aa:bb:cc:dd:ee:ff>" command (or prints
|
||||||
// the current one with a bare "mac"). Refuses blank/multicast/locally
|
// the current one with a bare "mac"). Refuses blank/multicast/locally
|
||||||
// administered/all-zero-OUI addresses so the running MAC stays reachable, and
|
// administered/all-zero-OUI addresses so the running MAC stays reachable, and
|
||||||
@@ -443,11 +460,11 @@ void parse_mac_cmd(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cmd_words_len != 2 || !parse_mac(cmd_words_b[1])) {
|
if (cmd_words_len != 2 || !parse_mac(cmd_words_b[1])) {
|
||||||
print_string("Error: mac [<aa:bb:cc:dd:ee:ff>]\n");
|
cmd_error("mac [<aa:bb:cc:dd:ee:ff>]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((mac_parse_result[0] & 0x03) || ((mac_parse_result[0] | mac_parse_result[1] | mac_parse_result[2]) == 0)) {
|
if ((mac_parse_result[0] & 0x03) || ((mac_parse_result[0] | mac_parse_result[1] | mac_parse_result[2]) == 0)) {
|
||||||
print_string("refusing: must be unicast, globally administered\n");
|
cmd_error("the MAC must be unicast and globally administered\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (memcmp(mac_parse_result, uip_ethaddr.addr, 6) == 0) {
|
if (memcmp(mac_parse_result, uip_ethaddr.addr, 6) == 0) {
|
||||||
@@ -525,7 +542,7 @@ void parse_lag(void)
|
|||||||
port_lag_members_set(group, members);
|
port_lag_members_set(group, members);
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
print_string("Error: lag (show | <1-4> (d | <port>...))\n");
|
cmd_error("lag (show | <1-4> (d | <port>...))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -567,7 +584,7 @@ void parse_lag_hash(void)
|
|||||||
port_lag_hash_set(group, hash);
|
port_lag_hash_set(group, hash);
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
print_string("Error: laghash <1-4> [smac|dmac|sip|dip|sport|dport]\n");
|
cmd_error("laghash <1-4> [smac|dmac|sip|dip|sport|dport]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -621,7 +638,7 @@ void parse_vlan(void)
|
|||||||
*vlan_str++ = hex[(vlan_settings.vlan >> 4) & 0xf] ;
|
*vlan_str++ = hex[(vlan_settings.vlan >> 4) & 0xf] ;
|
||||||
*vlan_str++ = hex[vlan_settings.vlan & 0xf];
|
*vlan_str++ = hex[vlan_settings.vlan & 0xf];
|
||||||
while(!cmd_is_space_or_nul(pos)) {
|
while(!cmd_is_space_or_nul(pos)) {
|
||||||
uint8_t c = cmd_buffer[pos++];
|
uint8_t c = name_char(cmd_buffer[pos++]);
|
||||||
write_char(c);
|
write_char(c);
|
||||||
*vlan_str++ = c;
|
*vlan_str++ = c;
|
||||||
}
|
}
|
||||||
@@ -665,7 +682,7 @@ void parse_vlan(void)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
print_string("Error: vlan (<vlan-id>|show) [port][t]...\n");
|
cmd_error("vlan (<vlan-id>|show) [port][t]...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -716,7 +733,7 @@ void parse_isolate(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("Error: isolate <port> [show|off] [port]...\n");
|
cmd_error("isolate <port> [show|off] [port]...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -753,7 +770,7 @@ void parse_ingress(void)
|
|||||||
// Setting mode for all ports at once
|
// Setting mode for all ports at once
|
||||||
for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) {
|
for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) {
|
||||||
if (!port_ingress_filter(log_port, mode)) {
|
if (!port_ingress_filter(log_port, mode)) {
|
||||||
print_string("Error setting ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
print_string("All ports ingress filter set to: ");
|
print_string("All ports ingress filter set to: ");
|
||||||
@@ -764,18 +781,18 @@ void parse_ingress(void)
|
|||||||
idx = cmd_words_b[w];
|
idx = cmd_words_b[w];
|
||||||
uint8_t ret = cmd_parse_port(idx);
|
uint8_t ret = cmd_parse_port(idx);
|
||||||
if (ret != 1) {
|
if (ret != 1) {
|
||||||
print_string("Invalid physical port number\n");
|
cmd_error("Invalid physical port number\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
log_port = atoi_results_u8;
|
log_port = atoi_results_u8;
|
||||||
idx += ret;
|
idx += ret;
|
||||||
|
|
||||||
if (!vlan_ingress_mode_parse(cmd_buffer[idx++], &mode) || !cmd_is_space_or_nul(idx)) {
|
if (!vlan_ingress_mode_parse(cmd_buffer[idx++], &mode) || !cmd_is_space_or_nul(idx)) {
|
||||||
print_string("Invalid ingress mode for port "); print_phys_port(log_port); print_string(" in ingress command\n");
|
cmd_error("Invalid ingress mode for port "); print_phys_port(log_port); print_string(" in ingress command\n");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (!port_ingress_filter(log_port, mode)) {
|
if (!port_ingress_filter(log_port, mode)) {
|
||||||
print_string("Error setting ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
print_string("Port "); print_phys_port(log_port);
|
print_string("Port "); print_phys_port(log_port);
|
||||||
@@ -785,7 +802,7 @@ void parse_ingress(void)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
print_string("Error: ingress [p]<u/t/a>...\n");
|
cmd_error("ingress [p]<u/t/a>...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_mirror(void)
|
void parse_mirror(void)
|
||||||
@@ -850,7 +867,7 @@ void parse_mirror(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("Port/command missing: mirror [status/off/<mirroring port> [port][t/r]]...\n");
|
cmd_error("Port/command missing: mirror [status/off/<mirroring port> [port][t/r]]...\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,7 +875,7 @@ err:
|
|||||||
void parse_port(void)
|
void parse_port(void)
|
||||||
{
|
{
|
||||||
if (cmd_words_len < 3) {
|
if (cmd_words_len < 3) {
|
||||||
print_string("\nUsage:" \
|
cmd_error("\nUsage:" \
|
||||||
"\nport <port> [show|on|off]" \
|
"\nport <port> [show|on|off]" \
|
||||||
"\nport <port> [10m|100m|1g|2g5|duplex] [half|full]" \
|
"\nport <port> [10m|100m|1g|2g5|duplex] [half|full]" \
|
||||||
"\nport <port> name [custom port name]\n");
|
"\nport <port> name [custom port name]\n");
|
||||||
@@ -866,7 +883,7 @@ void parse_port(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_parse_port_separator(cmd_words_b[1]) == 0) {
|
if (cmd_parse_port_separator(cmd_words_b[1]) == 0) {
|
||||||
print_string("Invalid port number\n");
|
cmd_error("Invalid port number\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
phy_settings.port = atoi_results_u8;
|
phy_settings.port = atoi_results_u8;
|
||||||
@@ -879,11 +896,14 @@ void parse_port(void)
|
|||||||
print_string_x(port_names[phy_settings.port]);
|
print_string_x(port_names[phy_settings.port]);
|
||||||
if (!machine.is_sfp[phy_settings.port]) {
|
if (!machine.is_sfp[phy_settings.port]) {
|
||||||
phy_show(phy_settings.port);
|
phy_show(phy_settings.port);
|
||||||
|
} else {
|
||||||
|
write_char('\n');
|
||||||
}
|
}
|
||||||
|
port_media_show(phy_settings.port);
|
||||||
} else if (cmd_compare(2, "name")) {
|
} else if (cmd_compare(2, "name")) {
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
while ( (i < PORT_NAME_SIZE-1) && (cmd_buffer[cmd_words_b[3] + i] != NUL) ) {
|
while ( cmd_words_len > 3 && (i < PORT_NAME_SIZE-1) && (cmd_buffer[cmd_words_b[3] + i] != NUL) ) {
|
||||||
port_names[phy_settings.port][i] = cmd_buffer[cmd_words_b[3] + i];
|
port_names[phy_settings.port][i] = name_char(cmd_buffer[cmd_words_b[3] + i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
port_names[phy_settings.port][i] = NUL;
|
port_names[phy_settings.port][i] = NUL;
|
||||||
@@ -944,7 +964,7 @@ void parse_port(void)
|
|||||||
phy_settings.duplex = PHY_DUPLEX_HALF;
|
phy_settings.duplex = PHY_DUPLEX_HALF;
|
||||||
phy_set_duplex();
|
phy_set_duplex();
|
||||||
} else {
|
} else {
|
||||||
print_string("Unknown port command\n");
|
cmd_error("Unknown port command\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,7 +992,7 @@ void parse_mtu(void)
|
|||||||
print_byte(p);
|
print_byte(p);
|
||||||
|
|
||||||
if (atoi_short(cmd_words_b[2]) == 0 || atoi_results_short < 64 || atoi_results_short > 0x3fff) {
|
if (atoi_short(cmd_words_b[2]) == 0 || atoi_results_short < 64 || atoi_results_short > 0x3fff) {
|
||||||
print_string("MTU must be 64..16383\n");
|
cmd_error("MTU must be 64..16383\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (atoi_results_short >> 10) & 0xf, (atoi_results_short >> 2) & 0xff,
|
REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (atoi_results_short >> 10) & 0xf, (atoi_results_short >> 2) & 0xff,
|
||||||
@@ -981,7 +1001,7 @@ void parse_mtu(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("mtu [port] [size]\n");
|
cmd_error("mtu [port] [size]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,11 +1058,11 @@ void parse_sfp(void)
|
|||||||
idx += ret;
|
idx += ret;
|
||||||
slot = atoi_results_u8 - 1;
|
slot = atoi_results_u8 - 1;
|
||||||
if (ret == 0 || !cmd_is_space(idx) || slot > 1) {
|
if (ret == 0 || !cmd_is_space(idx) || slot > 1) {
|
||||||
print_string("Illegal SFP slot number\n");
|
cmd_error("Illegal SFP slot number\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (slot >= machine.n_sfp) {
|
if (slot >= machine.n_sfp) {
|
||||||
print_string("SFP slot not present\n");
|
cmd_error("SFP slot not present\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,7 +1088,7 @@ void parse_sfp(void)
|
|||||||
handle_sfp();
|
handle_sfp();
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
print_string("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
|
cmd_error("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1100,7 +1120,7 @@ void parse_regget(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: regget <hexvalue>\n\tlike: regget 0BB0 or regget 0c");
|
cmd_error("regget <hexvalue>\n\tlike: regget 0BB0 or regget 0c");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1147,7 +1167,7 @@ void parse_regset(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: regset <hexvalue> <hexvalue>\n\tlike regset 0b abcd1234.");
|
cmd_error("regset <hexvalue> <hexvalue>\n\tlike regset 0b abcd1234.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1190,7 +1210,7 @@ void parse_sdsget(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: sdsget <sds-id> <hex:page> <hex:reg>\n");
|
cmd_error("sdsget <sds-id> <hex:page> <hex:reg>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1246,7 +1266,7 @@ void parse_sdsset(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: sdsset <sds-id> <hex:page> <hex:reg> <hex:val>\n");
|
cmd_error("sdsset <sds-id> <hex:page> <hex:reg> <hex:val>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1295,7 +1315,7 @@ void parse_phyget(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: phyget <phy-id> <dev-id> <hex:reg>\n");
|
cmd_error("phyget <phy-id> <dev-id> <hex:reg>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1355,7 +1375,7 @@ void parse_physet(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: physet <phy-id> <dev-id> <hex:reg> <hex:val>\n");
|
cmd_error("physet <phy-id> <dev-id> <hex:reg> <hex:val>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1390,7 +1410,7 @@ void parse_passwd(void)
|
|||||||
passwd[j] = NUL;
|
passwd[j] = NUL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
print_string("Missing password\n");
|
cmd_error("Missing password\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1413,8 +1433,8 @@ void parse_eee(void)
|
|||||||
speed_word = 2;
|
speed_word = 2;
|
||||||
} else if (cmd_is_space_or_nul(idx)) {
|
} else if (cmd_is_space_or_nul(idx)) {
|
||||||
// Word 2 is a port number
|
// Word 2 is a port number
|
||||||
if (cmd_parse_port_separator(idx) == 0) {
|
if (cmd_parse_port_separator(cmd_words_b[2]) == 0) {
|
||||||
print_string("Speed word invalid, use: [100m|1g|2g5]\n");
|
cmd_error("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = atoi_results_u8;
|
port = atoi_results_u8;
|
||||||
@@ -1433,7 +1453,7 @@ void parse_eee(void)
|
|||||||
speed = EEE_2G5;
|
speed = EEE_2G5;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print_string("Speed word invalid, use: [100m|1g|2g5]\n");
|
cmd_error("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1453,7 +1473,7 @@ void parse_eee(void)
|
|||||||
else
|
else
|
||||||
port_eee_status_all();
|
port_eee_status_all();
|
||||||
} else {
|
} else {
|
||||||
print_string("eee [on|off|status] [port] [100m|1g|2g5]\n");
|
cmd_error("eee [on|off|status] [port] [100m|1g|2g5]\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1524,7 +1544,7 @@ void parse_bw(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
print_string("usage: bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
cmd_error("bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_syslog(void)
|
void parse_syslog(void)
|
||||||
@@ -1562,7 +1582,7 @@ void parse_syslog(void)
|
|||||||
if (was_enabled)
|
if (was_enabled)
|
||||||
syslog_start();
|
syslog_start();
|
||||||
} else {
|
} else {
|
||||||
print_string("Invalid IP address\n");
|
cmd_error("Invalid IP address\n");
|
||||||
}
|
}
|
||||||
} else if (cmd_compare(1, "port")) {
|
} else if (cmd_compare(1, "port")) {
|
||||||
if (cmd_words_len < 3) { // no additional argument -> print current port
|
if (cmd_words_len < 3) { // no additional argument -> print current port
|
||||||
@@ -1573,7 +1593,7 @@ void parse_syslog(void)
|
|||||||
/* atoi_short() returns zero for no digits and for a value past
|
/* atoi_short() returns zero for no digits and for a value past
|
||||||
* 65535; port zero is not a port either, so both tests are needed. */
|
* 65535; port zero is not a port either, so both tests are needed. */
|
||||||
if (!atoi_short(cmd_words_b[2]) || !atoi_results_short) {
|
if (!atoi_short(cmd_words_b[2]) || !atoi_results_short) {
|
||||||
print_string("Invalid port\n");
|
cmd_error("Invalid port\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* The port is frozen into the connection by uip_udp_new(), so
|
/* The port is frozen into the connection by uip_udp_new(), so
|
||||||
@@ -1589,9 +1609,9 @@ void parse_syslog(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print_string("Error: syslog [on|off|ip [ip-address]|port [number]]\n");
|
cmd_error("syslog [on|off|ip [ip-address]|port [number]]\n"
|
||||||
print_string(" on/off enables or disables syslog, ip sets the syslog server IP address,\n");
|
" on/off enables or disables syslog, ip sets the syslog server IP address,\n"
|
||||||
print_string(" port sets the destination UDP port (default 514)\n");
|
" port sets the destination UDP port (default 514)\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1778,7 +1798,7 @@ void cmd_parser(void) __banked
|
|||||||
print_string("Setting ip: ");
|
print_string("Setting ip: ");
|
||||||
print_ip(ip); write_char('\n');
|
print_ip(ip); write_char('\n');
|
||||||
} else {
|
} else {
|
||||||
print_string("Invalid IP address\n" \
|
cmd_error("Invalid IP address\n" \
|
||||||
"Error: ip [<ip-address>|dhcp]\n" \
|
"Error: ip [<ip-address>|dhcp]\n" \
|
||||||
" The dhcp option enables the dhcp client, calling ip without options prints the current IP\n" \
|
" The dhcp option enables the dhcp client, calling ip without options prints the current IP\n" \
|
||||||
" Calling with a valid IP address will stop any ongoing dhcp client and set the IP address\n");
|
" Calling with a valid IP address will stop any ongoing dhcp client and set the IP address\n");
|
||||||
@@ -1794,7 +1814,7 @@ void cmd_parser(void) __banked
|
|||||||
print_string("Setting gw: ");
|
print_string("Setting gw: ");
|
||||||
print_ip(ip); write_char('\n');
|
print_ip(ip); write_char('\n');
|
||||||
} else {
|
} else {
|
||||||
print_string("Invalid IP address\n" \
|
cmd_error("Invalid IP address\n" \
|
||||||
"Error: gw <ip-address>\n");
|
"Error: gw <ip-address>\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1808,7 +1828,7 @@ void cmd_parser(void) __banked
|
|||||||
print_string("Setting netmask: ");
|
print_string("Setting netmask: ");
|
||||||
print_ip(ip); write_char('\n');
|
print_ip(ip); write_char('\n');
|
||||||
} else {
|
} else {
|
||||||
print_string("Invalid IP address\n");
|
cmd_error("Invalid IP address\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_char('\n');
|
write_char('\n');
|
||||||
@@ -1824,8 +1844,9 @@ void cmd_parser(void) __banked
|
|||||||
igmp_setup();
|
igmp_setup();
|
||||||
else if (cmd_compare(1, "show"))
|
else if (cmd_compare(1, "show"))
|
||||||
igmp_show();
|
igmp_show();
|
||||||
else
|
else {
|
||||||
print_string("Error: igmp on|off|show\n");
|
cmd_error("igmp on|off|show\n");
|
||||||
|
}
|
||||||
} else if (cmd_compare(0, "mac")) {
|
} else if (cmd_compare(0, "mac")) {
|
||||||
parse_mac_cmd();
|
parse_mac_cmd();
|
||||||
} else if (cmd_compare(0, "hostname")) {
|
} else if (cmd_compare(0, "hostname")) {
|
||||||
@@ -1843,22 +1864,25 @@ void cmd_parser(void) __banked
|
|||||||
uint8_t c = *hp++;
|
uint8_t c = *hp++;
|
||||||
if (c == NUL || c == '\r' || c == '\n')
|
if (c == NUL || c == '\r' || c == '\n')
|
||||||
break;
|
break;
|
||||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
*dst++ = name_char(c);
|
||||||
c = '.';
|
|
||||||
*dst++ = c;
|
|
||||||
}
|
}
|
||||||
*dst = NUL;
|
*dst = NUL;
|
||||||
} else {
|
} else {
|
||||||
print_string("Error: hostname [name] - the name must not contain spaces\n");
|
cmd_error("hostname [name] - the name must not contain spaces\n");
|
||||||
}
|
}
|
||||||
} else if (cmd_compare(0, "stp")) {
|
} else if (cmd_compare(0, "stp")) {
|
||||||
stp_parse();
|
stp_parse();
|
||||||
|
#ifdef HEALTH
|
||||||
|
} else if (cmd_compare(0, "health")) {
|
||||||
|
health_show();
|
||||||
|
#endif
|
||||||
} else if (cmd_compare(0, "pvid")) {
|
} else if (cmd_compare(0, "pvid")) {
|
||||||
if (cmd_words_len == 3 && cmd_parse_port_separator(cmd_words_b[1]) != 0
|
if (cmd_words_len == 3 && cmd_parse_port_separator(cmd_words_b[1]) != 0
|
||||||
&& atoi_short(cmd_words_b[2]) && atoi_results_short && atoi_results_short <= 4094)
|
&& atoi_short(cmd_words_b[2]) && atoi_results_short && atoi_results_short <= 4094)
|
||||||
port_pvid_set(atoi_results_u8, atoi_results_short);
|
port_pvid_set(atoi_results_u8, atoi_results_short);
|
||||||
else
|
else {
|
||||||
print_string("Error: pvid <port> <1-4094>\n");
|
cmd_error("pvid <port> <1-4094>\n");
|
||||||
|
}
|
||||||
} else if (cmd_compare(0, "vlan")) {
|
} else if (cmd_compare(0, "vlan")) {
|
||||||
parse_vlan();
|
parse_vlan();
|
||||||
} else if (cmd_compare(0, "isolate")) {
|
} else if (cmd_compare(0, "isolate")) {
|
||||||
@@ -1920,11 +1944,11 @@ void cmd_parser(void) __banked
|
|||||||
parse_session();
|
parse_session();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print_string("Unknown command\n");
|
cmd_error("Unknown command\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (save_cmd && cmd_words_len) {
|
if (save_cmd && cmd_words_len && err_status == ERR_OK) {
|
||||||
// Find end of the cmd-buffer, looking for the NUL-byte.
|
// Find end of the cmd-buffer, looking for the NUL-byte.
|
||||||
uint8_t i = cmd_words_b[cmd_words_len - 1];
|
uint8_t i = cmd_words_b[cmd_words_len - 1];
|
||||||
do {
|
do {
|
||||||
@@ -1969,6 +1993,7 @@ void execute_config(void) __banked
|
|||||||
save_cmd = 0;
|
save_cmd = 0;
|
||||||
|
|
||||||
uint8_t cmd_idx = 0;
|
uint8_t cmd_idx = 0;
|
||||||
|
uint8_t skipping = 0;
|
||||||
do {
|
do {
|
||||||
flash_region.addr = pos;
|
flash_region.addr = pos;
|
||||||
flash_region.len = FLASH_READ_BURST_SIZE;
|
flash_region.len = FLASH_READ_BURST_SIZE;
|
||||||
@@ -1979,20 +2004,23 @@ void execute_config(void) __banked
|
|||||||
do {
|
do {
|
||||||
if (cmd_idx >= (CMD_BUF_SIZE - 1)) {
|
if (cmd_idx >= (CMD_BUF_SIZE - 1)) {
|
||||||
cmd_buffer[cmd_idx] = NUL;
|
cmd_buffer[cmd_idx] = NUL;
|
||||||
print_string("ERROR: Command too long: ");
|
print_string("ERROR: Command too long, skipped: ");
|
||||||
print_string_x(cmd_buffer);
|
print_string_x(cmd_buffer);
|
||||||
write_char('\n');
|
write_char('\n');
|
||||||
err_status = ERR_CMD_TOO_LONG;
|
cmd_idx = 0;
|
||||||
goto config_done;
|
skipping = 1;
|
||||||
}
|
}
|
||||||
c = flash_buf[cfg_idx++];
|
c = flash_buf[cfg_idx++];
|
||||||
if (c == 0 || c == '\n') {
|
if (c == 0 || c == '\n') {
|
||||||
cmd_buffer[cmd_idx] = NUL;
|
if (skipping) {
|
||||||
if (cmd_idx) {
|
skipping = 0;
|
||||||
cmd_tokenize();
|
} else {
|
||||||
if (err_status != ERR_OK)
|
cmd_buffer[cmd_idx] = NUL;
|
||||||
goto config_done;
|
if (cmd_idx) {
|
||||||
cmd_parser();
|
cmd_tokenize();
|
||||||
|
if (err_status == ERR_OK)
|
||||||
|
cmd_parser();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
goto config_done;
|
goto config_done;
|
||||||
@@ -2000,8 +2028,10 @@ void execute_config(void) __banked
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_buffer[cmd_idx] = c;
|
if (!skipping) {
|
||||||
cmd_idx++;
|
cmd_buffer[cmd_idx] = c;
|
||||||
|
cmd_idx++;
|
||||||
|
}
|
||||||
} while (cfg_idx);
|
} while (cfg_idx);
|
||||||
|
|
||||||
pages_left--;
|
pages_left--;
|
||||||
@@ -2018,6 +2048,7 @@ config_done:
|
|||||||
// If a command is too long or can't be tokenized, remaining commands are not executed
|
// If a command is too long or can't be tokenized, remaining commands are not executed
|
||||||
// Returns the status via `err_status`-variable.
|
// Returns the status via `err_status`-variable.
|
||||||
void execute_commands(__xdata uint8_t *p) __banked {
|
void execute_commands(__xdata uint8_t *p) __banked {
|
||||||
|
__xdata uint8_t failed = ERR_OK;
|
||||||
err_status = ERR_OK;
|
err_status = ERR_OK;
|
||||||
uint8_t cmd_idx = 0;
|
uint8_t cmd_idx = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -2028,9 +2059,13 @@ void execute_commands(__xdata uint8_t *p) __banked {
|
|||||||
if (err_status != ERR_OK)
|
if (err_status != ERR_OK)
|
||||||
return;
|
return;
|
||||||
cmd_parser();
|
cmd_parser();
|
||||||
|
if (failed == ERR_OK)
|
||||||
|
failed = err_status;
|
||||||
}
|
}
|
||||||
if (*p == 0)
|
if (*p == 0) {
|
||||||
|
err_status = failed;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
cmd_idx = 0;
|
cmd_idx = 0;
|
||||||
} else {
|
} else {
|
||||||
if (cmd_idx < (CMD_BUF_SIZE - 1)) {
|
if (cmd_idx < (CMD_BUF_SIZE - 1)) {
|
||||||
@@ -2047,3 +2082,161 @@ void execute_commands(__xdata uint8_t *p) __banked {
|
|||||||
p++;
|
p++;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HEALTH
|
||||||
|
/*
|
||||||
|
* Health instrumentation. The counters live in xdata and are fed from the
|
||||||
|
* main loop through the banked entry points below; the "health" command
|
||||||
|
* prints everything in one go. All figures are raw hex, diffing two dumps
|
||||||
|
* gives the rates. Phase times are in system ticks (SYS_TICK_HZ = 200,
|
||||||
|
* 5 ms each); a phase counts as slow when it spans 2 or more ticks.
|
||||||
|
*/
|
||||||
|
extern __xdata uint16_t len_left; /* httpd: bytes still to send of the current file */
|
||||||
|
extern __xdata uint8_t entry; /* httpd: index of the file being sent */
|
||||||
|
|
||||||
|
static __xdata uint32_t health_loops;
|
||||||
|
__xdata uint16_t health_rx_frames;
|
||||||
|
|
||||||
|
static __xdata uint16_t ph_last_t;
|
||||||
|
static __xdata uint8_t ph_max[HEALTH_PHASES];
|
||||||
|
static __xdata uint16_t ph_slow[HEALTH_PHASES];
|
||||||
|
|
||||||
|
/* The ISR increments ticks between the two byte reads of a 16-bit load, so
|
||||||
|
* read until two loads agree. */
|
||||||
|
static uint16_t ticks_lo(void)
|
||||||
|
{
|
||||||
|
uint16_t a, b;
|
||||||
|
a = (uint16_t)ticks;
|
||||||
|
do {
|
||||||
|
b = a;
|
||||||
|
a = (uint16_t)ticks;
|
||||||
|
} while (a != b);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void health_loop_start(void) __banked
|
||||||
|
{
|
||||||
|
health_loops++;
|
||||||
|
ph_last_t = ticks_lo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void health_phase(uint8_t id) __banked
|
||||||
|
{
|
||||||
|
__xdata uint16_t now = ticks_lo();
|
||||||
|
__xdata uint16_t d = now - ph_last_t;
|
||||||
|
ph_last_t = now;
|
||||||
|
if (d > 0xff)
|
||||||
|
d = 0xff;
|
||||||
|
if ((uint8_t)d > ph_max[id])
|
||||||
|
ph_max[id] = d;
|
||||||
|
if (d >= 2)
|
||||||
|
ph_slow[id]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fill the stack area above the current frame with a pattern; the dump scans
|
||||||
|
* for how much of it survived. The 8051 stack grows upward, so everything
|
||||||
|
* above SP is free at this point. Interrupts are held off so an ISR does not
|
||||||
|
* push into the area mid-paint. */
|
||||||
|
void health_stack_paint(void) __banked
|
||||||
|
{
|
||||||
|
__xdata uint8_t from = SP + 4;
|
||||||
|
__xdata uint8_t ea = EA;
|
||||||
|
EA = 0;
|
||||||
|
for (uint8_t i = 0xff; i >= from; i--)
|
||||||
|
*(__idata uint8_t *)i = 0xa5;
|
||||||
|
EA = ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ph_line(__code const char *name, uint8_t id)
|
||||||
|
{
|
||||||
|
print_string(name);
|
||||||
|
print_string(" max ");
|
||||||
|
print_byte(ph_max[id]);
|
||||||
|
print_string(" slow ");
|
||||||
|
print_short(ph_slow[id]);
|
||||||
|
write_char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void health_show(void) __banked
|
||||||
|
{
|
||||||
|
__xdata uint8_t i;
|
||||||
|
|
||||||
|
print_string("up ");
|
||||||
|
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||||
|
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||||
|
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||||
|
print_string(" ticks ");
|
||||||
|
print_long(ticks);
|
||||||
|
print_string(" loops ");
|
||||||
|
print_long(health_loops);
|
||||||
|
print_string(" rx ");
|
||||||
|
print_short(health_rx_frames);
|
||||||
|
write_char('\n');
|
||||||
|
|
||||||
|
/* Phase timing: max duration seen (ticks of 5 ms) and slow-pass count */
|
||||||
|
ph_line("link", HEALTH_PH_LINK);
|
||||||
|
ph_line("sfp ", HEALTH_PH_SFP);
|
||||||
|
ph_line("rx ", HEALTH_PH_RX);
|
||||||
|
ph_line("tx ", HEALTH_PH_TX);
|
||||||
|
ph_line("stp ", HEALTH_PH_STP);
|
||||||
|
ph_line("cmd ", HEALTH_PH_CMD);
|
||||||
|
|
||||||
|
/* Stack: current depth plus how much of the painted area is untouched */
|
||||||
|
print_string("sp ");
|
||||||
|
print_byte(SP);
|
||||||
|
print_string(" untouched ");
|
||||||
|
i = 0;
|
||||||
|
while (*(__idata uint8_t *)(0xff - i) == 0xa5 && i < 0x86)
|
||||||
|
i++;
|
||||||
|
print_byte(i);
|
||||||
|
write_char('\n');
|
||||||
|
|
||||||
|
/* The TCP connection slot. One on this configuration; a build with more
|
||||||
|
* has to say which slot each line is, so make that a visible decision. */
|
||||||
|
#if UIP_CONNS != 1
|
||||||
|
#error "health: the tcp dump prints a single slot, extend it for UIP_CONNS > 1"
|
||||||
|
#endif
|
||||||
|
i = 0;
|
||||||
|
{
|
||||||
|
print_string("tcp ");
|
||||||
|
print_string("st ");
|
||||||
|
print_byte(uip_conns[i].tcpstateflags);
|
||||||
|
print_string(" tmr ");
|
||||||
|
print_byte(uip_conns[i].timer);
|
||||||
|
print_string(" rtx ");
|
||||||
|
print_byte(uip_conns[i].nrtx);
|
||||||
|
print_string(" rto ");
|
||||||
|
print_byte(uip_conns[i].rto);
|
||||||
|
print_string(" len ");
|
||||||
|
print_short(uip_conns[i].len);
|
||||||
|
print_string(" mss ");
|
||||||
|
print_short(uip_conns[i].mss);
|
||||||
|
write_char('\n');
|
||||||
|
print_string(" lport ");
|
||||||
|
print_short(HTONS(uip_conns[i].lport));
|
||||||
|
print_string(" rport ");
|
||||||
|
print_short(HTONS(uip_conns[i].rport));
|
||||||
|
print_string(" rip ");
|
||||||
|
print_short(HTONS(uip_conns[i].ripaddr[0]));
|
||||||
|
write_char(' ');
|
||||||
|
print_short(HTONS(uip_conns[i].ripaddr[1]));
|
||||||
|
write_char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* httpd transfer state and the protocol flags */
|
||||||
|
print_string("httpd left ");
|
||||||
|
print_short(len_left);
|
||||||
|
print_string(" entry ");
|
||||||
|
print_byte(entry);
|
||||||
|
print_string(" stp ");
|
||||||
|
print_byte(stp_enabled);
|
||||||
|
print_string(" mvlan ");
|
||||||
|
print_short(management_vlan);
|
||||||
|
write_char('\n');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -6,9 +6,35 @@
|
|||||||
#include "rtl837x_common.h"
|
#include "rtl837x_common.h"
|
||||||
|
|
||||||
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||||
extern __xdata uint8_t cmd_available;
|
extern __bit __at(0x03) cmd_available;
|
||||||
extern __xdata uint8_t err_status;
|
extern __xdata uint8_t err_status;
|
||||||
|
|
||||||
|
/* Health instrumentation, built with HEALTH=1. Without it the hooks below
|
||||||
|
* compile to nothing and the "health" command does not exist. */
|
||||||
|
#ifdef HEALTH
|
||||||
|
/* Phase ids, in main-loop order */
|
||||||
|
#define HEALTH_PH_LINK 0
|
||||||
|
#define HEALTH_PH_SFP 1
|
||||||
|
#define HEALTH_PH_RX 2
|
||||||
|
#define HEALTH_PH_TX 3
|
||||||
|
#define HEALTH_PH_STP 4
|
||||||
|
#define HEALTH_PH_CMD 5
|
||||||
|
#define HEALTH_PHASES 6
|
||||||
|
|
||||||
|
extern __xdata uint16_t health_rx_frames;
|
||||||
|
#define health_rx_frame() health_rx_frames++
|
||||||
|
|
||||||
|
void health_loop_start(void) __banked; /* once per idle() pass, resets the phase baseline */
|
||||||
|
void health_phase(uint8_t id) __banked; /* after each phase; accounts ticks since last checkpoint */
|
||||||
|
void health_stack_paint(void) __banked; /* paint the unused stack area once at boot */
|
||||||
|
void health_show(void) __banked; /* "health" CLI dump */
|
||||||
|
#else
|
||||||
|
#define health_rx_frame()
|
||||||
|
#define health_loop_start()
|
||||||
|
#define health_phase(id)
|
||||||
|
#define health_stack_paint()
|
||||||
|
#endif
|
||||||
|
|
||||||
void cmd_tokenize(void) __banked;
|
void cmd_tokenize(void) __banked;
|
||||||
void cmd_parser(void) __banked;
|
void cmd_parser(void) __banked;
|
||||||
void execute_config(void) __banked;
|
void execute_config(void) __banked;
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ void dhcp_addopt_request_ip(void)
|
|||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
||||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -151,13 +150,11 @@ void dhcp_addopt_server_id(void)
|
|||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
||||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
||||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcp_send_discover(void)
|
void dhcp_send_discover(void)
|
||||||
{
|
{
|
||||||
print_string("dhcp_send_discover called\n");
|
|
||||||
dhcp_prepare_request();
|
dhcp_prepare_request();
|
||||||
|
|
||||||
dhcp_state.opt_ptr = 0;
|
dhcp_state.opt_ptr = 0;
|
||||||
@@ -193,7 +190,6 @@ void dhcp_send_discover(void)
|
|||||||
|
|
||||||
void dhcp_send_request(void)
|
void dhcp_send_request(void)
|
||||||
{
|
{
|
||||||
print_string("dhcp_send_request called\n");
|
|
||||||
dhcp_prepare_request();
|
dhcp_prepare_request();
|
||||||
|
|
||||||
dhcp_state.opt_ptr = 0;
|
dhcp_state.opt_ptr = 0;
|
||||||
@@ -232,19 +228,21 @@ void ip_opt(__xdata uint8_t * ip)
|
|||||||
{
|
{
|
||||||
dhcp_state.opt_ptr++;
|
dhcp_state.opt_ptr++;
|
||||||
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
if (len >= 4)
|
||||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
memcpy(ip, &DHCP_OPT[dhcp_state.opt_ptr], 4);
|
||||||
*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
|
// There may be more than one IP option, such as 2 DNS servers advertised
|
||||||
dhcp_state.opt_ptr += len - 4;
|
dhcp_state.opt_ptr += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void long_opt(void)
|
uint8_t long_opt(void)
|
||||||
{
|
{
|
||||||
dhcp_state.opt_ptr++;
|
dhcp_state.opt_ptr++;
|
||||||
dhcp_state.opt_ptr++;
|
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
if (len < 4) {
|
||||||
|
dhcp_state.opt_ptr += len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
long_value = DHCP_OPT[dhcp_state.opt_ptr++];
|
long_value = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
long_value <<= 8;
|
long_value <<= 8;
|
||||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
@@ -252,6 +250,8 @@ void long_opt(void)
|
|||||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
long_value <<= 8;
|
long_value <<= 8;
|
||||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||||
|
dhcp_state.opt_ptr += len - 4;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -275,16 +275,16 @@ void parse_opts(void)
|
|||||||
ip_opt(&dhcp_state.broadcast[0]);
|
ip_opt(&dhcp_state.broadcast[0]);
|
||||||
break;
|
break;
|
||||||
case DHCP_LEASE:
|
case DHCP_LEASE:
|
||||||
long_opt();
|
if (long_opt())
|
||||||
dhcp_state.lease = long_value;
|
dhcp_state.lease = long_value;
|
||||||
break;
|
break;
|
||||||
case DHCP_REBIND:
|
case DHCP_REBIND:
|
||||||
long_opt();
|
if (long_opt())
|
||||||
dhcp_state.rebind = long_value;
|
dhcp_state.rebind = long_value;
|
||||||
break;
|
break;
|
||||||
case DHCP_RENEWAL:
|
case DHCP_RENEWAL:
|
||||||
long_opt();
|
if (long_opt())
|
||||||
dhcp_state.renewal = long_value;
|
dhcp_state.renewal = long_value;
|
||||||
break;
|
break;
|
||||||
case DHCP_END:
|
case DHCP_END:
|
||||||
break;
|
break;
|
||||||
@@ -376,13 +376,11 @@ void dhcp_start(void) __banked
|
|||||||
*tid++ = SFR_DATA_8;
|
*tid++ = SFR_DATA_8;
|
||||||
*tid = SFR_DATA_0;
|
*tid = SFR_DATA_0;
|
||||||
dhcp_state.state = DHCP_START;
|
dhcp_state.state = DHCP_START;
|
||||||
print_string("dhcp_start done\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dhcp_stop(void) __banked
|
void dhcp_stop(void) __banked
|
||||||
{
|
{
|
||||||
print_string("dhcp_stop called\n");
|
|
||||||
uip_udp_remove(dhcp_state.conn);
|
uip_udp_remove(dhcp_state.conn);
|
||||||
dhcp_state.state = DHCP_OFF;
|
dhcp_state.state = DHCP_OFF;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# F7008-2.5
|
||||||
|
|
||||||
|
Documentation for the unmanaged 8 + 1 switch sold as `7018-2.5G` by Guangnianwei
|
||||||
|
(光年微), board marking `F7008-2.5`, PCB `F7008-2.5GPOE-V1.2`.
|
||||||
|
|
||||||
|
### Brands
|
||||||
|
|
||||||
|
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||||
|
|-------|------|---------|-----|-------|----------|
|
||||||
|
| Guangnianwei (光年微) | 7018-2.5G | No | F7008-2.5GPOE-V1.2 | W25Q64JVSSIQ | 8373N + 8224N |
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- SFP+ port with 1G/2.5G/10G modules
|
||||||
|
- LEDs of the eight RJ45 ports
|
||||||
|
|
||||||
|
### Not verified
|
||||||
|
|
||||||
|
- The LED pads for the SFP+ cage are not mapped yet. The SFP+ lamps are left
|
||||||
|
undriven, so an inserted module lights nothing.
|
||||||
|
- The UART header footprint is present but unpopulated, and no boot log could be
|
||||||
|
captured from it, so the baud rate is unknown. There are most likely
|
||||||
|
unpopulated 0-Ohm resistors next to the header; bridging those should bring
|
||||||
|
the console to life.
|
||||||
|
|
||||||
|
### Build target
|
||||||
|
|
||||||
|
```
|
||||||
|
make MACHINE=F7008_2_5
|
||||||
|
```
|
||||||
|
|
||||||
|
### LED wiring
|
||||||
|
|
||||||
|
Measured pad to lamp map (`led_mux` index -> lamp):
|
||||||
|
|
||||||
|
| Port | green lamp | yellow lamp |
|
||||||
|
|------|-----------|-------------|
|
||||||
|
| 1 | pad 0 | pad 1 |
|
||||||
|
| 2 | pad 2 | pad 3 |
|
||||||
|
| 3 | pad 4 | pad 5 |
|
||||||
|
| 4 | pad 6 | pad 8 |
|
||||||
|
| 5 | pad 9 | pad 10 |
|
||||||
|
| 6 | pad 12 | pad 15 |
|
||||||
|
| 7 | pad 18 | pad 21 |
|
||||||
|
| 8 | pad 24 | pad 25 |
|
||||||
|
|
||||||
|
Pads 7, 11, 13, 14, 16, 17, 19, 20, 22, 23, 26 and 27 do not drive an RJ45 lamp.
|
||||||
|
|
||||||
|
The front panel is silkscreened `2.5G: Green / 10/100M: Yellow`, and the target
|
||||||
|
follows it: the green lamp is on while the port is linked at 2.5G, the yellow
|
||||||
|
lamp blinks while data is flowing.
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
The board is marked `F7008-2.5GPOE-V1.2`.
|
||||||
|
|
||||||
|
Top side:
|
||||||
|
|
||||||
|
<img src="photos/F7008-2.5/PCB-top.jpg" width="600" />
|
||||||
|
|
||||||
|
Bottom side:
|
||||||
|
|
||||||
|
<img src="photos/F7008-2.5/PCB-bottom.jpg" width="600" />
|
||||||
|
|
||||||
|
### Hardware notes
|
||||||
|
|
||||||
|
- 4 x `RT4802SNE` magnetics
|
||||||
|
- Unpopulated UART header footprint, next to the magnetics
|
||||||
|
- Power input 12V 1A, 180 x 84 x 29 mm metal case
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Hasivo S1100WP-8GT-1SX-SE
|
||||||
|
|
||||||
|
RTL8373-based 8×2.5G PoE + 1×SFP switch.
|
||||||
|
|
||||||
|
### Label specifications
|
||||||
|
|
||||||
|
- **Manufacturer**: Hasivo
|
||||||
|
- **Model**: S1100WP-8GT-1SX-SE
|
||||||
|
- **Ports**:
|
||||||
|
- 8 × RJ45: 10/100/1000/2500 Mbps with PoE
|
||||||
|
- 1 × SFP: 1G / 2.5G / 10G
|
||||||
|
- **Power input**: DC 52V 2.5A
|
||||||
|
- **Stock firmware defaults**: IP 192.168.0.1, user/password `admin`/`admin`
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE is not configurable via RTLPlayground)
|
||||||
|
- SFP port supporting 1G, 2.5G and 10G modules
|
||||||
|
- LEDs: green (2.5G) and amber (1G/100M/10M) per copper port; combined link/act on the SFP port
|
||||||
|
|
||||||
|
### Photos
|
||||||
|
|
||||||
|
Front panel:
|
||||||
|
|
||||||
|
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/front.jpg" width="600" />
|
||||||
|
|
||||||
|
Label:
|
||||||
|
|
||||||
|
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/label.jpg" width="600" />
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
Top side:
|
||||||
|
|
||||||
|
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/pcb_top.jpg" width="600" />
|
||||||
|
|
||||||
|
Bottom side:
|
||||||
|
|
||||||
|
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/pcb_bottom.jpg" width="600" />
|
||||||
|
|
||||||
|
### Port layout
|
||||||
|
|
||||||
|
| Logical port | Physical port | Type |
|
||||||
|
|--------------|---------------|--------|
|
||||||
|
| 1-8 | 1-8 | Copper |
|
||||||
|
| 9 | 9 | SFP |
|
||||||
|
|
||||||
|
### LED configuration
|
||||||
|
|
||||||
|
Copper ports use LED SET0, the SFP port uses LED SET1.
|
||||||
|
|
||||||
|
| SET | LED0 | LED2 |
|
||||||
|
|------|-----------------------------------------------|------------------------------------------------------|
|
||||||
|
| SET0 | Green — lights on 2.5G link with activity | Amber — lights on 1G / 100M / 10M link with activity |
|
||||||
|
| SET1 | All speeds — lights on any link with activity | — |
|
||||||
|
|
||||||
|
### SFP GPIO assignments
|
||||||
|
|
||||||
|
| SFP (logical 9) | pin_detect (ModAbs) | pin_los | pin_tx_disable | SerDes | I2C SDA | I2C SCL |
|
||||||
|
|-----------------|---------------------|---------|----------------|--------|-----------------|---------------------|
|
||||||
|
| SFP | GPIO30_ACL_BIT3_EN | GPIO37 | GPIO_NA | SDS1 | GPIO39_I2C_SDA4 | GPIO40_I2C_SCL3_MDC1 |
|
||||||
|
|
||||||
|
### Machine configuration
|
||||||
|
|
||||||
|
- `reset_pin`: GPIO54_ACL_BIT2_EN
|
||||||
|
- High LEDs (pads 27-29): mux = `LED_27 | LED_28_SYS | LED_29`, enable = `LED_28_SYS | LED_29`
|
||||||
|
|
||||||
|
### PoE
|
||||||
|
|
||||||
|
The 8 copper ports support PoE powered by a DC 52V 2.5A input. Power management is handled by two HS104PTI chipsets over I2C (GPIO47_I2C_SDA0, GPIO46_I2C_SCL0):
|
||||||
|
|
||||||
|
* Chip 1 (I2C address 0x1A): 2.5G Ports 1–4
|
||||||
|
* Chip 2 (I2C address 0x2A): 2.5G Ports 5–8
|
||||||
|
|
||||||
|
Note: The current implementation does not yet support PoE management. Consequently, PoE currently operates in standalone mode without software control.
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# IG108
|
||||||
|
|
||||||
|
Following is documentation for unmanaged switch marked as `IG108`.
|
||||||
|
|
||||||
|
Original software is running UART on 9600 baud rate.
|
||||||
|
|
||||||
|
Using SPI clamp in-board is the only method for initial installation.
|
||||||
|
|
||||||
|
### Brands
|
||||||
|
|
||||||
|
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||||
|
|---------|------------|---------|------------|-------------|---------------|
|
||||||
|
| Goalake | IG108 | No | PB-2132 | cFeon Q32A | 8373N + 8224N |
|
||||||
|
| Netcore | GS9 | No | PB-2132 | cFeon Q32A | 8373N + 8224N |
|
||||||
|
|
||||||
|
### What works
|
||||||
|
|
||||||
|
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||||
|
- SFP port with 1G/2.5G/10G modules
|
||||||
|
- LEDs
|
||||||
|
|
||||||
|
### PCB overview
|
||||||
|
|
||||||
|
**Board markings**
|
||||||
|
|
||||||
|
- Top silkscreen: PB-2132
|
||||||
|
|
||||||
|
Front Goalake:
|
||||||
|
|
||||||
|
<img src="photos/PB-2132/case.jpg" width="600" />
|
||||||
|
|
||||||
|
Label Goalake:
|
||||||
|
|
||||||
|
<img src="photos/PB-2132/label.jpg" width="600" />
|
||||||
|
|
||||||
|
Top side:
|
||||||
|
|
||||||
|
<img src="photos/PB-2132/PCB-top.jpg" width="600" />
|
||||||
|
|
||||||
|
Bottom:
|
||||||
|
|
||||||
|
<img src="photos/PB-2132/PCB-bottom.jpg" width="600" />
|
||||||
|
|
||||||
|
### Serial console
|
||||||
|
|
||||||
|
The PCB has unpopulated through-holes near the SFP Port, with description of each pin, works out of the box.
|
||||||
|
|
||||||
|
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
|
||||||
|
|
||||||
|
### Power supply
|
||||||
|
|
||||||
|
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 519 KiB |
|
After Width: | Height: | Size: 529 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 907 KiB |
|
After Width: | Height: | Size: 923 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 360 KiB |
@@ -0,0 +1,79 @@
|
|||||||
|
# The health command
|
||||||
|
|
||||||
|
`health` prints a one-page snapshot of the firmware's vital signs on the
|
||||||
|
serial console. It exists for the situations where the switch misbehaves and
|
||||||
|
every probe from the network measures the network instead of the device: the
|
||||||
|
dump is taken from inside, costs one command, and works while HTTP does not.
|
||||||
|
|
||||||
|
```
|
||||||
|
> health
|
||||||
|
up 0000001f ticks 0x00001f4c loops 0x000016da rx 0x024e
|
||||||
|
link max 01 slow 0x0000
|
||||||
|
sfp max 74 slow 0x0001
|
||||||
|
rx max 00 slow 0x0000
|
||||||
|
tx max 00 slow 0x0000
|
||||||
|
stp max 04 slow 0x0001
|
||||||
|
cmd max 02 slow 0x0001
|
||||||
|
sp 80 untouched 62
|
||||||
|
tcp st 00 tmr 00 rtx 00 rto 00 len 0x0000 mss 0x05b4
|
||||||
|
lport 0x0000 rport 0x0000 rip 0x0000 0x0000
|
||||||
|
httpd left 0x0000 entry 00 stp 01 mvlan 0x0002
|
||||||
|
```
|
||||||
|
|
||||||
|
The instrumentation is not part of a default build. It costs about 1.1 kB
|
||||||
|
of bank 2, a few bytes of xdata and seven banked calls per main-loop pass,
|
||||||
|
which is nothing a user needs unless they are chasing a problem, so it is
|
||||||
|
switched on at build time:
|
||||||
|
|
||||||
|
```
|
||||||
|
make MACHINE=SWTGW218AS HEALTH=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Without it the hooks compile to nothing and `health` is not a command.
|
||||||
|
|
||||||
|
All figures are raw hex. The counters are cumulative: take two dumps a known
|
||||||
|
time apart and the differences give the rates.
|
||||||
|
|
||||||
|
## The first line
|
||||||
|
|
||||||
|
`up` is the seconds counter, `ticks` the system tick (200 per second),
|
||||||
|
`loops` the number of main-loop passes and `rx` the frames handle_rx has
|
||||||
|
taken off the NIC. A healthy loop completes one pass per tick, so the
|
||||||
|
difference in `loops` tracks the difference in `ticks`; a loop that falls
|
||||||
|
behind is being held up by one of the phases below. The `rx` rate separates
|
||||||
|
a flooded CPU port from a stalled loop, which look identical from outside.
|
||||||
|
|
||||||
|
## Phases
|
||||||
|
|
||||||
|
Each line is one section of the main loop: the link poll, SFP handling,
|
||||||
|
frame reception, TCP transmission, the STP timers and the command dispatch.
|
||||||
|
`max` is the worst time that section has taken, in ticks of 5 ms; `slow`
|
||||||
|
counts the passes that took two ticks or more. A misbehaving subsystem
|
||||||
|
names itself here, which is the difference between knowing that the loop is
|
||||||
|
slow and knowing why.
|
||||||
|
|
||||||
|
A dump of its own output takes the console some milliseconds, so running
|
||||||
|
`health` repeatedly increments the `cmd` counters by itself. That is the
|
||||||
|
instrument observing itself, not a fault.
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
At boot the free stack area is painted with a pattern. `sp` is the live
|
||||||
|
stack pointer; `untouched` counts the painted bytes still intact at the top,
|
||||||
|
which is the closest thing to a high-water mark this hardware offers. A
|
||||||
|
shrinking `untouched` across dumps means something is reaching deeper than
|
||||||
|
anything before it.
|
||||||
|
|
||||||
|
## The TCP slot
|
||||||
|
|
||||||
|
The connection table is printed whole, one slot per pair of lines: TCP
|
||||||
|
state (3 is ESTABLISHED, 0 closed), retransmission timer and counter, bytes
|
||||||
|
in flight, negotiated MSS, then the ports and the peer address. With a
|
||||||
|
single slot serving the entire web interface, one glance answers the
|
||||||
|
question every management outage starts with: who is holding it. A slot
|
||||||
|
showing state 3 with nothing in flight and a peer that no longer answers is
|
||||||
|
a connection whose owner went away.
|
||||||
|
|
||||||
|
`httpd left` and `entry` describe the file transfer the web server believes
|
||||||
|
it is in the middle of, and the trailing flags show whether STP is running
|
||||||
|
and which VLAN carries management.
|
||||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 120 KiB |
@@ -6,6 +6,8 @@ The following devices have been tested and are fully working:
|
|||||||
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
||||||
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
|
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
|
||||||
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
|
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
|
||||||
|
| Goalake | IG108 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||||
|
| Hasivo | S1100WP_8GT_1SX_SE | Yes | [S1100WP_8GT_1SX_SE-V1.05](devices/HASIVO_S1100WP_8GT_1SX_SE.md) | 2M | 8 + 1 |
|
||||||
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
|
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
|
||||||
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
||||||
@@ -21,9 +23,11 @@ The following devices have been tested and are fully working:
|
|||||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
|
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
|
||||||
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
|
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
|
||||||
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
||||||
|
| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
|
||||||
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
||||||
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||||
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
||||||
|
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||||
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
|
||||||
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
|
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
|
||||||
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
@@ -33,7 +37,7 @@ The following devices have been tested and are fully working:
|
|||||||
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
|
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
|
||||||
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||||
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||||
| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
|
| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 |
|
||||||
|
|
||||||
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
|
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
|
||||||
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
|
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ sy_rebooting:"Rebooting, reconnect in about 20 s",sy_bytes:"bytes",
|
|||||||
cw_title:"Write this startup configuration?",cw_save_title:"Save running configuration to flash?",
|
cw_title:"Write this startup configuration?",cw_save_title:"Save running configuration to flash?",
|
||||||
cw_info:"{n} / 2048 bytes, replayed line by line on every boot",
|
cw_info:"{n} / 2048 bytes, replayed line by line on every boot",
|
||||||
cw_toolarge:"Too large: the config sector accepts at most 2048 bytes. Remove lines first.",
|
cw_toolarge:"Too large: the config sector accepts at most 2048 bytes. Remove lines first.",
|
||||||
|
cw_longline:"Line {n} is {m} bytes long: the switch can only replay lines up to 126 bytes and would skip it on boot, so the write is refused. Shorten it first.",
|
||||||
cw_unknown:"Not in the known config grammar (will still be written): ",cw_empty:"(empty)",
|
cw_unknown:"Not in the known config grammar (will still be written): ",cw_empty:"(empty)",
|
||||||
cw_writing:"Writing configuration...",cw_failed:"config write failed: HTTP {n}",
|
cw_writing:"Writing configuration...",cw_failed:"config write failed: HTTP {n}",
|
||||||
cw_verify_fail:"Verification failed: flash content differs from what was sent. Command log NOT cleared.",
|
cw_verify_fail:"Verification failed: flash content differs from what was sent. Command log NOT cleared.",
|
||||||
@@ -203,6 +204,7 @@ sy_rebooting:"再起動中です。約 20 秒後に再接続してください",
|
|||||||
cw_title:"この起動設定を書き込みますか?",cw_save_title:"実行中の設定をフラッシュに保存しますか?",
|
cw_title:"この起動設定を書き込みますか?",cw_save_title:"実行中の設定をフラッシュに保存しますか?",
|
||||||
cw_info:"{n} / 2048 バイト、起動のたびに 1 行ずつ実行されます",
|
cw_info:"{n} / 2048 バイト、起動のたびに 1 行ずつ実行されます",
|
||||||
cw_toolarge:"サイズ超過: 設定セクタは最大 2048 バイトです。先に行を削除してください。",
|
cw_toolarge:"サイズ超過: 設定セクタは最大 2048 バイトです。先に行を削除してください。",
|
||||||
|
cw_longline:"{n} 行目は {m} バイトです: スイッチが起動時に実行できる行は 126 バイトまでで、この行は読み飛ばされるため、書き込みを拒否します。先に短くしてください。",
|
||||||
cw_unknown:"既知の設定文法に含まれない行 (そのまま書き込まれます): ",cw_empty:"(空)",
|
cw_unknown:"既知の設定文法に含まれない行 (そのまま書き込まれます): ",cw_empty:"(空)",
|
||||||
cw_writing:"設定を書き込み中...",cw_failed:"設定の書き込みに失敗しました: HTTP {n}",
|
cw_writing:"設定を書き込み中...",cw_failed:"設定の書き込みに失敗しました: HTTP {n}",
|
||||||
cw_verify_fail:"検証失敗: フラッシュの内容が送信内容と異なります。コマンドログは消去されていません。",
|
cw_verify_fail:"検証失敗: フラッシュの内容が送信内容と異なります。コマンドログは消去されていません。",
|
||||||
@@ -315,6 +317,7 @@ sy_rebooting:"正在重启,约 20 秒后重新连接",sy_bytes:"字节",
|
|||||||
cw_title:"写入此启动配置?",cw_save_title:"将运行配置保存到 Flash?",
|
cw_title:"写入此启动配置?",cw_save_title:"将运行配置保存到 Flash?",
|
||||||
cw_info:"{n} / 2048 字节,每次启动时逐行执行",
|
cw_info:"{n} / 2048 字节,每次启动时逐行执行",
|
||||||
cw_toolarge:"过大: 配置扇区最多容纳 2048 字节。请先删除部分行。",
|
cw_toolarge:"过大: 配置扇区最多容纳 2048 字节。请先删除部分行。",
|
||||||
|
cw_longline:"第 {n} 行有 {m} 字节: 交换机启动时只能执行不超过 126 字节的行,该行会被跳过,因此拒绝写入。请先缩短该行。",
|
||||||
cw_unknown:"不属于已知配置语法的行 (仍会写入): ",cw_empty:"(空)",
|
cw_unknown:"不属于已知配置语法的行 (仍会写入): ",cw_empty:"(空)",
|
||||||
cw_writing:"正在写入配置...",cw_failed:"配置写入失败: HTTP {n}",
|
cw_writing:"正在写入配置...",cw_failed:"配置写入失败: HTTP {n}",
|
||||||
cw_verify_fail:"校验失败: Flash 内容与发送内容不一致。命令日志未清除。",
|
cw_verify_fail:"校验失败: Flash 内容与发送内容不一致。命令日志未清除。",
|
||||||
@@ -335,6 +338,117 @@ fw_applied:"升级已应用",fw_done_t:"固件已升级",
|
|||||||
fw_done:"交换机已校验镜像并以新镜像重启。会话已重置,需要重新登录。",
|
fw_done:"交换机已校验镜像并以新镜像重启。会话已重置,需要重新登录。",
|
||||||
fw_login:"前往登录",fw_rebooting:"交换机正在重启...",
|
fw_login:"前往登录",fw_rebooting:"交换机正在重启...",
|
||||||
fw_timeout:"150 秒后交换机仍未恢复: 请检查电源 / 串口控制台"
|
fw_timeout:"150 秒后交换机仍未恢复: 请检查电源 / 串口控制台"
|
||||||
|
},
|
||||||
|
es:{
|
||||||
|
nav_dash:"Panel",nav_ports:"Puertos",nav_stp:"Árbol de expansión",nav_stats:"Estadísticas",
|
||||||
|
nav_vlan:"VLAN",nav_l2:"Tabla MAC",nav_mirror:"Duplicación",nav_lag:"LAG",nav_eee:"EEE",
|
||||||
|
nav_bw:"Ancho de banda",nav_system:"Sistema",nav_fw:"Firmware",
|
||||||
|
hdr_dirty:"cambios sin guardar",hdr_dirty_t:"La configuración en ejecución difiere de la guardada",
|
||||||
|
hdr_save:"Guardar en flash",hdr_save_t:"Persistir la configuración en ejecución a flash",
|
||||||
|
th_auto:"Sistema",th_auto_sel:"Sistema (Selenized)",sy_display:"Pantalla",sy_theme:"Tema",sy_display_note:"Se almacena solo en este navegador.",th_light:"Claro",th_dark:"Oscuro",
|
||||||
|
th_sel_light:"Selenized claro",th_sel_dark:"Selenized oscuro",
|
||||||
|
c_port:"Puerto",c_name:"Nombre",c_link:"Enlace",c_apply:"Aplicar",c_cancel:"Cancelar",c_confirm:"Confirmar",
|
||||||
|
c_close:"Cerrar",c_refresh:"Actualizar",c_off:"apagado",c_offc:"Apagado",c_down:"caído",c_on:"Encendido",c_auto:"Auto",c_delete:"Eliminar",
|
||||||
|
c_type:"Tipo",c_state:"Estado",c_enabled:"Habilitado",c_load:"Cargar",c_disable:"Deshabilitar",c_sfp:"SFP",
|
||||||
|
c_full:"dúplex completo",c_half:"semidúplex",c_devices:"dispositivos",c_yes:"sí",c_no:"no",
|
||||||
|
d_ports:"Puertos",d_ports_h:"pulsa un puerto para ver detalles",d_system:"Sistema",d_traffic:"Tráfico",
|
||||||
|
d_traffic_h:"paquetes/s, en vivo",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX erróneos",d_rxbad:"RX erróneos",
|
||||||
|
i_host:"Nombre de host",i_ip:"Dirección IP",i_mask:"Máscara de red",i_gw:"Puerta de enlace",i_mac:"MAC",i_fw:"Firmware",
|
||||||
|
i_built:"Compilado",i_hw:"Hardware",i_flash:"Flash",i_syslog:"Syslog",
|
||||||
|
p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo",p_txgb:"TX correctos / erróneos",p_rxgb:"RX correctos / erróneos",
|
||||||
|
p_pkts:"paquetes",p_module:"Módulo",p_temp:"Temperatura",p_vcc:"Vcc",p_txbias:"Polarización TX",p_txpower:"Potencia TX",
|
||||||
|
p_rxpower:"Potencia RX",p_txfault:"Fallo TX",p_txdis:"TX deshabilitado",p_rxlos:"Pérdida RX (LOS)",p_adv:"Anunciado",
|
||||||
|
pt_title:"Configuración de puerto",pt_conn:"Conectado",pt_speed:"Velocidad",pt_mtu:"MTU",
|
||||||
|
pt_sfp_note:"La velocidad del SFP se ajusta por ranura y no se guarda en la configuración de inicio.",
|
||||||
|
pt_name_err:"Nombre de puerto: 1-15 caracteres, sin espacios",pt_mtu_err:"El MTU debe estar entre 64 y 16383",
|
||||||
|
stp_title:"Árbol de expansión",stp_h:"RSTP, 802.1w",stp_version:"Versión",stp_v_stp:"STP compatible",
|
||||||
|
stp_prio:"Prioridad del puente",stp_hello:"Hello [s]",stp_maxage:"Edad máxima [s]",stp_fwd:"Retardo de reenvío [s]",
|
||||||
|
stp_txhold:"Retención TX",stp_bridge_apply:"Aplicar ajustes del puente",
|
||||||
|
stp_off_msg:"El árbol de expansión está deshabilitado: todos los puertos reenvían.",stp_bridge:"Puente",stp_root:"Raíz",
|
||||||
|
stp_root_self:"este puente es la raíz",stp_via:"vía puerto",stp_cost:"coste de ruta",stp_tc:"cambios de topología",
|
||||||
|
stp_prio_note:"La prioridad más baja gana la elección de raíz (8 por defecto = 32768). Los ajustes se aplican inmediatamente; usa Guardar en flash para conservarlos.",
|
||||||
|
stp_portcfg:"Configuración de puertos",stp_edge:"Borde",stp_pcost:"Coste de ruta",stp_pprio:"Prioridad",
|
||||||
|
stp_guard:"Protección",stp_filter:"Filtro BPDU",stp_p2p:"Punto a punto",
|
||||||
|
stp_port_note:"Los puertos de borde reenvían inmediatamente y no causan cambios de topología; Auto trata un puerto como de borde tras 3 s sin BPDUs, y cualquier BPDU recibido lo revoca. Coste de ruta 0 = automático.",
|
||||||
|
stp_status:"Estado de puertos",stp_role:"Rol",stp_db:"Puente designado",stp_dp:"Puerto designado",
|
||||||
|
stp_dc:"Coste designado",stp_oedge:"Borde operativo",stp_op2p:"P2P operativo",
|
||||||
|
stp_s0:"deshabilitado",stp_s1:"bloqueo",stp_s2:"aprendizaje",stp_s3:"reenvío",
|
||||||
|
stp_r1:"Raíz",stp_r2:"Designado",stp_r3:"Alternativo",stp_trip:"protección disparada",
|
||||||
|
stp_g_none:"Ninguno",stp_g_bpdu:"BPDU",stp_g_root:"Raíz",
|
||||||
|
stp_en_q:"¿Habilitar el árbol de expansión?",
|
||||||
|
stp_en_d:"Los puertos empiezan bloqueados y tardan hasta el doble del retardo de reenvío en alcanzar el reenvío; los puertos de borde se recuperan inmediatamente.",
|
||||||
|
stp_dis_q:"¿Deshabilitar el árbol de expansión?",stp_dis_d:"Todos los puertos pasan directamente a reenviar; se pierde la protección contra bucles.",
|
||||||
|
stp_cost_err:"El coste de ruta debe estar entre 0 y 200000000",
|
||||||
|
st_title:"Estadísticas de puertos",st_h:"totales desde el arranque",st_txg:"TX correctos",st_txb:"TX erróneos",st_rxg:"RX correctos",
|
||||||
|
st_rxb:"RX erróneos",st_details:"Detalles",st_counters:"Contadores MIB",st_nonzero:"solo no nulos",
|
||||||
|
st_autoref:"actualización automática",st_counter:"Contador",st_value:"Valor",st_fail:"error al cargar contadores",
|
||||||
|
v_title:"VLANs",v_vid:"VID",v_members:"Miembros",v_tagged:"Etiquetados",v_untagged:"Sin etiquetar",v_pvid_on:"PVID activo",
|
||||||
|
v_empty:"No hay VLANs configuradas.",v_mgmt:"VLAN de gestión",v_mgmt_none:"sin etiquetar",v_editor:"Editor de VLANs",
|
||||||
|
v_optional:"opcional",v_setmgmt:"Establecer como VLAN de gestión",v_setmgmt_t:"Hacer esta la VLAN de gestión",
|
||||||
|
v_member:"Miembro",v_pvid:"PVID",
|
||||||
|
v_legend:"U = miembro sin etiquetar, T = miembro etiquetado, - = no miembro. PVID asigna esta VLAN al tráfico entrante sin etiquetar.",
|
||||||
|
v_ingress:"Filtrado de entrada",v_ingress_h:"solo escritura: el estado no se puede leer desde el switch",
|
||||||
|
v_accept:"Aceptar",v_ing_all:"Todos",v_ing_apply:"Aplicar modos de entrada",v_del_t:"Eliminar VLAN",
|
||||||
|
v_del_q:"¿Eliminar VLAN {n}?",v_del_d:"Los puertos conservan su PVID hasta que se reasignen.",
|
||||||
|
v_vid_err:"Introduce un ID de VLAN (1-4094)",v_name_err:"El nombre debe empezar por una letra (letras, dígitos, _)",
|
||||||
|
v_loaded:"VLAN {n} cargada",v_notfound:"VLAN {n} no encontrada (aún se puede crear una nueva)",
|
||||||
|
v_nomember:"Selecciona al menos un puerto miembro (o elimina la VLAN)",
|
||||||
|
v_ing_none:"Elige un modo de entrada para al menos un puerto",v_vid_first:"Introduce primero un ID de VLAN",
|
||||||
|
v_mgmt_q:"¿Establecer VLAN {n} como VLAN de gestión?",
|
||||||
|
v_mgmt_d:"El switch empezará a etiquetar su propio tráfico con esa VLAN. Si el puerto por el que te conectas no la transporta, esta página dejará de ser accesible y el ajuste solo podrá deshacerse por la consola.",
|
||||||
|
l2_title:"Tabla de direcciones MAC",l2_filter:"filtrar...",l2_flush:"Vaciar entradas aprendidas",l2_static:"estática",
|
||||||
|
l2_learned:"aprendida",l2_loading:"cargando...",l2_failed:"error de carga",l2_entries:"entradas",
|
||||||
|
l2_del_t:"Eliminar entrada",l2_flush_q:"¿Vaciar todas las entradas MAC aprendidas?",
|
||||||
|
m_title:"Duplicación de puertos",m_active:"activa",m_monitor:"Puerto monitor",m_mirror:"Duplicar",m_both:"Ambos",
|
||||||
|
m_note:"Ambos = duplica RX y TX del puerto al puerto monitor.",m_none:"Selecciona al menos un puerto duplicado",
|
||||||
|
lag_hash:"Hash:",lag_note:"Un LAG necesita al menos un miembro para guardarse en la configuración de inicio; aplicar un grupo vacío lo borra.",
|
||||||
|
lag_clear_q:"¿Borrar LAG {n}?",lag_clear_d:"Todos los puertos miembros vuelven a la operación normal.",
|
||||||
|
e_title:"Ethernet de bajo consumo",e_adv:"Anunciado",e_lp:"Par de enlace",e_active:"Activo",e_enable:"Habilitar",
|
||||||
|
e_note:"Banderas anunciadas y del socio de enlace por velocidad: 100M, 1G, 2.5G. Los puertos SFP no soportan EEE.",
|
||||||
|
e_idle:"inactivo",e_na:"n/d",
|
||||||
|
bw_title:"Límites de ancho de banda",bw_h:"Mbit/s, 0.016-10000",bw_in:"Límite de entrada",bw_out:"Límite de salida",
|
||||||
|
bw_exceed:"Al excederse",bw_fc:"Control de flujo",bw_drop:"Descartar",
|
||||||
|
bw_in_err:"El límite de entrada debe estar entre 0.016 y 10000 Mbit/s",bw_out_err:"El límite de salida debe estar entre 0.016 y 10000 Mbit/s",
|
||||||
|
sy_network:"Red",sy_dhcp:"Usar DHCP",sy_dhcp_t:"Solicitar dirección mediante DHCP",sy_services:"Servicios",
|
||||||
|
sy_igmp:"IGMP snooping",sy_sysip:"IP del servidor",sy_server:"Servidor",sy_port:"Puerto",
|
||||||
|
sy_services_note:"El estado del servicio refleja la configuración de inicio; el estado en ejecución no es legible.",
|
||||||
|
sy_password:"Contraseña de administrador",sy_newpw:"Nueva contraseña",sy_repeat:"Repetir",sy_pwapply:"Cambiar contraseña",
|
||||||
|
sy_pw_note:"Toma efecto inmediatamente; guarda en flash para conservarla tras el reinicio.",sy_console:"Consola",
|
||||||
|
sy_cmd:"Comando de CLI...",sy_send:"Enviar",sy_startup:"Configuración de inicio",sy_replayed:"reaplicada en cada arranque",
|
||||||
|
sy_reload:"Recargar desde flash",sy_write:"Escribir en flash",sy_unknown_note:"Las líneas desconocidas se resaltan antes de escribir.",
|
||||||
|
sy_maint:"Mantenimiento",sy_reboot:"Reiniciar switch",sy_lang:"Idioma",
|
||||||
|
sy_ip_err:"IP / máscara / puerta de enlace no válidos",sy_host_err:"Nombre de host: 1-23 caracteres imprimibles, sin espacios ni comillas",
|
||||||
|
sy_net_q:"¿Aplicar ajustes de red?",sy_net_d:"La IP de gestión cambia a {ip}: esta página deberá reabrirse allí.",
|
||||||
|
sy_ip_changed:"IP cambiada, reconecta en http://{ip}/",sy_dhcp_q:"¿Cambiar a DHCP?",
|
||||||
|
sy_dhcp_d:"El switch solicita una dirección mediante DHCP. Deberás encontrar su nueva IP para reconectar.",
|
||||||
|
sy_sysip_err:"IP del servidor syslog no válida",sy_sysport_err:"El puerto de syslog debe estar entre 1 y 65535",
|
||||||
|
sy_pw_len:"Contraseña: 1-20 caracteres",sy_pw_space:"La contraseña no puede contener espacios",sy_pw_match:"Las contraseñas no coinciden",
|
||||||
|
sy_pw_q:"¿Cambiar la contraseña de administrador?",sy_pw_d:"Toma efecto inmediatamente para los nuevos inicios de sesión. Guarda en flash para persistir.",
|
||||||
|
sy_reboot_q:"¿Reiniciar el switch?",sy_reboot_d:"Hay cambios SIN GUARDAR y se perderán. Guarda en flash primero si quieres conservarlos.",
|
||||||
|
sy_rebooting:"Reiniciando, reconecta en unos 20 s",sy_bytes:"bytes",
|
||||||
|
cw_title:"¿Escribir esta configuración de inicio?",cw_save_title:"¿Guardar la configuración en ejecución en flash?",
|
||||||
|
cw_info:"{n} / 2048 bytes, reaplicada línea a línea en cada arranque",
|
||||||
|
cw_toolarge:"Demasiado grande: el sector de configuración admite como máximo 2048 bytes. Elimina líneas primero.",
|
||||||
|
cw_unknown:"No está en la gramática de configuración conocida (aun así se escribirá): ",cw_empty:"(vacío)",
|
||||||
|
cw_writing:"Escribiendo configuración...",cw_failed:"error al escribir la configuración: HTTP {n}",
|
||||||
|
cw_verify_fail:"Verificación fallida: el contenido de la flash difiere de lo enviado. El registro de comandos NO se ha borrado.",
|
||||||
|
cw_saved:"Configuración de inicio guardada y verificada",cw_collect:"Recopilando cambios en ejecución...",
|
||||||
|
t_applied:"Aplicado: {c}",t_cmds:"{n} comando(s) aplicado(s)",t_rejected:"comando rechazado: {c}",t_failed:"fallo: {c}",
|
||||||
|
fw_title:"Actualización de firmware",
|
||||||
|
fw_intro:"Sube una imagen de RTLPlayground (512 KiB .bin). La imagen se almacena provisionalmente en flash y se comprueba con CRC; si es correcta, el switch se reinicia, vuelve a verificar la imagen y la aplica. La configuración de inicio se conserva.",
|
||||||
|
fw_upload:"Subir",fw_checking:"{f}: {n} bytes. Comprobando...",fw_size_err:"el tamaño es {n}, se esperaban 524288 (512 KiB)",
|
||||||
|
fw_magic_err:"falta la cabecera de banco / magia LJMP: no es una imagen de firmware",fw_crc_err:"comprobación CRC16 fallida: imagen corrupta",
|
||||||
|
fw_valid:"imagen de RTLPlayground válida (tamaño, magia y CRC16 correctos)",fw_q:"¿Subir firmware?",
|
||||||
|
fw_d:"Si la suma de comprobación es correcta, el switch se reinicia y aplica la imagen durante el arranque (la configuración de inicio se conserva). No lo apagues hasta que vuelva.",
|
||||||
|
fw_finishing:"terminando escritura en flash... {s} s",fw_uploading:"subiendo... {p}% / {s} s",
|
||||||
|
fw_verified:"suma de comprobación verificada, el switch se está reiniciando...",
|
||||||
|
fw_rejected:"el switch rechazó la imagen (suma de comprobación incorrecta), no se aplicó nada",
|
||||||
|
fw_lost:"error de subida: conexión perdida durante la transferencia",
|
||||||
|
fw_noreboot:"no se detectó reinicio: lo más probable es que la imagen fuera rechazada. Si actualizas desde un firmware antiguo, verifica la versión en la barra lateral tras volver a iniciar sesión.",
|
||||||
|
fw_applied:"actualización aplicada",fw_done_t:"Firmware actualizado",
|
||||||
|
fw_done:"El switch verificó la imagen y se reinició con ella. La sesión se restableció, así que se te pedirá que vuelvas a iniciar sesión.",
|
||||||
|
fw_login:"Ir al inicio de sesión",fw_rebooting:"el switch se está reiniciando...",
|
||||||
|
fw_timeout:"el switch no ha vuelto tras 150 s: comprueba la alimentación / consola serie"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var rtlLang=(function(){
|
var rtlLang=(function(){
|
||||||
@@ -438,7 +552,7 @@ var CONF_CMDS=[
|
|||||||
/^ingress(\s+\d{1,2}[tua])+$/,/^ingress\s+[tua]$/,
|
/^ingress(\s+\d{1,2}[tua])+$/,/^ingress\s+[tua]$/,
|
||||||
/^port\s+\d{1,2}\s+(10m|100m|1g|2g5|5g|10g|auto|on|off)(\s+(half|full))?$/,
|
/^port\s+\d{1,2}\s+(10m|100m|1g|2g5|5g|10g|auto|on|off)(\s+(half|full))?$/,
|
||||||
/^port\s+\d{1,2}\s+name\s+\S+$/,
|
/^port\s+\d{1,2}\s+name\s+\S+$/,
|
||||||
/^eee(\s+\d{1,2})?\s+(on|off)$/,
|
/^eee\s+(on|off)(\s+\d{1,2})?(\s+(100m|1g|2g5))?$/,
|
||||||
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,/^mirror\s+off$/,
|
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,/^mirror\s+off$/,
|
||||||
/^lag\s+[1-4](\s+\d{1,2})+$/,/^lag\s+[1-4]\s+d$/,/^laghash\s+[1-4](\s+\w+)+$/,
|
/^lag\s+[1-4](\s+\d{1,2})+$/,/^lag\s+[1-4]\s+d$/,/^laghash\s+[1-4](\s+\w+)+$/,
|
||||||
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
|
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
|
||||||
@@ -537,13 +651,18 @@ TABS.forEach(function(tb){
|
|||||||
});
|
});
|
||||||
$("burger").addEventListener("click",function(){$("nav").classList.toggle("open")});
|
$("burger").addEventListener("click",function(){$("nav").classList.toggle("open")});
|
||||||
|
|
||||||
|
var IDLE_STOP_MS=600000,lastInput=Date.now();
|
||||||
|
["mousemove","mousedown","keydown","touchstart","wheel"].forEach(function(ev){
|
||||||
|
addEventListener(ev,function(){lastInput=Date.now()},{passive:true});
|
||||||
|
});
|
||||||
function Poller(fn,ms){this.fn=fn;this.ms=ms;this.on=false;this.t=null}
|
function Poller(fn,ms){this.fn=fn;this.ms=ms;this.on=false;this.t=null}
|
||||||
Poller.prototype.start=function(){if(this.on)return;this.on=true;this.tick()};
|
Poller.prototype.start=function(){if(this.on)return;this.on=true;this.tick()};
|
||||||
Poller.prototype.stop=function(){this.on=false;clearTimeout(this.t)};
|
Poller.prototype.stop=function(){this.on=false;clearTimeout(this.t)};
|
||||||
Poller.prototype.tick=function(){
|
Poller.prototype.tick=function(){
|
||||||
var self=this;
|
var self=this;
|
||||||
if(!self.on)return;
|
if(!self.on)return;
|
||||||
var run=document.hidden?Promise.resolve():Promise.resolve().then(self.fn).catch(function(){});
|
var quiet=document.hidden||Date.now()-lastInput>IDLE_STOP_MS;
|
||||||
|
var run=quiet?Promise.resolve():Promise.resolve().then(self.fn).catch(function(){});
|
||||||
run.then(function(){ if(self.on)self.t=setTimeout(function(){self.tick()},self.ms); });
|
run.then(function(){ if(self.on)self.t=setTimeout(function(){self.tick()},self.ms); });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -727,6 +846,7 @@ tabHooks.dash={
|
|||||||
var SPEEDS=[["auto","c_auto"],["2g5","2.5G"],["1g","1G"],["100m full","100M full"],
|
var SPEEDS=[["auto","c_auto"],["2g5","2.5G"],["1g","1G"],["100m full","100M full"],
|
||||||
["100m half","100M half"],["10m full","10M full"],["10m half","10M half"]];
|
["100m half","100M half"],["10m full","10M full"],["10m half","10M half"]];
|
||||||
var SFPRATES=[["auto","c_auto"],["10g","10G"],["2g5","2.5G"],["1g","1G"],["100m","100M"]];
|
var SFPRATES=[["auto","c_auto"],["10g","10G"],["2g5","2.5G"],["1g","1G"],["100m","100M"]];
|
||||||
|
var ADVSEL={63:"auto",31:"auto",32:"2g5",16:"1g",8:"100m full",4:"100m half",2:"10m full",1:"10m half"};
|
||||||
function speedLabel(s){
|
function speedLabel(s){
|
||||||
if(s==="c_auto")return t("c_auto");
|
if(s==="c_auto")return t("c_auto");
|
||||||
return s.replace(" full"," "+t("c_full")).replace(" half"," "+t("c_half"));
|
return s.replace(" full"," "+t("c_full")).replace(" half"," "+t("c_half"));
|
||||||
@@ -789,6 +909,8 @@ function portsStatus(){
|
|||||||
S.ports.forEach(function(p){
|
S.ports.forEach(function(p){
|
||||||
var i=p.portNum-1,el=$("plink"+i);
|
var i=p.portNum-1,el=$("plink"+i);
|
||||||
if(el)el.innerHTML=linkBadge(p);
|
if(el)el.innerHTML=linkBadge(p);
|
||||||
|
var sel=$("pspd"+i),v=p.isSFP?0:ADVSEL[parseInt(p.adv,2)];
|
||||||
|
if(sel&&v&&document.activeElement!==sel)sel.value=v;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function applyPort(i){
|
function applyPort(i){
|
||||||
@@ -1428,7 +1550,7 @@ function eeeLoad(){
|
|||||||
var on=parseInt(p.eee,2)!==0;
|
var on=parseInt(p.eee,2)!==0;
|
||||||
var sw=h("label",{class:"switch"},[
|
var sw=h("label",{class:"switch"},[
|
||||||
h("input",{type:"checkbox",onchange:function(){
|
h("input",{type:"checkbox",onchange:function(){
|
||||||
postCmd("eee "+p.portNum+" "+(this.checked?"on":"off"))
|
postCmd("eee "+(this.checked?"on":"off")+" "+p.portNum)
|
||||||
.then(function(){setTimeout(eeeLoad,300)}).catch(function(){});
|
.then(function(){setTimeout(eeeLoad,300)}).catch(function(){});
|
||||||
}}),h("i")]);
|
}}),h("i")]);
|
||||||
sw.firstChild.checked=on;
|
sw.firstChild.checked=on;
|
||||||
@@ -1606,11 +1728,16 @@ function cfgReload(){
|
|||||||
cfgParseKnown(x);
|
cfgParseKnown(x);
|
||||||
}).catch(function(){});
|
}).catch(function(){});
|
||||||
}
|
}
|
||||||
|
function cfgLongLine(v){
|
||||||
|
var ls=v.split("\n");
|
||||||
|
for(var i=0;i<ls.length;i++){var n=new Blob([ls[i]]).size;if(n>126)return{n:i+1,m:n};}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
function cfgBytes(){
|
function cfgBytes(){
|
||||||
var n=new Blob([$("cfgedit").value]).size;
|
var v=$("cfgedit").value,n=new Blob([v]).size;
|
||||||
var el=$("cfgbytes");
|
var el=$("cfgbytes");
|
||||||
el.textContent=n+" / 2048 "+t("sy_bytes");
|
el.textContent=n+" / 2048 "+t("sy_bytes");
|
||||||
el.style.color=n>2048?"var(--bad)":"";
|
el.style.color=(n>2048||cfgLongLine(v))?"var(--bad)":"";
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
$("cfgedit").addEventListener("input",cfgBytes);
|
$("cfgedit").addEventListener("input",cfgBytes);
|
||||||
@@ -1624,9 +1751,9 @@ var CONF_OVERWRITE=[
|
|||||||
/^ip\b/,/^gw\b/,/^netmask\b/,/^hostname\b/,
|
/^ip\b/,/^gw\b/,/^netmask\b/,/^hostname\b/,
|
||||||
/^syslog\s+ip\b/,/^syslog\s+port\b/,/^passwd\b/,/^session\b/,
|
/^syslog\s+ip\b/,/^syslog\s+port\b/,/^passwd\b/,/^session\b/,
|
||||||
/^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
|
/^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
|
||||||
/^pvid\s+\d{1,2}\b/,/^ingress\b/,
|
/^pvid\s+\d{1,2}\b/,
|
||||||
/^port\s+\d{1,2}(?!\s+name\b)/,/^port\s+\d{1,2}\s+name\b/,
|
/^port\s+\d{1,2}(?!\s+name\b)/,/^port\s+\d{1,2}\s+name\b/,
|
||||||
/^eee\s+\d{1,2}\b/,/^eee\b/,/^mirror\b/,
|
/^mirror\b/,
|
||||||
/^lag\s+\d\b/,/^laghash\s+\d\b/,/^isolate\s+\d{1,2}\b/,
|
/^lag\s+\d\b/,/^laghash\s+\d\b/,/^isolate\s+\d{1,2}\b/,
|
||||||
/^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/,
|
/^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/,
|
||||||
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+(edge|cost|prio|guard|filter|p2p)\b/,
|
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+(edge|cost|prio|guard|filter|p2p)\b/,
|
||||||
@@ -1643,8 +1770,28 @@ function mergeConf(base,texts){
|
|||||||
var m;
|
var m;
|
||||||
if((m=line.match(/^vlan (\d{1,4}) d$/))){drop(new RegExp("^vlan "+m[1]+"( |$)"));return;}
|
if((m=line.match(/^vlan (\d{1,4}) d$/))){drop(new RegExp("^vlan "+m[1]+"( |$)"));return;}
|
||||||
if((m=line.match(/^lag (\d) d$/))){drop(new RegExp("^lag(hash)? "+m[1]+"( |$)"));return;}
|
if((m=line.match(/^lag (\d) d$/))){drop(new RegExp("^lag(hash)? "+m[1]+"( |$)"));return;}
|
||||||
|
if((m=line.match(/^eee (on|off)(?: (\d{1,2}))?(?: (?:100m|1g|2g5))?$/))){
|
||||||
|
if(m[2])drop(new RegExp("^eee (on|off) "+m[2]+"\\b"));
|
||||||
|
else drop(/^eee /);
|
||||||
|
conf.push(line);return;
|
||||||
|
}
|
||||||
if(line==="mirror off"){drop(/^mirror /);return;}
|
if(line==="mirror off"){drop(/^mirror /);return;}
|
||||||
if(!isConfCmd(line))return;
|
if(!isConfCmd(line))return;
|
||||||
|
if((m=line.match(/^ingress (.+)$/))){
|
||||||
|
if(/^[tua]$/.test(m[1])){drop(/^ingress /);conf.push(line);return;}
|
||||||
|
var ports={},order=[],last=-1;
|
||||||
|
conf.forEach(function(c,i){if(/^ingress [tua]$/.test(c))last=i;});
|
||||||
|
conf.forEach(function(c,i){
|
||||||
|
var cm=c.match(/^ingress (.+)$/);
|
||||||
|
if(!cm||/^[tua]$/.test(cm[1])||i<last)return;
|
||||||
|
cm[1].split(" ").forEach(function(tk){var n=tk.slice(0,-1);if(!(n in ports))order.push(n);ports[n]=tk;});
|
||||||
|
});
|
||||||
|
m[1].split(" ").forEach(function(tk){var n=tk.slice(0,-1);if(!(n in ports))order.push(n);ports[n]=tk;});
|
||||||
|
conf=conf.filter(function(c){var cm=c.match(/^ingress (.+)$/);return!cm||/^[tua]$/.test(cm[1])});
|
||||||
|
order.sort(function(a,b){return a-b});
|
||||||
|
conf.push("ingress "+order.map(function(n){return ports[n]}).join(" "));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if((m=line.match(/^bw (in|out) (\d{1,2}) (\S+)$/))){
|
if((m=line.match(/^bw (in|out) (\d{1,2}) (\S+)$/))){
|
||||||
var pre="^bw "+m[1]+" "+m[2]+" ";
|
var pre="^bw "+m[1]+" "+m[2]+" ";
|
||||||
if(m[1]==="out"||m[3]==="off")drop(new RegExp(pre));
|
if(m[1]==="out"||m[3]==="off")drop(new RegExp(pre));
|
||||||
@@ -1672,18 +1819,18 @@ function mergeConf(base,texts){
|
|||||||
});
|
});
|
||||||
return conf;
|
return conf;
|
||||||
}
|
}
|
||||||
function writeConfig(txt,title){
|
function writeConfig(txt,title,fromLog){
|
||||||
var info=h("p",{class:"small mut"}),warn=h("p",{class:"small"});
|
var info=h("p",{class:"small mut"}),warn=h("p",{class:"small"});
|
||||||
var ed=h("textarea",{class:"cfg",spellcheck:"false",placeholder:t("cw_empty"),style:"min-height:45vh"});
|
var ed=h("textarea",{class:"cfg",spellcheck:"false",placeholder:t("cw_empty"),style:"min-height:45vh"});
|
||||||
ed.value=txt.replace(/\r\n/g,"\n");
|
ed.value=txt.replace(/\r\n/g,"\n");
|
||||||
var ok=h("button",{class:"ctl pri",text:t("sy_write"),onclick:function(){closeModal();doWriteConfig(cfgText(ed.value))}});
|
var ok=h("button",{class:"ctl pri",text:t("sy_write"),onclick:function(){closeModal();doWriteConfig(cfgText(ed.value),fromLog)}});
|
||||||
function refresh(){
|
function refresh(){
|
||||||
var v=cfgText(ed.value),bytes=new Blob([v]).size;
|
var v=cfgText(ed.value),bytes=new Blob([v]).size,long=cfgLongLine(v);
|
||||||
var unknown=v.split("\n").filter(function(l){return l.trim()&&!isConfCmd(l.trim().replace(/\s+/g," "))});
|
var unknown=v.split("\n").filter(function(l){return l.trim()&&!isConfCmd(l.trim().replace(/\s+/g," "))});
|
||||||
info.textContent=t("cw_info",{n:bytes});
|
info.textContent=t("cw_info",{n:bytes});
|
||||||
ok.disabled=bytes>2048;
|
ok.disabled=bytes>2048||!!long;
|
||||||
warn.style.color=ok.disabled?"var(--bad)":"var(--warn)";
|
warn.style.color=ok.disabled?"var(--bad)":"var(--warn)";
|
||||||
warn.textContent=ok.disabled?t("cw_toolarge"):(unknown.length?t("cw_unknown")+unknown.join(" | "):"");
|
warn.textContent=bytes>2048?t("cw_toolarge"):long?t("cw_longline",long):(unknown.length?t("cw_unknown")+unknown.join(" | "):"");
|
||||||
}
|
}
|
||||||
ed.addEventListener("input",refresh);refresh();
|
ed.addEventListener("input",refresh);refresh();
|
||||||
modal(title,h("div",null,[info,warn,ed]),[h("button",{class:"ctl",text:t("c_cancel"),onclick:closeModal}),ok]);
|
modal(title,h("div",null,[info,warn,ed]),[h("button",{class:"ctl",text:t("c_cancel"),onclick:closeModal}),ok]);
|
||||||
@@ -1692,7 +1839,7 @@ function cfgText(txt){
|
|||||||
txt=txt.replace(/\r\n/g,"\n");
|
txt=txt.replace(/\r\n/g,"\n");
|
||||||
return txt&&txt.slice(-1)!=="\n"?txt+"\n":txt;
|
return txt&&txt.slice(-1)!=="\n"?txt+"\n":txt;
|
||||||
}
|
}
|
||||||
function doWriteConfig(txt){
|
function doWriteConfig(txt,fromLog){
|
||||||
var form=new FormData();
|
var form=new FormData();
|
||||||
form.append("configuration",new Blob([txt],{type:"application/octet-stream"}),"config.txt");
|
form.append("configuration",new Blob([txt],{type:"application/octet-stream"}),"config.txt");
|
||||||
toast(t("cw_writing"));
|
toast(t("cw_writing"));
|
||||||
@@ -1702,9 +1849,10 @@ function doWriteConfig(txt){
|
|||||||
}).then(function(back){
|
}).then(function(back){
|
||||||
back=back.replace(/\0[\s\S]*$/,"").replace(/\r\n/g,"\n").trim();
|
back=back.replace(/\0[\s\S]*$/,"").replace(/\r\n/g,"\n").trim();
|
||||||
if(back!==txt.trim())throw new Error(t("cw_verify_fail"));
|
if(back!==txt.trim())throw new Error(t("cw_verify_fail"));
|
||||||
return api("/cmd_log_clear").catch(function(){});
|
if(!fromLog)return false;
|
||||||
}).then(function(){
|
return api("/cmd_log_clear").then(function(){return true},function(){return true});
|
||||||
setDirty(false);
|
}).then(function(cleared){
|
||||||
|
if(cleared)setDirty(false);
|
||||||
$("cfgedit").value=txt;cfgBytes();cfgParseKnown(txt);
|
$("cfgedit").value=txt;cfgBytes();cfgParseKnown(txt);
|
||||||
toast(t("cw_saved"),"ok");
|
toast(t("cw_saved"),"ok");
|
||||||
}).catch(function(e){toast(e.message||String(e),"err")});
|
}).catch(function(e){toast(e.message||String(e),"err")});
|
||||||
@@ -1715,9 +1863,9 @@ $("saveBtn").addEventListener("click",function(){
|
|||||||
getText("/config").catch(function(){return""}),
|
getText("/config").catch(function(){return""}),
|
||||||
getText("/cmd_log").catch(function(){return""}),
|
getText("/cmd_log").catch(function(){return""}),
|
||||||
]).then(function(r){
|
]).then(function(r){
|
||||||
var cur=r[0].replace(/\0[\s\S]*$/,"");
|
var cur=r[0].replace(/\0[\s\S]*$/,"").split(/\r?\n/).map(function(l){return l.trim().replace(/\s+/g," ")}).filter(Boolean);
|
||||||
var merged=mergeConf([],[cur,r[1].replace(/\0[\s\S]*$/,"")]);
|
var merged=mergeConf(cur,[r[1].replace(/\0[\s\S]*$/,"")]);
|
||||||
writeConfig(merged.join("\n"),t("cw_save_title"));
|
writeConfig(merged.join("\n"),t("cw_save_title"),true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
|||||||
<option value="en">English</option>
|
<option value="en">English</option>
|
||||||
<option value="ja">日本語</option>
|
<option value="ja">日本語</option>
|
||||||
<option value="zh">中文</option>
|
<option value="zh">中文</option>
|
||||||
|
<option value="es">Español</option>
|
||||||
</select></label>
|
</select></label>
|
||||||
<label class="row"><span class="lb" data-i18n="sy_theme">Theme</span>
|
<label class="row"><span class="lb" data-i18n="sy_theme">Theme</span>
|
||||||
<select class="in" id="themeSel">
|
<select class="in" id="themeSel">
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ button:hover{filter:brightness(1.1)}
|
|||||||
var L={
|
var L={
|
||||||
en:["Switch Login","RTLPlayground management interface","Password","Sign in","Wrong password, try again."],
|
en:["Switch Login","RTLPlayground management interface","Password","Sign in","Wrong password, try again."],
|
||||||
ja:["スイッチ ログイン","RTLPlayground 管理インターフェース","パスワード","ログイン","パスワードが違います。もう一度お試しください。"],
|
ja:["スイッチ ログイン","RTLPlayground 管理インターフェース","パスワード","ログイン","パスワードが違います。もう一度お試しください。"],
|
||||||
zh:["交换机登录","RTLPlayground 管理界面","密码","登录","密码错误,请重试。"]
|
zh:["交换机登录","RTLPlayground 管理界面","密码","登录","密码错误,请重试。"],
|
||||||
|
es:["Inicio de sesión del switch","Interfaz de gestión de RTLPlayground","Contraseña","Iniciar sesión","Contraseña incorrecta, inténtalo de nuevo."]
|
||||||
};
|
};
|
||||||
var l=null;
|
var l=null;
|
||||||
try{l=localStorage.getItem("rtl_lang");}catch(e){}
|
try{l=localStorage.getItem("rtl_lang");}catch(e){}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ __xdata uint16_t session_timeout = SESSION_TIMEOUT_DEFAULT;
|
|||||||
extern volatile __xdata uint8_t sfr_data[4];
|
extern volatile __xdata uint8_t sfr_data[4];
|
||||||
extern volatile __xdata uint32_t ticks;
|
extern volatile __xdata uint32_t ticks;
|
||||||
extern __xdata uint8_t cmd_capture; /* owned by rtlplayground.c, see write_char_no_syslog() */
|
extern __xdata uint8_t cmd_capture; /* owned by rtlplayground.c, see write_char_no_syslog() */
|
||||||
extern __code uint8_t * __code hex;
|
extern __code const uint8_t * __code const hex;
|
||||||
extern __code struct f_data f_data[];
|
extern __code const struct f_data f_data[];
|
||||||
extern __code char * __code mime_strings[];
|
extern __code const char * __code const mime_strings[];
|
||||||
extern __xdata struct flash_region_t flash_region;
|
extern __xdata struct flash_region_t flash_region;
|
||||||
extern __xdata uint32_t flash_size;
|
extern __xdata uint32_t flash_size;
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
|||||||
__xdata uint8_t entry;
|
__xdata uint8_t entry;
|
||||||
__xdata uint16_t slen;
|
__xdata uint16_t slen;
|
||||||
__xdata uint16_t o_idx;
|
__xdata uint16_t o_idx;
|
||||||
|
__xdata uint16_t sent_len;
|
||||||
__xdata uint16_t len_left;
|
__xdata uint16_t len_left;
|
||||||
__xdata uint16_t cont_len;
|
__xdata uint16_t cont_len;
|
||||||
__xdata uint32_t cont_addr;
|
__xdata uint32_t cont_addr;
|
||||||
@@ -130,7 +131,7 @@ uint8_t find_entry(__xdata uint8_t *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
bool is_word(__xdata uint8_t *xdata_str_p, __code const uint8_t * __xdata code_str_p)
|
||||||
{
|
{
|
||||||
uint8_t u, c;
|
uint8_t u, c;
|
||||||
|
|
||||||
@@ -152,7 +153,7 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
|||||||
|
|
||||||
|
|
||||||
/* name must be lower-case, starting with the '\n' of the previous line's end */
|
/* name must be lower-case, starting with the '\n' of the previous line's end */
|
||||||
__xdata uint8_t *header_value(__xdata uint8_t *p, __code uint8_t *name)
|
__xdata uint8_t *header_value(__xdata uint8_t *p, __code const uint8_t *name)
|
||||||
{
|
{
|
||||||
uint8_t u, c;
|
uint8_t u, c;
|
||||||
|
|
||||||
@@ -351,8 +352,9 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
|||||||
if (is_word_x(session, session_id)) {
|
if (is_word_x(session, session_id)) {
|
||||||
authenticated = 1;
|
authenticated = 1;
|
||||||
last_session_use = now;
|
last_session_use = now;
|
||||||
} else
|
} else {
|
||||||
dbg_string("Invalid session cookie!\n");
|
dbg_string("Invalid session cookie!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
@@ -379,8 +381,8 @@ void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
|
|||||||
static uint8_t config_take(void)
|
static uint8_t config_take(void)
|
||||||
{
|
{
|
||||||
// #386: needs static, otherwise it still lands in SRAM/DSEG
|
// #386: needs static, otherwise it still lands in SRAM/DSEG
|
||||||
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
|
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last, cfg_i;
|
||||||
__xdata uint8_t cfg_bl;
|
__xdata uint8_t cfg_bl, cfg_run;
|
||||||
|
|
||||||
cfg_bl = strlen_x(boundary);
|
cfg_bl = strlen_x(boundary);
|
||||||
|
|
||||||
@@ -422,6 +424,13 @@ static uint8_t config_take(void)
|
|||||||
// the payload plus its terminator must fit the sector
|
// the payload plus its terminator must fit the sector
|
||||||
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
|
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
|
||||||
return 2;
|
return 2;
|
||||||
|
cfg_run = 0;
|
||||||
|
for (cfg_i = cfg_body; cfg_i < cfg_end; cfg_i++) {
|
||||||
|
if (config_buf[cfg_i] == '\n')
|
||||||
|
cfg_run = 0;
|
||||||
|
else if (++cfg_run >= CMD_BUF_SIZE - 1)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
config_buf[cfg_end] = 0;
|
config_buf[cfg_end] = 0;
|
||||||
flash_region.addr = CONFIG_START;
|
flash_region.addr = CONFIG_START;
|
||||||
flash_sector_erase();
|
flash_sector_erase();
|
||||||
@@ -534,6 +543,19 @@ uint8_t stream_upload(void)
|
|||||||
crc16_bank1(upload_settings.p + upload_settings.bptr);
|
crc16_bank1(upload_settings.p + upload_settings.bptr);
|
||||||
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
||||||
if (write_len >= FLASH_PAGE_SIZE) {
|
if (write_len >= FLASH_PAGE_SIZE) {
|
||||||
|
/* The staged image spans FIRMWARE_UPLOAD_START to twice that,
|
||||||
|
* the span check_and_flash_update_image() reads back. Nothing
|
||||||
|
* else bounds uptr: a body whose closing boundary never arrives
|
||||||
|
* keeps writing, and on a flash exactly this size the address
|
||||||
|
* wraps onto the running image at zero. */
|
||||||
|
if (uptr >= (uint32_t)FIRMWARE_UPLOAD_START * 2) {
|
||||||
|
print_string("Upload runs past the image area! Aborting.\n");
|
||||||
|
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 30\r\n"
|
||||||
|
"Content-Type: text/plain\r\n\r\n"
|
||||||
|
"NO: upload exceeds image area\n");
|
||||||
|
s->tstate = TSTATE_NONE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
||||||
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
||||||
if (uptr % FLASH_SECTOR_SIZE == 0) {
|
if (uptr % FLASH_SECTOR_SIZE == 0) {
|
||||||
@@ -563,7 +585,7 @@ static void handle_config_fragment(__xdata uint8_t *p)
|
|||||||
__xdata uint16_t frag_len;
|
__xdata uint16_t frag_len;
|
||||||
uint8_t taken;
|
uint8_t taken;
|
||||||
|
|
||||||
frag_len = uip_len - (p - uip_appdata);
|
frag_len = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||||
print_string("Configuration too large, aborting.\n");
|
print_string("Configuration too large, aborting.\n");
|
||||||
config_upload = 0;
|
config_upload = 0;
|
||||||
@@ -593,7 +615,7 @@ static void handle_firmware_fragment(__xdata uint8_t *p)
|
|||||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
__xdata uint16_t frag_len, payload_start;
|
__xdata uint16_t frag_len, payload_start;
|
||||||
|
|
||||||
frag_len = uip_len - (p - uip_appdata);
|
frag_len = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||||
print_string("Firmware upload header too large, aborting.\n");
|
print_string("Firmware upload header too large, aborting.\n");
|
||||||
config_upload = 0;
|
config_upload = 0;
|
||||||
@@ -690,7 +712,7 @@ static uint8_t post_body_take(__xdata uint8_t *p)
|
|||||||
send_bad_request();
|
send_bad_request();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
have = uip_len - (p - uip_appdata);
|
have = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||||
if (have >= content_length) {
|
if (have >= content_length) {
|
||||||
p[content_length] = NUL;
|
p[content_length] = NUL;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -756,6 +778,10 @@ void handle_post(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_word(request_path, "upload")) {
|
if (is_word(request_path, "upload")) {
|
||||||
|
if (!authenticated) {
|
||||||
|
send_unauthorized();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
||||||
{
|
{
|
||||||
print_string("Flash too small for firmware upload!\n");
|
print_string("Flash too small for firmware upload!\n");
|
||||||
@@ -783,7 +809,23 @@ void handle_post(void)
|
|||||||
dbg_string("Multipart request\n");
|
dbg_string("Multipart request\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_word(request_path, "cmd")) {
|
if (s->tstate == TSTATE_MULTIPART || 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;
|
||||||
|
}
|
||||||
|
if (config_upload)
|
||||||
|
handle_config_fragment(p);
|
||||||
|
else
|
||||||
|
handle_firmware_fragment(p);
|
||||||
|
return;
|
||||||
|
} else if (is_word(request_path, "cmd")) {
|
||||||
p += 4;
|
p += 4;
|
||||||
if (!authenticated) {
|
if (!authenticated) {
|
||||||
send_unauthorized();
|
send_unauthorized();
|
||||||
@@ -809,22 +851,6 @@ void handle_post(void)
|
|||||||
return;
|
return;
|
||||||
run_login_body(p);
|
run_login_body(p);
|
||||||
return;
|
return;
|
||||||
} else if (s->tstate == TSTATE_MULTIPART || 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;
|
|
||||||
}
|
|
||||||
if (config_upload)
|
|
||||||
handle_config_fragment(p);
|
|
||||||
else
|
|
||||||
handle_firmware_fragment(p);
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
send_not_found();
|
send_not_found();
|
||||||
return;
|
return;
|
||||||
@@ -832,6 +858,13 @@ void handle_post(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void tx_send(uint16_t len)
|
||||||
|
{
|
||||||
|
sent_len = len;
|
||||||
|
uip_send(outbuf + o_idx, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void httpd_appcall(void)
|
void httpd_appcall(void)
|
||||||
{
|
{
|
||||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||||
@@ -867,9 +900,9 @@ void httpd_appcall(void)
|
|||||||
}
|
}
|
||||||
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
||||||
dbg_string("ACK\n");
|
dbg_string("ACK\n");
|
||||||
if (slen > uip_mss()) {
|
if (slen > sent_len) {
|
||||||
slen -= uip_mss();
|
slen -= sent_len;
|
||||||
o_idx += uip_mss();
|
o_idx += sent_len;
|
||||||
} else {
|
} else {
|
||||||
slen = 0;
|
slen = 0;
|
||||||
}
|
}
|
||||||
@@ -878,11 +911,11 @@ void httpd_appcall(void)
|
|||||||
|
|
||||||
if (slen > uip_mss()) {
|
if (slen > uip_mss()) {
|
||||||
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, uip_mss());
|
tx_send(uip_mss());
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
} else if (slen > 0) {
|
} else if (slen > 0) {
|
||||||
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, slen);
|
tx_send(slen);
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
} else if (cont_len) {
|
} else if (cont_len) {
|
||||||
dbg_string("CONT cont_len: "); dbg_short(cont_len);
|
dbg_string("CONT cont_len: "); dbg_short(cont_len);
|
||||||
@@ -893,7 +926,7 @@ void httpd_appcall(void)
|
|||||||
flash_region.len = slen;
|
flash_region.len = slen;
|
||||||
flash_read_bulk(outbuf);
|
flash_read_bulk(outbuf);
|
||||||
o_idx = 0;
|
o_idx = 0;
|
||||||
uip_send(outbuf + o_idx, slen);
|
tx_send(slen);
|
||||||
cont_len -= slen;
|
cont_len -= slen;
|
||||||
cont_addr += slen;
|
cont_addr += slen;
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
@@ -904,8 +937,9 @@ void httpd_appcall(void)
|
|||||||
reset_chip();
|
reset_chip();
|
||||||
}
|
}
|
||||||
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||||
// Check here maxupload by subtracting uip_len and close socekt if fails!
|
if (config_upload || uip_len <= max_upload) {
|
||||||
if (max_upload - uip_len > 0) {
|
if (!config_upload)
|
||||||
|
max_upload -= uip_len;
|
||||||
upload_settings.p = uip_appdata;
|
upload_settings.p = uip_appdata;
|
||||||
upload_settings.bptr = 0;
|
upload_settings.bptr = 0;
|
||||||
upload_settings.plen = uip_len;
|
upload_settings.plen = uip_len;
|
||||||
@@ -1051,24 +1085,20 @@ do_send:
|
|||||||
o_idx = 0;
|
o_idx = 0;
|
||||||
if (slen > uip_mss()) {
|
if (slen > uip_mss()) {
|
||||||
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, uip_mss());
|
tx_send(uip_mss());
|
||||||
dbg_string("Sending a done\n");
|
dbg_string("Sending a done\n");
|
||||||
} else {
|
} else {
|
||||||
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, slen);
|
tx_send(slen);
|
||||||
dbg_string("Sending b done\n");
|
dbg_string("Sending b done\n");
|
||||||
}
|
}
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
||||||
dbg_string("RETRANSMIT requested\n");
|
dbg_string("RETRANSMIT requested\n");
|
||||||
if (slen > uip_mss()) {
|
if (sent_len) {
|
||||||
dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n');
|
dbg_string("Sending C: "); dbg_short(sent_len); dbg_char('\n');
|
||||||
uip_send(outbuf + o_idx, uip_mss());
|
tx_send(sent_len);
|
||||||
dbg_string("Sending C done\n");
|
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");
|
|
||||||
}
|
}
|
||||||
s->tstate = TSTATE_TX;
|
s->tstate = TSTATE_TX;
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern __xdata uint16_t management_vlan;
|
|||||||
extern __xdata uint16_t session_timeout;
|
extern __xdata uint16_t session_timeout;
|
||||||
extern __xdata uint16_t cont_len;
|
extern __xdata uint16_t cont_len;
|
||||||
extern __xdata uint32_t cont_addr;
|
extern __xdata uint32_t cont_addr;
|
||||||
extern __code uint8_t * __code hex;
|
extern __code const uint8_t * __code const hex;
|
||||||
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||||
|
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
@@ -48,8 +48,8 @@ extern __xdata char sfp_module_model[2][17];
|
|||||||
extern __xdata char sfp_module_serial[2][17];
|
extern __xdata char sfp_module_serial[2][17];
|
||||||
extern __xdata uint8_t sfp_options[2];
|
extern __xdata uint8_t sfp_options[2];
|
||||||
|
|
||||||
__code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
__code const uint8_t * __code const HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||||
__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
__code const uint8_t * __code const HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
||||||
|
|
||||||
// Convert uint8_t to ascii HEX char push on html-buffer.
|
// Convert uint8_t to ascii HEX char push on html-buffer.
|
||||||
void charhex_to_html(char c)
|
void charhex_to_html(char c)
|
||||||
@@ -71,6 +71,21 @@ void char_to_html(char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void str_x_to_html(__xdata const char *s)
|
||||||
|
{
|
||||||
|
while (*s)
|
||||||
|
outbuf[slen++] = *s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void json_char_to_html(uint8_t c)
|
||||||
|
{
|
||||||
|
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||||
|
c = '.';
|
||||||
|
outbuf[slen++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Convert uint8_t to ascii HEX char.
|
// Convert uint8_t to ascii HEX char.
|
||||||
void byte_to_html(uint8_t val)
|
void byte_to_html(uint8_t val)
|
||||||
{
|
{
|
||||||
@@ -115,7 +130,7 @@ void itoa16_html(uint16_t v) /* up to five digits (65535) */
|
|||||||
char_to_html('0' + (v % 10));
|
char_to_html('0' + (v % 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_to_html(__code char *s)
|
void string_to_html(__code const char *s)
|
||||||
{
|
{
|
||||||
while (*s) char_to_html(*s++);
|
while (*s) char_to_html(*s++);
|
||||||
}
|
}
|
||||||
@@ -178,6 +193,20 @@ void reg_to_html_long(uint16_t reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The 64-bit counter of the last STAT_GET as one number: the low word keeps
|
||||||
|
* its leading zeros whenever the high word is set. */
|
||||||
|
void counter_to_html(void)
|
||||||
|
{
|
||||||
|
reg_read_m(RTL837X_STAT_V_HIGH);
|
||||||
|
if (SFR_DATA_24 | SFR_DATA_16 | SFR_DATA_8 | SFR_DATA_0) {
|
||||||
|
sfr_data_to_html();
|
||||||
|
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||||
|
} else {
|
||||||
|
reg_to_html(RTL837X_STAT_V_LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_sfp_info(uint8_t sfp)
|
void send_sfp_info(uint8_t sfp)
|
||||||
{
|
{
|
||||||
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||||
@@ -187,8 +216,8 @@ void send_sfp_info(uint8_t sfp)
|
|||||||
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
||||||
continue;
|
continue;
|
||||||
uint8_t c = sfp_buf[i & 0xf];
|
uint8_t c = sfp_buf[i & 0xf];
|
||||||
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
|
if (c)
|
||||||
char_to_html(c);
|
json_char_to_html(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +313,7 @@ void send_vlan(uint16_t vlan)
|
|||||||
dbg_string("VLAN has no name\n");
|
dbg_string("VLAN has no name\n");
|
||||||
} else {
|
} else {
|
||||||
while(vlan_names[n] && vlan_names[n] != ' ')
|
while(vlan_names[n] && vlan_names[n] != ' ')
|
||||||
char_to_html(vlan_names[n++]);
|
json_char_to_html(vlan_names[n++]);
|
||||||
}
|
}
|
||||||
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
||||||
uint16_t pvid_mask = 0;
|
uint16_t pvid_mask = 0;
|
||||||
@@ -316,8 +345,7 @@ bool send_counters(uint8_t phys_port)
|
|||||||
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
||||||
STAT_GET(counter, log_port);
|
STAT_GET(counter, log_port);
|
||||||
slen += strtox(outbuf + slen, "\"0x");
|
slen += strtox(outbuf + slen, "\"0x");
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
counter_to_html();
|
||||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
|
||||||
char_to_html('\"');
|
char_to_html('\"');
|
||||||
if (counter != 0x36)
|
if (counter != 0x36)
|
||||||
char_to_html(',');
|
char_to_html(',');
|
||||||
@@ -437,8 +465,6 @@ void l2_delete(uint16_t idx)
|
|||||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||||
dbg_string("L2 DELETE\n");
|
dbg_string("L2 DELETE\n");
|
||||||
dbg_short(idx);
|
dbg_short(idx);
|
||||||
__xdata uint8_t entries_left = L2_MAX_TRANSFER;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
reg_read(RTL837X_TBL_CTRL);
|
reg_read(RTL837X_TBL_CTRL);
|
||||||
} while (SFR_DATA_0 & TBL_EXECUTE);
|
} while (SFR_DATA_0 & TBL_EXECUTE);
|
||||||
@@ -819,7 +845,7 @@ void send_status(void)
|
|||||||
itoa_html(i);
|
itoa_html(i);
|
||||||
slen += strtox(outbuf + slen, ",\"name\":\"");
|
slen += strtox(outbuf + slen, ",\"name\":\"");
|
||||||
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
||||||
char_to_html(port_names[i][j]);
|
json_char_to_html(port_names[i][j]);
|
||||||
}
|
}
|
||||||
slen += strtox(outbuf + slen, "\"");
|
slen += strtox(outbuf + slen, "\"");
|
||||||
|
|
||||||
@@ -858,14 +884,11 @@ void send_status(void)
|
|||||||
sfp_send_data(sfp, 238, 1);
|
sfp_send_data(sfp, 238, 1);
|
||||||
}
|
}
|
||||||
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
||||||
for (uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
|
str_x_to_html(sfp_module_vendor[sfp]);
|
||||||
outbuf[slen++] = sfp_module_vendor[sfp][s];
|
|
||||||
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
||||||
for (uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
|
str_x_to_html(sfp_module_model[sfp]);
|
||||||
outbuf[slen++] = sfp_module_model[sfp][s];
|
|
||||||
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
||||||
for (uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
|
str_x_to_html(sfp_module_serial[sfp]);
|
||||||
outbuf[slen++] = sfp_module_serial[sfp][s];
|
|
||||||
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
||||||
if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
|
if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
|
||||||
slen += strtox(outbuf + slen,"null");
|
slen += strtox(outbuf + slen,"null");
|
||||||
@@ -919,8 +942,7 @@ void send_status(void)
|
|||||||
|
|
||||||
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
||||||
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
counter_to_html();
|
||||||
reg_to_html(RTL837X_STAT_V_LOW);
|
|
||||||
|
|
||||||
slen += strtox(outbuf + slen, "\",\"txB\":\"0x");
|
slen += strtox(outbuf + slen, "\",\"txB\":\"0x");
|
||||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||||
@@ -928,8 +950,7 @@ void send_status(void)
|
|||||||
|
|
||||||
slen += strtox(outbuf + slen, "\",\"rxG\":\"0x");
|
slen += strtox(outbuf + slen, "\",\"rxG\":\"0x");
|
||||||
STAT_GET(STAT_COUNTER_RX_PKTS, i);
|
STAT_GET(STAT_COUNTER_RX_PKTS, i);
|
||||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
counter_to_html();
|
||||||
reg_to_html(RTL837X_STAT_V_LOW);
|
|
||||||
|
|
||||||
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
||||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||||
@@ -995,7 +1016,7 @@ void send_cmd_log(void)
|
|||||||
__xdata uint8_t found_begin = 0;
|
__xdata uint8_t found_begin = 0;
|
||||||
dbg_string("History ptr: ");
|
dbg_string("History ptr: ");
|
||||||
dbg_short(cmd_history_ptr); dbg_char('\n');
|
dbg_short(cmd_history_ptr); dbg_char('\n');
|
||||||
while (p != cmd_history_ptr) {
|
while (p != cmd_history_ptr && slen < TCP_OUTBUF_SIZE) {
|
||||||
if (!cmd_history[p] || cmd_history[p] == '\n')
|
if (!cmd_history[p] || cmd_history[p] == '\n')
|
||||||
found_begin = 1;
|
found_begin = 1;
|
||||||
if (found_begin && cmd_history[p])
|
if (found_begin && cmd_history[p])
|
||||||
@@ -1039,7 +1060,7 @@ void send_vlanlist(void)
|
|||||||
n = vlan_name(i);
|
n = vlan_name(i);
|
||||||
if (n != 0xffff) {
|
if (n != 0xffff) {
|
||||||
while (vlan_names[n] && vlan_names[n] != ' ')
|
while (vlan_names[n] && vlan_names[n] != ' ')
|
||||||
char_to_html(vlan_names[n++]);
|
json_char_to_html(vlan_names[n++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
slen += strtox(outbuf + slen, "\"}");
|
slen += strtox(outbuf + slen, "\"}");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
extern __code uint8_t * __code HTTP_RESPONCE_TXT;
|
extern __code const uint8_t * __code const HTTP_RESPONCE_TXT;
|
||||||
|
|
||||||
void itoa16_html(uint16_t v);
|
void itoa16_html(uint16_t v);
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
__xdata uint8_t buffer[0x1000];
|
__xdata uint8_t buffer[0x1000];
|
||||||
__xdata uint8_t dio_enabled;
|
__xdata uint8_t dio_enabled;
|
||||||
|
|
||||||
__code uint8_t * __code hex = "0123456789abcdef";
|
__code const uint8_t * __code const hex = "0123456789abcdef";
|
||||||
|
|
||||||
void isr_timer0(void) __interrupt(1)
|
void isr_timer0(void) __interrupt(1)
|
||||||
{
|
{
|
||||||
@@ -67,7 +67,7 @@ void write_char(char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void print_string(__code char *p)
|
void print_string(__code const char *p)
|
||||||
{
|
{
|
||||||
while (*p)
|
while (*p)
|
||||||
write_char(*p++);
|
write_char(*p++);
|
||||||
|
|||||||
@@ -5,6 +5,29 @@
|
|||||||
#include "rtl837x_regs.h"
|
#include "rtl837x_regs.h"
|
||||||
#include "rtl837x_common.h"
|
#include "rtl837x_common.h"
|
||||||
|
|
||||||
|
#define I2CBUS_INVALID (7)
|
||||||
|
// This is a MACRO to check if I2C_BUS_FROM_SDA_PIN or I2C_BUS_FROM_SCL_PIN don't return I2CBUS_INVALID.
|
||||||
|
// When I2CBUS_INVALID is returned, compiler stops with "machine.c:<line>: error 176: sizeof applied to an incomplete type"
|
||||||
|
#define I2CBUS_VALID(bus) (0 * sizeof(char[(bus) != I2CBUS_INVALID ? 1 : 0]))
|
||||||
|
#define I2CBUS(sda, scl) \
|
||||||
|
((uint8_t)((I2C_BUS_FROM_SCL_PIN(scl) << RTL837X_REG_I2C_SCL_SHIFT) | \
|
||||||
|
(I2C_BUS_FROM_SDA_PIN(sda) << RTL837X_REG_I2C_SDA_SHIFT) | \
|
||||||
|
I2CBUS_VALID(I2C_BUS_FROM_SCL_PIN(scl)) | \
|
||||||
|
I2CBUS_VALID(I2C_BUS_FROM_SDA_PIN(sda))))
|
||||||
|
|
||||||
|
#define I2C_BUS_FROM_SDA_PIN(sda_pin) \
|
||||||
|
((sda_pin) == GPIO47_I2C_SDA0 ? 0 : \
|
||||||
|
(sda_pin) == GPIO49_I2C_SDA1 ? 1 : \
|
||||||
|
(sda_pin) == GPIO51_I2C_SDA2_UART1_RX ? 2 : \
|
||||||
|
(sda_pin) == GPIO41_I2C_SDA3_MDIO1 ? 3 : \
|
||||||
|
(sda_pin) == GPIO39_I2C_SDA4 ? 4 : I2CBUS_INVALID)
|
||||||
|
|
||||||
|
#define I2C_BUS_FROM_SCL_PIN(scl_pin) \
|
||||||
|
((scl_pin) == GPIO46_I2C_SCL0 ? 0 : \
|
||||||
|
(scl_pin) == GPIO48_I2C_SCL1 ? 1 : \
|
||||||
|
(scl_pin) == GPIO50_I2C_SCL2_UART1_TX ? 2 : \
|
||||||
|
(scl_pin) == GPIO40_I2C_SCL3_MDC1 ? 3 : I2CBUS_INVALID)
|
||||||
|
|
||||||
#if defined(MACHINE_KP_9000_6XHML_X2) || \
|
#if defined(MACHINE_KP_9000_6XHML_X2) || \
|
||||||
defined(MACHINE_KP_9000_6XH_X2_V1_1) || \
|
defined(MACHINE_KP_9000_6XH_X2_V1_1) || \
|
||||||
defined(MACHINE_KP_9000_6XHML_X2_V1_1) || \
|
defined(MACHINE_KP_9000_6XHML_X2_V1_1) || \
|
||||||
@@ -34,13 +57,13 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO10_LED10,
|
.sfp_port[0].pin_los = GPIO10_LED10,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 0,
|
.sfp_port[0].sds = 0,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
// Right SFP port (6)
|
// Right SFP port (6)
|
||||||
.sfp_port[1].pin_detect = GPIO30_ACL_BIT3_EN,
|
.sfp_port[1].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||||
.sfp_port[1].pin_los = GPIO37,
|
.sfp_port[1].pin_los = GPIO37,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[1].sds = 1,
|
.sfp_port[1].sds = 1,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
@@ -70,7 +93,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
/* Conditions for LED on:
|
/* Conditions for LED on:
|
||||||
* dual led orange: ledset_0 & ledset_2
|
* dual led orange: ledset_0 & ledset_2
|
||||||
@@ -105,13 +128,13 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_detect = GPIO38,
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
// Right SFP port
|
// Right SFP port
|
||||||
.sfp_port[1].pin_detect = GPIO37,
|
.sfp_port[1].pin_detect = GPIO37,
|
||||||
.sfp_port[1].pin_los = GPIO_NA,
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO48_I2C_SCL1, // Button-Switch is unpopulated on PCB, but can be added manually (hole in case is already there)
|
.reset_pin = GPIO48_I2C_SCL1, // Button-Switch is unpopulated on PCB, but can be added manually (hole in case is already there)
|
||||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
@@ -152,7 +175,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
@@ -177,7 +200,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||||
@@ -227,7 +250,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_detect = GPIO38,
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO48_I2C_SCL1,
|
.reset_pin = GPIO48_I2C_SCL1,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -265,13 +288,13 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
|
||||||
// Right SFP port (J2)
|
// Right SFP port (J2)
|
||||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
.sfp_port[1].pin_los = GPIO_NA,
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
|
||||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
@@ -306,13 +329,13 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
|
||||||
// Right SFP port (J2)
|
// Right SFP port (J2)
|
||||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
@@ -346,7 +369,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO48_I2C_SCL1,
|
.reset_pin = GPIO48_I2C_SCL1,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -385,12 +408,12 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = 10,
|
.sfp_port[0].pin_los = 10,
|
||||||
.sfp_port[0].pin_tx_disable = 0xFF,
|
.sfp_port[0].pin_tx_disable = 0xFF,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.sfp_port[1].pin_detect = 30,
|
.sfp_port[1].pin_detect = 30,
|
||||||
.sfp_port[1].pin_los = 51,
|
.sfp_port[1].pin_los = 51,
|
||||||
.sfp_port[1].pin_tx_disable = 0xFF,
|
.sfp_port[1].pin_tx_disable = 0xFF,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 , .enable = LED_27 | LED_29 },
|
.high_leds = { .mux = LED_27 , .enable = LED_27 | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
@@ -425,7 +448,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -458,7 +481,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA, // no LOS pin wired
|
.sfp_port[0].pin_los = GPIO_NA, // no LOS pin wired
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -499,7 +522,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -531,7 +554,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
@@ -556,12 +579,12 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO50_I2C_SCL2_UART1_TX,
|
.sfp_port[0].pin_los = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO54_ACL_BIT2_EN,
|
.sfp_port[0].pin_tx_disable = GPIO54_ACL_BIT2_EN,
|
||||||
.sfp_port[0].sds = 0,
|
.sfp_port[0].sds = 0,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO47_I2C_SDA0, .scl = GPIO46_I2C_SCL0 },
|
.sfp_port[0].i2c = I2CBUS( GPIO47_I2C_SDA0, GPIO46_I2C_SCL0 ),
|
||||||
.sfp_port[1].pin_detect = GPIO36_PWM_OUT,
|
.sfp_port[1].pin_detect = GPIO36_PWM_OUT,
|
||||||
.sfp_port[1].pin_los = GPIO37,
|
.sfp_port[1].pin_los = GPIO37,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
|
.sfp_port[1].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
|
||||||
.sfp_port[1].sds = 1,
|
.sfp_port[1].sds = 1,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO49_I2C_SDA1, .scl = GPIO48_I2C_SCL1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO49_I2C_SDA1, GPIO48_I2C_SCL1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
.led_sets = {
|
.led_sets = {
|
||||||
@@ -596,13 +619,13 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_detect = GPIO38,
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
// Right SFP port
|
// Right SFP port
|
||||||
.sfp_port[1].pin_detect = GPIO37,
|
.sfp_port[1].pin_detect = GPIO37,
|
||||||
.sfp_port[1].pin_los = GPIO_NA,
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
@@ -641,7 +664,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -676,7 +699,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO48_I2C_SCL1,
|
.reset_pin = GPIO48_I2C_SCL1,
|
||||||
.high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
.led_mux_custom = 1,
|
.led_mux_custom = 1,
|
||||||
@@ -720,14 +743,14 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
// Right SFP port (6)
|
// Right SFP port (6)
|
||||||
// LED pin 24
|
// LED pin 24
|
||||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||||
@@ -769,11 +792,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = {
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.sda = GPIO39_I2C_SDA4,
|
|
||||||
.scl = GPIO40_I2C_SCL3_MDC1
|
|
||||||
},
|
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
|
|
||||||
.high_leds = {
|
.high_leds = {
|
||||||
@@ -823,14 +842,14 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
|
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
|
||||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
|
|
||||||
@@ -879,14 +898,14 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 0,
|
.sfp_port[0].sds = 0,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
// SFP port on SDS1 / logical port 8
|
// SFP port on SDS1 / logical port 8
|
||||||
.sfp_port[1].pin_detect = GPIO38,
|
.sfp_port[1].pin_detect = GPIO38,
|
||||||
.sfp_port[1].pin_los = GPIO_NA,
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[1].sds = 1,
|
.sfp_port[1].sds = 1,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
@@ -925,7 +944,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
@@ -968,7 +987,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||||
@@ -1049,13 +1068,13 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_detect = GPIO38,
|
.sfp_port[0].pin_detect = GPIO38,
|
||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
// Right SFP port
|
// Right SFP port
|
||||||
.sfp_port[1].pin_detect = GPIO37,
|
.sfp_port[1].pin_detect = GPIO37,
|
||||||
.sfp_port[1].pin_los = GPIO_NA,
|
.sfp_port[1].pin_los = GPIO_NA,
|
||||||
.sfp_port[1].sds = 0,
|
.sfp_port[1].sds = 0,
|
||||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
@@ -1114,7 +1133,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO_NA,
|
.sfp_port[0].pin_los = GPIO_NA,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -1160,10 +1179,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = {
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.sda = GPIO39_I2C_SDA4,
|
|
||||||
.scl = GPIO40_I2C_SCL3_MDC1
|
|
||||||
},
|
|
||||||
|
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = 0, .enable = 0 },
|
.high_leds = { .mux = 0, .enable = 0 },
|
||||||
@@ -1197,7 +1213,7 @@ __code const struct machine machine = {
|
|||||||
.sfp_port[0].pin_los = GPIO37,
|
.sfp_port[0].pin_los = GPIO37,
|
||||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||||
.sfp_port[0].sds = 1,
|
.sfp_port[0].sds = 1,
|
||||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
.reset_pin = GPIO_NA,
|
.reset_pin = GPIO_NA,
|
||||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
@@ -1226,6 +1242,160 @@ __code const struct machine machine = {
|
|||||||
0x1a, 0x19, 0x1d, 0x1e, 0x1c,
|
0x1a, 0x19, 0x1d, 0x1e, 0x1c,
|
||||||
0x1d, 0x20, 0x21 },
|
0x1d, 0x20, 0x21 },
|
||||||
};
|
};
|
||||||
|
#elif defined MACHINE_PB_2132
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "PB-2132",
|
||||||
|
.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 = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
|
||||||
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
/* LED0 = RJ45: Amber LED: 2.5G */
|
||||||
|
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||||
|
/* LED1 = RJ45: Green LED: 10M / 100M / 1000M */
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* SFP+ single Green LED. */
|
||||||
|
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif defined MACHINE_HASIVO_S600W_4GT_2XGT_SE
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "Hasivo S600W-4GT-2XGT-SE",
|
||||||
|
.isRTL8373 = 0,
|
||||||
|
.min_port = 3,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 0,
|
||||||
|
.n_10g = 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, 0, 0, 0, 0, 0, 0},
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||||
|
/* Ports 1-4: Green: 2.5GBit, Orange: 10/100/1000MBit
|
||||||
|
* Ports 5-6: Green: 10GBit, Orange: 5/2.5GBit, None: 10/100/1000MBit
|
||||||
|
*/
|
||||||
|
.led_sets = {
|
||||||
|
{
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Yellow
|
||||||
|
LEDS_2G5 | LEDS_LINK, // Green
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK, // Orange
|
||||||
|
0, // Unused
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Yellow
|
||||||
|
LEDS_10G | LEDS_LINK, // Green
|
||||||
|
LEDS_5G | LEDS_2G5 | LEDS_LINK, // Orange
|
||||||
|
0, // Unused
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.led_mux_custom = 1,
|
||||||
|
.led_mux = {
|
||||||
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||||
|
0x3f, 0x3f, 0x3f, 0x0f, 0x20,
|
||||||
|
0x21, 0x22, 0x10, 0x11, 0x12,
|
||||||
|
0x14, 0x15, 0x16, 0x18, 0x19,
|
||||||
|
0x1a, 0x1c, 0x1d, 0x1e, 0x0c,
|
||||||
|
0x0d, 0x0e, 0x23
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
#elif defined MACHINE_HASIVO_S1100WP_8GT_1SX_SE
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "Hasivo S1100WP-8GT-1SX-SE",
|
||||||
|
.isRTL8373 = 1,
|
||||||
|
.mac_flash_offset = 0x1FC000,
|
||||||
|
.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 = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
|
||||||
|
0,
|
||||||
|
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#elif defined MACHINE_F7008_2_5
|
||||||
|
__code const struct machine machine = {
|
||||||
|
.machine_name = "F7008-2.5 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 = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||||
|
.reset_pin = GPIO_NA,
|
||||||
|
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||||
|
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
|
.led_sets = {
|
||||||
|
{ /* SET0 */
|
||||||
|
LEDS_2G5 | LEDS_LINK, /* LEDID0 - green: 2.5G link */
|
||||||
|
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* LEDID1 - yellow: traffic */
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
{ /* SET1 - SFP+ */
|
||||||
|
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_LINK,
|
||||||
|
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_LINK | LEDS_ACT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.led_mux_custom = 1,
|
||||||
|
.led_mux = {
|
||||||
|
0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x02,
|
||||||
|
0x0d, 0x10, 0x11, 0x02, 0x14, 0x02, 0x02, 0x15,
|
||||||
|
0x02, 0x02, 0x18, 0x02, 0x02, 0x19, 0x02, 0x02,
|
||||||
|
0x1c, 0x1d, 0x02, 0x02,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "Please select a machine type in machine.h"
|
#error "Please select a machine type in machine.h"
|
||||||
|
|||||||
@@ -46,13 +46,10 @@
|
|||||||
// #define MACHINE_FG_8GT_1SX
|
// #define MACHINE_FG_8GT_1SX
|
||||||
// #define MACHINE_LIANGUO_HYWS_SGT0108S
|
// #define MACHINE_LIANGUO_HYWS_SGT0108S
|
||||||
// #define MACHINE_POE_2G080110GS
|
// #define MACHINE_POE_2G080110GS
|
||||||
|
// #define MACHINE_PB_2132
|
||||||
typedef struct {
|
// #define MACHINE_HASIVO_S600W_4GT_2XGT_SE
|
||||||
// GPIO pins for SDA/SCL
|
// #define MACHINE_HASIVO_S1100WP_8GT_1SX_SE
|
||||||
uint8_t sda;
|
// #define MACHINE_F7008_2_5
|
||||||
uint8_t scl;
|
|
||||||
} i2c_bus_t;
|
|
||||||
|
|
||||||
|
|
||||||
#define LED_27 1
|
#define LED_27 1
|
||||||
// SYSTEM LED
|
// SYSTEM LED
|
||||||
@@ -72,7 +69,7 @@ struct sfp_port
|
|||||||
uint8_t pin_los; // 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 pin_tx_disable; // gpio number 0-63, 0xFF = not present
|
||||||
uint8_t sds;
|
uint8_t sds;
|
||||||
i2c_bus_t i2c;
|
uint8_t i2c;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct machine {
|
struct machine {
|
||||||
|
|||||||
@@ -7,6 +7,14 @@
|
|||||||
|
|
||||||
#define SYS_TICK_HZ 200
|
#define SYS_TICK_HZ 200
|
||||||
|
|
||||||
|
/* Timers of the main loop count system ticks, not loop passes: a pass is as
|
||||||
|
* long as the packets it handles, and since #483 the loop no longer sleeps
|
||||||
|
* while packets wait, so passes can outrun the tick as well as lag it. `last`
|
||||||
|
* is the low byte of ticks when the timer last ran; the byte arithmetic wraps
|
||||||
|
* every 256 ticks, so a pass longer than 1.28 s loses time rather than
|
||||||
|
* running the timer 64 times to catch up. */
|
||||||
|
#define TICKS_DUE(last, period) ((uint8_t)((uint8_t)ticks - (last)) >= (period))
|
||||||
|
|
||||||
#define CPU_PORT 9
|
#define CPU_PORT 9
|
||||||
#define NUL '\0'
|
#define NUL '\0'
|
||||||
|
|
||||||
@@ -54,6 +62,7 @@ extern __xdata uint8_t sbuf[SBUF_SIZE];
|
|||||||
#define ERR_OK 0
|
#define ERR_OK 0
|
||||||
#define ERR_TOO_MANY_ARGUMENTS 1
|
#define ERR_TOO_MANY_ARGUMENTS 1
|
||||||
#define ERR_CMD_TOO_LONG 2
|
#define ERR_CMD_TOO_LONG 2
|
||||||
|
#define ERR_INVALID_ARGUMENT 3
|
||||||
|
|
||||||
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
|
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
|
||||||
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
|
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
|
||||||
@@ -97,7 +106,7 @@ struct vlan_tag {
|
|||||||
#define FIRMWARE_UPLOAD_START 0x80000
|
#define FIRMWARE_UPLOAD_START 0x80000
|
||||||
|
|
||||||
// Constants for the circular command buffer, the size must be 2^n
|
// Constants for the circular command buffer, the size must be 2^n
|
||||||
#define CMD_HISTORY_SIZE 0x400
|
#define CMD_HISTORY_SIZE 0x800
|
||||||
#define CMD_HISTORY_MASK (CMD_HISTORY_SIZE - 1)
|
#define CMD_HISTORY_MASK (CMD_HISTORY_SIZE - 1)
|
||||||
|
|
||||||
enum sfp_speeds {
|
enum sfp_speeds {
|
||||||
@@ -134,9 +143,9 @@ extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
|||||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||||
|
|
||||||
// Headers for calls in the common code area (HOME/BANK0)
|
// Headers for calls in the common code area (HOME/BANK0)
|
||||||
void print_string_no_syslog(__code char *p);
|
void print_string_no_syslog(__code const char *p);
|
||||||
void print_string_newline_no_syslog(__code char *p);
|
void print_string_newline_no_syslog(__code const char *p);
|
||||||
void print_string(__code char *p);
|
void print_string(__code const char *p);
|
||||||
void print_string_x(__xdata char *p);
|
void print_string_x(__xdata char *p);
|
||||||
void print_long(uint32_t a);
|
void print_long(uint32_t a);
|
||||||
void print_short(uint16_t a);
|
void print_short(uint16_t a);
|
||||||
@@ -182,13 +191,13 @@ uint16_t strlen(__code const char *s);
|
|||||||
uint16_t strcpy(__xdata uint8_t *dst, const char *s);
|
uint16_t strcpy(__xdata uint8_t *dst, const char *s);
|
||||||
char strcmp(__xdata const uint8_t *a, __code const uint8_t *b);
|
char strcmp(__xdata const uint8_t *a, __code const uint8_t *b);
|
||||||
#endif
|
#endif
|
||||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len);
|
void memcpyc(__xdata uint8_t *dst, __code const uint8_t *src, uint16_t len);
|
||||||
uint16_t strlen_x(__xdata const char *s);
|
uint16_t strlen_x(__xdata const char *s);
|
||||||
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
|
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
|
||||||
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b);
|
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b);
|
||||||
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b);
|
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b);
|
||||||
void tcpip_output(void);
|
void tcpip_output(void);
|
||||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
uint8_t read_flash(uint8_t bank, __code const uint8_t *addr);
|
||||||
void get_random_32(void);
|
void get_random_32(void);
|
||||||
void read_reg_timer(__xdata uint32_t * tmr);
|
void read_reg_timer(__xdata uint32_t * tmr);
|
||||||
bool gpio_pin_test(uint8_t pin);
|
bool gpio_pin_test(uint8_t pin);
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ void flash_read_uid(void)
|
|||||||
flash_configure_mmio();
|
flash_configure_mmio();
|
||||||
}
|
}
|
||||||
|
|
||||||
__code char* get_flash_size_str(void)
|
__code const char* get_flash_size_str(void)
|
||||||
{
|
{
|
||||||
switch (flash_capacity_code) {
|
switch (flash_capacity_code) {
|
||||||
case 0x12: return "256 KB";
|
case 0x12: return "256 KB";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ void flash_read_security(void);
|
|||||||
void flash_sector_erase(void);
|
void flash_sector_erase(void);
|
||||||
void flash_read_bulk(__xdata uint8_t *dst);
|
void flash_read_bulk(__xdata uint8_t *dst);
|
||||||
void flash_write_bytes(__xdata uint8_t *ptr);
|
void flash_write_bytes(__xdata uint8_t *ptr);
|
||||||
__code char* get_flash_size_str(void);
|
__code const char* get_flash_size_str(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "rtl837x_igmp.h"
|
#include "rtl837x_igmp.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
extern __code struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata uint8_t igmpEnabled;
|
extern __xdata uint8_t igmpEnabled;
|
||||||
|
|
||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
|
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
extern __code struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata struct machine_runtime machine_detected;
|
extern __xdata struct machine_runtime machine_detected;
|
||||||
|
|
||||||
#pragma codeseg BANK2
|
#pragma codeseg BANK2
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "rtl837x_leds.h"
|
#include "rtl837x_leds.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
extern __code struct machine machine;
|
extern __code const struct machine machine;
|
||||||
|
|
||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ void leds_setup(void) __banked
|
|||||||
sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0;
|
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_SET1);
|
||||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||||
__code uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
__code const uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
||||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||||
sfr_data[0] = *(lptr + 5);
|
sfr_data[0] = *(lptr + 5);
|
||||||
sfr_data[1] = *(lptr + 4);
|
sfr_data[1] = *(lptr + 4);
|
||||||
@@ -275,7 +275,7 @@ void leds_setup(void) __banked
|
|||||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||||
} else {
|
} else {
|
||||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||||
sfr_data[3 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
sfr_data[3 - ((set - 2) << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||||
}
|
}
|
||||||
lptr += 8;
|
lptr += 8;
|
||||||
@@ -291,7 +291,7 @@ void leds_setup(void) __banked
|
|||||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||||
} else {
|
} else {
|
||||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||||
sfr_data[2 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
sfr_data[2 - ((set - 2) << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||||
}
|
}
|
||||||
lptr += 8;
|
lptr += 8;
|
||||||
|
|||||||
@@ -20,9 +20,11 @@
|
|||||||
#pragma codeseg BANK2
|
#pragma codeseg BANK2
|
||||||
#pragma constseg BANK2
|
#pragma constseg BANK2
|
||||||
|
|
||||||
extern __code uint16_t bit_mask[16];
|
extern __code const uint16_t bit_mask[16];
|
||||||
extern __code const struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata struct machine_runtime machine_detected;
|
extern __xdata struct machine_runtime machine_detected;
|
||||||
|
extern volatile __xdata uint32_t ticks;
|
||||||
|
extern __xdata uint32_t rtl8224_release_tick;
|
||||||
|
|
||||||
__xdata struct phy_settings phy_settings;
|
__xdata struct phy_settings phy_settings;
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ __xdata struct phy_settings phy_settings;
|
|||||||
// Note: Adding `Swapping the RX for N-devices`-setting on the end of the array, didn't work.
|
// 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.
|
// Setting will apply but still no packets flow.
|
||||||
// Settings are `0x2000, 0xc10c`,
|
// Settings are `0x2000, 0xc10c`,
|
||||||
__code uint16_t rtl8224_sds0_setttings[42] = {
|
__code const uint16_t rtl8224_sds0_setttings[42] = {
|
||||||
// SDS_DATA, SDS_CMD
|
// SDS_DATA, SDS_CMD
|
||||||
0x4480, 0xc842,
|
0x4480, 0xc842,
|
||||||
0x0400, 0xc9c2,
|
0x0400, 0xc9c2,
|
||||||
@@ -214,9 +216,20 @@ void phy_config(uint8_t phy) __banked
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rtl8224_wait_ready(void) __banked
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID + 1);
|
||||||
|
if (SFR_DATA_U16 == 0x8224)
|
||||||
|
return;
|
||||||
|
} while ((ticks - rtl8224_release_tick) < (SYS_TICK_HZ * 5 / 2));
|
||||||
|
print_string("\r\nRTL8224 not responding\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
void phy_config_8224(void) __banked
|
void phy_config_8224(void) __banked
|
||||||
{
|
{
|
||||||
uint16_t pval;
|
uint16_t pval;
|
||||||
|
uint16_t tries;
|
||||||
print_string("\r\nphy_config_8224 called\r\nRTL8224 ID: ");
|
print_string("\r\nphy_config_8224 called\r\nRTL8224 ID: ");
|
||||||
|
|
||||||
// Print RTL8224 chip id
|
// Print RTL8224 chip id
|
||||||
@@ -244,9 +257,12 @@ void phy_config_8224(void) __banked
|
|||||||
i++;
|
i++;
|
||||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, rtl8224_sds0_setttings[i]);
|
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, rtl8224_sds0_setttings[i]);
|
||||||
i++;
|
i++;
|
||||||
|
tries = 0xffff;
|
||||||
do {
|
do {
|
||||||
rtl8224_read_reg_u16(0x3f8);
|
rtl8224_read_reg_u16(0x3f8);
|
||||||
} while (SFR_DATA_8 & 0x80);
|
} while ((SFR_DATA_8 & 0x80) && --tries);
|
||||||
|
if (SFR_DATA_8 & 0x80)
|
||||||
|
print_string("\r\nRTL8224 SerDes access timed out\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
print_string("\r\nphy_config_8224 done\r\n");
|
print_string("\r\nphy_config_8224 done\r\n");
|
||||||
@@ -354,8 +370,9 @@ void phy_set_speed(void) __banked
|
|||||||
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
||||||
} else {
|
} else {
|
||||||
// AN Advertisement Register (MMD 7.0x0010)
|
// AN Advertisement Register (MMD 7.0x0010)
|
||||||
// bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
// bits 0-4: 0x1 (802.3 supported), bit 10: PAUSE,
|
||||||
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1001);
|
// Extended Next Page format used
|
||||||
|
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1401);
|
||||||
if (phy_settings.speed == PHY_SPEED_1G) {
|
if (phy_settings.speed == PHY_SPEED_1G) {
|
||||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||||
// bit 14: SLAVE, bit 13: Multi-Port device, 1: LD Loop timin enableed
|
// bit 14: SLAVE, bit 13: Multi-Port device, 1: LD Loop timin enableed
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ extern __xdata struct phy_settings phy_settings;
|
|||||||
void rtl8224_phy_enable(void) __banked;
|
void rtl8224_phy_enable(void) __banked;
|
||||||
void phy_config(uint8_t phy) __banked;
|
void phy_config(uint8_t phy) __banked;
|
||||||
void phy_config_8224(void) __banked;
|
void phy_config_8224(void) __banked;
|
||||||
|
void rtl8224_wait_ready(void) __banked;
|
||||||
void phy_set_speed(void) __banked;
|
void phy_set_speed(void) __banked;
|
||||||
void phy_set_duplex(void) __banked;
|
void phy_set_duplex(void) __banked;
|
||||||
void phy_show(uint8_t port) __banked;
|
void phy_show(uint8_t port) __banked;
|
||||||
|
|||||||
@@ -10,38 +10,6 @@ extern __xdata uint8_t sfr_data[4];
|
|||||||
#pragma codeseg BANK2
|
#pragma codeseg BANK2
|
||||||
#pragma constseg BANK2
|
#pragma constseg BANK2
|
||||||
|
|
||||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked {
|
|
||||||
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) __banked{
|
|
||||||
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 */
|
/* Returns RTL837X_REG_GPIO_XX_OUTPUT register address */
|
||||||
static uint16_t gpio_output_reg(uint8_t pin) __banked{
|
static uint16_t gpio_output_reg(uint8_t pin) __banked{
|
||||||
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
|
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
|
||||||
@@ -147,8 +115,7 @@ bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
|
|||||||
|
|
||||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
|
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
|
||||||
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
|
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
|
||||||
(dev >> 5) | i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5
|
(dev >> 5) | machine.sfp_port[slot].i2c,
|
||||||
| i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2,
|
|
||||||
((dev << 3) & 0xff) | 0x1);
|
((dev << 3) & 0xff) | 0x1);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|||||||
@@ -71,12 +71,6 @@
|
|||||||
/* Not available GPIO */
|
/* Not available GPIO */
|
||||||
#define GPIO_NA 0xFF
|
#define GPIO_NA 0xFF
|
||||||
|
|
||||||
/* Convert SDA PIN GPIO to I2C bus number */
|
|
||||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked;
|
|
||||||
|
|
||||||
/* Convert SCL PIN GPIO to I2C bus number */
|
|
||||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup a GPIO pin as input
|
* Setup a GPIO pin as input
|
||||||
* pin: GPIO pin number 0-63
|
* pin: GPIO pin number 0-63
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
#pragma codeseg BANK1
|
#pragma codeseg BANK1
|
||||||
#pragma constseg BANK1
|
#pragma constseg BANK1
|
||||||
|
|
||||||
extern __code uint8_t * __code hex;
|
extern __code const uint8_t * __code const hex;
|
||||||
extern __code uint16_t bit_mask[16];
|
extern __code const uint16_t bit_mask[16];
|
||||||
extern __code struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
extern __xdata uint16_t vlan_ptr;
|
extern __xdata uint16_t vlan_ptr;
|
||||||
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||||
@@ -40,7 +40,6 @@ static void wait_table_ready(void)
|
|||||||
|
|
||||||
void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked
|
void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked
|
||||||
{
|
{
|
||||||
print_string("\nport_mirror_set called \n");
|
|
||||||
print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: ");
|
print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: ");
|
||||||
print_short(rx_pmask); print_string(", tx mask: "); print_short(tx_pmask);
|
print_short(rx_pmask); print_string(", tx mask: "); print_short(tx_pmask);
|
||||||
write_char('\n');
|
write_char('\n');
|
||||||
@@ -52,7 +51,6 @@ void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t t
|
|||||||
|
|
||||||
void port_mirror_del(void) __banked
|
void port_mirror_del(void) __banked
|
||||||
{
|
{
|
||||||
print_string("\nport_mirror_del called \n");
|
|
||||||
REG_SET(RTL837x_MIRROR_CTRL, 0);
|
REG_SET(RTL837x_MIRROR_CTRL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +100,9 @@ static void port_pvid_write(uint8_t port, __xdata uint16_t pvid)
|
|||||||
|
|
||||||
reg_read_m(reg);
|
reg_read_m(reg);
|
||||||
if (port & 0x1) {
|
if (port & 0x1) {
|
||||||
REG_WRITE(reg, sfr_data[0], pvid >> 4, sfr_data[2] & 0x0f | (pvid << 4), sfr_data[3]);
|
REG_WRITE(reg, sfr_data[0], pvid >> 4, (sfr_data[2] & 0x0f) | (pvid << 4), sfr_data[3]);
|
||||||
} else {
|
} else {
|
||||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0 | (pvid >> 8), pvid);
|
REG_WRITE(reg, sfr_data[0], sfr_data[1], (sfr_data[2] & 0xf0) | (pvid >> 8), pvid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +110,6 @@ void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked
|
|||||||
{
|
{
|
||||||
uint8_t lag = port_lag_of(port);
|
uint8_t lag = port_lag_of(port);
|
||||||
|
|
||||||
print_string("\nport_pvid_set called \n");
|
|
||||||
if (lag == PORT_LAG_NONE) {
|
if (lag == PORT_LAG_NONE) {
|
||||||
port_pvid_write(port, pvid);
|
port_pvid_write(port, pvid);
|
||||||
return;
|
return;
|
||||||
@@ -141,7 +138,6 @@ void vlan_delete(uint16_t vlan) __banked
|
|||||||
if (!vlan || vlan >= 0xfff)
|
if (!vlan || vlan >= 0xfff)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
print_string("\nvlan_delete called \n"); print_short(vlan);
|
|
||||||
vlan_name_remove(vlan);
|
vlan_name_remove(vlan);
|
||||||
REG_WRITE(RTL837x_TBL_DATA_IN_A, 0, 0, 0, 0);
|
REG_WRITE(RTL837x_TBL_DATA_IN_A, 0, 0, 0, 0);
|
||||||
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_WRITE | TBL_EXECUTE);
|
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_WRITE | TBL_EXECUTE);
|
||||||
@@ -232,7 +228,7 @@ void vlan_create(void) __banked
|
|||||||
vlan_settings.members |= 0x0200; // Set 10th bit
|
vlan_settings.members |= 0x0200; // Set 10th bit
|
||||||
vlan_settings.tagged |= 0x0200;
|
vlan_settings.tagged |= 0x0200;
|
||||||
|
|
||||||
print_string("\nvlan_create called\nvlan: "); print_short(vlan_settings.vlan);
|
print_string("vlan: "); print_short(vlan_settings.vlan);
|
||||||
print_string(", members: "); print_short(vlan_settings.members);
|
print_string(", members: "); print_short(vlan_settings.members);
|
||||||
print_string(", tagged: "); print_short(vlan_settings.tagged); write_char('\n');
|
print_string(", tagged: "); print_short(vlan_settings.tagged); write_char('\n');
|
||||||
|
|
||||||
@@ -250,7 +246,6 @@ void vlan_create(void) __banked
|
|||||||
|
|
||||||
wait_table_ready();
|
wait_table_ready();
|
||||||
|
|
||||||
print_string("vlan_create done \n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -263,7 +258,6 @@ void vlan_create(void) __banked
|
|||||||
*/
|
*/
|
||||||
void vlan_setup(void) __banked
|
void vlan_setup(void) __banked
|
||||||
{
|
{
|
||||||
print_string("\nvlan_setup called \n");
|
|
||||||
|
|
||||||
// No VLAN names set up so far
|
// No VLAN names set up so far
|
||||||
vlan_ptr = 0;
|
vlan_ptr = 0;
|
||||||
@@ -285,7 +279,7 @@ void vlan_setup(void) __banked
|
|||||||
#endif
|
#endif
|
||||||
reg_read_m(reg);
|
reg_read_m(reg);
|
||||||
if (i & 0x1) {
|
if (i & 0x1) {
|
||||||
REG_WRITE(reg, sfr_data[0], 0, sfr_data[2] & 0x0f | 0x10, sfr_data[3]);
|
REG_WRITE(reg, sfr_data[0], 0, (sfr_data[2] & 0x0f) | 0x10, sfr_data[3]);
|
||||||
} else {
|
} else {
|
||||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0, 0x01);
|
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0, 0x01);
|
||||||
}
|
}
|
||||||
@@ -331,7 +325,6 @@ void vlan_setup(void) __banked
|
|||||||
print_string("\nvlan_setup, REG 0x4f4c: "); print_reg(0x4f4c);
|
print_string("\nvlan_setup, REG 0x4f4c: "); print_reg(0x4f4c);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
print_string("vlan_setup done \n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -354,7 +347,6 @@ void port_l2_forget_port(uint8_t port) __banked
|
|||||||
*/
|
*/
|
||||||
uint8_t port_l2_forget(void) __banked
|
uint8_t port_l2_forget(void) __banked
|
||||||
{
|
{
|
||||||
print_string("\nport_l2_forget called\n");
|
|
||||||
// Configure the entries to be flushed:
|
// Configure the entries to be flushed:
|
||||||
// port-based (bits 0-1 are 0 and dynamic entries, bit 2 specifies dynamic entries
|
// port-based (bits 0-1 are 0 and dynamic entries, bit 2 specifies dynamic entries
|
||||||
REG_SET(RTL837x_L2_TBL_FLUSH_CNF, 0x0);
|
REG_SET(RTL837x_L2_TBL_FLUSH_CNF, 0x0);
|
||||||
@@ -370,7 +362,6 @@ uint8_t port_l2_forget(void) __banked
|
|||||||
reg_read_m(RTL837x_L2_TBL_FLUSH_CTRL);
|
reg_read_m(RTL837x_L2_TBL_FLUSH_CTRL);
|
||||||
} while (sfr_data[1]);
|
} while (sfr_data[1]);
|
||||||
|
|
||||||
print_string("port_l2_forget done\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +456,6 @@ void port_l2mc_set(uint8_t mac_last, __xdata uint16_t vid, __xdata uint16_t pmas
|
|||||||
*/
|
*/
|
||||||
void port_l2_setup(void) __banked
|
void port_l2_setup(void) __banked
|
||||||
{
|
{
|
||||||
print_string("\nport_l2_setup called\n");
|
|
||||||
|
|
||||||
port_l2_forget();
|
port_l2_forget();
|
||||||
|
|
||||||
@@ -483,7 +473,38 @@ void port_l2_setup(void) __banked
|
|||||||
// When maximim entries learned, then simply flood the packet
|
// When maximim entries learned, then simply flood the packet
|
||||||
reg_bit_set(RTL837X_L2_LRN_PORT_CONSTRT_ACT, 0);
|
reg_bit_set(RTL837X_L2_LRN_PORT_CONSTRT_ACT, 0);
|
||||||
|
|
||||||
print_string("\nport_l2_setup done\n");
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void port_media_show(uint8_t port) __banked
|
||||||
|
{
|
||||||
|
uint8_t pause;
|
||||||
|
|
||||||
|
if (!machine.is_sfp[port]) {
|
||||||
|
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||||
|
if (sfr_data[(port / 8) + 1] >> (port % 8) & 1) {
|
||||||
|
print_string("Link role: ");
|
||||||
|
reg_read_m(RTL837X_MAC_MSTR_SLV_STS);
|
||||||
|
if (sfr_data[3 - (port >> 3)] & (1 << (port & 7)))
|
||||||
|
print_string("master\n");
|
||||||
|
else
|
||||||
|
print_string("slave\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_string("Pause negotiated:");
|
||||||
|
reg_read_m(RTL837X_MAC_TX_PAUSE_STS);
|
||||||
|
pause = sfr_data[3 - (port >> 3)] & (1 << (port & 7));
|
||||||
|
if (pause)
|
||||||
|
print_string(" TX");
|
||||||
|
reg_read_m(RTL837X_MAC_RX_PAUSE_STS);
|
||||||
|
if (sfr_data[3 - (port >> 3)] & (1 << (port & 7))) {
|
||||||
|
print_string(" RX");
|
||||||
|
pause = 1;
|
||||||
|
}
|
||||||
|
if (!pause)
|
||||||
|
print_string(" none");
|
||||||
|
write_char('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -590,12 +611,12 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
|
|||||||
|
|
||||||
if (machine.is_sfp[port])
|
if (machine.is_sfp[port])
|
||||||
{
|
{
|
||||||
print_string("EEE can't be enabled for SFP port "); print_byte(port); print_string("\n");
|
print_string("EEE can't be enabled for SFP port "); print_phys_port(port); print_string("\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), EEE_RX_ENABLE | EEE_TX_ENABLE);
|
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), EEE_RX_ENABLE | EEE_TX_ENABLE);
|
||||||
print_string("EEE on for "); print_byte(port); print_string(" speed ");
|
print_string("EEE on for "); print_phys_port(port); print_string(" speed ");
|
||||||
// Enable all speeds up to the specified speed
|
// Enable all speeds up to the specified speed
|
||||||
if (speed & EEE_100) {
|
if (speed & EEE_100) {
|
||||||
print_string("100m\n");
|
print_string("100m\n");
|
||||||
@@ -654,7 +675,7 @@ void port_eee_disable(uint8_t port) __banked
|
|||||||
if (machine.is_sfp[port])
|
if (machine.is_sfp[port])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
print_string("EEE off for "); print_byte(port); write_char('\n');
|
print_string("EEE off for "); print_phys_port(port); write_char('\n');
|
||||||
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), 0);
|
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), 0);
|
||||||
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
|
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
|
||||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
|
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
|
||||||
@@ -758,7 +779,7 @@ void port_eee_enable_all(__xdata uint8_t speed) __banked
|
|||||||
port_eee_enable(i, speed);
|
port_eee_enable(i, speed);
|
||||||
} else {
|
} else {
|
||||||
if (speed & EEE_10G)
|
if (speed & EEE_10G)
|
||||||
port_eee_enable(i, speed & EEE_NORESET | EEE_2G5);
|
port_eee_enable(i, (speed & EEE_NORESET) | EEE_2G5);
|
||||||
else
|
else
|
||||||
port_eee_enable(i, speed);
|
port_eee_enable(i, speed);
|
||||||
}
|
}
|
||||||
@@ -899,7 +920,7 @@ void vlan_dump(void) __banked
|
|||||||
/** Set the ingress VLAN filtering */
|
/** Set the ingress VLAN filtering */
|
||||||
bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
||||||
{
|
{
|
||||||
if (port < machine.min_port || port > machine.max_port && port != CPU_PORT) {
|
if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (enabled)
|
if (enabled)
|
||||||
@@ -913,7 +934,7 @@ bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
|||||||
/** Get the ingress VLAN filtering status */
|
/** Get the ingress VLAN filtering status */
|
||||||
bool port_ingress_vlan_filter_get(uint8_t port) __banked
|
bool port_ingress_vlan_filter_get(uint8_t port) __banked
|
||||||
{
|
{
|
||||||
if (port < machine.min_port || port > machine.max_port && port != CPU_PORT) {
|
if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ extern __xdata struct vlan_settings vlan_settings;
|
|||||||
uint8_t port_l2_forget(void) __banked;
|
uint8_t port_l2_forget(void) __banked;
|
||||||
void port_l2_learned(void) __banked;
|
void port_l2_learned(void) __banked;
|
||||||
void port_stats_print(void) __banked;
|
void port_stats_print(void) __banked;
|
||||||
|
void port_media_show(uint8_t port) __banked;
|
||||||
int8_t vlan_get(uint16_t vlan) __banked;
|
int8_t vlan_get(uint16_t vlan) __banked;
|
||||||
__xdata uint16_t vlan_name(uint16_t vlan) __banked;
|
__xdata uint16_t vlan_name(uint16_t vlan) __banked;
|
||||||
void vlan_name_remove(uint16_t vlan) __banked;
|
void vlan_name_remove(uint16_t vlan) __banked;
|
||||||
|
|||||||
@@ -83,6 +83,10 @@
|
|||||||
#define RTL837X_REG_LINKS 0x63f0
|
#define RTL837X_REG_LINKS 0x63f0
|
||||||
#define RTL837X_REG_LINKS_89 0x63f4
|
#define RTL837X_REG_LINKS_89 0x63f4
|
||||||
#define RTL837X_REG_LINKS_STS 0x63E8
|
#define RTL837X_REG_LINKS_STS 0x63E8
|
||||||
|
/* Per-port status bits: bit N is chip port N */
|
||||||
|
#define RTL837X_MAC_TX_PAUSE_STS 0x63FC
|
||||||
|
#define RTL837X_MAC_RX_PAUSE_STS 0x6400
|
||||||
|
#define RTL837X_MAC_MSTR_SLV_STS 0x6408
|
||||||
|
|
||||||
/* Each nibble encodes the link state of a port.
|
/* Each nibble encodes the link state of a port.
|
||||||
Port 0 appears to be the CPU port
|
Port 0 appears to be the CPU port
|
||||||
@@ -126,6 +130,10 @@
|
|||||||
#define RTL837X_REG_I2C_CTRL2 0x041c
|
#define RTL837X_REG_I2C_CTRL2 0x041c
|
||||||
#define RTL837X_REG_I2C_IN 0x0420
|
#define RTL837X_REG_I2C_IN 0x0420
|
||||||
#define RTL837X_REG_I2C_OUT 0x0424
|
#define RTL837X_REG_I2C_OUT 0x0424
|
||||||
|
#define RTL837X_REG_I2C_SCL_SHIFT 5
|
||||||
|
#define RTL837X_REG_I2C_SDA_SHIFT 2
|
||||||
|
#define RTL837X_REG_I2C_SCL_MASK 0x3
|
||||||
|
#define RTL837X_REG_I2C_SDA_MASK 0x7
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NIC Related registers
|
* NIC Related registers
|
||||||
@@ -137,6 +145,10 @@
|
|||||||
#define RTL837X_REG_RX_CTRL 0x785c
|
#define RTL837X_REG_RX_CTRL 0x785c
|
||||||
#define RTL837X_REG_TX_CTRL 0x7860
|
#define RTL837X_REG_TX_CTRL 0x7860
|
||||||
#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874
|
#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874
|
||||||
|
#define RTL837X_NIC_INT_STS 0x7854
|
||||||
|
#define RTL837X_NIC_INT_MSK 0x7858
|
||||||
|
#define NIC_INT_RXIS 0x02
|
||||||
|
#define NIC_INT_RXIE 0x02
|
||||||
#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c
|
#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c
|
||||||
#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884
|
#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884
|
||||||
#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890
|
#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890
|
||||||
@@ -144,6 +156,9 @@
|
|||||||
#define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C
|
#define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C
|
||||||
#define RTL837X_REG_MAC_FORCE_MODE 0x6344
|
#define RTL837X_REG_MAC_FORCE_MODE 0x6344
|
||||||
|
|
||||||
|
/* Flags in byte 1 of the RX frame descriptor */
|
||||||
|
#define RX_TAG_L4_CSUM_BAD 0x04
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Statistics related registers
|
* Statistics related registers
|
||||||
*/
|
*/
|
||||||
@@ -263,6 +278,9 @@
|
|||||||
*/
|
*/
|
||||||
#define RTL8373_RLDP_TIMER 0x1074
|
#define RTL8373_RLDP_TIMER 0x1074
|
||||||
#define RTL837X_RMA0_CONF 0x4ecc
|
#define RTL837X_RMA0_CONF 0x4ecc
|
||||||
|
#define RTL837X_IMR_INT_PORT_LINK_STS_CHG 0x5f34
|
||||||
|
#define RTL837X_ISR_SW_INT_MODE 0x5f84
|
||||||
|
#define RTL837X_ISR_INT_PORT_LINK_CHG 0x5f88
|
||||||
#define RTL837X_RMA_CONF 0x4f1c
|
#define RTL837X_RMA_CONF 0x4f1c
|
||||||
#define RTL837X_MSTP_STATES 0x5310
|
#define RTL837X_MSTP_STATES 0x5310
|
||||||
#define RTL837X_REG_LED_RLDP_1 0x65F8
|
#define RTL837X_REG_LED_RLDP_1 0x65F8
|
||||||
|
|||||||
@@ -15,12 +15,14 @@
|
|||||||
#include "uip.h"
|
#include "uip.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
|
extern __xdata uint8_t err_status;
|
||||||
|
|
||||||
// All entry points are __banked and nothing here runs from an interrupt,
|
// All entry points are __banked and nothing here runs from an interrupt,
|
||||||
// so the module does not need to stay in the resident bank
|
// so the module does not need to stay in the resident bank
|
||||||
#pragma codeseg BANK2
|
#pragma codeseg BANK2
|
||||||
#pragma constseg BANK2
|
#pragma constseg BANK2
|
||||||
|
|
||||||
extern __code struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
extern __xdata struct machine_runtime machine_detected;
|
extern __xdata struct machine_runtime machine_detected;
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
|||||||
extern __xdata uint8_t cmd_words_len;
|
extern __xdata uint8_t cmd_words_len;
|
||||||
extern __xdata uint8_t cmd_words_b[15];
|
extern __xdata uint8_t cmd_words_b[15];
|
||||||
extern __xdata char save_cmd; /* 0 while execute_config() replays the saved config */
|
extern __xdata char save_cmd; /* 0 while execute_config() replays the saved config */
|
||||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd);
|
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd);
|
||||||
uint8_t atoi_byte(uint8_t idx);
|
uint8_t atoi_byte(uint8_t idx);
|
||||||
uint8_t cmd_parse_port_separator(uint8_t idx);
|
uint8_t cmd_parse_port_separator(uint8_t idx);
|
||||||
extern __xdata uint8_t atoi_results_u8;
|
extern __xdata uint8_t atoi_results_u8;
|
||||||
@@ -1134,5 +1136,6 @@ void stp_parse(void) __banked __reentrant
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
|
err_status = ERR_INVALID_ARGUMENT;
|
||||||
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | port <1-9>|lag <1-4> on|off|edge|cost|prio|guard|filter ...\n");
|
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | port <1-9>|lag <1-4> on|off|edge|cost|prio|guard|filter ...\n");
|
||||||
}
|
}
|
||||||
@@ -79,20 +79,23 @@ void crc16_bank1(__xdata uint8_t *v) __naked;
|
|||||||
|
|
||||||
__xdata uint8_t idle_ready;
|
__xdata uint8_t idle_ready;
|
||||||
|
|
||||||
__code uint8_t ownIP[] = { 192, 168, 2, 2 };
|
__code const uint8_t ownIP[] = { 192, 168, 2, 2 };
|
||||||
__code uint8_t gatewayIP[] = { 192, 168, 2, 22};
|
__code const uint8_t gatewayIP[] = { 192, 168, 2, 22};
|
||||||
__code uint8_t netmask[] = { 255, 255, 255, 0};
|
__code const uint8_t netmask[] = { 255, 255, 255, 0};
|
||||||
|
|
||||||
__xdata struct uip_eth_addr uip_ethaddr;
|
__xdata struct uip_eth_addr uip_ethaddr;
|
||||||
|
|
||||||
volatile __xdata uint32_t ticks;
|
volatile __xdata uint32_t ticks;
|
||||||
volatile __xdata uint8_t sec_counter;
|
volatile __xdata uint8_t sec_counter;
|
||||||
volatile __xdata uint16_t sleep_ticks;
|
volatile __xdata uint16_t sleep_ticks;
|
||||||
__xdata uint8_t stp_clock;
|
__xdata uint8_t stp_tick_last;
|
||||||
__xdata uint8_t arp_age_secs;
|
__xdata uint8_t arp_age_secs;
|
||||||
extern __xdata struct dhcp_state dhcp_state;
|
extern __xdata struct dhcp_state dhcp_state;
|
||||||
|
|
||||||
#define STP_TICK_DIVIDER 3
|
#define STP_TICK_STEP (SYS_TICK_HZ / STP_HZ)
|
||||||
|
#define STP_CATCH_UP 8
|
||||||
|
#define SFP_TICK_STEP 10
|
||||||
|
__xdata uint8_t sfp_tick_last;
|
||||||
|
|
||||||
/* Buffer for serial input, SBUF_SIZE must be power of 2 < 256
|
/* Buffer for serial input, SBUF_SIZE must be power of 2 < 256
|
||||||
* Writing to this buffer is under the sole control of the serial ISR
|
* Writing to this buffer is under the sole control of the serial ISR
|
||||||
@@ -108,8 +111,8 @@ extern __xdata uint8_t gpio_last_value[8];
|
|||||||
|
|
||||||
extern __xdata struct flash_region_t flash_region;
|
extern __xdata struct flash_region_t flash_region;
|
||||||
|
|
||||||
__code uint8_t * __code greeting = "\nA minimal prompt to explore the RTL8372:\n";
|
__code const uint8_t * __code const greeting = "\nA minimal prompt to explore the RTL8372:\n";
|
||||||
__code uint8_t * __code hex = "0123456789abcdef";
|
__code const uint8_t * __code const hex = "0123456789abcdef";
|
||||||
|
|
||||||
__xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
__xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||||
|
|
||||||
@@ -126,7 +129,7 @@ __xdata bool stp_enabled;
|
|||||||
__xdata uint8_t igmpEnabled;
|
__xdata uint8_t igmpEnabled;
|
||||||
__xdata char hostname[24]; /* device hostname, default set at boot, see rtl837x_common.h */
|
__xdata char hostname[24]; /* device hostname, default set at boot, see rtl837x_common.h */
|
||||||
|
|
||||||
__code uint16_t bit_mask[16] = {
|
__code const uint16_t bit_mask[16] = {
|
||||||
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
||||||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
||||||
};
|
};
|
||||||
@@ -134,6 +137,11 @@ __code uint16_t bit_mask[16] = {
|
|||||||
|
|
||||||
__xdata uint8_t linkbits_last[4];
|
__xdata uint8_t linkbits_last[4];
|
||||||
__xdata uint8_t linkbits_last_p89;
|
__xdata uint8_t linkbits_last_p89;
|
||||||
|
__data __at(0x20) volatile uint8_t evflags;
|
||||||
|
volatile __bit __at(0x00) link_irq;
|
||||||
|
volatile __bit __at(0x01) rx_irq;
|
||||||
|
volatile __bit __at(0x02) tick_pending;
|
||||||
|
__bit __at(0x03) cmd_available;
|
||||||
// Last known state of the SFP detection/Loss of Signal pins
|
// Last known state of the SFP detection/Loss of Signal pins
|
||||||
__xdata bool button_last;
|
__xdata bool button_last;
|
||||||
__xdata uint8_t button_sec_counter_last;
|
__xdata uint8_t button_sec_counter_last;
|
||||||
@@ -195,6 +203,7 @@ void isr_timer0(void) __interrupt(1)
|
|||||||
void isr_timer2(void) __interrupt(5)
|
void isr_timer2(void) __interrupt(5)
|
||||||
{
|
{
|
||||||
ticks++;
|
ticks++;
|
||||||
|
tick_pending = 1;
|
||||||
if (sleep_ticks > 0)
|
if (sleep_ticks > 0)
|
||||||
sleep_ticks--;
|
sleep_ticks--;
|
||||||
sec_counter++;
|
sec_counter++;
|
||||||
@@ -254,8 +263,19 @@ void write_char(char c)
|
|||||||
write_char_no_syslog(c);
|
write_char_no_syslog(c);
|
||||||
|
|
||||||
if (syslog_state.enabled) {
|
if (syslog_state.enabled) {
|
||||||
logbuf[syslog_state.writeptr++] = c;
|
__xdata uint16_t next = (syslog_state.writeptr + 1) & (LOGBUF_SIZE - 1);
|
||||||
syslog_state.writeptr &= (LOGBUF_SIZE - 1);
|
|
||||||
|
/* The ring is drained once per main loop pass, and a single command
|
||||||
|
* can print several times its size, so writing on regardless laps
|
||||||
|
* the reader and the datagram starts mid record. Drop instead, and
|
||||||
|
* flag a line so the reader empties what is there even if no
|
||||||
|
* newline has been seen yet. */
|
||||||
|
if (next == syslog_state.readptr) {
|
||||||
|
syslog_state.line_available = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logbuf[syslog_state.writeptr] = c;
|
||||||
|
syslog_state.writeptr = next;
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
syslog_state.line_available = 1;
|
syslog_state.line_available = 1;
|
||||||
}
|
}
|
||||||
@@ -303,19 +323,19 @@ void itoa_short(uint16_t v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void print_string(__code char *p)
|
void print_string(__code const char *p)
|
||||||
{
|
{
|
||||||
while (*p)
|
while (*p)
|
||||||
write_char(*p++);
|
write_char(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_string_no_syslog(__code char *p)
|
void print_string_no_syslog(__code const char *p)
|
||||||
{
|
{
|
||||||
while (*p)
|
while (*p)
|
||||||
write_char_no_syslog(*p++);
|
write_char_no_syslog(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_string_newline_no_syslog(__code char *p)
|
void print_string_newline_no_syslog(__code const char *p)
|
||||||
{
|
{
|
||||||
write_char_no_syslog('\n');
|
write_char_no_syslog('\n');
|
||||||
print_string_no_syslog(p);
|
print_string_no_syslog(p);
|
||||||
@@ -349,7 +369,7 @@ int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len)
|
void memcpyc(__xdata uint8_t *dst, __code const uint8_t *src, uint16_t len)
|
||||||
{
|
{
|
||||||
while (len--)
|
while (len--)
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
@@ -478,14 +498,14 @@ void print_cmd_prompt(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* External IRQ 0 Service Routine: Called on link change?
|
* External IRQ 0 Service Routine: the switch reports a link change. The
|
||||||
* Note that all registers are being put on the STACK because of calling a subroutine
|
* register access macros share the SFR data bytes with the main loop, so
|
||||||
|
* the handler only latches the event; idle() reads and clears it.
|
||||||
*/
|
*/
|
||||||
void isr_ext0(void) __interrupt(0)
|
void isr_ext0(void) __interrupt(0)
|
||||||
{
|
{
|
||||||
EX0 = 0; // Disable interrupt for the moment
|
EX0 = 0;
|
||||||
IT0 = 1; // Trigger on falling edge of external interrupt
|
link_irq = 1;
|
||||||
EX0 = 1; // Re-enable interrupt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -494,9 +514,8 @@ void isr_ext0(void) __interrupt(0)
|
|||||||
*/
|
*/
|
||||||
void isr_ext1(void) __interrupt(2)
|
void isr_ext1(void) __interrupt(2)
|
||||||
{
|
{
|
||||||
// This flag should only be reset after all packets have been read
|
|
||||||
EX1 = 0;
|
EX1 = 0;
|
||||||
EX1 = 1;
|
rx_irq = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -785,7 +804,7 @@ void nic_tx_packet(uint16_t ring_ptr)
|
|||||||
* Note that the address in the flash memory is not simply 0xbbaddr, because
|
* Note that the address in the flash memory is not simply 0xbbaddr, because
|
||||||
* the size of a bank is merely 0xc000.
|
* the size of a bank is merely 0xc000.
|
||||||
*/
|
*/
|
||||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr)
|
uint8_t read_flash(uint8_t bank, __code const uint8_t *addr)
|
||||||
{
|
{
|
||||||
uint8_t v;
|
uint8_t v;
|
||||||
uint8_t current_bank = PSBANK;
|
uint8_t current_bank = PSBANK;
|
||||||
@@ -973,14 +992,19 @@ void tcpip_output(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define RX_BUDGET 4
|
||||||
|
|
||||||
void handle_rx(void)
|
void handle_rx(void)
|
||||||
{
|
{
|
||||||
// Check the amount of data available on the NIC/ASIC side
|
__xdata uint8_t budget = RX_BUDGET;
|
||||||
reg_read_m(RTL837X_REG_NIC_RX_BUFF_DATA);
|
|
||||||
if (sfr_data[2] != 0 || sfr_data[3] != 0) {
|
while (budget--) {
|
||||||
reg_read_m(RTL837X_REG_CPU_RX_CURR_PKT);
|
// Check the amount of data available on the NIC/ASIC side
|
||||||
uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8;
|
reg_read(RTL837X_REG_NIC_RX_BUFF_DATA);
|
||||||
ring_ptr |= sfr_data[3];
|
if (!SFR_DATA_U16)
|
||||||
|
break;
|
||||||
|
reg_read(RTL837X_REG_CPU_RX_CURR_PKT);
|
||||||
|
uint16_t ring_ptr = SFR_DATA_U16;
|
||||||
ring_ptr <<= 3;
|
ring_ptr <<= 3;
|
||||||
if (!nic_rx_header(ring_ptr)) {
|
if (!nic_rx_header(ring_ptr)) {
|
||||||
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
|
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
|
||||||
@@ -999,6 +1023,7 @@ void handle_rx(void)
|
|||||||
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
|
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
health_rx_frame();
|
||||||
|
|
||||||
#ifdef RXTXDBG
|
#ifdef RXTXDBG
|
||||||
print_string("\n<< ");
|
print_string("\n<< ");
|
||||||
@@ -1152,54 +1177,8 @@ void handle_button(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
void check_links(void)
|
||||||
// An idle function that sleeps for 1 tick and does all the house-keeping
|
|
||||||
//
|
|
||||||
void idle(void)
|
|
||||||
{
|
{
|
||||||
PCON |= 1;
|
|
||||||
if (sec_counter >= SYS_TICK_HZ) {
|
|
||||||
sec_counter -= SYS_TICK_HZ;
|
|
||||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
|
||||||
uint8_t v = sfr_data[3];
|
|
||||||
#ifdef DEBUG
|
|
||||||
print_string(" Tick counter: "); print_long(ticks); write_char('\n');
|
|
||||||
#endif
|
|
||||||
v++;
|
|
||||||
sfr_data[3] = v;
|
|
||||||
if (!v) {
|
|
||||||
v = sfr_data[2];
|
|
||||||
v++;
|
|
||||||
sfr_data[2] = v;
|
|
||||||
if (!v) {
|
|
||||||
v = sfr_data[1];
|
|
||||||
v++;
|
|
||||||
sfr_data[1] = v;
|
|
||||||
if (!v) {
|
|
||||||
v = sfr_data[0];
|
|
||||||
v++;
|
|
||||||
sfr_data[0] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reg_write_m(RTL837X_REG_SEC_COUNTER);
|
|
||||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
|
||||||
|
|
||||||
// Check for button presses once a second
|
|
||||||
handle_button();
|
|
||||||
// Age the ARP cache: uip_arp_timer() expects a 10 s cadence
|
|
||||||
if (++arp_age_secs >= 10) {
|
|
||||||
arp_age_secs = 0;
|
|
||||||
uip_arp_timer();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
print_sfr_data();
|
|
||||||
write_char('\n');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for Link changes
|
|
||||||
reg_read_m(RTL837X_REG_LINKS_89);
|
reg_read_m(RTL837X_REG_LINKS_89);
|
||||||
__xdata uint8_t linkbits_p89 = sfr_data[3];
|
__xdata uint8_t linkbits_p89 = sfr_data[3];
|
||||||
|
|
||||||
@@ -1232,24 +1211,102 @@ void idle(void)
|
|||||||
cpy_4(linkbits_last, sfr_data);
|
cpy_4(linkbits_last, sfr_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for changes with SFP modules
|
|
||||||
handle_sfp();
|
|
||||||
|
|
||||||
// Check new Packets RX
|
//
|
||||||
handle_rx();
|
// An idle function that sleeps for 1 tick and does all the house-keeping
|
||||||
// Check UIP for packets to transmit
|
//
|
||||||
|
static void handle_tick(void)
|
||||||
|
{
|
||||||
|
if (sec_counter >= SYS_TICK_HZ) {
|
||||||
|
sec_counter -= SYS_TICK_HZ;
|
||||||
|
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||||
|
uint8_t v = sfr_data[3];
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_string(" Tick counter: "); print_long(ticks); write_char('\n');
|
||||||
|
#endif
|
||||||
|
v++;
|
||||||
|
sfr_data[3] = v;
|
||||||
|
if (!v) {
|
||||||
|
v = sfr_data[2];
|
||||||
|
v++;
|
||||||
|
sfr_data[2] = v;
|
||||||
|
if (!v) {
|
||||||
|
v = sfr_data[1];
|
||||||
|
v++;
|
||||||
|
sfr_data[1] = v;
|
||||||
|
if (!v) {
|
||||||
|
v = sfr_data[0];
|
||||||
|
v++;
|
||||||
|
sfr_data[0] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reg_write_m(RTL837X_REG_SEC_COUNTER);
|
||||||
|
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||||
|
|
||||||
|
// Check for button presses once a second
|
||||||
|
handle_button();
|
||||||
|
link_irq = 1;
|
||||||
|
// Age the ARP cache: uip_arp_timer() expects a 10 s cadence
|
||||||
|
if (++arp_age_secs >= 10) {
|
||||||
|
arp_age_secs = 0;
|
||||||
|
uip_arp_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_sfr_data();
|
||||||
|
write_char('\n');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
health_phase(HEALTH_PH_LINK);
|
||||||
|
if (TICKS_DUE(sfp_tick_last, SFP_TICK_STEP)) {
|
||||||
|
sfp_tick_last += SFP_TICK_STEP;
|
||||||
|
handle_sfp();
|
||||||
|
}
|
||||||
|
health_phase(HEALTH_PH_SFP);
|
||||||
handle_tx();
|
handle_tx();
|
||||||
// If STP protocol enabled, decrease STP timers to trigger actions
|
health_phase(HEALTH_PH_TX);
|
||||||
if (stp_enabled) {
|
if (stp_enabled) {
|
||||||
if (!stp_clock) {
|
uint8_t n = STP_CATCH_UP;
|
||||||
stp_clock = STP_TICK_DIVIDER;
|
while (n-- && TICKS_DUE(stp_tick_last, STP_TICK_STEP)) {
|
||||||
|
stp_tick_last += STP_TICK_STEP;
|
||||||
stp_timers();
|
stp_timers();
|
||||||
} else {
|
|
||||||
stp_clock--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check whether a command is waiting in the cmd_buffer and execute
|
health_phase(HEALTH_PH_STP);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void idle(void)
|
||||||
|
{
|
||||||
|
if (!evflags)
|
||||||
|
PCON |= 1;
|
||||||
|
health_loop_start();
|
||||||
|
if (tick_pending) {
|
||||||
|
tick_pending = 0;
|
||||||
|
handle_tick();
|
||||||
|
}
|
||||||
|
if (link_irq) {
|
||||||
|
link_irq = 0;
|
||||||
|
REG_SET(RTL837X_ISR_INT_PORT_LINK_CHG, 0x3ff);
|
||||||
|
EX0 = 1;
|
||||||
|
check_links();
|
||||||
|
}
|
||||||
|
health_phase(HEALTH_PH_LINK);
|
||||||
|
if (rx_irq) {
|
||||||
|
rx_irq = 0;
|
||||||
|
handle_rx();
|
||||||
|
REG_SET(RTL837X_NIC_INT_STS, NIC_INT_RXIS);
|
||||||
|
reg_read(RTL837X_REG_NIC_RX_BUFF_DATA);
|
||||||
|
if (SFR_DATA_U16)
|
||||||
|
rx_irq = 1;
|
||||||
|
else
|
||||||
|
EX1 = 1;
|
||||||
|
}
|
||||||
|
health_phase(HEALTH_PH_RX);
|
||||||
if (cmd_available) {
|
if (cmd_available) {
|
||||||
cmd_available = 0;
|
cmd_available = 0;
|
||||||
cmd_tokenize();
|
cmd_tokenize();
|
||||||
@@ -1257,6 +1314,7 @@ void idle(void)
|
|||||||
cmd_parser();
|
cmd_parser();
|
||||||
print_cmd_prompt();
|
print_cmd_prompt();
|
||||||
}
|
}
|
||||||
|
health_phase(HEALTH_PH_CMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1282,14 +1340,16 @@ void reset_chip(void)
|
|||||||
|
|
||||||
void setup_external_irqs(void)
|
void setup_external_irqs(void)
|
||||||
{
|
{
|
||||||
REG_SET(0x5f84, 0x42);
|
REG_SET(RTL837X_ISR_SW_INT_MODE, 0x42);
|
||||||
REG_SET(0x5f34, 0x3ff);
|
REG_SET(RTL837X_ISR_INT_PORT_LINK_CHG, 0x3ff);
|
||||||
|
REG_SET(RTL837X_IMR_INT_PORT_LINK_STS_CHG, 0x3ff);
|
||||||
|
|
||||||
// EX0 = 1; // Enable external IRQ 0 (Link-change)
|
link_irq = 1;
|
||||||
EX0 = 0;
|
IT0 = 1; // External IRQ 0 on falling edge (link change)
|
||||||
IT0 = 1; // External IRQ on falling edge
|
EX0 = 1;
|
||||||
|
|
||||||
EX1 = 1; // External IRQ 1 enable
|
rx_irq = 1;
|
||||||
|
EX1 = 1; // External IRQ 1: the NIC has received a packet
|
||||||
EX2 = 1; // External IRQ 2 enable: bit EIE.0
|
EX2 = 1; // External IRQ 2 enable: bit EIE.0
|
||||||
EX3 = 1; // External IRQ 3 enable: bit EIE.1
|
EX3 = 1; // External IRQ 3 enable: bit EIE.1
|
||||||
PX3 = 1; // Set EIP.1 = 1: External IRQ 3 set to high priority
|
PX3 = 1; // Set EIP.1 = 1: External IRQ 3 set to high priority
|
||||||
@@ -1570,7 +1630,8 @@ void check_and_flash_update_image(void)
|
|||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
ticks = 0;
|
ticks = 0;
|
||||||
stp_clock = STP_TICK_DIVIDER;
|
stp_tick_last = (uint8_t)ticks;
|
||||||
|
sfp_tick_last = (uint8_t)ticks;
|
||||||
dhcp_state.state = DHCP_OFF;
|
dhcp_state.state = DHCP_OFF;
|
||||||
sbuf_ptr = 0;
|
sbuf_ptr = 0;
|
||||||
|
|
||||||
@@ -1674,6 +1735,8 @@ void main(void)
|
|||||||
|
|
||||||
REG_SET(RTL837X_PIN_MUX_2, 0x0); // Disable pins for ACL
|
REG_SET(RTL837X_PIN_MUX_2, 0x0); // Disable pins for ACL
|
||||||
init_smi();
|
init_smi();
|
||||||
|
if (machine_detected.isRTL8373)
|
||||||
|
rtl8224_wait_ready();
|
||||||
|
|
||||||
rtl8373_revision();
|
rtl8373_revision();
|
||||||
|
|
||||||
@@ -1714,6 +1777,7 @@ void main(void)
|
|||||||
stp_enabled = 0;
|
stp_enabled = 0;
|
||||||
stp_defaults(); /* 802.1D/w default config before any "stp ..." replay */
|
stp_defaults(); /* 802.1D/w default config before any "stp ..." replay */
|
||||||
nic_setup();
|
nic_setup();
|
||||||
|
REG_SET(RTL837X_NIC_INT_MSK, NIC_INT_RXIE);
|
||||||
vlan_setup();
|
vlan_setup();
|
||||||
port_l2_setup();
|
port_l2_setup();
|
||||||
igmp_setup();
|
igmp_setup();
|
||||||
@@ -1751,6 +1815,7 @@ void main(void)
|
|||||||
|
|
||||||
cmd_editor_init();
|
cmd_editor_init();
|
||||||
|
|
||||||
|
health_stack_paint();
|
||||||
while (1) {
|
while (1) {
|
||||||
cmd_edit();
|
cmd_edit();
|
||||||
idle(); // Enter Idle mode until interrupt occurs
|
idle(); // Enter Idle mode until interrupt occurs
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ extern __code const struct machine machine;
|
|||||||
|
|
||||||
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
||||||
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
||||||
|
extern volatile __xdata uint32_t ticks;
|
||||||
|
|
||||||
__xdata uint8_t sfp_pins_last;
|
__xdata uint8_t sfp_pins_last;
|
||||||
__xdata char sfp_module_vendor[2][17];
|
__xdata char sfp_module_vendor[2][17];
|
||||||
__xdata char sfp_module_model[2][17];
|
__xdata char sfp_module_model[2][17];
|
||||||
@@ -28,6 +30,8 @@ __xdata uint8_t sfp_options[2];
|
|||||||
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
||||||
__xdata uint8_t sfp_speed[2];
|
__xdata uint8_t sfp_speed[2];
|
||||||
__xdata uint8_t sfp_quirks[2];
|
__xdata uint8_t sfp_quirks[2];
|
||||||
|
__xdata uint8_t sfp_wake_at[2];
|
||||||
|
__xdata uint8_t sfp_wake_pending[2];
|
||||||
|
|
||||||
|
|
||||||
__code enum sfp_quirk {
|
__code enum sfp_quirk {
|
||||||
@@ -35,12 +39,12 @@ __code enum sfp_quirk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct sfp_quirk_entry {
|
struct sfp_quirk_entry {
|
||||||
__code char *vendor; // Set vendor or model to 0 to act as wildcard
|
__code const char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||||
__code char *model;
|
__code const char *model;
|
||||||
uint8_t quirks;
|
uint8_t quirks;
|
||||||
};
|
};
|
||||||
|
|
||||||
static __code struct sfp_quirk_entry sfp_quirk_table[] = {
|
static __code const struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,9 +92,14 @@ bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t lengt
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
dst[length] = NUL;
|
dst[length] = NUL;
|
||||||
memcpy(dst, sfp_buf, length);
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
uint8_t c = sfp_buf[i];
|
||||||
|
if (c && (c < 0x20 || c > 0x7e || c == '"' || c == '\\'))
|
||||||
|
c = '.';
|
||||||
|
dst[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
while (length > 0 && dst[--length] == ' ')
|
while (length-- > 0 && (dst[length] == ' ' || dst[length] == NUL))
|
||||||
dst[length] = NUL;
|
dst[length] = NUL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -152,7 +161,6 @@ static bool sfp_module_read(uint8_t sfp)
|
|||||||
|
|
||||||
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
||||||
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
||||||
delay(100); // Delay, because some modules need time to wake up
|
|
||||||
if (!sfp_read_block(sfp, 11, 2))
|
if (!sfp_read_block(sfp, 11, 2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -194,6 +202,11 @@ void handle_sfp(void) __banked
|
|||||||
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
||||||
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
||||||
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
|
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
|
||||||
|
sfp_wake_at[sfp] = ticks;
|
||||||
|
sfp_wake_pending[sfp] = 1;
|
||||||
|
} else if (sfp_wake_pending[sfp]
|
||||||
|
&& (uint8_t)((uint8_t)ticks - sfp_wake_at[sfp]) >= SFP_WAKE_TICKS) {
|
||||||
|
sfp_wake_pending[sfp] = 0;
|
||||||
if (!sfp_module_read(sfp)) {
|
if (!sfp_module_read(sfp)) {
|
||||||
print_string("SFP: an I2C read failed, retrying on the next poll\n");
|
print_string("SFP: an I2C read failed, retrying on the next poll\n");
|
||||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||||
@@ -202,6 +215,7 @@ void handle_sfp(void) __banked
|
|||||||
} else {
|
} else {
|
||||||
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
||||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||||
|
sfp_wake_pending[sfp] = 0;
|
||||||
print_string("\n<MODULE REMOVED> Slot: "); write_char('1' + sfp); write_char('\n');
|
print_string("\n<MODULE REMOVED> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef SFP_H
|
#ifndef SFP_H
|
||||||
#define SFP_H
|
#define SFP_H
|
||||||
|
|
||||||
|
#define SFP_WAKE_TICKS 100
|
||||||
|
|
||||||
extern __xdata uint8_t sfp_pins_last;
|
extern __xdata uint8_t sfp_pins_last;
|
||||||
extern __xdata char sfp_module_vendor[2][17];
|
extern __xdata char sfp_module_vendor[2][17];
|
||||||
extern __xdata char sfp_module_model[2][17];
|
extern __xdata char sfp_module_model[2][17];
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ void syslog_stop(void) __banked
|
|||||||
void syslog_callback(uint16_t lport) __banked
|
void syslog_callback(uint16_t lport) __banked
|
||||||
{
|
{
|
||||||
uint16_t syslog_hdr;
|
uint16_t syslog_hdr;
|
||||||
if (lport != state.syslog_conn->lport)
|
if (!state.syslog_conn || lport != state.syslog_conn->lport)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((state.readptr != state.writeptr) && state.line_available)
|
if ((state.readptr != state.writeptr) && state.line_available)
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
SRCROOT = ..
|
SRCROOT = ..
|
||||||
# -include shim first so __xdata/__code/__banked vanish before any firmware header.
|
# -include shim first so __xdata/__code/__banked vanish before any firmware header.
|
||||||
CFLAGS = -std=gnu11 -g -O1 -Wall -Wextra -Wno-unused-parameter -Wno-unknown-pragmas \
|
CFLAGS = -std=gnu11 -g -O1 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unknown-pragmas \
|
||||||
|
-Wno-pointer-sign \
|
||||||
-DRTLP_HOST_TEST \
|
-DRTLP_HOST_TEST \
|
||||||
-fsanitize=address,undefined -fno-omit-frame-pointer \
|
-fsanitize=address,undefined -fno-omit-frame-pointer \
|
||||||
-include sdcc_shim.h -I. -I$(SRCROOT) -I$(SRCROOT)/httpd -I$(SRCROOT)/uip
|
-include sdcc_shim.h -Istub -I. -I$(SRCROOT) -I$(SRCROOT)/httpd -I$(SRCROOT)/uip
|
||||||
ifeq ($(findstring clang,$(shell $(CC) --version 2>/dev/null)),)
|
ifeq ($(findstring clang,$(shell $(CC) --version 2>/dev/null)),)
|
||||||
CFLAGS += -Wno-builtin-declaration-mismatch
|
CFLAGS += -Wno-builtin-declaration-mismatch
|
||||||
endif
|
endif
|
||||||
@@ -23,7 +24,16 @@ LDFLAGS = -fsanitize=address,undefined
|
|||||||
BUILDDIR = build
|
BUILDDIR = build
|
||||||
|
|
||||||
# One binary per subsystem under test.
|
# One binary per subsystem under test.
|
||||||
TESTS = $(BUILDDIR)/test_cmd_editor
|
TESTS = $(BUILDDIR)/test_cmd_editor \
|
||||||
|
$(BUILDDIR)/test_port_tables \
|
||||||
|
$(BUILDDIR)/test_page_json \
|
||||||
|
$(BUILDDIR)/test_httpd_tx \
|
||||||
|
$(BUILDDIR)/test_tick_gate
|
||||||
|
|
||||||
|
# The table tests link the register mock and one environment file; stub/
|
||||||
|
# stands in for the two headers a firmware build generates.
|
||||||
|
TABLE_ENV = support.c hw_mock.c env_tables.c $(SRCROOT)/cmd_editor.c \
|
||||||
|
$(SRCROOT)/rtl837x_port.c $(SRCROOT)/httpd/page_impl.c
|
||||||
|
|
||||||
all: run
|
all: run
|
||||||
|
|
||||||
@@ -34,6 +44,21 @@ $(BUILDDIR):
|
|||||||
$(BUILDDIR)/test_cmd_editor: test_cmd_editor.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
$(BUILDDIR)/test_cmd_editor: test_cmd_editor.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
||||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
# rtl837x_port.c and httpd/page_impl.c are compiled UNMODIFIED from the firmware tree.
|
||||||
|
$(BUILDDIR)/test_port_tables: test_port_tables.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
|
||||||
|
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
$(BUILDDIR)/test_tick_gate: test_tick_gate.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
$(BUILDDIR)/test_page_json: test_page_json.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
|
||||||
|
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
# httpd/httpd.c and uip/uip.c are compiled UNMODIFIED from the firmware tree;
|
||||||
|
# this test carries the environment below them itself.
|
||||||
|
$(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR)
|
||||||
|
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
run: $(TESTS)
|
run: $(TESTS)
|
||||||
@fail=0; for t in $(TESTS); do \
|
@fail=0; for t in $(TESTS); do \
|
||||||
echo "=== $$t ==="; \
|
echo "=== $$t ==="; \
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ fires — so it drops straight into CI.
|
|||||||
- **`sdcc_shim.h`** (force-included) erases SDCC 8051 keywords (`__xdata`,
|
- **`sdcc_shim.h`** (force-included) erases SDCC 8051 keywords (`__xdata`,
|
||||||
`__code`, `__banked`, …) so firmware sources compile under host gcc. It changes
|
`__code`, `__banked`, …) so firmware sources compile under host gcc. It changes
|
||||||
no logic — the code under test is byte-for-byte the firmware source.
|
no logic — the code under test is byte-for-byte the firmware source.
|
||||||
|
- **`hw_mock.c` / `hw_mock.h`** simulate the ASIC edge: a flat register file
|
||||||
|
behind `reg_read`/`reg_write` and the `SFR_DATA_*` registers, with a table
|
||||||
|
engine that performs a VLAN or L2 operation the moment `TBL_CTRL` is written,
|
||||||
|
fetches a MIB counter on `STAT_GET` and drops entries on `L2_TBL_FLUSH_CTRL`.
|
||||||
|
Nothing ever reports busy, so a polling loop runs once. The header states the
|
||||||
|
VLAN and L2 entry layouts independently of the firmware, so a test can hold
|
||||||
|
what `rtl837x_port.c` writes against what `page_impl.c` reads.
|
||||||
|
- **`env_tables.c`** carries the globals and leaf calls those two modules link
|
||||||
|
against; **`stub/`** stands in for the two headers only a firmware build
|
||||||
|
generates, so the harness needs no SDCC build first.
|
||||||
- **`support.c` / `support.h`** mock the hardware edges: the 16-byte serial ring
|
- **`support.c` / `support.h`** mock the hardware edges: the 16-byte serial ring
|
||||||
(`sbuf`), the command/history buffers, and the character-output sink
|
(`sbuf`), the command/history buffers, and the character-output sink
|
||||||
(`write_char` etc.). Buffers are sized **exactly** as on target, so ASan
|
(`write_char` etc.). Buffers are sized **exactly** as on target, so ASan
|
||||||
@@ -35,6 +45,9 @@ fires — so it drops straight into CI.
|
|||||||
| Test binary | TU under test | Findings exercised |
|
| Test binary | TU under test | Findings exercised |
|
||||||
|-------------|---------------|--------------------|
|
|-------------|---------------|--------------------|
|
||||||
| `test_cmd_editor` | `cmd_editor.c` | **C4** — full-line hang + `cmd_buffer` 1-byte overflow; basic entry & backspace regressions |
|
| `test_cmd_editor` | `cmd_editor.c` | **C4** — full-line hang + `cmd_buffer` 1-byte overflow; basic entry & backspace regressions |
|
||||||
|
| `test_port_tables` | `rtl837x_port.c` | VLAN entry layout and round trip, PVID register sharing, static multicast and management entries, per-port flush, trunk membership and hash seed |
|
||||||
|
| `test_page_json` | `httpd/page_impl.c` + `rtl837x_port.c` | `/vlan.json`, `/vlanlist`, `/l2.json` (walk, wrap marker, paging inside `outbuf`), 64-bit counters in `/status.json` and `/counters.json` |
|
||||||
|
| `test_httpd_tx` | `httpd/httpd.c` + `uip/uip.c` | a GET of a static file against a client that moves its receive window: ACK accounting, continuation chunks out of flash, retransmission |
|
||||||
|
|
||||||
## Adding a test for another module
|
## Adding a test for another module
|
||||||
1. Write `test_<module>.c` with `main()` driving the module's entry points and
|
1. Write `test_<module>.c` with `main()` driving the module's entry points and
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* env_tables.c - what rtl837x_port.c and httpd/page_impl.c link against
|
||||||
|
* besides the register mock: the console, the buffers page_impl writes into,
|
||||||
|
* the machine description and leaf calls into subsystems not under test.
|
||||||
|
* Buffers keep their firmware sizes so AddressSanitizer sees the same bounds
|
||||||
|
* the 8051 has.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_port.h"
|
||||||
|
#include "machine.h"
|
||||||
|
#include "uip.h"
|
||||||
|
#include "rtl837x_flash.h"
|
||||||
|
#include "syslog.h"
|
||||||
|
#include "rtl837x_phy.h"
|
||||||
|
#include "support.h"
|
||||||
|
|
||||||
|
/* ---- console: everything lands in out_buf (support.c) ---- */
|
||||||
|
void print_byte(uint8_t v)
|
||||||
|
{
|
||||||
|
static const char h[] = "0123456789abcdef";
|
||||||
|
write_char(h[(v >> 4) & 0xf]);
|
||||||
|
write_char(h[v & 0xf]);
|
||||||
|
}
|
||||||
|
void print_short(uint16_t v) { print_byte(v >> 8); print_byte(v); }
|
||||||
|
void print_long(uint32_t v) { print_short(v >> 16); print_short(v); }
|
||||||
|
void print_reg(uint16_t v) { print_short(v); }
|
||||||
|
void itoa_short(uint16_t v)
|
||||||
|
{
|
||||||
|
char b[6]; int n = 0;
|
||||||
|
do { b[n++] = '0' + v % 10; v /= 10; } while (v);
|
||||||
|
while (n) write_char(b[--n]);
|
||||||
|
}
|
||||||
|
void dbg_string(char *p) { (void)p; }
|
||||||
|
void dbg_short(uint16_t v) { (void)v; }
|
||||||
|
void dbg_char(char c) { (void)c; }
|
||||||
|
void dbg_byte(uint8_t v) { (void)v; }
|
||||||
|
|
||||||
|
/* ---- copied verbatim from rtlplayground.c ---- */
|
||||||
|
uint16_t strtox(uint8_t *dst, const char *s)
|
||||||
|
{
|
||||||
|
uint8_t *b = dst;
|
||||||
|
while (*s)
|
||||||
|
*dst++ = *s++;
|
||||||
|
*dst = 0;
|
||||||
|
return dst - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t bit_mask[16] = {
|
||||||
|
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
||||||
|
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
||||||
|
};
|
||||||
|
const uint8_t hex_chars[] = "0123456789abcdef";
|
||||||
|
uint8_t *hex = (uint8_t *)hex_chars;
|
||||||
|
|
||||||
|
/* ---- a 9-port RTL8373 whose logical ports map to themselves ---- */
|
||||||
|
const struct machine machine = {
|
||||||
|
.machine_name = "HOSTTEST",
|
||||||
|
.min_port = 0,
|
||||||
|
.max_port = 8,
|
||||||
|
.n_sfp = 0,
|
||||||
|
.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 },
|
||||||
|
};
|
||||||
|
struct machine_runtime machine_detected = { .isRTL8373 = 1 };
|
||||||
|
|
||||||
|
/* ---- firmware state the modules read or write ---- */
|
||||||
|
uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||||
|
uint16_t slen;
|
||||||
|
uint16_t management_vlan = 1;
|
||||||
|
uint16_t cont_len;
|
||||||
|
uint32_t cont_addr;
|
||||||
|
uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||||
|
uint16_t vlan_ptr;
|
||||||
|
uint8_t sfp_pins_last = 0xff;
|
||||||
|
uint8_t sfp_options[2];
|
||||||
|
char sfp_module_vendor[2][17];
|
||||||
|
char sfp_module_model[2][17];
|
||||||
|
char sfp_module_serial[2][17];
|
||||||
|
char hostname[24] = "hosttest";
|
||||||
|
char port_names[9][PORT_NAME_SIZE];
|
||||||
|
struct flash_region_t flash_region;
|
||||||
|
struct syslog_state syslog_state;
|
||||||
|
bool stp_enabled;
|
||||||
|
|
||||||
|
uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||||
|
struct uip_eth_addr uip_ethaddr = { .addr = { 0x02, 0x11, 0x22, 0x33, 0x44, 0x55 } };
|
||||||
|
|
||||||
|
/* ---- leaf calls into subsystems not under test ---- */
|
||||||
|
void flash_read_bulk(uint8_t *dst) { (void)dst; }
|
||||||
|
const char *get_flash_size_str(void) { return "2M"; }
|
||||||
|
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg) { (void)slot; (void)reg; return 0; }
|
||||||
|
bool gpio_pin_test(uint8_t pin) { (void)pin; return false; }
|
||||||
|
void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg) { (void)phy_id; (void)dev_id; (void)reg; }
|
||||||
|
void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t val) { (void)phy_id; (void)dev_id; (void)reg; (void)val; }
|
||||||
|
void phy_reset(uint8_t port) { (void)port; }
|
||||||
|
uint8_t stp_port_role(uint8_t port) { (void)port; return 0; }
|
||||||
|
uint8_t stp_port_state(uint8_t port) { (void)port; return 3; }
|
||||||
|
|
||||||
|
/* ---- STP state send_stp() prints; the tree is not under test here ---- */
|
||||||
|
#include "rtl837x_stp.h"
|
||||||
|
struct bridge root_bridge;
|
||||||
|
struct bridge stp_dbridge[STP_ENTITIES];
|
||||||
|
uint16_t stp_bpdu_age[STP_ENTITIES];
|
||||||
|
uint16_t stp_dpid[STP_ENTITIES];
|
||||||
|
uint16_t stp_lag_mask[STP_LAG_COUNT];
|
||||||
|
uint16_t stp_tc_count;
|
||||||
|
uint32_t root_bridge_cost;
|
||||||
|
uint32_t stp_dcost[STP_ENTITIES];
|
||||||
|
uint32_t stp_pcost[STP_ENTITIES];
|
||||||
|
uint8_t stp_ent_of[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||||
|
uint8_t stp_fwddelay_s = 15, stp_hello_s = 2, stp_maxage_s = 20;
|
||||||
|
uint8_t stp_pflags[STP_ENTITIES];
|
||||||
|
uint8_t stp_pp2p[STP_ENTITIES];
|
||||||
|
uint8_t stp_pprio[STP_ENTITIES];
|
||||||
|
uint8_t stp_prio = 0x80, stp_root_port = 0xff, stp_rstp = 1, stp_txhold = 6;
|
||||||
|
|
||||||
|
/* ---- SFP: no module present, reads fail ---- */
|
||||||
|
uint8_t sfp_buf[16];
|
||||||
|
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) { (void)slot; (void)reg; (void)len; return false; }
|
||||||
|
void print_phys_port(uint8_t port) { itoa_short(machine.log_to_phys_port[port]); }
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
/*
|
||||||
|
* hw_mock.c - the ASIC edge: SFR storage, register file, table engine.
|
||||||
|
*
|
||||||
|
* The shim declares every SFR extern so that including rtl837x_sfr.h from many
|
||||||
|
* translation units does not define them repeatedly. Undefining the four
|
||||||
|
* keywords here and re-including the header emits the definitions once, so
|
||||||
|
* the mock tracks the real register list without a hand-kept copy.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#undef __sfr
|
||||||
|
#undef __sfr16
|
||||||
|
#undef __sfr32
|
||||||
|
#undef __sbit
|
||||||
|
#define __sfr volatile uint8_t
|
||||||
|
#define __sfr16 volatile uint16_t
|
||||||
|
#define __sfr32 volatile uint32_t
|
||||||
|
#define __sbit bool
|
||||||
|
#include "rtl837x_sfr.h"
|
||||||
|
#undef __sfr
|
||||||
|
#undef __sfr16
|
||||||
|
#undef __sfr32
|
||||||
|
#undef __sbit
|
||||||
|
#define __sfr extern volatile uint8_t
|
||||||
|
#define __sfr16 extern volatile uint16_t
|
||||||
|
#define __sfr32 extern volatile uint32_t
|
||||||
|
#define __sbit extern bool
|
||||||
|
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "hw_mock.h"
|
||||||
|
|
||||||
|
uint8_t sfr_data[4];
|
||||||
|
unsigned long hw_reads, hw_writes;
|
||||||
|
|
||||||
|
static uint32_t regfile[0x10000];
|
||||||
|
static uint32_t vlan_tbl[4096];
|
||||||
|
static struct hw_l2 l2[HW_L2_MAX];
|
||||||
|
static uint64_t counters[16][64];
|
||||||
|
|
||||||
|
void hw_reset(void)
|
||||||
|
{
|
||||||
|
memset(regfile, 0, sizeof(regfile));
|
||||||
|
memset(vlan_tbl, 0, sizeof(vlan_tbl));
|
||||||
|
memset(l2, 0, sizeof(l2));
|
||||||
|
memset(counters, 0, sizeof(counters));
|
||||||
|
memset(sfr_data, 0, sizeof(sfr_data));
|
||||||
|
hw_reads = hw_writes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_reg_set(uint16_t addr, uint32_t v) { regfile[addr] = v; }
|
||||||
|
uint32_t hw_reg_get(uint16_t addr) { return regfile[addr]; }
|
||||||
|
uint32_t hw_vlan_word(uint16_t vid) { return vlan_tbl[vid & 0xfff]; }
|
||||||
|
void hw_counter_set(uint8_t port, uint8_t counter, uint64_t value) { counters[port & 0xf][counter & 0x3f] = value; }
|
||||||
|
|
||||||
|
/* ---- L2 table -------------------------------------------------------- */
|
||||||
|
|
||||||
|
static int l2_cmp(const void *x, const void *y)
|
||||||
|
{
|
||||||
|
const struct hw_l2 *a = x, *b = y;
|
||||||
|
if (a->present != b->present)
|
||||||
|
return a->present ? -1 : 1;
|
||||||
|
return (int)a->idx - (int)b->idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void l2_sort(void) { qsort(l2, HW_L2_MAX, sizeof(l2[0]), l2_cmp); }
|
||||||
|
|
||||||
|
int hw_l2_count(void)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
for (int i = 0; i < HW_L2_MAX; i++)
|
||||||
|
n += l2[i].present;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct hw_l2 *hw_l2_at(int n)
|
||||||
|
{
|
||||||
|
l2_sort();
|
||||||
|
return (n >= 0 && n < hw_l2_count()) ? &l2[n] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void l2_key(const struct hw_l2 *e, uint8_t mac[6], uint16_t *vid)
|
||||||
|
{
|
||||||
|
mac[0] = e->b >> 8; mac[1] = e->b;
|
||||||
|
mac[2] = e->a >> 24; mac[3] = e->a >> 16; mac[4] = e->a >> 8; mac[5] = e->a;
|
||||||
|
*vid = ((e->b >> 16) & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct hw_l2 *hw_l2_find(const uint8_t mac[6], uint16_t vid)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < HW_L2_MAX; i++) {
|
||||||
|
uint8_t m[6]; uint16_t v;
|
||||||
|
if (!l2[i].present)
|
||||||
|
continue;
|
||||||
|
l2_key(&l2[i], m, &v);
|
||||||
|
if (v == vid && !memcmp(m, mac, 6))
|
||||||
|
return &l2[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hw_l2 *l2_free(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < HW_L2_MAX; i++)
|
||||||
|
if (!l2[i].present)
|
||||||
|
return &l2[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t l2_hash(const uint8_t mac[6], uint16_t vid)
|
||||||
|
{
|
||||||
|
uint16_t h = vid;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
h = (uint16_t)(h * 31 + mac[i]);
|
||||||
|
return h & 0xfff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_l2_put(uint16_t idx, const uint8_t mac[6], uint16_t vid, uint16_t port_or_pmask, bool is_static)
|
||||||
|
{
|
||||||
|
struct hw_l2 *e = (struct hw_l2 *)hw_l2_find(mac, vid);
|
||||||
|
bool mc = mac[0] & 1;
|
||||||
|
if (!e)
|
||||||
|
e = l2_free();
|
||||||
|
e->present = true;
|
||||||
|
e->idx = idx & 0xfff;
|
||||||
|
e->a = ((uint32_t)mac[2] << 24) | ((uint32_t)mac[3] << 16) | ((uint32_t)mac[4] << 8) | mac[5];
|
||||||
|
e->b = (0x20u << 24) | ((uint32_t)(vid & 0xfff) << 16) | ((uint32_t)mac[0] << 8) | mac[1];
|
||||||
|
if (mc) {
|
||||||
|
e->b |= (uint32_t)(port_or_pmask & 0x3) << 30;
|
||||||
|
e->c = (port_or_pmask >> 2) & 0xff;
|
||||||
|
} else {
|
||||||
|
e->b |= (uint32_t)(port_or_pmask & 0x3) << 30;
|
||||||
|
e->c = (port_or_pmask >> 2) & 0x3;
|
||||||
|
}
|
||||||
|
if (is_static)
|
||||||
|
e->c |= 1u << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_l2_decode(const struct hw_l2 *e, uint8_t mac[6], uint16_t *vid, uint16_t *port_or_pmask,
|
||||||
|
bool *valid, bool *is_static, bool *mc)
|
||||||
|
{
|
||||||
|
l2_key(e, mac, vid);
|
||||||
|
*valid = (e->b >> 29) & 1;
|
||||||
|
*is_static = (e->c >> 16) & 1;
|
||||||
|
*mc = mac[0] & 1;
|
||||||
|
if (*mc)
|
||||||
|
*port_or_pmask = ((e->b >> 30) & 0x3) | ((e->c & 0xff) << 2);
|
||||||
|
else
|
||||||
|
*port_or_pmask = ((e->b >> 30) & 0x3) | ((e->c & 0x3) << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- the engine ------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void l2_out(const struct hw_l2 *e, uint16_t idx)
|
||||||
|
{
|
||||||
|
regfile[RTL837x_L2_DATA_OUT_A] = e ? e->a : 0;
|
||||||
|
regfile[RTL837x_L2_DATA_OUT_B] = e ? e->b : 0;
|
||||||
|
regfile[RTL837x_L2_DATA_OUT_C] = e ? e->c : 0;
|
||||||
|
regfile[RTL837x_TBL_DATA_0] = (regfile[RTL837x_TBL_DATA_0] & ~0x1fffu) | (e ? 0x1000 : 0) | (idx & 0xfff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void table_exec(uint32_t ctrl)
|
||||||
|
{
|
||||||
|
uint16_t idx = ((ctrl >> 16) & 0xfff);
|
||||||
|
uint8_t type = ctrl >> 8;
|
||||||
|
bool write = ctrl & TBL_WRITE;
|
||||||
|
|
||||||
|
if (type == TBL_VLAN) {
|
||||||
|
if (write)
|
||||||
|
vlan_tbl[idx] = regfile[RTL837x_TBL_DATA_IN_A];
|
||||||
|
else
|
||||||
|
regfile[RTL837x_L2_DATA_OUT_A] = vlan_tbl[idx];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type != TBL_L2_UNICAST)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32_t d0 = regfile[RTL837x_TBL_DATA_0];
|
||||||
|
uint8_t method = (d0 >> 14) & 0x3;
|
||||||
|
bool clear = (d0 >> 18) & 1;
|
||||||
|
|
||||||
|
if (method == TBL_LUTREAD_MAC) {
|
||||||
|
struct hw_l2 key = { .present = true, .a = regfile[RTL837x_TBL_DATA_IN_A],
|
||||||
|
.b = regfile[RTL837x_TBL_DATA_IN_B], .c = regfile[RTL837x_TBL_DATA_IN_C] };
|
||||||
|
uint8_t mac[6]; uint16_t vid;
|
||||||
|
l2_key(&key, mac, &vid);
|
||||||
|
struct hw_l2 *e = (struct hw_l2 *)hw_l2_find(mac, vid);
|
||||||
|
if (write) {
|
||||||
|
if (clear) {
|
||||||
|
if (e)
|
||||||
|
e->present = false;
|
||||||
|
l2_out(0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!e) {
|
||||||
|
e = l2_free();
|
||||||
|
e->idx = l2_hash(mac, vid);
|
||||||
|
}
|
||||||
|
e->present = true;
|
||||||
|
e->a = key.a; e->b = key.b; e->c = key.c;
|
||||||
|
l2_out(e, e->idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
l2_out(e, e ? e->idx : 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next-entry reads: the first present entry at or after idx, wrapping */
|
||||||
|
l2_sort();
|
||||||
|
int n = hw_l2_count();
|
||||||
|
struct hw_l2 *e = 0;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
if (l2[i].idx >= idx) { e = &l2[i]; break; }
|
||||||
|
if (!e && n)
|
||||||
|
e = &l2[0];
|
||||||
|
if (write) {
|
||||||
|
/* a write by index replaces the entry that sits there */
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
if (l2[i].idx == idx) { e = &l2[i]; break; }
|
||||||
|
if (!e)
|
||||||
|
e = l2_free();
|
||||||
|
e->present = (regfile[RTL837x_TBL_DATA_IN_B] >> 29) & 1;
|
||||||
|
e->idx = idx;
|
||||||
|
e->a = regfile[RTL837x_TBL_DATA_IN_A];
|
||||||
|
e->b = regfile[RTL837x_TBL_DATA_IN_B];
|
||||||
|
e->c = regfile[RTL837x_TBL_DATA_IN_C];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
l2_out(e, e ? e->idx : idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_exec(uint32_t ctrl)
|
||||||
|
{
|
||||||
|
uint16_t mask = ctrl & 0x3ff;
|
||||||
|
bool dynamic_only = regfile[RTL837x_L2_TBL_FLUSH_CNF] == 0;
|
||||||
|
for (int i = 0; i < HW_L2_MAX; i++) {
|
||||||
|
uint8_t mac[6]; uint16_t vid, p; bool valid, st, mc;
|
||||||
|
if (!l2[i].present)
|
||||||
|
continue;
|
||||||
|
hw_l2_decode(&l2[i], mac, &vid, &p, &valid, &st, &mc);
|
||||||
|
if (mc || (st && dynamic_only))
|
||||||
|
continue;
|
||||||
|
if ((mask >> p) & 1)
|
||||||
|
l2[i].present = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stat_exec(uint32_t v)
|
||||||
|
{
|
||||||
|
uint8_t cnt = (uint8_t)(((v >> 8) & 0xff) << 3) | ((v >> 5) & 0x7);
|
||||||
|
uint8_t port = (v >> 1) & 0xf;
|
||||||
|
uint64_t c = counters[port][cnt & 0x3f];
|
||||||
|
regfile[RTL837X_STAT_V_HIGH] = (uint32_t)(c >> 32);
|
||||||
|
regfile[RTL837X_STAT_V_LOW] = (uint32_t)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reg_store(uint16_t addr, uint32_t v)
|
||||||
|
{
|
||||||
|
hw_writes++;
|
||||||
|
regfile[addr] = v;
|
||||||
|
switch (addr) {
|
||||||
|
case RTL837X_TBL_CTRL:
|
||||||
|
if (v & TBL_EXECUTE) {
|
||||||
|
table_exec(v);
|
||||||
|
regfile[addr] = v & ~(uint32_t)TBL_EXECUTE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RTL837x_L2_TBL_FLUSH_CTRL:
|
||||||
|
if (v & L2_TBL_FLUSH_EXEC) {
|
||||||
|
flush_exec(v);
|
||||||
|
regfile[addr] = v & ~(uint32_t)L2_TBL_FLUSH_EXEC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RTL837X_STAT_GET:
|
||||||
|
if (v & 1) {
|
||||||
|
stat_exec(v);
|
||||||
|
regfile[addr] = v & ~1u;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t sfr_word(void)
|
||||||
|
{
|
||||||
|
return ((uint32_t)SFR_DATA_24 << 24) | ((uint32_t)SFR_DATA_16 << 16) | ((uint32_t)SFR_DATA_8 << 8) | SFR_DATA_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfr_load(uint32_t v)
|
||||||
|
{
|
||||||
|
SFR_DATA_24 = v >> 24; SFR_DATA_16 = v >> 16; SFR_DATA_8 = v >> 8; SFR_DATA_0 = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reg_read(uint16_t addr)
|
||||||
|
{
|
||||||
|
hw_reads++;
|
||||||
|
sfr_load(regfile[addr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reg_read_m(uint16_t addr)
|
||||||
|
{
|
||||||
|
reg_read(addr);
|
||||||
|
sfr_data[0] = SFR_DATA_24; sfr_data[1] = SFR_DATA_16; sfr_data[2] = SFR_DATA_8; sfr_data[3] = SFR_DATA_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reg_write(uint16_t addr)
|
||||||
|
{
|
||||||
|
reg_store(addr, sfr_word());
|
||||||
|
}
|
||||||
|
|
||||||
|
void reg_write_m(uint16_t addr)
|
||||||
|
{
|
||||||
|
sfr_load(((uint32_t)sfr_data[0] << 24) | ((uint32_t)sfr_data[1] << 16) | ((uint32_t)sfr_data[2] << 8) | sfr_data[3]);
|
||||||
|
reg_write(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reg_bit_set(uint16_t addr, char bit)
|
||||||
|
{
|
||||||
|
reg_read_m(addr);
|
||||||
|
sfr_data[3 - (bit >> 3)] |= 1 << (bit & 7);
|
||||||
|
reg_write_m(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reg_bit_clear(uint16_t addr, char bit)
|
||||||
|
{
|
||||||
|
reg_read_m(addr);
|
||||||
|
sfr_data[3 - (bit >> 3)] &= ~(1 << (bit & 7));
|
||||||
|
reg_write_m(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t reg_bit_test(uint16_t addr, char bit)
|
||||||
|
{
|
||||||
|
reg_read_m(addr);
|
||||||
|
return (sfr_data[3 - (bit >> 3)] >> (bit & 7)) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set)
|
||||||
|
{
|
||||||
|
sfr_data[3 - n] = (sfr_data[3 - n] & ~mask) | set;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* hw_mock.h - a simulated RTL837x register file and table engine.
|
||||||
|
*
|
||||||
|
* The firmware reaches the ASIC only through reg_read/reg_read_m/reg_write/
|
||||||
|
* reg_write_m and the SFR_DATA_* registers, so mocking that edge is enough to
|
||||||
|
* run the table code on the host. Every register is a 32-bit word in a flat
|
||||||
|
* file; a few addresses are live: writing TBL_CTRL with EXECUTE performs the
|
||||||
|
* table operation at once and clears the bit, STAT_GET fetches a counter,
|
||||||
|
* L2_TBL_FLUSH_CTRL drops entries. Nothing here ever reports busy, so a
|
||||||
|
* polling loop in the firmware runs exactly once.
|
||||||
|
*
|
||||||
|
* The VLAN and L2 entry layouts mirror what rtl837x_port.c writes and what
|
||||||
|
* httpd/page_impl.c reads; the decoders below are an independent statement
|
||||||
|
* of that layout, so a test can compare the firmware's two ends against it.
|
||||||
|
*/
|
||||||
|
#ifndef TEST_HW_MOCK_H
|
||||||
|
#define TEST_HW_MOCK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void hw_reset(void); /* every register 0, tables empty */
|
||||||
|
void hw_reg_set(uint16_t addr, uint32_t v);
|
||||||
|
uint32_t hw_reg_get(uint16_t addr);
|
||||||
|
|
||||||
|
extern uint8_t sfr_data[4]; /* the firmware's register scratch, owned here */
|
||||||
|
extern unsigned long hw_reads; /* reg_read + reg_read_m calls since hw_reset */
|
||||||
|
extern unsigned long hw_writes; /* reg_write + reg_write_m calls since hw_reset */
|
||||||
|
|
||||||
|
/* VLAN table: the 32-bit word the firmware wrote for that VID, 0 = never written */
|
||||||
|
uint32_t hw_vlan_word(uint16_t vid);
|
||||||
|
|
||||||
|
/* L2 table: entries as the three data words the firmware exchanges with the
|
||||||
|
* engine. Word B: bit 29 valid, bits 31:30 the low two bits of the port (or
|
||||||
|
* of the member mask), bits 27:16 VID, bits 15:0 the first two MAC octets.
|
||||||
|
* Word A: the last four MAC octets. Word C: bit 16 static, bits 1:0 the high
|
||||||
|
* two bits of the port; for a multicast MAC bits 7:0 are the member mask
|
||||||
|
* shifted right by two. */
|
||||||
|
#define HW_L2_MAX 64
|
||||||
|
struct hw_l2 {
|
||||||
|
bool present;
|
||||||
|
uint16_t idx;
|
||||||
|
uint32_t a, b, c; /* DATA_IN_A/B/C on write, L2_DATA_OUT_A/B/C on read */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Pointers returned below stay valid until the next table operation. */
|
||||||
|
int hw_l2_count(void);
|
||||||
|
const struct hw_l2 *hw_l2_at(int n); /* n-th present entry in idx order */
|
||||||
|
const struct hw_l2 *hw_l2_find(const uint8_t mac[6], uint16_t vid);
|
||||||
|
/* Put an entry the way the switch would hold it: a learned unicast entry on
|
||||||
|
* one port, or a static one. mc entries use pmask instead of a port. */
|
||||||
|
void hw_l2_put(uint16_t idx, const uint8_t mac[6], uint16_t vid, uint16_t port_or_pmask, bool is_static);
|
||||||
|
void hw_l2_decode(const struct hw_l2 *e, uint8_t mac[6], uint16_t *vid, uint16_t *port_or_pmask,
|
||||||
|
bool *valid, bool *is_static, bool *mc);
|
||||||
|
|
||||||
|
/* MIB counter the next STAT_GET for (port, counter) returns */
|
||||||
|
void hw_counter_set(uint8_t port, uint8_t counter, uint64_t value);
|
||||||
|
|
||||||
|
#endif /* TEST_HW_MOCK_H */
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#define SDCC_SHIM_H
|
#define SDCC_SHIM_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/* Memory-space qualifiers → nothing (host has one flat address space). */
|
/* Memory-space qualifiers → nothing (host has one flat address space). */
|
||||||
#define __xdata
|
#define __xdata
|
||||||
@@ -22,12 +23,27 @@
|
|||||||
/* bool, not unsigned char: SDCC's bit types normalize any assigned value
|
/* bool, not unsigned char: SDCC's bit types normalize any assigned value
|
||||||
* to 0/1, which _Bool reproduces exactly. */
|
* to 0/1, which _Bool reproduces exactly. */
|
||||||
#define __bit bool
|
#define __bit bool
|
||||||
#define __sbit bool
|
|
||||||
|
|
||||||
/* NOTE: the firmware ships its own 8051 memcpy/memset/strlen/strcpy/sleep with
|
/* Special-function registers are declared in rtl837x_sfr.h as
|
||||||
* incompatible signatures (rtl837x_common.h). Host TUs must therefore build with
|
* `__sfr __at(0xNN) NAME;`. With __at erased those become plain declarations,
|
||||||
* -fno-builtin (so gcc doesn't auto-declare the builtins) and must NOT include
|
* so they must carry extern or every translation unit including the header
|
||||||
* <string.h>/<unistd.h>. Test code uses the t_* helpers in support.h instead. */
|
* defines its own copy. __sbit is the bit-in-an-SFR form and only appears
|
||||||
|
* there; the local bit variable keyword is __bit above. test/hw_mock.c
|
||||||
|
* undefines these four and re-includes the header once to emit the storage. */
|
||||||
|
#define __sfr extern volatile uint8_t
|
||||||
|
#define __sfr16 extern volatile uint16_t
|
||||||
|
#define __sfr32 extern volatile uint32_t
|
||||||
|
#define __sbit extern bool
|
||||||
|
|
||||||
|
/* The firmware ships its own memcpy/memset/strlen/strcpy/sleep, and
|
||||||
|
* rtl837x_common.h hides those prototypes under RTLP_HOST_TEST so host builds
|
||||||
|
* take the C library versions. Something has to declare them, and firmware
|
||||||
|
* sources do call memset and memcpy; this header is force-included ahead of
|
||||||
|
* everything, so pulling <string.h> in here puts the libc versions in scope
|
||||||
|
* before any firmware header and nothing clashes. sleep() is not in
|
||||||
|
* <string.h> and is declared on its own rather than through <unistd.h>. */
|
||||||
|
#include <string.h>
|
||||||
|
extern unsigned int sleep(unsigned int seconds);
|
||||||
|
|
||||||
/* Function attributes → nothing (no banking / no 8051 calling conventions). */
|
/* Function attributes → nothing (no banking / no 8051 calling conventions). */
|
||||||
#define __banked
|
#define __banked
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/* Stand-in for the generated html_data.h: the table generators under test
|
||||||
|
* never touch the embedded file list, and the real header exists only after
|
||||||
|
* a firmware build, which the host harness must not depend on. */
|
||||||
|
#ifndef FDATA_DEFS_H
|
||||||
|
#define FDATA_DEFS_H
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef enum mime_type_e { mime_HTML = 0, mime_SVG, mime_ICO, mime_PNG, mime_JS, mime_CSS, mime_TXT } mime_type_t;
|
||||||
|
struct f_data { __code const char *file; uint32_t start; uint16_t len; mime_type_t mime; uint8_t gzip; };
|
||||||
|
#define FDATA_START_login_html 0x00040000UL
|
||||||
|
#define FDATA_START_favicon_ico 0x00041000UL
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#ifndef VERSION_H
|
||||||
|
#define VERSION_H
|
||||||
|
#define VERSION_SW "host-test"
|
||||||
|
#define BUILD_DATE "1970-01-01 00:00:00"
|
||||||
|
#endif
|
||||||
@@ -47,7 +47,7 @@ static void out_putc(char c) {
|
|||||||
|
|
||||||
/* --- mocked print helpers (signatures match rtl837x_common.h post-shim) ---- */
|
/* --- mocked print helpers (signatures match rtl837x_common.h post-shim) ---- */
|
||||||
void write_char(char c) { out_putc(c); }
|
void write_char(char c) { out_putc(c); }
|
||||||
void print_string(char *p) { while (*p) out_putc(*p++); }
|
void print_string(const char *p) { while (*p) out_putc(*p++); }
|
||||||
void print_string_x(char *p) { while (*p) out_putc(*p++); }
|
void print_string_x(char *p) { while (*p) out_putc(*p++); }
|
||||||
void print_cmd_prompt(void) { print_string((char *)"> "); }
|
void print_cmd_prompt(void) { print_string((char *)"> "); }
|
||||||
void itoa(uint8_t v) { /* firmware prints a decimal number */
|
void itoa(uint8_t v) { /* firmware prints a decimal number */
|
||||||
|
|||||||
@@ -0,0 +1,508 @@
|
|||||||
|
/*
|
||||||
|
* Host-side bench for the httpd transmit path.
|
||||||
|
*
|
||||||
|
* Compiles the UNMODIFIED httpd/httpd.c and uip/uip.c and drives them through a
|
||||||
|
* real handshake and a real GET from a client that moves its receive window.
|
||||||
|
* Everything below the two modules - flash, console, JSON pages - is mocked
|
||||||
|
* here, so what the bench observes is the byte stream the firmware would put on
|
||||||
|
* the wire.
|
||||||
|
*
|
||||||
|
* The file served out of the simulated flash carries a position-dependent
|
||||||
|
* pattern, so a duplicated or skipped range shows up as a mismatch at a known
|
||||||
|
* offset instead of an anonymous "content differs".
|
||||||
|
*
|
||||||
|
* Run: make -C test (exit code 0 = all scenarios pass)
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Some hosts ship these in <sys/_endian.h>, and they assign to their argument;
|
||||||
|
* uip.h refuses to be included next to them. The firmware definitions are the
|
||||||
|
* ones this bench needs, so the host macros go first. */
|
||||||
|
#undef HTONS
|
||||||
|
#undef NTOHS
|
||||||
|
|
||||||
|
#include "httpd.h"
|
||||||
|
#include "uip.h"
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "rtl837x_flash.h"
|
||||||
|
#include "page_impl.h"
|
||||||
|
#include "html_data.h"
|
||||||
|
|
||||||
|
/* Private to uip.c, and the client needs them to build segments. */
|
||||||
|
#define TCP_SYN 0x02
|
||||||
|
#define TCP_PSH 0x08
|
||||||
|
#define TCP_ACK 0x10
|
||||||
|
|
||||||
|
#define TCPH ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||||
|
|
||||||
|
#define MSS_FULL 1460
|
||||||
|
#define SMALL_WINDOW 600
|
||||||
|
|
||||||
|
/* httpd.c serves this one file without a session, which keeps the bench clear
|
||||||
|
* of the login machinery: what is under test is the transmit path. */
|
||||||
|
#define FILE_START FDATA_START_login_html
|
||||||
|
#define FILE_NAME "/login.html"
|
||||||
|
#define FILE_LEN 6000
|
||||||
|
#define STREAM_MAX 16384
|
||||||
|
|
||||||
|
static int failures;
|
||||||
|
static int verbose;
|
||||||
|
|
||||||
|
#define CHECK(cond, name) do { \
|
||||||
|
if (cond) printf("PASS %s\n", name); \
|
||||||
|
else { printf("FAIL %s\n", name); failures++; } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static uint8_t pattern(uint32_t addr)
|
||||||
|
{
|
||||||
|
return (uint8_t)((addr * 7u) + (addr >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- firmware environment below httpd.c --------------------------------- */
|
||||||
|
|
||||||
|
volatile uint8_t sfr_data[4];
|
||||||
|
volatile uint32_t ticks;
|
||||||
|
uint8_t cmd_capture;
|
||||||
|
uint8_t err_status;
|
||||||
|
const uint8_t * const hex = (const uint8_t *)"0123456789abcdef";
|
||||||
|
uint16_t crc_value;
|
||||||
|
const uint8_t * const HTTP_RESPONCE_TXT = (const uint8_t *)"HTTP/1.1 200 OK\r\n\r\n";
|
||||||
|
uint32_t flash_size = 0x80000;
|
||||||
|
uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||||
|
uint8_t rx_headers[16];
|
||||||
|
struct flash_region_t flash_region;
|
||||||
|
|
||||||
|
const char * const mime_strings[] = { "text/html", "image/svg+xml", "image/x-icon",
|
||||||
|
"image/png", "text/javascript", "text/css", "text/plain" };
|
||||||
|
|
||||||
|
const struct f_data f_data[] = {
|
||||||
|
{ FILE_NAME, FILE_START, FILE_LEN, mime_HTML, 0 },
|
||||||
|
{ 0, 0, 0, mime_HTML, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
void flash_read_bulk(uint8_t *dst)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0; i < flash_region.len; i++)
|
||||||
|
dst[i] = pattern(flash_region.addr + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_init(uint8_t enable_dio) { (void)enable_dio; }
|
||||||
|
void flash_sector_erase(void) { }
|
||||||
|
void flash_write_bytes(uint8_t *ptr) { (void)ptr; }
|
||||||
|
const char *get_flash_size_str(void) { return "512 kB"; }
|
||||||
|
void crc16_bank1(uint8_t *v) { (void)v; }
|
||||||
|
void reset_chip(void) { }
|
||||||
|
void delay(uint16_t t) { (void)t; }
|
||||||
|
void write_char(char c) { (void)c; }
|
||||||
|
void write_char_no_syslog(char c) { (void)c; }
|
||||||
|
void print_string(const char *p) { (void)p; }
|
||||||
|
void print_string_newline_no_syslog(const char *p) { (void)p; }
|
||||||
|
void set_sys_led_state(uint8_t state) { (void)state; }
|
||||||
|
void cmd_parser(void) { }
|
||||||
|
void execute_config(void) { }
|
||||||
|
void execute_commands(uint8_t *p) { (void)p; }
|
||||||
|
void clear_command_history(void) { }
|
||||||
|
void udp_callbacks(void) { }
|
||||||
|
void tcpip_output(void) { }
|
||||||
|
void get_random_32(void) { }
|
||||||
|
void read_reg_timer(uint32_t *tmr) { *tmr = 0; }
|
||||||
|
|
||||||
|
/* uip-conf.h asks uIP not to define the packet buffer: on the switch it lives
|
||||||
|
* at a fixed XDATA address, so the bench provides the storage itself. */
|
||||||
|
u8_t uip_buf[UIP_BUFSIZE + 2];
|
||||||
|
|
||||||
|
uint16_t strlen_x(const char *s) { return (uint16_t)strlen(s); }
|
||||||
|
|
||||||
|
uint16_t strtox(uint8_t *dst, const char *s)
|
||||||
|
{
|
||||||
|
uint16_t n = 0;
|
||||||
|
|
||||||
|
while (s[n]) { dst[n] = (uint8_t)s[n]; n++; }
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void memcpyc(uint8_t *dst, const uint8_t *src, uint16_t len) { memcpy(dst, src, len); }
|
||||||
|
|
||||||
|
bool strstart(const uint8_t *a, const uint8_t *b)
|
||||||
|
{
|
||||||
|
while (*b) { if (*a++ != *b++) return false; }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool strstart_x(const uint8_t *a, const uint8_t *b) { return strstart(a, b); }
|
||||||
|
|
||||||
|
bool send_counters(uint8_t phys_port) { (void)phys_port; return false; }
|
||||||
|
void send_status(void) { }
|
||||||
|
void send_vlan(uint16_t vlan) { (void)vlan; }
|
||||||
|
void send_basic_info(void) { }
|
||||||
|
void send_bandwidth(void) { }
|
||||||
|
void send_eee(void) { }
|
||||||
|
void send_l2(uint16_t idx) { (void)idx; }
|
||||||
|
void l2_delete(uint16_t idx) { (void)idx; }
|
||||||
|
void send_mirror(void) { }
|
||||||
|
void send_mtu(void) { }
|
||||||
|
void send_config(void) { }
|
||||||
|
void send_cmd_log(void) { }
|
||||||
|
void send_lag(void) { }
|
||||||
|
void send_stp(void) { }
|
||||||
|
void send_stp_counters(void) { }
|
||||||
|
void send_vlanlist(void) { }
|
||||||
|
|
||||||
|
extern uint8_t authenticated;
|
||||||
|
|
||||||
|
/* uip.c defines the listen table but no header declares it; the bench reads it
|
||||||
|
* to confirm the port httpd_init() asked for is the one uIP is watching. */
|
||||||
|
extern u16_t uip_listenports[UIP_LISTENPORTS];
|
||||||
|
|
||||||
|
/* ---- the simulated client ----------------------------------------------- */
|
||||||
|
|
||||||
|
static uint32_t cli_seq; /* next sequence number we send */
|
||||||
|
static uint32_t cli_rcv_nxt; /* next sequence number we expect */
|
||||||
|
static uint16_t cli_window; /* what we advertise */
|
||||||
|
|
||||||
|
static uint8_t stream[STREAM_MAX]; /* bytes accepted from the server */
|
||||||
|
static int stream_len;
|
||||||
|
|
||||||
|
static uint8_t last_tx[MSS_FULL + 64]; /* payload of the last server segment */
|
||||||
|
static int last_tx_len;
|
||||||
|
|
||||||
|
static uint16_t hton16(uint16_t v)
|
||||||
|
{
|
||||||
|
return (uint16_t)((v << 8) | (v >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wr32(uint8_t *p, uint32_t v)
|
||||||
|
{
|
||||||
|
p[0] = v >> 24; p[1] = v >> 16; p[2] = v >> 8; p[3] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t rd32(const uint8_t *p)
|
||||||
|
{
|
||||||
|
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
|
||||||
|
((uint32_t)p[2] << 8) | p[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace(const char *tag)
|
||||||
|
{
|
||||||
|
if (!verbose)
|
||||||
|
return;
|
||||||
|
printf(" [%-8s] uip_len=%-5u flags=0x%02x seq=%-6u ack=%-6u | conn: state=0x%02x len=%-5u mss=%-5u tstate=%u\n",
|
||||||
|
tag, uip_len,
|
||||||
|
uip_len ? TCPH->flags : 0,
|
||||||
|
uip_len ? rd32(TCPH->seqno) : 0,
|
||||||
|
uip_len ? rd32(TCPH->ackno) : 0,
|
||||||
|
uip_conns[0].tcpstateflags, uip_conns[0].len, uip_conns[0].mss,
|
||||||
|
uip_conns[0].appstate.tstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Takes in one outgoing segment, if uIP produced one. */
|
||||||
|
static int harvest(void)
|
||||||
|
{
|
||||||
|
uint8_t *payload;
|
||||||
|
uint32_t seq;
|
||||||
|
int plen, hlen;
|
||||||
|
|
||||||
|
if (uip_len == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
seq = rd32(TCPH->seqno);
|
||||||
|
/* The SYNACK carries the MSS option, so the header is not always 20 B. */
|
||||||
|
hlen = (TCPH->tcpoffset >> 4) * 4;
|
||||||
|
payload = &uip_buf[UIP_LLH_LEN + 20 + hlen];
|
||||||
|
plen = (int)uip_len - 20 - hlen;
|
||||||
|
if (plen < 0)
|
||||||
|
plen = 0;
|
||||||
|
|
||||||
|
if (plen > 0) {
|
||||||
|
last_tx_len = plen > (int)sizeof(last_tx) ? (int)sizeof(last_tx) : plen;
|
||||||
|
memcpy(last_tx, payload, last_tx_len);
|
||||||
|
|
||||||
|
/* A real client keeps what continues the stream and drops the
|
||||||
|
* rest, so bytes sent twice under new sequence numbers land in
|
||||||
|
* the file just as they would in a browser. */
|
||||||
|
if (seq == cli_rcv_nxt) {
|
||||||
|
if (stream_len + plen <= STREAM_MAX) {
|
||||||
|
memcpy(stream + stream_len, payload, plen);
|
||||||
|
stream_len += plen;
|
||||||
|
}
|
||||||
|
cli_rcv_nxt += plen;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
printf(" server -> %d B, seq %u\n", plen, seq);
|
||||||
|
}
|
||||||
|
if (TCPH->flags & TCP_SYN)
|
||||||
|
cli_rcv_nxt = seq + 1;
|
||||||
|
|
||||||
|
uip_len = 0;
|
||||||
|
return plen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_send(uint8_t flags, const char *payload, int plen)
|
||||||
|
{
|
||||||
|
int hlen = 20;
|
||||||
|
|
||||||
|
/* A SYN carries the MSS option, as every real client does: uIP takes the
|
||||||
|
* connection MSS from it, and without one the server has nothing to send
|
||||||
|
* with. */
|
||||||
|
if (flags & TCP_SYN)
|
||||||
|
hlen = 24;
|
||||||
|
|
||||||
|
memset(uip_buf, 0, UIP_LLH_LEN + 20 + hlen + (plen > 0 ? plen : 0));
|
||||||
|
TCPH->vhl = 0x45;
|
||||||
|
TCPH->tos = 0;
|
||||||
|
TCPH->len[0] = (uint8_t)((20 + hlen + plen) >> 8);
|
||||||
|
TCPH->len[1] = (uint8_t)((20 + hlen + plen) & 0xff);
|
||||||
|
TCPH->ttl = 64;
|
||||||
|
TCPH->proto = UIP_PROTO_TCP;
|
||||||
|
TCPH->ipchksum = 0;
|
||||||
|
TCPH->srcipaddr[0] = hton16(0x0a00); TCPH->srcipaddr[1] = hton16(0x0002);
|
||||||
|
TCPH->destipaddr[0] = hton16(0x0a00); TCPH->destipaddr[1] = hton16(0x0001);
|
||||||
|
TCPH->srcport = hton16(40000);
|
||||||
|
TCPH->destport = hton16(80);
|
||||||
|
wr32(TCPH->seqno, cli_seq);
|
||||||
|
wr32(TCPH->ackno, cli_rcv_nxt);
|
||||||
|
TCPH->tcpoffset = (uint8_t)((hlen / 4) << 4);
|
||||||
|
TCPH->flags = flags;
|
||||||
|
TCPH->wnd[0] = (uint8_t)(cli_window >> 8);
|
||||||
|
TCPH->wnd[1] = (uint8_t)(cli_window & 0xff);
|
||||||
|
TCPH->tcpchksum = 0;
|
||||||
|
|
||||||
|
if (hlen == 24) {
|
||||||
|
uint8_t *opt = &uip_buf[UIP_LLH_LEN + 40];
|
||||||
|
|
||||||
|
opt[0] = 2; opt[1] = 4; /* kind = MSS, length 4 */
|
||||||
|
opt[2] = MSS_FULL >> 8; opt[3] = MSS_FULL & 0xff;
|
||||||
|
}
|
||||||
|
if (plen > 0)
|
||||||
|
memcpy(&uip_buf[UIP_LLH_LEN + 20 + hlen], payload, plen);
|
||||||
|
|
||||||
|
uip_len = 20 + hlen + plen;
|
||||||
|
uip_input();
|
||||||
|
trace("input");
|
||||||
|
cli_seq += plen;
|
||||||
|
if (flags & TCP_SYN)
|
||||||
|
cli_seq++;
|
||||||
|
harvest();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_ack(uint16_t window)
|
||||||
|
{
|
||||||
|
cli_window = window;
|
||||||
|
client_send(TCP_ACK, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_periodic(int rounds)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < rounds; i++) {
|
||||||
|
uip_periodic(0);
|
||||||
|
trace("timer");
|
||||||
|
harvest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void session_start(uint16_t window)
|
||||||
|
{
|
||||||
|
uip_init();
|
||||||
|
httpd_init();
|
||||||
|
authenticated = 1;
|
||||||
|
|
||||||
|
cli_seq = 1000;
|
||||||
|
cli_rcv_nxt = 0;
|
||||||
|
cli_window = window;
|
||||||
|
stream_len = 0;
|
||||||
|
last_tx_len = 0;
|
||||||
|
|
||||||
|
client_send(TCP_SYN, NULL, 0);
|
||||||
|
client_ack(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void request_file(uint16_t window)
|
||||||
|
{
|
||||||
|
static const char get[] = "GET " FILE_NAME " HTTP/1.1\r\nHost: sw\r\n\r\n";
|
||||||
|
|
||||||
|
cli_window = window;
|
||||||
|
client_send(TCP_ACK | TCP_PSH, get, (int)strlen(get));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drains the response, acknowledging every segment with the given window. */
|
||||||
|
static void drain(uint16_t window)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 20 && stream_len < STREAM_MAX; i++) {
|
||||||
|
client_ack(window);
|
||||||
|
run_periodic(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int body_offset(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i + 4 <= stream_len; i++)
|
||||||
|
if (!memcmp(stream + i, "\r\n\r\n", 4))
|
||||||
|
return i + 4;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Offset of the first body byte that is not the one the file holds there, or
|
||||||
|
* -1 when the body matches, or -2 when no header ever arrived. */
|
||||||
|
static int first_body_mismatch(void)
|
||||||
|
{
|
||||||
|
int off = body_offset();
|
||||||
|
|
||||||
|
if (off < 0)
|
||||||
|
return -2;
|
||||||
|
for (int i = 0; i < FILE_LEN && off + i < stream_len; i++)
|
||||||
|
if (stream[off + i] != pattern(FILE_START + i))
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report(const char *tag)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
printf(" %s: header %d B, stream %d B, first mismatch %d\n",
|
||||||
|
tag, body_offset(), stream_len, first_body_mismatch());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- scenarios ---------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Instrument check: with a window that never moves, the MSS at ACK time and the
|
||||||
|
* length sent earlier are the same number, so the file must arrive intact. If
|
||||||
|
* this one fails, the bench is wrong - not the firmware. */
|
||||||
|
static void scenario_steady_window(void)
|
||||||
|
{
|
||||||
|
session_start(MSS_FULL);
|
||||||
|
if (verbose)
|
||||||
|
printf(" listen port=0x%04x, initial mss=%u\n",
|
||||||
|
uip_listenports[0], uip_conns[0].initialmss);
|
||||||
|
request_file(MSS_FULL);
|
||||||
|
drain(MSS_FULL);
|
||||||
|
report("steady");
|
||||||
|
|
||||||
|
CHECK(body_offset() >= 0, "control: response carries an HTTP header");
|
||||||
|
CHECK(stream_len >= body_offset() + FILE_LEN,
|
||||||
|
"control: the whole file arrives");
|
||||||
|
CHECK(first_body_mismatch() == -1,
|
||||||
|
"control: file content without duplicates or gaps");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The client stops draining, so the window in the ACK is smaller than the
|
||||||
|
* segment that ACK covers. */
|
||||||
|
static void scenario_shrinking_window(void)
|
||||||
|
{
|
||||||
|
session_start(MSS_FULL);
|
||||||
|
request_file(MSS_FULL);
|
||||||
|
drain(SMALL_WINDOW);
|
||||||
|
report("shrinking");
|
||||||
|
|
||||||
|
CHECK(body_offset() >= 0,
|
||||||
|
"shrinking window: response carries an HTTP header");
|
||||||
|
CHECK(stream_len >= body_offset() + FILE_LEN,
|
||||||
|
"shrinking window: the whole file arrives");
|
||||||
|
CHECK(first_body_mismatch() == -1,
|
||||||
|
"shrinking window: file content without duplicates or gaps");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The client catches up, so the window in the ACK is larger than the segment
|
||||||
|
* that ACK covers. */
|
||||||
|
static void scenario_growing_window(void)
|
||||||
|
{
|
||||||
|
session_start(SMALL_WINDOW);
|
||||||
|
request_file(SMALL_WINDOW);
|
||||||
|
drain(MSS_FULL);
|
||||||
|
report("growing");
|
||||||
|
|
||||||
|
CHECK(stream_len >= body_offset() + FILE_LEN,
|
||||||
|
"growing window: the whole file arrives");
|
||||||
|
CHECK(first_body_mismatch() == -1,
|
||||||
|
"growing window: file content without duplicates or gaps");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A segment is lost, a window update shrinks the window while it is still
|
||||||
|
* unacknowledged, and the retransmission timer fires. */
|
||||||
|
static void scenario_rexmit_after_shrink(void)
|
||||||
|
{
|
||||||
|
uint8_t original[MSS_FULL + 64];
|
||||||
|
int original_len, same = 1;
|
||||||
|
|
||||||
|
session_start(MSS_FULL);
|
||||||
|
request_file(MSS_FULL);
|
||||||
|
|
||||||
|
original_len = last_tx_len;
|
||||||
|
memcpy(original, last_tx, original_len);
|
||||||
|
|
||||||
|
/* The segment never arrived: take it back out of the client's stream and
|
||||||
|
* send a pure window update, which acknowledges nothing. */
|
||||||
|
if (original_len > 0 && stream_len >= original_len) {
|
||||||
|
stream_len -= original_len;
|
||||||
|
cli_rcv_nxt -= original_len;
|
||||||
|
}
|
||||||
|
cli_window = SMALL_WINDOW;
|
||||||
|
client_send(TCP_ACK, NULL, 0);
|
||||||
|
|
||||||
|
memset(&uip_buf[UIP_LLH_LEN + 40], 0xaa, MSS_FULL);
|
||||||
|
|
||||||
|
last_tx_len = 0;
|
||||||
|
run_periodic(UIP_RTO + 2);
|
||||||
|
|
||||||
|
if (last_tx_len != original_len || memcmp(last_tx, original, original_len))
|
||||||
|
same = 0;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
printf(" first %d B, retransmitted %d B\n",
|
||||||
|
original_len, last_tx_len);
|
||||||
|
|
||||||
|
CHECK(original_len > 0, "retransmission: the first segment went out");
|
||||||
|
CHECK(same, "retransmission: the repeat carries the same bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scenario_bad_l4_checksum(void)
|
||||||
|
{
|
||||||
|
uip_stats_t chkerr_before;
|
||||||
|
uint32_t seq_before;
|
||||||
|
int len_before;
|
||||||
|
|
||||||
|
session_start(MSS_FULL);
|
||||||
|
|
||||||
|
chkerr_before = uip_stat.tcp.chkerr;
|
||||||
|
len_before = stream_len;
|
||||||
|
seq_before = cli_seq;
|
||||||
|
|
||||||
|
rx_headers[1] = RX_TAG_L4_CSUM_BAD;
|
||||||
|
request_file(MSS_FULL);
|
||||||
|
rx_headers[1] = 0;
|
||||||
|
cli_seq = seq_before;
|
||||||
|
|
||||||
|
CHECK(uip_stat.tcp.chkerr == chkerr_before + 1,
|
||||||
|
"bad checksum: the segment is counted as a checksum error");
|
||||||
|
CHECK(stream_len == len_before,
|
||||||
|
"bad checksum: the request draws no reply");
|
||||||
|
|
||||||
|
request_file(MSS_FULL);
|
||||||
|
drain(MSS_FULL);
|
||||||
|
report("bad checksum");
|
||||||
|
|
||||||
|
CHECK(body_offset() >= 0,
|
||||||
|
"bad checksum control: the same request with a good flag is served");
|
||||||
|
CHECK(first_body_mismatch() == -1,
|
||||||
|
"bad checksum control: the file that follows is intact");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc > 1 && !strcmp(argv[1], "-v"))
|
||||||
|
verbose = 1;
|
||||||
|
|
||||||
|
printf("== httpd: accounting for the bytes actually sent ==\n");
|
||||||
|
scenario_steady_window();
|
||||||
|
scenario_shrinking_window();
|
||||||
|
scenario_growing_window();
|
||||||
|
scenario_rexmit_after_shrink();
|
||||||
|
scenario_bad_l4_checksum();
|
||||||
|
|
||||||
|
printf("\n%s (%d failure%s)\n",
|
||||||
|
failures ? "BENCH: FAILURES" : "BENCH: ALL PASS",
|
||||||
|
failures, failures == 1 ? "" : "s");
|
||||||
|
return failures ? 1 : 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* test_page_json.c - the JSON generators of httpd/page_impl.c, fed by the
|
||||||
|
* table code of rtl837x_port.c over the simulated engine. Both modules are
|
||||||
|
* compiled unmodified, so what the web page shows is checked against what
|
||||||
|
* the CLI configured, through the same bytes the switch would hold.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "rtl837x_port.h"
|
||||||
|
#include "machine.h"
|
||||||
|
#include "page_impl.h"
|
||||||
|
#include "support.h"
|
||||||
|
#include "hw_mock.h"
|
||||||
|
|
||||||
|
extern uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||||
|
extern uint16_t slen;
|
||||||
|
extern uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||||
|
extern uint16_t vlan_ptr;
|
||||||
|
extern uint16_t management_vlan;
|
||||||
|
|
||||||
|
/* The response body: what follows the blank line after the header. */
|
||||||
|
static const char *body(void)
|
||||||
|
{
|
||||||
|
outbuf[slen < TCP_OUTBUF_SIZE ? slen : TCP_OUTBUF_SIZE - 1] = 0;
|
||||||
|
const char *p = strstr((const char *)outbuf, "\r\n\r\n");
|
||||||
|
return p ? p + 4 : (const char *)outbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int has(const char *needle) { return strstr(body(), needle) != 0; }
|
||||||
|
|
||||||
|
static int count(const char *needle)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
for (const char *p = body(); (p = strstr(p, needle)); p += strlen(needle))
|
||||||
|
n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Brackets and braces balance outside strings, quotes pair up. */
|
||||||
|
static int balanced(void)
|
||||||
|
{
|
||||||
|
int depth = 0, instr = 0;
|
||||||
|
for (const char *p = body(); *p; p++) {
|
||||||
|
if (*p == '"') { instr = !instr; continue; }
|
||||||
|
if (instr) continue;
|
||||||
|
if (*p == '{' || *p == '[') depth++;
|
||||||
|
if (*p == '}' || *p == ']') depth--;
|
||||||
|
if (depth < 0) return 0;
|
||||||
|
}
|
||||||
|
return depth == 0 && !instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void name_vlan(uint16_t vid, const char *name)
|
||||||
|
{
|
||||||
|
static const char h[] = "0123456789abcdef";
|
||||||
|
vlan_names[vlan_ptr++] = h[(vid >> 8) & 0xf];
|
||||||
|
vlan_names[vlan_ptr++] = h[(vid >> 4) & 0xf];
|
||||||
|
vlan_names[vlan_ptr++] = h[vid & 0xf];
|
||||||
|
while (*name) vlan_names[vlan_ptr++] = *name++;
|
||||||
|
vlan_names[vlan_ptr++] = ' ';
|
||||||
|
vlan_names[vlan_ptr] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void make_vlan(uint16_t vid, uint16_t members, uint16_t tagged)
|
||||||
|
{
|
||||||
|
vlan_settings.vlan = vid;
|
||||||
|
vlan_settings.members = members;
|
||||||
|
vlan_settings.tagged = tagged;
|
||||||
|
vlan_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_vlan(void)
|
||||||
|
{
|
||||||
|
printf("[test] /vlan.json shows what vlan_create and pvid wrote\n");
|
||||||
|
hw_reset(); out_reset(); vlan_ptr = 0; vlan_names[0] = 0;
|
||||||
|
make_vlan(10, 0x0015, 0x0004);
|
||||||
|
name_vlan(10, "lab");
|
||||||
|
port_pvid_set(0, 10);
|
||||||
|
port_pvid_set(2, 10);
|
||||||
|
port_pvid_set(4, 20);
|
||||||
|
send_vlan(10);
|
||||||
|
char want[32];
|
||||||
|
snprintf(want, sizeof want, "\"members\":\"0x%x\"", hw_vlan_word(10));
|
||||||
|
CHECK(has(want), "members is the entry word");
|
||||||
|
CHECK(has("\"name\":\"lab\""), "name comes from the name table");
|
||||||
|
CHECK(has("\"pvid\":\"0x0005\""), "pvid mask has ports 1 and 3, not 5");
|
||||||
|
CHECK(balanced(), "valid JSON");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_vlanlist(void)
|
||||||
|
{
|
||||||
|
printf("[test] /vlanlist lists the VLANs that exist\n");
|
||||||
|
hw_reset(); out_reset(); vlan_ptr = 0; vlan_names[0] = 0;
|
||||||
|
make_vlan(10, 0x0015, 0x0004);
|
||||||
|
make_vlan(20, 0x00f0, 0x0000);
|
||||||
|
make_vlan(4094, 0x0001, 0x0000);
|
||||||
|
name_vlan(10, "lab");
|
||||||
|
name_vlan(4094, "top");
|
||||||
|
management_vlan = 10;
|
||||||
|
send_vlanlist();
|
||||||
|
CHECK(has("\"mgmt\":10"), "management VLAN");
|
||||||
|
CHECK(has("{\"id\":10,\"name\":\"lab\"}"), "VLAN 10 with its name");
|
||||||
|
CHECK(has("{\"id\":20,\"name\":\"\"}"), "VLAN 20 without a name");
|
||||||
|
CHECK(has("{\"id\":4094,\"name\":\"top\"}"), "VLAN 4094 is the last one listed");
|
||||||
|
CHECK(count("\"id\":") == 3, "and nothing else");
|
||||||
|
CHECK(balanced(), "valid JSON");
|
||||||
|
vlan_delete(20);
|
||||||
|
send_vlanlist();
|
||||||
|
CHECK(count("\"id\":") == 2 && !has("\"id\":20"), "a deleted VLAN drops out");
|
||||||
|
management_vlan = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t base_mac[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00 };
|
||||||
|
|
||||||
|
static void put(uint16_t idx, uint8_t last, uint16_t vid, uint8_t port, bool st)
|
||||||
|
{
|
||||||
|
uint8_t m[6];
|
||||||
|
memcpy(m, base_mac, 6);
|
||||||
|
m[5] = last;
|
||||||
|
hw_l2_put(idx, m, vid, port, st);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_l2(void)
|
||||||
|
{
|
||||||
|
printf("[test] /l2.json walks the table\n");
|
||||||
|
hw_reset(); out_reset();
|
||||||
|
put(0x010, 0x01, 1, 4, false);
|
||||||
|
put(0x020, 0x02, 2, CPU_PORT, true);
|
||||||
|
put(0x8f0, 0x03, 1, 7, false);
|
||||||
|
send_l2(0);
|
||||||
|
CHECK(count("\"mac\":") == 4, "three entries, and the first one again: that repeat is how the page sees the wrap");
|
||||||
|
CHECK(count("\"idx\":\"0010\"") == 2 && strstr(body(), "\"idx\":\"0010\"}]"), "the repeat closes the list");
|
||||||
|
CHECK(has("{\"vlan\":\"001\",\"mac\":\"00:11:22:33:44:01\",\"type\":\"l\",\"port\":4,\"lag\":0,\"idx\":\"0010\"}"), "learned entry, VLAN, port and index");
|
||||||
|
CHECK(has("\"mac\":\"00:11:22:33:44:02\",\"type\":\"s\",\"port\":9"), "static entry on the CPU port");
|
||||||
|
CHECK(has("\"idx\":\"08f0\""), "an index above 0x800 keeps its high bit");
|
||||||
|
CHECK(balanced(), "valid JSON");
|
||||||
|
|
||||||
|
out_reset();
|
||||||
|
send_l2(0x100);
|
||||||
|
const char *b = body();
|
||||||
|
CHECK(strstr(b, "44:03") && strstr(b, "44:03") < strstr(b, "44:01"), "starting at 0x100 lists 0x8f0 first and wraps");
|
||||||
|
CHECK(count("\"mac\":") == 4 && count("44:03") == 2, "and still finds all three before repeating 0x8f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk the table the way the page does: ask for the index after the last
|
||||||
|
* entry of each page until an index comes back that was seen before. */
|
||||||
|
static void t_l2_page(void)
|
||||||
|
{
|
||||||
|
printf("[test] /l2.json pages the way the web page walks it\n");
|
||||||
|
hw_reset(); out_reset();
|
||||||
|
for (int i = 0; i < 40; i++)
|
||||||
|
put(0x100 + i * 3, 0x10 + i, 1, i % 8, false);
|
||||||
|
uint8_t seen[4096 / 8] = { 0 };
|
||||||
|
int pages = 0, unique = 0, wrapped = 0, idx = 0, biggest = 0;
|
||||||
|
while (!wrapped && pages < 10) {
|
||||||
|
out_reset();
|
||||||
|
send_l2(idx);
|
||||||
|
pages++;
|
||||||
|
if (slen > TCP_OUTBUF_SIZE || !balanced())
|
||||||
|
break;
|
||||||
|
if ((int)slen > biggest)
|
||||||
|
biggest = slen;
|
||||||
|
int n = 0, last = -1;
|
||||||
|
for (const char *p = body(); (p = strstr(p, "\"idx\":\"")); p += 7) {
|
||||||
|
int v = (int)strtol(p + 7, 0, 16);
|
||||||
|
n++;
|
||||||
|
if (seen[v >> 3] & (1 << (v & 7))) { wrapped = 1; break; }
|
||||||
|
seen[v >> 3] |= 1 << (v & 7);
|
||||||
|
unique++;
|
||||||
|
last = v;
|
||||||
|
}
|
||||||
|
if (!n)
|
||||||
|
break;
|
||||||
|
idx = last + 1;
|
||||||
|
}
|
||||||
|
CHECK(wrapped, "the walk ends on a repeated index");
|
||||||
|
CHECK(unique == 40, "and has visited every entry once");
|
||||||
|
CHECK(pages == 2, "in two pages");
|
||||||
|
CHECK(biggest <= TCP_OUTBUF_SIZE, "no page outgrows outbuf");
|
||||||
|
CHECK(balanced(), "every page is valid JSON");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_status_counters(void)
|
||||||
|
{
|
||||||
|
printf("[test] /status.json prints 64-bit packet counters in full\n");
|
||||||
|
hw_reset(); out_reset();
|
||||||
|
hw_counter_set(0, STAT_COUNTER_TX_PKTS, 0x100000005ULL);
|
||||||
|
hw_counter_set(0, STAT_COUNTER_RX_PKTS, 0x00000000000000ffULL);
|
||||||
|
hw_counter_set(1, STAT_COUNTER_TX_PKTS, 0x00000001ffffffffULL);
|
||||||
|
send_status();
|
||||||
|
CHECK(has("\"txG\":\"0x100000005\""), "a counter past 2^32 keeps the zeros of its low word");
|
||||||
|
CHECK(has("\"rxG\":\"0xff\""), "a small counter stays short");
|
||||||
|
CHECK(has("\"txG\":\"0x1ffffffff\""), "a low word of all ones");
|
||||||
|
out_reset();
|
||||||
|
send_counters(1);
|
||||||
|
CHECK(has("\"0x100000005\"") && has("\"0x0\""), "/counters.json prints them the same way");
|
||||||
|
CHECK(slen <= TCP_OUTBUF_SIZE, "fits the buffer");
|
||||||
|
CHECK(balanced(), "valid JSON");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("== httpd/page_impl.c JSON tests ==\n");
|
||||||
|
t_vlan();
|
||||||
|
t_vlanlist();
|
||||||
|
t_l2();
|
||||||
|
t_l2_page();
|
||||||
|
t_status_counters();
|
||||||
|
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
|
||||||
|
return tests_failed ? 1 : 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* test_port_tables.c - rtl837x_port.c against the simulated table engine.
|
||||||
|
*
|
||||||
|
* What the firmware writes to the VLAN and L2 tables is checked against an
|
||||||
|
* independent statement of the entry layout (hw_mock.h), and what it reads
|
||||||
|
* back is checked against what it wrote. The module is compiled unmodified.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_regs.h"
|
||||||
|
#include "rtl837x_port.h"
|
||||||
|
#include "machine.h"
|
||||||
|
#include "support.h"
|
||||||
|
#include "hw_mock.h"
|
||||||
|
|
||||||
|
extern struct machine_runtime machine_detected;
|
||||||
|
|
||||||
|
/* VLAN entry as vlan_create() lays it out: bit 25 valid, bits 0-9 members,
|
||||||
|
* bits 10-19 the untag set, which is every port not in the tagged set (the
|
||||||
|
* bit of a non-member is meaningless to the switch and stays set). */
|
||||||
|
static uint32_t vlan_word(uint16_t members, uint16_t tagged)
|
||||||
|
{
|
||||||
|
return (1u << 25) | ((uint32_t)(~tagged & 0x3ff) << 10) | members;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_vlan_roundtrip(void)
|
||||||
|
{
|
||||||
|
printf("[test] VLAN entry: create, read back, delete\n");
|
||||||
|
hw_reset(); out_reset();
|
||||||
|
vlan_settings.vlan = 10;
|
||||||
|
vlan_settings.members = 0x0015; /* ports 1, 3, 5 */
|
||||||
|
vlan_settings.tagged = 0x0004; /* port 3 tagged */
|
||||||
|
vlan_create();
|
||||||
|
/* the CPU port is always a tagged member */
|
||||||
|
CHECK(hw_vlan_word(10) == vlan_word(0x0015 | 0x0200, 0x0004 | 0x0200), "vlan 10 entry has the documented layout");
|
||||||
|
CHECK(hw_vlan_word(11) == 0, "the neighbouring entry is untouched");
|
||||||
|
|
||||||
|
uint32_t w = hw_vlan_word(10);
|
||||||
|
CHECK(vlan_get(10) == 0, "vlan_get finds it");
|
||||||
|
CHECK(((uint32_t)sfr_data[0] << 24 | (uint32_t)sfr_data[1] << 16 | (uint32_t)sfr_data[2] << 8 | sfr_data[3]) == w,
|
||||||
|
"and returns the word that was written");
|
||||||
|
CHECK(sfr_data[0] & 0x02, "with the valid bit the JSON generators test for");
|
||||||
|
|
||||||
|
unsigned long r = hw_reads;
|
||||||
|
CHECK(vlan_get(4095) == -1, "VLAN 4095 is refused");
|
||||||
|
CHECK(hw_reads == r, "without touching the engine");
|
||||||
|
|
||||||
|
vlan_delete(10);
|
||||||
|
CHECK(hw_vlan_word(10) == 0, "vlan_delete clears the entry");
|
||||||
|
vlan_delete(0);
|
||||||
|
vlan_delete(4095);
|
||||||
|
CHECK(hw_vlan_word(0) == 0 && hw_vlan_word(4095) == 0, "VLAN 0 and 4095 cannot be deleted");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_vlan_rtl8372(void)
|
||||||
|
{
|
||||||
|
printf("[test] VLAN entry on an RTL8372: ports 0-2 are not there\n");
|
||||||
|
hw_reset();
|
||||||
|
machine_detected.isRTL8373 = 0;
|
||||||
|
vlan_settings.vlan = 20;
|
||||||
|
vlan_settings.members = 0x03ff;
|
||||||
|
vlan_settings.tagged = 0x0000;
|
||||||
|
vlan_create();
|
||||||
|
uint32_t w = hw_vlan_word(20);
|
||||||
|
CHECK(((w >> 10) & 0x7) == 0, "the untagged bits of ports 0-2 stay clear");
|
||||||
|
CHECK((w & 0x3ff) == 0x03ff, "the member bits are what was asked for");
|
||||||
|
machine_detected.isRTL8373 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_pvid(void)
|
||||||
|
{
|
||||||
|
printf("[test] PVID: two ports share one register\n");
|
||||||
|
hw_reset();
|
||||||
|
port_pvid_set(2, 100);
|
||||||
|
port_pvid_set(3, 4094);
|
||||||
|
CHECK(port_pvid_get(2) == 100, "even port reads back");
|
||||||
|
CHECK(port_pvid_get(3) == 4094, "odd port reads back");
|
||||||
|
port_pvid_set(3, 7);
|
||||||
|
CHECK(port_pvid_get(2) == 100, "writing the odd port leaves the even one alone");
|
||||||
|
CHECK(port_pvid_get(3) == 7, "and takes the new value");
|
||||||
|
port_pvid_set(2, 4001);
|
||||||
|
CHECK(port_pvid_get(3) == 7, "writing the even port leaves the odd one alone");
|
||||||
|
CHECK(port_pvid_get(8) == 0, "an untouched port reads 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_l2mc(void)
|
||||||
|
{
|
||||||
|
printf("[test] static multicast entry steering a group to the CPU\n");
|
||||||
|
hw_reset();
|
||||||
|
port_l2mc_set(0x0e, 2, PMASK_CPU);
|
||||||
|
const uint8_t mac[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e };
|
||||||
|
const struct hw_l2 *e = hw_l2_find(mac, 2);
|
||||||
|
CHECK(e != 0, "the entry exists for 01:80:c2:00:00:0e in VLAN 2");
|
||||||
|
if (e) {
|
||||||
|
uint8_t m[6]; uint16_t vid, pm; bool valid, st, mc;
|
||||||
|
hw_l2_decode(e, m, &vid, &pm, &valid, &st, &mc);
|
||||||
|
CHECK(valid, "valid");
|
||||||
|
CHECK(mc, "multicast");
|
||||||
|
CHECK(pm == PMASK_CPU, "member mask is the CPU port alone");
|
||||||
|
}
|
||||||
|
port_l2mc_set(0x0e, 2, PMASK_CPU | 0x0003);
|
||||||
|
e = hw_l2_find(mac, 2);
|
||||||
|
CHECK(hw_l2_count() == 1, "writing the same key again replaces, not adds");
|
||||||
|
if (e) {
|
||||||
|
uint8_t m[6]; uint16_t vid, pm; bool valid, st, mc;
|
||||||
|
hw_l2_decode(e, m, &vid, &pm, &valid, &st, &mc);
|
||||||
|
CHECK(pm == (PMASK_CPU | 0x0003), "with the new mask, low bits included");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_static_mgmt(void)
|
||||||
|
{
|
||||||
|
printf("[test] the management MAC pinned to the CPU port\n");
|
||||||
|
hw_reset();
|
||||||
|
uint8_t mac[6] = { 0x02, 0x11, 0x22, 0x33, 0x44, 0x55 };
|
||||||
|
port_l2_static_mgmt(mac, 2, false);
|
||||||
|
const struct hw_l2 *e = hw_l2_find(mac, 2);
|
||||||
|
CHECK(e != 0, "entry present in VLAN 2");
|
||||||
|
if (e) {
|
||||||
|
uint8_t m[6]; uint16_t vid, p; bool valid, st, mc;
|
||||||
|
hw_l2_decode(e, m, &vid, &p, &valid, &st, &mc);
|
||||||
|
CHECK(valid && st && !mc, "valid, static, unicast");
|
||||||
|
CHECK(p == CPU_PORT, "on the CPU port");
|
||||||
|
}
|
||||||
|
port_l2_static_mgmt(mac, 0, false);
|
||||||
|
CHECK(hw_l2_find(mac, 1) != 0, "management VLAN 0 means VLAN 1");
|
||||||
|
port_l2_static_mgmt(mac, 2, true);
|
||||||
|
CHECK(hw_l2_find(mac, 2) == 0, "removal deletes the VLAN 2 entry");
|
||||||
|
CHECK(hw_l2_find(mac, 1) != 0, "and leaves the other one");
|
||||||
|
port_l2_static_mgmt(mac, 3, true);
|
||||||
|
CHECK(hw_l2_count() == 1, "removing an entry that is not there changes nothing");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_flush(void)
|
||||||
|
{
|
||||||
|
printf("[test] flushing a port forgets its learned entries only\n");
|
||||||
|
hw_reset();
|
||||||
|
const uint8_t a[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x01 };
|
||||||
|
const uint8_t b[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x02 };
|
||||||
|
const uint8_t c[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x03 };
|
||||||
|
hw_l2_put(0x010, a, 1, 4, false);
|
||||||
|
hw_l2_put(0x020, b, 1, 4, true);
|
||||||
|
hw_l2_put(0x030, c, 1, 5, false);
|
||||||
|
port_l2_forget_port(4);
|
||||||
|
CHECK(hw_l2_find(a, 1) == 0, "learned entry on port 5 (index 4) gone");
|
||||||
|
CHECK(hw_l2_find(b, 1) != 0, "static entry on the same port stays");
|
||||||
|
CHECK(hw_l2_find(c, 1) != 0, "entry on another port stays");
|
||||||
|
port_l2_forget();
|
||||||
|
CHECK(hw_l2_find(c, 1) == 0 && hw_l2_find(b, 1) != 0, "forget-all drops every learned entry and keeps the static one");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_lag(void)
|
||||||
|
{
|
||||||
|
printf("[test] trunk membership and its hash seed\n");
|
||||||
|
hw_reset();
|
||||||
|
port_lag_members_set(1, 0x0180);
|
||||||
|
CHECK(port_lag_members_get(1) == 0x0180, "members read back");
|
||||||
|
CHECK(port_lag_of(7) == 1 && port_lag_of(8) == 1, "both ports belong to group 2");
|
||||||
|
CHECK(port_lag_of(0) == PORT_LAG_NONE, "a port outside is in no group");
|
||||||
|
CHECK((hw_reg_get(RTL837X_TRK_HASH_CTRL_BASE + 4) & 0xff) == LAG_HASH_DEFAULT, "an unset hash gets the default");
|
||||||
|
hw_reg_set(RTL837X_TRK_HASH_CTRL_BASE + 8, 0x06);
|
||||||
|
port_lag_members_set(2, 0x0060);
|
||||||
|
CHECK((hw_reg_get(RTL837X_TRK_HASH_CTRL_BASE + 8) & 0xff) == 0x06, "a hash already set is kept");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("== rtl837x_port.c table tests ==\n");
|
||||||
|
t_vlan_roundtrip();
|
||||||
|
t_vlan_rtl8372();
|
||||||
|
t_pvid();
|
||||||
|
t_l2mc();
|
||||||
|
t_static_mgmt();
|
||||||
|
t_flush();
|
||||||
|
t_lag();
|
||||||
|
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
|
||||||
|
return tests_failed ? 1 : 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* test_tick_gate.c - the timers of the main loop keep time by the system
|
||||||
|
* tick, however often the loop passes. The gate is the TICKS_DUE macro from
|
||||||
|
* rtl837x_common.h; the loop bodies of idle() and handle_tx() are restated
|
||||||
|
* here, so this checks the arithmetic, not those functions.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "rtl837x_common.h"
|
||||||
|
#include "rtl837x_stp.h"
|
||||||
|
#include "support.h"
|
||||||
|
|
||||||
|
volatile uint32_t ticks;
|
||||||
|
|
||||||
|
#define STP_TICK_STEP (SYS_TICK_HZ / STP_HZ)
|
||||||
|
#define STP_CATCH_UP 8
|
||||||
|
|
||||||
|
static uint8_t stp_tick_last, tx_tick_last;
|
||||||
|
static unsigned stp_calls, tx_calls;
|
||||||
|
|
||||||
|
/* One pass of the loop: the STP block of idle() and the gate of handle_tx() */
|
||||||
|
static void pass(void)
|
||||||
|
{
|
||||||
|
uint8_t n = STP_CATCH_UP;
|
||||||
|
while (n-- && TICKS_DUE(stp_tick_last, STP_TICK_STEP)) {
|
||||||
|
stp_tick_last += STP_TICK_STEP;
|
||||||
|
stp_calls++;
|
||||||
|
}
|
||||||
|
if (TICKS_DUE(tx_tick_last, 1)) {
|
||||||
|
tx_tick_last = (uint8_t)ticks;
|
||||||
|
tx_calls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run `seconds` of wall clock with one pass every `pass_us` microseconds. */
|
||||||
|
static void run(double pass_us, unsigned seconds)
|
||||||
|
{
|
||||||
|
double t = 0, next_tick = 0, tick_us = 1e6 / SYS_TICK_HZ, end = seconds * 1e6;
|
||||||
|
ticks = 0;
|
||||||
|
stp_tick_last = tx_tick_last = 0;
|
||||||
|
stp_calls = tx_calls = 0;
|
||||||
|
while (t < end) {
|
||||||
|
while (next_tick <= t) { ticks++; next_tick += tick_us; }
|
||||||
|
pass();
|
||||||
|
t += pass_us;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_rates(void)
|
||||||
|
{
|
||||||
|
printf("[test] STP time follows the tick whatever the loop does\n");
|
||||||
|
run(5000, 10);
|
||||||
|
CHECK(stp_calls == 10 * STP_HZ, "one pass per tick: 500 STP steps in 10 s");
|
||||||
|
CHECK(tx_calls == 10 * SYS_TICK_HZ, "and 2000 TX periodics");
|
||||||
|
run(16000, 10);
|
||||||
|
CHECK(stp_calls >= 10 * STP_HZ - 1 && stp_calls <= 10 * STP_HZ, "a 16 ms pass, as under an IPv4 stream: still 500 (was 156 when the clock counted passes)");
|
||||||
|
CHECK(tx_calls == 625, "TX periodic once per pass when passes are slower than the tick");
|
||||||
|
run(600, 10);
|
||||||
|
CHECK(stp_calls == 10 * STP_HZ, "a 0.6 ms pass, the loop no longer sleeping: still 500 (was 4166)");
|
||||||
|
CHECK(tx_calls == 10 * SYS_TICK_HZ, "TX periodic capped at the tick rate");
|
||||||
|
run(1300000, 13);
|
||||||
|
CHECK(stp_calls <= 10 * STP_CATCH_UP, "a 1.3 s pass loses time instead of firing 65 steps at once");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void t_wrap(void)
|
||||||
|
{
|
||||||
|
printf("[test] the byte arithmetic survives the tick counter wrapping\n");
|
||||||
|
ticks = 0xfffffffeUL;
|
||||||
|
stp_tick_last = (uint8_t)ticks;
|
||||||
|
stp_calls = 0;
|
||||||
|
for (int i = 0; i < 8; i++) { ticks++; pass(); }
|
||||||
|
CHECK(stp_calls == 2, "two STP steps across 0xffffffff -> 0x00000006");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("== tick gate tests ==\n");
|
||||||
|
t_rates();
|
||||||
|
t_wrap();
|
||||||
|
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
|
||||||
|
return tests_failed ? 1 : 0;
|
||||||
|
}
|
||||||
@@ -318,7 +318,7 @@ int main(int argc, char **argv)
|
|||||||
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, "#include <stdint.h>\n\n");
|
||||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p,
|
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");
|
"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 uint8_t gzip;\n};\n\n");
|
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "struct f_data {\n __code const char *file;\n uint32_t start;\n uint16_t len;\n mime_type_t mime;\n uint8_t gzip;\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, "typedef uint16_t (* fcall_ptr)(void);\n\n");
|
||||||
|
|
||||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "// This file is automatically generated, do not edit!\n\n");
|
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "// This file is automatically generated, do not edit!\n\n");
|
||||||
@@ -326,9 +326,9 @@ int main(int argc, char **argv)
|
|||||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#include \"%s.h\"\n\n", arguments.prefix);
|
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#include \"%s.h\"\n\n", arguments.prefix);
|
||||||
if (arguments.bank)
|
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, "#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"
|
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " __code const char * __code const 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");
|
" \"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, "__code struct f_data f_data[] = {\n");
|
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "__code const 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
|
// Now that the beginning of the buffer is filled with out image, optionally resize the image
|
||||||
|
|||||||
@@ -95,6 +95,9 @@
|
|||||||
#endif /* UIP_CONF_IPV6 */
|
#endif /* UIP_CONF_IPV6 */
|
||||||
|
|
||||||
#include "../rtl837x_common.h"
|
#include "../rtl837x_common.h"
|
||||||
|
#include "../rtl837x_regs.h"
|
||||||
|
|
||||||
|
extern __xdata uint8_t rx_headers[16];
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
/* Variable definitions. */
|
/* Variable definitions. */
|
||||||
@@ -1120,6 +1123,12 @@ uip_process(u8_t flag) __banked
|
|||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
#else /* UIP_UDP_CHECKSUMS */
|
#else /* UIP_UDP_CHECKSUMS */
|
||||||
|
if (rx_headers[1] & RX_TAG_L4_CSUM_BAD) {
|
||||||
|
UIP_STAT(++uip_stat.udp.drop);
|
||||||
|
UIP_STAT(++uip_stat.udp.chkerr);
|
||||||
|
UIP_LOG("udp: bad checksum.");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
uip_len = uip_len - UIP_IPUDPH_LEN;
|
uip_len = uip_len - UIP_IPUDPH_LEN;
|
||||||
#endif /* UIP_UDP_CHECKSUMS */
|
#endif /* UIP_UDP_CHECKSUMS */
|
||||||
|
|
||||||
@@ -1200,15 +1209,12 @@ uip_process(u8_t flag) __banked
|
|||||||
|
|
||||||
/* Start of TCP input header processing code. */
|
/* Start of TCP input header processing code. */
|
||||||
|
|
||||||
// BUG: We need to reimplement this with RTL837x TCP checksum checking
|
if (rx_headers[1] & RX_TAG_L4_CSUM_BAD) {
|
||||||
// i.e. figure out which bit in the RX-tag states the checksum is correct
|
UIP_STAT(++uip_stat.tcp.drop);
|
||||||
// if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
|
UIP_STAT(++uip_stat.tcp.chkerr);
|
||||||
// checksum. */
|
UIP_LOG("tcp: bad checksum.");
|
||||||
// UIP_STAT(++uip_stat.tcp.drop);
|
goto drop;
|
||||||
// UIP_STAT(++uip_stat.tcp.chkerr);
|
}
|
||||||
// UIP_LOG("tcp: bad checksum.");
|
|
||||||
// goto drop;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
/* Demultiplex this segment. */
|
/* Demultiplex this segment. */
|
||||||
|
|||||||
@@ -912,8 +912,8 @@ __xdata struct uip_udp_conn *uip_udp_new(__xdata uip_ipaddr_t * __xdata ripaddr,
|
|||||||
((__xdata u16_t *)addr1)[1] == ((__xdata u16_t *)addr2)[1])
|
((__xdata u16_t *)addr1)[1] == ((__xdata u16_t *)addr2)[1])
|
||||||
#define uip_ipaddr_cmpx(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__xdata u16_t *)addr2)[0] && \
|
#define uip_ipaddr_cmpx(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__xdata u16_t *)addr2)[0] && \
|
||||||
((__xdata u16_t *)addr1)[1] == ((__xdata u16_t *)addr2)[1])
|
((__xdata u16_t *)addr1)[1] == ((__xdata u16_t *)addr2)[1])
|
||||||
#define uip_ipaddr_cmpc(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__code u16_t *)addr2)[0] && \
|
#define uip_ipaddr_cmpc(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__code const u16_t *)addr2)[0] && \
|
||||||
((__xdata u16_t *)addr1)[1] == ((__code u16_t *)addr2)[1])
|
((__xdata u16_t *)addr1)[1] == ((__code const u16_t *)addr2)[1])
|
||||||
#else /* !UIP_CONF_IPV6 */
|
#else /* !UIP_CONF_IPV6 */
|
||||||
#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
|
#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
|
||||||
#endif /* !UIP_CONF_IPV6 */
|
#endif /* !UIP_CONF_IPV6 */
|
||||||
|
|||||||