Re: Setting CAN FD data bitrate with libsocketcan

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux