⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diag_l2.c

📁 Freediag contains various drivers (ISO9141, ISO14230, SAEJ1850-VPW, SAEJ1850-PWM) for different adap
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *	freediag - Vehicle Diagnostic Utility
 *
 *
 * Copyright (C) 2001 Richard Almeida & Ibex Ltd (rpa@ibex.co.uk)
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *************************************************************************
 *
 * L2 diagnostic interface, generic routines
 *
 * This sits "under" the L2 per-protocol (such as ISO 14230, SAE J1979)
 *  - understands the protocol format,
 *  - removes the "half duplex" echos from half duplex interfaces
 *  - pads messages as needed,
 *  - and sends "tester present" messages at the correct intervals to keep
 *	the link to an ECU alive
 *
 */

#include "diag_os.h" /* operating specific includes */

#include <stdlib.h>
#include <stdio.h>

#include <fcntl.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>

#include "diag.h"
#include "diag_l1.h"
#include "diag_l2.h"
#include "diag_err.h"
#include "diag_general.h"

/* includes for the different level 2 layers        */
/* these are referenced in the diag_proto structure */
#include "diag_l2_raw.h"
#include "diag_l2_iso9141.h"
#include "diag_l2_iso14230.h"
#include "diag_l2_saej1850.h"
#include "diag_l2_vag.h"
#include "diag_l2_mb1.h"

/* */

static char *cvsid = "$Id: diag_l2.c,v 1.9 2002/06/16 22:26:44 rpalmeida Exp $";

int diag_l2_debug = 0;

#define DIAG_MODULE "diag_l2"

/*
 * Interface to individual protocols
 */
typedef struct diag_proto
{
	int	diag_id;
	int	diag_l2_flags;

	/* Individual L2 routines, see description of interface in diag_l2.h */
	int	(*diag_l2_proto_startcomms)(diag_l2_conn_t*, u_int16_t, int, u_int8_t, u_int8_t);
	int	(*diag_l2_proto_stopcomms)(diag_l2_conn_t*);
	int	(*diag_l2_proto_send)(diag_l2_conn_t*, diag_msg_t*);
	int	(*diag_l2_proto_recv)(diag_l2_conn_t *d_l2_conn, int timeout, void (*callback)(void *handle, diag_msg_t *msg), void *handle);
	diag_msg_t *	(*diag_l2_proto_request)(diag_l2_conn_t*, diag_msg_t*, int*);
	int	(*diag_l2_proto_atp)(diag_l2_conn_t* d_l2_conn, int p2min, int p2max, int p3min, int p3max, int p4min);
	void	(*diag_l2_proto_timer)(int);
	void	(*diag_l2_proto_timeout)(diag_l2_conn_t*);
} diag_proto_t;

/*
 * These are the L2 protocols
 *
 * This table must be in numeric order of the DIAG_L2_PROT_XXX as defined
 * in diag_l2.h
 * the init routine will check this and exit if its not.
 */
diag_proto_t diag_protocols[] =
{
	{ DIAG_L2_PROT_RAW, 0,
		diag_l2_proto_raw_startcomms,
		diag_l2_proto_raw_stopcomms,
		diag_l2_proto_raw_send,
		diag_l2_proto_raw_recv,
		diag_l2_proto_raw_request,
		NULL,
		diag_l2_proto_raw_timer,
		diag_l2_proto_raw_timeout
	},
	{ DIAG_L2_PROT_ISO9141, 0,
		diag_l2_proto_9141_startcomms,
		diag_l2_proto_raw_stopcomms,
		diag_l2_proto_9141_send,
		diag_l2_proto_9141_recv,
		diag_l2_proto_9141_request,
		NULL,
		diag_l2_proto_raw_timer,
		diag_l2_proto_raw_timeout
	},
	{ DIAG_L2_PROT_ISO9141_2, DIAG_L2_FLAG_FRAMED,
		diag_l2_proto_9141_2_startcomms,
		diag_l2_proto_raw_stopcomms,
		diag_l2_proto_9141_send,
		diag_l2_proto_9141_recv,
		diag_l2_proto_9141_request,
		NULL,
		diag_l2_proto_raw_timer,
		diag_l2_proto_raw_timeout,
	},
	{ DIAG_L2_PROT_ISO14230, DIAG_L2_FLAG_FRAMED | DIAG_L2_FLAG_DATA_ONLY
		| DIAG_L2_FLAG_KEEPALIVE | DIAG_L2_FLAG_DOESCKSUM,
		diag_l2_proto_14230_startcomms,
		diag_l2_proto_14230_stopcomms,
		diag_l2_proto_14230_send,
		diag_l2_proto_14230_recv,
		diag_l2_proto_14230_request,
		diag_l2_proto_14230_atp,
		diag_l2_proto_14230_timer,
		diag_l2_proto_14230_timeout,
	},
	{ DIAG_L2_PROT_SAEJ1850, DIAG_L2_FLAG_FRAMED | DIAG_L2_FLAG_DATA_ONLY
		| DIAG_L2_FLAG_DOESCKSUM | DIAG_L2_FLAG_CONNECTS_ALWAYS,
		diag_l2_proto_j1850_startcomms,
		diag_l2_proto_j1850_stopcomms,
		diag_l2_proto_j1850_send,
		diag_l2_proto_j1850_recv,
		diag_l2_proto_j1850_request,
		NULL, NULL, NULL
	},
	{ DIAG_L2_PROT_CAN, 0,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
	{ DIAG_L2_PROT_VAG, DIAG_L2_FLAG_FRAMED | DIAG_L2_FLAG_DOESCKSUM,
		diag_l2_proto_vag_startcomms,
		diag_l2_proto_raw_stopcomms,
		diag_l2_proto_vag_send,
		diag_l2_proto_vag_recv,
		diag_l2_proto_vag_request,
		NULL,
		diag_l2_proto_raw_timer,
		diag_l2_proto_raw_timeout,
	},
	{ DIAG_L2_PROT_MB1, DIAG_L2_FLAG_FRAMED | DIAG_L2_FLAG_DATA_ONLY
		| DIAG_L2_FLAG_KEEPALIVE | DIAG_L2_FLAG_DOESCKSUM,
		diag_l2_proto_mb1_startcomms,
		diag_l2_proto_raw_stopcomms,
		diag_l2_proto_mb1_send,
		diag_l2_proto_mb1_recv,
		diag_l2_proto_mb1_request,
		NULL,
		diag_l2_proto_raw_timer,
		diag_l2_proto_mb1_timeout,
	},
};

/*
 * Values for diag_state
 *
 * The state values are mainly used by the timer code to determine if
 * keepalive timers are needed.
 */
#define DIAG_L2_STATE_CLOSED		0	/* Not in use (but not free for anyones use !!) */
#define DIAG_L2_STATE_SENTCONREQ	1	/* Sent connection request (waiting for response/reject) */
#define DIAG_L2_STATE_OPEN		2	/* Up and running */
#define DIAG_L2_STATE_CLOSING		3	/* Sent close request (possibly), waiting for response/timeout */


/*
 * The list of connections, not searched often so no need to hash
 * (maybe when we actually finish supporting talking to more than
 * one ECU on one interface at once)
 */
diag_l2_conn_t	*diag_l2_connections = NULL;
diag_l2_conn_t	*diag_l2_conbyid[256];		/* Look up by ECU address */

int diag_l2_init_done = 0;	/* Init done */


/*
 * The list of L1 devices we have open, not used often so no need to hash
 */
diag_l2_link_t *diag_l2_links = NULL;

/*
 * Find our link to the L1 device, by name
 */
diag_l2_link_t *
diag_l2_findlink(char *dev_name)
{
	diag_l2_link_t *d_l2_link = diag_l2_links;

	while (d_l2_link)
	{
		if ( strcmp(d_l2_link -> diag_l2_name , dev_name) == 0)
			return(d_l2_link);
		d_l2_link = d_l2_link -> next;
	}
	return (NULL);
}
/*
 * Find our link to the L1 device, by Fd
 */
diag_l2_link_t *
diag_l2_findlink_byfd(int fd)
{
	diag_l2_link_t *d_l2_link = diag_l2_links;

	while (d_l2_link)
	{
		if (d_l2_link->diag_l2_fd == fd)
			return(d_l2_link);
		d_l2_link = d_l2_link -> next;
	}
	return (NULL);
}

/*
 * Remove a link, caller should free it
 */
int
diag_l2_rmlink(diag_l2_link_t *d)
{
	diag_l2_link_t *d_l2_link, *d_l2_last;

	d_l2_link = diag_l2_links;
	d_l2_last = NULL;

	while (d_l2_link)
	{
		if (d_l2_link == d)
		{
			if (d_l2_last)
				d_l2_last = d->next;
			else
				diag_l2_links = d->next;
			break;
		}
		d_l2_last = d_l2_link;
		d_l2_link = d_l2_link -> next;
	}
	return (0);
}

/*
 *
 * remove a L2 connection from our list
 * - up to the caller to have shut it down properly first
 */
int
diag_l2_rmconn(diag_l2_conn_t *d)
{
	diag_l2_conn_t	*d_l2_conn = diag_l2_connections;
	diag_l2_conn_t	*d_l2_last_conn = NULL;

	while (d_l2_conn)
	{
		if (d_l2_conn == d)
		{
			/* Remove it from list */
			if (d_l2_last_conn)
				d_l2_last_conn->next = d->next ;
			else
				diag_l2_connections = d->next;

			break;
		}
		d_l2_last_conn = d_l2_conn;
		d_l2_conn = d_l2_conn->next;
	}
	return (0);
}

/*
 * Called regularly to check timeouts etc (call at least once per
 * second)
 */
void
diag_l2_timer()
{
	diag_l2_conn_t	*d_l2_conn;
	diag_proto_t *dp;
	struct timeval now;

	int i;

	/*
	 * Go thru L2 protocols and call their timer()
	 * routines
	 */
	for (i=0, dp = diag_protocols ; i<ARRAY_SIZE(diag_protocols); i++, dp++)
	{
		if (dp->diag_l2_proto_timer)
			dp->diag_l2_proto_timer(0);
	}

	/*
	 * Calculate the expiration time, we use 2/3 of P3max
	 * to calculate when to call the L2 protocol timeout() routine
	 */
	(void)gettimeofday(&now, NULL);

	for (d_l2_conn = diag_l2_connections;
		d_l2_conn; d_l2_conn = d_l2_conn -> next)
	{
		struct timeval expiry;

		int expired = 0;

		/*
		 * If in monitor mode, we don't do anything as were
		 * just listening
		 */
		if ((d_l2_conn->diag_l2_type & DIAG_L2_TYPE_INITMASK)
				== DIAG_L2_TYPE_MONINIT)
		{
			continue;
		}

		/* Check the send timers vs the p3max timer */
		memcpy(&expiry, &d_l2_conn->diag_l2_lastsend, sizeof(now));

		expiry.tv_sec +=  (d_l2_conn->diag_l2_p3max*2/3) / 1000;
		expiry.tv_usec += ((d_l2_conn->diag_l2_p3max*2/3) % 1000) * 1000;
		if (expiry.tv_usec > 1000000)
		{
			expiry.tv_sec ++;
			expiry.tv_usec -= 1000000;
		}

		if (now.tv_sec > expiry.tv_sec)
			expired = 1;
		if (now.tv_sec == expiry.tv_sec)
		{
			if (now.tv_usec > expiry.tv_usec)
				expired = 1;
		}

		/* And if expired, call the timeout routine */
		if (expired && diag_protocols[d_l2_conn->diag_l2_protocol].diag_l2_proto_timeout)
			diag_protocols[d_l2_conn->diag_l2_protocol].diag_l2_proto_timeout(d_l2_conn);

	}
}

/*
 * Add a message to the message list on the L2 connection
 */
void
diag_l2_addmsg(diag_l2_conn_t *d_l2_conn, diag_msg_t *msg)
{
	diag_msg_t *tmsg = d_l2_conn->diag_msg;

	if (d_l2_conn->diag_msg == NULL)
	{
		d_l2_conn->diag_msg = msg;
		d_l2_conn->diag_msg->mcnt = 1;
		return;
	}
	/* Add to end of list */
	while (tmsg)
	{
		if (tmsg->next == NULL)
		{
			msg->next = NULL;
			tmsg->next = msg;
			d_l2_conn->diag_msg->mcnt ++;
			break;
		}
		tmsg = tmsg->next;
	}
}

/************************************************************************/
/*  PUBLIC Interface starts here					*/
/************************************************************************/

/*
 * Init called to initialise local structures, and same for layers below
 */
int diag_l2_init()
{
	diag_proto_t *dp;
	int i;

	if (diag_l2_debug & DIAG_DEBUG_INIT)
		fprintf(stderr,"%s: diag_l2_init called\n", DIAG_MODULE);

	if ( diag_l2_init_done )
		return(0);
	diag_l2_init_done = 1;

	memset(diag_l2_conbyid, 0, sizeof(diag_l2_conbyid));

	/*
	 * Sanity check, check that the protocol table is in numeric order
	 */
	for (i=0, dp = diag_protocols; i<ARRAY_SIZE(diag_protocols); i++, dp++)
	{
		if (dp->diag_id != i)
		{
			fprintf(stderr,"ERROR: Diag protocols defined wrongly\n");
			fprintf(stderr,"ERROR: element %d value %d\n",
				i, dp->diag_id);
		}
	}

	/*
	 * And go do the layer 1 init
	 */
	return(diag_l1_init());
}

/*
 * Open a link to a Layer 1 device, returns fd, if device is already
 * open, close and then re-open it (as we need to pass it a new "protocol"
 * field if the l1 protocol is different
 * 
 * The ID is the interface number, for instance COM0 may be ID 0, COM1 = ID 1
 * etc
 *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -