can-calc-bit-timing: prepare for different can_bittiming (i.e. CAN-FD)
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>pull/333/head
parent
7bc81678bb
commit
7ec433f6a6
|
|
@ -2,7 +2,7 @@
|
||||||
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
|
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
|
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
|
||||||
* Copyright (C) 2016, 2021 Marc Kleine-Budde <mkl@pengutronix.de>
|
* Copyright (C) 2016, 2021, 2022 Marc Kleine-Budde <mkl@pengutronix.de>
|
||||||
*
|
*
|
||||||
* Derived from:
|
* Derived from:
|
||||||
* can_baud.c - CAN baudrate calculation
|
* can_baud.c - CAN baudrate calculation
|
||||||
|
|
@ -122,9 +122,27 @@ struct calc_bittiming_const {
|
||||||
const struct can_bittiming_const bittiming_const;
|
const struct can_bittiming_const bittiming_const;
|
||||||
|
|
||||||
const struct calc_ref_clk ref_clk[16];
|
const struct calc_ref_clk ref_clk[16];
|
||||||
|
|
||||||
const void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
const void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct calc_data {
|
||||||
|
const struct can_bittiming_const *bittiming_const;
|
||||||
|
const void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
const struct calc_ref_clk *ref_clks;
|
||||||
|
const unsigned int *bitrates;
|
||||||
|
|
||||||
|
unsigned int sample_point;
|
||||||
|
|
||||||
|
const struct calc_ref_clk *opt_ref_clk;
|
||||||
|
const unsigned int *opt_bitrates;
|
||||||
|
const struct can_bittiming *opt_bt;
|
||||||
|
|
||||||
|
bool quiet;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* minimal structs, just enough to be source level compatible
|
* minimal structs, just enough to be source level compatible
|
||||||
*/
|
*/
|
||||||
|
|
@ -529,6 +547,7 @@ static const unsigned int common_bitrates[] = {
|
||||||
50000,
|
50000,
|
||||||
20000,
|
20000,
|
||||||
10000,
|
10000,
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||||
|
|
@ -745,12 +764,13 @@ static __u32 get_cia_sample_point(__u32 bitrate)
|
||||||
return sampl_pt;
|
return sampl_pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_bit_timing(const struct calc_bittiming_const *btc,
|
static void print_bittiming_one(const struct can_bittiming_const *bittiming_const,
|
||||||
const struct can_bittiming *ref_bt,
|
const struct can_bittiming *ref_bt,
|
||||||
const struct calc_ref_clk *ref_clk,
|
const struct calc_ref_clk *ref_clk,
|
||||||
unsigned int bitrate_nominal,
|
unsigned int bitrate_nominal,
|
||||||
unsigned int sample_point_nominal,
|
unsigned int sample_point_nominal,
|
||||||
bool quiet)
|
void (*printf_btr)(struct can_bittiming *bt, bool hdr),
|
||||||
|
bool quiet)
|
||||||
{
|
{
|
||||||
struct net_device dev = {
|
struct net_device dev = {
|
||||||
.priv.clock.freq = ref_clk->clk,
|
.priv.clock.freq = ref_clk->clk,
|
||||||
|
|
@ -765,35 +785,31 @@ static void print_bit_timing(const struct calc_bittiming_const *btc,
|
||||||
printf("Bit timing parameters for %s%s%s%s with %.6f MHz ref clock\n"
|
printf("Bit timing parameters for %s%s%s%s with %.6f MHz ref clock\n"
|
||||||
"nominal real Bitrt nom real SampP\n"
|
"nominal real Bitrt nom real SampP\n"
|
||||||
"Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ",
|
"Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ",
|
||||||
btc->bittiming_const.name,
|
bittiming_const->name,
|
||||||
ref_clk->name ? " (" : "",
|
ref_clk->name ? " (" : "",
|
||||||
ref_clk->name ? ref_clk->name : "",
|
ref_clk->name ? ref_clk->name : "",
|
||||||
ref_clk->name ? ")" : "",
|
ref_clk->name ? ")" : "",
|
||||||
ref_clk->clk / 1000000.0);
|
ref_clk->clk / 1000000.0);
|
||||||
|
|
||||||
if (btc->printf_btr)
|
if (printf_btr)
|
||||||
btc->printf_btr(&bt, true);
|
printf_btr(&bt, true);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref_bt) {
|
if (ref_bt) {
|
||||||
bt = *ref_bt;
|
bt = *ref_bt;
|
||||||
|
|
||||||
if (can_fixup_bittiming(&dev, &bt, &btc->bittiming_const)) {
|
if (can_fixup_bittiming(&dev, &bt, bittiming_const)) {
|
||||||
printf("%7d ***parameters exceed controller's range***\n", bitrate_nominal);
|
printf("%7d ***parameters exceed controller's range***\n", bitrate_nominal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
|
if (can_calc_bittiming(&dev, &bt, bittiming_const)) {
|
||||||
printf("%7d ***bitrate not possible***\n", bitrate_nominal);
|
printf("%7d ***bitrate not possible***\n", bitrate_nominal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get nominal sample point */
|
|
||||||
if (!sample_point_nominal)
|
|
||||||
sample_point_nominal = get_cia_sample_point(bitrate_nominal);
|
|
||||||
|
|
||||||
bitrate_error = abs(bitrate_nominal - bt.bitrate);
|
bitrate_error = abs(bitrate_nominal - bt.bitrate);
|
||||||
sample_point_error = abs(sample_point_nominal - bt.sample_point);
|
sample_point_error = abs(sample_point_nominal - bt.sample_point);
|
||||||
|
|
||||||
|
|
@ -822,11 +838,44 @@ static void print_bit_timing(const struct calc_bittiming_const *btc,
|
||||||
printf("%4.1f%% ", /* Sample Point Error */
|
printf("%4.1f%% ", /* Sample Point Error */
|
||||||
100.0 * sample_point_error / sample_point_nominal);
|
100.0 * sample_point_error / sample_point_nominal);
|
||||||
|
|
||||||
if (btc->printf_btr)
|
if (printf_btr)
|
||||||
btc->printf_btr(&bt, false);
|
printf_btr(&bt, false);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_bittiming(const struct calc_data *data)
|
||||||
|
{
|
||||||
|
const struct calc_ref_clk *ref_clks = data->ref_clks;
|
||||||
|
|
||||||
|
while (ref_clks->clk) {
|
||||||
|
unsigned int const *bitrates = data->bitrates;
|
||||||
|
bool quiet = data->quiet;
|
||||||
|
|
||||||
|
while (*bitrates) {
|
||||||
|
unsigned int sample_point;
|
||||||
|
|
||||||
|
/* get nominal sample point */
|
||||||
|
if (data->sample_point)
|
||||||
|
sample_point = data->sample_point;
|
||||||
|
else
|
||||||
|
sample_point = get_cia_sample_point(*bitrates);
|
||||||
|
|
||||||
|
print_bittiming_one(data->bittiming_const,
|
||||||
|
data->opt_bt,
|
||||||
|
ref_clks,
|
||||||
|
*bitrates,
|
||||||
|
sample_point,
|
||||||
|
data->printf_btr,
|
||||||
|
quiet);
|
||||||
|
bitrates++;
|
||||||
|
quiet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
ref_clks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void do_list(void)
|
static void do_list(void)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
@ -835,51 +884,41 @@ static void do_list(void)
|
||||||
printf("%s\n", can_calc_consts[i].bittiming_const.name);
|
printf("%s\n", can_calc_consts[i].bittiming_const.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_calc(const char *name,
|
static void do_calc(struct calc_data *data)
|
||||||
const struct can_bittiming *opt_ref_bt,
|
|
||||||
__u32 bitrate_nominal, unsigned int spt_nominal,
|
|
||||||
struct calc_ref_clk *opt_ref_clk, bool quiet)
|
|
||||||
{
|
{
|
||||||
const struct calc_bittiming_const *btc;
|
unsigned int i;
|
||||||
const struct calc_ref_clk *ref_clk;
|
|
||||||
unsigned int i, j, k;
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
|
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
|
||||||
if (name &&
|
const struct calc_bittiming_const *btc;
|
||||||
strcmp(can_calc_consts[i].bittiming_const.name, name) != 0)
|
|
||||||
|
btc = &can_calc_consts[i];
|
||||||
|
|
||||||
|
if (data->name && strcmp(data->name, btc->bittiming_const.name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
btc = &can_calc_consts[i];
|
|
||||||
|
|
||||||
for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) {
|
if (btc->bittiming_const.name[0]) {
|
||||||
if (opt_ref_clk)
|
data->bittiming_const = &btc->bittiming_const;
|
||||||
ref_clk = opt_ref_clk;
|
data->printf_btr = btc->printf_btr;
|
||||||
|
|
||||||
|
if (data->opt_ref_clk)
|
||||||
|
data->ref_clks = data->opt_ref_clk;
|
||||||
else
|
else
|
||||||
ref_clk = &btc->ref_clk[j];
|
data->ref_clks = btc->ref_clk;
|
||||||
|
|
||||||
if (!ref_clk->clk)
|
if (data->opt_bitrates)
|
||||||
break;
|
data->bitrates = data->opt_bitrates;
|
||||||
|
else
|
||||||
|
data->bitrates = common_bitrates;
|
||||||
|
|
||||||
if (bitrate_nominal) {
|
print_bittiming(data);
|
||||||
print_bit_timing(btc, opt_ref_bt, ref_clk, bitrate_nominal,
|
|
||||||
spt_nominal, quiet);
|
|
||||||
} else {
|
|
||||||
for (k = 0; k < ARRAY_SIZE(common_bitrates); k++)
|
|
||||||
print_bit_timing(btc, opt_ref_bt, ref_clk,
|
|
||||||
common_bitrates[k],
|
|
||||||
spt_nominal, k);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
if (opt_ref_clk)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
|
printf("error: unknown CAN controller '%s', try one of these:\n\n", data->name);
|
||||||
do_list();
|
do_list();
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
@ -887,18 +926,21 @@ static void do_calc(const char *name,
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
__u32 bitrate_nominal = 0;
|
struct calc_ref_clk opt_ref_clk[] = {
|
||||||
unsigned int spt_nominal = 0;
|
{ .name = "cmd-line" },
|
||||||
struct calc_ref_clk opt_ref_clk = {
|
{ /* sentinel */ }
|
||||||
.name = "cmd-line",
|
|
||||||
};
|
};
|
||||||
struct can_bittiming bt = { 0 };
|
struct can_bittiming opt_bt[1] = { };
|
||||||
bool quiet = false, list = false;
|
unsigned int opt_bitrate[] = {
|
||||||
const char *name = NULL;
|
0,
|
||||||
|
0 /* sentinel */
|
||||||
|
};
|
||||||
|
struct calc_data data[1] = { };
|
||||||
|
bool list = false;
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
const struct option long_options[] = {
|
const struct option long_options[] = {
|
||||||
{ "tq", required_argument, 0, OPT_TQ, },
|
{ "tq", required_argument, 0, OPT_TQ, },
|
||||||
{ "prop-seg", required_argument, 0, OPT_PROP_SEG, },
|
{ "prop-seg", required_argument, 0, OPT_PROP_SEG, },
|
||||||
{ "phase-seg1", required_argument, 0, OPT_PHASE_SEG1, },
|
{ "phase-seg1", required_argument, 0, OPT_PHASE_SEG1, },
|
||||||
{ "phase-seg2", required_argument, 0, OPT_PHASE_SEG2, },
|
{ "phase-seg2", required_argument, 0, OPT_PHASE_SEG2, },
|
||||||
|
|
@ -912,11 +954,11 @@ int main(int argc, char *argv[])
|
||||||
while ((opt = getopt_long(argc, argv, "b:c:lqs:?", long_options, NULL)) != -1) {
|
while ((opt = getopt_long(argc, argv, "b:c:lqs:?", long_options, NULL)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'b':
|
case 'b':
|
||||||
bitrate_nominal = atoi(optarg);
|
opt_bitrate[0] = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
opt_ref_clk.clk = strtoul(optarg, NULL, 10);
|
opt_ref_clk->clk = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
@ -924,11 +966,11 @@ int main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
quiet = true;
|
data->quiet = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
spt_nominal = strtoul(optarg, NULL, 10);
|
data->sample_point = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
|
|
@ -937,40 +979,40 @@ int main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_TQ:
|
case OPT_TQ:
|
||||||
bt.tq = strtoul(optarg, NULL, 10);
|
opt_bt->tq = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_PROP_SEG:
|
case OPT_PROP_SEG:
|
||||||
bt.prop_seg = strtoul(optarg, NULL, 10);
|
opt_bt->prop_seg = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_PHASE_SEG1:
|
case OPT_PHASE_SEG1:
|
||||||
bt.phase_seg1 = strtoul(optarg, NULL, 10);
|
opt_bt->phase_seg1 = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_PHASE_SEG2:
|
case OPT_PHASE_SEG2:
|
||||||
bt.phase_seg2 = strtoul(optarg, NULL, 10);
|
opt_bt->phase_seg2 = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SJW:
|
case OPT_SJW:
|
||||||
bt.sjw = strtoul(optarg, NULL, 10);
|
opt_bt->sjw = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_BRP:
|
case OPT_BRP:
|
||||||
bt.brp = strtoul(optarg, NULL, 10);
|
opt_bt->brp = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_TSEG1: {
|
case OPT_TSEG1: {
|
||||||
__u32 tseg1;
|
__u32 tseg1;
|
||||||
|
|
||||||
tseg1 = strtoul(optarg, NULL, 10);
|
tseg1 = strtoul(optarg, NULL, 10);
|
||||||
bt.prop_seg = tseg1 / 2;
|
opt_bt->prop_seg = tseg1 / 2;
|
||||||
bt.phase_seg1 = tseg1 - bt.prop_seg;
|
opt_bt->phase_seg1 = tseg1 - opt_bt->prop_seg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPT_TSEG2:
|
case OPT_TSEG2:
|
||||||
bt.phase_seg2 = strtoul(optarg, NULL, 10);
|
opt_bt->phase_seg2 = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -986,23 +1028,24 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == optind + 1)
|
if (argc == optind + 1)
|
||||||
name = argv[optind];
|
data->name = argv[optind];
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
do_list();
|
do_list();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100)) {
|
if (data->sample_point && (data->sample_point >= 1000 || data->sample_point < 100))
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_calc(name,
|
if (opt_ref_clk->clk)
|
||||||
bt.prop_seg ? &bt: NULL,
|
data->opt_ref_clk = opt_ref_clk;
|
||||||
bitrate_nominal, spt_nominal,
|
if (opt_bitrate[0])
|
||||||
opt_ref_clk.clk ? &opt_ref_clk : NULL,
|
data->opt_bitrates = opt_bitrate;
|
||||||
quiet);
|
if (opt_bt->prop_seg)
|
||||||
|
data->opt_bt = opt_bt;
|
||||||
|
|
||||||
|
do_calc(data);
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue