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

📄 diag_l1.c

📁 Freediag contains various drivers (ISO9141, ISO14230, SAEJ1850-VPW, SAEJ1850-PWM) for different adap
💻 C
字号:
/*
 *	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.
 *
 *************************************************************************
 *
 * L1 diagnostic interface, generic routines
 *
 * These look much like the L0 interface, but handle things such
 * as de-duplexing etc
 *
 * This is written so that sometime this can dynamically support more
 * than one L0 interface - I don't have more than one (or more than one type)
 * so it's not completely that way :-(
 *
 * HOWEVER, if the L0 interface has multiple interfaces in it, which have
 * different flags, then this code needs some enhancements. One of the
 * interfaces we use does have this (multiplex engineering interface) 
 */


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

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

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

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

static char *cvsid = "$Id: diag_l1.c,v 1.6 2002/06/17 20:58:33 rpalmeida Exp $";

int diag_l0_debug = 0;
int diag_l1_debug = 0;


int diag_l1_saferead(int fd, char *buf, int bufsiz, int timeout);

/*
 * Layer 0 (L0) interface table
 */
extern int diag_l0_sileng_init(void);
extern int diag_l0_sileng_open(int , int);
extern int diag_l0_sileng_close(int);
extern int diag_l0_sileng_initbus(int, struct diag_l1_init*);
extern int diag_l0_sileng_send(int, int, char*, int);
extern int diag_l0_sileng_recv(int, int, char*, int, int);
extern int diag_l0_sileng_setspeed(int, int, int, int, int);
extern int diag_l0_sileng_getflags(int);

extern int diag_l0_muleng_init(void);
extern int diag_l0_muleng_open(int , int);
extern int diag_l0_muleng_close(int);
extern int diag_l0_muleng_initbus(int, struct diag_l1_init*);
extern int diag_l0_muleng_send(int, int, char*, int);
extern int diag_l0_muleng_recv(int, int, char*, int, int);
extern int diag_l0_muleng_setspeed(int, int, int, int, int);
extern int diag_l0_muleng_getflags(int);

extern int diag_l0_vwtool_init(void);
extern int diag_l0_vwtool_open(int , int);
extern int diag_l0_vwtool_close(int);
extern int diag_l0_vwtool_initbus(int, struct diag_l1_init*);
extern int diag_l0_vwtool_send(int, int, char*, int);
extern int diag_l0_vwtool_recv(int, int, char*, int, int);
extern int diag_l0_vwtool_setspeed(int, int, int, int, int);
extern int diag_l0_vwtool_getflags(int);

extern int diag_l0_br_init(void);
extern int diag_l0_br_open(int , int);
extern int diag_l0_br_close(int);
extern int diag_l0_br_initbus(int, struct diag_l1_init*);
extern int diag_l0_br_send(int, int, char*, int);
extern int diag_l0_br_recv(int, int, char*, int, int);
extern int diag_l0_br_setspeed(int, int, int, int, int);
extern int diag_l0_br_getflags(int);

/*
 * XX, the full-name/flags/type shouldn't be here, they should be in the
 * interface driver as it's a property of that, not of this "switch" table
 */

struct diag_l0 diag_l0_devices[] =
{
	{ 	"Silicon Engines 9141 Converter", 
		"SE9141",
		DIAG_L1_ISO9141 | DIAG_L1_ISO14230 | DIAG_L1_RAW,
		diag_l0_sileng_init,
		diag_l0_sileng_open,
		diag_l0_sileng_close,
		diag_l0_sileng_initbus,
		diag_l0_sileng_send,
		diag_l0_sileng_recv,
		diag_l0_sileng_setspeed,
		diag_l0_sileng_getflags
	},
	{ 	"Multiplex Engineering T16 interface",
		"MET16",
		DIAG_L1_J1850_VPW | DIAG_L1_J1850_PWM |
			DIAG_L1_ISO9141 | DIAG_L1_ISO14230,
		diag_l0_muleng_init,
		diag_l0_muleng_open,
		diag_l0_muleng_close,
		diag_l0_muleng_initbus,
		diag_l0_muleng_send,
		diag_l0_muleng_recv,
		diag_l0_muleng_setspeed,
		diag_l0_muleng_getflags
	},
	{ 	"VAGTool Compatible interface", 
		"VAGTOOL",
		DIAG_L1_ISO9141 | DIAG_L1_ISO14230 | DIAG_L1_RAW,
		diag_l0_vwtool_init,
		diag_l0_vwtool_open,
		diag_l0_vwtool_close,
		diag_l0_vwtool_initbus,
		diag_l0_vwtool_send,
		diag_l0_vwtool_recv,
		diag_l0_vwtool_setspeed,
		diag_l0_vwtool_getflags
	},
	{ 	"B. Roadman BR-1 interface",
		"BR1",
		DIAG_L1_J1850_VPW | DIAG_L1_J1850_PWM |
			DIAG_L1_ISO9141 | DIAG_L1_ISO14230,
		diag_l0_br_init,
		diag_l0_br_open,
		diag_l0_br_close,
		diag_l0_br_initbus,
		diag_l0_br_send,
		diag_l0_br_recv,
		diag_l0_br_setspeed,
		diag_l0_br_getflags
	},
	{
		"", "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL
	}
};

/* For debug messages */
#define DIAG_MODULE	"diag_l1"

/*
 * One l1-device per active interface
 *
 * XXX needs to be enhanced to be one per protocol per interface, which
 * will require switching from using a fd to some sort of handle
 */
struct diag_l1_device
{
	int dev_fd;		/* File descriptor */
	int protocol;		/* Protocol */
	struct diag_l0 *dev_device;
};


struct diag_l1_device diag_l1_devices[DIAG_L1_MAXINTF];

/* Global init flag */
int diag_l1_initdone = 0;

int
diag_l1_init(void)
{
	int i;
	struct diag_l0 *l0_dev;

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

	/* FD == -1 is magic unused flag */
	for (i = 0; i < DIAG_L1_MAXINTF; i++)
	{
		diag_l1_devices[i].dev_fd = -1;
	}
	/* Now call the init routines for the L0 devices */

	l0_dev = diag_l0_devices;
	while ((l0_dev->diag_l0_name[0]) != 0)
	{
		(l0_dev->diag_l0_init)();
		l0_dev ++;
	}
	return (0);
}

struct diag_l1_device *
diag_l1_finddev(int fd)
{
	int i;
	struct diag_l1_device *dev;

	for (i = 0; i < DIAG_L1_MAXINTF; i++)
	{
		dev = &diag_l1_devices[i];
		if (dev->dev_fd == fd) 
			return(dev);
	}

	return (NULL) ;
}

/*
 * Open the diagnostic device, returns a file descriptor
 *
 * Finds the unique name in the l0 device table,
 * calls the init routine, with the device parameter from the table
 *
 * This is passed a L1 Protocol ID (ie, what type of physical interface
 * to run on
 */
int
diag_l1_open(char *name, int id, int l1protocol)
{
	struct diag_l0 *l0_dev;
	struct diag_l1_device *l1_dev;
	int rv;

	l0_dev = diag_l0_devices;
	while (l0_dev -> diag_l0_name[0])
	{
		if (strcmp(name, l0_dev->diag_l0_name) == 0)
		{
			/* Found it */

			/* Check h/w supports this l1 protocl */
			if ((l0_dev->diag_l0_type & l1protocol) == 0)
				return(DIAG_ERR_PROTO_NOTSUPP);

			/* Get a L1 device structure */
			l1_dev = diag_l1_finddev(-1);
			if (l1_dev == NULL)
				return (-1);

			/* Call the open routine */
			rv = (l0_dev->diag_l0_open)(id, l1protocol);

			if (rv < 0)
				return (rv);
			l1_dev->dev_fd = rv;
			l1_dev->dev_device = l0_dev;
			return (rv);
		}
		l0_dev ++;
	}
	return (-1);
}

int
diag_l1_close(int fd)
{
	struct diag_l1_device *dev;

	dev = diag_l1_finddev(fd);
	if (dev)
	{
		(dev->dev_device->diag_l0_close)(fd);
		dev->dev_fd = -1;	/* No longer in use */
	}

	return(0);
}

/*
 * Do wakeup/init on the net.
 */
int
diag_l1_initbus(int fd, struct diag_l1_init *in)
{
	struct diag_l1_device *dev;

	dev = diag_l1_finddev(fd);
	if (dev)
		return ((dev->dev_device->diag_l0_initbus)(fd, in));
	return (-1);
}

/*
 * Send a load of data
 *
 * P4 is the inter byte gap
 *
 * This does very un-clever half duplex removal, there better not be
 * any outstanding data on the bus (or in the l0 buffers) or this
 * will think it has a half-duplex failure, i.e a bus error
 *
 * Returns 0 on success -1 on failure
 */
diag_l1_send(int fd, int subinterface, char *data, int len, int p4)
{
	struct diag_l1_device *dev;
	int rv = -1;
	int l0flags;

	dev = diag_l1_finddev(fd);
	if (dev)
	{
		/*
		 * If p4 is zero and not in half duplex mode, or if
		 * L1 is a "DOESL2" interface send the whole message to L0
		 * as one write
		 */ 
		l0flags = diag_l1_getflags(fd);

		if (   ((p4 == 0) && (l0flags & DIAG_L1_HALFDUPLEX == 0))
			|| (l0flags & DIAG_L1_DOESL2FRAME) 
			|| (l0flags & DIAG_L1_DOESP4WAIT) )
		{
			/*
			 * Send the lot if we don't need to delay, or collect
			 * the echos
			 */
			rv = (dev->dev_device->diag_l0_send)(fd, subinterface, data, len);
		}
		else
		{
			char *dp = data;

			/* Send each byte */
			while (len--)
			{
				rv = (dev->dev_device->diag_l0_send)(fd, subinterface, dp, 1);
				if (rv != 0)
					break;

				/*
				 * If half duplex, read back the echo, if
				 * the echo is wrong then this is an error
				 * i.e something wrote on the diag bus whilst
				 * we were writing
				 */
				if (l0flags & DIAG_L1_HALFDUPLEX)
				{
					char c;

					c = *dp - 1; /* set it with wrong val */
					(void)diag_l1_saferead(fd, &c, 1, 1000);

					if (c != *dp)
					{
printf("buserror got 0x%x expected 0x%x\n",
	c&0xff, *dp & 0xff);
						rv = DIAG_ERR_BUSERROR;
						break;
					}
				}
				dp++;

				if (p4)	/* Inter byte gap */
					diag_os_millisleep(p4);
			}
		}
		if (rv < 0)
			return(rv);
	}
	return(rv);
}

/*
 * Get data (blocking, unless timeout is 0)
 */
diag_l1_recv(int fd, int subinterface, char *data, int len, int timeout)
{
	struct diag_l1_device *dev;
	int rv = -1;

	dev = diag_l1_finddev(fd);
	if (dev) {
		rv = (dev->dev_device->diag_l0_recv)(fd, subinterface, data, len, timeout);
	}

	return(rv);
}

/*
 * Set speed/parity etc
 */
diag_l1_setspeed(int fd, int speed, int bits, int stop_bits, int parflag )
{
	struct diag_l1_device *dev;

	dev = diag_l1_finddev(fd);
	if (dev)
		return ((dev->dev_device->diag_l0_setspeed)(fd, speed, bits, stop_bits, parflag) );
	return (-1);
}

int diag_l1_getflags(int fd)
{
	struct diag_l1_device *dev;

	dev = diag_l1_finddev(fd);

	if (dev)
		return ((dev->dev_device->diag_l0_getflags)(fd) );

	return (0);
}

int diag_l1_gettype(int fd)
{
	struct diag_l1_device *dev;

	dev = diag_l1_finddev(fd);
	if (dev)
		return(dev->dev_device->diag_l0_type);
	return (0);
}

int
diag_l1_saferead(int fd, char *buf, int bufsiz, int timeout)
{
	int cnt;

	/* And read back the single byte echo, which shows TX completes */
	while ( (cnt = diag_os_read(fd, buf, bufsiz, timeout)) < 0)
	{
		if (errno != EINTR)
		{
			/* Error, EOF */
			perror("read");
			fprintf(stderr, "%s: read returned error %d !!\n", DIAG_MODULE, errno);
			return(-1);
		}
	}

	return(cnt);
}

⌨️ 快捷键说明

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