Commit a05baa15 authored by Ille, Ondrej, Ing.'s avatar Ille, Ondrej, Ing.

Implemented Kvaalt logger for recording

Kvaser CAN FD Frames by Altera logic Analyzer
Signal TAP II.
parent 54fdf042
CFLAGS = -Wall
CC = gcc
LIBS = -lcanlib -lpthread -lm -lutil
INCLUDE = kvalt_logger.c kvaser.c stp.c data_processor.c
all:
@echo ***** Building Kvaser/Altera CAN logger *****
rm -rf build
mkdir build
$(CC) $(CFLAGS) -o build/kvalt_logger $(INCLUDE) $(LIBS)
clean:
@echo ***** Cleaning Kvaser/Altera CAN logger *****
rm -rf build
# Kvaalt Logger
Generator / Logger for Kvaser and Quartus FPGAs.
To run this program following must be available:
1. Quartus must be installed with Signal TAP II Logic Analyzer. Logic analyzer must be in "/opt/quartus/bin/quartus_stp"
2. CAN Library from Kvaser must be installed.
3. Kvaser device with two channels MUST be connected to single CAN Bus (e.g. Kvaser II Memorator Pro)
4. Altera USB Blaster must be connected to FPGA with Signal TAP II Logic Analyzer design synthesized in.
5. CAN RX line from Kvaser must be connected to FPGA.
Program sequence:
1. Initialize 2 Kvaser Channels and Start Signal TAP II in separate deamon.
2. Generate random CAN Frame.
3. Start Signal TAP II Logic analyzer recording.
4. Send CAN Frame by Kvaser.
5. Wait until logic analyzer aquisition has finished.
6. Export data to temporary file by Signal TAP II (.tbl file)
7. Parse bit sequence from .tbl file, and add it to output file
8. Repeat "frame_count" times
Can be executed in following way:
`./build/kvalt_logger 1000 stp_session_template.stp auto_signaltap_0 "signal_set: 2018/06/18 19:22:19 #0" "trigger: 2018/06/18 19:22:19 #1" build/output_file`
/*******************************************************************************
*
* Kvaser / Altera Logger of CAN FD frames.
*
* Module: Text processor for parsing Signal TAP II exported data and
* generation of output files for VHDL testbenches.
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pty.h>
#include <utmp.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <canlib.h>
#include <time.h>
#include <stdlib.h>
#include "include/kvaser.h"
#include <regex.h>
int parse_stp_output(FILE *stp, FILE *out)
{
char line_buf[30];
regex_t regex;
int reg_res;
int first_sample = 0;
int eq_pos = 0;
char prev_val = '0';
int eq_count = 0;
/* Parse sampled lines */
reg_res = regcomp(&regex, "[ ]*[0-9]*.[0-9]> [0-9] = [0-9]*", 0);
if (reg_res) {
fprintf(stderr, "Unable to compile Regex\n");
return EXIT_FAILURE;
}
fprintf(out, "Bit sequence: ");
while (1) {
fgets(line_buf, 30, stp);
if (feof(stp))
break;
/* Evaluate Regex over the line */
reg_res = regexec(&regex, line_buf, 0, NULL, 0);
/* Process only matching Elements */
if (reg_res == REG_NOMATCH)
continue;
/* Extract position of '=' in first line */
if (first_sample == 0) {
eq_pos = strcspn(line_buf, "=");
first_sample = 1;
continue;
}
/* Count and write when signal value changes */
if (prev_val != line_buf[eq_pos + 2]){
fprintf(out, "%d %c ", eq_count, prev_val);
eq_count = 0;
} else {
eq_count++;
}
prev_val = line_buf[eq_pos + 2];
}
fprintf(out, "%d %c \n", eq_count, prev_val);
regfree(&regex);
return EXIT_SUCCESS;
}
int store_frame_info(struct kvalt_can_frame *frame, FILE *out)
{
if (frame->fr_type) {
fprintf(out, "CAN FD ");
} else {
fprintf(out, "CAN 2.0 ");
}
if (frame->id_type) {
fprintf(out, "EXTENDED ");
} else {
fprintf(out, "BASE ");
}
if (frame->rtr) {
fprintf(out, "RTR ");
} else {
fprintf(out, " ");
}
if (frame->brs) {
fprintf(out, "BRS ");
} else {
fprintf(out, " ");
}
fprintf(out, "Data length: %2d ", frame->data_length);
fprintf(out, "ID: %9ld ", frame->id);
fprintf(out, "Data: ");
for (int i = 0; i < 64; i++)
fprintf(out, "%02x ", frame->data[i]);
return EXIT_SUCCESS;
}
int process_stp_output(char *in_path, char *out_path, struct kvalt_can_frame *frame)
{
FILE *stp;
FILE *out;
char path_with_ext[200];
memset(path_with_ext, '\0', sizeof(path_with_ext));
strcpy(path_with_ext, "./");
strcat(path_with_ext, in_path);
strcat(path_with_ext, ".tbl");
stp = fopen(path_with_ext, "r");
if (stp == NULL){
fprintf(stderr, "Could not open Signal TAP II Exported file!\n");
fprintf(stderr, "Path: %s\n", path_with_ext);
return EXIT_FAILURE;
}
out = fopen(out_path, "a");
if (stp == NULL){
fprintf(stderr, "Could not open output file!\n");
fprintf(stderr, "Path: %s\n", out_path);
return EXIT_FAILURE;
}
store_frame_info(frame, out);
parse_stp_output(stp, out);
fclose(stp);
fclose(out);
return EXIT_SUCCESS;
}
void erase_file(char *path)
{
char cmd[100];
memset(&cmd, '\0', sizeof(cmd));
sprintf(cmd, "rm %s", path);
system(cmd);
}
/*******************************************************************************
*
* Kvaser / Altera Logger of CAN FD frames.
*
* Module: Text processor for parsing Signal TAP II exported data and
* generation of output files for VHDL testbenches.
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
/*
* Processes Signal TAP II exported file and stores logged bit sequence
* to output file. Data are stored like so:
* <CAN FRAME INFO> <BIT SEQUENCE>
*
* Bit sequence is coded like so:
* <NUM> <VAL>
* where NUM reffers to number of consecutive ocurrences of VAL.
* E.g. sequence:
* 4 0 5 1 3 0
* Represents:
* 000011111000
*
* Arguments:
* frame Pointer to frame which should be sent
* channel Kvaser channel to send the frame on (0, 1)
*/
int process_stp_output(char *in_path, char *out_path, struct kvalt_can_frame *frame);
/*
* Erase file.
*
* Arguments:
* path Path to file which should be erased.
*/
void erase_file(char *path);
/*******************************************************************************
*
* Kvaser / Altera Logger of CAN FD frames.
*
* Module: Kvaser access functions.
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
/*
* CAN Frame structure
*
* New structure is created instead of Linux structure. Linux uses different
* structs for CAN and CAN FD frames. Single struct is more pragmatic in this
* application
*/
struct kvalt_can_frame {
unsigned int data_length;
long id;
uint8_t id_type; // Identifier type: 0 - BASE, 1 - EXTENDED
uint8_t fr_type; // Frame type: 0 - CAN 2.0, 1 - CAN FD
uint8_t brs; // Bit rate shift flag
uint8_t rtr; // Remote transmission request flag
unsigned char data[64]; // Data bytes
};
/*
* Initializes Kvaser device via "canlib" with following settings:
* 1. Channels 0 an 1 are opened.
* 2. Bit-rate on both channels is set to 500 Kb/s Nominal, 2Mb Data. 80 % Sample point.
*/
int kvaser_init(void);
/*
* Prints CAN frame to standard output.
*
* Arguments:
* frame Pointer to frame that should be printed.
*/
void print_can_frame(struct kvalt_can_frame *frame);
/*
* Generate random CAN / CAN FD frame. Following constraints are applied:
* 1. RTR flag is only for CAN Frames.
* 2. BRS Flag is only for CAN FD Frames.
* 3. If BRS is false and FD frame is generated. Data length is
* mostly 16 bytes.
*
* Arguments:
* frame Pointer where generated frame will be returned.
*/
int generate_can_frame(struct kvalt_can_frame *frame);
/*
* Send CAN Frame via Kvaser.
*
* Arguments:
* frame Pointer to frame which should be sent
* channel Kvaser channel to send the frame on (0, 1)
*/
int kvaser_send_frame(struct kvalt_can_frame *frame, int channel);
/*
* Read CAN Frame via Kvaser.
*
* Arguments:
* frame Pointer to frame in which read frame will be stored
* channel Kvaser channel to read frame from (0, 1)
*/
int kvaser_read_frame(struct kvalt_can_frame *frame, int channel);
/*******************************************************************************
*
* Kvaser / Altera Logger of CAN FD frames.
*
* Module: Signal TAP II Logic Analyzer access functions.
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
#define QUARTUS_STP_PATH "/opt/quartus/bin/quartus_stp"
/*
* Initializes Quartus Signal TAP II Logic analyzer.
* Forks new process, connects input path and starts execution of command.
*
* Arguments:
* stp_path Path to Signal TAP II Analyzer binary.
*/
int stp_init(char *stp_path);
/*
* Terminates Quartus Signal TAP II Logic analyzer.
*/
void stp_exit(void);
/*
* Creates local copy of Signal TAP II session.
*
* Arguments:
* in_session Path to Signal TAP II Analyzer session (.stp file).
* This session will be duplicated.
* out_session Path to duplicated session.
*/
int stp_create_temp_session(char *in_session, char *out_session);
/*
* Sends command to Signal TAP II Logic analyzer to initialize sesssion.
*
* Arguments:
* session Path to Signal TAP II Analyzer session (.stp file).
*/
int stp_start_session(char *session);
/*
* Sends command to Signal TAP II Logic analyzer to start aquisition.
*
* Arguments:
* instance Name of the instance within session
* signals Name of signal set
* trigger Name of trigger
*/
int stp_run_aquisition(int log, char *instance, char *signals, char *trigger);
/*
* Waits 500 ms. Signal TAP II Aquisition should be over by then.
*
* Arguments:
* instance Name of the instance within session
* signals Name of signal set
* trigger Name of trigger
*/
void stp_wait_aquisition_end(void);
/*
* Export logged data from Signal TAP II logic analyzer aquisition.
* Exported data are not stored in the session anymore!
*
* Arguments:
* instance Name of the instance within session
* signals Name of signal set
* trigger Name of trigger
* dest Destination where data should be stored.s
*/
int stp_export_log(int log, char *instance, char *signals, char *trigger, char *dest);
/*
* Closes Signal TAP II Logic analyzer session. Session is automatically
* saved to .stp file.
*
*/
int stp_close_session(void);
/*******************************************************************************
*
* Kvaser / Altera Logger of CAN FD frames.
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pty.h>
#include <utmp.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <canlib.h>
#include <time.h>
#include <stdlib.h>
#include "include/stp.h"
#include "include/kvaser.h"
#include "include/data_processor.h"
/*
* Number of arguments for Kvalt logger:
* frame_count
* stp_session
* instance
* signal_Set
* trigger
* path to output file
*/
#define ARG_CNT 6
void print_help(void)
{
fprintf(stdout, "**************************\n");
fprintf(stdout, "*** Kvaalt logger help ***\n");
fprintf(stdout, "**************************\n");
fprintf(stdout, "Usage: \n");
fprintf(stdout, " kvaalt_logger <frame_count> <stp_sesssion> "
"<instance> <signal_set> <trigger> <out_file>\n\n");
fprintf(stdout, "Example:\n");
fprintf(stdout, " kvaalt_logger 10 /DOKUMENTY/Skola/CVUT-FEL/"
"CAN_FD_PCIe/FPGA_design"
"/Quartus/CAN_FD_SoC/output_files/debug.stp "
"\"signal_set: 2018/06/14 15:19:43 #0\" "
"\"trigger: 2018/06/14 15:19:43 #1\" \n");
fprintf(stdout, "\n");
}
int kvaalt_start_log(int num_frames, char *session, char *instance,
char *signals, char *trigger, char *outfile)
{
struct kvalt_can_frame tx_frame;
struct kvalt_can_frame rx_frame;
char *export = "build/tmp_export";
char *tmp_session = "build/tmp_session.stp";
/* Randomize for generator */
srand(time(NULL));
/* Initialize Kvaser on both channels */
if (kvaser_init()){
fprintf(stderr, "Error in Kvaser intialization\n");
return 1;
}
/* Start Altera Quartus Signal TAP II in separate shell */
if (stp_init(QUARTUS_STP_PATH)){
fprintf(stderr, "Error in Signal TAP II initialization\n");
return 1;
}
/* Erase output file */
erase_file(outfile);
stp_create_temp_session(session, tmp_session);
stp_start_session(tmp_session);
/* Execute logging itself */
for (int i = 0; i < num_frames; i++){
generate_can_frame(&tx_frame);
stp_run_aquisition(i, instance, signals, trigger);
kvaser_send_frame(&tx_frame, 0);
kvaser_read_frame(&rx_frame, 1);
stp_wait_aquisition_end();
stp_export_log(i, instance, signals, trigger, export);
process_stp_output(export, outfile, &tx_frame);
fprintf(stdout, "Iteration nr: %d\n", i + 1);
}
stp_close_session();
/* Close Altera Quartus Signal Tap II */
stp_exit();
return 0;
}
int main(int argc, char *argv[])
{
int result;
if (argc != ARG_CNT + 1){
print_help();
exit(EXIT_FAILURE);
}
if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")){
print_help();
exit(EXIT_FAILURE);
}
fprintf(stdout, "\n");
fprintf(stdout, "Starting Kvaser / Altera CAN Logger...\n");
fprintf(stdout, "Number of frames: %s\n", argv[1]);
result = kvaalt_start_log(atoi(argv[1]), argv[2], argv[3], argv[4],
argv[5], argv[6]);
exit(result);
}
/*******************************************************************************
*
* Kvaser / Altera Logger of CAN FD frames.
*
* Module: Kvaser access functions
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pty.h>
#include <utmp.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <canlib.h>
#include <time.h>
#include <stdlib.h>
#include "include/kvaser.h"
/* Kvaser global variables */
static canHandle hnd_chn_1;
static canHandle hnd_chn_2;
static int kvalt_dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
static void check(char* id, canStatus stat)
{
if (stat != canOK) {
char buf[50];
buf[0] = '\0';
canGetErrorText(stat, buf, sizeof(buf));
printf("%s: failed, stat=%d (%s)\n", id, (int)stat, buf);
}
}
int kvaser_init(void)
{
canStatus stat;
/* Allow signals to interrupt syscalls */
siginterrupt(SIGINT, 1);
canInitializeLibrary();
/* Open channel, set parameters and go on bus */
hnd_chn_1 = canOpenChannel(0, canOPEN_CAN_FD | canOPEN_EXCLUSIVE |