diff --git a/cmd_parser.c b/cmd_parser.c index 6f631cc..21ff7a8 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -50,6 +50,7 @@ __xdata char port_names[9][PORT_NAME_SIZE]; extern __xdata uint16_t management_vlan; extern __xdata uint8_t sfp_speed[2]; extern __xdata uint8_t sfp_pins_last; +extern __xdata uint8_t sfp_options[2]; __xdata uint8_t gpio_last_value[8] = { 0 }; // Temporatly for str to hex convertion value. @@ -741,7 +742,7 @@ void parse_mtu(void) void sfp_print_measurements(uint8_t sfp) { print_string("Options: "); print_byte(sfp_read_reg(sfp, 92)); write_char('\n'); - if (!(sfp_read_reg(sfp, 92) & 0x40)) + if (!(sfp_options[sfp] & 0x40)) return; print_string("Temp: "); print_byte(sfp_read_reg(sfp, 224)); print_byte(sfp_read_reg(sfp, 225)); write_char('\n'); print_string("Vcc: "); print_byte(sfp_read_reg(sfp, 226)); print_byte(sfp_read_reg(sfp, 227)); write_char('\n'); diff --git a/httpd/httpd.c b/httpd/httpd.c index c05a7e1..0a861a3 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -101,21 +101,6 @@ uint8_t find_entry(__xdata uint8_t *e) } -char strcmp(__xdata uint8_t *c, __code uint8_t * __xdata d) -{ - uint8_t i = 0; - - while (d[i] && (d[i] == c[i])) - i++; - - if (c[i] < d[i]) - return -1; - else if (c[i] > d[i]) - return 1; - return 0; -} - - bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p) { uint8_t u, c; diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 66b234e..7ca29e4 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -660,52 +660,53 @@ void send_status(void) slen += strtox(outbuf + slen, "\""); if (machine.is_sfp[i]) { + uint8_t sfp = machine.is_sfp[i] - 1; slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":"); - if (!(sfp_pins_last & (0x1 << ((machine.is_sfp[i] - 1) << 2)))) { + if (!(sfp_pins_last & (0x1 << (sfp << 2)))) { bool_to_html(1); slen += strtox(outbuf + slen,",\"sfp_options\":\"0x"); - byte_to_html(sfp_options[machine.is_sfp[i]-1]); - if (sfp_options[machine.is_sfp[i]-1] & 0x40) { + byte_to_html(sfp_options[sfp]); + if (sfp_options[sfp] & 0x40) { slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 224, 2); + sfp_send_data(sfp, 224, 2); slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 226, 2); + sfp_send_data(sfp, 226, 2); slen += strtox(outbuf + slen,"\",\"sfp_txbias\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 228, 2); + sfp_send_data(sfp, 228, 2); slen += strtox(outbuf + slen,"\",\"sfp_txpower\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 230, 2); + sfp_send_data(sfp, 230, 2); slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 232, 2); - if (sfp_options[machine.is_sfp[i]-1] & 0x10) { + sfp_send_data(sfp, 232, 2); + if (sfp_options[sfp] & 0x10) { slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 212, 4); + sfp_send_data(sfp, 212, 4); slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 216, 4); + sfp_send_data(sfp, 216, 4); slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 204, 4); + sfp_send_data(sfp, 204, 4); slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 208, 4); + sfp_send_data(sfp, 208, 4); slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 184, 16); - sfp_send_data(machine.is_sfp[i] - 1, 200, 4); + sfp_send_data(sfp, 184, 16); + sfp_send_data(sfp, 200, 4); } slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x"); - sfp_send_data(machine.is_sfp[i] - 1, 238, 1); + sfp_send_data(sfp, 238, 1); } slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\""); - for (register uint8_t s = 0; s < 16; s++) - outbuf[slen++] = sfp_module_vendor[machine.is_sfp[i]-1][s]; + for (register uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++) + outbuf[slen++] = sfp_module_vendor[sfp][s]; slen += strtox(outbuf + slen,"\",\"sfp_model\":\""); - for (register uint8_t s = 0; s < 16; s++) - outbuf[slen++] = sfp_module_model[machine.is_sfp[i]-1][s]; + for (register uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++) + outbuf[slen++] = sfp_module_model[sfp][s]; slen += strtox(outbuf + slen,"\",\"sfp_serial\":\""); - for (register uint8_t s = 0; s < 16; s++) - outbuf[slen++] = sfp_module_serial[machine.is_sfp[i]-1][s]; + for (register uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++) + outbuf[slen++] = sfp_module_serial[sfp][s]; slen += strtox(outbuf + slen,"\",\"sfp_los\":"); - if (machine.sfp_port[machine.is_sfp[i]-1].pin_los == GPIO_NA) { + if (machine.sfp_port[sfp].pin_los == GPIO_NA) { slen += strtox(outbuf + slen,"null"); } else { - bool_to_html(sfp_pins_last & (0x2 << (((machine.is_sfp[i]-1) << 2)))); + bool_to_html(sfp_pins_last & (0x2 << (sfp << 2))); } } else { bool_to_html(0); diff --git a/rtl837x_common.h b/rtl837x_common.h index 6d6abb5..9aa9af4 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -158,6 +158,7 @@ uint16_t strlen(register __code const char *s); uint16_t strlen_x(register __xdata 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); +char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b); void tcpip_output(void); uint8_t read_flash(uint8_t bank, __code uint8_t *addr); void get_random_32(void); diff --git a/rtlplayground.c b/rtlplayground.c index 356ea9c..30b15d8 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -138,10 +138,25 @@ __xdata char sfp_module_model[2][17]; __xdata char sfp_module_serial[2][17]; __xdata uint8_t sfp_options[2]; __xdata uint8_t sfp_speed[2]; +__xdata uint8_t sfp_quirks[2]; __xdata bool button_last; __xdata uint8_t button_sec_counter_last; volatile __bit tx_buf_empty; +__code enum sfp_quirk { + SFP_QUIRK_DDM = (1 << 0), +}; + +struct sfp_quirk_entry { + __code char *vendor; // Set vendor or model to 0 to act as wildcard + __code char *model; + uint8_t quirks; +}; + +static __code struct sfp_quirk_entry sfp_quirk_table[] = { + { "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM }, +}; + struct eth_in { struct uip_eth_addr dst; struct uip_eth_addr src; @@ -327,6 +342,21 @@ uint16_t strlen_x(register __xdata const char *s) } +char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b) +{ + uint8_t i = 0; + + while (b[i] && (b[i] == a[i])) + i++; + + if (a[i] < b[i]) + return -1; + else if (a[i] > b[i]) + return 1; + return 0; +} + + void print_short(uint16_t a) { // allocating the registers first improves the sdcc code here @@ -1199,18 +1229,46 @@ void sfp_print_info(uint8_t sfp) print_string("\n"); } +// 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 +{ + dst[length] = '\0'; + + for (uint8_t i = 0; i < length; i++) + dst[i] = sfp_read_reg(sfp, start + i); + + while (length > 0 && dst[--length] == ' ') + dst[length] = '\0'; +} void sfp_get_info(uint8_t sfp) { - for (uint8_t i = 20; i < 36; i++) - sfp_module_vendor[sfp][i-20] = sfp_read_reg(sfp, i); - sfp_module_vendor[sfp][16] = '\0'; - for (uint8_t i = 40; i < 56; i++) - sfp_module_model[sfp][i-40] = sfp_read_reg(sfp, i); - sfp_module_model[sfp][16] = '\0'; - for (uint8_t i = 68; i < 84; i++) - sfp_module_serial[sfp][i-68] = sfp_read_reg(sfp, i); - sfp_module_serial[sfp][16] = '\0'; + sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16); + sfp_read_field(sfp_module_model[sfp], sfp, 40, 16); + sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16); +} + +void sfp_apply_quirks(uint8_t sfp) __reentrant +{ + sfp_quirks[sfp] = 0; + + for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) { + if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) { + if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) { + sfp_quirks[sfp] |= sfp_quirk_table[i].quirks; + } + } + } + + if (sfp_quirks[sfp] & SFP_QUIRK_DDM) { + if (!(sfp_options[sfp] & 0x40)) { + // 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 + if (sfp_read_reg(sfp, 226) != 0xff) { + sfp_options[sfp] |= 0x40; + } + } + } } @@ -1255,6 +1313,7 @@ void handle_sfp(void) print_string("\n"); sfp_options[sfp] = sfp_read_reg(sfp, 92); sfp_get_info(sfp); + sfp_apply_quirks(sfp); sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate)); } } else {