* [PATCH iproute2-next 5.16 v6 3/5] iplink_can: use PRINT_ANY to factorize code and fix signedness
2021-11-03 16:44 [PATCH iproute2-next 5.16 v6 0/5] iplink_can: cleaning, fixes and adding TDC support Vincent Mailhol
2021-11-03 16:44 ` [PATCH iproute2-next 5.16 v6 1/5] iplink_can: fix configuration ranges in print_usage() and add unit Vincent Mailhol
2021-11-03 16:44 ` [PATCH iproute2-next 5.16 v6 2/5] iplink_can: code refactoring of print_ctrlmode() Vincent Mailhol
@ 2021-11-03 16:44 ` Vincent Mailhol
2022-10-07 7:44 ` Marc Kleine-Budde
2021-11-03 16:44 ` [PATCH iproute2-next 5.16 v6 4/5] iplink_can: print brp and dbrp bittiming variables Vincent Mailhol
` (2 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Vincent Mailhol @ 2021-11-03 16:44 UTC (permalink / raw)
To: David Ahern, Stephen Hemminger
Cc: Marc Kleine-Budde, netdev, linux-can, Vincent Mailhol
Current implementation heavily relies on some "if (is_json_context())"
switches to decide the context and then does some print_*(PRINT_JSON,
...) when in json context and some fprintf(...) else.
Furthermore, current implementation uses either print_int() or the
conversion specifier %d to print unsigned integers.
This patch factorizes each pairs of print_*(PRINT_JSON, ...) and
fprintf() into a single print_*(PRINT_ANY, ...) call. While doing this
replacement, it uses proper unsigned function print_uint() as well as
the conversion specifier %u when the parameter is an unsigned integer.
Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
---
ip/iplink_can.c | 331 +++++++++++++++++++-----------------------------
1 file changed, 130 insertions(+), 201 deletions(-)
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index c910365d..c0165237 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -275,11 +275,19 @@ static const char *can_state_names[CAN_STATE_MAX] = {
[CAN_STATE_SLEEPING] = "SLEEPING"
};
-static void can_print_json_timing_min_max(const char *attr, int min, int max)
+static void can_print_nl_indent(void)
{
- open_json_object(attr);
- print_int(PRINT_JSON, "min", NULL, min);
- print_int(PRINT_JSON, "max", NULL, max);
+ print_nl();
+ print_string(PRINT_FP, NULL, "%s", "\t ");
+}
+
+static void can_print_timing_min_max(const char *json_attr, const char *fp_attr,
+ int min, int max)
+{
+ print_null(PRINT_FP, NULL, fp_attr, NULL);
+ open_json_object(json_attr);
+ print_uint(PRINT_ANY, "min", " %d", min);
+ print_uint(PRINT_ANY, "max", "..%d", max);
close_json_object();
}
@@ -305,56 +313,38 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_berr_counter *bc =
RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]);
- if (is_json_context()) {
- open_json_object("berr_counter");
- print_int(PRINT_JSON, "tx", NULL, bc->txerr);
- print_int(PRINT_JSON, "rx", NULL, bc->rxerr);
- close_json_object();
- } else {
- fprintf(f, "(berr-counter tx %d rx %d) ",
- bc->txerr, bc->rxerr);
- }
+ open_json_object("berr_counter");
+ print_uint(PRINT_ANY, "tx", "(berr-counter tx %u", bc->txerr);
+ print_uint(PRINT_ANY, "rx", " rx %u) ", bc->rxerr);
+ close_json_object();
}
if (tb[IFLA_CAN_RESTART_MS]) {
__u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]);
- print_int(PRINT_ANY,
- "restart_ms",
- "restart-ms %d ",
- *restart_ms);
+ print_uint(PRINT_ANY, "restart_ms", "restart-ms %u ",
+ *restart_ms);
}
/* bittiming is irrelevant if fixed bitrate is defined */
if (tb[IFLA_CAN_BITTIMING] && !tb[IFLA_CAN_BITRATE_CONST]) {
struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]);
-
- if (is_json_context()) {
- json_writer_t *jw;
-
- open_json_object("bittiming");
- print_int(PRINT_ANY, "bitrate", NULL, bt->bitrate);
- jw = get_json_writer();
- jsonw_name(jw, "sample_point");
- jsonw_printf(jw, "%.3f",
- (float) bt->sample_point / 1000);
- print_int(PRINT_ANY, "tq", NULL, bt->tq);
- print_int(PRINT_ANY, "prop_seg", NULL, bt->prop_seg);
- print_int(PRINT_ANY, "phase_seg1",
- NULL, bt->phase_seg1);
- print_int(PRINT_ANY, "phase_seg2",
- NULL, bt->phase_seg2);
- print_int(PRINT_ANY, "sjw", NULL, bt->sjw);
- close_json_object();
- } else {
- fprintf(f, "\n bitrate %d sample-point %.3f ",
- bt->bitrate, (float) bt->sample_point / 1000.);
- fprintf(f,
- "\n tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
- bt->tq, bt->prop_seg,
- bt->phase_seg1, bt->phase_seg2,
- bt->sjw);
- }
+ char sp[6];
+
+ open_json_object("bittiming");
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "bitrate", " bitrate %u", bt->bitrate);
+ snprintf(sp, sizeof(sp), "%.3f", bt->sample_point / 1000.);
+ print_string(PRINT_ANY, "sample_point", " sample-point %s", sp);
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "tq", " tq %u", bt->tq);
+ print_uint(PRINT_ANY, "prop_seg", " prop-seg %u", bt->prop_seg);
+ print_uint(PRINT_ANY, "phase_seg1", " phase-seg1 %u",
+ bt->phase_seg1);
+ print_uint(PRINT_ANY, "phase_seg2", " phase-seg2 %u",
+ bt->phase_seg2);
+ print_uint(PRINT_ANY, "sjw", " sjw %u", bt->sjw);
+ close_json_object();
}
/* bittiming const is irrelevant if fixed bitrate is defined */
@@ -362,28 +352,18 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_bittiming_const *btc =
RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]);
- if (is_json_context()) {
- open_json_object("bittiming_const");
- print_string(PRINT_JSON, "name", NULL, btc->name);
- can_print_json_timing_min_max("tseg1",
- btc->tseg1_min,
- btc->tseg1_max);
- can_print_json_timing_min_max("tseg2",
- btc->tseg2_min,
- btc->tseg2_max);
- can_print_json_timing_min_max("sjw", 1, btc->sjw_max);
- can_print_json_timing_min_max("brp",
- btc->brp_min,
- btc->brp_max);
- print_int(PRINT_JSON, "brp_inc", NULL, btc->brp_inc);
- close_json_object();
- } else {
- fprintf(f, "\n %s: tseg1 %d..%d tseg2 %d..%d "
- "sjw 1..%d brp %d..%d brp-inc %d",
- btc->name, btc->tseg1_min, btc->tseg1_max,
- btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
- btc->brp_min, btc->brp_max, btc->brp_inc);
- }
+ open_json_object("bittiming_const");
+ can_print_nl_indent();
+ print_string(PRINT_ANY, "name", " %s:", btc->name);
+ can_print_timing_min_max("tseg1", " tseg1",
+ btc->tseg1_min, btc->tseg1_max);
+ can_print_timing_min_max("tseg2", " tseg2",
+ btc->tseg2_min, btc->tseg2_max);
+ can_print_timing_min_max("sjw", " sjw", 1, btc->sjw_max);
+ can_print_timing_min_max("brp", " brp",
+ btc->brp_min, btc->brp_max);
+ print_uint(PRINT_ANY, "brp_inc", " brp_inc %u", btc->brp_inc);
+ close_json_object();
}
if (tb[IFLA_CAN_BITRATE_CONST]) {
@@ -399,64 +379,47 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
bitrate = bt->bitrate;
}
- if (is_json_context()) {
- print_uint(PRINT_JSON,
- "bittiming_bitrate",
- NULL, bitrate);
- open_json_array(PRINT_JSON, "bitrate_const");
- for (i = 0; i < bitrate_cnt; ++i)
- print_uint(PRINT_JSON, NULL, NULL,
- bitrate_const[i]);
- close_json_array(PRINT_JSON, NULL);
- } else {
- fprintf(f, "\n bitrate %u", bitrate);
- fprintf(f, "\n [");
-
- for (i = 0; i < bitrate_cnt - 1; ++i) {
- /* This will keep lines below 80 signs */
- if (!(i % 6) && i)
- fprintf(f, "\n ");
-
- fprintf(f, "%8u, ", bitrate_const[i]);
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "bittiming_bitrate", " bitrate %u",
+ bitrate);
+ can_print_nl_indent();
+ open_json_array(PRINT_ANY, is_json_context() ?
+ "bitrate_const" : " [");
+ for (i = 0; i < bitrate_cnt; ++i) {
+ /* This will keep lines below 80 signs */
+ if (!(i % 6) && i) {
+ can_print_nl_indent();
+ print_string(PRINT_FP, NULL, "%s", " ");
}
-
- if (!(i % 6) && i)
- fprintf(f, "\n ");
- fprintf(f, "%8u ]", bitrate_const[i]);
+ print_uint(PRINT_ANY, NULL,
+ i < bitrate_cnt - 1 ? "%8u, " : "%8u",
+ bitrate_const[i]);
}
+ close_json_array(PRINT_JSON, " ]");
}
/* data bittiming is irrelevant if fixed bitrate is defined */
if (tb[IFLA_CAN_DATA_BITTIMING] && !tb[IFLA_CAN_DATA_BITRATE_CONST]) {
struct can_bittiming *dbt =
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
-
- if (is_json_context()) {
- json_writer_t *jw;
-
- open_json_object("data_bittiming");
- print_int(PRINT_JSON, "bitrate", NULL, dbt->bitrate);
- jw = get_json_writer();
- jsonw_name(jw, "sample_point");
- jsonw_printf(jw, "%.3f",
- (float) dbt->sample_point / 1000.);
- print_int(PRINT_JSON, "tq", NULL, dbt->tq);
- print_int(PRINT_JSON, "prop_seg", NULL, dbt->prop_seg);
- print_int(PRINT_JSON, "phase_seg1",
- NULL, dbt->phase_seg1);
- print_int(PRINT_JSON, "phase_seg2",
- NULL, dbt->phase_seg2);
- print_int(PRINT_JSON, "sjw", NULL, dbt->sjw);
- close_json_object();
- } else {
- fprintf(f, "\n dbitrate %d dsample-point %.3f ",
- dbt->bitrate,
- (float) dbt->sample_point / 1000.);
- fprintf(f, "\n dtq %d dprop-seg %d dphase-seg1 %d "
- "dphase-seg2 %d dsjw %d",
- dbt->tq, dbt->prop_seg, dbt->phase_seg1,
- dbt->phase_seg2, dbt->sjw);
- }
+ char dsp[6];
+
+ open_json_object("data_bittiming");
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "bitrate", " dbitrate %u", dbt->bitrate);
+ snprintf(dsp, sizeof(dsp), "%.3f", dbt->sample_point / 1000.);
+ print_string(PRINT_ANY, "sample_point", " dsample-point %s",
+ dsp);
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "tq", " dtq %u", dbt->tq);
+ print_uint(PRINT_ANY, "prop_seg", " dprop-seg %u",
+ dbt->prop_seg);
+ print_uint(PRINT_ANY, "phase_seg1", " dphase-seg1 %u",
+ dbt->phase_seg1);
+ print_uint(PRINT_ANY, "phase_seg2", " dphase-seg2 %u",
+ dbt->phase_seg2);
+ print_uint(PRINT_ANY, "sjw", " dsjw %u", dbt->sjw);
+ close_json_object();
}
/* data bittiming const is irrelevant if fixed bitrate is defined */
@@ -465,29 +428,18 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
struct can_bittiming_const *dbtc =
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]);
- if (is_json_context()) {
- open_json_object("data_bittiming_const");
- print_string(PRINT_JSON, "name", NULL, dbtc->name);
- can_print_json_timing_min_max("tseg1",
- dbtc->tseg1_min,
- dbtc->tseg1_max);
- can_print_json_timing_min_max("tseg2",
- dbtc->tseg2_min,
- dbtc->tseg2_max);
- can_print_json_timing_min_max("sjw", 1, dbtc->sjw_max);
- can_print_json_timing_min_max("brp",
- dbtc->brp_min,
- dbtc->brp_max);
-
- print_int(PRINT_JSON, "brp_inc", NULL, dbtc->brp_inc);
- close_json_object();
- } else {
- fprintf(f, "\n %s: dtseg1 %d..%d dtseg2 %d..%d "
- "dsjw 1..%d dbrp %d..%d dbrp-inc %d",
- dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max,
- dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max,
- dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc);
- }
+ open_json_object("data_bittiming_const");
+ can_print_nl_indent();
+ print_string(PRINT_ANY, "name", " %s:", dbtc->name);
+ can_print_timing_min_max("tseg1", " dtseg1",
+ dbtc->tseg1_min, dbtc->tseg1_max);
+ can_print_timing_min_max("tseg2", " dtseg2",
+ dbtc->tseg2_min, dbtc->tseg2_max);
+ can_print_timing_min_max("sjw", " dsjw", 1, dbtc->sjw_max);
+ can_print_timing_min_max("brp", " dbrp",
+ dbtc->brp_min, dbtc->brp_max);
+ print_uint(PRINT_ANY, "brp_inc", " dbrp_inc %u", dbtc->brp_inc);
+ close_json_object();
}
if (tb[IFLA_CAN_DATA_BITRATE_CONST]) {
@@ -505,30 +457,23 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
dbitrate = dbt->bitrate;
}
- if (is_json_context()) {
- print_uint(PRINT_JSON, "data_bittiming_bitrate",
- NULL, dbitrate);
- open_json_array(PRINT_JSON, "data_bitrate_const");
- for (i = 0; i < dbitrate_cnt; ++i)
- print_uint(PRINT_JSON, NULL, NULL,
- dbitrate_const[i]);
- close_json_array(PRINT_JSON, NULL);
- } else {
- fprintf(f, "\n dbitrate %u", dbitrate);
- fprintf(f, "\n [");
-
- for (i = 0; i < dbitrate_cnt - 1; ++i) {
- /* This will keep lines below 80 signs */
- if (!(i % 6) && i)
- fprintf(f, "\n ");
-
- fprintf(f, "%8u, ", dbitrate_const[i]);
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "data_bittiming_bitrate", " dbitrate %u",
+ dbitrate);
+ can_print_nl_indent();
+ open_json_array(PRINT_ANY, is_json_context() ?
+ "data_bitrate_const" : " [");
+ for (i = 0; i < dbitrate_cnt; ++i) {
+ /* This will keep lines below 80 signs */
+ if (!(i % 6) && i) {
+ can_print_nl_indent();
+ print_string(PRINT_FP, NULL, "%s", " ");
}
-
- if (!(i % 6) && i)
- fprintf(f, "\n ");
- fprintf(f, "%8u ]", dbitrate_const[i]);
+ print_uint(PRINT_ANY, NULL,
+ i < dbitrate_cnt - 1 ? "%8u, " : "%8u",
+ dbitrate_const[i]);
}
+ close_json_array(PRINT_JSON, " ]");
}
if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) {
@@ -538,29 +483,21 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
sizeof(*trm_const);
int i;
- if (is_json_context()) {
- print_hu(PRINT_JSON, "termination", NULL, *trm);
- open_json_array(PRINT_JSON, "termination_const");
- for (i = 0; i < trm_cnt; ++i)
- print_hu(PRINT_JSON, NULL, NULL, trm_const[i]);
- close_json_array(PRINT_JSON, NULL);
- } else {
- fprintf(f, "\n termination %hu [ ", *trm);
-
- for (i = 0; i < trm_cnt - 1; ++i)
- fprintf(f, "%hu, ", trm_const[i]);
-
- fprintf(f, "%hu ]", trm_const[i]);
- }
+ can_print_nl_indent();
+ print_hu(PRINT_ANY, "termination", " termination %hu [ ", *trm);
+ open_json_array(PRINT_JSON, "termination_const");
+ for (i = 0; i < trm_cnt; ++i)
+ print_hu(PRINT_ANY, NULL,
+ i < trm_cnt - 1 ? "%hu, " : "%hu",
+ trm_const[i]);
+ close_json_array(PRINT_JSON, " ]");
}
if (tb[IFLA_CAN_CLOCK]) {
struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]);
- print_int(PRINT_ANY,
- "clock",
- "\n clock %d ",
- clock->freq);
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "clock", " clock %u ", clock->freq);
}
}
@@ -573,31 +510,23 @@ static void can_print_xstats(struct link_util *lu,
if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) {
stats = RTA_DATA(xstats);
- if (is_json_context()) {
- print_int(PRINT_JSON, "restarts",
- NULL, stats->restarts);
- print_int(PRINT_JSON, "bus_error",
- NULL, stats->bus_error);
- print_int(PRINT_JSON, "arbitration_lost",
- NULL, stats->arbitration_lost);
- print_int(PRINT_JSON, "error_warning",
- NULL, stats->error_warning);
- print_int(PRINT_JSON, "error_passive",
- NULL, stats->error_passive);
- print_int(PRINT_JSON, "bus_off", NULL, stats->bus_off);
- } else {
- fprintf(f, "\n re-started bus-errors arbit-lost "
- "error-warn error-pass bus-off");
- fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d",
- stats->restarts, stats->bus_error,
- stats->arbitration_lost, stats->error_warning,
- stats->error_passive, stats->bus_off);
- }
+ can_print_nl_indent();
+ print_string(PRINT_FP, NULL, "%s",
+ " re-started bus-errors arbit-lost error-warn error-pass bus-off");
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "restarts", " %-10u", stats->restarts);
+ print_uint(PRINT_ANY, "bus_error", " %-10u", stats->bus_error);
+ print_uint(PRINT_ANY, "arbitration_lost", " %-10u",
+ stats->arbitration_lost);
+ print_uint(PRINT_ANY, "error_warning", " %-10u",
+ stats->error_warning);
+ print_uint(PRINT_ANY, "error_passive", " %-10u",
+ stats->error_passive);
+ print_uint(PRINT_ANY, "bus_off", " %-10u", stats->bus_off);
}
}
-static void can_print_help(struct link_util *lu, int argc, char **argv,
- FILE *f)
+static void can_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
{
print_usage(f);
}
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH iproute2-next 5.16 v6 5/5] iplink_can: add new CAN FD bittiming parameters: Transmitter Delay Compensation (TDC)
2021-11-03 16:44 [PATCH iproute2-next 5.16 v6 0/5] iplink_can: cleaning, fixes and adding TDC support Vincent Mailhol
` (3 preceding siblings ...)
2021-11-03 16:44 ` [PATCH iproute2-next 5.16 v6 4/5] iplink_can: print brp and dbrp bittiming variables Vincent Mailhol
@ 2021-11-03 16:44 ` Vincent Mailhol
2021-11-04 15:50 ` [PATCH iproute2-next 5.16 v6 0/5] iplink_can: cleaning, fixes and adding TDC support patchwork-bot+netdevbpf
5 siblings, 0 replies; 9+ messages in thread
From: Vincent Mailhol @ 2021-11-03 16:44 UTC (permalink / raw)
To: David Ahern, Stephen Hemminger
Cc: Marc Kleine-Budde, netdev, linux-can, Vincent Mailhol
At high bit rates, the propagation delay from the TX pin to the RX pin
of the transceiver causes measurement errors: the sample point on the
RX pin might occur on the previous bit.
This issue is addressed in ISO 11898-1 section 11.3.3 "Transmitter
delay compensation" (TDC).
This patch brings command line support to nine TDC parameters which
were recently added to the kernel's CAN netlink interface in order to
implement TDC:
- IFLA_CAN_TDC_TDCV_MIN: Transmitter Delay Compensation Value
minimum value
- IFLA_CAN_TDC_TDCV_MAX: Transmitter Delay Compensation Value
maximum value
- IFLA_CAN_TDC_TDCO_MIN: Transmitter Delay Compensation Offset
minimum value
- IFLA_CAN_TDC_TDCO_MAX: Transmitter Delay Compensation Offset
maximum value
- IFLA_CAN_TDC_TDCF_MIN: Transmitter Delay Compensation Filter
window minimum value
- IFLA_CAN_TDC_TDCF_MAX: Transmitter Delay Compensation Filter
window maximum value
- IFLA_CAN_TDC_TDCV: Transmitter Delay Compensation Value
- IFLA_CAN_TDC_TDCO: Transmitter Delay Compensation Offset
- IFLA_CAN_TDC_TDCF: Transmitter Delay Compensation Filter window
All those new parameters are nested together into the attribute
IFLA_CAN_TDC.
The TDC parameters extend the FD parameters. As such, the TDC
parameters must be specified together the "fd on" flag.
When "fd on" flag is provided, a tdc-mode parameter allows to specify
how to operate. Valid options for tdc-mode are:
* auto: the transmitter dynamically measures TDCV for each of the
transmitted frames. As such, TDCV can not be manually provided. In
this mode, the user must specify TDCO and may also specify TDCF if
supported.
* manual: use a static TDCV provided by the user. In this mode, the
user must specify both TDCV and TDCO and may also specify TDCF if
supported.
* off: TDC is explicitly disabled.
* tdc-mode parameter omitted (default mode): the kernel decides
whether TDC should be enabled or not and if so, it calculates the
TDC values. TDC parameters are an expert option and the average
user is not expected to provide those, thus the presence of this
"default mode".
If the fd flag is omitted, all the FD values (including TDC values)
remain unchanged.
If "fd off" flag is specified, all FD values (including TDC values)
are zeroed.
TDCV is always reported in manual mode. In auto mode, TDCV is reported
only if the value is available. Especially, the TDCV might not be
available if the controller has no feature to report it or if the
value in not yet available (i.e. no data sent yet and measurement did
not occur).
TDCF is reported only if tdcf_max is not zero (i.e. if supported by
the controller).
For reference, here are a few samples of how the output looks like:
| $ ip link set can0 type can bitrate 1000000 dbitrate 8000000 fd on tdco 7 tdcf 8 tdc-mode auto
| $ ip --details link show can0
| 1: can0: <NOARP,ECHO> mtu 72 qdisc noop state DOWN mode DEFAULT group default qlen 10
| link/can promiscuity 0 minmtu 0 maxmtu 0
| can <FD,TDC-AUTO> state STOPPED (berr-counter tx 0 rx 0) restart-ms 0
| bitrate 1000000 sample-point 0.750
| tq 12 prop-seg 29 phase-seg1 30 phase-seg2 20 sjw 1 brp 1
| ES582.1/ES584.1: tseg1 2..256 tseg2 2..128 sjw 1..128 brp 1..512 brp_inc 1
| dbitrate 8000000 dsample-point 0.700
| dtq 12 dprop-seg 3 dphase-seg1 3 dphase-seg2 3 dsjw 1 dbrp 1
| tdco 7 tdcf 8
| ES582.1/ES584.1: dtseg1 2..32 dtseg2 1..16 dsjw 1..8 dbrp 1..32 dbrp_inc 1
| tdco 0..127 tdcf 0..127
| clock 80000000 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
| $ ip --details --json --pretty link show can0
| [ {
| "ifindex": 1,
| "ifname": "can0",
| "flags": [ "NOARP","ECHO" ],
| "mtu": 72,
| "qdisc": "noop",
| "operstate": "DOWN",
| "linkmode": "DEFAULT",
| "group": "default",
| "txqlen": 10,
| "link_type": "can",
| "promiscuity": 0,
| "min_mtu": 0,
| "max_mtu": 0,
| "linkinfo": {
| "info_kind": "can",
| "info_data": {
| "ctrlmode": [ "FD","TDC-AUTO" ],
| "state": "STOPPED",
| "berr_counter": {
| "tx": 0,
| "rx": 0
| },
| "restart_ms": 0,
| "bittiming": {
| "bitrate": 1000000,
| "sample_point": "0.750",
| "tq": 12,
| "prop_seg": 29,
| "phase_seg1": 30,
| "phase_seg2": 20,
| "sjw": 1,
| "brp": 1
| },
| "bittiming_const": {
| "name": "ES582.1/ES584.1",
| "tseg1": {
| "min": 2,
| "max": 256
| },
| "tseg2": {
| "min": 2,
| "max": 128
| },
| "sjw": {
| "min": 1,
| "max": 128
| },
| "brp": {
| "min": 1,
| "max": 512
| },
| "brp_inc": 1
| },
| "data_bittiming": {
| "bitrate": 8000000,
| "sample_point": "0.700",
| "tq": 12,
| "prop_seg": 3,
| "phase_seg1": 3,
| "phase_seg2": 3,
| "sjw": 1,
| "brp": 1,
| "tdc": {
| "tdco": 7,
| "tdcf": 8
| }
| },
| "data_bittiming_const": {
| "name": "ES582.1/ES584.1",
| "tseg1": {
| "min": 2,
| "max": 32
| },
| "tseg2": {
| "min": 1,
| "max": 16
| },
| "sjw": {
| "min": 1,
| "max": 8
| },
| "brp": {
| "min": 1,
| "max": 32
| },
| "brp_inc": 1,
| "tdc": {
| "tdco": {
| "min": 0,
| "max": 127
| },
| "tdcf": {
| "min": 0,
| "max": 127
| }
| }
| },
| "clock": 80000000
| }
| },
| "num_tx_queues": 1,
| "num_rx_queues": 1,
| "gso_max_size": 65536,
| "gso_max_segs": 65535
| } ]
Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
---
ip/iplink_can.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index cf6b06b8..f4b37528 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -28,6 +28,7 @@ static void print_usage(FILE *f)
"\n"
"\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n"
"\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n"
+ "\t[ tdcv TDCV tdco TDCO tdcf TDCF ]\n"
"\n"
"\t[ loopback { on | off } ]\n"
"\t[ listen-only { on | off } ]\n"
@@ -38,6 +39,7 @@ static void print_usage(FILE *f)
"\t[ fd-non-iso { on | off } ]\n"
"\t[ presume-ack { on | off } ]\n"
"\t[ cc-len8-dlc { on | off } ]\n"
+ "\t[ tdc-mode { auto | manual | off } ]\n"
"\n"
"\t[ restart-ms TIME-MS ]\n"
"\t[ restart ]\n"
@@ -51,6 +53,9 @@ static void print_usage(FILE *f)
"\t PHASE-SEG1 := { NUMBER in tq }\n"
"\t PHASE-SEG2 := { NUMBER in tq }\n"
"\t SJW := { NUMBER in tq }\n"
+ "\t TDCV := { NUMBER in tc}\n"
+ "\t TDCO := { NUMBER in tc}\n"
+ "\t TDCF := { NUMBER in tc}\n"
"\t RESTART-MS := { 0 | NUMBER in ms }\n"
);
}
@@ -113,6 +118,8 @@ static void print_ctrlmode(enum output_type t, __u32 flags, const char* key)
print_flag(t, &flags, CAN_CTRLMODE_FD_NON_ISO, "FD-NON-ISO");
print_flag(t, &flags, CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
print_flag(t, &flags, CAN_CTRLMODE_CC_LEN8_DLC, "CC-LEN8-DLC");
+ print_flag(t, &flags, CAN_CTRLMODE_TDC_AUTO, "TDC-AUTO");
+ print_flag(t, &flags, CAN_CTRLMODE_TDC_MANUAL, "TDC-MANUAL");
if (flags)
print_hex(t, NULL, "%x", flags);
@@ -125,6 +132,8 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
{
struct can_bittiming bt = {}, dbt = {};
struct can_ctrlmode cm = { 0 };
+ struct rtattr *tdc;
+ __u32 tdcv = -1, tdco = -1, tdcf = -1;
while (argc > 0) {
if (matches(*argv, "bitrate") == 0) {
@@ -190,6 +199,18 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
NEXT_ARG();
if (get_u32(&dbt.sjw, *argv, 0))
invarg("invalid \"dsjw\" value\n", *argv);
+ } else if (matches(*argv, "tdcv") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tdcv, *argv, 0))
+ invarg("invalid \"tdcv\" value\n", *argv);
+ } else if (matches(*argv, "tdco") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tdco, *argv, 0))
+ invarg("invalid \"tdco\" value\n", *argv);
+ } else if (matches(*argv, "tdcf") == 0) {
+ NEXT_ARG();
+ if (get_u32(&tdcf, *argv, 0))
+ invarg("invalid \"tdcf\" value\n", *argv);
} else if (matches(*argv, "loopback") == 0) {
NEXT_ARG();
set_ctrlmode("loopback", *argv, &cm,
@@ -226,6 +247,23 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
NEXT_ARG();
set_ctrlmode("cc-len8-dlc", *argv, &cm,
CAN_CTRLMODE_CC_LEN8_DLC);
+ } else if (matches(*argv, "tdc-mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "auto") == 0) {
+ cm.flags |= CAN_CTRLMODE_TDC_AUTO;
+ cm.mask |= CAN_CTRLMODE_TDC_AUTO;
+ } else if (strcmp(*argv, "manual") == 0) {
+ cm.flags |= CAN_CTRLMODE_TDC_MANUAL;
+ cm.mask |= CAN_CTRLMODE_TDC_MANUAL;
+ } else if (strcmp(*argv, "off") == 0) {
+ cm.mask |= CAN_CTRLMODE_TDC_AUTO |
+ CAN_CTRLMODE_TDC_MANUAL;
+ } else {
+ fprintf(stderr,
+ "Error: argument of \"tdc-mode\" must be \"auto\", \"manual\" or \"off\", not \"%s\"\n",
+ *argv);
+ exit (-1);
+ }
} else if (matches(*argv, "restart") == 0) {
__u32 val = 1;
@@ -263,6 +301,17 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
if (cm.mask)
addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
+ if (tdcv != -1 || tdco != -1 || tdcf != -1) {
+ tdc = addattr_nest(n, 1024, IFLA_CAN_TDC | NLA_F_NESTED);
+ if (tdcv != -1)
+ addattr32(n, 1024, IFLA_CAN_TDC_TDCV, tdcv);
+ if (tdco != -1)
+ addattr32(n, 1024, IFLA_CAN_TDC_TDCO, tdco);
+ if (tdcf != -1)
+ addattr32(n, 1024, IFLA_CAN_TDC_TDCF, tdcf);
+ addattr_nest_end(n, tdc);
+ }
+
return 0;
}
@@ -291,6 +340,62 @@ static void can_print_timing_min_max(const char *json_attr, const char *fp_attr,
close_json_object();
}
+static void can_print_tdc_opt(FILE *f, struct rtattr *tdc_attr)
+{
+ struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
+
+ parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr);
+ if (tb[IFLA_CAN_TDC_TDCV] || tb[IFLA_CAN_TDC_TDCO] ||
+ tb[IFLA_CAN_TDC_TDCF]) {
+ open_json_object("tdc");
+ can_print_nl_indent();
+ if (tb[IFLA_CAN_TDC_TDCV]) {
+ __u32 *tdcv = RTA_DATA(tb[IFLA_CAN_TDC_TDCV]);
+
+ print_uint(PRINT_ANY, "tdcv", " tdcv %u", *tdcv);
+ }
+ if (tb[IFLA_CAN_TDC_TDCO]) {
+ __u32 *tdco = RTA_DATA(tb[IFLA_CAN_TDC_TDCO]);
+
+ print_uint(PRINT_ANY, "tdco", " tdco %u", *tdco);
+ }
+ if (tb[IFLA_CAN_TDC_TDCF]) {
+ __u32 *tdcf = RTA_DATA(tb[IFLA_CAN_TDC_TDCF]);
+
+ print_uint(PRINT_ANY, "tdcf", " tdcf %u", *tdcf);
+ }
+ close_json_object();
+ }
+}
+
+static void can_print_tdc_const_opt(FILE *f, struct rtattr *tdc_attr)
+{
+ struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
+
+ parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr);
+ open_json_object("tdc");
+ can_print_nl_indent();
+ if (tb[IFLA_CAN_TDC_TDCV_MIN] && tb[IFLA_CAN_TDC_TDCV_MAX]) {
+ __u32 *tdcv_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCV_MIN]);
+ __u32 *tdcv_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCV_MAX]);
+
+ can_print_timing_min_max("tdcv", " tdcv", *tdcv_min, *tdcv_max);
+ }
+ if (tb[IFLA_CAN_TDC_TDCO_MIN] && tb[IFLA_CAN_TDC_TDCO_MAX]) {
+ __u32 *tdco_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCO_MIN]);
+ __u32 *tdco_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCO_MAX]);
+
+ can_print_timing_min_max("tdco", " tdco", *tdco_min, *tdco_max);
+ }
+ if (tb[IFLA_CAN_TDC_TDCF_MIN] && tb[IFLA_CAN_TDC_TDCF_MAX]) {
+ __u32 *tdcf_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCF_MIN]);
+ __u32 *tdcf_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCF_MAX]);
+
+ can_print_timing_min_max("tdcf", " tdcf", *tdcf_min, *tdcf_max);
+ }
+ close_json_object();
+}
+
static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
if (!tb)
@@ -421,6 +526,10 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
dbt->phase_seg2);
print_uint(PRINT_ANY, "sjw", " dsjw %u", dbt->sjw);
print_uint(PRINT_ANY, "brp", " dbrp %u", dbt->brp);
+
+ if (tb[IFLA_CAN_TDC])
+ can_print_tdc_opt(f, tb[IFLA_CAN_TDC]);
+
close_json_object();
}
@@ -441,6 +550,10 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
can_print_timing_min_max("brp", " dbrp",
dbtc->brp_min, dbtc->brp_max);
print_uint(PRINT_ANY, "brp_inc", " dbrp_inc %u", dbtc->brp_inc);
+
+ if (tb[IFLA_CAN_TDC])
+ can_print_tdc_const_opt(f, tb[IFLA_CAN_TDC]);
+
close_json_object();
}
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread