Merge upstream/main into the Spanning Tree branch

Only httpd.c conflicted: main added the buffered configuration upload
next to the pointers this branch had moved into xdata to free internal
RAM. Both belong, so the new globals sit above declarations that keep
their storage class.
This commit is contained in:
d00f
2026-08-25 23:28:09 +02:00
10 changed files with 384 additions and 120 deletions
+25 -14
View File
@@ -759,18 +759,25 @@ void parse_mtu(void)
write_char('\n'); write_char('\n');
} }
void sfp_print_measurements(uint8_t sfp) bool sfp_print_measurements(uint8_t sfp)
{ {
print_string("Options: "); print_byte(sfp_read_reg(sfp, 92)); write_char('\n'); if (!sfp_read_block(sfp, 92, 1))
return false;
print_string("Options: "); print_byte(sfp_buf[0]); write_char('\n');
if (!(sfp_options[sfp] & 0x40)) if (!(sfp_options[sfp] & 0x40))
return; return true;
print_string("Temp: "); print_byte(sfp_read_reg(sfp, 224)); print_byte(sfp_read_reg(sfp, 225)); write_char('\n'); if (!sfp_read_block(sfp, 224, 16))
print_string("Vcc: "); print_byte(sfp_read_reg(sfp, 226)); print_byte(sfp_read_reg(sfp, 227)); write_char('\n'); return false;
print_string("TX Bias: "); print_byte(sfp_read_reg(sfp, 228)); print_byte(sfp_read_reg(sfp, 229)); write_char('\n'); print_string("Temp: "); print_byte(sfp_buf[0]); print_byte(sfp_buf[1]); write_char('\n');
print_string("TX Power: "); print_byte(sfp_read_reg(sfp, 230)); print_byte(sfp_read_reg(sfp, 231)); write_char('\n'); print_string("Vcc: "); print_byte(sfp_buf[2]); print_byte(sfp_buf[3]); write_char('\n');
print_string("RX Power: "); print_byte(sfp_read_reg(sfp, 232)); print_byte(sfp_read_reg(sfp, 233)); write_char('\n'); print_string("TX Bias: "); print_byte(sfp_buf[4]); print_byte(sfp_buf[5]); write_char('\n');
print_string("Laser: "); print_byte(sfp_read_reg(sfp, 234)); print_byte(sfp_read_reg(sfp, 235)); write_char('\n'); print_string("TX Power: "); print_byte(sfp_buf[6]); print_byte(sfp_buf[7]); write_char('\n');
print_string("State: "); print_byte(sfp_read_reg(sfp, 238)); write_char('\n'); print_string("RX Power: "); print_byte(sfp_buf[8]); print_byte(sfp_buf[9]); write_char('\n');
print_string("Laser: "); print_byte(sfp_buf[10]); print_byte(sfp_buf[11]); write_char('\n');
print_string("State: "); print_byte(sfp_buf[14]); write_char('\n');
return true;
} }
@@ -788,11 +795,15 @@ void parse_sfp(void)
print_string(" - empty\n"); print_string(" - empty\n");
continue; continue;
} }
print_string(" - Rate: "); print_byte(sfp_read_reg(slot, 12)); if (!sfp_read_block(slot, 11, 2)) {
print_string(" Encoding: "); print_byte(sfp_read_reg(slot, 11)); print_string(" - I2C read failed on this slot\n");
continue;
}
print_string(" - Rate: "); print_byte(sfp_buf[1]);
print_string(" Encoding: "); print_byte(sfp_buf[0]);
write_char('\n'); write_char('\n');
sfp_print_info(slot); if (!sfp_print_info(slot) || !sfp_print_measurements(slot))
sfp_print_measurements(slot); print_string("I2C read failed on this slot\n");
} }
return; return;
} }
+99 -5
View File
@@ -42,6 +42,15 @@ __xdata uint32_t cont_addr;
// HTTP header properties // HTTP header properties
__xdata uint8_t boundary[72]; __xdata uint8_t boundary[72];
// a client may split the request anywhere, including inside a boundary or a
// part header, so a configuration upload is parsed only once it is complete;
// sized for a full config sector plus the multipart framing around it
#define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384)
__xdata uint8_t config_upload;
__xdata uint8_t config_buf[CONFIG_UPLOAD_BUF];
__xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
__xdata uint8_t cfg_bl;
__xdata uint8_t * __xdata content_type = 0; __xdata uint8_t * __xdata content_type = 0;
__xdata uint8_t * __xdata session = 0; __xdata uint8_t * __xdata session = 0;
@@ -78,6 +87,7 @@ inline uint8_t is_separator(uint8_t c)
void httpd_init(void) __banked void httpd_init(void) __banked
{ {
config_upload = 0; // xdata is not zeroed by the startup code
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate); __xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
// Start listening to port 80 // Start listening to port 80
uip_listen(HTONS(80)); uip_listen(HTONS(80));
@@ -316,6 +326,65 @@ void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes)
} }
/* 0: body incomplete, 1: configuration stored, 2: malformed */
static uint8_t config_take(void)
{
cfg_bl = strlen_x(boundary);
// the body is complete once the closing boundary has arrived
cfg_last = 0;
while (1) {
if (cfg_last + cfg_bl + 1 >= write_len)
return 0;
if (strstart_x(&config_buf[cfg_last], boundary)
&& strstart(&config_buf[cfg_last + cfg_bl], "--"))
break;
cfg_last++;
}
// every part lies ahead of the closing boundary, so it bounds the walk
cfg_pos = 0;
while (cfg_pos < cfg_last) {
if (!strstart_x(&config_buf[cfg_pos], boundary)) {
cfg_pos++;
continue;
}
cfg_hdr = cfg_pos + cfg_bl;
cfg_body = cfg_hdr;
while (1) {
if (cfg_body + 3 >= cfg_last)
return 2;
if (strstart(&config_buf[cfg_body], "\r\n\r\n"))
break;
cfg_body++;
}
cfg_end = cfg_body;
cfg_body += 4;
// reaching cfg_last is a match: the last part ends at the closing boundary
while (cfg_end < cfg_last && !strstart_x(&config_buf[cfg_end], boundary))
cfg_end++;
while (cfg_hdr + 8 < cfg_body) {
// the part carrying a filename holds the configuration
if (strstart(&config_buf[cfg_hdr], "filename")) {
// the payload plus its terminator must fit the sector
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
return 2;
config_buf[cfg_end] = 0;
flash_region.addr = CONFIG_START;
flash_sector_erase();
flash_region.addr = CONFIG_START;
flash_region.len = cfg_end - cfg_body + 1;
flash_write_bytes(config_buf + cfg_body);
return 1;
}
cfg_hdr++;
}
cfg_pos = cfg_end;
}
return 2;
}
/* /*
* Reads post data from the http stream and writes it into flash memory * Reads post data from the http stream and writes it into flash memory
* Input: the current position in the TCP buffer (uip_appdata) * Input: the current position in the TCP buffer (uip_appdata)
@@ -438,6 +507,7 @@ void handle_post(void)
return; return;
} }
print_string("Firmware upload started."); print_string("Firmware upload started.");
config_upload = 0;
uptr = FIRMWARE_UPLOAD_START; uptr = FIRMWARE_UPLOAD_START;
verify_crc = 1; verify_crc = 1;
max_upload = 1024576; max_upload = 1024576;
@@ -446,12 +516,10 @@ void handle_post(void)
send_unauthorized(); send_unauthorized();
return; return;
} }
dbg_string("Configuration upload, erasing config mem!\n"); dbg_string("Configuration upload\n");
uptr = CONFIG_START;
verify_crc = 0; verify_crc = 0;
max_upload = 2048; config_upload = 1;
flash_region.addr = CONFIG_START; write_len = 0;
flash_sector_erase();
} }
// Check for other POST requests, which are not multipart, below // Check for other POST requests, which are not multipart, below
} else { } else {
@@ -505,6 +573,32 @@ void handle_post(void)
send_bad_request(); send_bad_request();
return; return;
} }
if (config_upload) {
cfg_pos = uip_len - (p - uip_appdata);
if (write_len + cfg_pos >= CONFIG_UPLOAD_BUF) {
print_string("Configuration too large, aborting.\n");
config_upload = 0;
s->tstate = TSTATE_NONE;
send_bad_request();
return;
}
memcpy(config_buf + write_len, p, cfg_pos);
write_len += cfg_pos;
uint8_t taken = config_take();
if (!taken) {
s->tstate = TSTATE_MULTIPART;
return;
}
config_upload = 0;
s->tstate = TSTATE_NONE;
if (taken == 2) {
send_bad_request();
return;
}
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
return;
}
// We skip the intial parts as part of the header // We skip the intial parts as part of the header
do { do {
p = skip_boundary(p); p = skip_boundary(p);
+9 -29
View File
@@ -178,10 +178,12 @@ void reg_to_html_long(register uint16_t reg)
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
for (uint8_t i = 20; i < 60; i++) { for (uint8_t i = 16; i < 64; i++) {
if (i >= 36 && i < 40) // Skip Non-ASCII codes if (!(i & 0xf))
sfp_read_block(sfp, i, 16);
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
continue; continue;
uint8_t c = sfp_read_reg(sfp, i); uint8_t c = sfp_buf[i & 0xf];
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
char_to_html(c); char_to_html(c);
} }
@@ -194,32 +196,10 @@ void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
if (len > 16) if (len > 16)
return; return;
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address sfp_read_block(slot, reg, len);
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
}
reg_read_m(RTL837X_REG_I2C_CTRL); for (uint8_t i = 0; i < len; i++)
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2); byte_to_html(sfp_buf[i]);
reg_write_m(RTL837X_REG_I2C_CTRL);
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
// Execute I2C Read
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
// Wait for execution to finish
do {
reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1);
for (uint8_t i = 0; i < len; i++) {
if (!(i & 0x3))
reg_read_m(RTL837X_REG_I2C_OUT + i);
byte_to_html(sfr_data[3 - (i & 0x3)]);
}
} }
@@ -936,7 +916,7 @@ found_end:
if (valid_len > (TCP_OUTBUF_SIZE - slen)) { if (valid_len > (TCP_OUTBUF_SIZE - slen)) {
cont_len = valid_len - (TCP_OUTBUF_SIZE - slen); cont_len = valid_len - (TCP_OUTBUF_SIZE - slen);
valid_len = TCP_OUTBUF_SIZE - slen; valid_len = TCP_OUTBUF_SIZE - slen;
cont_addr = valid_len; cont_addr = CONFIG_START + valid_len;
} }
flash_region.addr = CONFIG_START; flash_region.addr = CONFIG_START;
+81
View File
@@ -444,6 +444,87 @@ __code const struct machine machine = {
}; };
void machine_custom_init(void) { } void machine_custom_init(void) { }
#elif defined MACHINE_PCB_SWTG018AS_V2_1_0 // Sold as Sodola SL902 / Horaco "SWTGW218AS"; the SWTGW218AS label also covers other PCBs with different SFP and LED wiring (see MACHINE_SWTGW218AS)
__code const struct machine machine = {
.machine_name = "SWTGW218AS (SWTG018AS-V2.1.0)",
.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 = GPIO38, // pulled low on module insert
.sfp_port[0].pin_los = GPIO_NA, // no LOS pin wired
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
// LED wiring matches the SWTG018AS-A V2.0 (same PCB family)
.led_sets = {
{ /* RJ45: First LED, yellow, second LED: green */
LEDS_2G5 | LEDS_LINK,
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
}, { /* SFP set (superseded by the raw register override in machine_custom_init) */
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0,
0,
0,
}},
.led_mux_custom = 1,
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
0x09, 0x0c, 0x09, 0x0d, 0x10, // 65e4
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
0x1d, 0x20, 0x21 },
};
// The LED-set encoding cannot express this board's bi-color SFP LED (green <= 2.5G,
// blue at 10G), so program the LED register block with the values the stock firmware
// uses. Runs after leds_setup() and overrides the values computed there.
// The final entry routes the blue-LED pin to the LED controller via PIN_MUX_0;
// as a GPIO (the default) no LED register can light it. PIN_MUX_1/2 stay
// untouched so SFP detect (GPIO38) and i2c remain GPIOs.
static __code const struct { uint16_t reg; uint32_t val; } custom_init_regs[] = {
{ 0x6520, 0x0023e430UL }, // LED_MODE
{ 0x6524, 0xff001400UL }, // LED3_0_SET3
{ 0x6528, 0x00100000UL }, // LED3_0_SET1
{ 0x652c, 0x007f013fUL }, // LED3_2_SET3
{ 0x6530, 0x02000400UL }, // LED1_0_SET3
{ 0x6534, 0x01400141UL }, // LED3_2_SET2
{ 0x6538, 0x01440170UL }, // LED1_0_SET2
{ 0x653c, 0x18000041UL }, // LED3_2_SET1
{ 0x6540, 0x01400155UL }, // LED1_0_SET1
{ 0x6544, 0x01411000UL }, // LED3_2_SET0
{ 0x6548, 0x01740141UL }, // LED1_0_SET0
{ 0x654c, 0x00010000UL }, // LED_PORT_SET_SEL
{ 0x65d8, 0x3ffb6dffUL }, // LED_GLB_ACTIVE
{ 0x65dc, 0x7f24977fUL }, // LED_GLB_IO_EN
{ 0x65e0, 0x08144040UL }, // LED_GLB_MUX_1
{ 0x65e4, 0x10349309UL }, // LED_GLB_MUX_2
{ 0x65e8, 0x12454391UL }, // LED_GLB_MUX_3
{ 0x65ec, 0x19616555UL }, // LED_GLB_MUX_4
{ 0x65f0, 0x1c79d65aUL }, // LED_GLB_MUX_5
{ 0x65f4, 0x0002181dUL }, // LED_GLB_MUX_6
{ 0x7f8c, 0x20db6880UL }, // PIN_MUX_0
};
void machine_custom_init(void) {
uint8_t i;
// REG_SET is a multi-statement macro without a do-while wrapper: braces required
for (i = 0; i < sizeof(custom_init_regs) / sizeof(custom_init_regs[0]); i++) {
REG_SET(custom_init_regs[i].reg, custom_init_regs[i].val);
}
}
#elif defined MACHINE_LIANGUO_ZX_SWTGW215AS // Has PCB branded PCB-SWTG115AS-V2.0 but is labeled and reports as a ZX-SWTGW215AS, seems to be identical to the "real" ZX-SWTGW215AS except for the LEDs #elif defined MACHINE_LIANGUO_ZX_SWTGW215AS // Has PCB branded PCB-SWTG115AS-V2.0 but is labeled and reports as a ZX-SWTGW215AS, seems to be identical to the "real" ZX-SWTGW215AS except for the LEDs
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "Lianguo ZX-SWTGW215AS", .machine_name = "Lianguo ZX-SWTGW215AS",
+1
View File
@@ -18,6 +18,7 @@
// #define MACHINE_HG0402XG_V1_1 // #define MACHINE_HG0402XG_V1_1
// #define MACHINE_SWTG018AS_A_V_2_0 // #define MACHINE_SWTG018AS_A_V_2_0
// #define MACHINE_SWTGW218AS // #define MACHINE_SWTGW218AS
// #define MACHINE_PCB_SWTG018AS_V2_1_0
// #define MACHINE_PCB_K0402WS_V3 // #define MACHINE_PCB_K0402WS_V3
// #define MACHINE_K0501W_V2_0 // #define MACHINE_K0501W_V2_0
// #define MACHINE_LIANGUO_ZX_SWTGW215AS // #define MACHINE_LIANGUO_ZX_SWTGW215AS
+6 -2
View File
@@ -130,6 +130,7 @@ 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 char *p);
void print_string_newline_no_syslog(__code char *p);
void print_string(__code char *p); void print_string(__code 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);
@@ -154,7 +155,8 @@ void sleep(uint16_t t);
void write_char_no_syslog(char c); void write_char_no_syslog(char c);
void write_char(char c); void write_char(char c);
void print_reg(uint16_t reg); void print_reg(uint16_t reg);
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg); bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant;
extern __xdata uint8_t sfp_buf[16];
void reg_bit_set(uint16_t reg_addr, char bit); void reg_bit_set(uint16_t reg_addr, char bit);
void reg_bit_clear(uint16_t reg_addr, char bit); void reg_bit_clear(uint16_t reg_addr, char bit);
uint8_t reg_bit_test(uint16_t reg_addr, char bit); uint8_t reg_bit_test(uint16_t reg_addr, char bit);
@@ -169,11 +171,13 @@ uint16_t strlen_x(register __xdata const char *s);
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s); uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s);
uint16_t strcpy(register __xdata uint8_t *dst, register const char *s); uint16_t strcpy(register __xdata uint8_t *dst, register const char *s);
char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b); char strcmp(register __xdata const uint8_t *a, register __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);
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 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);
void sfp_print_info(uint8_t sfp); bool sfp_print_info(uint8_t sfp);
bool gpio_pin_test(uint8_t pin); bool gpio_pin_test(uint8_t pin);
void set_sys_led_state(uint8_t state); void set_sys_led_state(uint8_t state);
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg); void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
+58
View File
@@ -1,6 +1,11 @@
#include "rtl837x_pins.h" #include "rtl837x_pins.h"
#include "rtl837x_common.h" #include "rtl837x_common.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h" #include "rtl837x_regs.h"
#include "machine.h"
extern __code const struct machine machine;
extern __xdata uint8_t sfr_data[4];
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked { uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked {
@@ -119,3 +124,56 @@ void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) __banked{
reg_bit_set(gpio_direction_reg(pin), (pin % 32)); reg_bit_set(gpio_direction_reg(pin), (pin % 32));
} }
/*
* Read up to 16 consecutive registers of the EEPROM via I2C into sfp_buf
*/
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
{
uint8_t dev;
uint8_t val;
len--;
if (len > 15)
return false;
dev = (reg & 0x80) ? 0x51 : 0x50; // 0x51 holds the diagnostics, 0x50 the module data
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
(dev >> 5) | i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5
| i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2,
((dev << 3) & 0xff) | 0x1);
do {
reg_read(RTL837X_REG_I2C_CTRL);
} while (SFR_DATA_0 & 0x1);
if (SFR_DATA_0 & 0x2)
return false;
for (uint8_t i = 0; i <= len; i++) {
switch (i & 0x3) {
case 0:
reg_read(RTL837X_REG_I2C_OUT + i);
val = SFR_DATA_0;
break;
case 1:
val = SFR_DATA_8;
break;
case 2:
val = SFR_DATA_16;
break;
default:
val = SFR_DATA_24;
break;
}
sfp_buf[i] = val;
}
return true;
}
+90 -55
View File
@@ -140,6 +140,7 @@ __xdata char sfp_module_vendor[2][17];
__xdata char sfp_module_model[2][17]; __xdata char sfp_module_model[2][17];
__xdata char sfp_module_serial[2][17]; __xdata char sfp_module_serial[2][17];
__xdata uint8_t sfp_options[2]; __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_speed[2]; __xdata uint8_t sfp_speed[2];
__xdata uint8_t sfp_quirks[2]; __xdata uint8_t sfp_quirks[2];
__xdata bool button_last; __xdata bool button_last;
@@ -292,6 +293,12 @@ void print_string_no_syslog(__code char *p)
write_char_no_syslog(*p++); write_char_no_syslog(*p++);
} }
void print_string_newline_no_syslog(__code char *p)
{
write_char_no_syslog('\n');
print_string_no_syslog(p);
}
void print_string_x(__xdata char *p) void print_string_x(__xdata char *p)
{ {
while (*p) while (*p)
@@ -363,6 +370,32 @@ char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b)
} }
/*
* True when b is a prefix of a. Unlike strcmp() the byte after the match is not
* compared, and unlike is_word_x() it need not be a separator.
*/
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b)
{
uint8_t i = 0;
while (b[i] && (b[i] == a[i]))
i++;
return !b[i];
}
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b)
{
uint8_t i = 0;
while (b[i] && (b[i] == a[i]))
i++;
return !b[i];
}
void print_short(uint16_t a) void print_short(uint16_t a)
{ {
// allocating the registers first improves the sdcc code here // allocating the registers first improves the sdcc code here
@@ -1061,37 +1094,6 @@ void sds_config(uint8_t sds, uint8_t mode)
} }
/*
* Read a register of the EEPROM via I2C
*/
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg)
{
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x50 >> 5, (0x50 << 3) & 0xff);
}
reg_read_m(RTL837X_REG_I2C_CTRL);
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2);
reg_write_m(RTL837X_REG_I2C_CTRL);
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
// Execute I2C Read
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
// Wait for execution to finish
do {
reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1);
reg_read_m(RTL837X_REG_I2C_OUT);
return sfr_data[3];
}
/* /*
* Adds TX Header to uip_buf and calls nic_tx_packet to send the packet * Adds TX Header to uip_buf and calls nic_tx_packet to send the packet
* over the wire * over the wire
@@ -1251,36 +1253,46 @@ static inline uint8_t sfp_rate_to_sds_config(register uint8_t rate)
} }
void sfp_print_info(uint8_t sfp) bool sfp_print_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
for (uint8_t i = 20; i < 60; i++) { for (uint8_t i = 16; i < 64; i++) {
if (i >= 36 && i < 40) // Skip Non-ASCII codes if (!(i & 0xf) && !sfp_read_block(sfp, i, 16))
return false;
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
continue; continue;
uint8_t c = sfp_read_reg(sfp, i); uint8_t c = sfp_buf[i & 0xf];
if (c) if (c)
write_char(c); write_char(c);
} }
print_string("\n"); print_string("\n");
return true;
} }
// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons // Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons
void sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant
{ {
dst[length] = '\0'; if (!sfp_read_block(sfp, start, length))
return false;
for (uint8_t i = 0; i < length; i++) dst[length] = '\0';
dst[i] = sfp_read_reg(sfp, start + i); memcpy(dst, sfp_buf, length);
while (length > 0 && dst[--length] == ' ') while (length > 0 && dst[--length] == ' ')
dst[length] = '\0'; dst[length] = '\0';
return true;
} }
void sfp_get_info(uint8_t sfp) bool sfp_get_info(uint8_t sfp)
{ {
sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16); if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16))
sfp_read_field(sfp_module_model[sfp], sfp, 40, 16); return false;
sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16); if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16))
return false;
return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16);
} }
void sfp_apply_quirks(uint8_t sfp) __reentrant void sfp_apply_quirks(uint8_t sfp) __reentrant
@@ -1299,7 +1311,7 @@ void sfp_apply_quirks(uint8_t sfp) __reentrant
if (!(sfp_options[sfp] & 0x40)) { if (!(sfp_options[sfp] & 0x40)) {
// The module reports that DDM is not implemented, but try a dummy read to confirm // The module reports that DDM is not implemented, but try a dummy read to confirm
// 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V // 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V
if (sfp_read_reg(sfp, 226) != 0xff) { if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) {
sfp_options[sfp] |= 0x40; sfp_options[sfp] |= 0x40;
} }
} }
@@ -1323,17 +1335,17 @@ void setup_sfp_gpio(void)
} }
} }
void handle_sfp(void) static bool sfp_module_read(uint8_t sfp)
{ {
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { uint8_t rate;
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
if (sfp_pins_last & (0x1 << (sfp << 2))) {
sfp_pins_last &= ~(0x01 << (sfp << 2));
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + 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 delay(100); // Delay, because some modules need time to wake up
uint8_t rate = sfp_read_reg(sfp, 12); if (!sfp_read_block(sfp, 11, 2))
return false;
rate = sfp_buf[1];
if (sfp_speed[sfp] == SFP_SPEED_100M) if (sfp_speed[sfp] == SFP_SPEED_100M)
rate = 0x1; rate = 0x1;
else if (sfp_speed[sfp] == SFP_SPEED_1G) else if (sfp_speed[sfp] == SFP_SPEED_1G)
@@ -1343,13 +1355,36 @@ void handle_sfp(void)
else if (sfp_speed[sfp] == SFP_SPEED_10G) else if (sfp_speed[sfp] == SFP_SPEED_10G)
rate = 0x69; rate = 0x69;
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored? print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
print_string(" Encoding: "); print_byte(sfp_read_reg(sfp, 11)); print_string(" Encoding: "); print_byte(sfp_buf[0]);
print_string(" Module: "); sfp_print_info(sfp); print_string(" Module: ");
if (!sfp_print_info(sfp))
return false;
print_string("\n"); print_string("\n");
sfp_options[sfp] = sfp_read_reg(sfp, 92);
sfp_get_info(sfp); if (!sfp_read_block(sfp, 92, 1))
return false;
sfp_options[sfp] = sfp_buf[0];
if (!sfp_get_info(sfp))
return false;
sfp_apply_quirks(sfp); sfp_apply_quirks(sfp);
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate)); sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
return true;
}
void handle_sfp(void)
{
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
if (sfp_pins_last & (0x1 << (sfp << 2))) {
sfp_pins_last &= ~(0x01 << (sfp << 2));
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
if (!sfp_module_read(sfp)) {
print_string("SFP: an I2C read failed, retrying on the next poll\n");
sfp_pins_last |= 0x01 << (sfp << 2);
}
} }
} else { } else {
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) { if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
+5 -5
View File
@@ -30,16 +30,16 @@ void syslog_start(void) __banked
uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]); uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]);
state.syslog_conn = uip_udp_new(&server_ip, HTONS(514)); state.syslog_conn = uip_udp_new(&server_ip, HTONS(514));
if (state.syslog_conn == 0) { if (state.syslog_conn == 0) {
print_string_no_syslog("Failed to create a new UDP client\n"); print_string_newline_no_syslog("Failed to create a new UDP client");
return; return;
} }
print_string_no_syslog("Started syslog to IP "); print_string_newline_no_syslog("Started syslog to IP ");
itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.'); itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.');
itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n'); itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n');
state.enabled = 1; state.enabled = 1;
} }
else { else {
print_string_no_syslog("Syslog is already running\n"); print_string_newline_no_syslog("Syslog is already running");
} }
} }
@@ -49,9 +49,9 @@ void syslog_stop(void) __banked
if (state.syslog_conn != 0) { if (state.syslog_conn != 0) {
uip_udp_remove(state.syslog_conn); uip_udp_remove(state.syslog_conn);
state.syslog_conn = 0; state.syslog_conn = 0;
print_string_no_syslog("Stopped syslog\n"); print_string_newline_no_syslog("Stopped syslog");
} else { } else {
print_string_no_syslog("Syslog is not running\n"); print_string_newline_no_syslog("Syslog is not running");
} }
} }
+1 -1
View File
@@ -234,7 +234,7 @@ __xdata struct uip_stats uip_stat;
#endif /* UIP_STATISTICS == 1 */ #endif /* UIP_STATISTICS == 1 */
#if UIP_LOGGING == 1 #if UIP_LOGGING == 1
#define UIP_LOG(m) print_string_no_syslog(m); #define UIP_LOG(m) print_string_newline_no_syslog(m);
#else #else
#define UIP_LOG(m) #define UIP_LOG(m)
#endif /* UIP_LOGGING == 1 */ #endif /* UIP_LOGGING == 1 */