"\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"
"\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"
"\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"
);
}
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);
{
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) {
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,
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;
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;
}
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)
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();
}
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();
}