Signed-off-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx> --- ip/iplink_can.c | 209 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 196 insertions(+), 13 deletions(-) diff --git a/ip/iplink_can.c b/ip/iplink_can.c index 54acc65c..43018c54 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -26,6 +26,10 @@ static void print_usage(FILE *f) "\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[ xl-dbitrate BITRATE [ xl-dsample-point SAMPLE-POINT] ] |\n" + "\t[ xl-dtq TQ xl-dprop-seg PROP_SEG xl-dphase-seg1 PHASE-SEG1\n \t xl-dphase-seg2 PHASE-SEG2 [ xl-dsjw SJW ] ]\n" + "\t[ xl-tdcv TDCV xl-tdco TDCO xl-tdcf TDCF ]\n" + "\n" "\t[ loopback { on | off } ]\n" "\t[ listen-only { on | off } ]\n" "\t[ triple-sampling { on | off } ]\n" @@ -36,6 +40,8 @@ static void print_usage(FILE *f) "\t[ presume-ack { on | off } ]\n" "\t[ cc-len8-dlc { on | off } ]\n" "\t[ tdc-mode { auto | manual | off } ]\n" + "\t[ xl { on | off } ]\n" + "\t[ xl-tdc-mode { auto | manual | off } ]\n" "\n" "\t[ restart-ms TIME-MS ]\n" "\t[ restart ]\n" @@ -116,6 +122,9 @@ static void print_ctrlmode(enum output_type t, __u32 flags, const char* key) 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"); + print_flag(t, &flags, CAN_CTRLMODE_XL, "XL"); + print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_AUTO, "XL-TDC-AUTO"); + print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_MANUAL, "XL-TDC-MANUAL"); if (flags) print_hex(t, NULL, "%x", flags); @@ -132,9 +141,10 @@ struct can_tdc { static int can_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { - struct can_bittiming bt = {}, fd_dbt = {}; + struct can_bittiming bt = {}, fd_dbt = {}, xl_dbt = {}; struct can_ctrlmode cm = { 0 }; struct can_tdc fd = { .tdcv = -1, .tdco = -1, .tdcf = -1 }; + struct can_tdc xl = { .tdcv = -1, .tdco = -1, .tdcf = -1 }; while (argc > 0) { if (matches(*argv, "bitrate") == 0) { @@ -212,6 +222,53 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); if (get_u32(&fd.tdcf, *argv, 0)) invarg("invalid \"tdcf\" value", *argv); + } else if (matches(*argv, "xl") == 0) { + NEXT_ARG(); + set_ctrlmode("xl", *argv, &cm, + CAN_CTRLMODE_XL); + } else if (matches(*argv, "xl-dbitrate") == 0) { + NEXT_ARG(); + if (get_u32(&xl_dbt.bitrate, *argv, 0)) + invarg("invalid \"xl-dbitrate\" value", *argv); + } else if (matches(*argv, "xl-dsample-point") == 0) { + float sp; + + NEXT_ARG(); + if (get_float(&sp, *argv)) + invarg("invalid \"xl-dsample-point\" value", *argv); + xl_dbt.sample_point = (__u32)(sp * 1000); + } else if (matches(*argv, "xl-dtq") == 0) { + NEXT_ARG(); + if (get_u32(&xl_dbt.tq, *argv, 0)) + invarg("invalid \"xl-dtq\" value", *argv); + } else if (matches(*argv, "xl-dprop-seg") == 0) { + NEXT_ARG(); + if (get_u32(&xl_dbt.prop_seg, *argv, 0)) + invarg("invalid \"xl-dprop-seg\" value", *argv); + } else if (matches(*argv, "xl-dphase-seg1") == 0) { + NEXT_ARG(); + if (get_u32(&xl_dbt.phase_seg1, *argv, 0)) + invarg("invalid \"xl-dphase-seg1\" value", *argv); + } else if (matches(*argv, "xl-dphase-seg2") == 0) { + NEXT_ARG(); + if (get_u32(&xl_dbt.phase_seg2, *argv, 0)) + invarg("invalid \"xl-dphase-seg2\" value", *argv); + } else if (matches(*argv, "xl-dsjw") == 0) { + NEXT_ARG(); + if (get_u32(&xl_dbt.sjw, *argv, 0)) + invarg("invalid \"xl-dsjw\" value", *argv); + } else if (matches(*argv, "xl-tdcv") == 0) { + NEXT_ARG(); + if (get_u32(&xl.tdcv, *argv, 0)) + invarg("invalid \"xl-tdcv\" value", *argv); + } else if (matches(*argv, "xl-tdco") == 0) { + NEXT_ARG(); + if (get_u32(&xl.tdco, *argv, 0)) + invarg("invalid \"xl-tdco\" value", *argv); + } else if (matches(*argv, "xl-tdcf") == 0) { + NEXT_ARG(); + if (get_u32(&xl.tdcf, *argv, 0)) + invarg("invalid \"xl-tdcf\" value", *argv); } else if (matches(*argv, "loopback") == 0) { NEXT_ARG(); set_ctrlmode("loopback", *argv, &cm, @@ -263,6 +320,21 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv, invarg("\"tdc-mode\" must be either of \"auto\", \"manual\" or \"off\"", *argv); } + } else if (matches(*argv, "xl-tdc-mode") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "auto") == 0) { + cm.flags |= CAN_CTRLMODE_XL_TDC_AUTO; + cm.mask |= CAN_CTRLMODE_XL_TDC_AUTO; + } else if (strcmp(*argv, "manual") == 0) { + cm.flags |= CAN_CTRLMODE_XL_TDC_MANUAL; + cm.mask |= CAN_CTRLMODE_XL_TDC_MANUAL; + } else if (strcmp(*argv, "off") == 0) { + cm.mask |= CAN_CTRLMODE_XL_TDC_AUTO | + CAN_CTRLMODE_XL_TDC_MANUAL; + } else { + invarg("\"xl-tdc-mode\" must be either of \"auto\", \"manual\" or \"off\"", + *argv); + } } else if (matches(*argv, "restart") == 0) { __u32 val = 1; @@ -297,6 +369,8 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv, addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt)); if (fd_dbt.bitrate || fd_dbt.tq) addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &fd_dbt, sizeof(fd_dbt)); + if (xl_dbt.bitrate || xl_dbt.tq) + addattr_l(n, 1024, IFLA_CAN_XL_DATA_BITTIMING, &xl_dbt, sizeof(xl_dbt)); if (cm.mask) addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); @@ -312,6 +386,18 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_CAN_TDC_TDCF, fd.tdcf); addattr_nest_end(n, tdc); } + if (xl.tdcv != -1 || xl.tdco != -1 || xl.tdcf != -1) { + struct rtattr *tdc = addattr_nest(n, 1024, + IFLA_CAN_XL_TDC | NLA_F_NESTED); + + if (xl.tdcv != -1) + addattr32(n, 1024, IFLA_CAN_TDC_TDCV, xl.tdcv); + if (xl.tdco != -1) + addattr32(n, 1024, IFLA_CAN_TDC_TDCO, xl.tdco); + if (xl.tdcf != -1) + addattr32(n, 1024, IFLA_CAN_TDC_TDCF, xl.tdcf); + addattr_nest_end(n, tdc); + } return 0; } @@ -342,58 +428,67 @@ can_print_timing_min_max(const char *json_attr, const char *fp_attr, close_json_object(); } -static void can_print_tdc_opt(struct rtattr *tdc_attr) +static void can_print_tdc_opt(struct rtattr *tdc_attr, bool is_xl) { 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"); + const char *tdc = is_xl ? "xl-tdc" : "tdc"; + + open_json_object(tdc); can_print_nl_indent(); if (tb[IFLA_CAN_TDC_TDCV]) { + const char *tdcv_fmt = is_xl ? " xl-tdcv %u" : " tdcv %u"; __u32 *tdcv = RTA_DATA(tb[IFLA_CAN_TDC_TDCV]); - print_uint(PRINT_ANY, "tdcv", " tdcv %u", *tdcv); + print_uint(PRINT_ANY, "tdcv", tdcv_fmt, *tdcv); } if (tb[IFLA_CAN_TDC_TDCO]) { + const char *tdco_fmt = is_xl ? " xl-tdco %u" : " tdco %u"; __u32 *tdco = RTA_DATA(tb[IFLA_CAN_TDC_TDCO]); - print_uint(PRINT_ANY, "tdco", " tdco %u", *tdco); + print_uint(PRINT_ANY, "tdco", tdco_fmt, *tdco); } if (tb[IFLA_CAN_TDC_TDCF]) { + const char *tdcf_fmt = is_xl ? " xl-tdcf %u" : " tdcf %u"; __u32 *tdcf = RTA_DATA(tb[IFLA_CAN_TDC_TDCF]); - print_uint(PRINT_ANY, "tdcf", " tdcf %u", *tdcf); + print_uint(PRINT_ANY, "tdcf", tdcf_fmt, *tdcf); } close_json_object(); } } -static void can_print_tdc_const_opt(struct rtattr *tdc_attr) +static void can_print_tdc_const_opt(struct rtattr *tdc_attr, bool is_xl) { + const char *tdc = is_xl ? "xl-tdc" : "tdc"; struct rtattr *tb[IFLA_CAN_TDC_MAX + 1]; parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr); - open_json_object("tdc"); + 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]); + const char *tdcv = is_xl ? " xl-tdcv" : " tdcv"; - can_print_timing_min_max("tdcv", " tdcv", *tdcv_min, *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]); + const char *tdco = is_xl ? " xl-tdco" : " tdco"; - can_print_timing_min_max("tdco", " tdco", *tdco_min, *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]); + const char *tdcf = is_xl ? " xl-tdcf" : " tdcf"; - can_print_timing_min_max("tdcf", " tdcf", *tdcf_min, *tdcf_max); + can_print_timing_min_max("tdcf", tdcf, *tdcf_min, *tdcf_max); } close_json_object(); } @@ -547,7 +642,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) print_uint(PRINT_ANY, "brp", " dbrp %u", dbt->brp); if (tb[IFLA_CAN_TDC]) - can_print_tdc_opt(tb[IFLA_CAN_TDC]); + can_print_tdc_opt(tb[IFLA_CAN_TDC], false); close_json_object(); } @@ -571,7 +666,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) print_uint(PRINT_ANY, "brp_inc", " dbrp_inc %u", dbtc->brp_inc); if (tb[IFLA_CAN_TDC]) - can_print_tdc_const_opt(tb[IFLA_CAN_TDC]); + can_print_tdc_const_opt(tb[IFLA_CAN_TDC], false); close_json_object(); } @@ -610,6 +705,94 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) close_json_array(PRINT_ANY, " ]"); } + /* data bittiming is irrelevant if fixed bitrate is defined */ + if (tb[IFLA_CAN_XL_DATA_BITTIMING] && + !tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) { + struct can_bittiming *dbt = + RTA_DATA(tb[IFLA_CAN_XL_DATA_BITTIMING]); + char dsp[6]; + + open_json_object("xl_data_bittiming"); + can_print_nl_indent(); + print_uint(PRINT_ANY, "bitrate", " xl-dbitrate %u", dbt->bitrate); + snprintf(dsp, sizeof(dsp), "%.3f", dbt->sample_point / 1000.); + print_string(PRINT_ANY, "sample_point", " xl-dsample-point %s", + dsp); + can_print_nl_indent(); + print_uint(PRINT_ANY, "tq", " xl-dtq %u", dbt->tq); + print_uint(PRINT_ANY, "prop_seg", " xl-dprop-seg %u", + dbt->prop_seg); + print_uint(PRINT_ANY, "phase_seg1", " xl-dphase-seg1 %u", + dbt->phase_seg1); + print_uint(PRINT_ANY, "phase_seg2", " xl-dphase-seg2 %u", + dbt->phase_seg2); + print_uint(PRINT_ANY, "sjw", " xl-dsjw %u", dbt->sjw); + print_uint(PRINT_ANY, "brp", " xl-dbrp %u", dbt->brp); + + if (tb[IFLA_CAN_XL_TDC]) + can_print_tdc_opt(tb[IFLA_CAN_XL_TDC], true); + + close_json_object(); + } + + /* data bittiming const is irrelevant if fixed bitrate is defined */ + if (tb[IFLA_CAN_XL_DATA_BITTIMING_CONST] && + !tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) { + struct can_bittiming_const *dbtc = + RTA_DATA(tb[IFLA_CAN_XL_DATA_BITTIMING_CONST]); + + open_json_object("xl_data_bittiming_const"); + can_print_nl_indent(); + print_string(PRINT_ANY, "name", " %s:", dbtc->name); + can_print_timing_min_max("tseg1", " xl-dtseg1", + dbtc->tseg1_min, dbtc->tseg1_max); + can_print_timing_min_max("tseg2", " xl-dtseg2", + dbtc->tseg2_min, dbtc->tseg2_max); + can_print_timing_min_max("sjw", " xl-dsjw", 1, dbtc->sjw_max); + can_print_timing_min_max("brp", " xl-dbrp", + dbtc->brp_min, dbtc->brp_max); + print_uint(PRINT_ANY, "brp_inc", " xl-dbrp_inc %u", dbtc->brp_inc); + + if (tb[IFLA_CAN_XL_TDC]) + can_print_tdc_const_opt(tb[IFLA_CAN_XL_TDC], true); + + close_json_object(); + } + + if (tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) { + __u32 *dbitrate_const = + RTA_DATA(tb[IFLA_CAN_XL_DATA_BITRATE_CONST]); + int dbitrate_cnt = + RTA_PAYLOAD(tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) / + sizeof(*dbitrate_const); + int i; + __u32 dbitrate = 0; + + if (tb[IFLA_CAN_XL_DATA_BITTIMING]) { + struct can_bittiming *dbt = + RTA_DATA(tb[IFLA_CAN_XL_DATA_BITTIMING]); + dbitrate = dbt->bitrate; + } + + can_print_nl_indent(); + print_uint(PRINT_ANY, "xl_data_bittiming_bitrate", " xl-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", " "); + } + print_uint(PRINT_ANY, NULL, + i < dbitrate_cnt - 1 ? "%8u, " : "%8u", + dbitrate_const[i]); + } + close_json_array(PRINT_ANY, " ]"); + } + if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) { __u16 *trm = RTA_DATA(tb[IFLA_CAN_TERMINATION]); __u16 *trm_const = RTA_DATA(tb[IFLA_CAN_TERMINATION_CONST]); -- 2.45.2