On 03/25/2018 12:46 PM, André Hartmann wrote: > Hi Marc all, > > after very long time I was able to test Lars' patch for CAN FD > data bitrate setting in libsocketcan. I think this is a very > useful feature still missing in this library. > > I tested it, and it works fine in my setup. > > I did some editorial changes to the original patch and asking for > inclusion in libsocketcan hereby. I already got Lars Susaas > approval for that. Please send patches with git send-email, not as an attachment. > From c92d50adb6fb61ef16170b057341aa8b9c56cf38 Mon Sep 17 00:00:00 2001 > From: Lars Elgtvedt Susaas <larssusaas@xxxxxxxxx> > Date: Sun, 25 Feb 2018 18:46:14 +0100 > Subject: [PATCH] Get and set CAN FD data bitrate > > Imported from https://bitbucket.org/nimrof/canfestival-3-asc > > Tested with a PCAN USB Pro FD and Kernel 4.9.0. > > Done-with: Andre Hartmann <aha_1980@xxxxxx> > --- > include/libsocketcan.h | 5 ++ > src/libsocketcan.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 192 insertions(+) > > diff --git a/include/libsocketcan.h b/include/libsocketcan.h > index dc52053..7a3a903 100644 > --- a/include/libsocketcan.h > +++ b/include/libsocketcan.h > @@ -41,6 +41,9 @@ int can_set_bittiming(const char *name, struct can_bittiming *bt); > int can_set_ctrlmode(const char *name, struct can_ctrlmode *cm); > int can_set_bitrate(const char *name, __u32 bitrate); > int can_set_bitrate_samplepoint(const char *name, __u32 bitrate, __u32 sample_point); > +int can_set_data_bittiming(const char *name, struct can_bittiming *databt); > +int can_set_data_bitrate(const char *name, __u32 bitrate); > +int can_set_data_bitrate_samplepoint(const char *name, __u32 bitrate,__u32 sample_point); ^^ space > > int can_get_restart_ms(const char *name, __u32 *restart_ms); > int can_get_bittiming(const char *name, struct can_bittiming *bt); > @@ -49,6 +52,8 @@ int can_get_state(const char *name, int *state); > int can_get_clock(const char *name, struct can_clock *clock); > int can_get_bittiming_const(const char *name, struct can_bittiming_const *btc); > int can_get_berr_counter(const char *name, struct can_berr_counter *bc); > +int can_get_data_bittiming(const char *name, struct can_bittiming *bt); > +int can_get_data_bittiming_const(const char *name, struct can_bittiming_const *btc); > int can_get_device_stats(const char *name, struct can_device_stats *cds); > > #ifdef __cplusplus > diff --git a/src/libsocketcan.c b/src/libsocketcan.c > index c97a28c..3a545fe 100644 > --- a/src/libsocketcan.c > +++ b/src/libsocketcan.c > @@ -54,6 +54,8 @@ > #define GET_BITTIMING_CONST 6 > #define GET_BERR_COUNTER 7 > #define GET_XSTATS 8 > +#define GET_DATA_BITTIMING 9 > +#define GET_DATA_BITTIMING_CONST 10 > > struct get_req { > struct nlmsghdr n; > @@ -72,6 +74,7 @@ struct req_info { > __u32 restart_ms; > struct can_ctrlmode *ctrlmode; > struct can_bittiming *bittiming; > + struct can_bittiming *databittiming; > }; > > static void > @@ -481,6 +484,26 @@ static int do_get_nl_link(int fd, __u8 acquire, const char *name, void *res) > fprintf(stderr, "no berr_counter data found\n"); > > break; > + case GET_DATA_BITTIMING: > + if (can_attr[IFLA_CAN_DATA_BITTIMING]) { > + memcpy(res, > + RTA_DATA(can_attr[IFLA_CAN_DATA_BITTIMING]), > + sizeof(struct can_bittiming)); > + ret = 0; > + } else > + fprintf(stderr, "no bittiming_const data found\n"); > + > + break; > + case GET_DATA_BITTIMING_CONST: > + if (can_attr[IFLA_CAN_DATA_BITTIMING_CONST]) { > + memcpy(res, > + RTA_DATA(can_attr[IFLA_CAN_DATA_BITTIMING_CONST]), > + sizeof(struct can_bittiming_const)); > + ret = 0; > + } else > + fprintf(stderr, "no data_bittiming_const data found\n"); > + > + break; > > default: > fprintf(stderr, "unknown acquire mode\n"); > @@ -601,6 +624,12 @@ static int do_set_nl_link(int fd, __u8 if_state, const char *name, > sizeof(struct can_bittiming)); > } > > + if (req_info->databittiming != NULL) { > + addattr_l(&req.n, 1024, IFLA_CAN_DATA_BITTIMING, > + req_info->databittiming, > + sizeof(struct can_bittiming)); > + } > + > if (req_info->ctrlmode != NULL) { > addattr_l(&req.n, 1024, IFLA_CAN_CTRLMODE, > req_info->ctrlmode, > @@ -929,6 +958,106 @@ int can_set_bitrate_samplepoint(const char *name, __u32 bitrate, > > /** > * @ingroup extern > + * can_set_data_bittiming - setup the data bittiming. > + * > + * @param name name of the can device. This is the netdev name, as ifconfig -a shows > + * in your system. usually it contains prefix "can" and the numer of the can > + * line. e.g. "can0" > + * @param bt pointer to a can_bittiming struct > + * > + * This sets the data bittiming of the can device. This is for advantage usage. > + * > + * Please see can_set_bittiming for more information about bit timing. > + * > + * @return 0 if success > + * @return -1 if failed > + */ > +int can_set_data_bittiming(const char *name, struct can_bittiming *databt) > +{ > + int result; > + struct can_ctrlmode cm; > + struct can_bittiming bitTiming; > + > + memset(&cm, 0, sizeof(cm)); > + > + // Need to enable can FD to be able to set data bit timing > + cm.mask = CAN_CTRLMODE_FD; > + cm.flags = CAN_CTRLMODE_FD; I'm not sure if you want to enable the FD implicitly here, use can_set_ctrlmode() from your application instead. > + > + result = can_get_bittiming(name,&bitTiming); > + if (result == -1) > + return result; Why do you get the bittiming from the kernel here? > + > + // Kernel wants to recalc, remove bitrate to avoid EINVAL in can_get_bittiming > + bitTiming.bitrate = 0; > + > + struct req_info req_info = { > + .bittiming = &bitTiming, and why do you set it? > + .databittiming = databt, > + .ctrlmode = &cm > + }; > + > + return set_link(name, 0, &req_info); > +} > + > +/** > + * @ingroup extern > + * can_set_data_bitrate - setup the data bitrate. > + * > + * @param name name of the can device. This is the netdev name, as ifconfig -a shows > + * in your system. usually it contains prefix "can" and the numer of the can > + * line. e.g. "can0" > + * @param bitrate data bitrate of the can bus > + * > + * This is the recommended way to setup the bus bit timing. You only have to > + * give a bitrate value here. The exact bit timing will be calculated > + * automatically. To use this function, make sure that CONFIG_CAN_CALC_BITTIMING > + * is set to y in your kernel configuration. > + * > + * @return 0 if success > + * @return -1 if failed > + */ > +int can_set_data_bitrate(const char *name, __u32 bitrate) > +{ > + struct can_bittiming bt; Use C99 initializers here: struct can_bittiming bt = { .bitrate = bitrate, }; > + > + memset(&bt, 0, sizeof(bt)); > + bt.bitrate = bitrate; ...so you can remove the memset() and the assignment. > + > + return can_set_data_bittiming(name, &bt); > +} > + > +/** > + * @ingroup extern > + * can_set_data_bitrate_samplepoint - setup the data bitrate. > + * > + * @param name name of the can device. This is the netdev name, as ifconfig -a shows > + * in your system. usually it contains prefix "can" and the numer of the can > + * line. e.g. "can0" > + * @param bitrate data bitrate of the can bus > + * @param sample_point sample point value > + * > + * This one is similar to can_set_date_bitrate, only you can additionally set up the > + * time point for sampling (sample point) customly instead of using the > + * CIA recommended value. sample_point can be a value between 0 and 999. > + * > + * @return 0 if success > + * @return -1 if failed > + */ > +int can_set_data_bitrate_samplepoint(const char *name, __u32 bitrate, > + __u32 sample_point) > +{ > + struct can_bittiming bt; > + > + memset(&bt, 0, sizeof(bt)); > + bt.bitrate = bitrate; > + bt.sample_point = sample_point; same here > + > + return can_set_data_bittiming(name, &bt); > +} > + > +/** > + * @ingroup extern > * can_get_state - get the current state of the device > * > * @param name name of the can device. This is the netdev name, as ifconfig -a shows > @@ -1114,6 +1243,64 @@ int can_get_berr_counter(const char *name, struct can_berr_counter *bc) > > /** > * @ingroup extern > + * can_get_data_bittiming - get the current data bit timing configuration. > + * > + * @param name name of the can device. This is the netdev name, as ifconfig -a shows > + * in your system. usually it contains prefix "can" and the numer of the can > + * line. e.g. "can0" > + * @param bt pointer to the bittiming struct. > + * > + * This one stores the current data bittiming configuration. > + * > + * Please see can_set_bittiming for more information about bit timing. > + * > + * @return 0 if success > + * @return -1 if failed > + */ > +int can_get_data_bittiming(const char *name, struct can_bittiming *bt) > +{ > + return get_link(name, GET_DATA_BITTIMING, bt); > +} > + > +/** > + * @ingroup extern > + * can_get_data_bittiming_const - get the current data bit timing constant. > + * > + * @param name name of the can device. This is the netdev name, as ifconfig -a shows > + * in your system. usually it contains prefix "can" and the numer of the can > + * line. e.g. "can0" > + * @param btc pointer to the bittiming constant struct. > + * > + * This one stores the hardware dependent data bittiming constant. The > + * can_bittiming_const struct consists: > + * > + * @code > + * struct can_bittiming_const { > + * char name[16]; > + * __u32 tseg1_min; > + * __u32 tseg1_max; > + * __u32 tseg2_min; > + * __u32 tseg2_max; > + * __u32 sjw_max; > + * __u32 brp_min; > + * __u32 brp_max; > + * __u32 brp_inc; > + * }; > + * @endcode > + * > + * The information in this struct is used to calculate the bus bit timing > + * automatically. > + * > + * @return 0 if success > + * @return -1 if failed > + */ > +int can_get_data_bittiming_const(const char *name, struct can_bittiming_const *btc) > +{ > + return get_link(name, GET_DATA_BITTIMING_CONST, btc); > +} > + > +/** > + * @ingroup extern > * can_get_device_stats - get the can_device_stats. > * > * @param name name of the can device. This is the netdev name, as ifconfig -a shows > -- > 2.7.4 > Marc -- Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Attachment:
signature.asc
Description: OpenPGP digital signature