소스 검색

change testcandbc, add log support, asc is not complete.

yuchuli 7 달 전
부모
커밋
4e692fcddf
5개의 변경된 파일1357개의 추가작업 그리고 2개의 파일을 삭제
  1. 901 0
      src/test/testcandbc/lib.c
  2. 261 0
      src/test/testcandbc/lib.h
  3. 187 2
      src/test/testcandbc/mainwindow.cpp
  4. 6 0
      src/test/testcandbc/mainwindow.h
  5. 2 0
      src/test/testcandbc/testcandbc.pro

+ 901 - 0
src/test/testcandbc/lib.c

@@ -0,0 +1,901 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * lib.c - library for command line tools
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <linux-can@vger.kernel.org>
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <linux/can.h>
+#include <linux/can/error.h>
+#include <sys/socket.h> /* for sa_family_t */
+
+#include "lib.h"
+
+#define CANID_DELIM '#'
+#define CC_DLC_DELIM '_'
+#define XL_HDR_DELIM ':'
+#define DATA_SEPERATOR '.'
+
+const char hex_asc_upper[] = "0123456789ABCDEF";
+
+#define hex_asc_upper_lo(x) hex_asc_upper[((x)&0x0F)]
+#define hex_asc_upper_hi(x) hex_asc_upper[((x)&0xF0) >> 4]
+
+static inline void put_hex_byte(char *buf, __u8 byte)
+{
+	buf[0] = hex_asc_upper_hi(byte);
+	buf[1] = hex_asc_upper_lo(byte);
+}
+
+static inline void _put_id(char *buf, int end_offset, canid_t id)
+{
+	/* build 3 (SFF) or 8 (EFF) digit CAN identifier */
+	while (end_offset >= 0) {
+		buf[end_offset--] = hex_asc_upper_lo(id);
+		id >>= 4;
+	}
+}
+
+#define put_sff_id(buf, id) _put_id(buf, 2, id)
+#define put_eff_id(buf, id) _put_id(buf, 7, id)
+
+/* CAN DLC to real data length conversion helpers */
+
+static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
+					8, 12, 16, 20, 24, 32, 48, 64};
+
+/* get data length from raw data length code (DLC) */
+unsigned char can_fd_dlc2len(unsigned char dlc)
+{
+	return dlc2len[dlc & 0x0F];
+}
+
+static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,		/* 0 - 8 */
+					9, 9, 9, 9,				/* 9 - 12 */
+					10, 10, 10, 10,				/* 13 - 16 */
+					11, 11, 11, 11,				/* 17 - 20 */
+					12, 12, 12, 12,				/* 21 - 24 */
+					13, 13, 13, 13, 13, 13, 13, 13,		/* 25 - 32 */
+					14, 14, 14, 14, 14, 14, 14, 14,		/* 33 - 40 */
+					14, 14, 14, 14, 14, 14, 14, 14,		/* 41 - 48 */
+					15, 15, 15, 15, 15, 15, 15, 15,		/* 49 - 56 */
+					15, 15, 15, 15, 15, 15, 15, 15};	/* 57 - 64 */
+
+/* map the sanitized data length to an appropriate data length code */
+unsigned char can_fd_len2dlc(unsigned char len)
+{
+	if (len > 64)
+		return 0xF;
+
+	return len2dlc[len];
+}
+
+unsigned char asc2nibble(char c)
+{
+	if ((c >= '0') && (c <= '9'))
+		return c - '0';
+
+	if ((c >= 'A') && (c <= 'F'))
+		return c - 'A' + 10;
+
+	if ((c >= 'a') && (c <= 'f'))
+		return c - 'a' + 10;
+
+	return 16; /* error */
+}
+
+int hexstring2data(char *arg, unsigned char *data, int maxdlen)
+{
+	int len = strlen(arg);
+	int i;
+	unsigned char tmp;
+
+	if (!len || len % 2 || len > maxdlen * 2)
+		return 1;
+
+	memset(data, 0, maxdlen);
+
+	for (i = 0; i < len / 2; i++) {
+		tmp = asc2nibble(*(arg + (2 * i)));
+		if (tmp > 0x0F)
+			return 1;
+
+		data[i] = (tmp << 4);
+
+		tmp = asc2nibble(*(arg + (2 * i) + 1));
+		if (tmp > 0x0F)
+			return 1;
+
+		data[i] |= tmp;
+	}
+
+	return 0;
+}
+
+/* the 8-bit VCID is optionally placed in the canxl_frame.prio element */
+#define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */
+#define CANXL_VCID_VAL_MASK 0xFFUL /* VCID is an 8-bit value */
+#define CANXL_VCID_MASK (CANXL_VCID_VAL_MASK << CANXL_VCID_OFFSET)
+
+int parse_canframe(char *cs, cu_t *cu)
+{
+	/* documentation see lib.h */
+
+	int i, idx, dlen, len;
+	int maxdlen = CAN_MAX_DLEN;
+	int mtu = CAN_MTU;
+	__u8 *data = cu->fd.data; /* fill CAN CC/FD data by default */
+	canid_t tmp;
+
+	len = strlen(cs);
+	//printf("'%s' len %d\n", cs, len);
+
+	memset(cu, 0, sizeof(*cu)); /* init CAN CC/FD/XL frame, e.g. LEN = 0 */
+
+	if (len < 4)
+		return 0;
+
+	if (cs[3] == CANID_DELIM) { /* 3 digits SFF */
+
+		idx = 4;
+		for (i = 0; i < 3; i++) {
+			if ((tmp = asc2nibble(cs[i])) > 0x0F)
+				return 0;
+			cu->cc.can_id |= tmp << (2 - i) * 4;
+		}
+
+	} else if (cs[5] == CANID_DELIM) { /* 5 digits CAN XL VCID/PRIO*/
+
+		idx = 6;
+		for (i = 0; i < 5; i++) {
+			if ((tmp = asc2nibble(cs[i])) > 0x0F)
+				return 0;
+			cu->xl.prio |= tmp << (4 - i) * 4;
+		}
+
+		/* the VCID starts at bit position 16 */
+		tmp = (cu->xl.prio << 4) & CANXL_VCID_MASK;
+		cu->xl.prio &= CANXL_PRIO_MASK;
+		cu->xl.prio |= tmp;
+
+	} else if (cs[8] == CANID_DELIM) { /* 8 digits EFF */
+
+		idx = 9;
+		for (i = 0; i < 8; i++) {
+			if ((tmp = asc2nibble(cs[i])) > 0x0F)
+				return 0;
+			cu->cc.can_id |= tmp << (7 - i) * 4;
+		}
+		if (!(cu->cc.can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe?  */
+			cu->cc.can_id |= CAN_EFF_FLAG;   /* then it is an extended frame */
+
+	} else
+		return 0;
+
+	if ((cs[idx] == 'R') || (cs[idx] == 'r')) { /* RTR frame */
+		cu->cc.can_id |= CAN_RTR_FLAG;
+
+		/* check for optional DLC value for CAN 2.0B frames */
+		if (cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
+			cu->cc.len = tmp;
+
+			/* check for optional raw DLC value for CAN 2.0B frames */
+			if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
+				tmp = asc2nibble(cs[idx]);
+				if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC))
+					cu->cc.len8_dlc = tmp;
+			}
+		}
+		return mtu;
+	}
+
+	if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
+		maxdlen = CANFD_MAX_DLEN;
+		mtu = CANFD_MTU;
+
+		/* CAN FD frame <canid>##<flags><data>* */
+		if ((tmp = asc2nibble(cs[idx + 1])) > 0x0F)
+			return 0;
+
+		cu->fd.flags = tmp;
+		cu->fd.flags |= CANFD_FDF; /* dual-use */
+		idx += 2;
+
+	} else if (cs[idx + 14] == CANID_DELIM) { /* CAN XL frame '#80:00:11223344#' */
+		maxdlen = CANXL_MAX_DLEN;
+		mtu = CANXL_MTU;
+		data = cu->xl.data; /* fill CAN XL data */
+
+		if ((cs[idx + 2] != XL_HDR_DELIM) || (cs[idx + 5] != XL_HDR_DELIM))
+			return 0;
+
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		cu->xl.flags = tmp << 4;
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		cu->xl.flags |= tmp;
+
+		/* force CAN XL flag if it was missing in the ASCII string */
+		cu->xl.flags |= CANXL_XLF;
+
+		idx++; /* skip XL_HDR_DELIM */
+
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		cu->xl.sdt = tmp << 4;
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		cu->xl.sdt |= tmp;
+
+		idx++; /* skip XL_HDR_DELIM */
+
+		for (i = 0; i < 8; i++) {
+			if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+				return 0;
+			cu->xl.af |= tmp << (7 - i) * 4;
+		}
+
+		idx++; /* skip CANID_DELIM */
+	}
+
+	for (i = 0, dlen = 0; i < maxdlen; i++) {
+		if (cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */
+			idx++;
+
+		if (idx >= len) /* end of string => end of data */
+			break;
+
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		data[i] = tmp << 4;
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		data[i] |= tmp;
+		dlen++;
+	}
+
+	if (mtu == CANXL_MTU)
+		cu->xl.len = dlen;
+	else
+		cu->fd.len = dlen;
+
+	/* check for extra DLC when having a Classic CAN with 8 bytes payload */
+	if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
+		unsigned char dlc = asc2nibble(cs[idx]);
+
+		if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC))
+			cu->cc.len8_dlc = dlc;
+	}
+
+	return mtu;
+}
+
+int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep)
+{
+	/* documentation see lib.h */
+
+	unsigned char is_canfd = cu->fd.flags;
+	int i, offset;
+	int len;
+
+	/* ensure space for string termination */
+	if (size < 1)
+		return size;
+
+	/* handle CAN XL frames */
+	if (cu->xl.flags & CANXL_XLF) {
+		len = cu->xl.len;
+
+		/* check if the CAN frame fits into the provided buffer */
+		if (sizeof("00123#11:22:12345678#") + 2 * len + (sep ? len : 0) > size - 1) {
+			/* mark buffer overflow in output */
+			memset(buf, '-', size - 1);
+			buf[size - 1] = 0;
+			return size;
+		}
+
+		/* print prio and CAN XL header content */
+		offset = sprintf(buf, "%02X%03X#%02X:%02X:%08X#",
+				 (canid_t)(cu->xl.prio & CANXL_VCID_MASK) >> CANXL_VCID_OFFSET,
+				 (canid_t)(cu->xl.prio & CANXL_PRIO_MASK),
+				 cu->xl.flags, cu->xl.sdt, cu->xl.af);
+
+		/* data */
+		for (i = 0; i < len; i++) {
+			put_hex_byte(buf + offset, cu->xl.data[i]);
+			offset += 2;
+			if (sep && (i + 1 < len))
+				buf[offset++] = '.';
+		}
+
+		buf[offset] = 0;
+
+		return offset;
+	}
+
+	/* handle CAN CC/FD frames - ensure max length values */
+	if (is_canfd)
+		len = (cu->fd.len > CANFD_MAX_DLEN) ? CANFD_MAX_DLEN : cu->fd.len;
+	else
+		len = (cu->fd.len > CAN_MAX_DLEN) ? CAN_MAX_DLEN : cu->fd.len;
+
+	/* check if the CAN frame fits into the provided buffer */
+	if (sizeof("12345678#_F") + 2 * len + (sep ? len : 0) +	\
+	    (cu->fd.can_id & CAN_RTR_FLAG ? 2 : 0) > size - 1) {
+		/* mark buffer overflow in output */
+		memset(buf, '-', size - 1);
+		buf[size - 1] = 0;
+		return size;
+	}
+
+	if (cu->fd.can_id & CAN_ERR_FLAG) {
+		put_eff_id(buf, cu->fd.can_id & (CAN_ERR_MASK | CAN_ERR_FLAG));
+		buf[8] = '#';
+		offset = 9;
+	} else if (cu->fd.can_id & CAN_EFF_FLAG) {
+		put_eff_id(buf, cu->fd.can_id & CAN_EFF_MASK);
+		buf[8] = '#';
+		offset = 9;
+	} else {
+		put_sff_id(buf, cu->fd.can_id & CAN_SFF_MASK);
+		buf[3] = '#';
+		offset = 4;
+	}
+
+	/* CAN CC frames may have RTR enabled. There are no ERR frames with RTR */
+	if (!is_canfd && cu->fd.can_id & CAN_RTR_FLAG) {
+		buf[offset++] = 'R';
+		/* print a given CAN 2.0B DLC if it's not zero */
+		if (len && len <= CAN_MAX_DLEN) {
+			buf[offset++] = hex_asc_upper_lo(cu->fd.len);
+
+			/* check for optional raw DLC value for CAN 2.0B frames */
+			if (len == CAN_MAX_DLEN) {
+				if ((cu->cc.len8_dlc > CAN_MAX_DLEN) && (cu->cc.len8_dlc <= CAN_MAX_RAW_DLC)) {
+					buf[offset++] = CC_DLC_DELIM;
+					buf[offset++] = hex_asc_upper_lo(cu->cc.len8_dlc);
+				}
+			}
+		}
+
+		buf[offset] = 0;
+		return offset;
+	}
+
+	/* any CAN FD flags */
+	if (is_canfd) {
+		/* add CAN FD specific escape char and flags */
+		buf[offset++] = '#';
+		buf[offset++] = hex_asc_upper_lo(cu->fd.flags);
+		if (sep && len)
+			buf[offset++] = '.';
+	}
+
+	/* data */
+	for (i = 0; i < len; i++) {
+		put_hex_byte(buf + offset, cu->fd.data[i]);
+		offset += 2;
+		if (sep && (i + 1 < len))
+			buf[offset++] = '.';
+	}
+
+	/* check for extra DLC when having a Classic CAN with 8 bytes payload */
+	if (!is_canfd && (len == CAN_MAX_DLEN)) {
+		unsigned char dlc = cu->cc.len8_dlc;
+
+		if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
+			buf[offset++] = CC_DLC_DELIM;
+			buf[offset++] = hex_asc_upper_lo(dlc);
+		}
+	}
+
+	buf[offset] = 0;
+
+	return offset;
+}
+
+int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view)
+{
+	/* documentation see lib.h */
+
+	unsigned char is_canfd = cu->fd.flags;
+	int i, j, dlen, offset;
+	size_t maxsize;
+	int len;
+
+	/* ensure space for string termination */
+	if (size < 1)
+		return size;
+
+	/* handle CAN XL frames */
+	if (cu->xl.flags & CANXL_XLF) {
+		len = cu->xl.len;
+
+		/* crop to CANFD_MAX_DLEN */
+		if (len > CANFD_MAX_DLEN)
+			dlen = CANFD_MAX_DLEN;
+		else
+			dlen = len;
+
+		/* check if the CAN frame fits into the provided buffer */
+		if (sizeof(".....123 [2048] (00|11:22:12345678)  ...") + 3 * dlen > size - 1) {
+			/* mark buffer overflow in output */
+			memset(buf, '-', size - 1);
+			buf[size - 1] = 0;
+			return size;
+		}
+
+		if (view & CANLIB_VIEW_INDENT_SFF) {
+			memset(buf, ' ', 5);
+			put_sff_id(buf + 5, cu->xl.prio & CANXL_PRIO_MASK);
+			offset = 8;
+		} else {
+			put_sff_id(buf, cu->xl.prio & CANXL_PRIO_MASK);
+			offset = 3;
+		}
+
+		/* print prio and CAN XL header content */
+		offset += sprintf(buf + offset, " [%04d] (%02X|%02X:%02X:%08X) ",
+				  len,
+				  (canid_t)(cu->xl.prio & CANXL_VCID_MASK) >> CANXL_VCID_OFFSET,
+				  cu->xl.flags, cu->xl.sdt, cu->xl.af);
+
+		for (i = 0; i < dlen; i++) {
+			put_hex_byte(buf + offset, cu->xl.data[i]);
+			offset += 2;
+			if (i + 1 < dlen)
+				buf[offset++] = ' ';
+		}
+
+		/* indicate cropped output */
+		if (cu->xl.len > dlen)
+			offset += sprintf(buf + offset, " ...");
+
+		buf[offset] = 0;
+
+		return offset;
+	}
+
+	/* ensure max length values */
+	if (is_canfd)
+		len = (cu->fd.len > CANFD_MAX_DLEN) ? CANFD_MAX_DLEN : cu->fd.len;
+	else
+		len = (cu->fd.len > CAN_MAX_DLEN) ? CAN_MAX_DLEN : cu->fd.len;
+
+	/* check if the CAN frame fits into the provided buffer */
+	maxsize = sizeof("12345678  [12]  ");
+	if (view & CANLIB_VIEW_BINARY)
+		dlen = 9; /* _10101010 */
+	else
+		dlen = 3; /* _AA */
+
+	if (cu->fd.can_id & CAN_RTR_FLAG) {
+		maxsize += sizeof("    remote request");
+	} else {
+		maxsize += len * dlen;
+
+		if (len <= CAN_MAX_DLEN) {
+			if (cu->fd.can_id & CAN_ERR_FLAG) {
+				maxsize += sizeof("    ERRORFRAME");
+				maxsize += (8 - len) * dlen;
+			} else if (view & CANLIB_VIEW_ASCII) {
+				maxsize += sizeof("    'a.b.CDEF'");
+				maxsize += (8 - len) * dlen;
+			}
+		}
+	}
+
+	if (maxsize > size - 1) {
+		/* mark buffer overflow in output */
+		memset(buf, '-', size - 1);
+		buf[size - 1] = 0;
+		return size;
+	}
+
+	/* initialize space for CAN-ID and length information */
+	memset(buf, ' ', 15);
+
+	if (cu->cc.can_id & CAN_ERR_FLAG) {
+		put_eff_id(buf, cu->cc.can_id & (CAN_ERR_MASK | CAN_ERR_FLAG));
+		offset = 10;
+	} else if (cu->fd.can_id & CAN_EFF_FLAG) {
+		put_eff_id(buf, cu->fd.can_id & CAN_EFF_MASK);
+		offset = 10;
+	} else {
+		if (view & CANLIB_VIEW_INDENT_SFF) {
+			put_sff_id(buf + 5, cu->fd.can_id & CAN_SFF_MASK);
+			offset = 10;
+		} else {
+			put_sff_id(buf, cu->fd.can_id & CAN_SFF_MASK);
+			offset = 5;
+		}
+	}
+
+	/* The len value is sanitized (see above) */
+	if (!is_canfd) {
+		if (view & CANLIB_VIEW_LEN8_DLC) {
+			unsigned char dlc = cu->cc.len8_dlc;
+
+			/* fall back to len if we don't have a valid DLC > 8 */
+			if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) &&
+			      (dlc <= CAN_MAX_RAW_DLC)))
+				dlc = len;
+
+			buf[offset + 1] = '{';
+			buf[offset + 2] = hex_asc_upper[dlc];
+			buf[offset + 3] = '}';
+		} else {
+			buf[offset + 1] = '[';
+			buf[offset + 2] = len + '0';
+			buf[offset + 3] = ']';
+		}
+
+		/* standard CAN frames may have RTR enabled */
+		if (cu->fd.can_id & CAN_RTR_FLAG) {
+			offset += sprintf(buf + offset + 5, " remote request");
+			return offset + 5;
+		}
+	} else {
+		buf[offset] = '[';
+		buf[offset + 1] = (len / 10) + '0';
+		buf[offset + 2] = (len % 10) + '0';
+		buf[offset + 3] = ']';
+	}
+	offset += 5;
+
+	if (view & CANLIB_VIEW_BINARY) {
+		/* _10101010 - dlen = 9, see above */
+		if (view & CANLIB_VIEW_SWAP) {
+			for (i = len - 1; i >= 0; i--) {
+				buf[offset++] = (i == len - 1) ? ' ' : SWAP_DELIMITER;
+				for (j = 7; j >= 0; j--)
+					buf[offset++] = (1 << j & cu->fd.data[i]) ? '1' : '0';
+			}
+		} else {
+			for (i = 0; i < len; i++) {
+				buf[offset++] = ' ';
+				for (j = 7; j >= 0; j--)
+					buf[offset++] = (1 << j & cu->fd.data[i]) ? '1' : '0';
+			}
+		}
+	} else {
+		/* _AA - dlen = 3, see above */
+		if (view & CANLIB_VIEW_SWAP) {
+			for (i = len - 1; i >= 0; i--) {
+				if (i == len - 1)
+					buf[offset++] = ' ';
+				else
+					buf[offset++] = SWAP_DELIMITER;
+
+				put_hex_byte(buf + offset, cu->fd.data[i]);
+				offset += 2;
+			}
+		} else {
+			for (i = 0; i < len; i++) {
+				buf[offset++] = ' ';
+				put_hex_byte(buf + offset, cu->fd.data[i]);
+				offset += 2;
+			}
+		}
+	}
+
+	buf[offset] = 0; /* terminate string */
+
+	/*
+	 * The ASCII & ERRORFRAME output is put at a fixed len behind the data.
+	 * For now we support ASCII output only for payload length up to 8 bytes.
+	 * Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console?
+	 */
+	if (len > CAN_MAX_DLEN)
+		return offset;
+
+	if (cu->fd.can_id & CAN_ERR_FLAG)
+		offset += sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME");
+	else if (view & CANLIB_VIEW_ASCII) {
+		j = dlen * (8 - len) + 4;
+		if (view & CANLIB_VIEW_SWAP) {
+			sprintf(buf + offset, "%*s", j, "`");
+			offset += j;
+			for (i = len - 1; i >= 0; i--)
+				if ((cu->fd.data[i] > 0x1F) && (cu->fd.data[i] < 0x7F))
+					buf[offset++] = cu->fd.data[i];
+				else
+					buf[offset++] = '.';
+
+			offset += sprintf(buf + offset, "`");
+		} else {
+			sprintf(buf + offset, "%*s", j, "'");
+			offset += j;
+			for (i = 0; i < len; i++)
+				if ((cu->fd.data[i] > 0x1F) && (cu->fd.data[i] < 0x7F))
+					buf[offset++] = cu->fd.data[i];
+				else
+					buf[offset++] = '.';
+
+			offset += sprintf(buf + offset, "'");
+		}
+	}
+
+	return offset;
+}
+
+static const char *error_classes[] = {
+	"tx-timeout",
+	"lost-arbitration",
+	"controller-problem",
+	"protocol-violation",
+	"transceiver-status",
+	"no-acknowledgement-on-tx",
+	"bus-off",
+	"bus-error",
+	"restarted-after-bus-off",
+	"error-counter-tx-rx",
+};
+
+static const char *controller_problems[] = {
+	"rx-overflow",
+	"tx-overflow",
+	"rx-error-warning",
+	"tx-error-warning",
+	"rx-error-passive",
+	"tx-error-passive",
+	"back-to-error-active",
+};
+
+static const char *protocol_violation_types[] = {
+	"single-bit-error",
+	"frame-format-error",
+	"bit-stuffing-error",
+	"tx-dominant-bit-error",
+	"tx-recessive-bit-error",
+	"bus-overload",
+	"active-error",
+	"error-on-tx",
+};
+
+static const char *protocol_violation_locations[] = {
+	"unspecified",
+	"unspecified",
+	"id.28-to-id.21",
+	"start-of-frame",
+	"bit-srtr",
+	"bit-ide",
+	"id.20-to-id.18",
+	"id.17-to-id.13",
+	"crc-sequence",
+	"reserved-bit-0",
+	"data-field",
+	"data-length-code",
+	"bit-rtr",
+	"reserved-bit-1",
+	"id.4-to-id.0",
+	"id.12-to-id.5",
+	"unspecified",
+	"active-error-flag",
+	"intermission",
+	"tolerate-dominant-bits",
+	"unspecified",
+	"unspecified",
+	"passive-error-flag",
+	"error-delimiter",
+	"crc-delimiter",
+	"acknowledge-slot",
+	"end-of-frame",
+	"acknowledge-delimiter",
+	"overload-flag",
+	"unspecified",
+	"unspecified",
+	"unspecified",
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+static int snprintf_error_data(char *buf, size_t len, uint8_t err,
+			       const char **arr, int arr_len)
+{
+	int i, n = 0, count = 0;
+
+	if (!err || len <= 0)
+		return 0;
+
+	for (i = 0; i < arr_len; i++) {
+		if (err & (1 << i)) {
+			int tmp_n = 0;
+			if (count) {
+				/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
+				tmp_n = snprintf(buf + n, len - n, ",");
+				if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
+					return n;
+				}
+				n += tmp_n;
+			}
+			tmp_n = snprintf(buf + n, len - n, "%s", arr[i]);
+			if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
+				return n;
+			}
+			n += tmp_n;
+			count++;
+		}
+	}
+
+	return n;
+}
+
+static int snprintf_error_lostarb(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	if (len <= 0)
+		return 0;
+	return snprintf(buf, len, "{at bit %d}", cf->data[0]);
+}
+
+static int snprintf_error_ctrl(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	int n = 0;
+
+	if (len <= 0)
+		return 0;
+
+	n += snprintf(buf + n, len - n, "{");
+	n += snprintf_error_data(buf + n, len - n, cf->data[1],
+				controller_problems,
+				ARRAY_SIZE(controller_problems));
+	n += snprintf(buf + n, len - n, "}");
+
+	return n;
+}
+
+static int snprintf_error_prot(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	int n = 0;
+
+	if (len <= 0)
+		return 0;
+
+	n += snprintf(buf + n, len - n, "{{");
+	n += snprintf_error_data(buf + n, len - n, cf->data[2],
+				protocol_violation_types,
+				ARRAY_SIZE(protocol_violation_types));
+	n += snprintf(buf + n, len - n, "}{");
+	if (cf->data[3] > 0 &&
+	    cf->data[3] < ARRAY_SIZE(protocol_violation_locations))
+		n += snprintf(buf + n, len - n, "%s",
+			      protocol_violation_locations[cf->data[3]]);
+	n += snprintf(buf + n, len - n, "}}");
+
+	return n;
+}
+
+static int snprintf_error_cnt(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	int n = 0;
+
+	if (len <= 0)
+		return 0;
+
+	n += snprintf(buf + n, len - n, "{{%d}{%d}}",
+		      cf->data[6], cf->data[7]);
+
+	return n;
+}
+
+int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
+                  const char* sep)
+{
+	canid_t class, mask;
+	int i, n = 0, classes = 0;
+	char *defsep = ",";
+
+	if (!(cf->can_id & CAN_ERR_FLAG))
+		return 0;
+
+	class = cf->can_id & CAN_EFF_MASK;
+	if (class > (1 << ARRAY_SIZE(error_classes))) {
+		fprintf(stderr, "Error class %#x is invalid\n", class);
+		return 0;
+	}
+
+	if (!sep)
+		sep = defsep;
+
+	for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
+		mask = 1 << i;
+		if (class & mask) {
+			int tmp_n = 0;
+			if (classes) {
+				/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
+				tmp_n = snprintf(buf + n, len - n, "%s", sep);
+				if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
+					buf[0] = 0; /* empty terminated string */
+					return 0;
+				}
+				n += tmp_n;
+			}
+			tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]);
+			if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
+				buf[0] = 0; /* empty terminated string */
+				return 0;
+			}
+			n += tmp_n;
+			if (mask == CAN_ERR_LOSTARB)
+				n += snprintf_error_lostarb(buf + n, len - n,
+							   cf);
+			if (mask == CAN_ERR_CRTL)
+				n += snprintf_error_ctrl(buf + n, len - n, cf);
+			if (mask == CAN_ERR_PROT)
+				n += snprintf_error_prot(buf + n, len - n, cf);
+			if (mask == CAN_ERR_CNT)
+				n += snprintf_error_cnt(buf + n, len - n, cf);
+			classes++;
+		}
+	}
+
+	if (!(cf->can_id & CAN_ERR_CNT) && (cf->data[6] || cf->data[7])) {
+		n += snprintf(buf + n, len - n, "%serror-counter-tx-rx", sep);
+		n += snprintf_error_cnt(buf + n, len - n, cf);
+	}
+
+	return n;
+}
+
+int64_t timespec_diff_ms(struct timespec *ts1,
+					  struct timespec *ts2)
+{
+	int64_t diff = (ts1->tv_sec - ts2->tv_sec) * 1000;
+
+	diff += (ts1->tv_nsec - ts2->tv_nsec) / 1000000;
+
+	return diff;
+}
+
+void timespec_add_ms(struct timespec *ts, uint64_t milliseconds)
+{
+	uint64_t total_ns = ts->tv_nsec + (milliseconds * 1000000);
+
+	ts->tv_sec += total_ns / 1000000000;
+	ts->tv_nsec = total_ns % 1000000000;
+}

+ 261 - 0
src/test/testcandbc/lib.h

@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * lib.h - library include for command line tools
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <linux-can@vger.kernel.org>
+ *
+ */
+
+#ifndef CAN_UTILS_LIB_H
+#define CAN_UTILS_LIB_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+__attribute__((format (printf, 1, 2)))
+static inline int pr_debug(const char* fmt, ...) {return 0;}
+#endif
+
+/* CAN CC/FD/XL frame union */
+typedef union {
+	struct can_frame cc;
+	struct canfd_frame fd;
+	struct canxl_frame xl;
+} cu_t;
+
+/*
+ * The buffer size for ASCII CAN frame string representations
+ * covers also the 'long' CAN frame output from sprint_long_canframe()
+ * including (swapped) binary represetations, timestamps, netdevice names,
+ * lengths and error message details as the CAN XL data is cropped to 64
+ * byte (the 'long' CAN frame output is only for display on terminals).
+ */
+#define AFRSZ 6300 /* 3*2048 (data) + 22 (timestamp) + 18 (netdev) + ID/HDR */
+
+/* CAN DLC to real data length conversion helpers especially for CAN FD */
+
+/* get data length from raw data length code (DLC) */
+unsigned char can_fd_dlc2len(unsigned char dlc);
+
+/* map the sanitized data length to an appropriate data length code */
+unsigned char can_fd_len2dlc(unsigned char len);
+
+unsigned char asc2nibble(char c);
+/*
+ * Returns the decimal value of a given ASCII hex character.
+ *
+ * While 0..9, a..f, A..F are valid ASCII hex characters.
+ * On invalid characters the value 16 is returned for error handling.
+ */
+
+int hexstring2data(char *arg, unsigned char *data, int maxdlen);
+/*
+ * Converts a given ASCII hex string to a (binary) byte string.
+ *
+ * A valid ASCII hex string consists of an even number of up to 16 chars.
+ * Leading zeros '00' in the ASCII hex string are interpreted.
+ *
+ * Examples:
+ *
+ * "1234"   => data[0] = 0x12, data[1] = 0x34
+ * "001234" => data[0] = 0x00, data[1] = 0x12, data[2] = 0x34
+ *
+ * Return values:
+ * 0 = success
+ * 1 = error (in length or the given characters are no ASCII hex characters)
+ *
+ * Remark: The not written data[] elements are initialized with zero.
+ *
+ */
+
+int parse_canframe(char *cs, cu_t *cu);
+/*
+ * Transfers a valid ASCII string describing a CAN frame into the CAN union
+ * containing CAN CC/FD/XL structs.
+ *
+ * CAN CC frames (aka Classical CAN, CAN 2.0B)
+ * - string layout <can_id>#{R{len}|data}{_len8_dlc}
+ * - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
+ * - {len} can take values from 0 to 8 and can be omitted if zero
+ * - {_len8_dlc} can take hex values from '_9' to '_F' when len is CAN_MAX_DLEN
+ * - return value on successful parsing: CAN_MTU
+ *
+ * CAN FD frames
+ * - string layout <can_id>##<flags>{data}
+ * - <flags> a single ASCII Hex value (0 .. F) which defines canfd_frame.flags
+ * - {data} has 0 to 64 hex-values that can (optionally) be separated by '.'
+ * - return value on successful parsing: CANFD_MTU
+ *
+ * CAN XL frames
+ * - string layout <vcid><prio>#<flags>:<sdt>:<af>#{data}
+ * - <vcid> a two ASCII Hex value (00 .. FF) which defines the VCID
+ * - <prio> a three ASCII Hex value (000 .. 7FF) which defines the 11 bit PRIO
+ * - <flags> a two ASCII Hex value (00 .. FF) which defines canxl_frame.flags
+ * - <sdt> a two ASCII Hex value (00 .. FF) which defines canxl_frame.sdt
+ * - <af> a 8 digit ASCII Hex value which defines the 32 bit canxl_frame.af
+ * - {data} has 1 to 2048 hex-values that can (optionally) be separated by '.'
+ * - return value on successful parsing: CANXL_MTU
+ *
+ * Return value on detected problems: 0
+ *
+ * <can_id> can have 3 (standard frame format) or 8 (extended frame format)
+ * hexadecimal chars
+ *
+ *
+ * Examples:
+ *
+ * 123# -> standard CAN-Id = 0x123, len = 0
+ * 12345678# -> extended CAN-Id = 0x12345678, len = 0
+ * 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
+ * 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
+ * 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
+ * 123#R8_9 -> standard CAN-Id = 0x123, len = 8, dlc = 9, RTR-frame
+ * 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
+ *
+ * 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
+ * 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
+ * 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14
+ * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
+ * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
+ * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ *
+ * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
+ * 123##1112233 -> CAN FD frame, flags = CANFD_BRS, len = 3
+ * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
+ * 123##3 -> CAN FD frame, flags = (CANFD_ESI | CANFD_BRS), len = 0
+ *     ^^
+ *     CAN FD extension to handle the canfd_frame.flags content
+ *
+ * 45123#81:00:12345678#11223344.556677 -> CAN XL frame with len = 7,
+ *   VCID = 0x45, PRIO = 0x123, flags = 0x81, sdt = 0x00, af = 0x12345678
+ *
+ * Simple facts on this compact ASCII CAN frame representation:
+ *
+ * - 3 digits: standard frame format
+ * - 8 digits: extendend frame format OR error frame
+ * - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
+ * - an error frame is never a RTR frame
+ * - CAN FD frames do not have a RTR bit
+ */
+
+int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep);
+/*
+ * Creates a CAN frame hexadecimal output in compact format.
+ * The CAN data[] is separated by '.' when sep != 0.
+ *
+ * A CAN XL frame is detected when CANXL_XLF is set in the struct
+ * cu.canxl_frame.flags. Otherwise the type of the CAN frame (CAN CC/FD)
+ * is specified by the dual-use struct cu.canfd_frame.flags element:
+ * w/o  CAN FD flags (== 0) -> CAN CC frame (aka Classical CAN, CAN2.0B)
+ * with CAN FD flags (!= 0) -> CAN FD frame (with CANFD_[FDF/BRS/ESI])
+ *
+ * 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0
+ * 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14, data, sep = 0
+ * 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
+ * 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
+ * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
+ * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
+ * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
+ * 45123#81:00:12345678#11223344.556677 -> CAN XL frame with len = 7,
+ *   VCID = 0x45, PRIO = 0x123, flags = 0x81, sdt = 0x00, af = 0x12345678
+ *
+ */
+
+#define CANLIB_VIEW_ASCII	0x1
+#define CANLIB_VIEW_BINARY	0x2
+#define CANLIB_VIEW_SWAP	0x4
+#define CANLIB_VIEW_ERROR	0x8
+#define CANLIB_VIEW_INDENT_SFF	0x10
+#define CANLIB_VIEW_LEN8_DLC	0x20
+
+#define SWAP_DELIMITER '`'
+
+int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view);
+/*
+ * Creates a CAN frame hexadecimal output in user readable format.
+ *
+ * A CAN XL frame is detected when CANXL_XLF is set in the struct
+ * cu.canxl_frame.flags. Otherwise the type of the CAN frame (CAN CC/FD)
+ * is specified by the dual-use struct cu.canfd_frame.flags element:
+ * w/o  CAN FD flags (== 0) -> CAN CC frame (aka Classical CAN, CAN2.0B)
+ * with CAN FD flags (!= 0) -> CAN FD frame (with CANFD_[FDF/BRS/ESI])
+ *
+ * 12345678   [3]  11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data
+ * 12345678   [0]  remote request -> extended CAN-Id = 0x12345678, RTR
+ * 14B0DC51   [8]  4A 94 E8 2A EC 58 55 62   'J..*.XUb' -> (with ASCII output)
+ * 321   {B}  11 22 33 44 55 66 77 88 -> Classical CAN with raw '{DLC}' value B
+ * 20001111   [7]  C6 23 7B 32 69 98 3C      ERRORFRAME -> (CAN_ERR_FLAG set)
+ * 12345678  [03]  11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, len = 3
+ *      123 [0003] (45|81:00:12345678) 11 22 33 -> CAN XL frame with VCID 0x45
+ *
+ * 123   [3]  11 22 33         -> CANLIB_VIEW_INDENT_SFF == 0
+ *      123   [3]  11 22 33    -> CANLIB_VIEW_INDENT_SFF == set
+ *
+ * There are no binary or ASCII view modes for CAN XL and the number of displayed
+ * data bytes is limited to 64 to fit terminal output use-cases.
+ */
+
+int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
+			     const char *sep);
+/*
+ * Creates a CAN error frame output in user readable format.
+ */
+
+/**
+ * timespec_diff_ms - calculate timespec difference in milliseconds
+ * @ts1: first timespec
+ * @ts2: second timespec
+ *
+ * Return negative difference if in the past.
+ */
+int64_t timespec_diff_ms(struct timespec *ts1, struct timespec *ts2);
+
+/**
+ * timespec_add_ms - add milliseconds to timespec
+ * @ts: timespec
+ * @milliseconds: milliseconds to add
+ */
+void timespec_add_ms(struct timespec *ts, uint64_t milliseconds);
+
+#endif

+ 187 - 2
src/test/testcandbc/mainwindow.cpp

@@ -4,6 +4,14 @@
 #include <QFileDialog>
 #include <iostream>
 
+
+#include <linux/can.h>
+
+extern "C"
+{
+#include "lib.h"
+}
+
 MainWindow::MainWindow(QWidget *parent)
     : QMainWindow(parent)
     , ui(new Ui::MainWindow)
@@ -21,10 +29,17 @@ MainWindow::~MainWindow()
 
 void MainWindow::on_LoadDump_clicked()
 {
-    QString str = QFileDialog::getOpenFileName(this,"Load candump file",".","*.txt");
+    QString str = QFileDialog::getOpenFileName(this,"Load candump file",".","Dump File(*.txt);;log File(*.log);;ASC File(*.asc);;");
     if(str.isEmpty())return;
 
-    LoadDump(str);
+    if(str.right(4) == ".txt")
+        LoadDump(str);
+
+    if(str.right(4) == ".log")
+        LoadLog(str);
+
+    if(str.right(4) == ".asc")
+        LoadAsc(str);
 }
 
 
@@ -65,6 +80,7 @@ bool MainWindow::LoadDump(QString strpath)
         nread = xFile.readLine(pstrline,nlinedatamax);
     }
     xFile.close();
+    delete [] pstrline;
     ui->lineEdit_FrameCount->setText(QString::number(mvectorFrame.size()));
 
     if(mvectorFrame.size() > 0)
@@ -125,6 +141,175 @@ bool MainWindow::parsedumpline(char *strline,struct CanFrame & xFrame)
 
 }
 
+bool MainWindow::LoadLog(QString strpath)
+{
+    QFile xFile;
+    xFile.setFileName(strpath);
+    if(!xFile.open(QIODevice::ReadOnly))
+    {
+        return false;
+    }
+    mvectorFrame.clear();
+    mvectorrawframe.clear();
+    const int nlinedatamax = 1000;
+    char * pstrline = new char[nlinedatamax];
+    int64_t nread = 0;
+    nread = xFile.readLine(pstrline,nlinedatamax);
+    while(nread > 0)
+    {
+        struct CanFrame xFrame;
+        if(parselogline(pstrline,xFrame))
+        {
+            mvectorFrame.push_back(xFrame);
+            mvectorrawframe.push_back(QString(pstrline));
+        }
+        //       std::cout<<" line data: "<<pstrline<<std::endl;
+        nread = xFile.readLine(pstrline,nlinedatamax);
+    }
+    delete [] pstrline;
+    xFile.close();
+    ui->lineEdit_FrameCount->setText(QString::number(mvectorFrame.size()));
+
+    if(mvectorFrame.size() > 0)
+    {
+        ui->lineEdit_CurrentFrame->setText("0");
+        ui->plainTextEdit_Frame->setPlainText(mvectorrawframe[0]);
+        updateparse();
+    }
+    else
+    {
+        ui->lineEdit_CurrentFrame->setText("");
+        ui->plainTextEdit_Frame->setPlainText("");
+    }
+    return true;
+}
+
+bool MainWindow::parselogline(char * strline,struct CanFrame & xFrame)
+{
+    xFrame.dat.clear();
+    QString str(strline);
+    QStringList strlist = str.split(" ",Qt::SkipEmptyParts);
+
+    // char device[22], afrbuf[AFRSZ];
+    // unsigned long long sec, usec;
+    cu_t cu;
+
+    if(strlist.size() >= 3)
+    {
+        QString strdat = strlist[2];
+
+        if(strdat.right(1) == '\n')strdat.chop(1);
+        int mtu = parse_canframe(strdat.toLatin1().data(), &cu);
+
+        /* convert only CAN CC and CAN FD frames */
+        if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) {
+            printf("no valid CAN CC/FD frame\n");
+            return false;
+        }
+
+        struct CanFrame xFrame;
+        xFrame.address =  cu.fd.can_id;
+        xFrame.src = 0;
+        int i;
+        for(i=0;i<cu.fd.len;i++)
+        {
+            xFrame.dat.push_back(cu.fd.data[i]);
+        }
+
+
+
+
+
+
+    }
+    else
+    {
+        return false;
+    }
+    return true;
+}
+
+bool MainWindow::LoadAsc(QString strpath)
+{
+    QFile xFile;
+    xFile.setFileName(strpath);
+    if(!xFile.open(QIODevice::ReadOnly))
+    {
+        return false;
+    }
+    mvectorFrame.clear();
+    mvectorrawframe.clear();
+    const int nlinedatamax = 1000;
+    char * pstrline = new char[nlinedatamax];
+    int64_t nread = 0;
+    nread = xFile.readLine(pstrline,nlinedatamax);
+    while(nread > 0)
+    {
+        struct CanFrame xFrame;
+        if(parseascline(pstrline,xFrame))
+        {
+            mvectorFrame.push_back(xFrame);
+            mvectorrawframe.push_back(QString(pstrline));
+        }
+        //       std::cout<<" line data: "<<pstrline<<std::endl;
+        nread = xFile.readLine(pstrline,nlinedatamax);
+    }
+    xFile.close();
+    delete [] pstrline;
+    ui->lineEdit_FrameCount->setText(QString::number(mvectorFrame.size()));
+
+    if(mvectorFrame.size() > 0)
+    {
+        ui->lineEdit_CurrentFrame->setText("0");
+        ui->plainTextEdit_Frame->setPlainText(mvectorrawframe[0]);
+        updateparse();
+    }
+    else
+    {
+        ui->lineEdit_CurrentFrame->setText("");
+        ui->plainTextEdit_Frame->setPlainText("");
+    }
+    return true;
+}
+
+bool MainWindow::parseascline(char * strline,struct CanFrame & xFrame)
+{
+    xFrame.dat.clear();
+    QString str(strline);
+    QStringList strlist = str.split(" ",Qt::SkipEmptyParts);
+
+    int npart = strlist.size();
+
+    if(npart<9)
+    {
+        return false;
+    }
+
+    int nlen = strlist[8].toInt();
+    QString strid = strlist[4];
+
+    xFrame.src = 0;
+    sscanf(strid.toLatin1().data(),"%x",&xFrame.address);
+
+    if((nlen + 8) > npart)
+    {
+        std::cout<<" asc data not complete. "<<strline<<std::endl;
+        return false;
+    }
+
+    int i;
+    for(i=0;i<nlen;i++)
+    {
+        unsigned char c1;
+        int npos = i+ 9;
+        sscanf(strlist.at(npos).toLatin1().data(),"%02X",&c1);
+        xFrame.dat.push_back(c1);
+    }
+
+    return true;
+}
+
+
 
 void MainWindow::on_pushButton_Pre_clicked()
 {

+ 6 - 0
src/test/testcandbc/mainwindow.h

@@ -43,6 +43,12 @@ private:
     bool LoadDump(QString strpath);
     bool parsedumpline(char * strline,struct CanFrame & xFrame);
 
+    bool LoadLog(QString strpath);
+    bool parselogline(char * strline,struct CanFrame & xFrame);
+
+    bool LoadAsc(QString strpath);
+    bool parseascline(char * strline,struct CanFrame & xFrame);
+
     void updateparse();
 
 private:

+ 2 - 0
src/test/testcandbc/testcandbc.pro

@@ -9,10 +9,12 @@ CONFIG += c++17
 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
 
 SOURCES += \
+    lib.c \
     main.cpp \
     mainwindow.cpp
 
 HEADERS += \
+    lib.h \
     mainwindow.h
 
 FORMS += \